pax_global_header00006660000000000000000000000064134211725560014520gustar00rootroot0000000000000052 comment=d195c57b9aaaffeb5e886b6ac7a1ad8638078b7b O-Saft-19.01.19/000077500000000000000000000000001342117255600130535ustar00rootroot00000000000000O-Saft-19.01.19/.o-saft.pl000066400000000000000000000321141342117255600146600ustar00rootroot00000000000000#!/bin/cat #? #? NAME #? .o-saft.pl - resource file for o-saft.pl #? DESCRIPTION #? Contains arguments and options for o-saft.pl . #? SYNOPSIS #? File must be located in current working directory or installation #? directory of o-saft.pl . #? SYNTAX #? Empty lines are ignored. #? Lines starting with # are ignored (comment lines). #? Each other line will be passed as one single argument or option. #? Note that all values for --cfg-cmd= are all lower case letters. #? NEW COMMANDS #? New commands may be defined herein using --cfg_cmd= . #? Please see example +preload below. #? New Hints may be defined herein using --cfg_hint= . #? #? It is recommended to use a prefix in each private command to avoid #? conflicts with existing (or future) commands in o-saft.pl itself. #? Following prefixes (for commands) are not used by o-saft.pl: #? +fy- +ma- +mein- +mea- +meu- +mi- +mia- +mijn- +min- +mio #? +moj- +mo- +moj- +mon- +muj- +my- +nire- #? #? The special line #? ##? Some text #? contains a brief description for the next new command defined with #? --cfg_cmd= . This will be used in the GUI only. #? VERSION #? @(#) .o-saft.pl 1.95 19/01/19 14:10:20 #? AUTHOR #? 13-dec-13 Achim Hoffmann #? # ----------------------------------------------------------------------------- SID.rc = 1.95; # our own SID required for Makefile and some tools ### ### force to use private openssl ### #--openssl=/usr/local/openssl/bin/openssl #--openssl-cnf=/usr/local/openssl/ssl/openssl.cnf #--force-openssl ### or #--lib=/usr/local/lib ### disable special openssl options (if not supported by openssl) #--no-nextproto #--no-reconnect #--no-tlsextdebug ### ### specify CA bundle ### #--ca-path=/etc/ssl/certs/ #--ca-file=/etc/ssl/certs/ca-certificates.crt #--ca-depth=4 ### ### disable cipher checks ### #--no-tcp #--no-sslv2 #--no-sslv3 #--no-tlsv1 #--no-tlsv11 #--no-tlsv12 #--no-tlsv13 #--no-udp #--no-dtlsv1 #--no-dtlsv11 #--no-dtlsv12 #--no-dtlsv13 ### ### avoid various problems ### #--ssl-lazy #--no-http #--no-sni #--no-dns #--no-md5-cipher #--no-cert #--ignorecase ### ### make output parsable ### #--label=owasp #--showhost #--trace=key #--header #--no-header #--no-warning #--separator=CHAR #--enabled ### ### omit output for commands ### # commands are used witout + prefix # Example: all commands for various BSI compliance checks 'cause these checks # are rarely used in practice and most likely produce a huge amount of data. --ignore-output=tr_03116+ --ignore-output=tr_03116- --ignore-output=rfc_7525 --ignore-output=ism --ignore-output=pci --ignore-output=fips --ignore-output=ev+ # https_body contains the HTML page, not important --ignore-output=https_body # temporary disbaled until proper implementation (04/2017) # ... ### ### define new command +preload ### ##? Check STS header preload attributes # To satisfy the requirements on https://hstspreload.appspot.com/ the # HSTS header must: # * have the max-age with at least 18 weeks (10886400 seconds) # * have the includeSubDomains attribute # * have the preload attribute # * redirect to https first, then to sub-domains (if redirected) # * have an HSTS header in each redirect to https. # # Additionally, the site must have: # * a valid certificate # * serve all subdomains over https. # # Except the last requirement, following +preload will do the checks. # --cfg_cmd=preload=sts_maxage18 sts_subdom sts_preload hsts_is301 hsts_samehost hsts_httpequiv expired hsts_maxage hsts_subdom hsts_preload ### ### define new command +ciphercheck ### ##? Check various cipher usage # +ciphers shows which ciphers are accepted/supported and shows the severity. # This command summarizes the other cipher checks. # --cfg_cmd=ciphercheck=cipher_selected cipher_strong cipher_null cipher_adh cipher_exp cipher_cbc cipher_des cipher_rc4 cipher_edh cipher_pfs cipher_pfsall cnt_ciphers cnt_totals ### ### define new command +names ### ##? Collection of all info and check commands related to certificate names # --cfg_cmd=names=cn subject issuer altname verify_altname verify_hostname hostname sni certfqdn wildcard wildhost rfc_2818_names rfc_6125_names ### ### define new command +ocsp ### ##? Collection of all info and check commands related to OCSP data # --cfg_cmd=ocsp=ocsp_response ocsp_response_status ocsp_cert_status ocsp_this_update ocsp_next_update ocsp_subject_hash ocsp_public_hash ocsp_uri ocsp_valid ocsp_stapling len_ocsp --cfg_hint=ocsp=use ++oscp_response_data to get the full response ### ### define new command +fingerprints ### ##? Check all certificate fingerprints # +ciphers shows which ciphers are accepted/supported and shows the severity. # This command summarizes the other cipher checks. # --cfg_cmd=fingerprints=fingerprint_type fingerprint fingerprint_hash fingerprint_md5 fingerprint_sha1 fingerprint_sha2 fp_not_md5 ### ### reconfigure list of check for special commands (+http +check ...) ### # The default behaviour to print the results is to loop over the list of hash # keys. This is usually a sorted alphanumerically according the key name. For # human readability, the default behaviour may not be appropriate. Hence the # sequence of the output can be sorted as needed. Therefore simply define the # commands to be used below. They then will be printed in that order. # # NOTE that the list defined here overwrites o-saft.pl's default list, which # can result in missing output. # In particular after updates, the local .o-saft.pl containing redefines # should be checked against o-saft.pl's default commands. # Hint: use --tracekey which prints the keys ### ### redefine command +http ### --cfg_cmd=http=http_status http_location http_refresh http_sts https_status https_server https_location https_refresh https_alerts https_sts hsts_maxage hsts_subdom hsts_preload http_https hsts_is301 hsts_is30x hsts_redirect hsts_samehost hsts_fqdn hsts_httpequiv hsts_sts hsts_location hsts_refresh sts_maxage sts_subdom sts_maxage0d sts_maxage1d sts_maxage1m sts_maxage1y sts_maxage18 sts_maxagexy sts_expired https_pins pkp_pins http ### ### redefine command +hsts ### --cfg_cmd=hsts=http_https hsts_is301 hsts_is30x hsts_redirect hsts_samehost hsts_fqdn hsts_ip hsts_httpequiv hsts_maxage hsts_preload hsts_subdom hsts_sts hsts_location hsts_refresh sts_maxage sts_subdom sts_maxage0d sts_maxage1d sts_maxage1m sts_maxage1y sts_maxage18 sts_maxagexy sts_expired ### ### redefine command +info ### --cfg_cmd=info=certversion cn subject subject_hash issuer issuer_hash serial fingerprint fingerprint_type fingerprint_hash fingerprint_sha2 fingerprint_sha1 fingerprint_md5 before after dates email certificate sigdump signame sigkey_len sigkey_value pubkey pubkey_algorithm modulus_len pubkey_value modulus_exponent aux trustout ocspid ocsp_uri ocsp_public_hash ocsp_subject_hash selfsigned chain chain_verify extensions altname verify_altname verify_hostname verify error_verify heartbeat expansion compression renegotiation resumption srp krb5 psk_identity psk_hint ocsp_response alpns npns alpn npn next_protocols dh_parameter master_key session_id session_ticket session_lifetime sslversion http_status http_location http_refresh http_sts https_server https_status https_location https_refresh https_alerts https_sts hsts_maxage hsts_subdom hsts_preload http_https hsts_is301 hsts_is30x hsts_redirect hsts_fqdn hsts_httpequiv hsts_sts hsts_location hsts_refresh sts_maxage sts_subdom sts_maxage0d sts_maxage1d sts_maxage1m sts_maxage1y sts_maxage18 sts_maxagexy https_pins pkp_pins info # useless for +info ('cause aliases): issuer issuer_hash # included in +info to be printed with --v : # certificate sigdump pubkey extensions ext_* # ext_* printed with +info--v ### ### redefine command +check ### --cfg_cmd=check=cipher_selected cipher_strong hassslv2 hassslv3 hastls12 cipher_null cipher_adh cipher_exp cipher_cbc cipher_des cipher_rc4 cipher_edh cipher_pfs cipher_pfsall dh_512 dh_2048 ecdh_256 ecdh_512 ism pci fips tr_02102+ tr_02102- tr_03116+ tr_03116- rfc_7525 beast breach ccs crime time drown freak heartbleed logjam lucky13 poodle rc4 robot sloth sweet32 sni hostname reversehost cps crl crl_valid ev+ ev- ev_chars crnlnull nonprint ocsp_uri ocsp_valid fp_not_md5 sha2signature sig_encryption sig_enc_known pub_encryption pub_enc_known modulus_exp_65537 modulus_exp_oldssl modulus_size_oldssl expired dates rootcert selfsigned constraints verify certfqdn wildcard wildhost rfc_2818_names rfc_6125_names sernumber http_https hsts_is301 hsts_is30x hsts_redirect hsts_samehost hsts_fqdn hsts_httpequiv hsts_sts hsts_location hsts_refresh sts_maxage sts_subdom sts_maxage0d sts_maxage1d sts_maxage1m sts_maxage1y sts_maxage18 sts_maxagexy sts_expired pkp_pins krb5 psk_identity psk_hint master_key session_id session_ticket session_lifetime session_random ocsp_stapling closure sgc zlib open_pgp lzo hasalpn hasnpn fallback renegotiation resumption srp scsv cnt_checks_yes cnt_checks_no cnt_ciphers cnt_totals cnt_chaindepth cnt_altname cnt_wildcard len_cps len_crl len_crl_data len_ocsp len_oids len_altname len_chain len_issuer len_pembase64 len_pembinary len_publickey len_sigdump len_subject len_sernumber check # useless for +check: ip # don't use +check: (SSLv|TLSv)* ### ### redefine command +quick ### --cfg_cmd=quick=sslversion hassslv2 hassslv3 hastls12 cipher cipher_selected cipher_strong cipher_null cipher_adh cipher_exp cipher_cbc cipher_des cipher_rc4 cipher_edh cipher_pfs beast ccs crime drown freak heartbleed logjam lucky13 poodle rc4 robot sloth sweet32 fingerprint_hash fp_not_md5 sha2signature pub_encryption email serial subject dates verify heartbeat expansion compression hostname hsts_sts crl resumption renegotiation ### ### redefine command +sizes ### --cfg_cmd=sizes=cnt_chaindepth cnt_wildcard cnt_altname len_altname len_subject len_issuer len_pembase64 len_pembinary len_publickey len_sigdump len_sernumber len_chain len_cps len_crl len_crl_data len_ocsp len_oids ### ### redefine command +bsi ### --cfg_cmd=bsi=after dates crl cipher_rc4 renegotiation tr_02102+ tr_02102- tr_03116+ tr_03116- ### ### redefine command +pfs ### --cfg_cmd=pfs=cipher_pfs cipher_pfsall session_random ### ### redefine command +protocols ### --cfg_cmd=prots=hassslv2 hassslv3 hastls10 hastls11 hastls12 hastls13 hasalpn hasnpn session_protocol fallback_protocol alpns npns alpn npn next_protocols https_protocols http_protocols https_svc http_svc ### ### redefine command +vulns ### --cfg_cmd=vulns=beast breach ccs crime drown freak heartbleed logjam lucky13 poodle rc4 robot sloth sweet32 time hassslv2 hassslv3 compression fallback cipher_pfs session_random renegotiation resumption ### ### redefine texts ### # Syntax # --cfg_text=KEY=VALUE # # the new (VALUE) string consist of all characters right to left-most = # all \n, \r and \t will be replace by corresponding character # # NOTE that @@ is a placeholder and will be replaced with actual value # NOTE that charater = will be lost if it is the last character in line # workaround: add space or \t # # Hint # o-saft.pl --help=text can be used to get all available texts. # # Examples below simply set texts to German. # #--cfg_text=cert-chars= <> #--cfg_text=cert-dates= <> #--cfg_text=cert-valid= <> #--cfg_text=cipher=Schlüssel #--cfg_text=desc=Beschreibung #--cfg_text=desc-check=Prüfergebnis ('yes' ist gut) #--cfg_text=desc-info=Wert #--cfg_text=desc-score=Score (max. Wert 100) #--cfg_text=disabled=<> #--cfg_text=EV-large= <<@@ zu groß>> #--cfg_text=EV-miss= <<@@ fehlt>> #--cfg_text=gethost= <> #--cfg_text=host-DNS=DNS Einträge für übergebenen Hostnamen #--cfg_text=host-host=Übergebener Hostname #--cfg_text=host-IP=IP des übergebenen Hostnamens #--cfg_text=host-rhost=Reverse resolved Hostname #--cfg_text=miss-ECDSA= <> #--cfg_text=miss-RSA= <> #--cfg_text=need-cipher=<> #--cfg_text=no-cert=<> #--cfg_text=no-dns=<> #--cfg_text=no-http=<> #--cfg_text=no-tlsextdebug= <> #--cfg_text=no-reneg= <> #--cfg_text=no-STS=<> #--cfg_text=out-checks=\n=== Prüfungen === #--cfg_text=out-ciphers=\n=== Schlüssel: prüfe @@ === #--cfg_text=out-infos=\n=== Informationen === #--cfg_text=out-list==== Liste @@ Schlüssel ==== #--cfg_text=out-scoring=\n=== Bewertung === #--cfg_text=out-summary=== Schlüssel: Zusammenfassung @@ === #--cfg_text=out-target=\n==== Zielsystem: @@ ====\n #--cfg_text=protocol=<> #--cfg_text=response=<> #--cfg_text=security=Sicherheit #--cfg_text=support=angeboten #--cfg_text=undef=<> #--cfg_text=wildcards= <> # # unknown option, to force warning "option with trailing spaces" # #--option=-with_trailing_spaces O-Saft-19.01.19/CHANGES000066400000000000000000001344321342117255600140550ustar00rootroot00000000000000 Version: 19.01.19 BUGFIX * t/Makefile.*: BT: macro ALL.inc.type corrected * osaft.pm: BF: +fingerprint_sha2 honors --format=hex * o-saft.pl: BF: printing header (for list of ciphers) corrected * o-saft.pl: BF: "Ciphers: Summary" prints correct numbers if no ciphers found * o-saft.pl: BF: --legacy=key disabled; --label=key enabled (honors --header option) CHANGES * t/Makefile.*: ET: targets simplified and unified; critic345 implemented * o-saft.pl: EF: +cipher results are sorted according "severity/security risk" NEW * o-saft.pl: NF: --help=cmd and --help=cfg-cmd added * o-saft.pl: NT: +session_startdate and +session_starttime added * o-saft.pl: NF: new option --legacy=owasp for +cipher * o-saft.pl: NF: new option --label=long|short|key * o-saft.pl: NF: alias commands for CVEs added * t/Makefile.misc: targets for profiling Version: 18.10.18 BUGFIX * o-saft-docker: use correct VERSION in docker_build() * o-saft-man.pm: output for --help=cfg-text correctd * o-saft-man.pm: HTML encode << ; CSS improved * o-saft.pl: warning added if https request failed * o-saft.pl: --exit=MAIN corrected * o-saft.tcl: value None not highlighted * o-saft.tcl: --docker and --id=* handled correctly * t/Makefile.opt: added (missed at github) * t/Makefile: message-% rule description to avoid syntax errors * Makefile: missing files t/Makefile.exit, t/Makefile.FQDN added to ALL.Makefiles * Makefile: dependencies for generated files improved CHANGES * o-saft-docker: docker_build() uses OSAFT_VM_SHA_OSAFT environment variable * contrib/build_openssl.sh renamed to contrib/install_openssl.sh * o-saft-dbx.pm: trace and verbose output use cfg{prefix_trace} and cfg{prefix_verbose} instead of cfg{mename} * t/Makefile.*: various minor bugfixes * Makefile: install target improved * Net::SSLinfo.pm: set https_body to private string if https request fails * osaft: call other tools with proper path * osaft.pm: cipher suites for RFC 8446 (TLS 1.3) added * o-saft-man.pm: new button to change schema in generated o-saft.cgi.html * o-saft-man.pm: online documentation in generated html improved * --help: section TESTING added * o-saft.tcl: using o-saft.pl in docker container improved * t/o-saft_bench renamed to t/o-saft_bench.sh * t/Makefile* improved NEW * "help"-Button foreach --help=* in o-saft.cgi.html * --help=cipherpattern added * options -comp and -no_comp implemented (OP_NO_COMPRESSION) * Makefile.help: cloc* target added * o-saft-man.pm: cgi and html page provides discrete commands * o-saft-man.pm: cgi page provides input fields for options with values * o-saft-man.pm: "return to top" button in generated .cgi.html added Version: 18.07.18 BUGFIX * o-saft: pass $* instead of $@ * o-saft-docker: check for image IDs corrected * o-saft-docker: ENTRYPOINT corrected; usage corrected * o-saft-docker: get correct number of ciphers from docker * o-saft.tcl: workaround for X error BadAlloc implemented * o-saft.tcl: highlight of code examples corrected * o-saft.tcl: size of help window adapted to larger font size * content of o-saft.tgz corrected (gernerated by makefile) * o-saft.pl: +cipher-dh requires openssl * o-saft.pl: use of $cfg{'openssl'}->{'-msg'} corrected * o-saft.pl: print warning when trying to read RC-file in cgi mode * o-saft.pl: avoid Use of uninitialized value in $CFG{sni_name} * o-saft.pl: avoid Use of uninitialized value in _init_openssldir() * o-saft-dbx.pm: avoid Use of uninitialized value $cfg{"sni_name"} * o-saft-man.pm: --help=html does not contain "start" buttons (like --help=cgi) * Net::SSLinfo.pm: initialize Net::SSLinfo::file_sclient * Net::SSLinfo.pm: verify_altname(); avoid uninitialized value * Net::SSLinfo.pm: verify_alias() CHANGES * +ocsp_response and +ocsp_stapling (check) implemented * print !!Hint when multiline data is not printed * "reading:" message only printed with --v or --warning * +vulns also contains: +compression +fallback +resumption +renegotiation * +compression is information (+info) and check (+check, +vulns) * o-saft-docker: build improved; build supports some environment variables * Dockerfile: handle master directory from github, move it to $OSAFT_DIR if found * Dockerfile: add -rpath flag to build SSLeay.so * o-saft_bench: write result on STDOUT instead of hardcoded file * o-saft_bench moved to test/ * INSTALL.sh renamed to INSTALL-template.sh; INSTALL.sh generated by Makefile * LHS condition check * contrib/INSTALL-template.sh: improved (--check, --openssl) * contrib/Dockerfile.alpine:3.6 renamed to contrib/Dockerfile.alpine-3.6 * Net::SSLhello.pm: better handling of SSL/TLS connection errors * prepared for +ccs NEW * o-saft.cgi: avoid infinite loop if no parameter given * o-saft.cgi: first parameter must be --cgi or --cgi= * contrib/build_openssl.sh * Makefile; complete test suite in test/Makefile* * INSTALL-template.sh * o-saft.tcl: +quit option (for usage in Makefiles) * o-saft.tcl: scrolling with keys and mouse whell in help window implemented * o-saft-man.pm: --help=exit implemented * o-saft-man.pm: POD added * o-saft: modes/options -gui -cli -docker added * o-saft-docker: mode sshx to tunnel X suing ssh Version: 18.01.18 BUGFIX * markup for generated documentation corrected * various Perl warnings (in rare runtime situations) fixed * hostname, SNI and certificate subject checks are case insensitive CHANGES * --help=tools added to give an overview of all tools comming with O-Saft * use of $cfg{'sni_name'} and $cfg{'usesni'} improved (--sni --no-sni --sniname= ) * SSLv3 cipher checks are done without SNI (automatically disabled just for SSLv3) * simple connection check to avoid "hanging" connection * documentation moved from o-saft-man.pm to OSaft/Doc/help.txt * Net::SSLinfo.pm: treat "failed handshake" only as error when * Net::SSLinfo::ignore_handshake is not set * contrib/zap_config.xml: description improved * +version prints starting directory (PWD) * +sni command contains +certfqdn * detecting host and port improved * use relative instead of absolute timestamps for --traceTIME NEW * wrapper script: o-saft * --traceCLI option added * --std-format= options implemented (allows generating files with any charset) * o-saft.tcl: write result of o-saft.pl in Tcl table (experimental) * +robot ROBOT added * --ignore-handshake implemented * --time-absolut to write absolute timestamps for --traceTIME Version: 17.11.17 BUGFIX * o-saft.cgi: IPv6 addresses are not allowed * do not print prefered cipher for SSLv2, as it has no such cipher * no warning (401) for SSLv2 selected cipher * do not complain about cipher mismatch (warning 411) for SSLv2 * missleading hint message for WARNING 126 corrected * check for bit-length of serial number corrected (approx aproach) CHANGES * --help=cgi generated HTML for cgi usage improved * +protocols and +vulns documentation added * warnings and hints improved if SNI used with/for SSLv3 * remove non-printable characters from HTTPS Status line * Dockerfile: build Net::SSLeay and IO::Socket::SSL based on enhanced openssl-chacha * +cipherall uses same output format as +cipher * documentation improved NEW * o-saft.tcl: trace implemented; option --trace Version: 17.09.17 BUGFIX * bugfix: avoid sub-subdomain matching againt subdomain wildcard * bugfix: BEAST check (https://github.com/OWASP/O-Saft/pull/99) * Net::SSLinfo.pm: support timeout commands which require -t option (BusyBox) * Net::SSLinfo.pm: handle binary IP address in certificate's altname attribut * regex to detect port numbers in URL: {1,5} quantifier instead of {1-5} * Dockerfile: install perl-readonly for alpine also CHANGES * Dockerfile build openssl with GOST and KRB5 ciphers (for alpine:edge) * Dockerfile supports environment variables * Net::SSLinfo.pm: checking for Alt-Svc, X-Firefox-Spdy headers improved NEW * o-saft-docker: checks for proper installed images * o-saft-docker: rmi command implemented; status command improved Version: 17.07.17 BUGFIX * +tr-02102+ corrected (len_sigdump check) * check for redirect HTTP to HTTPs corrected (+http_https) * Net::SSLinfo.pm: do_ssl_new() improved (avoid "Segmentation fault" or "double free or corruption .. Abort" in rare cases) * o-saft.pl: setting ALPN and NPN options with Net::SSLeay improved (avoid "Segmentation fault" in rare cases) * warning message for --experimental corrected * avoid perl warning "Argument isn't numeric" for +tr_02102 checks * osaft.pm: export printhint() * print hint for +info commands also CHANGES * check for heartbleed only if requested * hint for DROWN check added * error and warning messages have a unique number * print warning for trailing spaces in options read from RC-file * contrib/gen_standalone.sh: generates working script * *.pl and *.om improved for use with contrib/gen_standalone.sh * o-saft-lib.pm: initialization of %cfg with dynamic data done in _osaft_init() * trace output improved * contrib/* more examples added NEW * --connect-delay implemented * --cipher-range=* implemented for +cipher command * OSaft/Doc/Glossary.pm, use OSaft::Doc::Rfc * contrib/JSON-*.awk * o-saft-lib.pm: new cipher-ranges: c0xx, ccxx, ecc * +host command (to display host and DNS information) added * --exit=WARN implemented * --v prints each checked cipher for +cipher * more aliases for commands and options added (mainly from testssl.sh) * new options: --hint-check and --hint-info Version: 17.06.17 BUGFIX * counting exitcode for -exitcode corrected * reading +commands from RC-FILE CHANGES * names of +cipher* commands unified * cfg{ciphers_openssl} --> cfg{ciphers_local} NEW * --rc=path/to/RC-FILE added * --cfg-cipher=CIPHER=TEXT added * +rfc_2818_names implemented * +subjectaltnames added (alias) Version: 17.05.17 BUGFIX * o-saft-lib.pm: missing commands added to need-cipher list * --protosnpn=, corrected * +selected does not need to check for all ciphers * enable ALPN and NPN when testeing for ciphers (+cipher) * NET::SSLinfo.pm: passing -alpn and -nextprotoneg option to openssl corrected CHANGES * missing ciphers and missing cipher descriptions added * +info does no onger complain for missing ALPN/NPN functionality * NET::SSLinfo.pm: checks improved to detect handshake fail for HTTPS * NET::SSLinfo.pm: ::next_protos replaced by ::alpn_protos and ::npn_protos * check and warning messages for available functionality improved NEW Version: 17.04.17 BUGFIX * NET::SSLinfo.pm: avoid "Segmentation fault" when connection fails * NET::SSLinfo.pm: pass errors from openssl to caller (simple workaround) * label texts corrected for modulus_size_oldssl and modulus_exp_oldssl * print correct OpenSSL version for +version * do not load NET::SSLinfo for +cipherraw * o-saft-lib.pm: +lucky13 requires a cipher check: added to list * 'need-cipher' CHANGES * NET::SSLinfo.pm: %_OpenSSL_opt and s_client_*() for openssl capabilities * implemented * NET::SSLinfo.pm: internal method _stcmd improved * o-saft.pl: warning message improved if connection without SNI fails * o-saft.pl: --ignore-no-reply option added for more proper +heartbleed check * o-saft.pl: +modulus_exp_size renamed to +modulus_exp_oldssl * o-saft.pl: +modulus_size renamed to +modulus_size_oldssl * o-saft.pl: -trace-time improved * o-saft.pl: +npn renamed to +hasnpn; label texts adapted * o-saft-lib.pm: @npn renamed to cfg{next_protos}; cfg{usealpn} and cfg{usenpn} added * documentation improved * _load_modules(), _check_versions(), _check_methods() implemented NEW * NET::SSLinfo.pm: new function _ssleay_ssl_np() to set ALPN and NPN option * NET::SSLinfo.pm: do_ssl_new() and do_ssl_free() implemented * --ssl-error --ssl-error-max --ssl-error-timeout implemented * o-saft.pl: +alpn and +npn implemented * o-saft.pl: remove leading spaces for options when reading .o-saft.pl * o-saft.pl: better checks for ancient perl modules; documentation improved * .o-saft.pl: new command +fingerprints * o-saft.tcl: --load=FILE option implemented Version: 17.03.17 BUGFIX * bugfix: remove eading spaces in some values * Net::SSLeay.pm: set NPN option when used with sockets * "use of uninitialized value" at _useopenssl() call * assume CGI mode with --cgi-exec * better check of cfg{ca_path} (avoid uninitialized value) * wrong ca_path instead of ca_paths in trace output * don't complain "need Time::Local module for this check" CHANGES * +ocsp (check) command renamed to +ocsp_uri * +ocsp-subject-hash +ocsp-public-hash * o-saft-man.pm: HTML generated by --help=cgi improved * o-saft-man.pm: improved for --help=cgi (Full GUI) * o-saft-man.pm: improved for --help=cgi (Simple GUI) * Net::SSLinfo::::protocols renamed to ::next_prots * check withh --yeast-data improved * better check for Time::Local * +version reports information about Time::Local * documentation for options improved NEW * +ocsp (in .o-saft.pl) * +fingerprint_sha2 * osaft.pm: @npn - list for NPN added Version: 17.01.17 BUGFIX * avoid useless data checks for +info command * no heartbleed check for +info * output format for +ocspid corrected * Net::SSLinfo.pm: parsing and extracting data for ocsp* corrected * Net::SSLinfo.pm: ocspid fully returned (workaround for openssl problem with "x509 -ocspid") * +selfsigned returns correct value (yes) if not self signed * +fingerprint_type returns type without additional strings * using path for --ca-path corrected CHANGES * --exitcode counts weak ciphers and protocols also * .o-saft.pl: documentation improved * +fingerprint_sha is alias for +fingerprint_sha1 NEW * options --exitcode-no-* implemented * options --file-sclient= and --file_pem= added * +fallback_protocol implemented * options -CAfile and -CApath (as alias) added Version: 16.12.16 BUGFIX * processing commands and options improved (more variations allowed) * avoid crash if IO::Socket::SSL::get_sslversion() is missing * close and open socket if SSL connection failed * avoid "Segmentation fault" when X509 data is missing * avoid "Segmentation fault" when $x509 is empty or undef CHANGES * checking for (default) selected cipher improved * better error handling if connection to target fails * o-saft-man.pm: layout for +help=* commands improved * o-saft-dbx.pm: print exitcode with --trace only * Net::SSLinfo.pm: set user-specified timout for TCP and SSL connection NEW * +fingerprint-sha2 implemented * +cipher-default implemented * --rc option implemented * --socket-reuse added and implemented * o-saft.tcl: STDOUT button added * contrib/zap_config.xml added Version: 16.11.16 BUGFIX * avoid perl warning when checking certificate dates * better check for ext_crl and ocsp_uri (avoid perl warnings) * osaft.pm: regex->TR-02102 corrected * .o-saft.pl: cmd-info should not contain selected CHANGES * o-saft-man.pm: comments? description for TR-02102-2 (2016-01) instead of TR-02102-2 (2013-01) Version: 16.11.14 BUGFIX * Net::SSLinfo.pm: avoid "Segmentation fault" if $x509 is empty or undef * avoid "Use of uninitialized value ..." in some rare cases * *ARIA-* cipher descriptions improved CHANGES * Net::SSLinfo.pm: support modern Net::SSLeay::CTX_* methods * Net::SSLinfo.pm: better check if X509 certificate data is available * Net::SSLinfo.pm: test_ssleay -> ssleay_test NEW * Net::SSLinfo.pm: new ssleay_methods() Version: 16.09.29 BUGFIX * avoid "Use of uninitialized value ..." for $version::VERSION (see issue 51) * PSK-* cipher descriptions improved; PSK-* cipher descriptions improved * check for CN improved (DV and EV certificates) * contrib/.o-saft.tcl: syntax error corrected * some regex non-capturing groups corrected (parsing options only) CHANGES * commands for cipher checks unified (+*_cipher); alias commands added * check for CRIME improved (SPDY/3 is vulnerable) * Net/SSLinfo.pm: sequence for "nextprotoneg" reversed (weakest first) NEW * searching documentation improved * return exit status for checks with result with option --exitcode * +cnt_checks_no and +cnt_checks_yes implemented * +cbc_cipher and +des_cipher command added * ARIA ciphers descriptions added * cfg(TKPOD) added (external viewer for POD files) Version: 16.09.16 BUGFIX * filter scripts contrib/* adapted to new formats; print all lines CHANGES * files removed: generate_ciphers_hash, openssl_h-to-perl_hash, INSTALL-devel.sh NEW * INSTALL.sh Version: 16.08.01 BUGFIX * print warning if OPENSSLDIR is missing (see https://github.com/OWASP/O-Saft/issues/29 ) * remove trailing path when compareing FQDNs * output for --legacy=compact corrected (bug since 1.407) * handle arguments after --trace option correctly * don't call openssl if not available * avoid "uninitalited value" in checks if no certificate data is available CHANGES * --v print performed cipher checks * better check of required versions; warning messages unified * o-saft-man.pm: "Using outdated modules" section added; documentation improved NEW * o-saft.tcl: quick access for O-Saft options added * Net::SSLinfo.pm: detect more SPDY protocols (h2c,npn-spdy/2) and X-Firefox-Spdy Version: 16.08.01 BUGFIX * handle missing data in .o-saft.tcl properly * bugfix: on some Mac OS X tk_getSaveFile has no -confirmoverwrite option CHANGES * use IO::Socket::SSL without version, but warn if not sufficient * o-saft.tcl: layout improved NEW * Sweet32 implemented and added to glossar * HEIST added to glossar Version: 16.06.01 BUGFIX * check for supported ciphers uses full match * parsing X509 data improved (avoids: Use of uninitialized value ...) * missing host and port parameter added in some check* functions added * +sts_maxage0d checks corrected (check if STS reset aka max-age=0) * o-saft.tcl: do not set tooltip if fontchooser misses * do not print Cipher Summary for legacy formats * print selected ciphers from --legacy=format only once * allow mixed case in customized texts (--cfg-*= options) * --legacy=sslscan without perl warnings * some texts corrected in o-saft.tcl CHANGES * o-saft.tcl: better detection of section header lines in help * o-saft.tcl: context sensitive help buttons * o-saft.tcl: hash-bang line improved * o-saft-README disabled as most people are not willing to read it * critic.sh: check for potential repository files and skipp check for them NEW * Sweet32 implemented and added to glossar * HEIST added to glossar * new commands can be added with --cfg-cmd=* * +hsts_httpequiv +hsts_preload added * o-saft.tcl: home, back, next button added Version: 16.05.10 BUGFIX * print properly aligned text for --help=cfg-* * output for "Total number of checked ciphers" corrected * +ciphers command honors --legacy option * avoid perl warning "Argument isn't numeric" when getting bits of a cipher CHANGES * --help=* simplified (formal change) * printing of internal data with --help=* simplified and unified * --cfg-* settings improved * print Hint for +renegotiation check * Net::SSLinfo.pm: new variables: starttls and proxy* NEW * --help=hint implemented * --hint and --no-hint implemented * man_alias() implemented for --help=alias * man_pod() implemented for --help=gen-pod * Version: 16.04.14 CHANGES * %cfg no defined in osaft.pm only * use !!Hint instead of **Hint * description for compliance checks improved NEW * +crl_valid, +ocsp_valid: check if CRL and OSCP from certificate are valid * +rfc7525 implemented * contrib/.o-saft.tcl Version: 16.04.02 CHANGES * perlcritic: eval, grep with block form * perlcritic: use lexical loop iterator * documentation improved * o-saft.tcl: table of content improved for help * o-saft.tcl: don't show button for empty configuration window NEW * --checks implemented (compatibility with TLS-Check.pl) * osaft_sleep() as wrapper for IO::select added * +sts_expired added: STS max-age < certificate's validity * new options --starttls-phase* and --starttls-error* * contrib/critic.sh added Version: 16.03.30 BUGFIX * Net/SSLinfo.pm: prototypes for do_openssl() and do_ssl_open() corrected * Net/SSLhello.pm: constants added; $me* variables removed * Net/SSLhello.pm: setting _trace variable in version() removed NEW * Net/SSLinfo.pm: dummy function net_sslinfo_done() added * Net/SSLhello.pm: dummy function net_sslhello_done() added Version: 16.03.27 CHANGES * o-saft.pl: configuration moved to osaft.pm NEW * +drown check for DROWN attack vulnerability Version: 16.03.26 CHANGES * o-saft.pl: configuration moved to osaft.pm Version: 16.03.16 BUGFIX * duplicate hint message for +quit corrected CHANGES * o-saft-dbx.pm: _yeast_args() improved * o-saft-man.pm: Program Code documentation improved * o-saft-man.pm: typos corrected and more glossar NEW * o-saft-man.pm: hint to check Net::SSLeay methods added to INSTALLATION * --slow-server-delayand --sni-toggle added Version: 16.01.16 BUGFIX * duplicate hint message for +quit corrected CHANGES * most configuration now in osaft.pm NEW * experimental: SLOTH check * contrib/bunt.pl: postprocess script to colourize shell output * contrib/bunt.sh: postprocess script to colourize shell output Version: 30.12.15 BUGFIX * do not print cipher summary if no ciphers were checked * --help=wiki prints wiki list items with leading : (colon) * pretty-print path in output for +version CHANGES * USAGE improved; no more +cipher as default command * checking DH parameters simplified * +version prints path of included (use) module * _trace_1arr() renamed to _trace_cmd() * INSTALLATION section improved * help: SECURITY section moved to top * collect *ARG* variables in %cfg for debugging * o-saft_bench: output format improved; accept host as parameter NEW * description for some more CHACHA cipher suites added * --exit=* for debugging implemted * --trace-me and --trace-not-me implemented * +cipher-sh implemented * o-saft-man.pm: INSTALLATION section Version: 15.12.15 BUGFIX * some command aliases corrected * label for protocols corrected CHANGES * report ciphers with DH parameters if possible * description of compatibility options improved NEW * description for KCI and Invalid Curve Attack * new options --format=0x and --format=\x * more command aliases Version: 15.11.15 BUGFIX * o-saft-dbx.pm: avoid infinite loop for trace>2 CHANGES * avoid warning if protocol disabled: cannot get default cipher * warning if openssl does not return DH parameters * checking DH paramters improved * workaround to avoid perl (Net::SSLeay) warnings for unsupported protocols NEW * --help=error --help=warning --help=problem added Version: 15.10.15 BUGFIX * Net::SSLinfo.pm: call Net::SSLeay::CTX_set_ssl_version() corrected * Net::SSLinfo.pm: alpn(), next_protocol() added * Net::SSLinfo.pm: handling of hex conversion on poor 32-bit systems improved * o-saft.tcl: quick & dirty fix to simplefy startup on Mac OSX CHANGES * o-saft.pl: checking protocols (and default) cipher improved * o-saft-dbx.pm: debug output improved * o-saft.tcl: layout improved * Net::SSLinfo.pm: more alternate protocols NEW * --linux_debug and --slowly option (passed to Net::SSLeay) * o-saft.pl: print hint about using +cipherall * o-saft.tcl: new Filter TAB; more filter rules * o-saft.tcl: more verbose output added Version: 15.09.15 CHANGES * output for +version improved * use perl constants for some strings in o-saft.pl * o-saft.tcl improved * respect --no-header option for output of --help=* * documentation, glossar improved NEW * new command +help=ourstr to print regex for matching own strings * logjam implemented Version: 15.06.19 BUGFIX * handle checks for EC public keys correctly * DTLSv09 is 0x0100 * missing shorttexts added * support serial number in hex format; use Math::BigInt if necessary * check for +sernumber corrected CHANGES * all o-saft-*.pm print help if called by themselfs NEW * dh_parameter implemented * detect id-ecPublicKey as known and good encryption * support public key with EC parameters * DTLSv1x added (experimental) * +modulus_exp_size +modulus_size and +pub_encryption implemented Version: 15.06.09 BUGFIX * setting of path for CAs corrected (when --openssl=Tool is used) * using --openssl=TOOL corrected CHANGES * use VERSION as string constants * using string constants NEW * _yeast_prot() implemented in o-saft-dbx.pm * +session_protocol added to +protocols * +session_protocol +session_timeout added * improved +version Version: 15.05.15 Version: 15.04.15 CHANGES * o-saft.tcl markup for help text improved * support proxy and STARTTLS (no longer experimental) NEW * prepared for RFC 7525 check Version: 15.04.05 CHANGES * some texts for compliance texts changed NEW * --ignore-{cmd,output, --no-{cmd,output} implemented Version: 15.04.04 CHANGES * o-saft-dbx.pm: added $cfg{'ignore-out'} Version: 15.04.02 BUGFIX * check for wildcards in certificate's CN also Version: 15.01.07 BUGFIX * avoid huge memory consumtion (fix for issue/39) CHANGES * command line parsing improved NEW * new files in contrib/ Version: 14.12.07 * new tarball Version: 14.11.23 BUGFIX * text for checks{hostname} corrected (check was ok, but proided text not accurate) CHANGES * cipherrange vor SSLv2 improved NEW * pass --mx option to SSLhello * pass --starttls-delay=SEC option to SSLhello * Net::SSLinfo hostname for SNI can be specified in $Net::SSLinfo::use_SNI * --sni-name=NAME added Version: 14.11.22 BUGFIX CHANGES * o-saft-man.pm: generating various formats improved NEW * new check: Certificate private key signature is SHA2 * .o-saft.pl new check sha2signature added to +check and +quick Version: 14.11.21 BUGFIX * missing useecc parameter passed to Net::SSLhello * --h same as --help * better handling of results for +sigkey_algorithm NEW * --use-ec-point option passed to Net::SSLhello Version: 14.11.20 CHANGES * get VERSION for --help from caller NEW * o-saft-man.pm Version: 14.11.19 CHANGES * documentation improved NEW * o-saft-man.pm Version: 14.11.18 CHANGES * markup in documentation improved Version: 14.11.17 BUGFIX * check version mismatch Version: 14.11.16 CHANGES * beast-default removed Version: 14.11.15 NEW * --help=opt and --help=options implemented Version: 14.11.14 NEW * check for Poodle attack * --trace-time implemented * o-saft-dbx.pm: trace command prints timestamp for --trace-time * options for +cipherraw command documented BUGFIX * --showhost print host:port * keys in internal hashes in lower case letters * .o-saft.pl: duplicate commands in -cfg_cmd=check removed CHANGES * _yeast_init() prints SSL versions to be checked with --v * .o-saft.pl: list of commands for +quick improved Version: 14.10.12 NEW * --cipherrange=shifted Version: 14.07.27 CHANGES * formal changes Version: 14.07.26 BUGFIX * @INC set in BEGIN{} Version: 14.07.25 CHANGES * using (require) modules and files simplified; documentation improved * warnings unified and improved * o-saft-usr.pl: usr_version() and usr_pre_init() added; formal (name) changes NEW * +TLS_FALLBACK_SCSV added * +VERSION implemented Version: 14.07.18 CHANGES * +ciphers and +list command improved (handle different output formats) Version: 14.07.17 BUGFIX * corrected output (counts) for command +list --v CHANGES * cipher descriptions improved; missing descriptions added * print version mismatch (openssl vs. Net::SSLeay) * lazy commands added Version: 14.07.16 BUGFIX * avoid uninitialized value and WARNING messages for some commands CHANGES * options -v and -V improved * formal changes Version: 14.07.15 BUGFIX * avoid uninitialized value in +list command Version: 14.07.14 CHANGES * cipher descriptions improved; security and score qualification adapted Version: 14.07.07 CHANGES * check for low memory * backticks replaced by qx() Version: 14.06.30 CHANGES * TECHNICAL INFORMATION added NEW * --starttls=PROT added (experimental) * --ssl-maxciphers added Version: 14.06.16 BUGFIX * printing warnings enabled CHANGES * --experimental option added Version: 14.06.15 CHANGES * formal changes Version: 14.06.14 BUGFIX CHANGES * printmediawiki() moved to o-saft-usr.pm::usr_printwiki() * commands unified: +gen-html +gen-wiki +gen-cgi Version: 14.06.13 BUGFIX * bugfix: parsing --trace (without argument) corrected (bug since 14.06.08) * honor --noSSL options for +cipherraw command CHANGES * improvements for CGI usage; internal option --cgi-exec * formal changes in documentation Version: 14.06.12 CHANGES * avoid error messages when gethostbyaddr() fails Version: 14.06.11 CHANGES * store all --usr* options and arguments in $cfg{'usr-args'} Version: 14.06.10 BUGFIX * avoid perl's uninitalized value after GET request * +cipher and cipherraw (commnad line parsing) corrected * no SNI for SSLv3 with +cipherraw Version: 14.06.08 CHANGES * --no-rc option added * scanning options and arguments from command line simplified and improved NEW * --help=range implemented * +quit command implemented Version: 14.06.07 CHANGES * -ssl-* options for +cipherraw command added; check with and without SNI for +checkraw Version: 14.06.05 CHANGES * +version improved (print more informations about Net::SSLeay) Version: 14.06.04 BUGFIX * bugfix: print usage with correct script name Version: 14.06.01 NEW * --cipherrange=RANGE implemented; +cipherall supports full range Version: 14.05.31 CHANGES * print $Net::SSLhello::VERSION with --trace and --version Version: 14.05.27 BUGFIX * using scalar() instead of length() for array Version: 14.05.26 NEW * --help=wiki implemented Version: 14.05.25 CHANGES * avoid some check warnings for +cipherall Version: 14.05.24 NEW * --no-md5-cipher implemented (avoids some error messages) Version: 14.05.23 BUGFIX * avoid some checks and connections if not required by given command Version: 14.05.22 CHANGES * better compatibility to ssldiagnose.exe * compatibility ssl-cert-check, THCSSLCheck NEW * +constraints check implemented * --protocol SSL implemented; better compatibility to ssldiagnose.exe * --printavailable as alias for +ciphers Version: 14.05.21 BUGFIX * +ciphers command re-enabled Version: 14.05.21 NEW * +tlsextensions implemented Version: 14.05.20 CHANGES * +ext_* commands enabled * more TLS extensions added Version: 14.05.17 BUGFIX * parsing command line argunents improved Version: 14.05.16 CHANGES * output for --legacy=compact improved Version: 14.05.15 CHANGES * output for --tracecmd improved * output for --no-http improved * passing options and arguments to openssl improved Version: 14.05.14 CHANGES * detect more TLS extensions; +heartbeat and --no-tlsextdebug implemented Version: 14.05.13 NEW * prepared for TLSv1.3 Version: 14.05.12 NEW * +cipherall implemented with Net/SSLhello.pm; ALPHA version! * Net/SSLhello.pm Version: 14.05.11 CHANGES * some missing cipher descriptions added Version: 14.05.10 BUGFIX * "None" values are mainly treated as "no" for checks Version: 14.05.09 BUGFIX * setting default +cipher command corrected if no command given * bugfix: avoid "Broken Pipe" if connection fails Version: 14.05.08 BUGFIX * CHANGES * o-saft-dbx.pm: _yeast_init() improved Version: 14.05.07 BUGFIX * missing descriptions for KRB5* ciphers added Version: 14.05.07 CHANGES * print warning for invalid command combinations (defense, user-friendly programming) Version: 14.05.06 NEW * --ssl-lazy option implemented Version: 14.05.05 NEW * --no-warning implemented Version: 14.04.28 NEW * +cipherall ALPHA version implemented Version: 14.04.27 CHANGES * more _trace*() functions added Version: 14.04.26 NEW * --proxy* options added (but no functionality) Version: 14.04.24 BUGFIX * output corrected for --showhost --legacy=full CHANGES * improved path settings for windows Version: 14.04.10 NEW * +heartbleed implemented Version: 14.02.17 BUGFIX * +sts implies --http * +sts command re-implemented Version: 14.02.01 BUGFIX * use SNI if possible for cipher checks (+cipher command) CHANGES * +version improved NEW * --force-sni added Version: 14.1.31 CHANGES * code cleanup Version: 14.1.30 CHANGES * --cipher no longer alias for +cipher so we can support "--cipher CIPHER" option Version: 14.1.29 CHANGES * code cleanup for checkciphers() * check Net::SSLeay::cipher_local() can return array * check Net::SSLeay::VERSION < 1.49 Version: 14.1.28 CHANGES * +default can get cipher using openssl Version: 14.1.27 BUGFIX * parsing options and commands improved CHANGES * documentation improved * +quick command uses common output format (instead of --legacy=quick) Version: 14.1.26 CHANGES * typos documentation corrected NEW * --call=METHOD implemented Version: 14.1.25 CHANGES * allow --exe-path=PATH and --lib-path=PATH * --lib= and --exe= can be used multiple times * debugging improved; _yeast_args() added; _yeast_init() improved Version: 14.1.24 CHANGES * allow --exe-path=PATH and --lib-path=PATH * --lib= and --exe= can be used multiple times * debugging improved; _yeast_args() added; _yeast_init() improved Version: 14.1.23 BUGFIX * +pfs command enabled CHANGES * SSL protocol options (SSL version, cipher list) improved * collecting SSL information improved NEW * commands +options +sslversion +cert_type +error_verify +error_depth Version: 14.1.22 BUGFIX * +default command enabled * avoid uninitialized value CHANGES * set SSL protocol version for connections * Net::SSLinfo::do_ssl_close() with version list parameter Version: 14.1.21 NEW * existing socket for connection can be provided with $Net::SSLinfo::socket * usr_pre_open() added Version: 14.1.12 UPDATE * get list of ciphers improved: cipher_list() uses Net::SSLeay::new() to get list of ciphers NEW * new sub usr_pre_info() in o-saft-usr.pm Version: 14.1.4 BUGFIX * bugfix: regex for pubkey_value on windows * bugfix: empty len_public_key and len_sidump on windows corrected UPDATE * documentation improved Version: 14.1.3 BUGFIX * bugfix: avoid perl warning for +cipher * bugfix: avoid perl warning in Net::SSLinfo::do_openssl() Version: 14.1.2 BUGFIX * bugfix: avoid perl warning in Net::SSLinfo::do_openssl() Version: 14.1.1 NEW * option --win-CR implemented Version: 13.12.31 BUGFIX * bugfix: separator in output for --trace-corrected * bugfix: no checks for master_key and session_id to avoid perl warnings * bugfix: initialization of check values corrected UPDATE * Net::SSLeay initialization inside BEGIN{} * use Net::SSLeay::set_tlsext_host_name() for SNI Version: 13.12.30 BUGFIX * check for +ev improved NEW * +dv command and checks added Version: 13.12.29 BUGFIX * bugfix: missing \n added when printing checks with --legacy=full UPDATE * check for CN= in checkev() * +ev improved * special handling for +ev removed (use --legacy=full now) Version: 13.12.28 NEW * +chain_verify command added * documentation according +verify, +selsigned added Version: 13.12.27 NEW * options --ca-file --ca-path --ca-depth implemented Version: 13.12.26 BUGFIX * print hostname correctly with --showhost * reset checks when multiple hosts are given * --tracekey and --showhost was missing for +check Version: 13.12.25 NEW * --usr option for o-saft-usr.pm implemented * new file o-saft-usr.pm Version: 13.12.24 NEW * --tab option added * contrib file Version: 13.12.21 UPDATE * --help=cfg_{check,data,text} and --cfg_{check,data,text}= implemented the same way Version: 13.12.20 UPDATE * don't read external files in CGI mode Version: 13.12.19 UPDATE * formal changes * --yeast implemented to call _yeast_data() * _yeast_data() improved; documentation improved in o-saft-dbx.pl * don't read external files in CGI mode Version: 13.12.18 UPDATE * --cfg_* configuration options implemented * CUSTOMIZATION description added Version: 13.12.17 UPDATE * samples to redefine texts in Deutsch added in .o-saft.pl * --cfg_text* implemented * print internal data with --help=* simplified * --set-score renamed to --cfg_score Version: 13.12.16 Version: 13.12.15 BUGFIX * (issue 16) define $_timeout variable when missing (Mac OS X problem) * reading score values from files corrected; allow + in score settings UPDATE * get subject_hash and issuer_hash from Net::SSLeay * commands issuer and issuer_hash added to --cfg_cmd-info in .o-saft.pl NEW * +chain to retrive Certificate Chain implemented * +protocols to retrive supported protocols by target (requres openssl with -nextprotoneg support) Version: 13.12.14 NEW * Serial Number <= 20 octets (RFC5280, 4.1.2.2. Serial Number) * new commands len_sernumber and sernumber added to --cfg_cmd-check in .o-saft.pl Version: 13.12.13 UPDATE * documentation improved (better English) Version: 13.12.12 BUGFIX * error handling for DNS corrected (if something failed) * no scoring for +info (avoids some "unitialised" warnings too) * avoid some warnings with --cmd-* in .o-saft.pl * reverse hostname computation corrected * --cfg_cmd-check withoud valid command in .o-saft.pl NEW * --cfg_cmd-quick added in .o-saft.pl Version: 13.12.11 BUGFIX * STS check corrected UPDATE * +http improved * huge code cleanup; checks improved; scoring now in sub scoring() * Net/SSLinfo.pm: hsts_pins renamed to https_pins; hsts renamed to https_sts NEW * o-saft-README file implemented * o-saft-dbx.pm with functions for debug, trace and verbose output * .o-saft.pl as local resource file implemented * --cfg_text-* and --cfg_cmd-* options implemented Version: 13.12.09 UPDATE * duplicate messages removed Version: 13.12.08 BUGFIX * bugfix: check for renegotiation and resumption corrected UPDATE * --no-header avoids printing most formating lines Version: 13.12.07 BUGFIX * --showhost works for +check too * checks corrected if --no-http was used * checks improved if --no-cert was used * bugfix: missing (..) added in sub checkhttp UPDATE * code cleanup and simplified, all %check_* --> %checks * documentation improved NEW * --help=cmd, --help=commands, --help=intern Version: 13.11.30 UPDATE * _yeast_data() implemented; documentation improved for o-saft-dbx.pm * cleanup for texts Version: 13.11.29 BUGFIX * some warnings (perl -w) corrected (for --no-cert option) UPDATE * code cleanup for checkssl() * output for +check sorted * output improved for --no-cert option Version: 13.11.28 UPDATE * check hostname vs. certificate name improved Version: 13.11.27 UPDATE * omit cipher checks if protocoll not supported for BSI TR-02102 Version: 13.11.26 BUGFIX * better extraction of certificate extensions details NEW * check invalid characters in extensions added Version: 13.11.25 BUGFIX * checks for CRL, OCSP corrected; * missing EV checks for AIA, CRL and OCSP added * ouput of certificate extensions corrected NEW * commands for details of certificate extensions added ext_authority, ext_cps, ext_crl, ... Version: 13.11.23 NEW * +extensions implemented; --header, --no-header implemented Version: 13.11.22 BUGFIX * print cipher totals for all versions; some texts unified Version: 13.11.21 BUGFIX * "Given hostname is same as reverse resolved hostname" ccorrected * check for wildcards in TR-02102-2 compliance corrected * +info--v command fixed; _dump() call UPDATE * texts and output layout unified; prepared for configurable texts * debug, trace and verbose functions are emty stubs, now in o-saft-dbx.pm NEW * o-saft-dbx.pm with functions for debug, trace and verbose output Version: 13.11.20 UPDATE * texts and output layout unified; prepared for configurable texts * certificate's date checks improved Version: 13.11.19 BUGFIX * some warnings (perl -w) corrected * perl warnings fixed for +version command UPDATE * --trace command improved * function calls unified * using temporary variables for better (human) readability NEW * --trace=VALUE implemented; --trace-cmd implemented Version: 13.11.18 UPDATE * function calls unified * using temporary variables for better (human) readability Version: 13.11.17 BUGFIX * missing labels in output added * +bsi does not inhibit other checks * +quick with more check (got lost with implementation of +bsi) UPDATE * some labels in output improved * +quick improved with labels Version: 13.11.16 UPDATE * missing security flag for some ciphers added; documentation improved Version: 13.11.15 UPDATE * RC4 ciphers degraded as weak Version: 13.11.14 UPDATE * documentation and glossar improved Version: 13.11.13 NEW * compliance check: BSI TR-02102 implemented; command +bsi Version: 13.11.12 UPDATE * glossar improved Version: 13.11.11 BUGFIX * parsing altname in certificate corrected UPDATE * +sts alias for +hsts NEW * check for RC4 implemented Version: 13.10.22 UPDATE * retrive target data for: krb5 psk_hint psk_identity srp master_key session_id session_ticket Version: 13.10.20 BUGFIX * connecting with openssl improved for openssl 1.0.1.e UPDATE * --v honored in various modes * --format=hex includes +fingerprint NEW * reading options and arguments from rc-file implemented Version: 13.10.19 BUGFIX * more improvements for perl's -w * Net::SSLinfo::do_openssl() uses optional $data parameter; code improved Version: 13.10.18 BUGFIX * bugfix: variable syntax corrected; more improvements for perl's -w Version: 13.10.17 BUGFIX * code improved for perl's -w Version: 13.10.16 BUGFIX * syntax improved for ActivePerl UPDATE * INSTALLTION part added to README file Version: 13.10.14 BUGFIX * --cmd=quick is same as +quick * --help=checks instead of --help=check Version: 13.10.11 BUGFIX UPDATE * --v honored in various modes * --format=hex includes +fingerprint NEW * description for CIPHER NAMES Version: 13.09.29 BUGFIX * check --envlibvar= option * +cipher command corrected UPDATE * fomal code changes in checkciphers() NEW * --force-openssl implemented to use openssl for cipher checks Version: 13.09.28 BUGFIX * s_client command corrected * PFS check label text corrected * Net::SSLinfo::do_openssl() supports ciphers command correctly NEW * EV-SSL checks implemented * +subject_ev implemented Version: 13.09.27 UPDATE * minor changes of output texts NEW * --format=hex implemented Version: 13.09.25 UPDATE * regex and check for compliance and attacks improved Version: 13.09.16 BUGFIX * label for EDH check corrected * RegEx ADHorDHA and DHEorEDH corrected UPDATE * glossar improved NEW * --format=raw implemented Version: 13.09.15 BUGFIX * +list command exits NEW * check for CRIME implemented Version: 13.09.14 BUGFIX * BEAST check for default cipher corrected Version: 13.09.13 UPDATE * documentation improved * huge amount of code cleanup (no change of functionality) Version: 13.09.12 not released Version: 13.09.11 BUGFIX * reverse hostname lookup corrected; now prints list * print host (target) information before doing checks UPDATE * be greedy to allow +BEAST, +CRIME, etc. * cipher names are prependet by SSL version in +check output * documentation (COMMANDS, OPTIONS) improved * legacy option improved NEW * -no-dns implemented (workaround for ') * %cfg{regex} added Version: 13.09.10 BUGFIX * output for some legacy formats corrected (sslscan, ssltest, sslyze) * print correct SSL version for ciphers in results * legacy option --no-failed corrected UPDATE * Glossar improved Version: 13.09.09 BUGFIX * +cipher command corrected Version: 13.09.08 NEW * --cipher= allows other names; _find_cipher_name() implemented Version: 13.09.07 BUGFIX * --short texts corrected UPDATE * scoring improved * documentation improved NEW * +quick command for quick and simple check * +http command for HTTP(S) checks * --legasy=testsslserver implemented Version: 13.07.31 UPDATE * debugging and tracing improved NEW * STS checks implemented (scoring not yet perfect) * PFS checks implemented * --format=raw implemented * new commands: +sigkey_value, +sigkey_algorithm, +sigkey_len Version: 13.03.31 BUGFIX * avoid useless or wrong output when --no-cert given UPDATE * glossar NEW * --http implemented * --set_score implemented * --help=LABEL implemented * --ignorecase implemented * --showhost implemented * scoring implemented (first simple attempt) O-Saft-19.01.19/Dockerfile000066400000000000000000000332011342117255600150440ustar00rootroot00000000000000#!/usr/bin/docker build --force-rm --rm -f #? USAGE #? This Dockerfile uses "buildargs" variables to build the Docker image. #? For default settings, please use: awk '/^ARG/{print $2}' Dockerfile #? #? OSAFT_VERSION #? Version of this build (should be used as image tag also). #? #? OSAFT_VM_FROM #? Base image to be used for this build. Tested images are: #? (2017) alpine:3.6 alpine:edge debian:stretch-slim debian #? (2018) alpine:3.8 debian #? #? OSAFT_VM_APT_INSTALL #? Additional packages to be installed in the image. #? Note that the package names depend on the used base image. #? Tested packages are: tcl tk xvfb openssl #? #? OSAFT_VM_SRC_OSAFT #? URL to fetch o-saft.tgz archive. #? #? OSAFT_VM_SHA_OSAFT #? SHA256 checksum for the o-saft.tgz archive. #? Note that the checksum in the Dockerfile provided by this .tgz #? archive is wrong (due to hen-egg-problem). #? https://github.com/OWASP/O-Saft/blob/master/Dockerfile is the #? most current version and contains proper checksums. #? #? OSAFT_VM_TAR_OSAFT #? Name of archive file for O-Saft (during build). #? #? OSAFT_VM_SRC_OPENSSL #? URL to fetch openssl.tgz archive. #? #? OSAFT_VM_SHA_OPENSSL #? SHA256 checksum for the openssl-1.0.2-chacha.tar.gz archive. #? #? OSAFT_VM_TAR_OPENSSL #? Name of archive file for OpenSSL (during build). #? #? OSAFT_VM_DYN_OPENSSL #? Build (link) mode of openssl executable: --static or --shared #? #? OSAFT_VM_SRC_SSLEAY #? URL to fetch Net-SSLeay.tar.gz archive. #? #? OSAFT_VM_SHA_SSLEAY #? SHA256 checksum for the Net-SSLeay.tar.gz archive. #? #? OSAFT_VM_TAR_SSLEAY #? Name of archive file for Net-SSLeay.tgz (during build). #? #? OSAFT_VM_SRC_SOCKET #? URL to fetch IO-Socket-SSL.tar.gz archive. #? #? OSAFT_VM_SHA_SOCKET #? SHA256 checksum for the IO-Socket-SSL.tar.gz archive. #? #? OSAFT_VM_TAR_SOCKET #? Name of archive file for IO-Socket-SSL.tgz (during build). #? #? ENVIRONMENT VARIABLES #? The build image sets environment variables. They are mainly used for #? documentation or by other programs to check for the right build. #? #? Following environment variables are set inside the docker image: #? #? osaft_vm_build #? Build version of this image, used by o-saft-docker. #? OSAFT_DIR #? Directory where O-Saft is installed. #? OPENSSL_DIR #? Directory where OpenSSL is installed. #? OPENSSL_VERSION #? Version of installed OpenSSL #? TERM #? Prefered X-Terminal program. #? LD_RUN_PATH #? Additional paths for runtime loader, used while linking with #? "ld -rpath=..." #? Linking of openssl, libssl.so and SSLeay.so will use -rpath #? in LDFLAGS to ensure that the special library will be used. #? Default:${OPENSSL_DIR}/lib #? PATH #? PATH for shell, set to: #? $OSAFT_DIR:$OSAFT_DIR/contrib:$OPENSSL_DIR/bin:$PATH #? WORK_DIR #? Directory where to build the packages (used for Dockerfile's #? WORKDIR dierective. #? #? EXAMPLES #? Simple build with defaults: alpine:edge, o-saft.tgz, openssl-chacha #? docker build --force-rm --rm \ #? -f Dockerfile -t owasp/o-saft . #? #? Simple build with base image alpine:3.8 #? docker build --force-rm --rm \ #? --build-arg "OSAFT_VM_FROM=alpine:3.8" \ #? -f Dockerfile -t owasp/o-saft . #? #? Build with base image alpine:3.6 and Tcl/Tk #? docker build --force-rm --rm \ #? --build-arg "OSAFT_VM_FROM=alpine:3.6" \ #? --build-arg "OSAFT_VM_APT_INSTALL=tcl tk xvfb" \ #? -f Dockerfile -t owasp/o-saft . #? #? Build with other SHA256 checksum for o-saft.tgz #? docker build --force-rm --rm \ #? --build-arg "OSAFT_VM_SHA_OSAFT=caffee" \ #? -f Dockerfile -t owasp/o-saft . #? #? Build with development O-Saft download from github #? docker build --force-rm --rm \ #? --build-arg "OSAFT_VM_SRC_OSAFT=https://github.com/OWASP/O-Saft/archive/master.tar.gz" \ #? --build-arg "OSAFT_VERSION=latest-development" \ #? -f Dockerfile -t owasp/o-saft . #? #? Note that o-saft-docker searches for a Docker image owasp/o-saft #? so don't forget to tag at least one image with this name. #? ARG OSAFT_VM_FROM=alpine:3.8 FROM $OSAFT_VM_FROM MAINTAINER Achim # Parameters passed to build # OSAFT_VM_FROM must be defined again, otherwise its value is not available ARG OSAFT_VM_FROM ARG OSAFT_VM_SRC_OSAFT="https://github.com/OWASP/O-Saft/raw/master/o-saft.tgz" ARG OSAFT_VM_SHA_OSAFT="29d4faa2ed3025ed18d31175e868d6be9312b36ba486c6e5f305afeb34947f68" ARG OSAFT_VM_TAR_OSAFT="o-saft.tgz" ARG OSAFT_VM_SRC_SSLEAY="http://search.cpan.org/CPAN/authors/id/M/MI/MIKEM/Net-SSLeay-1.85.tar.gz" ARG OSAFT_VM_SHA_SSLEAY="9d8188b9fb1cae3bd791979c20554925d5e94a138d00414f1a6814549927b0c8" ARG OSAFT_VM_TAR_SSLEAY="Net-SSLeay.tgz" ARG OSAFT_VM_SRC_SOCKET="http://search.cpan.org/CPAN/authors/id/S/SU/SULLR/IO-Socket-SSL-2.052.tar.gz" ARG OSAFT_VM_SHA_SOCKET="e4897a9b17cb18a3c44aa683980d52cef534cdfcb8063d6877c879bfa2f26673" ARG OSAFT_VM_TAR_SOCKET="IO-Socket-SSL.tgz" ARG OSAFT_VM_SRC_OPENSSL="https://github.com/PeterMosmans/openssl/archive/1.0.2-chacha.tar.gz" ARG OSAFT_VM_SHA_OPENSSL="ad3d99ec091e403a3a7a678ddda38b392e3204515425827c53dc5baa92d61d67" ARG OSAFT_VM_TAR_OPENSSL="openssl.tgz" ARG OSAFT_VM_DYN_OPENSSL="--shared" # --static not yet (2017) working 'cause of libkrb5 ARG OSAFT_VM_APT_INSTALL ARG OSAFT_VERSION="undefined" LABEL \ VERSION="$OSAFT_VERSION" \ \ DESCRIPTION="Build O-Saft docker image (with Peter Mosman's openssl)" \ SYNOPSIS="docker build --force-rm --rm -f ./Dockerfile -t owasp/o-saft:$OSAFT_VERSION -t owasp/o-saft ." \ DETAILS="Please see https://github.com/OWASP/O-Saft/raw/master/o-saft-docker" \ SOURCE0="https://github.com/OWASP/O-Saft/raw/master/Dockerfile" \ SOURCE1="$OSAFT_VM_SRC_OSAFT" \ SOURCE2="$OSAFT_VM_SRC_OPENSSL" \ SID="@(#) Dockerfile 1.29 19/01/20 23:25:44" \ AUTHOR="Achim Hoffmann" ENV osaft_vm_build "Dockerfile $OSAFT_VERSION; FROM $OSAFT_VM_FROM" ENV OSAFT_DIR /O-Saft ENV OPENSSL_DIR /openssl ENV OPENSSL_VERSION 1.0.2-chacha ENV TERM xterm ENV LD_RUN_PATH ${OPENSSL_DIR}/lib ENV PATH ${OSAFT_DIR}:${OSAFT_DIR}/contrib:${OPENSSL_DIR}/bin:$PATH ENV BUILD_DIR /tmp_src ENV WORK_DIR / WORKDIR $WORK_DIR RUN \ #== Install required packages, development tools and libs #apk update && \ # no update neded and not wanted apk add --no-cache wget ncurses $OSAFT_VM_APT_INSTALL \ gcc make musl-dev linux-headers \ krb5-dev zlib-dev perl perl-readonly perl-dev \ ca-certificates && \ # perl-io-socket-ssl perl-net-ssleay \ #== Pull, build and install enhanced openssl apk add --no-cache gmp-dev lksctp-tools-dev && \ cd $WORK_DIR && \ mkdir -p $BUILD_DIR $OPENSSL_DIR && \ wget --no-check-certificate $OSAFT_VM_SRC_OPENSSL -O $OSAFT_VM_TAR_OPENSSL && \ # check sha256 if there is one [ -n "$OSAFT_VM_SHA_OPENSSL" ] && \ echo "$OSAFT_VM_SHA_OPENSSL $OSAFT_VM_TAR_OPENSSL" | sha256sum -c ; \ \ tar -xzf $OSAFT_VM_TAR_OPENSSL -C $BUILD_DIR --strip-components=1 && \ cd $BUILD_DIR && \ # patch openssl.cnf for GOST sed -i '/RANDFILE/a openssl_conf=openssl_def' apps/openssl.cnf && \ # using echo instead of cat to avoid problems with stacked commands: # cat -> shell -> docker (\ echo 'openssl_conf=openssl_def'; \ echo '[openssl_def]'; \ echo 'engines=engine_section';\ echo '[engine_section]'; \ echo 'gost=gost_section'; \ echo '[gost_section]'; \ echo 'engine_id = gost'; \ echo 'default_algorithms=ALL';\ echo 'CRYPT_PARAMS=id-Gost28147-89-CryptoPro-A-ParamSet'; \ ) >> apps/openssl.cnf && \ # config with all options, even if they are default LDFLAGS="-rpath=$LD_RUN_PATH" && export LDFLAGS && \ # see description for LD_RUN_PATH above ./config --prefix=$OPENSSL_DIR --openssldir=$OPENSSL_DIR/ssl \ $OSAFT_VM_DYN_OPENSSL \ --with-krb5-flavor=MIT --with-krb5-dir=/usr/include/krb5/ \ -fPIC zlib zlib-dynamic enable-zlib enable-npn sctp \ enable-deprecated enable-weak-ssl-ciphers \ enable-heartbeats enable-unit-test enable-ssl-trace \ enable-ssl3 enable-ssl3-method enable-ssl2 \ enable-tls1 enable-tls1-method enable-tls\ enable-tls1-1 enable-tls1-1-method enable-tlsext \ enable-tls1-2 enable-tls1-2-method enable-tls1-2-client \ enable-dtls1 enable-dtls1-method \ enable-dtls1-2 enable-dtls1-2-method \ enable-md2 enable-md4 enable-mdc2 \ enable-rc2 enable-rc4 enable-rc5 \ enable-sha0 enable-sha1 enable-sha256 enable-sha512 \ enable-aes enable-cms enable-dh enable-egd \ enable-des enable-dsa enable-rsa enable-rsax \ enable-ec enable-ec2m enable-ecdh enable-ecdsa \ enable-blake2 enable-bf enable-cast enable-camellia \ enable-gmp enable-gost enable-GOST enable-idea \ enable-poly1305 enable-krb5 enable-rdrand enable-rmd160 \ enable-seed enable-srp enable-whirlpool \ enable-rfc3779 enable-ec_nistp_64_gcc_128 experimental-jpake \ -DOPENSSL_USE_BUILD_DATE -DTLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES -DTEMP_GOST_TLS \ && \ make depend && make && make report -i && make install && \ # make report most likely fails, hence -i # simple test echo -n "# number of ciphers $OPENSSL_DIR/bin/openssl: " && \ $OPENSSL_DIR/bin/openssl ciphers -V ALL:COMPLEMENTOFALL:aNULL|wc -l && \ # cleanup apk del --purge gmp-dev lksctp-tools-dev && \ cd $WORK_DIR && \ rm -rf $BUILD_DIR $OSAFT_VM_TAR_OPENSSL && \ \ #== Pull, build and install Net::SSLeay cd $WORK_DIR && \ mkdir -p $BUILD_DIR && \ wget --no-check-certificate $OSAFT_VM_SRC_SSLEAY -O $OSAFT_VM_TAR_SSLEAY && \ # check sha256 if there is one [ -n "$OSAFT_VM_SHA_SSLEAY" ] && \ echo "$OSAFT_VM_SHA_SSLEAY $OSAFT_VM_TAR_SSLEAY" | sha256sum -c ; \ \ tar -xzf $OSAFT_VM_TAR_SSLEAY -C $BUILD_DIR --strip-components=1 && \ # install additional packages for Net-SSLeay ... apk add --no-cache perl-net-dns perl-net-libidn perl-mozilla-ca && \ cd $BUILD_DIR && \ perl -i.orig -pe 'if (m/^#define\s*REM_AUTOMATICALLY_GENERATED_1_09/){print "const SSL_METHOD * SSLv2_method()\n\nconst SSL_METHOD * SSLv3_method()\n\n";}' SSLeay.xs && \ # quick&dirty patch, results in warning, which can be ignored # Warning: duplicate function definition 'SSLv2_method' detected in SSLeay.xs, line 4256 LDFLAGS="-rpath=$LD_RUN_PATH" && export LDFLAGS && \ echo "n" | env OPENSSL_PREFIX=$OPENSSL_DIR perl Makefile.PL \ INC=-I$OPENSSL_DIR/include DEFINE=-DOPENSSL_BUILD_UNSAFE=1 && \ # Makefile.PL asks for "network tests", hence pipe "n" as answer # installation in (default) /usr/local, hence no PREFIX= make && make test && make install && \ cd $WORK_DIR && \ rm -rf $BUILD_DIR $OSAFT_VM_TAR_SSLEAY && \ \ #== Pull, build and install IO::Socket::SSL mkdir -p $BUILD_DIR && \ wget --no-check-certificate $OSAFT_VM_SRC_SOCKET -O $OSAFT_VM_TAR_SOCKET && \ # check sha256 if there is one [ -n "$OSAFT_VM_SHA_SOCKET" ] && \ echo "$OSAFT_VM_SHA_SOCKET $OSAFT_VM_TAR_SOCKET" | sha256sum -c ; \ \ tar -xzf $OSAFT_VM_TAR_SOCKET -C $BUILD_DIR --strip-components=1 && \ cd $BUILD_DIR && \ echo "n" | perl Makefile.PL INC=-I$OPENSSL_DIR/include && \ make && make test && make install && \ cd $WORK_DIR && \ rm -r $BUILD_DIR $OSAFT_VM_TAR_SOCKET && \ \ #== Pull and install O-Saft cd $WORK_DIR && \ mkdir -p $OSAFT_DIR && \ adduser -D -h ${OSAFT_DIR} osaft && \ \ wget --no-check-certificate $OSAFT_VM_SRC_OSAFT -O $OSAFT_VM_TAR_OSAFT && \ # check sha256 if there is one [ -n "$OSAFT_VM_SHA_OSAFT" ] && \ echo "$OSAFT_VM_SHA_OSAFT $OSAFT_VM_TAR_OSAFT" | sha256sum -c ; \ \ tar -xzf $OSAFT_VM_TAR_OSAFT && \ # handle master directory from github, mv to $OSAFT_DIR # checks fail sometimes, hence in a sub-shell (\ [ -d "./O-Saft-master" ] && mv ./O-Saft-master/* $OSAFT_DIR/ ; \ [ -d "./O-Saft-master" ] && mv ./O-Saft-master/.[a-zA-Z]* $OSAFT_DIR/ ; \ [ -d "./O-Saft-master" ] && rm -rf ./O-Saft-master/ ; \ exit 0 ; \ ) && \ chown -R root:root $OSAFT_DIR && \ chown -R osaft:osaft $OSAFT_DIR/contrib && \ chown osaft:osaft $OSAFT_DIR/.o-saft.pl && \ cp $OSAFT_DIR/.o-saft.pl $OSAFT_DIR/.o-saft.pl-orig && \ perl -i.bak -pe "s:^#?\s*--openssl=.*:--openssl=$OPENSSL_DIR/bin/openssl:;s:^#?\s*--openssl-cnf=.*:--openssl-cnf=$OPENSSL_DIR/ssl/openssl.cnf:;s:^#?\s*--ca-path=.*:--ca-path=/etc/ssl/certs/:;s:^#?\s*--ca-file=.*:--ca-file=/etc/ssl/certs/ca-certificates.crt:" $OSAFT_DIR/.o-saft.pl && \ chmod 666 $OSAFT_DIR/.o-saft.pl && \ rm -f $OSAFT_VM_TAR_OSAFT && \ \ #== Cleanup apk del --purge gcc make musl-dev linux-headers perl-dev # do not delete krb5-dev zlib-dev because we need # libkrb5.so.3, libk5crypto.so.3 and libz.so to run openssl WORKDIR $OSAFT_DIR USER osaft RUN o-saft-docker usage ENTRYPOINT ["/O-Saft/o-saft"] CMD ["--norc", "--help=docker"] # vim:set ft=dockerfile: O-Saft-19.01.19/INSTALL.sh000077500000000000000000000315521342117255600145260ustar00rootroot00000000000000#! /bin/sh #? #? File generated from Makefile 1.47 #? #? NAME #? $0 - install script for O-Saft #? #? SYNOPSIS #? $0 [options] [installation directory] #? #? DESCRIPTION #? Some people want to have an installation script, in particular named #? INSTALL.sh, even O-Saft should work without a specific installation. #? Here we go. #? #? This script does nothing except printing some messages unless called #? with an argument. The arguments are: #? #? /absolute/path #? - copy all necessary files into specified directory #? --install - copy all necessary files into default directory #? --check - check current installation #? --clean - move files not necessary to run O-Saft into subdir #? ./release_information_only # This is the behaviour of the old INSTALL-devel.sh script. #? --openssl - same as calling contrib/install_openssl.sh #? (build and install openssl and Net::SSLeay) #? #? OPTIONS #? --h got it #? --n do not execute, just show #? --blind use blue instead of green coloured texts #? --force install .o-saft.pl and .o-saft.tcl in $HOME, overwrites #? existing ones #? #? EXAMPLES #? $0 #? $0 --clean #? $0 --check #? $0 --install #? $0 /opt/bin/ #? $0 /opt/bin/ --force #? # HACKER's INFO # This file is generated from INSTALL-template.sh . # The generator (make) inserts some values for internal variables. In # particular the list of source files to be installed. See the strings # generated from Makefile 1.47 . # TODO: --check does not work if installed in other dir than default one # # Environment variable inst can be set to installation directory: This # is usefull for development only, hence not officially documented. # #? DEPENDENCIES #? Following tools are required for proper functionality: #? awk, cat, perl, tr #? VERSION #? @(#) INSTALL-template.sh 1.14 18/11/04 15:45:10 #? #? AUTHOR #? 16-sep-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- # --------------------------------------------- internal variables; defaults try='' ich=${0##*/} bas=${ich%%.*} dir=${0%/*} [ "$dir" = "$0" ] && dir="." # $0 found via $PATH in . colour="32m" # 32 green, 34 blue for colour-blind clean=./release_information_only force=0 optn="" mode=""; # "", check, clean, dest inst=${inst:="/usr/local/o-saft"} text_miss="missing, try installing with "; # 'cpan $m'" text_dev="did you run »$0 --clean«?" text_alt="file from previous installation, try running »$0 --clean« " text_old="ancient module found, try installing newer version, at least " osaft_exe="o-saft.pl" osaft_gui="o-saft.tcl" # corresponding RC-files do not need their own variable; simply prefix with . inst_openssl="contrib/install_openssl.sh" # generated from Makefile 1.47 { files_contrib=" contrib/.o-saft.tcl contrib/Cert-beautify.awk contrib/Cert-beautify.pl contrib/Dockerfile.alpine-3.6 contrib/HTML-simple.awk contrib/HTML-table.awk contrib/INSTALL-template.sh contrib/JSON-array.awk contrib/JSON-struct.awk contrib/XML-attribute.awk contrib/XML-value.awk contrib/bash_completion_o-saft contrib/bunt.pl contrib/bunt.sh contrib/cipher_check.sh contrib/critic.sh contrib/dash_completion_o-saft contrib/distribution_install.sh contrib/filter_examples contrib/fish_completion_o-saft contrib/gen_standalone.sh contrib/install_openssl.sh contrib/install_perl_modules.pl contrib/lazy_checks.awk contrib/o-saft.php contrib/tcsh_completion_o-saft contrib/usage_examples contrib/zap_config.sh contrib/zap_config.xml " files_install=" .o-saft.pl Dockerfile Net/SSLhello.pm Net/SSLinfo.pm OSaft/Ciphers.pm OSaft/Doc/Data.pm OSaft/Doc/coding.txt OSaft/Doc/glossary.txt OSaft/Doc/help.txt OSaft/Doc/links.txt OSaft/Doc/misc.txt OSaft/Doc/rfc.txt OSaft/Doc/tools.txt OSaft/error_handler.pm checkAllCiphers.pl o-saft o-saft-dbx.pm o-saft-docker o-saft-docker-dev o-saft-img.tcl o-saft-man.pm o-saft-usr.pm o-saft.pl o-saft.tcl osaft.pm " # generated from Makefile 1.47 } files_not_installed=" o-saft.cgi contrb/o-saft.php contrib/install_openssl.sh contrib/install_perl_modules.pl " files_ancient="generate_ciphers_hash openssl_h-to-perl_hash o-saft-README INSTALL-devel.sh .perlcriticrc o-saft_bench " files_develop="o-saft-docker-dev Dockerfile Makefile Makefile.help t/" files_info="CHANGES README o-saft.tgz" # --------------------------------------------- internal functions echo_yellow () { echo "\033[1;33m$@\033[0m" } echo_green () { echo "\033[1;$colour$@\033[0m" } echo_red () { echo "\033[1;31m$@\033[0m" } # --------------------------------------------- arguments and options while [ $# -gt 0 ]; do case "$1" in '-h' | '--h' | '--help') \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 exit 0 ;; '-n' | '--n') optn="--n"; try=echo; ;; '--check') mode=check; ;; '--clean') mode=clean; ;; '--install') mode=dest; ;; # install in hardcoded path '--openssl') mode=openssl; ;; '--force') force=1; ;; '--blind') colour="34m"; ;; '--color-blind') colour="34m"; ;; '--colour-blind') colour="34m"; ;; '--version') \sed -ne '/^#? VERSION/{' -e n -e 's/#?//' -e p -e '}' $0 exit 0 ;; '+VERSION') echo 1.14 ; exit; ;; # for compatibility to $osaft_exe *) mode=dest; inst="$1"; ;; # last one wins esac shift done # --------------------------------------------- main # ------------------------- default mode --------- { if [ -z "$mode" ]; then echo "" cat << EoT # O-Saft does not need a specific installation. It may be used from this # directory right away. # # If you want to run O-Saft from this directory, then consider calling: $0 --clean # If you want to install O-Saft in a different directory, then please call: $0 /path/to/installation/directoy $0 /path/to/installation/directoy --force # To check if O-Saft will work, you may use: $0 --check # In a Docker image, this script may only be called like: $0 --check EoT exit 0 fi; # default mode } if [ "$mode" != "check" ]; then if [ -n "$osaft_vm_build" ]; then echo "**ERROR: found 'osaft_vm_build=$osaft_vm_build'" echo_red "**ERROR: inside docker only --check possible; exit" exit 6 fi fi # ------------------------- openssl mode --------- { if [ "$mode" = "openssl" ]; then [ ! -x "$inst_openssl" ] && echo_red "**ERROR: $inst_openssl does not exist; exit" && exit 2 $inst_openssl $optn status=$? if [ $status -ne 0 ]; then cat << EoT # $inst_openssl uses its default settings. To check the settings, use: # $0 --openssl --n # If other configurations should be used, please use directly: # $inst_openssl --help # $inst_openssl --n # $inst_openssl /path/to/install EoT fi exit $status fi; # openssl mode } # ------------------------- clean mode ----------- { if [ "$mode" = "clean" ]; then # do not move contrib/ as all examples expect contrib/ right here for f in $files_info $files_ancient $files_develop ; do [ -e "$clean/$f" ] && $try \rm -f "$clean/$f" $try \mv "$f" "$clean" done exit 0 fi; # clean mode } # ------------------------- install mode -------- { if [ "$mode" = "dest" ]; then if [ ! -d "$inst" ]; then echo_red "**ERROR: $inst does not exist; exit" [ "$try" = "echo" ] || exit 2 fi echo "# remove old files ..." # TODO: argh, hard-coded list of files ... for f in $files_install ; do f="$inst/$f" if [ -e "$f" ]; then $try \rm -f "$f" || exit 3 fi done echo "# installing ..." $try \mkdir -p "$inst/Net" $try \mkdir -p "$inst/OSaft/Doc" for f in $files_install ; do $try \cp "$f" "$inst/$f" || exit 4 done if [ $force -eq 1 ]; then $try \cp .$osaft_exe "$inst/" || echo_red ".$osaft_exe failed" $try \cp contrib/.$osaft_gui "$inst/" || echo_red ".$osaft_gui failed" fi echo -n "# installation in $inst "; echo_green "completed." exit 0 fi; # install mode } # ------------------------- check mode ----------- { if [ "$mode" != "check" ]; then echo_red "**ERROR: unknow mode $mode; exit" exit 5 fi # all following is check mode err=0 echo "" echo "# check installation" echo "# (warnings are ok if 'git clone' will be used for development)" echo "#--------------------------------------------------------------" # err=`expr $err + 1` ; # errors not counted here files="openssl_h-to-perl_hash generate_ciphers_hash o-saft-README" for f in $files ; do [ -e "$f" ] && echo -n "# found $f ...\t" && echo_yellow "$text_alt" done files="$files_develop $files_info " for f in $files ; do [ -e "$f" ] && echo -n "# found $f ...\t" && echo_yellow "$text_dev" done echo "#--------------------------------------------------------------" echo "" echo "# check for installed O-Saft" echo "#--------------------------------------------------------------" for o in $osaft_exe $osaft_gui ; do for p in `echo $PATH|tr ':' ' '` ; do d="$p/$o" if [ -e "$d" ]; then v=`$p/$o +VERSION` echo -n "# version $v:\t" && echo_green "$d" fi done done echo "#--------------------------------------------------------------" echo "" echo "# check for installed O-Saft resource files" echo "#--------------------------------------------------------------" # currently no version check for p in `echo $HOME $PATH|tr ':' ' '` ; do rc="$p/.$osaft_exe" if [ -e "$rc" ]; then echo -n "# $rc\t" && echo_yellow "will be used when started in $p only" fi done rc="$HOME/.$osaft_gui" if [ -e "$rc" ]; then v=`awk '/RCSID/{print $3}' $rc | tr -d '{};'` echo -n "# found $rc\t" && echo_green "$v" echo -n "# exist $rc\t" && echo_yellow "consider updating from contrib/.$osaft_gui" else echo -n "# miss. $rc\t" && echo_yellow "consider copying contrib/.$osaft_gui into your HOME directory: $HOME" fi echo "#--------------------------------------------------------------" echo "" echo "# check for installed perl modules" echo "#--------------------------------------------------------------" modules="Net::DNS Net::SSLeay IO::Socket::SSL Net::SSLinfo Net::SSLhello osaft OSaft::error_handler OSaft::Doc::Data" for m in $modules ; do echo -n "# testing for $m ...\t" v=`perl -M$m -le 'printf"\t%s",$'$m'::VERSION' 2>/dev/null` if [ -n "$v" ]; then case "$m" in 'IO::Socket::SSL') expect=1.90; ;; # 1.37 and newer work, somehow ... 'Net::SSLeay') expect=1.49; ;; # 1.33 and newer may work 'Net::DNS') expect=0.80; ;; esac case "$m" in 'Net::SSLinfo' | 'Net::SSLhello') c="green"; ;; 'OSaft::error_handler' | 'osaft') c="green"; ;; 'OSaft::Ciphers' ) c="green"; ;; 'OSaft::Doc::Data' ) c="green"; ;; *) c=`perl -le "print (($expect > $v) ? 'red' : 'green')"`; ;; esac [ "$c" = "green" ] && echo_green "$v" [ "$c" = "red" ] && echo_red "$v , $text_old $expect" [ "$c" = "red" ] && err=`expr $err + 1` [ "$c" = "red" ] && echo E $err else text_miss="$text_miss 'cpan $m'" echo_red "$text_miss" err=`expr $err + 1` echo e $err fi done exit echo "#--------------------------------------------------------------" echo "" echo "# check for important perl modules used by O-Saft" echo "#--------------------------------------------------------------" modules="Net::DNS Net::SSLeay IO::Socket::SSL" for p in `echo $PATH|tr ':' ' '` ; do o="$p/$osaft_exe" [ -e "$o" ] || continue echo "# testing $o ...\t" for m in $modules ; do v=`$o --no-warn +version | awk '($1=="'$m'"){print}'` echo_green "$v" done done echo "#--------------------------------------------------------------" echo "" echo "# check openssl executable in PATH" echo "#--------------------------------------------------------------" echo -n "# openssl:\t\t" && echo_green "`which openssl`" echo -n "# openssl version:\t" && echo_green "`openssl version`" # TODO: openssl older than 0x01000000 has no SNI echo "#--------------------------------------------------------------" echo "" echo "# check for openssl executable used by O-Saft" echo "#--------------------------------------------------------------" for p in `echo $PATH|tr ':' ' '` ; do o="$p/$osaft_exe" r="$p/.$osaft_exe" if [ -x "$o" ]; then ( cd $p openssl=`$o --no-warn +version | awk '/external executable/{print $NF}' | tr '\012' ' '` echo -n "# $o:\t" && echo_green "$openssl" ) fi done echo "#--------------------------------------------------------------" echo "" echo "# check for contributed files" echo "# (in $inst )" echo "#--------------------------------------------------------------" for c in $files_contrib ; do c="$inst/$c" if [ -e "$c" ]; then echo -n "# found\t" && echo_green "$c" else echo -n "# not found\t" && echo_red "$c" err=`expr $err + 1` fi done echo "#--------------------------------------------------------------" echo "" echo -n "# checks\t" if [ $err -eq 0 ]; then echo_green "passed" else echo_red "failed , $err error(s) detected" fi # check mode } exit $err O-Saft-19.01.19/LICENSE.md000066400000000000000000000404121342117255600144600ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Audit of TLS/SSLv3 Configuration of a Remote Web Server Copyright (C) 2013 Achim Hoffmann This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. https://www.owasp.org/index.php/User:Achim O-Saft-19.01.19/Makefile000066400000000000000000000524231342117255600145210ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for O-Saft project #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Traditional Makefile to perform common tasks for O-Saft project. #? For help about the targets herein, please see: #? #? make #? make help #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? Requires GNU sed for generating (target) INSTALL.sh. #? # TODO: move complete documentation to Makefile.help # HACKER's INFO # This Makefile uses mainly make's built-in variables (aka macros) and # targets. None of them are disabled explicitly. Therefore some behaviour # may depend on the local make configuration. # # SEE Make:automatic variables also. # # Note: macro is a synonym for variable in makefiles. # Note: macro definitions in makefiles must not be sequential! # Use of $$ avoids evaluating $ (the macro). # # Variable, macro names # General rules for our variable names in this Makefile: # * variable names consist only of characters a-zA-Z0-9_. # * variable names start with upper case letters or _ # # Internal variables: # _SID - version in project's Makefile # _SID.* - version in included makefiles # _MYSELF.* - name of the Makefile itself (in included makefiles) # # The _SID* variables are used to check if sub-makefiles were included. # More variables and targets are defined in following included files: # Makefile.help # t/Makefile # t/Makefile.inc # Where t/Makefile may include more files. # Each of the included files may be used independently using -f option, # for example:: # make -f Makefile.help # make -f t/Makefile # # Following name prefixes are used: # SRC - defines a source file # GEN - defines a genarted file # EXE - defines a tools to be used # ALL - defines summary variables # TEST - something related to the t/ directory # CONTRIB - something related to the contrib/ directory # CRITIC - something related to percritic targets # _ - names of internal (helper) variables (they are not # intended to be overwritten on command line) # HELP - defines texts to be used in help and doc target # # Following names are used, which potentially conflict with make itself: # ECHO - echo command # MAKE - make command # MAKEFILE - Makefile (i.g. myself, but may be redifined) # # Notes about some special variables: # ALL.src - list of all sources to be distributed # ALL.tgz - same as ALL.src but all sources prefixed with O-Saft/ # ALL.test - list of all sources used for testing the project # ALL.tests - list of all targets for testing # ALL.includes - dynamically generated list of all included makefiles # ALL.inc.type - list of all types of included makefiles # ALL.Makefiles - static list of all source makefiles of the project # # In general no quotes are used around texts in variables. Though, it is # sometimes necessary to use quotes to force correct evaluation of used # variables in the text (mainly in target actions). # # HACKER's HELP # For details, in particular the syntax of the HELP-* macros used here, # please see Makefile.help . # More details why and how some things are implemented are described in # t/Makefile.pod . "SEE Make:some text" is used to reference to it. # #? VERSION #? @(#) Makefile 1.47 19/01/11 23:08:12 #? #? AUTHOR #? 21-dec-12 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID = 1.47 # define our own SID as variable, if needed ... ALL.includes := Makefile # must be := to avoid overwrite after includes # each $(TEST.dir)/Makefile* will add itself to ALL.includes MAKEFLAGS = --no-builtin-variables --no-builtin-rules .SUFFIXES: first-target-is-default: default MAKEFILE = Makefile # define variable for myself, this allows to use some targets # within other makefiles # Note that $(MAKEFILE) is used where any Makefile is possible # and Makefile is used when exactly this file is meant. # $(ALL.Makefiles) is used, when all Makefiles are needed. #_____________________________________________________________________________ #________________________________________________________________ variables __| Project = o-saft ProjectName = O-Saft INSTALL.dir = /usr/local/$(Project) # source files SRC.lic = yeast.lic DEV.pl = yeast.pl CHK.pl = checkAllCiphers.pl OSD.dir = OSaft/Doc OSD.pm = OSaft/Doc/Data.pm OSD.txt = \ coding.txt \ glossary.txt \ help.txt \ links.txt \ misc.txt \ rfc.txt \ tools.txt SRC.txt = $(OSD.txt:%=$(OSD.dir)/%) NET.pm = SSLinfo.pm \ SSLhello.pm _CIPHER = \ _ciphers_osaft.pm \ _ciphers_iana.pm \ _ciphers_openssl_all.pm \ _ciphers_openssl_low.pm \ _ciphers_openssl_medium.pm \ _ciphers_openssl_high.pm # add to SRC.pm $(_CIPHER:%=OSaft/%) when used OSAFT.pm = Ciphers.pm error_handler.pm USR.pm = \ $(Project)-dbx.pm \ $(Project)-man.pm \ $(Project)-usr.pm SRC.pm = \ osaft.pm \ $(NET.pm:%=Net/%) \ $(OSAFT.pm:%=OSaft/%) \ $(USR.pm) \ $(OSD.pm) SRC.sh = $(Project) SRC.pl = $(Project).pl SRC.tcl = $(Project).tcl $(Project)-img.tcl SRC.cgi = $(Project).cgi SRC.docker = \ $(Project)-docker \ $(Project)-docker-dev \ Dockerfile SRC.rc = .$(SRC.pl) SRC.make = Makefile SRC.misc = README CHANGES SRC.inst = $(CONTRIB.dir)/INSTALL-template.sh # contrib files CONTRIB.dir = contrib CONTRIB.examples= filter_examples usage_examples CONTRIB.post.awk= \ Cert-beautify.awk Cert-beautify.pl \ HTML-simple.awk HTML-table.awk \ JSON-array.awk JSON-struct.awk \ XML-attribute.awk XML-value.awk \ lazy_checks.awk CONTRIB.post = bunt.pl bunt.sh CONTRIB.misc = \ cipher_check.sh \ critic.sh \ gen_standalone.sh \ distribution_install.sh \ install_openssl.sh \ install_perl_modules.pl \ INSTALL-template.sh \ Dockerfile.alpine-3.6 \ o-saft.php CONTRIB.zap = zap_config.sh zap_config.xml CONTRIB.rc = .$(Project).tcl # some file should get the $(Project) suffix, which is appended later CONTRIB.complete= \ bash_completion \ dash_completion \ fish_completion \ tcsh_completion SRC.contrib = \ $(CONTRIB.complete:%=$(CONTRIB.dir)/%_$(Project)) \ $(CONTRIB.examples:%=$(CONTRIB.dir)/%) \ $(CONTRIB.post.awk:%=$(CONTRIB.dir)/%) \ $(CONTRIB.post:%=$(CONTRIB.dir)/%) \ $(CONTRIB.misc:%=$(CONTRIB.dir)/%) \ $(CONTRIB.zap:%=$(CONTRIB.dir)/%) \ $(CONTRIB.rc:%=$(CONTRIB.dir)/%) ALL.contrib = $(SRC.contrib) # test files TEST.dir = t TEST.logdir = $(TEST.dir)/log TEST.do = SSLinfo.pl \ o-saft_bench.sh \ critic_345.sh \ test-bunt.pl.txt CRITIC.rc = .perlcriticrc SRC.test = \ $(TEST.do:%=$(TEST.dir)/%) \ $(CRITIC.rc:%=$(TEST.dir)/%) ALL.test = $(SRC.test) # documentation files DOC.dir = docs DOC.src = o-saft.odg o-saft.pdf o-saft-docker.pdf SRC.doc = $(DOC.src:%=$(DOC.dir)/%) WEB.dir = doc/img WEB.src = \ img.css \ O-Saft_cipherCLI.png \ O-Saft_cmd_GUI.png \ O-Saft_optGUI.png \ O-Saft_altnameCLI.png \ O-Saft_filterGUI.png \ O-Saft_protGUI.png \ O-Saft_altnameGUI.png \ O-Saft_cmd_GUI-0.png \ O-Saft_helpGUI-0.png \ O-Saft_vulnsCLI.png \ O-Saft_checkGUI.png \ O-Saft_cmd_GUI--docker.png \ O-Saft_helpGUI-1.png \ O-Saft_vulnsGUI.png \ O-Saft_CLI__faked.txt SRC.web = $(WEB.src:%=$(WEB.dir)/%) ALL.doc = $(SRC.doc) $(SRC.web) # generated files TMP.dir = /tmp/$(Project) GEN.html = $(Project).html GEN.cgi.html = $(Project).cgi.html GEN.text = $(Project).txt GEN.wiki = $(Project).wiki GEN.pod = $(Project).pod GEN.src = $(Project)-standalone.pl GEN.inst = INSTALL.sh GEN.tags = tags GEN.rel = $(Project).rel GEN.tgz = $(Project).tgz GEN.tmptgz = $(TMP.dir)/$(GEN.tgz) # summary variables SRC.exe = $(SRC.pl) $(SRC.tcl) $(CHK.pl) $(DEV.pl) $(SRC.sh) ALL.Makefiles = \ $(SRC.make) Makefile.help $(TEST.dir)/Makefile.pod \ $(TEST.dir)/Makefile $(TEST.dir)/Makefile.inc \ $(TEST.dir)/Makefile.opt $(TEST.dir)/Makefile.cmds \ $(TEST.dir)/Makefile.ext $(TEST.dir)/Makefile.exit \ $(TEST.dir)/Makefile.cgi $(TEST.dir)/Makefile.tcl \ $(TEST.dir)/Makefile.warnings $(TEST.dir)/Makefile.misc \ $(TEST.dir)/Makefile.critic $(TEST.dir)/Makefile.template \ $(TEST.dir)/Makefile.FQDN # NOTE: sequence in ALL.Makefiles is important, for example when used in target doc ALL.osaft = $(SRC.pl) $(SRC.tcl) $(CHK.pl) $(SRC.pm) $(SRC.sh) $(SRC.txt) $(SRC.rc) $(SRC.docker) ALL.exe = $(SRC.exe) $(SRC.cgi) $(GEN.src) $(SRC.docker) ALL.test = $(SRC.test) ALL.contrib = $(SRC.contrib) ALL.pm = $(SRC.pm) ALL.gen = $(GEN.src) $(GEN.pod) $(GEN.html) $(GEN.cgi.html) $(GEN.inst) $(GEN.tags) ALL.src = \ $(ALL.exe) \ $(ALL.pm) \ $(SRC.txt) \ $(SRC.rc) \ $(SRC.misc) \ $(SRC.doc) \ $(ALL.gen) \ $(ALL.Makefiles) \ $(ALL.test) \ $(ALL.contrib) ALL.tgz = $(ALL.src:%=O-Saft/%) # internal used tools (paths hardcoded!) ECHO = /bin/echo -e MAKE = $(MAKE_COMMAND) EXE.single = contrib/gen_standalone.sh EXE.docker = o-saft-docker EXE.pl = $(SRC.pl) # SRC.pl is used for generating a couple of data # INSTALL.sh must not contain duplicate files, hence the variable's content # is sorted using make's built-in sort which removes duplicates _INST.contrib = $(sort $(ALL.contrib)) _INST.osaft = $(sort $(ALL.osaft)) _INST.text = generated from Makefile 1.47 EXE.install = sed -e 's@INSTALLDIR_INSERTED_BY_MAKE@$(INSTALL.dir)@' \ -e 's@CONTRIB_INSERTED_BY_MAKE@$(_INST.contrib)@' \ -e 's@OSAFT_INSERTED_BY_MAKE@$(_INST.osaft)@' \ -e 's@INSERTED_BY_MAKE@$(_INST.text)@' # generate targets to print HELP texts _HELP.targets = $(shell $(EXE.eval) $(ALL.Makefiles)) #_____________________________________________________________________________ #___________________________________________________________ default target __| default: @$(TARGET_VERBOSE) @$(ECHO) "$(_HELP_HEADER_)" @$(EXE.help) $(ALL.Makefiles) @echo "$(_HELP_LINE_)" @echo "# see also: $(MAKE) doc" @echo "" doc: @$(TARGET_VERBOSE) @$(MAKE) -s e-_HELP_HEADER_ $(_HELP.targets) #_____________________________________________________________________________ #__________________________________________________________________ targets __| HELP-_known = _______________________________________ well known targets _ HELP-all = does nothing; alias for help HELP-clean = remove all generated files '$(ALL.gen)' HELP-release = generate signed '$(GEN.tgz)' from sources HELP-install = install tool in '$(INSTALL.dir)' using INSTALL.sh, $(INSTALL.dir) must exist HELP-uninstall = remove installtion directory '$(INSTALL.dir)' completely $(INSTALL.dir): @$(TARGET_VERBOSE) mkdir $(_INSTALL_FORCE_) $(INSTALL.dir) all: default clean: @$(TARGET_VERBOSE) -rm -r --interactive=never $(ALL.gen) clear: clean # target calls installed $(SRC.pl) to test general functionality install: $(GEN.inst) $(INSTALL.dir) @$(TARGET_VERBOSE) $(GEN.inst) $(INSTALL.dir) \ && $(INSTALL.dir)/$(SRC.pl) --no-warning --tracearg +quit > /dev/null install-f: _INSTALL_FORCE_ = -p install-f: install uninstall: @$(TARGET_VERBOSE) -rm -r --interactive=never $(INSTALL.dir) _RELEASE = $(shell perl -nle '/^\s*STR_VERSION/ && do { s/.*?"([^"]*)".*/$$1/;print }' $(SRC.pl)) release.show: @echo "Release: $(_RELEASE)" release: $(GEN.tgz) @$(TARGET_VERBOSE) mkdir -p $(_RELEASE) sha256sum $(GEN.tgz) > $(_RELEASE)/$(GEN.tgz).sha256 @cat $(_RELEASE)/$(GEN.tgz).sha256 gpg --local-user o-saft -a --detach-sign $(GEN.tgz) gpg --verify $(GEN.tgz).asc $(GEN.tgz) mv $(GEN.tgz).asc $(_RELEASE)/ mv $(GEN.tgz) $(_RELEASE)/ @echo "# don't forget:" @echo "# # change digest: sha256:... in README; upload to github" @echo "# # change digest: sha256:... in Dockerfile; upload to github" @echo "# make docker" @echo "# make test.docker" @echo "# make docker.push" # TODO: check if files are edited or missing # Generating a release file, containing all files with their SID. # This file should be easily readable by humans and easily parsable by scripts, # hence following format is used (one per line): # SID\tdate\ttime\tfilename\tfull_path # How it works: # "sccs what" returns multiple lines, at least 2, these look like: # path/filename: # o-saft.pl 1.823 18/11/18 23:42:23 # this is resorted to have the fixed-width field SID, date and time at the # beginning (left), followed by the filename and the full path. # NOTE: only files available in the repository are used, therefor the variable # $(ALL.src) is used. Because $(ALL.src) also contains $(ALL.gen), which # is wrong here, $(ALL.gen) is set empty for this target. # o-saft.pl is generated from yeast.pl, but o-saft.pl is not a repository # file, hence yeast is substituded by o-saft (should occour only once). $(GEN.rel): ALL.gen = $(GEN.rel): $(ALL.src) sccs what $(ALL.src) | perl -anle '/^(.*):$$/&&do{$$f=$$m=$$1;$$m=~s#.*/##;next;};/.*?($$m|%[M]%)/&&do{$$f=~s/yeast/o-saft/;$$F[0]=~s/yeast/o-saft/;printf("%s\t%s\t%s\t%s\t%s\n",$$F[1],$$F[2],$$F[3],$$F[0],$$f)};' rel :$(GEN.rel) $(_RELEASE).rel: Makefile @$(MAKE) -s $(GEN.rel) > $@ .PHONY: all clean install install-f uninstall release.show release rel doc default variables = \$$(variables) # # define literal string $(variables) for "make doc" HELP-_project = ____________________________________ targets for $(Project) _ HELP-help = print overview of all targets HELP-doc = same as help, but evaluates '$(variables)' HELP-pl = generate '$(SRC.pl)' from managed source files HELP-cgi = generate HTML page for use with CGI '$(GEN.cgi.html)' HELP-pod = generate POD format help '$(GEN.pod)' HELP-html = generate HTML format help '$(GEN.html)' HELP-text = generate plain text help '$(GEN.text)' HELP-wiki = generate mediawiki format help '$(GEN.wiki)' HELP-tar = generate '$(GEN.tgz)' from all source prefixed with O-Saft/ HELP-tmptar = generate '$(GEN.tmptgz)' from all sources without prefix HELP-docker = generate local docker image (release version) and add updated files HELP-docker-dev = generate local docker image (development version) HELP-docker.push= install local docker image at Docker repository HELP-cleantar = remove '$(GEN.tgz)' HELP-cleantmp = remove '$(TMP.dir)' HELP-clean.all = remove '$(GEN.tgz) $(ALL.gen)' HELP-install-f = install tool in '$(INSTALL.dir)' using INSTALL.sh, $(INSTALL.dir) may exist OPT.single = --s # alias targets help: default pl: $(SRC.pl) cgi: $(GEN.cgi.html) pod: $(GEN.pod) html: $(GEN.html) text: $(GEN.text) wiki: $(GEN.wiki) standalone: $(GEN.src) tar: $(GEN.tgz) GREP_EDIT = 1.47 tar: GREP_EDIT = 1.47 tmptar: GREP_EDIT = something which hopefully does not exist in the file tmptar: $(GEN.tmptgz) tmptgz: $(GEN.tmptgz) cleantar: clean.tar cleantgz: clean.tar cleantmp: clean.tmp cleartar: clean.tar cleartgz: clean.tar cleartmp: clean.tmp clear.all: clean.tar clean clean.all: clean.tar clean tgz: tar tar: OPT.single = tgz: OPT.single = tmptar: OPT.single = tmptgz: OPT.single = # docker target uses project's own script to build and remove the image docker.build: @$(TARGET_VERBOSE) $(EXE.docker) -OSAFT_VERSION=$(_RELEASE) build $(EXE.docker) cp Dockerfile $(EXE.docker) cp README docker: docker.build docker.rm: @$(TARGET_VERBOSE) $(EXE.docker) rmi docker.dev: @$(TARGET_VERBOSE) docker build --force-rm --rm \ --build-arg "OSAFT_VM_SRC_OSAFT=https://github.com/OWASP/O-Saft/archive/master.tar.gz" \ --build-arg "OSAFT_VERSION=$(_RELEASE)" \ -f Dockerfile -t owasp/o-saft . # TODO: docker.push should depend on docker.build (above), but docker.build # is not a file and creates a Docker image; means that this target itself # has no dependency. Make then executes the target always, which fails if # a Docker image already exists. Need a target, which checks the current # Docker image for the proper version. docker.push: @$(TARGET_VERBOSE) docker push owasp/o-saft:latest .PHONY: pl cgi pod html wiki standalone tar tmptar tmptgz cleantar cleantmp help .PHONY: docker docker.rm docker.dev docker.push clean.tmp: @$(TARGET_VERBOSE) rm -rf $(TMP.dir) clean.tar: @$(TARGET_VERBOSE) rm -rf $(GEN.tgz) clean.tgz: clean.tar clean.docker: docker.rm # targets for generation $(TMP.dir)/Net $(TMP.dir)/OSaft $(TMP.dir)/OSaft/Doc $(TMP.dir)/$(CONTRIB.dir) $(TMP.dir)/$(TEST.dir): @$(TARGET_VERBOSE) mkdir -p $@ # cp fails if SRC.pl is read-only, hence we remove it; it is generated anyway $(SRC.pl): $(DEV.pl) @$(TARGET_VERBOSE) rm -f $@ cp $< $@ $(GEN.src): $(EXE.single) $(SRC.pl) $(ALL.pm) @$(TARGET_VERBOSE) $(EXE.single) $(OPT.single) $(GEN.pod): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TARGET_VERBOSE) $(SRC.pl) --no-rc --no-warning --help=gen-pod > $@ $(GEN.text): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TARGET_VERBOSE) $(SRC.pl) --no-rc --no-warning --help > $@ $(GEN.wiki): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TARGET_VERBOSE) $(SRC.pl) --no-rc --no-warning --help=gen-wiki > $@ $(GEN.html): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TARGET_VERBOSE) $(SRC.pl) --no-rc --no-warning --help=gen-html > $@ $(GEN.cgi.html): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TARGET_VERBOSE) $(SRC.pl) --no-rc --no-warning --help=gen-cgi > $@ $(GEN.inst): $(SRC.inst) Makefile @$(TARGET_VERBOSE) $(EXE.install) $(SRC.inst) > $@ chmod +x $@ $(GEN.tgz)--to-noisy: $(ALL.src) @$(TARGET_VERBOSE) @grep -q '$(GREP_EDIT)' $? \ && echo "file(s) being edited or with invalid SID" \ || echo tar zcf $@ $^ # Special target to check for edited files; it only checks the source files of # the tool (o-saft.pl) but no other source files. _notedit: $(SRC.exe) $(SRC.pm) $(SRC.rc) $(SRC.txt) @$(TARGET_VERBOSE) @grep -q '$(GREP_EDIT)' $? \ && echo "file(s) being edited or with invalid SID" \ && exit 1 \ || echo "# no edits" .PHONY: _notedit #$(GEN.tgz): _notedit $(ALL.src) # not working properly # tar: _notedit: Funktion stat failed: file or directory not found # .tgz is tricky: as all members should have the directory prefixed, tar needs # to be executed in the parent directory and use $(ALL.tgz) as members. # The target itself is called in the current directory, hence the dependencies # are local to that which is $(ALL.src). Note that $(ALL.tgz) is generated from # $(ALL.src), so it contains the same members. Executing tar in the parent dir # would generate the tarball there also, hence the tarball is specified as full # path with $(PWD). # The directory prefix in the tarball is the current directory, aka $(PWD) . $(GEN.tgz): $(ALL.src) @$(TARGET_VERBOSE) cd .. && tar zcf $(PWD)/$@ $(ALL.tgz) $(GEN.tmptgz): $(ALL.src) @$(TARGET_VERBOSE) tar zcf $@ $^ #_____________________________________________________________________________ HELP-_special = ___________ any target may be used with following suffixes _ HELP--v = verbose: print target and newer dependencies HELP--vv = verbose: print target and all dependencies # verbose command # TARGET_VERBOSE is the string to be printed in verbose mode # it is epmty by default # TARGET_VERBOSE can be set as environment variable, or used on command # line when calling make # it is also used internal for the -v targets, see below # examples: # TARGET_VERBOSE = \# --Target: $@-- # TARGET_VERBOSE = \# --Target: $@: newer dependencies: $? -- # TARGET_VERBOSE = \# --Target: $@: all dependencies: $^ -- # verbose targets # Note: need at least one command for target execution %-v: TARGET_VERBOSE=echo "\# $@: $?" %-v: % @echo -n "" %-vv: TARGET_VERBOSE=echo "\# $@: $^" %-vv: % @echo -n "" # the traditional way, when target-dependent variables do not work #%-v: # @$(MAKE) $(MFLAGS) $(MAKEOVERRIDES) $* 'TARGET_VERBOSE=# $$@: $$?' # #%-vv: # @$(MAKE) $(MFLAGS) $(MAKEOVERRIDES) $* 'TARGET_VERBOSE=# $$@: $$^' #_____________________________________________________________________________ #_____________________________________________ targets for testing and help __| include Makefile.help include $(TEST.dir)/Makefile # Note that $(TEST.dir)/Makefile includes all other Makefile.* there O-Saft-19.01.19/Makefile.help000066400000000000000000000367641342117255600154620ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for help targets of O-Saft project #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile with help targets for O-Saft project. It also describes the #? (special) syntax used in all Makefiles of the project. #? #? EXAMPLES #? make help.doc #? make help.syntax #? make macro macro=MAKEFILE #? make m-MAKEFILE #? make echo echo=MAKEFILE #? make e-MAKEFILE #? make p-MAKEFILE #? make t-help.doc #? make targets #? make targets.me #? make cloc #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # Description used for target help.syntax . #. #. Terms used for description of makefiles #. The term makefile(s) is used, when files to be used as input for make # in general are meant. #. The term Makefile is used, when a particular file is meant (usually #. the file itself in which the term is used). #. The terms target, target rule or simply rule are used, when make's #. rules are meant (a rule consist of dependencies and recipes). #. The term host or hostname is used for a system (wether it is a FQDN #. or an IP) to be tested with $(EXE.pl). #. The term argument(s) is used, when (command line) arguments for to be #. passed to $(EXE.pl) are meant. #. The terms macro and variable are used interchangeable. #. #. Note that the O-Saft's documentation uses target for the system to be #. tested. #. Also: arguments are commands and options in O-Saft's documentation. #. #. Syntax used in all makefiles #. For extracting information from the Makefiles, i.e macros/variables and #. their definitions, following special syntax is used: #. * all texts for documentation (help) are stored in variables #. * all these variables are named with the prefix HELP- #. * anything following the prefix is the name of an existing target, #. example: HELP-doc contains the description of the target doc #. * variable names with prefix HELP-_ are treated as header texts, #. example: HELP-_help = ____ targets for help about Makefile _ #. #. Targets in the makefiles are grouped. Each group is headed by the help #. texts for the targets. The first line of this group should be a header #. text describing the group. Example: #. HELP-_group = _______________________________ some targets _ #. HELP-help = print overview of all targets #. HELP-doc = same as help, but evaluates macros #. These variables are used by the help and doc target. Each of these #. lines is printed as follows (from example above): #. _______________________________ some targets _ #. help - print overview of all targets #. doc - same as help, but evaluates variables #. #. To extract and format the texts, the targets use external tools, mainly #. awk, sed and tr. Each tool including its command line arguments is #. defined as variable, see corresponding EXE.* variables. #. #. All variable names used for help texts use - (dash) instead of . (dot). #. This simplifies matching the names, as the dash is not a meta character #. in RegEx and so must not be escaped. #. Exception is the HELP.something variable, which defines the help text #. for the corresponding Makefile itself (it must not be matched). #. #. Unfortunately some of the macros use variables of the makefile, like #. $(T), while other macros must use the TAB character verbatim, which is #. difficult to identify by human eyes. #. #. The main difference between the target help and doc is, that help #. uses external tools to extract the information from the makefile, while #. doc uses make's functionality to display the same information, which #. also evaluates variables used in the targets. Both targets use the same #. text. #. The EXE.* macros used by these targets take care for the formatting. #. They rely on the above conventions for variable names. #. #. Additional to the help targets described above, there are targets which #. show information about variables and targets: #. list, echo, show, macro, pmacro, target #. These targets show the information, which is passed in a variable with #. the same name as the target itself. Example: #. make macro macro=MAKEFILE #. To simplify such command lines, a special pattern rule exists for each #. of these targets. Example: #. make m-MAKEFILE #. These targets search in all makefiles, they use $(MAKEFILE_LIST) and #. and not our own $(ALL.Makefiles). This way the targets work, somehow, #. in all other makefiles too (as they include this one). #. #. Naming conventions for targets: #. tst.name - public available targets use . (dot) as separator #. tst-name - internal and pattern rule targets use - (dash) as #. separator #. tst.name_arg - some pattern rule targets use _ to pass parameters #. tst.name.log - same as test.name but store results in logfile #. tst%ext - pattern rule used instead of explicit target rule to #. allow spelling variants, like tst.ext or tst-ext #. #. Makefiles and Includes #. Note that GNU make's include directive does not understand macros, the #. used path must be verbatim. #. To keep the make's functionality (targets) maintainable, multiple files #. are used. They are all named Makefile or Makefile.SUFFIX, where the #. SUFFIX describes the content, somehow. I.g. it should be possible to #. use each of these makefiles by its own, like: #. make -f Makefile.SUFFIX target #. #. As GNU make's include functionality is difficult to use, in particular #. when including files from sub-directories, following trick is used: #. * sub-directories contain a symbolic link to . (itself) #. * Makefiles always include other files with relative paths #. Example: #. ./t/ (directory) contains: t -> . #. ./t/Makefile.cgi contains: include t/Makefile #. This avoid sophistcated syntax in the files itself, like: #. ifeq (t,$(findstring t,$(PWD))) #. TEST.dir = . #. # if called inside t directory, TEST.dir must be redifined #. endif #. #. GNU make cannot manage recursive includes of the same file. This must #. be check before including, for example with (using our private _SID.* #. variable): #. ifeq (,$(_SID.test)) #. include t/Makefile #. endif #. #. Makefiles #. All targets of the Makefiles --the make system-- are for testing O-Saft #. functionality, code quality, and performance. #. All testing functionality is grouped in individual makefiles. All these #. makefiles reside in the $(TEST.dir) directory (usually ./t ). The main #. Makefile simply includes all other files. The includes are organised as #. follows: #. Makefile #. include Makefile.help #. include t/Makefile #. include t/Makefile.inc #. include t/Makefile.warnings #. include t/Makefile.cmds #. include t/Makefile.exit #. include t/Makefile.opt #. include t/Makefile.ext #. include t/Makefile.cgi #. include t/Makefile.tcl #. include t/Makefile.misc #. include t/Makefile.critic #. #. To get a list of all makefiles, use: #. make s-ALL.includes #. #. Each of the t/Makefile.* includes t/Makefile. This allows to use each #. Makefile.* on its own, like: #. make -f t/Makefile.exit #. cd t && make -f Makefile.exit #. #. The default target in each makefile simply prints a brief help. #. #. Quick Hints #. There are a bunch of targets which provide information about the macros #. and targets from the Makefiles itself. They are mainly meant to show a #. readable (for humans) information in contrast to the sometimes cryptic #. syntax of makefiles can do. This is done in Makefile.help , see: #. make -f Makefile.help #. To get brief (mainly technical) information about a makefile, use: #. make -f t/Makefile.cgi #. make -f t/Makefile.cgi targets.me #. make -f t/Makefile.cgi macros.me #. make -f t/Makefile.cgi s-ALL.test.cgi #. ... #. #. Most included Makefiles.SUFFIX contain very limited comments. For general #. details of their functionality, see t/Makefile.template . #. #. Special Syntax here #. To extract the syntax documentation, all the lines start with #. , see #. EXE.syntax also. #. #? VERSION #? @(#) Makefile.help 1.21 18/11/01 21:13:32 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.help = 1.21 _MYSELF.help = Makefile.help ALL.includes += $(_MYSELF.help) MAKEFLAGS += --no-builtin-variables --no-builtin-rules .SUFFIXES: first-help-target-is-default: help.doc #_____________________________________________________________________________ #________________________________________________________________ variables __| # internal variables _TAB = \\011 _NL = \\012 _CR = \\015 T = $$""(_NL) # internal help # (for details about the commands, please see Syntax above) _HELP_INFO_ = \# Name | Description/Content _HELP_LINE_ = \#---------------+------------------------------------------------------------ _HELP_HEADER_ = $(_HELP_LINE_)\012$(_HELP_INFO_)\012$(_HELP_LINE_) _HELP_USAGE_ = **USAGE: $(MAKE) $($@) '$($@)=your-query' # tools used to gather information from herein # take care! real TABS are inside the sed commands EXE.list = awk '/^[_a-zA-Z][_a-zA-Z.]* *=/{sub(/=/,"",$$1);print $$1}' EXE.eval = awk -F= '/^HELP-_/{print "_f-"$$1}/^HELP-[^ _]/{sub(/HELP-/,"");print "f-"$$1}' EXE.help = sed -n -e 's/^HELP-_[^=]*=[" ]*\([^"]*\)"*/ \1/p' \ -e 's/^HELP-\(.*\)[ ]*=[" ]*\([^"]*\)"*/ \1 - \2/p' EXE.macro = sed -n -e '/^$($@)[ :+]*=/{' \ -e ':m' -e 'p' -e '/\\$$/{' -e 'n' -e 'bm' -e '}' -e '}' EXE.pmacro = sed -n -e '/.*$($@).*[ :+]*=/{' \ -e ':m' -e 'p' -e '/\\$$/{' -e 'n' -e 'bm' -e '}' -e '}' EXE.target = sed -n -e ':t' -e '/^[^:\#]*$($@)[^:\#]*[:]/{' \ -e ':c' -e 'p' -e 'n' -e '/^ /bc' -e 'bt' -e '}' EXE.targets = awk '/^[_a-zA-Z][_a-zA-Z.]* *:/{sub(/:/,"",$$1);print $$1}' EXE.syntax = sed -n -e 's/^\#\.//p' EXE.wordperline = tr -s " $(_TAB)" "$(_NL)$(_NL)" # # must use " so that make's variables are evaluated correctly EXE.wordperline = awk '{for(i=1;i<=NF;i++){printf("\t\t %s\n",$$i)}}' # NOTE all EXE.* macros above cannot be shown using echo, eval or show target # they all may return errors like: /bin/sh: 1: Syntax error:... # other tools OPT.cloc = EXE.cloc = cloc $(OPT.cloc) #_____________________________________________________________________________ #_____________________________________________________________ help targets __| # no HELP-* macros are used herein to avoid printing their content with "make" HELP.help = " \ \# __________________________ targets for help about Makefile _$(_NL)\ macros - list all macro names used in Makefile* (alias: list, vars)$(_NL)\ targets - list all targets used in Makefile* (alias: rules)$(_NL)\ macros.me - list all macro names used in calling Makefile$(_NL)\ targets.me - list all targets used in calling Makefile$(_NL)\ e-MACRO - show content of MACRO expanded (all in one line)$(_NL)\ s-MACRO - show content of MACRO expanded (one word per line)$(_NL)\ m-MACRO - show definition of MACRO as is --exact macro match$(_NL)\ p-MACRO - show all definitions of MACRO as is --macro pattern match$(_NL)\ t-TARGET - show TARGET --exact target match$(_NL)\ $(_NL)\ \# ________________________________ targets for documentation _$(_NL)\ help.doc - print this documentation$(_NL)\ help.test - print documentation about test targets$(_NL)\ help.critic - print documentation about perlcritic targets$(_NL)\ help.syntax - print documentation about syntax used in Makefile.*$(_NL)\ help.HEAD - print header line for documentation texts$(_NL)\ $(_NL)\ " ALL.help +=$(HELP.help) # TODO: auch zu ALL.help.test ?? help.help: help.HEAD @$(EXE.help) $(_MYSELF.help) @echo $(HELP.help) ; # no quotes! help.doc: help.help # legacy alias help.syntax: $(EXE.syntax) Makefile.help help.HEAD: @echo "$(_HELP_HEADER_)" .PHONY: help.doc help.help help.syntax help.HEAD #dbx _isempty: @echo "# target: $($@) - $($($@))." # NOTE: following target is adapted to be use in echo, show, macro and target # targets, hence the target name must be recursively evaluated, that's # why we use $($($@)) instead of $($@) _notempty: @if [ '$($($@))' = '' ]; then \ $(ECHO) "$(HELP-$($@))"; \ $(ECHO) "$(_HELP_USAGE_)"; \ exit 1; \ fi; @$(ECHO) "$(_HELP_HEADER_)" _line: @echo "" @$(ECHO) "$(_TAB)$(_TAB)$($($@))" .PHONY: _notempty _line macros: @$(TARGET_VERBOSE) @$(EXE.list) $(MAKEFILE_LIST) | sort macros%me: @$(TARGET_VERBOSE) @$(EXE.list) $(MAKEFILE) | sort vars: macros list: macros lists%me: macros.me targets: @$(TARGET_VERBOSE) @$(EXE.targets) $(MAKEFILE_LIST) | sort -u targets%me: @$(TARGET_VERBOSE) @$(EXE.targets) $(MAKEFILE) | sort -u rules: targets rules%me: targets.me eval: @$(TARGET_VERBOSE) @$(ECHO) "$($@)$(_TAB)$(_TAB)- $(HELP-$($@))" echo: @$(TARGET_VERBOSE) @$(ECHO) '$($($@))' show: _notempty=show show: _notempty @$(TARGET_VERBOSE) @$(ECHO) '$($@) = ' @$(ECHO) '$($($@))' | $(EXE.wordperline) macro: _notempty=macro macro: _notempty @$(TARGET_VERBOSE) @$(EXE.macro) $(MAKEFILE_LIST) makro: macro pmacro: _notempty=pmacro pmacro: _notempty @$(TARGET_VERBOSE) @$(EXE.pmacro) $(MAKEFILE_LIST) target: _notempty=target target: _notempty @$(TARGET_VERBOSE) @$(EXE.target) $(MAKEFILE_LIST) # following rules are shortcuts for the above targets e-%: @$(MAKE) -s echo=$* echo f-%: @$(MAKE) -s eval=$* eval _f-%: @$(MAKE) -s _line=$* _line s-%: @$(MAKE) -s show=$* show m-%: @$(MAKE) -s macro=$* macro p-%: @$(MAKE) -s pmacro=$* pmacro t-%: @$(MAKE) -s target=$* target # cloc is not realy a "help" target, anyway defined here as rarely use is expected HELP-_cloc = ________________________________________ statistic targets _ HELP-cloc = count lines of code of all source files; summary output HELP-cloc.file = count lines of code of all source files; output by file HELP-cloc.lang = same as cloc.file and cloc # NOTE: also possible usage: # make cloc OPT.cloc=--3 # make cloc OPT.cloc=--csv # make cloc OPT.cloc=--xml # NOTE: --quiet suppresses count of files also, hence not used by default cloc%: @$(TARGET_VERBOSE) @$(EXE.cloc) $(sort $(ALL.src)) cloc.stat: OPT.cloc += cloc.file: OPT.cloc += --by-file cloc.lang: OPT.cloc += --by-file-by-lang cloc: cloc.stat .PHONY: macros targets rules list vars eval echo show macro pmacro target cloc O-Saft-19.01.19/Net/000077500000000000000000000000001342117255600136015ustar00rootroot00000000000000O-Saft-19.01.19/Net/SSLhello.pm000077500000000000000000012247121342117255600156400ustar00rootroot00000000000000#!/usr/bin/perl -w ## PACKAGE { # Filename : SSLhello.pm #!############################################################################# #!# Copyright (c) Torsten Gigler #!# This module is part of the OWASP-Project 'o-saft' #!# It simulates the SSLhello packets to check SSL parameters like the ciphers #!# indepenantly from any SSL library like Openssl or gnutls. #!#---------------------------------------------------------------------------- #!# THIS Software is in ALPHA state, please give us feed back via #!# https://lists.owasp.org/mailman/listinfo/o-saft #!#---------------------------------------------------------------------------- #!# This software is provided "as is", without warranty of any kind, express or #!# implied, including but not limited to the warranties of merchantability, #!# fitness for a particular purpose. In no event shall the copyright holders #!# or authors be liable for any claim, damages or other liability. #!# This software is distributed in the hope that it will be useful. #!# #!# This software is licensed under GPLv2. #!# #!# GPL - The GNU General Public License, version 2 #!# as specified in: http://www.gnu.org/licenses/gpl-2.0 #!# or a copy of it https://github.com/OWASP/O-Saft/blob/master/LICENSE.md #!# Permits anyone the right to use and modify the software without limitations #!# as long as proper credits are given and the original and modified source #!# code are included. Requires that the final product, software derivate from #!# the original source or any software utilizing a GPL component, such as #!# this, is also licensed under the same GPL license. #!############################################################################# #!# WARNING: #!# This is no "academically" certified code, but written to be understood and #!# modified by humans (you:) easily. Please see the documentation in section #!# "Program Code" at the end of this file if you want to improve the program. # TODO: check if SNI-extension is supported by the server, if 'usesni' is set ## no critic qw(Subroutines::ProhibitSubroutinePrototypes) # NOTE: Contrary to Perl::Critic we consider prototypes as useful, even if # the compile-time checks of Perl are not perfect, Perl may give some # hints. ## no critic qw(Variables::ProhibitPackageVars) # NOTE: we have a couple of global variables, but do not want to write them in # all CAPS (as it would be required by Perl::Critic) package Net::SSLhello; use strict; use warnings; use constant { ## no critic qw(ValuesAndExpressions::ProhibitConstantPragma) SSLHELLO_VERSION=> '18.06.03', SSLHELLO => 'O-Saft::Net::SSLhello', # SSLHELLO_SID => '@(#) SSLhello.pm 1.31 18/07/03 09:16:19', }; use Socket; ## TBD will be deleted soon TBD ### use IO::Socket::INET; #require IO::Select if ($main::cfg{'trace'} > 1); use Carp; use OSaft::error_handler qw (:sslhello_contants); # use internal error_handler, get all constants used for SSLHELLO, for subs # the full names will be used (includung OSaft::error_handler->) ######################################################## public documentation # =pod =head1 NAME Net::SSLhello - Perl extension for SSL to simulate SSLhello packets to check SSL parameters (especially ciphers). Connections via proxy and using STARTTLS (SMTP, IMAP, POP3, FTPS, LDAP, RDP, XMPP and experimental: ACAP) are supported. =head1 SYNOPSIS use Net::SSLhello; =head1 DESCRIPTION SSLhello.pm is a Perl Module that is part of the OWASP-Project 'o-saft'. It checks some basic SSL/TLS configuration of a server, like ciphers and extensions (planned) of the SSL/TLS protocol. These checks work independantly from any SSL library like openSSL or gnutls. It does this by simulating the first packets of a SSL/TLS connection. It sends a ClientHello message and analyzes the ServerHello packet that is answered by the server. It gives you a wide range of options for this, so you can even check ciphers that are not yet defined, reserved or obsole, by their 2-octett-values (see http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4). As it simulates only the first part of the SSL/TLS handshake, it is really fast! Another advantage of this is that it can even analyze SSL/TLS ciphers of servers that verify client certificates without any need to provide one (this is normally done later in the SSL/TLS handshake). Export Functions: $socket = openTcpSSLconnection ($host; $port); # Open a TCP/IP connection to a host on a port (via proxy) and doing STARTTLS if requested @accepted = Net::SSLhello::checkSSLciphers ($host, $port, $ssl, @testing); # Check a list if ciphers (@testing), output: @accepted ciphers (if the first 2 ciphers are equal the server has an order) Net::SSLhello::printCipherStringArray ($cfg{'legacy'}, $host, $port, $ssl, $sni, @accepted); # print the list of ciphers (@accepted ciphers) =head1 METHODS =cut #our %main::cfg; # provided by caller our $dtlsEpoch = 0; # for DTLS only (globally) our %_SSLhello; # our internal data structure our $my_error = ""; # global store for error message use Exporter qw(import); use base qw(Exporter); our $VERSION = SSLHELLO_VERSION; our @EXPORT_OK = qw( net_sslhello_done checkSSLciphers compileClientHello compileSSL2CipherArray compileTLSCipherArray hexCodedCipher hexCodedSSL2Cipher hexCodedString hexCodedTLSCipher openTcpSSLconnection parseServerHello parseServerKeyExchange parseSSL2_ServerHello parseTLS_Extension parseTLS_ServerHello printCipherStringArray printParameters printSSL2CipherList printTLSCipherList version ); our $HAVE_XS = eval { local $SIG{'__DIE__'} = 'DEFAULT'; eval { require XSLoader; XSLoader::load('Net::SSLhello', $VERSION); 1; } or do { require DynaLoader; bootstrap Net::SSLhello $VERSION; 1; }; } ? 1 : 0; # All Main Parameters, Constants, Lists and Functions that are used by o-saft andSSLhello use osaft; # TBD add "raw"; use constant { ## no critic qw(ValuesAndExpressions::ProhibitConstantPragma) _MY_SSL3_MAX_CIPHERS => 64, # Max nr of ciphers sent in a SSL3/TLS Client-Hello to test if they are supported by the server, e.g. 32, 48, 64, 128, ... _MY_PRINT_CIPHERS_PER_LINE => 8, # Nr of ciphers printed in a trace _PROXY_CONNECT_MESSAGE1 => "CONNECT ", _PROXY_CONNECT_MESSAGE2 => " HTTP/1.1\n\n", _MAX_SEGMENT_COUNT_TO_RESET_RETRY_COUNT => 16, # Max number og TCP-Segments that can reset the retry counter to '0' for next read _SLEEP_B4_2ND_READ => 0.5, # Sleep before second read (STARTTLS and proxy) [in sec.x] _DTLS_SLEEP_AFTER_FOUND_A_CIPHER => 0.75, # DTLS-Protocol: Sleep after found a cipher to segregate the following request [in sec.x] _DTLS_SLEEP_AFTER_NO_CIPHERS_FOUND => 0.05 # DTLS-Protocol: Sleep after not found a cipher to segregate the following request [in sec.x] }; #our $LONG_PACKET = 1940; # try to get a 2nd or 3rd segment for long packets # # #defaults for global parameters $Net::SSLhello::trace = 0;# 1=simple debugging Net::SSLhello $Net::SSLhello::traceTIME = 0;# 1=trace prints timestamp $Net::SSLhello::usesni = 1;# 0=do not use SNI extension, 1=use SNI extension (protocol >=tlsv1), 2(or 3): toggle sni (run twice per protocol without and with sni) $Net::SSLhello::use_sni_name = 0;# 0=use hostname (default), 1: use sni_name for SNI mode connections $Net::SSLhello::sni_name = "1";# name to be used for SNI mode connection is use_sni_name=1; ###FIX: "1": quickfix until migration of o-saft.pl is compleated (tbd) $Net::SSLhello::force_TLS_extensions= 0;# prevent to not to use TLS extensions in SSLv3 $Net::SSLhello::timeout = 2;# time in seconds $Net::SSLhello::retry = 3;# number of retry when timeout occurs $Net::SSLhello::connect_delay = 0;# time to wait in seconds for starting next cipher check $Net::SSLhello::usereneg = 0;# secure renegotiation $Net::SSLhello::use_signature_alg = 1;# signature_algorithm: 0 (off), 1 (auto on if >=TLSv1.2, >=DTLS1.2), 2: always on $Net::SSLhello::useecc = 1;# use 'Supported Elliptic' Curves Extension $Net::SSLhello::useecpoint = 1;# use 'ec_point_formats' extension $Net::SSLhello::starttls = 0;# 1= do STARTTLS $Net::SSLhello::starttlsType = "SMTP";# default: SMTP @Net::SSLhello::starttlsPhaseArray = [];# STARTTLS: customized phases (1-5) and error handling (6-8) $Net::SSLhello::starttlsDelay = 0;# STARTTLS: time to wait in seconds (to slow down the requests) $Net::SSLhello::slowServerDelay = 0;# proxy and STARTTLS: time to wait in seconds (for slow proxies and STARTTLS servers) $Net::SSLhello::double_reneg = 0;# 0=Protection against double renegotiation info is active $Net::SSLhello::proxyhost = "";# $Net::SSLhello::proxyport = "";# $Net::SSLhello::experimental = 0;# 0: experimental functions are protected (=not active) $Net::SSLhello::max_ciphers = _MY_SSL3_MAX_CIPHERS; # max nr of ciphers sent in a SSL3/TLS Client-Hello to test if they are supported by the server $Net::SSLhello::max_sslHelloLen = 16388; # according RFC: 16383+5 bytes; max len of sslHello messages (some implementations had issues with packets longer than 256 bytes) $Net::SSLhello::noDataEqNoCipher = 1; # 1= for some TLS intolerant servers 'NoData or timeout equals to no cipher' supported -> Do NOT abort to test next ciphers my %RECORD_TYPE = ( # RFC 5246 'change_cipher_spec' => 20, 'alert' => 21, 'handshake' => 22, 'application_data' => 23, 'heartbeat' => 24, '255' => 255, '<>' => -1 # added for internal use ); my %HANDSHAKE_TYPE = ( # RFC 5246 'hello_request' => 0, 'client_hello' => 1, 'server_hello' => 2, 'hello_verify_request' => 3, # rfc4347 DTLS 'certificate' => 11, 'server_key_exchange' => 12, 'certificate_request' => 13, 'server_hello_done' => 14, 'certificate_verify' => 15, 'client_key_exchange' => 16, 'finished' => 20, '255' => 255, '<>' => -1, # added for internal use '<>'=> -99 # added for internal use ); my %PROTOCOL_VERSION = ( 'SSLv2' => 0x0002, 'SSLv3' => 0x0300, 'TLSv1' => 0x0301, # TLS1.0 = SSL3.1 'TLSv11' => 0x0302, # TLS1.1 'TLSv12' => 0x0303, # TLS1.2 'TLSv13' => 0x0304, # TLS1.3, not YET specified 'TLSv1.FF' => 0x03FF, # Last possible Version of TLS1.x (NOT specified) 'DTLSv09' => 0x0100, # DTLS, OpenSSL pre 0.9.8f, not finally standardized (udp) 'DTLSfamily' => 0xFE00, # DTLS1.FF, no defined PROTOCOL, for internal usea only (udp) 'DTLSv1' => 0xFEFF, # DTLS1.0 (udp) 'DTLSv11' => 0xFEFE, # DTLS1.1: has NEVER been used (udp) 'DTLSv12' => 0xFEFD, # DTLS1.2 (udp) 'DTLSv13' => 0xFEFC, # DTLS1.3, not YET specified (udp) 'SCSV' => 0x03FF # adapted to o-saft.pl, was TLS1.FF # FIXME: TLS1.FF was better ;-) TBD: change it at o-saft.pl and delete it here ); # http://www.iana.org/assignments/tls-parameters/tls-parameters-6.csv # Value,Description,DTLS-OK,Reference my %TLS_AlertDescription = ( 0 => [qw(close_notify Y [RFC5246])], 10 => [qw(unexpected_message Y [RFC5246])], 20 => [qw(bad_record_mac Y [RFC5246])], 21 => [qw(decryption_failed Y [RFC5246])], 22 => [qw(record_overflow Y [RFC5246])], 30 => [qw(decompression_failure Y [RFC5246])], 40 => [qw(handshake_failure Y [RFC5246])], 41 => [qw(no_certificate_RESERVED Y [RFC5246])], 42 => [qw(bad_certificate Y [RFC5246])], 43 => [qw(unsupported_certificate Y [RFC5246])], 44 => [qw(certificate_revoked Y [RFC5246])], 45 => [qw(certificate_expired Y [RFC5246])], 46 => [qw(certificate_unknown Y [RFC5246])], 47 => [qw(illegal_parameter Y [RFC5246])], 48 => [qw(unknown_ca Y [RFC5246])], 49 => [qw(access_denied Y [RFC5246])], 50 => [qw(decode_error Y [RFC5246])], 51 => [qw(decrypt_error Y [RFC5246])], 60 => [qw(export_restriction_RESERVED Y [RFC5246])], 70 => [qw(protocol_version Y [RFC5246])], 71 => [qw(insufficient_security Y [RFC5246])], 80 => [qw(internal_error Y [RFC5246])], 86 => [qw(inappropriate_fallback Y [RFC5246_update-Draft-2014-05-31])], ### added according 'https://datatracker.ietf.org/doc/draft-bmoeller-tls-downgrade-scsv/?include_text=1' 90 => [qw(user_canceled Y [RFC5246])], 100 => [qw(no_renegotiation Y [RFC5246])], 110 => [qw(unsupported_extension Y [RFC5246])], 111 => [qw(certificate_unobtainable Y [RFC6066])], 112 => [qw(unrecognized_name Y [RFC6066])], 113 => [qw(bad_certificate_status_response Y [RFC6066])], 114 => [qw(bad_certificate_hash_value Y [RFC6066])], 115 => [qw(unknown_psk_identity Y [RFC4279])], ); my %ECCURVE_TYPE = ( # RFC 4492 'explicit_prime' => 1, 'explicit_char2' => 2, 'named_curve' => 3, 'reserved_248' => 248, 'reserved_249' => 249, 'reserved_250' => 250, 'reserved_251' => 251, 'reserved_252' => 252, 'reserved_253' => 253, 'reserved_254' => 254, 'reserved_255' => 255, ); #http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10 #Value => Description bits(added) DTLS-OK Reference my %ECC_NAMED_CURVE = ( 0 => [qw(Unassigned_0 0 N [IANA])], 1 => [qw(sect163k1 163 Y [RFC4492])], 2 => [qw(sect163r1 163 Y [RFC4492])], 3 => [qw(sect163r2 163 Y [RFC4492])], 4 => [qw(sect193r1 193 Y [RFC4492])], 5 => [qw(sect193r2 193 Y [RFC4492])], 6 => [qw(sect233k1 233 Y [RFC4492])], 7 => [qw(sect233r1 233 Y [RFC4492])], 8 => [qw(sect239k1 239 Y [RFC4492])], 9 => [qw(sect283k1 283 Y [RFC4492])], 10 => [qw(sect283r1 283 Y [RFC4492])], 11 => [qw(sect409k1 409 Y [RFC4492])], 12 => [qw(sect409r1 409 Y [RFC4492])], 13 => [qw(sect571k1 571 Y [RFC4492])], 14 => [qw(sect571r1 571 Y [RFC4492])], 15 => [qw(secp160k1 160 Y [RFC4492])], 16 => [qw(secp160r1 160 Y [RFC4492])], 17 => [qw(secp160r2 160 Y [RFC4492])], 18 => [qw(secp192k1 192 Y [RFC4492])], 19 => [qw(secp192r1 192 Y [RFC4492])], 20 => [qw(secp224k1 224 Y [RFC4492])], 21 => [qw(secp224r1 224 Y [RFC4492])], 22 => [qw(secp256k1 256 Y [RFC4492])], 23 => [qw(secp256r1 256 Y [RFC4492])], 24 => [qw(secp384r1 384 Y [RFC4492])], 25 => [qw(secp521r1 521 Y [RFC4492])], 26 => [qw(brainpoolP256r1 256 Y [RFC7027])], 27 => [qw(brainpoolP384r1 384 Y [RFC7027])], 28 => [qw(brainpoolP512r1 512 Y [RFC7027])], 29 => [qw(ecdh_x25519 255 Y [draft-ietf-tls-tls][draft-ietf-tls-rfc4492bis])], #TEMPORARY-registered_2016-02-29,_expires 2017-03-01, 30 => [qw(ecdh_x448 448 Y [draft-ietf-tls-tls][draft-ietf-tls-rfc4492bis])], #TEMPORARY-registered_2016-02-29,_expires 2017-03-01, 31 => [qw(eddsa_ed25519 255 Y [https://tools.ietf.org/html/draft-ietf-tls-tls13-11])], # Signature curves, vanished in https://tools.ietf.org/html/draft-ietf-tls-tls13-12 32 => [qw(eddsa_ed448 448 Y [https://tools.ietf.org/html/draft-ietf-tls-tls13-11])], # Signature curves, vanished in https://tools.ietf.org/html/draft-ietf-tls-tls13-12 256 => [qw(ffdhe2048 2048 Y [RFC-ietf-tls-negotiated-ff-dhe-10])], 257 => [qw(ffdhe3072 3072 Y [RFC-ietf-tls-negotiated-ff-dhe-10])], 258 => [qw(ffdhe4096 4096 Y [RFC-ietf-tls-negotiated-ff-dhe-10])], 259 => [qw(ffdhe6144 6144 Y [RFC-ietf-tls-negotiated-ff-dhe-10])], 260 => [qw(ffdhe8192 8192 Y [RFC-ietf-tls-negotiated-ff-dhe-10])], 65281 => [qw(arbitrary_explicit_prime_curves -variable- Y [RFC4492])], 65282 => [qw(arbitrary_explicit_char2_curves -variable- Y [RFC4492])], ); ################################################################################## # List of Functions ################################################################################## sub checkSSLciphers ($$$@); sub printCipherStringArray ($$$$$@); sub _timedOut; sub _error; # TODO: import/export of the trace-function from o-saft-dbx.pm; # this is a workaround to get trace running using parameter '$main::cfg{'trace'}' ## forward declarations #sub _trace {}; #sub _trace1 {}; #sub _trace2 {}; #sub _trace3 {}; ## Print Errors; Debugging #sub _error { local $\ = "\n"; print ">>>Net::SSLhello>>> ERROR: " . join(" ", @_); } #sub _trace_ { _trace (@_); } #sub _trace1_ { _trace1(@_); } #sub _trace2_ { _trace2(@_); } #sub _trace3_ { _trace3(@_); } #sub _trace4($){ print "# Net::SSLhello::" . join(" ", @_) if ($Net::SSLhello::trace >3); } #sub _trace4_ { _trace4(@_); } sub _y_ts { if ($main::cfg{'traceTIME'} <= 0) { return ""; } return sprintf("[%02s:%02s:%02s] ", (localtime)[2,1,0]) } sub _trace($) { my @messages = @_; local $\ = ""; print "#" . _y_ts() . SSLHELLO . "::" . $messages[0] if ($main::cfg{'trace'} > 0); return } sub _trace0($) { my @messages = @_; local $\ = ""; print "#" . _y_ts() . SSLHELLO . "::" if ($main::cfg{'trace'} > 0); return } sub _trace1($) { my @messages = @_; local $\ = ""; print "# " . _y_ts() . SSLHELLO . "::" . join(" ", @messages) if ($main::cfg{'trace'} > 1); return } sub _trace2($) { my @messages = @_; local $\ = ""; print "# --> " . _y_ts() . SSLHELLO . "::" . join(" ", @messages) if ($main::cfg{'trace'} > 2); return } sub _trace3($) { my @messages = @_; local $\ = ""; print "# --> " . _y_ts() . SSLHELLO . "::" . join(" ", @messages) if ($main::cfg{'trace'} ==3); return } sub _trace4($) { my @messages = @_; local $\ = ""; print "# ---> " . _y_ts() . SSLHELLO . "::" . join(" ", @messages) if ($main::cfg{'trace'} > 3); return } sub _trace_($) { my @messages = @_; local $\ = ""; print " " . join(" ", @messages) if ($main::cfg{'trace'} > 0); return } sub _trace1_($){ my @messages = @_; local $\ = ""; print " " . join(" ", @messages) if ($main::cfg{'trace'} > 1); return } sub _trace2_($){ my @messages = @_; local $\ = ""; print join(" ", @messages) if ($main::cfg{'trace'} > 2); return } sub _trace3_($){ my @messages = @_; local $\ = ""; print join(" ", @messages) if ($main::cfg{'trace'} ==3); return } sub _trace4_($){ my @messages = @_; local $\ = ""; print join(" ", @messages) if ($main::cfg{'trace'} > 3); return } sub _carp { #? print warning message if wanted # don't print if --no-warning given my @txt = @_; return if ((grep{/(:?--no.?warn)/ix} @main::ARGV) > 0); local $\ = "\n"; carp(STR_WARN, join(" ", @txt)); return; } sub _hint { #? print hint message if wanted # don't print if --no-hint given my @txt = @_; return if ((grep{/(:?--no.?hint)/ix} @main::ARGV) > 0); local $\ = "\n"; print(STR_HINT, join(" ", @txt)); return; } #if (! eval("require o-saft-dbx.pm;")) { # # o-saft-dbx.pm may not be installed, try to find in program's directory # push(@INC, $main::mepath); # require "o-saft-dbx.pm"; #} ### end trace functions ################################################################################### my $CHALLENGE = "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20o-saft\xbb\xcc\xdd\xee\xff"; # 16-32 bytes, ################################################################################## # sslv2 ################################################################################## #http://www-archive.mozilla.org/projects/security/pki/nss/ssl/draft02.html ################################################################################## # Information: not all parameters are used within SSLhello.pm #C.1 Protocol Version Codes my $SSL_CLIENT_VERSION = 0x0002; my $SSL_SERVER_VERSION = 0x0002; #C.2 Protocol Message Codes #The following values define the message codes that are used by version 2 of the SSL Handshake Protocol. # SSL2_PROTOCOL_MESSAGE_CODES my $SSL_MT_ERROR = 0; my $SSL_MT_CLIENT_HELLO = 1; my $SSL_MT_CLIENT_MASTER_KEY = 2; my $SSL_MT_CLIENT_FINISHED = 3; my $SSL_MT_SERVER_HELLO = 4; my $SSL_MT_SERVER_VERIFY = 5; my $SSL_MT_SERVER_FINISHED = 6; my $SSL_MT_REQUEST_CERTIFICATE = 7; my $SSL_MT_CLIENT_CERTIFICATE = 8; #C.3 Error Message Codes #The following values define the error codes used by the ERROR message. my $SSL_PE_NO_CIPHER = 0x0001; my $SSL_PE_NO_CERTIFICATE = 0x0002; my $SSL_PE_BAD_CERTIFICATE = 0x0004; my $SSL_PE_UNSUPPORTED_CERTIFICATE_TYPE = 0x0006; #C.5 Certificate Type Codes #The following values define the certificate type codes used in the SERVER-HELLO and CLIENT-CERTIFICATE messages. my $SSL_CT_X509_CERTIFICATE = 0x01; #C.6 Authentication Type Codes #The following values define the authentication type codes used in the REQUEST-CERTIFICATE message. my $SSL_AT_MD5_WITH_RSA_ENCRYPTION = 0x01; #C.7 Upper/Lower Bounds #The following values define upper/lower bounds for various protocol parameters. my $SSL_MAX_MASTER_KEY_LENGTH_IN_BITS = 256; my $SSL_MAX_SESSION_ID_LENGTH_IN_BYTES = 16; my $SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES = 64; my $SSL_MAX_RECORD_LENGTH_2_BYTE_HEADER = 32767; my $SSL_MAX_RECORD_LENGTH_3_BYTE_HEADER = 16383; #C.8 Recommendations #Because protocols have to be implemented to be of value, we recommend the following values for various operational parameters. This is only a recommendation, and not a strict requirement for conformance to the protocol. ################################################################# my %cipherHexHash = ( #!#----------------------------------------+-------------+--------------------+ #!# Protocol: SSL2 (uppercase!) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x020700C0'=> [qw(DES_192_EDE3_CBC_WITH_MD5 DES-CBC3-MD5)], '0x020701C0'=> [qw(DES_192_EDE3_CBC_WITH_SHA DES-CBC3-SHA)], '0x02060040'=> [qw(DES_64_CBC_WITH_MD5 DES-CBC-MD5)], '0x02060140'=> [qw(DES_64_CBC_WITH_SHA DES-CBC-SHA)], '0x02FF0800'=> [qw(DES_64_CFB64_WITH_MD5_1 DES-CFB-M1)], '0x02050080'=> [qw(IDEA_128_CBC_WITH_MD5 IDEA-CBC-MD5)], '0x02FF0810'=> [qw(NULL NULL)], '0x02000000'=> [qw(NULL_WITH_MD5 NULL-MD5)], '0x02040080'=> [qw(RC2_128_CBC_EXPORT40_WITH_MD5 EXP-RC2-CBC-MD5)], '0x02030080'=> [qw(RC2_128_CBC_WITH_MD5 RC2-CBC-MD5)], '0x02020080'=> [qw(RC4_128_EXPORT40_WITH_MD5 EXP-RC4-MD5)], '0x02010080'=> [qw(RC4_128_WITH_MD5 RC4-MD5)], '0x02080080'=> [qw(RC4_64_WITH_MD5 RC4-64-MD5)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: SSL3 (invented) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300001B'=> [qw(ADH_WITH_DES_192_CBC3_SHA ADH-DES-CBC3-SHA)], '0x03000019'=> [qw(ADH_WITH_DES_40_CBC_SHA EXP-ADH-DES-CBC-SHA)], '0x0300001A'=> [qw(ADH_WITH_DES_64_CBC_SHA ADH-DES-CBC-SHA)], '0x03000018'=> [qw(ADH_WITH_RC4_128_MD5 ADH-RC4-MD5)], '0x03000017'=> [qw(ADH_WITH_RC4_40_MD5 EXP-ADH-RC4-MD5)], '0x0300000D'=> [qw(DH_DSS_WITH_DES_192_CBC3_SHA DH-DSS-DES-CBC3-SHA)], '0x0300000B'=> [qw(DH_DSS_WITH_DES_40_CBC_SHA EXP-DH-DSS-DES-CBC-SHA)], '0x0300000C'=> [qw(DH_DSS_WITH_DES_64_CBC_SHA DH-DSS-DES-CBC-SHA)], '0x03000010'=> [qw(DH_RSA_WITH_DES_192_CBC3_SHA DH-RSA-DES-CBC3-SHA)], '0x0300000E'=> [qw(DH_RSA_WITH_DES_40_CBC_SHA EXP-DH-RSA-DES-CBC-SHA)], '0x0300000F'=> [qw(DH_RSA_WITH_DES_64_CBC_SHA DH-RSA-DES-CBC-SHA)], '0x03000013'=> [qw(EDH_DSS_WITH_DES_192_CBC3_SHA EDH-DSS-DES-CBC3-SHA)], '0x03000011'=> [qw(EDH_DSS_WITH_DES_40_CBC_SHA EXP-EDH-DSS-DES-CBC-SHA)], '0x03000012'=> [qw(EDH_DSS_WITH_DES_64_CBC_SHA EDH-DSS-DES-CBC-SHA)], '0x03000016'=> [qw(EDH_RSA_WITH_DES_192_CBC3_SHA EDH-RSA-DES-CBC3-SHA)], '0x03000014'=> [qw(EDH_RSA_WITH_DES_40_CBC_SHA EXP-EDH-RSA-DES-CBC-SHA)], '0x03000015'=> [qw(EDH_RSA_WITH_DES_64_CBC_SHA EDH-RSA-DES-CBC-SHA)], '0x0300001D'=> [qw(FZA_DMS_FZA_SHA FZA-FZA-CBC-SHA)], '0x0300001C'=> [qw(FZA_DMS_NULL_SHA FZA-NULL-SHA)], '0x0300001E'=> [qw(FZA_DMS_RC4_SHA FZA-RC4-SHA)], '0x03000023'=> [qw(KRB5_WITH_DES_192_CBC3_MD5 KRB5-DES-CBC3-MD5)], '0x0300001F'=> [qw(KRB5_WITH_DES_192_CBC3_SHA KRB5-DES-CBC3-SHA)], '0x03000029'=> [qw(KRB5_WITH_DES_40_CBC_MD5 EXP-KRB5-DES-CBC-MD5)], '0x03000026'=> [qw(KRB5_WITH_DES_40_CBC_SHA EXP-KRB5-DES-CBC-SHA)], '0x03000022'=> [qw(KRB5_WITH_DES_64_CBC_MD5 KRB5-DES-CBC-MD5)], '0x0300001E'=> [qw(KRB5_WITH_DES_64_CBC_SHA KRB5-DES-CBC-SHA)], '0x03000025'=> [qw(KRB5_WITH_IDEA_128_CBC_MD5 KRB5-IDEA-CBC-MD5)], '0x03000021'=> [qw(KRB5_WITH_IDEA_128_CBC_SHA KRB5-IDEA-CBC-SHA)], '0x0300002A'=> [qw(KRB5_WITH_RC2_40_CBC_MD5 EXP-KRB5-RC2-CBC-MD5)], '0x03000027'=> [qw(KRB5_WITH_RC2_40_CBC_SHA EXP-KRB5-RC2-CBC-SHA)], '0x03000024'=> [qw(KRB5_WITH_RC4_128_MD5 KRB5-RC4-MD5)], '0x03000020'=> [qw(KRB5_WITH_RC4_128_SHA KRB5-RC4-SHA)], '0x0300002B'=> [qw(KRB5_WITH_RC4_40_MD5 EXP-KRB5-RC4-MD5)], '0x03000028'=> [qw(KRB5_WITH_RC4_40_SHA EXP-KRB5-RC4-SHA)], '0x0300000A'=> [qw(RSA_WITH_DES_192_CBC3_SHA DES-CBC3-SHA)], '0x03000008'=> [qw(RSA_WITH_DES_40_CBC_SHA EXP-DES-CBC-SHA)], '0x03000009'=> [qw(RSA_WITH_DES_64_CBC_SHA DES-CBC-SHA)], '0x03000007'=> [qw(RSA_WITH_IDEA_128_SHA IDEA-CBC-SHA)], '0x03000000'=> [qw(NULL_WITH_NULL_NULL NULL-NULL)], '0x03000001'=> [qw(RSA_WITH_NULL_MD5 NULL-MD5)], '0x03000002'=> [qw(RSA_WITH_NULL_SHA NULL-SHA)], '0x03000006'=> [qw(RSA_WITH_RC2_40_MD5 EXP-RC2-CBC-MD5)], '0x03000004'=> [qw(RSA_WITH_RC4_128_MD5 RC4-MD5)], '0x03000005'=> [qw(RSA_WITH_RC4_128_SHA RC4-SHA)], '0x03000003'=> [qw(RSA_WITH_RC4_40_MD5 EXP-RC4-MD5)], '0x030000FF'=> [qw(EMPTY_RENEGOTIATION_INFO_SCSV SCSV-RENEG)], #activated 'Signaling Cipher Suite Value' '0x03005600'=> [qw(FALLBACK_SCSV_DRAFT SCSV-FALLBACK-DRAFT)], ### added according 'https://datatracker.ietf.org/doc/draft-bmoeller-tls-downgrade-scsv/?include_text=1' #!#----------------------------------------+-------------+--------------------+ #!# Protocol: TLS 1.0 (invented) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x030000A6'=> [qw(ADH_WITH_AES_128_GCM_SHA256 ADH-AES128-GCM-SHA256)], '0x03000034'=> [qw(ADH_WITH_AES_128_SHA ADH-AES128-SHA)], '0x0300006C'=> [qw(ADH_WITH_AES_128_SHA256 ADH-AES128-SHA256)], '0x030000A7'=> [qw(ADH_WITH_AES_256_GCM_SHA384 ADH-AES256-GCM-SHA384)], '0x0300003A'=> [qw(ADH_WITH_AES_256_SHA ADH-AES256-SHA)], '0x0300006D'=> [qw(ADH_WITH_AES_256_SHA256 ADH-AES256-SHA256)], '0x03000046'=> [qw(ADH_WITH_CAMELLIA_128_CBC_SHA ADH-CAMELLIA128-SHA)], '0x03000089'=> [qw(ADH_WITH_CAMELLIA_256_CBC_SHA ADH-CAMELLIA256-SHA)], '0x0300009B'=> [qw(ADH_WITH_SEED_SHA ADH-SEED-SHA)], '0x03000063'=> [qw(DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA EXP1024-DHE-DSS-DES-CBC-SHA)], '0x03000065'=> [qw(DHE_DSS_EXPORT1024_WITH_RC4_56_SHA EXP1024-DHE-DSS-RC4-SHA)], '0x030000A2'=> [qw(DHE_DSS_WITH_AES_128_GCM_SHA256 DHE-DSS-AES128-GCM-SHA256)], '0x03000032'=> [qw(DHE_DSS_WITH_AES_128_SHA DHE-DSS-AES128-SHA)], '0x03000040'=> [qw(DHE_DSS_WITH_AES_128_SHA256 DHE-DSS-AES128-SHA256)], '0x030000A3'=> [qw(DHE_DSS_WITH_AES_256_GCM_SHA384 DHE-DSS-AES256-GCM-SHA384)], '0x03000038'=> [qw(DHE_DSS_WITH_AES_256_SHA DHE-DSS-AES256-SHA)], '0x0300006A'=> [qw(DHE_DSS_WITH_AES_256_SHA256 DHE-DSS-AES256-SHA256)], '0x03000044'=> [qw(DHE_DSS_WITH_CAMELLIA_128_CBC_SHA DHE-DSS-CAMELLIA128-SHA)], '0x03000087'=> [qw(DHE_DSS_WITH_CAMELLIA_256_CBC_SHA DHE-DSS-CAMELLIA256-SHA)], '0x03000066'=> [qw(DHE_DSS_WITH_RC4_128_SHA DHE-DSS-RC4-SHA)], '0x03000099'=> [qw(DHE_DSS_WITH_SEED_SHA DHE-DSS-SEED-SHA)], '0x0300009E'=> [qw(DHE_RSA_WITH_AES_128_GCM_SHA256 DHE-RSA-AES128-GCM-SHA256)], '0x03000033'=> [qw(DHE_RSA_WITH_AES_128_SHA DHE-RSA-AES128-SHA)], '0x03000067'=> [qw(DHE_RSA_WITH_AES_128_SHA256 DHE-RSA-AES128-SHA256)], '0x0300009F'=> [qw(DHE_RSA_WITH_AES_256_GCM_SHA384 DHE-RSA-AES256-GCM-SHA384)], '0x03000039'=> [qw(DHE_RSA_WITH_AES_256_SHA DHE-RSA-AES256-SHA)], '0x0300006B'=> [qw(DHE_RSA_WITH_AES_256_SHA256 DHE-RSA-AES256-SHA256)], '0x03000045'=> [qw(DHE_RSA_WITH_CAMELLIA_128_CBC_SHA DHE-RSA-CAMELLIA128-SHA)], '0x03000088'=> [qw(DHE_RSA_WITH_CAMELLIA_256_CBC_SHA DHE-RSA-CAMELLIA256-SHA)], '0x0300009A'=> [qw(DHE_RSA_WITH_SEED_SHA DHE-RSA-SEED-SHA)], '0x030000A4'=> [qw(DH_DSS_WITH_AES_128_GCM_SHA256 DH-DSS-AES128-GCM-SHA256)], '0x03000030'=> [qw(DH_DSS_WITH_AES_128_SHA DH-DSS-AES128-SHA)], '0x0300003E'=> [qw(DH_DSS_WITH_AES_128_SHA256 DH-DSS-AES128-SHA256)], '0x030000A5'=> [qw(DH_DSS_WITH_AES_256_GCM_SHA384 DH-DSS-AES256-GCM-SHA384)], '0x03000036'=> [qw(DH_DSS_WITH_AES_256_SHA DH-DSS-AES256-SHA)], '0x03000068'=> [qw(DH_DSS_WITH_AES_256_SHA256 DH-DSS-AES256-SHA256)], '0x03000042'=> [qw(DH_DSS_WITH_CAMELLIA_128_CBC_SHA DH-DSS-CAMELLIA128-SHA)], '0x03000085'=> [qw(DH_DSS_WITH_CAMELLIA_256_CBC_SHA DH-DSS-CAMELLIA256-SHA)], '0x03000097'=> [qw(DH_DSS_WITH_SEED_SHA DH-DSS-SEED-SHA)], '0x030000A0'=> [qw(DH_RSA_WITH_AES_128_GCM_SHA256 DH-RSA-AES128-GCM-SHA256)], '0x03000031'=> [qw(DH_RSA_WITH_AES_128_SHA DH-RSA-AES128-SHA)], '0x0300003F'=> [qw(DH_RSA_WITH_AES_128_SHA256 DH-RSA-AES128-SHA256)], '0x030000A1'=> [qw(DH_RSA_WITH_AES_256_GCM_SHA384 DH-RSA-AES256-GCM-SHA384)], '0x03000037'=> [qw(DH_RSA_WITH_AES_256_SHA DH-RSA-AES256-SHA)], '0x03000069'=> [qw(DH_RSA_WITH_AES_256_SHA256 DH-RSA-AES256-SHA256)], '0x03000043'=> [qw(DH_RSA_WITH_CAMELLIA_128_CBC_SHA DH-RSA-CAMELLIA128-SHA)], '0x03000086'=> [qw(DH_RSA_WITH_CAMELLIA_256_CBC_SHA DH-RSA-CAMELLIA256-SHA)], '0x03000098'=> [qw(DH_RSA_WITH_SEED_SHA DH-RSA-SEED-SHA)], '0x0300C009'=> [qw(ECDHE_ECDSA_WITH_AES_128_CBC_SHA ECDHE-ECDSA-AES128-SHA)], '0x0300C02B'=> [qw(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ECDHE-ECDSA-AES128-GCM-SHA256)], '0x0300C023'=> [qw(ECDHE_ECDSA_WITH_AES_128_SHA256 ECDHE-ECDSA-AES128-SHA256)], '0x0300C00A'=> [qw(ECDHE_ECDSA_WITH_AES_256_CBC_SHA ECDHE-ECDSA-AES256-SHA)], '0x0300C02C'=> [qw(ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 ECDHE-ECDSA-AES256-GCM-SHA384)], '0x0300C024'=> [qw(ECDHE_ECDSA_WITH_AES_256_SHA384 ECDHE-ECDSA-AES256-SHA384)], '0x0300C008'=> [qw(ECDHE_ECDSA_WITH_DES_192_CBC3_SHA ECDHE-ECDSA-DES-CBC3-SHA)], '0x0300C006'=> [qw(ECDHE_ECDSA_WITH_NULL_SHA ECDHE-ECDSA-NULL-SHA)], '0x0300C007'=> [qw(ECDHE_ECDSA_WITH_RC4_128_SHA ECDHE-ECDSA-RC4-SHA)], '0x0300C013'=> [qw(ECDHE_RSA_WITH_AES_128_CBC_SHA ECDHE-RSA-AES128-SHA)], '0x0300C02F'=> [qw(ECDHE_RSA_WITH_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256)], '0x0300C027'=> [qw(ECDHE_RSA_WITH_AES_128_SHA256 ECDHE-RSA-AES128-SHA256)], '0x0300C014'=> [qw(ECDHE_RSA_WITH_AES_256_CBC_SHA ECDHE-RSA-AES256-SHA)], '0x0300C030'=> [qw(ECDHE_RSA_WITH_AES_256_GCM_SHA384 ECDHE-RSA-AES256-GCM-SHA384)], '0x0300C028'=> [qw(ECDHE_RSA_WITH_AES_256_SHA384 ECDHE-RSA-AES256-SHA384)], '0x0300C012'=> [qw(ECDHE_RSA_WITH_DES_192_CBC3_SHA ECDHE-RSA-DES-CBC3-SHA)], '0x0300C010'=> [qw(ECDHE_RSA_WITH_NULL_SHA ECDHE-RSA-NULL-SHA)], '0x0300C011'=> [qw(ECDHE_RSA_WITH_RC4_128_SHA ECDHE-RSA-RC4-SHA)], '0x0300C004'=> [qw(ECDH_ECDSA_WITH_AES_128_CBC_SHA ECDH-ECDSA-AES128-SHA)], '0x0300C02D'=> [qw(ECDH_ECDSA_WITH_AES_128_GCM_SHA256 ECDH-ECDSA-AES128-GCM-SHA256)], '0x0300C025'=> [qw(ECDH_ECDSA_WITH_AES_128_SHA256 ECDH-ECDSA-AES128-SHA256)], '0x0300C005'=> [qw(ECDH_ECDSA_WITH_AES_256_CBC_SHA ECDH-ECDSA-AES256-SHA)], '0x0300C02E'=> [qw(ECDH_ECDSA_WITH_AES_256_GCM_SHA384 ECDH-ECDSA-AES256-GCM-SHA384)], '0x0300C026'=> [qw(ECDH_ECDSA_WITH_AES_256_SHA384 ECDH-ECDSA-AES256-SHA384)], '0x0300C003'=> [qw(ECDH_ECDSA_WITH_DES_192_CBC3_SHA ECDH-ECDSA-DES-CBC3-SHA)], '0x0300C001'=> [qw(ECDH_ECDSA_WITH_NULL_SHA ECDH-ECDSA-NULL-SHA)], '0x0300C002'=> [qw(ECDH_ECDSA_WITH_RC4_128_SHA ECDH-ECDSA-RC4-SHA)], '0x0300C00E'=> [qw(ECDH_RSA_WITH_AES_128_CBC_SHA ECDH-RSA-AES128-SHA)], '0x0300C031'=> [qw(ECDH_RSA_WITH_AES_128_GCM_SHA256 ECDH-RSA-AES128-GCM-SHA256)], '0x0300C029'=> [qw(ECDH_RSA_WITH_AES_128_SHA256 ECDH-RSA-AES128-SHA256)], '0x0300C00F'=> [qw(ECDH_RSA_WITH_AES_256_CBC_SHA ECDH-RSA-AES256-SHA)], '0x0300C032'=> [qw(ECDH_RSA_WITH_AES_256_GCM_SHA384 ECDH-RSA-AES256-GCM-SHA384)], '0x0300C02A'=> [qw(ECDH_RSA_WITH_AES_256_SHA384 ECDH-RSA-AES256-SHA384)], '0x0300C00D'=> [qw(ECDH_RSA_WITH_DES_192_CBC3_SHA ECDH-RSA-DES-CBC3-SHA)], '0x0300C00B'=> [qw(ECDH_RSA_WITH_NULL_SHA ECDH-RSA-NULL-SHA)], '0x0300C00C'=> [qw(ECDH_RSA_WITH_RC4_128_SHA ECDH-RSA-RC4-SHA)], '0x0300C018'=> [qw(ECDH_anon_WITH_AES_128_CBC_SHA AECDH-AES128-SHA)], '0x0300C019'=> [qw(ECDH_anon_WITH_AES_256_CBC_SHA AECDH-AES256-SHA)], '0x0300C017'=> [qw(ECDH_anon_WITH_DES_192_CBC3_SHA AECDH-DES-CBC3-SHA)], '0x0300C015'=> [qw(ECDH_anon_WITH_NULL_SHA AECDH-NULL-SHA)], '0x0300C016'=> [qw(ECDH_anon_WITH_RC4_128_SHA AECDH-RC4-SHA)], '0x0300008B'=> [qw(PSK_WITH_3DES_EDE_CBC_SHA PSK-3DES-EDE-CBC-SHA)], '0x0300008C'=> [qw(PSK_WITH_AES_128_CBC_SHA PSK-AES128-CBC-SHA)], '0x0300008D'=> [qw(PSK_WITH_AES_256_CBC_SHA PSK-AES256-CBC-SHA)], '0x0300008A'=> [qw(PSK_WITH_RC4_128_SHA PSK-RC4-SHA)], '0x03000062'=> [qw(RSA_EXPORT1024_WITH_DES_CBC_SHA EXP1024-DES-CBC-SHA)], '0x03000061'=> [qw(RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 EXP1024-RC2-CBC-MD5)], '0x03000060'=> [qw(RSA_EXPORT1024_WITH_RC4_56_MD5 EXP1024-RC4-MD5)], '0x03000064'=> [qw(RSA_EXPORT1024_WITH_RC4_56_SHA EXP1024-RC4-SHA)], '0x0300009C'=> [qw(RSA_WITH_AES_128_GCM_SHA256 AES128-GCM-SHA256)], '0x0300002F'=> [qw(RSA_WITH_AES_128_SHA AES128-SHA)], '0x0300003C'=> [qw(RSA_WITH_AES_128_SHA256 AES128-SHA256)], '0x0300009D'=> [qw(RSA_WITH_AES_256_GCM_SHA384 AES256-GCM-SHA384)], '0x03000035'=> [qw(RSA_WITH_AES_256_SHA AES256-SHA)], '0x0300003D'=> [qw(RSA_WITH_AES_256_SHA256 AES256-SHA256)], '0x03000041'=> [qw(RSA_WITH_CAMELLIA_128_CBC_SHA CAMELLIA128-SHA)], '0x03000084'=> [qw(RSA_WITH_CAMELLIA_256_CBC_SHA CAMELLIA256-SHA)], '0x0300003B'=> [qw(RSA_WITH_NULL_SHA256 NULL-SHA256)], '0x03000096'=> [qw(RSA_WITH_SEED_SHA SEED-SHA)], '0x0300C01C'=> [qw(SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA SRP-DSS-3DES-EDE-CBC-SHA)], '0x0300C01F'=> [qw(SRP_SHA_DSS_WITH_AES_128_CBC_SHA SRP-DSS-AES-128-CBC-SHA)], '0x0300C022'=> [qw(SRP_SHA_DSS_WITH_AES_256_CBC_SHA SRP-DSS-AES-256-CBC-SHA)], '0x0300C01B'=> [qw(SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA SRP-RSA-3DES-EDE-CBC-SHA)], '0x0300C01E'=> [qw(SRP_SHA_RSA_WITH_AES_128_CBC_SHA SRP-RSA-AES-128-CBC-SHA)], '0x0300C021'=> [qw(SRP_SHA_RSA_WITH_AES_256_CBC_SHA SRP-RSA-AES-256-CBC-SHA)], '0x0300C01A'=> [qw(SRP_SHA_WITH_3DES_EDE_CBC_SHA SRP-3DES-EDE-CBC-SHA)], '0x0300C01D'=> [qw(SRP_SHA_WITH_AES_128_CBC_SHA SRP-AES-128-CBC-SHA)], '0x0300C020'=> [qw(SRP_SHA_WITH_AES_256_CBC_SHA SRP-AES-256-CBC-SHA)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: http://tools.ietf.org/html/draft-chudov-cryptopro-cptls-04 #!# added manually 20140209: GOST 28147-89 Cipher Suites for Transport Layer Security (TLS) #!# draft-chudov-cryptopro-cptls-04 (2008-12-08) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x03000080'=> [qw(GOSTR341094_WITH_28147_CNT_IMIT GOSTR341094-28147-CNT-IMIT)], '0x03000081'=> [qw(GOSTR341001_WITH_28147_CNT_IMIT GOSTR341001-28147-CNT-IMIT)], '0x03000082'=> [qw(GOSTR341094_WITH_NULL_GOSTR3411 GOSTR341094-NULL-GOSTR3411)], '0x03000083'=> [qw(GOSTR341001_WITH_NULL_GOSTR3411 GOSTR341001-NULL-GOSTR3411)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-01 #!# added manually 20140209: ChaCha Stream Cipher for Transport Layer Security #!# 20160330: renamed Ciphers 0x0300CC12 .. 0x0300CC19 as hex-numbers changed #!# in version 05 of the draft: __OLD, __OLD #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300CC12'=> [qw(RSA_WITH_CHACHA20_POLY1305__OLD RSA-CHACHA20-POLY1305__OLD)], '0x0300CC13'=> [qw(ECDHE_RSA_WITH_CHACHA20_POLY1305__OLD ECDHE-RSA-CHACHA20-POLY1305__OLD)], '0x0300CC14'=> [qw(ECDHE_ECDSA_WITH_CHACHA20_POLY1305__OLD ECDHE-ECDSA-CHACHA20-POLY1305__OLD)], '0x0300CC15'=> [qw(DHE_RSA_WITH_CHACHA20_POLY1305__OLD DHE-RSA-CHACHA20-POLY1305__OLD)], '0x0300CC16'=> [qw(DHE_PSK_WITH_CHACHA20_POLY1305__OLD DHE-PSK-CHACHA20-POLY1305__OLD)], '0x0300CC17'=> [qw(PSK_WITH_CHACHA20_POLY1305__OLD PSK-CHACHA20-POLY1305__OLD)], '0x0300CC18'=> [qw(ECDHE_PSK_WITH_CHACHA20_POLY1305__OLD ECDHE-PSK-CHACHA20-POLY1305__OLD)], '0x0300CC19'=> [qw(RSA_PSK_WITH_CHACHA20_POLY1305__OLD RSA-PSK-CHACHA20-POLY1305__OLD)], '0x0300CC20'=> [qw(RSA_WITH_CHACHA20_SHA RSA-CHACHA20-SHA)], '0x0300CC21'=> [qw(ECDHE_RSA_WITH_CHACHA20_SHA ECDHE-RSA-CHACHA20-SHA)], '0x0300CC22'=> [qw(ECDHE_ECDSA_WITH_CHACHA20_SHA ECDHE-ECDSA-CHACHA20-SHA)], '0x0300CC23'=> [qw(DHE_RSA_WITH_CHACHA20_SHA DHE-RSA-CHACHA20-SHA)], '0x0300CC24'=> [qw(DHE_PSK_WITH_CHACHA20_SHA DHE-PSK-CHACHA20-SHA)], '0x0300CC25'=> [qw(PSK_WITH_CHACHA20_SHA PSK-CHACHA20-SHA)], '0x0300CC26'=> [qw(ECDHE_PSK_WITH_CHACHA20_SHA ECDHE-PSK-CHACHA20-SHA)], '0x0300CC27'=> [qw(RSA_PSK_WITH_CHACHA20_SHA RSA-PSK-CHACHA20-SHA)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-05 #!# added manually 20160330: NEW ChaCha Stream Cipher for Transport Layer Security #!# ATTENTION: the same Ciphers existed before using 0x0300CC12 .. 0x0300CC19 #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300CCA0'=> [qw(RSA_WITH_CHACHA20_POLY1305 RSA-CHACHA20-POLY1305)], '0x0300CCA1'=> [qw(ECDHE_RSA_WITH_CHACHA20_POLY1305 ECDHE-RSA-CHACHA20-POLY1305)], '0x0300CCA2'=> [qw(ECDHE_ECDSA_WITH_CHACHA20_POLY1305 ECDHE-ECDSA-CHACHA20-POLY1305)], '0x0300CCA3'=> [qw(DHE_RSA_WITH_CHACHA20_POLY1305 DHE-RSA-CHACHA20-POLY1305)], '0x0300CCA4'=> [qw(DHE_PSK_WITH_CHACHA20_POLY1305 DHE-PSK-CHACHA20-POLY1305)], '0x0300CCA5'=> [qw(PSK_WITH_CHACHA20_POLY1305 PSK-CHACHA20-POLY1305)], '0x0300CCA6'=> [qw(ECDHE_PSK_WITH_CHACHA20_POLY1305 ECDHE-PSK-CHACHA20-POLY1305)], '0x0300CCA7'=> [qw(RSA_PSK_WITH_CHACHA20_POLY1305 RSA-PSK-CHACHA20-POLY1305)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04 #!# added manually 20160331: #!# ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ # CipherSuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xTBD, 0xTBD} {0xCC, 0xA8} # CipherSuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = {0xTBD, 0xTBD} {0xCC, 0xA9} # CipherSuite TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xTBD, 0xTBD} {0xCC, 0xAA} # CipherSuite TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xTBD, 0xTBD} {0xCC, 0xAB} # CipherSuite TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xTBD, 0xTBD} {0xCC, 0xAC} # CipherSuite TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xTBD, 0xTBD} {0xCC, 0xAD} # CipherSuite TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = {0xTBD, 0xTBD} {0xCC, 0xAE} '0x0300CCA8'=> [qw(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 ECDHE-RSA-CHACHA20-POLY1305-SHA256)], '0x0300CCA9'=> [qw(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 ECDHE-ECDSA-CHACHA20-POLY1305-SHA256)], '0x0300CCAA'=> [qw(DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 DHE-RSA-CHACHA20-POLY1305-SHA256)], '0x0300CCAB'=> [qw(PSK_WITH_CHACHA20_POLY1305_SHA256 PSK-CHACHA20-POLY1305-SHA256)], '0x0300CCAC'=> [qw(ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 ECDHE-PSK-CHACHA20-POLY1305-SHA256)], '0x0300CCAD'=> [qw(DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 DHE-PSK-CHACHA20-POLY1305-SHA256)], '0x0300CCAE'=> [qw(RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 RSA-PSK-CHACHA20-POLY1305-SHA256)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: http://tools.ietf.org/html/rfc5932 #!# added manually 20140630: Camellia Cipher Suites for TLS #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ # CipherSuite TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = { 0x00,0xBA }; # CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = { 0x00,0xBB }; # CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = { 0x00,0xBC }; # CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = { 0x00,0xBD }; # CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = { 0x00,0xBE }; # CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = { 0x00,0xBF }; '0x030000BA'=> [qw(RSA_WITH_CAMELLIA_128_CBC_SHA256 RSA-CAMELLIA128-SHA256)], '0x030000BB'=> [qw(DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 DH-DSS-CAMELLIA128-SHA256)], '0x030000BC'=> [qw(DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 DH-RSA-CAMELLIA128-SHA256)], '0x030000BD'=> [qw(DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 DHE-DSS-CAMELLIA128-SHA256)], '0x030000BE'=> [qw(DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 DHE-RSA-CAMELLIA128-SHA256)], '0x030000BF'=> [qw(ADH_WITH_CAMELLIA_128_CBC_SHA256 ADH-CAMELLIA128-SHA256)], # CipherSuite TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = { 0x00,0xC0 }; # CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = { 0x00,0xC1 }; # CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = { 0x00,0xC2 }; # CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = { 0x00,0xC3 }; # CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = { 0x00,0xC4 }; # CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = { 0x00,0xC5 }; '0x030000C0'=> [qw(RSA_WITH_CAMELLIA_256_CBC_SHA256 RSA-CAMELLIA256-SHA256)], '0x030000C1'=> [qw(DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 DH-DSS-CAMELLIA256-SHA256)], '0x030000C2'=> [qw(DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 DH-RSA-CAMELLIA256-SHA256)], '0x030000C3'=> [qw(DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 DHE-DSS-CAMELLIA256-SHA256)], '0x030000C4'=> [qw(DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 DHE-RSA-CAMELLIA256-SHA256)], '0x030000C5'=> [qw(ADH_WITH_CAMELLIA_256_CBC_SHA256 ADH-CAMELLIA256-SHA256)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: http://tools.ietf.org/html/rfcrfc6367 #!# added manually 20140701: Camellia Cipher Suites for TLS #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ # CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = {0xC0,0x72}; # CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = {0xC0,0x73}; # CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = {0xC0,0x74}; # CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = {0xC0,0x75}; # CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = {0xC0,0x76}; # CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = {0xC0,0x77}; # CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = {0xC0,0x78}; # CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = {0xC0,0x79}; '0x0300C072'=> [qw(ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 ECDHE-ECDSA-CAMELLIA128-SHA256)], '0x0300C073'=> [qw(ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 ECDHE-ECDSA-CAMELLIA256-SHA384)], '0x0300C074'=> [qw(ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 ECDH-ECDSA-CAMELLIA128-SHA256)], '0x0300C075'=> [qw(ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 ECDH-ECDSA-CAMELLIA256-SHA384)], '0x0300C076'=> [qw(ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 ECDHE-RSA-CAMELLIA128-SHA256)], '0x0300C077'=> [qw(ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 ECDHE-RSA-CAMELLIA256-SHA384)], '0x0300C078'=> [qw(ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 ECDH-RSA-CAMELLIA128-SHA256)], '0x0300C079'=> [qw(ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 ECDH-RSA-CAMELLIA256-SHA384)], # CipherSuite TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x7A}; # CipherSuite TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x7B}; # CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x7C}; # CipherSuite TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x7D}; # CipherSuite TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x7E}; # CipherSuite TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x7F}; '0x0300C07A'=> [qw(RSA_WITH_CAMELLIA_128_GCM_SHA256 RSA-CAMELLIA128-GCM-SHA256)], '0x0300C07B'=> [qw(RSA_WITH_CAMELLIA_256_GCM_SHA384 RSA-CAMELLIA256-GCM-SHA384)], '0x0300C07C'=> [qw(DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 DHE-RSA-CAMELLIA128-GCM-SHA256)], '0x0300C07D'=> [qw(DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 DHE-RSA-CAMELLIA256-GCM-SHA384)], '0x0300C07E'=> [qw(DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 DH-RSA-CAMELLIA128-GCM-SHA256)], '0x0300C07F'=> [qw(DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 DH-RSA-CAMELLIA256-GCM-SHA384)], # CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x80}; # CipherSuite TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x81}; # CipherSuite TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x82}; # CipherSuite TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x83}; # CipherSuite TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x84}; # CipherSuite TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x85}; '0x0300C080'=> [qw(DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 DHE-DSS-CAMELLIA128-GCM-SHA256)], '0x0300C081'=> [qw(DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 DHE-DSS-CAMELLIA256-GCM-SHA384)], '0x0300C082'=> [qw(DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 DH-DSS-CAMELLIA128-GCM-SHA256)], '0x0300C083'=> [qw(DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 DH-DSS-CAMELLIA256-GCM-SHA384)], '0x0300C084'=> [qw(ADH_DSS_WITH_CAMELLIA_128_GCM_SHA256 ADH-DSS-CAMELLIA128-GCM-SHA256)], '0x0300C085'=> [qw(ADH_DSS_WITH_CAMELLIA_256_GCM_SHA384 ADH-DSS-CAMELLIA256-GCM-SHA384)], # CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x86}; # CipherSuite TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x87}; # CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x88}; # CipherSuite TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x89}; # CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x8A}; # CipherSuite TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x8B}; # CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x8C}; # CipherSuite TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x8D}; '0x0300C086'=> [qw(ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 ECDHE-ECDSA-CAMELLIA128-GCM-SHA256)], '0x0300C087'=> [qw(ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 ECDHE-ECDSA-CAMELLIA256-GCM-SHA384)], '0x0300C088'=> [qw(ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 ECDH-ECDSA-CAMELLIA128-GCM-SHA256)], '0x0300C089'=> [qw(ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 ECDH-ECDSA-CAMELLIA256-GCM-SHA384)], '0x0300C08A'=> [qw(ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 ECDHE-RSA-CAMELLIA128-GCM-SHA256)], '0x0300C08B'=> [qw(ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 ECDHE-RSA-CAMELLIA256-GCM-SHA384)], '0x0300C08C'=> [qw(ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 ECDH-RSA-CAMELLIA128-GCM-SHA256)], '0x0300C08D'=> [qw(ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 ECDH-RSA-CAMELLIA256-GCM-SHA384)], # CipherSuite TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x8E}; ##BUG in RFC6376## # CipherSuite TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x8F}; # CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x90}; # CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x91}; # CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = {0xC0,0x92}; # CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = {0xC0,0x93}; '0x0300C08E'=> [qw(PSK_WITH_CAMELLIA_128_GCM_SHA256 PSK-CAMELLIA128-GCM-SHA256)], '0x0300C08F'=> [qw(PSK_WITH_CAMELLIA_256_GCM_SHA384 PSK-CAMELLIA256-GCM-SHA384)], '0x0300C090'=> [qw(DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 DHE-PSK-CAMELLIA128-GCM-SHA256)], '0x0300C091'=> [qw(DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 DHE-PSK-CAMELLIA256-GCM-SHA384)], '0x0300C092'=> [qw(RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 RSA-PSK-CAMELLIA128-GCM-SHA256)], '0x0300C093'=> [qw(RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 RSA-PSK-CAMELLIA256-GCM-SHA384)], # CipherSuite TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = {0xC0,0x94}; # CipherSuite TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = {0xC0,0x95}; # CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = {0xC0,0x96}; # CipherSuite TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = {0xC0,0x97}; # CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = {0xC0,0x98}; # CipherSuite TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = {0xC0,0x99}; '0x0300C094'=> [qw(PSK_WITH_CAMELLIA_128_CBC_SHA256 PSK-CAMELLIA128-SHA256)], '0x0300C095'=> [qw(PSK_WITH_CAMELLIA_256_CBC_SHA384 PSK-CAMELLIA256-SHA384)], '0x0300C096'=> [qw(DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 DHE-PSK-CAMELLIA128-SHA256)], '0x0300C097'=> [qw(DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 DHE-PSK-CAMELLIA256-SHA384)], '0x0300C098'=> [qw(RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 RSA-PSK-CAMELLIA128-SHA256)], '0x0300C099'=> [qw(RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 RSA-PSK-CAMELLIA256-SHA384)], # CipherSuite TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = {0xC0,0x9A}; # CipherSuite TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = {0xC0,0x9B}; '0x0300C09A'=> [qw(ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 ECDHE-PSK-CAMELLIA128-SHA256)], '0x0300C09B'=> [qw(ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 ECDHE-PSK-CAMELLIA256-SHA384)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: http://tools.ietf.org/html/rfc6655 #!# added manually 20140705: AES-CCM cipher suites for TLS #!# precompiled using #!# cat rfc6655.txt | grep 'CipherSuite TLS_' | sed -e "s#.*CipherSuite TLS_\(.*\)\s*\=\s*{0x\(.*\),0x\(.*\)[})]# \'0x0300\2\3\'=> [qw(\1 \1)]\,#" #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300C09C'=> [qw(RSA_WITH_AES_128_CCM RSA-AES128-CCM)], '0x0300C09D'=> [qw(RSA_WITH_AES_256_CCM RSA-AES256-CCM)], '0x0300C09E'=> [qw(DHE_RSA_WITH_AES_128_CCM DHE-RSA-AES128_CCM)], '0x0300C09F'=> [qw(DHE_RSA_WITH_AES_256_CCM DHE-RSA-AES256_CCM)], '0x0300C0A0'=> [qw(RSA_WITH_AES_128_CCM_8 RSA-AES128-CCM8)], '0x0300C0A1'=> [qw(RSA_WITH_AES_256_CCM_8 RSA-AES256-CCM8)], '0x0300C0A2'=> [qw(DHE_RSA_WITH_AES_128_CCM_8 DHE-RSA-AES128_CCM8)], '0x0300C0A3'=> [qw(DHE_RSA_WITH_AES_256_CCM_8 DHE-RSA-AES256_CCM8)], '0x0300C0A4'=> [qw(PSK_WITH_AES_128_CCM PSK-WITH-AES128_CCM)], '0x0300C0A5'=> [qw(PSK_WITH_AES_256_CCM PSK-WITH-AES256_CCM)], '0x0300C0A6'=> [qw(DHE_PSK_WITH_AES_128_CCM DHE-PSK-AES128_CCM)], '0x0300C0A7'=> [qw(DHE_PSK_WITH_AES_256_CCM DHE-PSK-AES256_CCM)], '0x0300C0A8'=> [qw(PSK_WITH_AES_128_CCM_8 PSK-AES128-CCM8)], '0x0300C0A9'=> [qw(PSK_WITH_AES_256_CCM_8 PSK-AES256-CCM8)], '0x0300C0AA'=> [qw(PSK_DHE_WITH_AES_128_CCM_8 PSK-DHE-AES128-CCM8)], '0x0300C0AB'=> [qw(PSK_DHE_WITH_AES_256_CCM_8 PSK-DHE-AES256-CCM8)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: http://www-archive.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html #!# added manually 20141011: #!# Netscape: FIPS SSL CipherSuite Numbers (OBSOLETE) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300FEE0'=> [qw(RSA_FIPS_WITH_3DES_EDE_CBC_SHA RSA-FIPS-3DES-EDE-SHA)], '0x0300FEE1'=> [qw(RSA_FIPS_WITH_DES_CBC_SHA RSA-FIPS-DES-CBC-SHA)], '0x0300FEFE'=> [qw(RSA_FIPS_WITH_DES_CBC_SHA RSA-FIPS-DES-CBC-SHA)], '0x0300FEFF'=> [qw(RSA_FIPS_WITH_3DES_EDE_CBC_SHA RSA-FIPS-3DES-EDE-SHA)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: some PSK and CCM ciphers (from o-saft.pl, nane1 <-> name2) #!# added manually 20141012 #!# #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300002C' => [qw(PSK_WITH_NULL_SHA PSK-SHA)], '0x0300002D' => [qw(DHE_PSK_WITH_NULL_SHA DHE-PSK-SHA)], '0x0300002E' => [qw(RSA_PSK_WITH_NULL_SHA RSA-PSK-SHA)], '0x0300008E' => [qw(DHE_PSK_WITH_RC4_128_SHA DHE-PSK-RC4-SHA)], '0x0300008F' => [qw(DHE_PSK_WITH_3DES_EDE_CBC_SHA DHE-PSK-3DES-SHA)], '0x03000090' => [qw(DHE_PSK_WITH_AES_128_CBC_SHA DHE-PSK-AES128-SHA)], '0x03000091' => [qw(DHE_PSK_WITH_AES_256_CBC_SHA DHE-PSK-AES256-SHA)], '0x03000092' => [qw(RSA_PSK_WITH_RC4_128_SHA RSA-PSK-RC4-SHA)], '0x03000093' => [qw(RSA_PSK_WITH_3DES_EDE_CBC_SHA RSA-PSK-3DES-SHA)], '0x03000094' => [qw(RSA_PSK_WITH_AES_128_CBC_SHA RSA-PSK-AES128-SHA)], '0x03000095' => [qw(RSA_PSK_WITH_AES_256_CBC_SHA RSA-PSK-AES256-SHA)], '0x030000AA' => [qw(DHE_PSK_WITH_AES_128_GCM_SHA256 DHE-PSK-AES128-GCM-SHA256)], '0x030000AB' => [qw(DHE_PSK_WITH_AES_256_GCM_SHA384 DHE-PSK-AES256-GCM-SHA384)], '0x030000AC' => [qw(RSA_PSK_WITH_AES_128_GCM_SHA256 RSA-PSK-AES128-GCM-SHA256)], '0x030000AD' => [qw(RSA_PSK_WITH_AES_256_GCM_SHA384 RSA-PSK-AES256-GCM-SHA384)], '0x030000AE' => [qw(PSK_WITH_AES_128_CBC_SHA256 PSK-AES128-SHA256)], '0x030000AF' => [qw(PSK_WITH_AES_256_CBC_SHA384 PSK-AES256-SHA384)], '0x030000B0' => [qw(PSK_WITH_NULL_SHA256 PSK-SHA256)], '0x030000B1' => [qw(PSK_WITH_NULL_SHA384 PSK-SHA384)], '0x030000B2' => [qw(DHE_PSK_WITH_AES_256_CBC_SHA256 DHE-PSK-AES128-SHA256)], '0x030000B3' => [qw(DHE_PSK_WITH_AES_256_CBC_SHA384 DHE-PSK-AES256-SHA384)], '0x030000B4' => [qw(DHE_PSK_WITH_NULL_SHA256 DHE-PSK-SHA256)], '0x030000B5' => [qw(DHE_PSK_WITH_NULL_SHA384 DHE-PSK-SHA384)], '0x030000B6' => [qw(RSA_PSK_WITH_AES_256_CBC_SHA256 RSA-PSK-AES128-SHA256)], '0x030000B7' => [qw(RSA_PSK_WITH_AES_256_CBC_SHA384 RSA-PSK-AES256-SHA384)], '0x030000B8' => [qw(RSA_PSK_WITH_NULL_SHA256 RSA-PSK-SHA256)], '0x030000B9' => [qw(RSA_PSK_WITH_NULL_SHA384 RSA-PSK-SHA384)], '0x0300C0AC' => [qw(ECDHE_ECDSA_WITH_AES_128_CCM ECDHE-RSA-AES128-CCM)], '0x0300C0AD' => [qw(ECDHE_ECDSA_WITH_AES_256_CCM ECDHE-RSA-AES256-CCM)], '0x0300C0AE' => [qw(ECDHE_ECDSA_WITH_AES_128_CCM_8 ECDHE-RSA-AES128-CCM-8)], '0x0300C0AF' => [qw(ECDHE_ECDSA_WITH_AES_256_CCM_8 ECDHE-RSA-AES256-CCM-8)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: some PSK ciphers #!# added manually 20141012 #!# #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ # RFC 5487: http://tools.ietf.org/html/rfc5487 # CipherSuite TLS_PSK_WITH_AES_128_GCM_SHA256 = {0x00,0xA8}; # CipherSuite TLS_PSK_WITH_AES_256_GCM_SHA384 = {0x00,0xA9}; '0x030000A8' => [qw(PSK_WITH_AES_128_GCM_SHA256 PSK-AES128-GCM-SHA256)], '0x030000A9' => [qw(PSK_WITH_AES_256_GCM_SHA384 PSK-AES256-GCM-SHA384)], # RFC 5489: http://tools.ietf.org/html/rfc5489 # CipherSuite TLS_ECDHE_PSK_WITH_RC4_128_SHA = {0xC0,0x33}; # CipherSuite TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = {0xC0,0x34}; # CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = {0xC0,0x35}; # CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = {0xC0,0x36}; # CipherSuite TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = {0xC0,0x37}; # CipherSuite TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = {0xC0,0x38}; # CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA = {0xC0,0x39}; # CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA256 = {0xC0,0x3A}; # CipherSuite TLS_ECDHE_PSK_WITH_NULL_SHA384 = {0xC0,0x3B}; '0x0300C033' => [qw(ECDHE_PSK_WITH_RC4_128_SHA ECDHE-PSK-RC4-SHA)], '0x0300C034' => [qw(ECDHE_PSK_WITH_3DES_EDE_CBC_SHA ECDHE-PSK-3DES-SHA)], '0x0300C035' => [qw(ECDHE_PSK_WITH_AES_128_CBC_SHA ECDHE-PSK-AES128-SHA)], '0x0300C036' => [qw(ECDHE_PSK_WITH_AES_256_CBC_SHA ECDHE-PSK-AES256-SHA)], '0x0300C037' => [qw(ECDHE_PSK_WITH_AES_128_CBC_SHA256 ECDHE-PSK-AES128-SHA256)], '0x0300C038' => [qw(ECDHE_PSK_WITH_AES_256_CBC_SHA384 ECDHE-PSK-AES256-SHA384)], '0x0300C039' => [qw(ECDHE_PSK_WITH_NULL_SHA ECDHE-PSK-SHA)], '0x0300C03A' => [qw(ECDHE_PSK_WITH_NULL_SHA256 ECDHE-PSK-SHA256)], '0x0300C03B' => [qw(ECDHE_PSK_WITH_NULL_SHA384 ECDHE-PSK-SHA384)], # RFC 6209 (To be done) # CipherSuite TLS_RSA_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x3C }; # CipherSuite TLS_RSA_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x3D }; # CipherSuite TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x3E }; # CipherSuite TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x3F }; # CipherSuite TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x40 }; # CipherSuite TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x41 }; # CipherSuite TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x42 }; # CipherSuite TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x43 }; # CipherSuite TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x44 }; '0x0300C03C'=>[qw(RSA_WITH_ARIA_128_CBC_SHA256 RSA-ARIA128-SHA256)], '0x0300C03D'=>[qw(RSA_WITH_ARIA_256_CBC_SHA384 RSA-ARIA256-SHA384)], '0x0300C03E'=>[qw(DH_DSS_WITH_ARIA_128_CBC_SHA256 DH-DSS-ARIA128-SHA256)], '0x0300C03F'=>[qw(DH_DSS_WITH_ARIA_256_CBC_SHA384 DH-DSS-ARIA256-SHA384)], '0x0300C040'=>[qw(DH_RSA_WITH_ARIA_128_CBC_SHA256 DH-RSA-ARIA128-SHA256)], '0x0300C041'=>[qw(DH_RSA_WITH_ARIA_256_CBC_SHA384 DH-RSA-ARIA256-SHA384)], '0x0300C042'=>[qw(DHE_DSS_WITH_ARIA_128_CBC_SHA256 DHE-DSS-ARIA128-SHA256)], '0x0300C043'=>[qw(DHE_DSS_WITH_ARIA_256_CBC_SHA384 DHE-DSS-ARIA256-SHA384)], '0x0300C044'=>[qw(DHE_RSA_WITH_ARIA_128_CBC_SHA256 DHE-RSA-ARIA128-SHA256)], # CipherSuite TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x45 }; # CipherSuite TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x46 }; # CipherSuite TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x47 }; '0x0300C045'=>[qw(DHE_RSA_WITH_ARIA_256_CBC_SHA384 DHE-RSA-ARIA256-SHA384)], '0x0300C046'=>[qw(DH_anon_WITH_ARIA_128_CBC_SHA256 ADH-ARIA128-SHA256)], '0x0300C047'=>[qw(DH_anon_WITH_ARIA_256_CBC_SHA384 ADH-ARIA256-SHA384)], # CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x48 }; # CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x49 }; # CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x4A }; # CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x4B }; # CipherSuite TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x4C }; # CipherSuite TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x4D }; # CipherSuite TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x4E }; # CipherSuite TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x4F }; '0x0300C048'=>[qw(ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 ECDHE-ECDSA-ARIA128-SHA256)], '0x0300C049'=>[qw(ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 ECDHE-ECDSA-ARIA256-SHA384)], '0x0300C04A'=>[qw(ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 ECDH-ECDSA-ARIA128-SHA256)], '0x0300C04B'=>[qw(ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 ECDH-ECDSA-ARIA256-SHA384)], '0x0300C04C'=>[qw(ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 ECDHE-RSA-ARIA128-SHA256)], '0x0300C04D'=>[qw(ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 ECDHE-RSA-ARIA256-SHA384)], '0x0300C04E'=>[qw(ECDH_RSA_WITH_ARIA_128_CBC_SHA256 ECDH-RSA-ARIA128-SHA256)], '0x0300C04F'=>[qw(ECDH_RSA_WITH_ARIA_256_CBC_SHA384 ECDH-RSA-ARIA256-SHA384)], # CipherSuite TLS_RSA_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x50 }; # CipherSuite TLS_RSA_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x51 }; # CipherSuite TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x52 }; # CipherSuite TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x53 }; # CipherSuite TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x54 }; # CipherSuite TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x55 }; # CipherSuite TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x56 }; # CipherSuite TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x57 }; # CipherSuite TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x58 }; # CipherSuite TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x59 }; # CipherSuite TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x5A }; # CipherSuite TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x5B }; '0x0300C050'=>[qw(RSA_WITH_ARIA_128_GCM_SHA256 RSA-ARIA128-GCM-SHA256)], '0x0300C051'=>[qw(RSA_WITH_ARIA_256_GCM_SHA384 RSA-ARIA256-GCM-SHA384)], '0x0300C052'=>[qw(DHE_RSA_WITH_ARIA_128_GCM_SHA256 DHE-RSA-ARIA128-GCM-SHA256)], '0x0300C053'=>[qw(DHE_RSA_WITH_ARIA_256_GCM_SHA384 DHE-RSA-ARIA256-GCM-SHA384)], '0x0300C054'=>[qw(DH_RSA_WITH_ARIA_128_GCM_SHA256 DH-RSA-ARIA128-GCM-SHA256)], '0x0300C055'=>[qw(DH_RSA_WITH_ARIA_256_GCM_SHA384 DH-RSA-ARIA256-GCM-SHA384)], '0x0300C056'=>[qw(DHE_DSS_WITH_ARIA_128_GCM_SHA256 DHE-DSS-ARIA128-GCM-SHA256)], '0x0300C057'=>[qw(DHE_DSS_WITH_ARIA_256_GCM_SHA384 DHE-DSS-ARIA256-GCM-SHA384)], '0x0300C058'=>[qw(DH_DSS_WITH_ARIA_128_GCM_SHA256 DH-DSS-ARIA128-GCM-SHA256)], '0x0300C059'=>[qw(DH_DSS_WITH_ARIA_256_GCM_SHA384 DH-DSS-ARIA256-GCM-SHA384)], '0x0300C05A'=>[qw(DH_anon_WITH_ARIA_128_GCM_SHA256 ADH-ARIA128-GCM-SHA256)], '0x0300C05B'=>[qw(DH_anon_WITH_ARIA_256_GCM_SHA384 ADH-ARIA256-GCM-SHA384)], # CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x5C }; # CipherSuite TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x5D }; # CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x5E }; # CipherSuite TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x5F }; # CipherSuite TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x60 }; # CipherSuite TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x61 }; # CipherSuite TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x62 }; # CipherSuite TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x63 }; '0x0300C05C'=>[qw(ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 ECDHE-ECDSA-ARIA128-GCM-SHA256)], '0x0300C05D'=>[qw(ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 ECDHE-ECDSA-ARIA256-GCM-SHA384)], '0x0300C05E'=>[qw(ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 ECDH-ECDSA-ARIA128-GCM-SHA256)], '0x0300C05F'=>[qw(ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 ECDH-ECDSA-ARIA256-GCM-SHA384)], '0x0300C060'=>[qw(ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 ECDHE-RSA-ARIA128-GCM-SHA256)], '0x0300C061'=>[qw(ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 ECDHE-RSA-ARIA256-GCM-SHA384)], '0x0300C062'=>[qw(ECDH_RSA_WITH_ARIA_128_GCM_SHA256 ECDH-RSA-ARIA128-GCM-SHA256)], '0x0300C063'=>[qw(ECDH_RSA_WITH_ARIA_256_GCM_SHA384 ECDH-RSA-ARIA256-GCM-SHA384)], # CipherSuite TLS_PSK_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x64 }; # CipherSuite TLS_PSK_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x65 }; # CipherSuite TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x66 }; # CipherSuite TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x67 }; # CipherSuite TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x68 }; # CipherSuite TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x69 }; # CipherSuite TLS_PSK_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x6A }; # CipherSuite TLS_PSK_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x6B }; # CipherSuite TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x6C }; # CipherSuite TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x6D }; # CipherSuite TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 = { 0xC0,0x6E }; # CipherSuite TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 = { 0xC0,0x6F }; # CipherSuite TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 = { 0xC0,0x70 }; # CipherSuite TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 = { 0xC0,0x71 }; '0x0300C064'=>[qw(PSK_WITH_ARIA_128_CBC_SHA256 PSK-ARIA128-SHA-56)], '0x0300C065'=>[qw(PSK_WITH_ARIA_256_CBC_SHA384 PSK-ARIA256-SHA384)], '0x0300C066'=>[qw(DHE_PSK_WITH_ARIA_128_CBC_SHA256 DHE-PSK-ARIA128-SHA256)], '0x0300C067'=>[qw(DHE_PSK_WITH_ARIA_256_CBC_SHA384 DHE-PSK-ARIA256-SHA384)], '0x0300C068'=>[qw(RSA_PSK_WITH_ARIA_128_CBC_SHA256 RSA-PSK-ARIA128-SHA256)], '0x0300C069'=>[qw(RSA_PSK_WITH_ARIA_256_CBC_SHA384 RSA-PSK-ARIA256-SHA384)], '0x0300C06A'=>[qw(PSK_WITH_ARIA_128_GCM_SHA256 PSK-ARIA128-GCM-SHA256)], '0x0300C06B'=>[qw(PSK_WITH_ARIA_256_GCM_SHA384 PSK-ARIA256-GCM-SHA384)], '0x0300C06C'=>[qw(DHE_PSK_WITH_ARIA_128_GCM_SHA256 DHE-PSK-ARIA128-GCM-SHA256)], '0x0300C06D'=>[qw(DHE_PSK_WITH_ARIA_256_GCM_SHA384 DHE-PSK-ARIA256-GCM-SHA384)], '0x0300C06E'=>[qw(RSA_PSK_WITH_ARIA_128_GCM_SHA256 RSA-PSK-ARIA128-GCM-SHA256)], '0x0300C06F'=>[qw(RSA_PSK_WITH_ARIA_256_GCM_SHA384 RSA-PSK-ARIA256-GCM-SHA384)], '0x0300C070'=>[qw(ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 ECDHE-PSK-ARIA128-SHA256)], '0x0300C071'=>[qw(ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 ECDHE-PSK-ARIA256-SHA384)], #!#----------------------------------------+-------------+--------------------+ ); # cipherHexHash ################################################################# # TLS_PROTOCOL_MESSAGE_CODES my $TLS_CLIENT_HELLO = 1; my $TLS_SERVER_HELLO = 2; my %SSL2_CIPHER_STRINGS = ( '0x020700C0'=> [qw(DES_192_EDE3_CBC_WITH_MD5 DES-CBC3-MD5 SSL_CK_DES_192_EDE3_CBC_WITH_MD5)], '0x020701C0'=> [qw(DES_192_EDE3_CBC_WITH_SHA DES-CBC3-SHA)], '0x02060040'=> [qw(DES_64_CBC_WITH_MD5 DES-CBC-MD5 SSL_CK_DES_64_CBC_WITH_MD5)], '0x02060140'=> [qw(DES_64_CBC_WITH_SHA DES-CBC-SHA)], '0x02FF0800'=> [qw(DES_64_CFB64_WITH_MD5_1 DES-CFB-M1)], '0x02050080'=> [qw(IDEA_128_CBC_WITH_MD5 IDEA-CBC-MD5 SSL_CK_IDEA_128_CBC_WITH_MD5)], '0x02FF0810'=> [qw(NULL NULL)], '0x02000000'=> [qw(NULL_WITH_MD5 NULL-MD5)], '0x02040080'=> [qw(RC2_128_CBC_EXPORT40_WITH_MD5 EXP-RC2-CBC-MD5 SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5)], '0x02030080'=> [qw(RC2_128_CBC_WITH_MD5 RC2-CBC-MD5 SSL_CK_RC2_128_CBC_WITH_MD5)], '0x02020080'=> [qw(RC4_128_EXPORT40_WITH_MD5 EXP-RC4-MD5 SSL_CK_RC4_128_EXPORT40_WITH_MD5)], '0x02010080'=> [qw(RC4_128_WITH_MD5 RC4-MD5 SSL_CK_RC4_128_WITH_MD5)], '0x02FFFFFF'=> [qw(SSL2_UNFFINED_CIPHER_0x02FFFFFF SSL2_UNFFINED_CIPHER_0x02FFFFFF SSL2_UNFFINED_CIPHER_0x02FFFFFF)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: SSL3 (invented) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300001B'=> [qw(ADH_WITH_DES_192_CBC_SHA ADH-DES-CBC3-SHA)], '0x03000019'=> [qw(ADH_WITH_DES_40_CBC_SHA EXP-ADH-DES-CBC-SHA)], '0x0300001A'=> [qw(ADH_WITH_DES_64_CBC_SHA ADH-DES-CBC-SHA)], '0x03000018'=> [qw(ADH_WITH_RC4_128_MD5 ADH-RC4-MD5)], '0x03000017'=> [qw(ADH_WITH_RC4_40_MD5 EXP-ADH-RC4-MD5)], '0x0300000D'=> [qw(DH_DSS_WITH_DES_192_CBC3_SHA DH-DSS-DES-CBC3-SHA)], '0x0300000B'=> [qw(DH_DSS_WITH_DES_40_CBC_SHA EXP-DH-DSS-DES-CBC-SHA)], '0x0300000C'=> [qw(DH_DSS_WITH_DES_64_CBC_SHA DH-DSS-DES-CBC-SHA)], '0x03000010'=> [qw(DH_RSA_WITH_DES_192_CBC3_SHA DH-RSA-DES-CBC3-SHA)], '0x0300000E'=> [qw(DH_RSA_WITH_DES_40_CBC_SHA EXP-DH-RSA-DES-CBC-SHA)], '0x0300000F'=> [qw(DH_RSA_WITH_DES_64_CBC_SHA DH-RSA-DES-CBC-SHA)], '0x03000013'=> [qw(EDH_DSS_WITH_DES_192_CBC3_SHA EDH-DSS-DES-CBC3-SHA)], '0x03000011'=> [qw(EDH_DSS_WITH_DES_40_CBC_SHA EXP-EDH-DSS-DES-CBC-SHA)], '0x03000012'=> [qw(EDH_DSS_WITH_DES_64_CBC_SHA EDH-DSS-DES-CBC-SHA)], '0x03000016'=> [qw(EDH_RSA_WITH_DES_192_CBC3_SHA EDH-RSA-DES-CBC3-SHA)], '0x03000014'=> [qw(EDH_RSA_WITH_DES_40_CBC_SHA EXP-EDH-RSA-DES-CBC-SHA)], '0x03000015'=> [qw(EDH_RSA_WITH_DES_64_CBC_SHA EDH-RSA-DES-CBC-SHA)], '0x0300001D'=> [qw(FZA_DMS_FZA_SHA FZA-FZA-CBC-SHA)], '0x0300001C'=> [qw(FZA_DMS_NULL_SHA FZA-NULL-SHA)], # '0x0300001E'=> [qw(FZA_DMS_RC4_SHA FZA-RC4-SHA)], #doppelt => prüfen '0x03000023'=> [qw(KRB5_WITH_DES_192_CBC3_MD5 KRB5-DES-CBC3-MD5)], '0x0300001F'=> [qw(KRB5_WITH_DES_192_CBC3_SHA KRB5-DES-CBC3-SHA)], '0x03000029'=> [qw(KRB5_WITH_DES_40_CBC_MD5 EXP-KRB5-DES-CBC-MD5)], '0x03000026'=> [qw(KRB5_WITH_DES_40_CBC_SHA EXP-KRB5-DES-CBC-SHA)], '0x03000022'=> [qw(KRB5_WITH_DES_64_CBC_MD5 KRB5-DES-CBC-MD5)], '0x0300001E'=> [qw(KRB5_WITH_DES_64_CBC_SHA KRB5-DES-CBC-SHA)], '0x03000025'=> [qw(KRB5_WITH_IDEA_128_CBC_MD5 KRB5-IDEA-CBC-MD5)], '0x03000021'=> [qw(KRB5_WITH_IDEA_128_CBC_SHA KRB5-IDEA-CBC-SHA)], '0x0300002A'=> [qw(KRB5_WITH_RC2_40_CBC_MD5 EXP-KRB5-RC2-CBC-MD5)], '0x03000027'=> [qw(KRB5_WITH_RC2_40_CBC_SHA EXP-KRB5-RC2-CBC-SHA)], '0x03000024'=> [qw(KRB5_WITH_RC4_128_MD5 KRB5-RC4-MD5)], '0x03000020'=> [qw(KRB5_WITH_RC4_128_SHA KRB5-RC4-SHA)], '0x0300002B'=> [qw(KRB5_WITH_RC4_40_MD5 EXP-KRB5-RC4-MD5)], '0x03000028'=> [qw(KRB5_WITH_RC4_40_SHA EXP-KRB5-RC4-SHA)], '0x0300000A'=> [qw(RSA_WITH_DES_192_CBC3_SHA DES-CBC3-SHA)], '0x03000008'=> [qw(RSA_WITH_DES_40_CBC_SHA EXP-DES-CBC-SHA)], '0x03000009'=> [qw(RSA_WITH_DES_64_CBC_SHA DES-CBC-SHA)], '0x03000007'=> [qw(RSA_WITH_IDEA_128_SHA IDEA-CBC-SHA)], '0x03000000'=> [qw(NULL_WITH_NULL_NULL NULL-NULL)], '0x03000001'=> [qw(RSA_WITH_NULL_MD5 NULL-MD5)], '0x03000002'=> [qw(RSA_WITH_NULL_SHA NULL-SHA)], '0x030000FF'=> [qw(EMPTY_RENEGOTIATION_INFO_SCSV SCSV-RENEG)], ); ############################################################################################# ############################################################################################ sub version { # version of SSLhello #? prints the official version number of SSLhello (yy-mm-dd) local $\ = ""; # no auto '\n' at the end of the line print "NET::SSLhello ($VERSION)\n"; return; } sub printParameters { #? prints the global parameters # local $\ = ""; # no auto '\n' at the end of the line print ("#O-Saft::Net::SSLhello::Parameters:\n"); print ("#SSLHello: retry=$Net::SSLhello::retry\n") if (defined($Net::SSLhello::retry)); print ("#SSLHello: timeout=$Net::SSLhello::timeout\n") if (defined($Net::SSLhello::timeout)); print ("#SSLHello: connect_delay=$Net::SSLhello::connect_delay\n") if (defined($Net::SSLhello::connect_delay)); print ("#SSLHello: trace=$Net::SSLhello::trace\n") if (defined($Net::SSLhello::trace)); print ("#SSLHello: traceTIME=$Net::SSLhello::traceTIME\n") if (defined($Net::SSLhello::traceTIME)); print ("#SSLHello: usereneg=$Net::SSLhello::usereneg\n") if (defined($Net::SSLhello::usereneg)); print ("#SSLHello: double_reneg=$Net::SSLhello::double_reneg\n") if (defined($Net::SSLhello::double_reneg)); print ("#SSLHello: usesni=$Net::SSLhello::usesni\n") if (defined($Net::SSLhello::usesni)); print ("#SSLHello: use_sni_name=$Net::SSLhello::use_sni_name\n") if (defined($Net::SSLhello::use_sni_name)); print ("#SSLHello: sni_name=$Net::SSLhello::sni_name\n") if (defined($Net::SSLhello::sni_name)); print ("#SSLHello: use_signature_alg=$Net::SSLhello::use_signature_alg\n") if (defined($Net::SSLhello::use_signature_alg)); print ("#SSLHello: useecc=$Net::SSLhello::useecc\n") if (defined($Net::SSLhello::useecc)); print ("#SSLHello: useecpoint=$Net::SSLhello::useecpoint\n") if (defined($Net::SSLhello::useecpoint)); print ("#SSLHello: starttls=$Net::SSLhello::starttls\n") if (defined($Net::SSLhello::starttls)); print ("#SSLHello: starttlsType=$Net::SSLhello::starttlsType\n") if (defined($Net::SSLhello::starttlsType)); for my $i (1..5) { print ("#SSLHello: starttlsPhaseArray[$i]=$Net::SSLhello::starttlsPhaseArray[$i]\n") if (defined($Net::SSLhello::starttlsPhaseArray[$i])); } for my $i (6..8) { print ("#SSLHello: starttlsErrorArray[".($i-5)."]=$Net::SSLhello::starttlsPhaseArray[$i] = starttlsPhaseArray[$i] (internally)\n") if (defined($Net::SSLhello::starttlsPhaseArray[$i])); } print ("#SSLHello: starttlsDelay=$Net::SSLhello::starttlsDelay\n") if (defined($Net::SSLhello::starttlsDelay)); print ("#SSLHello: slowServerDelay=$Net::SSLhello::slowServerDelay\n") if (defined($Net::SSLhello::slowServerDelay)); print ("#SSLHello: experimental=$Net::SSLhello::experimental\n") if (defined($Net::SSLhello::experimental)); print ("#SSLHello: proxyhost=$Net::SSLhello::proxyhost\n") if (defined($Net::SSLhello::proxyhost)); print ("#SSLHello: proxyport=$Net::SSLhello::proxyport\n") if (defined($Net::SSLhello::proxyport)); print ("#SSLHello: max_ciphers=$Net::SSLhello::max_ciphers\n") if (defined($Net::SSLhello::max_ciphers)); print ("#SSLHello: max_sslHelloLen=$Net::SSLhello::max_sslHelloLen\n") if (defined($Net::SSLhello::max_sslHelloLen)); print ("#------------------------------------------------------------------------------------------\n"); return; } ### --------------------------------------------------------------------------------------------------------- ### ### compile packets functions ### --------------------------------------------------------------------------------------------------------- ### Aufruf mit printCipherStringArray ($cfg{'legacy'}, $host, $port, "TLS1.2 0x0303", $cfg{'usesni'}, @acceptedCipherArray); sub printCipherStringArray ($$$$$@) { #? FIXME: <> # @cipherArray: string representation of the cipher octetts, fe.g. 0x0300000A # The first two ciphers are identical, if the server has a preferred order # my($legacy, $host, $port, $ssl, $usesni, @cipherArray) = @_; # my $legacy = shift; #$_[0] # my $host = shift; #$_[1] # my $port = shift; #$_[2] # my $ssl = shift; #$_[3] # my $usesni = shift; #$_[4] # my (@cipherArray) = @{$_[5]}; my $arrayLen = @cipherArray; my $cipherOrder = ""; # cipher suites in server-preferred order or not my $sni = ""; my $sep = ", "; my $protocol = $PROTOCOL_VERSION{$ssl}; # 0x0002, 0x3000, 0x0301, 0x0302 local $\ = ""; # no auto '\n' at the end of the line _trace4 ("printCipherStringArray: {\n"); if ($usesni) { $sni = "SNI"; #tbd: check in serverHello if SNI is supported by the server $Net::SSLhello::use_sni_name = 1 if ( ($Net::SSLhello::use_sni_name == 0) && ($Net::SSLhello::sni_name) && ($Net::SSLhello::sni_name ne "1") ); ###FIX: quickfix until migration of o-saft.pl is compleated (tbd) $sni .= " ($Net::SSLhello::sni_name)" if ( ($Net::SSLhello::use_sni_name) && ($Net::SSLhello::sni_name) ); } else { $sni = "no SNI"; } my $firstEle = 0; if ($arrayLen > 1) { # 2 or more ciphers if ( ($cipherArray[0] eq $cipherArray[1]) ) { # cipher suites in server-preferred order if ($legacy eq 'compact') { $cipherOrder = "Server Order"; } else { print "# cipher suites in server-preferred order:\n"; } $firstEle = 1; } else { if ($legacy eq 'compact') { $cipherOrder = "No Order"; } else { print "# server has NO preferred order for cipher suites\n"; } } } elsif ($arrayLen == 0) { # no cipher for this protocol if ($legacy eq 'compact') { # csv-style, protocol without cipher printf "%s%s%s%s%-6s (0x%04X)%s%6s%s%-12s%s%10s%s\n", $host, $sep, # %s%s $port, $sep, # %s%s $ssl, # %-6s ( $protocol, $sep, # 0x%04X)%s $sni, $sep, # %6s%s% "", $sep, # %-12s%s "", $sep; # %10s%s } } foreach my $protocolCipher (@cipherArray[$firstEle .. $#cipherArray]) { # array may have the first element twice to signal a server-preferred order if ($legacy eq 'compact') { # csv-style printf "%s%s%s%s%-6s (0x%04X)%s%6s%s%-12s%s%10s%s", $host, $sep, # %s%s $port, $sep, # %s%s $ssl, # %-6s ( $protocol, $sep, # 0x%04X)%s $sni, $sep, # %6s%s% $cipherOrder, $sep, # %-12s%s $protocolCipher, $sep; # %10s%s if ( (defined ($cipherHexHash {$protocolCipher}) ) && ($#{$cipherHexHash {$protocolCipher}}>0) ) { # definiert, max index >0 printf "%-28s%s%-34s", $cipherHexHash {$protocolCipher}[1], $sep, # %-28s%s $cipherHexHash {$protocolCipher}[0]; # %-34s if (defined ($_SSLhello {$protocolCipher."\|ServerKey"})) { #length of dh_param printf "%s%s\n", $sep, "(".$_SSLhello {$protocolCipher."\|ServerKey"}.")"; # %s%s } else { print "\n"; } } else { # no RFC-Defined cipher printf "%-28s%s%-34s\n", "NO-RFC-".$protocolCipher, $sep, # %-28s%s "NO-RFC-".$protocolCipher; # %-34ss } } else { # human readable output if ( (defined ($cipherHexHash {$protocolCipher}) ) && ($#{$cipherHexHash {$protocolCipher}}>0) ) { # definiert, max index >0 printf "# Cipher-String: >%s<, %-32s, %s",$protocolCipher, $cipherHexHash {$protocolCipher}[1], $cipherHexHash {$protocolCipher}[0]; if (defined ($_SSLhello {$protocolCipher."\|ServerKey"})) { #length of dh_param print ", (".$_SSLhello {$protocolCipher."\|ServerKey"}.")"; } } else { print "# Cipher-String: >".$protocolCipher."<, NO-RFC-".$protocolCipher; } print "\n"; } } # foreach my $protocolCipher ... if ($legacy eq 'compact') { # csv-style print "\n"; } _trace4 ("printCipherStringArray: }\n\n"); return; } # printCipherStringArray sub checkSSLciphers ($$$@) { #? simulate SSL handshake to check any ciphers by the HEX value #? @cipher_str_array: string representation of the cipher octet, e.g. >=SSLv3: 0x0300000Aa, SSLv2: 0x02800102 #? if the first 2 ciphers are identical the array is sorted by priority of the server # my($host, $port, $ssl, @cipher_str_array) = @_; # my $host = shift || "localhost"; # hostname # my $port = shift || 443; # my $ssl = shift || ""; # SSLv2 # my (@cipher_str_array) = @_ || (); my $cipher_spec = ""; # raw data with all hex values, SSLv2: 3 bytes, SSLv3 and later: 2 bytes my $acceptedCipher = ""; my @cipherSpecArray = (); # temporary Array for all ciphers to be tested in the next _doCheckSSLciphers my @acceptedCipherArray = (); # all ciphers accepted by the server my @acceptedCipherSortedArray = (); # all ciphers accepted by the server with server order my $arrayLen = 0; my $i = 0; my $protocol = $PROTOCOL_VERSION{$ssl}; # 0x0002, 0x3000, 0x0301, 0x0302 my $maxCiphers = $Net::SSLhello::max_ciphers; local $\ = ""; # no auto '\n' at the end of the line printParameters () if ($Net::SSLhello::trace >= 4); # additional trace information OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => 'checkSSLciphers', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); if ($Net::SSLhello::trace > 0) { _trace("checkSSLciphers ($host, $port, $ssl, Cipher-Strings:"); foreach my $cipher_str (@cipher_str_array) { # $cipher_str: human readable in internal repesentation ('0x0300xxxx' or '0x02yyyyyy') _trace_ ("\n ") if (($i++) %_MY_PRINT_CIPHERS_PER_LINE == 0); # print up to '_MY_PRINT_CIPHERS_PER_LINE' ciphers per line _trace_ (" >$cipher_str<"); } _trace_(") {\n"); } if ($protocol == $PROTOCOL_VERSION{'SSLv2'}) { #SSL2 _trace4_ ("\n"); foreach my $cipher_str (@cipher_str_array) { _trace4 ("checkSSLciphers: Cipher-String: >$cipher_str< -> "); ($cipher_str) =~ s/(?:0x03|0x02|0x)?\s?([a-fA-F0-9]{2})\s?/chr(hex $1)/egx; ## Str2hex _trace4_ (" >". hexCodedCipher($cipher_str)."<\n"); $cipher_spec .= $cipher_str; # collect cipher specs } _trace4_ ("\n"); $acceptedCipher = _doCheckSSLciphers($host, $port, $protocol, $cipher_spec); if ($Net::SSLhello::trace > 0) { #about: _trace $i = 0; my $anzahl = int length ($acceptedCipher) / 3; _trace(" checkSSLciphers: Accepted ". $anzahl ." Ciphers:\n"); foreach my $cipher_str (compileSSL2CipherArray ($acceptedCipher) ) { _trace_ ("\n ") if (($i++) %_MY_PRINT_CIPHERS_PER_LINE == 0); # print up to '_MY_PRINT_CIPHERS_PER_LINE' ciphers per line _trace_ (" >" . $cipher_str . "<"); } _trace_("\n"); _trace(" checkSSLciphers: }\n\n"); } return (compileSSL2CipherArray ($acceptedCipher)); } else { # SSL3, TLS, DTLS .... check by the cipher $cipher_spec = ""; # collect cipher specs _trace4_ ("\n"); foreach my $cipher_str (@cipher_str_array) { _trace4 ("checkSSLciphers: Cipher-String: >$cipher_str< -> "); if ($cipher_str !~ /0x02/x) { # No SSL2 cipher ($cipher_str) =~ s/(?:0x0[3-9a-fA-F]00|0x)?\s?([a-fA-F0-9]{2})\s?/chr(hex $1)/egx; ## Str2hex _trace4_ (" >". hexCodedCipher($cipher_str)."<"); } else { _trace4_ (" SSL2-Cipher suppressed\n"); next; # nothing to do for this cipher } _trace4_ ("\n"); push (@cipherSpecArray, $cipher_str); # add cipher to next test $arrayLen = @cipherSpecArray; if ( $arrayLen >= $maxCiphers) { # test up to ... ciphers ($Net::SSLhello::max_ciphers = _MY_SSL3_MAX_CIPHERS) with 1 doCheckSSLciphers (=> Client Hello) $my_error = ""; # reset error message # reset error_handler and set basic information for this sub OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => 'checkSSLciphers', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); $cipher_spec = join ("",@cipherSpecArray); # all ciphers to test in this round if ($Net::SSLhello::trace > 1) { # print ciphers that are tested this round: $i = 0; if ($Net::SSLhello::starttls) { _trace1 ("checkSSLciphers ($host, $port (STARTTLS), $ssl): Checking ". scalar(@cipherSpecArray)." Ciphers, this round (1):"); } else { _trace1 ("checkSSLciphers ($host, $port, $ssl): Checking ". scalar(@cipherSpecArray)." Ciphers, this round (1):"); } _trace4_ ("\n"); foreach my $cipher_str (compileTLSCipherArray (join ("",@cipherSpecArray)) ) { _trace_ ("\n ") if (($i++) %_MY_PRINT_CIPHERS_PER_LINE == 0); # print up to '_MY_PRINT_CIPHERS_PER_LINE' ciphers per line _trace_ (" >" . $cipher_str . "<"); } _trace2_ ("\n"); } $acceptedCipher = _doCheckSSLciphers($host, $port, $protocol, $cipher_spec, $dtlsEpoch); # test ciphers and collect accepted ciphers, $dtlsEpoch is only used in DTLS _trace2_ (" "); if ($acceptedCipher) { # received an accepted cipher _trace1_ ("=> found >0x0300".hexCodedCipher($acceptedCipher)."<\n"); if (grep { $_ eq $acceptedCipher } @cipherSpecArray) { #accepted cipher that was in the checklist @cipherSpecArray = grep { $_ ne $acceptedCipher } @cipherSpecArray; # delete accepted cipher from ToDo-Array '@cipherSpecArray' } else { # cipher was *NOT* in the checklist carp ("**WARNING: Server replied (again) with cipher '0x".hexCodedCipher($acceptedCipher)."' that has not been requested this time (1): ('0x".hexCodedCipher($cipherSpecArray[0])." ... 0x".hexCodedCipher($cipherSpecArray[-1])."'."); @cipherSpecArray = (); # => Empty @cipherSpecArray } push (@acceptedCipherArray, $acceptedCipher); # add the cipher to the list of accepted ciphers } else { # no ciphers accepted _trace1_ ("=> no Cipher found\n"); if ( ((OSaft::error_handler->get_err_type()) <= (OERR_SSLHELLO_RETRY_HOST)) || ($my_error =~ /Fatal Exit/) || ($my_error =~ /make a connection/ ) || ($my_error =~ /create a socket/) ) { #### Fatal Errors -> Useless to check more protocols _trace ("checkSSLciphers (1.1): '$my_error'\n") if ($my_error); _trace ("**WARNING: checkSSLciphers => Exit loop (1.1): -> Abort '$host:$port' caused by ".OSaft::error_handler->get_err_str."\n"); @cipherSpecArray =(); # server did not accept any cipher => nothing to do for these ciphers => empty @cipherSpecArray last; } elsif ( ((OSaft::error_handler->get_err_type()) <= (OERR_SSLHELLO_RETRY_PROTOCOL)) || ($my_error =~ /answer ignored/) || ($my_error =~ /protocol_version.*?not supported/) || ($my_error =~ /check.*?aborted/x) ) { # Just stop, no warning _trace2 ("checkSSLciphers (1.2): '$my_error'\n") if ($my_error); @cipherSpecArray =(); # server did not accept any cipher => nothing to do for these ciphers => empty @cipherSpecArray last; } elsif ( ($my_error =~ /target.*?ignored/x) || ($my_error =~ /protocol.*?ignored/x) ) { #### Fatal Errors -> Useless to check more ciphers _trace2 ("checkSSLciphers (1.3): \'$my_error\'\n") if ($my_error); carp ("**WARNING: checkSSLciphers => Exit Loop (1.3)"); @cipherSpecArray =(); # server did not accept any cipher => nothing to do for these ciphers => empty @cipherSpecArray last; } elsif ( ((OSaft::error_handler->get_err_type()) <= (OERR_SSLHELLO_RETRY_CIPHERS)) || ($my_error =~ /\-> Received NO Data/)) { # some servers 'Respond' by closing the TCP connection => check each cipher individually if ($Net::SSLhello::noDataEqNoCipher == 1) { # ignore error messages for TLS intolerant servers that do not respond if non of the ciphers are supported _trace2 ("checkSSLciphers (1.4): Ignore error messages for TLS intolerant servers that do not respond if non of the ciphers are supported. Ignored: '$my_error'\n"); @cipherSpecArray =(); # => empty @cipherSpecArray $my_error = ""; # reset error message next; } else { # noDataEqNoCipher == 0 _trace2 ("checkSSLciphers (1.5): \'$my_error\', => Please use the option \'--noDataEqNoCipher\' for servers not answeing if none of the requested ciphers are supported. Retry to test the following cipheres individually:\n"); carp ("**WARNING: checkSSLciphers (1.5): \'$my_error\', => Please use the option \'--noDataEqNoCipher\' for servers not answeing if none of the requested ciphers are supported."); } } elsif ( ((OSaft::error_handler->get_err_type()) <= (OERR_SSLHELLO_RETRY_RECORD)) || ($my_error =~ /Error 1: too many requests/)) { #### Too many connections: Automatic suspension and higher timeout did not help _trace2 ("checkSSLciphers (1.6): \'$my_error\', => Please use the option \'--starttls_delay=SEC\' to slow down\n"); carp ("**WARNING: checkSSLciphers (1.6): \'$my_error\', => Please use the option \'--starttls_delay=SEC\' to slow down"); next; } elsif ((OSaft::error_handler->is_err) || $my_error) { # Error found unless (OSaft::error_handler->is_err) { # no error set, but no socket obtaied OSaft::error_handler->new( { type => (OERR_SSLHELLO_ERROR_MESSAGE_IGNORED), id => '(1.9)', message => "Unexpected Error Messagege ignored: \'$my_error\'", warn => 1, } ); } $my_error = ""; # reset error message #reset error_handler and set basic information for this sub OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => 'checkSSLciphers', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); } # else: no cipher accepted but no error @cipherSpecArray =(); # => Empty @cipherSpecArray } # end: if 'no ciphers accepted' } # end: test ciphers } # end: foreach my $cipher_str... while ( (@cipherSpecArray > 0) && (!OSaft::error_handler->is_err) && (!$my_error) ) { # there are still ciphers to test in this last round $cipher_spec = join ("",@cipherSpecArray); # all ciphers to test in this round; if ($Net::SSLhello::trace > 1) { #print ciphers that are tested this round: $i = 0; _trace ("checkSSLciphers ($host, $port, $ssl): Checking ". scalar(@cipherSpecArray)." Ciphers, this round (2):"); _trace4_ ("\n"); foreach my $cipher_str (compileTLSCipherArray (join ("",@cipherSpecArray)) ) { _trace_ ("\n ") if (($i++) %_MY_PRINT_CIPHERS_PER_LINE == 0); # print up to '_MY_PRINT_CIPHERS_PER_LINE' ciphers per line _trace_ ( " >" . $cipher_str . "<"); } _trace2_ ("\n"); } $acceptedCipher = _doCheckSSLciphers($host, $port, $protocol, $cipher_spec, $dtlsEpoch); # test ciphers and collect Accepted ciphers _trace2_ (" "); if ($acceptedCipher) { # received an accepted cipher ## TBD: Error handling using `given'/`when' TBD _trace1_ ("=> found >0x0300".hexCodedCipher($acceptedCipher)."<\n"); if (grep { $_ eq $acceptedCipher } @cipherSpecArray) { # accepted cipher that was in the checklist @cipherSpecArray = grep { $_ ne $acceptedCipher } @cipherSpecArray; # delete accepted cipher from ToDo-Array '@cipherSpecArray' } else { # cipher was *NOT* in the checklist carp ("**WARNING: Server replied (again) with cipher '0x".hexCodedCipher($acceptedCipher)."' that has not been requested this time (2): ('0x".hexCodedCipher($cipherSpecArray[0])." ... 0x".hexCodedCipher($cipherSpecArray[-1])."'."); @cipherSpecArray = (); # => Empty @cipherSpecArray } push (@acceptedCipherArray, $acceptedCipher); # add the cipher to the list of accepted ciphers } else { # no cipher accepted _trace1_ ("=> no cipher found\n"); if ( ($my_error =~ /Fatal Exit/) || ($my_error =~ /make a connection/ ) || ($my_error =~ /create a socket/) ) { #### Fatal Errors -> Useless to check more ciphers _trace2 ("checkSSLciphers (2.1): '$my_error'\n"); carp ("**WARNING: checkSSLciphers => Exit Loop (2.1)"); @cipherSpecArray =(); # server did not accept any cipher => nothing to do for these ciphers => empty @cipherSpecArray last; } elsif ( ($my_error =~ /answer ignored/) || ($my_error =~ /protocol_version.*?not supported/) || ($my_error =~ /check.*?aborted/) ) { # just stop, no warning _trace1 ("**checkSSLciphers => Exit Loop (2.2)"); @cipherSpecArray =(); # server did not accepty any cipher => nothing to do for these ciphers => empty @cipherSpecArray last; # no more ciphers to test } elsif ( ($my_error =~ /target.*?ignored/x) || ($my_error =~ /protocol.*?ignored/x) ) { #### Fatal Errors -> Useless to check more ciphers _trace2 ("checkSSLciphers (2.3): '$my_error'\n"); carp ("**WARNING: checkSSLciphers => Exit Loop (2.3)"); @cipherSpecArray =(); # server did not accept any cipher => nothing to do for these ciphers => empty @cipherSpecArray last; } elsif ( $my_error =~ /\-> Received NO Data/) { # some servers 'Respond' by closing the TCP connection => check each cipher individually if ($Net::SSLhello::noDataEqNoCipher == 1) { # ignore error messages for TLS intolerant servers that do not respond if non of the ciphers are supported _trace1 ("checkSSLciphers (2.4): Ignore Error Messages for TLS intolerant Servers that do not respond if non of the Ciphers are supported. Ignored: '$my_error'\n"); @cipherSpecArray =(); # => Empty @cipherSpecArray $my_error = ""; # reset error message next; # here: eq last } else { # noDataEqNoCipher == 0 _trace2 ("checkSSLciphers (2.5): '$my_error', => Please use the option \'--noDataEqNoCipher\' for Servers not answering if none of the requested Ciphers are supported. Retry to test the following Cipheres individually:\n"); carp ("**WARNING: checkSSLciphers (2.5): '$my_error', => Please use the option \'--noDataEqNoCipher\' for Servers not answering if none of the requested Ciphers are supported."); } } elsif ($my_error =~ /Error 1: too many requests/) { #### Too many connections: Automatic suspension and higher timeout did not help _trace2 ("checkSSLciphers (1.6): \'$my_error\', => Please use the option \'--starttls_delay=SEC\' to slow down\n"); carp ("**WARNING: checkSSLciphers (1.6): \'$my_error\', => Please use the option \'--starttls_delay=SEC\' to slow down"); next; } elsif ($my_error) { # error found _trace2 ("checkSSLciphers (2.6): Unexpected Error Messagege ignored: '$my_error'\n"); carp ("checkSSLciphers (2.6): Unexpected Error Messagege ignored: '$my_error'\n"); $my_error = ""; # reset error message } @cipherSpecArray =(); # => Empty @cipherSpecArray } } # end while ... if ($Net::SSLhello::trace > 0) { # about: _trace $i = 0; _trace(" checkSSLciphers ($host, $port, $ssl): Accepted ". scalar(@acceptedCipherArray)." Ciphers (unsorted):"); foreach my $cipher_str (compileTLSCipherArray (join ("",@acceptedCipherArray)) ) { _trace_ ("\n ") if (($i++) %_MY_PRINT_CIPHERS_PER_LINE == 0); # print up to '_MY_PRINT_CIPHERS_PER_LINE' ciphers per line _trace_ (" >" . $cipher_str . "<"); } _trace_("\n"); } # >>>>> Check priority of ciphers <<<<< #################################################################################################################### ###### Derzeit wird der 1. Cipher doppelt in die Liste eingetragen, wenn der Server die Prio vorgibt ##### #################################################################################################################### my $cipher_str = join ("",@acceptedCipherArray); printTLSCipherList ($cipher_str) if ($Net::SSLhello::trace > 3); # abt: _trace4 while ($cipher_str) { # found some cipher => Check priority _trace2 ("checkSSLciphers: Check Cipher Prioity for Cipher-Spec >". hexCodedString($cipher_str)."<\n"); $my_error = ""; # reset error message $acceptedCipher = _doCheckSSLciphers($host, $port, $protocol, $cipher_str, $dtlsEpoch, 1); # collect accepted ciphers by priority _trace2_ ("# -->". hexCodedCipher($acceptedCipher)."<\n"); if ($my_error) { _trace2 ("checkSSLciphers (3): '$my_error'\n"); # list untested ciphers $i = 0; my $str = ""; #output string with list of ciphers foreach my $cipher_str (compileTLSCipherArray (join ("",@acceptedCipherArray)) ) { if (($i++) != 0) { # not 1st element $str .= "\n " if ($i %_MY_PRINT_CIPHERS_PER_LINE == 0); # 'print' up to '_MY_PRINT_CIPHERS_PER_LINE' ciphers per line $str .= " "; } $str .= ">" . $cipher_str . "<"; } # End: list untested ciphers if ( ($my_error =~ /Fatal Exit/) || ($my_error =~ /make a connection/ ) || ($my_error =~ /create a socket/) || ($my_error =~ /target.*?ignored/x) || ($my_error =~ /protocol.*?ignored/x) ) { _trace1 ("checkSSLciphers (3.1): => Unexpected Loss of Connection while checking the priority of the ciphers \'$str\' -> Exit Loop. Reason: '$my_error'\n"); carp ("**WARNING: checkSSLciphers (3.1): => Unexpected Loss of Connection while checking the priority of the ciphers \'$str\' -> Exit Loop. Reason: '$my_error'"); $my_error = ""; # reset error message last; } elsif ( ($my_error =~ /answer ignored/) || ($my_error =~ /protocol_version.*?not supported/) || ($my_error =~ /check.*?aborted/x) ) { # Just stop, no warning _trace1 ("checkSSLciphers (3.2): => Unexpected Lack of Data or unexpected Answer while checking the priority of the ciphers \'$str\' -> Exit Loop. Reason: '$my_error'\n"); carp ("**WARNING: checkSSLciphers (3.2): => Unexpected Lack of Data or unexpected Answer while checking the priority of the ciphers \'$str\' - > Exit Loop. Reason: '$my_error'"); _hint("The server may have an IPS in place. To slow down the test, consider adding the option '--connect-delay=SEC'."); $my_error = ""; # reset error message last; } } if ($acceptedCipher) { # received an accepted cipher push (@acceptedCipherSortedArray, $acceptedCipher); # add found cipher to sorted List $arrayLen = @acceptedCipherSortedArray; if ( $arrayLen == 1) { # 1st cipher if ($acceptedCipher eq ($acceptedCipherArray[0])) { # is equal to 1st cipher of requested cipher_spec _trace3 ("# Got back 1st cipher of unsorted List => Check again with this Cipher >".hexCodedTLSCipher($acceptedCipher)."< at the end of the List\n"); shift (@acceptedCipherArray); # delete first cipher in this array $cipher_str = join ("",@acceptedCipherArray).$acceptedCipher; # test again with the first cipher as the last _trace3 ("Check Cipher Prioity for Cipher-S(2) > ". hexCodedCipher($cipher_str)."< "); _trace4 ("\n"); $acceptedCipher = _doCheckSSLciphers($host, $port, $protocol, $cipher_str, $dtlsEpoch, 1); # if server uses a priority List we get the same cipher again! _trace3_ ("# -->". hexCodedCipher($acceptedCipher)."<\n"); _trace4_ ("# --->". hexCodedCipher($acceptedCipher)."<\n"); if ($acceptedCipher) { # received an accepted cipher ### TBD: if ($acceptedCipher eq ($acceptedCipherArray[0]) => no order => return (@acceptedCipherSortedArray[0].$acceptedCipherArray) push (@acceptedCipherSortedArray, $acceptedCipher); } } else { # 1st element is nOT equal of 1st checked cipher => sorted => NOW: add cipher again to mark it as sorted list push (@acceptedCipherSortedArray, $acceptedCipher); # add found cipher again to sorted List } } # not the first cipher if ( (grep { $_ eq $acceptedCipher } @acceptedCipherArray) || (($arrayLen == 1) && ($acceptedCipher eq $acceptedCipherSortedArray[1])) ) { # accepted cipher was in the checklist @acceptedCipherArray = grep { $_ ne $acceptedCipher } @acceptedCipherArray; # delete accepted cipher in ToDo-Array '@acceptedCipherArray' } else { # cipher was *NOT* in the checklist carp ("**WARNING: checkSSLciphers: Server replied (again) with cipher '0x".hexCodedCipher($acceptedCipher)."' that has not been requested this time (3): ('0x".hexCodedCipher($acceptedCipherArray[0])." ... 0x".hexCodedCipher($acceptedCipherArray[-1])."'. Untested Ciphers:"); # list untested ciphers $i = 0; my $str = ""; # output string with list of ciphers foreach my $cipher_str (compileTLSCipherArray (join ("",@acceptedCipherArray)) ) { if (($i++) != 0) { # not 1st element $str .= "\n " if ($i %_MY_PRINT_CIPHERS_PER_LINE == 0); # 'print' up to '_MY_PRINT_CIPHERS_PER_LINE' ciphers per line $str .= " "; } $str .= ">" . $cipher_str . "<"; } # End: list untested ciphers @acceptedCipherArray = (); # => Empty @cipherSpecArray } # End cipher was *NOT* in the ckecklist $cipher_str = join ("",@acceptedCipherArray); # check prio for next ciphers } else { # nothing received => lost connection _trace2 ("checkSSLciphers (6): '$my_error'\n"); # list untested ciphers $i = 0; my $str = ""; # output string with list of ciphers foreach my $cipher_str (compileTLSCipherArray (join ("",@acceptedCipherArray)) ) { if (($i++) != 0) { # not 1st element $str .= "\n " if ($i %_MY_PRINT_CIPHERS_PER_LINE == 0); # 'print' up to '_MY_PRINT_CIPHERS_PER_LINE' ciphers per line $str .= " "; } $str .= ">" . $cipher_str . "<"; } # End: list untested ciphers if ( ($my_error =~ /Fatal Exit/) || ($my_error =~ /make a connection/ ) || ($my_error =~ /create a socket/) || ($my_error =~ /target.*?ignored/x) || ($my_error =~ /protocol.*?ignored/x) ) { _trace1 ("checkSSLciphers (6.1): => Unexpected Loss of Connection while checking the priority of the ciphers \'$str\' -> Exit Loop. Reason: '$my_error'\n"); carp ("**WARNING: checkSSLciphers (6.1): => Unexpected Loss of Connection while checking the priority of the ciphers \'$str\' -> Exit Loop. Reason: '$my_error'"); $my_error = ""; # reset error message last; } elsif ($my_error =~ /Error 1: too many requests/) { #### Too many connections: Automatic suspension and higher timeout did not help _trace2 ("checkSSLciphers (1.6): \'$my_error\', => Please use the option \'--starttls_delay=SEC\' to slow down\n"); carp ("**WARNING: checkSSLciphers (1.6): \'$my_error\', => Please use the option \'--starttls_delay=SEC\' to slow down"); next; } elsif ($my_error) { #any other Error like: #} elsif ( ( $my_error =~ /\-> Received NO Data/) || ($my_error =~ /answer ignored/) || ($my_error =~ /protocol_version.*?not supported/) || ($my_error =~ /check.*?aborted/) ) { _trace1 ("checkSSLciphers (6.2): => Unexpected Lack of Data or unexpected Answer while checking the priority of the ciphers \'$str\' -> Exit Loop. Reason: ''\n"); carp ("**WARNING: checkSSLciphers (6.2): => Unexpected Lack of Data or unexpected Answer while checking the priority of the ciphers \'$str\' -> Exit Loop. Reason: '$my_error'"); _hint("The server may have an IPS in place. To slow down the test, consider adding the option '--connect-delay=SEC'."); $my_error = ""; # reset error message last; } } } # end while-Loop ### _trace4 ("# Accepted (sorted) Ciphers [cipher1 = cipher 2 => sorted by Server]:\n"); ### TBD: _trace4: print all ciphers?!! _trace(" checkSSLciphers: }\n\n"); return (compileTLSCipherArray (join ("",@acceptedCipherSortedArray))); } } # checkSSLciphers sub openTcpSSLconnection ($$) { #? open a TCP connection to a server and port and send STARTTLS if requested #? this SSL connection could be made via a http proxy my $host = shift || ""; # hostname my $port = shift || ""; my $socket; my $connect2ip; my $alarmTimeout = $Net::SSLhello::timeout +1; # 1 sec more than normal timeout as a time line of second protection my $proxyConnect = ""; my $clientHello = ""; my $input = ""; my $input2 = ""; my $retryCnt = 0; my $sleepSecs = $Net::SSLhello::starttlsDelay || 0; my $slowServerDelay = $Net::SSLhello::slowServerDelay || 0; my $suspendSecs = 0; my $firstMessage = ""; my $secondMessage = ""; my $starttlsType=0; # SMTP # 15 Types defined: 0:SMTP, 1:SMTP_2, 2:IMAP, 3:IMAP_CAPACITY, 4:IMAP_2, 5:POP3, 6:POP3_CAPACITY, 7:FTPS, 8:LDAP, 9:RDP, 10:RDP_SSL, 11:XMPP, 12:ACAP, 13:IRC, 14:IRC_CAPACITY # # ##TBD new subs openTcpSSLconnectionViaProxy, openTcpSSLconnectionUsingStarttls # # local $my_error = "" if (!defined($my_error)); my @starttls_matrix = ( ["SMTP", ".*?(?:^|\\n)220\\s", # Phase1: receive '220 smtp.server.com Simple Mail Transfer Service Ready' "EHLO o-saft.localhost\r\n", # Phase2: send 'EHLO o-saft.localhost\r\n' ".*?(?:^|\\n)250\\s", # Phase3: receive '250 smtp.server.com Hello o-saft.localhost' "STARTTLS\r\n", # Phase4: send 'STARTTLS' ".*?(?:^|\\n)220\\s", # Phase5: receive '220' ".*?(?:^|\\n)(?:421|450)\\s", # Error1: temporary unreachable (too many connections); 450 Traffic is being throttled (connects per ip limit: ...), +454? ".*?(?:^|\\n)4[57]4\\s", # Error2: This SSL/TLS-Protocol is not supported 454 or 474 ".*?(?:^|\\n)(?:451|50[023]|554)\\s", # Error3: fatal Error/STARTTLS not supported: '500 Syntax error, command unrecognized', '502 Command not implemented', '503 TLS is not allowed', 554 PTR lookup failure ... ], ["SMTP_2", # for servers that do *NOT* respond compliantly to RFC 821, or are too slow to get the last line: # 'three-digit code' one line of text (at least the last line needs a Space after the numer, according to the RFC) ".*?(?:^|\\n)220", # Phase1: receive '220-smtp.server.com Simple Mail Transfer Service Ready' or '220 smtp.server.com ....' "EHLO o-saft.localhost\r\n", # Phase2: send 'EHLO o-saft.localhost\r\n' ".*?(?:^|\\n)250", # Phase3: receive '250-smtp.server.com Hello o-saft.localhost' "STARTTLS\r\n", # Phase4: send 'STARTTLS' ".*?(?:^|\\n)220", # Phase5: receive '220-' ".*?(?:^|\\n)(?:421|450)", # Error1: temporary unreachable (too many connections); 450-Traffic is being throttled (connects per ip limit: ...), +454? ".*?(?:^|\\n)4[57]4", # Error2: This SSL/TLS-Protocol is not supported 454-or 474- ".*?(?:^|\\n)(?:451|50[023]|554)", # Error3: fatal Error/STARTTLS not supported: '500-Syntax error, command unrecognized', '502-Command not implemented', '503-TLS is not allowed', 554-PTR lookup failure ... ], ["IMAP", # according RFC2595; found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py' ".*?(?:^|\\n)\\*\\s*OK.*?IMAP(?:\\s|\\d)", # Phase1: receive '* OK IMAP' "", # Phase2: send -unused- "", # Phase2: receive -unused- "a001 STARTTLS\r\n", # Phase4: send 'STARTTLS' ".*?(?:^|\\n)(?:\\*|a001)\\s*OK\\s", # Phase5: receive 'OK completed' "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported ".*?(?:^|\\n)(?:\\*|a00\\d)\\s*(?:BAD|NO)\\s.*?(?:invalid.+?command|unrecognized.+?command|TLS.*?(?:isn\\'t|not)|\\s+no\\s+.*?(?:SSL|TLS)|authoriz)", # Error3: fatal Error/STARTTLS not supported ], ["IMAP_CAPACITY", # according RFC2595; found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py' ".*?(?:^|\\n)\\*\\s*OK.*?IMAP(?:\\s|\\d)", # Phase1: receive '* OK IMAP' "a001 CAPABILITY\r\n", # Phase2: send view CAPABILITY (optional) ".*?(?:^|\\n)\\*\\s*CAPABILITY", # Phase3: receive CAPABILITY-List should include STARTTLS "a002 STARTTLS\r\n", # Phase4: send 'STARTTLS' ".*?(?:^|\\n)(?:\\*|a002)\\s*OK\\s", # Phase5: receive 'OK completed' "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported ".*?(?:^|\\n)(?:\\*|a00\\d)\\s*(?:BAD|NO)\\s.*?(?:invalid.+?command|unrecognized.+?command|TLS.*?(?:isn\\'t|not)|\\s+no\\s+.*?(?:SSL|TLS)|authoriz)", # Error3: fatal Error/STARTTLS not supported ], ["IMAP_2", # found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py' ".*?(?:^|\\n)\\*\\sOK.*?IMAP(?:\\s|\\d)", # Phase1: receive '* OK IMAP' "", # Phase2: send -unused- "", # Phase3: receive -unused- ". STARTTLS\r\n", # Phase4: send 'STARTTLS' ".*?(?:^|\\n). OK\\s", # Phase5: receive '. OK completed' "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported ".*?(?:^|\\n)(?:\\*|a00\\d)\\s*(?:BAD|NO)\\s.*?(?:invalid.+?command|unrecognized.+?command|TLS.*?(?:isn\\'t|not)|\\s+no\\s+.*?(?:SSL|TLS)|authoriz)", # Error3: fatal Error/STARTTLS not supported ], ["POP3", # according RFC2595; found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py' ".*?(?:^|\\n)\\+\\s*OK(?:\\s+|.*?ready|\\r|\\n)", # Phase1: receive '+ OK...ready.' "", # Phase2: send -unused- "", # Phase3: receive -unused- "STLS\r\n", # Phase4: send 'STLS' (-> STARTTLS)' ".*?(?:^|\\n)\\+\\s*OK", # Phase5: receive '+OK Begin TLS' "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported ".*?(?:^|\\n)\\-\\s*ERR.*?(?:invalid command|TLS.*?(?:isn\\'t|not)|\\s+no\\s+.*?(?:SSL|TLS)|authoriz)", # Error3: fatal Error/STARTTLS not supported: '-ERR TLS support isn't enabled' ], ["POP3_CAPACITY", # according RFC2595; found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py' ".*?(?:^|\\n)\\+\\s*OK(?:\\s+|.*?ready|\\r|\\n)", # Phase1: receive '+ OK...ready.' "CAPA\r\n", # Phase2: send view CAPABILITY (optional) ".*?(?:^|\\n)\\+\\s*OK", # Phase3: receive List of should include STLS "STLS\r\n", # Phase4: send 'STLS' (-> STARTTLS)' ".*?(?:^|\\n)\\+\\s*OK", # Phase5: receive '+OK Begin TLS' "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported ".*?(?:^|\\n)\\-\\s*ERR.*?(?:invalid command|TLS.*?(?:isn\\'t|not)|\\s+no\\s+.*?(?:SSL|TLS)|authoriz)", # Error3: fatal Error/STARTTLS not supported: '-ERR TLS support isn't enabled' ], ["FTPS", # found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py' ".*?(?:^|\\n)220\\s", # Phase1: receive '220 ProFTPD 1.3.2rc4 Server (TJ's FTPS Server) [127.0.0.1]' "", # Phase2: send view CAPABILITY (optional) "", # Phase3: receive List of should include STLS "AUTH TLS\r\n", # Phase4: send 'AUTH TLS' (-> STARTTLS)' ".*?(?:^|\\n)234\\s+", # Phase5: receive '234 AUTH TLS successful' "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported "", # Error3: fatal Error/STARTTLS not supported ], ["LDAP", # found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py'$ "", # Phase1: receive -unused-$ "", # Phase2: send -unused-$ "", # Phase3: receive -unused-$ "0\x1d\x02\x01\x01w\x18\x80\x161.3.6.1.4.1.1466.20037", # Phase4: send 'STARTTLS' "0\\x24\\x02\\x01\\x01\\x78\\x1F\\x0A\\x01\\x00\\x04\\x00\\x04\\x00\\x8A\\x161\\.3\\.6\\.1\\.4\\.1\\.1466\\.20037", # Phase5: receive 'Start TLS request accepted.' "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported "", # Error3: fatal Error/STARTTLS not supported ], ["RDP", # found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py'$ "", # Phase1: receive -unused-$ "", # Phase2: send -unused-$ "", # Phase3: receive -unused-$ "\x03\x00\x00\x13\x0E\xE0\x00\x00\x00\x00\x00\x01\x00\x08\x00\x0B\x00\x00\x00", # Phase4: send 'STARTTLS'; http://msdn.microsoft.com/en-us/library/cc240500.aspx "\\x03\\x00\\x00\\x13\\x0E\\xD0.....\\x02.\\x08\\x00[\\x01\\x02\\x08]\\x00\\x00\\x00", # Phase5: receive 'Start TLS request accepted' = [PROTOCOL_SSL, PROTOCOL_HYBRID, PROTOCOL_HYBRID_EX] http://msdn.microsoft.com/en-us/library/cc240506.aspx "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported "\\x03\\x00\\x00\\x13\\x0E\\xD0.....\\x03.\\x08\\x00[\\x01\\x02\\x08]\\x00\\x00\\x00", # Error3: fatal Error/STARTTLS not supported ], # Typical ErrorMsg if STARTTLS is *not* supported: ---> O-Saft::Net::SSLhello ::openTcpSSLconnection: ## STARTTLS (Phase 5): ... Received STARTTLS answer: 19 bytes # >0x03 0x00 0x00 0x13 0x0E 0xD0 0x00 0x00 0x12 0x34 0x00 0x03 0x00 0x08 0x00 0x02 0x00 0x00 0x00 < #### SSL_NOT_ALLOWED_BY_SERVER; http://msdn.microsoft.com/en-us/library/cc240507.aspx ["RDP_SSL", # found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py' "", # Phase1: receive -unused-$ "", # Phase2: send -unused-$ "", # Phase3: receive -unused-$ "\x03\x00\x00\x13\x0E\xE0\x00\x00\x00\x00\x00\x01\x00\x08\x00\x01\x00\x00\x00", # Phase4: send 'STARTTLS' for latency RDP not supporting HYBRID modes "\\x03\\x00\\x00\\x13\\x0E\\xD0.....\\x02.\\x08\\x00[\\x01\\x02\\x08]\\x00\\x00\\x00", # Phase5: receive 'Start TLS request accepted' = [PROTOCOL_SSL, PROTOCOL_HYBRID, PROTOCOL_HYBRID_EX] "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported "\\x03\\x00\\x00\\x13\\x0E\\xD0.....\\x03.\\x08\\x00[\\x01\\x02\\x08]\\x00\\x00\\x00", # Error3: fatal Error/STARTTLS not supported ], ["XMPP", # according rfc3920; found good hints at 'https://github.com/iSECPartners/sslyze/blob/master/utils/SSLyzeSSLConnection.py'$ "", # Phase1: receive -unused-$ "", # Phase2: send Client initiates stream to server (no from to try to avoid to get blocked due to too much connects!) ## " from='osaft\@im.owasp.org' to='".$host."' xml:lang='en' version='1.0'>", # Phase2: send Client initiates stream to server ### " xmlns:tls='http://www.ietf.org/rfc/rfc2595.txt' to='".$host."' xml:lang='en' version='1.0'>", # Phase2: send Client initiates stream to server "", # Phase3: receive response steam header "", # Phase4: send 'STARTTLS'$ "", # Phase5: receive 'Start TLS request accepted.' # Errors: text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>You exceeded the number of connections/logins allowed in 60 seconds, good bye. "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported "", # Error3: fatal Error/STARTTLS not supported ], ["ACAP", # according RFC2595; http://www.vocal.com/secure-communication/secure-acap-over-ssltls/ ".*?(?:^|\\n)\\*\\s*OK.*?ACAP(?:\\s|\\d)", # Phase1: receive '* OK ACAP' "", # Phase2: send -unused- "", # Phase2: receive -unused- "a001 STARTTLS\r\n", # Phase4: send 'a001 STARTTLS' ".*?(?:^|\\n)(?:\\*|a001)\\s*OK\\s", # Phase5: receive 'a001 OK (Begin TLS Negotiation)' "", # Error1: temporary unreachable (too many connections); "", # Error2: This SSL/TLS-Protocol is not supported "", # Error3: fatal Error/STARTTLS not supported ], ["IRC", # according https://github.com/ircv3/ircv3-specifications/blob/master/extensions/tls-3.1 and # https://gist.github.com/grawity/f661adc10fb2d7a580ea ".*?NOTICE.*?", # Phase1: receive ': NOTICE AUTH :*** No ident response; username prefixed with ~' "", # Phase2: send -unused- "", # Phase2: receive -unused- "STARTTLS\r\n", # Phase4: send 'STARTTLS' ".*?(?:^|\n)\\:.*?\\s670\\s+\\:STARTTLS\\s", # Phase5: receive ': 670 :STARTTLS successful, go ahead with TLS handshake' ".*?(?:^|\n)ERROR\\s.*?too.*?(?:fast|much|many)", # Error1: temporary unreachable (too many connections); "", # Error2: this SSL/TLS-Protocol is not supported ".*?(?:^|\\n)421\\s", # Error3: fatal Error/STARTTLS not supported: '421 ERR_UNKNOWNCOMMAND " :Unknown command"' ], ["IRC_CAPACITY", # according https://github.com/ircv3/ircv3-specifications/blob/master/extensions/tls-3.1 and # https://gist.github.com/grawity/f661adc10fb2d7a580ea ".*?NOTICE.*?", # Phase1: receive ': NOTICE AUTH :*** No ident response; username prefixed with ~' "CAP LS\r\n", # Phase2: send view CAPABILITY (optional) ".*?(?:^|\n)\\:.*?\\sCAP\\s.*?\\:.*tls(?:\\s|$|\r\n)", # Phase3: receive : CAP * LS :account-notify away-notify multi-prefix tls us erhost-in-names "STARTTLS\r\n", # Phase4: send 'STARTTLS' ".*?(?:^|\n)\\:.*?\\s670\\s+\\:STARTTLS\\s", # Phase5: receive ': 670 :STARTTLS successful, go ahead with TLS handshake' ".*?(?:^|\n)ERROR\\s.*?too.*?(?:fast|much|many)", # Error1: temporary unreachable (too many connections); "", # Error2: this SSL/TLS-Protocol is not supported ".*?(?:^|\\n)421\\s", # Error3: fatal Error/STARTTLS not supported: '421 ERR_UNKNOWNCOMMAND " :Unknown command"' ], ["CUSTOM", # CUSTOMize your own starttls sequence wit up to 5 phases "", # Phase1: receive "", # Phase2: send "", # Phase2: receive "", # Phase4: send STARTTLS' "", # Phase5: receive OK (Begin TLS Negotiation)' "", # Error1: temporary unreachable (too many connections): "", # Error2: this SSL/TLS-Protocol is not supported: "", # Error3: fatal Error/STARTTLS not supported: ], ); my %startTlsTypeHash; local $my_error = ""; # reset error message OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => 'openTcpSSLconnection', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); if ( ($Net::SSLhello::proxyhost) && ($Net::SSLhello::proxyport) ) { # via proxy _trace2 ("openTcpSSLconnection: Try to connect and open a SSL connection to $host:$port via proxy ".$Net::SSLhello::proxyhost.":".$Net::SSLhello::proxyport."\n"); } else { _trace2 ("openTcpSSLconnection: Try to connect and open a SSL connection to $host:$port\n"); } $retryCnt = 0; if ($Net::SSLhello::starttls) { # starttls -> find STARTTLS type $startTlsTypeHash{$starttls_matrix[$_][0]} = $_ for 0 .. scalar(@starttls_matrix) - 1; _trace4 ("openTcpSSLconnection: nr of Elements in starttlsTypeMatrix: ".scalar(@starttls_matrix)."; looking for starttlsType $Net::SSLhello::starttlsType\n"); if (defined($startTlsTypeHash{uc($Net::SSLhello::starttlsType)})) { $starttlsType = $startTlsTypeHash{uc($Net::SSLhello::starttlsType)}; _trace4 ("openTcpSSLconnection: Index-Nr of StarttlsType $Net::SSLhello::starttlsType is $starttlsType\n"); if ( grep {/^$starttlsType$/x} ('12', '13', '14','15') ) { # ('12', '13', ...) -> Use of an experimental STARTTLS type if ($Net::SSLhello::experimental >0) { # experimental function is are activated _trace_("\n"); _trace ("openTcpSSLconnection: WARNING: use of STARTTLS type $starttls_matrix[$starttlsType][0] is experimental! Send us feedback to o-saft (at) lists.owasp.org, please\n"); } else { # use of experimental functions is not permitted (option is not activated) if ( grep {/^$starttlsType$/x} ('12', '13', '14', '15') ) { # experimental and untested OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROGRAM), id => 'ckeck starttls type (1)', message => "WARNING: use of STARTTLS type $starttls_matrix[$starttlsType][0] is experimental and *untested*!! Please take care! Please add option '--experimental' to use it. Please send us your feedback to o-saft (at) lists.owasp.org", warn => 1, } ); } else { # tested, but still experimental # experimental but tested OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROGRAM), id => 'ckeck starttls type (2)', message => "WARNING: use of STARTTLS type $starttls_matrix[$starttlsType][0] is experimental! Please add option '--experimental' to use it. Please send us your feedback to o-saft (at) lists.owasp.org", warn => 1, } ); } exit (1); # stop program } } if ($starttls_matrix[$starttlsType][0] eq 'CUSTOM') { # customize the starttls_matrix for my $i (1..8) { if (defined($Net::SSLhello::starttlsPhaseArray[$i])) { _trace4 ("openTcpSSLconnection: Customize starttls_matrix: \$Net::SSLhello::starttlsPhaseArray[$i]= >$Net::SSLhello::starttlsPhaseArray[$i]< = hex: >".unpack("H*",$Net::SSLhello::starttlsPhaseArray[$i])."<\n"); if (($i == 2) || ($i == 4)) { #TX Data needs a different handling $starttls_matrix[$starttlsType][$i] = "$Net::SSLhello::starttlsPhaseArray[$i]"; #($starttls_matrix[$starttlsType][$i]) =~ s/(\[^xc]|\c.)/chr(ord('$1'))/eg; ## escape2hex does not work ($starttls_matrix[$starttlsType][$i]) =~ s/\\r/chr(13)/egx; ## return character ($starttls_matrix[$starttlsType][$i]) =~ s/\\n/chr(10)/egx; ## new line character ($starttls_matrix[$starttlsType][$i]) =~ s/\\t/chr(9)/egx; ## tab character ($starttls_matrix[$starttlsType][$i]) =~ s/\\e/chr(27)/egx; ## 'esc' character ($starttls_matrix[$starttlsType][$i]) =~ s/\\x([a-fA-F0-9]{2})/chr(hex $1)/egx; ## Str2hex ($starttls_matrix[$starttlsType][$i]) =~ s/\\\\/\\/gx; ## escaping the escape character } else { # normal copy $starttls_matrix[$starttlsType][$i] = $Net::SSLhello::starttlsPhaseArray[$i]; } _trace2 ("openTcpSSLconnection: Customize \$starttls_matrix[$starttlsType][$i]= >$starttls_matrix[$starttlsType][$i]< = hex: >".unpack("H*",$starttls_matrix[$starttlsType][$i])."<\n"); } } } } else { $starttlsType=0; carp ("openTcpSSLconnection: Undefined StarttlsType, use $starttls_matrix[$starttlsType][0] instead"); } } RETRY_TO_OPEN_SSL_CONNECTION: { do { # connect to #server:port (via proxy) and open a ssl connection (use STARTTLS if activated) OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => 'openTcpSSLconnection', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); if ( defined($Net::SSLhello::connect_delay) && ($Net::SSLhello::connect_delay > 0) ) { _trace_ ("\n"); _trace ("openTcpSSLconnection: connect delay $cfg{'connect_delay'} second(s)\n"); sleep($Net::SSLhello::connect_delay); _trace4 ("openTcpSSLconnection: connect delay $cfg{'connect_delay'} second(s) [End]\n"); } alarm (0); # switch off alarm (e.g. for next retry ) if ($retryCnt >0) { # retry _trace1_ ("\n") if (($retryCnt == 1) && ($main::cfg{'trace'} < 3)); # to catch up '\n' if 1st retry and trace-level is 2 (1 < trace-level < 3) if ( ($Net::SSLhello::proxyhost) && ($Net::SSLhello::proxyport) ) { # via proxy _trace1 ("openTcpSSLconnection: $retryCnt. Retry to connect and open a SSL connection to $host:$port via proxy ".$Net::SSLhello::proxyhost.":".$Net::SSLhello::proxyport); if ($retryCnt > $Net::SSLhello::retry) { _trace1_ (" (this is an additional retry after suspension)"); } _trace1_ ("\n"); } else { _trace1 ("openTcpSSLconnection: $retryCnt. Retry to connect and open a SSL connection to $host:$port\n"); } } if ($Net::SSLhello::starttls) { _trace ("openTcpSSLconnection: $host:$port: wait $sleepSecs sec(s) to prevent too many connects\n") if ( ($main::cfg{'trace'} >2) || ($sleepSecs > 0) ); sleep ($sleepSecs); } { # >> start a block local $@ = ""; eval { local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); # set Alarm for get-socket and set-socketoptions->timeout(s) socket($socket,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]) or croak "Can't create a socket \'$!\' -> target $host:$port ignored "; setsockopt($socket, SOL_SOCKET, SO_SNDTIMEO, pack('L!L!', $Net::SSLhello::timeout, 0) ) or croak "Can't set socket Sent-Timeout \'$!\' -> target $host:$port ignored"; #L!L! => compatible to 32 and 64-bit setsockopt($socket, SOL_SOCKET, SO_RCVTIMEO, pack('L!L!', $Net::SSLhello::timeout, 0) ) or croak "Can't set socket Receive-Timeout \'$!\' -> target $host:$port ignored"; alarm (0); # clear alarm } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = $@; # save the error message as soon as possible alarm (0); # clear alarm if not done before OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_HOST), id => 'socket (1)', message => $my_error, warn => 0, } ); next RETRY_TO_OPEN_SSL_CONNECTION; # Error -> next retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before } # << end a block ######## Connection via a proxy ######## if ( ($Net::SSLhello::proxyhost) && ($Net::SSLhello::proxyport) ) { # via proxy GET_PROXY_IP: { # >> start a block $my_error = ""; $connect2ip = inet_aton($Net::SSLhello::proxyhost); if (!defined ($connect2ip) ) { # no IP address $my_error = "Can't get the IP address of the proxy $Net::SSLhello::proxyhost:$Net::SSLhello::proxyport -> target $host:$port ignored"; carp "$my_error"; OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_HOST), id => 'get proxy IP', message => $my_error, warn => 0, } ); last RETRY_TO_OPEN_SSL_CONNECTION; # retry } } # << end a block { # >> start a block $my_error = ""; local $@ = ""; eval { local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); # set Alarm for Connect connect($socket, pack_sockaddr_in($Net::SSLhello::proxyport, $connect2ip) ) or croak "Can't make a connection to proxy $Net::SSLhello::proxyhost:$Net::SSLhello::proxyport -> target $host:$port ignored"; # TBD will be: TBD # $sock = new IO::Socket::INET( # Proto => "tcp", # PeerAddr => "$Net::SSLhello::proxyhost:$Net::SSLhello::proxyport", # Blocking => 1, # Default # Timeout => $timeout, # ) or die "Can't make a connection to proxy $Net::SSLhello::proxyhost:$Net::SSLhello::proxyport ($@, $!) -> target $host:$port ignored"; # error handling alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = $@; # save the error message as soon as possible alarm (0); # clear alarm if not done before OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_HOST), id => 'connection via proxy (1)', message => $my_error, warn => 0, } ); close ($socket) or carp("**WARNING: ". OSaft::error_handler->get_err_str() ."; Can't close socket, too: $!"); #tbd löschen ### #_trace2 ("openTcpSSLconnection: $@ -> Fatal Exit in openTcpSSLconnection"); sleep (1); # last; # no retry next RETRY_TO_OPEN_SSL_CONNECTION; # next retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before } # << end a block { # >> start a block $my_error = ""; local $@ = ""; eval { $proxyConnect=_PROXY_CONNECT_MESSAGE1.$host.":".$port._PROXY_CONNECT_MESSAGE2; _trace4 ("openTcpSSLconnection: ## ProxyConnect-Message: >$proxyConnect<\n"); local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); # set Alarm for Connect defined(send($socket, $proxyConnect, 0)) || croak "Can't make a connection to $host:$port via proxy $Net::SSLhello::proxyhost:$Net::SSLhello::proxyport [".inet_ntoa($connect2ip).":$Net::SSLhello::proxyport] -> target $host:$port ignored"; alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = $@; # save the error message as soon as possible alarm (0); # clear alarm if not done before OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_HOST), id => 'connection via proxy (2)', message => $my_error, warn => 0, } ); close ($socket) or carp("**WARNING: ". OSaft::error_handler->get_err_str() ."; Can't close socket, too: $!"); if (defined($slowServerDelay) && ($slowServerDelay>0)) { _trace2 ("openTcpSSLconnection: via proxy $host:$port: wait $slowServerDelay sec(s) to wait for slow proxies\n"); sleep ($slowServerDelay); } next RETRY_TO_OPEN_SSL_CONNECTION; # retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before } # << end a block { # start a block $my_error = ""; local $@ = ""; # CONNECT via proxy eval { $input = ""; _trace2 ("openTcpSSLconnection ## CONNECT via proxy: try to receive the Connected-Message from the proxy $Net::SSLhello::proxyhost:$Net::SSLhello::proxyport, Retry = $retryCnt\n"); # select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($retryCnt > 0); # if retry: sleep some ms osaft::osaft_sleep (_SLEEP_B4_2ND_READ) if ($retryCnt > 0); # if retry: sleep some ms local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); recv ($socket, $input, 32767, 0); if (length ($input)==0) { # did not receive a Message _trace4 ("openTcpSSLconnection: ... Received Connected-Message from proxy (1a): received NO Data\n"); sleep(1) if ($retryCnt > 0); # Sleep for 250 milliseconds osaft::osaft_sleep (_SLEEP_B4_2ND_READ); # select(undef, undef, undef, _SLEEP_B4_2ND_READ); recv ($socket, $input, 32767, 0); # 2nd try #### TBD TBD received NO Data TBD TBD ### } alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = $@; # save the error message as soon as possible alarm (0); # clear alarm if not done before OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_HOST), id => 'connection via proxy (3)', message => $my_error, warn => 0, } ); close ($socket) or carp("**WARNING: ". OSaft::error_handler->get_err_str() ."; Can't close socket, too: $!"); if (defined($slowServerDelay) && ($slowServerDelay>0)) { _trace2 ("openTcpSSLconnection: via proxy $host:$port: wait $slowServerDelay sec(s) to wait for slow proxies\n"); sleep ($slowServerDelay); } next RETRY_TO_OPEN_SSL_CONNECTION; # retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before } # << end a block if (length ($input) >0) { # got data _trace3 ("openTcpSSLconnection: ... Received data via proxy: ".length($input)." bytes\n >".substr(_chomp_r($input),0,64)."< ...\n"); _trace4 ("openTcpSSLconnection: ... Received data via proxy: ".length($input)." bytes\n >"._chomp_r($input)."<\n"); if ($input =~ /(?:^|\s)200\s/x) { # HTTP/1.0 200 Connection established\r\nProxy-agent: ... \r\n\r\n $my_error = ""; # connection established _trace2 ("openTcpSSLconnection: Connection established to $host:$port via proxy ".$Net::SSLhello::proxyhost.":".$Net::SSLhello::proxyport."\n"); } else { if ($Net::SSLhello::trace == 0) { # no trace => shorten the output $input =~ /^((?:.+?(?:\r?\n|$)){1,4})/x; # maximal 4 lines $input = _chomp_r($1); } OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_HOST), id => 'connection via proxy (4)', message => "Can't make a connection to $host:$port via proxy $Net::SSLhello::proxyhost:$Net::SSLhello::proxyport; target ignored. Proxy error: ".$input, # error message received from the proxy warn => 0, } ); close ($socket) or carp("**WARNING: ". OSaft::error_handler->get_err_str() ."; Can't close socket, too: $!"); if (defined($slowServerDelay) && ($slowServerDelay>0)) { _trace2 ("openTcpSSLconnection: via proxy $host:$port: wait $slowServerDelay sec(s) to wait for slow proxies\n"); sleep ($slowServerDelay); } next RETRY_TO_OPEN_SSL_CONNECTION; } } } else { #### no proxy #### { # >> start a block $my_error = ""; $connect2ip = inet_aton($host); if (!defined ($connect2ip) ) { # no IP address $my_error = "Can't get the IP address of $host -> target $host:$port ignored in openTcpSSLconnection"; #croak "$my_error"; carp "$my_error"; OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_HOST), id => 'get host IP', message => $my_error, warn => 0, } ); last RETRY_TO_OPEN_SSL_CONNECTION; # retry } } # << end a block { # >> start a block $my_error = ""; local $@ = ""; eval { local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); # set alarm for connect connect( $socket, pack_sockaddr_in($port, $connect2ip) ) or croak "Can't make a connection to $host:$port [".inet_ntoa($connect2ip).":$port]; -> target ignored "; alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = $@; # save the error message as soon as possible alarm (0); # clear alarm if not done before if (defined ($connect2ip) ) { $my_error .= " -> No connection to $host:$port [".inet_ntoa($connect2ip).":$port]; -> target ignored in openTcpSSLconnection"; } else { $my_error .= " -> No connection to $host:$port; -> target ignored in openTcpSSLconnection"; } OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_HOST), id => 'connect (1)', message => $my_error, warn => 0, } ); close ($socket) or carp("**WARNING: ". OSaft::error_handler->get_err_str() ."; Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; # retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before _trace2 ("openTcpSSLconnection: Connected to server $host:$port\n"); } # << end a block } if ( !(OSaft::error_handler->is_err) && ($Net::SSLhello::starttls) ) { # no Error and starttls ############### Begin STARTTLS Support ############# _trace2 ("openTcpSSLconnection: try to STARTTLS using the ".$starttls_matrix[$starttlsType][0]." protocol for server $host:$port, Retry = $retryCnt\n"); # select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($sleepSecs > 0) || ($retryCnt > 0); # if slowed down or retry: sleep some ms if (($slowServerDelay > 0) || ($retryCnt > 0)) { # slow server or retry: sleep some secs _trace2 ("openTcpSSLconnection: $host:$port: wait ".($slowServerDelay||1)." sec(s) to cope with slow servers\n"); sleep ($slowServerDelay||1); # sleep $slowServerDelay secs or min 1 sec #select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($retryCnt > 1); # if retry: sleep some ms } ### STARTTLS_Phase1 (receive) if ($starttls_matrix[$starttlsType][1]) { local $@ = ""; eval { $input = ""; _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 1): try to receive the ".$starttls_matrix[$starttlsType][0]."-Ready-Message from the Server $host:$port\n"); #select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($retryCnt > 0); # if retry: sleep some ms osaft::osaft_sleep (_SLEEP_B4_2ND_READ) if ($retryCnt > 0); # if retry: sleep some ms local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); recv ($socket, $input, 32767, 0); #|| die "openTcpSSLconnection: STARTTLS (Phase 1aa): Did *NOT* get any ".$starttls_matrix[$starttlsType][0]." Message from $host:$port\n"; # did not receive a Message ## unless seems to work better than if!! alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "STARTTLS phase #1 failed): $@"; # save the error message as soon as possible alarm (0); # clear alarm if not done before next RETRY_TO_OPEN_SSL_CONNECTION; # Error -> next retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before if (length ($input) >0) { # received Data => 220 smtp.server.com Simple Mail Transfer Service Ready? _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 1): ... Received ".$starttls_matrix[$starttlsType][0]."-Message (1): ".length($input)." bytes: >"._chomp_r($input)."<\n"); if ($input =~ /$starttls_matrix[$starttlsType][1]/) { # e.g. SMTP: 220 smtp.server.com Simple Mail Transfer Service Ready $my_error = ""; # server is ready } else { $input=_chomp_r($input); if ( ($starttls_matrix[$starttlsType][6]) && ($input =~ /$starttls_matrix[$starttlsType][6]/) ) { # did receive a temporary error message if ($retryCnt > $Net::SSLhello::retry) { # already an additional final retry -> restore last error message $my_error = "STARTTLS (Phase 1): Error 1: too many requests: $host:$port \'$input\' -> suspend $suspendSecs second(s) and all subsequent packets will be slowed down by $sleepSecs second(s)"; last RETRY_TO_OPEN_SSL_CONNECTION; } $Net::SSLhello::starttlsDelay = $sleepSecs; # adopt global variable 1 step later $sleepSecs += $retryCnt + 2; $suspendSecs= 60 * ($retryCnt +1); $my_error = "STARTTLS (Phase 1): Error 1: too many requests: $host:$port \'$input\' -> suspend $suspendSecs second(s) and all subsequent packets will be slowed down by $sleepSecs second(s)"; _trace2 ("openTcpSSLconnection: $my_error\n"); carp ("**WARNING: openTcpSSLconnection: ... $my_error"); #if ($retryCnt > 1); # warning if at least 2nd retry close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); sleep($suspendSecs); _trace4 ("openTcpSSLconnection: STARTTLS (Phase 1): End suspend\n"); if ($retryCnt == $Net::SSLhello::retry) { # signal to do an additional retry $retryCnt++; _trace4 ("openTcpSSLconnection: STARTTLS (Phase 1): 1 additional final retry after too many requests => retry number $retryCnt represented by $retryCnt+1\n"); redo RETRY_TO_OPEN_SSL_CONNECTION; # extra retry } next RETRY_TO_OPEN_SSL_CONNECTION; # next retry } elsif ( ($starttls_matrix[$starttlsType][7]) && ($input =~ /$starttls_matrix[$starttlsType][7]/) ) { # did receive a protocol error message OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'STARTTLS (Phase 1): Error 2', message => "unsupported protocol: $host:$port \'$input\'", warn => 0, } ); close ($socket) or carp("**WARNING: ". OSaft::error_handler->get_err_str() ."; Can't close socket, too: $!"); last; } elsif ( ($starttls_matrix[$starttlsType][8]) && ($input =~ /$starttls_matrix[$starttlsType][8]/) ) { # did receive a fatal error message $my_error = "STARTTLS (Phase 1): Error 3: Fatal Error: $host:$port \'$input\' -> target $host:$port ignored"; _trace2 ("openTcpSSLconnection: $my_error\n"); close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); last RETRY_TO_OPEN_SSL_CONNECTION; } else { if ($Net::SSLhello::trace == 0) { # no trace => shorten the output $input =~ /^(.+?)(?:\r?\n|$)/; # maximal 1 line of error message $input = $1; # if (($startType == x) || () ....) { $input = hexString ($input) } # } $my_error = "STARTTLS (Phase 1): Did *NOT* get a ".$starttls_matrix[$starttlsType][0]." Server Ready Message from $host:$port; target ignored. Server-Error: >"._chomp_r($input)."<"; # error message received from the server _trace2 ("openTcpSSLconnection: $my_error\n"); close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; # next retry } } } else { $my_error = ("STARTTLS (Phase 1): Did *NOT* get any ".$starttls_matrix[$starttlsType][0]." message from $host:$port -> slow down and try to retry target."); _trace ("openTcpSSLconnection: $my_error\n"); $Net::SSLhello::starttlsDelay = $sleepSecs; # adopt global variable 1 step later $sleepSecs += $retryCnt + 2; close ($socket) or carp("**WARNING: openTcpSSLconnection: STARTTLS: $my_error; Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; } } else { _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 1): Nothing to do for ".$starttls_matrix[$starttlsType][0]."\n"); } # end-if $starttls_matrix[$starttlsType][1] ### STARTTLS_Phase2 (send) ##### if ($starttls_matrix[$starttlsType][2]) { local $@ = ""; eval { _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 2): send $starttls_matrix[$starttlsType][0] Message: >"._chomp_r($starttls_matrix[$starttlsType][2])."<\n"); local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); # set Alarm for Connect defined(send($socket, $starttls_matrix[$starttlsType][2], 0)) || die "Could *NOT* send $starttls_matrix[$starttlsType][0] message '$starttls_matrix[$starttlsType][2]' to $host:$port; target ignored\n"; alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "STARTTLS phase #2 failed): $@"; # save the error message as soon as possible alarm (0); # clear alarm if not done before _trace2 ("openTcpSSLconnection: $my_error\n"); close ($socket) or carp("**WARNING: openTcpSSLconnection: $my_error Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; # next retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before # wait before next read # select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($sleepSecs > 0) || ($retryCnt > 0); # if slowed down or retry: sleep some ms osaft::osaft_sleep (_SLEEP_B4_2ND_READ) if ($sleepSecs > 0) || ($retryCnt > 0); # if slowed down or retry: sleep some ms # select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($retryCnt > 1); # if retry: sleep some ms osaft::osaft_sleep (_SLEEP_B4_2ND_READ) if ($retryCnt > 1); # if retry: sleep some ms ### STARTTLS_Phase1 (receive) } else { _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 2): Nothing to do for ".$starttls_matrix[$starttlsType][0]."\n"); } # end-if $starttls_matrix[$starttlsType][2] ### STARTTLS_Phase3: receive (SMTP) Hello Answer if ($starttls_matrix[$starttlsType][3]) { local $@ = ""; eval { $input = ""; _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 3): try to receive the $starttls_matrix[$starttlsType][0] Hello Answer from the Server $host:$port\n"); osaft::osaft_sleep (_SLEEP_B4_2ND_READ) if ($retryCnt > 0); # if retry: sleep some ms # select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($retryCnt > 0); # if retry: sleep some ms local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); recv ($socket, $input, 32767, 0); alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "STARTTLS phase #3 failed): $@"; # save the error message as soon as possible alarm (0); # clear alarm if not done before next RETRY_TO_OPEN_SSL_CONNECTION; # Error -> next retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before if (length ($input) >0) { # received Data => 250-smtp.server.com Hello o-saft.localhost? _trace3 ("openTcpSSLconnection: ## STARTTLS (Phase 3): ... Received $starttls_matrix[$starttlsType][0]-Hello: ".length($input)." bytes\n >".substr(_chomp_r($input),0,64)." ...<\n"); _trace4 ("openTcpSSLconnection: ## STARTTLS (Phase 3): ... Received $starttls_matrix[$starttlsType][0]-Hello: ".length($input)." bytes\n >"._chomp_r($input)."<\n"); if ($input =~ /$starttls_matrix[$starttlsType][3]/) { # e.g. SMTP: 250-smtp.server.com Hello o-saft.localhost $my_error = ""; # server is ready _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 3): received a $starttls_matrix[$starttlsType][0] Hello Answer from the Server $host:$port: >"._chomp_r($input)."<\n"); } else { $input=_chomp_r($input); if ( ($starttls_matrix[$starttlsType][6]) && ($input =~ /$starttls_matrix[$starttlsType][6]/) ) { # did receive a temporary Error Message if ($retryCnt > $Net::SSLhello::retry) { # already an additional final retry -> restore last error message $my_error = "STARTTLS (Phase 3): Error 1: too many requests: $host:$port \'$input\' -> too many retries ($retryCnt)"; last RETRY_TO_OPEN_SSL_CONNECTION; } $Net::SSLhello::starttlsDelay = $sleepSecs; # adopt global variable 1 step later $sleepSecs += $retryCnt + 2; $suspendSecs= 60 * ($retryCnt +1); $my_error = "STARTTLS (Phase 3): Error 1: too many requests: $host:$port \'$input\' -> suspend $suspendSecs second(s) and all subsequent packets will be slowed down by $sleepSecs second(s)"; _trace2 ("openTcpSSLconnection: $my_error\n"); carp ("**WARNING: openTcpSSLconnection: ... $my_error"); # if ($retryCnt > 1); # warning if at least 2nd retry close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); sleep($suspendSecs); _trace4 ("openTcpSSLconnection: STARTTLS (Phase 3): End suspend\n"); if ($retryCnt == $Net::SSLhello::retry) { # signal to do an additional retry $retryCnt++; _trace4 ("openTcpSSLconnection: STARTTLS (Phase 3): 1 additional final retry after too many requests => retry number $retryCnt represented by $retryCnt+1\n"); } next RETRY_TO_OPEN_SSL_CONNECTION; } elsif ( ($starttls_matrix[$starttlsType][7]) && ($input =~ /$starttls_matrix[$starttlsType][7]/) ) { # did receive a protocol error message OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'STARTTLS (Phase 3): Error 2', message => "unsupported protocol: $host:$port \'$input\'", warn => 0, } ); close ($socket) or carp("**WARNING: ". OSaft::error_handler->get_err_str() ."; Can't close socket, too: $!"); last RETRY_TO_OPEN_SSL_CONNECTION; } elsif ( ($starttls_matrix[$starttlsType][8]) && ($input =~ /$starttls_matrix[$starttlsType][8]/) ) { # did receive a fatal error message $my_error = "STARTTLS (Phase 3): Error 3: Fatal Error: $host:$port \'$input\' -> target $host:$port ignored"; _trace2 ("openTcpSSLconnection: $my_error\n"); close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); last RETRY_TO_OPEN_SSL_CONNECTION; } else { if ($Net::SSLhello::trace == 0) { # no trace => shorten the output $input =~ /^(.+?)(?:\r?\n|$)/x; # maximal 1 line of error message $input = $1; # if (($startType == x) || () ....) { $input = hexString ($input) } # } $my_error = "STARTTLS (Phase 3): Did *NOT* get a $starttls_matrix[$starttlsType][0] Server Hello Answer from $host:$port; target ignored. Server-Error: >"._chomp_r($input)."<"; # error message received from the SMTP-Server _trace2 ("openTcpSSLconnection: $my_error; try to retry\n"); close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; } } } else { # did receive a message with length = 0 ?! $my_error = ("STARTTLS (Phase 3): Did *NOT* get any answer to".$starttls_matrix[$starttlsType][0]." client message from $host:$port -> slow down and try to retry target."); _trace ("openTcpSSLconnection: $my_error\n"); $Net::SSLhello::starttlsDelay = $sleepSecs; # adopt global variable 1 step later $sleepSecs += $retryCnt + 2; close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; # next retry } } else { _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 3): Nothing to do for ".$starttls_matrix[$starttlsType][0]."\n"); } # end-if $starttls_matrix[$starttlsType][3] #### STARTTLS_Phase4: Do STARTTLS if ($starttls_matrix[$starttlsType][4]) { local $@ = ""; eval { _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 4): $starttls_matrix[$starttlsType][0] Do STARTTLS message: >"._chomp_r($starttls_matrix[$starttlsType][4])."<\n"); local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($Net::SSLhello::timeout); # set Alarm for Connect defined(send($socket, $starttls_matrix[$starttlsType][4], 0)) || die "Could *NOT* send a STARTTLS message to $host:$port; target ignored\n"; alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "STARTTLS phase #4 failed): $@"; # save the error message as soon as possible alarm (0); # clear alarm if not done before _trace2 ("openTcpSSLconnection: $my_error\n"); close ($socket) or carp("**WARNING: openTcpSSLconnection: ## $my_error Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; # next retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; # wait before next read osaft::osaft_sleep (_SLEEP_B4_2ND_READ) if ($sleepSecs > 0) || ($retryCnt > 0); # if slowed down or retry: sleep some ms # select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($sleepSecs > 0) || ($retryCnt > 0); # if slowed down or retry: sleep some ms osaft::osaft_sleep (_SLEEP_B4_2ND_READ) if ($retryCnt > 1); # if retry: sleep some ms # select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($retryCnt > 1); # if retry: sleep some ms } else { _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 4): Nothing to do for ".$starttls_matrix[$starttlsType][0]."\n"); } # endi-if $starttls_matrix[$starttlsType][4] #### STARTTLS_Phase 5: receive STARTTLS answer if ($starttls_matrix[$starttlsType][5]) { local $@ = ""; eval { $input = ""; _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 5): Try to receive the $starttls_matrix[$starttlsType][0] STARTTLS answer from the server $host:$port\n"); osaft::osaft_sleep (_SLEEP_B4_2ND_READ) if ($retryCnt > 0); # if retry: sleep some ms # select(undef, undef, undef, _SLEEP_B4_2ND_READ) if ($retryCnt > 0); # if retry: sleep some ms local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); recv ($socket, $input, 32767, 0); alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "STARTTLS phase #5 failed): $@"; # save the error message as soon as possible alarm (0); # clear alarm if not done before next RETRY_TO_OPEN_SSL_CONNECTION; # Error -> next retry }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # clear alarm if not done before if (length ($input) >0) { # received Data => 220 _trace3 ("openTcpSSLconnection: ## STARTTLS (Phase 5): ... Received STARTTLS-Answer: ".length($input)." bytes\n >".substr(_chomp_r($input),0,64)." ...<\n"); _trace4 ("openTcpSSLconnection: ## STARTTLS (Phase 5): ... Received STARTTLS-Answer: ".length($input)." bytes\n >"._chomp_r($input)."<\n"); if ($input =~ /$starttls_matrix[$starttlsType][5]/) { # e.g. SMTP: 220 $my_error = ""; # server is ready to do SSL/TLS _trace2 ("openTcpSSLconnection: ## STARTTLS: Server is ready to do SSL/TLS\n"); } else { $input=_chomp_r($input); if ( ($starttls_matrix[$starttlsType][6]) && ($input =~ /$starttls_matrix[$starttlsType][6]/) ) { # did receive a temporary error message if ($retryCnt > $Net::SSLhello::retry) { # already an additional final retry -> restore last error message $my_error = "STARTTLS (Phase 5): Error 1: Too many requests: $host:$port \'$input\' -> suspend $suspendSecs second(s) and all subsequent packets will be slowed down by $sleepSecs second(s)"; last RETRY_TO_OPEN_SSL_CONNECTION; } $Net::SSLhello::starttlsDelay = $sleepSecs; # adopt global Variable 1 step later $sleepSecs += $retryCnt + 2; $suspendSecs = 60 * ($retryCnt +1); $my_error = "STARTTLS (Phase 5): Error 1: Too many requests: $host:$port \'$input\' -> suspend $suspendSecs second(s) and all subsequent packets will be slowed down by $sleepSecs second(s)"; _trace2 ("openTcpSSLconnection: $my_error\n"); carp ("**WARNING: openTcpSSLconnection: ... $my_error"); # if ($retryCnt > 1); # warning if at least 2nd retry close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); sleep($suspendSecs); _trace4 ("openTcpSSLconnection: STARTTLS (Phase 5): End suspend\n"); if ($retryCnt == $Net::SSLhello::retry) { # signal to do an additional retry $retryCnt++; _trace4 ("openTcpSSLconnection: STARTTLS (Phase 5): 1 additional final retry after too many requests => retry number $retryCnt represented by $retryCnt+1\n"); } next RETRY_TO_OPEN_SSL_CONNECTION; } elsif ( ($starttls_matrix[$starttlsType][7]) && ($input =~ /$starttls_matrix[$starttlsType][7]/) ) { # did receive a protocol error message OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'STARTTLS (Phase 5): Error 2', message => "unsupported protocol: $host:$port \'$input\'", warn => 0, } ); close ($socket) or carp("**WARNING: ". OSaft::error_handler->get_err_str() ."; Can't close socket, too: $!"); last RETRY_TO_OPEN_SSL_CONNECTION; } elsif ( ($starttls_matrix[$starttlsType][8]) && ($input =~ /$starttls_matrix[$starttlsType][8]/) ) { # did receive a Fatal Error Message $my_error = "STARTTLS (Phase 5): Error 3: Fatal Error: $host:$port \'$input\' -> target $host:$port ignored"; _trace2 ("openTcpSSLconnection: $my_error\n"); close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); last RETRY_TO_OPEN_SSL_CONNECTION; } else { if ($Net::SSLhello::trace == 0) { # no trace => shorten the output $input =~ /^(.+?)(?:\r?\n|$)/x; # maximal 1 line of error message $input = $1; # if (($startType == x) || () ....) { $input = hexString ($input) } # } $my_error = "STARTTLS (Phase 5): Did *NOT* get a server SSL/TLS confirmation from $host:$port (retry: $retryCnt); target ignored. Server-Error: >"._chomp_r($input)."<"; # error message received from the SMTP-Server _trace2 ("openTcpSSLconnection: ## $my_error; try to retry;\n"); close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; } } } else { # did not receive a message $my_error = ("STARTTLS (Phase 5): Did *NOT* get any answer to".$starttls_matrix[$starttlsType][0]." STARTTLS request from $host:$port -> slow down and try to retry target."); _trace ("openTcpSSLconnection: $my_error\n"); $Net::SSLhello::starttlsDelay = $sleepSecs; # adopt global variable 1 step later $sleepSecs += $retryCnt + 2; close ($socket) or carp("**WARNING: STARTTLS: $my_error; Can't close socket, too: $!"); next RETRY_TO_OPEN_SSL_CONNECTION; # next retry } } else { _trace2 ("openTcpSSLconnection: ## STARTTLS (Phase 5): Nothing to do for ".$starttls_matrix[$starttlsType][0]."\n"); } # end-if $starttls_matrix[$starttlsType][5] } ############### End STARTTLS Support ################## } while ( ($my_error) && ( ($retryCnt++ < $Net::SSLhello::retry) || ($retryCnt == $Net::SSLhello::retry + 2) ) ); } # 1 Extra retry if $retryCnt++ == $Net::SSLhello::retry +2 if ($my_error) { #Error chomp($my_error); carp ("**WARNING: openTcpSSLconnection: $my_error"); _trace2 ("openTcpSSLconnection: Exit openTcpSSLconnection }\n"); return (undef); } alarm (0); # race condition protection _trace2 ("openTcpSSLconnection: Connected to '$host:$port'\n"); return ($socket); } # openTcpSSLconnection sub _doCheckSSLciphers ($$$$;$$) { #? simulate SSL handshake to check any ciphers by the HEX value #? called by checkSSLciphers to check some ciphers by the call #? if $parseAllRecords==0: solely the ServerHello is parsed to get the selected cipher from the server #? if $parseAllRecords >0: All other messages are received up to ServerHelloDone: #? Certificate: not parsed in detail yet #? ServerKeyExchange: optional message, parsed (if DH, ECDH or EXPORT-RSA Ciphers are used) #? CertificateRequest: not parsed in detaili yet #? ServerHelloDone: parsed (as trigger to end this function) #? $cipher_spec: RAW octets according to RFC # my $host = shift || ""; # hostname my $port = shift || 443; my $protocol = shift || 0; # 0x0002, 0x3000, 0x0301, 0x0302, 0x0303, etc my $cipher_spec = shift || ""; my $dtls_epoch = shift || 0; # optional, used in DTLS only my $parseAllRecords = shift || 0; # option to read, parse and analyze all received records (-> 1) my $socket; my $connect2ip; my $proxyConnect = ""; my $clientHello = ""; my $input=""; my $input2=""; ### my $pduLen=0; my $v2len=0; ### my $v2type=0; ### my $v3len=0; ### my $v3type=0; ### my $v3version=0; ### my ($recordType, $recordVersion, $recordLen, $recordEpoch, $recordSeqNr) = (0,0,0,0,0); my $recordData = ""; my $acceptedCipher=""; my $retryCnt = 0; my $firstMessage = ""; my $secondMessage = ""; my $segmentCnt=0; my $dtlsSequence = 0; my $dtlsCookieLen = 0; my $dtlsCookie = ""; my $dtlsNewCookieLen = 0; my $dtlsNewCookie = ""; my $alarmTimeout = $Net::SSLhello::timeout +1; # 1 sec more than normal timeout as a time line of second protection my $isUdp = 0; # for DTLS my $buffer = ""; my $lastMsgType = $HANDSHAKE_TYPE {'<>'}; # undefined message type my $lastRecordType = $RECORD_TYPE {'<>'}; # undefined record type my %rhash = reverse %PROTOCOL_VERSION; my $ssl = $rhash{$protocol}; if (! defined $ssl) { $ssl = "--unknown protocol--"; } _trace4 (sprintf ("_doCheckSSLciphers ($host, $port, $ssl: >0x%04X<\n >",$protocol).hexCodedString ($cipher_spec," ") .") {\n"); local $my_error = ""; # reset error message OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => '_doCheckSSLciphers', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); $isUdp = ( (($protocol & 0xFF00) == $PROTOCOL_VERSION{'DTLSfamily'}) || ($protocol == $PROTOCOL_VERSION{'DTLSv09'}) ); # udp for DTLS1.x or DTLSv09 (OpenSSL pre 0.9.8f) unless ($isUdp) { # NO UDP = TCP #### Open TCP connection (direct or via a proxy) and do STARTTLS if requested $socket=openTcpSSLconnection ($host, $port); # open TCP/IP, connect to the server (via proxy if needes) and STARTTLS if nedded if ( (!defined ($socket)) || (OSaft::error_handler->is_err()) || ($@) ) { # no SSL connection if ((OSaft::error_handler->get_err_type) == OERR_SSLHELLO_RETRY_HOST) { # no more retries OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_HOST), # warn => 1, } ); } unless (OSaft::error_handler->is_err) { # no error set, but no socket obtaied OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_HOST), id => 'open TCP SSL connection (1)', message => "WARNING: Did not get a valid SSL-socket from function openTcpSSLconnection -> fatal exit of openTcpSSLconnection", # generic error message # warn => 1, } ); } return (""); } } else { # udp (no proxy nor STARTTLS) if ( defined($Net::SSLhello::connect_delay) && ($Net::SSLhello::connect_delay > 0) ) { _trace_ ("\n"); _trace ("_doCheckSSLciphers (udp): connect delay $cfg{'connect_delay'} second(s)\n"); sleep($Net::SSLhello::connect_delay); _trace4 ("_doCheckSSLciphers (udp): connect delay $cfg{'connect_delay'} second(s) [End]\n"); } { # >> start a block $my_error = ""; $socket = IO::Socket::INET->new ( Proto => "udp", PeerAddr => "$host:$port", Timeout => $Net::SSLhello::timeout, #Blocking => 1, #Default ) or $my_error = " \'$@\', \'$!\'"; if ( (!defined ($socket)) || ($my_error) ) { # no UDP socket OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_HOST), id => 'open UDP socket (1)', message => "WARNING: Did not get a valid socket for UDP: $my_error -> fatal exit of _doCheckSSLciphers (udp)", # warn => 1, } ); return (""); } } # << end a block _trace4 ("_doCheckSSLciphers: ## New UDP socket to >$host:$port<\n"); } # end udp socket $retryCnt = 0; $my_error = ""; # reset error message RETRY_TO_EXCHANGE_CLIENT_AND_SERVER_HELLO: while ($retryCnt++ < $Net::SSLhello::retry) { # no error and still retries to go #### compile ClientHello $clientHello = compileClientHello ($protocol, $protocol, $cipher_spec, $host, $dtls_epoch, $dtlsSequence++, $dtlsCookieLen, $dtlsCookie); #### send ClientHello _trace3 ("_doCheckSSLciphers: sending Client_Hello\n >".hexCodedString(substr($clientHello,0,64)," ")." ...< (".length($clientHello)." bytes)\n\n"); _trace4 ("_doCheckSSLciphers: sending Client_Hello\n >".hexCodedString ($clientHello," ")."< (".length($clientHello)." bytes)\n\n"); local $@ = ""; eval { local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); # set alarm for connect defined(send($socket, $clientHello, 0)) || die "Could *NOT* send ClientHello to $host:$port; $! -> target ignored\n"; alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "send client hello failed: $@"; # save the error message as soon as possible alarm (0); # protection against race conditions OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_HOST), id => 'send client hello failed', message => $my_error, warn => 0, } ); return (""); }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # protection against race conditions ###### receive the answer (SSL+TLS: ServerHello, DTLS: Hello Verify Request or ServerHello) ###### Errors are reported in local $my_error ($input, $recordType, $recordVersion, $recordLen, $recordData, $recordEpoch, $recordSeqNr, $my_error) = _readRecord ($socket, $isUdp, $host, $port, $protocol); # error handling if ((OSaft::error_handler->get_err_type()) <= (OERR_SSLHELLO_RETRY_PROTOCOL)) { if ((OSaft::error_handler->get_err_type()) == (OERR_SSLHELLO_RETRY_HOST)) { # no more retries OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_HOST), # upgrade error to abort # warn => 1, } ); } _trace ("**WARNING: ".OSaft::error_handler->get_err_str."\n"); return (""); } if ( ($my_error) && ((length($input)==0) && ($Net::SSLhello::noDataEqNoCipher==0)) ) { _trace2 ("_doCheckSSLciphers: ... Received Data: Got a timeout receiving Data from $host:$port (protocol: $ssl ".sprintf ("(0x%04X)",$protocol).", ".length($input)." bytes): Eval-Message: >$my_error<\n"); carp ("**WARNING: _doCheckSSLciphers: ... Received Data: Got a timeout receiving Data from $host:$port (protocol: $ssl ".sprintf ("(0x%04X)",$protocol).", ".length($input)." bytes): Eval-Message: >$my_error<\n"); return (""); } elsif (length($input) ==0) { # len == 0 without any timeout $my_error= "... Received NO Data from $host:$port (protocol: $ssl ".sprintf ("(0x%04X)",$protocol).") after $Net::SSLhello::retry retries; This may occur if the server responds by closing the TCP connection instead with an Alert. -> Received NO Data"; _trace2 ("_doCheckSSLciphers: $my_error\n"); return (""); } elsif ($my_error) { # any other error _trace2 ("_doCheckSSLciphers: Error-Message: $my_error\n"); return (""); } _trace2("_doCheckSSLciphers: Server '$host:$port': (protocol $ssl [".sprintf ("0x%04X", $protocol)."], (record) type $recordType: received a record with ".length($recordData)." bytes payload (recordData) >".hexCodedString (substr($recordData,0,48)," ")."< ...) \n"); if ($recordVersion <= 0) { # got no SSL/TLS/DTLS-PDU # Try to read the whole input buffer ($input, $my_error) = _readText ($socket, $isUdp, $input, ""); if ($Net::SSLhello::starttls) { if ($input =~ /(?:^|\s)554(?:\s|-)security.*?$/ix) { # 554 Security failure; TBD: perhaps more general in the future _trace2 ("_doCheckSSLciphers ## STARTTLS: received SMTP Reply Code '554 Security failure': (Is the STARTTLS command issued within an existing TLS session?) -> input ignored and try to Retry\n"); # retry to send clientHello $my_error = ""; # reset error message $input = ""; # reset input data $pduLen=0; next; # retry to send and receive a SSL/TLS or DTLS-Packet } } elsif ($input =~ /(?:^|\s)220(?:\s|-).*?$/x) { # service might need STARTTLS $my_error= "**WARNING: _doCheckSSLciphers: $host:$port looks like an SMTP-Service, probably the option '--starttls' is needed -> target ignored\n"; carp ($my_error); return (""); } $my_error = "**WARNING: _doCheckSSLciphers: $host:$port dosen't look like a SSL or a SMTP-Service (1) -> Received data ignored -> target ignored\n"; carp ($my_error); _trace_ ("\n") if ($retryCnt <=1); _trace ("_doCheckSSLciphers: Ignored data: ".length($input)." bytes\n >".hexCodedString($input," ")."<\n >"._chomp_r($input)."<\n"); $input = ""; $pduLen = 0; return (""); } if (length($input) >0) { _trace2 ("_doCheckSSLciphers: Total data received: ". length($input). " bytes\n"); ($acceptedCipher, $lastMsgType, $dtlsNewCookieLen, $dtlsNewCookie) = parseHandshakeRecord ($host, $port, $recordType, $recordVersion, $recordLen, $recordData, "", $protocol); if ((OSaft::error_handler->get_err_type()) <= (OERR_SSLHELLO_RETRY_PROTOCOL)) { if ((OSaft::error_handler->get_err_type()) == (OERR_SSLHELLO_RETRY_HOST)) { # no more retries OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_HOST), # warn => 1, } ); } _trace ("**WARNING: ".OSaft::error_handler->get_err_str."\n"); return (""); } if ( ($acceptedCipher ne "") && ($parseAllRecords > 0) && ($lastMsgType != $HANDSHAKE_TYPE {'server_hello_done'}) ) { _trace2 ("_doCheckSSLciphers: Try to get and parse next records\n"); while ( (length($input) >0) && ($lastMsgType != $HANDSHAKE_TYPE {'server_hello_done'}) ) { ###### receive next record _trace2 ("_doCheckSSLciphers: receive next record\n"); $input = ""; ($input, $recordType, $recordVersion, $recordLen, $recordData, $recordEpoch, $recordSeqNr, $my_error) = _readRecord ($socket, $isUdp, $host, $port, $protocol); last if ( (length($input)==0) || ($my_error) ); if ( ($lastMsgType == $HANDSHAKE_TYPE {'<>'}) && ($recordType == $lastRecordType) ) { # last message was fragmented $recordData = $buffer.$recordData; $recordLen += length($buffer); _trace4 ("_doCheckSSLciphers: recompiled fragmented message -> compiled RecordLen: $recordLen\n"); } # parse the next record (no cipher expected...) ($buffer, $lastMsgType, $dtlsNewCookieLen, $dtlsNewCookie) = parseHandshakeRecord ($host, $port, $recordType, $recordVersion, $recordLen, $recordData, $acceptedCipher, $protocol); # get more information received together with the accepted cipher $lastRecordType = $recordType; # only used for fragmented messages } } if ( ($acceptedCipher ne "") || (! $isUdp) ) { last; } if ($my_error ne "") { _trace4 ("_doCheckSSLciphers: Exit with Error: '$my_error'\n"); return (""); } if ( ($dtlsNewCookieLen > 0) && $isUdp) { $dtlsCookieLen = $dtlsNewCookieLen; $dtlsCookie = $dtlsNewCookie; $dtlsNewCookieLen = 0; $dtlsNewCookie = ""; _trace2 ("_doCheckSSLciphers: received a cookie ($dtlsCookieLen bytes): >".hexCodedString($dtlsCookie," ")."<\n"); $retryCnt--; } _trace4 ("_doCheckSSLciphers: DTLS: sleep "._DTLS_SLEEP_AFTER_NO_CIPHERS_FOUND." sec(s) after *NO* cipher found\n"); osaft::osaft_sleep (_DTLS_SLEEP_AFTER_NO_CIPHERS_FOUND); # sleep after NO cipher found # select(undef, undef, undef, _DTLS_SLEEP_AFTER_NO_CIPHERS_FOUND); # sleep after NO cipher found } } # end while (RETRY_TO_EXCHANGE_CLIENT_AND_SERVER_HELLO) if ($isUdp) { # reset DTLS connection using an alert record local $@ = ""; eval { local $SIG{ALRM}= "Net::SSLhello::_timedOut"; my $level = 2; #fatal my $description = 90; #### selected alert 90: user_canceled [RFC5246] alarm($alarmTimeout); # set alarm for connect defined(send($socket, compileAlertRecord ($protocol, $host, $level, $description, $dtls_epoch, $dtlsSequence++), 0)) || die "Could *NOT* send an alert record to $host:$port; $! -> Error ignored\n"; alarm (0); } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "reset DTLS failed: $@"; # save the error message as soon as possible alarm (0); # protection against race conditions OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_PROTOCOL), id => 'reset DTLS failed', message => $my_error, warn => 0, } ); # carp ("_doCheckSSLciphers: $my_error"); return (""); }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # protection against race conditions } unless ( close ($socket) ) { carp("**WARNING: _doCheckSSLciphers: Can't close socket: $!"); } if (($isUdp) && (defined ($acceptedCipher) ) && ($acceptedCipher ne "") ) { _trace4 ("_doCheckSSLciphers: DTLS: sleep "._DTLS_SLEEP_AFTER_FOUND_A_CIPHER." sec(s) after received cipher >".hexCodedCipher($acceptedCipher)."<\n"); # select(undef, undef, undef, _DTLS_SLEEP_AFTER_FOUND_A_CIPHER); osaft::osaft_sleep ( _DTLS_SLEEP_AFTER_FOUND_A_CIPHER); } _trace2 ("_doCheckSSLciphers: }\n"); return ($acceptedCipher); } # _doCheckSSLciphers ############################################################ sub _readRecord ($$;$$$$) { #? receive the answers: # Handshake: # 1) SSL+TLS: ServerHello, DTLS: Hello Verify Request or ServerHello # 2) Certificate # 3) Server Key Exchange (kEDH, kEECDH and ADH only) # 4) Client Certificate Request (optional) # 5) Server Hello Done # # or Error Messages # my $socket = shift || ""; my $isUdp = shift || 0; my $host = shift || ""; # for warn- and trace-messages my $port = shift || ""; # for warn- and trace-messages my $client_protocol = shift || -1; # optional my $MAXLEN = 16384; # according RFC 5246: 16384 bytes for the packetData (without the packet header) my $pduLen = 0; # no PDUlen detected, yet my $readLen = ($isUdp) ? $MAXLEN : 7; # minimum len is: # all readable octetts for UDP (-> MAXLEN), # 7 octetts for TCP (=len of an alert message); # remark rk: the minimum record len is 5 bytes, but it is better to # read 7 bytes to get a compete alert message before any # disconnects can occure #### was: $MAXLEN; # read up to MAXLEN Octetts my $len = 0; my $recordType = 0; my $recordVersion = 0; my $recordEpoch = 0; my $recordSeqNr_null= 0; # (0x0000) my $recordSeqNr = 0; my $my_error = ""; my $recordLen = 0; my $recordData = ""; my $recordHeaderLen = 0; my ($rin, $rout); my $alarmTimeout = $Net::SSLhello::timeout +1; # 1 sec more than normal timeout as a time line of second protection$ my $retryCnt = 0; my $segmentCnt = 0; my $input = ""; my $input2 = ""; my @socketsReady = (); require IO::Select if ($Net::SSLhello::trace > 0); my $select; #used for tracing only $select = IO::Select->new if ($Net::SSLhello::trace > 0); my $success=0; $select->add($socket) if ($Net::SSLhello::trace > 0); #reset error_handler and set basic information for this sub OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => '_readRecord', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); ###### receive the answer (SSL+TLS: ServerHello, DTLS: Hello Verify Request or ServerHello) vec($rin = '',fileno($socket),1 ) = 1; # mark SOCKET in $rin RETRY_TO_RECEIVE_A_RECORD: while ( ( (length($input) < $pduLen) || ($input eq "") ) && ($retryCnt++ <= $Net::SSLhello::retry) ) { if ($isUdp) { # #still use select for udp $my_error = ""; local $@ = ""; eval { # check this for timeout, protect it against an unexpected exit of the program # set alarm and timeout local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); # opimized with reference to 'https://github.com/noxxi/p5-ssl-tools/blob/master/check-ssl-heartbleed.pl' $success = select($rout = $rin,undef,undef,$Net::SSLhello::timeout); alarm (0); #clear alarm } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "failed to select data: $@"; # save the error message as soon as possible alarm (0); # clear alarm if not done before OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_CIPHERS), id => '_readRecord (udp): unknown Timeout error (1)', message => $my_error, warn => 0, } ); carp ("_readRecord (udp): $my_error"); _trace4 ("_readRecord (udp) from Server '$host:$port' -> LAST: Received (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($input)." bytes (from $pduLen expected) after $retryCnt tries:\n"); last RETRY_TO_RECEIVE_A_RECORD; }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # protection against race conditions if ( ! $success) { # nor data NEITHER special event => timeout OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_CIPHERS), id => '_readRecord (udp): Timeout error (1)', message => $my_error, warn => 0, } ); _trace4 ("_readRecord (udp): Server '$host:$port' -> Timeout (received nor data NEITHER special event) while reading a record with".length($input)." bytes (from $pduLen expected) after $retryCnt tries:\n"); last RETRY_TO_RECEIVE_A_RECORD; # resend the UDP packet } if (vec($rout, fileno($socket),1)) { # got data local $@ = ""; eval { # check this for timeout, protect it against an unexpected exit of the program # set alarm and timeout local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); @socketsReady = $select->can_read(0) if ($Net::SSLhello::trace > 3); ###additional debug (use IO::select needed) _trace4 ("_readRecord (udp): can read (1): (Segement: $segmentCnt, retry: $retryCnt, position: ".length($input)." bytes)\n") if (scalar (@socketsReady)); $success = sysread ($socket, $input, $readLen - length($input), length($input)); #if NO success: EOF or other Error while reading Data alarm (0); #clear alarm } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "failed to read data with sysread: $@"; # save the error message as soon as possible alarm (0); # clear alarm if not done before OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_CIPHERS), id => '_readRecord (udp): unknown Timeout error (2)', message => $my_error, warn => 0, } ); carp ("_readRecord (udp): $my_error"); _trace4 ("_readRecord (udp) -> LAST: Received (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($input)." bytes (from $pduLen expected) after $retryCnt tries:\n"); last RETRY_TO_RECEIVE_A_RECORD; # resend the UDP packet }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # protection against race conditions @socketsReady = $select->can_read(0) if ($Net::SSLhello::trace > 3); ###additional debug (use IO::select needed) _trace4 ("_readRecord (udp) can read (2): (Segement: $segmentCnt, retry: $retryCnt, position: ".length($input)." bytes)\n") if (scalar (@socketsReady)); if (! $success ) { # EOF or other Error while reading Data if (length ($input) == 0) { # Disconnected, no Data $my_error = "Server '$host:$port': received EOF (Disconnect), no Data\n"; OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_CIPHERS), id => '_readRecord (udp): no Data', message => $my_error, warn => 0, } ); _trace4 ("_readRecord (udp) : $my_error\n"); last RETRY_TO_RECEIVE_A_RECORD; } else { $my_error = "Server '$host:$port': No data (EOF) after ".length($input)." of expected $pduLen bytes: '$!' -> Retry to read\n"; OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_CIPHERS), id => '_readRecord (udp): EOF', message => $my_error, warn => 0, } ); _trace1 ("_readRecord (udp): $my_error\n"); @socketsReady = $select->can_read(0) if ($Net::SSLhello::trace > 1); ###additional debug (use IO::select needed) _trace1 ("_readRecord (udp): can read (3): (Segement: $segmentCnt, retry: $retryCnt, position: ".length($input)." bytes)\n") if (scalar (@socketsReady)); #select (undef, undef, undef, _SLEEP_B4_2ND_READ); osaft::osaft_sleep (_SLEEP_B4_2ND_READ); next RETRY_TO_RECEIVE_A_RECORD; } } } else {# got NO data $my_error = "Server '$host:$port': No data in _readRecord after reading $len of $pduLen expected bytes; $!"; OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_CIPHERS), id => '_readRecord (udp): Received (no more) data', message => $my_error, warn => 0, } ); _trace1 ("_readRecord (udp): ... Received data: $my_error\n"); _trace4 ("_readRecord (udp) :-> LAST: Received (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($input)." bytes (from $pduLen expected) after $retryCnt tries:\n"); last RETRY_TO_RECEIVE_A_RECORD; } ### End got Data } else { # TCP local $@ = ""; eval { # check this for timeout, protect it against an unexpected exit of the program # set alarm and timeout local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); _trace4 ("_readRecord (tcp): try to recv (1): (Segement: $segmentCnt, retry: $retryCnt, position: ".length($input)." bytes)\n"); $success = recv ($socket, $input2, $readLen - length($input), 0); #if NO success: $success undefined alarm (0); #clear alarm } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "failed to receive data (recv) $@"; # save the error message as soon as possible alarm (0); # clear alarm if not done before OSaft::error_handler->new( { type => (OERR_SSLHELLO_RETRY_CIPHERS), id => '_readRecord (tcp): recv: unknown Timeout error', message => $my_error, warn => 0, } ); carp ("_readRecord (tcp): $my_error"); _trace4 ("_readRecord (tcp): recv -> LAST: Received (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($input)." bytes (from $pduLen expected) after $retryCnt tries:\n"); last RETRY_TO_RECEIVE_A_RECORD; }}; # End of the section 'or do { if () { ...'. Do NOT forget the; alarm (0); # protection against race conditions $input .= $input2; # append new input $success = length ($input2); # same usage as sysread _trace4 ("_readRecord (tcp): recv: (Segement: $segmentCnt, retry: $retryCnt, position: ".length($input)." bytes)\n"); } # End TCP $len = length($input); if ($success) { # got new data if ($pduLen == 0) { # no PduLen decoded, yet _trace4 ("_readRecord (tcp): Server '$host:$port': ... Received first $len bytes to detect PduLen\n"); if ( (! $isUdp) && ($len >= 5) ) { # try to get the pduLen of the SSL/TLS Pdu (=protocol aware length detection) # Check PDUlen; parse the first 5 bytes to check the len of the PDU (SSL3/TLS) ($recordType, #C (record_type) $recordVersion, #n (record_version) $recordLen, #n (record_len) ) = unpack("C n n", $input); # assuming to parse a SSLv3/TLS record, will be redone if it is SSLv2 if ( ($recordType < 0x80) && (($recordVersion & 0xFF00) == $PROTOCOL_VERSION{'SSLv3'} || $recordVersion == 0x0000) ) { #SSLv3/TLS (no SSLv2 or 'dummy-Version 0x0000' if recoord version is not supported by the server) _trace2_ (sprintf ( "# --> => SSL3/TLS record type: >%02X<):\n". "# --> record_version: >%04X<\n". "# --> record_len: >%04X<\n", $recordType, $recordVersion, $recordLen, )); # if ($serverHello{'record_type'} == $RECORD_TYPE {'handshake'}); $recordHeaderLen = 5; # record data starts at position 6 _trace2 ("_readRecord (tcp): Server '$host:$port': ... Received data: Expected SSLv3/TLS-PDU-Len:"); } else { # Check for SSLv2 (parse the Inpit again) ($recordLen, # n (V2Len > 0x8000) $recordType, # C = 0 ) = unpack("n C", $input); if ( ($recordLen > 0x8000) && (($recordType == $SSL_MT_SERVER_HELLO) || ($recordType == $SSL_MT_ERROR)) ) { # SSLv2 check $recordLen -= 0x8000; $recordHeaderLen = 2; # Message Data starts at position 3 $pduLen = $recordLen + $recordHeaderLen; $recordVersion = $PROTOCOL_VERSION{'SSLv2'}; # added the implicitely detected protocol _trace2 ("_readRecord (tcp): Server '$host:$port': ... Received data: Expected SSLv2-PDU-Len:"); } else { ### no SSL/TLS/DTLS PDU => Last $my_error = "no known SSL/TLS PDU type"; $recordType = 0; $recordVersion = 0; $recordLen = 0; _trace1 ("_readRecord (tcp): $my_error\n"); _trace4 ("_readRecord (tcp): -> LAST: received (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($input)." bytes (from $pduLen expected) after $retryCnt tries:\n"); last RETRY_TO_RECEIVE_A_RECORD; } } } elsif ( ($isUdp) && ($len >= 13) ) { # try to get the pduLen of the DTLS Pdu (=protocol aware length detection) # check PDUlen; parse the first 13 bytes to check the len of the PDU (DTLS) _trace2 ("_readRecord (udp): Server '$host:$port': Protocol: DTLS\n"); ($recordType, # C $recordVersion, # n $recordEpoch, # n $recordSeqNr_null, # n (0x0000) $recordSeqNr, # N $recordLen, # n ) = unpack ("C n n n N n", $input); _trace2_ (sprintf ( "# --> => DTLS record type: Handshake (%02X):\n". ### only for handshake records that we analyze, yet "# --> record_version: >%04X<\n". "# --> record_epoch: >%04X<\n". # n "# --> record_seqNr_null: >%04X<\n". # n (0x0000) "# --> record_seqNr: >%08X<\n". # N "# --> record_len: >%04X<\n", $recordType, $recordVersion, $recordEpoch, # n $recordSeqNr_null, # n (0x0000) $recordSeqNr, # N $recordLen, # n )); if ( ($recordType < 0x80) && ( (($recordVersion & 0xFF00) == $PROTOCOL_VERSION{'DTLSfamily'}) # DTLS || ($recordVersion == $PROTOCOL_VERSION{'DTLSv09'}) ) ) { # DTLS, or DTLSv09 (OpenSSL pre 0.9.8f) $recordHeaderLen = 13; # record data starts at position 14 _trace2 ("_readRecord (udp): Server '$host:$port': ... Received data: Expected DTLS-PDU-Len:"); } else { # isUdp is set, but no DTLS-Record recognized $my_error = "Server '$host:$port': no known DTLS PDU type -> unknown protocol"; _trace1 ("_readRecord (udp): $my_error\n"); _trace1 ("_readRecord (udp): -> LAST: Received (record) type $recordType, -version: ".sprintf ("(0x%04X)", $recordVersion)." with ".length($input)." bytes (from $recordLen expected) after $retryCnt tries: reset all the mentioned parameters to 0\n"); $recordType = 0; $recordVersion = 0; $recordLen = 0; $pduLen = 0; $recordHeaderLen = 0; last RETRY_TO_RECEIVE_A_RECORD; } } # end: if DTLS $pduLen = $recordLen + $recordHeaderLen; # check PDUlen = len + size of record header; _trace2_ (" $pduLen (including the SSL/TLS header)\n"); if ($recordLen > $MAXLEN) { # check the raw length without the specific size of the header _trace1 ("_readRecord: Server '$host:$port': Expected len of the SSL/TLS record ($recordLen) is higher than the maximum ($MAXLEN) -> cut at maximum length!"); carp ("_readRecord: Server '$host:$port': Expected len of the SSL/TLS record ($recordLen) is higher than the maximum ($MAXLEN) -> cut at maximum length!"); $pduLen += -$recordLen +$MAXLEN; # => MAXLEN + size of record header } $readLen = $pduLen; # read only pduLen Octetts (-> only by one record) $retryCnt = 0 if ($readLen > 0); # detection of the recordLen is no retry -> reset counter } else { $segmentCnt++; _trace4 ("_readRecord: Server '$host:$port': ... Received $len bytes in $segmentCnt segment(s)\n"); $retryCnt = 0 if ($segmentCnt <= _MAX_SEGMENT_COUNT_TO_RESET_RETRY_COUNT); # reset retry count to 0 (in next loop) } if (defined ($client_protocol)) { if ($client_protocol != $recordVersion) { my %rhash = reverse %PROTOCOL_VERSION; my $ssl_client = $rhash{$client_protocol}; my $ssl_server = $rhash{$recordVersion}; if (! defined $ssl_client) { $ssl_client = "--unknown protocol--"; } if (! defined $ssl_server) { $ssl_server = "--unknown protocol--"; } if ($recordVersion == 0) { # some servers respond with the dummy protocol '0x0000' if they do *not* support the requested protocol OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'check record protocol (1)', message => sprintf ("unsupported protocol $ssl_client (0x%04X) by $host:$port, answered with (0x%04X)", $client_protocol, $recordVersion), warn => 0, } ); } else { # unknown protocol OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'check record protocol (2)', message => sprintf ("unsupported protocol $ssl_client (0x%04X) by $host:$port, answered with $ssl_server (0x%04X)", $client_protocol, $recordVersion), warn => 0, } ); } return ($input, $recordType, $recordVersion, 0, "", $recordEpoch, $recordSeqNr); } } } } # end while if (!($my_error) && (length($input) < $pduLen) ) { # no error, but the loop did *NOT* get all data within the maximal retries $my_error = "Server '$host:$port': Overrun the maximal number of $retryCnt retries in _readRecord after reading $len of $pduLen expected bytes in the ". $segmentCnt . "th segment; $!"; _trace1 ("_readRecord ... Error receiving data: $my_error\n"); _trace4 ("_readRecord -> LAST: Received (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($input)." bytes (from $pduLen expected) after $retryCnt tries:\n"); } chomp ($my_error); if ($client_protocol >= 0) { _trace3("_readRecord: Server '$host:$port': (expected protocol= >".sprintf ("%04X", $client_protocol)."<,\n (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($input)." bytes >".hexCodedString (substr($input,0,48)," ")."< ...)\n"); } else { _trace4("_readRecord: Server '$host:$port': (any protocol, (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($input)." bytes\n Data=".hexCodedString ($input," ").")\n"); } ($recordData) = unpack ("x[$recordHeaderLen] a*", $input); # get recordData from input skipping the header if (length($recordData) != $recordLen) { _trace1 ("_readRecord: Server '$host:$port': (expected protocol= >".sprintf ("%04X", $client_protocol)."<, (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion) .": recordLen ".sprintf ("%04X",length($recordData))." is not equal to the expected value ".sprintf ("%04X",$recordLen). "\n"); carp ("_readRecord: Server '$host:$port': (expected protocol= >".sprintf ("%04X", $client_protocol)."<, (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion) .": recordLen ".sprintf ("%04X",length($recordData))." is not equal to the expected value ".sprintf ("%04X",$recordLen). "\n"); } return ($input, $recordType, $recordVersion, $recordLen, $recordData, $recordEpoch, $recordSeqNr, $my_error); } # _readRecord ############################################################### sub _readText ($;$) { #? receive the answer e. of a proxy or STARTTLS # my $socket = shift || ""; my $isUdp = shift || 0; my $input = shift || ""; # input that has been read before my $my_local_error = ""; my $untilFound = shift || ""; my $len = 0; my $MAXLEN= 32767; my $alarmTimeout = $Net::SSLhello::timeout +1; # 1 sec more than normal timeout as a time line of second protection my ($rin, $rout); my $input2 = ""; my $retryCnt = 0; # 1st read with up to 5 bytes will be not counted ###### receive the answer vec($rin = '',fileno($socket),1 ) = 1; # mark SOCKET in $rin RECEVICE_ANSWER: while ( ($untilFound) && ( ! m {\A$untilFound\Z}) ) {{ $my_local_error = ""; local $@ = ""; eval { # check this for timeout, protect it against an unexpected exit of the program # set alarm and timeout local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); # Opimized with reference to 'https://github.com/noxxi/p5-ssl-tools/blob/master/check-ssl-heartbleed.pl' if ( ! select($rout = $rin,undef,undef,$Net::SSLhello::timeout) ) { # Nor data NEITHER special event => Timeout alarm (0); #clear alarm $my_local_error = "Timeout in _readText $!"; last RECEVICE_ANSWER; } alarm (0); #clear alarm } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_local_error = "failed to select text: $@" }}; # End of the section 'or do { if () { ...'. Do NOT forget the; #$my_error .= $@; # save the error message as soon as possible alarm (0); # protection against race conditions if ($my_local_error) { $my_local_error = "_readText: unknown Timeout-Error (1): $my_error"; carp ("_readText: $my_local_error"); return ($input, $my_local_error); } if (vec($rout, fileno($socket),1)) { # got data local $@ = ""; eval { # check this for timeout, protect it against an unexpected exit of the program # set alarm and timeout local $SIG{ALRM}= "Net::SSLhello::_timedOut"; alarm($alarmTimeout); ## read only up to 5 bytes in the first round, then up to the expected pduLen recv($socket, $input2, $MAXLEN - length($input), 0 ); # EOF or other Error while reading data $input .= $input2; alarm (0); # clear alarm } or do { if ( ($@) or ($^O !~ m/MSWin32/) ) { # End of eval section, begin of an error section ('or do'), that works for Windows, too. $my_error = "failed to receice text: $@" }}; # End of the section 'or do { if () { ...'. Do NOT forget the; #$my_error .= $@; # save the error message as soon as possible alarm (0); # protection against race conditions if ($my_local_error) { $my_local_error = "_readText unknown Timeout-Error (2): $my_error"; carp ("_readText: $my_local_error"); last RECEVICE_ANSWER; } if ($len <= 0) { # error no data $my_local_error = "NULL-Len-Data in _readText $!"; _trace1 ("_readText: $my_local_error\n"); last RECEVICE_ANSWER; } } else {# got NO (more) data last RECEVICE_ANSWER; } if ($retryCnt++ < $Net::SSLhello::retry) { $my_local_error = "Retry-Counter exceeded $Net::SSLhello::retry while reading Text"; _trace1 ("_readText: $my_local_error\n"); last; } }} alarm (0); # race condition protection chomp ($my_local_error); $my_error = $my_local_error if (defined($my_error)); return ($input, $my_local_error); } # _readText ############################################################ sub compileClientHello ($$$$;$$$$) { #? compile a Client Hello Packet # my $record_version = shift || ""; my $version = shift || ""; my $ciphers = shift || ""; my $host = shift || ""; my $dtls_epoch = shift || 0; # optional my $dtls_sequence = shift || 0; # optional my $dtls_cookieLen = shift || 0; # optional my $dtls_cookie = shift || ""; # optional my $clientHello = ""; # return value my $clientHello_tmp = ""; my $clientHello_extensions = ""; my $challenge = $CHALLENGE; # 16-32 bytes, my $i; #counter my %rhash = reverse %PROTOCOL_VERSION; my $ssl = $rhash{$version}; _trace4 (sprintf("compileClientHello (%04X, %04X,\n >%s<, %s) {\n", $record_version, $version, hexCodedString ($ciphers," "), $host) ); $challenge= pack("Na[28]", time(), $challenge); # 4 bytes: uint32 gmt_unix_time;, 28 byte random _trace4_("# ---> challenge >".hexCodedString ($challenge)."<\n"); my %clientHello = ( #V2ClientHello 'record_type' => $RECORD_TYPE {'handshake'},# from SSL3: Handshake (22=0x16) #uint8 'record_version' => $record_version, # from SSL3: #uint16 'record_epoch' => 0x0000, # DTLS only: #uint16 'record_seqNr' => 0x000000, # DTLS only: #uint24 (!) 'record_len' => 0x0000, # from SSL3: #uint16 'msg_type' => $SSL_MT_CLIENT_HELLO, # 0x01 #uint8 'msg_len' => 0x000000, # SSL2: uint16 | 0x8000, from SSL3: uint24 (!) 'msg_seqNr' => 0x0000, # DTLS only: #uint16 'fragment_offset' => 0x000000, # DTLS only: #uint24 (!) 'fragment_len' => 0x000000, # DTLS only: #uint24 (!) 'version' => $version, # SSL2:0x0002,SSL3:0x3000,TLS1:0x0301 #uint16 'cipher_spec_len' => length($ciphers), # uint16 'session_id_len' => 0x0000, # uint16 'cookie_len' => 0x00, # DTLS only: #uint8 'cookie' => "", # DTLS only: 0.32 bytes (rfc 4347) 'challenge_len' => length($challenge), # uint16 'cipher_spec' => $ciphers, # sslv2: 3 bytes, SSL3/TLS: 2 bytes 'session_id' => "", # client_helo => len=0, 'challenge' => $challenge, # 16-32 bytes | SSL3/TLS: 32 bytes 'compression_method_len' => 0x01, # len = 1 'compression_method' => 0x00, # SSL3/TLS1.x 00 ); if ($version == $PROTOCOL_VERSION{'SSLv2'}) { #SSL2 _trace2 ("compileClientHello: Protocol: SSL2\n"); $clientHello_tmp = pack ("C n n n n a* a*", $clientHello{'msg_type'}, #C $clientHello{'version'}, #n $clientHello{'cipher_spec_len'},#n $clientHello{'session_id_len'}, #n $clientHello{'challenge_len'}, #n $clientHello{'cipher_spec'}, #A #### $clientHello{'session_id'}, # len = 0 $clientHello{'challenge'}, #A ); $clientHello{'msg_len'} = length ($clientHello_tmp) | 0x8000; _trace2_ ( sprintf ( "# --> msg_len \| 0x8000 (added): >%04X<\n". "# --> msg_type: >%02X<\n". "# --> version: >%04X< (%s)\n". "# --> cipher_spec_len: >%04X<\n". "# --> session_id_len: >%04X<\n". "# --> challenge_len: >%04X<\n". "# --> cipher_spec: >%s<\n". "# --> session_id: >%s<\n". "# --> challenge: >%s<\n", $clientHello{'msg_len'}, $clientHello{'msg_type'}, $clientHello{'version'}, $ssl, $clientHello{'cipher_spec_len'}, $clientHello{'session_id_len'}, $clientHello{'challenge_len'}, hexCodedString ($clientHello{'cipher_spec'}," >"), hexCodedString ($clientHello{'session_id'}), hexCodedString ($clientHello{'challenge'}) ) ); if (($Net::SSLhello::trace > 3)) { printSSL2CipherList ($clientHello{'cipher_spec'}); } $clientHello = pack ("n a*", $clientHello{'msg_len'}, $clientHello_tmp, ); _trace4 (sprintf ("compileClientHello: ClientHello(Version= %04X)\n >%s<\n",$version, hexCodedString ($clientHello," "))); } elsif (($record_version & 0xFF00) == $PROTOCOL_VERSION{'SSLv3'}) { #SSL3 , TLS1.x _trace2 ("compileClientHello: Protocol: SSL3/TLS1.x\n"); $clientHello_extensions = _compileClientHelloExtensions ($record_version, $version, $ciphers, $host, %clientHello); $clientHello{'extensions_total_len'} = length($clientHello_extensions); _trace4 ("compileClientHello (SSL3/TLS) (1):\n"); $clientHello_tmp = pack ("n a[32] C n a[$clientHello{'cipher_spec_len'}] C C[$clientHello{'compression_method_len'}] a[$clientHello{'extensions_total_len'}]", $clientHello{'version'}, # n $clientHello{'challenge'}, # A[32] = gmt + random [4] + [28] bytes $clientHello{'session_id_len'}, # C $clientHello{'cipher_spec_len'}, # n $clientHello{'cipher_spec'}, # A[$clientHello{'cipher_spec_len'}] $clientHello{'compression_method_len'}, # C (0x01) $clientHello{'compression_method'}, # C[len] (0x00) $clientHello_extensions # optional ); _trace4_ (" >".hexCodedString ($clientHello_tmp," ")."<\n"); $clientHello{'msg_len'} = length ($clientHello_tmp); $clientHello{'record_len'} = $clientHello{'msg_len'} + 4; $clientHello = pack ("C n n C C n a*", $clientHello{'record_type'}, # C $clientHello{'record_version'}, # n $clientHello{'record_len'}, # n $clientHello{'msg_type'}, # C 0x00, # C (0x00) $clientHello{'msg_len'}, # n $clientHello_tmp # a ); _trace3 ( "compileClientHello (SSL3/TLS) (2):\n >".hexCodedString ($clientHello," ")."<\n"); _trace2_ ( sprintf ( "# -->SSL3/TLS-clientHello:\n". "# --> record_type: >%02X<\n". "# --> record_version: >%04X< (%s)\n". "# --> record_len: >%04X<\n". "# --> Handshake protocol: \n". "# --> msg_type: >%02X<\n". "# --> msg_len: >00%04X<\n". "# --> version: >%04X< (%s)\n". "# --> challenge/random: >%s<\n". "# --> session_id_len: >%02X<\n". "# --> cipher_spec_len: >%04X<\n". "# --> cipher_spec: >%s<\n", #Comma!! $clientHello{'record_type'}, $clientHello{'record_version'}, $ssl, $clientHello{'record_len'}, $clientHello{'msg_type'}, $clientHello{'msg_len'}, $clientHello{'version'}, $ssl, hexCodedString ($clientHello{'challenge'}), $clientHello{'session_id_len'}, $clientHello{'cipher_spec_len'}, hexCodedString ($clientHello{'cipher_spec'}), )); if ($Net::SSLhello::trace > 3) { printTLSCipherList ($clientHello{'cipher_spec'}); } _trace2_ ( sprintf ( "# --> compression_method_len: >%02X<\n". "# --> compression_method: >%02X<\n". "# --> extensions_total_len: >%04X<\n", #Comma!! $clientHello{'compression_method_len'}, # C (0x01) $clientHello{'compression_method'}, # C[1] (0x00) $clientHello{'extensions_total_len'}, )); _trace4_ ( sprintf ( "# ---> extensions: >%s<\n", hexCodedString ($clientHello_extensions), ) ); _trace4 (sprintf ("compileClientHello (%04X)\n >",$record_version).hexCodedString ($clientHello," ")."<\n"); } elsif ( (($record_version & 0xFF00) == $PROTOCOL_VERSION{'DTLSfamily'}) || ($version == $PROTOCOL_VERSION{'DTLSv09'}) ) { #DTLS1.x or DTLSv09 (OpenSSL pre 0.9.8f) _trace2 ("compileClientHello: Protocol: DTLS\n"); $clientHello_extensions = _compileClientHelloExtensions ($record_version, $version, $ciphers, $host, %clientHello); $clientHello{'extensions_total_len'} = length($clientHello_extensions); $clientHello{'cookie_len'} = $dtls_cookieLen; $clientHello{'cookie'} = $dtls_cookie; _trace4 ("compileClientHello (DTLS) (1):\n"); $clientHello_tmp = pack ("n a[32] C C A[$clientHello{'cookie_len'}] n a[$clientHello{'cipher_spec_len'}] C C[$clientHello{'compression_method_len'}] a[$clientHello{'extensions_total_len'}]", $clientHello{'version'}, # n $clientHello{'challenge'}, # A[32] = gmt + random [4] + [28] bytes $clientHello{'session_id_len'}, # C $clientHello{'cookie_len'}, # C, DTLS only $clientHello{'cookie'}, # A[$clientHello{'cookie_len'}], DTLS $clientHello{'cipher_spec_len'}, # n $clientHello{'cipher_spec'}, # A[$clientHello{'cipher_spec_len'}] $clientHello{'compression_method_len'}, # C (0x01) $clientHello{'compression_method'}, # C[len] (0x00) $clientHello_extensions # optional ); _trace4_ (" >".hexCodedString ($clientHello_tmp," ")."<\n"); $clientHello{'msg_len'} = length ($clientHello_tmp); $clientHello{'fragment_len'} = $clientHello{'msg_len'}; ## Up to now no fragmented packets (TBD?) $clientHello{'record_len'} = $clientHello{'msg_len'} + 12; #=+4 +8 (DTLS) $clientHello{'record_epoch'} = $dtls_epoch; $clientHello{'record_seqNr'} = $dtls_sequence; $clientHello{'msg_seqNr'} = $dtls_sequence; ## Up to now no fragmented packets (TBD?)$ $clientHello = pack ("C n n n N n C C n n C n C n a*", $clientHello{'record_type'}, # C $clientHello{'record_version'}, # n $clientHello{'record_epoch'}, # n 0x0000, # n (0x0000) $clientHello{'record_seqNr'}, # N $clientHello{'record_len'}, # n $clientHello{'msg_type'}, # C 0x00, # C (0x00) $clientHello{'msg_len'}, # n $clientHello{'msg_seqNr'}, # n 0x00, # C (0x00) $clientHello{'fragment_offset'}, # n TBD: verify 0x00, # C (0x00) $clientHello{'fragment_len'}, # n TBD: verify $clientHello_tmp # a ); _trace2 ( "compileClientHello (DTLS) (2):\n >".hexCodedString ($clientHello," ")."<\n"); _trace2_ ( sprintf ( "# --> DTLS-clientHello (Record):\n". "# --> record_type: >%02X<\n". "# --> record_version: >%04X< (%s)\n". "# --> record_epoch: >%04X<\n". # DTLS "# --> record_seqNr: >%012X<\n". # DTLS "# --> record_len: >%04X<\n". "# --> Handshake protocol: \n". "# --> msg_type: >%02X<\n". "# --> msg_len: >%06X<\n". "# --> msg_seqNr: >%04X<\n". # DTLS "# --> fragment_offset: >%06X<\n". # DTLS = 0x000000 if not fragmented "# --> fragment_len: >%06X<\n". # DTLS = msg_len if not fragmented "# --> version: >%04X< (%s)\n". "# --> challenge/random: >%s<\n". "# --> session_id_len: >%02X<\n". "# --> cookie_len: >%02X<\n". # DTLS "# --> cookie: >%s<\n". # DTLS "# --> cipher_spec_len: >%04X<\n". "# --> cipher_spec: >%s<\n", # Comma!! $clientHello{'record_type'}, $clientHello{'record_version'}, $ssl, $clientHello{'record_epoch'}, # DTLS $clientHello{'record_seqNr'}, # DTLS $clientHello{'record_len'}, $clientHello{'msg_type'}, $clientHello{'msg_len'}, $clientHello{'msg_seqNr'}, # DTLS $clientHello{'fragment_offset'}, # DTLS $clientHello{'fragment_len'}, # DTLS $clientHello{'version'}, $ssl, hexCodedString ($clientHello{'challenge'}), $clientHello{'session_id_len'}, $clientHello{'cookie_len'}, # DTLS hexCodedString ($clientHello{'cookie'}," "), # DTLS $clientHello{'cipher_spec_len'}, hexCodedString ($clientHello{'cipher_spec'}," "), )); if ($Net::SSLhello::trace > 3) { printTLSCipherList ($clientHello{'cipher_spec'}); } _trace2_ ( sprintf ( "# --> compression_method_len: >%02X<\n". "# --> compression_method: >%02X<\n". "# --> extensions_total_len: >%04X<\n", #Comma! $clientHello{'compression_method_len'}, # C (0x01) $clientHello{'compression_method'}, # C[1] (0x00) $clientHello{'extensions_total_len'}, )); _trace4 (sprintf ("compileClientHello (%04X)\n >",$record_version).hexCodedString ($clientHello," ")."<\n"); } else { if (! defined $ssl) { $ssl = "--unknown protocol--"; } # my ($ssl) = grep {$record_version ~~ ${$cfg{'openssl_version_map'}}{$_}} keys %{$cfg{'openssl_version_map'}}; local $my_error = "**WARNING: compileClientHello: protocol version $ssl (0x". sprintf("%04X", $record_version) .") not (yet) defined in Net::SSLhello.pm -> protocol ignored"; carp($my_error); } if ( ($Net::SSLhello::max_sslHelloLen > 0) && (length($clientHello) > $Net::SSLhello::max_sslHelloLen) ) { # According RFC: 16383+5 bytes; handshake messages between 256 and 511 bytes in length caused sometimes virtual servers to stall, cf.: https://code.google.com/p/chromium/issues/detail?id=245500 if (! defined $ssl) { $ssl = "--unknown protocol--"; } if ($Net::SSLhello::experimental >0) { # experimental function is are activated _trace_("\n"); _trace ("compileClientHello: WARNING: Server $host (protocol: $ssl): use of ClintHellos > $Net::SSLhello::max_sslHelloLen bytes did cause some virtual servers to stall in the past. This protection is overridden by '--experimental'"); } else { # use of experimental functions is not permitted (option is not activated) local $my_error = "**WARNING: compileClientHello: Server $host: the ClientHello is longer than $Net::SSLhello::max_sslHelloLen bytes, this caused sometimes virtual servers to stall, e.g. 256 bytes: https://code.google.com/p/chromium/issues/detail?id=245500;\n Please add '--experimental' to override this protection; -> This time the protocol $ssl is ignored"; carp ($my_error); } } return ($clientHello); } # compileClientHello ########################### sub compileAlertRecord ($$$$;$$) { #? compile an alert record my $record_version = shift || ""; my $host = shift || ""; my $level = shift || ""; my $description = shift || ""; my $dtls_epoch = shift || 0; # optional my $dtls_sequence = shift || 0; # optional my $alertRecord = ""; # return value my %rhash = reverse %PROTOCOL_VERSION; my $ssl = $rhash{$record_version}; _trace4 ("compileAlertRecord ($host) {\n"); local $my_error = ""; # reset error message my %alertRecord = ( # alert record 'record_type' => $RECORD_TYPE {'handshake'},# from SSL3: Handshake (22=0x16) #uint8 'record_version' => $record_version, # from SSL3: #uint16 'record_epoch' => 0x0000, # DTLS only: #uint16 'record_seqNr' => 0x000000, # DTLS only: #uint24 (!) 'record_len' => 0x0002, # from SSL3: #uint16: always 2 bytes! 'level' => $level, # from SSL3: #uint8: Alarm-Level 'description' => $description, # from SSL3: #uint8: Alarm ); if ($record_version == $PROTOCOL_VERSION{'SSLv2'}) { #SSL2 # _trace2 ("compileAlertRecord: Protocol: SSL2\n"); $my_error = "compileAlert for SSL2 is not yet supported"; _trace1 ("compileAlertRecord: $my_error\n"); carp ($my_error); # $alertRecord_tmp = pack ("C n ", # $alertRecord{'msg_type'}, #C # $alertRecord{'version'}, #n # ); # $alertRecord{'msg_len'} = length ($alertRecord_tmp) | 0x8000; # _trace2_ ( # sprintf ( # "# --> msg_len \| 0x8000 (added): >%04X<\n". # "# --> msg_type: >%02X<\n". # "# --> version: >%04X< (%s)\n". # $alertRecord{'msg_len'}, # $alertRecord{'msg_type'}, # $alertRecord{'version'}, # $ssl, # ) # ); # $alertRecord = pack ("n a*", # $alertRecord{'msg_len'}, # $alertRecord_tmp, # ); # _trace4 (sprintf ("compileAlertRecord (Version= %04X)\n >%s<\n",$version, hexCodedString ($alertRecord," "))); } elsif (($record_version & 0xFF00) == $PROTOCOL_VERSION{'SSLv3'}) { #SSL3 , TLS1.x _trace2 ("compileAlertRecord (SSL3/TLS) (1):\n"); $alertRecord{'record_type'} = $RECORD_TYPE {'alert'}; $alertRecord = pack("C n n C C", # compile alert-messages $alertRecord{'record_type'}, # C $alertRecord{'record_version'}, # n $alertRecord{'record_len'}, # n $alertRecord{'level'}, # C $alertRecord{'description'} # C ); if ($TLS_AlertDescription {$alertRecord{'description'}} ) { # defined, no Null-String $description = $TLS_AlertDescription {$alertRecord{'description'}}[0]." ".$TLS_AlertDescription {$alertRecord{'description'}}[2]; } else { $description = "Unknown/Undefined"; } _trace2_ ( sprintf ( "# -->SSL3/TLS-AlertRecord:\n". "# --> record_type: >%02X<\n". "# --> record_version: >%04X< (%s)\n". "# --> record_len: >%04X<\n". "# --> Alert Message:\n". "# --> Level: >%02X<\n". "# --> Description: >%02X< (%s)\n", $alertRecord{'record_type'}, $alertRecord{'record_version'}, $ssl, $alertRecord{'record_len'}, $alertRecord{'level'}, $alertRecord{'description'}, $description, )); _trace4 (sprintf ("compileAlertRecord (%04X)\n >",$record_version).hexCodedString ($alertRecord," ")."<\n"); } elsif ( (($record_version & 0xFF00) == $PROTOCOL_VERSION{'DTLSfamily'}) || ($record_version == $PROTOCOL_VERSION{'DTLSv09'}) ) { #DTLS1.x or DTLSv09 (OpenSSL pre 0.9.8f) _trace2 ("compileAlertRecord: Protocol: DTLS\n"); $alertRecord{'record_type'} = $RECORD_TYPE {'alert'}; $alertRecord{'record_epoch'} = $dtls_epoch; $alertRecord{'record_seqNr'} = $dtls_sequence; $alertRecord = pack ("C n n n N n C C", $alertRecord{'record_type'}, # C $alertRecord{'record_version'}, # n $alertRecord{'record_epoch'}, # n 0x0000, # n (0x0000) $alertRecord{'record_seqNr'}, # N $alertRecord{'record_len'}, # n $alertRecord{'level'}, # C $alertRecord{'description'} # C ); if ($TLS_AlertDescription {$alertRecord{'description'}} ) { # defined, no Null-String $description = $TLS_AlertDescription {$alertRecord{'description'}}[0]." ".$TLS_AlertDescription {$alertRecord{'description'}}[2]; } else { $description = "Unknown/Undefined"; } _trace2 ( "compileAlertRecord (DTLS) (2):\n >".hexCodedString ($alertRecord," ")."<\n"); _trace2_ ( sprintf ( "# --> DTLS-Record (Alert):\n". "# --> record_type: >%02X<\n". "# --> record_version: >%04X< (%s)\n". "# --> record_epoch: >%04X<\n". # DTLS "# --> record_seqNr: >%012X<\n". # DTLS "# --> record_len: >%04X<\n". "# --> Alert Message:\n". "# --> Level: >%02X<\n". "# --> Description: >%02X< (%s)\n", $alertRecord{'record_type'}, $alertRecord{'record_version'}, $ssl, $alertRecord{'record_epoch'}, # DTLS $alertRecord{'record_seqNr'}, # DTLS $alertRecord{'record_len'}, $alertRecord{'level'}, $alertRecord{'description'}, $description, )); _trace4 (sprintf ("compileAlertRecord (%04X)\n >",$record_version).hexCodedString ($alertRecord," ")."<\n"); } else { if (! defined $ssl) { $ssl = "--unknown protocol--"; } # my ($ssl) = grep {$record_version ~~ ${$cfg{'openssl_version_map'}}{$_}} keys %{$cfg{'openssl_version_map'}}; $my_error = "**WARNING: compileAlertRecord protocol version $ssl (0x". sprintf("%04X", $record_version) .") not (yet) defined in Net::SSLhello.pm -> protocol ignored"; carp($my_error); } if ( ($Net::SSLhello::max_sslHelloLen > 0) && (length($alertRecord) > $Net::SSLhello::max_sslHelloLen) ) { # According RFC: 16383+5 bytes; handshake messages between 256 and 511 bytes in length caused sometimes virtual servers to stall, cf.: https://code.google.com/p/chromium/issues/detail?id=245500 if (! defined $ssl) { $ssl = "--unknown protocol--"; } if ($Net::SSLhello::experimental >0) { # experimental function is are activated _trace_("\n"); _trace ("compileAlertRecord: WARNING: Server $host (protocol: $ssl): use of alert message > $Net::SSLhello::max_sslHelloLen bytes did cause some virtual servers to stall in the past. This protection is overridden by '--experimental'"); } else { # use of experimental functions is not permitted (option is not activated) $my_error = "**WARNING: compileAlertRecord: Server $host: the alert message is longer than $Net::SSLhello::max_sslHelloLen bytes, this caused sometimes virtual servers to stall, e.g. 256 bytes: https://code.google.com/p/chromium/issues/detail?id=245500;\n Please add '--experimental' to override this protection; -> This time the protocol $ssl is ignored"; carp ($my_error); } } return ($alertRecord); } # compileAlertRecord ############################ sub _compileClientHelloExtensions ($$$$@) { #? FIXME: <> my ($record_version, $version, $ciphers, $host, %clientHello) = @_; #my $record_version = shift || ""; #my $version = shift || ""; #my $ciphers = shift || ""; #my $host = shift || ""; #my (%clientHello) = @_; my $clientHello_extensions = ""; my %rhash = reverse %PROTOCOL_VERSION; my $ssl = $rhash{$version}; if ( ( ($version == $PROTOCOL_VERSION{'SSLv3'}) && (!$Net::SSLhello::force_TLS_extensions) ) || ($version == $PROTOCOL_VERSION{'SSLv2'}) ) { # prevent to not to use tls extensions with SSLv2 or SSLv3 _trace2 ("compileClientHelloExtensions: Protocol $ssl does not support TLS extensions including SNI -> no extension added\n"); return (""); } # ggf auch prüfen, ob Host ein DNS-Name ist if ($Net::SSLhello::usesni) { # allow to test SNI (with version TLSv1 and above or DTLSv09 (OpenSSL pre 0.9.8f), DTLSv1 and above) ### data for extension 'Server Name Indication' in reverse order $Net::SSLhello::sni_name =~ s/\s*(.*?)\s*\r?\n?/$1/gx if ($Net::SSLhello::sni_name); # delete Spaces, \r and \n $Net::SSLhello::use_sni_name = 1 if ( ($Net::SSLhello::use_sni_name == 0) && ($Net::SSLhello::sni_name) && ($Net::SSLhello::sni_name ne "1") ); ###FIX: quickfix until migration of o-saft.pl is compleated (tbd) unless ($Net::SSLhello::use_sni_name) { $clientHello{'extension_sni_name'} = $host; # Server Name, should be a Name no IP } else { $clientHello{'extension_sni_name'} = ($Net::SSLhello::sni_name) ? $Net::SSLhello::sni_name : ""; # Server Name, should be a Name no IP } $clientHello{'extension_sni_len'} = length($clientHello{'extension_sni_name'}); # len of server name $clientHello{'extension_sni_type'} = 0x00; # 0x00= host_name $clientHello{'extension_sni_list_len'} = $clientHello{'extension_sni_len'} + 3; # len of server name + 3 bytes (sni_len, sni_type) $clientHello{'extension_len'} = $clientHello{'extension_sni_list_len'} + 2; # len of this extension = sni_list_len + 2 bytes (sni_list_len) $clientHello{'extension_type_server_name'} = 0x0000; # 0x0000 # $clientHello{'extensions_total_len'} = $clientHello{'extension_len'} + 4; # war +2 len server name extension + 2 bytes (extension_type) #??? +4?!!## $clientHello_extensions = pack ("n n n C n a[$clientHello{'extension_sni_len'}]", $clientHello{'extension_type_server_name'}, #n $clientHello{'extension_len'}, #n $clientHello{'extension_sni_list_len'}, #n $clientHello{'extension_sni_type'}, #C $clientHello{'extension_sni_len'}, #n $clientHello{'extension_sni_name'}, #a[$clientHello{'extension_sni_len'}] ); _trace2 ("compileClientHelloExtensions ($ssl): extension_sni_name extension added (name='$clientHello{'extension_sni_name'}', len=$clientHello{'extension_sni_len'})\n"); } else { _trace2 ("compileClientHelloExtensions ($ssl): NO extension_sni_name extension added\n"); } if ($Net::SSLhello::usereneg) { # use secure Renegotiation my $anzahl = int length ($clientHello{'cipher_spec'}) / 2; my @cipherTable = unpack("a2" x $anzahl, $clientHello{'cipher_spec'}); unless ( ($Net::SSLhello::double_reneg == 0) && (grep {/\x00\xff/x} @cipherTable) ) { # Protection against double renegotiation info is active # do *NOT* send a reneg_info extension if the cipher_spec includes already Signalling Cipher Suite Value (SCSV) # "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" {0x00, 0xFF} ### data for extension 'renegotiation_info' $clientHello{'extension_type_renegotiation_info'} = 0xff01; # Tbd: hier, oder zentrale Definition?! $clientHello{'extension_reneg_len'} = 0x0001; # Tbd: hier, oder zentrale Definition?! $clientHello{'extension_reneg_info_ext_len'} = 0x00; # Tbd: hier, oder zentrale Definition?! $clientHello_extensions .= pack ("n n c", $clientHello{'extension_type_renegotiation_info'}, #n = 0xff01 $clientHello{'extension_reneg_len'}, #n = 0x0001 $clientHello{'extension_reneg_info_ext_len'}, #c = 0x00 ); _trace2 ("compileClientHelloExtensions ($ssl): reneg_info Extension added\n"); } else { _trace2 ("compileClientHelloExtensions ($ssl): *NOT* sent a reneg_info Extension as the cipher_spec includes already the Signalling Cipher Suite Value (TLS_EMPTY_RENEGOTIATION_INFO_SCSV {0x00, 0xFF})\n"); } } # extension_type_signature_algorithms if ( ($Net::SSLhello::use_signature_alg >1) || (($Net::SSLhello::use_signature_alg >0) && ( (($record_version >= $PROTOCOL_VERSION{'TLSv12'}) && ($record_version < $PROTOCOL_VERSION{'DTLSfamily'})) || (($record_version >= $PROTOCOL_VERSION{'DTLSfamily'}) && ($record_version <= $PROTOCOL_VERSION{'DTLSv12'})) ) ) ) { # use_signature_alg: 0 (off), 1(auto on if >=TLSv1.2, >=DTLS1.2), 2: always on ### data for extension 'signature_algorithms' $clientHello{'extension_type_signature_algorithms'} = 0x000d; ##TBD hier, oder zentrale Definition?! $clientHello{'extension_hash_algorithms_list'} = "" ."\x06\x01\x06\x02\x06\x03" #SHA512: RSA/DSA/ECDSA ."\x05\x01\x05\x02\x05\x03" #SHA384: RSA/DSA/ECDSA ."\x04\x01\x04\x02\x04\x03" #SHA256: RSA/DSA/ECDSA ."\x03\x01\x03\x02\x03\x03" #SHA224: RSA/DSA/ECDSA ."\x02\x01\x02\x02\x02\x03" #SHA1: RSA/DSA/ECDSA .""; $clientHello{'extension_hash_algorithms_list_len'} = length ($clientHello{'extension_hash_algorithms_list'}); #30 = 0x1E $clientHello{'extension_signature_algorithms_len'} = $clientHello{'extension_hash_algorithms_list_len'} + 2; #32 = 0x20 $clientHello_extensions .= pack ("n n n a[$clientHello{'extension_hash_algorithms_list_len'}]", $clientHello{'extension_type_signature_algorithms'}, #n = 0x001d $clientHello{'extension_signature_algorithms_len'}, #n $clientHello{'extension_hash_algorithms_list_len'}, #n $clientHello{'extension_hash_algorithms_list'}, #a[$clientHello{'extension_hash_algorithms_list_len'}] ); _trace2 ("compileClientHelloExtensions ($ssl): signature_algorithms Extension added\n"); } # extension elliptic_curves my $anzahl = int length ($clientHello{'cipher_spec'}) / 2; my @cipherTable = unpack("a2" x $anzahl, $clientHello{'cipher_spec'}); # send always ECC extensions if not switched off manually #if ( grep(/\xc0./, @cipherTable) || 1==1 ) { # found cipher C0xx, lazy check; ### TBD: check with a range of ECC-ciphers ### if ($Net::SSLhello::useecc) { # use Elliptic Curves Extension ### Data for Extension 'elliptic_curves' (in reverse order) $clientHello{'extension_ecc_list'} = "" # TBD: should be altered to get all supported ECurves (not only the primary # # disable one line after the other to find manually the secondary, tertiary etc curve # ."\x00\x00" # 0x0000 (Unassigned_0) ## disabled by default ."\x00\x01" # 0x0001 (sect163k1) ."\x00\x02" # 0x0002 (sect163r1) ."\x00\x03" # 0x0003 (sect163r2) ."\x00\x04" # 0x0004 (sect193r1) ."\x00\x05" # 0x0005 (sect193r2) ."\x00\x06" # 0x0006 (sect233k1) ."\x00\x07" # 0x0007 (sect233r1) ."\x00\x08" # 0x0008 (sect239k1) ."\x00\x09" # 0x0009 (sect283k1) ."\x00\x0a" # 0x000a (sect283r1) ."\x00\x0b" # 0x000b (sect409k1) ."\x00\x0c" # 0x000c (sect409r1) ."\x00\x0d" # 0x000d (sect571k1) ."\x00\x0e" # 0x000e (sect571r1) ."\x00\x0f" # 0x000f (secp160k1) ."\x00\x10" # 0x0010 (secp160r1) ."\x00\x11" # 0x0011 (secp160r2) ."\x00\x12" # 0x0012 (secp192k1) ."\x00\x13" # 0x0013 (secp192r1) ."\x00\x14" # 0x0014 (secp224k1) ."\x00\x15" # 0x0015 (secp224r1) ."\x00\x16" # 0x0016 (secp256k1) ."\x00\x17" # 0x0017 (secp256r1) ## => common default curve ."\x00\x18" # 0x0018 (secp384r1) ."\x00\x19" # 0x0019 (secp512r1) ."\x00\x1a" # 0x001a (brainpoolP256r1) ."\x00\x1b" # 0x001b (brainpoolP384r1) ."\x00\x1c" # 0x001c (brainpoolP512r1) ."\x00\x1d" # 0x001d (ecdh_x25519) ."\x00\x1e" # 0x001e (ecdh_x25519) ."\x00\x1f" # 0x001f (eddsa_ed25519) ## Signature curves, vanished in https://tools.ietf.org/html/draft-ietf-tls-tls13-12 ."\x00\x20" # 0x0020 (eddsa_ed448) ## Signature curves, vanished in https://tools.ietf.org/html/draft-ietf-tls-tls13-12 .""; # ALL defined ECCs; TBD: move general list to osaft.pl TBD $clientHello{'extension_ecc_list_len'} = length($clientHello{'extension_ecc_list'}); # len of ECC List $clientHello{'extension_elliptic_curves_len'} = $clientHello{'extension_ecc_list_len'}+2; # len of ECC Extension $clientHello{'extension_type_elliptic_curves'} = 0x000a; # Tbd: hier, oder zentrale Definition?! $clientHello_extensions .= pack ("n n n a[$clientHello{'extension_ecc_list_len'}]", $clientHello{'extension_type_elliptic_curves'}, #n = 0x000a $clientHello{'extension_elliptic_curves_len'}, #n = 0x00xz $clientHello{'extension_ecc_list_len'}, #n = 0x00xy $clientHello{'extension_ecc_list'}, #a[$clientHello{'extension_ecc_list_len'}] = 0x00.... ); _trace2 ("compileClientHelloExtensions ($ssl): elliptic_curve Extension added\n"); } if ($Net::SSLhello::useecpoint ) { # use Elliptic Point Formats Extension ### Data for Extension 'ec_point_formats' $clientHello{'extension_type_ec_point_formats'} = 0x000b; # Tbd: hier, oder zentrale Definition?! $clientHello{'extension_ec_point_formats_len'} = 0x0002; # Tbd: hier, oder zentrale Definition?! $clientHello{'extension_ec_point_formats_list_ele'} = 0x01; # Tbd: hier, oder zentrale Definition?! $clientHello{'extension_ec_point_formats_list'} = "\x00"; # Tbd: hier, oder zentrale Definition?! $clientHello_extensions .= pack ("n n C a[$clientHello{'extension_ec_point_formats_list_ele'}]", $clientHello{'extension_type_ec_point_formats'}, #n = 0x000b $clientHello{'extension_ec_point_formats_len'}, #n = 0x00xz $clientHello{'extension_ec_point_formats_list_ele'}, #C = 0xxy $clientHello{'extension_ec_point_formats_list'}, #a[$clientHello{'extension_ec_point_formats_list_ele'}] = 0x00.... ); _trace2 ("compileClientHelloExtensions ($ssl): ec_point_formats Extension added\n"); } #} #end send always ECC extensions $clientHello{'extensions_total_len'} = length($clientHello_extensions); if ($clientHello_extensions) { # not empty $clientHello_extensions = pack ("n a*", length($clientHello_extensions), #n $clientHello_extensions #a[length($clientHello_extensions)] ); _trace4 (sprintf ("_compileClientHelloExtensions ($ssl) (extensions_total_len = %04X)\n >", $clientHello{'extensions_total_len'}).hexCodedString ($clientHello_extensions ," ")."<\n"); } return ($clientHello_extensions); } # _compileClientHelloExtensions =pod =head2 parseServerKeyExchange( ) Manually parse a Server Kex Exchange Packet from - DHE handshake to detect the length of the DHparam (needed for openssl <= 1.0.1), e.g. dh, 2048 bits (dh in small letters to be different from openssl (large letters) - ECDHE handshake to check for the most priorized Curve =cut sub parseServerKeyExchange($$$) { #? parse a ServerKeyExchange packet to detect length of DHparam my ($keyExchange, $len, $d) = @_; my ($_tmpLen, $_null, $_handshake_type, $_bits) = 0; my %_mySSLinfo; _trace2("parseServerKeyExchange($keyExchange, $len, ...)\n"); _trace4("parseServerKeyExchange(KeyExchange= $keyExchange, Len= $len, Data= ".unpack("H*",$d)."\n"); $_tmpLen = length (unpack("H*",$d))/2; carp ("parseServerKeyExchange: Error in ServerKeyExchange Message: unexpected len ($_tmpLen) should be $len bytes") if ($len != $_tmpLen); return if ($len != $_tmpLen); if ($keyExchange eq "DH") { ($_mySSLinfo{'DH_ServerParams_p_len'}, # n $d) = unpack("n a*", $d); ($_mySSLinfo{'DH_ServerParams_p'}, # a[$_mySSLinfo{'IDH_ServerParams_p_len'}] $_mySSLinfo{'DH_ServerParams_g_len'}, # n $d) = unpack("a[$_mySSLinfo{'DH_ServerParams_p_len'}] n a*", $d); $_mySSLinfo{'DH_ServerParams_p'} = unpack ("H*", $_mySSLinfo{'DH_ServerParams_p'}); # Convert to a readable HEX-String ($_mySSLinfo{'DH_ServerParams_g'}, # a[$_mySSLinfo{'IDH_ServerParams_g_len'}] $_mySSLinfo{'DH_ServerParams_PubKeyLen'}, # n $d) = unpack("a[$_mySSLinfo{'DH_ServerParams_g_len'}] n a*", $d); $_mySSLinfo{'DH_ServerParams_g'} = unpack ("H*", $_mySSLinfo{'DH_ServerParams_g'}); # Convert to a readable HEX-String ($_mySSLinfo{'DH_ServerParams_PubKey'}, # a[$_mySSLinfo{'IDH_ServerParams_g_len'}] $d) = unpack("a[$_mySSLinfo{'DH_ServerParams_PubKeyLen'}] a*", $d); $_mySSLinfo{'DH_ServerParams_PubKey'} = unpack ("H*", $_mySSLinfo{'DH_ServerParams_PubKey'}); # Convert to a readable HEX-String _trace2( sprintf ( " DH_ServerParams (len=%d):\n". "# --> p: (len=0x%04X=%4d) >%s<\n". "# --> g: (len=0x%04X=%4d) >%s<\n". "# --> PubKey: (len=0x%04X=%4d) >%s<\n", $len, $_mySSLinfo{'DH_ServerParams_p_len'}, $_mySSLinfo{'DH_ServerParams_p_len'}, $_mySSLinfo{'DH_ServerParams_p'}, $_mySSLinfo{'DH_ServerParams_g_len'}, $_mySSLinfo{'DH_ServerParams_g_len'}, $_mySSLinfo{'DH_ServerParams_g'}, $_mySSLinfo{'DH_ServerParams_PubKeyLen'}, $_mySSLinfo{'DH_ServerParams_PubKeyLen'}, $_mySSLinfo{'DH_ServerParams_PubKey'} )); $_bits = $_mySSLinfo{'DH_ServerParams_p_len'} * 8; $_mySSLinfo{'DH_serverParam'} = "dh, ". $_bits ." bits"; # manually generate the same message that is generated by openssl >= 1.0.2 but here with 'dh' in small letters ###TEST TEST $_mySSLinfo{$keyExchange.'_serverParam'} = "dh, ". $_bits ." bits"; # manually generate the same message that is generated by openssl >= 1. 0.2 but here with 'dh' in small letters _trace4("parseServerKeyExchange: DH_serverParam: ".$_mySSLinfo{'DH_serverParam'}."\n"); _trace2("parseServerKeyExchange() done.\n"); return ($_mySSLinfo{'DH_serverParam'}); } elsif ($keyExchange eq "ECDH") { # check for the most priorized Curve; TBD: check for all supported Curves later (by sending more Client_hellos, like to check the ciphers); this should be managed by a superior routine ($_mySSLinfo{'ECDH_eccurve_type'}, # C $d) = unpack("C a*", $d); if ($_mySSLinfo{'ECDH_eccurve_type'} == $ECCURVE_TYPE{'named_curve'}) { ($_mySSLinfo{'ECDH_namedCurve'}, # n $d) = unpack("n a*", $d); $_mySSLinfo{'ECDH_serverParam'} = "(primary) named_curve: <>"; # set a default value $_mySSLinfo{'ECDH_serverParam'} = "(primary) named_curve: ". $ECC_NAMED_CURVE {$_mySSLinfo{'ECDH_namedCurve'}}[0] .", ". $ECC_NAMED_CURVE {$_mySSLinfo{'ECDH_namedCurve'}}[1] . " bits" if ( defined ($ECC_NAMED_CURVE {$_mySSLinfo{'ECDH_namedCurve'}}[0]) ); } elsif ($_mySSLinfo{'ECDH_eccurve_type'} == $ECCURVE_TYPE{'explicit_prime'}) { # only basic parsing, no additional trace information about additional parameters, yet, ($_mySSLinfo{'ECDH_explicit_prime_p_len'}, # C $d) = unpack("C a*", $d); $_bits = $_mySSLinfo{'ECDH_explicit_prime_p_len'} * 8; $_mySSLinfo{'ECDH_serverParam'} = "(primary) explicite_prime: ". $_bits ." bits"; # manually generate a message that could ressemble to openssl >= 1.0.2 but here with 'ecdh' in small letters (TBD: get an original Message from OpenSSL for this special type of Curves } elsif ($_mySSLinfo{'ECDH_eccurve_type'} == $ECCURVE_TYPE{'explicit_char2'}) { # no parsing yet: #TBD: support this type later $_mySSLinfo{'ECDH_serverParam'} = "(primary) explicite_char2: <>"; } else { $_mySSLinfo{'ECDH_serverParam'} = "<>"; } _trace4("parseServerKeyExchange: ECDH_serverParam: '".$_mySSLinfo{'ECDH_serverParam'}."'\n"); _trace2("parseServerKeyExchange() done.\n"); return ("ecdh, ".$_mySSLinfo{'ECDH_serverParam'}); } elsif (($keyExchange =~ /^RSA/x) || ($keyExchange =~ /^EXP/x)) { # check for RSA ($_mySSLinfo{'RSA_ServerParams_modulus_len'}, # n $d) = unpack("n a*", $d); ($_mySSLinfo{'RSA_ServerParams_modulus'}, # a[$_mySSLinfo{'RSA_ServerParams_modulus_len'}] $_mySSLinfo{'RSA_ServerParams_exponent_len'}, # n $d) = unpack("a[$_mySSLinfo{'RSA_ServerParams_modulus_len'}] n a*", $d); $_mySSLinfo{'RSA_ServerParams_modulus'} = unpack ("H*", $_mySSLinfo{'RSA_ServerParams_modulus'}); # Convert to a readable HEX-String ($_mySSLinfo{'RSA_ServerParams_exponent'}, # a[$_mySSLinfo{'RSA_ServerParams_exponent_len'}] $d) = unpack("a[$_mySSLinfo{'RSA_ServerParams_exponent_len'}] a*", $d); $_mySSLinfo{'RSA_ServerParams_exponent'} = unpack ("H*", $_mySSLinfo{'RSA_ServerParams_exponent'}); # Convert to a readable HEX-String _trace2( sprintf ( " RSA_ServerParams (len=%d):\n". "# --> modulus: (len=0x%04X=%4d) >%s<\n". "# --> exponent: (len=0x%04X=%4d) >%s<\n", $len, $_mySSLinfo{'RSA_ServerParams_modulus_len'}, $_mySSLinfo{'RSA_ServerParams_modulus_len'}, $_mySSLinfo{'RSA_ServerParams_modulus'}, $_mySSLinfo{'RSA_ServerParams_exponent_len'}, $_mySSLinfo{'RSA_ServerParams_exponent_len'}, $_mySSLinfo{'RSA_ServerParams_exponent'} )); $_bits = $_mySSLinfo{'RSA_ServerParams_modulus_len'} * 8; $_mySSLinfo{'RSA_serverParam'} = "rsa, ". $_bits ." bits"; # manually generate the same message that is generated by openssl >= 1.0.2 but here with 'rsa' in small letters ###TEST TEST $_mySSLinfo{$keyExchange.'_serverParam'} = "dh, ". $_bits ." bits"; # manually generate the same message that is generated by openssl >= 1. 0.2 but here with 'dh' in small letters _trace4("parseServerKeyExchange: RSA_serverParam: ".$_mySSLinfo{'RSA_serverParam'}."\n"); _trace2("parseServerKeyExchange() done.\n"); return ($_mySSLinfo{'RSA_serverParam'}); } else { # nor DH neither ECDH _trace2("parseServerKeyExchange: The only supported KeyExchange types are DH, ECDH and RSA yet (not $keyExchange)\n"); _trace2("parseServerKeyExchange() done.\n"); return (""); } } # parseServerKeyExchange sub parseHandshakeRecord ($$$$$$$;$) { #? FIXME: <> <> # return (, , my $host = shift || ""; # for warn- and trace messages my $port = shift || ""; # for warn- and trace messages my $recordType = shift || 0; # recordType my $recordVersion = shift || 0; # recordVersion or SSLv2 my $recordLen = shift || 0; # recordLen my $recordData = shift || ""; # record my $lastCipher = shift || ""; # lastCipher my $client_protocol = shift || ""; # optional my $rest = ""; my $tmp_len = 0; my $message = ""; my $nextMessages = ""; my %serverHello; my $cipher = ""; my $keyExchange = ""; my $description = ""; my $lastMsgType = $HANDSHAKE_TYPE {'<>'}; #undefined local $my_error = ""; # reset error message my $sni = ""; my %rhash = reverse %PROTOCOL_VERSION; my $ssl_client = $rhash{$client_protocol}; #reset error_handler and set basic information for this sub OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => 'parseHandshakeRecord', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); $Net::SSLhello::use_sni_name = 1 if ( ($Net::SSLhello::use_sni_name == 0) && ($Net::SSLhello::sni_name) && ($Net::SSLhello::sni_name ne "1") ); ###FIX: quickfix until migration of o-saft.pl is compleated (tbd) unless ($Net::SSLhello::use_sni_name) { $sni = "'$host'" if ($Net::SSLhello::use_sni_name); # Server Name, should be a Name no IP } else { # different sni_name $sni = ($Net::SSLhello::sni_name) ? "'$Net::SSLhello::sni_name'" : "''"; # allow empty nonRFC-SNI-Names } if (defined $client_protocol) { _trace2("parseHandshakeRecord: Server '$host:$port': (expected protocol= >".sprintf ("%04X", $client_protocol)."<,\n (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($recordData)." bytes >".hexCodedString (substr($recordData,0,48)," ")."< ...)\n"); } else { _trace2("parseHandshakeRecord: Server '$host:$port': (any protocol, (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($recordData)." bytes\n recordData=".hexCodedString (substr($recordData,0,48)," ").")... \n"); } if (length ($recordData) >=1) { # received data in the record, at least 1 byte if ($recordVersion == $PROTOCOL_VERSION{'SSLv2'}) { #SSL2 (no real record -> get MessageData from data that has been parsed before) _trace2_ ("# -->SSL: Message type SSL2-Msg\n"); # SSLV2 uses Messages directly, no records -> get data from record-parameters $serverHello{'msg_len'} = $recordLen; # n (MSB already deleted) $serverHello{'msg_type'} = $recordType; # C ($message) = unpack("x a*", $recordData); # Skip '$serverHello{'msg_type'}, # C' -> 'x', which is already parsed as a dummy 'recordType' _trace2_ (sprintf ( "# --> msg_len: >%04X<\n". "# --> msg_type: >%02X<\n", $serverHello{'msg_len'}, $serverHello{'msg_type'} )); _trace4 ("parseHandshakeRecord: Server '$host:$port': MessageData:\n".hexCodedString ($message," ")."\n"); $lastMsgType = $serverHello{'msg_type'} || $HANDSHAKE_TYPE {'<>'}; if ($serverHello{'msg_type'} == $SSL_MT_SERVER_HELLO) { _trace4 (" Handshake protocol: SSL2 Server Hello\n"); _trace4 (" Message type: (Server Hello (2)\n"); return (parseSSL2_ServerHello ($host, $port, $message, $client_protocol), $lastMsgType, 0, ""); # cipher_spec-Liste } elsif ($serverHello{'msg_type'} == $SSL_MT_ERROR) { # simple error handling for ssl2 ($serverHello{'err_code'} # n ) = unpack("n", $message); _trace2 ("parseHandshakeRecord: Server '$host:$port': received a SSLv2 error message, code: >0x".hexCodedString ($serverHello{'err_code'})."<\n"); unless ($serverHello{'err_code'} == 0x0001) { # SSLV2_No_Cipher, TBD: this could be improved later (if needed) carp ("**WARNING: parseHandshakeRecord: Server '$host:$port': received a SSLv2 error message: , code: >0x".hexCodedString ($serverHello{'err_code'})." -> answer ignored\n"); } return ("", $lastMsgType, 0, ""); } else { # if ($serverHello{'msg_type'} == 0 => unsupported protocol (?!) $my_error= " Unknown SSLv2 message type (Dez): ".$serverHello{'msg_type'}.", Msg: >".hexCodedString ($message)."< -> check for SSLv2 is aborted\n"; return ("",$lastMsgType, 0 , ""); } } else { # SSLv3, TLS or DTLS:a parse messages if ($recordType == $RECORD_TYPE {'handshake'}) { $nextMessages = $recordData; while ($nextMessages ne "") { # read and parse all included messages and return the cipher at the end if (($recordVersion & 0xFF00) == $PROTOCOL_VERSION{'SSLv3'}) { #SSL3 , TLS1. ($serverHello{'msg_type'}, # C $serverHello{'msg_len_3rd_byte'}, # C: 3rd, most significant byte $serverHello{'msg_len'}, # n $rest) = unpack("C C n a*", $nextMessages); _trace2_ (sprintf ( "# --> Handshake-Message:\n". "# --> msg_type: >%02X<\n". "# --> msg_len: >%02X%04X<\n", #value with 3 bytes! $serverHello{'msg_type'}, $serverHello{'msg_len_3rd_byte'}, # prefetched for record_type handshake $serverHello{'msg_len'} # prefetched for record_type handshake )); $lastMsgType = $serverHello{'msg_type'} || $HANDSHAKE_TYPE {'<>'}; } elsif ( (($recordVersion & 0xFF00) == $PROTOCOL_VERSION{'DTLSfamily'}) || ($recordVersion == $PROTOCOL_VERSION{'DTLSv09'}) ) { #DTLS1.x or DLSv09 (OpenSSL pre 0.9.8f) ($serverHello{'msg_type'}, # C $serverHello{'msg_len_3rd_byte'}, # C: 3rd, most significant byte $serverHello{'msg_len'}, # n $serverHello{'msg_seqNr'}, # n $serverHello{'fragment_offset_3rd_byte'}, # C (0x00) $serverHello{'fragment_offset'}, # n TBD: verify $serverHello{'fragment_len_3rd_byte'}, # C (0x00) $serverHello{'fragment_len'}, # n TBD: verify $rest) = unpack ("C C n n C n C n a*", $nextMessages); _trace2_ (sprintf ( "# --> Handshake-Message:\n". "# --> msg_type: >%02X<\n". "# --> msg_len: >%02X%04X<\n". # C n: value with 3 bytes! "# --> msg_seqNr: >%04X<\n". # n "# --> fragment_offset: >%02X%04X<\n". # C n: TBD: verify "# --> fragment_len: >%02X%04X<\n", # C n: TBD: verify, $serverHello{'msg_type'}, $serverHello{'msg_len_3rd_byte'}, # prefetched for record_type handshake $serverHello{'msg_len'}, # prefetched for record_type handshake $serverHello{'msg_seqNr'}, # n $serverHello{'fragment_offset_3rd_byte'}, # C (0x00) $serverHello{'fragment_offset'}, # n TBD: verify $serverHello{'fragment_len_3rd_byte'}, # C (0x00) $serverHello{'fragment_len'}, # n TBD: verify, )); ### if ($serverHello{'record_type'} == $RECORD_TYPE {'handshake'}); $lastMsgType = $serverHello{'msg_type'} || $HANDSHAKE_TYPE {'<>'}; if ( ( (defined ($serverHello{'fragment_offset'}) ) && ($serverHello{'fragment_offset'} > 0) ) || ( (defined ($serverHello{'fragment_offset_3rd_byte'}) ) && ($serverHello{'fragment_offset_3rd_byte'} > 0) ) ) { $serverHello{'fragment_offset'} |= $serverHello{'fragment_offset_3rd_byte'} <<16 if ($serverHello{'fragment_offset_3rd_byte'} > 0); _trace ("parseHandshakeRecord: $host:$port: Received a huge fragment offset of $serverHello{'fragment_offset'} bytes\n") if ($serverHello{'fragment_offset_3rd_byte'} > 0); $my_error= "$host:$port: sorry, fragmented DTLS packets are not yet supported -> Retry"; ####TBD TBD TBD ### _trace2 ("parseHandshakeRecord: $my_error\n"); carp ("parseHandshakeRecord: $my_error"); return ("", $lastMsgType, 0, ""); } $serverHello{'fragment_len'} |= $serverHello{'fragment_len_3rd_byte'} <<16 if ($serverHello{'fragment_len_3rd_byte'} > 0); _trace ("parseHandshakeRecord: >>>WARNING: $host:$port: Received a huge fragment with $serverHello{'fragment_len'} bytes\n") if ($serverHello{'fragment_len_3rd_byte'} > 0); carp ("parseHandshakeRecord: >>>WARNING: $host:$port: Received a huge fragment with $serverHello{'fragment_len'} bytes\n") if ($serverHello{'fragment_len_3rd_byte'} > 0); } $serverHello{'msg_len'} |= $serverHello{'msg_len_3rd_byte'} <<16 if ($serverHello{'msg_len_3rd_byte'} > 0); if (length ($rest) < $serverHello{'msg_len'}) { #The message is fragmented .... rare, but it may occur # fragmented message -> Read next Packet, parse the packet Haeder go on with the message) ## fragmented message (real length is shorter than the claimed length); test with STARTTLS at smtp.rzone.de:25 -> and receive a very long Certificate Request # test huge messages using '10000-sans.badssl.com' (https) _trace2_ ("parseHandshakeRecord: Server '$host:$port': Received a huge message with $serverHello{'msg_len'} bytes\n") if ($serverHello{'msg_len_3rd_byte'} > 0); _trace2_ ("parseHandshakeRecord: fragmented message with $serverHello{'msg_len'} bytes length -> get next record\n"); return ($nextMessages, $HANDSHAKE_TYPE {'<>'}, $serverHello{'cookie_length'}, $serverHello{'cookie'}); } _trace ("parseHandshakeRecord: >>> WARNING: Server '$host:$port': Received a huge message with $serverHello{'msg_len'} bytes\n") if ($serverHello{'msg_len_3rd_byte'} > 0); carp ("parseHandshakeRecord: >>> WARNING: Server '$host:$port': Received a huge message with $serverHello{'msg_len'} bytes\n") if ($serverHello{'msg_len_3rd_byte'} > 0); ($message, #a[$serverHello{'msg_len'}] $nextMessages) = unpack("a[$serverHello{'msg_len'}] a*", $rest); _trace4_ ( sprintf ( "# ---> message [len= %d]: >%s<\n", length ($message), #real length hexCodedString ($message, " ") )); # parse several messages types (only those that we do need....) if ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'server_hello'}) { ### Serever Hello -> to get the cipher and some supported extensions (planned) _trace2_ ("# --> Handshake type: Server Hello (22)\n"); $cipher = parseTLS_ServerHello ($host, $port, $message, $serverHello{'msg_len'},$client_protocol); $lastCipher = $cipher; # to link further Information to this cipher # return (parseTLS_ServerHello ($host, $port, $message, $serverHello{'msg_len'},$client_protocol),$lastMsgType, 0,""); # moved bebind the 'while-loop' _trace2_ ("# ==> found cipher: >0x0300".hexCodedCipher($cipher)."<\n"); } elsif ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'hello_verify_request'}) { # DTLS only: get the Cookie to resend the request if (length($message) >= 3) { ($serverHello{'version'}, # n $serverHello{'cookie_length'}, # C $rest) = unpack("n C a*", $message); $serverHello{'cookie'} = ""; ($serverHello{'cookie'}, # a[$serverHello{'cookie_length'} $rest) = unpack("a[$serverHello{'cookie_length'}] a*", $rest) if ($serverHello{'cookie_length'} > 0) ; _trace2_ ( sprintf ( #added to check the supported Version "# --> version: >%04X<\n". "# --> cookie_length: >%02X<\n". # C "# --> cookie: >%s<\n", # a[$serverHello{'cookie_length'} $serverHello{'version'}, $serverHello{'cookie_length'}, # C hexCodedString ($serverHello{'cookie'}) # a[$serverHello{'cookie_length'} )); if (length ($serverHello{'cookie'}) != $serverHello{'cookie_length'}) { $my_error = "Server '$host:$port': DTLS-HelloVerifyRequest: Len of Cookie (".length ($serverHello{'cookie'}).") <> 'cookie_length' ($serverHello{'cookie_length'})"; $serverHello{'cookie_length'} = length ($serverHello{'cookie'}); carp ("parseHandshakeRecord: $my_error"); } if ($serverHello{'cookie_length'} > 32) { $my_error = "Server '$host:$port': DTLS-HelloVerifyRequest: 'cookie_length' ($serverHello{'cookie_length'}) out of Range <0..32)"; carp ("parseHandshakeRecord: $my_error"); } return ("", $lastMsgType, $serverHello{'cookie_length'}, $serverHello{'cookie'}); } } elsif ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'server_key_exchange'}) { ##### Server Key Exchange: to check DHE und ECDHE parameters _trace2 ("parseHandshakeRecord: Cipher: ".hexCodedCipher ($lastCipher)."\n"); $keyExchange = $cipherHexHash {'0x0300'.hexCodedCipher($lastCipher)}[0]; if (defined ($keyExchange)) { # found a cipher _trace2_ (" --> Cipher(1): $keyExchange\n"); $keyExchange =~ s/((?:EC)?DHE?)_anon.*/A$1/x; # DHE_anon -> EDH, ECDHE_anon -> AECDH, DHE_anon -> ADHE _trace4_ (" --> Cipher(2): $keyExchange\n"); $keyExchange =~ s/((?:EC)?DH)E.*/E$1/x; # DHE -> EDH, ECDHE -> EECDH _trace4_ (" --> Cipher(3): $keyExchange\n"); $keyExchange =~ s/^(?:EXP[_-])?(?:E|A|EA)((?:EC)?DH).*/$1/x; # EDH -> DH, ADH -> DH, EECDH -> ECDH _trace2_ (" --> KeyExchange (DH or ECDH) = $keyExchange\n"); # => ECDH or DH # $_SSLhello {hexCodedString($pduVersion)."\|".$sni."\|".hexCodedCipher($lastCipher)."\|ServerKey"} = parseServerKeyExchange ($keyExchange, length($message), $message); $_SSLhello {'0x0300'.hexCodedCipher($lastCipher)."\|ServerKey"} = parseServerKeyExchange ($keyExchange, length($message), $message); if (defined ($_SSLhello {'0x0300'.hexCodedCipher($lastCipher)."\|ServerKey"})) { _trace2_("\n parseHandshakeRecord: Cipher:".hexCodedCipher ($lastCipher)." -> DH_serverParam: ".$_SSLhello {'0x0300'.hexCodedCipher($lastCipher)."\|ServerKey"}); } } else { # no cipher found _trace2 ("parseHandshakeRecord: No name found for cipher: >0x3000".hexCodedCipher($lastCipher)."< -> counld NOT check the ServerKeyExchange\n"); $_SSLhello{'0x0300'.hexCodedCipher($lastCipher)."\|ServerKey"} = "---unknown--"; } } elsif ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'certificate'}) { _trace2("parseHandshakeRecord: MessageType \"Certificate\" = ".sprintf("0x%02X", $serverHello{'msg_type'}) . " not yet analyzed\n"); } elsif ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'certificate_request'}) { _trace2("parseHandshakeRecord: MessageType \"Certificate request\" = ".sprintf("0x%02X", $serverHello{'msg_type'}) . " not yet analyzed\n"); } elsif ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'server_hello_done'}) { _trace4("parseHandshakeRecord: MessageType \"ServerHelloDone\" = ".sprintf("0x%02X", $serverHello{'msg_type'}) . " -> Final hello Message\n"); last; # hello message phase of the handshake is completed } else { _trace2("parseHandshakeRecord: MessageType ".sprintf("%02X", $serverHello{'msg_type'}) . " not yet analyzed\n"); } _trace2_("\n"); # next message } # while (nextMessages ne ""() return ($cipher,$lastMsgType, 0,""); } elsif ($recordType == $RECORD_TYPE {'alert'}) { $serverHello{'msg_type'} = 0; # NO Handshake => set 0 $serverHello{'msg_len_3rd_byte'} = 0; # NO Handshake => set 0 $serverHello{'msg_len'} = 0; # NO Handshake => set 0 $serverHello{'fragment_3rd_byte'} = 0; # NO Handshake => set 0 $serverHello{'fragment_offset'} = 0; # NO Handshake => set 0 $serverHello{'fragment_3rd_byte'} = 0; # NO Handshake => set 0 $serverHello{'fragment_len'} = 0; # NO Handshake => set 0 ($serverHello{'level'}, # C $serverHello{'description'} # C ) = unpack("C C", $recordData); # parse alert messages if ($TLS_AlertDescription {$serverHello{'description'}} ) { # defined, no Null-String $description = $TLS_AlertDescription {$serverHello{'description'}}[0]." ".$TLS_AlertDescription {$serverHello{'description'}}[2]; } else { $description = "Unknown/Undefined"; } _trace2_ ("# --> Alert Message (Record type 21):\n"); _trace2_ ("# --> Level: $serverHello{'level'}\n"); _trace2_ ("# --> Description: $serverHello{'description'} ($description)\n"); if ($recordVersion == 0x0000) { # some servers use this dummy version to indicate that the requested version is not supported if (! defined $ssl_client) { $ssl_client = "--unknown protocol--"; } OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'parse alert record (1)', message => sprintf ("unsupported protocol $ssl_client (0x%04X) by $host:$port, answered with (0x%04X)", $client_protocol, $recordVersion), warn => 0, } ); return ("", $lastMsgType, 0 , ""); } # error handling according to # http://www.iana.org/assignments/tls-parameters/tls-parameters-6.csv unless ( ($serverHello{'level'} == 2) && ( ($serverHello{'description'} == 40) # handshake_failure(40): usually cipher not found is suppressed || ($serverHello{'description'} == 71) # insufficient_security(71): no (secure) cipher found, is suppressed ) ) { if ($serverHello{'level'} == 1) { # warning if ($serverHello{'description'} == 112) { #SNI-Warning: unrecognized_name if ( ($Net::SSLhello::usesni) && !( ( ($client_protocol == $PROTOCOL_VERSION{'SSLv3'}) && (!$Net::SSLhello::force_TLS_extensions) ) || ($client_protocol == $PROTOCOL_VERSION{'SSLv2'}) ) ) { # SNI sent $sni = ""; unless ($Net::SSLhello::use_sni_name) { $sni = "'$host'"; # Server Name, should be a Name no IP } else { # different sni_name $sni = ($Net::SSLhello::sni_name) ? "'$Net::SSLhello::sni_name'" : "''"; # allow empty nonRFC-SNI-Names } $my_error = sprintf ("parseHandshakeRecord: Server '$host:$port' ($ssl_client): received SSL/TLS warning: Description: $description ($serverHello{'description'}) -> check of virtual server $sni aborted!\n"); _trace4 ($my_error); carp ("**WARNING: $my_error\n"); } else { # NO SNI extension sent $my_error = sprintf ("parseHandshakeRecord: Server '$host:$port' ($ssl_client): received SSL/TLS warning: Description: $description ($serverHello{'description'}), but NO SNI extension has been sent. -> check of server aborted!"); _trace4 ($my_error); carp ("**WARNING: $my_error\n"); _hint ("Server seens to to be a virtual server, consider adding the option '--sni' (Server Name Indication)for TLSv1 and higher"); } return ("", $lastMsgType, 0 , ""); } else { carp ("**WARNING: parseHandshakeRecord: Server '$host:$port' ($ssl_client): received SSL/TLS warning (1): Description: $description ($serverHello{'description'})\n"); } } elsif ($serverHello{'level'} == 2) { # fatal if ($serverHello{'description'} == 70) { # protocol_version(70): (old) protocol recognized but not supported, is suppressed OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'parse alert record (2)', message => sprintf ("unsupported protocol $ssl_client (0x%04X) by $host:$port: received a SSL/TLS-Warning: Description: $description ($serverHello{'description'})", $client_protocol), warn => 0, } ); } elsif ($serverHello{'description'} == 112) { #SNI-Warning: unrecognized_name if ( ($Net::SSLhello::usesni) && !( ( ($client_protocol == $PROTOCOL_VERSION{'SSLv3'}) && (!$Net::SSLhello::force_TLS_extensions) ) || ($client_protocol == $PROTOCOL_VERSION{'SSLv2'}) ) ) { # SNI sent $sni = ""; unless ($Net::SSLhello::use_sni_name) { $sni = "'$host'" if ($Net::SSLhello::usesni); # Server Name, should be a Name no IP } else { # different sni_name $sni = ($Net::SSLhello::sni_name) ? "'$Net::SSLhello::sni_name'" : "''"; # allow empty nonRFC-SNI-Names } $my_error = sprintf ("parseHandshakeRecord: Server '$host:$port' ($ssl_client): received fatal SSL/TLS error (2a): Description: $description ($serverHello{'description'}) -> check of virtual server $sni aborted!\n"); _trace4 ($my_error); carp ("**WARNING: $my_error\n"); } else { # NO SNI extension sent $my_error = sprintf ("parseHandshakeRecord: Server '$host:$port' ($ssl_client): received fatal SSL/TLS error (2b): Description: $description ($serverHello{'description'}), but NO SNI extension has been sent. -> check of server aborted!"); _trace4 ($my_error); carp ("**WARNING: $my_error\n"); _hint ("Server seens to to be a virtual server, consider adding the option '--sni' (Server Name Indication)for TLSv1 and higher"); } return ("", $lastMsgType, 0 , ""); } else { _trace4 ($my_error); carp ("**WARNING: parseHandshakeRecord: Server '$host:$port' ($ssl_client): received fatal SSL/TLS error (2c): Description: $description ($serverHello{'description'})\n"); if ($serverHello{'description'} == 50) { # decode_error (50) _hint("The server may not support the extension for elliptic curves (ECC) nor discard it silently, consider adding the option '--ssl-nouseecc'."); } } } else { # unknown carp ("**WARNING: parseHandshakeRecord: Server '$host:$port' ($ssl_client): received unknown SSL/TLS error level ($serverHello{'level'}): Description: $description ($serverHello{'description'})\n"); } } } else { ################################ to get information about record types that are not parsed, yet ############################# _trace_ ("\n"); carp ("**WARNING: parseHandshakeRecord: Server '$host:$port': Unknown SSL/TLS record type received that is not (yet) defined in Net::SSLhello.pm:\n"); carp ("# Record type: Unknown value (0x".hexCodedString($recordType)."), not (yet) defined in Net::SSLhello.pm\n"); carp ("# Record version: $recordVersion (0x".hexCodedString ($recordVersion).")\n"); carp ("# Record len: $recordLen (0x".hexCodedString ($recordLen).")\n\n"); } return ("", $lastMsgType, 0 , ""); } #End SSL3/TLS or DTLS } else { carp ("**WARNING: parseHandshakeRecord: Server '$host:$port': (no SSL/TLS record) : ".hexCodedString ($recordData)."\n"); return ("",$lastMsgType, 0 , ""); } carp ("**WARNING: parseHandshakeRecord: Server '$host:$port': Internal error: ".hexCodedString ($recordData)."\n"); return ("",$lastMsgType, 0 , ""); } # parseHandshakeRecord sub parseServerHello ($$$;$) { #? FIXME: <> <> # Variable: String/Octet, dass das Server-Hello-Paket enthält ; second (opional) variable: protocol-version, that the client uses my $host = shift || ""; # for carp- and trace messages my $port = shift || ""; # for carp- and trace messages my $buffer = shift || ""; my $client_protocol = shift || ""; # optional my $rest = ""; my $tmp_len = 0; my $message = ""; my $nextMessages = ""; my %serverHello; my $description = ""; local $my_error = ""; if (length ($buffer) >=5) { # received data in the buffer, at least 5 bytes my $firstByte = unpack ("C", $buffer); if (defined $client_protocol) { _trace2("parseServerHello: Server '$host:$port': (expected protocol= >".sprintf ("%04X", $client_protocol)."<,\n >".hexCodedString (substr($buffer,0,48)," ")."< ...)\n"); } else { _trace2("parseServerHello: Server '$host:$port': (any protocol,\n Data=".hexCodedString (substr($buffer,0,48)," ").")... \n"); } _trace4 (sprintf ("parseServerHello: Server '$host:$port': 1. Byte: %02X\n\n", $firstByte) ); if ($firstByte >= 0x80) { # SSL2 with 2 byte Length _trace2_ ("# -->SSL: Message type SSL2-Msg"); ($serverHello{'msg_len'}, # n $serverHello{'msg_type'}, # C $rest) = unpack("n C a*", $buffer); $serverHello{'msg_len'} -= 0x8000; # delete MSB _trace2_ (sprintf ( "# --> ParseServerHello(1):\n". "# --> msg_len: >%04X<\n". "# --> msg_type: >%02X<\n", $serverHello{'msg_len'}, $serverHello{'msg_type'} )); _trace4 ("parseServerHello: Server '$host:$port': Rest: >".hexCodedString ($rest)."<\n"); if ($serverHello{'msg_type'} == $SSL_MT_SERVER_HELLO) { _trace4 (" Handshake Protocol: SSL2 Server Hello\n"); _trace4 (" Message Type: (Server Hello (2)\n"); return (parseSSL2_ServerHello ($host, $port, $rest,$client_protocol)); # cipher_spec-Liste } elsif ($serverHello{'msg_type'} == $SSL_MT_ERROR) { #TBD error handling for ssl2 ($serverHello{'err_code'} # n ) = unpack("n", $rest); _trace2 ("parseServerHello: Server '$host:$port': received a SSLv2-Error-Message, Code: >0x".hexCodedString ($serverHello{'err_code'})."<\n"); unless ($serverHello{'err_code'} == 0x0001) { # SSLV2_No_Cipher carp ("**WARNING: parseServerHello: Server '$host:$port': received a SSLv2-Error_Message: , Code: >0x".hexCodedString ($serverHello{'err_code'})." -> Target Ignored\n"); } return (""); } else { # if ($serverHello{'msg_type'} == 0 => NOT supported protocol (?!) $my_error = " Unknown SSLv2 message type (Dez): ".$serverHello{'msg_type'}.", Msg: >".hexCodedString ($buffer)."< -> Target Ignored\n"; } return (""); } else { # TLS record _trace2_("# -->TLS record layer:\n"); ($serverHello{'record_type'}, # C $serverHello{'record_version'}, # n $serverHello{'record_len'}, # n ### perhaps this could be a good point to start a new function to parse a Message => to check certificates etc later### $serverHello{'msg_type'}, # C $serverHello{'msg_len_3rd_byte'}, # C $serverHello{'msg_len'}, # n $rest) = unpack("C n n C C n a*", $buffer); if ($serverHello{'record_type'} == $RECORD_TYPE {'handshake'}) { _trace2_ (sprintf ( "# --> => SSL3/TLS record type: Handshake (%02X):\n". "# --> record_version: >%04X<\n". "# --> record_len: >%04X<\n". "# --> msg_type: >%02X<\n". "# --> msg_len: >%02X%04X<\n", $serverHello{'record_type'}, $serverHello{'record_version'}, $serverHello{'record_len'}, $serverHello{'msg_type'}, $serverHello{'msg_len_3rd_byte'}, # prefetched for record_type handshake $serverHello{'msg_len'} # prefetched for record_type handshake )); $serverHello{'msg_len'} |= $serverHello{'msg_len_3rd_byte'} <<16 if ($serverHello{'msg_len_3rd_byte'} > 0); _trace ("parseServerHello: >>> WARNING: Server '$host:$port': Received a huge message with $serverHello{'msg_len'} bytes\n") if ($serverHello{'msg_len_3rd_byte'} > 0); carp ("parseServerHello: >>> WARNING: Server '$host:$port': Received a huge message with $serverHello{'msg_len'} bytes\n") if ($serverHello{'msg_len_3rd_byte'} > 0); ($message, #a[$serverHello{'msg_len'}] $nextMessages) = unpack("a[$serverHello{'msg_len'}] a*", $rest); _trace4_ ( sprintf ( "# ---> message: >%s<\n", hexCodedString ($message) )); if ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'server_hello'}) { _trace3_ ("# --> Handshake type: Server Hello (22)\n"); _trace4_ ("# ---> Handshake type: Server Hello (22)\n"); return (parseTLS_ServerHello ($host, $port, $message, $serverHello{'msg_len'},$client_protocol)); } } elsif ($serverHello{'record_type'} == $RECORD_TYPE {'alert'}) { _trace2_ ("# --> Record type: Alert (21)\n"); _trace2_ (sprintf("# --> Record version: $serverHello{'record_version'} (0x%04X)\n",$serverHello{'record_version'})); _trace2_ (sprintf("# --> Record len: $serverHello{'record_len'} (0x%04X)\n",$serverHello{'record_len'})); $serverHello{'msg_type'} = 0; # KEIN Handshake = löschen $serverHello{'msg_len_3rd_byte'} = 0; # KEIN Handshake = löschen $serverHello{'msg_len'} = 0; # KEIN Handshake = löschen ($serverHello{'level'}, # C $serverHello{'description'} # C ) = unpack("x5 C C", $buffer); # Workaroud, da oben zu viel gelesen wird if ($TLS_AlertDescription {$serverHello{'description'}} ) { # defined, no Null-String $description = $TLS_AlertDescription {$serverHello{'description'}}[0]." ".$TLS_AlertDescription {$serverHello{'description'}}[2]; } else { $description = "Unknown/Undefined"; } _trace2_ ("# --> Alert Message:\n"); _trace2_ ("# --> Level: $serverHello{'level'}\n"); _trace2_ ("# --> Description: $serverHello{'description'} ($description)\n"); if ($serverHello{'record_version'} == 0x0000) { # some servers use this dummy version to indicate that the requested version is not supported my %rhash = reverse %PROTOCOL_VERSION; my $ssl_client = $rhash{$client_protocol}; if (! defined $ssl_client) { $ssl_client = "--unknown protocol--"; } $my_error = sprintf ("parseServerHello: Server '$host:$port': requested protocol $ssl_client (0x%04X) is not supported by the Server (the server answered with the protocol 0x%04X) -> protocol_version recognized but not supported!", $client_protocol, $serverHello{'record_version'}); _trace2 ("$my_error\n"); return (""); } # error handling according to # http://www.iana.org/assignments/tls-parameters/tls-parameters-6.csv unless ( ($serverHello{'level'} == 2) && ( ($serverHello{'description'} == 40) # handshake_failure(40): usually cipher not found is suppressed || ($serverHello{'description'} == 71) # insufficient_security(71): no (secure) cipher found, is suppressed ) ) { if ($serverHello{'level'} == 1) { # warning if ($serverHello{'description'} == 112) { #SNI-Warning: unrecognized_name my $sni = ""; $Net::SSLhello::use_sni_name = 1 if ( ($Net::SSLhello::use_sni_name == 0) && ($Net::SSLhello::sni_name ne "1") ); ###FIX: quickfix until migration of o-saft.pl is compleated (tbd) unless ($Net::SSLhello::use_sni_name) { $sni = "'$host'" if ($Net::SSLhello::usesni); # server name, should be a name no IP } else { # different sni_name $sni = ($Net::SSLhello::sni_name) ? "'$Net::SSLhello::sni_name'" : "''"; # allow empty nonRFC-SNI-Names } $my_error = sprintf ("parseServerHello: Server '$host:$port': received SSL/TLS-Warning: Description: $description ($serverHello{'description'}) -> check of virtual Server $sni aborted!\n"); print $my_error; return (""); } else { carp ("**WARNING: parseServerHello: Server '$host:$port': received SSL/TLS-Warning (1): Description: $description ($serverHello{'description'})\n"); } } elsif ($serverHello{'level'} == 2) { # fatal if ($serverHello{'description'} == 70) { # protocol_version(70): (old) protocol recognized but not supported, is suppressed $my_error = sprintf ("parseServerHello: Server '$host:$port': received SSL/TLS-Warning: Description: $description ($serverHello{'description'}) -> protocol_version recognized but not supported!\n"); } else { carp ("**WARNING: parseServerHello: Server '$host:$port': received fatal SSL/TLS-Error (2): Description: $description ($serverHello{'description'})\n"); if ($serverHello{'description'} == 50) { # decode_error (50) _hint("The server may not support the extension for elliptic curves (ECC) nor discard it silently, consider adding the option '--ssl-nouseecc'."); } } } else { # unknown carp ("**WARNING: parseServerHello: Server '$host:$port': received unknown SSL/TLS-Error-Level ($serverHello{'level'}): Description: $description ($serverHello{'description'})\n"); } } } else { ################################ to get information about record types that are not parsed, yet ############################# _trace_ ("\n"); carp ("**WARNING: parseServerHello: Server '$host:$port': Unknown SSL/TLS record type received that is not (yet) defined in Net::SSLhello.pm:\n"); carp ("# Record type: Unknown value (".$serverHello{'record_type'}."), not (yet) defined in Net::SSLhello.pm\n"); carp ("# Record version: $serverHello{'record_version'} (0x".hexCodedString ($serverHello{'record_version'}).")\n"); carp ("# Record len: $serverHello{'record_len'} (0x".hexCodedString ($serverHello{'record_len'}).")\n\n"); } return (""); } #End SSL3/TLS } else { carp ("**WARNING: parseServerHello Server '$host:$port': (no SSL/TLS record) : ".hexCodedString ($buffer)."\n"); } return; } # parseServerHello sub parseSSL2_ServerHello ($$$;$) { #? FIXME: <> <> # Variable: String/Octet, das den Rest des Server-Hello-Pakets enthält my $host = shift || ""; # for warn- and trace messages my $port = shift || ""; # for warn- and trace messages my $buffer = shift || ""; my $client_protocol = shift || ""; # optional my $rest; my %serverHello; $serverHello{'cipher_spec'} = ""; if (defined $client_protocol) { _trace3("parseSSL2_ServerHello: Server '$host:$port': (expected protocol=".sprintf ("%04X", $client_protocol).", Data=".hexCodedString (substr($buffer,0,48)," ")."...)\n"); } else { _trace4("parseSSL2_ServerHello: Server '$host:$port': (any protocol, Data=".hexCodedString (substr($buffer,0,48)," ")."...)\n"); } ($serverHello{'session_id_hit'}, # C $serverHello{'certificate_type'}, # C $serverHello{'version'}, # n $serverHello{'certificate_len'}, # n $serverHello{'cipher_spec_len'}, # n $serverHello{'connection_id_len'}, # n $rest) = unpack("C C n n n n a*", $buffer); _trace2_ ( sprintf ( "# --> => SSL2: ServerHello (%02X):\n". "# --> session_id_hit: >%02X<\n". "# --> certificate_type: >%02X<\n". "# --> version: >%04X<\n". "# --> certificate_len: >%04X<\n". "# --> cipher_spec_len: >%04X<\n". "# --> connection_id_len: >%04X<\n", $SSL_MT_SERVER_HELLO, $serverHello{'session_id_hit'}, $serverHello{'certificate_type'}, $serverHello{'version'}, $serverHello{'certificate_len'}, $serverHello{'cipher_spec_len'}, $serverHello{'connection_id_len'} )); _trace4 ("Rest: Server '$host:$port': >".hexCodedString ($rest)."<\n"); ( $serverHello{'certificate'}, # n $serverHello{'cipher_spec'}, # n $serverHello{'connection_id'} # n ) = unpack("a[$serverHello{'certificate_len'}] a[$serverHello{'cipher_spec_len'}] a[$serverHello{'connection_id_len'}]", $rest); _trace4 ("parseSSL2_ServerHello(2): Server '$host:$port':\n"); _trace2_ ( sprintf ( "# --> certificate: >%s<\n". # n "# --> cipher_spec: >%s<\n". # n "# --> connection_id: >%s<\n". # n "# --> parseServerHello-Cipher:\n", # headline for next actions hexCodedString ($serverHello{'certificate'}), hexCodedString ($serverHello{'cipher_spec'}," "), hexCodedString ($serverHello{'connection_id'}) )); if ($Net::SSLhello::trace >= 3) { #trace3+4: added to check the supported version printf "## Server Server '$host:$port': accepts the following Ciphers with SSL-Version: >%04X<\n", $serverHello{'version'}; printSSL2CipherList($serverHello{'cipher_spec'}); print "\n"; } ### added to check if there is a bug in getting the cipher_spec if (length ($serverHello{'cipher_spec'}) != int ($serverHello{'cipher_spec_len'}) ) { # did not get all ciphers? carp("**WARNING: parseSSL2_ServerHello: Server '$host:$port': Can't get all Ciphers from Server-Hello (String-Len: ".length ($serverHello{'cipher_spec'})." != cipher_spec_len: ".$serverHello{'cipher_spec_len'}."): >". hexCodedSSL2Cipher ($serverHello{'cipher_spec'})."<"); printf "# => SSL2: ServerHello (%02X):\n". "# session_id_hit: >%02X<\n". "# certificate_type: >%02X<\n". "# version: >%04X<\n". "# certificate_len: >%04X<\n". "# cipher_spec_len: >%04X<\n". "# connection_id_len: >%04X<\n", $SSL_MT_SERVER_HELLO, $serverHello{'session_id_hit'}, $serverHello{'certificate_type'}, $serverHello{'version'}, $serverHello{'certificate_len'}, $serverHello{'cipher_spec_len'}, $serverHello{'connection_id_len'}; printf "## certificate: >%s<\n". # n "## cipher_spec: >%s<\n". # n "## connection_id: >%s<\n", # n hexCodedString ($serverHello{'certificate'}), hexCodedString ($serverHello{'cipher_spec'}," "), hexCodedString ($serverHello{'connection_id'}); } return ($serverHello{'cipher_spec'}); } # parseSSL2_ServerHello sub parseTLS_ServerHello { #? parse and get data from a ServerHello message that has been received via SSLv3 or TLS #? according RFC6101 (SSL3), RFC2246 (TLS1), RFC4346 (TLS1.1), RFC5246 (TLS1.2) and draft-ietf-tls-tls13 (TLS1.3) #? FIXME: <> #? Variableis: #? $host and $port: used for error and trave messages #? $buffer: unparsed data of the ServerHello #? $len: Len if the buffer #? $client_protokoll: optional the protocol used by the client # my $host = shift || ""; #for warn- and trace-messages my $port = shift || ""; #for warn- and trace-messages my $buffer = shift || ""; my $len = shift || 0; my $client_protocol = shift || ""; # optional my $rest = ""; my $rest2 = ""; my %serverHello; $serverHello{'cipher_spec'} = ""; $serverHello{'extensions_len'} = 0; #reset error_handler and set basic information for this sub OSaft::error_handler->reset_err( {module => (SSLHELLO), sub => 'parseTLS_ServerHello', print => ($Net::SSLhello::trace > 0), trace => $Net::SSLhello::trace} ); if (defined $client_protocol) { _trace3("parseTLS_ServerHello: Server '$host:$port': (expected protocol=".sprintf ("%04X", $client_protocol).",\n ".hexCodedString (substr($buffer,0,48)," ")."...)\n"); } else { _trace4("parseTLS_ServerHello: Server '$host:$port': (any protocol, Data=".hexCodedString (substr($buffer,0,48)," ")."...)\n"); } if (length($buffer) || $len >= 35) { ($serverHello{'version'}, # n $serverHello{'random_gmt_time'}, # N # A4 $serverHello{'random'}, # A28 $serverHello{'session_id_len'}, # C $rest) = unpack("n N a[28] C a*", $buffer); _trace2_ ( sprintf ( # added to check the supported version "# --> => SSL/TLS-Version: (%04X):\n", $serverHello{'version'} )); if (defined ($client_protocol)) { if ($client_protocol != $serverHello{'version'}) { my %rhash = reverse %PROTOCOL_VERSION; my $ssl_client = $rhash{$client_protocol}; my $ssl_server = $rhash{$serverHello{'version'}}; if (! defined $ssl_client) { $ssl_client = "--unknown protocol--"; } if (! defined $ssl_server) { $ssl_server = "--unknown protocol--"; } if ($serverHello{'version'} == 0) { # some servers respond with the dummy prtotocol '0x0000' if they do *not* support the requested protocol OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'check record protocol (1)', message => sprintf ("unsupported protocol $ssl_client (0x%04X) by $host:$port, answered with $ssl_server (0x%04X)", $client_protocol, $serverHello{'version'}), warn => 0, } ); } else { # unknown protocol OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'check record protocol (2)', message => sprintf ("unsupported protocol $ssl_client (0x%04X) by $host:$port, answered with $ssl_server (0x%04X)", $client_protocol, $serverHello{'version'}), warn => 0, } ); } return (""); } } else { carp ("**WARNING: parseTLS_ServerHello: Server '$host:$port': internal error: All Server Versions are accepted, because there is no information provided which version the client has requested.\n"); } _trace2_ ( sprintf ( "# --> version: >%04X<\n". # "# --> random_gmt_time: >%08X< (%s)\n". "# --> random_gmt_time: >%08X<\n". "# --> random: >%s<\n". "# --> session_id_len: >%02X<\n", $serverHello{'version'}, $serverHello{'random_gmt_time'}, # localtime($serverHello{'random_gmt_time'}), hexCodedString ($serverHello{'random'}), $serverHello{'session_id_len'} )); _trace4_ ( sprintf ( "# --> Rest: (len=%04X) >%s<\n", length ($rest), hexCodedString ($rest, " ") )); ($serverHello{'session_id'}, # A[] $serverHello{'cipher_spec'}, # A2: cipher_spec_len = 2 $serverHello{'compression_method'}, # C $serverHello{'extensions_len'}, # n $rest2) = unpack("a[$serverHello{'session_id_len'}] a2 C n a*", $rest); _trace2_ ( sprintf ( "# --> session_id: >%s<\n". "# --> cipher_spec: (len=%2s) >%s<\n", hexCodedString ($serverHello{'session_id'}), length ($serverHello{'cipher_spec'}), hexCodedCipher ($serverHello{'cipher_spec'}) )); ### added to check if there is a bug in getting the cipher_spec: cipher_spec_len = 2 ### if (length ($serverHello{'cipher_spec'}) != 2 ) { # did not get the 2-Octet-Cipher? carp("**WARNING: parseTLS_ServerHello: Server '$host:$port': Can't get the Cipher from Server-Hello (String-Len: ".length ($serverHello{'cipher_spec'})." != cipher_spec_len: 2): >". hexCodedString ($serverHello{'cipher_spec'})."<"); } _trace2_ ( sprintf ( # added to check the supported version "# --> The Server Server '$host:$port': accepts the following Cipher(s) with SSL3/TLS-Version: >%04X<:\n", $serverHello{'version'} )); if ($Net::SSLhello::trace > 2) { printTLSCipherList ($serverHello{'cipher_spec'}); } _trace2_ ( sprintf ( "\n# --> compression_method: >%02X<\n", $serverHello{'compression_method'} )); if ( $serverHello{'extensions_len'} !~ /(?:^$|[\x00]+)/x) { # extensions_len > 0 ($serverHello{'extensions'}, # A[] $rest) = unpack("a[$serverHello{'extensions_len'}] a*", $rest2); _trace2_ ( sprintf ( "# --> extensions_len: >%04X<\n", $serverHello{'extensions_len'} )); _trace4_ ( sprintf ( "# --> extensions: >%s<\n". "# --> Rest: >%s<\n", hexCodedString ($serverHello{'extensions'}), hexCodedString ($rest) )); parseTLS_Extension ($serverHello{'extensions'}, $serverHello{'extensions_len'}); if (length($rest) > 0) { # should be 0 _trace2 ( sprintf ("\n\n## parseTLSServerHello Server '$host:$port': did not parse the whole message (rest): >".hexCodedString ($rest)."< To Be Done\n")); } } return ($serverHello{'cipher_spec'}); } else { return (""); } } # parseTLS_ServerHello sub parseTLS_Extension { #? FIXME: <> <> # Variable: String/Octet, das die Extension-Bytes enthält my $buffer = shift || ""; my $len = shift || 0; my $rest = ""; my %serverHello; if (length($buffer) || $len >= 2) { ($serverHello{'extension_type'}, # n $serverHello{'extension_type_len'}, # n $rest) = unpack("n n a*", $buffer); _trace2_ ( sprintf ( "# --> extension_type: >%04X<\n". "# --> extension_type_len: >%04X<\n", $serverHello{'extension_type'}, $serverHello{'extension_type_len'} )); if (($rest) && ($serverHello{'extension_type_len'}) ) { ($serverHello{'extension_data'}, # A[] $rest) = unpack("a[$serverHello{'extension_type_len'}] a*", $rest); _trace2_ ( sprintf ( "# --> extension_data: >%s<\n". "# --> Rest: >%s<\n", hexCodedString ($serverHello{'extension_data'}), hexCodedString ($rest) )); if (($rest) && (($len -4 -$serverHello{'extension_type_len'}) >0) ) { parseTLS_Extension ($rest, ($len -4 -$serverHello{'extension_type_len'})); } } } return; } # parseTLS_Extension sub _timedOut { croak "NET::SSLhello: Receive data timed out -> Received NO data (timeout)"; } sub _chomp_r { # chomp \r\n my $string = shift || ""; $string =~ s/(.*?)\r?\n?$/$1/gx; if ($string =~ /[^\x20-\x7E\t\r\n]/x) { # non printable charachers in string $string =~ s/([\x00-\xFF])/sprintf("%02X ", ord($1))/eigx; #Code all Octets as HEX values and seperate then with a 'space' } return ($string); } sub hexCodedString { #? FIXME: <> <> # Variable: String/Octet, der in HEX-Werten dargestellt werden soll, gibt Ausgabestring zurück my $codedString = shift || ""; my $prefix = shift; # set an optional prefix after '\n' return ("") if ($codedString eq ""); if (!defined($prefix)) { # undefined -> "" $prefix = ""; } $codedString =~ s/([\x00-\xFF])/sprintf("%02X ", ord($1))/eigx; # code all octets as HEX values and seperate then with a 'space' $codedString =~ s/((?:[0-9A-Fa-f]{2}\s){48})(?=[0-9A-Fa-f]{2})/"$1\n$prefix"/eigx; # add a new line each 48 HEX-octetts (=144 symbols incl. spaces) if not last octett reached chomp ($codedString); # delete CR at the end chop ($codedString); # delete 'space' at the end return ($codedString); } # hexCodedString sub hexCodedCipher { #? FIXME: <> <> # Variable: String/Octet, der in HEX-Werten dargestellt werden soll, gibt Ausgabestring zurück my $codedString= shift || ""; my $prefix= shift; # set an optional prefix after '\n' return ("") if ($codedString eq ""); if (!defined($prefix)) { # undefined -> "" $prefix = ""; } $codedString =~ s/([\x00-\xFF])/sprintf("%02X", ord($1))/eigx; # code all octets as HEX values and seperate then with a 'space' $codedString =~ s/((?:[0-9A-Fa-f]{2}){64})/"$1\n$prefix"/eigx; # add a new line each 64 HEX octetts (=128 symbols incl. spaces) chomp ($codedString); #delete CR at the end return ($codedString); #delete 'space' at the end } # hexCodedCipher sub hexCodedSSL2Cipher { #? FIXME: <> <> # Variable: String/Octet, der in HEX-Werten dargestellt werden soll, gibt Ausgabestring zurück my $codedString = shift || ""; my $prefix = shift; # set an optional prefix after '\n' return ("") if ($codedString eq ""); if (!defined($prefix)) { # undefined -> "" $prefix = ""; } $codedString =~ s/([\x00-\xFF])([\x00-\xFF])([\x00-\xFF])/sprintf("%02X%02X%02X ", ord($1), ord($2), ord($3))/eigx; #Code all 3-Octet-Ciphers as HEX value-Pairs and separate then with a 'space' $codedString =~ s/((?:[0-9A-Fa-f]{6}){16}\s)/"$1\n$prefix"/eigx; # add a new line each 16 ciphers (=112 symbols incl. spaces) chomp ($codedString); #delete CR at the end return ($codedString); #delete 'space' at the end } sub hexCodedTLSCipher { #? FIXME: <> <> # Variable: String/Octet, der in HEX-Werten dargestellt werden soll, gibt Ausgabestring zurück my $codedString = shift || ""; my $prefix = shift; # set an optional prefix after '\n' return ("") if ($codedString eq ""); if (!defined($prefix)) { # undefined -> "" $prefix = ""; } $codedString =~ s/([\x00-\xFF])([\x00-\xFF])/sprintf("%02X%02X ", ord($1), ord($2))/eigx; # code all 2-Octet-Ciphers as HEX value pairs and separate then with a 'space' $codedString =~ s/((?:[0-9A-Fa-f]{4}){16}\s)/"$1\n$prefix"/eigx; # add a new line each 16 ciphers (=80 symbols incl. spaces) chomp ($codedString); # delete CR at the end return ($codedString); # delete 'space' at the end } # hexCodedSSL2Cipher sub compileSSL2CipherArray ($) { #? FIXME: <> <> my $cipherList = shift || ""; my $protocolCipher=""; my $firstByte = ""; my @cipherArray = (); my $anzahl = int length ($cipherList) / 3; my @cipherTable = unpack("a3" x $anzahl, $cipherList); _trace4 ("compileSSL2CipherArray ($anzahl) {\n"); for (my $i = 0; $i < $anzahl; $i++) { _trace4_ ( sprintf (" Cipher[%2d]: ", $i)); _trace4_ ( sprintf (" >".hexCodedSSL2Cipher ($cipherTable[$i])."< -> ")); $firstByte = unpack ("C", $cipherTable[$i]); _trace4_ ( sprintf ("1. Byte: %02X -> ", $firstByte)); if ($firstByte == 0x00) { # Version 3 Cipher 0x00xxxx $protocolCipher = pack ("a4a*", "0x03", hexCodedCipher($cipherTable[$i])); } else { # V2Cipher $protocolCipher = pack ("a4a*", "0x02", hexCodedCipher($cipherTable[$i])); } if ($Net::SSLhello::trace > 2) { if ($cipherHexHash {$protocolCipher} ) { # defined, no Null-String _trace_ (sprintf "%s -> %-32s -> %s", $protocolCipher, $cipherHexHash {$protocolCipher}[1], $cipherHexHash {$protocolCipher}[0]); } else { _trace_ ("$protocolCipher"." -> NO-RFC-".$protocolCipher); } _trace4_ ("\n"); } push (@cipherArray, $protocolCipher); # add protocolCipher to Array } _trace4 ("compileSSL2CipherArray: }\n"); return (@cipherArray); } # compileSSL2CipherArray sub compileTLSCipherArray ($) { #? FIXME: <> <> my $cipherList = shift || ""; my $protocolCipher = ""; my $firstByte = ""; my @cipherArray = (); my $anzahl = int length ($cipherList) / 2; my @cipherTable = unpack("a2" x $anzahl, $cipherList); _trace4 ("compileTLSCipherArray ($anzahl):\n"); for(my $i = 0; $i < $anzahl; $i++) { _trace4_ (sprintf (" Cipher[%2d]: ", $i)); _trace4_ (sprintf (" >".hexCodedCipher ($cipherTable[$i])."< -> ")); $protocolCipher = pack ("a6a*", "0x0300", hexCodedCipher($cipherTable[$i])); if ($Net::SSLhello::trace > 2) { if ( (defined ($cipherHexHash {$protocolCipher})) && ($#{$cipherHexHash {$protocolCipher}}>0) ) { # definiert, max index >0 _trace4_ (sprintf ("%s -> %-32s -> %s", $protocolCipher, $cipherHexHash {$protocolCipher}[1], $cipherHexHash {$protocolCipher}[0])); } else { _trace4_ ("$protocolCipher -> NO-RFC-".$protocolCipher); } _trace4_ ("\n"); } push (@cipherArray, $protocolCipher); # add protocolCipher to array } _trace4 ("compileTLSCipherArray: }\n"); return (@cipherArray); } # compileTLSCipherArray sub printSSL2CipherList ($) { #? FIXME: <> <> my $cipherList = shift || ""; my $protocolCipher = ""; my $firstByte = ""; my $anzahl = int length ($cipherList) / 3; my @cipherTable = unpack("a3" x $anzahl, $cipherList); local $\ = ""; # no auto '\n' at the end of the line if ($Net::SSLhello::trace > 3) { _trace4 ("printSSL2CipherList ($anzahl):\n"); for (my $i = 0; $i < $anzahl; $i++) { _trace4_ ( sprintf (" Cipher[%2d]: ", $i)); _trace4_ (" >".hexCodedCipher ($cipherTable[$i])."< -> "); $firstByte = unpack ("C", $cipherTable[$i]); _trace4_ (sprintf (" 1. Byte: %02X -> ", $firstByte)); if ($firstByte == 0x00) { # Version 3 Cipher 0x00xxxx $protocolCipher = pack ("a4a*", "0x03", hexCodedCipher($cipherTable[$i])); } else { # V2Cipher $protocolCipher = pack ("a4a*", "0x02", hexCodedCipher($cipherTable[$i])); } if ( (defined ($cipherHexHash {$protocolCipher})) && ($#{$cipherHexHash {$protocolCipher}}>0) ) { # definiert, max index >0 _trace4_ (sprintf ("%s -> %-32s -> %s", $protocolCipher, $cipherHexHash {$protocolCipher}[1], $cipherHexHash {$protocolCipher}[0])); } else { _trace4_ ("$protocolCipher -> NO-RFC-".$protocolCipher); } _trace_ "\n"; } _trace_ "\n"; } return; } # printSSL2CipherList sub printTLSCipherList ($) { #? FIXME: <> <> my $cipherList = shift || ""; my $protocolCipher = ""; my $anzahl = int length ($cipherList) / 2; my @cipherTable = unpack("a2" x $anzahl, $cipherList); local $\ = ""; # no auto '\n' at the end of the line # if ($Net::SSLhello::trace > 2) if ($Net::SSLhello::trace > 1) { _trace4 ("printTLSCipherList ($anzahl):\n"); for(my $i = 0; $i < $anzahl; $i++) { _trace4_ (sprintf(" Cipher[%2d]: ", $i)); _trace4_ (" >".hexCodedCipher ($cipherTable[$i])."< -> "); $protocolCipher = pack ("a6a*", "0x0300", hexCodedCipher($cipherTable[$i])); if ( (defined ($cipherHexHash {$protocolCipher})) && ($#{$cipherHexHash {$protocolCipher}}>0) ) { # definiert, max index >0 _trace_ (sprintf "%s -> %-32s -> %s", $protocolCipher, $cipherHexHash {$protocolCipher}[1], $cipherHexHash {$protocolCipher}[0]); } else { _trace_ ("$protocolCipher -> NO-RFC-".$protocolCipher); } _trace4_ "\n"; } _trace4_ ("\n"); } return; } # printTLSCipherList =pod =head1 EXAMPLES See DESCRIPTION above. =head1 LIMITATIONS =head1 KNOWN PROBLEMS =head1 DEENDENCIES L =head1 SEE ALSO L =head1 AUTHOR 19-November-2014 Torsten Gigler =cut sub net_sslhello_done() {}; # dummy to check successful include ## PACKAGE } unless (defined caller) { # print myself or open connection printf("# %s %s\n", __PACKAGE__, $VERSION); if (eval {require POD::Perldoc;}) { # pod2usage( -verbose => 1 ); exit( Pod::Perldoc->run(args=>[$0]) ); } if (qx(perldoc -V)) { # may return: You need to install the perl-doc package to use this program. #exec "perldoc $0"; # scary ... printf("# no POD::Perldoc installed, please try:\n perldoc $0\n"); exit 0; } } 1; O-Saft-19.01.19/Net/SSLinfo.pm000077500000000000000000004714711342117255600154750ustar00rootroot00000000000000#! /usr/bin/perl ## PACKAGE { #!############################################################################# #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!#---------------------------------------------------------------------------- #!# If this tool is valuable for you and we meet some day, you can spend me an #!# O-Saft. I'll accept good wine or beer too :-). Meanwhile -- 'til we meet -- #!# your're encouraged to make a donation to any needy child you see. Thanks! #!#---------------------------------------------------------------------------- #!# This software is provided "as is", without warranty of any kind, express or #!# implied, including but not limited to the warranties of merchantability, #!# fitness for a particular purpose. In no event shall the copyright holders #!# or authors be liable for any claim, damages or other liability. #!# This software is distributed in the hope that it will be useful. #!# #!# This software is licensed under GPLv2. #!# #!# GPL - The GNU General Public License, version 2 #!# as specified in: http://www.gnu.org/licenses/gpl-2.0 #!# or a copy of it https://github.com/OWASP/O-Saft/blob/master/LICENSE.md #!# Permits anyone the right to use and modify the software without limitations #!# as long as proper credits are given and the original and modified source #!# code are included. Requires that the final product, software derivate from #!# the original source or any software utilizing a GPL component, such as #!# this, is also licensed under the same GPL license. #!############################################################################# package Net::SSLinfo; use strict; use warnings; use constant { SSLINFO_VERSION => '18.12.18', SSLINFO => 'Net::SSLinfo', SSLINFO_ERR => '#Net::SSLinfo::errors:', SSLINFO_HASH => '<>', SSLINFO_UNDEF => '<>', SSLINFO_PEM => '<>', SSLINFO_SID => '@(#) SSLinfo.pm 1.224 19/01/19 17:12:36', }; ######################################################## public documentation # # Documentaion starts here, so POD-style inline documentation can be used for # functions also which will be extracted automatically by POD tools. All public # functions will be prefixed with a POD description. # # Dragons with perldoc: # =head2 # Needs at least one space between ( and ) , otherwise formatting will be # wrong. # C<$something> # Does not print "$something" but simply $something unless $somthing # contains = or * character, i.e. $some=thing. Hence we use I<$something> # instead. # NOTE: This module should not use any print(), warn() or die() calls to avoid # unexpected behaviours in the calling program. Exception are: # warn() when used to inform about ancient modules # print() when used in trace mode (0 < $trace). ## no critic qw(ErrorHandling::RequireCarping) # NOTE: See NOTE above. ## no critic qw(Subroutines::ProhibitExcessComplexity) # it's the nature of some checks to be complex # a max_mccabe = 40 would be nice, but cannot be set per file =pod =encoding utf8 =head1 NAME Net::SSLinfo -- perl extension for SSL connection and certificate data =head1 SYNOPSIS # on command line: Net::SSLinfo.pm # print help Net::SSLinfo.pm your.tld # print data from your.tld # from within perl scripts: use Net::SSLinfo; print join("\n", PEM("www.example.com",443), dates(), selected() ciphers() ); do_ssl_close("www.example.com",443); =head1 DESCRIPTION This module is an extension to L to provide information according a SSL connection to a specific server. The purpose is to give as much as possible information to the user (caller) according the specified server aka hostname without struggling with the internals of SSL as needed by Net::SSLeay. =head1 RETURN VALUES All methods return a string on success, empty string otherwise. No output is written on STDOUT or STDERR. Errors need to be retrived using I method. =head1 DEBUGGING Simple tracing can be activated with I<$Net::SSLinfo::trace=1>. I<$Net::SSLinfo::trace=2> or I<$Net::SSLinfo::trace=3> will be passed to I<$Net::SSLeay::trace>. I<$Net::SSLeay::linux_debug=1> will be set if trace > 2. Debugging of low level SSL can be enabled by setting I<$Net::SSLeay::trace>, see L for details. In trace messages empty or undefined strings are written as "<>". =over =item $Net::SSLeay::linux_debug Passed to Net::SSLeay; default: 0 =item $Net::SSLinfo::slowly Passed to Net::SSLeay; default: 0 =back =head1 VARIABLES Following variables are supported: =over =item $Net::SSLinfo::ca_crl URL where to find CRL file; default: '' =item $Net::SSLinfo::ca_file File in PEM format file with all CAs; default: '' Value will not be used at all is set C. =item $Net::SSLinfo::ca_path Directory with PEM files for all CAs; default: '' Value will not be used at all is set C. =item $Net::SSLinfo::ca_depth Depth of peer certificate verification; default: 9 Value will not be used at all if set C. =item $Net::SSLinfo::no_compression Set SSL/TLS option to use compression; default: 1 =item $Net::SSLinfo::ignore_handshake If set to "1" connection attempts returning "faild handshake" will be treated as errorM default: 0. =item $Net::SSLinfo::proxyhost FQDN or IP of proxy to be used; default: ''. =item $Net::SSLinfo::proxyport Port for proxy; default: ''. =item $Net::SSLinfo::proxypass Username for proxy authentication (Basic or Digest Auth); default: ''. =item $Net::SSLinfo::proxyuser Password for proxy authentication (Basic or Digest Auth); default: ''. =item $Net::SSLinfo::proxyauth Authentication string used for proxy; default: ''. =item $Net::SSLinfo::socket Socket to be used for connection. This must be a file descriptor and it's assumed to be an AF_INET or AF_INET6 TCP STREAM type connection. Note: the calling application is responsible for closing the socket. =item $Net::SSLinfo::socket_reuse If set to "1" sockets will be reused if a SSL connection fails and is opened again. The socket will be closed and reopend if set to "0". Background: some servers complain with an TLS Alert if such a socket will be reused. In such cases the default "1" should be set to "0". =item $Net::SSLinfo::starttls Use STARTTLS if not empty. =item $Net::SSLinfo::openssl Path for openssl executable to be used; default: openssl =item $Net::SSLinfo::timeout Path for timeout executable to be used; default: timeout =item $Net::SSLinfo::use_openssl More informations according the SSL connection and the certificate, additional to that of Net::SSLeay, can be retrived using the openssl executable. If set to "1" openssl will be used also; default: 1 If disabled, the values returned will be: # =item $Net::SSLinfo::use_sclient Some informations according the SSL connection and the certificate, can only be retrived using "openssl s_client ...". Unfortunatelly the use may result in a performance penulty on some systems and so it can be disabled with "0"; default: 1 If disabled, the values returned will be: # =item $Net::SSLinfo::use_SNI If set to "1", "$Net::SSLinfo::sni_name" will be used as SNI when opening the connection. If set to "0", no SNI will be used. SNI is needed if there are multiple SSL hostnames on the same IP address. This can be used to check if the target supports SNI; default: 1 =item $Net::SSLinfo::sni_name The specified string will be used as hostname for SNI. It will be used if $Net::SSLinfo::use_SNI is set to 1. supports SNI; default: "" =item $Net::SSLinfo::use_http If set to "1", make a simple HTTP request on the open SSL connection and parse the response for additional SSL/TLS related information (for example Strict-Transport-Security header); default: 1 =item $Net::SSLinfo::use_alpn If set to "1", protocols from "$Net::SSLinfo::protos_alpn" are used for the ALPN option to open the SSL connection. =item $Net::SSLinfo::use_npn If set to "1", protocols from "$Net::SSLinfo::protos_npn" are used for the NPN option to open the SSL connection. =item $Net::SSLinfo::protos_alpn List of protocols to be used for ALPN option when opening a SSL connection. Used if "$Net::SSLinfo::use_alpn" is set. =item $Net::SSLinfo::protos_npn List of protocols to be used for NPN option when opening a SSL connection. Used if "$Net::SSLinfo::use_npn" is set. =item $Net::SSLinfo::no_cert The target may allow connections using SSL protocol, but does not provide a certificate. In this case all calls to functions to get details from the certificate fail (most likely with "segmentation fault" or alike). Due to the behaviour of the used low level ssl libraries, there is no way to detect this failure automatically. If the calling programm terminates abnormally with an error, then setting this value can help. If set to "0", collect data from target's certificate; this is default. If set to "1", don't collect data from target's certificate and return an empty string. If set to "2", don't collect data from target's certificate and return the string defined in "$Net::SSLinfo::no_cert_txt". =item $Net::SSLinfo::no_cert_txt String to be used if "$Net::SSLinfo::no_cert" is set. Default is (same as openssl): "unable to load certificate" =item $Net::SSLinfo::method Will be set to the Net::SSLeay::*_method used to in do_ssl_open(). =item $Net::SSLinfo::file_sclient Use content of this file instead opening connection with openssl. Used for debugging. Note: there are no checks if the content of this file matches the other parameters, in particular the host and port. =back =head1 EXAMPLES See SYNOPSIS above. =head1 LIMITATIONS =head2 Collected data with openssl Some data is collected using an external openssl executable. The output of this executable is used to find proper information. Hence some data may be missing or detected wrong due to different output formats of openssl. If in doubt use "$Net::SSLinfo::use_openssl = 0" to disable openssl usage. Port 443 is used when calling: Net::SSLinfo.pm your.tld =head2 Threads This module is not thread-save as it only supports one internal object for socket handles. However, it will work if all threads use the same hostname. =head1 KNOWN PROBLEMS =head2 Certificate Verification The verification of the target's certificate chain relies on the installed root CAs. As this tool uses Net::SSLeay which usually relies on openssl and its libraries, the (default) settings in these libraries are effective for our certificate chain verification. I.g. the root CAs can be provided in a single combined PEM format file, or in a directory containing one file per CA with a proper link which name is the CA's hash value. Therefore the library uses the CAPFILE and/or CAPATH environment variable. The tools, like openssl, have options to pass proper values for the file and path. We provide these settings in the variables: I<$Net::SSLinfo::ca_file>, I<$Net::SSLinfo::ca_path>, I<$Net::SSLinfo::ca_depth> . Please see B for details. Unfortunately the default settings for the libraries and tools differ on various platforms, so there is no simple way to check if the verification was successful as expected. In particular the behaviour is unpredictable if the environment variables are set and our internal variables (see above) too. Hence, we recommend to either ensure that no environment variables are in use, or our variables are set C. =head2 Errors Net::SSLeay::X509_get_subject_name() from version 1.49 sometimes crashes with segmentation fault. Error message like: panic: sv_setpvn called with negative strlen at Net/SSLinfo.pm line 552, line 1384. Reason most likely Net::SSLeay Version (version<1.49) which doesn't define C. =begin HACKER_INFO Internal documentation only. =head1 General Program Flow =over =item _ssleay_socket() socket() connect() select() =item _ssleay_ctx_new() Net::SSLeay::CTX_tlsv1_2_new() Net::SSLeay::CTX_set_ssl_version() Net::SSLeay::CTX_set_options() Net::SSLeay::CTX_set_timeout() =item _ssleay_ctx_ca() Net::SSLeay::CTX_set_verify() Net::SSLeay::CTX_load_verify_locations() Net::SSLeay::CTX_set_verify_depth() =item _ssleay_ssl_new() Net::SSLeay::new() Net::SSLeay::set_tlsext_host_name() Net::SSLeay::ctrl() =item _ssleay_ssl_np() Net::SSLeay::CTX_set_alpn_protos() Net::SSLeay::CTX_set_next_proto_select_cb() =item do_ssl_new() _ssleay_socket() _ssleay_ctx_new() _ssleay_ctx_ca() _ssleay_ssl_new() _ssleay_ssl_np() Net::SSLeay::connect() =item do_ssl_open() do_ssl_new() _ssleay_get() Net::SSLeay::*() # getter $_SSLinfo{'*'} # getter Net::SSLeay::write() && Net::SSLeay::ssl_read_all # HTTPS _header_get() # getter Net::SSLeay::get_http() $headers # getter _openssl_x509() # getter using openssl do_openssl() =item do_ssl_free() close(socket) Net::SSLeay::free() Net::SSLeay::CTX_free() =item do_ssl_close() do_ssl_free() _SSLinfo_reset() =back =head1 General Usage =over =item Open TCP connection and collect data do_ssl_open(host,port) #... check some stuff do_ssl_close() =item Open TCP connection do_ssl_new(host,port,ssl-version,cipher)) #... check some stuff do_ssl_free() =back =end HACKER_INFO =head1 METHODS All methods are simple getters to retrieve information from `SSL objects'. The general usage is: =over =item # 1. very first call with hostname and port my $value = method('hostname', 8443); =item # 2. very first call with hostname only, port defaults to 443 my $value = method('hostname'); =item # 3. continous call, hostname and port not necessary my $value = method(); =back Methods named C open and close the TCP connections. They are called automatically by the getters (see above) if at least a C parameter is given. It's obvious, that for these C methods the C parameter is mandatory. All following descriptions omit the C parameter as they all follow the rules describend above. =cut ############################################################## initialization # use Exporter qw(import); use base qw(Exporter); our $VERSION = SSLINFO_VERSION; our @EXPORT = qw( net_sslinfo_done ssleay_methods ssleay_test datadump s_client_check s_client_get_optionlist s_client_opt_get do_ssl_new do_ssl_free do_ssl_open do_ssl_close do_openssl set_cipher_list options errors PEM pem text fingerprint fingerprint_hash fingerprint_text fingerprint_type fingerprint_sha2 fingerprint_sha1 fingerprint_md5 cert_type email serial serial_int serial_hex modulus modulus_len modulus_exponent subject_hash issuer_hash aux pubkey pubkey_algorithm pubkey_value signame sigdump sigkey_len sigkey_value extensions tlsextdebug tlsextensions heartbeat trustout ocsp_uri ocspid ocsp_response ocsp_response_data ocsp_response_status ocsp_cert_status ocsp_next_update ocsp_this_update before after dates issuer subject default selected cipher_list cipher_openssl cipher_local ciphers cn commonname altname subjectaltnames authority owner certificate SSLversion version keysize keyusage https_protocols https_svc https_body https_status https_server https_alerts https_location https_refresh https_pins http_protocols http_svc http_status http_location http_refresh http_sts hsts hsts_httpequiv hsts_maxage hsts_subdom hsts_preload verify_hostname verify_altname verify_alias verify error_verify error_depth chain chain_verify compression expansion next_protocols alpn no_alpn next_protocol krb5 psk_hint psk_identity srp master_key session_id session_startdate session_starttime session_lifetime session_ticket session_ticket_hint session_timeout session_protocol renegotiation resumption dh_parameter selfsigned s_client error CTX_method ); # insert above in vi with: # :r !sed -ne 's/^sub \([a-zA-Z][^ (]*\).*/\t\t\1/p' % our $HAVE_XS = eval { local $SIG{'__DIE__'} = 'DEFAULT'; eval { require XSLoader; XSLoader::load('Net::SSLinfo', $VERSION); 1; } or do { require DynaLoader; bootstrap Net::SSLinfo $VERSION; 1; }; } ? 1 : 0; use Socket; use Net::SSLeay; BEGIN { Net::SSLeay::load_error_strings(); Net::SSLeay::SSLeay_add_ssl_algorithms(); # Important! Net::SSLeay::randomize(); if (1.45 > $Net::SSLeay::VERSION) { warn "**WARNING: ancient Net::SSLeay $Net::SSLeay::VERSION < 1.49; cannot use ::initialize"; } else { Net::SSLeay::initialize(); } } my $_protos = 'http/1.1,h2c,h2c-14,spdy/1,npn-spdy/2,spdy/2,spdy/3,spdy/3.1,spdy/4a2,spdy/4a4,h2-14,h2-15,http/2.0,h2'; # NOTE: most weak protocol first, cause we check for vulnerabilities # next protocols not yet configurable # h2c* - HTTP 2 Cleartext # protocols may have prefix `exp' which should not be checked by server # grpc-exp not yet supported (which has -exp suffix, strange ...) $Net::SSLinfo::timeout = 'timeout'; # timeout executable $Net::SSLinfo::openssl = 'openssl'; # openssl executable $Net::SSLinfo::use_openssl = 1; # 1 use installed openssl executable $Net::SSLinfo::use_sclient = 1; # 1 use openssl s_client ... $Net::SSLinfo::use_extdebug= 1; # 0 do not use openssl with -tlsextdebug option $Net::SSLinfo::use_nextprot= 1; # 0 do not use openssl with -nextprotoneg option $Net::SSLinfo::use_reconnect=1; # 0 do not use openssl with -reconnect option $Net::SSLinfo::sclient_opt = '';# option for openssl s_client command $Net::SSLinfo::file_sclient= '';# file to read "open s_client" data from $Net::SSLinfo::sni_name = '';# use this as hostname for SNI $Net::SSLinfo::use_SNI = 1; # 1 use SNI to connect to target; 0: do not use SNI; string: use this as hostname for SNI $Net::SSLinfo::use_http = 1; # 1 make HTTP request and retrive additional data $Net::SSLinfo::use_alpn = 1; # 1 to set ALPN option using $Net::SSLinfo::protos_alpn $Net::SSLinfo::use_npn = 1; # 1 to set NPN option using $Net::SSLinfo::protos_npn $Net::SSLinfo::protos_alpn = $_protos; $Net::SSLinfo::protos_npn = $_protos; $Net::SSLinfo::no_cert = 0; # 0 collect data from target's certificate # 1 don't collect data from target's certificate # return empty string # 2 don't collect data from target's certificate # return string $Net::SSLinfo::no_cert_txt $Net::SSLinfo::no_cert_txt = 'unable to load certificate'; # same as openssl 1.0.x $Net::SSLinfo::ignore_case = 1; # 1 match hostname, CN case insensitive $Net::SSLinfo::ignore_handshake = 0; # 1 treat "failed handshake" as error $Net::SSLinfo::timeout_sec = 3; # time in seconds for timeout executable $Net::SSLinfo::starttls = '';# use STARTTLS if not empty $Net::SSLinfo::proxyhost = '';# FQDN or IP of proxy to be used $Net::SSLinfo::proxyport = '';# port for proxy $Net::SSLinfo::proxypass = '';# username for proxy authentication (Basic or Digest Auth) $Net::SSLinfo::proxyuser = '';# password for proxy authentication (Basic or Digest Auth) $Net::SSLinfo::proxyauth = '';# authentication string used for proxy $Net::SSLinfo::method = '';# used Net::SSLeay::*_method $Net::SSLinfo::socket_reuse= 1; # 0: close and reopen socket for each connection $Net::SSLinfo::no_compression = 0; # 1: use OP_NO_COMPRESSION for connetion in Net::SSLeay $Net::SSLinfo::socket = undef;# socket to be used for connection $Net::SSLinfo::ca_crl = undef;# URL where to find CRL file $Net::SSLinfo::ca_file = undef;# PEM format file with CAs $Net::SSLinfo::ca_path = undef;# path to directory with PEM files for CAs $Net::SSLinfo::ca_depth = undef;# depth of peer certificate verification verification # 0=verification is off, returns always "Verify return code: 0 (ok)" # 9=complete verification (max. value, openssl's default) # undef= not used, means system default is used $Net::SSLinfo::trace = 0; # 1=simple debugging Net::SSLinfo # 2=trace including $Net::SSLeay::trace=2 # 3=dump data including $Net::SSLeay::trace=3 $Net::SSLinfo::linux_debug = 0; # passed to Net::SSLeay::linux_debug $Net::SSLinfo::slowly = 0; # passed to Net::SSLeay::slowly $Net::SSLeay::slowly = 0; # avoid perl warning "... used only once: possible typo ..." my $dumm_1 = $Net::SSLinfo::linux_debug; my $dumm_2 = $Net::SSLinfo::proxyport; my $dumm_3 = $Net::SSLinfo::proxypass; my $dumm_4 = $Net::SSLinfo::proxyuser; my $dumm_5 = $Net::SSLinfo::proxyauth; my $dumm_6 = $Net::SSLinfo::ca_crl; my $dumm_7 = $Net::SSLinfo::use_nextprot; my $trace = $Net::SSLinfo::trace; # forward declarations sub do_ssl_open($$$@); sub do_ssl_close($$); sub do_openssl($$$$); sub _traceset { $trace = $Net::SSLinfo::trace; # set global variable $Net::SSLeay::trace = $trace if (1 < $trace); # must set $Net::SSLeay::trace here again as $Net::SSLinfo::trace # might unset when Net::SSLinfo called initially; $Net::SSLeay::linux_debug = 1 if (2 < $trace); # Net::SSLeay 1.72 uses linux_debug with trace > 2 only $Net::SSLeay::slowly = $Net::SSLinfo::slowly; return; } sub _trace { my $txt = shift; local $\ = "\n"; print '#' . SSLINFO . '::' . $txt if (0 < $trace); return; } # define some shortcuts to avoid $Net::SSLinfo::* my $_echo = ''; # dangerous if aliased or wrong one found my $_timeout = undef; my $_openssl = undef; sub _setcommand { #? check for external command $command; returns command or empty string my $command = shift; return '' if ('' eq $command); my $cmd; my $opt = "version"; $opt = "--version" if ($command =~ m/timeout$/); $cmd = qx($command $opt 2>&1); if (defined $cmd) { # chomp() and _trace() here only to avoid "Use of uninitialized value $cmd ..." chomp $cmd; _trace("_setcommand: $command = $cmd"); $cmd = "$command"; if ($cmd =~ m#timeout$#) { # some timout implementations require -t option, i.e. BusyBox v1.26.2 # hence we check if it works with -t and add it to $cmd $cmd = "$cmd -t " if (qx($cmd -t 2 pwd 2>&1) !~ m/timeout/); } } else { _trace("_setcommand: $command = ''"); $cmd = ''; # i.e. Mac OS X does not have timeout by default; can work without ... } if ($^O !~ m/MSWin32/) { # Windows is too stupid for secure program calls $cmd = '\\' . $cmd if (($cmd ne '') and ($cmd !~ /\//)); } return $cmd; } # _setcommand sub _setcmd { #? check for external commands and initialize if necessary # set global variabales $_openssl and $_timeout return if (defined $_timeout); # lazy check $_openssl = _setcommand($Net::SSLinfo::openssl); $_timeout = _setcommand($Net::SSLinfo::timeout); $_timeout .= " $Net::SSLinfo::timeout_sec" if (defined $_timeout); _trace("#_setcmd using: $_openssl ; $_timeout"); if ($^O !~ m/MSWin32/) { # Windows is too stupid for secure program calls $_echo = '\\' . $_echo; } return; } # _setcmd sub _traceSSLbitmasks { # print bitmasks of available SSL constants my $txt = shift; # prefix string as in _trace() my $mask = shift; # cannot use _trace() 'cause we want our own formatting my $_op_sub; _traceset(); foreach my $op (qw( OP_ALL OP_MICROSOFT_SESS_ID_BUG OP_NETSCAPE_CHALLENGE_BUG OP_LEGACY_SERVER_CONNECT OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG OP_TLSEXT_PADDING OP_MICROSOFT_BIG_SSLV3_BUFFER OP_SAFARI_ECDHE_ECDSA_BUG OP_SSLEAY_080_CLIENT_DH_BUG OP_TLS_D5_BUG OP_TLS_BLOCK_PADDING_BUG OP_DONT_INSERT_EMPTY_FRAGMENTS OP_NO_QUERY_MTU OP_COOKIE_EXCHANGE OP_NO_TICKET OP_CISCO_ANYCONNECT OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION OP_NO_COMPRESSION OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION OP_SINGLE_ECDH_USE OP_SINGLE_DH_USE OP_CIPHER_SERVER_PREFERENCE OP_TLS_ROLLBACK_BUG OP_NO_SSLv2 OP_NO_SSLv3 OP_NO_TLSv1 OP_NO_TLSv1_1 OP_NO_TLSv1_2 OP_NO_TLSv1_3 OP_NO_SSL_MASK OP_NETSCAPE_CA_DN_BUG OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG OP_CRYPTOPRO_TLSEXT_BUG OP_SSLREF2_REUSE_CERT_TYPE_BUG OP_MSIE_SSLV2_RSA_PADDING OP_EPHEMERAL_RSA OP_PKCS1_CHECK_1 OP_PKCS1_CHECK_2 OP_ALLOW_NO_DHE_KEX OP_NON_EXPORT_FIRST OP_NO_CLIENT_RENEGOTIATION OP_NO_ENCRYPT_THEN_MAC OP_NO_RENEGOTIATION OP_PRIORITIZE_CHACHA )) { no strict; ## no critic (TestingAndDebugging::ProhibitNoStrict) # necessary as we use {"Net::SSLeay::$op"} printf("#%s: %-30s ", $txt, $op); ## $_op_sub = \&{"Net::SSLeay::$op"}; # will not catch all values and errors; hence eval() below my $opt; my $_ok = eval { $opt = &{"Net::SSLeay::$op"}; }; if (defined $_ok) { my $bit = (($mask & $opt)>0) || 0; printf("0x%08x %s\n", $opt, $bit); } else { printf("<<$@>>\n"); # error string from Net::SSLeay instead <> } } return; } # _traceSSLbitmasks ##################################################### internal data structure # my %_OpenSSL_opt = ( # openssl capabilities # openssl has various capabilities which can be used with options. # Depending on the version of openssl, these options are available or not. # The data structure contains the important options, each as key where its # value is 1 if the option is available at openssl. # Currently only options for openssl's s_client command are supported. # This data structure is for one openssl command. More than one command is # not expected, not usefull, hence it is thread save. # NOTE: some options are present in different spellings because different # openssl version use different spellings, grrr. 'done' => 0, # set to 1 if initialized 'data' => '',# contains output from "openssl s_client -help" #--------------+------------ # key (=option) supported=1 #--------------+------------ '-alpn' => 0, '-npn' => 0, # same as -nextprotoneg '-nextprotoneg' => 0, '-reconnect' => 0, '-fallback_scsv'=> 0, '-comp' => 0, '-no_comp' => 0, '-no_ticket' => 0, '-no_tlsext' => 0, '-serverinfo' => 0, '-servername' => 0, '-serverpref' => 0, '-showcerts' => 0, '-curves' => 0, '-debug' => 0, '-bugs' => 0, '-key' => 0, '-msg' => 0, '-nbio' => 0, '-psk' => 0, '-psk_identity' => 0, '-pause' => 0, '-prexit' => 0, '-proxy' => 0, '-quiet' => 0, '-sigalgs' => 0, '-state' => 0, '-status' => 0, '-strict' => 0, '-client_sigalgs' => 0, '-nbio_test' => 0, '-record_padding' => 0, '-tlsextdebug' => 0, '-no_renegotiation' => 0, '-legacyrenegotiation' => 0, '-legacy_renegotiation' => 0, '-legacy_server_connect' => 0, '-no_legacy_server_connect' => 0, '-CAfile' => 0, '-CApath' => 0, #--------------+------------ # options in server mode #--------------+------------ #'-anti_replay' => 0, #'-no_anti_replay' => 0, #'-dhparam' => 0, #'-prioritize_chacha' => 0, #'-no_resumption_on_reneg' => 0, ); my %_SSLmap = ( # map libssl's constants to speaking names # SSL and openssl is a pain, for setting protocols it needs a bitmask # and SSL itself returns a hex constant, which is different # /----- returned by Net::SSLeay::version($ssl) # key v bitmask used in Net::SSLeay::CTX_set_options() #-------------+---------+--------------------------------------------- 'SSLv2' => [0x0002, Net::SSLeay::OP_NO_SSLv2() ], # 0x01000000 'SSLv3' => [0x0300, Net::SSLeay::OP_NO_SSLv3() ], # 0x02000000 'TLSv1' => [0x0301, undef], # 0x04000000 'TLSv11' => [0x0302, undef], # 0x08000000 'TLSv12' => [0x0303, undef], # 0x10000000 'TLSv13' => [0x0304, undef], # 0x10000000 'TLS1FF' => [0x03FF, undef], # 'DTLSfamily'=> [0xFE00, undef], # 'DTLSv09' => [0x0100, undef], # 0xFEFF in some openssl versions 'DTLSv1' => [0xFEFF, undef], # ?? 'DTLSv11' => [0xFEFE, undef], # ?? 'DTLSv12' => [0xFEFD, undef], # ?? 'DTLSv13' => [0xFEFF, undef], # ?? ); # unfortunately not all openssl and/or Net::SSLeay versions have all constants, # hence we need to assign some values dynamically (to avoid perl errors) # NOTE: existance cannot be checked with: defined &Net::SSLeay::OP_NO_TLSv1 $_SSLmap{'TLSv1'} [1] = Net::SSLeay::OP_NO_TLSv1() if (eval {Net::SSLeay::OP_NO_TLSv1()}); $_SSLmap{'TLSv11'} [1] = Net::SSLeay::OP_NO_TLSv1_1() if (eval {Net::SSLeay::OP_NO_TLSv1_1()}); $_SSLmap{'TLSv12'} [1] = Net::SSLeay::OP_NO_TLSv1_2() if (eval {Net::SSLeay::OP_NO_TLSv1_2()}); $_SSLmap{'TLSv13'} [1] = Net::SSLeay::OP_NO_TLSv1_3() if (eval {Net::SSLeay::OP_NO_TLSv1_3()}); $_SSLmap{'DTLSv1'} [1] = Net::SSLeay::OP_NO_DTLSv1() if (eval {Net::SSLeay::OP_NO_DTLSv1()}); #$_SSLmap{'DTLSv11'}[1] = Net::SSLeay::OP_NO_DTLSv1_1() if (eval {Net::SSLeay::OP_NO_DTLSv1_1()}); #$_SSLmap{'DTLSv12'}[1] = Net::SSLeay::OP_NO_DTLSv1_2() if (eval {Net::SSLeay::OP_NO_DTLSv1_2()}); #$_SSLmap{'DTLSv13'}[1] = Net::SSLeay::OP_NO_DTLSv1_3() if (eval {Net::SSLeay::OP_NO_DTLSv1_3()}); # NOTE: we use the bitmask provided by the system # NOTE: all checks are done now, we don't need to fiddle around that later # we just need to check for undef then # TODO: %_SSLmap should be inherited from $cfg{openssl_version_map} or vice versa my %_SSLhex = map { $_SSLmap{$_}[0] => $_ } keys %_SSLmap; # reverse map sub _SSLversion_get { return $_SSLmap{$_[0]}[0]; } ## no critic qw(Subroutines::RequireArgUnpacking) sub _SSLbitmask_get { return $_SSLmap{$_[0]}[1]; } ## no critic qw(Subroutines::RequireArgUnpacking) # for 'no critic' above, see comment far below my %_SSLtemp= ( # temporary internal data structure when establishing a connection # 'key' => 'value', # description #-------------+-------------+--------------------------------------------- 'addr' => undef, # raw INET IP for hostname (FQDN) 'socket' => undef, # socket handle of new connection 'ctx' => undef, # handle for Net::SSLeay::CTX_new() 'ssl' => undef, # handle for Net::SSLeay 'method' => '', # used Net::SSLeay::*_method 'errors' => [], # stack for errors, if any #-------------+-------------+--------------------------------------------- ); # %_SSLtemp sub _SSLtemp_reset { #? reset internal data structure%_SSLtemp ; for internal use only foreach my $key (keys %_SSLtemp) { $_SSLtemp{$key} = undef; } $_SSLtemp{'method'} = ''; $_SSLtemp{'errors'} = []; return; } # _SSLtemp_reset my %_SSLinfo= ( # our internal data structure 'key' => 'value', # description #-------------+-------------+--------------------------------------------- 'host' => '', # hostname (FQDN) or IP as given by user 'addr' => undef, # raw INET IP for hostname (FQDN) 'ip' => '', # human readable IP for hostname (FQDN) 'port' => 443, # port as given by user (default 443) 'ctx' => undef, # handle for Net::SSLeay::CTX_new() 'ssl' => undef, # handle for Net::SSLeay '_options' => '', # option bitmask used for connection 'errors' => [], # stack for errors, if any 'cipherlist'=> 'ALL:NULL:eNULL:aNULL:LOW', # we want to test really all ciphers available 'verify_cnt'=> 0, # Net::SSLeay::set_verify() call counter # now store the data we get from above handles 'SSLversion'=> '', # Net::SSLeay::version(); used protocol version 'version' => '', # certificate version 'error_verify' => '', # error string of certificate chain check 'error_depth' => '', # integer value of depth where certificate chain check failed 'keysize' => '', 'keyusage' => '', 'altname' => '', 'cn' => '', 'subject' => '', 'issuer' => '', 'before' => '', 'after' => '', 'PEM' => '', 'text' => '', 'cert_type' => '', # X509 certificate type EXPERIMENTAL 'ciphers' => [], # list of ciphers offered by local SSL implementation # all following are available when calling openssl only 's_client' => "", # data we get from `openssl s_client -connect ...' 'ciphers_openssl' => "", # list of ciphers returned by openssl executable 'subject_hash' => "", # 'issuer_hash' => "", # 'aux' => "", # 'ocsp_response' => "", # selected data from OCSP Response Data 'ocsp_response_data'=> "", # complete OCSP Response with "openssl -tlsextdebug -status .." 'ocsp_response_status'=>"", # OCSP Response Data: Response Status 'ocsp_cert_status' => "", # OCSP Response Data: Cert Status 'ocsp_next_update' => "", # OCSP Response Data: Next Update 'ocsp_this_update' => "", # OCSP Response Data: This Update 'pubkey' => "", # certificates public key 'pubkey_algorithm' => "", # certificates public key algorithm 'pubkey_value' => "", # certificates public key value (same as modulus) 'signame' => "", # 'sigdump' => "", # algorithm and value of signature key 'sigkey_len' => "", # bit length of signature key 'sigkey_value' => "", # value of signature key 'extensions' => "", # 'tlsextdebug' => "", # TLS extension visible with "openssl -tlsextdebug .." 'tlsextensions' => "", # TLS extension visible with "openssl -tlsextdebug .." 'email' => "", # the email address(es) 'heartbeat' => "", # heartbeat supported 'serial' => "", # the serial number, string as provided by openssl: int (hex) 'serial_hex' => "", # the serial number as Integer 'serial_int' => "", # the serial number as hex 'modulus' => "", # the modulus of the public key 'modulus_len' => "", # bit length of the public key 'modulus_exponent' => "", # exponent of the public key 'fingerprint_text' => "", # the fingerprint text 'fingerprint_type' => "", # just the fingerprint hash algorithm 'fingerprint_hash' => "", # the fingerprint hash value 'fingerprint_sha2' => "", # SHA2 fingerprint (if available) 'fingerprint_sha1' => "", # SHA1 fingerprint (if available) 'fingerprint_md5' => "", # MD5 fingerprint (if available) 'selected' => "", # cipher selected for session by server # all following need output from "openssl s_client ..." 'verify' => "", # certificate chain verification 'chain' => "", # certificate's CA chain 'chain_verify' => "", # certificate's CA chain verifacion trace 'dh_parameter' => "", # DH Parameter (starting with openssl 1.0.2a) 'renegotiation' => "", # renegotiation supported 'resumption' => "", # resumption supported 'selfsigned' => "", # self-signed certificate 'compression' => "", # compression supported 'expansion' => "", # expansion supported 'next_protocols' => "", # Protocols advertised by server 'alpn' => "", # ALPN protocol 'no_alpn' => "", # No ALPN negotiated 'next_protocol' => "", # Next protocol 'krb5' => "", # Krb Principal 'psk_hint' => "", # PSK identity hint 'psk_identity' => "", # PSK identity 'srp' => "", # SRP username 'master_key' => "", # Master-Key 'session_id' => "", # Session-ID 'session_startdate' => "", # TLS session start time (human readable) 'session_starttime' => "", # TLS session start time (seconds EPOCH) 'session_lifetime' => "", # TLS session ticket lifetime hint 'session_ticket' => "", # TLS session ticket 'session_timeout' => "", # SSL-Session Timeout 'session_protocol' => "", # SSL-Session Protocol # following from HTTP(S) request 'https_protocols' => "", # HTTPS Alternate-Protocol header 'https_svc' => "", # HTTPS Alt-Svc, X-Firefox-Spdy header 'https_body' => "", # HTTPS response (HTML body) 'https_status' => "", # HTTPS response (aka status) line 'https_server' => "", # HTTPS Server header 'https_alerts' => "", # HTTPS Alerts send by server 'https_location' => "", # HTTPS Location header send by server 'https_refresh' => "", # HTTPS Refresh header send by server 'https_pins' => "", # HTTPS Public Key Pins header 'http_protocols' => "", # HTTP Alternate-Protocol header 'http_svc' => "", # HTTP Alt-Svc, X-Firefox-Spdy header 'http_status' => "", # HTTP response (aka status) line 'http_location' => "", # HTTP Location header send by server 'http_refresh' => "", # HTTP Refresh header send by server 'http_sts' => "", # HTTP Strict-Transport-Security header send by server (whish is very bad) 'https_sts' => "", # complete STS header 'hsts_httpequiv' => "", # http-equiv meta tag in HTTP body 'hsts_maxage' => "", # max-age attribute of STS header 'hsts_subdom' => "", # includeSubDomains attribute of STS header 'hsts_preload' => "", # preload attribute of STS header #-------------+-------------+--------------------------------------------- ); # %_SSLinfo sub _SSLinfo_reset { #? reset internal data structure%_SSLinfo ; for internal use only foreach my $key (keys %_SSLinfo) { $_SSLinfo{$key} = ''; } # some are special $_SSLinfo{'key'} = 'value'; $_SSLinfo{'ctx'} = undef; $_SSLinfo{'ssl'} = undef; $_SSLinfo{'addr'} = undef; $_SSLinfo{'port'} = 443; $_SSLinfo{'errors'} = []; $_SSLinfo{'ciphers'} = []; $_SSLinfo{'cipherlist'} = 'ALL:NULL:eNULL:aNULL:LOW'; $_SSLinfo{'verify_cnt'} = 0; $_SSLinfo{'ciphers_openssl'} = ''; return; } # _SSLinfo_reset sub ssleay_methods { #? returns list of available Net::SSLeay::*_method; most important first # TODO: check for mismatch Net::SSLeay::*_method and Net::SSLeay::CTX_*_new my @list; # following sequence is important: most modern methods first; DTLS not yet important push(@list, 'TLSv1_3_method' ) if (defined &Net::SSLeay::TLSv1_3_method); # Net::SSLeay > 1.72 push(@list, 'TLSv1_2_method' ) if (defined &Net::SSLeay::TLSv1_2_method); push(@list, 'TLSv1_1_method' ) if (defined &Net::SSLeay::TLSv1_1_method); push(@list, 'TLSv1_method' ) if (defined &Net::SSLeay::TLSv1_method); push(@list, 'SSLv23_method' ) if (defined &Net::SSLeay::SSLv23_method); push(@list, 'SSLv3_method' ) if (defined &Net::SSLeay::SSLv3_method); push(@list, 'SSLv2_method' ) if (defined &Net::SSLeay::SSLv2_method); push(@list, 'DTLSv1_3_method' ) if (defined &Net::SSLeay::DTLSv1_3_method); # Net::SSLeay > 1.72 push(@list, 'DTLSv1_2_method' ) if (defined &Net::SSLeay::DTLSv1_2_method); # Net::SSLeay > 1.72 push(@list, 'DTLSv1_1_method' ) if (defined &Net::SSLeay::DTLSv1_1_method); # Net::SSLeay > 1.72 push(@list, 'DTLSv1_method' ) if (defined &Net::SSLeay::DTLSv1_method); # Net::SSLeay > 1.72 push(@list, 'DTLS_method' ) if (defined &Net::SSLeay::DTLS_method); # Net::SSLeay > 1.72 push(@list, 'CTX_tlsv1_3_new' ) if (defined &Net::SSLeay::CTX_tlsv1_3_new); push(@list, 'CTX_tlsv1_2_new' ) if (defined &Net::SSLeay::CTX_tlsv1_2_new); push(@list, 'CTX_tlsv1_1_new' ) if (defined &Net::SSLeay::CTX_tlsv1_1_new); push(@list, 'CTX_tlsv1_0_new' ) if (defined &Net::SSLeay::CTX_tlsv1_0_new); push(@list, 'CTX_tlsv1_new' ) if (defined &Net::SSLeay::CTX_tlsv1_new); push(@list, 'CTX_v23_new' ) if (defined &Net::SSLeay::CTX_v23_new); push(@list, 'CTX_v3_new' ) if (defined &Net::SSLeay::CTX_v3_new); push(@list, 'CTX_v2_new' ) if (defined &Net::SSLeay::CTX_v2_new); push(@list, 'CTX_new_with_method') if (defined &Net::SSLeay::CTX_new_with_method); push(@list, 'CTX_new' ) if (defined &Net::SSLeay::CTX_new); push(@list, 'CTX_dtlsv1_3_new') if (defined &Net::SSLeay::CTX_dtlsv1_3_new); push(@list, 'CTX_dtlsv1_2_new') if (defined &Net::SSLeay::CTX_dtlsv1_2_new); push(@list, 'CTX_dtlsv1_new' ) if (defined &Net::SSLeay::CTX_dtlsv1_new); push(@list, 'CTX_get_options' ) if (defined &Net::SSLeay::CTX_get_options); push(@list, 'CTX_set_options' ) if (defined &Net::SSLeay::CTX_set_options); push(@list, 'CTX_set_timeout' ) if (defined &Net::SSLeay::CTX_set_timeout); push(@list, 'CTX_set_alpn_protos') if (defined &Net::SSLeay::CTX_set_alpn_protos); # Net::SSLeay > 1.72 ?? push(@list, 'CTX_set_next_proto_select_cb') if (defined &Net::SSLeay::CTX_set_next_proto_select_cb); return @list; } # ssleay_methods sub ssleay_test { #? print availability and information about Net::SSLeay my @list = ssleay_methods(); my $line = "#------------+------------------+-------------"; my $data = "# Net::SSLeay{ function 1=available $line # ::SSLv2_method = " . ((grep{/^SSLv2_method$/} @list) ? 1 : 0) . " # ::SSLv3_method = " . ((grep{/^SSLv3_method$/} @list) ? 1 : 0) . " # ::SSLv23_method = " . ((grep{/^SSLv23_method$/} @list) ? 1 : 0) . " # ::TLSv1_method = " . ((grep{/^TLSv1_method$/} @list) ? 1 : 0) . " # ::TLSv1_1_method = " . ((grep{/^TLSv1_1_method$/} @list) ? 1 : 0) . " # ::TLSv1_2_method = " . ((grep{/^TLSv1_2_method$/} @list) ? 1 : 0) . " #{ following missing in Net::SSLeay (up to 1.72): # ::TLSv1_3_method = " . ((grep{/^TLSv1_3_method$/} @list) ? 1 : 0) . " # ::DTLSv1_method = " . ((grep{/^DTLSv1_method$/} @list) ? 1 : 0) . " # ::DTLSv1_2_method = " . ((grep{/^DTLSv1_2_method$/} @list) ? 1 : 0) . " # ::DTLS_method = " . ((grep{/^DTLS_method$/} @list) ? 1 : 0) . " #} # ::CTX_new_with_method = " . ((grep{/^CTX_new_with_method$/} @list) ? 1 : 0) . " # ::CTX_new = " . ((grep{/^CTX_new$/} @list) ? 1 : 0) . " # ::CTX_v2_new = " . ((grep{/^CTX_v2_new$/} @list) ? 1 : 0) . " # ::CTX_v3_new = " . ((grep{/^CTX_v3_new$/} @list) ? 1 : 0) . " # ::CTX_v23_new = " . ((grep{/^CTX_v23_new$/} @list) ? 1 : 0) . " # ::CTX_tlsv1_new = " . ((grep{/^CTX_tlsv1_new$/} @list) ? 1 : 0) . " # ::CTX_tlsv1_0_new = " . ((grep{/^CTX_tlsv1_0_new$/} @list) ? 1 : 0) . " # ::CTX_tlsv1_1_new = " . ((grep{/^CTX_tlsv1_1_new$/} @list) ? 1 : 0) . " # ::CTX_tlsv1_2_new = " . ((grep{/^CTX_tlsv1_2_new$/} @list) ? 1 : 0) . " # ::CTX_tlsv1_3_new = " . ((grep{/^CTX_tlsv1_3_new$/} @list) ? 1 : 0) . " # ::CTX_dtlsv1_new = " . ((grep{/^CTX_dtlsv1_new$/} @list) ? 1 : 0) . " # ::CTX_dtlsv1_2_new = " . ((grep{/^CTX_dtlsv1_2_new$/} @list) ? 1 : 0) . " # ::CTX_dtlsv1_3_new = " . ((grep{/^CTX_dtlsv1_3_new$/} @list) ? 1 : 0) . " # ::CTX_get_options = " . ((grep{/^CTX_get_options$/} @list) ? 1 : 0) . " # ::CTX_set_options = " . ((grep{/^CTX_set_options$/} @list) ? 1 : 0) . " # ::CTX_set_timeout = " . ((grep{/^CTX_set_timeout$/} @list) ? 1 : 0) . " # ::CTX_set_alpn_protos = " . ((grep{/^CTX_set_alpn_protos$/} @list) ? 1 : 0) . " # ::CTX_set_next_proto_select_cb = " . ((grep{/^CTX_set_next_proto_select_cb$/} @list) ? 1 : 0) . " $line # Net::SSLeay} function # Net::SSLeay{ constant hex value $line # ::OP_NO_SSLv2 = " . ((defined &Net::SSLeay::OP_NO_SSLv2) ? sprintf('0x%08x', Net::SSLeay::OP_NO_SSLv2()) : "<>") . " # ::OP_NO_SSLv3 = " . ((defined &Net::SSLeay::OP_NO_SSLv3) ? sprintf('0x%08x', Net::SSLeay::OP_NO_SSLv3()) : "<>") . " # ::OP_NO_TLSv1 = " . ((defined &Net::SSLeay::OP_NO_TLSv1) ? sprintf('0x%08x', Net::SSLeay::OP_NO_TLSv1()) : "<>") . " # ::OP_NO_TLSv1_1 = " . ((defined &Net::SSLeay::OP_NO_TLSv1_1) ? sprintf('0x%08x', Net::SSLeay::OP_NO_TLSv1_1()) : "<>") . " # ::OP_NO_TLSv1_2 = " . ((defined &Net::SSLeay::OP_NO_TLSv1_2) ? sprintf('0x%08x', Net::SSLeay::OP_NO_TLSv1_2()) : "<>") . " # ::OP_NO_TLSv1_3 = " . ((defined &Net::SSLeay::OP_NO_TLSv1_3) ? sprintf('0x%08x', Net::SSLeay::OP_NO_TLSv1_3()) : "<>") . " # ::OP_NO_DTLSv09 = " . ((defined &Net::SSLeay::OP_NO_DTLSv09) ? sprintf('0x%08x', Net::SSLeay::OP_NO_DTLSv09()) : "<>") . " # ::OP_NO_DTLSv1 = " . ((defined &Net::SSLeay::OP_NO_DTLSv1) ? sprintf('0x%08x', Net::SSLeay::OP_NO_DTLSv1()) : "<>") . " # ::OP_NO_DTLSv1_1 = " . ((defined &Net::SSLeay::OP_NO_DTLSv1_1) ? sprintf('0x%08x', Net::SSLeay::OP_NO_DTLSv1_1()) : "<>") . " # ::OP_NO_DTLSv1_2 = " . ((defined &Net::SSLeay::OP_NO_DTLSv1_2) ? sprintf('0x%08x', Net::SSLeay::OP_NO_DTLSv1_2()) : "<>") . " # ::OP_NO_DTLSv1_3 = " . ((defined &Net::SSLeay::OP_NO_DTLSv1_3) ? sprintf('0x%08x', Net::SSLeay::OP_NO_DTLSv1_3()) : "<>") . " $line # Net::SSLeay} constant # Net::SSLeay{ call # experimental ... # Net::SSLeay::CTX_new { # ::CTX_get_options(CTX)= " . sprintf('0x%08x', Net::SSLeay::CTX_get_options(Net::SSLeay::CTX_new())) . " # Net::SSLeay::CTX_new } # Net::SSLeay::CTX_v3_new { # ::CTX_get_options(CTX)= " . sprintf('0x%08x', Net::SSLeay::CTX_get_options(Net::SSLeay::CTX_v3_new())) . " # Net::SSLeay::CTX_v3_new } # Net::SSLeay::CTX_v23_new { # ::CTX_get_options(CTX)= " . sprintf('0x%08x', Net::SSLeay::CTX_get_options(Net::SSLeay::CTX_v23_new())) . " # ::CTX_get_timeout(CTX)= " . Net::SSLeay::CTX_get_timeout(Net::SSLeay::CTX_v23_new()) . " # ::CTX_get_verify_mode(CTX) = " . sprintf('0x%08x', Net::SSLeay::CTX_get_verify_mode(Net::SSLeay::CTX_v23_new())) . " # ::CTX_get_verify_depth(CTX)= " . Net::SSLeay::CTX_get_verify_depth(Net::SSLeay::CTX_v23_new()) . " # Net::SSLeay::CTX_v23_new } # Net::SSLeay::CTX_tlsv1_2_new { # ::CTX_get_options(CTX)= " . sprintf('0x%08x', Net::SSLeay::CTX_get_options(Net::SSLeay::CTX_tlsv1_2_new())) . " # ::CTX_get_timeout(CTX)= " . Net::SSLeay::CTX_get_timeout(Net::SSLeay::CTX_tlsv1_2_new()) . " # ::CTX_get_verify_mode(CTX) = " . sprintf('0x%08x', Net::SSLeay::CTX_get_verify_mode(Net::SSLeay::CTX_tlsv1_2_new())) . " # ::CTX_get_verify_depth(CTX)= " . Net::SSLeay::CTX_get_verify_depth(Net::SSLeay::CTX_tlsv1_2_new()) . " # Net::SSLeay::CTX_tlsv1_2_new } # Net::SSLeay} call\n"; return $data; } # ssleay_test sub _dump { my $key = shift; my $txt = shift; my $val = shift; return sprintf("#{ %-12s:%s%s #}\n", $key, $txt, ($val || "<>")); } # _dump sub datadump { #? return internal data structure my $data = ''; if ($Net::SSLinfo::use_sclient > 1) { $data .= _dump('s_client', " ", $_SSLinfo{'s_client'}); } else { $data .= _dump('s_client', " ", "#### please set 'Net::SSLinfo::use_sclient > 1' to dump s_client data also ###"); } $data .= _dump('PEM', " ", $_SSLinfo{'PEM'}); $data .= _dump('text', " ", $_SSLinfo{'text'}); $data .= _dump('ciphers', " ", join(' ', @{$_SSLinfo{'ciphers'}})); foreach my $key (keys %_SSLinfo) { next if ($key =~ m/ciphers|errors|PEM|text|fingerprint_|s_client/); # handled special $data .= _dump($key, " ", $_SSLinfo{$key}); } foreach my $key (keys %_SSLinfo) { next if ($key !~ m/fingerprint_/); $data .= _dump($key, " ", $_SSLinfo{$key}); } $data .= _dump('errors', "\n", join("\n ** ", @{$_SSLinfo{'errors'}})); return $data; } # datadump ########################################################## internal functions # ### _OpenSSL_opt_get() defined later to avoid forward declaration sub _SSLinfo_get { # get specified value from %_SSLinfo, first parameter 'key' is mandatory my ($key, $host, $port) = @_; _traceset(); _trace("_SSLinfo_get('$key'," . ($host||'') . "," . ($port||'') . ")"); if ($key eq 'ciphers_openssl') { _trace("_SSLinfo_get($key): WARNING: function obsolete, please use cipher_openssl()"); return ''; } if ($key eq 'errors') { # always there, no need to connect target #src = Net::SSLeay::ERR_peek_error; # just returns number #src = Net::SSLeay::ERR_peek_last_error; # should work since openssl 0.9.7 return wantarray ? @{$_SSLinfo{$key}} : join("\n", @{$_SSLinfo{$key}}); } return '' if not defined do_ssl_open($host, $port, ''); if ($key eq 'ciphers') { # special handling return wantarray ? @{$_SSLinfo{$key}} : join(' ', @{$_SSLinfo{$key}}); return wantarray ? @{$_SSLinfo{$key}} : join(':', @{$_SSLinfo{$key}}); # if we want `openssl ciphers' format } if ($key eq 'dates') { return ( $_SSLinfo{'before'}, $_SSLinfo{'after'}); } _trace("_SSLinfo_get '$key'=" . ($_SSLinfo{$key} || '')); return (grep{/^$key$/} keys %_SSLinfo) ? $_SSLinfo{$key} : ''; } # _SSLinfo_get # # general internal functions # sub _check_host { #? convert hostname to IP and store in $_SSLinfo{'host'}, returns 1 on success my $host = shift; _trace("_check_host(" . ($host||'') . ")"); $host = $_SSLinfo{'host'} unless defined $host; my $ip = undef; if($ip = gethostbyname($host)) { # check result of assignment! $_SSLinfo{'host'} = $host; $_SSLinfo{'addr'} = $ip; $_SSLinfo{'ip'} = join('.', unpack('W4', $ip)); } else { push(@{$_SSLinfo{'errors'}}, "_check_host: $!"); } _trace("_check_host $_SSLinfo{'host'} $_SSLinfo{'ip'} ."); return (defined $ip) ? 1 : undef; } # _check_host sub _check_port { #? convert port name to number and store in $_SSLinfo{'port'}, returns 1 on success my $port = shift; _trace("_check_port(" . ($port||'') . ")"); $port = $_SSLinfo{'port'} unless defined $port; $port = getservbyname($port, 'tcp') unless $port =~ /^\d+$/; push(@{$_SSLinfo{'errors'}}, "_check_port: $!") if ($! !~ m/^\s*$/); $_SSLinfo{'port'} = $port if (defined $port); _trace("_check_port $port ."); return (defined $port) ? 1 : undef; } # _check_port sub _ssleay_get { #? get specified value from SSLeay certificate # wrapper to get data provided by certificate # note that all these function may produce "segmentation fault" or alike if # the target does not have/use a certificate but allows connection with SSL my ($key, $x509) = @_; _traceset(); _trace("_ssleay_get('$key', x509)"); if (0 != $Net::SSLinfo::no_cert) { _trace("_ssleay_get 'use_cert' $Net::SSLinfo::no_cert ."); return $Net::SSLinfo::no_cert_txt if (2 == $Net::SSLinfo::no_cert); return ''; } if (not $x509) { # ugly check to avoid "Segmentation fault" if $x509 is 0 or undef return $Net::SSLinfo::no_cert_txt if ($key =~ m/^(PEM|version|md5|sha1|sha2|subject|issuer|before|after|serial_hex|cn|policies|error_depth|cert_type|serial|altname)/); ## no critic qw(RegularExpressions::ProhibitComplexRegexes) } return Net::SSLeay::PEM_get_string_X509( $x509) || '' if ($key eq 'PEM'); return Net::SSLeay::X509_get_version( $x509) + 1 if ($key eq 'version'); return Net::SSLeay::X509_get_fingerprint( $x509, 'md5') if ($key eq 'md5'); return Net::SSLeay::X509_get_fingerprint( $x509, 'sha1') if ($key eq 'sha1'); return Net::SSLeay::X509_get_fingerprint( $x509, 'sha256') if ($key eq 'sha2'); return Net::SSLeay::X509_NAME_oneline( Net::SSLeay::X509_get_subject_name($x509)) if ($key eq 'subject'); return Net::SSLeay::X509_NAME_oneline( Net::SSLeay::X509_get_issuer_name( $x509)) if ($key eq 'issuer'); return Net::SSLeay::P_ASN1_UTCTIME_put2string(Net::SSLeay::X509_get_notBefore( $x509)) if ($key eq 'before'); return Net::SSLeay::P_ASN1_UTCTIME_put2string(Net::SSLeay::X509_get_notAfter( $x509)) if ($key eq 'after'); return Net::SSLeay::P_ASN1_INTEGER_get_hex(Net::SSLeay::X509_get_serialNumber( $x509)) if ($key eq 'serial_hex'); return Net::SSLeay::X509_NAME_get_text_by_NID( Net::SSLeay::X509_get_subject_name($x509), &Net::SSLeay::NID_commonName) if ($key eq 'cn'); return Net::SSLeay::X509_NAME_get_text_by_NID( Net::SSLeay::X509_get_subject_name($x509), &Net::SSLeay::NID_certificate_policies) if ($key eq 'policies'); return Net::SSLeay::X509_STORE_CTX_get_error_depth($x509) if ($key eq 'error_depth'); return Net::SSLeay::X509_certificate_type( $x509) if ($key eq 'cert_type'); return Net::SSLeay::X509_subject_name_hash( $x509) if ($key eq 'subject_hash'); return Net::SSLeay::X509_issuer_name_hash( $x509) if ($key eq 'issuer_hash'); my $ret = ''; if ($key =~ 'serial') { #dbx# print "#SERIAL# $key #\n"; # TODO: dead code as Net::SSLeay::X509_get_serialNumber() does not really return an integer $ret = Net::SSLeay::P_ASN1_INTEGER_get_hex(Net::SSLeay::X509_get_serialNumber( $x509)); return $ret if($key eq 'serial_hex'); my $int = hex($ret); return $int if($key eq 'serial_int'); return "$int (0x$ret)"; # if($key eq 'serial'); } if ($key eq 'altname') { my @altnames = Net::SSLeay::X509_get_subjectAltNames($x509); # returns array of (type, string) _trace("_ssleay_get: Altname: " . join(' ', @altnames)); while (@altnames) { # construct string like openssl my ($type, $name) = splice(@altnames, 0, 2); # TODO: replace ugly code by %_SSLtypemap $type = 'DNS' if ($type eq '2'); $type = 'URI' if ($type eq '6'); $type = 'X400' if ($type eq '3'); $type = 'DIRNAME' if ($type eq '4'); $type = 'EDIPARTY' if ($type eq '5'); $type = 'IPADD' if ($type eq '7'); $type = 'RID' if ($type eq '8'); $type = 'email' if ($type eq '1'); $name = '<>' if(($type eq '0') && ($name!~/^/)); $type = 'othername' if ($type eq '0'); $name = join('.', unpack('W4', $name)) if ($type eq 'IPADD'); # all other types are used as is, so we see what's missing $ret .= ' ' . join(':', $type, $name); } } _trace("_ssleay_get: $ret."); # or warn "**WARNING: wrong key '$key' given; ignored"; return $ret; } # _ssleay_get sub _ssleay_socket { #? craete TLS socket or use given socket # side-effects: uses $Net::SSLinfo::starttls, $Net::SSLinfo::proxyhost ::proxyport my $host = shift; my $port = shift; my $socket = shift; my $src = ''; # function (name) where something failed my $err = ''; my $dum = ''; _traceset(); _trace("_ssleay_socket(" . ($host||'') . "," . ($port||'') . ")"); return $socket if (defined $socket); local $! = undef; # avoid using cached error messages TRY: { unless (($Net::SSLinfo::starttls) || ($Net::SSLinfo::proxyhost)) { # $Net::SSLinfo::proxyport was already checked in main #1a. no proxy and not starttls # $host and $port may be undefined, hence the ugly setting of $src # to avoid Perl's "Use of uninitialized value $host in concatenation ... " # _check_host() and _check_port() woll work poper with undef values $src = '_check_host(' . ($host||'') . ')'; if (not defined _check_host($host)) { $err = $!; last; } $src = '_check_port(' . ($port||'') . ')'; if (not defined _check_port($port)) { $err = $!; last; } $src = 'socket()'; socket( $socket, &AF_INET, &SOCK_STREAM, 0) or do {$err = $!} and last; $src = 'connect()'; $dum=()=connect($socket, sockaddr_in($_SSLinfo{'port'}, $_SSLinfo{'addr'})) or do {$err = $!} and last; } else { #1b. starttls or via proxy require Net::SSLhello; # ok here, as perl handles multiple includes proper Net::SSLhello::version() if (1 < $trace); # TODO: already done in _yeast_init() $src = 'Net::SSLhello::openTcpSSLconnection()'; # open TCP connection via proxy and do STARTTLS if requested # NOTE that $host cannot be checked here because the proxy does # DNS and also has the routes to the host ($socket = Net::SSLhello::openTcpSSLconnection($host, $port)) or do {$err = $!} and last; } ## no critic qw(InputOutput::ProhibitOneArgSelect) select($socket); local $| = 1; select(STDOUT); # Eliminate STDIO buffering ## use critic return $socket; }; # TRY push(@{$_SSLinfo{'errors'}}, "_ssleay_socket() failed calling $src: $err"); _trace("_ssleay_socket: undef"); return; } # _ssleay_socket sub _ssleay_ctx_new { #? get SSLeay CTX object; returns ctx object or undef my $method = shift;# CTX method to be used for creating object my $ctx = undef;# CTX object to be created my $ssl = undef; my $src = ''; # function (name) where something failed my $err = ''; my $old = ''; _traceset(); _trace("_ssleay_ctx_new($method)"); $src = "Net::SSLeay::$method"; _trace("_ssleay_ctx_new: $src"); local $! = undef; # avoid using cached error messages TRY: { # no proper generic way to replace following ugly SWITCH code, however: it's save # calling function already checked for CTX_* and *_method, but we do # not have the information (aka result from ssleay_methods()) here, so # we need to check for existance of *_method again # CTX_* (i.e. CTX_v23_new) returns an object, errors are on error stack # last gets out of TRY block $_ = $method; # { # SWITCH /CTX_tlsv1_3_new/ && do { #2.1. prepare SSL's context object ($ctx = Net::SSLeay::CTX_tlsv1_3_new()) or last;# create object #2.2. set default protocol version if (defined &Net::SSLeay::TLSv1_3_method) { $src = 'Net::SSLeay::CTX_set_ssl_version(TLSv1_3_method)'; Net::SSLeay::CTX_set_ssl_version($ctx, Net::SSLeay::TLSv1_3_method()) or do {$err = $!} and last; # allow all versions for backward compatibility; user specific # restrictions are done later with CTX_set_options() $src = ''; # push error on error stack at end of SWITCH } else { $src = 'Net::SSLeay::TLSv1_3_method()'; } }; /CTX_tlsv1_2_new/ && do { ($ctx = Net::SSLeay::CTX_tlsv1_2_new()) or last; if (defined &Net::SSLeay::TLSv1_2_method) { $src = 'Net::SSLeay::CTX_set_ssl_version(TLSv1_2_method)'; Net::SSLeay::CTX_set_ssl_version($ctx, Net::SSLeay::TLSv1_2_method()) or do {$err = $!} and last; $src = ''; } else { $src = 'Net::SSLeay::TLSv1_2_method()'; } # default timeout is 7200 }; /CTX_tlsv1_1_new/ && do { ($ctx = Net::SSLeay::CTX_tlsv1_1_new()) or last; if (defined &Net::SSLeay::TLSv1_1_method) { $src = 'Net::SSLeay::CTX_set_ssl_version(TLSv1_1_method)'; Net::SSLeay::CTX_set_ssl_version($ctx, Net::SSLeay::TLSv1_1_method()) or do {$err = $!} and last; $src = ''; } else { $src = 'Net::SSLeay::TLSv1_1_method()'; } }; /CTX_tlsv1_new/ && do { ($ctx = Net::SSLeay::CTX_tlsv1_new()) or last; if (defined &Net::SSLeay::TLSv1_method) { $src = 'Net::SSLeay::CTX_set_ssl_version(TLSv1_method)'; Net::SSLeay::CTX_set_ssl_version($ctx, Net::SSLeay::TLSv1_method()) or do {$err = $!} and last; $src = ''; } else { $src = 'Net::SSLeay::TLSv1_2_method()'; } }; /CTX_v23_new/ && do { # we use CTX_v23_new() 'cause of CTX_new() sets SSL_OP_NO_SSLv2 ($ctx = Net::SSLeay::CTX_v23_new()) or last; if (defined &Net::SSLeay::SSLv23_method) { $src = 'Net::SSLeay::CTX_set_ssl_version(SSLv23_method)'; Net::SSLeay::CTX_set_ssl_version($ctx, Net::SSLeay::SSLv23_method()) or do {$err = $!} and last; $src = ''; } else { $src = 'Net::SSLeay::SSLv23_method()'; } # default timeout is 300 }; /CTX_v3_new/ && do { ($ctx = Net::SSLeay::CTX_v3_new()) or last; if (defined &Net::SSLeay::SSLv3_method) { $src = 'Net::SSLeay::CTX_set_ssl_version(SSLv3_method)'; Net::SSLeay::CTX_set_ssl_version($ctx, Net::SSLeay::SSLv3_method()) or do {$err = $!} and last; $src = ''; } else { $src = 'Net::SSLeay::SSLv3_method()'; } }; /CTX_v2_new/ && do { ($ctx = Net::SSLeay::CTX_v2_new()) or last; if (defined &Net::SSLeay::SSLv2_method) { $src = 'Net::SSLeay::CTX_set_ssl_version(SSLv2_method)'; Net::SSLeay::CTX_set_ssl_version($ctx, Net::SSLeay::SSLv2_method()) or do {$err = $!} and last; $src = ''; } else { $src = 'Net::SSLeay::SSLv2_method()'; } }; /CTX_dtlsv1_3_new/ && do { }; /CTX_dtlsv1_2_new/ && do { }; /CTX_dtlsv1_1_new/ && do { }; /CTX_dtlsv1_new/ && do { }; #} # SWITCH return if (not $ctx); # no matching method, ready $_SSLinfo{'CTX_method'} = $method; # for debugging only if ('' ne $src) { # setting protocol options failed (see SWITCH above) push(@{$_SSLinfo{'errors'}}, "_ssleay_ctx_new() WARNING '$src' not available, using system default for '$method'"); # if we don't have proper *_method(), we better use the system's # default behaviour, because anything else would stick on the # specified protocol version, like SSLv3_method() } #2.3. set protocol options my $options = &Net::SSLeay::OP_ALL; # sets all options, even those for all protocol versions (which are removed later) if (0 < $Net::SSLinfo::no_compression) { $options |= &Net::SSLeay::OP_NO_COMPRESSION; # default: OP_ALL does not contain OP_NO_COMPRESSION # this is ok as we want to detect if targets support compression, # disabling compression must be requested with special option } #test# # quick$dirty disable SSL_OP_TLSEXT_PADDING 0x00000010L (see ssl.h) #test# $options ^= 0x00000010; # OP_CIPHER_SERVER_PREFERENCE, OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION # should also be set now $src = 'Net::SSLeay::CTX_set_options()'; # Net::SSLeay::CTX_set_options(); # can not fail according description! Net::SSLeay::CTX_set_options($ctx, 0); # reset options Net::SSLeay::CTX_set_options($ctx, $options); $src = 'Net::SSLeay::CTX_set_timeout()'; ($old = Net::SSLeay::CTX_set_timeout($ctx, $Net::SSLinfo::timeout_sec)) or do {$err = $!; } and last; _trace("_ssleay_ctx_new ::CTX_get_session_cache_mode(CTX)= " . sprintf('0x%08x', Net::SSLeay::CTX_get_session_cache_mode($ctx))); _trace("_ssleay_ctx_new ::CTX_get_timeout(CTX)= $old -> " . Net::SSLeay::CTX_get_timeout($ctx)); _trace("_ssleay_ctx_new ::CTX_get_options(CTX)= " . sprintf('0x%08x', Net::SSLeay::CTX_get_options($ctx))); _traceSSLbitmasks( SSLINFO . "::_ssleay_ctx_new CTX options", Net::SSLeay::CTX_get_options($ctx) ) if (0 < $trace); _trace("_ssleay_ctx_new: $ctx"); return $ctx; } # TRY # reach here if ::CTX_* failed push(@{$_SSLinfo{'errors'}}, "_ssleay_ctx_new() failed calling $src: $err"); _trace("_ssleay_ctx_new: undef"); return; } # _ssleay_ctx_new sub _ssleay_ctx_ca { #? set certificate verify options (client mode); returns undef on failure # uses settings from $Net::SSLinfo::ca* my $ctx = shift; my $ssl = undef; my $src = ''; # function (name) where something failed my $err = ''; my $cafile = ''; my $capath = ''; _traceset(); _trace("_ssleay_ctx_ca($ctx)"); TRY: { Net::SSLeay::CTX_set_verify($ctx, &Net::SSLeay::VERIFY_NONE, \&_check_peer); # we're in client mode where only VERYFY_NONE or VERYFY_PEER is # used; as we want to get all informations, even if something went # wrong, we use VERIFY_NONE so we can proceed collecting data # possible values: # 0 = SSL_VERIFY_NONE # 1 = SSL_VERIFY_PEER # 2 = SSL_VERIFY_FAIL_IF_NO_PEER_CERT # 4 = SSL_VERIFY_CLIENT_ONCE # TODO: SSL_OCSP_NO_STAPLE $src = 'Net::SSLeay::CTX_load_verify_locations()'; $cafile = $Net::SSLinfo::ca_file || ''; if ($cafile !~ m#^(?:[a-zA-Z0-9_,.\\/()-])*$#) { $err = "invalid characters for " . '$Net::SSLinfo::ca_file; not used'; last; } $capath = $Net::SSLinfo::ca_path || ''; if ($capath !~ m#^(?:[a-zA-Z0-9_,.\\/()-]*)$#) { $err = "invalid characters for " . '$Net::SSLinfo::ca_path; not used'; last; } if (($capath . $cafile) ne '') { # CTX_load_verify_locations() fails if both are empty Net::SSLeay::CTX_load_verify_locations($ctx, $cafile, $capath) or do {$err = $!} and last; # CTX_load_verify_locations() sets SSLeay's error stack, which is # roughly the same as $! } $src = 'Net::SSLeay::CTX_set_verify_depth()'; if (defined $Net::SSLinfo::ca_depth) { if ($Net::SSLinfo::ca_depth !~ m/^[0-9]$/) { $err = "invalid value '$Net::SSLinfo::ca_depth' for " . '$Net::SSLinfo::ca_depth; not used'; last; } Net::SSLeay::CTX_set_verify_depth($ctx, $Net::SSLinfo::ca_depth); } # TODO: certificate CRL # just code example, not yet tested # # enable Net::SSLeay CRL checking: # &Net::SSLeay::X509_STORE_set_flags # (&Net::SSLeay::CTX_get_cert_store($ssl), # &Net::SSLeay::X509_V_FLAG_CRL_CHECK); return 1; # success } # TRY push(@{$_SSLinfo{'errors'}}, "_ssleay_ctx_ca() failed calling $src: $err"); _trace("_ssleay_ctx_ca: undef."); return; } # _ssleay_ctx_ca sub _ssleay_ssl_new { #? create new SSL object; return SSL object or undef # uses $Net::SSLinfo::use_SNI my $ctx = shift; my $host = shift; my $socket = shift; my $cipher = shift; my $ssl = undef; my $src = ''; # function (name) where something failed my $err = ''; _traceset(); _trace("_ssleay_ssl_new($ctx)"); TRY: { #3. prepare SSL object $src = 'Net::SSLeay::new()'; ($ssl= Net::SSLeay::new($ctx)) or do {$err = $!} and last; $src = 'Net::SSLeay::set_fd()'; Net::SSLeay::set_fd($ssl, fileno($socket)) or do {$err = $!} and last; $src = "Net::SSLeay::set_cipher_list($cipher)"; Net::SSLeay::set_cipher_list($ssl, $cipher) or do {$err = $!} and last; if (0 < $Net::SSLinfo::use_SNI) { my $sni = $Net::SSLinfo::sni_name; _trace("_ssleay_ssl_new: SNI"); if (1.45 <= $Net::SSLeay::VERSION) { $src = 'Net::SSLeay::set_tlsext_host_name()'; Net::SSLeay::set_tlsext_host_name($ssl, $sni) or do {$err = $!} and last; } else { # quick&dirty instead of: # use constant SSL_CTRL_SET_TLSEXT_HOSTNAME => 55 # use constant TLSEXT_NAMETYPE_host_name => 0 $src = 'Net::SSLeay::ctrl()'; Net::SSLeay::ctrl($ssl, 55, 0, $sni) or do {$err = $!} and last; # TODO: ctrl() sometimes fails but does not return errors, reason yet unknown } } return $ssl; } # TRY push(@{$_SSLinfo{'errors'}}, "_ssleay_ssl_new() failed calling $src: $err"); _trace("_ssleay_ssl_new: undef."); return; } # _ssleay_ssl_new sub _ssleay_ssl_np { #? sets CTX for ALPN and/or NPN if possible # returns -1 on success, otherwise array with errors # Note: check if functionality is available should be done before, # for defensive programming, it's done here again # Note that parameters are different: ALPN array ref. vs. NPN array my $ctx = shift; my $protos_alpn = shift; my $protos_npn = shift; my @protos_alpn = split(/,/, $protos_alpn); # Net::SSLeay wants a list my @protos_npn = split(/,/, $protos_npn); _trace("_ssleay_ssl_np(ctx, $protos_alpn, $protos_npn)"); my $src; my @err; # functions return 0 on success, hence: && do{} to catch errors # ALPN (Net-SSLeay > 1.55, openssl >= 1.0.2) if ($protos_alpn !~ m/^\s*$/) { if (exists &Net::SSLeay::CTX_set_alpn_protos) { $src = 'Net::SSLeay::CTX_set_alpn_protos()'; Net::SSLeay::CTX_set_alpn_protos($ctx, [@protos_alpn]) && do { push(@err, "_ssleay_ssl_np(),alpn failed calling $src: $!"); }; } } # NPN (Net-SSLeay > 1.45, openssl >= 1.0.1) if ($protos_npn !~ m/^\s*$/) { if (exists &Net::SSLeay::CTX_set_next_proto_select_cb) { $src = 'Net::SSLeay::CTX_set_next_proto_select_cb()'; Net::SSLeay::CTX_set_next_proto_select_cb($ctx, @protos_npn) && do { push(@err, "_ssleay_ssl_np(),npn failed calling $src: $!"); }; } } _trace("_ssleay_ssl_np $#err."); return @err; } # _ssleay_ssl_np sub _header_get { #? get value for specified header from given HTTP response; empty if not exists my $head = shift; # header to search for my $response= shift; # response where to serach my $value = ''; _trace("__header_get('$head', <>)"); if ($response =~ m/[\r\n]$head\s*:/i) { $value = $response; $value =~ s/.*?[\r\n]$head\s*:\s*([^\r\n]*).*$/$1/ims; } return $value; } # _header_get sub _openssl_MS { #? wrapper to call external openssl executable on windows my $mode = shift; # must be openssl command my $host = shift; # '' if not used my $port = shift; # '' if not used my $text = shift; # text to be piped to openssl my $data = ''; return '' if ($^O !~ m/MSWin32/); _trace("_openssl_MS($mode, $host, $port)"); if ('' eq $_openssl) { _trace("_openssl_MS($mode): WARNING: no openssl"); return SSLINFO_HASH; } $host .= ':' if ($port ne ''); $text = '""' if (not defined $text); chomp $text; $text = '""' if ($text !~ /[\r\n]/); # $data = `echo '$text' | $_openssl $mode ... 2>&1`; # windows hangs even with empty STDIN, hence we use cmd.exe always # convert multiple lines to an echo for each line $text =~ s/\n/\n echo /g; $text = "(echo $text)"; # it's a subshell now with multiple echo commands my $err = ''; my $src = 'open'; my $tmp = '.\\_yeast.bat'; # do not use $ENV{'TMP'} as it can be empty or unset _trace("_openssl_MS $mode $host$port: cmd.exe /D /C /S $tmp") if (1 < $trace); TRY: { my $fh; open($fh, '>', $tmp) or do {$err = $!} and last; print $fh "$text | $_openssl $mode $host$port 2>&1"; close($fh); #dbx# print `cat $tmp`; $src = 'cmd.exe'; ($data = `cmd.exe /D /S /C $tmp`) or do {$err = $!} and last; $src = 'unlink'; unlink $tmp or do {$err = $!} and last; $data =~ s#^[^)]*[^\r\n]*.##s; # remove cmd.exe's output $data =~ s#WARN.*?openssl.cnf[\r\n]##; # remove WARNINGs _trace("_openssl_MS $mode $host$port : $data #") if (1 < $trace); } if ('' ne $err) { $text = "_openssl_MS() failed calling $src: $err"; _trace($text) if (1 < $trace); push(@{$_SSLinfo{'errors'}}, $text); return ''; } return $data; } # _openssl_MS sub _openssl_x509 { #? call external openssl executable to retrive more data from PEM my $pem = shift; my $mode = shift; # must be one of openssl x509's options my $data = ''; _trace("_openssl_x509($mode,...)."); _setcmd(); if ($_openssl eq '') { _trace("_openssl_x509($mode): WARNING: no openssl"); return SSLINFO_HASH; } if ('' eq $pem) { # if PEM is empty, openssl may return an error like: # unable to load certificate # 140593914181264:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:701:Expecting: TRUSTED CERTIFICATE _trace("_openssl_x509($mode): WARNING: no PEM"); return $Net::SSLinfo::no_cert_txt; } #if ($mode =~ m/^-(text|email|modulus|serial|fingerprint|subject_hash|trustout)$/) { # # supported by openssl's x509 (0.9.8 and higher) #} if ($mode =~ m/^-?(version|pubkey|signame|sigdump|aux|extensions)$/) { # openssl works the other way around: # define as -certopt what should *not* be printed # hence we use a list with all those no_* options and remove that one # which should be printed my $m = 'no_' . $mode; $mode = '-text -certopt no_header,no_version,no_serial,no_signame,no_validity,no_subject,no_issuer,no_pubkey,no_sigdump,no_aux,no_extensions,ext_default,ext_dump'; # ca_default not used as it's already in $_SSLinfo{'text'} $mode =~ s/$m//; $mode =~ s/,,/,/; # need to remove , also, otherwise we get everything } if ($mode =~ m/^-?ocsp/) { $mode = "x509 $mode"; # openssl x509 -ocspid returns data only without noout, probably a bug } else { $mode = "x509 -noout $mode"; } _trace("_openssl_x509(openssl $mode).") if (1 < $trace); if ($^O !~ m/MSWin32/) { $data = `echo '$pem' | $_openssl $mode 2>&1`; } else { # it's sooooo simple, except on Windows :-( $data = _openssl_MS($mode, '', '', $pem); } chomp $data; $data =~ s/\n?-----BEGIN.*$//s if ( $mode =~ m/ -ocsp/); # see above $data =~ s/\s*$//; # be sure ... $data =~ s/\s*Version:\s*//i if (($mode =~ m/ -text /) && ($mode !~ m/version,/)); # ugly test for version #_dbx# print "#3 $data \n#3"; return $data; } # _openssl_x509 ############################################################ public functions # =pod =head2 s_client_check() Check if specified openssl executable is available and check capabilities of "s_client" command.. Returns undef if openssl is not available. =head2 s_client_get_optionlist Get list of options for openssl s_client command. Returns array. =head2 s_client_opt_get($option) Returns 1 if specified option is available for openssl s_client. =cut sub s_client_check { #? store capabilities of "openssl s_client" command in %_OpenSSL_opt return 1 if (0 < $_OpenSSL_opt{'done'}); _traceset(); _trace("s_client_check()"); _setcmd(); if ('' eq $_openssl) { _trace("s_client_check(): WARNING: no openssl"); return undef; ## no critic qw(Subroutines::ProhibitExplicitReturnUndef) } # check with "openssl s_client --help" where --help most likely is unknown # and hence forces the usage message which will be analysed # Note: following checks asume that the returned usage properly describes # openssl's capabilities # Partial example of output: # unknown option --help # usage: s_client args # # -host host - use -connect instead # -port port - use -connect instead # -connect host:port - who to connect to (default is localhost:4433) # -proxy host:port - use HTTP proxy to connect #... # -CApath arg - PEM format directory of CA's # -CAfile arg - PEM format file of CA's # -reconnect - Drop and re-make the connection with the same Session-ID # -pause - sleep(1) after each read(2) and write(2) system call # -debug - extra output # -msg - Show protocol messages # -nbio_test - more ssl protocol testing # -psk_identity arg - PSK identity # -psk arg - PSK in hex (without 0x) # -fallback_scsv - send TLS_FALLBACK_SCSV # -bugs - Switch on all SSL implementation bug workarounds #... # -servername host - Set TLS extension servername in ClientHello # -tlsextdebug - hex dump of all TLS extensions received # -status - request certificate status from server # -no_ticket - disable use of RFC4507bis session tickets # -serverinfo types - send empty ClientHello extensions # -curves arg - Elliptic curves to advertise # -sigalgs arg - Signature algorithms to support # -nextprotoneg arg - enable NPN extension # -alpn arg - enable ALPN extension # -legacy_renegotiation - enable use of legacy renegotiation # -no_tlsext - Don't send any TLS extensions # if ($^O =~ m/MSWin32/) { $_OpenSSL_opt{'data'} = _openssl_MS('s_client -help', '', '', ''); # no host:port } else { $_OpenSSL_opt{'data'} = qx($_openssl s_client -help 2>&1); } #_trace("data{ $_OpenSSL_opt{'data'} }"; # store data very simple: set value to 1 if option appears in output foreach my $key (keys %_OpenSSL_opt) { next if ($key !~ m/^-/); # ensure that only options are set $_OpenSSL_opt{$key} = grep{/^ *$key\s/} split("\n", $_OpenSSL_opt{'data'}); # returns 1 or 0 } $_OpenSSL_opt{'-npn'} = $_OpenSSL_opt{'-nextprotoneg'}; # -npn is an alias $_OpenSSL_opt{'done'} = 1; _trace("s_client_check done."); return 1; } # s_client_check sub _OpenSSL_opt_get{ #? get specified value from %_OpenSSL_opt, parameter 'key' is mandatory my $key = shift; _traceset(); if (0 <= $_OpenSSL_opt{'done'}) { # initilize %_OpenSSL_opt if (not defined s_client_check()) { _trace("_OpenSSL_opt_get('$key') undef"); return SSLINFO_HASH; } } _trace("_OpenSSL_opt_get('$key')=" . ($_OpenSSL_opt{$key} || 0)); return (grep{/^$key$/} keys %_OpenSSL_opt) ? $_OpenSSL_opt{$key} : ''; } # _OpenSSL_opt_get sub s_client_get_optionlist { return (grep{/^-/} keys %_OpenSSL_opt); } sub s_client_opt_get{ return _OpenSSL_opt_get(shift); } =pod =head2 do_ssl_free($ctx,$ssl,$socket) Destroy and free L allocated objects. =cut sub do_ssl_free { #? free SSL objects of NET::SSLeay TCP connection my ($ctx, $ssl, $socket) = @_; close($socket) if (defined $socket); Net::SSLeay::free($ssl) if (defined $ssl); # or warn "**WARNING: Net::SSLeay::free(): $!"; Net::SSLeay::CTX_free($ctx) if (defined $ctx); # or warn "**WARNING: Net::SSLeay::CTX_free(): $!"; return; } # do_ssl_free =pod =head2 do_ssl_new($host,$port,$sslversions[,$cipherlist,$alpns,$npns,$socket]) Establish new SSL connection using L. Returns array with $ssl object, $ctx object, $socket and CTX $method. Errors, if any, are stored in $_SSLtemp{'errors'}. This method is thread safe according the limitations described in L. Use L to free allocated objects. =cut sub do_ssl_new { my ($host, $port, $sslversions, $cipher, $protos_alpn, $protos_npn, $socket) = @_; my $ctx = undef; my $ssl = undef; my $method = undef; my $src; # function (name) where something failed my $err = ''; # error string, if any, from sub-system $src my $tmp_sock= undef;# newly opened socket, # Note: $socket is only used to check if it is defined my $dum = undef; $cipher = '' if (not defined $cipher); # cipher parameter is optional $protos_alpn= '' if (not defined $protos_alpn); # -"- $protos_npn = '' if (not defined $protos_npn); # -"- _traceset(); _trace("do_ssl_new(" . ($host||'') . ',' . ($port||'') . ',' . ($sslversions||'') . ',' . ($cipher||'') . ',' . ($protos_alpn||'') . ',socket)'); _SSLtemp_reset(); # assumes that handles there are already freed TRY: { # TRY_PROTOCOL: { # Open TCP connection and innitilize SSL connection. # This nitialization is done with Net::SSLeay's CTX_*_new and *_method # methods (i.e. CTX_tlsv1_2_new and TLSv1_2_method). # Remember the concepts: work with ancient (perl, openssl) installations # Hence we try all known methods, starting with the most modern first. # The list of methods and its sequence is provided by ssleay_methods. # We loop over this list of methods (aka protocols) until a valid CTX # object will be returned. # NOTE: _ssleay_ctx_new() gets $ctx_new but also needs *_method, which # is not passed as argument. Hence _ssleay_ctx_new() needs to # check for it again, ugly ... may change in future ... # # Some servers (godaddy.com 11/2016) behave strange if the socket will # be reused. In particular they respond with an TLS Alert, complaining # that the protocol is not allowed (alert message 70). # * Until Version 17.03.17 # The socket (if it exists) will be closed and then reopend. # FIXME: 11/2016: not tested if the $Net::SSLinfo::socket is provided # by the caller # * Version 17.04.17 # Socket opened only if it is undef; the caller is responsibel for a # proper $socket value. my @list = ssleay_methods(); foreach my $ctx_new (@list) { next if ($ctx_new !~ m/^CTX_/); next if ($ctx_new =~ m/CTX_new$/); # CTX_new next if ($ctx_new =~ m/_method$/); # i.e. CTX_new_with_method next if ($ctx_new =~ m/_options$/); # i.e. CTX_get_options next if ($ctx_new =~ m/_timeout$/); # i.e. CTX_set_timeout $method = $ctx_new; _trace("do_ssl_new: $method ..."); $src = $ctx_new; #0. first reset Net::SSLeay objects if they exist do_ssl_free($ctx, $ssl, $tmp_sock); $ctx = undef; $ssl = undef; $tmp_sock = undef; #1a. open TCP connection; no way to continue if it fails ($tmp_sock = _ssleay_socket($host, $port, $tmp_sock)) or do {$src = '_ssleay_socket()'} and last TRY; # TODO: need to pass ::starttls, ::proxyhost and ::proxyport #1b. get SSL's context object ($ctx = _ssleay_ctx_new($ctx_new)) or do {$src = '_ssleay_ctx_new()'} and next; #1c. disable not specified SSL versions, limit as specified by user foreach my $_ssl (keys %_SSLmap) { # $sslversions passes the version which should be supported, but # openssl and hence Net::SSLeay, configures what should *not* be # supported, so we skip all versions found in $sslversions next if ($sslversions =~ m/^\s*$/); # no version given, leave default next if (grep{/^$_ssl$/} split(/ /, $sslversions)); my $bitmask = _SSLbitmask_get($_ssl); if (defined $bitmask) { # if there is a bitmask, disable this version _trace("do_ssl_new: OP_NO_$_ssl"); # NOTE: constant name *not* as in ssl.h Net::SSLeay::CTX_set_options($ctx, $bitmask); } #$Net::SSLeay::ssl_version = 2; # Insist on SSLv2 # or =3 or =10 seems not to work, reason unknown, hence CTX_set_options() above } # TODO: Client-Cert see smtp_tls_cert.pl # TODO: proxy settings work in HTTP mode only ##Net::SSLeay::set_proxy('some.tld', 84, 'z00', 'pass'); ##print "#ERR: $!"; #1d. set certificate verification options ($dum = _ssleay_ctx_ca($ctx)) or do {$src = '_ssleay_ctx_ca()' } and next; #1e. set ALPN and NPN option my @err = _ssleay_ssl_np($ctx, $protos_alpn, $protos_npn); if (0 < $#err) { # somthing failed, just collect errors push(@{$_SSLtemp{'errors'}}, @err); } #1f. prepare SSL object ($ssl = _ssleay_ssl_new($ctx, $host, $tmp_sock, $cipher)) or do {$src = '_ssleay_ssl_new()'} and next; #1g. connect SSL local $SIG{PIPE} = 'IGNORE'; # Avoid "Broken Pipe" my $ret; $src = 'Net::SSLeay::connect() '; $ret = Net::SSLeay::connect($ssl); # may call _check_peer() .. if (0 > $ret) { $src .= " failed start with $ctx_new()"; # i.e. no matching protocol $err = $!; push(@{$_SSLtemp{'errors'}}, "do_ssl_new() $src: $err"); next; } # following check only if requested; fails to often if ($Net::SSLinfo::ignore_handshake <= 0){ if (0 == $ret) { $src .= " failed handshake with $ctx_new()"; $err = $!; push(@{$_SSLtemp{'errors'}}, "do_ssl_new() $src: $err"); next; } } $src = ''; last; } # TRY_PROTOCOL } if ('' eq $src) { _trace(join("\n" . SSLINFO_ERR . ' ', '', @{$_SSLtemp{'errors'}})); _trace(" errors reseted."); @{$_SSLtemp{'errors'}} = (); # messages no longer needed goto finished; } else { # connection failed (see TRY_PROTOCOL above) push(@{$_SSLtemp{'errors'}}, "do_ssl_new() connection failed in '$src': $err"); $src = " failed to connect"; last; } #goto finished if (not $ctx); # TODO: not yet properly tested 11/2016 _trace("do_ssl_new: $method"); } # TRY # error handling close($tmp_sock) if (defined $tmp_sock); push(@{$_SSLtemp{'errors'}}, "do_ssl_new() failed calling $src: $err"); if (1 < $trace) { Net::SSLeay::print_errs(SSLINFO_ERR); print SSLINFO_ERR . $_ foreach @{$_SSLtemp{'errors'}}; } _trace("do_ssl_new() failed."); return; finished: _trace("do_ssl_new() done."); return wantarray ? ($ssl, $ctx, $tmp_sock, $method) : $ssl; } # do_ssl_new =pod =head2 do_ssl_open($host,$port,$sslversions[,$cipherlist]) Opens new SSL connection with Net::SSLeay and stores collected data. I<$sslversions> is space-separated list of SSL versions to be used. Following strings are allowed for versions: C. If I<$sslversions> is empty, the system's default settings of versions are used. If I<$cipherlist> is missing or empty, default C will be used. Returns array with $ssl object and $ctx object. This method is called automatically by all other functions, hence no need to call it directly. Use L to free allocated objects. This method tries to use the most modern methods provided by Net::SSLeay to establish the connections, i.e. CTX_tlsv1_2_new or CTX_v23_new. If a method is not available, the next one will be used. The sequence of used methods is hardcoded with most modern first. The current sequence can be seen with: C =cut # from openssl/x509_vfy.h sub _X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT () { return 18; } sub _FLAGS_ALLOW_SELFSIGNED () { return 0x00000001; } sub do_ssl_open($$$@) { my ($host, $port, $sslversions, $cipher) = @_; $cipher = '' if (not defined $cipher); # cipher parameter is optional #$port = _check_port($port); # TODO: port may be empty for some calls; results in "... uninitialized # value $port ..."; need to check if call can provide a port # mainly happens if called with --ignore-no-connect _traceset(); _trace("do_ssl_open(" . ($host||'') . "," . ($port||'') . "," . ($sslversions||'') . "," . ($cipher||'') . ")"); goto finished if (defined $_SSLinfo{'ssl'}); #_traceSSLbitmasks( # SSLINFO . "::do_ssl_open SSL version bitmask", # &Net::SSLeay::OP_ALL #) if (0 < $trace); # TODO: no real value for _traceSSLbitmasks() #_SSLinfo_reset(); # <== does not work yet as it clears everything if ($cipher =~ m/^\s*$/) { $cipher = $_SSLinfo{'cipherlist'}; } else { $_SSLinfo{'cipherlist'} = $cipher; } _trace("do_ssl_open cipherlist: $_SSLinfo{'cipherlist'}"); my $ctx = undef; my $ssl = undef; my $socket = undef; my $method = undef; my $src; # function (name) where something failed my $err = ''; # error string, if any, from sub-system $src # initialize %_OpenSSL_opt $src = 's_client_check'; if (0 < $Net::SSLinfo::use_openssl) { if (not defined s_client_check()) { push(@{$_SSLinfo{'errors'}}, "do_ssl_open() WARNING $src: undefined"); } } if (defined $Net::SSLinfo::next_protos) { # < 1.182 warn "**WARNING: Net::SSLinfo::next_protos no longer supported, please use Net::SSLinfo::protos_alpn instead" } TRY: { #0. first reset Net::SSLinfo objects if they exist # note that $ctx and $ssl is still local and not in %_SSLinfo Net::SSLeay::free($ssl) if (defined $ssl); Net::SSLeay::CTX_free($ctx) if (defined $ctx); if (1 > $Net::SSLinfo::socket_reuse) { close($Net::SSLinfo::socket) if (defined $Net::SSLinfo::socket); $Net::SSLinfo::socket = undef; } #1. open TCP connection; no way to continue if it fails $src = 'Net::SSinfo::do_ssl_new()'; ($ssl, $ctx, $socket, $method) = do_ssl_new($host, $port, $sslversions, $cipher, $Net::SSLinfo::protos_alpn, $Net::SSLinfo::protos_npn, $Net::SSLinfo::socket); if (not defined $ssl) { $err = 'undef $ssl'; last; } if (not defined $ctx) { $err = 'undef $ctx'; last; } $_SSLinfo{'ctx'} = $ctx; $_SSLinfo{'ssl'} = $ssl; $_SSLinfo{'method'} = $method; $Net::SSLinfo::method = $method; $Net::SSLinfo::socket = $socket; push(@{$_SSLinfo{'errors'}}, @{$_SSLtemp{'errors'}}); _trace("do_ssl_open: $Net::SSLinfo::method"); #print "### ext: ". Net::SSLeay::get_tlsext_status_type($ssl); # from here on mainly IO::Socket::SSL is used from within Net::SSLeay # using Net::SSLeay::trace is most likely same as IO::Socket::SSL::DEBUG #dbx# $Net::SSLeay::trace = 2; #dbx# $IO::Socket::SSL::DEBUG = 1; #dbx# Net::SSLeay::print_errs(); #5. SSL established, let's get informations # TODO: starting from here implement error checks $src = 'Net::SSLeay::get_peer_certificate()'; my $x509= Net::SSLeay::get_peer_certificate($ssl); # $x509 may be undef or 0; this may cause "Segmentation fault"s in # some Net::SSLeay::X509_* methods; hence we always use _ssleay_get #5a. get internal data $_SSLinfo{'x509'} = $x509; $_SSLinfo{'_options'} .= sprintf("0x%016x", Net::SSLeay::CTX_get_options($ctx)) if $ctx; $_SSLinfo{'SSLversion'} = $_SSLhex{Net::SSLeay::version($ssl)}; # TODO: Net::SSLeay's documentation also has: # get_version($ssl); get_cipher_version($ssl); # but they are not implemented (up to 1.49) #5b. store actually used ciphers for this connection my $i = 0; my $c = ''; push(@{$_SSLinfo{'ciphers'}}, $c) while ($c = Net::SSLeay::get_cipher_list($ssl, $i++)); $_SSLinfo{'selected'} = Net::SSLeay::get_cipher($ssl); # same as above: Net::SSLeay::CIPHER_get_name(Net::SSLeay::get_current_cipher($ssl)); #5c. store certificate informations $_SSLinfo{'certificate'}= Net::SSLeay::dump_peer_certificate($ssl); # same as issuer + subject #$_SSLinfo{'master_key'} = Net::SSLeay::SESSION_get_master_key($ssl); # TODO: returns binary, hence see below $_SSLinfo{'PEM'} = _ssleay_get('PEM', $x509); # 'PEM' set empty for example when $Net::SSLinfo::no_cert is in use # this inhibits warnings inside perl (see NO Certificate below) $_SSLinfo{'subject'} = _ssleay_get('subject', $x509); $_SSLinfo{'issuer'} = _ssleay_get('issuer', $x509); $_SSLinfo{'before'} = _ssleay_get('before', $x509); $_SSLinfo{'after'} = _ssleay_get('after', $x509); $_SSLinfo{'policies'} = _ssleay_get('policies',$x509); if (1.45 <= $Net::SSLeay::VERSION) { $_SSLinfo{'version'}= _ssleay_get('version', $x509); } else { warn "**WARNING: Net::SSLeay >= 1.45 required for getting version"; } if (1.33 <= $Net::SSLeay::VERSION) {# condition stolen from IO::Socket::SSL, $_SSLinfo{'altname'}= _ssleay_get('altname', $x509); } else { warn "**WARNING: Net::SSLeay >= 1.33 required for getting subjectAltNames"; } if (1.30 <= $Net::SSLeay::VERSION) {# condition stolen from IO::Socket::SSL $_SSLinfo{'cn'} = _ssleay_get('cn', $x509); $_SSLinfo{'cn'} =~ s{\0$}{};# work around Bug in Net::SSLeay <1.33 (from IO::Socket::SSL) } else { warn "**WARNING: Net::SSLeay >= 1.30 required for getting commonName"; } if (1.45 <= $Net::SSLeay::VERSION) { $_SSLinfo{'fingerprint_md5'} = _ssleay_get('md5', $x509); $_SSLinfo{'fingerprint_sha1'}= _ssleay_get('sha1', $x509); $_SSLinfo{'fingerprint_sha2'}= _ssleay_get('sha2', $x509); } else { warn "**WARNING: Net::SSLeay >= 1.45 required for getting fingerprint_md5"; } if (1.46 <= $Net::SSLeay::VERSION) {# see man Net::SSLeay #$_SSLinfo{'pubkey_value'} = Net::SSLeay::X509_get_pubkey($x509); # TODO: returns a structure, needs to be unpacked $_SSLinfo{'error_verify'} = Net::SSLeay::X509_verify_cert_error_string(Net::SSLeay::get_verify_result($ssl)); $_SSLinfo{'error_depth'} = _ssleay_get('error_depth', $x509); $_SSLinfo{'serial_hex'} = _ssleay_get('serial_hex', $x509); $_SSLinfo{'cert_type'} = sprintf("0x%x <>", _ssleay_get('cert_type', $x509) || 0); $_SSLinfo{'subject_hash'} = sprintf("%x", _ssleay_get('subject_hash', $x509) || 0); $_SSLinfo{'issuer_hash'} = sprintf("%x", _ssleay_get('issuer_hash', $x509) || 0); # previous two values are integers, need to be converted to # hex, we omit a leading 0x so they can be used elswhere } else { warn "**WARNING: Net::SSLeay >= 1.46 required for getting some certificate checks"; } $_SSLinfo{'commonName'} = $_SSLinfo{'cn'}; $_SSLinfo{'authority'} = $_SSLinfo{'issuer'}; $_SSLinfo{'owner'} = $_SSLinfo{'subject'}; # used by IO::Socket::SSL, allow for compatibility and lazy user # owner commonName cn subject issuer authority subjectAltNames # alias: owner == subject, issuer == authority, commonName == cn # TODO: certificate chain depth, OCSP # see: http://search.cpan.org/~mikem/Net-SSLeay-1.68/lib/Net/SSLeay.pod#Certificate_verification_and_Online_Status_Revocation_Protocol_%28OCSP%29 #5d. get OSCP related data # TODO: related constants # TLSEXT_STATUSTYPE_ocsp V_OCSP_CERTSTATUS_GOOD V_OCSP_CERTSTATUS_REVOKED # V_OCSP_CERTSTATUS_UNKNOWN # TODO: check if supported # if (not exists &Net::SSLeay::OCSP_cert2ids) { $cfg{'ssleay'}->{'can_ocsp'} = 0 } # # same as IO::Socket::SSL::can_ocsp() IO::Socket::SSL::can_ocsp_staple() # TODO: # see:https://mojolicious.org/perldoc/Net/SSLeay (same as) # https://metacpan.org/pod/release/MIKEM/Net-SSLeay-1.81/lib/Net/SSLeay.pod # # Extract OCSP_RESPONSE. # my $resp = eval { Net::SSLeay::d2i_OCSP_RESPONSE($content) }; # # Check status of response. # my $status = Net::SSLeay::OCSP_response_status($resp); # if ($status != Net::SSLeay::OCSP_RESPONSE_STATUS_SUCCESSFUL()) # die "OCSP response failed: " . Net::SSLeay::OCSP_response_status_str($status); # # set TLS extension before doing SSL_connect # Net::SSLeay::set_tlsext_status_type($ssl, Net::SSLeay::TLSEXT_STATUSTYPE_ocsp()); #5e. get data related to HTTP(S) if (0 < $Net::SSLinfo::use_http) { _trace("do_ssl_open HTTPS {"); #dbx# $host .= 'x'; # TODO: <== some servers behave strange if a wrong hostname is passed # TODO: test with a browser User-Agent my $ua = "User-Agent: Mozilla/5.0 (quark rv:52.0) Gecko/20100101 Firefox/52.0"; my $response = ''; my $request = "GET / HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n"; # $t1 = time(); # ($ctx = Net::SSLeay::CTX_v23_new()) or do {$src = 'Net::SSLeay::CTX_v23_new()'} and last; # FIXME: need to find proper method instead hardcoded CTX_v23_new(); see _ssleay_ctx_new #dbx# $Net::SSLeay::trace = 2; $src = 'Net::SSLeay::write()'; Net::SSLeay::write($ssl, $request) or {$err = $!} and last; $src = 'Net::SSLeay::ssl_read_all()'; # use ::ssl_read_all() instead of ::read() to get HTTP body also $response = Net::SSLeay::ssl_read_all($ssl) || "<>"; _trace("request #{\n$host:$port\n$request"); _trace("request #}"); _trace("response #{\n$response"); _trace("response #}"); if ($response =~ /handshake_failed/) { # may get: http2_handshake_failed $response = "<>"; # no last; # as it will break checks outside } if ($response =~ /bad client magic byte string/) { # http2_handshake_failed # dirty hack with goto #$Net::SSLinfo::protos_alpn = ""; #goto TRY; $response = "<>"; } # TODO: Net::SSLeay::read() fails sometimes, i.e. for fancyssl.hboeck.de # 03/2015: even using ssl_write_all() and ssl_read_all() does not help # TODO: reason unknown, happens probably if server requires SNI # $t2 = time(); set error = "<>"; $_SSLinfo{'https_body'} = $response; $_SSLinfo{'https_body'} =~ s/.*?\r\n\r\n(.*)/$1/ms; $_SSLinfo{'https_location'} = _header_get('Location', $response); # if a new Location is send for HTTPS, we should not follow $_SSLinfo{'https_status'} = $response; $_SSLinfo{'https_status'} =~ s/[\r\n].*$//ms; # get very first line $_SSLinfo{'https_server'} = _header_get('Server', $response); $_SSLinfo{'https_refresh'} = _header_get('Refresh', $response); $_SSLinfo{'https_pins'} = _header_get('Public-Key-Pins', $response); $_SSLinfo{'https_protocols'}= _header_get('Alternate-Protocol', $response); $_SSLinfo{'https_svc'} = _header_get('Alt-Svc', $response); $_SSLinfo{'https_svc'} .= _header_get('X-Firefox-Spdy', $response); $_SSLinfo{'https_sts'} = _header_get('Strict-Transport-Security', $response); $_SSLinfo{'hsts_httpequiv'} = $_SSLinfo{'https_body'}; $_SSLinfo{'hsts_httpequiv'} =~ s/.*?(http-equiv=["']?Strict-Transport-Security[^>]*).*/$1/ims; $_SSLinfo{'hsts_httpequiv'} = '' if ($_SSLinfo{'hsts_httpequiv'} eq $_SSLinfo{'https_body'}); $_SSLinfo{'hsts_maxage'} = $_SSLinfo{'https_sts'}; $_SSLinfo{'hsts_maxage'} =~ s/.*?max-age=([^;" ]*).*/$1/i; $_SSLinfo{'hsts_subdom'} = 'includeSubDomains' if ($_SSLinfo{'https_sts'} =~ m/includeSubDomains/i); $_SSLinfo{'hsts_preload'} = 'preload' if ($_SSLinfo{'https_sts'} =~ m/preload/i); # TODO: $_SSLinfo{'hsts_alerts'} =~ s/.*?((?:alert|error|warning)[^\r\n]*).*/$1/i; # TODO: HTTP header: # X-Firefox-Spdy: 3.1 # X-Firefox-Spdy: h2 (seen at policy.mta-sts.google.com 9/2016) # X-Firefox-Spdy most likely returned only for proper User-Agent _trace("do_ssl_open HTTPS }"); _trace("do_ssl_open HTTP {"); # HTTP uses its own connection ... my %headers; $src = 'Net::SSLeay::get_http()'; ($response, $_SSLinfo{'http_status'}, %headers) = Net::SSLeay::get_http($host, 80, '/', Net::SSLeay::make_headers('Connection' => 'close', 'Host' => $host) # TODO: test with a browser User-Agent # 'User-Agent' => 'Mozilla/5.0 (quark rv:52.0) Gecko/20100101 Firefox/52.0'; ); # NOTE that get_http() returns all keys in %headers capitalized my $headers = ""; # for trace only foreach my $h (keys %headers) { $headers .= "$h: $headers{$h}\n"; } _trace("request #{\n$host:$port\n$request"); _trace("request #}"); _trace("response #{\n$headers\n$response"); _trace("response #}"); # Net::SSLeay 1.58 (and before) # Net::SSLeay::get_http() may return: # Read error: Connection reset by peer (,199725) at blib/lib/Net/SSLeay.pm (autosplit into blib/lib/auto/Net/SSLeay/tcp_read_all.al) line 535. # Read error: Die Verbindung wurde vom Kommunikationspartner zurückgesetzt (,199725) at blib/lib/Net/SSLeay.pm (autosplit into blib/lib/auto/Net/SSLeay/tcp_read_all.al) line 535. # # Unfortunately in this case Net::SSLeay::ERR_get_error is 0 # and Net::SSLeay::print_errs() returns nothing even the error # is present as string (according current locale) in $!. # It still may return a response and a status, hence there is # need to handle it special as the check for the status below # already does the work. # The error is printed by Net/SSLeay, and cannot be omitted. # # Following error ocours (Net::SSLeay 1.58) when _http() failed: # Use of uninitialized value $headers in split at blib/lib/Net/SSLeay.pm (autosplit into blib/lib/auto/Net/SSLeay/do_httpx2.al) line 1291. # $t3 = time(); set error = "<>"; if ($_SSLinfo{'http_status'} =~ m:^HTTP/... ([1234][0-9][0-9]|500) :) { # TODO: not tested if following grep() catches multiple occourances $_SSLinfo{'http_location'} = $headers{(grep{/^Location$/i} keys %headers)[0] || ''}; $_SSLinfo{'http_refresh'} = $headers{(grep{/^Refresh$/i} keys %headers)[0] || ''}; $_SSLinfo{'http_sts'} = $headers{(grep{/^Strict-Transport-Security$/i} keys %headers)[0] || ''}; $_SSLinfo{'http_svc'} = $headers{(grep{/^Alt-Svc$/i} keys %headers)[0] || ''} || ''; $_SSLinfo{'http_svc'} .= $headers{(grep{/^X-Firefox-Spdy$/i} keys %headers)[0] || ''} || ''; $_SSLinfo{'http_protocols'} = $headers{(grep{/^Alternate-Protocol/i} keys %headers)[0] || ''}; # TODO: http_protocols somtimes fails, reason unknown (03/2015) } else { # any status code > 500 #no print "**WARNING: http:// connection refused; consider using --no-http"; # no print here! push(@{$_SSLinfo{'errors'}}, "do_ssl_open() WARNING $src: " . $_SSLinfo{'http_status'}); if ($_SSLinfo{'http_status'} =~ m:^HTTP/... (50[12345]) :) { # If we get status 50x, there is most likely a (local) # proxy which is not able to connect to the target. # This could either be 'cause the target refuses the # connection (status 503 and 504) or 'cause the proxy # itself has a problem. # HTTP headers and response may contain more hints. push(@{$_SSLinfo{'errors'}}, "do_ssl_open() WARNING $src: check HTTP gateway"); #} else { Net::SSLeay::get_http() most likely returns status 900 } $response = ''; # avoid uninitialized value later } _trace("do_ssl_open HTTP }"); } if (0 == $Net::SSLinfo::use_openssl) { # calling external openssl is a performance penulty # it would be better to manually parse $_SSLinfo{'text'} but that # needs to be adapted to changes of openssl's output then _trace("do_ssl_open() without openssl done."); goto finished; } #5f. get data from openssl, if required # NOTE: all following are only available when openssl is used # those alredy set before will be overwritten # NO Certificate { # We get following data using openssl executable. # There is no need to check $Net::SSLinfo::no_cert as openssl is # clever enough to return following strings if the cert is missing: # unable to load certificate # If we use 'if (defined $_SSLinfo{'PEM'}) ' instead of an empty # $_SSLinfo{'PEM'} (see initial setting above), then all values # would contain an empty string instead of the the openssl warning: # unable to load certificate my $fingerprint = _openssl_x509($_SSLinfo{'PEM'}, '-fingerprint'); chomp $fingerprint; $_SSLinfo{'fingerprint_text'} = $fingerprint; $_SSLinfo{'fingerprint'} = $fingerprint; #alias ($_SSLinfo{'fingerprint_type'}, $_SSLinfo{'fingerprint_hash'}) = split(/=/, $fingerprint); $_SSLinfo{'fingerprint_type'} = $Net::SSLinfo::no_cert_txt if (not defined $_SSLinfo{'fingerprint_type'}); $_SSLinfo{'fingerprint_hash'} = $Net::SSLinfo::no_cert_txt if (not defined $_SSLinfo{'fingerprint_hash'}); $_SSLinfo{'fingerprint_type'} =~ s/\s+.*$//; $_SSLinfo{'fingerprint_type'} =~ s/(^[^\s]*).*/$1/ if (m/^[^\s]*/); # TODO: ugly check $_SSLinfo{'subject_hash'} = _openssl_x509($_SSLinfo{'PEM'}, '-subject_hash'); $_SSLinfo{'issuer_hash'} = _openssl_x509($_SSLinfo{'PEM'}, '-issuer_hash'); $_SSLinfo{'version'} = _openssl_x509($_SSLinfo{'PEM'}, 'version'); $_SSLinfo{'text'} = _openssl_x509($_SSLinfo{'PEM'}, '-text'); $_SSLinfo{'modulus'} = _openssl_x509($_SSLinfo{'PEM'}, '-modulus'); #$_SSLinfo{'serial'} = _openssl_x509($_SSLinfo{'PEM'}, '-serial'); # done below $_SSLinfo{'email'} = _openssl_x509($_SSLinfo{'PEM'}, '-email'); $_SSLinfo{'trustout'} = _openssl_x509($_SSLinfo{'PEM'}, '-trustout'); $_SSLinfo{'ocsp_uri'} = _openssl_x509($_SSLinfo{'PEM'}, '-ocsp_uri'); $_SSLinfo{'ocspid'} = _openssl_x509($_SSLinfo{'PEM'}, '-ocspid'); $_SSLinfo{'aux'} = _openssl_x509($_SSLinfo{'PEM'}, 'aux'); $_SSLinfo{'pubkey'} = _openssl_x509($_SSLinfo{'PEM'}, 'pubkey'); $_SSLinfo{'extensions'} = _openssl_x509($_SSLinfo{'PEM'}, 'extensions'); $_SSLinfo{'signame'} = _openssl_x509($_SSLinfo{'PEM'}, 'signame'); $_SSLinfo{'sigdump'} = _openssl_x509($_SSLinfo{'PEM'}, 'sigdump'); ($_SSLinfo{'sigkey_value'} = $_SSLinfo{'sigdump'}) =~ s/.*?\n//ms; ($_SSLinfo{'pubkey_algorithm'} = $_SSLinfo{'pubkey'}) =~ s/^.*?Algorithm: ([^\r\n]*).*/$1/si; ($_SSLinfo{'pubkey_value'} = $_SSLinfo{'pubkey'}) =~ s/^.*?Modulus ?([^\r\n]*)//si; # damn Windows: some versions behave like *NIX and return: # Modulus (2048 bit): # but some versions return: # Modulus: # which makes the regex dirty: space followed by question mark $_SSLinfo{'pubkey_value'} =~ s/^.*?pub:([^\r\n]*)//si; # public key with EC use "pub:" instead of "Modulus:" $_SSLinfo{'pubkey_value'} =~ s/(Exponent|ASN1 OID).*//si; # public key with EC use "ASN1 OID:" instead of "Exponent:" $_SSLinfo{'modulus_exponent'} = $_SSLinfo{'pubkey'}; $_SSLinfo{'modulus_exponent'} =~ s/^.*?(?:Exponent|ASN1 OID): (.*)$/$1/si; $_SSLinfo{'modulus'} =~ s/^[^=]*=//i; $_SSLinfo{'signame'} =~ s/^[^:]*: //i; $_SSLinfo{'modulus_len'} = 4 * length($_SSLinfo{'modulus'}); # Note: modulus is hex value where 2 characters are 8 bit if ($_SSLinfo{'sigkey_value'} ne $Net::SSLinfo::no_cert_txt) { $_SSLinfo{'sigkey_len'} = $_SSLinfo{'sigkey_value'}; $_SSLinfo{'sigkey_len'} =~ s/[\s\n]//g; $_SSLinfo{'sigkey_len'} =~ s/[:]//g; $_SSLinfo{'sigkey_len'} = 4 * length($_SSLinfo{'sigkey_len'}); } chomp $_SSLinfo{'fingerprint_hash'}; chomp $_SSLinfo{'modulus'}; chomp $_SSLinfo{'pubkey'}; chomp $_SSLinfo{'signame'}; # NO Certificate } $_SSLinfo{'s_client'} = do_openssl('s_client', $host, $port, ''); # this should be the forst call to openssl herein my $eee = $_SSLinfo{'s_client'}; if ($eee =~ m/.*(?:\*\*ERROR)/) { # pass errors to caller $eee =~ s/.*(\*\*ERROR[^\n]*).*/$1/s; push(@{$_SSLinfo{'errors'}}, "do_ssl_open() WARNING openssl: $eee"); } else { $eee = ''; } # FIXME: lazy and incomplete approach to pass errors # from s_client: (if openssl supports -nextprotoneg) # Protocols advertised by server: spdy/4a4, spdy/3.1, spdy/3, http/1.1 # from s_client: (openssl > 1.0.1) # Peer signing digest: SHA512 # Server Temp Key: DH, 2048 bits # Server Temp Key: ECDH, P-256, 256 bits # from s_client: # SSL-Session: # Protocol : TLSv1 # Cipher : ECDHE-RSA-RC4-SHA # Session-ID: 322193A0D243EDD1C07BA0B2E68D1044CDB06AF0306B67836558276E8E70655C # Session-ID-ctx: # Master-Key: EAC0900291A1E5B73242C3C1F5DDCD4BAA7D9F8F4BC6E640562654B51E024143E5403716F9BF74672AF3703283456403 # Key-Arg : None # Krb5 Principal: None # PSK identity: None # PSK identity hint: None # SRP username: None # Timeout : 300 (sec) # Compression: zlib compression # Expansion: zlib compression # TLS session ticket lifetime hint: 100800 (seconds) # TLS session ticket: # 0000 - 00 82 87 03 7b 42 7f b5-a2 fc 9a 95 9c 95 2c f3 ....{B........,. # 0010 - 69 91 54 a9 5b 7a 32 1c-08 b1 6e 3c 8c b7 b8 1f i.T.[z2...n<.... # 0020 - e4 89 63 3e 3c 0c aa bd-96 70 30 b2 cd 1e 2d c0 ..c><....p0...-. # 0030 - e7 fe 10 cd d4 82 e9 8f-d8 ee 91 16 02 42 7b 93 .............B}. # 0040 - fc 93 82 c4 d3 fd 0a f3-c6 3d 77 ab 1d 25 4f 5a .........=w..%OZ # 0050 - fc 44 9a 21 3e cb 18 e9-a4 44 1b 30 7c 98 4d 04 .D.!>....D.0|.M. # 0060 - bb 12 3e 67 c8 9a ad 99-b4 50 32 81 1e 54 70 2d ..>g.....P2..Tp- # 0070 - 06 08 82 30 9a 94 82 6f-e2 fa c7 e8 5a 19 af dc ...0...o....Z... # 0080 - 70 45 71 f9 d1 e6 a8 d7-3c c2 c6 b8 e1 d5 4f dd pEq.....<.....O. # 0090 - 52 12 f3 90 0c 51 c5 81-6c 9e 69 b6 bd 0c e6 e6 R....Q..l.i..... # 00a0 - 4c d4 72 33 L.r3 # # Start Time: 1435254245 my %match_map = ( # %_SSLinfo key string to match in s_client output #-------------------+----------------------------------- 'session_id' => "Session-ID:", 'master_key' => "Master-Key:", 'krb5' => "Krb5 Principal:", 'psk_identity' => "PSK identity:", 'psk_hint' => "PSK identity hint:", 'srp' => "SRP username:", 'compression' => "Compression:", 'expansion' => "Expansion:", 'alpn' => "ALPN protocol:", 'no_alpn' => "No ALPN negotiated", # has no value, see below 'next_protocol' => "Next protocol:", 'next_protocols' => "Protocols advertised by server:", 'session_protocol' => "Protocol\\s+:", # \s must be meta 'session_timeout' => "Timeout\\s+:", # \s must be meta 'session_lifetime' => "TLS session ticket lifetime hint:", 'session_starttime'=> "Start Time:", #'session_ticket' => "TLS session ticket:", # this is a multiline value, must be handled special, see below #'renegotiation' => "Renegotiation", # Renegotiation comes with different values, see below 'dh_parameter' => "Server Temp Key:", #'ocsp_response_data' => "OCSP response:", # this is a multiline value, must be handled special, see below ); my $d = ''; my $data = $_SSLinfo{'text'}; # from text: # Serial Number: 11598581680733355983 (0xa0f670963276ffcf) $d = $data; $d =~ s/.*?Serial Number:\s*(.*?)\n.*/$1/si; $_SSLinfo{'serial'} = $d; $d =~ s/\s.*$//; $_SSLinfo{'serial_int'} = $d; # getting integer value from text representation 'cause # Net::SSLeay does not have a proper function # and converting the retrived hex value to an int with # hex($hex) returns an error without module bigint if ($d =~ m/[0-9a-f]:/i) { # some certs return 09:f5:fd:2e:a5:2a:85:48:db:be:5d:a0:5d:b6 # or similar, then we try to convert to integer manually $d =~ s/://g; my $b = 8; # the usual size in 64-bit systems if (8 < length($d)) { # check if we are on 32-bit system # on 32-bit systems perl may handle large numbers correctly # if compiled properly, can be checked with $Config{ivsize} # so we need the value which requires loading the module # # cannot use eval with block form here, needs to be quoted ## no critic qw(BuiltinFunctions::ProhibitStringyEval) if (eval('use Config; $b = $Config{ivsize};')) { # use $Config{ivsize} } else { $err = "use Config"; push(@{$_SSLinfo{'errors'}}, "do_ssl_open(),Cfg failed calling $src: $err"); $_SSLinfo{'serial_int'} = "<<$err failed>>"; } ## use critic } if (($b < length($d)) # larger than integer of this architecture ||(16 < length($d))) # to large at all { # ugly check if we need bigint if (eval {require Math::BigInt;}) { $_SSLinfo{'serial_int'} = Math::BigInt->from_hex($d); } else { $err = "Math::BigInt->from_hex($d)"; push(@{$_SSLinfo{'errors'}}, "do_ssl_open(),Big failed calling $src: $err"); $_SSLinfo{'serial_int'} = "<<$err failed>>"; } } else { $_SSLinfo{'serial_int'} = hex($d); } } $data = $_SSLinfo{'s_client'}; # Note: as openssl s_client is called with -resume, the retrived # data may contain output of s_client up to 5 times # it's not ensured that all 5 data sets are identical, hence # we need to check them all -at least the last one- # Unfortunately all following checks use all 5 data sets. foreach my $key (keys %match_map) { my $regex = $match_map{$key}; $d = $data; $d =~ s/.*?$regex\s*([^\n]*)\n.*/$1/si; if ($data =~ m/$regex/) { $_SSLinfo{$key} = $d if ($data =~ m/$regex/); $_SSLinfo{$key} = $regex if ($key eq 'no_alpn'); # no_alpn: single line, has no value: No ALPN negotiated } } # from s_client: # .... # Start Time: 1544899903 # Timeout : 300 (sec) # Verify return code: 0 (ok) # --- my $key = 'session_starttime'; $_SSLinfo{'session_startdate'} = scalar localtime($_SSLinfo{$key}); # add human readable time # from s_client: # OCSP response: no response sent # or: # OCSP response: # ====================================== # OCSP Response Data: # OCSP Response Status: successful (0x0) # Response Type: Basic OCSP Response # Version: 1 (0x0) # Responder Id: 1C6C1E3B17EDF8DAB15CEBCDBC2D315868862497 # Produced At: Jul 7 16:34:44 2018 GMT # Responses: # Certificate ID: # Hash Algorithm: sha1 # Issuer Name Hash: 881A4A74FEFF4652F354BB510FD3A4EEEFE0A1C8 # Issuer Key Hash: 919E3B446C3D579C42772A34D74FD1CC4A972CDA # Serial Number: 2000036E72ADED906765595FAE000000036E72 # Cert Status: good # This Update: Jul 7 16:34:44 2018 GMT # Next Update: Jul 11 16:34:44 2018 GMT # Response Single Extensions: # OCSP Archive Cutoff: # Jul 7 16:34:44 2017 GMT # # Signature Algorithm: sha256WithRSAEncryption # .... # (following Signature and Certificate date not shown and skipped) # TODO: extract single values 'ocsp_response_*' from above output, # can be done with %match_map $d = $data; $d =~ s/.*?OCSP response:\s*([a-zA-Z0-9,. -]+)[\n\r].*/$1/si; if ($d =~ m/^\s*$/) { # probably complete OCSP Response Data: $d = $data; $d =~ s/.*?OCSP response:\s*[\n\r]+(.*?)[\n\r][\n\r].*/$1/si; $d =~ s/^[\n\r]*//; if ($d =~ m/OCSP Response Status:\s*([^\n\r]+)[\n\r]/i) { $_SSLinfo{'ocsp_response_status'} = $1; } if ($d =~ m/Cert Status:\s*([^\n\r]+)[\n\r]/i) { $_SSLinfo{'ocsp_cert_status'} = $1; } if ($d =~ m/This Update:\s*([^\n\r]+)[\n\r]/i) { $_SSLinfo{'ocsp_this_update'} = $1; } if ($d =~ m/Next Update:\s*([^\n\r]+)[\n\r]/i) { $_SSLinfo{'ocsp_next_update'} = $1; } $_SSLinfo{'ocsp_response'} = "Response Status: " . $_SSLinfo{'ocsp_response_status'} . "; Cert Status: " . $_SSLinfo{'ocsp_cert_status'} . "; This Update: " . $_SSLinfo{'ocsp_this_update'} . "; Next Update: " . $_SSLinfo{'ocsp_next_update'}; # TODO: no extract more important values } else { # probably only OCSP response: $_SSLinfo{'ocsp_response'} = $d; } $_SSLinfo{'ocsp_response_data'} = $d; # complete string, both cases above $d = $data; $d =~ s/.*?TLS session ticket:\s*[\n\r]+(.*?)\n\n.*/$1_/si; if ($data =~ m/TLS session ticket:/) { $d =~ s/\s*[0-9a-f]{4}\s*-\s*/_/gi; # replace leading numbering with marker $d =~ s/^_//g; # remove useless marker $d =~ s/ .{16}//g; # remove traling characters $d =~ s/[^0-9a-f]//gi; # remove all none hex characters $_SSLinfo{'session_ticket'} = $d; } # from s_client: # Secure Renegotiation IS supported # Secure Renegotiation IS NOT supported # TODO: pedantically we also need to check if "RENEGOTIATING" is # there, as just the information "IS supported" does not # mean that it works $d = $data; $d =~ s/.*?((?:Secure\s*)?Renegotiation[^\n]*)\n.*/$1/si; $_SSLinfo{'renegotiation'} = $d; # from s_client: # Reused, TLSv1/SSLv3, Cipher is RC4-SHA # Session-ID: F4AD8F441FDEBDCE445D4BD676EE592F6A0CEDA86F08860DF824F8D29049564F # Start Time: 1387270456 # we do a simple check: just grep for "Reused" in s_client # in details it should check if all "Reused" strings are # identical *and* the "Session-ID" is the same for all # if more than 2 "New" are detected, we assume no resumption # finally "Reused" must be part of s_client data # should also check "Start Time" $d = $data; my $cnt =()= $d =~ m/(New|Reused),/g; if ($cnt < 3) { _trace("do_ssl_open: slow target server; resumption not detected; try to increase \$Net::SSLinfo::timeout_sec"); } else { $cnt =()= $d =~ m/New,/g; _trace("do_ssl_open: checking resumption: found $cnt `New' "); if ($cnt > 2) { # too much "New" reconnects, assume no resumption $cnt =()= $d =~ m/Reused,/g; _trace("do_ssl_open: checking resumption: found $cnt `Reused' "); $_SSLinfo{'resumption'} = 'no'; } else { $d =~ s/.*?(Reused,[^\n]*).*/$1/si; $_SSLinfo{'resumption'} = $d if ($d =~ m/Reused,/); } } # from s_client (different openssl return different strings): # verify error:num=10:certificate has expired # verify error:num=18:self signed certificate # verify error:num=20:unable to get local issuer certificate # verify error:num=21:unable to verify the first certificate # verify error:num=27:certificate not trusted # # s_client returns at end: # Verify return code: 0 (ok) # or just one of following, even if more than one applies: # Verify return code: 10 (certificate has expired) # Verify return code: 19 (self signed certificate in certificate chain) # Verify return code: 20 (unable to get local issuer certificate) # Verify return code: 21 (unable to verify the first certificate) # # following matches any line, but return first only: # TODO: need more extensive tests with different servers and openssl versions $d = $data; $d =~ s/.*?Verify (?:error|return code):\s*((?:num=)?[\d]*[^\n]*).*/$1/si; $_SSLinfo{'verify'} = $d; # TODO: $_SSLinfo{'verify_host'}= $ssl->verify_hostname($host, 'http'); # returns 0 or 1 # scheme can be: ldap, pop3, imap, acap, nntp http, smtp $d =~ s/.*?(self signed.*)/$1/si; $_SSLinfo{'selfsigned'} = $d; # beside regex above, which relies on strings returned from s_client # we can compare subject_hash and issuer_hash, which are eqal when # self-digned # from s_client: # $_SSLinfo{'s_client'} grep # Certificate chain $d = $data; $d =~ s/.*?Certificate chain[\r\n]+(.*?)[\r\n]+---[\r\n]+.*/$1/si; $_SSLinfo{'chain'} = $d; # from s_client: # $_SSLinfo{'s_client'} grep # depth= ... --- $d = $data; $d =~ s/.*?(depth=-?[0-9]+.*?)[\r\n]+---[\r\n]+.*/$1/si; $_SSLinfo{'chain_verify'} = $d; #dbx# print "TLS: $data\n"; # from s_client -tlsextdebug -nextprotoneg # TLS server extension "server name" (id=0), len=0 # TLS server extension "renegotiation info" (id=65281), len=1 # TLS server extension "session ticket" (id=35), len=0 # TLS server extension "heartbeat" (id=15), len=1 # TLS server extension "EC point formats" (id=11), len=4 # TLS server extension "next protocol" (id=13172), len=25 # TLS server extension "session ticket" (id=35), len=0 foreach my $line (split(/[\r\n]+/, $data)) { next if ($line !~ m/TLS server extension/i); $d = $line; $d =~ s/TLS server extension\s*"([^"]*)"/$1/i; # remove prefix text, but leave id= and len= for caller my $rex = $d; # $d may contain regex meta characters, like () $rex =~ s#([(/*)])#\\$1#g; next if ((grep{/$rex/} split(/\n/, $_SSLinfo{'tlsextensions'})) > 0); $_SSLinfo{'tlsextdebug'} .= "\n" . $line; $_SSLinfo{'tlsextensions'} .= "\n" . $d; $_SSLinfo{'heartbeat'}= $d if ($d =~ m/heartbeat/); # following already done, see above, hence with --trace only _trace("-tlsextdebug $d") if ($d =~ m/session ticket/); _trace("-tlsextdebug $d") if ($d =~ m/renegotiation info/); } $_SSLinfo{'tlsextensions'} =~ s/\([^)]*\),?\s+//g; # remove additional informations $_SSLinfo{'tlsextensions'} =~ s/\s+len=\d+//g; # ... _trace("do_ssl_open() with openssl done."); print Net::SSLinfo::datadump() if (0 < $trace); goto finished; } # TRY #6. error handling push(@{$_SSLinfo{'errors'}}, "do_ssl_open(),TRY failed calling $src: $err"); if (1 < $trace) { Net::SSLeay::print_errs(SSLINFO_ERR); print SSLINFO_ERR . $_ foreach @{$_SSLinfo{'errors'}}; } _trace("do_ssl_open() failed."); return; finished: _trace("do_ssl_open() done."); return wantarray ? ($_SSLinfo{'ssl'}, $_SSLinfo{'ctx'}) : $_SSLinfo{'ssl'}; } # do_ssl_open =pod =head2 do_ssl_close( ) Close L connection and free allocated objects. =cut sub do_ssl_close($$) { #? close TCP connection for SSL my ($host, $port) = @_; _trace("do_ssl_close($host,$port)"); do_ssl_free($_SSLinfo{'ctx'}, $_SSLinfo{'ssl'}, $Net::SSLinfo::socket); _SSLinfo_reset(); $Net::SSLinfo::socket = undef; $Net::SSLinfo::method = ''; return; } # do_ssl_close =pod =head2 do_openssl($command,$host,$port,$data) Wrapper for call of external L executable. Handles special behaviours on some platforms. If I<$command> equals C it will add C<-reconnect -connect> to the openssl call. All other values of I<$command> will be used verbatim. Note that the SSL version must be part (added) as proper openssl option to C<$command> as this option cannot preceed the command in openssl.. Examples for I<$command>: ciphers -sslv3 s_client -tlsv1_1 -connect The value of I<$data>, if set, is piped to openssl. Returns retrieved data or '<>' if openssl or s_client missing. Returns '<>' if PEM missing. =cut sub do_openssl($$$$) { #? call external openssl executable to retrive more data my $mode = shift; # must be openssl command my $host = shift; my $port = shift || ''; # may be empty for some calls my $pipe = shift || ''; # piped data is optional my $data = ''; my $capath = $Net::SSLinfo::ca_path || ''; my $cafile = $Net::SSLinfo::ca_file || ''; _trace("do_openssl($mode,$host,$port...)."); _setcmd(); if ('' eq $_openssl) { _trace("do_openssl($mode): WARNING: no openssl"); return SSLINFO_HASH; } if ($mode =~ m/^-?s_client$/) { if ($Net::SSLinfo::file_sclient !~ m/^\s*$/) { if (open(my $fh, '<:encoding(UTF-8)', $Net::SSLinfo::file_sclient)) { undef $/; # get anything $data = <$fh>; close($fh); return $data; } _trace("do_openssl($mode): WARNING: cannot open $Net::SSLinfo::file_sclient"); return SSLINFO_HASH; } if (0 == $Net::SSLinfo::use_sclient) { _trace("do_openssl($mode): WARNING: no openssl s_client") if (1 < $trace); return SSLINFO_HASH; } # TODO: Optionen hier entfernen, muss im Caller gemacht werden # pass -alpn option to validate 'protocols' support later # pass -nextprotoneg option to validate 'protocols' support later # pass -reconnect option to validate 'resumption' support later # pass -tlsextdebug option to validate 'heartbeat' support later # pass -status option to get 'ocsp_response_data' support later # NOTE that openssl 1.x or later is required for -nextprotoneg # NOTE that openssl 1.0.2 or later is required for -alpn $mode = 's_client' . $Net::SSLinfo::sclient_opt; # FIXME: { following fixes general verify, but not self signed $mode .= ' -CApath ' . $capath if ('' ne $capath); $mode .= ' -CAfile ' . $cafile if ('' ne $cafile); # } $mode .= ' -reconnect' if (1 == $Net::SSLinfo::use_reconnect); $mode .= ' -tlsextdebug' if (1 == $Net::SSLinfo::use_extdebug); $mode .= ' -status'; } if (($mode =~ m/^-?s_client$/) || ($mode =~ m/^-?s_client.*?-cipher/)) { $mode .= ' -alpn ' . $Net::SSLinfo::protos_alpn if (1 == $Net::SSLinfo::use_alpn); $mode .= ' -nextprotoneg ' . $Net::SSLinfo::protos_npn if (1 == $Net::SSLinfo::use_npn); } if ($mode =~ m/^-?s_client/) { $mode .= ' -connect' if ($mode !~ m/-connect/); } $host = $port = '' if ($mode =~ m/^-?(ciphers)/); # TODO: may be scary _trace("echo '' | $_timeout $_openssl $mode $host:$port 2>&1"); if ($^O !~ m/MSWin32/) { $host .= ':' if ($port ne ''); $data = `echo $pipe | $_timeout $_openssl $mode $host$port 2>&1`; if ($data =~ m/(\nusage:|unknown option)/s) { #$data =~ s/((?:usage:|unknown option)[^\r\n]*).*/$1/g; my $u1 = $data; $u1 =~ s/.*?(unknown option[^\r\n]*).*/$1/s; my $u2 = $data; $u2 =~ s/.*?\n(usage:[^\r\n]*).*/$1/s; $data = "**ERROR: $u1\n**ERROR: $u2\n"; # pass basic error string to caller _trace("do_openssl($mode): WARNING: openssl does not support -nextprotoneg option"); push(@{$_SSLinfo{'errors'}}, "do_openssl($mode) failed: $data"); # try to do it again with mostly safe options $mode = 's_client'; $mode .= ' -CApath ' . $capath if ('' ne $capath); $mode .= ' -CAfile ' . $cafile if ('' ne $cafile); $mode .= ' -reconnect' if (1 == $Net::SSLinfo::use_reconnect); $mode .= ' -connect'; $data .= `echo $pipe | $_timeout $_openssl $mode $host$port 2>&1`; } } else { $data = _openssl_MS($mode, $host, $port, ''); if ($data =~ m/(\nusage:|unknown option)/s) { # we like performance penulties ... _trace("do_openssl($mode): WARNING: openssl does not support -nextprotoneg option"); $data = _openssl_MS($mode, $host, $port, ''); } } if ($mode =~ m/^-?(ciphers)/) { # check for errors in getting cipher list if ($data =~ m/^\s*(?:Error|openssl)(?: |:)/i) { push(@{$_SSLinfo{'errors'}}, "do_openssl($mode) failed: $data"); $data = ''; } } chomp $data; $data =~ s/\s*$//; # be sure ... return $data; } # do_openssl # From here on, we use a pod sections for multiple functions, then the # corresponding function definitions follow that section. This is done # to make the code more readable for humans. =pod =head2 set_cipher_list($ssl,$cipherlist) Set cipher list for connection. List is colon-separated list of ciphers. Returns empty string on success, errors otherwise. =cut sub set_cipher_list { my $ssl = shift; my $cipher = shift; Net::SSLeay::set_cipher_list($ssl, $cipher) or return SSLINFO . '::set_cipher_list(' . $cipher . ')'; $_SSLinfo{'cipherlist'} = $cipher; return ''; } =pod =head2 errors( ) Get list of errors, intenal ones but most likely from I<$Net::SSLeay::*> calls. =head2 s_client( ) Dump data retrived from "openssl s_client ..." call. For debugging only. =head2 options( ) Return hex value bitmask of (openssl) options used to establish connection. Useful for debugging and trouble shooting. =head2 PEM( ), pem( ) Get certificate in PEM format. =head2 text( ) Get certificate in human readable format. =head2 before( ) Get date before certificate is valid. =head2 after( ) Get date after certificate is valid. =head2 dates( ) Get dates when certificate is valid. =head2 issuer( ) Get issuer of certificate. =head2 subject( ) Get subject of certificate. =head2 selected( ) Get cipher selected by server for current session. Returns ciphers string. =head2 cipher_list($pattern) Get cipher list offered by local SSL implementation (i.g. Net::SSLeay). Returns space-separated list of ciphers. Returns array if used in array context, a single string otherwise. Requires successful connection to target. =head2 cipher_openssl($pattern) Get cipher list offered by local openssl implementation. Returns colon-separated list of ciphers. Does not require connection to any target. =head2 ciphers($pattern) Returns List of ciphers provided for current connection to target. Calls cipher_list() or cipher_openssl() depending on Net::SSLinfo::use_openssl. =cut sub cipher_list { my $pattern = shift || $_SSLinfo{'cipherlist'}; # use default if unset my ($ctx, $ssl, $cipher); my $priority = 0; my @list; _trace("cipher_list($pattern)"); TRY: { # defensive programming with simple error checks # just getting local ciphers does not need sophisticated error handling ($ctx = Net::SSLeay::CTX_new()) or last; ($ssl= Net::SSLeay::new($ctx)) or last; Net::SSLeay::set_cipher_list($ssl, $pattern) or last; # second parameter must not be empty; default see above push(@list, $cipher) while ($cipher = Net::SSLeay::get_cipher_list($ssl, $priority++)); } # TRY Net::SSLeay::free($ssl) if (defined $ssl); Net::SSLeay::CTX_free($ctx) if (defined $ctx); return (wantarray) ? @list : join(' ', @list); } # cipher_list sub cipher_openssl { my $pattern = shift || $_SSLinfo{'cipherlist'}; # use default if unset my $list; _trace("cipher_openssl($pattern)"); _setcmd(); _trace("cipher_openssl: openssl ciphers $pattern") if (1 < $trace); $list = do_openssl("ciphers $pattern", '', '', ''); chomp $list; return (wantarray) ? split(/[:\s]+/, $list) : $list; } # cipher_openssl ## no critic qw(Subroutines::RequireArgUnpacking) # "critic Subroutines::RequireArgUnpacking" disabled from hereon for a couple # of subs because using explicit variable declarations in each sub would make # (human) reading more difficult; it is also ensured that the called function # _SSLinfo_get() does not modify the parameters. sub cipher_local { warn("WARNING: function obsolete, please use cipher_openssl()"); return cipher_openssl(@_); } # cipher_local sub ciphers { return cipher_list( @_) if ($Net::SSLinfo::use_openssl == 0); return cipher_openssl(@_); } # ciphers =pod All following functions have $host and $port parameter and return information according the the connection, certificate for this connection. =head2 cn( ), commonname( ) Get common name (CN) from certificate. =head2 altname( ) Get alternate name (subjectAltNames) from certificate. =head2 authority( ) Get authority (issuer) from certificate. =head2 owner( ) Get owner (subject) from certificate. =head2 certificate( ) Get certificate (subject, issuer) from certificate. =head2 SSLversion( ) Get SSL protocol version used by connection. =head2 version( ) Get version from certificate. =cut # TODO: not yet implemented #=head2 keysize( ) # #Get certificate private key size. # #=head2 keyusage( ) # #Get certificate X509v3 Extended Key Usage (Version 3 and TLS only?) =pod =head2 ssleay_methods( ) Return list of available methods: Net::SSLeay::*_method and Net::SSLeay::CTX_*_new . Most important (newest) method first. =head2 ssleay_test( ) Test availability and print information about Net::SSLeay: Example: C =head2 datadump( ) Print all available (by Net::SSLinfo) data. Due to huge amount of data, the value for s_client is usually omitted. Please set I<$Net::SSLinfo::use_sclient gt 1> to print this data also. =head2 (details) All following require that I<$Net::SSLinfo::use_openssl=1;> being set. =head2 compression( ) Get target's compression support. =head2 exapansion( ) Get target's exapansion support. =head2 next_protocols( ) Get (NPN) protocols advertised by server, =head2 alpn( ) Get target's selected protocol (ALPN). =head2 no_alpn( ) Get target's not negotiated message (ALPN). =head2 next_protocol( ) Get target's next protocol message (ALPN). =head2 krb5 Get target's Krb5 Principal. =head2 psk_identity Get target's PSK identity. =head2 psk_hint Get target's PSK identity hint. =head2 srp Get target's SRP username. =head2 master_key Get target's Master-Key. =head2 session_protocol Get target's announced SSL protocols. =head2 session_startdate Get target's TLS Start Time (human readable format)) =head2 session_starttime Get target's TLS Start Time (seconds since EPOCH) =head2 session_ticket Get target's TLS session ticket. =head2 session_ticket_hint, session_lifetime Get target's TLS session ticket lifetime hint. =head2 session_timeout Get target's SSL session timeout. =head2 dh_parameter( ) Get targets DH parameter. =head2 fingerprint_hash( ) Get certificate fingerprint hash value. =head2 fingerprint_md5( ) Get MD5 fingerprint if available (Net::SSLeay >= 1.49) =head2 fingerprint_sha1( ) Get SHA1 fingerprint if available (Net::SSLeay >= 1.49) =head2 fingerprint_sha2( ) Get SHA2 fingerprint if available (Net::SSLeay >= 1.49) =head2 fingerprint_type( ) Get certificate fingerprint hash algorithm. =head2 fingerprint_text( ) Get certificate fingerprint, which is the hash algorthm followed by the hash value. This is usually the same as I. =head2 fingerprint( ) Alias for I. =head2 email( ) Get certificate email address(es). =head2 serial_hex( ) Get certificate serial number as hex value. =head2 serial_int( ) Get certificate serial number as integer value. =head2 serial( ) Get certificate serial number as integer and hex value. =head2 modulus( ) Get certificate modulus of the public key. =head2 modulus_exponent( ) Get certificate modulus' exponent of the public key. =head2 modulus_len( ) Get certificate modulus (bit) length of the public key. =head2 ocsp_response( ) Get OCSP Response (compact list with values from ocsp_response_data()). =head2 ocsp_response_data( ) Get complete OCSP Response Data. =head2 ocsp_response_status( ) Get OCSP Response Status value. =head2 ocsp_cert_status( ) Get OCSP Response Cert Status value. =head2 ocsp_next_update( ) Get OCSP Response Next Update date. =head2 ocsp_this_update( ) Get OCSP Response This Update date. =head2 pubkey( ) Get certificate's public key. =head2 pubkey_algorithm( ) Get certificate's public key algorithm. =head2 pubkey_value( ) Get certificate's public key value. Same as I but may be different format. =head2 renegotiation( ) Get certificate's renegotiation support. =head2 resumption( ) Get certificate's resumption support. Some target servers respond with `New' and `Reused' connections in unexpected sequence. If `Reused' is found and less than 3 `New' then resumption is assumed. If resumption is not detected, increasing the timeout with i.e. I<$Net::SSLinfo::timeout_sec = 5> may return different results. =head2 sigkey_len( ) Get certificate signature key (bit). =head2 sigkey_value( ) Get certificate signature value (hexdump). =head2 subject_hash( ), issuer_hash( ) Get certificate subject/issuer hash value (in hex). =head2 verify( ) Get result of certificate chain verification. =head2 error_verify( ) Get error string of certificate chain verification, if any. =head2 error_depth( ) Get depth where certificate chain verification failed. =head2 chain( ) Get certificate's CA chain. =head2 chain_verify( ) Get certificate's CA chain verification trace (for debugging only). =head2 selfsigned( ) If certificate is self signed. =head2 https_alerts( ) Get HTTPS alerts send by server. =head2 https_protocols( ) Get HTTPS Alterenate-Protocol header. =head2 https_svc( ) Get HTTPS Alt-Svc and X-Firefox-Spdy header. =head2 https_body( ) Get HTTPS response (body) =head2 https_status( ) Get HTTPS response (aka status) line. =head2 https_server( ) Get HTTPS Server header. =head2 https_location( ) Get HTTPS Location header. =head2 https_refresh( ) Get HTTPS Refresh header. =head2 http_protocols( ) Get HTTP Alterenate-Protocol header. =head2 http_svc( ) Get HTTP Alt-Svc and X-Firefox-Spdy header. =head2 http_status( ) Get HTTP response (aka status) line. =head2 http_location( ) Get HTTP Location header. =head2 http_refresh( ) Get HTTP Refresh header. =head2 http_sts( ) Get HTTP Strict-Transport-Security header, if any. =head2 hsts_httpequiv( ) Get hhtp-equiv=Strict-Transport-Security attribute from HTML body, if any. =head2 hsts( ) Get complete STS header. =head2 hsts_maxage( ) Get max-age attribute of STS header. =head2 hsts_subdom( ) Get includeSubDomains attribute of STS header. =head2 hsts_preload( ) Get preload attribute of STS header. =head2 https_pins( ) Get pins attribute of STS header. =head2 CTX_method( ) Get used Net::SSLeay::CTX_*_new) method. Useful for debugging only. =cut sub errors { return _SSLinfo_get('errors', $_[0], $_[1]); } sub s_client { return _SSLinfo_get('s_client', $_[0], $_[1]); } sub options { return _SSLinfo_get('_options', $_[0], $_[1]); } sub PEM { return _SSLinfo_get('PEM', $_[0], $_[1]); } sub pem { return _SSLinfo_get('PEM', $_[0], $_[1]); } # alias for PEM sub text { return _SSLinfo_get('text', $_[0], $_[1]); } sub before { return _SSLinfo_get('before', $_[0], $_[1]); } sub after { return _SSLinfo_get('after', $_[0], $_[1]); } sub dates { return _SSLinfo_get('dates', $_[0], $_[1]); } sub issuer { return _SSLinfo_get('issuer', $_[0], $_[1]); } sub subject { return _SSLinfo_get('subject', $_[0], $_[1]); } #sub default { return _SSLinfo_get('selected', $_[0], $_[1]); } # alias; used in VERSION < 14.11.14 sub selected { return _SSLinfo_get('selected', $_[0], $_[1]); } sub cn { return _SSLinfo_get('cn', $_[0], $_[1]); } sub commonname { return _SSLinfo_get('cn', $_[0], $_[1]); } # alias for cn sub altname { return _SSLinfo_get('altname', $_[0], $_[1]); } sub subjectaltnames { return _SSLinfo_get('altname', $_[0], $_[1]); } # alias for altname sub authority { return _SSLinfo_get('authority', $_[0], $_[1]); } sub owner { return _SSLinfo_get('owner', $_[0], $_[1]); } # alias for subject sub certificate { return _SSLinfo_get('certificate', $_[0], $_[1]); } sub SSLversion { return _SSLinfo_get('SSLversion', $_[0], $_[1]); } sub version { return _SSLinfo_get('version', $_[0], $_[1]); } sub keysize { return _SSLinfo_get('keysize', $_[0], $_[1]); } # NOT IMPLEMENTED sub keyusage { return _SSLinfo_get('keyusage', $_[0], $_[1]); } # NOT IMPLEMENTED sub email { return _SSLinfo_get('email', $_[0], $_[1]); } sub modulus { return _SSLinfo_get('modulus', $_[0], $_[1]); } sub serial_hex { return _SSLinfo_get('serial_hex', $_[0], $_[1]); } sub serial_int { return _SSLinfo_get('serial_int', $_[0], $_[1]); } sub serial { return _SSLinfo_get('serial', $_[0], $_[1]); } sub aux { return _SSLinfo_get('aux', $_[0], $_[1]); } sub extensions { return _SSLinfo_get('extensions', $_[0], $_[1]); } sub tlsextdebug { return _SSLinfo_get('tlsextdebug', $_[0], $_[1]); } sub tlsextensions { return _SSLinfo_get('tlsextensions', $_[0], $_[1]); } sub heartbeat { return _SSLinfo_get('heartbeat', $_[0], $_[1]); } sub trustout { return _SSLinfo_get('trustout', $_[0], $_[1]); } sub ocsp_uri { return _SSLinfo_get('ocsp_uri', $_[0], $_[1]); } sub ocspid { return _SSLinfo_get('ocspid', $_[0], $_[1]); } sub ocsp_response { return _SSLinfo_get('ocsp_response', $_[0], $_[1]); } sub ocsp_response_data { return _SSLinfo_get('ocsp_response_data', $_[0], $_[1]); } sub ocsp_response_status { return _SSLinfo_get('ocsp_response_status', $_[0], $_[1]); } sub ocsp_cert_status{ return _SSLinfo_get('ocsp_cert_status', $_[0], $_[1]); } sub ocsp_next_update{ return _SSLinfo_get('ocsp_next_update', $_[0], $_[1]); } sub ocsp_this_update{ return _SSLinfo_get('ocsp_this_update', $_[0], $_[1]); } sub pubkey { return _SSLinfo_get('pubkey', $_[0], $_[1]); } sub signame { return _SSLinfo_get('signame', $_[0], $_[1]); } sub sigdump { return _SSLinfo_get('sigdump', $_[0], $_[1]); } sub sigkey_value { return _SSLinfo_get('sigkey_value', $_[0], $_[1]); } sub sigkey_len { return _SSLinfo_get('sigkey_len', $_[0], $_[1]); } sub subject_hash { return _SSLinfo_get('subject_hash', $_[0], $_[1]); } sub issuer_hash { return _SSLinfo_get('issuer_hash', $_[0], $_[1]); } sub verify { return _SSLinfo_get('verify', $_[0], $_[1]); } sub error_verify { return _SSLinfo_get('error_verify', $_[0], $_[1]); } sub error_depth { return _SSLinfo_get('error_depth', $_[0], $_[1]); } sub chain { return _SSLinfo_get('chain', $_[0], $_[1]); } sub chain_verify { return _SSLinfo_get('chain_verify', $_[0], $_[1]); } sub compression { return _SSLinfo_get('compression', $_[0], $_[1]); } sub expansion { return _SSLinfo_get('expansion', $_[0], $_[1]); } sub next_protocols { return _SSLinfo_get('next_protocols', $_[0], $_[1]); } sub protocols { return _SSLinfo_get('next_protocols', $_[0], $_[1]); } # alias for backward compatibility (< 1.169) sub alpn { return _SSLinfo_get('alpn', $_[0], $_[1]); } sub no_alpn { return _SSLinfo_get('no_alpn', $_[0], $_[1]); } sub next_protocol { return _SSLinfo_get('next_protocol', $_[0], $_[1]); } sub krb5 { return _SSLinfo_get('krb5', $_[0], $_[1]); } sub psk_hint { return _SSLinfo_get('psk_hint', $_[0], $_[1]); } sub psk_identity { return _SSLinfo_get('psk_identity', $_[0], $_[1]); } sub srp { return _SSLinfo_get('srp', $_[0], $_[1]); } sub master_key { return _SSLinfo_get('master_key', $_[0], $_[1]); } sub session_id { return _SSLinfo_get('session_id', $_[0], $_[1]); } sub session_startdate{return _SSLinfo_get('session_startdate',$_[0], $_[1]); } sub session_starttime{return _SSLinfo_get('session_starttime',$_[0], $_[1]); } sub session_lifetime{ return _SSLinfo_get('session_lifetime', $_[0], $_[1]); } sub session_ticket_hint{return _SSLinfo_get('session_lifetime',$_[0],$_[1]); } # alias sub session_ticket { return _SSLinfo_get('session_ticket', $_[0], $_[1]); } sub session_timeout { return _SSLinfo_get('session_timeout', $_[0], $_[1]); } sub session_protocol{ return _SSLinfo_get('session_protocol', $_[0], $_[1]); } sub fingerprint_hash{ return _SSLinfo_get('fingerprint_hash', $_[0], $_[1]); } sub fingerprint_text{ return _SSLinfo_get('fingerprint_text', $_[0], $_[1]); } sub fingerprint_type{ return _SSLinfo_get('fingerprint_type', $_[0], $_[1]); } sub fingerprint_sha2{ return _SSLinfo_get('fingerprint_sha2', $_[0], $_[1]); } sub fingerprint_sha1{ return _SSLinfo_get('fingerprint_sha1', $_[0], $_[1]); } sub fingerprint_md5 { return _SSLinfo_get('fingerprint_md5' , $_[0], $_[1]); } sub fingerprint { return _SSLinfo_get('fingerprint', $_[0], $_[1]); } # alias for fingerprint_text sub cert_type { return _SSLinfo_get('cert_type', $_[0], $_[1]); } sub modulus_len { return _SSLinfo_get('modulus_len', $_[0], $_[1]); } sub modulus_exponent{ return _SSLinfo_get('modulus_exponent', $_[0], $_[1]); } sub pubkey_algorithm{ return _SSLinfo_get('pubkey_algorithm', $_[0], $_[1]); } sub pubkey_value { return _SSLinfo_get('pubkey_value', $_[0], $_[1]); } sub renegotiation { return _SSLinfo_get('renegotiation', $_[0], $_[1]); } sub resumption { return _SSLinfo_get('resumption', $_[0], $_[1]); } sub dh_parameter { return _SSLinfo_get('dh_parameter', $_[0], $_[1]); } sub selfsigned { return _SSLinfo_get('selfsigned', $_[0], $_[1]); } sub https_protocols { return _SSLinfo_get('https_protocols', $_[0], $_[1]); } sub https_body { return _SSLinfo_get('https_body', $_[0], $_[1]); } sub https_svc { return _SSLinfo_get('https_svc', $_[0], $_[1]); } sub https_status { return _SSLinfo_get('https_status', $_[0], $_[1]); } sub https_server { return _SSLinfo_get('https_server', $_[0], $_[1]); } sub https_alerts { return _SSLinfo_get('https_alerts', $_[0], $_[1]); } sub https_location { return _SSLinfo_get('https_location', $_[0], $_[1]); } sub https_refresh { return _SSLinfo_get('https_refresh', $_[0], $_[1]); } sub https_pins { return _SSLinfo_get('https_pins', $_[0], $_[1]); } sub http_protocols { return _SSLinfo_get('http_protocols', $_[0], $_[1]); } sub http_svc { return _SSLinfo_get('http_svc', $_[0], $_[1]); } sub http_status { return _SSLinfo_get('http_status', $_[0], $_[1]); } sub http_location { return _SSLinfo_get('http_location', $_[0], $_[1]); } sub http_refresh { return _SSLinfo_get('http_refresh', $_[0], $_[1]); } sub http_sts { return _SSLinfo_get('http_sts', $_[0], $_[1]); } sub https_sts { return _SSLinfo_get('https_sts', $_[0], $_[1]); } sub hsts_httpequiv { return _SSLinfo_get('hsts_httpequiv', $_[0], $_[1]); } sub hsts_maxage { return _SSLinfo_get('hsts_maxage', $_[0], $_[1]); } sub hsts_subdom { return _SSLinfo_get('hsts_subdom', $_[0], $_[1]); } sub hsts_preload { return _SSLinfo_get('hsts_preload', $_[0], $_[1]); } sub CTX_method { return _SSLinfo_get('CTX_method', $_[0], $_[1]); } =pod =head2 verify_hostname( ) Verify if given hostname matches common name (CN) in certificate. =cut ############ TODO: do_ssl_open vorbereiten fuer verify_* sub verify_hostname { my ($host, $port) = @_; return if (not defined do_ssl_open($host, $port, '')); return $Net::SSLinfo::no_cert_txt if (0 != $Net::SSLinfo::no_cert); my $cname = $_SSLinfo{'cn'}; my $match = ''; if (1 == $Net::SSLinfo::ignore_case) { $host = lc($host); $cname= lc($cname); } $match = ($host eq $cname) ? 'matches' : 'does not match'; return sprintf("Given hostname '%s' %s CN '%s' in certificate", $host, $match, $cname); } # verify_hostname =head2 verify_altname( ), verify_alias( ) Verify if given hostname matches alternate name (subjectAltNames) in certificate. =cut sub verify_altname { my ($host, $port) = @_; return if (not defined do_ssl_open($host, $port, '')); return $Net::SSLinfo::no_cert_txt if (0 != $Net::SSLinfo::no_cert); _trace("verify_altname($host)"); my $match = 'does not match'; my $cname = $_SSLinfo{'altname'}; return "No alternate name defined in certificate" if ('' eq $cname); _trace("verify_altname: $cname"); foreach my $alt (split(/ /, $cname)) { # list of strings like: DNS:some.tld DNS:other.tld email:who@some.tld next if ($alt =~ m/^\s*$/); my ($type, $name) = split(/:/, $alt); #dbx# print "#ALT# $alt: ($type, $name)"; # TODO: implement IP and URI; see also o-saft.pl: _checkwildcards() push(@{$_SSLinfo{'errors'}}, "verify_altname() $type not supported in SNA") if ($type !~ m/DNS/i); my $rex = $name; if (1 == $Net::SSLinfo::ignore_case) { $host = lc($host); $rex = lc($rex); } $rex =~ s/[.]/\\./g; if ($name =~ m/[*]/) { $rex =~ s/(\*)/[^.]*/; } _trace("verify_altname: $host =~ $rex "); if ($host =~ /^$rex$/) { $match = 'matches'; $cname = $alt; # only show matching name $cname =~ s/^[a-zA-Z0-9]+://; # remove leading type, i.e. DNS: last; # else # $cname still contains type like DNS: } } _trace("verify_altname() done."); return sprintf("Given hostname '%s' %s alternate name '%s' in certificate", $host, $match, $cname); } # verify_altname sub verify_alias { return verify_altname($_[0], $_[1]); } sub _check_peer { # TBD my ($ok, $x509_store_ctx) = @_; _trace("_check_peer($ok, $x509_store_ctx)"); $_SSLinfo{'verify_cnt'} += 1; return $ok; } # _check_peer sub _check_client_cert {print "##check_client_cert\n"; return; } #$my $err = Net::SSLeay::set_verify ($ssl, Net::SSLeay::VERIFY_CLIENT_ONCE, \&_check_client_cert ); sub _check_crl { # TBD my $ssl = shift; _trace("_check_crl()"); return; } # _check_crl sub error { # TBD #return Net::SSLeay::ERR_get_error; } # error =pod =head1 DEENDENCIES L L (required if necessary only) =head1 SEE ALSO L =head1 AUTHOR 08-aug-12 Achim Hoffmann =cut sub net_sslinfo_done {}; # dummy to check successful include ## PACKAGE } unless (defined caller) { # print myself or open connection printf("# %s %s\n", __PACKAGE__, $VERSION); if (0 <= $#ARGV) { local $\="\n"; do_ssl_open( shift, 443, ''); print Net::SSLinfo::datadump(); exit 0; } if (eval{require POD::Perldoc;}) { # pod2usage( -verbose => 1 ); exit( Pod::Perldoc->run(args=>[$0]) ); } if (qx(perldoc -V)) { # may return: You need to install the perl-doc package to use this program. #exec "perldoc $0"; # scary ... printf("# no POD::Perldoc installed, please try:\n perldoc $0\n"); exit 0; } } 1; O-Saft-19.01.19/OSaft/000077500000000000000000000000001342117255600140675ustar00rootroot00000000000000O-Saft-19.01.19/OSaft/Ciphers.pm000077500000000000000000001531031342117255600160300ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { =pod =encoding utf8 =head1 NAME OSaft::Ciphers - common perl module to define O-Saft ciphers ##### # perlcritic -3 OSaft/Ciphers.pm # -verbose 10 ######################## E X P E R I M E N T A L ####################### ###################### not used in O-Saft 18.11.18 ##################### =cut # test resources with: ## /usr/bin/time --quiet -a -f "%U %S %E %P %Kk %Mk" OSaft/Ciphers.pm names ## 0.12 0.00 0:00.12 96% 0k 6668k ## 0.11 0.00 0:00.11 98% 0k 6852k ## 0.14 0.01 0:00.16 97% 0k 7100k ############# # RFC in OSaft/_ciphers_iana.pm abgeglichen mit https://tools.ietf.org/rfc/rfcXXXX.txt # d.h. keys passen zu den Konstanten ############# # TODO: see comment at %ciphers_names ######################## E X P E R I M E N T A L ####################### package OSaft::Ciphers; use strict; use warnings; use Carp; our @CARP_NOT = qw(OSaft::Ciphers); # TODO: funktioniert nicht my $VERSION = '18.03.28'; # official verion number of tis file my $SID_ciphers = "@(#) Ciphers.pm 1.25 18/11/11 18:13:49"; my $STR_UNDEF = '<>'; # defined in osaft.pm our $VERBOSE = 0; # >1: option --v # VERBOSE instead of verbose because of perlcritic #_____________________________________________________________________________ #_____________________________________________________ public documentation __| # more public documentation, see start of methods section, and at end of file. ## no critic qw(Variables::ProtectPrivateVars) # Our private variable names start with an _ as suggested by percritic. # However, percritic is too stupid to recognice such names if the is fully # qualified with preceding package name. ## no critic qw(Documentation::RequirePodSections) # Our POD below is fine, perlcritic (severity 2) is too pedantic here. ## no critic qw(Documentation::RequirePodAtEnd) # Our POD is inline as it serves for documenting the code itself too. # But: this is a violation for severity 1, which is fixed and the produces # another violation for severity 2. ## no critic qw(RegularExpressions::RequireExtendedFormatting) # There're a lot of expressions here, it's ok to use them without /x flag. =pod =head1 SYNOPSIS OSaft::Ciphers.pm # on command line will print help use OSaft::Ciphers; # from within perl code =head1 DESCRIPTION Utility package for O-Saft (o-saft.pl and related tools). This package declares and defines common L and L to be used in the calling tool. It contains the primary data structure for cipher suites. This documentaion is intended for developers. Users should read any of the help texts for example provided by O-Saft, i.e. C. This module provides additional functionality to list and check the used data structures for the cipher suites. All L and L are only for this additional functionality, please read descriptions there. =head2 Used Functions Following functions (methods) must be defined in the calling program: None (06/2016). =head1 CONCEPT The main data structure is C<%ciphers>, which will be defined herein. It's defined as a static hash with the cipher's ID (hex number) as the hash key and all cipher suite data (in an array) as value for that hash key. For example I: '0x00,0x3D' =E [qw( TLSv12 RSA RSA AES 256 SHA256 Y 5246 HIGH :)], For a more detailed description, please use: OSaft/Ciphers.pm ciphers_description or consult the source code directly, in particular C<%ciphers_desc>. The main key -aka ID- to identify a cipher suite is the identifier (hex number) of a cipher suite as defined vy IANA. This key is also used in all other data structures related to ciphers. Other data, related to the cipher suite (like the cipher suite name, the cipher suite constant) are defined in additional data structures C<%ciphers_const> and C<%ciphers_names>. Each cipher suite is defined as a perl array (,see above) and will be converted to a perl hash at initialization like: '0x00,0x3D' =E { ssl=>"TLSv12", keyx=>"RSA", enc=>"AES", ... }, Such a hash is simpler to use. Finally a getter method (see L) is provided for each value. This approach to specify the definition, which must be done by developers, in a simple table, which then will be converted into a hash automatically, is based on the consideration that the data structure for all cipher suite needs to be maintained very carefully. It is the author's opinion that tabular data is more easy to maintain than structured data. =cut #The decision to use an array with proper getter methods (see METHODS) rather #than a hash is based on the consideration that the cipher suite data structure #needs to be maintained very carefully. It's the author's opinion that tabular #data is simpler to maintain than structured data, which requires the hash key #for each value in each line. =pod =head2 Variables All variables except C<@cipher_results> are constants, and hence read-only. There is no need to change them in the calling program. =head2 Methods Because all variables are constants, we only provide getter methods for them. =head2 Testing All data structures are defined herein. For testing, the data structures can be read from a file. =head2 Documentaion This documentaion describes the public variables and methods only, but not the internal ones, in particular the C functions. Please see the source itself for that. =head1 VARIABLES =over 4 =item %ciphers Hash with all cipher suites and paramters of each suite. Indexed by cipher ID. =item %ciphers_desc Describes the data structure in C<%ciphers>. =item %ciphers_names Hash with various names, identifiers and constants for each cipher suite. Indexed by cipher ID. =item %ciphers_alias Hash with additional names, identifiers and constants for a cipher suite. Indexed by cipher ID. =item @cipher_results Array with all checked ciphers. =back =head1 METHODS Only getter, setter and print methods are exported. All other methods must be used with the full package name. =cut ## no critic qw(Modules::ProhibitAutomaticExportation, Variables::ProhibitPackageVars) # FIXME: perlcritic complains to not declare (global) package variables, but # the purpose of this module is to do that. This may change in future. use Exporter qw(import); use base qw(Exporter); our @EXPORT_OK = qw( %ciphers %ciphers_desc %ciphers_names %ciphers_alias %ciphers_const @cipher_results get_param get_ssl get_keyx get_auth get_enc get_bits get_mac get_dtls get_rfc get_sec get_tags get_score get_desc get_hex get_name get_alias get_const sort_cipher_names cipher_done ); # insert above in vi with: # :r !sed -ne 's/^our \([\%$@][a-zA-Z0-9_][^ (]*\).*/\t\t\1/p' % # :r !sed -ne 's/^sub \([a-zA-Z][^ (]*\).*/\t\t\1/p' % # TODO: interanl wrappers for main's methods sub _trace { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking) sub _trace0 { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking Subroutines::ProhibitUnusedPrivateSubroutines) sub _trace1 { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking Subroutines::ProhibitUnusedPrivateSubroutines) sub _trace2 { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking Subroutines::ProhibitUnusedPrivateSubroutines) sub _trace3 { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking Subroutines::ProhibitUnusedPrivateSubroutines) sub _warn { my @args = @_; carp("**WARNING: ", join(' ', @args)); return; } sub vprint { my @args = @_; return if (1 > $VERBOSE); print("# ", join(' ', @args) . "\n"); return; } sub v2print { my @args = @_; return if (2 > $VERBOSE); print("# ", join(' ', @args) . "\n"); return; } #_____________________________________________________________________________ #________________________________________________________________ variables __| our %ciphers_desc = ( # description of following %ciphers table 'head' => [qw( ssl keyx auth enc bits mac dtls rfc sec tags )], # abbreviations used by openssl: # SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2 # Kx= key exchange (DH is diffie-hellman) # Au= authentication # Enc= encryption with bit size # Mac= mac encryption algorithm 'text' => [ # full description of each column in 'ciphers' below # all following informations as reported by openssl 0.9.8 .. 1.0.1h 'SSL/TLS version', # Protocol Version: # SSLv2, SSLv3, TLSv1, TLSv11, TLSv12, TLSv13, DTLS0.9, DTLS1.0, PCT # NOTE: all SSLv3 are also TLSv1, TLSv11, TLSv12 # (cross-checked with sslaudit.ini) 'Key Exchange', # DH, ECDH, ECDH/ECDSA, RSA, KRB5, PSK, SRP, GOST # last column is a : separated list (only export from openssl) # different versions of openssl report ECDH or ECDH/ECDSA 'Authentication', # None, DSS, RSA, ECDH, ECDSA, KRB5, PSK, GOST01, GOST94 'Encryption Algorithm', # None, AES, AESCCM, AESGCM, CAMELLIA, DES, 3DES, FZA, IDEA, RC4, RC2, SEED, GOST89 'Key Size', # in bits 'MAC Algorithm', # MD5, SHA1, SHA256, SHA384, AEAD, GOST89, GOST94 'DTLS OK', # Y if cipher is compatible for DTLS, N otherwise # (information from IANA) 'RFC', # RFC number where cipher was defined 'Security', # LOW, MEDIUM, HIGH as reported by openssl 0.9.8 .. 1.0.1h # WEAK as reported by openssl 0.9.8 as EXPORT # weak unqualified by openssl or know vulnerable # NOTE: weak includes NONE (no security at all) # high unqualified by openssl, but considerd secure # 'tags', # export as reported by openssl 0.9.8 .. 1.0.1h # OSX on Mac OS X only # : (colon) is empty marker (need for other tools ], 'sample' => { # example '0x00,0x3D' => [qw( TLSv12 RSA RSA AES 256 SHA256 Y 5246 HIGH :)], # AES256-SHA256 }, ); # %ciphers_desc ####### nur %ciphers und %ciphers_names wird verwendet ####### alle anderen %_cipher* sind nur zur Initialisierung our %ciphers = ( #? list of all ciphers, will be generated in _ciphers_init() #------------------+----+----+----+----+----+----+-------+----+---+-------, # hex,hex => [qw( ssl keyx auth enc bits mac DTLS-OK RFC sec tags )], #------------------+----+----+----+----+----+----+-------+----+---+-------, #------------------+----+----+----+----+----+----+-------+----+---+-------, # ... ); # %ciphers # iana - aus _ciphers_iana.pm # OpenSSL - aus _ciphers_?? (ssl.h, tls.h, ...) # openssl - aus _ciphers_openssl_all.pm (openssl ciphers -V) # osaft - aus _ciphers_osaft.pm (handgestrickt) our %ciphers_const = ( #? list of cipher suite constant names, will be generated in _ciphers_init() #------------------+-------+-------+-------+--------, # hex,hex => [qw( iana OpenSSL openssl osaft )], # (osaft: SSL_CK_ and TLS_ prefix missing) #------------------+-------+-------+-------+--------, # ... ); # %ciphers_const # defined in OSaft/_ciphers_iana.pm, OSaft/_ciphers_osaft.pm our %ciphers_names = ( #? list of cipher suite names, will be generated in _ciphers_init() #------------------+-------+-------+-------+--------, # hex,hex => [qw( iana OpenSSL openssl osaft )], # (osaft: SSL_CK_ and TLS_ prefix missing) #------------------+-------+-------+-------+--------, # ... ); # %ciphers_names # defined in OSaft/_ciphers_iana.pm, OSaft/_ciphers_osaft.pm our %ciphers_alias = ( #? list of cipher suite alias names, will be generated in _ciphers_init() #------------------+-----------------------------+----------------------, # hex,hex => [qw( cipher suite name aliases )],# comment (where found) #------------------+-----------------------------+----------------------, # ... ); # %ciphers_alias # defined in OSaft/_ciphers_osaft.pm our @cipher_results = [ # currently (12/2015) # [ sslv3, rc4-md5, yes ] # [ sslv3, NULL, no ] # in future (01/2016) # [ ssl, cipher, pos+cipher, pos+cipherraw, dh-bits, dh-param, "comment"] # # # ssl : SSLv2, SSLv3, TLS10, ... # # cipher : hex-Wert (als String) # # pos+* : -1 = undef (noch nicht berechnet), 0 = keine Reihenfolge # beim Server, 1 .. n wie vom Server ausgewaehlt # # dh-bits : DH Bits # # dh-param : ECDH Kurve # dann können verschieden Algorithmen implementiert werden ### 1. o-saft wie jetzt ### 2. o-saft mit cipherraw wie jetzt ### 3. cipherraw mit unterschiedlicher Anzahl Ciphers, z.B.: ### 1, 8,9,15,16,17,32,64,48,49,127,128,129 ### 4. von cipherraw den selected Cipher geben lassen ]; # @cipher_results #_____________________________________________________________________________ #______________________________________________________ temporary variables __| ### ### die Hashes werden hier statisch definiert, können aber dynamisch ### aus den Files geladen werden ### Stand 6/2016: bis die erste statische Version fertig ist, werden die ### Daten dynamisch geladen my %_ciphers_openssl_all = ( #? internal list, generated by gen_ciphers.sh #-------------------+----+----+----+----+----+----+----+-------, # hex,hex => [qw( ssl keyx auth enc bits mac name tags )], #-------------------+----+----+----+----+----+----+----+-------, # '0x00,0x05' => [qw( SSLv3 RSA RSA RC4 128 SHA1 RC4-SHA #-------------------+----+----+----+----+----+----+----+-------, ); # %_ciphers_openssl_all eval {require qw{OSaft/_ciphers_openssl_all.pm}; } or _warn "cannot read OSaft/_ciphers_openssl_all.pm"; my %_ciphers_openssl_inc = ( #? internal list, generated from openssl source ); # %_ciphers_openssl_inc my %_ciphers_iana = ( #? internal list, generated by gen_ciphers.sh #-------------------+------------------------------------+-------+---------, # hex,hex => [qw( IANA cipher suite constant RFC(s) DTLS-OK )], #-------------------+------------------------------------+-------+---------, # '0xC0,0x32' => [qw( TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 5289 Y )], # '0xC0,0x33' => [qw( TLS_ECDHE_PSK_WITH_RC4_128_SHA 5489,6347 N )], #-------------------+------------------------------------+-------+---------, ); # %__ciphers_iana eval {require qw{OSaft/_ciphers_iana.pm}; } or _warn "cannot read OSaft/_ciphers_iana.pm"; my %_ciphers_osaft = ( #? internal list, additions to %_ciphers_openssl # /opt/tools/openssl-chacha/bin/openssl ciphers -V ALL:eNULL:LOW:EXP \ );# %_ciphers_osaft eval {require qw{OSaft/_ciphers_osaft.pm}; } or _warn "cannot read OSaft/_ciphers_osaft.pm"; ###################################################### sub id2key { #? convert any hex or integer id to key used in internal data structure # Umrechnung: 0x0300C01C <--> 0xC0C1 <--> 0xC0,0x1C my $ssl_base = 0x02000000; # 33554432 my $tls_base = 0x03000000; # 50331648 my $ptc_base = 0x80000000; # 2147483648 my $chacha_mask = 0xCC; # i.e 0xCC,0xAA my $fips_mask = 0xFE; # i.e 0xFE,0xE0 my $gost_mask = 0xFF; # i.e 0xFF,0x01 # Sonderfall 0x00,0x1e , sonst alle upper case return; }; # id2key # sub is_auth { } # sub is_enc { } # sub is_ephermeral { } # sub is_export { } ###################################################### #_____________________________________________________________________________ #__________________________________________________________________ methods __| =pod =head2 get_param($cipher, $key) =head2 get_ssl( $cipher) =head2 get_keyx($cipher) =head2 get_auth($cipher) =head2 get_enc( $cipher) =head2 get_bits($cipher) =head2 get_mac( $cipher) =head2 get_dtls($cipher) =head2 get_rfc( $cipher) =head2 get_sec( $cipher) =head2 get_tags($cipher) =head2 get_score($cipher) =head2 get_hex( $cipher) =head2 get_name( $cipher) =head2 get_alias($cipher) =head2 get_const($cipher) =head2 get_desc( $cipher) Get information from internal C<%cipher> data structure. =cut # some people prefer to use a getter function to get data from objects # each function returns a spcific value (column) from the %cipher table # see %ciphers_desc about description of the columns # returns STR_UNDEF if requested cipher is missing sub get_param { #? internal method to return required value from %cipher my ($cipher, $key) = @_; return $ciphers{$cipher}->{$key} || '' if (0 < (grep{/^$cipher/i} %ciphers)); return $STR_UNDEF; }; # get_param sub get_ssl { my $c=shift; return get_param($c, 'ssl'); } sub get_keyx { my $c=shift; return get_param($c, 'keyx'); } sub get_auth { my $c=shift; return get_param($c, 'auth'); } sub get_enc { my $c=shift; return get_param($c, 'enc'); } sub get_bits { my $c=shift; return get_param($c, 'bits'); } sub get_mac { my $c=shift; return get_param($c, 'mac'); } sub get_dtls { my $c=shift; return get_param($c, 'dtls'); } sub get_rfc { my $c=shift; return get_param($c, 'rfc'); } sub get_sec { my $c=shift; return get_param($c, 'sec'); } sub get_tags { my $c=shift; return get_param($c, 'tags'); } sub get_score { my $c=shift; return $STR_UNDEF; } # obsolete since 16.06.16 sub get_desc { # get description for specified cipher from %ciphers my $c=shift; if (not defined $ciphers{$c}) { _warn("undefined cipher description for '$c'"); # TODO: correct %ciphers return $STR_UNDEF; } my @x = sort values %{$ciphers{$c}}; shift @x; return join(' ', @x) if (0 < (grep{/^$c/} %ciphers)); return ''; } =pod =head2 get_hex($cipher) Get cipher's hex key from C<%ciphers_names> or C<%ciphers_alias> data structure. =head2 get_name($cipher) Check if given C<%cipher> name is a known cipher. =cut sub get_hex { #? find hex key for cipher in %ciphers_names or %ciphers_alias # example: RC4-MD5 -> 0x01,0x00,0x80 ; AES128-SHA256 -> 0x00,0x3C my $c = shift; # FIXME: returns first matching even if more exist; example: RC4-MD5 # need protocol parameter foreach my $k (keys %ciphers_names) { # database up to VERSION 14.07.14 return $k if (($ciphers_names{$k}[0] eq $c) or ($ciphers_names{$k}[1] eq $c)); } foreach my $k (keys %ciphers_alias) { # not yet found, check for alias return $k if ($ciphers_alias{$k}[0] eq $c); } # NOTE: need to check if this is necessary here #foreach my $k (keys %ciphers_old) { # not yet found, check old names # return $k if ($ciphers_old{$k}[0] eq $c); #} return ''; } # get_hex sub get_key { #? translate given string to valid hex key for %cipher; returns key if exists # example: RC4-MD5 -> 0x01,0x00,0x80 ; AES128-SHA256 -> 0x00,0x3C my $txt = shift; my $key = uc($txt); $key =~ s/X/x/g; # FIXME: returns first matching even if more exist; example: RC4-MD5 # need protocol parameter return $key if defined $ciphers{$key}; $key = $txt; $key =~ s/^(?:SSL[23]?|TLS1?)_//; # strip any prefix; $key =~ s/^(?:CK|TXT)_//; # strip any prefix; # not a key itself, try to find in names foreach my $k (keys %ciphers_names) { foreach (qw( iana OpenSSL openssl osaft )) { #print "#$ciphers_names{$k}->{$_}#\n" if ($ciphers_names{$k}->{$_} =~ m/$key/i); return $k if (defined $ciphers_names{$k}->{$_} && ($ciphers_names{$k}->{$_} =~ m/^$key$/i)); } } return ''; } # get_key sub get_name { #? check if given cipher name is a known cipher # checks in %ciphers if nof found in %ciphers_names # example: RC4_128_WITH_MD5 -> RC4-MD5 ; RSA_WITH_AES_128_SHA256 -> AES128-SHA256 # Note: duplicate name (like RC4_128_WITH_MD5) are no problem, because they # use the same cipher suite name (like RC4-MD5). my $cipher = shift; return $cipher if (0 < (grep{/^$cipher/} %ciphers)); _trace("get_name: search $cipher"); foreach my $k (keys %ciphers_names) { return $ciphers_names{$k}[0] if ($cipher =~ m/$ciphers_names{$k}[0]/); return $ciphers_names{$k}[0] if ($ciphers_names{$k}[1] =~ /$cipher/); } # nothing found yet, try more lazy match foreach my $k (keys %ciphers_names) { if ($ciphers_names{$k}[0] =~ m/$cipher/) { _warn("partial match for cipher name found '$cipher'"); return $ciphers_names{$k}[0]; } } return ''; } # get_name =pod =head2 sort_cipher_names(@ciphers) Sort given list of C<@ciphers> according their strength, most strongest first. returns sorted list of ciphers. C<@ciphers> is a list of cipher suite names. These names should be those used by openssl(1) . =cut sub sort_cipher_names { # cipher suites must be given as array # NOTE: the returned list may not be exactly sorted according the cipher's # strength, just roughly # known insecure (i.e. CBC, DES, RC4) and NULL ciphers are added at the end my @ciphers = @_; my @sorted ; my @latest ; my $cnt = scalar @ciphers; # number of passed ciphers; see check at end # now define list of regex to match openssl cipher suite names # each regex could be seen as a class of ciphers with the same strength # the list defines the strength in descending order, most strength first # NOTE the list may contain pattern, which actually do not match a valid # cipher suite name; doese't matter, but may avoid future adaptions, see # warning at nd also my @insecure = ( qw((?:RC[24])) , # all RC2 and RC4 qw((?:CBC|DES)) , # all CBC, DES, 3DES qw((?:DSS)) , # all DSS qw((?:MD[2345])), # all MD qw(DH.?(?i:anon)) , # Anon needs to be caseless qw((?:NULL)) , # all NULL ); my @strength = ( qw((?:ECDHE|EECDH).*?CHACHA) , # 1. all ecliptical curve, ephermeral, GCM qw((?:ECDHE|EECDH).*?512.GCM) , # .. sorts -ECDSA before -RSA qw((?:ECDHE|EECDH).*?384.GCM) , qw((?:ECDHE|EECDH).*?256.GCM) , qw((?:ECDHE|EECDH).*?128.GCM) , qw((?:EDH|DHE).*?CHACHA) , # 2. all ephermeral, GCM qw((?:EDH|DHE).*?512.GCM) , # .. sorts AES before CAMELLIA qw((?:EDH|DHE).*?384.GCM) , qw((?:EDH|DHE).*?256.GCM) , qw((?:EDH|DHE).*?128.GCM) , qw(ECDH[_-].*?CHACHA) , # 3. all ecliptical curve, GCM qw(ECDH[_-].*?512.GCM) , # .. sorts -ECDSA before -RSA qw(ECDH[_-].*?384.GCM) , qw(ECDH[_-].*?256.GCM) , qw(ECDH[_-].*?128.GCM) , qw(ECDHE.*?CHACHA) , # 4. all remaining ecliptical curve, ephermeral qw(ECDHE.*?512) , qw(ECDHE.*?384) , qw(ECDHE.*?256) , qw(ECDHE.*?128) , qw(ECDH[_-].*?CHACHA) , # 5. all remaining ecliptical curve qw(ECDH[_-].*?512) , qw(ECDH[_-].*?384) , qw(ECDH[_-].*?256) , qw(ECDH[_-].*?128) , qw(AES) , # 5. all AES and specials qw(KRB5) , qw(SRP) , qw(PSK) , qw(GOST) , qw((?:EDH|DHE).*?CHACHA) , # 6. all DH qw((?:EDH|DHE).*?512) , qw((?:EDH|DHE).*?384) , qw((?:EDH|DHE).*?256) , qw((?:EDH|DHE).*?128) , qw((?:EDH|DHE).*?(?:RSA|DSS)) , qw(CAMELLIA) , # 7. unknown strength qw((?:SEED|IDEA)) , qw(RSA[_-]) , # 8. qw(DH[_-]) , qw(RC) , qw(EXP) , # 9. Export ... qw(AEC.*?256) , # insecure qw(AEC.*?128) , qw(AEC) , qw(ADH.*?256) , # no encryption qw(ADH.*?128) , qw(ADH) , ); foreach my $rex (@insecure) { # remove all known insecure suites _trace2("sort_cipher_names: insecure regex\t= $rex }"); push(@latest, grep{ /$rex/} @ciphers); # add matches to result @ciphers = grep{!/$rex/} @ciphers; # remove matches from original list } foreach my $rex (@strength) { # sort according strength $rex = qr/^(?:(?:SSL|TLS)[_-])?$rex/; # allow IANA constant names too #_trace2("sort_cipher_names(): regex\t= $rex }"); push(@sorted, grep{ /$rex/} @ciphers); # add matches to result @ciphers = grep{!/$rex/} @ciphers; # remove matches from original list } push(@sorted, @latest); # add insecure ciphers again my $num = scalar @sorted; if ($cnt != $num) { # print warning if above algorithm misses ciphers; uses perl's warn() # instead of our _warn() to clearly inform the user that the code here # needs to be fixed #warn STR_WARN . "missing ciphers in sorted list: $num < $cnt"; warn "**WARNING: missing ciphers in sorted list: $num < $cnt"; ## no critic qw(ErrorHandling::RequireCarping) #dbx# print "## ".@sorted . " # @ciphers"; } return @sorted; } # sort_cipher_names #_____________________________________________________________________________ #_________________________________________________________ internal methods __| sub show_getter03 { #? show hardcoded example for all getter functions for key 0x00,0x03 # 0x00,0x03 RSA 40 N RC4 RSA(512) MD5 4346,6347 0 WEAK SSLv3 export # 0x00,0x03 EXP-RC4-MD5 RSA_RC4_40_MD5 # C,0x00,0x03 RSA_EXPORT_WITH_RC4_40_MD5 my $cipher = "0x00,0x03"; print "# testing: $cipher ...\n"; printf("# %20s\t%s\t%-14s\t# %s\n", "function(key)", "key", "value", "(expected)"); printf("#----------------------+-------+----------------+---------------\n"); # printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_hex", $cipher, "hex", get_hex($cipher), "?"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_dtls", $cipher, "dtls", get_dtls($cipher), "N"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_bits", $cipher, "bits", get_bits($cipher), "40"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_enc", $cipher, "enc", get_enc( $cipher), "RC4"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_keyx", $cipher, "keyx", get_keyx($cipher), "RSA(512)"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_auth", $cipher, "auth", get_auth($cipher), "RSA"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_mac", $cipher, "mac", get_mac( $cipher), "MD5"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_rfc", $cipher, "rfc", get_rfc( $cipher), "4346,6347"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_sec", $cipher, "sec", get_sec( $cipher), "WEAK"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_ssl", $cipher, "ssl", get_ssl( $cipher), "SSLv3"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_tags", $cipher, "tags", get_tags($cipher), "export"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_name", $cipher, "name", get_name($cipher), "?"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_desc", $cipher, "desc", get_desc($cipher), "40 4346,6347 MD5 N RC4 RSA RSA(512) SSLv3 WEAK export"); printf("#----------------------+-------+----------------+---------------\n"); return; } # show_getter03 sub show_getter { #? show example for all getter functions for specified cipher key my $cipher = shift; printf("#%s:\n", (caller(0))[3]); if ($cipher !~ m/^[x0-9a-fA-F,]+$/) { # no cipher given, print hardcoded example show_getter03; return; } print "# testing: $cipher ...\n"; printf("# %20s\t%s\t%s\n", "function(key)", "key", "value"); printf("#----------------------+-------+----------------\n"); # printf("%-8s %s\t%s\t%s\n", "get_hex", $cipher, "hex", get_hex($cipher) ); printf("%-8s %s\t%s\t%s\n", "get_dtls", $cipher, "dtls", get_dtls($cipher) ); printf("%-8s %s\t%s\t%s\n", "get_bits", $cipher, "bits", get_bits($cipher) ); printf("%-8s %s\t%s\t%s\n", "get_enc", $cipher, "enc", get_enc( $cipher) ); printf("%-8s %s\t%s\t%s\n", "get_keyx", $cipher, "keyx", get_keyx($cipher) ); printf("%-8s %s\t%s\t%s\n", "get_auth", $cipher, "auth", get_auth($cipher) ); printf("%-8s %s\t%s\t%s\n", "get_mac", $cipher, "mac", get_mac( $cipher) ); printf("%-8s %s\t%s\t%s\n", "get_rfc", $cipher, "rfc", get_rfc( $cipher) ); printf("%-8s %s\t%s\t%s\n", "get_sec", $cipher, "sec", get_sec( $cipher) ); printf("%-8s %s\t%s\t%s\n", "get_ssl", $cipher, "ssl", get_ssl( $cipher) ); printf("%-8s %s\t%s\t%s\n", "get_tags", $cipher, "tags", get_tags($cipher) ); printf("%-8s %s\t%s\t%s\n", "get_name", $cipher, "name", get_name($cipher) ); printf("%-8s %s\t%s\t%s\n", "get_desc", $cipher, "desc", get_desc($cipher) ); printf("#----------------------+-------+----------------\n"); return; } # show_getter sub show_key { #? print hex key if found in internal data structure my $txt = shift; my $key = get_key($txt); printf("#%s:\n", (caller(0))[3]); print "key for $txt : $key\n"; return; } # show_key sub show_desc { #? print textual description for columns %cipher hash printf("#%s:\n", (caller(0))[3]); print "\n# %ciphers : example line:\n"; my $key = 0; printf(" '0x00,0x3D' -> ["); foreach (@{$ciphers_desc{head}}) { printf("\t%s", $ciphers_desc{sample}->{'0x00,0x3D'}[$key]); $key++; } printf(" ]\n"); print "\n# %ciphers : tabular description of one (example) line:\n"; printf("#-------+------+-----------------------+--------\n"); printf("# [%s]\t%5s\t%16s\t%s\n", "nr", "key", "description", "example"); printf("#-------+------+-----------------------+--------\n"); $key = 0; foreach (@{$ciphers_desc{head}}) { printf(" [%s]\t%6s\t%-20s\t%s\n", $key, $ciphers_desc{head}[$key], $ciphers_desc{text}[$key], $ciphers_desc{sample}->{'0x00,0x3D'}[$key]); $key++; } printf("#-------+------+-----------------------+--------\n"); print "\n# %ciphers : description of one line as perl code:\n"; printf("# varname %-23s\t# example # description\n", "%ciphers hash"); printf("#---------+-----------------------------+---------+---------------\n"); $key = 0; foreach (@{$ciphers_desc{head}}) { printf(" %6s = \$ciphers{'0xBE,0xEF'}[%s];\t# %-7s # %s\n", '$' . $ciphers_desc{head}[$key], $key, $ciphers_desc{sample}->{'0x00,0x3D'}[$key], $ciphers_desc{text}[$key]); $key++; } printf("#---------+-----------------------------+---------+---------------\n"); print "\n# %ciphers_names : description of one line as perl code:\n"; #printf("# key => [qw( iana OpenSSL openssl osaft )],\n)"; printf("# varname %-31s\t # source of name\n", "%ciphers hash"); printf("#---------+---------------------------------------+-----------------\n"); $key = 0; foreach (qw( iana OpenSSL openssl osaft )) { printf("%8s = \$ciphers_names{'0xBE,0xEF'}[%s];\t # %s\n", '$' . $_, $key, $_); $key++; } printf("#---------+---------------------------------------+-----------------\n"); print "\n# %ciphers_const : description of one line as perl code:\n"; #printf("# key => [qw( iana OpenSSL openssl osaft )],\n)"; printf("# varname %-31s\t # source of constant\n", "%ciphers hash"); printf("#---------+---------------------------------------+-----------------\n"); $key = 0; foreach (qw( iana OpenSSL openssl osaft )) { printf("%8s = \$ciphers_const{'0xBE,0xEF'}[%s];\t # %s\n", '$' . $_, $key, $_); $key++; } printf("#---------+---------------------------------------+-----------------\n"); print "\n# \@cipher_results : description of one line in array:\n"; # currently (12/2015) printf("#------+---------------+-------\n"); printf("# %s\t%12s\t%s\n", "ssl", "cipher name", "support"); printf("#------+---------------+-------\n"); printf(" %s\t%-12s\t%s\n", "TLSv12", "AES256-SHA256", "yes"); printf(" %s\t%-12s\t%s\n", "SSLv3", "NULL", "no"); printf("#------+---------------+-------\n"); printf("# in future (01/2016)\n"); printf("#------+---------------+-------+-------+-------+-------+-------\n"); printf("# %s\t%s\t%s\t%s\t%s\t%s\t%s\n", "ssl", "cipher\t", "pos +cipher", "pos +cipherraw", "dh-bits", "dh-par", "comment"); printf("#------+---------------+-------+-------+-------+-------+-------\n"); printf(" %s\t%s\t%s\t%s\t%s\t%s\t%s\n", "TLSv12", "0x00,0x3D", "0", "3", "512", "ec256", "comment"); printf("#------+---------------+-------+-------+-------+-------+-------\n"); return; } # show_desc sub show_overview { printf("#%s:\n", (caller(0))[3]); print <<'EoT'; = overview if cipher description and name exists in internal data structure = description of columns: = key - hex key for cipher suite = cipher desc - cipher suite known in internal data structure = cipher const- cipher suite constant name exists = cipher name - cipher suite (openssl) name exists = name # desc - 'yes' if name and description exists EoT print "= Note: following columns should have a *\n"; print "= ciphers_desc, ciphers_const, ciphers_name\n"; printf("=%s+%s+%s+%s+%s\n", "-" x 14, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 7); printf("= %13s\t%s\t%s\t%s\t%s\t%s\n", "", "ciphers", "ciphers", "ciphers", "ciphers", "name +"); printf("= %13s\t%s\t%s\t%s\t%s\t%s\n", "key ", " desc", " const", " name", " alias", " desc"); printf("=%s+%s+%s+%s+%s+%s\n", "-" x 14, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 7); my $cnt = 0; foreach my $key (sort keys %ciphers) { $cnt++; my $both = "no"; my $desc = " "; my $name = " "; my $const = " "; my $alias = " "; $desc = "*" if $ciphers{$key}; $name = "*" if $ciphers_names{$key}->{'osaft'}; $const = "*" if defined $ciphers_const{$key}; $alias = "*" if defined $ciphers_alias{$key}; $both = "yes" if ('*' eq $desc and '*' eq $name); printf("%14s\t%s\t%s\t%s\t%s\t%s\n", $key, $desc, $const, $name, $alias, $both); } printf("=%s+%s+%s+%s+%s+%s\n", "-" x 14, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 7); printf("= %s ciphers\n", $cnt); return; }; # show_overview sub show_const { printf("#%s:\n", (caller(0))[3]); print <<'EoT'; = overview of various cipher suite constant names = description of columns: = key - hex key for cipher suite = iana - constant of cipher suite as defined by IANA = OpenSSL - constant of cipher suite used in openssl's *.h files = osaft - constant of cipher suite used by O-Saft = o=iana o=op - yes if IANA's cipher suite name is same as O-Saft's name EoT printf("=%s+%s+%s+%s+%s-%s\n", "-" x 14, "-" x 39, "-" x 31, "-" x 31, "-" x 7, "-" x 7); printf("=%s osaft = \n", " " x 119); printf("= %13s\t\t%-37s\t%-31s\t%-23s\t%s\n", "key ", "iana", "OpenSSL", "osaft", "iana\topenssl"); printf("=%s+%s+%s+%s+%s+%s\n", "-" x 14, "-" x 39, "-" x 31, "-" x 31, "-" x 7, "-" x 7); foreach my $key (sort keys %ciphers) { my $const1 = $ciphers_const{$key}->{'iana'} || ''; my $const2 = $ciphers_const{$key}->{'OpenSSL'} || ''; my $const3 = $ciphers_const{$key}->{'osaft'} || ''; my $o_i = "no"; $o_i = "yes" if ($const1 eq ("TLS_" . $const3)); my $o_o = "no"; $o_o = "yes" if ($const2 eq ("TLS_" . $const3)); printf("%14s\t%-37s\t%-31s\t%-31s\t%s\t%s\n", $key, $const1, $const2, $const3, $o_i, $o_o); } printf("=%s+%s+%s+%s+%s+%s\n", "-" x 14, "-" x 39, "-" x 31, "-" x 31, "-" x 7, "-" x 7); return; }; # show_const sub show_alias { printf("#%s:\n", (caller(0))[3]); print <<'EoT'; = overview of various cipher suite alias names = description of columns: = key - hex key for cipher suite = alias - alias of cipher suite name = used in - where alias is used / was found EoT printf("= %13s\t%-37s\t%s\n", "key", "suite alias name", "used in"); printf("=%s+%s+%s\n", "-" x 14, "-" x 39, "-" x 31); foreach my $key (sort keys %ciphers_alias) { my $alias = $ciphers_alias{$key}[0]; my $from = $ciphers_names{$key}[2]; printf("%14s\t%-37s\t%-31s\n", $key, $alias, $from); } # hex,hex => [qw( cipher suite name aliases )],# comment (where found) printf("=%s+%s+%s\n", "-" x 14, "-" x 39, "-" x 31); return; }; # show_const sub show_names { printf("#%s:\n", (caller(0))[3]); print <<'EoT'; = overview of various cipher suite names = description of columns: = key - hex key for cipher suite = OpenSSL - cipher suite name used in openssl's *.h files = openssl - cipher suite name used by openssl executable = osaft - cipher suite name used by O-Saft = o=o - yes if openssl's cipher suite name is same as O-Saft's name EoT printf("=%s+%s+%s+%s+%s\n", "-" x 14, "-" x 23, "-" x 23, "-" x 23, "-" x 7); printf("= %13s\t\t%-23s\t%-23s\t%-15s\t%s\n", "key ", "OpenSSL", "openssl", "osaft", "openssl=osaft"); printf("=%s+%s+%s+%s+%s\n", "-" x 14, "-" x 23, "-" x 23, "-" x 23, "-" x 7); foreach my $key (sort keys %ciphers) { my $name1 = $ciphers_names{$key}->{'openssl'} || ''; my $name2 = $ciphers_names{$key}->{'osaft'} || ''; my $both = "no"; $both = "yes" if ($name1 eq $name2); printf("%14s\t%-23s\t%-23s\t%-23s\t%s\n", $key, $ciphers_names{$key}->{'OpenSSL'} || '', $name1, $name2, $both, ); } printf("=%s+%s+%s+%s+%s\n", "-" x 14, "-" x 23, "-" x 23, "-" x 23, "-" x 7); return; }; # show_names ###################################################### # show_names_o-o { # print "= openssl O-Saft iden-"; # print "= key name name tical"; # print "=----+------+----+-------"; # print " key DHE- DHE- yes "; # print " key DHE- EDH- no "; # }; # # show_const_o-o { # print "= openssl O-Saft iden-"; # print "= key const const tical"; # print "=----+------+----+-------"; # print " key TLS_ TLS_ yes "; # print " key TLS_ PCT_ no "; # }; # ###################################################### sub show_rfc { printf("#%s:\n", (caller(0))[3]); print <<'EoT'; = cipher suite and corresponding RFCs = description of columns: = key - hex key for cipher suite = RFC - RFC numbers, where cipher suite is described = OpenSSL - cipher suite name as used in openssl EoT printf("=%s+%s+%s\n", "-" x 14, "-" x 15, "-" x 23); printf("= %13s\t\t%s\t%s\n", "key ", "RFC", "OpenSSL"); printf("=%s+%s+%s\n", "-" x 14, "-" x 15, "-" x 23); foreach my $key (sort keys %ciphers) { my $rfc = $ciphers{$key}->{'rfc'} || ''; $rfc = "$rfc" if ('' eq $rfc); printf("%14s\t%-15s\t%-23s\n", $key, $rfc, $ciphers_names{$key}->{'osaft'} || '', ); # TODO: in 'rfc' können mehrer stehen, durch : getrennt } printf("=%s+%s+%s\n", "-" x 14, "-" x 15, "-" x 23); return; }; # show_rfc sub _show_tablehead { # print table headline according given format my $format = shift; my @values; return if ($format =~ m/tab$/); if ($format =~ m/^(?:dump|yeast)/) { my $key = "0x00,0x00"; # use first entry to get keys foreach my $val (sort keys %{$ciphers{$key}}) { push(@values, $val); } printf"%12s\t%s\n", $key, join("\t",@values); printf"#%s%s\n", "-" x 14, join("", ("+-------" x ($#values + 1))); } # printf("=%14s\t%-39s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", # "key", "name", "sec", "ssl", "enc", "bit", "mac", "auth", "keyx", "score", "tag" ); # format=15.12 if ($format =~ m/^(?:16|16.06.16|new|osaft)/) { printf("=%14s\t%-47s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", "key", "name", "ssl", "keyx", "auth", "enc", "bits", "mac", "tags" ); printf("=%s+%s+%s+%s+%s+%s+%s+%s+%s\n", "-" x 14, "-" x 47, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 11 ); } # 0x00,0x00,0x00 - NULL-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=None(0) Ma if ($format =~ m/^openssl/) { printf("=% 18s - %-23s %-5s %-11s %-7s %-11s %-7s %s\n", "key", "name", "ssl", "keyx", "auth", "enc(bit)", "mac", "tags" ); printf("=%s+%s+%s+%s+%s+%s+%s+%s\n", "-" x 19, "-" x 24, "-" x 5, "-" x 11, "-" x 7, "-" x 11, "-" x 7, "-" x 11 ); } return; } # _show_tablehead sub _show_tableline { # print table headline according given format my ($format, $key) = @_; my $name= $ciphers_names{$key}->{'iana'} || ''; my $ssl = $ciphers{$key}->{'ssl'} || ''; my $kx = $ciphers{$key}->{'keyx'} || ''; my $au = $ciphers{$key}->{'auth'} || ''; my $enc = $ciphers{$key}->{'enc'} || ''; my $bit = $ciphers{$key}->{'bits'} || '0'; my $mac = $ciphers{$key}->{'mac'} || ''; my $sec = $ciphers{$key}->{'sec'} || ''; my $tag = $ciphers{$key}->{'tags'} || ''; my $score = "0"; # dummy because we don't have scores in new structure if ($format =~ m/^(?:15|15.12.15|old)/) { $name= $ciphers_names{$key}->{'osaft'} || ''; #next if $key =~ m/0x/; # dirty hack 'til %cipher is clean printf(" %-30s %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", $name, $sec, $ssl, $enc, $bit, $mac, $au, $kx, $score, $tag); } if ($format =~ m/^(?:16|16.06.16|new|osaft)/) { $name= $ciphers_names{$key}->{'iana'} || ''; $name= $ciphers_names{$key}->{'osaft'} || ''; printf("%14s\t%-41s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", $key, $name, $ssl, $kx, $au, $enc, $bit, $mac, $tag); } if ($format =~ m/^(?:openssl)/) { $name= $ciphers_names{$key}->{'openssl'} || ''; printf("%19s - %-23s %-5s Kx=%-8s Au=%-4s Enc=%s(%s) Mac=%-4s %s\n", $key, $name, $ssl, $kx, $au, $enc, $bit, $mac, $tag); } return; } # _show_tableline sub _show_ciphers { # print internal list of ciphers my $format = shift; foreach my $key (sort keys %ciphers) { my @values; if ($format =~ m/^(?:dump|yeast)/) { foreach my $val (sort keys %{$ciphers{$key}}) { push(@values, $ciphers{$key}->{$val}); } printf"%12s\t%s\n", $key, join("\t",@values); next; } _show_tableline($format, $key); } return; } # _show_ciphers # =pod # # =head2 show_ciphers($format) # # Print C<%ciphers> data structure in specified format. # # Supported formats are: # * openssl - like openssl ciphers -V # * osaft - most important data # * dump - all available data # * 15.12.15 - format like in version 15.12.15 (for compatibility) # # =cut sub show_ciphers { #? print internal list of ciphers in specified format my $format = shift; printf("#%s:\n", (caller(0))[3]); if ($format !~ m/(?:dump|tab|yeast|osaft|openssl|15.12.15|15|old|16.06.16|16|new)/) { _warn("unknown format '$format'"); return; } if ($format !~ m/tab$/) { print <<'EoT'; = internal lists of ciphers = description of columns: = key - hex key for cipher suite EoT my $key = 0; foreach (@{$ciphers_desc{head}}) { printf("= %-4s - %s\n", $ciphers_desc{head}[$key], $ciphers_desc{text}[$key]); $key++; } } _show_tablehead($format); _show_ciphers($format); if ($format =~ m/^(?:16|16.06.16|new|osaft)/) { printf("=%s+%s+%s+%s+%s+%s+%s+%s+%s\n", "-" x 14, "-" x 47, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 11 ); } return; }; # show_ciphers #_____________________________________________________________________________ #___________________________________________________ initialization methods __| our @_keys; sub _ciphers_init_iana { my @keys; vprint "initialize from IANA tls-parameters.txt ..."; foreach my $key (keys %OSaft::Ciphers::_ciphers_iana) { if (grep{/^$key$/} @keys) { _warn(" duplicate IANA key: »$key«"); } else { push(@keys, $key); } $ciphers_const{$key}->{'iana'} = $OSaft::Ciphers::_ciphers_iana{$key}[0] || ''; $ciphers_names{$key}->{'iana'} = $OSaft::Ciphers::_ciphers_iana{$key}[0] || ''; $ciphers{$key}->{'rfc'} = $OSaft::Ciphers::_ciphers_iana{$key}[1] || ''; $ciphers{$key}->{'dtls'}= $OSaft::Ciphers::_ciphers_iana{$key}[2] || ''; } undef %OSaft::Ciphers::_ciphers_iana; # correct IANA settings (new in June 2016) foreach my $key (qw(0xA8 0xA9 0xAA 0xAB 0xAC 0xAD 0xAE)) { $ciphers{'0xCC,' . $key}->{'rfc'} = "7905"; } vprint " keys: " . ($#keys + 1); vprint " ciphers: " . scalar(keys %ciphers); return @keys; }; # _ciphers_init_iana sub _ciphers_init_osaft { vprint "initialize from OSaft settings ..."; foreach my $key (sort keys %{OSaft::Ciphers::_ciphers_osaft}) { ## no critic qw(Subroutines::ProtectPrivateSubs) if (grep{/^$key$/} @_keys) { v2print(" found O-Saft key: »$key«"); } else { v2print(" new O-Saft key: »$key«"); push(@_keys, $key); $ciphers{$key}->{'rfc'} = ''; $ciphers{$key}->{'dtls'} = ''; } $ciphers{$key}->{'ssl'} = $OSaft::Ciphers::_ciphers_osaft{$key}[0] || ''; $ciphers{$key}->{'keyx'}= $OSaft::Ciphers::_ciphers_osaft{$key}[1] || ''; $ciphers{$key}->{'auth'}= $OSaft::Ciphers::_ciphers_osaft{$key}[2] || ''; $ciphers{$key}->{'enc'} = $OSaft::Ciphers::_ciphers_osaft{$key}[3] || ''; $ciphers{$key}->{'bits'}= $OSaft::Ciphers::_ciphers_osaft{$key}[4] || '0'; $ciphers{$key}->{'mac'} = $OSaft::Ciphers::_ciphers_osaft{$key}[5] || ''; $ciphers{$key}->{'sec'} = $OSaft::Ciphers::_ciphers_osaft{$key}[6] || ''; $ciphers{$key}->{'tags'}= $OSaft::Ciphers::_ciphers_osaft{$key}[7] || ''; $ciphers{$key}->{'score'} = "0"; # dummy because we don't have scores in new structure $ciphers_names{$key}->{'osaft'} = $OSaft::Ciphers::_ciphers_names{$key}[0] || ''; $ciphers_const{$key}->{'osaft'} = $OSaft::Ciphers::_ciphers_names{$key}[1] || ''; #print "$key - $ciphers{$key}->{'ssl'} : $ciphers_names{$key}->{'osaft'} #\n"; } # add misisng names and constants foreach my $key (sort keys %{OSaft::Ciphers::_ciphers_names}) { ## no critic qw(Subroutines::ProtectPrivateSubs) my $name = $OSaft::Ciphers::_ciphers_names{$key}[0] || ''; my $const = $OSaft::Ciphers::_ciphers_names{$key}[1] || ''; if (not defined $ciphers_names{$key}->{'osaft'}) { #print(" undef O-Saft name: $key : »$name«\n"); $ciphers_names{$key}->{'osaft'} = $name; next; } if ('' eq $ciphers_names{$key}->{'osaft'}) { #print(" emtpty O-Saft name: $key : »$name«\n"); $ciphers_names{$key}->{'osaft'} = $name; } } undef %OSaft::Ciphers::_ciphers_const; undef %OSaft::Ciphers::_ciphers_names; undef %OSaft::Ciphers::_ciphers_osaft; #vprint " keys: " . ($#_keys + 1); vprint " ciphers: " . scalar(keys %ciphers); return; }; # _ciphers_init_osaft sub _ciphers_init_openssl { vprint "initialize data from »openssl ciphers -V« ..."; foreach my $key (keys %OSaft::Ciphers::_ciphers_openssl_all) { if (grep{/^$key$/} @_keys) { _warn(" duplicate openssl key: »$key«"); } else { push(@_keys, $key); } #print $key; $ciphers{$key}->{'ssl'} = $OSaft::Ciphers::_ciphers_openssl_all{$key}[0]; $ciphers{$key}->{'kexx'}= $OSaft::Ciphers::_ciphers_openssl_all{$key}[1]; $ciphers{$key}->{'auth'}= $OSaft::Ciphers::_ciphers_openssl_all{$key}[2]; $ciphers{$key}->{'enc'} = $OSaft::Ciphers::_ciphers_openssl_all{$key}[3]; $ciphers{$key}->{'bits'}= $OSaft::Ciphers::_ciphers_openssl_all{$key}[4]; $ciphers{$key}->{'mac'} = $OSaft::Ciphers::_ciphers_openssl_all{$key}[5]; $ciphers{$key}->{'tags'}= $OSaft::Ciphers::_ciphers_openssl_all{$key}[7] || ''; my $name = $OSaft::Ciphers::_ciphers_openssl_all{$key}[6]; $ciphers_names{$key}->{'openssl'} = $name; } vprint " ciphers: " . scalar(keys %ciphers); return; }; # _ciphers_init_openssl sub _ciphers_init { #? additional initializations for data structures # scan options, must be ckecked here also because this function will be # called before _main() foreach (@ARGV) { $VERBOSE++ if ($_ =~ /^--v$/); } @_keys = _ciphers_init_iana(); _ciphers_init_osaft(); undef @_keys; _ciphers_init_openssl(); return; }; # _ciphers_init sub _main_help { #? print help printf("# %s %s\n", __PACKAGE__, $VERSION); if (eval {require POD::Perldoc;}) { # pod2usage( -verbose => 1 ); exec( Pod::Perldoc->run(args=>[$0]) ); } if (qx(perldoc -V)) { ## no critic qw(InputOutput::ProhibitBacktickOperators) # may return: You need to install the perl-doc package to use this program. #exec "perldoc $0"; # scary ... printf("# no POD::Perldoc installed, please try:\n perldoc $0\n"); } return; }; # _main_help sub _main_usage { #? print usage my $name = (caller(0))[1]; print "# commands to show internal cipher tables:\n"; foreach my $cmd (qw(overview names const alias rfc description)) { printf("\t%s %s\n", $name, $cmd); } print "# commands to show ciphers based on origin:\n"; foreach my $cmd (qw(ciphers=osaft ciphers=openssl ciphers=iana ciphers=old)) { printf("\t%s %s\n", $name, $cmd); } print "# various commands:\n"; foreach my $cmd (qw(ciphers=dumptab)) { printf("\t%s %s\n", $name, $cmd); } printf("\t$name getter=KEY #(KEY: )\n"); printf("\t$name key=KEY #(KEY: )\n"); printf("\t$name ciphers=osaft\n"); printf("\t$name ciphers=openssl\n"); printf("\t$name ciphers=dumptab > c.csv; libreoffice c.csv\n"); printf("\t$name ciphersdescr\n"); return; }; # _main_usage sub _main { #? print own documentation if (0 > $#ARGV) { _main_help; exit 0; } # got arguments, do something special while (my $arg = shift @ARGV) { # ----------------------------- options $VERBOSE++ if ($arg =~ /^--v$/); # ----------------------------- commands print "$VERSION\n" if ($arg =~ /^version/i); show_overview() if ($arg =~ /^overview/); show_names() if ($arg =~ /^names/); show_const() if ($arg =~ /^const/); show_alias() if ($arg =~ /^alias(?:es)?/); show_rfc() if ($arg =~ /^rfc/i); show_desc() if ($arg =~ /^desc(?:ription)?/); show_desc() if ($arg =~ /^ciphers.?desc(?:ription)?/); #show_ciphers($1) if ($arg =~ /^ciphers=(.*)$/); # 15|16|dump|osaft|openssl if ($arg =~ /^ciphers=(.*)$/) { show_ciphers($1); } # same as above, but keeps perlcritic quiet if ($arg =~ /^getter=?(.*)/) { show_getter($1); } if ($arg =~ /^key=?(.*)/) { show_key($1); } if ($arg !~ /^--h(?:elp)?/) { next; } _main_usage(); } exit 0; }; # _main sub cipher_done {}; # dummy to check successful include # complete initializations _ciphers_init(); #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =head1 COMMANDS If called from command line, like OSaft/Ciphers.pm [OPTIONS ..] [COMMANDS] this modules provides following commands: =over 4 =item version - just print the module's version =item description - print description of all data structures =item overview - print overview if cipher description and name exists in internal lists =item names - print overview of various cipher suite names =item const - print overview of various cipher suite constant names =item rfc - print cipher suite name and corresponding RFCs =item ciphers=dump - print internal lists of ciphers (all data, internal format) =item ciphers=osaft - print internal lists of ciphers (internal format) =item ciphers=openssl - print internal lists of ciphers (format like "openssl ciphers -V") =item ciphers=16 =back =head1 OPTIONS =over 4 =item --v - print verbose messages (in CLI mode only). =back =head1 NOTES It's often recommended not to export constants and variables from modules, see for example http://perldoc.perl.org/Exporter.html#Good-Practices . The main purpose of this module is defining variables. Hence we export them. =head1 SEE ALSO # ... =head1 AUTHOR 28-may-16 Achim Hoffmann =cut ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main() if (not defined caller); 1; O-Saft-19.01.19/OSaft/Doc/000077500000000000000000000000001342117255600145745ustar00rootroot00000000000000O-Saft-19.01.19/OSaft/Doc/Data.pm000077500000000000000000000372671342117255600160250ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!# This software is licensed under GPLv2. Please see o-saft.pl for details. ## no critic qw(Documentation::RequirePodSections) # Our POD below is fine, Perl::Critic (severity 2) is too pedantic here. ## no critic qw(RegularExpressions::ProhibitFixedStringMatches) # Using regex instead of strings is not bad. Perl::Critic (severity 2) # is too pedantic here. ## no critic qw(ControlStructures::ProhibitPostfixControls) # We believe it's better readable (severity 2 only) ## no critic qw(RegularExpressions::RequireExtendedFormatting) # Most of our regex are easy to read, it's the nature of the code herein # to have simple and complex regex. /x is used for human readability as # needed. package OSaft::Doc::Data; use strict; use warnings; our $VERSION = "18.11.03"; # official verion number of tis file my $SID_data = "@(#) Data.pm 1.13 18/11/10 16:44:01"; # binmode(...); # inherited from parent, SEE Perl:binmode() #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME OSaft::Doc::Data - common Perl module to read data for user documentation =head1 SYNOPSIS use OSaft::Doc::Data; =head1 METHODS =cut #_____________________________________________________________________________ #_________________________________________________________ internal methods __| sub _replace_var { #? replace $0 by name and $VERSION by version in array, return array my ($name, $version, @arr) = @_; # SEE Perl:map() s#\$VERSION#$version#g for @arr; # add current VERSION s#(?) { $egg .= $_ if (m/^#begin/..m/^#end/); } $egg =~ s/#(begin|end) .*\n//g; close($fh); return scalar reverse "\n$egg"; } # get_egg =pod =head2 get_markup($file,$name,$version) Return all data converted to internal markup format. Returns array of lines. =cut sub get_markup { my $file = shift; my $parent = shift || "o-saft.pl"; my $version = shift || $VERSION; my @txt; my $fh = _get_filehandle($file); # Preformat plain text with markup for further simple substitutions. We # use a modified (& instead of < >) POD markup as it is easy to parse. # & was choosen because it rarely appears in texts and is not a meta # character in any of the supported output formats (text, wiki, html), # and also causes no problems inside regex. for (<$fh>) { ## no critic qw(InputOutput::ProhibitReadlineInForLoop) # There is no differnce if the array is allocated by # using a local variable or implecitely in the loop ## no critic qw(RegularExpressions::ProhibitComplexRegexes) # it's the nature of some regex to be complex # SEE MARKUP next if (m/^#begin/..m/^#end/); # remove egg next if (/^#/); # remove comments next if (/^\s*#.*#$/); # remove formatting lines s/^([A-Z].*)/=head1 $1/; s/^ {4}([^ ].*)/=head2 $1/; s/^ {6}([^ ].*)/=head3 $1/; # for =item keep spaces as they are needed in man_help() s/^( +[a-z0-9]+\).*)/=item * $1/;# list item, starts with letter or digit and ) s/^( +\*\* .*)/=item $1/; # list item, second level s/^( +\* .*)/=item $1/; # list item, first level s/^( {11})([^ ].*)/=item * $1$2/;# list item s/^( {14})([^ ].*)/S&$1$2&/; # exactly 14 spaces used to highlight line s/^( {18})([^ ].*)/S&$1$2&/; # exactly 18 if (not m/^(?:=|S&|\s+\$0)/) { # no markup in example lines and already marked lines s#(\s)((?:\+|--)[^,\s).]+)([,\s).])#$1I&$2&$3#g; # markup commands and options # TODO: fails for something like: --opt=foo="bar" # TODO: above substitute fails for something like: --opt --opt # hence same substitute again (should be sufficent then) s#(\s)((?:\+|--)[^,\s).]+)([,\s).])#$1I&$2&$3#g; } if (not m/^S/ and not m/^ {14,}/) { s/((?:Net::SSLeay|ldd|openssl|timeout|IO::Socket(?:::SSL|::INET)?)\(\d\))/L&$1&/g; s/((?:Net::SSL(?:hello|info)|o-saft(?:-dbx|-man|-usr|-README)(?:\.pm)?))/L&$1&/g; } s/ (L&[^&]*&)/ $1/g; s/(L&[^&]*&) /$1 /g; # If external references are enclosed in double spaces, we squeeze # leading and trailing spaces 'cause additional characters will be # added later (i.e. in man_help()). Just pretty printing ... if (m/^ /) { # add internal links; quick&dirty list here # we only want to catch header lines, hence all capital letters s/ ((?:DEBUG|RC|USER)-FILE)/ X&$1&/g; s/ (CONFIGURATION (?:FILE|OPTIONS))/ X&$1&/g; s/ (CIPHER NAMES)/ X&$1&/g; s/ (LAZY SYNOPSIS)/ X&$1&/g; s/ (KNOWN PROBLEMS)/ X&$1&/g; s/ (BUILD DOCKER IMAGE)/ X&$1&/g; s/ (RESULTS|COMMANDS|OPTIONS|CHECKS|OUTPUT|CUSTOMIZATION) / X&$1& /g; s/ (LIMITATIONS|DEPENDENCIES|INSTALLATION|DOCKER|TESTING) / X&$1& /g; s/ (CUSTOMIZATION|SCORING|EXAMPLES|ATTRIBUTION|VERSION) / X&$1& /g; s/ (DESCRIPTION|SYNOPSIS|QUICKSTART|SECURITY|DEBUG|AUTHOR) / X&$1& /g; } push(@txt, $_); } close($fh); return _replace_var($parent, $version, @txt); } # get_markup =pod =head2 get_text($file) Same as get() but with some variables substituted. =cut sub get_text { #? print program's help # NOTE: NOT YET READY, not yet used my $file = shift; my $label = shift || ""; # || to avoid uninitialized value $label = lc($label); my $anf = uc($label); my $end = "[A-Z]"; # _man_dbx("man_help($anf, $end) ..."); # no special help, print full one or parts of it my $txt = join ("", get_markup($file)); # #if (1 < (grep{/^--v/} @ARGV)) { # with --v --v # # print scalar reverse "\n\n$egg"; # # return; # #} #print "T $txt T"; if ($label =~ m/^name/i) { $end = "TODO"; } #$txt =~ s{.*?(=head. $anf.*?)\n=head. $end.*}{$1}ms;# grep all data # above terrible performance and unreliable, hence in peaces below $txt =~ s/.*?\n=head1 $anf//ms; $txt =~ s/\n=head1 $end.*//ms; # grep all data $txt = "\n=head1 $anf" . $txt; $txt =~ s/\n=head2 ([^\n]*)/\n $1/msg; $txt =~ s/\n=head3 ([^\n]*)/\n $1/msg; $txt =~ s/\n=(?:[^ ]+ (?:\* )?)([^\n]*)/\n$1/msg;# remove inserted markup $txt =~ s/\nS&([^&]*)&/\n$1/g; $txt =~ s/[IX]&([^&]*)&/$1/g; # internal links without markup $txt =~ s/L&([^&]*)&/"$1"/g; # external links, must be last one if (0 < (grep{/^--v/} @ARGV)) { # do not use $^O but our own option # some systems are tooo stupid to print strings > 32k, i.e. cmd.exe print "**WARNING: using workaround to print large strings.\n\n"; print foreach split(//, $txt); # print character by character :-(( } else { #print $txt; } #print "t $txt t"; if ($label =~ m/^todo/i) { print "\n NOT YET IMPLEMENTED\n"; # TODO: { # foreach my $label (sort keys %checks) { # next if (0 >= _is_member($label, \@{$cfg{'commands-NOTYET'}})); # print " $label\t- " . $checks{$label}->{txt} . "\n"; # } # TODO: } } return $txt; } # get_text =pod =head2 get_as_text($file) Return all data from file as is. Returns data as string. =cut sub get_as_text { my $fh = _get_filehandle(shift); return <$fh>; } # TODO: misses close($fh); =pod =head2 get($file,$name,$version) Return all data from file and replace $0 by $name. Returns data as string. =cut sub get { my $file = shift; my $name = shift || "o-saft.pl"; my $version = shift || $VERSION; my $fh = _get_filehandle($file); return _replace_var($name, $version, <$fh>); # TODO: misses close($fh); } # get =pod =head2 print_as_text($file) Same as get() but prints text directly. =cut sub print_as_text { my $fh = _get_filehandle(shift); print <$fh>; return; } # TODO: misses close($fh); sub _main_help { #? print help printf("# %s %s\n", __PACKAGE__, $VERSION); if (eval {require POD::Perldoc;}) { # pod2usage( -verbose => 1 ); exit( Pod::Perldoc->run(args=>[$0]) ); } ## no critic qw(InputOutput::ProhibitBacktickOperators) # SEE Perl:perlcritic if (qx(perldoc -V)) { # may return: You need to install the perl-doc package to use this program. #exec "perldoc $0"; # scary ... printf("# no POD::Perldoc installed, please try:\n perldoc $0\n"); exit 0; } }; # _main_help =pod =head1 COMMANDS If called from command line, like OSaft/Doc/Data.pm [COMMANDS] file this modules provides following commands: =head2 VERSION Print VERSION version. =head2 version Print internal version. =head2 list Print list of *.txt files in current directory. =head2 get filename Call get(filename). =head2 get_text filename Call get_text(filename). =head2 get_as_text filename Call get_as_text(filename). =head2 get_markup filename Call get_text(filename). =head2 print_as_text filename Call print_as_text(filename). =head1 OPTIONS =over 4 =item --V Print VERSION version. =back =cut sub list { my $dir = $0; $dir =~ s#[/\\][^/\\]*$##; my $txt = ""; opendir(DIR, $dir) or return $!; while (my $file = readdir(DIR)) { next unless (-f "$dir/$file"); next unless ($file =~ m/\.txt$/); $txt .= "$file\n"; } closedir(DIR); return $txt; } # list sub _main { #? print own documentation ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # see .perlcritic for detailed description of "no critic" my @argv = @_; binmode(STDOUT, ":unix:utf8"); # latin1 geht nicht binmode(STDERR, ":unix:utf8"); if (0 > $#argv) { _main_help; exit 0; } # got arguments, do something special while (my $cmd = shift @argv) { my $arg = shift @argv; if ($cmd =~ /^--?h(?:elp)?$/ ) { _main_help; exit 0; } # ----------------------------- commands if ($cmd =~ /^list$/) { print list(); } if ($cmd =~ /^get$/) { print get($arg); } if ($cmd =~ /^get.?mark(up)?/) { print get_markup($arg); } if ($cmd =~ /^get.?text/) { print get_text($arg); } if ($cmd =~ /^get.?as.?text/) { print get_as_text($arg); } if ($cmd =~ /^print$/) { print_as_text($arg); } if ($cmd =~ /^version$/) { print "$SID_data\n"; exit 0; } if ($cmd =~ /^(-+)?V(ERSION)?$/){ print "$VERSION\n"; exit 0; } } exit 0; } # _main sub o_saft_help_done {}; # dummy to check successful include =pod =head1 MARKUP Following notations / markups are used for public (user) documentation (for example help.txt): =over 2 =item TITLE Titles start at beginning of a line, i.g. all upper case characters. =item SUB-Title Sub-titles start at beginning of a line preceeded by 4 or 6 spaces. =item code Code lines start at beginning of a line preceeded by 14 or more spaces. =item "text in double quotes" References to text or cite. =item 'text in single quotes' References to verbatim text elswhere or constant string in description. =item '* list item Force list item (first level) in generated markup. =item ** list item Force list item (second level) in generated markup. =item d) list item Force list item in generated markup (d may be a digit or character). =item $VERSION Will be replaced by current version string (as defined in caller). =item $0 Will be replaced by caller's name (i.g. o-saft.pl). =item `$0' Will not be replaced, but kept as is. =back Referenzes to titles are written in all upper case characters and prefixed and suffixed with 2 spaces. There is only one special markup used: =over 2 =item X&Some title here& Which refers to sub-titles. It must be used to properly markup internal links to sub-sections if the title is not written in all upper case. =back All head lines for sections (see TITLE above) must be preceeded by 2 empty lines. All head lines for commands and options should contain just this command or option, aliases should be written in their own line (to avoid confusion in some other parsers, like Tcl). List items should be followed by an empty line. Texts in section headers should not contain any quote characters. I.g. no other markup is used. Even Lines starting with '#' as first character are usually not treated as comment line but verbatim text. =head2 Special markups =head3 Left hand space =over 6 =item none - head line level 1 =item exactly 4 - head line level 2 =item exactly 6 - head line level 3 =item exactly 11 - list item =item exactly 14 - highlighted line =item exactly 18 - code line =back =head3 Left hand *: =over 6 =item spaces * - list item level 1 =item spaces ** - list item level 2 =back =head3 Left hand digit or letter followed by ) List item may start with letter or digit fowwed by ) . =head3 Special markups for o-saft.tcl The sub-titles in the COMMANDS and OPTIONS sections must look like: =over 6 =item Commands for whatever text =item Commands to whatever text =item Options for whatever text =back Means that the prefixes "Commands for" and "Options for" are used to identify groups of commands and options. If a sub-title does not start with these prefixes, all following commands and options are ignored. =head1 SEE ALSO # ... =head1 VERSION C<$VERSION> =head1 AUTHOR 17-oct-17 Achim Hoffmann =cut ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main(@ARGV) if (not defined caller); 1; # SEE Note:Documentation # All public (user) documentation is in plain ASCII format (see help.txt). =pod =head1 Annotations, Internal Notes The annotations here are for internal documentation only. For details about our annotations, please SEE Annotations, in o-saft.pl. =cut __DATA__ O-Saft-19.01.19/OSaft/Doc/Glossary.pm000077500000000000000000000507111342117255600167440ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!# This software is licensed under GPLv2. Please see o-saft.pl for details. ## no critic qw(Documentation::RequirePodSections) # our POD below is fine, perlcritic (severity 2) is too pedantic here. package OSaft::Doc::Glossary; use strict; use warnings; my $VERSION = "17.10.17"; # official verion number of tis file my $SID = "@(#) Glossary.pm 1.6 18/01/13 21:56:44"; print STDERR "**WARNING: OSaft::Doc::Glossary obsolete since O-Saft version 18.01.18"; #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME OSaft::Doc::Glossary - common perl module to define O-Saft glossary texts =head1 SYNOPSIS use OSaft::Doc::Glossary; =head1 METHODS =head2 get() Return all data. =cut #_____________________________________________________________________________ #__________________________________________________________________ methods __| sub get { return ; } sub print_as_text { print ; return; } sub o_saft_glossary_done() {}; # dummy to check successful include ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| print_as_text() if (! defined caller); 1; # All documentation following __DATA__ is in plain ASCII format. # It's designed for human radability and simple editing. # Syntax is: # each line consist of a KEY and a TEXT # KEY and a TEXT are separated by TAB (aka \09 aka 0x09) # To support duplicate keys, for example because they have different TEXTs, # some keys may hav added whitespaces on right. # Keys which contain spaces at right siteto make key unique: CBC, CSP, EME __DATA__ AA Attribute Authority AAD additional authenticated data ACME Automated Certificate Management Environment ACL Access Control List ADH Anonymous Diffie-Hellman Adler32 hash function AE Authenticated Encryption AEAD Authenticated Encryption with Additional Data AECDHE Anonymous Ephemeral ECDH AEM Authenticated Encryption Mode aka Advanced Encryption Mode aka OCB3 AES Advanced Encryption Standard AES-XTS ? AIA Authority Information Access (certificate extension) AKC Agreement with Key Confirmation AKID Authority Key IDentifier ALPN Application Layer Protocol Negotiation ARC4 Alleged RC4 (see RC4) ARCFOUR alias for ARC4 ARIA 128-bit Symmetric Block Cipher ASN Autonomous System Number ASN.1 Abstract Syntax Notation number One BACPA Blockwise-adaptive chosen-plaintext attack bcrypt hash function (Niels Provos, David Mazières, 1999) BLAKE hash function (Jean-Philippe Aumasson, Luca Henzen, Willi Meier, Raphael C.-W. Phan, 2008) BLAKE2 fast secure hashing function (2012) BLAKE-224 see BLAKE (224 bit) BLAKE-256 see BLAKE (256 bit) BLAKE-384 see BLAKE (384 bit) BLAKE-512 see BLAKE (512 bit) BEAR block cipher combining stream cipher and hash function BDH Bilinear Diffie-Hellman BEAST Browser Exploit Against SSL/TLS BER Basic Encoding Rules BGP Boorder Gateway Protocol Blowfish symmetric block cipher boomerang attack attack on BLAKE Brainpool signature algorithm, from BSI BREACH Browser Reconnaissance & Exfiltration via Adaptive Compression of Hypertext (a variant of CRIME) Bullrun NSA program to break encrypted communication CAMELLIA Encryption algorithm 128 bit (by Mitsubishi and NTT) CAST-128 Carlisle Adams and Stafford Tavares, block cipher CAST5 alias for CAST-128 CAST-256 Carlisle Adams and Stafford Tavares, block cipher CAST6 alias for CAST-256 cipher suite cipher suite is a named combination of authentication, encryption, and message authentication code algorithms CA Certificate Authority (aka root CA) CAA Certificate Authority Authorization CAA RR CAA Resource Record CBC Cyclic Block Chaining CBC Cipher Block Chaining (sometimes) CBC Ciplier Block Chaining (sometimes) CBC-MAC Cipher Block Chaining - Message Authentication Code CBC-MAC-ELB Cipher Block Chaining - Message Authentication Code - Encrypt Last Block CCM CBC-MAC Mode CCS Change Cipher Spec (protocol) CDH ? Diffie-Hellman CDP CRL Distribution Points CEK Content Encryption Key CFB Cipher Feedback CFB3 Cipher Feedback CFBx Cipher Feedback x bit mode ChaCha stream cipher algorithm ChaCha-Poly1305 Authenticated Encryption with Associated Data (AEAD) CHAP Challenge Handshake Authentication Protocol CKA (PKCS#11) CKK (PKCS#11) CKM (PKCS#11) CMAC Cipher-based MAC CMC CBC-mask-CBC CMP X509 Certificate Management Protocol CMS Cryptographic Message Syntax CMVP Cryptographic Module Validation Program (NIST) CN Common Name CP Certificate Policy (certificate extension) CPD Certificate Policy Definitions CPS Certification Practice Statement CRC Cyclic Redundancy Check CRC8 CRC with polynomial length 8 CRC16 CRC with polynomial length 16 CRC32 CRC with polynomial length 32 CRC64 CRC with polynomial length 64 CRAM Challenge Response Authentication Mechanism CRIME Compression Ratio Info-leak Made Easy (Exploit SSL/TLS) CRL Certificate Revocation List CSP Certificate Service Provider CSP Cryptographic Service Provider CSP Critical Security Parameter (used in FIPS 140-2) CSP: Content Security Policy (used as HTTP header) CSR Certificate Signing Request CT Certificate Transparency CTL Certificate Trust Line CTR Counter Mode (sometimes: CM; block cipher mode) CTS Cipher Text Stealing Curve448 signature algorithm, aka Goldilocks (224 bit) Curve25519 signature algorithm by Dan J. Bernstein (ca. 128 bit) CWC CWC Mode (Carter-Wegman + CTR mode; block cipher mode) DAA Data Authentication Algorithm DAC Data Authentication Code DACL Discretionary Access Control List DANE DNS-based Authentication of Named Entities DDH Decisional Diffie-Hellman (Problem) DEA Data Encryption Algorithm (sometimes a synonym for DES) DECIPHER synonym for decryption DEK Data Encryption Key DER Distinguished Encoding Rules DES Data Encryption Standard DESede alias for 3DES ?java only? DESX extended DES 3DES Tripple DES (168 bit) 3DES-EDE alias for 3DES 3TDEA Three-key Tripple DEA (sometimes: Tripple DES; 168 bit) 2TDEA Double-key Tripple DEA (sometimes: Double DES; 112 bit) D5 Verhoeff's Dihedral Group D5 Check DH Diffie-Hellman DHE Diffie-Hellman ephemeral (historic acronym, often used, mainly in openssl) DLIES Discrete Logarithm Integrated Encryption Scheme DLP Discrete Logarithm Problem DN Distinguished Name DNSSEC DNS Security Extension DPA Dynamic Passcode Authentication (see CAP) DRBG Deterministic Random Bit Generator DROWN Decrypting RSA with Obsolete and Weakened eNcryption (Exploit SSL/TLS) DSA Digital Signature Algorithm DSS Digital Signature Standard DTLS Datagram TLS DTLSv1 Datagram TLS 1.0 Dual EC DBRG Dual Elliptic Curve Deterministic Random Bit Generator DV Domain Validation DV-SSL Domain Validated Certificate EAL Evaluation Assurance Level EAP Extensible Authentication Protocol EAP-PSK Extensible Authentication Protocol using a Pre-Shared Key EAX EAX Mode (block cipher mode) EAXprime alias for EAX Mode EBC Edge Boundery Controller EC Elliptic Curve ECB Electronic Code Book mode ECC Elliptic Curve Cryptography ECDH Elliptic Curve Diffie-Hellman ECDHE Ephemeral ECDH ECDSA Elliptic Curve Digital Signature Algorithm ECGDSA Elliptic Curve ??? DSA ECHO hash function (Ryad Benadjila, Olivier Billet, Henri Gilbert, Gilles Macario-Rat, Thomas Peyrin, Matt Robshaw, Yannick Seurin, 2010) ECIES Elliptic Curve Integrated Encryption Scheme ECKA Elliptic Curve Key Agreement ECKA-EG Elliptic Curve Key Agreement of ElGamal Type ECKDSA Elliptic Curve ??? DSA ECMQV Elliptic Curve Menezes-Qu-Vanstone ECOH Elliptic Curve only hash # 'ECRYPT ?? Ed25519 alias for Curve25519 Ed448 alias for Curve448 EDE Encryption-Decryption-Encryption EDH Ephemeral Diffie-Hellman EGADS Entropy Gathering and Distribution System EGD Entropy Gathering Daemon EKU Extended Key Usage ELB Encrypt Last Block ElGamal asymmetric block cipher ENCIPHER synonym for encryption EME ECB-mask-ECB EME Encoding Method for Encryption ESP Encapsulating Security Payload ESSIV Encrypted salt-sector initialization vector EtM Encrypt-then-MAC ETSI-TS European Telecommunications Standards Institute - Technical Specification EV Extended Validation EV-SSL Extended Validation Certificate FEAL Fast Data Encryption Algorithm FFC Finite Field Cryptography FFT Fast Fourier Transform FIPS Federal Information Processing Standard FIPS46-2 FIPS Data Encryption Standard (DES) FIPS73 FIPS Guidelines for Security of Computer Applications FIPS140-2 FIPS Security Requirements for Cryptographic Modules FIPS140-3 proposed revision of FIPS 140-2 FIPS180-3 FIPS Secure Hash Standard FIPS186-3 FIPS Digital Signature Standard (DSS) FIPS197 FIPS Advanced Encryption Standard (AES) FIPS198-1 FIPS The Keyed-Hash Message Authentication Code (HMAC) FREAK Factoring Attack on RSA-EXPORT Keys FQDN Fully-qualified Domain Name FSB Fast Syndrome Based Hash FSM Finite State Machine FZA FORTEZZA G-DES ??? DES GCM Galois/Counter Mode (block cipher mode) GHASH Hash funtion used in GCM GMAC MAC for GCM Grøstl hash function (Lars Knudsen, 2010) Goldilocks see Curve448 GOST Gossudarstwenny Standard (block cipher) Grainv1 stream cipher (64-bit IV) Grainv128 stream cipher (96-bit IV) GREASE Generate Random Extensions And Sustain Extensibility HAIFA HAsh Iterative FrAmework hash127 fast hash function (by Dan Bernstein) HAVAL one-way hashing HAS-160 hash function HAS-V hash function HC128 stream cipher HC256 stream cipher HEARTBLEED attack against TLS extension heartbeat HEIST HTTP Encrypted Information can be Stolen through TCP-windows HIBE hierarchical identity-based encryption HNF-256 hash function (Harshvardhan Tiwari, Krishna Asawa, 2014) HMAC keyed-Hash Message Authentication Code HMQV h? Menezes-Qu-Vanstone HSM Hardware Security Module HPKP HTTP Public Key Pinning HSR Header + Secret + Random HSTS HTTP Strict Transport Security HTOP HMAC-Based One-Time Password IAPM Integrity Aware Parallelizable Mode (block cipher mode of operation) ICM Integer Counter Mode (alias for CTR) IDP Issuing Distribution Points IDEA International Data Encryption Algorithm (by James Massey and Xuejia Lai) IESG Internet Engineering Steering Group IETF Internet Engineering Task Force IFC Integer Factorization Cryptography IGE Infinite Garble Extension IKE Internet Key Exchange IKEv2 IKE version 2 IND-BACPA Indistinguishability of encryptions under blockwise-adaptive chosen-plaintext attack IND-CCA Indistinguishability of encryptions under chosen-cipgertext attack IND-CPA Indistinguishability of encryptions under chosen-plaintext attack INT-CTXT Integrity of ciphertext INT-PTXT Integrity of plaintext ISAKMP Internet Security Association and Key Management Protocol IV Initialization Vector JH hash function (Hongjun Wu, 2011) JSSE Java Secure Socket Extension Keccak hash function (Guido Bertoni, Joan Daemen, Michaël Peeters und Gilles Van Assche, 2012) KCI Key Compromise Impersonation KEA Key Exchange Algorithm (alias for FORTEZZA-KEA) KEK Key Encryption Key KSK Key Signing Key (DNSSEC) KU Key Usage LAKE hash function (Jean-Philippe Aumasson, Willi Meier, Raphael C.-W. Phan, 2008) LFSR Linear Feedback Shift Register LION block cipher combining stream cipher and hash function LLL Lenstra–Lenstra–Lovász, lattice basis reduction algorithm LM hash LAN Manager hash aka LanMan hash Logjam Attack to force server to downgrade to export ciphers LRA Local Registration Authority LRW Liskov, Rivest, and Wagner (blok encryption) Lucky 13 Break SSL/TLS Protocol MARS MAC Message Authentication Code MCF Modular Crypt Format MDC2 Modification Detection Code 2 aka Meyer-Schilling MDC-2 same as MDC2 MD2 Message Digest 2 MD4 Message Digest 4 MD5 Message Digest 5 MEE MAC-then-Encode-then-Encrypt MEK Message Encryption Key MECAI Mutually Endorsing CA Infrastrukture MGF Mask Generation Function MISTY1 block cipher algorithm MQV Menezes-Qu-Vanstone (authentecated key agreement MtE MAC-then-encrypt NCP Normalized Certification Policy (according TS 102 042) Neokeon symmetric block cipher algorithm nonce (arbitrary) number used only once NPN Next Protocol Negotiation NSS Network Security Services NTLM NT Lan Manager. Microsoft Windows challenge-response authentication method. NULL no encryption NUMS nothing up my sleeve numbers OAEP Optimal Asymmetric Encryption Padding OCB Offset Codebook Mode (block cipher mode of operation) OCB1 same as OCB OCB2 improved OCB aka AEM OCB3 improved OCB2 OCSP Online Certificate Status Protocol OCSP stapling formerly known as: TLS Certificate Status Request OFB Output Feedback OFBx Output Feedback x bit mode OID Object Identifier OMAC One-Key CMAC, aka CBC-MAC OMAC1 same as CMAC OMAC2 same as OMAC OPIE One-time pad Password system OTP One Time Pad OV Organisational Validation OV-SSL Organisational Validated Certificate P12 see PKCS#12 P7B see PKCS#7 PACE Password Authenticated Connection Establishment PAKE Password Authenticated Key Exchange PBE Password Based Encryption PBKDF2 Password Based Key Derivation Function PC Policy Constraints (certificate extension) PCBC Propagating Cipher Block Chaining PCFB Periodic Cipher Feedback Mode PCT Private Communications Transport PEM Privacy Enhanced Mail PES Proposed Encryption Standard PFS Perfect Forward Secrecy PFX see PKCS#12 (Personal Information Exchange) PGP Pretty Good Privacy PII Personally Identifiable Information PKCS Public Key Cryptography Standards PKCS1 PKCS #1: RSA Encryption Standard PKCS3 PKCS #3: RSA Encryption Standard on how to implement the Diffie-Hellman key exchange protocol PKCS5 PKCS #5: RSA Encryption Standard on how to derive cryptographic keys from a password PKCS6 PKCS #6: RSA Extended Certificate Syntax Standard PKCS7 PKCS #7: RSA Cryptographic Message Syntax Standard PKCS8 PKCS #8: RSA Private-Key Information Syntax Standard PKCS10 PKCS #10: Describes a standard syntax for certification requests PKCS11 PKCS #11: RSA Cryptographic Token Interface Standard (keys in hardware devices, cards) PKCS12 PKCS #12: RSA Personal Information Exchange Syntax Standard (public + private key stored in files) PKE Public Key Enablement PKI Public Key Infrastructure PKIX Internet Public Key Infrastructure Using X.509 PKP Public-Key-Pins PM Policy Mappings (certificate extension) PMAC Parallelizable MAC (by Phillip Rogaway) PMS pre-master secret Poly1305 Authenticator Poly1305-AES MAC (by D. Bernstein) POP Proof of Possession POODLE Padding Oracle On Downgraded Legacy Encryption PRF pseudo-random function PRNG pseudo-random number generator PSK Pre-shared Key PWKE Pair-Wise Key Establishment Schemes Using Discrete Logarithm Cryptography QUIC Quick UDP Internet Connection RA Registration Authority (aka Registration CA) Rabbit stream cipher algorithm RADIUS Remote Authentication Dial-In User Service Radix-64 alias for Base-64 RBG Random Bit Generator RC2 Rivest Cipher 2, block cipher by Ron Rivest (64-bit blocks) RC4 Rivest Cipher 4, stream cipher (aka Ron's Code) RC5 Rivest Cipher 5, block cipher (32-bit word) RC5-64 Rivest Cipher 5, block cipher (64-bit word) RC6 Rivest Cipher 6 RCSU Reuters' Compression Scheme for Unicode (aka SCSU) RFC Request for Comments Rijndael symmetric block cipher algorithm RIPEMD RACE Integrity Primitives Evaluation Message Digest RMAC Randomized MAC (block cipher authentication mode) RNG Random Number Generator ROT-13 see XOR ROBOT Return Of Bleichenbacher's Oracle Threat RTP Real-time Transport Protocol RSA Rivest Sharmir Adelman (public key cryptographic algorithm) RSS-14 Reduced Space Symbology, see GS1 RTN Routing transit number S/KEY One-time pad Password system SA Subordinate Authority (aka Subordinate CA) SACL System Access Control List SAFER Secure And Fast Encryption Routine, block cipher Salsa20 stream cipher (by D. Bernstein, 2005) Salsa20/8 see scrypt Salsa20/12 see Salsa20 Salsa20/20 see Salsa20 SAM syriac abbreviation mark SAN Subject Alternate Name Sarmal hash function SAX Symmetric Authenticated eXchange SCA Selfsigned CA signature SBCS single-byte character set SCEP Simple Certificate Enrollment Protocol scrypt password based key derivation function (Colin Percival) SCSU Standard Compression Scheme for Unicode (compressed UTF-16) SCSV Signaling Cipher Suite Value SCVP Server-Based Certificate Validation Protocol SCT Signed Certificate Timestamp SDES Security Description Protokol SEED 128-bit Symmetric Block Cipher Serpent symmetric key block cipher (128 bit) SGC Server-Gated Cryptography SGCM Sophie Germain Counter Mode (block cipher mode) SHA Secure Hash Algorithm SHA-0 Secure Hash Algorithm (insecure version before 1995) SHA-1 Secure Hash Algorithm (since 1995) SHA-2 Secure Hash Algorithm (since 2002) SHA-3 Secure Hash Algorithm (since 2015), see Keccak also SHA-224 Secure Hash Algorithm (224 bit) SHA-256 Secure Hash Algorithm (256 bit) SHA-384 Secure Hash Algorithm (384 bit) SHA-512 Secure Hash Algorithm (512 bit) SHA1 see for SHA-1 (160 bit) SHA2 see for SHA-2 (224, 256, 384 or 512 bit) SHA3 see for SHA-3 (224, 256, 384 or 512 bit) SHA3-224 Secure Hash Algorithm (224 bit) SHA3-256 Secure Hash Algorithm (256 bit) SHA3-384 Secure Hash Algorithm (384 bit) SHA3-512 Secure Hash Algorithm (512 bit) SHAKE128 Secure Hash Algorithm (variable bit) SHAKE256 Secure Hash Algorithm (variable bit) SHAvite-3 hash function (Eli Biham, Orr Dunkelman, 2009) SPHINCS post-quantum hash function SPHINCS-256 alias for SPHINCS SWIFFT hash function (Vadim Lyubashevsky, Daniele Micciancio, Chris Peikert, Alon Rosen, 2008) SWIFFTX see SWIFFT SHS Secure Hash Standard SIA Subject Information Access (certificate extension) SIC Segmented Integer Counter (alias for CTR) Skein hash function (Niels Ferguson, Stefan Lucks, Bruce Schneier, Doug Whiting, Mihir Bellare, Tadayoshi Kohno, Jon Callas, Jesse Walker, 2010) SKID subject key ID (certificate extension) SKIP Message Skipping Attacks on TLS SKIP-TLS see SKIP Skipjack block cipher encryption algorithm specified as part of the Fortezza SLOTH Security Losses from Obsolete and Truncated Transcript Hashes SMACK State Machine AttaCKs Snefu hash function SNI Server Name Indication SNOW word-based synchronous stream ciphers (by Thomas Johansson and Patrik Ekdahl ) Snuffle 2005 see Salsa20 Snuffle 2008 see ChaCha SPDY Google's application-layer protocol on top of SSL SPKI Subject Public Key Infrastructure SPN Substitution-Permutation Network Square block cipher SRI Subresource Integrity SRP Secure Remote Password protocol SRTP Secure RTP SSCD Secure Signature Creation Device SSEE Sichere Signaturerstellungseinheit (same as SSCD) SSL Secure Sockets Layer SSLv2 Secure Sockets Layer Version 2 SSLv3 Secure Sockets Layer Version 3 SSP Security Support Provider SSPI Security Support Provider Interface SST Serialized Certificate Store format SCT Signed Certificate Timestamp STS Strict Transport Security STS Station-to-Station protocol Sweet32 Sweet32: Birthday attacks on 64-bit block ciphers in TLS and OpenVPN TA Trust Agent TACK Trust Assertions for Certificate Keys TCB Trusted Computing Base TDEA Tripple DEA TEA Tiny Encryption Algorithm TEK Traffic Encryption Key Tiger hash function TIME Timing Info-leak Made Easy (Exploit SSL/TLS) TIME A Perfect CRIME? TIME Will Tell Threefish hash function TLS Transport Layer Security TLSA TLS Trust Anchors TLSv1 Transport Layer Security version 1 TLSA RR TLSA resource Record TMAC Two-Key CMAC, variant of CBC-MAC TOCTOU Time-of-check, time-of-use TOFU Trust on First Use TR-02102 Technische Richtlinie 02102 (des BSI) TR-03116 Technische Richtlinie 03116 (des BSI) TSK Transmission Security Key TSK TACK signing key TSP trust-Management Service Provider TSS Time Stamp Service TTP trusted Third Party Twofish symmetric key block cipher (128 bit) UC Unified Capabilities UC Unified Communications (SSL Certificate using SAN) UCC Unified Communications Certificate (rarley used) UMAC Universal hashing MAC; optimized for 32-bit architectures URI Uniform Resource Identifier URL Uniform Resource Locator VMAC Universal hashing MAC; 64-bit variant of UMAC (by Ted Krovetz and Wei Dai) VMPC stream cipher WHIRLPOOL hash function X.680 X.680: ASN.1 X.509 X.509: The Directory - Authentication Framework X25519 alias for Curve25519 ? X680 X.680: ASN.1 X509 X.509: The Directory - Authentication Framework XCBC eXtended CBC-MAC XCBC-MAC same as XCBC XEX XOR Encrypt XOR XKMS XML Key Management Specification XMACC counter-based XOR-MAC XMACR radomized XOR-MAC XMLSIG XML-Signature Syntax and Processing XMSS hash function XSalsa2 variant of Salsa20 XTEA extended Tiny Encryption Algorithm XTS XEX-based tweaked-codebook mode with ciphertext stealing XUDA Xcert Universal Database API XXTEA enhanced/corrected Tiny Encryption Algorithm ZLIB Lossless compression file format ZRTP SRTP for VoIP ZSK Zone Signing Key (DNSSEC) O-Saft-19.01.19/OSaft/Doc/Links.pm000077500000000000000000000144251342117255600162230ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!# This software is licensed under GPLv2. Please see o-saft.pl for details. ## no critic qw(Documentation::RequirePodSections) # our POD below is fine, perlcritic (severity 2) is too pedantic here. package OSaft::Doc::Links; use strict; use warnings; my $VERSION = "17.10.17"; # official verion number of tis file my $SID = "@(#) Links.pm 1.6 18/01/13 21:50:21"; print STDERR "**WARNING: OSaft::Doc::Links obsolete since O-Saft version 18.01.18"; #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME OSaft::Doc::Links - common perl module to define links related to SSL/TLS. =head1 SYNOPSIS use OSaft::Doc::Links; =head1 METHODS =head2 get() Return all data. =cut #_____________________________________________________________________________ #__________________________________________________________________ methods __| sub get { return ; } sub print_as_text { print ; return; } sub o_saft_links_done() {}; # dummy to check successful include ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| print_as_text() if (! defined caller); 1; # All documentation is in plain ASCII format. # It's designed for human radability and simple editing. # Syntax is: # each line consist of a KEY and a TEXT # KEY and a TEXT are separated by TAB (aka \09 aka 0x09) # To support duplicate keys, for example because they have different TEXTs, # some keys may hav added whitespaces on right. __DATA__ OWASP TLS Cheat Sheet https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet OWASP Certificate and Public Key Pinning https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning OWASP HTTP Strict Transport Security https://www.owasp.org/index.php/HTTP_Strict_Transport_Security BSI TR-02102 Teil 2 https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR02102/BSI-TR-02102-2.pdf ENISA: Algorithms, Key Sizes and Parameters Report http://www.enisa.europa.eu/activities/identity-and-trust/library/deliverables/algorithms-key-sizes-and-parameters-report EV Certificate Guidelines https://www.cabforum.org/EV_Certificate_Guidelines.pdf AIA http://www.startssl.com/certs/sub.class4.server.ca.crt ALPN (draft) http://tools.ietf.org/html/draft-friedl-tls-applayerprotoneg-02 ALPN https://www.imperialviolet.org/2013/03/20/alpn.html CDP http://www.startssl.com/crt4-crl.crl, http://crl.startssl.com/crt4-crl.crl CT http://ctwatch.net/ False Start https://www.imperialviolet.org/2012/04/11/falsestart.html False Start https://technotes.googlecode.com/git/falsestart.html HPKP https://timtaubert.de/blog/2014/10/http-public-key-pinning-explained/ HPKP https://blog.pregos.info/2015/02/23/http-public-key-pinning-hpkp-erklaerung-und-einrichtung/ HPKP https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead HPKP in Chrome hrome://net-internals/#hsts (show, reset pins in Chrome) HSTS http://tools.ietf.org/html/draft-hodges-strict-transport-sec-02 NPN (draft) https://tools.ietf.org/id/draft-agl-tls-nextprotoneg-04.html NPN https://technotes.googlecode.com/git/nextprotoneg.html NPN https://www.imperialviolet.org/2013/03/20/alpn.html OCSP http://ocsp.startssl.com/sub/class4/server/ca OCSP Stapling http://en.wikipedia.org/wiki/OCSP_stapling PFS http://en.wikipedia.org/wiki/Perfect_forward_secrecy Resumtion https://www.imperialviolet.org/2011/11/22/forwardsecret.html Resumtion https://www.imperialviolet.org/2013/06/27/botchingpfs.html SCSV https://datatracker.ietf.org/doc/draft-bmoeller-tls-downgrade-scsv/?include_text=1 Server Pinning https://tools.ietf.org/id/draft-sheffer-tls-pinning-ticket-02.txt SNI apache https://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI SPDY/3 http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3 SPDY Protocol http://www.chromium.org/spdy/spdy-protocol SRI Subresource Integrity: https://www.w3.org/TR/SRI/ 4/2016 SRI (Mozilla) https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity TACK http://tack.io/draft.html, 2013 Moxie Marlinspike, Trevor Perrin Elliptic Curve https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations#Supported_elliptic_curves Elliptic Curve for IPsec https://www.researchgate.net/profile/Johannes_Merkle/publication/260050106_Standardisierung_der_Brainpool-Kurven_fur_TLS_und_IPSec/links/00b7d52f36a0cc2fdd000000.pdf Elliptic Curve http://datatracker.ietf.org/doc/draft-mcgrew-tls-aes-ccm-ecc/ Elliptic Curve http://datatracker.ietf.org/doc/draft-merkle-tls-brainpool/ Elliptic Curve http://datatracker.ietf.org/doc/draft-merkle-ikev2-ke-brainpool/ Elliptic Curve http://datatracker.ietf.org/doc/draft-sheffer-ipsecme-dh-checks/ Elliptic Curve https://tools.ietf.org/html/draft-josefsson-tls-curve25519-06 Elliptic Curve http://eprint.iacr.org/2007/286 Elliptic Curve http://www.teletrust.de/fileadmin/files/oid/ecgdsa_final.pdf Elliptic Curve https://datatracker.ietf.org/doc/draft-harkins-ikev3/ XMSS https://eprint.iacr.org/2011/484.pdf BEAST ? BREACH http://www.breachattack.com/ CRIME http://zoompf.com/2012/09/explaining-the-crime-weakness-in-spdy-and-ssl DROWN https://drownattack.com/ FREAK https://freakattack.com/ FREAK https://mitls.org/pages/attacks/SMACK#freak Lucky 13 ? LogJam https://weakdh.org/ POODLE https://www.openssl.org/~bodo/ssl-poodle.pdf ROBOT https://robotattack.org/ SLOTH ? SKIP https://mitls.org/pages/attacks/SMACK SMACK https://mitls.org/pages/attacks/SMACK Sweet32 https://sweet32.info/ TIME ? # TS 102 042 : http:// # # http://rsapss.hboeck.de/rsapss-1.0.1.pdf # https://www.bsi.bund.de/DE/Themen/weitereThemen/SINA/sina_node.html # http://datatracker.ietf.org/doc/draft-eastlake-additional-xmlsec-uris/ # Firefox Add-ons # https://calomel.org/firefox_ssl_validation.htm Calomel SSL Validation # https://addons.mozilla.org/de/firefox/addon/cert-viewer-plus/ Cert Viewer Plus # # http://patrol.psyced.org/ Certifiate Patrol # certwatch.simos.info CertWatch # O-Saft-19.01.19/OSaft/Doc/Rfc.pm000077500000000000000000000222551342117255600156550ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!# This software is licensed under GPLv2. Please see o-saft.pl for details. ## no critic qw(Documentation::RequirePodSections) # our POD below is fine, perlcritic (severity 2) is too pedantic here. package OSaft::Doc::Rfc; use strict; use warnings; my $VERSION = "17.10.17"; # official verion number of tis file my $SID = "@(#) Rfc.pm 1.6 18/01/13 21:53:23"; print STDERR "**WARNING: OSaft::Doc::Rfc obsolete since O-Saft version 18.01.18"; #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME OSaft::Doc::Rfc - common perl module to define RFC (number and title) related to SSL/TLS. =head1 SYNOPSIS use OSaft::Doc::Rfc; =head1 METHODS =head2 get() Return all data. =cut #_____________________________________________________________________________ #__________________________________________________________________ methods __| sub get { return ; } sub print_as_text { print ; return; } sub o_saft_rfc_done() {}; # dummy to check successful include ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| print_as_text() if (! defined caller); 1; # All documentation following __DATA__ is in plain ASCII format. # It's designed for human radability and simple editing. # Syntax is: # each line consist of a KEY and a TEXT # KEY and a TEXT are separated by TAB (aka \09 aka 0x09) # First line contains base URL to find RFC. # number | title / description #----------+----------------------------------------+-----------------------+ # zu RFC 2412: # alle *DH* sind im Prinzip PFS. # wird manchmal zusaetzlich mit DHE bezeichnet, wobei E für ephemeral # also flüchtige, vergängliche Schlüssel steht # D.H. ECDHE_* und DHE_* an den Anfang der Cipherliste stellen, z.B. # TLS_ECDHE_RSA_WITH_RC4_128_SHA # TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA # TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA # TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA # zu RFC 4366 # AKID - authority key identifier # Server name Indication (SNI): server_name # Maximum Fragment Length Negotiation: max_fragment_length # Client Certificate URLs: client_certificate_url # Trusted CA Indication: trusted_ca_keys # Truncated HMAC: truncated_hmac # Certificate Status Request (i.e. OCSP stapling): status_request # Error Alerts # zu RFC 6066 # PkiPath # Truncated CA keys (value 3) # Truncated HMAC (value 4) # (Certificate) Status Request (value 5) # OCSP stapling mechanism # zu RFC 6125 # Representation and Verification of Domain-Based Application Service # Identity within Internet Public Key Infrastructure Using X.509 (PKIX) # Certificates in the Context of Transport Layer Security (TLS) __DATA__ # url base URL for RFC descriptions # http://tools.ietf.org/html/rfcXXXX # http://tools.ietf.org/rfc/rfcXXXX.txt url http://tools.ietf.org/ 6167 Prohibiting Secure Sockets Layer (SSL) Version 2.0 6101 SSL Version 3.0 2246 TLS Version 1.0 (with Cipher Suites) 4346 TLS Version 1.1 (with Cipher Suites) 5246 TLS Version 1.2 (with Cipher Suites) 4347 DTLS Version 0.9 6347 DTLS Version 1.2 2616 Hypertext Transfer Protocol Version 1 (HTTP/1.1) 7540 Hypertext Transfer Protocol Version 2 (HTTP/2) 7230 HTTP/1.1: Message Syntax and Routing 7231 HTTP/1.1: Semantics and Content 7232 HTTP/1.1: Conditional Requests 7233 HTTP/1.1: Range Requests 7234 HTTP/1.1: Caching 7235 HTTP/1.1: Authentication 3490 Internationalizing Domain Names in Applications (IDNA) 3987 Internationalized Resource Identifiers (IRIs) 4518 Internationalized String Preparation in LDAP 3986 Uniform Resource Identifier (URI): Generic Syntax 2104 HMAC: Keyed-Hashing for Message Authentication 2405 The ESP DES-CBC Cipher Algorithm With Explicit IV 2406 IP Encapsulating Security Payload (ESP) 2407 The Internet IP Security Domain of Interpretation for ISAKMP 2408 Internet Security Association and Key Management Protocol (ISAKMP) 2409 The Internet Key Exchange (IKE) - 1998 4306 The Internet Key Exchange (IKEv2) Protocol - 2005 7296 The Internet Key Exchange Protocol 2 (IKEv2) - 2014 4753 ECP Groups for IKE and IKEv2 2412 AKLEY Key Determination Protocol (PFS - Perfect Forward Secrec) 2818 HTTP Over TLS 2945 SRP Authentication & Key Exchange System 2986 PKCS#10 5967 PKCS#10 5081 TLSPGP: Using OpenPGP Keys for Transport Layer Security (TLS) Authentication 4309 AES-CCM Mode with IPsec Encapsulating Security Payload (ESP) 5116 An Interface and Algorithms for Authenticated Encryption (AEAD) 3749 TLS Compression Method 3943 TLS Protocol Compression Using Lempel-Ziv-Stac (LZS) 3546 TLS Extensions (obsolete) 4366 TLS Extensions 4868 Using HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 with IPsec 5116 An Interface and Algorithms for Authenticated Encryption 4749 TLS Compression Methods 5077 TLS session resumption without Server-Side State 5746 TLS Extension: Renegotiation Indication Extension 5764 TLS Extension: SRTP 5929 TLS Extension: Channel Bindings 6066 TLS Extension: Extension Definitions 7301 TLS Extension: Application-Layer Protocol Negotiation (ALPN) 7633 TLS Extension: Feature Extension: Must Staple 6176 Prohibiting Secure Sockets Layer (SSL) Version 2.0 3711 The Secure Real-time Transport Protocol (SRTP) 6189 ZRTP: Media Path Key Agreement for Unicast Secure RTP 6520 TLS Extensions: Heartbeat 6961 TLS Multiple Certificate Status Request Extension 7627 TLS Session Hash and Extended Master Secret Extension 6460 NSA Suite B Profile for TLS 2560 Online Certificate Status Protocol (OCSP, obsolete) 6267 Online Certificate Status Protocol Algorithm Agility (OCSP, obsolete) 4210 X509 PKI Certificate Management Protocol (CMP) 3279 x509 Algorithms and Identifiers for X.509 PKI and CRL Profile 3739 x509 PKI Qualified Certificates Profile; EU Directive 1999/93/EC 3280 X509 PKI Certificate and Certificate Revocation List (CRL) Profile (obsolete) 4158 X509 PKI Certification Path Building 4387 X509 PKI Operational Protocols: Certificate Store Access via HTTP 5280 X509 PKI Certificate and Certificate Revocation List (CRL) Profile 6960 X509 Online Certificate Status Protocol (OCSP) 2712 TLSKRB: Addition of Kerberos Cipher Suites to TLS 3268 TLSAES: Advanced Encryption Standard (AES) Cipher Suites for TLS 4132 Addition of Camellia Cipher Suites to TLS 4162 Addition of SEED Cipher Suites to TLS 4279 TLSPSK: Pre-Shared Key Ciphersuites for TLS 4357 Additional Cryptographic Algorithms for Use with GOST 28147-89, GOST R 34.10-94, GOST R 34.10-2001, and GOST R 34.11-94 Algorithms 4491 Using the GOST Algorithms with X509 (GOST R 34.10-94, GOST R 34.10-2001, GOST R 34.11-94) 4492 TLSECC: Elliptic Curve Cryptography (ECC) Cipher Suites for TLS 4785 Pre-Shared Key (PSK) Cipher Suites with NULL Encryption for TLS 5054 Secure Remote Password (SRP) Protocol for TLS Authentication 5114 Additional Diffie-Hellman Groups for Use with IETF Standards 5288 AES Galois Counter Mode (GCM) Cipher Suites for TLS 5289 TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode (GCM) 5430 Suite B Profile for TLS 5487 Pre-Shared Key Cipher Suites for TLS with SHA-256/384 and AES Galois Counter Mode 5489 ECDHE_PSK Cipher Suites for TLS 5589 Session Initiation Protocol (SIP) Call Control - Transfer 5639 Elliptic Curve Cryptography (ECC) Brainpool Standard Curves and Curve Generation 5903 Elliptic Curve Groups modulo a Prime (ECP Groups) for IKE and IKEv2 7027 Elliptic Curve Cryptography (ECC) Brainpool Curves for TLS 7748 Elliptic Curve for Security 5741 RFC Streams, Headers, and Boilerplates 5794 Description of the ARIA Encryption Algorithm 5932 Camellia Cipher Suites for TLS 6209 Addition of the ARIA Cipher Suites to TLS 6367 Addition of the Camellia Cipher Suites to TLS 6655 AES-CCM Cipher Suites for TLS 7251 AES-CCM Elliptic Curve Cryptography (ECC) Cipher Suites for TLS 7507 TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks 5055 Server-Based Certificate Validation Protocol (SCVP) 5019 simplified RFC 2560 5705 Keying Material Exporters for TLS 6125 Representation and Verification of Domain-Based Application Service (PKIX) for TLS 6797 HTTP Strict Transport Security (HSTS) 6962 Certificate Transparency 7366 Encrypt-then-MAC for TLS and DTLS 7457 Summarizing Known Attacks on TLS and DTLS 7469 Public Key Pinning Extension for HTTP 7525 Recommendations for Secure Use of TLS and DTLS 7539 ChaCha20 and Poly1305 for IETF Protocols 7627 TLS Session Hash and Extended Master Secret Extension 7905 ChaCha20-Poly1305 Cipher Suites for TLS 1135 The Helminthiasis of the Internet 6698 DNS-Based Authentication of Named Entities (DANE) 6844 DNS Certification Authority Authorization (CAA) Resource Record O-Saft-19.01.19/OSaft/Doc/coding.txt000066400000000000000000000427031342117255600166060ustar00rootroot00000000000000 # Description about Program Code and Documentation # It is not shown with +help but can be retrieved with: $0 --help=ProgramCode HACKER's INFO Program Code First of all: the main goal is to have a tool to be simple for users. It's not designed to be academic code or simple for programmers. Also testing for various flaws in other tools and protocols could not be done in a standardized generic way, using well designed software, but often needs highly adapted code for each individual check, and -- more worse -- sometimes variants of the same code. Please keep this in mind, before trying to unitise the code. Note: following descriptions mainly uses the term "sub" (the perlish term) when talking about functions, procedures, and/or methods. Syntax style Identation is 4 spaces. TABs would be the better solution, IMHO. Unfortunately some repositories have issues with TABs, so spaces are used only. Sick. Additional spacing is used to format the code for better human reada- bility. There is no strict rule about this, it's just done as needed. Empty lines (empty, without any space!) are used to group code blocks logically. However, there is no strict rule about this too. K&R-style curly brackets for subs and conditions are used. K&R-style round brackets for subs and conditions are used (means that definitions of subs, and calls of subs do not use spaces before the opening bracket, while conditions use spaces). Calls of subs are written in K&R-style using round brackets, and the perlisch way without round brackets. This may be unitised in future. Main exception is print, which is used without brackets. Short subs and conditions may be written in just one line. Note: there is no need for each command in its one line, as debugging on code level is rarely done. subs are defined with number and type of parameters to have a minimal syntax check at compile time. This will be changed in future. The code mainly uses 'text enclosed in single quotes' for program internal strings such as hash keys. It uses "double quoted text" for texts being printed. However, exceptions if obviously necessary ;-) Strings used for RegEx are always enclosed in single quotes. Reason is mainly to make searching texts a bit easier. Code style Global variables are used, see X&Variables& for details below. Variables are declared at beginning of subs. I.g. we do not use local or my declarations in blocks (there may be some exceptions). The code tries to avoid if-else constructs as much as possible. If an else condition is used, it is written in one line: } else { . elsif is used in "borrowed" code only ;-) Early return statements in subs are prefered, rather than complicated and nested conditions. There are also goto statements in parsers, but return statements are prefered. Most code is seqential instead of using functions, except the code is used multiple times. This may be changed in future ... It is not intended to have OO-code, even perl's OO capabilities are used when rational. Code quality The code is regulary analysed using "perlcritic" -a front-end command line tool to the Perl::Critic module. As decribed above, this code is not supposed to be academically correct. Nevertheless, we follow the recommendations given by perlcritic to make the most of it. For details please see: * Annotations at end of o-saft.pl * .perlcriticrc * contrib/critic.sh . General Exceptions are not used, there is no need for them. In general, the code *must not* use any additional libraries. We know that there exist infinite marvellous libraries and frameworks (called modules in perl), which would make some programming simpler, but one of the main goals of this tool is that it should work on any system with just the core language (i.e. perl) installed. We do not want any additional dependency, in particular no dependency on versions beside the core language. Currently some perl modules are an exception, and will be removed in future. However, libraries part of perl5 are assumed to be "core language". Perl's 'die()' is used whenever an unrecoverable error occurs. The message printed will always start with '**ERROR: '. warnings are printed using perl's 'warn()' function and the message always starts with '**WARNING: '. All output is written to STDOUT. However perl's 'die()' and 'warn()' write on STDERR. Only debug messages inside $0 are written to STDERR. All 'print*()' functions write to STDOUT directly. They are slightly prepared for using texts from the configuration (%cfg, %checks), so these texts can be adapted easily (either with OPTIONS or in code). Calling external programs uses 'qx()' rather than backticks or perl's 'system()' function. Also note that it uses round brackets insted of slashes to avoid confusion with RegEx. The code flow often uses postfix conditions, means the if-conditions are written right of the command to be executed. This is done to make the code better readable (not disturbed by conditions). The code is most likely not thread-safe. Anyway, we don't use them. For debugging the code, the --trace option can be used. See DEBUG section below for more details. Be prepared for a lot of output! LHS condition checks It's a common (human) error to write assignments where conditions are required, in paricular in if(), while() and until() statements. To avoid such unintended statements, which often happen when changing the code, the conditions are written with the constant LHS and the variable RHS, for example: if (0 < $var) { print "$var > 0"; } This works with constants (integers, strings) and variables only, but not when matching RegEx (probably with perl 6.x). Comments Following comments are used in the code: # TODO: Parts not working perfect, needs to be changed. # FIXME: Program code known to be buggy, needs to be fixed. # NOTE: Special brief descriptions #!# Comments not to be removed in compressed code. #? Description of sub. #| Code sections (documents program flow). ## Comments used by third-party programs (for example: contrib/gen_standalone.sh, perlcritic). # func name of sub behind the closing bracket of sub Comments usually precede the code line(s) or are placed at end of the code line which they belong too. If the comments are placed after the code line which they belong too, the lines are idented. Annotations To reduce the huge amount of comments, and to write them only once if needed multiple times, an annotation section have been added at the end of $0 file. In this section a title for the comment is followed by the comment's text. Example: == Note:A Title Text for comment. Such comments are refered to in the code by: SEE Note:A Title This is experimental, to see if it helps to make the control flow of code more readable by humans, but keep the full documentation. Modules I.g. using modules, Perl modules and private ones, should be avoided. Unfortunately maintaining huge code without proper modularization is difficult. Hence Perl modules are reduced to a minimum needs, and all private modules are loaded when needed only. All private modules are in the sub-directory OSaft. The name O-Saft is prefered, but the - (dash) in the name is not possible in Perl's module names. Sick. Some modules are still in the main directory. This will change soon. While Net::SSLinfo uses Net::SSLeay(1), $0 itself uses only IO::Socket::SSL(1). This is done 'cause we need some special features there. However, IO::Socket::SSL(1) uses Net::SSLeay(1) anyways. Variables As explained above, global variables are used to avoid definitions of complex subs with various parameters. Most subs use global variables (even if they are defined in main with 'my'). These variables are mainly: @DATA, @results, %cmd, %data, %cfg, %checks, %ciphers, %prot, %text. Variables defined with 'our' can be used in o-saft-dbx.pm and o-saft-usr.pm. For a detailed description of the used variables, please refer to the text starting at the line '#!# set defaults' in o-saft.pl. Function names Some rules used for sub names: check* Functions which perform some checks on data. print* Functions which print results. get_* Functions to get values from internal data structure. _ Some kind of helper (internal) function. _trace* _y* Print information when --trace is in use. _v*print Print information when --v is in use. Function (sub) definitions are followed by a short description, which is just one line right after the 'sub' line. Such lines always start with '#?' (see below how to get an overview). Subs are ordered to avoid forward declarations as much as possible. Code information Examples to get an overview of perl functions (sub): egrep '^(sub|\s*#\?)' $0 Same a little bit formatted, see +traceSUB command. Examples to get an overview of programs workflow: egrep '(^#\|\s|\s\susr_)' $0 Following to get perl's variables for checks: $0 +check localhost --trace-key \ | awk -F'#' '($2~/^ /){a=$2;gsub(" ","",a);next}(NF>1){printf"%s{%s}\n",a,$2}' \ | tr '%' '$' Debugging, Tracing Most functionality for trace, debug or verbose output is encapsulated in functions (see X&Function names& above). These subs are defined as empty stubs in $0. The real definitions are in o-saft-dbx.pm, which is loaded on demand when any --trace* or --v option is used. As long as these options are not used, $0 works without o-saft-dbx.pm. Debug messages always start with '#dbx#'. verbose messages always start with '#o-saft.pl: '. Trace messages always start with '#o-saft.pl::'. Following formats are used in trace messages: #o-saft.pl:: some data - output from $0's main #o-saft.pl::subfunc(){ - inital output in subfunc #o-saft.pl::subfunc: some data - some output in subfunc #o-saft.pl::subfunc() = result } - result output of subfunc However, these rules are implemented very lazy. The prefix for verbose and trace message can be configured like: $0 --cfg-init=prefix_verbose="#VERBOSE: " $0 --cfg-init=prefix_trace="#my-trace:: " When --trace is used, additional trace output with timestamps are are also printed,even if no --trace-time was given. This is useful because it automatically "scopes" other output with '{' and '}'. Note: in contrast to the name of the RC-FILE, the name o-saft-dbx.pm is hard-coded. Abstract program flow check special options and command (+exec, +cgi, --envlibvar) read RC-FILE, DEBUG-FILE and USER-FILE if necessary initialize internal data structure scan options and arguments perform commands without connection to target loop over all specified targets print DNS stuff open connction and retrive information print ciphers print protocols print information print checks Arguments (+commands and --options) As described multiple times, it should be possible to mix options and commands and other arguments in any order. It is also possible to use various formats of commands and options. A simple method to allow variants of a string (command or option) is to match it against RegEx. Unfortunately it is hard to use a generic way to parse commands and options. perl's Getopt module would be nice but requires a hash with fixed keys. Using a hash, which conatins a proper RegEx for each command and option, could be done, but the code for such a sophisticated parser may be hard to understand. So a loop over all arguments with a huge "switch" statment is implemented. Each "switch-case" matches a RegEx, and then assign a proper value in the configuration. See the "#{ COMMANDS" and "#{ OPTIONS" sections in $0 . Program flow As explained in the documentation (please see +help) there are mainly 3 types of `checks': +info - getting as much information as possible about the target its certificate and the connection +cipher - checking for supported ciphers by the target +check - doing all the checks based on +info and +cipher Any information is collected using Net::SSLinfo and stored in %data. All information according ciphers is collected directly and stored in @results. Finally, when performing the checks, these informations are used and compared to expected well know values. The results of these checks are stored in %checks. Then all information from %data and %checks is printed by just loop- ing through these hashes. Information is just collected using Net::SSLinfo and then printed. Checks are performed on provided data by Net::SSLinfo and specified conditions herein. Most checks are done in functions 'check*', see above. Some checks depend on other checks, so check functions may be called anywhere to solve dependencies. To avoid multiple checks, each check function sets and checks a flag if already called, see $cfg{'done'}. Documentation All documentation of code details is close to the corresponding code lines. Some special comment lines are used, see X&Comments& above. Note: comments describe *why* the code is written in some way (means the logic of the code), and not *what* the code does (which is most likely obvious). All documentation for the user is written in plain ASCII text format, see *.txt files in OSaft/Doc/ . All documentation was initially written in perl's POD format. After 2 years of development, it seems that POD was not the best decision, as it makes extracting information from documentation complicated, some- times. Using POD is also a huge performance penulty on all platforms. POD will now be genereated on request using --help=pod option. Repository All code is maintained in a repository. Due to various conceptual and personal opinions, the master repository used internally is based on SCCS/CSSC, while the public repository is git/github. The maintainer keeps both in sync. The public repository must contain workable code only, well nobody is perfect ... Rules * Each file has at least one string containing the unuique id of the file version in the repository. This id is named SID or SID_. This string looks like: filename ID_in_repository date_of_last_change time_of_last_change example: filename 1.42 18/10/23 23:42:23 If this is assigned to a variable, it may look like: my $SID = "coding.txt 1.4 18/11/11 18:12:37"; (Note beside: previous example is the SID of this file) Exceptions: some files for documentation only miss the SID string. * Changes are made in very small chunks, each commited separately to the repository. * Different types of changes see Commit Comments below) must not be mixed in one commit. Commit Comments * Since 11/2018 all comments are prefixed with a 2-letter code, which describes the type of the committed change. The types are: Bd: - bugfix in internal (developer) documentation BD: - bugfix in public/user documentation BT: - bugfix in core SSL/TLS check or test functionality BF: - bugfix in general functionality or feature ED: - enhancement/improvement in documentation ET: - enhancement/improvement in core SSL/TLS checks or tests EF: - enhancement/improvement in general functionality or feature ND: - new documentation NT: - new core SSL/TLS check or test functionality NF: - new general functionality or feature Lower case b instead of B means that the bug was introduced in a recent change. O-Saft-19.01.19/OSaft/Doc/glossary.txt000066400000000000000000000604351342117255600172100ustar00rootroot00000000000000 # SID @(#) glossary.txt 1.13 19/01/11 00:04:14 # acronym | description #------+----------------------------------------------------------------------+ 0-RTT zero Round-Trip Time AA Attribute Authority AAD Additional Authenticated Data ACME Automated Certificate Management Environment ACL Access Control List Adiantum ChaCha stream cipher with Poly1305 and XChaCha12 ADH Anonymous Diffie-Hellman Adler32 hash function AE Authenticated Encryption AEAD Authenticated Encryption with Additional Data AECDHE Anonymous Ephemeral ECDH AEM Authenticated Encryption Mode aka Advanced Encryption Mode aka OCB3 AES Advanced Encryption Standard AES-XTS ? AIA Authority Information Access (certificate extension) AKC Agreement with Key Confirmation AKID Authority Key IDentifier ALPN Application Layer Protocol Negotiation AMASTRID stream cipher algorithm ARC4 Alleged RC4 (see RC4) ARCFOUR alias for ARC4 ARIA 128-bit Symmetric block cipher ARX add–rotate–xor ASN Autonomous System Number ASN.1 Abstract Syntax Notation number One AtE Authenticate-then-Encrypt (see also MtE) BACPA Blockwise-Adaptive Chosen-Plaintext Attack BADA55 "locate weak cryptography somewhere", Bernstein, Lange, et al. BADA55-VPR-224 improved verifiably pseudorandom 224-bit curve BADA55-VR-224 curve useng the same prime as NIST P-224 BADA55-VR-256 curve useng the same prime as NIST P-256 BADA55-VR-384 curve useng the same prime as NIST P-384 bcrypt hash function (Niels Provos, David Mazières, 1999) BLAKE hash function (Jean-Philippe Aumasson, Luca Henzen, Willi Meier, Raphael C.-W. Phan, 2008) BLAKE2 fast secure hashing function (2012) BLAKE2b see BLAKE (32 bit) BLAKE-32 see BLAKE (32 bit) BLAKE-64 see BLAKE (64 bit) BLAKE-224 see BLAKE (224 bit) BLAKE-256 see BLAKE (256 bit) BLAKE-384 see BLAKE (384 bit) BLAKE-512 see BLAKE (512 bit) BEAR block cipher combining stream cipher and hash function BDH Bilinear Diffie-Hellman BEAST Browser Exploit Against SSL/TLS BEAST . fast block cipher for arbitrary blocksizes BER Basic Encoding Rules BGP Boorder Gateway Protocol Blowfish symmetric block cipher boomerang attack attack on BLAKE Brainpool signature algorithm, from BSI BREACH Browser Reconnaissance & Exfiltration via Adaptive Compression of Hypertext (a variant of CRIME) Bullrun NSA program to break encrypted communication CAMELLIA symmetric key block cipher; encryption algorithm 128 bit (by Mitsubishi and NTT) CAST-128 Carlisle Adams and Stafford Tavares, block cipher CAST5 alias for CAST-128 CAST-256 Carlisle Adams and Stafford Tavares, block cipher CAST6 alias for CAST-256 cipher suite cipher suite is a named combination of authentication, encryption, and message authentication code algorithms CA Certificate Authority (aka root CA) CAA Certificate Authority Authorization CAA RR CAA Resource Record CBC Cyclic Block Chaining CBC Cipher Block Chaining (sometimes) CBC Ciplier Block Chaining (sometimes) CBC-MAC Cipher Block Chaining - Message Authentication Code CBC-MAC-ELB Cipher Block Chaining - Message Authentication Code - Encrypt Last Block CCA chosen-ciphertext attack CCM CBC-MAC Mode (authenticated encryption block cipher mode) CCS Change Cipher Spec (protocol) CDH ? Diffie-Hellman CDP CRL Distribution Points CECPQ1 key-agreement algorithm; Combined elliptic Curve and Post-Quantum Cryptography Key Exchange CECPQ2 Combined elliptic Curve and Post-Quantum Cryptography Key Exchange CEK Content Encryption Key CFB Cipher Feedback CFB3 Cipher Feedback CFBx Cipher Feedback x bit mode CFRG Crypto Forum Research Group ChaCha stream cipher algorithm (with 256-bit key) ChaCha8 see ChaCha ChaCha12 see ChaCha (aka 12-round ChaCha) ChaCha20 see ChaCha (aka 20-round ChaCha) ChaCha-Poly1305 Authenticated Encryption with Associated Data (AEAD) CHAP Challenge Handshake Authentication Protocol CKA (PKCS#11) CKK (PKCS#11) CKM (PKCS#11) CMAC Cipher-based MAC CMC CBC-mask-CBC CMP X509 Certificate Management Protocol CMS Cryptographic Message Syntax CMVP Cryptographic Module Validation Program (NIST) CN Common Name CP Certificate Policy (certificate extension) CPA chosen-plaintext attack CPD Certificate Policy Definitions CPS Certification Practice Statement CRC Cyclic Redundancy Check CRC8 CRC with polynomial length 8 CRC16 CRC with polynomial length 16 CRC32 CRC with polynomial length 32 CRC64 CRC with polynomial length 64 CRAM Challenge Response Authentication Mechanism CRIME Compression Ratio Info-leak Made Easy (Exploit SSL/TLS) CRL Certificate Revocation List CRYPTREC Cryptography Research and Evaluation Committees CSP Certificate Service Provider CSP Cryptographic Service Provider CSP Critical Security Parameter (used in FIPS 140-2) CSP: Content Security Policy (used as HTTP header) CSR Certificate Signing Request CSPRNG Cryptographically Secure Pseudo-Random Number Generator CT Certificate Transparency CTL Certificate Trust Line CTR Counter Mode (sometimes: CM; block cipher mode) CTS Cipher Text Stealing Curve448 signature algorithm, aka Goldilocks (224 bit) Curve25519 signature algorithm by Dan J. Bernstein (ca. 128 bit) CWC CWC Mode (Carter-Wegman + CTR mode; block cipher mode) CyaSSL formerly name of wolfSSL DAA Data Authentication Algorithm DAC Data Authentication Code DACL Discretionary Access Control List DANE DNS-based Authentication of Named Entities DDH Decisional Diffie-Hellman (Problem) DEA Data Encryption Algorithm (sometimes a synonym for DES) DECIPHER synonym for decryption DEK Data Encryption Key DER Distinguished Encoding Rules DES Data Encryption Standard DESede alias for 3DES ?java only? DESX extended DES 3DES Tripple DES (168 bit) 3DES-EDE alias for 3DES 3TDEA Three-key Tripple DEA (sometimes: Tripple DES; 168 bit) 2TDEA Double-key Tripple DEA (sometimes: Double DES; 112 bit) D5 Verhoeff's Dihedral Group D5 Check DH Diffie-Hellman DHE Diffie-Hellman ephemeral (historic acronym, often used, mainly in openssl) DLIES Discrete Logarithm Integrated Encryption Scheme DLP Discrete Logarithm Problem DN Distinguished Name DNSSEC DNS Security Extension DPA Dynamic Passcode Authentication (see CAP) DRAGON stream cipher algorithm DRG Deterministic Random Generator DRBG Deterministic Random Bit Generator DROWN Decrypting RSA with Obsolete and Weakened eNcryption (Exploit SSL/TLS) DSA Digital Signature Algorithm DSCP Differentiated Services Code Point DSS Digital Signature Standard DTLS Datagram TLS DTLSv1 Datagram TLS 1.0 Dual EC DBRG Dual Elliptic Curve Deterministic Random Bit Generator (NIST) Dual_EC_DBRG Dual Elliptic Curve Deterministic Random Bit Generator (NIST) DV Domain Validation DV-SSL Domain Validated Certificate EAL Evaluation Assurance Level EAP Extensible Authentication Protocol EAP-PSK Extensible Authentication Protocol using a Pre-Shared Key EAX Encrypt-then-Authenticate-then-Translate EAX EAX Mode (block cipher mode) EAXprime alias for EAX Mode EBC Edge Boundery Controller EC Elliptic Curve ECB Electronic Code Book mode ECC Error Corection Code ECC Elliptic Curve Cryptography ECCSI Elliptic Curve-Based Certificateless Signatures for Identity-Based Encryption ECDH Elliptic Curve Diffie-Hellman ECDHE Ephemeral ECDH ECDLP Elliptic Curve Discrete Logarithm Problem ECDSA Elliptic Curve Digital Signature Algorithm ECDSA-256 Elliptic Curve Digital Signature Algorithm (256 bits) ECDSA-384 Elliptic Curve Digital Signature Algorithm (384 bits) ECDSA-521 Elliptic Curve Digital Signature Algorithm (521 bits) ECGDSA Elliptic Curve ??? DSA ECHO hash function (Ryad Benadjila, Olivier Billet, Henri Gilbert, Gilles Macario-Rat, Thomas Peyrin, Matt Robshaw, Yannick Seurin, 2010) ECIES Elliptic Curve Integrated Encryption Scheme ECKA Elliptic Curve Key Agreement ECKA-EG Elliptic Curve Key Agreement of ElGamal Type ECKDSA Elliptic Curve ??? DSA ECMQV Elliptic Curve Menezes-Qu-Vanstone ECN Explicit Congestion Notification ECOH Elliptic Curve only hash # ECRYPT ?? ECSVDP-DH Elliptic Curve Secret Value Derivation Primitive, Diffie-Hellman version Ed25519 alias for Curve25519 Ed448 alias for Curve448 edwards25519 alias for Curve25519 edwards448 alias for Curve448 EdDSA alias for signatures using public key and private key formats, like Curve448 and Curve25519 EDE Encryption-Decryption-Encryption EDH Ephemeral Diffie-Hellman EGADS Entropy Gathering and Distribution System EGD Entropy Gathering Daemon EKU Extended Key Usage ELB Encrypt Last Block ElGamal asymmetric block cipher ENCIPHER synonym for encryption EME ECB-mask-ECB EME Encoding Method for Encryption ESNI Encrypted Server Name Indication ESP Encapsulating Security Payload ESSIV Encrypted salt-sector initialization vector EtA Encrypt-then-Authenticate (see also EtM) E&A Encrypt-and-Authenticate (see also E&M) E&M Encrypt-and-MAC (see also E&A) EtM Encrypt-then-MAC (see also EtA) ETSI-TS European Telecommunications Standards Institute - Technical Specification EV Extended Validation EV-SSL Extended Validation Certificate FEAL Fast Data Encryption Algorithm FFC Finite Field Cryptography FFT Fast Fourier Transform FIPS Federal Information Processing Standard FIPS46-2 FIPS Data Encryption Standard (DES) FIPS73 FIPS Guidelines for Security of Computer Applications FIPS140-2 FIPS Security Requirements for Cryptographic Modules FIPS140-3 proposed revision of FIPS 140-2 FIPS180-3 FIPS Secure Hash Standard FIPS186-3 FIPS Digital Signature Standard (DSS) FIPS197 FIPS Advanced Encryption Standard (AES) FIPS198-1 FIPS The Keyed-Hash Message Authentication Code (HMAC) FREAK Factoring Attack on RSA-EXPORT Keys FQDN Fully-qualified Domain Name FSB Fast Syndrome Based Hash FSM Finite State Machine FZA FORTEZZA G-DES ??? DES GCM Galois/Counter Mode (authenticated encryption block cipher mode) GHASH Hash funtion used in GCM GMAC MAC for GCM Grøstl hash function (Lars Knudsen, 2010) Goldilocks see Curve448 GOST Gossudarstwenny Standard (block cipher) GOST hash function (used in GOST cipher suite) Grainv1 stream cipher (64-bit IV) Grainv128 stream cipher (96-bit IV) GREASE Generate Random Extensions And Sustain Extensibility GRØSTL256 hash function GRØSTL512 hash function GROESTL256 alias for GRØSTL256 GROESTL512 alias for GRØSTL512 HAIFA HAsh Iterative FrAmework hash127 fast hash function (by Dan Bernstein) HAVAL one-way hashing HAS-160 hash function HAS-V hash function HC128 alias for HC128 HC256 alias for HC256 HC-128 stream cipher algorithm HC-256 stream cipher algorithm HCH Hash-Coputer-Hash HCTR a variable-input-length encryption mode HEARTBLEED attack against TLS extension heartbeat HEIST HTTP Encrypted Information can be Stolen through TCP-windows HIBE hierarchical identity-based encryption HKDF HMAC-based Extract-and-Expand Key Derivation Function HNF-256 hash function (Harshvardhan Tiwari, Krishna Asawa, 2014) HMAC keyed-Hash Message Authentication Code (aka Hashed MAC) HMQV h? Menezes-Qu-Vanstone HPC Hasty Putting Cipher HPKP HTTP Public Key Pinning HPolyC ChaCha stream cipher with Poly1305 and XChaCha12, XChaCha20 HRSS encryption algorithm HSM Hardware Security Module HSR Header + Secret + Random HSTS HTTP Strict Transport Security HTOP HMAC-Based One-Time Password IAPM Integrity Aware Parallelizable Mode (block cipher mode of operation) IBE Identity-Based Encryption ICM Integer Counter Mode (alias for CTR) IDP Issuing Distribution Points IDEA International Data Encryption Algorithm (by James Massey and Xuejia Lai) IESG Internet Engineering Steering Group IETF Internet Engineering Task Force IFC Integer Factorization Cryptography IGE Infinite Garble Extension IKE Internet Key Exchange IKEv2 IKE version 2 IND-BACPA Indistinguishability of encryptions under blockwise-adaptive chosen-plaintext attack IND-CCA Indistinguishability of encryptions under chosen-cipgertext attack IND-CPA Indistinguishability of encryptions under chosen-plaintext attack INT-CTXT Integrity of ciphertext INT-PTXT Integrity of plaintext IRTF Internet Research Task Force ISAKMP Internet Security Association and Key Management Protocol IV Initialization Vector JH hash function (Hongjun Wu, 2011) JH-224 see JH (224 bits) JH-256 see JH (256 bits) JH-384 see JH (384 bits) JH-512 see JH (512 bits) JSSE Java Secure Socket Extension Keccak hash function (Guido Bertoni, Joan Daemen, Michaël Peeters und Gilles Van Assche, 2012) KCI Key Compromise Impersonation KDF Key Derivation Function KEA Key Exchange Algorithm (alias for FORTEZZA-KEA) KEK Key Encryption Key KMS Key Management Service KPAK KMS Public Authentication Key KSAK KMS Secret Authentication Key KSK Key Signing Key (DNSSEC) KU Key Usage LAKE hash function (Jean-Philippe Aumasson, Willi Meier, Raphael C.-W. Phan, 2008) LEXv2 stream cipher algorithm LFSR Linear Feedback Shift Register LION block cipher combining stream cipher and hash function LLL Lenstra–Lenstra–Lovász, lattice basis reduction algorithm LM hash LAN Manager hash aka LanMan hash Logjam Attack to force server to downgrade to export ciphers LRA Local Registration Authority LRW Liskov, Rivest, and Wagner (blok encryption) Lucifer block cipher (developed at IBM in the 1970s) Lucky 13 Break SSL/TLS Protocol MARS 128-bit block cipher (developed at IBM) MAC Message Authentication Code MCF Modular Crypt Format MDC Modification Detection Code MDC2 Modification Detection Code 2 aka Meyer-Schilling MDC-2 same as MDC2 MD2 Message Digest 2 MD4 Message Digest 4 MD5 Message Digest 5 MEE MAC-then-Encode-then-Encrypt (see also MtE, AtE) MEK Message Encryption Key MECAI Mutually Endorsing CA Infrastrukture MGF Mask Generation Function MISTY1 block cipher algorithm MQV Menezes-Qu-Vanstone (authentecated key agreement) MtE MAC-then-encrypt (see also AtE) NaCl "Salt", crypto library (by D. Bernstein, Tanja Lange, Peter Schwabe) NCP Normalized Certification Policy (according TS 102 042) Neokeon symmetric block cipher algorithm NewHope post-quantum key exchange nistp192 alias for P-192 nistp224 alias for P-224 nistp256 alias for P-256 nistp384 alias for P-384 nistp521 alias for P-521 NLSv2 stream cipher algorithm nonce (arbitrary) number used only once NPN Next Protocol Negotiation NSS Network Security Services NTG none-Deterministic Random Generator NTLM NT Lan Manager. Microsoft Windows challenge-response authentication method. NTRU asymetric cipher algorithm using lattice reduction NULL no encryption NUMS nothing up my sleeve numbers OAEP Optimal Asymmetric Encryption Padding OCB Offset Codebook Mode (block cipher mode of operation) OCB1 same as OCB OCB2 improved OCB aka AEM OCB3 improved OCB2 OCELOT1 stream cipher algorithm OCELOT2 stream cipher algorithm OCSP Online Certificate Status Protocol OCSP stapling formerly known as: TLS Certificate Status Request OFB Output Feedback OFBx Output Feedback x bit mode OID Object Identifier OMAC One-Key CMAC, aka CBC-MAC OMAC1 same as CMAC OMAC2 same as OMAC OPIE One-time pad Password system OTP One Time Pad OV Organisational Validation OV-SSL Organisational Validated Certificate P12 see PKCS#12 P7B see PKCS#7 P-192 Elliptic Curve used in FIPS 186-4 (NIST) P-224 Elliptic Curve used in FIPS 186-4 (NIST) P-256 Elliptic Curve used in FIPS 186-4 (NIST) P-384 Elliptic Curve used in FIPS 186-4 (NIST) P-521 Elliptic Curve used in FIPS 186-4 (NIST) PACE Password Authenticated Connection Establishment PAD Peer Authorization Database PAKE Password Authenticated Key Exchange Panama stream cipher algorithm PCN Pre-Congestion Notification PBE Password Based Encryption PBKDF2 Password Based Key Derivation Function PC Policy Constraints (certificate extension) PCBC Propagating Cipher Block Chaining PCFB Periodic Cipher Feedback Mode PCT Private Communications Transport PEM Privacy Enhanced Mail PES Proposed Encryption Standard PFS Perfect Forward Secrecy PFX see PKCS#12 (Personal Information Exchange) PGP Pretty Good Privacy PII Personally Identifiable Information PKCS Public Key Cryptography Standards PKCS1 PKCS #1: RSA Encryption Standard PKCS3 PKCS #3: RSA Encryption Standard on how to implement the Diffie-Hellman key exchange protocol PKCS5 PKCS #5: RSA Encryption Standard on how to derive cryptographic keys from a password PKCS6 PKCS #6: RSA Extended Certificate Syntax Standard PKCS7 PKCS #7: RSA Cryptographic Message Syntax Standard PKCS8 PKCS #8: RSA Private-Key Information Syntax Standard PKCS10 PKCS #10: Describes a standard syntax for certification requests PKCS11 PKCS #11: RSA Cryptographic Token Interface Standard (keys in hardware devices, cards) PKCS12 PKCS #12: RSA Personal Information Exchange Syntax Standard (public + private key stored in files) PKE Public Key Enablement PKI Public Key Infrastructure PKIX Internet Public Key Infrastructure Using X.509 PKP Public-Key-Pins PM Policy Mappings (certificate extension) PMAC Parallelizable MAC (by Phillip Rogaway) PMS Pre-Master Secret Poly1305 Authenticator (MAC) Poly1305-AES MAC (by D. Bernstein) POP Proof of Possession POODLE Padding Oracle On Downgraded Legacy Encryption PQC Post-Quantum Crypto PRF Pseudo-Random Function PRP Pseudo-Random Permutation prime192v1 alias for P-192 prime224v1 alias for P-224 prime256v1 alias for P-256 prime384v1 alias for P-384 prime521v1 alias for P-521 PRNG Pseudo-Random Number Generator PSK Pre-shared Key PSKC Portable Symmetric Key Container PTG Physical Random Generator PVT Public Validation Token PWKE Pair-Wise Key Establishment Schemes Using Discrete Logarithm Cryptography QUIC Quick UDP Internet Connection RA Registration Authority (aka Registration CA) Rabbit stream cipher algorithm RADIUS Remote Authentication Dial-In User Service Radix-64 alias for Base-64 RBG Random Bit Generator RC2 Rivest Cipher 2, block cipher by Ron Rivest (64-bit blocks) RC4 Rivest Cipher 4, stream cipher (aka Ron's Code) RC5 Rivest Cipher 5, block cipher (32-bit word) RC5-64 Rivest Cipher 5, block cipher (64-bit word) RC6 Rivest Cipher 6 RCSU Reuters' Compression Scheme for Unicode (aka SCSU) RFC Request for Comments Rijndael symmetric block cipher algorithm (AES) RIPEMD RACE Integrity Primitives Evaluation Message Digest RLWE Ring Learning-with-Errors RMAC Randomized MAC (block cipher authentication mode) RNG Random Number Generator ROT-13 see XOR ROBOT Return Of Bleichenbacher's Oracle Threat RTP Real-time Transport Protocol RSASSA-PSS RSA Probabilistic Signature Scheme RSA Rivest Sharmir Adelman (public key cryptographic algorithm) RSS-14 Reduced Space Symbology, see GS1 RTN Routing transit number S/KEY One-time pad Password system SA Subordinate Authority (aka Subordinate CA) SACL System Access Control List SAD Security Association Database SAE Simultaneous Authentication of Equals SAFER Secure And Fast Encryption Routine, block cipher Salsa20 stream cipher (by D. Bernstein, 2005) Salsa20/8 see scrypt Salsa20/12 see Salsa20 Salsa20/20 see Salsa20 SAM syriac abbreviation mark SAN Subject Alternate Name Sarmal hash function SAX Symmetric Authenticated eXchange SBCS single-byte character set SCA Selfsigned CA signature SCEP Simple Certificate Enrollment Protocol scrypt password based key derivation function (Colin Percival) SCSU Standard Compression Scheme for Unicode (compressed UTF-16) SCSV Signaling Cipher Suite Value SCVP Server-Based Certificate Validation Protocol SCT Signed Certificate Timestamp SDES Security Description Protokol secp192r1 alias for P-192 secp224r1 alias for P-224 secp256r1 alias for P-256 secp384r1 alias for P-384 secp521r1 alias for P-521 SEED 128-bit Symmetric block cipher Serpent symmetric key block cipher (128 bit) SGC Server-Gated Cryptography SGCM Sophie Germain Counter Mode (authenticated encryption block cipher mode) SHA Secure Hash Algorithm SHA-0 Secure Hash Algorithm (insecure version before 1995) SHA-1 Secure Hash Algorithm (since 1995) SHA-2 Secure Hash Algorithm (since 2002) SHA-3 Secure Hash Algorithm (since 2015), see Keccak also SHA-224 Secure Hash Algorithm (224 bit) SHA-256 Secure Hash Algorithm (256 bit) SHA-384 Secure Hash Algorithm (384 bit) SHA-512 Secure Hash Algorithm (512 bit) SHA1 alias for SHA-1 (160 bit) SHA2 alias for SHA-2 (224, 256, 384 or 512 bit) SHA3 alias for SHA-3 (224, 256, 384 or 512 bit) SHA3256 alias for SHA3-256 SHA3-224 Secure Hash Algorithm (224 bit) SHA3-256 Secure Hash Algorithm (256 bit) SHA3-384 Secure Hash Algorithm (384 bit) SHA3-512 Secure Hash Algorithm (512 bit) SHAKE128 Secure Hash Algorithm (variable bit) SHAKE256 Secure Hash Algorithm (variable bit) SHAvite-3 hash function (Eli Biham, Orr Dunkelman, 2009) SHS Secure Hash Standard SIA Subject Information Access (certificate extension) SIC Segmented Integer Counter (alias for CTR) SIMON block cipher combining Skein hash function (Niels Ferguson, Stefan Lucks, Bruce Schneier, Doug Whiting, Mihir Bellare, Tadayoshi Kohno, Jon Callas, Jesse Walker, 2010) Skein-256-256 see Skein (256 bits) Skein-512-256 see Skein (256 bits) Skein-512-512 see Skein (512 bits) Skein-1024-1024 see Skein (1024 bits) SKID Subject Key ID (certificate extension) SKIP Message Skipping Attacks on TLS SKIP-TLS see SKIP Skipjack block cipher encryption algorithm specified as part of the Fortezza SLOTH Security Losses from Obsolete and Truncated Transcript Hashes SM4 block cipher algorithm SMS4 see SM4 SMACK State Machine AttaCKs Snefu hash function Snow20 stream cipher algorithm SNI Server Name Indication SNOW word-based synchronous stream ciphers (by Thomas Johansson and Patrik Ekdahl ) Snuffle 2005 see Salsa20 Snuffle 2008 see ChaCha Sosemanuk stream cipher algorithm Speck block cipher algorithm SPD Security Policy Database SPDY Google's application-layer protocol on top of SSL SPECK block cipher combining SPHINCS post-quantum hash function SPHINCS-256 alias for SPHINCS SPI Security Parameters Index SPKI Subject Public Key Infrastructure SPN Substitution-Permutation Network SPRP Strong Pseudo-Random Permutation Square block cipher SRI Subresource Integrity SRP Secure Remote Password protocol SRTP Secure RTP SSCD Secure Signature Creation Device SSEE Sichere Signaturerstellungseinheit (same as SSCD) SSK Secret Signing Key SSL Secure Sockets Layer SSLv2 Secure Sockets Layer Version 2 SSLv3 Secure Sockets Layer Version 3 SSP Security Support Provider SSPI Security Support Provider Interface SST Serialized Certificate Store format STES stream cipher algorithm Streebog hash function Streebog-256 see Streebog Streebog-512 see Streebog STS Strict Transport Security STS Station-to-Station protocol SUF-CMA Strong UnForgeability against Chosen-Message Attacks Sweet32 Birthday attacks on 64-bit block ciphers in TLS and OpenVPN SWIFFT hash function (Vadim Lyubashevsky, Daniele Micciancio, Chris Peikert, Alon Rosen, 2008) SWIFFTX see SWIFFT TA Trust Agent TACK Trust Assertions for Certificate Keys TCB Trusted Computing Base TDEA Tripple DEA TEA Tiny Encryption Algorithm TEK Traffic Encryption Key TET ? Tiger hash function TIME Timing Info-leak Made Easy (Exploit SSL/TLS) TIME A Perfect CRIME? TIME Will Tell Threefish hash function TLS Transport Layer Security TLSA TLS Trust Anchors TLSv1 Transport Layer Security version 1 TLSA RR TLSA resource Record TMAC Two-Key CMAC, variant of CBC-MAC TOCTOU Time-of-check, time-of-use TOFU Trust on First Use TR-02102 Technische Richtlinie 02102 (des BSI) TR-03116 Technische Richtlinie 03116 (des BSI) Trivium stream cipher algorithm TSK Transmission Security Key TSK TACK signing key TSP trust-Management Service Provider TSS Time Stamp Service TTP trusted Third Party Twofish symmetric key block cipher (128 bit) UC Unified Capabilities UC Unified Communications (SSL Certificate using SAN) UCC Unified Communications Certificate (rarley used) UMAC message authentication code based on universal hashing; aka universal hashing MAC; optimized for 32-bit architectures URI Uniform Resource Identifier URL Uniform Resource Locator VMAC Universal hashing MAC; 64-bit variant of UMAC (by Ted Krovetz and Wei Dai) VMPC stream cipher algorithm VR-224 alias for BADA55-VR-224 VR-256 alias for BADA55-VR-256 VR-384 alias for BADA55-VR-384 WHIRLPOOL hash function WPAD Web Proxy Auto-Discovery wolfSSL SSL library mainly intended and used for embedded and real-time systems X.680 X.680: ASN.1 X.509 X.509: The Directory - Authentication Framework X25519 alias for Curve25519 ? X448 alias for Curve448 ? X680 X.680: ASN.1 X509 X.509: The Directory - Authentication Framework X3DH Extended Triple Diffie-Hellman XCBC eXtended CBC-MAC XCBC-MAC same as XCBC XChaCha12 stream cipher algorithm XChaCha20 stream cipher algorithm XEX XOR Encrypt XOR XKMS XML Key Management Specification XMACC counter-based XOR-MAC XMACR radomized XOR-MAC XMLSIG XML-Signature Syntax and Processing XMSS hash function XSalsa2 variant of Salsa20 XTEA extended Tiny Encryption Algorithm XTS XEX-based tweaked-codebook mode with ciphertext stealing XUDA Xcert Universal Database API XXTEA enhanced/corrected Tiny Encryption Algorithm yaSSL same as CyaSSL ZLIB Lossless compression file format ZRTP SRTP for VoIP ZSK Zone Signing Key (DNSSEC) O-Saft-19.01.19/OSaft/Doc/help.txt000066400000000000000000005204361342117255600162770ustar00rootroot00000000000000 # SID @(#) help.txt 1.22 19/01/20 23:08:32 NAME O-Saft - OWASP SSL advanced forensic tool OWASP SSL audit for testers DESCRIPTION This tools lists information about remote target's SSL certificate and tests the remote target according given list of ciphers. Note: Throughout this description `$0' is used as an alias for the program name 'o-saft.pl'. SYNOPSIS $0 [COMMANDS ..] [OPTIONS ..] target [target target ...] where [COMMANDS] and [OPTIONS] are described below and target is a hostname either as full qualified domain name or as IP address. Multiple commands and targets may be combined. All commands and options can also be specified in a rc-file, see RC-FILE below. I.g. all commands start with a '+' character and options start with '-' or '--' characters. Anything else is treated as target name. QUICKSTART Before going into a detailed description of the purpose and usage, here are some examples of the most common use cases: * Show supported (enabled) ciphers of target: $0 +cipher --enabled example.tld * Show supported (enabled) ciphers with their DH parameters: $0 +cipher-dh example.tld * Test all ciphers, even if not supported by local SSL implementation: $0 +cipherall example.tld * Show details of certificate and connection of target: $0 +info example.tld * Check certificate, ciphers and SSL connection of target: $0 +check example.tld * Check connection to target for vulnerabilities: $0 +vulns example.tld * Check for all known ciphers (independant of SSL library): $0 +cipherraw example.tld --range=full checkAllCiphers.pl example.tld checkAllCiphers.pl example.tld --range=full --v * Get the certificate's Common Name for a bunch of servers: $0 +cn example.tld some.tld other.tld * List more usage examples $0 --help=examples * List all available commands: $0 --help=commands * Get table of contents for complete help $0 --help=toc * Show just one section, for example SECURITY, from help $0 --help=SECURITY * Start the simple GUI o-saft.tcl # above o-saft.tcl must have trailing space, otherwise markup fails * Start the simple GUI which uses $0 in a Docker image o-saft.tcl --docker For more specialised test cases, refer to the sections COMMANDS and OPTIONS below. For more examples please refer to EXAMPLES section. For more details, please see X&Requirements& and INSTALLATION below. WHY? Why a new tool for checking SSL security and configuration when there are already a dozen or more such good tools in existence (in 2012)? Unique features: * working in closed environments, i.e. without internet connection * checking availability of ciphers independent of installed library * checking for all possible ciphers (up to 65535 per SSL protocol) * mainly same results on all platforms. Currently available tools suffer from some or all of following issues: * lack of tests of unusual SSL certificate configurations * may return different results for the same checks on given target * missing tests for modern SSL/TLS functionality * missing tests for specific, known SSL/TLS vulnerabilities * no support for newer, advanced, features e.g. CRL, OCSP, EV * limited capability to create your own customised tests Other reasons or problems are that other tools are either binary or use additional binaries and hence are not portable to other platforms. In contrast to (all?) most other tools, including openssl(1), it can be used to "ask simple questions" like "does target support STS" just by calling: $0 +hsts_sts example.tld For more, please see EXAMPLES section below. If it should run on systems with old software (perl or perl modules), please see DEBUG section below. SECURITY This tool is designed to be used by people doing security or forensic analyses. Hence no malicious input is expected. There are no special security checks implemented. Some parameters are roughly sanatised according unwanted characters. In particular there are no checks according any kind of code injection. Care should be taken, when additional tools and modules are installed as described in INSTALLATION below. In particular it is recommended to do these installations into directoies specially prepared for use with $0 . No other tools of your system should use these installations i.e. by accident or because your environment variables point to them. Note that compilation and installation of additional tools (openssl, Net::SSLeay, etc.) uses known insecure configurations and features! This is essential to make $0 able to check for such insecurities. It is highly recommended to do these installations and use the tools on a separate testing system. DO NOT USE THESE INSTALLATIONS ON PRODUCTIVE SYTEMS. CONCEPTS The purpose of O-Saft is to do the work, not to force the user to learn a new tool or to install "newer" software first. However, the user "should do something" if necessary depending on the reported results. Results Results of checks are marked 'yes' or 'no'. This leaves the proper interpretation, if the result is "good" or "bad", to the user. Background: it is not always possible to rate a result as "good" or "bad" or "insecure" or whatever. That's why O-Saft can not give the "the best" or a "proper" recomendation. In practice it depends on the context what a recomendation, or countermeasure should be. That's why all results are marked 'yes' or 'no' if considered "questionable" or "not good" (for example according other checks). ... more comming soon ... TECHNICAL INFORMATION It is important to understand, which provided information is based on data returned by underlaying (used) libraries and the information computed directly. OpenSSL, libssl, libcrypto In general the tool uses perl's Net::SSLeay(1) module which itself is based on libssl and/or libssleay library of the operating system. It's possible to use other versions of these libraries, see options: * --exe-path=PATH --exe=PATH * --lib-path=PATH --lib=PATH * --envlibvar=NAME The external openssl(1) is called to extract some information from its output. The version of openssl can be controlled with following options: * --openssl=TOOL * --no-openssl * --force-openssl * --exe-path=PATH --exe=PATH Above applies to all commands except +cipherall and +cipherraw which uses no other libraries. OpenSSL is recommended to be used for libssl and libcrypto. Versions 0.9.8k to 1.0.2e (Jan. 2016) are known to work. However, versions be- for 1.0.0 may not provide all informations. LibreSSL is not recommended, because some functionallity considered insecure, has been removed. For more details, please see INSTALLATION below. Certificates and CA All checks according the validity of the certificate chain are based on the root CAs installed on the system. NOTE that Net::SSLeay(1) and openssl(1) may have their own rules where to find the root CAs. Please refer to the documentation on your system for these tools. However, there are folloing options to tweak these rules: * --ca-file=FILE * --ca-path=DIR * --ca-depth=INT Commands and options All arguments starting with '+' are considered COMMANDS for this tool. All arguments starting with '--' are considered OPTIONS for this tool. Reading any data from STDIN or here-documents is not yet supported. It's reserved for future use. Environment variables Following environment variables are incorporated: * LD_LIBRARY_PATH - used and extended with definitions from options * OPENSSL - if set, full path to openssl executable * OPENSSL_CONF - if set, full path to openssl's openssl.cnf or directory where to find openssl.cnf # * OPENSSL_FIPS - # * OPENSSL_ENGINES - # * OPENSSL_ALLOW_PROXY # * OPENSSL_ALLOW_PROXY_CERTS Requirements For checking all ciphers and all protocols with +cipherall command, just perl (5.x) without any modules is required. For +info and +check (and all related) commands, perl (5.x) with following modules (minimal version) is recommended: * IO 1.25 (2011) * IO::Socket::INET 1.37 (2011) * IO::Socket::SSL 1.90 (2013) * Net::DNS 0.66 (2011) * Net::SSLeay 1.49 (2012) However, it is recommended to use the most recent version of the mod- ules which then gives more accurate results and less warnings. If the modules are missing, they can be installed i.e. with: cpan Net::SSLeay Note: if you want to use advanced features of openssl or Net::SSLeay, please see INSTALLATION section how to compile and install the tools fully customized. Also an openssl executable should be available, but is not mandatory. For checking DH parameters of ciphers, openssl 1.0.2 or newer should be available. If an older version of openssl is found, we try hard to extract the DH parameters from the data returned by the server, see +cipher-dh command. If you need to run on systems with older perl or perl module versions please refer to the DEBUG section for more inofrmation. RESULTS All output is designed to be easily parsed by postprocessors. Please see OUTPUT section below for details. For the results, we have to distinguish those returned by +cipher command and those from all other tests and checks like +check or +info command. +cipher The cipher checks will return one line for each tested cipher. It contains at least the cipher name, 'yes' or 'no' whether it is supported or not, and a security qualification. It may look like: AES256-SHA yes HIGH NULL-SHA no weak Depending on the used --legacy=* option the format may differ and also contain more information. For details see --legacy=* option below. The text for security qualifications are (mainly) those returned by openssl (version 1.0.1): LOW, MEDIUM, HIGH and WEAK. The same texts, but with all lower case characters, are used if the qualification was adapted herein. Following rules for adjusting the qualification were used: * weak: ** all *NULL* ciphers ** all *RC2* and *RC4* ciphers ** all *EXPORT* ciphers ** all *anon* (aka ADH aka DHA) ciphers ** all *CBC* and *CBC3* (aka 3DES) and DES ciphers * low: * high: ** all *AES(128|256)* ciphers ** all *CAMELLIA* ciphers +check These tests return a line with a label describing the test and a test result for it. The idea is to report 'yes' if the result is considered "secure" otherwise report 'no' followed by the reason why it's considered insecure. Example of a check considered secure: Label of the performed check: yes Example of a check considered insecure: Label of the performed check: no (reason why) Note that there are tests where the results appear confusing when first viewed, like for www.wi.ld: Certificate is valid according given hostname: no (*.wi.ld) Certificate's wildcard does not match hostname: yes This can for example occur with: Certificate Common Name: *.wi.ld Certificate Subject's Alternate Names: DNS:www.wi.ld Please check the result with the +info command also to verify if the check sounds reasonable. +info The test result contains detailed information. The labels there are mainly the same as for the +check command. COMMANDS There are commands for various tests according the SSL connection to the target, the targets certificate and the used ciphers. All commands are preceded by a '+' to easily distinguish from other arguments and options. However, some --OPTIONS options are treated as commands for historical reason or compatibility to other programs. The most important commands are (in alphabetical order): +check +cipher +info +http +list +quick +sni +sni_check +version A list of all available commands will be printed with: $0 --help=cmds The description of all other commands will be printed with: $0 --header --help=commands The summary and internal commands return requested information or the results of checks. These are described below. Note that some commands may be a combination of other commands, see: $0 --header --help=intern The following sub-sections only describe the commands, which do more than giving a simple information from the target. All other commands can be listed with: $0 --header --help=commands The final sub-sections X&Notes about commands& describes some notes about special commands and related commands. Commands for information about this tool All these commands will exit after execution (cannot be used together with other commands). +ciphers Show ciphers offered by local SSL implementation. This commands prints the ciphers in a format like "openssl ciphers" does. It also accepts the -v and -V option. The --legacy=TYPE option can be used as described for +list command. Use +list command for more information according ciphers. +list Show all ciphers supported by this tool. This includes cryptogrphic details of the cipher and some internal details about the rating. In contrast to the +ciphers command, +list uses TAB characters instead of spaces to seperate columns. It also prints table header lines by default. Different output formats are used for the --legacy option: * --legacy=simple tabular output of cipher values * --legacy=full as --legacy=simple but more data * --legacy=openssl output like with +ciphers command * --legacy=ssltest output like "ssltest --list" # Use --v option to show more details. # seit 15.01.07 nicht mehr benutzt +VERSION Just show version and exit. +version Show version information for both the program and the Perl modules that it uses, then exit. Use --v option to show more details. +libversion Show version of openssl. +quit Show internal data and exit, used for testing and debugging only. Please see TESTING below. Commands to check SSL details # # Check for SSL connection in SNI mode and if given FQDN matches # certificate's subject. Following (summary and internal) commands are simply a shortcut for a list of other commands. For details of the list use: $0 --help=intern +check Check the SSL connection for security issues. Implies +cipher . +host Print details about the targets hostname, DNS, etc. These details are usually printed only for the +check and +info command, but not for any individual command. +http Perform HTTP checks (like STS, redirects etc.). +info Overview of most important details of the SSL connection. Use --v option to show details also, which span multiple lines. +info--v Overview of all details of the SSL connection. It is a shortcut for all commands listed below but not including +cipher. This command is intended for debugging as it prints some details of the used Net::SSLinfo module. +quick Quick overview of checks. Implies --enabled and --label=short. +pfs Check if servers offers ciphers with prefect forward secrecy (PFS). +protocols Check for protocols supported by target. +vulns Check for various vulnerabilities. +sts +hsts Various checks according STS HTTP header. This option implies --http, means that --no-http is ignored. +sni Check for Server Name Indication (SNI) usage. +sni_check +check_sni Check for Server Name Indication (SNI) usage and validity of all names (CN, subjectAltName, FQDN, etc.). +bsi Various checks according BSI TR-02102-2 and TR-03116-4 compliance. +ev Various checks according certificate's extended Validation (EV). Hint: use option --v --v to get information about failed checks. +sizes Check length, size and count of some values in the certificate. +s_client Dump data retrieved from "openssl s_client ..." call. This should be used for debugging only. It can be used just like openssl itself, for example: openssl s_client -connect host:443 -no_sslv2 +dump Dumps internal data for SSL connection and target certificate. This is mainly for debugging and should not be used together with other commands (except +cipher). Each key-value pair is enclosed in '#{' and '#}' . Using --trace --trace dumps data of Net::SSLinfo too. +exec Command used internally when requested to use other libraries. This command should not be used directly. Commands to test ciphers provided by target Beside the description of the commands itself here, please see also X&Notes about commands& below. +cipher Check target for ciphers, either all ciphers, or ciphers specified with --cipher=CIPHER option. Note that ciphers not supported by the local SSL implementation are not checked by default, use +cipherall or +cipherraw command. Use --v option to see all ciphers being checked. +cipherraw Check target for all possible ciphers. Does not depend on local SSL implementation. In contrast to +cipher this command has some options to tweak the cipher tests, connection results and some strange behaviours of the target. See X&Options for cipherall and cipherraw command& for details. +cipherall Same as +cipherraw but ouput format similar to +cipher command. +cipher-default Lists the cipher selected by the server for each protocol sometimes referred to as "default cipher". For each protocol the two selected ciphers are shown, one returned by the server if the cipher list in the ClientHello is sorted with the strongest cipher first, and one returned if the cipher list in the ClientHello is sorted with strongest cipher last. See X&Notes about commands& for details. +cipher-dh Checked target for ciphers. All ciphers supported by the server are printed with their DH or ECDH paramaters (if available). ciphers. +null +cipher-null Check if target accepts NULL ciphers. +adh +cipher-adh Check if target accepts ciphers with anonymous key exchange. +export +cipher-exp Check if target accepts EXPORT ciphers. +cbc +cipher-cbc Check if target accepts CBC ciphers. +des +cipher-des Check if target accepts DES ciphers. +cipher-rc4 Check if target accepts RC4 ciphers. +edh +cipher-edh Check if target supports ephemeral ciphers. +cipher-pfs Check if target supports ciphers with PFS. +cipher-strong Check if target selects strongest cipher. +cipher-weak Check if target selects weak cipher (oposite of +cipher-strong). Discrete commands to test SSL connection and certificate details Discrete commands, please see: $0 --help=commands Notes about commands +cipher vs. +cipherall +cipher can only check for ciphers - more precise: cipher suites - provided by the local SSL implementation (i.e. libssl). +cipherall can check for any cipher, as it just uses the cipher's integer value in the range 0 .. 65532. +cipherall vs. +cipherraw These commands are identical, just the output format is different. +cipher vs. +cipher-dh While +cipher prints checked ciphers, +cipher-dh prints ciphers with their DH or ECDH paramaters (if available) only for supported ciphers. +cipher vs. +cipher-default Both commands show the default cipher foreach protocol. +cipher lists a summary of ciphers selected by the server for each protocol requested by the user (for example by using options like: --sslv3 --tlsv1 etc.). When the --v option is used, all selected ciphers for all known protocols are listed. This summary focuses on counts for various ciphers. +cipher-default lists the cipher selected by the server for each protocol. +cipher-selected vs. +cipher-default +selected lists the cipher selected by the server if no particular protocol was specified and the system's default cipher list is send in the ClientHello to the server. +cipher-default lists the cipher selected by the server for each protocol. # other names: SSLHonorCipherOrder prefer-server-ciphers PreferServerCipherSuites Server-Defined-Cipher-Order +cipher-strong vs. +cipher-default +strong-cipher shows the result of the check if strong ciphers are preferred by the server. It is a check command. +cipher-default lists the cipher selected by the server for each protocol. It is a information command. It is not possible to check if a server uses 'SSLHonorCipherOrder'. Even if it is used (switched on), it is not possible to check the specified order of the ciphers. I. g. it is expected that the order is according the cipher suite's strength, meaning the most strongest first, and the weakest last. It does not make sense to use an order where a weak cipher preceeds a stronger one. Such a (mis-)configuration should be detected. Having this in mind, the algorithm to detect a proper cipher order is as simply as follows: 1. pass sorted cipher list with strongest cipher first 2. pass sorted cipher list with strongest cipher last if the server returns the same cipher for both checks, it's assumed that it prefers to use the most strongest cipher. In this case it's obvious that 'SSLHonorCipherOrder' is set (exceptions see below). +cipherall uses a more accurate algorithm to detect the server's cipher order. Exceptions: If either, the server or the client, uses only one cipher suite in the list, SSLHonorCipherOrder cannot be detected at all. The same happens, if only one cipher in the client's list matches a cipher in the server's list. +extensions vs. +tlsextensions +extensions shows the "Certificate extensions" and +tlsextensions will show the TLS protocol extensions. Use +tlsextdebug to show more informations about the TLS protocol extensions. +http2 +spdy +spdy3 +spdy31 +spdy4 +prots These commands are just an alias for the +protocols command. +hostname vs. +wildhost vs. +altname vs. +rfc_2818 The commands +cn and +altname print the information stored in the certificate. The command +hostname checks if the given hostname matches the CN value in the certificate. Note that wildcard names in the CN, only allow to contain one '*'. The command +wildcard checks if the given hostname does not match any name specified in the certificate's "subjectAltname". This check is usefull if the certificate and the configuration must comply to RFC 6125 or EV certificates. OPTIONS All options are written in lowercase. Words written in all capital in the description here is text provided by the user. Options for help and documentation --h --help WYSIWYG --help=cmds Show available commands; short form. --help=commands Show available commands with short description. --help=opt Show available options; short form. --help=options Show available options with their description. --help=checks Show available checks. --help=tools Description of tools around O-Saft, when, where and how to use. --help=cmd Show additional and user specified commands. --help=cfg-cmd Show additional and user specified commands. Output can be use in RC-FILE or as option. --help=check-cfg --help=cfg-check Show texts used as labels in output for checks (see +check) ready for use in RC-FILE or as option. --help=data Show available informations. --help=data-cfg --help=cfg-data --help=cfg-info Show texts used as labels in output for data (see +info) ready for use in RC-FILE or as option. --help=hint Show texts used in hint messages. --help=hint-cfg --help=cfg-hint Show texts used in hint messages ready for use in RC-FILE or as option. --help=text Show texts used in various messages. --help=text-cfg --help=cfg-text Show texts used in various messages ready for use in RC-FILE or as option. --help=legacy Show possible legacy formats (used as value in --legacy=TOOL). --help=compliance Show available compliance checks. --help=intern Show internal commands. --help=alias Show alias for commands and options. --help=pattern Show list of cipher pattern (used for --cipher=CIPHER). --help=range Show list of cipherranges (see --cipherrange=RANGE). --help=score Show score value for each check. Value is printed in format to be used for --cfg-score=KEY=SCORE. Note that the sequence of options is important. Use the options --trace and/or --cfg-score=KEY=SCORE before --help=score. --help=toc --help=content Show headlines from help text. Useful to get an overview. --help=SECTION Show 'SECTION' from documentation, see --help=toc for a list. Example: $0 --help=EXAMPLES --help=ourstr Show regular expressions to match our own strings used in output. --help=regex Show regular expressions used internally. --help=gen-html Print documentation in HTML format. --help=gen-pod Print documentation in POD format. --help=gen-wiki Print documentation in mediawiki format. --help=gen-cgi Print documentation in format to be used for CGI. --help=error --help=warning --help=problem Show X&KNOWN PROBLEMS& section with description of known error and warning messages. --help=faq Show X&KNOWN PROBLEMS& and LIMITATIONS section. --help=glossary Show common abbreviation used in the world of security. --help=links Show list of URLs related to SSL/TLS. --help=rfc Show list of RFC related to SSL/TLS. --help=todo Show known problems and bugs. --help=exit Show possible --exit=KEY options. Used for debugging only. --help=program.code For developers. Options for all commands (general) --dns Do DNS lookups to map given hostname to IP, do a reverse lookup. --no-dns Do not make DNS lookups. Note that the corresponding IP and reverse hostname may be missing in some messages then. --host=HOST Specify HOST as target to be checked. Legacy option. --port=PORT Specify PORT of target to be used. Legacy option. --host=HOST --port=PORT HOST:PORT HOST When giving more than one HOST argument, the sequence of the given HOST argument and the given --port=PORT and the given --host=HOST options are important. The rule how ports and hosts are mapped is as follows: HOST:PORT arguments are used as is (connection to HOST on PORT) only HOST is given, then previous specified --port=PORT is used Note that URLs are treated as HOST:PORT, if they contain a port. Example: $0 +cmd host-1 --port 23 host-2 host-3:42 host-4 will connect to: * host-1:443 * host-2:23 * host-3:42 * host-4:23 --proxyhost=PROXYHOST --proxy=PROXYHOST:PROXYPORT Make all connection to target using PROXYHOST. Also possible is: --proxy=PROXYUSER:PROXYPASS@PROXYHOST:PROXYPORT --proxyport=PROXYPORT Make all connection to target using PROXYHOST:PROXYPORT. --proxyuser=PROXYUSER Specify username for proxy authentication. --proxypass=PROXYPASS Specify password for proxy authentication. --starttls Use 'STARTTLS' command to start a TLS connection via SMTP. This option is a shortcut for --starttls=SMTP . --starttls=SMTP --starttls=PROT Use 'STARTTLS' command to start a TLS connection via protocol. 'PROT' may be any of: 'SMTP', 'IMAP', 'IMAP2', 'POP3', 'FTPS', 'RDP', 'LDAP' or 'XMPP' . For --starttls=SMTP see --dns-mx also to use MX records instead of host --starttls-delay=SEC Number of seconds to wait before sending a packet, to slow down the 'STARTTLS' requests. Default is 0. This may prevent blocking of requests by the target due to too much or too fast connections. Note: In this case there is an automatic suspension and retry with a longer delay. --cgi --cgi-exec Internal use for CGI mode only. Options for SSL tool --rc Read RC-FILE if exists, from directory where program was found. --no-rc Do not read RC-FILE. --exitcode The exit status code will be greater 0, if any of following applies: * any check returns 'no' * insecure protocols are available * insecure ciphers are supported * ciphers without PFS are supported (disable with --exitcode-cipher) In particular, the status code will be the total count of all these checks. Parts of these checks can be diasabled, see --exitcode-* options below. Functionality implemented experimental, may change in future. --exitcode-no-checks Do not count checks with result 'no' for --exitcode . --exitcode-no-low --exitcode-no-weak --exitcode-no-medium Do not count LOW, WEAK or MEDIUM security ciphers for --exitcode . --exitcode-no-ciphers Do not count any ciphers for --exitcode . --exitcode-no-ciphers Do not count any ciphers for --exitcode . --exitcode-no-pfs Do not count ciphers without PFS for --exitcode . --openssl-s_client --s_client Use "openssl s_slient ..." call to retrieve more information from the SSL connection. This is disabled by default on Windows because of performance problems. Without this option (default on Windows !) following informations are missing: compression, expansion, renegotiation, resumption, selfsigned, verify, chain, protocols, DH parameters See Net::SSLinfo for details. If used together with --trace, s_client data will also be printed in debug output of Net::SSLinfo. --no-openssl Do not use external "openssl" tool to retrieve information. Use of "openssl" is disabled by default on Windows. Note that this results in some missing informations, see above. --openssl=TOOL 'TOOL' can be a path to openssl executable; default: openssl # * ssleay: use installed Net::SSLeay library for perl # * x86_32: use ** NOT YET IMPLEMENTED ** # * x86_64: use ** NOT YET IMPLEMENTED ** # * x86Mac: use ** NOT YET IMPLEMENTED ** # * arch: use ** NOT YET IMPLEMENTED ** --openssl-cnf=FILE --openssl-conf=FILE 'FILE' path of directory or full path of openssl.cnf If set, environment variable OPENSSL_CONF will be set to given path (or file) when openssl(1) is started. Please see openssl's man page for details about specifying alternate openssl.cnf files. --openssl-ciphers --force-openssl Use openssl to check for supported ciphers; default: IO::Socket(1) This option forces to use "openssl s_slient -connect CIPHER .." to check if a cipher is supported by the remote target. This is useful if the --lib=PATH option doesn't work (for example due to changes of the API or other incompatibilities). --exe-path=PATH --exe=PATH 'PATH' is a full path where to find openssl. --lib-path=PATH --lib=PATH 'PATH' is a full path where to find libssl.so, libcrypto.so. See X&HACKER's INFO& below for a detailed description how it works. --envlibvar=NAME 'NAME' is the name of a environment variable containing additional paths for searching dynamic shared libraries. Default is LD_LIBRARY_PATH. Check your system for the proper name, i.e.: DYLD_LIBRARY_PATH, LIBPATH, RPATH, SHLIB_PATH. --ssl-error The connection to a target may fail, or even block, due to various reasons for example lost network at all, blocking at firewall, etc. In particular when checking ciphers with +cipher , this may result in long delays until results are printed. Using this option stops trying to do more connections to the target when --ssl-error-max=CNT consecutive errors occoured, or when the total amount of errors increases --ssl-error-total=CNT. Note that this may result in loss of information and/or checks. # --ssl-error-delay=SEC (default: 0). --ssl-error-max=CNT Max. amount of consecutive errors (default: 5). --ssl-error-timeout=SEC Timeout in seconds when a failed connection is treated as error and then counted (default: 1). --ssl-error-total=CNT Max. total amount of errors (default: 10). --ssl-lazy I.g. this tools tries to identify available functionality according SSL versions from the underlaying libraries. Unsupported versions are then disables and a warning is shown. Unfortunately some libraries have not implemented all functions to check availability of a specific SSL version, which then results in a compile error. This option disables the strict check of availability. If the underlaying library doesn't support the required SSL version at all, following error may occour: Can't locate auto/Net/SSLeay/CTX_v2_new.al in @INC ... See X&Note on SSL versions& for a general note about SSL versions. A more detailled description of the problem and how Net::SSLeay be- haves, can be found in the source of $0 , see section starting at #| check for supported SSL versions --timeout=SEC Timeout in seconds when connecting to the target (default: 2). # following missing on owasp.org 'cause still not fully implemented --call=METHOD 'METHOD' method to be used for specific functionality Available methods: * info-socket use internal socket to retrieve information * info-openssl use external openssl to retrieve information * info-user use usr_getinfo() to retrieve information * cipher-socket use internal socket to ckeck for ciphers * cipher-openssl use external openssl to ckeck for ciphers * cipher-user use usr_getciphers() to ckeck for ciphers Method names starting with: * info- are responsible to retrieve information about the SSL connection and the target certificate (i.e. what the +info command provides) * cipher- are responsible to connect to the target and test if it supports the specified ciphers (i.e. what the +cipher command provides) * check- are responsible for performing the checks (i.e. what's shown with the +check command) * score- are responsible to compute the score based on check results The second part of the name denotes which kind of method to call: * socket the internal functionality with sockets is used * openssl the exteranl openssl executable is used * user the external special function, as specified in user's o-saft-usr.pm, is used. Example: --call=cipher-openssl will use the external openssl(1) executable to check the target for supported ciphers. Default settings are: --call=info-socket --call=cipher-socket --call=check-socket Just for curiosity, instead of using: $0 --call=info-user --call=cipher-user --call=check-user --call=score-user ... consider to use your own script like: #!/usr/bin/env perl usr_getinfo();usr_getciphers();usr_checkciphers();usr_score(); :-)) -v Print list of ciphers in style like: "openssl ciphers -v". Option used with +ciphers command only. -V Print list of ciphers in style like: "openssl ciphers -V". Option used with +ciphers command only. Options for SSL connection to target --cipher=CIPHER * 'CIPHER' can be any string accepeted by openssl or following: * 'yeast' use all ciphers from list defined herein, see +list Beside the cipher names accepted by openssl, CIPHER can be the name of the constant or the (hex) value as defined in openssl's files. Currently supported are the names and constants of openssl 1.0.1k. Example: * --cipher=DHE_DSS_WITH_RC4_128_SHA * --cipher=0x03000066 * --cipher=66 will be mapped to 'DHE-DSS-RC4-SHA' Note: if more than one cipher matches, just one will be selected. Default is 'ALL:NULL:eNULL:aNULL:LOW' as specified in Net::SSLinfo. --socket-reuse TCP socket will be reused for next connection attempt even if SSL connection failed. --no-socket-reuse Close TCP socket and then reopen for next connection attempt if SSL connection failed. This is useful for some servers which may return an "TLS alert" if the connection fails and then fail again on the same socket. --ignore-no-connect A simple check if the target can be connected will be performed by default. If this check fails, the target will be ignored, means no more requested checks will be done. As this connection check some- times fails due to various reasons, the check can be disabled using this option. --no-md5-cipher Do not use *-MD5 ciphers for other protocols than SSLv2. This option is only effective with +cipher command. The purpose is to avoid warnings from IO::Socket::SSL(1) like: Use of uninitialized value in subroutine entry at lib/IO/Socket/SSL.pm line 430. which occours with some versions of IO::Socket::SSL(1) when a *-MD5 ciphers will be used with other protocols than SSLv2. Note that these ciphers will be checked for SSLv2 only. # # IO::Socket::SSL->new() does not return a proper error # see in IO::Socket::SSL.pm Net::SSLeay::CTX_set_cipher_list() call # # --local # # It does not make much sense trying a connection with a cipher which # is not supported by the local SSL implementation. Hence these are # silently ignored by default. # With this option we try to use such ciphers also. # # Option reserved for future use ... # --sslv2 --sslv3 --tlsv1 --tlsv11 --tlsv12 --tlsv13 --dtlsv09 --dtlsv1 --dtlsv11 --dtlsv12 --dtlsv13 --SSL, -protocol SSL --no-sslv2 --no-sslv3 --no-tlsv1 --no-tlsv11 --no-tlsv12 --no-tlsv13 --no-dtlsv09 --no-dtlsv1 --no-dtlsv11 --no-dtlsv12 --no-dtlsv13 --no-SSL * 'SSL' can be any of: ssl, ssl2, ssl3, sslv2, sslv3, tls1, tls1, tls11, tls1.1, tls1-1, tlsv1, tlsv11, tlsv1.1, tlsv1-1 (and similar variants for tlsv1.2). For example: --tls1 --tlsv1 --tlsv1_1 are all the same. (--SSL variants): Test ciphers for this SSL/TLS version. (--no-SSL variants): Don't test ciphers for this SSL/TLS version. --no-tcp Shortcut for: --no-sslv2 --no-sslv3 --no-tlsv1 --no-tlsv11 --no-tlsv12 --no-tlsv13 --tcp Shortcut for: --sslv2 --sslv3 --tlsv1 --tlsv11 --tlsv12 --tlsv13 --no-udp Shortcut for: --no-dtlsv09 --no-dtlsv1 --no-dtlsv11 --no-dtlsv12 --no-dtlsv13 --udp Shortcut for: --dtlsv09 --dtlsv1 --dtlsv11 --dtlsv12 --dtlsv13 --nullsslv2 This option forces to assume that SSLv2 is enabled even if the target does not accept any ciphers. The target server may accept connections with SSLv2 but not allow any cipher. Some checks verify if SSLv2 is enabled at all, which then would result in a failed test. The default behaviour is to assume that SSLv2 is not enabled if no ciphers are accepted. --http Make a HTTP request if cipher is supported. If used twice debugging will be enabled using environment variable 'HTTPS_DEBUG'. --no-http Do not make HTTP request. --sni Make SSL connection in SNI mode. --no-sni Do not make SSL connection in SNI mode (default: SNI mode). --sni-toggle --toggle-sni Test with and witout SNI mode (+cipherall only). --force-sni Do not check if SNI seems to be supported by Net::SSLeay(1). Older versions of openssl and its libries do not support SNI or the SNI support is implemented buggy. By default it's checked if SNI is properly supported. With this option this check can be disabled. Be warned that this may result in improper results. --servername=NAME --sni-name=NAME If SNI mode is active, see --sni above, 'NAME' is used instead of hostname for connections to the target. If SNI mode is not active, see --no-sni above, 'NAME' is not used. The default is undefined, which forces to use the given FQDN. This is useful, for example when an IP instead of a FQDN was given, where a correct hostname (i.g. a FQDN) needs to be specified. Note: i.g. there is no need to use this option, as a correct value for the SNI name will be choosen automatically (except for IPs). However, it is kind of fuzzing ... even setting to an empty string is possible. Limitation: the same 'NAME' is used for all targets, if more than one target was specified. --no-cert Do not get data from target's certificate, return empty string. --no-cert --no-cert Do not get data from target's certificate, return default string of Net::SSLinfo (see --no-cert-text=TEXT option). --no-cert-text=TEXT Set 'TEXT' to be returned from Net::SSLinfo if no certificate data is collected due to use of --no-cert. --ca-depth=INT Check certificate chain to depth 'INT' (like openssl's -verify). --ca-file=FILE Use 'FILE' with bundle of CAs to verify target's certificate chain. --ca-path=DIR Use 'DIR' where to find CA certificates in PEM format. --ca-force --force-ca NOT YET IMPLEMENTED I. g. openssl uses default settings where to find certificate files. When --ca-file=FILE and/or --ca-path=DIR was used, this default will be overwritten by appropriate options passed to openssl. If the default does not work as expected, --force-ca can be used to force setting of proper values according well known common defaults. See: $0 +version $0 +version --force-ca to see the used settings. --alpn Use -alpn option for openssl. --no-alpn Do not use -alpn option for openssl. --no-npn --no-nextprotoneg Do not use -nextprotoneg option for openssl. --proto-alpn=NAME Name of protocol to be added to list of applcation layer protocols (ALPN), which is used for any connection to the targets. See --cipher-alpn=NAME also. --proto-npn=NAME Name of protocol to be added to list of next protocol negotiations (NPN), which is used for any connection to the targets. See --cipher-npn=NAME also. --ssl-compression --compression Use SSL option "compression" for connection. --no-ssl-compression --no-compression Use SSL option "no compression" for connection (default: don't use) --no-reconnect Do not use -reconnect option for openssl. --no-tlsextdebug Do not use -tlsextdebug option for openssl. --sclient-opt=VALUE Argument or option passed to openssl's s_client command. Options for +cipher command --connect-delay=SEC Additional delay in seconds after each connect for a cipher check. This is useful when connecting to servers which have IPS in place, or are slow in accepting new connections or requests. --cipher-alpn=NAME Name of protocol to be added to list of applcation layer protocols (ALPN), which is used for cipher checks. --cipher-alpn=, sets empty list. --cipher-alpn=,, sets list to empty element "". --cipher-npn=NAME Name of protocol to be added to list of next protocol negotiations (NPN), which is used for cipher checks. --cipher-npn=, sets empty list. --cipher-npn=,, sets list to empty element "". Note: setting empty list or element most likely does not work with openssl executable (i.e. --force-openssl). --cipher-curve=NAME Name of ecliptic curve to be added to list of ecliptic curves (EC), which is used for cipher checks. --cipher-curve=, sets empty list. --cipher-curve=,, sets list to empty element "". Note: setting empty list or element most likely does not work with openssl executable (i.e. --force-openssl). Options for cipherall and cipherraw command --range=RANGE --cipherrange=RANGE Specify range of cipher constants to be tested by +cipherall. Following RANGEs are supported: * 'rfc' all ciphers defined in various RFCs * 'shifted' 'rfc', shifted by 64 bytes to the right * 'long' like 'rfc' but more lazy list of constants * 'huge' all constants 0x03000000 .. 0x0300FFFF * 'safe' all constants 0x03000000 .. 0x032FFFFF * 'full' all constants 0x03000000 .. 0x03FFFFFF * 'SSLv2' all ciphers according RFC for SSLv2 * 'SSLv2_long' more lazy list of constants for SSLv2 ciphers Note: 'SSLv2' is the internal list used for testing SSLv2 ciphers. It does not make sense to use it for other protocols; however ... --slow-server-delay=SEC Additional delay in seconds after the server is connected using a proxy or before starting 'STARTTLS'. This is useful when connecting via slow proxy chains or connecting to slow servers before sending the 'STARTTLS' sequence. --ssl-maxciphers=CNT Maximal number of ciphers sent in a sslhello (default: 32). --ssl-double-reneg Send SSL extension 'reneg_info' even if list of ciphers includes 'TLS_EMPTY_RENEGOTIATION_INFO_SCSV' (default: do not include) # alias: --sslnodataeqnocipher --nodataeqnocipher --ssl-nodata-nocipher Some servers do not answer (i.g. they disconnect) if none of the offered ciphers is supported by the server. Continue testing with next ciphers when the target disconnects or does not send data within specified timeout (see --timeout). Useful for TLS intolerant servers. --no-ssl-nodata-nocipher Abort testing with next ciphers when the target disconnects. --ssl-use-ecc Use supported elliptic curves. Default on. --ssl-use-ec-point Use TLS 'ec_point_formats' extension. Default on. --ssl-use-reneg Test for ciphers with "secure renegotiation" flag set. Default: don't set "secure renegotiation" flag. --ssl-retry=CNT Number of retries when connection timed-out (default: 2). --ssl-timeout=SEC Number of seconds to wait until connection is qualified as timeout. --dns-mx --mx Get DNS MX records for given target and check the returned targets. (only useful with --starttls=SMTP). Options for checks and results Options used for +check command: --enabled Only print result for ciphers accepted by target. --disabled Only print result for ciphers not accepted by target. --ignorecase Checks are done case insensitive. --no-ignorecase Checks are done case sensitive. Default: case insensitive. Currently only checks according CN, alternate names in the target's certificate compared to the given hostname are effected. --ignore-no-reply When checking for the TLS "heartbeat" extension, the server may not respond at all, which would result in a "no reply" message. This marks the check for +heartbleed as 'no'. I.g. a server is not vulnerable to the heartbleed attack if the TLS "heartbeat" extension is disabled. Hence the check result 'no' may be mis-leading. This option treats the "no reply" result as "not vulnerable" and returns 'yes' then. Note: if the server does not respond for this check, does not mean that the "heartbeat" extension is switched off. If unsure, disable this lazy check with --no-ignore-no-reply . Options for output format --label=TYPE Defines the format of the descriptive text (label) for +check and +info command. Following 'TYPE's are supported: --label=long Prints full text for labels: Certificate Common Name: some.tld --label=short Prints short less descriptive text for labels: Common Name: some.tld --label=key Internal format: print name of key instead of text as label. Key is Prints name of key instead of text as label. The key is that of the internal data structure(s). [cn] some.tld For ciphers and protocols, the corresponding hex value is used as key. Note that these values are unique. --legacy=TOOL For compatibility with other tools, the output format used for the result of the +cipher command can be adjusted to mimic the format of other SSL testing tools. The argument to the --legacy=TOOL option is the name of the tool to be simulated. Following TOOLs are supported: * 'sslaudit' format of output similar to sslaudit * 'sslcipher' format of output similar to ssl-cipher-check * 'ssldiagnos' format of output similar to ssldiagnos * 'sslscan' format of output similar to sslscan * 'ssltest' format of output similar to ssltest * 'ssltestg' format of output similar to ssltest -g * 'ssltest-g' format of output similar to ssltest -g * 'sslyze' format of output similar to sslyze * 'ssl-cipher-check' same as sslcipher * 'ssl-cert-check' format of output similar to ssl-cert-check * 'testsslserver' format of output similar to TestSSLServer.jar * 'thcsslcHeck' format of output similar to THCSSLCheck Note that these legacy formats only apply to output of the checked ciphers. Other texts like headers and footers are adapted slightly. Please do not expect identical output as the TOOL when using these options, it's a best guess and should be parsable in a very similar way. --legacy=TYPE --legacy=compact Internal format: mainly avoid tabs and spaces format is as follows: Some Label:<-- anything right of colon is data --legacy=full Internal format: pretty print each label in its own line, followed by data prepended by tab character (useful for +info only). --legacy=owasp Results for cipher checks use rating from OWASP Cipher Cheat Sheet. --legacy=quick Internal format: use tab as separator; ciphers are printed with bit length (implies --tab). --legacy=simple Internal default format. --format=0x --format=\x --format=/x --format=hex --format=raw This option is used to specify the format of the result lines. This covers the value of the result line only. * 'raw' Print raw data as passed from Net::SSLinfo. Note: all data will be printed as is, without additional label or formatting. It's recommended to use the option in conjunction with exactly one command. Otherwise the user needs to know how to "read" the printed data. * 'hex' Convert some data to hex: 2 bytes separated by ':'. * '0x' Convert some data with hex values: 2 bytes preceded by '0x' and separated by a space. * '/x' Same as --format=\x * '\x' Convert some data with hex values: 2 bytes preceded by '\x' and no separating char. --header Print formatting header. Default for +check, +info, +quick and and +cipher only. --no-header Do not print formatting header. Usefull if raw output should be passed to other programs. Note: must be used on command line to inhibit all header lines. --ignore-cmd=CMD --ignore-output=CMD --no-cmd=CMD --no-output=CMD Do not print output (data or check result) for command 'CMD'. 'CMD' is any valid command, see COMMANDS , without leading '+'. Option can be used multiple times. --score Print scoring results. Default for +check. --no-score Do not print scoring results. --separator=CHAR --sep=CHAR 'CHAR' will be used as separator between label and value of the printed results. Default is ':'. --tab 'TAB' character (0x09, \t) will be used as separator between label and value of the printed results. As label and value are already separated by a TAB character, this options is only useful in conjunction with the --legacy=compact option. --showhost Prefix each printed line with the given hostname (target). The hostname will be followed by the separator character. # However, it applies partially if used twice for +info. --std-format=utf8 --std-format=crlf --std-format=raw --std-format=unix --std-format=CHARSET This option is used to specify the general output format for STDOUT and STDERR. All results are written to STDOUT, errors and warnings may also be written to STDERR . The default is ':unix:utf8', which is the perlish definition used internally. Following values are supported: * 'raw' * 'unix' Print raw data, binary in bytes without conversion. Note: binary here just means characters (as all output is text). * 'utf8' Convert all characters to UTF-8. * 'crlf' Use CR LF as end of line. * 'CHARSET' 'CHARSET' can be any of the local installed character sets, like UTF-8, UTF-16LE, CP1252, iso-8859-7, etc.. This conversion may print its own warnings. The option can be used multiple times with different values. To reset the default behaviour, either 'raw' or 'unix' must be used. Obviously, they must be used first. All other values are used additionally. Note: 'utf8' just defines the format of the characters, it does no further checks on the converted characters. In contrast, 'UTF-8' is used as real encoding and does some checks. For more details, please see "perldoc -f binmode" . Currently (Jan. 2018), these options must be used before any --help option. --win-CR Obsolete, please use --std-format=crlf . Options for compatibility with other programs Please see other programs for detailed description (if not obvious:). Note that often only the long form options are accepted as most short form options are ambiguous. If other programs use the same option,but with a different behaviour, then thes other options are not supported. For a list of supported options, please see: $0 --help=alias Following list contains only those options not shown with: $0 --help=alias Tool's Option (Tool) $0 Option #--------------------+---------------+------------------------# * --checks CMD (TLS-Check.pl) same as +CMD * -h, -h=HOST (various tools) same as --host HOST * -p, -p=PORT (various tools) same as --port PORT * -t HOST (ssldiagnos) same as --host HOST * --UDP (ssldiagnos) same as --udp * --timeout, --grep (ssltest.pl) ignored * -r, -s, -t, -x (ssltest.pl) ignored * --insecure (cnark.pl) ignored * --nopct --nocolor (ssldiagnos) ignored * -connect, -H, -u, -url, -U ignored * -noSSL same as --no-SSL * -no_SSL same as --no-SSL #--------------------+---------------+------------------------# For definition of 'SSL' see --SSL and --no-SSL above. Options for customization For general descriptions please see CUSTOMIZATION section below. --cfg_cmd=CMD=LIST --cfg-cmd=CMD=LIST Redefine list of commands. Sets %cfg{cmd-CMD} to LIST. Commands can be written without the leading '+'. If CMD is any of the known internal commands, it will be redifned. If CMD is a unknown command, it will be created. Example: --cfg-cmd=sni="sni hostname" An example +preload can be found in '.$0' . To get a list of commands and their settings, use: $0 --help=intern Main purpose is to reduce list of commands or to print them sorted. --cfg-score=KEY=SCORE Redefine value for scoring. Sets %checks{KEY}{score} to 'SCORE'. Most score values are set to 10 by default. Values '0' .. '100' are allowed. To get a list of current score settings, use: $0 --help=score For deatils how scoring works, please see SCORING section. Use the --trace-key option for the +info and/or +check command to get the values for 'KEY'. --cfg_checks=KEY=TEXT --cfg-checks=KEY=TEXT --cfg_data=KEY=TEXT --cfg-data=KEY=TEXT Redefine texts used for labels in output. Sets %data{KEY}{txt} or %checks{KEY}{txt} to 'TEXT'. To get a list of preconfigured labels, use: $0 --help=cfg-checks $0 --help=cfg-data --cfg-cipher=CIPHER=value Redefine the security value (i.e. HIGH) in the cipher description. Example: --cfg-cipher=NULL-MD5=no-security-at-all --cfg_text=KEY=TEXT --cfg-text=KEY=TEXT Redefine general texts used in output. Sets %text{KEY} to 'TEXT'. To get a list of preconfigured texts, use: $0 --help=cfg-text Note that \n, \r and \t are replaced by the corresponding character when read from RC-FILE. --cfg-text=FILE Read definitions for %text{KEY}="my text" from file 'FILE'. --cfg-hint=KEY=TEXT Redefine texts used for hints. Sets %cfg{hints}{KEY} to 'TEXT'. To get a list of preconfigured texts, use: $0 --help=cfg-hint --cfg-init=KEY=VALUE Set the internal %cfg hash. This options is intended for testing and debugging only. Please see TESTING below. --call=METHOD See X&Options for SSL tool&. --usr Execute functions defined in o-saft-usr.pm. --usr-* --user-* Options ignored, but stored as is internal in $cfg{usr-args} . These options can be used in o-saft-usr.pm or o-saft-dbx.pm. --experimental Use experimental functionality. Some functionality of this tool is under development and only used when this option is given. Options for tracing and debugging --n Do not execute, just show commands (only useful in conjunction with using openssl). Difference --trace vs. --v While --v is used to print more data, --trace is used to print more information about internal data such as procedure names and/or variable names and program flow. --v --verbose Print more information about checks. Note that this option should be first otherwise some debug messages are missing. Note that --v is different from -v (see above). --v --v Print remotely checked ciphers. --v-cipher --cipher-v Print remotely checked ciphers. In contrast to --v --v above, this just prints the ciphers while while being checked, but no other verbose messages. # following no longer implemented (8/2016) # # --v --v --v # # Print remotely checked ciphers one per line. # # --v --v --v --v # # Print processed ciphers (check, skip, etc.). # --trace Print debugging messages. --trace --trace Print more debugging messages and pass 'trace=2' to Net::SSLeay and Net::SSLinfo. --trace --trace --trace Print more debugging messages and pass 'trace=3' to Net::SSLeay and Net::SSLinfo. --trace --trace --trace --trace Print processing of all command line arguments. --trace-cli Print complete command line first. Used for internal testing. --trace-arg --trace-- Print command line argument processing. # cannot use --trace= 'cause = will be removed (CGI mode) --trace-cmd Trace execution of command processing (those given as +*). --trace-key --trace@ Print some internal variable names in output texts (labels). Variable names are prefixed to printed line and enclosed in # . Example without --trace-key : Certificate Serial Number: deadbeef Example with --trace-key : #serial# Certificate Serial Number: deadbeef --trace-time Prints trace output with timestamps. More timestamps are printed if used together with --trace-cmd. --trace=VALUE Alias for --trace-VALUE options (see above). Trace Option Alias Option #--------------------+----------------------------# * --trace=1 same as --trace * --trace=2 same as --trace --trace * --trace=arg same as --trace-arg * --trace=cmd same as --trace-cmd * --trace=key same as --trace-key * --trace=time same as --trace-time --trace=FILE Use FILE instead of the default RC-FILE, i.e. '.$0'. --trace-me Print debugging messages for $0 only, but not any modules. --trace-not-me Print debugging messages for modules only, but not $0 itself. --trace-sub +traceSUB Print formatted list of internal functions with their description. Not to be intended in conjunction with any target check. --hint Print hint messages (!!Hint:). --no-hint Do not print hint messages (!!Hint:). --warning Print warning messages (**WARNING:). --no-warning Do not print warning messages (**WARNING:). --exit=KEY Terminate $0 at specified 'KEY'. Please see TESTING below. Options vs. Commands For compatibility with other programs and lazy users, some arguments looking like options are silently taken as commands. This means that --THIS becomes +THIS then. These options are: * --help * --abbr * --todo * --chain * --default * --fingerprint * --list * --version Take care that this behaviour may be removed in future versions as it conflicts with those options and commands which actually exist, like: --sni vs. +sni LAZY SYNOPSIS Commands Following strings are treated as a command instead of target names: * ciphers * s_client * version A warning will be printed. Options We support following options, which are all identical, for lazy users and for compatibility with other programs. Option Variants * --port PORT * --port=PORT This applies to most such options, --port is just an example. When used in the RC-FILE, the --OPTION=VALUE variant must be used. # does not apply to --trace option Option Names Dash '-', dot '.' and/or underscore '_' in option names are optional, all following are the same: * --no.dns * --no-dns * --no_dns * --nodns This applies to all such options, --no-dns is just an example. Targets Following syntax is supported also: $0 http://some.tld other.tld:3889/some/path?a=b Note that only the hostname and the port are used from an URL. Options vs. Commands See X&Options vs. Commands& in OPTIONS section above CHECKS All SSL related check performed by the tool will be described here. General Checks Lookup the IP of the given hostname (FQDN), and then tries to reverse resolve the FQDN again. SSL Ciphers Check which ciphers are supported by target. Please see RESULTS for details of this check. SSL Connection heartbeat Check if "heartbeat" extension is supported by target. poodle Check if target is vulnerable to POODLE attack (SSLv3 enabled). robot Check if target is vulnerable to ROBOT attack (server offers ciphers with RSA encryption). sloth Check if target is vulnerable to SLOTH attack (server offers RSA-MD5 or ECDSA-MD5 ciphers). sweet32 Check if target is vulnerable to Sweet32 attack (server offers CBC or CBC3 or DES or 3DES ciphers). Note that FIPS-140 compliance requires 3DES ciphers, hence compliant systems are then vulnerable to Sweet32 attacks. ALPN Check if target supports ALPN. Following messages are evaluated: ALPN protocol: h2-14 No ALPN negotiated Please see also CHECKS ALPN and NPN below. SSL Vulnerabilities ADH Check if ciphers for anonymous key exchange are supported: ADH|DHA. Such key exchanges can be sniffed. EDH Check if ephemeral ciphers are supported: DHE|EDH. They are necessary to support Perfect Forward Secrecy (PFS). BEAST Check if ciphers with CBC for protocol SSLv1, SSLv3 or TLSv1 are used. TLSv1.2 checks are not yet implemented. CRIME Connection is vulnerable if target supports SSL-level compression, or supports SPDY/3 (because SPDY/3 uses compression). See http://zoompf.com/2012/09/explaining-the-crime-weakness-in-spdy-and-ssl Note: SPDY/3 is only possible if the client explicitely asks for this alternate protocol (for example "openssl ... -nextprotoneg spdy/3"). DROWN Connection is vulnerable if target supports SSLv2. FREAK Attack against SSL/TLS to downgrade to EXPORT ciphers. Currently (2018) a simple check is used: SSLv3 enabled and EXPORT ciphers supported by server. See CVE-2015-0204 and https://freakattack.com/ . HEARTBLEED Check if target is vulnerable to heartbleed attack, see CVE-2014-0160 and http://heartbleed.com/ . HEIST Not implemented. There are no checks for the HEIST attack implemented, because this is an attack on TCP/IP rather than SSL/TLS on top of TCP/IP. KCI To perform a MiTM attack with Key Compromise Impersonation, the atta- cker needs to engage the victim to install and use a client certificate. This is considered a low risk and hence not tested here. Logjam Check if target is vulenerable to Logjam attack. Check if target suports EXPORT ciphers and/or DH Parameter is less than 2048 bits. ECDH must be greater to 511 bits. Lucky13 Check if CBC ciphers are offered. NOTE the recommendation to be safe against Lucky13 was to use RC4 ciphers. But they are also subject to attacks (see below). Hence the check is only for CBC ciphers. RC4 Check if RC4 ciphers are supported. They are assumed to be broken. Note that +rc4 reports the vulnerabilitiy to the RC4 Attack, while +cipher-rc4 simply reports if RC4 ciphers are offered. However the check, and hence the result, is the same. PFS Check if DHE ciphers are used. Checks also if the TLS session ticket is random or not used at all. TLSv1.2 checks are not yet implemented. POODLE Check if target is vulnerable to POODLE attack (just check if SSLv3 is enabled). Practical Invalid Curve Attack This attack allows an attacker to read the servers private key if the server does not check properly the passed points for a ecliptic curve when EDH ciphers are used. This check will not send multiple invalid points, but only checks if the server closes the connection or responds with no matching cipher. ROBOT Bleichebacher's Oracle attack against SSL/TLS ciphers. Not implemented. https://robotattack.org/ # SKIP # # Check if target is vulnerable to SKIP attack. # Message Skipping Attacks on TLS. Attack to force server or client to # skip messages in handshake protocol, SLOTH Currently (2016) we check for ciphers with ECDSA, RSA-MD5. Checking the TLS extension 'tls-unique' is not yet implemented. Sweet32 Currently (2016) we check for ciphers with CBC or CBC3 or DES or 3DES. Ticketbleed NOT YET IMPLEMENTED Check if target is vulnerable to ticketbleed, means that it returns up to 31 random bytes from memory as Session Ticket, see CVE-2016-9244 and https://filippo.io/Ticketbleed/ . Target (server) Configuration and Support BEAST, BREACH, CRIME, DROWN, FREAK, Logjam, Lucky13, POODLE, RC4, ROBOT, SLOTH, Sweet32 See above. Renegotiation Check if the server allows client-side initiated renegotiation. # This is known as "Secure Renegotiation". Version rollback attacks NOT YET IMPLEMENTED Check if the server allows changing the protocol. DH Parameter Check if target's DH Parameter is less 512 or 2048 bits. Target (server) Certificate Certificate Hashes Check that fingerprint is not MD5. Check that certificate private key signature is SHA2 or better. Root CA Provided certificate by target should not be a Root CA. Self-signed Certificate Certificate should not be self-signed. FQDN is listed in subjectAltname (RFC2818) The FQDN must be listed in the certificates subjectAltname. The check command +rfc_2818_names is based on the info command +verify_hostname . The check was added in 05/2017 because browsers started to complain if the FQDN is not part of the subjectAltname. IP in CommonName or subjectAltname (RFC6125) NOT YET IMPLEMENTED Basic Constraints Certificate extension Basic Constraints should be CA:FALSE. # otherwise someone can generate an intermediate cert OCSP, CRL, CPS Certificate should contain URL for OCSP and CRL. Private Key encyption Certificates signature key supports encryption. Private Key encyption well known Certificates signature key encryption algorithm is well known. Public Key encyption Certificates public key supports encryption. Public Key encyption well known Certificates public key encryption algorithm is well known. Public Key Modulus size Some (historic) SSL implementations are subject to buffer overflow if #bad# the key exceeds 16384 or 32768 bits. The check is against 16384 bits. Public Key Modulus Exponent size The modulus exponent should be = 65537 as it is a prime number and an easy to calculate exponent. If the exponent is less than 65537, "Boradcast" attacks are possible. However, some (mainly historic) SSL implementations may have problems to connect because they are not able to do the crypt mathematics with exponenents larger than 65536. # if > 65536 then all clients usisng MS-SSL-stack will fail to connect If ecliptive curves are used, the result for these checks is always 'no (< 1 year * +modulus_exp_1 - Public Key Modulus Exponent <>1 * +modulus_exp_65537 - Public Key Modulus Exponent =65537 * +modulus_exp_oldssl - Public Key Modulus Exponent <65537 * +modulus_size_oldssl - Public Key Modulus <16385 bits For some details of these cjecks, please see the description above at Public Key Modulus Exponent size The recommendations for DH parameters (RSA and ecliptice curve) are are checked as follows: * +dh_512 - DH Parameter >= 512 bits * +dh_2048 - DH Parameter >= 2048 bits * +ecdh_256 - DH Parameter >= 256 bits (ECDH) * +ecdh_512 - DH Parameter >= 512 bits (ECDH) Note that only one of the checks '+dh_*' and '+ecdh_*' can return 'yes'. ALPN and NPN The commands for the checks to report 'yes' or 'no', are +hasalpn and +hasnpn. Both, the Application Layer Protocol Negotiation (ALPN) and the Next Protocol Negotiation (NPN) will be tested. The commands for that are: * +alpns * +npns Each, ALPN and NPN, is tested separately with all known protocols. The test sets only one protocol, tries to make a connection and then checks if the protocol was accepted by the server. The collected list of protocols will be printed with the aforementioned commands, or the +info command. Note the difference for the commands +next_protocols and +alpns, where +next_protocols simply reports what the server itself advertises, while +alpns reports what the server supports if asked for. Compliances Note that it is not possible to satisfy all following compliances. Best match is: 'PSF' and 'ISM' and 'PCI' and 'lazy BSI TR-02102-2'. # example: fancyssl.hboeck.de In general it is difficult to satisfy all conditions of a compliance, and it is also difficult to check all these conditions. That is why some compliance checks are not completely implemented. For details see below please. Also note that in the RC-FILE the output of results for some checks is disabled by default. A '!!Hint:' message will be printed, if any of these checks are used. * FIPS-140 * ISM * PCI * BSI TR-02102-2 (2016-01) * BSI TR-03116-4 * RFC 2818 * RFC 6125 * RFC 6797 * RFC 7525 # NSA Suite B BSI TR-02102-2 (+tr-02102+ +tr-02102- +bsi) Checks if connection and ciphers are compliant according TR-02102-2, see https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen /TechnischeRichtlinien/TR02102/BSI-TR-02102-2_pdf.pdf?__blob=publicationFile (following headlines are taken from TR-02102-2 Version 2016-01) 3.1.3 Schlüssellängen bei EC-Verfahren die EC-Verfahren ... und weitere Erläuterungen siehe Bemerkung 4 in Kapitel 3 in [TR-02102-1] . 3.2 SSL/TLS_Versionen Only TLSv1.2 allowed (except for +tr-02102- which also allows TLSv1.1) 3.3.1 Empfohlene Cipher Suites Allows only *DHE-*-SHA256, *DHE-*-SHA384, *DH-*-SHA256 and *DH-*-SHA384 ciphers and PSK ciphers with ephermeral keys. For +tr-02102+ they must be AES-GCM, +tr02102- also allows AES-CBC. 3.3.2 Übergangsregelungen SHA1 temporary allowed. SHA256 and SHA384 recommended. RC4 not reocmmended. Use of SHA1 will only be checked for +tr-02102+ 3.4.1 Session Renegotation Only server-side (secure) renegotiation allowed (see RFC 5746). 3.4.2 Verkürzung der HMAC-Ausgabe Truncated HMAC according RFC 6066 not recommended. 3.4.3 TLS-Kompression und der CRIME-Angriff No TLS compression. 3.4.4 Der Lucky13-Angriff 3.4.5 Die "Encrypt-then-MAC"-Erweiterung Use of AES-GCM ciphers only. Use of Encrypt-then-MAC according RFC 7366 cannot be checked. 3.4.6 Die Heartbeat-Erweiterung Target must not support the heartbeat extension. 3.4.7 Die Extended Master Secret Extension Use of Extended Master Secret Extension according RFC 7627 cannot be checked. 3.5 Authentisierung der Kommunikationspartner Not checked as only applicable for VPN connections. 3.6 Domainparameter und Schlüssellängen Check if signature key is > 2048 bits. # --------------+---------------+-------- # Minimale # Algorithmus Schlüssellänge Verwendung bis # --------------+---------------+-------- # Signaturschlüssel für Zertifikate und Schlüsseleinigung # ECDSA 224 Bit 2015 # ECDSA 250 Bit 2022+ # DSS 2000 Bit 2022+ # RSA 2000 Bit 2022+ # Statische Diffie-Hellman Schlüssel # ECDH 224 Bit 2015 # ECDH 250 Bit 2022+ # DH 2000 Bit 2022+ # Ephemerale Diffie-Hellman Schlüssel # ECDH 224 Bit 2015 # ECDH 250 Bit 2022+ # DH 2000 Bit 2022+ # --------------+---------------+-------- 3.6.1 Verwendung von elliptischen Kurven **NOT YET IMPLEMENTED** Use only following curves according RFC 5639 and RFC 7027: brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 Use of secp256r1 and secp384r1 temporary allowed. 4.1 Schlüsselspeicherung This requirement is not testable from remote. 4.2 Umgang mit Ephemeralschlüsseln This requirement is not testable from remote. 4.3 Zufallszahlen This requirement is not testable from remote. BSI TR-03116-4 (+tr-03116+ +tr-03116- +bsi) Checks if connection and ciphers are compliant according TR-03116-4, see https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen /TechnischeRichtlinien/TR03116/BSI-TR-03116-4.pdf?__blob=publicationFile (following headlines are taken from there) 2.1.1 TLS-Versionen und Sessions Allows only TLS 1.2. 2.1.2 Cipher Suites Cipher suites must be ECDHE-ECDSA or -RSA with AES128 and SHA265. For curiosity, stronger cipher suites with AES256 and/or SHA384 are not not allowed. To follow this curiosity the +tr-03116- (lazy) check allows the stronger cipher suites ;-) 2.1.1 TLS-Versionen und Sessions The TLS session lifetime must not exceed 2 days. 2.1.4.2 Encrypt-then-MAC-Extension 2.1.4.3 OCSP-Stapling MUST have 'OCSP Stapling URL'. 4.1.1 Zertifizierungsstellen/Vertrauensanker Certificate must provide all root CAs. (NOT YET IMPLEMENTED). Should use a small certificate trust chain. 4.1.2 Zertifikate Must have 'CRLDistributionPoint' or 'AuthorityInfoAccess'. End-user certificate must not be valid longer than 3 years. Root-CA certificate must not be valid longer than 5 years. Certificate extension 'pathLenConstraint' must exist, and should be a small value ("small" is not defined). All certificates must contain the extension 'KeyUsage'. Wildcards for 'CN' or 'Subject' or 'SubjectAltName' are not allowed in any certificate. EV certificates are recommended (NOT YET checked properly). 4.1.3 Zertifikatsverifikation Must verify all certificates in the chain down to their root-CA. (NOT YET IMPLEMENTED). Certificate must be valid according issue and expire date. All Checks must be doen for all certificates in the chain. 4.1.4 Domainparameter und Schlüssellängen This requirement is not testable from remote. 4 5.2 Zufallszahlen This requirement is not testable from remote. RFC 2818 (+rfc2818) Check if the FQDN is listed in the certificates 'subjectAltname'. RFC 6125 (+rfc6125) Checks values 'CommonName', 'Subject' and 'SubjectAltname' of the certificate for: * must all be valid characters for DNS * must not contain more than one wildcard * must not contain invalid wildcards * must not contain invalid IDN characters RFC 6797 (+rfc6797) Same as STS header +hsts . RFC 7525 (+rfc7525) Checks if connection and ciphers are compliant according RFC 7525. See http://tools.ietf.org/rfc/rfc7525.txt (following headlines are taken from there) 3.1.1. SSL/TLS Protocol Versions SSLv2 and SSLv3 must not be supportetd. TLSv1 should only be supported if there is no TLSv1.1 or TLSv1.2. Either TLSv1.1 or TLSv1.2 must be supported, prefered is TLSv1.2. 3.1.2. DTLS Protocol Versions DTLSv1 and DTLSv1.1 must not be supported. 3.1.3. Fallback to Lower Versions (check implecitely done by 3.1.1, see above) 3.2. Strict TLS Check if server provides Strict Transport Security. ('STARTTLS' check NOT YET IMPLEMENTED). 3.3. Compression Compression on TLS must not be supported. 3.4. TLS Session Resumption Server must support resumtion and random session tickets. (Randomnes of session tickets implemented YET experimental.) Check if ticket is authenticated and encrypted NOT YET IMPLEMENTED. 3.5. TLS Renegotiation Server must support renegotiation. 3.6. Server Name Indication (Check for SNI support implemented experimental.) 4. Recommendations: Cipher Suites 4.1. General Guidelines 4.2. Recommended Cipher Suites Check for recommended ciphers. 4.3. Public Key Length DH parameter must be at least 256 bits or 2048 bits with EC. (Check currently, 4/2016, based on openssl which may not provide DH parameters for all ciphers.) 4.5. Truncated HMAC TLS extension "truncated hmac" must not be used. 6. Security Considerations 6.1. Host Name Validation Given hostname must matches hostname in certificate's subject. 6.2. AES-GCM 6.3. Forward Secrecy 6.4. Diffie-Hellman Exponent Reuse (NOT YET IMPLEMENTED). 6.5. Certificate Revocation OCSP and CRL Distrbution Point in cetificate must be defined. # score will be removed, so don't anounce it #SCORING # # Coming soon ... OUTPUT All output is designed to make it easily parsable by postprocessors. Following rules are used: * Lines for formatting or header lines start with '='. * Lines for verbosity or tracing start with '#'. * Errors and warnings start with '**'. * Empty lines are comments ;-) * Label texts end with a separation character; default is ':'. * Label and value for all checks are separated by at least one TAB character. * Texts for additional information are enclosed in '<<' and '>>'. * 'N/A' is used when no proper informations was found or provided. Replace 'N/A' by whatever you think is adequate: "No answer", "Not available", "Not applicable", ... Lines not described above, will have the form (by default): Label for information or check: TABresult For more details on these lines, please refer to RESULTS above. When used in --legacy=full or --legacy=simple mode, the output may contain formatting lines for better (human) readability. Postprocessing Output It is recommended to use the --legacy=quick option, if the output should be postprocessed, as it omits the default separation character (':' , see above) and just uses on single tab character (0x09, \t or TAB) to separate the label text from the text of the result. Example: Label of the performed checkTABresult More examples for postprocessing the output can be found here: https://github.com/OWASP/O-Saft/blob/master/contrib # Overview of Special Formattings # #----------------------+---------------+---------------- # | label has # +cmd and/or --legacy=* | : spaces TAB # #----------------------+-------+-------+---------------- # --legacy=simple | yes yes yes # --legacy=compact | yes no no # --legacy=quick | no no yes # +quick | yes yes yes # #----------------------+-------+-------+---------------- CUSTOMIZATION This tools can be customized as follows: * Using command line options This is a simple way to redefine specific settings. Please see CONFIGURATION OPTIONS below. * Using Configuration file A configuration file can contain multiple configuration settings. Syntax is simply KEY=VALUE. Please see CONFIGURATION FILE below. * Using resource files A resource file can contain multiple command line options. Syntax is the same as for command line options iteself. Each directory may contain its own resource file. Please see RC-FILE below. * Using debugging files These files are - nomen est omen - used for debugging purposes. However, they can be (mis-)used to redefine all settings too. Please see DEBUG-FILE below. * Using user specified code This file contains user specified program code. It can also be (mis-)used to redefine all settings. Please see USER-FILE below. Customization is done by redefining values in internal data structure which are: %cfg, %data, %checks, %text, %scores. Unless used in DEBUG-FILE or USER-FILE, there is no need to know these internal data structures or the names of variables; the options will set the proper values. The key names being part of the option, are printed in output with the --trace-key option. I.g. texts (values) of keys in %data are those used in output of the "Information" section. Texts of keys in %checks are used for output in "Performed Checks" section. And texts of keys in %text are used for additional information lines or texts (mainly beginning with '='). Configuration File vs. RC-FILE vs. DEBUG-FILE * CONFIGURATION FILE Configuration files must be specified with one of the --cfg-* options. The specified file can be a valid path. Please note that only the characters: a-zA-Z_0-9,.\/()- are allowed as pathname. Syntax in configuration file is: 'KEY=VALUE' where 'KEY' is any key as used in internal data structure. * RC-FILE Resource files are searched for and used automatically. For details see RC-FILE below. * DEBUG-FILE Debug files are searched for and used automatically. For details see DEBUG-FILE below. * USER-FILE The user program file is included only if the --usr option was used. For details see USER-FILE below. CONFIGURATION OPTIONS Configuration options are used to redefine texts and labels or score settings used in output. The options are: * --cfg-cmd=CMD=LIST * --cfg-checks=KEY=TEXT * --cfg-data=KEY=TEXT * --cfg-hint=KEY=TEXT * --cfg-text=KEY=TEXT * --cfg-cipher=CIPHER=TEXT 'KEY' is the key used in the internal data structure, and 'TEXT' is the value to be set for this key. Note that unknown keys are ignored silently. If KEY=TEXT is an exiting filename, all lines from that file are read and set. For details see CONFIGURATION FILE below. CIPHER must be a valid cipher suite name as shown with: $0 ciphers NOTE that such configuration options should be used before any --help or --help=* option, otherwise the changed setting is not visible. CONFIGURATION FILE Note that the file can contain 'KEY=TEXT' pairs for any kind of the configuration as given by the --cfg-CFG option. For example when used with --cfg-text=FILE only values for %text will be set, when used with --cfg-data=FILE only values for %data will be set, and so on. 'KEY' will not be used when 'KEY=TEXT' is an existing filename. It i recommended to use a non-existing key, i.e.: --cfg-text=my_file=some/path/to/private/file . RC-FILE The rc-file will be searched for in the working directory only. The name of the rc-file is the name of the program file prefixed by a '.' (dot), for example: '.$0'. A rc-file can contain any of the commands and options valid for the tool itself. The syntax for them is the same as on command line. Each command or option must be in a single line. Any empty or comment line will be ignored. Comment lines start with '#' or '='. Note that options with arguments must be used as 'KEY=VALUE' instead of 'KEY VALUE'. Configurations options must be written like '--cfg-CFG=KEY=VALUE'. Where 'CFG' is any of: 'cmd', 'check', 'data', 'text' and 'KEY' is any key from internal data structure (see above). All commands and options given on command line will overwrite those found in the rc-file. DEBUG-FILE All debugging functionality is defined in o-saft-dbx.pm , which will be searched for using paths available in '@INC' variable. Syntax in this file is perl code. For details see DEBUG below. USER-FILE All user functionality is defined in o-saft-usr.pm , which will be searched for using paths available in '@INC' variable. Syntax in this file is perl code. All functions defined in o-saft-usr.pm are called when the option --usr was given. The functions are defined as empty stub, any code can be inserted as need. Please see perldoc o-saft-usr.pm to see when and how these functions are called. SHELL TWEAKS Configuring the shell environment where the tool is startet, must be done before the tools starts. It is not really a task for the tool itself, but it can simplify your life, somehow. There exist customizations for some commonly used shells, please see the files in the ./contrib/ directory. COMMANDS The option --cfg-cmd=CMD=LIST can be used to define own commands. When configuring own commands, CMD must not be one of the commands listed with --help=intern and CMD must constist only of digits and letters. Examples in '.$0' are +preload and +ciphercheck . CIPHER NAMES While the SSL/TLS protocol uses integer numbers to identify ciphers, almost all tools use some kind of "human readable" texts for cipher names. These numbers (which are most likely written as hex values in source code and documentations) are the only true identifier, and we have to rely on the tools that they use the proper integers. As such integer or hex numbers are difficult to handle by humans, we decided to use human readable texts. Unfortunately no common standard exists how to construct the names and map them to the correct number. Some, but by far not all, oddities are described in X&Name Rodeo&. The rules for specifying cipher names are: 1) textual names as defined by IANA (see [IANA]) 2) mapping of names and numbers as defined by IANA (see [IANA]) 3) '-' and '_' are treated the same 4) abbreviations are allowed, as long as they are unique 5) beside IANA, openssl's cipher names are preferred 6) name variants are supported, as long as they are unique 7) hex numbers can be used [IANA] http://www.iana.org/assignments/tls-parameters/tls-parameters.txt September 2013 [openssl] ... openssl 1.0.1 If in any doubt, use +list --v to get an idea about the mapping. Use --help=regex to see which regex are used to handle all variants herein. Mind the traps and dragons with cipher names and what number they are actually mapped to. In particular when --lib, --exe or --openssl options are in use. Always use these options with +list command too. Name Rodeo As said above, the SSL/TLS protocol uses integer numbers to identify ciphers, but almost all tools use some kind of human readable texts for cipher names. For example the cipher commonly known as 'DES-CBC3-SHA' is identified by '0x020701c0' (in openssl) and has 'SSL2_DES_192_EDE3_CBC_WITH_SHA' as constant name. A definition is missing in IANA, but there is 'TLS_RSA_WITH_3DES_EDE_CBC_SHA'. Thers is also '0x000A' for the same cipher 'DES-CBC3-SHA'. Both are valid, first one if used with SSLv2, and second one when used with SSLv3. It's the responsibility of each tool to map the human readable cipher name to the correct (hex, integer) identifier. For example Firefox uses 'dhe_dss_des_ede3_sha', which is what? Furthermore, there are different acronyms for the same thing in use. For example 'DHE' and 'EDH' both mean "Ephemeral Diffie-Hellman". Comments in the openssl(1) sources mention this. And for curiosity these sources use both in cypher names, but allow 'EDH' as shortcut only in openssl's "ciphers" command. Wonder about (up to 1.0.1h): openssl ciphers -V EDH openssl ciphers -V DHE openssl ciphers -V EECDH openssl ciphers -V ECDHE Next example is 'ADH' which is also known as 'DH_anon' or 'DHAnon' or 'DHA' or 'ANON_DH'. You think this is enough? Then have a look how many acronyms are used for "Tripple DES". Compared to above, the interchangeable use of '-' vs. '_' in human readable cipher names is just a very simple one. However, see openssl again what following means (returns): openssl ciphers -v RC4-MD5 openssl ciphers -v RC4+MD5 openssl ciphers -v RC4:-MD5 openssl ciphers -v RC4:!MD5 openssl ciphers -v RC4!MD5 Looking at all these oddities, it would be nice to have a common unique naming scheme for cipher names. We have not. As the SSL/TLS protocol just uses a number, it would be natural to use the number as uniq key for all cipher names, at least as key in our internal sources. Unfortunately, the assignment of ciphers to numbers changed over the years, which means that the same number refers to a different cipher depending on the standard, and/or tool, or version of a tool you use. As a result, we cannot use human readable cipher names as identifier (aka unique key), as there are to many aliases for the same cipher. And also the number cannot be used as unique key, as a key may have multiple ciphers assigned. The default behaviour will be to use the cipher names like openssl(1) does. If a name is ambigous, the first matching will be choosen. This -first matching- only applies to names provided by the user by option or whatever, internally the latest IANA number will be used, because they have the most less ambiguities. KNOWN PROBLEMS This section describes knwon problems, and known error messages which may occour when using $0. This sections can be used as FAQ too as it gives hints and workarounds. Segmentation fault Sometimes the program terminates with a 'Segmentation fault'. This mainly happens if the target does not return certificate information. If so, the --no-cert option may help. **WARNING: empty result from openssl; ignored at ... This most likely occurs when the provided cipher is not accepted by the server, or the server expects client certificates. **WARNING: unknown result from openssl; ignored at ... This most likely occurs when the openssl(1) executable is used with a very slow connection. Typically the reason is a connection timeout. Try to use --timeout=SEC option. To get more information, use --v --v and/or --trace also. **WARNING: undefined cipher description May occour if ciphers are checked, but no description is available for them herein. This results in printed cipher checks like: EXP-KRB5-RC4-MD5 no <> instead of: EXP-KRB5-RC4-MD5 no weak **WARNING: Can't make a connection to your.tld:443; no initial data **WARNING: Can't make a connection to your.tld:443; target ignored This message occours if the underlaying SSL library (i.e. libssl.a) was not able to connect to the target. Known observed reasons are: * target does not support SSL protocol on specified port * target expects a client certificate in ClientHello message More details why the connection failed can be seen using --trace=2 . If the targets supports SSL, it should be at least possible to check for supported ciphers using +cipherall instead of +cipher . Use of uninitialized value $headers in split ... do_httpx2.al) The warning message (like follows or similar): Use of uninitialized value $headers in split at blib/lib/Net/SSLeay.pm (autosplit into blib/lib/auto/Net/SSLeay/do_httpx2.al) line 1290. occurs if the target refused a connection on port 80. This is considered a bug in Net::SSLeay(1). Workaround to get rid of this message: use --no-http option. invalid SSL_version specified at ... IO/Socket/SSL.pm This error may occur on systems where a specific SSL version is not supported. Subject are mainly SSLv2, SSLv3 TLSv1.3 and DTLSv1. For DTLSv1 the full message looks like: invalid SSL_version specified at C:/programs/perl/perl/vendor/lib/IO/Socket/SSL. See also X&Note on SSL versions& . Workaround: use option: --no-sslv2 --no-sslv3 --no-tlsv13 --no-dtlsv1 Use of uninitialized value $_[0] in length at (eval 4) line 1. This warning occours with IO::Socket::SSL 1.967, reason is unknown. It seems not to harm functionality, hence no workaround, just ignore. Use of uninitialized value in subroutine entry at lib/IO/Socket/SSL.pm line 430. Some versions of IO::Socket::SSL return this error message if *-MD5 ciphers are used with other protocols than SSLv2. Workaround: use --no-md5-cipher option. Can't locate auto/Net/SSLeay/CTX_v2_new.al in @INC ... Underlaying library doesn't support the required SSL version. See also X&Note on SSL versions& . Workaround: use --ssl-lazy option, or corresponding --no-SSL option. Read error: Connection reset by peer (,199725) at blib/lib/Net/SSLeay.pm\ (autosplit into blib/lib/auto/Net/SSLeay/tcp_read_all.al) line 535. Error reported by some Net::SSLeay versions. Reason may be a timeout. This error cannot be omitted or handled properly. Workaround: try to use same call again (no guarantee, unfortunatelly) # see Net::SSLinfo.pm for details Odd number of elements in anonymous hash at Net/SSLinfo.pm line 1613. This warning from perl have been observed when the connection to the target to check for supported ciphers cannot be established. This message can be ignored. openssl: ...some/path.../libssl.so.1.0.0: no version information available (required by openssl) Mismatch of openssl executable and loaded underlaying library. This most likely happens when options --lib=PATH and/or --exe=PATH are used. See also X&Note on SSL versions& . Hint: use following commands to get information about used libraries: $0 +version $0 --v --v +version Integer overflow in hexadecimal number at ... This error message may occour on 32-bit systems if perl was not com- piled with proper options. I.g. perl automatically converts the value to a floating pont number. Please report a bug with output of following command: $0 +s_client +dump your.tld openssl did not return DH Paramter>> Text may be part of a value. This means that all checks according DH parameters and logkam attack cannot be done. Workaround: try to use --openssl=TOOL option. This text may appears in any of the compliance checks (like +rfc7525) which may be a false positive. For these checks openssl is also used to get the DH Parameter. Workaround: not available yet No output with +help and/or --help=todo On some (mainly Windows-based) systems using $0 +help $0 --help does not print anything. Workaround: use --v option. $0 +help --v or $0 +help | more Character set (like UTF-8) not recognized in some tools Some tools do not diplay all characters properly, i.e. some versions of podviewer. It is not the obligation of this tool to fix well known bugs in other tools. However, we can offer workarounds. Workaround: generate the affected output using --std-format=* options For example: $0 --no-rc --std-format=raw --help=gen-pod **WARNING: on MSWin32 additional option --v required, sometimes ... On some (mainly Windows-based) systems this may happen when calling for example: $0 --help=FAQ which then may produce: **WARNING: on MSWin32 additional option --v required, sometimes ... === reading: ./.o-saft.pl (RC-FILE done) === === reading: Net/SSLinfo.pm (O-Saft module done) === **USAGE: no command given # most common usage: o-saft.pl +info your.tld o-saft.pl +check your.tld o-saft.pl +cipher your.tld # for more help use: o-saft.pl --help Workaround: use full path to perl.exe, for example C:\Programs\perl\bin\perl.exe $0 --help=FAQ Performance Problems There are various reasons when the program responds slow, or seems to hang. Performance issues are most likely a target-side problem. Most common reasons are (no specific order): a) DNS resolver problems Try with --no-dns b) target does not accept connections for https Try with --no-http c) target's certificate is not valid Try with --no-cert d) target expects that the client provides a client certificate No option provided yet ... e) target does not handle Server Name Indication (SNI) Try with --no-sni f) use of external openssl(1) executable Use --no-openssl g) target does not respond at all and/or blocks Use --ssl-error For a detailed description, please see X&Connection Problems&. Other options which may help to get closer to the problem's cause: --trace-time, --timeout=SEC, --trace, --trace-cmd Using --trace-time should show following times: * DNS: 1 - 10 sec * need_default: <5 sec * need_cipher: 1 - 299 sec (+cipher with socket) * need_cipher: 1 - 20 sec (+cipherraw) * no SNI: 1 - 10 sec * connection test: 1 - 5 sec * prepare checks: 2 - 20 sec * checkalpn. 1 - 15 sec * checkprot. 1 - 15 sec * cipher: <1 sec * info: <1 sec * check: <1 sec LIMITATIONS Commands Some commands cannot be used together with others, for example: +cipher, +ciphers, +list, +libversion, +version, +check, +help, +protocols . +quick should not be used together with other commands, it returns strange output then. It is the only command which allows +cipher together with other commands. +protocols requires openssl(1) with support for '-nextprotoneg' option. Otherwise the value will be empty. Options The option --port=PORT must preceed --host=HOST for a target like HOST:PORT . The characters '+' and '=' cannot be used for --separator=CHAR option. Following strings should not be used in any value for options: '+check', '+info', '+quick', '--header' as they my trigger the --header option unintentional. The used timeout(1) command cannot be defined with a full path like openssl(1) can with the --openssl=path/to/openssl . --cfg-text=FILE cannot be used to redefine the texts 'yes' and 'no' as used in the output for +cipher command. Checks (general) +constraints This check is only done for the certificate provided by the target. All other certificate in the chain are not checked. This is currently (2018) a limitation in $0. Broken pipe This error message most likely means that the connection to specified target was not possible (firewall or whatever reason). Target Certificate Chain Verification The systems default capabilities i.e. libssl.so, openssl, are used to verify the target's certificate chain. Unfortunately various systems have implemented different approaches and rules how identify and how to report a successful verification. As a consequence this tool can only return the same information about the chain verification as the used underlying tools. If that information is trustworthy depends on how trustworthy the tools are. These limitations apply to following commands: * +verify * +selfsigned Following commands and options are useful to get more information: * +chain_verify, +verify, +error_verify, +chain, +s_client * --ca-file, --ca-path, --ca-depth User Provided Files Please note that there cannot be any guarantee that the code provided in the DEBUG-FILE o-saft-dbx.pm or USER-FILE o-saft-usr.pm will work flawless. Obviously this is the user's responsibility. Problems and Errors Checking the target for supported ciphers may return that a cipher is not supported by the server misleadingly. Reason is most likely an improper timeout for the connection. See --timeout=SEC option. If the specified targets accepts connections but does not speak SSL, the connection will be closed after the system's TCP/IP-timeout. This script will hang (about 2-3 minutes). If reverse DNS lookup fails, an error message is returned as hostname, like: '<>'. Workaround to get rid of this message: use --no-dns option. All checks for EV are solely based on the information provided by the certificate. Some versions of openssl (< 1.x) may not support all required options which results in various error messages, or more worse, may not be visibale at all. Available functionalitity of openssl will be checked for right at the beginning. Proper warnings and hints are printed. Following table shows the openssl option and how to disable it within $0: * -nextprotoneg --no-nextprotoneg * -reconnect --no-reconnect * -tlsextdebug --no-tlsextdebug * -alpn --no-alpn Connection Problems Sometimes the connection cannot be established. This may have various reasons. Unfortunaly this script seems to hang then. In particular when checking for ciphers with +cipher or +cipherall . The reason is most likely that the server does not respond to the TCP/IP request and hence the script closes the connection after the configured time- out (see --timeout=SEC option). Continous connection attempts can be inhibited with the --ssl-error option, which is set by default. Avoiding further connections results in a loss of information and consequentely, leads to wrong checks. It is a trade-off to wait for all information done accurately, or to get the results quickly. The logic to stop connecting for --ssl-error can be controlled with following additional options: * --ssl-error-max=CNT - max. continous errors * --ssl-error-timeout=SEC - treat a failure as error after timeout * --ssl-error-total=CNT - max. amount of errors This means that no more connections are made when more than * --ssl-error-max errors occour sequentialy or * --ssl-error-total errors occoured Examples: * --ssl-error-max=3 * --ssl-error-timeout=6 * --ssl-error-total=6 no more connections are made if for example any sequence of timeouts occour: 0 5 2 2 - --ssl-error-max matches 0 1 3 0 0 0 4 1 2 2 2 - --ssl-error-max matches 0 5 0 2 0 2 2 0 2 0 2 - --ssl-error-total matches This allows to fine-tune the condition when to stop connecting to the target. For example, continous but not consecutive timeouts may indi- cate a bad or instable network connection, but not that the target to be connected blocks. In such a case sequence of timeouts like follows may be observed (assuming --ssl-error-max=3): 0 5 1 2 2 2 4 2 3 2 3 3 3 2 . . . ^ ^____ stop for --ssl-error-timeout=3 . . . |______________________ stop for --ssl-error-timeout=2 On normal (even slow) network connections dozens of connections per second are usual, hence the timeout is always 0 or 1. Based on that experience --ssl-error is enabled and set with defaults as follows: * --ssl-error-max=5 * --ssl-error-timeout=1 * --ssl-error-total=10 Poor Systems Use of openssl(1) is disabled by default on Windows due to various performance problems. It needs to be enabled with --openssl option. On Windows the usage of "openssl s_client" needs to be enabled using --s_client option. On Windows it's a pain to specify a correct path for --openssl=TOOL option. Variants are: * --openssl=/path/to/openssl.exe * --openssl=X:/path/to/openssl.exe * --openssl=\path\to\openssl.exe * --openssl=X:\path\to\openssl.exe * --openssl=\\path\\to\\openssl.exe * --openssl=X:\\path\\to\\openssl.exe You have to fiddle around to find the proper one. Debug and Trace Output When both --trace-key and --trace-cmd options are used, output is mixed, obviously. Hint: output for --trace-cmd always contains "CMD". Any --trace* option implies --trace-time . DEPENDENCIES All perl modules and all private moduels and files will be searched for using paths available in the '@INC' variable. '@INC' will be prepended by following paths: * . * ./lib * INSTALL_PATH * INSTALL_PATH/lib Where 'INSTALL_PATH' is the path where the tool is installed. To see which files have been included use: $0 +version --v --user Perl Modules * IO::Socket::SSL(1) * IO::Socket::INET(1) * Net::SSLeay(1) * Net::SSLinfo * Net::SSLhello Additional files used if requested * .o-saft.pl * o-saft-dbx.pm * o-saft-man.pm * o-saft-usr.pm * o-saft-README * o-saft-docker INSTALLATION The tool can be installed in any path. It just requres the modules as described in DEPENDENCIES above. However, it's recommended that the modules Net::SSLhello and Net::SSLinfo are found in the directory './Net/' where '$0' is installed. For security reasons, most modern libraries disabled or even removed insecure or "dirty" functionality. As the purpose of this tool is to detect such insecure settings, functions, etc., it needs these dirty things enabled. It needs (incomplete list): * insecure protocols like SSLv2, SSLv3 * more ciphers enabled, like NULL-MD5, AECDH-NULL-SHA, etc. * some SSL extensions and options Therefore we recommend to compile and install at least following: * OpenSSL with SSLv2, SSLv3 and more ciphers enabled * Net::SSLeay compiled with openssl version as described before. Please read the SECURITY section first before following the install instructions below. OpenSSL Currently (since 18.06.18) it is recommend to build openssl using contrib/install_openssl.sh Other possibilities are: * compiling openssl using following sources https://github.com/PeterMosmans/openssl/ see X&Example: Compile OpenSSL&, * use any of the precomiled versions provided by https://testssl.sh/ * use Docker owasp/o-saft (which contains a special openssl) The sources are available at * https://github.com/PeterMosmans/openssl/archive/1.0.2-chacha.zip A precomiled static versions are available at * https://github.com/drwetter/testssl.sh/ (see bin directory there) For all following installation examples we assume: * openssl-1.0.2-chacha.zip or openssl-1.0.2d.tar.gz * /usr/local as base installation directory * a bourne shell (sh) compatible shell Example: Precompiled OpenSSL Simply download the tarball or zip file for your platform, unpack it, and install (copy) the binaries into a directory of your choice. Example: Compile OpenSSL OpenSSL can be used from http://openssl.org/ or, as recommended, from https://github.com/PeterMosmans/openssl/ . OpenSSL-chacha Compiling and installing the later is as simple as: unzip openssl-1.0.2-chacha.zip cd openssl-1.0.2-chacha ./config --shared -Wl,-rpath=/usr/local/lib make make test make install which will install openssl, libssl.so, libcrypto.so and some include files as well as the include files in /usr/local/ . The shared version of the libraries are necessary for Net::SSLeay. OpenSSL.org Building openssl from the offical openssl.org sources requires some patching before compiling and installing the libraries and binaries. Example with openssl-1.0.2d: echo == unpack tarball tar xf openssl-1.0.2d.tar.gz cd openssl-1.0.2d echo == backup files to be modified cp ssl/s2_lib.c{,.bak} cp ssl/s3_lib.c{,.bak} cp ssl/ssl3.h{,.bak} cp ssl/tls1.h{,.bak} echo == patch files vi ssl/tls1.h +/TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES/ # define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 1 vi ssl/ssl3.h ssl/s{2,3}_lib.c +"/# *if 0/" #==> remove all # if 0 and corresponding #endif # except if lines contain: # _FZA # /* Fortezza ciphersuite from SSL 3.0 # /* Do not set the compare functions, # if (s->shutdown & SSL_SEND_SHUTDOWN) echo == configure with static libraries echo omitt the zlib options if zlib-1g-dev is not installed echo omitt the krb5 options if no kerberos libraries available LD_RUN_PATH=/usr/local/openssl/lib LDFLAGS="-rpath=$LD_RUN_PATH" && export LDFLAGS ./config --prefix=/usr/local --openssldir=/usr/local/ssl \ enable-zlib zlib zlib-dynamic enable-ssl2 \ enable-krb5 --with-krb5-flavor=MIT \ enable-mdc2 enable-md2 enable-rc5 enable-rc2 \ enable-cms enable-ec enable-ec2m enable-ecdh enable-ecdsa \ enable-gost enable-seed enable-idea enable-camellia \ enable-rfc3779 enable-ec_nistp_64_gcc_128 \ experimental-jpake -fPIC \ -DTEMP_GOST_TLS -DTLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES \ -shared echo == make binaries and libraries make depend make make test make install echo == if you want static binaries and libraries make clean echo same ./config as before but without shared option ./config --prefix=/usr/local --openssldir=/usr/local/ssl \ enable-zlib zlib zlib-dynamic enable-ssl2 \ enable-krb5 --with-krb5-flavor=MIT \ enable-mdc2 enable-md2 enable-rc5 enable-rc2 \ enable-cms enable-ec enable-ec2m enable-ecdh enable-ecdsa \ enable-gost enable-seed enable-idea enable-camellia \ enable-rfc3779 enable-ec_nistp_64_gcc_128 \ experimental-jpake -fPIC -static \ -DTEMP_GOST_TLS -DTLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES make depend make make test echo next make will overwrite the previously installed dynamic echo shared openssl binary with the static openssl binary make install Example: Compile Net::SSLeay To enable support for ancient protocol versions, Net::SSLeay must be compiled manually after patching 'SSLeay.xs' (see below). Reason is, that Net::SSLeay enables some functionality for SSL/TLS according the identified openssl version. There is, currently (2015), no possibility to enable this functionality by passing options on to the configuration script 'perl Makefile.PL'. Building our own library and module (with openssl from '/usr/local'): echo == unpack tarball tar xf Net-SSLeay-1.72.tar.gz cd Net-SSLeay-1.72 echo == patch files echo "edit SSLeay.xs and change some #if as described below" LD_RUN_PATH=/usr/local/openssl/lib LDFLAGS="-rpath=$LD_RUN_PATH" && export LDFLAGS env OPENSSL_PREFIX=/usr/local perl Makefile.PL PREFIX=/usr/local \ INC=-I/usr/local/include DEFINE=-DOPENSSL_BUILD_UNSAFE=1 make make install cd /tmp && $0 +version SSLeay.xs needs to be changed as follows: * search for #ifndef OPENSSL_NO_SSL2 #if OPENSSL_VERSION_NUMBER < 0x10000000L const SSL_METHOD * SSLv2_method() #endif #endif #ifndef OPENSSL_NO_SSL3 #if OPENSSL_VERSION_NUMBER < 0x10002000L const SSL_METHOD * SSLv3_method() #endif #endif * and replace by const SSL_METHOD * SSLv2_method() const SSL_METHOD * SSLv3_method() Note that Net::SSLeay will be installed in '/usr/local/' then. This can be adapted to your needs by passing another path to the 'PREFIX' and 'DESTDIR' parameter. Following command can be used to check which methods are avilable in Net::SSLeay, hence above patches can be verified: perl -MNet::SSLinfo -le 'print Net::SSLinfo::ssleay_test();' Testing OpenSSL After installation as descibed above finished, openssl may be tested: echo already installed openssl (found with PATH environment) openssl ciphers -v openssl ciphers -V -ssl2 openssl ciphers -V -ssl3 openssl ciphers -V ALL openssl ciphers -V ALL:COMPLEMENTOFALL openssl ciphers -V ALL:eNULL:EXP echo own compiled and installed openssl /usr/local/openssl ciphers -v /usr/local/openssl ciphers -V -ssl2 /usr/local/openssl ciphers -V -ssl3 /usr/local/openssl ciphers -V ALL /usr/local/openssl ciphers -V ALL:COMPLEMENTOFALL /usr/local/openssl ciphers -V ALL:eNULL:EXP The difference should be obvious. Note, the commands using 'ALL:COMPLEMENTOFALL' and 'ALL:eNULL:EXP' should return the same result. Testing Net::SSLeay As we want to test the separately installed Net::SSLeay, it is best to do it with $0 itself: $0 +version we should see a line similar to follwong at the end of the output: Net::SSLeay 1.72 /usr/local/lib/x86_64-linux-gnu/perl/5.20.2/Net/SSLeay.pm Now check for supported (known) ciphers: $0 ciphers -V we should see lines similar to those of the last '/usr/local/openssl' call. However, it should contain more cipher lines. Stand-alone Executable Some people asked for a stand-alone executable (mainly for Windows). Even perl is a scripting language there are situations where a stand- alone executable would be nice, for example if the installed perl and its libraries are outdated, or if perl is missing at all. Currently (2016) there are following possibilities to generate such a stand-alone executable: * perl with PAR::Packer module pp -C -c $0 pp -C -c $0 -M Net::DNS -M Net::SSLeay -M IO::Socket \ -M Net::SSLinfo -M Net::SSLhello -M osaft pp -C -c checkAllCiphers.pl pp -C -c checkAllCiphers.pl -M Net::DNS * ActiveState perl with its perlapp perlapp --clean $0 perlapp --clean $0 -M Net::DNS -M Net::SSLeay -M IO::Socket \ -M Net::SSLinfo -M Net::SSLhello -M osaft perlapp --clean checkAllCiphers.pl perlapp --clean checkAllCiphers.pl -M Net::DNS -M osaft * perl2exe from IndigoSTar perl2exe $0 perl2exe checkAllCiphers.pl For details on building the executable, for example how to include all required modules, please refer to the documentation of the tool. * http://search.cpan.org/~rschupp/PAR-Packer-1.030/lib/PAR/Packer.pm * http://docs.activestate.com/pdk/6.0/PerlApp.html * http://www.indigostar.com Note that pre-build executables (build by perlapp, perl2exe) cannot be provided due to licence problems. Also note that using stand-alone executable have not been tested the same way as the $0 itself. Use them at your own risk. DOCKER The tool can be used inside a Docker image. To start $0 inside the Docker image, use following: o-saft-docker +info some.tld or docker run --rm -it owasp/o-saft +info some.tld For more details, please refer to: o-saft-docker usage o-saft-docker -help BUILD DOCKER IMAGE The Docker image can be installed as follows: docker pull owasp/o-saft The image can also easily be build from the Dockerfile (which is part of the distribution) as follows: o-saft-docker build To build the image from the Dockerfile with docker commands, see: o-saft-docker -n build For more details, please refer to: o-saft-docker -help SEE ALSO * openssl(1), Net::SSLeay(1), Net::SSLhello, Net::SSLinfo, timeout(1) * http://www.openssl.org/docs/apps/ciphers.html * IO::Socket::SSL(1), IO::Socket::INET(1) * o-saft, o-saft-docker, o-saft-docker-dev, Dockerfile, docker HACKER's INFO Note on SSL versions Automatically detecting the supported SSL versions of the underlaying system is a hard job and not always possible. Reasons could be: * used perl modules (Socket::SSL, Net::SSLeay) does not handle errors properly. Erros may be: invalid SSL_version specified at ... IO/Socket/SSL.pm Use of uninitialized value in subroutine entry at lib/IO/Socket/SSL.pm There're some workarounds implemented since version 15.11.15 . * the underlaying libssl does not support the version, which then may result in segmentation fault * the underlaying libssl is newer than the perl module and the module has not been reinstalled. This most often happens with Net::SSLeay This can be detected with (see version numbers for Net::SSLeay): $0 +version * perl (in particular a used module, see above) may bail out with a compile error, like Can't locate auto/Net/SSLeay/CTX_v2_new.al in @INC ... There're some workarounds implemented since version 15.11.15 . We try to detect unsupported versions and disable them automatically, a warning like follwoing is shown then: **WARNING: SSL version 'SSLv2': not supported by openssl All such warnings look like: **WARNING: SSL version 'SSLv2': ... If problems occour with SSL versions, following commands and options may help to get closer to the reason or can be used as workaround: $0 +version $0 +version --v $0 +version | grep versions $0 +version | grep 0x $0 +protocols your.tld $0 +protocols your.tld --no-rc Checking for SSL version is done at one place in the code, search for supported SSL versions However, there are some dirty hacks where SSLv2 and SSLv3 is checked again. Using private libssl.so and libcrypt.so For all cryptographic functionality the libraries installed on the system will be used. In particular perl's Net::SSLeay(1) module, the system's libssl.so and libcrypt.so and the openssl(1) executable. It is possible to provide your own libraries, if the perl module and the executable are linked using dynamic shared objects (aka shared library, position independent code). The appropriate option is --lib=PATH. On most systems these libraries are loaded at startup of the program. The runtime loader uses a preconfigured list of directories where to find these libraries. Also most systems provide a special environment variable to specify additional paths to directories where to search for libraries, for example the LD_LIBRARY_PATH environment variable. This is the default environment variable used herein. If your system uses another name it must be specified with the --envlibvar=NAME option, where NAME is the name of the environment variable. Understanding --exe=PATH, --lib=PATH, --openssl=TOOL If any of --exe=PATH or --lib=PATH is provided, the pragram calls ('exec') itself recursively with all given options, except the option itself. The environment variables 'LD_LIBRARY_PATH' and 'PATH' are set before executing as follows: * prepend 'PATH' with all values given with --exe=PATH * prepend 'LD_LIBRARY_PATH' with all values given with --lib=PATH This is exactly, what X&Cumbersome Approach& below describes. So these option simply provide a shortcut for that. Note that --openssl=TOOL is a full path to the openssl executable and will not be changed. However, if it is a relative path, it might be searched for using the previously set 'PATH' (see above). Note that 'LD_LIBRARY_PATH' is the default. It can be changed with the --envlibvar=NAME option. While --exe mainly impacts the openssl(1) executable, --lib also impacts $0 itself, as it loads other shared libraries if found. Bear in mind that all these options can affect the behaviour of the openssl subsystem, influencing both which executable is called and which shared libraries will be used. NOTE that no checks are done if the options are set proper. To verify the settings, following commands may be used: $0 --lib=YOUR-PATH --exe=YOUR-EXE +version $0 --lib=YOUR-PATH --exe=YOUR-EXE --v +version $0 --lib=YOUR-PATH --exe=YOUR-EXE --v --v +version Why so many options? Exactly as described above, these options allow the users to tune the behaviour of the tool to their needs. A common use case is to enable the use of a separate openssl build independent of the openssl package used by the operating system. This allows the user fine grained control over openssl's encryption suites which are compiled/available, without affecting the core system. Caveats Depending on your system and the used modules and executables, it can be tricky to replace the configured shared libraries with own ones. Reasons are: a) the linked library name contains a version number, b) the linked library uses a fixed path, c) the linked library is searched at a predefined path, d) the executable checks the library version when loaded. Only the first one a) can be circumvented. The last one d) can often be ignored as it only prints a warning or error message. To circumvent the "name with version number" problem try following: 1) use ldd(1) (or a similar tool) to get the names used by openssl: ldd /usr/bin/openssl which returns something like: libssl.so.0.9.8 => /lib/libssl.so.0.9.8 (0x00007f940cb6d000) libcrypto.so.0.9.8 => /lib/libcrypto.so.0.9.8 (0x00007f940c7de000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f940c5d9000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f940c3c1000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f940c02c000) /lib64/ld-linux-x86-64.so.2 (0x00007f940cdea000) Here only the first two libraries are important. Both, libcrypto.so and libssl.so need to be version "0.9.8" (in this example). 2) create a directory for your libraries, i.e.: mkdir /tmp/dada 3) place your libraries there, assuming they are: /tmp/dada/libssl.so.1.42 /tmp/dada/libcrypto.so.1.42 4) create symbolic links in that directory: ln -s libssl.so.1.42 libssl.so.0.9.8 ln -s libcrypto.so.1.42 libcrypto.so.0.9.8 5) test program with following option: $0 +libversion --lib=/tmp/dada $0 +list --v --lib=/tmp/dada or: $0 +libversion --lib=/tmp/dada -exe=/path/to-openssl $0 +list --v --lib=/tmp/dada -exe=/path/to-openssl 6) start program with your options, i.e.: $0 --lib=/tmp/dada +ciphers This works if openssl(1) uses the same shared libraries as Net::SSLeay(1), which most likely is the case. It's tested with Unix/Linux only. It may work on other platforms also if they support such an environment variable and the installed Net::SSLeay(1) and openssl(1) are linked using dynamic shared objects. Depending on compile time settings and/or the location of the used tool or lib, a warning like following may occur: WARNING: can't open config file: /path/to/openssl/ssl/openssl.cnf This warning can be ignored, usually as req or ca sub commands of openssl is not used here. To fix the problem, either use --openssl-cnf=FILE option or set the the environment variable OPENSSL_CONF properly. Cumbersome Approach A more cumbersome approach to call this program is to set following environment variables in your shell: PATH=/tmp/dada-1.42/apps:$PATH LD_LIBRARY_PATH=/tmp/dada-1.42 Windows Caveats I.g. the used libraries on Windows are libeay32.dll and ssleay32.dll. Windows also supports the LD_LIBRARY_PATH environment variable. If it does not work as expected with that variable, it might be possible to place the libs in the same directory as the corresponding executable (which is found by the PATH environment variable). # openssl.exe 1.0.0e needs: libeay32.dll, ssleay32.dll Using CGI mode This script can be used as CGI application. Output is the same as in common CLI mode, using 'Content-Type:text/plain'. Keep in mind that the used modules like Net::SSLeay(1) will write some debug messages on STDERR instead STDOUT. Therefore multiple --v and/or --trace options behave slightly different. No additional external files like RC-FILE or DEBUG-FILE are read in CGI mode; they are silently ignored. Some options are disabled in CGI mode because they are dangerous or don't make any sense. WARNING There are no input data validation checks implemented herein. All input data is url-decoded once and then used verbatim. More advanced checks must be done outside before calling this tool. It is not recommended to run this tool in CGI mode. You have been warned! # The only code necessary for CGI mode is encapsulated at the beginning, # see 'if ($me =~/\.cgi/){ ... }'. Beside some minor additional regex # matches (mainly removing trailing '=' and empty arguments) no other # code is needed. # Using user specified code There are some functions called within the program flow, which can be filled with any perl code. Empty stubs of the functions are prepared in o-saft-usr.pm. See also USER-FILE . DEBUG Debugging, Tracing Following options and commands are useful for hunting problems with SSL connections and/or this tool. Note that some options can be given multiple times to increase amount of listed information. Also keep in mind that it's best to specify --v as very first argument. Note that the file o-saft-dbx.pm is required, if any --trace* or --v option is used. Commands * +dump * +libversion * +s_client * +todo * +version Options * --v * --v-- * --trace * --trace-arg * --trace-cmd * --trace-key Empty or undefined strings are written as '<>' in texts. Some parameters, in particular those of HTTP responses, are written as '<>'. Long parameter lists are abbreviated with '...'. Output When using --v and/or --trace options, additional output will be prefixed with a '#' (mainly as first, left-most character. Following formats are used: #[space] Additional text for verbosity (--v options). #[variable name][TAB] Internal variable name (--trace-key options). #o-saft.pl:: #Net::SSLinfo:: Trace information for --trace options. #{ Trace information from NET::SSLinfo for --trace options. These are data lines in the format: #{ variable name : value #} Note that 'value' here can span multiple lines and ends with: #} Using outdated modules The tools was designed to work with old perl modules too. When using old modules, a proper '**WARNING:' will be printed. These warinings cannot be switched of using --no-warning . The warning also informs about the missing functionality or check. I.g. it is best to install newer versions of the module if possible. A good practice to check if modules are available in a proper version is to call: $0 +version $0 +version --v --v Following example shows the result without warnings: === reading: ./.o-saft.pl (RC-FILE done) === === reading: Net/SSLhello.pm (O-Saft module done) === === reading: Net/SSLinfo.pm (O-Saft module done) === === ./o-saft.pl 16.09.09 === Net::SSLeay:: ::OPENSSL_VERSION_NUMBER() 0x268443744 ::SSLeay() 0x268443744 Net::SSLeay::SSLeay_version() OpenSSL 1.0.2-chacha (1.0.2f-dev) = openssl = version of external executable OpenSSL 1.0.2-chacha (1.0.2f-dev) external executable /opt/openssl-chacha/bin/openssl used environment variable (name) LD_LIBRARY_PATH environment variable (content) <> path to shared libraries full path to openssl.cnf file <> common openssl.cnf files /usr/lib/ssl/openssl.cnf \ . /etc/ssl/openssl.cnf \ . /System//Library/OpenSSL/openssl.cnf \ . /usr/ssl/openssl.cnf URL where to find CRL file <> directory with PEM files for CAs /opt/tools/openssl-chacha/ssl/certs PEM format file with CAs /etc/ssl/certs/ca-certificates.crt common paths to PEM files for CAs /etc/ssl/certs /usr/lib/certs \ . /System/Library/OpenSSL common PEM filenames for CAs ca-certificates.crt certificates.crt certs.pem number of supported ciphers 177 openssl supported SSL versions SSLv3 TLSv1 TLSv11 TLSv12 o-saft.pl known SSL versions SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 TLSv13 \ . DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13 = o-saft.pl +cipherall = default list of ciphers 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300C0FF, . 0x0300CC00 .. 0x0300CCFF, 0x0300FE00 .. 0x0300FFFF, = Required (and used) Modules = @INC ./ ./lib . /bin /usr/share/perl5 \ . /usr/lib/x86_64-linux-gnu/perl5/5.20 \ . /usr/lib/x86_64-linux-gnu/perl/5.20 \ . /usr/share/perl/5.20 /usr/local/lib/site_perl . = module name VERSION found in = ----------------------+--------+------------------------------------------ IO::Socket::INET 1.35 /usr/lib/x86_64-linux-gnu/perl/5.20/IO/Socket/INET.pm IO::Socket::SSL 2.002 /usr/share/perl5/IO/Socket/SSL.pm Net::DNS 0.81 /usr/lib/x86_64-linux-gnu/perl5/5.20/Net/DNS.pm Net::SSLeay 1.72 /usr/lib/x86_64-linux-gnu/perl5/5.20/Net/SSLeay.pm Net::SSLinfo 16.06.01 Net/SSLinfo.pm Net::SSLhello 16.05.16 Net/SSLhello.pm Ciphers osaft 16.05.10 osaft.pm Following example shows the result with warnings (line nr. may vary): === reading: ./.o-saft.pl (RC-FILE done) === === reading: ./Net/SSLhello.pm (O-Saft module done) === **WARNING: ancient Net::SSLeay 1.35 < 1.49; cannot use ::initialize at /Net/SSLinfo.pm line 481. === reading: ./Net/SSLinfo.pm (O-Saft module done) === **WARNING: ancient perl has no 'version' module; version checks may not be accurate; at o-saft.pl line 1662. **WARNING: ancient Net::SSLeay 1.35 < 1.49 detected; at o-saft.pl line 1687. **WARNING: ancient IO::Socket::SSL 1.22 < 1.37 detected; at o-saft.pl line 1687. **WARNING: ancient version IO::Socket::SSL 1.22 < 1.90 does not support SNI or is known to be buggy; SNI disabled; at o-saft.pl line 5905. !!Hint: --force-openssl can be used to disables this check **WARNING: ancient version Net::SSLeay 1.35 < 1.49 may throw warnings and/or results may be missing; at o-saft.pl line 5934. **WARNING: SSL version 'TLSv11': not supported by Net::SSLeay; not checked **WARNING: SSL version 'TLSv12': not supported by Net::SSLeay; not checked **WARNING: SSL version 'TLSv13': not supported by Net::SSLeay; not checked === o-saft.pl 16.09.09 === Net::SSLeay:: ::OPENSSL_VERSION_NUMBER() 0x9470143 **WARNING: ancient version Net::SSLeay 1.35 < 1.49; cannot compare SSLeay with openssl version at o-saft.pl line 4778. ::SSLeay() 0x1.35 **WARNING: ancient version Net::SSLeay 1.35 < 1.49; detailed version not available at o-saft.pl line 4806. = openssl = version of external executable OpenSSL 0.9.8y 5 Feb 2013 external executable /usr/bin/openssl used environment variable (name) LD_LIBRARY_PATH environment variable (content) <> path to shared libraries full path to openssl.cnf file <> common openssl.cnf files /usr/lib/ssl/openssl.cnf \ . /etc/ssl/openssl.cnf \ . /System//Library/OpenSSL/openssl.cnf \ . /usr/ssl/openssl.cnf URL where to find CRL file <> directory with PEM files for CAs /System/Library/OpenSSL/certs PEM format file with CAs <> common paths to PEM files for CAs /etc/ssl/certs /usr/lib/certs /System/Library/OpenSSL common PEM filenames for CAs ca-certificates.crt certificates.crt certs.pem number of supported ciphers 43 openssl supported SSL versions SSLv2 SSLv3 TLSv1 o-saft.pl known SSL versions SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 TLSv13 \ . DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13 **WARNING: ancient version Net::SSLeay 1.35 < 1.49; cannot compare SSLeay with openssl version at o-saft.pl line 4778. **WARNING: used openssl version '9470143' differs from compiled Net:SSLeay '1.35'; ignored = o-saft.pl +cipherall = default list of ciphers 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300C0FF, . 0x0300CC00 .. 0x0300CCFF, 0x0300FE00 .. 0x0300FFFF, = Required (and used) Modules = @INC ./ ./lib /bin /Library/Perl/Updates/5.10.0 \ . /System/Library/Perl/5.10.0/darwin-thread-multi-2level \ . /System/Library/Perl/5.10.0 \ . /Library/Perl/5.10.0/darwin-thread-multi-2level \ . /Library/Perl/5.10.0 \ . /Network/Library/Perl/5.10.0/darwin-thread-multi-2level \ . /Network/Library/Perl/5.10.0 \ . /Network/Library/Perl \ . /System/Library/Perl/Extras/5.10.0/darwin-thread-multi-2level \ . /System/Library/Perl/Extras/5.10.0 . = module name VERSION found in = ----------------------+--------+------------------------------------------ IO::Socket::INET 1.31 /System/Library/Perl/5.10.0/darwin-thread-multi-2level/IO/Socket/INET.pm IO::Socket::SSL 1.22 /System/Library/Perl/Extras/5.10.0/IO/Socket/SSL.pm Net::DNS 0.65 /System/Library/Perl/Extras/5.10.0/darwin-thread-multi-2level/Net/DNS.pm Net::SSLeay 1.35 /System/Library/Perl/Extras/5.10.0/darwin-thread-multi-2level/Net/SSLeay.pm Net::SSLinfo 16.06.01 ./Net/SSLinfo.pm Net::SSLhello 16.05.16 ./Net/SSLhello.pm osaft 16.05.10 /osaft.pm Please keep in mind that the shown version numbers and the shown line numbers are examples and may differ on your system. When starting $0 with outdated modules, more '**WARNING:' will be shown. The warnings depend on the installed version of the module. $0 is known to work with at least: IO::Socket::INET 1.31, IO::Socket::SSL 1.22, Net::DNS 0.65 Net::SSLeay 1.30 TESTING When talking about "testing the tool", functional tests are meant. So this section describes "developer" rather that "user" options. Testing the tool is a challenging task. Beside the oddities described elsewhere, for example X&Name Rodeo&, there are a bunch of problems and errors which may occour during runtime. Following options and commands are available to improve testing. They mainly can simulate error conditions or stop execution properly (they are not intended for other use cases): +quit Stop execution after processing all arguments and before precessing any target. The runtime configuration is complete at this point. --exit=KEY Terminate tool at specified 'KEY'. For available 'KEY', please see: $0 --help=exit grep exit= $0 --cfg-init=KEY=VALUE With this option values in the internal %cfg hash can be set: $cfg{KEY} = VALUE Only (perl) scalars or arrays can be set. The type will be detected automatically. Example, this option can be used to change the text used as prefix in each output line triggerd by the --v option: $0 --cfg-init=prefix_verbose="#VERBOSE: " or the text used as prefix triggerd by the --trace option: $0 --cfg-init=prefix_trace="#TRACE: " EXAMPLES ($0 in all following examples is the name of the tool) General $0 +cipher some.tld $0 +info some.tld $0 +check some.tld $0 +quick some.tld $0 +help=commands $0 +certificate some.tld $0 +fingerprint some.tld 444 $0 +after +dates some.tld $0 +version $0 +version --v $0 +list $0 +list --v Some specials * Get an idea how messages look like $0 +check --cipher=RC4 some.tld * Check for Server Name Indication (SNI) usage only $0 +sni some.tld * Check for SNI and print certificate's subject and altname $0 +sni +cn +altname some.tld * Check for all SNI, certificate's subject and altname issues $0 +sni_check some.tld * Only print supported ciphers $0 +cipher --enabled some.tld * Only print unsupported ciphers $0 +cipher --disabled some.tld * Test for a specific ciphers $0 +cipher --cipher=ADH-AES256-SHA some.tld * Test all ciphers, even if not supported by local SSL implementation $0 +cipherraw some.tld $0 +cipherall some.tld $0 +cipherall some.tld --range=full checkAllCiphers.pl example.tld --range=full --v * Show supported (enabled) ciphers with their DH parameters: $0 +cipher-dh some.tld * Test using a private libssl.so, libcrypto.so and openssl $0 +cipher --lib=/foo/bar-1.42 --exe=/foo/bar-1.42/apps some.tld * Test using a private openssl $0 +cipher --openssl=/foo/bar-1.42/openssl some.tld * Test using a private openssl also for testing supported ciphers $0 +cipher --openssl=/foo/bar-1.42/openssl --force-openssl some.tld # score will be removed, so don't anounce it # * Show current score settings # $0 --help=score # # * Change a single score setting # $0 --cfg-score=http_https=42 +check some.tld # # * Use your private score settings from a file # $0 --help=score > magic.score # edit as needed: magic.score # $0 --cfg-score magic.score +check some.tld * Use your private texts in output $0 +check some.tld --cfg-text=desc="my special description" * Use your private texts from RC-FILE $0 --help=cfg-text >> .$0 edit as needed: .$0 $0 +check some.tld * Use your private hint texts in output $0 +check some.tld --cfg-hint=renegotiation="my special hint text" # # * Use your private score settings from a file # $0 --help=score > magic.score * Get the certificate's Common Name for a bunch of servers: $0 +cn example.tld some.tld other.tld $0 +cn example.tld some.tld other.tld --showhost --no-header * Generate simple parsable output $0 --legacy=quick --no-header +info some.tld $0 --legacy=quick --no-header +check some.tld $0 --legacy=quick --no-header --trace-key +info some.tld $0 --legacy=quick --no-header --trace-key +check some.tld * Generate simple parsable output for multiple hosts $0 --legacy=quick --no-header --trace-key --showhost +check some.tld other.tld * Just for curiosity $0 some.tld +fingerprint --format=raw $0 some.tld +certificate --format=raw | openssl x509 -noout -fingerprint Specials for hunting problems with connections etc. * Do not read RC-FILE .$0 $0 +info some.tld --no-rc * Show command line argument processing $0 +info some.tld --trace-arg * Simple tracing $0 +cn some.tld --trace $0 +info some.tld --trace * A bit more tracing $0 +cn some.tld --trace --trace * Show internal variable names in output $0 +info some.tld --trace-key * Show internal argument processeing $0 +info --trace-arg some.tld * Show internal control flow $0 +info some.tld --trace-cmd * Show internal timing $0 +info some.tld --trace-time * Show checking ciphers $0 +cipher some.tld --v --v # # * List checked ciphers one per line # $0 +cipher some.tld --v --v --v # # * Show processing of ciphers # $0 +cipher some.tld --v --v --v --v * Show values retrieved from target certificate directly $0 +info some.tld --no-cert --no-cert --no-cert-text=Value-from-Certificate * Show certificate CA verifications $0 some.tld +chain_verify +verify +error_verify +chain * Avoid most performance and timeout problems (don't use --v) $0 +info some.tld --no-dns --no-sni --ignore-no-conn $0 +info some.tld --no-dns --no-sni --no-cert --no-http --no-openssl * Identify timeout problems $0 +info some.tld --trace-cmd this will show lines containing: #O-Saft CMD: test ... #begin --v --v .raw nerobeg sretset rof tidua LSS PSAWO - "tfaS-O" retseT reuf tiduA LSS PSAWO - "tfaS-O" :nnawdnegri nnad sib ,elieW enie sad gnig oS ..wsu ,"haey-lss" ,"agoy-lss" :etsiL red fua dnats -reteaps reibssieW eretiew raap nie- nohcs se tnha nam ,ehcuS eid nnageb os ,nebegrev nohcs dnis nemaN ednessap eleiV .guneg "giffirg" thcin reba sad raw gnuhciltneffeoreV enie reuF .noisrevsgnulkciwtnE red emaN red tsi saD . loot LSS rehtona tey - "lp.tsaey" :resseb nohcs tsi sad ,aha ,tsaey -- efeH -- reibssieW -- .thcin sad tgnilk srednoseb ,ajan eigeRnegiE nI resworB lSS nIE redeiW - "lp.reibssiew" . :ehan gal se ,nedrew emaN "regithcir" nie hcod nnad se etssum hcan dnu hcaN .edruw nefforteg setsre sla "y" sad liew ,"lp.y" :eman -ietaD nie snetsednim ,reh emaN nie etssum sE .slooT seseid pytotorP retsre nie nohcs hcua dnatstne iebaD .tetsokeg reibssieW eleiv dnu nednutS eginie nnad hcim tah esylanA eiD .)dnis hcon remmi dnu( neraw nedeihcsrev rhes esiewliet eis muraw ,nednifuzsuareh dnu nehetsrev uz )noitpO "*=ycagel--" eheis( slooT-tseT-LSS reredna releiv essinbegrE nehcildeihcsretnu eid hcusreV mieb dnatstne looT meseid uz eedI eiD )-: ti dnatsrednu :laog txeN .eno neddih eht ,ti tog uoY #end --v ATTRIBUTION Based on ideas (in alphabetical order) of: * cnark.pl, SSLAudit.pl sslscan, ssltest.pl, sslyze.py, testssl.sh * O-Saft - OWASP SSL advanced forensic tool Thanks to Gregor Kuznik for this title. * +cipherraw and some proxy functionality implemented by Torsten Gigler. * For re-writing some docs in proper English, thanks to Robb Watson. * Code to check heartbleed vulnerability adapted from Steffen Ullrich (08. April 2014): https://github.com/noxxi/p5-scripts/blob/master/check-ssl-heartbleed.pl * Colouration inspired by https://testssl.sh/ . VERSION @(#) $VERSION AUTHOR 31. July 2012 Achim Hoffmann (at) sicsec de Project Home: https://www.owasp.org/index.php/O-Saft # TODO must be last section TODO # openssl (nicht bei 0.9.8, bei 1.0.1*) -legacy_renegotiation # SSLCertScanner.exe http://www.xenarmor.com/network-ssl-certificate-scanner.php ansehen * new features ** client certificate ** some STRATTLS need : HELP STARTTLS HELP as output of HELPs are different ** support: PCT protocol ** Checking fallback from TLS 1.1 to TLS 1.0 (see ssl-cipher-check.pl) ** Minimal encryption strength: weak encryption (40-bit) (TestSSLServer.jar) ** check dynamic HTTP Public Key Pinning (HPKP) * missing checks ** SSL_honor_cipher_order => 1 ** implement TLSv1.2 checks ** DNSEC and TLSA ** checkcert(): KeyUsage, keyCertSign, BasicConstraints ** DV and EV miss some minor checks; see checkdv() and checkev() ** +constraints does not check +constraints in the certificate of the certificate chain. ** TR-03116-4: does not check data in certificate chain ** RFC 7525: does not check data in certificate chain ** RFC 7525: 3.2. Strict TLS (for 'STARTTLS') ** RFC 7525: 3.4. TLS Session Resumption (session ticket must be authenticated and encrypted) ** RFC 7525: 3.6. Server Name Indication (more reliable check) ** RFC 7525: 4.3. Public Key Length (need more reliable check) ** RFC 7525: 6.2. AES-GCM ** RFC 7525: 6.3. Forward Secrecy ** RFC 7525: 6.4. Diffie-Hellman Exponent Reuse * vulnerabilities ** Ticketbleed ** complete TIME, BREACH check ** BEAST more checks, see: http://www.bolet.org/TestSSLServer/ * verify CA chain: ** Net::SSLinfo.pm implement verify* ** implement +check_chain (see Net::SSLinfo.pm implement verify* also) ** implement +ca = +verify +chain +rootcert +expired +fingerprint * postprocessing Remove all options for output formatting. Use a "postprocess" script instead. ** scoring implement score for PFS; lower score if not all ciphers support PFS make clear usage of score from %checks ** write postprocessor for tabular data, like ssl-cert-check -p 443 -s mail.google.com -i -V * Net::SSLinfo ** Net::SSLeay::ctrl() sometimes fails, but doesn't return error message ** Net::SSLeay::CTX_clear_options() Need to check the difference between the SSL_OP_LEGACY_SERVER_CONNECT and SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; see also SSL_clear_options(). see https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html ** Net::SSLinfo::do_ssl_close() does not realy work * Windows ** Unicode: try: cmd /K chcp 65001 or: chcp 65001 or: reg add hklm\system\currentcontrolset\control\nls\codepage -v oemcp -d 65001 ** perl perl 5.10.x from PortableApps does not work, cause it misses IO/Socket/SSL.pm, however, checkAllCiphers.pl works. perl from older PortableApps/xampp (i.e. 1.7.x) does not work, cause IO/Socket/SSL.pm is too old (1.37). ** Windows on Windows print of strings > 32k does not work. Ugly workaround using --v implemented in o-saft-man.pm only. * internal ** move all configuration and code for commans line arguments to Arg.pm ** use qr() for defining regex, see $cfg{'regex'} ** print_line() has ugly code for legacy=cipher ** "Label" texts are defined twice: o-saft.pl and Net::SSLeay ** make a clear concept how to handle +CMD whether they report checks or informations (aka %data vs. %check_*) currently (2016) each single command returns all values ** client certificates not yet implemented in _usesocket() _useopenssl(), see t.client-cert.txt ** (nicht wichtig, aber sauber programmieren) _get_default(): Net::SSLinfo::default() benutzen O-Saft-19.01.19/OSaft/Doc/links.txt000066400000000000000000000130051342117255600164540ustar00rootroot00000000000000 # SID @(#) links.txt 1.6 19/01/07 20:19:06 # name | description #------+----------------------------------------------------------------------+ OWASP TLS Cheat Sheet https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet OWASP Certificate and Public Key Pinning https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning OWASP HTTP Strict Transport Security https://www.owasp.org/index.php/HTTP_Strict_Transport_Security BEAR and LION https://www.cl.cam.ac.uk/~rja14/Papers/bear-lion.pdf BSI TR-02102 Teil 2 https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR02102/BSI-TR-02102-2.pdf ENISA: Algorithms, Key Sizes and Parameters Report http://www.enisa.europa.eu/activities/identity-and-trust/library/deliverables/algorithms-key-sizes-and-parameters-report EV Certificate http://www.evsslcertificate.com/ EV Certificate Guidelines https://www.cabforum.org/EV_Certificate_Guidelines.pdf Adantium https://eprint.iacr.org/2018/720.pdf Adantium https://github.com/google/adiantum AIA http://www.startssl.com/certs/sub.class4.server.ca.crt ALPN (draft) http://tools.ietf.org/html/draft-friedl-tls-applayerprotoneg-02 ALPN https://www.imperialviolet.org/2013/03/20/alpn.html CDP http://www.startssl.com/crt4-crl.crl, http://crl.startssl.com/crt4-crl.crl Choosen-boundary attack http://erlend.oftedal.no/blog/beast/ CT http://ctwatch.net/ False Start https://www.imperialviolet.org/2012/04/11/falsestart.html False Start https://technotes.googlecode.com/git/falsestart.html HPKP https://timtaubert.de/blog/2014/10/http-public-key-pinning-explained/ HPKP https://blog.pregos.info/2015/02/23/http-public-key-pinning-hpkp-erklaerung-und-einrichtung/ HPKP https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead HPKP in Chrome hrome://net-internals/#hsts (show, reset pins in Chrome) HSTS http://tools.ietf.org/html/draft-hodges-strict-transport-sec-02 NaCl http://nacl.cr.yp.to NPN (draft) https://tools.ietf.org/id/draft-agl-tls-nextprotoneg-04.html NPN https://technotes.googlecode.com/git/nextprotoneg.html NPN https://www.imperialviolet.org/2013/03/20/alpn.html OCSP http://ocsp.startssl.com/sub/class4/server/ca OCSP Stapling http://en.wikipedia.org/wiki/OCSP_stapling PFS http://en.wikipedia.org/wiki/Perfect_forward_secrecy Resumtion https://www.imperialviolet.org/2011/11/22/forwardsecret.html Resumtion https://www.imperialviolet.org/2013/06/27/botchingpfs.html SCSV https://datatracker.ietf.org/doc/draft-bmoeller-tls-downgrade-scsv/?include_text=1 Server Pinning https://tools.ietf.org/id/draft-sheffer-tls-pinning-ticket-02.txt SNI apache https://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI SIMON and SPECK https://eprint.iacr.org/2013/404 SM4 https://tools.ietf.org/id/draft-crypto-sm4-00.html LatinDances http://cr.yp.to/rumba20/newfeatures-20071218.pdf LatinDances2 https://eprint.iacr.org/2012/065.pdf Poly1305_Donna https://github.com/floodyberry/poly1305-donna Cache-Collisions http://research.microsoft.com/pubs/64024/aes-timing.pdf Snuffle https://cr.yp.to/snuffle/812.pdf BADA55 https://bada55.cr.yp.to/ SPDY/3 http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3 SPDY Protocol http://www.chromium.org/spdy/spdy-protocol SRI Subresource Integrity: https://www.w3.org/TR/SRI/ 4/2016 SRI (Mozilla) https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity TACK http://tack.io/draft.html, 2013 Moxie Marlinspike, Trevor Perrin TLS Lite http://trevp.net/tlslite/ Elliptic Curve https://en.wikipedia.org/wiki/Comparison_of_TLS_implementations#Supported_elliptic_curves Elliptic Curve for IPsec https://www.researchgate.net/profile/Johannes_Merkle/publication/260050106_Standardisierung_der_Brainpool-Kurven_fur_TLS_und_IPSec/links/00b7d52f36a0cc2fdd000000.pdf Elliptic Curve http://datatracker.ietf.org/doc/draft-mcgrew-tls-aes-ccm-ecc/ Elliptic Curve http://datatracker.ietf.org/doc/draft-merkle-tls-brainpool/ Elliptic Curve http://datatracker.ietf.org/doc/draft-merkle-ikev2-ke-brainpool/ Elliptic Curve http://datatracker.ietf.org/doc/draft-sheffer-ipsecme-dh-checks/ Elliptic Curve https://tools.ietf.org/html/draft-josefsson-tls-curve25519-06 Elliptic Curve http://eprint.iacr.org/2007/286 Elliptic Curve http://www.teletrust.de/fileadmin/files/oid/ecgdsa_final.pdf Elliptic Curve https://datatracker.ietf.org/doc/draft-harkins-ikev3/ XMSS https://eprint.iacr.org/2011/484.pdf BEAST https://vnhacker.blogspot.com/2011/09/beast.html BREACH http://www.breachattack.com/ CCS http://ccsinjection.lepidum.co.jp/ CRIME http://zoompf.com/2012/09/explaining-the-crime-weakness-in-spdy-and-ssl DROWN https://drownattack.com/ FREAK https://freakattack.com/ FREAK https://mitls.org/pages/attacks/SMACK#freak Lucky 13 ? LogJam https://weakdh.org/ POODLE https://www.openssl.org/~bodo/ssl-poodle.pdf ROBOT https://robotattack.org/ SLOTH https://www.mitls.org/pages/attacks/SLOTH SKIP https://mitls.org/pages/attacks/SMACK SMACK https://mitls.org/pages/attacks/SMACK Sweet32 https://sweet32.info/ TIME ? # TS 102 042 : http:// # # http://rsapss.hboeck.de/rsapss-1.0.1.pdf # https://www.bsi.bund.de/DE/Themen/weitereThemen/SINA/sina_node.html # http://datatracker.ietf.org/doc/draft-eastlake-additional-xmlsec-uris/ # Firefox Add-ons # https://calomel.org/firefox_ssl_validation.htm Calomel SSL Validation # https://addons.mozilla.org/de/firefox/addon/cert-viewer-plus/ Cert Viewer Plus # # http://patrol.psyced.org/ Certifiate Patrol # certwatch.simos.info CertWatch # O-Saft-19.01.19/OSaft/Doc/misc.txt000066400000000000000000000125351342117255600162760ustar00rootroot00000000000000 # SID @(#) misc.txt 1.3 18/11/01 02:25:01 ## miscellaneous observations and texts (some in German only) SSLv2 # SSLv3 # https://tools.ietf.org/html/rfc6101#appendix-E # Appendix E. Version 2.0 Backward Compatibility # SSLv2 Ciphers used in SSLv3 # 0x01,0x00,0x80 SSL_RC4_128_WITH_MD5 # 0x02,0x00,0x80 SSL_RC4_128_EXPORT40_WITH_MD5 # 0x03,0x00,0x80 SSL_RC2_CBC_128_CBC_WITH_MD5 # 0x04,0x00,0x80 SSL_RC2_CBC_128_CBC_EXPORT40_WITH_MD5 # 0x05,0x00,0x80 SSL_IDEA_128_CBC_WITH_MD5 # 0x06,0x00,0x40 SSL_DES_64_CBC_WITH_MD5 # 0x07,0x00,0xC0 SSL_DES_192_EDE3_CBC_WITH_MD5 # # Additional informations: OCSP # cat some.crl | openssl crl -text -inform der -noout # OCSP response "3" (TLS 1.3) ==> certifcate gueltig # SPDY - SPDY Protocol : http://www.chromium.org/spdy/spdy-protocol ALPN # https://tools.ietf.org/html/rfc7301 # ExtensionType Values 16 # ProtocolNameList: # Protocol: HTTP/1.1 # Identification Sequence: http/1.1 # Protocol: SPDY/1 # Identification Sequence: spdy/1 # Protocol: SPDY/2 # Identification Sequence: spdy/2 # Protocol: SPDY/3 # Identification Sequence: spdy/3 # Application-Layer Protocol Negotiation (ALPN) is available with # Net::SSLeay 1.56+ and +openssl-1.0.2+. # Check support with: 'IO::Socket::SSL->can_alpn()'. # Note that some client implementations may encounter problems if # both NPN and ALPN are +specified. Since ALPN is intended as a # replacement for NPN, try providing ALPN protocols +then fall back # to NPN if that fails. HSTS # Strict-Transport-Security: max-age=16070400; includeSubDomains # Apache config: # Header set Strict-Transport-Security "max-age=16070400; includeSubDomains" # SNI apache: https://wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI # SSLStrictSNIVHostCheck, which controls whether to allow non SNI clients to access a name-based virtual host. # when client provided the hostname using SNI, the new environment variable SSL_TLS_SNI Resumption # TLS session resumption problem with session ticket # see https://www.imperialviolet.org/2011/11/22/forwardsecret.html # "Since the session ticket contains the state of the session, and # thus keys that can decrypt the session, it too must be protected # by ephemeral keys. But, in order for session resumption to be # effective, the keys protecting the session ticket have to be kept # around for a certain amount of time: the idea of session resumption # is that you can resume the session in the future, and you can't # do that if the server can't decrypt the ticket! # So the ephemeral, session ticket keys have to be distributed to # all the frontend machines, without being written to any kind of # persistent storage, and frequently rotated." # see also https://www.imperialviolet.org/2013/06/27/botchingpfs.html # HPKP SRI - Subresource Integrity # supported by: Chrome 45, Firefox 43, Opera 32 # Note that SRI is SSL/TLS-related but security-related # zu RFC 2412: # alle *DH* sind im Prinzip PFS. # wird manchmal zusaetzlich mit DHE bezeichnet, wobei E für ephemeral # also flüchtige, vergängliche Schlüssel steht # D.H. ECDHE_* und DHE_* an den Anfang der Cipherliste stellen, z.B. # TLS_ECDHE_RSA_WITH_RC4_128_SHA # TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA # TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA # TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA # zu RFC 4366 # AKID - authority key identifier # Server name Indication (SNI): server_name # Maximum Fragment Length Negotiation: max_fragment_length # Client Certificate URLs: client_certificate_url # Trusted CA Indication: trusted_ca_keys # Truncated HMAC: truncated_hmac # Certificate Status Request (i.e. OCSP stapling): status_request # Error Alerts # zu RFC 6066 # PkiPath # Truncated CA keys (value 3) # Truncated HMAC (value 4) # (Certificate) Status Request (value 5) # OCSP stapling mechanism # zu RFC 6125 # Representation and Verification of Domain-Based Application Service # Identity within Internet Public Key Infrastructure Using X.509 (PKIX) # Certificates in the Context of Transport Layer Security (TLS) CIPHER Output (cipherscan) # prio ciphersuite protocols pfs curves # 1 ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 ECDH,P-521,521bits secp521r1,secp384r1,prime256v1 CIPHER Output (sslscan) # Preferred TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384 Curve P-521 DHE 521 # Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve P-521 DHE 521 Certificate Output # Certificate: untrusted, 2048 bits, sha256WithRSAEncryption signature O-Saft-19.01.19/OSaft/Doc/rfc.txt000066400000000000000000000176711342117255600161230ustar00rootroot00000000000000 # SID @(#) rfc.txt 1.11 19/01/11 00:05:23 # number| title / description #------+----------------------------------------------------------------------+ # url base URL for RFC descriptions # http://tools.ietf.org/html/rfcXXXX # http://tools.ietf.org/rfc/rfcXXXX.txt url http://tools.ietf.org/ 6101 SSL Version 3.0 6601 SSL Version 3.0 2246 TLS Version 1.0 (with Cipher Suites) 4346 TLS Version 1.1 (with Cipher Suites) 5246 TLS Version 1.2 (with Cipher Suites) 8446 TLS Version 1.3 (with Cipher Suites) 4347 DTLS Version 0.9 6347 DTLS Version 1.2 8447 IANA Registry Updates for TLS and DTLS 2616 Hypertext Transfer Protocol Version 1 (HTTP/1.1) 7540 Hypertext Transfer Protocol Version 2 (HTTP/2) 7230 HTTP/1.1: Message Syntax and Routing 7231 HTTP/1.1: Semantics and Content 7232 HTTP/1.1: Conditional Requests 7233 HTTP/1.1: Range Requests 7234 HTTP/1.1: Caching 7235 HTTP/1.1: Authentication 3490 Internationalizing Domain Names in Applications (IDNA) 3987 Internationalized Resource Identifiers (IRIs) 4518 Internationalized String Preparation in LDAP 3986 Uniform Resource Identifier (URI): Generic Syntax 2104 HMAC: Keyed-Hashing for Message Authentication 2405 The ESP DES-CBC Cipher Algorithm With Explicit IV 2406 IP Encapsulating Security Payload (ESP) 2407 The Internet IP Security Domain of Interpretation for ISAKMP 2408 Internet Security Association and Key Management Protocol (ISAKMP) 2409 The Internet Key Exchange (IKE) - 1998 4306 The Internet Key Exchange (IKEv2) Protocol - 2005 7296 The Internet Key Exchange Protocol 2 (IKEv2) - 2014 4753 ECP Groups for IKE and IKEv2 4754 IKE and IKEv2 Authentication Using the Elliptic Curve Digital Signature Algorithm (ECDSA) 2412 AKLEY Key Determination Protocol (PFS - Perfect Forward Secrec) 2817 Upgrading to TLS Within HTTP/1.1 2818 HTTP Over TLS 2945 SRP Authentication & Key Exchange System 2986 PKCS#10 5967 PKCS#10 2313 PKCS#1: RSA Cryptography Specifications Version 1.5 2437 PKCS#1: RSA Cryptography Specifications Version 2.0 3447 PKCS#1: RSA Cryptography Specifications Version 2.1 8017 PKCS#1: RSA Cryptography Specifications Version 2.2 2712 TLSKRB: Addition of Kerberos Cipher Suites to TLS 3268 TLSAES: Advanced Encryption Standard (AES) Cipher Suites for TLS 4279 TLSPSK: Pre-Shared Key Ciphersuites for TLS 5081 TLSPGP: Using OpenPGP Keys for Transport Layer Security (TLS) Authentication - 2007 6091 TLSPGP: Using OpenPGP Keys for Transport Layer Security (TLS) Authentication - 2011 3711 The Secure Real-time Transport Protocol (SRTP) 6189 ZRTP: Media Path Key Agreement for Unicast Secure RTP 4309 AES-CCM Mode with IPsec Encapsulating Security Payload (ESP) 5116 An Interface and Algorithms for Authenticated Encryption (AEAD) 3749 TLS Compression Method (obsolete) 3943 TLS Protocol Compression Using Lempel-Ziv-Stac (LZS) 4680 TLS Handshake Message for Supplemental Data 4749 TLS Compression Methods 3546 TLS Extensions (obsolete) 4366 TLS Extensions 5746 TLS Extension: Renegotiation Indication Extension 5764 TLS Extension: Secure Real-time Transport Protocol (SRTP) 5878 TLS Extension: Authorization 5929 TLS Extension: Channel Bindings 6066 TLS Extension: Extension Definitions 6520 TLS Extension: Heartbeat 7301 TLS Extension: Application-Layer Protocol Negotiation (ALPN) 7633 TLS Extension: Feature Extension: Must Staple 8449 TLS Extension: Record Size Limit 5077 TLS session resumption without Server-Side State 6961 TLS Multiple Certificate Status Request Extension 7627 TLS Session Hash and Extended Master Secret Extension 6176 Prohibiting Secure Sockets Layer (SSL) Version 2.0 7568 Deprecating Secure Sockets Layer Version 3.0 6460 NSA Suite B Profile for TLS 2560 Online Certificate Status Protocol (OCSP, obsolete) 6267 Online Certificate Status Protocol Algorithm Agility (OCSP, obsolete) 4210 X509 PKI Certificate Management Protocol (CMP) 3279 x509 Algorithms and Identifiers for X.509 PKI and CRL Profile 3739 x509 PKI Qualified Certificates Profile; EU Directive 1999/93/EC 3280 X509 PKI Certificate and Certificate Revocation List (CRL) Profile (obsolete) 4158 X509 PKI Certification Path Building 4387 X509 PKI Operational Protocols: Certificate Store Access via HTTP 5280 X509 PKI Certificate and Certificate Revocation List (CRL) Profile 5480 X509 PKI Elliptic Curve Cryptography Subject 5758 X509 PKI Additional Algorithms and Identifiers for DSA and ECDSA 6960 X509 Online Certificate Status Protocol (OCSP) 8410 X509 PKI Algorithm Identifiers for Ed25519, Ed448, X25519, and X448 4132 Addition of Camellia Cipher Suites to TLS 4162 Addition of SEED Cipher Suites to TLS 4357 Additional Cryptographic Algorithms for Use with GOST 28147-89, GOST R 34.10-94, GOST R 34.10-2001, and GOST R 34.11-94 Algorithms 4418 UMAC: Message Authentication Code using Universal Hashing 4491 Using the GOST Algorithms with X509 (GOST R 34.10-94, GOST R 34.10-2001, GOST R 34.11-94) 6986 GOST R 34.11-2012: Hash Function 4868 Using HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 with IPsec 4785 Pre-Shared Key (PSK) Cipher Suites with NULL Encryption for TLS 5054 Secure Remote Password (SRP) Protocol for TLS Authentication 5114 Additional Diffie-Hellman Groups for Use with IETF Standards 5288 AES Galois Counter Mode (GCM) Cipher Suites for TLS 5289 TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode (GCM) 5430 Suite B Profile for TLS 5487 Pre-Shared Key Cipher Suites for TLS with SHA-256/384 and AES Galois Counter Mode 5489 ECDHE_PSK Cipher Suites for TLS 5589 Session Initiation Protocol (SIP) Call Control - Transfer 6040 Tunnelling of Explicit Congestion Notification 6090 Fundamental Elliptic Curve Cryptography Algorithms 4492 TLSECC: Elliptic Curve Cryptography (ECC) Cipher Suites for TLS (obsolete) 5639 Elliptic Curve Cryptography (ECC) Brainpool Standard Curves and Curve Generation 5903 Elliptic Curve Groups modulo a Prime (ECP Groups) for IKE and IKEv2 6507 Elliptic Curve-Based Certificateless Signatures for Identity-Based Encryption (ECCSI) 7027 Elliptic Curve Cryptography (ECC) Brainpool Curves for TLS 7748 Elliptic Curve for Security 8422 Elliptic Curve Cryptography (ECC) Cipher Suites for TLS Versions 1.2 and Earlier 5528 Camellia Counter Mode and Camellia Counter with CBC-MAC Mode Algorithms 5741 RFC Streams, Headers, and Boilerplates 5794 Description of the ARIA Encryption Algorithm 5932 Camellia Cipher Suites for TLS 6209 Addition of the ARIA Cipher Suites to TLS 6367 Addition of the Camellia Cipher Suites to TLS 6655 AES-CCM Cipher Suites for TLS 7251 AES-CCM Elliptic Curve Cryptography (ECC) Cipher Suites for TLS 7507 TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks 5055 Server-Based Certificate Validation Protocol (SCVP) 5019 simplified RFC 2560 5705 Keying Material Exporters for TLS 6125 Representation and Verification of Domain-Based Application Service (PKIX) for TLS 6797 HTTP Strict Transport Security (HSTS) 6962 Certificate Transparency 6979 Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) 7366 Encrypt-then-MAC for TLS and DTLS 7457 Summarizing Known Attacks on TLS and DTLS 7465 Prohibiting RC4 Cipher Suites 7469 Public Key Pinning Extension for HTTP 7525 Recommendations for Secure Use of TLS and DTLS 7539 ChaCha20 and Poly1305 for IETF Protocols (obsolete) 8439 ChaCha20 and Poly1305 for IETF Protocols 7627 TLS Session Hash and Extended Master Secret Extension 7905 ChaCha20-Poly1305 Cipher Suites for TLS 7919 Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for TLS 1135 The Helminthiasis of the Internet 6698 DNS-Based Authentication of Named Entities (DANE) 6844 DNS Certification Authority Authorization (CAA) Resource Record 3610 Counter with CBC-MAC (CCM) 3852 Cryptographic Message Syntax (CMS) 5083 Cryptographic Message Syntax (CMS) Authenticated-Enveloped-Data Content Type 4086 Randomness Requirements for Security 4107 Guidelines for Cryptographic Key Management 8032 Edwards-Curve Digital Signature Algorithm (EdDSA) 7710 Captive Portal Using DHCP 8484 DNS over HTTPS (DoH) 8467 Padding for DoH und DoT O-Saft-19.01.19/OSaft/Doc/tools.txt000066400000000000000000000160061342117255600165000ustar00rootroot00000000000000 # SID @(#) tools.txt 1.5 18/11/06 00:13:04 NAME O-Saft Tools - tools for o-saft.pl DESCRIPTION Description of tools around o-saft.pl, when, where and how to use. SYNOPSIS o-saft [OPTIONS ..] [COMMANDS ..] target [target target ...] o-saft.pl [OPTIONS ..] [COMMANDS ..] target [target target ...] o-saft.pl [OPTIONS ..] [COMMANDS ..] target [target target ...] | CMD o-saft.tcl [OPTIONS ..] target [target target ...] o-saft-docker [OPTIONS ..] [COMMANDS ..] target [target target ...] env QUERY_STRING="--cgi&OPTIONS&COMMANDS&target" o-saft.cgi https://o-saft.cgi?--cgi&OPTIONS&COMMANDS&target INSTALL.sh contrib/install_openssl.sh contrib/install_perl_modules.pl contrib/gen_standalone.sh contrib/cipher_check.sh contrib/critic.sh where [COMMANDS] and [OPTIONS] are described in the corresponding documentation of the tool. CONCEPTS The main tool, doing all the SSL/TLS related tests, is o-saft.pl . All other tools described here are just wrappers around o-saft.pl or tools for postprocessing output data of o-saft.pl . These tools can be categorized as follows: category tools purpose #---------------+----------------+---------------------------------- CLI o-saft.pl # it's me General Wrapper o-saft # use o-saft.pl with prostprocessors GUI o-saft.tcl # use o-saft.pl from GUI CGI o-saft.cgi # use o-saft.pl from web server VM o-saft-docker # use o-saft.pl inside docker Postprocess contrib/* # prostprocessor tools Advanced Tools contrib/* # use o-saft.pl in advanced modes Installation INSTALL.sh # simple installation tool Development make # functional testing Development .... # ... comming soon #---------------+----------------+---------------------------------- For a description of o-saft.pl itself, please see: o-saft.pl --help All results printed by o-saft.pl are on STDOUT. It does not create any files, even no intermediate/temporary files. So it is very simple to pipe o-saft.pl to other programs, they are called postprocessors here. TOOLS CLI o-saft.pl is the main tool, see CONCEPTS above. It will be called by all other tools. General Wrapper o-saft is the general wrapper. It calls o-saft.pl with all passed arguments. All output from called o-saft.pl is piped to the command specified with the -post= option. The main purpose is to use postprocessors inside a VM like docker, or when called from a CGI script. o-saft [COMMANDS] [OPTIONS] target o-saft [COMMANDS] [OPTIONS] target -post='bunt.pl' o-saft-docker -id=osawp/o-saft -post='bunt.pl' ' [COMMANDS] [OPTIONS] target GUI o-saft.tcl is the graphical user interface for o-saft.pl . o-saft.tcl o-saft.tcl --docker o-saft-docker -id=osawp/o-saft CGI o-saft.cgi is a wrapper to start o-saft.pl via a webserver. The webpage to use o-saft.pl as CGI can be generated with: o-saft.pl --no-rc --no-warning --help=gen-cgi it can also be generated using: make o-saft.cgi.html this HTML form then calls o-saft.cgi with the appropriate parameters. o-saft.php is a wrapper to start o-saft.pl via a webserver, usage is not recommended, see WARNING in the file itself. VM o-saft-docker calls o-saft.pl in a docker image. o-saft-docker [COMMANDS] [OPTIONS] target o-saft-docker -id=osawp/o-saft.pl [COMMANDS] [OPTIONS] target See also docs/o-saft-docker.pdf . Postprocess Various postprocessors exist. They all change the content or format of o-saft.pl's output. See the files itself what they do. contrib/bunt.pl contrib/*.awk contrib/* TBD The are used in general like: o-saft.pl ... target | contrib/..... Advanced Tools Check a target for ciphers with various methods: contrib/cipher_check.sh In legacy systems, or when resoources are limited, a special vesrion o-saft-standalone.pl can be used. It is a single Perl script, which contains most functionality. This script can be generated with: make o-saft-standalone.pl Installation INSTALL.sh contrib/install_openssl.sh contrib/install_perl_modules.pl contrib/distribution_install.sh contrib/*_completion_o-saft Development Various, mainly functional, tests have been defined in Makefiles. Simply call make (without arguments) to get more informations. Other files for development are: o-saft-docker-dev t/.perlcritic contrib/critic.sh CUSTOMIZATION The tools can be customized with following files: * o-saft.pl .o-saft.pl o-saft-usr.pl * o-saft.tcl .o-saft.tcl o-saft-img.tcl * o-saft.cgi none, but see contrib/o-saft.php * o-saft-docker none, but see o-saft-docker-dev * SHELL TWEAKS contrib/bash_completion_o-saft contrib/fish_completion_o-saft contrib/tcsh_completion_o-saft EXAMPLES As described in CONCEPTS above, all results printed by o-saft.pl are on STDOUT. The simplest and most common usage looks like: o-saft.pl +check --header some.tld o-saft +check --header some.tld Using postprocessors is done as usual: o-saft.pl +check --header some.tld | contrib/bunt.pl which is the same as: o-saft -post=bunt.pl +check --header some.tl Even if o-saft.pl runs in a container like docker, its results can be postprocessed either in docker itself, like: o-saft -docker -post=bunt.pl +check --header some.tl o-saft-docker -post=bunt.pl +check --header some.tl or do it the traditional way with postprocessing on the calling host: o-saft -docker +check --header some.tld | contrib/bunt.pl o-saft-docker +check --header some.tld | contrib/bunt.pl The GUI o-saft.tcl can also be run in docker: o-saft -docker -gui o-saft-docker -gui or o-saft.tcl can use o-saft.pl in the container o-saft.tcl -docker SEE ALSO * o-saft * o-saft.pl * o-saft.tcl * o-saft-docker * o-saft-docker-dev * Dockerfile * docker * INSTALL.sh VERSION @(#) $VERSION AUTHOR 18. Jan. 2018 Achim Hoffmann O-Saft-19.01.19/OSaft/error_handler.pm000077500000000000000000000540651342117255600172700ustar00rootroot00000000000000#!/usr/bin/perl -w # Filename: error_handler.pm #!############################################################################# #!# Copyright (c) Torsten Gigler #!# This script is part of the OWASP-Project 'o-saft'. #!# It's a simple library 'OSaft::error_handler' stores and optionally #!# prints all classified errors for other parts of o-saft. #!#---------------------------------------------------------------------------- #!# THIS Software is in ALPHA state, please give us feed back via #!# https://lists.owasp.org/mailman/listinfo/o-saft #!#---------------------------------------------------------------------------- #!# This software is provided "as is", without warranty of any kind, express or #!# implied, including but not limited to the warranties of merchantability, #!# fitness for a particular purpose. In no event shall the copyright holders #!# or authors be liable for any claim, damages or other liability. #!# This software is distributed in the hope that it will be useful. #!# #!# This software is licensed under GPLv2. #!# #!# GPL - The GNU General Public License, version 2 #!# as specified in: http://www.gnu.org/licenses/gpl-2.0 #!# or a copy of it https://github.com/OWASP/O-Saft/blob/master/LICENSE.md #!# Permits anyone the right to use and modify the software without limitations #!# as long as proper credits are given and the original and modified source #!# code are included. Requires that the final product, software derivate from #!# the original source or any software utilizing a GPL component, such as #!# this, is also licensed under the same GPL license. #!############################################################################# #!# WARNING: #!# This is no "academically" certified code, but written to be understood and #!# modified by humans (you:) easily. Please see the documentation in section #!# "Program Code" at the end of this file if you want to improve the program. #!############################################################################# #?############################################################################# #? package 'error_handler' stores and optionally prints all classified errors. #? The latest error can be called back, eg. if the last retry missed. #? This package uses static class methods and static data within the handler #? to store and read the last error. #? To use it call 'use OSaft::error_handler qw(:subs :sslhello_constants)' #? exported subs: #? error_handler->new({=>}); set new values for a new error #? with = #? type: no error (OERR_NO_ERROR(=1)) or type of the error(<0) #? (see sslhello_constants, constant OERR_...), needs to be #? a more severe error than the stored error type (=smaller value) #? module: text: module or package of the caller where the error occured #? sub text: sub of the caller where the error occored #? id text: id inside the sub to identify the exact location where #? the error occured #? message: text: error message providede by the caller #? print: 1: prints a standardized warning to stdout; 0: no output (default) #? warn: 1: prints a standardized warning to stderr; 0: no output (default) #? trace: 1: prints a standardized trace to stdouti (default); 0: no output #? error_handler->reset_err(): #? reset the last error, optionally set a new error using hash_ref #? error_handler->is_err(): returns '1' if an error has occured #? error_handler->get_err_type(): get (internal) number of the last error type #? error_handler->get_err_type_name(): get name of the last error type #? error_handler->get_err_val(): get a value of the error hash #? error_handler->get_err_str(): get and print an error message #? #? mainly used for testing and debugging: #? error_handler->get_err_hash(, ): #? get the error hash as string, is an optional prefix after a new #? line (e.g. some spaces for the indent), #? if the optional 'hash_ref' is valid this hash is used #? error_handler->get_all_err_types(): get all possible defined error types and their internal representation #? as a string #? ---------------------------------------------------------------------------- #? constants: #? sslhello_contants: CONSTANTS used for SSLHello: import them using #? 'use OSaft::error_handler qw(:subs :sslhello_constants)' #?############################################################################# package OSaft::error_handler; use strict; use warnings; use Carp; use Exporter qw(import); use constant { ## no critic qw(ValuesAndExpressions::ProhibitConstantPragma) # the version number of this package OERR_VERSION => '18.03.18', # error types (general) OERR_NO_ERROR => 1, # no error OERR_UNKNOWN_TYPE => -9999, # unknown error type, needs to be the most fatal error (=smallest number) # error texts OERR_UNDEFINED_TXT => "<>", OERR_UNKNOWN_TXT => "<>", #special error types for SSLhello, the smaller value is more severe (they may be changed here if needed) OERR_SSLHELLO_ABORT_PROGRAM => -9000, # error: abort running this program -> exit OERR_SSLHELLO_ABORT_HOST => -99, # error: abort testing this host OERR_SSLHELLO_RETRY_HOST => -94, # error: retry testing this host OERR_SSLHELLO_ABORT_PROTOCOL => -89, # error: abort testing this protocol for this host OERR_SSLHELLO_RETRY_PROTOCOL => -84, # error: retry testing this protocol for this host OERR_SSLHELLO_ABORT_CIPHERS => -79, # error: abort testing this cipher(s) for this protocol OERR_SSLHELLO_RETRY_CIPHERS => -74, # error: retry testing this cipher(s) for this protocol OERR_SSLHELLO_ABORT_EXTENSIONS => -69, # error: abort testing this extensions for this ciphers OERR_SSLHELLO_RETRY_EXTENSIONS => -64, # error: retry testing this extensions for this ciphers OERR_SSLHELLO_TEST_EXTENSIONS => -59, # test all possible values for listed extensions OERR_SSLHELLO_RETRY_RECORD => -49, # error: retry to send this record (e.g. DTLS) OERR_SSLHELLO_MERGE_RECORD_FRAGMENTS => -39, # try to merge fragmented record OERR_SSLHELLO_MERGE_DTLS => -29, # try to merge fragmented DTLS packets OERR_SSLHELLO_ERROR_MESSAGE_IGNORED => -1, # error message ignored }; our $VERSION = OERR_VERSION; our @EXPORT_OK = ( qw( new is_err get_err_str reset_err get_err_val get_err_type get_err_type _name get_err_hash get_all_err_types version OERR_VERSION OERR_UNKNOWN_TYPE OERR_NO_ERROR OERR_UNDEFINED_TXT OERR_UNKNOWN_TXT OERR_SSLHELLO_ABORT_PROGRAM OERR_SSLHELLO_ABORT_HOST OERR_SSLHELLO_RETRY_HOST OERR_SSLHELLO_ABORT_PROTOCOL OERR_SSLHELLO_RETRY_PROTOCOL OERR_SSLHELLO_ABORT_CIPHERS OERR_SSLHELLO_RETRY_CIPHERS OERR_SSLHELLO_ABORT_EXTENSIONS OERR_SSLHELLO_RETRY_EXTENSIONS OERR_SSLHELLO_TEST_EXTENSIONS OERR_SSLHELLO_RETRY_RECORD OERR_SSLHELLO_MERGE_RECORD_FRAGMENTS OERR_SSLHELLO_MERGE_DTLS OERR_SSLHELLO_ERROR_MESSAGE_IGNORED ) ); our %EXPORT_TAGS = ( subs => [qw(new is_err get_err_str reset_err get_err_val get_err_type get_err_type_name get_err_hash get_all_err_types )], #all subs besides 'version' sslhello_contants => [qw( OERR_VERSION OERR_NO_ERROR OERR_UNKNOWN_TYPE OERR_UNDEFINED_TXT OERR_UNKNOWN_TXT OERR_SSLHELLO_ABORT_PROGRAM OERR_SSLHELLO_ABORT_HOST OERR_SSLHELLO_RETRY_HOST OERR_SSLHELLO_ABORT_PROTOCOL OERR_SSLHELLO_RETRY_PROTOCOL OERR_SSLHELLO_ABORT_CIPHERS OERR_SSLHELLO_RETRY_CIPHERS OERR_SSLHELLO_ABORT_EXTENSIONS OERR_SSLHELLO_RETRY_EXTENSIONS OERR_SSLHELLO_TEST_EXTENSIONS OERR_SSLHELLO_RETRY_RECORD OERR_SSLHELLO_MERGE_RECORD_FRAGMENTS OERR_SSLHELLO_MERGE_DTLS OERR_SSLHELLO_ERROR_MESSAGE_IGNORED )], ); # reverse hash to show the names of the used constants in the modules that use this package my $ERROR_TYPE_RHASH_REF = { (OERR_NO_ERROR) => 'OERR_NO_ERROR', (OERR_UNKNOWN_TYPE) => 'OERR_UNKNOWN_TYPE', (OERR_SSLHELLO_ABORT_PROGRAM) => 'OERR_SSLHELLO_ABORT_PROGRAM', (OERR_SSLHELLO_ABORT_HOST) => 'OERR_SSLHELLO_ABORT_HOST', (OERR_SSLHELLO_RETRY_HOST) => 'OERR_SSLHELLO_RETRY_HOST', (OERR_SSLHELLO_ABORT_PROTOCOL) => 'OERR_SSLHELLO_ABORT_PROTOCOL', (OERR_SSLHELLO_RETRY_PROTOCOL) => 'OERR_SSLHELLO_RETRY_PROTOCOL', (OERR_SSLHELLO_ABORT_CIPHERS) => 'OERR_SSLHELLO_ABORT_CIPHERS', (OERR_SSLHELLO_RETRY_CIPHERS) => 'OERR_SSLHELLO_RETRY_CIPHERS', (OERR_SSLHELLO_ABORT_EXTENSIONS) => 'OERR_SSLHELLO_ABORT_EXTENSIONS', (OERR_SSLHELLO_RETRY_EXTENSIONS) => 'OERR_SSLHELLO_RETRY_EXTENSIONS', (OERR_SSLHELLO_TEST_EXTENSIONS) => 'OERR_SSLHELLO_TEST_EXTENSIONS', (OERR_SSLHELLO_RETRY_RECORD) => 'OERR_SSLHELLO_RETRY_RECORD', (OERR_SSLHELLO_MERGE_RECORD_FRAGMENTS) => 'OERR_SSLHELLO_MERGE_RECORD_FRAGMENTS', (OERR_SSLHELLO_MERGE_DTLS) => 'OERR_SSLHELLO_MERGE_DTLS', (OERR_SSLHELLO_ERROR_MESSAGE_IGNORED) => 'OERR_SSLHELLO_ERROR_MESSAGE_IGNORED', }; # static hash object to store the last error my %err_hash = ( type => OERR_NO_ERROR, module => "", sub => OERR_UNDEFINED_TXT, id => "", message => OERR_UNDEFINED_TXT, print => 0, warn => 0, trace => 1, ); #?--------------------------------------------------------------------------------------- #? sub version () #? prints the official version number of error_handler (yy-mm-dd) sub version { local $\ = ""; # no auto '\n' at the end of the line print "OSaft::error_handler (". OERR_VERSION .")\n"; return; } # version #?--------------------------------------------------------------------------------------- #? sub _compile_err_str (;$) #? internal sub that compiles a string ($err_str) based on the hash keys of $err_hash #? $err_hash{type} should be defined and known. If it isn't the err_string #? remarks this lack all other hash keys are suppressed if they do not exist #? or are not defined no input variables needed #? if the optional variable 'hash_ref' is used, the referenced hash is used instead of the $err_hash sub _compile_err_str { my ($arg_ref) = @_; # $arg_ref is optional, internal function: no $class! unless (defined ($arg_ref) && ($arg_ref)) { # use \$err_hash if $arg_ref is not defined (default) $arg_ref = \%err_hash; } elsif ($err_hash{trace}) { print " \$arg_ref defined: $arg_ref\n"; } my $err_str=""; $err_str = $arg_ref->{module} if ( (exists ($arg_ref->{module})) && (defined ($arg_ref->{module})) ); $err_str .= "::".$arg_ref->{sub} if ( (exists ($arg_ref->{sub})) && (defined ($arg_ref->{sub})) ); $err_str .= " (".$arg_ref->{id}."):" if ( (exists ($arg_ref->{id})) && (defined ($arg_ref->{id})) ); $err_str .= " ".$arg_ref->{message} if ( (exists ($arg_ref->{message})) && (defined ($arg_ref->{message})) ); if ( (exists ($arg_ref->{type})) && (defined ($arg_ref->{type})) ) { # type key is used # check if is type is known (defind in the reverse hash): if ( (exists ($ERROR_TYPE_RHASH_REF->{$arg_ref->{type}})) && (defined ($ERROR_TYPE_RHASH_REF->{$arg_ref->{type}})) ) { if ( (exists ($arg_ref->{trace})) && (0<$arg_ref->{trace}) ) { # show the type if trace is used $err_str .= " [Type=".$ERROR_TYPE_RHASH_REF->{$arg_ref->{type}}; $err_str .= "(".$arg_ref->{type}.")" if (2<$arg_ref->{trace}); $err_str .= "]"; } # end trace } else { # unknown type (not defined in ERROR_TYPE_RHASH_REF) $err_str .= " [Type= ".(OERR_UNKNOWN_TXT)." (".$arg_ref->{type}.")]"; } } else { # undefined type $err_str .= " [Type=".(OERR_UNDEFINED_TXT)."]"; } return ($err_str); } # _compile_err_str #?--------------------------------------------------------------------------------------- #? sub new($$): #? set default values of an error hash and set values for received elements #? parameters: #? $class: added automatically when method is used #? $arg_ref: the referenced hash ovwerwrites the $err_hash if its type is #? more fatal than the old type sub new { my ($class, $arg_ref) = @_; # $class is not used my $tmp_err_str = ""; my $tmp_text = ""; # error handling inside error handling: # undefined/unknown error type in static err_hash unless ( (exists ($ERROR_TYPE_RHASH_REF->{$err_hash{type}})) && (defined ($ERROR_TYPE_RHASH_REF->{$err_hash{type}})) ) { $tmp_err_str = _compile_err_str(); $tmp_text = "OSaft::error_handler->new: internal error: unknown error type in"; print qq($tmp_text "$tmp_err_str".) if ($err_hash{trace}); carp (qq($tmp_text "$tmp_err_str".)); $err_hash{type} = OERR_UNKNOWN_TYPE; # define error type to 'unknown', which is the most fatal } else { # undefined $arg_ref: no new error unless (defined ($arg_ref)) { $arg_ref->{type} = OERR_UNKNOWN_TYPE; # define error type to 'unknown', which is the most fatal $arg_ref->{module} = 'OSaft::error_handler'; $arg_ref->{sub} = 'new'; $arg_ref->{message} = "internal error: undefined \$arg_ref"; $tmp_err_str = _compile_err_str($arg_ref); print "$tmp_err_str" if ($err_hash{trace}); carp ($tmp_err_str); return 0; } # undefined/unknown Error Type in new $arg_ref->{type} unless ( (exists ($ERROR_TYPE_RHASH_REF->{$arg_ref->{type}})) && (defined ($ERROR_TYPE_RHASH_REF->{$arg_ref->{type}})) ) { $tmp_err_str = _compile_err_str($arg_ref); print qq($tmp_text "$tmp_err_str".) if ($err_hash{trace}); carp (qq($tmp_text "$tmp_err_str".)); $arg_ref->{type} = OERR_UNKNOWN_TYPE; # define error type to 'unknown', which is the most fatal } if ($err_hash{type} < $arg_ref->{type}) { # new error is less important than the previous my $old_err_str = _compile_err_str(); $tmp_err_str = _compile_err_str($arg_ref); $tmp_text = "OSaft::error_handler->new: new error type in"; print qq($tmp_text "$tmp_err_str" is less important than the previous "$old_err_str".) if ($err_hash{trace}); carp (qq($tmp_text "$tmp_err_str" is less important than the previous "$old_err_str".)); return 0; } } %err_hash = ( %err_hash, # previous keys and values %$arg_ref # keys and values overwrite the previous ) if ($arg_ref); my $err_str = _compile_err_str(); print "$err_str\n" if ($err_hash{print}); carp ($err_str) if ($err_hash{warn}); return 1; } # new #?--------------------------------------------------------------------------------------- #? reset the error_handler (no error) #? opionally owerwrite it with the hash values referenced by arg_ref sub reset_err { my ($class, $arg_ref) = @_; # $class is not used %err_hash = ( # reset to default values and overwrite by optional hash arg_ref type => OERR_NO_ERROR, module => "", sub => OERR_UNKNOWN_TXT, id => "", message => OERR_UNKNOWN_TXT, print => 0, warn => 0, trace => 1, ); %err_hash = ( %err_hash, # previous keys and values %$arg_ref # keys and values overwrite the previous if $arg_ref is defined and not empty ) if ($arg_ref); if (2<$err_hash{trace}) { my $err_str = _compile_err_str(); print "$err_str\n"; } return 1; } # reset_err #?--------------------------------------------------------------------------------------- #? sub is_err(): #? returns true (1) if an error is stored in the hash of the error_handler sub is_err { if ( (exists ($err_hash{type})) && (defined ($err_hash{type})) ) { return ($err_hash{type} != OERR_NO_ERROR); } else { # internal error: no type defined my $err_str = "OSaft::error_handler->is_err: internal error: undefined error type in \$error_hash: "; $err_str .= _compile_err_str(); print "$err_str\n" if (2<$err_hash{trace}); carp ($err_str); return (1); } } # is_err #?--------------------------------------------------------------------------------------- #? sub get_err_type(): #? get error type (number) sub get_err_type { if ( (exists ($err_hash {type})) && (defined ($err_hash {type})) ) { return ($err_hash {type}); } else { print "Error type is ".OERR_UNDEFINED_TXT if ($err_hash{trace}); carp ("Error type is ".OERR_UNDEFINED_TXT); } return (undef); } # get_err_type #?--------------------------------------------------------------------------------------- #? sub get_err_type_name(): #? get error type ame sub get_err_type_name { if ( (exists ($err_hash {type})) && (defined ($err_hash {type})) ) { return ($ERROR_TYPE_RHASH_REF->{$err_hash{type}}) if ( (exists ($ERROR_TYPE_RHASH_REF->{$err_hash{type}})) && (defined ($ERROR_TYPE_RHASH_REF->{$err_hash{type}})) ); return (OERR_UNKNOWN_TXT); } else { print "Error type is ".OERR_UNDEFINED_TXT if ($err_hash{trace}); carp ("Error type is ".OERR_UNDEFINED_TXT); } return (OERR_UNDEFINED_TXT); } # get_err_type_name #?--------------------------------------------------------------------------------------- #? sub get_err_val(): #? get a single value of an error hash element #? parameters: #? $class: added automatically when method is used #? $key_arg: hash key where the value sould be fetched sub get_err_val { my ($class, $key_arg) = @_; # $class is not used return ($err_hash {$key_arg}) if ( (exists ($err_hash {$key_arg})) && (defined ($err_hash {$key_arg})) ); return; } # get_err_val #?--------------------------------------------------------------------------------------- #? sub get_err_str(): #? get the error string #? no input variable needed sub get_err_str { unless ( (exists ($ERROR_TYPE_RHASH_REF->{$err_hash{type}})) && (defined ($ERROR_TYPE_RHASH_REF->{$err_hash{type}})) ) { # undefined Error Type my $tmp_err_str = _compile_err_str(); my$tmp_text = "OSaft::error_handler->get_err_str: internal error: unknown error type in"; print qq($tmp_text "$tmp_err_str".\n) if ($err_hash{trace}); carp (qq($tmp_text "$tmp_err_str".\n)); $err_hash{type} = OERR_UNKNOWN_TYPE; # overwrite error type to unknown, which is the most fatal } return (_compile_err_str()); } #get_err_str #?--------------------------------------------------------------------------------------- #? sub get_err_hash ($;$$): #? get the error hash as string (mainly used for debugging) #? parameters: #? $class: added automatically when method is used #? $prefix: optional prefix after new line (e.g. some spaces for the indent) #? $hash_ref: optional ref to an error_hash (default: %err_hash) #? returns the compiled output sub get_err_hash { my ($class, $prefix, $hash_ref) = @_; # $class is not used later, it is added automatically when calling the method my $err_hash_str = ""; $prefix = "" if (not defined($prefix)); # default is no indent $hash_ref = \%err_hash if (not defined($hash_ref)); # default is the error_hash print ">get_err_hash\n" if (2<$err_hash{trace}); #_trace "\n\$class = $class\n"; #_trace "\$hash_ref = ".\%$err_hash."\n"; foreach my $err_key (sort (keys(%$hash_ref)) ) { $err_hash_str .= $prefix if ($err_hash_str !~ /^$/x); # not the first line $err_hash_str .= "\$hash->\{$err_key\} => ".$hash_ref->{$err_key}."\n"; } return ($err_hash_str); } # get_err_hash #?--------------------------------------------------------------------------------------- #? sub get_all_err_types($;$) #? get all possible defined error types and their internal representation as #? a string (mainly used for debugging) #? parameters: #? $class: added automatically when method is used #? $prefix: optional prefix after new line (e.g. some spaces for the indent) sub get_all_err_types { my ($class, $prefix) = @_; my $err_types_str=""; print ">get_all_err_types\n" if ($err_hash{trace}); foreach my $key (sort {$a <=> $b} (keys(%$ERROR_TYPE_RHASH_REF)) ) { $err_types_str .= $prefix if ($err_types_str !~ /^$/x); # not the first line $err_types_str .= "ERROR_TYPE_RHASH_REF\{$key\} => ".$ERROR_TYPE_RHASH_REF->{$key}."\n"; } return ($err_types_str); } # get_all_err_types 1; O-Saft-19.01.19/README000066400000000000000000000114011342117255600137300ustar00rootroot00000000000000 /~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-. Version: 19.01.19 ) O-Saft - OWASP SSL advanced forensic tool ( ) /~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-/ ( ) DESCRIPTION ( This tools lists information about remote target's SSL certificate ) and tests the remote target according given list of ciphers. ( ) UNIQUE FEATURES ( =============== ) ### * working in closed environments, i.e. without internet connection ( ### * checking availability of ciphers independent of installed library ) ### * checking for all possible ciphers (up to 65535 per SSL protocol) ( ### * needs just perl without modules for checking ciphers and protocols ) ### * mainly same results on all platforms ( ) WHY? ( Why a new tool for checking SSL when there already exist a dozens or ) more good tools in 2012? Some (but not all) reasons are: ( * lack of tests of unusual ciphers ) * different results returned for the same check on same target ( * missing functionality (checks) according modern SSL/TLS ) * lack of tests of unusual (SSL, certificate) configurations ( * (mainly) missing feasability to add own tests ) ( For more details, please use ) o-saft.pl --help ( or read the source ;-) ) ( TARGET AUDIENCE ) * penetration testers ( * administrators ) ( INSTALLATION ) o-saft.pl requires following Perl modules: ( Net::SSLeay (prefered >= 1.51, recommended 1.85) ) IO::Socket::SSL (prefered >= 1.37, recommended 2.002) ( IO::Socket::INET (prefered >= 1.31) ) Net::DNS (prefered >= 0.65, for --mx option only) ( ) O-Saft can be executed from within the unpacked or cloned directory, ( installation is not necessary. However, a INSTALL.sh script will be ) provided, which can be called as follows: ( INSTALL.sh ) INSTALL.sh --clean ( INSTALL.sh --check ) INSTALL.sh --n /path/to/install --force ( INSTALL.sh /path/to/install --force ) ( There're no dependencies to other perl modules for checkAllCiphers.pl ) so the test of all ciphers (aka +cipherall) will work with it. ( The modules Net::SSLinfo, Net::SSLhello are part of O-Saft and should ) be installed in ./Net . ( ) ( Following files are optional: ) .o-saft.pl (private user configuration) ( o-saft-dbx.pm (for debugging, tracing) ) o-saft-usr.pm (private functions, some kind of API) ( o-saft-man.pm (documentation and generation functions) ) o-saft.pod (documentation in POD format) ( checkAllCiphers.pl (simple script for +cipherall option) ) .o-saft.tcl (private user configuration for GUI) ( o-saft-img.tcl (images for buttons in GUI) ) contrib/* (additional programs and tools) ( ) QUICK START ( o-saft.pl --help ) o-saft.pl +check your.tld ( o-saft.pl +info your.tld ) o-saft.pl +quick your.tld ( o-saft.pl +cipher your.tld ) o-saft.pl +cipherall your.tld ( o-saft.pl --help=commands ) ( o-saft.tcl (simple GUI; requires Tcl/Tk 8.5 or newer) ) ( o-saft-docker (simple wrapper to call o-saft.pl in docker image) ) ( Project home is https://www.owasp.org/index.php/O-Saft ) Project roadmap https://www.owasp.org/index.php/Projects/O-Saft/Roadmap ( ) Historic Project home https://www.owasp.org/index.php/Projects/O-Saft ( ) Get a Copy (latest stable release) ( wget https://github.com/OWASP/O-Saft/raw/master/o-saft.tgz ) ( Get a Copy (development version) ) git clone https://github.com/OWASP/O-Saft.git ( git clone git@github.com:OWASP/O-Saft.git ) ( Get Docker Image (latest stable release) ) docker pull owasp/o-saft ( ) VERSION ( The version of the tarball o-saft.tgz represents the version listed ) on top herein. All other files in the repository may be ahead of this ( (tarball) version. ) ( SHA256 checksum of o-saft.tgz ) 29d4faa2ed3025ed18d31175e868d6be9312b36ba486c6e5f305afeb34947f68 ( ) SHA256 checksum of owasp/o-saft:latest and owasp/o-saft:18.11.18 ( b85423d142c186c1cf10494aa0e993f6f2030ab769977aca9584d7d650421697 ) ( NOTE that the checksums listed here are the previous versions if this ) file is from o-saft.tgz itself, or inside the docker image. ( \_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-~-_-/ O-Saft-19.01.19/checkAllCiphers.pl000077500000000000000000001047761342117255600164560ustar00rootroot00000000000000#!/usr/bin/perl -w # Filename : checkAllCiphers.pl #!############################################################################# #!# Copyright (c) Torsten Gigler #!# This script is part of the OWASP-Project 'o-saft' #!# It's a simple wrapper the SSLhello. #!#---------------------------------------------------------------------------- #!# THIS Software is in ALPHA state, please give us feed back via #!# https://lists.owasp.org/mailman/listinfo/o-saft #!#---------------------------------------------------------------------------- #!# This software is provided "as is", without warranty of any kind, express or #!# implied, including but not limited to the warranties of merchantability, #!# fitness for a particular purpose. In no event shall the copyright holders #!# or authors be liable for any claim, damages or other liability. #!# This software is distributed in the hope that it will be useful. #!# #!# This software is licensed under GPLv2. #!# #!# GPL - The GNU General Public License, version 2 #!# as specified in: http://www.gnu.org/licenses/gpl-2.0 #!# or a copy of it https://github.com/OWASP/O-Saft/blob/master/LICENSE.md #!# Permits anyone the right to use and modify the software without limitations #!# as long as proper credits are given and the original and modified source #!# code are included. Requires that the final product, software derivate from #!# the original source or any software utilizing a GPL component, such as #!# this, is also licensed under the same GPL license. #!############################################################################# #!# WARNING: #!# This is no "academically" certified code, but written to be understood and #!# modified by humans (you:) easily. Please see the documentation in section #!# "Program Code" at the end of this file if you want to improve the program. use strict; use warnings; use Carp; #replaces warn and die use OSaft::error_handler qw (:sslhello_contants); # use internal error_handler, get all constants used for SSLHELLO, for subs the full names will be used (includung OSaft::error_handler->)$ use osaft; BEGIN { my $_path = $0; $_path =~ s#[/\\][^/\\]*$##; unshift(@INC, $_path, "/bin" ); # /bin for special installation on portable media } my $VERSION = "17.07.15"; my $me = $0; $me =~ s#.*(?:/|\\)##; my $mepath = $0; $mepath =~ s#/[^/\\]*$##; $mepath = "./" if ($mepath eq $me); my $mename = "checkAllCiphers"; $mename = "O-Saft " if ($me !~ /checkAllCiphers/); sub printhelp { print << "EoT"; NAME $me - simple wrapper for Net::SSLhello to test for all ciphers SYNOPSIS $me [OPTIONS] hostname[:port] | mx-domain-name[:port] OPTIONS --help nice option --host=HOST add HOST to list of hosts to be checked -h=HOST dito. --port=PORT use PORT for following hosts (default is 443) -p=PORT dito. --proxy=PROXYHOST:PROXYPORT make connection through proxy on PROXYHOST:PROXYPORT --proxyhost=PROXYHOST make connection through proxy on PROXYHOST --proxyport=PROXYPORT make connection through proxy on PROXYHOST:PROXYPORT --proxyuser=PROXYUSER (not yet implemented) user to authenticate at PROXYHOST --proxypass=PROXYPASS (not yet implemented) passowrd to authenticate at PROXYUSER --mx make a MX-Record DNS lookup for the mx-domain-name (makes sense together with --STARTTLS=SMTP) --SSL test for this SSL version SSL is any of: sslv2, sslv3, tlsv1, tlsv11, tlsv12, tlsv13, dtlsv09, dtlsv1, (dtlsv11), dtlsv12, dtlsv13 (e.g. --dtlsv12; default: sslv2, sslv3, tlsv1, tlsv11, tlsv12, tlsv13) Remark: All DTLS-Protocols are experimental (see --experimental), DTLSv09 (=OpenSSL pre 0.9.8f), DTLSv11 has never been released --no-SSL do not test for this SSL version SSL see --SSL option --no-tcp do not test any SSL versions using TCP, like sslv2, ... tlsv13 --no-udp do not test any SSL versions using UDP, like dtlsv09, ... dtlsv13 --legacy=L use format L in printed results available formarts: compact, simple, full --sni test with 'Server Name Indication (SNI)' mode if supported by the protocol (default) --no-sni do not test with SNI mode --toggle-sni test with and witout SNI mode (equivalent to --sni-toggle) --sniname=SNINAME if SNINAME is set, this Name is used in the Server Name Indication (SNI) Extension (instead of the hostname) --connect-delay=SEC Additional delay in seconds after each connect for a cipher check. This is useful when connecting to servers which have IPS in place, or are slow in accepting new connections or requests --ssl-retry=CNT number of retries for connects, if timed-out --ssl-timeout=SEC timeout in seconds for connects --cipherrange=RANGE, --range=RANGE RANGE is any of rfc, long, huge, safe, full, SSLv2, shifted (rfc, shifted by 64 bytes to the right) (see o-saft.pl --help) --ssl-maxciphers=CNT maximal number of ciphers sent in a sslhello (default is 64) --ssl-nodataeqnocipher some servers do not answer if none of the ciphers is supported This handling is by default on. Use '--no-ssl-nodataeqnocipher' to switch it off --ssl-use-ecc use supported elliptic curves. Default on. --ssl-use-ec-point use TLS 'ec_point_formats' extension. Default on. --ssl-usereneg use secure renegotion --ssl-doubel-reneg use renegotion SSL Extension also for SCSV (double send) --slow-server-delay=SEC additional delay n secs after a server s connected via a proxy or before starting STARTTLS. This is useful for testing connections via slow proxy chains or slow servers before sending the STARTTLS sequence --starttls Use STARTTLS to start a TLS connection via SMTP --starttls=STARTTLS_TYPE Use STARTTLS to start TLS. STARTTLS_TYPE is any of SMTP (SMTP_2), ACAP, IMAP (IMAP_2), IRC, POP3, FTPS, LDAP, RDP (RDP_SSL), XMPP, CUSTOM (Notes: * SMTP_2 and IMAP_2 are second ways to use SMTP/IMAP, like RDP_SSL for RDP * SMTP: use '--mx' for checking a mail-domain instead of a host) Please give us feedback (especially for FTPS, LDAP, RDP, CUSTOM) The STARTTLS_TYPEs 'ACAP', 'IRC' and 'CUSTOM' need the '--experimental' option, and please take care! You can use the STARTTLS_TYPE 'CUSTOM' to customize your own STARTTLS sequence including error handling, see '--starttls_phase1..5' and --starttls_error1..3 --starttls_delay=SEC seconds to pause before sending a packet, to slow down the starttls-requests (default = 0). This may prevent a blockade of requests due to too much/too fast connections. (Info: In this case there is an automatic suspension and retry with a longer delay) --starttls_phase1..5="VALUE" (VALUE might be an expression or a string) Customize the internal state machine to manage STARTTLS, you can use up to 5 phases: --starttls_phase1: set expression for 'receive data (RX)', e.g. ".?(?:^|\\n)220\\s" --starttls_phase2: set string for 'send data (TX)', e.g. "EHLO o-saft.localhost\\r\\n" --starttls_phase3: set expression for RX, e.g. ".?(?:^|\\n)250\\s" --starttls_phase4: set string for TX, e.g. "STARTTLS\\r\\n" --starttls_phase5: set expression for RX, e.g. ".?(?:^|\\n)220\\s" For the TX phases 2 and 4 solely the escape sequences '\\r', '\\n', '\\t', '\\e', '\\x<00-ff>' and '\\' are supported, e.g. "\\r\\n", "\\x0d\\x0a" It is recommended to use at least TX and RX (last RX to get data that does not belong to the handshake of SSL/TLS itself), furthermore you should use '--trace=3' when you start customizing. Please share your results with us (o-saft (at) lists.owasp.org or via github). needs also '--starttls=CUSTOM', see above optional use of '--starttls_error1..3' to handle errors --starttls_error1..3="EXPRESSION" (or '--starttls_err1..3="EXPRESSION") Optional error handling for customized STARTTLS used in the RX phases (1, 3 and 5) --starttls_error1: set expression for 'temporary unreachable (too many connections)', e.g. ".?(?:^|\\n)(?:421|450)\\s" --starttls_error2: set expression for 'this SSL/TLS-Protocol is not supported', e.g. ".?(?:^|\\n)4[57]4\\s" --starttls_error3: set exptession for 'fatal Error/STARTTLS not supported', e.g. ".*?(?:^|\\n)(?:451|50[023]|554)\\s" needs also '--starttls=CUSTOM' and '--starttls_phase1..3', see above --experimental to use experimental functions --trace Print debugging messages --trace= Print more debugging messages (VALUE=1..4) --trace-time prints additional timestamps in trace output for benchmarking and debugging DESCRIPTION This is just a very simple wrapper for the Net::SSLhello module to test a target for all available ciphers. It is a shortcut for o-saft.pl +cipherall YOUR-HOST INSTALLATION checkAllCiphers.pl requires following Perl modules: IO::Socket::INET (preferred >= 1.31) Net::DNS (if option '--mx' is used) Module Net::SSLhello is part of O-Saft and should be installed in ./Net . All dependencies for these modules must also be installed. EoT return; } # printhelp ##no critic qw(Modules::RequireBarewordIncludes) # Modul name includes a hyphen -> '' and .pm are necessary if (! eval {require 'o-saft-dbx.pm';} ) { # o-saft-dbx may not be installed, try to find in program's directory push(@INC, $mepath); require("o-saft-dbx.pm"); } ##use critic if (! eval {require Net::SSLhello;} ) { # Net::SSLhello may not be installed, try to find in program's directory push(@INC, $mepath); require Net::SSLhello; } my $arg = ""; my @argv = grep {/--trace.?arg/} @ARGV;# preserve --tracearg option push(@argv, @ARGV); #dbx# _dbx "ARG: " . join(" ", @argv); # read file with source for trace and verbose, if any # ------------------------------------- my @dbx = grep {/--(?:trace|v$|yeast)/} @argv; # option can be in .rc-file, hence @argv if ($#dbx >= 0) { $arg = "./o-saft-dbx.pm"; $arg = $dbx[0] if ($dbx[0] =~ m#/#); $arg =~ s#[^=]+=##; # --trace=./myfile.pl if (! -e $arg) { carp "**WARNING: '$arg' not found"; $arg = join("/", $mepath, $arg); # try to find it in installation directory croak "**ERROR: '$!' '$arg'; exit" unless (-e $arg); # no need to continue if required file does not exist # Note: if $mepath or $0 is a symbolic link, above checks fail # we don't fix that! Workaround: install file in ./ } push(@{$dbx{file}}, $arg); printf("=== reading trace file ===\n") if(grep {/(:?--no.?header)/i} @ARGV <= 0); require $arg; # `our' variables are available there } # initialize defaults my $ssl; # temporary variable used in main my $host = ""; # the host currently processed in main my $port = 443; # the port currently used in main # above host, port, legacy and verbose are just shortcuts for corresponding # values in $cfg{}, used for better human readability my %text = ( 'separator' => ":", # separator character between label and value ); # set some default cfg values different to osaft $cfg{'legacy'} = "compact"; # used for sub printCipherStringArray $cfg{'sslhello'}{'maxciphers'} = 64; # configurations for TCP SSL protocol$: number of ciphers sent in SSL3/TLS Client-Hello # scan options and arguments # ------------------------------------- while ($#argv >= 0) { $arg = shift @argv; push(@{$dbx{argv}}, $arg) if (($arg !~ m/^--cfg_/) && ($arg =~ m/^[+-]/)); push(@{$dbx{cfg}}, $arg) if ($arg =~ m/^--cfg_/); # both aprox. match are sufficient for debugging if ($arg !~ /(?:[+]|--)(?:cmd|host|port|exe|lib|cipher|format|legacy|timeout|url)=/) { $arg =~ s/=+$//; # remove trailing = (for CGI mode) } # Simple check for option; only options with syntax --KEY=VALUE allowed. # Following checks use exact matches with 'eq' or regex matches with '=~' #{ options #!# You may read the lines as table with colums like: #!#--------+------------------------+------------------------- #!# argument to check value to be set #!#--------+------------------------+------------------------- if ($arg =~ /^--http$/i) { $cfg{'usehttp'}++; next; } # must be before --h if ($arg =~ /^--no[_-]?http$/i) { $cfg{'usehttp'} = 0; next; } if ($arg =~ /^--h(?:elp)?(?:=(.*))?$/i) { printhelp(); exit 0; } # allow --h --help --h=* if ($arg =~ /^\+help=?(.*)$/i) { printhelp(); exit 0; } # allow +help +help=* if ($arg =~ /^--v(erbose)?$/i) { $cfg{'verbose'}++; next; } if ($arg =~ /^--n$/i) { $cfg{'try'} = 1; next; } if ($arg =~ /^--connect[_-]?delay=(\d+)$/i) { $cfg{'connect_delay'}=$1; next;} if ($arg =~ /^--trace$/i) { $cfg{'trace'}++; next; } if ($arg =~ /^--trace(--|[_-]?arg)$/i) { $cfg{'traceARG'}++; next; } # special internal tracing if ($arg =~ /^--trace([_-]?cmd)$/i) { $cfg{'traceCMD'}++; next; } # .. if ($arg =~ /^--trace(@|[_-]?key)$/i) { $cfg{'traceKEY'}++; next; } # .. if ($arg =~ /^--trace=(\d+)$/i) { $cfg{'trace'} = $1; next; } if ($arg =~ /^--trace([_-]?time)$/i) { $cfg{'traceTIME'}++; $cfg{'trace'} = $cfg{'trace'}||1; next; } # Timestamp on; trace on if it was off if ($arg =~ /^--?p(?:ort)?=(\d+)$/i) { $cfg{'port'} = $1; next; } if ($arg =~ /^--?h(?:ost)?=(.+)$/i) { push(@{$cfg{'hosts'}}, $1 . ":" . ($cfg{'port'}||443)); next; } # proxy options if ($arg =~ /^--proxy=(.+?)\:(\d+)$/i) { $cfg{'proxyhost'}= $1; $cfg{'proxyport'}= $2; next; } if ($arg =~ /^--proxyhost=(.+)$/i) { $cfg{'proxyhost'}= $1; next; } if ($arg =~ /^--proxyport=(.+)$/i) { $cfg{'proxyport'}= $1; next; } if ($arg =~ /^--proxyuser=(.+)$/i) { $cfg{'proxyuser'}= $1; next; } if ($arg =~ /^--proxypass=(.+)$/i) { $cfg{'proxypass'}= $1; next; } if ($arg =~ /^--proxyauth=(.+)$/i) { $cfg{'proxyauth'}= $1; next; } if ($arg =~ /^--slow[_-]?server[_-]?delay=(\d+)$/i) {$cfg{'slowServerDelay'}=$1; next; } if ($arg =~ /^--starttls$/i) { $cfg{'starttls'} = 1; $cfg{'starttlsType'}='SMTP'; next; } # starttls, starttlsType=SMTP(=0) if ($arg =~ /^--starttls=(\w+)$/i) { $cfg{'starttls'} = 1; $cfg{'starttlsType'}=uc($1); next;} # starttls, starttlsType=Typ (EXPERIMENTAL!!) ##Early Alpha!! 2xIMAP to test! # 9 Types defined: SMTP, IMAP, IMAP2, POP3, FTPS, LDAP, RDP, XMPP, CUSTOM if ($arg =~ /^--starttls[_-]?phase(\d)=(.+)$/i){ $cfg{'starttls_phase'}[$1] = $2 if (($1 >0) && ($1<=5)); next; } # starttl, CUSTOM starttls-sequence if ($arg =~ /^--starttls[_-]?err(?:or)?(\d)=(.+)$/i){ $cfg{'starttls_error'}[($1)] = $2 if (($1 >0) && ($1<=3)); next; } # starttls, error-handling for CUSTOMized starttls if ($arg =~ /^--starttls[_-]?delay=(\d+)$/i) {$cfg{'starttlsDelay'}=$1; next;} # option if ($arg =~ /^--sni$/i) { $cfg{'usesni'} = 1; next; } if ($arg =~ /^--no[_-]?sni$/i) { $cfg{'usesni'} = 0; next; } if ($arg =~ /^--toggle[_-]?sni$/i) { $cfg{'usesni'} = 2; next; } # test with and without SNI if ($arg =~ /^--sni[_-]?toggle$/i) { $cfg{'usesni'} = 2; next; } # test with and without SNI if ($arg =~ /^--sni[_-]?name$/i) { $cfg{'sni_name'} = ""; $cfg{'use_sni_name'} = 1; next; } # sniname="" if ($arg =~ /^--sni[_-]?name=(.*)$/i) { $cfg{'sni_name'} = $1; $cfg{'use_sni_name'} = 1; next; } # sniname=SNINAME if ($arg =~ /^--no[_-]?sni[_-]?name$/i) { $cfg{'use_sni_name'} = 0; $cfg{'sni_name'} = "1"; next; } # go back to hostname; ##FIX: reset 'sni_name'="1" until o-saft migrated to get 'use_sni_name', too if ($arg =~ /^--header$/i) { $cfg{'out_header'}= 1; next; } if ($arg =~ /^--no[_-]?header$/i) { $cfg{'out_header'}= 0; push(@ARGV, "--no-header"); next; } # push() is ugly hack to preserve option even from rc-file if ($arg =~ /^--?sslv?2$/i) { $cfg{'SSLv2'} = 1; next; } # allow case insensitive if ($arg =~ /^--?sslv?3$/i) { $cfg{'SSLv3'} = 1; next; } # .. if ($arg =~ /^--?tlsv?1$/i) { $cfg{'TLSv1'} = 1; next; } # .. if ($arg =~ /^--?tlsv?1[-_.]?1$/i) { $cfg{'TLSv11'} = 1; next; } # allow ._- separator if ($arg =~ /^--?tlsv?1[-_.]?2$/i) { $cfg{'TLSv12'} = 1; next; } # .. if ($arg =~ /^--?dtlsv?0[-_.]?9$/i) { $cfg{'DTLSv09'} = 1; next; } # .. OpenSSL pre 0.9.8f if ($arg =~ /^--?dtlsv?1[-_.]?0?$/i) { $cfg{'DTLSv1'} = 1; next; } # .. if ($arg =~ /^--?dtlsv?1[-_.]?1$/i) { $cfg{'DTLSv11'} = 1; next; } # .. if ($arg =~ /^--?dtlsv?1[-_.]?2$/i) { $cfg{'DTLSv12'} = 1; next; } # .. if ($arg =~ /^--?dtlsv?1[-_.]?3$/i) { $cfg{'DTLSv13'} = 1; next; } # .. if ($arg =~ /^--no[_-]?sslv?2$/i) { $cfg{'SSLv2'} = 0; next; } # allow _- separator if ($arg =~ /^--no[_-]?sslv?3$/i) { $cfg{'SSLv3'} = 0; next; } # .. if ($arg =~ /^--no[_-]?tlsv?1$/i) { $cfg{'TLSv1'} = 0; next; } # .. if ($arg =~ /^--no[_-]?tlsv?11$/i) { $cfg{'TLSv11'} = 0; next; } # .. if ($arg =~ /^--no[_-]?tlsv?12$/i) { $cfg{'TLSv12'} = 0; next; } # .. if ($arg =~ /^--no[_-]?tlsv?13$/i) { $cfg{'TLSv13'} = 0; next; } # .. if ($arg =~ /^--no[_-]?dtlsv?09$/i) { $cfg{'DTLSv09'} = 0; next; } # .. OpenSSL pre 0.9.8f if ($arg =~ /^--no[_-]?dtlsv?10?$/i) { $cfg{'DTLSv1'} = 0; next; } # .. if ($arg =~ /^--no[_-]?dtlsv?11$/i) { $cfg{'DTLSv11'} = 0; next; } # .. if ($arg =~ /^--no[_-]?dtlsv?12$/i) { $cfg{'DTLSv12'} = 0; next; } # .. if ($arg =~ /^--no[_-]?dtlsv?13$/i) { $cfg{'DTLSv13'} = 0; next; } # .. if ($arg =~ /^--no[_-]?tcp$/i) { $cfg{'SSLv2'} = 0; $cfg{'SSLv3'} = 0; $cfg{'TLSv1'} = 0; $cfg{'TLSv11'} = 0; $cfg{'TLSv12'} = 0; $cfg{'TLSv13'} = 0; next; } # ..$ if ($arg =~ /^--no[_-]?udp$/i) { $cfg{'DTLSv09'} = 0; # OpenSSL pre 0.9.8f $cfg{'DTLSv1'} = 0; $cfg{'DTLSv11'} = 0; $cfg{'DTLSv12'} = 0; $cfg{'DTLSv13'} = 0; next; } # ..$ if ($arg =~ /^--nullsslv?2$/i) { $cfg{'nullssl2'} = 1; next; } # .. if ($arg =~ /^--no[_-]?dns$/i) { $cfg{'usedns'} = 0; next; } if ($arg =~ /^--dns$/i) { $cfg{'usedns'} = 1; next; } if ($arg =~ /^--no[_-]?(?:dns[_-]?)?mx$/i) { $cfg{'usemx'} = 0; next; } if ($arg =~ /^--(?:dns[_-]?)?mx$/i) { local $@=""; # this command needs an additional Perl Module eval { require Net::DNS; $cfg{'usemx'}= 1; # no error 1; } or do { # error handling carp ("$me: Perl Module 'NET::DNS' is not installed, opition '$arg' ignored: $@"); }; next; } if ($arg =~ /^--enabled$/i) { $cfg{'enabled'} = 1; next; } if ($arg =~ /^--disabled$/i) { $cfg{'disabled'} = 1; next; } if ($arg =~ /^--printavailable$/i) { $cfg{'enabled'} = 1; next; } # ssldiagnos if ($arg =~ /^--showhost$/i) { $cfg{'showhost'} = 1; next; } if ($arg =~ /^--no[_-]failed$/i) { $cfg{'enabled'} = 0; next; } # sslscan if ($arg =~ /^--range=(.*)/i) { $cfg{'cipherrange'}=$1;next; } if ($arg =~ /^--cipherrange=(.*)$/i) { $cfg{'cipherrange'}=$1;next; } if ($arg =~ /^--legacy=(.*)$/i) { $cfg{'legacy'} =$1;next; } if ($arg =~ /^--tab$/i) { $text{'separator'}="\t";next;} # TAB character if ($arg =~ /^--no[_-]?ssl[_-]?useecc$/i) { $cfg{'sslhello'}->{'useecc'} = 0; next; } # alias ... if ($arg =~ /^--ssl[_-]?nouseecc$/i) { $cfg{'sslhello'}->{'useecc'} = 0; next; } if ($arg =~ /^--ssl[_-]?useecc$/i) { $cfg{'sslhello'}->{'useecc'} = 1; next; } if ($arg =~ /^--no[_-]?ssl[_-]?useecpoint$/i) { $cfg{'sslhello'}->{'useecpoint'} = 0; next; } # alias ... if ($arg =~ /^--ssl[_-]?nouseecpoint$/i) { $cfg{'sslhello'}->{'useecpoint'} = 0; next; } if ($arg =~ /^--ssl[_-]?useecpoint$/i) { $cfg{'sslhello'}->{'useecpoint'} = 1; next; } if ($arg =~ /^--ssl[_-]?retry=(\d+)$/i) { $cfg{'sslhello'}->{'retry'} =$1; next; } if ($arg =~ /^--ssl[_-]?timeout=(\d+)$/i) { $cfg{'sslhello'}->{'timeout'} =$1; next; } if ($arg =~ /^--ssl[_-]?maxciphers=(\d+)$/i) { $cfg{'sslhello'}->{'maxciphers'} =$1; next; } if ($arg =~ /^--ssl[_-]?usereneg=(\d+)$/i) { $cfg{'sslhello'}->{'usereneg'} =$1; next; } if ($arg =~ /^--no[_-]?ssl[_-]?usereneg$/i) { $cfg{'sslhello'}->{'usereneg'} = 0; next; } # alias ... if ($arg =~ /^--ssl[_-]?no[_-]?usereneg$/i) { $cfg{'sslhello'}->{'usereneg'} = 0; next; } if ($arg =~ /^--ssl[_-]?use[_-]?reneg$/i) { $cfg{'sslhello'}->{'usereneg'} = 1; next; } if ($arg =~ /^--ssl[_-]?double[_-]?reneg$/i) { $cfg{'sslhello'}->{'double_reneg'} = 1; next; } if ($arg =~ /^--no[_-]?ssl[_-]?doublereneg$/i) { $cfg{'sslhello'}->{'double_reneg'} = 0; next; } # alias ... if ($arg =~ /^--ssl[_-]?no[_-]?doublereneg$/i) { $cfg{'sslhello'}->{'double_reneg'} = 0; next; } if ($arg =~ /^--no[_-]?nodata(?:eq)?nocipher$/i) { $cfg{'sslhello'}->{'nodatanocipher'} = 0; next; } # alias ... if ($arg =~ /^--no[_-]?ssl[_-]?nodata(?:eq)?nocipher$/i){ $cfg{'sslhello'}->{'nodatanocipher'} = 0; next; } if ($arg =~ /^--ssl[_-]?nodataneqnocipher$/i) { $cfg{'sslhello'}->{'nodatanocipher'} = 0; next; } # alias ... if ($arg =~ /^--nodataneqnocipher$/i) { $cfg{'sslhello'}->{'nodatanocipher'} = 0; next; } # alias if ($arg =~ /^--ssl[_-]?nodata(?:eq)?nocipher$/i) { $cfg{'sslhello'}->{'nodatanocipher'} = 1; next; } if ($arg =~ /^--nodata(?:eq)?nocipher$/i) { $cfg{'sslhello'}->{'nodatanocipher'} = 1; next; } # alias if ($arg =~ /^--?experimental$/i) { $cfg{'experimental'} = 1; next; } #} +---------+----------------------+------------------------- if ($arg =~ /^[+-]/) { carp "**WARNING: unknown command or option '$arg' ignored. Try '$me --help' to get more information!"; next; } push(@{$cfg{'hosts'}}, $arg . ":" . ($cfg{'port'}||443)); } # while # set defaults for Net::SSLhello # ------------------------------------- { no warnings qw(once); # avoid: Name "Net::SSLhello::trace" used only once: possible typo at ... $Net::SSLhello::trace = $cfg{'trace'} if ($cfg{'trace'} > 0); $Net::SSLhello::traceTIME = $cfg{'traceTIME'}; $Net::SSLhello::usesni = $cfg{'usesni'}; $Net::SSLhello::use_sni_name = $cfg{'use_sni_name'}; $Net::SSLhello::sni_name = $cfg{'sni_name'}; $Net::SSLhello::connect_delay = $cfg{'connect_delay'}; $Net::SSLhello::starttls = $cfg{'starttls'}; $Net::SSLhello::starttlsType = $cfg{'starttlsType'}; @Net::SSLhello::starttlsPhaseArray = @{$cfg{'starttls_phase'}}; # add 'starttls_error' array elements according Net::SSLhello's internal # representation push(@Net::SSLhello::starttlsPhaseArray, @{$cfg{'starttls_error'}}[1..3]); if ($cfg{'trace'} > 3) { for my $i (1..5) { _trace (" \$cfg{'starttls_phase'}[$i]=$cfg{'starttls_phase'}[$i]\n") if (defined($cfg{'starttls_phase'}[$i])); } for my $i (1..3) { _trace (" \$cfg{'starttls_error'}[$i]=$cfg{'starttls_error'}[$i]\n") if (defined($cfg{'starttls_error'}[$i])); } } $Net::SSLhello::starttlsDelay = $cfg{'starttlsDelay'}; #reset to original value for each host (same as some lines later to prevent 'used only once' warning) $Net::SSLhello::slowServerDelay = $cfg{'slowServerDelay'}; $Net::SSLhello::timeout = $cfg{'sslhello'}->{'timeout'}; $Net::SSLhello::retry = $cfg{'sslhello'}->{'retry'}; $Net::SSLhello::usereneg = $cfg{'sslhello'}->{'usereneg'}; $Net::SSLhello::useecc = $cfg{'sslhello'}->{'useecc'}; $Net::SSLhello::useecpoint = $cfg{'sslhello'}->{'useecpoint'}; $Net::SSLhello::double_reneg = $cfg{'sslhello'}->{'double_reneg'}; $Net::SSLhello::proxyhost = $cfg{'proxyhost'}; $Net::SSLhello::proxyport = $cfg{'proxyport'}; $Net::SSLhello::max_ciphers = $cfg{'sslhello'}->{'maxciphers'}; $Net::SSLhello::cipherrange = $cfg{'cipherrange'}; $Net::SSLhello::experimental = $cfg{'experimental'}; $Net::SSLhello::noDataEqNoCipher = $cfg{'sslhello'}->{'nodatanocipher'}; } print "##############################################################################\n"; print "# '$me' (part of OWASP project 'O-Saft'),\n"; print "# Version (yy.mm.dd): $VERSION\n"; print "# using (internal) modules:\n"; print "# O-Saft::"; Net::SSLhello::version(); print "# O-Saft::"; OSaft::error_handler::version(); print "##############################################################################\n\n"; #reset error_handler and set basic information for this sub$ OSaft::error_handler->reset_err( {module => $me, sub => '', print => ($cfg{'trace'} > 0), trace => $cfg{'trace'}} ); Net::SSLhello::printParameters() if ($cfg{'trace'} > 1); my $protocols; print "Protocols to check:\n"; # check ssl protocols foreach my $ssl (@{$cfg{'versions'}}) { if ( ($ssl =~ /DTLS/) && ($cfg{$ssl} == 1) && ($cfg{'experimental'} !=1 ) ) { # DTLS support is experimental $protocols .= ", " if ($protocols); $protocols .= "$ssl"; next; } next if ($cfg{$ssl} != 1); # = 0 or undefined print "$ssl\n"; push(@{$cfg{'version'}}, $ssl); } print "Use of Protocol(s) '$protocols' is experimental, please use the option '--experimental' and take care.\n" if ($protocols); print "\n"; if ($cfg{'usemx'}) { # get mx-records _trace2 (" \$cfg{'usemx'} = $cfg{'usemx'}\n"); print "\n# get MX-Records:\n"; @{$cfg{'mx_domains'}} = @{$cfg{'hosts'}}; #we have got mx domains no hosts, yet $cfg{'hosts'} = []; foreach my $mx_domain (@{$cfg{'mx_domains'}}) { # loop domains if ($mx_domain =~ m#.*?:\d+#) { ($mx_domain, $port) = split(":", $mx_domain); } _trace3 (" get MX-Records for '$mx_domain'\n"); my $dns = Net::DNS::Resolver->new; my $mx = $dns->query($mx_domain, 'MX'); my $sep =", "; if (defined ($mx) && defined($mx->answer)) { foreach my $mxRecord ($mx->answer) { _trace3 (" => ". $mxRecord->exchange. ' ('. $mxRecord->preference. ")\n"); push(@{$cfg{'hosts'}}, $mxRecord->exchange . ":" . ($port||25)); printf "%16s%s%5s%s%-6s%s%32s%-6s%s%-4s%s\n", $mx_domain, $sep, # %16s%s ($port||25), $sep, # %5s%s "MX", $sep, # %-6s%s $mxRecord->exchange, $sep, # %32s%s "Prio", $sep, # %-6s%s $mxRecord->preference, $sep;# %-4s%s } } else { printf "%16s%s%5s%s%-6s%s%32s%-6s%s%-4s%s\n", $mx_domain, $sep, # %16s%s ($port||25), $sep, # %5s%s "MX", $sep, # %-6s%s "", $sep, # %32s%s "Prio", $sep, # %-6s%s "", $sep; # %-4s%s } } print "------------------------------------------------------------------------------\n"; } foreach my $host (@{$cfg{'hosts'}}) { # loop hosts #reset error_handler and set basic information for this sub$ OSaft::error_handler->reset_err( {module => $me, sub => '', print => ($cfg{'trace'} > 0), trace => $cfg{'trace'}} ); if ($host =~ m#.*?:\d+#) { ($host, $port) = split(":", $host); $cfg{'port'} = $port; # $cfg{'host'} = $host; } _trace("host{ " . ($host||"") . ":" . $port . "\n"); $cfg{'host'} = $host; $Net::SSLhello::starttlsDelay = $cfg{'starttlsDelay'}; #reset to original value for each host foreach my $ssl (@{$cfg{'version'}}) { my @accepted = (); # List of all Ciphers that are supported by the server with the tested Protocol my @testing = (); my $range = $cfg{'cipherrange'}; # use specified range of constants $range = 'SSLv2_long' if ($ssl eq 'SSLv2'); # but SSLv2 needs its own list: SSLV2+SSLV3-Ciphers #reset error_handler and set basic information for this sub$ OSaft::error_handler->reset_err( {module => $me, sub => '', print => ($cfg{'trace'} > 0), trace => $cfg{'trace'}} ); ## no critic qw(BuiltinFunctions::ProhibitStringyEval) # NOTE: this eval must not use the block form because the value needs to be evaluated push(@testing, sprintf("0x%08X",$_)) foreach (eval($cfg{'cipherranges'}->{$range})); ## use critic if ($Net::SSLhello::usesni) { # usesni (--sni: 1 or --togglesni: 2) is set if ( ($Net::SSLhello::usesni > 1) || ($ssl eq 'SSLv2') || ($ssl eq 'SSLv3') ) { # toggle SNI (2): test first without sni, old protocols: test solely without SNI $Net::SSLhello::usesni = 0; @accepted = Net::SSLhello::checkSSLciphers ($host, $port, $ssl, @testing); if ((OSaft::error_handler->get_err_type()) <= (OERR_SSLHELLO_RETRY_HOST)) { # severe error _trace ("**WARNING: checkAllCiphers (1.1): -> Abort '$host:$port' caused by ".OSaft::error_handler->get_err_str."\n"); carp ("**WARNING: checkAllCiphers (1.1): -> Abort '$host:$port'"); last; } _trace(" $ssl: tested ciphers: " . scalar(@testing) . ", accepted: " . (scalar(@accepted) - (scalar(@accepted) >= 2 && ($accepted[0] eq $accepted[1]) )) . "\n"); # delete 1 when the first 2 ciphers are identical (this indicates an Order by the Server) _v_print(" $ssl: tested ciphers: " . scalar(@testing) . ", accepted: " . (scalar(@accepted) - (scalar(@accepted) >= 2 && ($accepted[0] eq $accepted[1]) )) ); # delete 1 when the first 2 ciphers are identical (this indicates an Order by the Server) _trace("accepted ciphers: @accepted\n"); Net::SSLhello::printCipherStringArray ($cfg{'legacy'}, $host, $port, $ssl, 0, @accepted); $Net::SSLhello::usesni=$cfg{'usesni'}; # restore } next if ($ssl eq 'SSLv2');# SSLv2 has no SNI next if ($ssl eq 'SSLv3');# SSLv3 has originally no SNI # next if ($ssl eq 'DTLSv09');# DTLSv09 has originally no SNI(??) } @accepted = Net::SSLhello::checkSSLciphers ($host, $port, $ssl, @testing); if ((OSaft::error_handler->get_err_type()) <= (OERR_SSLHELLO_RETRY_HOST)) { # severe error _trace ("**WARNING: checkAllCiphers (1.2): -> Abort '$host:$port' caused by ".OSaft::error_handler->get_err_str."\n"); carp ("**WARNING: checkAllCiphers (1.2): -> Abort '$host:$port'"); last; } _trace(" $ssl: tested ciphers: " . scalar(@testing) . ", accepted: " . (scalar(@accepted) - (scalar(@accepted) >= 2 && ($accepted[0] eq $accepted[1]) )) . "\n"); # delete 1 when the first 2 ciphers are identical (this indicates an Order by the Server) _v_print(" $ssl: tested ciphers: " . scalar(@testing) . ", accepted: " . (scalar(@accepted) - (scalar(@accepted) >= 2 && ($accepted[0] eq $accepted[1]) )) ); # delete 1 when the first 2 ciphers are identical (this indicates an Order by the Server) _trace("accepted ciphers: @accepted\n"); Net::SSLhello::printCipherStringArray ($cfg{'legacy'}, $host, $port, $ssl, $Net::SSLhello::usesni, @accepted); } _trace("host}" . "\n"); } exit; O-Saft-19.01.19/contrib/000077500000000000000000000000001342117255600145135ustar00rootroot00000000000000O-Saft-19.01.19/contrib/.o-saft.tcl000077500000000000000000000225001342117255600164700ustar00rootroot00000000000000#!/usr/bin/tclsh #? #? NAME #? .o-saft.tcl - resource file for o-saft.tcl #? #? SYNOPSIS #? source .o-saft.tcl #? #? DESCRIPTION #? This is the user-configuration file for O-Saft's GUI o-saft.tcl . #? #? USAGE #? This file is in O-Saft's contrib directory and must be copied to the #? user's HOME directory or the local directory where o-saft.tcl will be #? started. #? #? SYNTAX #? Content of this file must be valid Tcl syntax. #? #? VERSION #? @(#) .o-saft.tcl 1.14 17/12/28 23:35:20 #? #? AUTHOR #? 04. April 2016 Achim Hoffmann #? # ----------------------------------------------------------------------------- set cfg(RCSID) {1.14}; # initial SID, do not remove package require Tcl 8.5 set cfg(TITLE) {O-Saft} #_____________________________________________________________________________ #_____________________________________________________ settings for colours __| array set cfg_color " DESC {-- CONFIGURATION colours used for buttons -------------------} closeme orange closetab orange closewin orange cmdstart yellow cmdcheck #ffd800 cmdcipher #ffd000 saveresult lightgreen saveconfig lightgreen reset lightblue filter lightblue DESC_other {-- CONFIGURATION colours used for other objects -------------} osaft gold button lightyellow code lightgray link blue status wheat "; #_____________________________________________________________________________ #_____________________________________________ texts for labels and buttons __| array set cfg_label " DESC {-- CONFIGURATION texts used in GUI for buttons --------------} about {!} help {?} closeme {Quit} closewin {Close} closetab {Close TAB} saveresult {Save} saveconfig {Save} reset {Reset} filter {Filter} tkcolor {Color Chooser} tkfont {Font Chooser} host_del {-} host_add {+} help_home {^} help_prev {<} help_next {>} helpsearch {>>} cmdstart {Start} cmdcheck {+check} cmdcipher {+cipher} cmdinfo {+info} cmdquick {+quick} cmdquit {+quit} cmdprotocols {+protocols} cmdvulns {+vulns} cmdversion {+version} DESC_other {-- CONFIGURATION texts used in GUI for labels ---------------} host {Host\[:Port\]} hideline {Hide complete line} c_toggle {toggle visibility\nof various texts} "; #_____________________________________________________________________________ #_______________________________________________________ texts for tooltips __| array set cfg_tipp " DESC {-- CONFIGURATION texts used for tool tips on buttons --------} help {Open window with complete help} closeme {Close program} closetab {Close this TAB} closewin {Close window} saveresult {Save result to file} saveconfig {Save configuration to file} showfilterconfig {Show configuration for filtering results} resetfilterconfig {Reset configuration to values from $cfg(INIT)} settings {Open window with more settings} host_del {Remove this line for a host} host_add {Add new line for a host} tkcolor {Open window to choose a color} tkfont {Open window to choose a font} help_home {Go to top of page (start next search from there)} help_prev {Search baskward for text} help_next {Search forward for text} helpsearch {Text to be searched} cmdstart {Execute $cfg(SAFT) with commands selected in 'Commands' tabs } cmdcheck {Execute $cfg(SAFT) +check} cmdcipher {Execute $cfg(SAFT) +cipher} DESC_other {-- CONFIGURATION texts used for tool tips on other objects --} choosen {Choosen value} hideline {Hide complete line instead of pattern only} show_hide {show/hide: } help_mode {Mode how pattern is used for searching} helpclick {Click to show in Help window} tabCMD { Select commands. All selected commands will be executed with the 'Start' button. } tabOPT { Select and configure options. All options are used for any command button. } tabFILTER { Configure filter for text markup: r, e and # specify how the Regex should work; Forground, Background, Font and u specify the markup to apply to matched text. Changes apply to next +command. } DESC_misc {-- CONFIGURATION texts used in GUI for various texts --------} f_key {Key} f_moder {r} f_modee {e} f_chars {#} f_regex {Regex} f_fg {Foreground} f_bg {Background} f_font {Font} f_u {u} DESC_opts {-- CONFIGURATION texts used in GUI for option checkbuttons --} --header {print header line} --enabled {print only enabled ciphers} --no-dns {do not make DNS lookups} --no-http {do not make HTTP requests} --no-sni {do not make connections in SNI mode} --no-sslv2 {do not check for SSLv2 ciphers} --no-tlsv13 {do not check for TLSv13 ciphers} "; # Note: Text for tab* contain new lines. #_____________________________________________________________________________ #_______________________________________________________ settings for sizes __| #----------------------------------------------------- window manager geometry # set minimal window sizes to be usable in a 1024x768 screen # windows will be larger if the screen supports it (we rely on "wm maxsize") set myX(geoO) "600x720-0+0"; # geometry and position of Help window set myX(geo-) ""; # (reserved for future use) #et myX(geoS) "700x720"; # geometry and position of O-Saft window set myX(geoA) "600x610"; # geometry and position of About window set myX(geoF) ""; # geometry and position of Filter window (computed dynamically) set myX(geoT) ""; # set myX(minx) 700; # O-Saft window min. width set myX(miny) 720; # O-Saft window min. height #---------------------------------------------------- some special GUI objects set myX(lenl) 15; # fixed width of labels in Options window set myX(rpad) 15; # right padding in the lower right corner set myX(padx) 5; # padding to right border #_____________________________________________________________________________ #____________________________________________________________ misc settings __| #----------------------------------------------------- where to find o-saft.pl # if o-saft.pl will not be found with the system's PATH environment # variable, a full path to o-saft.pl can be set here set prg(SAFT) {o-saft.pl}; # name of O-Saft executable #--------------------------------------------------- viewer to show o-saft.pod # o-saft.tcl uses built-in functionality to show its documentation. This # documentation is available in POD format also: o-saft.pod. # If this variable is set to the name of an external program, this program # will be used to show the documentation. It is recommended to use full a # path to the program. # Possible values, beside others, are: # O-Saft - reserved for o-saft.tcl's built-in vierwer # tkpod - Tcl/Tk-based viewer # podviewer - GTK-based viewer # Advantage of external viewers: # tkpod + much better search capabilities # Disadvantage of external viewers: # tkpod - context-sensitive help used by o-saft.tcl not possible # podviewer - context-sensitive help used by o-saft.tcl not possible # * - all viewers must be started in background and will not be # closed with o-saft.tcl itself set prg(TKPOD) {O-Saft}; # name of executable to view O-Saft's POD file #--------------------------------- list of buttons for "quick access commands" # for each O-Saft command in this list a button will be created in # the GUI # NOTE that this must be commands for o-saft.pl, which usually start # with + character set prg(Ocmd) {{+check} {+cipher} {+info} {+quick} {+protocols} {+vulns}}; #------------------------------- list of checkboxes for "quick access options" set prg(Oopt) {{--header} {--enabled} {--no-dns} {--no-http} {--no-sni} {--no-sslv2} {--no-tlsv13}}; #------------------------------------------------------ executable for browser # o-saft.tcl tries to find the browser automatically, it uses a list # of well known browser names for that. If another browser should be # used, it can be set here. # Must be a full path or found with PATH environment variable. # set prg(BROWSER) ""; #----------------------------------------- buttons style: simple text or image set cfg(bstyle) {image}; # button style: {image} or {text} set cfg(layout) {text}; # layout o-saft.pl's results: text or table #-------------------------------------------- set font for various tcl widgets # NOTE that setting other fonts may change the layout of the GUI, it # may be necessary to adapt some sizes (see myX) too. # option add *Button.font Bold; # option add *Label.font Bold; # option add *Text.font mono; #------------------------------------- when to show overview of search results set search(more) 5; # show overview when more than this search results O-Saft-19.01.19/contrib/Cert-beautify.awk000077500000000000000000000133121342117255600177250ustar00rootroot00000000000000#!/usr/bin/gawk -f #? #? NAME #? Cert-beautify.awk - formatting o-saft.pl's certificate data #? #? SYNOPSIS #? o-saft.pl +info ... | Cert-beautify.awk #? o-saft.pl +info ... | gawk -f Cert-beautify.awk #? o-saft.pl +info ... | Cert-beautify.awk -v all=1 #? #? OPTIONS #? -v all=1 - prints all line not matching certificate data from input #? default is to extract matching certificate data only #? #? DESCRIPTION #? Formats certificate related data for better human readability. #? #? VERSION #? @(#) Cert-beautify.awk 1.2 17/07/15 00:52:43 #? #? AUTHOR #? 07. July 2017 Achim Hoffmann #? # ----------------------------------------------------------------------------- function write(key,val) { sub(/^[ \t]*/, "", val); printf" %-22s%s\n", key, val; } BEGIN { FS = ":"; } /^\s*$/ { if (all==0) {next} } /^=/ { if (all==0) {next} } # line with --tracekey /^#\[subject\]/ { data["Subject"] = $3; next; } /^#\[issuer\]/ { data["Issuer"] = $3; next; } /^#\[before\]/ { dates["Valid from"] = $3; next; } /^#\[after\]/ { dates["Valid until"] = $3; next; } /^#\[serial\]/ { finger["Serial Number"] = $3; next; } /^#\[altname\]/ { finger["Subject Altnames"]= $3; next; } /^#\[signame\]/ { finger["Signature Algorithm"] = $3; next; } /^#\[fingerprint\]/ { finger["Fingerprint"] = $3; next; } /^#\[sigkey_len\]/ { finger["Signature Value"] = $3; next; } /^#\[modulus_len\]/ { finger["Public Key"] = $3; next; } /^#\[pubkey_algorithm\]/{ finger["Public Key Algorithm"] = $3; next; } /^#\[modulus_exponent\]/{ finger["Public Key Exponent"] = $3; next; } /^#\[verify\]/ { $1=""; $2=""; finger["Certificate Chain"] = $0; next; } # line without --tracekey /^Certificate Subject's Alternate:/ { finger["Subject Altnames"]= $2; next; } /^Certificate Subject:/ { data["Subject"] = $2; next; } /^Certificate Issuer:/ { data["Issuer"] = $2; next; } /^Certificate valid since:/ { dates["Valid from"] = $2; next; } /^Certificate valid until:/ { dates["Valid until"] = $2; next; } /^Certificate Serial Number:/ { finger["Serial Number"] = $2; next; } /^Certificate Signature Algorithm:/ { finger["Signature Algorithm"] = $2; next; } /^Certificate Fingerprint:/ { finger["Fingerprint"] = $2; next; } /^Certificate Signature Key Length:/ { finger["Signature Value"] = $2; next; } /^Certificate Public Key Length:/ { finger["Public Key"] = $2; next; } /^Certificate Public Key Algorithm:/ { finger["Public Key Algorithm"] = $2; next; } /^Certificate Public Key Exponent::/ { finger["Public Key Exponent"] = $2; next; } /^Validity Certificate Chain:/ { $1=""; dates["Certificate Chain"] = $0; next; } { if (all==1) {print} } END { split(data["Subject"], arr, "/"); #asort(arr); for (key in arr) { val = arr[key]; #printf" %-14s%s\n", key, val; if (val ~ /CN=/) { subjct["Common Name (CN)"] = substr(val, 4); } if (val ~ /O=/) { subjct["Organisation (O)"] = substr(val, 3); } if (val ~ /L=/) { subjct["Location (L)"] = substr(val, 3); } if (val ~ /ST=/) { subjct["State (ST)"] = substr(val, 4); } if (val ~ /C=/) { subjct["Country (C)"] = substr(val, 3); } } split(data["Issuer"], arr, "/"); for (key in arr) { val = arr[key]; #printf" %-14s%s\n", key, val; if (val ~ /CN=/) { issuer["Common Name (CN)"] = substr(val, 4); } if (val ~ /O=/) { issuer["Organisation (O)"] = substr(val, 3); } if (val ~ /L=/) { issuer["Location (L)"] = substr(val, 3); } if (val ~ /ST=/) { issuer["State (ST)"] = substr(val, 4); } if (val ~ /C=/) { issuer["Country (C)"] = substr(val, 3); } } print "\nIssued for (Subject)"; for (key in subjct) { write(key, subjct[key]); } print "\nIssued from (Issuer)"; for (key in issuer) { write(key, issuer[key]); } print "\nValidity"; for (key in dates) { write(key, dates[key]); } print "\nFingerprints and Signatures"; for (key in finger) { write(key, finger[key]); } print ""; } # __DATA__ # Example: # #[cn]: Certificate Common Name: demo #[subject]: Certificate Subject: /C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.de #[subject_hash]: Certificate Subject Name Hash: f6e9b9c5 #[issuer]: Certificate Issuer: /C=US/O=Google Inc/CN=Google Internet Authority G2 #[issuer_hash]: Certificate Issuer Name Hash: f6e9b9c5 #[serial]: Certificate Serial Number: 13434941386788252546 (0xba72800289b52b82) #[fingerprint]: Certificate Fingerprint: SHA1 Fingerprint=55D7A8009A0FB2B2467716A8F209FF7F6AA8C95B #[fingerprint_type]:Certificate Fingerprint Algorithm: SHA1 #[fingerprint_hash]:Certificate Fingerprint Hash Value: 55D7A8009A0FB2B2467716A8F209FF7F6AA8C95B #[fingerprint_sha2]:Certificate Fingerprint SHA2: 143EDA5B172589299D45126A054DEC858F5375B0D6490F7FB5F2D30A81571D3A #[fingerprint_sha1]:Certificate Fingerprint SHA1: 55D7A8009A0FB2B2467716A8F209FF7F6AA8C95B #[fingerprint_md5]: Certificate Fingerprint MD5: 3A879291D4616D8762EF0F847230DC2F #[before]: Certificate valid since: Feb 11 10:29:01 2016 GMT #[after]: Certificate valid until: Feb 16 10:29:01 2016 GMT #[signame]: Certificate Signature Algorithm: sha256WithRSAEncryption #[sigkey_len]: Certificate Signature Key Length: 2048 #[pubkey_algorithm]:Certificate Public Key Algorithm: rsaEncryption #[modulus_len]: Certificate Public Key Length: 2048 #[modulus_exponent]:Certificate Public Key Exponent: 65537 (0x10001) #[aux]: Certificate Trust Information: #[trustout]: Certificate trusted: #[altname]: Certificate Subject's Alternate Names: O-Saft-19.01.19/contrib/Cert-beautify.pl000077500000000000000000000063071342117255600175640ustar00rootroot00000000000000#!/usr/bin/perl -a -n -F: #? #? NAME #? Cert-beautify.pl - formatting o-saft.pl's certificate data #? #? SYNOPSIS #? o-saft.pl +info ... | Cert-beautify.pl #? o-saft.pl +info ... | perl Cert-beautify.pl #? o-saft.pl +info -tracekey ... | Cert-beautify.pl #? #? DESCRIPTION #? Formats certificate related data for better human readability. #? #? VERSION #? @(#) Cert-beautify.pl 1.1 17/08/05 16:29:07 #? #? AUTHOR #? 07. August 2017 Achim Hoffmann #? # ----------------------------------------------------------------------------- ## no critic qw(Variables::ProhibitPackageVars) # NOTE: need "our" here because of autosplit mode (see -a -n) use strict; use warnings; our %subject; our %issuer; our %finger; our %dates; my $c = "Certificate"; sub printline { my ($key, $val) = @_; $val =~ s/^\s*//; printf(" %-24s%s", $key, $val); return; } # printline sub printvalue { my $line = shift; # example: L=Mountain View return if ($line =~ m/^\s*$/); chomp $line; my $key = ""; my $val = $line; $val =~ s/^[^=]*=//; $key = "Common Name (CN)" if ($line =~ m/CN=/); $key = "Organisation (O)" if ($line =~ m/O=/); $key = "Location (L)" if ($line =~ m/L=/); $key = "State (ST)" if ($line =~ m/ST=/); $key = "Country (C)" if ($line =~ m/C=/); printline($key, "$val\n"); return; } # printvalue /^\s*$/ and next; /^=/ and next; # NOTE: some : at end of string to distinguish from other matching strings $subject{"Subject"} = $F[-1] if m/^(#\[subject\]|$c Subject:)/; $subject{"Issuer"} = $F[-1] if m/^(#\[issuer\]|$c Issuer:)/; $dates{"Valid from"} = $F[-1] if m/^(#\[before\]|$c valid since:)/; $dates{"Valid until"} = $F[-1] if m/^(#\[after\]|$c valid until:)/; $dates{"Certificate Chain"} = $F[-1] if m/^(#\[verify\]|Validity $c Chain:)/; $finger{"Serial Number"} = $F[-1] if m/^(#\[serial\]|$c Serial Number)/; $finger{"Subject Altnames"} = $F[-1] if m/^(#\[altname\]|$c Subject's Alternate)/; $finger{"Signature Algorithm"} = $F[-1] if m/^(#\[signame\]|$c Signature Algorithm)/; $finger{"Fingerprint"} = $F[-1] if m/^(#\[fingerprint\]|$c Fingerprint:)/; $finger{"Signature Value"} = $F[-1] if m/^(#\[sigkey_len\]|$c Signature key Length)/; $finger{"Public Key"} = $F[-1] if m/^(#\[modulus_len\]|$c Public Key Length)/; $finger{"Public Key Algorithm"} = $F[-1] if m/^(#\[pubkey_algorithm\]|$c Public Key Algorithm)/; $finger{"Public Key Exponent"} = $F[-1] if m/^(#\[modulus_exponent\]|$c Public Key Exponent)/; END { local $\ = "\n"; # FIXME: following split fails, is wrong if / is inside double quotes print "\nIssued for (Subject)"; # example: /C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.de foreach my $key (split(m(/), $subject{"Subject"})) { printvalue($key); } print "\nIssued from (Issuer)"; # example: /C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.de foreach my $key (split(m(/), $subject{"Issuer"})) { printvalue($key); } print "\nValidity"; foreach my $key (keys %dates) { printline($key, $dates{$key}); } print "\nFingerprint"; foreach my $key (sort keys %finger) { printline($key, $finger{$key}); } print "\nSignatures"; } # END O-Saft-19.01.19/contrib/Dockerfile.alpine-3.6000066400000000000000000000075421342117255600202700ustar00rootroot00000000000000#!/usr/bin/docker build --force-rm --rm -f FROM alpine:3.6 MAINTAINER Achim LABEL \ VERSION="17.06.17" \ \ DESCRIPTION="Build O-Saft docker image (with Peter Mosman's openssl)" \ SYNOPSIS="docker build --force-rm --rm -f ./Dockerfile -t owasp/o-saft:17.06.17 -t owasp/o-saft ." \ DETAILS="Please see https://github.com/OWASP/O-Saft/raw/master/o-saft-docker" \ SOURCE0="https://github.com/OWASP/O-Saft/raw/master/Dockerfile" \ SOURCE1="https://github.com/OWASP/O-Saft/raw/master/o-saft.tgz" \ SOURCE2="https://github.com/PeterMosmans/openssl/archive/1.0.2-chacha.tar.gz" \ SOURCE3="http://search.cpan.org/CPAN/authors/id/S/SU/SULLR/IO-Socket-SSL-2.049.tar.gz" \ SID="@(#) Dockerfile.alpine:3.6 1.1 17/07/25 23:01:19" \ AUTHOR="Achim Hoffmann" ENV o-saft-docker-build "Dockerfile 17.06.17" ENV OSAFT_DIR /O-Saft ENV OPENSSL_DIR /openssl ENV OPENSSL_VERSION 1.0.2-chacha ENV TERM xterm ENV PATH ${OSAFT_DIR}:${OSAFT_DIR}/contrib:${OPENSSL_DIR}/bin:$PATH # Install required packages RUN apk update && \ apk add --no-cache wget perl perl-net-dns perl-net-ssleay ncurses WORKDIR / # Install O-Saft RUN \ mkdir $OSAFT_DIR && \ adduser -D -h ${OSAFT_DIR} osaft && \ \ wget --no-check-certificate \ https://github.com/OWASP/O-Saft/raw/master/o-saft.tgz \ -O o-saft.tgz && \ echo "a55702d69314b8eda52e921e35b89aef9eef02b14c870b3077fbddf3af91320d o-saft.tgz" | sha256sum -c && \ \ tar -xzf o-saft.tgz && \ chown -R root:root $OSAFT_DIR && \ chown -R osaft:osaft $OSAFT_DIR/contrib && \ chown osaft:osaft $OSAFT_DIR/.o-saft.pl && \ mv $OSAFT_DIR/.o-saft.pl $OSAFT_DIR/.o-saft.pl-orig && \ sed -e "s:^#--openssl=.*:--openssl=$OPENSSL_DIR/bin/openssl:" \ < $OSAFT_DIR/.o-saft.pl-orig \ > $OSAFT_DIR/.o-saft.pl && \ chmod 666 $OSAFT_DIR/.o-saft.pl && \ rm -f o-saft.tgz # Pull and build IO::Socket::SSL (July/2017: missing in alpine's perl) RUN \ # pull and extract module mkdir /src_iosocket && \ wget --no-check-certificate \ http://search.cpan.org/CPAN/authors/id/S/SU/SULLR/IO-Socket-SSL-2.049.tar.gz \ -O iosocket.tgz && \ \ tar -xzf iosocket.tgz -C /src_iosocket --strip-components=1 && \ cd /src_iosocket && \ # build iosocket { # install development tools apk add --no-cache make && \ echo n | perl Makefile.PL && \ make && make test && make install && \ # cleanup apk del --purge make && \ # build iosocket } cd / && \ rm -r /src_iosocket iosocket.tgz # Pull and build enhanced openssl RUN \ # pull and extract module mkdir $OPENSSL_DIR /src_openssl && \ wget --no-check-certificate \ https://github.com/PeterMosmans/openssl/archive/1.0.2-chacha.tar.gz \ -O openssl.tgz && \ \ tar -xzf openssl.tgz -C /src_openssl --strip-components=1 && \ cd /src_openssl && \ # build openssl { # install development tools apk add --no-cache musl-dev gcc make zlib-dev && \ ./config --prefix=$OPENSSL_DIR --openssldir=$OPENSSL_DIR/ssl \ enable-zlib enable-ssl3 enable-rc5 enable-rc2 enable-GOST \ enable-cms enable-md2 enable-mdc2 enable-ec enable-ec2m \ enable-ecdh enable-ecdsa enable-seed enable-idea enable-camellia \ enable-rfc3779 enable-ec_nistp_64_gcc_128 \ -static experimental-jpake -DOPENSSL_USE_BUILD_DATE && \ make depend && make && make report && make install && \ # simple test echo -e "# number of ciphers $OPENSSL_DIR/bin/openssl: " && \ $OPENSSL_DIR/bin/openssl ciphers -V ALL:COMPLEMENTOFALL:aNULL|wc -l && \ # cleanup apk del --purge musl-dev gcc make zlib-dev && \ # build openssl } cd / && \ rm -r /src_openssl openssl.tgz # Install traditional openssl # RUN apk add --no-cache openssl # Install Tcl/Tk support # RUN apk add --no-cache tcl tk xvfb WORKDIR $OSAFT_DIR USER osaft #RUN o-saft-docker usage ENTRYPOINT ["perl", "/O-Saft/o-saft.pl"] CMD ["--help=docker"] # vim:set ft=dockerfile: O-Saft-19.01.19/contrib/Dockerfile.wolfssl000066400000000000000000000212731342117255600202020ustar00rootroot00000000000000#!/usr/bin/docker build --force-rm --rm -f #? USAGE #? This Dockerfile uses "buildargs" variables to build the Docker image. #? For default settings, please use: awk '/^ARG/{print $2}' Dockerfile #? #? OSAFT_VERSION #? Version of this build (should be used as image tag also). #? #? OSAFT_VM_FROM #? Base image to be used for this build. Tested images are: #? (2018) alpine:3.8 #? #? OSAFT_VM_SRC_WOLFSSL #? URL to fetch wolfssl.tgz archive. #? #? OSAFT_VM_SHA_WOLFSSL #? SHA256 checksum for the wolfssl archive. #? #? OSAFT_VM_TAR_WOLFSSL #? Name of archive file (during build). #? #? OSAFT_VM_DYN_WOLFSSL #? Build (link) mode of wolfssl executable: --enable-static or --enable-shared #? #? OSAFT_VM_HOSTNAME #? Hostname to be used for running container (/etc/hostname) #? #? ENVIRONMENT VARIABLES #? The build image sets environment variables. They are mainly used for #? documentation or by other programs to check for the right build. #? #? Following environment variables are set inside the docker image: #? #? osaft_vm_build #? Build version of this image. #? WOLFSSL_DIR #? Directory where wolfSSL is installed. #? WOLFSSL_VERSION #? Version of installed OpenSSL #? TERM #? Prefered X-Terminal program. #? LD_RUN_PATH #? Additional paths for runtime loader, used while linking with #? "ld -rpath=..." #? Linking of wolfssl, libssl.so and SSLeay.so will use -rpath #? in LDFLAGS to ensure that the special library will be used. #? Default:${WOLFSSL_DIR}/lib #? PATH #? PATH for shell, set to: #? $OSAFT_DIR:$OSAFT_DIR/contrib:$WOLFSSL_DIR/bin:$PATH #? WORK_DIR #? Directory where to build the packages (used for Dockerfile's #? WORKDIR dierective. #? #? EXAMPLES #? Simple build with defaults: alpine:3.8, wolfssl #? docker build --force-rm --rm \ #? -f Dockerfile.wolfssl -t o-saft/wolfssl . #? ARG OSAFT_VM_FROM=alpine:3.8 FROM $OSAFT_VM_FROM MAINTAINER Achim # Parameters passed to build # OSAFT_VM_FROM must be defined again, otherwise its value is not available ARG OSAFT_VM_FROM ARG OSAFT_VM_SRC_WOLFSSL="https://github.com/wolfSSL/wolfssl/archive/v3.15.3-stable.tar.gz" # -----BEGIN PGP SIGNATURE----- ARG OSAFT_VM_SHA_WOLFSSL="\ iQEcBAABCgAGBQJbLXUHAAoJEOvIDkFcopZ3NYMIAJMSsKQQxTHdiO4tjhofhgu2\ uH8QmY4XjyDqVEzID1GTmjS092bh/wNfQLRW5nMNMdS965XzA8gmSqo1bWIfFBG+\ eKZLc4xu+oIEDKfF7r5gkmPQNRVsHmOQK6BeOG0BnXBSdE9E0CIIlk81pZC7HSo7\ U6/I1hVlXyL9Y8ctfL2doDzil1jAvc0tQo/HNU4UikHtcbH2tsYSzjA1wXnjqeXQ\ WYy0TcJ0MbJrnpqX0li6JWc/6FSqM1hgCzrf/7kScdsu2zxMKxuxUvCCRJ1meYKt\ Vf2K6SlLFg5iqxqe+JRTvIiq2EDalsqClW9I1rbkphvYspZ9WI0Jf4YJUp4xPVk=\ =AlNB" # -----END PGP SIGNATURE----- ARG OSAFT_VM_TAR_WOLFSSL="wolfssl.tgz" ARG OSAFT_VM_DYN_WOLFSSL="--enable-static" # --enable-static not yet (2017) working 'cause of ARG OSAFT_VM_HOSTNAME ARG OSAFT_VERSION="18.10.12" LABEL \ VERSION="$OSAFT_VERSION" \ \ DESCRIPTION="Build docker image with wolfssl" \ SYNOPSIS="docker build --force-rm --rm -f ./Dockerfile.wolfssl -t o-saft/wolfssl:$OSAFT_VERSION -t o-saft/wolfssl ." \ SOURCE0="https://github.com/OWASP/O-Saft/raw/master/contrib/Dockerfile.wolfssl" \ SOURCE2="$OSAFT_VM_SRC_WOLFSSL" \ SID="@(#) Dockerfile.wolfssl 1.1 18/10/15 23:38:12" \ AUTHOR="Achim Hoffmann" ENV osaft_vm_build "Dockerfile $OSAFT_VERSION; FROM $OSAFT_VM_FROM" ENV WOLFSSL_DIR /wolfssl ENV WOLFSSL_VERSION v3.15.3 ENV TERM xterm ENV LD_RUN_PATH ${WOLFSSL_DIR}/lib ENV PATH ${WOLFSSL_DIR}/bin:$PATH ENV BUILD_DIR /tmp_src ENV WORK_DIR / WORKDIR $WORK_DIR # Install required packages, development tools and libs #RUN apk update && \ # no update neded and not wanted RUN apk add --no-cache wget ncurses linux-headers \ gcc make musl-dev zlib-dev m4 perl autoconf automake libtool file && \ # # Pull, build and install wolfssl apk add --no-cache lksctp-tools-dev && \ cd $WORK_DIR && \ mkdir -p $BUILD_DIR $WOLFSSL_DIR && \ wget --no-check-certificate $OSAFT_VM_SRC_WOLFSSL -O $OSAFT_VM_TAR_WOLFSSL && \ ### # check sha256 if there is one ### [ -n "$OSAFT_VM_SHA_WOLFSSL" ] && ### echo "$OSAFT_VM_SHA_WOLFSSL $OSAFT_VM_TAR_WOLFSSL" | sha256sum -c ; ### tar -xzf $OSAFT_VM_TAR_WOLFSSL -C $BUILD_DIR --strip-components=1 && \ cd $BUILD_DIR && \ # LDFLAGS="-Wl,-rpath=$LD_RUN_PATH" && export LDFLAGS && \ # see description for LD_RUN_PATH above ### --enable-fips fails with: ### make[1]: *** No rule to make target 'ctaocrypt/src/fips.c', needed by 'ctaocrypt/src/src_libwolfssl_la-fips.lo'. Stop. ### --enable-qsh requires special includes ### --enable-opensslcoexist fails with ### src/ssl.c: In function 'wolfSSL_BIO_new_file': ### src/ssl.c:30496:9: warning: implicit declaration of function 'wolfSSL_BIO_set_fp' [-Wimplicit-function-declaration] ### if (wolfSSL_BIO_set_fp(bio, fp, BIO_CLOSE) != WOLFSSL_SUCCESS) { ### ^~~~~~~~~~~~~~~~~~ ### missing in v3.15.3: --enable-tls13-draft28 --enable-aescbc --enable-sha2 ./autogen.sh && \ # config with all options, even if they are default # using --disable-option-checking in the hope for back- and forward-compatibility ./configure --prefix=$WOLFSSL_DIR $OSAFT_VM_DYN_WOLFSSL \ --disable-option-checking \ --enable-rng --with-libz \ --enable-sslv3 --enable-dtls \ --enable-tlsv10 --enable-tlsv12 --enable-tls13 --enable-oldtls \ --enable-tls13-draft18 --enable-tls13-draft22 --enable-tls13-draft23 \ --enable-tls13-draft26 --enable-tls13-draft28 \ --enable-aescbc --enable-aesccm --enable-aesgcm --enable-aesctr \ --enable-aescfb --enable-aesni \ --enable-md2 --enable-md4 --enable-md5 \ --enable-sha2 --enable-sha3 --enable-sha224 --enable-sha512 \ --enable-cmac --enable-dsa --enable-des3 --enable-dh \ --enable-ecccustcurves --enable-ecc --enable-eccshamir \ --enable-eccencrypt --enable-ed25519 --enable-curve25519 \ --enable-supportedcurves --enable-fpecc --enable-compkey \ --enable-hkdf --enable-arc4 --enable-psk --enable-sep \ --enable-blake2 --enable-ripemd --enable-camellia --enable-x963kdf \ --enable-rabbit --enable-hc128 --enable-anon --enable-nullcipher \ --enable-idea --enable-chacha --enable-poly1305 \ --enable-alpn --enable-sni --enable-crl --enable-truncatedhmac \ --enable-mcast --enable-sctp --enable-srp \ --enable-rsa --enable-rsapss --enable-xts \ --enable-coding --enable-base16 --enable-base64encode \ --enable-oldnames --enable-errorstrings --enable-enckeys \ --enable-ocsp --enable-ocspstapling --enable-ocspstapling2 \ --enable-tlsx --enable-session-ticket --enable-extended-master \ --enable-secure-renegotiation \ --enable-opensslall --enable-opensslextra \ --enable-lighty --enable-webclient --enable-earlydata \ && echo "# configure done." || cat ./config.log && \ make && make -i test && make install && \ # make test most likely fails, hence -i # manually install tools (without error checks) # NOTE: installs the binaries, not the wrapper scripts cp examples/echoclient/.libs/echoclient $WOLFSSL_DIR/bin/; \ cp examples/echoserver/.libs/echoserver $WOLFSSL_DIR/bin/; \ cp examples/client/.libs/client $WOLFSSL_DIR/bin/; \ cp examples/server/.libs/server $WOLFSSL_DIR/bin/; \ cp examples/sctp/.libs/sctp-client-dtls $WOLFSSL_DIR/bin/; \ cp examples/sctp/.libs/sctp-server-dtls $WOLFSSL_DIR/bin/; \ cp examples/sctp/sctp-client $WOLFSSL_DIR/bin/; \ mv certs/ $WOLFSSL_DIR/bin/; \ ln -s $WOLFSSL_DIR/bin/certs /certs ; \ # simple test echo -n "# number of ciphers $WOLFSSL_DIR/bin/client: " && \ $WOLFSSL_DIR/bin/client -e|tr ':' '\012'|wc -l && \ $WOLFSSL_DIR/bin/client -e && \ # cleanup apk del --purge lksctp-tools-dev && \ cd $WORK_DIR && \ echo rm -rf $BUILD_DIR $OSAFT_VM_TAR_WOLFSSL && \ # Cleanup apk del --purge gcc make m4 autoconf automake musl-dev linux-headers \ perl-dev readline bash libltdl libtool file && \ # installed by libtool: readline bash libltdl libtool # do not delete krb5-dev zlib-dev because we need # libkrb5.so.3, libk5crypto.so.3 and libz.so to run openssl [ -n "$OSAFT_VM_HOSTNAME" ] && \ echo "$OSAFT_VM_HOSTNAME" > /etc/hostname ; WORKDIR $WOLFSSL_DIR ### USER wolfssl ### RUN ?? ENTRYPOINT ["/wolfssl/bin"] EXPOSE 443/tcp # vim:set ft=dockerfile: O-Saft-19.01.19/contrib/HTML-simple.awk000077500000000000000000000015361342117255600172620ustar00rootroot00000000000000#!/usr/bin/gawk -f #? #? NAME #? HTML-simple.awk - formatting o-saft.pl's output as simple HTML table #? #? SYNOPSIS #? o-saft.pl ... | HTML-simple.awk #? o-saft.pl ... | gawk -f HTML-simple.awk #? #? DESCRIPTION #? Formats all output as HTML with label and value in table lines. #? Common Nameexample.tld #? #? VERSION #? @(#) HTML-simple.awk 1.2 16/09/25 09:39:49 #? #? AUTHOR #? 06. June 2016 Achim Hoffmann #? # ----------------------------------------------------------------------------- BEGIN { FS="\t"; print ""; } (NF>0){ gsub(/&/,"\\&"); gsub(/"/,"\\""); gsub(//,"\\>"); } /^\s*$/{ next; } ($1~/^[#=]/) {print "";next} { printf(" \n", $1, $2); } END { print "
%s%s
" } O-Saft-19.01.19/contrib/HTML-table.awk000077500000000000000000000047531342117255600170640ustar00rootroot00000000000000#!/usr/bin/gawk -f #? #? NAME #? HTML-table.awk - formatting o-saft.pl's output as HTML with table #? #? SYNOPSIS #? o-saft.pl ... | HTML-table.awk #? o-saft.pl ... | gawk -f HTML-table.awk #? #? DESCRIPTION #? Formats all output as HTML with label and value in table lines. #? One table for each section in output and colours for some values. #? Common Nameexample.tld #? #? VERSION #? @(#) HTML-table.awk 1.2 16/09/25 09:37:03 #? #? AUTHOR #? 06. June 2016 Achim Hoffmann #? # ----------------------------------------------------------------------------- BEGIN { FS="\t"; print ""; print ""; } (NF>0){ gsub(/&/,"\\&"); gsub(/"/,"\\""); gsub(//,"\\>"); } /^\s*$/{ next; } ($1~/ reading/) { next; } ($1~/^**ERROR/) { $0 = sprintf("%s", $0); } ($1~/^**WARN/) { $0 = sprintf("%s", $0); } ($1~/^**HINT/) { $0 = sprintf("%s", $0); } ($1~/^!!Hint/) { $0 = sprintf("%s", $0); } ($3~/[Hh][Ii][Gg][Hh]/) { $3 = sprintf("%s", $3); } ($3~/[Mm][Ee][Dd][Ii]/) { $3 = sprintf("%s", $3); } ($3~/[Ll][Oo][Ww]/) { $3 = sprintf("%s", $3); } ($3~/[Ww][Ee][Aa][Kk]/) { $3 = sprintf("%s", $3); } ($NF == "yes") { $NF = sprintf("%s", $NF); } ($NF ~ /^no/) { $NF = sprintf("%s", $NF); } ($1~/^===/ && $NF~/===/) { gsub(/===/,""); printf("

%s

\n", $0); next; } ($1~/^== /) { printf("\n", $0); next; } ($1~/^[#=]/) { print ""; next; } (NF == 2) { printf(" \n", $1, $2); next; } (NF == 3) { printf(" \n", $1, $2, $3); next; } { print; } END { print "
%s
%s%s
%s%s%s
"; } O-Saft-19.01.19/contrib/INSTALL-template.sh000077500000000000000000000274271342117255600200050ustar00rootroot00000000000000#! /bin/sh #? #? File INSERTED_BY_MAKE #? #? NAME #? $0 - install script for O-Saft #? #? SYNOPSIS #? $0 [options] [installation directory] #? #? DESCRIPTION #? Some people want to have an installation script, in particular named #? INSTALL.sh, even O-Saft should work without a specific installation. #? Here we go. #? #? This script does nothing except printing some messages unless called #? with an argument. The arguments are: #? #? /absolute/path #? - copy all necessary files into specified directory #? --install - copy all necessary files into default directory #? --check - check current installation #? --clean - move files not necessary to run O-Saft into subdir #? ./release_information_only # This is the behaviour of the old INSTALL-devel.sh script. #? --openssl - same as calling contrib/install_openssl.sh #? (build and install openssl and Net::SSLeay) #? #? OPTIONS #? --h got it #? --n do not execute, just show #? --blind use blue instead of green coloured texts #? --force install .o-saft.pl and .o-saft.tcl in $HOME, overwrites #? existing ones #? #? EXAMPLES #? $0 #? $0 --clean #? $0 --check #? $0 --install #? $0 /opt/bin/ #? $0 /opt/bin/ --force #? # HACKER's INFO # This file is generated from INSTALL-template.sh . # The generator (make) inserts some values for internal variables. In # particular the list of source files to be installed. See the strings # INSERTED_BY_MAKE . # TODO: --check does not work if installed in other dir than default one # # Environment variable inst can be set to installation directory: This # is usefull for development only, hence not officially documented. # #? DEPENDENCIES #? Following tools are required for proper functionality: #? awk, cat, perl, tr #? VERSION #? @(#) INSTALL-template.sh 1.14 18/11/04 15:45:10 #? #? AUTHOR #? 16-sep-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- # --------------------------------------------- internal variables; defaults try='' ich=${0##*/} bas=${ich%%.*} dir=${0%/*} [ "$dir" = "$0" ] && dir="." # $0 found via $PATH in . colour="32m" # 32 green, 34 blue for colour-blind clean=./release_information_only force=0 optn="" mode=""; # "", check, clean, dest inst=${inst:="INSTALLDIR_INSERTED_BY_MAKE"} text_miss="missing, try installing with "; # 'cpan $m'" text_dev="did you run »$0 --clean«?" text_alt="file from previous installation, try running »$0 --clean« " text_old="ancient module found, try installing newer version, at least " osaft_exe="o-saft.pl" osaft_gui="o-saft.tcl" # corresponding RC-files do not need their own variable; simply prefix with . inst_openssl="contrib/install_openssl.sh" # INSERTED_BY_MAKE { files_contrib=" CONTRIB_INSERTED_BY_MAKE " files_install=" OSAFT_INSERTED_BY_MAKE " # INSERTED_BY_MAKE } files_not_installed=" o-saft.cgi contrb/o-saft.php contrib/install_openssl.sh contrib/install_perl_modules.pl " files_ancient="generate_ciphers_hash openssl_h-to-perl_hash o-saft-README INSTALL-devel.sh .perlcriticrc o-saft_bench " files_develop="o-saft-docker-dev Dockerfile Makefile Makefile.help t/" files_info="CHANGES README o-saft.tgz" # --------------------------------------------- internal functions echo_yellow () { echo "\033[1;33m$@\033[0m" } echo_green () { echo "\033[1;$colour$@\033[0m" } echo_red () { echo "\033[1;31m$@\033[0m" } # --------------------------------------------- arguments and options while [ $# -gt 0 ]; do case "$1" in '-h' | '--h' | '--help') \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 exit 0 ;; '-n' | '--n') optn="--n"; try=echo; ;; '--check') mode=check; ;; '--clean') mode=clean; ;; '--install') mode=dest; ;; # install in hardcoded path '--openssl') mode=openssl; ;; '--force') force=1; ;; '--blind') colour="34m"; ;; '--color-blind') colour="34m"; ;; '--colour-blind') colour="34m"; ;; '--version') \sed -ne '/^#? VERSION/{' -e n -e 's/#?//' -e p -e '}' $0 exit 0 ;; '+VERSION') echo 1.14 ; exit; ;; # for compatibility to $osaft_exe *) mode=dest; inst="$1"; ;; # last one wins esac shift done # --------------------------------------------- main # ------------------------- default mode --------- { if [ -z "$mode" ]; then echo "" cat << EoT # O-Saft does not need a specific installation. It may be used from this # directory right away. # # If you want to run O-Saft from this directory, then consider calling: $0 --clean # If you want to install O-Saft in a different directory, then please call: $0 /path/to/installation/directoy $0 /path/to/installation/directoy --force # To check if O-Saft will work, you may use: $0 --check # In a Docker image, this script may only be called like: $0 --check EoT exit 0 fi; # default mode } if [ "$mode" != "check" ]; then if [ -n "$osaft_vm_build" ]; then echo "**ERROR: found 'osaft_vm_build=$osaft_vm_build'" echo_red "**ERROR: inside docker only --check possible; exit" exit 6 fi fi # ------------------------- openssl mode --------- { if [ "$mode" = "openssl" ]; then [ ! -x "$inst_openssl" ] && echo_red "**ERROR: $inst_openssl does not exist; exit" && exit 2 $inst_openssl $optn status=$? if [ $status -ne 0 ]; then cat << EoT # $inst_openssl uses its default settings. To check the settings, use: # $0 --openssl --n # If other configurations should be used, please use directly: # $inst_openssl --help # $inst_openssl --n # $inst_openssl /path/to/install EoT fi exit $status fi; # openssl mode } # ------------------------- clean mode ----------- { if [ "$mode" = "clean" ]; then # do not move contrib/ as all examples expect contrib/ right here for f in $files_info $files_ancient $files_develop ; do [ -e "$clean/$f" ] && $try \rm -f "$clean/$f" $try \mv "$f" "$clean" done exit 0 fi; # clean mode } # ------------------------- install mode -------- { if [ "$mode" = "dest" ]; then if [ ! -d "$inst" ]; then echo_red "**ERROR: $inst does not exist; exit" [ "$try" = "echo" ] || exit 2 fi echo "# remove old files ..." # TODO: argh, hard-coded list of files ... for f in $files_install ; do f="$inst/$f" if [ -e "$f" ]; then $try \rm -f "$f" || exit 3 fi done echo "# installing ..." $try \mkdir -p "$inst/Net" $try \mkdir -p "$inst/OSaft/Doc" for f in $files_install ; do $try \cp "$f" "$inst/$f" || exit 4 done if [ $force -eq 1 ]; then $try \cp .$osaft_exe "$inst/" || echo_red ".$osaft_exe failed" $try \cp contrib/.$osaft_gui "$inst/" || echo_red ".$osaft_gui failed" fi echo -n "# installation in $inst "; echo_green "completed." exit 0 fi; # install mode } # ------------------------- check mode ----------- { if [ "$mode" != "check" ]; then echo_red "**ERROR: unknow mode $mode; exit" exit 5 fi # all following is check mode err=0 echo "" echo "# check installation" echo "# (warnings are ok if 'git clone' will be used for development)" echo "#--------------------------------------------------------------" # err=`expr $err + 1` ; # errors not counted here files="openssl_h-to-perl_hash generate_ciphers_hash o-saft-README" for f in $files ; do [ -e "$f" ] && echo -n "# found $f ...\t" && echo_yellow "$text_alt" done files="$files_develop $files_info " for f in $files ; do [ -e "$f" ] && echo -n "# found $f ...\t" && echo_yellow "$text_dev" done echo "#--------------------------------------------------------------" echo "" echo "# check for installed O-Saft" echo "#--------------------------------------------------------------" for o in $osaft_exe $osaft_gui ; do for p in `echo $PATH|tr ':' ' '` ; do d="$p/$o" if [ -e "$d" ]; then v=`$p/$o +VERSION` echo -n "# version $v:\t" && echo_green "$d" fi done done echo "#--------------------------------------------------------------" echo "" echo "# check for installed O-Saft resource files" echo "#--------------------------------------------------------------" # currently no version check for p in `echo $HOME $PATH|tr ':' ' '` ; do rc="$p/.$osaft_exe" if [ -e "$rc" ]; then echo -n "# $rc\t" && echo_yellow "will be used when started in $p only" fi done rc="$HOME/.$osaft_gui" if [ -e "$rc" ]; then v=`awk '/RCSID/{print $3}' $rc | tr -d '{};'` echo -n "# found $rc\t" && echo_green "$v" echo -n "# exist $rc\t" && echo_yellow "consider updating from contrib/.$osaft_gui" else echo -n "# miss. $rc\t" && echo_yellow "consider copying contrib/.$osaft_gui into your HOME directory: $HOME" fi echo "#--------------------------------------------------------------" echo "" echo "# check for installed perl modules" echo "#--------------------------------------------------------------" modules="Net::DNS Net::SSLeay IO::Socket::SSL Net::SSLinfo Net::SSLhello osaft OSaft::error_handler OSaft::Doc::Data" for m in $modules ; do echo -n "# testing for $m ...\t" v=`perl -M$m -le 'printf"\t%s",$'$m'::VERSION' 2>/dev/null` if [ -n "$v" ]; then case "$m" in 'IO::Socket::SSL') expect=1.90; ;; # 1.37 and newer work, somehow ... 'Net::SSLeay') expect=1.49; ;; # 1.33 and newer may work 'Net::DNS') expect=0.80; ;; esac case "$m" in 'Net::SSLinfo' | 'Net::SSLhello') c="green"; ;; 'OSaft::error_handler' | 'osaft') c="green"; ;; 'OSaft::Ciphers' ) c="green"; ;; 'OSaft::Doc::Data' ) c="green"; ;; *) c=`perl -le "print (($expect > $v) ? 'red' : 'green')"`; ;; esac [ "$c" = "green" ] && echo_green "$v" [ "$c" = "red" ] && echo_red "$v , $text_old $expect" [ "$c" = "red" ] && err=`expr $err + 1` [ "$c" = "red" ] && echo E $err else text_miss="$text_miss 'cpan $m'" echo_red "$text_miss" err=`expr $err + 1` echo e $err fi done exit echo "#--------------------------------------------------------------" echo "" echo "# check for important perl modules used by O-Saft" echo "#--------------------------------------------------------------" modules="Net::DNS Net::SSLeay IO::Socket::SSL" for p in `echo $PATH|tr ':' ' '` ; do o="$p/$osaft_exe" [ -e "$o" ] || continue echo "# testing $o ...\t" for m in $modules ; do v=`$o --no-warn +version | awk '($1=="'$m'"){print}'` echo_green "$v" done done echo "#--------------------------------------------------------------" echo "" echo "# check openssl executable in PATH" echo "#--------------------------------------------------------------" echo -n "# openssl:\t\t" && echo_green "`which openssl`" echo -n "# openssl version:\t" && echo_green "`openssl version`" # TODO: openssl older than 0x01000000 has no SNI echo "#--------------------------------------------------------------" echo "" echo "# check for openssl executable used by O-Saft" echo "#--------------------------------------------------------------" for p in `echo $PATH|tr ':' ' '` ; do o="$p/$osaft_exe" r="$p/.$osaft_exe" if [ -x "$o" ]; then ( cd $p openssl=`$o --no-warn +version | awk '/external executable/{print $NF}' | tr '\012' ' '` echo -n "# $o:\t" && echo_green "$openssl" ) fi done echo "#--------------------------------------------------------------" echo "" echo "# check for contributed files" echo "# (in $inst )" echo "#--------------------------------------------------------------" for c in $files_contrib ; do c="$inst/$c" if [ -e "$c" ]; then echo -n "# found\t" && echo_green "$c" else echo -n "# not found\t" && echo_red "$c" err=`expr $err + 1` fi done echo "#--------------------------------------------------------------" echo "" echo -n "# checks\t" if [ $err -eq 0 ]; then echo_green "passed" else echo_red "failed , $err error(s) detected" fi # check mode } exit $err O-Saft-19.01.19/contrib/JSON-array.awk000077500000000000000000000047621342117255600171200ustar00rootroot00000000000000#!/usr/bin/gawk -f #? #? NAME #? JSON-array.awk - formatting o-saft.pl's output as JSON array #? #? SYNOPSIS #? o-saft.pl --tracekey --tab ... | JSON-array.awk #? o-saft.pl --tracekey --tab ... | gawk -f JSON-array.awk #? #? DESCRIPTION #? Input format must be: key\tlabel\tvalue #? #? Formats all output as JSON array. Each array element consists of: #? typ, line, key, label, value #? #? VERSION #? @(#) JSON-array.awk 1.1 17/06/26 11:47:42 #? #? AUTHOR #? 23. June 2017 Achim Hoffmann #? # ----------------------------------------------------------------------------- BEGIN { FS="\t"; e=0; w=0; h=0; c=0; d=0; i=0; print "["; } function trim(val) { gsub(/^ */, "", val); gsub(/ *$/, "", val); return val; } function line(key,val,sep) { printf("\"%s\":\"%s\"%s", trim(key), trim(val), sep); } function stat(key,val) { printf(" {"); line("typ","stat", ","); line("key", key, ","); line("value", val, ""); print "},"; } (NF>0) { gsub(/"/,"\\\";"); } # escape " /^#\[/ { sub(/^#\[/,""); sub(/\]/,"");} # pretty-print key: #[key] --> key /^\s*$/ { s++; next; } # empty lines /^=/ { s++; next; } # header lines ($1~/ reading/) { s++; next; } # other lines { # must be first check if ($NF ~ /^no/ || $NF == "yes") { d++; typ = "check"; } else { i++; typ = "info"; if ($0 ~ /^cnt_/ || $0 ~ /^len_/) { typ = "check"; } } } ($1~/^**ERROR/) { e++; typ = "error"; $0 = sprintf("%s\t%s\t%s", e, FNR, $0); } ($1~/^**WARN/) { w++; typ = "warning"; $0 = sprintf("%s\t%s\t%s", w, FNR, $0); } ($1~/^**HINT/) { h++; typ = "hint"; $0 = sprintf("%s\t%s\t%s", h, FNR, $0); } ($1~/^!!Hint/) { h++; typ = "hint"; $0 = sprintf("%s\t%s\t%s", h, FNR, $0); } ($NF~/[Hh][Ii][Gg][Hh]/) { c++; typ = "cipher"; } ($NF~/[Mm][Ee][Dd][Ii]/) { c++; typ = "cipher"; } ($NF~/[Ll][Oo][Ww]/) { c++; typ = "cipher"; } ($NF~/[Ww][Ee][Aa][Kk]/) { c++; typ = "cipher"; } { #dbx# print " // ", $0; delete arr; split($0, arr, /\t/); printf(" {"); line("typ", typ, ","); line("line", FNR, ","); line("key", arr[1], ","); line("label", arr[2], ","); # ciphers support is listed as yes/no, the cipher column gets this value if (typ == "cipher") { line("supported", arr[3], ","); } line("value", arr[length(arr)], ""); print "},"; next; } END { stat("error", e); stat("warning", w); stat("cipher", c); stat("check", d); stat("info", i); stat("skip", s); print "];"; } O-Saft-19.01.19/contrib/JSON-struct.awk000077500000000000000000000062231342117255600173200ustar00rootroot00000000000000#!/usr/bin/gawk -f #? #? NAME #? JSON-struct.awk - formatting o-saft.pl's output as JSON data #? #? SYNOPSIS #? o-saft.pl --tracekey --tab ... | JSON-struct.awk #? o-saft.pl --tracekey --tab ... | gawk -f JSON-table.awk #? #? DESCRIPTION #? Input format must be: key\tlabel\tvalue #? #? Formats all output as JSON array. The array contains following lists: #? *WARN, !!Hint, cipher, info, check #? Each list contains following elements: #? typ, cnt, array-of-items #? Each item contains: #? key, label, value #? #? VERSION #? @(#) JSON-struct.awk 1.1 17/06/26 11:47:42 #? #? AUTHOR #? 23. June 2017 Achim Hoffmann #? # ----------------------------------------------------------------------------- BEGIN { err[0] = ""; warn[0] = ""; hint[0] = ""; cipher[0] = 0; check[0] = ""; info[0] = ""; FS="\t"; print "["; } function trim(val) { gsub(/^ */, "", val); gsub(/ *$/, "", val); return val; } function line(key,val,sep) { printf("\t\t\"%s\"\t: \"%s\"%s\n", trim(key), trim(val), sep); } function data(val) { #dbx##dbx# print "\t // ", val, delete arr; split(val, arr, /\t/); print "\t {"; line("key", arr[1], ","); line("label", arr[2], ","); line("value", arr[length(arr)]); print "\t },"; } function anf (key,cnt) { printf(" {\n\ttyp\t: \"%s\",\n\tcnt\t: \"%s\",\n\t{\n", key, cnt); } function end () { print "\t}\n },"; } (NF>0) { gsub(/"/,"\\\";"); } # escape " /^#\[/ { sub(/^#\[/,""); sub(/\]/,"");} # pretty-print key: #[key] --> key /^\s*$/ { next; } # empty lines /^=/ { next; } # header lines ($1~/ reading/) { next; } # other lines ($1~/^**ERROR/) { err[e++] = $0; prev_typ = "e"; next; } ($1~/^**WARN/) { warn[w++] = $0; prev_typ = "w"; next; } ($1~/^**HINT/) { hint[h++] = $0; prev_typ = "h"; next; } #($1~/^!!Hint/) { hint[h++] = $0; prev_typ = "h"; next; } ($NF~/[Hh][Ii][Gg][Hh]/) { cipher[cg++] = $0; prev_typ = "c"; next; } ($NF~/[Mm][Ee][Dd][Ii]/) { cipher[cm++] = $0; prev_typ = "c"; next; } ($NF~/[Ll][Oo][Ww]/) { cipher[cl++] = $0; prev_typ = "c"; next; } ($NF~/[Ww][Ee][Aa][Kk]/) { cipher[cw++] = $0; prev_typ = "c"; next; } ($1~/^!!Hint/) { switch (prev_typ) { case "e": top = length(err); case "w": top = length(warn); case "c": top = length(cipher); case "d": top = length(check); case "i": top = length(info); } hint[prev_typ,top,h++] = $0; next; } { if ($NF ~ /^no/ || $NF == "yes") { check[c++] = $0; prev_typ = "d"; } else { if ($0 ~ /^cnt_/ || $0 ~ /^len_/) { check[c++] = $0; prev_typ = "d"; } else { info[i++] = $0; prev_typ = "i"; } } } END { i = 1; anf("**WARN", length(warn)); for (l in warn) { line(i++, warn[l], ","); } end(); i = 1; anf("!!Hint", length(hint)); for (l in hint) { line(i++, hint[l], ","); } end(); anf("cipher", length(cipher)); for (l in cipher) { data(cipher[l]); } end(); anf("info", length(info)); for (l in info) { data(info[l]); } end(); anf("check", length(check)); for (l in check) { data(check[l]); } end(); print "]"; } O-Saft-19.01.19/contrib/XML-attribute.awk000077500000000000000000000017261342117255600176710ustar00rootroot00000000000000#!/usr/bin/gawk -f #? #? NAME #? XML-attribute.awk - formatting o-saft.pl's output as XML with attributes #? #? SYNOPSIS #? o-saft.pl ... | XML-attribute.awk #? o-saft.pl ... | gawk -f XML-attribute.awk #? #? DESCRIPTION #? Formats all output as XML with label and value as tag attributes: #? #? #? VERSION #? @(#) XML-attribute.awk 1.2 16/09/25 13:42:31 #? #? AUTHOR #? 06. June 2016 Achim Hoffmann #? # ----------------------------------------------------------------------------- BEGIN { FS="\t"; print "" } (NF>0) { gsub(/&/,"\\&"); gsub(/"/,"\\""); gsub(//,"\\>"); } /^\s*$/{ next; } ($1~/^[#=]/) {print "";next} { i++; printf(" \n",i,$1,$2); } END { print "" } O-Saft-19.01.19/contrib/XML-value.awk000077500000000000000000000016611342117255600170000ustar00rootroot00000000000000#!/usr/bin/gawk -f #? #? NAME #? XML-value.awk - formatting o-saft.pl's output as XML with values #? #? SYNOPSIS #? o-saft.pl ... | XML-value.awk #? o-saft.pl ... | gawk -f XML-value.awk #? #? DESCRIPTION #? Formats all output as XML with label and value as tag values: #? *exacmle.tld #? #? VERSION #? @(#) XML-value.awk 1.2 16/09/25 13:40:43 #? #? AUTHOR #? 06. June 2016 Achim Hoffmann #? # ----------------------------------------------------------------------------- BEGIN { FS="\t"; print "" } (NF>0) { gsub(/&/,"\\&"); gsub(//,"\\>"); } /^\s*$/{ next; } ($1~/^[#=]/) { print ""; next; } { printf(" %s\n", $1, $2); } END { print ""; } O-Saft-19.01.19/contrib/bash_completion_o-saft000077500000000000000000000023121342117255600210560ustar00rootroot00000000000000#?/bin/bash #? NAME #? bash_completion_o-saft - bash completion function for o-saft.pl #? #? DESCRIPTION #? This bash function provides values to be used in bash's completion #? (see bash's [TAB][TAB] key). #? #? USAGE #? source bash_completion_o-saft #? complete -F _o-saft o-saft.pl #? #? SEE ALSO #? bind -p | grep complete #? http://www.gnu.org/software/bash/manual/bash.html#Programmable-Completion #? #? AUTHOR #? 14-dec-14 Achim Hoffmann # ------------------------------------------------------------------------------ # bash is not my favorite, I guess this could be improved in many ways :-) _y_cmds=`o-saft.pl --help=commands|awk '/^\+/{print $1}'` _y_opts=`o-saft.pl --help=opts |awk '/^\-/{print $1}'` _y_rang=`o-saft.pl --help=range |awk "/ *'/"'{print "--cipherrange="$1}'` _o-saft() { local curr_arg; curr_arg=${COMP_WORDS[COMP_CWORD]} case "$curr_arg" in +*) COMPREPLY=( $(compgen -W "$_y_cmds" -- $curr_arg ) ); ;; --cipherrange*) COMPREPLY=( $(compgen -W "$_y_rang" -- $curr_arg ) ); ;; -*) COMPREPLY=( $(compgen -W "$_y_opts" -- $curr_arg ) ); ;; esac } complete -F _o-saft o-saft complete -F _o-saft o-saft.pl O-Saft-19.01.19/contrib/bunt.pl000077500000000000000000000273551342117255600160370ustar00rootroot00000000000000#!/usr/bin/perl #? #? NAME #? $0 - postprocess to colourize output of o-saft.pl #? #? SYNOPSIS #? o-saft.pl | $0 [OPTIONS] #? #? DESCRIPTION #? That's it. #? #? OPTIONS #? --h got it #? --test simple self-testing #? --line colourize complete line #? --word colourize special words #? --blind use blue instead of green #? --purple use purple instead of yellow #? purple may be better readable on light backgrounds #? --italic colourize special words and additionally print "label texts:" #? with italic characters #? "label text:" is all text left of first : including : #? --NUM if a number, change assumed terminal width to NUM #? (used for padding text on the right); default: terminal width #? #? LIMITATIONS # # HACKER's INFO # Feel free to write your own code. You just need to add/modify the code # following "main" below. # # How it workd, see function testme below calling with $0 --test #? #? VERSION #? @(#) bunt.pl 1.10 17/06/25 20:33:25 #? #? AUTHOR #? 08-jan-16 Achim Hoffmann _at_ sicsec .dot. de #? # ----------------------------------------------------------------------------- use strict; use warnings; use charnames qw( :full ); our ($VERSION) = -1; # dummy assignment to keep `perlcritic -s ...' silent ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers) my $ich = $0; $ich =~ s#.*[/\\]##; sub _warn(@) { my @args = @_; print STDERR "[$ich]: **", @args, "\n"; return; } if (defined $ENV{TERM}) { _warn("WARNING: 'TERM=screen'; take care ...") if ($ENV{TERM} eq 'screen'); } # else # not a terminal, switch off terminal capabilities # checks are done with: (defined $ENV{TERM}) # probably better exit here # --------------------------------------------- internal variables; defaults my $mode = 'word'; # default: colourize words my $italic = 0; # default: nothing italic my $_LEN = 80; # default: 80 characters per line; -1 for unsupported terminals # set to termial width below my $cols = $_LEN; # check terminal width if (defined $ENV{ComSpec}) { # supported systems do not have it, usually .. # Note that cmd.exe and command.exe do not support colours, at least # not per word or line. There exists some alternates like ansicmd.exe # or cecho.exe, which are not supported herein (not tested if loaded # modules support them). If any of these alternates mudt be supported, # feel free to hack the code below. Meanwhile, colourizing for these # dumb terminals is simply disabled. # Hint to get the number of columns in cmd.exe: # $c= qx(mode); # $c=~s/.*CON:[\n\r]+(?:[^\n\r]*[\n\r]+){2}[^:]*:\s*([\d]+).*/$1/ms; if (!defined $ENV{TERM}) { # cygwin has both environment variables, no warning there _warn("WARNING: unsupported terminal '$ENV{ComSpec}'; printing text as is"); } $_LEN = -1; } else { if ($^O !~ m/MSWin32/) { $cols = qx(\\tput cols); # quick&dirty } else { my $rows; $cols = $ENV{COLUMNS}; if (eval { require Win32::Console; }) { ($cols, $rows) = Win32::Console::Size(); } else { if (eval {require Term::Size;}) { ## no critic qw(TestingAndDebugging::ProhibitNoStrict) # NOTE: we need "no strict" here to avoid perl warning: # Bareword "Term::Size::chars" not allowed ... # Term::Size::chars is only called when the module was successfully loaded. no strict 'subs'; ## use critic ($cols, $rows) = Term::Size::chars *STDOUT{IO}; #($x, $y) = Term::Size::pixels; } # else ... gave up; feel free to try harder on dumb system } if (! defined $cols) { _warn("WARNING: cannot find terminal width, using default '$_LEN'"); _warn("HINT: consider setting 'COLUMNS' environment variable"); $cols = $_LEN; } } } chomp $cols; if (defined $ENV{COLUMNS}) { _warn("WARNING: terminal width '$ENV{COLUMNS}' mismatch, using '$cols'") if ($ENV{COLUMNS} ne $cols); $_LEN = $cols; } $_LEN = $cols; my %map = ( # colours # escape sequence to be used #----------+---------------------------------------- 'black' => '0;30m', 'dark_gray' => '1;30m', 'red' => '0;31m', 'light_red' => '1;31m', 'green' => '0;32m', 'light_green' => '1;32m', 'brown' => '0;33m', 'yellow' => '1;33m', 'blue' => '0;34m', 'light_blue' => '1;34m', 'purple' => '0;35m', 'light_purple' => '1;35m', 'cyan' => '0;36m', 'light_cyan' => '1;36m', 'gray' => '0;37m', 'white' => '1;37m', 'off' => '0m', # used to reset colours '' => '', # dummy #----------+---------------------------------------- ); # --------------------------------------------- functions sub colour ($$$) { my ($fg, $bg, $txt) = @_; return $txt if (!defined $ENV{TERM}); return $txt if ($_LEN == -1); $bg = $map{$bg}; $fg = $map{$fg}; $bg =~ s#;3#;4# if ($bg ne ""); $bg = "\N{ESCAPE}[${bg}" if ($bg ne ""); $fg = "\N{ESCAPE}[${fg}" if ($fg ne ""); return "$fg$bg$txt\N{ESCAPE}[0m"; } sub colour_reset () { print colour('off', '', ''); return; } sub deco ($$) { my ($mm, $txt) = @_; return $txt if (!defined $ENV{TERM}); return "\N{ESCAPE}[$mm$txt\N{ESCAPE}[0m"; } sub bold ($) { return deco('1m', shift); } sub dim ($) { return deco('2m', shift); } sub italic ($) { return deco('3m', shift); } sub underline ($) { return deco('4m', shift); } sub reversebg ($) { return deco('7m', shift); } sub reversefg ($) { return deco('8m', shift); } sub strike ($) { return deco('9m', shift); } # as changing text colour (forground) is the most common usage, there is one # function for each color, and one function to just switch the background sub black ($) { return colour('black', "", shift); } sub red ($) { return colour('red', "", shift); } sub green ($) { return colour('green', "", shift); } sub brown ($) { return colour('brown', "", shift); } sub blue ($) { return colour('blue', "", shift); } sub purple ($) { return colour('purple', "", shift); } sub magenta ($) { return colour('purple', "", shift); } # alias for purple sub cyan ($) { return colour('cyan', "", shift); } sub gray ($) { return colour('gray', "", shift); } sub white ($) { return colour('white', "", shift); } sub yellow ($) { return colour('yellow', "", shift); } sub boldred ($) { return colour('light_red', "", shift); } sub boldpurple ($){ return colour('light_purple', "", shift); } sub something ($) { return colour('purple', "", shift); } sub background ($){ return colour("", shift, ""); } sub italic_label ($) { my $txt = shift; $txt =~ s/^(.*:)(.*)/return italic($1),$2;/es; return $txt; } sub pad_right ($) { my $txt = shift; my $_c = " "; $_c = "_" if (defined $ENV{ComSpec}); # dirty hack $txt .= $_c for length($txt)..($_LEN - 1); return "$txt"; } sub testme () { my ($txt, $and, $t2, $t3); $txt = pad_right(" line padded"); print reversebg("$txt\n"); $and = reversebg("and"); print red( " line red\n"); print green( " line green\n"); print brown( " line brown\n"); print blue( " line blue\n"); print purple( " line purple\n"); print cyan( " line cyan\n"); print gray( " line gray\n"); print black( " line black\n"); print white( " line white\n"); print yellow( " line yellow\n"); print underline(" line underlined\n"); print strike( " line striked\n"); print bold( " line bold\n"); print italic( " line italic\n"); print something( " line something\n"); $txt = red( "red"); $t2 = green( "green"); $t3 = underline("underlined"); print " line with $txt word\n"; print " line with $txt $and $t2 $and $t3 word\n"; $txt = bold( "bold"); $t2 = dim( "dimmed"); $t3 = strike("striked"); print " line with $txt $and $t2 $and $t3 word\n"; $txt = bold( "striked bold green"); $txt = strike("$txt"); $txt = green( "$txt"); print " line with $txt word\n"; print reversebg(" line reverse\n"); print italic_label "label with italic text:\t\tnormal text \n"; background('cyan'); # FIXME: does not yet work proper print colour('black', 'cyan', " line black\n"); print colour('green', 'cyan', " line green\n"); print " line\n"; background('off'); print boldred(" line bold red\n"); colour_reset; # no reset background completely; print green("done\n"); return; } # --------------------------------------------- options while ( $#ARGV >= 0 ) { my $arg = shift; my $fh; my $dumm; if ($arg =~ m/--?h(elp)/) { open($fh, '<:encoding(UTF-8)', $0) || die "[$0]: **ERROR: cannot read myself.\n"; $dumm = grep { my $l; $l = $_; $l =~ s/\$0/$ich/g; /#\?(.*)$/ && print "$1\n"; } (<$fh>); close($fh); exit 0; } if ($arg =~ m/--version/) { open($fh, '<:encoding(UTF-8)', $0) || die "$0: WARNING: cannot read myself.\n"; $dumm = grep { my $l; $l = $_; $l =~ /^#\?\s*@\(#\)/ && $l =~ s/#\?// && print } (<$fh>); close($fh); exit 0; } if ($arg =~ m/--line/) { $mode='line'; $italic=0; } if ($arg =~ m/--word/) { $mode='word'; } if ($arg =~ m/--italic/) { $mode='word'; $italic=1; } if ($arg =~ m/--blind/) { $map{'green'} = $map{'blue'}; $map{'light_green'} = $map{'light_blue'}; } if ($arg =~ m/--purple/) { $map{'brown'} = $map{'purple'}; $map{'yellow'} = $map{'light_purple'}; } if ($arg =~ m/--test/) { testme; exit 0; } if ($arg =~ m/--(\d+)/) { my $num = $1; _warn("WARNING: given width '$num' larger than computed size '$_LEN'") if ($num > $_LEN); $_LEN = $num } } # --------------------------------------------- main # get o-saft.pl's markup as regex # o-saft.pl --help=ourstr sub bgcyan ($) { background("cyan"); print gray(shift); colour_reset; # FIXME: does not yet work proper return; } ## no critic qw(InputOutput::ProhibitInteractiveTest) # it's the authors opinion that the perlish -t is better (human) readable if (-t STDIN) { _warn("ERROR text on STDIN expected; exit"); exit 2; } ## use critic my $txt = ""; while (my $line = ) { $_ = $line; # = $_; if ("$line" =~ m/^\s*$/) { print "\n"; next; } # speed! #dbx print "DBX: $_"; #{ all modes /^##yeast*CMD:/ && do { bgcyan( "$line"); next; }; /^\#[^[]/ && do { print blue( "$line"); next; }; /^\!\!Hint/ && do { print purple( "$line"); next; }; /^\*\*HINT/ && do { print purple( "$line"); next; }; /^\*\*WARN/ && do { print boldpurple("$line");next; }; /^\*\*ERROR/ && do { print boldred("$line"); next; }; /^=+/ && do { chomp $line; $txt = pad_right("$line"); print reversebg("$txt\n"); next; }; /^Use of .*perl/ && do { print purple("$line"); next; }; #} all modes if ($mode eq "line") { /<<[^>]*>>/ && do { print cyan( "$line"); next; }; /yes.*WEAK/i && do { print red( "$line"); next; }; /yes.*LOW/i && do { print red( "$line"); next; }; /yes.*MEDIU/i && do { print brown("$line"); next; }; /yes.*HIGH/i && do { print green("$line"); next; }; /yes$/ && do { print green("$line"); next; }; /no$/ && do { print brown("$line"); next; }; /no .*/ && do { print red( "$line"); next; }; print "$line"; next; } if ($mode eq "word") { /yes\s*(?:LOW|WEAK|MEDIUM|HIGH)$/i && do { # match cipher line with risk s/(LOW)$/ red( $1);/ie; s/(WEAK)$/ red( $1);/ie; s/(MEDIUM)$/ brown($1);/ie; s/(HIGH)$/ green($1);/ie; print "$_"; next; }; s/([[a-zA-Z0-9.-]+:[0-9]{1,5})/cyan($1);/ie && print && next; # leading host:port s/(#\[(?:[^\]]*)])/ cyan( $1);/ie && print && next; # leading #[key]: s/^([^:]+:)/italic $1; /e if ($italic == 1); # any other word: s/(yes\s*$)/ green( $1);/ie && print && next; s/(no\s*$)/ brown( $1);/ie && print && next; s/(no\s+\(.*\))/ yellow($1);/ie && print && next; print; } } exit 0; O-Saft-19.01.19/contrib/bunt.sh000077500000000000000000000252361342117255600160320ustar00rootroot00000000000000#! /bin/sh #? #? NAME #? $0 - postprocess to colourize output of o-saft.pl #? #? SYNOPSIS #? o-saft.pl | $0 [OPTIONS] #? #? DESCRIPTION #? That's it. #? #? OPTIONS #? --h got it #? --test simple self-testing #? --line colourize complete line #? --word colourize special words #? --blind use blue instead of green #? --italic colourize special words and additionally print "label texts:" #? with italic characters #? "label text:" is all text left of first : including : #? --NUM if a number, change assumed terminal width to NUM #? (used for padding text on the right); default: terminal width #? #? LIMITATIONS #? With --line all formatting with spaces and TABs is lost. #? #? Requires additional UNIX-style programs: #? /bin/echo, egrep, sed, tput, wc . # # HACKER's INFO # Feel free to write your own code. You just need to add/modify the code # following "main" below. # # How it workd, see function testeme below calling with $0 --test # $echo is used if /bin/echo or /usr/bin/printf is needed, \echo is used # if shell builtin is needed. #? #? VERSION #? @(#) bunt.sh 1.7 17/06/25 20:24:07 #? #? AUTHOR #? 08-jan-16 Achim Hoffmann _at_ sicsec .dot. de #? # ----------------------------------------------------------------------------- ich=${0##*/} _warn () { \echo "[$ich]: **$@" >&2 } if [ -n "$TERM" ]; then case "$TERM" in screen) _warn "WARNING: 'TERM=screen'; take care ..."; ;; esac else # not a terminal, switch off terminal capabilities # checks are done with: [ -z "$TERM" ] # probably better exit here true fi # --------------------------------------------- internal variables; defaults try='' dir=${0%/*} [ "$dir" = "$0" ] && dir="." # $0 found via $PATH in . seq=/usr/bin/seq echo=/bin/echo printf=0 # try to detect GNU echo if [ -x $echo ]; then $echo --version | \egrep -q 'echo.*GNU' if [ $? -eq 0 ]; then echo="/bin/echo -e" else if [ -e /usr/bin/printf ]; then echo="/usr/bin/printf %b" printf=1 _warn "WARNING: using '$echo'; take care ..." else _warn "WARNING: not GNU '$echo'; take care ..." # more escape sequenzes for GNU /bin/echo: # \a alarm \c no more output fi fi fi word=1 # default: colourize words italic=0 # default: nothing italic _LEN=80 # default: 80 characters per line; set to termial width below _MOD=0 # default: normal text, no highlight, bold, italic, underline, ... # more modes for /usr/bin/printf and GNU /bin/echo: # [0 normal # [1 bold/highlight # [2 dark # [3 normal italic # [4 normal underlined # [6 normal light gray # [7 reverse background # [8 reversed foreground (bold) # [9 normal strike # colours # escape sequence to be used in echo #-----------+---------------------------------------- black='0'; # black='0;30m'; dark_gray='1;30m' red='1'; # red='0;31m'; light_red='1;31m' green='2'; # green='0;32m'; light_green='1;32m' brown='3'; # brown='0;33m'; yellow='1;33m' blue='4'; # blue='0;34m'; light_blue='1;34m' purple='5'; # purple='0;35m'; light_purple='1;35m' cyan='6'; # cyan='0;36m'; light_cyan='1;36m' gray='7'; # gray='0;37m'; white='1;37m' off=''; # used to reset colours #-----------+---------------------------------------- # we use $_MOD later to switch to light colours _FG="" _BG="" # default: do not change background _MM=0m # used for changing character decoration # check terminal width # NOTE: Unfortunatelly stty fails if we have no terminal, i.e. in cron, # or the intended use in a stream (pipe). Hence we use tput; if # that fails too, 80 will be hardcoded (which then may return the # warning about length misatches). arg=`\tput cols` expr "$arg" + 0 >/dev/null ; # prints warning on STDERR [ $? -eq 0 ] && len=$arg if [ -n "$COLUMNS" ]; then # we got a hint, i.e. a bash [ $COLUMNS -ne $len ] && _warn "WARNING: terminal width $COLUMNS mismatch, using $len" fi _LEN=$len # got it # --------------------------------------------- functions colour () { [ -z "$TERM" ] && echo $@ && return _bg='' _fg='' [ -n "$_BG" ] && _bg='\033[1;4'$_BG'm' [ -n "$_FG" ] && _fg='\033['$_MOD';3'$_FG'm' $echo "$_fg$_bg$@\033[0m\c" # does not print \n at end of line, must be done by caller } colour_reset () { r=$_FG; _FG=$off; colour ""; _FG=$r } deco () { [ -z "$TERM" ] && echo $@ && return $echo "\033[$_MM$@\033[0m\c" } bold () { _MM=1m; deco "$@" } dim () { _MM=2m; deco "$@" } italic () { _MM=3m; deco "$@" } underline () { _MM=4m; deco "$@" } reversebg () { _MM=7m; deco "$@" } reversefg () { _MM=8m; deco "$@" } strike () { _MM=9m; deco "$@" } # as changing text colour (forground) is the most common usage, there is one # function for each color, and one function to just switch the background background () { case "$1" in black) _BG=$black ; ;; red) _BG=$red ; ;; green) _BG=$green ; ;; brown) _BG=$brown ; ;; blue) _BG=$blue ; ;; purple) _BG=$purple; ;; cyan) _BG=$cyan ; ;; gray) _BG=$gray ; ;; *) _BG=''; ;; esac } black () { m=$_FG; _FG=$black; colour "$@"; _FG=$m } red () { m=$_FG; _FG=$red; colour "$@"; _FG=$m } green () { m=$_FG; _FG=$green; colour "$@"; _FG=$m } brown () { m=$_FG; _FG=$brown; colour "$@"; _FG=$m } blue () { m=$_FG; _FG=$blue; colour "$@"; _FG=$m } purple () { m=$_FG; _FG=$purple; colour "$@"; _FG=$m } magenta () { m=$_FG; _FG=$purple; colour "$@"; _FG=$m; # alias for purple } cyan () { m=$_FG; _FG=$cyan; colour "$@"; _FG=$m } gray () { m=$_FG; _FG=$gray; colour "$@"; _FG=$m } white () { m=$_MOD; _MOD=1; gray "$@"; _MOD=$m } yellow () { m=$_MOD; _MOD=1; brown "$@"; _MOD=$m } boldred () { m=$_MOD; _MOD=1; red "$@"; _MOD=$m } boldpurple () { m=$_MOD; _MOD=1; purple "$@"; _MOD=$m } something () { m=$_MOD; _MOD=6; purple "$@"; _MOD=$m } talic () { f=$_FG; _FG=$gray m=$_MOD; _MOD=3; colour "$@"; _MOD=$m; _FG=$f } reverse () { deco "$@"; # alias for reversebg } italic_label () { \echo "$@" | \sed -e "s/^\(.*:\)/`italic \&`/" } pad_right () { space="" from=`echo "$@" | \wc -c` if [ $printf -eq 1 ]; then from=`\expr $_LEN - $from` _p=$@; # printf is is really strange; squeezes spaces also /usr/bin/printf "%s%${from}c" "$_p" else if [ -x $seq ]; then for s in `$seq $from $_LEN`; do space="$space " done fi $echo "$@$space" fi } testeme () { reversebg "`pad_right ' line padded'`\n" red " line red\n" green " line green\n" brown " line brown\n" blue " line blue\n" purple " line purple\n" cyan " line cyan\n" gray " line gray\n" black " line black\n" white " line white\n" yellow " line yellow\n" underline " line underlined\n" strike " line striked\n" bold " line bold\n" italic " line italic\n" something " line something\n" \echo " line with `red 'red'` word" \echo " line with `red 'red'` `reversebg and` `green 'green'` `reversebg and` `underline 'underlined'` word" \echo " line with `bold 'bold'` `reversebg and` `dim 'dimmed'` `reversebg and` `strike 'striked'` word" txt=`bold 'striked bold green'` txt=`strike "$txt"` txt=`green "$txt"` \echo " line with $txt word" reversebg " line reverse\n" italic_label "label with italic text: normal text " background cyan black " line black\n" green " line green\n" \echo " line" background '' boldred "line bold red\n" colour_reset # reset background completely green "done\n" } # --------------------------------------------- options while [ $# -gt 0 ]; do case "$1" in '-h' | '--h' | '--help') \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 exit 0 ;; '--version') \sed -ne '/^#? VERSION/{' -e n -e 's/#?//' -e p -e '}' $0 exit 0 ;; '--line') word=0; italic=0; ;; '--word') word=1; ;; '--italic') word=1; italic=1; ;; '--test') testeme; exit 0 ;; '--blind') green='4'; ;; # use blue instead of green --*) arg=`expr "$1" ':' '--\(.*\)'` expr "$arg" + 0 >/dev/null ; # prints warning on STDERR if [ $? -eq 0 ]; then [ $arg -gt $_LEN ] && \ _warn "WARNING: given width '$arg' larger than computed size '$_LEN'" _LEN=$arg fi ;; esac shift done # --------------------------------------------- main # get o-saft.pl's markup as regex # o-saft.pl --help=ourstr bgcyan () { background cyan \echo `gray "$@"` colour_reset # FIXME: does not yet work proper } if [ -t 0 ]; then _warn "ERROR: text on STDIN expected; exit" exit 2 fi while read line; do [ -z "$line" ] && $echo && continue; # speed! case "$line" in \#\[*) true; ;; #\#yeast*CMD:*) bgcyan "$line"; continue; ;; \#*) blue "$line\n"; continue; ;; \*\*HINT*) purple "$line\n"; continue; ;; \*\*WARN*) boldpurple "$line\n"; continue; ;; \*\*ERROR*) boldred "$line\n"; continue; ;; =*) reversebg "`pad_right $line`\n"; continue; ;; "Use of "*perl*) purple "$line\n"; continue; ;; esac if [ $word -eq 0 ]; then case "$line" in *"<<"*">>"*) cyan "$line\n"; ;; *yes*weak) red "$line\n"; ;; *yes*WEAK) red "$line\n"; ;; *yes*low) red "$line\n"; ;; *yes*LOW) red "$line\n"; ;; *yes*medium) brown "$line\n"; ;; *yes*MEDIUM) brown "$line\n"; ;; *yes*high) green "$line\n"; ;; *yes*HIGH) green "$line\n"; ;; *yes) green "$line\n"; ;; *no) brown "$line\n"; ;; *"no "*) red "$line\n"; ;; *) \echo "$line"; ;; esac fi if [ $word -eq 1 ]; then [ $italic -eq 1 ] && line=`italic_label "$line"` # first a general check to improve performance \echo "$line" | \egrep -q -i '(LOW|WEAK|MEDIUM|HIGH|yes)$' if [ $? -eq 0 ]; then \echo "$line" | \egrep -q 'yes$' [ $? -eq 0 ] && \echo "$line" | \sed -e "s/yes$/`green yes`/" && continue \echo "$line" | \egrep -q -i 'yes.*(WEAK|LOW|MEDIUM|HIGH)$' # some older sed do not support i flag, hence # case insensitive matching the traditional way [ $? -eq 0 ] && \echo "$line" | \sed \ -e "s/\([Ll][Oo][Ww]\)$/`red \&`/" \ -e "s/\([Ww][Ee][Aa][Kk]\)$/`red \&`/" \ -e "s/\([Mm][Ee][Dd][Ii][Uu][Mm]\)$/`brown \&`/" \ -e "s/\([Hh][Ii][Gg][Hh]\)$/`green \&`/" \ && continue \echo "$line" continue fi # anything with "no" in value is a bit special \echo "$line" | \egrep -q 'no$' [ $? -eq 0 ] && \echo "$line" | \sed -e "s/no$/`brown no`/" && continue \echo "$line" | \egrep -q 'no \(' [ $? -eq 0 ] && \echo "$line" | \sed -e "s/\(no (.*\)/`yellow \&`/" && continue \echo "$line" | \egrep -q '^#\[' [ $? -eq 0 ] && \echo "$line" | \sed -e "s/^\(#\[.*\]\)/`cyan \&`/" && continue \echo "$line" fi done exit 0 O-Saft-19.01.19/contrib/cipher_check.sh000077500000000000000000000115731342117255600174700ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - test for ciphers with various methods #? #? SYNOPSIS #? $0 target #? #? OPTIONEN, Argumente #? --h - na sowas #? --n - try, do nothing #? --delay - check with --connect-delay=1 also; default: do not check #? #? DESCRIPTION #? Unfortunately modern systems (2016 and later) often behave unusual. #? Detecting such unusual behaviour is often not possible, This script #? uses different methods (commands and options) to check for ciphers. #? If these methods return different results, the results should be #? verified carefully. #? #? This script calls o-saft.pl with different commands and options to #? check the target for supported ciphers. The purpose is to get a more #? accurate list of supported ciphers. #? Reasons to do different checks are: #? * target supports unusal ciphers (not known by underlaying libssl) #? * target behaves strange when connecting to test for ciphers, i.e. a #? target may return an TLS alert #? * the target is protected by an IPS, which blocks further connects #? if it detects to many connects within a specific timeframe #? * general network problems #? #? This script writes results to various ./cipher_check__.*.log files. #? #? WARNING #? With the --delay option, the script will use options to delay the #? connetcs to the target. This slows down the script, obviously. #? Example: a delay of 1 second will result in a 5 x 200 = 1000 seconds #? (200 ciphers for 5 protocols, approx 17 minutes). #? # HACKER's INFO # The results are analysed programatically to detect differences. # Therfore following options are used to generate a parsable output: # --tracekey --legacy=compact --noheader --enabled # Also, all the tests are done for each SSL protocol separately. This # avoids heavy load (due to many connections) on the server and also # simplifies the comparison of the generated result files. #? #? EXAMPLES #? $0 site.tld #? $0 site.tld --delay #? #? LIMITATIONS #? #? SEE ALSO #? o-saft.pl #? #? VERSION #? @(#) cipher_check.sh 1.1 17/07/14 22:23:42 #? #? AUTHOR #? 07-jul-17 Achim Hoffmann #? # ----------------------------------------------------------------------------- ich=${0##*/} try="" log="" dly=0 exe=o-saft.pl ini=/tmp/cipher_check.ini log_ok=cipher_check__.log methods=" # +cipher # +ciher is the initial test, it's used as reference for following +cipher --no-ssl-error # +cipher --ssl-error-max=23 +cipher --connect-delay=1 +cipher --cipheralpn=, +cipher --ciphernpn=, +cipher --cipheralpn=, --ciphernpn=, +cipher --force-openssl +cipher --force-openssl --connect-delay=1 # TODO: following have different output format # +cipher-dh # +cipherall " SSL="sslv2 sslv3 tlsv1 tlsv11 tlsv12 tlsv13 dtlsv1 dtlsv11 dtlsv12 dtlsv13" echo "" > $log_ok # write new logfile logname() { echo "cipher_check__"`echo $*|\tr -s ' ' '_'`.txt } check_cipher() { # use all variables from main, quick&dirty echo -n "##{ testing $exe $target --rc=$ini --$ssl $cmd > $log " if [ -z $try ] ; then $exe $target --rc=$ini --$ssl $cmd \ | \sed -e 's/0x020701C0/0x0300000A/' \ > $log fi echo " ##}" return 0 } check_result() { # use all variables from main, quick&dirty line="######################################" base_log=`logname $ssl +cipher` if [ -z $try ] ; then ( #echo "" \diff -q $base_log $log 2>&1 > /dev/null status=$? if [ $status -eq 0 ]; then echo "# OK: $cmd" else echo "# diff: $cmd $line" echo "diff $base_log $log" \diff $base_log $log echo "" fi ) >> $log_ok fi return $status } while [ $# -gt 0 ]; do arg="$1" shift case "$arg" in '-h' | '--h' | '--help' | '-?') \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 exit 0 ;; '-n' | '--n') try=echo; ;; '--delay') dly=1; ;; *) target=$arg; ;; esac done # generate our private RC-file (to avoid long command line) \cat > $ini <> $ini done cat $ini # redefine list of protocols for practical use (2017) SSL="sslv2 sslv3 tlsv1 tlsv11 tlsv12" # check ciphers with other methods, separate for each SSL protocol for ssl in $SSL; do cmd="+cipher" # use +cipher as reference test log=`logname $ssl $cmd` check_cipher echo "$methods" | while read cmd ; do [ -z "$cmd" ] && continue echo "$cmd" |\egrep -q '^\s*#' && continue # skip comment line if [ $dly -eq 0 ] ; then echo "$cmd"|\egrep -q 'delay=' && continue # skip delay command fi log=`logname $ssl $cmd` check_cipher check_result done done \rm $ini \cat $log_ok echo "# see cipher_check__.* files" echo O-Saft-19.01.19/contrib/critic.sh000077500000000000000000000160101342117255600163250ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - einfacher Wrapper für perlcritic #? #? SYNOPSIS #? $0 [] [] [perlcritic optionen] #? #? OPTIONEN, Argumente #? --h - na sowas #? --n - nix machen, nur zeigen #? -- - alle weiteren Argumenta an perlcritic übergeben #? --v - alias für: --verbose 10 #? --all - Aufruf von perlcritic für alle Quelldateien #? --doc - wird direkt an perlcritic durchgereicht #? #? only - perlcritic mit --verbose 10 --single-policy aufrufen #? --only - Alias für only #? disabled - nur die Policys prüfen, die in .perlcritic disabled sind #? --disabled - Alias für disabled #? #? x::x - jeder String, der min einmal :: enthält #? #? Nützliche Optionen von perlcritic #? -5 | -4 | -3 | -2 | -1 #? - Severity-Level der Prüfung #? --doc PATTERN- Beschreibung für PATTERN ausgeben #? --noprofile - .perlcriticrc ignorieren #? --force - ignoriere "## no critic" Annotationen im Source-Code #? --nocolor - Ausgabe nicht farblich markieren #? --verbose 10 - gibt zu allen Findings die Beschreibung aus #? --exclude PATTERN - dieses PATTERN nicht prüfen #? #? BESCHREIBUNG #? Wrapper-Script zum vereinfachten Aufruf von perlcritic. #? Werden nur Dateinamen als Argumente angegeben, dann wird perlcritic mit #? nur diesen aufgerufen. Bei allen anderen Argumenent wird geprüft, ob es #? eine Option (siehe oben) ist, wenn nicht wird es an perlcritic überge- #? ben. #? Argumente für Policy [] werden automatisch erkannt, wenn min. #? einmal :: enthalten ist. #? Werden Policys ohne die Option --only angegeben, dann werden sie mit #? der Option --include an perlcritic übergeben. #? Werden Policys mit - angegeben, dann werden sie mit der Option #? --exclude an perlcritic übergeben. #? #? Alle Ausgaben von $0 selbst beginnen mit # (hash), alle anderen Aus- #? gaben kommen von perlcritic. #? #? BEISPIELE #? * normaler Aufruf (identisch zu perlcritic direkt): #? $0 datei #? #? * nur angegebe Policy prüfen mit ausführlicher Erklärung: #? $0 datei Subroutines::RequireArgUnpacking --only #? $0 datei Subroutines::RequireArgUnpacking only #? #? * normaler Aufruf und zusätzlich Policy prüfen #? $0 datei Subroutines::RequireArgUnpacking #? #? * normaler Aufruf und Policy nicht prüfen #? $0 datei -Subroutines::RequireArgUnpacking #? #? * nur deaktivierte Policy prüfen mit ausführlicher Erklärung: #? $0 datei --disabled #? #? * nur Beschreibung für PATTERN ausgeben #? $0 --doc ValuesAndExpressions::RequireNumberSeparators #? #? * alle Dateien des Projektes mit Severity 5, 4 und 3 prüfen #? $0 --all #? #? EINSCHRÄNKUNGEN #? Wenn es eine Datei gibt, die genauso heisst, wie eine Policy, dann wird #? dieses Argument immer als Dateiname und nie als Policy-Name benutzt. #? #? Dateien in den Verzeichnissen: .git .svn CVS RCS SCCS werden nicht #? bearbeitet, es wird eine Warnung ausgegeben. #? #? SIEHE AUCH #? perlcriticrc(1) #? .perlcriticrc #? #? VERSION #? @(#) critic.sh 1.6 16/07/17 10:59:20 #? #? AUTHOR #? 06-apr-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- ich=${0##*/} try='' mode="--include"; # oder --single-policy oder leer opts="" our_sources="\ osaft.pm o-saft-dbx.pm o-saft-man.pm o-saft-usr.pm \ Net/SSLhello.pm Net/SSLinfo.pm checkAllCiphers.pl" _isrepository () { #? check if path is a potentially a repository directory #? returns 0 if it is, 1 otherwise arg="$1" dir=${path%/*} case "$dir" in .git | .svn | CVS | RCS | SCCS ) #echo "# [$ich] **WARNING: $arg seems to be a repository file; skipped" echo "# [$ich] **WARNING: $arg scheint eine Repository-Datei zu sein; ignoriert" return 0 break; esac return 1 }; # _isrepository while [ $# -gt 0 ]; do arg="$1" shift case "$arg" in '-h' | '--h' | '--help' | '-?') \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 exit 0 ;; '-n' | '--n') try=echo; ;; '-v' | '--v') opts="--verbose 10 $opts"; ;; '--only' | 'only') mode="--single-policy"; ;; '--disabled' | 'disabled') mode="--single-policy" pols="`perl -lne '/^\[-/ && do {$_=~s/\[-([^\]]*).*/$1/;$\=q( );print}' .perlcriticrc`" ;; '-1' | '-2' | '-3' | '-4' | '-5') opts="$arg"; ;; '--1' | '--2' | '--3' | '--4' | '--5') opts="$arg"; ;; # for lazy people '--doc') opts="$arg"; mode=""; break; ;; '--all' | '--all-o-saft') mode="ALLE"; files="o-saft.pl $our_sources"; break; ;; '--yeast' | '--all-yeast') mode="ALLE"; files="yeast.pl $our_sources"; break; ;; '--') break; ;; # alle weiteren Argumnta für perlcritic *) # es kann kommen: # * Dateiname # * : Subroutines::RequireArgUnpacking if [ -e $arg ]; then files="$files $arg" continue fi par=${arg#*::} if [ "$par" = "$arg" ]; then echo "# [$ich] unbekanntes Argument, wird an perlcritic übergeben »$par«" opts="$opts $arg" # Option für perlcritic continue else case "$arg" in -*) arg=${arg#*-} echo "# [$ich] Exclude Policy: »$arg«" excl="$excl --exclude $arg" ;; *) echo "# [$ich] Include Policy: »$arg«" pols="$pols $arg" ;; esac continue fi opts="$opts $arg" # Option für perlcritic ;; esac done if [ "$mode" = "ALLE" ]; then echo "# [$ich] alle Dateien: $files" echo "# [$ich] Statistik" for serverity in -5 -4 -3; do echo echo "# [$ich] $serverity {############################################################" echo "# perlcritic $serverity --count $files $opts" $try \perlcritic $serverity --count $files $opts echo echo "# perlcritic $serverity --statistics-only $files $opts" $try \perlcritic $serverity --statistics-only $files $opts echo "# [$ich] $serverity }" done echo echo "# [$ich] Violations" for serverity in -5 -4 -3; do echo echo "# [$ich] $serverity {############################################################" for file in $files; do _isrepository $file && continue echo echo "# perlcritic $serverity $file $opts" $try \perlcritic $serverity $file $opts done echo "# [$ich] $serverity }" done exit 0 fi [ "$mode" = "--single-policy" ] && opts="--verbose 10 $opts" if [ -n "$pols" ]; then for p in $pols; do policy="$policy $mode $p" done fi echo "# [$ich] Dateien: $files" echo "# [$ich] Policys: $policy $excl" echo "# [$ich] Optionen: $opts" echo "# [$ich] Optionen: $@" echo "" for file in $files; do _isrepository $file && continue echo \perlcritic $file $policy $excl $opts $@ [ -n "$try" ] && continue \perlcritic $file $policy $excl $opts $@ [ $? -ne 0 ] && echo $file critique done O-Saft-19.01.19/contrib/distribution_install.sh000077500000000000000000000016751342117255600213300ustar00rootroot00000000000000#!/bin/bash # # script provided by HeitorG https://github.com/HeitorG if [ -e /etc/pacman.conf ] then sudo pacman -S perl --needed elif [ -e /etc/apt ] then sudo apt-get install perl elif [ -e /etc/yum.conf ] then sudo yum install perl perl-CPAN else echo "Your system is unsupported by this script" echo "Please install the dependencies manually" echo "open the terminal and type: sudo cpan install strict Net::SSLeay IO::Socket::SSL IO::Socket::INET Net::DNS" fi sudo cpan install strict Net::SSLeay IO::Socket::SSL IO::Socket::INET Net::DNS if [ -e /usr/share/O-Saft ] then sudo rm -rf /usr/share/O-Saft fi if [ -e /usr/bin/O-Saft ] then sudo rm /usr/bin/O-Saft fi cd .. && sudo mv O-Saft /usr/share/ sudo sh -c 'echo "#!/bin/bash" > /usr/bin/O-Saft' sudo sh -c 'echo "cd /usr/share/O-Saft" >> /usr/bin/O-Saft' sudo sh -c 'echo "exec perl o-saft.pl $@" >> /usr/bin/O-Saft' sudo chmod +x /usr/bin/O-Saft clear echo "Type 'O-Saft', to open." O-Saft-19.01.19/contrib/filter_examples000066400000000000000000000142231342117255600176230ustar00rootroot00000000000000#!/bin/cat #? NAME #? filter_examples - examples for formatting o-saft.pl's output #? #? DESCRIPTION #? This file contains examples for more sophisticated convertions of #? o-saft.pl's output. #? All examples should work just by copy&paste. #? #? LIMITATIONS #? Some of the provided filter scripts are awk scripts. They most likely #? require Gnu awk (or compatible) instead of the traditional AT&T awk. #? #? Depending on the operating system and/or it's configuration, the awk #? scripts need to be used like: #? gawk -f contrib/script #? instead of (as shown in our examples): #? contrib/script #? ############################################################################### ### ### Using filters (overview) ### o-saft.pl +cipher localhost | contrib/bunt.pl o-saft.pl +info localhost | contrib/HTML-simple.awk o-saft.pl +check localhost | contrib/HTML-table.awk o-saft.pl +info localhost --tracekey --tab | contrib/JSON-array.awk o-saft.pl +info localhost --tracekey --tab | contrib/JSON-struct.awk o-saft.pl +check localhost --tracekey --tab | contrib/JSON-array.awk o-saft.pl +info localhost | contrib/XML-value.awk o-saft.pl +check localhost | contrib/XML-attribute.awk ############################################################################### ### ### CSV convertions ### ### +info output: separate label and value, one per line o-saft.pl +info --legacy=quick localhost \ | gawk -F'\t' '/^\s*$/{next}($1~/^[#=]/){next}{print $1","$2}' # or o-saft.pl +info localhost --legacy=compact --no-header --sep=, ############################################################################### ### ### HTML convertions ### ### +info output: label and value per line (full html) o-saft.pl +info localhost | contrib/HTML-simple.awk # or o-saft.pl +info --legacy=quick localhost \ | gawk 'BEGIN{FS="\t";print ""}(NF>0){gsub(/&/,"\\&");gsub(/"/,"\\"");gsub(//,"\\>");}/^\s*$/{next}($1~/^[#=]/){print "";next}{print " "}END{print "
"$1""$2"
"}' ### +info output: label and value per line (html table lines only) o-saft.pl +info --legacy=quick localhost \ | gawk -F'\t' '/^\s*$/{next}(NF>0){gsub(/&/,"\\&");gsub(//,"\\>");}($1~/^[#=]/){print "";next}{print " "$1""$2""}' ### +check output: label and value in table; header lines o-saft.pl +check localhost | contrib/HTML-table.awk # or o-saft.pl +check --legacy=quick localhost \ | gawk 'BEGIN{FS="\t";print ""}(NF>0){gsub(/&/,"\\&");gsub(//,"\\>");}/^\s*$/{next}($1~/ reading /){next;}($1~/^===/ && $NF~/===/){printf("

%s

\n",$0);next}($1~/^== /){print "";next;}($1~/^[#=]/){print "";next}{print " "}END{print "
"$0"
"$1""$2"
"}' ############################################################################### ### ### JSON convertions ### ### +info output: label and value per line in JSON style array o-saft.pl +info --legacy=quick localhost \ | gawk 'BEGIN{FS="\t";print "info=["}(NF>0){gsub(/\\/,"&&");gsub(/"/,"\\\"");}/^\s*$/{next}($1~/^[#=]/){print "// "$0;next}{printf(" \"%s\": \"%s\",\n",$1,$NF)}END{print " dumm:\"dumm\"\n];"}' o-saft.pl +info --tracekey --tab localhost | contrib/JSON-array.awk o-saft.pl +info --tracekey --tab localhost | contrib/JSON-struct.awk ############################################################################### ### ### XML convertions ### ### +info output: label and value per line o-saft.pl +info localhost | contrib/XML-value.awk # or o-saft.pl +info --legacy=quick localhost \ | gawk 'BEGIN{FS="\t";print ""}(NF>0){gsub(/&/,"\\&");gsub(//,"\\>");}/^\s*$/{next}($1~/^[#=]/){print "";next}{print " \n \n "$2"\n "}END{print ""}' ### +info output: one line per label and value o-saft.pl +info localhost \ | gawk 'BEGIN{FS="\t";print ""}(NF>0){gsub(/&/,"\\&");gsub(//,"\\>");}/^\s*$/{next}($1~/^[#=]/){print "";next}{print " "$2""}END{print ""}' # same as before a bit more compact o-saft.pl +info --legacy=quick localhost \ | gawk 'BEGIN{FS="\t";print ""}(NF>0){gsub(/&/,"\\&");gsub(//,"\\>");}/^\s*$/{next}($1~/^[#=]/){next}{print ""$2""}END{print ""}' ### +info output: one line per label and value as attribute o-saft.pl +info localhost | contrib/XML-attribute.awk # or o-saft.pl +info --legacy=quick localhost \ | gawk 'BEGIN{FS="\t";print ""}(NF>0){gsub(/&/,"\\&");gsub(/"/,"\\"");gsub(//,"\\>");}/^\s*$/{next}($1~/^[#=]/){print "";next}{i++;printf(" \n",i,$1,$2);}END{print ""}' ############################################################################### ### ### Parsable SSL protocol in output ### ### +cipher output: cipher lines with SSL protocol version o-saft.pl +cipher localhost --header --legacy=sslaudit o-saft.pl +cipher localhost --header --legacy=ssldiagnose o-saft.pl +cipher localhost --header --legacy=full ### +cipher output: all lines are prefixed with SSL protocol version o-saft.pl +cipher localhost --header --legacy=quick \ | awk '/^=== Ciphers:/{p=$(NF-1)}/^/{printf"%s\t%s\n",p,$0;}' ### +cipher output: all lines are prefixed with SSL protocol version, no headers o-saft.pl +cipher localhost --header --legacy=quick \ | awk '/^=== Ciphers:/{p=$(NF-1)}/^=/{next}/^/{printf"%s\t%s\n",p,$0;}' O-Saft-19.01.19/contrib/fish_completion_o-saft000077500000000000000000000045101342117255600210740ustar00rootroot00000000000000#!/usr/bin/env ruby #? NAME #? fish_completion_o-saft - fish completion function for o-saft.pl #? #? DESCRIPTION #? This fish function provides values to be used in fish's completion #? (see fish's complete command). #? #? USAGE #? cp fish_completion_o-saft ~/.config/fish/completion/o-saft.pl.fish #? #? There are various methods of using this file in fish, please see #? fish's manual page for details. The above "cp" command just shows #? how to make this file autoloaded by fish (note that fish requires #? a special name for the file then). #? #? SEE ALSO #? http://fishshell.com/docs/current/index.html#completion-own #? #? AUTHOR #? 14-dec-14 Benjamin Kellermann # ------------------------------------------------------------------------------ SID="fish_completion_o-saft 1.1 16/09/25 11:10:47" BIN="o-saft.pl" require "pp" class String def shell_escape self.gsub("'",'\'').gsub("\"",'\"').gsub('`','\`') end end options = [["",""]] `#{BIN} --help=options`.lines.each{|l| if l =~ /^\s*-/ options << [] options.last << l.scan(/^\s*(\-.*)/).flatten[0] options.last << "" else options.last[1] += l end } options.each{|o| o[1].strip!} options.uniq! options.delete(["",""]) options.delete([nil,""]) simopts = [] options.collect!{|o| if o[0] =~ /, / o[0].split(",").collect{|e|e.strip}.each{|e| simopts << [e,o[1]]} nil else o end } options += simopts options.delete(nil) options.collect!{|o,d| case o when / /,"" # cannot use options with spaces inside or empty nil else [o,d] end } options.delete(nil) options.collect!{|o,d| # remove newlines or double spaces [o,d.gsub("\n"," ").gsub(/ {2,}/," ")] } options.collect!{|o,d| # cut everything after and including the first dot [o,d.gsub(/\..*$/,'')] } options.each{|o,d| if o case o when /^--/ opt = "l" #when /^-\w\w/ # old-style options #opt = "o" when /^-\w$/ opt = "s" else opt = nil #unknown end if opt print "complete -f -c #{BIN} -#{opt} '#{o.gsub(/^-*/,"")}'" print " --description \"#{d.shell_escape}\"" if d != "" puts end end } commands = `#{BIN} --help=commands`.lines.collect{|l| l.strip.scan(/^(\+[^\s]*)\s*(.*)$/).flatten }.uniq commands.each{|c,d| if c print "complete -f -c #{BIN} -a '#{c}'" print " --description \"#{d.shell_escape}\"" if d != "" puts end } O-Saft-19.01.19/contrib/gen_standalone.sh000077500000000000000000000115731342117255600200420ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - generate o-saft_standalone.pl #? #? SYNOPSIS #? $0 #? #? OPTIONS #? --h got it #? --n do not execute, just show what would be done #? --t do not check if all files are commited to repository #? --s silent, do not print informations (for usage with Makefile) #? --v be a bit verbose #? #? DESCRIPTION #? Generate script, which contains (all) modules for O-Saft. #? #? NOTE: this will not generate a bulletproof stand-alone script! #? #? VERSION #? @(#) gen_standalone.sh 1.9 18/05/01 21:51:02 #? #? AUTHOR #? 02-apr-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- dst=o-saft-standalone.pl src=o-saft.pl try= sid=1 info=1 while [ $# -gt 0 ]; do case "$1" in '-h' | '--h' | '--help') ich=${0##*/} \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 exit 0 ;; '-n' | '--n') try=echo; ;; '-t' | '--t') sid=0 ; ;; '-s' | '--s') info=0 ; ;; '-v' | '--v') set -x ; ;; esac shift done o_saft=" osaft.pm OSaft/error_handler.pm OSaft/Doc/Data.pm Net/SSLhello.pm Net/SSLinfo.pm o-saft-dbx.pm o-saft-usr.pm o-saft-man.pm " osaft_doc=" OSaft/Doc/coding.txt OSaft/Doc/glossary.txt OSaft/Doc/help.txt OSaft/Doc/links.txt OSaft/Doc/rfc.txt " # OSaft/Doc/misc \ if [ $sid -eq 1 ]; then for f in $o_saft ; do # NOTE contribution to SCCS: %I''% \egrep -q 'SID.*%I''%' $f \ && \echo "**ERROR: $f changes not commited; exit" \ && exit 2 done fi if [ $info -eq 1 ]; then \echo "# generate $dst ..." \echo "" fi $try \rm -rf $dst [ "$try" = "echo" ] && dst=/dev/stdout # general hints how to include: # 1. extract from o-saft.pl anything before line ## PACKAGES # # 2. add o-saft.pl POD # # 3. add $osaft_standalone # # ?. include osaft.pm # # 4. include text from module file enclosed in ## PACKAGE scope from all modules # # 5. add rest of o-saft.pl # # 6. add separator line for POD ( # 1. $try \perl -ne 'print if (m()..m(## PACKAGES ))' $src # 2. $try $src --no-warning --no-rc --help=pod # 3. \echo '' \echo '$osaft_standalone = 1;' \echo '' # 4. # osaft.pm without brackets and no package f=osaft.pm \echo "# { # $f" $try \perl -ne 'print if (m(## PACKAGE {)..m(## PACKAGE })) and not m(package osaft;)' $f \echo "# } # $f" \echo "" ## TODO: OSaft/Doc/Data.pm f=OSaft/Doc/Data.pm \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE {)..m(## PACKAGE }))' $f \echo "} # $f" \echo "" # TODO: o-saft-usr.pm works, but not yet perfect f=o-saft-usr.pm \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE {)..m(## PACKAGE }))' $f #$try \cat $f \echo "} # $f" \echo "" ## TODO: o-saft-dbx.pm still with errors #f=o-saft-dbx.pm #\echo "{ # $f" #$try \perl -ne 'print if (m(## PACKAGE {)..m(## PACKAGE }))' $f #\echo "} # $f" #\echo "" ## TODO: o-saft-man fails to include properly f=o-saft-man.pm \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE {)..m(## PACKAGE })) and not m(use osaft;)' $f \ | \grep -v '^use OSaft::Doc::Data' \echo "} # $f" \echo "" f=OSaft/error_handler.pm \echo "{ # $f" #$try \perl -ne 'print if (m(## PACKAGE {)..m(## PACKAGE }))' $f $try \cat $f \echo "} # $f" \echo "" f=Net/SSLinfo.pm \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE {)..m(## PACKAGE }))' $f \echo "" \echo 'my $_ssinfo_dum = $Net::SSLinfo::next_protos; # avoid Perl warning: "used only once: possible typo ..."' \echo "} # $f" \echo "" ## TODO: Net/SSLhello.pm fails # Reasons: use of STR_HINT in _hint(); need: no strict 'subs' #f=Net/SSLhello.pm #\echo "{ # $f" #$try \perl -ne 'print if (m(## PACKAGE {)..m(## PACKAGE }))' $f \ # | \egrep -v '^use (osaft|OSaft::error_handler)' #\echo "} # $f" #\echo "" # 5. \echo "package main;" $try \perl -ne 'print if (not m()..m(## PACKAGES)) and not m(use osaft;)' $src \ | \egrep -v 'require (q.o-saft-man.pm|Net::SSLhello)' ) \ | $try \perl -pe '/^=head1 (NAME|Annotation)/ && do{print "=head1 "."_"x77 ."\n\n";};' \ > $dst $try \chmod 555 $dst [ $info -eq 0 ] && exit $try \ls -la $dst \echo "# $dst generated" cat << EoDescription The generated stand-alone script misses following functionality: * Commands +cipherall +cipher-dh * Options --help --help=* --v --trace --trace-* --exit* --starttls Use of any of these commands or options will result in Perl compile errors like (unsorted): Use of uninitialized value ... Undefined subroutine ... Subroutine XXXX redefined at ... "our" variable XXXX redeclared at ... However, --help and --help=* will work if following files $osaft_doc are located in the same directory as $dst . "perldoc $dst" contains all POD of all included (module) files in unsorted order. For more details for a stand-alone script, please see: o-saft.pl --help=INSTALL EoDescription exit O-Saft-19.01.19/contrib/install_openssl.sh000077500000000000000000000312221342117255600202630ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - build and install special openssl and Net::SSLeay #? #? SYNOPSIS #? $0 [OPTIONS] #? #? OPTIONS #? --h - nice option #? --n - do not execute, just show where to install #? #? DESCRIPTION #? Build special openssl based on Peter Mosman's openssl. Enables SSLv2 #? and SSLv3 and all possible ciphers. #? Installs build in specified directory; default: /usr/local/openssl . #? Additionally builds perl module Net::SSLeay based on special openssl. #? Net::SSLeay will be installed in /usr/local/lib . #? Modifies .o-saft.pl . #? This script is intended to be executed in the installation directory #? of O-Saft. #? #? Finally this script starts "o-saft.pl +version" using the installed #? openssl binary and the installed Net::SSLeay. The output should look #? like (paths may differ): #? ------------------------------------------------------------------------- #? # test o-saft.pl ... #? **WARNING: 143: SSL version 'TLSv13': not supported by Net::SSLeay; not checked #? Net::SSLeay:: #? ::OPENSSL_VERSION_NUMBER() 0x100020b0 (268443824) #? ::SSLeay() 0x100020b0 (268443824) #? Net::SSLeay::SSLeay_version() OpenSSL 1.0.2-chacha (1.0.2k-dev) #? = openssl = #? external executable /usr/local/openssl/bin/openssl #? version of external executable OpenSSL 1.0.2-chacha (1.0.2k-dev) #? full path to openssl.cnf file /usr/local/openssl/ssl/openssl.cnf #? common openssl.cnf files /usr/lib/ssl/openssl.cnf /etc/ssl/openssl.cnf /System//Library/OpenSSL/openssl.cnf /usr/ssl/openssl.cnf #? directory with PEM files for CAs /usr/local/openssl/ssl/certs #? common paths to PEM files for CAs /etc/ssl/certs /usr/lib/certs /System/Library/OpenSSL #? openssl supported SSL versions SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 #? Net::SSLeay 1.82 /usr/local/lib/x86_64-linux-gnu/perl/5.20.2/Net/SSLeay.pm #? ------------------------------------------------------------------------- #? #? WARNING #? Note that compilation and installation of openssl and Net::SSLeay #? uses known insecure configurations and features! This is essential to #? make o-saft.pl able to check for such insecurities. #? #? It's highly recommended to do this installation on a separate testing #? system. #? #? DO NOT USE THESE INSTALLATIONS ON PRODUCTIVE SYSTEMS. #? #? PRECONDITIONS #? Script needs write access to installation directories (/usr/local and #? /usr/local/lib by default). #? To build openssl, following libraries and include files are needed: #? gmp krb5 lksctp zlib #? Assumes that ca-certificates are install in /etc/ssl/certs/ . #? Assumes that following perl modules are installed: #? Net::DNS Mozilla::CA libidn.so #? #? ENVIRONMENT VARIABLES #? This script knows about following environment variable, which are the #? same as used in the Dockerfile. Use --n option to see the defaults. #? #? OSAFT_VM_SRC_OPENSSL #? URL to fetch openssl.tgz archive. #? #? OSAFT_VM_SHA_OPENSSL #? SHA256 checksum for the openssl-1.0.2-chacha.tar.gz archive. #? #? OSAFT_VM_TAR_OPENSSL #? Name of archive file for OpenSSL (during build). #? #? OSAFT_VM_DYN_OPENSSL #? Build (link) mode of openssl executable: --static or --shared #? #? OSAFT_VM_SRC_SSLEAY #? URL to fetch Net-SSLeay.tar.gz archive. #? #? OSAFT_VM_SHA_SSLEAY #? SHA256 checksum for the Net-SSLeay.tar.gz archive. #? #? OSAFT_VM_TAR_SSLEAY #? Name of archive file for Net-SSLeay.tgz (during build). #? #? Following environment variables can also be used: #? #? OSAFT_DIR #? Installation directory of O-Saft, used to find .o-saft.pl . #? #? OPENSSL_DIR #? Full path to installation directory of newly build openssl. #? #? SSLEAY_DIR #? Default installation of Net::SSLeay . #? #? LD_RUN_PATH #? Additional paths for runtime loader, used while linking with: #? "ld -rpath=..." #? Linking of openssl, libssl.so and SSLeay.so will use -rpath #? in LDFLAGS to ensure that the special library will be used. # # HACKER's INFO # This file mainly uses the commands from Dockerfile 1.20. Dockerfile's # syntax, which does not work in a shell, is deactivated with aliases. #? #? EXAMPLES #? Simple build with defaults: #? $0 #? VERSION #? @(#) install_openssl.sh 1.5 18/11/04 09:11:03 #? #? AUTHOR #? 18-jun-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- dir=`pwd` # Parameters passed to build OSAFT_VM_SRC_SSLEAY=${OSAFT_VM_SRC_SSLEAY:="http://search.cpan.org/CPAN/authors/id/M/MI/MIKEM/Net-SSLeay-1.85.tar.gz"} OSAFT_VM_SHA_SSLEAY=${OSAFT_VM_SHA_SSLEAY:="9d8188b9fb1cae3bd791979c20554925d5e94a138d00414f1a6814549927b0c8"} OSAFT_VM_TAR_SSLEAY=${OSAFT_VM_TAR_SSLEAY:="Net-SSLeay.tgz"} OSAFT_VM_SRC_OPENSSL=${OSAFT_VM_SRC_OPENSSL:="https://github.com/PeterMosmans/openssl/archive/1.0.2-chacha.tar.gz"} OSAFT_VM_SHA_OPENSSL=${OSAFT_VM_SHA_OPENSSL:="ad3d99ec091e403a3a7a678ddda38b392e3204515425827c53dc5baa92d61d67"} OSAFT_VM_TAR_OPENSSL=${OSAFT_VM_TAR_OPENSSL:="openssl.tgz"} OSAFT_VM_DYN_OPENSSL=${OSAFT_VM_DYN_OPENSSL:="--shared"} # --static not yet (2017) working 'cause of libkrb5 DESCRIPTION="Build special openssl (based on Peter Mosman's openssl)" OPENSSL_VERSION=1.0.2-chacha OSAFT_DIR=${OSAFT_DIR:="."} OPENSSL_DIR=${OPENSSL_DIR:=/usr/local/openssl} SSLEAY_DIR=${SSLEAY_DIR:=/usr/local/lib} LD_RUN_PATH=${LD_RUN_PATH:=$OPENSSL_DIR/lib} PATH=${OPENSSL_DIR}/bin:$PATH BUILD_DIR=${BUILD_DIR:=/tmp/_src} WORK_DIR=$dir optn=0 while [ $# -gt 0 ]; do ich=${0##*/} arg="$1" shift case "$arg" in '-h' | '--h' | '--help' | '-?') sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 exit 0 ;; '-n' | '--n') optn=1 try=echo cat < shell -> docker (\ echo 'openssl_conf=openssl_def'; \ echo '[openssl_def]'; \ echo 'engines=engine_section';\ echo '[engine_section]'; \ echo 'gost=gost_section'; \ echo '[gost_section]'; \ echo 'engine_id = gost'; \ echo 'default_algorithms=ALL';\ echo 'CRYPT_PARAMS=id-Gost28147-89-CryptoPro-A-ParamSet'; \ ) >> apps/openssl.cnf && \ # config with all options, even if they are default LDFLAGS="-rpath=$LD_RUN_PATH" && export LDFLAGS && \ # see description for LD_RUN_PATH above ./config --prefix=$OPENSSL_DIR --openssldir=$OPENSSL_DIR/ssl \ $OSAFT_VM_DYN_OPENSSL \ --with-krb5-flavor=MIT --with-krb5-dir=/usr/include/krb5/ \ -fPIC zlib zlib-dynamic enable-zlib enable-npn sctp \ enable-deprecated enable-weak-ssl-ciphers \ enable-heartbeats enable-unit-test enable-ssl-trace \ enable-ssl3 enable-ssl3-method enable-ssl2 \ enable-tls1 enable-tls1-method enable-tls\ enable-tls1-1 enable-tls1-1-method enable-tlsext \ enable-tls1-2 enable-tls1-2-method enable-tls1-2-client \ enable-dtls1 enable-dtls1-method \ enable-dtls1-2 enable-dtls1-2-method \ enable-md2 enable-md4 enable-mdc2 \ enable-rc2 enable-rc4 enable-rc5 \ enable-sha0 enable-sha1 enable-sha256 enable-sha512 \ enable-aes enable-cms enable-dh enable-egd \ enable-des enable-dsa enable-rsa enable-rsax \ enable-ec enable-ec2m enable-ecdh enable-ecdsa \ enable-blake2 enable-bf enable-cast enable-camellia \ enable-gmp enable-gost enable-GOST enable-idea \ enable-poly1305 enable-krb5 enable-rdrand enable-rmd160 \ enable-seed enable-srp enable-whirlpool \ enable-rfc3779 enable-ec_nistp_64_gcc_128 experimental-jpake \ -DOPENSSL_USE_BUILD_DATE -DTLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES -DTEMP_GOST_TLS \ && \ make depend && make && make report -i && make install && \ # make report most likely fails, hence -i # simple test echo -n "# number of ciphers $OPENSSL_DIR/bin/openssl: " && \ $OPENSSL_DIR/bin/openssl ciphers -V ALL:COMPLEMENTOFALL:aNULL|wc -l && \ # cleanup apk del --purge gmp-dev lksctp-tools-dev && \ cd $WORK_DIR && \ rm -rf $BUILD_DIR $OSAFT_VM_TAR_OPENSSL && \ # Pull, build and install Net::SSLeay RUN \ cd $WORK_DIR && \ mkdir -p $BUILD_DIR && \ wget --no-check-certificate $OSAFT_VM_SRC_SSLEAY -O $OSAFT_VM_TAR_SSLEAY && \ # check sha256 if there is one [ -n "$OSAFT_VM_SHA_SSLEAY" ] && \ echo "$OSAFT_VM_SHA_SSLEAY $OSAFT_VM_TAR_SSLEAY" | sha256sum -c ; \ \ tar -xzf $OSAFT_VM_TAR_SSLEAY -C $BUILD_DIR --strip-components=1 && \ # install additional packages for Net-SSLeay ... apk add --no-cache perl-net-dns perl-net-libidn perl-mozilla-ca && \ cd $BUILD_DIR && \ perl -i.orig -pe 'if (m/^#define\s*REM_AUTOMATICALLY_GENERATED_1_09/){print "const SSL_METHOD * SSLv2_method()\n\nconst SSL_METHOD * SSLv3_method()\n\n";}' SSLeay.xs && \ # quick&dirty patch, results in warning, which can be ignored # Warning: duplicate function definition 'SSLv2_method' detected in SSLeay.xs, line 4256 LDFLAGS="-rpath=$LD_RUN_PATH" && export LDFLAGS && \ echo "n" | env OPENSSL_PREFIX=$OPENSSL_DIR perl Makefile.PL \ INC=-I$OPENSSL_DIR/include DEFINE=-DOPENSSL_BUILD_UNSAFE=1 && \ # Makefile.PL asks for "network tests", hence pipe "n" as answer # installation in (default) /usr/local, hence no PREFIX= make && make test && make install && \ cd $WORK_DIR && \ rm -rf $BUILD_DIR $OSAFT_VM_TAR_SSLEAY && \ echo "# Adapt O-Saft's .o-saft.pl ..." cd $WORK_DIR && \ cp $OSAFT_DIR/.o-saft.pl $OSAFT_DIR/.o-saft.pl-orig && \ rm -f ./.o-saft.pl && \ perl -pe "s:^#\s*--openssl=.*:--openssl=$OPENSSL_DIR/bin/openssl:;s:^#?\s*--openssl-cnf=.*:--openssl-cnf=$OPENSSL_DIR/ssl/openssl.cnf:;s:^#?\s*--ca-path=.*:--ca-path=/etc/ssl/certs/:;s:^#?\s*--ca-file=.*:--ca-file=/etc/ssl/certs/ca-certificates.crt:" $OSAFT_DIR/.o-saft.pl-orig > ./.o-saft.pl && \ chmod 666 ./.o-saft.pl # Dockerfile 1.20 } echo "# test o-saft.pl ..." $OSAFT_DIR/o-saft.pl +version |egrep -i '(openssl|SSLeay)' O-Saft-19.01.19/contrib/install_perl_modules.pl000077500000000000000000000104011342117255600212670ustar00rootroot00000000000000#!/usr/bin/perl #? #? NAME #? $0 - install perl moduls #? #? DESCRIPTION #? Build and install Net::DNS, Net::SSLeay and IO::Socket::SSL in a #? local private ./lib directory. #? Using perl instead of sh in the hope that it will be mainly platform- #? independent. #? #? In shell-speak it does: #? tar xf Net-DNS-x.xx.tar.gz #? (cd Net-DNS-x.xx && perl Makefile.PL && make && make install) #? tar xf Net-SSLeay-x.xx.tar.gz #? (cd Net-SSLeay-x.xx && perl Makefile.PL && make && make install) #? tar xf IO-Socket-SSL-x.xx.tar.gz #? (cd IO-Socket-SSL-x.xx && perl Makefile.PL && make && make install) #? #? OPTIONS #? --n - do not execute, just show what would be done #? --f - do not exit if specified installation directory exists #? --l - list avaialble modules to be installed #? #? LIMITATIONS #? Module tarballs must exist in local ./ directory. #? Some perl modules may require make and/or cc to install properly. #? Installation path is hardcoded to ./lib to change edit code below. #? Unfortunatelly some installations require interactive input. #? #? AUTHOR #? 17-feb-17 Achim Hoffmann #? # ----------------------------------------------------------------------------- use strict; use warnings; use Cwd; my $VERSION = "@(#) install_perl_modules.pl 1.3 18/10/01 17:18:09"; my $pwd = cwd(); my $lib = "$pwd"; $lib = "$pwd/lib" if ($pwd !~ m#/lib/?#); my $try = ""; # echo for --n my $force = 0 ; # --f local $\ = "\n"; my @modules = qw(Net-DNS*gz Net-SSLeay*gz IO-Socket-SSL*gz); # http://search.cpan.org/~nlnetlabs/Net-DNS/ # http://search.cpan.org/CPAN/authors/id/N/NL/NLNETLABS/Net-DNS-1.08.tar.gz # http://search.cpan.org/CPAN/authors/id/M/MI/MIKEM/Net-SSLeay-1.80.tar.gz # http://search.cpan.org/CPAN/authors/id/S/SU/SULLR/IO-Socket-SSL-2.047.tar.gz $try = "echo" if (grep {/^--?n$/} @ARGV); $force = 1 if (grep {/^--?f$/} @ARGV); if (grep {/^--?l$/} @ARGV) { foreach my $module (@modules) { my $targz = (sort glob($module))[-1]; if (defined $targz) { print "# $try $targz -> $lib"; } else { print "# $module\t: not found"; } } exit 0; } sub do_install { my $try = shift; my $tar = shift; my $dst = shift; my $targz = (sort glob($tar))[-1]; # ls Net-SSLeay*gz | sort | tail -1 chomp $targz; my $dir = $targz; $dir =~ s/\.tar.gz$//; $dir =~ s/\.tgz$//; # in case it is .tgz instead of .tar.gz my @args = (); push(@args, $try) if ($try ne ""); print "# build $targz ..."; do { push(@args, "tar", "xf", $targz); eval { system(@args) }; # TODO: error check }; print "# cd $dir ..."; chdir($dir) or do { warn "**WARNING: cannot cd to '$dir': $!"; $try = "echo"; # avoids errors in next do{} }; @args = (); push(@args, $try) if ($try ne ""); do { # env NO_NETWORK_TESTING=n perl Makefile.PL PREFIX=$lib local $ENV{'NO_NETWORK_TESTING'} = "n"; # eval { require "Makefile.PL", "PREFIX=$lib"; }; # does not work @args = ("perl", "Makefile.PL", "PREFIX=$lib"); eval { system(@args) }; @args = (); push(@args, $try) if ($try ne ""); push(@args, "make"); eval { system(@args) }; push(@args, "install"); eval { system(@args) }; }; print "# rm $dir ..."; @args = ("rm", "-rf", "$dir"); chdir("..") and eval { system(@args) }; return; }; # do_install if (-e $lib) { if ($force < 1) { die "**ERROR: '$lib' exists; please use --f to enforce using it; exit"; } } else { mkdir($lib); } foreach my $module (@modules) { print "\n# $try $module -> $lib"; do_install($try, $module, $lib); chdir($pwd); # not necessary print <<'EoT'; # try testing with: o-saft.pl +version # # if it complains that modules cannot be loaded i.e. IO/Socket/SSL.pm or # Net/SSLeay.pm , then adding path to @INC in o-saft.pl may help, like: unshift(@INC, "./", "./lib", "./lib/share/perl/5.20.2/", "./lib/lib/x86_64-linux-gnu/perl/5.20.2/", ... # done. EoT } O-Saft-19.01.19/contrib/lazy_checks.awk000077500000000000000000000027161342117255600175270ustar00rootroot00000000000000#!/usr/bin/gawk -f #? #? NAME #? lazy_checks.awk - filters some check results #? #? SYNOPSIS #? o-saft.pl +check ... | lazy_checks.awk #? o-saft.pl +check ... | gawk -f lazy_checks.awk #? #? DESCRIPTION #? Some checks from o-saft.pl's +check command report 'no (...)' as result #? and consequently increase the counter for total number of 'no' checks. #? As some of these checks report 'no ()' because of specific conditions, #? i.e. something is not applicapble (N/A), the total count for 'no' may #? sometimes be mis-leading. #? #? This filter removes these results and adjusts the count. #? #? Currently the following results are filtered: #? no (< ! | $ < in parameters are silently #? removed. This is a simple, but not perfect attempt to inhibit shell #? injections. #? #? VERSION #? @(#) o-saft.php 1.2 18/09/30 23:28:13 #? #? AUTHOR #? 17-feb-17 Achim Hoffmann # ----------------------------------------------------------------------------- header('Content-Type: text/plain'); $qs = ""; if (isset($_SERVER['QUERY_STRING'])) { $qs = join(' ', split('&', $_SERVER['QUERY_STRING'])); } $qs = preg_replace('/[;&`>!|$<]/', '', $qs, -1);# remove dangerous characters #dbx# echo("/cgi-bin/o-saft.pl --cgi $qs \n"); #passthru("/cgi-bin/o-saft.pl --cgi $qs", $err); passthru("cd ../cgi-bin;./o-saft.pl $qs", $err); # --cgi avoids messages like: "=== reading: ..." # add more options as needed #dbx# echo "# ERROR: $err\n"; exit; ?> O-Saft-19.01.19/contrib/tcsh_completion_o-saft000077500000000000000000000016561342117255600211140ustar00rootroot00000000000000#?/bin/tcsh #? NAME #? $0 - tcsh completion function for o-saft.pl #? #? DESCRIPTION #? This tcsh function provides values to be used in tcsh's completion #? (see tcsh's complete key). #? #? USAGE #? source tcsh_completion_o-saft #? complete o-saft.pl C/+/(+help +version)/ #? #? SEE ALSO #? http://hyperpolyglot.org/unix-shells #? http://www.tcsh.org/tcsh.html/Builtin_commands.html#complete #? Get inspired by: #? http://www.opensource.apple.com/source/tcsh/tcsh-64/tcsh/complete.tcsh #? #? AUTHOR #? 14-dec-14 Achim Hoffmann # ------------------------------------------------------------------------------ complete o-saft.pl \ 'C@+@`o-saft.pl --help=commands|awk /^\\+/\{print\ \$1\}`@' \ 'C@-@`o-saft.pl --help=opts |awk /^\\-/\{print\ \$1\}`@' \ # NOTE: Some tcsh's man-pages state that ` (backtick) needs to be esacped in # the substitute part. This seems to be wrong. O-Saft-19.01.19/contrib/usage_examples000066400000000000000000000132361342117255600174450ustar00rootroot00000000000000#!/bin/cat #? NAME #? usage_examples - examples for advanced usage of o-saft.pl #? #? DESCRIPTION #? This file just contains examples and hints for advanced usage of #? o-saft.pl. #? ############################################################################### ### ### Command completion ### # Command and parameter completion exists for following shells: # # shell file to be used # -------+------------------------- # bash bash_completion_o-saft # fish fish_completion_o-saft # tcsh tcsh_completion_o-saft # -------+------------------------- # # These files are located in the contrib/ directory. For installing and using # them, please see the files itself and the shell's manual pages. ############################################################################### ### ### Postprocessing output ### # All output is designed to be easily parsed by postprocessors. For details # please see: o-saft.pl --help=OUTPUT o-saft.pl --help=RESULTS # For converting (postprocessing) the results to other formats, some filter # scripts are provided in the contrib/ directory. The usage i.g. is like: # o-saft.pl ... | contrib/filter-script # for example: o-saft.pl +cipher --header --enabled your.tld | contrib/HTML-table.awk # If you write your own filter script, it's probably best to use o-saft.pl's # --legacy=quick option, which separates label and value by a TAB character. # However, it should be still possible to parse the default format of the # results, which is: # Text of label: TABvalue # Where the : (colon) terminates the label text, which is followed by spaces # to align in columns, followed by a TAB character (aka \t aka 0x09) followed # by the value (the result). # # For practical examples, please see contrib/filter_examples . ############################################################################### ### ### Postprocessing output with colours ### # To colourize the results, the script contrib/bunt.pl (or contrib/bunt.sh) # can be used. It generates ANSI codes for the termnal. Example: o-saft.pl some.tld +check | contrib/bunt.pl # Sometimes colours need to be adapted, i.e. for red-green visual impairments # or when a light background is used. o-saft.pl some.tld +check | contrib/bunt.pl --blind o-saft.pl some.tld +check | contrib/bunt.pl --purple # If the "aha - Ansi HTML Adapter" (from https://github.com/theZiz/aha) is # available, the output can be converted to an HTML page: o-saft.pl some.tld +check | contrib/bunt.pl | aha -w -b -t "some.tld +check" > some.tld_check.html # If "ansi2html" is availabe (sometimes in package colorized-logs), output # can be converted to an HTML page: o-saft.pl some.tld +check | contrib/bunt.pl | ansi2html > some.tld_check.html ############################################################################### ### ### Generating a list with all possible commands ### o-saft.pl --help=cmd # same, but one command per line: o-saft.pl --help=cmd --norc | awk 'BEGIN{i=4}{while (i true O-Saft +info o-saft.pl%site% +info --header truetrue true O-Saft +cipher o-saft.pl%site% +cipher --header --enabled truetrue true O-Saft +check o-saft.pl%site% +check --header --enabled truetrue true O-Saft +vulns o-saft.pl%site% +vulns --header --enabled truetrue true O-Saft GUI o-saft.tcl%site% truefalse true O-Saft-19.01.19/docs/000077500000000000000000000000001342117255600140035ustar00rootroot00000000000000O-Saft-19.01.19/docs/Summit2017-todo.txt000066400000000000000000000136251342117255600173060ustar00rootroot00000000000000 Wishes: * get and use a reliable repository (currently git sucks) ** mandatory features of a reliable repository are: + no delete operation available (except last commit) + commit must be assigne to unique user + commit must have a reliable timestamp (based on epoch) + atomic commit (if more than one commit in push) + search and get/clone based on timestamp, tag ** prefered features + platform idependent client + merge functionality (if files are not locked for editing) + tree views (tags, branches, time-based) * write postprocess for each --legacy= option ** remove --legacy from o-saft.pl ** start with printciphers() * write postprocess for scoring ** remove anything related to scoring from o-saft.pl * Cipher list, see OSaft/_ciphers_osaft.pm ** check settings; sort list, add RFC, include comments (from source) ** after change check printciphers() first ** after change check all loops: foreach (sort keys %ciphers) ... -- problem always: currenlty the cipher suite name is the key in %ciphers which is ambigious for some like DES-CBC.SHA which exist for more than one protocol in future the hex-id is the key to %ciphers, only renamed ones are then a problem (i.e. 0xcc,0x13 etc.) * implement full OCSP checking (URL and response data) * implement getting certificate with all chains * implement full certificate chain checking * implement CCS injection; see _isccs() * check implementation of FALLBACK_SCSV: +scsv and +fallback * implement --proxy* for openssl calls also * implement client-side renegotiation for/with +reneg * change Net::SSLinfo _openssl_x509() from openssl to Net::SSLeay::* * complete implementation of ccs vulnerability * implement BEAST (if possible) * EV certificate checks needs a review (new standard) cabforum.org siehe EV SSL Cert. Guideline (Version 1.4.5 und 1.6.0 Appendix D ) * review check for RFC7525 and complete implementation * complete implementation of reading from files (output from openssl) ** implement some kind of dump, which can be replayed * Net::SSLinfo::do_ssl_open() does not honor --sni when using GET / * improve testing (simple sample script exist) ** build system which stores and compares data ** test must be repeatable, by host, by test-class, by +command ** CI with travis, rudimentary .travis.yml exists ** add knwon SSL-testservers and proper test cases to test-suite, like badssl.com *.tlsfun.de fancyssl.hboeck.de * long term: build own server for testing * o-saft.tcl ** mark search in slide bar ** implement semantic search (nltk, tf-idf) ** make start page more sexy (big buttons are badly identified) * improve --help=any section so that it also will show +commands or --options or sub-sections * reactivate Makefile * implement --alpn and --npn incl. --cipher-*= for openssl ### TODO: -nextprotoneg : openssl sollte für jedes Protokoll aufgerufen werden, ### nicht alle zusammen (siehe Net::SSLinfo.pm) ### Hintergrund: encrypted.google.com nimmt das erste passende Protokoll ### liefert aber keine Liste wenn diese leer ist (siehe man openssl: ### -nextprotoneg protocols ### enable Next Protocol Negotiation TLS extension and provide a list ### of comma-separated protocol names that the client should advertise ### support for. The list should contain most wanted protocols first. ### Protocol names are printable ASCII strings, for example "http/1.1" ### or "spdy/3". Empty list of protocols is treated specially and will ### cause the client to advertise support for the TLS extension but ### disconnect just after reciving ServerHello with a list of server ### supported protocols. * internal cleanup: do commands in .o-saft.pl still match those in o-saft.pl itself? info, check, quick, ... --norc * +cipher with sockets is implemented in o-saft.pl, while +cipher with openssl is implemented in Net::SSLinfo.pm * rething concept for Net::SSLinfo::do_openssl() should not silently add option (-CApath -alpn etc.) * test with local installed modules (Net::SSLeay, IO::Socket::SSL) ** write proper documentation * setup wiki or alike for internal documentation of concept and code * do we need translations? Note: all used text defaults must be inside the code, prefered language english; an english "text" setting page may then be generated = some unsorted = * -nextprotoneg may return: Next protocol: (1) spdy/3 Next protocol: (2) gibts nicht * +hasslpn vs. +alpns vs. +alpn (same for npn) * strange syntax for --cipheralpn= --ciphernpn= --cipheralpn=, and --cipheralpn=,, is a general problem with option parsing which ignores options with empty values: --opt= needs a fix like: if ($arg =~ m/^--.*=$/) .... * implement check in printciphers_dh() * filter and check ext_authority_* for TR* * internal: --sni : check what value 0 does * add option to use installed and passed openssl --openssl=/path... * pass "s_client" as variable to _useopenssl() so that we can add more options like -starttls -proxy* * +rfc7525 cannot use get_dh_paramter() because check requires ciphers, but get_dh_paramter() only uses openssl, not Net::SSLeay * check implementation of _hint() and osaft::printhint() * special --traceconnect which shows commands (socket or openssl) to connect to target, no other trace output * replace huge if-switch for argument parsing by a proper table with all options and commands (table needs to contain a regex for each option/command, the cfg-value to set, and ..??.. * cfg{openssl} structure also in Net::SSLinfo then move all related _check_* and _*enable_* functions to Net::SSLinfo BUT: at least ALPN, NPN and Curves checks are also necessary for "+cipher --force-openssl" which does not need Net::SSLinfo === Epilog === Content herein becomes TODO for O-Saft after OWASP Summit 2017 O-Saft-19.01.19/docs/concepts.txt000066400000000000000000000273211342117255600163670ustar00rootroot00000000000000 ############################################################################### ## ## ## This file/text is still a draft (Januar 2017). ## ## It describes the main concepts used for programming O-Saft ## ## ## ############################################################################### === Concepts === The purpose of this tool is to do the work, not to tell the user what to do to get the tool working! The purpose of ''O-Saft'' is to do the work, not to force the user to learn a new tool or to install "newer" software first. It follows the perl principle "Perl is a language for getting your job done." O-Saft has many features that ease the task of the users at the expense of greater complexity in some parts of the code (for example the parser for command line options and arguments). The design of O-Saft's commands and options is very much influenced by linguistic principles. For examples, most options can be abrevated in various ways. Also, common things should be short and easy to remember, aka "concise and natural for humans". In the documentation important information should come first, details will follow. include Huffman coding (common constructions should be short), good end-weighting (the important information should come first), and a large collection of language primitives. It's often a matter of opinion and taste how something should be done, for example command line arguments. So we try to allow all options and arguments a user might be used to (i.e. from other tools). It'also often a matter of opinion and taste how results should be presented. O-Saft strictly follows the rule: one check result in one line of output. It should be very easy to postprocess output. Think the UNIX pipe model. Results (checks) are marked "yes" or "no". It leaves the interpretation, if the result is "good" or "bad", to the user. This tool should run on older systems too. Background: Most tools rely on the newest frameworks, libraries, modules and other gimmicks just to make work easy for programmers. These programmers forget, that productive systems are still most often one year or more behind the newest releases. In practice users of these tools are then forced to upgrade parts of the system or can't use the tool. Why? A program should do what the user wants and not the other way around, where the user does what the program wants. Hence O-Saft tries hard to run on ancient systems too. It may not have all features then, but it should work. In such cases, **WARNING messages are printed. These warnings cannot be switched off the usual way with --no-warning. just to keep you -the user- informed, that not everything is possible. --> Drawbacks, traps: O-Saft complains about unkwown commands (+cmd), but not about unknown options. This means that unknown options are silently ignored, a misspelled option is unknown. If unknown option are used with parameters, like -legacy=compact then the parameter (compact here) is treated as hostname. (may change in future) --> HACKER's INFO Because of our goal to support running on old systems too (see CONCEPTS), parts of the code make ugly checks for version numbers and try to do checks in a cumbersome way. Keep in mind: the code knows how to do the work, the user most likely does not know. === Programming === O-Saft's code favours language constructs that are easy to read for humans, even they are unusual for other programming languages (like postfix conditions). The purpose of O-Saft is to make users' life simpler, not the programmers'. We try hard to fullfil this goal. Programming is often done in a very defensive way, means that any kind of error (and exception if any) will be catched and displayed to the user. Unfortnately not all errors can be foreseen, hence a "silent" catch is used sometimes, which disacrds any error message (mainly used in the GUI o-saft.tcl). There are often situations where the underlaying system misses tools, is improper configured or simply behaves strange. If such conditions are identified, a proper **WARNING or !!Hint will be printed. This may disturb or bore the user, but we don't hide what we detect, which might be suspiscious somehow. This is a tool to check security accurate, not to give a "good feeling". == Programming: Cipher == There are to modes (technically spoken) to detect the ciphers supported by the server: +cipher - using perl's IO::Socket:SSL module (mainly based on openssl) +cipherall - private implementation without using other perl modules == Programming: +cipher == To get the ciphers supported by the server, a basic connection is made using IO::Socket:SSL->new(). This connection does not check the server's certificate as it is not important for the cipher. It also uses SNI by default (unless disabled with --no-sni), because most modern servers expect TLS instead of SSL protocols and may fail with "handshake error" (see man IO::Socket:SSL) if the server expects SNI but is not set. Most likely IO::Socket:SSL->new() uses CTX_tlsv1_2_new() (from under- laying libssl), which has proper fallbacks to older protocols (like TLSv1 or even SSLv3). == Programming: +cipherall == In this mode, all checks to get the server's cipher is done using core perl without additional modules. == Programming: +info == All other commands, beside +cipher and +cipherall, use Net::SSLeay to connect to the server. However, Net::SSLeay uses IO::Socket:SSL underneath. In this case, the connection must succeed. We encounter the same problems as described for +cipher, in particular the server expects modern protocols (TLS instead of SSL) and SNI. Hence we try to connect using the most modern protocol first (which is CTX_tlsv1_2_new() and TLSv1_2_method() in 2017). If the connection fails, the next method is used, until the connection is established or failed at all. This logic is implemented in Net::SSLinfo's do_ssl_open(). === Results === The purpose of this tool is to do the work, not to tell the user what to do! Results (checks) are marked "yes" or "no". It leaves the interpretation, if the result is "good" or "bad", to the user. However, for the reults of the checks, it is not always possible to rate the result as "good" or "bad" or "insecure" or whatever. Hence O-Saft can not give "the best" recomendation, or a "proper" recomendation. In practice it depends on the context what a recomendation, or countermesure should be. Hence, most results are marked "yes" if considered good, and "no" if considered "questionable" or "not good" (i.e. according other checks). == Results: Status Code == Wha does O-Saft not support a --fail option? Long answer: As said before, the functionality is implemented now, 'cause I see the practical use-case. However, it's experimental for now (means option and functionality may change slightly in near furure), please check when new versions are used. Clone from github, and everything should work as requested. Background: one of O-Saft's concepts is to "show important information" and to inform about the performed checks based on these informations. The check results are basically "yes" or "no". It leaves the interpretation, if the result is "good" or "bad", to the user. This means that all reported results are unbiased. Said this, it's obvious that o-saft.pl cannot return any other status beside the printed results (which *are* the status). The idea is, that postprocessors should be used to use the results for scoring or alike. This is another concept, and o-saft.pl is prepared for the ease use of prostprocessors. As it is common sense that a status code other then 0 indicates that something is wrong, such a status code would violate this concept as it is biased. A status code other than 0 would also make using o-saft.pl in a pipe much more difficult. Now, I see the practical use in a pipe or process chain, which simplifies the handling of the results, sometimes. So, the requirement makes sense, but throws a couple of questions to be answered. The requirement, as descibed in this issue, is to return a status code other than 0, if any check reports "no". Could be done (is done 11oct2016:), but is not the complete truth. What about the other checks * like the sizes? * the DNS checks? * are medium ciphers subject for fail? * What about incomplete checks because the server did not return proper data (i.e. DH parameters)? * What about failed checks, which could be considered unimportant in the tested environment (i.e. some STS or compliance checks)? These are the same questions as for scoring the results (like other tools do). It's a matter of personal opinion and/or the attributes of the tested enviroinment, if "something" should be considered "good" or "bad". However, if a user is aware of such problems, she can configure O-Saft to do only the relevant checks. Other tools cannot do this, and hence score everything, wether important, usefull, practical, ... or not. Please see next comment for a practical example. How to deal with these questions? I.g. the "--fail" functionality needs to be configurable by the user. Best example why this is necessary, is the +cipher command. Is any supported cipher other than HIGH subject for fail? Should MEDIUM ciphers not fail? Or ask your marketing people what they think about disabling DES-CBC3-SHA (which is weak now), just to pass the test? My opinion is, that a configurable --fail in conjunction with the existing configuration of the checks to be performed, can do the trick. Conclusion: there is no -and will not be- a general --fail option. Instead, we provide some options if various kinds of checks should be subject for an exit code. With this concepts, it's up to the user to configure O-Saft to return a proper exit code. This should not be difficult for experianced users with special requirements ;-) For now, --exitcode just counting the "no" checks is the starting points. Here we go, this desciption is subject for discussion. Please provide you opinions. == Examples for --exitcode == Here is a practical example why a general "--fail" would not return the expected results. Using `o-saft.pl mysite.org --exitcode +vulns` would return results like shown in the very first comment above. Looking at these results, we see 6 "no" checks: BEAST, BREACH, DROWN, Lucky13, Sweet32 and SSLv2. My opinion is -please correct me if wrong- that only 2 checks should count for the exit code: Lucky13 and Sweet32. Currently, having the concepts (see previous comment) in mind, the solution to filter the improper checks would be to use prostprocessor: o-saft.pl mysite.org --exitcode +vulns \ |grep -v '(<<'|egrep -q 'no( |$)' || echo fail o-saft.pl could be configured to do the proper tests only. There are at least 3 ways to do it: 1. using proper commands only: o-saft.pl mysite.org --exitcode +crime +freak +heartbleed +logjam +lucky13 \ +poodle +rc4 +sloth +sweet32 +time +hassslv3 +pfs_cipher +session_random 2. using .o-saft.pl (the traditional way): cat > .o-saft.pl < .o-saft.pl <> stream x-;n%Sп؀4ʭNP-틃t ER1#>W9ὦ rP I!C^xm+z__ߏ_?C; Y[ǿ?P[kJg~__ 1RO~HW{ܾ[K޾+_o)ǃ!ﷆ ?T0}R{}Q xTG=OK͡(\9[4*qD SY702Nsv{ %jIFS}{@}RjRUSWRZ,VyޏM[N :1Wx(~ʪ~b^~wTܟ?Z2Ըۊ즊[5<j4Sk*Nz.BWۣoT:9V^M\6T3 }3s+mV[=EQI¥w!@wSu*LȜ:n˰%PZJc{ߒx1t@DxB}73BZ;WB(oM٠3PzI_ZQsD"(Ō7xVhk BU95l8Tjrz(%tH֘Z )jg+wI ?FfTCijM3mN0F ,HJ%Uk?VBCÀ\)fBi'}S 1 Zb&ېw; j;ԂvdG!T[|X ,2 7AXTR[nPkJSkU-$ډmSIV['#gjjzɼ0KO%{q?Ph"la8l~ڭ {AQ?@fl 2JykЎIQ}TzI_Dy7Giv ރTRQxyB_Vdtt/zʗXEPPf"J}卜Vm^Z&%:Z1:lbܺ(VrZ,znb ETow'CQBk143Qz[A J5C1`"J~ V13Qz[#  J1C1F@Iگ3(&`7(1YJww5OCr@yk2o?u;4ғt-gP̘юG*~ƣǟ?G;uz4fr\tź7PRjM7rgp̚'My~խ̱IngnTm2rZ 6УvdT[#'JMvfj?Vݍxku+wDDyk2YJS/=K(pCr7Jm>To53r'(E*Jَ:*M/]SҠd; {J}ۍAΎIxMs~2ݓ G;fI/]Ԃ]X]+mBI6pPNCI4ŌC:Ҁ3 Ӷat+wҀذE 6nu #w3?Dl4؏3x ;,Ć2R TfX &HAmT6ڸ;dv[* ldG2vG-2 < FJ6TWʝ@PLM6āj-U%؝h0G j]!((p'*JFzH/(9T4(6AXlO%JU)6葊z4r' *F>RT[# G6[7ʝhPl$U3V>@vbA`AQl%] - 4UaҖC%z&zIFAPRnNߐm$uAio(4(6 vߪFA̱uil$6 ]΢ ®KEM[6 Ժg qrl$o6 ju, ;Nˉ24b/D/+vZy*-s#XK8-%HH C`#!VZbH1CcjwʝqiPl(]S3QRY(dq(Br!/N,46zʙz`u(ɼdc!(M)߇Zla7; ja(y08JSox+(}o:+zy|pGwi˘:eUth}HaJpH`є F*" q VU?0S }c7FqdPy.!5F2dDb8uJVVZ0΄''[%.04—U21 +9H2y#GgsWhV2L|Ed+Iex!; z\=٪lߚִc-ghBZjtBYGFkfdNjhq*Lüõ K-64RR8V:ȿ@`IrRu!L^FeC%I-jԑ˴:m]*  kE0$Exelԑt KeV9ȿ̔6R3X`*sK8WM:I&*,ER;@D|D% I1{@M p4Ui2%Ke\-Y, T;l0Y4IO4K X[ K{D05UlLR3\R8#sb:ҤvVJ4)+;,B8#&E[R9UM67rOhRe!`D = !H(U*uBbZR8M:Eq@5b)uB:ФhҰL%9 ]c*h/ R{V";`YbMҎs"Z{V©:$U3.SzW"udGN) ?Mz>MeW ւS|Oܐ|Rr+ށBκ8~F62bV1bf Pk7DGi{xЋlAvkB)1- \” !\= *=Gn>啩1RL<+uϿJF x6+FXfQ#uϿJvH&pXp iNQ +T V9KbX&}Y~JH?EaRq~\x{VBj8gh g`%Zх(Pק3)tvlUeRXq/ҙsJp>Ɍs:d.3HrdS5=Dj%C;Rܫ\jN\2R|`U^DPXŖDp$dݳrAO8UȚco^~}e1uJݳT@=jA ֐pؐYlƖ[}(u`ab*P 0{"g)jQȍ ۈ Fx4+rB@=ŎUlA>mV2Nc9RWåiDm|:Z@Q}ERwypx- |v 2g_єVKc[PJ/a-$,D:+B߷Q  z,S5S3obw鉂sqrxWzX3ԝ)J=]ZFvz,ƈq"Z#FfVCthʮW*&ց1>c KouWFT3+{seUYL`ՀkmLcī!t8:40wkKVNA=zb>HePqfywoF tl(jg }aJ&){8*:%:an W^gBPÌhЮ 8hF>YwY򰝣_v{d>amӆ;:|_-0:`P"72}+85̂acxETZXڒ3@C ׇP*шse+b"tp=)b e2PYCDanUbc ϤvDk%bӠ*ur!cR$M;bϷsi:aH<,dfMPiY'L{U;Ьigx4YJ^"%<,ZBtF*%s(ҠJĆ^jhڅ jJf0U5i+zŢ ,o b=MA-6TaKIO@+uf,9G4͆⦖d  fg "6#NR 뭖߄ E('DQ0 cbM3A4֚KMܡ (P bdi\T{6mڠvD}wy{.} A fEf.z)SꞋE"t@4 J2mP8bS"HjpwkA}vOi-&;utE2D 32qI DIc<_6A Q o>dF fdNGܫU(fGjfyMHx"s]nBΙS h6i-VЪ!af  c@}*uϺn!JCLg+OduXW7iJ"o $H\'g\ N2!.51U t&YO4R̫B$_(}CQMK\̵{[Y@q(VqD{56;nˉ^ F9hhWxy:0vfX`x /ja_ZAcqtR vx_*wϾzeonA wp)qJݳJ l9uң,rVk%rR&ߚ:9\jWQL#wz(;~Maj0UUSmPCgȪFdaa^ppGl@XHݳZFcam9S- SYXCoe?@2 oTUV>T9Q4MDªԦ83~j35zaXFêPz)c+crRCi k8Ο__5FT_?ӿ_6ˍ(UUf'oǿo?~¯-ү5_6~~y2k+)3,{Rzc%wP]d}- *|! Ax1W(= +&Ssь\yᅕl57YjWfX3it YmUYdcpp% P-@O ? MZ`uSإH :w X8b\ `Q -@+AQv6;ja~`u;xno? kbXC!v v SF,DAtځO!< Yd+`{T ,@PU:v [jynypEKu*ٱ6;jI_@9PI75'} p5bE+MY40 *Jv(٢I_BY.H90ȟ0kvsim}9&т$b:?K+5ɁTRHr @v;@'|rC>E;AyQbt(š'}pY"T7xҗP  }r> ZXng7 |:/a!aݰng7鰿 }q㾸qݸϧ  ~q X(n7ōr:b_/n7ȿ ~uC_/gC~uC_ЯgC~uC_ЯgC~sC_ЯgC> ~sC +Yhn77 v6Hd O~wCΆ,t7 ~?W$2 ~wC +Ynw7ݍ~6d O=)=uZ9I~ණ*7w7w7}A$  ^7}qHv vl󓾴\^eJs(١+fP|+sBY[/T C!`}V!9fL':P-Ba:CAHFe1:jtOҊpqb,th:k,\Q)5)8bLge/RLt`UC`% pf8'7p>bf09ќhΧ. lrvC9sXn$3ٍ|:ωb1\@.f g7@>'q1㸘q\8.&Ōbqq㸜 X,n W3 r:/b#oE0#\H#*`r:PgC*Xn,׳|AC~0cXngc, fssù +.S݌nss㹝+pǹf@77ـ"5E0#݈g#$6[3ݍ~6/(b#Ỳ̀n@}E]D`n~6aqwz7z:݀O1l\ iMN7}A KAOB K[r 439}E @׭=% ɉ%9PvBY(aH(աTRpdw ŁO %l$5(D((MݡO( )lĵ(šnݓ_QC%;|rA e ((M͡(/CJis!dFVJs(ɡ.G$RU,W(.]RQNP—"H| q%jt1Ɖ玧eq~upꊜ Ok ?oospCధԍI{QڣL,#sϟRI:C3cf4LZhF?+k\ihH{TDEvJS<Ϛ=:-!64 P ScØA*-h(HΆfἋuZpǖ*&N~QQ Хa*22lWtJ4씹eK pa逊jJ3F-c=U,cI5 -3^َv!2 zýpv1PO&'[ *VXFQWl+Hr==h}CHQ m֖[nT*޹K3Ҁf W'9Тvp.򹛡TFIJsv&h&z7P;_H{d:ȉe4h 2 t}qKPWw 7j&* ݓ62:k{ TJ܂4u$MW@#uO RFT4KS = @Hy^G.>0^U?VQadqMn$下h#BD@FB8Dc-iSߌJK5F,hcMjԫ>ǘ,1}v^HNh-IZk?"N'&5hZ gLV4*uKuZ 9-ňƖ[jSb!|h&NaL 7PP_N2(-Ncʪd4u" U֜Xot@HS!q40FN'U: (Ҟ!V{g֘C⭕攤ԧ2V4T:{I|aRA43U,N𧰑OG(k].QQΩ\q!7zӣ*wj9%VTJP*W 8М4'n(7=:Á$5F*_i)!Xti) ;NwHcA/hh9bNRo|}h̄r.N 6X@J ;ڊ1)Ӂ@?oT̺T\rF@{D jX"YV+"h.I/J\/ƚ#J~RoYBkI._rbw(nX Չge҈4XdwY{ԎvB-Sᡣr9^ީ(187 cm,-?Ƣw*0'ϑ5(?J*1)ϒ67I{ ՏF>KVڤ杩Dh/ UxF%hq:䄶"4g-* E,2R)4,M 5̹KY,}FgPUFh/En&V* UF*rAH&/T"'4(yq4-VeQaVr q mĈFP %wEPvI , w ;S5-8Ah#%άבEh%ng+nJT$$SșvG" ̨VLCGJ0nHX䰜RP# "/tUr*sϏ:9K8%N;D+$5n]hs0&Z+[*:CpR㳈-4R8u S#wЦFdp3%@ĬTB(INPTkv;0EsN#g~_:b4*\n5#Lѷ%F M%9TmcG; 38liFЙrJgy#'Dɠ98TapxqTm0iprhNFHWq<>V\/Vr}|@3i'#,2%cFc Z{qkhr W&6[~gZEb`_<]%d ݓF}&F)D[ҽBň,p>ag[Epv"|;(nhR{ǰH+z.Έ94#sǷ+1q4QdIO Ggqr"NFB(K :Vy!4'2]s1e^E;K ΑG8h uBEelw#H}(rUYR.'ʗ?"<#uBű  z یT{ ^#rV}]b0[93O f4RO7ŧ#.tr]fUy]'R#%Cz_z'Uu5fKihzSgyr!m."{Ĕ&|TKfuRHnBO:nuT;wԂXTWl1c=H7HGHdߊ8Ȟe^*5g]ʒ"GNk'ALhYWt?]~k%dDfy*R$ę8dE(s8EOUsq( ޒV盜ӆH "|Y{Xu+a!amB<'Mcԓ_)baLEDz+!Ȓ ܴx2}ZeIEoN`\q+ YxV5r.[ࣞ%h7L=ߊY3QƬyTWnzԧ{εb\TVKrhԗˋzgd2Sb d'\6 -t~V:+¡"tJݳZJ>7O 㚲5r/9˖p0 SdVyT[|>W,J=[u9&N@Qh\t:zb|&(y4$Y$OU* 9'9g[veY80YlzD6>FXBTN0VN%Ͳ8% }+"VH4RWtK/*D$|$Z\u :%V{f==Rމ`IV}/+w)+f>y܅aBU{վ@C (s r6O/%z`g )N0W~VHZ8Wn*)6DFTe*"K7\NfǗy*JiUU,BCL/'pV_'&7\~ -3qt`b׸ZbeO#w˽J|, sRiq$py.T6Ty8nN,$ *;UyW"f`3SJZl, lx 5̫7(ב:_3kN(K **Q(,=U6+y dz 䥚NO4%-p0:y>\Z{Ε I̲6D`E\%@@Az8̢TWcmESnT4fezuh7F3.@qV@nYWV]P: gj`wBZ3R3 0nmJđwY{U|62T}z&X̺Tp22+QS\Rz~]&5=&52Oܙ\‰8~B1i*5rGb́oU [N#I+|N)Ӆ/+ RTƥpJؼT864W* ]hW*i1 3QHT C2*\N#&5rxWdjEJo(&GYđv[œC# ?+\s@/LU۪RW%/ű0[YVRnTߨ ",OMʩFݤlwjԅ*|9mLBZ:4rRNdE.QY)r&,PUʰ~K ;Np|m4p .-7Д>I ny&dV%u7&V4/Z2,t R0(7d;E0FSbsmѳn.pC ]ݰ=' ARwa: Qq#ƍRQ6Qad^pB+7)M XS yiH@/\F[#X*qI$a Z #MU oX06;8TzgPS$x*u˻wV9`KD IXNdg)s ܕ+Ĭ!&Hݧ x$HI$ ٸvF̊R.V!VdAjY"T2;b7qr˶u3>DIJܰs)2bPD#o5/?#̝T!#N&T{3*Ӟf-pgnmc[$R#)VD&^P<#uZ/=PKAO6jb1"u…Z/};{Mpp=M;U@p rv4z%5F MnV!V(*]H*rn%j9z85ee/j0ncg3\eZ 82x$NUaH#w`5>piߊ v8~/(ޔz i ]p{ʹ3b1*wϵ .;V՜7 DAR' 5UR1뻨hp/FF QÚ]Bp¤yv=poSnijhͬ?@mZAT٭'N3(T.)=pD1;|+j ʜei- ҅KQ5 gJYfapR>ɓHLDq:-Rx] kZH|I8ByAT\֍V Y s*w w%1c!%GJ42V `J[Gڒa)1$U一d엥r;Rnh`_a)4nq$0hHd`΋=q{Q+D=[񍥒~fsN6TR^f=E8V0&L[Bv"&7 O6 ȝVUM\5778ޕ1f1*wϹTI2ˍ{PgS *r@rL=P``T 8vqr#Bf*IUuF쫒ap[Q S%LD{ƻʬ$j`1g>gF=]\ƌ8c-#i02i&HSWq{UFQ0"o6TId,nkZi$-7쫴ITr08H ugbU}ET&N@ @Dː+<Ԧ!7DZfD jL؋ &Jݳ(W^ cR']ǒ~7ΊLH]R`ҹhX5y R T ,# L9{yJˤ1+$4#=$rcuRW8[9U!=' hn3_1۴r (~33Uꞃ6*}J H k4rXXzJ[ %rXXށssIvW*CMhٔ" k0:bCO^"J 8ƽKqV"@"u3̝pwfN"lF~m #|Mޙiˆ &reU9YSF;2bD#+sʠr3Go6{B6抠*k8SũMLgbVeEĹbX3=qiJQk\Ɖ`1*wFz*_Ug>Ua([.{ahT꞉7q5U4yOqxF枉C`T^ာ𤂰J3_eN*3aΤ ݳqT5)XZsQ)tA4UҚ]k%RLkA*]=[y/SCZe冇qlj*7y.l΀=+#HEP5 7ʈ] +qLʍ^2#ƉR| ך^Tn+`xFꞍƵM[r]0U3+u[)Em F=W,OXl]E|Tt6+gd6Q^Nph|?o#{=rۏ1~_?孰~~Ϳl˖~ 歌Bo!m?ۏg D?=AS ; ?_/o>L3#l΂q j ׁ$[Mȧ@]-Sևo0Z8!!L8qG/iobZ95Rew0mwOoc'/'?Z+~s\gD9E~DЛ?$gEXyH~L.=g)Yk( PM3{JHl)5wo4젷ra Zm,{672?ת2-hyD5_eDeZ*@֞;| 7XUt=0x KǮRf C+oߙuix21N\݌#_H#?!쑸BΧ'De 9r_Fk-(C nv$WrEt.\yG5Bai6Y2矶Ƌ1华O[_]G'k>3q܆k?\_[eO&z.1>[He OAn([ )]#bJbmy>\9DJi#_~%ΊoHSxENHYgGIJ1Or@FZFa&BHYB)H$O rAIB#̰W(s,ηP>p`Xh h#UוqS}qSt~9opTL4_]%ߝ~zҗw^ X6Ի;z+u2QCIOr+&RJq(ɡ(,^1Ood[JJas}>֢`nп ՟~7/gL[i__gͩwm/xVB;7/VQfӋKSow(pDk=(ɡ؁OrL+6Q(Fgt*s}L 4eAh \D :a=56!7{BXg9dtStȈ4y\zCQSV0@>^WGr;@@CZX H,Ht㍯rVrxҗ.@Z9FbG@'P+`8AqOr\+F|xҗ.P#[dP'V"%:7/(Ƕ2.(f4F?,Ƕr_ŠT +VNաt! VƝ7({] e9~{Da,=TH9@ CXWk1֗W]o-Fuп,H{wݐ^lr97R{կ2_,qw3rsVQ˾'Hv n\t RexҗA\YH'Hw nI_YsnL)%=U6N|X2,Qo+U!.ܑ|  ZjQ@Xo<,_?Uf-Ti%C*UBPCC+֐(šJ:A:9PC)PR@TH*Q_\zwGrpɏ$` *fF! WM397 /(ǸpݜTHCe&u#,HrOrkh(ɡA'}e=U8!+8Wbť8e=҅a;7 /],Gf`Qxҗ#]H(ɡQ'}e=ԅR99 e9օgҌKSoq(r w(@0̖bv[,Jq0e*%8P0,bw!MXjPEi RJ2GJiR,bx!3DT7PepוtƳt*}{(VBt*;5 In8Rx\fJuc{U0>1TP(#DžifZJHAqFBGnrλ#P_({⢓gЋy&`J=bSD#Å|_H|_gI]nG W3{᪒O1!/7ˆAWZVa: #k%A3G7D"3w.#y LwoOD#u뢏 >΍L19 3msqd !.Tn5.QW8#w$ے/Ɋ#P)gsq6A=IHj߂:@{6W|Nk9Yߨ;z64rl.x2&16ck_rMR@#$MUg:R(z̯/oJdL(++".+a6Dʸ3wsWg?CoD32.pkInL7oWH.|t}ց^r9xp.p"3ROYpᆑ 8)<`#',8pHƵkׯ̭ ##E`," ˼ELoLE4R'+Gq;F2w}gĨF l{7~-)xԂ3lWz ,ҏw㖩e pbu3rGӁȄJ%Wxʖ&z֒3S¨X)aH3 Zl-xpH.c*d8)/yBZl̶S.>+^6"XO"WF m 'yʤ'ƲR G\*j%=1\T8#w %U2Oe iNN+gRblѫF2U 8p:]q@iFr Dp- o0H=alEGڃ.xQVfwfR e)(|omD4'l:AJ/F(7nmCU^r72.xJ3v4rZ19T0n[ W:k N_*s}d^U03@5l[qiS4#exWTe]sw~S#*›.nȃ,;Vƭn4wnPF*{Mg @v*\"5.c^e5Sp]v8pVU.+ i#/G}A3R+$cM_ئR5V\<m"*Er^886Fc^yOmiF5a7;AYW .j|a k(gdg ^88'Ö(^ Dt9ViΈJ2r{]g kma>=*󊡳7}3@Ė}SD#uϼZkXN@ < kiͥ[!6#VɯF6\52fF)->rrDgMUb2 xV5V;0u{S#/#uϿ(S 쇧I_r.L QdWC)rD!&f3YzS qO(D AB1RW,2y3Q:Ёݲp<2(b8;XXX<9&]5fd! ;rƁg#wB.2iLX+Slg<:}"_uk98@ Dw^ω= kZ"Ƕq|BFDH*ZW Ɗ(1r<ΦCoښrW#el3K( ^66-^9FKN#a3x#uZW:ҙF%#\NQ!É^ei䵝=] fyc-ըD mXB2'X9W;}n"'BT{FUwy&+G9e"&ER*/J9vp'2 uu9U#N>C7,.="a*χOcݬ/UQqK>=)D^Y:*wϨR%gƂ'dr&{" MTy|8f} ܸ'~ cur*,GH,24RGW5V 8Āib8dm1):lVnUwL$P Se\o-j| wV)@L![evsɩrܪ6^BI Jy-1y9* F-5d}SnyU(,' nNqڅJݲpV8JiBէ;xfArkd,[KO#uB|ZUك.ʙ΋}@FT{vPd*' ',q\x}&\xg Pp#SpqODB +)NHhȫ̫,zcF_GݐuLD>5rV v|FU"Pq{ +E=XhSߣUʝ~B:b͑YȺLѬpԘ+,[UQYX6/r_G"}! dHڄӠ~kr©$i X>иRKr5uR4Mp5&cK =㉡RO$qeQ{c*f䎤C|݅[x3f*wOJ>+X/q,"'`&G2sL ]lat =K&DT{B._3OTX%N,i-+p?ɽw(qW9,791Dd.r2Y|@eZDKӎ["{*9'N<:Yd%jxэCܑ T.W g3#r'(+oKnunJML{@肅K[7`J`.a!g=v/&qr.ޙ QVj*O>Ipew.MC]lZa"nrަIjT9n H ly4AT5mb+}%K7h#ye\Z2y,ps}D͖\ 6F,J= zVKY`gz`_! l9V8=Z~%iI{@ݖdظpL:$உDijU+$:0qjevei MƤǰARrW!4/V5YEXWH=y( X^#ROH^*I^(4O:g]*YOPCņ{**@LHHiҎ"43- GBEjvS@1UçئLٴse֓$/ X ӹv~4ƀRdT5z-Sxk UI-غ0+[. kel\Z/\uԉ (k5ujHgd\۩f۰/aLmX:=|BN[-' rDis l̤˜`=-d [_5J5x ֊]w{2&L0UVBM g\ؾLHrU`ZySMO m'Vle+hޒUn8t5>nE Tnrޖ1{{r$[,$56SkykV]gW%4txg^~3r$ʛ,Z+oͨxcVNK$RµEѭc6ad???.7[o#JsqY_/ϿX%e_/[5[C_~lO_b^XF6OHh!/鏁nk>m~|7P<*?ކNӻ4 1{`%_,۷x91ޅi0a4IQK62eɈzd edFc8NCޥgx11gbEWJ`:v }-]cöN/j@p-Zש~x @SjhNg]KKc]q^y[W,`aiE-V!uj'k-Jw(k ea[阣u-ցk-AJ>}-]ceöNZ\p@S?{,`k9Pp_ewkj\:Ԭ^,<`k=PCINo_KŚUũ_ko7 lMJs(Mk sԖ\,uqmkee[끒o}-]Wn]6JšX?-7ZPӛzfe;-k eTw퇥Z@9\kJr(\\{5ؙ-wܻ|ΜeWWn^}p _\{qiAWn^|\h_K [t/>]zyίݢ{ѽMvdw S[[Hr=-9$9@Zak;@ u"[JszZ@Y9zewzZBYxz>/m҂r$%9FZBKU{ٽW,+65(ݡt7 O$+bkQҲ#b[ 쫸dtQQ#;l{9ؚ l*y.ntҝڼ@N5~؊jJmrx]zba֩E-VF\:9̮8rtҝ޼+NrtֵZJ}Z'V%sŰZ,Lbk6t0b[ÁJwzZBYb1^6w]ll0q)9"g|wmMjRcvf_(r6T9rqi -.o'u.L.cISPCugrNʱ^uъܑ)讍$)2EC+9*wPŎ5bh%FP @n>*v+O滂XĬ=?+qQ: 5!5āU&%J6%{܋/` Ɓh[HPvSR',̽MΜbr? zܙaZf.%үQ<-֪9F12hMQ F)-Ɣ;aZrglP(VԙDdi 3QJ 8TgL0ͽ8{҂F?CMIdgk&^n*hOYE?\CȦ$R''ܬZɦèr' ~Vr(h+L;(ݡK#? Ee7U=uh`OڹJF-wX0mi~Vd5tU0)3~Vv(0 VRVn+u_UdO_R#^VpwLpմL1uey%e2/QNY#;aSf}r`T!tR+SGlPX0%Ve|)Fd6\;$.~r )$9O8abe-O:|.@NX~/Kpy˃4bkejJ lԔG,oBDUV{ , D6foT{%U5}Ȼ2_ ȹ@hD"sJw(nA/Q8Wՠ@22F1^ΏW;(:P)|RjYB]8򭒃h~R-{ƷӁ;@ROV ~!"p7ud5۪8vPJpz>Ye 7b4 _c*eX)7AT>=cY%9NzKI_Vj=P.1z.\cyVl{ef1ITu¶B#~Ũ'\n1_ Js(ɡ5JlWbP5Z5nY,漝߈`t1q7 PARґo%n3DZʏVCI TNeoչ;K(aN+(͔Tr\uP :meݡ#5jZ?PEZ߱`RڈA ߊOӱ~|qm m V?]; aJv]Dmyz2$3.xWFOZ. `ΐ+pԂ9C{e4N!}qϼ2Zt,xޒ[ޕ9]ּbLאy;n9WStVϏBZs +Kj LJ J 5KBم c\zD#z5 Gz\-֞,+Y8x'/G&?ljfu~)m0`Z cadmC4-#pmY]E-I;nSgܶ&8:SfPs PZ嚾kJ(7樐&pm\sAJ1(aƁµ9e`W11zиk>&pEkSiĕ/+W7m]2( L.P4`]~Gt\ zBY/z]H\5i2Z #+:G&\?qMJ\ \)x6èڝ*uʫ ]_hgTp0xp.5\z }kV`CPChJPOT!8 +IjP25Ͱw#8#s |"T+%qCw_Ry(rզn"֤[$ڏĭjtv^]k_w 6lVNGs4L: '݁d9ą tq m5~{i‘)rZffCs[@d (28Pڗ|H^k.([_[LJZ⊴% nJU| :dyG):9vV4n!tǪ4 V ľ [;2caL5tZt} &;PK,4(LhslAlPaZIt^K8L\mB8"ʝF1rɀ`T_)-ykFct-Z{ǩ%\y qʁ J6(a^+u MA;RVk!\`<.`X[0O1jʱ/ 3T])Si|q (I,^$ލ $En|>^GVFe#*Sވ{zɵ}3;Kz2O~=NҎͤREZVjhkfKt0Rӟ_U '(gS-yEj5WI$T߉^5Sȝ`ogDOK X(Nk61f:i%95b?x V~wߝ $H!mRA=k*D7k"J;}(*IN ܾI}0RknH}@JUBЅJr T9IaԩURAdf%=]$$rPFךa4fߒ݄ۊW!V!4dr:PI/ak({UxX @ͥ_Y-+e ex?*ڤq |ʘZ&qK~ϰMf1]3T$*?`N5y+*Q>3TL<+uN1jN/yj4)mسۗd# r3l'-).񪱞<+#r~ ?b5Jo_rEȝ^کԭz~Q?bZ9EW_2ɬ4O$y9^ux 9`vjVfvB0]́^t;v$7-'SG|wIR&ʜ'IW26͕M4~0?mY9n%P;! o%F}0*+Cn$/QH0|rwA!B(YܡY=O>|]I4+6!%7ݣa"K!Rb؛:T.3%#O5ڝ*whWe+̷wg(xPJM][Ҥ7J_=ίd3*wDaCɬۻǯ+cɩM}QN0h@ɗq4^Vb-Fst߸\ڃknC']$4,+G^F|d7{2n؞+}K@Q2=}'2fe1i?4`?{PrZpHjX*w7m{2'WV0l5pj<- 9>˻k*qN!%.Z0J]Іk3ab a" |:qi:Jۼ6\;p2RZ` J];oʜ`^L%{t[#wR Aae" 6_]~c :`H|x:ށAl˒o3H}1F_Igdc"*kԙA*cTH+z-V2!i'8x-k!X%4%9-pJJ,NX%m3pxkUX & (%P|wIv7F9-+$?5M x'+s}~pb[㈛]%*7E[EUJMqAR|WrYnQX7ZD_(&67i|f f蝴:%|AI.gmD+NR\etlIG:%OF26y&ݲP%uH^I=8hw'%u,mn;(cĝ'lay1Er/VPeU(iWH*at2rI(eiH^A:PGPTY+yD@oŠyrTC4FizVLKZЂEP=JH[-c'U `gSC)~&LZ?H G򖊳-~I*atU3im9_roR$;@,&r !$ԃmųLZˏyA`UԿ$U#GjxPjŝ?rdN6~*qh>TrT8{ύ1H)w~H}GϱriQqXऋ8k׊{nV/PjJƞmIZ@T"jt ƞ[+z-Jr(s5Bߒ7Nc^;*Z `aՖ;䊀!/i~IZ>9♺^=+iCX8W}WDceLZ@AoҪgO*eMMJ%T?ƭ!v(C]"OG>ɃÅWIY B {)]ը$)XEjn wͩ $lgQrȧ!KL 1fkv M;ӊ$tr* 9,EJ>)rBG*' K^yZ,䘫C Z 'PA"3T] H)gF5SRl2hJ;m2䘮 K:< r١ ZFi`( Hbi(rۂ h*s.l= M>@tR:ѷBP_:CS.d߻C)ǁy! n&6Tf,*\ÂJ !&HTzKcj"q!+{aDc%_Ci%9D$E"bCxyZ2a?vG>$Rv$K5ǭ(_ JlY -GyD$x%KVnd A \&:h mnMeG0MǣGWr!$dǖOϩƙ',X ʮ5`l!ݢFYciFM0jT d2FvӮqk*e04\"K On5* WIA_doF{#; : Zp $Cl;PC/E!B`x~Y/oT.5!R!IW0ظ+#LLW# οzBR b$RS0FlBLtVJ1xq-i 'F}VaDZ-:{mRèNSԬ$:UFM3'܅?ã7fӦ5 Y![y}RYO9f@,qG2CL%YmfJ*e0#ޟ&b4CW1O)aab:W {%=%( Z = C@ ;O"x*)Jdm\eKA}ҟrR2DӔ )r 3^Mv` iS"B IʛrEijb`BՠX Ζ:"zRFd1)V(;B"s=1 fMR(1?KpNSUȩ(cܼoNcZK~ *.^rANoYK+%Pyֵ_ dsMSrNڶv(0(҂^-Ɇ(0Ȫu߉q7ہqANoYK |xPf{nVp:ZZ^|'<ˀcy }--00U8ԂzF=|yK_a-- 2{nƃYrrТ47E6efY;3dQ涖0YE75ڞۧ%ާ`"̜zo\B_KK=/ѩON^* )uh?(BiN.PwҢT7Ee}͆ѵ|tVE"[gkt([Ҋ*oRf&&=OˋhkiDa5~^aePҊ3Z/'-}f餋I l^RJqzZZQ8$F47EE8@S["hI&bKlؗ_I]K˴"tA"'S0˫kiդy@%9w䈒]'ήg׉}I'̀TRڸVf6q/K`1~^afPӛגG\"gH+iQv;e-(ciga|Q:Zxr't>ey }--,4&a$apZNw.7;urByyX>/{3(MkiA DgqqA;y-(%yAٝ޺!$ .g 257AV׃k19fePþ/=X|ST77V׃N87yi@͍սzp=ݝ(3Iuscu=87J?jj:F]K+.2Mu:Z(]hE͓S]mnjl+҂"{;@ oD4({}\%$n3 ):q-(' dBs:ZZx`s\;-kiE8r \ d-KnFdTCN1˭60HFkJ)KG(6p]$x?_i`fEԀT6)0ƤOwMЃVk^K+M>!ɕ(Cٝ޺/2Ql׍nf[hkiT)r;Ht ѩ ™e&<.Fv-D{2Eb_8}}ɜ(!=]n^DOK?")ubic]23u`;xZZ^ ran^L&{Zŗ$_%EpX^ (*<^Ҝ޼Vλzprcro"|Q M.hߊ%߃x`{pvSc^B_KK=|fb"9ۅVdK 8ޓHpt\9cd7/fyK󢐍'aI|Nm^K+orlPv;u--(R%[XҊ[]͏Z(-A<;adaĆߓM73׃Ndf]h>pq3cq.|LI gM|[uѝֲV x;7MrU\.'$9hvbzpu=xan3~4F4%Xq.`_K+os_rjBv(-#6V]nr TOBIrUQ^]V}}ӝDoʦAu$$g'fnn8";7͆X]mn^l;kiu'&tpWvUt\mnZl'A$IxiUsλT_VghQIK JwzZZPxxyi.&oswab%(ۚzx^6^:]Mw콜vyb̤";ArGs0r)\@̿3nv$zǫ^r>0db:| @^pWOR*[l i:ȘԥFg-hnll259*PWit;̿Dj :bڽIǐ]sz4 M)KBT+fUqZ d$364>IƈJңAS[;Y;zX0^Vj.ޙ&O’&LVz)5PM 7ڍrW~Ā퓫a0B%aSVEI@w;D:=2kl\NV@޿ 'HC,yiqPϫu|urxIKT-qʙ- g(ddcN:1.ٗ)7֏A;Ӣ8mPK/[!+gf7 %ڴ7`I]AIT&gF(5)l&eG~ ޥdZ%0s( ct+cv>G7IASߗhkŲs_WUAQ_b_bVt9YlsxK F h@%Vt XoNk2Y^Xmad:)ҡ}i7̩Tx Emǔ3,_!q4wNVzR$%;N*sHF&0R(o\n0-PZճ'-x_Ig=ICU?Ca ?(eDe(BaFPfVΠ0 %ޟr#oA%iNPƱ6߬T6W)IgW״'Lmmcfz,t=x%(C}cMAV}:D &<#7@[=xt#j Hu xfӘJ jl:0Fl#Y5z3v©?x@2G[@ZqFrEY"(admY\`y3 LGE:AH0RIvC18Q?} :0_`:+ l'd^eb۽iMdPITA=CͣAɦf֗(LidBY+l'RCqZ>ϪYu~rx0;gD'p#(͡]^rH`,D/ufckR ƴXj|v>%UN [':'rG:8i+ΞqӐ`Z9Eܾ̖2I>'qBu=>Vh^3bN[D3MF=+IA,mHX4be,DQɎ!)nr# ̫tbxz4-q2N%Hq J)GCak~2e9(zpʉyBWAJa:RS  NnM$D1kT?,Fe1v222Z N*3$l![L_f73r>b1Y @f78ǛR7eFug(aSɕ!*sGJ^f]Ze$^j~R1.iPmE`fE'?fXg/iObE%IUN+YS.yUjV*F ]=v>E9'AYg ́H QN0e+~)G J.QHPVJq(ա'JTO>Р^Yon#J:\( =#zPC1[*%@ Eԣ!?,d%k|a!JC0xJW/G pB%E噕D(s`َApIZD9yVEu_nŷNΨPy!B;"g ́XHS;2U;@)H=\СP)JACYr;E'(z s0ݩ*NUeΓA$u;#Bσ%@IG ŖLoIRV/PȡZ)&u\TQ}4JE-/4OP׊7/(Q6U7u%|Q}E|O;E9R3Qtg(r"!Q.Pw(TpC9BYA9C*s@ !?S^%QiQ3@,fSQO!5ZF8'FRdRH>3M#Eɳ DJ:`S!ꈁOj3g-#CNAhAugLQs3 '[:_~ҿ2s^A)!zD95;!GYg4Pe'  eb1͓ RGpEzPuhQ[zgdL1J5B{x],!D]O3Fu ֒z<^*s">8J swD 4(%䂚E'EYGEPV+0Ci- #9teAYہRJҎ(4(kSP,q e4J=S $@>QNQ@Qt~%ڝ30ȗu Wqq)S,MjC35 7PιQx9~̩|gUlJ*^kf1õJd)z6E>ZK”Z=sn0mkzKR CLe S +iq@#%]J[ada+eZ.sR@΢%K3#;p$KuY$%BJ)D)5|曜8ylLv;Pfe:R*;Uͨ5sRbD>SOW'D)(dʬT㙂Q^^p'R'4)}`(ѡ(W4)1Tb3RZ{ N==e"dFF*e(XW)16XNTTlT I*6x6)1 !dB^Qj7a8tR#S1Q$.T UD4ULR8<;.(5ZyÒ%$O*d*{OR˕k ͂8z$FJU tpR-S(]r("3kL5*zZ(N  DqN(Q!KDV jwoo['$(Xtߞ1|Dj 3FMKPH_%S@. 8Od Qɡ`jv(ա#59*Ƹ H+ HApʮYF7)EA4sVTe;b0w(AΏHSbA|~,qN1k4UxRgPC)˴#ڔXEA*'53~DQlFq4F7aZ?Lfs^kuJDC/4)Y-߮\(VkRILmUi݋CQRjF$;fJ)]v Dq(5]Tj_ 2UGEDpZZ[j-uBH޼NrOQjF\;PfQjڗ$kd\RxDRJw(H 8 " @rF7)z^c2WI}7)x^:+OB0٪__fC_WE+yG1[:oЬQ9ޒXlzƩ)j^ѧQ@`$Q 7T2emxR/S[ʔ/HKRffQF:b\2KR Jt(^η)&ʲ[ݐXy S;@HpR'S[ϓQnj_ҡR*s;4ͼ%/標M}Lސ@>zN(J֬ Bjkd$ B)&{ſ s-׿돿=|^'4\3HD)yo?~ү˖k4 ۯQ?ۏs\FMۯ lCߊS_~ a5ӓk2͟)ZFSZ+?pk".z_`PI}ޡy#*eFz+뿼?/myP= /’|q>Y ;+jE}ZQBLѠW;H@ْm/dK_A2wv@YQ[A}P{| ygK}%’.T٘'rP}Άڰmw-n%)EΒv$][_zߦCf+(w61 P_zަ-D7hie>Z"h]p ^,r|'sG. ,ޠ]ciT_2̝)̔᭹2&v`{XAL;S=Ҝ]RgD0]~ٿgSD7~5%λNw?]}20wP+rXtwOܙR7-dsi~ts2?>v/}>VaJeV<;JƨdX~EQ{Fa8_|P޿[o9}CuޛJ_SOjOjqy {-STa_PEBw<~)?NMjv/jw~;۷ԟKoy=]>(Nӏ;;ݾ[ݎ{Oʿ3e}Eow^{3owV{-gKkjgi{-.ʿo8G*grw?oq}rN-7}G=O>Kk|vEo}Vxٴ>U[ʿ[K[m~;m[m~;mrxҳP[ 7I NT'OjxhX1fa$1$ӨФo2SzwkNx99# egШM9k|Ҙ3jc^&$p6|pjk?t]IRcL'cy-U|і6sǧYs;T-r.Si JΠQ=*k8;D FTgO%{MVg˳#ͽ-ɖ- qxZFtG\Na{SY[#:9=iP'abld" ՚gb?U]AI22ˤuFu<|Vj%kms,cDʕsgO'e!<6jͳG-XVclw=A]쨶tkEVWNcƊXE*VWyZ0Wt2pOͶGY"Gf#,vĥe> m>Fc[ 6-Ɏ%>vtf*yUΒ-qrC4veHs!wv^^S+a3vd=T;;\/tz%& #,vdkӭ ې_rb×(V6tHt! z#Ij m;XrI7toՂ\o*/Fכg жf{;=e';;m(!$<$|gf(֊6 76h=MN5cm>[ҾeI;#8;C;ʷ~j[O񤟪S;;ڭ;KSgvcEV<j=!vögKO|raWoQQeG6v{+8cdzD"OΎb+,-߱١+l?}h7,vK[^=Kl/zΎg}KͯziV/ 6K[ugɳҾKC{]^lF ^L/nUf{of찫xKzziuY/꥛VfYo١+l/ݞ[Kؠbd2(襶döFtv<ua[L%HziF/uEJ7·gKR+6kjxf7,讗g~a/bƎxKziwԶB6o;;^]/[j_ޒg4vgA6V^w|Âmem8h{iV/m`[ ~J^uRҗ}/YߐO7vH:;7 ü>4v<[.Ѳ;;Ѽ{#+7 |nZQև4~`kX%Y.[KĞrԷTf~Z]?VO~Oֵ2O}m÷iqZaWe4|O\.s<[ԟY6=l> S ɮ4|f'̶H~߾WafnUj\_$9Klpv<߉ٺ^H>iv8+l>s=k+6]~0"&OS6Ξ\?}߉D%iNLvc'ԇ1v> OwbbbMIĎ~'&f&*ƎxO72 mg>~SP u"r1lbG;TcZN~bɗmsd simp{9X9jx„Ǧ2#r~'N;^eK3{"L{sZ\Y[Ҡ |g?%ǍBUf{jKNѺF<:&[155/aŷ}58^kD.-ɼNY'g64-2ն#Hn0tc֔Wu_kiPHcI]q>j[B)bWvݴfk|^9xq7L<[z߶fߏbOZIg£5̚lǘ{ܣ-={E+oӜ=c[mȚMk8k5sa~~`S';KN%ԭ%Ғ_ϒ9*nluXӚtik 7ùs)nnK{󽹦|UgOrkk={sjOv%k77t7桥YSeojlVw'Œ5ޒ~iI/X򽹦ϢgFok ësMusۣmȞ5խkv7K󽹦umk[={sjMqmk7x[̺}cw-{s[KLwOmllcOlɮlٿ94;,ָpc=m4C[53<֖zb7f%}mG|oiv]3[DJvy!}߳9k_Zh!}߱;[̺&1;SKK44v4sxmszO0xr-v&󱕏MaYݜOzSXm<Dsvw2ly?m)2׼|+ٶROf5Yɶ{flM4k iz̼0{Ysv2mm[̄HMkFxnebF#uCcr JgE%ʹ} %˙|ٖROn2*w؇: Fog+ 6Ϭ11#Vi1{Dc>#h9l*Z=G>~Ǥ+ֶ2aag+x%/!6;U?g"_&r2I={Cu(FJ\/maeSnh(9kjN%_֜q+1R9XYދylI7U&zgl}7V=Yȷ6kcٍ'RӞ@|HρZٴi#( ڒD褅 ߶dt4>1X8Q wm 5?L˥'=X2{jx2&gsy;+ēZ(?\/wfJ94n>-lRr7/[ Q]{,0#j Os27M[h0%^ 6~jɖ(YRzVsZtݻ ̦5XӮ)~==≜ԗK0=u˿t'\WM[+Kнzóq\-%(231/AvTRaycE~^vlΒg^{~iŵ'f7ʣVɬ/{[>$~lw} oAv^ؽ l~t<'gMƿ+'4{ g-ז$gڽwnd"  Y;`wv?hr6؜K;b,YZw6̳9&M Ζʖ~OK̩x0-Mrؚ?Z>'tV]~p۷wMKZ9[k8[$=jԒ$dXaG%$=2.ݷ$>opZY$gK<[)׋Us<'8{aOsns<*o}|8[a|oD٘ݽ3vt2*47|{tޚ*#}WeZlyU^Q5ϼϱ^WY\Za3ۯyX[ecm~yk5P'ɈܞKpgϓ؞f~~nOrZlyU(*TUX[ nΞg_~:ϛz/btnr<oX"s[&9kFZ{_==S󽯂DŞl8[wMK$覔v2_ZƮ_WE|2r!Nv.ܞP-z6=e,XvJZiM7c# 9hJ}_KyxX;\";bQP* _ox-FAyfT_/ 8:* m|c6Q!m`bG`l<@ۄg)?2ܑF9kK&ґDw ʰ} ~>h)Nz/_e_&_/[~Ceӯ?m5ǟCOcbb$rCb*9oGEbgn_>x[hLTohƄ.zҗ>PԏwcJƖ~Wqr*:[f*.N{9n]b.Gi'}6d[#G=IQUyقJjxeۉ:D%՛ly2@1/-_#ʻ;`kݵXȝFetbɼJZ,RJf(Ѷ^zҗPB٣DbbXh[FxW#٣Bqf zҗ`t 5VBIX嬱ݯ@iC n^5=K(a%ovҥ-9ٹ7WKO%{(sd+$GsM@rmUDݛ'}i{I~%؉87Vn"'} ;G5vjmVSLv .mzҗjzNlJS0^zҗ.Q20KSJqˌ ƨIvJ)οTR6; N֢>fd[)-@o鮩AOҡ B[ mSξտ5KlN j򥫦*Q`۪ʒ/]U#GIv5>I_DI!yZکۿ+'cR[R{/] &0BvJi~zk~6{Pf0~{Cb,ےmfzҗjV=JrmUܛ'} W("lV]ciKӣT`NTR5X=i{Q UgݬXVzS0Tn?V&ʸТ`ݫ'}(""dnp:hFZ7&!2ͶI=~4(N½r=KW(7(ݵn'a*ZLcJ( n'=TBO% FF+B3*J0^zҗP v^ޓ}])]Qj=KۙvwopScwKn'$8]'sWТbK*J2VHyH ROP*ϡEt>*E9oP2%ʹ(3r\閭|$^Ha$>.DKb2sv"Ey@@\"MSU"l.J vtK齨1z傫 rmZ3R`r2X.r\gq&lOȯ"_@%'IRKݸfqGgUb^2?"IAj'Wf nQYhx䓎+It i%c`Yh~qA@=* yt+c W>D zdܜ1: J,hAR"Λ ׵+72\D;b ~x..ԓĞ;}b(y;( Ta N-ɗ/~ As9ZCz%kE4:_ Vr4t],x ւymFKŠ]FtClV$H:+-g VӉ C5bk<{ q,q ׶!#~R W=e쌷>A[ݓkQ Ϡ&#If%<F69r~#K$זIY2.tP ȨȥKNg}" OA%-r(Eϕ<~!#q$*Iڄ'A9] MOH ,TTv/ - d+MV!,4Y@0lbay_h2AJbsH<W ChP;5FH`kg)YFtTbuBB5,DZ-3tӅ~RbA%d[kv'^Qbᡄ,BKStJꌡoX Q& ,Y3K5^E|C`/99 ,<_ϬCX{BqTG qB->/WÜv d7 ,<hRicG Via{(`BN c"/Xx6!0,=R>GA})c,9+ ϭX{B{arwnuʫ}0`&g*C[Ih騺®d/2CߨiY&{>k ȍ?JKJ"꠻†TdTY[`t獲령hR,AZFD q~ 9L o{~ʹ UN~ oر`1B *oZ9v픩tZjNPQI[@6-Ig}~Ž'dZId|a8(*Qۓhɐ`Po[ ~PZx8! иO8wɫo|lR宅:譸yB ĶO%ߕ ' !Bg 6>Vjkvݥ-( +YCilkQWˡʫueaeȷMK)zƍ Ly7G5"Swr5J#'ʫ!wn4Tw-\j3_ eF8rnL~]m*- 7&(x% A4&;C_6 =U$çգw+=\m]0 r4UU>oPz5Xg!Ga⋽h^WV$6da3k7Uk"q:AX,t_ ն)\6a6 /*f2qcd aA3I^:]һڻ -s}2"~ ʇ j|/J+ޘwD~fcn;\RzBi%T ^{rkc_(VD\}XV+\ĩ* uϛC0,5>n#c U@E.a&jZ(Vڢ(zs&Xi pNDɽ Uvot~aP0QJsŌPゑwuA^6O|$x+w +<9UCKŕîLZ˄ҙll@yRq%);2㫻}eV'^ղ"nX'Pbi]!Ѹ]fp@!WL \ &B'ua¢rWO܁ʜK1TvrSj;޶կ;_wr\$d4`,uj㷐4eJqK]W*Jj7 /z&QnM-50|zghc !ikUC-^~N;m &=3"[謚,-*# ^'{"]qZgQ?TI ї>UiŲ; CQ2L7.gZk常ZhZ@lǛ[/*&eΘouqLߵj&m̂5)l խZ!BZg5pʋ %Y\b:SĞKzkReaI6P(7&o#cuxUZET$۲a׈e"d:7uP/j+&͖«|~ V Zg04xsj,iC/|v%LvgSwbNpbi|N# Reib18A&jZۨϸkE1^o8fݕ Fߪ y2#s~ZPKrUoL0m?k2wvd ~ YQuRMͭWUŦ>R[&zj_Cd R|s&5iPF  {AaW˸0 \+`ӶH#L SJw|iq0B)|OAߵ ITV Otoʕƪa9cn0S8r](xgS(zYBH)(AI*nh1GtVRmb!} &ZeT2 Dm UVMŬЊ i'PPgRJcVpvJqDα,+a齮Vmoc"3$ݗAmސPr"LA,9eF2Xdh!~oū*zE :QS'=mZF񅦳CGZާ$7m20^oJzCN;{v=B掭Vͥ |,Q|;gx)[z_h'KiY#ћUuRWVvC_hU:*P@umRڱjJZ+S 4^) ؍Ss}D9 2謸Gb HI(2N 7NKbnNG.V+ W2b4}^'{z\'ˆ_BDj|/z %0a4}:+ }~Q*`EP{d9Zvc|9j^Wc2a4vo+ci V9( `[=r:9ǥj!^AxmitUo6xd<+{] TN ȒytN'a STUs*k!Y. 7G¦Bj_hd%!Qds}Bs% RʑEk)x˛橡/4W4`Q%Flqi ^Q^;$^=WH iP먷s):80$;T:#ޏxᤦG V,8Pq&'6L+FD-g.(⣌­9 seuzq8.:D1z2U3u*rw{cׅt.R$|1 '00Np! Ga~u|qC NuB΅;k;M"yϯ[{r%Db=Ha)y_Nƅ:bb k G> WHiZNzPa[f (zQeege6\Th VN׵pkH )9,(b tz͓+D@}P]2Mɘ1{#{-_!wM'rް #R:U,lY7^ fs^̌#W2轮E\zJMS1dƑ+xsXȸ^(,$gji7*W גVSAn%]<-u{B5|LdGV]Zf#-s?73-Z(ϻ? -wf<Qq2~p!7әb f~p(nkOb392U_.[.Th" ^Z$;x''`/1p!x{k\տKt 3E<3+j^nJ )wb(o3j~\[d^gg/xyk$QgGVƲx7niZJh/l,TuckUpqUPK$k yl;^t'+Ziဢ|/0|p:$aV/䫁$[WKkxՕƢ߉FUj%# 7뢂%B߈d[(mw%gs-xq<[Y.xX?BxG3Ac{BUځG 3}8ae*(W隷:HV +U=fDIԠ{Bµ'К ںC\\FP!wzIl}qIՑ -L|1Xn/?X.?S?&nRL) {/HeY¿݆ Ip#/cb<~ ʺW̿F3??H 8øH6,޻!cX3ѾɠĎ{aIbA+ kĸ{AF+&(s~R_ʳ Q[[O%N,xoYQ2e.e7ZǫtCl;xE &LjhȻ]G9"m͟_0vg҇y48CB|iANKI49F!'N .Țˌ_17\5}885%.F8B%~^ YHׄ-u$#W%.ĊX8yƗLrɳlO.ڸޙp 9rOd~"kJJK;rvXb-"\Vbco">~ =o(\RQpn4WF0x4#˿}Ý}nk{e=ӦiǫJ'Y;W/1|LЇEcܬɇ7c)؊fI*&VHPE/ޠ('K@ђMl&["ʑh@^e:ԝŰfw`X>c97k?L7ѾzIXXeLL]u$ 8Q8X@{颏#Ėd>mL2if,ҁf5[Xf+q{|LIZ Ȇ],\1`W F.Y+C&PcҺ{\MDoG[ cy#g#kSBDVԊXMfI 1Fs+GĜ肓LJtOt-J:XDγv'ޠ3޸LsD腣6%G< L4 Gd!f&\j'.;nK0&Afb*=$J)+V[ 22J}z2 XKx\519x׸.XU :U+WOt\/& ʒjk~ ?`KLa'VDH3M6sH(.utzމh 656"##Ҟq#r4}>*pv,\031*/"GsO7,>^ӵVtx]^.'!CJt"ik>s?xFw*z75KOBqv0@?8n(;Sḙk ;gT+L;ujD{ i&`s[ dy(Usz琉DRq ݻ^H}A2 q[rA(BYN1L.hĠC/X\yDYbC@64`KB9WH}Du]a7z߁h {mxDQD*z 4MX#Q7 xȷ+<<;rr2E'DQ>1w!x oZ:Ǣ'.3ё vt39}WOnojݶz?χ~Π ]@S,++jFҿdY8*Z]R06l!sp lqR@N)KX,o}_^rq<՘G62E2"~ږdCV-FU#diu^Fk!TϮ+uohV 3' h9BOg0GqhK<,NEeҺa;,*)$ 8՛$6OLܵ!O2inY>6vۤʂ"!:Ir$l6<(a0TSeT/dmbtK*r@Stw2>FE=ijt655)$KS|J~{YIzfoWW1I,\Tz/EqLd0mMӻ5d M\ lI'؆U ?/ЬaȀysK+N.󹚘酮pML3$ lݷ|]ea7wyd+< uc7PЇ U,yΥt\wʢzS+!yt7 kvBṺWeLF"ҎF|Ypȼg|fEL< dwsn'yr{ rΨv$|9r`F՘F N2Q,T$3 c7TXfI&HeLNGFw@P $xʄ:j6QL '_PT ;~8;e&d$r4(G7#f4DA|yW2?)qtCtt]6##U. ;KΗ6M%QQ>wˬaAZy߸vP*B7DM~6J@KTCrF(f?>201CD!fً>/MV%320)Us0[416/]S1߈ IoTeEɗ#g?t3R {{L* ei;b 4V<9|>&+;ʌGX$N8 (H\dWɗ#oSmCDYV|>:Dɗ8"QM/c2!A/ԙl‏6"o<]M72ʗ[URh5 x"pP&͞`>a7$Xblpd/n 3j"0: tY 80@HT嘏apb ]!tLʨRYq&;%hqi݉6B\n"0|BDScf2 CE#v/d"`X/P),r uH\(!9HA[2;`·$u[X<88wRhDG52y '_8]Y`߸tP'£P4UfIțgrd(בʀ*ވ:8佸4 3ሀȄ"'+zˍ'd]V8OW q|9>pY7D[8p t )ǎ`~i$.|{Vw>r ]ym; Tm[(UuY KӍ`[i\fF G4~nѐȶr6d0SƁuܚm%TǕk:`m/6I2r>ĸO!K,Ux*o5HRٌn>I!:CN L1T!騮CFs 3V֔& sVyS޸EPH9d ))GY ܦ%*#X -bkڭqūD1G bB^*1r(8ZE[?X❵b%|9<.9y2S΁vbr=9G=@DL= &f+oAhR#sᅎHypom[rO^#P!!@B2!8\;7(,ѓQ> u N0H:iRҁۆtd2VaQFUecb&hɬye)hI-~FmeYd/_W\ۢdH,!̀jg;7 `l6YqQd.OeƸfP;͚v. AaT] vR[TULԑEk p`-t}Ȩ좧h6P#A*0NDAu5 =~!0āf@|uDgu<]a&/.%ϼ$Y*bѓkIG@G6IH6J}t!oYJ:8拎I b52st&nфf&92B7 r "BF H=s'G٥/͂n9M\J: D!B/+QG2WIxgc.ҋ0w2TST bHzaxvArʦ/r8; u#G3YEF!;N'CU8LV1d-"ǥqGd(U+QMؑp,"ťC*ᚰ`6V0z3^Ž dҎ'e&G.s0@/yI$UZdRQPː ur'h Ys "OuHI-ud5B7 HdH*'ע:805Kt')f%B%~ruHv,ిtL0SYdI̚t;  n\xMU}ru/RQMPeO)-"aUP$n4 8DcG_f^-uf=`Nt⎀ns2%qHY1 )h+]v?.kZ}$%f JI-X[i!6'vdڸ2a5^v% B*،n;&Y')Dv)AމS HsM~\:&: tT8卸hZ"1%^\ :& :Crl\;'zr-R0C%Dd(& 5B0RH&C6ɵ#"KT0r8:C:5E$|0E@G>}~M$0Ty(XqS:/ B 'w( n<٢jbUv1Nk*ȋ;.I"^L\GxxHΛ)p)P!u"rGc7y}wHumwUL~z2qsijz ߣ W^1}ajө W9XH ; JHI,!5R#篅lg"E9 "E7Rp/uI(mI$>GcިŽ6 .ȕ _~%p<w8 Oew;$lϕJvA8x>]%Q!}Hjz<#6dʏ&$0(Hᚒ$ #1pH:94>N[Yd3ExA|I䕦zcC PڑPkҎh5}$,ߓ5.SJ%9-^҄KwYTځ_CK('7sXZ:/.ȋoGo ;1*UAX5ilWXUvƕrJ <`P!}L~jxBy42iG.vH ҞNa6J*z@؁f揾jSn1BY&՚#] xIt͊v$٭B8ٕC*>nn QGҲQXSZ|a9CeUG?RўZ!"IE3ZM^nj^vWTq_~L)dUb"M7rK^fx6E&*4ʍ}58*s}߬+4!*䨘Js4NR'PʁB+*ٙ.-YK6LfrPPTrT=s;M\J9 ψݥb8U2bc)drdRBZ0ATC7 B8h*hv'ǥ#`!W;EOc]<+UāxKqKGPFɇK~<*v'kd>DŽA0EdlRA1XҎ(ߨ^")c)ۈ3ݹlc n&H D\HRXei㞉cz*^o!/ b27RF=ŶDޓ*መ 3]7NL0Љ .o8*E]gUyQKG^ 94DEX&^V戨YLBEٓ+ c|W,xRTSȢW(w=1D7< ߣW {HPp#$]܃+FD|0hl<SQ LRQNbrԡqpjJ7{r%pJ䲍\]C1h#y"ڈAކ W$3ُ+Ɇc2dl<'Ys]#byU`Cv`#I8yr)؈.LjEɗEQ,!ِME!tDžd.AJt*PE.(ݺK)9Rײպ%-GH}S%؂t ɥ0& Cq ^\: \6ULj..*8C8 R1/. Z$g"M~\): rWI5E6ÕTGK &'OåC*܃ۢ/Ჲy_(9rI'ARyE^\)9p,| WJzr ,H%N\)9r,U5_9L,I:*FhMhǵ:R"RE'Tv#NYrI?J_gɦ\mɢGE3WTx[Uñ"D.5My6Ez[HYrYաRաx4GgrTtHqi.$3KֿU!E99Q!3M` M,cm9DѤNdc6R͟͡7_edDw2èqՄh`5a<ɴXo+#uBHMPIur:|IZ#0eWOku1X3!ɶM/,eqn5,T"{wqǹsk9WsG@:Yq_kN抎@s[`,PG}R$ؒTсw:EW*wFj.gp tWxkG'm:M\= s%Cu4Ӆ>P{ Sc3D=9Vy{Tp4{49s1ÉnRa&gC,xq0ār}̭59ͅɮ,xq0ȝMrQ//up@2̬/L|ɥ072+W FB_Gp԰~!yDQ'O|SyɇKG@38Gɐ.qȮh3aZP7VTG%a(h#ts:t+weCG8j!GqiHz]Q&aE/wt;!Hxtv}̇e@Z:݋K݇!]6UҢxdKՇa=$ S}H\E5?^z{R#Rdì`pG]TB_> sNUuF ~2xGqGE!DuXp  maJOrr"rH$i=&ɓKa-i.pZCzb W]zJwV }NT0]!"EOu!qu9QuaZP10ryJD8%cdIɥ#`CLɏKG 8e Ga<P!(g .w%MܱCN!u}8"+b/&|ʨCΉC*E7)trHj1ʏĕ}_M!4bW%\i>7n/٧z9" tAXˀq*pH} LQk c_J<N y׵<8?^3} ۖ-RR7i'*V٤}+sj-ZJ4[uj4e>m I53 Ti oe,2+ iVR)6$CZ_\i{\Jd_Txۨ|p,;R°GëZԾB!.ʭ% W6~Uu&cAc[Z?wT'dH%^+h/-W (B5, ݖaȩzޖ>-( z踭r+d eD@*NJtT~߃i{OR*6C; Z~chIGI{bS HEʥyGw%q/΂u(7U.O NX7"!7$ _tQ5<́Bb-E5Pd /z@jaP@Yяљ DaqҐ#Q^/9>lӈQyDeR y]|Hܢo R8EOnEŕ>t [s`}[(N _!D||7 * 핅*;,Hv$o57f̑B;C*l;j+B{!hywakhmuСa#ם~6ljS^GԇǤDr+c+kMg'@8eM݅f{COhXtz5Ml,@>H)Y2U&7^ w|G|a~d^%rS/JD0ٻ'/Rn-`>h_UWt DɏW+FV>wU@1[u(f~>ؔr^'/J}f'9Cw)|݉M$.:8bGWpЏљ# Fmz 9g! M7"1o>rηӎd!2F_^e}=rݐ]&c敥1Yx->)l?P"682Fo>r>>n(F4@L 1r@(p8C*DC&1zW㖸#Cآ& ˁ^Ш .L!=^'*=j11'勾JE>lcL7y@uN`pL9]Qi*.w=0cb`Gq*&No\G'j⋞88'\~(rL|(|y4wʁx7{!ӹGvtavl~\l-?=d]90@N-|K1YM;NjQc?b|Ƽ6GɓWmsPQqpݰ͞ i&"vf?^; l#PDr+Z~}]n䕁`$͂D6{qgםqKMbTcYlbNc7JkvGA^^f7 v\`A1gW?EұOKLS'-vpp ADku.uD-'Eˌ^]gqk az@$8\gv!QZbkJ7{b ~à1&-hҐ/3+:9xpdJ#J';Qݵp͞uB gi4ltʠgc.9PL]+N>#핃0\i#B]w9DāUpd ֹ!SmܘEz[vX~~rvZىQm6Ӿ~w~vaXKJӖH6ple>q;qgsd0:)%h24]D@6QaoVopei٣PQs 7iIVzlՔȧ?p>tڮO2fNrijo:OEqƻv3^ !Sמ'[Oj:W,eg~w6ְ9ոD:##9Ňx)I^Jb0. |pɦdGKꍏl ZW??]= k;_an|`\&&?H]*a-~L3S,0 ;C+zW &~#t{!`upI82M^ёZL2 1؉ Tf /1rzWSG΅Wi98jdǒasȂw`q܇S{zPg8"rb93I}AR+,?eӗVs a78ㆍ cD:͑q:37|' F׀䦪ʅrǑ 񭀯=JVZ`k  VPTNvhޙ1;̫}xn&j{xqI9 DXq<65659?>ogd L \WƦ*k9 ΀d`pmZ;nG:1583tM)Du܁I=:PVTΌћ sqzNcO`]cOnr@b`PL৻ ؂L N`AS٢K>И۰Q9pXq4VB9?G 3g ,D ƾ=zџ SlrGQIp$P 9D}(D=0_ HG}ȁ#Rc{h*Y㆚ I>c3sdA.&8CjޏW|`8,p(g{5cYQR 4-! /r˗pPP$J~(Z犄ع\9PpġUb0ґ8/9@Xqâ~$rFE epU`q""ҁ9`S`q܇ :cvF-1zs.!5% ї G^Fա9E_؇9dDa햝/ "4:8bH :df ]p]C17nleMEBΟXųI|+ۇdyg9{dwwCJz(.biP,NPnX)*\VW1gByv6#"7m#YU-'غ?@kfz8l#y祅S ioԲ VD`tzk=<y&bKni0ܳuu3s]`ݫ-bu loڈnwCye=XeՅYfxmߘ n, 3:zRUa6Z ̈wowtjv sٺ$ ݩٖ)w>׸P%Vfi#[Z7ZZ冖${h*ܤūXڒ藽 -hæ񌃥8Z*|箬w+T/rq~V`?'>_PɆ9fп=,rgEeYV{lz\ )q $+۰6?{'[NCYY Gj5#^%пeVV<۴OXkkY,Uם:xt#GYXa h[t YA0;E*ܠYAw ۬wCK2؋ֲZFo}}OCǡ5o@Ԋ7n-BUdue kl 57ֻ9[Zgws8< -=FBҋ6_("h-lO΋m&aiG ZZM[h{_^Z'7H{p6R-oh8T 5m1=;W_{oQi<殂IuN/qS3T8.x_U)SΝr+[B/M!`%5WV+Dx] 'z$#h'_.kPtpH\fI7rU 0RɅ‰*3Ntu- npƞI&O. L , g y!($[U'ɱk1 }74.P}3Id\1Ԧg-7BcC9CE=h؏b8s!E_>ܱc5mZ&M\1K_N}x:Fg.l#~r8%Z/N芄Dsznvr83l.pw˲b$̌ћr8,(tZ^&OxA#Ҩy|ZFHwY '"|ux>atPIN 8?J ~W' z椲*09R8<3&?.&J`#|R8"kCgu1KN2ΌћCׂ8 J[94$d* !.6J-3EW\w+#w4.P]26Tj 7Y~'r] 'BpUXymb\ `V *N}gu9 qZ[9l4\a\ 񥻕Zgf\ @Jd43U1T>qzq@KL6E?w!V|'r] 'e@^.̌ћǡN@̵yL|5}̡'Tޭ N6z}9rqTH dy`,|[+\É5~4A'K1مn &|΄љ˂8nbA 7rU'bBVGWZ'M~\ĉ`VGo\AE v,ǃN mĉ ' J:đgfq"C+Nϟk;'e1Z]ΰ#jѓb8wd>n̓J7qU 'b>nrp=i,9EO.DǍ̶@7yrU 'ba)fpU)q)4dWp"F‘P G6_‰`X8Q~;#25M2eqDQ^].Z)tm +c"H=IsW٦F1Z)$C[Qzh76$-xSm' *X4ibÈ86h=W9yxi'twKBE :w-z=G*PPy-a}j?X Kz@jaSJla3CUV~B$sE'ksP-[!V/fVN>ۍ:nqne@Aykoy"qS2~Ne.E]a+BٴοAwXb1r^ikBtF`}j??J ,I"*Y߼CۍωB[FRm.r̽[x*}"Fm'\_"*Em-J~*~w}mTPTHd%iם?>ˆ6$z{e~I^߂5]oEmlHP m:*?LUі2.?n.=oheP-5<2GBO1 2(T'eLFXi̓^c[ `˵>M dj}WǛfu2F|Vo?=t2 iXEa Xm^'XZ8R'wߙ5^Lqz9l7#Ry >U|5W$\'4a)49HAx88/83E/nNNV lٯ#, ^U.񀮥^E"A#E@V Y{l'IעsgɁ")C VqMDщxUa*_Ԟ&Sb8bH`^X1RLCnR6#KvN*/s ԉޑ=EO">RI5XStW [ #k;E= _%UmGDl&/`5!sV L[WieD(z5-lX#Mtךw@8ld61<_a#a>%Im~\j2x/9+☻zlW{~tJ^c{脄=i0qۈŋKE\&툯q8KsYG;|F#"7p=+)tIYxKƟ3D+zh5oU^ 4F7H‰x{+69`W:SPE2N)܁+!HtM9\&;t&3؍own| ^J CҌnCuef;2E/noЙvEOS;vm8d^EDTuxͤF[\:J,<u Օ$BsE2 tkKT'\6Z}QX p6sE?s#S/e2.81fEv+RD1* McCUmj2}JVFcE,"l7YdDDJ7N9AJ&J]|M  `cӗnprSшl1PJe /ڸ[dUHu }Ē8Rw!F//|.SFQK"҈N2N65Sar܈Maenh`cFwY݅>>./yY>Bݩ,Ue?˟߱/4Z۸5.jYGok0 [іo3. _K,76mѐ"k"Fhucm[y+8'̝05.#vye xV0IH%mnNqԌS=pFiMHfȵ*?TOdS;ښ7/y&J<:b6YʕG#`6}ifN[A'nLo7 Y^3p&x]WcP^f> = LɄ;+Ot#z?~33p&xZ0&)8;>|y$,ܭ~df (q?dd9a,d?y7CRhel^67H~P#0Éh7 P?N زze+gF{tNm,{W39p"h׈dW&ÉP#IERKLW‰LhwOV_| 'JmO$!QQ+QLC@L<#g&|8g,]9a'ŒuTcNDчw f./RL+iHMTы3iFbT%Rqp"h)Y&>2_+5oɁϒ6eẼ^(#y_ΖTeNDч3QFU"z#X*w׃ivj1'c?a, yji'7ʪpEv 1'Daz=L'5#/_~"X@bU"ND=8^!#iOI6Lщ @䙛g$nO&X"ZnW(0*Ji24C[ f/WI$MO `>PEmj0o(> 7ܪW*Ɔ^\1D.tnݙG gstݷ;H_oh[R̋QOEKi$͟mfYɦe˚5Ks1.K$ޣEkoZQ5u6\b|֔dƧh$lre$H$,ꩶ:Oa L1e(7!F1v}[\TE7CYmՃulm=Qt Vv#X?'֧+t=%;[*ڢ`Q*,+>M,RƢ,|/F,-ƛM"bog(n! 3"}ʢz@E Ź{@tˋ8` a +P-^Za߲֧-%8(P[h -9U ,FYMâmf!m#? ^tVS#oͨ! i_nuưѶ`Sw)Q hQa^T3rA}a֢-z@Ӷja6 r`:M~V2*r@S]%x!u4#|3hm-ô|i L  Ԃ!&pE16_ ],okMUI38U{-{{~@qH&X/j ^FC t@NhٌvVihڵUDåNC tPř&s5=9+M:(]ڑ+qR#Cs,,J4psdji)pUK5D8+ax@i0Z ORPSR9 J=t'ˁ+q]hiT&=9+M9آ'g9i@B8ӁnUKjَlmX>6 3q6s4%,!K%~w+T@9.iaشfr`A^m¤@&*Ls]sթ*}-Q5B 嫴WӖD~@O"u 6ZJ [6ygxNk¼XʸWOޘK@B_Jm$ʡHrZ?zΤ*t!?iMTP 9UUvoIVQ]RMK+B]ɸ@v3] sMs8`O }`*KP/7ט<筘e7?e Mx[,F}WŒFT%hAS߿{&XV#+F?qE?N#qCUYJk-zY1buH9QDć5# 't#W#ϚU#-hF"GHriU5֯P %EN4#jF抑gbđ\QU4EHd " "17=8ыDā" Eflj^[n:ED`j+xY-񀾻Z#U\яHDruT\яHfjcUp-PL{ґ*qK;j5H4/H7zc<ːL\ы3Hz7@M1sM~E ""h&G""ԋ 43ə^$ lJU>\\gzlúR}8Q4`(KaGd|Z$t@rACv<ӋDo2P6yrvK@جRgv=mL5R'Zʼnn2q,+WB SD5Ѐ-q#Cl3řj$ >dG2XWMl'gfcf<9Sā5\'h. WMDхH@{ĝ|y_&N4#j,$t;SMnF"7j6P55]#y-A58Q<ɫVm}e8ӍF*CЁkL5M5ڋ8fɏ3H@ruRF3əj$ b#Kh9fɏ3Ո5Hʦ8ZF MyJM#rLчϚrBhrD3bpZ*5#㘩'4#Y_c8ӌā/Wz,T1MF"WӍՕ3ّ.onuN"ʼnj$bcrDg7R5Wy/38tSv<7l 3Ǚr$ |Um'L'ʑd:nd`昙܃H@n&昙&/t#qdDЇYXIYj">!Uf}UKWqxƷϑwh{g?CL SKoi S E#u&ys>ߵߦ@ "L<8N>Qh%i#W=CҴa 3rJ{CR}7,PP'}i\٨ ѶUy&J6#(&AcA_"c ՁC~֯Z21CѴȸ3h\RBjs8YF|CI}ʸ("SzYi[kV!>f e'C`>(Dxܑ(DjEe@B2"#SiO.jjQi1*`UB;33dj[ 6,VQk6E?_R`T!-&$ )UXUXGU6 N4!jBR2u=2E/4!7Q+T9Gʼn*$}s]Hj_ɵ3W㤖HD|E!I՘٢'gʐՕ!Tc~BC;Յ`ZH8SB"wAdq'8庪.$kmzdB""wׅ=9хDāᆍݕ!3[2$~smHTэ7 UDkɖ+zY:$_DщmHē܁ D`| q4 wWַS2$=Fc=Wp\..!3eH$\ q0 )A2>B"k"OnUDÉ&$&s[5!3WD~sE$M2sE?N4!'rQ mS\7hv\q4AێKoW5Hd |ւD4`)V-8тDā/j"mU\яwT87׃ 3S$ l7rc[ )pxC {U "AЛS,$5d-:S?SՁ*S*#͒d-G@Y[ )лlGb•'l.buϏ[bnnAlLA-Xb[ֲnfGwy^okJ[S5mk4/T-fovLb۾1N!pSgma£eW~4*"W bD&[[U3ȏ$UT:q/:F[ L|*Cئ2$Cb*CTeHVREu!0R,)_hRR20NKk\ݡnOzP D{e ҖJ-zmXٰiB6lC7V=Fiڡ/Q[BK2ͅY#"ᥘy͒WyH^Odި,aXʈ2qAtDKmHL :>I7]7Pu%hvoaDR-QP)8 9T%TD|YPf4Lҥ]L#D;I+[T)< }RHŽ,GWՋ\؆a4A+bm'ƨ ֆ-+l>EﮢaiM,ĸyTK96=! >DF$hh\,"R_ORO]3BK9!I늌۩?Vɋ YTlȓMM|Mx0voK+Au$2PK#ƏZqB@&FhQ7{:Fu#Kf@XDܻ_3(:H4~a'ʖkA}`m_G $6'6GpZUGj_U{{.$8Nx nriiZ"tfe;u3DzVg$ |c8ӔWӔab>(J۝'6B Ù$=ƙx9pM~I:#i+,kDObp&਼STщ5Iʹ$ K<$&, L# `Mnc&8ӑā/WgT9t"|`;7ӓU2TzLG݇a+Ʃ*W'&/4%^9]05q( x`) 5kLOMIU3Ǚ$ ݴcVf/N$&Șwܴa{a|V0@&lhrB_k6PM2Vw陚$ _%Sxl'gjك }'KWɏ5z35sȤhPTщ5ICL2dC&?$IL1sM~iI@$u4+pM^iIлiI*Q1sM~p| =!@g- Z_[F:3ENt$ ػ)8I/vd8ӑā/U{叙k*I X*7.)H-{ 3Ǚ$ ~Bƙ6yrRe$"|ԓ$J6yr' %~ǙVQT$/LϤyՒ4`%I(LgZ“Zp/U 9NXc$b#V ":#7HTyDх=  M}8Q<&I8au9kLM\X*9&O$9N[cf<\e$xt NL5qRe$]dE^fNt%m`ť$Uj="Ù$}aN]5q+ _*KyS1Mh6 ܆K>&ɏ3u /T,c}snB!χ& tB~<&ȋ%NaiIvm{ҠY^4mdGr'CK ->$=n'ч)HpŶ,MmIMjMM[ r=u 2ANL]KE1mC[XPld=mRZ7&Ն̐K軎O ̃’ HPbCF}{cɷ匌 6^igZ7XSZrC A>Z9 Nxa."ޒeNFkLdLMP,N2QƱd^Γ++o6৵`/Ew=^m$*c0vd$W*+ȧUTVk@IU4v'\R:,2"]uV/-9B/n]Fu=Vi@YM0a'8<Y{t^0EO૴$"C#\L;EON+<ּpE?N+,p=/+zYrf LB8))~/\яϥPUޙ,xVLDD5o". H8Dād掟7* ^q,ݵR Op%by6~;(5OD~O;8D W!!&M3Sp%zЦLhLQB29ךv rv2p@gJD6fxٗmh`^U". y*g=tJs%<{" .|D4`5 <}8D.vg,'?sE?N*xp5*V=9Dā:&3[Pc~t",Wq,rgrm,)xYрJML8Dā/q/٢''|,3آ'D%z4N@̓ue@'<7\ς]֭;׃ӏ\яJDu]olѓϒx ܱ*q"Yqk l(Xp_G \]DщJēĶHmZrE/ޡ![s2wpE?~xM@rq7..QcZ^آ''•](y~V"}xqa,31M>|8 KFrW+ S RF n073^gOo`u:Cl ^|D V"K5YL,Y_h&ynq@qe}U8)*D)ya^V"@qrU8DeVl9ڄKo~̊$Il `f{乚Yfd)\XS-b]=/ ʗJ!IomI>#UMR!U$Qd,w)}H 4_# #%.öߟdIskiL'kMlMQ.͖JFԒ7)Ģw9޷qbq͌C^, G`Ae@ ґ ʜF:ltYK I=eTRX)HG!xѸ;FE>6# 6U#T T@K$u}"ayT>RFxUT@*R*!̭ @ }RIV1.m(`D|pp@F6N/ G[2T+ΉֆD-<+jN?i>6F0I$TJ Q}Q &nt$}Bɖ bԯV1IvR+9QX¬E\6iUPK%$8-8;RئIB_I(hxI-P`+ WDr5mINΒ=?ۼYzHkqh+qjSi ۔Ri -?%a<OօeTZ"eT1;nVOs36dlcHO*Dā/g{Q`cf<9D&0+G;vh8 oYdlzٝkL\|$c#&/%!7N2qIƾsM^KK2v^Dƙ$ jҒWz5q".8U 390@&-sEL49q&- .]&@z6yI\Ѐ$c˕D41M^|v]D<iL`$;%3ʼn$ ӵSfg=84`wupZgMLg⒀ wRqɢ;tK &NT 2L.ն -R1ى${wyɢ˲8Ǎ ȝf-zr"0 dBLE$Ud"8~Dř$}uR]13E/$&ocO J#rE/&&Ke2)A' Wn)KXᑢ<8]]\` 3OL\bxU]Z3WDXdYn؏\я3aI@re5\ ״#[LZdA %&I=i`E*٢'g%+q". p J4p"-1kjѸj92>KKDB\XgC$8<.,AQ`z\я3aI@|HX^S _]1EO΄%a&3WLX84[% 7\ыj(蛋KW%3WJDr}!/BB&gQmS3SD\pU\"L'ҒWL8/WV%,:r&. o..I(=9ā_]\"(&/N%&_ե% 7gLaI@9o3SDX\XHKI& E$(R"[N&L eaɘB*`a.(:XG1N0©ܦm9I5Jsbo@/u[:Cb@lXyAAFQ|r 5&zf|nXL"^=zc2" eڗV.),,I~U569~T5q(&6O>K&`Qɢ4,+e^!&fWd&/$ %1 ]o> s6%$ysWފYu%cim t%D~1h.2!l7Bn;ТĬ&Udbw=>#l @R ,4VudbR\Fz/_آ'e$ IZD숝6lLSɄ$(p"#x@_]F6Lы"5WrICM*'zAB]B"Njd>HH"eK92M^|8 s{sId# h]@) Hfʼn$"|T\d~H؛7rgGIƂBUGX-t|"NKMf@Wل/$Y&bke>IHлIHckDB:%$w*yTggGJHfGɋ3 I$8&/$$'҇uA+zq" x@MϑZky@e/ecJH ؛HaU1sE/Nd$oc]nɏ3!I@jR{Xy~8Q:Vty.S ř$[8"ˤR3Ǚ$ >dWH2!aDd<9D7䮧ə$ |p!|8@#@գwQtDFbh.3o},# puTp p61SMn I"7}2y6yrV$ >nw}ə$ _1c8IIr./L'BnB#2M> I@kK!I^9QO\gBN@L1sM~ Ip9$)$639 K)WyS13E>HwUTvT'28RFŽlrLF#+Dɓ3I@r})kJIjR#2>HI3 p/{4p"$ pqdc&8 K!IFEx !ϥT'ߜ#6ZCЬwt~kF#'8AϏFjH%j2nwhmoo[r&SҶU97"lI:Q6U, U Vioڿi%aUT)#j_ZdZ6FO7Xn=¿a,_1o۔Z5F_T28' Fh>E[Lb2(w&xUT.eIU4'g>> X]TT8ի5Jr͖ @ۤ"]p YX7C{mlB0E?r4()'YMU0bw=6.1ERmE<RT-K 9!i^d\n6I5D|%pw ŰbX+>P"0\i6#Y"QK{C0\SE#@+Y'3Gh ӒV5YHm.i~xx+&=[s?6ˏ6 `(A]hrТ`D-IVv?Gwh_EdEZrH*|;T,zi^ͺ <-(*ߘaT$ݏR8āK$ӂ=9D(QTlѓ# Fjy8<ˑ,51oL""X#E""8T™+q" 69yYto/i=RE7$#7E163>E IPc|'%, 6ϱ$$k3OL,>c.ᨖr~DWHh)8"W IF@ǡd`~IF";),+q& x'de\ы" p*~d(:/7j T4B|*al$]u@|A7sE?N#Qu.:Ggو=tZSȖH,x@]4+c8DǍ:tdGsH7JGfHDXNPˀ"3-z:jUH.A'G8C[8ъL‘‘b wND8~sو{+q"qE"7[\.23E/Nj8|Gt.;qL F"Wu&xC2+({r+r)AF@s?̨@jY5G\U-I-uB,I[UjB_WFػ -tyj4F̓jTiMm#ےvL#c޴uyο C[7#mXA2!)}a{YE[mߘK"\,an4&mYPR}AmP@&F NOˢS~ U#֖sV!HB<(#WlLaAAh4?(mA~wt~%Y&\JDZ8)[%#ycUD>or&X 2bo puaL+&y^5H}W!8ZdE9 ćDX*!I'"IIEE3Rp$H0TFBؘ ֆ8,O3{2W']@#}+vDې[M(#=>|'$'`Q*jPy$-y%'d"k|K. H2۠EVRO߀mJhQFp[lc!)EIYW.09% ܴP #$ h$^R8j"ř$ k$9f/ND&m`P\ L`(pكI@v7 'T}Lg8w[15q&11<++zY`S1)y%Зv D3l$<N..z!3ə$ 3XLl''I"G3hv`<9D&3y(f/ND&!;OL*ÙfN$& ^V}L'YXI5L5q&11K*cgIxJ;4L49q&11 &H*&7΄&'rrE+*\ыI~WLg27cWDɋwCTh.T^ yS2sM~|O\\ =P L69r&7 _*8K!\oM\ x($2>M ^ MLчIreUn"9\gCwH>D [w*9 C72,:Uɉ-z$'Ctœ.6M.j*D f*<%CQ!ۖhtd\!2Js -=ŗ|߸/)y̭o/|#!Yf-!=a`ATPB[ R=u2eDHܫ^\Tr}a[T Ih7tXtpX]9CXLR\22bݬ& @6#f8X #ۃe7ƯSvI >?4BoeVث~V鑌Kr֒k`'J.Qd4#>J+O|Wɏ#ipN8DGWXh+^tUX 2M^Ǻ 8Qu6yrė!Z4\ޱMm#d!㴃s>gE%w`68:լ9r 8UÐ6a ~<ڂPD'ɮ[‏MwLG\,4Vv,-E_naqZ3bc1VH90XYKTPEy$9r0kc7o*Ԋ,><3_^4 ֱ t[h~9Տ 7ї#CQv='BLz27;dot¶a0'~ϑqugq܇[b3s`"k %cʁ1zs`9!Ӛ9ˑe ,(ad _uo<8 G/Qᕓ*9r䋾p&E ع܆}` Э 2tPdje @H jbq܇oq9K g"bqEH@ cq^ ݏ9g^/&Es_i}9r`w/6@VJXIC7sDV:WˁCOGM"R8;׷ћ#N,;XP,W~<:pF,78P[DS?vj6y5&)>.E9oxb3/Ws0Hf-_uAXwW[ϑe',8[f>gȲ|`$nA] ։?;Ɓ%nxZBo0̳ood 1,1/7v-!#cd٧1#EZ6\:cȂM4Eh)KAO?9C# 7ű#N cȁM)CQ蕛|W|] :c 0ɏ7^gL{K9`;F`pQj[?,,g$Wm\ʜtm9o&$Aƙ$fa"b$4ڼ 2\8+2%653#›_*7ZEqfR=YDc5heT>.4޽v.i/|,%o2vwYŶC~(k$CJ~n$= Ґ񷼭0qf[]-vKyiv}|3TIk[߆ce{qƈ[⇶ѲbK$ H#mۥ]<fd.E<$wǿvhwĘjڝv{>/2ҹ y:r#m?ro??4G/??|8O+?A'-so*3$0w7"h8F f_ O57c/wܸ"ek u|O" OU2]Ǘ*"*iț{@dF5G[5Q\`{ZRh`VA -Į3P2mlT1Ȯ#-IlSK{rr1RjmK̇BMLʋn5B"Z}~x2uֱZu*p^ףsiiH(,ih)aj`̖ DJbz,2`-Q< PW({A)Lbob iEyjT|IM[UM~ D j(ެM,Sd$zC/Q%%%*s R, VS!4SG|RWU?7ͼ $J$?k%2Nn-j%+5~xYn:qD=_6I,$ds$-bmUaZB- puGZbTqp{]+:se5 PȘ]$ ppcn e|lWG2uHTUB9WF"`8ׅ+/r*t>L01FouwR}U|`\#+' NћkDEbwDb!0NKD@UHT.T&?.D*Ƙt&6J  @tѕkmD,UnџkmD}Hael-gZp4:cUџk}D]  oRdF,ؚyAE`:=VF-|PQPq-cRq TV`*DɟKeD}HwSmD q(UG8C]QڤVpɕ>"b!>@sqпԈ,m/l 5EVbZU-&V`,* ,*>u3}QĴrȸ#F6"Xdg#hz>yd/`UEK[MP%aO'9F"th$j<f 7j*̝HB;0A@?wrh1ң+4ϮyXk *:@Pg/~mST@-(/Ѯp1Φ  A KjRmC#nZ̡ި!֠@ XT|{6Dִ6`L~zFiOlݸ1d=j6 w=3:YT/ P Ih_*U ƯbG֥~i}`7tPb4?y,!q7TÕp_Bm(xRPVx7n'U3hA mA>He@|2$^1A{^Sa\>W#^2n_WBU@]YOA2UZvqM ]U p?ʋ ڀ-}i9 ؖ/Gm`6@pk;qNUl:BMuI5^3ZbMPeF+q xnʀZpiJ u$24;_Bk]>RIBu`ɥ. `MҿԂ~|'׺:8P_Zp;ɛKe@$X;M]p !rAl+ܹp233˥6` ;aPEhy 3:jA=w|/׺;X\|r5H _iT0s~p jMTm,[ZSp2kwŲ3͵> ë@L9 ɥ: ``45eUDO7u@\;dY~f~N i2s^].ʩin|Os3u C}| εni1rҙ,&WU:W6@Ac\*C ԕWl8ys[ټ*23ϵB >djU7RfvCc_TPa*'e#ǥF+mB∭zd^\MݏGu@c|/u`YڂX&`~0P!xsp s4|}PGc Fji~fpKegɛ U8LPEΧ7{rU9%*rZ ~靰DrB}Rj*e~D 7D%vVͥ6 >n&|E'_k(ԑYUl}D#Dok(\a1}@q溂#ޑ-W?EO.' Ti~拞\O)Y-!_EЧqJa,Rȳ9QKJ=;ɟ: [ž3IIPKoƣU HݠLuN`~{Q\tƾu-h\8i Vbyd=N\3`g.i&fi#ZVѣmخ}N+s6NR1-z63}_k[/8PfڝVxnt7O$z:_ݏpvܽ5&) l#'yMG{em}.Ò~7Cd6ɔ,h-F%`^/o Ml[>udjeH`J}R˞os:i鬧QUE+]R<їmq:wf9&^6~orҖlh!?f/*\n;ԪOnӏfGW9R^8HǴf[j/bɍV$o>m DҘ$Ra|O}ϗ,d d}Y|(\oy~0Q_ Ⅻ(Ƀ|AD2 ɔ3y|]8h> ]1un^p-;TȖ-g~\,EƘ9}eЄ|2R=x~ /^(z^F('w~ xmJ3qzZ򡌂0;/3fƫG7<} Yz׋˧c9R^"m|ySc_rrɘΉ<Z-La2'o~Tѷ+jYzs'o~oK 3N@ׯjYFO' fe^P-GߨAp'o~oaJ#kZ'rNo3EFvKETͮ*Oߺg[q|6zA }cvvojFm`FcUUm`m~*ؙ!Wn?з6]Mq~wFi#4I<f_~fGaR+$k| SS܃,B7,=p5K:5Ț/\[!OOɟ_遫zz9Ws318yL@<W@?'Yf 7O 7ceӧ5Yf>I.~{=MOnq@N|ѓ遪Ryrb9&ꁫz;ɛe=DjGrGo?1%޸V|<1޶|53?[O<_}ش[.WRsտ c$XlKUmՑ|I|m/ʁ03yf+vIusdiO}aYF>lomW .,`ӌorMLFkg>^s@`S'[>1?rl]BjZU%jmH,oVϱ͖ⵇ7\aA,N=ś[_IoHi[891oTtpz;{Gsb1+-?mI 3۰tAYpfzfҗ6^4h&>%%>El|ߓ3[O؇/_#-|xJفi&>mO-ȧ۝JX*&GQ/mͮȲz^OQ/؀}xz;zMqERqJF㠁 .fdHDI [2^WjQ{9H5:weɳ?=<Ay[`v?Lco `_ 7txQj YEJXbF$->E .l)>Q#x-:[ o2z/x\"~I+h;b0yeSڱfu.Ϛ1?gRT;_sa2?:?*E$2"'ʱL|)G8d|TJA YE7|2mB>_J((<8=Nf+g{ŰRDf(<ߍWƟ';192L*Y&&N#cbwP|KG+B'&ėK] ?"{bvH|aҸ⹋'C(o |ZI܄S*J_X OM?"AoE\u+B'>ė+M?"{bE(rEsOg¤qsT~bE(ę5@ kB;|m ?&{RD/E.X ]XِGrօ×ErV"s}Cru٫+vE1<_2Q|i s,7ECs,_q|ae(wFJ&/, m[#D@J ^|am(w,`U۬c +C %+v]4wQ|ae(2⑓hPxvXJq ō],w1|ae(\1,^)ncІʀ>[.¿6NtEM_k ! v8Sq+'8bכ-W좹 +g8yWpD^g +g8{WbJ.7&n)Ef<WN7ۦ 𕻧{ݓ" +'9zWemU.]fh")޳"E.7g$ lS K.  ^jɍfҋngNn7b]?sz#lJ&9B֢dbyuJ,__4xzo)cGL eJhGnyl]1[0ެջ{0J1TnUY8go`Z~26ٹ]tE9E[m;Xƪ}6*0naE#aOӚ^Qm73px-/~n ~r!fؽx\{zl}fC=Q-@^vʈL)e*'>8z]slO=NyY,;q4ϕb+q;jH?ӌ]kA=1q.+fm ڟ챊ɕahU_wM;(+&Bܯ&X;{\}W.W_{G`|=˵ƾ2k1N%돰6}h`U$[7vDK8.X~izc|zr9{@|czM kbbe7f&?oZ_r.;=1-ay{hzbV(z9K.gpSy1*qo3ӫGp~o,4ؼi1u(NL&.{{cqE@ܽˑܤ6_{czLGEk,37`&Y`ige.{{getڿ˫\=ڽ2S#\&Y]$υN0ut,DMA>#Y0r|g]v&e+.{{_qkb~KQ܂; *C ˫R@ҍ1=XYGiYm\&YDiC]HL$ʯ9@{g+!`&Y>qj-.E.scw }htI>X6i_薽* =}b~+'%vb9eڅwD9w!\=}DZI*ǭVJ(>|1Ob]>:X=^m>^ '.[2ǺjŬ˪N48|(=}Y0rUhICkJ0rSWaS7F+gv9EgN`&>9 p;O3H@ꓳ Q!X>:]T>90g^ϯb]-ة@nk>UV_Ϣ䏱hHYv,ܮiY4 4󳅩TLEɓ{j{5<ϷhE[6P,7ZV[v\6;M9g6[WKIYX'Ru{kߺ=[_w-]OGVfߨ;}Mܫm`}Z |hO-أ}4?E5s}jyb,ha}.ڬnکiKn^1Cքê'ڣouj8[.k ܌fŵ_xFz/s2 G[ oP1Nŵ_/CXv|j1ۀ3ElQ_Œe$5eؤ]mlNK9,Z6b>˧=iF==||m>lc)`zr&,KZXF=m"biN gݳߦbU+T[w]4`=[ o)XF>{5 ߬e|Ndg5vqE}q|lz.7i'7iX>m*X4[ȷLwM)!~z6.~ŘB=Cۦw]4a˚FGMӓ^gPQuJlHD>{~SwTʶ-;~ 7oSL[w]46vO~5S̱ |v$lԩ~ |+.ayTR=)T-pџP}k*>m%6Mh>~!}ZOƦbeoe[wz],CV/uh[b>j\y6 NSGϊ],g [[Q[W0ӟs4*O>m*v:I1G3+4 7H6UW[wz]$#>,X*Oz)^Ƅe-\*hoSY9R/`R33?~ <7svO9W髄&b5nޒ=oS8Co^-ӟs4C^׸Y{ž"q)`K^-z9!^ԸU{*mbEztyfgY{TVáۧ?)h^58xm X2uOz)>P|wz#՟gM:j$z)췩9Gda̿뇶gl&[aho0 ġڛͧэo@n'3 [,glZU{+sg9?7uXWso֬mA3ezU;,m.0t#:l[mˋ,mkdO[9 sǟK,g"- v-{R{q*@նkQ{uOhGNoZOx5dӋ8ڻ}ʎ.Gemq,>|37Yg>]q}'pδI;8O$HMxGd}uoШ?9{&sM:eIp+vW5:_m+юmyx+=rE: šE5~T:YOF$tFaNgm2zXuq.L()}j9|-SG"yżx]DrV_ ggHV?ۼWd}0*lCf0YO.Aa2$o{>zxIi1eW#RMٽ<{^A_vz- 5[8:ȾOGqhL 6 o9(JP=i8~r/{ʥ#O~ݜ߃AQr? eb܅Z'~<~۝v:h%z#'߉yO4=(޶2wvsw"0=Pˑ א^=Iw9!On-Cz'STީu ~!Po!mz#6{9_ٸ^jx6ůV-AߦbR;Q&~Ϙ'֋O=`,)h ?yFqrIg.!O>mlSSgFɰ>{}hsN1G3u)Wն iv!O~fqX͙zS|6vO;ˈ'& s~/r(c^63ݶybe73;ϰ>~K# 1¤FJ)1ŧW鱕(Åb:O^''AԳ^ɐ'P(WK-z91O^u"L=)h ?m*O_mLS בMzi )X?ym3ۖY.s4c6[.5sTE+簝L0V晍&O:l[xWšk:"_# Ժl+ یq"iӎgOV?B`۟/QOWhcBCHF-Q=1y^Y*ԹsOS+,MX}IFD߯nh~ ^ϟ'y3a`R%xeTgm4%yۼqI=1l}[[|~G a)CkciB R! {x4d*k@SE` MN? oE (;ѧTlx>guj}_çW4ͯWhg3O𝩿&z}}QE~͟"_y fJdMl?~Fm-|kQnNˡsE+}]kj$-~6IЅi9!-f&թ&NJ6`ةž/l _5,ً%_К ۣnܾj鑅UMǎ_t=>{ ȾOljݧ5sv:Y'z5wr{8(zcq{lwv1z4Uq }vb6SKbY eHߦrjAך(zVgߖj==Q3$RN v5x>q֩H-&x0>ʱ|Z]^>fT~0טLV]z]$iXMN;.!~*=DAg.!~@1sh>6Ըi[9zV̱}jXYX>6cdK-W9^$1KPNfDŹ}mOǍ+ߦ23RѳfϐgMj[l9^h>{mk'z}$#n}BgGw.!^j;.a}Pٔ2DcM4=+v kkS@pY12k@I` +.n ~5,3+4R8b_-NR!2IWaĬ0j&b5չ=-=og>k)^Cnf 뻸Xf`hpl16@B~2,?df9?]#쵿V}Gj{-g^kDY^?}1rӗ}wWjG=_FoΙs}LZ~-ʼneb^nG-> x:Y{_ZU_3Zq5pk;_'<#V/6D~Uf݉|z뭝]_V1x6KU6S, mAˆxhC ! ރƣl֎:X<F=VW܄$`)C0Rkk2ZCa;KY[-||Utf>jvɟĶYnKTۗ%V(R}EnݼCOl~|ƚ,+E7x;K1-e}Mk?;| T˂}׼یRū*: Ne=F 5 Y8Ak{|Lk/9}KӒc㜞3;Gq|Ո)=@>4n;(}S)Vǟ3zwc,gcW8'B}-B?=9.},\Q*xU">{{m R?iZco+O(rպH>m*xnnb$E3dq|Okcc"39^HFm Trz Zΰ>m*^1JܼSьI{m xacybi ;1N/2+4b|DC12k|]v9bfߦbrz&KzgLo X\c˹y-)k'͘'MczҜͳbeLW#GRk?饣npz1i5O)!O^uυXI/2Ma5ˁBbeD&a> #֥`fLߦ=DߥfgLokk*w91O^3<s,cJ~[jLr،͓^eX_߼*ӷ>֬RLGצ*(2lۻ5yṞI}4PDQ-a\*hƤ>}S#'cvnixƤ>5P25.!Ul"ؖWH}P@#:/s4cB^u^dOSp:OĽ^uqؼlw\zC4\ dHצ9GVCdI1Gy&NLt<!yfIIl~{jWf8o~H}kkU|@Gf6qlUE|aƧ2_l[>Ób_5kcl';jc6Y{mvWo?LxMAl4{(-{5*lVd-7gg},&-G_ڏJrjnsڵSUV]m:^m^wW<7mlW:wiKs]55~08^xo)eb\;5m_^kò; G3~ @CY΃e,P[X&}v8n`ۏ0~/A>SWfbo[Lx˾ѧ,|bQdMSTj"aۺhv;,%xƇ7,uiYŽVp.q1[:J"]93lt21b >6g;nz>v-N[|:f{ww3Ok.nnW`lq3:;3zt&C1pOnOSo-͕a;9cr@ t܅ <~ +f>k+NHn!R8="^9Di|b {x*@T0׍ǥf?OH~$փ=.s4)XGai8*XצaA7U1G3 Gn_ЌiYƣOpMAy̚:be8 y~c/ku](hߦ޺617)idgܺS iߣ'n6 6 LWp|cOH^QA'_cy%Ox;9m ]PƓkSM⃵^R$i緥0W81H7&*VN> Wx"@m#6Kzm~Ϝ 4/Q7צT8%+ҟS,ÉkӰV$gG36m3[鏽fg< ~c3.gԭi6Jp5C`x +̫Ӕ!'Ag.\h΋ QSR )_f =8F>9}(vp/!|&lEy̱ +ׇ%7ήcg˰@?y}HXlJ.y%cH^qV.E1c;gX!R#ޟ<>[o&\8q qS)m.Gs,O?y}H] ,U,E2:`BʫV b>~'.׍2y&চ%pPaU :V\1`! )bX狅h[Yѓy<$~~gSg`Z55Z=MRsXӰ=ǧ2_lDMi٫g|mw*_=y&A36a :^ =Ţ̱ _m>\(ß*$s'ڟ~=(g*7Ry8*/%8+UlrrU*OWolb̂*^_׏TKUndؾbCi@U!aMްD7sim'MfJ#dw츁wW|4~g6 1Q~ܲ>Uh94#mLtXpU/*kOiedɩ[hrEgC@W꠩IKdY6hOo:&h)PGr}S\Hx$ alD׎J9,XQhG-m{muO*O^Km~tD?t>Ťkk]1/܏l݋+ؾ*W^RG.o|9ͺ\ Q?'`-?i8T^A}wG|#Hj XB-q'#|} F|;` TrNeLKآ C/q'x|]Xny_@xbw9q~ *Fj]9[T^~(ǚE^./M)\>]OXs_4s<T޽@ڔz],7ug4j~Kq!ZDTaq~4e3`xwʐՒ^0)hnQyx0GPHb2pj1\T*߉u ^a5ʇ^O9 FSz9[L^~Wa['hxn1y_5AIw9[D“s18}QLG!ܷWY|c'K">g:<'/F|L9r(wX6?1@UPJPy,XZJ.G2O^ Qoς9aQ~$ ߞy^u y+G8PS7X|e^r$wX_ru i$>g*q:|lɽ\o#cYVc`3 ;t ">M@ʷdI.Eqkwks:VH!AH|l°(r9ɩ5%| ԬWz9CbH+W# `,g֘o *i{kGᠶ04{fYvoh&Qv%Ou+eڑUBM'=4[@%_螖tм ߲ s|-N>uz0Tm{_D܌~F6 DX??}m0ξ/Gxr|xA=}i#_ҖZKqj_mdϣY܀-GYv,F6+,u_s[W K/Nz*Qm* g(l=y !BisiJ U߯?Mo%[{+~wOOE_?F<<k9m:eESiO]|I'sYVjScKAiQӴL"g@}sg>C3'@N‚YZzJ,WQ[o~Gݹ">ȳrRVC{,y.ݵuZI}E`qb&zrQ v k+>#-hY5,ԋLrƒ`RmK[t.(BWzdiyBGs3f3 ]n?am+m=Y/yebkCZnn5up1w Ϊٷ铯P;[paֱ`v= KeU{>䜷:VF`/X}=mB~4NuCbi?r%ys_ybV~Ey]09OosΘ '/moH}9NӼy3Ҧ,˟"< endstream endobj 3 0 obj 128439 endobj 87 0 obj <> stream x  o&1 endstream endobj 88 0 obj 687 endobj 89 0 obj <> stream x Ź?^ ^D- QrQP/` jP*Q\P r5HpQA-B  Μa6Ns:]]]U>Vԩz-+)=;gϞgy7:묳>^z{{yקOo۷_~߿^xE}0`K.dРA߻K/# <C :taî>|#~pW^uUW9rԨQ?kF}u]7f̘c^ 7x;nܸnr-?0a­zm0qogwq &M뮻&L<{wʔ)SNixӧ|衇f̘#<裏>6s'|r֬Y={SO=œ9syg}/s}_yϛ7oxW,XDž kozE/~oɒ%??K.[l!|駟}_W$ͳ.;㿝lrudN}ْhD{ylhG;zu폝l˖D{/}։֓L'[_O;֗-E'ڗ*dD'['}~dIwI{莖l/.ml:ю^nNvmg[,[N󣗭N+VX);ٮqFi(w\Ͷllho^ʶRNOQu-+[7l)ebpۖݧG;۠ /[%ى*Jَ /[7;(Nq *[;[ YhPP$[ޛx7h,No'SJ'Ul;9NjNjʕ$%=O?ݟm`'OD'5I][\ovRʖNI-vR*.z;JefjpοFuRCT mAb'uNʉzI-lܲ]jdwx駝F˶ltRlNjQS6@6@N*( /kֈMjΐS|NToNRJýT P9JftRSblB=iS$_R:) Px'u+$~K6@2J'E]E%{b.8lh ;b'U(~'5I7@N*IFsvRي wݔ>ўlCTSwT/zUN/A'۵"=S*9i/ۿNy;NJ_vZ!6|Z!*;^IREN*]/۵  O=XTrNJJIUPɋ"l|N T0n|}pwRPɉ%IECyQ*9?NDn_NcddN._OJ:WW%sR\ʠlwPʨd~bfϯ{&;ld6 4,P^J~:1x(IvÆ c*T2ϡ|ВLdTrrXv]O%f˯ebz(~(C%UɁ(Ih7n+dd!L*YȡjpB%e[]olg. m Pv:T>ݻyÝ.tT,~M%?dC>VB ْh aduUl{/ SH%d/ܙ2wT]4.Jv>pk+LL%˝:]%f,dUmu1ym@ԟ:]%v?_s$d<Ʈeȶ"!L*Yȡ,yDL\([;ۚٶ JV[%˶ GsUeSa:)'[p[K`,~hfwTr2S'TrH'dn`dUr>ha w KK%vRA*_1Tm>Zp_7J%4XJ&l;A%'5u"谛mIpTXFUr`%*[Gjf˶20f]k뎳ek-` E8ov1f{jdTrlk: J.m]kdž㩰4 ND[[ʚeQ–lkdG% ߕJvofA%kobv# K0fdx9ۯa vU:m}# 'Z% :!uTN A%롒NY^JC%;ep#۽`8U"ٲ dNT]2SU2|w 9l?I%?uBJvmaZ։PZ|GySa*<I5463¡y?bQɚ=FSBwnlŔldپJf?w˶՗@%ke#/wTA*)ۦvlW 0r+y7@)BuRN?XȡVlf[=eNHUZ<FSN²N8,dJTM%;)7ڣ| T*͖W5ךTS'Tm "cw6B/7U%dJvmT*9_QrYƟ Kylyz*I%vR NO&,U`c!0IE˶dUIdkJΗmK\W-:!u]0f+ۈnTW%'7uBJs(/Vv9^0Urls#:8]tRZ饒NHl1l:\klJVX%MMiP*=VB%xL4XȡLm눗Y 0r(/^%ȶm\*YSaL*Y٩*DgJGF0U$8ryBO'ESN]@**13T6!*6 *Y9L&;TyS'VL]4SaI0VN#EJr(ocʡ]@pRɤlE.>fJ&e+MvQ~W֞ g+rNTP>$wւJNA%:)amr!\d5T2Y.x*,ͧ|e)MvcCxil- 0p(J&v uJ&يmԉU2)[)Zj20o o]奪d!4,P^ l-Urg6*9Ulg+MWy*;eRi 05JVP^ԉ=.1[KJ~*e~n@%ɒ,7[˨:Q$kpE 0Tܲé'7X i,pSPɤle/6P)䄲TXrO;?NiM``ԉelJN`DKr>\LHV%*y*,%eO-p3W'i] gkA%' O6m]wT^pU:`\ÅJNB%'$@%'X0Zm2?uBJN-[K *9%*YJN3[ OIRn'YTr*R.[S'tPigku:Q,TdEUOmRSa2wѦ$H8d+Vd*Y%@%KPJ-O|*LͭCy:!uP^%@%ˀJ6G%Qeh0TX408 u˖,J%V.T^ߥSaj-AB 9Wl-;\dMTr\E6T~QxG,*9QB%JVl PUeKSaU"I 0T5)[x,P>}I_(*Y%@%GPZ-O)TXt0us6eKJ;קl P\*Y%0U`,~ƅNJ%@%u/[T2J֮l-;\L`P-]4,~eKԉpgCUeKJVc29uC%[Tk3uB%eLкl Pɦ-O:)˖Ƒwi_,d ([TrJ6l dyOQ o 3u06eE֘9OT2 Mn0 "p(co'e\$\,uT6uœd;[>.x* uqCyW%uɸJ6c뢺JT[,d?.`lF$+S'JT;[?T'C 3c,*EMJ6|g'c*9#[ Qəغ$si:u}KYܞKVTr>.Pɝغdᩰ}l]*KUIMtUrv~~*,}Tg*`JnnUTܕV{*LJħuQpqCy|l -bJ֏QOe,~cQm9dDO!`y*:um *Y 0tV9D[ U2 AߧrQa(;u"d1e@O܂hYQ%tWwPݦN-;zdD˅N*9!QPV%ehe1S'ZmtPɭj4WmTTՊ=u*DYhSam8Ӌ:؎hŠJFP쩰 &f JFQF%7WoQC%p:  öVqN`X)ZIU%c=KOa=CyJp(8QX 8!WGrER$|z CM(ɩX&)\ߖ4$TAǩJzUr=~rU&\MOz.a=NI*HQɇr* A%c=VC~(lb=V*y#$ZR{kq2b ;]"r(qUn,O%8Xab=DUҪOqD"l]+~NMX5C%Wb9 f\X;: 8];zZb9֕*yw|4BGzC˶!lwUBJysvlh͢C1i8V> stream x1 g OoTA endstream endobj 91 0 obj 688 endobj 92 0 obj <> stream x Ź?^ ^D- QrQP/` jP*Q\P r5HpQA-B  Μa6Ns:]]]U>Vԩz-+)=;gϞgy7:묳>^z{{yקOo۷_~߿^xE}0`K.dРA߻K/# <C :taî>|#~pW^uUW9rԨQ?kF}u]7f̘c^ 7x;nܸnr-?0a­zm0qogwq &M뮻&L<{wʔ)SNixӧ|衇f̘#<裏>6s'|r֬Y={SO=œ9syg}/s}_yϛ7oxW,XDž kozE/~oɒ%??K.[l!|駟}_W$ͳ.;㿝lrudN}ْhD{ylhG;zu폝l˖D{/}։֓L'[_O;֗-E'ڗ*dD'['}~dIwI{莖l/.ml:ю^nNvmg[,[N󣗭N+VX);ٮqFi(w\Ͷllho^ʶRNOQu-+[7l)ebpۖݧG;۠ /[%ى*Jَ /[7;(Nq *[;[ YhPP$[ޛx7h,No'SJ'Ul;9NjNjʕ$%=O?ݟm`'OD'5I][\ovRʖNI-vR*.z;JefjpοFuRCT mAb'uNʉzI-lܲ]jdwx駝F˶ltRlNjQS6@6@N*( /kֈMjΐS|NToNRJýT P9JftRSblB=iS$_R:) Px'u+$~K6@2J'E]E%{b.8lh ;b'U(~'5I7@N*IFsvRي wݔ>ўlCTSwT/zUN/A'۵"=S*9i/ۿNy;NJ_vZ!6|Z!*;^IREN*]/۵  O=XTrNJJIUPɋ"l|N T0n|}pwRPɉ%IECyQ*9?NDn_NcddN._OJ:WW%sR\ʠlwPʨd~bfϯ{&;ld6 4,P^J~:1x(IvÆ c*T2ϡ|ВLdTrrXv]O%f˯ebz(~(C%UɁ(Ih7n+dd!L*YȡjpB%e[]olg. m Pv:T>ݻyÝ.tT,~M%?dC>VB ْh aduUl{/ SH%d/ܙ2wT]4.Jv>pk+LL%˝:]%f,dUmu1ym@ԟ:]%v?_s$d<Ʈeȶ"!L*Yȡ,yDL\([;ۚٶ JV[%˶ GsUeSa:)'[p[K`,~hfwTr2S'TrH'dn`dUr>ha w KK%vRA*_1Tm>Zp_7J%4XJ&l;A%'5u"谛mIpTXFUr`%*[Gjf˶20f]k뎳ek-` E8ov1f{jdTrlk: J.m]kdž㩰4 ND[[ʚeQ–lkdG% ߕJvofA%kobv# K0fdx9ۯa vU:m}# 'Z% :!uTN A%롒NY^JC%;ep#۽`8U"ٲ dNT]2SU2|w 9l?I%?uBJvmaZ։PZ|GySa*<I5463¡y?bQɚ=FSBwnlŔldپJf?w˶՗@%ke#/wTA*)ۦvlW 0r+y7@)BuRN?XȡVlf[=eNHUZ<FSN²N8,dJTM%;)7ڣ| T*͖W5ךTS'Tm "cw6B/7U%dJvmT*9_QrYƟ Kylyz*I%vR NO&,U`c!0IE˶dUIdkJΗmK\W-:!u]0f+ۈnTW%'7uBJs(/Vv9^0Urls#:8]tRZ饒NHl1l:\klJVX%MMiP*=VB%xL4XȡLm눗Y 0r(/^%ȶm\*YSaL*Y٩*DgJGF0U$8ryBO'ESN]@**13T6!*6 *Y9L&;TyS'VL]4SaI0VN#EJr(ocʡ]@pRɤlE.>fJ&e+MvQ~W֞ g+rNTP>$wւJNA%:)amr!\d5T2Y.x*,ͧ|e)MvcCxil- 0p(J&v uJ&يmԉU2)[)Zj20o o]奪d!4,P^ l-Urg6*9Ulg+MWy*;eRi 05JVP^ԉ=.1[KJ~*e~n@%ɒ,7[˨:Q$kpE 0Tܲé'7X i,pSPɤle/6P)䄲TXrO;?NiM``ԉelJN`DKr>\LHV%*y*,%eO-p3W'i] gkA%' O6m]wT^pU:`\ÅJNB%'$@%'X0Zm2?uBJN-[K *9%*YJN3[ OIRn'YTr*R.[S'tPigku:Q,TdEUOmRSa2wѦ$H8d+Vd*Y%@%KPJ-O|*LͭCy:!uP^%@%ˀJ6G%Qeh0TX408 u˖,J%V.T^ߥSaj-AB 9Wl-;\dMTr\E6T~QxG,*9QB%JVl PUeKSaU"I 0T5)[x,P>}I_(*Y%@%GPZ-O)TXt0us6eKJ;קl P\*Y%0U`,~ƅNJ%@%u/[T2J֮l-;\L`P-]4,~eKԉpgCUeKJVc29uC%[Tk3uB%eLкl Pɦ-O:)˖Ƒwi_,d ([TrJ6l dyOQ o 3u06eE֘9OT2 Mn0 "p(co'e\$\,uT6uœd;[>.x* uqCyW%uɸJ6c뢺JT[,d?.`lF$+S'JT;[?T'C 3c,*EMJ6|g'c*9#[ Qəغ$si:u}KYܞKVTr>.Pɝغdᩰ}l]*KUIMtUrv~~*,}Tg*`JnnUTܕV{*LJħuQpqCy|l -bJ֏QOe,~cQm9dDO!`y*:um *Y 0tV9D[ U2 AߧrQa(;u"d1e@O܂hYQ%tWwPݦN-;zdD˅N*9!QPV%ehe1S'ZmtPɭj4WmTTՊ=u*DYhSam8Ӌ:؎hŠJFP쩰 &f JFQF%7WoQC%p:  öVqN`X)ZIU%c=KOa=CyJp(8QX 8!WGrER$|z CM(ɩX&)\ߖ4$TAǩJzUr=~rU&\MOz.a=NI*HQɇr* A%c=VC~(lb=V*y#$ZR{kq2b ;]"r(qUn,O%8Xab=DUҪOqD"l]+~NMX5C%Wb9 f\X;: 8];zZb9֕*yw|4BGzC˶!lwUBJysvlh͢C1i8V> stream x  o7x2, endstream endobj 94 0 obj 662 endobj 95 0 obj <> stream x řF4B4Yb0&D@`e%DY]Tfu5$h Μ33TOtWwU f9o?S|9\8 G*i=S F?sE$Rz%FFF?>rN+7~ӿuȑ?(;zӮpZr#G?eJ@Sф>X 7G~9C(=L@ihgH(4zNK3zc3Y#ǎqFF>'Rx3ǎ.G=yL0ޣ 3ͳǏJx,nQr)gYpN(=ҿuOpZ{Ѱ!©!`zQhw?23vdBiʐ V&]B@Hidt`9©8cOJ##_CHSCw!=G8)nR)چ71r&}Hx9 W ^ciR7wHp }`H(Lw9 |kQw!=6ڂ;>rT*ލF=W!l{Q>>)<)=@idTj9z]!=p-/T{єhHT 8F9ݾ(4憎Ti_8>o7Vi)=*-G7 h0r;e7S=n~8hWlxKjH0C47_oP='R*{}70@idTj9ǻIS:5ϟizI[Bé1`F1ˑlEJor\J}DQhרk=)=ƻ쐾&?r6i7߷!UC*Ɲ)w-M* w6Rٷl1Sc"yMQN FF#x70zlWyUqc!UC gtY4ƻᐆQh}߾$<>пq}poOijSLt߾}/Q?#.;^S!&©J !/ލR? Nզoz/kwW:QhtGQQH$w!ݻN4Cj"ލ4P"ӨHwF"etϋG fYrĻ)g߬ҽݻ ^1TSIC{.gRrrD)("8Cj(ލĐ?ԏĸΐjwg߼]_NSZfC8H*hO 9i78J3?Ļ)'ҌCڔ 9p!_mwQyS>D0?N()}9'T:CTU]vHSI&4GڔS! 9>ڪM(atfkMrwuǻ³o4x`Hƻw_ycgUYp&C*!QN3!-G:ov`;|8-$J-G[CpR+Mx42iᐖ6e[4mHUd]-[4ҁj(etcQ?Qj*Mn(4Z[w?*6]vHM \)g*ݴNxI6.GO/G!ݴi#%_tW\gHCs2WDno9n#6Y6ǻnglH}SŻrݸaC jSϾCazlΐJ}r 5r*TD.;I"ҜߊĻJM݄G~ֆHRTxnu8R&xW+]GMs}\ &^BjT8\9etݺvvxצjSr]Cԏ\3iCjڤ*eϾCP՝JuW\~QϨN<ǦxWrpN*uզ(R FwHSmƻr1~)[6ޥ6ݤ!5^mw}wFxk!R&xWٷ(eJ: iox.Gџ16 },G9iMˑtڵ?vm4Uq݉w!]j9M2\9M*Sc*&~ۿFt?R x4p_Y#n*xr U$&QkT*zsjSnhtjjJwMWξCf*j*QmJ_VU鰳onz^=>UR\gFMݤ;wƻMx7^BIA\s雫2ǻ{Vm*ts=զ!o0(4zoTdoZmŻRgx{]Inxզ7@i`te+VmŻ쐮\j3y Ud]jSLW=Pɉ+ޥ6ƻk!NJG)}9nz<޽FWj2ǻ쐮XԂqPmw!wS%ݒ\%eξCzw霺]s&Q[ڔ*u$9\9er9JZm&~ړצRTdJW"kl$wJƻξyC+-Sn7We_VtwRJw&QeqVd]%&x7p9 ~w9LxwĻZoJ?w©[jx7}._j_pJ}']vHQ&7WewJwڮEI6A_/G,VתZI6r,ܩ[j;;QhtRjkCq]&7Wew!]jZ\%-FNmmT}stK #&xWr$列}JEJ,)T6HkU]vH,ڝ׺j2ǻI:u(M\u9J U*;}{1>T \%-b zBj#Nŋ Qm*s7FY5^m*tsj7wH-7j ]˪MiH…YZ6w!]hSY$*6ƻM)o0!]Vj}JQm,G}Cz9Pj$VR[&{zMjuxc[UvqusU!Q.Mr7`ڤ* &QK:M*sSzKfj}[j/G~fn*U) 37഍jSxқo筴oxzզx7iTI6ޥ6exoɕǻ&xWEJ6kpsE]7z*UMxH*E)G+*t:imKRmwy:̨7M)CQ:w.@ћ_mŻΝ;NiHUǻIDNFyoZmwh^;gΜ)wWmw9g!J]R7WW\~=F̞MmT檟w(ٳg(RZ(MQ0gwUjU ]s&x7^t֬1ԱTxWpݝ5IwUmŻhi7W64Udx9iiUZMxWkI6<̙_3զ|7W},Gљ7`NSjSy( :utŻ&-7WewFNiYnexWei X*5ԻjSjSv0t܂jS)]N;1z CNV*qsUx3و҆xd檌o0Q:J'J{sUզo]fHg\w 6UDjl+_i7W8Y!>]VEMnUm6ӧUvMnRXmŻr*ZJ9]&QU25WmCznyMJ;AhUꎢڤ$w(4zVy&xWII6USm+NEwĻe*s/GkZӱRU2.;Wtz7WVŻJ}W]Mi`7W6]vHtBզB7W6e~YrV \$wciӚjVݤR=N[զ\%Ym/G-G+ԡ=4T Z:#6w(4z4JݳMH6Zmw!bz9o\U> stream x1 go~Ht endstream endobj 97 0 obj 661 endobj 98 0 obj <> stream x흏ULP4 H$HDM0 IR$% @P4 D0Q;36?vw̞3g}|?wss%(vT8y?@G>~pIGJh ~|VomRPwЧmԇ~ 3x| |@@nӇJ!NKK}{4Pq۽FKW:qwҷ = ie{i/GѽoR !4.;{߄S[pGNtJŻ* 1m9zw92=g"t8'0(J-GQ0{Ae4e9&)-Ι!Fixk9 w/54ϜLR7wH_ki)=(,G h0r;ewS1|?9.pJAßѶRx_=.;w Ҭg|F)Rٳ쐾J#Rˑ8M*}K^)ᐦWD(4* fƻiQtPGNwLF_y*ͱ>C.;O$NU#]mJy(BJ[ORm&r0N5ƹ]7wHl* ^s<R?$g`i}IGUqJj9zr)LHyˑΛ2ǻ7OP?2ks'4p92YmJ]n~bCzZdgxCpڟg7m9tsUxQy3mt)節6[!ԏbfڐ6iN4JVƻ7w7cOVz=^6o0(PcpC*5usUx=)ӳi{H]&Q5M}x]=g]wഇgWo0r MR?BhٷjS!}Q8eixWiIQt#S itVmJyi}h}ԂjSVpڦ3qk$r#裾ч~6e`Wd]hcNCCjeIvFF@4 ƻ~ jlUaCڳYmŻnx!'JH-GզLAwRKM}r2j6w7&SZrsUwr9>~+6}U!-GppR&xrXw?*6]vH:Kcڔ3e[7N{xI6.Gt/G!]n-%^tW\gHC4eH-6r]GlYUmw!]5,;w7v͚r3MnJ?5AZC*umQ0WSѐ$w!]'m`Hsƻ-*6wJ￟Y"eHKQmŻriא6ƻg߼]_*mo0r]5NCjU]vHWkmwm6/GUK56M];VݩۣTwIUg_slw՟}M.GJwH)nRWmJ_"P?xm:&n/G-G ξe]j(M*!R&xw{H;Qh!Zmw}]vHﮤSΐ*7rJjq3jSwr)S񐖾ڔJW\ jqgF]g߭xҕ!-UݤJ9uo0n\mǻQhwQ{P+wM=g!]qe9檂gߝ!m/GѻVPPEb9Z_mŻ޵*N]7W6FW,xt;+/֡զ(PlY;檧n޳݉!]Nj!umڤ;M*- zWkk$w(4zϨ5*s?ZJ!lզB7WSmZBwiJI*&Q+u͏w!㎥^ wYmJy Fizb&Qҥ?6PI6ޥ6~;]jltTҗHj;y;;Qhtj?96鿹*s%?$3&x7h9 v!Y-URJ;Ω;5WmŻEM)o0R護RK2ǻZ.@iUMݤ[=Im*EI6].e9M_d]&QQ2wR_iy:vsUhI{9 |3dg\mŻ\JhI6URmw! MmeS$zsU7wHoZ\ nɪMݴo &Rx}e~+uw!]|c :VT\9M*is MOx9 hFժMnohN2T\%ZBR[#j6*s颅V;mU2Hiht D7wHްZ;Ymw,Gn7tQtk2JeݏĻ\9et p6*sTjSdUYHmKPꛫϾCzSѨHURh9 ηЩ(j6iJj9ĻΟ?`&2ǻ:Cz}`tuN]զB7W6}st޼P;LZVmJ[GJΥҨL`\z&xWII6]mJyi ܹQ{WjS7f9뮳iR&xڔ:-ߧ6[m*UsŻ7y-^K;X7W_nEJmqڔ;m/G|sPˌp)MZnPmŻαĩcT2ǻFJǻe6o0r5WIwsUM)o0!MTŻ^}UF?o}ƻի6ĻINM.})L͉~w}ߛM>ޥ6ƻ(RJ>7WW$ޕZ|W͞={j\$w!=iRTrĻ١RJƻ$&x7^!ݙdF1\%WmJҖҙ3ɜJ\Uj(ettJ3/G7WU?M*%r{sjl/G3f|Hl[jl9LPڔ7:ct n7W=P$ޕZp`HOFKiYn6/GNfi[m7W=-wUdx9iӾmZcY;mڕW*V$w!Ҵ&n_mJy(jTiCUի6ƻr6:ըfVDjl{ҩSeTV\~ݳF^q9T \%-G^aЩ;+ޥ6i*sۭ7ztJrsĻ*M=nrP)TVRt!TJʜ}i˧r:jT2ǻNM#Jk*]j2t/GL(+UVU'w!re&TmŻZMnƳoﮯt~u\{g9 tdN6*W)ېN J6JaIQK5+uNwVDFx\_饺:m6*pH{^U;jj(ލ%ZzWd]%&xWM)ﮯ:w)nF/bNGJUmkd]vH/ n6wF/HҚjS)n*\mŻ^XMnRWm+PrV \$wekjrZڤ*&x7TE|7WIVѥ]Qh t(m* զlCzM&x9 ?IRdjld9wVd]vHϟީwJ7Ww&Mr)Mx7C:ʝ\mwMyo1RNG*&Q/GѯVi}@nZmŻQTS3jVĻr=oJICզ*sy:w\m( NB5Wmw! SmV*0ASDٷl$j6ƻr R $XdoUҗH27WW\9ލ_RVwUTD.;~5JǪts&y(4zqTǻ\g!=眳8*UZMnﶆ4P=[\e7e쳿@ћڔ5M(=JG4\Ujxxw";g)pCIUg߼]_` endstream endobj 99 0 obj 5583 endobj 83 0 obj <> stream x U[v endstream endobj 100 0 obj 664 endobj 101 0 obj <> stream x řVB4!&Q\XٸHd! "hp1 &`J+.F 93nLOTMwuW[ܿ`S8fݐ6L0E!Jz{RD옾9z )T}0JmH9RRm"Ǵt߾}> T8JmHR08)Ұ7Riq.0NsDRoRZӾp6}LsoB*#xc6$٨7uCFU79v.uLeΆ*} R+=s*{Ώz1}_J_xCRv4p( q'FGc,etSNFS:}U/]m):p٨w/;BN܉1\ )rW_i4R*!F6P]_81ᘪz1ݵw_81Ψ7hC ׯ" *11}RM^9U{Jy J_~T 5>6ַ!z1}RnpToԛtSޘjzzw3J%HU;9>lL7)kz6] )TϢ*#RTIc"iHi!J_I8toCIF옾R 1Ͳ!zΝ;~$ek5=^vLw>hO4zY;:"8cj(}_ˎA\J;茩֨wa8w y 6$+6;RtsϦ_d^vLw<fS )TܳԏMޘ=F )r5h4D)!UĐ1UzU樗۟~F%iNsD{O)/2=*ۜLS}'ToSZܟ^Q0;i'Ud0Z?IF/#΋Ԇ$9 SB˛!*sWVf5niWqiȆ7[B6{Ocq$vsЩS樷"-RIH4dI"#ܐBOóW g#JE{O7O@^Wan~r7$"oH>RYc*unmLly)LGj{O7ސ"Q?FVulcc3tLm=eu(ޘQޓlݐ|[Bj-"$mH_S?L;H'Qu)}GcZިG 15{zN}iΨ"Qoޓ(eWk*mg1{2N7oԁ15{zcR<￟oH{O1IMS{O!u&gl!Y{>pZ3; z WzM~FSC|W\st}uSpW\ߐBu*DQ/;r#6E09޿zR^ƍu2=qxCƍxI69 Nk!m: *sې"~W\ez1pzG]$굪!J7__uicj*Mst_P?uNu^q~>4PJK^lH~S+7=P?ymtǴB'^oH1Rc; zzO7tC8{OQoΘRt]5c$=^vL׭9gLKyUކ*njq3Qa8wLﮞT񘖿![+Ϩ%(uzoHnH?VKjꘖꊫQoO=ȘJw2R?TW*=!Z{EIՑeC튫1mHһvĆ#굿$z12R^W\i=oHҵkm(&5{8 5=굤!N׬Ycj! vnW ܇u1]Kun=M:- Wkk$z )T;5*sӄrK ]qeQI"ݐBwRޓWZ{OW0\cz2KusG%=  JWAm&?DQ/;XE&/^ޓlK{"qjUY^ޓl{WbLWZIm'_q!ENWRɃUW\>7PR ʁhW^vLWvjC8u=IEw6P~Woɮڐfùcz+%IzDQoSʋL4PdR:]q9etŊ$'pZS֨7ۨEI{*EI6]f2IMd^'Qd;0;]N*3Nʼ!mH契?tIc|ee#=FJzO2Qo0ц*Vj]Ez^q~[!-YIUԛzξȄN}B-,n^[ ձDpU7{Riע$`~{KZU=Fyc;\[ޓ+6 )TzچGZ{OfczRJbC!JoZF-nmRùcz2{+ޓlԫdCzenv'q*~X$披Q/;nUk]WޤSK:'[ʸ! (Rj}\چzOv_q~.Rj"BW\ImH7w6P%Z^'-W\ImHӥK{+ )Rzctw&q ]qe4p%YL-1cSk[)eCZ9]2LF.^Zc?^`I6U{zR^d:cxMR}=e~a61]&c=F1:ZeWoW\FJt`T^W\ߐn!ENR?]E҅Hu){OZ{E.\-j!Sv9]gCļRbLX!MwUzO)/21]zjS E^=Val[SZԛtov85{z{O^d ia(:rQ/}I6nHSb\quoWjC^+?i{EΧ:gԫ$zzFΜyn6Jqŕax0z=)=ކ)u:=FJzOQS^ NGFzKU7ސ|W̘SXzOV]q-3szW\rF}NIm=⊫'QˎDzOR{;}kr:YS+DQo!ur]R\q$&NE{*W'4C N"=+tiipꌠd47P饗w-{zlHQޓTˎzdqŕߩk_S=iJkIQoHK.Q;kT+2G^V(}[pC ~yB +{z1TR=U,eN:KʜgRe^%'٨WkI6Mߐ%6`L~ITo'${ŕ>SeRG鯸=*soH/^iW\-*=ޯ&*:U+l=xC ^|iG\31"5RGJvŕޓ+2GјNC}A1\qe0cz(p:a2G)SHmtUzOKc:e ;uO犫pOﴸԑ ]q%{E*c endstream endobj 102 0 obj 5617 endobj 82 0 obj <> stream x  o783:/ endstream endobj 103 0 obj 662 endobj 104 0 obj <> stream x흍UHodx!)/\H/&a$Z^ XB[*^b$ZW"*5wpg5{=fZϚ/{gg~O@('iCT:{? 1~@G?P;:N!FFJ?L0E!J|{RD옾 9z )T}0JmH9RRm'"Ǵt߾}> T8JmHR0 8)Ұ7Riq.0NsDROoPZӾp6}LsOo@*#xc6$٨7uCJU79v.uLeΆ*}R+=s*{Ώz1}_J_xCRv4p( q'FGc,et?RNFS:}/]m):p٨w/;@N܉1\ )rW_i4R*!F6P]_81ᘪz1ݵ_81Ψ7hC 2ׯ" *11}RM^9U{Jy J_zT 5>6ַ!z1} RnpToԛt;P) 1fwwr|ؘ=oHSHU;JmHREUhGJ6$ޓ(eEHU7pC qTx߆;ݓz1}a'&ceC/2ӝ;w>OHʎj 8{E|Rўh6$7v3t Ep&PǾwSQpOR51mHW\ImH/v6P稟MYi78N3? ExRs18*{ORgOq1{zRt;*^khzSY;"۷C,!cQ/;۷?CJdzR^dzN!U9>zO )P?&?^a8wLO4x`LFz_yiH͈3SW\ImH/ ې"ۨV9N6$W\ezw@6HRa8wLmf?Sd!=9})Gf=? I6sӧ 57mCuU樷ߩOjVQӐ oLnT1^;mL RǴI'g/SQoEf[t듐*i6 ɒSEF!Jog'SO+2G ikԏF?1zuDQo<'/pQ/;B#nH'E&ސ1}b tT0T)ۘn8S zDQo!EN~69zO 5f{Q'i 1^s'٨!JJn[E&I6ې"~vS;{O4R#P?N+ǴQ/;@icj$rJy6$K{OӇTϑڐH{O~z}R?TbcjiixԻQЃ9^Vp3 i}S'٨W*}`3%"ӜQEޜ'Qˎ6T"c7en\Ocj$r77xL7?&ߐt \qcL#26DQowC(&gl!Y{>pZ3; z WzM~FSC|W\st}uSpW\ߐBu*DQ/;b#6E09޿zR^ƍu2=qxCƍxI69 Nk!m: *sې"~W\ez1pzG]$굪!J7__uicj*MstS?uNu^q~>4PJK^lHӟQ?x )W {OR{6cZ/7S]1FD'Qԛt!S'٨axgL )TR1{zDQ/;k3*LoC }7|i0;wWOxL{Jߐ֭':ÍFJ7$7N%5uLKuU7GTr_d]qčz )PUI+z-=ޤHͲ!vU6P]wQPEbC{EURQ+47P56@= stJHZ{Jߐ|k֬! ; ꊫgQo@䘮a: 7{&^jի55{E*;5*srK ]qeQI"ݐBwRޓWZ{OW0\cz2KusG%=  JWAm&?DQ/;XE&/^ޓlK{"qjUY^ޓl{WbLWZIm'_q!ENWRɃUW\>7PP ʁhW^vLWvjC8u=IEw6P~Woɮڐfùcz+%IzDQoSʋL4PdR:]q9etŊ$'pZS֨7ۨEI{*EI6]f2IMd^'Qd;0;]N*3Nʼ!mH契?tIc|ee#=FJzO2Qo0ц*Vj]Ez^q~[!-YIUԛzξȄN}B-,n^[ ձDpU7Riע$`~ﻶKZU=Fyc;\[ޓ+6 )TzچGZ{OfczRJbC!JoZF-nmRùcz2{+ޓlԫdCzenv'q*~P$披Q/;nUk]WޤSK:'[ʸ! (Rj}\چzOv_q~,Rj"BW\ImH7w6P%Z^'-W\ImHӥK{+ )Rzctɷ&q ]qe4p%^L-1cSk[)eCZ9]2LF.^Zc?^`I6U{zR^d:cxMR}=e~a61][&c=F1:ZeWoW\FJt`T^W\ߐn!ENR?]E҅Hu){OZ{E.\Mj!Sv9]gCļRbLX!MwUzO)/21]zjS E^=Val[SZԛt ;=F /20 ^wS$ 7)f H+!JΟOZW\=^vLJtS鵄N'zIzOQo!cI&pŕd)E3I 'Qˎ\C4${UzO)Qo)TQ+dxCJ>ȩl[ޓl; HuN \qE{*0!ENMI.T6fr:nAQa ;LI7{W^vLgەF6TF'CW\e{a6ȩʮޓ(YW^yW 8$zdެ἟^ߩM\q0|.oC ڪhWzO_iBW\=ޫ3gj=%^sQ/;3g^۩MR\q%s)ǩ^(zO {O!EJNy'٨WII6U{;hѨ"Qo鯸3tJ+Uɪ+)c:ct}N/+SΨit> R\qU$z1>_u9PW {O~zOrMN'{*tŕޓ(7^KjӚޓ+ޤiZ(zOJݐfoHiZGpŕS162 NF*RNݳ{OQ I6{z1TTa8R;~Kʝ=⊫$+eSRk=FW\ؐ"_PtfW\=/~AfM{E6ȩZ''-W\i=)z )Tz%*zg qU樗KJz+{"nHOUAwUzO2Q/;PjQ/tR'4]qUޓĘNNS=*0;?4@ endstream endobj 105 0 obj 5595 endobj 81 0 obj <> stream x1 g /)zA endstream endobj 106 0 obj 634 endobj 107 0 obj <> stream x흋U-5/IxO$ !Q 4 !PB!41ICQ4 !AMceu}̌my̙9s93ϙy߿`czhzL*Lɘ8(d6kdc{ܹWW`ԗ5Hx<* ;vh ف=Ҟ(3DwE+6<HymV6;N+YEF(gk"oIyXR'f oR`NȗUV5qD¤$C@{{+P Zá̫7^^*Ն:D:Qfu<:Lf2H)JG6u(;ffM18QfH6̆Y {$nܶKQjZ5^ "n^ Jwڬl djz@q"5))F6RH (l=Lh@J.uY8"F(e5d.;룥WW|h#(fe*L&,t"~dVGWW\荚_6NL4?GJh|zuJDk$'۬ǿ qi;D:Q1+HVRftܱxKKT HPdmְen _Gڬv ReR5 dq;amV6/nI?#Cevܲe +6?1yY@ny&#ЛuFdqm֨0ъwڬ^c{|~3z]4/oI>Z 6kR%Ա=n~zɔBwܽGDc|gMA_dmGf[$L0p'ͦMM5$:n 7/۬O}m@Z"^:dpGJ5D9PX Lv`k*2R|YM0Fo{4#lz駩OV@$H)JG$L:XBlJ>QYGK@Y:H XmT'n{8"7n*# d;ڬl 7>Z3]SNX&@foypԟ^JZ8,͚D9ȶȮ6iܽ;amVy-ulOn^MBkR KG$Co5lJ kq J0D#OzAoF:J J'wV)D6mV6ׯ^T"I?RR}&V36bY}=NE#$H)ǨWX@=fJ Nc{|Ljͦڬ᥎#r-7ݏ=QNf|Y,kȤdwڬl ׮#ET x\≲Oc5kW @ep':@n K9#{\f5" do\ LZT9# +;Q,~$'Zjy|QΙ@=f(shMrKVKիM=Dy6k;P%Mn3@6kRԱ=>z٥Ȳ܏$>QU3kt'#?QfD>\jW^.с$|\~ 䪕+^*mD;R jc{np'rԫ/aC 1ihʟ( k|Z,2YU܉nv|Y-Om@yY:j4:hrK d~'ʁR[dLڬJY"wD.Pa;e7l6+#rٲ JKXRY0#(uL ,`6+w'@Ο+jMb ڬQ{Rͥݏr&5wY K+EmJ@ l~:.MJwY'ʼ/)Բ0۬6f]zNj[w?R6_&*=l~pGT2=qPZz<#p ʚ4kuڬ;/Y@b&uw܏pG\X;vji<*ݏ$DR 9sqhuHeޗ9 4JY)vuԱiM-ΏQGfesfVͤ KGϩձhU}< Y1J;#D9PXfu6fJ+fͤa4J2H۬l gTǤQΚl;6qDΠ8 Wdu6x̖:ǟPŤ)R6+`IH*YRge1ۨ*{?Rҽ0Wa;@c{m:E ;RڬN%0)f-hp'<ӧ+`2#hzު.x\~/d#%=Qv۬i"򰹌@2dC6kA;Rڬ^czuڴi7$# R 䴛)MKs?j{$4iԻasi'3-'SD*f)[c:ʤZmVir)J۬~4&aN}\~]8ܤȒ ȿ)dp'rM Dj>#:)'lap'Yw ɓD~$tEZ'nY=l~p'rҤ즇K[7+H>l.:`"q?Reޗ9H}l.D9PXMwTxQ|YMW\H&1S۬^z|L=C6_d.&y'ʣl:qrYy(r\&GymVԱ=+]d$;>l.(u,+d#e|> stream x1 g OoTA endstream endobj 109 0 obj 688 endobj 110 0 obj <> stream x Ź?^ ^D- QrQP/` jP*Q\P r5HpQA-B  Μa6Ns:]]]U>Vԩz-+)=;gϞgy7:묳>^z{{yקOo۷_~߿^xE}0`K.dРA߻K/# <C :taî>|#~pW^uUW9rԨQ?kF}u]7f̘c^ 7x;nܸnr-?0a­zm0qogwq &M뮻&L<{wʔ)SNixӧ|衇f̘#<裏>6s'|r֬Y={SO=œ9syg}/s}_yϛ7oxW,XDž kozE/~oɒ%??K.[l!|駟}_W$ͳ.;㿝lrudN}ْhD{ylhG;zu폝l˖D{/}։֓L'[_O;֗-E'ڗ*dD'['}~dIwI{莖l/.ml:ю^nNvmg[,[N󣗭N+VX);ٮqFi(w\Ͷllho^ʶRNOQu-+[7l)ebpۖݧG;۠ /[%ى*Jَ /[7;(Nq *[;[ YhPP$[ޛx7h,No'SJ'Ul;9NjNjʕ$%=O?ݟm`'OD'5I][\ovRʖNI-vR*.z;JefjpοFuRCT mAb'uNʉzI-lܲ]jdwx駝F˶ltRlNjQS6@6@N*( /kֈMjΐS|NToNRJýT P9JftRSblB=iS$_R:) Px'u+$~K6@2J'E]E%{b.8lh ;b'U(~'5I7@N*IFsvRي wݔ>ўlCTSwT/zUN/A'۵"=S*9i/ۿNy;NJ_vZ!6|Z!*;^IREN*]/۵  O=XTrNJJIUPɋ"l|N T0n|}pwRPɉ%IECyQ*9?NDn_NcddN._OJ:WW%sR\ʠlwPʨd~bfϯ{&;ld6 4,P^J~:1x(IvÆ c*T2ϡ|ВLdTrrXv]O%f˯ebz(~(C%UɁ(Ih7n+dd!L*YȡjpB%e[]olg. m Pv:T>ݻyÝ.tT,~M%?dC>VB ْh aduUl{/ SH%d/ܙ2wT]4.Jv>pk+LL%˝:]%f,dUmu1ym@ԟ:]%v?_s$d<Ʈeȶ"!L*Yȡ,yDL\([;ۚٶ JV[%˶ GsUeSa:)'[p[K`,~hfwTr2S'TrH'dn`dUr>ha w KK%vRA*_1Tm>Zp_7J%4XJ&l;A%'5u"谛mIpTXFUr`%*[Gjf˶20f]k뎳ek-` E8ov1f{jdTrlk: J.m]kdž㩰4 ND[[ʚeQ–lkdG% ߕJvofA%kobv# K0fdx9ۯa vU:m}# 'Z% :!uTN A%롒NY^JC%;ep#۽`8U"ٲ dNT]2SU2|w 9l?I%?uBJvmaZ։PZ|GySa*<I5463¡y?bQɚ=FSBwnlŔldپJf?w˶՗@%ke#/wTA*)ۦvlW 0r+y7@)BuRN?XȡVlf[=eNHUZ<FSN²N8,dJTM%;)7ڣ| T*͖W5ךTS'Tm "cw6B/7U%dJvmT*9_QrYƟ Kylyz*I%vR NO&,U`c!0IE˶dUIdkJΗmK\W-:!u]0f+ۈnTW%'7uBJs(/Vv9^0Urls#:8]tRZ饒NHl1l:\klJVX%MMiP*=VB%xL4XȡLm눗Y 0r(/^%ȶm\*YSaL*Y٩*DgJGF0U$8ryBO'ESN]@**13T6!*6 *Y9L&;TyS'VL]4SaI0VN#EJr(ocʡ]@pRɤlE.>fJ&e+MvQ~W֞ g+rNTP>$wւJNA%:)amr!\d5T2Y.x*,ͧ|e)MvcCxil- 0p(J&v uJ&يmԉU2)[)Zj20o o]奪d!4,P^ l-Urg6*9Ulg+MWy*;eRi 05JVP^ԉ=.1[KJ~*e~n@%ɒ,7[˨:Q$kpE 0Tܲé'7X i,pSPɤle/6P)䄲TXrO;?NiM``ԉelJN`DKr>\LHV%*y*,%eO-p3W'i] gkA%' O6m]wT^pU:`\ÅJNB%'$@%'X0Zm2?uBJN-[K *9%*YJN3[ OIRn'YTr*R.[S'tPigku:Q,TdEUOmRSa2wѦ$H8d+Vd*Y%@%KPJ-O|*LͭCy:!uP^%@%ˀJ6G%Qeh0TX408 u˖,J%V.T^ߥSaj-AB 9Wl-;\dMTr\E6T~QxG,*9QB%JVl PUeKSaU"I 0T5)[x,P>}I_(*Y%@%GPZ-O)TXt0us6eKJ;קl P\*Y%0U`,~ƅNJ%@%u/[T2J֮l-;\L`P-]4,~eKԉpgCUeKJVc29uC%[Tk3uB%eLкl Pɦ-O:)˖Ƒwi_,d ([TrJ6l dyOQ o 3u06eE֘9OT2 Mn0 "p(co'e\$\,uT6uœd;[>.x* uqCyW%uɸJ6c뢺JT[,d?.`lF$+S'JT;[?T'C 3c,*EMJ6|g'c*9#[ Qəغ$si:u}KYܞKVTr>.Pɝغdᩰ}l]*KUIMtUrv~~*,}Tg*`JnnUTܕV{*LJħuQpqCy|l -bJ֏QOe,~cQm9dDO!`y*:um *Y 0tV9D[ U2 AߧrQa(;u"d1e@O܂hYQ%tWwPݦN-;zdD˅N*9!QPV%ehe1S'ZmtPɭj4WmTTՊ=u*DYhSam8Ӌ:؎hŠJFP쩰 &f JFQF%7WoQC%p:  öVqN`X)ZIU%c=KOa=CyJp(8QX 8!WGrER$|z CM(ɩX&)\ߖ4$TAǩJzUr=~rU&\MOz.a=NI*HQɇr* A%c=VC~(lb=V*y#$ZR{kq2b ;]"r(qUn,O%8Xab=DUҪOqD"l]+~NMX5C%Wb9 f\X;: 8];zZb9֕*yw|4BGzC˶!lwUBJysvlh͢C1i8V> stream x1 g /)zA endstream endobj 112 0 obj 634 endobj 113 0 obj <> stream x흋E-5I$'(AH(j(b $^@ A/_evΞ9}fyyg~3s*A@ oH7_S j׹o _Sg-0k޶"ǀT:{&/a2 \v=~eIRJ IBJ]qkZ}h÷9#lul0I> ?=j?%:xDFYقZoAFYقdzL:;>Fju""a2UncV6[[qc0Ձ[QډձEdJ={cV s_\L^V$s,%f=Toul0Po Ĭq^꿺zGH KgJU½Ge MǽQXbV O/F,2D9Yʊܳ&V'd= *+f:HD^(=~zA[iŬlA~5(ՁNǬǽ5db>QAF)FcEyGɋYc xNٽ) &lǬlA5;#{DI9:0ËYق (4N9"ߦ^ sZɃ;}odҀS[^A:ȿS/JyXzzYGe.2ԉrJ1+[odTF' ޏi4<& i)pcbV ߄(h% =bݏuQ<)'cVހɐV'PipTE)Y%(7=v=AD:#2형w[;`2Q*HձZ&+bV~c\O[ݏ{5f|YmL[Ǥ^dwx1+[z" 3x\rgmQp6 2/;mu r]t 2;S֭^ +NˏYق\LjCŘ5ppGX?Rsd#8Qnhu_V5+.ƊTtp(䚂|[V[k WS/vU/kwx1+[l*Hch;Vg-N NA*? fu[ LQMjUOCy{YPZT~1kǧ^4:d WOd-.W1f>6[S]>_VG(S gezL|?ReF3UVz%$fUspjJ꥗K>bH;V,ȕ3xgpr ŗH&'Ŭeϗ,+ dRX;^'_!r66|YM˗S N̪ձEd͚շ1<0<.[F@ ͚B({Z'-E0LD~HjVg-r)d;#~(; wKo2ˏYK$;kOٽSKxZE2x3 HY#(}Y 6ͥƬn_B-#A_ޏ _c1Ƙշ1<>dɒ>b~$e6x[Kd#)2ËY]K,95'Y)wĬn.v /#%:EriNwx1+[-% Qȅ^"~H'ʼmu_օ >F-&*k69Q-ȅ-6 /#I:Dž ˤU|̷1 rr‹;[ ϑI"3fasy14M#YE>J-(,VŬM͉ɰ}*yޣ.rP)2d5(yї5}YmΥ$Hu6v?R蘕-ȹTܑF:fAΝ;ڔjwH?Qv[3GmzVG)1ߗ+jYAp{\~:#Զ;Hcf4y<1<1<ΞM-G")1keOctLVmû>}*9I~1+[Ӧ)d\uw|b֦V9_R1+OV󩪘KƬԃ;G]"&H*bVՙf~YN2ڡ6N#E{89E Z6?9Q:)-^5ܑ:Q:ȟMVdE5ODNɲ;܏"fu[ '?Rփ;4ˏYEԇp?Re'f:'ъle(䃓HMb֌wĬncx|hҤI$# ~Y 4iH;/Ф6JK;Qmu,?H'Rј~d)rD*Z/kAwǬnS/ȉ'(!ˏYEҘ;QNas1kձ=N_9ܑ?gp94"[{pGJ: Ebp'tt[Ǐ#(wB#8.sZGy^q?!J:XdJ#eܘmujy_&"q?Re/!rl"[a;XfiٲŬlAc -?Rqcz;fL"Y3~<ރ=Q-1ٙlb:fADv^Y|r^Z[[LEv?Rv)\:Ĥ)R6xW{291G3*I~1+SGJߤH $YV,QN_#eeOcwmYwĭ-{1R:ȻJd҃;# Wwlr'Y[[iR(f%~\≲ձ<ޙ260#{EޑJGRppoOMd5H$NˏYق==z76s?DjxDaN=ȴLacf#?;=l.9fu[㭷crHǬ"S1YG( XGLAd 6OD[#0]Ĭncy9BH+;>l.1f:o#%|> stream x  o783:/ endstream endobj 115 0 obj 662 endobj 116 0 obj <> stream x]MkS'P~t)r; ɉCEHpeB 3cYk^{Z{}wo?_wwhqJԿ C%5U3߿F3J3Y駢Һ @}%X=ppYC? V8x\cԿ ̈_'ؓb~=_HaϞ=?ψСOU{d&~):]gԿ &6H_AO|o*V_^wVZTTTks'`o)V_2i=|ѳ;M'#GW vkX9RR  N=VVQkX]GAѣGO5)4~bMGb6v6ieKIkR;w,t~ddêov/;~IM|c$V>v%_;Xe|ܤhWհdF+_JJ&`OIpM*aŪ_zĩ)Izj&5YF_2h=y9&UU?2%S'OTK#ǶLZw3 N%SN!۶}m%X*E;2R|m[v>sS8:|AX!ӧƉ [Xe}%ehuV$\~)b>},QϷP< ΈL%*sդX7~)Akypزb/q'b-9Pdk>n!ֳ  VJY=[Z),bUB~ɢ%LPg7F0_ VKF>~)Ak%jJ-Ϗ`Vk8apZࣂ.}$A+ >]r+@+>(M_nRyC.b 3 N Jb&Rxap/UVIOSbX~}JB~I\ VA0֭[KTa_X`u_ڒ)V@v:KM*gKUUk50+hƚ5k250kU- |&-V U旪.V|`g/ҤV^A3 %&|\nj ZU/J%ֳZ9heMV9RapUʄUB~IW&XXe2bKN%X#UXMEu5'K\`y_Zsc{&/UW_XrX]F0h+9*<#ݤ*h4Tz k*嗂=.V7fERs&U_x:;&˽5*jy+Ԛ~')VYnXkAk,V]*HTapR@k Vv'VUT&YI,XKj4b_Xj"IVkqdiҥbU> 6Rmm-.,YoKTF0>3%Tv5ub% CkR9Zw9?X`?TWǟEr8_[o-Z=b[&bU* K ~MU&*ofZR~֤eTbͻBU?7 6ĚoϛoX5.ajC^}Z_XKkTg|z޼v %uT6VӺ êXg%`| V_[/K!jd{ #8Fl3W_uU/Ҥ" #wi`UΈU|yNҤ:$ߤU5nM*XuO%Xu`0I+ 6Ūu޼y*YKU.#AW汉UyVg&K.sZbMXMXKtgvQbiRRϛu_"mRШ%~bթIe ?/}/kC\2* VIK13VY7$M*jFp|g V#9nҤIT$a!֨g_"=~*bd/kO4cI~Iz|92cƌ9F0ㆤIY8u?g\&`4bUI%4b闦M>=3yY-&|\, XM6=dy\+>4>|2M*08FI&Lb}9#ֈTM&U8X4 VITUR~Iby^Dפ2YX)UWys)UzܼY-yZ딧_RI~&"IĔ$~bZ6=)&SYMR.X'O~rsKyYK7KapX VJI`K c٤ ա4]aPXڤ zUWRhRe5<~XJ<_4C%&|LҤRVu!6J%ҳZK S#8Ŋ02 topR~ apapJꗜb%iRizV+_ zc*mR|V+vV*<'=" &iRQAXdu_MP%ҳZ4bU/e]{b/#V!:M*@XbUe*<>EҤR' n ջ VvjYJ  XKMys&|פ"guXR sZ$M*0S?X *V͖*Oy$#ֈT6Fܤ /zGUQDwVeZ$MB&U G;CRs&gG0Ӧ~bլIby^DԤ"d&~ Ӧ_G0%*VUvyNڤRﬖ~b\Y% duV>}n/ٚTa0IJӳZr~`rO{)VфR׻7X 5kRROͽXe}ܐ44=EӤa^|F0fELҤVT.V)DݤITՒauv^bEF\/N깾=bezܐ4VWc>niR,YmңX5HpT~٣X7, *6`&A[*ѣdy08#VaVvn/mb_# gjNޙkMM*XITAeuu7UǍfgiRUzyhn#X" &iRͤX/X* YѵX5[Kadub׮]3`1Vw+֓*"iR{GҤiR*藄XۥXiRizV/ sj֤>EҤEXΝMV9\a_JUoo{I\dg3`UJ5jPoJ@'%Ye~M*0xYM*Vrs>nФ 6 g_[#X0MXw/V-ϹYs*apxsnVt)5E`͚Ta^Z&7:vd=NJ< eL9G08?TE7[uE<^0X&՜>6|X+W󕒯b%iRᬖt"nJQIY-|Ԧ:x`&|<" &iRwV/.ҡSR~~ DzVka0suYJˇ\g!iR! 6*/mb%iRizVHJk֤JuVI%/ITap ~]vs@gHTappMZRwM]k> stream x1 go~Ht endstream endobj 118 0 obj 661 endobj 119 0 obj <> stream x]Mk.ݺ ">DJ|]ƥ"K$7CuP!4cT}>gߏgoֳ׻Y47╨@Jkfؿ?ggeQ Kzƨ @7Y=p蹦@?Od'Ū%փR[Կ ž={~0iݟC?=۳'k0Y=s?m 7Y@J?| x{UW\|xs-<_c V#,V>/|wNIÇmU?9rD\[zȑX`wU_`0]]: Z=zIyYkr=Zr ;uhI+_J\عsgK&%"V|E>~ɤpMjU&:G)פ _vhK V9]פv5_2i=q I%lXuK9`XO8u:e`97)VO|Kjٯ5Bg\#/%hB8>3X!VqlЊ'NgLbݕ_:ejZMAbS6qV)ԢI V-l7n+ V+ nKd\^~ASذazVqOz|XeR_2X=wSUjy~eynK_DDO>XKMbF o0Yu`Mrap\ߔ_#-V)dkRɇMlfŪXbͷ"-Vy0`1>Yr5M*Z-Gp}C>=o^}5XMyi]aKRsҳZ%aIk.ZVQjK yye…_ # 6X͏+8*iR.H*e*<'iRoRĪfVY&M':GDLrVIb:bK,SjܨsrĪo^'VTi^j~IyB=o^0Xy'YeRM*0qӤէu&/%Tij7oC$apTi3&X:apPFfܹs-Vy7 V5%Xu`0X&Tlw h}b 9 ZDsRzUࠚT)t93xΜ9ϙ2%[J08=.sΜ#8؋b08b}`ITaM_Xv!iR)xV6En|Xg*ؤR/=n:yJn08^b}1U&08I&) %T~arbdSTaM,VS$M*j)N8iR (`&UTg넉Ċ08aU" K'LqCҤR/ oR)3giRQ6T]*9U\4n8F*դIT.a Vs%JuرG0`08r>XX򼀢IIY*XѤb #X%0X|ybyNzV( Tf* Y(Y3Oj/'2b_S"iRKXz" VIe+a*ׇҴJ%j /ϣ!ƪXM*Z$M*08<&cr%͗)R_IV195jXR gV(sVIYQF_"mRɇ(j7L:/9ŪY*ZGe~IݳZ42gB}یH"Vu`=a~XG1Y.C>X7J5gT}Xﷳ4oRɇ>z$ F*=X'*DzI V#/i<zN" I‡$b Ѥk#x}&dyY-|)hV%YeK.M*0IY~)albKgFp֡C2a0erФX Yf/9JҤVN܇{dU/ۤRV`{zUjyNzVk9ELҤڱ}v4/ͣKgiR&_08t]w'zoFB~)VuTJzŪẌU|yN}VINw`50X&@Ll*HT)M*0دIE`U @gHTap= ~ J4;Uw)V)t_"=D0ﹺc\b%K`Mà3bezܐ4\/:Y ŗ644=Uu_yCb% 5kRE}VaSLb:EҤS$M*0g?ۡCR sZ$M*08&U'XK.ϵ y6+nJ-IjӤ< w6M-V]ڃ" ~PųZ$MPJW`!YwVK&k\a%YK6S,ϩTapEE5;%wfsZ$M*0]_&V,ϣp'n0X>_riRɇS"iRq7 fhd/Ҥ_8EҤ*hRf56ڷk"VzM*=jU0ᦵm(V4rbVt_n׶m~ MHڶu[_`$uN.kRwVK/&\wXkR)rVIUF6YFk֤ cs6m#_R7 ֬Ieza6ŪYyTGqKU\$B4[b#khRb$u_!Na0IJӳZ~&b%95" &iR+ۮXKYIrFVJjk+IJ08M*fR#*XiRizV+_b&yW[>nTa0IJݳZqɪMR~M*0I%\x՞b%K`R{՟-2=n&U6**ㆤI5B&zapUR/l}UXI`͚T$aխ[{dy~'1&|\nEjSW~It DݤݛT\6hպswymGjCV,VK4lb_ڼU+/8EҤ*hRJҤb 9I'~b%iRizV+&PK endstream endobj 120 0 obj 6340 endobj 70 0 obj <> stream x  o7x2, endstream endobj 121 0 obj 662 endobj 122 0 obj <> stream x]Mk$|TH)u:JRɡ$WCR !B | 3c3*s{^>ޏgw_gLS@a•@}KkAnطoߏ?gkeq{MѺ @R3iƸ@=?O;C%R[ܿ ݻ0yݗ?=Hݽ;o 7i=s?m(7iuF?|4{VW\|"M sК/|Db[zXd`W@ӔKq`E;wu 9r($>rhcGQQ.W&ӔkIqX'cǎ")iLZKEN,f\Lc+`7&LruNǎRzIE?Z8^)#V9l7ieRr I1l7h i2y=~ I)lhu5M]Ǐ<:f\o OuR_o۶e &'NuR_i +i2zdi54~lu;\:i2z$‰رuW_ۦ0ir5E2'ŗ[ȕ'1/ ^g :N|ؒG+'4*DŽ-[y2MNXfSg_|]EpNP_a6M)^+1#L#>k_GM&^Sn );m]d%W`8K뙲JDNr2Mg/bG?ߴ)3yM>.dZk "(o SUg>rڦsx鄎}$ם9 \-E*6*1M)^#r 6y2MjVɠKaaÆ r%ܦLAky^:!a}֍l7 r ׯߐ?8{\oqҼ>tM)w4=WALOMZ*M?M&ֳ. r"'X&UsZSlE^:ּ), \+*!úux5`8+׊*|`urݦiZ ^ρW|l#M?6UW |qW!$\ke%xG6Z]e0zڏL^iX4E g ^efڌ\LAͪ\SWqYOTiXumiڜ‘Zz0M5+g02MUUR5`ؒ+xǪUV35`ؒku$~*+W7U0fσW.|h4RӴW.\a3 &|0\aj ^V/J&[ ֕&)`8M+xe V!DRb RրW0h_9 &\MM)\^rf"ךzӴ&`X|^,hj, ˗/>XrowK׬j ^,K'Us^orŻZJpoy fiu6fUe.\;&˼MՁwLZmrzĵMzoifLkK-Z]*kHkVpZkK Zv$WUjV9iX&5jVN]#Xb"iZqi%rU>6MS]]4-^OKojVͦ0>Moh5M լr5ho([o!W`8C (V/R.2M h"VӔ`4MyEpraSyӤUJ)%oa$W%5 T2_~y\uڦxy d:oir٦/ަYo87CiK*c}8w\Li͊4vLF=_9/h N5\/y}u̦ImzJr^0hMOɵQW/*Wmzf% ^LF>ϧieR5+`Өu&/&jVYʙ3gC$pjVYj4gh :pXٳ-Zy8)ZuϥhuNa`XT0lwx}r չe ^D2zUjVt9cx֬Yϙ2&[J`8;/c֬SVf0t>c$W`XU4%YO;he}Ԭe $6hMOgMKJ>&YÆ\fG3~KRV5uf TpBMӌ&0&ꚕDˌ3fLa7IJ[6]`07,rUf% ԬiM>=7yM-|0\,N\M6 DzMW.N\zj\U|LI0H)V&k5"U)W*ar +\JgIW)DZLM/Y&ES ZmzEi6iJDAs sq^S6Vr:'*kERHF$1%Mk\5xo%3yTӤyͪ4-ɓplՖɓ}N06]e4i$n5YƙG+Go0\'N*dԽER U}lҚ76M+(LSbuԨG<媙i:q ?4jT\U|N}fE 4=dw`XM5_*e4%MU.rڦ֬oԬXȿ3MoQjo#Ӵ2&lӓrkȑ Po-UF'WYDZwRYEqudirUU">69LԩYoEEzl#6l8\5 ݦGq}aYqY{(o׬o4i^/Ñ}\7h+I0U `{V/W.Nd*"Z0i<wCrE0j*}iZ]J f'L^g+6][|ISIj\jV0IJ[>)!Clr2M gp30e0t\M0Pi49JRi z=*dԭY|+=vZ*M'"&YQá\ۤuiMaP&[Ԭ¢nV4d0g뮻r7'W!䔫:5+phӢU*MERR'n ; Zri0YJ 3ТU4֬QlөkVpP͊ց.r2MlөoԬZ{0Lp0p \5ۦ Sp Ò+\cYsJ2L9ZEM(oԬ(jV5+ZZovJmIkVʟ¤/yUfmz1Q͊r&l2Mt/~ئGjhg*Wm:iJ[t[T׾}-ZTJ[$5\}MZSY*[4/nLÚլLS#ZU`Xmz V,Zy8êl hŢ4f->4+U0->}:H`XK0,K>}z+iլa$ezqc%_8o+Wrۻ7\ 5Yr/Mhe}Ԭ4ES^0gE0LRVX.W)D]IjVߒuv^rE0E0|Iճ}{:!Y!Zc qԩY l%hmң\լHhkV~գ\׬uSX+,Zc1MSUY$5+WqTܣG)6pN.[rrߦ*MG0,Ake_V_ޑk55+\IjVaue7V7fԩYHzyhnSX"&Yͤئ/ئ* Ei޵\5ۦ0MQub׮]3aAZu+*"Y2{ RթY*hhۥ\թYiz4ѺsjVERhΝMZ9L\iJUoo{ f6]h3ŠUJլo-ޚZOtK$WjVN[5+Z|s qP 7_SX`5\t,W͂micE+ptt~Zww)3EajV[?:vdɽNJ<t>r\0\5+~뢛,ZY:"\0v͊@}֎ pDޓ nK k8[WFx\IjV%]I3qԩYizm _cifSf% OIjVߪ挄˻ti4ZC0l]ھ\ILa`}si@92qHjVjt\IjVߪ:e<ܮ}3Úլ⾿C;&R"Y(ak0\jӳڵkoB٦S"YլxX=5E+iRwm0y,ޘ6:5؃a8ТU(UER4y|u &\omzԩYU~I&טkV0ZnZ4)|0-UEͪ4f9ڶM[JmիYq}-7uFf oӋYM9xMm۲&Ԭb5Mǯku '?o~:*MWf-!ļwuLrկf-U=#{[K0Y*[GZJM6¦I`XYk[U`8 HVn J6Vw]U荃Uxt[l6=pAS8`5+[n=ځ"&YizK414ؤU$Q$5beu5 p 0+W2h YYm|5^r%Y 'fwhe:5+Mo&fV6^}Ef% Ԭ*eXIjV0;M뮺S$ 0U0ッ?KLoq4fUp0M!Y Sf^0<^|ÚլHam:M+[+6Nmc5+`x]0MZ}Lf% {ԬXmzE˖)m0:haz5i fe6]`զ%-Zxɵ E0|-\M$5+`պr$WBYtW; endstream endobj 123 0 obj 6347 endobj 67 0 obj <> stream x U[v endstream endobj 124 0 obj 664 endobj 125 0 obj <> stream x]MkS'P~t)r; ɉCEHpeB 3cYk^{Z{}wo?_wwD z?TRbulm? >֟~**tطo_5Dc"uI끃G5F{ nj\`z藢FQ|oj끔\O1r5hH%C|5[EEEx:OY>|)fr&Ç={) p$~r=rx`&ȑ#%հN$)AceQ`vu =z$(L'>zX)cgaanW&Ӕkq X'sB)iLZAN,f\}L'a7&LruNcǏZrIE|V7N_jU;LZmruR ; Z48Q []'N::n\o'NuR_m߾e &ד'OuR_%i+i2zTI4zlu\9i2z‰ȱmۗ_٦0ir5AR'۶+O0l30#_˕4r=}O5V7i2i=]?&[n5iMer-xMOӧK  >|\ Ń\KJT>>7iMʕla-[,ZLG0|2-ג!MZ04r=[zۺ٠KpֳB,ZY*d,^] }ysj \ɠjDNa>_)LiV"r 搫66xK'plS&U4h5[Y "@)V7iJzSظΫijV4MUc7ȕpn3Mex Z7&mz.+;W)lذaczuIN 6ʚ-Fdz|-11>1i66f ZϝȉlgjVjMsxP&YSX"2MIWC=N0ky%>D_t`8IyJlrqdܦ J?J*dkV^rF\ ӴBXkA.^04MU듴20\ ֭_i"Y5kV*u+U0,`8&h]cdp(p**]69Lq 'LSex.r> ^f͚r ;ZU?II˕C ie5MԬ<$ WLBɥf% [WvKRVN^AjVE0aEi"YÕ Z+V\LS&Wxo*VFSrkux͍&`X|^$hW|5V\!WE) ^s`rߦYeդzayV7Nx5rwߵx2M6M+M"Wm:iͪ4]X^wLZ{&u)\S*Ɖj+~')WYnͪ\kk,Z]*kHkVpRk Zv'WUjV&iZ&5jVNM,5huk $CԴdRV* `,%W7R5fSצZyMB5+\ ZxbáլrןEYzuriELZ9LSa4+筷- M+-VW* 󛦄\t E+\ئԬLS]~r4iuNa7Nrp)\ט7x3-W)dYò5l+gE\ rͻWB7,Zy`ؠ!>[r55+[ͧp]}^r^{u\L5jy]KRt[kތ-\jVQo57Myu)i #6h͓1ꫯ:*dY){:?A\6fuHfekrϟUqY}8/As K$HjV^)W?k.W!6}?ir Z2M:m<_6i7?ir٦ަYeo87EiK*e}4w\Li͊4vLF=_9/hN5\/y}Ѥu+̦ImzBr^4hyMOȵQW /*Wmzf% 兩^JMF>/$ieR5+`Өu &/&jViʙ3gC$pjVij4g'h:pPٳ-Zy8 Zu'huNa`XT0lx}r չe ^DRz5jV)t9cx֬Yϛ2&[J`8=c/k֬S8Yr`8r}֠IT5i\q!Y)x6cI\LkV1$~)_ᘚ3M^e6M5+Ճ˱3f1y8$5+%oZ9#\լqieR5+`اfO4m)koԬfp:mڴ鹧p$tx駧\ŷ˕Yq$6ieF\*Ypլb&Ak5Xqx2M5-"Ik\:ՠOئMOY&lӛX$O:0uoosߊ\jj\am2m:b`8Z>bҚ56M(LS"uԨG=媙i ;p ?|m s&uoS 3,A\ ئq6lpfj Mre(URYq}N+iҼf% _C>`%W`5P^r\0˚UH5hMLaӤy06=C:`8КUʕ*F*K!L!>"Wmi4Ԭazr? U4Zg0\(WÔpSx}r6MuPVV+IJ[9MS{-W!ӤnJ[}\%Wm:0I͊"lz=&Mh 44ߊf:p$)/&YizKZگw)`8`Xv9`8`XֺzfRf5+`XWohjVR^۫f}㌢IjVZj^*ekV0I*[Rً[%X=׷SLo\rQʞ={zLa7:5+am Czt6]I0nJ/{`6q⚕|0\\0=i254UŚ|0LR2xLE=z‘l g*Nr5#WmMtV5i);3rf5fe+I*[´f*:5j Z/-{ K$5et[B(;vfU)[Nڵkwfbr0,H]2rezR[$5+`Xy]xOHjV:5+\M}t:5+Mo&1Zu#WjVHjV<йI+i6+7MI -;{OaԬߦ mpUYd$Lrկf% f%B[nqNa7jVtKz + fNY0m:?h} oO랎:h0YJ>KqVuZǎ,S8ԩYܴ1\( g͊ߺfVV+ ]=2PߠiB06$ƛo+aej7ݜC$5+ߒY]M)ZY8Ԭ46/4C)Q'S$5+oUqFe]:tpU4OaHo-!|.k!\ILa`}S?}\8$5+|pvZEamM$5+MoU^2Wi׾\IajVQ{ܡ\oԬ0I͊5avڵm٦S"YլjyX=5A+iRwm0Yq㍖\oUjNzKU0Ͽih*nC*"Y WoFW76][Ԭ\J#<&I+iRf5bN]˫8h-n\5ۦS"Yqb6bu0̱;qA LKJ>~I&׈kV0ZnZ$)|02-U!Eͪ$f9ֶM[JmիYq}-7uFf3ߦ7p֭۶e5MYEj7O\ߺ06+7huUv^J[By-7_J[\5:FVʢ5`XUXkUjmMf5+s=׵-W͂o7# Z[&*n+X}]V7jVm=ouMHaԬ\o1k`f-j`VVF ԬwmZ&ì^۠k #V,fei˵zɕf^03ޙUԬ441ڴk,ZE8T5+`f-vVݤ&W)WŚ|0LRYm*O&T0/\8iq*aV^CRbJ`89yXܽr% 5YÒtVVl-Wm]ljkVpA0MZs&uS)LuJ>YqڴE˖)m0[h4RU|]0j-چ"Ij.E&Wk0jmɕfjV6-)aԭYͤئ/ئ?pZW endstream endobj 126 0 obj 6373 endobj 64 0 obj <> stream x  o783:/ endstream endobj 127 0 obj 662 endobj 128 0 obj <> stream x]Mk[7PB҇H 7ܸUTjTTHrQs uI2A&`0a3fT}>gߏgoֳ׻Y45•@eU3麨@&?TR^/Ȱw<hcb}W4F{njX )V-תߣUvIkqF| ~ؽ;k3Y=Kɚ?m 7Yu_Jrx{UWRrE?|`5[%%%x:GOY}1 $~b=t9qoMZCjb]IV}RG\(ڹE#ؠᚔGQU?&GåGʱSW;v2XKK5;v`OdZzT-aU7;\LZ=V פ&1Yes9zײpM 2>nRzWհdF+_J*&`OIcpM*aŪ_z؉)mIz&5նmXF_2h=~x\ *ɪX)'cW&yz)'ID[6yS VO)غ5Xy`XO:) _|~ɓxD-Y>n|I$a˖-&IZS|di<]oqkxkY)sդX7~)Ake=pؼb/qb-;Pdk>n!1&U/iVOCg*V!dZqS8|٦M뗊jo5B}\#/%hB8>5X!VQlЊ'NLbݙ_:aj34٬>nxR6l*嗚5apUֳXz.O@+>(M_nRyC.b 3 N ZeC\~)08΁VIKSbXn]JB~I\ VA0֮]KTa0_X`u_ڜՠUYfms%&3 Nj* V]}lrckvl|ȅ>X+* fKA+>iRyIVA+VXKJ> h5YxXY~ 2}U&~)08*heJU!DҤb րV4XM? %XM\Z}ʕbI"V%0X|y^"j@knxϤ +VX|Xŗ绥Tb5YXfUq^X/ԃVE_ _`ݪfx7ͪXMr/tB-c/2%Tv ^hXIКT_gZf%ʅ~~RZ.\h~ɠ5o7opol5o?oU0/%Ěϛ7ߴXes&U_͛&)T. n>o*lM*0XI-ּ{,Xk|`CY`*XcbmȫO\~i5qV\)7]B~I&U<ϰ%V9YR0ؤ5_f|,`K+)RHgKyΟ?1#Ka1_}UXR M*09~ןy V]Xŗ$MM*X̛7*X֤U sK$gHT^a)V?*YSjܠsr+lbiyUj~eyBzyNrVKIM*j8ҤJ]7/͝*V)Dڤ" #QK6VĪS*-MVZ'ĪEUXu⋮b]TaZMnBU&*դ/7Z}Z`_ҫIF3xΜ91jRŪ `OA-tg϶X}h'Xm] ZOa:M*0!V0XZ\~r?Rz5ࠚT)Κ5yV&dkRGp͚|w{>kCb ~`ITaM_Xq!iR)xV6+g V#9nҤIT$a!֨g_"=~*%xIVR|̘i,_nRR3f̘c>nHTJՊf?g\&`4bUI%4b6}KgHTapm08^b6m#8rap\\Fe4H%O2X#nRQ4ʸT?`50X&U&6Zij3򼄮IeN5X+1S~ ~)Sy]ųZ\gb#)O=%VYY-&LD,)IV*<'mRE{V+SLZ%͛T\~IiNfyX'MC-IX*<װIfb\Tam %uj4r>nxbX+ؤR/=a:qRn08^b}qU&08 &) %T~arb`STaM*b/9JҤ쬖rI&d`0x.ELҤꬖbb7~Xs u*X{!iR7cYeK4H(Tuر.bK*T. _3f XjRɇ$M*0X4:XN0Xi=zF,G.m3b_ϥhR&nRyV+r>f*V4Xh~% _/X*% ##&Y#8j/EV+JVGzS 5_Of*<>EҤ" ˗'EN&V&UD#oiK^GCUJ-ITgHTap$֑3i/i|ms%ujӤʜ m3,X Xa6lpfj<be(դPoRa}*_ҼI%_>`%V0M*gu%ʅlRPK.?tSmRa?ɪX`4u&dyY->4C%&|LҤRVu!6J%ҳZ S#8Ŋ02 m3Iz%:(*_rIY~)_RIY>Y20IEcA~i4_CHjEӤ {LV#8a@H{b/#V!:M*@6wYXŗgHTAmȰ*jLqVIUDѤ*hR>mJ-ITOYU&fy Qr%,σKdO~Xꗨ6LV]*<'mRwVK|y}Z2U&"gHT)}n/ٚTa0IJӳZrO~`RݻwN" & n!޽ĪTY- buS,VY7$M*Mj4dX2W/E48%^*嗨Ta0I*ԳZ2ً[%X)V I ap.JgϞ#qNJ0Xdy.jÐ=* VIe_jM.]ĪNJӳZ,~IյU&Y-&Uv,tlᗰ< RR"~{K#M"N1XuRM*Z˕9ۤǻ%Ye~M*0x'YM*Vrs>nФ 6 :ݒhR%ǝ:U08nsnVnA;uJ`0X&|⬖I괎YFp|jӤyT9G08?T]7[uE<^0X&絏5y6|X+F2sIZMZ>)*F&gFp3;tM*0x2ELҤRV5sLbKS%ҳZu--m!XI`0ݥg!iR! */mb%iRizV<#7+IY*ZxXC;&R"iRɇ(`&k\}]vs@gHTappM*ٮ Vysm`=ozSFRsҳZ4"9p-V]ڍ" ~HųZ$MPs/oѤqCW]=XkR)rVIŸ*H`͚TAbG[J6~I0X&AkfurU08 64Xm ] /SMask 131 0 R >> stream x \WvEQVYMe?YKEh~۬5Ȉ8'/_߿~d~ӧ~D_3:T-sC]3:TCB~\P/ С3P-:T$sCO3:T"sC /3:T&sC~o3:dw sCn2:dv0sC^3:du"sCN2:dt2sC>3:ds!sC.2:dr1sC3:dq#sC2:dp3sC|3:D7 sClC2 A[tkXEfn![tgxEXdn!I[tcZEfn!ə a ZaE Ya Xař [a ڒaM ٖa ؚa͙ ۞a  a  a@ a`  a  a  a a   I$ KD Id Kᬄ Iጤ Kę I K ^+" +B +b >*W3:dB\𷲙 R8sßJg.tC̅ 2:4\t"s[̅Ngm2:}5\t*sS̅NG2:4\t2sK̅N'm3:}4\t:sC̅N3:ЩN_ dЩK dS"t*/N=2@T#N-2ݟ $',:u)S_pS_T 7N~2Nv2?: ;y0NV2?Od$,:4N62/d",:y2N2od ,:6Nt2̇:|̇:Q| ̇:|0̇:|̧:|̧:Q|"̧:|2̧:|̗:;|̗:|!̗:;|1̗:|̷:+|̷:|#̷:+|33̷:<3C:3<3:<3C:3<3:< 3C:#<(3:<03C:#<8s:w<sS:w< s:W<sS:W<s:g2g"s2g) sz2g9&s6Z2g $s6:2g"s62g+ s6|2g;&s\2'$s<2' "s2' sx2'&sX2'$$s82',"s2'4 s}2'<%s=2'!su2' _%s52'_!sy2'%s92'%!sq2'-%s12'5!s{2'=#s k2"ss2 ?#s c2?"sG2J$ɜ#S&s_dNaB)M9 ]4 t@eN C9Mt]7tHeN+=C9t ]/tPeNKB9Mu ]_[F4eeNk=B9u8eN{]P>tçꧻʋ.sn2爵2\tO*.sE]AE9E'0b Kd>ӝd>E' &t‘xNw Pd> D8 CXtLB't'fN dJkxFg#bFMdBk dYN dYJ{dYFEdYB{ dЙN dЙJ1dЙFqIdЙB dNdJ1 djP "Ȅ2M ɼ>#ޞ;zs2Aɼ 7&>ޖ;zS2E-ɼ7$~ގ;z32Iȼ+7"ކ;z2M-ȼ;7 s^zy2B/MIɜ,7%s~$dτ^ˑ9 K9 ː9 K9 ӓ9 =9sS9=1sӒ9 =)sS9=!sӑ9 =sS9=sӐ9 = sS9=sÓ9 =83C9c=03Ò9=(3C9c = 3Ñ9 =3C9s=3Ð9=3C9s =3з9 }3з9k}#з9}з9k }З9 }1З9{}!З9}З9{ }Ч9 }2Ч91}"Ч9q}Ч9}Ї9}0EHDeч9qYAdNd}E@Dgo9YdNEAda/9yXdN&/98O9XdNFB?Et?Ade9y E?@d'dN~N7dN%S_9U)SП9!S9S!s*OdNMB̩Jɜ̩L_ɜڄI't@eNC9=]t8tGeN'MC9 ]t0tOeNGB9= ]t(tWeNgMB9]t tCeC9t2?]𗲡V4tÏJ.sYe*b)B)"^)IHġJḤHᜄJdHDJ$H F;Wdc]0Je ]0Rec ]0Ze ]0Ces ]0Ke ]0Ses]0em]ekl ]ʶel ]Җekm]e-]e{, ]˲e, ]Ӓe{-]eM]e1L ]ŴeqL ]ɔeL]e ]e1 ]հeq ]ِe ]e ]e9]ey\ ]ɥe\]e ]ѩe9]ey ]١e]e ]Pe5]Peu< ]Pe<]P͇e|9YPgC}e}9YPgC}eCt8 endstream endobj 130 0 obj 5449 endobj 131 0 obj <> stream xu>C[R!HH  uHII)tIK\owz>;sg3II$$>L %1N俐Xя_4U= :*2)^SİfR,o67h3o$㓘@<4JQf/T|?3|Ѫ-]8)*)1ɚWڜTS]޻z/wy3<Sy J KeKJJ9eRu>nGO\~8.66)QxeWct}ܽT)T\Bہ~^H;$F|FMyNʝP->fŠ;{,"<,\EA V >v{^8:6NtMjf_l;rbÄh^NҢcrT*?s-ؠQ=f;yzݤ8/ru /~^*_{@lީޡc]aץBR;PW{U>ߪִi-kb" [dF>}Uuן:~ѓxFw$|iDMyyyReQ)ֻ; (hñ}/? S34SOʗ\Zru\:q/":FtiZt>+E4KUYS׭8|kXc%h(:&ukk|lp䃤u"Syx]~I>_ɢgśN$>T{%r3tުrQs믾f磞D'Eq;ު*_US',_ћk/Hd6=y# Bתߥ蘒y $YSym>7*E꼩+k~aغ؉vFdހ*oيg{b>C~sGL!:d.'m@uW_'vw#r=:pw3s/ykփ;쑅;'\M̓nTtVv? `o1f-Xe$씂 CDA6 tl:n@} ^{ww:r:L+8Dnvn*aQ 1|B]Mg9UDGT_ aiU|01OFs>D;;ёlbs '`'#%\GtD \p0=LZs=u&Pwkd.Oź/1¢&Lp}xn?y쇓~щWDw>$xd]E=4wF{~}$IRPtOǢ{pr{:'OsxȩD>;%5ܣs@Ϩ**:{N5w{p%Di T}ItTc~kM.W7z]t"1dbq{|Tű(D;}*cep={i.MfPP*tQ!D(.|>dIQ0= [C찅3 Wu\ݟP>/KN9We~8][C}D3z:۫E)bbo):埯^ѽ s=RxѬ+{p)q7eL{{Sp%z }n\JµDGt$ƗE 8/cW^r_,QqEޞq=AtSmO0H]Bt&ku] ㅩK ݵPG,":[janEO+:0nk$!SeUG2q$EE'1T@r=T*m`h%Fu5tι.{p{[?j\:jVqytEw/|=U*tm^(-:TN49:}szkqNvޮna4~&:\@hPԢ8)L%0:W{a@e5SN6ݯZPE0 \DgёR^@i /jnsbs$$<޺Zw~\s!:<\XP w^71+qtݹ&}  ,7_ѽ u5<]w<ˀPϖWO):Vqnů:[t7B%gPjU iS S6g@CeB{StG"l/:NP ukF)t lc]v*P$VEϔxߗ*畢;wxK<TUf?݀qWf@'.=B< GltͯHq'?=ce. ';n+:N隻; U΃꼻%Si<\c }8>Lmdzr+<:zAIz?WeXt29wՕ0D'Ϲ('{}sGuKʊZ'' ߳U~E3gTy19[í| S$[p&u2cl^>%gz0j*_?E;D%DLx'Ryh'+q 9_{BD_.,yk-VPe@e̓67 t)l`KFZ1zs+D>+kϻD[_wF,G~(Ʃ qk?KA2a](YOFwu\ I@n=KiXڝ_\OpޯBuf{~k{zCeMZIU1O82k]t3 3kub`y.5:'t2 q_#2oƺfr^+ K;#&/t8`YOzɘ'%as,Ã]%ߝ^UC/{ a􅩕O{Ikvy{.DϿs~$NP;yW F^~pfLyf5u.*nJynJ̓uz^9@?!N ߱R?8쐎\Hot NS'u!S\ UbnLty+x;l产<B\d"ҕlub>:܅D6ͽ^*yk^64ܛo.GK!g׎yRR¬H]i ]e.RnԦ׎yRB*?bVUyq&6v3|2}zpMKJ0 ,IITx#[T"|aK|MzZ*W]k po_T?/3z7Ep՜ ǿ~:\oݴ/:'N/1ɀ:zmǠҔCvEwpNn_Y!Xp{{{BUi+ֺَ?S.-_S+Nm\S"6RH==>uKý.-kl?ݞ*rk{ʵpo1y믊wX&%|ۗ>o|וY389/ůݿL+%=IIu|ȿvo+Bolm-ce%>M{ez,z󭮖#ZeD(ſʎy\ ;ǩmfZؿp"z|wIj ~9xQBW|C,7{~)dy|}&.`{ʉt˕) {wC#ʾy)­kfx|cݹ]H}7XWΐzLu>9oP{{Wy)'ĆڊF: [SWcEƳcK w?8=Mu.5&8龂 rd94'Mrڵ$GpZļе7;cʉε_^rZ;[uw+#_t:{jH#+sX =m:pA{Sg]lS\N5|0'քO ܵ/;u{:V*:&gA=7ӸӪgk)rz/N$b [QݵC9`g]>t9|[Bt| G}jT)ٖ ,43{ UJJ}Y :rީ.G[ZEt‘2==7pu;'G7t~LQW2 h= 5]()ɑwwpCO/:F5bYu>C/>+#_{C62Q鎮ujor `qM:θ<N+:)>K#\29kvVoJA1pKa;?-:z憈=VU܋,3w{]5yW%.xL~ =.e_5Ώ Ȁc$nm"_ c<It%(!a[q-۹p}=,){cqbשRtWn+H[ U܅)Eg\|]{K%ɾtav[>tQM).:Z_a+(w6H#:*W/sajJzg8Ό¢CP?90a?L':*U#Du+~O\@ݝ;pgr*EOEwƢWtU꛹p_qYĂ9HNJUx6EQPt}+ [6D*7^Zs}&CyѧMn[ښ_s kC^puHGJm?11>L*|eU Ѯs-EwU4]CE МWpS=շlwEܯ܌ 8XB Q7Ȝo?vslj[Z@bWsr8Z)E.-^jE._"'e>K<^d|r8\ܽ 0=x[?T7{W +O{]a1Wrf xesj+n/,/,ygG/)'Jn? |$nK\yE1G{%<Y}Eb6s'ysA1l/A1Wa %ܻ2NtuԂpѭ<MDU/|(񀇸7<9[YUЋs9-*,t窱Nwͥ8GaLBrʷ{' _u8IlQDl;Yu,$ w1o%|b^9k~pTqmgIXUFDS9Lt}4r_ek#T l}pr:?*ڻcE6S~__ [xRxyy99]"kKˉ14p$DgpcJz{;7YnU𒲮rNֳ~4^tqC:o]֝5{~VtOw]j_CН8p"ݡ59VD9/2c'R\GtM}wԋLZdB~Wt}н<y;T4U8wP}O-ՀG[__?+Qw\/jÜ.OteVPl9Dt2azf.e[&:[@X*~۩ARG6۵Єc'tˣc ŀ:QTR Y4{Q.x4&NwoTZ)%+du6g^~PJ &g+twUO zjiL7_3,^<n0"Ȑ&V*l]r.xx{y@Φ"C){)Kt˽Bbv-m_z&[8!DtAVuyAݢ9 lٴg|Otcum\L2d4lieKrQ>ry Ok5@2jIA`&V-fn낇9 nX|Omq\2oHX]5SQld{_69gʤ<Oq+ JܪY5HY2۪UgzC ܡdyٲeeX|72liml\P}Xqb.|+f+rw<(.RX{=<ՑRkr,lUnV-1rZܹAϩ\\|bt<ȣYj@c*]u3:[&Cl LAO\~8Bn\Rse>glﻍ Lø(1dae4t r٬.xH=SB6)'>u}Mule\,.xeiVnuyAWF]uyAE<F=\yKY9-lYSY}/>^V7ɫG"=:59k<胞>s1\hf}Kt) 1cVPiYgjO.D@䡞% ,TPʺqPgΖKYg{n!?.\Hl5_@. z!^r]u}!g|{… tiP/ e=#ly?;ϑ΀pjsBA`AG.jiRcЭlQUtScwu6arV>s´p)_M<:#*UmqэpՌA^Y&gfO삇Rפֿ(r'x[ z5i._VgmU<vVPWmMߖG]u6G.}r:4/dYVGCM5QW1QN͸&W5%܀:ե~Mb8 A+ImꊠUm,WuvX/+y\K]έGݲf!-&JV_CCt)V*Uƽﲨyp1~z8WSd{+əd׮mtee7"FGWzueA^N󂺡fk6-~.=,=ЫIROMZ:#eM?/דӨ[^]{|VmG.5e\tQo1'Nmzדu6w{~]-)1Ffi^ J81wMAXc!KMku+8pEvnP1.QRgiwRT\}]uŘ3fczͶ3.Ɖn+"~РfD "wCAzvn +A#C͢nQ2IQtMtkX}kR A׏13QYKYg)+R٭aÆ KY.Օ,/ɽ7g[?oPD zL{ θ.1zKFAW]ڦ6tXP^[~T͚VŜyFA]u}r35F}VEXCu1]9umЛ<&-{[ƺ76u6~[פKuku63ڜ7.ss&M7n"Q7-lk׮uUI}o5ђX$נfi;Mzօ54Ae]n54-:6M<6czgv$JtSpM65z-lbvqi;Ot.eʘޠ1nHtSbx.^_^gәpYtKdm5}=7Qٌ{cpQ wvo.yayMK)#E7-3Z4=in&+>r1ٚt\UȀˊAt⻍:[˃gޭ?E{`f͛uŋaKl.Kk$RmY Ao=${du~rfA7m,1U~.?_6E͛ۈXVgk`z^{.A-ZhBu=]teeMpawnݲE ]֍c{l6h6dv).x'-[l.fu65Ɵt+Rץ>7D6gިiM _ףM˖4:aLץD7mhJC>x:4?鏀 Kx8}V+na{yXm\X[nպ٘n5Ug3}oŦ9Bvoߦ6꺠+Aݬ&;LZN*#1zu6mKYo٪!겏\Cn:=}muQ[(l\Qom8ѭaGjr~ll~Vx?et嚜lCG.Mk?Fxٝ?0]6Qo!/Yٚ+ +7]>nEQ?^*ȣ.[|oeQgkn_m.e]6u1iL~7At#;Lt<_2ݸ&gt]yˏ/ԵC{SQӕwmпe+bv1):-Z ^t<:>:V>\D'8puV|?]Z|ׯɖX"Xt @̩ztHC ~EN&7[|o=x:G1ݸpy6ء.ACX~y>`\]_ztM<-le[EQ<:[{c.m{;/^lNAWNM7ϴbWgX !̃^Qg-}b~ѩS1]u)lƃg˜`.T\_Q:uiL:~Lny;kHAd U] ņXޮ 82IҘuEn$}qgI'|M#59cеYOHuXKu&+k>lZx#zt u+c:כoq?*!}ӵtI&ש|MNWgH^gkCA>]>Y>Wkr:[^kHIO>G]tirfP+˸nhu.u6EХWqGh HO$RХ5krlC7f 9H8:ZƠ+٤y0DxWSSЕQwFO. vnHĐu1Xg}T~S>* :~T {0NzwgKQ7ٺ| $ Q~3 )1bMάΦ{vɂ?{t3iLjZ|u}z2ԏVM 6wG.73Cܡow]uӋ'ݲֹSL HԷ7]<59˽3=G~v/'/{t7je令w_xY;\=G)1[7cqg"L\ smczwUʺeM[PtdYx㳿ѣg]{u-t}aK3V|Lf|Q7?5DG˺1RХw׏VuwGxYa{'\tcܴ$}󹤧i. Ц"$ ի,cz7:ۈ,FضA}{阂޳gYewqlĞ7O/Y 1]zo~p/K/zջ.R{~n ΦOE?8iH>z u1ۣGG zo}Х1ݲf(w#}@qg}1DڋWA矊~n/-}5[.ӥWw^I} {Q/~j/ku!=O?.~ܯ_u6}>O $tAnYgi}-V-skIA׏}<6x:#.r]uM|!s :h! w]^R?eF3~ӿqnn*5'?I_ 0<ʨ_{ {d%j AW6l}6HV/ˁ/dcW^g*TCx Ԓ>8+l}]H^"t]ԥKY1/Gp9*qȗ_JA|(kLv5J3x%R/AW RG-8"D]X>fР/%1ZMm% yQG6HGucG1~fE]ZSeczP'mY9E?1W}y!AuCmymg|t$/s 2XuM֥A}qL~mJj@2jȐCdQ7ߍuĵE?2Wt˃_351hO \\=yP)ҫ43$7 F~5tà>"蚨'n[پ2Q'Æ ]ʺ1}qS+S_Z͹>_lGD?/WrhaÇ68}.Ocd'õtAG]>׏~*c?!]?3) T]G.591v"@9Fh><ʨkb.r$?17LZc1]^g6i ;oƠ.ӍCGWQɹߎ2ꖋ,q5Vx 77|Lڸ>j΋kP?ѣ͂_9441ߏ~nkGNYpQdԬqcAc6I~Tƌ%~LiI~Tj(tŚܦǢ뉺qƎ5F}tm7>^Ob䑹)|U7zWx]'}Ԩ#8( Hn>oQѣz>8 =oA>vը-Qk;f?]ԥtŚH /ǙߵQtm֧.Éd,o'IAG}qL'LF́d,̂ɓ&M2D}Eݰ7D?&חx})I7˯~Lo 'kHAd6KWD?%7{oɓ A7 *ŃdnEecrb$oNNtCMA7ٖ^H͍?MAO5Q_t(?AKA>I&'E}uԩRcwuMLSxq/:UҘ>8}ԉ9̩c.)SwH7~?Q]umڗǻ9=5c4S͢9̅_>s4)֢>w}/>M ucn>qO3x#>}4){t)뚘L̍ߧOa61]3Ks S?1]3G)躨o=Í.Y?JAt{ݠ_Mf%En ?kfOKY 9/oO5鋶 ً 7 )ubuE34~>pgfΜ1sumo';gj̐HAon x9O5s<%p Wv-6?+uMԗ8M7}YZ?KdA_JY ,SеQ'总YRԉ9.͙D >砝p 7_fvy(CȑϞ3{6 c6paw,1[b rb;Gb 6s=ą0w9s皍鿝H+͕肮gvA`wwΛ7o2ꚬ;n_ϛgE#5Ae] \b'-/:1HW.\`1}bk{jc![GF~4{ JI7E}[pZ ۗ,``^ƒ-Zp) ,Z1GkIAF}Ś=wD?QGYxѢRuY_ra.JHKkIQWm:‡+;b)若/uQbK[97D]O~,u׺K.]b7Dc6Xtm7TcǶ\$]%ێ^#I5AKcs weA˂tY}'|[#=h #ذ|rSЃ܏X(ѩ˗lCa nZb.Vp,L3/-+$ڨܰ3яήm[r?]Wosrnm_j6wq{kj{_c o#ٽׯ^j.1wtdž:?~i'`gܰfm׬pY$1Mmu.B<[z_}H9~®W5nMbm׮u&9wv؎usD87 MwFzn:mRx`1W[ -88pCژ|]G~vuzN?0A}7hbUnUܒ64;w#\pMްQ7p>41߿q-ߏbpKoڸi׾O7m#Wp[!}?of#|}6n+薭[τ> stream x U[v endstream endobj 133 0 obj 664 endobj 134 0 obj <> stream x흍yhCLX4Jhb@l$H~+V,FĊZ FĄHUD*~׾ﻻ3t>vw̞3g󜙽ݹ~}.*(f'P @%؉O?*8YcPW;駑SHȉH'ǎ :g1=;NCZvΎGw#_iѣZ^#'Nczȇ7c:R?uxgL )R៩< O1G@ [;}4R#Z.N<)lH9_ M`LN@jihiOˎOh|Eژ> 2M;szwCZ/o4}Lb;q4wLxC TqϜN8MÇߣJoHwߥ3"p /gҬþwޡoE옾6ҪJ{EIH⌳JS^fC C?4~s= 獩GcoH>dRM?Ӕӷ!I_iǩ\oH?- U;wv6)ڀ3~N4󘶝6$a8jVmTT0kT"Z:ի;s_?KJTkGɨBj6TWR+6NUZ2 {O6Hsҝ1xLMùcsR?01%=mHFNyYiCFjCzsHM+2GN}~jV6{zlH=cc15{JӶӧN2GOCoH2 )TP?<;15}U樷!h;}YmTԫ$z1 >V0\G˼z}۩u;/C=2ĎS!kaS1ݾIh;hCzDQo!EN~6:F#gkmLxRxAcjC)ǩ5t4zd^+(}R#wUW$ې"Q?M;H'Qq)}G DcZިG!Bژ=F\G~cڷ!Y{E>Ku ;}7G?4RcjO)Oԛt:REcjW C>HdǴ0Č)wCz8t:RSTEI6U!JFp4gq7gIcۆSH|Ș=z۶ Ծ15{zR<x'1ᓚ26DQogCj+0=cji)GpImlH{OxC>uIP)W1z0Iu1: 7zU )T:DRcZޓ(e_m~֦pQgE^%ueːHMr8Qo!ut˖ԏ IwI69 z} Ջ?dT_q9nHQ?q+2Gno#M8=oH͛6U]jژ=z1ݴO]+cj~_VZkUԫ0 )r^1Ja)}C {/FgL+{E{++U.ޓW\s+VT+ *]Z Pԫ+ crR[V,JfC*]j}8{O2{; ,vı(국!._nfUzO&^vL/_FmY$*=F{O)21]*^2̆;˖N d^Sژv@m2kG7#nU*tˠ )reQ. .Ej+'Qˎҥߧ2{*Wގ"KP qȣRxCJ;6ɮ*W)C=K\O-ԧS믷@iz7突^=F 24zJXWz{OQpCK}E^ WztbZSJwIcV)= z1; NzOJ0<SSR[c=)=)⯵:{zd^EL^NݱQ{E_q97$_shꍕdWߗz13g>J3q(M7aT+DQ/;g. ]q;{kr:YS+DQo!ur]R=iJkI>M:4E|W\ )T:K&{6f]i ] /SMask 137 0 R >> stream xݍvg<0oudu%*}{_Vxà |mۧ!ˀoOB`o~Vhz}Jz`Mҿ$XߏGҿ(~6{4OxOx4}4=y9h<Iaޣi? ~9&'>NI&`? y٣戃iyޓNn Gҿ!9ӣc:ߣo yh:9P.hz$h:y.h:9?.HN>hKqӮh:9v]H qG)蚏Gҿq8+?|]Gө?MHKg%h:-U3пij^Hk/stJsb_>O戭<IQ9&=N@װG# {4=@G)[L}4="SL~41߈y4>y4hQXʣ4Gy4戦F/|;p$b7]/!}#hz4GͣGsOy4i!}6&hz.|#hz4房x4Et&C<+}Oh#4G|4sXuُMsGx-Oz hMDst[{:6[^ԁy4 QGӍJtNsԑ'戂#}-KOt.=U4G4Gk1^zj4Gk1#}-KOtQGZL9H_]EsDAsԑ'Bzh(h:bDW}(h:b:QGZ*# Nsq>ӥ'戂#}-KOtDWQux鉮99H_4Gk1^zh(h:b:QBzh(h:bDWQHOtQGZ*# Nsԑ'戂#}-uh('戂#}-KOtDWQux鉮99H_4Gk1^zh(h:bDWQHOtQGZ*# 鉮99H_]EsDAsԑi:bDWQutDWQux鉮9*_b鍮'戂#}-OOt/=U4G4Gk1CsD!=U4G4Gk1^zh('戂#}-KOtQGZL9H_]EsDSzt]EsD!=U4G>7JZ*# 鉮99H_]EsDKzt~ZGZ*# 9QHOtk1#}-KOtDWQux鉮99H_4Gk1^zh(h:b:QBzh(h:bDWQHOtQGZ*# Nsԑ'Nsԑi:4G]EsDAsԑ'Bzh(h:bDWyi:bDWI_]EsDAsԑi:4G]EsDAsԑ'ʛ.=U4G4Gk1^zh(h:b:QGZ*# Nsԡ9*# /=U4G]EsDAsԑ'戂#}-ux鉮99H_4G# 鉮99H_]EsD!=U4G4Gk1^zh(h:b:QGZ*# Ns:}.KOtQGZ*# 鉮99H_]EsDAsԑi:bDWQutDWQux鉮9*# /=U4G4Gk1#}-KOtQGZ*# 鉮99H_]EsD!=U4Gޤ7JZ*# Nsԑ'戂#}-KOtDWQux鉮9*# /=U4G4Gk1#}-KOtQGZ*# 鉮9>UbDWQ&b:?[#}-KOtQGZL:=UbDWQux鉮9*_b:QGZ*# 7戂sԑ'戂#}-ux鉮91UbDWQHOtQGZ*# QGZ*# Nsԑ'戂#}-uh('戂#}-KOtn99H_]EsDszt/=U>t/=U4G]EsDAsԑ'NsԠ99H_]EsDAsԑi:bDWQux鉮9*# /=U4G4Gk1#}-KOtk1#}-ux鉮99H_]>}-KOtQGZ*~QGZL9H_]EsDAsԑi:bDWQux鉮9*# ]%}-KOt爂#}-ux鉮99H_4Gws1]zh(h:bDWQHOtQGZ*# Nsԑ'戂#}-uh('戂#}-KOtDWQux鉮99H_4Gk1^zh(h:b:QBzh(h:bDWQHOtQGZ*# Nsԑ'戂#}-KOtDWQux鉮9*# /=U4G4Gk1#}-KOtQGZL9QHOtQGZ*# 鉮5}-{*k1^zh(h:bDWI_]EsDAsԑi:4G]EsDAsԑ'Bzh(h:bDWQut/=U4G>7JZL*=U4G]EsDAsԑ'Bzh(h:bDWQ*k1֑'戂#}-}:4G]sZL!UbDWQHOtQGZ*# Nsԑ'戂#}-uh('戂#}-KOtDWQux鉮99H_4Gk1^z|L_4Gk1CsD!=U4G4Gk1^zh('戂#}-KOtwk1#}-OOt/=U4G4Gk1CsD!=U4G4Gk1^zI_]EsDAsԑ'戂#}-ux鉮99H_4G# 鉮99H_]EsD!=U4G4Gk1^zh(h:b:QGZ*# Nsԡ9*# /=U4G]EsDAsԑ'戂#}-ux鉮99H_4GbDWQux鉮9*# /=U4G4Gk1#}-KOt]%}-uh('戂#}-KOtDWQux鉮99H_4Gk1^zh(h:b:QBz|I_4Gk1^zh('›FWI_]EsDAsԑi:bDWQuts1]z>G4Gk1^zh('戂#}-KOtQGZL9H_]EsDAsԑ'Bzh(h:bDWQ#MH_l/=U4G4Gk1DWI_]EsDAsԑ'Bzjޥ7JZ*# #}-KOtQGZL9H_]czt~ZBzh(h:bDWQ5h(h:bDWQut]%}-KOt#}-KOtDWQux鉮99jQux鉮99Ub:#}-KOt#}-KOt.=U4G4Gk1^zh(h4G4Gk1^zO_4Gk1#}-KOtQGZ*# 鉮99H_]EsDkzt/=U4G4Gk1֑'戂#}-KOtDWQux鉮99H_4Gk1^zh(h:b:Q]\L*# /=U4G]EsDAsԑ'戂#}-ux鉮99H_4G# 鉮99H_]EsD!=U4G4Gk1^zh(h:b:QGZ*# Nsԡ9*# /=U4G]EsDAsԑ'Nsԑi:bDWQutDWQux鉮9*# /=U4G4Gk1#}-KOtQGZLw*# 鉮99H_]EsD!=U4G4Gk1^zh(h:b:QGZ*# Nsԡ9*# /=U4G]!}-{*k1^zh(h:bDWI_]CZL9H_4G# 鉮)}-ux鉮9*k1FWI_]EsD!=]bF%}0z?Fsݽ.ݘ͇/a.9oy4=SM/> sܽݣ4GţgdsI_83tVtv铒t Che: ̛M9}_ȣ'ZM;wS7MKhhZkz-G2sMhhZ)=~ģir;4Gx4-'<Mg[Os4GӭH/ [&h)$qy4"QGӭJ/sϣ9&^"QLM#&g~|<4GMcȣ ~ah_j4GMPxjsOG?k<<|^{49hhws5khhɣئ endstream endobj 136 0 obj 8432 endobj 137 0 obj <> stream xetS)nppwwwZܥhBK{Mvvd'gwLV5;, Ѵ?,F?_4n`!T 0b}h :ɾ"d~$`Ƨe򐞩e2B$2̦ߴ? ًy7"Oh~M+d|3 /Z)=`ﵵW!ڟ|ʓ,YwWڟ=lϓu!1?YRVcGyɱ=k'U+?R&cshd#ȓM_1 bn6J!ܠd5 ֊,Uh.Hմ$K6>`"NUvΓuQ?WFgES#eu$Kj|^2tuڂzqɲ/LsED$+3/H(eYU &$bq9|A:/?:9hdVpfxdj]̋dgy%{ 7c4CyS(/ލ4'.x@Fs!@ܢݚ%s'>x28rk'kU?)@qrjnIZLmh 'j+O,#I]|˓U~ `r|Žo`L͓n 4s\$+8ۛHʂWs͏Б9g0(ʥD|Ge5 C6K$v^C3$US& N 6b[X'(O)j^(?ɒS(Q~'0O6y'B#87$q'YFil$Ǵ8Yv0Hzb<x}Q&zIз^)'G0@!_iLc?:@RW.hlj| . '¦e$-m>P|D>/q2,N{%of`Ly(Vu?iyL'Yp4$ ŋրm޳ӛ.OF^UM'~^E_'g7]dv͏^E#=WGڶa@M~R;5%P>8IPjK(^4=&i/ 5RDi/ .iL'wlq,CeĽ>טde] tIrI^LPqYeEs`Oj}}1yW4bbjFMsqR5~@k"Օ&OTc'0&NU sDqɪ^QI^Qaj\t rTqR(1+yJQ+ '` $s>UL<P_H'>&`:jý#`EĊ*E;8F|CAH\sLM"'4>$BD?@Fs'A09<`n#lOyOk0Ê.  ?9B%xֆ>I:j`'/BhAdP`n^SixO|`֧$^6(0s1jQ6o/d%6sQ^f-Lz:]`"!O#mDMَS$T~I z c]0[&O ɺeiGHu^QD= \kw0KQB}'{N{ޓR4GHhgGU!h3  Vy'uI_iCh7 y*$ fF},}7c̼@O9/@ccX wf%Mcc}k! x>7Yms(} ^~?)uI0s_zm3鶻N+ %yOfSg' I9=_fnI"G)IOhaxMt2zJy腂`sڟd֥]ie}vFĪ5BARO*I~u!ўvB(|gms˓C-a5Qr.IyBA69|$sG6QX6zż隤_`@is-RG"J#򏙝?$uǺD?hbX|0{w船La_KUh#Su|$-J}Xh>Q݁v.ˡ8օ$pQڱ ͏"/1zS(C-T$U/q IGF3x=aeui2ij!xXQiz_B;*o$Cfډ[E7EkDE;ˮ1g$bmayk P$/H;i{#ҟδl/CPvLAn@mYߏPK6.}oT#-@]h3?U+1P@ݻN`Ŏc%яvLY$?΁8E>Is`2){:qNUD=ژrq5Fi[ sF ݮO;d{uGuFw so'4,mؠ+h'F!P@Ij?dc"r[e~B%w[79;h ( ',]Kp_,0)Jy6/t?~ ؕ^w /XER} ͅ@^ܴ%6( .j%~RH?3^ m3Sb}/'-?|8<Aք3m.kE{IYiK>Fg/1NH8%#z o 3hKakB1?c3T'|kIY=O;v̥/rhK&CϏxK=*%xA[V|H]jGM88wu:c] K9 &8EhO*6պ@gcK,*u57tbva!O2ӈk|wS'®`v$ymܘ״tX3'.}ly2{+HNKGoek(Wf×._P Ֆ{?>U,x{oE[K,+?{id,Px2Ŝʶ?zU+;tᙏbAh`:7%T)YJWoЮ[FFN\vۏn\w5LnE;b#̕u?+T%}/R ωv _&k T֠qkx+_0fdʞ^&Zqn}ƌ4~Ŷp]r K= ON˗(QXGM\o'^y\/_ ]RPur wשuq3VzgW{4G˓>k6='6k1^Qe|kOߨP !x$Xz݁=HDɲ/P sܟdl,w6)Sx?UW:}_M,YK.K;ɒOOϗ?e[UTe+SaC7u^o/A:?RdȞ^hN{c~[M'PD/L>+_hJ0aK=|nrǀ~iwe/6Ud'L%4hO\z[n_̯_}cC]FK6Qs;rRVEo_jFyG.?zZ3W~MT0#|dKM.c<)dY4>ߨY]o=<9IڅQdʃS 5^rQ>kK+o̎ldSIMbg)2Y4jۮ&_{ٻ?qʇI|A evfC…(:Kv/0w{.B~|5%izH`i$g :v~p׫Ox|JkN&v!I˗:qK??E%~;I=ĄGU&4{'HjMڗ{)|n2-8i)Y/S}v$gy~y5N{7QQh@2IƜG{R:EJlߴ o?>C.X,d$K$㷙t^2d狓͓Mw [ICYr}LK̜d$H{9@bn3ޟ$Qkj^2tIF4Oh@:[)Nt}LI6O'5P`Z͓lNtry"Oh/@23Sxu:<9D,['yJ1CrHG4O?["CTA{ҹJJlW 2d_iuHg8dӿ^1d\WKL=PhQI&ˋ!`ٞ| T崗 )ҷ$ 0#HjayjM{:X\y ,yCÊD,ocrqZG{9`ү >hv: \_ԑ2/v8]h|/uS D,[z-PiX{I67=K.Nɺ`ٞP;Ho0WB{ҚEj^-\ғS! )ʟr$i^.L%'c_ UCT6H*o^.*ۓv$C,N,^-אSA~ 9j[ y )8xE{lFn_~ګVr3$.ZiHF,Oi\IE=(@,Ohy w8uF{zۗXZiɇe$2i@Z 2SW S^FeyYXlj`'TNp˓c=O`Ƒ+H4C{[X_Xq"625&wlC*Ov^.C*N< h/@bGSi(B-P^,6%?i/@Zѷs*ٔC{F(N2YrǁT H4boJ{Cl\ 5?<w@ClDW HI)H]Rqnzb$5LbxX9 I|2b=<\M{ҊvKM_8K6 t,ptlmO(O)[o|-^+vd!i@br y,݋Z(YYOBq_wt*e=xntm!UsZ$y;|M ,ݫd$5vCҽE*Ou/^+Ծ@&N% ,Ld$x#҅&kh@j!SS6,ߍ $[K{RٌPy^+>ճ#^+z&'oh@j~s :t$ԱaSэZ$8@{Gfu YIa#.Ă LgB,X>Jdz.ۖLdh/@rZ EIK&Ou?1Јwh/@rk\೮wR>?<+6,L$Og (|ZS؟}m@fQӸp "qٌ,`Ɠٟg^*"ǐyg!x;6l}TɅ$3"־?.Ε"'FrKܥD$ky|m^*侭0$&'"W0,\2^)sSݴ dޱx8R$r*3BHXDy钓D-knH@%7 6"'Yx"'oW =DFB{KN N o3HOV=P,Z@5eɡą#"i/;$j^PU&'7i5 *=4 V!Q0/ywp$s @$pb^RS! @@Hb[he$.:oP%С!BHX_H8ɲ΢L"x{YG "n嵑>Oi^( K'YکpLߖ@2N@Ȏ@PB(Ns>Oc(;+5 2K'A @B,VVR'*?iRɶ5 S7 !zOIk' !ZFd[3u󢴽2Oʺ= JC[ym2xTF'm |Nߛ$M0uOG[U˓]󧴗 @ćoP6D^'rAm%ߠ_C c*$mͼ oij[%UlLZNAIW/6,cg'U/6g 4qM{$`'M+]N"WI )ګ "xE{E|% '`Ω>F(=<#^ uJ*eJ JP37- :ѯ?*O’I;umʽr`ğṕyKܒȎ/SSN_0uͳg (Mj.O);umU%>bV,+ߠRԜArx؀WoU((SdúHBwKSih+|O$ak}^#!!{+S=fgP^$!AGW*~IB3J`j<(I^#!GjOʓ[["R @$Lwu'`ƕiΠ&fo?5rBL%<2jPVDr K\JFb7sR)#I8ٔ9L{h)`ҽLZl"`EFTyE% uk Ƶf2r-6 FRurR+IA%'TgvA6)IMD>Fbn6ɜI$!|fy.zw`E̕rK;u_3BIk>a^^#);(: ީ7b3xX`FŶY2koPgP?N]k ,A{D˓斄vnrn$pxuhfD\hSfQS7)Yg>D{9 _̍ K`Iߴ@JٹFR.7Ț%6<1VcfD?K'fWnPNʶU3O̝U̝C]aNݒ-yfD-A$[);uTmvB`Gk<$D:u><̾c^lYuKb+I5DbwVȞ=[Vfx JԵJ sd~A$ u sp}sNNE4% M<5 4-qi=rE{J۩ìs.Bb\PصXa Tm؟j=J|:u5M;u0d{9rgPN]a>/ob̳ oUs(;V/eNL/2<,gPUD^"9˫̑#Gv3(#ԩ5\v|_^1WΜ\%>^O(hYUy=22l}a%G*T$ߩħwKBSW$'޿0'3(M~IB ʑe;\7DPV'#aJ'˟%7/ Aiu BЭLqQ0 sxX*εB+^ 9߹T_=s#4T\ìkİe`IE sRAYSWP% vEkLTyozHV'A a% XzQO$!~-V$u'~>V(ZT[0ܩkdx;u#O-R @nVcMeWxy I$9kѩޠ @gT-Z+:2ҩk`x*ON]UI®> XxtbŊ Jša;u$Ҵ$uR<~B4ީ+v-VU3O"Z`xm[tkSz.mPpˢ:2=`Jn%/.I$t$lL{}$=^S"$;uEJgPlsn >Bw(]\( Jf'^fW~S7-YB'-^wr N4Π\L*OŴΠ1<,SWxk4S~]Dŋ%BKšyF>PFd0H0bR副=<ȵX03>^IgJbԍsxoS^MZ{ӜAi$ uߒMVfO.\\ߠ5sa[;u:KdugR>e ˩U3llx故)[ߦ:B\W䉯k_5Щlhx}#i=m˔*W0#t:urpGyYҥ''>F(Nݬzb[ Jy<UJ$%>U3O!ʪ_(Kb|-ڠJ% #"b;ucKir`߂:eʨ6(MIB J$!r3.nV '3(0k|bz }0nU.OSWdxYm#`Lӎ5| &ک[p]#1jTZEUS~I;u&/ѴW@ρNUyoPb% Ai sPj; 㿻N5ep5 FoIhus̝8¼ֵVZUUJ45s#4 2,0&&իqyܒS3 { :_̓hIB6#N `Ƅ@*\ѼSHn!kٵ:uPUwa{^"PkF_;<,k#qkW5_0ҩ- Dᷱ?cb>mhVF|IBZlr 4ÊLJ{q=ޤjR$*WtA)dxxXNS^1@أ15k4b+hO48k憇vy &?лnM>P3(N]" +:ڍHCZt Kߩ+:<,Klg?Ԁ5654b ӛn)6ߒPpCSWZl.T> =Y].O% aͼ$(T5sW|&~φ<թk٩k䝺95 v> Xr`u/I\)I-6 is< J:u% a\I"߰^Q'$ʓvnyA03(ZO XvAz %zgP;uc7\B+!0'˜fsy9{3/ yހ˓OS3;VTS+I䩳.kbѸAzf.&/ǖ$u<^ `6h[ŗ$4gPFv J;^yO'5T~ JةUP)I>ޣ 9'3(#gPb$HSEp2p-VSWtxX@NT $;ua.72׫:*Ԑ{lP5EŊtVfL6_Z'u@IBS3WA;Wh/ 6nmPXnkFީ;wg'`M7d$-0e ]r`N[oPF:uJbU5^qTq#VI l ӜA >u&|% abzj90'͛ry-I_L,'2Ošy8%k$ 2/nբ9A5k5sJ$ u=`O[+ԜA>z'+̖-[pfHЩ+(IhwVtk}waEn[qyj.8-IϠ +Rk̥@T9ǴSoPMylF\ީ[]ݵUK.PZ5>^+۩r0PaeV4T>P: vj nITs/Y[Tfkêk``x2O۬[A1>nޠv% D)NO Xk]\Z$\9*?xQ6 J$!kw Sw:ݯ-'- N]aj{_Ŝ0`<"Om-IAAթ[rMlvm;- N]T ]72.ʓ$D3J| =Ve)4Թcn\txSص*qym|NO|%Vz% kN]MIBө[94\ST+oIT{ y6"Ok Ϡ Sf]/p , 9[Ϊ>>Pz% af^%QMxXٲL}1a Ӻ+ԉ{$bE:u SOY.(1(d$*vꖯ?G '_.;O|$t;uSruL ;={.]<$4gPzE;u+87Fw %aSW$!z-| F; IS풄pj*aT~ߡXL:A'E%|IB]3o\uީu[(F=L?\:yڠZ :uEi^`nh8F|-ߍ˓≯_5<<tqO<Ν[;u% a\ JA[olnݺ.IAש˕$Z'`ˋIu j4$Fm\<]'?<0NؒD^1ޠ: :uE_.I4}`R={7(ay]͵X-VG;!=yݠT5sb;uEK5;My剫$ te7ڋ"ۥŃz+ J$ے?tꊔ$xCM/6 ի'w{epxX}=`Rģ{+ JX0ҩk5w `SSryRJh]kuOЩ` $lx޽4`a5[:>w`Sݛ˓NIB3Z% - N]aꚹ$Ѱ:¿\X2?'aI"S?}3ҩ[o l ~~*O[ڝ"% 3:uY}'nOcKkZgPu42{`cGx͗$45s% f^@ύUCpyS/.OgPF K||IňCq5fCЩU0N'Fz=`TӇPJu%6< lt:̹ 좑<)k||I~IB얄hI'W@Gcqy牿0[GaM{.< 0*Ѧ1Կ|ͼfSWz%FƟ&:/9h ~|I"Z03(ag*:俯->x eΠ;u :uk]m9r3\V:;՟?*I_U[֨Ͱ-O|1p ?(UIBJSWoxXӮipwC 5pIB Jlx"P܁Y/L NIBX3v j:u[w~=|8t(AŮj:uEq%fL;C{MDuEJ$שY0#Ævǵr`3ƍSIUPA$ ^-I7."}X:yAW0ܩ+־$Z!? z% a o4="3a'% 05>Mn;"O7[ޒ0Щ+>Ŗ$bE:uEJ=z?a1nm¤:% MP[3>3O0,ɵ3'Oė$Ty583(#ԝ=u ]/:J(u\ة+R[i;iw'VM:eʔx$90 jz\ٱxbRPAVIB읺gއ^̊ӧ4A/It*^|OzgT|A$TyoIt*kCoP)}u2OT|"5sgPz[.3۠r| jkN]uIb/|̊ |cZ3( <'`Wt̛9C(OpH8;ukv f͜9ߠgPZ% 03(MIbE~Ǽ`Y g)%HX0ة.I 3<">vle$-v!3wM{=Du`͂9U^f`xUb0,˽}sΙ3{l.O:% Ýz%Qs^~s\`YȻ (4˓HIB]3A 0d^ Ua_o\hA$jut 9{MolN_+{V/7o.C͊}_S$gPZq.ֵXaؙO<Ǡ=`[˗.] B$!r7;q˔ΠDJf/v'`Ztз'^br?Z`Z斄Z<Ӣܯڲf%e<-ϠJS7 /EmkW*x[ʗ$yҾ%aSwܤ٫w|JMyuW)%V :oƒͧ^ eݸfUVqo$`SwHo|<@oP:%Y% 5Y]nLe`'Wܰv*O+5s$aSWAzgEy>:{`뺵k׬_o%[O 7_i s$;u?Y'̉#rhyRnP>Zf>c&LԴً;c 07Nۦz0P’NݩSf.]>!xzs6(7u^I"Nk_xg'`[O\]vnڸq#'% u J8Es;&`P%9 |޾Axօ|w؞m[l%|Ib9ķx^Ibު [>z% qEx]uN!??o.E|ffJP3-I,ݸ/q#{޽K(.OG>.OgPaWmspH`GNܻw"O*$!]ԍ-Iڸ_~Er`^.߿o*Pc<٠vsRݒЭs% 9}ǯ= «qA~yvc>t˓2P{ *$}ן\ؚ{rz#G ] /SMask 140 0 R >> stream xӱ0@9)&pw |>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >u >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| >@|>| 9* endstream endobj 139 0 obj 2688 endobj 140 0 obj <> stream xuXTpDDNnEL[DDP,BksfAB`ٳ;Yzֳ?|.G %$ecؤ?Q ~'DYv%1H⧺hnrFȸwT1 (gS2U< 'Aᇿ[UYə8Cg뤯Vct@7t~Imt4k L!aޝl)ȁ@ҟ~ÊeT9P;@/H)oPEKXOݯ;HC qpF(tuTeb;P@^TRA(fy ]4Y Gxt@\?l#JϺP2@=gԌ?%d}wWu9P.4 Sh rӬ64χVʓ5I/CH0J5V(kt?T]]@wu bZ}sP)°ұʿ9Щ'Vʠ )wGU7*^C}q C F-P Z%%cH>zUh4;Z:PnbAҐr@I1z_ִ.`,Y}s8Z9P+7-l^c`iOҟZWSߤL-ӦFziz-du QG: @Tm O0^&pb]9P<oKmYVbTjS`,NņcvXqs @@+JrIVj9Ov(B ڜ딁҃ΐYI ?/jQགྷ'ZT|4h)r@EAÙoB5VsP`|ޝ嘒wř20MjME,x<D:k[89/F0wɧo!FL`‰UqR ^8z1sbgҟ@lWW֖F/(6~MݤiIƆ/lwe)@hH@qR7+'<F o8W'VՒbLK(t5pWQt hThF@mhWV?JJn^F3+vw,^rscm@IX)x^SVP-??/@ѥn)UFu2"cu({ 'xI/6,o gl:ہ`GWA*o4ki 'ͫY>f4T"YA<|x1T՝j#|&zԤ@II#Byccu4kɏzݎ@"5Q͢L*'}c{R x?@"^ńz@Bx$l+PUaw}I]]QrSi+?p񿶴lH'mThs \VҢ(9zd'@2oJm & -wS.`xfDyiJGqT$;.mA} ȁZXp6ҕE 䏓perӮ3 Gi@Ka6KQ|ElCnRf=FƤlR nw0|/$;*+wkjdHĠŀ 3@^aWFP\`֟,3@ _Sy+_SEhHc@6? ɠ. #JZ2,ʤA  oۺP¨5bG)X%\i /a_;@@پ6Ҽo-hV[MoȒd Co2 &D|XבLj~b;@Y_9"%% _Plt{a!hb;Kʁj~X) חT BG bes9l# TBETm@z ,ե-PTv83h ʵ9S +ۢ&*DsU}=퀬=홊h @t-Oz(@EMB:JF?Ù2佥a1Pip% \veeƒ‹ [9Dgi4n!![4Qo1v@/y[Oo $}Y,ʗnT4X7^pb>E(9[~fliFՁ^}>)+L?#hVZ6Jt[GEk(YܮӦA֫?LdrnsuzlT$v [+Meڏ©ռ )vUIO 6d*PtZ莹OSiHHPyEEZix9?&t9PRwōЀᦚL%%f+mI (~ކ&QաRMIzC!/ہYږV%Y4*,!=: =+a ^֦z'|:lLz@!pL7y4 >kӬ(fKx09f+Z^5ּf!@5^ڋ-tw&b0BZոɗZꓞШ.v@1^ԇUƴi֒5)6aG qd>mW*e{Ez>MCǓl* ې%`6>r gUJJ(MXXo w*&cGXgbje9ē)`Ojy,6,:.{ρ@ .,C lT: M*C8@NtEU_EiEf5j"!G@II|X(5~nMzf 8JjxEzZ#H0ږHO"Rs3. 4Zl#H5| j̣ؤ *rPRE7ہiD{),Ù2HY~UI~[ ]1O՗l-9+p?M8JVxe3)y]\8 UNBz^ZOI0YڏB)|)GGY4kJ#=vAO5{Ujb;]=lHHY?b=9]2W۳QmRr;ɐ.FL"ziU9\>ꍕ2H7`9hՒ?!rCиl\rM6H=uIORPj)A'ρFˋimK]ғTk.zNz A&dr]ΓCwXMmHѩ?8|Ks8:\:S_GoWjɥ$VP>FQˢ4Yb;(KZauUz Yz(VC($X#rS_*FPBn齃Tq_ͭEzKr9G?|o3XJ{ƑOOG󚐞R/ )p[XJTj/|Az)(Yb;tW-.T*&=@stizvIYaA)#=UR{&:Aq_TbDB}~DYF? 63H}Hɫd!U#H4׬gETKA@TUuIORh}<츣=+0}u d^j+  j2V4j#ܠ kR,ᱬ&7btI_ʺ=Ev ÏR#q#-ΜסNp:pًRn :J0*)CⱿT䔡].F`চOMzrʐNYȃ,Eg!=@3S*Qr=q9?mGٚwH!=@+=2IE~u~-#ȁp]=R4CLUYX @+cnCGh$ai ҳ}R~]R$@`@clQ#:CQ@,=L?E,ʡiB,mZ$RKX*C_(ʽ3* g<Èl$?_콹 :;F?~ wVGQ /F Ѳ|uWR<'pBUE9PRn׊.}og}3,"5ȇ():4yHH៤ a1iH^Y/STV`{T = ɫjΔXԊ ֳ(?;RI@L Zgg18KSXf5PEHqbe18 j HZE>ds#*4Ȉ|"6ȏѤ{ u}GeZQ=_֒Z~ƑN@_N@R,%=hݮ錄C{NJ}ElVCTdBͯIVlَbb͢B) CkJX/"p eBQ@K>5|+Kzў[*;29N 4`;{i5P՛<gL2:EP`1/xCMSL.hT#fJ ozB;L [cQQ(kwb;f };JQ1{/ (|I?ERa (K{2 J揤2'qҳKT'Í~6M|ǣA(c Cq+/wDg;IsPԒ3,a_gQt3ef,!=LIh,}mpvP<ͮIxavskWFx0b~}ѤT &\sRvŦjSp/qa9ғJVG =OE#c]-J@VHKUH(9Uc4!0qO{JB(cn8;(!ʫƓAR6"?Qp}NGJn]lXqo xIwW$=fc=֏hp][>܋SRP1} q7:9FM)E(w ]MwFzKElG(k]ɥl'#FIO#W}D?[M*J|#ީK(ۻ(9ē.1O'%=a-4p[,*A~ n!ȫx)FZg3T: % Gҡ?Nσ)Hc >ldP0Nukw&A~Na NѤS(>mhR7w 7fLz0KͱX*˙4-Ifov3Lҍeg*U*k\IP,u|i{+ \JK8J6ܰ@+W`T* tH'BѱW'=iH?.w }j־#BEW Eҧl0 .<U hh7܈~xa=wަ! %Ug~ BQ;?xrжmeK:Tt] BQx88}-Ə߿ijժU24hPNOO~#Jj{gʉ/7Wϟ?wɓ׭Xd GܽCUBWK8Kp???...Nv߽{vv-1cԞ-[lVIGŧ[7XJ{{g8wƐ!C45+[FGG[[K𜤩*hH1w %GYݿUsO:~{wi%hPY (_\VBLLTǏ^Y=~dy{.2iҤ͛5kfUzmi Íthk;w.ݫWfP-Aa_@`^Bo6޽{a-[O;r=uܡyFTX6J|/a~zbdDD?~|~իwLM/ݹie&GNzȦ`[Hri)))ɉlܴiӚݺuPMl]',"<UV-8O^];nݪEUtuUծGBC||Ç-n^<{-+W,[`2Dk}#-]5hVv e 2bB]Yvp߾= IOJ~ JMM>' xݚS$@Ʃ Ј'% jk`0IzN:j/AUHIăeީ9IPxcaR$Bߤj$u='=@kdŎdsN*jInӭ^ xia聛|$EF2m"=ic*V?aUg#9Շ<™2$:/"=)Sl@g#9׼OăaǑ䨖u1 - 4l$Hjo{HJ6ϭIOFu?W4ජ%Hz%H@?gŭLu5j? ^KJF2͊e(y\;{S1l(9^a[tSx-5^Vk +Ve+#&߈׼rE\vltE29lذ۶mۼv*U ZV?&LY%>'/avn8t&&&cm޼Nb;Ə#͋F: ?oZW;;;c{`2bnM* !&"\f'QlxWkP4sIYkw}ݿYYXX-fzxppO'WO߿{1M 4p@V ֩QAlg2 r"m{y(/2ZkS2Rb#BCCC|ln ۴jiúvXzV+;c  rF tW}WiU}xfzϞ5yHsRl/9Zd Mk#tnܸtr>+ȡ+!Yr,S5 nDS(TL}RvV4^VrZ,LhiBMHO"ШE@ IO"|$HݩGzި4X$/ p :I^6cʈ$/y{0"I^5naû6L$L%BSZ-^H0wos9hڢCߔ Pd55Hr*Lzx*՛Hqgk2۬s'=RdPxUfG ,s(FƥLP\\ҟiCz<+Wz@:[CQu r\#Ԩp( Uv@3v ـgdۚ'`˓U8ݬIzKVgkLK;WFns$=RdQ]JAzE!G ,i%9^jH0Y'deAOGPagd*3p  ם,LxE<F]ۚ,LD9GtJ&=Pd|qUHrNe2P(}ҳ\2%/PM'9.-߁B1OEP| MBi50FOG!9xs~ghu Y'©#qf{42Y.YH0agd'`S ϣ)P@^2MBuIrfأ)P@C^}MB)A&djeD)P(hҳ\2u&qH0Yつgd\4(qY.YQ eGҳ\ ^'`6yHrow =Nl咵>8q@zKŸ@oVU@&xgUIrˌ)P(/sZ}^R[l dPyρfϣT59_F ?ٟE׺^#P)xkvgl> KI_l8V"=%Ҫc"PƷD͟d(`rPtm=qf ӌ,\'tCҳ\(eUZ]@z٬V#=%hEz|(ĿC,DY}]2Z!=%Ѯy h@5h|K\ $=%2΂8EOzKV{d(Y.Y_I0^gd|H0mIrԻ'=Nl듞wRz(L'`2~E }\zL7jMڷ6UvEv@%vq}tk^@۴HOstB)P)"M\;~(`8/S|. E@c}HsIteɆݬP)pFUڷ6=wpJ)︢T<^<@atƋXD@x*qҾ¨S eKy\H0\9/.xaK8A -͋TLCz|ӼN`ԦyNi5JEIzKREңLeځ<'G ${(fa]\7p(gdDzK JqYg4X\Mjv@? .*-7|}$0|JS4ɖXB!=%ZDzt'=%Ьd9HOt ^E/} 'Z@)~e+>w u_w vZ@GI©MzX뒞S'0åjEzN\Jq"P'= W6aKrjJz "? lw&`8;tjK>8Mj9jAzK29j0EzKPeTң 3D4(ñcNէ|I0\6ٍNz-rJ =LpawǒTe2Pg_7]ĠkN] p JVD&ң ǏGzK'a\GZS:lcT8i޹H  >ӋWuNvP&+̲L'=Lp> jjq%yQz0ZIOt :L#=Jt.ېԚ"tkruX?ZD`9ң ljАE:Ӭ"H0wOEMSPZIߖhW?V䃉'K2p.A/9hdXԘD҃LrSD/r ({9SPULcH0jzAQPi1^8GI0lUdb_z/7*P6^(p ԊvdVH_ɬ7Ŗd.'7$`OKRVzݟ =[T/8Lnӻz!T=Vލʵ: Vmz{26 @8Y'uW#=HtSHOi;(ӱݖ6%= ;eQK2PT/J)~-?nOEj-7h@_*  fmMeSPk?H0sgiT;C4;xz5ho%=Lpu^&@3 reΤ  :/5\!=HxwwρQ ~Z}SPCk aDzJө  wVSPUM@T PAƋ{87t:_Cz"Nnr6-lB%e8K%:NNvIz'= 1վoJe_^-۠tj_Kрb IOBUkC4'`cz&7oF@t~ Z#n /Ƥ,ɪ$`<+|z^q'ޙ }؆T/T<jY/G"= UitqfMݰ{Z:gzT[#=HxoeP^s~:^:3]RI0^t>]Z|uIOBx/|$5[aAZ#tIOB6"=Hxkh}@d҃fh^퍒kjt.*H JboڒQ461%XZ z w4dZ=HOBU% Xͣwߢk=<@5/ZtA2p qmS5e5w4{ Lw!=Fx[8Wz%$`_8e!P-LU稸| Tktv*:)s`~6MjiosjM&=Fx<ˍUUi.;J4́x%P.5@CU@9o~9E@h9i:_(wH9 ݹ߈P`;555qheoI07jz}@_  s!sPf0Rhg@U9P68E=Eh5@9C5蛃~>Psf#uQw\m#!>R9PV̓mk@jOzFzUפonDPw~ +eB׋18<ll^9%JMrq?Ӣq;v?MsB&*"PaU+@:WtXwWq]pVyMa2s HW^<ſ[Q,}sP_4ʅ^]V90$%v@5Z9$An;*M~#=Dbޙ4oTu^%=D|oDh.q#=D|< D99GtI;jija TK>Ե"sE@dd璲r(-e@֙5pZI ms{ѡm?Kt0 9.)Az{sK`l@Tc\ t雃>@9ed&GI(73@=óvX%xw5@[[4oQ!m:}spC wGJ́f C ~VrWwNмEhtCq=7BY@E@i4jpT^l?vh8ᇮE@9U蛃CE(pa A <6H0hkmBKеmeŕVp/x\]|c~ɤ35U<`MZXOAʈWZy/)P!'C -LcG@蛃vQZ[M,' +[TG]fP}sSuM!㧽X9o|6E@9vņ9sO)-ʵFXPRK~VE@YoZԋ9>Ĩ<]s=1?@tM+sO)-%I(5]M"P{W)Oh4nA܇S堜8-thRE!w_mŒ@U蛃WY@X 6ND9,Dzɟ,Vd'|sYiBԟ8ZrlϳM*3OPbqqr&󕲺dkxY9(q8C h %bu{VPrޒS-B[tmzBS?fCgtAA7=QY74m-34^߾*VP8KNˊKN lB} Tu'=BB-խBY<"pҷj%˹@5aLCCq JNҼԝ"x^]9Pq؅"He5@ʔ7G?ؚT@"7o:Z6DP/^n&soZ*t́~C_PSQJP>ivKʲ́ѠI(eDYi]X9e}e[~buK}O@EI,UreAI[t(v~Qds]R.rS*W*@=~%]ifޱJ\]9P{1qSm65AJ9T_me v>PzŤ>]sj0*!豩SM@x}6Mj|NK:UAߒS:4oQ6z+1qIh_mMS\zZVBL|Nz@$mX(9H-ZU7y&!Pܰ Ԡk^ CIP蚃ާ` KA'G^jȅ-j8^/bA"6uoD4 /55iXGB q]5hR%1vrP:W,9ը:yEפ]sP!x#pFtAVhR{amajs HBWY%E9ؼE -O !tAAu隃a֧N:PxP-~VoH([ ;3juF]t|]}4Zݏ}A./bfݺ9$fS[*|DCSnh z`u2tR'@:hj`9nQ(;EnR-Zod!ʼ&́jy1+6gT\Ğ)Ȃ~MrsZ-T@]oD\;^ڡ~ir *9-j/)Vq9d7g5nz#4SZ4^ 9ˁ0krX۵/ źTK-v[s@Ə˓:4e- z4i {y+ P_Aj^)-9$A -*~^B3]|5gtls^P˲^ң(B:B>[ iޢ'-U@3:3ngkO{ꇟэe@BȽsoBҼE[˴@=~hO@aPx4AQ~7@=v-7nԨ89(IB$WB @xAoVh&kvM陃=}'=BxvoD y 595 E@=~Ɂ횔:T\W:7 xwEV́VM/:YHuDf4@KrPv4 xfM rI9䴬(+%R'$ EZց9Pl9' I>GtnI~w Lr|N-6pJ9Tܼ%c+.95ynUvѤG7Ą6i&W=I({lFhu89zxc[7 {P- iޢ^-F P?͖oEh ;Hz@!=Y=u Z\]v8;9ߢEW-9f"7o1,[ )Vwg4*-*@">Ӂ9(l Y3MKA7oiCi[yKQsP,@2_բlsP&F;} vgTκd ]ڶz.j&A- iR-ŔZCu2r3UK)%eB.)krFK, (ەi&P \;rBA7sq=O{Zl/pd!vm۶@B]rݼ~![Ҽ|Ty- Z@!Oi@XNi:zS@u=;rF%hR-mR"^ė3;yyr&F Vj@xזH(kZ@,ûo' xT\jW-ʁΐpǎq?7g{ G\R,AbH(^۽C2zM!PHw@i4oɼ,Ts G q?nߡCQs zOZ|I9wɩ(JNU9PkS<zw^AF 7;&ґ967LA.fQ|W^Rn{UrZ3csy^evCcuaʵ|τjS/#=>,x* {䴹(m nR-iޢr' @i^7ew ܄M2ekͼK  ztܩS'q-9f4o1hq $[tc4*w^  i!wOЕ9i1{". ${ٷ[q:s Hh- ռ{' ?馾ݻAM5v\iF- 8n[&2um #=@XNJT I?N33BWqi4yKB4*yq) kdwWE4!kdD{ۦe.0 G QGt*9-FF4o1.z<9I213"n-ԧ=rQJǝv&=@Nf[La  &=@a ꓕй0;r@"/=>{SMrIYZ9Ce 2iwyDZrE.m 2cbQImv-m hBIj"`g>?%Źc rWF oI(wg @TܕbHry h*_rw,EO{e@߾}A>tI9csJNkKNkr- 8W$ p=__HTj9fupE 阃wL–)Pse~IvBVi[KyK$ dbc栂Qigk29#0jO=k@́Q_>-9%ּj]N HPښ!h ̽"SX[cZn-LAXVM:P~ 8-yK;d~ X#x>1F9 Tt7xթ0kO:ڴ 0wA @4oiWH&4o)N6^/1|,$lrO/)g 0z2bqpp:ZG߅d 5y \$HBwNm.ΩsPk,<i'OE@=߽}K!ۼW>-qJVPpdQFI=\vǍywmL:nq"l{nI0\s:$iK2A;-bU3ft1sPe^R-MD9^!-95nH({05jC8xmc9'.90gd )ć"wiK?(9.wiњۼVqI(>+ItA? &=B1?X?ssc G;SƏ {t(mlޒX{>qpTsbm1~rPI%@=ns0:pud;ɕ3&M?n8qFs H-)mh6;9 fgYo7x_!Kxssҩ4A@=N͹O0A0Bs:-KӼi-yrиZKX\qR#om18qrQL@=^OaMzp;xqI[zyKsаrS0(a~{ɤI砀KM \acN~(y8vaዏX{(𷹶w|L@1wNmw@U7⪽O;j rШi h~b4A[|ӧ{Ur:ZQi4yKsS?"ZFBȏ'Ξ&rЬӠH(DwNn79h7jͅ b ԋr}y3O:u8Y'KNeռY-]_[@pKfNY5M vzl09h?hPh 2 fM>]qʴyKtr&("/=)mf̘AW-?V@5+α5i/9G4jD7볻,=Si 88-Kڼ9{ߘ4<x /Y8kL G/)7kѶ˔vaeiV,=#q?;s͂9@)Ӊ n2K!c\/l]898dxP+e`8ӧrOlsg{qpTˈߎe bPWY%D9l{yKöWa/Y8Of9hݾ)-&L7Ņ0Yyw (}ozp%3s0w(+Sqiɛ)vFePd .m:4҃LKĶtAwx+ g@1NǧwoXDE9u4yˤ4oSHN4oiinAhL'Eya1\8sŋ.\(/jyfV-(߱Qe e}{z :~ ~)Pegq˗.`8$6Nryd%ere7߃QJlw˖<EioQW9JN-!@!>+.3W-[Ft7j3oPXs>YwzϺ3 Z dWsйeGy&a e|sbˆ+\+/)OνR*9#ʁ4g\[ҼE GIPÊΕ+V,]6y([:o-skԢ\PXԊ1?w5@ŹWyKNgr[Ҽߴ}O~G&/PMKcw䦵V]Y:w{Qv\x9(8zu֮^j($d@BȿTV[z_T K:Hw6YZzg#l2NH=w{Y' qS8}huk֬@BX{4tx[FyKV}3g@٩֮]V9LB~M6:%'`2>')什Սh>puu@!^zëشn:Q+;Y%[斦yK1rĂwla $y}t2_rH"=Jdoo]G 8oQ!,# ˈwlذA As*rqIؼ%s _vwDu,?˳;mټQ9(QAWrfFu)PJ p{|Ц1[?:%ۥ@ >7-)6糵-7oD 2zʼ 'JE*ܴ(_?Q2Wq]|gh!UIn[]kW Lq;wA >b]v ϊt`}‘4Ss ŋ vʁ ͢d-9z<91vKOq C{v޽k]rȉ)`&+!*5#FMbQ7H0SZLۗwO^:}t(9$axtsu9,^%ȱ +r2c'Lxݞk/KRK틇W>( `̅rBR;`̵Ϛ=. m?.On_|ɣ..9]&A !o鬢7o]_1iTeR]X^;}C1cM2c΂5{K*>'M/0]s0aΛ?uċ/AxqAnN3qSD9$x7J9k]P"A [y wppLd3Ӓc~|qcǎ=zMs0qً^z57m@z~?}rIZ`v|o @z2?oY޻u's H¡r >qvɁ[Ҽ$O67O`D|j@ |>$G~ziq©'O8q8Ms0i)SL{sΞ9}s0k}|, VRBlTxHOo7t3gN8Sg[fcW|Dw(=NZRto߽z D9$!3'Nrsz0OQ(lޒ;yƣ]#(@oݸvK.W?}ѶsXv %٬8P˧/EA 73,Zn7~R(>[@o.?}xŝ_8$d@B8{4xt(6oo󖼗K9K78g~)($Rbý\8ؼ{綹OD2A{IYBX_}#R<<Aq8;=--599))!.:-o_zʕ˗/_t"s0{eowkdASRc"#C~8}{w* Bf.s HBf9 BK5[~t@q9I^^}dGܾ r *9JyerV颜9]'<#bR*y9p"破4VjJJR|X@o_߾~z7_vs0w%V^_Yx ro?<ܾF1ⶩ8 \/. 9W;A-ev~#޾UZ)-9ݝ?P-6oYny'B"br9>"D|~ ͻ7/޽#p -^tي.[|{< 7ao`cogGGOl_|⹕ݻ$ܾ-JYfD V4=vw_\qr"]8}Ǐ>|`W/~G=+eqd^ {䔂-S8 Ir㳓]sϬ>}*iÇ---,,ܿ' o9$AK=g%?.+>2㻳 <cqIr6lݹKY/+c#F+"89$FJⒸBTrzNQɩhOi޲*-69~ή^aqC}%Xqa.o^0*+vt. ;%.2v6o_~"9Xfm>v~ JI W9$!3•rfsp[A2s \!\V.9 ;6o_-ܼclCq,TCEi驱9<y鳏?"SRYil Ɔ{dA|k6l޶cyAi %&|klTx/go_X= s Hh\Ӽ%D99f\1Xacg.}G`D\2AyaujbL돯߾|BV:{/cY<AqӒ|tr}gVO[Z>GlظyYh}?kjam?/)qҒbƒ}pvyS;Y%WD9OS6on_-`]:wWo?}":&(%91.,U7/./o}#(,o ]>{'Ϝpu[f>z'aQI( Ab"BC=]&%E9wUrzo9;xF~ /l>::{  NHa@#Ĩp_?]3o?67}vPG,ml?8|  KbÃ<]wqo߾~!y2K s^3[=|惭G߮n#R㤧%'}}ܜ=0_ ~&g~Lx JQS63;d|`U?(4R4T3ۢrE8aH^_|rI^䣐`ƧeT6|!"@ŽQc}> stream xXc *(vŮgb]lg`o'].xE^PQeow d&- 7~)oJIy\aӄA׼; 0`!e9K&k 0`@?c b gN^À 0ջ}_2x0`A|:7ҮؙN0TZ;JVR嶔C]޾&܁ 0$F}hESM4i3g-]i@\{˶-նn*eS-n1cA-rѡsCusZƓvخ-מ[|\lklk[4Ү6y;h>hpe1HX5^|OJ{ %Οu=t[{nm t?uk6=__q7 roqf &׵z]v׮}~Ĉ>tAshj}Kg-ih|1@*1!H_cRv9~cD?/_v%8՘>{oЅe7メT&ZUo9XXXZXfpȝnV\$Ӌ6[mdWH ] W6]t#$E[t`} ;dRwj',@qwo;t*QfɫL>|0U;te L%[Ҍq̳[V&N3[bAܧ>gά{G!"kk׮3v,\649qOh +, w؁wwxIêb|e2.Zv0`00}epa_u؂U;\ݶK4i@˶dwȝ==gɖԬxeb2sxě0`0ðpɓ'n~S®>}jM^ΗZy.oZ\b>2` [ܷ,Hm6D/L6.Y|_񖋛kֲ]5k80zƸ[!v瞞~u.hۙ% Ł;5c9D¯k*}*8;?;(W}z= nиcN D %-5nEn݄u6':ɞ>}zHb=.T%W3[M{P/,cϹG 8ٳO>y:9sܹ3{zժcƎ]ʇڴ޿#zhܷ>q%[h60È{sul1O1dRظn#:at\q=5Uh՚Jkϳ;̙qqnnqGǍcM7mZᅦn3K@6Xw' ~3P*5iťq+mSNDr{ C-T@M=dNakI|eepMevM_WIuz4iƺAPL< H|={v<|}[v„ϸʵ+e|]b>W]q".YBrVѵT bQrmiZ&_:tԉb:thb{YFm& qW?v_ KZVxr@u.VL7 $XXZ-DBڸ8ѿv2{!װS馝$C[i}g95cIV_-Ίǀ&ƍ'O4m'ɵuSk?:QUܯ{{?=\j^]tec}lO]d\[7m-k ve5k9aAO $ %nsyNï@:JٲTi 0`` ;vQQ9KX$hڢ=uXXƌ s%dWYfz$&N\rVc`u&Mkr7B}b 6z76ھ1E5kΟ2[FE. @X/:7T1Patu[%n3wU 3 $ w>a ;I|HH݋w|+V!f'-v^b 2Yf 9uA k&C 3fzz.ܵkǁ,cL5kV?n6{[e>+NAG[+nTlvKT杂vѕ*_}ke [بѧv~t2;to[k\iA㓋`A@퓦-wt>ܢ R-MlQs-_䃈۳`a|]I|H 80ױs!K H5whC͚hJ;~r3h`Hʰbٳg>%FK.?avxk~alTM%Kw/;fum>ہqW ;VZWasuI6gΝ.]޹aM\@ny1 W'oTKcƿ{6q5M>^ Ɵ .-:)ǜB_69mZlf;sQ&Mڼ2 6m<,M@ 5]t[w<ܡH !iQ &B9!@xGN]mr0p)S7mxԉ'=zჇp!cgΜ޻wǴ Nr]usKzzE׎ ~|mvldՐ۪sC%fWwЏ>>鎪Y?׶6iziԨ3f|>|U׆ o۾r=7{ŀ!5Umʘ wM/[Kt]_б9Ț5_Hք+;&X<&+i|*U~aa\* $spڴ;wtbhhHHիW_v-488Cs̙2 aVlz/VDG-=73c.vMx}(+8y\ ыV|}i˿X봶U4mzM7~_DzeWٰჷw…ڷsWQ.@׃?]6kB0׈'G/wR}[fqk݆g[}^m|{ԪtKVɨ1`HL垮} ΐ!Cƌ+o i͸p;+V"[6Aש[of>>s 5  &jiD zYY#&0pVYdWǏwv I?~yvwɫVkr0ZhKmܼӚ+©ݻo2b˖;vQ؅S>v[GT+ęݳn7a˄;x)>1 c88qN}O݇O0``&ѓ8hѢ}ώ}bsABc0SO0``ٳxc"{ ,S̈#}|ïM.$ 4ڟ[]A1'^J&wŋ\ĉ }Dd h@cADh dȐѱ\rj՚5kk׮ A{AA16mZ[[ۼy,Yɩ~ ,勗Whh(h b SLrh ߾}ټy7L-,tJƀ 11fkl<<<"""lmmm4X[[KδB"S+(1@h H Aaҥț7Ǐ?~PP!89rhѢŋ/[lզIPx͛7 C!7 :o 1`P!b҇?}ݛ6m۷>|Sˈ|?1k#CU@a.4$1@.=%Yu Ϗ9!22dɒ_|ٳgϟM-#nl0w Ra_c#XbI\5мys^Xax[2d` C>|˗` DDDL2ŋް3H Gj <|i"k..{(?rY qZ2eǴjM& &M8A}:uX̛7W^h 9ϿzǏ߿?vؗ/_N> ?^$ Z$1)S 2ח)S⭭K.|ra<,,Uנ v2d&L(TPڴie޽رmWZ˗a*.]:XrQ@%K.\ҥK$#i={V94D 1_~ }xYI]Tՠ<=KeS~BL%l{i>}:yOx]t!?~ضmۃU0rH_'eR1U5[9W@rOjڴyc ?~SJcPd&cѣGo@,Y' Hblٲ1 bHmx{{Ґ[9H Qd wI+7o8p@+'VM@@)S= i 2ڙzej-%@X땁ӿyF4U+P ^@IH+AyzʖOƀæcǎyΝ;lll6lح[*U@|2ɝZj̀TxXPkԩgϞU^Gc???cCP`JAcASI,M1fV71pӧ+V,cƌ4hеkO͚5kaaamm]jUrpœ9s 1K*Fސ`„ `.]zŊ*e۷o/DcA!oTo*>f $ \DAGj K4X::` JD? 1p*`l !h  "ɓ'V=zbU-tDh A #5Ξ=?ybfDc@1 )Cb4CA"}q…F%((HN=ⵐW4A$ =qādBx_{,8; _ ],h  HJ˞V񕁴26 AcAAR9h  H*AI1  4A$~kǡloe9'HGh  s54lܼ]e-h5r>q_>/O^wކ3Go T8 b[{lwѱ_1Cؿ/FyQ^> b>qs1zFPk\4wI> lh8tCCw$_q[7i3dWR  bܸޠ ,^\xV߿x 10uC֏_v$xŇ Xh(ӧ}kRqf@ϟzz@EZ*.م C`i?~>};p]!6@Z̈́m'h;aG [ VAsΚCuh <}պ~!Gڇw1:OeV-&[dEhѣT_⾰[K!.*Z̥"-ʿOO%,.=!\ ^ے;^~+waTW wQ_Vċm~zm?i'X`4uo>y[R(P:|ëw\*K!-ɟ5;Du]'.Wi|Akw\* z࿺7\2 Y<|{G%W `L9N%p9ik\@Q[@˷?~obbbx;H)MͧŸmw=`Tg1׊1ѹOٍrr@$-'#ɱSe_Ӓ!F cnRbZ6=g`^ђ]i*35 J!ļU$[W4 3A8WZ`KZgWR@3ribziv\{YfS}ϫٯ8ӆasƫ14YoB(iWD΀u nh@wÇ>}c Sԧ߿2moɻZ>jѯb_T"(UƀD׍˓˔+^<{rgOsՐz6kŤ."WRw殺dAc E9CْF]Ԓlu8prg^=,-Yg]`&W.u(Ң'\\]Rx|okIF\҄x \k*NyP- :dQklգzv{ƓjK`Sݱ{>?hᱡo߾|s}W=|G}q`ܽP,Ƥ4~|JҬ ՛7/?mޠZB7$c5ь aQ"nDuPR{&_0N"5L7uE~=cFyN7:HV9V?4Ӣ ak9Z͞%bnG$Nk9B v Z(v9┇ c`( fu'M֛Nn­uk4|S1Lin\gt[qrcԨgm'66o0߯`tk^c`X 5ty$?Dq![6pYl8?f#wzsիgڷ{_CNvM p![z^A1ҺQu˜>9jt ΟK"jq=qX|w]ԗrswh/l Ҧ|鲏f_t˜ CqJi\_OJ2Xrո{A\P]+RPdqpOp=;&4!wYjW 亵 Iiϥ:TW)y/qVurs1_rnsLPZ@+TSa̿10 ^\v[uCO )q!1Ptq-E# )TGUx ɛʝĕ*e+s v%fp>[ u̗Pέ/?uhL:~|.`+K\zM.Y%}=>^5+QH"[7l mI勫=>٥Pd?RZ1f&'[5+ |=!-vVqC10h8~=?ΒQ0ȝ\\,Uvj{nJgrUAIGršwc`o:rK+7w<:'Ǭ8܄Ο yCn\lbz=;M3a?7u1FCo:<Sn WQ=@ps'#W/JVQԡ]|b0@ W3t=iݨRaL4fa]t6=mlKM!}tiOs#{ȫuKtG ƫHAL񊣡F#⛒:S˗[}\/.MvNhr_mوKdGkD|pg +]HJtR]XW:jZjͨ: \ jrGc6V5V@FdL1˫ȑS˜1AAh~!$HiSÚ\,ܥ]?8=<ȭruEjU|LK5|TMSO.꘶ 4=o5eϢVu3[DF;%B Mi ڦ2VܠNje ȩNڂKeu.c4R->Ҍ}$9hεl56x3:>hcu"hM_*Ny({jfWYӴ꾚U3+XU_C||\:f8 hm?1i66~?^x ,+πA4|OZ~j"cߠyc|eh1gpǂڕ\ԑ^~%f\_rs_3*zG ^8)y7H}z0u'}8wN=MzP?^v|]Z :,MIv^hm= u)hb ,>~V͓?>N}|xSBp%4k֚&{Ҫ.{59?gQH#.WT'_,ҫc"N)Jnp5քӓd[TUk|Mxc8d/?7|w9$h %Ң ^SiOUW3_Pk\ڥJ\:s꯷vNj냃 =@2ݗd?Oh/<^kVVuKF$ZL;6A=}9>;!5-4 53N}_s箬W~)t_;,TqCQ͙e/n#e>Qu\:G|2H\q5Y,)_oUvA>d)OVf#77~Z沀샰LY+ϟ?8}{WUgZX7sϙ` D-f6\ӻa}{]ٮ`]=̿NLhZz>N Sr 4ZJyqz^HhuSK95cf%(-zȉC}.yՁCuʊy5;}?U, dwOkI}L7ϟY( I.A=aP0:c]%ǁ~ kJhٝ>ޮQU,\ݳLK#jI/|QM>nQK3&kO ~Zx|wm>J9^J_ lZn:tPr S'u}U?[!{Um h~7<\>Q?JHwa%S6>vޙ┇Bc͆_";jj*?c4:Qg\&;.M:u:*S5>WV; hWl:rKk77F.;v@TTԗ/_`{onQSDמxlMK"|BI>q T﵁?PzfRN1[' ݘsm>owwƤqf K||O@F/G.fp3Zp7jM8ا+4@ D"W-wraKk5XεܡLoNZc ~{:H=7U.V{';lfA? Y~ڀiǏ>}KD ucWĀ~N:@xīD|f~|9C7U\^(WI}|h1zQ^ch4'WUׯ!K:Z$XqoǗrmlV̶6ܿu|8Mmׯ׹w}޹cǐ<_~D&'|1O:<Mi(TQ6ȢcMsd?I֦>8%'|wnPZ- \Jʜ{sTOcsiZt|xf_~*í4pG<5SΊwΗU'8Qp)˜џW}|csox2bKB{§foxwkښ%bġūB~z{KK$_Ǘu˩#WJ@j .eAȕe}K#3'%\!>W1pg9pPFZd}3P)y4ƀˆ_"F#Aw 6A\-Op!TsZqL:H=7]6z]c`َFom3A@Nb1+L ###?jXs΢}7:seq[}nғ950e| S|6G6 T+1r/"?W5k͟͝h#{s+o \Y(N"1F2׫Ix˜Ρ~,k3 QKKע=O),g`qۺ\TXiuƐgrsjr9s#U~11ҦQoh.BWф&k~y6hnhW}#M,@iGDuƈin+M6.꯫'\"eT, Eg9nuT\W/u$h|Om5$hZU}7\S1A}\]s vp9rfL蝊EdL_- !ƀz.hzꟉ{jUQ{NO]4K$*M5vkIKō+ՐF8;xHzꛧ6VM+p4VmOa- -#9^.ܨ\NT9t_;tSqʃ)pUR;Tgn tV7lN(ܟrXpVYc,ɥ$M֛O1Жy`@m l4w{ްnuUG, [/OYz9vO yoppy4ρ?|5~f:f@+_r6ڵ3y/r6X5Us7uTfԤ W` ػ\m͟/,/N|x~T2nDSEO7Kd'4Yӧn\.;Mr}Q(^ށ,:+$kSG _c8\cĞ\9$GUZ-[=*Ak~z_Q}ݠP.nWϟu:]\gu 4j ǹښdfrPZWse p-FWj~&yt =7=;y3Yr6ܚ!Z?u._Z*V+bv">Pz/pg|_ZKrpFqerYr(y{o.wRA\<ܚ}슃]CND1\1.S!Ϙ_[t|øt\\ \vjc׻eťJp5NrV9K$M֛k7wZ'F.:fvreߟG.DM=ߋ/^-0 2C}e¸gk X>W*$c#LD}!=(k3QjuuV @(](N%Z۩8CBy0 AN뾘 <|;@mv\2 ߶x9y.i! }gņ}vuCGxO]ϫW^~F=a }cI^cV~D|_Ye3]鎋q_䕔!ɟB]20'CV|Fk?.Z6y֢S.Jn1˄ ƀa"ZtE3D\=w"h=ELC>gO.UT\2 ##i!\{`ljwu{Ρ 4/Xu4/^|J]Ư97j)0-XTg1('..5iQ=m[*[)M~t'"2R7@w""֢>q'ϧ%w"E!>q{9!lq}d5NkMJ6kIf!nED(.-T0ĭg}S<+J~t}l s7s/X?˴f!A׻>GO`Lx, W_Xr?,12^=uLgr宫% }Ϋ[nq7өnr(ݴxqWnq)yd|B-./,^\f[t\2 q,^[t-+ʋK!nŋ8(ʓKF!nŋ/3^K[%?b lo>q bcp{8=n k& ` Ư9t# ׌Nof(JÍݑ/ZƼcrZ~~iݑ7Z\ϣΙy!#oo쎼2&0%1ی' ZQAAa7OiB黽gu~cVW1 ~ˤmǮ=w>ڵkZkAcAA̖ЀI0oңwTxGM_{'OݺuK4Al N8}^ K~즕.xzٻ7gk^n?ns:Zk]9r̙1  ^z9??{Y5|[σP՛6m3`?\t͛J@cAAׯ_|r``Saa}z:u}C a֬Ya+axIjzFH>>>ҭ$wc@ ޼y"/^(J Foܸ0:$1k*ĸKH^`UaW= YX+Tc@n,XP6K0N#e@~2Ha-l1Ξ= #GaS \<7 E/zQzF1e˖\r)l tҪU wgΜhV\v ~7k~y *bƀiYI?)SfرUaw9 karki2ϝ;zP *dH Լ/_['1k9u|1pǀVk j*U3uTYs"'ȬҞ~:Pu |a'%@UV\keeUhQ?|pkk}y+?'0UKmׯ?qDN@ٳwԩS|bR vʕ+מ={1,Q7)+Y.ЧO++\r&]>h4P@'-[VUw!{ƌ!3T'T ݻC 1c/[`ƀPBo ݛ9sfGG1cư.Q`ƀrǓ \tI<*d˖- }lܺy&I<|p3a^_x: Io =@4`a#nܸ7]gI;h D%ne5`@ ~K4A2G& 4xkd BAc@M2i A!h 1G& %0ɤ50Ls D**1jFA$ё^EcAARh  HweEu2BA Hcxn1`AOj @< J`H4A$!5HǏGA"x+WTPD(rP9tPj-ΝcǎeϞ].5dlll֮] #6LBBB޽{OdiD 7BΛ7,U = S&"_'O,l%_G6fI..b|~&P$1!fd O:mKݻwٓ/x`vi R sX(j p1ҩ"c$uԶSkFRNy'SWouITCXSQH%uvH, r%…a-9ϝ;%K uH)wTYgBcdObQ}=Yf[^ 5Aʕ(V4 K$0,-- PTpܠAZ&ǏҥKC')8#g͚-[ gTxɠv`r X#r"&&c֮]\ H_!$D)#i/QaMHfR'VyXFZ;|wss[d Tիrʁ@y۩-֮|8oPRVZTN]+R8FY'MI.:;:D]d^Zj=x@^Ec`̙2J{uZ#Ecd奒: O@ X~Niڴ߾}B7K.7n܀0~(Hj/QE2HY`AvTNDIJ#>I)/[nxx8lذaL JIbjWHǨ@_= pªȐB1RH2cDOi#Ld` /5mSwgggթS'44tر`(o;Eu!d= 񠕔˩kE HD.:eJvu**:2gt!z+svLϟHG,OX=Lh ذ]䁍Gq;A`B_UZUŋ{.\:K"땁9sr^t$;)Sj~0(_&"TXFZ;|ϔ)la=iٲٳg<01pa_rjs1ң"iɢ(sRtrQkF"hʯKR;:D]hɓ'|E˗, u2I#%.#u֙ .L6 {ʕ,:t xXXDBA!0d3fܲeVc·.^N)poDڶmۊ+2dӧ֭[̙3CI5k%HdtΝS~:̙3&_Ǡ]E Rp`c-6mPgLEvS(#Q/NCکӆZ;|ݻ>|lK05|vP.]1czNkE"DS58ںD8jN维"hʬKR;DWc@$k ?;DC k͛7oܸ!QCϞ=+dĉ6l`IR(ԮFHḳ2CcTR/^áCXΝNdd$ \2:u*<~xZFO>ׯ5eIß"k؜6k֌%"n:Vŋ,QDhhw/_T&뤃cO ] 8"00pΜ9®.!BϞ=[4Fp/\Çp63Da)P$=F^bA6RCݪ' ( TY}7(%|p0e0 tm;.CdNNNj:NE֬#%jHwiEєYDvƀT$q޼ya kQʘ1c|,/^C#TX uH1R22RIMk 2RvmA'uL2s6LGR(h IFcv,Hkaa~7ZAuiȐ!G̈#UZ2R(ƮE?񣟟_ܹ9ڳv@ժUM-) xzzFEE=zHQ&'""ҏdP84A$Փ;xtJ^׉XRv!CL%Y /ѝ]*6LGQd]ouS7Py$Ux#EdMZHR:ФO\*&%L-WVXNeRձDR@$uPjur{aJUc{S˯H$'lI_KҥKWbElٲ%$h۶-|uIlWիW/09@.]ʕ+D(: l 'I3jA@4!p04&)Eh!d,ڴifȖ-t*Uޟ>}:0"mmm/@"s:FԹDakmfb\HLk ,S$ X#(P o޼d?~` K+Du"sI~=t萼j`ola%'r傊`5KC> 4~],X@bzyy {!MUJZiٮ];y зիW:lӦM[Z5ivieBc@ޤ%Qu^zH' )%Zj c@ C r!Z-,, j B])<>A3y6*իW-Z†߭S;$`c@!W@2PT)h Hrue@":FԹDa $Ʌ H$&}h]%K R)2 ]a3Ⱥ2iΝ;שSGkJЌلѕ馏܂?z($N  ciҤ]R ?+2e"![ ieƀB3:cDKID:Iz٦M#Gvԩu%KCؼysNrzc(ߐgD)a'1cF///) 14#XU@C\]] zޞDR;$m iӦ͞=%Q.gʔ).]~Agʿ@`„ 3gag*ȿ @~&r+t7u.QLj:6L B$E"Z(]\ҧOܹs[ZZ^laKp jժE߿|oU/.gϞ@v",?zE*IܫW/;;;eM2{˖-# c'(_؏ NNNm>ر# 6@]䐿.?H3WA[v-/\: )tk,@=ԹD#\N0͟J>0 )0!_N>Mu63f0X4Ӡ!XI Lh H^Ijʀqٶm[,,,r٫W/BA38" RPz-DAR$h wdJhN͊+ԇ=dѸX&V@b8(Zf6X-b9==zL׮]իWWWk DfZn]]k'ksnRb>͔)_WzW+LK ZLETcLW L<<_>L:J*ӧջwB _@KU$jdRNiI=z^4Skfh KDZh^  rBZ&5;E^RɬI]S[D5jժuYI-|I@BKɬ3f$9 j/]EܧO)z37o̙3Ym_HHʅ:FYF A)SEƺԣ$R3-&ueT!1 )ukA!uZ&5;i9-NfHʐ"1@(XhCu(*4 ѨQOCEH^6XzuWX^y84i02!DIKJrj2w*AT*LϋHfJ[DMʠ9;DK$'k",c@vvj|UƷPa'Z$ueNm3;w~[L۩%Mv7|ee?u,佋) c"&@'3'S>;uꤤFHHt8dV RwDjEѤ ʍ!.^ EɽJR+Z&5;"+Cjԕ!+;E2} {pSK`OYO8f(o߾a _ ^b_eR"Q#uҒ1" >#֬Y*WQGzj+7dX:DLBJM :BB~"Aj۩eRS[res4WByKکŲ\K90/B֕a4א EFhI%&Jjia4w|=3`fR:ԕzn@gIH DKArZHuPg7lfϞMl~Iu;HZ&5;E,W ;Z;Y:DYN&rz8iҤ;1wMʟifhCFF c"(]9 * L$!Dh~L#IM`f:ԕznќr tvBH.^  ̙T j\*dj͕!IDNϟ['gϞ/_i;u;;SH4ѫW/fѣRrpppիW!W7g޽$f=LRHHQۅ.ƀtt2&<4SEѤ s3SfEK$Hc01!v%vQ՞4(cR@7"ZA Z!W z-TgW;" 1BTI^ SsAR::fo 4I&_S۶mML{SlHv${nFav 11`aaѠA80&tKйpЫW3FEEqѢE *D^d4LSB ŊSi*،;::p@  ̙34i^̜֬Ywŋ-"3)ϟ?S O۷”"cʀj rLh ={ֱRJM>=_|DKRæL2Ι3gРAzRl ̘1hٳgC$H2n80E@\r ɛ7ի"eOs m+H$-S-^~ {|}}PfM۷nݺ :t@$c l۶dɒ#7o>0d8.WׯǏ/P_l`cV1c888<$бcGڃ'.lݺ`D UL1cƌV_*1@mHZ$]o(0`^bVm-޼ycv 17" d1  4A$ƀBБ" RI@XXX ,,,4 I>%  i:88 0 ::ZFxHǎ1H.ZɎׯ_n^hy䱵m޼9 +6662z rkT"!201 z$_OXpxܹ2“4AI7oސwR ٳ?~q5kLSNf9bĈ {.""H"2NS* &`їC,ɩnIzu9cƌaƍöHёb_|Q-,,EAsΑ+V N@ U$A5fh ԭ[]z5bI`PFBARl4ijԨ!!6ٳ'$HCGH1 `c8E¸899F 8zy U$A5fh ~2K_3Hu;HR"`G 4ouc] #E4 U  ߿ wVVVzN* 34*UtСW¢'/T%h:aiiI.~M@GqZjyzzR|U2IK$A;BcwYTÌvPyQxe)3EavJu<+Jˍ̀H$wxc6TIoCARK:RDGׯ_]4iRVݻC&ztBrӊ۷<@Z;5%K$AR&4_# 1nZ YNI0 0@vvv|J777飃ġ0=`N6M&%vjJHLh !۴  Hƀ__VZ͙3ɕvAI٠1 $((hѢy;v,EARh  H*aÆI-<'_>旌5 F&H.]ܹ#Ν;E76$0ТH@T(QļyZj?@@D1 01 tPخ];N.U4T2HˤfgUr(԰:5ӧsj 'D3'<mvڴi` @ݻ 0Hڵkݺu1bځ H2 @5VHpE栐Oi쬊XEOy3r@O zhWTg!'i`b16mڛ7oZZZ§(SoMA15*UfPȟnTR}OZ&5;"#ESLR9@3`ݻwחj 5kք߾}֭FD?ȳdǏgS"PES(T2HˤfVrxH&:55j԰=1 DEE@[[[*UjŊ,c <ȃ$`74h… +WGDDoήE>4V0+@cǎ%MT1:-ׯ_n^7'O[[͛^`ii g̨=z@9rxxxZ;H1 {-}X75 $h ͛7o˚zsُ?;L{CDN*sĈ`c{ "ENEHR@9gח VP@8Sr$׏?>j#GIE FrTU7D۷7=#y1V*N]jG4޼r Ks0EYΝ;GXZکPE~$aM T :1@޳׾}SN7y٣S8qʽR^(ZƿH$*E H {DjQ=aիEBӜXEI _ϟ?'~S$$0A9-Z5 yBw zh^D2cD ){-d!|}_&˿!U$H*;L$r2]'thTu '|"VQwޅBVVVzN*QL%B"+` +]v#Ae4nX.rhnNk"m۶G5Viϗwf HǴݻ˕+G&㣇T'd4Pu}̘1ڵk*mmmk֬ F 1ǎ+_}v~9k~ ZKׯ_K P޼y~&r;W$5cBc9֎UvXy PQkq'8$֭[']Ì 9{Vg*gx0{A9?Or;W$5cBcرcSLM42D~XNZx% TRɣ.&O,vvvG3_TQx ټyk@wx&}@N͛V2nwtR4 Adi3cǎeZZZF#YXJJNIFzҔcǎ͓'iX6IJCCC:(AT<]vj yWaxc`РAM4yOڶm;m40' 3]6ޭ[#F$ckIN0D,\>Fꠐ5Em;vVt=0-,,I0c mڴ7o޴OkkkQSN()$c@*Zj; G4A!I+WƍԶjWvDHDDxD&%K06y>å!I[ Hrk!2ѣH]R\U Xm.v|f@ϟ?S O۷”"c#2 s1 ADZhԶxTb Pr„ Ej۩˴oSN3^~ ٽ{|}}PfM۷nݺQ#h S&Bie< *1tuP(Oweڎƀ<٥&Aemm]T+Vjժڶh͛7k ɘBAA r@ATN4k! ('E'֒B _xAŋgΜ9]t+`ƷU荧չsR`" UNZh H->|GI$޿'>?,YJ|ědbTXR%kk%K>|$U$J L<"G4Y#UtDϟ?~RQʩB>[. Ǹq`>}Uxsc;v$Ǜ7odXXXll,W&FE?~ȕ+צM͛팙{QDc943i7|qweEo h*Zh"!: N8pqqLދذaCک- O  '_D՚͛7#^| Lנ +4G ZǏaaP Wb lܸH"_.!ur(uΨB 1|Kr$| ٳgϟ')Y.KIʩV*h۷oaP}]X.66>UFRRZCH1ʗ/x2g˖M#2@ (P@pHu@uΨ֚&p }3d ϒ NyX"a[ 1.]VėC"~- T!$> K.Æ vjۉH/_Ti2#!TQYcY':Ez8MoҬHH^I=ߩ1ZZZ0c 721@CiP 5f@xL'ک- /H+Ejdɒ凅(((Hp>,84XJ. [|2oēd1 Y`lXgFdٲeo]Qbлwoy-DG˰ӧ %!P;$%w=@c ٱ|r0,--իG݃ " *?~WD':ƦiӦ.bBr1  4̟;W'6n(r„ Fqfttj;$U}ؤ0cMZlJUdJǏݺu# 'M>z2eڵk%nJM0B;YkPcǎy7N u-߿L2Тڵk' /S*' >y<H„-*ΤP]Q#0DN`1ɥu X=DuBEu\re1@Ms1HڵKZ)+ɓaٰaCr0yթu2XNav)D׷B ”T*Y0s(,G5W* v2?Z%GgIR`-ni6T_3*w J01 u\ߙ 6jb)X;k,ZNjgϞM#;88tqG@WxVTlE:+2Rhș3gq5PMkdVv430P$j4@=]h^ Y ޽ OuԉԩL0o.n{`ԩ{6L.V^S|' LE %I`M>]묣"qP=QiWU`Fa Paqf<{IM @~ֻe|bY`vN.XjeS\ 6ŋ 7fΜI,P0i`M,)#tQ]ɆD0Tf %TR7o X7lؐ鯰LتnZ1}tr2r47Zj%򸭰L=z4C"KJgI@Xvؓ!gkdC07c@3)Tl[:222Nv,0azb9bv;Y~tr.j*ضK^'5 rʔ)n5j$w^TgmN>|2e 2BRI]83P$j) 6JkE+U;88Ty^JQnxR9Uי3f$^eJxH#GvEDD*R{:]EE(=X GJz@bɔ9xȂUزɧ$Of4[̡޹s{g,ìCy(v2<%7fPoO>2suؠ1  i <\+DAJ48kڴ0&,,B |JsCFB>H]igggee%|͎~YAw.W\ 㣇T- 0`D;vZX"""~7ҮE2PՂx"Sʈѣ]3XoF\-TP̙Ӭ.\(S XڵRiJ*IAR&4ӤIީS'jq]Q7oLoTn]XǍVdI^ q(7@Hɽ{D{ŋzj\\ܳg_J ^bELLL޽ObԔTBLh 4k,mڴ?~TOܹN4}z:w1co޼g߂~Ś5kf2jg /{+W&?~Jфj\\\T5lP*=N%(o^腍e fΝ;Sk*<ARQ;~ʫU;~[ |ʕT؜9s`ܸqUAJ6"K{ҥC#ui'R*HjJ%&7$`KA Xׯ/hѢ "JL۰:,XP?R/d]` $^x: o>|4п(;KxjwzlikNY)StkॢvD,\>R!+D0jE` @Œ@f1p]8(}h~VOuiG./_> )CjJ ׯF &' } ܮ d̘Q`#DH71׫WOf;^Tf ɓ'r„ *1РAf݆c W%S[D.&00TpƍT!)/O???VTi^0jEG)S &v]2Bd !壺Sie˂4~xPRʳgϟ? `Bcؼvr+KsIFj$m *o޼}tN k֬ٻwoŅjg /o5,~JsQF*1@֑+}e O" "5=CmᏩ"ndf@%1ߓ` RvB"vCaJ>(ϝ;'t HJńcȿ La9s ԫW/e "iooz 6wå:ÃK^J6eٲe ^%ud!QAuBiPP f`۶m|!>NmUx*|&L;j P+7n4e\DYɑ>Mw0PQ&O̪'22r  Zl uUXM"""8Du] ,? I"9uhO!'8!/(aE"D)hd aÆ(9mItP{IM%P(:?u^:p|"dڮLN} 쵐Z;5P׮ġ]gU<͔>3`%Aj9r$ϟ?jС|'SOppplل1"cZ;dXp!o'pEPt )VFyXkTNjK,Tc@&% K.Æ vjۉH/_Ti2#!TQYcY':E\x(>iH$] PˤTH^ &FRuxL WV`pK, [~XdMc 3!|.]02}e޼y޽#OKzeŋwT*TWlY_fML:tST ?*e\^*I Y[[cƌ` ϒ<::e' L=d>3 M"T,/ڢPi:u*Խ{wIš!^: yDOlUT'Ө>րY^$V,PbT!Tvfĉx{zzʔ)SR._L [Zpqll?O>Yd*}`X_P/䂼0k׮[,ժU-Z,Bè܍ZpYX)a-ʟ?Z0˘1ׯ-,)M1HGSyHR^.#Vo߾]B%M4I a8MGHJ^:p2OuX"INV*<IB?fD8%?x%J*3`Z zO/$h 3Bc#l27Į(1ݻ7"ye`Մb^d1 )B ϟ_UbщCiڴ)Kh  H*bU "++7ʧ0aQܨIU(y$6)`F[ᣳ_;cnlll&M>z2eڵk%nJM0B;YkPcǎy7N u-߿L2Тڵk' /S*' >x]+ ˌɚ5+ (0m4򨒁eRٳg?~7ne]׼ynH=KҼrs$yaBcqrgR.بz"'S׺RŠY zȢ:b2N˦ܹl$w%nɰlذ!y9:Y0Ev[BaJBCĹsNpI#r`K+S^NoRDe ;NHģճ$)E4O/BZC%:RL 5RMɔ,y5ky-'5g@l&T8Jk+i|X9s&wTlc@a'CC5v3f ~XHgեNlHC%k֬P2JZ(uzyf`+uÆ ˄ vӧO'W ,*JsSUV (ѣG?P+R{ e=yPzƱ@=s3;BuF{/))###d &,*{/jaH埋M'bVm H^tiuRc"LQFqEqϗ)S"߿/#$ՋԥAC=Ev`d.ZXbP O 셡5j醗)S1cF2]-_歄 T9rh׮]DD"KJgIa十[4_3\!~ $ʝL,^XEa}-|JDiF:;wёw29:Ilb'SS"zcl&,XS,3 0Y  IKyJAIHc㸦M c*T`aa?ɧD̜:dvvvVVV臮E11{reȐ!o޼>>>zOU @رc,X5+(DoxsF%TNӣS1gTo߾-ZP̙3ӧYy/\PL"ڵkbҔT ,_$Lh IݽSN⺢P54o<1ފi^D }b*1Bc ɹwH}/^xW^{Kp+VݻU c ^X@T f͚MǏU>ʝ;Éo޼666[/^Xf,@0V,Yj?t2dE[&(ʻ% @5bYmoԨQl٦N?:u*o;VjY|"{|!:$mXh(ԥ!#ïAAANNN*CjJ% 11OE@dsСpq4ijԨA^5&\'HPB H>+3 Or$˫jժ5Oxr\r7CCC~[ |C ƍ ԨL&#D˗ЖK:::ӧyԥH۫^ )U4$;؍`]I$5&4`_HE*Th 0wnT`A{4u[5xj0l߾}Cؽ ˈg!5va3Tc@׮ 3\_,S ppBJyEWTHCNޅ LFwB[@҇>iժU.˗ׯy!5%C !ASanW2f(xի'J}v؝Io4PSg!~ȑ2e@$ UI5t:07nL$U/^>~T> |C)o{rGd ^aPGuiXe˖i'&4VgϞ͟?b5Ah(3y=>W֦/M4RMgȕy ԰f͚{/^\Xv,D:68j$(F4Nxyt:0PTdccC]j =zTyۅԊm13*1@|c8ϕgV T /ԔZ}P;wN@A cǎL27::gΜAՋ$fi4X$W^aV8)=<|ܹSe81k+0 ry䱵m޼˔)j׮Ϳ0**G#GԔܻ֮tr(S bVBC[֭[bܸqnnn%KqPk8:z{-Dc@?hp0{Ǐ昌CYرǏӦM#.!#F4hݻw`)RDJ5!]Qʩ<;A Zh3g!bB|(o;Ux*]B9Btqq1A7H1BPoUwoUT Ӄ΅(ϟ,r +;-.uĐNQǐ8O@/JˤԻvwEivjhsd Beڎ f&H%^ Hо}SNvT9UR,c@교'M]) Tݻwk T젷zjgggVv0a{ J FOY@$P0pđ4LJkgyWfvEd Beڎ fz-4BvWŠA^8o`Yr*7^ Yƀk!|a_~(5@0(ի1y`P Ν۷XbE LDLׯRSW;ջ"jrQ(^#YanWR'OB &v:",c@>y7pLnH150YL tr|}}!p# ʴVZ2(Q7۷W%###I~G&޵hGEZ*LIBx-[;Ns@Yrފe GZHu(5= ;2@ڢ'0BO< qҥ 2h-!ytv:tP\-2DL|"MIa-Ԕ.HEsF.rj-S ێ z-4BKKK0f̘A0w\N%hI&A2L!|-BT,cL;m۶1 /b$AA$L~ڣG1f$ { nժoв ??~L>z$G۷<@Z;5S+JSNTx,ʅgAZ(Ld^ a=K^)<:*&K,7o$)իa-TP̙_v55e*yꜧHpPˤFR: 6Syہ%K8::B˗'ie\BC0_:0l&]G\6m/ecƌX[7oțFh&(47#ߟ3gNɻTIC'/Hq)mϛ7ب5%NNN/^\xWB Ϟ={LI#3Už2EʇC?w|3)6So޼ iL q ^ Mⵐ4Y;kƍu7k,>N] _"M\$jR{CߑMŊ۷o2ɨPWʕ+A}S-۰e˖mر|]_|=zt|@o2:R!:7&MgԔ:D;+W*oȅ mV@R4ʽ@R#e<6*b1TWH)<6*II>,СC*THLfBmNá1 l&5f%K`M0&H%^ ׺u>H@F$ )S&XH$"4Wu$[ y5rX~TY ׿X~H1…qOe1 '1a:P;e2wڕkРA_~'ЛCPLnݺ34/w}ȑ|]:Dm+CV4On]CJCHj$c"Hcl~XD/ب0J84au/_.][>}|u2™*SaS;"Cc@LiJTvʄSXKPz-4B&ZZ&|%o:=;` T|z]aT.5L$8*U*44T"46zzzGZ'Nر_,0i$>^yrd͚Uy DxBeIꂩb( {I w)}4r)P]R#EݸqC6Q: @R#YEJ 6vc ^r@ 0 AVZ:HLfBmNA-S"Q3)uj¶ì2az V%]H%^ J*QI5oE I8AjJ"QS"ʉVD ǗUžvE: WD͔TLm^`SkTya(WwG0(#rc:̀Bwov`A?7re6_ O xdOWZBK[H)A˾ӂY0DA@2"Ȣn(0U&*(Ȩ0?q@Q,",(B?o4$B[<ɛ$77˽p +e$}iAǚP~fՐ[ ՐMd5k1OLxc͖ iA[5]egg˃o_ ᑿL1}iP_ɵTVM5ӫ!M7[o4 hM'w-X?0}c͖Vw~W>feߪi4yMw0ӊlnyZ2M[,ӭ ܠAjp{Ϭ*୅-[ M1Mɴ4ΤJ*s{n:RMz#6S2]!.}aۂ7 (oРA /_?i1xg,ê=tPrr2 c>Ok„ у/^l&p|`1S ,D_|EM_eh<[{رCӫ!6o4 h ɭdW);9XfKͪrGJK_6U*hܓtk͛V2M[,ӭnNO?Ԫ" 7>=//oСvkZ8={$$$dffszf͚!!!qíi!(@ SZbonrzekp(E1NlY(qJ6+ì^Ā+Y_2YF1`0Yvp0fQZb+Ü^kGYMRb@ R Ν+ٖ TpC"ڵc~~~A;vlgϞG~^zEFF:6(E1}v//ɓ'u]3f =z8](#ׯ?J{ӖeG \r%::zժU|WvR\7nܸM6z^t믿1Rݺuモ M8FQQQcǎtˇ;? &&F1\˾~̘1 fV-㏇z(666$$϶d?{CU8X-*y#UU.CҥKPP̙3nT1b˗ZOt»:u*nܸ:*s„ *?01O:w>eʔ5kv!??_Unxs {7Ϝ94 cJQ TZ[nqʇgAqXjݺ5w""8"ϩO9{/8spPofrIKKZh񐊯o۶mnr) /433300nѣGlRooȐ!CX䰿fS2]!رces!u.Bm&o5Fʕ8ŽL`Vz ˀÇ۷OZ2Yr| š:uOBBB:udRnݺ2·ڵk링:ecMUZ⸇'  ,/=*yZD{VZça WGX6̪L[2xիgggw=11ŴVer*[ɻwH"ަ΂ Յ2w^_RR;_p!sv&Mԯ_?Ǚ@ CY2KR٘Ɋ^<:nݺ5jM7]n&M(EJc zW :8NMS2miJ\\cvVe]g1He䩧_K+999F>vy bPJQ M7ħ~o8 Z2^^^.8Wbcc TWh|n.(~*&&xlq[*fWL/L7#IFꫯV$o蘖(>>v I4Ob`۶mrT >3pB \p J*i!š_< gϞ}}s=ա%KXBsmL[ʧ3͚5-Lќ9a8-*y#X6S}wnSrgZOtYx1OgE=mРArT}}}RΟ?oU|c ;fr+y<v.~;ws󟩩X~}tt+Wd<==K>s8V>5jԈ{>.e=PZ'}>liu}Wj׮GN*|, 􂶱'!!!|- HLL ԩ|nkƔLӧOs&UT?޽[_qhh#dLW;3ʗT2M6O3;w䴥ζ*%㣢x0a $og)οO>Lx[F_X._YG2&7?0~GRݚkJ1`ȦMgϞ-TX]b &={$$$dffg6)/be P)1pe,P*8@b@ S*b`ىe/ȏ ʸq.vXs|ոĉ/F瓢q$;\q=zԩS?2'ɩ~w+|OPv f\_b`ّ! ;{}fٓ!/9sªr?S8`7RA7_b`e1 G+~F>ķ1hq?y,XbX>9ydvIE`)REw}kY d\LITڽ9=MÉJy{sLǎ;Qn=ŝ)V K׮_BԺEwN5SS缽O +7 ۵kD;s6=$kUe ٷ0>сnLRv,o֯]g1Q!wq>c;)f화w;Dx&ŌJov@H$nTzGŌFU1]QZ+j0kdq´[t<|,rz^J1L>A@]vo&%h&]٢[+TT;h5u}5+O#U*iҎ(gžbk# 8ȑ[s`#gru3VmڴióW^B6l G jI<۫}؜^xQkС>G8.%-/JNz+6[.X).͛'|2((HWǏ类wիWHHHhhhJJ֭[94idժUqqq=z$2ZF;qjQ~~I ^^G;k41@BөfR4?њ0Ph߫9}[NR(2Q&Zh/kG+2K&mj߷{VѨ4TzSz˪[6"/"o갌_jT%րj-Du`OkA!¯Փ&/ MaKf,msl:,8QlCs[s`L8mO]1X]Ћϲyz{ea>ǃUĞeހ}pru3Vt6ZS\ _џ1cFll[80++vI{{{׬Ys޽r*p//O wWD'xy[T* wsGSFTU=y\t_j*&yQh&=(dtt>8ύy~-&QiEMZq實 ?)dlj荝Vb`BZYJ.Z< Jt-N7D&# mcU v2fVmx?W5.w5L=X+-A+1mzx?4=z\[ ]/W7cElӲeK?Ui߾}{{19͛Eժ}g<صkW\d>>~>Ͼ QV}@;]X.F]^%>k+_ťV>dYb`iQ1xN-P ,rlZëuѾY&sfU+Vqm"5َ#Dwi&!n"&Ir;*LwAw/̶SeGdpIzcn;V!:l3.{ܘcAep족<~Ɩ 1]nƊڦE qQnݺ- a1qٕ[ɗb`ʔ)rE7+ʲΟ} _mh_8b,Z7Z8F"kcńI5֧Oo>h1e 5YDB1|Qp"&m\MjQd ~&sfUK1` FpQ4yy?~^/AZ"ꅑkDp&W*q-P&+!#sɭ9YB?`EW98qc7}y`wqG}5botdΑ-ru3V4o.͜9).5k8ډn'O111X~T_uFy,yq;Tn'iÑ+Rٟݵ_Ȩ+6*$ m'zt Z-2$u]|i'iwo}}XǶiL1cS<<\իW;)))gfff`ʕm&#۷o7]}dy7^&Ҍ%Ck۪i^5^ߒS:W/isQ?$i_o"マ?M2@P_wUkTR{O~ѝGq0(ܯVr ߮/t+eMş$L6).+W:w}7-[5jGnVݛB*Usp_x0Cy$ 5zL1JS?H}Z0uk(>ME|`qV`'?/)ԧ1E,-Zda1جU͒Ź -+43_:ԥ!Ss&3U;qmJV lQ-[r1/>F>)=Z)Ā>6ggQpC.>¢ۇB#02fm(=u[rc۾Uc*{g5^:U!W{pz09-B㒂NmNLɈR+,?o1˾`aѠz| /4Fԁql`\݌o&Mz).^zX??~̏@rjcm>O@XNmرc{LSB4U#Kלg@^#1/7uB26rݫ4+?cE~-@STA,g֯9w8||:C+;|d~s|J90-!@19{mFJ3EJrvdU-t=U"EwY%0m 18l"40χPF: բ^"_[ p5|Bn=6#3 81ahOrA# mN]}R 欤 DAP%1~Tm;́z($O͓L<(bpDYC%- zӯ+Ġ& U j-b`.8T~F`7zoۙyP2ܵssӋK/} ŀRs{z^s̓!Gg- ~V ~;O b`(jKM &n 18D oL, ("~>tib9pP[jb`oW=vyP2O6xvuEW Zgb DŎӄgc/$i 18@؁)5]@ӵ, &Q%B1O* ֐I& 18> stream x1 Om   endstream endobj 144 0 obj 381 endobj 15 0 obj < ] /SMask 146 0 R >> stream xׁ]WtDABb1KAp3MUx~^}_)6OO܇}Oԗ }ÕPb.?PB.?P"!.?P)N?^Pd%N?PD-N?P$N?R0?NP`?NR@4?.P ?.R2ަ?nPMޢ?nR 6^?PEc^?Qc?RIc(?S c8?&PAc ?&Qc?&Rc*?&S c:>?Pc >?Qc~?Rc)~?Sc9?6Poc ?6Qc#ꏝ?j^جuc?BhZe#@?BiVU#Fꏀ?BjRE#?B+^t#?R(ZHd#D?R)VHT#Bꏄ?R*RHD#?RK^H.u#?JHZ("eB?JIV(&UDꏂ?JJR(*E?J ^(.t?ZZh"dF?Z Vh&T@ꏆ?Z Rh*Dƶ?Z\hnk?k[_?mC??`qO?bao?x`Q?xbA?xar?xcb?8`RC?8hBÆ?8apS?8i`ӆ?`PK?hD?v;)vR @Ia'N ;)vR @Ia'N ;)vR @Ia'N ;)vR @Ia'N ;)vR @Ia'N ;)vR @Ia'N ;)vR @Ia'N ;)vR @Ia'N ;)v1)՟q)ٟᜱ)ݟ)џ9)՟y)ޙٟᵹ)^ݟ)Yџ5)Y՟u)Zٟᳵ)>Zݟ?S kG OӮ;S Ot?HgS }EOt?SHGqS DOt?KH'S }DOt?CHqS EOT?R[HeS ueOT?RSHEyS dOT?RKH%S udOT?RCHyS eOd?[HfS yUOdU?SHFuS TOdS?KH&S yTOdQ?CHuS UODW?[HdS quODգ?SHD}S tODӫ?KH$S qtODѳ?CH}S uOֻ?WNS '@v߿zYM)YI_)uYE(5YA(M(I(yEG(9wAG)wMg(wIg)qwEW(1wAW)wKw({wCw)wJ#(k7B(79K#)s79C)79J3(c79B(7yG3)7yE)7yF+(yD(J+)H)o=/@=OEo'؝R`oMo?ؕbP`OB/H؍bQ`/F/؅bR`J/.֧XbS`mN/>֥ XrP`MB/֣LXrQ`-F/֡XrR` J//槿rS`nN/?楿 jP`NB棿JjQ`.F桿jR`J.ƧjS`lN>ƥzP`LBƣNzQ`,FơzR` J/zS^N;?I{(p/?G \K|W \G|U# \C<3 O<+ K; GY CQ O KY GQ C\U O\ Gܣ;] Nܧ F+( > stream xwt@B**(EzQEQ TWC(ґ[:;ےd;|?s ι< y./xqՉ+6 4"2248髋77o2l`mx^tLhċkw9yP۶e+TҵG&*&$YçW[߯[V`q̞< 2?A/:&,En_0{M/))yFi>MȐZ= W,W$WT^j26vtu oաb"yLJ5y * &z1A|ϟY` ^͛)/W}3il31!1ϟ9wr݆_~erLQ3B"m;GǦ*ʕ&C'ubDńż }-շysMmy8YtLdL@Ç}ϛݳ'++6GMn,@opP?ߓG9燡Ztg Wߛ_hRkܢe#CXy/p]k6凎_T}p^oRow8nK +>0kоT_ w6r7> }Eˢ {E ١Uι @/ gY|O_U9=2zx bIX1wE9 9">p~N:5e=T /:&*,ɋ+]6g|șMJ^ZWIQ,ÕB^ܼ FR;%rdZs, 4#\l[L xzϿK׎ճE%3Hӱ"* /A_9 srr,c<%7q"rznǜs4)?G\CnpқDoãMS~ yxt[ep/(4Dg)R~+XT,(g2"MjU+ҵ8ǁ\hӦGK,Fmo[[tB,}sѽKKߜuhtl3P雞!Ю3SZfGJΝwdhrB.nIw@| sfht"Z wlKK*wcA Iq Qu1J79ҴN XV6sjiq N~-5*7zBlwR=~mvS![_+`}i_V[vw2u&UWDSv+,:4z >;%0w* \[%kaZON-%:7veHx 6ĊYnTcT@ ō^C@.\ίKg;(<7 $`gh|`:+~#4'#:@ɕq*,O`?pYgu-*:Bɓy*뺾kߗ|H'];YrI/\* \sD(ONȍ=D')~$ɵNδ4dѬkbT@h).<FIJr[Y{s֔$e.he,4v~{@QFtȳV|gAJ* \sdm'pmvٯW{g-lS3׽"e,CEݘ^Ytγ&* \/E(R W22%g | .,|QW`*EB ɢN ,.:Dz% .AiC 57ad-I9-%O7B.\UsPx:"%Ih}=OJTnSᢢM-:A]$o.z 7W{T@-!:@] ukJ%ʗ ~^+]G{fJ6ISᒶ(:>]$_s͵~J -؁wâ$\"NF+7 $ލ_*{ǝLp=uwM0zpEs󉎎}'z|6l\].~@b=XRەBIחՄ?rv"mKOEL N}_tp%g׫&85sEx>DN Q^-:7v.f{lWࢮ}\~@bOQK6k \DƎM}&7߆-Whco]yEƞOc' \H3cW>J]Gtf4p}VљSiA:B-:2Uhp?v&yY]ޝ $EXˈ?Y߹"jG.A@"3EUF7s#X[l|Cvс6ЂE :0Ytg>Hf&E}܌ t{|Iγpߤbw)5\>Im3%lP YHt\+HoAĉ)D>8B+vHEg1 {GtR_-uUEg!R|V4hޣnwA~B|{N.uwû*M;P:oEQ2|@օvy5F-(:({Aqt^e* -|{EQ2:D-u9P-/RmOdt M\Wm;P7/]G~@O):&ODqv.]X5 ww!},o~@|6UJ#:%f-H-moǓx F7 2@cM^ M Q'nO>z>([k_1`]]y]REbc5؁^g}̭iPs `!!<)=^_~ǀU!0i U$O+VY{м?d'0˯| ~CK|jNl^>y &aYa\xGd(C.Ch oL^ͤBlMƟ$yO ngqӍ7Ɨ?WlZ7zUY/i俗vRW $(ވv̎=x5\iy|(ϓ~ {RyH9vN_LK_+`Wkjl#h2T?&[$P*> z9L^~aYSNp+lwSzm-{_A ;:qQ2l+<5 ̴o@iJeC*U*?lƆ6AJL5V'{A'ozf]A&E*W ^mIlBI/G32M˙&\XQSQ4܆88QҪB_+,%Elrq㧶U+CKoYmCvmc"vV$IK5s{aNvz_^Phޚ TbH큑A~=l>Ʒ34MdV!RN8_O[D^yO 8ZoK',>o`OHⴴР%5rSa2'tQI'͊ۥB̬Oӈehˡi5U9>d LW0ZucMMv|fUe sæE)x0ft~`K}LUJ.lu;->|GDޔuړs 9ю5SpϮokOnH]41 y}fDo}.D,Ȏ "o M㑽 W:]Aԣ;_S5߈]DسizjhM4m[NYoD\$G+:IԚ Wdv-~B@ 1l19ڟsܿ$b'|{]G1l^*=@rkZt=A= Y&~#ZYO|L(b.)'QQN,,z"K`Dqb، m]pRy|m84j;Akq@0 m Mq"9zԽ3W@.4fmK_kc 5R@c6ձrHſ_ ̒ã:ѯb?͙߹p/$HrGKN*D_ Lg;hޡB.B4+pCmg!RfMx*+06~@Oy"n"'9|0nC\^EG /(^kg??;^~@>MS%I/jgdj _FYL]$%ϫk|DaLQuBE&,YF>=~@,.I]/>և[.h]i/,;d+?Ӏi=|@u#KǓG}AKsF4\6P ;EWEbbc ULSuz zp'f+h?AbO]baڊ3CMLW~*oEᗾs%S_N11j_%~Gro-Ѐ ȟGGh@"*`Ghr[A3TZ&zB Wur`O]#09ع<,?v3tj?m0N͟G7DЌP=DЌ}ν޻ffh{NS"Eb*7똀XԵE2k;3f+Sm@"DАpN_fg ĉWӉZȉ[rʕ~'nEZi%z8f* i,2r}ߤwVRr:PxmyZg0KG hK^N8:PE}3EEЖ;pRZ)z\Y0wى Y0WG h͍Κ/zDH6 (<Hhу4&:xR^/W] K2eDКo9!}| Pz4N3eEО>]<Ӗ̍r",}TWǤ{xyy~U@)pyTJ_\ =T@VTZ\H ="=Ry/:DP :loTP~RIJ|~ ;U@},_*ԩr}hmq"WYd:uAEР}}+S yK{ԥ~"zU?:M4=P@BF$PUԆFR [Jf=LP$#IYgVbӗ6M7۱ P0Drҧ=&^L؀EI:{zҗX/z&EnHfP+l3K.]5 ܘ*{OO3)}ҽQo>L>q==Y$ӥ?5''Z4Ŏ33t(UNT{^,{ϴƙCdQm[a,ҧ{&^3T 3d( u} Byϋ/^wYTE?Ƕ8mʲɪ1VqPllxga *'ݕ3/q<}R25ǍLeeL=/3/ieӞ~ ;5$U߳z1aOeiY2f*a+ԉcЦXt?'zVl2 *pfy˒j^{Ol8ZiXSyI-?=ux#Sٟ#Ue{z*OnQ+H+] kjiSz*T2Y c*o8{v0n83y1VLv#]&Tɟ~ÙjiO>yI/ۗYZW^y){OK{O̙3hpJ ZY%g ۭ=[/s~BQ[3/Ϣ̬fEЮ3}Z%SgQ'z]bY* gVz7V+zvE=_}ÙjiqAuŘ,!e~c pfczi_ֺk!a+ʫ|63^֬6 e}! YI9,z4T̋y2Z=/#E|Y4FyO㢟!}oXμ'/[Ύ6 +]3MXtW=PK_\KgguQ~R~yy#ceϞw3btE{ʫ_&Ӑz=>@BWVmyQtWfBWˬ{')4*HM (g+X,ӧȟ!}9rSh3SOv/^ٙ,/V?̋)9s欱vk@洖K3Ei_j˩@^M-Vy`Y[ guc9r5FxZP۲46R;`1M9m^4μdT.O瓽܉xjk=U{ؙSr w~g>ei~g\s֗g<.'?eSyQ?`{f/6 BtVioSSӬ)nlFka3e)~yrSpуxLzOaU?G)|pHȃޑ8SƉz~y⪟|% W4٪a3jX+ݗ߀@B̚E̡=sZO}˗/ _ $ gVdS6R=/SD >UzOن3=/jO_|H*׵pfYg_1c3O`)T@ A巡̡q&~q3[ P[R=XUI5_~8⧾L{7~z V6W"5O̯~%kM ?F [T{Oâ,}*Te d"YWY޲$[wP,+zOC|aS%lO{ҧSsq.j|y,zϷ! l+\A_(;Xܲ$_\O…ko=.5\`JpV|Ŕ…}  k&yo8+`{ԡ6y<`Ng4~gb =.%/f"3<}!E֥6 ռCgܢ_ASEnO{{Z.YTzŊhM-~_?ei9>cө3a!`q|=U_\+Vu>lqUngy)^xT@&Q2?{O+3/I>r<U 1gB(QάGm5[EB Y= +Qc^Q."lO"';'_\Jx,6ԵY?kG S~Ij =(U},Yy667[,7){OWRQ̫3Ӑ?Yi_=&eIw g_qeST#.%K_eYļ,H< +zH^^|EQ~TRJ.UvY/+K\yt+]gD pg>U?>]{] =$uYQ> g꽧{[ Nт6{IS奄Z{H_\$ez\;ܬ̋lӲWJV}א2v݋qeU)}=/Ӑw H+vc{8vydTg^Jʫ_\+SLMlN1kf^3Oe~"|!~ϐ?KDp)w.>C+[l&Dp%[kp{='p.%%-6%Y$˕3.忡U-7Y64NȪ_yI,Aw=/-aT$j,z)+6'z86flN`կlۯU^J=,(k\S=n9iY{O`.&twb[O{^,zϲWDp1W5lyH_i޳4{*ՙ)z4U˻޳7O?I?=lT~X*W19{рD>ݫ-Kq佧jO~﯈ jBgU{vo8ypx qOtV=~ɊJi|uY q0ޙVzO}$UJ:AD X=g%c*ϼU| H;C+Y=+O{aiODpA/j~DB3/}Xn3 $Zжv5UzOC @XY$OV{OCjP.(rW{ՃXy1O_ B@T~W_G"߱5T[+{O}өY狹H-6g~UzOS$ ~g!H)6)髦=MOR]bHY̫YiL_Z>|=\@oovkӢ4O_ݶ Q4lYTzOKM}j}G]s1/VS4TzOC k0D8t|@>CjG?jM\Rt6ӞgofկIݠ@R[>ŞSIԮìCIrklݪ /~dկNSzYC K>u_Z$ 2ꪟrE6iu[P0;=/-_?yK_zuOe%HSzꪽgmW^zM{=EE\R=c=Ϙ>]5x%X0^;T{OCi~_~&Xꏵ?TyT~z% , T%{~T[9b~R4N $QM{O:UzO)}R4{V uT{Z~5hؠwR:KyȼYK_CIMIjeK=/ gU?F<=e@}ϴ.~ͫ_5h@]I-g]TtkԨqoO|wHyA>רq{3@REݝLXr=ͪIoUz*O{U?)MyGvzQ?c'Iw9 $YĦֱSvH_S_|=HKc~ťl!6}dcI.[Y/m{*O@2QⰃK#̋}"ʂWil,}4ΰHkl Ә?.DpeiSr/cci?}Epi:WvWf_@77T]3~5i1\ڳ5NDi̟A=v΍j, ͼ\VVd5H~z&N Yjfj=姍=7E>!xM鋷4P|Hyjih= 铴ZX.nO{gJ_lZ~5:Gd Lqz˜>CZ9dk>bj=Mu՜ _(- >XZj٪ >$4Q6=կe+I E?ÿ2~Ӑ깓@^h/pfYCދ~pDN5M{rE{ʟWA{86ʲY=} fk{~i{~e׽҃_)zO~36_wI E_{OT֧OM߽pѷ&[V?cӧo:wKsn!Łժ2}_ҧ `)W؎C؅?)f^Yq:q(W~c{WV?N=\؀xyiYcNoj/.}u܏>#۩V~שs]zL,7vydկc\ܥp/l{W?Eug} BxziVb':ƝT.zկK׮]{Eɟ-'4~nr0kͼ/μĦO_n#O~hm:{ERb׭[Ѐxjկ׭{}ǎl^̴4{aD?2F.Ws\SO_n~dmD=_.ӧw|( oy1ٳ= :ɫ_̋ oY.'= m~dܚ*UQҧ3xvvqn|l)O"}۫WqgE?1F"ѥ4y{j_я $EK\ջwA\n~Ǣn{׻(v`f~0= ݧOt̋1}?K sUzOCW?I>÷Āz{Z2}R$^[ xJY)O~~`<7;Ū!}kЯo~C"p݈>ʙc'oOg"{=[Ӑ>CϐsKn/g>ҧ~u3]{ϐ 3v(媟1}7`r( KZμ7p~\)?t *,8e'aq2;~ϼ&^,7A~=J&>} 4B;{3wh\9P^ӧo#yu~7jE~v{L7~Ss9 `wW}V 2U?]~a + 4O!C7%u[^Ϙ?W `avN4Ϙ?ɴ#E?+~[3Ji~ _vvȟ#C:t~T =1m٪_\3O2lD?*n?D4Ϙ?ɌX3/8߭7\;p3{ӧ?=˯@LT='׏_?9^4ϐG,%0F'oĈm ec1zqvwt(CF0oĈznj9"hB#Gn41/?<ߨq>qyFO?M\t_c;E6b{IF9x1NO7jԪ{4CD2"}M8wrt?.~:8ِI2k O;]'I/P潧ԩSgm`&p4Sf~M6wܝ>I6m .YMdZJ4O2ku?)ͪt3| z˜Oߌs֞|"茔@E$3}#@OJӧ_gߣ3[ʪ>}3g͚,S'%pY7{5O6Yo  8>]]ـH #6͞3gYѿ/U9v^Հ}_T>C$_ꀟ^A//7/Cx㩧 x=DE]]>}cKܒ8տ7U?S} 8ɵ 4V?ɂ?,X} \ߺz-[{.HC{.2U .Xp Nr%q[pwD?e>-ZhNNwzrcouXɥ}+obɊ~& O%Wn?z<4/nXȘ%>H 4AϬOtҥkL#Tl38Mx Oʟd$p蘛Z~-_+Ntwƕ-l13= ] /SMask 149 0 R >> stream xA @6Qѐ;}tJ3s1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j1j:yǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨyǨ][ endstream endobj 148 0 obj 2084 endobj 149 0 obj <> stream xg\SI.M ػ]{U{W,kذ!b{"^Mntrsye33!B!B!B!B!B!B!B!B!B[ 3($C ܟy-C mj}@r01c bq=-kխoKĐeUX O1jbj-bDޫJ>Ł,H ,>П(@ 61uӻIПǪ6Kߎjitz qquEc)h @8{ZfH`ȯ1lG,GBy =cU,A$DY& H\'-c#?"G~5?_dH\#cՆ~ $&#b,Z碠?"ŗMM1П "j_?#b)?ͩPTXZ 7iI r(bQ帏^\j ʇ|HGmjV\X,[ɼtϘHUD뷱ؙGt菈d\ȱj%dL 菈d[%$GmPB+b/?kl) _]rx^ԗ J͘Pâ gTjX!O|*(R/2dɪ4UDzQbt* پLS'gE2:Lc4*eʘ1: _eόX@аk{(#YÍT[c Iv,h]rpD^ c]KT}|ۭX$@j$Kr?,1(5Bj$C׷,ςO,٣ifJ>ПɌ37b7G<Qv#Ƴ 7P$^4SeW$cC6,g4V`Y:aQ{OrA+_bcqT+1O%*MN]DvWc|# +d[Tl!PtJͻ;Z%"bN->4+ UiUDĜ,DwS| +jYlwQq >ooZɈX,68TlN*cC? Vլ|Xmk3E1D\9 QTy3FGcլI--*Y+dra4OIW=Kx0Z}ۭXJ}C?>:+b,pi~sc8BRIKO5߱u+JJPo/Mʳqu1Vih/7ゟ&S!)qg_)Nmυ˪2>s!jF i#/QB*_]$QXE|Z21Cx)= Kv+FEF=4Ǿ~</D-D~@ÊE֜c}O#Re>-"ȵMk*5!Xړ9oRˇω|i(7î49kØNz;x0[3X+XmgGE08)-2s3S)1؀']˥M_ (ɵU1^k0d'{s~}XL,[58yyMdp2k!=-ATk't~a1*+iAbDW ?Oc؎?=&HlnKqG$)+Ò#۪fБѿtMI8Pi腓%)ŔLoC$찁~XJnC#9V@AbZM~T ( =8H !v=Tc7 /fB KcZHye]ckD4;e\R&RqNEB͒M\Ƽ#T)A*-OEC [ukQBWttJgz #]9RИ Y4-Drɨ{&RQxl\#-=SwȦ`[f` ޴PNOwI/T~bOAc/xrˋ zXc~~(eH(P˭sdTβzT^Τz4 zSO"+AУ-2?X'⬱2P{&w̔ ғP/;}:[|$'j{y_t~My)y=y%tl/$52&qSS~ӻlWO:լ]vIђPp_wϜ9oSWNm۶jbdd_j*]z˗Ę?~|~ѣ[g)Sm֐ 9G]e}ӶVVVv1iݺEz}ŦB2(˷̤`{>p>g6m!F(H ~}ɓ6Ϸӵk?Ĭ9|Rg$%G~zs{6vHe/ Kڕ^X:"f4? Ȥٶ*lmmTbB#*wtD* DʞSoZ܄qCQ:b&z(Q1 X{ )}tFyߛ÷[=z׭\t7mWu:GKg*L}_?9o߶Y n5jTTSUU. |)!* ~c77>::Çܺ|V273ضYeRl|WD쩳ȏC{LwڵU\dZsJ$:kHkn 1ky=u>=Iܬ)3 = I1Jzށ7ĉ||_($ZƆqzB'ԂشЃ 1Q@LP}DK5=D =jvxc.|Հ3?'z~}(A@L0^۸%CbRM=yDM3&D X#cutƆ=(Mc) Ĩ9;I:kӠ1 bpXM1*y?茙BbT晎[zR7ΘC4n tέ\Q@LT6c==Oc=Qǡ_I{8z,>q FyV͘Z \v#e،UIdK>[X 0 Nd{>8c*c 12|Ap{/oOL'[2$V'1@~>v[A@ 1]x ;FL#.ɖke1^1*?f6l4|Ĩϭa#;=Q ΍`#a* Fj+ \6cFb1N8U-lЃ4a,Ƥt. F7砇1+@M} =Y1cm, c79=;6c C=1lSs،)n0K،)"?ٲ? PPK|ylIZFUW1@̊\ fm #\P=،}1e{}{W,cdK|M\&U،İ!z[V_ =YہZÓ6b118c[CbVv SwL(n쪠S"[51+NЈ_Ĭ䍰WN~EXɸYItVmls1+>4c{ \QةvN$\xzB# =0jCv hT“tMK&jx&?z)c1hL "?"ÞA \ l{bX'\!CЈJJ} 8FlV'**I}*à1{dXgtA38!6.c1d6 ^zzD!@ =JEw/#ζ-hƌm"p9F6N }Ȉ{[kj4NKtj1V#s~ЌAbXZ^=a'A69=aFLa#@L BA6z2VKv: }Y Zc 1]q7Xӏc> 2n6w?1qc׃Ajz#7'AbX[}"?%@LlG1,ߐX% xbև<.]ss\0a,#voȌw|.g;hqx@ +pt9AvVI=IɆdT^ yT 8U/z`Xkp⥿ b E/l#]dבT Ĵu*Ѻ nlaS%opA:NlƯ1yfO#7Ŷdɮ  ҅˘R+xW*Bem =qSk(eLo!^ҵ"cx_6VUX{g#^p%%%*ce)߰JMF~8 {d&?c c3<1Ϧ*\[:21<zbheLQp ~d3%@52T6NM1d)2'#]5ӂ˘M#$koʰ[u+ e^,c5n$qFeLY1-5?σĴl!2VX6\/T-*c ˰X6F52fwƈz*UDh_\"Wc{6XZjt444թʰQ=qy 2hx z8{i 2VʘD{ԇ>ĸL?Kc)9_cF]j˘hOa˯r1f͚Tx%mѯ%\Tv˳N>nS)h3Tȗ>VZ5kԨ!^/*u'FeLR=dGC??b^ &2> +s}AD?,=d$KyM y4ؠx+Hy:M^x!gHKyT(c-7}~|$MAellLq.32VʘB&, ߣ ^*V@eKcˋ(cjn%c2|6g7[ezqr*uHj1Џ~kqF 62&\~]Wypת[#) }J}6qc*cTˆ7[ z{ȪG< }qR(c$>%R_/ژ1dY} y[8-]}ZdLޖRĺLhդIcdiL, mWԳx{Hي.`2jމD>NAfMR͖T؟=5=b\Js ,[ȁk:eWx)VnogLX( <#_A&@b1q/lӼ/d5dL2=*u^A?>\9ZdLo_-8wn!XSADR{*p/ze||vkXEx"KWMT-,OB9oo1Џx6-[䇌?Y ˰ꅰ ߳UjVѡrqF/[ɘR=-qޮԺU+AƚSk"eQ^Ϗu Lƪ[Mp冝5oӚXK*cE bakt= 4S)r ͖mxkMe*64-/(מHlGXѮQ5F>Nqڶ2ƛ-2`/i@[DOE/2×'>@gJqmol%^Td_g(Բz HlͻdLAcG+2I;Ae+~hv[.{uɘvq1F>Nۛ'˖ɲǘcPdOUZEKr g0knu?C"_ C;t@e1QV{ ) ڣ]Z81炰/2/ԑTDe gaTċD70S+ 㸹:uQ1*c)羸b>8Qʁs3zdL48<=|,Șhߖ7kV)[5[S2# f)Ht{O.B֑7YM}2C;#,kS*W ݾ= 2y^+I'vXTƄ aVP*\Tc GPzy U7z8# |>W3&^D^Wȁl%zL4Yv\x,KЋؔ(^"c5˃~|$vz%ȘhB,+p]\fӓX 7>AdLwϏI8=_/~zRʰ]=&2\\2bep~/e2i{*FL$xLܧw^Tx%U,E=&2\\~񳨿ʘX!w[Ȫ}_וVݯ1lCTKOQ2uKIǻ,` {/Zϼȁ ucRMeLX- 1&^w_ezM,@?=YdiJ,;'˶ɲ9}lH, ׵X7q|O2ikvˁ0CB֏ʘpa +,Eg|sqv*[@Bf:_tԩYR͖Druxm ]wIjvt[xe8D8nNUOA&QVK!|öswb™3?H8N^OgΘ4AD~d9>YOCd٫붝zL9/5+Bd7lܼΚ5k3DT_0Y ˰RXL{{S& ތ}e>sܻfD: >2 `ٜ9Ie7[N'ʰ!r^t%ˮ|yyZ+uG@6 +šel c3  uoc$IŵCAdsݾDI6N^ ͛7w cE43SaɲS>gOn\"cf:&Cb'? ,?>1&}?G_/&KѾx"Een}pOϮܸ$cfG$7+u…  =e/lݺ[OeK 2cЬWو+HcEC&,犪Ex0l=ݻ_$\Z;s{dlobKpO^dł&˹r&6\r3#f}r| 5bu81@zceˬ.]Jel1l9,gʰ==/kc$Ĉzd~5@[~w'ɖ+/~ VTƄ~Qtz$zg8+]" O0nVWO3V/_Co8W 5WB=fMe7[ZU}wi\ܜo71gl.wDd[6[jJ*c[JeLX]0J6\:퓛_b{=rf*^$aV$}v;eWSWem\H,g'˩r}M, ׃5\O_by?q>s526d3a\>nۺiZ^&r*cRXL2`bIK)rKN$fkG*H]ׯ[GZp=v,'/c먌QyrѪ{N(4=I2qBߺ_:s 26d8> tɕ~@el c K1f@jf>~)/9*sv6x Q3V:D$WF͓v+cْv, _)0|k3r"FԘ7ٺe|1$ǻg޹f*cke%{h_KyO䝘 D{pmlll 26b윕; Č׷m2ʘhTaR[RS}V=sO\jVIKKqޝ;vlQ=%z8 B|8>p`ﮝT&dYԾRѪW5li,\ۗŋDFl/S]Az[N/l!E,' rXN9<$K;WNػwϞ=@7mѺ]CISiW>*cwSIe7[nV2gRzz,zzO_TbM:<ğ足'N?~QȌMtfW~M)RqSc|xέWy+'O2vozx{nw\o}}9]8w'`2{Ѫ +.Zoa׋ʰ?[e!Gthu MƈI1+%A >GpppPPP``߽~~,K/^tttpyYdź9 =ȠOo޼yիWϞ>}#{nnnwn޸|eK.Cv Yl)I*c;LeLX2&^؊g2&a)L3Ϟxܻs͛`8_~ڵW"&5^f}ǯ=*lϕQ>/2~ƜJeI1dyV0YLǨ`|[ph$ 򄛗 w\op}9]}=Uvv;8zwo|W%Dgn\=wp5аظ,,||'ktttO VQqsR蒳2yK !B!B!B!B!B!B!B!B!?`[* endstream endobj 150 0 obj 16334 endobj 13 0 obj < ] /SMask 152 0 R >> stream xA !7 BHRHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZHZe>~ endstream endobj 151 0 obj 2036 endobj 152 0 obj <> stream x݅_TKpZELym_;VTƎkwaa'"".=. p?93gT@zxO)!9 OI`Es$&i>xH#}5*8\" ly<4VYH%t J)pێ qHc&PԘD+q:9s\RROHN;bI%L>G+ɠ7?4\RiUm C2r.f4DF T#VzM7xc輘[@D:N@c "U1/#hSL~ a%Կ 4 `EA__)&Rh&ULV9_ch >l;o oU.GVnh# 3|DjirׁIqEPh2Od~/ TI౳VҪn6PVJQãԿ4۶|Y%R* s^+3ߎGHZR!@r:iYP 5{]\̪5ZZ͞ST7{ ߀ElXctJfQ1Կ9y2bz.=R˨o?\ 2d J-·Z_F@rZG` tmc` JdS~Nq?ԕ0vK-'݀B]HDEIP$U|3eA#RK+wxqXnG^1DqW)2r(^%A1Lf3Z:eG6( Hg2d¨V'J"$(@jimzwA56~"M dQEd:1fQ){w>pz;K_!HV6'%zg[䑓Ԃ ȷQ7C:5Q P )< ;޴.@ji׵'AN溣l}UƤI/`6C9fs }D+k}U*Wm ܾr{4@с䞒vP JZR[*3 /\_7έDjn@Kd}G79u-<"Wɮm9-+य़*N[@Vgz+) 1{ήD|Lm[)/ZZ3_S !GIqRNd;rXMk$F103S춱ZfQJ1RvU=OINˉWE{Bc eAQvCJ ڍ-?qLZ_%XP5,7&_YSV}$ͭWwPsq8ː6x,?XDnT5TH-OB2y}a&840}[D6̷!3z+asuHBRrZ32ݕt"6 zq1d$sbyRKˠ)̇k :Σ))嵙 A H͵Oƫ$.p}]]#+t`FGNwiOH2>%[pIBz>Z%R۠D~Jx=] 9ebr?}_z&7&d%7B`$Hm^Un-o/pt *mCDR,x_dtu`xֵuE wSRS? ]1@/j]h[7ຶ>uyzG$500$Tz4\Rj9ɰe(uEVm\9LPhپLH&=JKmjQFNR_zů􊍹B] #<ԁoj/t. I0:J@m^ԅ#>7BK$U5Uj# 5~+la-RPC []h(?%Ak2=uy@Œ#^=O7&P ]+*%]:vYj[%5Iv ?"9z:&0s_Uy+,iK}X]IcXmg*|_^Օt Dw* kݏ_8R դ4qK!n˼iFDZURvԕURğ _rj9-҉,u ޡN̯P7mumFɠ7% <Ӗ*aoꒁ2ſT:e23-Xr9]~΁gYb\]`mcV~$Mz=90ublL+|VS2Q7#y(EŨ%·cv\.RJ%~:{ΠO*~|6́o"GKu#L9:Yr7nMT3)KSK~:|FC"  CRϯC"yjYur1u%w]_q~[8Zi_5o aĩ>9rq<3&URM$5Э(zEfPވZH]:N m9˪'uGrxurubLӯkMx!uPpu=!#RKKotåD@$1j 9[ψ9Ran滧IN\^1%lyߞkdvuI!;! LUnԝPꪂn]qWꪂR帾*U.ܾS%<.KH]XOwGL[͑b޵PiDԵy|\V>GʔI})'R+\(BCSdiEQu\^ZtK%j /ԱQQduj+uA)۽dW9_" boԧr̷ájEW;Cz.WɉجTZREJota!~x)괨Bݨk 9]:,*2v2^%ٗ`z\-w冿 ߝOW~~jp;^%wgU+缩 Y&K2}NtHQ꘨NMI =7զNj |a:kdVc3n;f.u_*-z>o3+b?5߅W UE5f'bGLn{͜~ԥ$LH = ƫ$[SgV8wJPgOjqtq9i̦~HE6;ZfbI)fP7o3@MɐXdI»q+Sŷ~C!j)<crÌGrQgZ տ_䩿3l&Ok$?뇇$R-i#RKKxe\uÄ(4 Ke| \yXV{^݁xD w}WIrn˩ۭU~ĄI7FP*nqCVr9`QqtC*qwLk)6-hͨu3DEl:l)1>#f+<)YGkkMh SQF'Oq+^pOᘣ!֕ԬTΟ]<<=#bbcpBΑbi q.Z+ Kz9C]U_*: HwvXɱwVW:G'o(A'O|Ρ|wQǫkZ,C|ytMԵyWԤRI][G5Եyx,vkb%u-!VgEMȯ"liG]\ZcE="uU.зHRO 2F+ʏQђ%ˉ۷qL[80C/:ogTm\luy6_|o`P,-ldN#.ce5JJ0@,Ӱu^/\"""bbbbSRRdU)t nffj݇/ܾsg,݆cBQ|y?::Z4_瞇I,O?{ta:sU)Ppo#ob6(BFfnąq`]ѕ~.wCǿʝP^:?܂3Ŋ6ERTO>PKP!fWR'b:C,P0Ձj1Y3 4^«!1Lߛj)ScNj˜ @oCƝ2HI] w;Ҍ'VmwcC=$Q9,ӧO 8PzpA(C;u=ܫ:D] qpq P)wAA4^&AA;yL5^.|ۉC/9l;uM_P`gjǚ@o=;G] wu*mxЮ|^l{{2u=Z|{/@ZSC @$u9܋qAB#/KQCE.WyZ/!;ScR$1 vAi%ESFa.>HSWyg] l@QV.[niz%,㰑^M.B4}GC*p[IOi"cfdА {04a fG]%u7xI>:i+].K1O4%V6WeeJ#<ϣ >J#|VaznVYւzqNb1 xߣ(uӴ?@] `ը\bdEhXpu9\~t.@N? u4<*nJs] =:i;$z,Nb=KHQel7j=қ?hʵ:OSz۶o.0 +-B#H[::QolD4w`RmP'1MR=gDj1r$QpjlIv[@j絬t-<u1!X99Tm 6m-L4piN4 sZ:$H,`nQRSw^RSLљb`dt4IT&[u1v3Nq ېsu% cRS^e䔬n.EEv+Z "v%?!5n0u { ;τ:H"pcMqAԵq6oeCVnRSm"d;b '"/osZ O5"ONm@tM7FfZs H^h "G:SGQY @s HM[UV¨ HlDE^U wb Yna-$!5|]6ڤx1/= Qgd!5U࿲uyzޤ. f0ޅ 1rwD85ec\kSΣIl ZMFPXӈHaRSnfcȨ@b ̮@F^Uk,J:b{ܣ ߂a/q4A6.B] `!l̶L"x*ݚ\Ȟ|REwRQL5n'j 6zU69gtCvb, "|k,70uE = %hqI496 Odb.n- p'\Q̀>0݂*{H߬'2HN[Oe%@Y+oJ+J&.G]NDhIpkHȴHC>j-B>I F5yc'ZDhJ] `+3%2&?1kd%2_m3wB#|N+Dd2PWẢ*H>yŁ̟fo)D~8L@] `Ķf*Iσ (0'etze"BأO q.Y+7XJ~HJH?SWXGe^'`%Z\ǰ b)~)t,ZyJ#N*DfS@BmK =ُD֚Ɂ%Ҏog8hm#~. dm`WT'4] SuApƥw! b1γk'ؐr+iHq%HٹN /*c,,m{(e3=q"9yhLȒM- WS [,'0ȢeZ^A#h2&xE/ lO7LlD-}o&7 jiiϷeNdIq;l;)xr/;D46'ĤZ7,JƊ]''U\D>D.D4)ZԤXb喼ę&}ir%T'+wlSRͺA (ŋM@ d^)K7-}D=h_Xa ;ѸDYxr]`}()o"Kw+$w K]D띩 D]IReDy1Q|[.YD%u|ĢO)C7c"H\_!jnk?&1KdRz\CmjMf]xaj~ | D.|7%xiD&tqW p?P?)xAKdvn$!Od;{qH<ͭr/,)Nd2ejK;҇<..0㺲HZ؉&ה\"˖i lZN{E >$<7kbǹ .Be]->p+1uۭxM]`F£5I—ǹDV*Jd:wJ[85~ vt@q)mEmy\իרl-?|^ԉvs4/7DZ'f;0nDe%Dj0pmy8RV;ӲueHփv5Q kԬY;n=,JNdM.$ ]gFY^Mv8vU'Ix̮Yv: zū$HD5mE mD֮xE8B#џffzۼFz`H/fIE,u_0 2nDVYOdM>uD6lw!Mҗm])vbՁYޘ}1MȿMlD֫|4G *)L;~OdSx 7H<[PH jy\Qԭ+Jd6So nH{mLe )F6'~G) (82kկ_Ak<d= He" ڌ: n@"㿚yHFv~AV}/"Hfi Jii"6j176KO뾤~6)N4~Ю\"iGk2ܨf~A[Ȧ:eIH백s1;P)"M[\v ˒ AVAM6ky#,KB:@D6k5xl4seH.6f-;[.#޼>Ld֣wò$H:̪>Jjx&D6o޼E! ?$]5_,Jdn:`ziblGU~>Qcq"Ecٲmc^ef${]RP2ڛr`&2@?hK~\$[OF]`'Md/czinv)'6-[jam4ԦMdA.{]$ѧa^֭۴4%ABtxdlԅv\P8OiR̼FٱfYye܉ĆOdmE Q e"Yx.@ !s`*e7jy\'69f ^0o[Q'rA 5g _ eu+f'ZFeR>_^Цb89lܜM׾$" wevf+KYWR$r~ C&A,偉)<#JС\"9uɎI$NR_A[ͺR$rؿGM8 &pb)#Xu! aW\Y9|Ͼ: _%qyrI7_ j qQ6uUD9jʚc+l$9=oy|(7f9rQc- @ z|f&:@D5v֛_G1m(["?k<.Nh9z,v=0#ڱ]RJi9z ɽ܂\YGDyAȑqߤ} 8 " pui.\"'Lc^׵գ5u@v.=pS@ Gtż˯TPL1{8O4#O,/Ȯ*8q⤥o|A*:޵2Zm^%r83-{Ku-NЫY#DNLqҏ(fiff6wU/s8a/O9;a"̙clYaXTA\ŰlȾGk7p>ܷl477bǎ!hK5hz![k?D'r޼y XuPOBjjRO/XoA>ʐ ?4L9O,>f|"D.Xxي{ Ucv&L… sWt1xpϫFvQhg.|"-ZbrvWX2TAܗG7էa"-^rש/BJ=']X:B[d<.^s\tM;C n]?gt\tٲ[_zO9.9!A=: y9?f/K.l嚵{/n/J&LNsft_ŵ'rHS>s~~%rUk7 AKCH.+VmwW0s40%))~[WN4~b IA;-+-WY5j..]i:?i"WZZZ'_+& R|5-˴-MRUk֮[aEbv7n^(&rklWn~XdBArŵ(MY5q. ~bc+Vj8k׮۰qc7=o NDn޼e՞cg=xDSC%x3g2wIȭ[mf}O?c;Jxs˦VZ"3X\Íْ8[iee}'.\g(S#%x>9b^Ω,};wwʣw.18 R"||UF+:,F)l\"Ec6;ĉWow@x,i;G5ͺjyܽ{={;xF' 9EJbwfH~6Wĉ.N]Dݻw߁'_~s;>ѱX$'כM߸qYWܷoᅢ\{,ߝ^ܽrti%RA{?hoA[=|"|[.~AQ11qxbjA;N4 ԭ}6:|ȑG;cs߹T%Ą<2ډW̙"K"<Š-8ǎ<w?~[{]ܽBcG. .\ O9{k6o~#[ۧv7or>9s>%MzfΘ>}sΝpŋ/]t+W^vMn߹{gxP /؜ݿmR?)Aj~g}Dl.1?fS1[ʼn'(Wܼkq)xFQɝ+r4(cU'㍛ۯЮ@ nk#,_$A4lcy|'?k󚃙kD8D+=}eHuݛ/\0ˡN"k'\|#E' trx3wmYGA?hs}ʍ;|'0$,m}5JӓlXdEg&Q"qa?mn۾-0*8@ !*ӻWn\>wd%r.gMʉE<{/8,"6 <- Gwo\r˹$.Sr"ǣh\aW߰hlaLD'ݵtV[[1jyK'.\?|q I~#L Nܲi(wG5\WF"҈u;r?$9 "}]>;ٿ}ޝ[gO>zw[-f݌5x{>~WW/?x̧AZI^v/^<ޝiSBII|={?8@.訐@o777_?z$ޡcksxG~S7nܸɹub~uqu O7(LJ/h;1{{6gP*arl '6664?<r'F endstream endobj 153 0 obj 15977 endobj 4 0 obj <> stream JFIFHHAdobed@      ^^   s!1AQa"q2B#R3b$r%C4Scs5D'6Tdt& EFVU(eufv7GWgw8HXhx)9IYiy*:JZjzm!1AQa"q2#BRbr3$4CS%cs5DT &6E'dtU7()󄔤euFVfvGWgw8HXhx9IYiy*:JZjz ?>UaMh&,GV6m#7A)p9_}> Mny-#u0X#ϗ:o䵜rھ]p  z֒}9]Fp:x[ Pc}0|:*R*{ɫm=?`C;(RhN7CC=o˳$8I;B}w#յ ]+K]jl8qD^J7 ňYxISyGE ےZ]N,$ 1RwjliI5.`rdά@Tk}wW}x,u .ԄD* *fhEl\d31#=v0N\ht?Z_Ao:ZToILe?%KJvy} q=#+|e{{O0%Եh][ӼiI%Q̓g6m\9d9dM XnBUPjt5;Y`G9.K ʼL/kk1삷sՠia0j!_z<1䭴w łeTR7KAQY#Ÿ,j>[GfѼԗM $J•۷\.ó}aCxѐt:͢"wc~BWH&Q5b6H2؜ݛ&O,،kVNoE]q={ mrQ4'djUyTAE:=,b"2 SMokkwy4v׈ifp PaSohsqϚ8q$DY}u/.iEН>M; KP5V` ERInKUԝz/g4&Bddoum{ӫݣ9;oWk>q5-D?7;Yz^E( My`ܖ"o^2͟9ñtDf(1XNM[z'GQȚi48Z>Q8 Xbnn=`@  uEJ9GWYؚ1q?`l bEe$v<PEN%kQe LŏI-՜,ƣvnH#˼kauLhP] } M@; GmW 3oow^{yI#)gmejsNS>&߾<,F7~ "±o#^I) ۿ 1OGN:IDd%q1Vۿkxd~?[8GWӿוXmGD,Mh+N8I6PN4=z˗ߤ,a OCA"B96݉Lu8 ˊ`G1].F5x$Hw> `QFVT Fx>tv)2Gs >}Ax:z8|qƵ{:鲱SSʠH*o^ym_ko;hֺOUb"u rrH^a@3=t=Qt1Ă5ewxG̽'mj5=L{~.m_wI[M/#o>ܰ$"c }"CGmy^~&Pt ahG=2@A'ST%lnf od1WĤ?#@B `FgDײR[mUwxlD Pb#'ӵ z^:6yW_ViϚ:7 f_ۿS\BGG#:A_\N"' jȍVf On)yg{ۇ5,S Z]o}ZKtES5Rڼx2 qU_Bk1c"cx'˗g4k.x?CG .btbqߋ)s29aDcQ<\"@Yq3.n|դYuTӨD(ۥ|3Mퟲp@0@c_ =tKNӖB4 DxϹ]ݶnh}i}`)+31u:7{@I)"/L |cis[ڭђ"],ad~[P)+Z,PD3X@!8dKÓ)O 6b!(,޿Gzϖ5l'mGlXo>bS"B g=FW/O.!!\ݏ2xns;߻"Ώ,Sv7GhִZ8۵}d9D7n{bg(Ĉ |6ZjǫG3Mޠ ᪯}Jv5 Wo) Cܜ[:I K4 @Po|P Mֿ*㣇cӵADTv$ 59>{KI>-^yO5Y#jZkcv5U4L}nO\P糠1|#iJ"58"oPG82#*(L?AJ+,;zD/^w`cqrsCؽ>3ۏ//؅];P`9[ E *F >}~NND Sֲe\Z8 Flj.QU!ˑM4YThUՑOӸHLߞ-[ WM~v\$}b$oH@k1sb~F9_5;-q$pﱹ>XtZ^~~s!ኌbkZ2 +l_W,壹Jco~Iv/-yQ${{sHR9'1Ssv\پcLMS] X6>ͽ u= SFklͻO}=3=}ښUD VMマ#t'w \^ 7-x wZv0!dXN(^kZ*<'s7$5 H?&J<9@Ե)Xڢ-jJkS'!(Y1{^MN`ZVzrvX%[c@3ZȢin~?h+ hwҼSԀ ӑߖFP,%Q"LF_6cvj={R+[duY¼`޹~]f|xDcje0r_Px[ Xm>E攎f5cz{.|}DDWS-h3u754F?,K K*듁{,ǪaLj+\S_^{Jc[?#G"G]Tv t>{-KkFd2OpZ%ZēĚoP3۩tF O9K1[asa["|FmZIt0y69tIէ4TjK1Ѝ wγŎ||A1suGC 8,:FAx~_(M5oncR!HWk<,ulut{c1yЁ-9.*$;@jROXwH~缒 $fxT• }QG_ip;@d҆mr4eP [-Q%nh G) :a'AhqMjo-'Fj)P~/W2a "dO 7.>C $KɃʶk:HY@[t_|mSȎg;'U3?~Ҟՙlq_KG{nRnO@g_><\F  [WQuS}ۤ:l0[gS@@U\}}7e Y1Ѝ˥L$~l̾S7.azY. 銺K SSCP=Y}$!Oby'kGmIww_\HGSqq],sOT+=\MOsδHF9qg}dO1K.~yQ3sݯ@I@ @O|k}C  G}g K;Rm癯Ǖu%kh.4XtOT}K|bݓ4|H޳Fꚮ!oU$&q ^ԂdG/՝_bW9s_ u*8{hV7KybjsMȆX)Zgr ccq Fj5ݡ. 1T?Yy_2n2Gơ<"mG r1Q:/ϴqa1$o+ʻ(Cv7KsRO$#D5 jEP=̉]_>Uثm{w׺n#rUhd[t6ZIjb.ݿTҤUZ 66*MkPgK9&H%zY=1Xe8Eu<Y;scw<޺j/Loz5jTfqܺguGF#Kʶ|o,.37^o6~|*'lrVC>HhEO~ U,c HOr6gG ߘSTInX4EA(惑;S8ߟ9e8}Qpg~Gnjb"D|uGol|ez}^7wchOB 1Aν7/NgF|Cq}[wvQv._ endstream endobj 5 0 obj <> /Length 73 /Filter/FlateDecode >> stream xE;0 C3CE…CJ,Ac|n" z{2gOfaZkT-p, endstream endobj 6 0 obj <> endobj 7 0 obj <> /Length 54 /Filter/FlateDecode >> stream x3633R061׳P2Acs#0ʆ(dp)iq ja endstream endobj 8 0 obj <> endobj 9 0 obj <> /Length 76 /Filter/FlateDecode >> stream xE10w^JȇB.֝,PzbaiKh$i*癴*W3% endstream endobj 10 0 obj <> endobj 11 0 obj <> /Length 53 /Filter/FlateDecode >> stream x303T0513R2 M# S "x` B_WB8 endstream endobj 12 0 obj <> endobj 16 0 obj <> /Length 76 /Filter/FlateDecode >> stream x=1PCwN@CA/di-*?M Pr6yk YO_d[M|mK endstream endobj 17 0 obj <> endobj 18 0 obj <> /Length 55 /Filter/FlateDecode >> stream x3523Q0513R2LL M rĹh> endobj 21 0 obj <> /Length 72 /Filter/FlateDecode >> stream x33U071S210ѳ rL ,<> endobj 23 0 obj <> /Length 51 /Filter/FlateDecode >> stream x310ѳT071\&B:CRHDD endstream endobj 24 0 obj <> endobj 25 0 obj <> /Length 76 /Filter/FlateDecode >> stream x33U0& \&&z`B1mdA> endobj 27 0 obj <> /Length 53 /Filter/FlateDecode >> stream x310ѳT03V2rL L4gr2ҴA endstream endobj 28 0 obj <> endobj 29 0 obj <> /Length 2553 /Filter/FlateDecode >> stream xu= E^ŋ'ϕx ƮX$A KZ}>Ͽ~ұO7Uf3|mߟ~?o?M.w^Ϡz篟?[ u/׿? Q-_[Q'%Դ)J3RJ[ RH?xv.Z ?̓4}O^Q̽DPP\LšEI/#Q?vOgܔJoPK(srWJR7Q╠MɠtP:fsr>)6Ju0f%"¨ ^ߦǸ)ӞgeWk/'{~K5HR6PBN2FI4P&r!2F)tP:H7(2(U7ū7BIDUK)2>Q:(]-Xpާ VBu / 滛MykFTP*FAtj 2àū򢖤Fbr# 滛C(D"Yj)%&%8F8B,cPA)j)*T#L%%RAJlX6%k6.NG.%"@SfF"N( $B񋈯/ǔ&NLJq ,Q\Ϥ,oByL/턌-3HR6;ܔQY I-R8d?~YE-$\LI2VFu̒1POA j):+;)A|oIt^eHqO_|eS"( Q-a_QYY-Vt0(o_gUKRbeqvC}[ f7.(V㕠A0]-&-IAm,PWAYy>0 Q"( #+_Ե[]a$P*(~ZBٍM4dP:(~ZJEY"K0^Hx_^]hLouVtjwPFXg b .}TIXgP! VB-hgnk76{2V?(ABQֆ>=u+ƆQ c P3DDz ueuH§Y iPnR[q0Jyf j( C+==-m( ! ?.ѺfgLK*gPՒXIiz;ۡ/&٩J%oWK(vr(L㳎[?ncSq;Dk]OCG*ƍRǍzRY{AOƭk#͸I8,綪%AX_ ]-em! ƓO1oYE dńxnʪͺA( j)aM8`֯|Q( ~ZBysLūϢ~z7aK'!^ڷsOL #{Yʶu_|EVDZ~ًQR{qx;A]ޔ=rNUKbCx6K7@UARԒ0lιG#GXo{; d{l68 ֯|Q (~ZBYM rR66DZ~7%? J%.FIDUK)몵=,_ $% iMCa C3%|Ӥ|1_"d|S|W.YRGoTK)ւ7%݂ڇ3 ak.[ožO_Uƪ.ǎ; uzSk_˸]%#Y) j db_T@*&ncOdJ߬PvzSl"Wo͠Ϫ(x6i<4v!,IhjIvrSYbD0||(vy9g7QMߛ}=-+_JߨRFI4P&;P66y_HۢBrCl.;-(EQ" 왬_"|v`m$L >SM˪=k^ .)xXP@5` Xj#ߟX j\xHxg0Z@=+Bի$?ߔ=owP"(LBWK)} 6,_/xXSUvR7ܔp,3,^uN  JoVK)Pl$W?(೪%"i3spC]lðy@x7>K vv>,vx9A oPo^;3ܔgP۠^KmO`{686A, endstream endobj 30 0 obj <> endobj 31 0 obj <> /Length 54 /Filter/FlateDecode >> stream x310ѳT073W2 rL L> endobj 55 0 obj <> /Length 87 /Filter/FlateDecode >> stream x+T0103Q07\ 1By(< p-<.,J*T03 QH  RL 3 endstream endobj 56 0 obj <> endobj 57 0 obj <> /Length 77 /Filter/FlateDecode >> stream x313T06\&PB)gn r&& 9.C3> 9 \ iZ\ endstream endobj 58 0 obj <> endobj 59 0 obj <> /Length 50 /Filter/FlateDecode >> stream x351V063Q2rLML@l3=K8 C3Ҵq endstream endobj 60 0 obj <> endobj 65 0 obj <> /Length 368 /Filter/FlateDecode >> stream x]KN fx '01q n6)ͩs@,[|y90AU Ɵ#q4OgM#szt 3!ca&0"m:蠁 %!q?ڧXՇa5*R:!`po\+hڤ.2]U(6xxZ*YS+@JB[Ru [좦Tx4S-U}Rv> endobj 68 0 obj <> /Length 366 /Filter/FlateDecode >> stream xeKN0 EYW%[` oBe}OP͹خS29SMJ.ҹCH1ge5IC~ _*5PG}?vIOkαӧcc/7YAh$x ,X$:`BGK-(Pct4;8GC4)6;v apZ|)qÖbYbB8V9͋3rzl=҄8Σ2~`]PsU uoRUmť#ֱ:xӜ>5 $[7ݞ ج3XpGG'svL|G]S| mC='xA5<_R endstream endobj 69 0 obj <> endobj 71 0 obj <> /Length 368 /Filter/FlateDecode >> stream xe=N0 "'b' #t2񳝶Jm8$92bN*_BNDb <-|>s|#v&)0mΩ%Ǟ%f"jY$6皆#rF4sXŦzK8j $-AR| {g&Ɛ)+]MLvZ7؀*`T婩(e B4Ysav" GR)M͋Puڲt5nʹK`Va㬻zќ2qKb`.3k :eoI6ql`ЖuD:zQY_S[Wv;{x C endstream endobj 72 0 obj <> endobj 74 0 obj <> /Length 371 /Filter/FlateDecode >> stream x]An D'@TE#dѪJׯdž$_!)22S.zEFoO!EfeIz#u=E9z ,[l$Y(q%Fdz2=pn nE}㴼D `%xj겥kJS1X \3XcQUKZ**fU;_}X3!GV3@Q1FCTWj/,Jk<ɶW?IUSnɂ Z> endobj 77 0 obj <> /Length 364 /Filter/FlateDecode >> stream x]MN0 9OI !l>V3tI^^4ZffJE~gy"jG%zuez(q#.KȊ4a[&\cADC7#7Xj`˪'Ű b%RM ۂނ qb t7I f+V" pSp8> endobj 155 0 obj <> stream x7.U  endstream endobj 156 0 obj 14 endobj 54 0 obj <> endobj 157 0 obj <> stream x7.U  endstream endobj 158 0 obj 14 endobj 53 0 obj <> endobj 159 0 obj <> stream x7.U  endstream endobj 160 0 obj 14 endobj 52 0 obj <> endobj 161 0 obj <> stream x7.U  endstream endobj 162 0 obj 14 endobj 51 0 obj <> endobj 163 0 obj <> stream x7.U  endstream endobj 164 0 obj 14 endobj 50 0 obj <> endobj 165 0 obj <> stream x7.U  endstream endobj 166 0 obj 14 endobj 49 0 obj <> endobj 167 0 obj <> stream x7.U  endstream endobj 168 0 obj 14 endobj 48 0 obj <> endobj 169 0 obj <> stream x7.U  endstream endobj 170 0 obj 14 endobj 47 0 obj <> endobj 171 0 obj <> stream x7.U  endstream endobj 172 0 obj 14 endobj 46 0 obj <> endobj 173 0 obj <> stream x7.U  endstream endobj 174 0 obj 14 endobj 45 0 obj <> endobj 175 0 obj <> stream x7.U  endstream endobj 176 0 obj 14 endobj 44 0 obj <> endobj 177 0 obj <> stream x7.U  endstream endobj 178 0 obj 14 endobj 43 0 obj <> endobj 179 0 obj <> stream x7.U  endstream endobj 180 0 obj 14 endobj 42 0 obj <> endobj 181 0 obj <> stream x7.U  endstream endobj 182 0 obj 14 endobj 41 0 obj <> endobj 183 0 obj <> stream x7.U  endstream endobj 184 0 obj 14 endobj 40 0 obj <> endobj 185 0 obj <> stream x7.U  endstream endobj 186 0 obj 14 endobj 39 0 obj <> endobj 187 0 obj <> stream x7.U  endstream endobj 188 0 obj 14 endobj 38 0 obj <> endobj 189 0 obj <> stream x7.U  endstream endobj 190 0 obj 14 endobj 37 0 obj <> endobj 191 0 obj <> stream x7.U  endstream endobj 192 0 obj 14 endobj 36 0 obj <> endobj 193 0 obj <> stream x7.U  endstream endobj 194 0 obj 14 endobj 35 0 obj <> endobj 195 0 obj <> stream x7.U  endstream endobj 196 0 obj 14 endobj 34 0 obj <> endobj 197 0 obj <> stream x{y|׵=hȲ!x ;xۘ@b&XlM`6I4 xm B鳳O> T& SiID 20M  j8%}%8"܂fL!Rj4!a Қ(avT'I&'U(I US`y&jYnM_S[GkCP|B M!vȡ>!+Ms[4!EHrj.Cl%Ѡ& 9!cR)xOs xّᬕ*)JHH(5)8ZHif]V:_ H~pح&Ժt)0~άcMT镦`{0TjC]er)Y5^R,d `wB- gnbU.랝V 9 (` !Ag'Uau|5 ^Ŏ& oRcDg4MaOn]Or90qFtm3yTe⦧qUnilznfˌоBZ9JiEi>V JH/X 6 d=9Q.H%5 -`!g,SMjPY8>Ma3K<.|p||zU_!$,8MK;N4~P]2;Qظ(mTQn uE4Sp`98WdQEAދoHՀ%M4I%?}}?QIЩ_h F_8xAl:Rrᄉ򱥮#rG又m+{ip/;R5ˡxd>d!^zkגBYU8 9eQāw@EnPqdp;MN<{ ekރ1 _^|Tѓϳ 4=\h7 eG9PzW@lڵ=d]jyIe˖[wjBpTnl(/WYWUV+/=bҹ3dO6/ON)+{ׯ^_,:}/FCZvՒMlSrRS%6/ܞ5czάs7Z{QNQFnm |e.~H#!k+z~+gNy^iVB}%,Ca:H9()O91e҅rqaUkese7txL\z+MӠݟ8~+mԎ8| Jlo~~Qvn}hNJ&X3-{HpU+gͷzF[FwΤ:㌜r՜Mb&3*ǹMy!fNPr6p@-WJrw;m?mJ92*0ӹu4텁7Xd;h'ew !Lx)r\vXMԝ"_G<$@J&q4Ϊ9v=ȴrJ6c]S1q@6ˑ{N'L?jϯt:S8D| ?Fiю.˾[ Ź5C,~9`1Oj"\(v7n6"_"kvQOppVW|\1hGю2 utdgyuIg'- C"C] ryPRGm^6ﰣ+/Z9n׸*SK-M>lXm,3 VC.h,Gگ!&}sTS7HT HեJD58T{cm- ?&bxI[<9SMZ]Įwy=g<@n454GfT^578 3Þoxً7i10rﶁ׵kt"xID1˒Cr`et.svbd;#.D|zzdٲ~E&2^s:f~"]yV;=pw1n= +7Pkmoq,$y:MA0f >:! ~7l<*(p Ђp,[[HtxO"{!P<>{+NsrO.!~?ۮ7dF|C3o Sn>lɇ||7]-Ο$N|̅aW>C [,evkSCu3I}MޱU7MBy/$,VTAMBŽ^ ;}g~5GEƸcuhǮ[,Qw:]#.㨠Hl]G'w% SsJt1TuQ^GlOtS fao{-"C>Y׳/*9-͏J-\pvⰋ~OOQz=S&, #6&#oF8jCx d>|`(7< ο u&ԫ%$Ӯ Y^{U*)`GɂD$,85G؇ =ie.o4?ǠC0L5QlEYd{Hf @I:2Vbv=I2eD-,)obqFQ;m@>vv|ڞ zNp~e?V$>𡤿DN"/I"LcK,Ķ;vd™LHdB̈́әJ{ʠw"C7Q;+A> Md6n:҆6!># WY p14;PFC0U J6PdR}0J鄠\b* v&kpQW!V̘6;3+^p,~4 _#7 Wb 1(X""4@uA .8.(u₤) |X"* q1^ 0!O{2F_{|_ v̏1n[^j 'Γd E :3w-)eѼ-ev*G1Hl!dEqʄMp4fBs&dA.5wtv@m1.P]ѵPܟݳ_$UTu41&:yQo4s'-JzSvf!w V(n~E+NX17:n+C9X"X"(DAo &™L.x#gdD"waY ݞ)S,=<}3~|3/>|_t2.W:֡2񪏀`4f=/ H.AV0f%e䬘@B(ƊډQPm{* !md 20C Fؠ! %TyT}K~{4 fav5F F|;5BUzI EV ~7/a g4bf4lCl@r*F&ߕ;ˆN}hOv`DapG%t|ûpg KÀI~{V;FQ8 C V2i8XR~Yr(JtBqVCX;;[&蹬jiGy9{ 4υ.Epc\;38S$|>r|>?3yc,[Q}BH/U}~^y/h: 9o;#'OG 2Y`GFw`w6څ3hg={=zW,x}x٢k ڧ2pG?ǽ?^o=ܶry'K4e9}a{)JfשW8o2,cyYj6tEO"L3-5PlSͧ 8*}[ Ϩ@VיL722da ʰLz&P$O >M~%?-sp sdJa e;e8&.sex^d_m2  DP f'pD=2l7fS27RYsozY*("M@*OȀ>!ý~kcU\dBNy!U:ӨG2/ j .`9L&=Ƙ8ʫpWjuEssI;\v#@)pU+=]1xT{_ YB/Y@0+WnR} $ FuނɄ7doAn . {Yޒjp^ɂ4a!/u:>yT{ ܢ}6j|ҫ|x~=B#,^m)?|}+|D"#G:<c Q׫4F 9d+R=O=u]tGx[O@A JeE1 iwF6xyQAE{} ]P9k7~sN>txo8ɛTmn99ES9xxyK>0vlN0 ON\ j5d2Xm6vf.0;bhN/F40uċEbWnb~䧦`iuO_= e;WMj"EHf,q H`xSOV~P7r+ &RB+&'_ҍO]th_tTL֨z ds-!*Un=L҃^o9-hS^ D-p-Pj2]y4oŰwVApgwnxzqU}W:{w?t}s8\=?M{$$t2=ĥe0]:ad++ S:[?9YY|F'4#OzPJ9ؑ> =I\}0Iofch]uU<Hx:Ͽ{'=g~/%-:E=ӶQXtzo-fŌw|ǖRb z.mk)mgV9} w l0`@T8vXOOr3f\wIc 8:M/Y3}I8dsoAݾ}pG'4KڴS4*G#KW-ht"Ү5,Qt,hst@r ;sp:<wup@jh 8+>=q13p@f8Hp/;1qܜjcvQi;N ֳ$ᑢ\d8@F0!v' Ȏ-Ln)věpn7ɖ4 eN%x7=,{M_HΉ]DIJ}Ҧ7A@S Ko, kn&R יF섻Bv7=G/*[~|21*vWY^Ʌ]g8©\/w;ʉft:ҹ0[6oQ\Б~Y2{J @;xR{X :0JxywA lŰ⯽8kM?񾅾&&E/EY`"6hj^DmpmPjvy`?>@.=?Öy\s9aΖ /b|OoiصEB'nz~b6ViMql. !~聘Z=@<0e x @=P&kW٫y0` <ݖ̑>BBlOwK9m>w1HGO4j2sx% >! ܃A:`9HcV|c{0BH덬? GMQ|܀mx #V|ُ_نtϱ1א!?Wϣ{0 }Nc~YxU!J'>9/ǫ;£lI.YMsp#Bus;/LC w Q]nYAgxe̒y-uHOYV[=lm;m7ڷΩs.wq=R\@*迓0I YU|#Ʊ7dq͐\ذQiOyERed":"*@l P*jSetAcl&#[;*[H%ZAl%Y#Id \<Se KSe:+Njl 3?NMۢ*TY"KTBVRe+0Qݵ+u}{HtcOθZ-UfE"+W+3#=HO8.6ͼL(1]+ړʂpwlFduXk{w[{R\{YU״hCYqii؋ SJ'־&s鸔}eW,ރ]JC8WmJv#p$މZkjŊ2# ەx{,=#ù=]k"c ]ʆpLikuK(ƵtwG#cXgWJ%FkHP8]xOWkx(5Q+Ig~8IytD3b=8O-kuWqt{­,XWk1yDE5z"v$rѬ$#cc -FцK\pՑȵt)$-Y4ގHwFp[i]9On`_tu8XĊ;褒 6SRiE#mObYz.JJm-]Ăs(SRcf-NJc]#=+KkjH+u=z6zK$Bd#aPت|l-g)%cR0+w%vr0!ݤ[槨c`i6oE sq W! MbdWXnEn,SX^e5 &6QTi6i EC}.6 xPೇ\mO \;b {Ya"FRl [f;p|+hᦚrgǫ:&BqpoJudn=*N17Ժ<[5ʋ H Ìml4յ}?GI ҍ&cƤ16o7Ρ`9/1.&T(ca`objnLOr)sh${ImHZX0+b3h)~XIt"$ڞpQR[jU(k)"5L8oŘp1[Yvw7E8KVfJx5FIiY{m [w&5(joRIuLjI+Jp 3FRCJҲYE'ӻ(Qe RGLJkRS4_tE[E-kƹ)uì6-y2/MOmse\32oy*؅8'xYְq8 ɷ|/*L&0-*~O?>'rdal=bXYR( 8ۯz>3/Uz>sR bRB'i^8:>󠞇ޯv|+/g*%gvOCӑӻN8-O?:9b g*|X!! K!]Kŋ<jwDA?9}{s-ox[<}$p-o, 68B_}`z쨼Ps' r7~ "}tPTK>$ɣOrY>ik~OS zxҏw@j~nAoު ʵ#'9ЃrOB)z lxEwޛޟr?ݱ#mH~[sVPo5jm۸ofn=ν8^1 Q\gBQ80xF)tkY[P_/ԡ\8ߌKkK__\;*s.QB0ƒ L {\οa\;N6?믫 g^Lur{l eƒAp<3îo56Vom'l6}ze׸p9 }ÒܒY@ - p}~pmd9M96,Ћ}2cuA#XvmaͱX<'!)wD Lq M 2@l:zg5JaN>2k?(0 endstream endobj 198 0 obj 11427 endobj 199 0 obj <> endobj 200 0 obj <> stream x]M0>ncJ ġ*C#$ yVx<3<6|{~ɿc{ 9C7x`NV^)cq[0ǺqS_.p1O?Ǹ>ާWa1E^.c\]s,][cnSӆ.!bm~o,Yr:?9ژZ\,;S3ǂK bW}0^_oo-/+;3k++8X l0+'+O7䏳X;'مq} +=⌲"nnBRބ^_j>+uiOQN8$܏_ӥ{so=]z?K}ubiGBPgSiP@}> endstream endobj 201 0 obj <> endobj 202 0 obj <> stream xz}|Ss[i6o4-%}4@ER mhRiܤ(1&NP!|e/tn?tNn?~}rS :w{sssܶ =%._xBNYmkb"[N!ƒ0[+:q%BBTVvkiy?!Ou|'儌ʘځ*B$];bE 41 .TYqHn_WG/pӗCn2iRYG1 w$EG21rRk3:!+h2[crlyc?Eo$&>H2|N]y&B:F^$ɾH[]|*KU$&ۿA"{Ƚ6 \]GĕO`JGzQx|<%'0fƝgͼn$wp{!Hv +Kr&$@B%;cd=fo~y5&Ar;zRMM^b! 15WUgok__F F-9؀zq}%榅 ny~MjnTW͝3]9놙Ϙ>JK&/,ȗ9VAԦi*XH8[ <>Z֎j}bB$_\lnNw= zq&)/!Ux44#J\!hqp XnE/=m47V\DLG(>A Y@fB>j?^\]es8ER%Td\WQbPVl{?'+Z~ﻵ9pn/[{oOdŝERUu)K]0N%!%sۑΟS0Bs"qfn4;A[z$;9ܳBRo_FFoMQq}k*[,g7,m3ÇlO#4 -pfvMV Мdq:qU(&ғLoзͽq`_Fo{V`t&;F39,8KyEj?(B4=Fҫ/_m@!K.YNTݪ鰢 ]L渻 OXu_Y)ÂUԙR)7JsF+UllSiq8imSfKi^սUIdYRC5<7Eu)[%3bV6V]l9n/z+5rء&hpxi,lmj4OSIdq\A5bf[R `\]EF="DҜ x+b3HՈOU /NvO3h-Z+1iBr2w̐HRcLʍ۶ZYj).6O }nڸY=r[6a:ۗgE)2R@jo{MHrAm'P:vIɅ Bn KR)nq$Gdxڭqg0Z2bShhևPIӸmIp'5te%G3NO\h|aX;xT~9PmF8HM,TDȈI9tiI U`ރKb^yS^,*Q؉cQ,ӥ Y0}epM.v4|4_rs7u(+8FN0<DZƮ=%VR4*ur .pazV&^{O?wWeu m>4wx0yǦ_޳eu{\B{޳ewڛ0Ly,<+iJWshHNZ-7L|׬҈i s! s8sa/¹W\yer#@à we,Y6n޽pagxݑǘCL9vI|SCϱ0dY䞜G23uA'KYLBYZlN5̇p>a8?"Wrj4ZHFk叭?2| sLxU ;u,#XKV/gM_{컯{AϟlV"R ,կtt)jҊ3g3rb]D/sLjQ[nzV7-^.'DG_S 'g*QeXAO\@wXozf?/~<ǎ`|s M|{ (:& xQu TXg6yZO~]9`K7`[+]F/ǔ&LMb";laLt4v`قLvKb`akQ,d9k`Q]߂:d=LŽ_cq/-eV 붠ecGU rOV=…&r[Le)R_'Ǟش~=6=ه/2XTFcN8)WcNi ո:&˘{̠yi+!&UިuerIe;^U_~jgmj2 A؛w qhbZ#jrL[ dDgb; Np:ℳNx O:atB SjnC[|78a`se'\Gv9!2pNRq*'L$\xeJÙ]R-.\~?+IQN`̝Nh5rCJ@^-#ר,2B!^p,usbNiל#ǩdQ8zQX촽E5C?# ]bUW둷Jeڞ'n co3!k}Vi+jz+Yu -=[g?>}qݾ?ƌM|ݿ LYBooHhiq_VØ1,/fICt%b*c+36m1/L˧//QqQ'{Jgʵi YZv%MXH\,"/")"@Hg=1VԑUX % BWY,{|ϱײ +6>_y׹?m^+[w͛=on_ܰp>g܄w=|6c7Ֆ̜TM>9fO;t:QZ:Re,1VQcn$F46'*D08DĊ'N&&p{{NaTbbfɭh izNC%jרtɹd6Jg;A5  agEzOlkO{,cChnlN,ܸ߈2uVb7),0p&dKB'x!TB a G~ݘ唄q/G>i2y2!=ȿ1pm랭7M=Oxg7w,IK|>|->t w8*6qj L@@50@\{5У 8O;5PGI_k͑MyMw1^| r3.p/p= L6[XZeDwՐ6٬ZVeZcv3,4 S͐o83\2'fx G̰ pOrb.!>4fSfQT.*.hE)q~CDp"fVf>Uj%kTF] e\}xwi?> 63\ ect͔ZiFob[WkkWwWpHŅ?p-_fp-ˁ܁'+\ $v|&͖]5$~y*/OǙʰpX.mlru'?آ9cOO©ݘPb 6SJB\uBNsQAf:y^ Exoe0d),ێ7&2y`8-ی!4)$ !{w9f3fcw+w_??$>RRUki妵d6BzRJnE`?RBȞGRvfR`yU`d , _Ud=9j"֐Lp+pN'̉)a~ZR'SQ48:+0lB*0Kp#c ̓\[ , % ֐\~@Ә_8LST3ȭ/XKn,PL2EBUpe0\~_'"1qBDlrxc(3 E¡/ uis+_HV2?"d};}Ѷ@?k. D2\^RVV2 `T􉱈EV#h,Ad[l*i,}@wLuŅ#ۃml Db>d:PVGQM^-Z2([4k;X, uEq-lv$*v:ĵD+bx>Kwwh \(B#hG{@$خc@,luvCuq t`C^y$)‘^q-t:>oE3C  E1b]\: P7οˆj%  u D)ww ʎ;q. zXG(}C1}~? j[%-K)kPJW# (-]vmOJ:%~-.P\tuGw^[M]+oq|.rP$rrde 4c0D%:|REd%1דo} u$B:+ bB7"W8_s aQ!MJFi,5t~BPBʘV ud4⨛D鼕d5CوiCL7ʒgoEFe)An7K "EVQe|Bx^|%D PE#?*nBFUOgVպ)¯YWlmԋ)6*[=oC[G~:/(U}\4R5oxy98*Jl6] G-֢&Q{l9+0o\GTt'I-9E3J5D>vh!R>Bj!?\B$W]dZ#{G~8+HFK"ņQS+PdGs}$1 (QmSV+5 SL1 w@b VbZ#RD'7:Jv7Oq\Jw j+4ʒSiƾ61eȏ¹גYW, )´]hVtи CvF\iS2Dѹ`3==N{˅ ݅ -v\8|O?~>Ykgc<\_>-'Mӟ4}Bp,M6ޱЇMsxB ?`~OOd_8 *OT;:O!|dߑVwv>g@ uG+^8wƙx?>gKWf=ziʧOBL݁/>=pa톗vnO,v. vŗ=~y;zv0;w@L-g n͛&cJ{7iTs4emR&ފoL/]Rc_YM<+g:Y`gN[,ao` < 30#kPxYs&}?]Wkmq:]NН TcCNξNgIڸ~i 姻aI\'MK6|ǻev2'6^oe}^Fcj|A 13!G$B"pbIA4C|#Z(NE$\`9 G,D4(',g]N endstream endobj 203 0 obj 8176 endobj 204 0 obj <> endobj 205 0 obj <> stream x]Mn0Ft!؉R$Qi@`H YpzfVl7<1Ta _ְ~0y d,]+zccgu^`L?eYyqA:pGQu} F0<ScBJm˺Ղi-Y:mӂk,re%G.}8_*}i%23k8>#x?BNSdE dL{fs`>G#9"Ļ=!,zʈY!ƞc쯰d%k쯱dcd״z쯨A8ϨE{sΏ.';Nc|ѱ endstream endobj 206 0 obj <> endobj 207 0 obj <> endobj 208 0 obj <> /ExtGState<> /Shading<> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 209 0 obj <> endobj 210 0 obj < /Dest[1 0 R/XYZ 0 842 0]/Parent 209 0 R>> endobj 154 0 obj <> endobj 211 0 obj <> /Outlines 209 0 R >> endobj 212 0 obj < /Subject /Keywords /Creator /Producer /CreationDate(D:20170611105330+02'00')>> endobj xref 0 213 0000000000 65535 f 0000490848 00000 n 0000000019 00000 n 0000128529 00000 n 0000443014 00000 n 0000450840 00000 n 0000451087 00000 n 0000451127 00000 n 0000451356 00000 n 0000451396 00000 n 0000451648 00000 n 0000451689 00000 n 0000451920 00000 n 0000424534 00000 n 0000405661 00000 n 0000384112 00000 n 0000451961 00000 n 0000452213 00000 n 0000452254 00000 n 0000452487 00000 n 0000323712 00000 n 0000452528 00000 n 0000452778 00000 n 0000452819 00000 n 0000453046 00000 n 0000453087 00000 n 0000453341 00000 n 0000453382 00000 n 0000453613 00000 n 0000453654 00000 n 0000456387 00000 n 0000456428 00000 n 0000456660 00000 n 0000292436 00000 n 0000467658 00000 n 0000467310 00000 n 0000466962 00000 n 0000466614 00000 n 0000466266 00000 n 0000465918 00000 n 0000465570 00000 n 0000465222 00000 n 0000464874 00000 n 0000464526 00000 n 0000464178 00000 n 0000463830 00000 n 0000463482 00000 n 0000463134 00000 n 0000462786 00000 n 0000462438 00000 n 0000462090 00000 n 0000461742 00000 n 0000461394 00000 n 0000461045 00000 n 0000460696 00000 n 0000456701 00000 n 0000456966 00000 n 0000457007 00000 n 0000457260 00000 n 0000457301 00000 n 0000457527 00000 n 0000260224 00000 n 0000253538 00000 n 0000226978 00000 n 0000219543 00000 n 0000457568 00000 n 0000458114 00000 n 0000212100 00000 n 0000458155 00000 n 0000458695 00000 n 0000204685 00000 n 0000458736 00000 n 0000459282 00000 n 0000197278 00000 n 0000459323 00000 n 0000459872 00000 n 0000189844 00000 n 0000459913 00000 n 0000460455 00000 n 0000183508 00000 n 0000176177 00000 n 0000169870 00000 n 0000163207 00000 n 0000156520 00000 n 0000149876 00000 n 0000143200 00000 n 0000135875 00000 n 0000128552 00000 n 0000129416 00000 n 0000129437 00000 n 0000135853 00000 n 0000136740 00000 n 0000136761 00000 n 0000143178 00000 n 0000144039 00000 n 0000144060 00000 n 0000149854 00000 n 0000150714 00000 n 0000150735 00000 n 0000156498 00000 n 0000157363 00000 n 0000157385 00000 n 0000163184 00000 n 0000164048 00000 n 0000164070 00000 n 0000169847 00000 n 0000170683 00000 n 0000170705 00000 n 0000176154 00000 n 0000177044 00000 n 0000177066 00000 n 0000183485 00000 n 0000184321 00000 n 0000184343 00000 n 0000189821 00000 n 0000190685 00000 n 0000190707 00000 n 0000197255 00000 n 0000198118 00000 n 0000198140 00000 n 0000204662 00000 n 0000205526 00000 n 0000205548 00000 n 0000212077 00000 n 0000212943 00000 n 0000212965 00000 n 0000219520 00000 n 0000220384 00000 n 0000220406 00000 n 0000226955 00000 n 0000232746 00000 n 0000232769 00000 n 0000253514 00000 n 0000254381 00000 n 0000254403 00000 n 0000260201 00000 n 0000268998 00000 n 0000269021 00000 n 0000292412 00000 n 0000295375 00000 n 0000295398 00000 n 0000323688 00000 n 0000383503 00000 n 0000383527 00000 n 0000384090 00000 n 0000389041 00000 n 0000389064 00000 n 0000405637 00000 n 0000407971 00000 n 0000407994 00000 n 0000424510 00000 n 0000426808 00000 n 0000426831 00000 n 0000442990 00000 n 0000491164 00000 n 0000460496 00000 n 0000460675 00000 n 0000460845 00000 n 0000461024 00000 n 0000461194 00000 n 0000461373 00000 n 0000461542 00000 n 0000461721 00000 n 0000461890 00000 n 0000462069 00000 n 0000462238 00000 n 0000462417 00000 n 0000462586 00000 n 0000462765 00000 n 0000462934 00000 n 0000463113 00000 n 0000463282 00000 n 0000463461 00000 n 0000463630 00000 n 0000463809 00000 n 0000463978 00000 n 0000464157 00000 n 0000464326 00000 n 0000464505 00000 n 0000464674 00000 n 0000464853 00000 n 0000465022 00000 n 0000465201 00000 n 0000465370 00000 n 0000465549 00000 n 0000465718 00000 n 0000465897 00000 n 0000466066 00000 n 0000466245 00000 n 0000466414 00000 n 0000466593 00000 n 0000466762 00000 n 0000466941 00000 n 0000467110 00000 n 0000467289 00000 n 0000467458 00000 n 0000467637 00000 n 0000467806 00000 n 0000479322 00000 n 0000479346 00000 n 0000479551 00000 n 0000480089 00000 n 0000480480 00000 n 0000488745 00000 n 0000488768 00000 n 0000488966 00000 n 0000489394 00000 n 0000489679 00000 n 0000489725 00000 n 0000490994 00000 n 0000491053 00000 n 0000491266 00000 n 0000491436 00000 n trailer < <5A928D0D90F44074BE0DB10DE8B922D3> ] /DocChecksum /BF5360A62AAE3F1D969955276C451241 >> startxref 492172 %%EOF O-Saft-19.01.19/docs/o-saft-2.pdf000066400000000000000000015346041342117255600160430ustar00rootroot00000000000000%PDF-1.4 %äüöß 2 0 obj <> stream x-; S2O$U@TBc*kЯߋn3~VĺIr7# F^?WRKǿ{p叭?\zZl~gK[':WRc1}J?ַ~Wޖ.O7n+/Jo,ݏ?rczqPmvއ]O~u]>wtzoc3F$bً_Wy8y] ⱛQGak{_:phb %yy&} {ϸrӁ~@7RÅ܇5,΃ 7@qyyԺ (4z!oia\ŗd;u@O&ߺ] #Ӂ3*85oHmOwQgC}'o\+HokU-/n% *pĽ~vPI` [Hȍƣe(w/wyasH^*?|h@ _'C qn-X*\{q~;6{yْ8 =r sFr< >yd \HQ͑~ФtRYHfTpv>zTc45Tu¦/7Q\JOQ^NkxWodH* ą)EX#T{M.ŵ9>1EJ]F 0ܿ;+qg¥&RkfҵRܥ  Łdl'\PA.w.>N T/)-,1h NM8i{p/ ,c=>/OK ˧&Fp36HFjv xMX^j=KtRFP6qXME 0_㛱8Q\[.앟Ii@ރHŵ^UoߩG/ )ߚ:ŵɈwƱanSɸ d p˻6(x앞0peTZ!AL|2;R,&( SCNNjW^ beH{|RfwM86ӿ4 Oay6 DM 4cdS6Yz(ҠhR=y%L8 G3E2ipcRŊ;n=Gby7LJ{dy Qp&0) e,&\ߤH;Kpyo\^-0vH=>9=t9e06=ħ}@ Kfl>B.-܄\_]YM|wϨwizih~ķ÷o|m0>)^ ~cĂ@,p#B>->z/"./&%}|Q,cqﭼ1T=>5:i} 7 oik%$}^ 0+Dڏ_ Mԁfl%}h2&z8phܭ~ .]3Z#&^^ , 0 MtR5='q#5//q&W" փo1mI;$>mݟkr,{qq(/!(A2hDwmYZ^zӹG$pY#<| oԺ|"Q cs/KFR3K0GOk`HȰy'/SC|8K#iqtއ4o gw29oF)M 嗓u2wgHilLrF*%4oJRA<2z8XwXw}xEB,.Ƃe=+0VdPpXcNqJYF= AT#E`/RڽF)ǷLR3>]!aĹTsy]O8V>8 a9[AcP ĥ _D&Rbzg)8{g2$AGi[%yD(XMjs ɦ $m/Ui^~ZCa &'#oA|TK\fxA4 G2 ea=2xR Ʒ3Bj='^2G.M i;AJNF^>QB?azyNO#A{ ߠDia#r=3;3(Q1k|gPϤ/* ,#&X06ls/w#^y`k2tX9M$3md|, @fv~1Oy`##y`5Mv /?mN, 1JF_CQCV'@36IDI ŋ/QʥT8p'xb-=ccdN9k{ kߌOzOR`lGF qО9SJ/úa G,(cq]#^^luIԼhj/}(Fw$\c,N=kdod062ld͹odž7'2±PָC(X9C+|{W#InKdeށ痆5d~75.)M eD|`Cp%3bl>hKc=p/5PddRz#|73@7x =0N7Nηy4H{lC 9Ĭ6a} XCSSƤġ6W ǝij> 0#(tG4V';7V#\(/U  ǼɘBL@aU ̭6tvE2OD۽2mr2P*s+CG]J?[ĭa􁯼On)/Tpa4ͽLԥkA+erx0&E.5DBSA2ZQȝ|4.q7,C 6Li,2ͽs$@^dX\J@FX*$օԍղXi[x@fXn [h 3b~b [hPwY|c͝xs'\#âp?xx!5^bMy;](Nj<\θ[ AaejoFO.|R~fة9> uNIƩ O Q Kֆ(З3v:֖W8cs/ 5>~5Bh2\BW@3s2 e~+ mJC!yB2P|xΐ?ɍG`%r4! ): ŋit9,0y; DƠ%!1+A;\>aųT•Lx<'uGX@Q. ʎ?'NG5cWatj88 ^0j [m@!4ѿl\X܋FǷ{,d:- yXpz-<<N*j,7 /(bV\tx%D|i;Ra=:d+jas̀0 :@Dƫ@: lnar'+zC0N<:|Dc𸓎W,3XţƩ aV@0:z@ 1Bnp^B}b\0٬(s I ez,q'%>Yms"U gx܈IkbGWOЌyriAcX]#00j }T%8>P3h'aq/+}'yBᳬ"r-r$Zaq+*U]ߐ&z4lnƥjqEDfU\ҵ-a#^`j VD]-@G.ȓww'4qJө\I]ĦkDY 4V';)6r!>(uFSBƫ@YS@ 1\Cp+Kn Fp%?5^B Пn9-<ħ9?W!QwO\&Ԇ;Hep˄h9 LQD7.Y/jux(7-aж\!?zj"Kn*'$B@0&7BR#(!x>|@3VbIY\Oas/G5>%*E0L RaaBu|zN`X}`xBxg#ӻ8ZCc TWB]^b36+y*T}Ʉ~عFF EBީd}Fj܉"7J_!4v]q'܄f<hAdN|G;\cIj|c/7 Am|burݿ\2b )4 ;]*r`x +gF{m)xZ>mqM-,xh&Sӛflթg@xmfl:ugNJK\zNuطBdTMءP)T{aiy;nT2y T xս{-1ό;2ab{qiŠXd2yUՌguiW=e\gNJRwC!~'M++ :~J8~f'*fJ+iA0etqoAKsP9-}:E7E5n !^P{qZ]ch(9 S{F`MDcu"IU4)D7u%nb;}3}7Үqyd: өrOJltdż^s92 sjuY(L\hX'PFf r_$q. 9ʵ+V}Z WR+yQV/LՉxw'aIjPB_FZ*C[pmA zSt[54A*A6'a wUr04M;0HܩV%"DWT۫~{A\6pXŁ+,сxU.-mA2&?kң Ae?8FGı8r3Bۏ#^@ܭ d~PmHQ!N*:s2 U3H@Hr8ŽFu!5Nj~̝<&x V3W}١j6wJUlNJX8r{`j^];*zґe* H^ 0kfتH.&fvZ*&?JPκTV'ڴyQEfpB'4|EK)] *NvʿtgaJđ~,26ΡO-t(8I&= UoePS6P"$>'OA^7pfaAT?04:*nN{-?2>Sa5#fl>',vTI}9MѱuG^n^֗Y( HSdXBE"dRxr:M{39чӌE2/DRLV&ԴW"~iF,0K036ݔa9|v~S(@:a"pθ&r,"'{Xb e(^u*B3H'skmړC2NJhFTǚ.iX+O3z,fP`>nduMp?Eό^Yu`i͵rS#Y>E4= <̟;uCț6(̐N,"yeQ琏\cq:ii*e_,b wjӌ>˟Hơ2ʇ3{SSr# MiA = 6T&)TV?~ɉUM\2JX8jTOΔ1A>q*2=DdIЪwM {H?^o?_/7mav_/k_ſ:wJ/B2!uȠPu$@.]t7oyiݺщEWVrk9jЍ^Ϻ3\q] IG5'ӵ>54LwtGrl:NH3|;٩/^[h|gHZW}܉j/ 3 ~uO wWXq7f8%c jw ! !1of|#>M}/= /O,X7gO (+VWת/8ן=?kګ+Rj<9`͎Xp.WLf;PQѫL};@&B =L͗*l+l0ξ`8]l Rwz[^-mAh ;6w/.{  B/v 8_`^2"Pk}˰'p fw ; -h!٫ EGBؾfS+.KXۅ^zyt ^#52i= P׬-Y3V__! س -x]#@:jAh5 1;zm+L&Bk @p\v  xW+?7(VVbm {[B2`b3aB~g/XG! !䁐+i||yimRLeB޸itw}Aˢh^^L&f+5]VHONz@ Ia*k__ ho"4kG{vc YzoT2aX6X;x~NSr!&oQr+ oT*ѫ__ 0g-땂Fg̈um߲dTSs @oYA*i__`T8 6F;:M @^19} @[PӶ^_ g-3T9+~gс&&@oX)i__`>oQyW#C|Ƶ}|򶿾@m8eqN-݋yò O^8+UlW9쯯[ڂfwG ²*@HʦWg!ki}HSQyyU  "ZՕ_D_;Rb]Yͦ;d e3/k٬y溿#`gYV>^嶿 "TbCTӲmAh B3^w g_ *n}pAXʲZh1]k9[P ²ZlwW9ۥbbi(=2gڷA>H,DJ__! gfb>QkJ&1e, J__ ܷ -x]_! g53R f_ T*mGO].+uY&xUMZV{jq_g}X)ީE_\4%?s꣚ȍ-][5E1DB N3ۼE;EDtIEʩ#`κ? ;$dU2{p%76{e2@d"K8R`λS9Nhn$*V!EVtJ1pb"$q! FƆEP' ؅cmh6iԤ9!_NC#-dq/ڤf\N{"3vZ:hpVG鶇D4wJٮ2n&$ܩtF&frm;[Kc<@9 ʥ;˕]r--0ry&HrZnIiDs$ܦx-s [qdžGEX&qWS$V1XqT784̓xǍYW15G5df 7^%dSLcw2/[;{)Ԙ#!%nb[QrBBp+WFn a:jwD9(.s^&yDBQg&Tc''BSaD4fnIȶ}4uV*$%UHH[6MxMS8( ;uVn̈́ĝ8jw9[|ZmvBh R$!r6G_5;}mrP%ERYx'n=NBI.ڰ Ip>7' % ǦB{t7_aw,A pXG╉7lh<:;T?apa+3)ytl2)~u;z!& ({__4ݬQOb#Ӎ AXHd dzLDl1wGGŒc{muEfRpR`&0+dRlè;} iwD9*4`Ϋ)b P0;A94CbZ±lĎB0DDŽċ WC1ExO5bēkV'{%Tc%P%h?8V ,&恎 m)b,(Lb_aw,Q˴ѫZ%0HUW 6k0~A~IL`!ʨv N;SK]D (PU89}akwD9j*FVӈ ;A90A$96ak%%ӊ)e_-6W6%MC{oQUlwȨK6X恾 CYxʗ&n T'}q!Bl30e"LD4VGIV 2t&l3-&MU';A90Llw 2C$$`.kwD9(")Z|gFyō޶9px1iljuqP=a|=I!)axE*oZ1' VZ¡kBvRE?f%OH~w)UQx5*0VA*ߔ4(=|eNC)*(mdxJSڃI iw9(pEbͼ[h6";ju8B%:qJ  Tllju8QC\tW#d <]VR5f|M(cH ^~n3 3ŸRN!5; :;Ėя*) f:TGC˅ó%1;㨞 ,G*(`|d*wd [1KoL̕(FljgT[%ΟgC kvVվkK6ViUUyx`tWA(#k=2A3r2fb(_QȒ (t_̌GZOg`xAd3y]>CLUW?Fa -bi뮌ߺC<|9Cl{PÈ1ofx*R#S+VW^we"Pf?Pogͽjpxz ,aF雙jtib`pĘKӠ}Q^YYj-q2>kМnj12ĤP]\±JDhLΈWDWkW{ @t3LnUWƧ_zH!7ɢ-G^y}"6t|E4V'jzE2S] NFT43] G:jsɸ@; `&h,[q:C'lL^-[q 622,ҹU\XrIzI5BZ:G.)jɄD^seffR-c2^♶zbO,{:u4vfgꭌO, F !DQar2^eUG  ,x˽jx5~Ѱ r2^: ` Ng+esDTWm%H*hD94vTWoݲ% QȖ-{Ik?U[ XؓTI" [U0TYWWJ+.X/sbZ>Z+n{^:0>GJQn1-{ŕ4J8ONj+sTDuWoMH3D^ueY#YFgɭjz9i`Tz i2q2>kkXSБųL25O0L8[RG[ yT9$\.w+ynD G8CVke|"綳c`r2~#vQ!X9lV+VT勐0UY]AX'.S^9xTX$qngͽTn ϭʸ Y9:+ P79 \!-[qZFјc#Št jꬌ[BEZ2:+uJA 6,MX %Y{;q #؍,j2n T=%PqWHKVge2T(5*wJSp-q2.`8pfkW )hxɭX`{&xijLx~s:ó\V+֯\m3ߊhܩ#c 3@KXK\pk!0-{P|tpb+(H’qŴ|UV\wBg͕jBS& 7dqhG8CNae\h 7Fƭ7t+Y. +(o0aZ>G(8ny͝aZ>:+㷣 EyD^geuOD2Y ?fЃ K ,[ ;MwR^_ev $Dt?olMZ6 + U/:Gb^A> gd qE\nUkǐOB㑿[#PJF ꠴2~;lh {3e2>;cIʕh {*OKʐxTYYk~-VUVȧz0p7lii8k+CLǪ생,?dLգ>d *s漸K*jZ}mrኙl|ávY3qM-lԝneE:EI iHǃt,:HF$|q=l97qqD[VD<>a@8FpB:;Kd,:zk#Y!3({ qLUkZrY&u>4WOczm"b1lqDx H<43MqZ=m9&\<1M2rW˚K-[^#㉞g# Y ".e[^"#ɒ'.8bz9ȶ7A( 'f0U׀ߥlkVd=x8̕av6 >H/Mw\Js]4MzRhdok&bcu ك|H .er*5Bz}t^n(7AМ=a.@M-$Yh4/ָ$ac 9V[A}+0dׅxǍh1q8 G28kM2[vЮnlv@3zcw˷Bd@Ed|2i5 ݽ *eORpMDS;L!]ܸ Ewe,Qg;U1f̓TYЮ숄*vX=mT.& ΢ʚHj6 a *1W,W]I\ʶxr@ޡTDY\y7 tf73i@5 v/J9hAV[WшSޱRY@[<FevJdg鲐lDr=QΛ/ Ӥ^492(఺KŃ^Tfl#X1`^\m;aa7-%jDuw%bbQR&DHn˶j "6ܝv'ʪx&:@!kRC:`Ӡr+9]'|CS ޴:V[rW,~B˱-Ri@M^*G߈i.ױ|OEA: NzY@iދHQ/@YuPm͙p)j3וY LD6m$n-S1gVã"B7}P0! Q+vc?ce]hBhսt0a^WCpLP[ָ AmJwhLm]pp^b(7G`vac,V \`ؐ웣^fX!Qtr5Ǖ|{-CuAQ])FG7[dװJQ"kY N{kPySQX*q*ս|[h4*FRsAqڝv".Jܛ;t*25+6l#zwېURˍ]I1P05śfںz%P4+w8*ܴH? Nr鿹˵T9NubgNEv d(n*RuJ%Bɼn).LeJZ&2$P4y`Xg`e*C7¬0 UKC'JP4lDLqڱk{Pd쟰xUyCk{˿?__w^VCE䤯 9.kI?xGыHf&c]rZ3k՚Y ~.,`ጿZ9TE:}u]GzW\輼|p&l|ʯ;[/e)GYʑrث&JŻ,ev://6$y7kcPv://[Ng˂;_wW(;Wd[r@+%.eKYRpV C)'J6wo\rꎜ)yx7fqY{͗weQ-EiKQ鿬ݽQETiwo[ҮrP}y9px[ܩ_rB٩&JŻ۲{՗S&JŻ7Nޞ F^Jz_)&B]JQRC)ʯqb4ZRU_݋슲l nxm#3v'E왑:1-~]a/d q)H/׻ G]N$-% KIYIε_8 oLůֻC?~ P0wm;b=$n_v]^4\bnmK1ڇb`8`n7zwQ Y'B 4N_H9Q=n2vɌbYR$ {Wd˲P2B/׻  JZFieFW*ɔEN(>ﴌPB 4$[;vjɌd6;QR`;dcwTQa^Dee_w({ELb~j:^)|*v !gL^ C(َ p7.S:cwSA8QR%ێ+à<(4/SrB) ~(Ŕr,`MN7ގpeA6 |1L؊?-\(Ҝi)FZlk*: Ml?~RtRuO[LŻwB L-eYfm^!%$߶}(^#۲NN'[ņ(y7z[cw6h.˺LߌݭV  R,˺LߌQ̵SyI1AR,%)%+Ơ "| nR$;d!ٯl[B.(X['HÅD.23v4!R%lzOUcťy)A^J.[ۑ(ږhe]Kpm:@C*2o3v'U5ۜ#l&pLیݭj;Ą"_[r)ǂ&JXLQe [Xʒ F2>Rp [4`wïY{Xز@ N׬m꯰m)F[QbOƺ'S gͪ-8=?Ƃl9 Fx~]Kv7g/ vf({XT JZʒU(y)JZΊr ./%KIRldz 랜A1a_;gv i~II vf5dݓ),ކ-e"lYR;2/׻+{e1߸ldz$ >AD&4ku^Id0Rdw뿮4dW[Rm)E]JQ?b#{;2vP;u{ Yb "P%]b! aN:J#`Czwב0:J^ʒصkw# !-eJ i)K:+ˉ{hK9Rl|z( a͖#nK9R݉G^^]'Ef<]mre`~*/跼upԢ7puj^ZN}Ps9aw/.DE~s дr">޺gTo" w δ2vw&qnDW;X\oߎgNRC V1ݽuH1b;nxnu Z{WZCԗH4SGfb-Xn0&?fcꔩWh88N@G,zL2`z-]eNF41ŖTqkOxx%@4VZ ~+r' (Y'I1$ez֒Q Oϓcgx'OE4vOZ2(؎ _ISB❄i=PkɃQ<9('$IH1ݽZKA[@PPj$_'{֊EH8-pjWTNA V+66(agX=Qjz^I+GY${1(z 9tmܟowKWau:hd2YUPSx2rLI؝hJ- 6Kg =UJTDc@*}Bvve J$邭HbH|6{rlIT q!Ig,w!p$ 8 0Po 2Qdm&:K WS~1D71' CL=@#El=g~ELFRճR 14v'({ 2bvTg ;B{h(<[ fBO+x%Zh$A%a9 }B%5z# ۴{ȒLC ݗ;i4͋DD?=|&jPSfZ`MN曊8uubP $ ;Q*{Ŋ, 8j7D'ۅ|%^r|hE8xEv-O4ݽK[(IBQ񊛀Jwi[ S!ˀvWNT`MBZQCAJ[Z*NqzJ,r*ť>bΔgN NuXZ]u.G0  SytVTXE~Jr+-& Y힨dxW5lĖfĹfh"}U%}=p}+q0`%4$tIl:W&{*,uD uI1CQ%?k@e$Xʏ~x7m+/(%F ymXx?dXoڠsF^SbvN'+SuuC xĞH:i BTNNn"?Jr`_n\G=\Y]*X2k(`4"z8N0+YWHz-+3 y֔5m0\ɲR{(?wpI=N1eO,L0cJ$~T6έ޳js>=qO53. խފrҨdiicTDXm{ɳ߅ @X1>,j]$:D^1TW ΐ$Ha&g*UBā紺U\uNZR] W͸sZ*z1T 5(1{Y[ C"3Ș+ʸF맜$ Anci譸dD@ P^hBPyl]#3J+d~WQAH\s1vV/ֲ3W+fvag 9ݽʸ)7N)`1MC^k5`^B\bqNjXx #P`ݕxtZ qYE䞍hOm 3&v'({U11"։hib-0++Wr!HSo/<3Bj"7Ci:i*f[s UgLHz0ͭCa6 :%f 2aؤg.` NO71bnnY'r\+;0 Դ(ʴLtcD )B-L`aKfe"JB02ǰPGR\1wok r-f5tn,Vdt LS(,*bZx Gj אg#.is2+ V5MERT.9:^Y*;>[:HTMI=̊z"*d){d5Mq=p8].@]UnxYxs/Z& |~1Kqp@V.Ы ]֫7* ꁄ Vzz:(Iܦ"Z)ظpy)܄3v2\!^\Ҵƛ~j/JdХ:̓aʡȦLuL% ޖ%I/t !Hp@v2.訚1ёxhN{!iE"wXoh h\`W/A: mkJT s+傄2[`IQLJak'r$B…@Zm,{,26TM"X^cI A5Vԕ 0j TZ%R^ȅDUx< ,j-Av\WX$G-@Ń|ꑈ N{*(FPKCeʣ3m*3xjBS Mh`Y ,F1tmPAV$\৫HZdG8ս ƥx!X!T QӊpKjXIsGB iN@2.lasy<AVd\'^;F6M~Q0N(rEmt*B*YR Z^ԝQBZX*R ^~ XOZtaW".$ymȀzL8 nIV$\פY!oCnq ^n 䭲!d&o=oal~EmmScz " r4 ##ʫaqj<"sG&Bd"7oGAȖ\3igd\OX%]WDgeސ?-^ߝ~7m&kE_/[_-5e[/}W_?Zwƽ}mWS^G;_Γs? ? ?.^.Y({DaЗ䣎P/D^>|L;~\q)#WT z#ݾw=r5Hٿi^U}6c3c dIɤ CPīU_^O0v'PeF?<M\''.M#QM# V)H C,+#ܝ(LPG}D֏UNaezǴ#8"8NB4cz*BIE)Гs,I%g]HOzF/Jzg R80@C09]zwe W: % 7!%H3:$)+ɥeマ*~Vk"l}#C+ πj{d+E o_{Iq<;V%!LI}>.ڔ XKszO/D룖 PEVA#'ۤv*|ZE4>〣2mD׼cD"h>8AA ڄ4v@T)෣;1q'P4vG.ġMPlrr4]``mbNp_aIrǐ$z4hcdNPd8Jx(0,@AɿH5JdkL7|4VzP!{<TUZ@`a/lwۖq#JAiSa{]+O=*ﯗ;zgg9 E;a3ǡålBp +Uv\3Z╛ѤE|ر'Ⱊ8 pqK'xͣ1Fǘv6#p/Fw< 9%S#Hǽ R+;AA4dW79MP5Zje@kt[cuB"Hݒ^;Q疕d1`"F N-YS0Ũgjk%ȯQ_1]) 1%p2߱2QF/up󯗵1/A9>x"nz4ĴKVDcuR I  ''I)"$OD<5WUw,cΈԁ&ٴ6RmKe/cZ<]HyoI'7b/I,?Mk$H~8ٱخ> TAyM/6ʂaHLNC/7c}\_db q&:jxbH HEvv@(_`֖b|&E'kX}`VP;? 1K!EVĉi(ԃ: J'g#<7䀠-G13)("N= :)"g >pb$ģ@8$ʝTUxE &rŮOLcwD<2ħ7̼`xJo$4O0[Z^SbOvZWd "l{ǐq3.AN*EX^9ZBmDqڝ@50w\Sǰ DP"Ϋ>sHKB"[Wi"Hs|`CHD|*|nVoì1\zs|38X DkuQ\'/x5840Ĝ<3[|qK ǹ0`qloڌ7L^ra!!UL3&.L‘R5.$ ( ;(x A84äO9 kQ\'U~Y&30Nf?kp< 'Y`cڙB ?@u?"ps5;WI:WzD,R`Z# 3pH.@Iɝ<ceq_'^+5#/s8Cn.WugXlM(ĩAZ(tju2#_rjX}Pj yxe̵RSVkG(i0G]p8 >uzF0fe۸3hF Zl'ru5z/ǭ2x3R^HVC3,n $%"6Gւ̵Ber_1" ïSQ C-@d>܆$͂Y:z]"@_3JW2"Q{U04fhhW#ak=71 ^l \b޸"Z6]@r4dCS㴸2e rR&ܰ(a¬)-D^ށj@l"+b77/(uD`(/|~W'L:ޠ"UOMcBQc<|tlAƯ&P˂(ϭ:8L^?Q{yg!(Ҵ9A邓goHkUp>Ҷ"w`5 ]X{MpBl#hxqgxKVoewF2>uU<*F^0&cE4vTmBֽd4vT/P~l1Tlf&s,tOD3ܫc;@wJ X}PzO]0?^3"V,1'^Pf3VT+0$N D^xS30kŽx:4@Z`:T]T|qA3V+1^ ki@ Lҥ86< kPc:+*27,ZkZ%r۔m0z+c@ lOt!Y6Z`V@#Z-#N+&D=6qvv4v` x?k#d+0zҺ!"-LnrDb c={} E'*`Qy=2cwAq/ ׭xEebJbJ`(XSqA15pQD+Gb/s1} i_?FTISwjka unuUdu7ju^/ Z&Bw& %t%GPS#PqFF@;hNj[!A]V hAh+0(e~C\n֫`u%޵g\ch6y>Fxi/Pʂ"u^h0pkLH?4SG*wfTH`2y(KʈO7 d\t5dkڧ@M;LV l٠+{nGLem_E) v=$i^.6i#W[@LnA _'J؍mf^ztlAoU/P6>FxinUm%HY@dXݪNebC%36F._dK4n8._]"ȭ#}T[p< ;7,Oj`fB]Ŷ8ϯi2V۷$Aþ``qN/Nfq,[-pu_$_{>b{5 XElnӫb5i~սړ`,xg xUZ] knؙ8REzJ;Ii&n-Yx=^/a oK!ߗ sZ}e5{ mq,ɘcIG~#PTN#"FDM\Ӑ1de0fn KxrgQGNNhꁔ[N(OBȕlRQDcwR#Lu^۸&NF"h1FiuuQc/b^lwLV+roe NAj =}*v{S{uc7rU"։hzk. $/*FY(f`3CW=b'ab*S:RZ?L7* '@1xc'(#t dzaχ@t_'ޯ;+]Bq>N倱gze,q"]I2RO^ hfi"-IAd57(pWD8 vm5Xt ::`r+Œt9k~l=dʧx-Z}k+΅ ̍^MI)]E)~279_~[XRܺk$ǹE"TKxou 1SeHxʄfѡ9vnj@‹qwFghNjnisX="^/c h+z E/NZ9"OwqQ Pl6~q|7¶ t0V "-6'b'Bqnq|tY)&Npq d\YTHn85g@TuGfYw.GHGLƽo@4vPУy4 B1ueٳ8p5vDߺM!z5gT[.E`[TT~+evQHw:5.N=s/3VX 0zyL;!)n fȵZ95f QYL*z Mt1lѮ(փj7vgN]Hթl 5S#nP׎!r)G 8cD5K\z2kϪnVęh7)Tq9Я4N,] F:B5a{xp-Sd|Eo `]X1ZPtHtO3u~7(ߕ-Z:rg=@fhxET.#n0xjr+22B* ! ;uW5'^[< |" b'^Y nҠ)qo@']V8!$0K(8xqHG434v2^ikp+ biҴ~Lb(<yqDG~̀Og7'ؙenq(H1yz2؝E;-LJ}4=&&w.0o#1ʹ3cw/z hK&XͽWBxzJ!në/Xz=0kdn/+E{Uap m tԙ}d@a9b %؜JR0r{T*kՁAd+  m)NA@?m CJċ 3N$a #GLO\n%HOy6U"fE4V$q1"iШg2񔌗wN$KF%5Ty2L#PK#ْTj 5eF3|N}?KQU:iL1dTg2eJ Euqkoܑ@uɣWd)E͒Np.2:g2'h!#Je&b`z*\c N?)-z n{*Pq `zB~BJfpqv`7W٘{/3[x>O>_gOܧooܗ'+}yҹߞ;]+_T?g}/W7.QWG}qWa>_|D.ݗ#r|~?"~nܷoԕ}㞿½[Q7;~ܸߺ_KqܸߺO_OK_W*/\ׄ:Pr~ WW'}~uqrd Aڴo܇܇Oȥ~Bg[ioܧOȥ0'+[uBݸ? ~rgۗq"S$>w'ƽB]9ig~a3vn/UO>F} j20JB-ثAkZ )ݟ R V֯i1I f+*e<Fë /lQṚDEbû[#7ޡ5N8~C{}WˢNmmňpn|;hHLuFmoqlx #f&}eG"/$"H# vK@Րx8BbQ(AzHwP2Ŋ(|e^+:>¡Y mKyЅ.&m#iQ/h@EXhdK#R$ݑ,u5oi=]fsIVĺa^HyF޺o9EH$OCkhGD~Dl);d͚==L Hl~U_+nPyLUAcrK+D, 謩8ʏ4Lg`# yHz|ilx8Vp|vĖOC:|Y ۚf)tOd~*ؿkr$ӎdu'b)~i(Bv$Q,WPC}[YTܑ4!}[ɚ0bZ|r13#:a'O4¾tyL@#k6lS1h[#y #-}3iW=y _R'ȃ2YQc×'N`Ǯ5'nd;4O<}3mñzh&Z ُMQ3Y2,ؕ&a3fG_rؘ`gHVhie7(ZA.I8~Xbl LIdj -jZ 2L|d%bZF0-/C2L|bqXV1Y Ό §[ٴ SVMȏZw#@&!=/D&L}3m"6 P1,jڄ7mA}2Mbڄ,̑Ex&Ay6ak&|>8h9{13o[,dޓ3ߏ؏q@K}>Qa5b'_FI}Y2CUrb(˸o S/yGŷ<&/c89<`mYGmG1m"619M|](8%Q=i9I_Dݪj;d&ĹGfMpENp~@jV9J ?4~W{fnMh"mJLʺPkʛ)vVBe!Tn*")}q#:K'!'R # S_\8ܢjYHp |C=VįT>mpi/I{4eV)B'kx;eZlwn@;J}L^^ _oz>tB3mZzn'2>2}s7~ۻ] =2<]xt3<ŨdGyV~M`et%Ug|*7_Y8/ɻvMHj#-ɻ͓GPG؅e[>>&"O'_)-h>BBc~/s vo86SB* MO7cQ_/$}K^܌nl>aL}'UFKeO#זv]o7XɦlēanffVe~IY8ԹY3 b?Xr{.2YyS1'U︤\fXu*g-=b 7l'}Fζ۔9ݲgᰌ!onEeTfT #?pXv:AFfOCF<w'/|,/ݤ\m? [{۶,HmWG|=vn7LY諞N8ll kG Fuak·_پ0/C]= 㷌Bkwi/}(~n \iCbї}aub_%nL O^Xae=K[&t( ճ/EKQ昿@gg}P>7u/mUc9TOԕ|Ҟ,.Pڼ 6XUEBkDA%hRfOijκlڞj2 /e$ӱWb0nmce~#ɵӳ<;#E~,q"_[پ>b4@Q-96IN ~ #5']cO6K$ 9'ڲ5=30i[߳0׏uBz{ocͶ'?ډXl/QΪ9v9L@'ij! |,,1L (YYg+ui%~+ntXɍ1RG !Ny %גGґs󄜌d(ΗSyY%ʷ㐐Y3aQ9&^?7tBѰ_RE/t83jJ4bئ}#jhpKΑsG%)!hE:ɲ oaV)^Nz& KuƠ7uo#eR&web2x .ÐdJ>kZҡ";3CrvJaR9u:o\Yez3k+~՘% 6,=ب%ObY N\%lQ6LxYy$q|z~7-dZD)#*[Ӫp(\ˁ4"]ij91#Ǔg?f8L;s0*.vSN['RP|d\'>+-0,+Շg=kؤoEh|C1UcMh<8. ]}Zz*TB=0@[3XeLkqލDJ:]we#`|[1V4;Oŝ:~H/\y&'{ I u Eč3K_l6mJ.9߱b=8$s!5ʿ 972DM{5۟e U.8wC_? ^ht0t雭iscv0xdZdo2TyR'θrN#2HO猠rJf=WGjT8Cc>9M vn4 !;cCz] {Cf|O{3^2u["f&Cl2Tq,Td.ezP5bc~!3>?$D*7[3>]q?c(  GٟUA86zz0ʵiwW}|ksl''$iѬfiO4EhiAMb>P#S>45Y%Rؚ= *6Au#&|N,3澵uR~HQ >$^z?CP*H~GI"|:qh{xHb9-6̇bP, h{h2DQ&d?S W+uZ,&gM gu#Lj5掌dSYC-4>5,6vK=_G~gTBk4XN hKcET04'̌4i3!~a<D%C* klfRKeZܝ]/ PHzR1oˬhZܝc]/4!TB3}I k0㯨0XN*C"Y{M0Gx ;⬇F_"4Y7ԁ;GGo5 h_>9^\S1Dl&t|[zg]v1$~*me!% 6j3Tgl/Lۯr~,\kc-8x]KkB|XGp*fX Qx;3-䥏5! o?~gYl/M›u>~zӟx+fZܝq˦D}@Kwkcm.y͗-<npq&\m"ضYw}<}ḓPZ n\˯<ܜq |{2xӏ/T~" Uxrk3->8 $"}wKEO9jjX%]ƾ4nT>tCfDz8cԅk'L7Je®֌c{/W 2]?Z^o?5<6I\ǻn,h}ʎB0 I"<R1 1<'rdMP;fvoSFICH-)}nN)*R+uj;BĻkg*gmd.] tJ\쮩L6*qIbф_$sK kO^P[MZ^~G,#a+Pz-0~Cb[%@| 0~ Ph_/~ жoܗ[% | 0 ~ H_o9@| P_߯ } оC9_o—[%C84M-@  Pܗ(G'%ߖ} 0 ͉#} p/KK-=H/KKzڗK<!OKӐ'%?p}_o}ܟG?_? w~r_r~|fv}~R.$wu@^G$FĐrēhҴ}H)JSJa&ExT699 bפ2!Lq 72Fza/Im^U7c*s?Hdw$Ql + TɊer넥-)HD|Gh&د;kKϨH7! ᄁ&U[__1c71}u1GLi7)fCIh'qѩZ>OxK峺+tfr0$ҎD'd_fL=}CC2#!YjI`_OtȶĝR>fmz v*KMplJޤ޶p?K5}CRGRW zf>$F,5dl 9,~Mwsm{W'~;fKmu~O8UвvK-mii<[?$\8[lU-dZR [3c0 &˾VLk& Xn$]mk 5}wg.߶V?Z.*^FZaHFfZ{Ыu/ &yiKnkޏֺa%L}-c٧ xvqia61jyǥj%Bf3cG1uٰ֖ܖ'.X-/ oOz~m3qK{5-jj3/{QBc[l0-6=7v/ã0YbmKL|qD.wj~͛z8rLl-Ml79nig϶Be6˷m͞Z&Kmg_GYnѶ>_bS?7M~۳mT21>ox̲bO:j3fk竍LiK-TfLg.}gyaljoyxs}gYݶ%JQ5[?b'[;j~>n&bZIڌ"-8Ħ9aGM36mn.|ٳ ä,&?x<9Z9Z\F϶KdΌML:ҎoZeU6w\luFz(K:yuLnj:jaMVgc_x$Q!, 3ҔN64_ļt|',tlNN/Պ qUĕ[蔅N ?Ֆm.ۓIa{q⬒O̾Bi}v?7zEc(LO>SS FߕMG6.A,.ہ}s؎չEZ]t}\{kʌ̈́Ektĕ˱>o>fH^uC.~E)_Iz9cOBX`/?zɧR3'8Z OJꮖ r:w<뉞nO,JigaPY0+n=e<|z feQ1g㌏mg%tǧ>΃֖_ogF eԐ}FeQ1:-lEEˡcv7l&}+022(|֑n]Z88)S 222r 5dޖ%˅. t&}ž]ieL~gslw}6l~pX!;le',}a^eU~(< ={Q<y0*~/J\²uCwOF_~/J\e7?nѳ~H ާ~HK_"mHcji_'fl]==m ^V6nړMھR,&|#ߗl"ůK?]vVϲc/>zY4w"Oqrp[=bVu ksG .uRN6`-ҚvLd Yf9ϲT2'g'yvA:DB)Oc1Rf,BAzu=8\\6mI;ՋkSYB&/djItjc 5"YW 1vNrdGrS!2i!(%Vtv 3PϨ,C$^NӋn誗#Þ1>ֆ_ˈw.^*i_QgEMteU5#|{E~_,i5lRUEӑMagޕ__+d Q綾!.e3sFO'-3ۻ+?&{-:|)5=S<Ԇzfq9$4֌}ͯ<;x-:rMrȣO뽫[R9YıMN@Q~ʢI6ң,3Wu$,:ŒʢW_ Weϼ<>UU57ueYyhu@=cMckP~ڿ`Os_}[ Ԙǵ9UhO0RR"0x|{tnZD 윥v1,Q3'W#jzp1:UJ'=8N(F/Gu×q^1}619`3-^KhcHPTNLJ͝f9rLX354Ք8X Ŀܒ%fG&h;t,o[eV[_f,O(a=H[^kȞ!N̐+$-`ͭ9n;k$jE3omx"i~xYٝ/WIQ,g^[CGhv}EDuxXgܡ&>=@ƶohʳ|2`~1ΜXS2PD&]tdh7JfR1Di|IcؚmmT"h/;- P uc$bȄo_h_.Mf s|:/;-y3s-*e_fg*ycWY_y1%f;~cv|?׉/ffKPq_Z1ff[RO[l_',m9 giT*ۑ'2N 2f7z[dUT3< dGdTC3FprȤaޘ6e3|?GY:}' *Q5!N3l*hVkL<>sR9n˳k+>_혯!snLh턩՚Y ^-։^iw_ݻo{oomӒ oz[O S .Onǿ?oaJ-8yZ_tK-%T AAV1{k~z!4@+;(OLVw;:-.{ըn#ac?]:7tš;8~8Ջgmӓۖkև;ݳsePwovه6(>l:NApwտ?c}hsVϱFLY.?ُLvqRy橦ݹWr\'Tyyyp&.fS-橖9ݹ.yNny]Yj9>Tu3w5|q==݅3S-|ٓ_vuFڽd7{x>_ww|}׾¼ߌf¿iFD}8ܝ/547盖'w#/7_>\i-{ \i8Y\Ϻopw@i6^tito4j]gw?mv'}a;ܝ%L֗[/v^3lbp-[|a),}Xi?_:f'ˍ1. h|q==.O={?~ c:]W3s#ȷDNjX/swӳտ3= ,=,=\YZ0B=ܝ~o&k?33{aYGʩw[33KffkmOff,-3.36Y23̒;ܝoff23Kpw8'3po3qw8̒ef?qƿ%33K,?:]F{35Kfj>-#t=q}C*yf1 {Co&󢦲\;E(:=B2SN3gܛY2SLR=ܝG θ7Slfyv;ut˲e^9:0t?z<][Wnpqq:g6ʲ;ܝ MfR: Cpt4syp|1'Fg3'?cƿe3'˜,݅o[ս|Ľ3#+KwP={ȊeFV?pd?Z~U Y/fFVYs fFV̌,3ws^3#+ˌ#0o&kL2Y+pwa8|_Yr}7*sҲ8p,Ut ́:e nJ[a; M;'N7tL[<:Uܾoĉ7lt6664zuZR)y2_;A6y iM۝6!QqW#^~ick@5P%;W %6O;2}-t_bv7L=]xp 5XV rr.5p6iwrPȇ!Y'_ 7s;6_N_iwrDzl |Wm/&Q6~k=&Ue1Uy㋨Vt=r4B&hT҉hST`l@IlwjCTr8`_`+-'ML؝>N Tj6o!frȦĆʶZ34;A٩~$((^U围 _iuWȷUFC 9 OShIa \Dn@-m8PZN45mhd:uhkG/vAyT*/!˄4v' {]4`a!;Aȏ$~SJ X| YNPj!diǚ'3(W!/A 'Rml)D!⫭MN0!W`6qBDBā8NP!_p2MtsQ" ;FhM&"n8GdZZl4#[o3H⁆7 ?pX!ݱJ_7JV1RJ8^:kz}V]ơ&;Yp!{-Qͱq@L4^t(L$"&;uEב+I#$ae.KB;4L~b]ø$:ޡmsQJ#'/CaC{0!ϽkDkţ([kƈuxkfpvԫ 3s8B_U8LFbV9NP# \(p'50D`@JŜvDIHj 9e"9@$MNc*14v'({5|ݟbM glduo ;U~%Fc{ drHMEn$MP \;U\ݬk]6_(p'm.RgkR#Q^E$hU/P8SCƬϽŪE!Nʊhܫߌ)(hkW`ZDA8"Z6++8TnTgϝxE?Xfyų\nWé))"w++ԍpYpAW^hD.QS_X؁ fgtnW-VH1;|.-:+(&_0-{񋥘IIѲ^ @h2pV0gܪO]MXР-siWQn,"j2~ds2~e=UYF Z67FK!.+b]ܬQ`9"Z6+(M48EaZ>+o](vpri3Օ| K#9UXo&w"֎ͽx_o7h+W`4C6Ѳf"q NZ{^Fꎈ˭8DRВ9e ,1Ȩ*23D樎kWIUؒC0U_ XsP!y#j [H?`}3D樏k_] 90\1-{ƶ*/AMc`Z>*,7r+l] Ѳ٫e:t.2Qqt=Pa*A6N-[q c~XO2έ˸ .DX@r:6\*w,Xdeأ἟[h鯌KL^_s|Y*7+7O9+G@K()cֿAZ:Z, C3WpdnX)և=50I>clh"w:딙4G0CVe|b:NaFö4 -er2^e zppW<^}5b;UnpU^XcG`pElnWoM1!{t}gd2~.ah0NVjѐKp` `ywX-{ ;ijLC! i5X-Iz`C8ǃθ".\ xF;=ΏD, 6:,oGA6FD>x}~PbkCqas^wF.1ɛ)&*,# ef[ 9谌W`TCKxƳ,戲bY R80>GNev ziz鶜p!s^A*!Urb'XjrpWb @PcCj-[0<"!Aڊp2QWyDApدj-c2^ H?؏㊸c)uVa)l2Uh%P1\9G,+Mm!6-i(ݚhҨ6FlZ\hQq(cQkp$ڍŽ mEl5Vdy(K'w\Ɍgb9NPE&Nkyq4Vf(KRAoۜ2"N.Ƶ׬ydVj(Ue*KV]^X#8qgVj B.W\3`!HGr9);.qkt"8 .w.!7$B<8VS0 GFC3]p(D&^1x{a7=ӱ2 4Q5\ח.5me3!A6jyELx9U4|e(Kp:u_Lih0q+L BHFJظlF`@ۘ 2ef́2Q&sOEΓ+=cAq\\A'W\4x̪5S9ֺ\qpg_e/V>؈g%lJF?#mK6)V _+zPa|K-;:M#l7yu\eVNبnΛfn+6nדVF+ SAn·n#wBZaCmTp_M )a]EpZډ+NhŞ?5ֺBYYammRak],Qn޸.P6VX}h}g70ʟKV~voIߺDYXa7wZW(+/ bRavhFzֺDYammRmk]Mμ^ו+VX}h}(֭zPȉ+*Ďu5+/d&6#'Z(P'NnڰV+^؏&aV`V^1j'NdTUVFŞ8zFsj'쉓[7oKV=q`ORek],0&=qrK֭uj'쉓[VPa5#g M~w߶n@ءL}GNnڱ@XYckJtHt9xvhԮ++V=vhRak]xء,,ў9J b5#g-U%g2=o 5@ءCS/9_&ɮnzֺ|77pZW(+kd' nֺDYXc5v7í&nnhyc?#gp~; 8[ w&wLy3;4GrΛ)lKAvh2?"ɝ7;oPV١$wLP9dLJd8kd2;m&wLֺYydɝ6qXPP6&YnfnKQ{wLn)In'i0ʒYx;-*WLNɝ6;m\rɒ;fw ֺBٸdD;fwurɲ;fw$ֺBYeBUstS~# A4h[+,hv얏v z$ &DAKA4hvG.[ eY^B;ft亵.v.YvBsZ_Bat0pPl4ȮQX1TOl d;*RLV r\Xj2E ^gi[#`F#mɗxlD}&oL Y%)"s\7^QrkWXTgpX/sMUzuc3-rO8\K hiMX`0U K?*;izӊ{V=]asIz ^wc^})*{zEŷ}jC<ϓ=ᒹwNdAK^8{bߐǽ+Zr- LnE=`n1of$g9_Y1ּ*Og+<*p3fW) [Ae6В;c&{j;x{a^Pu^P<#WFEW|n;? b 6?Ѿѡq2N^Nʗ0:TčEق7.naM\% { ljcY`e/wqOjI· =h%Ms Sp6Wy{ָl*OArO8Zr}n5Jycc-w*~ #l^}z2O8Z cFr [ۦ`g5LB#w7 eVJI^ }k59Xܒg2b)?*ա9Xy`r+E5iEN3%U1#Wo!3LSiNP&8B$/z&E7"5v8wL^2 J=aPyq?01U kRIJA `URE,D#ӈ{":bG-?U(āV~sp?$5!GŃf\3:=p@weI yqrX֎'r^=`);fgF-+&CN֖[*ؤϿyY[nWV7203Pr˼Z Ҫ"Zkve~\FXôr^ aX厃%:9~ qGVB"Xefܲoc Ȏg֚[cuPLk-|O;`Z{nWV/Ӊ_hW }erأU=e-֚.T+#ːDa,Ɩ;&@l4mY[nXV+셽9KXXV7 /!?o%7,Sr!z;'x֖;U %yvHk˪H g"!9w,V#Јy ҚsjxB;Jfz<5玃er &Sd&1<5斁er&$Y7ˑ- ,g`5 ,q4q'e1=ŠZ%'O@[)er#0[ Gh~XoWVqTv^ܙR+kjmz`pJ0"kV֖{65o=喋5\ wg c>N]WsʊeeM[4HDEg,ed<t5,Q`R~+NetijgS2q{q@.{EqrG:h;eB1 R;Si+ե.}?{t+xcT "X)C$MR7*wOB>=*{oɤ ʜӶO]᳭UZk7^?ؠU 3^4R]~MK\lۡSߑx vq]'RZIG\  IS53RT.~0~'}Oe'ZeF0'0ޣ ='J֒Zx5 7Ι>',TWONHPkI\(^uuJh>Nb^r r#Hx- hpNgS@>ͻ.Y rT.G[ʮa?@!z;ffoR$.ytLjMp)b4\ .3@ݓށ>AbrwF50@:y]qp# zЮ5s\SfF)&AC,L;AY\\%Ia?p3DiDTD.&%Wl-ͥMGj19@LQиJl?Z=6ܫ>{R;F䢃 ke)OvPl7 :X\ 4Γ#Dry3 "R$@=r^fP h(q(= shh74 _Rj&L{@r!A `i0l!c/%W!8X .ޤSjfTR\)>MyIPD1U,L<BHN0ٍgX+)=xF $iTez`:WcY+id+W#P9; KqS#v?$.Ԣ4|Ч> YlrXAp7#B}[ƅ琴EP94L*Ņ8BD;AY\dA*YHu HJ3r;yhta0Ɉ߅ J=!t8Z8ZE&J=s+cF@Z2're)Ń'Z'++uDUȕEeZ(G_X)w$.g{>tR$.pQ _R.+ l}X)\6wH+W>y Wu/0,:Tfn+Jp NTLV8VY;R!G=C[d١YJybDA9xIADh|H>T"U"l-W枺Ul4&KJ• y/L _*{CDua;- j@ Q.yU `:mM 0ɂyy1cn[5rZ $!D@{@ު4 /S=oŠc̓"e 0gI{".)\la0>\SYJ >-zIᢺyY@ Qi-yGo!h\$0T`K{i m\N Ud%qS6>ʰ"+[CDzv,b0D.0rG[&h؞ e#soLDf1*ENҁgx{FƸ XM_:b4:xՉH=qm5 ::DrϠr/S)Cz|Xǿ??kx׿O}Cx_(/_ןǏ}?Eg hs/_e+7Lӓ-2A $f(SaoǞJPwt'=ڛEшB~194iKg:#BÐPoP5مy ) l*&io?w;s?{YR 389WpS >5Q^֐_?NbFG`+w.]ecuy"I"_?>M\q&[ݴrֿ˱bP&O(2c9ʱ9Q(.?[*ߴ79Uim׊|L~zEnw1s+}rLy9mumh^}8/ֹ2Yўv;}yINcYu5PnI\0ӘזI6Sbkj:ս"4IhuC=v,LNֲjt۱۬^ߌ'W͔LڇV֩8DXF-Xўv;}y8NkYw5X~}V(^ߍ4u%7N)}+ikKuQbr_[nFڳn:l͝1NcYu5Uga:xK`nw1SyqM.tfN^ U.tR] h<.V&T]d$-V&T]d,V&T]dzظ+V&T2"mmyTj@āj\d3I0P5a"'K_0I0P5a'K_0=(P5Q&[_ 'V&T2mm_Āմ X[gZb5j@ՅL+Bb5j?EL+:b5j?Ll{AD&SMe8:W Tyկ4i2/Fߙ|5;O5B&Ko%O5b&[oٽV&T2"mmϛèOFկj"@D Sv@|g%pߜƴdi3Fp:տ j.#֖E1,fz޺ X[[\0Qow/uKZ U .R](kB UյuF .d=|hc7ꠉU .c]U .dK`5ڽuTjbAĂj_FS+IZ(CWb`5jBAPn졠KJ`5jBAP֞\NF&TuN[][^PP5:kT˒0laϴj@Մ ,}X@xa|dtm7~pOvOܜS, ێܤS-R ]r7Uߜ3+KgPᴛNtxUiXC2ؾY;>]p(٠D#u_dtSJ1ŀO YOYҁイ=16cQ &Fs#REU\cVMvW;G-']P =GfSta>ޕYn82F@T7l÷Eքb*Jw(ecfPA2=-fm԰,$P:{c8bZqL `dv؉,Ɣ/fmgvK˳Oe|[pZO|"Q Fƌd+M]9]}V^E cKQ3y,  G,RO9ݖ] " (uXzsA (ϾrfVt]ֽai'ў޲8&$P" 160!+EZ+\K0DA5p%Q+B/;iG+;qzF)9jZӃ<PDec RVeSZak1TMIZ9dZ* Jv( F5* +;t1*I ϿT ‘2D}F~ ܾ֊GH;C6Qs&iʹT+jp!Aag+ e8|r1R2`H:3j,Jv("wr6  HkFuc.1XG ZY ׉MKZ33p(q(#:jZ*vC>a+թK 44_/l%lH(FsɴTAi9cdNOz}ZF`Rð2=/֓lxd*u_j '[&d,k5Q!@bR'Mʀtȸ92,5A(3q'l#|N2A^ T Dre9g&;Y3h?pl3@x$ Vd5e)R](:nZ*wRd@9 )k#}Ci +)C)CdqM=9EQ $$<"ܚQ噶P<'_p*Ra~I1ӰpJ}΢d2QVS7 H1 ATR>9J-'2]/flL,0)/ Fc Fp5Y%Έ-1Fc7?wˉRÕk֓.]Ay`l[$N񏩝T yE]?cE ɚ*v=7 V lTY0:WC('\jPB $_9n6 N4-]3+g$eGܳV NބCLUAhmg]w1ZsϺ2zn֧׉i#ZkTrVB  X[Yx9b;L#wz%z^ڳv@}>6}`Z{WV#89Қ}zg5>,3Ցֽj% Bv >sOJ_^ MަcEvV¬F! K!Hܘ>-kV I0QU\n)cd-> 3h$0g~7@. [3*e@VdZ*008;^30ګ/|"kURm< N_(;]`A wZŠQ~- ʖh3mw~]Aa apTѾC,gn10'f+ZQ[ S-'N[BA16瞼02MW;y -T L+(b8{.[&P~@8V[ڬyvV H&oI{Pk\J>$}$"ŵ7W[6g?龤mU&lSK3}YW-6mB0ܪʡR([lb +(áS(i-$R JKU03=m-4(6ß@}گ MY 8׊rAjSam3le'i)\SQ2Sx[qNJ Pzig_nPBD]+^ _P؃Zu2f I FA'0\/ S f;0ګo<_ӷ fQ*|XPyeoLt2CRUb2N`uѸ*hсQ }0*5bPگ0(ՠH{lk7TyAkW3s9-|ɢtleKMZ@ן5gx(𳛥q?* .qP0_HAcܰ!hy΍wXSM&otȶ_5I*g+FRʔF JG_5;;7~m+(lא%RX9f.tԴ+Cj5"_eڝ)7鯬RM.?UY:L)/)-p2XW'?&ޥ$]^2;65\'Bxf h*AJZDӢTI6z4t S?d?i' >Fdi~S}Q'!>4Y}L |D15:Ϥ4\'Nl]_l@P~X?i4 V1C3+GC:jgv;A@u|5'Q~_R$nZЃXM=ie=KٌReNd%Z_K8v}2(V@bߠ5YcR]=~7zb!KSC4<@ӉT kX8<7y5-:lEPϟFWv5 uS9!Io,lbͯZJG ỎA=V&eB7?=ѐGDq `(ٴck$2;lUŷǠR.O,0ySe׬[C&y>_ q]y^ǪjH8ja7JҢX#C"!vb-IbWPSY#ѐ84JΨXS|Xe 8"4}j { }Xt]W\bפr`gqDG!Ծ)aB"]_ソ߸@Ұ7f/KU߸qC}ܹ PLSr:㈓`Z '93f]. izJPŊK)zqU?2?Ҵ'SZL=.Ֆl`(?p}S-;?OH 8QQFVha ю+ lF3Fi;hR&J|PE.PD @DZe&'4S8՜0$T^9q̮Ih~Nqި UZ}D^h.5PoQ JjѹH1jtbUܴ̓<.j|bn%FKz 0#hSgR64km*E|G覾okO S]HЬq:Ipk6NU[DSsrmXnct60 Ծ`=R/4BϴwnTANu~M d S @$<թNup}`%OEU bDдeH6NFb jHV@:IsIddՇUe|`Gh'^ÿCR sj_t'Ʀ]/$\_bt1vjF VG:* J:qa(֎(d,vfS߸>b0hƎ8ݪ?l0I `Ҍx) ZF<_UDК2)s[NLn$TFD7 Iɗ8ne͗UNU&1FDV=֔yS Pp%ˆ;6RYUWU=Q1:j<1}q94kʩ0ߍ0HƆȜ`%@NW9IMg1:2rݮs/XRS^HG26D>b27,=UGT#Va+ns+Fω Z6eDT'PM(ENUdM$ǧwq:Uk٬wƘqS ,@ahsآ|o>d'ܺmn3󸣀k.GnE-GCGu`;=]#:W}]ID] wD@4=F:wh(21˯C02*@gzneE2۾Gn3Z꫒(MQ/6,LIg0iJ˞N}UOAwelqdFҽ(NhtfJlA&Uh7-@Sbʥ^ބ ڋeu?)dJa;dF݆z̙lO"d)aWn h9CáSLB l&b~75vcfeDGgCUĆϘr)/VylO:KN"#/c)<˪>$E(&⦜oq ^}ldVFpUhHIP,;!Zʺ"#YU3 @;5pDO}儚'ڹjST}ח6Q'+U?]Eb,Ιȗx)q&N}U_g&A7#EXf|H`Ϊ<A|`Ì$Fƙ}lHcʹꫪB]Eb*8H1.5XdUT$ ċwŠLvx3!uuΓ^HZ$vLyDM$?ydar/]w7lU2"X꣪7=-p =# ̓׎F5ﶥ̕SY)e3%T=ɧ꣪?g] P,@x[" p]ޗ;k1iALkMkM]*ᰗzsJW>U_X#GCM`Go\wͬ|sIsiX*anV Yl0+oFFtʛ=B]՛4 #+ú{UJx;heuWjϻ30 6Yj]\ԇMp}QXШ !( ٥x,B^;SFT7ŝn%U5%zjJKXϖTtsC:h<"eʔPoTnٶIqƦ#7>T GbwtxHpSLrܺ'iy5㎨EiNo^[+ )qHZ%9MnYLn"st( 3Vzmm-+ wL~HܚIkk&ĽKvaX19t ?dC㟝BҁE*51;{NZO3qJ״,Jw(kkE>KPfXKe8um(Hczd\Fű,ւ"D3PCNX[ R2)8 4ځɮ1f3BqNRٗΚ(BBw Js(MkkE 4TzF;em( MQ E_tn-?'d6c9!8}^mkNS@c8P,/~ҫj=db=z />Qntu^\YLTċ嬋%꼸:/^{-0A`:'>,w[ m?|/rE!XnnqlC—ez\/7BXkh{[WL/pԝ(Dscsۜ.:Y%GSlFs4yqhnilys޵[ۯlZ9ny4HMPjáDޱVwe,Dvv{_znMw]ߝIقQ|5w ݎ}DԨlwbw۝=VńDѰlwkw8umHtT\w8]{ ]EJO íp><=ۖƄDp><2"IZQ`(38;x0&'%jtKTP' MEJszZP:D*d8ԖHe yĀXӞʶ5E Lywjr+cZ栯eĕsRyGXv.T]JKu)zR4|7NmZ[+\|Ruuv)];^~ZD{x@vRIեN%\A\&(eZ@^ݠ㒔Se.T/YzvN= ɳDcrnNJUO q.ka%L.T]⥺dR=I&ͮSPCNoY[EѷD+PTR}Zk*F.f*ذxk-10\T,RuYHeI W`(oH%˶TD'I$;Q"UE.r!֚z.T-Gkko'lnMt9ڗIkk/ 2K"Ru)r.եI IJ4lZw$; ; 8SFb]vX.$$E-6ovX.T]iՉcac}Rs-7.TOHRa { FvNe][˔?#.T]l֧y0Ioƺ4RuiHեI-E.T]lҳ<? DžFc]qA 9=\(~nB7D/O>(91ي.[E- ^uhfw gTKv~/1}r OXeрc bdg͘h)ӵ_DNkʔft%5lB{&.h5X8H-j4uR;_U@q5HJ9+ZNMɢ u$VSf+#F$DqEq^X֎ !4%:i*Ho@8'A'˚-0|rCj_)#w w-D]H~>+?DQ:/-shm{>!/+UZl|\J%c=jQ }I-X&`b߷Ճc8m,K0|^0`. xPw/3Qщ`.%$- B:!D#,8";Ev:A6L4jfzdNЂ^T;Sj+<6._ ZجK[]kA\ G/i䶜1wvIg(3HTD2$oT˳vH#gr, a7_@S B^8\1=rEMW /i@ٔc#0Djz ^lSG˜{ bTX\J/ \y P-gh0('ۉd̋Q ҇c!}R[S퐂lޤSE3R{V0̝OЩeΖI^<3xSfJ-95*'a0TA(.qkأҠ^W΃;hdQ&Z1̱4{OqZ2d4f ;RLZ.S7 kwj;j^U< gJNUvS%r;ys= /89&ycA' %B/J:;S8f @Ƅ!oizB\`a7K ({YyqT.r5"$`P"QOI.Q?{@n׳!H/)ee.MΙKH_rE;3AFh$$&¿"̞W va:*gVЛ{18GlIy25֚:~Ҡ-sLqݺbEgJt,EEaRe[UH#g@8q"%jy://Wf'1$Kڟ1"8+#u ! c7?ZЙ=gSwȘnIO/ș53GG4VLjj1YPVAO43̩ 5th"5ϖ EQD Fj[41& wШ%g>F,WSJJjSj7cT @Al"ʎd*+S?-+"0jҜ*Sg֜, bQ22 9X&1zOA > :IU?~ Ae#[CoQ%ohR IyFI[ЧfnnQ'4);YQ%NJCID(uCJ}dRTpo@T9p(cI;%m7(.%Lyݺnz\5t=Ѿ辤GMkj7;!~G'QF0,Fr?NHFzqE!.#o)FSk?^6avSKz{NPmXDU_ SyPBseC8JmY4!?EJ݀R.ZI B?SkcOޓ6(1қTNU%(6rt)Ac\{P5JZQ^3$^b\>b0hSS ?a(mĩS\ -%=m~Q b~0A+urI2z:[?Ei;i꿀oQ6Ҕ{Jw( S+(k&zr2e\\ѧ3PC7] % >LgNg{r@lNM}dtg;^*cyaHQL~vpA&cBVdMTgWi~'$C.QQ)ʨd~//ikZG 6S RQ!D!hQr O(1eeڣ+r Js(e2 gCɧ(գNU9eP 2G(ʬĪz|@; AP.HRF@vOӤ6%ߡ\Q^R)J\QRF'#[l2eDJ(OSN0.IS!Ga(=p|.A ? K]@~֧'3J@i=Uh=ðz=\ѥ6_ER5 ̿bD)c"(uGNPC)Q+S&S8 \N֟I).Au6su:>P՗Ԩ38.5KvX'IQF#NɥiFZQ7aO˛.8(R_o(QY݀=-)b~͕ ٸpXSVQROQj cp14JD Qjn,Jmg0*'2}C •c+Hs d.0L "9 qIy'rP!a28;nj JfU;3(_w5ZP&U=ILf3{ғXڹxP{"$԰c;'50Br!.)̎[Nzez|T0#[{2Zbx2r;WiC P HJWPؕ-2KJaTe|ORW+vtY~BRe:Ei2p8"n{a|'$[Y5ɁGuzY5D(5kҚvV?;sCR{'xVo6'AU|"9jZ>m'2=~@R*mP?Z?!AaPCR5W^It9i%\vl8=J W`Dad162,%Q|!C i-۾h/8lwOObF]'8.-PC)'Sv(db{rOѢ8 s)F0']Z0:PfPFsa~iiOLP@MC$#IT Imķf '2}VKZ)iEiz\ӠzA<_*u?8m+>1Ø=VKRTJYEEHA{(Qj\ P vs&mIQjf}_;cyKX4:KT?5*vkF foPtͦ(F5[(5] RHs Qj<8 Sbr~`8\h 3 :'_98(*UT5]ТdY!ROHQj;c$.SNe3 MF1(Qj67SՏt(PNmBU^r=*w;*l/ Pb1VӞezb3KRJ.~>>qTEɯ jN<>+JNQ5vP@FDv2; -/dQFظIj`j@1ݲ]'@ L{e{G2v3{=2?O '}2'@%;)[}E !jq<'/VbvniO8AiRMDz2v%!⭗YAql}2<;0lLdlgfQ^{]HG5R)p8PrA23Hv ݂M &w`Z.A01J +fw:|VmTPDn--(c;cF3-;j, 3=V >(\4JM3^hvcߧ-׿U&ן(m_vDA?^+OO%*TO덟=o2@|/87G'o~Cȿyȿyȿyȿ+bҵ_΂~9op> ~7 YYYYh}?9h9h__9s99A/`z/`z/4: ~A= _"rwsPO-~C~spACun~;ո y3f!zDᷳ~ B,_թf!z~ۃv&AȿY:B,\ɯއz6izr }ܩ^?Ռ]o -[VlDM -u iW%LwwҴCbyȐVk+yO]T7ZU-ws.bs7-bθgKFaD׎rOƨ.#2mQyoE\EUmdGZSG6gT %[sC.B䑗$`J6Ӑ'NBwTc -#TqPϦ;S$oJ7t2Ejy9BͺφyG:0~Uq.A`FH?g |.1M9T+{{3*qg3J8ؕ5{GdtBތnd)LjG#g䗣d@jEmUG rR?5BQ\yk?۝'qԍ~- Rp(-nՄጻI[# 5E[n̡W{fƚtb:NmYwwԒ/S)V[|Yi>[=G׎62dqL>";q̡Nӄ;qPݘVs8'>MRc!X'['ޢ }x)/؜5Tm>۲8qzUg|ɕlٝ8Z'։G0:'>G׺:њ-vNuwk\!iA8ᴎԍ5m[\, ?^EWByo[rNF-rU恝Vc',~||Yc}FѸl$Klw,[11qd|ƭ=nl5Y55$cIY}Κ)Κmhy_zqvx;['^̷~aIr^7ۣiMz{fogͶ]4<=|kb?eEc#/3߷gMqlEc#/.ۅ;{5:-̋e0X_~hW<.֞jqbtԇ_ZcV?&?&Қ)[ΞО;{5և}]#8v#aXYlЇ7֭=ևo̴[k0<:5|҇a7-y>5ևpxÿ~;v#g-և}xc|c}9k0:kpẊ/}|؍΢;{p5ևjLo;eq\6=ևo\[k(Ẋ|){[cucϯ|xw9ȇuj1eKH8 ަ-_pw>\5Y5|xcZc}؏4ƥ}yKH #ަ-_ps>E9k·CnZc}؏ٜ5|xFZ5~fo\;k-W7X뗳*ZvgI%ޫoBWgc1ݍ[kLo Yijϳ(ߖ['9{ l;sY,ʷeo Κyk~+tgȋ-ŭ׵p rX/+So[{:{8ky5&8kay5,?Sҋyſ7\JݟYý̭5vlh<.oX / :<$yſlq! ObFnz|Kq̷Z%vVKg2&a)}d齽Ÿ*˨<{1~;"+1@_7.7 ǃM('Ws!T_FWWb뾪m7ļ+h-Sqf5|+S҈ՂeU%ZVIᥗbܕ.GHQo'K"0W^zymn\~uuX5ߴ m`뻱"+2*NwVH?Wl;olI:ri/: ݭEcWǞ+=exxn|UZ~fEJed~uVvh빶n/T??Y?[6l%Awt >mHEmnoڰy 6 ;.̷(5-Eo5Ѭ~άy_qzgK-q2YcW#Rm8IS) y$ekNm1Ŧ5vX8g#crnGNY5/=jI$b+G箄ێ #kjۢ3byiPFⷶtʍ%_#Nh/1TBeF]Ssk$ޜgLPcm$JK`)3eG:Y3;Ff$ WrSK$u||u$Q X8g#c7I"חtXXg#SԖF.HWH?NoZ 4~h0~h0fȎom1dr_K#~+e,%g8_*_ljGh͒dL/3Uf¼:QFpR^%YbȌį-13͓Rhƛy{f^+ 3_5TId:;|tjViKkLV&4r ZK>|-MW(h#r5z` ƒȒygI$KkoWz0 c4\Վ`Q=9ϫ;re9(sh*L?'ï [r{H+3䟭ܶO6ҊƊg# [ݏ;;چTqܞi|i'1YrwWo :\YbpGcY̟@Zn/h%lkKt%'ÓU\v[q7folgx!>8mEF{4 m24\:Cڵ!ƌjOJ=J iwFobk!E*r^-xS>k호C˟PČg#aO~k73C,~ P!byƙnNm9CjNo3#0#83pf$,ѷE.o&jf1'lӌc,g2AgG\Hޔ;&'#_-g$vgd }62#2Ҙ!h nt|Ef&w-ͺ2OMQCřΓU'RH!:n&u2ߴ!}rjAȮ/H̏Bz=6%ScƳ)gTEÐ9k5EA$ i4 _W5O֐\|jD4? iY73D}$>Y)Ř׎L Ɣ'/LIzXC&FDc;Q,w&v7lΩf7\Yj$g.~e݈ΔhLy.,Kok1~ݘO޿]YjH5&ШplsyDG@"'&c|;V<-92<6h㧫.ysp$4:8M |ʷ9#;#ʩ5'}?#TH]}yR{d:ۗ43EV_cw#P/t}563VnGI-7\PКz;AG8BA-hٿ'?3~뫉 ~1IߺE<Ɩ%NO:Pۢ5FeV%Q^^VnG fb}85Zr^pzwКzS{tҧC0>[W ?E(1@ ƅs\8߫ 0\88΅spŒRG'\88΅sp‚vypp. S^Papp. 3YILGq. p8saA?QGpp>|xTJ4>G^|X|8:·x%s'~0GyptE gH;m9Y?9t 0;w|. i@vݹnwO] 4 s<'_3EʝvܪvnOݖۂ8msܶ@AvݹmwnOݖA2 v8ms~ 2.نO8ov-PP4(qs8q\ϡDvw#L4yGGMnMyǙNtٓp;Ğ;hb%P^^{ĉrh %ZЋO  J0# uR{VnGA@Ѡ$a5W[Ưޛ9np[9 Bb857;, QaPgֳr; –yppN`+waKE ΃<88 . <88v=+w¡ABd0!ƹ #hi;΅s\8 hiP4q8·]^ʝpҠ8·a׳r; )&ѹpt. 3 T;P G.gNP8|iP GѹKYKb&%fBkjMՅЙ4 \8:v=+gzo7:}]Vm AK7:}s߸+K#u%.8Y^J׃rʤ2v*'2hdGj,R뀳r:ّ%/s^J\}s=+<)<$ J e>Q݃;Kh)֮R\A1%@}njA=cr*L;a@-l.#czgڀ&rZy8<Fs{Tk> W&}q: d1\PUow;ס3@0;Dx -+o!֛ |ˢR[@ǯ7|D?oȩH`.&ܜDE9`.&~% Gʙf" .>VΖwhFfsEo:f<Ƀ΋xQEx[Ρ30c&GV pbriA3ROX[o[*_|oww #rX[T99{Z9؈" :|Z*%7-*:'W/zh BxQ=k+4 MURASX[Kį$c. ܔ)HWSRMD@-riANp"2CQ<tV!c)uBZxZSRܹD-rT`w`P@#wҋi9%JfI 7`64rZbs<9i̤F[+vQ}w&1v*iIM;1q`<7䞩WSn3h=>2bPD#ŇAxԜLz30bL1Bslʬ1Q+EcekѶ&I+0L-FꞫ7 zK` zdQH#Eư^& /'~3(9N;_+`Ixy2f0b'|-Zd3v02ȅJ!ĨF [~365 j~s܃ H=je_ hQȅp-U1v -rZ`ͽمTcFS+=6ush76& K!-тRij"w¡ژZ#B9+ Z{Ԣ~;PVcs_lҁ&;!2mK3`[DRY13΁OPnp2LgcQX#s#G+CZ#rOX{I?\A_Di䞰F()թES8 2J=p6VХhik@Lh.R Q1@n@!4RX NԀF k`t|t :a4rXVX{p4w#Jf;Z//.G58'*&D&٫콁}'. lF `t LNql~`f4r;Ufgc139 ;yP<}].րN/u= sLKnyXa" e2o53_@x= +r@4\o?uLU7e.+f4v!f!=_ M(PU7Yht2[6WxpoW98Gx7!o`#>? 8w 7 sh1jrW)`mGGLo"{Sm+G)ktǽ'cjrL#Ki4*J;K8; `hpX8OP! ĎURn8qX\N|MDJ*92oDktŴ㖁48u*":HR'쨅uh]\eƆN<2I&=К?G)~qZe*vKE! E}uhwݰ=pVu"E4r+\s9ZJb$DԎѢ2%oZ5hjXD#ӊ*ZT2IzJ}j-ApVq38צRXКԒ(`(zPChP|"*}DTEA.h?+@^IJyC+G3Gٍv)}QPWk2|&08sLO)O_~<$=V#6!i,=4rl#n4Zfpt=SFo~O.V+0#_|xp֘E&Tpz"n|>FOt(WeRXrβN!D;a1lFʈ,IzkpRUcc5 (EШ*̏e)M{(AfRW|'߇#mxdz4m[m0=a]Q6 X$ZK U0>U0V.p59G# fjl_qB8?ÅRD ;EbSUˈޙKm'Vv sla8>,Nh'$_ as629H[Huًms& qfʭѹUKnWV) *GQbNs˽Bh/1(+r!r WUcM1 B3ՙrp"OJsVB+ȆTveRroX'\V8g SΨ.Eٌ[&Hzf tҋ_j{:(,+CH#*j'9|֐G؈ƛYXΓcuCى bIJe2(VTNXLſB⟸3k|l*u +v ݟ ݳ$ > ;;J-ILCBN ޔeunY^Ksj,ebi:p(|1WkeRLcEyY=;YX?zZHN)OburBz9pX@frX%ɜ;c o,"-J=ajoAiɑJ";T Y7 ",F/P`9XubwAxo&>Sii*eB@e?bfgR8XS+r忂 _5"S{¢+@eAo@ h$srxX|Ep@oi[-zD#E/@4|E6H=`aŒ\1J=`aM?t/C*&b1S喅et,T҆Xe{jmear3c B,/7 ȝ\,[\@Y#v.bծ;=b{dԶKnQ,Fh=0YdiLLp_& 'n5Sjc 9 q/`mJݰӈD_P'yX|Ѵ<TD_ZVē-ʡˇ_,W]h\-=W)/q(Aߗ`, !qЁ䋋jeXJYZ# 꾥<\É'\g0s>w^dmF#\8D:T+Ϯ s3@pPqucb= e8Xk]N@ = uE+U KQ5D AT[n)]T1;s=`DKӎ[B[C\[xQiI.jYaD)Lb;c~Rr\OS.b{nNY:ۇ]<4eyxcoղsOS-mV'0=H$tKPfAP3Ll>&dTie*f:QCW+xKb&C3ʐbU;X]ҹض4W,q{Ŋ!MD&{sq[ TuVuPpqCp_c䉨R\lieih3MDT.öɬ_Y = qq5"-¶rQ 0b$.CSC RH\l_a!\^Z@RkOdNT\ \\d_(Y.9JLxVOT8L8=qo!3*󄼕})[^ / PPZUnx(T8Cz^|UꞾEH=t2$RYNRly o]ѴWų[Gn(`3:fA"e+x?'ʝl1* >L0]9 y؂rOH\ %Uj1%Y= qq,uП F~K4H񄞉= ,Rs<\XTR0ap~ H҂mEjcN_( \=*% \A-y9@#uObM2rz d! 2-GF IL aW4 9oY&R-,ȻT12N8n)]p,<aMܖЂ] $HN7H=8mqr̊,*v&RH[l$`RarvkI^RçۧSpTť5JwFqjfQL#02oP,2Qyӷ@>@̾N@z@ޒL(c ^ACWSŞ/[ "͖!4qx%u+|5L3!aGuZrK*cC9hO [%}KfB$Mߏ1 4Sj"oq"9]~ZW@c ƼRĠFy |l0-{o ih=020UӁс rKb D=Z4hUc׵W'E/[l_m/A LSXo衉Q/"̬F}- g.\'0%0 F/i*Pz&r$.~ٹF;J.+ H=py88lxŰ Iŗ+_yh-rb4 f^o 6G'F/[l]ťQ[1/v.OlgV$}9:M#4P<ث`Ԧoqiܹ\jPEO[&ukD7!c?_א-?^2ho e΋?_?z/=w?ǮE?Oxcϙxy&=u4~&.fcaF1ݏeh2Ng?YG:bI̸S,: b+DŽ)FQ7*Zj -*3yGSu#*Gx lE?kq#c%Al$>?}$1rv60P7Bʫx)Ec:akfѱH4Sht(SZ1Ά/4#;3)?`Ǐ¡*rf,Ft73PWȜg&(tBl|8\(d4_y\2Jkt2؊)@&xy=/;{wt2s1r엞ˈ8*X[dD@{m٫vCy_&QQJyOP 9 A ƌ#s{N@z|#ƮAIkJ|P~Pa񝢈K聼ѕN@@#c:hEН=ࠁ:nhd@Qrߕorؗ4(tlq 0V%,mOQhq!fgKz4?y2`,s!aAb~͔1y!>4r/noR)NKc>S`.%(x<W;|) ۠,!I!~%2'9e2C9 &{teRx0y|,|ݜD8'F@Ĩ_V!Fa M  Hꑴ7K?Jt)!bg!6́ŗn`s>$4I㡜vV'M|D-Dz@DI *QA#:AT @-ޡQ%v8h?)#PF"W4lm7rȅlŢ*O1UFsg]09P;tmNeXreA>8@]*4ߡ<|?( :Hc+a E7覸@5]䫽B{t#ңG( 4%vݠBpPRJQ;lNg"  o^҇0>Jt, b M4ȴEf#PVH}@ЌFk;xmw|ŀS)V8) ϑom226fKԵz ҉V`P U&ܔҍ`udg3[8#u҃%LgҷQIZZ!- a%w:";瘴9 ntw:@l(Pe k iJ~D۶ 8M H?ol ht0q9Ku#@#jP*%"L+vF'bMxwg-نh 'T&.8 HBDYK@o0dtNI9.$+]h#jiV@dRZ7@#C; 25:R*2-qx  zT?r#9,*s3:o>RcHqʣZyq@–qH3i8`Qwъݨ u֭&z%mWT߇>R+3NZ ("G) H}@(h%BQ=?rM#S$Vhd'0+X)Ho<H43QFф|PF>g4L+bφL pZh|<.1J>4Q2 D=N4s of /#{V YZek l`XlZ/Nx HkBZ u7>i*[4>Te WRh@8&Kr% 03_T/ ?+6 V, ~-TLPVlq+Z~yA{!˺Jmzj0(CZ7Zd:' CDj )FnJ5z/A1]KX.rJQ6\u.HU}ƂKhC̸dX*a'ٔwEA+o98}Hӂro3sye"XK(x%HꂿH]Тʻ^~* 5Ga&7 j~|I3#џu0Uի gv#F1p cmZ qܕ'b eӏ 3*ĉz8<\ \3`7*5%rK$J J/$Ur =Nn>O()a.׆2]X*aHʨzjW 7EeX*!HH!ʗP6jG'Fqzi>:*?*r&c;^=q#*2)=&4RHH'L{32!ɒ7T3q*CoAR #ڱVȳytҙ/PC٦-2ь _rMoqp6n#Mn)_|'aj=(v;W9۝: uES)m:|&o{|T(/ӎ /yq\ye4ɌV̤TUޕWJ`:6euH*U*r*sEnH9:'0y+eT=s c)lJȥHB 'Jx{1P6?a|c^1 2(ሎ(yBw~#Lf7CaqŸ}߸(,:5ӴcU-***kC55EFTpWFV IbJ@lmTT U.HY $k61'T%\όʴἢ8;]9%X*o=oCZDKG 0ʹ!㪛.T~ԦX2V00y#S+&U9^ ?i|)T!V>W5Ey*3WðjlXǸEX1H/#ub?=D/>}aZ3aTnxQU$0Ì@&[Î#X,B X4gBgzC[nr@Rp#B``^Q}}PJn*~.:L!pjT v ޔ6Kg9ʷ^dGF+w A:=P C&UԎ!Y6_`Mt 2wӟIC8e| |Svvb+Ca NzeUI @ׯH~XP2)/Z FcQ +Q&%naN0JaG+!Dꇬ8 xSdFaZDt;pFjɄrZy:%#  ΘnTkgC0 &i"HxF p/"^B d@ՂI-uJmƉ LBʓ_ F?Z] > [> dNE@ICM&SAÈVWf;1sYh?V"ތ @RO,t+_)OrG7ZM܇niheD-n `DER{78B# t+*Tz"iy:T&a7Y/$jT P|;A1l'd0OI@Wx32O4RJٞ U@4RPz@; }6!R'H: O`Djtd Pb9դA,:Z< YiiKfvs%$RjKGG#(1&Do2iW9"r DV_{#{RD#d Z Z&@tP 50 lS d.&lԏԒ {"T?ܷ{' |BOxLΘl:sO/%Is^7#;aNPѓ{J?EFbKOoH烾olW}c>(wVpnJIIKxo{moW Xpo"M:F@!w|"Ǝa9dV C>Dτ։wD'ݐoepZW+??(r#4Mڻ7~ >9fc'9eU9$ܮ06~>MND$t !R{7& @=Qp"KS<#u $%.ZQ 9oTQ#glE|Ц]1 Q"7 { 棡<x#<(3.]&d=Ə4c/U>A {/aXhS,@>*~uƂH)Ş".ROat΂&{J2MA\:`;1 V@dj; HwpbgwB0c^!\f~>:!A@e^]k9Ts@l/vF\~lJ|PCPu+'jMn 薄E"a۩0|P >5mGN8 =K$p) 2; D)Z'``L`Sf2!&L {_&<97FnQ$P;\7S0+0`Zڄ3R O(PI1Hr"gˁpiƥvhK98Sƌ4j12'P#Yz;U~6ǿZ(.#Rfx8?8szq~n+$!HX Ӿ $H9M6  QIaYd $TR/u^r%O# k4z&H& L8kf?CM\%p—ol4H{P_R&&YPl^Rbԉ,M"\Q%I@*1+LjӔهz n4_#a/lw{8ml*TjFt`;PBͧBrw_R$`"< i>̻E U%Q>0c ]7i<q>\nECR1O~'D c>0Iؕk:of6GU'c)D/ݍ W!$2Tj7&!W+:H 4)͈YCdrS[{-rfd#ʷQ'ty-`%],!2~$J%3XTعpݚ*>(rJ)d%1p.kqժ9LN9PVw rY\sU9i"u|HUdO c$Ti}#uj\ -j~DTR-x2ٸ5$ɗH\ ̼JkyHwhe^@&ڼ%Z3"b'uXj-/Ԍ0fDnv:) )]Q[j)U-\)@PMQ^-+C H`ґGWo98fUA7<fZ{ yh>i%[:,g0V<@Uj|`mYk>u8jVGyVr"wCeg@rcX86r x@םY{&W(`8*ᖦ&D]5䑦̵ѝ:'Aљ5՚<KnF+cT=/տqu2P՚k0"\gfPdCjI-#k2J'К&ZC -cZsOeB1息ULs] ZZC JҝZE؂պ &РiULe]QxdJ+;i=EepeDң9Kȹ|ɨ/@Q%KJVs45j\_2 kel%:Ar޹]Q핵eRs^FܼcZ{TynEќG4RsK=3BUPkkzq͋ ƴC _e'aDmq Met^F1;/t-֞ e#BI5f (ƴ枖k2L}cA,ܓrV سڎgmN?|@NU{ñpOm~/p!|Ԣ1[ΚrJƕPQ׼lUFΚğ_%zQqh__V-M$5is(<1u4rع3\zZsV]Ԥ}chI9c9/ 6e|GCfT)^ ]%#;*BC7^: w0oIxrW7l7lb^{&Spbo0z;*7&V-5FoO xDZQnKFqzY,_SW.`P&j ,TBލ N=~_LjmϊBkD;peRČI7 _|Fo0.,& xFA]~ Ɓz4ak'Fx3*#f hyAm8e!KHɯ%sz-b(5)eWʼni:RO-pCz:+_ 1D ;-(zeNYR(fjBΰ{Bb2'$OץsgЦN8L r_lr;yE>0lMg0Ԭ+w:*feڴd9&&Xh&R^]CXҸ\XF~9q Rߑhr3Y܉+^jwSxyZme>pl%;M |_ P0G39 -i^4@-×{9xjxA4r̸y<64z D(i-rە8uz΋"ˋsyy6^,3ue{1ٻ\^nsߪ :BYnR'J"$3RV˵/0Jn_r&<<4*I;.'rs.lL>'R 6?J a5xKoUy!s*v<-elёg8U\u-\E Ƿ`ɧ#1Yť\E m[67U/61xRI~ }S"RnU-٫ŞD(B^J'h\|hE./S<;vב)c1x]$el5ְwNy\r;`Q@#wM -mI<H1ME#IyEn3U4RK |'-b=f.ZR/ΚSbQ)uBx!IBpE(aLxdD#g H%^Lxny"oWmZmBhW>)Mv4rOxM&иd9 ZMKX)D-g8-D#˯q$\HKHdpP>`HIVQcB-''Oo 2SY<͜Ƙ2DB-'xh/FeeҰoz*PKJXzW8Co\ b~!Is^v1W!b#ٛxB8eZK ĤF:Iy1ː=tF)"*=I_餮V^b݂h2$9E^ߌI=7Q.8Ƀ"y9¹Kj {=^H A6ĊtޭqBđ;Ykg>b"Iy󅤱 YE7J4q7~?KHQ(' L#'Ȣe6ŤJavMHބLpEN4eYX~AB"8 [ʾ \LYD7R>$!G$yj4R\>H8H`LVǧ~1ǟiM`wUeD_՟c685 <}yP Ö[opB~K'}/1%3R\O?E͎˹b)kK[ɑt0v|@{%D,e1)/48eԹ%r;1"u#lo^ٰ|`*#bjo~D2R9T9\cyvׁhTPMV»MI 45w7hpy)D0#BiTNAYFG8ݽuׁ#xsH<¸+7> H˜G1cYT8x6|v!iu|_@ǿOq}/ dZ; Zg$%9fq7a9DW/Z{y't~Z2j8_ hkKcUX2 zm@vp/V_^rϔwOÓ~ YbG)vtr2: [3:FSƢ^Ugj)vp:8!Ƶ!A=KJyy~04 Or3 7Tg_+N].0[4䓵E\efGq,KMbiVKci,f^008 ;ݎC?01 ;DQCOC ;D7DC4Nh@^ޯMyAvR-q1DqjKcoB#R1Fw:Ro(|Ch P`7X >[ Ud>&vp3\oYɩNF% }`vJOh98 ;&| e?*(Z U<*pe>X%7VɍUtcױsQT"; ?"ުwvAbVnHݫe&AQ[aTa/QCP員oFQn(7-+^1v[̶UxqO|7L䵵Vޱ|+-R 7Nvj׫[Xpu#ROF4XnH,Gkk)憤!nH:$ t VsIZA (Š߲t֊0ߛon-~bx͠'l}3f,h%i8em-)ݨ 7ZÍVkkh"qpehMÍ8-AAҌ@68mpx;n9<0sNQC%;cm-(`)!v O œ3;^n'N8p8 f'im n+pp[m pq텃 '}kEa JtaA N퀻&͵0=eXp8 pOQXpp{aoݠhZ*90X%2VXLnP?NsdάL.$e!èN@ʸMr# `m6YQxJ3]^9rp{dqm0anN6EA2޼Y:E#v 5=M^Apj~۠sm)4'⪒! "]spvɮ9#f]spvɮ9K?MiR5we$a YܮYRök!q[ơ!'C"iNgY[ːH5Ol6DYmDŰc6dc UtIߺ#M"[p틃}qlÆ8qt6dc%0Q&팣G3ngOvYg(ádޱVʹ nܦ9M3ҷP=ݦ%sxiΒ8C8􎵵Hb6st[m9K69GsnOv+& N'o', wLnܶ9msLn8IfB )JvaX d&DGmnݶ9msܶdvz|`*n@8%!Ű$IŽG/q Gn?OB1T$~8ptd?,T̉2Dn?~8p< 0 JzLŎ"tC8 7m*GUnV9l||gǠr{xWD7bseפt浵2U-Wn^9Dw!]ttv.ZH/&ePymDG?zWqo*+xGzPQWV9HTkQl-@VC.JeZ"'':8QIk dEɋnh4P 0qrFɍ7nEo:ɍ'7:Lntq[T'%Nn\?(nF7Z/ q74nӈMnt)$^PEJPҤ[gi E/ɍ'7:Nntq [1M4yqD?qrn@'?;N~vxg_@KQ&?y}(l^k׎|mnj׎e2k;_> J0ʄ{*͓e'/[x?VF/ ӎ's( &/;N^v8yTqP6Li>EhaˎoloN(Nn628?Z/n4$`:NC{;x@qrL~έӐ`)j ;ə3'g:Ntq5ߩ((Nt ts4X|nnG&G:N 'gr#&G:Mti'P0 _ GɏNnhM E@&:`LNt49irӍ}>&:M.t\4ƅ[Ʌ%MzuBi JkrB N; E'eAɃNno|r^PS&L~o2N([&߷Lo|r}MjN5sk>ҳ"jailG8SS43N% ʴ9rnhE&5Lh H)kvB1 p9BO&wa˞0hSe\G*yxu&P/exV y#7X'|p]~.d,,y.fBЂhi"{trA#]1aQNttrRM#u`>)d N*w\+hRX(w/xF}]rDŗ ,~:yoI]q5X#sYmdB":)gK˰uB_k2k6H'wQ˜ZD <[Q,xQ'-jR5s(<(##\H끠%TxCz$Aӏjok9mdDܕ(O+K&Ve@k[lNPzG Z(kLG6>`O)J??5jelco\y+<2?nVtC_-֐1G]1sDg'nxN R$`7J.c ]P?KK8k_^qǾ2.PgN/I{ݵZe>0 f&ţ@{jxCf]Yp!H7Td0m` ":+kpF%ip׺LƦ6KK^'w9$QG贄xQwtRWG hm&؊ol(OzQ>J ゘hA &m| ^;J6Bz7@शq#ucTE6 G>t:==M] a3^{$/^>*@oA rMŐWTA&nԾKKNqy,Ĉ7J-+Ե5(UsR&Ly; mݦ#X?K`P9cv礮w 3Tw#>`C¦@/ k>%|55  Tvuvq{:HN766@LX4Nr#{d{TB{(ˋ(X$p՘7(A72ؐQ\E(`tQ;:STƪ\) كOh]KS>hF E^$nuNʦWSK3Ѭ .sCF6ĮU 9z@D*ncה 2 BhhC}:S݈W6P^Tdgdų検@l G 6Clc*y9)G]2VZpT&Y"x VU2ʍ5_l>nm4-Йxy^xᇡ6=NM1(A=YћDo0EP^AQ]ʡhJ2KVd&*]$-K(e + S8R%~?k5hO&#%KVCNGS )]k i+}yY2XqB$ưend?Sҫ機P I^\ N^!ԧ*5Jˣ&a'WiPS Xo)K т(^dޚ%ɴ~I2t/sLea'\Xފ%IӲ?!(^#Ji<]DWIWCjvnA/r{W kڦJ&"7@O^d3ɨ֮3gŀj@Cxd>@zsV$(KKX$.Y,yP^VPs;Lo!D}5#+pnJ#:j07JԚ@ xx̔o!:)~iAHa`|nԕ4ӥ.Sb(ϙ%~w>zvزKNWzj lrNS6 | uJB#]y`X|KכưeBU[:.Y\+oRUR!U4C^:ߤN{B0TA ΀%͊ګxAK ܙѤU c Ѭ -_nk[\ּ)e*|aE`>;RUŞ2שfgGirk ٓJaW2A+B 8Y*+,wN:7#TQ;g [J#{<3]=M~nupLB@@4Wxaɒ/%5}`2Cs2!i TTɼ)Rw<)l*yR :]Z.j}ȓxdQ';VJJt~a7<'%cJ$8΃Uɬ=aE$$"tU>YI@  RS2"Ngp3trXREFDVytzD`Nj͒U 8;Fd"a3*Pp=`Ja[4*mN Sf@ Rˤ%6|eyhCI9coRhUI4!ѡcrmQ1z$@s9濓{wylk醨 =ďФp>ތ@\IQib;@dԿAp{)-uM('𥐹Qo3hEͫN;O~x83Iul&-%m-' 8v[TA,K/Ij6!upaI%ڣl;a'FfcbI%fDca\8E2OXRNp"Z׳jhCGJV,I ~f4i[18'%M9qg]Ԥ9HM G*РJTO+ZTйGN~Tv;d.9P1<>6ᆟF:g(MJ+ CtRQceM m#0ʎR(j@H|Taĸ4(pQ5h'/0MiwQl/B_\4t`2+XvZheI=aIIؠ)_(`Lp(=aIUڔ츾X.:\v=aI\RξDirOXRO'ԅ)̖ؓ_pᷓ 95c{7aݠ\xRH9G( =aJQ ȶO1TI']mJ /]nNW*=LC?4-"t.*g RF Wr8S*HA!A!NS|ĉ^#CD=Ð5[ n.Ab4} ))/!Ed;TbJ k+G .@YẔ˒^0پ9',) 1%Bn%p7<' Lo +?%:(.-$FFeQeF |FfpB|2~Rrw ;X4tjCg2OQFH7MOܯ:,eHFa,n>8c'~񑥴h~ɍ]`_Ձg~(@Т;d~V»1SV"}Rg9L{BِKQ4Q6!I?"9);/}ݱP> jMV. #̞dMO U / ja9c:Cb:9`-Ų `͓e-5$bD07#C[ uH /`H !:5_ ? QhnecZF{lrkrDnjnNj͖:2 }H 7ddIEx-Ca9,IѢ*g;-K )T)ܒ-[4Cfc/|~IRjrQV/Bm X]N#uןkr#= ?_ߏ`?__?y?<B[:_?O/_=׿)iZ/; =xf$`AZYA x Wq9B7P{ R?5C?U1MVP]yhg NWPSa[߸D jf M?E2N ɢc^D3LՑ?DwGw5U3hx(dkNղKWmxRnvjܫfDT'ڷlsj]$Q.6\>7ިƹ.6զ+ƽjA46g'{V~(n^۩q:lmf5h1(Ud/o^~nQ ooTݭi;7nUzզpPuo cXdZ gJ[ rLܘU3^S3&/%7_)6&/)oT#`M^+~qS=^_T7JQCi7i:7(F@ohN&"t553:;44jn57N,-}D%fIVA<CYP)PMCs7+;5hܿr{]wJLP}"{]K<7ި&٩8>TΧΧOII5Wj)xm\lSlSΧs^$mSlSΧsj^q{mS]lSE-.-*wiOrmomoܘ5جjT{O~nܫpP=sSi|Q'S8Vjۛ7554TMՈA zMMۛ΍72նvVVFU3ep_<)gsgdjP-׹fƝLmտĵcRMM{΍{͈:f44ܸ̠loloަmƽfĜni^٩q7af76m?7NzeFf44ixy+Y2^_vPsbih]Myw]w5C3CC }e-o!$4.k44{[[>7U3$dmSlSsjLmjmjԴzn̪K j44ix:FuSmSӺF ^zI٦ۦMMƽjna%Sodn逬ƽj%dնvw릆JWdh=Msf mKmKsfCmimitnܫVPm[n[4=oT6?Tۖۖ-M/ƽj[0Tۖۖ-MռGݶ4ݶ4oiz=7ftgކm QݎWTv:E=Nwݰm3yԸMCYvjmzmk] zhM{aF+_:c>*%7Սֽ~jR/~l^5Bm4՟IMֽ$e7h0_Z#SNLUNAv WL1}Z|br ) hY>G OE*RVBut?x@ 297 ?:@3p@e`85#08 |I4'x7ܑ7h&Dhi95dq;  k;vQÆ%\+!<;Q^EyYKƇY+) nA$F^36vLXtϧ%Z1?4KX9Ǔ+$.2)xAݕv꬯A%J'fZ z1ɚ  yرDǭ_^) ~-N!<`!n53:^G}{` 9̚^r5 -pWdD6jᬎ뜊!mÂ%KD>pX,'t ?n6:gn mÊgؑL~<HB?A߅:lXF"s4ez`Hr2k0 (3=.0CvW^Nf!uS$@q$4 7,$HޑIx t2ƊYIp]T s WyK YJPˡ#g R t\|$HYsK$ S<$meLh}X0rG/ێNDעQ<."ȑ‘^ KCy57":y8PTRR.nprwQXLD"m hSHh&} 4\HEFE35EvIƦq<dIR-izyDnѐf|O"+ KVH!e,/#) _R$k" =@F^&+HNfM97r$ ^}$8e횗"Ҹ!a( :yNHK-egCJhLGE6, y xZ54yT ₑ,qoi&,Æ%WowF~ZdP(x:3\m?ˆ;p$A`MNc%˻b`lpPy>˲`8ImdW*0Ttx4'*onjm%7<4jz 䎹&HgΆۘxed//k h<[搃X5H_d%e WjΆخ"aNm(/[%YU hh16=xp\CV̆4lp(쥼f*n G<L e21 g++*1ڇKLF!@N_G;zHоzr13rTndf*u~f A8xHcɞREDLBY9Ęcc{` 6Y'1bEK//~@Jކ,lL"+_uT.tan8ꍒzl߬a 褮MW {$sdشCêR7gMRYВj]va܃Z0ZXVt,L%P xXx^eF !ɌQ3ˆᥤرg-*i7(4L:LWv^}&T2[Ucߩ8 W'S#rXC SG3[o3e?J89ׇ|¿C[ْf4Q#F(Ui7|ӡ_>ȴ xeo9v9Uސq ]HƒԨvɺ;E=RHAV43}<7l ~q$VʂbqD/܄3Yb8_Ý<.䬱ÚXqzƯ?XE79&VQԏ3{YŅ5Yb8c';kbqySVĆr=cM6=N#cĺ  GlXq{/DslCngɆi( W]8cMV,=NğoQLvX{#4ݯٮH +fIXqe m@! 铈1Et$3dÊtilDmcq:pQ4ԪKmcq:G%AqXzFCeQ ,gÊ4Jt=JC}dŊt @vQMv|f8?1n ҍ3 iaq %rKC6dԉ'5g]h2`q H JƭaMwXzJd ƣ3 l2cq*ġHCBOP+VcX۵M&VQ7$4ٰ ręFhT,Xz>9 },p&g蓃"i,XyF9#3'¢ LX+>ɃM-+eM&;V| ٷnšXyB99ٙx X1y>^Q|߽g$g4~E3wTMWɊ>JtDmcq:'bGišXz/hM\/5ٰb8U3dƊjhH7/xޔ?gbz.F, 5Zo&KV䞡7G4>+{ԣކRMv>N  _&;VSPűF~ -$;Q=nU < %y%z80W8gǂTʁX4yCƳ D[,Y~N|98=+zbÄX9MV?NqQn%8S~V)}P$V&@oDqZy]iG7[.ޖ ęʹ!# dɂTʹax).&3Kx㮩'4og)3D)8W 7p9KyljBBdƂ 4~A"kz(,.X΄)Icpf,oylf*Sɰ:*f4o鿧9?>J]-Wsƕ5g31ȫH%{cQs 荹B Ss8 ޼9CV H;ѡxޒK!f݌mbB^t[+X[-v^-t>M8u1ԳopPڑ`ca] @zs 's]-7MCӊb.xÎw Srmҙ@s ^0=(>j Z6@<"VΣ7c\!N":Nw+'DgˊY~cHXI k"=(Z^/ϻtrk~{ n<[$yĝu8 N|Pg˚`XPݯ+eM/rZ S`hM [sE9S^#%z\9'S{ȭA;$7ޘ5i=0PGKvmYӌV`k*@kI rAIZST7Ζ%i=0` 8y[>ӌF~D`E(XҌCnd9.WDolBM ;<,Uɰ3mFXQ{AhA%Ie4wǪ4 DmG8pp\bdj!@VE_ӆgwTU/DU,≍~_QPSjCL=&L~'`Yih'*D%HX!CZ<3iX"+L%y`a!(aETH770(-dTبR1F$_V}$FA$J'GiVGww2kRhhKIJiɒ1"pPK+pT$D3%QIR(2%)6 ~MRbU$\\>WCmXє(Ē}XAKwE V_ $rx"8H&)%S)k; ]6(JZGVmtdj`JX&&(aqG2co2l8ݦ$9QL/X&(er$HM qͰ`EN$+O;RcꂡŤٰLfENbAn3b,CcV5,YғetͨKӾ R.4YR@ Al*w_2r%nVF@tx¸kGԈA)w*fw{u{ IҦPCbIN*ͭac@&KA̚$m4ab25= {KK,tV TbWʋ4lذ"'YqAu#:kG``v'0 #B vR0$XJ>2uD0 r!_ѓbGPyF:̚T fj pːκ+QvIhd 22+,I/&3Q;%d`8"q@#uGGɬIJugLQ4xqMMި+q5Jr%K(R(Jb ߲4ԇ !9;&( | 9'30LLfMRFרp$Gl]Xd4%-/v>?#jf2kRm4+0X06A;vP0lK%#9+x";R_6,I04I:tN7)\I䠭H ڰd&%A?CWAG`e2t 07Y)H2JYai0~B(OuBLfLˠ)vf0*S(I\i7gVp5FE #46FFsl'vGñHinTFѰ: <XL#IwB7EU48.`di|bAJ}Ɇf27g6RT ЭeW&R %+"Ҏ(E/=I488v8u`{顱CR ]hH{]Z8H}䘾NLF-6ltdBٔ$4L:NҎ5.cj= H`xNnMC:Ӄps0eGR.; lqPܕHL@O1$$Pې!ѤnBgRvr,:㏁+Ua2mYR`]A3Yowx&iy͑';Ш@G#j@4ڰcI>m4@XyHF<'~c!yۨs,>я`au0ZAA!Ԛ|N!iz k2"9ٍ1[ź%rG005)exbЉF0M ĦAELѤbtt 6 sG$B2hu$$H0݁@MͥOf["oXx016F.*W*HO2֤ IME?ߐݿ_ן=׿ƿȧduXQSnOMeBKLs[*CKsPt~P6G a3*M'R*w\w=5N7VuӹqLN&D?7xDK}07UII*#4W^{VBL_T=5n1ҹB\+a!iG+C}pS[oԟHHi''&1[PYK!IG&7dlj#[rVh<>Wjz8I~ #1k5~'.6l6Һ&$M1>jHmNy m~i>ӑk|,{m}AftBSgt,iH0Ӌ'cB©uBYUoo7~piQ?JXFmӥuLDVߝ>iKAH{l- aڀzDFڃm4 Sܰ_Zw\$ G b>jn? f5Nh=ݤ&7~G[/$$l?Y7O0dn)?e)nVL[oB)c,6~mZq۴2mJ<馸-Zq[2mJnu_I=mъۢiVڥk:]H3U@i%{a T]!bVs@iͻZ0ʂa@@n/_L*Qg}-b/ͷZD5t]k,ِ^XɬI6]Y7JRtdPm6>^/{pQ0UaCf27i yށ+Bf2h7¯ @Lr6,77fٽ4 BTܒyM/Zc4 [Y7=>W|1LCP, .ZRWj-.f95bү-ދS ( FfiakXpyIw}\,-}ذbۀ4 0'&[^`ːBޚZU/+W494d[Yx2jʖ\Q/(WZNuDUvk6Ɩ)*wr!  [,nlԫV4+ʕxzҼ-.;Q^42V1 ىA8uxҮڽ ځ 5ig+D^ZWɬi;su^Q-ZNɹ!zC>W$M6JKKz{ ]L΍FQM (VJUL vrKn}h4^2lYKIL6օ (gڱ&!#0iy4*w)uCy*AJFaܵ(ؕ{;oE-t- nP.8.Ez+1wir7(j^ ;S+P;;(f.@%\pp&:7>BJ9qr)В5yo{$ (bwx&u-u%%ƅJh׋Џw. +!9"ܐ@xhZ ɭKLƍL$ mt$!w$VL'v ZzMzjj1L'.׌#[xxrdK(C)c)!4dE/!jCRc^S?c)e)ppB$ȕQ ݂! $.Y䖅jA;BKA*cw&t;Ŭ"[x\;Bֹ:]@@Ӄ|+w) ;{I-KJ(HGf* QBVK-)ySLA$7p f1a:ײ,7Pœ*AI 2Z!( '&bBDr6zβ:"񂴔rɁ5$Ye.@r$virrZQh _iԊVKD'!l̊X0RQwh&NH8,z;14@Cژ7b5 īd5"b%݊2HOuq_@׹d % <*Ȟ܈RV73I+!V9d _Jl"{eȢ;1܃GI̘tS3Vbi)G=wzQFYyjF0"zQ,%7p_}Kx%rF{GbWXq+ y6{Km݆or5bHiHueJyuahufM&K2yș5ixl0fg,o;ސޯ?- Ϙޞ ʙI"8ͽC);LoDs]Lù`'L'wE9s/LJ1Wޚ+ƉV"`m%\⮈ޖ+Ɖ]~vXp)klhB\P<+A,vQ0n5K׊#TWΈޖ+P5ȳlW@o̒l~1p^2 [s8=Z%⃄)Y"]/f t,Kg4gNJuu~1**EExޒ]WN+0%( 7}5kӋ3$Fn۳f^9r[JȸA֬yWCUj@G*-KΕkС-jg3fŹrZ"4 l< NWDo͒u"K 荹@WN)N.lLwB) Ι}B,d_989r[r sқd_9BX#қf_9zZPy3fͽrZqk*q7Y] _~8Ȋ#89;+<ߖ6 )$%kƕ*o-KƕӊS Fj譹ºrzr3l% 7v3gɺrjqt t#lK1k*'JǯY*xΒ%jQ[/$9K+VqhyC֬9WN/PR-(Ys/aiA֬WNk9e9gޖ5iŏ:xE\P.+dZvO*zg. ,W^ZrUgDoZq x_ќKnF졆+TNhNA&U"yma 1߀V$܅:tQA+zq;Do͒w5Ъ|BЙ]9=^:G7xޖ++̼Z$rܣ*n^":[+ٮ Auޚ+g̿rzqJtY^=n3gͿrzqBנq0=ki|9q.,UѼs.YXN)NÙw,9XN) \o8zc,g QSp,XNXv YJ Wo g8ggSC`;q1c8yS,,k2Qowޜ% ˩` H7p,yXN WTvO8M8XTCjMWaĒy4~i cT\%+Ѽkޕ n$&&5kޕӋljڟ5k֕ӊ}~c*zDo˒sʑLk n1W3Tr!F3WqF֬WC+ĶH_-KӊyςmNxޖ5i;h ۲] GF:/W@']9 $i5ti}欙WN/;ZmΈޚ+/̾Zw4d<#Se,WN끁djw4-)yY3^7%'Θޞ+ʙ(1Ĉ$+[_9 1*z#z[+][sE935@Iq4cz{˩ B^ʙ!9k{ W%=8#zk,,@9C^A&K QS&e%Kz`+0Z\1Έޚt~# 3J֙۞Ѽ%gW*V֊gDgq\U_yYS62:IhF Oi]WI5Nd"@޲z)Eo!R $>Pz;,M<AoIEO-N 9;xU`]Wa 6;=fΫfHW`ɘ814^ ̄jT)yP?ކq5cEHwyCfH`lcsbYFÑz5="p:ί?`QpӏFv`{@?ߒF&g`d"-śtD3Í"ܚenÌ#LX8,V?cpmsy7d4[ϣKeM\j鍙PԴE]SKFFic_Z=ѕXl&8e(w4/JМăXZ l%9QD'H#z@ڡLPnc2QOd %kc>Z}DM)KˁYfQ+ AhR7d3-K;'wx:"H;+G elC»}3Ј;zE[,K5wĆqeݣ`|W|GL8ugō+#M֫’0M=u4w IEY3Dirkzҋh-"(AA@ GLg = hĠVN*buw qnUvK IH`}!x|;`yM@ui} ^ldž!Ĉ^і5Iq$ f= iF ٞQZEGc`:'4#4Ev&>q'=Nt2 {GԖ5I C4 'ͻKSa-Y"U4LA )4vMYRޱ)I]1.4TkXċ ;$Tiu&)/K 2|6H~H=")I~7OCIk0s-E 4vMGq(~̊ԯ2n FәwE^dP(EMNR]:$ǒ5{%'^txqX򄢵SR⮣oi(C4g-ؔH*u T/%UhRZZAjQd_\)*mg"#\|4LAݽhy#xrf\ru'fMT~2/"r.:fHYآ lN>fgrkZvq J DIL8@f]UHGb}Jt1<6=!kJV` OƠ$N%+BچSmPFdg ;_9[JVEL)1NIN!R$ڕ^&40^њ+ƙv<$7$\c^uiرd@e1 h;8<[`Z s2;S'Z;RIβr0rǝRV4^^0H3~N) !5H8U^EayeQlkh ۴dv>`L'zMjMȂyǯ>3A~nV```)m7vZ|<%[h=0! 87^5JJ 8%VI< dRZ0a?'pԂ9τ /n ꀱc#Ґ[Sh]h1P:l-qKU^w@zвן%I,п2!z,e?߻?_ƿh_T-!z,?o/_G E~[?3 ߌ\뷆Zo\??IFt823PĴh}C13n`#@i8ld4>-#E JCD4TUf?q|jzTPUuyy"E9"Z)?m.&FCuʟM7gbN Dxp⥥{T:끓Y3Ӓ< Ȇ'K`wO4dV[_gSHX꭯?Rs֣d;%P[CC.iݬADACtrw+Y3rK7@H->Nf]߃{?Cs=P$^><4Tg=zp+$J:[̕v&I9\РNxp!D߃z?N3B==4Tg=zpJY-yND2@Uݼ[^zdn b d ڻ7M?h>n$ {j O&7OT2>t'oyrϦ;3L ۞ѭ?NF@T߁;}cM=8js 原:Wvg=cMda ƟLwOL1:'7khw2^#yd7kh'.ز"JP}>/jXwQ:pf:%Pwt%Ln Mԉ?o|"n)@tf|ߑztt {7I=|p3JA=H}.0 {P}Aԃ <nP~mFpdKuY;׶; Ǜ:[5k #N}w^\X_ <"OS/^\_p89< n@8 y쯭N>\'/8@v"5++o`rkPܳzs ʅ?J|%/G=~M{榡mwojnDžMhS?ԏgަ~[Cou;G7I%rnQ0|@|l-U[ F 4˹ iIz'COάx[Cmz 9M@|89ހa9Ug$nSO|˭aqdKFr]ql rk~Xt{@8>/[oa1y?!e{5;,aSԇ2~ׇ37,֩}D:QNâ&dkh7pÒml@!B:-7LJ˹KqJĩ+SW 4yi>}LC,Mir IrHK~XsH>Vh'wh^AԽ݌d?>veLKw#![6[3r죇l ^=`迵9O]SWݚ{yKRL;6'wr2M}iS_ԗ/XnS_|TM}irŇz͜{+w1z˴srb%L}IS_4rnC)/iKЗB+>P]RtqQGb^DaGi;04[ns/ަڧ^#[C?r]q0g$rn#ܔQeǴsr-S}|TK 5 j[SuW^\(]%HAgu2NA<;X{!\)ek҄q2NH@PPjX }KG &Du ℔+C#R$ 񰂋V)\;AR$'&9EY ƀW#) ,'8E!†F[6 XNfMqBrKVдchq6%2(OÎ)jҝ̛<󉆸*kS|\{y;_b/ÂIZw .nwq#(0/8Ԧ$ӂ +L1iK$'6|M5\I`fɬMR:+3eF,'&6̾00>ǧ 4'&6`Wp*q(PyZɬMdz} @jN՘5\͈AE<A3aUpa*cp}`6։dt&ܻ.+1gT0HOSrk2S@% fn1uDf&Yreg3k㑨-4'4N}V+U9Ґ2 GC^>,Xљ6mb:@ŀLbMiz\V_qC33HLK2jWD {Pӈ3U"2r2KJvy4̙ ZW!TT$-Ky@trOJ1a4"+uj]JeL93nF>*nkp!u 1a: iI<̇ 1^L#;͚RO(KFiR6K 0ʒx{c&dkbdN aI6 SSA d+--my@W'2;!rVN֚85'{ P+Kv"E9PU1RS8^Ȁf IZeqtjL5b1@'FFK-dDii}){BZ*:RVyFz§$aǚ$H9AѺ& DwAS̐){BLVLfklNJp+l{IDUnENʹă9h!9'NLyp$`,c.:0fv RX+troIJM';o]!ɄJiluS&pSB;w&sii|)I9/(†<3Iy/--;UyK(KTfMZJz6oO`NfMZeރ^ZQZ,y8?.皁\0B-H"*-usy$,Vpy9kĥ哧seACbgDMD_R~g[-UY/y4 kIc$%OmTqhxex 56:K@ 7K: AށN!*nR7z7FޏvF61BT ,gxTR, zE5йNǑ*lb$QLfMob>qˆs𷜂*עyۊ7Ḡ.pIL":+ƵfF+瑾BQ=9I`\*Ubij% u?8j2 <'uŸV U G 19S@y*2B;FㄇoI fS-z_ZY)\ 8 (eB)FGVIKśzR$ FaC*B`%R9(@c/\')3L>s71WK@[y$!V (Lq(/tg-qwawA Ň@orJJ9"1^?v]tI`\*f5-ڳ3\kbEb]@5)fFI]k3\GͅF ʹ> *#Vb1#֦͜o5/X(_yȠ1DtOjr7 Moq}>b_nEb/dy礮ꀪgRyai%HJmY1vI̼팅 e W%+&.Gh1|Ra;a("!]xKXԚQSZK7)buɭIU;(/=+Vxm`6睚Ms` C8.q(& GT\/tЇr7K}@y  ^a|Eh1o1wЬpW2v@\ìxy*(A.B^i8i@-UHLPx+R n8%-ܚ\B_`v'H'\xǂ#vdBC$ESqا53 0;ڙQtȋ<Ɏ+Y1yNbB"PI= X _ZUj |@5[*Kk*Cγ u AClYր\iIޑSB\>ɭUcRu BV爚:. Z\60k 5+Lʍvk/2R~tRkrR&T.~8.WnNnM=)4ˠYAd0UsH\\p8#U|蒼sRkRUT5dKA8LxLg$#-Tp=MtU9rlLT7gI* "}]P *Vsa-u D)xR `A:RE\Nx ɕ=P7f`8=S㵣E=~[p8E MstrTCox$/,4*7 %pR{@ktE@sKMN*RKC 8^]wt*'YZ@1(h8&S~"jcCh%n/4ϐ^ywclsMHJePY/ KTo1 D!=]j}[{HGqbyMMA'b'ø=D#>0NM*cJqLd͚ZZ;>2V;ꛪ̕t!U54`Cd{ܽᘚ̚TŜT {펝psMMA'ܐm<ǣG+oT"盚jUǫDjU+5ZPLwk=V o|߈KR>uy;'ǧ TDTZЪ&mG%|+2WBUϰ]"UCbYpOMzJM\̱rI~{*^+"_u@&S)pMIp$*KHV]w d\Q*!qTt$]g\G S>x&6ʓ7;M WQ2 (4,I)찾  &5>H2O/ɣE_NbÂY  gE G5v%Ў +v&f~IƖ!wJR2,X1$ ;Q/v#;-XqF!7Q %LLb;RGGڜTj<4YHՐī% fyRdn$@ɬG!$: 䄩<@#nd飊e-n]T9G|ǯb4fC;0GO6,X`VCΆҹ0IzБ:: U," 0a>+/M~B,'NC%ra.߃,X'aVI Yp$v dQ0! n~Y8 dɣjFID78`Dry5$V`TC4až,mKHis7)X2mbԍ*87i='4cAb.`rw RW(X'`?4?hu9u)H$ٍ(\T>PEjC~i2?aIcchR(R7aH( ebBثhj3E/"#D'Ұ uxGFVߎL/1Tkauͼ]i;YEZz}DR8^hR!#(Z;C43IŐ48IPp$}pL^t&J¦0$Z``&E@酢fgRQp7M~yDz@Ȃ qA$i"wyN9RԚ܃ T0) KϣRax-3{@R EidL͔5E*pp<aX%irOHR(젔^#fq&$h} I G }d;e˚\_* ZM3>`E#?[O=0MA>*Xx! fzffg27t U*B.-P)]0W* U &$e"FX-KT"`QӬM IRu3\p V6 :lk|^RIP6=ݍW?+AeP4hRk, Ţa8q,܎PO*&gZ8U)e|avtr,T1 I9lUO؃I%jRP4Cyim{i"LtP83MnMbMv_扤M%׉Ln]R>xG{)-G=Rd)ԔЇ `v[NǞoRxã7R Ah&.$Z-h# \=KNrIǏO(,r7d)·3M@q9LUJOz-I,6R2z%AK,iR<% 0h&;5S{]HR$= 묞փB:eXHѸ;C498,e;):>iw'g<ቐAܚ"E;(pw@N&fr&wC`:ѤhF&pDO%b6D'&IZ@;GRH9ѫ^HRACCO%ݑ 'ZSh]GZ9樚cܚ"%Tl\,8^:,Yѣ"hݻ0srSb]9&sUWQ7$)AC%0p07<{Ih`clDQ13P% 6ebOArkwߘaŁO:d/K+Cƪ™viuhA7pR"1w`ЏÍC1ـ<{|A&pؓ|2=o I`6[LB*ȎTނd󂄁V@w#zҒqR!zUGnDGd7:1Ta IDC hKKfcȸ_ABx Ti zk/CJ r";1,Mx a?tS`VCSZRaJ hC6 .T1W>ٍJ8M: h=0G F D/w#IE-ۈ$*'ӱ#́I~ Tnd!9A6|*-&(L&M|i$DbPZٍJ -LJt<B\DG~$z wp^}xTT (7c1EPت"C.Gd6N" .fARJ~/8a{U8EM*'wUd= r7zcJ2uH~d6 %bqNҍV`MκzTaze¸'D,K}ܡV`z]jHjFěN=J&1(?ֈTbSG6Zԉnu 1^-P q-9V,wTVѿa~1²a-0`D^`LAQ' y03OAf!2B rQjNR @3s)qW̒5Kso=9 ̚(q

pL=A4l /^Yw4D2rgPzۻ18*$@!kA* b0M~cL1rZN` ;lNB^q!ܡe?!8Q8U0&q%}J[9jStHWCq\FVn܇}0C/Y!7  Z'N!ݠ?PFVX PhG.tz1El0t$}cU#0"Pn%yc ]~p'e`-TFVh_tHHLBH`(DQ(#~+y.WPBOI`WFVt|y[w:, _鐰")}ˤEAMQh5iaMj*YenC.KND&dI=9J4w0A70&E_! D|:[B<'Ô.$HB!}Dw2=Nuqی?̈́@4Ԃ>tB`0*zQFV*ԝ.4V5D'w Em"$_((H8E]fXNꢝ:©¤/:Er=0Ig96W@0 K, hulSEI2Fbd}@S" Cp7 =g$trWH}[™񈘓}2X)>a,g@T؄U0y%<&ۄe!o:5/* v,z8}tr )BQy I^+0y2Έޖ`Q87+?}8M6co#ɬFޮ9;Vࡓ?ڐzddwG-jgjQxI9^+0؋LjsS.gCּG#V@w"Du a̒LU3qVwtrk^ :" 16Naz{(G) ztr7('v LcX%ʰGWRUT|b'Gq5ʉD"_0ܚ눒1Vv"- v4Ұʳ 褖(;,DuD^dRo0UN eC>| O-Kf0I{4ߎ +'E^/Pvi%4w5Kvz`dFÎO}ʤ4ųSjb-#^+0 Z105+~ǕjS[N^/P,.1Wb k a1Cψޖ+R^a xOe ףU;X2M!S ށ93(bW@'w3'n *=SJ[/0 2כĸ)bs:5/شcB0v>`'F!]Uj3e ŕ=s.cL &{@|0$뗷g z2ӇޗrYNޚ%/p*{dBoψNj Z!J md ;Lh f0МbPag1$:Vj j:_A۲dq0CI/z_J:!:5شbuS,y5,-xҁ% 2h Eh5piB1dϒ{b<ÉԋٮWL'{IQNޜ+Ljڝݯޜ ĎyGt+ЬK%+V_Fh[F5#7x'`זQܚlz%xz&z"^1ĕ^dWQ4MFb:5/K(ͣoo{5BټAAͣ&a͒ gVBԕzpJɬT֖1!'cV`^u y+[Z`2"LØw#Ž`#0e[qoFBB9+vfC38;h si<RyAPCj ZmǭY/%ܚ%xd}05K^p:צ9Jt;DE L|UvGZPjLjz>A UrT+^ܚz1dޞ%7 0„1yV4B`2]' ܚ c+wC,Y1Uq~L0'5,XMttb9+n(O$\yOKF0oM!z'`;nR@RRb(]'YrVL t$_ -IH)T[^JR?A:%3f $M }j Jz,w.F7 q` {Ӆ9s;Qv,9_Ǘ򄘮uDE T C> j!lޔ>$ iÂB}l2/) K3d z&Sbȼ)%=Kn0P^m&L''}B KԚ~IE21P+f Ta95MqH9N^ 2lV̴p[fPXt˜vUA`fp(4, Pb:%36\@93 *@ C9.g('qUbCDN>I}54a 04OyC>񀣤JdiEUxsrT] :WlT!^҂FEN%u \(\"Jy@9u!*efRs9{Z18,`ӫ(kG+[Mo%J(/uBtRĐ4}͜`;z8k:bg\X{#z`RhK-! MNm7PXr45 Xeup.D~v[%FA B+-ncKÖ%Y/PzAFH@tRV*{J >h5Q6L&R.0x,ua+ao.֬@&9Mz#%|T EkN.xAE-MxP\ДgڱD@qt] ~au4~gV`6!t]ǕcF=?,V-k.`h ,NEYhA<'ojpXTUGJjEϲN揢2dATD'T<5^k( ٢tR+Rn}؛IACQɭ-=kM4(ŢJ,Eaʊ*5QY<(qX؊E%Ru:*+G/hNÔ%MWNF\h?&)iLǒh5ZT=XI/BKby$Xy2䤮ҮlQ靲X#`ʽ hQ⏍ҐX5e>4G{Bܕ-*qZI\ =!M..{wbz(FU,z K#s!M&eqdOROryj',2qޱurO軻m"bÿ5jk!}JkLܰ1S@/&*긢jvKNذ{ڷc%c ɮcx+-b:sr_͈Zˎ0*Ȥ ژP8bc|Xx42ֺ}|*&>iѱ1^s:eX ZzY1#&<&~mXui5Iք^^A޿YlNEvps2D+Y|`dO^mc=T%Pu:0X_.wB:5&"堈BdRd$-F\'&󆎅y;@MsiIɼY¨cͱ ePo<,^nM=FE$- őH)QFaQ K+d~=O^s&"Q YC{޹ Ԇ? P&rL2Iݐ; 1&bGo/Gs[zY 2|gU{~d kڇԵ8-_Z#I w"i03ZàӖ Z1p4`bnqN>M:rI Aǒ\]bѩQbd^N4/.c1hxC=V )-hi42t&Q jԻ0\aMUE2ASbaӴ)"u|{~\T-Uf+v54pt*u}׊ɱH`]$tS f׍GJ/Vة8,Bf`NS#{hmΨd.csI+J;u&2 :D^`;Mki7LjM=jE(-h.nZyd=j&J/VWD'Z #⳦U]&B0!u0각 fk Ԋu*OǺak u _{xe!DGEZ#苿Jp_Ġ!;+wrSV^o?Cx8?g| 5nj ޘ3_ZUbgCl|d( D񿪲fHdxfH4Swf2&Y.o Z4 8czJT|Θ /bv:+f[3ΘkSFJN7d{Ƥ_7˼ 1k#gUP1gc17'ooZ48cwc|6(1#Gf_QfZќj_hny?>VoMDLC)fu^lMMSi3;wK?2԰%*9Cy~|?P'E|>T}t|Rz>T}r|R_T}v3|R߹?S>USwOI|>Qߩ?R|ުO~Oomo՗_?X?P9?Qղ*^mȔ߯T'|D+?"ttV?~y>ߨSq^/a#G<DO՗/o>"o#P_H}G#P`-=WY|D;GOP߬oէO?U@2/TFW>DoԷo?Udp#-SoBmp0DU}>Hmzٕ6( R9U&J$6|g7MR&݆4?kF$|~Ek5-@#ɔ‹olLΔ^Bՙbsכ S;nAM2MpoJy) K"4Z4ed>{SޮXj&:$56&'?xS6oJt ޷ܑΔL?@:.aJ!i2@aa$}2AnHHtih҆5wIo&@r>^tF9ni@! 4M B`G N&oX5zCYz!hD}`OO%9hd\iJ] V!oxz JӼК2b|_6}5.!Ud `>6u p3K,XVfhajOF0وqfD?$6.h$mg3XSOɄz~*'E. -z( -izڠ>73 jDLӈ|?? R<n]7˝4`_91 R:R Æ4? %O +ڑu|gp͸A!.!T狞 dɼHkf&cтT9*Y}{X9?QL {f뭍O<d~y2d'FT:f!KmO枖/ߛg]"/vq9[in @hãoZWu(g蹸vÆl#T"j 򏟉=UszsH?snτyٱ(p#j#Q=B҆l/{6T$T'/dY@amAp$Tno%ъ䩨kpK;7~ w?!S_SQ/׵fŰL>=OfY÷Ɏ ;qi 7oqi蹸\]YѺ{.d#1{dKf. |^AbOOv\8AK;{2Tw-#Ɏ wyiᬰ'F?!_z|B8}`='#'#?y2ZҊdv-ҎhObqh-\mwEx\\oy>c7;~y-]o/-hH(_]31zLL?>M7*3D}(˽fŰa|d6<`;z>#GOk6|S鉇#fM9I[WVǩ=ux}=éd=EB19{oX?z..YVl(b{\>'>N]E\a7Eu$`kv'qlU~Q_DVgzi!pI65 ΐP ǿo. 9GoΎjfmAVKnܓ bh`P})1 0IJI"rC /^GLfeH0<"OnۮƤ̀ݝٙz!N|<_'g;iwY_X/\ QK/x ^oukk z =g3jiJko$s]J~z b}ɫmU}J/ՖF[Kk9J-T{Ritˤ|P"^*Q4r)W"}fO|(GXw &i<.R99Xf/JsT_5ٻbuqvdM:z=iLu=cy׏盃~kqOqIqaa\6ƝM͍iO*^eZٞλ=ʓEÊmzcMWk~%e: ủ664 D;;J׍p~2p 6=a;㲶#p,hΎ1u_jjGuءk Ύr#;4Q6n%a;(w-IoҎ|xbGtVg!ۻM)yf[l>*ѦpOVuvI=Vy4;$b; ߭UzaU#=\WVVX+xv+7WpybGq+VK7~X^vl/b6(ΎG+Y='fGaY@O^~sҊ+ws6-4"O,84[=ZtR ?{ۊm?\ˏǣ; Yp;!Q;CmrVdͅpl aksvn۳;Rhz-~f٭W.ܺ+}Y1Vf'#_WO>N n6 l6ʱi6n^n;x^qǝ2UD7'ή_TUGQJV݊cja:Z=n=[^Uj،XKtÝ;ϥV?Вnk_ֶ)*wĶ&K.?:^іly67*:[yT ?rF ܨt]/Pw+iT.y6 {I!3nTf'ؚ^ʗ P@繲;Df_2P㔽6< &YM#r<%Y=d欚`z|eV~p{Yyd} 7OrP4j +\H@,ހ -12^Bdn=%)9Vk1n4\(!lHlQXP@^c|{y*̅Y)Gj!)/:1fFufT*dӒ{TӢ֐aãDR0P42--a}_ &{kV;=~2_-|P0oe֦W|Sc;mҰi4dV#dDu(޵_lIp;wGw=s6lػ[AJOKOݾ#&"6R%Z^'yoU.Ǩc +; 0~c2 fFЌh>%*fJ3rۚ[* : l%wW5C"o )>ᥕCʓtG(99v=jwDݾ"ןMH-TC$7u(2Sb2MG]I/VvJjFɉxGkighfD{mǶtlƜb+C"]df3d]i\]0Wk;2B>0/0P:J7??44}6pT飁;V#'gX~fJ˒8e޺/єM=4Ek)0R2 0d>)ݞR_5wE!Nbe#CjSP5h<2CS<4MS#:FfwfR(1j8C3!?2ae= ވG&2Ј2{C|0φjِ<@H[7˿/ɔuuK"lݨ:!?YW'g\lJѺE164=goO}hJV/'<\WuA|j3#ç.ަu5<2cٺuug}/1A?[Y7n->cwlVVΈOկ#OVV503;2HP1gCOVnr#:CڣuRuuw 3K [W{CYnVv2%ܮoMapS 1!?2Კ<ɈG&[#€3ܣi{φl[C4C[}vW7p|=߮oM(8Clάφ p Α5MLi?ZY[ 0%Ԧq2M?ZY[knd̲ΐVφdem)N+~rڳhemuZY- qL~eu2M54L+KܗegHyę>$>ΫА qxφ-յk}ypm D0^beOڪ{OllK|6d?G$Y(lLie Wg+W֖ꑜ!3dnInpߝڧ~^Y?%75S۴nVz 4Lڧ5&sQNI0vxd?l6+ib{ t|s[|oK}Kmg; f :n |C{~m9(>D[ahREn`߇,$C~ibT4߇CU.Eq~Esz\o^~;}ۯVEדz?]C3٠dc yTv39GS"&zhDy"do꯿/X.7[9+pUC8fCcs9Nwܺ׿גfoߦ]Z'߆h9߫o/{[o^}ǴXfZo?7?п [ӆߦq~oI[?nu޶8cimåF3cqr[Wsc?!liL֬{%{gy,ANTq;jnoF*7ZC'nV:cז⬿YmnV4z?iwˁ_Wsj۔ KX u^u~߆r{{۷Iq(>֯I-]ZcBP-F=`k0T} z鏶ȋ_qjOOͬ?"/$F՟MI錄;sǸb⦷L/7C,=WMc\W; ^v6uz_\sLsBw´:Yݠ/tVzR[煮>TFllkm{h ۥ5',gC vhmK^mm4Kj?`{[Vk9nV1K~Nrj8~C ݬffNvj8~C Zi,I8cIvmm4K~]ߝIuv-O.7NۮE]4r?ݦ,N]ZFddt6eqڔzc|쟨~a4㤬Zjekdpixnܞ,No|?C?nɢۓ鍏Һׯ7d'zA]ݢq;ѽ+LhEkudqړrigw{dqړzice Ωwݤiۥu!8mʒ۔iSu]B546emm}7ց6eizviݪgͩw6eiڔҺWS6empiݪǖl?GYr;4RNʱ+nVK~~U+nVZIֽ~~U+nVZɗI?h8FgZŏu~k=4~m/nVmZ)֭imʴM+r9u;QߜO,P;ʃMu$˲Ɩܑ:% Bel58 d>q|\zaupXK@QG6N"J؊/W:cqL>s@J,q F19xr.HbK5 E:lQLߚ8aH]{pe~\D/Z-G]5W WGҢ6(pHC:lYuiu`UJ4U[E]:y^")Ak)/-q397No9;M_dhVo!@o"fV3rWsgǍ^Qygkg+1Sgտ^VZ,p ʉCzM+roa@o#>0{VPΩB6\zMlQ FA@럴+䰶Q'h`e)yz2`AjD0MreȎP6,nP.,uT%7>z+14+ʕ#D$: }F^`G- rz:;33G|Ly ArUWZb!2?Hl!j [&A@!wtr 蠇QPO"[̚^T́2Go4:bY3G -O3H'w yX:$SꝏmFjNre"RU$G·Ro'fyi^y/wrTU=Vx N#&P2$'zGkS rnd$ILlU[# DAp) JL0Mre ɡ 2 `@fCtr7(Pa )-Ė2DǗ*X% ܇KVPdVgg9,"IxRFg3x -\@|+XBhQ H.E<7U)4Χ+l¿cuf MO3L'f-+Bs'-ĬBpvш•r)^ @xIi/ f1L'wrf!mFŒKdpGҨӖTKY,x:DKl$B/0xR9$9o`==8& ^cR֙L~OĢ%%&r@vir7(~2܎ѩLR7!񄧄?-lu Ң!ǥWG}$dE>xK19|*ok"2oaiT+ե Dc\iȒ$bgKԄWы2> r-E(uL*Z( ^VCrWSZ )mPD4 )R-LhaŋIl)I 7|BH03F.Rc9S ȕմS闒6Z좲nwp&2O16Լ g9FWQ0xkB=z!E(iiÈ̦F6%OLSDfN2DwJ`8uGгXn@nXNzs,~Yӝ9+)l's30 ʕ$/ks72H'f2L'g(oPY7ѭK (a ʙZS/2:D ]1d𠄇 :Siך;rz:3k'lHARJËÒl(yiQ{R_Ȍ|@c܇kf6 d0Gaw(Dmz](*OM T Y ɽ,B13 s0U2 s2 I!)%dksAV,@P]{qKuyp쇣⣥4+ÆtrW kJ*Cm<+Zo3(A9s#p'Qo%0MP3T+(B۩̒5JXMSHB#oYP^?O ik$ t1-8*aKx*?%Y@6t+1\!u ,*I5>@EZݠ\TBxFF-̆(WFE/DǦ&Ĵ ^ΡU {_锕fmČ(%G~GmH`XNJ=FmYs/azGh)fͽrzq4\E"J3qWN/P4˜^ZYs/šo5 ͅ}~1Q7zDorZ&^~@qEʐ:Vq*FɻP۲fa9r',MFxy[_Le7_ n:%ibJ& zk+ veΐޜ Wrzqx F zk3 khq S1-K j7p∤:Do͚L2ڝun0=kӫ'zg=1=W3bq}@'R |]tMU^PV.ŇGn~Ao"bp&&tA(0w C,Ö A+r"rly\gY`Za7yv_gIBm<έ,+ukgʻgo ]bΗGN:ONUo^: ]y40Mk5jfEÖKd-s1 zpDzi&Rl m.TKR. Ds97dpWפ]*՛7*$(]$&#}c*{rh]Պd4JѨ)z@B1An2ɬLHimÎ%ki5r|p1YI^ّJLnu&ualo$ FYs~k栁irH];f-/BhR(];AzWfTnIb1w4}FMnMBJݹ0UVݢ9KRl*rq- Q @ZNAFvFޑh3LvW4fI J(dw s$3> wɭi]ay3ry4Įhڏ/(Z{ ZW@HyrCTEĺC֪* N R73+ZQE -}J`]r7JcGFԎ% Vv9aID6A_H{@ WޯQUj&hNE4fEZ3dirkjh.ې d 93%4JDc{xVݢ5bԅQIٮۥc鰼:4x\KlN]eJr}OeMBN dF 8 [l#@Ö%+6Z^A+!d0D{@LQX*,׬jF`q])u8 Ѥ!bjer+GX9io[rh* VB14e&5DÖ٣:zt*'u%@R"z.t%%2k%طh7{vgR]Lm/vgRJb!Mb͉9v<);&wC:cI,֓nڿHrTu]:ge]YfEʗ%s d~ʽȐ-[`ͺ~q/U;M 8ٽ!tϣУTSؼb%+8?I 'ئHvY#GBW컞}12WٽtľW7iaU=9L{A/ʏ{{P>+bo.w[n4m*nwjBP":9~~s:C4e\]4|&+m#'R ƙ6]߆ tRl^jVNASp f&t{J+h\D՚Ѕ$绎RyHLj]]JD^Pп DA< FD\U U΅6W#f̅C LwV/\_ ӿn8xe/oGrd|qY>3D*wlxk * q_<5Lb+gVk:xHw@TVhV/H\^(wn\1Kʃ`ʠ{,^(D_i$m(Յu%q 8}rV?Ӹدz.p/Lt D.<{>Q]o{>?>~mC;b]VUx}~È>Q$K㠞~hF[Sa We梁 OVa߇|iHO"]Yˆ"y̪FW7u"ϕ>n{Y+W7 d^Z/B\p9ENu06㪮#cl6?ֽ [?#O?KTWjF?˺1l+ [ܬ~Y7OÛ.,E6e|i=?sJv[i@)ōOU5cgTUM#>J9XPj=~~i$qdzSݳr^gUlgvi=x?1nCZ i ~B=ݟ9VL$151:W13"gxiݻ?3}e]5MT5nt'UnDEN}Vh5_G?UAVkz-փ3{i,;cG*X/'4i֩̚&i|ۥ̚&o/{Tl|%w?NgTm|[mh/{gT 6^u&ӂu~f-Ng|ݠZ6Z #Zs6M-]ZLkmڴ]kҺA5]kn֦Z+փ3ݷ{|~?x=sۮ5]kvKv 1]Z'OmTۮiunvO/Vg]{:u]n֧փ3ϩZw۵>m~i9 ȫ)åu MYw>mzMɺۓiOӥ5d5u'nO֧=Yϗֽ =Yw{>zMɺۓ_dldLc8~iO֯{GSon|ݞOo}g=mOnaq/{gqZ۞{ˆ1]Zό%{۔9/{'6emåuS[t#܈Mjnݺ?2<ٹJ{'Vj on얓n^m6w:9g#E"EoWsCBu%uo/6~ziݺ?PmGv an Oϭ'~~i?m7]ZO|n ImWsk4BŸ6{Kgcx1irO'~roiu,Bv=~ti=?W'o/{gN8dm˥u&:nuS嫀9ܺ1m(K9nL4Һf vdئQփgo9~=CkqB1؎,{{ddH$g$ŕ@AR/x;LPd H|-T+[3*K0!.Uo"fR(:qxreZ" ~,/m!d5HgBi)wiA0|Zk D[*9̆nT.L4]o͎bB†g6ox=i[>5Z/\#{f /X+G⓫Յ[;4 \=JԂZkQΖ*ci۵RI*,H]ŚFV^ istGjZgdf*V2Bjj-UVXZ]"E uyZeitjk咤^ZڭU ffiRV[lnTR$ fxpB#-[,U"SfyśMyԚ..kvk UU%F^mtle>hjBg *ٲԵQS<4JK5~F ~CPgX _M֦Ikx)Cލ %6iZxM^Z|G Zefclm ʅ5T۪.q o*}TY^h-UKR!MzS E{k%d8pK_[Z:BZK'ݘMύKhZ;I#U^-5$l4.b(עxfY$ѳMV.զbPCM"nkM."Yּ"mL\X4\ol0"W%mGV. L{HIJ~+14K`vmTl@^ ٽPYjrvQe kHTejuQt9:)FunnDqGR+tDZkS380ՌQxAt^;V0Vzmn{B ϪRA:14T'+Ds2* Rg)B!~+d)~)~S%WC 7,((@x~SFTB1<[,wl D 2٭up ,YEY z~\P(L pcKs7LgZ~EJlU>ijT[:tTFCh@7<)bnJC6R zA0v6.0#^Vb+=\O4h2L;R^ڭu~D[804+g>ITF"27*VSBBƈrFF@+ ԗ+ƙy" m;򩲆k<ԗ ƅ~1l _ 94#N}Y3W`Tgĩ7Ksyːͭ.Sw , PSoL! m|08,W'ZbTޘǛzrewW+0N4v\q#`8'0~4̄9gͿr~%/$uǔެW+N B1nj`98[8= OSo,2 Ly9gr^q~]8 ,YXέ_oC-++pӑ*XqK=7v(6M]Yr[t x32=Yr[d ~3^n,Wޫ``;Dߗ%{FU)ґwr8+Nb"Wh#8ṞWާ@2x'K38g<ߗ%{tx֨8<˒u~1h)x}o+'? ]hhnLgLߟʻ%ax7ueŸR8*"9XF?Vl+JVs(, ˙s\y@i-~Dn0}('CB1D[+Έ7W҉}jfc-WDߗ%{b¾֟x|x{^y8z|8Lߟ%Jh_DSQsWޯhiZb}o'#b^k?M=Y(* >x%K@iYW+G+b֋3 P1 "CvC^{f`W=,T#"@@ ,X)N DQmi8\X2g I et{seHxXU#5 a0]_V,UN#?5tv3)<ߗ%˼⼳~4TAt}YWv\0}o+(}$  gɾ~q b8i̗S}Z!(%n\Lgs Qq % rnTVY gHߝ%˹RmM=pY2ӯq0Q~+ԑ ˹-؀Dt}|G,bW`P!yui895 ˹D<ΒgpX wfNq,$udſ.1+,`K d<Ix'Wnԙ~bXr:!ެX;.gr~RljiLHpY2[nDY'F r~҅Xwxp.gDߛ5 kxaz&3jխOx'KtÄ{f_9q>fɾn [XY[[9x8QO3W3kxGr &˒Ѓdԃ#XY3_42Zgr~h1NjqY30P'˛M}YO/1̿+ǒ|d@2ƥrey9X/PPXЙ6tNL,f9~Fj ;a9D0ȑ vF}bX+0jȣ|_l!iyBf er^ѹm9f+L,@@;A27h'gW.z`$!X\5zDߗ?+t33&aUB6R1*4R.F3)d8cbWk*%4~s~Aq'Q9>Xvd6?IhľBgKhVE4Y2Pf#+zPPbZ*hp8VWjUBǐSjn T"bqfƕ.(F(ZVx]i\&rF܁l[h]%u&s}|y7qIFa :˵Q@J}'bpfU".EAipըVuq]͚UZ;EZmQi@ ^PJf]a2+mYl`ݚU ;Aʛqtxai\ZRy<ƾd(;P5>yYjU|!|xCPѫSB2ji|$uIt[38bYhv/h]_V5|٠.3ZZf |p/-CZ\=kbOքo衠@ޏ uVY tim0}Įد0%iݠ\]^FNmeM?j**fMbyAraW1QTiVk2W@ͽJPc[P1`tVkI-Q.6%z4?ٽrE<>Hy-t z& k "Wfg2&>x<]Y I[{jpfuP*]&iRʔC_`;%%=)*;V4dΞwGP)-IT!ݚ1] ":TfA*V1ߤG=V Z/v"tI"-xJy,Ьn ΤDVA QƝC^/J^bfq_7X 6}b\)OP M@3SdeJObx$^pxfr1BA-?O=$ƕ -,+'Ν "T'`l^л $_>8*bzQ| L;8RkCs6/oGw~ cdrYo K'p g@4ǒ#{-ozm _&}3nUg WNLyXY pyR{q,~ 4ʫJvUaN{o{G@i?;8yQP< 5:lʋYӷG)v+9 oؼ(L߁9#%2a'^xfuU][R^ w(Kl=gnI-fi+ "{ABB߁Y kᙍ>9_K% K YmeC??|-ƿmßIۣ_;oLmhqC-퟾3wGB/Gw>oW Ѓ(Ub| JF^O1r)Ԗde([F+] A:dk:~qb aqgxr*+GjFfʑ r& !I %DD8:\;{D~x=q/H~ؠ&4ѬdE> 㒠_AI Ow~cBͽR *a&T yR6$xC@ow.űD#trL;6IHceb$DW`lH a4v`8nl yEr!\G30N X1l,aZdIE[$ӨpuR[j\R~ ]N80q4^ΒŵlBƠ8;0Qm $- V ZbaEd )fVE-J\0$fwsQ@ >dg6נG͵/7o`3mMP5 AzޘjUetѬrcn`kkJˉ'ENC8kgy韰(.6_r#D5|w(2yje< <7PucJ$o:>a<aN1(U55un6+nĬ1F0#H "``@#D:"4nt01SriAb'(q#YЅFSDgwsbZ!݃U jyY7B;]1n^UM1;ۉv(FHhXh/"h K&fuFЬ~8rQa[K +?>.%rC~4ޡBJ1 Vpq/'`<ݸTAҼi 9k@|-F!5o ! z3Ϟ3Z%"]T7HK ߿3 .a79= FC^WUy P+~XZeiCaVWi@$.H MDQPX$ cq˅A5 h @%y y83u!ɟ1*cer\_0 [hEC%&b:0uTAejEV{EX\9i Z " F_9U ۉp\W0R8d'v}Rk^4wbeY\~ee=mx]"7 i & g@eְ̯rA gPǮjpz 1,5H gfPH~ F07Kdm#+7\eIY]2"7'au3` NYEr|HxS*RdvvEʈߊK`.vfy tCtV#+ ,(K #ZҬĜBWݠWF W~ Hf(7l4#Q P L >""*-5̓qv׮ZF7oMw#F~tcuDžp!T!ԚE96xvjFp$8~9[0A9!I#xd:oI懝+xQZj.a[ KE\]pFiow 2+070(ͽ8ܽ:#hVBl^Q1J NEyjp2]k`lJ`xD: M2 /B(#{)cҧ:7cgwV&8{@e ).-5UJόF)"䚥~"Zde[ojz!ۚWVV?`85zԈq|kL) II13}e\ RJv 2`߂yyr4cџ ("N~@teӜ9$"h>[AXV7^3=j8K8iq0ƻ&4M)Lf{ /2NJhLbsJp5&BxZZ%g(< vV#u1i=(L)FNlpB÷"M4 y+(ݱ0h!3Ǭ*צ(s#ba~,4h#࢈bjB\GeS۝A[07L/K"`Q&e20gu~mQdwd5ky}sV#k:Nˡ`k'H͕] KЖ++6wF!BÀZ": "ML~adVF 7CaV?`0jpF0s5K:ib:+` kYeyע&-vD9 U}r^78X,қO"[>%܋L!ꍫcd'Y{X*Q89a:CA)̡qsa:PX~Rf0 Cq??ӎUvdR *|F+MjwO=!O $YQBJbMXq'MQCg<׏S8X5}_a mX=#h`{=0v1kkGˎ,YN;ViqxEE1 {p'l; {@I8;a,5s۟Pk@+[3ͯ J0Dguq {ƇS;MȢi9Jl>W``:Ff͒)Pa$~^wu,aui㳪ypIs 3ͳ{Go X6NX_`:.%7:O'\ym? 5;4lh'Kv0 4A0 YUS:j,£U qXLO!#y.yxCtvkv INU|/P0@VoF31FoV axrDt=<x5Q0ʍnpj6@cN1}$ʂ% 1\u8DkrvKw 9c Oua3U9k, wusu堆͒] t_?JMMU0ߑ%;8mژooP[_p9ѯzS@^Q\tcjpLcr=#wo} "cƙa!D ٭YޯJ h",Yic㠩< eE7 Ns2JuB,_71l\3O|rA%b+~yc6roBSFCQ"UGjf{D[&fYr[LtwQA >]S@azOxU4T[q@z5O_T9w(ϐO wm0Fo1)وnĩ7(N~A4lae^;7Eg GB1*jgNg%OXnQ(,8ًK9}0Ҏ40.fƚ# =#vĹhz^D Voe/K~e@&D z a0X`\0 &Naެ¢ϖʑ'Do503G['W>Nk~0p:b0Ѭ +Ar ZS@H V"ܑ7xQ>S^;KM]AiFlsό`PoCm5uGF0PT@hB ~;_e<9I <]O` 2vm@Ҹ;kVH]HԏH͈+yFMWs͚<E~J+] Vp|@05%Ń/αg99^M,94Sռ3(MAHi$8t޼3җbkhgbh 9d޼ccl_!_Lg̛7w&Iz6إ%ZPy8II8 Qʱq*Gn3I r)UXͬnɼR-[Z|e '|CzG<4.Dz`:g x&2ym%_ܿjI[$) &TW9EE7.(L N帧r>GGl5 1 1ؤhLh #x/LgrM"K.bI|j\ ^M`وɒFI]1i,xmw4r]1hQI6נ4QTJ>VB }*wtvk.œ&ˇE!hdpfME>4QOJS\BR7 .Rӭ2Tfx1ZT. A)zNhv?P^u1s.LE@MC]Q]T'\4h5y4b.l L?ZAZEyйcZT !&(=2owX*m#ϠF-L.0(ސw#DTgmJmԋ{a9Zάc6,17 Lmvpub E͔1=ѻ92r2ՋR;軑NS"5l_qyA t b5B| Jޕ-" A־1=B2[lR\ĖD5Af ZPAт S'hVk"/IKnO*WSjPLcrT5XQ"K ~1!5&4GsTB2Te05(i[yJUSaSq R*Zyy0)3H<H[ü,vk"oĨj!Mvb6tvk*o쨪I) G1ilyjIR N`)HAH a)f&JɎӟicf휔ZyY $RNE/"%f@0Pn,+RK iDq `sڍ7sY" ;VbZʦZ֤ޣvc18nrO&gì UH꼧v/ 3 =;eg9/ \@_ǕfGHg&6LdZo SV@gʋ%tHDž+ \g 8R#aDJ#b3Dgʋe&Y͚I霧r6c>-DA /CQZϨYMaaz*6Z0]Q,a2ZC5Z<C bbFwG$=vp^{Gʳ(Ad]R-dٽU "bŜUّn boFn* Dh6RѪQ Z/D-xeb>nGCS!`uUr:0;'ّj30Fw Ӂ<Is] ˻&QwLfO$MUwv/xޒ"#1$FnYyީH_IEx@i06nN=bfnUAD\gy4&m/2Q[7({NIzT##sQļaB9i!{'e?P7n8gw+Bp;S0E?]1%Æhex ^5d\a;9VDg\'Pu ,QZR  Lo 'MZ(|`:Lo|+(Ҥ˒y-{!"åI <*g!iY`޲Pٻr;/àJ0Dfv uIXqT"ɳ q"s6kƷ,{K]6 Qr[r&;x;j1+e0IILO.V_ n3<2r]u|Yy߱CDžp .wݬ^^i~LWAt)EH&ڸSFͦW&1 f11`@b|pj,ƍE;4y2rWP\݈;dk>X(&1 ;$qɂzۚ#+ꙥ=GFF>R37WD@%˜,y(1+XW+YKimNqP8.f&%Ɗ֍ܸ.ZH/ud֚ՕzˑqQVP!RYatdGFo\)G:CL)$H4/_.[D7l^7C}(>R6PP}[3Y`#el<72WDg$Qy/@Қ0*V/ި9| Zc'n^)Uk4$>4i>ӳQJI ,b쮴95BqnpdmTW1 Zs6dIʋ1FT?POf-,;a/>7ZP{H fLH.6f#nc=:vK8F72qu"idCs6k gdoȸ7x)xpƂD­3m8LnƤ|d5o\9%*0HI;52N:^fH$#TV͚\pN;J0ȏ޹TI%qjf^J-A%[s33H5׈NwlnYb;JBƝ'EU8~@|(T4QM]7 _gf{m&.pN8^6#q̎ ZP'eLueFuQf-M AsԽ wT^e#42'KWqW2!@$i:* D!z av}Ѕg_nŝd^rkg?2uSSu y-ٽ`J>0~`j@ ͝HZ(ٮ?n9ig~y $nf;}Bg_|_q_ iX^lVV4׋%3X}v5 gHMv90rRw gj>PDge8]2'ћg>.$NV%pJJV@gzMvV7#,Y+0z k+͚\5NjOj<HW4׏}D950~ndpt|!"G;hd }'b,Tg)ŮY=cX*;r奞-9w(p|tv2cBLqձ}&jD Mb@+[iBYrK{RDrV/+0\SFJћ5#݉WDߛ5 LYI3Yk?% ;Hx}7NYk?pȣ sY1S@$iaJ7 \|W<`&o\F 6 'hW;@A}wԙgFK* ~tv?hh=PT !ެ9E}BXm;-h8N58>hF@1ag [9sv/P?p(ox D'=zv^ J˚eKW`^ 1;p7Csy{2Tf_tb:5عH Aj*Q 1:s8QvS@`,rwe F&A\~'3'0OkVy^3;.bH^@;}ц 60\ K;yٽ;L!WDg ,Aoa@F:#:l`U0>G[e^ԅF)N/K60ԪvVEAs⩏3[[`(Uì-|Y,@ l`Jf= 'љ'un3R; btf F^9Q!^W"`'8g,;ͭJJmc+6<s4\՚\?цgQg8g #|:A(ءY b<:GηDlb:;ݔ:U1y1ܴ;ï)83{ .cAWLg~1h?(6@WP eEC#I9)%tV/J"h#7CzdYzo;%3<1|}9\\/)9`x=ܪf#}gCAֆ`ygΡ gPSZ -S:Y;6h9DgwrB(V5auCw=1L2A :<ݯ<8^p_`41L6AY1}Q4V' F`7k~0>'4g39FC lUu頖`6ޫ҈#ĒGj;ƚjd㻲;@ !f D8A,hGkֆGtV/­wr2[ F%b`W8Ы%*:r #o)Oh?u*Zx3jrf02yE(4C({iy8:xȒo Qaow a$6wԙ7Y#!aEsv77gue2.(nf'J5r6:;YDH/PW+f&f>f0n3e9Y bhx%7o*,a)$mB.-<ff,fЏI,@M27e52rAu(:םQZSZل9pH05*[m@VkZUɤF$ Yٸ]PJܤ %fy)mۭ_PqԎ:dk757o&@4Wk<#V ;f`L:c/YGv{t 5ҫzVU83p=S5Y*`` <{A#(mQW<ɒSdWT,e{AE ĀU>*Uϼ!:+gbޞl7Q0Y@[d$=r=By74k6kr/ I;EP*J 8^vϳPXUb4&zO'/ȣ4U:{ lnLE1Frnq`(gP.U &l%7QV]{AJ9* V% cN?{A2JdƨQ apʛzAIsU9 ^PzH2n:㬚.Gm%iL.ڐ?X53E^Py*c$T/wWuAi/,i8M,MˑV5n"kժSZ1e"̠j)rIZ: J[pցSGJ՘!&}Lojw3Y0QwuAMm.+ar'L#G#j2ԁ^yLNꮸ&4MƄ)j,;ˆc&M;hUBhv/J1|GfM0tSg QWLvZ4C&M Y_LHTDŽ#K(Ɖ V? 0Cɲg tOT@g&"e2͕8ʊz`N#޺lpB0(kCGBLP*#eB덬̮Qq3"W*V/hv^H‘UHbӣڽ!๒eB A^r0Dg֋u'S"7ІWDg7hM"UfmpIK!qpL }@4^G&4p3 8@zAItdDؒJD ٽ HdnZu+!sZSDtތLDQ([̧E$VY4ڽ fdnfԧB &0AzیY9YbH<Ӳ|WLgwrʉ W~Z^V1AVDtIG!bǜv/(W11TT廛a:54"EP">9C Y I~I~u2%U(+Z{&˪ʋ5ڦ!^ LBLܓB{ z/*PDBTdLF\hFLۘ7a": 9DF+":ބeMӬFÉNa f?"yB>BE"&Uw=Y0$_ J,x],SZB1SzW: GOdL-SV/h SQ 2*#] ٽ A$u,aUZ83VgGuV/ sv#UQdKI"lT*Ə#a-6/h,rS1]Yw FU6)!A!p!|썌@TW;G>9f&4|C__=OoA]*p>Ð= Oh+h>qBV;2:+2m 1U'R:"v~#|jp,o}drƮ x #+\|X sM.T_CG$N[`Иg67wJ38 ,[ 0@v׫ eޡ칼|HP Ä~@U5 oŊ&|DaN=gnReo܏ I#]3i )p+lZ `nPdoߏ ɷ9>py'-L^aus9}K`m0ڶ6Wߦ*P9H4ّ|+zи~D?l"#Y[ y+O #4=\9lx΃lVF lqd\1znE ۭ@dA~{@9 n\ JE$ȏM?.j9;w L'$AʪPI:oFjAD{ "*G~Gn婼2遳IPi(f`j": X(D"uIUc~R-2?[ N{NzA 1,+qph,Gs6W&x21^U׷S2nԔz  B~`T"6CVvSŁk8%~q.NfjA;n|b~5Lq0#XMH]hYs r#eu>B 3@cvLNqs^G$N I6asϣ ?P|!*!<9&PDP>{Y`U! ^ g&xDHYu}e Dg0&zAXd~TtV<Ո8cęCNCxVn @ockC8s"8~d!tv@cTBM=~X:y[TvY*0B-凱HdV7Z%ӎwZ+},qI󫕺q8&}#C(N}PJᔱR&ȡ4/@A\,stv56U%J0Lߟe|[7#&LgOzj:ݹ=~f]Y&YyȐ\jvo<|cK ױ;0Z|_Igd8l'DgqlyX׺Mgli.ȼ"6 3ƭ+)k9ǩ٭cԚhJ0DߛedR ݫN†UU|V7STҼ&b8ي^)Y,[%y_s>^5 ۯntnO+<9ue>e5 2*;c``}쯽3,.xETrD5#wD)AﰻA9G&cG'ٱz203Q:2~ 0(i+P̩?$2"$ʽ_ՋȤ*I;Z "N}y$"RX`*#ssD&W`@ O| O:27NS_^>*1E&t@keא9&IOe6B gu%*iªRXqJΤLo1JcT.5*y_5z񶳳B ~aXinU6_kp>-p]Uxe1Wx/`Ut+"/P[>d\7Wvju&f*]>A _RdX p嬴;jD|e|HP*/2]'_!t[eP@bLml$w^A1%ko(WcQͬR]"wB0Dɕot>jwkgDXƅ [3B& L7N3MO}83sZջ *%;DK,1W"sE惬V,>"ppR\>Y88Z7񠢛,4RϠ[224cL|w 4 Q̔]JNBfg0eF)9t}D @Tm$B#Je_Y` acXGU< ۳Z9 ʖJք;sqtrefg(CR삢RRصcRHVdhΡ`1TQikT/VFWSޑ4zrnfx4-%W9Κrվ& #)|;%cw/!> _W Y9 K30(A0Hja`]/jl{'"oi5; U13r^pQm]IeE9J?]@$U NB~zQfdP2jѕ3A2Z歩PعO;6P;wdbH <!N9&&Ni & 8vČ _(*FRraa1# ӻ nA<bDˆT|"?E 4lPhF@+*1C 4B@(E!:+wTӑl+0#{#E;DD6ǛVQjƴ4;Y`Z/r| l\7ed9tt)}ՔFL djf@ E?wUtV(V݋ xIo˒ N5ij+Vi&=o\ȷi9ꌺZ9Q-%+\4uJ:e&qtvUG;bfBG[{-n#0q!Idv[ZSBP{b15UT-̎&S[J<~⠁ʹvClIW~(- q*,"OeJ Js6SFV/auE=A{UΠn|٭`2mCcI~&|HcSnpt4ۭy$Ǥg:0UM^>:AU8)9e2UfJ^>q{I)1ѝ#plִO.TzG6{hdegσ+y4=IF+;B! NmvG}$+5ٽ|BMwMd]LRoa`:u2:#]Ӭ>_+K^>7R 5]5;어O&1'#Y0;e!A𫙙HgG瓱¢FbVW3S k э#ʙb0I?>kvHq|MRnM~y+Yc\\G9ްS3q4 iG;G~k15&k"ITW f|&Ti3*F : r>nML(Ƕ74ͽ_:!=mZMR}@;Sm0&nMT=޻w~W#٥kY ~vvS%NU)zZ 2|@zwVoՙnk"6K{V>6I9M6j惡8%B{lMԲ@`肼k%]ĆNWbi1ޞUaVLj݋8+(a}oQJˆCdꃦ[oZ8>Sż%փS#:ZRZHV3V1CwNڰIW %n*,BP9u:RCU;Mq j*4d٭ԏSpF&]VY;uI!GfHvsDϝ.ᒃ3+w IUk&!Vق^ٽHSG g- ;ϋ:14q:bGOuu\u1Y(*sEaTe"6Ctv)a) GB0݋u6"#Yɰ˵j%?#fF =rsQ,gNVG~.l0v˄yZHUTdT7n& `.)M':؀u EQ;Tp ;IN(2E:x[ dQ|[iv/ԡ_t[P.v^64v/%!~BDj~14W*E[`5x3EzK;:ɂhprO!` ʰpV;2I)k}`>ֽN#8e)#Y9 bB['~Qɺ>~GhF+06,6=sWY2be)c/ZGxHPO(?P͕Ŵ-:A=e *B[PyH'fqfNPO/6Hd+ š2ː40BP(DUJ$a1٭ɍ/<(9oo=|߶g? k :>l_Ͽ7?ݽ0|~w?8sS!;1(bQIz19;x oD˾gVoaw~*39>&4uUΎ9렎;D~ U.5FXI2ysyIo/@=v7fsυK?^.o_Zt 1pi=2xUux 5Nbr$Q(F5QҺܨf7yticWasFL/{: 1Oo~.Ӡ렪{l˷QX}nOo|c;Uyvj/8Mylփn|鿨8D&ڹ+/:9c[KkKaPmleiѲ_ZZw;}xn=Gx6Tя(Oud?Mn|Q|Bvrk/|,Tznpgu0O'~Le}rd!sjBK=}^};S=VL/QO.^ԝnӈK?OW݆1Ttȉ~aTng?uN4׭۠V[Gz6`ZuzF:?QF:ψl~:8Z[w;}xnaT/6Wk~vj=Gw6huڠriyqTӪۧiVu`mתۮiVۥw'֭oʗmڄ.B zeonܦMB.X9os6MmZi|8w6mmZNsAzo}=x66mmڴikҺϻM[s6mZikn֦M[˗ۚ 5NiʥuIF]'űoh~?x%?6'knO֦7M vݓpݞ=Y.{o3nOݞO{/ ɺۓ ۥu_oɺۓiOK?pD@zwOϭ9nOݞO{.{ 9nOݞO{/L9nS&DuM֭{{)~u_ֽ̗{@vFA53uoNua8mͺۚi&Һu(sfm5Һw sfm5Һu*G<:0Қ_Z'*5%@ڞXW;c8mnkbMڨ{)c֩1so{2QgQ٩}BmqQɍ!jng`=!c_|VdZw;}xnq=6e(磴|i=O۞ }\ZGVڞ c3477 o]Z%w;}xng=YmO_Z'X;1}wBe6=~f6GnhJ[`/ͿȎc19~G6U?px6wk~?xE{ ~;ֽۑAPiPӥa}CٍjqZq̗mmqFNX.{ 9FٽN"潺QmnT4ҺEHݛ&42=oοm -Fa~7lmU7k,93f eIտ߬:&-16wܺQ§Z Qo.[ߑ7?MnlFڽS9 |s4pbd]'0cB6n@f-2kb9;9ޢ  ܜ@͏t)U]2H.ٹѲ/Y >rsvW GT-_0yg ȅ#D2:175SrS ,n Qb/y=PkE]#x:;7YwK#S%E\ ^ (KIab&0"VCtv6 ,bRj?Q 1rdٓVԒ73A93}D:PɨȞ%o%f2LgwE}.tFtadj 1 ʉ#Adruy(tgV7g揬7;r#4zCTH\?ܫ]Zxf1D,@/Fv<:B|pP(ynG;]ϗ3Q()V;wA%nA)jQ!dufwr#?B[ӄFbraAw>(-L0-%ݠB2ƍkM'Kv3$;Z2ϟ_ѧMn0μ"~ l & jHWkݠ\CGoWVi$6`(WNXXSOW9Dg6<wE"?!3G4.qtUMg0vvt6Zutiīlް7؁xe6QnC{%tӜq-3 }zInzDL.(7"oH|"7!4ʆ /kvP4VTnP,IJEs7LgwEr0)@)]ܴtO>fm.v0@ҿ~8t`5³eE4TٚC#Hq%ciZuMĬnP.# Z9W WivD!irΙ-x)P-Gx>2>- e ݠIx$bqB\  ټ&͏>_.# ٓ5;;[ ,-e_ݨGh$/XPh3B dh o\J J~ FsXŚ7m\PGaBBQgv7Wp* aP-rQ+ʕ$A-'jۈWټ,EyW)Q2Pd GC\ؑ%kIt-blA/$nl' r]Jt rLQGvaܰ"~ztel-}kre t 6ZZ| a@z+ i?.4HxI c2r5%xMd4E٨E״Qo+jwraU r;8; []Q*SoyΦ_7ĄNrΡ<2ݽQA7dBjF0xPpqf ټaZxxǧ_KbQq`NJoKrvvmx\Uݦ[má[qb6t[9g_聄n%f521<3n#sNw@)va]9<-ΈzE=Y_ h^}o3jxbʭ.Q3;<ד%Dh:{D \4ex'k֕ 6>,e͹r^5aXgar"\1ά+Ucbެ qa^ gɳ˒u".U!O+͒uXK_C]!}w֬+P5 QgDߛ5jxE37 |d]98-ɟN7븲/FGf&̩?(ܥ0%̄9gr~q?qeFz_9_ț2ΈS_+3J2`8f;r~qjqLGƙ9gžr^qj1jnٝ;xS_EZx8D|GV+gj2\঎\H8gs fC7:se-W-NE^ 9ugɿrnlD~jӱ|:f_ 8}qGŨvA}Y2WJ$^񦾬yWG=DbZx'Kƕ;1.hhs?|+G;2 G 𦞬V+0UICw7<ԛ5Q4}=0.S(gΕ ./ESʹ)UV%w)+KC~KFb\y_qYFBEux'+֕02ax6%gDߛ+3Ŀ~ē9r@my8c,Wޯj5hҭÌ_y_PW6͙'sf`S;TiW@׈3ʂ~P=Ԃ$73+w c0qgIwgnqz (Jl:᦮,W8`e%&L;MX0KS8 >|W~f^y8F;| ;s%HtۯqKӿA,YX-[8 ;da98d`:b` pߌbY2 溱^98|NFʈHLWΫ? J$J3˚w5℻ 7 bpFt}YrWoqJz`T[ Έ7KΕs &GZ kHߝ+șy]j2qF`\W+w9Ń~ eɿr^! |$gDߛ5;-ggɿn AY +d,-^5 ;_9/J1yB},UZ( 3bhfr~(1^L@=a9XriF>-\-Έ7k*d3$+hɭMK?BR16bɿr>Ф.g<ߗ r~hie5`b\K'&s{9wf^An\+˒B`rf` @8H:PpL3˒}B n+gxVU`Dhcۣ~_W+0E`$ol+Mʚ~>сWPZIhHd!bVk{V*lʠA(IK塰Wt#󴨛vKTLtFGƾB"s5hPEeV?ҹ8b`Q Ru2t.GƁRW!+؟5+=tp"hdF 14Kɻ#"n|s F{A<8+TE4.lCyJqUG4.Bѧ=uU/kb뫑h; T4VJjuzUxGEm㨠V}YsJhemV$\H 4.eCXO±g!^uxfssgZWqՇ Xy T9ī#K`tsu;| @3Zrxl eJfDjDϬ^Pb z#=* ?~,\e Z@[P֮(R<{A*mlmKRGR57k2W~*9X:UKe_J4}YS* ཨA6#w.:<lj:b"k5,jo DC;u-̥wFGWVT.V"; * d(?Sds@L @jM:(ԀTILԀ45V,C/ #R3A36v\ICyIVF(cFF6cI⒞]%$k; PTTpv7$3KqNf =:D8ZdUK #,V4}YSc@"ƻkҞ,\-2]Vnlٽ rJVL`V뼪īҾH\ٕ$/o uRxQy\9 Hj(ˢ"(;5PLV!])P-JB+;)'Sj.Z?xu@!*BϿT u7K2oR 8sAXf`ݚuTK:vkld4w𺀘F_Vt.^ -<L>Fqfs͸+$ǨѬd.G.7\UqUˊȅލ@ mD,Ϋ؛%2ZxrD˽"ξ'ٿkjC{Wž r<‡7il&!zhvB^Rq|*Wb b“-R^2;+E97d"wz A"˪1$-_Nhv73KJ銻XD;[ ҅A:Z |ɣ{G*KԮ4Yl`Κ٬Kw 3; (WU7/\hFE)M«RZs$WX :WAi]d@%gV/\*إ(}B6zAj7( vh`fLB_8dؕ5\\A;)!l 'D^nEba;L}_~whvk2T1$*Et՚".&P'Wj.2{ rD`Xѻ35+:OK ~HAw nhg:W&Gi4gC/IT~i_S9dg#XYpt. 8s(̋4}Y"* ȕYH%΁ |r᭼x Wz`B}zؼ q~KO/vx&>=YSbee2G`( ^uxf&psLI3bՙ)G=XJG0>ҷRo =S¤~6k -t-కf(/% 5EozF0LBRCbu99#2x9*Ǯ./0e$'!q\=c-(\[ -z?aVn`fZ#Kjjxe(a#qm\K%PKiY!mx|{2! ep Bj xӏJww sqQvrN·.Z]QLtRU>ND^Wڵ(F1QhJֽ3+ƒ'փ+ irC ҺfqQKE|j=?1* ?* ?10Ϫ0:WAӠ* ?1 2kǠm~i=?fnǠB>ޱ$;JTY뉑nQWK=C˩5bcu٦ҥ'C;ֽ3Jwz?/V9ѭK̻Bonp4Һwb]i⎦i4ۥurϷ(Zmuĵ:tl4糳~j=VEC6)iۥįҸ8~nR>F?pi=?4MHuBxߋ4~zbRQnT4zbQ~T2j9TԪFNX.'FQm8K;f8n2^ئO|w.Ut;vhiڡ~iH^%QKn mփUr۵kiڮҺJnv-M۵.gkmҴ]KzJnv-M۵/{ik5:Jn\]~DZnRqki ҴbK:O dwLN9Omגۮi6emҴ)KҺܦ,MY6e_ZO d'ۥ56\d}{>Sv{dyړzf2e'nO7mֽ3_Gkj~?8=ۦ5Mk6փ33mZ6(k4{gp\b\ k ώ AӴ6V ̖8jZbAaJᢰ`%fsfV[B5Q!LRl* 8?eSQlH]{3[HSy?ө).yE% ra$fI)%EV+ 9H[j.&֙4 @X#đ@:*IxYu UfRu zpŌIKbKt9zA:33(4}?Fʘ mXƜHdn.)6u!}_"_Hu:sB}9ڬB 1Zyqi[%/zi"&-D!r,K̤?En4e wRT x9ެ(;[T72MRvmČnd%@ڸH~fwra+ic|a՝~1wiv/2ơ'j;Rݰ߿+3a+~r[Yd*X˖~) "܋KF* lxcnE$! 9n!4 ZJLN|^;MJ)H7ܥB`/ǵm!d6HgVY* #JAJe KiG,.:8Zk,] EjfVY;i#8MUB!國OZ(]XM&S߱d٩;Y@9N.U?Wv^<:ZqBKrjj]8Ơ˳7U\a6y2R9_QB*K ( P:2yÍٸf{e;v7NhHn<쫍J(W0 ͥ /J2Ζ<3 o5c- %p65A*OÛ͓F^.5zm-WٌUH1e4K5meONj ^pxfEP! W<{kGُ%J:|(7:ǣZaSA-oyd:'^>}cͧƃ>u6./;^i(&a 4j2B[y`:^kF0 ^_` &l}V[-5Iڷ#&HlX NJ?&.0;&0NX5-kX_ƃ gw܌gUܬ[F[FC|fʹC\u׌K8 |+ ;t]pp? \9_X.#v#0}֜+ cq@Sw?kΕ?e N7kƕŀ,J8 zƛz[9@h6##zgޕ1!{*kfB\WίeTށ}oܫv48 2\]_V+ĐNhάyWj(77k@qyTF!,W+ҢhfDߛ+̺r~R@Ă1}QEX\1}+(]Zxg̘?Wvԙlᘎ4lZ1#ެX+Nvi*$03˚~Q249M-!ެW+.scȦT +͒~QhqB\}g+#l׀z#+s#hqUC8udɼrNqLnm8M]Yq˯qX̨D3Ē<5FGJ)cr^TB ,C}oL,|ݸ+WDߛ5kx B3ˊ;k"Vz7383_&G#o{a 8POrfR`9r~xȠ  ԗ5kxŁȴȃ因|gDߗj8-Z{dc9@FyP ql,@CfѥQ7ped9J^I8ceY}:ϳY^Xf"/Udyt~t?l4p# <ξ(8KB'R/(`׎(r6?}όQp#YHQޑkGy5@dٽ u>Jmpٽ u퉽MŨ8DzABٷı@TKe*+k7ȊqQl^X;yסwgV/H]{ϯ?o]ǫR e90:I{$tV,-@( pM+;dJ35YpNuDfAcܺJ㲌Һ uȮCgk8PY0.%u`BތۯH]Tg>t|#O^Hh/Sǀ3T.-*)=PKC3յL^gZ]=0@-4 W5ڈ;@yx33KaJgM-HxCkRm%zA⊸>JV*!*N.V c8B"9|6egvkW~QAo\<E}Kw2 ~$|(CivWЙ+G Ь4B ~A n#!A:5+mdyz$*:4jx慰D)vhR66JjncZΞ$励i`Ml^=OBi;' % +(6c\ r-83˚ҕs UҼ8yA*{#Ӕc~9vgժWI ¡egK*Б% d} ˡ1ׁ| -S(L8\O5KIݤ2 ܎!>lAn٩ѰCQL.R[35Kvq!J!.vXnV+WK2Ip1*nM4 Ao6.:f] R fW%XպD`kt BCU^]ݓk#KVgCPaW6@gwCB;ӸƮ'c(p͊4 jV/h\}gK QPKrD.q|B$99^? |C__?}OoG,$!|?%m˟ ?3m~7˟&W=94DQPuR4~gmj#Q@ Ga䆑`+a_έb8fQ̽ýC˹uqEȇ{95֩g#&5|2R/rn+e%m((~gEѣ1Y^ i qõyfQ\ NRkuv7('YDwZt-?n63PDx5ZrfETx(=>]KYD~s9=5M2MO5οϯ,@(EL3rn=]ĉskq[k_Ņq~BbkxQvvό0CqFi6MV˹@QS!%C _έ,"9PN5-n="l(yi_έ',"qmZ 9P Ó?\h eõ,,!hgsrhQ,[qbE .vo:_=, /V5n?ȗ nݒh@t%T[O 'ZDnR 9P,(mEIJR6]KZ.L4 JJp,9(OL-88]B:BU*OWqm[k?\Ņ&G'"eo@u:{ݚ<lpۧK?\ʅ&vC KŖ_έ# [o{AZt-?M4R7OגBCl+QslnD 49Xa 9@C@qJp#[qI(`5: ;A }PP3s A BesC e6]4a2]KZ.LPkӵL3Vӵ:wmBk_hM1/l&Ͽ -ii>>^ТQ^t,W)Շ Ztl}pL$?5Zra_KW -|ݠhi_f[ï7yl6Z)p.K)ÄpK`2]{{RǢVTg)*t>ּ)y<'Ǜ͚}lH p8Z6p[3ӲE4`8rn݃iIHO1MTهݚtuiy?-Jt%4t%wQ'ZA#o}nt%wAǒqiG裏@LGQ*t^twrJc4y5G8d4y3W8t Zo..&\qclM[qiSٽ8]Kejw1ǢyWr4|},Xh8[jrv7Wq)fW榩:]<SYq`LUBM. (9v?ËD^/ErYUysчO@?uM{bxű=@v3 ܂yLi$׃u05O,. b܂lqoYopw8E|A_Ɩr6 ٙ*Ua(HE+gJ V/!݂ӴHжя%s 1%bbR n :̭q%AOAqް%Ntv/[| ]Z2RZ??fV;Vz=0dGZzE6Sj^p2PC^W<+ VPGHկol hUhaWQ,HHb9 -8 "! YM1%": 'y`Q3E"yL^0P] F>\An\ qlmX -<ɌN.Ⱦ"txmD7⃊!//E";+_s6GïndUo2wّ?Kj $DØؒICݚ" ,JX6y E%Kr@:5?u::1ZɄ;L 8`[@дT akVoY#Pȗ ҂$HEDDoffEC/eU__3 Loff~ƜCu PLowrgE$ݲ`w<_X"&w /ϰZOkjGA[p. - V e8Vm$^3!:7199h82DȨSLg8d6.ť r6HgzE&-aXqX((HdQ]O`"n> fJ+l&h#re)zFւwR=40ٽe aRRԾTo3[ ƅ8"ͳR2TޭBj3 j;q͍X)gˆ.^zBBb$&']XYx^#e;Wd5y t+,#9TO(RٽcYeݘP4G $+Cåq1+4z}s#[H+)՚JJ vD-idJzJU*ӢМFDVYJO qU ͋B#5*e8Z*!o7Go_H" l aWIfT `'`0@gU$-(9 eoڽ_dA-iJ;݀\XX^jbbb'CE4``qT4ZMy]xXz!^҈Y ٽaUvi`;hq!u<3&x" ټ CRQ=vq{@d=VoX }p^Q&zÿB*⒪( !:7̫Zĸ-'2!$"45dzLHgQn%OLUڇ8U ZV/WMVcbǽRnx X:._ ci#f^%zRNQUGp ńauEjX$U,ѫ97+< O-t,+,~ !:7+<*Z 5JdAt c ʧX^0Fo $ Dⵁm^p*XjlQx&Zw3ln_VxTM} dAie$eHZ^٬n]UQ%,$xq +(X#~,ۭWySPgR]F†֗VqsQ6RqGkɰ՚kEĪҌH~iF&a\Ty2 \Vcg%%A$;9>+Εw5gyneyBrv?0C*G$h wĻg{|GOjjue\3jr(Jպ>=g]ާnxQu4i9Z*MZhVkUuv N@٭W J~ij|Lj>ԁA9Wh Uҭ\V0Zu!o}Y4md9nІ͛ꌑ3ba8\i }esVWBѵ6# j%Mone %+| Xk)9 ٭XgtjQܗJQYM&QVo45"[ܝc YZW ^G?q0NV Ɋ{"t9Hd<oa&aw\42?1"5#e qYYX)b7U1R pl Y9XNk5 R1VD@`)0h]ݢTnj'^34y&Ҵjk٭WH__dυ?#b$f<I>̌JqHS62LgOwaXbEݭL6cGyK|6֥fuE(3(w>ֈ P+ⰺQ:sdWE#hEL֜+JYZ#_.n Sם5 ::,3ԘfuSUY"4^DC fwŴ U`#8֥jqe]1Wz ذ+S|\ץfq;~UaU1ui}YhPjax#RkA *#0ۊVpX ٽ[AZ~X.Xme^PGG2:pLRQxR$ ll@ԬnQzu]@ nej}Yry?-Ѣājoj/-85iOZ(b₲cbmc)8*ݠV8i,Z1'%~fW. \P^0Oד L:N ,hxM%FsaiƢ@qĨZ_Z)Df)[Zגqq3QT%h-@cAǹH0qٽZ!;PQe V4\+T#nTt9ؙÕ>ffZAAͨ\~ùէ٬085Oou[VVb4˪)c-hpZsL_ <8ٱ\+BTVJg*o ݚkpvzy8TϨ4VjssFX 1x}7.uXIeNe>w4׹c7XW'yy *\ 8V`!TV;i:x~d)a&[u:5 "JDW@e{A1 QQ/h .:  ED҂y'/ž}VCA s2mV~kQK"jpEU!DEm%"-U7A9ZRCW/OEF[wbIb ,_ӹij(ZSػ8 䵸]QUjsaAt(5jMՊMQxǔm(5^d{PeW(49\qxfusg %[l^dUնT bn nDĈ˛d-ad9k>f1Lg$k5U*5U-/Ld-Wtt~J"8*#n0bYm'7(u<) N=Q,%T*HDe]ӀVT*C3$#.)q9gBhb7D-q2eQjMע*x*4܂RPªg6WE2g=wR cÖWnM׊8js@Ikv/ZC$>@t0B*a L<#l8&WU٭I[ sή7~WY)[[aϡwk8r;45e 罬CFN!R {ct"n{]d]׀4}NYs.l@ٽoq#FV'/CasfuC:ʾk&h-O!SpsV/[GZ" M%^rxmgM ؉q(t kիfV7԰3q+$[OT)!`Y`[EE w> l^4Dy wSsgwC;ӷzwN d#kzMˊ1$b怃˶Lq kdʰ7G5c4-QU"j.֧ߝ VD nP _~4wUH1,[]k9B=4@tc LB1Sڻʮ$Ɂ+j/q#P8zZ z tBPYt3 Hf&C=hzj[IFUjD&\I-K {Hz;bok*K)U)[MȷѵBa;& f6!ǭl #k,\/Mx Z hn5!hu-J[HrF ƫp k[IH'o^ҭʁT{-uVWSq-X%"怘X[\gbx:BU)&GViRbގjkmTdFTunSa ! Ϊ\F5 Ռp  Sd :~{=TA -zE#_*wwr/y BX4C V3#Ve6? &\(ݨMoT βYLGt{W9FMyT^Ucnu?]$\m$6)9Vms0榺p(mu`u/BF8Уva!%Э[4& 8p z>;4'M:#2`-2YCzR~'{0`>f YfpV,M l1g)g1ipQ6X>Xwln#kt auRKm@nqx=]C̎-T:V!|Vm4$bv;ƈSj!6KvoO/".Ŋ+ Enk@t[ bg,nȶS*R=^#!La6E*>#|o)> YtFCBƛӈ$nBf?fT=#bV5Jn"z|'VZ>'w Yz0cb$_):$A*'Bvo@^\AɞKAAR&f n7!bt!P/BG@t Y`S PDv 48:Т憸;bna|d>xϓ\,*| #<('TXTm|^(Jr9oly ʫ ;0^ąTaE#+眢-XMH ~9.tn=% 9!Gw <ʑK8TTѾDpYz1(xyGJH@ V-T8.3yRJ @ VWGXalŹ;^*uR@s Uȅ*pGQD0._P ٺ@ܖ??]bc]>O?~?ߖ%g[>?å# ?rme/"m]fV[gomNdf߶J:FڙhM\*#ۿx..о4i mJi$qkPrmW] h~\uw]_wcO} ?au_o&ƦPv;Qkd%/]^>Uvn0W1#T>x_W%V[ި&6;jz{[FKiXՇi*x(=-N%kޘQb {^u7tW=繭a.}Is2̥ si\0m./7rtc1̥ sioI_3·BU{ skylÏW>r~O"BIq.ʫ-TG\04%}˨ca&uIfdԿe - pa"D^p==K|nSo`wgy5#/_o9a{C^ݭ-.4м4[FPWk`w{YqԸ5>ʋ-S* c1̥sAӴPʰC-9^}By2RKxJxʰC 62 B6W__>Es{Ga/`s_,vPG(<04#}Nj .z񫋫 S)ovCtp TzؠwO:\K PpJlq._x E 񫋫ws vo4d/j\EQzhpER G`w˵ si\0hqr si\ڻ|ej[U{ s96.0$Gu->mm.)΢ `w-|N2caiwEF-CP0e‹U:F7E~]NS['eU;ڂݽ..#O\8x E撆8xUa+zD0lCͽ2.9~_ @YÉ-kNOapp^;-']\F3 "e Uۆywx;d ^-rz+C{XM^uVޖy;m$ 3IL-ݪʒa&eIf.N,eIfRa&L^reL"5ɫ3g2jrAY1Uwmm˕u nqk,'Q1Wm>$n@{W($3La&tseL)Uw~~͕DY)Un^9Wz\a&06A5wz ƓW1x3OnY|P̕d'@!Ny-k摃%4bT!ڽQNOq.uK撇/sy͕ si\02̥|˫rlqZv'$g 7ʹqqG9^Nrk>፵c YٷaiF/ǫxU͝<Ša4#}ǫfyG #~0wOʹ׸uUr^9W)~c(!+NOa.iJxU;WҰ7M4 {4Mӻ')% sI\iz9; D*q"aɿ>NOዕ0:L%F]IuKT\ꗹ*~<9F^"/b_~s%/q8Jx:7/> ࢜+yfa0ub ࢖ 1}oZ[I1Ds.nk.ʬ^U\L[dлqk-o*EHLVeɿ}%0⫊Q*cֈ۝m9 uZt3c7fg/9^{zUq*ȊKmXOռ][MhVu:H^!$^ru`7>2pblްlNa~pۋS WՄ Ăgal?4Xh6 Y=}մU;PS[\uUWBHi=5Y0/і>;ֶ2t(9`fq 0M(Xyɔ24{]Ea- `5ڔY( Ҍ;إ 3MXDU7csߡ֏nB5+CQ0,7{$p,KJBDd1~p=ns"vj)tRI;kkLѺ5sxnBǴ:K*By(&Z(%]-(Ƭ͋la ֮)J=aƳ^bw vZ]uzJ5\ifCSߧ[+ +LyL̤4-ApjB hz+6ec []H?&8cjV*-a*sQ;Fٟ˖IδR3<=Be6§k͢ߨ+`7ԲNB \$Њfߧ voP^ZuY8=Cu 1c 痚x7"ՌVkepтJD,fZӖmS wG VJR)@іkgSaNnsnRzLFDje0g^h5 Ƿ*LՌBK>h IVr V)x|$ꬭ'XG:֘-ˬvfG v3Bi`\RmfYZZ ^zKhs_,NəhրnxfBe XES=sh]WV3, Viͨ^Sf7lY3r0322u82oH䎃݌6˶}fIȎ`2V)2i'݌> P5veeVP 6&4KԘ#Βڕo<_XFAWa"TWv$Vc>ʰJծpy 2-["+S,+uNѭh.j,u|WnI **g]شF1"EKW5 )$_BڭY&Xhc;*fWl c nkN7:5Cj *&(U-`5²]Emԟ0G ~ v*,T7@S[hU!ݔ k =dAUs`ujr TTe>o~4`%\J}oZdfV \UG=e,:jw`5t U~e )nH1Iv V3J^N!&]%įL(9* a!IuG!bv`FXP{e%[@t)+R,3$/oGvoP^5X;-uy,;z}D=ߎfX کz;Sq.+Sqe7UbҲ#tEAQr!*B~u!F%0݄W $BN08A,T+X<56BV v O=VT]:{vo@.*ySe CZos`Fu_Sj\I4Oǹ Г\c+;VT7- s 8v/&WgJ[2x# .},+JDS뷠xTxJupYyQv9k%jFw>ŕb%rftW((#j+y'^v`׫ =7 z1rA} \a^2[o_VM_A>{EЯ,+&VHUrz*wv%ȊR GvZ+$WG#GdޭB1U uU\!Jܸ-XWHu;KģSμ[t KuWH;CmUw^O֩*@Q\/3OgVytxHs=!olc3DoBAuuǽe9TjЛpgݪ9Љ@SDrq.:]*w7(-`5ª[ioheCnW InBU37sH}+؛n"^YGXHm'ʭAv, H 4sr[osJ hqPaU$/X]1e.Z,fSD@pLnz&X ?k]HJLpLbn3 D]I\cy#2`7:VܞkD9DЅV Fñ0~o}WaL ld S[]UZ^&Jq}l/:~y{6! #{.q~L`  `a?/UGhu qpQfEfA3U2a;V ,vrb~z9Vr$6v^Xѯ%^Lplrr꣹U`+$vZ`R*{Sټ`:}N-ӔnrwL.IY)#B `u:ue,)ە"+u{7/I]n5W)4 4{ >jN^:Fv|SG\5W,@IG6؎׬;x"EqU0`u*~\g#+H*{U9 QHEϝ9~|e`ʵ'HVkIvʇ1=iͭڏ"dq4 zbl=V^vekaWVek:v&[I jgv+ D]nKL9K Ƌ3beA6*.Az 1dF:6Cq *#n3 V+Jfxx^}i/aIFkwӭ5W׍^{'|;ݭt'b+da?,n~i}v+F˙W 䯟-m1X]1^uW52~kqfJVo0^XsJ)gF`ub" =\iDT ؘS-vq !$ voPzGAOh,s}-++Ş[dQ>o 3~Y]t2JX@*ն;c;%B^}" U.|l64 2A2Є$hG|߅ս TQ6ƌmlԭW(aNO 7{Pn5pu`wB?nSo,]1 P,.: Mx: >ԫD`uJ7m.*03PB14P(,h +Ls)lA+[avʫ9vU(.,6 " Էn5B \†^V "ԷnF^>\xa$+4 ƴ+>6n5ĵWB "A}.IuKo@J09`j!yzM"@y7Wk#VzIv[؆4U}۱1u UV5#Q4*^ Rޭ*DzMOv =S\!6>NC$=lJ^qQqËKVXPߕ݄ Bp?[hO.Dm&4W$ߍ*S[Y4AL}q55!~#X,Q_$:4| =g[}oaH6PJ3  0 oSoH>jlvҭ d:}SRT@MHؒ-O?:8ja&Pi* =CU% yإj`ŽjɜL&[+*쨔4۠.[@t+E"4먽/5]X]! ݄kW 7ÊL^9[ێ (J >%n D{"MEWV3X7 $)V(b;vAٞ% 'b ,rg ȸ3D9UIVb`qO4{Fd5!bO>jj\,0p6&[U 06A9xRm}s7WPs5^,125t FzSa0V5؛|g7+#{WAisNmd,$tH_$P$PWyWO&.eTb3]X@ ;۽AH ;r%Pͧ1FGCx+^.qVϪ2b*\/BE4r'ʠZkL$mPcEH$9@սkbcQVodP ocǻ0xkƬ5cW!ts2Zj j4Jhnk-Fx7odV;_}NmT-|, =M#psSoU݊8@Rsjś~%Ⱥ\%#`w/:nk_[̞Uc -An2'&{9wߧʁ4gKnZ;Z_˿mR1;8jcc!-p>2OO]@ PQBL{#z-6 ,ɃPR1ZMȺM1:Ќ$sQt aג)e C2Xne] *ד]ʃ6V,* AnWQ}PLZ)ZnBuX@͑2"*&݄ #<(n[U*%|^(I9\Jus{"'v NZQ:}2S@\XnD] 5om!Y%]ݼ6\iXLEUA~̽dx՝/mz?IN/[S5LW`$^dl&[.,.KEf,'܋.)`d_4,^$lPa|{Ϳ,>P06̣q{#2{U;.q.~0e.R沮˫r|˫=` 5^{f,-ݭt'} K>LEv,j,Yq3AZ=𪻭L賄ROf^Vv:g+_W@^Dl8}> *cBI{[{DʋyFG)٬E"fyzE gQ0:̥XUFr s9a.\^$m0}^\u0\^m:?_Z>0Qt=dK$0}eG2L _&IVQ#UZY7$gN# C~.t {ko j5J._RmM:1L&Q++ j ߥ:lC -sx:@;nAVk=j*UVN5^%nz),0Pv7Z0a Z-h-<ʻy:@x؁w;ZAha-b8ჼ%g`B{?Enm,gb!ڼŋ}ưlö4/x6l;[ #~gVⶡ2w8{[m-n1e *[#D7(e*G r|ʋԭvǰm Wpj vo@^omYF%W'[[a0HW/ǫxo~H,0}Y ڒY25 H_f*|kN@F>xƃ\Ok'1Or^֖.q.2̥ si_*}kL@:r"k(AWp#"C\5D[02#ݽFYyw kk'~0nodp-^u epP8-*XGI@-~Q7*NEگ7whCWFɽU;&UUj)'BѵS|QBP ,Vrh}?=EXH-a>en[9 [!c\ȪML޺ٱRhnB̅F);3M֧JZbQ]~8bYX΃m蠦y|fe7©0 2m! VSd;X࣫v<`y-?}LeXc){+yp-+BsBQ1Zl58" QQA E@V[w1^U/z:jES]:7 ?O{zoQ`XX.r⸲pD21ݽ~Ls,)0Ap'^x^Up|*=IN5Ա[\6-\-UBA5f[,ȊdSD+QRƩc݌rK^O eWBş8vd  rB\v095r[;Ӿx!7Q(KbYuz7_[붖J=%Ē7%xM>;U)j(b []\][JvЊR{Bέ&Zv sZv<Ϟxe9A{Q'H?Gf+{&dv`7b ݬ[*D\1XMVsKWH,$`7Z(HDk}39fQk!mTtLg^ѭfZ+3Wjr;: O3gY(lBvYǞyet݄Rk \Y~̫xMWVNӳeo!^q`FDBʔ}aR=Բtd{QݔocVuG(rw#7 MzWϺڿhVJa7E9EA'F²K\3(W RJ4b& v33oK=ԥ-ZjZVG Vz,v]CXN)Oɹ#Z>βQcʠV60>`7kDt-m+BŏЂԔ&0v vh5IJ}`E௲+ #UfXxu>>9 /%3M(:Dٕ=ʡYlIX,8fZK?p|e7B[ s51s7m,fTXִsz {͆_iTxclLY{e;ҤT Uۊx_۽F]Xmr>D6jJ0 $b_mof wʞQT&J_dmQd +b~ * V/fd7ZQP 1CZU24fW(\$YWNx2˧~f۰pIp Ekp5TN;7 %P}XکPx?M8_;C]كcw^0(6y=1v=qq|\m,!6"+'#USy=W8 ϖE($ qQ|6U'{JF UsF> ]sSG\1M(rqI.hP!j6oLHv!ʕD(eh“voKʫ|kVϞ&nu[/د:/1nq+ϻ[ݫм1SWb}U?d dj˔KdDcVIͣ*yU_?d?>XG UB%3QZ(@&us7/!î]hʽE`y#1$Rn7:dیl#D?!+m},+d5dt̫hs}kJs# z!dEE"WՄwT9GgEU^yӴUo,L{QpȯxjBmd+okd,uQ{Rz񪸪#GlLj N3WW\U#m qR+YM(jAO3S6zETњ;sKacHnWCeԭ`*dVU 9 HKoS]9Be™Ґ3R؄֗jQ1My磢[k"ot7ȥc [EswpK eυ7ˍ֊%o(ENwC T }!`w:ݖ N@vl &ԭ/z+mq).c)B,nu:bܬ/q0D9cw#`U[HE@{v슏2ݪr*nT/DU׾uV i&oD lAG,q퍬ȠFtgԂOi;jX|1((hnV)b%7;!GHq0wZu1$|P}8Z+Anr# Z7nsJOt6o[Oټjk Ȭ݉07m4]|W]ػGfF@ā]$Š hYvQ΄/t%;^c~7ˋ]-IշxNX1k;;ano]^eEH[{H,>/\UauDPgDGtq ҷu+o3_WAV6m[}(R J$V<`7b T#\"&w?b\tV*&>(pGfKG,aovoP^Wȶk/3]A_&6D&WHmõD2,^1?u CvvɰP!*$`7 ~Oɱd|iE[ɫ!N-Neq*]VC\FndZZY!|MJ٘.iU[!ӶQHZ`""B}wvz?%vI|sDh7B$7goVoQRjBmG,rNeV* tߦPFX4PTXH*ڏjAj&ZP;0*FU/c_*]1oRQVu\y(xsmx? kZkjj\p\qoXW#bYvCnE4|9殐[  &*`m2!y#ֱ^ő56Mxlըxsވ^Kfa| ޸k9`ݽtKMِ`=jU#սpl?@ ?Q=gsʜSHD[ކZ6;V޲hm^zt־wVuh1!ZT Ztw g]\( v-V"U%mCr'ZT}UyVJSt7W֢ (3 ljQi휖&[иo(8xX#VFw*ws 499eV5X3n" V[lƲy*od<n!n؊xA Hbma|<V%AeBȟl>GXcojJK&[[Q:}ahSUJt7(| k,uG]T8j#I΁7vt*ܘC{QtI^6xb̗g** QNPuAt7 מb]TƒI ;B}(wVCݹx^r0MHPQ…J&9K09F n((1W8zhOAI/  c<s1 4ޑ**cl&\+t])JmT`̊G[݄ kc;>E}^mK~sL` Jxn3.  e$uDYM Y,o%`! Lȸ0V(Gtշ&xjFąax$W+ؿ݊DS 46n7! uV`f&bvb.hMu*>LnFεp*Uq>)D(WWeX{s٪@(- q gV93G qVqEU)Z-\lo۽\]]B ?zgQl;[Nj qp n }'YOfsd7#9vV 50}H(+W9vPq"dϭ qtJ{IUQSEDsax287j!*\/`w/@0#?$IReD nB:)Q.YMH0B{X)PDlѭ&]|#?xGPE$ [M40vP_V7T0xRf/ Vb.@z:xϚO-`݄,q{PTw ^Ҙ^bɭ <ځXi~p+ށN\UЅr: JVU|Yc <lB6.{O1}BjGDB@-r.Y߽pral9wĠCVR.hSH^s\+~/XH0"]FdVwo,*4 \%]?G^qXt Z968_ $:=uyX~O6,ş[G۾mYh}c]l??_@È|;>W 3+*uAo ܩuo5'Do,&tW a5!6t3H QhA::AieT }^vTѵ`੆1Wum_BT Wi;~ܧ6i=?eަ /͸lvxH+ngIxZ/q&!V%-xV|*-'΍~.:z+{;v0+t9? qZp/ހjF/㧓qɘlzج %YoCOӤ?M(<6oLvӟf?SV4Ͷ'6Dmۖm?p6ĩ_^V|۲=_|Ng >RUWݞΕ¿ r7ۄo+I)D7 bn+%//`?$6Z^޹YLu˭&ϙmɦdmG?s@xǿ %%টm⺝/2hA(mh>PްwU"YL$G[L4X]$0; CrBzks[+*\Ei&(O{3t~??nҀҷlCyEvzNf6kH\j.xoÂwr;\P!aAzW@ṳ@}Q: ѹ!MG:r)&mnڈ뺚WxXW{3K#f~vg +1duRƱۗh FsE7-G qpŅYsE9^@6A`>saesQ)1O,b>E͵AV)HE6vkuаnstA>az{/k!Yueww%iByyi ޠ03!d(am]^i^ VW eX *8;4"v(Sէ|\P΋1ĐAb~ W\Q(&^ܝl^ν#b cƚeƆIm90+]Q$VpD'ֈޠPxQv=Qƹ2j=%#N>Xs[-iE}-%LHM5M&URd z!7!qɓfdƋi;bNC*/|7%/X#f{r[ɼfbd&blq:b-iA^K%w,Śo:9qz垪#b lofĸyʎI3]Qe4(Ū1b¡%HU3ؽA.Q>, \>?yyՇk~%n҈Xl:y宪#6j!]X6!EʍU+? cysjqs!+ M]a'`P1yU7QB^˕(yE Y8^a.w$n8]r_ hu,M# X+nyʪe_``ŮfG3=Tc&)ClKb۝YhZefh0]kQmt։Đ أev+^C}U lXq(%lknwh]qzj`<Y4^4oSYʉuw+΄e7XyC+Rm7r2čzCi&lY &İ-QSLdR^#B(-yaﯺ~ۃ$w:"bM2.>8:HW.x㼢j|Ŋz|13,|J3)o3&7+8pcFL`c׽ڋӲ1\6%bj ^Qwb?[1喭 NVc+W==\W.J {!Gsl't^XL+k㰫̓)#b=k(V}ZgNgߗ/UMT߾ ܳv+kr~׎+^-g|ƔpVċ#W`ڹvq4]d?(xGsvsDjr'ʣ{g!ʯq4] úML|A`\8u͘:bc0Dj0J v.0w>AzŌg_+lS>q4]K%;Dx0[ƮV%o`[ QqjtW6_?+z{G󀄀F<W}P{zػ$_쉄ăv_?jn7AYYQۤTcoP~P [&?<3+I !+ČߒjW͟BY }Eׇ6Knl&zn+~…lk_'wu<ڼJU[2&h?<8kkUb(Te v@+bq^M7K v۠bWtUѭ&h]Uo6ELxómVEtjJT X]rykn7AYQg&g5_$yt x +Fe1 yYO_I`* 6$d x*;m K qn7Amۉ Ue)3U}(BRR@`[ʬb N2M~ICE(=-pŕƺ}c""<nFVn.aύWQPndn({%"rb 3L# ')EK 2'g^a[мnmc폔Vs'g^)Y&H,͇sYW9mTͺ^H?JuD@cX[M~k{z=6eL#c\ Aг@^y @]\.dq#BRU8هu\krc+E+K@^]$z@/"pAnBxI!!-.Lk@s{9w_# d$iAIipL@ Wձ 7j{>b#d nwOk OQf%bq`龯%/^b[ ߟdT(DEfo<̃$e |-Unߒ Wd{R :`w e?He@PNvHÔ$d9\BV&X|ݹmJ X W`rI,"++ի]مߨjXN=Gً`=w'{rނa*ֲ 啯(D#SEN8X%u)IaLӧ2ąǯSgnICdVeo+x34}dk>_}x \s{P1N8߁TEOvjA5 'ENδ6CT1&hÄsALHnUal!s&hC~,2g(}e5ȓ7W$ELQ_\G,le,wE, _z%s `uWGӂK"نk~b5IVKd5ݛ+V0#I" #{#NI[|&j6W >)u{34l&H];8Nu7CT&HWà%:*[y7D[Men'i{U84vOQV@!KJjRڸe_”g!*xc:wB1v>[qokRʸMP/׽S?~3R7[ ]lɻ )̉`5 Xs;;`,E}Zj&W^샭5@ĊXn)CaZ,kV[MeW!]쓛Ӏ2M>o1}F=>0n7 |y6sws`5 @Xc ZE@D0>-1kISPCTְ&2zVIÛ}ImDҰ[MЅvH̉IF`B 0iLGSva,afk "^-UhesRݙ$ؾFlp.Jw^Ŋ[%)M>Ei\"^#ۇTyçWn| >?>EYWIZ i)>}:8hB.:'pYQpƾEIn7AvXl %%[|(|%̕({uꯝJ ll"%[mH %~A]6<l6H!ԈxLZv PqWCFucQp;i^{ sq}|䂷'["R.^񺿧e&R߈q@9앥 g?bLdߧ&&P qJU\YJxaw\plծLGšLe/PJإ +fT.>-v+ưc%\>\^yFVK?+lrs' }󺊍HxͿ<԰uq4yuJsߩZ-#f{&~Qzc fynuH3g*W~DwTrѧy_qL^5qܲsraqT0/e*W~RJ3+OKݜڰ"SK8[z) Οp\q`3Q}|Zf|XK}\Hn!1f">-vR;8{~.aJN㹗O˻>T0xyD)΋$+0[4< ,/㖡 > ڕ#ܮxq,3 :OA= v .x}Z.>2+"*F #eϧ"ΔW8 ^yHZXl@[d*RnW8[.aW+Q/x&ryią2yZm/hsɐ~#3m [WmTqDz&W^-eD{7e&uA>PUkrEȯN!a,WMJoH|Ƒ0uٻKW`qw] f ^<3 #3w R1#_O 2? i2Yjg-.E=[R(VpYLKwy  ;ubWIU?8T ڋV74_3* foqsv_zПy-¶(6%|ŵ.[(v$Y}*C<` R7vqJA-Bd^ʎCv3y$Y˫Hsn5AL@H`Hs-gu#kIWBUDM5k ?W_VSY?-x/1^!YPAd'#ϴ>Lxf*{W'Z,q4ͦ 2HKxۛݍ>Y[5;.:n.k7Ӳk xcvsYhr;=| *oQd7 Ra.ڐEZR0j3qIj ԔǼ!&C5>[zNbv=59ikk_ɢW?qx{aAn.oQɝ[ a\tZh-̥D5wW 7_̫*]=W:㹍Ahjun5^c d zXݎB| ~$&XP=^bk梳.l-L ZR}"1݄ PB`ԎyO4SٻGI7 IêǍВBr{@tD_TȤ(:vs~X_Ό- &dxXMQpz.@<=rwAUbJ(Rh  KU/;>Q" 8z6c'DM\R9(A}S''%V+p uݕ &^Q`X CX}[Y]9+4_=|S~}?h xPd@~oswI훚yHmnߧeJQ͂¬>.ib}TxtJ#+p,<,8d &e3o + WbwrfR1D%H߼f/"H0e˭ +԰p%Pg X HcޝbGd+C:^g5F9I & Wzd7+ W8ߞzw*LN=/U~*Wg0ܔCֲ*I'V4Qn#ҰZ*j2VmX}F#}W#'~jŖӀ%*V:VA\HHADJ}ZɶwbKV C+dN#,Δע`2?PT{)v_3vǍEJV,j_34WP}5^u,,D鵑AJd=| _/X=m;DUՄ2BI~,Or$Igr ڰ݈[[8ڄ2~>M[ӆrJtU`<{ ‰܁D?VN\rv撣ϮVl<*vv9B[QZYMhK19VD'jBY<7)C*ІS),rtHb!~y@\tYF2MʑLe[n,T+JRSëC"fBͤW)Gv3貧"hۭ&fWE+#н=mCrGrO6.$8l$6DnV7pѷ2]DŽeuXv3fv"PG`7A8Š9UIAZ n5AJTr L5O}ZQutџuh&n 0+ֹ_azIq|aܟݻPuz_/XqY~{#|AFq+s@ڔ2ő1t J+Zσh!9(XWhuEA}&];S="[ R`s+~O ibq-GM$\na,]zb{hn}ѯ}BOk80[q{W'lzk1厭^O msC`\ru+0,{l|\xruD@W#Wg8;^&FrE@^&ZcOQFrE'G? 0[a_ ALra<\]{Tɪ0[ν15#Ʊ0u ј³?tԊ`nD9JA^ܫ!vFW<ɾNBcc ;"\=ѤxXn: g*~ "Ʊ1uuCOn7i ^gW`X<ta"+)h a4!YTJ_8W.ݽhFP*JzOYMb$)}3v+k@D!9t-UC l? BX*ۤxuhS.[YޱRQgVhv֣?ײ Wy%ٶDe1eWuL^ȘYD \MSMZc W F:MB+ufP(ȞxU_{w<)'PvUan݄<(L;#NxQS))&."NbDP;*S BQ$\x%Tv S8^#Ac1PRC= ݄8O΢1qOXUitM&yxvAlPMSiπ?qKOҼ&vH摉w8^浅>?(.j)q܊,D >RaǓՄ(OV3($ʲ"v+ &dyxr,ZUßm,O΢b/\7cY_|D*ʫхS($=$.CX@n%yxtȽ\}Z]\n"Bu,6-c˞[FmGaek ѠN!{S5`7!㳰 7-(3:DʽD/gβ;RP R|:Rrb<֒M]X;xnBCI(b-˽c tp 9#R4zv4([U}%G kJ+ĻCj]V9'N,|-Z}gٻg!{WeNJ_ Ul! M`YHIu=Cc6>C+;hIV][´g7a^/JNG4@8>|o/* !jVF]zr@H.3Io EJ}ZG=UyLg: hM=v6DDXc# Uؔ,E$*r$%X_X/ITBD$ F;OvGWlaH44Bf >*Q>QLet- 71H^DC4>0"lܻGC% эtoPd)/7Ntݕ-|c~$#b(#*ށGpC`w~q&JR1& |ۣqpO'wut޽qwW"~>9i:ѺL?ǚo<j jXn&{W~ QHywG mSQ*{7?zn*+tͣJ֫!n&<7<"\x$j﮼{wlVSq ݺū?TnyT̽ Xpu7Ju7Z= 5Wp •Ŗ丕n&y"1@|#yީ+P޾GomJ޾;Xe+2 wO[Sټ%R4yw+޺A8j.{^h#/s/ؒ+vSٻ6fáڣ Wx,xi%kİ[wV4[wUZw74/J}^ ȆݍRP ,*{`7znUn0Ի%9W2wzwgWȤyՎ}wYFPG\'B;!d7FѳT}uѺ#bj"D]J5F Qd K,]yUݾWȹn5Լ;%wȱͻq?&#yn{AMTvUxhNjaj*kxg;j]"2x7V}wWbREꣷx*)Uݻ{rݻ܁n5[{ίVK!hnyܩ&L ࿧nrvYɰkMW uL?&s6Y4|Obَ5 |uecV}Ma7ft0TıQ|u S"X.X8#Wn$#7` WdUV7`@2!s8BcP4Kn:0 EnJ4`ޕ_K+ۜL)2w]PX9v*·wa,Sy 4P.XrEݼ@Ɉ7e*gW^QU_e B"jX&rv+Ү  6A 9CLFh5+؃]E#bS0/Hk9 uvLq32kcw.bGrԹOԂ. 8;ν*oD;V劺Fhw/sS;b"vW:D( ī%fv+2w!p%P:xsA~qQpM5T_WSs˱ʯ݃KNGtTɭn Dٶ-*'lܛed~a>)Da$N5obrbE(.VʠvN_V?Y|/ηy z֟HR}3uh7T}LYCe@#T}=GqhBBZIfx9㌧O#j u09ɮ$aJz n7!;frKԎz9/ڏ9 lc,pe:]% r 9r%N,8אOm41d V9䁘*l2vwE.C tLȨ-vNa v3YhfU_xǹپYͣFf&gמDʝŰe*qJQ̭芢&v\N؅NJڲ ;efE6mJ+‰v3a+ϩPtLڹa"bgUw7IouWDfWAΑnvߊufй4z 㣌RwcBRiG:wqkQ4ّoda1Gm0lu2AGj|Cvo%_włZƭH‚f\UdE4Rˆ}x`uODY'tP/vո v|5NfG0 Ev:;1vZ&!{{n3k'{Uы1i C޵bBtŒE(6.m&wO,MY(t0f&u71H(A(9[Md+?K(Sq(ۊV>^:q'&2wWl(DYq.(@W\[Mk]qwby vd>3lh+01{j*^aigkE+t^c% _w'ܜuDn"wU_Чdl`u 6wDtŚ8Ph'1XMP&BWm1;3.$w1XM+}1VdX)?a,w$_Shˮwz GܥW,6QI*Օ6f_.ܸE?M VRܥ-ZuB Bm`ut@@Z|, Xl-EhR#%lT#v.1ko&J?I\+?n&~;?QW/1Mh(օ^]go `3}јDR^&qKZx>Yb ,+չXq^hΊt*^nn$\؉T:*^2"v 0x5#z؎ߡl IBFrG.'P- h5QoAyAoLvP ;U v,f(nɈI|XNYzL0ݽ+1B eBy]l3+ٔd(nwOv((3곩X2g+D]_{%^' 3\w? Y  .t+!Muk<=Y(Ƣ %3Y <+/ +p⧦OW}7(nW+h<L=7^%r;ő|EH:q[TA^ĤzHa _ع*֒-RB cuhɷc%xv_ٹj--[o,䞟 ~Qd%˶3 b=;Q 2s'*2^Foċ#q'FuzD^GՍ-7!pE}SEe\1x9% @/W8{Q_j7䖧>Q uQIw #^Kػq4,]TA1upT_aܳtjmw!|5 ܳt+0Z"vſo-K}> -%Hn;ZB;"Kߧjf=Ox޾vs_ k}G8[A_wzGod-{c. 䖧>Ϳى_؉/䖩 ^*qVǓF8{.J B L1x:sUGTh b߽l&:˪$7h(&ڌeU +&>{.x} H"Wb=S>9Y!+k㹗@A(ͻq<Ɋ߭$B1枳 ^P-T*yBFr/ϮZvCC/^ԇ1ԄWlRg1M-@Bk8 Qw{o_D݄7^>P{o_1#'ξ&ҡ/喯P}!d,&;`q^49݌za'sEO*aגzw1^g]t-5*,޾#^ySE]>:GIQc. V>)z}Qg1&u,Zݎ^@!37 ,7n'Y |jo zU{wjCD2y { /KRAeՁwr ،'<Ѹ{W.&G v_ey2P[\BzB+ey8<\4:G/>JTx~D; <jTWdAj5H($+ y) ݄ /uř޴OzjKML5 ^O~xdԠ8!f/a"x6<<8 JF:ߢ?B /IFL٣>&rDOq¾W;k,#,^<>jC*҇b;*]X;\(?<8:G[ύzUWqs`7AYHWﬧĭ{b Q0nóc~O3.ѻc1 +釧G]wtV+B&yx~j 'P-``1!̣93TdkandnGw Mn5Ap>@#xO2#ã0mf(,~a: &yGQqm"L飷'6rI#CcPT,Da)/B-@"I&H]GC*@!\'MGq`5Njg`k=8Q]kx薷+wo9`⍤:۰S, wmޡ8XM}PH)q+^oPk1W2's6oܠͽ4)Bs+ZCS: V$PJYQ,Ks8b˨XEQ܉:^M^?[3xBU_ڨi9 w'1D\0n>׻8qx%&h7S+cw݂v4Z;1inDX^#VAf;D +6 NS鄦cSDeW{u\~MdZcޞx])@NMoOٸݿ9w_z1f"Z Jxubs'!}5_UB^uS o4hXӠ]]Q(\Bm!Vtf;R\kȮ29X'4Hd(B.߶8SUtF Vw] vD2$d]4(G?&)TӀ]'/$c,hbq֭&KQxL7Gg܃զo)&K֮т +l>!#MЄ˗fAGTv0c)FJW%yT2; v }(4hů6~j&wW^!dE+Rn&gR)C7+73V/T&hBy%ÓSmM>QB.;**)!-v3[6 8j.{7q jU嚈:ݸT.OBT7wIn7+(}L%>Xn5ApeSC'Dݽ*ԑ{96W:`j._ۣwX$2`sV"ؿC֤GȍWwvsY*þ^vĕLL/}w"^_x<}]ohu$Բ1Zﮬt==y᎘T:kʈJZcKN\qߕ_$׆hGDևgBv^ AUzP Zn7jЙֹ}3Zo'\Vr۽d{Z^U:9}rx+ԅ$yA@Wn e+R]{1R øޕǮoT=x-䫔=BQy<ő|cG?gJ7bq|uO˶M^{܎CXqS9zb݈mJQXfrx~g/>oR]a,<]DX|Vl;bTxIeUq439r, oζX7 䖥 >PAxm^Tniy(O[2^c@ vs; yI\pXLn~]mǨoFv+1dMo[QLxK3ukk a,<]zbv ⦅Հ2K`wy@ ceקe~HdQ0{)_ z k"Le2`gu맕Fr -;3\殼>-v 1ԙq43r fI!Uù_-me"t+ wd #eϧe&cHrwĨޯ2Ke&BH8{{52Ҟāb-G>-uufD.q43ٻE֕]mu .|Z6㖡 >P՘B2E8]y}_y@ٕg8 ={\1x9i9N`1tEBȞ5"]8EFF6)Ŀpr-?8jrOEX|u ]y+b{.}b]'+j5`Le/Pbih/_hviy]J#^ɭ/i"^T>-v+'LUxq,S +o8bG>gc=ߛP|+ETT/a,΍2uF3W12v3>dNq U)&(><<8c)#v]lu@{<'m&>?kVit,"#5 n.cw/q=ŝ~éS`76C`ZlNc\nu.jPuU80C7M}xEx75VgaVà:b{\=d7>U,5:b}x|%ؙ6 obv9&xxtv$ *R`pU"͇Gg};4 6DFQ}WT(?Բ0?c"4€cCw9~U 9AAj&g`EA{I;7drmn1sמq[u1Od;n ݷI]!l~p:t4ş&ʗ;C+ye8v%&fT;ܕB9y7(E2it]4eaK/=-Fhc%z5 6Y28n><;;KX5ss . bxnwOٕ+vqp ^-ASɫ/+XN-]9! \Ɲz_]RQuλXBHܕ9Jg^%_[nz@$^}Ώ2evsyYJy%ȩB`5uF C9?z%w^iە>z] wqGY*mP}0߲v+ W!E^rrBt{ݟg"IDb%c 7d!zfM?Sgi*7)5v" eQK\NGqo+hYtWT!gd-KS,|+q&k$њ7 RdU=n|+Y鬟]xZ,+U(wjgޱ^U>4͸08 ,<퉙 wP o4Ca<1`fHBwb:gE݄ܺ&{qӂ^ժ Qd5Ck\NP4p[M6LL5${S4ZlnwOv"]͋%G/}# p?X˫&8:r沚 WUbVu"'(YMv6KblT#8D?]ahM5ZONSQ~ ҩTx4UPPVj@(бj"?qn"sHU+  Bӣ`7C06/_а[!!Մ&pWFrV'lm(2t$J٧jG*b#ܻe J-(D4>mQu*e5CJʡ97ЬF(P@K Y(ifՕ(%ݽp ]q`/_ՄpÎ B09bFq?d~5~+7RoȾ^-Cդy*fK eӤu\d[s^B^HHztc񅗣7փhxw@#oo#h7g@&7ֹ}rrݣ<ꨊ*Xj ^QCb=#h" ^Xh!gSzEc':IH9?="ܲr-@P@ޮq8\{XL{Ԥ* m#>[7=QPR"s&7喙>o$HPPR~ے:l&hyN/W:YEY_(?[tP %9Q 1 5qSĭ԰ks7d٥8_";>f Ln+8u7^sH=z߿ jBG9XeP}Nf? c>X |(ʫ֟*I?Ӷïtv0EUP5܈4ePR^v6y%Fz?vo_i? (8( g Q+D@T`,C-"JSY9S%j"k y}Lyet + / ,qGN*Wbe7A!!J04;QlPEe5Aei=Pg3 c5ڿWG62vcKe울SCEE֟kMP~uFc(`7! IBT +L_j`n"o7#ťQU~((Lu)C 6~P<(F6S,hHRrb`n5A%ZqJYQ DL&H؆hrz]ɄBt /a7 8њ4MQ|&1n17_Ɲ *7>w aIjZqśȥvҼRLu'uу[M"c. @T3HJ}nfL [֠*`̇u݄A(3Xb͕ߞz>dzܽ/~qGj&]h:,g3+ /6.$nͲS2oOd|y׾_Cyaeh>bG۟g䎲Y< *xG_&qmWߢ{8_#R\KGC^[W+?^AO9$||k6:@Jh@_H}zD'-Hk1jbtX~lѶ&j"ŢD J:`W`Pl-Vq(BPYN8%Qnٰ?A|zO)"yEG>( afhz?vN&qyO6<`3"B>穚j'KIA g|D;9-r3u I+~(H#EFiR-C`B7'0^:"ph۲tM=y `0,{d?jCɭ)l 1UMvxQKM1֓{hU 4Jmr 5V>e~P=dǺ2"WE)o!J﹕ZD~FK˾a6\yH`V*=zF" 8^o91V~#gTWS)O 1ue(V8f+SRval`) ъH~:!,b0!@[]/"𝣜9C_=v*^6c2ϰu*R.d&cbl;rN:ν#ָd(vts0< }kclŰZ9)"~6j%6VFYljS:Dӧ5d5jP3u#柛c QeIpG&FjꞤ-g=I`E+P~ jP>ļKndvmPR}+fپ־7qJx0>J}B q-;*jX'L%b?}Zy"њGsx=w@R\b~1>-y)ٕA4"<>Qtrw.L\ʛF(Eь( }⩵Dhxf=ZJJ:\1bQܝ'ғEEt/"9i7=X> ;GM:1ρ`z ;NTުy99`?zE+DvAF369C]goԤj5X<}țcoEG' BՈ2(үNkM>=>߳:{T6}ĀY0Y[eӑ ܒhszMw㇖PnsgSRuwz-V4nrr@W`TbGWjAB9#JQnT^*bHnKpv$N`@ +vVEÕﲛ %Șf>9M nJYWhW[}%b mV Tudd.Do ,q75f6r7L#1$D ï5 vREqȻC{s`5A ^7VaS 56dl0qo(fȗgBxcAMՂ7nwO$u9\b'vWC;{ hb@i#W #!uY0;o FZ[Mq{7It%ICyF Qnzshb8;I2/.ڍ'+t_8՗V|yFS8Zmh59׭t5arРvT?i-PSߐQPzFA!lX%qU{ Ym?ŊW?-GtE~6X> endstream endobj 3 0 obj 274380 endobj 216 0 obj <> stream x \ endstream endobj 237 0 obj 126 endobj 238 0 obj <> stream xw<ǟ=(hI;R!MI4Jȃ4JFhGRveP W!< ǡsOu]&L0a„ &L0a„ &L0a/W'ߨN2#_@߿?jvW(ׯ?::~  kk.4 {cSs G%PWS]UYYU]SW:0ɀUWUT}fgBgG;WfgeffeULC܎ki*RMbrJZfNAɀ&tS}uyiABCB_E&|T@7;~&ʯ9S|=x_@hdt]^]@sQϙD?}mGς#}),ihjz&b%yYQ=]q8kkmm{~ )E_!4w77T|JOyⱧY+3cãG N9~,$͇*kǐ& qQwq}9Y?r@k{66ut?,:)5+͛4č!N~z峖vn^~-=#sۋn_INZF{0_SCܾzġ}5TUlئwݥk>.F1֦;5(-/#%))%3۴-]q7(dޤ͛8ELgݛTI>mtQqIE6lwy[]Y=#M]I-$ŧO?^Xdة}/{n4o qZRtiׯ\`Icƌ(n}IGWr.+v6V\(={d1#)0BKΓWV߼GEwys}LIFXb9S&?l(/a#s+ 1qcTK74̩ܺ"F !C_@?Rp.[qsWn{>F5?ba-0?50=v2мw}-1/f:p C "4x0;l("SC1)#=@K@#hy$-c4[OںVE "AAf[4:e80Mo<džU̝b` Ԡy/X|c 1 ¼WG ctcp\!/'!6UA)4,/]}ЌR!LM2oIi`]&4u`4yw1N8Lw &%Xq7h>4e01.i 1cl?L3]L)|l5'|iDo4}iԃ|izK& s{ѣYhv^{tdi h^{0]ie LT=z]:LJGA4p si%ЌӍDb8hOgć >&fx&1-Oc0хy&c騏5"fH  ^_0сc} 4Li0Ѭ1"9FsӓC^tήk' &TdXhTb* `c2#ĭqRd }- Sch}l.3G73>F{_dyQO<0҅%^(ttwh>&)d=pAJF'|oi2IE)+N t9oasJR3Qۿ=H)mb[R^5@fj:] {a$rNj+{/ژ޹QMYaEßR R}QaXh$@,=_A& `YF&:6^' jn۠BaS' N׼.?|(1'L&:KJn2ux0u~UM8ؽEFr8'-12sMڱQ}%ASS;fȤ/SQخkxR,ajVOQ!qs:cwoݠlsĐjv&+qLyXvM]vN>|*W{WN]W^Ľ/ ؟49ouW,]$'5[lZ7PS$By'L:cl#ekmھW[ͻ)"xfxq!)6<[nۜ:ncUJ`fGc©JH-_~MC&6.ݺyXԛYy0Q&݉ /9f {u4a7SP BMխ@y˻xي[w=|%כ^EÇ_*X>Jnw>g|獫ǧi٦LR^ǎK,^mͭ.z"$ oS3>`WAGQ=ڪ9iļre{[KC2450ByyEBy :c'A/#cA/*kW,r.oõ4} S&D z[ z"0 #E J@~!ૢE_UT6/Cѽ.2ʲҢO#_=P'lB\[Rt_^O$$[P\ZVY][ yϞB_@P)D,2,H}AqMꠞ^}CS>~’5u>|II _fV9+p@}ӕf\wLK?[3arӳrvmn!rϤ#G;RVW|E- .zqM&'adey FO;ƺkuZJRlD _FqRe2"nU^Eh?ߧh:V\wF&Mv+oҥ%Ep|.aD*/e;/̬qMZR1ƌ]v M\t|I6y "'dҥׄ%EeҒg9Kb,[0~yQSk’oז* H-XB qMhܲAmrJ+VYKV#橩5bmn|۷lؠqF̈^\%Sx/h78fjaiaČ,)`5qV'MMLN0bJT㚴%G{G+.95&,)_x辷ǝw<=yʩaČ,)`5 y@p(#fDcIASDGE%$aČ-):?7;#=-555-=#+' ˆQ[R*˾rI1#%yʊ򲲲J˕nH][G8/qR Zq8n5z-Xj䋺Guܭ`fwBX?=`q ߦ-&L0a„ &L0a„ &L0abIH*j endstream endobj 239 0 obj 4084 endobj 215 0 obj < ] /SMask 241 0 R >> stream xUǻAx 8]d[Pg$5Hr FT i04A % sXî}/b:=?@N﹧AAᘂr x#8"=Hğ]#".FYbtD%Ѕ H$=U+lb.F bPBZdC׃G B|V"bYgXʠ#+?e%oV"YId$DV"xG(<  CQbfr.O2+xAR+xAr+x>X]ei0WI'])OXG.k v10.DJV0%Ra`aE @V@V9ONV0yұaND^ +Pкh]![Ne a,'Zx> ՉG4;p(w᱋D06D: cI#}*OLࡋ儡rxh[hڃL>kOv16峺x07!}'m3]?bot10O:X? *ðr:b ]̻A`0Aa0,Aa0{(0ż0oF;M^;Rr>oLvp˰#%ffq3$ BlpԽŎn%$}-}$}-[h f数Hm_`^53hڒ >sg:]Sbݴ@I4eh%Z2Mܷbdf%ʹ :VzKJ|nvBJoU/`ބJt-! CR|⊧,!)7^#`mN4>$ŐNժUR犒Ɛ_VS,&WӛYRuݵ"Lv(O׿N⊘@FaY$r:V^]Z`ޢԭ0%7f 1՜Ϡu)–5jԬ)Nɜ0",'F KMwe*00 5=͖ej"hc{'Ia̼7!sk)^4D`ltƤ\/RL c'Y2gZPN|)l&BڵF1 N[aMJN:uj+b cӬȞI֤PN̋&06~imYr:?YrXtwuUw2f`] b%ؿ L"–K޻/R,0,Q[ :;w(@zI7+;($twShcӬpnAQH=v9٠AzN٬ƫDd#&T4ܨd6N7/ s+,Jy@Ra`қenO( 6T&Y_UxLo\F /d2+ Zr_xL՛5hS/YY L=V( 'jǛT1,Y L[ \zA2&M^|V^^fQq&M11 .37¨_͍b c>+'|l 1raUW7 ^41.7zE1ª߽MLIy\q%VYMe1,y`.o=r)qۓ v͚^@G0ޛ2kIpy!k3͛7'es`S)hx1Rȫw~!,0)=\6r!wOvv6E.{\'lŋ&0LpV}+[.̽ Ip*l"0Mc>+ t!PKKi`'/'j%]G&U_b cqV*- t1EVd1IeV}1!m٢E̋&0)ʕ#b^eKɋ&0&*(3$֭[TĴwf(Xe|o`έ/-MtVK:/S6 Yy&xmڴ!$^gU%v[ŋ&0/SM ֦1|}61o:E]I1I6+?}m۵Ҭ܋,j6E2JK۷oK[ʳP,С"Yg@_tG1Q,C@cdlKoޗEzipO4+3+K Y H;T1,|ȡN:^Lc<+'pWN( ;%)Q`g-OCM1EYY ɉΝ;v$ܩdA)ΰΝe1w;Y,ޣy@gRHbPClڵ*Z`blteؽ] /=\BYr@׮cpYt x2K.$|D)Mn]/?\vC)QѭEM#1tfP=T1;%JqC40Yi0 H/~M`Ci6tz&ɬ< no3<&tݞLCt 躽͢@~Ra`f6b c<+,'3EYy-t^gr߾=I1qK<hI}bNhVl[40d';=Ϙ~b ?+ ]9ߧO?K߄K,0}_V#{lV~d(߿*ʽpww{xcBz7 vV>]1<4h K_ x`ED\T\`"7 wsC Q 2 $ft\pp!C1u26pEL`N9 <0S冧ss%/恑X^x}ذaltaM`O@ %/ 7 ߡkEE\}'ftCEEB 2T8*00rܑ#I/mЕr){&~V_ׇT1ENFkJyjHK-n2mi`$1B $X_.+#M`td:20?*O;V2*a`B?v,!00E/>3~,00b'H(=-6 `fRh#9 ]aƬYr鯀_!zti@/̞= L)tiٲ}`NC1sFho8sbbKfxtdg+㘷KK%/6ti9sJ1௳rfΜ20gk9r¸_,hta\o޼20.kv<3o!T.%.Yh3 >p"E  (,\ ?/^HQ~l`0pbY"B ~ J^k[8筁`E Nx<H~l`T`jjK(ٽdjEL407+RL]"XDl. }fU΃狥k/5x[T tEw*bVd/u j*UtEUA tAO^9]"u1N Vb^1_@\v)DƵke1U "7n(bނd"F%t=`%eWAD( ]"erW^"WY WZr@R7r7o] "svͲA 2gnHbG)ᯛ6mUl؀=%\ڴ)t5̥-[6bC(ܲEuk9t1‰Jɋ(Oi /T*b6} ] Xz] m^P@ׂDپm,0%/CХ Qvخy$ʞХ Qc,t)H/ H^ބ.{_@Wĸk^IJ%{9]  o.I DRįD/AWJ t%H J$J޽[kJ=wKb@HZpǘ*'y?س';E/kTqrȾu $'8 h ӗ^>!% UE/hO/]-U Z/#tcǎ;3oZ e #Gx t#h6:|ȯ@t|~aBO>VhWNDGW\A+ay9Zנk@\}wᅬV˗ uv·)GB!wBWsP)c{A+4?@#.1Fކ.AAA4] endstream endobj 240 0 obj 5616 endobj 241 0 obj <> stream xչ;(p1 - \҆E -(ivdsdmFAmYUmFVYdA%HA5zNݧ֩>[]   SV ]LIA׀x<tHKZ9d-.!Px<ŜCPas aObN])V<(t=Hԣ% ]K `'ɊNj] $+O*1a,~C-t]|0c$bSY>V0 3+xE<"jn>ia>}2G v12ӂaT dfè<ҧHAV#b Q";+xFhvVH Y[.F`ab&'+xo3ܴ`@VIV0F ra E^VDVB4O+xfy[0 [NVYVY5V0Z|i0 )[d-<Yă]!F$CEk < ˑb=F$0,B>~دDXPR"],3KðU%"xfN4ăGfT H`3&S"],Ș(a2DD:TH_Hy -Bv 8? aSzd'NÝxxbw"aN<\1ϑ#OLࡋUW9k\*^5wE|#.> ci#}6y=bln($; \vV^ðb/jZk1x+baXE ۇa^ vK"jsoP$< suPd; z׌nĊ׊H@5ؑ6/Î0Rу)~襢3R8^ bgJz(Šf/vW"H@/MX^(0"P4a䑰2/Bф#^腢 #RD6T׉*HCUؐ>ψxl<;^'0"% NTaDJz†$aDzROrvs(Ł =#R"D@Pa㹉28@PA)86@/]ynz†ξD)86Tx׉*HCMxn8Bф)A腢 +RB EVD&H)^($gwl<7#3R+_ l_bEJ oA8*5)!kHXrk_o2#̂@&ʽ_C/9 1|83R?dzϳ#؂Ŵ@q4vDXO (Hݷv8cHI,/Px@RoͲCJb&$l%$?!)Y5)Rvӏ[(E~CR*VT ȋ/'OcHJ*)^( xoNǒ]_'Rv`|_\H/TYyE]ʕU/sY"SRbӫT\S~1=ȚS7 $mް]˒vfQh]fMULu}'hV}WJ2œF>+۱ Q7yEj&YٞM>Nz+IH/fe6Vؓ[YV-Ջ&064RBv`=j׮USS}9ҋ&0\v>{9^WHq>ŋ&0LrVU sH\*#40>[aa%?PL~V]\Ib kˉ_0-%6i&Md1fV }1a\nִi‹&0Y[/F&̼XQfM`n5 LYikQ(eI͛7oidYw9`ۚ+^& LR&,0SMiѢ%o>+7q[(^4vV>}!b"-47 upg&ziaY][)00f^/]|تU˖d4+vDj L2J+[nEIPoӦ"e8+Oq6md/Mc2+˙*00fЗ>'NQlh\}n˝6N~V> }nx۶mU/~(ն-!00&2Jhڦ ܬcŽhc>++ ];ھ}v;40(ݾ,.}'K9ջohO,0b:t蠊,0N6x2n.CZ~s@cts9terǎU1IysRlN:^41RlS'ً&0wFC]LΝ;bw2Kb'⥓i`2)t6 ]g ^Ro,.լE LYy}^Ror`< >M`R}qSEe 悇zcINzL~}b d)+߯,00Yy^41߆.. п?!&if%t}~NB  $00/z䏿>1iCr‹y`&B OH^#_byA(b Ct=rï"h|V~X?xEE1C V;60{K减2D240.#>(1 *e\1sPK+tCC^4I_C!NF]JybװafZh2ei`$1_@_ _.+~êM`t:b"d`2 4*O1B2I2 0SK.?.2)U`v ??%C7/X0l@xy|m,g.,eqɅ`E >x4^H~l`Z'̮E$/a袸gŋ1Yŋ^1.{,Y#H_g%E_@ׄ,]*{YL9tM˖-S(^VBׄ\Z"_"0kB.=rERELtM`E $$Ɋ+T1|:OV bty{JK"0!g]yF^@"{Qo;ӫVRH^.AWb^Ex@D+%/!YZ#y8J‹ 3k׮!@׃Yv,Fzt=șu$/ "SĈ^>$]5t=Ȼ%% 1A${D#z9]"sI^d1(3xo1\g XIx)'t9 섮9qYUj7J^$1ᷛ6mTĬ_CiS5j+7oRSN͛e17B(\ݲE"ap(b6}] X{] ϭ[W@ׂٶu,f >ambCپ}"R8{^.@9Х qN y$/vxA] ;$1G+Ast%HΝIݻ%/!س{$d1v핼P9_س' ]B־}IGqau $/h^!EъK/^Y$"t7@Wh9y@ *-ee@@+ fk \F+g{'VtNAAAbGs endstream endobj 242 0 obj 5623 endobj 214 0 obj < ] /SMask 244 0 R >> stream x 0} h=6%Nb$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&ObSP% endstream endobj 243 0 obj 2294 endobj 244 0 obj <> stream x݅CTYpZBqU,{ FֵP;@ TPEsa]9 Ɨg<x?t.P*Q_c(Vu,?.LNI ˊ[gʍDX+gsI:]CI7V(2ߎ2TVR3k 4 W#Jf& vmh(+6! b`w T!j #`AЩNJYGH"8o&b.E4_3:ӣI"^,[u &V +ԝB'Бmf CT~_P7'Jj'YVO) >&aTiY@ (,P JJ'cC$LhiBL)Xg;c(\Prsj̰fOl҅EiIA,j4>NCex. a!ۿq1EE:JJ* MP2Y?&)쮉TDRG\F߰%4Akz~JyTwMAhlmoV%k"Um}8tqO ']`Beڭ,L)J JMτQ tϮˈ ?&_KC~&tHe8/ А4:&g~#.Tw)ƤC[7yEil*wģJٯW>!UQK8١"Jt+;dx-QЇi6 ]1Ps/զD]#NB~#kNk:Y%cnuq1Ii3 ?g#] `:n.}+)U1= Hi1m;5p ;&le&Ks`H: 2]jA:ũ6F٠PO- Ъ >djȤu-@2A,T{ҵ9Ճt>)Q;ͅtR?lH:? Hz&xRZqx.˪N'e7|i ?>X5Q}o0{s`9< H ʕv{5_nlʄ<۞_蠮ټ1bnUҩa_UɎ:ܙy < W̼kjzq$aǻdIBvٟG0j C]iİ;)y"NyȋYiNy#N;nʞ] /mAm6Mh4C"ygqCfװ OO:`0ʽ[ ٹ4!Q{{o2}A, X(۳d]!T ǿlZ\#F88QVEQ7?lx_Y<9.y[~۲@&k8.#AYl' ]q{&$}/ E}$4 6g.'1'>Q0T*CY&N(2tAAl̨7@W\8,?y]yM:jV&&$ԪťLyT{ \7';1]2鲂"X^g-.G/7*KqpTd;,V:5ݍ:[yK;`RJM`\^$ͪYBzQ\N0,[R9:FDcy _Ґ ضu%qJ1(oW U>nұHgMn/{U,ITh?#.ɑZTd[t/(*/qllYq.\N[@iYw.VRR{3J'kq\xkc eҟi68Hy3>Vqg(ۆ:CDz X,f/9p٤PBHVUI' k)uLt@ލ,:Q֙s;V 8Jt|Bd;RF/hNr+@[v^{;&l7le?o(g7WM_8p.YoGGQHU M+ 6Z`槢3|&(p7hQ0]1{$y.߬G),F.؃YA?'ܼi.$&iX"¦ &Pz G@D<^Y<嚓BTmB*V >`ROE:,\0b 8׽q.FI2P0mֈ l8l ';gRtRL!_mL:,a8f(?Hrӄt8XϿ?sHg5;B& Pnp,1u-?$A>0 ;m&7f Iy^2gZ >A[$oNt/1?¦=AWvy0s%DQr|7@Q.C3DvD|<T~n;K׾izer]q.? #!~X#NESOq&,Up 5Z 8quNDNjA:̥RAKKRU!ZuԭWaV=& m9rǷ}IK>¨6jdC/\l'Or_荻8vmHG1Tԅ*T3ڿ;v}aM_FFFMu)-߰a666^zF$|( m㮉*vڵ5kvᓏII)iB,.d\˥ Uj ۴iӾG1s={q=g/?IqTjqQ_&&&#,X| sR,߬SV_~ 5`ڭW~C'.]r˗/rK@<.d]+Θܩjjժ)S,۶wa[]>|ׯ_A Y؍VYuӧ/9r;>|f ǜnSwMks'O>{xx M:Yu۰HlƋ;ڋtriY㫓5[i.׌bN4Nl o[Ɨ&*OJ pٕ<ɝڰx,OY貿4!7[ˬ I%&)ҥ9z^Z']kAMqF/xĠ|\e<=b|$*/:jt!]l34*ʚ*1sW j\\2mG3:IW@ἤN)rYYWa-[lkڹK1{ :1+':V.E.tj5i޲}qYlܶmѫ?4]ȏqܖVq>XVTU MM-]==? j526fn111q I)B5N12uh1Bj5 nƤG߾}M2e;w?sǯ}4#WL2TK $}hZ&mw7aEk={? 4"**&At)V2`q*l/c8nwٳ9vW?R#d~yѣGo\{xǗ HU:1{%`rcQ^}VqXc+[11ry[p0ysO "̜ٙ>1;Vofndk} 쀢 Wcv@чIU*Hz*U~Kl#WjnO4MƦwti5ԓ (dJ]qnW(w5Zt+<0xj⎘t3c_ҥHviA:Rw#]` Ό\1ԑti-3n{K6Èt`Ѭ{؀MHVS%O:ľx&4qn'da&Ś[~.]Fxl)NeJq=R T4cKRIWXdFnd4U0rܡ1 ov@Qȵ&+{[$jF:ҴB4Y>}*4m*lJSg+ҕֈ^ȍ~B2 ̼b[+h=@@U#OZT$W3&՜7;TtdP^(U)ꐎHWX:Je/nʒtbh OUiNz}p%P<3;IWX]+ov1teE.am ]`'lA<#]` <.^jü;T%b Jؓy+k3J@7lruҙb  "X)(K0tbh6WUYoN5b;&PŏE:Ҵy@ ͶiEґ-y|(8dk>. ȗHG?F>!]`h#[N L: -ҙ-@=8 Tg&T*,@Yֶ3+m(˴C:R#]`޷5 jg~C;Ls҈y[ BS =O:hES }\̼K<&]`kHgG H;l0%dG3"*\&]`̽Hgjq+P` Neՙ7zceIg4l@:T2@] =uI*mu6 7E G.&lZ͎bL'T~LLCyCJ@]U*3[u6q0$. 63[@ޯ90.ٳ'Z(dEήE:Zt]E]HgI؄Bi5[` wk3mXUw>WeܬǼ[^?~LrjyOxhA:Nu@]䓾;jkE( Snp)t]Exi;m+ߑ dҙ-rl":S$ܷ %hK:TZY AQ>4YE:tA,&qo1)V3K."EGw(Gmwz. ʳTH6* J!]5ҩͧBc|qPVYM."\9I6e.4tfZ?h8vu)>wWѤo'5[*h别룘ȦjlC**ۘvt_GUVؘi_,v *]v@Cfc-4Rg0mR{\htZʹF**!1F+IWť nls+@SZe6IpG:O,&2m4@?9ævJ5@ybvxܐag[IWX%ӱguұͧ;.u^*U-HW%0ұG)Ev^ۈY]@\.43N\hyNҹͫ6?e:ngE3IWX%}Vұ@UV]I:SVV2ˠٳɁtt@79^!V5gec C(.6*o.q/l@ÐÛKJ-7h >؅)gQUU+ԲJ(.iӵCVyuEvsaE*fBUUUՖHɲ2IB$lZBl2zAkPSl폋^7NR~žwdX5'ƶwU)-Ě:. oW} bu֤klp>GqnKYo.zZ#(bN. K F Ph2 ;(^-#Bvd-i_ADN7Q&w:'zqg2b(~׉B\B: -A:`5huX^'j&!lDClwc-+[⊵z. bB۸NbMMM-)8W t=wWgTuZ"]`fUHeq]1ВO;FRXz#s|?Na--mZ. KƯ-/XXL(68/e\' 5JBCd}BSe#=aV~q8+b%\mE/P:]G. sC%XNbaltxO>JU 'IϪ pN%!d?nfZ8ַeR+|!tQeVWdW\' Naa+]1ВDbClbpTdW\L+W֭ΕtMmꪯ1=+W7Db6{o¤J(26tJ:quuu{» F- 9OWA./r\WQMax k@>S ~7;襧 = ^S grF~A' X:Q3! ~Kz)&Ŀ}W@>FC=zw;'ax-DXʸNK;wqB6!p}cX dZ3*čg{%. L5XLm\^_j ?(Zm1)&<-@r9qx7=Gk44C\xt$)D!Z4x'|#]J?F ?ն.{F & 1q8ժ9揹T~ 3bK&ГTKN ʁqZ[p+"HyJ&nb7#Hң<1~{]k0իW7YI(2\Mq{|ICܰYL<,>3qQx{]CEXZQh%݄h5E_f bxE{/Y/& m#n$j,Gq uԩ1 ;%;$JZu{no"o h\'& j֪7a6-du⺝Vb{<~D(]/e\' q͚5kjh~-b'kY+ظՒ)XzRSH֯G{v.P=Yw֕]\>-71(F< ]`P24㺜 ۉ: L`:җA!6j4.@S滕ud4:QkNݾ0zxvSergBz55nݺmg9p0z߯l q^\qT h<"wu[b}fiNy:MD&:.2׉3ld\^uoX 4%zlȠrてlǙ%MV:Q!'t@tA!#tMm=*>'FgIX'an ?;.{w@OV:%M>!nu;>4NU+l2[?`ʅ R/Y%ylgڒ<֡+Ru9!_~f\p%Гe;VvC!5fKM56uEX^'j&D!nph<AF4?q'wcL&6(47eR 1q871[tIuBb9̜ qÿFj1|?ԈFf_M"]`W7~|u #ܨQH ]`~Qՙv#HXT& yCܸqcdиcBܪG tqKqXnnq&M Y%XcnSJb2 q&M6k?{/׵a%|堸7mi)(d * B,y57o5dkb+ 7p7kf:N ـ4# Y&b!/q(ME!nWxM[i0%-;L 3+Ev嬰5kּymۇ`hJ?3FB!nmQ +pբ6b9뚊CܢE֝W+eeEX3Bܪi-x--]5w-Zle:?8)bfοUU#0~6= ;M dzlREzG!2 q˖j=qךH?D"=gđ;~J4zX?.u֝Ny?bAk y-j;Ō!t[fo+챧N q'?qg~W#d!.NM"_mu|1m10eE|!V1A(#^XQaB۴iӮ㠥IX'+mۜ! 9ՙw9`4"Qb:ʇ ׵}&Fn;+m%90&]@@}DOa!ZN^hKE qN=r1čD!!mAK,pv**u90w2hsb#bmKZ:A㺎뺊Cܽ{wsC%0eF{w1;++Qו+yu!5cG:pwiȔU,M|v3!Ÿ.a߷I^)}s-ƾ3s➽,<>tEuot)K׉<:Q7!pϞv ż\ѷaU͜q^}_C_ 4eD;CB{#IXGyH_O;u8'ý{q+@7yêQN#]`/թqqD>}niQ;G`J,?;⻷?JNg\' qA3J#]`n܋Û0"Yfh&mT{A|뫤zCWAJ@[ۦmj1+W膸_{DДFDB,yw}EV/QMG6]Mf㺂7N&:M.NH ad @/ӹ-k1#ăG.: :3Y D!uĢ8[<@?ӹuj0#c-> Ă1%H3^M1+ 2vXzѲwfxY|K!hG q^֥`\'1 xIkF4@WFUב̙VbXL>'Ȁ q1x%>a hs[7QIrP츎n l2"]Ok[9%|Ԩvq])ro?|QxC6zWB&@72##Ư:'6R]؛#.ݸ.a9_p\6DÇO^㘈hy,؈!7goq{=X~\{3\ׯ{NaQGQ]{Gw06d@GiƇp#ظ!._u9݄(#!7c١75h;֬lg% Q{%]`AkKz fX1Sq]:h@j\{G3ss.Vn7]c3$ē A@W׭YOu$-QG3fe6~X025o`7i7M)/wq(ĢfBcOj5 +˹5`Bǎhclkza;6-mܪYҎqdm"'&N8mwY8p#Nޞ!2s1{=n=J;}?vיb\7NL2]]L>$[[4eD5oǟCA঄_[گK..g|DUI|dOӶtgrYf;3* p:OA!.b\7"93'ċ7yC*6_-jޱ-qxmB3!=g_ұ[Ȋvxb 庽xEL'+&(} Diu:bQgB1<>>Af]:5+{%%>I@ ;ݡ0%ī+=PZ9̸N6!n-/^d鲕뷝w @KC΄/Yt=@]vj烳zw+|\On:q70xew8td9X=sL e˖-߰נtU|+܀*Aue όoذqc^%sW%q?ܟl9d`\MH a!޼+_~JBOT%x]:c!(z,5ٴiӾw]9%_]زp`ņX2X#y[/?BKnaIPkp`\'5ě6m޼uBb̘͋o~a (f&x|lu%q]ℨ#7ěnߵgK~&.Ew6Z;!޲um;==(2> knP,njlM3Fl\Wa}*qdmBMl wx;\߷fI3#۶o߾cǞ7P(OWMo7[:NZM QCscg/ݸg4G)ߟ\;bʸQL Νvڽ]/ɩxCѲ>;۝Z2E&!;/IZbQ3C{|XB&֏X1^6£G)z\hw[YY{d._C"}_>w`cbQٻWh\:>E8Ѯ7ZN$0 #m%!޻G=ώW^g9csBo߾>sWHT|Z.Be$Džxwsi$uX 3>qND"eF{>>g*S'2'/LJ 9Mk%u׺u l4=*'N\v׮^~ai/Nfgtv`l8!:} >}䗙mY2i!>)gΜ={-.=}G&$gd5Ǣy1/o۱D㺽r'~[ qɓTnm.^r[vw>r~ۏ!1ɸ$x)Aٷcsg2/gsڊ/\`{νGO_}鋷ϏxYIDM yMgtGr I3!ҵ7nݱ/]?yzzy '&+ oOV߲a%ahm/^xW\zڵk8888׀ qCBBr#E?5.,ՓoYH#nBLvf"E%I^~<o߾{U0՞Ǵo@XLr& +ՆeK[.Z!q͛nݲ}Νw=dzo<ǤI.7x9{ӪEŇX6#NC|FZ'&$Dn7!j&D!)dq?>C{wnݴ~rfO_ǧ ~'%!*",UY%u\GƉҌr'$kⵉO|NP@Ftзw/޲9zh[7o\n5߸}=wtzϯ  GkNܽe])uK^bDDezO]ܾ~Id@M {WOݹugϞ>~X<㺣u6_n}0.]?~߯Tq28)q?||;=zzN3g!>wÇt'88<.9079>&&w^rzh/ݾqxI쒨7ȳ{hÇ8vq= 88,:)))A ] /SMask 247 0 R >> stream xUǻAx 8]d[Pg$5Hr FT i04A % sXî}/b:=?@N﹧AAᘂr x#8"=Hğ]#".FYbtD%Ѕ H$=U+lb.F bPBZdC׃G B|V"bYgXʠ#+?e%oV"YId$DV"xG(<  CQbfr.O2+xAR+xAr+x>X]ei0WI'])OXG.k v10.DJV0%Ra`aE @V@V9ONV0yұaND^ +Pкh]![Ne a,'Zx> ՉG4;p(w᱋D06D: cI#}*OLࡋ儡rxh[hڃL>kOv16峺x07!}'m3]?bot10O:X? *ðr:b ]̻A`0Aa0,Aa0{(0ż0oF;M^;Rr>oLvp˰#%ffq3$ BlpԽŎn%$}-}$}-[h f数Hm_`^53hڒ >sg:]Sbݴ@I4eh%Z2Mܷbdf%ʹ :VzKJ|nvBJoU/`ބJt-! CR|⊧,!)7^#`mN4>$ŐNժUR犒Ɛ_VS,&WӛYRuݵ"Lv(O׿N⊘@FaY$r:V^]Z`ޢԭ0%7f 1՜Ϡu)–5jԬ)Nɜ0",'F KMwe*00 5=͖ej"hc{'Ia̼7!sk)^4D`ltƤ\/RL c'Y2gZPN|)l&BڵF1 N[aMJN:uj+b cӬȞI֤PN̋&06~imYr:?YrXtwuUw2f`] b%ؿ L"–K޻/R,0,Q[ :;w(@zI7+;($twShcӬpnAQH=v9٠AzN٬ƫDd#&T4ܨd6N7/ s+,Jy@Ra`қenO( 6T&Y_UxLo\F /d2+ Zr_xL՛5hS/YY L=V( 'jǛT1,Y L[ \zA2&M^|V^^fQq&M11 .37¨_͍b c>+'|l 1raUW7 ^41.7zE1ª߽MLIy\q%VYMe1,y`.o=r)qۓ v͚^@G0ޛ2kIpy!k3͛7'es`S)hx1Rȫw~!,0)=\6r!wOvv6E.{\'lŋ&0LpV}+[.̽ Ip*l"0Mc>+ t!PKKi`'/'j%]G&U_b cqV*- t1EVd1IeV}1!m٢E̋&0)ʕ#b^eKɋ&0&*(3$֭[TĴwf(Xe|o`έ/-MtVK:/S6 Yy&xmڴ!$^gU%v[ŋ&0/SM ֦1|}61o:E]I1I6+?}m۵Ҭ܋,j6E2JK۷oK[ʳP,С"Yg@_tG1Q,C@cdlKoޗEzipO4+3+K Y H;T1,|ȡN:^Lc<+'pWN( ;%)Q`g-OCM1EYY ɉΝ;v$ܩdA)ΰΝe1w;Y,ޣy@gRHbPClڵ*Z`blteؽ] /=\BYr@׮cpYt x2K.$|D)Mn]/?\vC)QѭEM#1tfP=T1;%JqC40Yi0 H/~M`Ci6tz&ɬ< no3<&tݞLCt 躽͢@~Ra`f6b c<+,'3EYy-t^gr߾=I1qK<hI}bNhVl[40d';=Ϙ~b ?+ ]9ߧO?K߄K,0}_V#{lV~d(߿*ʽpww{xcBz7 vV>]1<4h K_ x`ED\T\`"7 wsC Q 2 $ft\pp!C1u26pEL`N9 <0S冧ss%/恑X^x}ذaltaM`O@ %/ 7 ߡkEE\}'ftCEEB 2T8*00rܑ#I/mЕr){&~V_ׇT1ENFkJyjHK-n2mi`$1B $X_.+#M`td:20?*O;V2*a`B?v,!00E/>3~,00b'H(=-6 `fRh#9 ]aƬYr鯀_!zti@/̞= L)tiٲ}`NC1sFho8sbbKfxtdg+㘷KK%/6ti9sJ1௳rfΜ20gk9r¸_,hta\o޼20.kv<3o!T.%.Yh3 >p"E  (,\ ?/^HQ~l`0pbY"B ~ J^k[8筁`E Nx<H~l`T`jjK(ٽdjEL407+RL]"XDl. }fU΃狥k/5x[T tEw*bVd/u j*UtEUA tAO^9]"u1N Vb^1_@\v)DƵke1U "7n(bނd"F%t=`%eWAD( ]"erW^"WY WZr@R7r7o] "svͲA 2gnHbG)ᯛ6mUl؀=%\ڴ)t5̥-[6bC(ܲEuk9t1‰Jɋ(Oi /T*b6} ] Xz] m^P@ׂDپm,0%/CХ Qvخy$ʞХ Qc,t)H/ H^ބ.{_@Wĸk^IJ%{9]  o.I DRįD/AWJ t%H J$J޽[kJ=wKb@HZpǘ*'y?س';E/kTqrȾu $'8 h ӗ^>!% UE/hO/]-U Z/#tcǎ;3oZ e #Gx t#h6:|ȯ@t|~aBO>VhWNDGW\A+ay9Zנk@\}wᅬV˗ uv·)GB!wBWsP)c{A+4?@#.1Fކ.AAA4] endstream endobj 246 0 obj 5616 endobj 247 0 obj <> stream xչ;(p1 - \҆E -(ivdsdmFAmYUmFVYdA%HA5zNݧ֩>[]   SV ]LIA׀x<tHKZ9d-.!Px<ŜCPas aObN])V<(t=Hԣ% ]K `'ɊNj] $+O*1a,~C-t]|0c$bSY>V0 3+xE<"jn>ia>}2G v12ӂaT dfè<ҧHAV#b Q";+xFhvVH Y[.F`ab&'+xo3ܴ`@VIV0F ra E^VDVB4O+xfy[0 [NVYVY5V0Z|i0 )[d-<Yă]!F$CEk < ˑb=F$0,B>~دDXPR"],3KðU%"xfN4ăGfT H`3&S"],Ș(a2DD:TH_Hy -Bv 8? aSzd'NÝxxbw"aN<\1ϑ#OLࡋUW9k\*^5wE|#.> ci#}6y=bln($; \vV^ðb/jZk1x+baXE ۇa^ vK"jsoP$< suPd; z׌nĊ׊H@5ؑ6/Î0Rу)~襢3R8^ bgJz(Šf/vW"H@/MX^(0"P4a䑰2/Bф#^腢 #RD6T׉*HCUؐ>ψxl<;^'0"% NTaDJz†$aDzROrvs(Ł =#R"D@Pa㹉28@PA)86@/]ynz†ξD)86Tx׉*HCMxn8Bф)A腢 +RB EVD&H)^($gwl<7#3R+_ l_bEJ oA8*5)!kHXrk_o2#̂@&ʽ_C/9 1|83R?dzϳ#؂Ŵ@q4vDXO (Hݷv8cHI,/Px@RoͲCJb&$l%$?!)Y5)Rvӏ[(E~CR*VT ȋ/'OcHJ*)^( xoNǒ]_'Rv`|_\H/TYyE]ʕU/sY"SRbӫT\S~1=ȚS7 $mް]˒vfQh]fMULu}'hV}WJ2œF>+۱ Q7yEj&YٞM>Nz+IH/fe6Vؓ[YV-Ջ&064RBv`=j׮USS}9ҋ&0\v>{9^WHq>ŋ&0LrVU sH\*#40>[aa%?PL~V]\Ib kˉ_0-%6i&Md1fV }1a\nִi‹&0Y[/F&̼XQfM`n5 LYikQ(eI͛7oidYw9`ۚ+^& LR&,0SMiѢ%o>+7q[(^4vV>}!b"-47 upg&ziaY][)00f^/]|تU˖d4+vDj L2J+[nEIPoӦ"e8+Oq6md/Mc2+˙*00fЗ>'NQlh\}n˝6N~V> }nx۶mU/~(ն-!00&2Jhڦ ܬcŽhc>++ ];ھ}v;40(ݾ,.}'K9ջohO,0b:t蠊,0N6x2n.CZ~s@cts9terǎU1IysRlN:^41RlS'ً&0wFC]LΝ;bw2Kb'⥓i`2)t6 ]g ^Ro,.լE LYy}^Ror`< >M`R}qSEe 悇zcINzL~}b d)+߯,00Yy^41߆.. п?!&if%t}~NB  $00/z䏿>1iCr‹y`&B OH^#_byA(b Ct=rï"h|V~X?xEE1C V;60{K减2D240.#>(1 *e\1sPK+tCC^4I_C!NF]JybװafZh2ei`$1_@_ _.+~êM`t:b"d`2 4*O1B2I2 0SK.?.2)U`v ??%C7/X0l@xy|m,g.,eqɅ`E >x4^H~l`Z'̮E$/a袸gŋ1Yŋ^1.{,Y#H_g%E_@ׄ,]*{YL9tM˖-S(^VBׄ\Z"_"0kB.=rERELtM`E $$Ɋ+T1|:OV bty{JK"0!g]yF^@"{Qo;ӫVRH^.AWb^Ex@D+%/!YZ#y8J‹ 3k׮!@׃Yv,Fzt=șu$/ "SĈ^>$]5t=Ȼ%% 1A${D#z9]"sI^d1(3xo1\g XIx)'t9 섮9qYUj7J^$1ᷛ6mTĬ_CiS5j+7oRSN͛e17B(\ݲE"ap(b6}] X{] ϭ[W@ׂٶu,f >ambCپ}"R8{^.@9Х qN y$/vxA] ;$1G+Ast%HΝIݻ%/!س{$d1v핼P9_س' ]B־}IGqau $/h^!EъK/^Y$"t7@Wh9y@ *-ee@@+ fk \F+g{'VtNAAAbGs endstream endobj 248 0 obj 5623 endobj 16 0 obj < ] /SMask 250 0 R >> stream x 0} h=6%Nb$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&Ob$&ObSP% endstream endobj 249 0 obj 2294 endobj 250 0 obj <> stream xuT[pTBAQV>QnEQ[݅؊݊ * J H7 13;0>0[Y=k}J/(tҿp_2HB.zIW/tv=@ezH1pVݎzjzB%xHCAmҨLҿ wV0(eXw @|+'}?W'J ZUQi[7w櫿c#pSs++/`M_BdT?e_B,ҿ WF6,P|n{G_pGy%Z pάjyB\q#H&OEŽL3H ~$.&-rJ[S  x+#.Ho5!3/gSa9}G㹲E|ClGk7_O1K/SO1PKpk(D'L?UH#ӆNzM_q3)Rm!VeBH!7o+-WP(uͿ8#=@f gNUm!`~GF6ga9Ųp=KyUF\l@~o@RO#,PM^cbe$!Lqߚ|菼e6 X;m!V3@ ~ieنXNJ$y-njiBŚP| `:/^IxAX#Xt'_ V@+ӁxA{_h}@@\?]G 73&Lv[o\ɵXO19Rk9tz<#7@sgFbyc_1is7m; (خu?ڊpZv@ p2˰HU(1WV,DpP Z,Juw>IS6(`BDƠ BFEa9u;X+bs"gQl"kP܄xZzcIEPͩQd!hhAO҆zeXNN5 ŊuBHV&$o b(N> w-qpI&O{jioZ1hu=8m&뚪Erޤ0(=N/ܑ$itۓàH|3V[ڕA5Gߊ'A L[G˺$3(Islh~ 8u|R'!o߇@2ʰ\QSpdyBR:  [.p]Rٟϟ ;%K?eFjVEd7 (0 2*XQq;tÄio6[haG=b`%nZ )\FʃNHw:?J%]a%W4lyG.!iLȗ|t];a7Gހru߱@ _յ.qK\`ƕ6b97P]y}뀀(jsBN[ M <3 =&"(XsJWvWG8uYꖈPhf/b]93p|ֵ%v6l?-r93qi8pgerS4YW< _m]͐`W!_Vy@Mr!?/IG ᾩ2V֛tVTLdQHT@7۪R8RN:ȗO\@{I;yxnEP*v{a$m.&ٴ:X# =IStʤsɊTy:Cb6>IȡA[?\Yt&YSKp@3kd(Y:q| 43+.xo7+i0xy>ŜǏ؟tR7q^zD-式jo @]P8s˓Qel0_>6h䲴H6!ؒaFT#!*gF9K{~I{\v #D^iAMS rrmMI[+5b Ų׀ whJ:?0]\ď9Űt/TyЃH ^ߪK(l諆q}IXGbeۿaS_m6O )斌!bus0ᙕ2nA%kEv%)KUČ m@!pYQKĹi7 0$H׼ G^e}AԭqoF\ 韦`V'Eϱ_N&:49@Ȼ<:)K#P;(鿵&zuPw  P/qcm7cWSyF|FPێnWX+UĹؼwꦶRi%n0F(vG 7x*][z_\d1((ؼT'`][ܼX/IAnv I'C&Oݛn%b:'6U# NQ-G<vb>6cubPt*8`lfV:39C Ɖ$O)Wb&{,}qf(lNUt~2τt8I^m#,PÎH灛%nooZ߸z <#Y|oiaa񏩩i-LS7?d {Y0zmLj׮YаA *h/ \I_=޸qک#Xp}ѰN:T|b_1ܞ=sf^z5/' ((*(( 9F=g*~3ǎejŲ--G֩SFFFUTXAA%g$'''%$8:^;idɒ:thSt)ć|rpj˖-L?rh_s6mڤzJtTJ & RR###D|?}z}ɓϘ1cz-[-C 7H@}޿uٳg/\p={vЪUjժUz85 bcD<_~vGm۴fe&5T<)ꌹOR߿D+++V I`8mW%D[wܹr䉭ÌIL*Oq 翱9ɘEYԶ%ہUHLƔ$G[IQAsԽ8eYzQ߲QlK3zn'(RFY슔'3?9ܹvՈ;ԯ^a% ښjjjʌ?*|H^2Lbɗ!}Я/Eo>̧ٳ}9s077ڸ^ڕ1yNkAQD)0Beoϟ>}zD4X4ܼ{J"YH*ײCۮv}!F[/o=v%/laa1:h oKB*Ttv%Ս9̨v=dfddRRRb"##_۟߼bI:kHWV+.ko:Rq7oXrH=ztlޤiY0FñV\⸛W"WzIONκO1<<4˧w޽8wO8kjd-=U&r\kΫT= |<==۝9u|ǪyfZuڵ}EP6##:_c>\迍=o\޽u){$*pO21'IUNp=:E&a V:z^. p2*%nYyOة SP'݊6{ѤK\Ƙ-#IbNY*_V?Ŋt\R]J4)_ΫTJ . pE#syJ6*l'yJcWmr]IӜz*n_ҥx3ؐt^paC.m|@sW`4W %WMO4Q|@gҥ:ڎt^t6ti+|QЁjݻ8 yNָJzѽ"JSm1:.6`(:.'  ?Rt^"wz}*xK\qg0t%ID/a*D0[8S[؀H'V LMfbCa4fX1<8 7:`嶤#f뀱)|l3J L 1$ټt8. pG]r#./҅K:Ժ `Jf1JWS+ɼ@<L vu$X)z"]c҉bg*gB,{FTLҕ׍TkLÐ1Euy5!q!tPtdu&ta;ilZ]]L RxD/uL҉L'I'Vav0%HZiJ:y(jၩP mҙCDLb_Qu 8I^ pǂڤ#B H#n7=ҙC3McLq!ߤF_\ \fSxCeK:y(,lXҺ3zItSi!#Ig6Utf0\N.!m).t]C\T%<|H.!7Ah9cCwM0ϫkuyL07-I'6 +Ҷڌs2§l$]8>eIg6joI8$"}T^#]jlUGz`&0w}yҙͣHeF2R'<8 VRA0=Vsw<c;`,=tu0׼!]X^eH677 pH3G~>sn3lbZ l' 0&WUtfsQԜǜ1%b`Eb`.0ҙͣU< %[ӷ h+dK B:iwpm`3>t]C|w{UӕnXpRtftG: VZ3nhH[>w;YlzC. pIΤ3b \?ŐthsSmE,!I{SwO1_jD:ۄi0'xUFDKkOvx pDm/H:5@,%.3ThlWe.I>ћtfht-tYC2-n 6V~8sZ(&L`\cʦueǽ?0rWn/cr8 `,3`msnx`.$ҙMt7$N:i?!]a䌚C[i\wҡx20 ?DUuDb} nRtjs4.׀Ln@,%)ǪQ6$.!9smI63B1x>MNy܌tfsWZ5`c1R΁|kI6ݞH0Q\Ejww< cOmnu Qths|1Cb`.ywMҡrO|4‡?\tjsbtUKчZP Sq?e.Sc#1pi: mnV!\T+m`F]U.2&V"ךtUKqQJ'0e.IYTkVlğL*ّ$L뀅mn> B~i5;? ʞ#7:`!4:%]acJ="0"]km6a} X9SYOqNô:[`HNkK%tUS܆T+~L`Zěv'&. peղ4X\ ,hKRLANIg9ެV')ĺ:`Cc29 Mޑ. pKÑu Vk+_hbyI UʊC,oɫH(-i֍b%ݽ"=Z(e4r'6=:`#Ҷe) j8XlD53*'kiNʴ/h8+beCؾl/\NbрB21#ҴSZtM[R?iVWy!tQ[bԤ(č|. pJem4B\lΨhN`mJVnvLSmƬ\k)o)NC&-.4EnI4@'+ĢEY v 5Ǽ@X ]W]_Mmmmq)h)OBZPbEqrբNv454;*I%ǺB\Ԛ(tQ["0@SǬXIXڶ|y剜 uu"M;: X M!e1 ๮1P>+Œ];>. pKZ^3B\ss4ĹM'6M;`+a&AKvnྼIkܒwbD*XtEn=PJ9S;N}Xw a-jWab7  ?@U) qX"VmZPbnکԙH&14':VWoVbLie*9 M;IuCz%n'b\jUq H7ʌG&1g3'z#]O:U h@!ٱo]׸pT+tig<O5AQ ]=UJd} >f%6;44'ĺo `%yB/qUÜ D>OȰi׼T\O$-ƢvZc`'ʮXA?lv]hF9 M;jiW5`۵EfX1 Vu][9S;/eд+nqvoFMU:xf`qI]Q M b9oq{ re: "mک״Vc`czBV0^\V׭֩#NdTLiPu0iyFԄXڢI+]խ[xhNŠץTd 8=!'nvx\/;ĢE-M;yeӹ~h7+&eL5NfM eX2+PNXw \YX__!.{D$5i&w6m q:9S;b!n +´7k =Lo(]nbÏ;6)5!6I:IQE?ńv z. p0yQ洄XA߭p"Lٺ8Œђv };>Y#ZBTs6VǔV 6Oȸiurơ:`G`cf?6+kN-eX4LCQ6Jҗc52ebY6L{IaJgzB\) a`EкGC\Ȧ]nPx0ꀝ&ĺ=}@ =Iƍ!nhi>m dz܍^tIcɷvlF?~Ldܴby N8Sd<6oCKFn3k3e&Kn6jnP"LpʪKEbMCi?训5mڔU2 /- 1Ѧch՜7t+ }o%!6TAoՙW|3 `uzb!n4g}(v,rIWnA?ZBy3Gv{3zi٢E q״cup_ZI4Q`'=e-#jIB\; ﷎ZbрB2˙zp8B\y GVqoLUxvjwH8&h qGS1 VRҶukQ)nFi3^AQrOxp6tXI(2k#pVdi+JHlj:`%-Qݺ oM;FCw&]8#ֵkv% M ш IWE u={nq6*7+tMc2"n4Z|we^ثzu.NdTLiW{~@ ,4e@:B_򱷱x+X=ܿGx ngIW&5ޔXK\|(vR>CXIkTAq`%}oE?[vR n-+IGzM}BjӮFp> z ^zCoo1kk0)yps|CܹSğo(QIpX{]];a%!~UD Ajĭ5%!1(.]E-݋ ]w'#ĕk[y7tIkӻwoQ)Aigl FNF k#v|`)sfX4'i;̶º u;=wd߾}Ȅ]jF8a <pnjBGb3FM;JFd ,xL߯/mN>Qjvx!f[sxġ lSC^lп~!m>Q'rvUk4>S:`~iaq+>&; E3hɗ5M;V شR׸m XCίOIk4j0+ޫC, q~9S;ԮvzsOb= ']f Kn(5ZMwa>h7wʱOK\~z!Y!40g@A*[;~#]AZ s e8oiWNFcuX:^9~$!~ʾX. :t!C!(Y(q&C wKGk[t5.nvҽ-c1|0qE DQ6ܯz(<l^^\5a(C\vQ0V2\0a$CLܴcup_ZCzk=>S:`Auo\#;Rv5nq+OYobQ%3df333E4Ct?9ű,F`b4v44+ 7.<3Sc,iwm9RcɨDӮI3H%9مm$G;: +Ov̱3z80bMA`Flu`DKQ)qs?@XzqhŌ c-G-OHӮxҢ}Z1e% !newCVbwҤI9RvM9|ݍp  n_<=;' (޴Ek`*F =9SLf"o5kAK/c H t~ft:BܢŪ^I s//5uQ'O8g8v]6]WA/no7/.㫇7,_l!a>x6Gp IzrW/X2'H4z妻ox2 #H wvʕ+Sf-&/{+@/>f(+V'rhΊm|g@"6 _Ϗ.߸zU21æYG~+w^twNbUK%_bco:qX|2>wÚ5kV{Y4݃ރw&]Ƞo;^8՚~о[7CVbQ%4$3;f6 X,dc"}xxn) ac&]#tv„/.m 2ty}I ]#0=1<'w?[bqY9s7[B!>{x;mbѨX2(eT\TM|^i7l҃7G%20)Ĩ+ /9q];!޺Ǡ8{}FoMZv={L$ 7a/%!62,kgٵvzB~h];wx8Ģdybv^qp-\cJH$%G}|֥cٳg]( ̘b5WlR\w\ݽyC[b[]Ԯ@M; ٫lO?t HĄB@ gf&DŽx:ٟ?~۷ls5ƌ;nxFc?3S"‚}}>}ݹGD!> ޽ڙ3rv]N!8k}g>1ȐOoݜ؟=ucǎ9thB5<`[Bz_qDOeD~ 鍻^>w#G>|AB<}rn<- m bc#||޽t}pݥ Ϟ>uXNs!%9[ʼi۝lVqp:5p )-I,.F$*<,,$W.q;}ɓ'Nd #D.ē]|&7|KވR$#,^޽uCwܺaoŋO:%X2'rٴo*67{}ÙMգ& nTpp$_޾}橳W/^psΝ={Ӣ 3f[lͮw|IdS}oߺggQo߼qŋE!̙K9 x"g@!Osnꜥ6N\wr}9{,n,2{?vvO4Rp) {{ׯ_v+W]|%C<}Y`/9%E|zvvc⫒_X4'r9qe״S.޺eLJo8LJ0={g'nQ?5m:tǷ Ki?-16".O:ݖ (J%yqHv'sfv9S;ix>q+4;{J-ŹC\4M;O,ݰ#cRpX'LO ᥛӇotFg,Yz]oXZ !LOMNJ +Tz.gy"g}BAfzJb|L@o.޶,OӴ,OOH'r'$3S5VXo}褝]޾!qIxLgnpMDCG1x^n:66v<}cxXb#Bxx.f (Nqnms J珜Q Y㬏'|g3ÿf|ś7\>yt[7]tǘ6fsރG;y+w:=w{ׯ"cp40hsFzz:/55!28W.ort;8қvwf _w鱇o I))i|YLM 띵Ǐ>|p_[0~&F "vײw|אdd-U&$$%&FGGEEExeG"=Ȓ;ؽ,/0|&="Z$6>11)92!H\gӷHw*lԄ\bsIDTvzW" endstream endobj 251 0 obj 18316 endobj 4 0 obj <> /Length 73 /Filter/FlateDecode >> stream xE̻ @ UlL:7S8'O#,GJYĄ2yvBĊވ&/^ endstream endobj 5 0 obj <> endobj 6 0 obj <> /Length 51 /Filter/FlateDecode >> stream x4ԳP0213Ws Mr,,8& y 'G!K!M  endstream endobj 7 0 obj <> endobj 8 0 obj <> /Length 72 /Filter/FlateDecode >> stream xM!0 y^a<RөFc>rSD4⸢"z!-~[F)? endstream endobj 9 0 obj <> endobj 10 0 obj <> /Length 50 /Filter/FlateDecode >> stream x353R0& \!`jf #x` B_WBB endstream endobj 11 0 obj <> endobj 12 0 obj <> /Length 77 /Filter/FlateDecode >> stream xM10w^NP!Zɖ]UNҗ`9x1b4ɦfr%ٕi ' endstream endobj 13 0 obj <> endobj 14 0 obj <> /Length 51 /Filter/FlateDecode >> stream x364ҳT063\B gUx}9\\ iZ\@w endstream endobj 15 0 obj <> endobj 17 0 obj <> /Length 78 /Filter/FlateDecode >> stream xM10Wx 4P-0utY%|C3K3J}s+H+]@~Mx0iy endstream endobj 18 0 obj <> endobj 19 0 obj <> /Length 53 /Filter/FlateDecode >> stream x3253Q0213W2 MrLMLy@`B_WB: endstream endobj 20 0 obj <> endobj 86 0 obj <> /Length 88 /Filter/FlateDecode >> stream x+T0253U027P(Kֳ@BUepk)q(`Q:W!iӯ 0гTi/JUj0U(PCJ endstream endobj 87 0 obj <> endobj 99 0 obj <> /Length 97 /Filter/FlateDecode >> stream x+T0363Q02T236ҳsl=#0XgUeE\ `!K* 42 R,L3f endstream endobj 100 0 obj <> endobj 101 0 obj <> /Length 77 /Filter/FlateDecode >> stream xM10НS0;hB/s_mqqI^\S}@rɞRk*b%l-{I:; endstream endobj 102 0 obj <> endobj 103 0 obj <> /Length 56 /Filter/FlateDecode >> stream x3573V04W2M,,rL < \̃QRH V^ endstream endobj 104 0 obj <> endobj 105 0 obj <> /Length 77 /Filter/FlateDecode >> stream xM10w^JBCU N}ĺ7,&EAȦ-E-G;,/*3 endstream endobj 106 0 obj <> endobj 107 0 obj <> /Length 52 /Filter/FlateDecode >> stream x3363W04\fB:CRHF< endstream endobj 108 0 obj <> endobj 109 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3353R0413S2333r,  M lS8T35̐LQRHxi endstream endobj 110 0 obj <> endobj 111 0 obj <> /Length 49 /Filter/FlateDecode >> stream x3333W0413Q2 r U 6BOBB(P endstream endobj 112 0 obj <> endobj 113 0 obj <> /Length 71 /Filter/FlateDecode >> stream x3353V3T2333qr,, L=STRH9@P¬ .4-. endstream endobj 114 0 obj <> endobj 115 0 obj <> /Length 44 /Filter/FlateDecode >> stream x3333WP20 ,rPTmBB} V endstream endobj 116 0 obj <> endobj 117 0 obj <> /Length 2513 /Filter/FlateDecode >> stream xuM u ? xŌ#/, {SBDW$D#ϝڷ~f_󽞾şe4뵟ϟ~s}K~, dϟ1*-,jjE[iwV6?_/D1b~i J#Ə~䗾N@g6Fn{V-FğxϏʐw''"1΋}3JAv+QC 6?1Lj>W?bW+5F̿s#y+gCbDdfzؠD; |{^? xNv(ǯ-*^Z~eǯ3~_bD'?5F_~jyh-FĶ:neRC5F^y(&Ig P'ygA*Y gcz_v1Ljx_W"1Nj0QbD|j?z,PJxSyow''"\ ?c32R|Ӌ 2 )Qb%C,P 0KO>k SHƯW+k?.{2I$F~j<_O5 J; $W` |v78#E_UPe%Ufꫦ]vEp؆B#qF#?__@5FğO㟚vùi1bsli#Mz&!#R 3Q ^; R YHEZcoveIge7ks݃?a+%F_lՔ/fObt+ V2$٠#~h dHq7,/@l7~fV, Ŭ.^lk3iziW+5F/gĈ֪M-(m>LAJlNf;39=Fğu\)RI,av%*R)%[IE T;i(DwYvWTPB9SJ*52vc,*Cgv#<}*C%!#[v^;3Ql7&;NYҤuh^77"1uPjt<P::&jwϯC)NXβ]nhwM-FķủO9{ =F_U@& СD+!oKWyءםIIC`!}gnoC x%`m' 0H&ĈSy'} C5FOV[r=}3WmTo(DXٷ[ 9=1ňy n7|͋߀߈XbD|Bn@1bZsK#NF-忲 2dkRn%Jx813~-D$(_d ,5H֛B.~~#bmX|7F MTf#1~5hj۸HXHs51Fy39=FķMEL0HF|kVx%C=Ch#UϬT{˷ ɠNC^d]o׼ |%bNMF} 9K}[vN61bi&>)@@\~&~#(ap!4HwE /)K|kxq&͎D_+%F_c;绛(UEPA*(nbzv{f>TP$ -B#/E|w"pJxIsv|͋1"9jn|A*9a7½ )FݚWw0y%_$v}ɋ߁߉Xck7npAyݯ֮MvEPAZHƈ5;/wV lD&@0W^E-^Pjv=BYHÕⲆ$_D,1"i.!;CiE_ $J=[={&B$!#[@c'{F PȄx.7?1Lj&yn"HADINk7M\?4  EU~]DXHӕW,zQt#SKNݼ Kͦ#;Bv F:6 endstream endobj 118 0 obj <> endobj 119 0 obj <> /Length 49 /Filter/FlateDecode >> stream x3333W0423Q2 r U 6BOBBND endstream endobj 120 0 obj <> endobj 133 0 obj <> /Length 91 /Filter/FlateDecode >> stream x+T0333R0443T 3Fpepk)q(`Q:W!ilbr.Xh[Ԥ`hdP endstream endobj 134 0 obj <> endobj 135 0 obj <> /Length 76 /Filter/FlateDecode >> stream xM1 =!CC1t<۲uW^5/]V]R۪_J\s+;}N } 6x endstream endobj 136 0 obj <> endobj 137 0 obj <> /Length 51 /Filter/FlateDecode >> stream x3103R016ճT2 ,,r gUx}9\\ iZ\: endstream endobj 138 0 obj <> endobj 139 0 obj <> /Length 73 /Filter/FlateDecode >> stream xE;CwNف2xU^օ ŅJ'4TNVXk6\5h>j>]bg endstream endobj 140 0 obj <> endobj 141 0 obj <> /Length 52 /Filter/FlateDecode >> stream x4ԳP023R4ԳT0213TQ48=9 \ iZ\ endstream endobj 142 0 obj <> endobj 143 0 obj <> /Length 74 /Filter/FlateDecode >> stream xE1@{^"܅ +XM&4]07u> endobj 145 0 obj <> /Length 53 /Filter/FlateDecode >> stream x3453R0213W2 Mr MMy@`B_WB8 endstream endobj 146 0 obj <> endobj 147 0 obj <> /Length 4211 /Filter/FlateDecode >> stream xKrDo@A|H;h{SB~C&yd|m_y߾׿~%_+};Wdv5;?7Ќ|mK+}7;k }J)қ_J}xޟ~DꦩM:;@ 8py ~{ SqLũT?Q9̀w~SL2UT![(t_. 'B *d s"MS)gf94p yӽ-raWvU_pz_e4Ls)wUhWvUhWB+QK ޜ>80!"؜v>k=vC8D'Uc}k*Tc&PJEӆ9Jt'o\3MG@*{^qҶ:Y)x>k ęUnO^_DBӬ{|"7`g* Hs4QRs@. I@+M5c`Id~^d!H i%HErAoJ"d(H9)~Xz$9Mbf: JZ囔cxf $)rh .|Jbv;5mU9m(7ZT I*$)̒\Dܔ *ԪPBRSBT,!G4U'uIc#Vh@%RêܞPH-kDhĽJ~ܔRA_3*^#B`ӶC8vb%.%RAh<_r]Q7d`;!`qK v@l_ 6S7( ŐD z+:@QK,~;UA(v,mK?Q(!or΀r}}nJb 5(֠X[()qLEKpiõ۠X[)vz%%m`Wڸ==2.q?NșhTqATR\qZdVr;oJPUiҨ2Nv5_gW!H +kJ 2enOiN[F\=QA'qQ'jOO2 Ro r*P@-崲QeYAT0ytJ^VPĂ[Npi喷xxn rB,pzUjِz ܤ Z j3g^S j8'dPVj]sJ~Es3is4uO@Pj92e zQ?}Sj9r׽yrHhOi91' ȸW\}BEv(ǜx4 91I{P|A܏4P*(y,d9 ˱O8'~RAG?@€bh)JT3:@2ܾJ; J/ 49(}ᓒ00D=Aب|?YjAm IAQ`3lsF\ %f">) Cܞ3#~C+ ۜQ qQ\ UTpygnH€P 'f~ff^d{}~C.թB t* DsT0 P+'D'7  vYj8ge+H71MaA"yeT )PĀDwi 8g|'5GseJ8(*qp/w"PT11SyG:GHKLN覹>}(jP f9/reZ;B7p.LS Jo>j@:GZ1Gq#r>MAW 3 }^YƽGѧ5VժA+T+*2N(11(^jո=i'4vFOmЪA+Ԁ+ 2=>ݰVl/u2 VٰDa2N(1b&c:G9pK+` ml X,&4e[6c1aw0Bs'l 6G' ]''N}yDcXKhWP+Zg-D t QJB6aͷQ [TR lȰ nP$qBA]?7limST(u~ C\ %+™mǰ neK +JRo( Ȱ NP/Ų_Wqu SSN}"6ڀ   ^C>ђ%% ;-$>)Ȱ$Ѱ$P5TcITTmzJϭ|a١m$ŀ òCo6fCS`m>:>}V ÂCo6fCy e&g6xfggMm@֐ߐ_5jܞ5)7W6xeC ]l @X^0xeǑȑH.C߸=sƻ ;:!nXƽzĜ r ;̰5xsF' *q{*&#FwՅ.G1\ƍs%/%[:;[xfر0þ0[:* ʢGR$|L; hqa"BGoX@бQuT}қwk]Wf'%T+!tho_!ܢRzc ;b %Ec 9?IJQ@Fӎc ;\kgڑJ%ݢpq,tX]uT}/6S J3t8]u8]ݢG: : E*Bu]G[ƍ X.`p]_pvrAu8]Gxݣ 8]rAGn:6(DZ\:j߾[,(v G қr`ñ~ll@1P y)Xz endstream endobj 148 0 obj <> endobj 149 0 obj <> /Length 50 /Filter/FlateDecode >> stream x345ѳP02\Q045> endobj 151 0 obj <> /Length 75 /Filter/FlateDecode >> stream xE10 C=5hCJ҅}K҉Whʍ F֬Z%z)ũKGp endstream endobj 152 0 obj <> endobj 153 0 obj <> /Length 53 /Filter/FlateDecode >> stream x4ԳP04W4ԳT029 FPcigt(dp)iq: } endstream endobj 154 0 obj <> endobj 155 0 obj <> /Length 76 /Filter/FlateDecode >> stream xE10 3EZ+mK'.-c+j{э ,JdF]oSR+u_ endstream endobj 156 0 obj <> endobj 157 0 obj <> /Length 55 /Filter/FlateDecode >> stream x3453R04W2,,r MM< \̃QRHhN endstream endobj 158 0 obj <> endobj 159 0 obj <> /Length 75 /Filter/FlateDecode >> stream xE;0 =`{"PTHL֓-k@XX!'KZOc-J7u  endstream endobj 160 0 obj <> endobj 161 0 obj <> /Length 53 /Filter/FlateDecode >> stream x343U063׳T2L ,r M > endobj 163 0 obj <> /Length 77 /Filter/FlateDecode >> stream xE9@{^: r|(ڂͲM*{dkx-Z(8o0SlZMaM!x6 endstream endobj 164 0 obj <> endobj 165 0 obj <> /Length 53 /Filter/FlateDecode >> stream x364ճP0213W2 Mr ,y@`B_WB=; endstream endobj 166 0 obj <> endobj 167 0 obj <> /Length 91 /Filter/FlateDecode >> stream x+T064S027P2643sl !2µ @(P47J Y**X*g(rG endstream endobj 168 0 obj <> endobj 169 0 obj <> /Length 77 /Filter/FlateDecode >> stream xM10CѝSx .TeH￶adK Oh;Rl u@Y> endobj 171 0 obj <> /Length 55 /Filter/FlateDecode >> stream x3253Q04W2,,rLML< \̃QRH X endstream endobj 172 0 obj <> endobj 173 0 obj <> /Length 77 /Filter/FlateDecode >> stream xM10 3C:4m>WH&&d8N%SX6M#5E3 ϟpX96: 2 endstream endobj 174 0 obj <> endobj 175 0 obj <> /Length 54 /Filter/FlateDecode >> stream x364ճP04W2,,r ̀4gYy0]9 \ iZ\ ng endstream endobj 176 0 obj <> endobj 177 0 obj <> /Length 77 /Filter/FlateDecode >> stream xM10WxpCUu2عthJla3K鄍%{Io3 K>-gl endstream endobj 178 0 obj <> endobj 179 0 obj <> /Length 53 /Filter/FlateDecode >> stream x313V0213W2 MrL Ly@  .4-.9 endstream endobj 180 0 obj <> endobj 181 0 obj <> /Length 76 /Filter/FlateDecode >> stream xM10{^q#VHeDz7Kjp0MsS`g#lSMYp\a(+.<l endstream endobj 182 0 obj <> endobj 183 0 obj <> /Length 51 /Filter/FlateDecode >> stream x3173W02\&B:CRH?9 endstream endobj 184 0 obj <> endobj 185 0 obj <> /Length 75 /Filter/FlateDecode >> stream xM!0=8]P`HP6D]ɉE.r@s[#7w+Qu endstream endobj 186 0 obj <> endobj 187 0 obj <> /Length 54 /Filter/FlateDecode >> stream x313V023R2LL rL 0yf @ .4-.: endstream endobj 188 0 obj <> endobj 189 0 obj <> /Length 74 /Filter/FlateDecode >> stream xM1@{^98*$c2X>yMdX<콽Km^,"_q"= - endstream endobj 190 0 obj <> endobj 191 0 obj <> /Length 53 /Filter/FlateDecode >> stream x3173W02\&BgUx}9\\ iZ\B endstream endobj 192 0 obj <> endobj 193 0 obj <> /Length 76 /Filter/FlateDecode >> stream xM10w^CUk S'ЙapҥZòT2}zxo}.}DC>7 endstream endobj 194 0 obj <> endobj 195 0 obj <> /Length 56 /Filter/FlateDecode >> stream x313V04W2M,,rL < \ăQRHkQ endstream endobj 196 0 obj <> endobj 197 0 obj <> /Length 76 /Filter/FlateDecode >> stream xM10{^qE& B"`cw;sʽ1$RE :.飶\ݑqa^9 endstream endobj 198 0 obj <> endobj 199 0 obj <> /Length 55 /Filter/FlateDecode >> stream x3173W04W2,,rL̍,< \̃QRH Tq endstream endobj 200 0 obj <> endobj 201 0 obj <> /Length 76 /Filter/FlateDecode >> stream xM;0 C3CD !r=4zؘ+4vtt+&m܂q endstream endobj 202 0 obj <> endobj 203 0 obj <> /Length 51 /Filter/FlateDecode >> stream x317ҳT063\&B gUx}9\\ iZ\F$ endstream endobj 204 0 obj <> endobj 205 0 obj <> /Length 76 /Filter/FlateDecode >> stream xM10W0w@@?TuH60uNC!SBء'Gdk,y$٪/s;+ endstream endobj 206 0 obj <> endobj 207 0 obj <> /Length 58 /Filter/FlateDecode >> stream x3323U063׳T2M ,ř,Ar@9V !pep)iqEz endstream endobj 208 0 obj <> endobj 209 0 obj <> /Length 76 /Filter/FlateDecode >> stream xM9@ 5E8ɇl**]']/b15%{S{1-E?3wM[x!< endstream endobj 210 0 obj <> endobj 211 0 obj <> /Length 51 /Filter/FlateDecode >> stream x34ѳP063׳T2L dgUx}9\\ iZ\LB endstream endobj 212 0 obj <> endobj 217 0 obj <> /Length 56 /Filter/FlateDecode >> stream x3P0¢tBCS#=0XT@XBH!9K3L%_! _ endstream endobj 218 0 obj <> endobj 219 0 obj <> /Length 40 /Filter/FlateDecode >> stream x3P0¢tB}W`#C b"#Cs|@.X endstream endobj 220 0 obj <> endobj 221 0 obj <> /Length 102 /Filter/FlateDecode >> stream xM0C~B<-BBej NB f$syuY<A z OQÏJE:>KፓtxNWsK$ endstream endobj 222 0 obj <> endobj 223 0 obj <> /Length 99 /Filter/FlateDecode >> stream xM90{^Ab%E) ȉ1Adhz } C7t53D0;1û),#\CvW[lu)mNa/ }8=y$ endstream endobj 224 0 obj <> endobj 225 0 obj <> /Length 102 /Filter/FlateDecode >> stream xM;0C*!|NTuHHUe0PiZ$'#!m?8f(|;U{FV.MW+^8np&$ endstream endobj 226 0 obj <> endobj 227 0 obj <> /Length 100 /Filter/FlateDecode >> stream xM10 "3!Vv'N*5\u*M(TFg6mE `3LZ"H={3->e{̱Lr,q7# endstream endobj 228 0 obj <> endobj 229 0 obj <> /Length 105 /Filter/FlateDecode >> stream xM9 {^:|(JAf1QDcik]U.$3V *I Wa <(.DS2ivYs9Ntl% endstream endobj 230 0 obj <> endobj 231 0 obj <> /Length 100 /Filter/FlateDecode >> stream xM;0CwNK.TuH6 ?\ ?I#ÎnơkJ15$ё6$$;(VOƜbSINI<$ endstream endobj 232 0 obj <> endobj 233 0 obj <> /Length 105 /Filter/FlateDecode >> stream xM90 5|!"EI(RZ صJtIT&R! 9/:&)kg.f~NO~Bedt2M粳S%M endstream endobj 234 0 obj <> endobj 235 0 obj <> /Length 103 /Filter/FlateDecode >> stream xM= НS0w ֟OP-۸ / $WS!J&ե7Rw <\;V$g|iI?;8&zF.$ endstream endobj 236 0 obj <> endobj 253 0 obj <> stream x7.U  endstream endobj 254 0 obj 14 endobj 132 0 obj <> endobj 255 0 obj <> stream x7.U  endstream endobj 256 0 obj 14 endobj 131 0 obj <> endobj 257 0 obj <> stream x7.U  endstream endobj 258 0 obj 14 endobj 130 0 obj <> endobj 259 0 obj <> stream x7.U  endstream endobj 260 0 obj 14 endobj 129 0 obj <> endobj 261 0 obj <> stream x7.U  endstream endobj 262 0 obj 14 endobj 128 0 obj <> endobj 263 0 obj <> stream x7.U  endstream endobj 264 0 obj 14 endobj 127 0 obj <> endobj 265 0 obj <> stream x7.U  endstream endobj 266 0 obj 14 endobj 126 0 obj <> endobj 267 0 obj <> stream x7.U  endstream endobj 268 0 obj 14 endobj 125 0 obj <> endobj 269 0 obj <> stream x7.U  endstream endobj 270 0 obj 14 endobj 124 0 obj <> endobj 271 0 obj <> stream x7.U  endstream endobj 272 0 obj 14 endobj 123 0 obj <> endobj 273 0 obj <> stream x7.U  endstream endobj 274 0 obj 14 endobj 122 0 obj <> endobj 275 0 obj <> stream x7.U  endstream endobj 276 0 obj 14 endobj 121 0 obj <> endobj 277 0 obj <> stream x7.U  endstream endobj 278 0 obj 14 endobj 98 0 obj <> endobj 279 0 obj <> stream x7.U  endstream endobj 280 0 obj 14 endobj 97 0 obj <> endobj 281 0 obj <> stream x7.U  endstream endobj 282 0 obj 14 endobj 96 0 obj <> endobj 283 0 obj <> stream x7.U  endstream endobj 284 0 obj 14 endobj 95 0 obj <> endobj 285 0 obj <> stream x7.U  endstream endobj 286 0 obj 14 endobj 94 0 obj <> endobj 287 0 obj <> stream x7.U  endstream endobj 288 0 obj 14 endobj 93 0 obj <> endobj 289 0 obj <> stream x7.U  endstream endobj 290 0 obj 14 endobj 92 0 obj <> endobj 291 0 obj <> stream x7.U  endstream endobj 292 0 obj 14 endobj 91 0 obj <> endobj 293 0 obj <> stream x7.U  endstream endobj 294 0 obj 14 endobj 90 0 obj <> endobj 295 0 obj <> stream x7.U  endstream endobj 296 0 obj 14 endobj 89 0 obj <> endobj 297 0 obj <> stream x7.U  endstream endobj 298 0 obj 14 endobj 88 0 obj <> endobj 299 0 obj <> stream x7.U  endstream endobj 300 0 obj 14 endobj 85 0 obj <> endobj 301 0 obj <> stream x7.U  endstream endobj 302 0 obj 14 endobj 84 0 obj <> endobj 303 0 obj <> stream x7.U  endstream endobj 304 0 obj 14 endobj 83 0 obj <> endobj 305 0 obj <> stream x7.U  endstream endobj 306 0 obj 14 endobj 82 0 obj <> endobj 307 0 obj <> stream x7.U  endstream endobj 308 0 obj 14 endobj 81 0 obj <> endobj 309 0 obj <> stream x7.U  endstream endobj 310 0 obj 14 endobj 80 0 obj <> endobj 311 0 obj <> stream x7.U  endstream endobj 312 0 obj 14 endobj 79 0 obj <> endobj 313 0 obj <> stream x7.U  endstream endobj 314 0 obj 14 endobj 78 0 obj <> endobj 315 0 obj <> stream x7.U  endstream endobj 316 0 obj 14 endobj 77 0 obj <> endobj 317 0 obj <> stream x7.U  endstream endobj 318 0 obj 14 endobj 76 0 obj <> endobj 319 0 obj <> stream x7.U  endstream endobj 320 0 obj 14 endobj 75 0 obj <> endobj 321 0 obj <> stream x7.U  endstream endobj 322 0 obj 14 endobj 74 0 obj <> endobj 323 0 obj <> stream x7.U  endstream endobj 324 0 obj 14 endobj 73 0 obj <> endobj 325 0 obj <> stream x7.U  endstream endobj 326 0 obj 14 endobj 72 0 obj <> endobj 327 0 obj <> stream x7.U  endstream endobj 328 0 obj 14 endobj 71 0 obj <> endobj 329 0 obj <> stream x7.U  endstream endobj 330 0 obj 14 endobj 70 0 obj <> endobj 331 0 obj <> stream x7.U  endstream endobj 332 0 obj 14 endobj 69 0 obj <> endobj 333 0 obj <> stream x7.U  endstream endobj 334 0 obj 14 endobj 68 0 obj <> endobj 335 0 obj <> stream x7.U  endstream endobj 336 0 obj 14 endobj 67 0 obj <> endobj 337 0 obj <> stream x7.U  endstream endobj 338 0 obj 14 endobj 66 0 obj <> endobj 339 0 obj <> stream x7.U  endstream endobj 340 0 obj 14 endobj 65 0 obj <> endobj 341 0 obj <> stream x7.U  endstream endobj 342 0 obj 14 endobj 64 0 obj <> endobj 343 0 obj <> stream x7.U  endstream endobj 344 0 obj 14 endobj 63 0 obj <> endobj 345 0 obj <> stream x7.U  endstream endobj 346 0 obj 14 endobj 62 0 obj <> endobj 347 0 obj <> stream x7.U  endstream endobj 348 0 obj 14 endobj 61 0 obj <> endobj 349 0 obj <> stream x7.U  endstream endobj 350 0 obj 14 endobj 60 0 obj <> endobj 351 0 obj <> stream x7.U  endstream endobj 352 0 obj 14 endobj 59 0 obj <> endobj 353 0 obj <> stream x7.U  endstream endobj 354 0 obj 14 endobj 58 0 obj <> endobj 355 0 obj <> stream x7.U  endstream endobj 356 0 obj 14 endobj 57 0 obj <> endobj 357 0 obj <> stream x7.U  endstream endobj 358 0 obj 14 endobj 56 0 obj <> endobj 359 0 obj <> stream x7.U  endstream endobj 360 0 obj 14 endobj 55 0 obj <> endobj 361 0 obj <> stream x7.U  endstream endobj 362 0 obj 14 endobj 54 0 obj <> endobj 363 0 obj <> stream x7.U  endstream endobj 364 0 obj 14 endobj 53 0 obj <> endobj 365 0 obj <> stream x7.U  endstream endobj 366 0 obj 14 endobj 52 0 obj <> endobj 367 0 obj <> stream x7.U  endstream endobj 368 0 obj 14 endobj 51 0 obj <> endobj 369 0 obj <> stream x7.U  endstream endobj 370 0 obj 14 endobj 50 0 obj <> endobj 371 0 obj <> stream x7.U  endstream endobj 372 0 obj 14 endobj 49 0 obj <> endobj 373 0 obj <> stream x7.U  endstream endobj 374 0 obj 14 endobj 48 0 obj <> endobj 375 0 obj <> stream x7.U  endstream endobj 376 0 obj 14 endobj 47 0 obj <> endobj 377 0 obj <> stream x7.U  endstream endobj 378 0 obj 14 endobj 46 0 obj <> endobj 379 0 obj <> stream x7.U  endstream endobj 380 0 obj 14 endobj 45 0 obj <> endobj 381 0 obj <> stream x7.U  endstream endobj 382 0 obj 14 endobj 44 0 obj <> endobj 383 0 obj <> stream x7.U  endstream endobj 384 0 obj 14 endobj 43 0 obj <> endobj 385 0 obj <> stream x7.U  endstream endobj 386 0 obj 14 endobj 42 0 obj <> endobj 387 0 obj <> stream x7.U  endstream endobj 388 0 obj 14 endobj 41 0 obj <> endobj 389 0 obj <> stream x7.U  endstream endobj 390 0 obj 14 endobj 40 0 obj <> endobj 391 0 obj <> stream x7.U  endstream endobj 392 0 obj 14 endobj 39 0 obj <> endobj 393 0 obj <> stream x7.U  endstream endobj 394 0 obj 14 endobj 38 0 obj <> endobj 395 0 obj <> stream x7.U  endstream endobj 396 0 obj 14 endobj 37 0 obj <> endobj 397 0 obj <> stream x7.U  endstream endobj 398 0 obj 14 endobj 36 0 obj <> endobj 399 0 obj <> stream x7.U  endstream endobj 400 0 obj 14 endobj 35 0 obj <> endobj 401 0 obj <> stream x7.U  endstream endobj 402 0 obj 14 endobj 34 0 obj <> endobj 403 0 obj <> stream x7.U  endstream endobj 404 0 obj 14 endobj 33 0 obj <> endobj 405 0 obj <> stream x7.U  endstream endobj 406 0 obj 14 endobj 32 0 obj <> endobj 407 0 obj <> stream x7.U  endstream endobj 408 0 obj 14 endobj 31 0 obj <> endobj 409 0 obj <> stream x7.U  endstream endobj 410 0 obj 14 endobj 30 0 obj <> endobj 411 0 obj <> stream x7.U  endstream endobj 412 0 obj 14 endobj 29 0 obj <> endobj 413 0 obj <> stream x7.U  endstream endobj 414 0 obj 14 endobj 28 0 obj <> endobj 415 0 obj <> stream x7.U  endstream endobj 416 0 obj 14 endobj 27 0 obj <> endobj 417 0 obj <> stream x7.U  endstream endobj 418 0 obj 14 endobj 26 0 obj <> endobj 419 0 obj <> stream x7.U  endstream endobj 420 0 obj 14 endobj 25 0 obj <> endobj 421 0 obj <> stream x7.U  endstream endobj 422 0 obj 14 endobj 24 0 obj <> endobj 423 0 obj <> stream x7.U  endstream endobj 424 0 obj 14 endobj 23 0 obj <> endobj 425 0 obj <> stream x7.U  endstream endobj 426 0 obj 14 endobj 22 0 obj <> endobj 427 0 obj <> stream x7.U  endstream endobj 428 0 obj 14 endobj 21 0 obj <> endobj 429 0 obj <> stream x{{|Tյ^133ɜd9Ð! 9$DAHɐ Bf V%XZ%hC*^nŠ( WU_WԂU-Eo+䮽g&~_ٯkx">mm8^HypUa8!͝Uk޿4!B!}l޲ sgWGH9!!]q~_b{B5]&̉D§=>Y6|M)+V{k;ޞ5kFX=r0!CǣQ24lEc^V h0d;+#ӭxپ1cܼ 'N*+'_]kkzq3qy%L'd!>)= 9+Ũ) o<(9ANUzI^"8E?ߏ5WE [Gnd8$m;h͂ar'C 9.x/ϽD7sȫ(ܭ7L#A)ԒG~Đ߭)IW|DFα _N_Nr_ZMps9@/_꺿.VUg$GkQݤI ?͗%pvPju %2,kNp9ujW{_U00G`0ArPÁUöAFoAsGVRJpt`zĽGF[hyM !`-j|[8ѷk55LЙ ]:$`Un5!梒k4 Ewd2ȕ] tj뻲/L:¢V-Xk1%h"3X=b]*VmwS3CI%2$Hk[ +QR֕ZZ .h~[+'$TC9e ] $Z8lQC 11_Y<)8o)AS{`/I0a1͜!;:g3a1D^3f44(Pk;jRp}QӜ45m"9@(&r8#*>=a LsYeuz9 ԄLFôRyVkRp8ݠLF+71G _VMyMx0E$uamc. ^ՉK-FstJ$xI{y&xrZEEE1U jps'qUo^(ܜ 8Jz9K;iC Ji!6L FHXk a}tA.L2e4ሐ}}]{ Uf5f$z{] 1 lۋX Y 5k$DBhI o^|͏IU % JNPWk.6i$ 8%QiJh]@>}c,kTTJ"f#e7H<ǛM"/`WաC MI9!CBǙCo6g<,q܂N+¬GP_F4w%&ZEpR"d}"%UU'eX+M&7dh$`2 )UovaZ7I36AgU!JKN2$WS CoqyiKa+$@fjXa nəN;y!dh&U>#ZD>J3 Jdg,\^悊x;S)/u",'M(r!蚫{7={WW-L?п|&mQOzZ!˶i . ?{U5K%'>ؿIWv_lK{˴Z,wɂWx?ʮ|fWpp$ fAD;RR8ڑA&oQ7 +Jl (fGC3Bh>z꫓R8j!0T 5*T67>x0G&ׯM&D(ԏzǏ?S#5Y'f!xT!)IlLpg}({.)'k yyF7_Ya_2Hmh[Ιe]r9%!4!@P +pee2)$Ie1՝3)8>XK9Ѹξl36dsP [M=.Ĭ}EVwX CW.,;zwܟ)W]h~YN tu˙9!X?yRQ:t9[*܂[(ǂ:>>&]i^dWrŗA7A=n:P#g;ws_C[AAwn{~|<~sTSQ IL6AP<6 6, rCFUrLx3W*rw;ҧv_í?kN:4*0uVtOX<җIƣ,k6[58ލv?G)N#4g@ w2 9ţ#/`?5,1={X?z,aCχxOjuxiXbbρ_AE {qh,ʇp4·fI>p| p<C"ˇ|hec+VrSK3)&sIy&K_sŎ54L{_^-r-0g%. =:p-C{п-OJ5û\cA0:9$;A!dlJ'8?[B 9k<:'-5²g_?Jߋ8=_x]=DulБ0eimyQo{G_B}"Xh^ ڧW D0ܳ%QAS׃ ޳L`e#K0ffPPG3tafc,*s*rb%RzA#M'q2$*F0KNxJ_±o'0"*5>桛KT1NA!'ͨ ӷ~_3tm,\f8"ddA!(`7 kZI"0Un<`~zhӟѧI8y9պՒυ#ߡ 1!sc rd쌅.nN2d`AepgXoͱjl5F AXjԌ}Fi/˜NF$Q.+$BLVX5y]xp@?{c^Õ7^^*'?7/y_m_uem˗6g>+-2݊G.fK6!ZH23  DGKHteBi&4q&&jhW.WseС~7y8O?$n~|\1d!g-VZB+?ۤzT'i yUj tIo7i_%xKpoGp>q `ES0nEySFfb6 lT*V(Р <^+SBxC_*O*nU`S|(l!tװGUUAU`S`-]p]WgG8 .QnP 7Vi)\ҢpOᦢ@APv&_ :hU+PGOT+܀G qVO0eCX#W\t0ohQryF>*d()1xDO Lڽ@/1^P0KRm ? gd9F)+̤[7ݶqޕ ۳T6$!YfQ9[YUըt{qt-۲ na1[@1, %&fmHgKȂg"1ZAˆR& i5uj08]??O }6opW~?nE}ÿL}W2e5ZDƎ e &JyWm xKKiTFM!\dIwcAZYQ yBeń*]ug8^4_cTݼuuy\#Ӣs2_(v<3򊜜YWxuy˖?nRN%6BĎ^B6KFؕ۳T$ Yfɬ', Vx"yz؜ĩӇExV`ߋ'GYGdVgyDUJ6#2/\4t#fjFYAm6Pmd9_VO+;VZI?#u|hy n7|\cP>#h'puYw\  NfvaKcͰ 30]gЫi aT$} ?neid h f8O^DK1BF>Ȇ~+Kc,`r&:2*jYx2#aj3\p~D&/`lg#8maZi^b Oy8 دz1Re\ +m2<:=kSRt*)>0_%IwY x_1vo>G>wq/??#fhn&wo WV$czJ΀{+.3m'F Lf%S4lXF^lM]b00KSJ.2ꆀjFnb} __;ԗIta,a@s+ǛVbI"ЎG v}'~ T"xjQ^-Ф ?%0-[%`+q$B\ \w%`O.%N% rK>E%̵JP#-8UL ޑNHܫlvI ZĥK%!NPK%A`T!qD)\TA$H@$Ia PQJ6I4,͜ L0+G| ۞r^{IX@3٘`qG~=ވv/XMLm%DAܱ =I{7z fw T>}碭[!46-cLSN<9$;Dܱ ͮr6L igc=wʫw߾ɥ-v>qk%6 w5 /~]7^i߫0/>Ĵ9,Of&02dd2Xgd>;CxԉcF4/ss_NM}o d _ygx/_zݥ' C O]'x?,]"?X{Y Sld$60p;|'Ra 0r˽9% <'z$_,H_I0IVDptG ,( Q>n@5 s4[c,1X%omd -ܮ[Sqm۩/=1^c}{}%(MtdŃ2&Rht>DpPqa"5*[@.Mv6`*zyO:n (S_"tasՒa.G82f"6bhi@<00x8y`Fg @  oyEs-XN,@ c0>kしkn(` QG=z#I$ZSPW8kk3{2pd(f@)679':^뷜}keQM*7),3,|+'l YދwA'%_r]\a0|û$N} 4u<~;ܞ$OD8C^ |BPbrmg葕  €yA C@B84h.83Ž/vuԗz !/=vlPxNh f" F +Y,É{j1L͈g5'[,)eSv4B',+Lx¯a),+]}_OeƆ/] >&kyx0-p$#AIdM3pgY{|WŴnlkV}͓TAu5^]WonRMQ.DrVJbD(h}`z%y͙< 2T^1u?| =qʡya aǁ#iq'֧{}1 H}'q~93缫sC42@ocr#X߆F҈X׈ZcMFa^>?%+d+!ؿ0mkFWXDDZ`V1&XŻ ivRyN8X W"4G\r)Vµm-vr+V./No4L7`4g|Sw_Ѭvm~^m_m~3߹ڹOkk뵔6+Ǔ,')!s3ttq` RXHyMSud"]?K $[n$גTD2,U7;ԥE3ܑTF*ycn'L3HՁT#&AMyR!"#lI $WؕiTDŧRu3#~[D=UéDM6vRa~{Uwڎv=mU]q5@-+T΍DVPDzp;Sls!XIԇKzڊwHªMXudMű^H`JюI (@Sj7ޱ6{<_cUw,ы=b1艫vubCggw[l荇8BW펵wQn⑉HSc}zY8Ez1䅒]۽62Q֥nX\Q=G0Υ'Irwvĺ{V1XGowg v{klDۭ"J4ֆx^@qR TK'T^퍬gz;:zO={Mwit{m,Xw[)uF=Ez#rQ"c5;b =F юS\HxM$rJgkw3GԈno9"mRim ǑXqW<^RaÆp*mhb\)SR*kGPchdEԡpj `IœR,Px8ֽ8һn> 8bj'*alF"$J6^Յ*,H)J"T Qft#^;R+” {".A60Vh*iVjlA̋ކP=X*)Qu &6QRe.i E#S7B5g#TX/B:^T`VHk3bhbP j&θ0E9v"~hѦzWJǫ:fBRbnibҭgwl޴h8\_{:yur'?d_ߺ?_/ǹ]~Cʚqhˣ^~%Ux7͓| s {JToRG>0Ss>P1$ љT'Kpπ2L[q2Z 64pn\ZQ]:.k*+e28;9@%ApjEXU&p8ǀca¾>B@" K%DN}j & 7'˚([o%c%ʚcCXh+α{Rcu bqZZİ!]# ;$+B'1@V'`8b蓵h/%.a('/ endstream endobj 430 0 obj 10978 endobj 431 0 obj <> endobj 432 0 obj <> stream x]M0>nJ( ġ*C#$2yVx?v;Ò Sw9cmΛ cfCwv{|=iqya/W?"5NRN=/O}]ٝEM[mmhG?mn{Qioћof7% endstream endobj 433 0 obj <> endobj 434 0 obj <> stream xz}|Ss[i6o4-%}4@ER mhRiܤ(1&NP!|e/tn?tNn?~}rS :w{sssܶ =%._xBNYmkb"[N!ƒ0[+:q%BBTVvkiy?!Ou|'儌ʘځ*B$];bE 41 .TYqHn_WG/pӗCn2iRYG1 w$EG21rRk3:!+h2[crlyc?Eo$&>H2|N]y&B:F^$ɾH[]|*KU$&ۿA"{Ƚ6 \]GĕO`JGzQx|<%'0fƝgͼn$wp{!Hv +Kr&$@B%;cd=fo~y5&Ar;zRMM^b! 15WUgok__F F-9؀zq}%榅 ny~MjnTW͝3]9놙Ϙ>JK&/,ȗ9VAԦi*XH8[ <>Z֎j}bB$_\lnNw= zq&)/!Ux44#J\!hqp XnE/=m47V\DLG(>A Y@fB>j?^\]es8ER%Td\WQbPVl{?'+Z~ﻵ9pn/[{oOdŝERUu)K]0N%!%sۑΟS0Bs"qfn4;A[z$;9ܳBRo_FFoMQq}k*[,g7,m3ÇlO#4 -pfvMV Мdq:qU(&ғLoзͽq`_Fo{V`t&;F39,8KyEj?(B4=Fҫ/_m@!K.YNTݪ鰢 ]L渻 OXu_Y)ÂUԙR)7JsF+UllSiq8imSfKi^սUIdYRC5<7Eu)[%3bV6V]l9n/z+5rء&hpxi,lmj4OSIdq\A5bf[R `\]EF="DҜ x+b3HՈOU /NvO3h-Z+1iBr2w̐HRcLʍ۶ZYj).6O }nڸY=r[6a:ۗgE)2R@jo{MHrAm'P:vIɅ Bn KR)nq$Gdxڭqg0Z2bShhևPIӸmIp'5te%G3NO\h|aX;xT~9PmF8HM,TDȈI9tiI U`ރKb^yS^,*Q؉cQ,ӥ Y0}epM.v4|4_rs7u(+8FN0<DZƮ=%VR4*ur .pazV&^{O?wWeu m>4wx0yǦ_޳eu{\B{޳ewڛ0Ly,<+iJWshHNZ-7L|׬҈i s! s8sa/¹W\yer#@à we,Y6n޽pagxݑǘCL9vI|SCϱ0dY䞜G23uA'KYLBYZlN5̇p>a8?"Wrj4ZHFk叭?2| sLxU ;u,#XKV/gM_{컯{AϟlV"R ,կtt)jҊ3g3rb]D/sLjQ[nzV7-^.'DG_S 'g*QeXAO\@wXozf?/~<ǎ`|s M|{ (:& xQu TXg6yZO~]9`K7`[+]F/ǔ&LMb";laLt4v`قLvKb`akQ,d9k`Q]߂:d=LŽ_cq/-eV 붠ecGU rOV=…&r[Le)R_'Ǟش~=6=ه/2XTFcN8)WcNi ո:&˘{̠yi+!&UިuerIe;^U_~jgmj2 A؛w qhbZ#jrL[ dDgb; Np:ℳNx O:atB SjnC[|78a`se'\Gv9!2pNRq*'L$\xeJÙ]R-.\~?+IQN`̝Nh5rCJ@^-#ר,2B!^p,usbNiל#ǩdQ8zQX촽E5C?# ]bUW둷Jeڞ'n co3!k}Vi+jz+Yu -=[g?>}qݾ?ƌM|ݿ LYBooHhiq_VØ1,/fICt%b*c+36m1/L˧//QqQ'{Jgʵi YZv%MXH\,"/")"@Hg=1VԑUX % BWY,{|ϱײ +6>_y׹?m^+[w͛=on_ܰp>g܄w=|6c7Ֆ̜TM>9fO;t:QZ:Re,1VQcn$F46'*D08DĊ'N&&p{{NaTbbfɭh izNC%jרtɹd6Jg;A5  agEzOlkO{,cChnlN,ܸ߈2uVb7),0p&dKB'x!TB a G~ݘ唄q/G>i2y2!=ȿ1pm랭7M=Oxg7w,IK|>|->t w8*6qj L@@50@\{5У 8O;5PGI_k͑MyMw1^| r3.p/p= L6[XZeDwՐ6٬ZVeZcv3,4 S͐o83\2'fx G̰ pOrb.!>4fSfQT.*.hE)q~CDp"fVf>Uj%kTF] e\}xwi?> 63\ ect͔ZiFob[WkkWwWpHŅ?p-_fp-ˁ܁'+\ $v|&͖]5$~y*/OǙʰpX.mlru'?آ9cOO©ݘPb 6SJB\uBNsQAf:y^ Exoe0d),ێ7&2y`8-ی!4)$ !{w9f3fcw+w_??$>RRUki妵d6BzRJnE`?RBȞGRvfR`yU`d , _Ud=9j"֐Lp+pN'̉)a~ZR'SQ48:+0lB*0Kp#c ̓\[ , % ֐\~@Ә_8LST3ȭ/XKn,PL2EBUpe0\~_'"1qBDlrxc(3 E¡/ uis+_HV2?"d};}Ѷ@?k. D2\^RVV2 `T􉱈EV#h,Ad[l*i,}@wLuŅ#ۃml Db>d:PVGQM^-Z2([4k;X, uEq-lv$*v:ĵD+bx>Kwwh \(B#hG{@$خc@,luvCuq t`C^y$)‘^q-t:>oE3C  E1b]\: P7οˆj%  u D)ww ʎ;q. zXG(}C1}~? j[%-K)kPJW# (-]vmOJ:%~-.P\tuGw^[M]+oq|.rP$rrde 4c0D%:|REd%1דo} u$B:+ bB7"W8_s aQ!MJFi,5t~BPBʘV ud4⨛D鼕d5CوiCL7ʒgoEFe)An7K "EVQe|Bx^|%D PE#?*nBFUOgVպ)¯YWlmԋ)6*[=oC[G~:/(U}\4R5oxy98*Jl6] G-֢&Q{l9+0o\GTt'I-9E3J5D>vh!R>Bj!?\B$W]dZ#{G~8+HFK"ņQS+PdGs}$1 (QmSV+5 SL1 w@b VbZ#RD'7:Jv7Oq\Jw j+4ʒSiƾ61eȏ¹גYW, )´]hVtи CvF\iS2Dѹ`3==N{˅ ݅ -v\8|O?~>Ykgc<\_>-'Mӟ4}Bp,M6ޱЇMsxB ?`~OOd_8 *OT;:O!|dߑVwv>g@ uG+^8wƙx?>gKWf=ziʧOBL݁/>=pa톗vnO,v. vŗ=~y;zv0;w@L-g n͛&cJ{7iTs4emR&ފoL/]Rc_YM<+g:Y`gN[,ao` < 30#kPxYs&}?]Wkmq:]NН TcCNξNgIڸ~i 姻aI\'MK6|ǻev2'6^oe}^Fcj|A 13!G$B"pbIA4C|#Z(NE$\`9 G,D4(',g]N endstream endobj 435 0 obj 8176 endobj 436 0 obj <> endobj 437 0 obj <> stream x]Mn0Ft!؉R$Qi@`H YpzfVl7<1Ta _ְ~0y d,]+zccgu^`L?eYyqA:pGQu} F0<ScBJm˺Ղi-Y:mӂk,re%G.}8_*}i%23k8>#x?BNSdE dL{fs`>G#9"Ļ=!,zʈY!ƞc쯰d%k쯱dcd״z쯨A8ϨE{sΏ.';Nc|ѱ endstream endobj 438 0 obj <> endobj 439 0 obj <> endobj 440 0 obj <> /ExtGState<> /Shading<> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 441 0 obj <> endobj 442 0 obj < /Dest[1 0 R/XYZ 0 595 0]/Parent 441 0 R>> endobj 252 0 obj <> endobj 443 0 obj <> /Outlines 441 0 R >> endobj 444 0 obj < /Subject /Keywords /Creator /Producer /CreationDate(D:20170611105308+02'00')>> endobj xref 0 445 0000000000 65535 f 0000430275 00000 n 0000000019 00000 n 0000274470 00000 n 0000348007 00000 n 0000348256 00000 n 0000348296 00000 n 0000348522 00000 n 0000348562 00000 n 0000348809 00000 n 0000348849 00000 n 0000349077 00000 n 0000349118 00000 n 0000349373 00000 n 0000349414 00000 n 0000349641 00000 n 0000326918 00000 n 0000349682 00000 n 0000349938 00000 n 0000349979 00000 n 0000350210 00000 n 0000405501 00000 n 0000405150 00000 n 0000404799 00000 n 0000404448 00000 n 0000404097 00000 n 0000403746 00000 n 0000403395 00000 n 0000403044 00000 n 0000402693 00000 n 0000402342 00000 n 0000401990 00000 n 0000401639 00000 n 0000401287 00000 n 0000400935 00000 n 0000400586 00000 n 0000400237 00000 n 0000399889 00000 n 0000399540 00000 n 0000399190 00000 n 0000398840 00000 n 0000398490 00000 n 0000398140 00000 n 0000397790 00000 n 0000397440 00000 n 0000397090 00000 n 0000396740 00000 n 0000396390 00000 n 0000396040 00000 n 0000395690 00000 n 0000395340 00000 n 0000394990 00000 n 0000394642 00000 n 0000394294 00000 n 0000393944 00000 n 0000393594 00000 n 0000393244 00000 n 0000392894 00000 n 0000392544 00000 n 0000392194 00000 n 0000391844 00000 n 0000391494 00000 n 0000391145 00000 n 0000390797 00000 n 0000390449 00000 n 0000390101 00000 n 0000389753 00000 n 0000389405 00000 n 0000389057 00000 n 0000388709 00000 n 0000388361 00000 n 0000388013 00000 n 0000387665 00000 n 0000387317 00000 n 0000386969 00000 n 0000386621 00000 n 0000386273 00000 n 0000385925 00000 n 0000385577 00000 n 0000385228 00000 n 0000384879 00000 n 0000384530 00000 n 0000384181 00000 n 0000383830 00000 n 0000383479 00000 n 0000383130 00000 n 0000350251 00000 n 0000350513 00000 n 0000382780 00000 n 0000382430 00000 n 0000382080 00000 n 0000381730 00000 n 0000381380 00000 n 0000381030 00000 n 0000380682 00000 n 0000380334 00000 n 0000379985 00000 n 0000379635 00000 n 0000379284 00000 n 0000350554 00000 n 0000350829 00000 n 0000350871 00000 n 0000351127 00000 n 0000351169 00000 n 0000351404 00000 n 0000351446 00000 n 0000351702 00000 n 0000351744 00000 n 0000351975 00000 n 0000352017 00000 n 0000352262 00000 n 0000352304 00000 n 0000352530 00000 n 0000352572 00000 n 0000352820 00000 n 0000352862 00000 n 0000353081 00000 n 0000353123 00000 n 0000355817 00000 n 0000355859 00000 n 0000356085 00000 n 0000378935 00000 n 0000378586 00000 n 0000378237 00000 n 0000377888 00000 n 0000377539 00000 n 0000377190 00000 n 0000376841 00000 n 0000376492 00000 n 0000376143 00000 n 0000375794 00000 n 0000375444 00000 n 0000375094 00000 n 0000356127 00000 n 0000356397 00000 n 0000356439 00000 n 0000356692 00000 n 0000356734 00000 n 0000356962 00000 n 0000357004 00000 n 0000357255 00000 n 0000357297 00000 n 0000357524 00000 n 0000357566 00000 n 0000357818 00000 n 0000357860 00000 n 0000358092 00000 n 0000358134 00000 n 0000362525 00000 n 0000362567 00000 n 0000362796 00000 n 0000362838 00000 n 0000363091 00000 n 0000363133 00000 n 0000363363 00000 n 0000363405 00000 n 0000363659 00000 n 0000363701 00000 n 0000363935 00000 n 0000363977 00000 n 0000364230 00000 n 0000364272 00000 n 0000364502 00000 n 0000364544 00000 n 0000364800 00000 n 0000364842 00000 n 0000365074 00000 n 0000365116 00000 n 0000365384 00000 n 0000365426 00000 n 0000365682 00000 n 0000365724 00000 n 0000365958 00000 n 0000366000 00000 n 0000366256 00000 n 0000366298 00000 n 0000366531 00000 n 0000366573 00000 n 0000366829 00000 n 0000366871 00000 n 0000367103 00000 n 0000367145 00000 n 0000367400 00000 n 0000367442 00000 n 0000367672 00000 n 0000367714 00000 n 0000367968 00000 n 0000368010 00000 n 0000368241 00000 n 0000368283 00000 n 0000368536 00000 n 0000368578 00000 n 0000368810 00000 n 0000368852 00000 n 0000369107 00000 n 0000369149 00000 n 0000369384 00000 n 0000369426 00000 n 0000369681 00000 n 0000369723 00000 n 0000369957 00000 n 0000369999 00000 n 0000370254 00000 n 0000370296 00000 n 0000370522 00000 n 0000370564 00000 n 0000370819 00000 n 0000370861 00000 n 0000371096 00000 n 0000371138 00000 n 0000371393 00000 n 0000371435 00000 n 0000371663 00000 n 0000313740 00000 n 0000292288 00000 n 0000279110 00000 n 0000274493 00000 n 0000371705 00000 n 0000371940 00000 n 0000371984 00000 n 0000372203 00000 n 0000372247 00000 n 0000372527 00000 n 0000372577 00000 n 0000372855 00000 n 0000372905 00000 n 0000373185 00000 n 0000373235 00000 n 0000373515 00000 n 0000373565 00000 n 0000373850 00000 n 0000373900 00000 n 0000374178 00000 n 0000374228 00000 n 0000374513 00000 n 0000374563 00000 n 0000374844 00000 n 0000274799 00000 n 0000274821 00000 n 0000279087 00000 n 0000286437 00000 n 0000286460 00000 n 0000292265 00000 n 0000294833 00000 n 0000294856 00000 n 0000313716 00000 n 0000321067 00000 n 0000321090 00000 n 0000326895 00000 n 0000329462 00000 n 0000329485 00000 n 0000347983 00000 n 0000430591 00000 n 0000374894 00000 n 0000375073 00000 n 0000375244 00000 n 0000375423 00000 n 0000375594 00000 n 0000375773 00000 n 0000375943 00000 n 0000376122 00000 n 0000376292 00000 n 0000376471 00000 n 0000376641 00000 n 0000376820 00000 n 0000376990 00000 n 0000377169 00000 n 0000377339 00000 n 0000377518 00000 n 0000377688 00000 n 0000377867 00000 n 0000378037 00000 n 0000378216 00000 n 0000378386 00000 n 0000378565 00000 n 0000378735 00000 n 0000378914 00000 n 0000379084 00000 n 0000379263 00000 n 0000379435 00000 n 0000379614 00000 n 0000379785 00000 n 0000379964 00000 n 0000380134 00000 n 0000380313 00000 n 0000380482 00000 n 0000380661 00000 n 0000380830 00000 n 0000381009 00000 n 0000381180 00000 n 0000381359 00000 n 0000381530 00000 n 0000381709 00000 n 0000381880 00000 n 0000382059 00000 n 0000382230 00000 n 0000382409 00000 n 0000382580 00000 n 0000382759 00000 n 0000382930 00000 n 0000383109 00000 n 0000383279 00000 n 0000383458 00000 n 0000383630 00000 n 0000383809 00000 n 0000383981 00000 n 0000384160 00000 n 0000384330 00000 n 0000384509 00000 n 0000384679 00000 n 0000384858 00000 n 0000385028 00000 n 0000385207 00000 n 0000385377 00000 n 0000385556 00000 n 0000385725 00000 n 0000385904 00000 n 0000386073 00000 n 0000386252 00000 n 0000386421 00000 n 0000386600 00000 n 0000386769 00000 n 0000386948 00000 n 0000387117 00000 n 0000387296 00000 n 0000387465 00000 n 0000387644 00000 n 0000387813 00000 n 0000387992 00000 n 0000388161 00000 n 0000388340 00000 n 0000388509 00000 n 0000388688 00000 n 0000388857 00000 n 0000389036 00000 n 0000389205 00000 n 0000389384 00000 n 0000389553 00000 n 0000389732 00000 n 0000389901 00000 n 0000390080 00000 n 0000390249 00000 n 0000390428 00000 n 0000390597 00000 n 0000390776 00000 n 0000390945 00000 n 0000391124 00000 n 0000391294 00000 n 0000391473 00000 n 0000391644 00000 n 0000391823 00000 n 0000391994 00000 n 0000392173 00000 n 0000392344 00000 n 0000392523 00000 n 0000392694 00000 n 0000392873 00000 n 0000393044 00000 n 0000393223 00000 n 0000393394 00000 n 0000393573 00000 n 0000393744 00000 n 0000393923 00000 n 0000394094 00000 n 0000394273 00000 n 0000394442 00000 n 0000394621 00000 n 0000394790 00000 n 0000394969 00000 n 0000395140 00000 n 0000395319 00000 n 0000395490 00000 n 0000395669 00000 n 0000395840 00000 n 0000396019 00000 n 0000396190 00000 n 0000396369 00000 n 0000396540 00000 n 0000396719 00000 n 0000396890 00000 n 0000397069 00000 n 0000397240 00000 n 0000397419 00000 n 0000397590 00000 n 0000397769 00000 n 0000397940 00000 n 0000398119 00000 n 0000398290 00000 n 0000398469 00000 n 0000398640 00000 n 0000398819 00000 n 0000398990 00000 n 0000399169 00000 n 0000399340 00000 n 0000399519 00000 n 0000399689 00000 n 0000399868 00000 n 0000400037 00000 n 0000400216 00000 n 0000400386 00000 n 0000400565 00000 n 0000400735 00000 n 0000400914 00000 n 0000401087 00000 n 0000401266 00000 n 0000401439 00000 n 0000401618 00000 n 0000401790 00000 n 0000401969 00000 n 0000402142 00000 n 0000402321 00000 n 0000402493 00000 n 0000402672 00000 n 0000402844 00000 n 0000403023 00000 n 0000403195 00000 n 0000403374 00000 n 0000403546 00000 n 0000403725 00000 n 0000403897 00000 n 0000404076 00000 n 0000404248 00000 n 0000404427 00000 n 0000404599 00000 n 0000404778 00000 n 0000404950 00000 n 0000405129 00000 n 0000405301 00000 n 0000405480 00000 n 0000405650 00000 n 0000416717 00000 n 0000416741 00000 n 0000416946 00000 n 0000417468 00000 n 0000417843 00000 n 0000426108 00000 n 0000426131 00000 n 0000426329 00000 n 0000426757 00000 n 0000427042 00000 n 0000427088 00000 n 0000430421 00000 n 0000430480 00000 n 0000430693 00000 n 0000430863 00000 n trailer < <74C14DBBEA4E6F40C02C4C933F6F10F7> ] /DocChecksum /FF88959570B0395CB724AD997C95F8E4 >> startxref 431599 %%EOF O-Saft-19.01.19/docs/o-saft-docker.pdf000066400000000000000000023557511342117255600171560ustar00rootroot00000000000000%PDF-1.4 %äüöß 2 0 obj <> stream x_ʲ函קೀ^=L@,-5OeIBnG8ޓ1"F̹Xn݋}Hb_fLx}L}i[mˏ3~we+7?^_[t^ukӲ 5]5>Ce{y_?R^u/o^ui|7ۘ]ܔrd-yKwB9?hֿw4?Mej|i8uVs}{GVY;TurԨOۯ7=E']M+_jהt:nP)Gm+oBdKqA1H,"LbyKB\P:KҪn]uQ_,*Wžѽ7ٯ@]E[oLnԙb Uݍz}Q jSl[# t8¨d E-F(ﭦ'ټʱ}٩<9.^&aUݶ_)JE־ȹ02#L $j "Fy7nU[q\v[}鱡r759F颻e-~JK((2Q|oU;ǎsՍRCCÈ$4*~1o](w3"[1aD\rDy]LQ]=OE39b kF * 6ad.8' Vn "ƼcՃ=I5)4az\bǭoH -PnF'.[z#A|Tx@mdnHrk?TDl^ڎ<)n7FF3㴵VF1vjDXD.[yƒ1P.~~يSTeg֛0W(qCe uu9DD9*+n[LQ]r4QPo5Yw{;q]_7;ˈeHH&`j*f[PNZw̨bŽ=((Ź4] b`Zgy+*j.A6B7?-Aʺ *+7z-Te⠿G;5E_ݐJۅ! 8A\ GK$U[{)t/Ԭpg'ݑqڼuq1J}`حEW]=rYޗDl3qLtD&[!P=BDG֗ݐs_cAmjATVn&8ǖE8ɎSe⴪[ .&>o_-rm`r\ ɿo=C^$w_DqU;9g 楮<'hekN܍rqo)[>EwEQP(13)]t_l5=p,1\PH 5!?&z2c6R䴵 zuq1J{S*[1s[Kv%tFٹ8MR:n5J3!vݎJecF5A70RV٪ }Rbq\޻ω֍rUnQE] g&ŴDV ;U{]v^)Mo (C:ToGY:'>j.ݍd8W3Eo)ݍe Bf#Bo<c-9eol.@!BG zXdݎq򩦣 (GƠ g|yY%5U6}0UNj{㾻 CQ*6:w(cjE1PUw] qךn-A+D_t Mm*b}NCOQ-AU1v1߄V(ͰU&&{ݤa>JD+lzGێ|64LH䝾}F5 ^yT.z"([r?JUwnCT64"QlP:1@)bP$^BCU1Ϻv張[E꽅Ra[*{8>V^]2刢yxM;`Nԛ@m,t'.Qj 8؝D>XIUT @bb]LsB1CTN"Ϲz͏h({#tf5 9۠v&j-|i6ZM *GVٳa`4wќ=r~}'ʐ'Ž<~L P\n7Q_dK{I>g4X5^(6_7JX"ܨ'ںA5>Q[F-|h*=\Pl EuQ4i6.j[lFA9ȣegtQGul\ rW$c *w=B|2i gP&ϧDPUn{Q@hʿaC4w?H3刢;-QTw51GqQgFA[VtMl[5Tb1Id7ao7qGUԴ1J,Rq}{UlՁ!PAL ˒kd}I4konBhM7AePi:/CϏuțd3"[mͲ*E';H5Y:=ˠ# B5(GQ4^|i(E xPǑcl@)b3hN U="QYQA"X'bx^_/;{1]#ħX~y+%^:ϔUb_.A?.?`EW*z̬{C-lmз6ih}m|wo˥ouiI3ZsB_<:v@?6O_KMܚ_yLJʢת薾-a&X3߁EGmވvfC< F| ӓB:kG>CJuDf=֬6DKPX~E䄜^@c; v@vE-1㈏\8(E7NQGϲ5^-nT;* Q)}5|TWAc 91SA^Ɂ2视8qFvgzSj#WNi`;ߩQn袯6 Fz ڕIkYGou"*į.xoV4*Q{V@gnba )<_LP_anðH9P_aHz6_+$"{X. $;++9bayW@`AG~ȫy;,VOa6ɰ#wK*ƋWݽE{vrzB׽#kȯ@x 㛽rwvO\c 2kO-ݍRO ZwwģOFx9p+Pt|Y+u+ԭ`BxqlPeMw{J ux]2WC5Q RO M#Q]rO K}a°5&  lq.] dQ颪%PMpUPՕ,*O*9'Qq@O=<TCׂhh;+"@܌O0t,S}/Lyx& CT+SU'_`B']M0 @|#_JE_}r,*b>3BUW!@) :o3fe_DM"ȵQt#-BarO| e H`emK=q-@U;ku.Gp0x,zYP}.2JoRp$: y7.j.GL^QBGs"  7 ."`4Q2F< f7EjS@|FlpEOm/1PKH*keT^R}2Wcς BIb Py.p_ahأvx,iQ,#꽄EMc=T #߂naQy!Jc{kyZ&iEJRO< PdPQ@P`A'j2'z|6Z&zjVNݤ4KWa6UeTHGD:KszU*WlCxyPn J=!pJX h =+@y{BVzP[A5 xf/}W&lH{\Xud*x / =p.@@mW0{\`NylUà!SfaB5LDoFtׅJ4_{TcT-RThk*.syMw,@z?[=Rd'yˆY[lOW@`B'1v{:L| V ֵ0̲Z%(Gc8JE+FKEcvUj r;H6 7vE5WCxe-9Cƻ~PW-dKʏ0h=I(1qzUt4^yB)c|\rGG\;5GxB?%.#0XW﷏xp?oXG|[͂7A/ﺵmZ ڷXj-9eM?uΠPtZl:N=Y'EO;V}+ivj2;q*cc%^>_\O5;irZy0=m!oxV>-3 Kf*4a-nRyKg*d^-m a$l[d}m/RWDZ&Yq/o m/RȢ݌*⡢,ױ)b| //w.6GЂ9DwlCŻe?Wv?m ogVqnq[cm™wX% Q+02=T=J=Rfd$Q{&aףӎ|D2DOFǿr(itC:{![ v~Iʡsz5 } Z'nD3ɖGjhk8+ŲUmΧ!WNB,cupxچr#X>_đrOmySCZ ?(-1 C'mƧtq6Klc 0#q= u&"aZa MzpkRm wqHS޲ WJc>!ɡmf &.4D8nnGb<JrOm-F9%n{`/b=(p<#ȕ|t}G3&O(EOxfiؙ@#&;-X.̳|fiM"c 5XylPt>ێ7/xJ\3"|mAsk>cd*@.zpׂzouقycB'76}Yvc V$Hby{YƳa.7{rS]_fقC`4"⨣̳5 rTV=ӹNs5aRqԡ#R,2SX *w69Za]5%ez<3@o1p*t3ӌr\6(Uvˮ醉Š0y${nZl u.a*[yGuԅRlWL,ˌyG<ұI%T03C9|s|mi LLKQ*x H Y͆4&5q6\طPE+5 lPꁧM hPn22l/P ]B Â!V0[(զ65,Ac1ۓ `*o*]X/y-)fE((#F& `}e?9[@xtReuhWt ;(]ڪXh3HA9|ɣQp 5O C,3$�'1 8 Bp$%WϤyxZCkDdpeoQ-tabluq‡<"\5%$abEef9FEϫB@6Y8}Eؑ&Vt& )(]k<A8g`  PR\m&j}G\q~4lN*GJ#)((]8 MʤrD罷یcFK=qAqG2y0mD6(Gx"̴ֽwD#Hی{~rOma3̮/*ak9GO[뉾josnB-{F aO.N)F-kHGkzВh?qei{gp%NJ5J;P<%o!ZrQE֖Q䈚n" YP;md B{_(7\oxE9T{ݗZ_Ј6^`|Ӷ⽵"å#[ *Gyzچ("۠Zoih75 yzC"]G0 o=06 Y&ʑc,-3@AKSSƌHRŐ= (4GFụdmH`/A'. < Q`/lI1 hbz_yyY=GEw"zGCPBA{;f{_5,!sx  co"/ ތ2O\ Dgm5oqxT+37 j6#<=7SLR| 5=c 鉨yurXDo6Q'JA<%=q1?y_uTP%({c.zKMU]  1(-#Tݾʤr @)|R| /qQ>֋RO& DC-a)|-0 IDVCÁN#c 93~Yd 19w0@}VÞ-{`.DZ'pƠ3l\O|(-Ѐq<=84>SKeB[?0$?Akdl(AUf|ңa[yB^ U(`vmXZU{L@( (oɎ=OeD BG.پ p.Xy%P?f|ux|kTs_ JS G-% īA-(W늇kx$nQ": 2ld|A!b@J'B_w,|~BG9z"@_]+;iq/J=sDBk%bwN[ J=0֝,+e9<ZHRlS&}P'.XAhTۚޠtYթnU'7P'.A=mjCAkex/L[j0zG?Qm[UwabdrO< ЅݣM:Iߡ+i]%xu(u{3*2mP-7ŢtJ=0O P6G3+y2ӣ΁pQnܷ>I/[O°2OhZaJEt,=ګhvF CmK#x˾\q9[I垸TMv^id;\(Gc0 Gd{`H8*Qdm'vS824}BGn ipiyNdɘrfџiwj&Ĵ#SK# =zo#9z2XR5ѩ)|-HM3WzaPogm_у-=Qy4$1Á6]zGp{'O yLJ1@'>LQ;}-egА.>,=1(ıw6{Pꉏ M p_8!GO |c_X།{9zcZiA'N"M# G_HlrO :(l:%(%"1(`] 4p>@R^€Uq]Ƞ7taʘ` #3_(Ͱ`t0g)[Ny4|J QȾ$+(4?ϱ7R4{${^څ6(Šaf-DRԎOzN{HRO 8jGh?bgH9CPyW[-l,T(rhBԣ0Z0D0hM/F@oP3hӵV 臵o  F|s~B%WUQ(`!*^ GJHl‚ԝI{Yz45F/?ri[}X{r@Y;;]>7$lV3,=RpƆL*m٫/,=nj![BuZGn!-k7FC*O޶SuZH!Me0mKn{?(Σ#ۿ-ssV/޹yKL*);[ HGӐdwZ{Fž b^m g>~cGϡVX@ fyDwq1nJ͡`&̤r罳!vAaO,Rd0nyaD>즥e9EN8"=.-b%f9=2Gx۠یd sDN{m.*LM,YZ8N[(EYz$$oW,-l!kJ},=Y¼Z8NK9zUص 2È^ J=KFHbS%") =q.M,>q7JiSC>UPUKrmIdihF"" =d݌oо Cgzo#TK 8v2y`6\FotaBj"4"<ދ1[]%@'66;lyY} Hue 5߅$"lN(٦H >(Ή|I(ٶ&قC` Dx^avcnE`farwrO|m?ueAڠZe y cY^M ЌMhH(&P~!Os9&R3<Σj{)s,fsd0Aݯ9O! =nrw&vL䥨r.[xvA, h^.17ϱ3TIx͏&f"ħ<(TlZ)@*#֧<3|eag*Eq~;8kÏWQY*+0;OV bzdzQ'6ytv`kB(D0(f_0xgE(jO `N)Z0X% L*GfOyUEVقU ƞ罷Rfa q#ARc\̣p!-yE֓u.߻=`UG w?^YzR5?1 v+kNq(6QG/̳)kxvl0DD=AH(+M1rS<}P'Z%/xP p̲<|+=.LHe q12d0n3iQ6(C,>5(&Ouy&p@WzO@f4$`!r:]:k :T(*}L4 ~qn*nb,>ۏ|n2$=PB q,/(]d9!vOXr%R'6*}Ƿ˰?Q;_4h$R=/qD\mްy/ )wrO|mЅog#eR e)ҫYB,PivY"HKedBT'|S:FU52R-DdA'~6PJ|]t3Y0{h 6n*HQb-13O4^)O8y'^6 3,A@+'zd*45-P Q>)= 5 "^XJ&T0(u6S{wA8rm8=s٧_g6ĜQ0?1aA)b|S:r Fr#,%3)'{k3_z?3Kw[sl e)RIJ3?^8Ƴ|0VanmrQDzp(ml! }gWmytvυ[?+bavN,."*~#o΄B,w,88PD<30\(/}6c ro ȣ@3D<|W?c.{RhJSL| ǀyG{R@WwT~硷P?9E"՟@a9Piw{mF 8 ^)sv_aA qxM{0oJB7"ɜ͟o'yO/(#}B-[wA(Scg fDO^$;J=r(n8I,m` ۅz}ػ)Ig<}@Emco,Ĉ#ߋzp p]P)l˱Z;B+9!@F̿NA o7ޫNk }2R f0DfLAE~e'5r(}fدH*[e[SUƖ7VqIHvC='&+{R.#W?pP>5 ANcw# zS(zKc9^сRO| ށU='/j{S.:kwDٴ0ud&{SHܻst|v-+qu'st8,h֫sHwoޢ59PW&" 8[Lyړ垸 Mw/l^E(CQ NV~YV;a%HHs\U v;Bps RO P_xOap"z BŻJ{" *@"r_C0;!`_@OBQN6`6v VDŽ`1r ņZ6ADZ;-XPWv{ [²B9 Q~YJSwAwbIHGP{Ɇ.蜀^ f`avC| 1Gs~D##ֿzLݬAlKr:b篈ݟ-5AiS:rẌ́'DrPzX-9eE0N[cFCm2ӷ$G}qid#NDM[4kW ]WǣHJt|j塒Ņh1a{}6{&Fva̜m刀-3=Ä2|L&MUb1*oGT$"uڪ@$]e1Ϟdye9~}֪cGbY^]P~-\|e ='_m]b}ycm%9ޥwE:VREO/Ȭ+/ R~-tLͤBF*RH30;."%nYlHr,/@w s©" wGޞ7uz7vlj&x!"/Zq}^pbLPpfe Y(-1[( ã:tͰ)0-ymG![qz`GY!+EzT.[:Ԅ$"3?\Wk\ĹMDdBgn8Uln./ YPNe% F5`C'n849q]ۅzgU8Ȫlu`t"RO|pP+[لP<*wM$E٘E 2y^8l-T~HKHPNe^GMr9&'."3/~m.Y0GYDԴԳ|= Opn./wY Bn(gexD Yvyׂ8ym,^%WZ[-eZ*Nx)xGE6H"%gϱ]c)S3Swe*R9f"{℃.r5BJE(Sd f"{6Ev"#/l@? #ωH:yVQE֡]P]5u垹vRKE`|aṛ=hE,}B0w!zT9b(',ǧAS=\rO\pЅ n-PW4b%(0v8\u_]w垹#xODuHP.zWፏ⧬yzAGzTva,a":' PMeEa>@ Dz*J]P.>Y 2cxv&9oyl} 9VU.[=2; Sʑ Nuaę-QB)c($c 06O8-/5?ꁦق9 㴅kM\KAnp6A K}3YbINcQz/r3m. 59p뽋(:jpCiG]dws(#${,rUق|(-79iDg9sqLЖ<|PȦe axDROpDtsU0V6B!zS/8Ԏ#Ysw HBC-gY ۋOxH:ȾsH#n~ǩU=7Kn>0suU1m00(Eִq*MK"W& vs,^㤅SpW( ]m+qta]2rܷ7~.a=kȡ1Aĝn~v)+{⃃.DEX=5Sp G5:n=/_D$RO.-3T>eo||'w85UB8"P8Vr"9=MP3w &$\](]$;.*eC&K('\䣢RvBwkyg(usOdp+i{+wM 1ءF UEޡEJh =w}E^e]p3&=rD @ݏx0CZ*=*cl!& 8{/|wm='DC!V|#ұ>.;K^JI3pCUقͮ & j^&x(5|E 9rO\pЅ#z ^"z UeUMkXYP]\=^Z%( uEѷ^R3kB-$ZN:}srOo5"9#|уRઔ;+#ڇ= J# pV8!DgY{썼Cwj/k J=AU =B$^a[P"Dz"G5"9X+T ӱGSOm~|sޞZk薾;k ͋`o1[7 {S]݋3SK8d˷?|9:QmZ[5-6{i޳׆؉"ňj{:icxT= (F#+8YsAPqGo׋MMѯ {dܘ6Z"Fx'lIyh{THU zpHPg~7BPn1k\@X]*@}z8COTSYs7 N|*w$;HnPqo/9ܞ)^?f wH7h'ѾR@G.9-;R5ɩ Ǽ=q@hxDv : t W& uBtMl!⻓_D=+@@_k,~(į@jU'=u͢3jkQ>!:4ἠr< Etyh-J9{Pb?Q]V-JSJCG~*BptT[\TWA=/:wo[(ȫ`qLAu ~pCKaxҴ mZ(c wHALn@)b,ׯ.!XbxJ\0l'": 3idSQ̓M(`_N)k t"_B#ˑ eeM3)_›(Ea|='"5z|H=EֳDAQ5A .~(1@)ޫ`lÝ^{vrxn5 TG~&{U{Dv&Ctnӱe(ЧL=K/ (c/ fLy^Je!r-=)@==¼w)v zS*rmna;nؠj"CnqF0-zT0Q7uRo:Kp٠#ԡNt.s"jgB9:jWa6K, BavaRd$gQQYe ٕ/)7j"?&VOĚ-ίR^M"i8ӭSA,6HlV\j&z9T)seoa/-PSA5/c,ˆ}Kbn} ЄE=(.p? ^ !‡L=,JX%iq 6LU@"=p)@/34 GjJ=(o/῅6{ w)@4l>X:ݢS(¿Z>?8{U,:Sf &EzT>5>[8F/8#_N]'"zS`ZQ?YBR| DuND+zg~5 ^)Z|mRO| jGpP'>x&9y1F,Q[dQ&-PO#-|(qbR9r|#rT/?]5$^sATd1+A'Nլ M@zxHe,"we@M8DieA6 rO| E_uyGw W1A'>6B'"=q*W&r49=|I8 ,5l2J=p*t MdhmL:^ Pf!'сRԈz*CCu8Bstw^(< P;4K0%GGzU0U% x5H3\cB-5"XgauD'^|:'zg'_x~p tJ+,2߻ R#AE2242`OīVEFKr\ 6lcLA)SF qk <(歀bNVx0.: 墣>eE7}~LrO 1b hզ񡳟{Utu{tuFP34 .j&B'N"YjV!#'L=Mf@ "Eʐbg]63;ĄYas+()b0IuXЯ5R PB`~|#`"=*t;KmH-AR ^w54$bl"2Qw+ 2 ǫ9N?bn/?r-KD*91*9+(&owˡsFcdY{O#U˖@Y)/|-"h?M"ma?RpQ}70syxYhIPA-"rDeBpsl1PmJeN[)cNflݲ޺y0xOp5c/Rp!1V)~䴥_XR\X qh"uV›ٖ>WӖʇ;pA}/gAI^f˨/r8;m~QϸyvV2H,g qt i?~DvWY~jР?Q/Rl^=V+0+?']]+ 9VmxY7tze.ARt֣UuUV޵(RP?vKV!U%caŎwSk!Ku{]jvTr9NKZ6v9QU^H+ðW6ъ@c?9{Qq ,%TYߌ?FSk)ǹU rqc~im_Eay[6!ַwWbJP,;QK[7@v,~X߬?f:.kt>KZZ8WY>=NYyGQlkYTlm5ϳvLڡִ]LV_¬%-QIk\^k16kEWY#g?qso3ٙ {7r{}r#Cdg| Wʉmt V|߈iSVPOz IѻI"?M5[qU"8A ?a}LOņ"~?׏9X;V U3.iwEƅmku@E`SCdƚ\ut14CtgQZYN>>N2&#*RWCk;m|>FzeyAyej6~/xFjC}jtڣƭ tWZW:}٧^۪6upS^,--|v/~ֻ 8K\-.]ɽ\.m(ؠ+]Cg Ѹ{\ٝn+:ȸaT={HwVOIB$-ׇt+ۻ:/WYV:Ee^^O~!mA!ŽerW>}>[2޸V>MeƱH[\[\&gv-ť [\'{\;ƧvN _!{\{TzJ|~kە5Qn[~(~T!镤>-Tؠ"U|~C(AXN{R[A Ǜ/55~7:Lô6:)n筬?Ou[wE~G un뤴F3i̯xI,e.ڳ $n[mb+so,>-dkPIf FzdIgrL"*I:IKe hw-Cz5A_NSӹ}[ ]ߥǕjOu>][*,Ult'Xq_+ V7t \_o_~6#lGt \,o]Ma–:dK}"onMaž:dK'vPᏙ_;v)Ct!\_ .f%gz7_Gt2헛r"N+E,PW9^y+? z^ڣWvtFr{C9Ve^~$`Jl] ?'q/Q2s_`Oڐb Q4$.^h_&&C{ѸK2K"@xtЇȏ6WYPa6^m ^Z.cͪ~ڀ#ҌEشy/bڠ6:$~c6\@irlz㻲x/)$!'XgG焜TB u$/66+^J/.Xuȵx!UeH?&AFeu[{f mf_ü6<~f <~a݆ZzZ\WMvEX횶H-WOϛZk1#ڿ vk\> n1(;|'uUu[^_2,ܲ,ZnF3m[~LT޾zw]//[R5nN;j޾MK6ӣ%]ޅ>wȌ{?[u+߇6[^n]$zv|ҋv-\_њ/jEOǎ7<ɿkT 結Q~Z[~m_O^~X)BՉW' frLkgHN EgeO4j7ӑ*f6]ddL%0[>uʿN*L5孨%;}V}8N3[5W7H7-J?SMy_mDMgپɗHNAܥ{^, q{Kj{XxϗQ,^Ve! DֻKΨn_dQ:.hcctL lޜXM_QMNJ>ap;҂oDuG,J>_Vrt?e oBMn NYr|OkuU)bMQǨUb֯ڣh44Ma[t—E,Bikk'mx!35n"MNykXmu_WUװj[Yuk-^6{^6i?$YUo]jГ^ǯ  g6b]w=AmI? @`QE Sƍ/}jOcð/2q2|i&{׉acWCow(5&X@.E>"̨g`e>L |Xdl=2qD1ceFFq)b`Fn^̘r;-co6v5Lq&N0RZA5D{AޡQ?l&حv -h\OX~>R5.3debldK_ s"GgMKuOq ҷx2 C_'FPBC9r~:u{Ψ\ ',i.7nSצ%77>3[ }L-LLg\eL |,Xcӱ1 lv\fN(ƨ53caFK bӴn:cә\0iZaLwJEӒ 1Elc.z@N!gVF̈lr-˖]i1l:4F0u=LLi2V#ՃPpT6z8UHKhɍYכFn9So n^(2peKFe֌pNxF&*jr9/b-P#=Րhq/9ڙUpi /IX,[3/HF輴0hp3%| ;B,8/`GGڦ$p\_hk!Q@3jg  lu>瞁2څq:f NDX..3.LFoWƄQ'LiY|Ӓ"/luz\fMKc@uȠj=Ms-c fk'\n-6-L*V I .ne/I_M`\:nZa'^HP/T7-|_Mɭt}O7-5O5OV|,:@{2h9lm9h1D8ølyIkR*YOͷT\K˞z9/;v }jlLXP y*5/Ueh8袲ò.RQo-1ꕡky1ft49S{OsWM€v@21182w4^1Zb!cFqy33Tto'\nt-/Qv"zq=\_g> !Ekbh$¿%p&Na44:!rnlyqnyI,Πwu% @-N-(\2g^&Nm6;  R/ Qk0p}^ˡ~e ӷ4ꬄLp17eF3l-/ô-ʀ ;5qe"D(AhjmyiPtcg,XQ l-/dj21!#%R55%H]ezaY[|PT} T,{ca,1t-/+2C.g\n-Í&A7M5+:ЖЍފƄmDLЗ4’ +A\bly-1f&CPUھSS?S]my/1hH`4FOUjV3i;S]myi 2cfr821pѤvѳؼg0-.wK%듺~ @ԡxPN);rHXkPkї{[0nd 5I^p$͆_d6O3WʘИxsT\]g2-ŒܤTg`vȴ4TȖ^Y_Lu MQnj>f'v1he_uȶ301-$̌ R4FKo` ܉0n4+2$9y?nײ *X"LSt hnN0- {XqX .-$̌ RAF5КuNNbaUz _,.C:ȖL0}iŮ03q\[^>4cpT3@AK2d[^}kM%;rMlyk" p\:ĖF 4I?j}`-Z^>UtC $X6FoU LAL WB?7( :ԖBoLW- зa$g_F|˳!TL(LXI-?x3XY.lyi#fUTrq=\__yCLhy+b[FLܤCPUFLa k`DX>T 鷤Y_3, :1a;RK8Z^ʈ5I = 7:I>Dqy`Dv&skrCAA44wxƋqNAL3eF؉PX>5' :;-,^ϤHv^*W̬\3EжATmWN~׀ -#f#xϰA4TsklkbDX?"=5&g RpJDИ<\V?6ƀ2bf]3=1.^=".EbewX6KS]lyi 2î]d4Nd pJupmd˫WL '6?T.Sw tp-/M&4&lN0\ *D@ݘNCkda4fh!yt-/c1Fءs%.ΰA4Ta* Lu ebc?bm -1bB88Lu 1J &T&,F8A jh }fK_?3,ʐ%ϸ~ŔVy>r=@a44 g=`ЏZ%rJ[<ַtEiiP]†:-ȐPM2bK7,_l P7x7-/ I`.ClyyKX `Clyih2AC,u-/[bBŽj r6F&D= 5^~#[+zDл}6A~z`my)h~я [^^տf֯"ٞZ^k2aVED3.įc`Ę;ndlyi5MDe`lyit} Z^bY?ُN+JRM8ßw_tp-/o1q.A_u=rMCkyih2FqT2b;y&O6艱2c RslsiHZI&)rEYov!y>}CշֺuCh Bĥr|m'O; _1u<'mPP@uTP{:$ߢ܌Nd5aRLٚ"QE=4hߘA>J8n@]DtT)e:{[q{Ȣ*_6WjzrcsN+|~la6WnkvMN[dֆz}M!\4?;~[rڬErjn@;Ƴ_ {S[nnvR͖r1REFnn+T*L5-ؐt~/ڛr>NGi~֯~Kq@Jy9 ejP BOr煵^ԏ,E4U4r nLj6i'ӴSSȁ5?:rjPnECgˊ䖂0 < $*!?٧^<~sK?}d3C)Q&ǹϢοy)ɱZ'8-YY 2ц)@jBU}ra-13 3ؘ1́UpLHh`RgAaF%ƹIG0̂M>&e0̂f|OHi ?V&$|2[yECRDЧlo_'Zoyany0ݖ[ 8Yԛ v4x?w[jmd(fAKbflI\Z1́>Z:_?(< hQgg~J@CE>;ZkF;7[ q41o Y{-e٣Z ZԚܠТʨoUHSʍJ}-jΌ&ւ0VyܞϢCƖۓa3hb_.__q'|Z&-u0YZ [ј$.!+ܠ(-g>^Q} _Cg q.}4ŒI9YТcM>+ҹ=3]~-: K&3E37Mmu0-Aq6Aσ1 ќR'BX~au,?̄*}Y5L菳άY>O+')_G:3l!}~κCҺeݮH;7^-ꭌ:T`lI EL> iu%6~&ssrKAd?î3w}uf51 E (!="9Nf?Z31a -5‡gQk%O;IɶssrK0̀fB ="A`e- LyֶܤV9ТD`ܠV' sEa(]:a {Dhese)fBCHr KW@Cwҷni%Oi 0ino]ҧK8wx/m3ֈsK ]|̻C9TI sy[ҷP~n zz33ܠܓ sQ(AUrchPK'rQkp%_dügsX BÓť(+(՜щƙϨYG"_У sQp6#rr[0F~jI/@:~ }$a""qRoyv:aj̈́ kRYeH~F<VfxCbf@z3RyhϨJЏw+Ag?z330cIgT*|dNMʭa䖺(YԿt˺^89NsyYmtیgT]W:y2&nIjdle=* ܖL|oN?a jV sy$n+\sO}LI `:f6?J+@'k (` zfwW3jb8׼'&Kd q 9ШgX3c"{a4%k3H=tQ33^ct:1\A35!aeajnPS-8\Vo}޳332Q Z,''76gTsf,8Yn-gT@ZHmu(: ۹rKA8T4|d+8:g?z>:'V>~貮Vr;wQjgdf@C1a97[ h z%k{eBRӇ hQofXogW&>Ȁh̘ύRO2E͕L9[(&ւ0fBLX3"Z93ExhMnE- 3AE_d|p f?:>>ersr;A>CU_?QD{2ps?|ufBgB=7'4 sao\3=I\*g 3s19Т̰C|nRn-hNSMROrE L spz){Do0j]CscD3E@J΄-@:}S.gD+=}v^Y[q#Z31cfƒt}|5W`unRnyϢLN~WFI N2|VFL.9ŷKDk1~5ǧ5w[nϢJ99rK?|u}"7& ylWjT%V4 3EeY][&AhGn gQc&X"I1NfZ ܠVo8T9}c֎)qh ZT嗐ϭ ua3hr -suS[sE~ }{RDsr7C%9;=)9'0{B_=aֳC%¨"ۙK9Ɇy3sa޳fqщ>>3úg@qowE0YT`WfѶ0 u4gw5+έa u}yzy.cvg3ϬV}޳-*ҝ9z=s]~,*OvL?ƙPo%w4MDƭF@[],j̈́ ܠM67cQQ0R?31c>7*7 hQsfh2CaЏB,jmڇ?*9Nf@:+O9[bv0UfܚLf?ޅ CK|9sEU_Y "ܜL6~Z3acrnϢJov:h=7(52ijQQ:Z X'7$&^ ;2d?<]ת6F|s<Р|q-O}+2rQ ٌPMˣώ?54ǣz3i֥G&Ѯy_]gVwv9i%y -,-6E:E.20>xjVo|]6~@G Yy]NȔc)e0OH&& CX,[&O.Li5M[RTB8'?\ūG"9.5Odp&q@V:!ّg*SVۨ'*fLg3vx0bY[{yk&@ߒ&,~UN*>^*IYvOAla~9 PԺ-Wݮn)j<\~9d+4ө/nQF ]#ZMKҺ*o/;#<%bD I)5jh}st8L*whؽnC,+tI/ܟ% Џl"ngM3˅5v Tɘ{kJij[&E#Ө㹅01HY#5Ul]x"/w _}zȆ7L[霷踃a  _uDL:s0?,& z 8.e/\9$2s Ho+&j鉆)wIeHQo%檒zylgXnw2E>$s^4 UtI m_' ?ΥJg̒ 5yK)T2gwZYHYFcRPU6y-0]R&@$}'ϩtIBS DI\;ɥv ՃQ'Jfz0E]sī~!yPY)uQSvVLMN' Ub0aefɡG#= A\菓Cu&4oPFhev7ze*ƌuyB Luyg*T')>2:w:B:w9&U33ʐ1NXئHQ6ټ XK^3Cf{8UTK2yp@ rzZXZxlg!aƫXe-ZLFH!ÄY3,3Bfe:Fɳ8` SgAu3F23Kc!Jfse qqP1ȵ֙Ѽ.#k+TѮrב8t' M%`70z[RM"0F9o\T †TAnPU2E/.qv2]<"c,jL3.ԻUce6)©AR2[d$, BrM@'8f{:m `uujgŋ,iD-0.Ad5XxTŇyBQɓ里Dhr/$H=+r0ZTBar o pa>E;Wo("eBF9͘oFS[UjgqBS u|| lA0_!AƶPUq/<6A\w Oڤ2 `8[oW| M%Wu} jI߰1:O2fO(Bes1 rƌz,rQsel8R =rkAg M%j_߬ ԁLI2ph.ymecI Μ\J Sï)LOimG`IF-,RY`^YTS%X Vz3rү3,P7 l,Κ (T)G1 oI6!%)R52*3XfEUHchVM0nA ><7vhz Crz]1̳U04˓|gUIYV$wqPT}BB˱AYVL &яZ0E-5Nk=[ט%Ykqo4*mkT;s M%h!pBeB$~WC";33K>[#4/zc@*c*30%隲qySBUfݳzaD!2HD׼IwY#cgoFGT f#BO9IyqS= \ϊ7"JkP3a HXM9R-~"a ]4!0TSo˹0!4E_nŠ$z@p"$/),xGGAp;-h:h5]#3K`<ѫ=b0aN5}HJHܔ`ϸ\mde؀L<VoT>eblЃC&Fu]%t&LFAY'Oډ)۹ (#TMؽީ.q˭u‡T>yrPf\w6qNidhLiae7sJ(+i>olE Re>>ϤߨɳbJ\mZT1F8aZB8n4=RJ0N- /R֪HGϚ(?%i*A=R45>?}XI\* >ySB `pUu:ʎ]=1ڐQ3cTMTOrxw|#3L34O!UW5r-\5Y wz0pEgBҏap+$.s^n$4y$I\7TF/OUrK qTZOoP oiKB+ sԓLQ=e,̠iOY0<̨XSl6yJX=1.(z#3ȔjAZ3C͐ 3ff!c4T.bG5q0)hh2|Czxgm\:ÞoD>f"VY(.AüQcIڌ,mta^Q(j1 PGQ,$e*8NKԿtES0VQ$iI X QQR35В5f8 !k{dl:d U!qբV 4tʌB;B dgB<+N*% ܀0L 2&lgGQҹU~dĘK^nGrBSN>qNՇWuwBe0ιuVamy+Fndʄ$I35('p y6LyJ6T!3!:y.(KKqBS Vod[0SeɓҰfjw8mT+3f8'm*C]:CiI&Nf M&a8;M»;$r,&od>& ̓tK>3, Զ ~ºDBn>)h,G1ŅY>ː0+nT e8K|7T!Shc’QD|vQYϚQ&bZS)vƍqabd}<RMZ7TW]+.c]*VkBQ,t<ƌz15Wʌ}\= L}7T0c>S]QTA峜~ᜎĿrg2,ICiUr\ )C `Ӝ30,úED`w"(0gUgJ2|?~aeA V}0o,XDprh.Bꣵ7Z#0p2Ú'dITgjm̨Xƌab" Ac:!Or)te;!Fa.PUxi3.3Ueka6{q!pAQO_Eb{fINq2䨱.PrF-vH%z6Wb=l:֪~cK 7KXmPpa.ehfBgrn;*B4jj_z̡ 6y&c9TۅATXo7ѢT&c94&O.s\' =Եog}b\Ƀ|{fCIr*>y( Fj}%B?9?LJPOȃ!jȨ!SUIh!v/1tT`P&۔y(gPC5- !j!(_꾵NlSsQTmW*a>ϔfڮ[8u*Nv8:db"%Ü֡ `NnS&7!+/2H_8ۦc{Lf,;&$>ϵSVe3߫d[PΦBG%KfT㟼q;&9.,?@mcV85vXdsʎXG;thr컽SQ\jdzlU>{dĴ$99#oRSudgFNJ=2m奈L> g oQe ψw? ̆ꕰJ~sT?x!$զDŽv& 'տĈgǩ?Sm{J1' e[g/H枼^@z8$K:cLI\x&?%`4EsoNxFhy}/!xަьzƈLQ.[hN?G!nNų~7&U$UB#1WT:F?#?A&CDl#s!=/ ]"~'\P7TY|F|t?_N9o')I!Ƕgغw"/# b#1Qn7t|:D1MwFo}̥G(h2{DKI>?̂GCz1`"?GC` 3b vz(c|EMaw%s(HuJp4ܟ#b4q ǀm0kk0EA|4#>eo{H>\}0=vWgќj`J5R?wTͥv܆m 7.1x߮)?uFz#q{yy7 f(;ֿ LQǀGFs b#+b0؟ ψ$c/!#ɡ~?1To fW`n1"o HUQLjQG\\gvE &Mw"3j![@|;kr_F<)h ?_⃹\"Ivҫ{Q{0Q%?4*ІyNRE~QR!3L SXA :#ʄZ1w.cD#xڳۙHF?O3b4=%`6'Rg0R_BWp}5D5KE+sScD"t,/eFuQABGr FR/!fyɈѿClfyQ"7F^!qA,"agy/!+BriMV"H{h7WQce /yyIegyY\:b|y-K!{@xѲAomѲ_8u_:Z6Z(cD# #t,/6Z7߀G/f}7"+2F"7-KF1b#heeyyE| XOhY^ `$?:Z˭IF2ė6_X\G;/NʚN6qu,/мF6FC@1䏤wؖG_4-t$^V?[,ys{JY޲=e(Aj"G I51wc;l=~e?w?ʿ^_x-&]w/}R[!߽W/ owV]wsFZAQweBq__ѱkg[׎`EN#FYlwJC៲VB-Z^ת-%,{R"eǏcX?j#N,key><vXb)[medSudhPhں:`:-Zǣ[jK;?GYzZ[Hz6/?۱#zVrݥfrWkmYg?plr+9΢gv`ۤq=BGV*Uj՗:_%>T5BkվւZע-^E[^;]/Kr(iOeW_Ui]omz&3Ard9pԎsJڡ}pw;+ynB]] DtZ?vz%j ּܣJr`ZK|ȺRݕ~X6_#;zs}G|_I=gWV9*{b]֎+n{ѽiw\gQNGH*\W[6+ք-7k*ۿY'w2ˣCqޑ k~!rg=qޡe'knv/=ͅ{%x&M'ȹ v:þ (;I[P"ltֈ1]WƖC% ֗N[ 2sy &q4'ʚ(AgPNcJ#JI7hӍ}`vRcM nI#5z`PM(wLAK{J|O-[v|K)|{s_zTK3RtԻ[ (f·-E\wIWrsKrKr7RZGK:ϖ[ʙn*-TZ꣖vsS6B]JO}>P0ӵStS̵OAPί%֙L51zbpyt@ܑ;DRMeKS-]$SD鉒.73iJzQ)|-dzQ)w/*eގ^TJzQ)Eܽ\(6v(DI-Iݓ^T݋ (}2ά^TjzQ)Eܽ8OtlB}TӫJ{UAczMwUjzW]޽2twQjzGw(cO~RIM'A gw FO WYQk믦OtϼunEFQkzAA"5Qkk5ܪt HZJ]|ev],Ko(5yDA (7PjzC ޽8ž7PjzC ޽)7PjzC ޽+rPJMo(5RP}7R JM/(5Ի ^=1ּ~Pz 7PjzCwo( Rt[R7zbJvЃ _ld}O*[IeI'z؛~ُZvҲ [faXYllFFE}A/( Zʎ"]&1- E[_Q^ f+ON_RfaH6 ,Ⱥ/P[m#s|!#Ҿio%6u+i)vF'_3g^ٷw]Wc{bY~o/z|zbѯ$~!1vSl=hb=w?&_AErkfZPk5$:_\5֊ǹﵟ)&zپvUWfW޿i5jw Eўk޿iCbwi8r4r=J wُfʯ/|y59)?i.bТ_g-W{TLF^@~4,}G{,)כ՝^f!4+)gϧ 勝]| XٯWj_zCɿTieE_vWU}CYm<Җwٿ7q/ ǭ#֞ҁ}ßE_jq7SIpt-@=gR-qtN[? hJv/{s\[Fɔd'96%l]ӗK%G~_Zf[vwv0>9wٝhsn>q~W"9W ,}]/ irHI KnlPY(Tvzkvcn]J]^7; 娏mmz+Uk޽Up*vig7PmT[׀19J/xC*./#7f! dP/k|hy8;޿-!뛬k7H)g 9_Mz7Gov|1ovST=Qg5bC0F#뇽GRW&?,ItK_Xu}ڈ?nSu2z,>gnN!yiWckZ6l7/S,e=/V_g~3mM~bG=~ h7X_%ש^dZuI"M3$]~9ǖ܁ԭ5a60nT:0^s՟zD 6ꚗCU?{^x\o-c0t2/Ycģ2S6BF&z6K #D=yH֛֏z`QyRoW!}Zx\l-& jKUSUf[mqmT2w^RJ,:󀢱^yUW)U6{G0>Nإ4 t2'ʒ((^h@N^Rh{'F!&yi>bkT0,!/a&.\rx.N/yi2cK9mv漼Dn(eLϜyU)UJC?ebXݹ(A0 */U|FKQ'74vChDخ-x+/7_5E'!fp\ Aс4 t9 $J2>NLrKY(-Q;tFtar}Cyy(3S^T*6PU%W~ÀuqoRA} ]y&WVy¸"I6dXƸbgi/yA1TSB4 sJַ}LKte"t"X-l?xySUc,[[QQl//͖2?fhv ^^&b"[t5_\@^^g.J+ű( ѾEF@^^&9Q+Db$ Kc,b]E^fp^^2\b'c&I Y%tqUz;K@)-eKSl(//o)kH xС$[ǽK#;1'r]aCyy=1SvQ)bP^^a tLCcIJؐ^^b <6xٖ*0ȵ 奚M5P5**5'* Ἴ4O#T91+kdzy(3SLua,wCK-cMU?K+E)JK#@5%Ӣ!"Stp//](^^^RZz%2lh//Ueh(.g"%:%6dtf^^-Qn ƞ*Sl*/?PDY^^Ƕ_|2b0ȵq 1:b3/"Zʫ[J1mH=8 c@4APel ЂdkDm6̗&g} VM xAa }'u%guK2/vUC3TcRu`C{y(rA4JI KW"&:ƀ*3bR~&r]azya#pmP//$ p¼r!rmzy(-QDYeKڰ^^JBuDa#'(:)ʼA^`K B(eJf?@DC_!^ܸK#lVo%ARF= t//@s  |yi<$ یc ^ņ%ZtT 7lgʣ@߆R] 6u_~\56؄xH93@%1l5SU;v%rmo2QZ,&ʖ()6mZ&"[v}DiR/|k˸AY\ia*B'Q`29\(eʜ(K̮( )6iZJTմ_D307iZ2/?eĨ̠; %MK#@U1J"uV`P^~`lĘme`ϴ4T&6j̮DX_ Ne`kwߒΗWyyK!@3@gٮ4d<]k<56"/QL"[41*3\Ji4Ud}Lvq2?S*W„:HrPi4#.2'ʒ20&WLKDYPQS(%LIJFP%1*3⼭(0-UecM ʖ(]/-]ݯ:J8crb~ΰe)`۔jK#@ %#6hNЁ4C m}˫לU4+CxyWeƒȵcmxy(Qh"kG\X갴4Jm$JR,VZ&J5Jk˸NAj4 tB3Xŏ1>A|Eii%1-k &D[@#Ԥ{1T5/M$^>Oy3F'{G95--fطO? y3Sv1s(ĭt(5{9訏kd5 b45LJmЙ1~D)揶grr# :9.bY_3Rk5e+nYCC} 3XmQp1GXr2/S>֭ti_P]Hddx5(8vnF-圍纶R-qhpfwGv'FCWc+)yB4ɉHsؽ}&aa˚hk[KԛDrH8)g뿦uIY%9$50@+޿Ѻţ"t<3ZNup"۵<фSK+f!m=^xK_+WM\5riMRU/UD㗪KՌl n^58^6DRxUJMts656ȉokZjgӟ:e'vӺM7qk͇r3j3)מ0ydT+F^sŒ(?d] Jo1ʶ{ĨK~pD<:Ì{Tw,)(n8{Twf̉{Tse4Oȥ~mQj-Ì{T !2ڵEZo0[ (K瘫Dm8^Ԛ k"sކAֽ8Cb$]A@ 3Eře6q潨RJ\vq1̻ug%18q޽RDQvn8ì{ػ2#k1Yc!Bܻ\Z9섔 &*gCA;9I˵Uԣ 3-L*&/Ea=n6QqRJJl.nSwOJ/euuRҡƿ's˨\Py1'ʈHy  zm"0^JO-Q88 ={.s1Xsrq=͓FZD%'gߋ3%|n7{Qsf ;"Kq2։~9nqPEMF۵ߋ32M] v8.H~m"0_\9c么S|;3X;>^T>1F,Ah0^T;=1ʵAXgsBO :3VQ{0̼z3aaµEV菳E{_|kO{QsDέcw/ i4Xmi0u {Q_ 0ٹ~eJeg:Ms.?̿=1,]O|U RԄa>=qe…sb8jCGsL)eKRlbi,ArE(C ns;1̼5'Ɛ}eFU7̻q<ŐBE.e^a޽l\[a޽o|]3h)N2SzkSOaos" 6;c/ Ne]{. +OiIyhF 3(] 8_"s"~eagN' kq[9~ji^euWf9cZa93ĨCF/,oiqB6e/jϔ(ejE핢CRR0̽5gBuBλfR>i|g[ k\Pꊠ1fM0_T)oI.nS9L)-0_`hɜo[ Ƈ|Qs0fekfCͅ`@vm {o_rm q=Ƅzm YP\[D8AwM6q&Dj 8^^)=$kfޘzm&į9Q88$ zhy [(E{9HIܥfދQ~쳌b .u8j΄&j@gї݋x'YLCB#B{/ uKs"e{/Δ)Vq1μuWϫP= 9({QwDٮmv8^^)1ls6c}/ND׾c{{d_]D1μ喀ֺ0jyuk{dCE\?(z|6L{taNJ <{QofŝrmC=**GaRO#^.nq0̘cqνR;zvKAf݋ڏ)2nSƹT>!uZ-Vyww/*=pSü{Pe3"RʹAT*{Qsf,1[ 0ƅ.+~K+5"DLV|{7L(Al\MܧގAF ae>4Eqy0V_[-0מ)oK2*q=3 :>ixA= xH O!%|m-cmk./VR&T%=@rm̈́JSQkA϶GV&)~|Oϔčnfܣ3eN)0]2CinS$O o3y~Ү}-(]`"Q9j1ܣڲt%J}sFRѣ'JI[It9LS$J6;cq1Yvk1FP#7=Q=93JblH9ηGVBsy&ncojN6q{1̷GuW~Ì":Rی{^q \EuQ=2XrF s[D)vQ9Qʜm\7]fg ޝ6Qʈ7ʹ/̡)Fm:as]aN"/ kb~T)è>D8|{T`,3J6q{2̸w跽-Qk){T{ 2x2ʼ7pzи+ ){T{,PeꠌrQ홲0%1jbu ЩXB?nPq&qs0ʽGfF!Ɩsb,eޣ+CgCy!ud+Z#QR[0ʹGV~|C2EBq{k8eukΌ-1nZEas_SYkQ^T]ߨTi |QQ&>mO:Sn9,fަZ' aJ9kTbdCaMzmEA?zd4Z1̸3S^^ȏSumѝ0^Z Y=zS[(~^>^T\uo2JFqs0̷'F"Ԥ=18g8^\.-17x2̻3cKsb9ψzhFz+ (qc0̸VFs̏u8^Ԝ 3mJu0^[ ev'Hj1η5gJI*no0ئ.st."j:|F ϙzdߓ3?~b "n/^eob{+{/%`6f{ڼÎʲ⣜'K]`۲5{KrpbpvcoMڊi}᩾Ѥ<]{D$->,)I_J?q$*8I"UZEHLbNE{OrMR;ѵJ-دaѫZ_ rWr 먓HaY4Tkl$o:gEc.Js֖?ۯiDeILrKAu3g$vQܓ,VۿtoH XM(R8Hq{dS=SaO _Y'@)qA;g1ћ'GVϒ=xQ_KIFջw./ jgO⤼5X&[.R]^70>Hh4}odEJ;ɪ5Z]i]oo ݤ>)i=^/:^nx{ZY{#@FWtJr2?NFw վEg rwX{5M{aw |_o ƽ)(tm_3}$ݖp{3߫zI^s^\2 ׫Cd7)UtM^Y2vǨ!ͨ2]41뺇` %4Вb΂foNhGwY<4/t%3.p1b/.1֐V*չ%$`0i^f3Ů:X^lA?2AOι-y+RX,:`@bP!XeZl &D(`'m$B,J=XI# iXAh{$uL].RNOTQ#3Jlg1c쎁Wl'D .T"Ģ^O!26yZPM0VFoM(m1I@*zK1J (G7Gn(Q^r2I틙IҩyE g`$KFh2h@; W"Š ,2M6Afu2h*wR㺘;%7[AO:BYs9J@aղ#b}SI I|Dka\lu$~h𞐱աN(LRbCEJs(` sd:cR P 8O4]leY4Gx;(%9fn'T[yW[-w.eAO)M(؃9M.QbvV,#qSE Bp{kX)!-WV̀8s5]} gg_t.`(Ƭꚾd?v$`/ȱ )/IBe$.)`֑Ycwh ;~8Fu tFRhB(c np;5cxg^iQGVuH#p]jLM$-`W.:9rfG}HĊƏSb ΍STA3b%vZӰD^N&>OݝPsBp#[~(g?xT,`L=7 E\ .;C϶}7BR΃Ij_^wޠm`DwΠI 2HwΠ0LɽNXT)NfE{* eEQL/Ua$ǰ$gYs92KÁǀ8;δjbpR9tEbR }&2F ]JI7O*cz>Rة$ch#h^@fKZN fE1JhwjHn(çJirH+s$׈is)*P 8vO士pŒ8"?UUq,iCcQƍ猑72S%Mu#^4ЎU4~$-Y5 %VbLp{,45ZfqX%b?WM71ė(-_7vs5UbКJk/]0GjDUl>T 3I1|8[Z| b Ú.R(%5]ls]ob$% I>B-o {Κ*1E-Sl5s(!t#`>ya΂FSI숼>1ֲ;۳~7!6E_~ asԏjUSfI$!ߍDBM P e z텮 HHsJ{'<2@kpTQ-f>D 5'υUYbC!.UdSc]< h4α;=~4Ib^EN΂X#dPE BH &hd\Fq [ Hj !<Ś|T˒#ɎBwN^'gZGTI#e12"eP%+-SCkHs۩3m#cC+'p{-EY`s B, r* Nh )R ܝm1&#Bwg% >nRF&cYn" /44dE\RE)QȜSBh(;P#]G"Y6%+%# Gצs2&W7Ӧz2(p3"QB7?9{Mf]'U/(G8Dq9nAavզJ Z 9nUja %;J]W1<Ħզ(edb2(({H  _)#J&F4foWģOD?]Qz^/齿BS*2!$@,ztg V(.h >&w 3{%gA=L|ԣ7ӲI209x]zj_g+%T;P?@bA ((QzYЍ)idBDyaAY RܰJ uk(+Ɣ<2H]@1eu@eeԁ&S^JNuJS #LD(L9xģ짪~臹OgڟWQo#JA5fԑGe&,(SJ)QQ}JqJy (iJ)PB% ] eQP}"@ |~BɯQ,%gݘF&i(5@YJ R;:R̚/Qg(f@)_1TՈzI1_#i({DN[0ojFG_Q?J3+0$N,Fk43ϳC~! Q~H$ )nCpqJҏ9S1q|Z0b@hIA 8-m&J|3D3׈g9^J0_DA(ۄn('LR3JP _ĕ%*|> 54"03vC#|D_lP_2M8El_D9F2#ꧪ#Z ǩ~EI֯Q>YB =R?0wRyP~2O{(Rwr\/Q\u;J)Q:Ѝ) 3.%e؛)ljPds%W)zQqPk(cS$%(ە0$oj9A#Qiz7W=ꇹ؜~O aQ.o#)@5QH-k(~ihO0+(@o GH}!JVH,p}$de1֑}cEz%hKB"a] _o|QR IPg qJ0 >503\^3cJ tgvCFJ+SJ&ݘn(rnk@O)FD9@UJ(aDy>l/Qx0ϗ7cJ>/@,A<_N)SJ)/o(k0xϗX]eJh3@P|"N[$NCx|I!<_+4K/_Їa|9S/hΗ`R_8DyΗ_b!|cNЖ;_N R3jH8BBEd% =N?  7/Bxl_O<,bcD{!|ɔ %MmdЃ/`3<G)|9%l_%@/oe 9#+b^z~<˗7/cqؿ!<_N)/e"eG )u4ԁCx|}F_X|bu쾜RY %S)e/帡 =xϗOPꄒc eJByR0k %0/v>=_~ˍ~O j"Ny~i0ϗE}%맫wt%/pz<>='cGʃux"rPs9ju=_B6|5Ä5xTs9g^$>ÈWjFav> PHI >*v{ֆ̽oovΑg?Y,G/鯏h?_[mec?ۿǿ}nwg]T珍x*D_Dz>ƺ~+{Ǒ <>N b+݋qۚk9z2?F?R`^}"!띶tOY3hR}u9xm;ߣ/3iv6W:<7I2MHA^*}>ZznV:D>Z{gT k1lF pjoЏ˩e 5u97U5s;Mk.GN!y-3ʉYwk:{vR.f͕ Wj#LIC;X6mWfKaGK7w/+弽Ν/|s<_v]o.,uЕ?zrjOBAq;6uztCvvVz5?n߶9l;637v$մW`xU6RzO{M~N㋬w>tIvBL/l:l 2zti?M#y#ύYVpQ(슖]Fe-\nO)/u;rvy sg;6zL\rso#?o7//dN<cԅ'$Z CH;f;V+I~Gyk|"CCbN*N; >ۑDjs; $0d}  eιSBH0Sس՚vLcO魗d)A2t}$F7$ϴu*C@*>ȓArG2@7@SUp }CV)x!opYBh7B{ȢL@aaT= X"!ZeaO\ Y f;WU$C MnҼݵccs4x>!E < g+*p{>:ɣN4,*{G a>:$|tH!M ^`NG AUF2>33YÎ y35{@mǫh{/3>0[E͢fye55ξo]xd? ozy'yXhy?hPfmѡxOW8'HHI 9M| o}Ӈɀ~o>2mkڑa}ڑ >hPh=Gmw:ퟕFըll&6xcz14wp@ /ovN?dLSOB~/Ҹy<.WON nC!h}sNgԢ˅*q`i^῞ұ}pps9 iv٤JpX9Ov%@+]r@=_H qȅsѝ*'{,%肧zƟUċD2^xFo>]eɐ{- w?l~[39u1P-/6?Y*7˾@?w~ IYQEߎ~wO_=Ewh -^虠 <K=vM"ޛ̈́XG~kh;ŕ>$*ꕝs-gd9o&N~בY+N1}C}eOP[xs1bo<{/߽7x4o4jZ9QS;tMI4zpo MkiD=I-d Eh  =Q/$lͿQ\y@榤$z/LF;^ޯ$3Z~&N/}$mғ"v^`e|Ty.~AUK&'7/*?zt $fw<|knXzΐcr|~w2M'~U:7IOioe{xciS'-fU|_kq~܀CU?* s}kt5lj}@vh 1G_ 9ʚ/m]VANBK87ϝ:/"PyL%(,;y(͗,ϊ _PT|",̑0A_E<ē Mf~{r.anLˎ}i#B<[vV/ ;%V|!ʃa$}"_i ԖIڴؗ,ϊ |Xh/@=G^:r(΋}I/VBaZ3Kl& iU s> cv&n$ARؗ HuH MS_{k}F!>ؗ,ϊ |ҏBXQX̴˹÷xJV E;oSód_"2; ;*h/m2u,mCu0^_2`{ _QXz.U>XIYP!K#`ngwiE{^ $@yj/Aܤw' 4ԗ,z҄ Tf|R(<ӗ&iѤ+*Ms$}ɓXOg^ﳍ'q@P[.N09Zσ> iD@E@a>lVS<З `Mso-4,@_~""لd]Yi4y% Ef 5k6C4K6Bix<˗ ѹ Py%țx;! Kq%7mP@y,˗& +4Ku>/[/8c`6L3IE3jvLY S+"qadϕ$g8c¬ &Dì#Y @h4˗ `Md:0h/qnB:! P 'x/6(Ddz| &nj4ʒ3@~!ūoQx8/MIKzGSF4KgETA(@?料_CeYOiN5Að/Q̠!ۅdgƣXdyVs5,_y•5-_\{RcSLxE % ̓Ұ,_Zĝ%|XX6+y[mT,_x62$g8dW)YQz,h$˗ `MNlo,Qѵ7(1'w dt%64"Js ] (<6$t%˳"|@T\ra%}+Y%WZIX=vX|Em`a`ueIk!ǃ4 nץn\~xas%"ɧsע0 `6^lX4h>MEE̒٥Ts`gʒ3@sY mq޷P^%Ò%4i~9dX"`g@չ @w^dyV$h&ke0 HJ/W9+YIa @(h#_-_vyVgM[#$@id˗*m댥MG|I(I'ZNj%8fɯ1f;2j"3_(T~Y{*(P{X (@cY|H/YIZI? ca ,_"" !`Gv VgARP}Gh/C@F6Цz%X%4q0 /F(o,BiT˗3"_q-_<+&m8;Z) #q%'"vx˗H  -~ F83dkOu Q<;Y0 /gU_IKҐکF!#YdcO(_/UT[ȚH'[/2) 1jh/<+Lv/jӍlNZAз;`5Dz\|d*f KwN gKfƤ&M}GIm~)8uؒ\]#dZ~E?hĘ,ӻ-EABχ} 닠K|W#L(V R6K3>JZ/5 FĎ6=t@˳i}V\|!=DHFgThN:ќ{tU ޓiDVpbA$^Moryeܨ/+6 (MƳ)qSwOFi6K>/I7 u⋫&I.Ew7K.,r5RkoRI^NgϥF7X nz/˧Puݩ~hÈ9vy\a.GiܳK{\\w5%|>y侜?b俩<> bc[*٣Ku|WHOӉ]U^svǬvljl}}}Wgr2b}llyג[n9d%+ [⺚9˒Q~eE[*c Y P%WGNKʛ7̡E" ZIuKŢ*VE},\L< |d.儊`E>Y_/U3@~ђv+jjSm(a v[bMiwt%ɺ*cg|趤-b(ކ`|-{He*vB%wCe*-uE whzeoұϒo3qʇ>K|$[z<)xi rüJK.K{4]'QcI&@BoK*+=4hhj|豤!|J"x,i]w] kK,&ؿ K&;s% 硡 qYҐ 3eg*XI4d&5;.Ҭ dmTĎ7mIl;yʇ^K.ȃiV^KXҶPm+ee`U1 ^K& P VTm[DZycoIԥ9pv5&TqI#? l00ˇ~K<`P9% 7.[ ג "}LLhĞ*(Yvi;^o<4@o?IjnP)K0(_*x쯤n sq`%:,iBc.K4K޳SɊU+*kI@PʇnK)YNLV k%E>[ҀU>~VP^K|$\-xOLe(5P6KgN( ډt춴Y2szW1%VCm%qM5C5z";-i\#"XENK)ef@*c tZҠ#ac%֔llP;C% [oj vZҐ P ;q VQC%>8IvK)7lBܴ풩kI@A:T+ʀYy/ Ȫ3~K4 . RdovǞK)/oGEz*UToIeqs;Q%M a;l# } ?26CYT9YHI>&*KZj{-iX`5z-i{ K䵚"{-i UZoj*`z;e/5v趤m QےLɥf*x4&U4_L,DI۷ zo\fzKE&izo\`E|b vYҐ'diXB%>xCXd0&-iK*:`U=t] V@ymc%V׼Ԇ&.i-R wsrY{VKu7K7/CU*.u׼NCU =v[ޙx1qYvLo?ڑM=Vb%m &̨dvB% ;uA%;-]fT{(,i$_@|4`"OįTmDP9C%e4(gsIG3-ʇK0oD}VcA:c7uIv x軤xɌ"XEK0wU켤A2Pd6T+yI6oCe".i$y(r4@Ff7wCyڭ Jx蹴ӛÖ4CE 4`w.TiVQCCsFҦ4BVH^K&dEbLuCC9Rb']ʩf(5Si-(/lQUP%m G6T[OC%XrfK#mχ9ݖE#V@5V[e E@~CtZp;dq_Y/VA|$\_Q  cb%mM\g~6PکvdѪ-~5T@$!|k}vPNK07CU ,d˂ oZtZ@A:T+Ǣג,+.C?!+`g|d!ʗ*r.K%YV_-=>Veɚ+&؄,&$~hsj9,hZ*TiI9-kW 6WiV5GqB% K XfՠSgIBiuUNC% ēDV|(hTj`9,Y`%,D]%u8:v"% Ce"-Y /mR, 8-G mI&C螃+UkIV\,3V+kC>!QE0cU*,i*P< |v/X4U2V* ס"VA}4\O6|TP ]4ZNm MXCU]`ɚ(k!gG6TgI[d. 6gC{{-[eNK2SS U*tzbPnC5 5@|Bx^K(f/uϦ-[U =@>tVlA}4`oJLT@4hc%VvWm V;C% X; (ws wgUX;C% \% {{6Lz%YSa5YqICVVXI`Yndemq`,E#k)^KqivC; :-i$/7}PA4`G [iGy4wZhI;,C3a U=ZxA~G2j(ߒLWߪT@躤!`C@*@켤AqCe*?]xAP *K+oj[U@!|C2T*);-{ػ]CU^K")KzYex-i4H]9X]U=t[&9^PlB4`O&.?˯(UTA<3U$A:[`M: =Z.>$^ۢymº'׈ ~;sRwhx|ZB\L_i<9iNOrſ%Li PLsx{'xk{~/S`#$LFȲ+w,9 Ps?d7m>tyv}:uJLbwOg7vٸJ=5GEq-6ظIzTrϔ؛f%HN>7$pޕ;dE+֮oW.'c/JrL7n7wvu0򁡏KJݥCFIz򣬄Wɖefϔr̠"HUXV鍽*#"YUz}3VI6Vy3gFQ㋳IWiTȤGJvL/}כ=qT6܈W~!6DE4$z?W?'nV$"6-MYb2& v:C*&]H}妡6rC;"SIxátMVY#+^d_"]WΓhyZ/ӕi6?[X ]轊8`ۢ7,O"_8^LK :ɐ/]ه\mUz!I/ٛ6kww|~ت;k!@?s Dڳ| ( gQM4195-۩a  ZMĭrmj&;<NlŠ"ʋdǛxlx2q-[$7+TOC;WI w5yE1HpA tșHaXtdKNërh ,/P,9(DRb{sXQVW"LŒ fXSż}PbFlᣣaĘ&T֛h6t1'V)ϩ9ElỦ?Xfጆq( a0 -kTBOf )(F MoTMz"Edž7ÌV˷ qg -V˶kPBt݄bÜ+:!e؋,f9n$^UkFB7biyQQbh7%I4h,wT3)՝+NhÚ(hY_9\&*.u*?ܽ)Ӫ01QE_g5{T7(7TiftX`Dae1xl$v'bVÜm6ͻyLFE -T i1ZAB|f5.P6(j!Y-4$b9Qαc " @3!REh/U-C1V@lBX#k|il "J W3,20`7+67HI~C*[X'*uTn-T laTY]Ya(T>4F7o;jfiE"Ck%Vj WSXIO"R8׿sUw}4lI5L|X|MqS&*K Lio }Wӫnh.2?4IIe9| 5 NP) vRMTsk 4CЉ"UQ$ sq&QCy~h*EoXS <KM4;QV$Tlf^jp^w>"HBTTxh5u?7\n٭L0IiUBl6f3hZ]i(fc[fjGZ b-$XqFfp"nPE]L ͳT`vdF!}*| eNƠm4uSw\(7>@h!+{&Plz$}Zw,tߖ[ڸKvw)i;8=qؼ V,y4Hf8 ( @B@w&` ײuw0ơkY@Eơ T%[Apиp h\*4'DJ -k|Qk!y=.xH\wSi7YO#dSӰX%!Ɔ{rO&@F@HÊ 6SM]Fd00mL'JyNOIz  T=SMd ,Bc>U$M})q[FXfދ݈ej4p"L>ԀI~ @ xh᪴jI$Izڴ7vY uTPi"?*{.X1G P|d(wg4y0@UN wĨ@Qbh@hH/q]I<ցq( 2!,nMkHOeOM!C#CS$j.5 o囥@ 034ARgZ~4[مx@LM䛙\Q&FQ4!4;ڠe, V օM.gqT>W4E(FelhJRV` +( (gX9 1KXT:f4=WKJJFD>4fʯ3rOдidԨf-X rjhrK CPQI/L<H\A{VރkھJC*T("#l*@hiqǬ*.6sH$f=E鳛h5 DFYNb$^HvG⇹,9Cc(d3eA9"'3=Q[da MQULt/CڀQE*^ 26VոH[yŪË&*ڪjnbT@hb{޳U(XC+=jH*qccVU$ %YBcV$@3k߳CWaYUTL8N${w8 ibWV|N>_Hv<.S_j6c$ )_|Q$a ڼyVT`QlՌǺ $J|/ŌjcVH<0&.>27H*YE"J f`cAQ.gX 0_UY2Y> @@Q3\U4귩GWM:\U@eO.@=E@Q+ e? f?A~0\tg.-F9Kt.tmTJ8(N<߉G9FM1<>$g{@ Qv) s{Z@ {g40/Us y|U>)O+ȋty5]eקu7n0 -_4g}Y<~i ϝm 1|I{(k&¬W"?#4Oer~3N~xor*.kQgqgsEf8BS"v8"<ϣ NP Q)` hjLWU@42([ %,ފ'ţS60âk kڏ ;)N䷫8W@Qv- pxki~oSfH3&0?-܂ N PQA$@9`0OiW@-P@Q0mQ+@^r\ēW QfT:t2yi0zE<ʤԦ*<;LsH@ ʅ< x3]_ىįa&;ћKo4&g uAw tsI7aιA:,Ci6{Y<gfpG➔F3(wy޾E<a^oDծ _3D:fzGў(3ڋ#Y; 56@ d닀03hN-l Ofs@Xxȇ^4U~Ed3=oMU<*fz8?W&v#{M} \`ߦa./|P@4#@ -<\W@e2͗ jMQ^-Ӝ=w3b=^գXs(#9٬Ls! (.`>+Q Ab8^K eǥLTg(ԍxzZ<e/P?s@hS@|IgAz)]֍r5 i&HyD> \ŷ@s^a%S|AS@ei (˒)* |,IOߋGE=!f6zAQ^#ӻ'p|h*_y3Y e%2M̼7JdOK6G e$4 +dPe@a Ӝ<h0}0c^/ڏ ;) _anP/ ;4ai˗S4_*}(8](oNRy[$cW|A^Ʈ|9߿ cW ,dz*4vKϡ|Ypxʗ_@cWNPbޭbiʗ `zAחkؙhʗ3U];cXVayHO\B@; T?U/4o/g4S% Ā4h ˗8?>}[L/?!O{;\q*-_e-c/G#?ʣp_Ey/ҩ룋|?=WS>SO`4g?w/1,sCqRs UKr?[lgȭ?Xy?z_k)u3Or3*.s$8g~h㎣=^]et*Hw|K#(&z3w["ُд׹uess*J?̯D~wXVҭ8-0}w]J}Ү[d-BU (~/k_oG,lNQ|9>wu=cz;?>3Ðl}?gs^uQ)QYP\ ٕz7G!ϕ7Lf,|!H_I۩~](kѯ|\%I>z,WO;_Sygbro*j[vnT|H>OHSftq]NqN\=52~YXsvɕ[^V?mnvꚵ_= ȕ+&Q[|棶~vFlo׳w$"QS ;G}j3^ClƭlKOCĽO \{?m:}ܵC}"]OWҕV}of[_˵^krGԦo4==w/?u~g4y֩r?:.z~ޛ3቎H~};qmkk'TN{rӑ~|;qݹr5Q~ 2d*QBNݯ{z%9OO(::({ۮ{e捱;P^>a8C/?lȊ DG+^(XZ(QHPdR*P5~mn}Fq1&o_nu6,\-{jfwF}Jا׽"+KIx BGk[]: KmDUEpdvQycʤKװ2$v)u)յQqYt)W NK; QuwLt*BuH^esڨNzUWGimf*J%hzhsW6=R #cl-N}^XV]iRJR9mfO*W `U^DIf*< "V5^=$܃J= u*=$܃J=E"T{PIA%T"fe7GU{TQ%Udv47gU{VY%ϞU"x ՛S%ϞQ@f|Iv'=[c`$};2k2'{>{ZY}'{@APt!̣F{#p݅NJ.+_zȚgw'PHwȌ"P{B %'<{BQ /֩=dJvO(yrP{B %'8ojn'P{B %ϞPd",֏=dJv(y2@dfin96PۗEeN/ %'P{Bɳ'"3M{BɻVv: %ϞPx]"*"')=X q'yx<} z?;s$(Ww[ooJ+Ɉvt|<!ޡ'YmgwcvO9ǂuE_{|]GEIlmҤQI(ڷ)4&PO-y_ g4X5IdƟ o{IW*vG5u:{z=SmO䢱D2T;ސOo!^gNY*]i/}{,H{ko>M'&H~L39s^Hv{*xp4h[߆TTIOiB 6fu+Q9tw,){L8{Vy9ZvҲBr>!{>>Ӿp*}]y/~Ihƽ"kCn{2ͩU6-4h$ZeUёt[$S"zmt{O*G*[f^QcbwMCI|{FX$H+[=Ӧ~Fo2Q*H4nb ֓v}W^UhhWC{N)[+ӻR'*v]{Ro=ߣ]@a+T{ɐ3 "x~6k^-~.mq}:W7{'Uy2 ޴ٕBg=}PntZV&-ϵX:$]mJ0 >CA@SJTg/yt)"t=ѦK֭5s/S"/y:qh/"HIRݞ8xBRRx,֗Nds{~H}+3s#G.}ԷG?.(DG,}E~P}F%?QY?C商gSa*V5B`"Q}j(F3Hh8IjۀQF K}3R߫*ϱ1 J{uGI1))mKG):UG{xBN|}G*'6rJ}ok~#sNd"eu221 h_:ʔQcE~ D8 "ϗ`л122_WRdګzX+?R %g Ě}M?A$Jyjjs䗥0ckE`3ͥ%3$pb䁑G"V4՗U? B}\}Q%]zȠ;h=x/HI!e`je{6}On>;R0m1/:op`y@!<_2Et=1@hy|]yJ<_2A4 **WF<_´}!QF"Fcj"(&~˲`zF^|Is9h? y9y4qve@z: g4NMw֤1axϗ/SjNa<_2EtBSdo`G"Fc cc0tE"P6w c#Q QHл62%ugۄErڝ)Iu04&ɪ@09%Tͮ߿+@/i)]II*e:E6X%3 ewudN)@hBxt(Q {E\ɔ('L. 4K(]yB,X^I$0 IV8ˮ"c4f@Z够1c+!ȨZ;cQ˕R_`G(OdJvȎ%I?!`bg怦tX_ڹ~kؕ9am8IB&O:bg}3UGýfW3 :_9p3g72Hd"Վd\m.W~Z9' s;ycҺK-y-0YEI֑Y%WZy(6;[!dyv Iz{Q.g"ga枬rߜȜL!D 9ر4Iuq\9>\{ Β9'rOGUu_dڨE/+X ~Y-1-3?zɗ=zeݣ Wo+Aj(W?kwh wן=@,i g];ccDS?>M%^wW7uޖn՛n[:Z›.XFX~&zEv4ٹrݓl,ӣ& 1UʐrQ6օ5߾^pQB?=(YoZKͰF 16dDz gxVc,cz92V`:*!փ!᝖ukZ[ONP*al:YYh Tӊ:V keveeF'r Iъ< γz{>Hza*%]я h: Jg#%#eÞrb$h!710b=딡urUB'GK=as{cM;IF0$UB'q#AZ~GR[%z71҂EȮN0*g=)F ,z*\Z+%p׳Q1V +l_'FYUJ(Za{;RzaqgCSM_+1B=@*!ٓ1QKe]$n$Pu~gQ#AS`VkYDi %egb_ۆCd@+aBG zIcʈ 1 JgpAXǞmÞ'&WߖG%BXY{r 1X%8^]}+i]*cg]Psybo=Q<4%B &X#8Z)v׳AJquQB=ѕlBSZH/=k#)jmkiO,e1x>{<`Ax?䫄jg6xx C*5F')Vui],j"lw!u:{72mhhP *cq{rDs׶TaϢ%F[Tgqg# Z kcb'ʾ{% klabG-d}Qg)o{|氠 뫌_"7FZazI'c[* j_6Bs<kuPI.f@^^UJp B= 1ֱRP]!{bB(Hk9=/(YHyiE 3WCgNX_c{914>LWPJ=$vdQzA0׳ @oGizյJz8R6GIcJ,z+}6Zu6F7OY1W5]t8j=r7OWerӕY"V:aj-b={dМm9rؓW`;qJ("^pQ= 9@+UgO>cs ]͏^SƤ 3Jg-(X3lY>{i{NIX+8,b= f u)#tۑI_Iρ:z52j*קWo޽:Bo= #FPW%z72e=( hDZ`̶iHϱ:zr}cu*:cY&`ɟoꡧ|84I>p~7z2HZa%ճ! 3Bs5v5Jgm^زʈDURqzi!ZY !e)^ÞNkThB*a7cu`U$h" ?1pCT**E\Jg=9?Z&)̡Fp1bg=1VW+ɵF{ɡCpދ,pbPFq;W k8Rbg=)Y \a:YD娫fXkz=PcaMYQ.B]V klWO"7eVCW=c IrlzAJ\4j$lA]0wՃ #)AӋ *Տ!Ճ֖mVN Ɩ-:+%t؃ؑe klab'OẌ\/R؃xMٲ56)ʱǞ-uBcmZ뫵P )i˚Bъ|gA#A,\EzY@`XVbG=~pj)xƾz9116d@=gѢX>2컚`-%=9zwQ b=(bu+ jVJg# eÞ~20/>Za:YH_j+]OǻA]U?Փ#m ScG=| z߆yAzuA<G= X%ʇnzߩ #;UcT`yZ7nz8Hza%ӳ)X3lYĞz+ e71 Fg#/9 kl[OTDߴ]=S)D!/3ߒ$B`6%[%7&mEz+ۻ$5( 'Iz|N|u%|U%z =qcOjH܉2]ENT蚥V29UN-߯p/t&zb EfOGbY4oU&/nyՏIiUK~)"K?]: ni3iYnϧ'At%W쭺]l(JZZ<|_!yKɤS=*2Vhm8y{q?u-ؤo+4{|-fX$MZI6pq[h=Kyn<u8n(COS:M&ӱI5ifZ01)%62]4;U!c'b4h HVZ<=D%FFqh%8ۺ ^$Yƈ,rd4(-#չ%$ c\N5d( 8 4r﫳X4fHV `qpvle#E7P~r!X@ 6Ua0k#d""1`5'b.Q*{vDƚ)[Qg9b!c1S%ƶ=9BhAB1ѽԑ %3]LwL^N&}:'pC2SEFF24eĞeWƁJq k֑X| !`nd2?ͮߟN.!Yg3}L@c`$ (GQ~j{Ubȅ( FwHovy3h9TQ4̣_EHh޴?NjKݚ:|4cb11kI5'Ey( A"8:21nK}17Spn*c1/?AWHM$]$ 4O)bSDHH1{89t5o7+V!#ͮ޻Woʎ8D/"azmԳ,[B#F0clv%/h*HUedb'WdEQf jfP- 6Q4Ub,Yjh>vC٘XxA&^NQ֔QtwPȄ2ZH1ߠUo0 b2*1Ŭ8)u'8b /PrB]z2CwuH; c ʃs{;.HLb[`ps۩$DDZԿ澳cwJ>( @Ŷ( RT;Fu{h޴dDjsRع^!hM6+#pjy6)ǔ<2F]Єf4e1c!Oxdy\n#Tܖۯ#sfyk]e7 πxJȑ/ټjˉ$s,{JN!P2@?s^Fɗ#?J#4Gد'/O2sSOƶQf\ƀLU:ʹgL'22<-DV50VM]lq`>0ƕ3/hJ2lV38(wQhvsXkk|(ORӵGY8 ,>%:$R7J 91k0e{jZ^KӡK)$6D!wHǢzzΔ<8K{_u&SFQ=Q UH-A&5UbEehFrtu(igM!T^C _jpYjXصTQ5UKcFcеt"eza4^N1Qtrv m$b4OEm1CbaNJ(1kTrI#O&2z0B5NtBY)0DEd')s[]C`*[K|(Uꤒm D 쎢%r]$D QΩX uPc_Ք@;eٯ<8K#6U`8B,%Dfy`LX"3mO ydC7#D^J Z,է.#4t ֣lSJPl&HRIQf< c,0"3EYb0A(ܹ8(QЪ24!]@Q6GxgRz(tg csz)T:>1LA=uK+9J2Ԙ3^:âF"f]YzfȠH23o0m TO-mPFbM},jsBz!VBGeU1bH(!S#$G!rSUbй61H()vJ #T=gRi ScA Jq?@ITZ>Rx=$j}lN@ :=*hm$B,J}bLw%$DˋE ,"9bh9zw(y >cņѦKZ߬8\,g-JR\\1?B B %Nn\MdPNHka,=E "sN%i]Dj.ӆmMi1>)PfжTA I:B:a,ʈmY1\R]rL8Oq 3rP- 66UbrciY#b4$;J{#em-7"QBhmĠǻcT' F; DjsR=."Qhű4öcbՌ[1%;Jqbp% 96j|9&c/'TyBJpl:nDe_+11K9 }~(#7I$U#X˩$/fY;cn*v/M`ݼg~\n1g/~c@sdshU D>us4CX̋d'etsQwZr̕?j1DE q+s !6>&l~`kN&)ZW,MPPmE]Rn(QߺqQ7]G"31̝M#CvSI>~ij @44d7Ubl`hX?Z)%`LfSINhee4y1Y>ٟ~c,o4]|}gJjڿd;׽2?@ U=x?TO)r/ 7y:*$sHW;>Π–i׿ D(>lOҿ'^L\ɒߨ_Kc&Wv|FsBtMQ7DֿZR 2#J#4#qfH.i~ao&eFwt!Lg2<Ä5%4S(9rGY_$f W Qp4=B>”@?z,Iu7ӏ2|_ 3+(17#ns?ER/Q`oFsjD9J%J (톲 06ƔmdFRa0R_CD٬AwFn(zRtKQ?Ei#sJ Q)ŔiED9A)? FqiЍ)#~VJ =DJG(Qo9A)aRQ8K eDcqp%}J9bJ7tg|CeRg(s2Fvd ;>8XoJxao#AsFHa Q~&tOfH¤Wƫϓ S.i+Q_ՌHD?~TN_} #$qzug V(n@8^&9uA@!@B4!} p%Ix}kVU#B .8^{o@lVGF]ţ4ߥ%⌰uB TcF2HMf0'%JPҔ>)]A7l7L6: ?M(2!0R$/QO(aՁBb(ܧߋnLiS0':%.VJ4)~FR.QRW)y9H?PBYJ% M)ġߋRZPFRnL9=R)aO(5J #y?_(Q΁"3Du).ftgtCYGJg >(拌J\ga+QrLU4v>h)1U/zCiu~_#(~rE?J4+0$N!+L2#]y(%D!|bBr _$):!J#A Cӫ)LM)aDYJ_R%<JQħ{(Yڨg8|QDQvҏr^iBPTvCخ(-!ƌ:HK%Ɣi.QDKtgRJK0Q/QO(a@Ѝ) $_@l1"7P?@ 3.R'72R\~S ?I^(Q"?%W)y (MR^̓߁2A`20SYJoO){H sׁo(iDJeu+#<@Y?1%J<0JYGJ;Jze (ۗ(a8Ѝ(H}2^%hz0j~4ۍpm&vMN4WQWej @5f@#J0ZGƜy4$>RH8eًte9z12.{3Ja{)Q1%JP usIxFD{)QO(+8QؔR3Fk`l_gDY4PB$s|&_zG)oa24HN A(gW)u9@1%ʡ e{ƒz|}F_X ԡrJ)|ѝQbvWiܛQxPϗOA=_N)e )*ET]~ JYs =4`2ShPϗS /_/"3 eۧ=(4o,ʸ7Q^yPϗSPhPϗ7% )*E4 JGO)4˗) #а/g{$@>'h$O oUݲgJ/_PQ|]4@̓z)i0ϗ]'SuԐCwdJ" %}Cwt4ԮPRhΗ/Sg唒?l!|%S P@G,ny(!hΗHH;_N)iBiORxΗLI/RSH;_~/t-y|=q'_2_zC'n49L Y,>I}?>ʣo/_׷|QOm?=)/]1QVG/+EqŸ&:":_,3lL+8i/o>*?ԵM7۳#QZ<һOMA7ma8kˣC5z\֞yjn; _>r6}nj}LGSgA?/3{TߟMbN.8v88V83qDk沜z)+/3\y7˔tGAf0mo++lm aP|7Eo#A\N{}fZ{vG>qWOSS񗻮7cw5Sosv<5z\| P_lf]vU}Ћ=;z-QJo3MSn=8>GtB5i[$WWSL_ArW FT_A*߿lή5|\8qFW4W+ՠ&A/Ÿ6C3zԣg=Enj\G0ŕE8 q n Ƹ~zլa0}?tA֏KicU}ɔ}|"cRN;&1d]5}NcN#G>_8}l-_ny/9\}n۹kqcOs~\{Ύw[yc}dӶq~Y(+oQgTԶJz}=Q߽M[ ~*nV֣qv_+5r~ݜ[+_Ol~[7^(uzuw}"me|T_9Hћx1DYNmN\k Q*kSvvٷlulOl;v骵_7U[<~%or _Olr僯6LWlwz;׾۶xnXDm1&wGܸ*ߧgT~ӽv>Qᶨ!ϦR?[g=SWˉ{ޟ$`zد03\KNV>x뼻'|T+?>-)kDz`|WGoyyF+t\l&qx;)ԹҟGcR뾧w{?:M)JP{o}@ͽ 'Dž@:QBR{/{zaY*9z{QtzVֱ=hue/P-a=1vǀJg b#Iײzs9 4P?E酔 亇h λ41&m_oa6I,Zdk@"jAԍ"S))cPEIL]J[n~ йh~Vkn$OD> rr1U O{> /8o\d%u]ov(9=PEM (zs{0㽁gwmeB %wwO/{a=$RJvO(HwR4P{B %'<{BQ 8ԕ=dJvO(yrP{B %'<{B$R4{B %'P EI*EXJv(=dg(DV,c`5}QD_5P{B %'<{B(~9'newP :nu*x+.}ҩx}]'I>mxq'yx<~Y3?{{=EޛяE~>^~@~{Isw(oRx7{R'8m=L#]{g;uoZwU^+5k9}Oօ; އTxRS/ yd8gi.F;r*<+NI{l>-oHo{7J'oFh8!z':1ۯ}O%x[ފTdIOouC}H6C޺IEJ̭tS|m)oiss6~X4J/o?Zyk໗V,*³򦃶ȅ{yeB?mGGϕz~p?N;8#]n{wH:Ao7v{3j~Tt$]iw;?+ԻeznVo6J7.z7^ ۸O ̦}(iwkt}e6Q %}p_ oXW觨?^#m W7wOo'盼1UZ^o.}o˿ʦߑ߯Ϯ]Ů[{tSޛmzCy<ÁzM {9fN2oiuxo[hZeT8C_'[]$OnZ&wC&$~۩<4]%kԳaF{Y3\&|4zssl%飘>$SQ/:}6I"}?p*w;ҙ# ]0:ܻD0?(m(g(c! ].hL7IM_'$;=J;L֨C }f<كa뇌<`+"{Lt_[M]yV|U9Bj>*9{#w/UIJؔ!Z* HVC]C1c'}*_e-}ԏ7ܣθj7Dv]t*vYxI%4atayFtĔVG)R%!f& wtQ\(gK HFF0j{[ӈ@T:s_2AT1֑h%xη/ePOl_2cw_<ʕ"ϖ#4G؀لfJ 'H_i`s#BҚ>*%WG=ny{k#"Q%qU(+9h\gHX<(?CL\_2Et^r:21DY_:Jru~@e}%JqQhruV8 F@6%ǡ0mclQYt>< /a-i޶<`ҭRE1 iJ3J=>oL][}+_>QhXϗL])0а/IH')0$Dc΢Jl53d9uTG)ewy%˩+"DY4 'b4ƐX0ԕ̐ȉq }U"KH:FXcpN(!'bwtP 4J`EZGġSPbVϦҕD) X\Iz$eXYH9=ήN^#RArts U?%YDdFv J72$X2p3eXG"ITH 4G")KmbkƣI eC: %3D.μ\y.!p/9)8e@x8ϗ8Q`5ru6 TGGVkA8*1O< :cȰ#<)R(e5Ѐ/"D&4SG&ƣ$GYo(QRȂ Fd(A*:s_:ʊ#+ %3HD rHX@ydBu Cys+=X:a}x(ϗL]@101h(ϗcFOgF~W*W29 dKrU 6G@د4W[!,/$ILR_ =xd)D8(4KG~dVM]u2xPϗ!L8Axh@ϗ!aaHUc%tKW*#(#,t)8Zp/AD &3QCb IB:Y@<_WIwYrHі<_2Et"y(|%FC 1 A _Q"Ƣ %3D1v`01 5!d.Y@ 4KO)mdyF<_: w$G1  (+"Ƣ iY^e`/!WNFrUȃAz QUN:DCy8ϗN/VLUi ϗ>6z`K BYtu$b4 +"Hi[QX˕ҘG ;C1r%3c@v8y'D{Jf*2c`"F%b%lb3 )t% }(r@Գ}xd"EnVc>l1|% $LIBe$b4=_2CT1B$J<_"ڨPd;D~{c4V7}^9^{916:FŒ5mbGJq(4D~{=Q6GMm欌obGF6ƘW M~FHE0 ,b=Y{s1 ygA|wb>LR}d2ʘleuU$?M~1/(Ďۘd,uOT$'c*z2b= 344nfRrŹ߳tZjlqYĠJdC/1(ߞŎQVGԅ~{=Qm+ʘ՜zY0cmBܮn;4ms ; o,ޕǜ0_"v߳ȍQ#9pxaAy-9MvX~|0wj"e{2Զt=̧t̴YHIҮYa],vb<|TDahʈ=,r`8B{5q&=@1%L[̀*v۳ȉW"1'W 0ҘӬ|޵|9g8fo7\r*!ۓ}YqYvGg(4]|z1V[qyvF ,pBГ>'& "tc(B:W!g=tyVvh{ycV.W];p4H Rƍn11+Jqk]j~96?IϠ~R}tu?;I^L~!vRC= 82}{!ڳQg@NRb+5Gބ5{=Q*k`w7uϢG=PfkF{ɪ!vXǴ`;@{:Qh:{--]B,r$d%EM!_"v߳!;ށi断2b=c\l]J,n"H[+cFeYƐP$$vb`M]ĿyAJ,rdTcV;YDn'Pxug#ſAaF db/^ l=LhfoYmdz'wYtS$U`SdU<كPCAĠ:^bHf3f+i"Gk@/m"'ۘfƜ0_c<=UŒ:O!ŬzTN / Ď1欔ub R2fcgIa†$}FfpxYF@OU1b=Y4[##U1^X}p~`ne=xI(F$˞hm+Be1:)ٳA(v1B=Q) 2Fgc)e (מN z'f ./X ތP!9M˞M 6'1slb=;0V 8ɪrQt` ],d#! %zYȐ* *Caʈ=,rbHWdTˊM _c.{91سo2gњ(&k&_&Uߞ5#מDmV*3b=4G: 1EODš3wmKފ,rdcVx퉨3^U= )מ톒9^{I9=![@#蚳0n,vc$hcV1B=YNCW6gTX5=X~ aoM߼k^ӭ'Q5G\FKb=1cps"= D#ߺh 6Dg#ewuL SVJge[y{n0gc{;220œ;YD{^:]r*aga uLB= B+OF b=fLfYn{7^eBꪓ [!N{wcN;퉮m'ɷP6v@ ,zlaJdm9͏Ş3e Fg= u# žUJg݃鞽#5)T{9'?wuLuB=[I;1cIHg{3ncV{7 (JbuDY{ j#~Cwn-͠vs#-g2,khB[ߞz?,)TChÙy4^ =B Iטy=)Ɨ2.ofNw}_08o_IM_y?fB凭S;}ڂ% #.o'?\(^w?Rb=y2 OM~]XxdpF^EKier|=_>ıs?x7>{G69ch-od,#3(-ly77_bG[Cnpt>f;[iqnPf6|e{r=γ;n&A?Ŵ+;5s2]%x/Pxv!|$|dǩ{1˽\p 8%T $ϤA)LҴ$.M,t$쀫wLPn_Y,x_bǑӕ.|,Y]HJY3QZ,;2n0Hvɕ4Ֆx+52Ts?sV[rl[42I %ʟΪ?+S\YF!Uc[̏]=ʯ_e1BW?|UYbJ%enȊTT%=!Kec:dG;T C/Xr15 84۲Cc,ݖ.l9u31cf[vr ZJ5N '6fI -+pر嗬]Ef{J)ߺ1I͜ba+ˎL(E?ƞ9+#v3UbNz Q)uqHBӨ؊TMXm#c1FhDƪ7:a+cFdJZo2!rٔ9-T#>)#32m?)>TOFZ)ya,v Ych dx&YT>DHJ1֑rgئ$D+HB(3b5SEzIrqFaD ԛ ] &Bj#‹jN/PЦMT?t0{e=w0ƤTѦ͛RB6%Jq,u{qRuA?"L)(%v}3]ż{@sMTq,G&iRt :qz2lPl E}A>(ZeWw4e4mc9%J7t10vU"pt `1+E"0*347v/9)z|GD Ak!"ڕ9 ^b3;% 9,Zs:c=\*£ԭ7BHG(%3]šYgbQB'kgGH_"Ls2ddXj". 4tChJX*&[Yw{z24l^|\$axG_K˔4Пo[P/cк,d$o<#S՞L)QnJs|#t"[e1Ć_19%3]3 n:}֑XˢHI0lg/C"岘K$+OusuSW0BAc4`H}:[6&ܨoJ1p`c#B4}<#KPЄ듍h@fhDitgBbB()qb亘%=7K E 7JtȖFyܹ(9̑TF?'P 8DL :T" V+Klhe[?F"&QTs00C^MI=Odi.K3l1ch4ʈ=EfF:fhLQ2^enEUrۄD#4jؑ"Bfr0gU,6j4UbtP:b0; kЭߣ :>/(#v{w`_ 2F&wO wmJB Qq䌑>0cG*1hҏtMj#1ʍueCynB:z : RwhXqC;J 1Z73KP4j1!OFΟe*,筝匂,]9R'J3 ϊN#s6#YnXo;vlJB] ϯ&#P}yqUFwy18c D_sX"½/&c#G)Dύ<;6!'f2Έ 6/jD3qc'_2#Oe$V I{Ms]q-[Qn:g)αS'(2y`bo1I4; \]5s_ЍC7i]a瞡πxrgZQƼ`+wٔڢ3#'ת;'QD:'h; ;8cL +nG xJy! pe1- 74mE\>`2kBc1\!쎐BΘMIV6'#R#v~]OɎv@ _-zdGoDY﫩Ceo@X޴3oB:ǚ$vo?9 8 }1HhȊ*ezDE{\6%!y6=PsB`C'9:>?^=QP~61gcn;2Գ"fllJBǢFƷB `C[[Sdt,L(a,ʈMmgcjЯ0ǃlaCREEȀj DW| x qUUyh#J U:HvSq|H&gh$#Փf 6e"_Q}&FQ:#tЀdRGj)/\WZ'V WoEhSf9vz|[$\GaLL%1"*H}b0lA(sl51^B"<21RIԝ1g 3udb>Ljs j="z 2zuBm1lrS9YjЮ4Q2h ~m?#8$O/N%!HǢ,E 2ޙ:tZ:}u (G"eYFBuv 4$D.ˠJ Vfs b4rt(w` #T;=6mR%ǔиtBo9C_5YrLǺE6F)jهZ:0NТ* pJD E>ckOlLR:oJ<ɚw #5PB.cAcxNTAo9sAŬc,g&-J([A7KH(TBWjS=TO*&$`1BOjQyؑKPVF"leZTsP+ Vzۦ$>ԍ=YDZOŜ!0F%U12X<%hGS^Q= RFYN3M(PHS)~m.Qc.Och4Ͷe2lzsBf1uun[ @ 6v6Udlü3.s *9a,7$S䄌.D2Xv$#AߦI*8,o`xvElmDu$149@fV!G 9AFFs1 0q% q,SX(UnBB5،J)Nb9vKzXQJ`Gnbu%p>1I; !Ljƕ[{zlnQ>q{_Li.S&Iae^dXwyw/ˬjh;~ɿgDHI o`ihǦIz9l`Hg$EoKڜB4a]֮ReÇ;[D;cbF{("vH#Ib^`61ЮtB Q*AS,|uxdaZRm}["5 vMP?K }J)O(aU%"ŕ,VEYDTtc1l%O(GL (%,jPʔ?DMA(yL1ʤ#6va+FuIB[¼GEDABEBT@4C{;:_aDU?_g%%?D: Nv톒n(fTtg4HmDI(Q̀r|ʼRT՗E2OZވG-,Sggo臅'Us_ERL;aeȟЎ*B^73mjzTG})O^ҍ/0ҔV]YJTuqK[yE!._"tMCD_gT7(%U9YJTp;[H)RFJTtcJRrߠԘ218 AD5A)>PS U_'07(-LK,"7P@)uPUݘrP&dX%())Q>}JXW/Qz;RoXo^ ~vk|TQI+ׁ挐B Q庀P_&,XtBUσ+3Ss?J ΁.R(H=(Q8Ѝ)醂źŠq/Q`iN ]) K]OenWģlc5Ti@B!@BTeBa5P}kaRRX+#*ﵣgv޾){A{ewNbt3SoW0L/N4Jb?G*1ꄱ  WR于R`EʏW(q0}NiJBJTkDUD)_ռ@wFԓ.#%*>%JeZ D OW)@ f}RcJT9 D)r*)# 3E]kzh0Ϸ72| zs ]M4/0x_c eJzBa<<|;|KО4էD|]{&P|>.<۟ԧA<7yϷ>՛&| :a, <ب(/%z>?<>Whs"]5Z`9B `XY>W`VZFX9P5"Fak{Zh>N_o7C.._#?H(cG+Ey-5t*">=_ ?΋em=)ϝ\U?}z Sv_oRKe~A\+?})t~|Z_kƟߞz.۷mv.Ѽ">?/OWg4@~l?3?>ٯ2u%2u3hz/%Ny_b^;WW<\>˧R>𩫞>Ohɧ=wIҿyIϽѷ?koҾӹ]_?DYJEB_qtk4҃/+gtxT\Mz>?{N?u)_6yr󾏹bzk"g9Z&٘4_&G1e'zdlq~99 X<;~-Q4y1iiҟYgt.~n/]Z'tu^sZh_bW"BW1zدog& hW&^_'1z|N>s?=Zy:ݚk C 3';ܡz>tJ^꼝Q2S$naqzc{:{%5b6>^,ɻ/= 5J/[y[N̤'<#YnKJv~VRyCϙNGG(s$h4?Y'*B ;?Zsϴ/6KL#+?sm#9R4Y(~\O3V>'ӮF2Q?~i ow}l4dԘi7j e_Ʊ_ze_=c~6"QN?g_zO$gmHyktcC3 ) 5E;sgE7zA~rYB;#ɹBEtyGC[^k=џȕo[2=)2uCxc} zqntuD V~O?O O<oo2Zy0G|<{| =ĺqĤ֗zt)?MSeΙpʮ7>9C应ɮ򤋞zrD{찫RH?)ugm {iқEг~`U~{t}Hp V*ٗ{JU(gR'kgYtdKw-]"^\i_3fG%;n7cQϋ_BۇkJԏ>m|.&6yA6'ѠB̳8~~/~bҟ;OMtοYfϬU[ <٢Hm~(/~ &Ezqvn>B$;Q|N_w|/z>nէ[y4~e<ϦT="7]EO2Vk ,m9w]+a@!=z;Go["9ƕo,E蓿c)/|҅Gnv1 T/kzcI/n6! 7@:@䍿63|.YlںXi4e=q̿" f_&g^˄w,T~QM9ʴg$J+&9*Yд4](**1#̤2_w8$\ | Á_ WT%Dk򲞊%ܷ+YMúiM<ܷLUbԾcv4G:&Q3}˔( (y.c%i:Bu{V 4ٷ05KtK8HxƱoqLS12h6ocقFHT 0_e 64%iڗ<-򔐟2hڬoy/%V}$b4M0c@o#Cm$,te`oi>6Ҝ>q5#"Q}-^ȃ -2@_i$B,BA<.cxRIZe% ) .[~1cTb=D4[f*1h:[1 04eoh#qN;2Et? M19|qt 36 j7oXiA$ye}DB[J21oE,[RRh`ϷLewu |(+R#;pyʷAjk]5YA,J=aK=YV{eJqytL(I0BDA_Qy#ȅ@ {eBsc.V8/P #Д=nuw-veQ^!BB0cОoȨ#qΠ={ 2iK124 &< =߂>]N}RmRU׵Ϛ@s5J?Ҙτ g]Q%FKPN 8Ds:ElZdGʒy`HV2CTamW"b Z( 10DwZRnQ#띺QJ3ì"HeM;ځ(E*Q$GݒPxb˔( (3FaF\$;2Up&!sL #uוĢɄ<`#HK"A+BFc!J,H]jV4]syh֩jSͮ<$X\+f .Zf*2 0vJXu *Ͱ*Uj! C)bˌc-+(\е;(u sV!t-SD(ty&&cZGߤ0>D2rFS=}dbk>V-I "D-Ducs ]SvJ(BYǼ-SD(X姑| QEFLHxvG8/ݫ2chA0@$;@q!hϷ"/-Ia]LG)<[ ENQByu)uB)cfRx8ϷL]`U| QE mXAy2@ 9U2x@ϷU`8B"Q  ]*fioh>Oo>vDz(zey3[lʪe|yg1rcTf@-/0b(.HeFreF1؟$vhw Coeg 0!}BK!)ۗ)2A<: ~X(?t1 )9ZG&c$)pA|@oR~1^&c-SD(ccF -2YHT>Ɔۭxt a<߂zҫ.G!?4C| QEFey-<4ۑ=+_%$f%>퐽b<6$(;f@xϷ3tS <[:2a;0oec TI!v&ƣ-SD)|ʝv^&c$l/RJCye(P)\8ڡ{ Rx0ϷL]8Fv1h0Ϸ`TfIobdb*`$! iϷ@62X;:1&-SD)uJ9EQ vJ)#e-DP%Rk㙁sqt½Of\S>5sf_nⶆ>nWpu2׬ۥ7=ĝ*G/M`n`fba .%9Sۙ8-v./8ܩ.Yw{791o;_'3 *?&QAws &^]z۞h82Z"=/{`u,fSؑqFUh_hASZԿA1ꡗBLۋb[mڄAkf>Kp,ɣg1u:ԃ7GoZ- }Mm՛# x5Œ;/.3תu(K6YS6wwUd=kO=:Wy-K|,xXJ?z9Z]Բm٤ ۷c+4>WI>69~rYH+t A@2(!{&۹jK4;ߪI !| 6w}+|6WWc٢_X+iXֿ4ިؔRy^DV{Kd &mǖ_>- o{/+rAK_LnId欌윤]._yڡ+_mվb߹o%7j`nmܖK$߈e;'3[K [6Lm܄ 7ZizVw6 n&b{we8 b7Sm)[*p`W=4Ի͟|IO. sQMzYy*e[1ǘЋO4ߥ$#Y> F^ŧkezPlRq}D2>j (D9 Z^|ukN(,Ȉ vd䐑 B/>ho!]jv]s7>+5!Gn|4gK oDAFP)f.\BO>uA)RƜ [!|72c^։}tmdz]^P"g>)h%^)RBg>)htyaƈ| vb85= /Y)/~Rb*9Fa|ɕb7}ŒyPƜ`;KB?>뿓 dȋF1#T.|0ɓ͉t dc2ЋŽ)iL 5JȧUd"{e)%葒29#SU"l ;Ƽ`;<_>!Үya*#t؉q~}._%D|v,^,Bo>3[EߛĜ\*a˧݂h;%WwHR#G><]<+7b?>A9 |@A6en|;2QYaƘ骛$^CzAD!R9K UFp  \f=*#tȍa{ UȏוYNJ̅XfǞ|92c1+W#D _Q5c#؉BnHŒ1 @0 qp/(kșOΎ:F:AlAP˘flȗb7Fֽ@} sVʂ|/RE6Y+e9f"!Y`oʈ| nbP=5'V+D1kV1"O>1L1'';FYxAVQBW>(m1O^C¼0ccD|vF#1+'1@-\ ~5ԕ:!1-TCD|*[R/D~2!mq4Zq<+#vȍavDǾÌzIĠiLhRiW2VBg#:F3(φ@"D)q#tؑc{3VFga,С-_r|gA#]dpւ#M X whfV Ə"Gu 36JgO`US j7|1=|0gĮ|c4 Î_>(QcVYH)Ƽ0g,As.aIa,pclr !瓸>OUxslI1]3LE?Mlwpl?| ʘ&kЕzXW%vAFum :U #ߵ:FRq:ikVƓZxjAOkVƓo^<+îՔYĠb)dߴ3E ,[!|jBy'^6 YDg|'}wD95UؙO"GFsm2W7EN z(.vy)BnfՍ?Ŏ(i;Y(7|=QhaF ,zlHaVg=}c 3VFg#9FUBKF+QUCG>_/;2fy~'IV_q㓨 9| *؉F;8]!_='>  ζ6DgePcv8tPw󂭀zY!#þH /YĮ|BokVZ'@UBgQޤ*|\Bd]5'D'=C@k/lcNПB$1۞y mӘlЍz^S҄ {V)#QUZ=%9 +E4@fRW9bu K-| +~ݒUBgq a׎!14q䣸>?Ӽ,fr\U=tⓘQ:SJxD>|51uqf;YHe s6Jg^=`rD)s9+#vؑQ0g̽,pBp 0)Eh†,tRǴ0eľ|6V7`sY6_qȍ O9aE'q#ALGKb *agA'Vׄ0UK!t峰AoHؕ"GL)cVQB_>Y8 HNYhq~ڐlЕOeuv FgC Nd+#v䓵0QʘlБcS{򂭌8I|uۘtn|xDc:W$j$쎐ƌ W!n|* zYz{tVbG>d䐑OyYr]mLk|7R/N^]5 3 ceľ|3Fғ(wsJk;FaTd{g!Rl|5ؓ"GFFs|:YͿ;ĿQ14_e~|926d\eMTHEJ1&Z(톂`gj|}0k|=P0],vb7zA^QB_>11/X +_\BcNeYưAjs|:Ah319A;I]mHLU?䓘I?-[*!㳨!R%0W ou J'RrIMYhiaʆHWPh1)v#AFqS1+( z'Jt ؉"GFuY{s3-,؇Ϣ&}Oa2\5Y+n[Y`~{g:F.(11++n|91衡|P+ek#ew4%t]91j9{lgؑ))c^سD2g 2Fgcuve#Eȡ[|BiF(13ۈhB4n$HԮ9XHJ| 6-'cNT>VJrQ zi޺:fmȋO.!e=(H77=(Ď(fГb`c}$}Z6B9`*!r僸e媄ȕ`o}MfML #U)tӸa~Q'>bMD\Ff1䃰Q")a< ^d{ĥ)%葲!e sFȧkI~,Ș<{[у 9A1]ŒTN-c9',vB/>{N(c>.W%D>|܊c[Y?>|w{3kncNO]8F-Ԙ ]O SBW>`N ;U'EN z&Ujq #ߜр1jʈV~)'"=rm4,n$]u0Dl-ЉF8U^slYĨ>);ENsiflraaJ ,pD_x "㓵R][#t؉q~IWmPƬ0ce^|17< c?>dEMIs ߮dNGxORm?|;_K]ԯ<<&.Y6u^@쟅^yr(/VKO?E\Y{sF4C+rɠ:Du V-OTq}7þM2^c -zcȏ>G٩%xTqthރ=󩟪MJwKzcu2o3O] ՍŊD'0'!׌:mG0wZR,$KH l4YVμjepjɑ…4Π r:u)T_垣1} k?nFfY|^ON"dEv۬NčiXZǻٝ6GO|U=&Bg.ɋl.Mw>rdiϹ獽dJ(ӱ^D O2K:wH,ŊOѣ½AGK;l3J%33/#T3Ksӌ鸡[?})gwJƚ,!YY{61ӕ,hЧU?/C^:jnُtmdeVM]Jɤ[Db)ҏ f{A~G~%iEЙL}7c?9z/L_~or&t8gz9e;kYt}!PS?VHBGcs?6&Z>u뗻Mܲs4Mj/{F,3 tQxb;7.7%8#Dcb v%BxQ3skHRBG8ՕJP"W8)GT P vlLRm1[선<"5`NB:[cj18sV `. L@ bwD+#MϩL $:#d`qK>#c.?xc(t#_7 ~4d @ߙK 4蝹ASH|gΡ QvTK_5zΧrf.fJĩiƩrsrlL|?*Pa9^.QhΩtDs`bTD AsF!nAS+Q6G.Qug*Da(|H% Q 1hBq%bZʸsUbtp~iA?a,Ƹ zv ]ihC9ǔ1k0oJ'ed6gS*1y0#3ծmJE &y4 wL tN-2$b)i_ĎczO$L( xJrhګhr;)jzJBcȋQ[nljcw *q\0nSMc|ܔ{C2c@ 6`eUe.4`v@ ]X%QF"d,؃TA\yAa,) MuE37!jwع0J"#tOFqz{yugBJN(;!aEkBXSEFvu$b4G{$G&:#qd$DI'?y`V& 45Ub7Y8$(#eUe(udvL^-,~J y TewDah4%_P5,5]ԅ}{) L:FRgڼVnhkĠPw`$ȎWTq,b,e14c5+:UFI{fF8T?tѭ9>135+Ra60Sj} & ĖBOB ^S%,]|U9UCDq}9)zXk9aˢ |-Ęesv=BO_%Tc!], ulRjNJAN(>c(tB%kTGE (4µ\4շ ՍӰh"/zY BaJ2HuL{ fWwڴx-/H䋈7,Md-jqԱE ^:rb㙰Qbb>dGnlcw#&*#M) uy|BNQȜS&J-ψqUuSHea+44P6Ubfhw#G⍁ Mm$v@ -vtU04ҏXo7ٔ"q>K~ =kץѣ_ARi1m-MB{YMZ޺{^^bbz PeZ/։zKj؜G&E;+//JdL*zM!x/_{jOIԦ_QT;.6QT?,%CWbuwqQ>79o9!_|,24,R*|1L +:RJS Ƶ)mB)1%, =e=JX&tR&zCjq}oӝQ SܯPJPSQJm3  3kNi1~RPW N}6ݘrL)RZ5ʼ+\"ŠWJ JXg)QAjEJeKRҧ0&輒O:/03%@H%DEB}|fˮ0 {~KSJTG)a恲 %* Rց2/ QeНQh^w|VK\QZW0JS-Ƃō5QuU5C֌ f'4[O/@?ABQbP}k)%B|vI [a`՜od [={njh&E? 1a`M=p‚?J ǔ.J#%n@%*=epA7 } RbJTtgzC)%dP(Q-[}N V̝YDTKUJTvO)5ĵcAwF)7}Dc6gGP;tcJbQׁ %* 3>Ȅme_2 )b*(X03,@EJXvtgmBوyLk,"Pʔ=RA(ï1/2ʕ`5=9#䀐FBT4 !?F+,%H[)CyIQ| F:{B DIO(a+ncDU@u2 KU@UkϮ~TF}E?*9?Tg F56sk|U! cBt==N˜_g EXsJHOX{Q KUouYGڕ/hovTj2ԖL_QKL~Q/M}$~Ճ1BX Tg }5 AD%,@(QYGЍ)eJ5cYJT N(%k2Q!şD CRn(HnL&i7(5 7!"ee(a!CЍ)톂 Q%—(4(/(a@E|cm7НQx Յ^`g\Kaս#DM¼DS QP_'D@3$}0W2טUAƂ5TTsUf\F}E?*@~ a..>e}\G~!zq?FŁ*2k $@,Z%,uƜY@3"p aZEGB&!FλΜFBTM5_:^aٴ/~T2_kQ@?s~ѯWL/WB%~'՘  򔲇RbĺRʼ>G  e~(RFKR&lK ([ƔzCma)%, J)R\ :C7mDD6O(a,KJP)&| 90oP !|2aCy}1'.Fx]|;%ox(ϷL͑ yt7`o!|"/M)4) |Ro1xϷ̨bԑA|6!}x0|K^|;ѧV7<[&jا ]S3 ~a2SܷS}ʃ|˔}BI_#|(iJ)O) )4/S)<ۗ)4o/(<J*Ɔ":C]N!h`Ϸ/SpiF=<|;俠oI#%bsؾKoeRn(0=߾LٞQh`Ϸߤ{RPh`ϷLI V(ioe&7)GL=N)_PvFD#| żr^ocBAC|c c{GKR??8|.}s`6gsolO#RK/OVH`I*9Ͽ`)+|ԞI^{猕?})SM>g$KY"Oͭ>cϝY_*ܖl)j|Fic(E쟓[화9WϽfJb=XRϠ\>m=TWZ>gٗ9:%QQQ?o|sr VV7:*G~K瑗|~:5+3R錔=J=Oc8#=7)D^elm{3Nz=N]kkϥm#e=yܴ$Gj]T8Mv9RGKKҙ.g 猔-+Џ?Jt^R&pt.s 9lHWzO;!_~/ŮVt9:2W~,5]],t׳}:sʄo5|w_}vе=u|uRu5j?ٯ]Q$?:R/IO>M6+"Y9ۏΚl5y>yܩpt7z3 .?\ t̾ʮGQ4ʩKO(뇅@\" wn?"u/_xBђkk 4/sHsQ݁fۍy(UOVN 'SHs냅@]<3YE c O?pהuQsY rKNNcrI x|~m;xQEw+/?a_cezޖӨ`g*9oS~ߟ4XGwg,OKDǢi>D"OPϿY oShdPN4/φzV%[dzY'O'<+o-x|cZ _Ȕ:?P<'@le:Dψj˓䝿 D$$ۥ~+w>꽯h/y2A{=sTu7gOcY/qQ/7<vn/͞U[y ?KZ̝S$+֦ErMZ<\t3smrşJB[ϜE3Ft!*Dy@D\|SlS8 h Ns|j,py}Yd}׃~Paҧ4T  V&t]0a'a/*J#Y_pIC$l{'4D>U?WՔY𤗪b;R!YM͟L9tևuVV۶|(sti_;{/u>=@'\~kv+}C+ q3E4xHE O$M< e۪;*OaJ~)w"7e2CddMRKhUCWyФ4TЛMkwa,Ҋ7uY>۵U@bMWݠ@/5\kuu(ş~c^9K[/+k}I?Y˲yC.IX5fӺ/錰H_'g^FW?CiIZJ-3HC+4z3T4!%ЈoiE%'K!cRud)4J[.R*RF"Fc cT{SXYLו-S)[}4%ztBy2xʷju>1cPAcb-o/t=Ћʾ0h7f&$ )_U'Gi$O3| }ieHs|ˏ֧m$vO<]Ƿ&b_C&jx>!!4Nw޷L<?=$n/T+34cP:FeޗCu /8ϷLٿLle ~@[ǀ-y&r b4Fg.e"Eμ֑(`|A /,)QZ_{e$b4Ơ :e"#cw aʾu 0}N>U"^UͧxF"lzUٷBϬ'X˾AEoiNEO9M{OhjɾjKɾ IԗkҨ:04F("*"@h(W}1v`l\Ϭ-3Qt(c1xc/icmm$b4J辵IFmk,ɉVQ6S>Aԯ"B[jϭ떑(gr)(ϱBW9GiO(<ٷL(ۘl[GYUi;<hVom[ZͿKγ}LKx,^߲h,?JHHtЭ6PW'Ūϫ-McM޷:Bq>Mv-O['D3HxoC&) D(4շL]侴M)(e +֦rvn{5sQh Ϸ%9(QWy ϷLeKrUG)-Sv>lcfPh(Ϸ2xja၈(| R%B $էA%c: [%oyC^w&UzXF"F=Cxu(Qv)x!a<ߺBɎO(2> -SD)l#1 񭣬Ď<1c0oADCBqDyϷ~Zg |Q%FK1֑h?=l9vmX!| c:J91ac͹o!(u(cF;:"?$i[y1hηh606Ghhη  >"Ƣ M8o-SDCo7'*_~ByeDO[010o"H9Ju(4)L(elJA=2Et?Ey%^&c(h"9z"!|˔( ( +|+24oY?vJӘen A=‹^i1!!y.< %MӜAC{wYͦWV4D"<[ЯN~2*h@Ϸ~~ela,K<m$)ƷL ?0e|ѝQ쎢k*|;kQʘٜBC{e~h {^G&ƣ!C$XoC|˔QțMS6 ݮQV8F06-3HT~@N(|˄:N^i`Ϸe-x:惹j/o!8Һ\$Ja=:B. ;@sq( A NW\v3DZ~VK""Z"D괮u)/[Z`Rnk"P_\u1 Uv~u]] (Ĕ"UW](+R#;xjeNg=4fAEBfPZ&*1;zѻHhv(L]ȩDFRӵWuFETĖ1Z_B ;s+nB䋓A<`+KA`b Q%їة_ͅDXKH~QG"*]=)[YUk]\1|$TU#$֤;ȃHDF %_Rͮ#vTČTuhMbu)cs f--3HY~OruRkŁ*1˭n8D\c(;@3`;@oRj!iw8Js2PxϷPĬBCyejЩGe$b4<2CTg!X$J11h(Ϸw-2%lCyeBs+r1 q6/clPĥ&'(4[͓@ 맮4Dw6d)#=c0o;C"1u\JA<2A4P o#,ŐrY'uj~tЧ!<߂>]f鑞?BHx%k1Ѽ)|(Rn()4[$Gz(QVtQ )Q|;h*| )22jW#u4`y"p o R%}^tTh4 -SʋĔ2RhϷҘQZDF<[f*2^R"b ce', o&X;]yfxu b)aT`4ؑAxe 23!!y2x8Ϸўʄ4Wg#1ׂ>]r鉞`%] %%kXc)׺nQ6Q&!zxee]L(4[.R/P4Poum$4[f*04G׿wbiyoPvLC76u8Z5Au<{<>|'xC>eҿGьAGm)$ER[,z5'Y" *E"ɘ.M V&-R 8}O9ŦiS=&P z Gd[]o#'JY$b,U_U1y#{7S2*z+aIm9 dXp:Ғ\%,=5$,σ95#'|-$& w5;_ IꗾeHZmPƈViYfV~(T @d:)$~xK>="}V90aoUvNڻbhu_7 uB9-@̒~_vX0]**fK+|6Ŧ3:,^YEGLs :;#8AeDeM.BޔZ"-~|ER.k#.Ϊ}_feZz[&CP"'7e)['7e/f\7_-xͥ>yђ)/۬d-V]o od/N-͡w'I wlw,7 ?E{ B=Z@~'R1-h`;ywg#euv 5F'PVMKV0B=c-QʘRb=jӂm;:I!:6*wOG Y#YvGg52W]Jإ,pd@BRb=C՚;mw@^14,%kFSh׾Ì;YKzb1C5F'k'd8B FgHZo֤ SNuX)ĎsB>C*z&}ekŎ(醂gbgџ7禄\^1B>2Ɯ\B4߿ UB侧Q#!9BfwW˜9=0MS#=Pd0Q͡瞮 H(luOc'F[me_#ds"y 3<"=ՕXР}@^QB=)cfQ">Օ;, c䄽Y=TRiDL"> 8zMuB=uA-cFvSPlc^SJG{Ãv!mKޚA(`7kID{+zX I:vlg}G6PfQФ+t߻P`7e{1d/Yaƈt xoNa輧qw}cser{Oc6 #4 |}O&BZ̡$(6*y2LVwt%/Y2eM6J#ewu VJs;МA(]yaJYЅ%ez*F:cC&.GV Z$@c2"=Dxd5#B=/د9aE輧q.fAOլ2\U?܃P!aE躧kf[}OFBum UB mohr ,YO|;R)œyRFnHqx|;2$'wǘlȁbGMH](@!oQlЇb'T}#rȍ!7xzU܇OVu 1!NЁB&=L!zd'M ndH.l?`ƒ5L!+(Ď )7 ] vb| @1/Y)Ď(%'>(4kJMAcfRb/>(QƼ0gc,@UcC`$l#4GƄ Uя|"G1lgYn|92e.ǐ+؍"G?LYaƚGg"-HcJB/k<0k)YI웣HNzi^0B7iasGcV7n|Yf1YY7YYC}lVƍoVv݄Ƣ7>|;H(@cFاC'kIH3šfkN1>/~Muʇ|4bɹnj).|720*/_7O؍O֖-]`+`|;0|tpd]([j"%t؉AOdl /BAJ,rdxgIaƚGg‹=g>= +#n1s $rLe1Ɯ [я$jϠ-3rUBgQ?ޯշK[7|92VǨcVQ|8!Trlh%(5]|1VDǤ0a|;11cA? 2VBg#8FŒ5؋b'~ȁ#t⓵clXǬ`+`N|?(W#$G<^|R9VEg} y^h>'ןBDSN:!1'w"KBigzg ,$HocfRb/>^1c1/I'rS[1 +|s;C."_ cR0B>MbmQmژn> kL}4=,j 4)~೸AGǜ0_>|;1!1wxɪ!C$;gn|:Qz7SVJg#rYYD{{p W,nd$`4d8ڲ>|4ɗ; aBgA5b>J).- .'W=$rd4Ƭ _!|91aW 3)QҘlЇO֖M*e3;Y3y<Ƽ0gcN|;"8Ƽ`;n|kJ.Ydm~> ʶB/XcFCsҭ,؇Oz 1'O%.|3Dg}3u1S%gnqys]PyJfU2|.PB/>) %; n|+z.}DuyǔBy|GHI7Q,vBE*!o1'"{e,ؑoJ2f4'n|5)TBwG V{*ȑcds/O@YV'DŽ`;H!⳰+fhJ,zH_8(EO*P!O؋b'ƱسwbT=̠0g~|;Rd?l`^1B?>Y;;5d_g { ŊeЏ®O},b_>>IsUЗObFdГrDOG뢮$>ō11'WCgjH:f+#p`!&lБOÏQEmDxr~|{F#1+J7n|?شRƬ_IE=!I^0B/>$T lcNЧ&WCw2#b>d쎑9a*#ȉQ{NŒ2#2 #BG> (mg~jH SVJg#eu0؉q~{Yaʈ},rcdOO?<Ѕn\,h#TGca@'qwBbeQeB?> #cNb/>yNv&C> uQf{"vᓵ7GIn(xz.|=QbOɳUE03(E(c^2> |Ov±h B6D'#96&*!tȉAߢ}Nf;Y(HcN1B/>Xbd*cq^|-fԽ2d/>b]RBG>Y{sQ5+' ̋UwYadm9(cN0B?>bH!qҥﻣTGAã؏ObGFum 2VB1lgyn|?'>K]5Yacgc%1%R~|5пVj֝;IԨ@?)[FB>QeQVK E s _c.|91aN뺻cflЉObGFsm 2Bg?9jv qЌ5؉bGJq4欔؋O}JY(xƎ|=R.TeБ"G8jU4 3(eчJiՅgbgUQꙨ+#p䳰K1!L'CJ+eSzIĠ|UL\^1n,rdTcVRBG>(11/('EQ13Z)+EI9>f_ueБ"7BC3 ,B?>j~ʥ35'U^|r,^t QT51AnvIĎ(lȍOf=yV`iyA Cu)"lȑGXn#I9+#؉q,{s6Juчd5=Р0cbt6*Uib\z!d_ g2>*2gӴ ?Ŕ%U_곤ʞ,)#wÕ.ӟ9pOSS^K//#?/ݲQ liWOJQX|:Glح)ƹeSyr1|R|QNٰcL'vר y esoHuL{W&Ip3S[M.xxegyq}?H1*|Yz/YWzg?}Yw7c;TqͩC{WKe8ֶha;!HJ}P03)J\kU^jw>WJ4%o/Ji|PCu卧A6iFT'*Q}]"gP$K:>ML%=џ_>䊴'YYe|;sgJ:?sռonYD{ngr{*d&a{4׹m7*_i+*+;_ b_=O&uKT]Q?-c?c>|_<%I2f~UdIW x#ΗI,bG?QnhfĨe4X1O_`+`nf91k-lbFuLu2|mB[& \Æ8D?4DM$rXCbʝ(t箦Я槗{I!!@P4c t4۞Rl,RI4 vpd!"esQGh2\J1"6];;F0ʄ7'//>}Id1) 6r~S4e^wD(~Șb1Ф+}SU"J bNMQURZ z{sB$ p,``. ,t`c3F\6=x%aQP)P"tSN藸+#DE ݔ H4p !tUb yltSvR n2t0ԗ=s2@dhрD(弸v^Ǭ0sڔdFxl nnr'Mm7.]@(uAE|11t0?BGdt}w1 QFhF) 94f~¹^ehF}0D(s>==gdTQгXOtPdu"hx&DZ:fhgHxJ c0q78!NmA(E42Lv!b,) ,0d1g!E{kl)@C1ƍg` :R%͋;cBX˂~$.fQSKi w14cxcەs_LHlHMO!;(@';6Xohlj'ˤrR͎)A,8le^J +N4k1cNJ JTf7 CcQƝWgZ7!A^̶Hh!~]GYLʂ,?I7a᧨c_u݅StRsyu P%J]2V\$xrZtt% Wo^0v*h { :9c1kXygV 2:WmHE$1=+šЄT4Mumз(e./ޮJB #T$CPmd)!^j0.&#KTY8eJΗIAQp*euq+#%tXR弼>F"欌_TmVExXeSZ#!1ڴ&΋(G@sq(!6i%M&~i]n94T^;QHGŒ^E[X B}19a3ҭ;*1}5Rݬ:'b4r?U'D LcMc6VtL] UYJ6UbOybЅT G_"B@k++^TnוCEH*ߊ+d4 yQW&tcjQw\m°XW*1b1 +Fov'a; B$Jv}Q'Ԕa.R6GYG&c'^*OlLR:/w(H54מ30ESFlm( c1o-' )2o>,/J?EjhJ-eh1#,ssЫUB\ J&8x'y!u_Q?J _)^M71?+3څ1 a+| 넰Xi0t=qW~?[&D%(ӽ᭭./ 6ݘn(־ %EگP3JX]G)aY+e J\{_bC{0ƔG  啿D)_DՑ2Ȫ:֘~Ty`9/kwq!cՌki/@?8QaPE_C򦌨0~e2_g V8*<@h_"E_$0 L-ڰ c0ҌVݘrP@dXG)aYށRRPH-JXOtSڄ2%,/}/03~B2!_넨~-hWG{b^rvDg_gT+%*9 3JWJ\)%JyFj=JT-tM(JFe^AU6RBO(BJXg)*"gN+%O(2ߠYeY}=L,":Pto1 )AS[2ϯGeLgz=|Oj!= X'=f`[\tg4uKHQџDD`?U9A#QjF%_au_"<{0D?C?,ʩ4Cx%$Z:a@e OޔU|QCFX 9y)́оIKa&'6+N>[ #Aj@FU+_`)%*6@wQr;PcJ5ՉQJX-% .M)QȁRzYJTtR@)#%*3y7 WhIFT}Ƶ08ߕ*&>9#PИgJ/1piJ*!,%@1]W~CJXtcJ`y-—3DTp䧔Rj%*$( % >lB_B"?J cJTG)a>5\ #pFm³T?*.wZ{ z=O7B4pP,.@ޗ()aU+)cQMd,XNLUkt֌}Y׏ Щf_B}܋9^( Dvƀ5HX=.oQ r;#\(FvCX-`l_RlS MeJJT\ tJuD~VE (;(Q]4}Niʗ ,%*h6Pʄr|4N(Re RZdL) e^ D ta 1P}؋t%XExB:!_L}&w3q vꌱm`^g1eZ% (T.}ҵ %PTk tJ]  5JtI˔ |;/{-SD7)ET  .Mi Ϸ?yk Km'j(Sx Ϸ)F4s{ʷf^<2"3ڰx ϷouB5By&RByeJP/PH<:vCi7j[y Ϸ_(4ۗ)4@oB?^|;@oR&^Ro(e@oe&iS6D1|)픲ʃ|ѝQ E4 eJyF=~=N-#_ h`ϷLn{@P_'_8˿ z} )<۟Ѐoܗڷ(<[vC#b mhKoLI_o7-SҋĔ4Px@Ϸ_(41g7|CaShPϷS}Ø-0C8˄|~=ߎ5uL3y|~vm;gI[3ͩ"uaBz>Y^QqnN_oq{:Gώs\a_Џy̹~~O#?9rSSa?>ötCZvdO-*?[>o!'s$s)sDk]{qb룰yخώ8?UԸm,~zY>P^+<|Һ>0suCS>y~7d~ZL9'>Q:?$~bq&YS $~C=?ӧ/ٺ^YV8~}7~W+>"e+k__THj#ztMk#< ܔ+q&W1d={t _ө@I?ZҙZ?[ ~ӓ | }ێ=Ϙ{M//W04 }tEiVk|x&˿ʻm _*X"2/(^Lp˯nӴ|-E>=e![Z>>_hjk'}jpL W[U3$_X@6x֣(g=aq(oa gZ>F]͎ ΁C c~~P&'h;irEe>T/j)+s.T1ۈεT^}9:& (»YׇS/N]{e}[evnn#V3ߎ0ۀ Q!>Ϡf=>Ǭ73;go"Wi KW?>t{6,){ F JPX;z4M1H~7Z{S:{$iU@hv'ѯ Z@>dd IIʐ}c έ _Y?V_ӿvl=܇i;.B]>wN^~puG% tFʰ 7 SQ4Sv.i/_+xҗ4W-΍ugZ[S4 _ih`=vU9|P/ /4O g~ WʫGC=q2'Uy_Р>Y |]ax}Ȣ_^~_+ r[0}V8eO~o7}`<8*?ohߟ_}Q|ҟo~ΐC+޽z]I?/sZ~]ؚ{U>8zW顲<x$ϛ,k|(EJV@, =}$~'9ԮoCzҐY-!KI](* m(zHp:| 26?M?`O~33D;EO*n|fJyѳOc$ ]XRA }9|V$KD 4M<}"ʃtug4pп4~T6Go %|;9R l&F?Ya#W!zUNekV LX|o1ak41mM4C7=!Xy=sntEܳ%>⧃[.O AKӉMnGN>w ~WߜZgOg>UnŲ\#X#ӿEd?h4*:eɮ:6{yAG)/]?Rի)yzmL1]k>NWzݡ@qoʍ<姮oʻDEcfC};v|$y&G}ntƏ'Ϲnj^Y EoJt! -KBwG~g6EWqO_Ra)U(t0G_p^!L>|9 kV.U#Ϻ|)T_. :??wײOlzM*2{BE yB(Fn h᯺ E }-< I9˴tF}ˌ1B:sȺ[!V2A4P8d48@O}fCjC 7'"ߜxi~o>1a>I%$N2A4t9>E+![G ,}KP_fQ Ei/ꆪt!`|+3Ϋ<ǽ!p>%o!_ mlEy.8Tipͷ/D'tZ;w8\ N | ;2*?q8hhͷnZjub&;Fp>!o0fbP@ '_CVxXͷ;g4^.UeКo!İM&Y]p>%o!fp<[oN3y=(@leh"aEvŹHt?@o.~0$4oN/}<[4Af[: A`tEYkڢh37WC{|{)K ^-3$rbdd WV<[&&8@Cku„/O C^Tg60V]YXc̐GBD}b@1۷U{)!c؂E|A{4[f*1j_4[H"cq+c@oQ遾4[oT?{o<[Tgmg ASk;H@PBBÆ巉|F6\znĚo#3V$Ek44 bQOJ z^y0lb `s=^^^c$om)XW%=X]t&|cm^I62#;<*}<4#XBI62paqhͷH`}zԒ 60ѧ~lX\I:kk!4o1IuD@lkӱV$U%xAyͷN:uDZ'|WT? 2}چ~>o[ZȊQ(AiͷyгdioQ&|k. aGBq|2R-#ek j-3D']6@1hͷ9"HUH(]6@1hͷ" '|Եȼxe`MMy4[E].k`u$BB<[&1dýH6: ݎ0yyͷ5ir l@(nH62CTAC0E'|"㖰(|$,*p>%$o8BFB3,¶xͷ(Qw΁ʠ62r!@<[3/Òp>%P4hX^I sV[*OSn)*Z&I״bSJ 0ka5﨟>I ub#2慨DTN,mLkI[I[m%|sq/U/] QEV],2 㖠=%$]$B[|J࢒u r~2#9F[|fUdHktcQGRV[f*1JꏔbQWW">רJF4H DlQb*tMoM!xDRе"!ONGUWJЕIP>TbEPGhn#3csL?UO@?|J|= TӪaZ"[Po^T0GUxؒ*'xѵ7:W%$oDؐ#iͷ/DR2\#ta>!$oou g4[֗IO*P>K5߲(~!șP#[+O믨wԷdl5߂~v f4[WM"PD "ѱ~a{ (# McP9d6M.cŵo!Ƞ㿏\ bSl2RȋE 4[&HA"d#h2}@SlEoraCŽ5߲hJjC>~<7MS3xzͷUbXo`8oZlX^Qia:AirͷN_F>{[oNߊutwttQ(|#*n8eh*q(C|Y< پV8'Jqa8CyͷHXFD3f!EBz͂|B#M ?;ڑ4[M"XMC>~2G-fo!İy[vH@_ذ|1&|*Oku„vOQ'|˄2!y|tBq.xzͷa5;Q##|ˌVWH8ajT˘ϏU·LM"X^18|Ji6:+nx K[fؑ] 2ZJ 7vh> ]pQjToM?Ro:h$oI[IC;[<[flFC:&bQO13Fq>%PAVѶE^^T|;OU>{O :w%q "'|VC1` D2#; `-3 H(cR0hͷ3vOGǀ.e4o!XpC1hͷS8ڕG<[&&~Q:(T͝\nE;T3Q\x'T@RQAly\ PS(Tf\ 4]5HuDa ~0АʡxT&|;%lH8 | ti[&&2ڈs)5:Ff+(4[f1 #kR0hͷa;QƤ\,i62CTa<p:|8t| Q}SOvʰA:|8 -6 I>|*OSmE[;@|uOۈ=@| MO++om=xͷLM"Xic[|߿ΰac"^nŏ8 پu4fT?k~P>A)6v}Q4mDa Nku^<>ԚoIs {˓ku ڡ8o!İ}1Y>Xle&|;eX>, " GCiͷH`}ҧ/ Ole.0yrͷ+VV<#Š nփ'| Q%U\Cc!ƽM2A|Y%t:-Zkѓ~sGX Ir:0q'kB3o ZC,tDqQ)e^S_ޅT-h^GԲ]֗קonR6^{ϼV]7C1Sm 23'r[.[huhfGmNMlխ+k^+CRU)m3"̉M'q?#%)EЯfWHN}8+Aϛaa 8{.NV֓J,lE^C7/Y) ݢEA4tTkG~ҥwI+&/To[\d)xlm>$!ĺ4=1[f3d:&ď+RdA@g- Tkπ86ߢbuv:J5p ey4ϵ@}nX.ESl),ɧ2En%9a>3_hAyTmSPSunA_xSvi\kC}Q(/Bz|̧xF3sz7C=?tA&~h.Y fa8n廩?>g@i "PeRjI'׃m'jɾ'h_6P!4FOz>jK^UMTfƩ?rn\D -jTRBrfQ+˘Sc3y7V UgʨqFQ>w;--NcBjfy13'Q>YDP1{)r@Y2.|,)l_5U)/`&)>S)嘲|\/TL lr\I>Y또J%fT<E6⡅|eL1Boff<&R e0agAK{RC3/d|? !v9`#Hc59Qp!Ɗ1^9m?i-`>g92 Òrs&cEFx.g7//IrxYB>W%g1k48O LHZT6I*!t7~RZ!KSjo&1~FuLTb&[p?ܓ婄̢Fn\;Y90lYXQǤ\ʈ}RzqY1%>̂6UzfvKR$h$Ϫ_ )יLy1Ed|J,dNZBYxJ>g5ʃ~ޯ>!.gw :Y_Q&1DǙ;9Ɗ},&BYrhL*L޽!]C2&{tq },UA ½^q:ABEBSL4gZ1ϙEmmLg*笢xzH]WLEny`:<D}3u4yVPc3-P2қUY@ IZYQ0;gqg)!'/fLBij~/8IHhHHc7a~YDsݴ&d;j`Ùōm41B3T]&,>g"))ЍgcQ'Rz: 똑|,rb}y:Ƅ|\_t$tBpf1bO*`婄̢K;L-'<#; Bn&1>XxZLJ?P{YNrfAJ?.495U>g6222ֱ\ʈ,rbГd8UBvfq#a7B#k@3>Pn5Tg(^\|*ןZ3arTeпԻq:sծ?t1RC3,L hSq7L S߸ Ssmۘд0EN *֜I|YH8R!lFo&qgGpcǘds38ӱÙhJlu ̺]埥R˙EMObdT WO>Co\,b ?ٶ)d\{ɻcddcB0B3QdKߙ2v` as-Dӗf׫;=eW,ndsBuT n~sf1.g\䬶<q̦\\2\yqr3 u1 LO#w3 i}PAo&(Č>iS.SsO10}, &=H]p7i.["7!|J n"XReoUD /c:>S%Df5*=t|B4j4yznZIːvR ČͧBnQA-j,y j$$ L07ӷf'jY6Eg412<$"3}L ]YBb3tk@FrZp^!##:ƊUt/^n=Bw3/TBmƚRSh6c~k1~BuLT hHZ^)7{1[k-dfE+3mQC$6sk 0"3P HBrQ#aEBxʅg5 oKg*RO9 :iD;k`.1e`AHHDŽ\Coq (G[W9,!"3 또U zi]S:bpQn9,LC3/w5-?3D:nY !8uLgL 5= 9†L[G { Yt&=4˙hB {M%1½^q9AFF6˙HB{MG1Ǻ)8A®1ߕY̤OE-ج4S ٜ"b:sb&^Cy*!Gf&022c@ԫP50%r,j$T$HZsb3\?&lYĠ9m._c>gɐ0_`\U?9M7&3Bt&N@ؐbuיD?Xw|1L3Lq.c&Jg.m.j* g5Ҙf7f5#R3c As5FFA65FpfJqfI|́,t9ȑ1UBqfq*}#A ,W!g5V#4SfV9(^}&f]s50"6}?7+d|J$fүW4y~n&1oq0aGB{)7Zq t8wWHXnjp/p ]άkq,zK;o:S Ǚ 6#WzT]D/zS;Z{Hb3ZQCVq7Xk~D߲Sb6}]#8oLb&}J6``YĨ_Q,zYDt\?zYXǔ\/xYĠR\ S !v80%=r0Q_@ ˙꘏KgWBS !v9w>撮!BBl;ĮR>y~nFmN?6&c~lf}Bm⫵c:'_p6~A1!ߗBDSlB.6yXn)^Enf}5b8ձÙh LE1Bpf=cu0c9ID{kTKfd*L>1=,Xw ?Д OP ǙŌ'v8w˩VMƦ̢Fn a3m{dmϬbl_7ȑ"n*!t7wz~82vc̢6಄\ϼN| 1B> t{=w}ŧ)̢6BA63UBo&QwncBf3',U}mflrd]`L\zf226d4OSÙM}ћ*_V},nafa1%y^g GcR+^g;PƔl,b3 kHr !v9w M79c>@=ά_PM5qhJ7yIvlpK v8NA;i.#zYD&Yt|B]Φ/c:!8@#rY,*)rޗ=Guhɴʩ6VĐCJ9{%28/oMߠ-ZT|KwAy}G^~(fݲ̏8y~6e9U/ :nrW:FI^{egS̊{tw $*ǢKzD\W18+P㾤*PѾ[*Th1PU_Ț$5rTB .;i3k[a?T-={?WnGwgo3q* :zg]!P})UǢf?EQߎi0L ʎͅ*͜밺owءIa~t.m]nZL9AG8;K_vo$^Nit.ҰOٟw G#Kxʶ'JBөkQM|_w{PT3,:QUʦ}(/{,%|k:GѥpJdyc>%u3w,no ّdny &ijzQ> \X.MH!B铖eS,'7{j ٮ0~cVP_mC7 ~h&1~Ao8ۑdE gSnڑDdR<1MIg춘M&9 Lbq T>'߮~c::0Kceax׉&Eۭsha_Ĥ=LDp>*"mT} ; N8nH"Vl&&$ѿ3K  ɅPA!=]7g[SFgĨ8 *cG&j,Lԕz(pD.f\8ƨq;:b[>$±-!jJ BlgHoH[/`OqM?gDɸFy^qy-h6r0 M"'iI#ǡ7?$ nA'+w"2d\[[1II0Pcqc (h4ug (Ġ¸{bN]Q(?RgP 2ymXiPd3aXGŌnE{XXˮ$$a/Q4Ȳ9P-es }cV(^*v jȎ =wL*՞7;$MQ=SzbW%(D?9ѧ$CWI(z޺20L4IzcƎbD~wq2ctc#!=l#=. TЂ]UyQMy|.s1qcUb#(Ƌ A}*&ܑdꢦR~@3E";Cn矶U>ߘ96P?5Rţ0Gf *?un E?Z!֟?/FB#7H4}.8fGN?sE(uG&SZjʡ$"#!cEy_RT/b+ޔ& bcIP%FZԟ#G]~#CE9sM"E]HiɌREܝRߍFgyBޔ73IP:]eaQ6R^AJӴ} BCBCBFB7 -.AmQT*Ƅ|$uQOQ)Lv2h:eBhD8uF%Xp>%D^Yb6p/LU=JKkHe.I[\(yG d aέ7M0I]*oJY:y~4@kb9pZYFDq:Gep8]<-8"r= Хd М 4u9 "]QH PuB @M( #X0hb*ĽZj2zGN]I-#K:qj-jD8B֘}ʻ~K{~-j>-B\P>f$Vh$؜Tz+9^ؘU3}(01lt)ԉп#ВXNýnjȨO1BӑAn ' l}LZiTŽb4J5Udddlؙ`jĠP3NU"c0&bNBU>% 5]5M"P*bj PuU޽9'cw4pP [ѡȶu *NdbV(d.I^+0Lj%!~&H7M\k p (70BO\;2шJ_kp(Q:kB>+ra0"QBhk@ I+i#!Y뎪yT檶#bW({Z1Mqh74%C^!xw^S%EPX; #@K/lWůZAYbIZ KTƌB_􄄄m^XZ'##a[Sq>Wnٱ|RdFEDiop^̽Y9nyDptlDryB80w ʣxsc\$L^~5}.eh<,\qæIZr^"xzTQ59BC;O* %B'o$*1h9,H#bTA bCcyx!3mN 5"u)I)] QHXZcD"NN꣕$ID՛'&D8ƒpTGꡓ(z!2(mGfB Eu_&^-M"#!#;R-Ir߀5\ + PqB HC瑑AE ˳Jr'Eb1YޝcVGHxˎ$CiN`hh='F\@͢-j"4%ǢnQHsmI8u@@D5Ld'bi< :Ǡ1r>!k>XN`5VMap?ۮ$Da z"wGӄk(E<6JdmDkf^χv'HIG_{AާR7~J鞾7A,wC_q\QM7 Ҹ=RSJ)aj}oR2%@=)<ĕM7 /QbJXHtg|CIJ\JzN?uM9%O(ԂqAO9bJXtߥ#妨=%G ;)g6;Wg6]lzb{qu|ʐu.!% yA|a9e$z%| ,BEFX&0We*=e{2/lҦ %.rl2al7j#M Y>뇥B¢q|@mTD_$oo/}p/UeV=|/Υ\)r0SEXe5iܚu',F ˷|PBr&O>xQ>xa|MfAG/^(x.*^[,^G$D1Fv'UcCj+)~R\Q-9b"x "o4DPqD䧈"څJQbD"ʅ ="88G?BEA#QcĎ #"x!#w~1~O&"(7" b}:A_Aw "(7G {#bA=P  oTDTf}"f%:ysD"{DT*T.STn?D@sYv{]~*A:PR ||P;N/UU<(z'|T/<&[$u@>eU=({Bˀ{o%ǻ S..{$:hxsoS@PQ`&襁OAݲP ʖiʣxTL/m:u^owQS >/;AM0/.ߖJ` iE9BDuA'׈vۏA/}#Lշ@=D"\s/yzQBDPCDy iHķQ D@uȋ\X\?([jՈQt~FC-DPoD{ ՛za[sDP+jDl?GD#ĬZHN\17>bGDG!"4"֟#x̷X^k/?XJ@N4c[^^+_2TVfͮ-ͩmP22f|"ϙ-l̽Ii̷'v++ϙ[$/@h̷!xsfE 5Q"Af%D^<{_Fo";I26Ľwǎv ѯc4^44ߒxX4۹<Ϡ-z+oAfz E[y̷?Bg%D"_4{ۧg|"!oD'=-"6B Zy̷H!3>Ew P'4{[D1ƈtA b1g%b"h̷O-͞w<{Ag #x̷H1ňb}HoD=m?Boc#`g ѿ[B1bg}=AoCD |>U.k>.Y4vH| į4ۗDg|+4۩p}O1>͏F]+*Ӽo顫<͙7+ Ƿ |<͙份d^^/+t8.zr}љ;|e@8$9q9}/!W|tOPv oߥlߒsc;S?}o,9{Ҏ4hGsXӗ!Fxr>: EХplAL[Otl9B]LyxDbʙhޑ?r>唤ä|)+}pZ>m$ZxUkCh=xD[s*:G_}rΥNKU)O$QFΌ]iYN3҃; !~r$G_˫M_*BөRSIF#9j#mc^?0GXȫ>ycJA'/I7tH8:}:-tO+=a|H}Ǖv~эx*Rz]Pr'<G[GK,ݾA'7n;0 uc0|&-lPa,7T|<}+O @@A@Acxk?,}o=Ooq8 U;OiȚ6L O3}!mncԧmyimz رK6<68FRG{ v8`1ӆia#b$-X Γ.x!S :8,vաG{LY~g {#㹐gcx!86 vGC)O-"$}cttMLƆQ~Pqt#2 1G*u2<\(\ RPK$j+ τ6lA]JéM.3~C}Hᘌ` T[ZF ߇ ݦ xfep^~[۸|@Jqtq+*:ń\Z [K*`-m֘?=9.ףH9/.p+e{r-x][WǭX}7WHH~K zOx\"(zWezFQI ;3`$wU泬F4(,BDCٿώQ_]';K3o{(Q\\ɓD ż-?űcv^^iō%Ս%}ŝ3e2n,n,;gd,D )͍)QuL)P,ԏaa.jiaQL(YVElpar"R<ܰrap]t +g8d}>:wL~?zeG(>4oiILX[m|/4/AڠnlrЮbT!A 4Jw_wmy:ӹ =V(p @EXVyVݝ/7> iuwdyr7˷ vOeۃt(зuC^m= ,Ue~زr]Ɓ|s|zc4nNl6Z~iҙo/HmYqp&WeUaQ{;w[|̂}L[r~:2Vl|O{8n<4wwԓQ'2rUN~$OsK3 |ce_|뺿@RNy^$_t6ˤ~`զ)weiH@7*w~ޮ/XL_Uv)OGO g[~Qw7y>k,ʡg+ >O7. r+!ǂ|,~˞#g |y|W;2"a}>1"cW;^?.td3U.6bb ܕ塔MTѧEZ:F>?::6{;/os֓_%ew_<ɳUk[ٝvvy/'LcrMJ7@$t5{CG]ƞMF:yC'w/`yyܡ/U_{/._[azc8&o?}Hb22}SY ZG8ԇ|gU({wT⏎. ,o>~/ć?تIc$^gn=WžYC=4||.x#Bc| ˗W?NjC)QJm7k~bOHb#èe/ϰaY^;Olqyqw>yS"#ideFơ4c[M$ 6\$2q|o ]ȠyFڽ?̿JD 4[&&xFYo I-D  mLEYTo#3->/b hlNK>3HV? 2G"^[5϶b%q(o#lL8#l@Gx|˄Sa 6T}TQ=,ǠoMo~k4* l#"m[M^D}Gu龶oAA4p.O=vo!Ȩ${Տ#Q#T&}(8 /``$ddHJeo|DBFBSrh|/·y|c@2^6 g>КTNoY:ŀV-3D|]6@0JcׇMη #;Ɔ Z[{9i>z6^[&&LG}3M(D)FF~T%0UըeuހOKQ} +{H&PB zM @i oA#05~۷UHTfGz۷LDBFB3H}d32 b1FRÆ+@Co#9N4ZFKVo!}kCF.ca VaseDNetc@Ž8㶾蟣CζncBðe<VG}zTշQqay$oUJ3uuN7 "}N߲.NȇGD/Q9K҃xI}+aj^zV^c$fl}k'Y-#b b-3DUl3PyXSla$bo!#!C @1hͷ" |$l5֗(T|k:WmaSkuL'e|sg Dۭm@ @Sk}8.8xjͷLM"#Mr0Ěo~qG'E|: ʦopp!8>g^cJ meHl'w~2rܐq$oWolW$"O|+2HnJ#,hͷL MM?~roY}wo# P}X-O!E?_8~3 xp'[u hbͷSFFFjeh2&g0G?<“ju|Ím^O'|ˌo9v 9F2hZͷcF._eԚo!h}KU$D 4[& _GyzͷSoe0>ưb]Ե+Pyd#FX>|K\P"ɽK# Tub󭩃6SmDYSk:H-Gơ'}aÀmXG}I;23D#Χ*X-Ddd1BDp>%дo8^ pYxRͷ uJ7媟O1c$d5Mj㪜c˖CcQO4)>co z2϶8g6 I+Hs|+2N>}<[XAh=g)<[TmFe W7f4[VEY_I͎G||2&_QaDoA/40GU)6zJQDb|Q'|.~BwP@ke;J- {yzͷ#!"9 '| +h ddXAl}QFSmez"YyXA] D|5bjQ'| Q%=*E.8hͷH,g6$H}n-,2}#Դoq(|a@|hyky <[EԧH0ehzdo׫>~<[ZꟴFW^Ђ60 է%WoQ|+Ev$X$doo;2 4[f*1dyYb@26 IY`4hͷSF2ҋ -3D}-4G„SnE'9ˈ!aGtoY?~Yd/IWOSmꔰLSH<[f*1j3{q>%To ]B6N o\NuxXOՠaq#ouѥeF!&_'8t-kDؐ@!҈si,U5] Q}HU/]?zY(-$Ԧt-Pc>t--!4$c:.S$UbW_:|$BuP'#LȎP|,q+0B"|r+˅G1x.؄##*f pPGc$ ]v#$TGStMGߢT%{Cw^Uy+B/AVI#.ړOB5 Z[&OtR [\A}Cue>s-Z-%4$H؀jR:εUbџ\+#À.cpM7׾q>[!@?^?1H!|J {ְ|F6\I<)VUaԚo9l2Z#M1c(Ȩ?w`-3D?vt<&b1MG3hͷUbP$iHmu {iͷNz} _yzͷ} ҃t1>-:i¿DE :'| P/#}\K/ӴoI]Ijw(@?Ѱqgo# Ӌ'|ˌ1R"3+.}ˌ#0zeAL {)ci5:FbPFAFu Z-3DVRC]򘔋41J52CTaE5Wnb `cȘlSc 628B5ur%ߴذ< 8,\r a*MkV]&軵Z[&4Gb겱tp oSyrͷ/>(~8| Oeq37imPsE}`ĚoI_5PGDaZc$fXv7yŢ ^-3D;222ch,Ơ)606d1ASlejjLǀ.eHZX#ēleBrlEs]`$\C巑A8M /Z^!gZsleF0²1c |S*|$FE>(Dfq4[yrͷߜK L 4[GȎPGTK$o!'$] Ohͷ KRuhU*t~F$oI_5`4ly.EOەiBI6:ʄ#hXMi60 6߂>/Z&{"ȕl<[fQQ4% 4[h̰RS|$Ѡ9#8hrͷLw.%Ԛo+pY>9yo!HȨ#21xhBG#meB }#+M\2Z%d#GVL\< tu4|BvB6ƸiXiw}DaΎ.А4˙4 iȳT| jj;|T<[fl/2{)Slu )+Asq>%o HXC 4[G(LHo`P}o vc{p.$xrͷUd$dTd4fh,5NV#6Q1Yl @B@ihͷ3*wyDOƀ.eDo!g`(&|;%[B <[&&x P ILL\> @i-5ꐇBMY)Es6r(S|jAc?R-Ld >k譲R5Zpyk.P/o$쏮Bm[13Sj15=Z4B[4K3#5oXτ'9tK_ vr0r`7vͩmݟRKVH46B9zWȂWc~.9vN]=fe,ŧpt-s!w~N,dɘ \<wT%rZѧ8ː7&eOp'/ WWDzD4=9eNHlvnRKV2UsO=Uγ BZ?i~yn#>- bxܶf9clYBOUf*4ԝܝOMGAɲCNa<3m&_|Sg gC?R@VgW{hj!},~{4hg|oyhV{goAz 8bxC/kPb8?`{zOq$? Dw\ɧֿJ~ kO|:ڷ(|UjWIɮ\% Cv5T'WCx-k!➾^ -v-Dx|-TܫkžVvcχZ%8}!!?9>:֠W stBS,\,Ē }َF{˜=b/4Q}H ՗I_7^h K1Bf bIY/݄h*Q;/ w]:h'I_TE??!¶-@c:c-t@^ABEBž̢&¾ADŽ\怌u'g61f@2,#2b3:kY9FFFf#/jDژVōNL-']YĤ;`=@?@Mtx%tRČf /&L~7Dt\/8YhyC?8\f###cr&.1ا{YD8В&4/42O* ͂> /:fUBV1hsW]B7gE=bDzU;=xIC}ZԶ,[-t>w7Ƅp/cg91v-@PCP5F&.cL O#vAOfĴcLfY \~YH>3U>tC &r=L?CI?/Z;S H(},LM 5$nh=j+}5c{M:9⛉g.7.h!D8똋\,nd;Z.h*8;$^ E-dq EN Yj@!XJ],n ~ !AO™}Im*!tBM~ Ml6m STMES>hu[eQ}L?A[VMzrCJ},j$p7ri8/4t6↺ͧc'4 +2| &F)B \YFP<[Rrپ&q!/R:fŌ1b4t}Vl TBfQ'3B&ZlFnLǘ ,DK4QMOjB.bkX u uLwB4"1п*B&w =?Ǥp/`nhiL z zdО9fS=* 6B $Ϸ!c WWq>0)j*!tD^MYNs>sDInqb>nh2*YĠ{jϕ 7OGZHFXDŽ|J,j"Г \u2B/4 9xKg* M-'<#^sB7grMfO( eL?ըMtc (ǥj)~h4Ҙ&*EMu_E+K9Įh72 21%hɠ9U͂6\|*I]q~Y2I~FMNE*ݪ:I~~3uLdR mVz!BSqCޥSIr4YJ| nh iLiR z2w =p#!qB)l9`N||g|fA!/ZxŌM_? b&BY](RC74QX2Ӈ//4~[m džMFstKcwazYDuƇt\O,tEQ)lYĠ<:ch/YHS !vEwċ,!'Em qG~hs+>4KU:iu˘ґKt@;Y>u]a͒,U?r?J[!$c:Mm4KekM]#!c½AH81% Mߝa3~OXJ Nh71)?*|B>S{_tp D^h)g7tp Dnh5Og* 5EV&nXDܩ  ꗫ>$z t 2VHtB L1#י] rdp"HMDB4T݌qe)^f:AX##Hq֊e 䔶LE?AY_ !<q]qЂʄ0.c*Ƌ0G՟:A$O%i҆,]IzAXr*#tAwCu)5˦Ɣp Fn V} ndp,l &XJ:A$)uǥj)Dnh41h #zAFCU 7Oc:Nh1ӝ;p铕ŚR ČͧTBQRa \z$^hw*!BSM9ǘFbS74+'j) $-دc6"'4#Tb1!יIͧ4\S}, M{+1KQ_M슟ZCĊX3@g_Lڗ;^ R>ܪ%#vB3vcȸ)m1#tD!-Bh0Yi:p1B6%~ #EM]CK3jb'č4vsG4 vYԠsi|f!#a xnh5,U^C\Db&+B/4 |Y̤OVv?w]42OgM-Uc@8O-vAeLg ͢6BOp`B.W$bG4tW!!)a:Y'AJ>b!;cG4 ۘT'!#aExNǾhuwZh3H(HDŽ\&@wN B#)FB2:&sUm/>y\ F+d,b`I !vBkۢ>h3߉ ˘SLu ##9lEcoa*|p}1 BG4}Zll_pDȑI|_pDO?N}UC74wOr\Y:>S%^hs\t}Y=Sc4Wԯc:.h3,h=zL)B6Mz9;ID{imRBb.h5*1! .hۘ"'#M\XEKzIX "%R)!Bw'GXЀKYf1~/;X2>K][_|*>hgJ#^SzIHHHcB>h)g1k 1!rЬg)4 :T{&uuuB?4d) FESZ} 3)EVIm*!BM_L7&:AT ש7TOc2ih/-:%wfEm.2b4pI[h#tAȑ1vV M*ʁe)l5FƆ3,rbEeNcJ>[!h4țxsixf>bk>BG4'f7^ho6IM!gp ~kEmLj"'F[.6٠70|ͭ,tDȑV똒V [NcDxȡiJ+~h728ͧsU M޺uz MT>c˲}, 6BCB*!B7;%Әaڱ TTU&:1> ͺ 똏Henh91EoiOcLgmNؔt C}ѬoAO%h7P`B,W%h5Ĺ1/DMtkQ=tDIXdSɵc<9Y(|6>M2V#$G@ ͢&B]nv |B,j$F/ 2 ^h71ڢw{i_Қ-1N2ep5y5n+GJ> s2)&fT&35Mso/K_nʹ*OG׮#)-fwuN+/B(fπ{S؄ۻ.쿔-}Iyl&{3nHB0;ЙO.4ˏ<>y5JeB+ *څOim)Ѯ!JŌe6-XgYbf3zŕz܋p%!9ɟ۬m+:AQ-˸VR҃(mOOO8Fn8~y4MgLz4;tZ?Gw7O[.W 'OWJDDg$=;k=?_Ԙ{}t<~Q¯o_mFohR(?z]̧fMzIrJ$u'$Qt}TB{TA}],ʈ ^`0B#S%FRGC;]vE!Bl42V c{&jfFAF{d؁ vH2U͡ZZÙwQhdhbuaHH0_ʟze C% e)j?n&F]<)"JL$ tBԩO7M8 طi_Q?\qGőpz8P2vfh,MF%jzR sFl% t8#avEPf+v2M"E]nq!2M$m6C H8GP΀6!< @u} ВJB3Ur'B R&bdo8#b>qiӜܺZ&|̈#!OGBCW+ywB~P]Ф|5jb:fheHHHXG B,SO&+ Zi#G&4/M,쩌ImӜzmYhʢնzkTqcPGD QfKKHΖI,l'T&S5j33аFs.$@] v#bвTA ,oّdڢ6od%2M"@i|JL d:.4Ol.>|ٲcCuQQBl&Aѽsҡ}K:ds)`fQ 7<ّDŌ>U4ЁuE?-f3It}L?vCBFB1BuO"ݸ*1t ݐI#򡝝xW*(Bh*14iX[ ctJBt|5lfhz9mH8 ʫQJh|@Dw;EVhGi{5IRlVN_|pRMT;4Vj7.c"6D"Ѝ<*Dg6SB]Ε%7-f3Ub:M1*2Bo6S%FZ}{[t|hGgB ,Э͛+sMuX^y3UbEFu ٛ{1za]L][ah'aEBquFg8GHn -я=XQϡE#cqQM"D*`s9;"{|+X}BCPtnET?]- Q1[o]KQ}K gNQCηN#velǨ;:Q%ƾs],!+ #!q>%%GȋX*͇!;!V$4#M :\v%!zxLu2PCA>i5DIDWBA&J&+Hh8+2%bK>$±%!jHe~8[yEH؍/Ɩ|Ihn#gʝ-;v>qYq&aF~ 8߯h߈Ƈw~#lH%FZO4@O8mFКqH/CdOQy4Н9c6 "Q9B 7怤Io8eGi(QFUvsA8:a4dAcc1IV_tas9ॿvE"(Rh}"*QIt)/# P*W+B3sCӍ]#-ꊉ.cоNτҨ{A#/j)b1FQ%FY` t$F cdvTRL%c]R]#QF?],fYJ*1#Ȏ|h-`FUoJyQRZ2tI##ƈ !tM"E}Nz:SxFb].P]ΔꘫP[āqjdrF5&BB yjGP`&"b ,JEʙE#4CBq}z\d:Ԅ2\\q>jٱ|>稉0 sni(';[Ƞɜ|Һ8g֛ vRV 2(v4M"r?RVWc.\<ݛcp=<-n"e$Y |y1SV'Ӭn j>hh*ެv*@?5M"Jm@BsPS yLɽώn/ԗj}&giz;&Ec`/}ʻӇ\eF(HD- ˾Hg0'w9Ddm 2$ŮGJLۈT=$5Eҧ}9d;CB I孛_M[.E2;@tټkj@BE 沱h>- &qhWȎ$C_92V̸44GFƽ^1G5UbX(\,2=" c.tٕh,TgUQF3F4}Z"asnWM}'9Ga> 춘m@m z̎a΍[-S^*w88p}*9J˷f~l*>WTocFN(44АPƘ]$/8yQIVVs!\-?cXS%(1U4`ĽZȀzE%|eWKl2U`c?ZyPVKb?ZgYZLU?t5E_MyAZv#^Py>˦;[QJD$4GHW"qhg-񔚦bz[_Q>r>@-~M  7Gɠ5\6u#ceQaf|/j~lD{Z$q.s";[/ Զ+ (t=N -M w Bl9lDHzW Á tTяH(`hwLIq^-KpD(Hh!Rл4@asX{9wͱќ]Ip2bvEPc9!a@?4AI>]s<#dS)ȶ*z;)˻ hv>).0BCeSDv:HIf[x?4g2pzzĆ̦ ͋9D !H2*2,[f "nFe@_ˎ(P&/9gS%-Q/bgS%-h:I!bȡ i]IrZFZY;;FBƊE*12\~,qEHz E_ @Da.2C$]>hh:m'W6LivFl;-JpmoqrITEmyptsH*ϟr`z'8ܩ.b75ǿ}J3~?W><]軍| ~ƙXֳʳGWi }VP;=g oM)aߤąM(uBi7tJ^)aߤU)=JXw{NSJ{BKf*e^6D Q&e٦; En˅W~RQ sJ%mDÕKX{|e%c\r)uSP^'u_'[B\wzNºӦIt%|!K%Mu!#]qeB k>CO(A?A톲PRE~#x=%G 8*%%=G }`6ݘO) (S( pk(x?EFXa$o)DZ>=^ӟ.%xuՏ ;/M~\oX4b.2~U&ayяK>9Elxɟc-bucr/T>;ʷy ҅ /La] 7>->Fo"ڷ#JӏX2*Z DnaW"#ZTU@d1\QYP o|Z4QG*? RsD " DFC5ZA{DT)=*## hT> hPtDl"(A /"ѫ킈*&bV9t/~P<TC~|X ňM Qm {QNm>imw "(ވDPQTў# "*!bXhZ^K?¶(qQM;P o/i~PvнCDPQPWVcAꦉt^lT jl/SޒevoS(lyMjP>(K TN%idXL'X|+ (v!DC kpuZ"U6"OQ2P Z7"3#Rc ꋈYkT爨D"h*jh1&^ DPkD䧈"^jr* sD"\:AgMDPQqAY"MDP T!cw邘@T=(c{o[ |Pp^>,Ԛw:SUԇOQq뀰S Q 9cTw##N"J]>Elg|KG_g>Ҿ}AoC1ElO4k[D1bXg|{E<@7mDk(3NTzqȵ$Mh~Py>/P|ovlNU{I}@Q|k4w;ץy̷siQV|;ҋr4E!`qZk2ߒ|>506|oe [P͗!QbĆ/-!2QB͗)2߾hO?Єi̷D9|KQ j34_!j2߾O4_ X!h̷H1Zy̷?B+|Q&!x̷_}Q h̷D'/-!D5D34_ۧ~ami̷KjNTy3BTC Asg}Ho!h̷/![\>xͷo\|;~&ϳg *6-rscqP:͛Mmy32|"Odw[LXbݺ( C!z;Rl=Bv/w{Q:lK>_hӡ~>ݨnKzZrޥZ[tVGoz|Mխ>L'uy}v"< UIK 8_|UU~Xμ*Ʃ^۷2|МԻѴy[u$|, :#}j 7>1:/%~"q[<)wX{?IQ/~ݠm:H|}gKٜ£ɶ'2щ>l㤏gle:_Ͻ֩O/~!C-.4~uOoJ?{Oc":S{wGPv~Q}Tn*66)uu=h%7VZGosaTnJWGW{LZ~>A0B<*wp 1l<ߵ Hȥ˧4dM؆'ӷ e>MK jӣ]q6dv=;@dyw$ȝ6L|4ǚlHp _ CNIx2 PI3WT3eql(86썌B EP[=Ppl(<<ȑ: 95O2FqCѡb$%@.+oj6}7E_T_Mͺ!xT.7qAGJqtq+Ⱥ8ń\*3 [4g=`-m֘?9.H9/.p+ex|Qx][WǭX}7WGRH~K z7w\ǿvWezFQH c2`$wU嶱/4B-V@E1=Ffw7;g$ YQ<ܹ'c]yS ~D X|)KK;gd,)KYXRXR]TwX"YSSΙ:SqY ^D @;e$esᆕuQs[ +Byapp'1V.l\Qymt>ɷ5UOB)sVInghb{-GYo"_Lk{t]%zsv>M"m}Z*SJ/톂v ʓO8r8#. l}mR~Rȗtd\oZ(\ɬZ;CV{UM~ˍ;QƯ‡lNu?YxG}>38~pzgrC>yMy<-Uxt09x`7 V&#&&g6I]oG/o}rU.ѭ=?_Oq`>Qɝwi5*2n.ɧvO#[D*${?˨wWGH CkxUDzн?w[r!tޮ#¤za{]G'-1}rT]{6I"pdZTˣ<-}mFՇe_.$@| gˤAo}jd_<\˰-y{ۨt_? }?gJ|rY_K6i`_.Gci/!},~˞ -qhc㻛}$g֩97c&pT}E t'7]ujB^vN#,,]!Ib=޵m#s0җc!]5d*62Nnbχ~Ŷkbbm,zTIׇe$AK>&^RKE|Uh=i?v>"Vd+}'v663Jr+E˭=Ϙw*|7\ /g8|t&a?gy-2>UG:6ΡnȃGybK6_}׷k9Vig\xB¸0O^V|^ RV? 3؇m]G{#&}+(}m"Pͼ4a؆E%PAS]*MkT};Q?yS+< :/O-L#O(gY(@GU 6Wc# }zŷtM'?`Mo d\V& oF:! aGecdflȐ_e [f*2]@16ocg޷6d䘁8-V6FBFA%{oiLb [X&<N.9`$x/^Ki=o'8,n]raS}zŷ/Hsx5o>'9&12h9o)c4caS㵨e}QD"|(| KQ}e;V?*4Q(V DŽހRbKR}tH :|JϮaCpG7HTw~e}C}~`ܷ[HTfD?~۷(McEFBXj,G}+3zhF|$J_jذ(< ԾEONAF)oY_4VC:\$!žaUaeDNhbl@##<䃩*-!qZ2Ad/$W:F'fɵ#}c"HGMxAYT:}O1V~PԷL8@F4;GCoaŠMC}I>Ў(D}a}j)6"AteqoY_4͆uĹH<F%|  tnl@kuE !|B52A4@|U#šX{FeO123,>M@1aH`.o3葨| Q%=>䡫#QM6GX߯[l'EӞ矘La>%O:Bu~1`>@52A4#!#!O FD ZcdfE-#Ţ ,Xy} hͷSFFF_co!bmbFi6:|5?q/`4oQ?jG#XJ6:sO I<6P Q:MER-)6N\GYl`̃Vzp!8MW/VQh7ub-Am~4QoA8mDak>Iz 7hSDO`BÆ#4 4P13vdd{ .Yeo!Ġ7db1M16ǰ8oa122Br4[X}l@Slei2@fCyͷ/Mr^ 6N%m\: dž"Iz`d0T&|h˽>~<[['K\EE|ԋSg=^IfՀ9*|䕚@`>&Ս=@| gw20Kէ6LD†<\$r djc*SZL…3Ɔ j-36ؑl0hͷ" ;#yɷw;X5eBABvCiͷ>oۈýxͷH!Hm"],Ơ">1Mv(-A? h-D01R-|J6:Bqfy8Ldl-ޚ 5Ehͷ4[E]/bOYt`> !o HL~F04xͷߟ#/nI+\x--H#P}q[_QwTO+O"oP}GuAyͷ:mMiͷ/D@dtp.=6 IЙY`4hͷSF0n M<[&&h/,78xͷP!#!}CjI62#;-eƨ fcQǤ\62CTQi@1hͷUdlȸ! E<)cHУ+A"HTmT4[GX'ckҨeA] (sRעoNPG}PҢ̿ 3`k`SOhB:ŹkI_&† 06k Hֻ|q(kg "$qZ&쎐P` ^6JHK:Fv:5ĖJܷueX!"]SF0pDՂ2#;F[|r<],0@$YI#bc#!&Z0kQ'_0Q2HT-!G!EQWU޸'t/UV%0s?מhQO #m--hեΊ~B}KޗRtu uL )DZf*1Ek'PEeb ZcF1cTC&1\$V1MvI@Ö|˄q'e@թ|OraCŽ5߲hkTlrlc4[f*1L?רdq>OW_D5Sirͷ.z~:׷D|D?sq'ku :Vׅ "9Alc <[f*1t[#QM##<c\-D GD8bu"OP}́Py\#i;PUq -#Xa >!4[GH1|BI62A4OU$Hy8@qȯ(po(OCo;aC @vi6ߒjPM o;-eq$oY_4#!#!9F#Oѐ) d-3DVYClFD2#9ke3t!W?6,/(Q,~<[̰d814[f 49F0xͷQ2&5MJ qP#"9ͩbU,leBs# Kgh#H@}LmeiTj ɭK^`to(^wT@ޥ4۫PuLeϓl%}$Ԡc8@Sleh"<[f*08hͷH`}+qΓmekNlZPj%;T5 ݺ-5Aa~0АʡxFfn 0k\cdfXa 2Y|T$ ;^-3I½ 6:Fbُ*],ƠI62CTb1M16f0=xͷHa%<~ʇc@1hͷU` aGBbE"f-Xꅐ q~E {m$> NSl5WmtS퐳sGle"i0ѷ8T|;o7kle}Q$}+Ae| ߿ΰaqCMċzӠ[GQ/CNwa&W6=YZS͋&闲:gZ"SlƉb$w~IlJ|u7y3qL>D}Jܣd\k<;3Zꏔe+2/YGOz-3ݒl^r>v=F71Sm[23,r[.[uTC53a371h-ogZ6.2VŽ 9SV|IA<ޣ[h(ݕ;\gzȿɇOa/ޏEٲF{ Zf+!?)E sG9d/-߄ <=Z(Cg>Hc)jG"Hd q|C?"˲V5=YeviA7zb%I>ٺj JܵK_=AgςǾn$6][KFdZ7v>6lqz&*3ge=_lz}.'[*Hԭ/OCn-ZhSg_T./+ohӣ}-W9}F?|!ZW@4oApĸ,^ȃ2A[2PR )|o})w\ɧu]["TS㈯^M]_K7ꯘ)ྰR%t\UQ효Nh쌮V"`"ʳ+"xѫW=r}cϰeM8pO1;Կ?\Xg/5PT|bhi~>S5?(eˉ#{~&^U_lYK1B&쓲^) C74p-4lc:Nh'CcF%"N jOf cB/{YD0k>1%];SC'4  [6>Q!nh1`M&B^1!Tc/4_@?-vCw W35ϛ# {YHHX}LYHSЖBO4u%{ \_D𾡟-ff#cEFr&ސ2ا;YD8Ԟ&2G4 0W,S,C?*1ʇh 1BW4.utK娲0SֿqDQ1RC/47ԧcLi~k;9Ɗ},&9"A֗7BG4yMƖ鹄pWѬgY410Fri't ʃ~UX>ؙ*jף_ c͢&B^cg.BWPXhq~f1>%R~h7类-:}̍x\|' !vD9͓b?4ZmQ *\^CBBEYDyoG2\-FFA65"?t#FfZ'Ǔe6Be>S$d.J\ ߉9$UW,jE_,b?4eZ$RC749ԯ>b/4yQ&nTOM,M$wP1Lt`:iLjtv&APOc"7^h ۘ+aڼ5w =)"Ew`)MXY!-Z4Yd'sfq#cEF)\MQLfe XJ$joP"&}cǶC=ll,YH(H،]8b?4ugW~|EvO%ݸY_K\YD9ځ))پfq#cCF)\YDew{^.qrIiĦ]^gU}ꄦdqAmTM%}ZCQ"4 %"4}wvf ^/xAؑpA|Jh+HHHX}B'zӺ&QĄV>@Р_] 'nh-XPm#;yhVybCs~ 4n$p A*(K?uCIUl\@AV~dO%9L(Şh92hQDV '8BR˜a#LboMYI<AHؐ0G^h3kA*._SʘS h M7x辨}{=AӠQ|DU<@SM9 KZZ  ۘLeNhʕ-G \S}B74#@) zi]Sk5` k>hSO`YĤ%: f) mBJtȘNV:@ZHHB74 5mQIn79 cS EN[:"ܚ nh920n*afA<`6>Q,d$lFh1O ͢&-D~|J,j ~񤎝,fҧ]LTn$j$4$1!TCof Aྨ͇zqBQ)lYxr_YfJ$`)l:Y'A>b!^sD"t|;ɻH>pBO4Ҕ2`IdlS$\rCl+0LQC'4 7ԯf.`İ#$c:Nh71YX 5F&ﮎI^X1r}|cJ~7^h7H،Q[ Dv6&~ ͢}Sc2>O՟;t0C4 { ^_$AQ=,^gkhn<,f"[vt: aqYhƊx>h6؝qc>U}v#Hg{Y8vH NIeEuLkNb#E~2~VZ_`o~fQ~V*!B:S/V^`\MME ELȝ^=&4 uǥM aޤ` Fn\/ɻclh>%Dz=,n"h<|藅,f.e.Vm J<O WO_Pc4VW]%TB&ntp Nh)gJÎR½%vCA1!ߛJDS>i*uw+Q)^`&Y cEF)Tͺ{^K]T ͺ˄!v nh7WrHSZrU 󢷰E}hq_WtʄDEWımfYQ?aELWoI9q4<]->!rUFfa|Ot Zpn\,n ~;窄͢&I?lrj?Nh7RHb74tߎ w}Lg*BFbۘOSC?4 e[d~_OS EϓorJEa*G`:+Nh526d4T M=l2Ao "zi/Y@B*!tAw)MwdddT@WMFwMiL sUZ;G,^@&tR]fE1R,n#$$cB>W%^hI49/;IfQ ϝD0lm\LpЬCuwb'4tˌ% \0挆4&5gĞhd̠a K z"GFAƆ O4Q~R:';YDȋߝ>rLe[øu OSCG4y+*L[|n]Bf1+>cLo-tC@w؎l qrRK]4!ѝi^j!.U]8>w2b*?] Vu]=RWAyqLYr{s~+Gloٻs99~6|n^t zj}V^)dh}F?吹>'Aݵ&r8w2uwƿܖhaoggt_.fvgI=ObF]XjbbQ{bA\U7P㾤2PߢG= *u"2Tn\,d6,h=C*mayQ[.fzV϶Cd!$q~xc8L3ZREͪ|r<8 ǵIbC*(#UDKjY~UnI? -^kidFNJn%}}~I~VT"f2RƎW\), mN7WZ @)W.էήb/-F}ĎhE] Dº髕?2ۋKol2d^QNc=ZGA$?*4ʲ^EeUk_?<;w4uj$e>ihJ#<={er6< }]uTKN2ZZJaH|w۴u=~fP+oFӋM26jY~-w{f3,4ȡ/gtGQFs,b*Q>%U3w:3&hLIEB.ҋBt 2ASBR.e6H#g4jO|#peL3BO%S%y$Sk*-ZPqBO%4,CPeġ-;L]Ԁ+W!FQɣTR-A#MD]HL WM&bdr!$7JnS<],/MjZD2aV(DQzŶCFF3pLm12$XJ>펺S6Mǎ4p,w cD!ɝtв 9<{%8D*OFELE L_G 7ZLfx4.8CC -$¾ iJH=?4ȍ[/. ?3FY*7]RʈݸLy5=],1{̪J3FN]I,b;FU*T5r|:F0^&IFCCk/D9o,Z`> kٍDڢFpOD &v3E?@g(&P>"{LOW 1p'n]cD"eTD87sP"ki*ڋYDؐ`kΥgJl0fq# c Ϩ6tخ$/fFBh^eJ'-KF+2*10q>;f2FhPC3S%FY!C!6=Bq+ A'-Эi{h9T\oi&ċT!p4p U*yTu)iwr2*2tI#t3UbEK@HˉE؆Wr[B e6ٝ u&xS~\ #A.UbsETaw:&pn^v?@7v+ax &󒻝&hIH3hGa?Q&;i7yIZ_Fĺ"/9F^t@Nŀ.eܙ QfmW U'@ 6tܛ3h>w"'F26dk{TAfQ E G]^yG_Q)63M"G0~ޢQC^>yE|7TgڈYrGˎ](Rq]%AF0҃@,_o|D7O 7܂os}#Iebcg{B U^&J z(Cc1ƍS>&0nEs]],+ %ZQHUԓSl9:a$dpx'sEUKu1v%gXWY>JHr2gG$±}(Uл#XmAM)Lv2oa}C $\T>TM60 U<#UN7зq#l:R ^th?1 ⫴iBJ'A.R8bI$BZT6`qhw:̢KT} B#aa@dF.wH(#s4PC` ɇvJBuQS*UBMv@ی01 29"'F3URGVCCl2N?U4p,JPB Hؑ8vcH8mLe.I[9buSD8749_'⻉C*Zts asBlɚh;e5 peDN2e*`ӧiARv)nQCFq bOyQWW*qYj@vx^̾u3{AmIfdl~*1hm1 ơ21)>t/`=!1*z{"zRQ>UGݛSZԱ>%{?\$Z g]-f#{KI+Ҫ`.zK\ʈT;-5EҧsB-gy҃b#!ZkEX ,UTkؑ@{TAKpf &b]IVrTR701r3US%FYt;{8B+UDx>C;\v$uod`(qdM!4#c0#E ӯߜ>U7HB ^ cnnTVDoXZ\'@*{||h/K/j8c[W 﨟@~َ$C+`9 pϱ;"# o#7#cGF^#ckH: 3`d0~E?ψy#cѬ#/(LŶQ36 V-#8 lCY$uAU;v$ZL wU4&a~^))spXkqj&|J=kEEatF"KZd`24O-QJ0,%Ʒ颟P=$.Ⱦ*b*bk$-j#s{w( b\S%3~HDzL5 JIhYԄq>%iZ"p/΀tH6T-*>ey E=|P2#CFEFBFv 4=}MʣV9ch,*2q,磱X{!ZYUPSPCs`єQBιp Z&C9i:6N~gn]aZK榈 1Q5BL?6M": $BC s_a~ZsCdSIl8 9=0ce~/-bW\Q_x an˦m-} i[7*2"Gb1Fh<2hmFƎ2 gz e#GýeWJ(wOA*1j[zelzB*1>8G<|$LqV#$9"MF2eEP%dϡ $T;#Mҧ` :Ǟ$)AP7=-qLs2d xؘTOly2bsjQ5Bq4!X$?7v⟫5Qw%!ZvEDt-Ύ"E W7צK*W!;J0V(iLa/-9z,EBwc#_[_Rܼ-p ,}_KEuU[- Let978n!ew~-SrZ ٙnsmyJ2>?GJ5᥺q,Dgc pYJO)g53YiQ'5eU" !<~Xqwz۱~{G?=\vKda^$$ P&QB٦; EP˅׸~RQ:s#J\t'rCqrզ.%_)a)%E)=JXsJyBN)(ai%JP eGJX0tg|CIJ\2}J)aw( %<"*';o6w)H)|OUJX}J)aw( %OD<*Yx gefrrPaVMSj,_,h|J"">""(+bc#Td}QQAVP %F`HO%DTAu1"]Q19b" !^F+(:AQ5D5QGcDXT'#+"(d:G)"=AuLA5D*GG? ⣠".o"fuC2poCA5D QQG爨(N[XYjweQNP=c];{$UTAͫ A9ׄX8jsa]͠&J{ :wzGu+o/|p/|!T7H~rXj_E:*s> * Oo|ZqD bt|G#N-F+"(#j3;ZzzPJQ54xTE=cxTp"Σ(_oz='9PXQBP a eGDPDGDv"2!FEDu G DiwՎC`0N)FWDPD爠0!z#bAM=PDz.#"f%x lkG݈Xف}}9W2t {DT}"2tJ c nA8ռȟs/i"oRpkz"z߅ o( (/JO+UyoQ(؞uxT?-5FIۛa3UcUЮh-YXuoRjA}QDPl8~*bAw{U{_`#UAh*~HS@>؁^A//@<+Q-U|GUg|QVf|;ҋr('Wգ LiEw͕v(?G\o !D]7f|#!x̷o"͜vijg5<A^y̷$ϣ8͞V,T|x 鷄o/4gۋ8.<ϗE3@ߨ<ϗ)"Zؼo[s}//#ٷ~x|o !!􍆠2>E4_5ϗMm4_ b9|"!SlH_$'{W3}}|oDee͗6D x̷? 6~PFob[m3zA|oDlO4_!Z2^o|o;`G@*Ne5My̷o8͗[AAwi̷&_~ _P|{ʛsf}04k۷T4|`{-q˴빱}ѡOBT| m/{T00+B!U D4N<(8<2Qg}V6?}#qd/!e]r [? EqC=ve?a?Д畲n$ٵ$-]Fe S|,$OǞ)^^^G.ܹ˯ }$-`aVN37ΏVP=? utxfX~ZoA5گ<5s&o$> ٱg`{w>2ux>U^*=z:$8:nI}|&yv66)wu9L s MO6oL~.:\ `\os#[+WSLr9Xy`!lYӆ)eO|󁀂߈,DOie4*>@ے l~cԧiyAW^2;@w֑ }P P-u57')!@dPPPPO!C}e7of/#3^;ίx'#g$)/Ơ76]s2(_QO4G;^:dtx'p8PPP@^A/A|ڝo2^=dzȓ,.gjxՐ!UC\5.2^1dbxŐ'W rv\wlh+_RAo $QJBC{AneN7f>qʃoy=N-y@= kejߢ/xP& #\s:wnA5Ck2fYAixP5Ck2f dtK / ^2%ÅOQ  @%C\2ΔgΝm|(xP5C\3\ @Ef(k~aP%CK2dxy8p菄/|?>?NK\2I=J1j^gf A4K}2qvθE~InPg ')#/p>OKi)~N.c$?ML}RNfNg@47d7V9)|D.M|öИI }|^_rXz4/ XywPy;_Aw&wC>7{;p:O.H?I3$4~KiC)i,ҋwm)yoNPP&$3o9}S-꘦SOO73<IKlJo7tAYYyГtǥtv?\oA u#ˡ!b?;S*J?5.DF tMnRi*;[Njtr] /y`෱?a-,|sL*#Սo?9eF'?aӑLF)k3; j}·˰7y#nd) ?,v3faSo7mS&(x 4;C>3]dFʰA;D y _n~ M/7o]?;fӛo6 mWR0[&YL>7 3^|^_OtsNN]M~7VKuc\ֿmW>s_hdQ|`H?ʔ35w:ݿ2"_[YZdO WY4 M{;s0 5փ?ĉ?~+2-4K>7ZTO]/tNlDko|  z}t^9g]>iِ;aGo}o~Ӎ^ny:w-V9rs"?PN _wb蝕3 z򿸻et׼JrEsum9o%!+2 A =sp T>tAst'}D\i,<{owz> ᱰ(şM/]јHC,G!‰þM"?3 4G"]`s]0f=% =jP:۾_ȉ~^&۸a/i{S6OX~b{xc}ׇbL?lRt㌳\y3^<7ڹ/C/>nv,>x>ѷowuPNsExcqnT"<蠾yϷ6^ 7' +<=x.ηWmćp*- Oo2ƨd|L|B|E\k*@XE@B"5Oơ3 }g~nl G) BXҷ6s2A` !Tҷ3E/ s|k7N 0U樅QA-.z:Uxex6x9r:5WN%;oQ@=7ϋFx5[3 h"};h*#>m0Ǣgߠ_g@ #P<-e<΍jx66oD3k Ơx-;% @4{qw1&cJE[L:Fog +@efRv}L P<--9g5aeO/=@L|CzIPZ[h0B֓s/Zyo{|E63v97c ДMK}x&^NC~lx-Bcߢ@fznP@Fz*طȆ 4sfeG-2Q1(=al1s$˃l}= 1W"|3预 *G-=BDzJs/JQQ*r(3S4AQ77D'DpzӷO>)N-H|ndķFoQ @"P?<oY @A>T/j S~E; ("Gْ_砝$:h5̨ <[Kz,ߢfOID-LS<[3k2>蠾i.˷`-GXo:wTL]<[CtQ8D|k6*ic B&63v6vkMXe|'ڎUӎjY 9,|屒r: ~3e9,߲@A~(ǒ} Qg|-ha_P0qĆ'>Ay%[3y'Cy˷3qtxءKZ1g|d*\oiu9woNsY E y,Z#&M)M-Bh&˷,L5 ӷ763n_ДM3Ye|'|go-A4[Sa)^.pY,5/&^0MY,ߢ@ u.Z&2'^-A4[3yoOsY+%W}Mk&YefLyU(O3ZEl |B˷g"s#3/|n-Bx>˷,LH38T*UA3':4[`& e6|~Ś墆qt- (@F; pGײ@FrnP@̢kQ` %LT"4LgO]͸s͢&!( z>u(t-ë-rځe4NKA #s-%ܨ7p];;7ECpmRJ,k;y?J_g\,],K:l fpې# !J ٽps-?K)9lY {rQ8T a]6c@O|CpoeҹaKA ~lX͂%LTCC|V&JL_Li>_G<¹k ^~.hwה,Ak1lD tVzѮ7-B(XZܩ \kY@3)lK.""|7`%LP\F˵ gsΞ^N3%@a٦)>M p3k^:^0Celo; ^.Jy.˷WcNX%8!>!~Dy,ߢ+ K2 LoY$pbbC_0 t} v(5;x˷,L(p LoY^65Cx.˷(;hx,yշô0 loDk ^JJFp3 7exbz?Y:hyyWow˃؃.@~ @- N4[sQ#OXE|eg:Z?>톚 Gs"GjyFHH1'Zlb8&mR3lJ6jd>gQ.VY>l4qZ*Y.&+B`Y&"`&~zY/O~y&ѿmU@UvèM-qL ɧa[< F3j|v/7A>GϽ1R:/JU*lRjc[dlIMeYA:`:x0"EoQ`lծ ɀE;J$47~QXgOρ[7M{d5g'@{v+e!$ ϬM%M^WgƟ^[>1:7x>x(jFm絼ϳ u*-_w1)Sb)3A<J*/PW!g:~,n X-~Yt!Yt-κ 6~, R0̂ zOGʌU=p(0#+~H#G6yOO]'5Nk_ɜ߸ٻ}qۿ\"^dZIx JYJUVVYa7#/GV :^i~V\\jfwsi:LWױWR /68C#>w[GsأI)+ː&ПIU|3>CS)K^;4i/`*:4i?ZD@ءI%LTMOh^)Igb&C&Qsd`"3i?rYd[Fi` 4`#^;3fb1KM+a&)ٱ$Lf3Rm"1i/I`z*1 2 lT4Rc-t0Q=x+%cG>dҐJɬ}rؚ>LؕwN(XT?D.&1/v՚Va}(V=e ZS#2iOC*"o\57<֖Y"vCW& yT0Ixgi,by3iȀg]z4U fҐA@~l);SeCZ=x4 ܙ4Cl[.݄)9fXk_g[ >vf ~MDt$䟃e҄JZ=;2I/.iXz 1Y?y] V^92Y F/f(ГB&n6+d0M\,dP `,|7A=VĬd0M,d@|I*>h f󮌷$b vhtITtDnzvK7ܛ"xE< 䀹);fbE8El6mY+_XegTU e&;{}.9 _K߻2YD`12d ={6k ߎȓzZ(PQNؕZtOVpcW&o4y3INYXݙ&p/}4AGL,7+SޫX$0=L.Fw[)ԝIҔT`zɎvdy+YIjjdf'e;ʎțIB&<ﵲloSC_& 0I|,dV&1LR+ l5yz2Y{"6$ *eh]_ y3Yl&J3T|$;W'įTY;\R>T|Dg7PygR#y3Io\­giX :te &0^S|d}xs1K<h('L%#ӄ\_#?&ГB+ $)dd`R 1Ygs1EO'b7s=4 9S`GL7|_]'MƞLE٪ *>d5W,0I)ؕɗ򅂸L' W LvIƎ1؛I&vOC?HN@UЛI,>g )I=ٻeCfЛIUKjG8~ Lj7ų^2et$a):td` \rIO ' tIRTxȤ$& $U dҐAvIؓwb,^ұc@ teҠ'YnY2CW&&fij.5lPJƕI&|$LP',gm{W[;2qծJbCȑI; yN١+w̤, <ǮL. K" L̄rGK2v ĮL4P`GؗI&C9W UЗI %LTbg& ?n7xqjZKb޸2iGt&(ؑ)YJ~~p {SxƔj%ӥ$9.LjJ"a؁Its<}-A=4dna2>L1wKK&C'&mЯ LnzFI2$o4dd0M]4drs׬n\"C_& XrkVVD0EǾL. KD,=ELl߇40=ǎLL׾Y"v 4ވ^2:21SNfwxJk&vc?& P}LTЏwqh xnL#g8`*؇{1iw({0vC7&.sjyW;^.X):cVaW|޴/Ba؍)[}=go41ibreKZ-LQBGn:*C23ؕI&}LDU tfҠA`E Nͤ[ʼ1خ"pK :3i_;3`xNL2fJR:2o7L.K?a4\Yڨl)4LfC#oxg9%<*9gnEc&&[V/X 4\oɀ&(q®v{lY4Zp3z3iov;jrj,p!!>]$:3i?6o{'h: L2.}i@;Ku7џ"viҐ/ֺ)LQKh좵]Lg즽\:gd4J8RovwUP/>'{n4\3js&Йw^ _'w1&{3qȄiN6W,I*|ˤ"{*=exI \O67,9@ˤA@F&/MnJq &)ؓIm?Гr{NzY*L.+K/a";1i$C)d0M4h(p82i$y%LSsG&ػm3CO&YJgUv ĮL4Pǒld0MŇLxmͤvR!{3&НxCx2i*÷%YIKؗI%LRB_& #7t0Q}4@ Е?S%cǀ@ˤ!mH|ˤ!xKaT0IŇLX =KK"v_&tEYJ<,?%L箈NhnL_sKɚ7L Q`/ zcWK:؋*:3i tM|4K|~lLBg& $LR7lx=L-뒴1d);eh ^ؑI%x}<ɨjaz4\oC/a=4`W+=!eTf-9i5I{2i@O@*;tdx (Bʘϙ('  !LR+ xﴤ]?G )/L|I*>teҐ?FkrѮ`]8`7K"cG&vW? ^_Ұ#92IkiW%D,A$V K/%,,;%GnL+7'%N# :xL2 (Жd6 &șIvzIŎ`|7D觗T,r_QdE.o&"H_ 1/s"ԓJVbI dѫBK"Gb*Wi>d^KΏMT'KΟ-V`S0? z/oP6A ޅߏǻo} :}Ňvh*ry, +FÔ>8p n$c0eFekE@lLiF9t w@; mW4.!+Ƕ+J$!v3j ƠxeO.ZdXWL4оmy/kE ؼe7C +-J$Ŷ:t$kP͎1ZG#&z7Hǁ'6Q& bMOS8Y1eJ1&QOKo,z`#ZvC `Jvp37O:PF -~h3/Gy?|7[:Css2V ],9Ba@J$O ;- %)=4҈I`G(UjɻتUD )ZH}!ݐ1I TeQ>4ï)SXˎNjEh95.2 ѫQ5[7#oxhZ$|ɨciVuB3B`YYͲ8˔0GF3S[p2㮝 I7&R7pD 8BUl"g蘺C(|317`E@*Y K 16Ҩ0:|h4`KXhIjDQv~gF{:)=+KHHDZ!6҈IF5RbK+e@F v8y׮Lo@Ik0Cc,eZG4=k|xS8DlӺVݖ Z:k)91mrަV VsL~V۴,Ѯ<ڍ)׊husin1-׊h9ukg!1m75Ht0`:P( )#Ҏ0ovVK (8w_ ղyu((qWFzIwӎvp ¸3 zI}1C۝MXA6CНMu0Aۆo#f{kp&chysձ)ofO5ŇcWs 'D >{O!~iTVg@tӲc@+2Q{6P`Gtʪ]v%C:Y(%fMÌL=KoM7g Ǡ1h$P7=2R8-#!Po%C7i_/ZӊUs"e1hahfw-.#뵊wL q^k?>V|K6:w_w)_\4m7g ZMO )&кMW%Vf /QHC ߔH|1ċ1>~c.Zv o 0-LR8}_pjVMH ~R4^(fHOyhj rl3=]bvjV@( )xscF'Lhf1X ^P!]@H.` sx/+ޱi]pHSH e4Kìer wG.`_%!&oE t p88rprq(VxL$nN}yMbPxhweo/kR?"1 36@@Bh)9&@+4 + ̜ЎvbL.1_(A_"cZ)vhaMHf {b7Y_ƘPx} oC3|lW;Ũ(<-6mڱ|P?'e/%wAe4eǘ@l !@EpIL\&, 4d9()%f0cA d/%wQm* 2Sl>E`1 j `tvs65fj $!օJ$|5'ʎ_-Aq0Ԛ ƅ $zLPޭ8ُ,=T[QP* Qh9W셟1QN,Zo̾(x* 7LtuL $3m@5LXJBzA[0*_  Z Jp1mg=gD낇Q@9rT0eFL$x1{ίmHC]F{4d) R$la8h b4k A֢d[D [ lbpvI-z_\M7įqmSH*+]b0))R躎深*Ef]SzUy_#\#|`8b.nطڞa PH[d(:nO<-?%ϙ5A%mJaC"!~EA5eD|󧔬>WРFUv^LhLˎ0|hjD']ڟ+5ℌ̫O-jb8;B d-9"!BV/?[66e1(|j"k8`7d[C-ۗ?P,\#;Za@3d8eG>4_ #>!">25"]SK.k!  :~QrvwrY^d/b|G\(%U8zϫ̣نBe%ҝ 7{ R;iFJr ^IՎrD~*?1*vs!4"T;VST TMq;@Xx&ҽ@Xiz$"PCj+s"_xD ]3z{zX5X$^Z(z|I`~_h@\N`{A v/ ⊽p\q75#@wBwR.EyWMz7Kƕm%.bxP$7g*ϠcM @gy:U⚱J+=:㺱OL ;h ĵ_گ ی>lz'.[$Wm.jV :_\я_UW9 gn+>-3z7 Sz{ OuYx|㺧c_jOa*ܰFC+(g“EU vSk9X\ekaun(ڞƜP`D5>(W@TE u:GW:vP`Zƌj(U65l~@TsXKaLcNP@wS۽@Tk@XrǷUF֩B㪣;):*z/UD4 / 52AWvT҈ⱄgXF+:8~n^ʍ(88`Wx=j--@$kxxdoHW鏠J1'-@X*S6haCc@l%8S"} QBc$PFVT`f}A 4]aAcFU vS(P h̗( (/D5/yſobGH4%ǕZGBt~U滢u ~3bW-MzQer$3D E @jMvQu;cFe&@XE LQ]>otƌj(%ram9cN-r lQk 5|T!NsxbqUo@GBzAUr{ޠ lt~U_=~\Gwͦ we_ȶxdGӞãi++^no;:PvWdϡ&iM\*ooZu'5^ÿ@T yv+6iE)=5 _zs"P(@TE-r=/P\@_su@T˘/ n"ֺ(/DدjyU{Hb}@TkHR%|XъS|邏*Z qO-X9lGᅡjQ]/ZTFS26aҽ@TEk@XEE DFOK"0e ʾOOUqz^`+9@ ZN%c2&_ 1'۽ 1}@XIkzU D{|a oG5aytTHxstNn:ZrWEv !(=8mQ!c^OTy+1*Q~U z~DV.D |:?S|D c̹D vRȮ1GPxO| :[?#^Ho]^_oKz~Oo|>$TP>#S{㣸6Pos)]vTZ%1ߊN|\N,#]Yeg($Z[Mgo9=&g$'s)|Rn?gt[?_)sK?rQFQẟMy }{st;{f5KCV#^O{)ʐq&9?';l+p?skvA {ѩۦ=)]!m3j%ua??|nMNKb4FkWm<_~w/|.Rs 'I?f~[d/oEX936 Mqex$ud]qnB7ߥOBo bϷ}=/h[(㼹w_/>^C?R㼼?_/_p٨/?N'<7θ'}ؖc>s3G}e;_kB6npyEtUp2 ))'ڗr×K&o.{IojCov/g?(Q|ۊ>X|/8_ǟCqe}oVϓz}}^o J5緿F7xpxSS/7>5)SS_i(>?ӥ?B|E}B}D}y\V+X醣J}WnnMnGf9p"^G]Wh'u<8~ L(p@AcB@nzkX<6"8h>' #a cCx. \L@džcCQʓE]ttMLƆ.Cѡb R@*O=RD"7'WaT(ɥ\ Ane 4^ix&8px8W~. G80χ::(-%p^Xe2l~o߀8!~\nr|dPk2*x%qQᛐއS)N81n*R;TbhYc&^O1| 6nyHIڝT7V:^WӵtIٜBs /xi]ֱ@Q-q+^A@:0~S*rbso< H>eivu$QPdzcₓ^sQ̎d!?@p*ũ<ܹ'c<1+*A~o D̈,i_ƒΙ2KFYpvr8Ι:KDE* )͍)QuL)򨱔5ѷaa.jia"MTpX9ܰr.j&ÊHYRqVR vNY;& ?ojPeɀpu'<=fpP\&]}>&<׾}~X;Mm/n=)zN}¾/!N/>{+߂8yΐ'i:|&X[|! >.Fst4ݟA J[F;&/k7[ ;9%ICi9́&7*pJPn'O,X%ꝧ'xa;-G97/o$M̀M^`oI_S4T4o%dpXs2k{_>l4MCo}m]En$dxn_e]-#UF14uC(+3vʱT~M|Sa}]HXcƯ~4 ~<" r7A2Ls|:>߅w拍~^MStzG׵?ηD?5}P \lJ n:o ڗ]n[yk-cl6Q]vMъ;Lwg~e_3'U;3SuLݩC#޾bS3;DtUHr!ʛ-Rfk93>J%exxXa6mc3%z;^ܥ䉺~6I}Ÿ ^p\iX߹C6>8v~7 x%S5@oI=L4/~S7ܿ "iFW)/V2%y@`Ao17W>_3Iv· 4Bvǡm~B/9x_} |"O[4ї>˴>\?<7)eCn/~{FǯU.*=!orK8O{cHT=/L I1ZeLw4{i82Uս!ѷ!4t?DN5JZ KoQ0Рi>߲PAvT6(đoQ*FP09C9 |?zM?mrX# .*[v2QgE/b@G|zDʷS>=\^C@eMGos.uL4zFz3&53zkJ{H>?B[ٸ>k:x|ܷN#Go],7~}BEc(b1 [w|̷pk4"Z it -k4PaG *} N?ɉVQ54 E1~K+%9usXЋoYCg9^o('  +4?۩BUXc*B[xV!f2gl|ʧ:4eߌo(p1:,2ͧPG[V8& ("R4u4NP)D3lУ 4Fᦄ!( Jendh:w5ȹH } Ԥ5PaG4 `vpj4ϭiY6,;:ۘ P[<\U}SȨLe?[xkQnƁih,5D#Fr=[!E[Lk<6HDa m7NOK>{bb=2[Vf^O3iqƒSXM{Ǒ-=܇>3rG%Y }C;g01TffI6ߺVte\$oAle 344I6hTEţVhͷ LR;vNǡ 4[PB(ele42j Fjo#i$ԨE5xͷN#='X{^bEа@q6hN\}ͷNciQytɪO5J(e9*toŠ àWyͷLo~(z>iͷ'/biͷ_yCCxͷ_M3 ,doC~%$ftf-?-D{|b> U!u )iTh^+],Aپe U4HE4 Oi3Ɗ4[(N?zGЃ |$@nE?|;!AΎ1>O$zv֧_F+|DU>=yJW&(gG>MFa\.ToYCq2HT: loA(|;U(B\+$oYA@9F("ѷ|4HQc <[[ݩLcCKG 4 4[ Q8, 51(toYA XN4t?}xͷ nE4&#v-g&+])51BķF6w#|˫WoHuf(|f-+Pa\4oYC!K~ȒG@C;bB%ҷLeitw D+;j P^vPoR]Ba NY%x1B<[*.7߀Vq%WЕ,4&)ЇkHN"j(0x+"h̟T˪L)sx1򹠟kO #ݤ0k=loOWOKQ\$o\4QFu0Rε9}J TOQ5خ\/εNc5(UPJm?8&o XL+Y!x C4۩B6zUHOS $ժF9C4[-Uh nSle zBqFsi$oo4*h)lU| $*64*qx1yͷ_?|{G&|ߥ|E]xͷ LTHul\$>4o ~kBAfAm +ߝŽ (>Ooc:iͷW&)P]%&"w~a/D`El-klN !(}>QG ty[V 7'U^=19Okո\ak6߲Fr5ģ@&|4Ө Sui6߲0IJl!7F|@lQvSle**8s;AjaA@?%B53-iͷNAN %VS| )𾚆%ǀM)NaCOy*P[Qǡ Tj_ox}6k]5w0 toDBoF|j-y-J3T/F9g<[؜ƎcQ jhN*NGUh-+9CqDQȯ+$oYA& +Q}cDuTsMi$(ѾHAme2s2 XT|4ZQ85hͷ!TҰZGE"{oYA Q6߲1QP>Mv·G{Smexә lZ 㯎 B< !ǵ.bt~͎46 Tܚ_r7¤0[ 4W S- 35N56H[G@.}BE5(bOiaOv/oȷt{  з|4kXuOyQiͷS"<[ V\ g~|пΰaziD!#:xͷ]Aߑ_F1B4[XGwg`kDރ'|Ku4uh(;xrͷNccP#; Myzͷ!TҐ T'?ySLG" <[V ୂġ|\턟_:rf|džD|C:j0-5:V'}hAkekt&VS`u;X!˻RYǡ 4[V&)XE?f &"y{և^*_ hM1_͇NE9Òs9b]蕴hW_}[NbfhFOAYE?)e#)2OV匬4!Ek m.C֐Sr̹ndq)[zy=v]a71 c3m23/p[?.[͛XC53e3/81l-og!Z.XXV;JəPvn/.vh=0we_.3(]hOJ{rd۱llhdўzÒ'mzH?G.5գ|d>ar|pd^Idsnq~fEe izܐXA,*&>R|gab^Uayߵ K1w:?~<[v8osգ \a[ru.&<» V'@W23 <ƻ뇛ҕ4eqh7ZӮڿT>hMGɒCNk<ݞmg^/DZs(<9@ms8gy%a-ou'}?g·x{>337L4c1K:L<8Sd HZ澗]$D^o{舯^Ovw-eߦbGWLpDI&ˠj.]Q\9ҳ䊊{xZn5OZĀ+[oOU},fP@~,{rI:j@dQ_zIȈOc6A '|ЄUыV׬cJx3>h9jPcw R-gcQOQ;U AQc 5VP#AIy>Dr쉊2HF/c2>Og1V" ,;MF w)L7)ǀBf1[ha)Cш=d42jcJxh},lh~۪%xKU )cǥ)~h7iӋsUFꘒ BW4y Nt|ʟ;YWluc.>MŇ~hp5IRv&""}Sz ~tS?v 똎A($EM uчW~|E995W5BkS 4B744!NvI|pCkQAcTw#BI/!dZ.trR[zYԦkH#cBi%M /ZvpKAf1=/779-OQ4f;m,RS4 g31LQM%>J0h1i1&MNNcCk:AAs׷<,)iDh9hBS٪Bq71%yE>h7*4T*?@I*TB4nBQ*w0%IOg D ;(t| fWZ~S셦{'B10B.<똋FG^hts ˲d Р[P%-eI OtBScb'4T(BSq;VlcB>WQ}Ц t~䁦1w;mq[2C3uQ#2~BLe|&Em,< /м-t?ӽ*'s[.I-@ӸQB s~QwvUsA$@E lcTM rCIC|:Kּ"?45hyCc>WG^hwv|/ K1 b&Z })XAԨB LU!rAIARQ t|zAԦ E# \@ӸIJ]0W dWc6.Q3X hҠz`?qFFFuL "?5x-nƄ|ʏ| j_seLEaA43ߵ^xY03&heHcC4aJ1fAK *H9o9 \B'45j1%inh7+z  *@?Nh3]p\>f=51%ןO8YߐF_-c ]RGpBQc1%*}U~:x2z8BFux.h3N_c(h3Z#A}~vf1BE}0yhnTC f[fFFu6iNh9j1%(Nh7)PksNh!%`~p5`/͢6:3 ML%Y;I̝wոۋI`:4  iTp~fnqW3<\YԨQPcrwXfifI|@#1%*ho+/FnY),%<ʲ=,P|z \v6c Em |9s3U*sGSU,jR6)LLE!v@Qa3^\O8YܤPcͧsMQuLu 6K2f: 3i4cFx3gDMN{&w3y#Lg3B^F1ߛ;YtKǐƆieč 1C1%Uٌ_FqHgƏ=ϬWHa[}EKQ{f+jTp Yτ)"zHu$P,jSP?cȨќqǭt/c eE5(GBI߽:gC9y-[Q,hgïc6>QŇ^h2)Eoei21qA$Yߍ[>OVqA唫&TtqAQcE M w~.Sr͢6%hks1<4 Ԡ;C1(>h)$P*?A;{[ɧ<Iߐ|2h./-uçʘORb4f\ne(Nh7*TTHcJc'w2V{K£qBAۘ'ЄZFcJxTf}C y]aLC'4e[_&25#V a Nh)}:k],b=5z:6Қv#AQBLYԤ@cW"''j.hd1ڋ-ұYOq9ovFQAL_'qɪhUYqHc69TMk69wxGp9 yhgϗ3=n;䑶v]N?Zybr^RDf;.'ܖCvgݢlWs¬VgQ YCzrbq`SykDA})/bRI4kZ5+HM!炋/pTTJ$E fnj \<6|{~|y'$l8yu9 -Q8MqUZEB !sJ6|lC'޷.oOn\H0=yRvaE!P󰲁4 ;?OFw"^h?;?m1/}EW |\T^_?tHzDjF1Ol<9֣4~hFdL,r55YVg1yg>UڛrO( B_=;c?GOтJp?anM\S͢1TTr~w-sz&%ߌ?|w7snFs*A#}{X_9F/,nI tl"hҁ_X" Sr=m^ Sz<99(FH7*lM 1I!-b}2ʹHPё1aLNC F<*1B$LWY-ZR0凎JD  +h$r("Q}? ~X3 U4ڢYFA< 4LE,Z|DL$cag%i.Nޖw[~x2ꩱ/`ebDB}S~5F$boF:nld[ 96 C(cBR*&Qn ırs&J?G7e8@ĴS첕M4bdʙX&8~nSBH ߔQI,]FV9L..jQFg1́TЂ d4R; b*4bFeְF9vwanD:`ngP[ ܯ w#5ӣ<| dԡQp'DLŸ51 14ѝGF17Y)S#F9Xh4epIB(bs ֍˨?e<ʢ5QQI#/4XL#㒽TvxtzvFK c/ /@)<2 nPzqa d9C@6`D1 sn/6/vJSxh/fLRݒSvr.3 d4D#M4 Ŭmѳp*&苒$A<25v@){#aFۥ".O h@lB3 A x Blx5Rc9HsD$^ =`k1I-5̀>{%C״,jG73aC& x)z d^L d }wЄ _NQLIO_~ف;NHb|܌T3jrTfꍋۨ/w'(n+Ʉ eNb*b$TPc+8aƩ.Eq(?43&)6QB+[7xD%P]C ^%Ful+'{WQPc(Jm_n(X${ SP;c`fs x)?J>?B<n1ƚ}|H琪%"ua )xsvB%s|Bp #&9X%qhWȁi)#ə}ݍEHA(hX 4"lR1Aj IkܷJ Z\?3 jľ{F%j!i{F% z&HbQCpT-,0T+%pbQBhgSFtzn(tfM5! 0rZ>=OUF OB%@/9 4Ȋi/$BK@hug(TҠ(NC5F>YRc 4n,Js] XP_TPʑ4834*aF9(x5 4mPE 7NW"]CuLiiSpedbB0I-j) ys02G9C"A~~?@Z=-L'?Po4VA#5*iHiRB|$0w5 ӢNÄꬥƛ㯀8r9̆qF)dT̠K YF_ uBh5{i̠n90X*9iWĎw57gQIRE]kPG g1Q|rAh- \10yxc|+LZs[,Ɖ1ަ '\h_n:Z.C! 05E|G85Wޜh&ǀBkQB/f@ȼkL5SGOG}ƻ$>ˢ8ġxטWT(@$:r,zHWnpoفh+Err C]+{WQB4 2v5*iZX(ZlNCcyW7(GAˡuZaʹhL/$a#[51[MmK, Q-}9-u0)޽^!m$1d),avB(=v"iM,g1)n.Q(%LS]R>U-Wã3FFAyQ"|W5{ˢ&E(bQؚبAnKR=QIrE͐PbmBӱQIrE=Pb۱QI.j=h4 36L~R>fF$~Б} {o1h'a'!%lSd@! 1v[} ek }E}Q%<z-**$Tv(h+O@8ŶFhE]PguAo3jl}!IrߔEMPb=."hEA} t9QΧ 0 9%9cEQ/hVTh ~MuJ^<¨ZJS83}cJKħeXcQ*4{I R (q=-!:PPv |6ꩁkCtc,S 5Rد~ʟR;;cfxmGAa Q[廿S%.=ԉJX۸ϪxU*aTpTdZ{M#-H!Ml?ų?/ xl0.Bj+{ڵQI%z=J~V%,[mWUU%,]JU*5\e/TƍUʍʆ*aQ%}Rbpqg*F%]TߪV~~E%%W$*в~RoTvT 9Y*7Uk*aAJ5+* qIe*a5f>"?.4o(߫쯩K)"%SUpU򷪄5StMm{mr**8J\ظ]墱(`ϸ.w)U![?^a6!_T\֫ U \rc"}Zx'|PWwn~XlyҺ@ w~m#4nZ^,*QIvu(|{,ޢR@HX^%JHT"*e"#_t>K2/݀Eh xT5{AWϿJN+0'}{ _d}E¶QI*HKA5O$r,.QAU*>#Q.SiMQ_(DPu/HLsHXbJLJԋ e5%j$ %@"(B TH_Kl )PE+"NAg$Ep*}]AQbu(PAB-X*x58.</A›&UT˗+<( |cYŨHUǼOF|,,wRvPrixPxs\ip,Aɗk Ny|2s(2.&9 PуDT);%biW ~Po.DP]bHX0Ee:H [?Ju^H_HHDFj53 Ѫ^Ĭ =T{Eb%/IF%jv@HP)6MbVu~ AW${ \"DPK`¨ v )_'xSq㞅wJoŔˋi6^wSzP+$>$_MQU@ z:j@6tVX x8VG) EϾM x;ZQR(QX\DT HhAW$ڽDTpu-N~P)l"NǯHD€:+zwIDս^_HŽFHQ"THT (̥ <jE%^Tz^nA)-wჺWX@w/{ ?_XwJժFKH媀 U"(3u/^*M5(Loզ^DP#j~]"*5IbV% u/k;"KDOJuFKI̙oIb%*ѿذ 4zK 9-JX]qG3D$x̷WϜ x̙o #f6\mp9.<}cs $AtGܙoY|JϢ\ Rn])Cg|K<<;6nW>͖E^g|4[Pb -Db$W6c~;i-I6`"e}QbBf|J_2ߢD* փg|"p- pۚy̷2~¦y2>>#|{yD|i̷߄?%NKo֕7G?o۲G#owooV>~8y\? zErON,(?5g ^A] endstream endobj 3 0 obj 266001 endobj 32 0 obj <> stream xw\}?aw*$v)SmNl'q؉{e[*%bH;)";A${/A`fP;s1#`ù_ .g~sȹoÂozFwgo}x?\_7[U?og&ko ilT#ͻ5l5m=ݣ:kGĎ;ޓ=Ȟ` xd \wFFW Wn{k+dRkܐhmu TMCbR!m4dfߵN_Hp$ȿ?sӥw.Ih.y] R^RRm:ߋ$qCxf*7Dא/LmCd)ِqy!Vv)6wPLJC`j"KɆ2kUܹ<< 9#?}4C4d2kww!)k26w=[kȧʋmW:wv`ŽVvlƯ(㶝(JKSJ;S[vvU|l.LEYՄ]r Y7vvlYeMXN]{k6//[ZAS 'ؚJ&;cCo^u]o`DlC>>pɉf#^KmbP^ۇE󼩆|xv,wTghqZs2Yy W;IɅCCgFCMaFb*ސEi"[MׯKJ 1sKf{,=j㚴.eC>9kbڑ͉"{#[ ]Xig>/>dž֟m rrVDӐ[HC"z5j 8=Vf}⸆2kȇ˫pj7qCUr:zrόs=n˩sl-oj3uX!hּMn#WW;7Dt"ۇ|}{fd'n,*[\$n3qӽV$AC:S1x"{BW; 4D:fgVG↬W;u qC73]+JoJ[Cfhjjs,956$7}F ~dž6]j!YT![j'Ǘ!ζ?ך^aSsT;>#hMٛZ۹LW} rc E~ccCd/sdlMАXT-K[NrL][K> pg[ Y?!oGVfxEFj^Oά>{Wڊ2cCd:H.7@d67hF$#|7cCu܈{Ci2iA6gʺ7ZvW3Ɉ!H47P^.λ7VOL=2b5Dv?F2bl"W=rhA׵z>:ddI#qCd \m&2cC'vֹ}:`JU 86Dv{(wzd$֐XF!IF0|EOȎڼ[ʍ $#~Gw%nn6cؐd]]ǠcCd+{GLZ7\KYFyOg^m$#ƆȞ"#@j^- -iWﮭ06_ #zߠcCU\WpFL !#@\mj7Z7a]p cCdO!#hF!r>ix^$#͋dsб!*{Mdؐ%#DrɩKܐUu cCdϐ`"H.7RUގۇ:?dސM eMdސ{frkOܐ*Z&Ȟ逻QphbCCdWjz}jsJcC>2n5de$!5jMߵpBF$ "˪jpwdspCrn$nJcC>:5]'[B)}BFG"O qCr"mO͏ެ46D<G[/Jݫ͏ުߐDW96DVHիd2(IJ3kȵhC«twďkdPt$n,HXC!ڐ!#MhvlF2blnLYaSjW]elE2 H:7ZwpN&+#B2ܬadžyeԹHF !#-4T7Z@!*cCd/htt@n$nHIs0u2HF <2ܢ 7BF[&jHА?g,#8gBCd/$#- J4 Z7Sp;: )[{R#$#Ɔ6զ}Y_Smll6n`zIs|CʼQ6Xml?/ #$7DVL?z&16BQ1kHyK.]@,#q r`(t]a5DrD'5_`tRKF !#j JC*[C)MƆnrt@ꐫMUۀd$m/#7ӯ`ruB5I32!d{SϯZ~\2Lш_G2boȿFFHF !#~n!yGgVF "2@E2bll>cC%+#|vq !16PzhK!GgVF #16DHo16?_/Yxpfe$!"#t$#Ɔ^%#Vcl痔VF R2@E24Pzd[!gVF "#16DPؐ/-##Te2@G2bllfO <ؐQFFhXbt|e9"16Pzbg!Oά|9K"ц|Б"[BF(YglV*VF r2@C2bllI2٬]uƆ|ce22@ʈ!\EFHF !#f$!ጤ{>$`eސo:cCdo O76۫+#|gu!16D=Ɔ|w be$!dd 2@ٽƆKFHF Z2@E2blli2 :Hۧudd٪3d3+#ܷPBF(=j2@HFb eddؐIFxٚ 2Kь5oU%#2@G2blr$#m2@E2bl4@!ug[>$0`!ddؐm #T^9[F!gskߩ~P2bo/Ɉ!dҜMƆܿP2bo4p!Γi26ddؐ_m"#T$#Ɔ޾$G=ƆzS 1>#BF(IF m #D2boɈ!dcݱlHF8{5{CRKFhHF !#^K5A2fX7a2@G2blZZ!M>$x!n##T$#ƆJcCd/G2boc H!l}!dь5P2bodd$֐ьظʈ!l"#4$#q ICZ dHVF sP"۟KF8{|!s7 #2БBF(}m|CdaeސGɈ!yd ь5daeސGɈ!CdƋmƆ,<9OF82mHS!##T$#ƆJ.HۧZ"`bCdG g.(а2boddQ2@asf!o>VHF82boȒdd2@iK$#JVF YzKFhHF  [3; Yv{$+#NFHF !#_06dyDHVF YqPBF(al-dd2@iU_\Cb9IF(tKzHcCV!#T$#ƆJ}Ɔ!#tBF(IF *vt!k3ZN XCVkȺV2@cO2@i5!ζ)##Y7d92@E2bl/{C$#t$#ƆJs}Ɔ2dpFL y936$O XC6\h;WAF82bo;Ɉ!dNcC6:cCCyƆ.Twv2@C2boȦKddE2@HA![2Ɉ!dR,#l$`eސddY!H\CN$P46CFHF !#*kT6`lHqsCF(HF )imƆȚd 5KFX7P" VF )##t$#Ɔ*5ƆZgƆT3kH&16D3$:ߠ!Umdd2@7hlPhdސv2@E2bl$kHu4#dAcC: Ɉ!dRS琱!2@H!ьɈ!dk/$HF i$#T$#ƆJ!cCdd3+#4u XC|5Pv""#*cC᱆tNh # &#T$#ƆJmSCddB{ﰱ!-dd2@/dl'8$+#*f!dRG_Y26PBF(2Y`e__АBF(uF3Y +{C䟓 cCdQO !cC%+#tG Ɉ!dRwYP2boH#16$a2Y!+#q :cCddB!Cd3+#F )F\Cd2@)ȆB>$`eސ #16$2Y`ܐ0`eސ2@G2bl$06D"#5d0DFH1 gdp&06d(t}P2bo"06D6JF( ^"42BF "2@i8tu2@ʈ!V!3$XFBDh!n phDC&6Y[FC\?嫏f endstream endobj 41 0 obj 8579 endobj 42 0 obj <> stream x흋Uc cwשhrq'Bӄ2Ʉ\JSC")CIHIGҽNJIIJIs{{޵w{^ﳿ[NͮmԨu] M4iڴifnoy-onUV~Gwis]wmۻGN^#?"\2g VF5{}={){C VwWo׷;n6|(ؾM75jxE9; ׯE]|ŗ\re].q?ҥˣC~liYSK(|nsg_sIծ}'שsʩvgqƙgdzϮ[nz vqRu{GڳS㎓˿,[<3:wm7􂺧:#8j֬y1{q 'xIUvU\_F亭ޮڵknf/-_:e/noٴ֫SۯFpxA|rȡv3ޣG}~1﷋vuvb=sϽk'׿&s} wO~g3]pwc\_[\ٳׄ/e\hN7y0O>TQk8ev}?]׽zO6H]!5׽{-$[z_Rv}%]ws\?O>KC~#(sKNחnF^}š~ PNM]Is=?bmȲ\ ZDnE,{0e볉]uwY3]_]?l Iz7DOQq}ڮ;:;~.Łw}ޮORw]˵K6"O9w=pРa=\w}s]7w-zKCCxqGuMg DJ. \ݽ].zu2RJtvW_!]AE6kϠÆ J]%u$蓻~\Y_}:2ԮTqzЗ_BB]"A_]\q\?z#|{AC\O# {v=ͷ%v Z}]v\zԨ)O0Am<=z~e:Ac/[*4$rݻ@cǎLWv6 h]?LOv>Z/]r=*zE N\t=oѺ~ (\6kֵO%2+8ĉsudO~1k6 c'cӮG\OZ^@A߉ \)x3kyē]wIOL'}"3x2뱹hKDHAA_AKJ w-r\}\{}T>x% D3$m<qƓU.ye{zd5xdVG%uѺ~d/O~+zkagWd'u iFѺV\Cq- ]OuVfYbfAu< ~ol/k/5Dxrw̋'=Yy}5hg"idzrd"\ƓZYwҮ.ԓ5DO5e'i ǵgЧz氼$kЗO]!R}%w3gh~i,>"252}ēr53d}}{Gf2?ו5DxRz_ &\Ww=Cw5k:,M"k$O0ē!RZWv gj2B\f@<#}ד.]ZX02.-ӖxR#蓺.^|\q=KJǢ5Dߠ/z,M.ēx2sYZX(] + q-XCTp>[(\ eA_ k)†5DO;\ 宷!ZX("q-,XCtqݵ` QDZXOFZ$ "k'] \į!ZO Ov%A_dk,2ʵHl<EZXEZ$| 1]vr-hk5D\d!Z${ 1c}U*A^C4̵Q<x 4̠/I^C*|r%kƹ ^C4ε0:[C4εHbR15D\Į!Z' hk5D] ē$u 1@I5D]!Z;30"kF 'H5D3]d!Z` !2xҬ!25DF 'cX '1-b` !25DFHA_I/A<>FȈYd\ A#Z` !25DF̏'yנ/"#XCdA# Z-k3çl15DF"#'"#XCdk ck dk` ē#eAuIF Oz5DFL'|.k ck dĬx2;Fē <08Z =XCd$#XCdk` }` !2!2x}` !2ĻXCdA#XCdkDYZ` !2x}` ē` !2!25DFA<>FIF15DFO25DFJIF15DFO25DFA<>FIF15DF!2x!2!2!2x} 2cA"#"#'A"#XCdA#pIF15DFO2} ck` ē` ē ck d#p\35DFIF15DFO2x!25DF1׌5#'A>F}5#AA\3x} akFfA#pIF1ȌfA\3׌5#p"3F85#p\3׌ |bkF\3׌5#p\3׌5#,``^̢ endstream endobj 43 0 obj 5227 endobj 23 0 obj <> stream xw\}?aw*$v)SmNl'q؉{e[*%bH;)";A${/A`fP;s1#`ù_ .g~sȹoÂozFwgo}x?\_7[U?og&ko ilT#ͻ5l5m=ݣ:kGĎ;ޓ=Ȟ` xd \wFFW Wn{k+dRkܐhmu TMCbR!m4dfߵN_Hp$ȿ?sӥw.Ih.y] R^RRm:ߋ$qCxf*7Dא/LmCd)ِqy!Vv)6wPLJC`j"KɆ2kUܹ<< 9#?}4C4d2kww!)k26w=[kȧʋmW:wv`ŽVvlƯ(㶝(JKSJ;S[vvU|l.LEYՄ]r Y7vvlYeMXN]{k6//[ZAS 'ؚJ&;cCo^u]o`DlC>>pɉf#^KmbP^ۇE󼩆|xv,wTghqZs2Yy W;IɅCCgFCMaFb*ސEi"[MׯKJ 1sKf{,=j㚴.eC>9kbڑ͉"{#[ ]Xig>/>dž֟m rrVDӐ[HC"z5j 8=Vf}⸆2kȇ˫pj7qCUr:zrόs=n˩sl-oj3uX!hּMn#WW;7Dt"ۇ|}{fd'n,*[\$n3qӽV$AC:S1x"{BW; 4D:fgVG↬W;u qC73]+JoJ[Cfhjjs,956$7}F ~dž6]j!YT![j'Ǘ!ζ?ך^aSsT;>#hMٛZ۹LW} rc E~ccCd/sdlMАXT-K[NrL][K> pg[ Y?!oGVfxEFj^Oά>{Wڊ2cCd:H.7@d67hF$#|7cCu܈{Ci2iA6gʺ7ZvW3Ɉ!H47P^.λ7VOL=2b5Dv?F2bl"W=rhA׵z>:ddI#qCd \m&2cC'vֹ}:`JU 86Dv{(wzd$֐XF!IF0|EOȎڼ[ʍ $#~Gw%nn6cؐd]]ǠcCd+{GLZ7\KYFyOg^m$#ƆȞ"#@j^- -iWﮭ06_ #zߠcCU\WpFL !#@\mj7Z7a]p cCdO!#hF!r>ix^$#͋dsб!*{Mdؐ%#DrɩKܐUu cCdϐ`"H.7RUގۇ:?dސM eMdސ{frkOܐ*Z&Ȟ逻QphbCCdWjz}jsJcC>2n5de$!5jMߵpBF$ "˪jpwdspCrn$nJcC>:5]'[B)}BFG"O qCr"mO͏ެ46D<G[/Jݫ͏ުߐDW96DVHիd2(IJ3kȵhC«twďkdPt$n,HXC!ڐ!#MhvlF2blnLYaSjW]elE2 H:7ZwpN&+#B2ܬadžyeԹHF !#-4T7Z@!*cCd/htt@n$nHIs0u2HF <2ܢ 7BF[&jHА?g,#8gBCd/$#- J4 Z7Sp;: )[{R#$#Ɔ6զ}Y_Smll6n`zIs|CʼQ6Xml?/ #$7DVL?z&16BQ1kHyK.]@,#q r`(t]a5DrD'5_`tRKF !#j JC*[C)MƆnrt@ꐫMUۀd$m/#7ӯ`ruB5I32!d{SϯZ~\2Lш_G2boȿFFHF !#~n!yGgVF "2@E2bll>cC%+#|vq !16PzhK!GgVF #16DHo16?_/Yxpfe$!"#t$#Ɔ^%#Vcl痔VF R2@E24Pzd[!gVF "#16DPؐ/-##Te2@G2bllfO <ؐQFFhXbt|e9"16Pzbg!Oά|9K"ц|Б"[BF(YglV*VF r2@C2bllI2٬]uƆ|ce22@ʈ!\EFHF !#f$!ጤ{>$`eސo:cCdo O76۫+#|gu!16D=Ɔ|w be$!dd 2@ٽƆKFHF Z2@E2blli2 :Hۧudd٪3d3+#ܷPBF(=j2@HFb eddؐIFxٚ 2Kь5oU%#2@G2blr$#m2@E2bl4@!ug[>$0`!ddؐm #T^9[F!gskߩ~P2bo/Ɉ!dҜMƆܿP2bo4p!Γi26ddؐ_m"#T$#Ɔ޾$G=ƆzS 1>#BF(IF m #D2boɈ!dcݱlHF8{5{CRKFhHF !#^K5A2fX7a2@G2blZZ!M>$x!n##T$#ƆJcCd/G2boc H!l}!dь5P2bodd$֐ьظʈ!l"#4$#q ICZ dHVF sP"۟KF8{|!s7 #2БBF(}m|CdaeސGɈ!yd ь5daeސGɈ!CdƋmƆ,<9OF82mHS!##T$#ƆJ.HۧZ"`bCdG g.(а2boddQ2@asf!o>VHF82boȒdd2@iK$#JVF YzKFhHF  [3; Yv{$+#NFHF !#_06dyDHVF YqPBF(al-dd2@iU_\Cb9IF(tKzHcCV!#T$#ƆJ}Ɔ!#tBF(IF *vt!k3ZN XCVkȺV2@cO2@i5!ζ)##Y7d92@E2bl/{C$#t$#ƆJs}Ɔ2dpFL y936$O XC6\h;WAF82bo;Ɉ!dNcC6:cCCyƆ.Twv2@C2boȦKddE2@HA![2Ɉ!dR,#l$`eސddY!H\CN$P46CFHF !#*kT6`lHqsCF(HF )imƆȚd 5KFX7P" VF )##t$#Ɔ*5ƆZgƆT3kH&16D3$:ߠ!Umdd2@7hlPhdސv2@E2bl$kHu4#dAcC: Ɉ!dRS琱!2@H!ьɈ!dk/$HF i$#T$#ƆJ!cCdd3+#4u XC|5Pv""#*cC᱆tNh # &#T$#ƆJmSCddB{ﰱ!-dd2@/dl'8$+#*f!dRG_Y26PBF(2Y`e__АBF(uF3Y +{C䟓 cCdQO !cC%+#tG Ɉ!dRwYP2boH#16$a2Y!+#q :cCddB!Cd3+#F )F\Cd2@)ȆB>$`eސ #16$2Y`ܐ0`eސ2@G2bl$06D"#5d0DFH1 gdp&06d(t}P2bo"06D6JF( ^"42BF "2@i8tu2@ʈ!V!3$XFBDh!n phDC&6Y[FC[ endstream endobj 44 0 obj 8581 endobj 45 0 obj <> stream x흋Uc cwשhrq'Bӄ2Ʉ\JSC")CIHIGҽNJIIJIs{{޵w{^ﳿ[NͮmԨu] M4iڴifnoy-onUV~Gwis]wmۻGN^#?"\2g VF5{}={){C VwWo׷;n6|(ؾM75jxE9; ׯE]|ŗ\re].q?ҥˣC~liYSK(|nsg_sIծ}'שsʩvgqƙgdzϮ[nz vqRu{GڳS㎓˿,[<3:wm7􂺧:#8j֬y1{q 'xIUvU\_F亭ޮڵknf/-_:e/noٴ֫SۯFpxA|rȡv3ޣG}~1﷋vuvb=sϽk'׿&s} wO~g3]pwc\_[\ٳׄ/e\hN7y0O>TQk8ev}?]׽zO6H]!5׽{-$[z_Rv}%]ws\?O>KC~#(sKNחnF^}š~ PNM]Is=?bmȲ\ ZDnE,{0e볉]uwY3]_]?l Iz7DOQq}ڮ;:;~.Łw}ޮORw]˵K6"O9w=pРa=\w}s]7w-zKCCxqGuMg DJ. \ݽ].zu2RJtvW_!]AE6kϠÆ J]%u$蓻~\Y_}:2ԮTqzЗ_BB]"A_]\q\?z#|{AC\O# {v=ͷ%v Z}]v\zԨ)O0Am<=z~e:Ac/[*4$rݻ@cǎLWv6 h]?LOv>Z/]r=*zE N\t=oѺ~ (\6kֵO%2+8ĉsudO~1k6 c'cӮG\OZ^@A߉ \)x3kyē]wIOL'}"3x2뱹hKDHAA_AKJ w-r\}\{}T>x% D3$m<qƓU.ye{zd5xdVG%uѺ~d/O~+zkagWd'u iFѺV\Cq- ]OuVfYbfAu< ~ol/k/5Dxrw̋'=Yy}5hg"idzrd"\ƓZYwҮ.ԓ5DO5e'i ǵgЧz氼$kЗO]!R}%w3gh~i,>"252}ēr53d}}{Gf2?ו5DxRz_ &\Ww=Cw5k:,M"k$O0ē!RZWv gj2B\f@<#}ד.]ZX02.-ӖxR#蓺.^|\q=KJǢ5Dߠ/z,M.ēx2sYZX(] + q-XCTp>[(\ eA_ k)†5DO;\ 宷!ZX("q-,XCtqݵ` QDZXOFZ$ "k'] \į!ZO Ov%A_dk,2ʵHl<EZXEZ$| 1]vr-hk5D\d!Z${ 1c}U*A^C4̵Q<x 4̠/I^C*|r%kƹ ^C4ε0:[C4εHbR15D\Į!Z' hk5D] ē$u 1@I5D]!Z;30"kF 'H5D3]d!Z` !2xҬ!25DF 'cX '1-b` !25DFHA_I/A<>FȈYd\ A#Z` !25DF̏'yנ/"#XCdA# Z-k3çl15DF"#'"#XCdk ck dk` ē#eAuIF Oz5DFL'|.k ck dĬx2;Fē <08Z =XCd$#XCdk` }` !2!2x}` !2ĻXCdA#XCdkDYZ` !2x}` ē` !2!25DFA<>FIF15DFO25DFJIF15DFO25DFA<>FIF15DF!2x!2!2!2x} 2cA"#"#'A"#XCdA#pIF15DFO2} ck` ē` ē ck d#p\35DFIF15DFO2x!25DF1׌5#'A>F}5#AA\3x} akFfA#pIF1ȌfA\3׌5#p"3F85#p\3׌ |bkF\3׌5#p\3׌5#,`1~ endstream endobj 46 0 obj 5228 endobj 14 0 obj <> stream xw\}?aw*$v)SmNl'q؉{e[*%bH;)";A${/A`fP;s1#`ù_ .g~sȹoÂozFwgo}x?\_7[U?og&ko ilT#ͻ5l5m=ݣ:kGĎ;ޓ=Ȟ` xd \wFFW Wn{k+dRkܐhmu TMCbR!m4dfߵN_Hp$ȿ?sӥw.Ih.y] R^RRm:ߋ$qCxf*7Dא/LmCd)ِqy!Vv)6wPLJC`j"KɆ2kUܹ<< 9#?}4C4d2kww!)k26w=[kȧʋmW:wv`ŽVvlƯ(㶝(JKSJ;S[vvU|l.LEYՄ]r Y7vvlYeMXN]{k6//[ZAS 'ؚJ&;cCo^u]o`DlC>>pɉf#^KmbP^ۇE󼩆|xv,wTghqZs2Yy W;IɅCCgFCMaFb*ސEi"[MׯKJ 1sKf{,=j㚴.eC>9kbڑ͉"{#[ ]Xig>/>dž֟m rrVDӐ[HC"z5j 8=Vf}⸆2kȇ˫pj7qCUr:zrόs=n˩sl-oj3uX!hּMn#WW;7Dt"ۇ|}{fd'n,*[\$n3qӽV$AC:S1x"{BW; 4D:fgVG↬W;u qC73]+JoJ[Cfhjjs,956$7}F ~dž6]j!YT![j'Ǘ!ζ?ך^aSsT;>#hMٛZ۹LW} rc E~ccCd/sdlMАXT-K[NrL][K> pg[ Y?!oGVfxEFj^Oά>{Wڊ2cCd:H.7@d67hF$#|7cCu܈{Ci2iA6gʺ7ZvW3Ɉ!H47P^.λ7VOL=2b5Dv?F2bl"W=rhA׵z>:ddI#qCd \m&2cC'vֹ}:`JU 86Dv{(wzd$֐XF!IF0|EOȎڼ[ʍ $#~Gw%nn6cؐd]]ǠcCd+{GLZ7\KYFyOg^m$#ƆȞ"#@j^- -iWﮭ06_ #zߠcCU\WpFL !#@\mj7Z7a]p cCdO!#hF!r>ix^$#͋dsб!*{Mdؐ%#DrɩKܐUu cCdϐ`"H.7RUގۇ:?dސM eMdސ{frkOܐ*Z&Ȟ逻QphbCCdWjz}jsJcC>2n5de$!5jMߵpBF$ "˪jpwdspCrn$nJcC>:5]'[B)}BFG"O qCr"mO͏ެ46D<G[/Jݫ͏ުߐDW96DVHիd2(IJ3kȵhC«twďkdPt$n,HXC!ڐ!#MhvlF2blnLYaSjW]elE2 H:7ZwpN&+#B2ܬadžyeԹHF !#-4T7Z@!*cCd/htt@n$nHIs0u2HF <2ܢ 7BF[&jHА?g,#8gBCd/$#- J4 Z7Sp;: )[{R#$#Ɔ6զ}Y_Smll6n`zIs|CʼQ6Xml?/ #$7DVL?z&16BQ1kHyK.]@,#q r`(t]a5DrD'5_`tRKF !#j JC*[C)MƆnrt@ꐫMUۀd$m/#7ӯ`ruB5I32!d{SϯZ~\2Lш_G2boȿFFHF !#~n!yGgVF "2@E2bll>cC%+#|vq !16PzhK!GgVF #16DHo16?_/Yxpfe$!"#t$#Ɔ^%#Vcl痔VF R2@E24Pzd[!gVF "#16DPؐ/-##Te2@G2bllfO <ؐQFFhXbt|e9"16Pzbg!Oά|9K"ц|Б"[BF(YglV*VF r2@C2bllI2٬]uƆ|ce22@ʈ!\EFHF !#f$!ጤ{>$`eސo:cCdo O76۫+#|gu!16D=Ɔ|w be$!dd 2@ٽƆKFHF Z2@E2blli2 :Hۧudd٪3d3+#ܷPBF(=j2@HFb eddؐIFxٚ 2Kь5oU%#2@G2blr$#m2@E2bl4@!ug[>$0`!ddؐm #T^9[F!gskߩ~P2bo/Ɉ!dҜMƆܿP2bo4p!Γi26ddؐ_m"#T$#Ɔ޾$G=ƆzS 1>#BF(IF m #D2boɈ!dcݱlHF8{5{CRKFhHF !#^K5A2fX7a2@G2blZZ!M>$x!n##T$#ƆJcCd/G2boc H!l}!dь5P2bodd$֐ьظʈ!l"#4$#q ICZ dHVF sP"۟KF8{|!s7 #2БBF(}m|CdaeސGɈ!yd ь5daeސGɈ!CdƋmƆ,<9OF82mHS!##T$#ƆJ.HۧZ"`bCdG g.(а2boddQ2@asf!o>VHF82boȒdd2@iK$#JVF YzKFhHF  [3; Yv{$+#NFHF !#_06dyDHVF YqPBF(al-dd2@iU_\Cb9IF(tKzHcCV!#T$#ƆJ}Ɔ!#tBF(IF *vt!k3ZN XCVkȺV2@cO2@i5!ζ)##Y7d92@E2bl/{C$#t$#ƆJs}Ɔ2dpFL y936$O XC6\h;WAF82bo;Ɉ!dNcC6:cCCyƆ.Twv2@C2boȦKddE2@HA![2Ɉ!dR,#l$`eސddY!H\CN$P46CFHF !#*kT6`lHqsCF(HF )imƆȚd 5KFX7P" VF )##t$#Ɔ*5ƆZgƆT3kH&16D3$:ߠ!Umdd2@7hlPhdސv2@E2bl$kHu4#dAcC: Ɉ!dRS琱!2@H!ьɈ!dk/$HF i$#T$#ƆJ!cCdd3+#4u XC|5Pv""#*cC᱆tNh # &#T$#ƆJmSCddB{ﰱ!-dd2@/dl'8$+#*f!dRG_Y26PBF(2Y`e__АBF(uF3Y +{C䟓 cCdQO !cC%+#tG Ɉ!dRwYP2boH#16$a2Y!+#q :cCddB!Cd3+#F )F\Cd2@)ȆB>$`eސ #16$2Y`ܐ0`eސ2@G2bl$06D"#5d0DFH1 gdp&06d(t}P2bo"06D6JF( ^"42BF "2@i8tu2@ʈ!V!3$XFBDh!n phDC&6Y[FC\?嫏f endstream endobj 47 0 obj 8579 endobj 48 0 obj <> stream x흋Uc cwשhrq'Bӄ2Ʉ\JSC")CIHIGҽNJIIJIs{{޵w{^ﳿ[NͮmԨu] M4iڴifnoy-onUV~Gwis]wmۻGN^#?"\2g VF5{}={){C VwWo׷;n6|(ؾM75jxE9; ׯE]|ŗ\re].q?ҥˣC~liYSK(|nsg_sIծ}'שsʩvgqƙgdzϮ[nz vqRu{GڳS㎓˿,[<3:wm7􂺧:#8j֬y1{q 'xIUvU\_F亭ޮڵknf/-_:e/noٴ֫SۯFpxA|rȡv3ޣG}~1﷋vuvb=sϽk'׿&s} wO~g3]pwc\_[\ٳׄ/e\hN7y0O>TQk8ev}?]׽zO6H]!5׽{-$[z_Rv}%]ws\?O>KC~#(sKNחnF^}š~ PNM]Is=?bmȲ\ ZDnE,{0e볉]uwY3]_]?l Iz7DOQq}ڮ;:;~.Łw}ޮORw]˵K6"O9w=pРa=\w}s]7w-zKCCxqGuMg DJ. \ݽ].zu2RJtvW_!]AE6kϠÆ J]%u$蓻~\Y_}:2ԮTqzЗ_BB]"A_]\q\?z#|{AC\O# {v=ͷ%v Z}]v\zԨ)O0Am<=z~e:Ac/[*4$rݻ@cǎLWv6 h]?LOv>Z/]r=*zE N\t=oѺ~ (\6kֵO%2+8ĉsudO~1k6 c'cӮG\OZ^@A߉ \)x3kyē]wIOL'}"3x2뱹hKDHAA_AKJ w-r\}\{}T>x% D3$m<qƓU.ye{zd5xdVG%uѺ~d/O~+zkagWd'u iFѺV\Cq- ]OuVfYbfAu< ~ol/k/5Dxrw̋'=Yy}5hg"idzrd"\ƓZYwҮ.ԓ5DO5e'i ǵgЧz氼$kЗO]!R}%w3gh~i,>"252}ēr53d}}{Gf2?ו5DxRz_ &\Ww=Cw5k:,M"k$O0ē!RZWv gj2B\f@<#}ד.]ZX02.-ӖxR#蓺.^|\q=KJǢ5Dߠ/z,M.ēx2sYZX(] + q-XCTp>[(\ eA_ k)†5DO;\ 宷!ZX("q-,XCtqݵ` QDZXOFZ$ "k'] \į!ZO Ov%A_dk,2ʵHl<EZXEZ$| 1]vr-hk5D\d!Z${ 1c}U*A^C4̵Q<x 4̠/I^C*|r%kƹ ^C4ε0:[C4εHbR15D\Į!Z' hk5D] ē$u 1@I5D]!Z;30"kF 'H5D3]d!Z` !2xҬ!25DF 'cX '1-b` !25DFHA_I/A<>FȈYd\ A#Z` !25DF̏'yנ/"#XCdA# Z-k3çl15DF"#'"#XCdk ck dk` ē#eAuIF Oz5DFL'|.k ck dĬx2;Fē <08Z =XCd$#XCdk` }` !2!2x}` !2ĻXCdA#XCdkDYZ` !2x}` ē` !2!25DFA<>FIF15DFO25DFJIF15DFO25DFA<>FIF15DF!2x!2!2!2x} 2cA"#"#'A"#XCdA#pIF15DFO2} ck` ē` ē ck d#p\35DFIF15DFO2x!25DF1׌5#'A>F}5#AA\3x} akFfA#pIF1ȌfA\3׌5#p"3F85#p\3׌ |bkF\3׌5#p\3׌5#,``^̢ endstream endobj 49 0 obj 5227 endobj 9 0 obj <> stream x훇VXoczWS²BBwْ?3Wk3A 4ߙvRqqqqqqqq~:677766VVVGdooowww{{;577733355599iT*uMLLX?%5>>>66fƺZ5::joamlggWWWuTƎ1]еH]ӱ8ނ "MI=B,t!b]t_TGib% ꑺh.*NOO Ґf0&& ԣ*iȴKR,KuX]f.// Ґi141N0Ơk``:G3777xuuo4CaNZW}Jpwww{{ uLX` CozB EcX-h˘ J61]A=Co"1 WhXA=֡C="6&pJ¹2}ibXۡucX1rdǹRW\ƸZȠM`%YzjeLB6U`P&Twh,^_1=(`/d'e,X-u11`+ 1&'܉d`L/c20@1ކ=(S~k^edĂA>wBHoS,~Hހ(;IV%)`w e]NI^))wu|q |&XB+ aw)zs*:.b NF2"'$#1u5Go &ƈu@]Go6L>>c:7"keM=}%h:#b^n/$#0 UW|Gn/@Ѣ.v{MƺEtY?8888888aV]X endstream endobj 50 0 obj 1278 endobj 51 0 obj <> stream x[P> K$/Ar!a``2|s~|}\w޻;1-EEAiBOV+h`nGEQte$jt%sǷVlntIVJ_x RF؅tLL~d?mV@!]ml"%9TE+Y2p YY(^'B>]0MoPhըt;\_wnp*WQƲ}Ź{JJ0uJ>q\YZPUҪe3fҧ de8\3n0L-BW:|qX :ݫɷ0)O1ڢnl eg)Eyni%Yi?荳{HPc.'q4E`q r*tə՝p e:=׿6]P-ú\)7&mcC'Lijh1\,XP^ kK> stream xm@ D+)tXgVa g I$I$I$IR~K_q6Kx>bsVDVbXG@bZ;I\-γj)v6W3\p[Cl%W\sX rUrs[C+v%X,.  .b^epuڊj5.&8Q-q4ÎVFZ,Lj"VQa$I$I$Iԩ'Q endstream endobj 53 0 obj 263 endobj 54 0 obj <> stream xgTWDPpE*Cj8Ta)u8P-΀`Ea( ZCYd$ @_v_s{~%{?FAAAAAAAAAArT( 9B10X!I$bX"Ɂf@! H @BD*W ID bqfP"Cz1`d!ɠST:cÃR9\*q9#!k7Kg3(#Ğ.|>JH ewp!j%%eXoIg@{Z;%غe+HZcq$\~ ]@)$-puTRGu~Ũ@WG;o<Kګ0"}kfP-Krjr;gD-jɀJrwJ HZX!w{+S#Cc3+D-GnŲFʯ]K8@@OOp΢ʱڶpwO#u$Dm_aHWw1lq*k'|L>/ غD_WGXVڹx0@Ta }ԮXocTO+=#sk7&O;k Sc##c3KݿyƃIa (õB9aV֫wG'4⇨%n*ξwxFuvk׬Ykkqp$}bj%ϛ'ռ||xhǖMnnݷzzxULf!Ĵ*(I6Mn.{p*2xnoݾASЩh_ (ΆҼ;⣏>v0$̓!*KC?~\CYAfWϝ=pp*@gF5U=HO{M[w> /Length 58 /Filter/FlateDecode >> stream x3P0 w.C,J*T03 *Y(\.}\|@.W endstream endobj 6 0 obj <> endobj 7 0 obj <> /Length 43 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu6SH/V)2UpW endstream endobj 8 0 obj <> endobj 10 0 obj <> /Length 60 /Filter/FlateDecode >> stream x3P0 w.C,J*T03 *++$r{Z*+rW endstream endobj 11 0 obj <> endobj 12 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu64TH/V)24PpWb ) endstream endobj 13 0 obj <> endobj 15 0 obj <> /Length 58 /Filter/FlateDecode >> stream x3P0 w.C,J*T03 *Y(Yɹ\& . \V endstream endobj 16 0 obj <> endobj 17 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu64SH/V)24UpW 3 endstream endobj 18 0 obj <> endobj 19 0 obj <> /Length 58 /Filter/FlateDecode >> stream x3P0 w.C,J*T03 *I=3\.}\K|@.V endstream endobj 20 0 obj <> endobj 21 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu62PH/V)2TpW 2 endstream endobj 22 0 obj <> endobj 24 0 obj <> /Length 60 /Filter/FlateDecode >> stream x3P0 w.C,J*T03 *Y()$r{(+rV endstream endobj 25 0 obj <> endobj 26 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu62UH/V)22QpW 3 endstream endobj 27 0 obj <> endobj 28 0 obj <> /Length 58 /Filter/FlateDecode >> stream x3P0 w.C,J*T03 *+ɹ\ . \V endstream endobj 29 0 obj <> endobj 30 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu6TH/V)2PpW3 ; endstream endobj 31 0 obj <> endobj 33 0 obj <> /Length 60 /Filter/FlateDecode >> stream x3P0 w.C,J*T03 *+[($r{(+rW endstream endobj 34 0 obj <> endobj 35 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu66QH/V)26VpW 3 endstream endobj 36 0 obj <> endobj 37 0 obj <> /Length 60 /Filter/FlateDecode >> stream x3P0 w.C,J*T03 *)[XY($r{Z*+rW endstream endobj 38 0 obj <> endobj 39 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu6PH/V)26WpW5 ; endstream endobj 40 0 obj <> endobj 57 0 obj <> stream xMʒ ׯ฀ ? \R)f)]:!ݍ` w5'-":2q{Iz0ۺ{?-=ߖǺ??woΏ.o[[t2~,[>k}HSvOPN{G[sZ_H=ϏDo׏{# Է[cu?6rdb~u_L淒mu-?ϏXYŴZv+ce}, ^.uecٟa!Xܖe?cG:EW]OP~,#}舓VXȏbGƼN֕M6Hn3_кpwGeAC,GBJ\QdwXǿ'sʑ, x4vnG$c?ѵm,>8rl)+sAVm,>;/|~Uqx)cmo,|L#_đ=xgN3oQ˕GZ.9,wk,KIpIk|qLkcyL|P}NDZ|\y9-q"ڱL9o|hO4I\8%q?bx_.gtQ1cWc<+: o8">'-P~K90UÜ. 8:J#=|jqe{yIHI 4a?߉&pI7nw|D^n8LXxG -NGmQx5-o=!Cš }²d![Z_HK;ѴwNY}qƤoYO0bsOz45G9|q,8D!gZ#!>C<1=;Nvg8T|];k _/|q‹ZxE  ,R=!{Z;.Q;w(^Mqwxj[⏥!~!^|v|Gא0 fP`go0 O'N~hvS$~;ÉvqCusw<;8q/N?dxx~q8w˨LGcp[}AB|~4DsrH☙q\߷cq75+}To2hjyz,Iv'uӁXb%I>?XYE<'aP)6mߎd 'Np w^zɃ:fdṿQ2?R)mDC)ʜ}Ztnwq|>?V '2wXz!.LfOޕ}l W+n?7h T;/~Xύ&EyKO:qڙeIu,58`ݴ?K+I=k3,'}_~&өWd̪ް墟jo;d$8M%]_t(onP;|eQ2ڍH. F7D2&9``:i;=F|LdDc0cΑM '8<}d[t&OAN29OT9#/'>'gzoZH._qaLrO-rr|]e 5cYiϐ`H._ @yK]|{|ܡSF;|22Ɂ=nE۝zPܒ\M_rq6uj;-wΩ;q|V9>+d]J/!;$ |7ȁtieq3|%8]Ցjj'PKǙC}K*#C'D&CG9b|eWhЅjNѨҥUx:K{ z|²n(8c??l-ݒRLFgOc| @7dzܣrq6YB%{K쩇wgR_t)go{^ZoNlJJߌL ?g^&U8Pҿw'wz8^+O[!GlԪF(+C7YႦWt_X\ߓ]?SsQ c7:oLVPGG_?am+<qVuΌ4Ɏ #Q͏ j2~!#T&d$焊a-܉0BkD7ʄsY@2CTѐgʈE<[{6e/T.cDoQ_1Dӌ$Ǘ2H`cЯraCBB?Fen*Pwa Ѝ80[G!vkc?У|<:/_g}]1xun/TxJ zL3PIֹc-~CLSXK$[IhC.cFS­+136-C@16 I{ _4`׌ Jc4HH3Gzf׷H"'98 [߲h"#9F #cS Xoɬ£*͟91-5|$BW}DB&,vq2~7}zck}džEVL{@IP:yfynz\ӷL؁r" &D5}9"9JңwIcm#QGp/<0Xx{[>''WI6^2, 0hͷU{ !8xͷHpn$Z΄ԧI6߲~rWnaOlè:2սleSޞp>%o㧞POD5:BcBE{T 9аran5:Fq >q|ˌdw]S*&|LE|H8~v~xB 4[& C?'|{p%QgD<[x{ǣfF4[SmYmb-?vVff÷xH?H7ke#F#O POL5:BcBF-=g* <ԟxH}f0t7Ěo0 bkeFq``bF5:Fv >:q+`o!hcϵt&|.kOJ>H@lehGD|{Nog [xӅv@=Ko3Ƕid-o<~_@~OQ<[zӅ5M Y +`q>M-uΓktDJa> %/5lX^Q|Y. =xjͷQQ^1p52#9=f4[Ȏaŕ]q+co᥯;yϱ XAl}Qf` 62CTM4z8@2xͷU`\lGd%#NO]`À>6lK'| LX:|J6{Qӷ(D|R @&|(oY}<V:CX[QdES/ꛪ[Mm=k1_P3R&|W&2ڌs_xͷ!o"d##|ˌ1y΍dː3M1R(Ȩj$+`14[XqAT O M3hXM.gY T&| wR-5y_l\$xͷUb4dȰ\,Ơ6>a4`)ln׳2u}!g0to~}q6߲zw28PP>!Do H6\$yͷo/\3 4Gɱ“n7Q"^Ψ3ζ}a[ONCӄo |$=hw"ѽSn|M,xͷL@/sxÆIP+촗n&4[DsxͷȎAo+E_.adncth@0fl-D􂗽V_&BiͷW- <[&&XxW&DO6],6^2 q7S\ 4 rۀt{Ev {Ė I2޶Hs~umV28Fk|QN  *}*uVj:FbFk2 2c$d`QBW:T82vGH E ]! ,&m7pn0/j"bۨfr\a?'b'}VR{=UԹ?BU' Z [PoT >k%oUζ BB$oY~7}:BY:Oԫ M(oY_I_!z!c}Z-7'3~h~❡,U&|;EYrMo!!#qYL?԰q uT @keu+{Feb -3R̨C@xrͷ1Êw(##8Ɔ ^-3DRZC< dG`mH(r,xͷ̠P0ʎ14[WБ8kejxOH0~b-&k.o>717Z <[EҷGZ#o`t2aJ"Iǡ* P,i пYM*rM, 6ߒm}E(3'|3vWLdŢ b-3DR[˰m[ #QM6$M72f*2 .%t$H؀2CTau5vr|$B lX%4izͷИ`E;f}"8hrͷLM$#p.35:L1 &|ˌVc [ #"9TVTmNK$ojipFf4GgMRL(3*/e :EW݆hq>%ДoA4UL"uAiͷgT=<[RgERr\|]a0Biͷ/HHX1A#˓luΌ|Ƞ0|*OSlu+A]|B 62A4VC\$IQ6r.͏>4[ЦuQ34D'|KLy"Ӌ|Vu<[flQl1xͷUdl(ȨXASluVtsc@2+@uhͷ )౏rb8hͷL Mӿy֑`8CyͷmTf.ۺoQ!c ĭQI2?Ai#7,2?җT̹xfŻ-c5&QMt`^$Ƅf+=Isl'_zE[+CIm.{;`U}177zl\sqV=В9'Md'|yɛ^$t(E3j 6;|頇{=)/E)؆SNi 'ˈttXȓI~j7:os#|=oq`7uVMGL]1~j/-Z/:Zqrx夛62ق_buTLjM\mtMx=?6H;`؏/b>Frk*ˉA*okGJ){ے+;x˅ՊDZ}.4!]dQ=V,4Ha̞f;כ?]elaH [nM"SV=9ś}ڏz5c+z#d[7y_Gu:uF!K|k$W3d[+$uh+$~䓱 ꯃN4R؛wGCsEȥ.c(%thsVL?Wsuu9^c!7?5p\r;Sr<|8 ]__xOϺX|\.gTIT^9$#ʹ~V︜*[̩\!l?xYԪnK!g3"%0&F[+뜒B3}rN9.g7Srپr&Ύ"p"8#f ڜ 3 izR­^zY.B?"˜OUC347s.fu1,umOͤGP6'hb5"2^##'61'sBm&XH؋qʐeYX/UÙ|Zw_.+쎰!̺䳜"﮹l\gj'Ng4GqZ.4E=9I,m Vt],:-x)̢FxwT g3-@g7$; |KeÙčSJfAhTtkIs:>S%g*93 FC J[>g0gП3U=7k dJJZ4'")oj9+),YHN7+ڜUO9Y{|n[4\o8Y! 9ƊTw\tl'f5*ҜUs=DUj˖E*w{%@˙ 9!ߛB=DSq* [~pf`%FI!gi9"iI=$g% uwʇfؕ M ,}o&qa0^!BƔ ̢&¸ykHHs\,t8]ClSZ5Fq&nQ݆[qf ڒA>ឌ|pfQ~2M-2B3yMGz}:>g1ޮl],^ҧt~G&%sTBqf1A-Qt\z .g7wz_ԂTpB\U?8А\fvrfAn.7\,lddsF.7\,rb}qzg-jD_',B3| Bw3tB7na } s6^Y]g^9ьfE[HʵfshZ㎡6JZ w3㞠X\oYȋ\{w$$GoFBRY Zl_G8KV,lbE  IDU?7A뜌Sc3q:eLbF٧Y3&$iNϙEmNj"'= njdI|:ȑ1UBtfq^qnj!gfәō ݧsBs&f;Y:g_qg\8{U*RѱLxw3i 󜇥‘*Er Ջ'bW3;F[͒p5^AFF:R 1vڥ)TBlq#a3~CXJ.["7[5b9)6Eo=@wr & $TY@_9ĄBoQ[Ζ-KbP.&f5mC3f[}LAH@;g*k3hq`WncM Vv{e=R}q#ԕJg˄ &(uN窄 6B'F0iެ䮗Wd0SQ fo"}So1}}'O>U},h$iŧ)ǙLTԂ1~t|J,f$lH蘎Rcw3~ ;m`:.SsP ,jcfa9!1B3iQL 2Ftƽ yNɶ};YHM-K9ng713cSr#;OsEg5:ʜfO<ΨGcۀ~of1#bIzpfqCg9220|J=,n"P/[Թ@b` !v8]3UµÙ|TNloњ*7pA}J|Y7Αm,B3ZG8f3[CBBB{)7ni:KÙ|9FA:g[Yrfc_6YR|J=,n$$%H|LeǙ}0&?wTC3Wos:>S%f;j-c:fs_t0OHS 4f1g3 8Os..M=bo3Q^%J0Bw3뜔 w3tu9%vEmf}C-ǖY*,%ף,VRF%c'f>tZ]sLz;s }ͤ+8 Q DWn!5^AWG"&})}:]3 29zYĠr\2!Òrqf##CnP}q&ynFƊ &XB],n du1B3 {'Bg*L|+#!~n&1>w{iNT٬pĨ_Q)v5-z{-Lp51'sBjfqcZ Y+ %f;Yؐ}J>W%f7.w>mNeYg70P|J],n"н/*Y>D˜Uϙ &ҡǙKǗMX&>E%g OQ3"Enɒio Lgwu9!DSt_>ݑBrJV8Y cEF)TBof=C%~3'bw3:rr7t2 }0>3LASBnvEHؐPbBp&QnusBf3gGxf"'ۢwG,7gBme87!ϽUFrf#-zK{:71B3_|B+~9~d O!g5V$9!g71-! :'s D#m=*\x|_؍G!۞1c?;RXL%c9QzyPmohRv*><҆xdFLAhWba36cK=F,lx(KOR{BK|ϝߜǖ碐 XU`,yL?H_ir\odKJ=wUF}JFlDR>SFuQB[/DKj%cG0SkJGY[dP?թٱm|'㙼2v+x"Z+_Z^ͬ˞lRAȞ%siǶlsW2O62 _j핅ꄘY>ZM^Et/ +Z"[H.myY5> Ee|y5&y&T*u|eD}NVkly6E_.%S+_56 E^2Ա굊8MA%sڿ*o]d=i乹m{=diNh\L^B9^I>@~Kc~itcVK*D'5Jqzg u8jԁuDAŜ|j)Ml#{Svtq]>VtYӍ43{gP!,v5!SZR\ o"$mH<\$tbԜPEB El~d?uX143'  EN zu._teҬqjdD(zf_3*#T2UbE]\1$%BG%tsB 04i&CoYӧ#ƶLI$w"q)}PÈF2E7KG:2Ud$` aeE"4@irBO,Ly#0zp8vw~%~~RٶziTq |˅mHLWɞW q~2eD:Dh@`m*B E^u;vU2222c`V*1be֭FD-&2l]P1)vЈ ڧ#q[gBC+tBN?[?fCb jLdiq(z}Gm:bg#ejV}*+ڌHW?2i97YuƹH+Ua3@.94gC;\6%qURyav^%ddǨȸ6 }TA!:p>oِdp2A4/jGs(T?tPw.-L?3CY>|ѲCYA+l( Zl|(Iph+&:Mo{O R" eƹ]8vd91 2"/u;:]CB+ mNMb3S%F]خ#À.eVg 3Ge ׼yfD苺~a>!i&򓸗T:K=>FH1> ͣ0]%ꢎw"Pg5 -,>-3'"tM4>كC8[lC˵P> If[9o绺itM.uǽ6Cpw|LiQW>a #m3UbEvϵIX>eHhJB-f ^n-&hZgLB 8 +â:AQ]64KN uaBzə&"Nz `>!^rI}'=2^`qhglD2ɠm_`Igq2P4|.*[- xPF̞Ot\4$GV%(mC1I(c8s{j'N9jymG$'qhgȆ(^؊ýe'-BQ +=3ˎp b{ neY<3ǣCBEBCvlH250j@C=tw ("ea+cN{J z"#IX퉪01ƻr:.P̆2&E, qV`q!63M$:1`gԅf"Z_#׿IkYm@ha%<!̈́6pcD;=Vg ƧIzf94p.$zfc{TϬcsb9Mu@vxY B(VkB1 b1K'Bg=3"#!crX{nB@#KC#qzY-ʀ9O aTgl Np`"c6`5 $A>sC|h A8}ahb~QPvE2ۢ& bɘU㵑H'WB=ignLQFFEsRȎCKEU%F^ԛ3RX>eSBU#w@ 6geQNy|׌ge[E=>p;94JHp ;0!!.L[SJwiOlE=$- !J5 GR$c_R(zƠt$T8D&?_TmR_~<"Y)G}!B#B6BAOGDmUrB(B@* XRX2EL;1og- lzY1kKW<=IBPU^zb0Bc+ח>nH2,g18qg#"dh,o8š*17b1Ƶ'He fnņBt> sYS%xV:!.Kuϙ?1UaЋ0fncxl0kq_.|!P++V5pS|zEZL*vMҧcܮ[:>ջWC'KH$Aƹ4$4B^mf*7q(!Mӯ/- lHVIz"$'Iފ-(,>VUs[#5Ubwog 2ch,2^ m 4k$rׂ#BFB5Z&8f;sh/tהHwIxSfeC^9n=0{~G-{-f"4$ۃ8+XxMI^$zLq2v BhlH(Hf `S=69Tq>npܨf[@`f%D?C].¦HT[6|JnN~Enc[AmШ@[NpghF̚JU|C.6$τ!#6M" 5M|Eb-PC|%@MB,@GEbyXT`f[ml#yWS tZ˦$D֎>G5Epjl,Ύ&Ō[~hl1cn{Mzߒy{,˧7_Cɮq(!tX͡?2O9! P]]&BCxHfCgjb:hllHˢMF'_llĠo[ȨU`,dgꢶPHíbۗBiVŭ TArE=byTArE]{|:;F cd P5}Jjh&m!a3BsJp>!%VҦIػ NON&JQqc`hoi ӯeR桏6 яE/_Q{!c5yH^$D/V'ϲxEɋAy&&tBJ7E)(˵^Ηba<i1rKya؎ W,+<2~Rռ Tׯ<, v\+ԡCc:> ~q`ofVͮݵ~ t7݌eeI0buhѷWbY#8*O)i%dS9+V.)a)IyQrަS%E?i)5ĵS(a=P J\LRKjψ aYmӽ4Bi(aUSZHkcϔ__ErŭM7'sJ֦ +%R=S_M)PU5%.0m1eBBquPpT *ה=JX٢*%͔'ŞM2ybrq1LxNWi w a;Եqa>Ậ zNW:,<3W {5+%|I ]oPNO#ܞPnP"R_%.xGD[A;~UnD5WAQbD>!_GT]FKDy;©"Q^"V= D^#%"@5OA;WE4T:# j81DUJ(Umm|O䣲UAUY~=S@T4/ AMkDDlQIOP=_`ſ oD58U3.AX|d3VY|xP(S[W)Yԃ>qqHe˷┳||PJ~xXR.YZ>AHX#ԍtE'kWAG/N:~G>(=[aeFP@ EΈ4W9";WUg􃲊 5QUEP 5Fl!>G _A5"8#-DP7"BzU |Y+[DD'"(A8#_@UAk|BDu[ ^ b[0u]K+vT7a>UDΈr,u!{3b ~ QٽkD`s%j3}LQټj(Gu@eޮ׳U;RP=(K դ2N+{܄2e-9TyXCxPJN턂xTP|Xz!]_nzSp5`  M0!*}M>A$@YK2'y;>Fl_b O(u̼xxPkZ<]&-?ɷY>9|&op;MZ،GD@.\A߈|]#KD{|@ D"__Gկ!F$_ADŵ~'"/HJl͈|h!X_G D,u/ D@`=FVX TDpatFe#AkD"C/bQ}z#B+-ogW9gN[zB]ϟ70z iK]y=m(.䷧4s[o_g|{8͘vG҇F p?K|o mk2޸|o'q*ط@yv6P};u3f͙M#5W/i̷O~.$Eɕg|Kxt@f7P͞|K6#Β'@;uϣ)ϑ|BqES~!yͷ_Oũ7m4oۓx8Ϙ$~-<͖iJPBNi<[/"lAe@2߆;--!ʷ匠2"bBEܶLi<[o!j"@lo/--!2߆W O~;Oe"}q2"5"4[[D+D~Ȉ2߾!x̷_D5f|{ؾ2fي og}nHv֧2~#x̷(1b4[o!e@1 i-!Dq+}L?/-_e?t߶VY/I{{~??ѴaV~4:-zۘV806Oko%k';=}_?To{, c~JM1 GGg$_"eOOr ɧOG $[ǙTND(pc=˺"t<e=q%7 4\x]e aG3ōޏüicx908ߡ#vBY\~ѣFXLiqve?j Ǟ_l2=dNm\OpLa@d+XmrizGQױrDvTXؖ}jc},l˟K#XEY8n}QSiz!5PGnG\GkB<Ҹ@~.nR'cr{q v(I;{5Qs*ʸЕV=nA+jzH>z~|3v<.~lH#-GtG#&*FR\0ʜѯcp7 ;z܏GXZo"KɶR}DZV8'86>>2=?Zu]ǁ)#Yr-Z,PJ^|PO&vaGsss''K_nOGVQF_˙Fct#a [8nMO[9~QVmcs]yp8yϡ;PrT d,*m9qxR9YB3%Ok˳4u~{| Jc Jw7u u1_I}$,~&*>VTq2.<5i@Fqh3z>V"qz]S%x>!kZ1>9]h;CwW&tRc7q7=ZWji% Hz y<Ȅk 2N+٦otkc~:`f<2'Ӎ^tkPS2 bp}yU 7T)nL* {P[:[pl86T쎂RηyE(x1׵@'pso[<1ȃn<]lQ;S~-/U+x ڼ' r*@ ^Zv~R@k(j.WW8=_$pvgaqIq}QBj.1_ώY_m;LgEj;PvGpJK1,yqu^}^]W J͸\9S/ƒb͍%͍%OsLK"/#ǔƔs])ܚaa. r +~1EA2^kQvwILQ]wG;a]ֻ_NO]>0gwTt0. \f*tv,n8R;xnw5=L3}:}\r#@e^_f3MӤ\[Pb"AS }̅cs'FRu'w+ϡ$&/213/|~!ȋJ7{ [ ǷjaR*~dUMxC!l V3̲ˬ4>wLnB4MEo}mcYn&&KkqL&OY[ Su۠ɍ96oip;ߋ0.U3^[zXпM8Ywx{>#8qpt@F&/zr)=]vNS].y<;.7 (-6xOQcccJ|Ԍ኎#i?v{tba;c줱VjUkAM$w>xKAnk;δqLJ[[Mɷ)w";MrlUx hÝ«}t;lO+Ė t/(,x`XaYegǕŸAundi7Dz5Y>.*+r;$hE X4vrOvȎzF{r_iп5U{BГ>E;~IE[ӧC4Uܸ1n_d.kANP$.+<):htݴITqg9`yOmDC\pqxN.Y=N]~ն²ck7zbS̝qD'~F|^(-ڈ]Ɲ}~fC˟+_er{ D"V=?p|W%>2~ZcroA> #^ Gl蜒>E֋6H8]nˤ:"]U _Il<|~Ȳ)u 407UO*[(ko/Lf | 7M$3 |OI7֧S) "8}x{ǀ|(U}uMǠoIzT-ոL'F!ovh"!]lE(#%cCx~} QEFeȖb1lclH<83ecddTdH'-3DHHsJ>%Н "ng9heq]lX\_7'.dԱ2=8A >ێzq>&t.`[GhLhc^~C}^[xV»GO |kzB\ >xnyC TL/L3%I+1hMH:|JϰaCroG:LTj7~ek+H."WLS2,v?[x&Vd ! H` O?:rK qJÆEО9zG^.⧤}ISx} Q%Fk 3GzطO6>x4oY8a>O%u 昬~v} ~%wlmX킑^2ڙA1<6|B~lX^I~kO!8=[]'[Q2a+\ua>!aQ:jO>oѾH+;I&7 ڋ$>Q.yl<[I3E `-3Dlq>!o*ɖ/hrͷL wgZ#TG(H3{| Q%='|XAkuf4[|d\];E0@$9 e@ pSlu튱bdI629=Dѫ #QMV$~(L$oYH7)GaNSle6lЧI6߂ʃ+7J:|Bi63+{o05 0Biͷz%:Ox)xeg[G/A3egOJ2xbͷH6],Ơ5:Ff= F13Ţ .*kV\ 5^2 2?L.} Q+V9Z.aT`cL|W6zjTb-#г|莡Z4[dĄmaϓle}$=3)Oq51q(&|DBSDbu^;aJ%df<#դi5T|+E(pN6F 63io)!!aš4P?~aW<[~G4@ZR,g¹H/6l .1 ־d$d{5| Q%=ռ"#@1hͷ"cgfBvxͷ F)9p.[͂'|8Uiͷ/]<"xͷUd Fw 4KFCxxl@_ذ<=VM^BiͷP^wyc+OF};M?1zВ TM ol{Wq0[rMM$H3E"Y6:m:^-!j62asd2Dӌm@mEo4%lHBoܡIzNMPeGHt?TodTM 2O15R8ayDy֤wA\$xͷQ##!;Ll=T!B+;mH@n}P=,Ч 7߲(kVx L^5B<[&&&~V?8vc }C>x-cXf}z]#0GoMoLiͷ־([<'u l-3Djy8g6,/(O֭|*Nlϳ~}@ؾeh޿镛>\$2O1cdd4dt(Ƞi628e/9F93hͷcFr*| Q%Fk| eXAme"cEFah,)7^21ҙPf¢ ˋ ɏCFo%O!8MAf A]JEwC*> %pS׆uN F];9ǘ̿ <0 UЀts$-yڟ%m 7T$>'Z&&${p.=zk0#8IK2#9Fkt^*2c3K]1r̨sR._cHAJl!(c0zC@2dkcs.8jQGlQ"^h3  DHVa\  Eζ BBc9DW4E>ی-L| w_Q}Vv ]B$NcNE{YgMZU+ Z?5eէ8TWES/$1 ߤDHÖYS2,JO$\12꜒VRεUbE+(P Mv],qu%\0`돁O&db g D(fCiͷH`}X;@|+Sum6OSk}~WK  +6 wOS+e9FM#QM ~@keDMn*{SyjͷN:bݣ|Oje}Q$} 荊3O {L؀p[5!ʎ$^c.T uNGd O) q>O=>MUTGc%QCOv\$6"m,`-6G;ɖZ tY[fb#W:DghOuPJXo!İ챰 H@ka <[&&hp_U-~| />^6иiX֪zQC 4$(Q%do@5!!1A}hW~ukkk sh//[lP_֙[|V(Jq>!To Hڡ_eG4K}}f-K1A p 4lX^Q>|3y,۷@#}\}!j uNmuS}*`$oI_5hyƹH4i6:ʌK QyͷCjxP}ReG"h-Hg%!1AP}d-[+Z㩯ReǗ_0 3 M1:3x>*uH@Sleh"e#XB 6^L(%@keh*waRdEzfw|h<A/TsI8t,3&m =-iQmi\%D&M8.V2{>{@\͢O+̶8O#6VhqCղbY֧C[}J^ʆ^K<Iu0f}̲ӭ8y4ofi?W/bfVl'6m8iֲ9p!UYŶ6lRp_zvitqA<5+h5#a]BS4y˞\Xht鶲v C\O/Qbs3g]aq`(M7>O>W &E14#sG"'Έ <83+r .D]OQ*1CJ7iUsנͤ=V(%:Zw=ǮcݰT|?C/O. I;gw=cy|.y_C5w gO V6v\/%iUFa6>LC6>wpqvA:Ud'td߯;.h*<ŬF r69c3 fIE/ӔP02}\|f ]Bؓ:D? b3"l "Ծ4gF2V@ä"'FZh/*zek3 QDU9YD8.Pu@,ZpRč<EMuL !v?P2}͢&F[G'3Bfq/W\,j ~*!t?O@P#b9!364Y0W,j$4$9!Y]Y.B?(9ʇgt@Xl|JHS xԅ&o\:?=Q}3,G%Y~{&X)V 4}2 B3 ~(̢&Iثʐg1:2ʜnO7!9%Oտv>nAypѯ u%jw rX: nc)h7b*!? u1E^LSb3 e Kgk4hr+7wxg0_X_ORlvFAFw Vw-I$`_Q͹`:n>9ESn-CۍeNP|&Q#;sB/"%մA9 h+2*26dd,rbEl{w%UFf##cNg&B1*!@OgGX}:g3_Vn)RC3f\_ '!v>>!B[f=915\Or>NAy;Rh`OMMVz&F_29%1B߳/R]HH3A{*>#pd#XB B3tvw9:z>h3x ͢V@D=K]Bo$I%U 3].7,rbE ? PJjoYg+̂&qYz_?q~fA#cCF-t?ȉAwɰEPr)lYH_t|:Y̤O K)vx 2}LFBGB aIf9O_@]'g3Dt\G=uN?k4 }Ѻtk|fA#!9YĠgqK窄 mNek6bruEKJyqL,'4 ;ʗ9ʇ>h㳤wO".´c3TT U?> }(|G9jOϮVg$s:p>KJwxgN窄hf-ˢO,nbE$c8~{g7PbBRrB|&]Aș c6uR}&A/%MU,foy zYDnl4c+<P2EMdIt|J,j$8=f&=\:fEmNk"'xeDre6B@25 ?M/ZSw򊳄l @M;,'89,O!h;˳mNTK3 3s&3 >oF\>7dVoA cEF Bzq!!/{f)lY-=Oc$C:[#>ȉAo9)9EgiGhHsJ &VӜT~;6@TSjz7™>!  |:'E?t@SE9MD1n-MB1#a=4ϮQGh2M 95Q=B4 `C^UDhHb3t!! \_AȨؐQ##?SEgM^:g+ 6Be>SՏ4~5zz gt|)Fw ꗎg.+mQ;&6#qHQ#3_L|B}Xe}>$aBƍ<~{Q#~_HRYs hP mǥj &U"#9L(>h92܅m0!Gh՗O$,L })os:>KՏ Qdp Џ b҇RTJ 0k3eN zU@Qh92{+ۚ>hnENtxqR~۲Bfq# UnsپrA @%<Ǣ$OSHO"&PG$CX*>G=,bB(՞8I̤Ocm[7hzy~&ޮ+wtF="U`:h.J7s& g(fG3C z:ۜFs' DUwM7L zz sJG:YDbX{Rrj5cEF)TBfqaT:$ˬngb~Lw guq̋@qv b3 lрS EMml!Pv .UK!t@Ogؐcϱ EN}ћڣt' B4_|B],@%́S \+M6yNTM"|;Z{f)D9RC3tב;YyLêF@OTC3 z{g726dtUL>aEBS­=FY_U=XM0WݎIXDJes g'/qz|f1aܬq}j[:>O%g OB~&rKYnc r1yL*vncYh7P \p6Ӎ.<4˜&A#9%Qя,j$p! As}>e[B|B,A_YI+2c73 |0gr 3UpĨL=aefۘ~yfa[>6(N@},ndhsJ.[eg91N6yw`*!t>(sJ.["t?@Ҹ!0Wя,j$4$9!Yc9!4 ɯs6>Q],d"Eoei$U?t@Q?>WX:>O&Wя,j/>u&xg37VM˭\,hh_>Mz[~|f>ScmȖ9v=>БC;YD{v㋌0!9(HێjEeۗ_(rba#CK_'s??蝮?vʯ_/F_/Hb2"Yr5KK:xr.$6,a!h6gI >SDZ9.ؘ/fy4Ah#|1 WϝpсR'h FoʻHL}K+gefEdXm.yPUR)xˋ/T׶GVɳ!+V;ck"Q*!R6|lC'>pi䅿]K||؃ccU ރ&[ު|666\f'8ɿKO.3;.F=NEؔ> k˴Vl+*e<#"#k8وlɓM WS ǘZk9yS$)E2˴1DqG/[xc/*eB_ ӌ8qPOqF)qvPѺ{M2i騆j 51|mr*Xu>+|[;Fs2滤zqnTO_xadDm3fEBO PhuBhb!O{(<9D%KB6\@ Ly;"MAl팶_ݪz2"v*>XHgߎD?2CXv}T>OF_3Jҹqkd4F4s_gmOLLdx4.8PfZJL~iȎ-Ԝ@Y:7Vle8FVFK\Bg.Q(g6qw,rdpлk() : 5߰O1Ǎq| ɷܠԷ|*Z|&ADRǡ}-1ZDб% ERU'|Ga:iWSGcdTL/u*3G,1O@`ؕ8֤ETvKb&†{W\fY(fV ۔bt7{-$7Ly1S1ɩ {bN_c5cƜV _MN=.̊2dh8$황",!ĦgҎ@cxD$~A)D&.yNV|B|LO!x6э P64I$͊ YhF`t&l9yiBlW 9>F2ʌOF\*KvlV}fDH: G4=LH-vp~.q 46M?ûn[=o8T?3M"н~AمFp5]o gPC!gUYxȨH3%eYTq6/MN&OH;˙&E|؂kB>+2B&⣈=[p_>VWԷD1݂"K*m"U^yАC3g;$}an0~b8C;B6D~!S̼AnA^v }q+c<3ɓȑQfmS獸: 5'@ 6tܻfsewD/ENvfwEƢ W'@C;f(!{e1)63M"싘T}yF^C6h,C:=fϑ6lم1[Ѐ٨ =7'O4!!/Pp<6ǠG#2 tqZT/}*1J XBxb!( -Zr._tНeA\IFh~ IqЧ^5qa;P>9 8Lz͊> 324$9w(҂W'V}AOIy|/8)a2ND~}*3?DQ5BCBFBqQ4(zq~셸/J)-IaHf;ls.3mT4I#vp[g ":;FVG鉵jσSB>|!Z3&n )>\BħQT1p&Qy}Hĥq|t jHΖ I-j)YW<1{lό2q%rdh|z0V OE֡T=!ʔ@&;[=#wox8@E#H4}.FM3 P1R@G ;6$mQwQz-a=TMOXe:Ll'!j"$$P݄>\fO*1"k+""Eg2{FW a29WB!8kJP%F] *#s],ٲ) E O@zTt'%ddǨȈL0!rbtc8v2dVٜ󺌜4Aީ3 PB H؀0|Bx+b.m!q5p M9MQ8X*l9EeN;  skVS\ ̶>B2Y,iĐ|pm)qX3O7Ǩ!8R,p% ],%2۬[cjĠW"32Vdl*1]b14cf1˽L_suԠ:-x!qI__GT?O?$Dm">uP+>-U`n7:-خT* p[*RfƠYi嬵"%7Hv5t >AUE:j2ʟ8*1.,bbMIh[+}P:!hhjcJ LN5w9B UDŠ>\$) z+J'^REb,6mJԁ~E{"[\(f]ԏ`> 辘@^aM/Rdj@*z|Ca|hPFB^e8c[W9P?> Iެ-ý kH![{?H83gkwX$0uc b^"E,S&nɬcTC цL0=]b5o` m6@Mf%j_",jgˆ$ChB.i:vvU+d0ZĠanp>[%"B0[6#zߘGIiz1s PBhy+B}.Qp781L1Y${o#867AC\Pz_6$~IQ€$ gM!J͚2OMwEMXݺ0-wM }C\$:r,tהHޯm[b]M2Ä=[;]k!"#!#;@NJ z69ch,o8*2c_GcNBfV?mr.OIC E%0FafP]G! 4 \\u[J.d!1FĶя4I8TO!J=vER`O&B(TA&pP<F$DoreQ["Tu@:GvĢzɨZ!2FlIlĠm+22c*15XulB9r4wxf+__#t9U8A{[H9"#a˦$Dp2"vF@cd4=?EK껪g]@Z>ic 1Xϊ5OEsV$Eq~lHhHHbk) +^Է UPOخT=PCc1Fh<3یmN6TZC! MQ(ЬqgmD(|ꚑ/BhS%S0%C#f2VR@C#i N:0mM-=z.&Jc BJ9 BZ! |y<@ga,ʈME"QkKj'~7d%䴨MiaBh=vL/BǴ;\*1bo<蔑-+ǵ#/b21Qq b,τR^,5 Xۭ@ZdPDzOOS׎.TU?Xn h u|ĕܥqbүtrd]us#ȃY2,KM*G{ꏝjSq} dW N+=nk?Vy, Bak~k\%M(,6ݘ.)L +nBJ\w9V߾KFfFul$zϡ<~R2[4B_׹~W=\_oZצJ5 <ǥMrߡ7)qzA)1%6J}AM_SQŠӦK|AO(X=.mWOX)5՞B)/(A "|MIߣx%J)O7Ϸ')-B/(q噂fL /nLeS(ץKDX>yW?'2tA9Me({-߿*@Q]$ >5uA3l'~PKEEu"DTw"3DP7"2 q1A[P *"*cuD Whg-X$Ъf O0cxT9k9zMo껪e*/_GXA3pa-_"JꨂĈ|BDT۷A5UP}(g"]CAIwMDPuF :z1"AkDD)#`+>:#ʏ~j;!qU;Z_%(D3⟿T b@}qUw;=GD;A@\u_ _?62T_c+>bWűdTŽ% w/X1UX>L)X)L:*<9KU9{W:8n\_07~Q<ƻF5\,8#_@UAl!zz~{AAƯ sDT qUOq֯A?(!"]!V0uD A5DT +B/tx6@TP5OT*_T@PWK5|T<( |-=A+U4qK,'W RqZ(,X;A.-DX TDptF#AkDTm TCD=/kD͈D5D\U og5"]"sDT TxӌX/=ϛ1а~ iKϛ6DKAfED=F`127'~y3@$gq7x_H&Nf515J/P}csh`z̙o3| q'ϟ63<͡/JV9ʂ+Ϥ{$>4%h Iܖiͷ(H/P|K$sg}O3߾3N V9zPKf|{G̙o ! 4͜[-B̙oh/4s D 9mؿ3| Q9-"+D]s;@$sg"/" ͡1},ϣ+yr?u#۲_v?N+zo폿uoѮ}oc={@v^6Ȕv<3?~}oSwk$U\Ḧ'󽌥 ;Fʥ/6H(م8#[뇪|<{%Myw~Cy'ÆR=W㑆c˯||x̶XXJr|x6XcXʺcc?,KtVOi,M)Lr{Xcy~u0*/ƾ:\XKv,-txS׎C>rScy:F5#ıֱR>}Ho%~de_˫fOKv냏v7GT8k#/fc)úˏHZ2se+,Q5q8K~yy,Ϗzެ#:?DG׶`y{ucort<㘩ػX8>Zf>q̟k/Ed^=ˍ5L3U#NYJjqaku^n֛4rZxԓw~><+ڳ$q hGQ8xܬc4=Ӫc859vyiKrǔ4{1ѻu\ZF#οjDZCkd@cܱxJc-ĥZDldTdwϱ)LO>%3ggC#HBky ey^Ae>V~~Ub|ʯ=՗ٓ;WЯNq׮=.rXϘ6*kOyh7iMAk^n]-ޡ@}슪_Rv//~SiW)y>:7w4=5NLȥw͛Ak^~ÈaDnvwӈ VۀÀ$$ϳ<co~ZߖɝCCrMϝi@]Qx|v )S}9ttH(=Nk>jwӶ1AkyI>}ʯ]+2i$?H1.腴[tQe@>.Ә RՓ$hv-/>\%d-J(竄Yڙ ]$ЧSPog\J ]$wP /CSk}y)g2'_4j˄rL'`.K ]'wP tw^p|}9ڠk @ϯv:w^p|mpgю@]ЧQyYA>8(Gyv>AqW)\H{zu/_+[lgRS~/ϺAݝW^Q7YN=^A=_n6TwuPA=_KkpuP꠺@i+\T8⠺z88sCA=_+AAuW]I;tVo=ꀟᝋ:$T8⠺z8HC+hc_dlOoįM_sc/Fю :tˋ^qdT=F|{;9c[zM~1x4lHrϩ#<"Z$#9&-_rYwK ~kd,%?Mڴu?>h]+*c}v},#rS /ӌe5cٶʳt5qaIeu"<6BCx;EȝjlDkߚf'ݤh |}o.ӵvhfw&%O=?p>p12Q-It7˕Ͽcw@tOzpeѢ5[\._x숨X.r;FwjwiieZ4n퇋tzApu:Gx@z Op4jwA87$ZtQGY/)Cz^K"!]P_ H.|lhe G6*ˑ~RIޭ&GL|<17XuȼeaZ5&??K拺-τٸ5f|)-2c> kU+n? 阨~r奦o!|) 7{A.N?9Cy.2pa%Si~׷R%;J;g+-,'ܸ/{(x ϷLi)4[G>@7ce,-Dt׽*!QBiηN:}yZ/ 4y[&@NC}WI TO1 0c35M]91~ϱ9g""->csFB}R.1Әng9Fo"3nBg&ƣ󭣬3֙_Ȝ1Vd$o#C^e?1ce$o*L|@xeC^%U^24˃&| OGilgt0'R| Q뫞ztgk2xηQ/ Qh"Ϸ/)m3J-SDސz[L(4[.RKJw(4KJs}3“{ee<hzϷH`}*a O{;p. #^)+>atX眮4[f}-+zH{u]{7Q&H*&3 Pq--H(Iun)=:Ja ZPФo9JrzཝQxZϷ%9Ju(8Ԟoăp§PΙa1警v&VW| #4 d$дo?eayQT;hOoI1|)E{wKv?x{e1ҙJA __.I=߲~cTj] !HWaV1V؀X>k"?"ͪ\w`b]2c-9FFs ZfH!sX!U9 csN ՟ZI~LX -ŠK}XmL[BC2o O/+yKTH+Pb R5v׸3bQĒJ4ֺc6`ڲt-SP(LҎX)0ge,OyzIF}|M#bOW(a3*2LkQ:F?18+X)Z[.RT:Jx" u)(Q2RDk"D@鎱;F )' 5kJ}G1YA b,Wd\p WT;2St)oO[#I3_zSȴ;˭V=}9k㖹vyo.y距Uh~ּט{&S~4"xzڱjfnlOG|] k'$gsP>td9X= O f=l|CGz˟ ^[D2S5n kb!)M&>.^L$U!pٔ'k%rwHo xh/*pz5J,|đ EYݸẍ6;02ہ }w7 OHYedeFYmWtόUBucG~ß;Ǵ!wcglTܚa^}*/M]?S%q >c^#wIt?Jm2<[&yW]k2לa)Ɨ/xYƻ}˱[~qqV,řXwiVܥd +0J=]~-W˯+:_tK,z#"4bU[A;/Q UZ ޿Z2Ji3&^k}O 儔 LwBv:ZK"=$Oݕ1ciǜ{&_䲝Dzw0Ćy%H<9{Y11ĚÛ{O_J0_c{;2c!!#t޳rW5{ UFg##C^vYaF ,\G̲ncŒYXœrg:fEosJB> \jErN VJ'ZfmE~sV{#sFIg3\U?tޣJ-u,eanuOUd0^,wÝ'~{uqfҷy]Fo)9+Qen{*C#_"_1lm]f|VدF $Zk󂌅]#$G!ܳj)\r~ uAo @J0B='16@{OT4s0B=c49@[yO>{#T;ž{1NGF{36J'#C2w#]AB=,Z׌u\VŃs?~sv6Ln ntɧ+022963B=UgvU#vǎ{56GsF_:A$-v;n= l8F='*#t݃؉A7, /(Ǝd,{"7sz2Œ5ЁbGJulȁ' dw޲rO{{8UB佧.f-jdwBFy)RKǥjb9htB'lo:M+z;Swu}(Q)zNTFs^UѢnu f)Ǟ{+}1 70J#%?$GASwOubde]DS{?3"=csV1"=|n&/1k:iԠ SՏ\ f"3'b%ho켧#;F>䫄K=!nz fUB#aB x{5}꜏T DmF3\uO{7A"IK]*!ۃ#s|-ob' v sVJǔfmsOue򂭌q#`@ „ y.>u Uޑ =%8vu''Do~sNاJoVǐgC9/ =ԗ9#OQ_~~9Oqz)Q6GɎDOz k3ìr  lNQr[;hwH SVJ#eu@#ub'x~gh#Q\B n#ׂ6fY\i$O ͒G^{2#0QM tۃ!XrkFQs^WEcϽSs,MeŎ &qyaF Q^󂭌Y.nxlb L/]V2= h!isJB= #*p{绢uACJrB'Q#:vrUBgqc[6;r4H =qbGJB9+ߞN9:V s6J'Ύ:J󂭌Yê) ^5F'oWYv@ ](lδ6bB>} 6kBrb_ō yk]fwBu0':SC="-5ڝBgq#ceu !v۳kt)jמEn۹0_e^{ѵι _%n{7 Wbu3L_-\>b=T=ò=;YHY0g~{:!F\0a{1n/*9 N ;F /Ș O,rd4H0{;Q!~Ch1{4flubGFz 3VFg^s!Wysr*!۳#:YNf퉪ʌ^Ŝ`+`\Y1St ztNlb_.)(E(fmw? #;FEX2b\.+W#pݳADqv!B=랃BH>)TeĮ{129|zԿѻ}ht+#Ď{5֘ C=PBCCX=EOqsNRb=xߝ!_DDGc=1ҹ0c#pݳ 5%֭0aC{:RÔzYDj\`#%XE}fc=TWA| L\aJYŋʫSns.>ݓO=*8Buk9En NŒCO>[Ngn#6H0c#ܳؑRes(h1YD/NNU4 6Jgчs^2j'拐u/_yE4 ƵmKUC=G.Fyݸ U!{XM9#=c\n\N}?19+,rdH,h\Vɧ?Ue(YnCf_'2Þ5Jg#%!欌}{YDJC`嫄y@kziEgq 5F'#;BBCSg!<"m,-jT5uFJuQ)YD]uӢFʔ]=))ÜYĠclЁbG(} 3VF'6MyO|,n%bYԟrB'Q}_@Giםx>'It'NƊt7*#vܓOсQYV=HUtzS{TC=$TGHsF؟C'rSEM-jT 9e+`{7Ȏ>UJgC*v!K ;uRĄ2]P4n5Jg#E:(/Z}_(М; *zY[ה(x.wO=tNvEkYjfuOwQ-"Dvl;IH({ UBgqKBٶ:Tlb= Ձ+%vܳ؉"53I/ZXŒ:YX 88Y;Ysz 5Ƶ㞅muZgDyXzAcdǨȀC7۳ȑAe|C3s|5oO>c;[#ܳȉQ.R. |YȘsr*!ܳMy@NYHYa,vbǧhAh0ceľ{yĨ0_c{9uJlyObGFs| 2B'tӲNleYĮ{;(s>UF'3ǡiuH甪uʇ~{1HHH8ӞEMm[[3؂ƲNzwMYY]3B=ƌ+] + ۞En sdC8Jgfo">t9kJgn 6GI.Z)E(۹0k\Y(ޝ>܅aǮÄ Y8wKVM}i*^# ,b=cagX F 1},l8zN5@gal1*%vݓؑ#󂌕:YȐC5Œ5qb' ݣœ:YJ/zwPjӃ,Y^1B= \B% T= 'ʲ]X5a|:}I˺K= ťot Q db_j9LT(t݃ȍ[R9 N}s^"=|wly T ѩ/WG&3=.rPMΓ8υ_G3~oVҡ/n-7rn Ea:R}Z'pl e(ϥ Q{nzH;xXA^}4e q]zqL |~Z~# wAU`3χx_FKtl׈@"Fn}`#>5õFo0Mț()&Et1޾ c(77^cEJi<>䵳ŁsPۯ<T|fXu=~ R]pZ^uۃD.ZS Fd|~HfG1/㗫f/00'T% xSXx/G-ϊ[ay.oTyەUYlGOlx㓲b%q,пH/4sAl/)C2Yݕ䕾da2] tT^ܒ--m|bFrYW~.8OiKJȿ8. "?^#xceޓXM\^Ht;}𸲱i|lɕϥ_d=S'Jzl{O}F?ۓ\ChX1V]1GUe>xYƥOX:zȃw](m@O]E:.Z:줊~0Ǟ`D N(g"FcL>C,(;.QY PX_9~,f#F7SE_O<B1}0[dA" pӟta˃32,*ca6Ohqdtiכ"QBRf( Xhmc4ˋ+}-Jlx&BIBoBg&lg̢GJBʙ9[Ȧ$̫-?Ty51ei3ޝ|ykp X-|޵#Vɘ mLNa8=`@t#6EJsrfb`+Wn:,idb<3I\|0iFFuAWUl! 9-ޙy68sn6 Smlvصk֓Ơڡ(yŔbPFlwbNH̨ۈ.Q dŋ!c621|ٙbndY` P 8p%MC/#ZD)ђeS6JNʺr^HeWڊkRNnNUm1W  pnNE`L59T^y#viZ#bB+w%.̗GN٪e[dW&%4[/S`B$)7鈲Ŋ4عB ):ZJI+_*(%o5]H5GFc/Pd:-ع,K*XqB+XQU: DE-+Lq爀+ SCj8;b?W5)#5ՓAZ24D ASb6ء^B mNob]S%M\Pg 1֑AΧ}$X;f"!P4ACFɇ2B+JӐ澘Ɏ s ( {YKŜt TA%yA7F󈽀(yd 8aL ("'1C¦K_5XtRXf11V'RŦK**e.qr<bbDBzB80'Sa )py^|uxyHZԷK^ױɱ*WƤص?iFa5hZ&hFq\,9RPLY\(ul!esgbjF -zGn(xM(4sY8 dX3-5|J˻bJhlD鳗#nQ*THn|sšqs@,V&6a?>;P꺨?Q@QyّDhTDuAc%IL92f ڢ>Ң6Gjg/Z'#ۢF|`[2l |'ܸI*1h&$;|(%~ƼOtBsIȵvFm*kC{j%T$n2BsjQFvJ9D5"cu61xٙz ޵-jeiעJP|L1$!3tsk iQ&T%6 òighmDɔ= Y$y*TO-KARFb,9#96gخ]f%sK?PcmSEƆb=M1v`@N1BmS%U;NhvQ^pcn%J/51#4fUeЬQȄS(P]BZlnĠ mQ+OhKbpٺ9JuҐ.QhF(c_'RImc[[Di@uDL"%n`@X؊$hjP&؎?$LU髛 UU@s4 9Mzhw  S`IB5b di)!25ȑ#DXmA(4YP4xٙhtCw3'P 8rI(Q6GCJ8J3Ĭ2KQDNLR} vZ eW4ǃ}^`ȑ> AǢswPŐXˮP051\!sQC>wl\=[=Ȟa/2_/EҵsC8@`Hi9H#*B5rOU]6O=KK4Wض8Z#[*$Ϧ%YTX_nmV]&R,ҰΦ_)n1%M)H +OI!%~OߣcJٟQ?IK.Q҄PMwF&ۖJk(e^#}HS VHU"oh .h.W3%y&{VU?u'z7ΘrL_'7%or[2=__ި]Y!/z6 ǀ-H Jr"{E@X]Fa-s֥h_ -BXC[BB Xd4.|m#7{ vI~צWR?kWo-niz=>"%.:;\QWJ'y9"Vpj6ǔrצORbWJ'K#%,|%8[&h 9 !l!sx~q5:=RWoJ_)?Ō-JXQ6RĠS҄ [%L J )a9ၒ %*' H vCIDA7l7,d8b{Re/ET cQ7#a X>zT0k}Q^"vTW#0wQYPeVL+]BT/4_!ț~m$Dby t1ieDe^A5f TJXS5ZD'N+(RJX\g)QqՀO) %, D)JӚ@UEw)eQJf%*j)Ɣc„-9())Q}R}JX G2'yQџEDEEA(@i7 W5*) 0` o%B~ ]B\4@HJx+Z(, 3>2>aՕ|?D7J%,9P?D%3A7)ETJJf~bʴ"vP)e{B +^(XI.,U9P@ UB)e)Qʷ(6D&VRn"A/aI֜X(%!rT2P^'\9*zj* B*$} 3hŋ'ihϷW}lcS\T|>ݜ^uuu[iӰo';4H[./`oY]G^cO>Ay}֦S/al~AyR?`oo({-SDwFi]L)Rx0ϷoS3JJ曈#)[-S PH<:vC#T Sh0Ϸ?ORh0Ϸ?K9]MKϗ#G>n[y_M'П=u&4+Mm@aTvKϾGl-w)ҝlf{# /ܙ}Ysnޟ#焏}mUe};震qoT28yot<깰QqpJ[v.+k_, I|-y;|s\I.+n+(pvNW83;WHm΁#S۞ O/͹P>x ]IJr!zy,zP٥=p(LoNb];i="$R?WhѬgRqb xs\>wl+|p>:hL5h|gGm+\}??pGeYJtgsg,Gg,q2VM:OZ8.W?M(΃?-Y*tox9Lȹ?KS(JGغ>P\8X\וOY:>Zo-yK' 3WX9kRKt[p}:?~ONwݯS| _r|lgn|c_eׯK'}ġýew+ןoL*?S#s*/IN| N?8̾ءJT=l^y JO]^hOf̭l։&/}v3߸ X?iU(_PXi9~pxiEW"M@93gT<.+OyHzчCĭ\顊+o8D[l C6<68B ;[;ʆg 2i h^X'?r2 ;^2Z;ea\D_~F#->S#U`CxUAzn^O'Ĺv8~xC\מ[W=n={x(QvwQ+[E$Hv}3e\FyM?JQ{(uN$w)w;O:"0 Q{\.yD(Ɵ TqC <-Y;HuSqV&"oJS9!E?#E5Э׵+_4wYi.Rii ϭ1]VEͥnR9~ᩴ:Jsw@ ϭᲲ{p'_<^#@|9Mxj%eu&5Yݭ:ܚ>Wgv:x yEoHK=?0=8ǎ ܶmk?ϛ"}QQDCa9 |Lyl4Tg̱&+v=sH_TKd>\u7Ȏ/AK_ڟMIO;|}P*+Y R\an*/:p'vlhů~l1_Q4+$ PXw edjL4൬{̬Ry\%*wYN)K,ˀ<(C_vcKnA?:UIn}ZN.q| +^/LgH "C9GOV}B)Ig}Gtt-]^rk_ð?DO*>UgLcUoY'STkz(ʃ_wk&Cz,&0p!?X~Ƀ?%~*_ =Dz]a ]ױ,Ɲ^k(' b0b "+/8ʇG`՚<կ-b/CZYysǧ7W_^UCRޞxZ0_.__|7ğDAhJ[ӓׇ> iqCo"{ГL kkz{dq++>YӀϹ8$ k;v]Y9e?蔩,rvKwn{{YHZm zsD)tŷ]]*h:{:?8 w=F4{DrCxKyeOƆ bA5Z_[{ |=+ig{V>?6|lϙ/]KtCw`_>ekKjᛦl3p6>) zDޠ"})yIxvr'81߇dT2}V^QpE"z#/ITK)U2~ҿo,QeXî}K~fLp03Gjtm}EN!G[} QEFd|"Q*VH!O'7 >@I:BaBkx]9\$Io!ؑQq3Ǣ 5QFF4[foy;oK['ES/ty}X(D_PnKo+z#Ap(A= ߂zk_+%_-?X\>[Ht7 u sp2!qaC}w} [_$;]q.=on˝Ȩ" ̷SƎ22Z>e"O÷"'122c%0`$@A@C@u 4wڷ(Ɗzocey?vHd ϡ-Hm`+}c"g/Ə'T:-Dmz%Էޗwҧ1z :o;֤־!\qk'F/zh Uil6_.;9*1cؑ#!| Q5Y4/B# xz%o, Qy2waOke}$Ԑ^q.xxͷfѐAkeFv yGL G"\#TG(Fx#8=и7q m|W_ $\-33Fq/co#-7y(||u17#Q>Fg|=+h#$ Qz_q>S!`o/搤̋[Nmwח7M1 ;<1s0է!e}$¶C8%WD5dc#?c|ˌ1VqH@Clut3p#5lX^IVQX. $`v -LrH|aֶ$qGE| QEƆrXAl2*24[f*1Z_KWE<[H!||4}-<[&& |`,!ocoWX@l3A~Az@T|KXXDV0Q7ߎr,K K4[#Dp8Cmud W_lذxrίVyhY Fy\JLhWKSad-3DRiIb[|"t| 1 8Ƣ f픑Qs j-3Dզr#_.cPo#9i.3`T`o!Ĩ84)1hͷ1 `$H&Z?t%a*MmZNbP}lT}~s9|є9;M(`o~B—?\[ӈLXG(Piͷ^f[WoWf4[)DY"S*ņDNmu)cהp/`ЀoH6wrXAn9^J]1E<[H̠ 4[f쎑Q~^a7:Ɗ $lH{;'A7^xͷߜ0iͷN8M^,K!`o }&B/w}d|J7:4<[;ϵtvaO?H|E De""3|-^xͷHA Wb1 1Vd aCxQoذ< LC9ەA8 5tMڷ/D9<$ E"Cme"(|;%$74[&&j_cYyxC<[G(Ќ?ǀ| Q%F3Ɔ,!0oo5@ؠay$s*4c T|DB "яAvp)pG,Hk;A4Mf~RWF!RFԵNWTzP}CWT"А4ɩy!柃T@K7׽ҧk5LSkY_45k0DsJuB*Z #H(WFt-D |v|J“:BaBk 2 "OBCJ1#7Ԝ5aH5>ӨJ\  :i° Xѕ(ȉьA3` A ~>C%8e ]yB$yyfN?vMQ͕ t%%@?]TTWŮIIn ޿0 ײz؂~{ ZO>K`T. a>%p:2A4PHV)9CRεP-Z=aBUɇ22k9ƎPQ 2FXu "GƎ\o)aTϩ\i. oo h-3$rbdP||Ame"cE~Xmu }Ru.J5ɶ?n-꜐QtpЧ6ߢ>SI5Ayͷ.Oky_[3(@Cmu ^xͷL8@%*rWBo~b?Ol[J1rayD!<[!Pv^vo#3jȨhVɆ D֚߃R\i.@oo; -3$rbȠb t/1cد@1hͷUbddԘ|ˌ<2HmWD<[$PBB†ԧ6߲h mRE9]q.%nEF} DVɃ'$po~uE:AmeԭAų'mԧa6߲Ej:eσmu :PĎxrYyhvOqP -~ T.پ~ yͷD:\lp.xͷcEƎxM62CT!##cw 4[fl# #Q  o<طfpUȵ/DJUT\$KJh@(|%&+z5Q-3DVɣכ~ȇb8UEUE\Y:Uc8gvJ8FBIp-D$lTb|B!7:B#$$Рo;aC [ݯ8Tiͷ@@ q|ַb>#1ơ4[O>gͨ;t6߂>[#t\j] DVŃgWCiͷLM$%<DEMhWevq*+ }vU䭀9k<+4[&&甡\vؐ!)\!62A4Ю)H>AClu +AUa@1hͷ؟1{|;3U4h b1  >ZWE<)ꈼmaT !@E5+   $lHؙ`|ַk:poY=UDl{a6߂CṼʍ?:Cп̰ayDJz T.ھu7m?>:a NCl%uUDyơ?123l_3],Ơ!62#=c+ 1vfX=Ţ h-3DtK2 b1 vʰ"ȯ1&HdԮ_ihͷU` aCD 4[$U e#ԑ<[/ }@|k+Z!gE+EMAm }^Z3DWdFOV2!iǫm.M}h6tS C3xX4W)o4ᠠ7zV93~I\Bk,3 25^r}aR56Lll$+kXCK4J3_+lkfp]K=k rՐ*dW$ea.ʾD^R1%Kq0=C:`fX:E 4Dc.OJ]oN7Ehtxή\:2On'[\5A-v%]`;v>(~`~cV4ѵ!QeF3_}~Z滠vKfvsSq=cat\:rS٥ ds>w40+`t$5 sKn7ϭi;ρ9NTS >m3An{}&\ 6$?mndkzZQ^=L?=z?a"Id0K]h7tlHS`Lp&c~vf}횎D+4NהpW,rdXI|hׁ)FF0,#2b3zsV#){YD8wXdKg*lbӯU-b4ǀn$j"b~U TbF0b3uXU;e}YX)l9,t@ȉp3'V ōE-KeMc|J>W!g7V$kJ.dk+ 9E.K3 Y5ʇgsEQT;sv&vͨ0] YL-c@bx" wGGblҝKe9l]c5!Dz,n"lOzRrjl;ƊS},L4Ms >@Y嚋JXSN%̠s>F$jԯ?yz{&r:=Gw>F]ϬOxBgoBgOOVd٬y6g_19#hAU5 !YD4o#_p{&q#!a~zFۊ9Ue<}YH(FHt|J},j$%iB>S!Įg5 >ꇎg3׫i2>O!Ďg-6}0w<.y\|7|w&!˩p~OcS!z̺ Lcg*S:הlz  5!ןCyfq ړ;涤kB>W%g3k:sLbDߒ,U=t@,j ~tG/Jg]22+3 h90W,j$pb\*lwfA:$';~g61忌g.,rdUZ=se7e7 KBtf1+0+yeB3 +Og*̢&, °'˙Em57}B.W}$n"53w1%U.g2W߮ٸD-̂& 6//yq*#v<ȑ^r#t=O-s/AǞgo/jc:>S%]dWo>C3 _1Ct`Ѷ h^Lj_x T7$k:7^g ;  l^;vݮ M T TgdkJ?_9Ġ9OIb/Ys㚒Vϙ|^`j/c6ȇ^g29 {rʝ_ZDF-z}%B3Aޝ_ۢD!DMzv\ !+N,6Ys~g4hbkDU>;@7#Ez̥ F}["R*!;ӭ7GXP#nDM^$E0g'Cgl\}4h"S6*h bFj5"34R!y !<|J< j"P)?}|~t|J< j$ M`B.g712EmzU n!5!s3'`5יδ[V~pXg&YcAϜ('5ߛJΠ_:ᓦfd$dwLcEU fw6L?d)LC3 "о ?!]Ϭ_"7GL4*?no >@},j#hbdd4ǀV=Z:zpW,rdԐQ^Pq>ȉAs kQImV s3 ɯl|*YDP% )̢F#T l;BBBĖ^qSя$ޏCn{ȁe`zIĨPd0GQ\6{mҪZH`H~gl_Y &xQ^q;@*kJNgWA† ԍәXԆS½{Y cGzM1B3bP/i[؉)יEaL0w:AG۽PX H.Ng0Խ^P:IDHV_p`n$j$4$ׄ0Sя,j";3cսc tB3ޚ+'+l>zİ#$ltp/sj],ndf1%1B3Zlaפp/p" άwA%v7` !9~י9>&{A ۙu 2Vd4L!^gII0wzMg٨K!_b34eڡċ7T/E6П<\h&|FFFƊ1T,rb^RVōY+6fYĠbѮ5Fpf#cEF&UFs&[ƺ#'wfqg. \8I(׮8dixwfU$l>B3ugBHF}b3 "zMۙl]c5!,n"Ef:\/xYHh>%B3ǢO{.}6>v9,%33 ]1_|s[~EaǙDH5RC3ڶ9隌cәhV&E6E.GTtp/3lf;RC3$$#w:SSάc-H`BR򝩄z$ytrMb3:1%{x&q#!!#"sHSy]?Ip&c{zsf~ 3軲L7.g3ʢaVG3 w$U<7I.lf-iZpfQ##!]媌L-fK#Y@@r4k'6!h\ :YNyzsJf(= ʹ:"4rDČ6h._VvN/ya3 xTW7y_cr7Yb$D/%,v@Y _!ċgN礬K2% ǜ7dŦqNzPrZ;m_lOC;`MLiUOC>5E]VRb\/w9BWϢ#eT@52ZřP?nLo%]/"!DhwB 4sT%^YjbQFld62F],Md=Vq/tٕ"NO-zUu@ 6tTUaE=q>v ƞJ@u*!tT2M"EZsX Xej,1hy.Է1 U[2n&]<ŶЊB%?m*|zڿ)-`e5Ih~AmԷ(T=rŮ/%Q~dDH XTPsȁ,N{n֫*)Cc1Fh 5gހ !#4sQ<֒-p/8L*1KdyW_J4Ieɞ&+P]ꩾKqGڑY34*SEFEƎ+X@*42UbLFBvќ2BDžMO-v2M$d$+E] 05?8>+ˇەhv~sfJH@8\#$nmL +xW4@0 7Yur &m/0 ͳL|є;E"]M;:u@{%+ ";v2M"|ꢕ"yTQ24pٕ"Vclif^*:2+F8lr>%kTq3k$"Nw]:MdLӘq;bW0S$ut(ꇾ`xQ#4*xxAcW0:?:rhͲc20gb TD97cX8@|h+&O`d8D?3M"ly}ڌd A#9 'wK7d1l+t'3+FOf tXeW* ӞUEH/ֻcl!#9Tvg91*2ΫjwHp(C.LEz"EZvBf$^̧h 'n!xT~nw^UAbh&ޞ[ [bWzviQ~h&KI6Up/=-=ݮ.͔Hw[ԗq !|sU L|FD\,/8ֻcW9w@ :zwB*?9s>% 56>&5_#T XJML3$kBn;n/t^+E;MPc79$ů=`^r퉾E!KJ8q#co v4wϋ~U} й%e@ +%݂"n|z"S/hcG' #YJb.<$ Zqpj'DvzT83dGEe2L5j nv8/Li!MH\qvH2gea'/CHP1b=ݺDq͚_;1#J ]D97xnx i$k6s;?Q%F׉D魲zHyGaH)(#!0:P4/^%N(!_ P"GN]+ KlvUu@ Ή0/I/| ($DQ4U1vHz]s 1=(:h.HiQ˩ÂoF(_Uq/;CE$wI!;ݘ**1E3z],ʸ1V䭋c `N(.) ƥQC&yTzɥQTA/;s;ߗ|$JiM$pFhC;EM7ᣞ<1{ n6#v>FzM ~E}tTkZugH~^7/>AYvS0Gj%ANimGe؜FaܔIfs;o(oaAs l|B9-n"lH\uGYQ]5OS%FKPeNO$2%{Gj$3}=3c`$SP-ZM5]:/X*1huE~X1g vmBMtlWD|&M&6u5M":R9fǡm4!a\$ݱgȔ_\vzMWϔ;;-fKU3tS=bRSD7\/*1z|$#aBX':+WwDĠ&fQΧI&CĹH^p>cTd ;Cv%! =PG!troߘA[+FhjĠ cdFJ )KX BۋBpQeь?+'')~}~.(ǎGǢξTǠ-;2''"0禮Eڊxl ])خ ,=ю\MilC+qȁ,jNȊ^B׿TA]E]ab1KƆ=f}aM4t@eW:)YS%MBFr <6 ,8z+<5M$$% 3`qhˎ$S$*c՚*1za$+GЯ6$EjnH4WX cЎnHC+(TOF/HEvGO* uU9l ,PdɊI4; 69 q~KۊKN7>J EQhgd^q"rklO QBhlHڪiQ/ C#y TO.CrIn c] P_ʛb7a$Tω|J SQu"!Zg2yQ{"ĽW9%6Ub$Z5(BD-h>M=P8CCSbVܧS 8GB4 o:Kwc /dȎѐ*1h,],MiXeWqjl,Bp;ubd8Uh!juh)BE":O1b0ceT`"H>e1l]MI.!21T0cf$͔"G"ѓ/6l38𲨃&>vH-yMC{[v%!Pu°" ]e9d쎁7NEN }BWchQ1cq/tٕ[*TҦItǢRLSb:J!p p _enù\eS&;H%NC ]yk՗P+hvO=˩렼9x峓/3yܕh/j e]lqmHPƣtBu ewVV(4YW,j@噰sZTb)ُ);;YVx:vQ9{sNE'եX6^4]៾}Ko[-չ5D+ɕSSa]iDhwI,K.ST Ȫw-y\ӴTye4oòWউ7v 䅪?Ljzj("lB]+>IJ\tߥԑS(^{Qʼƈ:–l_))DK)#%,=HI%.m1M ֺRSJ )qk}GJXRޢ=JXtc1a–/TR@kNO9bJX0%P#!²ѦQ|}2[v%hiLFBXa{2!.<' a'ŚM3$|!WF>c^c?6Ҧ %.TeP k80E"ª%}%=E[lvʄ0|\ *ꇕF?2|՟aq`SoO+Ұ*e/}C>$}+ rra]QrBr5PEq-DP ToQa+DPT'4k_u@DmG1+L~{T"aDTTCD!tçeeDTWAE؟Da;",vD~#" Dy@D\_AA%w6GUX 갂AB7*'AGDPTCO#T[j؟H>UzOߔ9ЮiJDf O0",6^]}ۨF; "I'BiRXDTTCDӢ#Rjr^oTM?ʏA*h .R]a*#򙯊D|Zg(ޓ ^q3D*'FsOă 7ާzX =Hګ*ԎUd$ RQ$a+'Q%4UctF*T/{M&ߐjfԷ8. ň: c #fϡ~P)Q+B|T ӍS(1_:AQFDPADD} "Z?jk#bE}zakSDT'Ae+k[ia,Ey}i9w "f>A%YA*U}~Na{DM;爠|;UzqY ~A'P\DT TD0|z Sy?D~|rz[_ߖ_y5m(/4ey1-P^o|zAeo,/m\SA\;_2ߚxӀD㱹(N6i̷i 3߆οx̷? X?="pfȷ[-3MD~g߆;! ň4N[Bl!q2,|q2߾ǿ3˵/o_}mk|.ieG֖wz7Zk4ԗW[=hYn}tm/3wͣ?tsܷk i86^;S_`y{.u&RwbHVѹ6E} ak* p 6?}^եOTJ?}-}бi:R-kԪ|쵿a-3məssKE孳 GpY>V"\9I}.s_ticI}/l-,. l ,, )GɟW~DsϾ,;QTUrrC^㫜mV={0$K=ByڳKL}3˿_u_o˽.gdFc|꟬.۵+7WҏگP畲k ]? _WtQIWa-Qup:ih\דgg}CZhu9%L;_#uTeDZҗ|ﺽL60// rZ>k|pY<Jt߹u®z*|!▟xTY:BUr'9yu2|QnAt8_2,4E] oZSE3}97> ;g;\E^5x-p(8Ȯ2w C,-?%0ѩp Rl 8%D!4w5 C;_';ǚN4GTc wN&P'ӷ^9`)i}2u* xt1@S;y?I?[PᖟdT Hj9䇝HH8!;B-?%PשW P~3eK~ҩ:^)r^Y턀}@N C^JrWܘɕB<R΍B7P5n9lH#;(2Qdȳ;+΍JwR5-n gIg\ [[vXzcl^);2t J٭d:'G(P@p!Aft@D7uȳ y:_2w?~oai|cڧ yv:gcv!2C=p*?p8}pg_[Bp!2C= _ݺSeu3pg7BYzݹ5^]D wyv1?*N:}Bmhkxm(.]DXyP(EO">( HAE:_ishagH{_aF9tJ_ac< :[e\~ϺS%ђIDexnRi 듆Mنr[U ɦ~DY\ϕZ{G{_ Q*G/k2=[҈}Ot|sy2 O:Rh+x͞&Qge{zQx̬vN l0D>GiY >9JoH'@v蟈^=AY+їޖ|u3]oWsrmOuk[>k6}xVfȤ~֘eSɖϴңO= )QQgoV~qV^ʥjt3YK|krfR~kܱHzuh#=yzI iP Pr7|E4y_۽rg6Ȝ̧ _.M] we=A=vf^ғqlQ?FLN·4"/\hNn|" UE韝\Wkt? ӧ7^ֱQzKrҞYE˛~aZ8.o8SyI/(:"@/0Q&t{/,=F_Rz祿xyv)OfXC妨e/z}Bv#t#KJ˙7TCoo+gU.|MW.2O+BU#/o6]kЗ[C/uC?okDd{խb/\V|CcHɗ댳P_<&fA~Zka7[5K_?xַhq n&iQV@9jx"F [x$vOoRvUNh]J#oBw|QEFsu$b4O:oE2)}MN6\~÷L)7~?a/c+uʌ 0v1ct2CTW~(^SFӷ!rΣ5H|A| QEe$b4JPu{{yLxI',G!asd9>vl@<N~Ӂ0T&l*1op?wGƢ]|ˌMhr`?U<[x!(eMp8e#a3r |ėVNƒ8T|넠y0#$$`FS^\eUz1cy oA:šVq>wu&$Ga3E}] ;@qs )@KxweoZXxBxRvGIQx ϷL_8LG&c$Gӎ# )Q?SFu<0x ϷN@ČAyŷ@i$B,Ba<2ATcukh4ҀM)f@o!8yȌ+!<[_>w?>@<2A4X^ am'M(YPd`|*6TDE tkېM oyjmSOAH|?Bxe"%9JQhϷB 2zHPRXxϷLed  QV*iDY<[f*KuғK#bQB} 'Hx%,<[}dzWNnz=sRxϷL]TD4[Ǩ0K+w\xeBuv!oWeYЗ6Pl|;0UݷUb2b 1e oocԑ8`oaZUDj2bߩZF"f -M=cU#$G#"Q}-''+j!!|˓VH>a?'󭣬HaU:| R%6z*DaH,Bl@L Y<[lBɄ L(4[I"VXxyuBH ㆁC-3c3R"쥌|:Fq 9Zg|% ܧ(QhPϷ/P[G{e6w21cocs ˞C{yū^$/ π23jS@3"DFi-ϻW}Gd4[WM$ \X4[(̠`py8ϷH9Fv}ipo%;(u sV )[<5.#1 !o"6DРo;Jk|b<21HY2Et:>21pW:ʔ>Uۄ;0Rյ(!Xt'^z 6D [=wx M]{èapQ2C"'ƁO*Brl A] -AaTu-3Ddl}f+k) "QĶPs}L_jjzKDz-TmJEHhʗ8M^2%LIB ZNQ$zԭL(RFҵL]r(Fc ,%Eu 'm$^X?e_D&t7ԵCvs,#H估`4Jႉ&%-i-SD(T`ANG"Fc )mcT(UJ] Q%FF 8k&*^)o#,zkC.G_9@dP XuyP^Ѐo;CT;"$Vhy$B,B<!9#d $$@oqb6$XO<[f$>Dh4픲?BxeETn/171eo:FƦP" [f*1c4ǨXAwadh#qJ<2EtBՃS_&c-SD)tya4ʠ}LmW4[f*1'9K+c1ݤ1c ,&-3`dGHH0_cАoc5#l#em'fW%I8D|K9#쎰!^%0tK'RvBJ5ב8gРo;CT;떐cy-6 ^xA<[RpI?9*GA<:Fq LlƒxePiU?Q40oߦdlJY?V-Rƚ(Tw8(o"Hcv<21`o%1%IK)Q. d1 QV8cȠ<2TEK/@XyeB}BH#O \h?(5בh?`o!Ƞ|+EhP=y-IN3>Jy43 P}-R%T7Gp_ %2c`?;xϷ3P~2xBCye"%nydb)T^ćJY= r咷R5˿q eJ'Wu1;NYLccvE_vD5JƙP3EC!y_-;]1~S&O+CG^}6E ?A>]>բoj-o-ևYĭI?*9Jý z )|@"2 s{/;m85?$kjOU es&K|Ck,喜#|ҵWwrUz%eѪz=b}At\>6ߺF woDWG{_|\"=|%5tJnMk1K]~Mk*-~|+rE^ew{+zfjۧ)-'g}ZgOx8T-W7H ,{g究ϔzpr8=EҸfzTU<Ш>L . q]'[oȉ,ZUL9pn\B,j#05#C[+MȬl CUBgq#:6j[5IHm^(E(fUOj SƼ`/`=,pUQ<Ƥ0aCz Iaʈ=dk޹UW"7yjz櫌YO"hQ첂|m~uꡛ[+zk'9䃹j/~zus(i Jg D13Z)l]eCʘSOT~'\I!UbG(fSOTJ/{ͧ #8vԳBFs gI7wջL`wB_= bH 5F'[7(b_=5Sx 36Jg#eGcl?[ YαDל;YHIÜzYlCe9+#ֳ؁e 36[>?pwh$ t֓aTE?Ө'ͬ<.AJ4j$GHcFB7= p4x9aI pDSt 9A@72bIaJ ] v$Gi׼0ccDzi+P 5hl/c{8r|+0F|V0"w=y1"LrlE?tӨG(@!i;멪e1scD`/c̝c;zM )N1b£O|B0"W=dwEzk*%tS],,3fi{G.{#ԃFH^UƂzrT_&diNBG=4Gl/AHAC/SNoZ)ޅBc]bOpAaF4vdpYYgWCo"Q>ڠ9V~+"w==mV#U ތa3b_=41XzNh^qֳؑEWr5FgIՌ 36J74G̦gϢ' =DbAHA(ϞE(Q'BFP Fg#c7#lbw%S1'77dh˞ō2llzYĠ(٘a*#س˘&kcO9 ˞Ď R$}6Ș 7{Qc+Q{;Rc^R=UܬO Dg#%PvGyqϢ' Aڥ4לY؀>1/(ߞ~R f/Y驮+cqn{N^{Ȫ7N{9xC*hIF(jl{IHR:*!׳Acl!Ǻqس؉BU.hV])Pg#%;:fY%tړHqDπib'/ s6mGDrv:YDTuL VFge嫄u&=J^' 'V}$n$4Gد9A:YDGONH0["tܳcJŒ;mTiI)I(%tܳ葲!e sVF'[ˉ~ %tܓwG;]󂽀zY` u 3VF'[әN-(cN0B=QTG=pݣAy1"ݩҡߞt @g*!۳}L>IaE7{sʎ19#tܳ؉-~Ya,rd$`؅(wge_51G#ݳ؁eu8 ,rbS9:׮1C5wOFe{2OncaBg#8Jf#tݓ>V<OubGκ7kŒ1wݳe$_".)LNkkR2b=cT`zjF },vtKVݻjŒY0^1/(Q>&AYA:YF(aC蹧qw=OTFi UBVGasҽn궧Bɟ_w tG^{rvt`?B=)1S5+WnlLPǬ`/`D~{?Ġ'pGiwa;!T2"]ׇ{_[OFS.j 1;u\> MbS_ȃ\bZ?NbpMޓc Ui}_3d6¹*Oq17q(rHu++s#-f1أc1ݭXﯞowN~8Pv47{LD,URI-bE`cϼ}z|s ֕?x6T(ߢ$өjXkF?n!2} =RwU6 9-VaQ3c3KD֡"sE͟<8?=^Fb:3{tCWb&6|ea7LFaL:N*|q<>->KBFY7 !/E&ڋiL=7+zR{ϯJ/|_:I^t.!k}m1fՔ=԰O^kscʃ# QLSBw e;OܮdGב^N_aR{3', kO62D_[cZ[798(yNIa#/Y"##]y.!ZIck 8O[ko*U9++jSc,eI(3{%u~>Q>4HFcg.$BZԉM ma,ٱ3l"U:w% d`*{U;jD[{$Eݶ\"=CގL)5Qh<^*/jܦR(u&)Qt %t 3]dGISƣ+tBoG@fuLRd9uFZ)<B1jpBl=fQ#aut]^o=I- "^Fؿ~ fhNxeS_MC2$I215h(x[dg"1n*.QcvDubcxy$쎐F^\%.:zpY*1R#cѮt1aKK)3Ik"&W&# ֤mMsg> Eb̧D!pz[Ɣ opBTv# 1]GipLG)":()eD&Kz&!}t,V11;eg"=32 )R]/4;ӍAbT\]a# bޓLi.c[% ^ >?7(+KuWQcϼX!Jci1v-]쎂 %v-4]TGhLRt0p&JQB1DhxOAǜRbD%J]Ys:xb"M` COE-f?̧Eh lJBeȴUHH;#e4FT0AH2֪/焆п1d\ j%pgˮwByE(&t,01y;.Q1{Q4x;.R-3C;KNQxzb)?]&P֑((R^CtDPVG؝Y"LTHh PQsR$j4JV)f8 7ԌF@yBXp8j*@]D31W+y2&{iWVɠ%#\@v+5vJX,.Wd H/TDLJRbG(ĜIB1hMNMn]]EWc~@ ]-zdGI9 \n]M(4o k۫ fXtEJ:pR‡ YG:"1+vJ |vQDUlaBX^+ Q,/BNC fY0^߬A$:͊fQL<;[,Lu29mlVkbxyvwlX+bM(ȄZHB9~'$E.Iy3jl;(> ע'Jv>A{$bpMX<D:^v%!^P [<5UbԬy8#4eFs$4c.퍃A۲#6i#lAJjAWؑ>|avIx&T6bR썱v'M3rjB[_S%͎b,+}Q1! _e11 7 g)!# 6Ub343F*0<: eY9Q(IPZMQlTѦ& .Qh1V!xϫj} йBD֗V!GĔ;*1h\Dah,Ƙ˦vH#^?@:!rXZGYb -я"4CcdQiXO}yi}Fؐ *1bǩ14#E:[vuBN^ٱG oTG"&eIYT@3(#bQBLJUaH' xw&b #T$6d6]TGG&cВtBL y&c";(j Msi}-t4:y"&lTHeG!K{) iBD/UMi"A [&3?BFD{Mf`d aq&m1+>VU73: G;Xv4+CIEyqh7NӦJ ],)F{it9J6$x{M)QvGs LR4+ۚ#me(ܗ<Jh\m%O(QĎb(qLѹt-01/Hm(V'c C14e.آ+0q &dNZ9՟ EN ykЗB(shm'A}.CkF}i;:aX,WlF~^R@c7nS%M01؏[._u%色9 9YQn;tv1)/P 86]Pi톲: ^bko%J/F"Fc'B+U=Q^ln8F[1-K^91[Fc%C{02M&. 2"PCƟ3RRBh5nD'#,qK>V-fǢ/N/Tg6 OUg1GXvGX!YcrPmyq b4庳J(5^9- AQǕi#=lI`3l[5'sDF)91ꔡXӮ$C F镋3AJ#< #t{Pzf.{(!htͱϙb0wFKyF"FВTA=gêq1cDJ Ҽ; ]v=bc28IB}3~mIv1-7_1Jas).[U(Ea$"b52pGTF%ZKFJX}N sPr?InL)&liRJH+(e^5DgFDX5}N٦ %.uԹeP ƥMUJ+%OF"%Sn1MQ?`eeCt;kUGh7c=*m1`KSV޾ø=g1'Py4=hU{Evm e3B\Wy1xK>jm!s0t;= R? Q3Ѵ~ҞQ5=DXGtR&tCq:Ҧ; EQH @$%.>EO(a 9%l1eR՛2l!%(i QցQo9L!,s*h"j u VA3$:`;$UQ":P?QA)J)QQMAwFO)XU2,o%MSJTG)a]ҁRRLꒂ.RNP@} Q!S(SR*.e)QПĕ@P{甲N#*婪a /oOH?~]ʛ3Ro{BT&T&3ph/. Rl@ֶYDT e{V (iJٞQ?J S.Q P^Xtg4؄فUQJXa2lSJzF*LnLnqQȟdD%!U5LT?*yVp)zD꯷ʍ*H1| w.{ R=eh#:cNx^-1 QD$BGHBxaqC|`%BT /oY 1HMQU"SľC %̈0B:cQFXH -VJ Q#@e$3>אPHJE(Q5 hߣD5@wFiJ-2/צPRRy%s7PB*A1e` ݁L9O~UսE(QJ<=FT_UF=$`a6я ~Xnp Im;l74Pn/Q9DUܾA!%,6PBJ.R uD%@{,M{BW(Qݴ(6~5{ R?䰰X@ٿCiVx"9JE$h"Aʘ! DX TȘz pLpSDTwk@ +o}rĔK|{C&=J!J7,TC|}a˸xϷSB.|˄2!PB}@{uPBE UzУIQ24[fb$ "`s1= )4[Gi74a–J=N)SJ)4,+7Fy*<۷)|{C9E=:mBn(RhHϷLޤG@A=8|RDuA{}?ao=$xz"G4[Ov.<۷{}m_x(Ϸ} 3[ax&% |{CISJzBa<:JJB O4[buB`#6NyϷo4ԧ{\w[4ۓ1 R?dOS< {9aQ Ma<:΄6ZHؑ@xeB [W 3a<46M[#hϷ?Nagmۑ7L9`tsmkmI}mk{_^m/v$U*Q]eɶm7;;^JKb}k~)nyZs93,+Vg;/ҦKw_wd9ɒj%`t>ҘVAѝ䞙d^o]Γ]zK ӄ|l{[}-9)|z>ɘ>>ekᣬ_7B[_:GQo˿{H*MύUضJx]{oG1V7&e&o7y5c%޿E_4s9g3ӵ {r?ߎҏc壣ӱcEG#Ht,Gܷ9ct~rM^-w?StIE8qLypLo짾rK_?ޖ| W_ u>W].|%cqtKke?UTDc_yֹ܍x<7/:?x'w=s?^7Y?c#ggѿW޶CGGVȪ|cr$UH>pƗU ƙ;entͰe2-iSesUjb<`pn]"/_EgTHT4+#+,:m~u[ eh^5!zxxpTx m͠43CC:qlhdw8e>9d8&#&pm\/M2!'%Jr1._I^ѹph+^&hMU_~BqSeu3.8Z+j<s"C_.E"ʣrUHO?Jmbez.Akdt> ɺ2O9(r(9s )ݴSYN:u*~If*. ;?7Z~}K_ QY GBz'bџr g󧣴/iN| k]ٗh߬'h挢id} δ_(gc>;xL|πG2=c$?_:zߏ#0|d>jBڑ%zZlm׽3mWx$;("OKz^Iuz@? nЧW\)VkV;دdPzٕQ~>Ů_ ?Þ&ygyju7~-g*ГxSC%.J?b7G|~g͓/wF*TEW>>Gs#Xyݯ9S!OPOz/SՂW~ISN4jpKgz+bTw}]k/}.Ow/N=%W8ӵuHy)!#O .{);~Jj̒p.MnZ|<zPАCf=hY*>d5ˁ=o`Yhz{_}0AˢEkDɟUח;oa(Bf/&@ѩAmEJæcZz]n)kQ A:rm<֗`JE^G*ė3]Gj0ܣ#oXEE/gY:q\5_p%[*_/n:"7gwSVL.xtlk#!6@LX'L/|fyM Nuu_({7s^4V{W=K /Uo:IdO_#8&'?8vm68dL/0-.4W5j'H{tP/9rǝV&^z5/NU~ѵ-G}/]}]Wֵ,WRQ)be3TؾڅC֒U`MS3C~]O3;ϵz_ONoM6}O_2RIBqed~F}EJr(.eJqzCig~ڷ"UDoAD8KFD"^oA?UBo&1F'LYDo W^Z\w-!{u*RlEo5TkS1ct[ 'YNI<[~NTΪ4<]G"F3- [HDE L(oW[YK0EQ"9ʻS.N9OWyϷL%Q|(+RX{| R%=S? XX@x}J/hϷLUb]rV>$DF{|EJEHhAx21:߶+{X.Džg4sqʼn!KWyPvzy[Z խ CcQ)#M-f0oߙQ62!!0o9BrDN&ƣ-SD]L(4Jr*| Wp@i]7LZ)21kОo"6K[ CQ5`g2ewJA1c#|ˌ̱Gm$^Ơ e/I< :cC$VݷSJ])R1e=2Et"N?#Ţ#TG(sӯOzeԧyVT zu\=2EtO֗wVu$b4=v66!alUAP5f/c:oĠIc2L瑈h'IY:JrQJB ׄu-Sl2ì"U[](+Rc1*4 I?GU%++QyZ&Q8nIHSN)5GYǼQZ.QJ_fDFREԵQD GTu-#TGrǕZR[(DW)RӵL]%j1Z&hvRpQm`pLh@P)a2CTO@ӻX%'0ntmgHkche+UҐ7wЇ=EBi |362Ϊ+ڈYF.Z l/V"F#礪e"O~#1>vʐ"`p@2cȉC*^]1tk8Fv Ik)K,:`u QJXS-Jh #DT@N<*UF c-SD)t#DF<[ǐ`{ACyeFs *E'x-c ].2x0Ϸ"6 ۍ|<2 q> %4&<ۮ/]5֤zȃH@Cx%"C>^~na,9o Qà/e |F0hηQ#;F1co"DZ,CTLya EX֦>fH4-3D' 16@qi_MSoCB{ 71c]5DWzGL|Eʺ#1 QVXmal74[fl8d{| R5GFX@ym;i#+nlZ\C{Y)k"4A\Q%-\hkZR)=Q|1-3D1cmo (k2<[fHuFPhϷ%RR9JF )K,aahUn+@ze1260eo Br I<ۮ/]W؀tx3_!xy<ܚF<7X<~I14e?k@k!K 2F"F=>)'rϟ\YOe"+VtgB/A#7E5M7oytR?LP+LjhW.w]3_އ<{K2#ݼLA r&U{΀H,%ٖ2Ȫi+}2H -:'bQIBq&:M<ܬ [inibzJ%]td +Ԑ)VX:,k2S#G(Gz\(C}ۻ·fs,O*M6~\̭_C*G|S+,/Ӕ)6elz=ee oB}p=ZP nv0/Djx nvNo1_L,?O\Tsr߃z1U"fzQɨZ9de/U2VǨ ?ndkA+H 'E[+QHL(Ď Ʉ c%zoj[\VRR3{;2cc^B=֣5'9YH)Ƽ0g>{5 ]Е 캼`/c>{13ǜ\J<4nG7d~䮧1wfBDh| O}4fO} T F_5#>鹧t "C1)PCDz=>t\sQcN f<٪~䭧Q_lg*!rӨs:Ine !tփQcs|tk)v-B"4e#B>C.-L9O 6Fc_!޿̞iJ } 4L;Ґx.{;2f0.+X z tt˘쥺DKOd`ƈdkG_s}.փP3ZtfaE诧[7GɎƬ`?D{+wD!x~F =h1"=U=ӊ|^QB=)k^1^{*zyZC5cj` h!9`B'[hicwkE賧q#ANr$9AB} ndH$!ȋ T֗;](kw<C=(|Gw2B=Kϲ0gD^{(Q5/N yKK04ccD~{909aƈ rbЫ쑴e UF趧#a pN{5iX=u0WaA#8@& كAo=:_ǔ0]D>{;RvYaˆխ$ ML\^P"==k^1"=zCk+ u 2FgRƬ0cn{:+Q87sO޹<bƅY{?w۳#goHUjKxC'{Y מč1'V ϞJazTޮ9Ɯ`?iz)醲: מJ`x{:Yʘv2b=N(@VQB99(5>{l&5aHEc˞Ŏʎe˞lKg`ל`W\,n$PP!媄eOΎ Oi1K5)س P{. 9"tڳ{.z6Lמ 3tYaʈd]('`'I&b>3m"Gs ԃ Œ?Y' Ng~A=Ya,vcdXǬ0ce^{y' cN.{5oo·䪄aϢ&F_t>Ԍ0W_"#1'EN m\櫌]O^QwǼ`?sǤKU>U[Osm!%ϒ]s¾a zBVإ]DkwbcV1b=dlp/ٳ@e 0["ڛ3VǨ>'ןB}D˼{?:f{Y˞m y.(QKǮz72YHN`zՍޕB3|crk9.{=R䓠QB=)IYrca|,pуE:5@gawFd;5J'#hm/xJIJS/c>+{3葟>DŮ~(%ٓȑc|YGq_%Lfy>{;R1/Y)ӞEO+aSm}fQ~{:"vDIa,pbŞŌ\J2xpog##]sr*!ڳP{ OS䰬0_#ڳȁ嚓V s=ˣq1%$ Y!N{z8̓RۘgyN{;QTRҘ欔kO\7euQ^'G>:&y^֚žUJg=tRɸO^p rm"WӯcF.[!^{]zA:ȇN{2jzYD')u1S#IU|U?e"GJq4f%tڳBSobF”Rgca{'[K-|z.},f8$$GAubGJr6欔uOb,f򂽀YӽPW myN 䰬0_#vݓȉAc׬ [,n$TG&xgqK-Ɯ0_,pDdXǤ0aCn{:Qbީ(6& +#v۳ؑ#AyaF ,vPE`0/XߞŎ1lsb?)l$= +1f{U~އfIr:.n|$f/NLUiBHc>B=:K]Y Ez1+SeĞ{*EþH /(Q:( )x'o`cQo:G](eL ;(ߞN z֊Zw _ֿqڛW|fǞL&.{+0 CǞō+0vǀc"'Oۙq~ݭcN1Bّ]i~>_R@u.IzZ-9;۟It7FD=38>3pۈȑ1.F=^.}b0n{v%ئ!wڳ 'G{c/43ZŌ8#)؋ȑ2ef#؋؅1ԽVHY[œzEA)C{Xp^Sr^( Qp 0려>{nbb,m^]svsv';Y;Q1JsJ0RVomm'r #ڋc`U}Y T<0Cӽq2y^0ўYaO:%ۋAN((hiaeD믅I^D31dU7~{?okY/"OY^H"`,7hY)+=WɥM uo/sI{k1cq]6? /)7{=RmfuPR={yϏ|Y>aEa䄽Yn{;*cD=i/z/Kg.{sSrv QeCv< &ǐaH)7 (49텮QCDN\2oGJɌvJ湇 e}-0qV^xaBYF}V_?8JƎm=[9v]2\aA^a)Om/<3Q].}~ⳇQ#5ֳ|ݻRQLc3=):WݱɌvJg/޺,>ί_沇 2f?")J8(Ǝ(;R'y浇qbü~EVq0=Dؚ8JN2CUkEx=ٕVZ\&[C*mz.2 XWҺ˟e3I )u8*8I|k#={ⷫ=,h;Du)je/K2HYՁ>=>|K^ +훿VLPP ”pKǷF #^oLc탿s;=1U{R|Ia`@b*OWiafDVl}d$W9ܵh՞(Goz\=U8/z_f ^tsk5:5LD76{cEzΘ{s[ȏ֝k^Og1KSx#EBΰMkA,-hNJ'J-l}/{=IuR1#<+ L4<)Gv>\dҪΠ?ϕċ-01ߦG8xh7խE_!jֽFvq=s$W-YY\X'+; K:\f'&oZWRvDh͡I]ݚ/yez-`[+|cFVbۜE8W J#fވLJ$ e:SĬ?-\j$(.7% ]Cq#% UdLF!ܔ,T aF'wȳNX7*$$ 8VpSw 1JKh΋{ KLmB8pP72zE& TO&x3R4wF%^~ڮU^InNfkg,C,&"\QAL b$Dzk+y@=1sB`3 W7=[#7osIkD(yU1vUd hX$THȀj؉D;$uk(( Ɖ٧d>p+}AAZZ"F^7s !tJ-@U6'1`tM\0]Sʁɐfn4h 0q5d̿h&zӹfկ0m?~JF Ǖ{Egt{Kh}g:/=f B#5sI?kA`!Ϭ[PAX ቈF[(UHji11#t hݯ)K hxcAhAWO;#3*_kiyc-[I$BL3LL)w6(cx>mgZ\t՝:宋fi3rPEac.]Eh«V!Ed8oS&b- FjcϚW(-K -vaX@<;݂CdT x@0!?~FbqF@'2q#&( $Sc&gĮUF'YT0ZYz7fcxIof&2+(Sɉ(sKi(B2WbZlNimZ[:hq];y@J!a/`ܸS.XQ(dA֌4vl] sV:;1Vbl [Kͳ݃(;Q<\(Q6!RPZe11cF D%O2Jv jO2 #Sclyu|/JOM7MJtI K GA.nl9yEiD!qidlt؍w'뀮@Ĥq);mZDwΝ*e0̿<}[,RzܣѦɡK98%7MR!QNH M.b&;K2#xghrO;pRe}GUaGn{f94S;v<2D, EW͡+Y\e% ^r,<һ@Y|xι ;=.G #RJ]yP9b&޽e~`ϯ$UkyGG+yt02 V0R[PFbaT=4"F㔁lCK땥*Mzj@ċن-gLm4 c,! qԓ4 n^޽7ԡz25էbGZe>e5*jjl}Géy=Bjl°W1:t" -N(eݰ>Z0);BBL9#wʎؑ1쬔B}$)8 %zv)u'BBXS+C/D)m]Jn-#{)m*2vb[ YǝEJVK'š#;$wUdl c)'Wz5-!#H]CU&|%ygTXˏ,Mh!XRPuk _*^6 5XX1&bŽ^BJ^27qTuc_,^#MPGxb7 d~{;Z:aMƐI9G27B m2M|fLn`ƥ ;awIfLn`:3(xҵ&QFlXp?uϭ@• )69G]w N&<޽E:Bv9/B,T8&騩&x|s,h }M^C?hgYA{e&YFCQ+u=T`Ɲ(b1B渎hEytQTt'E|x!P#ucߎ! e%Jj S2w)+Q&bʆu" eVo;T]7q چ)1:r3k[6S4/z[%7n+}۟_׵o6m 6՚#$ )W$5"c,ux^hRޣS^s߰_r׿z D+/Kxur>l#+mɱﴣ挴~1kCZp#qnif[s{[YG}YJMBZd=T;O9~>`n}jfF()n !-j~%췄桉+֙3<3xKInNo(Xt-!mc~eSN+[j ])K8uw)J^:t2w( &UV^`54#H7ե){$OR}ѥ,(iI&敜_/RZΡۣ 5c7ߡO(R=q 1ƆdΫ(km2^7;Y˚ӝf^x~~Vޫm=šp(/H-a >Ϫ[ŃI_k2-BV>Tc;sNKD^tk#d_gk|Ҫ?G6y(=MHfK 'V}[]JV[G)im݆"ݖQ¸>44.~5ZҸO(rTRoQ'7({Nɪ6~/G}DAl-"+G 9帡` [PZ e',"e{,~BYO({ C1"o2+IF~|V4`5!, !-  y>Ӳ3|cҭVjC-JZ+t{ JVG)iӗ(S٥dEN2唬B)KJZ4}~U*ݜ2wNˌ,"+3 ʜS2 e6(( el)Ym.e# a}dgE/Glnr(R憲0`dz*ccn27`7:A}d@.<%`D(9o[ =t([eL79eL Cny[] qKB(:ǭRL]3(2R[fv>/Zfq$9NAf*[ ^]2r:Z^nukxz:`WM{#su:#;&a?g?D0P>_r9vFk{5GR_}=Fw C;s!,[G >U[9?Qg3.5Ec~GT2zk?˱7GlUJfF}}_dR}Ϊ*;o{.يϮ{xtF{<>wcWڃ5Cb׉5ד}.~^{lc (G̙1S:&9=jx|UScKT3:f߿%U|5Ʊ8';%b93%zΞsYrs #5Żz%\s[\XWzԫޟsWzD5rwKQz|+vs= =?%^_Uo'/97=v:Ngtfܛ7%ygq=䝏jIF7#um]+ʬc2,ٲf1]9 |zFeGQhuͮʪǑQv`z'_ ([à[]2Ѳg0 10~]~'ꠍ 2oEbE^)(D.]W}[Ŏ 2wUʢdM(O lDHne]l zh<Qsf$:PvtM9{v:_5 !]R;.G@lxInzxPtKQtYLDى]$ E<-Re>w IR}$䭄b c]hRFbl|#xUnTvQFeݨ4nTvQFeݨI"*tӍN7*{F)NG|Ve[nUvU{*6]I*;ݫtӽ޻W1+2 io=S]XYO䝼Տ|lW{I5AJuŧt;[;w'4 ~wP ޻A1* btQ|ݡtrNw({)(ݡtrAw(G4'trAw(ݡ;YvAw(ݡtrPvAw(ݡtrPbku2c#į/g A7(ݠtrnPM;nPA9z7(F>Arit͝JCIrݡ 'S%-x0:y'o2|*A'JJC'Gs{r>xa9X?J,9J/}ۇ%_m{}>7OsGȣOԑ3ZKO>=',T'xR'MyQo& }"OW{׮u|sb3'g2Fcc,SYZȖ=S-[,:X5F]gU$^O>v3:Cs%>7eT+_6أ/b%$9?MWHŖ3E՟8' k{rU]﫯>`(vL2[uQߡN5X3=^_75&"99֦Hlѧ"UݟԼYƬݬuؤW>^'U=_yjתϋWQOyM~C\O/|_jL-]GbIԛJE>9GW Yӯ[~%n͟x//5]oDEjCur~DcaI"2j2t \v,c7}RJ}|aMdSMvJ鏍P_tmC="}=כ.y=Q.E^ljz~[zmu.Ze\/܈zBɍn׋_//{%O$Nܖ \pk`?GZ-v_6o~)oZqH^VG)(6F[Ozu2鴕nv|B72CQOM'@D+:ɭ2L 0 1v8Gk,HnaOώ%n;8CUaL=nh)IB֌m  ,hGjףjp[BDYԭ((;QVxI\rS,`!LDaa!Yne!J!NYnbB֬6dE&r 'ߡ eHyVn*CkL`J1ݘdj)x"yeRl]NlZq`OB˕ CxcK|t[Pe]`1`0Udltvx4N|tG2-,b>L^D&(r-QV蜫ZZ"MUƢgDcx,|~D)DxCUܾLY[f"Cz*tcM.-qqJUOa&"'H'A*ߊ/(2ǭ.lX5+ 0}6&v"@ y*Tw LH0g) QN=nm~լdSUYp\yP4v x?P]DE"H3dq0[gaA ʍyKQ=h@LT~AyVj 1 !/:RK(Q6/9(ZіZPlI,\Z&5K-Q(k2"EBJjϹa(*CTP|SKX`YnES3ǘAJRVlDU  U6(;Q R1VהZe0JݲOW" 7 c2[V0v`z݆êtb SEvfPDZu[3WE2`,D ^Xx"D u2L~aZu%B,NRXrR;~C 5JMg=h0o}3SH,A_b!'hyFj+a):V^8[7mlj  'bK])V(#CK R SFgjhb%gh%@ja()8%2^L(Z1E !V)CS\[KhzC/RaJ32dX[e0H|uVS8C}Ɛ=na'CQ_[E o(0<'uP۪UqN׫ q+yt Roly_| :-QvH}bKq STOO,Dh"Cy~2t [e0&mRXloMPd [DYRZ&ᇍ"LT+! ƒ qCj[x"eV JqJ(pٝt@[P[i- q2ey"z*tRUsnytX[$1”P_UHJf4}VM ;Ɩ !\y֓7ע-qyLD0!0}6@@B%R}x:-QV,7(+RvEL V1@ȥ[,DLL):ǭRLW(X%E Ѝ qC*@و4(Rei3ì"z*tuR1`Ȁ'0']UBd;1ƖzOM60QA`q:;0 e0[%f.'P]VF8sZy*4Odm%0t([bXn;18UHsU*-rTUs\ f"l-2t q+WV,:<X Jn(+Q  qKI)X(KV)+(\"ִ8CUG qDz(Rv :V cKh{!ĮU".WH2ǭRg{C%FQD3]=i˦~T}2AoI싶~5[@) "3YYfAKڹqmB6g 6w3ۈYj]:x\üd:o$;QpeNXDp WB{_ubFijm|g8ǚf`r73v_d+_dr} 3<_lM0;mվ'v|͘Bmfc{WgVI2GC>5[ovovSP– mfC=ۥd6KjYe򭚡6Iؚ_gL~*iD=[ nlV5Gfr8uEdj\ŠL񮟃,!OG[k5{ eLp+l-X.1%m=1ٿzn7G1;{1A#Mͥ̌53ٯ~#F[ow(WY羘jiéQkڷF&VhUkY{^6D4_ٯ_=>=B q`?H5w2(ݣ鏁,b5m=,vB[ ÍdY!+k~Iմ᦬Mhn6-DdSzK#lTNC*'wd۪rSUC(n^U՜g#\jC? I#_j?)!=\N@8V;x?'^Ds;o~M[\hhFmc"Ǝ !^ck=cTU\ NY~A"^ѵckŒE/\nB)۞۫06/^D31V`XʱFSfm]clڋ{X[#kB˧N{hadK!!+RLN2TEȐq/D(mNأ,r;ϯ0XLY~@I],vdXۼ c'{jc3?¦ B}ˀOr={V7)ֳBaf9r>uBq6:e\=W\<_H.e"S#{6لL]?փqk{ sϹoŒËw ֶ`?@dz0!nϿ9g:!փȑQ1[.e,/ sJ#e%xCAm:MT(c#n{9f'H6@FBzNR= #5'ֳ;A8F$7NJ } 4DJ$R={71vbt"c"m?\sf߹ 33 wۯ)ÞǍ˵ WO j!!(PrAFgAHو2P(u؃"&+̲ 3)D)m^s02=]2/t!<-/~Ď(5/8]=|>Vs ڃAMR5BIwP6+/H4r$XȂʳ5gdfzמ֧v7Bڬ`?d^{Pe$Lq}[P~#v'칪2 \˖AHY2yaFg6fhnK)D醂Ef}b}$ 0^.:[fo/"F(;Q4ܳOyVeڳ~"rdpQ 3Jo/tu31)L7^M vJ 5TUYaHzˋǀW0Bۃ87Yo| 6^={7_1]3}^ً;ĦzϞ{#91M6 3}A|ymB'{ٻ߇xn)S ދ4dEHxa@u/6sxYWy7^D "lAtJ, J[I{62 M .mAF"rdfnÌ=q/b9;%w܋"W7<sϽ)9zK{s0R={J ؜X`{I)CXAiVhc޸EQڬ0cg${vj9A|㞅w6H ߞE-yg_M W#n{72 16'?q/b,߇70g Jc fj7{n{#uދؑ1#D /){!.|p}h*w݋ȅ6F랽외,#EB};Qk^q0R=}7  lHO#3MtAR\<(#/HcbjS Dg`ݥ}{PZ_Prǽ)h9yaHLRtM5G? //(^Ď1Os/b?]~ }{q+cm3l=wO ~ !`~ՍŌ S#{Ec3ڈ0  ^č ,x3?q޽zmVW0rǽ]ޅ_#(sPRǽ](Re"ʎbs#ă„ٻ'ckSE}j8gk"G%'qQ A&J}@FkzE؈1]slEi2/8+8(^Ď)mV3r]ks0"_t:GkKXF6Fux,aYaAI em3{Y |.^g}׽:cput0H UFxnMr=$,D0r=S5˂iï={E eD3<ڋ2VIy7Iek fen{0A 3Jg#c'B 8]~<-۔`H"w܋33| F#jQ;svJ Ej.Hf"3׽\Ru|=\"V5C jCٻgb()͙r罈\RYQ4gO9a}"`JY۬0㠤{04pE)/ ^DB 3AB, t%]E؉cC$aG{U(c#sؑej򢜝9aBYBMQA9aX$E  | ID:#ȑ1c:!qøp~X j{% kI.̞FtW`e^Id{7 &'㞽wS>QERw}`^ԫN:a ºgcuk = ?v7Juk0=0(#Q 6s ]?xWK4 y;!՟$l+:ȜVs׊4/j8zY[1CLyHL̹e./Z"bŦՕѺBX'H@ؖYT,]}MlËHKYPgr#)_ dH-zEC7o[1UBQXNq/#jQ!H_4#gSNSg/U{R܂a]2*VXi>-U8_=~hq*afV4*GmSEzbEG{z /z_TDѽ֮%1Q>jea?gg~b5giN'3MuOl)RZt'5uGyr+ʋ.:MPw#9WYg9Y_/(6捴jJ[I|W!LG0EGKn-.nP?Cqڥ}X 7܇ guݨgc? L_vcwq|}fz^͠'4ZkhsW&U.}]2=gq]v9%r?f(g^ϩ_Vv;Nһ/X?59`\F.U|~>#^ucn1_tybJI>Yѷ~3~~#teމRTwP6)/k;BSW(3QlPN]YL({Pc5̃}^q M$LN_PBԭ+4p 6yIt[y݆MDVpjndYn'-DJ;px \:*C8N+mqW54.Mo vfF4e~@I"2e! ^r2`憶Fχw[y Di c.}؀#lw] `-n_I꼄ځdfoۇXMDF;0؏/us]CRC-Lh!(5UaCNX}"H"`Mv @YɁɐhf#5X[s-5c+GBhFUz H@SӀƃ20ya,ݩ"eR ]Eh&!Yfpv *ʆv`rpJ2K;{7ߪ(Ȁ55Ua*{"b4ϥVs]l"jzbb#Biy|' eu${A_ CFVb,h͍^m^}JjB{D(eQH #ZQ_<(T%hFنp屦 zC2)9<G# CSqDK0Rk+Cҫ G:!%4MHfz&xtB$SZQLɻ#w74Փ 'h &X$;6ɄSdհC؉] %`Vݩ=8_ B43H2ኹԞebN3ItQ a;2梳Vpm[lNDcx4]CSʰ-Kt mCXiMl+tkh5[:%~@I#vU(7 ֍*3A8"'Ļ ٓڰa/4 Ua`"f?bqF@0i"F1tOv^f8m*dW\0Pol$ǧlwZwFۦڹ}L `bSI| OH[eR8+!Bd BBhj`v0-4t2ab+FudP.R{6@y{܆JݚP2n)1L'(Ij"eR Q<ܘPJ#Y4L':#BRoiea/7u[1#Pv#bZHVCU^; D$FZw)l>pI漌گd* dwƍmkUUҟT!iEkJkQ},+B;*36b,m_tx e"2A 11g+[&-xO+I-/Ku*1 QA,؆0}! L6t"ƌ8#wİǕ{Aۮ" aC,%C#ԓ e䞴0 0!c#u5 /r!txw(2vƲʰpnm83"F1gֶʌ5+ mD~26"HuavۮU^ MF3Psmb#XC"! UaLĐcKhs>eFJKlC+K>{$`sP N؈c Fj coRyݳ1C> A0dɱãHzM)(k˄K,D*$n.˜|cB%^z#Ud %p C6CoMYa,؊^l# ٱQJNH}MJ+{^bm; Φ?v狾>Df"epńJ0C @jClB z;!UaȒcmpc"&b4KGJRfԭq((epfbjN]CW(V>)3me:q6n;,RxzѦ&ɦ{G[&(9tRW6zfa$94p \ T9#n߇61"˺qZNNALÔsD(D؉0b˲hVOYlvf"ЮQƒ_ bQzWFWԡDrJjBXW3nQj#LʡpuXXXEM[/ %usH(+,Ruw>}"31&`~&ʌN:tRXX.m/ex4Lڔum{AW[H 2dv ԍ#i6#0&"XQ&v"l׌0/jf0ATז2b*)+ -,=dVow~B(HH-CU[ʭ~&b4幥eP E{(eݰnb˜ZcP̟uyۉh G{&Ɣ2Fbja @jZW'0u>1~kjB(Q~&mduARP[3dMt<ɶB~ݡʣHudtA5x(EmZ{uu>{x.2Ť<;TNשnԅD 7߃!S1##yKVNF #rdC)}L((YGQޥ;~|[=JZg)YƆ"oQ5A4G]3YşdPJrdF[UIYJV'ʗ[) em)YC(ksFZMz%D)n}F~|V4PV'͔=VJ >ao0ro1pKYDV]ؗrC[JVtstCJi (3JVįLO)SN U=JVt{)kK罅!y/QW)Y鼆2>)%x=tC[JVK+eKSͼL?Q_2HݏTѵ?_PjgRu+by kJ~-MBZ T_eXP~|G%e QC-B–dZM–jao Ya K2TY@; ,͕C{[]JRHJ}RrJR u{RZJR,,]!aJR us~C:d-b{sDR< uߥl-%)QIyCҡHI~P_Q)Y 0QQ-%)e{BJxe{^/=/I孖|z] ^,=šzܾIX \ֹot[%fp*YDfP!;J!Lot.a.AUi3: :[aQ?a܆}uq_ۿM?ʹSۿ:^ֺ/4{u{y,|]?G} 4t![wL 1i]y=stN3Y[+ǽT Ki83>?/;c{/NS}/?GU=7jW>d7&FWCJԊ.v$r~zztd9U./W|K}I |~8 B>0{9-?ZMr~KAS쪱AVߘa~C<0>F1k{5?ǟןr_f+>$BRLtX-4u~z>=<W*UT~jz ׫ c5>?l=N#lr09Vv4㨇:y]{=~ `zkxF/aѓKgfQO3ʚ߮Y9iWVC/jKFUk/EF?;G?^} K [Ez_j㷾su/3^;z0x|ZNejק v=Q_?C_PxcS|i~hXUmOZ(r2hCvyTd3|UQBF:v4Wԍ\/>TQ~CcOmAd-X0d> e㉼cpā#o<_-Cue#ZN~TGւ2y0t Ꝛv@,x,-sK[@F/+Z+vʂ'ҹ8-A5 C.+^6 }W<U 7i}k3|ܬxBOr`l W)^ ^ džֹ.:K8( sahu(xa°ct U pFzdi\!l'0+;{`]kǁׅ vʁGѹ.@H[]6~zEௌd3 &_5# ׭Psk3L׵lDHn%[Y &底Kֱ;[_yTSi 4<0]?M׭$~8"g7_;s|w S3NZLY:nGC+QW}9>Vlt٨wV:Ou((Q6l{\.Cdj}=һpY<,t)?g[!͓/s|jaYR)~U.rZbB ˹h|=y쟣vu?d8\8=5A#qWanɓZmoy4v}h0ˢ呋䒙Oԋ= ê>I/]+>Z=Y<7).DR_Au@Ъ&}:^WydnhϸI7ra.;Dg?ׇ>~r6]?RA쫂qa:VhG=o|пG<[emgEYg{YhCk,2zhG~}|Qh~"Et}F Kdd?-^| ^[Rl!~5ꘟ>E\8~(vW+ɍ=~K/_'h6>=пum~ċ ,S)lC3c|QzF"/O|yN?3M1cCNR=Nz=nnE>8:lfė|տn~w\_Vі[ѮFk\6~ǀˡ?'cŏQ;z{d3;ݦj~Cmlh\ ͷݐw,>߼cdĪs fڵw솿]io2+=e_5g2HV۫پZ 9w=1l6yƜc3+{ C? nytEHN+Y͋2kkPգ@~hkFe/_q^M(zIuT\wC>MRl:?PO?h?_[]~nu8\fIg+څJCGaU"GH #v  DB}r O(u[[$q8A,%¦n"Z8? OV2+ M~\ CU ԭYd9$ :VØ2Jː.lveD[ꏷ am'8t>Dp-*QLVWuN! ne,jl0 W-c;U ]?^Q nA}GxiCǑoQW8'3rn`H؂01+0> ׋܅rwQ$~Fn-cq/`4n*c[nU\30Ud\>X!O72ֺ5}!OQa `C^5+ ,V 2Vex,/cTy*:_SH{nP^"Yr-T.2]a?R{naNbWݪgT@$8 #2{n` ŽYbϭ u(L_s+-T1ԷPAh]ga k-{,Ҳ[&2j~^~KPOѽxU)`ȔnnaRcFƆXS2fd-ņL26+ \U"cDƂuO3t3" c0Fdt0u[e05!c)gpĘQgf=ZJ87nV ; !Dƙ:ӈ?Do-a7ne˝tCY۸u^U7r^a P@>4`pqFa6nPzPPҰQm>W(ipyTsK++3XظU Cf8l+X!Clb[Fq` İek2k[Ϯ2H՜ b q Sq;ˈK0dk27y}m*"FA^@72-1Fd a8[#-6*/".sdiJ.n! q kSA~Жa6nCꉺaب8GFq Fa6n`rg(ӏ(\_ٸ%OWᲷoeFWG0e[PH]pU}bЗ6nui AR,- ŒNUڸ}Q!Cm*T!:g]vR,6nclUE^:팕3t.ci5!m*T}z}8XncDU;AB|GCpij6Q?Iz:ƭꛦdgG8?h6aWՆ1! B:m`pM'ї6nU}.|9Ё0e[H~= #0J8/0 2-V ,H(WgjhVVM WVlWs[]a?v.H{ŹmcV2kJ3t[e0l!/[@%2-1Fd a xQnبLKo(p./m"Wg,0MחknU4 5Y9^q}q S}(Cڸ2l-/Ǒ8AٸUi -=d8:-6" a_l*c,گ8:-V",A(H؉"AjA&(GJjll86npFEjHr}ײ \p)`?tranEFu WGԗ"Ј |-02> q.u@EN#LHVZ7M!u V_;!pBVGWgXKjaX~uǑ8AK^RD_`+Lm֭mV F- RKdp$#X c',ZJ3Ml׌(XEldQT0T-r^q4"J0M$D邢q8R/GeZ,i2Uɪ9S!A*(vu1>?>ki?jOuWꟲ?~0 {ؾ?^a]}+o%˱o-0 ZZ%&3RKsGbgl2{ƕYX8j`}yؔڍ},H<&{%Ƃ+2_4 0V-<P75>C۸U C* &+b q SEa p(Ȑeˋ tV ST 8\_ݸE}U6GO?>Y f+WulvGNs4q>&CSʿNWGS[/.P0'PF]ٸuWD}9>z#`:-1VeHe;1*?ذQI:tX q{Ø]3Jrͭ2LUQn.B>e+bq0l1#6p/``X" ^XZ q SJ=Hm"A&$H@}jV7/NE_ڸ}] 5?eLRQeC\)$e[/7[G|FĭE<)  qO%ݯlCPK؉Vn*?sU,WVrҟQCx0B*ZaG(t q \32*\o0d[e*00_qd[$~P?}0UZ_@E q ;k: ŏLRQ^t+py`J؈=Qmj/1M{JC+­Q:k?+ c0}uF]P䣤8m|(05n1=aQ< rc-ފ}8a5n`HXAna$ΐa5n(!Ն>cȰʰ )\W0t`[b,ʈ"RK|+b q S0vdblvQ5Qb@TЭ'4 $2ƭ2L)aQBDbhK2WX/mܪ(PQi]Fy )44@q N_fبё/"? uJA6n!W׵!\s4M_ٸX?vn:.`CF5n K%W135naXQ@%2-1eDmbqq S06dCٸ23kR}`@8įmO&hHd[e*0R¢ 2ma'@J?0]q kFy۹v މG`ORc@nvc&p;zQǰc`XW%{]'^Nzw{0| /)tq7qOB+2ꗕUK, /[ي+LnlQZ}XJlĬ*{۔yl\Z֯fD- ~YϨZY׀/:9zc*^[ itZZ]\d|qF$L܊GS~rϚK_ctЮkŷ|/_kEvhL6 P-vikRYQ^1`/y#/V#pS`EzvJhE:Y)P\ Ŷ&:wm/p'KcP.0٘;AqX[X/zJ:ҝ/ů - =Jz"~NyꓷWQ1pɫFJt\=Um*oW4#Qjd7un[b6n"!lj$j4I{|)a={'VN-0MW=f}|v3/w|W"sh{z~pp=P^~g|"◻\<Ò׃_C݌q>[r0K^8jΟz@`9puB*Iu]3fz T@O(xJEԡ?~Ù!A~In-B`zYġvL^,]??E0Ik2g36$t("naȐ5%3{w!Ƃ,2P]V\5Ru޽g6;"+RϢc1"c甸3ESZč9V˜[q F~Ӟ h92Fd6 [$n#6D_Yl#5NS3 8ԵǷP.ꖠ+gmծ߉~ UipӟP}t"f$hǢ;,]mr3{F pZ >Eyq a|8OgEȘsJr߳AIreY$g4P~fÉ|A aŸdut 'j͢F=k:go MpFȝ"f$lH8 }߳ƮPk6 gtƸfÉ!w=w,;#C5%׳#2vNs5Bzfv!qͶR߳ 5QBԟ/E~0ŠBH 岆cEwz~/8YHؑ\ s5Lk fT+ }EH؂0R߳ dgj,3D\0I],bAt]ST;ެ`F YD  _>Z{Ifׄo"ndȘ)Q/xEXq }ml~tByfEG"Bbr8,<+HX Qnw{]2rCƄ5gg92bkFF$Eg,@|%EA .t g72&dF=ڢ=7]?u>]?Q̎ggtBp7ȇR23W|Ux¹x /ׄ8W'dga-vdE:Kv$ׄ/:yT}}.J33P=iČYM4]ӡLئzdYk6ܑ.AB/)!LD; F>Mc\W-s=wQ8%'H n!Ԫ"y `d0+:}!hkQI-y&24M=>Q|- ,Y|Z=!1"c8S'gf$HrM,R3{7TϏ9خ)^EkPeǿ%")7 5'>4=ޖ 5}_C~iBu{{-FR%z,Fx$gY_< ׳ZR?E_PBd,H΃{XB&$g1kBS}fq#aG‚!w? f2v9g726dLNlzE'J=;="['hw \LM?wAz=*w-<+,Gy~f;'9z}6k"-uAKXJ`g.P):!u=P|0=\_p= v$,ה0WO"j!H +h ԍYč #0%白cExM F{ C*|`5Ls5,F}["Lw=E~7C˅St=>,"}ysS`2Ĺ{$Ǝځ*ִb,7PgF| \0?w-: 2kRԝ/8E yVRS5B})%̢}-Jݫ~U,];=#͸vMY.TQ?u=Q_Ouᱣ0KO}x|A jY-zej0R׳+2kQIE°ds+R׳ sk",=XEwYu# N5o\"RCdhi{EĢ/~:T8G"ׇFX9 㙾[2NYČe0Yč -:GpL F| c11kRog0 $LD8>Q^{j{;D ijA3 jGV{~|1wk*g2ajC.풭tbO$bT/$9vtfV>u.)Ur{t}5!`^gj$V;½E c_#)`~g0Lv2FexH:J*=wяp guYv+Z%25B…!_tX5k>+h0]Al@I7hO0qqJq@ a(1`\ ,Y-}gbsW1%2 #?ȅq d[Ug;f6Y ߮ qN{EȧlGB˧gr憎\s$M=w=>ߪ|Mt"F k2gfelGPaM>0 '{-^B~f2i#UXJOd;E@ɣkBrZ˕]LٻG B&!=3M;f~ED:O׳_P~l]><3M;O|v!<0A"0!-z7E@HG?#J8MBF;Z's}kq|U8p1bASu-a [tٍ_fVVmlBR>d|Њ.s.: [f6PAkwus31'-[%n2 2d7(>^n,fSpdՍtuF}2Ve.cK{h\MN/+6VCeU|jʊVjqZI|iU-R"aRFae{MHAe~z}ǵ7x5s@m-V?šA-fbdNf5McZ-]Sّ a 'v3b]^gBu6-]vly:J_QwCp#PY*b$G|Y D3OOOE7Şl5"{#3ȷ~~HǬv؜_$GA1`GFIQ{i= ƹ;mrqB~#&rm]xz*jkiҵSbm6t}J: j UKC/՗s\}CPJ[LsYRKg$\Oﻤ`ױYWUt35_VT7*_Q׫=bΛsy*H~+qZB}.H8z$rCІBUaZ ]32Va)T j XZ!ٻWbhȂ1g鶫Zz4}80M}L[øp8sg Rk`W)4PwϪ#2AE acB(2h3EpB؍ ^aL.̓k"A L'\Ƶ w@H,_[! v21N2{*TQ^ UWXK8ֻvcq2ա04 M$HpwF}'`ljgG;jAz#3{DPbLB /GG-{D%ڌFZ) ŴGW B8-WMy̏4۸[mW6BAn\)uϵ n\ʌmІBPU)0JBUe7aW ޺nRkP>#(H{2sȌDz}0Sq!,O}9 |DF@9!0Bf0fҟm*Q/d.2AMBQ|j1f/aka!|>c7(| u* Ua,ŒnR,z*26dW ԭ,T֦J ;}%m:y3]UqWl"1"c"bg* ytfI8m917!]n<]r>W^KP53e _Χ > zE@@;˲)q)S 1a3PߟG R>k)ip?#,WEbgfB eh Pyp>y% BpYKL^}Ƙ@'è m<>(5M&pjn g0%…pBj g7=V=]E8Y.'MYiyҺY;- WOB}@{] `}jb#pS f"UahߢZ@^-2V~!y1Cz]өn2_q AџP-z9vi.j%I<-qL+ԝ˝i aGqxg$# OL@o,.3V^ ;{EH 6b|]eAc..s&MS2vDx*ծTQg;.+ׄ8g1D\ aLC 7XWDpqm {ӝō pRٶ6 9Ѓ$\m0+SWBczک+UzԊ>fPsGDQ4ipK]Qwx2U!1V Ĩ{h\U S007-gפp/Ʈ"nٵN05.e*cI1ݭ_ C:k؜ b ƍg3jي+v2?@dЯ4 +"d1sghU*1#W!k/vTVbdi1. H<\>tͪ_[Vbié'gџ=z ed|դtK'AUu9T}@%{%ƒ2&bQj@ Xw1kfj@;}y"2˴xJjc BXwD/]a8 %h aU8!0BaF# k:U6?(WUJ(*33LUrv>&h a\u氣/-Q*x @S7Mw!†}iB'aDi#LpQA ΃Agm;VOZsO(/;^YԹAg1 ))ypW)qXO(3vdV z|^ uHF çj~z%+BiQb"붷+3EfV֍vq 6* Yc]:X^ 3D 0aF0`q2_qw2kL(3 ~䎣)cpwY)$RL G}G!K£t0C;vZlš>EYqi(xQ8!-jt" %d'$*if"U\YO"%ebPsS,7$DH^p>3 2+DhE!)b\U))wMTCQ b Fj%+2!0H/ZHbN*4^#z0rr 8O=YCZ>6G`#k1'Nc (1 nz7u5AGr`.ڹ^UűP X#*"05E_#;BPWjG6ƌupORRazFؐ1 >%!)Y}! 2@mW({ˠ*_2֖1"cJl CC=H̆& ]G]nPܒXJȺ8 5w M!-a(ܯ8E^5L]?u5EQZq B0}aQd*^Fh'cA4 8'vY?e,Tn8+!܋MdC91/7E^ByV)pMsM 2k>+0fd{ 3ph"aBG0B(Bsu" }Ga4yr"ՃD?{\up"ԤlȭCU*n[!#1BnLl/Kca#1 [;PABUd>c{N+1vdǡ* Y}p c'T"c&{A[x"LWMNB͒CS@MgI8%&f wvg1/,oyC:,jE_,iσ.! stg94PK2$uġ3QCS3G[6ڿN3,-X`=mUd-v@A.}ƊyH}#ralB t"cAxR,鶫53MMMK 6LD]mgZHj$I*RŠݝmyVh"`vk+.w"س>CN}]mlujLV񗺳<`"9ekea^"z_Z\TrY\k W9ױ_nfKXty0}/~ RjWJ' ORRܡJi)i9QvlQ`RAVV־R6¿KbCG)~(T:-RW(y}@ubB(y) k煪ߡVVR@L)(iQY爩B1+i+ashC[BZO(Yy{2!/)slx 4s-%|LүξuSDr> Vy͋#(%-|"%/(v73YE%x9e0/*IJ^ByʘsFZƜsUz^YXNji)`S1oHwZ"46WN '$ITunoGڮ(~+D|Mq^%oIuAy dW@R\d%q_"@ZVTlYQWkQ"h A "+i^1ھߟ'hA _%GYZT_D|+")%{( Z}E' O"" bU`_D$[A:²6|O"}ElOI+b>"+ #G`*vk.nw'IԟD$S1DRTT=,guJ__n}|VxBmݪ Ԫ'eEs Yf%AT}1#WX7o!z=R? 4go|ZDlI9Dd8/x.Ry'3D<9O g*>މw ^rR=Х+^+q7tV%[KW8-B7vͤtR+5P䝼Y/> ):QA26Q")TtAdA5El ^eT?)xElGdAs"?Ȋ"j!JTE|[}DRY9+b!v[XDVXH j i+by3DVG'I!AP4n%AKE#rYwDR}đ }WI>P}1p_a_;; "15%HZZt=Sz~U>+c=|V*?~#~{[s?-IĔ#U#.bzHJҁjrV2J$"$wA<LRr|#kbYM/P JZDRҫT `0(uEQzAdGTӺGlo!Z}ElO"ZXZK5ɎڨKz>A$~" -DRtUE-");)0G,đ"Q {DV3ؾɪ?5m:'Ş@3:OT>)|'fvoׯ5lR\m2nQ0W o2V훀7ce0BʸmIʸL䧎Cqxlu&Җ2nP^ʸ=C3DGq2֤e$`=QGθߔ3n]qCVE"mK+noriAei?%#g62fƭE\G˸~G^q8kԑ2nDV#ev?@H)bBGʸĖ#JZq)Gl )[-CH2Rƭ o!#eܦ[-SBFʸEĜ#J7:BGʸ)㶃X^؈e{V_FʸEr":Rm1w)V{]s2n#eܦzXBHo"{q5G9bEDMGz2Vƭ 1爩Ah)bBF̸E1Q3nQyIe\]v-`u[s/?2rm*_:ӝq%P cfܶoˈU>[qq1eČۮPVQY˸1q-"^y)БZ6H?8%=1}916x?y~4?1eX-ۿOӟ?Ywq?71.Ti44s5[3{{,Te$33ɵ\3#e]Fc9?}i맼uvfp.|]Ku}uZ?u]:u?mWF95^}ms|^kDul-_J}5,uDd}=9p26}.z>Oܚu|}ƱjX[)mϱrE|]#aHiGf#r9W}ig-<}^iYk.[_S5z|,_z,xZ6;ʖUM˹تxz,Q~*HskUźiFqFZGijt\4n9nczVEzc게ދ竕_I|5Ż+3^}[CGƟ/[})Q=[{H?GO7ң*c_}kka[`{3D55J=qkO׸)K^fɿf=&Wx[^c:ճV>?Rjur#q=.z$usW/{UhW߿}kc7Q]_u]}\ɕ|kןouhZYzW_ԿiקׇmM:)`LygDG1m5|ZUw#ZסuKwo@Y_OE8]Qt4TRR@w\N.:voSD%_~b&{hF_r鯕Sc-t+4:[YaAVP;y 6WS#|lJbHؑ]_١_<3R@ABYס4t"GNدy@E);;]Svꢝw*/)N'޹4:a(92}]bg#B OD U:cDٜ!_x FtJpQ5F1y'o%[և(+QV=[(:‘%']AhQc xU-ݯ[՟z*?U'bf?:OX3{²x2jɨ<ey+2׳>Mt,<7멾=Yuu7 E^ջmITڞĞ,Ɔl:ʽƓA㖧%R4&퓧"nұ~EV$Es/9|]]?W]f#.h'"κ2˳]dݐI$gOBd Y`՟,_b/Qj6磯HOT0Lig jcÞy3Y%mO_OŞulv>KFHb_Nkʒ?гUrNKBoS&}.$j6]{ȧjW a_6}bک ͶUϴ\_J;~z[5\jەSnVtZ7ϯ/c̟&G}vgǽ<;'zR~&ߒwT>?FJW >hWBزzXjyyxyCi>V<_:'@۳kO~󝳏}*[~MUS^bAcˢvKG2ԣg>s:ag=G=lOV=lCekMkӾ9lCEkAfߊ#rOUk@V]^5qp\'ў[rvzAzeKnG{ܢ%N')zfm"Co[O'/{S?X=i]۬:V'xפZzI:vm}dNyܬ=Wn ܖ`ӛEz^&YztS)nNd^Oƨ^7#}P&;^Y>u6+W}凲*oؔDXR)\KKojz[g7tr~4Qis.S'nR|M֨>t'jĶ諿Enuz,V=d˵}A{D(XW3 Bޙ_FMnϘN2gv nU~kOgqx{譸ē˪ם[Wqm->۷VrɕJW{w!yl}C5&=NAA'X?=83ǯ~A[)wR/$V۟:~+c s 2vlk& |AVrK ]0!sX!cJCA$/c܂ϕ{ԔdK˃H K-{I2&`DEbq Q[~+!'HAceENN#Ctsۥ,uKO6=>Iu)[xW>{CqKn WBXU>g`!x2eǯ$&)2-[.Rē21n(ԭR]}ϭR Q,YiW0!5؅W&`İ[%x[b[4+c Y6p}V'~2H8Z qKJlO? `F⟃q+`UUL%B,N!%5 qSLr1)(;Qēg  q 3!O;ck:|ǭ2F18?RF`oyK0d[e0k#D$F;ntzT BU La,ΐ{`Vyڇ_=@Dc֋ᡏ1cF16%DXZ^Kt[]a>y<<2ǭ2D5ʀ- 2m0AO/t[%0dVN%b4S:x-QvV(- qkݲӭc#2/clP2r8L62l-^J[mnRgoSt؎[.R.e'K)D9b3V)+<ekOP6 $:3rέ2vbIQ땈:C%DKKČ"yҸS Z?G5F,F=neE~Uany`CZC<]]%w)Aaly :-Qv]Rzx*e"LZo%bΐ[lP`qnd[egT; %2|-b[dtqۥ2;J--OAȦ~йHLM_U}D®-cOB%+ ,:ǭ,wF'3 z'''zJ;/$xe22ǭ6߶B7h AHt0[b7%~@݈cnR@)`nSt {*CTpy~%B,Fڸ*Tc-cx4UKوw(SJz*tb'_1`HWhPP֖HUzV ; e4.4'VZ"lDXAywFV*n&%Ql~ 1gXRjos[7]JR,2C l-3Ŷ2L5RZV-"1}I-uPJ#,)aBUVj 1 '/I+pBC۔0X]Ll!B8;~]l !'`J,+5gOkà5gV)3Q^ֿ &,)%A)v%b4?-R?%UTK>6"HMʃ!ycFAF˃} V%uH6:ǭZA*WxcSEq %b4NGbĘAnI/mB=yV* \"GXx7`D2P6WUD(k][&f(QF,-v`irER.@LUU0f? Q6,-EE2cj󂌍y*TUQ_cye'JA cG q0 +:ǭ2L08c qK ~bI8CUvH t4]VD1@p0Փ!TU8C S  qD:VKKht@[J%RRLCVSXDVW0t@[d(ˣcjX y*TeK? b4q} ZQۥ`qq4z>CͳU"c |'DfE-16e`Ւ:EUL/(; !VE`i:m> V)+,b2Uխ%b4unwS~e E h/#6 > A=vv;I҄> U 5">!uY8ӌye^m$qLwbi"8^j&TdSafB7t2-s2. !ѧUgv4scnD2A3s@S:z_,=^ivnCQhރ@ֽgD'2T؉Xt/95!CZ E&Le>? )Fˀ ܿӕXt&,U(f'4aJ=8^WwІڴus" w{fob'׵l`t;`+qBWʻҽXW߯Y>'lJ); qpQ\ֿ_n#:L"p2"It_J,es''yyϛi }0Z͵+?_=3zqpGfGǯ7)f_eǯk<`ɻHe_=\incģ.dEڛ?u\^prq+^_].4Q Xq0JH Jpm9J,ݛ30c1#ݳ?ƫ,| UFg#:h/YZU2}:f%t߳ؑ1+UOvYJg#es6欔؃OǂYDap \,p`^lYK 5@gaL">b>")aF v8FŒAnL>h6(Ǝy 2‚|;T޴OhN34؁)ۘ iȃOuwGA/8>|IY3`ƘX -U=tGY͎B7><;횕>y ;}zS#>Yj 433#-^ gyaeǢFZm Uų;;$G`zÀ޴"؉sI{BL)v9% ()c^SFd HH@\J| n$lJ[;1V@Љ&M;(z_ UF*t8 - %=(x>|92-'M|cAJ\ rdJƞÌ-ȇb' y|C=&]̬6$`F_@):J)߼XM%G̰QBG>)(j)Q" ,üX٬3EQv8ƾ|7ת] <鹖;W> Zw]aBGAw}~ׇxf#Y4QU$fߝ~; 2Bŗ,-]czB>g|7>|wu<Ƭ(`.|;1dV,s+Wdw( ŎQ5/XN +±#9%؁u 36Fg^_ŒIHh@cN>|5ec^c!wn|,ndTخ9aƘ{YI+-x h,2*#vUi8 c Jg#euv 3VF'r t,+8 1O?.+Wn|?}bޅQcw c/>#H+.|7 3D(!vH3ЃOFB!$ `?|* z*}۪T%bi{WƅbG(m s6Jg%-\ FrY'_ǎt zYĠWqhX=SkF $vd4cALqU<E)u]2Gi7~|92*0)C5Fg#CdA%+WEN Z2᳸@+ŴV'Xb>ckN1.|krv򀄀Ѕ&F_̚i10&؇"7{JŒIĠ~y1.d,؃"Gi 3<> DP5RZݷ)a},)aʈHU*<难({IЅOF}X&W.#UJE1LA=z)vೞ#cN؟wRǬWI"3rq@ H79б5Kujdu4IuQcqQEYHa \^2b/9CAgCVsFg+Pc@V2gѢtwup*8YDTFU,07eN|1mP4GƉOb'T#;\ڒB>c0c#t؉_"귐\ߚRb>)Q13(ER=| })` !ȍy9aE'Jy*H9DG tBίy߸ Y!n|70Xs_ejEN zw8JŒIh`ȍEN @hIŒ-ЏbGJum sVJg^c!9AS(#E1/YN r.8Ƭ0ccn|wvcVg}CUTI~N #ןB]$]e{qzӛƌmQWgO1%P]kAuʪc$(n׍Ŏ霴 sʍ#ߜ25g|CĠcC1BO>0>4#(h;:dw%3Mc/ȕꛍe+ؓOOuQ/ %rA{U s?> śc:J>|0tʾƼ&_sg#:6vflЇϢ'JZ;/3#iU7>|=R2RÜ1w {$0aC>|8R6Gi7c>(: -1OBs6Fgu+؇Ok(;8IH,΋@l 0'UC>y8e9>|71TW%tؑReœY脠⮙V'  !?#.)L(N^U'[5~ 3VFgnj} s6J'\3^TYQXk1Rtoxo";Qj}&z6>|HƜjs J8؇z(Ts2;:慽jЉϢ'Ը$&啱9zN|gl<%⓽SG#؉y %)UmI'DSt IĠ|TkfIVc'> ;iYFqCUFg#8z7EN}їdq1'E Q,vE_PSU$%\aF =,zaJ=doϟmy^#nCe s6J'#CUd,ؑ"?yw4jEǼ9Jv?> DdA1=C>,L}=MnqI7N|9RVGi׬0_cN|;1cǼ0g^|l&JYDɎrt2fY%cwN`%n|1Vu˘櫔БOc'kǼ c%D~|91;>b$(Y\UHq=%;QϜ ; ~/4M S? qy'OZ.bt>#oz2hi,d{~#V{i$n/1-A}Lw* Io/se y'ݝN`RW_;ro1=9SI\IF?Lű+"{rF˨,yכI/!5QYboQ~;G͒,fɗLLFl,&|;o5_^i9ƏŽI]Uo!wwrUֳUrFU 7, $,j{oU)7b׿~_LY3yNp 3_oU_2us?~.2EELLcoEg9]('@s+kyQѕ'~eV80 KW 5^g/zY۽|9cݩ]l?DGfjܧrqt5dGYeS`j}l! mL14[Wca n.hsBh%dP>]2mQr8݉s 4Сv?wI=97ia[ԑM ua,z\sDNed S]yM~v(i͗(醂-ї"/֧ ` Z}=I,jRڜc0gQ1Kf gu}A{b}1W9!TGH!;v03Ubl :eǀ09ßG[;4%JZ_#QJlfHIHqDah4)r(  :!Gj*}^Jx$Vh#C1DfD9ohwe4XP9Uڜ5Ф1 7&m)$Αo x˛2B6ٻ9 =A_x xщ⛔,MT=CzŖ;"gbā9FrMT;߯#bNCQ(Lƀjlg#X173I;0fqFhLRSN@n;DCՆ=bQBq.#Θ(!b6 / {op^b,TvRxs -@(4/-(RB?EJvuJx.QmM2xw'p( ~TU S_D8L]yɛ2"@P=YS.L`h4l>*G `l4hv&l,_Qzl2#Ӻ14Ub "Ң{)fpcH4$GɎVo%/ٸ/P6(RbBEJ$h5˂Ì,bwAf,Xh9tuhuAb8Ho 4E2iTeFc!?+u)2ti&sʍ"E:y̞(ΑSt/IRTIw.:"{;k϶X08Io=E"ަ3vg)'!- 6Kš}},fJ2 @;hB{R~ *1GH4ZjPg;%'T'+X:6 qFEM(y1Zv QBkQEJu(xi$Us*&U'RxO JETuF ثTCG58LL(ge_|Xˡ$BR{c:epQMJRRM T]ydqk~*q'A1v8xqL啾 `f*n`HP9鿯@5.țbTS%ƶ#/wmTuRIB̈-XM(i1]Y1&S{Zx)v}֋G[GW%JYlEY3 01wrk? 2FjVaU{5_1"fl/̈́EI,e-bM}Sb VTWr !DcsXڷ] unN@wZZvF1k#DF)ˬYLb0sbYQwZu䍱YV wcm *skTkĠUTBhvGlUkDI N(%4H7 X$yW ii󭅇10H2J~kDո0cjc tLZ芪XBAnH;b ]E(QJQJ`ke\b `]%!Z[@(]EN xo PyȰxMdH"@X; !v6Ud4(#nI*K'y̥&Y (!hi1ԁľeclXt=8JpQba(9&fm=/NjjŲwv.DwػTq j+Eo\~y0Xˡ Q27݉""4@U%br[[;wZ|8>3#Ǥ*#EM}`p9ط\5?. _(!,}7GXcóDVRW]h wz#p~!bQBdzjHphT(h9"ew2X{ŜΜ(uDQxQ#CJEKB'-k:3Ts@Lz^⋥V'9FKz{#"К4@' }Zv DAǢg G%z ,-!*Rׯ̟G/0EB$OAǗn')OohFeMHTmƪ,4Op67y6Qߓh5Ȗ"1gb?֬Ȼ,8u~эG)M+% %B"xFJXtg: +E_[QbWʦWq}od̫(ne??ڨ1&_@?._.>AXŠ:c;3oPpkJ K_(apQ kLUU_oޏsaInODj@ r'|}{S(a-[+jڦ1{)!a a +}NnA!1ewST1쩔rR浫}h" "cO@N+%,<=@5(qiӍ)DŽ {e^1[a+>!%pTj7aTRD='{@',0|RPŠ͏)IF\TaH=>M -|,fHx_Csu#%l3JEN \o)kƔ톂Eº% %O 3JP(VJXX8SJ~D ytC2aa/PRLV" ~PŠKJ(UFXWUw\W5Gm<~Tڻ3}{vO z—RuD(1B: A ~ն}Z~~Tv}A^։×"rL!aCBTT' A~rƕcg Z*넨j,h =$` +hBh#!*zK~'cZߚ":fR/Q⪺w"%#%* 3 -mS>P/QpkJD^DTu|%JXtc1F ~r%*reD~+%N:PhY%N 3J/O2e~ʘ}Pr/2ʕ?a)сH&<zha22ט|RQ"J y7&"E~ %&Ɣ톂’/QpkJJf/(aLEe)Zߋ]R\ɨS4aN)Qo*bJTt"vXGFTiaIUy³T?0@=, =Q)HVT'ԯQ HU{u+7~~T~FyF'.>w%,k S/b@+:9q}DЌ5$lH#vK!!,hHaJ[~a9CP &+[SDTp$%@S;>P%O)eZ<DcDA QտoJ}Hi1%t"~C#%*)5}OQ')aRN(R y"*P(Q<Ѝ(3"짌ȷz%%!Ŝg p[y8Ϸ/3pkF<~? )!-SJl|( JPRh8ϷOS')<)e}Hb ))H

m/Wi8ϷOnwQ>x8ϷOSn %&poBB0t?)|pooWoal`{p[!h8ϷN<>MRh8ϷSRC ) PΰA)=B۷n( >x8ϷSJ )Exzׁy}F<߾LQh8Ϸ7% Q P2Rh8ϷSJ =2`ÈrDcD4poo(eJ(<[G)LqC)H<~r)ǟ_z笒?Vo߲v s4oߗ8oXϷ}֏?˿|:>jcn=J%;+`Ewi*kfȲ^U!\_> >Rρ'vnUmVu[~'j?|qR>?~SO6'Jl3|g@UL969qW3g3Ozi7*zl"Ÿ~,Qt+cw3ҕoUz_׿sޗ->⼓'"O~>D߫~rWgt;ݟ3yVW:_Gﰿ匭Yz5tϭ^gL2_E|.r5~;w>hU[J8ۻ} &eC2SCWm{\߿=Xƴ%W;h@}RrQ%/;P Ro~ݺPx\y(G}O"(a-Э׭BYcw !L; oln]!@10g/@e?תoP |{R:Qx)|#PRD.-!rizi{@dBwK9-psR{Ùzp1ʩ9Js"o](6Jfsoo)"+(@ў~+ȲA6# QrC|NT%a' 58nxO9>8Jqu+G90L0>l];K . ܓJ=\)<>t %9{=ك Kt}%{]=4܃J= :6Gi]TAE()xWq*=4f*J< D=٣L=ƻ{ViYg6{V+Gi[sQ{\Qxک ^ܹ༻2yo%?Pk`y۩9έcv])<Ϋ= '6{BQPr'=';!.' = pO( E)W&QvG>:1{BRdܹ7Kr'='alQ{h/W95=p(esQ{\,L)yVL0N4 wݐ.)uɃgn.Dro2d߹/R xr '/cE2 u㭟6EhMƴ Pr^䀷&<޷hA|~;-J?鈝G2JQ>#4ߞP=uwUߙT^eHoJ.}S6|)?dk#+툼7ޤ-Y~j,ߛ,;)sTHoH!{U&UW{Iތx3R/>|xS[7q蟦gP$?v}sQZw$=sqLeGq4Nދ~_ː@~ {gK){{L=w?Z,un7ğHE mGw.cK|7w"v=c~*oT _$W G'<xs*Ǖʤ#uCzIS:~Aߏa;:~;07K<eX^>oWH!G'$mf!j?s+~tf9TЉ?V>rݢ|ǤOs7ߑoW~*}{u!s,ޢ{?rϭ-|WXtXgkW÷Iu!" %n]i?7 ^!oxDn:+৪\S4r}Srn/H뿈BϢE[D#nqpQ\LEyyL| 7— ݠrbֵ.<_tQ?wCg>_I5VWVrO։:^+E]D0?tR ?b-dLïo{Gk]4f aOꫯ!5QG@>L~yoҋc]ǡ}-JQnM\azKS'n4MtotAS!||՛o}|MGv,?P%!G@[9{Mq/h{ZRѥr~UnM΍.[U?L?Wd]jIyO'eK ɿ7z W#]@V74QewʏGn>3ߍ~9շ\ݜW!)[EhMWta]<-I'qrgWd[?eɟYVyOps^6~!K[tF܏r\cX4oJ׾R6GɎyM)ڷL]$G#1JC$Frb0E׾e(QJRrZ%)4w޷04@[Y|!b49e7c$fH,J?yL䫓Lnec[1֑h7,p:JsDhȠھe lW};aPt Z{ʛ3hoi,AUu$B,Bl@>9D|By[:DLVQ6GY%;JqY2Etrާ%v1h*oa2g_4P*nv4 ȒUw-D6XG"F4GKMfw-3cԐ[V1hϷ;\oB|Awe{9{,*q!b4J<2EtSG=BCxRd^٩KX8e oDclzH@]ON^s:@hϷ81#*|ut@|Ayy YY&9,<߾,> y&Ӕ56 %oazۭl5XG"FQSoޥH2xη;_o<(`П0e&;1o9o"Dbr\}db;Gfy&ƣ-SD)iJ-()8nϟAܷLO]u-S&ƣl"M# ґ;Sh]e*aoi$Cf6pA2EtR*f&ƣ)>ZGIP$pu@28JuVF&fDQĬaW3`I*ٕFb-3!Sz=" m lcN`oY_4@2֭r3H4c/1ȃye )LE^mH@yu2Sxpx Ϸ ] L % osUai#|()T!#;(Qxe*t$-]L(4% )=QPѱ221kpoesQĬBb%D?9Y )@C1 %d4-%8 [d0J(cX`o Ā&l"F󭣴/RRh@ϷL iXyu6v1@<2A4K6a #~<2xh#J {/}%|>0Рo;CT;K9mY9""mHؾBA=A&TFDW{|(8ʆ$"J!Ch0۹occ8eoADZ)R~hPϷLUd;1̓|; e}Bze+YHhACzu1*0Vv!QƐkQPVc4`ԑAzuzh#3V =*`%HYphPϷUdЅGU ee1hPϷS񀱇 -3DdP`pYx1hhϷcu1(u& Uőŷ駑6ӧ=ߒ>k>/~Hze"jq b4oJA=N)iBYРo"D)dUDF<[f*2*0>*BXAz2x 7Fepo!WbFpPqB>1 )44GxCzRvG9ns )K,cu21eo!XC-co ,BňeAC{e |F&SRA^q> 뷋zo.<[ՖsTSW\Gd6%s-T;7񏑇w,&[uX#3ҡɌBr-S6GIRE󂣀NHe"8Fh.E8Da/sҡ_1C@o")QtOЃo,籥C `(<[.Rk]L(4[G٘eZJq )4[TGydqF!=2Et1234cРo,>۠Ue Hz:)}6[≁${x ϷUdNݑ(|tG#|:Fr \E|Km c,(,T` As2e{HG&gd`͔>-5z|E6ƣZZɖ)4[H5GٻnpPh8ϷL]8Fr F<[d0 mG\<[&mI2=(`򲰍,>;:0&-SD);RF"Fc c}/@o& sP ΋uRД}W#~ʼB5eБb36ːW|ӎAt4@)ۿ0"G*ݖԇOQl} r\my9H-˶*&%UHh$Q"76煬6mt>{ҟ%d$goiyթPB :g/]oTbg%6ΪzSVxQC%D.A|%o ~.-rDJTf##Esҧ(w*6xᲟ:c1k,2p$~Sz)Ǵ^6M2\у9>/[>?Ya2o}a{|ja~Ö{ҋϐyŸMLbjc_aːΙ",`QE&qpQ\[8QU[0ɠe1#UǴ98˔G>1 ׋(#v?v kVmJBɎҐ.V53-cfpQb?>)ht8h>Ԕ-\w¦gdG#vA v|"(u^=*ɂhHЏϺj>ŌzM;S;)䓸?Oz2*!tvGHcFBgqjMY3J9aS+Ŏ(dGq+EkSsVFg# v=(Q䓽JUK\2FgCz嫄ȍOV}֣gG.|qW?jfyD2fy !tI[D#= d\[!ClcJp ">(i1 z_L S6J#%#e sF#/DCIyaF vlҮyaƈ\ vb|ffЗ"7,#r?e ,wp$d*#䓽aw|I1L'Xح=t11!8(t Rc^إFTW.{ N1/82O)yaeXEkȑop  A#8he 5F7e4Y!#tRחr VG'4fԯNsE)S%D^|* z)8W8ЍbGJ$G/ӽftZ̭d17Go#B.-L/ xG%fhƈ\ vb?p = OyKNB)caF\4vdbe\ÂTӘqǎ|+1b4`#ȑQcf*#ȉ/fAkȏ"Gڌd%r؉HŒAXcœAD9$XvŒAX[ȋ950gL=4i>]%K UȏiLSB?>[j஋%e9iȐޡeDd,ГOUcHeDcNpeA|ďj^|B^5JC:JCce:i I1+8 /ikYqF "aI13WD|=RJ{.4gsD)qF#cŒAł/`|4ʣ0UM!t䃠A^7LH/uM(#ĎQkaˆR9O``M2dG#ȕQ=\)Q"W>1;9myKzƗ"'H#MYHoocaJ,B{cc^1}2ne)瓠~d f U!|56Gh׌ S],j"f3lk],r8Fs|1 @okh[„ zI1#IABDUQ͟Ƭ8#㛗:/y͊]41lЏo^<cɕ]WBgCXAm1{\3r=*ؑOΎ@}#yg!~oYbB>/Yc4X-b_>xv\uA"٪~'QScAYDp s^$rd4cVB7>4U-w04c#vؑReœ2w]w(iq},tuε'mL VFg#ssYa,rbfckN.[!ľ|7V @UfYԗ2r*!峸 oޅQ9aE'qʴ<*!t䳸= Әyl#N( VX0g|(Q138(kg}DZ<Ǽg;I1h)1%t(CeA9 2Fg#zDŽ\|g] Zp(Q6L"t+tL>/=L^bW>ߝ~3TЏ~HewM)#E(dGAؓOtq Fg##1O+vȉAˀ?l=Js(s_> Cפ0]|81⽮/f%4@n !泸 QNl5؝O&մbV] [!|72vH~l5Ov^ۘЛGuJфYHϹya,vb:?4欔؛b' -!1g^g#C1 s6J'{oHq:fG#O},fŒIFhǜ [<$.o[b&N.HTCO> 9&lc:BG>Q괼' !CʘflЙOT:UWi 8,ΟE)k.b*߂汘Fg}bU(u R)?RxbvD./Uc|?D;ꇾ|5#'(pn|D}䝻PkVp0BW>9d$@Ӯؓ"'1^;#7Ŋ7W ;č1#Uc_c&}*v@ճГϢF^s!v䓽cH߷E]I|VpQbG>(҈c1+N zv8JqQ $pH ]v~y0ҘI~|+6F]5YQʸqؑYa,rbTdV ]a@NpeYc[sl 9Qƈ,rb8E0|VQ~|!ʘБt/{fʐ˼q !vȑQ#YaƚG7GYǼؕϢ?)tO0r6ܓoSqbPBG> 5 H B'q#au P?t㳨praf\b/>nJi_'I&L (B'>c0c#؉B6[8_@b9%tRe3ìɮbB%E3"_g#iZkЍ"GT[2?f*#vȉASVدYa,rbP{.^|;ir՚.Qb9F3ѣqȉATwYaƚGg#869%tr8J.3(+]%!e 2Fg -zwYa]d 15'8έؓOz5)\>ftXo܍O:ċv 1J8wyz){W-!"r} t 2vcVНJ]w_jc^H El7_:YH:(bY%RۙbzlJ,zK(X'{ ;bo>{C1#8o>O,CDq\bo>  Wя],j"D)uxrkEg#:6fB'D[4U}N;” YHHa8{Еb'ƱiMEO2 sʍ+ŎQ y|k>>}=MSS 򂣀zYp:B'{J0U˘eYD~|w7}Ɯ,WQ,fԗ߻brEN;a/ T"O> )QVGIxʇ%-J2r6FʇG \JLWNX)^2%oGċCJ.]|6_bj£a  Y5F'S6zWKI+b91vEn|3H."/>o%/Ȧl8E!9#r⳽ks0,'< F j>DK\3Vԏ/B,;b$7> Oե$k#7 2VJgNt<mo.[ʡ;ɜT+uK?m{ ;U%'o9җsi2;x}}ρdt>%lQ '|2{~L8<`J^a24"PCI%N-뻬C̝KtZPNnMI!?3&k"Ri3_gTi&9IY2dTq-p~=)zo 9[QV+Gҙ'EoQ㳸i]٤~u>{\ۭi복{IL6,6Uj.X|kyт8\q<̗)r/p'Rs>2gEZZ/} <.H6o"FY$ 33UsbƍF&12e?I|J :DsE-ݠx%֢m+<~7|v]_i]l4$`>sy=rwJz|bߋYv Gg\[JoHzaկ˽I/"}g$|{u|w|_kv~6IșU6]Y]dM?oS9~SE2k 7K&עzeVr6q};xhzcBUc?ߍ~yԷ;-[GA~ŷO9"„ TQw1` ySJd{7GAM/a'UT[la,tR%LG)+~#- SC(]78,/ƺ~&@hC ?NJz,QM(4UFɎ(%6SlcfsJhh%;J]cbr0J(H wqނ)YF͡bwA%J]C2 Fc]PTژ]-}W:=Ť4ئPT`^bbebQBhRhhYQo[*1djBcDź|&;<ʎRn{Rh*!e"FcpAI/0,!8N1+# vGh(!"!V@O;DQ%FZ%3T1%EwiX!nGinPvBu* NӲpCEDU:d_J#b4ʈEjƌ:eH,!r( p!lh(B'228F=RmH >8&ftB1aع/)BI1dc bRʈ!M*4{RhKB#|OhCӘ6 0 RrV x+!哣+,%%Or FF"kSI%ymyR2e"P:=tO7 |L)#sN]lOiY^IfL[yNJeYFrCɎRrcwYewfJz&fmK)QVG;_&)R/(H w&xҖ_upD @8z[mJx^tZ #CUƉn am7I A&;YcJǖ4e9בGϚ65,܍{Efns[H)QˆStBsॏꄂ hR4a{882;vlQqc*DMC)xrg *Hِ2eh4^hwBǢuIk [TTAS3GRE^; x s%M?_bͰ_yv"y1X96dtc{RQ~ٯ=;"ui,JIb6B7ж,UUŤ;S7!ĆKDtjDIX91JtjHREyӞI*RcpcTS%FẎW<+c1FhjXDF(7K*!cnNVŁ0ޫ`̨#îUS%{3FƢY812@􌆝.бuLHCZ+b5<8 7Vy#9<ɡ]JOnZc&/]Pc?XSEFakF{š.Q6G9ﳓ0eĎJ YFq%b,6'BbAskY%D_oǒu1P ˲2γjD08ֲA9HPKhhqMcZٻ9~C2ZDe b2Y%t}B!Fpr( ѪBJNb魩X Xޚ*2RȐb3#hOsrˁ]or 0 3ͭyT3NZhJ=sM}=kLtcΎs382P9E;Ld(ƻJ Zo-]UlDF;$6ޕOSXZ脠e=P1eu/JN*;)|Ԋ|M(Xzj1N<@m#ǺE&)Z-ѫ oEW((g뼍<8s`D¦U/1`PBh lD8[SNdF@Iv)"%*iwkn%r<BoaXJ¦EMsf J^yE qh>9bզJ Zise?1c>զ򐡱(#v ly 9TjЯu=,% 54 %RM ~hvmD5\_ OvxlvmDI- Rdhτ n]-aPⱎQHIzjQ9ꪝr.V+(m1g1dqFZ("CNfj [$Rm"1uՑ@ e hG =/Nf~/D8vߠ* ~iWct?ĕşg %-: %, nHٞ%. n_`m0=1g)aMW(%:Ɣ$Rk[P$8D6ݘP\u+ܚPnjj_)o(aM9%¶_6>`e¸36a(qo̫X_!ňu?m RJ RnL9&LS)qQ+%=1e^I[a%iEJ}2T6%?`ԸwRϏ)yB2WvW5l6M$oŔtK[P^G^[#'N(Qd}F%Pڗ( 6~IyWKnL >_fl!#H#a G'T׏jfB}C;}%BT:Teh僿2{x 1ů#k\=o\ݾU6-%0GtT[LoJ}(1·,\(aDoPkrK֮ ((QZ%JP +΂ ꈈ~RcJTv6)eĵbJJT+tc>Fj~J}y}RPRKVj41 Ul)ETJXj SR/QJXj5QQG] 帡`%ð>*(yBɠiDM6}Q&dկQꤪ:e(a}RНQzUV +ϸeEO>*) Q9Q$:xd`հ([XGFTuΐ(q З(#JTJFTsh_b;Uu$1ASCmBG6_@wG1|GzQ='i^BkYHH1!*@9 aI4@QIUK5诨ՉB~kU_:߿D:n^aaǧ(eœQšKj2RBʼ&##"*PQB;Ѕ]o(Xq&~R*/Q;J)QC}L 4 >EٟL7 !>K"yUJ%*R^A7 4ʴx-FDUJ JXt"w|CI#%_`mlK(ۄr^J<~+|;#ϣC}-~n``o_R_oy(ϷD|;S߯x(Ϸ`h^=8D"!||$cxh8Ϸ_ l!|;%h8ϷLh*9BF c72`m<߾YM)4)eHI!|RfO02cc4[` = @)|~&4oԧ?9a=߲~~ӣo#w)P?O<"2!žoJg$AV_}˹{ȭ-Vn*db-NsJ^) DNp@w-QM (./}eH_/g??>#3ch?ooz{̓A{~;?׃)>2}H@$3cH9wZIq:b]zוJJt1K^3#N> stream xT}S$[|bvn   BvwΝ%}={fݘ{sFKUk:tСC.:8Ѣ+E:tС˄!A&=NE:tС˄X& i]{N\7yСC:tFq @  ~+{iqȄy@>)A qe{ͥzvTVwlwcСCTs>{qG5j.Xqʱv^ug-۪lR{˿[n9yA=*bґuu`vVev1> U_CKwи՞q !E ȽIѲLjvZM:TNztj{Co7inKٯs\DtСC]q7iژ1׭[{ԩk׮^xq箝ӧO:lĴ먱oؾas];\!mzu5mpj>5֌F́rn׺^u99V\i/jewkLwvBw 6RF{k.Ht @("ݶы@;^7sOiGNmX?ou/{t\nc6KqѡCv)*רok#G9s98WxU1hb-,=SnGM_ax笫PelٲEk7l :e7sQcfϞ{ٳ7o^{7/^<{  :z"XsWzo~Tէ|׍X߾_y7pNmUX{5~7NG_XE̶2Mԉpjuk߲5 6 } 8u:;l\AQ$<֤㐞gR.JB[*?+-4R*СC'O\fNU۶iDP١F\JD',ѡCfSOzǏFz>}rv+'DX658u UkAŪ}Ֆ֗4/a5`. _ݻ==(u쾥_0-eG͏kOVX=r=~=q;zE"F ȅ6KNz/kcGF^~MVhsce@tIݸ٫e :t;k[fbbfmVnLdL~c5ewZw 9YX!LV:tܜޣG=00 88H޽sɓ' :k>ky;wzMjvŨy3Ѳs7b/ͼj;Tx\ꆳK;|Ĝ)oqc!ֆ)NKvvf[y~nU7i-YR"r \S_ w#:Rnz8wlN^mTUݚ7Qh^5jDo]oڭ?k4tUӘډn@={&{ػs6˚5+Ȟe{$.C)C. Sg͚5ر/]p¹sΜ=˹^x|-_l!m#6liq\OT՚jMwZIUV}h@@u rh\ΰC7z2l̻n ۓad6bm_PjlI쀡ll749?9̣B,!rDH#H'Hq9+m]!#ceSt|m4j"С3BתbsW]9`6ykow%LR*uLLLIP?:tҚ5f̒%vu9o޵kW1|$ʁ~Vבs~~3.$ʌ.zȻLX5fOqUj^sA YWOu=mD&4"#ynUyYyY 3С9sr As<%6v ;v#cfZ'I 7{{o}fĄ$k B"S'q9tХ)7|Ĉ˗ٻ[Y#mܸ~QzX 7:ZI#~]fOb1;3O:sLXݪ|VWFYZFB @4"<wω:tUxj8id4tH_o{[[;PPѰٻ](TT6V ,4FliF0s!ekwң?cGY &X̮ #4̾}M!T4G3efS*3MZFBD#4"idi=mtnc4G=h$:tR/?![v?q|R,QA:l{bĸiʔ'{mlfW,,MMS:tiM4k];/@A\|Wo!Թv뗚*Um9]+8-&uJLLmETyZQzA\# >Rh BHZ[5.[iJoiA$FF"W٨uҠj.WyհO@jXW*W>_:ߢ%kѡC'uM[#:dێN^=~6oҢ-ُP5ҁWĩ#03g.cfnN.[,FB.%+M6gQh'H->bĶ}'I݇F>:QLU ֍…+VUb=29|lʰeR=G3Ĉ WkU6lIHZm jb[B,G |ӥg|^=nlj/I@ 7[l;|E$ 0N "EСC܅ƎiƳgO>}#:t #G:us{0ai.X7ou~ۧ!jucZ]wԪ߾ SeaB̎.݋̰RCm& ێT`fonK \}ǣ~ٱYϾll6l֜kفڋ31'j{,2w,!D@#Z vW<0Lyv=PV-{|QԜ13'Ιlϵ>MxA=eݴu4.:t҈[rcNSSH3g]ܸer\u4`U$@V $VVyD֋to'^WС?n7n\ yہn:rǎpUqoq9,蟋cU3UꩱbE~^f˗=zڵ @/>}jÆu Ǝi[9>8dj57yѣ9.{Y1Jgf0;+Ԯ㩳߯Y{އuÞqⰩZTy^_D}?D-[X(8Bd) ֶ`KVτXVts U_mϿ%u^6~(СKvSHFjԨם޺^t@]֤IG9e3gL:e4ϴsN]FywϖmlgO[c6MWkÕ=zΊ̡̱JWueÍq~nXj8h\,j"F 7N4x>m ~lɲ/^yN*viOcC.F255͛7oÆ cWЃ?6tХ#篬\nE.ްi?{7֥+gwu!>;WȕO3!wʩsG3dXmH,B FD4 3":t2{5h2+gg6mDEEK Yٙ=N~(&h$5 ;-Z)PCd6~ԩK.^VT'NDEE;wvX5 @f x /dK_^h&HRL4}sٵ~z777/Y%K k׮0+@1`YfU0jj$$c7#Hصk۷oGGGBAR`*^N\8!A#MDLFjܸq'K'2W Zlm۶%e֬Y-ZX8p j4F ^p!_tWʞ=;U^=6FB26ԑxAϟ !H5RT1#QE rPFBAH5M)cxx9%#}i„ mii٪U+'''nӦ eaaQvۗ/_'IrwwOHRl%55 ELY)F^Ÿ'N$ϔ9;;dWAȑܼbŊZa޼yy`\,AD/Rk0S2B2S҃iԁ߳  FbMr/SrNQ{ G  zj)T5R5 EΜ9s* "*ktwlQ#%H FpҥKrS)Fz  >t&)K*[AI\r YvBvi$P#! >}{DD؊5~5ҰrFBA$m: H5  H  RP#! HA  "5  H wCc]jex8؀=n] iFBA D;c^f3w:7SkΓwÿ݉돧;W{ )FBA 7׫Ytq+V2WtD%n?~k~7z+$½4*ѭds>Cd?%Ұ%ӝ{AD2Z>FhJdx><ՀNP#Fz%ݹIsL\~_3uㅒW龦|niTmЖC0}j5l{!۪ b~m ~ŽI)dD9bO"U;sjM"s%28V˔VU"=:Ml ŖHNS3Z^a| DO.DRS#1#A\)o)fA蟱@\[8u4xMn]oAOn<r⾺#vX>`c}c6 !AF70bB]ho}B)/ >&}(>x:u_>J>U,/[HKC}kL⾆Sj *>h:u_.]#0Dct%4ҭ_ oDJhytu rL5 {='22ׯ?~WLL =R:l6x7 ooy t5 "(%|pa#dGj#BR`ߕdË, ij.QH .YKF:ɖ;Ɩ2[0$OZ^)9?cN]ۚ Ww۷o>GJ'd¾cxYs^G~ž5K/H^IH Er9:6R_z=YGD\BJJD4Pr-hTNR$O%gnm=rB;^ϗŎRȢIw%B=U 6zϺ5_:,YSJHR27 $̹ OR7S<-ؽmN߽)VuRFR rLdQ+Cjl)ÝK`c 5I"&Ro?q蟱Wt|u ; Lj#W\s]~Ȥ_~EEEl5PIdR!pKI]d٥FRiJ,?nBq4)]&+z(m&B$%n"H), FCȭIH~C) 1 Z.z:J. ވZ02U DLӆKU= E!7m98ݶ`YV)VtTF'R>8ttPO'ce+,XO#rzqqerf aƎeG w0nn\D jU]1)S9J{ Scn D~e\΀Y)I."`iɔ-/8p+&[6./?&&`EA l>_^kKӹ'xdѿrROo_Xp5SP9E(UtСP-sR(᪠FllW(u2&fxT f9B|b'w>G/τ-/Fլ78ϋNPɱuV@A.(l;.^sZa3KNn Y8 ]n)t\M}% ,g}qڑyjW-lұq?4ß\;p"8?o,0Df\>ϖ9!_ȅ:F9.[q111ZۭaNLj5PӉ=`IHw+z>5j<00\iۂcN:˗/=rW7j2'  f缶ܷܰ5. wYFl>r:5yIXT-?j8|z9v7͖)R诘wE L.-Iت]Z iV?OT6pԹlsBFvgGخ\o}\eQqMfׅ/rAX[(\s[ݿ)HJ~BP 6T[7sGYǕ{)CGvnGݪ@vvDk52Y63͢7]dJ}qًwNvufmG;!co.8wjf +~HlK0;se >c h|ZLã6ݚMS-A__lkQ+ E#rxAl  p*5*w`n:6U8l-{y6ד7@D?ۖ߯?ͫg`m [#,ĩ-Fx"hQD r̬9ڐ1$Gu+Ө'Nz {oI7ssfn&>f~Ų̙s̐L6 ?*WHr&\#ubKyTe?ퟎᎬ"]s]S2k>涕ֹ]eճgGS{C\B+Ṵ̄/^`f~9A ZrѠ5>۷9=^߅`o DLcvp}vS><(m"'=^9 rVrG)dc<Ҳg3!<0?S?+$]r!iT+t(༓lz-yE~S,W0.͸Wv Q`V]B 6̴\6\<(% t&n :L󷳎 SiyYl*_'/+{Ro&U i*~y@+$?qٕBmwRלsivpr^p =D!)lw^~mħF,|V؞纄 $lGF.y LM9C^綯\MvSCov6/\WʅK@ri6Y t lrg@JFj~p/u]n,-AY)';+K%eŠߊqJ=ₙ:vŵ9{˅)Ñk{C\B+źLI*6U݉T_Dj9`YǺx ik{ϟgC{yQo=pӉ[LX:TFvYjʮݻݳ;f̲5BH ]h. 8#y7~x2_=OoӖc^u )Q#yU!wÔ!f 8#yt='*NxiGvړ]e]8 >nWE'_"m\c/5RpIȹ 8 :PȶO^~ !r>ɖ%+OH\9pesA;N\?m<7Ho8y]vYnyŻ4h%G)^lD ?xm3\?m]D#^oCBs+5ǜ>m^/\ H [pHfx{״bpsЙ{9wwbd3yi(_JMd q -aѨyި]M'ߜ 5[]Ǐ(N 4ƐuWA>X|,%5|c:Rw%U#%]yO;Wzuun`&L,Ydcw~QBR:q@N{}* @TM`ڵNzY;/|h7ao+]vVN*%ѕͣYA9%iEHi\N86Hwّ]eKpJ`ig-dL+=9EQJoYCzD>rZ`ډ}h$ oAC)-gN{]&y_ :dJ}N;J 3;< |+QJtQ Nle"[07i ڵR8V/!nB\S-`ien i7T/ʉdz䤽W/SGFBvz]R'3{xdaFs~kؾ1+}?.{~ ]Gg!6yw,QM(o4vVtE6nݵ"dzvp?RfJWG%LʹSʒiҔBW*P߻q'L:/"lYf]$ _6a\FrFB4Җ7dilD#sfe2&90+옽??{vm(WHh߀F6{C/qӼ4tg?|۷o ح7^r?~ֱS_u4ҽS~n@F_ߪ1q]^n_^YȆ7bK=H2҉ JݿNssi,nsקT"׹>E.6qnܶYH ?ԛαyOl ϯ8'~`oq >@W?,9a[p ⌣qP7b?C)+:fफ%l:]ξ`-jrxx ~_~/(}H߅pf'}fDŜ_hň8%8la.͐÷B^VgXq],k!e~謽U>|{uv+zkKkI[lHn,&o*f`nCd>ncr-9j]RܩBY(5p8^W/p{l#oTs؞Fw -~H,.ب }r)&F͉pBb߶]t+X=[olkk#xbLv?Ts!/HfZMΜ\^ iȵ?6oe {K.YNW#I߾Tȭ&m%o k$Fy?N+}W\kcc%O H6,W lFHMlt,4ҼW \kw3RIĽNoYnU1ufcJS.i$>|&\.ZgV reX:c.S2ԃrE'pbrY5xjY@ <(@4RVfſk%{q2n5՞h~swI9G)w금>:w ۯ[V8kQ/׍1'6 7 GfO1]r"'_*hgwsB>RCRإ4+Rp^vy84B'rŞWRv:kpb/.?'>S]yjs agG#0[Cɮ" ZK90dA\8HߢkXգR1f&L2,IS.1B"Iq -/nOxXokt6ӏt{sپ+.Y{x3'`_r%x0ؽ1y|O.W5ҷFh?&I}]mjO(!~H9<7Tp(%R]4~Qi9_ǐWܳeVt)_teֻRdY\҈ShN]ؕi.Qnt_zN>T0bXH.)1ÖMgʍ[wK]UȤ-ydVSuͿiyBo߾}{qGo9|Ak|. Q={YbHP.$j|/\$'JSExx"ZCQ >8&-ѫ3{)YH&W.߳ZHo N'YDa}6IqZhQIZ: vߥvv#zCim6..6Mn[\޻rZsfw\p&(;Lt.l clW̹T&-?a⮯Q@&-pqӼ ,EسWx@ [q[Dj Hߣc:O I)dD;2I@zfj['(~A~t ~x([;#kΆ<<\wȕH+%9|-#؝Nv卼"[ogF-٭l 823ݸs~Cψ2?1D:tt9s4tIH[cQX9|ơEQ}[J^# 2le4peFW_u `A A+N R  xV_&/$nI̋{BZA%٠iޕ izr&+eО_٫ŹWqw/ςKE#yӺ;Q4RUnfVvVoiʮ/.˝j_sޢkMiӢ-"m3](ܼܷh.BҸKF־l˰| qw' *=VL'/>N|fkyKљ{n=~ ˏ_Ws%$Kh$A$08ّ#ozό(8mX+;ѥFBwPOG=|[]us鞋ό\;O\Gli8xՅKoV5 H%(fCV~rrU͞kt˗/ٱ٬A S%@A [z©~Vw޽zӧnr&ڸ`5߻EGFzjP7 xV^+֬ߵkѣGϟ?j$A @|bl EO\5)-[o/4!H x;ef[ glK۹ 7sޠ<ƍAAAzG /&`mO%>jϕ؆ Cpp;w|}}Ϟ={ԩG9r~O8>.]]h4@ މ/RiDGob,Imܽ iH ^((SCϷ>klۍϛyܲ)]B@ /EQd(z3ّ#ƶ=ߚ"3s.! A$ "EQd)EISՎv2FZpa޼y̾Ĥ҅FtһFJzH:iM#H}*Ğ0/zPMaE)" EQ/zg…smgg׾}7o&=SʹZ]%I<._\zu+++زnݺEZTXqΝIɂ.ʑ#a;$$*9)\ 1F 5a$W=$4HE#҈F2z=y+!,q+Eizڻw{nܸQ^'=Szʿf SV\44Ycwɋ/- Ο? ((hᎎIf͚ݻ'{=tj$> },O<۵k}vNmmm;vx7{=ٳg (0i$R!9N>ri֏H3fYܹ3yOU L 5#W`sӦM8{Ԣɥ jΔo7.u&*7o޼ Ø0>> gOrJƕ;wEI$끈"J #'ǒ Wb8x0YBS{5SΝ~;v$ =1jjR3fz۷o |-'""J3W?) $I-[v֬Y$_K666_~AjTKkGD00ҷC}<_aR#anZP!pMahӧOe˖*$!AZ# y)Ph^. L")CBa,YB \Ѩi9r̘1BZj\e$EI$DݭX51UE@8| ӿro/VN/֧jʕ={6l_Y'M8A}l2|+Wvy޼yd͛K(Aw(<<< 5k޸qHA!CHj 6!>HR Lڷ$N`qC% I;T Vj=]G"#Ik@ QnCa'B%P?~\ouAAW]<#T`+=Eܾ} _fϞ:FZW_)*#/^$ TS-"P#I;mBgv׭[и}6pҥ2e('65! C2z|2t{8)I L 5#C`rmF~$jѨi^xqŊP9pX`*U-p-׋HDѳ#G"S񞢿"Jk2yy$R7j>zZ{%qƁ@nNVчݵidtRE:0HkΝ;0Cwx%KT +x hӦM˖-Al@~ܼp°˗z3gLdbQ!p Gj%5go(=gQB?P 5#F3f PWۭ[7P\ʵ!h?vQF;ҥ y"PZDlΝK Pt<+W ϵ 0ׯ__~Bj 6PӧZs} -Hy'L;Xr`z0a[ܷ?ԩ}+=3k\4{쨨T0 H#5 EGFZwmI »xɺhDrn#jՏhcN75b%.IceF5 Q9A c-ޏCɇ}mKyrU$c@y{cj$AO/]~xibV]7HIZض$gN}*XZ۲uժUЩ^H@jd(zض#wSi5Rƶ%< ~~ǖ>1ĢǍmf5 F$(5\=rض#wh5Rƶ%a< ۲'N`qHA Hj_) +Eo#Hy@2-q;ûx~biGJ^ߏ $H(E}V"HJvhضّ#ܛ RjJLrÐc[A@ H_9(H:Leض#+VQmQ8>ٗE4kj򻲿2͸fg0P#!DĢ(qԷREbt֮jumK3f4夑'.^|T93`FRFGKak8騙4%|Ѽ(r'P!i[ik*F4 ?8L(7^|?eZ cpfCFJ/! k\IF鴙DˤEpb۬u>QdI_عK{]R?w84#9\ >H}P# FJDF鴙i~5/tD>D;ۯυ˦Zn[cRi64j$H(6PJDF0ކmޢ7c[ E(tcmy=shpI4zJdle˖9r8$Ƕm̒=K 1X*$k֬ɘ;Syxx]VA~ǎ˙3Y+y?1o,6T/Aڕ@Q|lI+?G gNiuW7Ȋr9I-[VBܹs[ZZ*Ujڴi2&/ɥ.]ZLSSSPUVɡ7" P 1DTÒnFڻw/dJ/_\zu+++ SiV#"Yl0P#;r-aDE+ K ? $oCB:r/ĦHS7S$HFZhŨQ?~OʄB$FZx1cN:uOOOwޭ5B։Hϟ.Qm۶9r$}u֐u˖-Ϟ=+3|ܥ=~Ϟ=b93}UJ@(P`ҤIB\oڴ)XY[3naFUV/// ۝:u趶;v{ڮ\20t?3n8 ܷo,x.6kCnՕ8/L#JTоۙ?0(H!q]$E$&Eɢ0^|+$YlFRDh$ayP:k׮]fǏݻH"DZ?:tйsg;`z" x ̝;0ԭ[z:`+S`8qC4'A}#G@(9 "䢳j4gg@AasPo 6@YfPiв`ݺu kذS@DQs-7n܀( ZĞrZߠAHŋK*%:u_p&M@\~޽{۷o H'OΟ?ٸ+۷AkݼyJ*I`a``m{H <XK e5k Z'6)5Y4&}b"خi3ۏA#$.4lw4`s`T9Ezf"2擿ӦM+T0¤06LdN f666X$$aǎ$3F 6FI*6ē'̹Bv B! ^H)H &A5.{ ߥKNo5Q4ҡCu}Nq@K 0S0Yvm*U JJH4ܹs .Lj/W\ Hduj "5W5z?br$s>yII5CFTHtIYX'IF:qL1 .x"XrHb#,7K+&QFבnݪwIo$`5BP6$)ܥ=n޽bݏd:]Gekkb ׯ_!/(5hu>~ 4!loܸ u WuujC #=xo^x¸-}Ja A2-}|brïB'o6CFo<$|̘16smj"s`rWkCsLuUUfM0PdIY`5dȐ|M™رc!ѣG===}`fdPS={Ilh H:cM42 ۳g\R:K{T6mF%sAlڴ)Ԫ4< < 2e<}J-+܏@Œ=jYf ٶmƍ_v u=0@#A@ X'NR^ P۷oC¥4!@pp0C( @MVIMP&!HRDZFo.FiH.]Z|ySSSK.=cƌK0Ղpߵt޾o߾ʱ`\mɥWWW/],Y"J*X{ϵ O۷?i$N'/Toܹ (s#2nܸ!MR 0(/{v  J]H &<0@#A3UPlٲE1H yܿ8b`qyZ d$島nm(nCLO?UrQ󗽁xdl'Dg;uރ$GIݺu y6h$A14RfvGA#G=^ҾFR6#iHPtϞ=K,u0wذa+WS <L#kT;;vجY3cq.`/ իȆo߾AǓ&&&6%o)Z-[z{{ IA3jbiLm0ņATXQjgiw ̝2BA H `V}=l={H"rFFF̙sӦMBRlӧɼFׯ_Ǐt fOF'&&&G˗+Ɖ mMR@DTS(ܹs ͛Ν;@5c LmRքغuBTR2R;U#- 0Fz)̕aR?esFY[[)Sqqq0U +u21kT;={\~,((|?>e( 5kVФiHKD5 D.]rwwx"԰א!C@52,mRpjk^~ ԗBrLvB͈宵e A~*^O(\^SU*ռyGgϞ̙30޸qC, "wt)j:9}˃mvܟ#gdIj<+EEEYYY?СCM6V&Jf7:5۵k7c olwjF 511!TB! i#ޏTreH F+g۷ow 80'L0޹s'::cǎzϟ?ÜEvZ:t #&+N8===!pxx8L=ڿ Bx*+Z( X[[jV29F'A evܮYUF]j5Ҁfeo_vTSiuCRH䡆j`計o,UONj9~5ʼn)g  b:2b{6T)AHXؼZ z@!<( /඿ d x{)5 )&c!jl [#{5 I >s'4DrH'#Zlu=d'$AAK#族JGdipLv␦+we::sLiI=1'4|JE(UJڃj3w~Wc5F5IQJcHdD<_3AvRMBADבwPo[yMӼd 79qWWϨT삩 ?U'uo ]GSN{mwnq+66/֑d'˿5 (`DTQLjz@{d]Ջ]{7Ԡ+@F@#MӭPwhXP>w-q h$w۵jp{TP;?Gr,-<}]K' ST*nfM}4x G  FǸilg"؊>?ߏԶ P{ڍvVQs"gMFu_jUHZJ/gBi_4Z'_Zro7QRz4PJ݈eՠv!wzs`J_Y2t!ϝȕèz6vM;  S/@>x3._j37n];9>ԏk@4Wx3UPShgO,ȕͫʭHb^k''۞<6$>M9ݢs#q {^"i@(DA3ɕd|3~]D  ci$WI~ŀ,"Mz2)17knFy!MkWVuFxVW[(I$&O9XiQ3|E(#^)%4j}-)i٩GAAF\GAm5MB=u~o}̀[>KZA=wUW#= ѯ#QT^G;gUEYɉZvF˝KUW AAR #j êI)r荮Tf65HUD H(s$(Pv?nu#΂y:YLͨPCY4h5ͤh$j>KAAH0"nc3䞦6cl7a1[7:g(j8 -Ǩ/-,ĕ>FDWfFtH$ yM"jtn 3seHA$]FA AAD j$m&+R-tm H  RP#%; KE{m bt~pOFZc2•߸=WtM[^ HĸEMb[x kG  ŸilAOlTkj[{ޫ/Ϩ`vֳ&]5">y&tԏk@}CVﵱqy6lO#.|m@kuݷ,D2DI=&rKAVդ]j5k),AAב@~TfTQlφTJw*OӑX7VC*n$n5${mT;֧)[T|ni!!}k*ǽl^ㅲͽ{%xxb." HZX-p&oý|+6DQVRe  ## ޶N}yԞR~>fRqߴ ׀*ѫHd)Fgj:9{&/:RݼtԲ߿5hIJ-AAĈ.w|F)FZe xFwZi$Mtw^9 OvOjg~|g+ drP#! HA  "5  H  RP#! HA  "5  H  RP#! HA  "5  H  RP#! HA  "5  h\UfPҠIHRX8M]Q0Kg5F1~$; jlY~ZKuW$9i XhHKFD2IC`\te1Ĩ>7R%p$L"'sO |F2 !B0FZ6[=yS[Q{ڍ_.Ϩ Y&$5AhW/4RD_ PE|IFuF.w9A5Iȥj\sHt0Dh$b~t`(HGqP6oM 6U#}䖣or_\>'al1Ro] & TfTHBZ܀KZ C췯l )C idrØySW/WA=' G vqpCC;qq;VVmY;!r|^R$VG5s<{vm]FjTCjP{/҆+Qjz:R;4H"/v  AňH0tTfTQlφ;eGFj³qZ)~ |sق zy D!M 7;Zo Vy NZv1nho&'̆_ޓZLjqNh*qOVK3&`RD%R"4`پ^;1I!0qsHN\"P~M=AG HJc,D(ɟ9EiÕ. ˆ}␦+]=nQE^.zcn$` 5ZZd݋P.PHS:h<5w qa"`BK`J%EBRPQ:T$ pz&5IZ"SN8O/׉BKTCH9Vܓ%T; )בwPo[yMӼұ 7ÔΈR +ȏ0醜)k:DXtUPHSn|0qk0b0>bP_8Bj4O4~0SL>WݶAVLjTs& ٥j8rʈ3R0"҆3w$#I=AGGTW; )5R]FIrH-7#k }FwN0TMFb;.&uPmVW=wGrP.M wVѝQU1r0UtCi8hT>޲wf $j-)l.Md$W/y9G] 5#IZ6(4{$ߏc\1 ?: v0ARci$8*˯Tng][0i`&L0vu:ԸEFnϠt<|gGN !*+檩iRM/0ujZT-;9J\GlXY#Qi8!4brQ} z¼ڕKuMy$~쨩4Uhk5w)r!5IZbtpCȮh;)ϵQø`C$ExN(5{H4uOɽ9Z:Hr =9M A1V#ݼ-1p Y=&yYJ)Dz$ݪoI^R')!"&j$ró+j^H&,yS"M*%zR. >ݓ:ZONk`CDLH  FBA AAD j$AA)AAFBA AAD j$AA)AAFBA AAD j$AA)AAFBA AADJH4%U"bHx,< Ѹ@IZZ8M]Q0Kg5m]!)d"; W#E`HZciJ#Y XxĂy4@%#vٶeUp;?u9FUѲ ?= U ڽGP((`q^Dm6飚*|FU=IRϓ5Uc[UF!M`duE>w=*RA5HW/jZFJ UF2Cjt_''sO"PkɈc8fzZܾƨ_>רTEC;A|`CkZC-kZJabbX76jvG\IROoϞh .ع`ڍKs Fþ~y A`\lz 5'8ΟN{ԅsẼgr\@R]婝1NTp crvDWuyFUQ jr70V˙T JH:gCn [w"/(5JD5j GX+ \ixH2+-tP+{2^!d eX ">rA#ҌX6֒J)CU]J[1Kr%`e2 "r~PMzB3N]K*DV H2b,c+?M%7&N0gT0֋ZKgij]nSI|Ey0~x~B8e2@!9{ɊB\8wC8QA}6O{>SnU5i g|KD5j4B;VVmYC49t×K+s!kf:a4nmTP3$WKrTtBP40޾x2*#&/ 9&kz5WɆh$aW^_>˦-Yܵ68D bC_eF=@0>sL;=ϝT='u2iM*~̎B 5!U'H7g!H[7w¤{rDr&;]O F?Y=UQ ЀDOlIz#jrzRQMlHF7w N▆B@Ah$PU?N%=ee3*(^/si HI$jMiU q0F"O֔䗏"Ҵ017fjYn2xyKblۢ y\8DV ȼ vzB5xʙd`45B/gmNSTjVp␦+Wd k5I _nbl< x,H33IZK T!'W2K֑Z 5Q=uZ/p|uj t8@ݡR"%ʧgpMyjA$1:m7iRɪ / XGyXuM^DE[\؄LTvݧ~WDpJ֑&; NOi09ѣ~pwL>WݶAVL  7VIMTV]qF &Q0$I{"`6Tj~s#IM\%v@$RA. i$]e$ TʡFBHQ#eT0ݬ4P:E}ڝ6E]k ޏ;wڌ8mscr/5L+MQP &i#xRM20wZ2<:> jtPIe nTB޽@cVQ9PU҄ZEM|[)ܥP3k#“IetSsO(`[\ rW~6smPKϞ{MAh?cKM<]Яwlw#(IR-kJhb"ɥ j8|n!b`,_݄{FXHOl/rQ} ׆O3sm#R¨n^<w.Պ Hj\?"grfN/pKH`<&\-)T8i}AشvíUț0M\K]smM9z@kݚ.$Ä^y\ BgهEx47D7fU,?w ʖpd2K]^R*$\4]] )*܆MMbbJy!՛0\ގ 5P#! HA  "5  H  RP#! HA  "5  H  RP#! HA  "5  H  RP#! HA  "5  iJ2D*XzyqMdiҌʅQ]:1-i%AD/HQ?زZKu*Mi4o,Ap:#?ݵ9F]{!Z s췯,D2D;D a`'+ q.N~ G50lU5i g|K$5s$wU/gW\.PkbJwڲ淄x)(-&x5I[հ4YmT橵$ dfS[eFl>Svj;n16J篟\O>MRO11\Ha=2ab5 ,_Ʉ{o%˻7\.gkKD5) {7VCya /&5]`miFu7@:TTIR@׫P#! z1F"O䗏"ҴtU5|2Q:d|M-pzȕHd1%ojJ\.T㉧I'iZrHD%ËI~ Y8M=S ZL-&7|%)P_.qˏ&IkIAqipu4 )MdEgx n#Tꚼ"6:7ð ( H`'x=֓[:$`>tL֒ŤF2D}dm9U*PMbRYGrRS5gZ9we)D-H H<2*VWOgE>~$r袮TkSVW{?ҏm{k38-{4b_k$פAZL'GJӽZUjbRά/,-݀jjk .'WLښ:Ns\_ֺ݀ZּBA '=6C9s$AFHٲeÇW^])FrСĿwލ5W\]]׬YV7m .^(ND&tKӤ8>} Ǐwpp[5ICZ{.SLʕ;v,XORC+"/_#5ᨇaBs?8p o޼0$ooohw0oH6A\'6;Xh88_N!#1Y}Ǹ8$tN /^1/i1 H4:tQʕ+~D|:BZ{0۷Ρ޿O|\\\ve JY… -1bאK.D7o^fQD/1|$HNH@D栒` ('Ȩ20FHp5jԨq0WV  KÙ gvvvS9Dj$jT;H8#7n\ٲe~-ݢS{Ј7::mƍ&&&:7jPU 4vڗ.]"{ lHNNN-YF ** xoA5|di 'N'A J":s)6 0Hеʗ/g'J*bO0_|a֬YR7oެW^9J((0D#QӤIXt):w\5FZEjԨ#GlժlBU>i>cY hҥKC5ᨇaBs޻wO#s"d@pt:~bsBB-Z%AF_GzmѢEovD{|һwJ*I:N2$:WfMN8aaas:r*eĉ^.yב\.ב,$h C}A5 ̙g.Ȅ]#۶mN"3P#{yfrӣ[#NtҤک`XD\K0,VΜ9sOVK,)q)QV)d #%;ŊSIyk8!)y;wtaqL2dB҂F"cǎ=z4iҥKCp6{숈Hpذabdsm4v*Ҏ; 78p ˏp:C#GP#&h$.kaR6l(^xPPJv6V(p56 ;zݱcGO 2!iA#&LW^HL޽~ ۴icnnnmm=b{hҒ,w\t4MBLr\kիk "˗//\0pɒ%׬YcC3%7I5 G= B5k9s&Jʟ?i% ݏ$?9Q\ :dgAAD j$AA)AAFBA)򲱱133'B>uInMdN~< Hz!SiHKKgϞ\߿ϑ#Şz3$3]ג oҤ ;::BooР˗/?:vhaa7o &ԩ":Olٲ:utwwV0IyĉҥKֵjպuBܹs ,~)#ruз7oG ;dj˙3'D!.n777b 1*Ux4Ҝ9st|rʽ{ɴi^xR*|dp0GGDD<}p›6m"NWBFڱcZ?~NNNFk]:0?/_^xƍӚ;;;/^aF Ǐ/_>ifPM">6llٲW# );)fTT,O>ѬL}Z2:roIy&yi0M!\JVȑ#|-=66Nlcc$'t3fl&#bR!pB[[[(ٳgt75>>>1GzhCeʔ3d!#t7ox׮]VћT9뒶… -1b Z/F&FH !?o:l[ O m۶Ç r Vre??ׯw.]]_W[bE4w*Ԍ&txޫW/߾}k֬19b M8P'5Ku&b,;O"ʕ iƍ'zMArժU|"w L4 pppڵii1#~5%4 3Dh#8)CZjcǎ۵k'dd^HQYCF"H4hPڵ!X#A%x)[0$K# KEa ;͛Ν;pj[oaaw̙sӦM0:i !uVM͝ 5#I ^# (Χ˗/+VL>u- y-r" sy:Ǘ`TR:P] D)SWIT/^xIӧt(Bƍ===UODRF_``+3X)h$ %w" AH}gz\k[d tݻCCᐑD 6CtҠ!B MMMɳk׮T(>} ]|pzC:^^^C >>>...[ZǏ7j>}t$iiFr&C#Xϟ@ꐕOjFHp4qDbaCai~ pL,?#s1cƴhB$9Oz{{{4xᚎ/1 ! UP+5kVn#N]Ĺ9ɡpȱ~:*MނF.<+YBӶmۖ*$B`rq-LRdyݕ7o^4ɭ:h$r>! UPPP&Hc:R"tPP8dݻ7٦~6QO? i#ޏTreHׯ_۷-ZF  D8l%::cǎ }ݻPQ|lFG4he/КǏO'&!CݭC`azU0I9|8!vvvݻwnæ c6`<"=K%WL)r:X@ mј1c4k-\[7pLG@}ZYYA1t 6ܹD # Jp@5oӧ)V&$HG[aRAI(/_c[ JH#lA$qӵkΝ;IU2FBAÇ-,,իAT%#i$AA5RPWhѢs i\]G4RddgR. 'q oҤ;::ԠA/_OSSN:7ںe)H]xڂjĉK&/,U 65MAs\s\1!`D\vH!r39s(޽; &~VC*U)KHsiժUfA:S:FJ|aʕ{ iӦxBR :~SϯB ɍڱcZ?~IROo2P. -Z_ф=<5JPIcAotR~]t!geZnݻwoҚ @s r={6p)y1F~9I|G^ =5jǬGyi$ &]W&Q?_" ORuQQQ>}Rk>Ƚ͛{rF=r䈲FcccY=˝LzBǘ1c,\[>*IsIT… mmmgϞ%P&aqTΥ!C_d.N.yu!79r@%m -Z4bRcI._nٲ`&_~1k$́K g+VjfS?fﵥ 1>{8<<۷o͚5?~—ͱ擂FZbE*UXKkLYErHr 0Hq鼕 έ UmQ|@]vUxcDZL*¨e_AMI@dbbfa#N ЮVرc!v 8&t4hTVQH,F  Tvm.HP0,a,Drܹscbb{8@5FMtF ֭[ɶ߭l$HzQSb˗+FXI*H޾} +|]a+U?LEVD߿'GL27Lzxăp4Mb|>}@7n陨z2&:ŔBFE"XPA#A`.!M"&߀Ċg^ ږ,Y{P8d'k֬aҥKixj)|TXIA=`#MW:5?{lr?\\p&@Qll1cZhl'{^.Ͱ00^K HwŤBU>PA#e͚|?W@"=urW0)'qpN1|prh(2r߿ mGp;wNI"H/GGEEi:ԴijժAR<c:H۵k7c o"[-H$w}L-ɓ'0UO !u4~k>)hh80U0΁жm[Aq^i8"̭[3Iu:5MrN\OwŤBU>044Ąh!8TӁzhuwޱuDȡpѻwo;,dB@G~9|EѬA0j~1k&OLׯI˗0L~Yhϟ?ͅB>U١C8]ѣGpesDmqmhh5jTƍaZ0!=ygϠ_zUfA|߀۷CkrJLz5#WԮ]z$&%}~͚5֭[Va B-&!pT^r8m87nHǏ8pJXH7OC+VL'`W#Gے#j$ꗣA4jԈ4D<_~Z\[:u4G٫W/jfS?O E{֯_okkkffv1V>YI6tx^DK*k>q,SSSr%Zx4,AF>}:BC !wU$$ u] &H#ۀPt,\1i$3DcƌQHGC[x pm19iee_J!3l0r5~$8*?ռyOX2H>S*W  i˗/@Y2F8 i???cbbvڹsgc dx )>laaQ^=mȒ4  Hr AAD j$AA)AAFBA AAD j$AA)AAFBA AAD j$AA)AAFBA AAD j$AA)K#ҔdTU"AW#E`k-ձ֢FBA$u0FzQӲ^*1[ AAilAOlEE rOSQbT XSl[N)~aTGyT*S5Uj[U]QaTک~03T{H00ƕQ5+_'vRM^vS.ixtAAb,tt'0Jӷ o/y0#?9#hzq]kv=*pR7vx tj{@k5țo_Y2e,Ψ HAޭjXg_'vJMɂ7|t^\>mP=  !q fʌ*:P}p MՠTŠBӆ=̧@DΣz ;5vRMBy7VC:TOã# bH壒YD6.BsCOwIӕ|MHE\pq^r>"W*N#'eH:SnI'iZrHDXꙠ ňH;S߼i^Hf(H_[q3`IbgU Yu# t֑k$qH3/?qg"# 5R]F0Djz@= 7i#@ot^B|~|gnܳ]QMm޳ \KF>˽[=nԤwo4Z͉|TOã+c<A$#a,r,w~= {EV.ڐ#>ʹϋJ.˅Qݼq2Պ HsmMNnRބi^;ǨnG[D{" HF"}g; AA2<j$AFJA$à AAD j$AA)H .,P@ܹK.}Mk-,,lllFhBBB9s&\rf<gΜӧ #H$BRbO++:u|5kVoPP_~-S^UF 9rdVQ$-R—/_ݻG2#%+]4̪^i͋gRJFMB#35޽3@CLԡ;!ܼy^z9r(QD``xkFR1[h}veTfMb',,,bbbi*}hѢX>5ҕ+Wݹ\&N-ּN'ec#cHp!Lz u$&wʍlב3(˗޽{WTIitfUF255՛b8FXb(Żyf> sΦM*h$8E͜3g\<0\:uJ4۶mAF*g&Ig\͗,YRhbH)DB#9ZӐC&=v 3PG0a0~x?R p֭2zh$1N]`X>rj AA#Q[SI;! z*lk >gώ6l΃Ng:!!L|%66vҤI 4Лb8}?WMMMϏ۴icnnnmm=bS:(hW^®*Tyɏ4͐ ޽{3L0^zr~5k9s&-e/_^pa[dISPGF!NwD3PG0apC%vbiѢ-Y5d:.]{*U+FNrqq݃s-X`ܹܹsb3씶{8 BDn>{,=ɒ!$%;j$KzGE932xFh&hg&%)lT ]h>\r޽B-44TVTy.\X'L6ŋrСިҌ4Jg$Znݻwo yxbbbvǏD/XhѢ&,,!9s房,9 i*ؓ,j$rJ]ϟț7o†K O>=z888А!CĦRĚ1c\LG- |M鋝FQT; ʝ;w޼y#G83RFaAF|MFO Lll,˿gƆ<|N$_ ڵk^9Bv |AXʕ+ z+pB[[[hS]qƍa.677/}G?~ԉ jӦMNeSk$Q uVݵk~H]x}@h_!wMFDD$,:lfX ZusQ# ƫo߾A??~ jժ_|!`HtgŊ—Uu!YjkN$Oc);NvLi>hQ~_j ڄmq} ?~QFAՆ* nyWy0'Wv_~} K0i$VtQ;d}РAG&vC&5wd|2Ms]r( CR##eϞ]1uwQT}s6-$N ! HGiAD/R^4 "M@^TJ&R!@L2nefHByNΝ;Nwgy-,,L|{{lzEuرѿҥKk5^֭[+Qu{-/f͚ۗWkI_ `kJrj :םQ9qDPk-EΎGr(S=$̆."H;Nk 5?a„-cvY>#X b"etYoڴ>мl_u",~nRjs>IGN(:CuI>ԫWΝ;_z^NZ~l;=pΝ5k֨{?@/V.]Jt^|q~gÇg҅|E9^xaÆNJ|vz1KPK.%M Bր/Fti=ʕ+i3fLbb"KLI6.M/=zȢ>TC3iN )_w\.\@N{$Lt?s>66V'hpwgk֬I/Hal6[~в}Μ9H"sB[F]ܘ*UCuUf F=R#ԩCMbH]LA{m4kk'qёkeʔ?l}8gϞHm0ӧO%J l=_"0`˘R{!C4N1ƍ:t({Z5 27j]O?& ]c s7j*FEFI&׮]SvHNo>F8t[lqBsL_&HJJbԭ[rnx$Nqksx٨M=v&',kQǑ#GHv|du gEo<==,;^w-ek,zt jժE[l^'vDȶmp<: #ߒ}YcCs]O<%ܹA @nese>6rٳ՟{G%55{ݺuŒ]O6H9\rJ5y4b.Htoo3tv w^kwaZ)B[nذA-]'H@ث]G_s:;;㑜t6wH5 G~_(X#Ycn:Sd֎x$7w~{ R  [:<5f̘ No ;_… CCCvjp@tVEJv{k%|4#FJs!WtseX)oӻ7J۲Aӥ[I@?7ghۙxyHi[ga{n#Q9qdu/# [{G(]C:MۅRw҅ǵt 1#˥'F r^{9Ǿ~\S0ddȱR6Ѽ~eTs?+uq[9,YCoqHFVUJ+G:q,5C4{ T=RZܵAZ_rG==AJ^~7AUKxj쉚MjhM`oX&R-7]g@IT{$lP+X^%sf7B|ݵ>#NP;&.ݡE~ 72fp(*g*r8hٽQk]mg5ty<":Kӭۥ)sK,o Ig)5i5]N?]Xy3) p_r)nr4'_c?fT0d-8v+$*>H W-#_F5lvcKX-Z+%Z[j[]_gԱ| ~g4b1ֿBjrIeV[#oX"6IgJ2Co*05Ɍ_4X)-&79 MŊT~3#5ꜨRF\p)m=AV]J[f(/G2[kJڟWm)tkc^۰墮>LԈ5֕ޛ ucFwlgmQ&錉] l]_gԀPG+N-x$JRZi~sq: HǏr>=0 >&**h4jB娉o7>yCBBL&ӎ;[1>I)9H9\@n߾]xQWc~18_p@r|y}@A$?xu #D3sRJm߾%7ݵk lݺ׵:Ȳ1b4n?'ի ?I'cǎQTcǎ˫:u8q"h(JHH8|}-kl1cVnj5>%%eTKXXX~޽+kgŋ+T@ͦbgϞNHd>Zr3gZح[7jða^ Nz$,l!lM;˾va$9=ҕ+WȤ+W #ib_[V-{h8pVYcDzd diQ֘Hx􈈈CQ>}+V8ydZZСCԩb0۷Y.a|va7ӧYfW^ڴioj_?7oޤ*C~ojV"'u *he:e&DYƍL'_nalY‡ɝ":wXVYv5e O+2zh |g8`XJBvava7SSS/~1vsJ*_K,鑓.xRFOOϣGRlʛ/iGҹ;&ѝEetG@!'=Mp5jXhѝ;w©_~Y ú+ɏ?/68P7DGGSॗ^bUTƐsWk>=&مf?w #88Xh֭[y**..en {Ï'Ȯ#"o_ : )SM;/0 9yYΝ;;t:`~A)nݺl{K~YȞ={Ϝ9C%#s۷o;t@SG?:u5{۶mT޽{Z&!^]MaSSS)fG>--mڴiKVOG#\<14,lj Saaa;vL'ImZoԩC-~NAl(L#I {_<Ҿ#I k㊂n"KOS?@Νp_?y`]ne- S;̙3 &S!W(^(eְ^?f$l[u?>ݓ|IG 5^. &Bwf~IVuGIC|Ξ=kΈ ܱcCCC%I2{pyKYyS r VXG˶DK]RA2IJ,ѮGyH^l* RRRVҥRXvIK*. l+]]P|$:7,{p6w1&(:f[Cͣ(Ѹm6 ( ܼGyV\|.wp yCP }ƻ\T&Խ[b@7#Yùh~rePL")`y,Sv[ a#UTC)XO6iTڒR|9G;YR#Ս]:þ-,MU?h;١ mkF@7VbN̵%/d2A(xrJXL=:4uԡRdժUYyM6Qxʔ)?~U]u!n/,|ݪ5_t bL0cjs/I+ٜR(KMQ<WUT-UQ_ia*XzKHg+) $WTUT^4_DSku- X%G!tr.y #"e|dY.%6r{&֥p"ar&vy5~%"[J ųeRXHe7S|9Mڵ>mC͊HHIᎧ{xJR2Fd(rFnoKC0%n+bq/)gcK"-eagmB /!- \P(:aPc5+'*P#W_2زtV>.iCoK ;HO*HJem1kK(([PXM *_^~T;֫!U0v` ^!\^= , 0,,tؼys:|\v|{. Sk6?<'+F[5L7} 6o]r?QɵDxuEKkmyU55}, 2=|]A 6Q$;<*o,#iIuYSGƦ>6Ohwh{XbS Z6)k,J"nm4Q_07*j05-/mdz7J#=oν&l SZ_#3=:zPXx5FT*Gf͚kBGxp#=e>}:MYk޼y7F%@8D͢gHvkmg5}mHu: xVj+[QL`b#Wߣ=NSF *vܸqX!̾7rH=]dɑv|Kַ:l"Ϸ8j<ё~Y.OYH,SD=<>Y{GZ^~gT u_ѭK<;f5m5WޞζVZ{qp;a^#r#ueKϞ|W. ;?B1Ba(eGbi:Xc<*zwJ6g[;ܮ’uHncuc (QarHzNʰEMh1Hv3BF=U^@!, щz+Cf)Txދ-.&̽QCQ1<[P8GC]D]4S-%*_@׍wq";Un)i,~\)mj*_X" E$shZMmLG)wT5q""|=o|R#N?|y֪wS#+5 c%b,GVO[2w)m.m&Xz-:$.gJ-%zU=4 "xp,X^v-*___B>-Z%dB/7|UUT*s<ɏG8WI6Rs !l&do(|jR~ȈVl {يz%-n Rڧfz$k%r)flNkkn(ºZ W%|^{${?#ϹGJ/Pk/VT|mE嫯} k9 ¢X~I|DlP}ҁ|sIշ)C=曭o6w>5%avH#OG:v1y[0U[ͱ  UÇ7X({<ɧPh-l;,"G"NqJ=]tJzxWO5O5 NɵN^{[G}݆ l&O{?ɚ`eeGzt{0Μ_[Jrkr|.j䅔D+Hho)]/uq\ȋ)]O~>_nܸqmIM{ {<<ؓ&6mcދ 5Nv=@!    HyP9@#H@!Fe-zvAAP!<AA/'=R݄։u[% xVi~Lܵ~:}d),~aG Cz(C!H^u23|봳SGW/g}-lٻs& _:Քe,`4W}6K8:=zEE_S:!A^j 5١u+4>5EU0R] B"g< ~# |b2Z]!ٷ·Pa=gMs}~4kv> vԮ)͞4R̝S}b.KQ#S3MͶG6>n=<CN\puGjh,z:dׯ]葲Atb| S Ӥ7LF&5fZ6hS h1Qe(#MU~jbJ5a;O\@)VP 7KJd?|ӻRc1,-4 #.~@ /GWMբMkp6䚴«k!u%HڅI" ȩu#*\OPu)z.Ʋ{{yoDm0#r!\GS9c+"o@rh0e:vCG7 0cZ5MlP+\ ;\u$پUa|x݅ &3tAP#ն>B~c/*esGD3,U*Hd[絝4rc2YlmGGkVcH[Cs&բ|{thF/\N뱯?\Z1[# /Gdʖ$SArMA^ V:_gXgw/1]waE:;ޙ;L=[ ATG5*XLO7yJ{$%TK)&D8ŏ}E):~X,J9𰠒!LUS>0FvjvҜؽ}S*Ġ)͒7 5w2atXbYoi0 =ҧƚF?:˖NZx="cӲQM 5TYd`ݡz&F2_B-=VEZ)N@$D^g B%|? П9 ϫCA[XPKYy  () _ B.x$  ^9HQ"#J3#߷{RMѽ,&'ycrKjnVEcդ=F̀ Gy|mDX0:Jڸ6 -gxGѰ|葮LGWx{P1?nÌj1ulM6 &{St?|CA9/=Ҏ5Ӛ?@e".\"iz ˇ?tGZű?tuFx52g~/zN5B'v̯P:bCSf r^{W:пrKGi`UdW~sЏ_u򇃎l{?zeJ٪i"{^2<ԪEs'(_&[qii2KERR& ;J zTڵWjAI,F%%YC'ŠٝRjm!H(䇎UzP_,R-u"Hڅ@"^«:)7ߚqXޝ[Ytp[7=j;BYOў߳ZxamZݳ7, 'rr&F:TMՓR֊Bsux <Zpp;4kϥ.a#3mi\:uڅrx-u"H'~BKepk7 0Q#quaSSo>Tw͟B6ZxЊ٦th/ zr#Y4!(GW;SN9EMGNѼGnIOo&DoxrrGܫ T]L-~%Ch֩]ܒ^'>|v'khI"kIJ NX] )c1F_:~)[G١:@#A+9ԯ3KfݽqFӇ7!jwnh#CpKF 1&6KӐd}VIuS˾"&iO;dש!oŽwfc% P«): GJtx*L_#/Zfc<6HAINzixg|g\կYE(c+F-IkjzrM߅34fRfId Ygw/v^Št>W$̮SCJc4 ڳiIx5ZѡYO]:ű?tWk˟¾F%[k1=7?^ H9<,)V7>x{P溜;k ޵0:E:6dlZ6Iv%"߅Qxлs gj祵}֖Zaz+fתO9wJV'!zx:C%N#ulmD3\꿨)ȍ#?~_Į1AyEA4ey/rE) O @Yw;;~g ()'):tTْKf^䊴f+APaO[Uh  UHAA  x#AAG  AA   <AA/x$  ^HAA  x#AAG  AA   <AA/x$  ^ Тd Nzxxx$0 4xd˝G3O*a YrR__i ]G@;[ څ.# K-eMaSu+yZܮʅҶVpHyCk47{RA>^RD[~Lje +[ DpHy] :?`t$N%L1T Y`@Q??ךArHŮd_-yI!/Rb6Vb(%0) jpD;E:<7Ͳ?f3; ,We[  7ڨFRb{J@:yf hR-B3\2<D^]]hdvf5l3Fiq&+_mɚ)<Ҋ>.4Ʌ.# Klk}ֶoxIf:d鏉F gH֔#]OVt+J3rH z6F1I +F%f J q,AIU_ O}KH7vGOGZ۵f\2<DctAFZo"٪Q۵1~,A{h䔞6yK6d=eHpɭUݶ^.ą.# K(ߗjB3\2<D!ˉ2F[bA~;GEe[Fex$d<7{dHPyrNKˆ۸ex$dɥ+I>RMoqHp ~x [[ƺ_x$8KZJcwQ#ϕ$<<  HAA*   ?1 endstream endobj 61 0 obj 61501 endobj 59 0 obj <> stream xTSs e@ {[{{Յ nQq8pZVֺGy0| ܺM{P7j  GN5bʭ{O# pRCQGN_CA!Q"Έf/:|NCAɃpFD?o۬Љד,i4tdl[H6o(-Y_HD7N/AAr)Θp F=f̄)~Y%v ߼æ-6naӏ65޸cʖ-0yxD;E;*Umo#jfmk]a_Ǟk5W:M[G%ZZ=$?@$B"*9p2_£Ufꂽ7DX=nn|}3u*)屶kVDAHp񓧏;&<|ѣGϞrpk-Yu&;ʜL~wݸ 5UZPZ3#5E}N򭩻om{a`-W/PVPZwׄߋٛ#2eMZ6u#!!bFnnj1ɔh)?gEPukNzt텤Iߝ=Ёzu9U=Ue*ED55J͆nVV:M nvpt׿R:g s+TZP!v"oԲcm(z?>̬mF3gӧ22>G=޵k֭[7tذ1+5ou ũy3=""JM_4YiIaD[NV_xMS??9ħo~xbRі2]ORZkKɦΟ^N^*M))ؔ8otu;HCC }YǡG1cUTGGݷ\bv߶igJAt7kk[æi^]ԾSt%YCA -c&L1cکS JFt^wӮ\I^j吡C]Z=R!3sѻ>}Jc|?7=іFF=%\k4:B%\{ًM!eG/ZQ[_RՊ0CG?}ӱˮ UHC D"D:>2R{ʺ4u׫~gw3^QryaQzć sV`mCE.?6cfmQ5.fҽع+#3~ 7l*:4wb=m(!eƌu))7vj|)S&6fl^*׶o.$]>|@ٹ qkihOiуv>/)]NŕYҔ[kű*Kf4b]vJ˛Rle"R i',JZqR*m$ӟ~c{ؽ> sC{|eJO JMu4jb}pFIV6 WT`ƒ mkkgnnNTlᓹ*/1iG@2qٳgqҩt 0X]~ʼ0VTRnU\a˟MZnbsWlYJP dرK.7Z]vٵfͪ#GLaSʯ^{Wնn-9s"hG*DSO{uQTQ_\ap]iFԦAk5<\ҜU&"!vQ1ۢH"T}xC>4QuѨxIA.VV<Jߓ vI;$-5~5XqsB#lu|'N[V[#UE6IѡW-Dg:(mZti-urk)}vdJ n|G){cU Z߻s∟]$He?t~x^Շ;{ JXy՘3N'>ya1??w~x0 *PPB=uUs6R羅N_R sqǮ_qXllۿw=|x|Ԯ'L>dR [䍛;C?|SO~@&>{m6opn؋EۃK\QHJjX$m$O3'uSvw_:[̙+{kO?H:nJ%[؉F=\ҡBH{e"!f/{Zzj;+gಛGI }|Ϛa ߮ kjD ~s]AЕeLjM;51b0֠u~Yə Cޏ پ3f„wl?\r˗/^xҥW$_ti}3f7~ḳk_e[Ջ?y%>iڇ3}XU7RUJkM=\Yᓟ/yI;fi3KOOTѾ6SZ5kO7_%ZL`tRҍ3/Y!b!!!!"b߾-dJ4{Ժ6v 1F7>Z:7Tm۪^dAk )Q'᧟6m4|xܪzvUoju[y ٰM7o}d׮er!aHاfGCvuHa!ۙ8)ߪJkU xOJQ?\{uJ"6m! H> 'O=zԩSf͚9m1rϚ{DJ٠Q4شBTT躻vܲUW ԰ֺ3Q D;*'WKhkp54uf}M[ZX'o`5E n-vDtF̈~=Ӑ;KCw5mF5m[oܺy-AA7i;~f,^hɺL5#SZ gEFMްyІCX)pg 3Aݷ])t3GO5tcVi3"!fDGN$R/AAL$N$LjN_Jy  C#3׾Q3D9s6A D"D:## !Y5KaDl#RI䨜(=zgـVNrvͬ( LL,y'9ʽ{rpW!#kT#(--aNC[IMMͩI\ D Ǜ&5j `Ϟ=\J#y󦵵uޟQFFƃ\>}\cQ?(4^sHjX8yj6m:|p fffnnn0ǎ˩̙3s0"@%|#JOO[AWbD]^c ĈkTBԱc@*ܺuKF_ys0"@%*?5`9 CnL6L:׷_~W^e֮][D /^ҥK;P~D0>>^X#G.\\T3gϞnё|rΈ^~Mϲ޾}++SBVX!}||N>h"77"E?N:QZwر>|oDwSQ\ETgD\T #jڴig9TPI&Q!$$ӓڵcHH ZhѪU+RAz)֧:QgD)))$"g/^<mAr Q?zZ9#۷/Փן ͩdF[0--wfFKKKr$Vɠ W#z/]De2Vvqq:_يQQQ%K ߈ic*U3e1"@jD>5rdd$;8lё#G <<3g*(^awԩq1)6T{n 6Je0ukkD߿xiՈQF#:Wϔ*ލhĉ:I֭ܶm[N:۷/_EkDk!F#T0dzzG>},IZZ9϶#RI?Qݻn:mT#F0m0"WxDFٳ|#x P9:/u[)yXMv iӦÇװ affFsر9s:w #(===#nSv^nbUH:vH倀[n 5oFQ@ޞ?} _7dԩ(666SڵkK(Aŋ_tblDFabb"{y ȑ# .lnna0"@%|##r+unFԴir(&MCHH'۵k*TEZ"54h>b}fՈRRR-Z>>x1,,,h[ 40"ds:ڶmߟʳgϦrtt4%'''[[%K:t͛?A9׮]S7޽{kwHi*5mLԩSdkL> ޽[FR4AZl #FtA0oϟ兯Uۺ #8q"[n%~988ԩS}˗zOvOժUu?x cP*ÈLY9gyfngf&Mbӧϕ+Wآ xXZZWX}Ř?X,V';Fa @ec7ӂ#Gx{,/|ݬmjj@ |#:km0_Q7s7FXr[ 7zm`D߈N8q(HHHy0"5e&/PWr[aD gΜQ a[0"dؘl@S'ܿh`D0"F#HIe^ӶV춬HMgS@{OJˆ`\H6pfs_;eC^M# ʵ?uZx|5YFg}>o~xNm=xv=ՈEO9ϒsi8rKk+YdnbBFC6V 7R*w ?7ISD*sM^W*>`ѡr/z*uNn(G跇_kVZ擴][u#G {@r<﫷p6L.=T7 TQ6T yn2`CS IE[XG]i&FzU!5Zǧ.7]~އ{YZS{W~ۣ?X'h#rIcڌ[ri'wYYV9DM5n5lkVg÷ƐͤF?_?YZWO>y^ʦZn[>JKߏyj2Tl[>}RGVK?3|PL}(fXF=m]I#&(:H㜻t5/7=yCC=T컮J Yvxn=xdz_y卻"&L]ovR#7F݇;vuas44/I?3B.MsU{m_识E4/lߣWOJ)j"牊#IC߁F#r6OZK:xAnaez&:`N۞??z͛7޽{=GvȺECT❇$E3"wEiD>ֻ蜷}x[*GrwoD"ѵ~y7e{eI*Vk7 kn.xe}zQRh6S.ӯinnu, 8;\%wi{W<~,/d_u z㬏?>SG> aG#%[COOK'y7o>?bY\n5޾o7ig+Y[EC: _|IFWz>}j.5vׂ}xߐԭ-fӈM}==lm ~ۧݽAݺ?ÇAYW(.|񄋾y܏=u.Y;{iW8× OmAeTd1ݥ٘vwԫiO#VGO,+NϗlM9-O{?nNȍο1/TߊMon @Y5o~8s]zhN>6u:I޽{'>o=mo{IQ[n.uEݪb^ŊN6}x.cNom <3NV`5YWHgS;R6cpo6?bDIBQG7:P]x B/)d5*(0mE+n/SsIT쑀y{JLd"J>̞¯~B^7)7:G<57Sq k͌v!-5õ I6QJ_:"Mw36$鱺RAjpL$PԘv"ZpǢ8fD>m#)j<.Kv&m>ru궘Ftfats z}Kaw1s3UnQTRU+։7U?]ȷ?VnK5 Qk^߽kA2Aஜ^_،^-7 ?cAg[쫵vU?/O3s3Ѷu,\Q]YE査EzE=]/7dxV+ k~qiWآiEu-ҒJJ'HuӢ -{uYEݼO ͷ6-PFw ;P͇G4">f2E.t~jUXsX`SA|P[8ſۣKA%=Ԁ6 rK])V)5߸9MboM-5=m|$ȎL$R|~|gGKļS^_bEەG׸jn|~ WMq *bF+Re:zrPRaҶ"9TTIevPB(ٛDke{;%[tGm 0<{Ͳ~TI :s_$wʒ-xڋfw'=_ޏ{#p=l\Ssߢ,z~DHz^{_|#R|hׇ|}XEon)*@lk?&T>wz@#=!=|߃VaFN1oop1#Fٍ+cC帅SUr[N{jK_:".fQ? '@25]M:2aȚ32H޾}K?ߍn ;wqRs=&&#z!5-x߫Uru-XH6WdgW@шNZJrה?o3 +S~Tm&%T{>+Es?7hկinx\T Qk= yQX*> amb*ߓkl=O_=őQ9b1\I',|v?o(L~w_fI/hNssXq4SwZ֠iP{ cbH6I: O 1#֕,'NTfc8ʅ-=C}u[&@xG*7*μ~Թ"1n%%J/*v.3ZS {|CaeE*^t88CfM*VaOhfW*Y /b#Ε+_ue2:)|Ƚ.yd]#j2z{j`tdp:=cQ\'>-W^~ZCSGo8?4,R%eS;(F_Ƴm1F_;,fKBo5גDV?Xu/ _~\WJf):Y){Y;\E9IefD"٢dFwR{_(0Y>ff9qITZuy#=GVR=vɂ/(pJʿ|y3!˚ITaFT;fDq`T%o ׇ&4wǿ!@NU.LŬJſUk`e!r/@wpֱأSJX&a9ٔ}p#\ q/7]~˭[q4*7"3 6>0S&?U3# x:K7r8GܵN(5Qdoѳ1v^~U6s ϗ텇sACJYhyt-^S;6?Yز @ ldD:`Ca[?2k7sGvLlF˗C/6eǕq/87hթ>ˎw[x!ScFœ]8#_ιvُDӻ 07:"\LOL-ve6YA%>;v;Jf):YLӓC{gv׮;RRI+ 缕n8a|nOej7DXiO6vMշc>] 5+fɎQpB)*SWBRw+ZެU-if?f"UxrDB'x巽Y=vYs FBYxsXEN"OR$=:ęʳzوT}z}.#=!yyk/NSή@Ú,}"=桔ڥ(xO=2J~0ulfƅ|ɕCie=lSMvάdq*g9YCvi#9ek#d틊#O5uJ~KONW%%8Q+4{*#/b#uR*?̈~PL<,tE]`2g X{&u˂# ;5b]_x_ߚumˣ֟L0`ȴaɈ]o6,k&}$<[7ʮ8:P@eg'OƎ su-ذY'um|hZ/FtɗVi, IH#~'Pk~,+)^p!wׂW*}䔑Ո7 bӺMU-˖Iأ~JyzҋXt+X.,v/WNhnjLT^+9 [W#_/+k6Uzn[mY? b.ntƦbܳg<(5Jr[MdF$o֪lv kvk"#sUg,:{ њŚ {|:{72/zH^Ը\_E_>dpr<] 6`\p4:s+4CT!wBQaFD'URy7Z5[˵\udOS&4T=MI P-i1mròy87Ns{n$;GHQ69rSqHB0'ReZ2Q)UF^Ԥwru8`@Tc#rh^gG5p8Nز @X5(2)aF4EfD&"EⴝWP}fNF4z!k8#:zdD=gɽG5S VٶU?-lm ~2ԕj/ [ֲnQbɟ|~j"]2wb=|ϒF lk%qo??վ% mrb<ˌhDR_UlF$_VbCZ_ry|1m (b>A9!Jߣ_HެUurE<]edq*(C -4DŸi|CKYhXl3:.י~w ׭K-_f kkU@P`֚ZܱԿl/sܞyІJx}ר8[uK8S) \_֥8`$rù7^x#|c]E?fC#/d+}[.|IQjʮ#K.3=y)eΞ [/]#:7x75kN}groVx]JHQ׼{YQH^$]^+LJaFt+=]e-UYOc9U!{v哔KKأh_WH-pr9ŠWGc6]NUO:-w.yTgo36+N]sOߣ7I/xK/xe'̈nmvf?YOMU{tm]#g {{Vn"/d,gk*(VzGaFtw֖ 8o..1,uIL^ä^#)ZbqQD4@GHxȸ{ƃLB&_qRvhш#7H}]ԕmeӈǏFK_[oCNh[~FOWGI|ɐ絩E(a=|BHv95RMŘ)~~F)](]ej#m)_nqnݺrDİ%_=SɈddXW& ZuDhЪ~^~tpth+d߈Ol< şmu:Qo(.k)f[Zv#ŖҳA?Wk9bHF=CB @~pVk٣w~:B_гӡj٣/F5NnZJfNf_|- =4ȍ-_!\R }KzsS7i3}_9?cQ\%}'5܅F]59ЋWƬvѣG8~yaIHH JNN(B0"F#4_3b٩SqFwJA(5B^-;t@;πpRgGp|*LFd:3MƢC "=>;pky@A@& F|*LHå~U#,ۈ6mdii)q.ÇrY1-[ٱbnn.jԨ1|ͫׯk׮92dO gO9ƹ FZB[[[GGRJM>=G^s2͛7WTvܦnݺ$9 *#OTH$JbŔ3!<<<00SJ:C‘#G\\\81h ovh߾/jXܢECAE`D}t3ŋ=^O8lٲ  rΒ#FqFgϞ|L׈4L:U.~f͚ߟNY_!C4 Usr\2"$:uDtر׬YVZܢ\AtYOkn`fDyz2 899e)-{6lջXbРAVҀPK$[[۲eFFF*E-&&;;;oooZM:F{y:#*Yȑ#k6mڶm_g̙4lgg.]ܸqi܅ pvԼys*}pL2zcg̘A@L?~<`/B׮]ۦM6-$$w17/_?xJ[W9Sϕ+WkXZ5[*2.烐z:ÇI 7M4 1IHfau{ZƉFD38MQQQ:u:th׮]?sq:t@ :ܱcGV&Ҁ7o^tt4׫W͉kuܹL2M+4bŊI4fr-*{yrU9 mEPXX;2CKI/^H=/^|{HܨQuR'NهuҫW/~UXmm6*?~Ϟ=.;FԬEth$UT{nܸѣGinUy**t𕶮rꧧ}~HYt i_rV#'!;AVB`R*UGgBOOݻ mQ>&f5izE_op6ӧO/R n^ *[Z! lQZdcؾ};kh!C888ʤZUVe1R2"vzٳhѢ{V >9ƅތ/_Ɔ&ҥKg L5^Yn<<<~gk?Ywh/S dɒ?5clܸ`Y{{{[Xw͜:utugϞ$N4W.\|JԞ24FDh/lٲ9Y3E}׌ᵵSHԩXf:aƏO]'NdGuРABH dw;H27nLuEg _)}}߭nOkv_S8:K7`GյIg\wP0"ɢԐ/yJ#R 4<{j/>U paD{p<wF#k#UF0Y`D0"T `8`D:.}m=;dbD&^`FPUQ^yԩSj`D05`D0"F#`D0"F# ={{ jA6oXP!ܾ}nA```,q4<8i0$111$$D,[ZZVPaZ]nІ*UԹsӧOSMg9'Õ 'E/;r-OOO6^?,qrÈT2`DyIݺum߾}Æ =<<&Lu-"]rׯRJ MD_ӧWFdP9ͿY:.>0"F9qFޞ_p[:%J{vzw%VhѢҥK;88І*T:Tk׮յyϟW\wܸqŋ<]vM6… S *GEN^`` )b~^u*EK}vh_FLUGIbnnQD뎌5ipA#T*tҥ*EڶmKQcIIFkS]s@éaTz0j=t~p;mLJmƚ)RD" >\"8;;ϝ;wڴi...b&W_X㩙ʓ\ë?Ϧ#Kh-$$d̙![Բe2eP~l/fI鵮v?Jzze=4mڔQ͚5rʭ[n߾?l֬7E+IejɉE/G^4ԍjҤITO/#T>!ѺQx|OezlժҨFYXXP 4(uGhDe:hwDNTOOAV^6l +FlTpjfoZ_~Ou/F5qD\ilvh۶֍fD }}E+޽pѺ#A(CCUN:ʗ//Rs ~޾W 0#2}WDਫ਼s@énTzrJt{ >\e|N9W_4Nj^"h}`DyIϞ=K%:Iӹ.DvvvD͆pu͈_~t4Rz]ҫ"AAAVVVnAoUu@(@QݺukҤIk$}r֍R 3j׮oĈTO5۷o_Rhst"!5ᾊB'Eql:hhk2ޮntNr5캥ŹsWQw|bx+"pjif,ЩDo߾,>>^]yN9W_4Nj^"h}`D ?ݼ:eze} Ɣ_LyM v zODEE)Rw]tiӦk0l&Ř1c*U$Kc @~رcK+QĬY8SSwB$cǎx`D0"F#`D0"F#`DѢ9d@P# FQ>Fd80#, QV̈́`DA#  1F?0"Ac:#JOOӧOeZ:IKKYԀ0"AcJ#޽{zL#B1(--aN0"UK&;lֺ>~឵#0xHw Ƀ(##A.@k2`DtIf7cz?ڼxkVTŝ_}THnoDu0";s;f\=5s}M>FY1s$#i&,,vۻwѺU`DtҫW{z˖+A?}}>I3X@#ڶ}YJe삫Wb ,,Y& oQv>77&vt9|tc% *$vϿ(hd)k^ʭ8ͻԞ= *B uHvtwFl&i\ IhE +uHٸiiooGvܕ% #Ժh{N爐Dm#Fк0" #=q[Y!vH-^*s5׭{VO@${eɑ6(vѨq-*X[{R 3 i<۬]7V*=z۷cbc %|Ԓ-?a =tuuђk) m‚VڭuL?\nXq5' :tRkQCܥkȏ?rV PZ;4 i*&HYjFXVVo׮ֵ}PpHvFZ,v9SVT'H.Cse}Hc65X@W2kbXW[.}:W~&+N=.'iƱf=tX6mPSn*c xET^a&Qȝ+n>FGçE6B_j}&blOM\%Kru ޯ_'E!0Bk)ԭ8g4zQuHoD*]\\ e e\َQD ;j4NRџ嗡tqʲ48:+Kmll=Gq-K%RH6DFCkk+O+\R6,YTT fIoD'IkرCH{f(SFd8DH_ *?zL? {{; [5KBL9|#:&{zzzJ$!L#B!I8UR;;[rK]7_CBL<|#; k2`DA7'N5C0"F bQrr\1W0"Ac ߈3gD(zL#B1ƨ4+E111QـVN^#2`D uF ~A (#2D}! `D0"FdPd>: ]={FdPd/4"[VrA#B10"F bt`DAΈ=zgـVNx>2A`DA҈߿$Gw^J&Ƞ!]F0LMMd"  ߚ}$7uD0"ݺHVVbkpJǶh]$PQrd`DoDuD0"ҢE}};i[d`DFf ]D"߿;wsA#B !v$ǎoc?I3uEPJ,jkkC5noh]#B '|#33`{{{:Gu-B/s#2(`D!$haz}wvMG/Y$DQ ΚМʬrY4qtr>}}ܻw`DoD)HHHeedn׮ֵM&Ƞ!cǷyzsWrll7nZuΟ+@5"PT677gׂ4,!]LhhX,vqq^/s#2(`Dç'OEΜ5]h]PMh*yN=y10zMq͚5D0"r4n3W>v|b;99j]$PQͩv!(bBPCkD* ߈.%))I`{B/s#2(`D!L߷M&}v,\؇iD"Tʕ˲דխGtTfV=zr^.!515 0"FBFSBi'++K~:={~U"oڼ|f, VDQ"E|ƌ՛Z ߈N #\ M&Ƞ!]FtRdfff;vҞD0"A ߈ `޽$&&FH{^&FdPA.|#; en2`DA7'N270"F btQrr\1W0"A ߈3gD(y?+0"F btQiDWbcccbbN\z5#FdPA.0"~A㊾g`D0"F#2(2GA.=@#2(2A-{DA#B10"F bt`DAΈ=zgـVNx>2A`DA҈߿$Gw^J&Ƞ!]F0LMMd" /#s)G edd<[M&ȠM~}vlӦd)ZI3vA/FdDf ]D"߿;wsA#Oqpm'i׵.8in۾R2NUpJ\?\dQ[[ҭq~{GEK&-WƚMueEʗ4) /mQ j]эNN ];un_Wϝ?hPsssVIjԻwjX0V+ GL妑FHHYPPPpp=#FкD0.UCܽG5s= d#ZT6 ݬynxHXiTOBtLe%%ʵjUѺ(|<6.]C~,[jy SS R1*7[]76ԣg};+@K;vj8$KK j҈UN4*vkh8M##|#JFBBBll,+DL'FvEen2`D(?m57nZu#*\؇̙7=|!l.b/_9Ȍ]*aݲnU.*Y(=lҴub-a *wAFA* j]4YGֳM&T,vUl1oD*]\\d" Q>ˇOwO9k(-ѺHȤiaaAmNRT~.uu;8$٢+NY[[xа5A.(6HЭuMgqE1O.beaݛN5k \E/s#2(`D)G6scǷ랓EB&Mv}pt]HzHĻºI_"??o*߰tj cFi) W &4tu]:T&|.ivh%T#4?7 °sqqIJJ؞d" Q~ }4uiӤoߎڴm"dQTPeY=shQ{4 ˦2ѳ{jmVh TбEn+T(͙1P||=iQݺ*#mJoBCZe6U\ ZW"k5IP }DM##|#:kcj2`D(?e>4!8YYYTد_gϯj]$⡲rwp\U~f, VDQ"E|ƌ՛ۊfՈ>˯/_@c9k1P6m^%߄nT պneY[[ Ո޼KݻK yrFGFtZr6fen2`DA ?O WIzSdQ cFtRt򘙙رCH{^&FdPsBLP1c ^V=oDw^OOOD#=C/s#2(`DbI8UR;;[rK]7_CB270"F btщ' zLA#B1(99y_.И  хoDę3gsļL A#B14+E111QـVN^ #2(`D FuF AAFDY qE߳`D0"F## F}   =Ƞ!]`DA#B10"F btQgD=zl@S'iiiy< 0"F btQiDܻw/g%FdPA.|#JKK{dffen2`DRDr.%ȑf98bvGZF n270"F̳W geeR^;~WH`D(===#n270"Fe_%nCt Hh P2|#33`{{{:Fu-B/s#2(`D?4ӫ喭KB>Э{'*O8HM.!TU [v=weܪUCŵ,--wh҈U]7ѳyZbԠc7KeRA~լy=' _:I0"FĮqםE]#JzHĻF6e#W:>F ߈.%))I`{B/s#2(`D?_`"-5ͼ}$fMƍz0_8ʶ6:ڭu kqaR\=I$wQhK>.GAn^sY- c(z!*7s>&SFdPy,yEXYYҼ="OQ4EYZ*gK˗rpȈf_KeY[[Z U#l&=mZpEVI,tZEmllh7nj՛ۚjYȕC:td#BToD.G`c^&FdPAB"##wlǎB3270"F+|#:&{zzzJ$!zLA#BtA270"F btщ' zLA#B1(99y_.И  хoDę3gsļL A#B14+E111QـVN^ #2(`D FuF AAFDY qE߳`D0"F## F}   =Ƞ!]`DA#B10"F btQgD=zl@S'iiiy< 0"F btQiDܻw/g%FdPA.|#JKK{dffen2`DK $bQFFƃ\d" ϳW geeR^;?Èr.JABgԭ^&FdP<~zߗ&hooI.![7OT3o,kCboeUGBBF\q?|'iƱf=tX6mPbA)"M~B׈+5젺 4"C1`BCCbKttzLA#Bѹh*__q8y*W:u&Jeo-K%l ԍ9ry٢h6"jXa Xs_ɒ 9)oDѻwo:j֬'pM&Ƞ!Jӧvg=~BԴq\uB?}$=8߼Ktf[}trrEk~twu4,]#RY-=Jkh0"ssszHu. ]KRR^&FdP77&vt߶}ksrK:99Ů:+ 7; 133 pĈZ"270"Fd'bz]D\A5$ 4;{ؾCs*+'ֽ'L[WQ`Y4!ޣ{-KK jHˣQZT7ڒMjSu {l׷obhQN-AoD)HHHeeTl׮ֵM&Ƞ! Q=\͙%C YէHfET^a!}uJ)XE,+lnn.q׈=lٺ\嫛|;gucǷ͚=z谞m6zU D`FtM0b%::ZH{M&Ƞ! ΨT#CE8!F%2mluJ)666ܶ޼KUVV4=2^eAD<AoDѻwo+5D0"$;5^]կ]zcZ:D øT^f!Ës55"E|tJ)|a׈"ˮ%_=$]#RRJue''G* KdAoDagg⒔$=D0"$;ɸwMB|Ҳ*$Nt֠zJTS\a{9:9(H~c}DG4nݺR _r.JAC#r^5,̈e ODA"\T0"$!)5ClaaA?L5ҫWXζ|RsU2M{z+V⥓atbV$Ekfu"0|#:-p93270"FTT JIDFFَ;gen2`D1DHFtL{H$111B3270"FT`D"$|#; en2`DA7'N270"F btQrr\1W0"A ߈3gD(y?+0"F btQiDWbcccbbN\z5#FdPA.0"~A㊾g`D0"F#2(2GA.=@#2(2A-{DA#B10"F bt`DAΈ=zgـVNx>2A`DA҈߿$Gw^J&Ƞ!]F0LMMd" b ɹ|DQFFƃ\d" #y,\իpzνl ܝ 31>D(===#n270"Fd?^%atҺucCt/SO4VvmDbeeݿ;wh] W*0"Fd?}v$[(W䋗)ͻ۩?W$'{>Vqt/[Ψ^_X'iM%K~xbsF{H\oXj}em0D<XP!صSVuEÐ:EK&>XWT&Vޟ27; 133 rĈZ"270"Fd?eR" FaaaѹKHn˗/5ePV?hpw֬}TfBQCm}}ܻwMPoע54nRʤ7fJ`vQ SD"f]7V*=z#+V,uRÐ:~NʵXX@WRܜ]aǞΕ_KU,]&!VIqYGֳM&^,v0$[t n2ޟ27k ...Ben2`D~^#:!Fш6oY-a5dGL'kPMtqʲ'e\d>V۹M MCÐk\lE7ݻ75k֌^&FdPOGCZݓTEq[zE`ghd&E\TCհ0e֔|" |ԕ/_9hOG\NNfM?.!))pxJWD0\\\'270"Fd?_(\G$Y!?o#a5^՗-Wb^N>@7ׯ_jߗדj nYLvIKܫW{(F$XìJ`mՅ?$>FTFt.d* #y,yEXYY:s+-_Ԝyc}M&ўĉ}IJibIHfB(QƆ2fϯfjD"@2ŬHքUR8<SiaؘD0"A ߈N 22lǎB3270"F bt1ݻS"id"  хoDqqqGsxM&Ƞ!]FtĉC@BB^&FdPA.|#JNNޗ /4*0"F btq̙%111g%FdPA.*JQlllLLLT6թW|d  EFdPo b\rF#`DE E߳`DE&B# {DOSA#B10"F bt`DA,`DyȠ!]Tѓ\F  хoD?~ P0FdPHΥz )GD -|#| P0FdPL!"5V Nye1j#2ZFt޽\0"Fd a+;4g-߾Uͩ!(MaaakזH$VVVsֵQ#2(`D&s:;\Ѡ"эʗtrr,TXکs?­mJ8:988W-\\ kjr+5#ݻX05Pg#7R{Fs6nZD"o|2EqNh]ﻒbi_ r`"/|#33`{{{:UFu-F{ IEYZZ<$\n~ZUzl׷obAN-"RzHԬynxH2MߝQzc&NLvkn0 0:4tYyTweܪUC]h-'*O8JFa5,ك(E L1*ڵӺ#=`DȤXIqYGֳM&@,ve se}HwKNMTc}aT^@$a:/RD6Qy:ЬdɢTnҴΠ=#ۮZ/}W2" aQL$oD*]\\0"FdR`DgQ8[daaASg4t璢|~mlx^6n0w'OErU\ 1aQL$oDѻwo:Ij֬'pQ#2(`D&yVs#U #Zvk&,2h<׈L\ԴU\ala\V*^3GjXaٹ$%% lOrA#27"vNr%zl'Z>-wіߏI|!Tvssu5a:7~ BS]_8ʶ6:ڭu xUQv^NWâ=H ߈0FdPL*(|t2Ŭh_>WiݺM]3G{jh߼KݻiC`s捥z++KP5 @C!747[aahרY}׌z~آWXΖVd;%d5,ك0l̀0"Fq}}/X9&%}Tz S;@dd$$fff;vҞ#=`D㜿T~tU>*oL gDOFdPo b\a/^)ۻm۶_^~ nݺhF̈D"{@@@n޼yvZZ)2p`D@o%5k@ #pFD888H$rʍ5h՗.],0" GP4"kkk777??RJUZuڴi$EV|209;::zyyUPVZ{ի!Er޽{oذ,PFFD.ԥKgg'>x`ܸq3gΜ3g… o~}(#rΈ߿?.\ ,?|RR˗o޼e`D@栗 &;v "dÇz/^~z/_Z`D@(22rժUgΜƍsss;wU={23X`D@pݻwo޼͛)))6lxu||˗/gΜ #2d`D@pƍK.q ]reӧOz~G4#r[n )^2Yٳg] D F 8133SW0" LYz1|fjX2`D@Vi`D@bDF>|@*ԘehC/Dv{kk+٭{ѻ ҃ 3Q*2"F@#tb={TTp(їi`P(BmazL>ծ]j^qpB`"Ύz.[}˗rtt<Nj)k-^:\6+M4[0Е DQQyT>h蓆DFDj]``~{Gֳ9Tc2lVŊeh_F膢yzè]ȝ+[8An{ussI٢!е[*UQ9$Z4wښ<$ZJSh'r֍\-"4A}*5Ce&ҕICUөLԣg;*Qu* {ءc *+;;[ DsF膢YYYóp5gwSqb* "[fuisgIZKMMTvttP?|`iiMy6ًU>}cT^ʗ2u![yfnfn( FkD;¨CqN<Me'v-"+0qT$ֹ$Z/WT4j\WC?V͢W̠˗{>iHJr޼Kenu llÈPvkM7]zcZݺ/E CzKM; :ϙ; -- jΈTQz5䫇̿^#uJCR%zL44SyqƽoJ}׬tbT߻Fq6}D' d2uԒ b2..NY9?X6o^=:KFDC2}DN2 En]R|}e,իW]> k֞VVV]Q,T̟ݟ.K hMгfc-6:̼γWdD4$!00^wBO/Yq_-p:iooHoD/J|0"@7TN4#z 40" i`D@%#B '0" 1ƉrD:uR )&F#`D0"F#`D0"F#`D0"F#`D9eDX#D$(5T.}#ѣO>3xh4Դ )#F$z9PߒKܿr޽8)#F4zw(1IKK{hdff7"чz ddd<0Zh9{@FT g` r(&l+2}' z\L~r"c&U*Tӳs׮]_޺u[fuŜ=CS@?FT\fdDeƾ`% LjJ*eʔrV+sRӧO9{((MfoDҢ/v{X9Qѳ2)K*TIW%E]u.h򍨩^PQ0~GȌ3b *EgϞm֬c8'LgeeZV-VٳD_2dQ9{"3\$ P^~ʅd@RDe6_P%H,+[8,$6;T0*WL6mڹsK倀l޴m… 7oJ6mԬY\H])Sxy܏CW8*"gϧf]٥ߊz|X_iLV~Vl;2\ PWq Yf_V`+_0*U$RfTMbŋa +~VOjD=SZjT0ap1"q?ږ%lEbm-~pQ!]dy.4Yǻu# +e6l_p!\Ǐ?q℟{X\kjhLr30oD?JK뜒 [yҷ1[(½.FXPγ֚H/,_!]L B ΦMOhOOϱ l߾QZR++[jh̾F#GO$ȾuRhpگׇ-h$ "񏅨A3"֦ǒ?8t*ncJRe;- k}ɬ*#:-3cr:uܡC*TѣGcC*)S]VRט^:-:tp71YJHX9TȥwTv.8bU} ~/U]B"J^v\e+?!7YUFtRʕ=ʛ6m277زe =]6-jѢ#U?^"4hРuNNN`ɒ%;vzzXR} g` d߈IKg)ciceVȪ,͘_آAV0"AA  Hnc+4P!/RAAA1AAdDJ?5]l*˖V&?[p &ruv<5fԠͽ<ĮN}:6~q+ki(?ݹztyEhsP}+ RG2Oky=nerAzz'o  H$;FԾE$sF楣)H$?NAAL!ٹ5}DSvn[>V߈& Hծy~WcDS/m~wwoU;&;Ԑ%TiD8jVozvAɛdOnֶaPTw;[[kR *P~=Vf}t5c(: Ր^-}6A>}#TgDW.X]Z8A1#?=  AA`D  /  0Vjc>f N^AA`D  ϮSaHlI[k=˱?*L-q;y&k?\MKFQ =գuAA}cD[bVlOIk^c@fe5633Y )Vv^7>K[GA$GjogTmTp`{5k|#>L> stream xz{|Sey6IASnӖGJH66hhRl"XDpp Έ"B@q|::\ơ8Gq^]ni߹翳ӽ[k}0ёNos{0Prjޔؚw'[3|AJg]ۖ?bi'DGp01Swۅ۾ҬYڢV==x[l[䅎`{gKlW:M$Ix8vߢӽ!]8tTJmJZz1+;dXb;1-9fOֵgj%'ɑQ]|{w8=ߣi '=o=فzkWbr/%J2"yU5#(r!31KH;v;܋}< QXIV#6}&aNiG![q_NoN$B6`&ߌTp>[kGO'!YU5ya ux_=܎BTC虜1C`4.\"ذ~Iܸzry^9o5siSJ'L_\T(ȷ[s}&ըUJ2@JDH0*GzrPem\R5BP;)&A,WpI"gu4w l2[2V5"O)|b౑+[JmjjB;C \Bf $Npĺa\3jV7CԼd{Z ƪJ[~~`r"1QIIdU)**RHBwI_}ɩ 9B[E6]lUW=)NtT~hŞGe蔴,Ss$"C;8>d4&(cE ",i̗.cs``Z`ptut]* 77gvD} r}Kj캕"SZ?#-8Gda`0;m"2g@d$J Q:(MmM}c- 90⻃bZRb1K[+(, P^ZR#n$.md~~}jC,aHzUMߦV+*0t!,mxrƪ]e(l„E*i22GLqήVUbb45RbYWBUWSeIilݤ*%f⪮Phopܵ| Tv6ZZ+Kk5u+gȎ ::5F[Z .R UEj p wlld' UJOjRiA6D= m5A F !NSHPc}.()VFGp (M  s9WKGF D<Ԑ)p:!ХvwIB/TF W0s,IcQQ8r|CVV'6꺽~EZxfA@w!R,#a%i 6ԔNJ({PzI iCԐ0H78uIq&RȼZWxu غABB39l({[㵥9:ÛpW5 +O'/]X.VL6.+UBH*Z`#fL &\tD|11_{$'WJx(;1~ X٘CR}eTT'.ß'sq'RF3Jd5j!s1 f4)|c~1x _==6ԫ!?a/L 2$3SoQꕅ,S&YZ6` !VB,B+UVmذxq̙Vgؾэ.e1xDX0riS+Jvj#[Ͽ~azY힃]]?ٵD +3m-c I˿W_KL؋joQAbUgRs$ǏXa:BVpY$7p^gGg~w=?nf\ǐFƕco] d9um iV>'[Rel`9r\rr ASv*/( 4(h* Tj?5m }5lUGX ǻNFˑ q{xFzyNϧmb&_VwG>m{eb?רPi9^A8+_ 3 {[<ޑ Pe28??mKGso&ݐ_0R:_m[s=J%+Plw_"gCq l+fU*qjBϙ j_4ЧQ5Щ츘k @-% E$>|C*.S&CqoOOB8~~nWv}& &1KRűfL, B.傘 Ws0say$bוd-Ϩr#F _>9a7@s" /.8N@+.@W˅0too)"rT턻bt7W\` d!Ϳ~c{\yzG}6N-ݙ[S7hl0F=ͯR3Wv~/ZG'ADB5BZ#h0NyL\5rBIۜ N9.SaNHpR _8j g^4-/׳ݾ7qxZ۴9mk+wb[ۛN!pv y17dRm' e*MaR>ijx(×<|{IxXʃ hA$cĭ0p*Q+itx*爔ǝ#Ƶ{hF;K/LнzRL Z |1𶔓p$ސVg1y,yA<sҫ|Zd xf}{7XBL'mFa\3Iנ"Z 7hm,!ϨS! '6i8';'Ξ8R%SKs΃P~N+'zxT9e Ƴ j.=_`#zѽJfҩ!F flwuPS[Ψ x~^dM>6Zη]90l. U8o̿n~DѲ Բ: WvIKuPA9:tЯeJ_۸]=s_WP\塯&;cO~.wp \PHިF9dH̨˦$< Mr^O zl,"-2>]9Ga%GeXES2ƵD5$2,$93/;2̓d\vz['X Ǧd!\ $ǭa~ Jaa5xT5$OqAۊOd8P?/:rKz$*#"pHA9kM ' ).aa4-,,cx0v  KPGu0Y",h.]YN3 ĒmDs# k. \^rNF5B2 ۃ[hh'xx]$ JK0H tX%p<Dh\1I"͒D#bQ o 7p"1?@[ټx=Z"ln4 !NDu qa # Un -p5ұNH`D8iU`Ry{84ڶ`c(Ӵ9l+M{aip X<79;N0\i$QGk0l`a"   vL򅋯1[@&m R"B6BmRWZqt/l<ߖhGEB0>cۥaCQڂIҞ(mM&c6o\ҌI)EeGKnT%-m1R6J_Xa|| 3CE9tl%H[i4ַTYw$LBD; B$Jbd SV db'⻜pVt!HoCy(3HFI)EҾ__9BKd?| BPC3Xrk:R@ATnو~cbӁ$ L5|?u$ ?wI~R$H^SoE\׋|aR´Z% QOTRBZ\Kb-ZlAf!f[(­r} ^*?o&ٯ5]fk/ˊ?8|vggR~Y}:hI>.' _4|DϹp ؆?a~e{%87O7J_fg> endobj 67 0 obj <> stream x]n0 K/w羠;$* a }Sպ6!M: gBQ,ي {(OBUUD`ͿJ $IE`\!o7[#yg 9#V #k{PK#d~D>=3Sϊ5Y`0gME_Ygg"x%ٿ*%]rx~F'06z(4/Tg-a} endstream endobj 68 0 obj <> endobj 69 0 obj <> stream xz{|Tյ^1$d$`d,#Hq)u?YCpofaT+o_2;Hܘe1va3qRI݆z=F REVZ]%.]TS]rR1^9e̾tVaA~^nVfFLoǝdZ q&A+G:ʧ˶˕r5Q/G%dxkkYhSۣ bv]0IL夜cU^yV.kAxW'G?au 2X#`RQihͦvFL \2bC0h74Y\V([\i3ZrG*6D2Q¨{d<{dQ+Y۞n~;W rުhMgqh:C.iKV<)x?֣K~J(FC/W zh+ Gzewh$>~(T&-Hbt靮h4,ڗjr5r{M0ArPUQFtpYK-D)Ev:rdbLG'F&{ѶK[BNo5j|?:k=55xmrY(9*fp 7tʐ5̟^A-Q."J[ݮnNF2*6'M-Q ůYzg`=U̘o(䭜.MѦEFI{6+ZPJj@iyv.>+M-KKlF$6@ Wbdt¹x"ZCA[YϨ>݀zV-"(F4[Tix}Q j:D: k]'vr8,kq*vb?ֲ.dr7yRBFô)\Ue)B5O4259ʍ.bfË'!wI%|qPVX.+[1Y@( 9wq琷ac>uHʼ\Lm#^mو5ly \p +}#3q)rv҆LR6 B Xkwa}> \c)!6L` g >v2$*Ũs khAywI#CFpVa "KW44DFBwIFcR-wRGj`#! h&|D5y8o%~ף8}m_Z<r\CO|TCa5Ru#Oĭ$8xA8Vp̖eeb[BNJ8Rr-XDRL@D㉋)89{<ůEB"J^Ir&$8yevq&rZy2_~y*^Wr\6 V₶5mȞ֭=IedΞEWdds%WIN}>xt$9>oǺM+'^hįnն6/~)J}>.XrPKvyή7s5J'xm GCv<#%++oIɷ{mC΢}~rCQN~ݢOVUљtBw- n[DE}ONP`G'8ɲg“(0dˬ(X&P-׆*BbTxKќPwտs޺ڹo[/o}~]wZ46?OHmc2oJ0$LubϤ3tb)26&q+`v[u[ǎWxu'د떘Ocq,b ܷf2J׶<0K} }gB'rEN&Ӎ8MsV: b*6SDk1s=L ps"aݗ?&ꅶ WO m]}u=_K^QOc9`yRD^EMv"GXJ ኩ%rC'`KWlF<|B5E.aYIR{'%Iנ~IS :԰A*%"%6+٢>Cm??1ݓ j$Hp#;C΄m::Y+ՠꝒXx>'v9'D1ퟥ!4XWLS <6ؒ͏yfϐbn yt[>xT{bC%T:MV6J|jH`%tvsVb^f+%^]:b~魠UۯHSsN)|B͉6f8O>pמW?vcw3Vu~CƕU-5vƄ7lEd0Mqqz^AoX8 JXQvjE1b^򀞩CUdؖ Ǔ@2%CA2š\h\2|n";l"IVZ*Tl}hͳ|dycLȡۃrd5 B 0Ð'>3O[8ofYДsD<M4 sgɂYp< Y7 jmL4t7 0N8s_mzښKT7<~G`Cc+po }5c~ ~m!"d[(n]c90 tj^8"5uK$oZz-j&q0L5IW"}lybly85@{͑c 7gj=Y\D F"84pFgmFh7gpGXrؔm$ V*^seʿBVyƞ|XQF^PRj ! ! # ؐCp1Xf0&N{$a _:^)J=/7yv 6W' {$VɵIJ3aN̝SAIBfr*h*`a$<>n:٢΋/sos^=8; a:^_Ow~ sQVziP ii^!7'>OI|ӧgB=_WrbW /wF-WU+>$0_ie͜ u&` $h08%" JP'\ $pI H'%xM$> vIm}(n!vJJܫ<'O$x@%}w!v)IpAO$8!1 bJ,q$XLqJt gG)quRĕPB.<%}B`kA^g$bniġTAaY #qH\HI1% `LzL-97B_NK|w!~ s8h%&6nrG\s·vB>'T: 3gRN8; 'wN ɺ8! NXw ;7N#'[ ]NhrBc63'鄗gDd0QNоʤ-tPQ(ūq=ㄟ0pd.[(qw-3M3zFc tJl,q~I,;6Ya^Q<.)-} 4| fW`iiny]EُdKY2ԦO+~ih Tカ`®?6 HLNu!Τ<=:Cqp$Acؓ¡GIq9p$;okʹc s1Zۃ^ONƽ!B]ı%q&OO';xsmsd4\҄ȣKW69Wy| ۷#j5 Vl#Xa&s?dF!^/ԅtQ?ޤ?c(7l5 rrYp$0=rs~c\#SnX`nxƁpgOΟ\4FuH$W %[0̕7wtt˛a3Y׏kȗϑqԏknB(w@ ӿNS=] 9Е"=-hN]Ǥ@tN垾@p//1#mOoOit,XOG)u y bK(VL`@aajN\b/NBƽ t)]3ҝ7Eޮ`eg'GMLXA*}H$4`~*h|\"[BJ_R|?FfZK5\y3gX{Bp~7?8f)Œ7a$2~l A"[^dao6H!L!V{q;ICgt`ῥVP&E-b߁⼵8:LO¤۽8sՏ0ŕIz'i/g8I"Q/1A!o—sa\#lJއrI׿ԋxf0XQaճT3ƭa5} :؅;E'0;m1A5']ÈIM-"_#LMulam]1-`Eu%|gdk3עkvǟ Ƥsr5}wgG2fav*4gټG# {gw}׵Zdmfq=v1^E[4?Yo }B{y"TB~kqF/Y4Y8¤R**aj 4&W`Xcښa+.gvf)V)^nJ:oMDduO1 ܍j(p4g jB8BydcQ.D`UYџ|}ScC|MyTԨe\|dmh̳e?5+(X2gbUļ&O2a!_9&MZL>ekJPv|=8N<`™.6}B6Ǚ?ߙZ;N^HciZ;MVy1A(`ݟRw縶Ppl޳Ί:#xfәNswfr$wq0~7?~f(Y)j~Ϗ P~7o&׏WӯG~z|?)2 bgg(Ϥe֌G<7(2! CʡCC"}>tйC(JB->$OrHY1?gl;ȍn*v o P%+#}@ŁPXӏ{#G3O RSR< NrCz}{},>Rn]3v2o#] ,wrGrv[ߴ۾ WRs yo;wB|~S/甛C`ȝ )bYv"w׬utZy{e,(YD E|s _A~/5Ҙ[4HÇ=憆5lMsR]zQHTj݋kRܵ5"\5Vj64[,ǒq(*yv[*,mmb)Ya)˸E_}g-|@A D#M99KF KUQ-HʲQmQҼrUoE*/5DۧD;P(0uD*}H81G /B_aa:kuÑHĦs$>qI q(2}ʎP$6y#}؅“+sz endstream endobj 70 0 obj 8999 endobj 71 0 obj <> endobj 72 0 obj <> stream x]n0E|"6 !)eчLR CzV"ؾ3>7cH:4t7_:ѥuiqZɳV}}zp(- ٪N/!ߺ}la}]ɍJGe:>OU\]) x'eemRw }U܅BR}k%sY5!u…v˜ sa^3 9Gyy̚y}?2o X{rOɟ5ds agKf's>O/] Sa^fgsf[Nߟ-3?-S.<} O(oއ񒁖j|\%oH endstream endobj 73 0 obj <> endobj 74 0 obj <> endobj 75 0 obj <> /ExtGState<> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 56 0 obj <>/Contents 57 0 R>> endobj 76 0 obj <> endobj 77 0 obj < /Dest[1 0 R/XYZ 0 841.8 0]/Parent 76 0 R/Next 78 0 R>> endobj 78 0 obj < /Dest[56 0 R/XYZ 0 841.8 0]/Parent 76 0 R/Prev 77 0 R>> endobj 63 0 obj <> endobj 79 0 obj <> /Outlines 76 0 R >> endobj 80 0 obj < /Subject /Keywords /Creator /Producer /CreationDate(D:20181106000656+01'00')>> endobj xref 0 81 0000000000 65535 f 0000642838 00000 n 0000000019 00000 n 0000266091 00000 n 0000311328 00000 n 0000313527 00000 n 0000313760 00000 n 0000313808 00000 n 0000314026 00000 n 0000308738 00000 n 0000314074 00000 n 0000314310 00000 n 0000314351 00000 n 0000314572 00000 n 0000294531 00000 n 0000314613 00000 n 0000314849 00000 n 0000314898 00000 n 0000315121 00000 n 0000315170 00000 n 0000315404 00000 n 0000315445 00000 n 0000315666 00000 n 0000280321 00000 n 0000315707 00000 n 0000315945 00000 n 0000315994 00000 n 0000316217 00000 n 0000316266 00000 n 0000316498 00000 n 0000316539 00000 n 0000316758 00000 n 0000266114 00000 n 0000316799 00000 n 0000317035 00000 n 0000317084 00000 n 0000317305 00000 n 0000317354 00000 n 0000317590 00000 n 0000317631 00000 n 0000317852 00000 n 0000274870 00000 n 0000274892 00000 n 0000280299 00000 n 0000289079 00000 n 0000289101 00000 n 0000294509 00000 n 0000303287 00000 n 0000303309 00000 n 0000308716 00000 n 0000310192 00000 n 0000310214 00000 n 0000311307 00000 n 0000311767 00000 n 0000311788 00000 n 0000313505 00000 n 0000643008 00000 n 0000317893 00000 n 0000518812 00000 n 0000580523 00000 n 0000518836 00000 n 0000580500 00000 n 0000623273 00000 n 0000643483 00000 n 0000623296 00000 n 0000631218 00000 n 0000631240 00000 n 0000631436 00000 n 0000631844 00000 n 0000632110 00000 n 0000641196 00000 n 0000641218 00000 n 0000641421 00000 n 0000641888 00000 n 0000642215 00000 n 0000642258 00000 n 0000643180 00000 n 0000643236 00000 n 0000643359 00000 n 0000643590 00000 n 0000643757 00000 n trailer < <38C0088D4B2638DF3D770E0CC4924973> ] /DocChecksum /A4D463B7257C91845DEE83FF4D999F05 >> startxref 644296 %%EOF O-Saft-19.01.19/o-saft000077500000000000000000000113631342117255600141760ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - simple wrapper to call o-saft.pl or o-saft.tcl #? #? SYNOPSIS #? $0 [options] target #? #? DESCRIPTION #? Calls o-saft.pl or o-saft.tcl with all specified arguments. #? o-saft.pl's output is piped to the command specified with the -post= #? option. The program given there must be located in contrib/ directory, #? or must be found via PATH environment variable. The default is cat, #? which means that all output is on STDOUT. #? #? OPTIONS #? -h got it #? -list list available programs in ./contrib/ directory #? -cli start o-saft.pl with remaining arguments; this is the default #? -cgi start o-saft.cgi with remaining arguments #? -gui start o-saft.tcl with remaining arguments # -tcl alias for -gui #? -docker start o-saft-docker with remaining arguments #? -id=* passed to o-saft-docker #? -tag=* passed to o-saft-docker #? -post="program [options]" #? program to pipe output of o-saft.pl to #? -- pass all remaining arguments to o-saft.pl or o-saft.tcl #? #? LIMITATIONS #? All option listed above must preceed options to be passed through. #? $0 must be install in the same directory as the tools it will call #? $0.pl $0.cgi $0.tcl #? #? EXAMPLES #? $0 +cmd --option target #? $0 -post='bunt.pl' ' +cmd --option target #? $0 -post='bunt.pl -blind' +cmd --option target #? $0 -gui target #? #? $0 -docker +cmd --option target #? $0 -docker -post='bunt.pl' ' +cmd --option target #? $0 -docker -post='bunt.pl -blind' +cmd --option target #? $0 -docker -gui target #? #? Specify program to execute script (if hashbang in file fails): #? $0 -docker -post='perl contrib/bunt.pl' ' +cmd --option target #? # # Hacker's INFO # Uses options -h and -post= and not --h or --help or --post to # avoid conflicts with same option for o-saft.pl . # #? VERSION #? @(#) o-saft 1.14 18/10/02 00:33:42 #? #? AUTHOR #? 17-dec-17 Achim Hoffmann #? # ----------------------------------------------------------------------------- ich=${0##*/} dir=${0%/*}; [ "$dir" = "$0" ] && dir="." # $0 found via $PATH in . prg=$dir/$ich.pl # most likely ich=o-saft .. gui=$dir/$ich.tcl cgi=$dir/$ich.cgi dok=$dir/$ich-docker # all tools are prefix with the path $dir to avoid incomplete $PATH settings contrib=$dir/contrib try= post="cat" # default, avoids special handling if -post= missing mode=cli # cli, cgi, gui docker=0 # cli or gui mode; cannot use $mode because it is needed for docker too docker_id= docker_tag= while [ $# -gt 0 ]; do case "$1" in -h | '-?') \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 \cat <. =head2 Functions defined herein =over 4 =item _yeast_init( ) =item _yeast_exit( ) =item _yeast_args( ) =item _yeast_data( ) =item _yeast_prot( ) =item _yeast_cipher( ) =item _yeast( ) =item _y_ARG( ), _y_CMD( ), _yline( ) =item _vprintme( ) =item _v_print( ), _v2print( ), _v3print( ), _v4print( ) =item _trace( ), _trace1( ), _trace2( ), _trace_cmd( ) =back =head2 Variables which may be used herein They must be defined as `our' in L: =over 4 =item $VERSION =item %data =item %cfg, i.e. trace, traceARG, traceCMD, traceKEY, time_absolut, verbose =item %checks =item %dbx =item $time0 =back Functions being used in L shoudl be defined as empty stub there. For example: sub _yeast_init() {} =head1 SPECIALS If you want to do special debugging, you can define proper functions here. They don't need to be defined in L if they are used only here. In that case simply call the function in C<_yeast_init> or C<_yeast_exit> they are called at beginning and end of L. It's just important that L was called with either the I<--v> or any I<--trace*> option, which then loads this file automatically. =cut # HACKER's INFO # Following (internal) functions from o-saft.pl are used: # _is_do() # _is_intern() # _is_member() # _need_cipher() # _get_ciphers_range() ## no critic qw(TestingAndDebugging::RequireUseStrict) # `use strict;' not usefull here, as we mainly use our global variables use warnings; my $SID_dbx= "@(#) o-saft-dbx.pm 1.67 18/11/10 16:13:44"; package main; # ensure that main:: variables are used, if not defined herein no warnings 'redefine'; ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) # must be herein, as most subroutines are already defined in main # warnings pragma is local to this file! no warnings 'once'; ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) # "... used only once: possible typo ..." appears when called as main only ## no critic qw(Subroutines::RequireArgUnpacking) # parameters are ok for trace output ## no critic qw(ValuesAndExpressions::ProhibitNoisyQuotes) # we have a lot of single character strings, herein, that's ok # debug functions sub _yTIME { if (0 >= $cfg{'traceTIME'}) { return ""; } my $now = time() - ($time0 || 0); $now = time() if (1 == $cfg{'time_absolut'});# $time0 defined in main return sprintf(" %02s:%02s:%02s", (localtime($now))[2,1,0]); } sub _yeast { local $\ = "\n"; print $cfg{'prefix_verbose'} . $_[0]; return; } sub _y_ARG { local $\ = "\n"; print $cfg{'prefix_verbose'} . " ARG: " . join(" ", @_) if (0 < $cfg{'traceARG'}); return; } sub _y_CMD { local $\ = "\n"; print $cfg{'prefix_verbose'} . _yTIME() . " CMD: " . join(" ", @_) if (0 < $cfg{'traceCMD'}); return; } sub _yTRAC { local $\ = "\n"; printf("%s%14s= %s\n", $cfg{'prefix_verbose'}, $_[0], $_[1]); return; } sub _yline { _yeast("#----------------------------------------------------" . $_[0]); return; } sub _y_ARR { return join(" ", "[", @_, "]"); } sub _yeast_trac {} # forward declaration sub _yeast_trac { #? print variable according its type, undertands: CODE, SCALAR, ARRAY, HASH my $ref = shift; # must be a hash reference my $key = shift; if (not defined $ref->{$key}) { # undef is special, avoid perl warnings _yTRAC($key, "<>"); return; } SWITCH: for (ref($ref->{$key})) { # ugly but save use of $_ here /^$/ && do { _yTRAC($key, $ref->{$key}); last SWITCH; }; ## no critic qw(RegularExpressions::ProhibitFixedStringMatches) /CODE/ && do { _yTRAC($key, "<>"); last SWITCH; }; /SCALAR/&& do { _yTRAC($key, $ref->{$key}); last SWITCH; }; /ARRAY/ && do { _yTRAC($key, _y_ARR(@{$ref->{$key}})); last SWITCH; }; /HASH/ && do { last SWITCH if (2 >= $ref->{'trace'}); # print hashes for full trace only _yeast("# - - - - HASH: $key = {"); foreach my $k (sort keys %{$ref->{$key}}) { #_yeast_trac($ref, ${$ref->{$key}}{$k}); # FIXME: _yTRAC(" ".$key."->".$k, join("-", ${$ref->{$key}}{$k})); # TODO: fast ok }; _yeast("# - - - - HASH: $key }"); last SWITCH; }; # DEFAULT _yeast(STR_WARN . " user defined type '$_' skipped"); } # SWITCH return; } # _yeast_trac sub _yeast_init { ## no critic qw(Subroutines::ProhibitExcessComplexity) #? print important content of %cfg and %cmd hashes #? more output if 1= ($cfg{'trace'} + $cfg{'verbose'})); my $arg = " (does not exist)"; if (-f $cfg{'RC-FILE'}) { $arg = " (exists)"; } _yeast("!!Hint: use --trace=2 to see Net::SSLinfo variables") if (2 > $cfg{'trace'}); _yeast("!!Hint: use --trace=2 to see external commands") if (2 > $cfg{'trace'}); _yeast("!!Hint: use --trace=3 to see full %cfg") if (3 > $cfg{'trace'}); _yeast("#") if (3 > $cfg{'trace'}); _yline(""); _yTRAC("$0", $VERSION); # $0 is same as $ARG0 _yTRAC("_yeast_init::SID", $SID_dbx) if (2 > $cfg{'trace'}); _yTRAC("::osaft", $osaft::VERSION); _yTRAC("Net::SSLhello", $Net::SSLhello::VERSION) if defined($Net::SSLhello::VERSION); _yTRAC("Net::SSLinfo", $Net::SSLinfo::VERSION); if (1 < $cfg{'trace'}) { _yline(" Net::SSLinfo {"); _yTRAC("::trace", $Net::SSLinfo::trace); _yTRAC("::linux_debug", $Net::SSLinfo::linux_debug); _yTRAC("::slowly", $Net::SSLinfo::slowly); _yTRAC("::timeout", $Net::SSLinfo::timeout); _yTRAC("::use_openssl", $Net::SSLinfo::use_openssl); _yTRAC("::use_sclient", $Net::SSLinfo::use_sclient); _yTRAC("::use_extdebug", $Net::SSLinfo::use_extdebug); _yTRAC("::use_nextprot", $Net::SSLinfo::use_nextprot); _yTRAC("::use_reconnect", $Net::SSLinfo::use_reconnect); _yTRAC("::use_SNI", $Net::SSLinfo::use_SNI); _yTRAC("::use_http", $Net::SSLinfo::use_http); _yTRAC("::no_cert", $Net::SSLinfo::no_cert); _yTRAC("::no_cert_txt", $Net::SSLinfo::no_cert_txt); _yTRAC("::protos_alpn", $Net::SSLinfo::protos_alpn); _yTRAC("::protos_npn", $Net::SSLinfo::protos_npn); _yTRAC("::sclient_opt", $Net::SSLinfo::sclient_opt); _yTRAC("::ignore_case", $Net::SSLinfo::ignore_case); _yTRAC("::timeout_sec", $Net::SSLinfo::timeout_sec); _yline(" Net::SSLinfo }"); } _yTRAC("RC-FILE", $cfg{'RC-FILE'} . $arg); _yTRAC("--rc", ((grep{/(?:--rc)$/i} @ARGV) > 0)? 1 : 0); _yTRAC("--no-rc", ((grep{/(?:--no.?rc)$/i} @ARGV) > 0)? 1 : 0); _yTRAC("verbose", $cfg{'verbose'}); _yTRAC("trace", "$cfg{'trace'}, traceARG=$cfg{'traceARG'}, traceCMD=$cfg{'traceCMD'}, traceKEY=$cfg{'traceKEY'}, traceTIME=$cfg{'traceTIME'}"); _yTRAC("time_absolut", $cfg{'time_absolut'}); # more detailed trace first if (1 < $cfg{'trace'}) { _yline(" %cmd {"); foreach my $key (sort keys %cmd) { _yeast_trac(\%cmd, $key); } _yline(" %cmd }"); _yline(" complete %cfg {"); foreach my $key (sort keys %cfg) { if ($key =~ m/(hints|openssl|ssleay)$/) { # sslerror|sslhello|data # FIXME: ugly data structures ... should be done by _yTRAC() _yeast("# - - - - HASH: $key = {"); foreach my $k (sort keys %{$cfg{$key}}) { if ($key eq "openssl") { _yTRAC($k, _y_ARR(@{$cfg{$key}{$k}})); } else { _yTRAC($k, $cfg{$key}{$k}); }; }; _yeast("# - - - - HASH: $key }"); } else { _yeast_trac(\%cfg, $key); } } _yline(" %cfg }"); } # now user friendly informations my $sni_name = $cfg{'sni_name'} || "<>"; # default is Perl's undef _yline(" cmd {"); _yeast("# " . join(", ", @{$dbx{'file'}})); _yeast(" path= " . _y_ARR(@{$cmd{'path'}})); _yeast(" libs= " . _y_ARR(@{$cmd{'libs'}})); _yeast(" envlibvar= $cmd{'envlibvar'}"); _yeast(" cmd->timeout= $cmd{'timeout'}"); _yeast(" cmd->openssl= $cmd{'openssl'}"); _yeast(" use_openssl= $cmd{'extopenssl'}"); _yeast("use cipher from openssl= $cmd{'extciphers'}"); _yline(" cmd }"); _yline(" user-friendly cfg {"); _yeast(" ca_depth= $cfg{'ca_depth'}") if defined $cfg{'ca_depth'}; _yeast(" ca_path= $cfg{'ca_path'}") if defined $cfg{'ca_path'}; _yeast(" ca_file= $cfg{'ca_file'}") if defined $cfg{'ca_file'}; _yeast(" use_SNI= $Net::SSLinfo::use_SNI, force-sni=$cfg{'forcesni'}, sni_name=$sni_name"); _yeast(" default port= $cfg{'port'} (last specified)"); if (0 == $cfg{'trace'}) { # simple list printf("%s%14s= [ ", $cfg{'prefix_verbose'}, "targets"); foreach my $target (@{$cfg{'targets'}}) { next if (0 == @{$target}[0]); # first entry conatins default settings printf("%s:%s ", @{$target}[2..3]); # the perlish way } printf("]\n"); } else { # complete array printf("%s%14s targets = [\n", $cfg{'prefix_verbose'}, "# - - - -ARRAY"); printf("%s# Index %6s %16s : %5s %10s %5s %10s %s\n", $cfg{'prefix_verbose'}, "Prot.", "Hostname or IP", "Port", "Auth", "Proxy", "Path", "Orig. Parameter"); foreach my $target (@{$cfg{'targets'}}) { next if (0 == @{$target}[0]); # first entry conatins default settings printf("%s [%3s] %6s %16s : %5s %10s %5s %10s %s\n", $cfg{'prefix_verbose'}, @{$target}[0,1..7]); } printf("%s%14s ]\n", $cfg{'prefix_verbose'}, "# - - - -ARRAY"); } foreach my $key (qw(out_header format legacy showhost usehttp usedns usemx starttls starttls_delay slow_server_delay cipherrange)) { printf("%s%14s= %s\n", $cfg{'prefix_verbose'}, $key, $cfg{$key}); # cannot use _yeast() 'cause of pretty printing } foreach my $key (qw(starttls_phase starttls_error)) { _yeast( "$key= " . _y_ARR(@{$cfg{$key}})); } _yeast(" SSL version= " . _y_ARR(@{$cfg{'version'}})); printf("%s%14s= %s", $cfg{'prefix_verbose'}, "SSL versions", "[ "); printf("%s=%s ", $_, $cfg{$_}) foreach (@{$cfg{'versions'}}); ## no critic qw(ControlStructures::ProhibitPostfixControls) printf("]\n"); _yeast(" special SSLv2= null-sslv2=$cfg{'nullssl2'}, ssl-lazy=$cfg{'ssl_lazy'}"); _yeast(" ignore output= " . _y_ARR(@{$cfg{'ignore-out'}})); _yeast(" user commands= " . _y_ARR(@{$cfg{'commands-USR'}})); _yeast("given commands= " . _y_ARR(@{$cfg{'done'}->{'arg_cmds'}})); _yeast(" commands= " . _y_ARR(@{$cfg{'do'}})); _yline(" user-friendly cfg }"); _yeast("(more information with: --trace=2 or --trace=3 )") if (1 > $cfg{'trace'}); # $cfg{'ciphers'} may not yet set, print with _yeast_ciphers() return; } # _yeast_init sub _yeast_ciphers { #? print ciphers fromc %cfg (output optimized for +cipher and +cipherraw) return if (0 >= ($cfg{'trace'} + $cfg{'verbose'})); _yline(" ciphers {"); my $_cnt = scalar @{$cfg{'ciphers'}}; my $need = _need_cipher(); my $ciphers = "@{$cfg{'ciphers'}}"; if (_is_do('cipherraw')) { $need = 1; my @range = $cfg{'cipherranges'}->{$cfg{'cipherrange'}}; if ($cfg{'cipherrange'} =~ m/(full|huge|safe)/i) { # avoid huge (useless output) $_cnt = 0xffffff; $_cnt = 0x2fffff if ($cfg{'cipherrange'} =~ m/safe/i); $_cnt = 0xffff if ($cfg{'cipherrange'} =~ m/huge/i); } else { # expand list @range = _get_ciphers_range(${$cfg{'version'}}[0], $cfg{'cipherrange'}); # FIXME: _get_ciphers_range() first arg is the SSL version, which is # usually unknown here, hence the first is passed # this my result in a wrong list; but its trace output only $_cnt = scalar @range; } $ciphers = "@range"; } _yeast(" _need_cipher= $need"); if (0 < $need) { $_cnt = sprintf("%5s", $_cnt); # format count _yeast(" starttls= " . $cfg{'starttls'}); if (_is_do('cipherraw')) { _yeast(" cipherrange= " . $cfg{'cipherrange'}); } else { _yeast(" cipherpattern= " . $cfg{'cipherpattern'}); _yeast("use cipher from openssl= " . $cmd{'extciphers'}); } _yeast(" $_cnt ciphers= $ciphers"); } _yline(" ciphers }"); return; } # _yeast_ciphers sub _yeast_exit { if (0 < $cfg{'trace'}) { _yTRAC("cfg'exitcode'", $cfg{'exitcode'}); _yTRAC("exit status", (($cfg{'exitcode'}==0) ? 0 : $checks{'cnt_checks_no'}->{val})); } _y_CMD("internal administration .."); _y_CMD("cfg'done'{"); foreach my $key (sort keys %{$cfg{'done'}}) { # cannot use _yeast_trac(\%{$cfg{'done'}}, $key); # because we want the CMD prefix here if ($key eq 'arg_cmds') { _y_CMD(" $key : [" . join(" ", @{$cfg{'done'}->{$key}}) . "]"); } else { _y_CMD(" $key : " . $cfg{'done'}->{$key}); } } _y_CMD("cfg'done'}"); return; } # _yeast_exit sub _yeast_args { return if (0 >= $cfg{'traceARG'}); # using _y_ARG() may be a performance penulty, but it's trace anyway ... _yline(" ARGV {"); _y_ARG("# summary of all arguments and options from command line"); _y_ARG(" called program ARG0= " . $cfg{'ARG0'}); _y_ARG(" passed arguments ARGV= " . _y_ARR(@{$cfg{'ARGV'}})); _y_ARG(" RC-FILE= " . $cfg{'RC-FILE'}); _y_ARG(" from RC-FILE RC-ARGV= ($#{$cfg{'RC-ARGV'}} more args ...)"); if (0 >= $cfg{'verbose'}) { _y_ARG(" !!Hint: use --v to get the list of all RC-ARGV"); _y_ARG(" !!Hint: use --v --v to see the processed RC-ARGV"); # NOTE: ($cfg{'trace'} does not work here } _y_ARG(" from RC-FILE RC-ARGV= " . _y_ARR(@{$cfg{'RC-ARGV'}})) if (0 < $cfg{'verbose'}); my $txt = "[ "; foreach my $target (@{$cfg{'targets'}}) { next if (0 == @{$target}[0]); # first entry conatins default settings $txt .= sprintf("%s:%s ", @{$target}[2..3]); # the perlish way } $txt .= "]"; _y_ARG(" collected targets= " . $txt); if (1 < $cfg{'verbose'}) { _y_ARG(" #--v { processed files, arguments and options"); _y_ARG(" read files and modules= ". _y_ARR(@{$dbx{file}})); _y_ARG("processed exec arguments= ". _y_ARR(@{$dbx{exe}})); _y_ARG("processed normal arguments= ". _y_ARR(@{$dbx{argv}})); _y_ARG("processed config arguments= ". _y_ARR(map{"`".$_."'"} @{$dbx{cfg}})); _y_ARG(" #--v }"); } _yline(" ARGV }"); return; } # _yeast_args sub _v_print { local $\ = "\n"; print $cfg{'prefix_verbose'} . join(" ", @_) if (0 < $cfg{'verbose'}); return; } sub _v2print { local $\ = "\n"; print $cfg{'prefix_verbose'} . join(" ", @_) if (1 < $cfg{'verbose'}); return; } sub _v3print { local $\ = "\n"; print $cfg{'prefix_verbose'} . join(" ", @_) if (2 < $cfg{'verbose'}); return; } sub _v4print { local $\ = ""; print $cfg{'prefix_verbose'} . join(" ", @_) if (3 < $cfg{'verbose'}); return; } sub _trace { print $cfg{'prefix_trace'} . $_[0] if (0 < $cfg{'trace'}); return; } sub _trace0 { print $cfg{'prefix_trace'} if (0 < $cfg{'trace'}); return; } sub _trace1 { print $cfg{'prefix_trace'} . join(" ", @_) if (1 < $cfg{'trace'}); return; } sub _trace2 { print $cfg{'prefix_trace'} . join(" ", @_) if (2 < $cfg{'trace'}); return; } sub _trace3 { print $cfg{'prefix_trace'} . join(" ", @_) if (3 < $cfg{'trace'}); return; } sub _trace_ { local $\ = ""; print " " . join(" ", @_) if (0 < $cfg{'trace'}); return; } # if --trace-arg given sub _trace_cmd { printf("%s %s->\n", $cfg{'prefix_trace'}, join(" ",@_))if (0 < $cfg{'traceCMD'}); return; } sub _vprintme { my ($s,$m,$h,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(); return if (0 >= ($cfg{'verbose'} + $cfg{'trace'})); _yeast("$0 " . $VERSION); _yeast("$0 " . join(" ", @{$cfg{'ARGV'}})); _yeast("$0 " . sprintf("%02s.%02s.%s %02s:%02s:%02s", $mday, ($mon +1), ($year +1900), $h, $m, $s)); return; } # _vprintme sub __data { return (_is_member(shift, \@{$cfg{'commands'}}) > 0) ? "*" : "?"; } sub _yeast_data { print " === _yeast_data: check internal data structure === This function prints a simple overview of all available commands and checks. The purpose is to show if a proper key is defined in %data and %checks for each command from %cfg{'commands'} and vice versa. "; my $old; my @yeast = (); # list of potential internal, private commands my $cmd = " "; printf("%20s %s %s %s %s %s %s %s\n", "key", "command", "intern ", " data ", "short ", "checks ", "cmd-ch.", " score"); printf("%20s+%s+%s+%s+%s+%s+%s+%s\n", "-"x20, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7); $old = ""; foreach my $key (sort {uc($a) cmp uc($b)} @{$cfg{'commands'}}, keys %data, keys %shorttexts, keys %checks ) # we use sort case-insensitively, hence the BLOCK for comparsion # it also avoids the warning: sort (...) interpreted as function { next if ($key eq $old); # unique $old = $key; if ((not defined $checks{$key}) and (not defined $data{$key})) { push(@yeast, $key); # probaly internal command next; } $cmd = "+" if (0 < _is_member($key, \@{$cfg{'commands'}})); # command available as is $cmd = "-" if ($key =~ /$cfg{'regex'}->{'SSLprot'}/); # all SSL/TLS commands ar for checks only printf("%20s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", $key, $cmd, (_is_intern($key) > 0) ? "I" : " ", (defined $data{$key}) ? __data( $key) : " ", (defined $shorttexts{$key}) ? "*" : " ", (defined $checks{$key}) ? "*" : " ", ((_is_member($key, \@{$dbx{'cmd-check'}}) > 0) || ($key =~ /$cfg{'regex'}->{'SSLprot'}/)) ? "*" : "!", (defined $checks{$key}->{score}) ? $checks{$key}->{score} : ".", ); } # FIXME: FIXME: @{$dbx{'cmd-check'}} is incomplete when o-saft-dbx.pm is # `require'd in main; some checks above fail (mainly those # those matching $cfg{'regex'}->{'SSLprot'}, hence the dirty # additional || ($key =~ /$cfg{'regex'}->{'SSLprot'}/) # printf("%20s+%s+%s+%s+%s+%s+%s+%s\n", "-"x20, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7); printf("%20s %s %s %s %s %s %s %s\n", "key", "command", "intern ", " data ", "short ", "checks ", "cmd-ch.", " score"); print ' + command (key) present I command is an internal command or alias - command (key) used internal for checks only * key present key not present ? key in %data present but missing in $cfg{commands} ! key in %cfg{cmd-check} present but missing in redefined %cfg{cmd-check} . no score defined in %checks{key} A shorttext should be available for each command and all data keys, except: cn_nosni, ext_*, valid_* Please check following keys, they skipped in table above due to '; print " internal or summary commands:\n " . join(" ", @yeast); print "\n"; return; } # _yeast_data sub _yeast_prot { #? print information about SSL/TLS protocols in various variables (hashes) #? this function is for internal use only local $\ = "\n"; my $ssl = $cfg{'regex'}->{'SSLprot'}; print "=== _yeast_prot: internal data according protocols ===\n"; _yline(" %cfg {"); foreach my $key (sort keys %cfg) { #printf("%16s= %s\n", $key, $cfg{$key}) if ($key =~ m/$ssl/); _yeast_trac(\%cfg, $key) if ($key =~ m/$ssl/); } _yline(" }"); _yline(" %cfg{openssl_option_map} {"); foreach my $key (sort keys %{$cfg{'openssl_option_map'}}) { _yeast_trac(\%{$cfg{'openssl_option_map'}}, $key); } _yline(" }"); _yline(" %cfg{openssl_version_map} {"); foreach my $key (sort keys %{$cfg{'openssl_version_map'}}) { _yeast(sprintf("%14s= ", $key) . sprintf("0x%04x (%d)", ${$cfg{'openssl_version_map'}}{$key}, ${$cfg{'openssl_version_map'}}{$key})); } _yline(" }"); # %check_conn and %check_dest are temporary and should be inside %checks _yline(" %checks {"); foreach my $key (sort keys %checks) { # $checks{$key}->{val} undefined at beginning _yeast(sprintf("%14s= ", $key) . $checks{$key}->{txt}) if ($key =~ m/$ssl/); } _yline(" }"); _yline(" %shorttexts {"); foreach my $key (sort keys %shorttexts) { _yeast(sprintf("%14s= ",$key) . $shorttexts{$key}) if ($key =~ m/$ssl/); } _yline(" }"); if (0 < ($cfg{'trace'} + $cfg{'verbose'})){ } return; } # _yeast_prot sub _yeast_cipher { # TODO: %ciphers %cipher_names } sub o_saft_dbx_done {}; # dummy to check successful include ## PACKAGE } unless (defined caller) { if (eval {require POD::Perldoc;}) { # pod2usage( -verbose => 1 ) exit( Pod::Perldoc->run(args=>[$0]) ); } if (qx(perldoc -V)) { # may return: You need to install the perl-doc package to use this program. #exec "perldoc $0"; # scary ... print "# try:\n perldoc $0\n"; } } 1; O-Saft-19.01.19/o-saft-docker000077500000000000000000000562721342117255600154530ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - wrapper script to handle O-Saft in a Docker image #? #? SYNOPSIS #? $0 #? $0 build #? $0 usage #? $0 shell #? $0 root #? $0 status #? $0 inspect #? $0 rmi #? $0 apk package #? $0 apt package #? $0 gui #? $0 sshx #? $0 call /path/to/program [arguments] #? $0 cp file-to-be-copied #? $0 [options and commands of o-saft.pl] #? #? OPTIONS #? -help got it #? -n do not execute, just show what would be done #? -v be a bit verbose #? -id=ID use Docker image ID (registry:tag); default: owasp/o-saft #? -tag=23 use Docker image ID with tag; default: (empty) #? -OSAFT_VERSION=21.11.12 same as OSAFT_VERSION environment variable #? -- pass all remaining parameters to o-saft.pl in Docker image #? #? QUICKSTART #? The main purpose of this wrapper is to provide a very simple call of #? o-saft.pl in a running O-Saft Docker image. It is the default mode. #? Example: #? $0 +info your.tld #? #? DESCRIPTION #? This is a multipurpose wrapper to handle O-Saft in a Docker image. #? It can operate in following modes: #? build - build the Docker image for O-Saft from Dockerfile #? usage - print the initial usage message for O-Saft in Docker #? status - show various information about O-Saft Docker image #? rmi - remove O-Saft Docker image(s) #? apk - add and commit packages in O-Saft Docker image #? shell - run a shell (/bin/sh) in Docker image #? root - run a shell (/bin/sh) as user root in Docker image #? call - run specified program with arguments in Docker image #? cp - copy file to /O-Saft directory in the Docker image # hacker - show more information #? gui - start o-saft.tcl in the Docker image (display to host) #? sshx - start o-saft.tcl in the Docker image (tunnel X via ssh) #? * - anything else (default): run o-saft.pl in Docker image #? #? This wrapper expects, that the O-Saft Docker image has the name: #? owasp/o-saft #? If there are more Docker images with the same (registry) name, a tag #? can be used to identify the image, see -tag=TAG option, i.e. #? $0 -tag=17.07.17 +info your.tld #? will use the name: owasp/o-saft:17.07.17 . The -id=ID option can #? be used to redefine the (registry:tag) name to be used completely. #? For example: #? owasp/o-saft:4711 #? #? If any other mode than the default is used, please see WARNING and #? SECURITY below. #? #? TERMINOLOGY #? #? Docker vs. docker #? The term "Docker" is used when the Docker system in general is meant. #? The term "docker" is used when the Docker client program is meant. #? #? mode vs. command #? The term "mode" is used for our script, which is similar to the term #? "command" of Docker. This is to distinguish the commands herein from #? those of Docker. #? #? "o-saft.pl in Docker image" #? Means that the program defined by O-Saft Docker's ENTRYPOINT will be #? executed. This can be o-saft.pl or o-saft . #? #? MODES #? Modes are simply an alias to call docker with the proper commands #? and options for the O-Saft Docker image. Most modes use the command #? "docker run --rm ...". #? This wrapper ensures that the proper O-Saft image within Docker will #? be used by passing the correct "repository:tag" image id (default: #? owasp/o-saft). This script will exit, if the image owasp/o-saft does #? exist (to avoid automatic pull from Docker's repository). #? #? The modes are: #? #? default #? In default mode, all parameters given to this wrapper are passed to #? o-saft.pl in the Docker image. This means that for all the existing #? calls, the name of the script (usually o-saft.pl) needs simply to be #? replaced by $0 . Example: #? o-saft.pl +info your.tld #? becomes #? $0 +info your.tld #? Please see LIMITATIONS below also. #? #? gui #? Start o-saft.tcl in the Docker image with display to the host where #? started. #? #? sshx #? Start o-saft.tcl in the Docker image using ssh to tunnel X to the #? hosts display. #? #? build #? This mode builds the Docker image for O-Saft from the Dockerfile. If #? ./Dockerfile is missing following will be used: #? https://github.com/OWASP/O-Saft/raw/master/Dockerfile #? See ENVIONMENT VARIABLES below for supported environment variables. #? #? apk #? apt #? Add and commit the specified packages in O-Saft Docker image. #? Note that this creates a new layer for the O-Saft Docker image. #? For more advanced mode, please refer to o-saft-docker-dev. #? Uses apk or apt to add/install the package, depending on the mode. #? #? rmi #? Remove all O-Saft images, including tagged images. #? #? usage #? Print a brief purpose and usage of this script. #? It is intended to be called from within the Docker image once, right #? after the initial build (see Dockerfile). #? #? shell #? Start a shell in O-Saft Docker image. #? This is useful because the ENTRYPOINT in the image is o-saft or #? o-saft.pl , which otherwise will always be executed. #? #? root #? Same as mode shell, but login as user root. #? #? cp #? Copy file to /O-Saft directory in the Docker image. #? #? call #? Execute specified program with given arguments. The program must be #? found using $PATH or a full path. #? This might be usefull to retrieve other information from the image, #? i.e. O-Saft itself uses it to get the environment variables set in #? the image: #? $0 call /usr/bin/env #? #? inspect #? Print information about O-Saft Docker image using inspect command. #? #? status #? Show various information about O-Saft Docker image. #? #? WARNING #? It is highly recommended to *not* use the created image as base for #? other Docker images. Also, do *not* use openssl from the image for #? other purpose than O-Saft intends. #? #? SECURITY #? When working with Docker images, at least two types of security have #? to be observed. #? #? It is rather difficult to create a secure Docker image, at least the #? pulled files (Dockerfile, image, other sources) must be trusted. #? #? The known security types are: #? #? Security of the created images #? When creating Docker images, wether using build, load or pull, you #? must trust the sources: the binary (load or pull) or the Dockerfile #? (which may be fetched at runtime too) used to build the image. #? #? Update June/2018: Crypto-Miner in Docker images detected: #? https://www.fortinet.com/blog/threat-research/yet-another-crypto-mining-botnet.html #? https://kromtech.com/blog/security-center/cryptojacking-invades-cloud-how-modern-containerization-trend-is-exploited-by-attackers #? https://sysdig.com/blog/detecting-cryptojacking/ #? That's why we prefer a transparent build of the Docker image. We re- #? comment to build the Docker image for O-Saft using the Dockerfile. #? #? Security of the tools executed from within the image (docker run) #? If the image is trustworthy (see before), the tools executed in the #? image may have security impacts. #? This script creates a Docker image for O-Saft. O-Saft is supposed to #? checks a target for SSL/TLS related issues. I. g. it doesn not harm #? the target using penetration or attacking techniques (except check #? for Heartbleed vulnerability). So o-saft.pl itself should not be any #? security issue. However, to perform the checks, O-Saft recommends to #? install a special version of OpenSSL. This OpenSSL has functionality #? enabled, which is known to be insecure (i. e. SSLv2, SSLv3). #? #? That's why this script uses a transparent method to create an image. #? #? HACKER's INFO #? Options for this script are with a single - (dash) only, because the #? same options with double -- exist for o-saft.pl. See LIMITATIONS #? below also. # # We do not use shortcut commands for docker like run, rmi, save, etc. # because they are depricated according docker documentation. # # Keep in mind that docker is picky about the sequence of commands and # options. In particular all options must preced the IMAGE argument. # # "docker commit ..." is used without the --message option because the # documentation about --message and/or -m is ambigious. Also passed # comment text is mainly the same as Docker already reports with the # "docker history IMAGE" command in the "CREATED BY" column. # # KNOWN PROBLEMS # * Error when building docker image # fetch http://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz # WARNING: Ignoring http://dl-cdn.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz: temporary error (try again later) # fetch http://dl-cdn.alpinelinux.org/alpine/edge/community/x86_64/APKINDEX.tar.gz # WARNING: Ignoring http://dl-cdn.alpinelinux.org/alpine/edge/community/x86_64/APKINDEX.tar.gz: temporary error (try again later) # ERROR: unsatisfiable constraints: # # Reason: backend mirror dl-cdn.alpinelinux.org down or not responding # Most likely an update of the host's docker package will fix it. #? #? LIMITATIONS #? The options -n -v -id=ID and -help must be specified leftmost #? if they should apply for this script. #? These options can only be passed to o-saft.pl in the Docker image, #? if they are preceeded by the -- parameter. #? Unknown parameters to this script will be treated as arguments to be #? passed to o-saft.pl and will terminate internal argument scanning in #? this script. #? The script calls the program defined by the ENTRYPOINT in the Docker #? image (which is most likely o-saft). #? This script is not intended to call o-saft.cgi in the Docker image. #? However, it is possible to do so: #? $0 call o-saft.cgi --cgi [options and commands of o-saft.pl] #? #? ENVIONMENT VARIABLES #? Following environment variables can be used to pass settings to the #? script: #? #? OSAFT_VERSION - version to be passed to Dockerfile #? OSAFT_VM_SRC_OSAFT - URL to o-saft.tgz #? OSAFT_VM_SRC_SSLEAY - URL to Net-SSLeay.tgz #? OSAFT_VM_SRC_SOCKET - URL to IO-Socket.tgz #? OSAFT_VM_SRC_OPENSSL - URL to openssl.tgz #? OSAFT_VM_SHA_OSAFT - checksum of o-saft.tgz #? o_saft_docker_name - contains an image registry name #? o_saft_docker_tag - contains an image tag #? #? To get the build-in defaults use: #? $0 status #? #? EXAMPLES #? See SYNOPSIS. #? #? SEE ALSO #? docker(1), o-saft-docker-dev, o-saft.pl, o-saft.tcl #? #? VERSION #? @(#) o-saft-docker 1.41 18/11/09 01:14:13 #? #? AUTHOR #? 17-jul-17 Achim Hoffmann #? # ----------------------------------------------------------------------------- VERSION="${OSAFT_VERSION:-18.11.18}" tag=${o_saft_docker_tag}; # tag=${tag:-17.09.17} registry=${o_saft_docker_name}; registry=${registry:-owasp/o-saft} image_name="${registry}" entrypoint_pl='ENTRYPOINT ["perl", "/O-Saft/o-saft.pl"]'; # default ENTRYPOINT entrypoint_sh='ENTRYPOINT ["/O-Saft/o-saft"]'; # default ENTRYPOINT entry__cmd='CMD ["--norc", "--help=docker"]': # default CMD [ -n "$tag" ] && image_name="${registry}:${tag}" try= exe=o-saft.pl dockerfile="https://github.com/OWASP/O-Saft/raw/master/Dockerfile" check_image_name () { #? check if image with configured registry:tag exists; exit otherwise # This function should be called before most docker commands. # This tool does not allow automatic pull by default. # Most (all?) Docker commands automatically try to pull the specified # image if it does not exist. More worse, while some Docker commands # use any matching registry name (run without --entrypoint=), others # require that the registry:tag name exists (run with --entrypoint=). # Unfortunately Docker does not provide any option or configuration # to inhibit such automatic pulls. # This function tries to find existing images matching the configured # image (name). The function exits the script if the found image name # does not equal the configured image name. # Lists all images matching the required one. As "docker image ls -q" # reports the image IDs only, duplicate image IDs may be returned. # Images which are just tags, return the same image ID. Hence we can # simply filter them using "sort -u". #dbx# \docker image ls ${image_name} -q | \sort -u | \wc -w is_id=`\docker image ls ${image_name} -q | \sort -u | \wc -w` [ "${is_id}" -eq 1 ] && return; # found image, return [ "${is_id}" -ne 1 ] && \ echo "**ERROR: given image '${image_name}' does not match found image(s)" # '${is_id}'" if [ "${is_id}" -gt 1 ]; then for tag in `\docker image ls ${image_name} | \awk '/^REPOSITORY/{next}{print $2}'` ; do # varaiable tag is the same as the global one! echo "# consider using option -id=${image_name}:$tag or -tag=$tag" done fi exit 3; # no image found, exit script } docker_usage () { _me=${0##*/} # TODO: env|grep osaft_vm_build _openssl="/openssl/bin/openssl"; # TODO: still hardcoded for docker if [ -n "$osaft_vm_build" ]; then _openssl="openssl" # we're inside docker _me=${0##*/} else _openssl="$0 call $_openssl" # we're outside docker _me=$0 fi _ciphers=`$_openssl ciphers -V ALL:COMPLEMENTOFALL:aNULL | \wc -l` cat << EoDescription # openssl: $_openssl supports $_ciphers ciphers # o-saft.pl: O-Saft docker image is ready to run o-saft.pl, use: docker run --rm -it ${image_name} +info your.tld or: $me +info your.tld or: o-saft -docker +info your.tld # o-saft.tcl: The GUI o-saft.tcl will only work inside Docker if the packages tcl tk and xvfb are installed. However o-saft.tcl may be started on the host and then use o-saft.pl from the Docker image. # run on host: o-saft.tcl --docker # run in Docker image $0 apk tcl tk xvfb $0 gui $0 gui your.tld EoDescription } # TODO: alpine:3.8 misses 'tablelist' there seems to be no package 'tklib' docker_hacker () { cat << EoHacker To use the GUI o-saft.tcl inside Docker, additionl packages need to be installed. For Docker image based on alpine, following works: $0 apk add tcl tk xvfb EoHacker } docker_inspect () { $try \docker image inspect ${image_name} } docker_status () { image_id=`\docker image ls -q ${image_name}` cat << EoStatus # using environment ... # OSAFT_VERSION = $OSAFT_VERSION # o_saft_docker_name = $o_saft_docker_name # o_saft_docker_tag = $o_saft_docker_tag # using ... # registry name = ${registry} # tag = ${tag} #? registry:tag = ${image_name} # docker image id for ${image_name} is $image_id # docker images for ${registry} ... EoStatus # list matching images $try \docker image ls ${registry}; # will be listed below again # list related (tagged) images for _id in `\docker image ls -q ${registry}` ; do $try \docker image ls | \grep "$_id" done; echo echo "# docker processes ..." $try \docker container ls -a echo "" echo "# O-Saft docker image ..." _id=`$0 call env | grep osaft_vm_build` if [ -n "$_id" ]; then echo "$_id" else echo "<>" fi } docker_build () { # build O-Saft Docker image from Dockerfile, mainly using defaults # from Dockerfile; cleanup the containers _arg1= _arg2= _arg3= _arg4= _arg5= _tar=./o-saft_docker.tar _cfg=./Dockerfile [ ! -e $_cfg ] && $try \wget ${dockerfile} -O $_cfg # pass environment variables (known by Dockerfile) to docker build [ -z "$OSAFT_VERSION" ] && OSAFT_VERSION="$VERSION" # use hardcoded VERSION if environment missing [ -n "$OSAFT_VERSION" ] && _arg0="--build-arg OSAFT_VERSION=$OSAFT_VERSION" [ -n "$OSAFT_VM_SRC_OSAFT" ] && _arg1="--build-arg OSAFT_VM_SRC_OSAFT=$OSAFT_VM_SRC_OSAFT" [ -n "$OSAFT_VM_SRC_SSLEAY" ] && _arg2="--build-arg OSAFT_VM_SRC_SSLEAY=$OSAFT_VM_SRC_SSLEAY" [ -n "$OSAFT_VM_SRC_SOCKET" ] && _arg3="--build-arg OSAFT_VM_SRC_SOCKET=$OSAFT_VM_SRC_SOCKET" [ -n "$OSAFT_VM_SRC_OPENSSL" ] && _arg4="--build-arg OSAFT_VM_SRC_OPENSSL=$OSAFT_VM_SRC_OPENSSL" [ -n "$OSAFT_VM_SHA_OSAFT" ] && _arg5="--build-arg OSAFT_VM_SHA_OSAFT=$OSAFT_VM_SHA_OSAFT" # TODO: do we need more of these variables? $try \docker image build -f ./Dockerfile --force-rm --rm -t ${image_name} \ $_arg0 $_arg1 $_arg2 $_arg3 $_arg4 $_arg5 . && \ $try \docker image save -o $_tar ${image_name} && \ $try \docker image rm `$try docker image ls -q ${image_name}` && \ $try \docker image load -i $_tar && \ $try \rm $_tar && \ $try \docker image tag ${image_name} o-saft && \ $try \docker image tag ${image_name} ${image_name}:$OSAFT_VERSION } docker_osaft () { # this is the command for the default mode, passing all parameters # expects a proper ENTRYPOINT like /O-Saft/o-saft.pl in the image $try \docker container run --rm -i ${image_name} $@ } docker_gui () { # start GUI in docker with display to host # --entrypoint= not really necessary if ENTRYPOINT=/O-Saft/o-saft $try \docker container run --rm -i --entrypoint=/O-Saft/o-saft.tcl \ -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix ${image_name} $@ } docker_sshx () { _ssh=`\docker port ${image_name} 22` if [ -z "${_ssh}" ]; then echo "**ERROR: no ssh port available for '${image_name}'" else # use "ip addr" to get docker's ip, should return something like: # 6: docker0 inet 172.17.0.1/16 brd 172.17.255.255 scope global ... # TODO: returns IP of last interface if more than on exists _ip=`\ip -4 -o addr | \awk '($2~/docker/){sub("/..","",$4);print $4}'` $try \ssh user@${_id} -p ${_ssh} /O-Saft/o-saft.tcl fi } docker_call () { cmd="$1" shift $try \docker container run --rm -it --entrypoint=$cmd ${image_name} $@ } docker_shell () { $try \docker container run --rm -it --entrypoint=/bin/sh ${image_name} } docker_root () { $try \docker container run --rm -it --entrypoint=/bin/sh --user root ${image_name} } docker_cp () { _id="o-saft-cp" # create a new container with a dummy command; exit if exists or fails $try \docker container run --name ${_id} ${image_name} +VERSION || exit 4 $try \docker container cp $@ ${_id}:/O-Saft/ $try \docker container commit ${_id} ${image_name} $try \docker container rm ${_id} # # if we need to reset the entrypoint: # $try \docker container commit \ # --change='ENTRYPOINT ["perl","/O-Saft/o-saft.pl"]' \ # or: # $try \docker container commit \ # --change='ENTRYPOINT ["/O-Saft/o-saft"]' \ # } docker_apk () { _id="o-saft-apk" # after commit the entrypoint is changed, hence the original one is # set again with commit's --change option; unfortunately hardcoded $try \docker container run -t --user root --entrypoint=/sbin/apk \ --name ${_id} ${image_name} add --no-cache $@ \ || exit 4 $try \docker container commit \ --change="${entrypoint_sh}" --change="${entry__cmd}" \ ${_id} ${image_name} $try \docker container rm ${_id} return # TODO: following more cleaner method does not work (reason yet unknown) $try \docker container run -d --name ${_id} ${image_name} +VERSION || exit 4 $try \docker container exec -t --user root ${_id} /sbin/apk add --no-cache $@ $try \docker container commit ${_id} ${image_name} $try \docker container rm ${_id} } docker_apt () { _id="o-saft-apt" $try \docker container run -t --user root --entrypoint=/usr/bin/apk \ --name ${_id} ${image_name} install --no-cache $@ \ || exit 4 $try \docker container commit \ --change="${entrypoint_sh}" --change="${entry__cmd}" \ ${_id} ${image_name} $try \docker container rm ${_id} } docker_rmi () { # parameters can only be the options for Docker's rmi command #dbx# echo "# registry: ${registry} # image_name: ${image_name}" _ids=`\docker image ls -q ${registry}` # ${image_name} echo "# image IDs to be deleted: $_ids " # need to find all images, including referenced images, this is done # with "images" command, then extract all lines with matching IDs, # only these IDs are deleted # Note: "docker images" should return newest image on top, hence all # images which just represent a tag (alias) come first and will # be deleted first \docker image ls | while read _any ; do for _id in $_ids ; do _img=`echo "$_any" | \awk "/$_id/"'{print $3}'` #dbx# echo "# ID $_any : $_id : $_img" [ -z "$_img" ] && continue # other image $try \docker image rm -f $@ $_img done done $try \docker image rm ${registry} } my_help () { ich=${0##*/} \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 } # first check for options while [ $# -gt 0 ]; do case "$1" in '-n') try=echo; ;; '-v') set -x ; ;; -tag=*) tag="`expr "$1" ':' '-tag=\(.*\)'`" image_name="${registry}:$tag" ;; -id=*) image_name="`expr "$1" ':' '-id=\(.*\)'`"; ;; -OSAFT_VERSION=*) OSAFT_VERSION="`expr "$1" ':' '-OSAFT_VERSION=\(.*\)'`"; ;; '-help') my_help; exit 0; ;; *) break; ;; esac shift done # don't run inside docker case "$1" in 'hacker') ;; 'usage') ;; *) if [ -n "$osaft_vm_build" ]; then echo "**ERROR: cannot run inside docker image; exit" exit 1 fi ;; esac # some modes do not need to check existing images case "$1" in 'build') ;; 'usage') ;; 'hacker') ;; *) check_image_name; # may exit, see description there esac # NOTE: All functions may use ${registry} and ${image_name}, which are global # variables. We do not pass these values as parameters to the functions # because we want $@ (all parameters of this script) in the functions while [ $# -gt 0 ]; do mode="$1" shift case "$mode" in 'build') docker_build; exit 0; ;; 'usage') docker_usage; exit 0; ;; 'call') docker_call $@; exit 0; ;; 'sshx') docker_sshx $@; exit 0; ;; 'gui') docker_gui $@; exit 0; ;; 'cp') docker_cp $@; exit 0; ;; 'apk') docker_apk $@; exit 0; ;; 'rmi') docker_rmi $@; exit 0; ;; 'root') docker_root; exit 0; ;; 'shell') docker_shell; exit 0; ;; 'inspect')docker_inspect; exit 0; ;; 'status') docker_status; exit 0; ;; 'hacker') docker_hacker; exit 0; ;; # -registry=*) registry= # not supported, as this is for O-Saft only '--') shift; break; ;; *) break; ;; esac done set -- "$mode" $@ ; # 1st argument has no special meaning, pass to o-saft.pl if [ $# -lt 1 ]; then # did not get any argument, print own usage my_help echo echo "**WARNING: $0 called without parameters; nothing done." echo exit 2 fi docker_osaft $@ exit O-Saft-19.01.19/o-saft-docker-dev000077500000000000000000000556561342117255600162340ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - wrapper script to build O-Saft in a Docker image #? #? SYNOPSIS #? $0 build [build options] #? $0 load [load options] #? $0 pull [pull options] # ? $0 config #? #? OPTIONS #? -help got it #? -n do not execute, just show what would be done #? -v be a bit verbose #? -- pass all remaining parameters to docker #? #? To create a Docker image, following additional options can be used: #? --force-rm pass --force-rm option to "docker build" #? --rm pass --rm option to "docker build" #? -del delete saved image file after "docker load" #? -clean shortcut for: --no-force-rm --no-rm -no-del #? -save save and then load created image (removes layers) #? -tag create addition tag for image (alias) o-saft #? --no-force-rm do not pass --force-rm option to "docker build" #? --no-rm do not pass --rm option to "docker build" #? -no-del do not delete saved image file after "docker load" #? -no-clean shortcut for: --force-rm --rm -del #? -no-save do not save and then load created image #? -no-tag do notcreate addition tag for image #? -alpine build image based on alpine #? -debian build image based on debian #? -from=BASE build image based on BASE (value used for FROM key) #? -author set MAINTAINER in Dockerfile #? #? Options for image content #? -apt=CMD use CMD as command for package manager # ? -tar=TAR use TAR file to build image instead of wget ... # ? -sha256sum check SHA256 checksum of tar archive # ? -no-sha256sum do not check SHA256 checksum of tar archive #? -openssl install openssl-chacha in image #? -iosocket install IO::Socket::SSL in image #? -ssleay install Net::SSLeay in image #? -tcl install Tcl/Tk (wish) in image #? -no-openssl do not install openssl-chacha #? -no-iosocket do not install IO::Socket::SSL #? -no-ssleay do not install Net::SSLeay #? -no-tcl do not install Tcl/Tk (wish) #? TODO: need option to pass SHA256 values # ? -pull [name[:tag] # ? Pulls specified image from hub.docker.net. [name[:tag] is # ? the same as for Docker's pull command. This command implies # ? the options: -no-save -no-tag -no-del #? #? The defaults are: -f ./Dockerfile --force-rm --rm -del -save -tag #? which results in: #? docker build -f ./Dockerfile --force-rm --rm ... #? #? DESCRIPTION #? The purpose of this script is to provide various modes to creates an #? O-Saft Docker image. It's a more powerful version of o-saft-docker's #? build command (mode) and provides some options mainly for debugging. #? #? It can operate in following modes: #? build - use Docker's build command to create the image #? load - use Docker's load command to create the image #? pull - use Docker's pull command to create the image #? #? In build mode it generates a Dockerfile and then calls docker build #? with. The Dockerfile consists mainly of five parts: #? 1. initial data #? 2. setup O-Saft #? 3. setup IO::Socket::SSL (if necessary) #? 4. setup special openssl (if enabled) #? 5. final data #? #? It is highly recommended to use this script with the -n option first #? and verify that the printed commands are correct. #? #? TERMINOLOGY #? Please see also: o-saft-docker -help #? #? del(ete) vs. rm (remove) vs. clean #? The term "remove" herein is used when objects, files, etc. inside #? Docker images or containers are removed. The term "delete" is used #? when objects, files, etc. on the host are deleted. The term "clean" #? is used when both, targets inside Docker and on the host, are meant. #? Options are named accordingly. #? #? build vs. load vs. pull #? These terms are used as Docker does. "build" creates the image on #? the local host. It uses the sources specified in the corresponding #? Dockerfile. "load" creates an image from a local (on the host) tar #? archive. And finally "pull" creates an image from a registry. #? Please refer to WHY? and SECURITY below, to understand why this #? difference is important. #? #? WHY? #? Why using a script, which finally generates a Dockerfile, to create #? Docker images, when simply using the Dockerfile would do the same? #? Some reasons are: #? used sources - Commands of the Dockerfile itself must be changed #? when a source will be provided by the host (local #? filesystem) instead of fetching from an internet #? archive (such as hub.docker.com). The difference #? is using COPY instead of RUN with wget. #? trustworth - I.g. creating your own image on your host is more #? trustworthy than downloading and blindly using an #? preconfigured image from resources not under your #? control. Using build provides full control over #? all used resources. Contrary, using pull from #? remote resources provides no control at all.. #? clean-up - After creating images, a proper clean-up must be #? done at three places: while creating the image by #? using proper option (like --force-rm), inside the #? image (mainly the RUN commands) and on the host. #? tagging - The name (registry:tag) for images must be given #? to the build command, it is not possible to write #? it inside the Dockerfile. Hence there is at least #? one program call (docker build ...) which must be #? closely related to the whole process of creating #? a Docker image. #? identity - Inside an image, it is hard, probably impossible, #? to identify how and when the image was build. #? #? MODES #? build #? Build image from a Dockerfile. #? #? load #? Install image with Docker's load command. #? #? pull #? Install image with Docker's pull command. Remember WHY? above. #? #? SECURITY #? Please see: o-saft-docker -help #? That's why this script provides different modes to create an image. #? The purpose is to make the build process as transparent as possible. #? please refer to the "build" modes described above #? #? HACKER's INFO # The purpose of this script is to build Docker images for o-saft.pl. # Hence all default settings support this. # # Docker's ADD command promisses to fetch archives from a URL and also # extract it. Unfortunately, modern archives can have various filename # extensions and also may be compressed with different algorithms. So # only COPY or wget is used to provide externa archives. # # The generated RUN commands to get and unpack archives depend on the # source. If it is a tarball, this must be copied or mounted into the # docker image. Unfortunately, this requires different syntax elements # in the Dockerfile, i.e. "COPY ..." vs. "RUN wget ...". To generate # the appropriate code, following functions take care of that: # _copy_src $_src $_tar # _run_wget $_src $_tar # _run_sha2 $_tar $_sha # _run_untar $_tar $_tmp # # Using sevaral independent Docker RUN commands, as the documentation # recommends, is not a wice idea, because it results in one layer for # each RUN command containing anything from the previous Docker layer. # Hence each generated RUN command contains as much internal commands # as possible (concatenated with &&). # # Docker itself provides no functionality to shrink an image while it # is build. This must be done by additional Docker commands (save and # load). # # Empty lines in Docker RUN commands may result in # [WARNING]: Empty continuation lines will become errors in a future release. # hence a single \ is used as "empty line". # #? LIMITATIONS #? The options -n -v and -help must be specified first (leftmost) #? if they should apply for this script. #? #? ENVIONMENT VARIABLES #? Following environment variables can be used to pass settings to the #? script: #? #? OSAFT_VERSION - version to be passed to Dockerfile #? o_saft_docker_name - contains an image registry name #? o_saft_docker_tag - contains an image tag #? #? SEE ALSO #? o-saft-docker #? #? EXAMPLES #? # FROM command sources openssl Tcl/Tk ... options #? +-----+-------+-------+-------+-------+-------+----------------------- #? alpine pull reg:tag -alpine -pull #? alpine build http:// openssl -alpine #? alpine build .tgz -alpine -tar=o-saft.tgz #? debian build http:// wish -debian #? debian build .tgz wish -debian -tar=o-saft.tgz #? #? VERSION #? @(#) o-saft-docker-dev 1.6 18/11/09 01:24:58 #? #? AUTHOR #? 17-jul-17 Achim Hoffmann #? # ----------------------------------------------------------------------------- try= cmd=unknown VERSION="${OSAFT_VERSION:-17.07.17}" registry="${o_saft_docker_name}"; registry="${registry:-owasp/o-saft}" image_tag="${o_saft_docker_tag}"; image_tag="${image_tag:-`date +%y.%m.%d`}" image_name="${registry}:${image_tag}" image_save="o-saft_docker.tar" image_from="alpine:edge" dockerfile="Dockerfile" maintainer="" # must be set with -author buildfrm="--force-rm" build_rm="--rm=true" buildtag=1 buildsav=1 inst_tcl=0 instwget=1 host_del=1 host_tar="" hostdate=`date +%y%m%d11/09/18M%S` apt="apk" upd="$apt update" apt_add="add" apt_del="del" apt__dev="" apt__gcc="gcc make" apt__tcl="" apt_wget="" check_sha256=1 make_o_saft=1 make_openssl= make_iosocket= make_ssleay= dir__o_saft="/O-Saft" dir_openssl="/openssl" # sources # NOTE: empty checksum must be specified as "-" url__o_saft="https://github.com/OWASP/O-Saft/raw/master/o-saft.tgz" sha__o_saft="a55702d69314b8eda52e921e35b89aef9eef02b14c870b3077fbddf3af91320d" url_openssl="https://github.com/PeterMosmans/openssl/archive/1.0.2-chacha.tar.gz" sha_openssl="-" urliosocket="http://search.cpan.org/CPAN/authors/id/S/SU/SULLR/IO-Socket-SSL-2.049.tar.gz" shaiosocket="-" url__ssleay="" sha__ssleay="-" _dbx_config () { cat < $_dir_8/.o-saft.pl && \ EoRUN } _run_osaft () { #? return Docker RUN command to build /O-Saft _src_9=${1} _sha_9=${2} _tar_9=${3:-o-saft} _dir_9=${4:-/O-Saft} _copy_src $_src_9 $_tar_9 cat < $_dockerfile_f < $_dockerfile_b [ "$try" = "echo" ] && echo && cat $_dockerfile_b && echo for file in $host_tar; do $try docker_build_file ${image_name} $_dockerfile_b done $try \docker image build --build-arg "OSAFT_VERSION=$VERSION" \ $buildfrm $build_rm -f $_dockerfile_b -t ${image_name} . [ $buildsav -eq 1 ] && docker_clean [ $host_del -eq 1 ] && [ -f ${image_save} ] && $try \rm ${image_save} [ $buildtag -eq 1 ] && $try \docker image tag ${image_name} o-saft } docker_pull () { $try \docker image pull $@ } docker_load () { $try \docker image load $@ } my_help () { ich=${0##*/} \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 } _cfg_alpine # set defaults args="$*" while [ $# -gt 0 ]; do case "$1" in '-n') try=echo; ;; '-v') set -x ; ;; '-help') cmd=help; ;; 'build') cmd=build; ;; 'load') cmd=load; ;; 'pull') cmd=pull; ;; 'config') cmd=config; ;; 'dockerfile') cmd=config; ;; '-alpine') _cfg_alpine alpine ; ;; '-debian') _cfg_debian debian ; ;; -from=*) image_from="`expr "$1" ':' '-from=\(.*\)'`"; ;; -tar=*) host_tar="$host_tar `expr "$1" ':' '-tar=\(.*\)'`"; ;; -apt=*) apt="`expr "$1" ':' '-apt=\(.*\)'`"; ;; '-author') maintainer="MAINTAINER Achim "; ;; '-sha256sum') check_sha256=1; ;; '-no-sha256sum') check_sha256=0; ;; '-openssl') make_openssl=1; ;; '-no-openssl') make_openssl=0; ;; '-iosocket') make_iosocket=1; ;; '-no-iosocket') make_iosocket=0; ;; '-ssleay') make_ssleay=1; ;; '-no-ssleay') make_ssleay=0; ;; '-save') buildsav=1; ;; '-no-save') buildsav=0; ;; '-tag') buildtag=1; ;; '-no-tag') buildtag=0; ;; '-tcl' | '-wish') inst_tcl=1; ;; '-no-tcl' | '-no-wish') inst_tcl=0; ;; '-force-rm' | '--force-rm') buildfrm="--force-rm"; ;; '-no-force-rm' | '--no-force-rm') buildfrm=""; ;; '-rm' | '--rm') build_rm="--rm"; ;; '-no-rm' | '--no-rm') build_rm=""; ;; '-del' | '--delete') host_del=1; ;; '-no-del' | '--no-delete') host_del=0; ;; '-clean') host_del=1; build_rm="--rm"; buildfrm="--force-rm"; ;; '-no-clean') host_del=0; build_rm=""; buildfrm=""; ;; '--') shift; break; ;; *) break; ;; esac shift done # TODO: options need to be documented # adapt platform-specific settings according options case "$image_from" in alpine*) _cfg_alpine "$image_from"; ;; debian*) _cfg_debian "$image_from"; ;; esac # commands for package manager case "$apt" in 'apk') apt_add="add --no-cache"; apt_del="del --purge"; ;; 'apt') apt_add="install"; apt_del="purge"; ;; esac [ "$try" = "echo" ] && _dbx_config && echo [ "$cmd" = "help" ] && my_help && exit 0; # just help, ready # make temp. directory, avoids: # unable to prepare context: the Dockerfile must be within the build context host_tmp=/tmp/$hostdate [ -d $host_tmp ] && echo "**ERROR: $host_tmp exists; aborted" && exit 2 \mkdir $host_tmp # no $try, because we need the dir if [ $? -ne 0 ]; then echo "**ERROR: create $host_tmp faild; aborted" exit 2 fi $try \cd $host_tmp case "$cmd" in 'help') my_help $0; ;; 'config') dockerfile $@; ;; 'build') docker_build $@; ;; 'load') docker_load $@; ;; 'pull') docker_pull $@; ;; *) echo && echo "**WARNING: $0 $cmd ... unknown mode, ignored" && echo ; ;; esac [ $host_del -eq 1 ] && \rm -r $host_tmp # # no $try, because we used the dir exit O-Saft-19.01.19/o-saft-img.tcl000066400000000000000000001172241342117255600155310ustar00rootroot00000000000000#!/usr/bin/wish #? NAME #? o-saft-img.tcl - images for o-saft.tcl #? SYNOPSIS #? source o-saft-img.tcl #? VERSION #? @(#) o-saft-img.tcl 1.7 16/12/16 13:06:03 #? AUTHOR #? Copyright (c) Achim Hoffmann, sic[!]sec GmbH #? This software is licensed under GPLv2. Please see o-saft.pl for details. #? Project Home: https://www.owasp.org/index.php/O-Saft #? Repository: https://github.com/OWASP/O-Saft # ----------------------------------------------------------------------------- set cfg(IMGSID) {16.09.09}; # initial SID, do not remove if {[tk windowingsystem] == "aqua"} { # grrr, ugly check to avoid Tcl errors package require Img; # some Mac OS X require it } # +_30x20_gray.png set IMG(+) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAABUUlEQVRIib3VsYoTURTG8d/gvEBC opXYTZFK0ELYNzAwRfIMIUUwIoJsOUVWsU3lSyTF4BtI0kSw3tIqLAmkl7mMVRYsROdumK+8h+/8 78e5h5vUdQ1Op9MQb/AcT1xWd/iBRafT2UBS17Xj8fgJ1xeG/U3XvV7vc7Lf74f42hIUAl6lIYRZ i1B4hPdpVVUvWgbDVRpCeBzjXC6XYD6fx9ifpiGEGKPtdgtms7hJpVVVRRnPaxjrb5R4tVopiuKP s8FgAIqiMB6P/x/c5MZZlplOp6AsS5Dn+X2tSa9GibMsk2UZ2O12YDKZ3Neb9Ip+XOcZx/qTzWZT xxgPhwPo9/tR4OjE3W4X8Ymj1+mhSkMIdy7/Df5Lt2kI4TuGLYN3aVVVH/EaSUvQX1gkdV0ry/ID bpC2AH2b5/mX5LyP6/X6Jd7hCs8uDPyJb1iMRqNb+A0h940EzNF3pwAAAABJRU5ErkJggg== }]; # -_30x20_gray.png set IMG(-) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAABCklEQVRIieXWMUrEQBTG8f/gXCAQ tBKLkF7QQljIAQykSJFLiIgIsmUgUfEG3iBdisUbiJVC6i2twkIgvcxjrNxOJMswQfy6Vzx+vJkH M8paC8A4jilwCRwDB7jNBuiAOgiCVwBlrWUYhgdg6Rj7KcswDB9V3/cp8OwJBRDgTIvIhUcUYA+4 0caYE88wwEKLyP4M8KEWkRlc0MaYSQ1VVdE0zbYuioKyLKfDUyeOoogkSbZ1HMfscmqq6zo7uctB 5rvjP7NczuB/OfEG98/gb1lrEXkHUs/wmzbG3APngPKEfgK1stayWq1ugTtAe0Cvsix7Ut9fn7Zt T4FrYAEcOQY/gBegzvN8DfAFUdVpEL9obbUAAAAASUVORK5CYII= }]; # ?_30x20_gray.png set IMG(?) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAABq0lEQVRIib2WvasaQRRHz+CCi5Uu YmThkUbQMpAUgVdoHUHB0lYsJAQNgfAarUxCesXgf7AgFpLGDxAMKSSCpb4yNkZQ7MMMkyJYhjiy 7Knv3MNvuJcZobUG4Hw+54E3wDPgCf5yANZAOxaLfQcQWmuOx+Mn4MFn2b94iMfjn8V+v88DXwOS AijgpaWUeh2gFCAEvLOklM8DFgPcW0qpxLXVs9kMz/PYbDacTicSiQTFYpF6vU4oFDIR31lKqaur J5MJ8/mcdDpNKpVivV7T7XaJRCJUq1UTMZaU8uriRqNBrVbDdV0ABoMBrVaL3W6HSR8Ao8TRaBQA pRSLxYJOp4PjOJTLZUz6gGHiC71ej36/Ty6Xo9ls4jiOcWKxWq20qTibzRIOhxmPxwghTI//FS+X S2OxH9x01dvtFoBMJnO72HQoDocDlUoFIQSe55FMJm8Tmya2bRvXddFaY9u28VBdENPp9Bf+P4P/ 49FSSq2AfMDiH5aU8iPwCrhtL8z5DbSF1prRaPQe+ABYAUjrhULhi7h8fYbD4QvgLXAPPPVZ+BP4 BrRLpdIjwB9dAqe4iEbEGAAAAABJRU5ErkJggg== }]; # Start_64x20_gold9.png set IMG(cmdstart) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAAC+UlEQVRYheWYWUhUYRTHf3eyBXPM LacM0wySKdLCpGVaVIQ0i8LQFOrFaFPDFgKpIB8GIoLeiqgH0cCHHkIiy2ixRQrS1GqEfHOBMEol TXEbTw+fOm5ZzbUu5h/+cO855/ufP2e+72O4iAiKJIlQKkLzcOj/Y7MID0SwDQU0EQHRLgK5zCzk osklTQZIAu4Z7cYAOIENHghZRjsxCLOA05r08xkINNqNQWgyIQQi4C4bG2D/AVgSDJ5eEG6FY5nQ 1KjyXZ2QcRBePHe/x0hOsV4w0oe4S2cPstKqpIIWI5ERyHxPZN5c5GuzqinMV/mb193vM5JTrYf0 Iu7y4wdlJsAf6e5Qsd5OpPqNer6Vj3ibR8/8ol3lbhch66NV3s8XSd6DfGpwaVsCEdtG5NljJGwZ kr5vcj13adKzhcxeoAGtrVBQCM5+mO0BayJVvqcH/P3VYYuPg5xsiI5SuZYW+NYOaamwPAzuFMPx EyP0gbdVkJIG9fXg6zO5nvvsRvTQnueSCg1BblxF+r678kkJg1v22uh1zi7Xc221qllkccUsgzfT rh1I+5df67lL09hr8U9xLhcelUDMVqhvgMNZkLALnM7J1xXfhc2xEBAEEVEq1tExvu7MKTCb9br8 OXQdgSHGx0HZQ3j2UG3VJ2VQcp/hrTyMwXqHA1LSoaIS8s5DUcH4miH4+ozpN4GeHuoagMMBz1/A gFO9b9sCq6zKW1ubis2Zo957ul3rqmtgQNRdkX0UFgb8fABje06kZ9wAaiFmO/gFQbQNVqyG8tfg swAS4lWNNVwZvmCHxN1w+QqELlWxmndwKBMyjqjL83cGMJGevgHowNpI2Lsb5nvCewd0dkJqMrx6 ChaLqsnJhPhY6OqCyirw9oYtNsg6rH7NklK4cBZ2Jv5ez4n09ECT7zQDFn0y0xZ1JoTKqThL05QV mrSzCShH/aeZSegFIkyY5RXqY0i/wYb+JXqBHMxSp74IAbRr64CTgA0IMc7bX0UD8BKw4y11AD8A CylTRgq9MSEAAAAASUVORK5CYII= }]; # +check_64x20_gold8.png set IMG(+check) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADW0lEQVRYheWYbUiUWRTHf8/MlC1G peiomKOmS5K1hUW2TRj0XmNrbFF9sjZ228RCUtgs6IUQqi/h17APfWnZCKKgsjeWzXV72YpdUNLJ BLPdZdg3txe3SZrn7Iczo+MkzjO1MZJ/+HPuOec5595z7+VcZhARlHhEuCSCr9/0/tEnQqMI7pDB EBEwjUNALaMLtdjkiCF9eIDz8V5NHBAA5jkwqYz3SuIEO1Bjw2Q2JrwrprvAGAetLSMyv9tBAOf/ tqdDQYLSRC/dyMqf5cC0/vXBwyr3vUG7tBsQy1wxI3SqMcIWy5X5tkkZaf+nB7ZUQGoufOCEwrnQ eHnwgppvQP5MGJ8By8rgcfdAfM/fUL4VkrIg2QWeddDREVv+0LednTC5AOyT4JvTFuqSPxGrXDhf GWkvW4kAkpaKLC5BkiYiP15RX1qq+sYlqC8lWfW1pa/Hly5DKj5D7DYkPxd58Yv1/K3NSNdPiCsT MUCO11urCfkdGY4NR3WCodhwFHlwS8cJY5HfWjTG/3ggPrTAg7tUv/C16hlO1TuC8ZnpSMCnto1r 1Hb1tPX8txqRvBwd19cNX1M4o/aAoumwv0bHJ06p3LxhwNfu1fH0AshI1WuVMCbsegab1CK32j7M Uf3pc9XbgvG/+sCePnjurm548a+1/FurobMLlpZA1ecQra4QHNE6Z1GhEuC7H1QeqB7wP+pWacCw XXhiovqN8IUHwAzGTHHB7h2DYxbMgbYOa/nbH8KkCXCtCc5dhLLlw9cVQkyvQD/CYqZkqWz1gs8H 6U7w+/WEnSkRMZGd2oTCfB3+8Rd8uhySk1R/3gvjE+Gl31r+Mw1gs4GnHDZVwb2LkJcTvRQbAbDK k/XKcNvMqVA8C/wvoWgFLN0I2fOg6SaDTyz0TodvQADyXbChFJ71QvFqqNwDa7+A3I9jy5+dAStL 4Ktt8OQZrPsS/L3Ra4rpGcx0KiPtZ4/B+lVgCly/DdmZMC2P1057qBuACccPwfZyPfVjJ6HpNnyy 5M3y11WDezb8fB8q90avyZCH+IC0oa7HKIDXQYC7gCfeK4kT7hjSxnygmWCjHUXoAz6yUSA3MKnF 5NW7+LU2QtmHSRUF4tV/hABajDnATsANZL/t9o5QPAK+B+qYIV6A/wDptX6WH0zX1gAAAABJRU5E rkJggg== }]; # +cipher_64x20_gold6.png set IMG(+cipher) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAAD6ElEQVRYheWYX0yVZRzHPy/nLEBp Ch3g0DkK8UcFXBa0eRCyVQQTylpaVhfW2mpWNteczdY/c1aj1poXbjW7qIvarC66qKhcTg9OZ3LB kCI4aKHTnUkaQ1mC5z2/Ln7v+cs5cCDwrPpuvz3P9/c8v7/v8z7v2UFEUKFVhO9E8IdV/z3xi9Au Qn1IYYgImMbbwHb+X9iOTdoMGaMV+Drd2aQBJuCxY/JcujNJE2zA1gwC1BKA2RbPanC44ZQvdRtn MRjzoKd79vNJIvV2TApmradRGB2FsTEIBtDDNh2YM7CZGRbZUwm0810dX9uWuucTHWCaYLMx7WJs xvRtZoqMcLcnkQNelXj98EV4cjPkL4FsF1SvgvYfdM1ZCfZC6OlR7l6u+w56oaoOsm6E21tgYIAJ T/zwESivhZzF0LQOzpyO7PnzAmzcBLmlkFcGrRvA54usOyuhYQ0c6oCyWnjsqSnqk3PIVHKHRyVe f38zAkihA7m7AcldgPz0ra4VOnTtxAHlLqfy+dnIPasRd5FyT03EX8gmK1P9OfKUr2uZGPPeRuSZ jYgtAykvQf46FfGRlYnk5yEZBvLs45PXhpxBEsneNg2USPa2If1enWdeh5zrVJsrAxH7cAP2Kw81 YPcbys93aaKA/PxjrM3Orcq/+UR5UYFynxXT5UTMQdU9slZ1+z+L9XFfIzLSm7i2aEl6B9RUw+tb dP7xlzo+sT6y9mu/zpcvgSKHHqdMOxPf3WDoqCldebPy/IWwrAy6foGTv0FVWcTkrjrdU7FY+cgl 5b1WzLN+sBXHhvk99JpY2PY0XJ+dIJ842AkkacAyFYCDR3Xc8XxkffC0jgaQ0IdVMGbsemA8wiVo bQnpLJsF85Qb0ckHIHhVp6WL4KVNseEabo31kZuTJK84pPQViCnGQqlLx55+8PvBmQ9XxmDkMhTc EGUbvmyUeo9B/S3gH4Lek6pbWhLrO2wTjNVVW6dk6CI82Ah5C5VfHoWc+Ul8TIGUGvDpO1FOLayo 0ON8rBtqHoDqCujugz2vwvrmKONgrN0r78P3XvANwvhV9VFZEpdsyCauoHI3bFgD+9ph5UPQtAr8 f4C3E4aOxCUdFzcZUvoMuhwq8fqvdsPDzRAUOHQcioug6qaJiUfzPS/DhWEYvgSNHvjivcTFJjoB mPDRDtj8qD71Dz/X4tfeOYmPKcSQLvxA4dS9+mdwN8HZ89C1D1YsnetoKaPPjkkn0Drnoaw7QK7d z9xUcNxOgLeAFqwLfc4R91VII8aBXfqHyFHjReBNwJ7mpK4VxoEt1MkH2gCAw8ZtwAtAPVCc3PZf jUGgA9hFg/QB/A006zCkHjUslgAAAABJRU5ErkJggg== }]; # +ciphers_64x20_gold6.png set IMG(+ciphers) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAAEaklEQVRYheWYf0zUZRzHX8fdAhRD 8IAjQIwfyq9lgRsghNMIEgpbWmY/rNUsKxtrTkcr05zlqLWm02WZW67VpuWWm0blcnI4DaWNIYX8 kESnu0kaoUzA+97TH5+7+973gAYJXT8+22fP8/48z/vz6/t8n+/tUEohSrlSfKMUDq/pv6cOpahR igKPwaSUAs20Gaji/yVVmFW1SQ1QDhwIdDYBEA3Is6DxUqAzCZCYgdVBOMnBCeOheUVgjYfO9tFz bIlgmgTNTeOTwxi1wIJG9Hi1tK8PBgbA5UQO2FhE+wucm5cEy0hBN74r4xtrRu/tVB1oGpjNjLkY s2nsnPGQIG/n/fSwXdTf3nMFnlkFUTMhNA4y50LNd7JmSwdLDDQ3C47Pkn1H7JCRDyG3wd1l0NHB kCd+9Bik5EDYdChZDOfP6Xt+uwzLV0JEEkQmQ/lSaG/X123pULgQausgOQceWyH2D3ZBWq7kaUuH RY8beWiAuogaTuflifrbF5WiABVjRd1TiIoIR534WtZirLJ26rDgOJvgyaGoe4tQ8bGC87J1fx5O SLD4s0YKXlw2NOb9xagXlqPMQaiUGajrnbqPkGBUVCQqyIR68SnUDweEc2sY6vknUBUlsu/3VmM9 qPMoj+6sFtJwurMa1WaXefAtqIsNwunv0PneBhwS7GnAljcFX2qURAH10/dGzsbVgg/uFhwbLbjd HTPOhtK6xPZohdgOfW708UAxqrdFbPt36byGg2JzntVz9ajhDsjOhPWVMv/kSxmfXqKvnW6TedZM iLXKEQq2MPTddXmOl8DcOwRHTYW0ZGj8Gc78AhnJOmVBvuxJnS6496rgFnfMCw4wJxrDnPW8Jm5Z 8xxMCRXb/FxIT4GWDphTDvNyYfNayM8x+rDg9GlAmijAkeMybnhZX+86J6MJ8OV5xV0wmnHdOahj 5XJv8djcnPBJgk2+zXSC64ZMkxLg1ZXGcIV3GX1EhOlxpoTAiX2w7VPYuhtq62HBMvhxP2Sk+jZg pJvXtxi3JMXJ2NwGDgfYoqB/AHqvQfQ0H673ghFor4eCO8HRDS1nxDZrhtG3l+My2jLdp6T7CjxU DJFTBV/rg7DJI/gArvdDWAhUrYDKJ+G+Z8HeIA82I2kUDfjsnaENmJ0qx7m+CbIfhMxUaGqF7etg SakP2WXkvf4+fGuH9i4YvCE+0v0b4OH4FZQSD0sXwp4ayH0YSuaC41cppvuYX9I+cffVwPptUJgN EeFwulPsWcnGGCN+BuOsov72r7bAI6XgUlB7EhJjIeP2oYn74u2vweUe6LkKxXnwxXvDFzvcCUCD jzfAqmXy1D/cK8VXzP8THxqkJkB4mDTuo70wLRx2rIOibOM+k2rEAcQwARJfAhcuQeMemD1rIiLc tLRa0GgAyifEvfsOUIH5mTsaOWnBydtAGe7LfULE76vwD5FBYJP8IXLctBZ4C7AEOKm/SwaBSvLV DmkAwFHTHOAVoABIHJn7r5YuoA7YRKFqBfgDJNo6W5zikUAAAAAASUVORK5CYII= }]; # +cipherall_80x20_gold6.png set IMG(+cipherall) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAFAAAAAUCAYAAAAa2LrXAAAEkklEQVRYhe2YfUxVdRjHP4d7EjBK kLdLgBAvyotLhEoQrNkYTjBzKYG5nNVspiBzzoZpaY5q1Kz5h1tNt2qtlunKPzJmVMpLkkmTAcV7 CUxFESJeNsB7Of3xu9zDPfdcuBTIWH63Z7/zfX6/53m+5/dyztmRFEVBQMoAcoE4wJ+70MMN4DJQ AMpPAJKiKGCW3gbyZ1Ta7EM+BqVQUobIAL6ZaTWzEGYgUcbMjplWMkthAHa7YCIBE0y1JT4GPkHw R5PzMcYQkOZCbfXU65lsbSe1JMuY8fuPK6GLgQEYGoIRE2KzTwbmfxEzVdDWHl9LsOyM0EPvivb1 Pc7rqCkDsxkMhnEF6MIgTT5myjCiqa3lGrhYZ3gc+7FUmNbf0w0v5IDvQnAPhNjlUPSd6DNGg+wP tbWCBy0W486XQkwSuD0AK9KhuRm7VS6/ABEJ4LEA0tZDe5s65q8u2LwNvMJgfjhkZEFTk9pvjIaU 1VBSBuEJ8OxW4T/5NSSmwbxQ8I6A9Zvh+jX72g65A3NqAlEspvFvyYWPvgCDCyQ/AtdvgI/nmBjN Ct7qhjWbICgAfL2h/Bd4brumDrBzH4QGg7sbFJfArv3qmOd3wqenIOVRyH4Kzp6D9I0wOKDm+LUa Ml+EK23gdb/wd3XB372QvQ7CQ+CrbyE33762Va+WO5ybdhQ9O1ZonTY7O1aI0lgqrl3noFyrFDGD zWq8v4/orykWPNAo+JE3BL9ZheLmKny//WAbc2i34Gc+ETzAT/AmS81AI4q5Vfiy1wpf8ee2OZ5M RemtU/WMjlfaRT1AMfo61qvljszhMzA+Fg7kieuPT4l2ywa1r75RXC9eCAE+YjVcZXW3WaFZ0WUP Ce7rCVHhUPU7tPwJMeFqyBNJYkzkAsF7+wSvs9S82gGGENsyV0aPuQV7XoL73FXf6SJ47zjUt0BP r/D19Y+j1xHXQMak3xEfJQzgfIVoD+aq/a1topUA3RyjR8Bs228aVrkyYhky6rPEzJsruDRWuAlG bovLsGDYu822XMpS2xxeHmqd2kbI3A6yDIf3gp83ZOWpeXX1OtCvhVNvYZtkFoQFquI6OsDoC4ND 0NsvBFqhecaUXoTkOOjohLoW4VsUapvbGjNi64u17NLObng6FeZ7Ct4/AB73OsgBXK6BEQXioiBn E5z7WTMO/ThdroFTE/jZO/bFlkSK43ixGuLXQWwkVDfA0ddgw6oxwZojsP99OFsKTa0wfFvkiA5F /9hobiQiCLJWw4kiWJYJacuh4xaUVkLnBY3oMXVDA0RbVQ9bX4XvK+Ae2f6e9PROyWdMoI8wrf/0 EXhmlVjdkksQEgAxD9rf+Fh+dB909UBPH6QmwsnD+pOltwMxw/GDkLNR7LoPvxSTt3blODnMsGIp 7MiGOTKcKYEDL8Oax/X1TfYzRlKq6OAO/L4KSoOrN6HqBCxZNN3V7hgaZMxUAhnTXsryDFQmeKbM MlySMfEWkI7lhTrtmOCtNoswDBSIH6oV0ivAm4A8QdBdCAwDeSQpH0jWX/rl0sPALiAZCHEc+79G K1AGFJCiNAD8A+Nsu7Kj+5PkAAAAAElFTkSuQmCC }]; # +info_64x20_gold4.png set IMG(+info) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADBElEQVRYheXYbWiVZRgH8N9xp0wY 0Rvu5F5qq2VKRm0q1iAqwqR9iD5kEQgFCsaCsFVaUJtaRG9+6YuFgSbZlyjpzWxmhSOwWm8b2USU WtDoW5aNtnN29+E+x50dNzlsZx2yP1zcz/W/7vu6r/vPcz8XPEIIomkNwYchGDxJnXk2GII9IWjJ EYkQAunEM9jg/4UNkuHZRBjSivfKXU0ZkMGypLS2cldSJlSgfZa0ZmlmwpbdyEV1HD1S/JrffmXF 7VRWcX41W1+Zmdqy1pKUNrd0oo7HiRP8PczocHbDIrDlJfbuZ14VC+ez8PLi104BtclSJN/0Yhyf bB/P935CJkNFhaIPceRoHNvX8tDaLDlzAphVildpf3e0Qj61iGQNfX1j/uLlvPEm9UuobGD5SgZ+ jvHHNvPuR1kBNlJzbeSH/uCRTuqamF1Hw1I2Pc/I0PRrL4kAQtYK+RwyY/7XvdzXzmV1zDmHrgOs 64jx8yqpScV5N1/H6rsif08bL7zMX0PcsJTfj9OxhdUPl1GAbbtI1Ef77GC0nL9tV54w+QKESD3R xr4d7Hguhj/vifH1a1h0ReTuXEHnA/zYz+4uZp/Nt+/QtZ2e3ZyV5LW3OHZsegIkZUwJTVfSkW2g 29+O4713jMXG5c2M929aEv3G2ugf/zMvnhNtNHLf/RDdqxqpmRu5Sy9mQQPfH+abPurnTe0MMOWP YNP8aPDpwTh23p83YZIrAOfOiX5idIL5+QKkScrjJ6g1MzIxXyxK0gVOFl2Ya4IrMM7PP/QkAuRE 7j3MwC/UphgY5FC2W1wzzTZZEgFe35x9mCxX4Ucx52cKOE4Rqb6KVbex8wOa76Z5AT2HGEmz8hYa q0+zbxEoiQDVF2QfJstVcAVOeQPy147mjVnu1cepT7FzDx9/QepC1q9i45rT7FkkEqHbIKqml+Y/ i/6ktK/QWu5KyoQvE2Gf69GNRLmr+ZcxjKvjD5G9iUfxtLyuc4ZjGA+6NWyNAsD7icVYhxZcUr7a ZhQ/4QCe0hr64R+Dq1N5biRYkwAAAABJRU5ErkJggg== }]; # +protocols_80x20_gold4.png set IMG(+protocols) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAFAAAAAUCAYAAAAa2LrXAAAElklEQVRYhe2Yf0xVZRjHP4cuP0zA gK4XA7uAOEAo2UUnKZAi/iMzWyFu2a+VxQyNtaSoMSlHv7ZWy+lkQbMM10zQSpe1mYFmFsLQbk5F 1AxtotXUSPBc4O2Ph8u9F+7dzl2bgPXdnp33+b7P97zf8573nPfeoymlEGj5wCogHbDwP7yhE2gF KkEdANCUUqBrbwBlI2pt7KGMIPWWprrIB3aNtJsxiD4g04RO8Ug7GaO4BXheU510AhNH2s1oQHQa dF4CewOkpRiSdJjQR9fkXeuGleXw+BLIybzBgzv3UwegG1JMNuHw3rN2nRzXPPuvbfmF+p2w6VOY nQ45GTd27EH0gq95GYoAdPAWew9IDOVjM8Fsg4b9MC0PQpIguwDaT7pqomdC1oPQ+B1MyYGHVgnf fRVKK+HO2RCcBAnZsPZdcPwt/bV1sHKNGHvqZdAS4M31xrTocPl3eGK1+BuXDKkLYPce4/qhK3Dj R5A8X84VPRMWL4eTbUPmRNlR3uLeGRJD+ZiJKECNH4dacA8q1iJ55t2uGksUKiQIZY5ABWioZ5YK f3+u1EZNQOVloiLDJX90kfTXvIqKjxEuLxNVsgy1p9qYVtlRi+cJZ4lCzZ+FighHNX1iXG+JEs6+ HfXDFmmHj0cVLUHdN1f6rxz0nA9UC8oZ1eUi8hbV5VITY5b8vdWSX9wjkwWoo9uEs0RKvigbdXWf cMfqhAsORHV8KdyZnahAk/CnvxAuP8tzPKPath2umt++kpqeg/6N7fRt34r6/B1px5hRzbXS39vk 8uSMABwDS9YBtkSoeFLCGi3hzG2Jnu+FWcmSm0Mh2SrcqV88a0qXQViQcEeOCZc2BWIjhYszQ0qc 8K1HB7T9A+I+ly8j2uPtrppJt0lNsObn2E70wrzp0n/+Esx4GOYuh6YjLk/OMLnvNrYECYCGZjm+ 8pjbid3eE73XGdyp1MBF9w15l0SEuGpMzvdLP547nA8tvf5ptT5pa4phO6jfYzsgLBCaqmD9dlhX D42tkFsMLTUwLc51Cp+byODD640H9rVIfuECHDsrXFL0cCNOnS1eKPtp6DgnXMc5lzbdKlxQgOTX e/zTJpil/fNp8YQOPV1wsdP42O6+u/+CUBOUFcKpzZBzF/To0HDIcz58/ozZUuo2CV5Qvgm+PgQn z4PeC7OSIOUOhj0Kzjz+dngkFz7eCxkrICMRWtrB0QeF2TDVIrUpsbADqPgQdn0PuelQWmBAi3j4 8QTYiiDVCj+dgQ3FUJBtbGx33/XfQkUtZKVCRCgc/1W60iZ71vpcgTHhEr5W4IYi+OMKXO6CvOmw rXR4jfsKRIcPimHNUggNhm8OQ0ggvPgAbC5x1ZQslPNduw7NbRAeZFz72UtQOAf6+6HRDlYzTJtk XO/ue+pEmHArbG2E93dDVBhUrYCcJM9r0lQdF/Dj81Xs03D+Tzj8NkyPM6q6aXHChE4zkG9YMnCX lPMu/LdxyISD14GFgOaX1I+/OzcpdKBSPqjWaC8ArwGmETY1VqADJSxXVdrgJ/2N2gzgOWAOYB05 b6MaZ4H9QCUr1AmAfwB60PbhRO4J8gAAAABJRU5ErkJggg== }]; # +quick_64x20_gold5.png set IMG(+quick) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADtUlEQVRYheWYf0hUWRTHP0+f2S4F ibljWKurafijXC1KVqJaKCIhg35uLZtbu7URi4jQthXpylT0z7b/bATtH/2xilBEhZCQRaFQprSz pljrDOoObGMltJGLOjPe/eO+mXlvHJ03IY3VFw733HO/99xzzv0xj0EIgRRKhKBRCFx+07snLiG4 LgTFPoMihAC3cgo4zPuFw8SJ04oYogSFhmhHEwV4gSIVDwejHUmUEAtUKuI5A8BH0Y7Gh6J1YO+F +zcgPW1ybnI2DDyDh82Ql/1ayzlV3NMneYChIRgZgbFRwB2GLLTWY4IbGgtUPJHNqDkj2+MVr7Vg WDxsAq8XYmPBdGyeCLhBiMENkcitFinBdocdVm+GmRmQtRIaGiExD5ILApxZWaAsAHuP7Nv+lH09 J7kA1DTo7JT9F4OwpwKSlsAHGZC7Bq7fwLjjnkAM85dB7MdQf9lcPmrER8d37ILm7SqH1g5ISoDk RNj+Pfw3DJbE8Vz/kfXtmtBxgo51WSVcvSn9FC+FB10wd7bG17iKF/r74PNd8M8AnLfCjvUh1g0B UwX47RJ8W220KYtke74aViyRyc9Q4Y9LkGKB2gb40vdlEa4AE3B67DL5+Djpd14SjIxC/Awj/9VL KD0Afz+BX36AvZtC+JsApt6AwkVQtV/qF67JtmxjYMzeK/XFmZCSKINft1ybLDDutJac4d6G4njh kV2qeQthXoLkxMeM5+6rAocT1hZB+RdE9B6YOgGFC6UA3G6TbfU3gfF+p2xjFPyVj9M7CFpDaPfv 3xcTc3CDZ0SqSqhxHR71wpxZ0HQPrjZB6arJ89Ej4keQMU10tnSLdNblgMHn0tZq82Ub4M3+UJr6 nLJ/p308R39KfH47HeByyfHhV/B0wMi9fArqfpL67ipw9JrPJ+JHsPaYpujm5adBYSY86IGlZVCQ Cc0dukkatygHrrTAVzWQnwG3beM5fnggPx1WZENrNxTuhtxPoMMBv1bAltUBaupcyEuHQzvhdB1s OQJ3z8LM+PD5xBjuowlJSZASbK87Cp/lwJNB6O4D69fGZPDAmQOw5lN4OQR/OeH3HyE31cjxwyv7 V2pg2yoYE3DHBqkWyJkfmmstg+JcsNnh4M/m8lFEIy7AEr5WkaGzDxZ/B5Y54Kqfau9ThscqbtqB kil3PdlP3PRBm4qbk8AGtMd2yqD/sJmeBRgFrPIPkYvKIeAEoEY5qDeFUaCcreKcLABAnbIMqACK gdSJ577V6AeaASs7xWOA/wHML0dPhYHW4gAAAABJRU5ErkJggg== }]; # +quit_64x20_gold2.png set IMG(+quit) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADIklEQVRYheXYb2iVdRQH8M91VxNq Ixu21bDFxGLZGtqqMWGsMKEGBYH4whBBJSJBon+jF01jToOgN0JSQb3QXgSyoEXBoAxfhClm5RJl 4WasLShKYXPP1nx68Tx393q31Xbv1Sv1hcP5/c7v+zu/8zvPuefhPsIwFInWMPR5GBqeMv33ZDgM fRaG1qQMiTAMCRJ70Ob/hTY3hG8kwgta0V3saIqASTQmBZ4rdiRFQgleSITn/Ypbix3NP6HxCfr6 +eYTaqoL6vrnpOD6vjyMjBCMczlAwOgltu9i81M0P5iX62VJQf4Bvv52pF97Nn9fM+GHLiYnKSlB wKFu3j9EUx3N9fn5XiDOaj7yxdeRZNt/6qNlE4tXcddjdPdQ3kRlc5pzUwOJe+nri+Ynv4/mmZzK ZpL1nOrlQBfbd0fBb9sZcffuzz32glSAy7HO8rXxVY7+yNKbqbyFDW2MBlQsmc41HtvG43mYwQnT nGCU8jIujrC2gZU1PLBiBn9zRM4JeO9Ttr15pS3RFOl3X+Sh2ujyi5J8+w5VSznYw9OdMXm2BExk 2LI5E2xZR9eXnBtiQwtbW2fhzhE5J2B1Ne0bo/EHPZHe/Gh6ra8/GtfdSVVZFOC6++LNszzduVSA QLriJuR88RSSxnLbuHpZJHD4ZKR3rk+vDwxGegFSZyz8K14M07YUwrHIduGPGTipBASxbTKeT0z3 M19ctR5QsyTSvef5/TfKSznam7En5pYuZiSgf5AV5Xz13XTOFOIKWLQgXh6bgTNPFCQBB5+JBxm+ 6m+LfgonBrj/FVZVc+RsvJhR3o3L+fgEm/ZRfweHT0/nTFVAXPK1lXSh/SO6j/HIPbyU6gXzREFe g1U3RpJt/3ArTcsZ+pPTg3Q8mXW5gLfW8/DdXLzE2SEObGHl7VdysnvAjhbW1kZvlOPnKFuYe+yJ cJ9hVOSWv/nh1C/UdVJRyvCea3Hiv+JMUuA4ciygeWKmDl9cHEsa04nHkbjqx2UmIM/uXQCMoyP6 INKeeBm7kSxyUNcK49hhV7g/SgC0JRrwPNagsH86rx8M4Ag67A3PwN/pwQmHiC6gcwAAAABJRU5E rkJggg== }]; # +version_64x20_gold1.png set IMG(+version) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAAEdElEQVRYheWYfUzVZRTHPz/ulXd5 UwEFSVQ2RMR4aUiSDpyKslTKkLkBurVatiLWNGwVQRQ1rTZXI1OXRejcookvA3M4pea8IhoaA6Ql LxKUOZMpXK7C0x/nXu+9cNXW1Nv0bM+e8/3+zjnPOd/fy90uSilkka4UNUrRe4t6+FavUlQrxVwL oSmlwKiVAgU8WlaAu/pIU1dIBw44uxsn2BAwR4+Rl53diZNMB7yuqQv8AQQ6u5vb2ZwM+LUdTlbB 1LB7Xr5Lj/H/OzzA9eswaILhAcB4z8tP1tQZ1Ei2eKvs77x4zw/8TzY0BDrd/antghFGriMGWbbc 7JWgxcLufVZu9z7hZq8UfOVPyNkI/k9BwDxIXwdtbdb44FRIzoVjx2FaOqzeIHzZLohcDh6JErP8 FWtecCroE+CXJsEDf8P6TRC2GNyegKlLofhzuHHN/pyELOkvfAl4J8GiF6CrY/SsDgVg2LxsuOyF otj3tVausla4nIWC1xZDeQ0kR0NWChwywNLXwNjHrce3oRmeexPae8DfEwynYd0m6PkLchdD4gww NEGQpzUHAJPg1W/B5l3Qb4R5MXD1GhRuh+ffs+kXON0Ka0tg2iTwcIXD9ZD/iYNZVTVKVaO25aHA 8dqWh/q9AqVzQXm5oQaqUP17xde5oHoqUG07JDZkHGrooNTMmi/c4Q8EB/kJfjoR1VcpXFWhNe/U FuFuHpDdNudcGar5S/HdxqC6vpHrF3aixuiE/+0r+5ySHMEHiwRP9LfWtSw9g6JYXBgUrhJ/5xHZ 16Rar030ggUx8MPPcOgEKAXXByEtFoK9YH+TxHZfBl26/XvWfhGIMssJrF8GY3XAIKREwoxQaL4I Ca/C/JlQmg1JkeZkyxfKBI2d4kaHQaiP5E/xk/yzHXCmBcL9rTkpMyQmYoLgvn7Btqa3PDJxIRCX If7Rs7K/m2ETaYScZBFg73ERAITDCMPmwlMDYeMK+0OSp2H3OPu7WvFYDU6WwGc1sKUGjjVB6tvQ UApRoTZFTKAfNvvD9vUsAw8N2vM+esGayX4OhwLYmeWgEdcyZoG3GxjOg+km+LjDilkSN9P8Y3qp D56JgQBvwdeM4O1urmW5mzaNDpjA2xUK0iAvFdI2Q915ONoIUePtc+ImiXuuE7q6YfI46LoMzd3C Px58m3Msd139SwEq1jgWwBN4Nha+NQjOTQIP892Y7gur4mFPAyQWwaIo6L0KdW1w6WObBkYIUGmA wv2QPF0+ii09wkcHjh4mfDxkJ0K5AeILIT4MGjrhxhBkxkOE310EcDCTQwFCPBwHA2THwdcnxM+J s4/ZngkTPOC7RthaJwMti7aJsXmfLVyEL/i6wZ56cHGBKQFQnAbzJo8YxpyzIxPC/aC8HmpbINgH 3lgARUvucM4dBNDUh/QCQaNHfSSsVY+RU0D6XUMfTqvXVAFPAj8BmrO7ecBmAmLkD5F8bQPwPqB3 clMPykxAHp+qL0QAgJe0BCAfmAs85rze7qt1AD8CJZSpVoB/AGkNpwW+3O5vAAAAAElFTkSuQmCC }]; # +vulns_64x20_gold3.png set IMG(+vulns) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADfUlEQVRYheWYW2xUVRSGv9MZkIFO iQ/ICMGq0FAsdEgdtEwNUJrIpSVQ4UlgWkjQRCByCxnjpaTBVF9K0mI06gNGCCEB0xoCBZOmVVpS rnITgZooJdAGHoSmoTOTsn1YZzp7DgM5Y0yP4p+s7LP+vfbe/1pnnT1NUUohRqlSNClF9yD15Fm3 UhxWiqI4YSilIGrUAGH+XwgzXH1qqHuUAgedVuMABoBCN1HWOq3EIbiAzYa6SQ/wjNNqAHz50HMH LjTD1NwhObLLTeTfkXwSokBkSE6a4Caa3orqnTJ+tO6fV4Myxxikq+vvIoOoeZhNaz4upnP+RWBM hr0NCW5vg3D+ReJnThe/s1P8n8+L7wtqe8VhFsAXhEC57PVCsezxeiV0XU+s+fxbyJ0HnmkSv/ht uHbNfj4ZRCAte2Caxq1cILq/O5rgDhwRLrTQ5OJvN97e8YSVtpc1RsGZX2DVBzBxPHiegh+Ow8Ya me84De9sh1u3oaIMXs2DjvMwNtN+PrY+ga+/hzWfJHNGQMavwrC8BML1cLgN+nslj6Z2cGXIXKq3 S0wrgF4MPUYJ9eEqeL8SDrVD6RZoPyfzPT0S7vXAmjJ4ORcGBsDlspz5GNgqQMGLUFUhz7uaZKyc n5h7NgtKCuDoKTjSBkpBXz/MfwV8XouYePvFLJwOyx1QnC9+jk/8e33iF0+DKc/B5esQWA2z/VDz FszMs5U7AG47t21BthhAyxkZt72pBUQgNFcK0NAqBQDhBvc3OWW2990/Nd4SQ4ykTyJrmPiG5bPx uuBEHexshLpGaD0HczfA6c/gpWxb+ad/CaJItK1m5TMgcwR0XIZjFyHLA0sCiXmvRw78/Yb4rWc1 FY+4BB/yLV1zvxcyXRB+A377EmblQX/MfEk287HVATr2rDcfLOtGGrC0EHb/KH7FHPBocYU50HAS QrXgz4aWS+bCVB2gXYJJvl6UCBxohap98NoUeHoU/NolU1PHPazvUUj774DxXk2UBSuD8E2LPIeC yTE7VsDdPujohKs3Yfda2LYf7vRqcSkuwSTf0gE5Y2C0B/a1QYYBz4+B6mUwa1JqfalgqF10A2Pt hT9xuOImwimg1GklDuGkoeoJAscAw2k1Q4wokC//EKk1tgIfA26HRQ0VosC7bFJfSAEAaowAsBEo Amz+iv7n8AfwE7Cd99QVgL8AXhA5u32zJK0AAAAASUVORK5CYII= }]; # Quit_64x20_gold0.png set IMG(quit) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADN0lEQVRYheXYXWiWZRgH8N+zvc2Z c0ZK21r2YcWSDRMsEkeaax2ER2bYx8EKsyAyJG1hEUo1s+8POsgo8qARFIgSnhRoSlYwhbQm4Vqa lpguD2zN3HyfPR3c+3gd88DeZ71Uf7i57+t6rud//6/rfd7rft8nSpIE2BEtwKOYiQr/TRzDN2gx L/kSoiRJ2Batw6qCSvvnsUpD8mKUfGYBthRaTQEQY3ZG1iOFVlIgFGNlRmxWoZWMhtkr6TxK22tM qxyzbeozYpekxdZxhGc/Yuu3nOjm4jIaZrDmbmqqz4+r5zS9Z+jPIuZUL8ve4f5bmVublmJTo2Sj JA2mfYeZ8xS//0lZKVdXcOAY3acpH89Xz1N7+flxxjHFxWH9wXaa3uLdh1namIbigCIxaYwVG0Ly 9TX8sp49L4f55uuCf8WG4diye4kW0Xkk2Ht+DHblkuGYyiVkFtN+kNbPWfZeEPzg2yH2hY3p6M7I 5l/FntNs/S6sn7uTSSXIUl7CM4toWMu2dk71cOG4nBuzOQOSEWtBZG8vk8tCIRvrqL2MG6/Mic0D GXH+JD93EQ8Irq0il7O2KszZ/hBXU5Vz4+An0T/C52z7gblsauNgF3fdxNJbzhH7N5BKAXI5ov6z 7dzkMoOxSc61eET8SD2j8aWheUhTCmRTL6I4Ck9B+2HmTx++1n44zBcUU13uLPHJQPIne3LIRnkC Ri1aSkilCU7I0DiQ9OrNnOweSKyb1ZuC//Y6SouCf2Jp8P10PNg7vh9Qk5w74ZKiYPb25a839SYI r9zB1wfY2cmlzUybwsET9PQxqZRXFxpqWrOvYvNemt7n+mq2/5BDNFJPHHzTK9iENZ+wZS8NNTTf lr/u1I7BugraHueeWZSNY9/RkPyEEnY1c83k4djXFzL/2tDVO47T2kTt4K+90XpCzPJ5NNZwqo/d h8IJk4buKHnDr8bg7+9vf1D/Jh1dLJ7Jh00UF6W9S97YXyS2O83v1OCYMp5PH6JqIh/v4b5W+s+k v0+eY1eUvGQOdiJKq6z/EvRhRnghsi56AmsNHNX/A/RhuSeT9dHQK7GW6AY8hnpcUThtY4pD+AIt nk72w19tEruoqRtljQAAAABJRU5ErkJggg== }]; # Close_64x20_gold0.png set IMG(close) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADuUlEQVRYhd3Ye2jWZRQH8M875/I+ 3XROtpW3meKS5cxLygyxAhdhYWWCaFB/VISVZJuIWs5bRlgYXTC6GJQilF0MJEWbSV6WlZTTFC+b 6Fy0NMG17d3bH8+8LAzdKzrZFx44D+ec5znf85znPPx+kVgsBmyJFOAZ5KKn1olK7EaxsbHvIRKL xdgUWYzCFg3t+qPQuNjSSGyDAnzV0tG0AKIYmaje0y0dSQuhDWYmisq7VjukT6XyL/asIOeWa7XL VWF0oqi0eL2rTrFgDV/s4EQ1aV0ZM4jZkxoJN/ZX0cZx4yErMd7AjlczfBYVf9IhiYEZHK7ikxIK J2pKuMGNmgBxJ2Dm+4H8Hf34ZjapnYk2sLWMIVmaEm6sgLO1zF3N6m1UniIjhel3UTSRtonB9K0N vL6eI1Ukd2BENq9OJbsX1WeY8QFf7iISYdQAlk8PuvgTUN98p3/q+GxHkJdMJrU96kNXGTsgyGh6 BeqZspzPd5HaifyB/HiIeWs4eJwPn2T7AZ5aSZf2TMsPVbZ9Pz07Bv/H3mRdKffdTlYq725kwiL2 LKVdUrwJiKMCKqqoqQty3s0uX95RysoD+ZsS+WkhmSnhygx4gY9KmD+Ryupg3rkdT4wlr0+oqjYJ HDgWyGd0Y92zJCSEivj0B7buZXxO83kQZwLqai/ICVdyvxv4uTyIOZlkJgef3ikM6sUvFew+xN2D w3zvcYbNZeytLH6IUf3ZWxH8j1XTZlrT5Q+fvIIY/gdxJSAzmYQIDTF+LWdkv8s4REk8J8dcMtho PZ2T2DGHFZt441u27GPcEkrn0dDo07c7RQVNfcf0u/SaV4KE809UM0antuRnhwWK1nL6zAXd0ZPU 1DTOz/WABoZmBXFPBeVVQV9eFU4bcjM4ezasXXgvBxeGPWrq2fwbg9ODXdXfPJjL46PDmJzHwLTm czg34mqCsOwB8l9j834yZ5Gdxh9nOFrNoQX0Tr3IOEqfrkwdzqod5BWH3lF6lLooDw8lO5WPtzPv 63Ci3TpQ1picnHT6p/BIHqtLGbGIewZx4jTf/U7Vsvg4cBXP4LBMtj3P/PWUHGTPMXp0YlIuXZNc 8hl8bwp9Uli1k41lpHfhxfG8NCHos7uT3C6QTIiEHvFyAfl9g37lo/ToyNrdvFMSknT/bf/Zq5mI xJY7ofV+/l4O+xJF7ULBZU1bJ3ZGYq+4E1sRaelorjNqMST8EFkcmYWFLnqtWjlqMUNR7O3I+V9i xZFheA6jcWN+vF49jqAExebE9sG//2lXIs72RkMAAAAASUVORK5CYII= }]; # Close-TAB_80x20_gold0.png set IMG(closetab) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAFAAAAAUCAYAAAAa2LrXAAAFhElEQVRYhe3YfZCVVR0H8M/dvQsI C6wLLhQLCbSbxIvLS4Cxsygy6kSDxEiSRMJUf4QVmgMtyEDlghRMg42lNpaBUaFNiZYkk6Du8raB b0AsWPK6w8umK4awwN69/XHuwu7l3pUpR4ZpvzNnnt9zfr/z/L7n+/zOOc88kXg8DrwUGYdvoQjd tCIVjuJVlBkd3wCReDzOusgDKL2k1C4/lBoT/2EkvtY4/OlSs7kMEcPIqHp3XWomlykycW9UzND/ 5Sndp3L0XbY/xIBPfEjULh+MiorJaymi5jj3P8kzlRypJS+H4n7MvS0hWOIMEku0jxDFpWyoSu0b UcDmJefvFz7FvJXBLpvCfZOax4+dzwtvBDszg64dKenP0un0uiothZ7RliZ9uJbhszn0Du3bcE0P 9tXw23JKJ2guWIOPXMBBiYpvaGDTnmCPLCAzk/49m/NZsY620fP2fROTHpYohE/n07UTr7zFUxup fpsNi9JzaFHAex8P4n2mL2vm0qUjsQYqqhiURLCxAk+dYf4qVm3k6HF65DLteuZMICsxgYfX8uBz 7K+hc/tQLUunUvAxak8w81c8u5VIhOsKWTYt+JLxs6+G64k6On4l2GvmktOhCSdB3D2Hufla4nHW vsHmXYwsvFDAWeMD3/U7GPMDKt8kXh+4pEKGelK106f4Y2UIWjyZLleE/swGRhc2iW26hOu5YxlL n+XkaUqu4fj7LHiSrz0c/FuqmPFYqO47SxjRly176NYh+Kf/lCdepvhTTL6O51/jc4uoO5ma57nW iBS+5euDa/xgJg4L9vL1SXFN5lF/mp37w21BdyKx9HnTVuChGurOBntoLx+8PGNUHeTprWGpvLaQ /Nyw5AtnsaKc703gaG0I79iOr49maO9Q1ZkZ/KOa1dvocSWr7yYjI1Tk7zZTsYuxA9LnbmY3uT99 llWbiODWwUQzmfF46Fs2hbZZicCEgNMfDQ16X8VvZrQ894xzCZPa2TNNghpSxyTvga/vC+aAfPI7 B//VufRLLL9X93JDYbivrmXYfK4vC8tEjF2HQlx1LZl3EpkaxIN9x1rgkErARHtmK++eZHgfenSm WzajCqg9GXzJ4wf34vPX8vEc9tbw/T+0nDdtBeZ3JiNCQ5ydBxnZN/1baCQebbTjSZNqDKmnYxsq 5/HQOn7yV17azZjFbFtAQ2JMn67MGdd8bHHf1M9szH0OSYfZ8opw3fIWkWnNh62oYFLjR1yiAr99 I9OKqX2fvLt5+hW272dgfurUaQXMzqKkgBf3MOf3rL6LTlcE34G3yetEu6zziTUwpGcwtx/iYA09 czn4DrsOh/6iHpw6RXYbSm9m5g3c8iAvv8mLf+em/iGu5t9MLCI3cRicqCO7nYsTsElFHX2P53cE e0Tv8yHxOJX7+MsOjtWGuZybR+Ll19WFrYXw4tPljjbbgJOw5AuU/DiImD+bgjz+dYIDtey9n6u7 NCfeO4epw3mikqFlYe/cdoCzMb44hIIu/HoLC/4cKurK9lQlxB3QnU/mcvtQVm1jxCJu6seR94LA NUtSUgxIdYhg5UbqGwKPzbOaDylayOvVrNzEPTeeF3Dxc/yynJ2HQ1dhHv3zknI0Qdo9UIxh+Wz8 DrcOJCuT7dXUx7itiJw2Ur75X9zB/FvIbssLVbSL8t2xrPhy8Bd0pXO7INLPK+jSgUdup6RP8D/2 Jb5ZEqru0fIg3viB6TmKCcs2iYcYyxP75+QhF46Z0ngab070JQTcfYzyfxLNYNJg1nyDLBeOb2yR +DJHtP6++m+xOypmK8Z9YGgrUuFvkfiPfBYVwqdSKy4eZzAo/FB9IDIbCzX5EmlFiziDmebEH4mc +6VfFhmGezAK/38/pi4O+1GOMvPiu+E/eQgzyYvpN84AAAAASUVORK5CYII= }]; # Filter_64x20_gray.png set IMG(filter) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADbUlEQVRYhd2XzUuqaRTAf6ZQaNgH dieCsUAkCArpC0FsIdSiQMp2geCicDEMYwQS5SKoKS4EbQfqTxAji0CEJKbaNDAEFd1F0SykGbLS RVb2Pr6zUq7dpgatXri/3XkO5zznPOcDHpUsywDc3NwMAD8DFuAHvk/+Af4E5mpqanYBVLIsk0gk FoBJRUP7eCYNBsNn1cXFxQCwoXQ0CiAAq0YI8ZPSkSiEGpjQSJLU8R7eBwcHOT8/JxwOYzQa6ezs JJFIEIlEaG5ufo8ri8GmEUJ8KsbS7Xazt7f3zfny8jIOh4N0Ok0mk+Hx8REhBLllK4RACMHd3R0z MzMMDw/T3d1dWhrF86NGCFGUZS4hs9mMwWDIn1dVVSGEYGNjAyEEarWar+/IZrMIIdjc3CQYDGKx WOjoeJcm/F9oJEkqyjD3AF6vl/7+/gKdJEnY7Xaurq5YW1vDbDbndUIIQqEQs7OzAAQCAQKBAOPj 44yNjZFKpVhYWCAWi6FSqbBYLExOTtLU1ASA3W7HaDTi8/mYnp6mra2NxcXFonIAKLkDchX9L3It /7X88PBAdXU1t7e3WK1WTCYTLS0tCCGYmpoiFovR09NDfX09wWAQr9fL6uoq5eXlABwdHeHz+Ugm k9hsthfvf42SO8Dv9+P3+/Pnu7u7aLXagpmXJKlAdjqdRKNR4vE4vb29uFwuAM7OzojFYtTV1bG0 tERZWRmpVIpIJML+/j5WqxVZlslkMlitVubn59HpdBSbA7xBB5hMJmprawt0Tyv+kizLcl4+PT0F 4PLy8pu9EI/HC+zcbjcVFRUlVR/e4AE8Hg99fX0FuueW3lP5uRHKVbKhoQGPx1Pgs7W1tcCPTqcr OXl4gxHIZrPPtuBLIyBJEmq1GoD7+/u8fWNjIwDJZBK73Y5erwcgnU6j1Wqf9VMqiixBIQRGoxGA lZUVdnZ2aG9vZ2RkBIfDwdbWFqOjo3R1dXF9fc3BwQHr6+sv+i2WkjvgtUo81efkoaEhjo+POTw8 5OTkBJvNhiRJTExMoNfr2d7eJhwOU1lZmde95LdYVNFo9G++3+/va3zRCCH+AAaUjkQh9jWSJM0D /YBK6Wg+mAwwp5JlmXA47Ad+BTQKB/VRZIBfnE7nb6rcMguFQp3AOGADGhUM7j35C/gdmHO5XF8A /gUyOhcgd06AqQAAAABJRU5ErkJggg== }]; # Reset_64x20_gray.png set IMG(reset) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAAEJUlEQVRYhd2XXUibVxjHfzEBw9tG DLWzla6JDW2hVBE/glbsRWp7MUVL6lWs0IZARB1Dp6OUCpZ2W3cleNNdWLTtRQkGBR2FEEygc73R WuOFYEilitaMtNbiR2N5z5tdJawb02m2BvqD5+q8/8P/ec7znMOrisViALx9+7YK+BooALL5PPkd eA7c1uv1vwGoYrEYr1+//hG4llJrn55rWVlZP6mWl5ergF9S7SYFCKBUI4RoTrWTFKEGvtXIslyU aicppFwjhPhit6qGhgaePn0KgFqtJjs7m8rKSjo6OpAk6T93+Vfev39PV1cXly5dwmw2J7PVlxoh xK5V8ZfDZDKxf/9+ZmZmePDgAevr69y5cycZQ/+Kx48f43a7KSgooKgouQZOk2WZ3Ua8AHa7nUeP HtHT0wPAkydPEt+8efOG9vZ2ioqKKC4uxuFwEAqFEusPHz7kwoULnD59mrKyMpxOZ2J9O+3g4CA3 b94E4MaNG5w4cYK7d+/uOod4JNUBiqKwtrZGIBAAIDMzk/h+169fx+/3c/bsWQ4dOoTb7cbpdDI0 NMTs7Cy3bt1i37591NbWEolEmJ6eRq/XI4TYVru1tUVmZiYbGxuUlpZiMpk4deoUe8kDQCPL8p4L 0NnZSWdnJwBarZa2tjZkWWZhYQG/38/Bgwfp7u4mLS2Nd+/e4fF4GB8fJxqNAiBJEhcvXkwkoFar mZub21ZbU1OD1+tlaWmJ8+fPY7VaAdhLHkByHWAymdja2mJxcZHm5mbMZjNCCF68eAFAJBL524zG jRuNRl6+fEl9fT2FhYW0tLSQn5+/o/bPfmOx2J5PPk5SBbDZbJw8eZLLly/T399PdXU1kiQlTiMn J4crV658pM3Ly0Or1dLX18fAwAAul4vJyUkaGxu5f//+jlohxEcjmHQBkhkBIQS5ubmcO3eO0dFR ent7aWpqwmAwALC6ukpFRQUZGRkAbG5uIkkSGxsbpKenU19fT11dHa2trQQCASYmJhLP2j9pZVlG rVYDEI1G99z6iQIkewkKIbh69Sp+vx+Xy0VVVRVHjhzBYrHg8/lwOByUlJSwsrJCIBBgZGQEn8/H vXv3yM/PR6fTMT8/D4DBYODw4cPbagGOHj0KQG9vL2NjYxQWFmKz2fZUAHVDQ0OXoijsJjweD+Fw mDNnznDs2DF0Oh3hcJhgMMji4iIWi4WSkhI2NzcJhUJMT0+zsrJCeXk5ZWVlRKNRnj17xtTUFMFg kAMHDmC326moqEBRlG21iqJgNBoJhUK8evWK1dVVzGYzx48f31UO8VB5vd4wn+/v707MaoQQE0BV qp2kiHGNLMs/AF8BqlS7+cR8AG6rYrEYw8PD3wHfA5oUm/pUfAC+qamp+VkVv9EHBweLgVagHDCk 0Nz/yTzwK3DbarXOAvwBorXCf/voWY8AAAAASUVORK5CYII= }]; # Color-Chooser_168x20_gray.png set IMG(tkcolor) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAIAAAAAUCAYAAABFyTWeAAAFtklEQVRoge2ZbUiTax/Af7epLddC 05pblsNGQri1nJEgBvYh4gxaL18CCZSyJY+ns4fsQapvmXIg6EMLDkFY9CGG0IftQPjCJOrQB0t7 oUjULHD2OGc5yoxxX9vzaT4tffKeO6c9nPaDG8b2/1/X73/d1677ujYpGo0C8P79exvwM2ABtKT5 OzIJDAKteXl5fwBI0WiUYDDYDrSkVC3N96aloKDgV+nt27c24PdU26T57gigMlMI8Y9Um6RJCSuA U5myLFtTbQJQUVFBMBikq6uL0tLSH67/FFGVKYRYn2wr09PTuFwuent7CQaD5OfnU1FRQWNjo+LB jG1GhRAIIZJVStjxr+7//5SNmckWGwgEOHToEJOTk6hUKkpKShgfH8fr9dLQ0JDwYEYikT/9BiTq +ANNADJlWU6qgba2NiYnJykrK+Pq1avk5uYihGBgYACj0Ygsy3z+/JnLly9z584dpqenWb9+PQcO HKChoYGsrKy49oQQinOqq6vZtGkTTqeTs2fPYjabuXjx4rIcY/T39+NwOAgGg1gsFlpbW9HpdACK nJTE3Lp1i5s3bzIxMYFGo8FsNnP69GkMBgOhUIj29nb6+vqQJAmLxUJLSwsGgyGhmpWSEVvylnPN zc3R29sLgNPpRKPRzH97ysvL5+Oam5vp6Ohgbm4Oq9XKhw8fcLlcnDt3bsGSm2jO8+fPcTqd+P3+ +f6X4xjjwoUL6PV6Vq5cyYMHD2hvb0/IaamYwcFBzp8/z9TUFHa7HZPJxNOnT8nLy0MIwZkzZ/B4 PGzfvp29e/dy//59HA4Hnz59UlxzIldSK4Df7yccDgOwZcsWFmtrbGwMn89HVlYWbrcbrVbLxMQE drsdr9eLw+Fgw4YNcc/g4eFhxTnhcJjKykra2tpQq9ULHJQ4wn/3IEePHuX48ePcu3ePkydP8vjx Y2RZVlRHOBxeMiYQCACQk5PD/v372bp1K0IIVqxYwatXr+jr62PdunVcunSJjIwMQqEQXV1d9Pf3 U1lZqajmREhqDxAb2NgALtbWy5cvAdi8eTMFBQUIIdBqtRgMBkZGRnjx4gWFhYXz8bEJkEjOkSNH UKlUi/avxPFLrFYrQgiKiooA+PjxI0IIRXXEbsS3Ynbu3InBYOD169fU1tZSXl5OU1MTZrOZ0dFR AKamprBa4w9nfr8/zv1bNSdCUhMgPz8fSZKIRqMMDw9jMpkWxEiSNP96sb5kWY57PxKJJJyjVqv/ 50AocfySnJwchBBEIpE4ByVOSmJUKhUdHR10dnbidrsZGBjgxIkT3LhxY34C6fV66urq4nJNJpPi mhMhQ5ZllntlZ2djsVgAuHLlCqFQaP6z8fFxZmdnMRqNAIyMjOD3+5FlGb/fz9jYGAAlJSXIshz3 CFhOTjKOi7X15eDKsqzISUnM7Ows2dnZ1NbW0tnZybZt2wiHwzx8+JDi4mIAZmZmqK6uxmazYbPZ qKmpoaioSHHNiVxJHwMbGxtpampicHAQu93Oxo0bmZmZIRAI4Ha70el07Nmzh+7uburr6yktLWVo aAghBDU1Nej1+gWbQK1Wm3DOt+pQ4vh1W8txApaM6e7u5tq1a5jNZjQaDW/evAGguLgYnU7H7t27 8fl8HDt2jB07dvDu3TuePHmC1+uNq+nP+r0i6WOg0WjE5XJx/fp1nj17xujoKLm5uezatYtVq1Yh yzLNzc1otVp6enp49OgRa9eu5fDhw9TV1S3YwMRm9nJyknH8uq2vVwBAkdNSMTqdDrVajc/nQ5Ik CgsLqa+vp6ysDFmWOXXqFGvWrOHu3bt4PB5Wr15NVVVVwjUrRerp6fk36b9/f1SGMoUQDwFbqk3S pIT+TFmW24CfAGmp6DR/K8JAqxSNRvF4PP8CLgCZKZZK830IA7/s27fvNyl2rLh9+3YF8E+gCihO oVyav443wD2g9eDBg0MA/wGqWH5yIUV0vwAAAABJRU5ErkJggg== }]; # Font-Chooser_168x20_gray.png set IMG(tkfont) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAIAAAAAUCAYAAABFyTWeAAAGl0lEQVRoge2ZXUhUaxfHfzs1PyZt 1KmtljaYJYQOk1oNiEFCEgWa2kUkgpI6yevbUTIR8yLQlCDwIoNDH1h0EVJ0MR4KP1AiqwvLyT5E SbOgsUbHVCqtYW/nXBxmaBq/Du/U8J7jHzYMz/o/z/qvZ6+9nrX3CDabDYDJyckDwH8BLSCygn8i zIARqA0ODn4AINhsNiwWSz1Q6VFpK/jVqFSpVGeF9+/fHwD+8LSaFfxyyIDOW5bl/3hayQo8Ai/g hLckSYmeVuIpJCUlYbFYaG1tJTY21tNyPIFkb1mW17tjpdzcXB4+fOgyfunSJVJTU93hAoDZ2VlO nz5NdnY2O3fuXJQ7MTFBY2MjHR0dWCwWQkNDSUpKori4mNjYWOwNsCzLyLLsNo3/R4j0dlfg9s3c smULKpXKMb527Vq3bu6dO3e4desWWq2WxMSFi9fY2BjZ2dmYzWb8/PyIjo7m3bt3tLS0UFhY6KLp X5oAeEuS5JaF7Amg1+vZv3+/k02SJL5+/cr58+e5e/cuExMTrF+/nszMTAoLC/Hx8QEgJSUFURTJ z8+noaGByclJtFottbW1hIeHYzAYqKmpAaC6uprq6mrKysooLCx00VNXV4fZbCYuLo6LFy+iVCqR ZZne3l5iYmL4Pu6enh70ej0Wi8XJH7As3cvh3Lhxg+vXrzM6OkpgYCAajYaTJ0+iVquZnp6mvr6e rq4uBEFAq9VSWVmJWq127EtUVBSlpaWcOnUKjUbDuXPn3HLfVtnL3/962RNgbm5uXnt5eTlNTU3M zs6SmJjIp0+faGxspLq62qkE9/f3U1VVRWRkJL6+vjx69Ij6+npkWebbt28olUoAdDodOTk5bNu2 zcXX7OwsHR0dAJSWlhIYGOhYPyEhwaXknzlzhoiICBd/y9W9FMdoNFJTU8P4+DgZGRnEx8fz7Nkz goODkWWZqqoqDAYD27dvZ9++fXR3d6PX65mZmXHofPnyJaWlpZhMJkc87rjcXgEqKiqoqKhwjD94 8ACz2UxnZyc+Pj40NzcjiiKjo6NkZGTQ0tKCXq9nw4YNjjWKioooKCjg/v37HD9+nKdPnyJJEunp 6bS3t2Mymdi7dy9ZWVkA/BiDyWTCarUCsHXrVhf7j5qPHj1KUVGRi7+RkZEldVut1iU5Y2NjAAQE BHDw4EFH0np5efH69Wu6urpYt24dDQ0NrFq1iunpaVpbW+np6UGn02Gz2bBareh0Ourq6lAoFAvG 9Hfh9h5g8+bNhISEONkGBgYcNpVKhSzLiKKIWq1maGiI/v5+wsLCHHz7U7px40YAPn/+7HJG22y2 Bc9t+81fimdHYmLivP6Wo9t+Ixbj7Nq1C7VazZs3b8jJySEhIYGSkhI0Gg3Dw8MAjI+Pu/Q0JpPJ SXtubi5+fn5u7VfcngB5eXmkpaU52QRBcPyez58kSU7j/v7+yLLM3Nycy7wfj5r5EBoaiiAI2Gw2 Xr16RXx8/KLaAwIC5vW3HN3L4fj5+dHU1MTNmzdpbm6mt7eXY8eOce3aNUcCRUREkJeX5zQ3Pj7e aU2FQuH2ZtXtR8Dc3JxLeYqJiQFgaGgIk8mEKIqYzWZGRkYAiI6ORpIkp9eyH5PCvqaXlxfwV+O1 kPbVq1ej1WoxGo1cuHCBs2fPolAoAPjw4QPBwcH4+vou6W85uu16FuN8+fIFX19fcnJyOHToEGVl ZfT19fH48WPHq+zU1BQpKSkEBQUBMDMzQ0BAwLz74k64vQLM92SKokhaWhptbW3k5+cTGxvL4OAg siyzZ88eIiIinOZ836R8PwYQFRUFwOXLl+nu7iYhIYEjR4646CkuLqakpASj0UhGRgaRkZFMTU0x NjZGc3Ozo8tfzN9ydANLctra2rhy5QoajYbAwEDevn0LwKZNmwgPDyc1NZXOzk4KCgrYsWMHHz9+ pK+vj5aWFqeYfsb3CrdXgIWytLy8HFEUaW9v58mTJ4SEhHD48GHy8vJc+ItVgMzMTPr7+3nx4gUD AwMkJyfP6y8mJobGxkauXr3K8+fPGR4eRqlUsnv3bvz9/Z3mLOZvObqX4oSHh6NQKOjs7EQQBMLC wsjPzycuLg5Jkjhx4gRBQUHcu3cPg8HAmjVr5o3rZ1QAob29/QMrf//+WzHoLcvyY+CAp5WswCPo 8ZYkqQ7YDwhLsVfwj4IVqBVsNhsGg6ECOAN4e1jUCn4NrMBv6enpvwv25u327dtJQBmQDGzyoLgV /Dy8Be4DtVlZWYMAfwJ2T7adbHyCXAAAAABJRU5ErkJggg== }]; # lt_30x20_gray.png set IMG(help_prev) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAABmUlEQVRIib2WMYsaQRiGnyVT2ghL UmkQxDqQCIGD7Y3ggv6MEI4QkMNSTEJALMVfoJ3gIv6BIKxESGVxlW4hciIIWwiG+ZhUF64Jccyy T/9+z3wwLzOOMQaA4/FYBT4Ar4AXJMsD8BPoZLPZOYBjjOFwOHwF7hKW/Y0713W/ObvdrgpMU5IC CPBWicj7FKUAz4BPSmv9OmUxwI0Skef/M0FEmEwmuK6L53mXxnJKRK4WBkFAv98niiK63S42s5TW 2lo4nU4ZDAZEUYTnebTbbcrlMjazrDZerVY0m0222y2VSoVer0epVPpzIBusNo7jmDiOATidTuz3 ewqFAo7jWEkBnOVyaWwC5/OZ2WzGcDhkvV6Tz+dpNBr4vk8mk7lcvFgsrMRPCcOQ0WhEGIa0Wi18 379cPJ/PrxY/stls0FpTLBYvzlxdp6fkcjnA7oJZ1ykplIg8kPwz+C/ulYgsgWrK4h9Ka/0FeAfY l/E6fgEdxxhDEARN4DOgUpDe1mq1gfP49RmPx2+Aj8AN8DJhYQR8Bzr1ev0e4DdlibkO9rUO5QAA AABJRU5ErkJggg== }]; # gt_30x20_gray.png set IMG(help_next) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAABq0lEQVRIib2WPYsaURSGn4kj1oIk hYRBW5uFTTGwtY2Kgr9CCMsSxDA/wCTExnYb8Q+ooAQEywlWBlIIworN2sjKiKBiIXO4qTaQsCFz d2VeONU9533uuR/cayilANhut3ngGrgA3nBePQA/gXo8Hh8DGEopPM/7Ajhnhv1LTiKR+GqsVqs8 8C0kKIAAtiki70OEAkSAqun7/mXIYIArU0ReB812XRfP8yiVSkQikZeA374SEYLGZrOhVquRzWbp dDqcTqfAtX+HMZvNlM5UJ5MJrVYL13WxLItKpUKhUNBeAWM6nWqBHzWfz2m32wyHQ5LJJI1Gg0wm E7je9H1fG6qUYr1eczweAdjtduz3e3S8TBEJnHw4HOj3+3S7XZbLJel0GsdxyOVyxGIxdLy0wKPR iGaziW3bVKtVbNv+PabjA2CMx+PAe7xYLIhGo1iWpQV5Slodp1IpQL+7J8HPOVznkCkiD5z/Gfyf 7kwR+QHkQwZPTN/3PwM5wAgJegLqhlKKwWDwEfgEmCFAb4rF4q3x+PXp9XrvgA/AFfDy+/Kn7oHv QL1cLt8B/ALZR/jn5MwXRgAAAABJRU5ErkJggg== }]; # gtgt_30x20_gray.png set IMG(helpsearch) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAB4AAAAUCAYAAACaq43EAAABvklEQVRIib2WMavaUBhAT5qIg5Mg 7SBFUJxcCi0SeLOLgoKbP0FKKUUsb+xgW+ri2kX8AyooguCY4vSEDk5PRKiLPIkIKg6Sm9vpdSgv iRabA990SA433MuNIqUEYLvd5oB3wCvgBdflAfgJ1MLh8BhAkVJimuZX4PbKMSduI5HIN2W1WuWA gU9RAAHomhDirY9RABWoaJZlvfY5DHCjCSGeO1nDMDBNk0KhgKqqF3sXXj4TQuA0m82GarVKJpOh 3W5zOp0u8m6jlsvlT7Zt89Qkk0nS6TSLxYJms8lgMCAUCpFIJAA8vdN7bdtGmU6n8pxvM5vNaLVa DIdDotEo9XqdVCp1tv8bzbIsz6iUkvV6zfF4BGC327Hf73l81ss/hTKZTBxXfDgc6PV6dDodlssl 8XicUqlENpslGAx6ejc0IYSjHI1GNBoNdF2nUqmg6/ofJ4Tw9G4o4/HYccXz+ZxAIEAsFvsn7xo2 DOOszXVtztpc/yUshHjg+tegF/eaEGIC5HwO32mWZX0BsoDiU/QE1BQpJf1+/yPwGdB8iL7P5/Pf lcdfn263+wb4ANwAl58Pd34BP4BasVi8B/gNJINTCcG8NKcAAAAASUVORK5CYII= }]; # Load_64x20_green.png set IMG(load) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADHUlEQVRYheXWbWiVZRgH8N/xnGml SVNz1XS60lH2Mtv8IEliEBEM6lMlVrCixDAQEdK+9AK9GGQfIiiCqCUJtQwJpRClDyVbqHM6UUcz deo8a3O5junyZXcf7rNOhEXrTM+qP9xcPNd1X//nf1/3fd3PI4QgDjUh+DIE6d9c/72RDsEXIZgz 4EiEEGQkXsUK/y+suFJ4LdER1GB9odUUAOcxO5VhcaGVFAhJLEtlqC60ksGgbTfzb2VcCRvTedPN SWWY+E+zl91N02aWv8+9tXmL+Vs4lbUBmfzpJqdO5pF9Pmv7kA/PYNCXjDYM0TtT+VTxXNb2ufBu nDlN/XM0fExvJ+NKmVvL/c+SKopzGuvZsIqOvYxIMWMetW9RfG2Md+7n3Sf4riHm35f9VvX/yTsH i7wK8PsTcCGetxfQvI7R45k+l/Ym1j7P0f08VhfndB/n515mzad9B1s/41yCRZ/G+JsPc+Bbxkxg bCl1S6J/iFrg4p2AH/bFxSdHsbSZqybRc5CVFTR+yF0vML6cmQupWhRz0nt4/WbatkS+Yy1x8cmR LNlOcRlNH7HmkSEswMW6A77fGe3EW0hNivGRU7n6Jjp3sX8Ho8rZs46GN+jeR9+JLF8mzj/SFp9L Kikqi77Se6JvWNwBf9UCv6Si/WOvDuScOs+B3XzyQOz9eau4YiLrH8rt7uns3JDMcfRl745h3wKj q6LtauHYYcZM5uRhevZm4zM51Ih+xs9k2tN0fJXLz6Do+izHLrq6uWwC7Vuib1gUYGA3m1ay54Oc f+oCpi1k6qMcXM3aasZV07Od/rOUPciI6SSzPzLHm9n0JJ2bSBTlFjeykuIqfmyi/naKK+luiDnD ogADJyDTGscAxs6O4ma8R1E5R1aT3syoa7hhORUvxvjldzJlMUfqOLqBG1+h83O6NuYWV7mGnY9z Yhu9bVTV0/IUZ3uHpgCJeUEaJUPA9W9EayrDNtQUWkmBsDVREdyBb5AotJpLjDO4LRFCcJ3EM3gZ qQKLulQ4gyUdwjuJEAIYKzELSzEHUwoo7mLiEL7GSz8JrfArU1DPntC9igEAAAAASUVORK5CYII= }]; # Save_64x20_gray.png set IMG(save1) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAAEUUlEQVRYhd2XXUhUaRiAnznnKP5k NGMzMuZiXeSFYCrNpKNG5NXMDlpIN14ICUJULLIs6qQEK7Y7LN4q7oVEN90OYRvMTKKRLgyoSdpN NqOJpi7W/CgOMp7PsxehS1cLHXOgB96r7/ve7zkv398xaJoGQCwWcwM/ARVAAd8n/wCzwAOj0fg3 gEHTND5+/OgFPGlVO348p0+f/sOwvr7uBv5Kt00aEEC1IoS4m26TNCEDvyiqql5Mt0kaqVWEEBa9 WdbW1ujv7ycUCpFIJLBardTU1HD79m0KCwuPQvRb8YNhYWFB05Nhf38ft9tNJBLBYrFgMplYXl5G CMHExARGo/GoZL8JiqqquhIsLS0RiUQ4deoUwWCQzMxM9vb2CIfD5OXloaoqfr+fR48eEYlEUBQF u93O/fv3MZvNXL9+nYWFBfr7+3G73QA8e/aMjo4OSkpKePLkCYlEAq/Xy/j4OAaDgYqKCjweD2fP ntVdAEkIgZ7IysoCIJFI4PP5SKVSSJJESUnJYZ9oNMr29jYul4uioiJGR0fp6+tDCEFDQwMAwWDw sH8gEACgoaEBIQTd3d2MjIxQWVmJ0+lkcnKSW7dukUwmdbkLITDMzs7q2gIAw8PDDA4OAmC1Wmlr a6OxsRFFUYDP20SSJAAikQg3btwgPz+f0dFRNjc3cTqdZGZm8uLFCzRN4+rVq6RSKQKBAMlkkmvX rmE2m/H7/UiShMfjIRAIMDQ0RHV1tS53RQih7+uB1tZWSktLefjwITMzM/T19eH3+xkYGECWZcbG xnj8+DHv379ne3sbgJ2dHYQQmEwmLl26RCgUYnJyEoDd3V0cDgdGo5H5+XkANjc3uXjxywvrw4cP 6PU/kgIA2Gw2bDYbr169orOzk6mpKV6+fMmZM2fo6upClmXa29sxmUz09PQAHMq7XC5CoRDj4+Mc PM1dLhdCCA7OqMLCQm7evPnFnGVlZfoLoPcQXFxcJJFIUF5ejiRJXLhwgXPnzjE3N0c8HmdrawtN 0zh//jxNTU3MzMwcjj2Yu66ujuzsbN68eYOqquTk5FBXV4eqqhQXFwMQj8e5fPkyJ0+eBCCZTJKT k4Nef90rIBwO09vbS25uLkVFRezs7LC6usqJEyew2+2srKwA8O7dO7xeL9PT08iyDPy3AjIyMrhy 5QrBYBAAp9OJoigIIbBardTX1zM2NkZbWxt2u51oNMrr1695+vSpLncAuaWl5df9/X2+NiRJ4tOn T8RiMdbX15FlmaqqKu7du0dBQQEWi4V4PM7S0hIbGxu0trYCnx9Pzc3Nh3mys7MJBAJomsadO3ew WCyHbXa7nWQySTgcZm5ujmg0Sm1tLQ6H46u9D8Lw/PnzDb7f39//460ihJgG3Ok2SRNTiqqqvwM/ AoZ02xwzKeCBQdM0RkZGOoHfACXNUsdFCmhvbGz803Bw7/p8PhvwM1ALFKdR7luyDEwAD5qamt4C /As1gqIY0l9fZQAAAABJRU5ErkJggg== }]; # Save_64x20_green.png set IMG(save) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAADlElEQVRYheXVXWiWZRgH8N+7vbpN 9/qt+cHU5qTAUkFrLs0iLTQxsw/UYJYHKWEhIYStDoSS8EDrQKI6CEUpRRRBw8xKU0MjIy0zl/N7 stf82OZmrem8O7hdw1Nf7aX8P1xwX899ffyv+76u5xFCEEIgmCT4XJAW/rdPWrBZMLq17kQIQSeJ d7DA7YUFF4XFib7BJGzKNpssoAWjkoXMzTaTLCEX85MpRmSbSRYxOpmiV6ZRmk5ytIK6bVypJa+I ro/Qv4L8opvB85ahKDE5CJlECFfZfi+NB8nrS15PLlURWni0mvbdbxbXW4NkYYYBLh6OxbfvwZSj 5OZx9TL1v9D1WvEn13JoCfW/kpOk18OMXEZBHzYPo+4nyj5h4Ixof/xTdj9Hl6FM3E9zLT/M4/RG JOhRxoj3SA3OkDxyUshEuqQiqeYL1KygYwud29F/eJtN4jwt9ZRMp/Mgqtez/5W4d1d5JJJe32af Xhff3T0z6ntncXwlfcYweDrpLex4nIKmzLinkJif4QjAnkV8+2ZcdxpIaQX3zIq3TRyTRE5cnz/I 8iF06M1LNTTW8FERufnMPUcIvN+TlibmVNPcyMeDKezH7JMxzqYZVK7mma0MGJ8Z92QqM3/w6BsU l7JzEce3s3U2VWso30JOLgc3sHsp5w7RVBd9Ljdcu4U+FI/jyBec2RIP4MolSibQuzeVG6N942mW 5l6f96/jMUYmyPgb0Iph46Mc+YblUzn2Fac+o1sxa5+N3TB5CYW9WDWNBFpzl86MB1C1gdZ+LJ0Z 9/OuRr1bMeNevz7nnWPaYtwoMu6A0we4dJ6SB8nJYfhD9BtC1S5CLRd+jCNQNJyJL1O5rc23NXfZ VNYVUv0dLc3kd2LUk7THoCHR5tJZyp6iY7eoNzWSfxNuL+MDuHCAZTMo6EzvwfxZT/owHbpQOoGa 36LdqX2sfpGfvyS3XeyAf3J34P6n2bUqqmOfp3tBXKdKGDWNPWtYXMrQx6hLc2gHH57NkDxyX1ho YR5uVPLbUVtD/RnOHiPZjhETmb+SooH0G8DFc5w4wPkTlL8V5zx9hPKKtjgdU3y9AoE570bf1r37 JvBHA8f2xcIbfqf0CcZOuXHerZLYFqRxR+Zn+Z9EZTLFXkzKNpMs4ftEZfAAdoljeTuhGUMTIQQ1 Eq9hEZJZJvVvoRnz+ggfJEKIP94GiZF4FaMxIIvkbiVOYCfeTgmV8De7v5MByjb9UQAAAABJRU5E rkJggg== }]; # STDOUT_64x20_green.png set IMG(stdout) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAEAAAAAUCAYAAAA9djs/AAAFi0lEQVRYheWWaWwUZRjHf7NXt7s7 PWhtYesW5CjCtkADpIVWEKgJWoQgiRGEgEf0gzFEjsphEAREA2jiQSThA0eUmKCRcB8FaoEaOQpN oS1XC4UeQtl2Z9st7e6+fth2d3bByhfdBP7JJLvPPPM8v/nP874zCCEQQoAQ+QhxECEa6A4+eUcD QhxAiJzukCSEIAZlHbCEp0tLnMhfSlZRlw/sjTRNBOQFsnUWlA8iTRIhaYGFOhllZKRJIqgcnYyS FB5tv9XIjWVbaD5eisehEGVLIn5iJqnLZnN55mqcp8ofWU3OGsLIPzZxIW8hzYXnAZD0WqJSEumV P4a+y2cT1Sch5Jq2K7XUfLad5sJzdDY50fWKIX5iJv0+nYtpcGog78yId2m9eJ30PZ+TOGVMIH5v bwnlry7DPHwAoy9s4Xzuh//Kp5JNJ+MKSRI+H2dfXozrci1R1l5Y0qy0XqunYetBMta8QfwwG1q8 4BM4SioBiMsejKTVINtTkXGhwwuAZagNfbwFpfwmdd//RtMvJ8gt2YCpXzIAyqWbnB+7GI/TjdZi RB5qo/VGI3/tPMb9fSXknl6PbO8L4O8JmHCjZm7DHTgv43osPrV0FpSQgPNqHa7LtRgSZabd+Bpt lB5fp4eWS7eJT5AYu2kOAJ2udnbJbwMw6cAiDHHmrgoKWjwA2Be/Qv954+l0tlE0dSN3iyqonL+J cbsX+Z/qgs14nG4Sc9IYv68AQ6zJnztlPXeLq6hcsJkJh5YCoMEHgBE3auaWLgM0+LCgPBZfiAFy WEAje0GCjvsu6rcdZvA7uWj0GmJHJIRc3El74LcFF1FdgOqnZaQdGQViIHt1PnvGVVC3/wLG1nsA NBb6RzV79RQSYr3++jGQtSqfvROraDx2iei2JnQmQ8CAaNyomaNVBsiPydejAbJVS87qyZz65CDF 7//IxXX7yVo2ifS3RqPRaQN5HTwIaWDsumkAXdcEBAwA9OkxAAiPD27fRggQXgGAzS5jUnHY7HIg V9TWIg9OCpj6Twb4l0Aw3hNfmAGuh4IvLc+mf9YzFK8tpuZEDUfe28W1n88x59AcNFoNAA/CGkSr GoROgL++xtMazNe68XmCT8QitWFGCvyXCOaaaUPGFTYBQebQCQjGe+ILMSB8D+jW8LwkhufN4HpR LVun76a6sJrafRexTx0IgJ6OsAaeRxrQXf9OaY2/oVFLik2D1yMhaSWEV6CU15A8Ibjj15ff8t+U TsJq02BAQa/vMqelOWQPoLkZAEOUFBLviU8tjYyC+nCW36S+qAqzz4mMwojxcaTY4wEQjpZAnkXl tgVXSI3wJeBraOTQ0iIAMqf3Iz7KTaK5nSF5KQAcXVGMrqXJf21LE0dX/A7AkLwUEkz+GinP+5dF 6bYyjO0OZBSM7Q4ubC8DIDUjNoShJ74Q1vA94H55Hd/NPE10rJ7eg2TcLR00XHVhitOTNTkuuKbp DGlgVjnePQGHvzhP0bdl3Klw0un2ktjPzLyNGYEaczdksLKkgWsnGyiw7iCpv4W71S4etHqJjtUz 76thgdzpBYMo/bWaiiN3+Ni6g4RUM023Wml1dBIdq+e1goEhe0BPfGo9ZIA908DYGb2pLHFQW+Yg JtFA7ut9mLUyjWeTPXS/CXSqkbLgwoI+WLTrXH2Vgt6oIfk5E1lTk5lRMAC5V7DG0HQtX/2Zy85V V7hYeI+6SicxCXqypyUza2Ua1kGaQK49Q8s3pS/w08orVJY4qKtoQU4wMOrNFGauGERKmoT6LdUT n1rScfFiA5D8yLNPvqp0MspZID/SJBHSGalKpI0FToLqPfR0qAMYJgkhqMdaAKwFdBGG+r/UAczv Q90PkhD+rzGFmFHAR0AO0DeCcP+lbgLFwBoZZxXA3wYF/RAYZ2W5AAAAAElFTkSuQmCC }]; O-Saft-19.01.19/o-saft-man.pm000077500000000000000000002170731342117255600153700ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!# This software is licensed under GPLv2. Please see o-saft.pl for details. package main; # ensure that main:: variables are used ## no critic qw(ValuesAndExpressions::ProhibitCommaSeparatedStatements) # FIXME: We have a lot of comman separated statements to simplify the code. # This needs to be changed in future to keep Perl::Critic happy. # However, the code herein is just for our own documentation ... ## no critic qw(RegularExpressions::ProhibitCaptureWithoutTest) # NOTE: This often happens in comma separated statements, see above. # It may also happen after postfix statements. # Need to check regularily for this problem ... ## no critic qw(RegularExpressions::ProhibitComplexRegexes) # Yes, we have very complex regex here. ## no critic qw(RegularExpressions::RequireExtendedFormatting) # We believe that most RegEx are not too complex. ## no critic qw(InputOutput::RequireBriefOpen) # We always close our filehandles, Perl::Critic is too stupid to read # over 15 lines. ## no critic qw(Modules::ProhibitExcessMainComplexity) # It's the nature of translations to be complex, hence don't complain. # NOTE: This expception fails, Perl::Critic still complains (probably a bug there) use strict; use warnings; use vars qw(%checks %data %text); ## no critic qw(Variables::ProhibitPackageVars) # binmode(...); # inherited from parent use osaft; use OSaft::Doc::Data; my $SID_man= "@(#) o-saft-man.pm 1.272 19/01/20 22:35:16"; my $parent = (caller(0))[1] || "O-Saft";# filename of parent, O-Saft if no parent $parent =~ s:.*/::; $parent =~ s:\\:/:g; # necessary for Windows only my $ich = (caller(1))[1]; # tricky to get filename of myself when called from BEGIN $ich = "o-saft-man.pm" if (not defined $ich); # sometimes it's empty :-(( $ich =~ s:.*/::; my $version= "$SID_man"; # version of myself $version= _VERSION() if (defined &_VERSION); # or parent's if available my $cfg_header = 0; # we may be called from within parents BEGIN, hence no %cfg available $cfg_header = 1 if (0 < (grep{/^--header/} @ARGV)); my $mytool = qr/(?:$parent|o-saft.tcl|checkAllCiphers.pl)/;# regex for our tool names my @help = OSaft::Doc::Data::get_markup("help.txt", $parent, $version); local $\ = ""; #_____________________________________________________________________________ #_________________________________________________________ internal methods __| sub _man_dbx { my @txt=@_; print "#" . $ich . " CMD: " . join(' ', @txt, "\n") if (0 < (grep{/^--(?:v|trace.?CMD)/i} @ARGV)); return; } # similar to _y_CMD # When called from within parent's BEGIN{} section, options are not yet # parsed, and so not available in %cfg. Hence we use @ARGV to check for # options, which is not performant, but fast enough here. sub _man_file_get { #? get filename containing text for specified keyword my $typ = shift; return OSaft::Doc::Data::get_as_text('glossary.txt') if ('abbr' eq $typ); return OSaft::Doc::Data::get_as_text('links.txt') if ('links' eq $typ); return OSaft::Doc::Data::get_as_text('rfc.txt') if ('rfc' eq $typ); return ''; } # _man_file_get sub _man_http_head { #? print HTTP headers (for CGI mode) return if (0 >= (grep{/--cgi.?trace/} @ARGV)); # Checking @ARGV for --cgi-trace is ok, as this option is for simulating # CGI mode only, in o-saft.pl SEE Note:CGI mode # When called from o-saft.cgi, HTTP headers are already written. print "X-Cite: Perl is a mess. But that's okay, because the problem space is also a mess. Larry Wall\r\n"; print "Content-type: text/html; charset=utf-8\r\n"; print "\r\n"; return; } # _man_http_head sub _man_html_head { #? print footer of HTML page # SEE HTML:JavaScript my $vers = shift; _man_dbx("_man_html_head($vers) ..."); print << 'EoHTML'; . : O - S a f t — OWASP - SSL advanced forensic tool : . EoHTML print << "EoHTML";

O - S a f t   —   OWASP - SSL advanced forensic tool

EoHTML # TODO: need return; } # _man_html_head sub _man_help_button{ #? return href tag for a help button my $url = shift; my $cmd = shift; # must be --help=* option; also used for button text my $class = shift; # value for class= attribute (if not empty) my $title = shift; # value for title= attribute my $txt = $cmd; # $txt =~ s/^--//; # button text without --help $txt =~ s/^help=//; # button text without --help $class = "class='$class'" if ($class !~ m/^\s*$/); return sprintf('%s', $class, $url, $cmd, $title, $txt); } # _man_help_button sub _man_form_head { #? print start of CGI form my $cgi_bin = shift; printf("
Help:\n"); printf(" %s\n", _man_help_button($cgi_bin, "--help", '', "open window with complete help")); printf(" %s\n", _man_help_button($cgi_bin, "--help=command", '', "open window with help for commands")); printf(" %s\n", _man_help_button($cgi_bin, "--help=checks", '', "open window with help for checks")); printf(" %s\n", _man_help_button($cgi_bin, "--help=example", '', "open window with examples")); printf(" %s\n", _man_help_button($cgi_bin, "--help=opt", '', "open window with help for options")); printf(" %s\n", _man_help_button($cgi_bin, "--help=FAQ", '', "open window with FAQs")); printf(" %s\n", _man_help_button($cgi_bin, "--help=abbr", '', "open window with the glossar")); printf(" %s\n", _man_help_button($cgi_bin, "--help=todo", '', "open window with help for ToDO")); print << "EoHTML";

Hostname:



EoHTML # Above HTML contains
which contains checkboxes for some # options. These checkboxes are added in following foreach loop. # Above HTML contains which contains the # quick buttons for some commands. These quick buttons shoud get the # description from the later generated help text in this page, hence # the buttons are not generated here but using JavaScript at runtime # so that the corresponding help text can be derived from the (HTML) # page itself. SEE HTML:JavaScript #foreach my $key (qw(cmd cmd cmd cmd)) { print _man_html_cmd($key); } # show most common used options; layout by lines using BR foreach my $key (qw(no-sslv2 no-sslv3 no-tlsv1 no-tlsv11 no-tlsv12 no-tlsv13 BR no-dns dns no-cert BR no-sni sni BR no-http http BR header no-header no-warnings BR enabled disabled BR traceKEY traceCMD trace v BR )) { if ('BR' eq $key) { print "
\n"; next; } my $tag_nam = '--' . $key; print _man_html_cbox('cgi', " ", "q$tag_nam", $tag_nam, "", $tag_nam) . "\n"; } print _man_html_go("cgi"); print << "EoHTML";

EoHTML return; } # _man_form_head sub _man_form_foot { #? print end of CGI form my $cgi_bin = shift; print << "EoHTML";



EoHTML return; } # _man_form_foot sub _man_html_foot { #? print footer of HTML page _man_dbx("_man_html_foot() ..."); print << "EoHTML"; Repository   Download (stable)
O-Saft Home

© sic[✓]sec GmbH, 2012 - 2017

EoHTML return; } # _man_html_foot sub _man_html_cbox { ## no critic qw(Subroutines::ProhibitManyArgs) #? return input checkbox tag with clickable label and hover highlight my ($mode, $prefix, $tag_id, $tag_nam, $tag_val, $cmd_txt) = @_; return $cmd_txt if ($mode ne 'cgi'); # for "html" nothing special return sprintf("%s  ", $prefix, $tag_id, $tag_id, $tag_nam, $tag_val, $cmd_txt); } # _man_html_cbox sub _man_html_chck { #? return checkbox, or input field with clickable label (to reset input) #? to beused for +commands and --options my $mode = shift; # cgi or html my $cmd_opt = shift || ""; # +cmd or --opt or --opt=value my $tag_nam = $cmd_opt; my $tag_val = ''; return '' if ($cmd_opt !~ m/^(?:-|\+)+/); # defensive programming return $cmd_opt if ($mode ne 'cgi'); # for "html" nothing special # $cmd_opt may contain: "--opt1 --opt2"; hence split at spaces and use first if ($cmd_opt =~ m/^(?:\+)/) { # is command, print simple checkbox $tag_val = scalar((split(/\s+/, $cmd_opt))[0]); $tag_nam = '--cmd'; } else { # is optionm print simple checkbox or input field # options are --opt or --opt=VALUE; SEE HTML:INPUT $tag_val = ''; # checkbox with empty value $tag_nam = scalar((split(/\s+/, $cmd_opt))[0]); my ($key, $val) = split(/=/, $tag_nam); # split into key and value if (defined $val && $val =~ m/^[A-Z0-9:_-]+/) { # --opt=VALUE my $label = sprintf("", $tag_nam, $key); my $input = sprintf("", $tag_nam, $key, $val, $val); return "$label$input"; # else: see below } } return _man_html_cbox($mode, "", "o$cmd_opt", $tag_nam, $tag_val, $cmd_opt); } # _man_html_chck sub _man_name_ankor { my $n = shift; $n =~ s/,//g; # remove comma #$n =~ s/\s/_/g;# replace spaces return $n; } # _man_name_ankor sub _man_html_ankor { #? return ankor tag for each word in given parameter my $n = shift; my $a = ''; return sprintf('', $n) if ($n !~ m/^[-\+]+/); foreach my $n (split(/[\s,]+/,$n)) { $a .= sprintf("", _man_name_ankor($n)); } return $a; } # _man_html_ankor sub _man_html_go { #? return button "Top" and button "start" # SEE HTML:start my $key = shift; return "" if ($key ne 'cgi'); my $top = sprintf("%8s^\n", ""); my $run = sprintf("%8s\n", ""); return "$top$run"; } # _man_html_go sub _man_html_cmds { #? return checkboxes for commands not found in help.txt but are generated dynamically my $key = shift; my $txt = ""; my $cmds= _man_cmd_from_source(); # get all command from %data and %check_* # $cmds.= _man_cmd_from_rcfile(); # RC-FILE not used here foreach my $cmd (split(/[\r\n]/, $cmds)) { next if ($cmd =~ m/^\s*$/); $cmd =~ s/^\s*//; if ($cmd =~ m/^[+]/) { my $desc = ""; ($cmd, $desc) = split(/\s+/, $cmd, 2); $txt .= sprintf("%s %s
\n", _man_html_cbox($key, "", "c$cmd", "--cmd", $cmd, $cmd), $desc); # TODO: should be

, but as h4 is a display:block tag, # the remainig text $desc would be rendered in a new line; # to avoid this, a with proper CSS needs to be used } else { $txt .= _man_html_go($key) . "\n"; $txt .= sprintf("%s\n

%s

\n", _man_html_ankor($cmd), $cmd); } } #print "## $txt ##"; exit; return $txt; } # _man_html_cmds sub _man_html { #? print text in HTML format my $key = shift; # cgi or html my $url = shift; # URL my $anf = shift; # pattern where to start extraction my $end = shift; # pattern where to stop extraction my $skip= 0; my $c = 0; my $h = 0; my $a = ""; # NOTE: Perl::Critic is scary, SEE Perlcritic:LocalVars my $p = ""; # for closing p Tag _man_dbx("_man_html($key, $anf, $end) ..."); while ($_ = shift @help) { # NOTE: sequence of following m// and s/// is important # FIXME: need s!<\n", m/^=head1 (.*)/ && do { printf("$p\n

%s %s

\n",_man_html_ankor($1),$1);$p="";next;}; m/^=head2 (.*)/ && do { my $x=$1; ## no critic qw(Variables::RequireLocalizedPunctuationVars) if ($x =~ m/Discrete commands to test/) { # SEE Help:Syntax # command used for +info and +check have no description in @help print _man_html_cmds($key); # extract commands from dource code } else { print _man_html_go($key); print _man_html_ankor($x) . "\n"; printf("

%s %s

\n", _man_html_chck($key,$x), $x ); } next; }; m/^=head3 (.*)/ && do { # commands and options expected with =head3 only $a=$1; ## no critic qw(Variables::RequireLocalizedPunctuationVars) print _man_help_button($url, $a, "b r", "open window with special help") if ($a =~ m/--help/); print _man_html_ankor($a) . "\n"; printf("

%s

\n", _man_html_chck($key,$a)); next; }; m/Discrete commands,/ && do { $skip=2; next; }; # skip next 3 lines; SEE Help:Syntax # encode special markup m/(--help=[A-Za-z0-9_.-]+)/ && do { # add button for own help (must be first in sequence) print _man_help_button($url, $1, "b r", "open window with special help"); }; m/^\s*S&([^&]*)&/ && do { my $v=$1; $v=~s!<$v\n"; next; }; # code or example line s!'([^']*)'!$1!g; # markup examples s!"([^"]*)"!$1!g; # markup examples s!L&([^&]*)&!$1!g; # markup other references s!I&([^&]*)&!$1!g; # markup commands and options s!X&([^&]*)&!$1!g; # markup references inside help s!^\s+($mytool .*)!

$1
!; # example line m/^=item +\* (.*)/&& do { print "
  • $1
  • \n";next;}; # very lazy ... m/^=item +\*\* (.*)/ && do{ print "
  • $1
  • \n";next;}; s/^(?:=[^ ]+ )//; # remove remaining markup s!<"; $p = "

    "; $a = ''; }; # SEE Perlcritic:LocalVars print; } print "$p"; # if not empty, otherwise harmless return; } # _man_html sub _man_head { ## no critic qw(Subroutines::RequireArgUnpacking) #? print table header line (dashes) my $len1 = shift; # this line triggers Perl::Critic, stupid :-/ my @args = @_; # .. hence "no critic" pragma above _man_dbx("_man_head(..) ..."); return if (1 > $cfg_header); my $len0 = $len1 - 1; printf("=%${len0}s | %s\n", @args); printf("=%s+%s\n", '-'x $len1, '-'x60); return; } # _man_head sub _man_foot { #? print table footer line (dashes) my $len1 = shift; # expected length of first (left) string return if (1 > $cfg_header); printf("=%s+%s\n", '-'x $len1, '-'x60); return; } # _man_foot sub _man_opt { #? print line in "KEY - VALUE" format my @args = @_; my $len = 16; $len = 1 if ($args[1] eq "="); # allign left for copy&paste printf("%${len}s%s%s\n", @args); return; } # _man_opt sub _man_cfg { #? print line in configuration format my ($typ, $key, $sep, $txt) = @_; $txt = '"' . $txt . '"' if ($typ =~ m/^cfg(?!_cmd)/); $key = "--$typ=$key" if ($typ =~ m/^cfg/); _man_opt($key, $sep, $txt); return; } # _man_cfg sub _man_txt { #? print text configuration format (replaces \n\r\t ) my ($typ, $key, $sep, $txt) = @_; $txt =~ s/(\n)/\\n/g; $txt =~ s/(\r)/\\r/g; $txt =~ s/(\t)/\\t/g; _man_cfg($typ, $key, $sep, $txt); return; } # _man_txt sub _man_pod_item { #? print line as POD =item my $line = shift; print "=over\n\n$line\n=back\n"; return; } # _man_pod_item sub _man_usr_value { #? return value of argument $_[0] from @{$cfg{'usr-args'}} # expecting something like usr-action=/some.cgi in $cfg{'usr-args'} my $key = shift; $key =~ s/^(?:--|\+)//; # strip leading chars my @arg = ''; # key, value (Note that value is anything right to leftmost = ) map({@arg = split(/=/, $_, 2) if /^$key/} @{$cfg{'usr-args'}}); # does not allow multiple $key in 'usr-args' return $arg[1]; } # _man_usr_value sub _man_doc_opt { #? print text from file $typ in "KEY - VALUE" format # type is: abbr, links, rfc # format is: opt, POD my ($typ, $sep, $format) = @_; # format is POD or opt my $url = ''; my @txt = _man_file_get($typ); # OSaft::Doc::*::get() returns one line for each term; format is: # term followd by TAB (aka \t) followed by description text foreach my $line (@txt) { chomp $line; next if ($line =~ m/^\s*$/); next if ($line =~ m/^\s*#/); my ($key, $val) = split("\t", $line); $key =~ s/\s*$//; if ('rfc' eq $typ) { # RFC is different, adapt $key and $val $url = $val if ($key eq "url"); # should be first line only $val = $val . "\n\t\t\t$url/html/rfc$key"; $key = "RFC $key"; } _man_opt($key, $sep, $val) if ('opt' eq $format); _man_pod_item("$key $sep $val\n") if ('POD' eq $format); } return; } # _man_doc_opt sub _man_doc_pod { #? print text from file $typ in POD format my ($typ, $sep) = @_; my @txt = _man_file_get($typ); # print comment lines only, hence add # to each line my $help = "@txt"; $help =~ s/\n/\n#/g; print "# begin $typ\n\n"; print "# =head1 $typ\n\n"; print $help; #_man_doc_opt($typ, $sep, "POD"); # if real POD should be printed print "# end $typ\n"; return; } # _man_doc_pod sub _man_pod_head { #? print start of POD format print <<'EoHelp'; #!/usr/bin/env perldoc #? # Generated by o-saft.pl . # Unfortunatelly the format in @help is incomplete, for example proper =over # and corresponding =back paragraph is missing. It is mandatory arround =item # paragraphs. However, to avoid tools complaining about that, =over and =back # are added to each =item to avoid error messages in the viewer tools. # Hence the additional identations for text following the =item are missing. # Tested viewers: podviewer, perldoc, pod2usage, tkpod EoHelp print "=pod\n\n=encoding utf8\n\n"; # SEE POD:Syntax return; } # _man_pod_head sub _man_pod_text { #? print text in POD format my $code = 0; # 1 if last printed line was `source code' format my $empty = 0; # 1 if last printed line was empty while ($_ = shift @help) { # @help already looks like POD last if m/^(?:=head[1] )?END\s+#/;# very last line in this file m/^$/ && do { ## no critic qw(RegularExpressions::ProhibitFixedStringMatches) if (0 == $empty) { print; $empty++; } # empty line, but only one next; }; s/^(\s*(?:o-saft\.|checkAll|yeast\.).*)/S&$1&/; # dirty hack; adjust with 14 spaces s/^ {1,13}//; # remove leftmost spaces (they are invalid for POD); 14 and more spaces indicate a line with code or example s/^S&\s*([^&]*)&/\t$1/ && do { # code or example line print "\n" if (0 == ($empty + $code)); print; $empty = 0; $code++; next; # no more changes }; $code = 0; s:['`]([^']*)':C<$1>:g; # markup literal text; # dumm ' s:X&([^&]*)&:L:g; # markup references inside help s:L&([^&]*)&:L<$1|$1>:g; # markup other references #s:L<[^(]*(\([^\)]*\)\>).*:>:g; # POD does not like section in link s:I&([^&]*)&:I<$1>:g; # markup commands and options s/^([A-Z., -]+)$/B<$1>/; # bold s/^(=item)\s+(.*)/$1 $2/; # squeeze spaces my $line = $_; m/^=/ && do { # paragraph line # each paragraph line must be surrounded by empty lines # =item paragraph must be inside =over .. =back print "\n" if (0 == $empty); print "$line" if $line =~ m/^=[hovbefpc].*/;# any POD keyword _man_pod_item "$line" if $line =~ m/^=item/; # POD =item keyword print "\n"; $empty = 1; next; }; print "$line"; $empty = 0; } return; } # _man_pod_text sub _man_pod_foot { #? print end of POD format print <<'EoHelp'; Generated with: o-saft.pl --no-warnings --no-header --help=gen-pod > o-saft.pod EoHelp print "=cut\n\n"; # SEE POD:Syntax _man_doc_pod('abbr', "-"); # this is for woodoo, see below _man_doc_pod('rfc', "-"); # this is for woodoo, see below print <<'EoHelp'; # begin woodoo # Some documentation is plain text, which is DATA in Perl sources. As such, # it is not detected as source, not as comment, and not as documentation # by most tools analyzing the source code. # O-Saft's public user documentation is plain text stored in separate files. # The files are usually also not counted as source. # Unfortunately, some people solely believe in statistics generated by magic # tools. They use such statistics to measure for example code quality without # looking themself at the code. # Hence the purpose of this file is to provide real comment and documentation # lines from our documentation in format of the used programming language. # Hopefully, if these people read this, they change the workflow (means: they # also review the source code) or adapt their conclusions having in mind that # statistics can be manipulated in many ways. Here we go ... # # Disclaimer: No offence meant anyhow, neither against any analyzing tool nor # against anyone using them. It is just a reminder to use the tools and their # results in a wise manner. Measuring quality is more than just automatically # generated statistics! # end woodoo EoHelp return; } # _man_pod_foot sub _man_wiki_head { #? print start of mediawiki format print <<'EoHelp'; ==O-Saft== This is O-Saft's documentation as you get with: o-saft.pl --help On Windows following must be used o-saft.pl --help --v __TOC__ [[Category:OWASP Project]] [[Category:OWASP_Builders]] [[Category:OWASP_Defenders]] [[Category:OWASP_Tool]] [[Category:SSL]] [[Category:Test]] ---- EoHelp return; } # _man_wiki_head sub _man_wiki_text { #? print text of mediawiki format # convert POD syntax to mediawiki syntax my $mode = shift; while ($_ = shift @help) { last if/^=head1 TODO/; s/^=head1 (.*)/====$1====/; s/^=head2 (.*)/=====$1=====/; s/^=head3 (.*)/======$1======/; s/^=item (\*\* .*)/$1/; # list item, second level s/^=item (\* .*)/$1/; # list item, first level s/^=[^= ]+ *//; # remove remaining markup and leading spaces print, next if/^=/; # no more changes in header lines s:['`]([^']*)':$1:g; # markup examples # dumm ' s/^S&([^&]*)&/ $1/ && do { print; next; }; # code or example line; no more changes s/X&([^&]*)&/[[#$1|$1]]/g; # markup references inside help s/L&([^&]*)&/\'\'$1\'\'/g; # markup other references s/I&([^&]*)&/\'\'$1\'\'/g; # markup commands and options s/^ +//; # remove leftmost spaces (they are useless in wiki) if ('colon' eq $mode) { s/^([^=].*)/:$1/; # ident all lines for better readability } else { s/^([^=*].*)/:$1/; # ... } s/^:?\s*($mytool)/ $1/; # myself becomes wiki code line s/^:\s+$/\n/; # remove empty lines print; } return; } # _man_wiki_text sub _man_wiki_foot { #? print end of mediawiki format print <<'EoHelp'; ---- Content of this wiki page generated with: o-saft.pl --no-warning --no-header --help=gen-wiki EoHelp return; } # _man_wiki_foot sub _man_cmd_from_source { #? return all command from %data and %check_* my $txt = ""; my $skip = 1; my $fh = undef; if (open($fh, '<:encoding(UTF-8)', $0)) { # need full path for $parent file here while(<$fh>) { # find start of data structure # all structure look like: # our %check_some = ( # description # 'key' => {... 'txt' => "description of value"}, # ); # where we extract the description of the checked class from first # line and the command and its description from the data lines if (m/^(?:my|our)\s+%(?:check_(?:[a-z0-9_]+)|data)\s*=\s*\(\s*##*\s*(.*)/) { $skip = 0; $txt .= "\n Commands to show results of checked $1\n"; next; } $skip = 1, next if (m/^\s*\)\s*;/); # find end of data structure next if (1 == $skip); next if (m/^\s*'(?:SSLv2|SSLv3|D?TLSv1|TLSv11|TLSv12|TLSv13)-/); # skip internal counter if (m/^\s+'([^']*)'.*"([^"]*)"/) { my $key = $1; my $val = $2; my $len = "%-17s"; $len = "%s " if (length($key) > 16); # ensure that there is at least one space my $t = "\t"; # $t .= "\t" if (length($1) < 7); $txt .= sprintf("+$len%s\n", $1, $2); } } close($fh); } return $txt; } # _man_cmd_from_source sub _man_cmd_from_rcfile { #? return all command RC-FILE my $txt = "\n Commands locally defined in $cfg{'RC-FILE'}\n"; my $val = ""; my $skip = 1; my $fh = undef; if (open($fh, '<:encoding(UTF-8)', $cfg{'RC-FILE'})) { while(<$fh>) { if (m/^##[?]\s+([a-zA-Z].*)/) { # looks like: ##? Some text here ... $skip = 0; $val = $1; next; } if (m/^--cfg_cmd=([^=]*)=/) { # looks like: --cfg_cmd=MyCommad=list items next if (1 == $skip); # continue only if previous match succedded $skip = 1; $txt .= sprintf("+%-17s%s\n", $1, $val); $val = ""; } } close($fh); } return $txt; } # _man_cmd_from_rcfile #_____________________________________________________________________________ #__________________________________________________________________ methods __| sub man_commands { #? print commands and short description # data is extracted from $parents internal data structure _man_dbx("man_commands($parent) ..."); # first print general commands, manually crafted here # TODO needs to be computed, somehow ... # SEE Help:Syntax print "\n"; _man_head(15, "Command", "Description"); print <<"EoHelp"; Commands for information about this tool +dump Dumps internal data for SSL connection and target certificate. +exec Internal command; should not be used directly. +help Complete documentation. +list Show all ciphers supported by this tool. +libversion Show version of openssl. +quit Show internal data and exit, used for debugging only. +VERSION Just show version and exit. +version Show version information for program and Perl modules. Commands to check SSL details +bsi Various checks according BSI TR-02102-2 and TR-03116-4 compliance. +check Check the SSL connection for security issues. +check_sni Check for Server Name Indication (SNI) usage. +ev Various checks according certificate's extended Validation (EV). +http Perform HTTP checks. +info Overview of most important details of the SSL connection. +info--v More detailled overview. +quick Quick overview of checks. +protocols Check for protocols supported by target. +s_client Dump data retrieved from "openssl s_client ..." call. +sizes Check length, size and count of some values in the certificate. +sni Check for Server Name Indication (SNI) usage. +sts Various checks according STS HTTP header. +vulns Check for various vulnerabilities. Commands to test ciphers provided by target +cipher Check target for ciphers (using libssl). +cipher-dh Check target for ciphers (using libssl), prints also DH parameter. +cipherall Check target for all possible ciphers (same format as +cipher). +cipherraw Check target for all possible ciphers (special format). +cipher-default Check target for (default) selected cipher for each protocol. +cipher-null Check if target accepts NULL ciphers. +cipher-adh Check if target accepts ciphers with anonymous key exchange. +cipher-exp Check if target accepts EXPORT ciphers. +cipher-cbc Check if target accepts CBC ciphers. +cipher-des Check if target accepts DES ciphers. +cipher-rc4 Check if target accepts RC4 ciphers. +cipher-edh Check if target supports ephemeral ciphers. +cipher-pfs Check if target supports ciphers with PFS. +cipher-strong Check if target selects strongest cipher. +cipher-selected Selected cipher. EoHelp print _man_cmd_from_source(); print _man_cmd_from_rcfile(); _man_foot(15); print "\n"; return; } # man_commands sub man_table { ## no critic qw(Subroutines::ProhibitExcessComplexity) #? print data from hash in tabular form, $typ denotes hash #? header of table is not printed if $typ is cfg-* # NOTE critic: McCabe 22 (tested 5/2016) is not that bad here ;-) my $typ = shift;# NOTE: lazy matches against $typ below, take care with future changes $typ =~ s/^cipher(pattern|range)/$1/;# normalize: cipherrange and range are possible my %types = ( # typ header left separator header right #-----------+---------------+-------+------------------------------- 'score' => ["key", " - ", " SCORE\t# Description"], 'regex' => ["key", " - ", " Regular Expressions used internally"], 'ourstr'=> ["key", " - ", " Regular Expressions to match own output"], 'abbr' => ["Abbrevation", " - ", " Description"], 'intern'=> ["Command", " ", " list of commands"], 'compl' => ["Compliance", " - ", " Brief description of performed checks"], 'range' => ["range name", " - ", " hex values in this range"], 'pattern' =>["pattern name", " - ", " pattern description; used pattern"], 'rfc' => ["Number", " - ", " RFC Title and URL"], 'links' => ["Title", " - ", " URL"], 'check' => ["key", " - ", " Label text"], 'data' => ["key", " - ", " Label text"], 'hint' => ["key", " - ", " Hint text"], 'text' => ["key", " - ", " text"], 'cmd' => ["key", " - ", " list of commands"], ); my $txt = ""; my $sep = "\t"; if (defined $types{$typ}) { # defensive programming $sep = $types{$typ}->[1]; } else { $sep = "=" if ($typ =~ m/(?:^cfg[_-]|[_-]cfg$)/); # the purpose of cfg_* is to print the results in a format so that # they can be used with copy&paste as command line arguments # simply change the separator to = while other headers are unused # (because no header printed at all) } _man_dbx("man_table($typ) ..."); _man_head(16, $types{$typ}->[0], $types{$typ}->[2]) if ($typ !~ m/^cfg/); # first only lists, which cannot be redefined with --cfg-*= (doesn't make sense) _man_doc_opt($typ, $sep, 'opt'); # abbr, rfc, links, ... if ($typ eq 'compl') { _man_opt($_, $sep, $cfg{'compliance'}->{$_}) foreach (sort keys %{$cfg{'compliance'}}); } if ($typ eq 'intern') { # first list command with all internal commands-* foreach my $key (sort keys %cfg) { next if ($key !~ m/^commands-(?:.*)/); _man_opt($key, $sep, "+" . join(' +', @{$cfg{$key}})); } foreach my $key (sort keys %cfg) { next if ($key !~ m/^cmd-(.*)/); _man_opt("cmd-" . $1, $sep, "+" . join(' +', @{$cfg{$key}})); } } # now all lists, which can be redefined with --cfg-*= # _man_cfg() prints different data for --help=TYP and --help=TYP-cfg if ($typ =~ m/(hint|ourstr|pattern|range|regex)/) { my $list = $1; $list =~ s/^cfg[._-]?//; $list =~ s/[._-]?cfg$//; $list = 'hints' if ($list =~ m/hint/); # the key in %cfg is 'hints'; 'hint' is different $list = 'cipherpatterns' if ($list =~ m/pattern/); $list = 'cipherranges' if ($list =~ m/range/); # TODO: --cfg_range=* and --cfg-regex=* are not yet implemented # however, we can print it using --help=cfg-regex foreach my $key (sort keys %{$cfg{$list}}) { $txt = $cfg{$list}->{$key}; if ('ARRAY' eq ref($cfg{$list}->{$key})) { $txt = join("\t", @{$cfg{$list}->{$key}}); } _man_cfg($typ, $key, $sep, $txt); } } if ($typ =~ m/cmd/) { foreach my $key (sort keys %cfg) { next if ($key !~ m/^cmd-/); next if ($key =~ m/^cmd-(?:check|info)/); # FIXME: currently disabled $txt = $cfg{$key}; if ('ARRAY' eq ref($cfg{$key})) { $txt = join(" ", @{$cfg{$key}}); } $key =~ s/^cmd.// if ($typ =~ m/cfg/); # $key in %cfg looks like cmd-sni, but when configuering the # key in RC-FILE it looks like --cfg_cmd=sni= ... _man_cfg($typ, $key, $sep, $txt); } } if ($typ =~ m/score/) { foreach my $key (sort keys %checks) { $txt = $checks{$key}->{score} . "\t# " . $checks{$key}->{txt}; $txt = $checks{$key}->{score} if ($typ =~ m/cfg/); _man_cfg($typ, $key, $sep, $txt); } } if ($typ =~ m/check/) { foreach my $key (sort keys %checks) { $txt = $checks{$key}->{txt}; _man_cfg($typ, $key, $sep, $txt); } } if ($typ =~ m/(?:data|info)/) { foreach my $key (sort keys %data) { $txt = $data{$key}->{txt}; _man_cfg($typ, $key, $sep, $txt); } } if ($typ =~ m/text/) { foreach my $key (sort keys %text) { #_dbx "$key : " . ref($text{$key}); if ('' eq ref($text{$key})) { # string $txt = $text{$key}; _man_txt($typ, $key, $sep, $txt); } if ('HASH' eq ref($text{$key})) { # TODO: not yet printed, as it may confuse the user #foreach my $k (sort keys $text{$key}) { # $txt = $text{$key}->{$k}; # _man_txt($typ, "$key($k)", $sep, $txt); #} } } } if ($typ !~ m/cfg/) { _man_foot(16); } else { # additional message here is like a WARNING or Hint, # do not print it if any of them is disabled return if (($cfg{'warning'} + $cfg{'out_hint'}) < 2); print <<"EoHelp"; = Format is: KEY=TEXT ; NL, CR and TAB are printed as \\n, \\r and \\t = (Don't be confused about multiple = as they are part of TEXT.) = The string @@ inside texts is used as placeholder. = NOTE: " are not escaped! EoHelp } return; } # man_table sub man_alias { #? print alias and short description (if available) # # Aliases are extracted from the source code. All lines handling aliases # for commands or options are marked with the pattern # alias: # From these lines we extract the regex, the real option or command and # the comment. # # /------- regex -------\ /--- command ----\ /pattern\ /--- comment --- # Examples of lines to match: # if ($arg eq '--nosslnodataeqnocipher'){$arg='--nodatanocipher';} # alias: # if ($arg =~ /^--ca(?:cert(?:ificate)?)$/i) { $arg = '--cafile';} # alias: curl, openssl, wget, ... # if ($arg =~ /^--cadirectory$/i) { $arg = '--capath'; } # alias: curl, openssl, wget, ... # if ($arg eq '-c') { $arg = '--capath'; } # alias: ssldiagnose.exe # #if ($arg eq '--protocol') { $arg = '--SSL'; } # alias: ssldiagnose.exe # print "\n"; _man_head(27, "Alias (regex) ", "command or option # used by ..."); my $fh = undef; my $p = '[._-]'; # regex for separators as used in o-saft.pl if (open($fh, '<:encoding(UTF-8)', $0)) { # need full path for $parent file here while(<$fh>) { next if (not m(# alias:)); next if (not m|^\s*#?if[^/']*.([^/']+).[^/']+.([^/']+).[^#]*#\s*alias:\s*(.*)?|); my $commt = $3; my $alias = $2; my $regex = $1; # simplify regex for better (human) readability $regex =~ s/^\^//; # remove leading ^ $regex =~ s/^\\//; # remove leading \ $regex =~ s/\$$//; # remove trailing $ $regex =~ s/\(\?:/(/g; # remove ?: in all groups $regex =~ s/\[\+\]/+/g; # replace [+] with + $regex =~ s/\$p\?/-/g; # replace variable if (29 > length($regex)) { printf("%-29s%-21s# %s\n", $regex, $alias, $commt); } else { # pretty print if regex is to large for first column printf("%s\n", $regex); printf("%-29s%-21s# %s\n", "", $alias, $commt); } } close($fh); } _man_foot(27); print <<'EoHelp'; = Note for names in Alias column: = For option names - or _ characters are not shown, they are stripped anyway. = For command names - or _ characters are also possible, but only - is shown. EoHelp return; } # man_alias sub man_toc { #? print help table of contents my $typ = lc(shift) || ""; # || to avoid uninitialized value _man_dbx("man_toc() .."); foreach my $txt (grep{/^=head. /} @help) { # note: @help is in POD format next if ($txt !~ m/^=head/); next if ($txt =~ m/^=head. *END/); # skip last line if ($typ =~ m/cfg/) { $txt =~ s/^=head1 *(.*)/{print "--help=$1\n"}/e; } else { # print =head1 and =head2 # just =head1 is lame, =head1 and =head2 and =head3 is too much $txt =~ s/^=head([12]) *(.*)/{print " " x $1, $2,"\n"}/e; # use number from =head as ident } } return; } # man_toc sub man_pod { #? print complete POD page for o-saft.pl --help=gen-pod #? recommended usage see at end of this sub _man_dbx("man_pod() ..."); _man_pod_head(); _man_pod_text(); _man_pod_foot(); return; } # man_pod sub man_html { #? print complete HTML page for o-saft.pl --help=gen-html #? recommended usage: $0 --no-warning --no-header --help=gen-html # for concept and functionality of the generated page SEE HTML:HTML _man_dbx("man_html() ..."); _man_http_head(); _man_html_head(STR_VERSION); _man_html('html', '', 'NAME', 'TODO'); # print complete help _man_html_foot(); return; } # man_html sub man_cgi { #? print complete HTML page for o-saft.pl used as CGI #? recommended usage: $0 --no-warning --no-header --help=gen-cgi #? o-saft.cgi?--cgi=&--usr&--no-warning&--no-header=&--cmd=html # for concept and functionality of the generated page SEE HTML:CGI # # help (HTML format) # previous link not generated because it prints multiple HTTP headers # # and values (link) must be specified using the # option --usr-action= at script start. # my $cgi_bin = _man_usr_value('user-action') || _man_usr_value('usr-action') || "/cgi-bin/o-saft.cgi"; # get action from --usr-action= or set to default (defensive programming) _man_dbx("man_cgi() ..."); _man_http_head(); _man_html_head(STR_VERSION); _man_form_head( $cgi_bin); _man_html('cgi', $cgi_bin, 'COMMANDS', 'LAZY'); # print help starting at COMMANDS _man_form_foot( $cgi_bin); _man_html_foot(); # TODO: osaft_action_http, osaft_action_file should be set dynamically return; } # man_cgi sub man_wiki { #? print documentation for o-saft.pl in mediawiki format (to be used at owasp.org) #? recommended usage: $0 --no-warning --no-header --help=gen-wiki my $mode = shift; # currently only mode=colon is implemented to print :* instead of * # Up to VERSION 15.12.15 list items * and ** where printed without # leading : (colon). Some versions of mediawiki did not support :* # so we can switch this behavior now. _man_dbx("man_wiki($mode) ..."); _man_wiki_head(); _man_wiki_text($mode); _man_wiki_foot(); return; } # man_wiki sub man_help { #? print complete user documentation for o-saft.pl as plain text (man-style) my $label = lc(shift) || ""; # || to avoid uninitialized value my $anf = uc($label); my $end = "[A-Z]"; _man_dbx("man_help($anf, $end) ..."); # no special help, print full one or parts of it my $txt = join ('', @help); # = OSaft::Doc::Data::get("help.txt", $parent, $version); if (1 < (grep{/^--v/} @ARGV)) { # with --v --v print OSaft::Doc::Data::get_egg("help.txt"); return; } if ($label =~ m/^name/i) { $end = "TODO"; } #$txt =~ s{.*?(=head. $anf.*?)\n=head. $end.*}{$1}ms;# grep all data # above terrible performance and unreliable, hence in peaces below $txt =~ s/.*?\n=head1 $anf//ms; $txt =~ s/\n=head1 $end.*//ms; # grep all data $txt = "\n=head1 $anf" . $txt; $txt =~ s/\n=head2 ([^\n]*)/\n $1/msg; $txt =~ s/\n=head3 ([^\n]*)/\n $1/msg; $txt =~ s/\n=(?:[^ ]+ (?:\* )?)([^\n]*)/\n$1/msg;# remove inserted markup $txt =~ s/\nS&([^&]*)&/\n$1/g; $txt =~ s/[IX]&([^&]*)&/$1/g; # internal links without markup $txt =~ s/L&([^&]*)&/"$1"/g; # external links, must be last one if (0 < (grep{/^--v/} @ARGV)) { # do not use $^O but our own option # some systems are tooo stupid to print strings > 32k, i.e. cmd.exe print "**WARNING: using workaround to print large strings.\n\n"; print foreach split(//, $txt); # print character by character :-(( } else { print $txt; } if ($label =~ m/^todo/i) { print "\n NOT YET IMPLEMENTED\n"; foreach my $label (sort keys %checks) { next if (0 >= _is_member($label, \@{$cfg{'commands-NOTYET'}})); print " $label\t- " . $checks{$label}->{txt} . "\n"; } } return; } # man_help sub src_grep { #? search for given text in source file, then pretty print my $hlp = shift; print "\n"; _man_head(14, "Option ", "Description where program terminates"); my $fh = undef; if (open($fh, '<:encoding(UTF-8)', $0)) { # need full path for $parent file here while(<$fh>) { next if (m(^\s*#)); next if (not m(_(?:EXIT|NEXT).*$hlp)); my $opt = $_; my $comment = $_; if ($opt =~ m/exit=/) { # line looks like: _yeast_EXIT("exit=BEGIN0 - BEGIN start"); # or : _yeast_NEXT("exit=HOST0 - host start"); $opt =~ s/^[^"]*"/--/; $opt =~ s/ - .*$//s; $comment =~ s/^[^-]*//; $comment =~ s/".*$//s; } printf("%-15s%s\n", $opt, $comment); } close($fh); } _man_foot(14); return; } # src_grep sub printhelp { ## no critic qw(Subroutines::ProhibitExcessComplexity) #? simple dispatcher for various help requests # NOTE critic: as said: *this code is a simple dispatcher*, that's it my $hlp = shift; _man_dbx("printhelp($hlp) ..."); # Note: some lower case strings are special man_help('NAME'), return if ($hlp =~ /^$/); ## no critic qw(RegularExpressions::ProhibitFixedStringMatches) man_help('TODO'), return if ($hlp =~ /^todo$/i); ## no critic qw(RegularExpressions::ProhibitFixedStringMatches) man_help('KNOWN PROBLEMS'), return if ($hlp =~ /^(err(?:or)?|warn(?:ing)?|problem)s?$/i); if ($hlp =~ /^faq/i) { man_help('KNOWN PROBLEMS'); man_help('LIMITATIONS'); return } man_help($hlp), return if ($hlp =~ /^(?:CHECKS?|CUSTOM)$/); # not case-sensitive! # NOTE: bad design, as we have headlines in the documentation which # are also used as spezial meaning (see below). In particular # CHECKS is a headline for a section in the documentation, # while checks is used to print the labels of performed all # checks. Workaround is to treat all-uppercase words as head- # line of a section and anything else as special meaning. # However, note that --help=chec already behaves the same way as # --help=CHECKS while --help=check prints the labels. Means that # this special condition (match CHECKS) is just for commodity. man_toc($1), return if ($hlp =~ /^((?:toc|content)(?:.cfg)?)/i); man_html(), return if ($hlp =~ /^(gen-)?html$/); man_wiki('colon'), return if ($hlp =~ /^(gen-)?wiki$/); man_pod(), return if ($hlp =~ /^(gen-)?pod$/i); man_cgi(), return if ($hlp =~ /^(gen-)?cgi$/i); man_alias(), return if ($hlp =~ /^alias(es)?$/); man_commands(), return if ($hlp =~ /^commands?$/); # anything below requires data defined in parent man_table('rfc'), return if ($hlp =~ /^rfcs?$/); man_table('links'), return if ($hlp =~ /^links?$/); man_table('abbr'), return if ($hlp =~ /^(abbr|abk|glossary?)$/); man_table(lc($1)), return if ($hlp =~ /^(intern|compl(?:iance)?|pattern)s?$/i); man_table(lc($1)), return if ($hlp =~ /^(cipher(?:pattern|range)?)s?$/i); man_table(lc($1)), return if ($hlp =~ /^(cmd|check|data|info|hint|text|range|regex|score|ourstr)$/i); man_table('cfg_'.lc($1)), return if ($hlp =~ /^(cmd|check|data|info|hint|text|range|regex|score|ourstr)[_-]?cfg$/i); man_table('cfg_'.lc($1)), return if ($hlp =~ /^cfg[_-]?(cmd|check|data|info|hint|text|range|regex|score|ourstr)s?$/i); # we allow: text-cfg, text_cfg, cfg-text and cfg_text so that # we can simply switch from --help=text and/or --cfg_text=* # we do not allow --help=cfg-cmds or --help=cfg-checks due to conflict # with --help=cmds (see next condiftion); since 19.01.19 if ($hlp =~ /^cmds$/i) { # print program's commands print "# $parent commands:\t+" . join(' +', @{$cfg{'commands'}}); return; } if ($hlp =~ /^legacys?$/i) { # print program's legacy options print "# $parent legacy values:\t" . join(' ', @{$cfg{'legacys'}}); return; } if ($hlp =~ /^help$/) { #my $hlp = OSaft::Doc::Data::get("help.txt", $parent, $version); my $txt = ""; foreach (@help) { $txt .= $_ if (m/Options for help and documentation/..m/Options for all commands/); }; # TODO: quick&dirty match against to fixed strings (=head lines) $txt =~ s/^=head.//msg; $txt =~ s/Options for all commands.*.//msg; print "$txt"; #man_help('Options for help and documentation'); return; } if ($hlp =~ m/^opts?$/i) { # print program's options my @txt = grep{/^=head. (General|Option|--)/} @help; # get options only foreach my $line (@txt) { $line =~ s/^=head. *//} # remove leading markup my($end) = grep{$txt[$_] =~ /^Options vs./} 0..$#txt; # find end of OPTIONS section print join('', "OPTIONS\n", splice(@txt, 0, $end)); # print anything before end return; } if ($hlp =~ m/^Tools$/i) { # description for O-Saft tools print OSaft::Doc::Data::get("tools.txt", $parent, $version); return; } if ($hlp =~ m/^Program.?Code$/i) { # print Program Code description print OSaft::Doc::Data::get("coding.txt", $parent, $version); return; } src_grep("exit="), return if ($hlp =~ /^exit$/i); # nothing matched so far, try to find special section and only print that _man_dbx("printhelp: " . uc($hlp)); man_help(uc($hlp)); return; } # printhelp sub _main { ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # see .perlcritic for detailed description of "no critic" my $arg = shift; binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); if ($arg =~ m/--?h(elp)?$/) { if (eval {require POD::Perldoc;}) { # pod2usage( -verbose => 1 ); exec( Pod::Perldoc->run(args=>[$0]) ); } if (qx(perldoc -V)) { ## no critic qw(InputOutput::ProhibitBacktickOperators) printf("# no POD::Perldoc installed, please try:\n perldoc $0\n"); } exit 0; } else { printhelp($ARGV[0]); } exit 0; } # _main sub o_saft_man_done {}; # dummy to check successful include #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME o-saft-man.pm - perl module to handle O-Saft's documentation =head1 DESCRIPTION This module provides functionality to generate O-Saft's user documentation in various formats. Supported formats are: =over 2 =item * POD =item * HTML =item * mediawiki =item * Plain Text =back Additionally various parts of the documentation can be generated. Please see L below. =head1 SYNOPSIS =over 2 =item * require q{o-saft-man.pm}; printhelp($type); =item * o-saft-man.pm [<$type>] =back =head1 METHODS =over 2 =item * printhelp($type) Public method for all functionality. The generated output format depends on the $type parameter, which is a literal string, as follows: =over 2 =item * pod -> all documentation in POD format =item * html -> all documentation in HTML format =item * wiki -> all documentation in mediawiki format =item * NAME -> all documentation in plain text (man-style) format =item * =item * NAME -> all documentation in plain text (man-style) format =item * contents =item * toc -> table of contents for documentation as plain text =item * help -> list all options to get (help) information =item * cgi -> all documentation as HTML for CGI usage =item * alias -> list of all aliases for commands and options =item * cmds -> list of all commands (just the commands) =item * command -> list of all commands with brief description =item * opts -> list of all options (just the options) =item * options -> list of all options with full description =item * legacy -> list of legacy options =item * checks -> list of all SSL/TLS checks (each can be used as command) =item * data -> list of all SSL/TLS data values (each can be used as command) =item * info -> list of all SSL/TLS info values (each can be used as command) =item * pattern -> list of supported pttern for SSL/TLS cipher ranges (for +cipher) =item * range -> list of supported SSL/TLS cipher ranges (for +cipher) =item * regex -> list of most RegEx used internaly for SSL/TLS checks =item * ourstr -> list with RegEx matching special strings used in output =item * tools -> list of tools delivered with o-saft.pl =item * abbr =item * glossar -> list of abbrevations and terms according SSL/TLS =item * links -> list of links according SSL/TLS (incomplete) =item * rfc -> list of RFCs according SSL/TLS (incomplete) =item * faq -> lists known problems and limitations =item * todo -> show list of TODOs =item * intern -> some internal documentations =item * Program.Code -> description of coding style, conventions, etc. =back =back If any other string is used, 'printhelp()' extracts just the section of the documention which is headed by that string. NOTE that above list is also documented in ./OSaft/Doc/help.txt in section "Options for help and documentation". In a perfect world it would be extracted from there (or vice versa). =head1 AUTHOR 14-nov-14 Achim Hoffmann =cut ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main(@ARGV) if (not defined caller); 1; # SEE Note:Documentation (in o-saft.pl) =pod =head1 Annotations, Internal Notes The annotations here are for internal documentation only. For details about our annotations, please SEE Annotations, in o-saft.pl. =head2 Perlcritic:LocalVars Perl::Critic complains that the variable $a should be localized in of the code, this is wrong, because it is exactly the purpose to find this value (other settings) in other lines. Hence "no critic Variables::RequireLocalizedPunctuationVars" needs to be set in each line using $a. =head2 Help:Syntax The text for documentation is derivied from "help.txt" aka @help using: OSaft::Doc::Data::get_markup("help.txt") This text contains some simple (intermediate) markup, which then will be transformed to the final markup, such as HTML, POD, wiki. Some sections in that text are handled special or needs to be completed. These specialsections are mainly identified by line starting as follows: Commands for ... Commands to ... Descrete commands to test ... Option for ... Option to ... These strings are hardcoded here. Take care when changing "help.txt". See also "OSaft/Doc/Data.pm". NOTE also that o-saft.tcl mainly uses the same texts for extra handling. =head2 POD:Syntax The special POD keywords =pod and =cut cannot be used as literal text in particular in here documents, because (all?) most tools extracting POD from this file (for example perldoc) would be confused. Hence these keywords need to be printed in a seperate statement. =head2 HTML:HTML The complete documentation can be returned as HTML page. The generation is straight forward, see function man_html(). Some details of the generated page are described in: SEE HTML:p and SEE HTML:JavaScript. In general, following rules must apply to the input data used to generate HTML: * strings for commands and options start with '+' or '-' * if options have a value, the syntax must be: --option=VALUE, where the VALUE must be written upper-case * commands and options may be grouped by level 3 head lines Data (text) in this format is returned by OSaft::Doc::Data::get_markup(). NOTE most functions use following global variables: * @help * $parent * $mytool =head2 HTML:CGI The HTML page with the form for the CGI should look as follows: +-----------------------------------------------------------------------+ | O - S a f t — ... T +-----------------------------------------------------------------------+ | Help: [help] [commands] [checks] [options] [FAQ] [Glossar] [ToDo] H |+--------------------------------------------------------------------+ H || Hostname: [_________________________________] [start] c | || c | || [+check] Check SSL connection ... c | || [+cipher] Overview of SSL connection ... c | || ... c | || c | || [Commands & Options] O | ||+-----------------------------------------------------------------+ | | ||| ( ) --header ( ) --enabled ( ) --options [Full GUI] q | | ||| ... q | | ||| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | | ||| COMMANDS [Simple GUI] o | | ||| ( ) +cmd o | | ||| ... o | | ||| OPTIONS o | | ||| ( ) --opt o | | ||| ( --opt=[________] o | | ||| ... o | | ||+-----------------------------------------------------------------+ | | |+--------------------------------------------------------------------+ | +-----------------------------------------------------------------------+ All commands and options avaialable in o-saft.pl are provided in the form. Additional to the hostname or URL, all selected commands and options will be passed as QUERY_STRING to o-saft.cgi (which is the form's action), when [start] button is clicked. The Interfase (web page) consist of following sections: T title H line with buttons openening new TAB with corresponding help text c input field for the hostname (target) and buttons for the most used commands O Options button opens the section with the most often used options q list with the most often used options, and the button [Full GUI] to show all available commands and options o all available commands and options, and the button [Simple GUI] to to switch back to the simple list of options =head2 HTML:INPUT Options are --opt or --opt=VALUE . A simple checkbox is sufficient for options without a value: --opt Options with a value need an input field for the value, and a reset button to undo changes. Additionally, the key=value should only be send on submit of the form if the value was changed. The change will be checked with the form's onsubmit event (which calls osaft_submit(); for details see there). The generated HTML looks like:
    ' is the modern standard. This simplifies formating with CSS. =head2 HTML:JavaScript When generating the HTML page (wether plain HTML or CGI), each description text for commands and options is placed in a paragraph ('

    ' tag), which has an 'id' attribute set to the name of the command or option. This name is prefixed with the letter 'h'. Example: the description of the '+cipher' command is placed in following paragraph:

    ...

    . These paragraphs are generated in '_man_html()'. This allows to extract the desciption text after generating the page using JavaScript. See JavaScript function 'osaft_buttons()'. =head2 HTML:start The documenation in HTML format contains a "start" button at the bottom of each toplevel section. This should only be done when the page is used for CGI (aka --help=cgi). =cut O-Saft-19.01.19/o-saft-usr.pm000077500000000000000000000117541342117255600154240ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!# This software is licensed under GPLv2. Please see o-saft.pl for details. ## no critic qw(Documentation::RequirePodSections) # SEE Perl:perlcritic =pod =head1 NAME o-saft-usr.pm - module for o-saft.pl's user definable functions =head1 SYNOPSIS require "o-saft-usr.pm"; =head1 DESCRIPTION Defines all function for user customization. WARNING: this is not a perl module defined with `package', but uses: package main; hence is is recommended that all variables and function use a unique prefix like: usr_ or _usr_ =head2 Functions defined herein =over 4 =item usr_pre_init( ) At beginning, right before initializing internal data. =item usr_pre_file( ) At beginning, right after initializing internal data. =item usr_pre_args( ) Right before reading command line arguments. All internal structures and variables are initialized, all external files are read (except configuration files specified witj I<--cfg_*=> option. =item usr_pre_exec( ) All command line arguments are read. Right before executing myself. =item usr_pre_cipher( ) Before getting list of ciphers. =item usr_pre_main( ) Before executing commands. =item usr_pre_host( ) Before starting loop over all given hosts. =item usr_pre_info( ) DNS stuff and SNI connection checked. Before doing commands per host. =item usr_pre_open( ) Before opening connection. =item usr_pre_cmds( ) Before listing or checking anything. SSL connection is open and all data available in $Net::SSLinfo::* . =item usr_pre_data( ) All data according SSL connection and ciphers available in %data and @results. Before doing any checks and before printing anything. =item usr_pre_print( ) All checks are done, ready to print data from %checks also. =item usr_pre_next( ) Host completely processed. Right before next host. =item usr_pre_exit( ) Right before program exit. =back =head2 Variables which may be used herein They must be defined as `our' in L: =over 4 =item $VERSION =item %data =item %cfg, i.e. trace, traceARG, traceCMD, traceKEY, verbose =item %checks =item %org =back Functions being used in L shoudl be defined as empty stub there. For example: sub usr_pre_args() {} =head1 VERSION Call: usr_version() =cut use strict; use warnings; my $SID_usr= "@(#) o-saft-usr.pm 1.23 18/11/10 16:18:47"; no warnings 'redefine'; ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) # must be herein, as most subroutines are already defined in main # warnings pragma is local to this file! package main; # ensure that main:: variables are used sub _usr_dbx { my @args = @_; _trace(join(" ", @args, "\n")); return; } # requires --v # user functions # ------------------------------------- # These functions are called in o-saft.pl sub usr_version { return "16.09.16"; } sub usr_pre_init { _usr_dbx("usr_pre_init ..."); return; }; sub usr_pre_file { _usr_dbx("usr_pre_file ..."); return; }; sub usr_pre_args { _usr_dbx("usr_pre_args ..."); return; }; sub usr_pre_exec { _usr_dbx("usr_pre_exec ..."); # All arguments and options are parsed. # Unknown commands are not available with _is_do() but can be # searched for in cfg{'done'}->{'arg_cmds'} which allows users # to "create" and use their own commands without changing # o-saft.pl itself. However, o-saft.pl will print a WARNING then. return; }; sub usr_pre_cipher { _usr_dbx("usr_pre_cipher ..."); return; }; sub usr_pre_main { _usr_dbx("usr_pre_main ..."); return; }; sub usr_pre_host { _usr_dbx("usr_pre_host ..."); return; }; sub usr_pre_info { _usr_dbx("usr_pre_info ..."); return; }; sub usr_pre_open { _usr_dbx("usr_pre_open ..."); ### ### sample code for using your own socket ### #use IO::Socket; #$Net::SSLinfo::socket = IO::Socket::INET->new(PeerHost=>'localhost', PeerPort=>443, Proto=>'tcp') #or die "**ERROR usr_pre_open socket(): $!\n"; return; }; sub usr_pre_cmds { _usr_dbx("usr_pre_cmds ..."); return; }; sub usr_pre_data { _usr_dbx("usr_pre_data ..."); return; }; sub usr_pre_print { _usr_dbx("usr_pre_print ..."); return; }; sub usr_pre_next { _usr_dbx("usr_pre_next ..."); return; }; sub usr_pre_exit { _usr_dbx("usr_pre_exit ..."); return; }; sub o_saft_usr_done {}; # dummy to check successful include ## PACKAGE } # local functions { # ------------------------------------- # local functions } unless (defined caller) { if (eval{require POD::Perldoc;}) { # pod2usage( -verbose => 1 ) exit( Pod::Perldoc->run(args=>[$0]) ); } ## no critic qw(InputOutput::ProhibitBacktickOperators) # SEE Perl:perlcritic if (qx(perldoc -V)) { # may return: You need to install the perl-doc package to use this program. #exec "perldoc $0"; # scary ... print "# try:\n perldoc $0\n"; } } 1; O-Saft-19.01.19/o-saft.cgi000077500000000000000000000216731342117255600147440ustar00rootroot00000000000000#!/usr/bin/perl ## no critic qw(Documentation::RequirePodSections) ## no critic qw(RegularExpressions::ProhibitComplexRegexes) # HACKER's INFO # To get a list of RegEx for invalid hosts, use: # grep qr/ $0 =pod =head1 NAME o-saft.cgi - wrapper script to start o-saft.pl as CGI script =head1 DESCRIPTIONS Calls ./o-saft.pl if first parameter is I<--cgi>. Returns results as: Content-type: text/plain;charset=utf-8 If parameter I<--format=html> is given returns results as: Content-type: text/html;charset=utf-8 Does some lazy checks according parameters and exits if found: =over 4 =item not allowed characters in parameters, except: a-zA-Z0-9,.:_&\!\/=\+- =item not allowed options: --env* --exe* --lib* --call* --openssl* =item illegal hostnames or IPs: localhost, (0|10|127|169|172|192|224|240|255).X.X.X *.local =item any IPv6 addresses in URLs =back Exits silently if any above error is detected. Exits with verbose error message for detected errors, if environment variable I is set. =head1 DEBUG If the environment variable I is set, detailed error messages are printed. This is only useful when used on command line, but not within the web server. =head1 EXAMPLE Call as CGI from command line: env "QUERY_STRING=--cgi&--host=demo.tld&--cmd=cn" o-saft.cgi For testing only, call from command line: o-saft.cgi --cgi --host=demo.tld --cmd=cn =head1 SEE ALSO =head2 L =head1 AUTHOR 12-sep-12 Achim Hoffmann =cut use strict; use warnings; my $SID_cgi = "@(#) o-saft.cgi 1.27 18/11/15 00:07:34"; my $VERSION = '18.11.18'; my $me = $0; $me =~ s#.*/##; my $mepath = $0; $mepath =~ s#/[^/\\]*$##; $mepath = './' if ($mepath eq $me); local $| = 1; # don't buffer, synchronize STDERR and STDOUT ############################################################################## my $osaft = "$mepath/o-saft.pl"; # $osaft = '/bin/o-saft/o-saft.pl'; # <== adapt as needed my $openssl = '/usr/local/openssl/bin/openssl'; # <== adapt as needed # NOTE tainted perl (-T) will complain if the path given in $osaft # or $openssl is writable; it also must be an absolute path ############################################################################## my @argv = @ARGV; sub _warn_and_exit { #? print error and exit my $txt = shift; die "**ERROR: $txt" if ($ENV{'OSAFT_CGI_TEST'}); ## no critic qw(ErrorHandling::RequireCarping) # #################################################################### # # This function should print an empty string and exit with status 0 in # production environments. # Above detailed error message is for testing only and not intended to # be used and seen when run as a CGI script in a web server. # As the client (browser) is not able to set the environment variable, # the code should be safe. # # #################################################################### print ""; exit 0; } # _warn_and_exit if ($ENV{'OSAFT_CGI_TEST'}) { print "**WARNNG: test mode: die with detailed messages on errors\n"; } if (not $ENV{'QUERY_STRING'}) { print "**WARNNG: test mode: restart using args as value in QUERY_STRING\n"; _warn_and_exit "call without parameters" if (0 > $#argv); # may be a command line call without QUERY_STRING environment variable # call myself with QUERY_STRING to simulate a call from CGI # NOTE: this produces output before any HTTP header; that's ok here ## no critic qw(Variables::RequireLocalizedPunctuationVars) $ENV{'QUERY_STRING'} = join('&', @argv); $ENV{'QUERY_STRING'} =~ s/[+]/%2b/g; $ENV{'QUERY_STRING'} =~ s/[ ]/%20/g; exec $0; } if ($me =~/\.cgi$/) { # CGI mode is pretty simple: # use QUERY_STRING and POST data and URL-decode once # check if data contains suspicious characters, die if so # NOTE that % is suspicious as we decode only once # check if target is suspicious host or net, die if so # then split data at & to get our options and arguments # ready we go with the existing code :) # NOTE: in true CGI-mode, QUERY_STRING just contains the form fields, # when used with our own osaft: schema, it also contains the # the schema and path, i.e. osaft:///o-saft.cgi? # NOTE: for debugging using system() writing to a file is better than # using perl's print(). my $cgi = 0; my $typ = 'plain'; my $qs = ''; $qs = $ENV{'QUERY_STRING'} if (defined $ENV{'QUERY_STRING'}); #dbx# system "echo '$qs #' >> /tmp/osaft-handler.log"; $qs =~ s/^"?(.*?)"?$/$1/; # remove enclosing " (windows problem) $qs =~ s#^o-?saft://##g; # remove schema if any (used in o-saft.cgi.html) $qs =~ s#^[^?]*\?##g; # remove path left of ? if any (used in o-saft.cgi.html) $qs =~ s/[+]/ /g; $qs =~ s/(?:%([0-9a-f]{2,2}))/pack("H2", $1)/egi; # url-decode once undef @argv; push(@argv, split(/[&?]/, $qs)); #dbx# system "echo '@argv :' >> /tmp/osaft-handler.log"; $cgi = shift @argv || ''; # remove first argument, which must be --cgi # || '' avoids uninitialized value push(@argv, "--cgi-exec"); # argument required for some more checks die "**ERROR: CGI mode requires strict settings\n" if ($cgi !~ /^--cgi=?$/); $typ = 'html' if ($qs =~ m/--format=html/); print "X-Cite: Perl is a mess. But that's okay, because the problem space is also a mess. Larry Wall\r\n"; print "X-O-Saft: OWASP – SSL advanced forensic tool 1.27\r\n"; print "Content-type: text/$typ; charset=utf-8\r\n";# for --usr* only print "\r\n"; if (defined $ENV{'REQUEST_METHOD'}) { # ToDo: NOT WORKING $qs .= <> if ($ENV{'REQUEST_METHOD'} eq 'POST');# add to GET data } foreach my $dangerous ( # check for suspicious characters and targets #dbx# print "#dbx: $dangerous # $qs\n"; qr/[^a-zA-Z0-9,.:_&\!\/=\+-]/i, # dangerous characters anywhere # above whitelist for allowed characters! # FIXME: this blocks also valid IPv6 in URL because of [ and/or ] qr/(cmd=list|--(env|exe|lib|call|openssl))/i, # dangerous commands and options # RFC addresses are not allowed, see https://tools.ietf.org/html/rfc5735 # 0.0.0.0/8 This Network # 10.0.0.0/8 Private-Use Networks # 100.64.0.0/10 ? # 127.0.0.0/8 Loopback # 169.254.0.0/16 Link local # 172.16.0.0/12 Private-Use Networks # 192.0.0.0/24 IETF Protocol Assignments # 192.0.2.0/24 TEST-NET-1 # 192.88.99.0/24 6to4 Relay Anycast # 192.168.0.0/16 Private-Use Networks # 198.18.0.0/15 Network Interconnect, Device Benchmark Testing # 198.51.100.0/24 TEST-NET-2 # 203.0.13.0/24 TEST-NET-3 # 224.0.0.0/4 224.0.0.0 - 239.255.255.255 Multicast # # https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml # 240.0.0.0/4 240.0.0.0 - 255.255.255.255 Reserved for future use # 255.255.255.255/32 qr/(-(host|url)=(localhost|(ffff)?::1|(ffff:)?7f00:1))/i, # localhost # TODO: IPv6 localhost: [7f00:1] .. [7fff:ffff] qr/(-(host|url)=((ffff:)?(0|10|127|22[4-9]|23[0-9]|24[0-9]|25[0-5])\.[\d]+.[\d]+.[\d]+))/i, # loopback, mulicast qr/(-(host|url)=((ffff:)?(100\.64|169.254|172\.(1[6-9]|2\d|3[01])|192\.168|198\.18)\.[\d]+.[\d]+))/i, # common Class B RFC networks for private use # TODO: 100.64.0.0/10 is not really class B qr/(-(host|url)=((ffff:)?(192\.0\.[02]|192.88\.99|198\.51\.100|203\.0\.13)\.[\d]+))/i, # common class C RFC networks for private use qr/(-(host|url)=.*?\.local$)/i, # multicast domain .local (RFC6762) qr/(-(host|url)=((fe80|fe[c-f][0-9a-f]:)))/i, # IPv6 link local or site local qr/(-(host|url)=((ff0[0-9a-f]|f[c-d][0-9a-f][0-9a-f]:)))/i, # IPv6 multicast or unique local unicast (RFC6762) qr{(-(host|url)=([a-z0-9:]+)?(//)?\[?([a-f0-9:]+)])}i, # IPv6 # NOTE: final ] not escaped, it's a literal character here! # FIXME: blocks any IPv6 # TODO: IPv6 still experimental # possible formats to be blocked: # ftp://[::ffff:7f00:1]/path # //[::ffff:7f00:1]/path # [::ffff:7f00:1]/path # ::ffff:7f00:1/path # illegal, but possible # HTTPS://[::ffff:7f00:1]:80/path # any:[::ffff:7f00:1]/path # also matched # FIXME: also blocks FQDN:port like cafe:4711/path ) { #dbx# print "#dbx: $dangerous # $qs\n"; _warn_and_exit "$dangerous" if ($qs =~ m#$dangerous#); } #dbx# print "\nQS: $qs\n"; local $ENV{LD_LIBRARY_PATH} = "$openssl/lib/"; local $ENV{PATH} = "$openssl/bin/" . ':' . $ENV{PATH}; local $| = 1; # don't buffer, synchronize STDERR and STDOUT #dbx# system "$osaft @argv >> /tmp/osaft-handler.log"; exec $osaft, @argv; # exec is ok, as we call ourself only # TODO: Win32 nost tested: exec 'perl.exe', $osaft, @argv; } exit 0; # never reached O-Saft-19.01.19/o-saft.pl000077500000000000000000017110421342117255600146120ustar00rootroot00000000000000#!/usr/bin/perl #!############################################################################# #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!#---------------------------------------------------------------------------- #!# If this tool is valuable for you and we meet some day, you can spend me an #!# O-Saft. I'll accept good wine or beer too :-). Meanwhile -- 'til we meet -- #!# your're encouraged to make a donation to any needy child you see. Thanks! #!#---------------------------------------------------------------------------- #!# This software is provided "as is", without warranty of any kind, express or #!# implied, including but not limited to the warranties of merchantability, #!# fitness for a particular purpose. In no event shall the copyright holders #!# or authors be liable for any claim, damages or other liability. #!# This software is distributed in the hope that it will be useful. #!# #!# This software is licensed under GPLv2. #!# #!# GPL - The GNU General Public License, version 2 #!# as specified in: http://www.gnu.org/licenses/gpl-2.0 #!# or a copy of it https://github.com/OWASP/O-Saft/blob/master/LICENSE.md #!# Permits anyone the right to use and modify the software without limitations #!# as long as proper credits are given and the original and modified source #!# code are included. Requires that the final product, software derivate from #!# the original source or any software utilizing a GPL component, such as #!# this, is also licensed under the same GPL license. #!############################################################################# #!# WARNING: #!# This is no "academically" certified code, but written to be understood and #!# modified by humans (you:) easily. Please see the documentation in section #!# "Program Code" (file coding.txt) if you want to improve the program. # NOTE: Perl's `use' and `require' will be used for common and well known Perl # modules only. All other modules, in particular our own ones, are loaded # using an internal function, see _load_file(). All required modules are # included as needed. This keeps away noisy messages and allows to be run # and print some information even if installed incompletely. ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # NOTE: see .perlcritic for detailed description of "no critic" ## no critic qw(Variables::RequireLocalizedPunctuationVars) # NOTE: Perl::Critic seems to be buggy as it does not honor the allow option # for this policy (see .perlcriticrc also). It even doesn't honor the # setting here, hence it's disabled at each line using $ENV{} = ... ## no critic qw(Variables::ProhibitPackageVars) # NOTE: we have a couple of global variables, but do not want to write them in # all CAPS (as it would be required by Perl::Critic) ## no critic qw(ErrorHandling::RequireCarping) # NOTE: Using carp() is nice in modules, as it also prints the calling stack. # But here it is sufficient to see the line number, hence we use warn(). ## no critic qw(Subroutines::ProhibitExcessComplexity) # NOTE: It's the nature of checks to be complex, hence don't complain. ## no critic qw(Modules::ProhibitExcessMainComplexity) # NOTE: Yes, it's a high, very high complexity here. # BUG: this pragma does not work here, needs mccabe value ... use strict; use warnings; use constant { ## no critic qw(ValuesAndExpressions::ProhibitConstantPragma) # NOTE: use Readonly instead of constant is not possible, because constants # are used for example in the BEGIN section. Constants can be used # there but not Readonly variables. Hence "no critic" must be used. SID => "@(#) yeast.pl 1.850 19/01/20 23:10:09", STR_VERSION => "19.01.19", # <== our official version number }; sub _set_binmode { # SEE Perl:binmode() my $layer = shift; binmode(STDOUT, $layer); binmode(STDERR, $layer); return; } # _set_binmode _set_binmode(":unix:utf8"); # set I/O layers very early sub _is_argv { my $rex = shift; return (grep{/$rex/i} @ARGV); } # SEE Note:ARGV sub _is_v_trace { my $rex = shift; return (grep{/--(?:v|trace$)/} @ARGV); } # case-sensitive! SEE Note:ARGV # need to check @ARGV directly as this is called before any options are parsed our $time0 = time(); sub _yeast_TIME(@) { # print timestamp if --trace-time was given; similar to _y_CMD my @txt = @_; my $me = $0; $me =~ s{.*?([^/\\]+)$}{$1}; my $now = time() - ($time0 || 0); $now = time() if _is_argv('(?:--time.*absolut)'); if (_is_argv('(?:--trace.?(?:time|cmd))') > 0) { printf("#$me %02s:%02s:%02s CMD: %s\n", (localtime($now))[2,1,0], @txt); } return; } # _yeast_TIME sub _yeast_EXIT($) { # exit if parameter matches given argument in @ARGV my $txt = shift; # example: INIT0 - initialization start my $arg = $txt; $arg =~ s# .*##; # strip off anything right of a space if ((grep{/(?:([+]|--)$arg).*/i} @ARGV) > 0) { # case-sensitve, cannot use _is_argv() printf STDERR ("#o-saft.pl _yeast_EXIT $txt\n"); exit 0; } return; } # _yeast_EXIT sub _yeast_NEXT($) { # return 1 if parameter matches given argument in @ARGV; 0 otherwise my $txt = shift; # example: INIT0 - initialization start my $arg = $txt; $arg =~ s# .*##; # strip off anything right of a space if ((grep{/(?:([+]|--)$arg).*/i} @ARGV) > 0) { # case-sensitve, cannot use _is_argv() printf STDERR ("#o-saft.pl _yeast_EXIT $txt\n"); return 1; } return 0; } # _yeast_NEXT sub _version_exit { print STR_VERSION . "\n"; exit 0; } # print VERSION and exit #$DB::single=1; # for debugging; start with: PERL5OPT='-dt' $0 BEGIN { _yeast_TIME("BEGIN{"); _yeast_EXIT("exit=BEGIN0 - BEGIN start"); sub _VERSION() { return STR_VERSION; } # required in o-saft-man.pm # SEE Perl:BEGIN , Therefore this scope is used for --help=* options only. my $_me = $0; $_me =~ s#.*[/\\]##; my $_path = $0; $_path =~ s#[/\\][^/\\]*$##; unshift(@INC, # NOTE that / works here even for Windoze "./", "./lib", # we support some local lib directories $_path, # user-friendly: add path of myself also "/bin", # special installation on portable media ); # handle simple help very quickly; _is_argv() cannot be used because upper case if ((grep{/(?:--|\+)VERSION/} @ARGV) > 0) { _version_exit(); } # be smart to users if systems behave strange :-/ print STDERR "**WARNING: 019: on $^O additional option --v required, sometimes ...\n" if ($^O =~ m/MSWin32/); _yeast_EXIT("exit=BEGIN1 - BEGIN end"); } # BEGIN _yeast_TIME("BEGIN}"); # missing for +VERSION, however, +VERSION --trace-TIME makes no sense _yeast_EXIT("exit=INIT0 - initialization start"); our $osaft_standalone = 0; # SEE Note:Stand-alone ## PACKAGES # dummy comment used by some generators, do not remove use osaft; # get most of our configuration; it's ok to die if missing #_____________________________________________________________________________ #________________________________________________________________ variables __| our $VERSION= STR_VERSION; my $me = $cfg{'me'}; # use a short and easy to remember variable name my $mepath = $0; $mepath =~ s#/[^/\\]*$##; $mepath = "./" if ($mepath eq $me); $cfg{'mename'} = $me; printf("#$me %s\n", join(" ", @ARGV)) if _is_argv('(?:--trace[_.-]?CLI$)'); # now set @INC # NOTE: do not use "-I . lib/" in hashbang line as it will be pre- and appended # don't add if $mepath == ./ as it most likely is already part of @INC # also note that this setting only applies to `require' but not `use' directives unshift(@INC, "$mepath", "$mepath/lib") ;#if ($mepath ne "./"); #dbx print STDERR "INC: ".join(" ",@INC) . "\n"; my $arg = ""; my @argv = (); # all options, including those from RC-FILE # will be used when ever possible instead of @ARGV # arrays to collect data for debugging, they are global! our $warning= 1; # print warnings; need this variable very early #| definitions: forward declarations #| ------------------------------------- sub __SSLinfo($$$); sub _is_intern($); # Perl avoid: main::_is_member() called too early to check prototype sub _is_member($$); # " #| README if any #| ------------------------------------- #if (open(my $rc, '<', "o-saft-README")) { print <$rc>; close($rc); exit 0; }; # SEE Since VERSION 16.06.16 #| CGI #| ------------------------------------- my $cgi = 0; $cgi = 1 if ((grep{/(?:--cgi-?(?:exec|trace))/i} @ARGV) > 0); #if ($me =~/\.cgi$/) { SEE Since VERSION 18.12.18 #die STR_ERROR, "020: CGI mode requires strict settings" if (_is_argv('--cgi=?') <= 0); #} # CGI #| definitions: debug and tracing #| ------------------------------------- # functions and variables used very early in main sub _dprint { my @txt = @_; local $\ = "\n"; print STDERR STR_DBX, join(" ", @txt); return; } sub _dbx { my @txt = @_; _dprint(@txt); return; } # alias for _dprint sub _warn { #? print warning if wanted; SEE Perl:Message Numbers # don't print if ($warning <= 0); my @txt = @_; return if _is_argv('(?:--no.?warn)'); # ugly hack 'cause we won't pass $warning local $\ = "\n"; print(STR_WARN, join(" ", @txt)); # TODO: in CGI mode warning must be avoided until HTTP header written _yeast_EXIT("exit=WARN - exit on first warning"); return; } # _warn sub _warn_and_exit { #? print warning that --experimental option is required #-method: name of function where this message is called #-command: name of command subject to this message my @txt = @_; local $\ = "\n"; if (_is_argv('(?:--experimental)') > 0) { my $method = shift; _trace("_warn_and_exit $method: " . join(" ", @txt)); } else { printf(STR_WARN . "099: (%s) --experimental option required to use '%s' functionality. Please send us your feedback about this functionality to o-saft(at)lists.owasp.org\n", @txt); exit(1); } return; } # _warn_and_exit sub _hint { #? print hint message if wanted # don't print if --no-hint given my @txt = @_; return if _is_argv('(?:--no.?hint)'); local $\ = "\n"; print(STR_HINT, join(" ", @txt)); return; } # _hint sub _warn_nosni { #? print warning and hint message if SNI is not supported by SSL my $err = shift; my $ssl = shift; my $sni = shift; return if ($sni < 1); return if ($ssl !~ m/^SSLv[23]/); # SSLv2 has no SNI; SSLv3 has originally no SNI _warn("$err $ssl does not support SNI; cipher checks are done without SNI"); return; } # _warn_nosni sub _print_read { #? print information which file will be read #? will only be written if --v or --warn or --trace is given and --cgi-exec #? or --no-header are not given # $cgi is not (yet) available, hence we use @ARGV to check for options # $cfg{'out_header'} is also not yet properly set, see LIMITATIONS also my ($fil, @txt) = @_; #_dbx "ARGV @ARGV : ". (grep{/(?:--no.?header|--cgi)/i} @ARGV); return if (0 < (grep{/(?:--no.?header|--cgi)/i} @ARGV)); # --cgi-exec or --cgi-trace return if (0 >= (grep{/(?:--warn|--v$|--trace)/i} @ARGV)); printf("=== reading: %s (%s) ===\n", $fil, @txt); return; } # _print_read sub _load_file { # load file with Perl's require using the paths in @INC # use `$0 +version --v' to see which files are loaded my $fil = shift; my $txt = shift; my $err = ""; #{ # # currently (2017) disabled, until all modules can be included with require # no warnings qw(once); # return "" if (defined($osaft_standalone)); # SEE Note:Stand-alone #} # need eval to catch "Can't locate ... in @INC ..." eval {require $fil;} or _warn("101: 'require $fil' failed"); $err = $@; chomp $err; if ($err eq "") { $txt = "$txt done"; $INC{$fil} = "." . $INC{$fil} if ("/$fil" eq $INC{$fil}); # fix ugly %INC # FIXME: above fix fails for NET::SSL* and absolute path like --trace=/file $fil = $INC{$fil}; } else { $txt = "$txt failed"; } push(@{$dbx{file}}, $fil); _print_read($fil, $txt); return $err; } # _load_file #| read RC-FILE if any #| ------------------------------------- _yeast_TIME("cfg{"); _yeast_EXIT("exit=CONF0 - RC-FILE start"); if (_is_argv('(?:--rc)') > 0) { # (re-)compute default RC-File $cfg{'RC-FILE'} = $0; # from directory where $0 found $cfg{'RC-FILE'} =~ s#($cfg{'me'})$#.$1#; } if (_is_argv('(?:--rc=)') > 0) { # other RC-FILE given $cfg{'RC-FILE'} = (grep{/--rc=.*/} @ARGV)[0]; # get value --rc=* $cfg{'RC-FILE'} =~ s#--rc=##; # stripp off --rc= # no check if file exists, will be done below } print "#o-saft.pl RC-FILE: $cfg{'RC-FILE'}\n" if _is_v_trace(); my @rc_argv = ""; if (_is_argv('(?:--no.?rc)') <= 0) { # only if not inhibited # we do not use a function for following to avoid passing @argv, @rc_argv if (open(my $rc, '<:encoding(UTF-8)', "$cfg{'RC-FILE'}")) { push(@{$dbx{file}}, $cfg{'RC-FILE'}); _print_read( "$cfg{'RC-FILE'}", "RC-FILE done"); ## no critic qw(ControlStructures::ProhibitMutatingListFunctions) # NOTE: the purpose here is to *change the source array" @rc_argv = grep{!/\s*#[^\r\n]*/} <$rc>; # remove comment lines @rc_argv = grep{s/[\r\n]//} @rc_argv; # remove newlines @rc_argv = grep{s/\s*([+-]-?)/$1/} @rc_argv;# get options and commands, remove leading spaces ## use critic close($rc); _warn("052: option with trailing spaces '$_'") foreach (grep{m/\s+$/} @rc_argv); push(@argv, @rc_argv); print "#o-saft.pl $cfg{'RC-FILE'}: #{" . join("\n ", "", @rc_argv) . "\n#}\n" if _is_v_trace(); } else { _print_read("$cfg{'RC-FILE'}", "RC-FILE: $!") if _is_v_trace(); } } _yeast_EXIT("exit=CONF1 - RC-FILE end"); $cfg{'RC-ARGV'} = [@rc_argv]; %{$cfg{'done'}} = ( # internal administration 'targets' => 0, 'dbxfile' => 0, 'rc_file' => 0, 'init_all' => 0, 'ssl_failed'=> 0, # local counter for SSL connection errors 'ssl_errors'=> 0, # total counter for SSL connection errors 'arg_cmds' => [], # contains all commands given as argument # all following need to be reset for each host, which is done in # _resetchecks() by matching the key against ^check or ^cipher 'default_get' => 0, 'ciphers_all' => 0, 'ciphers_get' => 0, 'checkciphers' => 0, # not used, as it's called multiple times 'checkprefered' => 0, 'check02102'=> 0, 'check03116'=> 0, 'check2818' => 0, 'check6125' => 0, 'check7525' => 0, 'checkdates'=> 0, 'checksizes'=> 0, 'checkbleed'=> 0, 'checkcert' => 0, 'checkprot' => 0, 'checkdest' => 0, 'checkhttp' => 0, 'checksni' => 0, 'checkssl' => 0, 'checkalpn' => 0, 'checkdv' => 0, 'checkev' => 0, 'check_dh' => 0, 'check_url' => 0, # not used, as it's called multiple times 'check_certchars' => 0, ); push(@argv, @ARGV); # got all now push(@ARGV, "--no-header") if ((grep{/--no-?header/} @argv)); # if defined in RC-FILE, needed in _warn() #| read DEBUG-FILE, if any (source for trace and verbose) #| ------------------------------------- my $err = ""; my @dbx = grep{/--(?:trace|v$|yeast)/} @argv; # may have --trace=./file if (($#dbx >= 0) and (grep{/--cgi=?/} @argv) <= 0) { # SEE Note:CGI mode $arg = "o-saft-dbx.pm"; $arg = $dbx[0] if ($dbx[0] =~ m#/#); $arg =~ s#[^=]+=##; # --trace=./myfile.pl $err = _load_file($arg, "trace file"); if ($err ne "") { die STR_ERROR, "012: $err" unless (-e $arg); # no need to continue if file with debug functions does not exist # NOTE: if $mepath or $0 is a symbolic link, above checks fail # we don't fix that! Workaround: install file in ./ } } else { # debug functions are defined in o-saft-dbx.pm and loaded on demand # they must be defined always as they are used wheter requested or not sub _yeast_init {} sub _yeast_exit {} sub _yeast_args {} sub _yeast_data {} sub _yeast_ciphers{} sub _yeast {} sub _y_ARG {} sub _y_CMD {} sub _v_print {} sub _v2print {} sub _v3print {} sub _v4print {} sub _vprintme {} sub _trace {} sub _trace1 {} sub _trace2 {} sub _trace3 {} sub _trace_cmd {} } #| read USER-FILE, if any (source with user-specified code) #| ------------------------------------- if ((grep{/--(?:use?r)/} @argv) > 0) { # must have any --usr option $err = _load_file("o-saft-usr.pm", "user file"); if ($err ne "") { # continue without warning, it's already printed in "=== reading: " line sub usr_version { return ""; }; # dummy stub, see o-saft-usr.pm sub usr_pre_init {}; # " sub usr_pre_file {}; # " sub usr_pre_args {}; # " sub usr_pre_exec {}; # " sub usr_pre_cipher {}; # " sub usr_pre_main {}; # " sub usr_pre_host {}; # " sub usr_pre_info {}; # " sub usr_pre_open {}; # " sub usr_pre_cmds {}; # " sub usr_pre_data {}; # " sub usr_pre_print {}; # " sub usr_pre_next {}; # " sub usr_pre_exit {}; # " } } usr_pre_init(); #| initialize defaults #| ------------------------------------- #!# set defaults #!# ------------------------------------- #!# To make (programmer's) life simple, we try to avoid complex data structure, #!# which are error-prone, by using a couple of global variables. #!# As there are no plans to run this tool in threaded mode, this should be ok. #!# Please see "Program Code" in o-saft-man.pm too. #!# #!# Here's an overview of the used global variables (mostly defined in o-saft-lib.pm): #!# $me - the program name or script name with path stripped off #!# %prot - collected data per protocol (from Net::SSLinfo) #!# %prot_txt - labes for %prot #!# @cipher_results - where we store the results as: [SSL, cipher, "yes|no"] #!# %data - labels and correspondig value (from Net::SSLinfo) #!# %checks - collected and checked certificate data #!# collected and checked target (connection) data #!# collected and checked connection data #!# collected and checked length and count data #!# HTTP vs. HTTPS checks #!# %shorttexts - same as %checks, but short texts #!# %data_oid - map known OIDs to human readable description #!# %info - like $data, but for data not retrived from Net::SSLinfo #!# %cmd - configuration for external commands #!# %cfg - configuration for commands and options herein #!# %text - configuration for message texts #!# %scores - scoring values #!# %ciphers_desc - description of %ciphers data structure #!# %ciphers - our ciphers #!# %cipher_names - (hash)map of cipher constant-names to names #!# %cipher_alias - (hash)map of cipher aliases (used in other programs) #!# #!# All %check_* contain a default 'score' value of 10, see --cfg-score #!# option how to change that. # NOTE: all keys in data and check_* must be unique 'cause of shorttexts!! # NOTE: all keys in check_* and checks must be in lower case letters!! # 'cause generic conversion of +commands to keys # exception are the keys related to protocol, i.e. SSLV3, TLSv11 # # Note according perlish programming style: # references to $arr->{'val') are most often simplified as $arr->{val) # same applies to 'txt', 'typ' and 'score' # some temporary variables used in main my $host = ""; # the host currently processed in main my $port = ""; # the port currently used in main my $legacy = ""; # the legacy mode used in main my $verbose = 0; # verbose mode used in main # above host, port, legacy and verbose are just shortcuts for corresponding # values in $cfg{}, used for better human readability my $info = 0; # set to 1 if +info my $check = 0; # set to 1 if +check was used my $quick = 0; # set to 1 if +quick was used my $cmdsni = 0; # set to 1 if +sni or +sni_check was used my $sniname = undef;# will be set to $cfg{'sni_name'} as this changes for each host our %info = ( # same as %data with values only; keys are identical to %data 'alpn' => "", 'npn' => "", 'alpns' => "", 'npns' => "", ); our %data0 = (); # same as %data but has 'val' only, no 'txt' # contains values from first connection only # NOTE: do not change names of keys in %data and all %check_* as these keys # are used in output with --trace-key our %data = ( # connection and certificate details # values from Net::SSLinfo, will be processed in print_data() #!#----------------+-----------------------------------------------------------+----------------------------------- #!# +command value from Net::SSLinfo::*() label to be printed #!#----------------+-----------------------------------------------------------+----------------------------------- 'cn_nosni' => {'val' => "", 'txt' => "Certificate CN without SNI"}, 'pem' => {'val' => sub { Net::SSLinfo::pem( $_[0], $_[1])}, 'txt' => "Certificate PEM"}, 'text' => {'val' => sub { Net::SSLinfo::text( $_[0], $_[1])}, 'txt' => "Certificate PEM decoded"}, 'cn' => {'val' => sub { Net::SSLinfo::cn( $_[0], $_[1])}, 'txt' => "Certificate Common Name"}, 'subject' => {'val' => sub { Net::SSLinfo::subject( $_[0], $_[1])}, 'txt' => "Certificate Subject"}, 'issuer' => {'val' => sub { Net::SSLinfo::issuer( $_[0], $_[1])}, 'txt' => "Certificate Issuer"}, 'altname' => {'val' => sub { Net::SSLinfo::altname( $_[0], $_[1])}, 'txt' => "Certificate Subject's Alternate Names"}, 'cipher_selected'=>{'val' => sub { Net::SSLinfo::selected( $_[0], $_[1])}, 'txt' => "Selected Cipher"}, # SEE Note:Selected Cipher 'ciphers_local' => {'val' => sub { Net::SSLinfo::cipher_openssl()}, 'txt' => "Local SSLlib Ciphers"}, 'ciphers' => {'val' => sub { join(" ", Net::SSLinfo::ciphers($_[0], $_[1]))}, 'txt' => "Client Ciphers"}, 'dates' => {'val' => sub { join(" .. ", Net::SSLinfo::dates($_[0], $_[1]))}, 'txt' => "Certificate Validity (date)"}, 'before' => {'val' => sub { Net::SSLinfo::before( $_[0], $_[1])}, 'txt' => "Certificate valid since"}, 'after' => {'val' => sub { Net::SSLinfo::after( $_[0], $_[1])}, 'txt' => "Certificate valid until"}, 'aux' => {'val' => sub { Net::SSLinfo::aux( $_[0], $_[1])}, 'txt' => "Certificate Trust Information"}, 'email' => {'val' => sub { Net::SSLinfo::email( $_[0], $_[1])}, 'txt' => "Certificate Email Addresses"}, 'pubkey' => {'val' => sub { Net::SSLinfo::pubkey( $_[0], $_[1])}, 'txt' => "Certificate Public Key"}, 'pubkey_algorithm'=>{'val'=> sub { Net::SSLinfo::pubkey_algorithm($_[0],$_[1])},'txt' => "Certificate Public Key Algorithm"}, 'pubkey_value' => {'val' => sub { __SSLinfo('pubkey_value', $_[0], $_[1])}, 'txt' => "Certificate Public Key Value"}, 'modulus_len' => {'val' => sub { Net::SSLinfo::modulus_len( $_[0], $_[1])}, 'txt' => "Certificate Public Key Length"}, 'modulus' => {'val' => sub { Net::SSLinfo::modulus( $_[0], $_[1])}, 'txt' => "Certificate Public Key Modulus"}, 'modulus_exponent'=>{'val'=> sub { Net::SSLinfo::modulus_exponent($_[0],$_[1])},'txt' => "Certificate Public Key Exponent"}, 'serial' => {'val' => sub { Net::SSLinfo::serial( $_[0], $_[1])}, 'txt' => "Certificate Serial Number"}, 'serial_hex' => {'val' => sub { Net::SSLinfo::serial_hex( $_[0], $_[1])}, 'txt' => "Certificate Serial Number (hex)"}, 'serial_int' => {'val' => sub { Net::SSLinfo::serial_int( $_[0], $_[1])}, 'txt' => "Certificate Serial Number (int)"}, 'certversion' => {'val' => sub { Net::SSLinfo::version( $_[0], $_[1])}, 'txt' => "Certificate Version"}, 'sigdump' => {'val' => sub { Net::SSLinfo::sigdump( $_[0], $_[1])}, 'txt' => "Certificate Signature (hexdump)"}, 'sigkey_len' => {'val' => sub { Net::SSLinfo::sigkey_len( $_[0], $_[1])}, 'txt' => "Certificate Signature Key Length"}, 'signame' => {'val' => sub { Net::SSLinfo::signame( $_[0], $_[1])}, 'txt' => "Certificate Signature Algorithm"}, 'sigkey_value' => {'val' => sub { __SSLinfo('sigkey_value', $_[0], $_[1])}, 'txt' => "Certificate Signature Key Value"}, 'trustout' => {'val' => sub { Net::SSLinfo::trustout( $_[0], $_[1])}, 'txt' => "Certificate trusted"}, 'extensions' => {'val' => sub { __SSLinfo('extensions', $_[0], $_[1])}, 'txt' => "Certificate extensions"}, 'tlsextdebug' => {'val' => sub { __SSLinfo('tlsextdebug', $_[0], $_[1])}, 'txt' => "TLS extensions (debug)"}, 'tlsextensions' => {'val' => sub { __SSLinfo('tlsextensions', $_[0], $_[1])}, 'txt' => "TLS extensions"}, 'ext_authority' => {'val' => sub { __SSLinfo('ext_authority', $_[0], $_[1])}, 'txt' => "Certificate extensions Authority Information Access"}, 'ext_authorityid'=>{'val' => sub { __SSLinfo('ext_authorityid', $_[0], $_[1])}, 'txt' => "Certificate extensions Authority key Identifier"}, 'ext_constraints'=>{'val' => sub { __SSLinfo('ext_constraints', $_[0], $_[1])}, 'txt' => "Certificate extensions Basic Constraints"}, 'ext_cps' => {'val' => sub { __SSLinfo('ext_cps', $_[0], $_[1])}, 'txt' => "Certificate extensions Certificate Policies"}, 'ext_cps_cps' => {'val' => sub { __SSLinfo('ext_cps_cps', $_[0], $_[1])}, 'txt' => "Certificate extensions Certificate Policies: CPS"}, 'ext_cps_policy'=> {'val' => sub { __SSLinfo('ext_cps_policy', $_[0], $_[1])}, 'txt' => "Certificate extensions Certificate Policies: Policy"}, 'ext_cps_notice'=> {'val' => sub { __SSLinfo('ext_cps_notice', $_[0], $_[1])}, 'txt' => "Certificate extensions Certificate Policies: User Notice"}, 'ext_crl' => {'val' => sub { __SSLinfo('ext_crl', $_[0], $_[1])}, 'txt' => "Certificate extensions CRL Distribution Points"}, 'ext_subjectkeyid'=>{'val'=> sub { __SSLinfo('ext_subjectkeyid',$_[0], $_[1])}, 'txt' => "Certificate extensions Subject Key Identifier"}, 'ext_keyusage' => {'val' => sub { __SSLinfo('ext_keyusage', $_[0], $_[1])}, 'txt' => "Certificate extensions Key Usage"}, 'ext_extkeyusage'=>{'val' => sub { __SSLinfo('ext_extkeyusage', $_[0], $_[1])}, 'txt' => "Certificate extensions Extended Key Usage"}, 'ext_certtype' => {'val' => sub { __SSLinfo('ext_certtype', $_[0], $_[1])}, 'txt' => "Certificate extensions Netscape Cert Type"}, 'ext_issuer' => {'val' => sub { __SSLinfo('ext_issuer', $_[0], $_[1])}, 'txt' => "Certificate extensions Issuer Alternative Name"}, 'ocsp_uri' => {'val' => sub { Net::SSLinfo::ocsp_uri( $_[0], $_[1])}, 'txt' => "Certificate OCSP Responder URL"}, 'ocspid' => {'val' => sub { __SSLinfo('ocspid', $_[0], $_[1])}, 'txt' => "Certificate OCSP Hashes"}, 'ocsp_subject_hash' => {'val' => sub { __SSLinfo('ocsp_subject_hash', $_[0], $_[1])}, 'txt' => "Certificate OCSP Subject Hash"}, 'ocsp_public_hash' => {'val' => sub { __SSLinfo('ocsp_public_hash', $_[0], $_[1])}, 'txt' => "Certificate OCSP Public Key Hash"}, 'ocsp_response' => {'val' => sub { Net::SSLinfo::ocsp_response( $_[0], $_[1])}, 'txt' => "Target's OCSP Response"}, 'ocsp_response_data' => {'val' => sub { Net::SSLinfo::ocsp_response_data( $_[0], $_[1])}, 'txt' => "Target's OCSP Response Data"}, 'ocsp_response_status'=> {'val' => sub { Net::SSLinfo::ocsp_response_status( $_[0], $_[1])}, 'txt' => "Target's OCSP Response Status"}, 'ocsp_cert_status' => {'val' => sub { Net::SSLinfo::ocsp_cert_status($_[0], $_[1])}, 'txt' => "Target's OCSP Response Cert Status"}, 'ocsp_next_update' => {'val' => sub { Net::SSLinfo::ocsp_next_update($_[0], $_[1])}, 'txt' => "Target's OCSP Response Next Update"}, 'ocsp_this_update' => {'val' => sub { Net::SSLinfo::ocsp_this_update($_[0], $_[1])}, 'txt' => "Target's OCSP Response This Update"}, 'subject_hash' => {'val' => sub { Net::SSLinfo::subject_hash( $_[0], $_[1])}, 'txt' => "Certificate Subject Name Hash"}, 'issuer_hash' => {'val' => sub { Net::SSLinfo::issuer_hash( $_[0], $_[1])}, 'txt' => "Certificate Issuer Name Hash"}, 'selfsigned' => {'val' => sub { Net::SSLinfo::selfsigned( $_[0], $_[1])}, 'txt' => "Certificate Validity (signature)"}, 'fingerprint_type'=>{'val'=> sub { Net::SSLinfo::fingerprint_type($_[0],$_[1])},'txt' => "Certificate Fingerprint Algorithm"}, 'fingerprint_hash'=>{'val'=> sub { __SSLinfo('fingerprint_hash',$_[0], $_[1])}, 'txt' => "Certificate Fingerprint Hash Value"}, 'fingerprint_sha2'=>{'val'=> sub { __SSLinfo('fingerprint_sha2',$_[0], $_[1])}, 'txt' => "Certificate Fingerprint SHA2"}, 'fingerprint_sha1'=>{'val'=> sub { __SSLinfo('fingerprint_sha1',$_[0], $_[1])}, 'txt' => "Certificate Fingerprint SHA1"}, 'fingerprint_md5' =>{'val'=> sub { __SSLinfo('fingerprint_md5', $_[0], $_[1])}, 'txt' => "Certificate Fingerprint MD5"}, 'fingerprint' => {'val' => sub { __SSLinfo('fingerprint', $_[0], $_[1])}, 'txt' => "Certificate Fingerprint"}, 'cert_type' => {'val' => sub { Net::SSLinfo::cert_type( $_[0], $_[1])}, 'txt' => "Certificate Type (bitmask)"}, 'sslversion' => {'val' => sub { Net::SSLinfo::SSLversion( $_[0], $_[1])}, 'txt' => "Selected SSL Protocol"}, 'resumption' => {'val' => sub { Net::SSLinfo::resumption( $_[0], $_[1])}, 'txt' => "Target supports Resumption"}, 'renegotiation' => {'val' => sub { Net::SSLinfo::renegotiation( $_[0], $_[1])}, 'txt' => "Target supports Renegotiation"}, 'compression' => {'val' => sub { Net::SSLinfo::compression( $_[0], $_[1])}, 'txt' => "Target supports Compression"}, 'expansion' => {'val' => sub { Net::SSLinfo::expansion( $_[0], $_[1])}, 'txt' => "Target supports Expansion"}, 'krb5' => {'val' => sub { Net::SSLinfo::krb5( $_[0], $_[1])}, 'txt' => "Target supports Krb5"}, 'psk_hint' => {'val' => sub { Net::SSLinfo::psk_hint( $_[0], $_[1])}, 'txt' => "Target supports PSK Identity Hint"}, 'psk_identity' => {'val' => sub { Net::SSLinfo::psk_identity( $_[0], $_[1])}, 'txt' => "Target supports PSK"}, 'srp' => {'val' => sub { Net::SSLinfo::srp( $_[0], $_[1])}, 'txt' => "Target supports SRP"}, 'heartbeat' => {'val' => sub { __SSLinfo('heartbeat', $_[0], $_[1])}, 'txt' => "Target supports Heartbeat"}, 'next_protocols'=> {'val' => sub { Net::SSLinfo::next_protocols($_[0], $_[1])}, 'txt' => "Target's advertised protocols"}, # 'alpn' => {'val' => sub { Net::SSLinfo::alpn( $_[0], $_[1])}, 'txt' => "Target's selected protocol (ALPN)"}, # old, pre 17.04.17 version 'alpn' => {'val' => sub { return $info{'alpn'}; }, 'txt' => "Target's selected protocol (ALPN)"}, 'npn' => {'val' => sub { return $info{'npn'}; }, 'txt' => "Target's selected protocol (NPN)"}, 'alpns' => {'val' => sub { return $info{'alpns'}; }, 'txt' => "Target's supported ALPNs"}, 'npns' => {'val' => sub { return $info{'npns'}; }, 'txt' => "Target's supported NPNs"}, 'master_key' => {'val' => sub { Net::SSLinfo::master_key( $_[0], $_[1])}, 'txt' => "Target's Master-Key"}, 'session_id' => {'val' => sub { Net::SSLinfo::session_id( $_[0], $_[1])}, 'txt' => "Target's Session-ID"}, 'session_protocol'=>{'val'=> sub { Net::SSLinfo::session_protocol($_[0],$_[1])},'txt' => "Target's selected SSL Protocol"}, 'session_ticket'=> {'val' => sub { Net::SSLinfo::session_ticket($_[0], $_[1])}, 'txt' => "Target's TLS Session Ticket"}, 'session_lifetime'=>{'val'=> sub { Net::SSLinfo::session_lifetime($_[0],$_[1])},'txt' => "Target's TLS Session Ticket Lifetime"}, 'session_timeout'=>{'val' => sub { Net::SSLinfo::session_timeout($_[0],$_[1])}, 'txt' => "Target's TLS Session Timeout"}, 'session_starttime' => {'val' => sub { Net::SSLinfo::session_starttime($_[0],$_[1])}, 'txt' => "Target's TLS Session Start Time EPOCH"}, 'session_startdate' => {'val' => sub { Net::SSLinfo::session_startdate($_[0],$_[1])}, 'txt' => "Target's TLS Session Start Time locale"}, 'dh_parameter' => {'val' => sub { Net::SSLinfo::dh_parameter( $_[0], $_[1])}, 'txt' => "Target's DH Parameter"}, 'chain' => {'val' => sub { Net::SSLinfo::chain( $_[0], $_[1])}, 'txt' => "Certificate Chain"}, 'chain_verify' => {'val' => sub { Net::SSLinfo::chain_verify( $_[0], $_[1])}, 'txt' => "CA Chain Verification (trace)"}, 'verify' => {'val' => sub { Net::SSLinfo::verify( $_[0], $_[1])}, 'txt' => "Validity Certificate Chain"}, 'error_verify' => {'val' => sub { Net::SSLinfo::error_verify( $_[0], $_[1])}, 'txt' => "CA Chain Verification error"}, 'error_depth' => {'val' => sub { Net::SSLinfo::error_depth( $_[0], $_[1])}, 'txt' => "CA Chain Verification error in level"}, 'verify_altname'=> {'val' => sub { Net::SSLinfo::verify_altname($_[0], $_[1])}, 'txt' => "Validity Alternate Names"}, 'verify_hostname'=>{'val' => sub { Net::SSLinfo::verify_hostname( $_[0],$_[1])},'txt' => "Validity Hostname"}, 'https_protocols'=>{'val' => sub { Net::SSLinfo::https_protocols($_[0],$_[1])}, 'txt' => "HTTPS Alternate-Protocol"}, 'https_svc' => {'val' => sub { Net::SSLinfo::https_svc( $_[0], $_[1])}, 'txt' => "HTTPS Alt-Svc header"}, 'https_status' => {'val' => sub { Net::SSLinfo::https_status( $_[0], $_[1])}, 'txt' => "HTTPS Status line"}, 'https_server' => {'val' => sub { Net::SSLinfo::https_server( $_[0], $_[1])}, 'txt' => "HTTPS Server banner"}, 'https_location'=> {'val' => sub { Net::SSLinfo::https_location($_[0], $_[1])}, 'txt' => "HTTPS Location header"}, 'https_refresh' => {'val' => sub { Net::SSLinfo::https_refresh( $_[0], $_[1])}, 'txt' => "HTTPS Refresh header"}, 'https_alerts' => {'val' => sub { Net::SSLinfo::https_alerts( $_[0], $_[1])}, 'txt' => "HTTPS Error alerts"}, 'https_pins' => {'val' => sub { Net::SSLinfo::https_pins( $_[0], $_[1])}, 'txt' => "HTTPS Public Key Pins"}, 'https_body' => {'val' => sub { Net::SSLinfo::https_body( $_[0], $_[1])}, 'txt' => "HTTPS Body"}, 'https_sts' => {'val' => sub { Net::SSLinfo::https_sts( $_[0], $_[1])}, 'txt' => "HTTPS STS header"}, 'hsts_httpequiv'=> {'val' => sub { Net::SSLinfo::hsts_httpequiv($_[0], $_[1])}, 'txt' => "HTTPS STS in http-equiv"}, 'hsts_maxage' => {'val' => sub { Net::SSLinfo::hsts_maxage( $_[0], $_[1])}, 'txt' => "HTTPS STS MaxAge"}, 'hsts_subdom' => {'val' => sub { Net::SSLinfo::hsts_subdom( $_[0], $_[1])}, 'txt' => "HTTPS STS include sub-domains"}, 'hsts_preload' => {'val' => sub { Net::SSLinfo::hsts_preload( $_[0], $_[1])}, 'txt' => "HTTPS STS preload"}, 'http_protocols'=> {'val' => sub { Net::SSLinfo::http_protocols($_[0], $_[1])}, 'txt' => "HTTP Alternate-Protocol"}, 'http_svc' => {'val' => sub { Net::SSLinfo::http_svc( $_[0], $_[1])}, 'txt' => "HTTP Alt-Svc header"}, 'http_status' => {'val' => sub { Net::SSLinfo::http_status( $_[0], $_[1])}, 'txt' => "HTTP Status line"}, 'http_location' => {'val' => sub { Net::SSLinfo::http_location( $_[0], $_[1])}, 'txt' => "HTTP Location header"}, 'http_refresh' => {'val' => sub { Net::SSLinfo::http_refresh( $_[0], $_[1])}, 'txt' => "HTTP Refresh header"}, 'http_sts' => {'val' => sub { Net::SSLinfo::http_sts( $_[0], $_[1])}, 'txt' => "HTTP STS header"}, #------------------+---------------------------------------+------------------------------------------------------- 'options' => {'val' => sub { Net::SSLinfo::options( $_[0], $_[1])}, 'txt' => "<> used SSL options bitmask"}, 'fallback_protocol' => {'val' => sub { return $prot{'fallback'}->{val} }, 'txt' => "Target's fallback SSL Protocol"}, #------------------+---------------------------------------+------------------------------------------------------- # following not printed by default, but can be used as command # 'PROT' => {'val' => sub { return $prot{'PROT'}->{'default'} }, 'txt' => "Target default PROT cipher"}, ##### # all others will be added below #------------------+---------------------------------------+------------------------------------------------------- # following are used for checkdates() only, they must not be a command! # they are not printed with +info or +check; values are integer 'valid_years' => {'val' => 0, 'txt' => "certificate validity in years"}, 'valid_months' => {'val' => 0, 'txt' => "certificate validity in months"}, 'valid_days' => {'val' => 0, 'txt' => "certificate validity in days"}, # approx. value, accurate if < 30 'valid_host' => {'val' => 0, 'txt' => "dummy used for printing DNS stuff"}, ); # %data # need s_client for: compression|expansion|selfsigned|chain|verify|resumption|renegotiation|next_protocols| # need s_client for: krb5|psk_hint|psk_identity|srp|master_key|session_id|session_protocol|session_ticket|session_lifetime|session_timeout|session_starttime|session_startdate # add keys from %prot to %data, foreach my $ssl (keys %prot) { my $key = lc($ssl); # keys in data are all lowercase (see: convert all +CMD) $data{$key}->{val} = sub { return $prot{$ssl}->{'default'}; }; $data{$key}->{txt} = "Target default $prot{$ssl}->{txt} cipher"; } # NOTE: the comments prefixed with ## are used by third-party software, # for example o-saft.tcl uses a pattern like: # (?:my|our) check_(.*)=\( ## (.*) our %checks = ( # key => {val => "", txt => "label to be printed", score => 0, typ => "connection"}, # # default for 'val' is "" (empty string), default for 'score' is 0 # 'typ' is any of certificate, connection, destination, https, sizes # both will be set in sub _init_all(), please see below # the default value means "check = ok/yes", otherwise: "check =failed/no" ); # %checks my %check_cert = ( ## certificate data # collected and checked certificate data #------------------+----------------------------------------------------- # key label to be printed (description) #------------------+----------------------------------------------------- 'verify' => {'txt' => "Certificate chain validated"}, 'fp_not_md5' => {'txt' => "Certificate Fingerprint is not MD5"}, 'dates' => {'txt' => "Certificate is valid"}, 'expired' => {'txt' => "Certificate is not expired"}, 'certfqdn' => {'txt' => "Certificate is valid according given hostname"}, 'wildhost' => {'txt' => "Certificate's wildcard does not match hostname"}, 'wildcard' => {'txt' => "Certificate does not contain wildcards"}, 'rootcert' => {'txt' => "Certificate is not root CA"}, 'selfsigned' => {'txt' => "Certificate is not self-signed"}, 'dv' => {'txt' => "Certificate Domain Validation (DV)"}, 'ev+' => {'txt' => "Certificate strict Extended Validation (EV)"}, 'ev-' => {'txt' => "Certificate lazy Extended Validation (EV)"}, 'ocsp_uri' => {'txt' => "Certificate has OCSP Responder URL"}, 'cps' => {'txt' => "Certificate has Certification Practice Statement"}, 'crl' => {'txt' => "Certificate has CRL Distribution Points"}, 'zlib' => {'txt' => "Certificate has (TLS extension) compression"}, 'lzo' => {'txt' => "Certificate has (GnuTLS extension) compression"}, 'open_pgp' => {'txt' => "Certificate has (TLS extension) authentication"}, 'ocsp_valid' => {'txt' => "Certificate has valid OCSP URL"}, 'cps_valid' => {'txt' => "Certificate has valid CPS URL"}, 'crl_valid' => {'txt' => "Certificate has valid CRL URL"}, 'sernumber' => {'txt' => "Certificate Serial Number size RFC5280"}, 'constraints' => {'txt' => "Certificate Basic Constraints is false"}, 'sha2signature' => {'txt' => "Certificate Private Key Signature SHA2"}, 'modulus_exp_1' => {'txt' => "Certificate Public Key Modulus Exponent <>1"}, 'modulus_size_oldssl' => {'txt' => "Certificate Public Key Modulus >16385 bits"}, 'modulus_exp_65537' =>{'txt'=> "Certificate Public Key Modulus Exponent =65537"}, 'modulus_exp_oldssl'=>{'txt'=> "Certificate Public Key Modulus Exponent >65537"}, 'pub_encryption'=> {'txt' => "Certificate Public Key with Encryption"}, 'pub_enc_known' => {'txt' => "Certificate Public Key Encryption known"}, 'sig_encryption'=> {'txt' => "Certificate Private Key with Encryption"}, 'sig_enc_known' => {'txt' => "Certificate Private Key Encryption known"}, 'rfc_6125_names'=> {'txt' => "Certificate Names compliant to RFC6125"}, 'rfc_2818_names'=> {'txt' => "Certificate subjectAltNames compliant to RFC2818"}, # following checks in subjectAltName, CRL, OCSP, CN, O, U 'nonprint' => {'txt' => "Certificate does not contain non-printable characters"}, 'crnlnull' => {'txt' => "Certificate does not contain CR, NL, NULL characters"}, 'ev_chars' => {'txt' => "Certificate has no invalid characters in extensions"}, # TODO: SRP is a target feature but also named a `Certificate (TLS extension)' # 'srp' => {'txt' => "Certificate has (TLS extension) authentication"}, #------------------+----------------------------------------------------- # extensions: # KeyUsage: # 0 - digitalSignature # 1 - nonRepudiation # 2 - keyEncipherment # 3 - dataEncipherment # 4 - keyAgreement # 5 - keyCertSign # indicates this is CA cert # 6 - cRLSign # 7 - encipherOnly # 8 - decipherOnly # verify, is-trusted: certificate must be trusted, not expired (after also) # common name or altname matches given hostname # 1 - no chain of trust # 2 - not before # 4 - not after # 8 - hostname mismatch # 16 - revoked # 32 - bad common name # 64 - self-signed # possible problems with chains: # - contains untrusted certificate # - chain incomplete/not resolvable # - chain too long (depth) # - chain size too big # - contains illegal characters # TODO: wee need an option to specify the the local certificate storage! ); # %check_cert my %check_conn = ( ## connection data # collected and checked connection data #------------------+----------------------------------------------------- 'ip' => {'txt' => "IP for given hostname "}, 'reversehost' => {'txt' => "Given hostname is same as reverse resolved hostname"}, 'hostname' => {'txt' => "Connected hostname equals certificate's Subject"}, 'beast' => {'txt' => "Connection is safe against BEAST attack (any cipher)"}, 'breach' => {'txt' => "Connection is safe against BREACH attack"}, 'ccs' => {'txt' => "Connection is safe against CCS Injection attack"}, 'crime' => {'txt' => "Connection is safe against CRIME attack"}, 'drown' => {'txt' => "Connection is safe against DROWN attack"}, 'time' => {'txt' => "Connection is safe against TIME attack"}, 'freak' => {'txt' => "Connection is safe against FREAK attack"}, 'heartbleed' => {'txt' => "Connection is safe against Heartbleed attack"}, 'logjam' => {'txt' => "Connection is safe against Logjam attack"}, 'lucky13' => {'txt' => "Connection is safe against Lucky 13 attack"}, 'poodle' => {'txt' => "Connection is safe against POODLE attack"}, 'rc4' => {'txt' => "Connection is safe against RC4 attack"}, 'robot' => {'txt' => "Connection is safe against ROBOT attack"}, 'sloth' => {'txt' => "Connection is safe against SLOTH attack"}, 'sweet32' => {'txt' => "Connection is safe against Sweet32 attack"}, 'sni' => {'txt' => "Connection is not based on SNI"}, # NOTE: following keys use mixed case letters, that's ok 'cause these # checks are not called by their own commands; ugly hack ... #------------------+----------------------------------------------------- ); # %check_conn my %check_dest = ( ## target (connection) data # collected and checked target (connection) data #------------------+----------------------------------------------------- 'sgc' => {'txt' => "Target supports Server Gated Cryptography (SGC)"}, 'hassslv2' => {'txt' => "Target does not support SSLv2"}, 'hassslv3' => {'txt' => "Target does not support SSLv3"}, # POODLE 'hastls10' => {'txt' => "Target supports TLSv1"}, 'hastls11' => {'txt' => "Target supports TLSv1.1"}, 'hastls12' => {'txt' => "Target supports TLSv1.2"}, 'hastls13' => {'txt' => "Target supports TLSv1.3"}, 'hasalpn' => {'txt' => "Target supports ALPN"}, 'hasnpn' => {'txt' => "Target supports NPN"}, 'cipher_strong' => {'txt' => "Target selects strongest cipher"}, 'cipher_order' => {'txt' => "Target does not honors client's cipher order"}, # NOT YET USED 'cipher_weak' => {'txt' => "Target does not accept weak cipher"}, 'cipher_null' => {'txt' => "Target does not accept NULL ciphers"}, 'cipher_adh' => {'txt' => "Target does not accept ADH ciphers"}, 'cipher_exp' => {'txt' => "Target does not accept EXPORT ciphers"}, 'cipher_cbc' => {'txt' => "Target does not accept CBC ciphers"}, 'cipher_des' => {'txt' => "Target does not accept DES ciphers"}, 'cipher_rc4' => {'txt' => "Target does not accept RC4 ciphers"}, 'cipher_edh' => {'txt' => "Target supports EDH ciphers"}, 'cipher_pfs' => {'txt' => "Target supports PFS (selected cipher)"}, 'cipher_pfsall' => {'txt' => "Target supports PFS (all ciphers)"}, 'closure' => {'txt' => "Target understands TLS closure alerts"}, 'compression' => {'txt' => "Target does not support Compression"}, 'fallback' => {'txt' => "Target supports fallback from TLSv1.1"}, 'ism' => {'txt' => "Target is ISM compliant (ciphers only)"}, 'pci' => {'txt' => "Target is PCI compliant (ciphers only)"}, 'fips' => {'txt' => "Target is FIPS-140 compliant"}, # 'nsab' => {'txt' => "Target is NSA Suite B compliant"}, 'tr_02102+' => {'txt' => "Target is strict TR-02102-2 compliant"}, 'tr_02102-' => {'txt' => "Target is lazy TR-02102-2 compliant"}, 'tr_03116+' => {'txt' => "Target is strict TR-03116-4 compliant"}, 'tr_03116-' => {'txt' => "Target is lazy TR-03116-4 compliant"}, 'rfc_7525' => {'txt' => "Target is RFC 7525 compliant"}, 'resumption' => {'txt' => "Target supports Resumption"}, 'renegotiation' => {'txt' => "Target supports Secure Renegotiation"}, 'krb5' => {'txt' => "Target supports Krb5"}, 'psk_hint' => {'txt' => "Target supports PSK Identity Hint"}, 'psk_identity' => {'txt' => "Target supports PSK"}, 'srp' => {'txt' => "Target supports SRP"}, 'ocsp_stapling' => {'txt' => "Target supports OCSP Stapling"}, 'session_ticket'=> {'txt' => "Target supports TLS Session Ticket"}, # sometimes missing ... 'session_lifetime' =>{ 'txt'=> "Target TLS Session Ticket Lifetime"}, 'session_starttime' =>{ 'txt'=> "Target TLS Session Start Time match"}, 'session_random'=> {'txt' => "Target TLS Session Ticket is random"}, 'heartbeat' => {'txt' => "Target does not support heartbeat extension"}, 'scsv' => {'txt' => "Target does not support SCSV"}, # following for information, checks not useful; see "# check target specials" in checkdest also # 'master_key' => {'txt' => "Target supports Master-Key"}, # 'session_id' => {'txt' => "Target supports Session-ID"}, 'dh_512' => {'txt' => "Target DH Parameter >= 512 bits"}, 'dh_2048' => {'txt' => "Target DH Parameter >= 2048 bits"}, 'ecdh_256' => {'txt' => "Target DH Parameter >= 256 bits (ECDH)"}, 'ecdh_512' => {'txt' => "Target DH Parameter >= 512 bits (ECDH)"}, #------------------+----------------------------------------------------- ); # %check_dest my %check_size = ( ## length and count data # collected and checked length and count data # counts and sizes are integer values, key mast have prefix (len|cnt)_ #------------------+----------------------------------------------------- 'len_pembase64' => {'txt' => "Certificate PEM (base64) size"}, # <(2048/8*6) 'len_pembinary' => {'txt' => "Certificate PEM (binary) size"}, # < 2048 'len_subject' => {'txt' => "Certificate Subject size"}, # < 256 'len_issuer' => {'txt' => "Certificate Issuer size"}, # < 256 'len_cps' => {'txt' => "Certificate CPS size"}, # < 256 'len_crl' => {'txt' => "Certificate CRL size"}, # < 256 'len_crl_data' => {'txt' => "Certificate CRL data size"}, 'len_ocsp' => {'txt' => "Certificate OCSP size"}, # < 256 'len_oids' => {'txt' => "Certificate OIDs size"}, 'len_publickey' => {'txt' => "Certificate Public Key size"}, # > 1024 # \---> same as modulus_len 'len_sigdump' => {'txt' => "Certificate Signature Key size"} ,# > 1024 'len_altname' => {'txt' => "Certificate Subject Altname size"}, 'len_chain' => {'txt' => "Certificate Chain size"}, # < 2048 'len_sernumber' => {'txt' => "Certificate Serial Number size"}, # <= 20 octets 'cnt_altname' => {'txt' => "Certificate Subject Altname count"}, # == 0 'cnt_wildcard' => {'txt' => "Certificate Wildcards count"}, # == 0 'cnt_chaindepth'=> {'txt' => "Certificate Chain Depth count"}, # == 1 'cnt_ciphers' => {'txt' => "Total number of offered ciphers"},# <> 0 'cnt_totals' => {'txt' => "Total number of checked ciphers"}, 'cnt_checks_no' => {'txt' => "Total number of check results 'no'"}, 'cnt_checks_yes'=> {'txt' => "Total number of check results 'yes'"}, 'cnt_exitcode' => {'txt' => "Total number of insecure checks"},# == 0 #------------------+----------------------------------------------------- # TODO: cnt_ciphers, len_chain, cnt_chaindepth ); # %check_size my %check_http = ( ## HTTP vs. HTTPS data # score are absolute values here, they are set to 100 if attribute is found # key must have prefix (hsts|sts); see $cfg{'regex'}->{'cmd-http'} #------------------+----------------------------------------------------- 'sts_maxage0d' => {'txt' => "STS max-age not reset"}, # max-age=0 is bad 'sts_maxage1d' => {'txt' => "STS max-age less than one day"}, # weak 'sts_maxage1m' => {'txt' => "STS max-age less than one month"}, # low 'sts_maxage1y' => {'txt' => "STS max-age less than one year"}, # medium 'sts_maxagexy' => {'txt' => "STS max-age more than one year"}, # high 'sts_maxage18' => {'txt' => "STS max-age more than 18 weeks"}, # 'sts_expired' => {'txt' => "STS max-age < certificate's validity"}, 'hsts_sts' => {'txt' => "Target sends STS header"}, 'sts_maxage' => {'txt' => "Target sends STS header with proper max-age"}, 'sts_subdom' => {'txt' => "Target sends STS header with includeSubdomain"}, 'sts_preload' => {'txt' => "Target sends STS header with preload"}, 'hsts_is301' => {'txt' => "Target redirects with status code 301"}, # RFC6797 requirement 'hsts_is30x' => {'txt' => "Target redirects not with 30x status code"}, # other than 301, 304 'hsts_fqdn' => {'txt' => "Target redirect matches given host"}, 'http_https' => {'txt' => "Target redirects HTTP to HTTPS"}, 'hsts_location' => {'txt' => "Target sends STS and no Location header"}, 'hsts_refresh' => {'txt' => "Target sends STS and no Refresh header"}, 'hsts_redirect' => {'txt' => "Target redirects HTTP without STS header"}, 'hsts_samehost' => {'txt' => "Target redirects HTTP to HTTPS same host"}, 'hsts_ip' => {'txt' => "Target does not send STS header for IP"}, 'hsts_httpequiv'=> {'txt' => "Target does not send STS in meta tag"}, 'pkp_pins' => {'txt' => "Target sends Public Key Pins header"}, #------------------+----------------------------------------------------- ); # %check_http # now construct %checks from %check_* and set 'typ' foreach my $key (keys %check_conn) { $checks{$key}->{txt} = $check_conn{$key}->{txt}; $checks{$key}->{typ} = 'connection'; } foreach my $key (keys %check_cert) { $checks{$key}->{txt} = $check_cert{$key}->{txt}; $checks{$key}->{typ} = 'certificate'; } foreach my $key (keys %check_dest) { $checks{$key}->{txt} = $check_dest{$key}->{txt}; $checks{$key}->{typ} = 'destination'; } foreach my $key (keys %check_size) { $checks{$key}->{txt} = $check_size{$key}->{txt}; $checks{$key}->{typ} = 'sizes'; } foreach my $key (keys %check_http) { $checks{$key}->{txt} = $check_http{$key}->{txt}; $checks{$key}->{typ} = 'https'; } foreach my $key (keys %checks) { $checks{$key}->{val} = ""; } # more data added to %checks after defining %cfg, see below our %shorttexts = ( #------------------+------------------------------------------------------ # %check +check short label text #------------------+------------------------------------------------------ 'ip' => "IP for hostname", 'DNS' => "DNS for hostname", 'reversehost' => "Reverse hostname", 'hostname' => "Hostname equals Subject", 'expired' => "Not expired", 'certfqdn' => "Valid for hostname", 'wildhost' => "Wilcard for hostname", 'wildcard' => "No wildcards", 'sni' => "Not SNI based", 'sernumber' => "Size Serial Number", 'sha2signature' => "Signature is SHA2", 'rootcert' => "Not root CA", 'ocsp_uri' => "OCSP URL", 'ocsp_valid' => "OCSP valid", 'hassslv2' => "No SSLv2", 'hassslv3' => "No SSLv3", 'hastls10' => "TLSv1", 'hastls11' => "TLSv1.1", 'hastls12' => "TLSv1.2", 'hastls13' => "TLSv1.3", 'hasalpn' => "Supports ALPN", 'hasnpn' => "Supports NPN", 'alpn' => "Selected ALPN", 'npn' => "Selected NPN", 'alpns' => "Supported ALPNs", 'npns' => "Supported NPNs", 'next_protocols'=> "(NPN) Protocols", 'cipher_strong' => "Strongest cipher selected", 'cipher_order' => "Client's cipher order", 'cipher_weak' => "Weak cipher selected", 'cipher_null' => "No NULL ciphers", 'cipher_adh' => "No ADH ciphers", 'cipher_exp' => "No EXPORT ciphers", 'cipher_cbc' => "No CBC ciphers", 'cipher_des' => "No DES ciphers", 'cipher_rc4' => "No RC4 ciphers", 'cipher_edh' => "EDH ciphers", 'cipher_pfs' => "PFS (selected cipher)", 'cipher_pfsall' => "PFS (all ciphers)", 'sgc' => "SGC supported", 'cps' => "CPS supported", 'crl' => "CRL supported", 'cps_valid' => "CPS valid", 'crl_valid' => "CRL valid", 'dv' => "DV supported", 'ev+' => "EV supported (strict)", 'ev-' => "EV supported (lazy)", 'ev_chars' => "No invalid characters in extensions", 'beast' => "Safe to BEAST (cipher)", 'breach' => "Safe to BREACH", 'ccs' => "Safe to CCS", 'crime' => "Safe to CRIME", 'drown' => "Safe to DROWN", 'time' => "Safe to TIME", 'freak' => "Safe to FREAK", 'heartbleed' => "Safe to Heartbleed", 'lucky13' => "Safe to Lucky 13", 'logjam' => "Safe to Logjam", 'poodle' => "Safe to POODLE", 'rc4' => "Safe to RC4 attack", 'robot' => "Safe to ROBOT", 'sloth' => "Safe to SLOTH", 'sweet32' => "Safe to Sweet32", 'scsv' => "SCSV not supported", 'constraints' => "Basic Constraints is false", 'modulus_exp_1' => "Modulus Exponent <>1", 'modulus_size_oldssl' => "Modulus >16385 bits", 'modulus_exp_65537' =>"Modulus Exponent =65537", 'modulus_exp_oldssl'=>"Modulus Exponent >65537", 'pub_encryption'=> "Public Key with Encryption", 'pub_enc_known' => "Public Key Encryption known", 'sig_encryption'=> "Private Key with Encryption", 'sig_enc_known' => "Private Key Encryption known", 'rfc_6125_names'=> "Names according RFC6125", 'rfc_2818_names'=> "subjectAltNames according RFC2818", 'closure' => "TLS closure alerts", 'fallback' => "Fallback from TLSv1.1", 'zlib' => "ZLIB extension", 'lzo' => "GnuTLS extension", 'open_pgp' => "OpenPGP extension", 'ism' => "ISM compliant", 'pci' => "PCI compliant", 'fips' => "FIPS-140 compliant", # 'nsab' => "NSA Suite B compliant", 'tr_02102+' => "TR-02102-2 compliant (strict)", 'tr_02102-' => "TR-02102-2 compliant (lazy)", 'tr_03116+' => "TR-03116-4 compliant (strict)", 'tr_03116-' => "TR-03116-4 compliant (lazy)", 'rfc_7525' => "RFC 7525 compliant", 'resumption' => "Resumption", 'renegotiation' => "Renegotiation", # NOTE used in %data and %check_dest 'hsts_sts' => "STS header", 'sts_maxage' => "STS long max-age", 'sts_maxage0d' => "STS max-age not reset", 'sts_maxage1d' => "STS max-age < 1 day", 'sts_maxage1m' => "STS max-age < 1 month", 'sts_maxage1y' => "STS max-age < 1 year", 'sts_maxagexy' => "STS max-age > 1 year", 'sts_maxage18' => "STS max-age > 18 weeks", 'sts_expired' => "STS max-age < certificate's validity", 'sts_subdom' => "STS includeSubdomain", 'sts_preload' => "STS preload", 'hsts_httpequiv'=> "STS not in meta tag", 'hsts_ip' => "STS header not for IP", 'hsts_location' => "STS and Location header", 'hsts_refresh' => "STS and no Refresh header", 'hsts_redirect' => "STS within redirects", 'http_https' => "Redirects HTTP", 'hsts_fqdn' => "Redirects to same host", 'hsts_is301' => "Redirects with 301", 'hsts_is30x' => "Redirects not with 30x", 'pkp_pins' => "Public Key Pins", 'selfsigned' => "Validity (signature)", 'chain' => "Certificate chain", 'chain_verify' => "CA Chain trace", 'verify' => "Chain verified", 'error_verify' => "CA Chain error", 'error_depth' => "CA Chain error in level", 'nonprint' => "No non-printables", 'crnlnull' => "No CR, NL, NULL", 'compression' => "Compression", 'expansion' => "Expansion", 'krb5' => "Krb5 Principal", 'psk_hint' => "PSK Identity Hint", 'psk_identity' => "PSK Identity", 'ocsp_stapling' => "OCSP Stapling", 'ocsp_response' => "OCSP Response", 'ocsp_response_data'=> "OCSP Response Data", 'ocsp_response_status' => "OCSP Response Status", 'ocsp_cert_status' => "OCSP Response Cert Status", 'ocsp_next_update' => "OCSP Response Next Update", 'ocsp_this_update' => "OCSP Response This Update", 'srp' => "SRP Username", 'master_key' => "Master-Key", 'session_id' => "Session-ID", 'session_protocol' => "Selected SSL Protocol", 'session_ticket' => "TLS Session Ticket", 'session_lifetime' => "TLS Session Ticket Lifetime", 'session_random' => "TLS Session Ticket random", 'session_timeout' => "TLS Session Timeout", 'session_startdate' => "TLS Session Start Time locale", 'session_starttime' => "TLS Session Start Time EPOCH", 'dh_parameter' => "DH Parameter", 'dh_512' => "DH Parameter >= 512", 'dh_2048' => "DH Parameter >= 2048", 'ecdh_256' => "DH Parameter >= 256 (ECDH)", 'ecdh_512' => "DH Parameter >= 512 (ECDH)", 'ext_authority' => "Authority Information Access", 'ext_authorityid'=>"Authority key Identifier", 'ext_constraints'=>"Basic Constraints", 'ext_cps' => "Certificate Policies", 'ext_cps_cps' => "Certificate Policies: CPS", 'ext_cps_policy'=> "Certificate Policies: Policy", 'ext_cps_notice'=> "Certificate Policies: User Notice", 'ext_crl' => "CRL Distribution Points", 'ext_subjectkeyid'=>"Subject Key Identifier", 'ext_keyusage' => "Key Usage", 'ext_extkeyusage'=>"Extended Key Usage", 'ext_certtype' => "Netscape Cert Type", 'ext_issuer' => "Issuer Alternative Name", 'fallback_protocol' => "Fallback SSL Protocol", 'len_pembase64' => "Size PEM (base64)", 'len_pembinary' => "Size PEM (binary)", 'len_subject' => "Size subject", 'len_issuer' => "Size issuer", 'len_cps' => "Size CPS", 'len_crl' => "Size CRL", 'len_crl_data' => "Size CRL data", 'len_ocsp' => "Size OCSP", 'len_oids' => "Size OIDs", 'len_altname' => "Size altname", 'len_publickey' => "Size pubkey", 'len_sigdump' => "Size signature key", 'len_chain' => "Size certificate chain", 'len_sernumber' => "Size serial number", 'cnt_altname' => "Count altname", 'cnt_wildcard' => "Count wildcards", 'cnt_chaindepth'=> "Count chain depth", 'cnt_ciphers' => "Count ciphers", 'cnt_totals' => "Checked ciphers", 'cnt_checks_no' => "Checks 'no'", 'cnt_checks_yes'=> "Checks 'yes'", #------------------+------------------------------------------------------ # %data +command short label text #------------------+------------------------------------------------------ 'pem' => "PEM", 'text' => "PEM decoded", 'cn' => "Common Name", 'subject' => "Subject", 'issuer' => "Issuer", 'altname' => "Subject AltNames", 'ciphers' => "Client Ciphers", 'ciphers_local' => "SSLlib Ciphers", 'cipher_selected' => "Selected Cipher", 'dates' => "Validity (date)", 'before' => "Valid since", 'after' => "Valid until", 'tlsextdebug' => "TLS Extensions (debug)", 'tlsextensions' => "TLS Extensions", 'extensions' => "Extensions", 'heartbeat' => "Heartbeat", # not realy a `key', but a extension 'aux' => "Trust", 'email' => "Email", 'pubkey' => "Public Key", 'pubkey_algorithm' => "Public Key Algorithm", 'pubkey_value' => "Public Key Value", 'modulus_len' => "Public Key Length", 'modulus' => "Public Key Modulus", 'modulus_exponent' => "Public Key Exponent", 'serial' => "Serial Number", 'serial_hex' => "Serial Number (hex)", 'serial_int' => "Serial Number (int)", 'certversion' => "Certificate Version", 'sslversion' => "SSL Protocol", 'signame' => "Signature Algorithm", 'sigdump' => "Signature (hexdump)", 'sigkey_len' => "Signature Key Length", 'sigkey_value' => "Signature Key Value", 'trustout' => "Trusted", 'ocspid' => "OCSP Hashes", 'ocsp_subject_hash' => "OCSP Subject Hash", 'ocsp_public_hash' => "OCSP Public Hash", 'subject_hash' => "Subject Hash", 'issuer_hash' => "Issuer Hash", 'fp_not_md5' => "Fingerprint not MD5", 'cert_type' => "Certificate Type (bitmask)", 'verify_hostname' => "Hostname valid", 'verify_altname' => "AltNames valid", 'fingerprint_hash' => "Fingerprint Hash", 'fingerprint_type' => "Fingerprint Algorithm", 'fingerprint_sha2' => "Fingerprint SHA2", 'fingerprint_sha1' => "Fingerprint SHA1", 'fingerprint_md5' => "Fingerprint MD5", 'fingerprint' => "Fingerprint:", 'https_protocols' => "HTTPS Alternate-Protocol", 'https_body' => "HTTPS Body", 'https_svc' => "HTTPS Alt-Svc header", 'https_status' => "HTTPS Status line", 'https_server' => "HTTPS Server banner", 'https_location'=> "HTTPS Location header", 'https_alerts' => "HTTPS Error alerts", 'https_refresh' => "HTTPS Refresh header", 'https_pins' => "HTTPS Public Key Pins", 'https_sts' => "HTTPS STS header", 'hsts_maxage' => "HTTPS STS MaxAge", 'hsts_subdom' => "HTTPS STS sub-domains", 'hsts_preload' => "HTTPS STS preload", 'hsts_is301' => "HTTP Status code is 301", 'hsts_is30x' => "HTTP Status code not 30x", 'hsts_samehost' => "HTTP redirect to same host", 'http_protocols'=> "HTTP Alternate-Protocol", 'http_svc' => "HTTP Alt-Svc header", 'http_status' => "HTTP Status line", 'http_location' => "HTTP Location header", 'http_refresh' => "HTTP Refresh header", 'http_sts' => "HTTP STS header", 'options' => "<> SSL bitmask", #------------------+------------------------------------------------------ # more texts dynamically, see "adding more shorttexts" below ); # %shorttexts # add keys from %prot to %shorttext, foreach my $ssl (keys %prot) { my $key = lc($ssl); # keys in data are all lowercase (see: convert all +CMD) $shorttexts{$key} = "Default $prot{$ssl}->{txt} cipher"; } my %scores = ( # keys starting with 'check_' are for total values # all other keys are for individual score values #------------------+-------------+---------------------------------------- 'check_conn' => {'val' => 100, 'txt' => "SSL connection checks"}, 'check_ciph' => {'val' => 100, 'txt' => "Ciphers checks"}, 'check_cert' => {'val' => 100, 'txt' => "Certificate checks"}, 'check_dest' => {'val' => 100, 'txt' => "Target checks"}, 'check_http' => {'val' => 100, 'txt' => "HTTP(S) checks"}, 'check_size' => {'val' => 100, 'txt' => "Certificate sizes checks"}, 'checks' => {'val' => 100, 'txt' => "Total scoring"}, #------------------+-------------+---------------------------------------- # sorting according key name ); # %scores my %score_ssllabs = ( # SSL Server Rating Guide: #------------------+------------+---------------+------------------------- 'check_prot' => {'val' => 0, 'score' => 0.3, 'txt' => "Protocol support"}, # 30% 'check_keyx' => {'val' => 0, 'score' => 0.3, 'txt' => "Key exchange support"}, # 30% 'check_ciph' => {'val' => 0, 'score' => 0.4, 'txt' => "Cipher strength support"}, # 40% # 'score' is a factor here; 'val' will be the score 0..100 # Letter grade translation # Grade Numerical Score #------------------------------------------+------+--------------- 'A' => {'val' => 0, 'score' => 80, 'txt' => "A"}, # score >= 80 'B' => {'val' => 0, 'score' => 65, 'txt' => "B"}, # score >= 65 'C' => {'val' => 0, 'score' => 50, 'txt' => "C"}, # score >= 50 'D' => {'val' => 0, 'score' => 35, 'txt' => "D"}, # score >= 35 'E' => {'val' => 0, 'score' => 20, 'txt' => "E"}, # score >= 20 'F' => {'val' => 0, 'score' => 20, 'txt' => "F"}, # score >= 20 # 'val' is not used above! # Protocol support rating guide # Protocol Score Protocol #------------------------------------------+-----+------------------ 'SSLv2' => {'val' => 0, 'score' => 20, 'txt' => "SSL 2.0"}, # 20% 'SSLv3' => {'val' => 0, 'score' => 80, 'txt' => "SSL 3.0"}, # 80% 'TLSv1' => {'val' => 0, 'score' => 90, 'txt' => "TLS 1.0"}, # 90% 'TLSv11' => {'val' => 0, 'score' => 95, 'txt' => "TLS 1.1"}, # 95% 'TLSv12' => {'val' => 0, 'score' => 100, 'txt' => "TLS 1.2"}, # 100% 'TLSv13' => {'val' => 0, 'score' => 100, 'txt' => "TLS 1.3"}, # 100% 'DTLSv09' => {'val' => 0, 'score' => 80, 'txt' => "DTLS 0.9"},# 80% 'DTLSv1' => {'val' => 0, 'score' => 100, 'txt' => "DTLS 1.0"},# 100% 'DTLSv11' => {'val' => 0, 'score' => 100, 'txt' => "DTLS 1.1"},# 100% 'DTLSv12' => {'val' => 0, 'score' => 100, 'txt' => "DTLS 1.2"},# 100% 'DTLSv13' => {'val' => 0, 'score' => 100, 'txt' => "DTLS 1.3"},# 100% # 'txt' is not used here! # # ( best protocol + worst protocol ) / 2 # Key exchange rating guide # Score Key exchange aspect # Score #------------------------------------------+-----+----------------------------------------------------------+------ 'key_debian' => {'val' => 0, 'score' => 0, 'txt' => "Weak key (Debian OpenSSL flaw)"}, # 0% 'key_anonx' => {'val' => 0, 'score' => 0, 'txt' => "Anonymous key exchange (no authentication)"}, # 0% 'key_512' => {'val' => 0, 'score' => 20, 'txt' => "Key length < 512 bits"}, # 20% 'key_export' => {'val' => 0, 'score' => 40, 'txt' => "Exportable key exchange (limited to 512 bits)"}, # 40% 'key_1024' => {'val' => 0, 'score' => 40, 'txt' => "Key length < 1024 bits (e.g., 512)"}, # 40% 'key_2048' => {'val' => 0, 'score' => 80, 'txt' => "Key length < 2048 bits (e.g., 1024)"}, # 80% 'key_4096' => {'val' => 0, 'score' => 90, 'txt' => "Key length < 4096 bits (e.g., 2048)"}, # 90% 'key_good' => {'val' => 0, 'score' => 100, 'txt' => "Key length >= 4096 bits (e.g., 4096)"}, # 100% # # # Cipher strength rating guide # Score Cipher strength # Score #------------------------------------------+-----+----------------------------------------+------ 'ciph_0' => {'val' => 0, 'score' => 0, 'txt' => "0 bits (no encryption)"}, # 0% 'ciph_128' => {'val' => 0, 'score' => 0, 'txt' => "< 128 bits (e.g., 40, 56)"}, # 20% 'ciph_256' => {'val' => 0, 'score' => 0, 'txt' => "< 256 bits (e.g., 128, 168)"}, # 80% 'ciph_512' => {'val' => 0, 'score' => 0, 'txt' => ">= 256 bits (e.g., 256)"}, # 100% # # ( strongest cipher + weakest cipher ) / 2 # ); # %score_ssllabs my %score_howsmyssl = ( # https://www.howsmyssl.com/ # https://www.howsmyssl.com/s/about.html 'good' => {'txt' => "Good"}, 'probably' => {'txt' => "Probably Okay"}, 'improvable' => {'txt' => "Improvable"}, # if they do not support ephemeral key cipher suites, # do not support session tickets, or are using TLS 1.1. 'bad' => {'txt' => "Bad"}, # uses TLS 1.0 (instead of 1.1 or 1.2), or worse: SSLv3 or earlier. # supports known insecure cipher suites # supports TLS compression (that is compression of the encryption # information used to secure your connection) which exposes it # to the CRIME attack. # is susceptible to the BEAST attack ); # %score_howsmyssl my %info_gnutls = ( # NOT YET USED # extracted from http://www.gnutls.org/manual/gnutls.html # security parameter ECC key # bits size size security description # ----------+-----------+--------+-----------+------------------ 'I' => "<72 <1008 <160 INSECURE Considered to be insecure", 'W' => "72 1008 160 WEAK Short term protection against small organizations", 'L' => "80 1248 160 LOW Very short term protection against agencies", 'l' => "96 1776 192 LEGACY Legacy standard level", 'M' => "112 2432 224 NORMAL Medium-term protection", 'H' => "128 3248 256 HIGH Long term protection", 'S' => "256 15424 512 ULTRA Foreseeable future", ); # %info_gnutls our %cmd = ( 'timeout' => "timeout", # to terminate shell processes (timeout 1) 'openssl' => "openssl", # OpenSSL 'libs' => [], # where to find libssl.so and libcrypto.so 'path' => [], # where to find openssl executable 'extopenssl' => 1, # 1: use external openssl; default yes, except on Win32 'extsclient' => 1, # 1: use openssl s_client; default yes, except on Win32 'extciphers' => 0, # 1: use openssl s_client -cipher for connection check 'envlibvar' => "LD_LIBRARY_PATH", # name of environment variable 'call' => [], # list of special (internal) function calls # see --call=METHOD option in description below ); #| construct list for special commands: 'cmd-*' #| ------------------------------------- my $old = ""; my $regex = join("|", @{$cfg{'versions'}}); # these are data only, not commands foreach my $key (sort {uc($a) cmp uc($b)} keys %data, keys %checks, @{$cfg{'commands-INT'}}) { next if ($key eq $old); # unique $old = $key; push(@{$cfg{'commands'}}, $key) if ($key !~ m/^(?:$regex)/); push(@{$cfg{'cmd-hsts'}}, $key) if ($key =~ m/$cfg{'regex'}->{'cmd-hsts'}/i); push(@{$cfg{'cmd-http'}}, $key) if ($key =~ m/$cfg{'regex'}->{'cmd-http'}/i); push(@{$cfg{'cmd-sizes'}}, $key) if ($key =~ m/$cfg{'regex'}->{'cmd-sizes'}/); push(@{$cfg{'need-checkhttp'}}, $key) if ($key =~ m/$cfg{'regex'}->{'cmd-hsts'}/); push(@{$cfg{'need-checkhttp'}}, $key) if ($key =~ m/$cfg{'regex'}->{'cmd-http'}/); } push(@{$cfg{'cmd-check'}}, $_) foreach (keys %checks); push(@{$cfg{'cmd-info--v'}}, 'dump'); # more information foreach my $key (keys %data) { push(@{$cfg{'cmd-info--v'}}, $key); next if (_is_intern($key) > 0); # ignore aliases next if ($key =~ m/^(ciphers)/ and $verbose == 0); # Client ciphers are less important next if ($key =~ m/^modulus$/ and $verbose == 0); # same values as 'pubkey_value' push(@{$cfg{'cmd-info'}}, $key); } push(@{$cfg{'cmd-info--v'}}, 'info--v'); _yeast_TIME("cfg}"); # definitions here until moved to OSaft/Ciphers.pm %ciphers = ( #-----------------------------+------+-----+----+----+----+-----+--------+----+--------, #'head' => [qw( sec ssl enc bits mac auth keyx score tags)], #-----------------------------+------+-----+----+----+----+-----+--------+----+--------, #'ADH-AES128-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 None DH 11 "")], #'ADH-AES256-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 None DH 11 "")], #'ADH-DES-CBC3-SHA' => [qw( HIGH SSLv3 3DES 168 SHA1 None DH 11 "")], #'ADH-DES-CBC-SHA' => [qw( LOW SSLv3 DES 56 SHA1 None DH 11 "")], #'ADH-RC4-MD5' => [qw(MEDIUM SSLv3 RC4 128 MD5 None DH 11 "")], #'ADH-SEED-SHA' => [qw(MEDIUM SSLv3 SEED 128 SHA1 None DH 11 "")], # above use anonymous DH and hence are vulnerable to MiTM attacks # see openssl's `man ciphers' for details (eNULL and aNULL) # so they are qualified weak here instead of the definition # in `openssl ciphers -v HIGH' #-------- # values -?- are unknown yet #!#---------------------------+------+-----+----+----+----+-----+--------+----+--------, #!# 'head' => [qw( sec ssl enc bits mac auth keyx score tags)], #!#---------------------------+------+-----+----+----+----+-----+--------+----+--------, # FIXME: Perl hashes may not have multiple keys (have them for SSLv2 and SSLv3) 'ADH-AES128-SHA' => [qw( weak SSLv3 AES 128 SHA1 None DH 0 :)], 'ADH-AES256-SHA' => [qw( weak SSLv3 AES 256 SHA1 None DH 0 :)], 'ADH-DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 None DH 0 :)], 'ADH-DES-CBC-SHA' => [qw( weak SSLv3 DES 56 SHA1 None DH 0 :)], 'ADH-RC4-MD5' => [qw( weak SSLv3 RC4 128 MD5 None DH 0 :)], # openssl: MEDIUM 'ADH-SEED-SHA' => [qw( weak SSLv3 SEED 128 SHA1 None DH 0 OSX)], # openssl: MEDIUM # 'AECDH-AES128-SHA' => [qw( weak SSLv3 AES 128 SHA1 None ECDH 11 :)], 'AECDH-AES256-SHA' => [qw( weak SSLv3 AES 256 SHA1 None ECDH 11 :)], 'AECDH-DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 None ECDH 0 :)], 'AECDH-NULL-SHA' => [qw( weak SSLv3 None 0 SHA1 None ECDH 0 :)], 'AECDH-RC4-SHA' => [qw( weak SSLv3 RC4 128 SHA1 None ECDH 11 :)], # openssl: MEDIUM 'AES128-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 RSA RSA 80 :)], 'AES256-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 RSA RSA 100 :)], 'DES-CBC3-MD5' => [qw( weak SSLv2 3DES 168 MD5 RSA RSA 0 :)], 'DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 RSA RSA 0 :)], 'DES-CBC3-SHA' => [qw( weak SSLv2 3DES 168 SHA1 RSA RSA 0 :)], 'DES-CBC-MD5' => [qw( weak SSLv2 DES 56 MD5 RSA RSA 0 :)], 'DES-CBC-SHA' => [qw( weak SSLv3 DES 56 SHA1 RSA RSA 0 :)], 'DES-CBC-SHA' => [qw( weak SSLv2 DES 56 SHA1 RSA RSA 0 :)], 'DES-CFB-M1' => [qw( weak SSLv2 DES 64 MD5 RSA RSA 20 :)], 'DH-DSS-AES128-SHA' => [qw(medium -?- AES 128 SHA1 DSS DH 81 :)], 'DH-DSS-AES256-SHA' => [qw(medium -?- AES 256 SHA1 DSS DH 81 :)], 'DH-RSA-AES128-SHA' => [qw(medium -?- AES 128 SHA1 RSA DH 81 :)], 'DH-RSA-AES256-SHA' => [qw(medium -?- AES 256 SHA1 RSA DH 81 :)], 'DHE-DSS-AES128-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 DSS DH 80 :)], 'DHE-DSS-AES256-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 DSS DH 100 :)], 'DHE-DSS-RC4-SHA' => [qw( weak SSLv3 RC4 128 SHA1 DSS DH 20 :)], # see SSLlabs.com: # https://www.ssllabs.com/ssltest/viewClient.html?name=IE&version=11&platform=Win%208.1 # ... Cannot be used for Forward Secrecy because they require DSA # keys, which are effectively limited to 1024 bits. 'DHE-DSS-SEED-SHA' => [qw(MEDIUM SSLv3 SEED 128 SHA1 DSS DH 81 OSX)], 'DHE-RSA-AES128-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 RSA DH 80 :)], 'DHE-RSA-AES256-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 RSA DH 100 :)], 'DHE-RSA-SEED-SHA' => [qw(MEDIUM SSLv3 SEED 128 SHA1 RSA DH 81 OSX)], 'ECDH-ECDSA-AES128-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 ECDH ECDH/ECDSA 91 :)], 'ECDH-ECDSA-AES256-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 ECDH ECDH/ECDSA 91 :)], 'ECDH-ECDSA-DES-CBC3-SHA'=>[qw( weak SSLv3 3DES 168 SHA1 ECDH ECDH/ECDSA 0 :)], 'ECDH-ECDSA-RC4-SHA' => [qw( weak SSLv3 RC4 128 SHA1 ECDH ECDH/ECDSA 81 :)], #openssl: MEDIUM 'ECDH-ECDSA-NULL-SHA' => [qw( weak SSLv3 None 0 SHA1 ECDH ECDH/ECDSA 0 :)], 'ECDH-RSA-AES128-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 ECDH ECDH/RSA 11 :)], 'ECDH-RSA-AES256-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 ECDH ECDH/RSA 11 :)], 'ECDH-RSA-DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 ECDH ECDH/RSA 0 :)], 'ECDH-RSA-RC4-SHA' => [qw( weak SSLv3 RC4 128 SHA1 ECDH ECDH/RSA 81 :)], #openssl: MEDIUM 'ECDH-RSA-NULL-SHA' => [qw( weak SSLv3 None 0 SHA1 ECDH ECDH/RSA 0 :)], 'ECDHE-ECDSA-AES128-SHA'=> [qw( HIGH SSLv3 AES 128 SHA1 ECDSA ECDH 11 :)], 'ECDHE-ECDSA-AES256-SHA'=> [qw( HIGH SSLv3 AES 256 SHA1 ECDSA ECDH 11 :)], 'ECDHE-ECDSA-DES-CBC3-SHA'=> [qw(weak SSLv3 3DES 168 SHA1 ECDSA ECDH 0 :)], 'ECDHE-ECDSA-NULL-SHA' => [qw( weak SSLv3 None 0 SHA1 ECDSA ECDH 0 :)], 'ECDHE-ECDSA-RC4-SHA' => [qw( weak SSLv3 RC4 128 SHA1 ECDSA ECDH 81 :)], #openssl: MEDIUM 'ECDHE-RSA-AES128-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 RSA ECDH 11 :)], 'ECDHE-RSA-AES256-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 RSA ECDH 11 :)], 'ECDHE-RSA-DES-CBC3-SHA'=> [qw( weak SSLv3 3DES 168 SHA1 RSA ECDH 0 :)], 'ECDHE-RSA-RC4-SHA' => [qw( weak SSLv3 RC4 128 SHA1 RSA ECDH 81 :)], #openssl: MEDIUM 'ECDHE-RSA-NULL-SHA' => [qw( weak SSLv3 None 0 SHA1 RSA ECDH 0 :)], 'EDH-DSS-DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 DSS DH 0 :)], 'EDH-DSS-DES-CBC-SHA' => [qw( weak SSLv3 DES 56 SHA1 DSS DH 0 :)], 'EDH-RSA-DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 RSA DH 0 :)], 'EDH-RSA-DES-CBC-SHA' => [qw( weak SSLv3 DES 56 SHA1 RSA DH 0 :)], 'EXP-ADH-DES-CBC-SHA' => [qw( weak SSLv3 DES 40 SHA1 None DH(512) 0 export)], 'EXP-ADH-RC4-MD5' => [qw( weak SSLv3 RC4 40 MD5 None DH(512) 0 export)], 'EXP-DES-CBC-SHA' => [qw( weak SSLv3 DES 40 SHA1 RSA RSA(512) 0 export)], 'EXP-EDH-DSS-DES-CBC-SHA'=>[qw( weak SSLv3 DES 40 SHA1 DSS DH(512) 0 export)], 'EXP-EDH-RSA-DES-CBC-SHA'=>[qw( weak SSLv3 DES 40 SHA1 RSA DH(512) 0 export)], 'EXP-RC2-CBC-MD5' => [qw( weak SSLv2 RC2 40 MD5 RSA RSA(512) 0 export)], 'EXP-RC2-CBC-MD5' => [qw( weak SSLv3 RC2 40 MD5 RSA RSA(512) 0 export)], 'EXP-RC4-MD5' => [qw( WEAK SSLv2 RC4 40 MD5 RSA RSA(512) 2 export)], 'EXP-RC4-MD5' => [qw( WEAK SSLv3 RC4 40 MD5 RSA RSA(512) 2 export)], 'EXP-RC4-64-MD5' => [qw( weak SSLv3 RC4 64 MD5 DSS RSA 2 :)], # (from RSA BSAFE SSL-C) 'EXP-EDH-DSS-RC4-56-SHA'=> [qw( WEAK SSLv3 RC4 56 SHA DSS DHE 2 :)], # (from RSA BSAFE SSL-C) 'EXP1024-DES-CBC-SHA' => [qw( weak SSLv3 DES 56 SHA1 RSA RSA(1024) 0 export)], 'EXP1024-DHE-DSS-RC4-SHA'=>[qw( WEAK SSLv3 RC4 56 SHA1 DSS DH(1024) 2 export)], 'EXP1024-DHE-DSS-DES-CBC-SHA' => [qw(weak SSLv3 DES 56 SHA1 DSS DH(1024) 0 export)], 'EXP1024-RC2-CBC-MD5' => [qw( weak SSLv3 RC2 56 MD5 RSA RSA(1024) 0 export)], 'EXP1024-RC4-MD5' => [qw( WEAK SSLv3 RC4 56 MD5 RSA RSA(1024) 1 export)], 'EXP1024-RC4-SHA' => [qw( WEAK SSLv3 RC4 56 SHA1 RSA RSA(1024) 2 export)], 'IDEA-CBC-MD5' => [qw( weak SSLv2 IDEA 128 MD5 RSA RSA 0 :)], 'IDEA-CBC-SHA' => [qw( weak SSLv2 IDEA 128 SHA1 RSA RSA 0 :)], 'NULL' => [qw( weak SSLv2 None 0 -?- None -?- 0 :)], # openssl SSLeay testing 'NULL-MD5' => [qw( weak SSLv2 None 0 MD5 RSA RSA(512) 0 :)], 'NULL-MD5' => [qw( weak SSLv3 None 0 MD5 RSA RSA(512) 0 export)], # FIXME: same hash key as before 'NULL-SHA' => [qw( weak SSLv3 None 0 SHA1 RSA RSA 0 :)], 'RSA-PSK-AES128-CBC-SHA'=> [qw( HIGH SSLv3 AES 128 SHA1 AES RSAPSK 0 :)], # 'RSA-PSK-AES128-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 AES RSAPSK 0 :)], # same as RSA-PSK-AES128-CBC-SHA 'RSA-PSK-AES256-CBC-SHA'=> [qw( HIGH SSLv3 RSA 256 SHA1 AES RSAPSK 0 :)], # 'RSA-PSK-AES256-SHA '=> [qw( HIGH SSLv3 RSA 256 SHA1 AES RSAPSK 0 :)], # same as RSA-PSK-AES128-CBC-SHA 'RSA-PSK-3DES-EDE-CBC-SHA'=>[qw( weak SSLv3 3DES 168 SHA1 RSA RSAPSK 0 :)], # 'RSA-PSK-3DES-SHA' => [qw( weak SSLv3 3DES 168 SHA1 RSA RSAPSK 0 :)], # same as RSA-PSK-3DES-EDE-CBC-SHA 'PSK-3DES-EDE-CBC-SHA' => [qw( weak SSLv3 3DES 168 SHA1 PSK PSK 0 :)], 'PSK-AES128-CBC-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 PSK PSK 0 :)], 'PSK-AES256-CBC-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 PSK PSK 0 :)], 'RSA-PSK-RC4-SHA' => [qw(MEDIUM SSLv3 RC4 128 SHA1 RSA RSAPSK 80 :)], 'PSK-RC4-SHA' => [qw(MEDIUM SSLv3 RC4 128 SHA1 PSK PSK 80 :)], 'RC2-CBC-MD5' => [qw( weak SSLv2 RC2 128 MD5 RSA RSA 0 :)], 'RC2-MD5' => [qw(MEDIUM SSLv2 RC2 128 MD5 RSA RSA 80 :)], 'RC4-64-MD5' => [qw( weak SSLv2 RC4 64 MD5 RSA RSA 3 :)], 'RC4-MD5' => [qw( weak SSLv2 RC4 128 MD5 RSA RSA 8 :)], #openssl: MEDIUM 'RC4-MD5' => [qw( weak SSLv3 RC4 128 MD5 RSA RSA 8 :)], #openssl: MEDIUM 'RC4-SHA' => [qw( weak SSLv3 RC4 128 SHA1 RSA RSA 8 :)], #openssl: MEDIUM 'SEED-SHA' => [qw(MEDIUM SSLv3 SEED 128 SHA1 RSA RSA 11 OSX)], #-----------------------------+------+-----+----+----+----+-----+--------+----+--------, 'ADH-CAMELLIA128-SHA' => [qw( weak SSLv3 CAMELLIA 128 SHA1 None DH 0 :)], #openssl: HIGH 'ADH-CAMELLIA256-SHA' => [qw( weak SSLv3 CAMELLIA 256 SHA1 None DH 0 :)], #openssl: HIGH 'CAMELLIA128-SHA' => [qw( HIGH SSLv3 CAMELLIA 128 SHA1 RSA RSA 80 :)], 'CAMELLIA256-SHA' => [qw( HIGH SSLv3 CAMELLIA 256 SHA1 RSA RSA 100 :)], 'DHE-DSS-CAMELLIA128-SHA'=>[qw( HIGH SSLv3 CAMELLIA 128 SHA1 DSS DH 80 :)], 'DHE-DSS-CAMELLIA256-SHA'=>[qw( HIGH SSLv3 CAMELLIA 256 SHA1 DSS DH 100 :)], 'DHE-RSA-CAMELLIA128-SHA'=>[qw( HIGH SSLv3 CAMELLIA 128 SHA1 RSA DH 80 :)], 'DHE-RSA-CAMELLIA256-SHA'=>[qw( HIGH SSLv3 CAMELLIA 256 SHA1 RSA DH 100 :)], 'GOST2001-GOST89-GOST89'=> [qw( HIGH SSLv3 GOST89 256 GOST89 GOST01 GOST 100 :)], 'GOST94-GOST89-GOST89' => [qw( HIGH SSLv3 GOST89 256 GOST89 GOST94 GOST 100 :)], 'GOST-GOST89STREAM' => [qw( HIGH SSLv3 GOST89 256 GOST89 RSA RSA 100 :)], 'GOST-GOST89MAC' => [qw( HIGH SSLv3 GOST89 256 GOST89 RSA RSA 100 :)], 'GOST-GOST94' => [qw( HIGH SSLv3 GOST89 256 GOST94 RSA RSA 100 :)], 'GOST-MD5' => [qw( weak SSLv3 GOST89 256 MD5 RSA RSA 0 :)], #openssl: HIGH 'GOST2001-NULL-GOST94' => [qw( HIGH SSLv3 None 0 GOST94 GOST01 GOST 100 :)], 'GOST94-NULL-GOST94' => [qw( HIGH SSLv3 None 0 GOST94 GOST94 GOST 100 :)], #-----------------------------+------+-----+----+----+----+-----+--------+----+--------, # from openssl-1.0.1c #!#-----------------------------------+------+-----+------+---+------+-----+--------+----+--------, #!# 'head' => [qw( sec ssl enc bits mac auth keyx score tags)], #!#-----------------------------------+------+-----+------+---+------+-----+--------+----+--------, 'SRP-AES-128-CBC-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 None SRP 0 :)], # openssl: HIGH 'SRP-AES-256-CBC-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 None SRP 0 :)], # openssl: HIGH 'SRP-DSS-3DES-EDE-CBC-SHA' => [qw( weak SSLv3 3DES 168 SHA1 DSS SRP 0 :)], 'SRP-DSS-AES-128-CBC-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 DSS SRP 0 :)], 'SRP-DSS-AES-256-CBC-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 DSS SRP 0 :)], 'SRP-RSA-3DES-EDE-CBC-SHA' => [qw( weak SSLv3 3DES 168 SHA1 RSA SRP 0 :)], 'SRP-RSA-AES-128-CBC-SHA' => [qw( HIGH SSLv3 AES 128 SHA1 RSA SRP 0 :)], 'SRP-RSA-AES-256-CBC-SHA' => [qw( HIGH SSLv3 AES 256 SHA1 RSA SRP 0 :)], 'SRP-3DES-EDE-CBC-SHA' => [qw( weak SSLv3 3DES 168 SHA1 None SRP 0 :)], # openssl: HIGH 'ADH-AES128-SHA256' => [qw( weak TLSv12 AES 128 SHA256 None DH 10 :)], # openssl: HIGH 'ADH-AES128-GCM-SHA256' => [qw( weak TLSv12 AESGCM 128 AEAD None DH 10 :)], # openssl: HIGH 'ADH-AES256-GCM-SHA384' => [qw( weak TLSv12 AESGCM 256 AEAD None DH 10 :)], # openssl: HIGH 'ADH-AES256-SHA256' => [qw( weak TLSv12 AES 256 SHA256 None DH 10 :)], # openssl: HIGH 'AES128-GCM-SHA256' => [qw( HIGH TLSv12 AESGCM 128 AEAD RSA RSA 91 :)], 'AES128-SHA256' => [qw( HIGH TLSv12 AES 128 SHA256 RSA RSA 91 :)], 'AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 AEAD RSA RSA 91 :)], 'AES256-SHA256' => [qw( HIGH TLSv12 AES 256 SHA256 RSA RSA 91 :)], 'DHE-DSS-AES128-GCM-SHA256' => [qw( HIGH TLSv12 AESGCM 128 AEAD DSS DH 91 :)], 'DHE-DSS-AES128-SHA256' => [qw( HIGH TLSv12 AES 128 SHA256 DSS DH 91 :)], 'DHE-DSS-AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 AEAD DSS DH 91 :)], 'DHE-DSS-AES256-SHA256' => [qw( HIGH TLSv12 AES 256 SHA256 DSS DH 91 :)], 'DHE-RSA-AES128-GCM-SHA256' => [qw( HIGH TLSv12 AESGCM 128 AEAD RSA DH 91 :)], 'DHE-RSA-AES128-SHA256' => [qw( HIGH TLSv12 AES 128 SHA256 RSA DH 91 :)], 'DHE-RSA-AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 AEAD RSA DH 91 :)], 'DHE-RSA-AES256-SHA256' => [qw( HIGH TLSv12 AES 256 SHA256 RSA DH 91 :)], 'ECDH-ECDSA-AES128-GCM-SHA256' => [qw( HIGH TLSv12 AESGCM 128 AEAD ECDH ECDH/ECDSA 91 :)], 'ECDH-ECDSA-AES128-SHA256' => [qw( HIGH TLSv12 AES 128 SHA256 ECDH ECDH/ECDSA 91 :)], 'ECDH-ECDSA-AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 AEAD ECDH ECDH/ECDSA 91 :)], 'ECDH-ECDSA-AES256-SHA384' => [qw( HIGH TLSv12 AES 256 SHA384 ECDH ECDH/ECDSA 91 :)], 'ECDHE-ECDSA-AES128-GCM-SHA256' => [qw( HIGH TLSv12 AESGCM 128 AEAD ECDSA ECDH 91 :)], 'ECDHE-ECDSA-AES128-SHA256' => [qw( HIGH TLSv12 AES 128 SHA256 ECDSA ECDH 91 :)], 'ECDHE-ECDSA-AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 AEAD ECDSA ECDH 91 :)], 'ECDHE-ECDSA-AES256-SHA384' => [qw( HIGH TLSv12 AES 256 SHA384 ECDSA ECDH 91 :)], 'ECDHE-RSA-AES128-GCM-SHA256' => [qw( HIGH TLSv12 AESGCM 128 AEAD RSA ECDH 91 :)], 'ECDHE-RSA-AES128-SHA256' => [qw( HIGH TLSv12 AES 128 SHA256 RSA ECDH 91 :)], 'ECDHE-RSA-AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 AEAD RSA ECDH 91 :)], 'ECDHE-RSA-AES256-SHA384' => [qw( HIGH TLSv12 AES 256 SHA384 RSA ECDH 91 :)], 'ECDH-RSA-AES128-GCM-SHA256' => [qw( HIGH TLSv12 AESGCM 128 AEAD ECDH ECDH/RSA 91 :)], 'ECDH-RSA-AES128-SHA256' => [qw( HIGH TLSv12 AES 128 SHA256 ECDH ECDH/RSA 91 :)], 'ECDH-RSA-AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 AEAD ECDH ECDH/RSA 91 :)], 'ECDH-RSA-AES256-SHA384' => [qw( HIGH TLSv12 AES 256 SHA384 ECDH ECDH/RSA 91 :)], 'NULL-SHA256' => [qw( weak TLSv12 None 0 SHA256 RSA RSA 0 :)], #-------------------------------------+------+-----+------+---+------+-----+--------+----+--------, # from openssl-1.0.2d #!#-----------------------------------+------+-----+------+---+------+-----+--------+----+--------, #!# 'head' => [qw( sec ssl enc bits mac auth keyx score tags)], #!#-----------------------------------+------+-----+------+---+------+-----+--------+----+--------, 'ADH-CAMELLIA128-SHA256' => [qw( weak TLSv12 CAMELLIA 128 SHA256 None DH 0 :)], #openssl: HIGH 'ADH-CAMELLIA256-SHA256' => [qw( weak TLSv12 CAMELLIA 256 SHA256 None DH 0 :)], #openssl: HIGH 'CAMELLIA128-SHA256' => [qw( HIGH TLSv12 CAMELLIA 128 SHA256 RSA RSA 80 :)], 'CAMELLIA256-SHA256' => [qw( HIGH TLSv12 CAMELLIA 256 SHA256 RSA RSA 100 :)], 'DHE-DSS-CAMELLIA128-SHA256' => [qw( HIGH TLSv12 CAMELLIA 128 SHA256 DSS DH 80 :)], 'DHE-DSS-CAMELLIA256-SHA256' => [qw( HIGH TLSv12 CAMELLIA 256 SHA256 DSS DH 100 :)], 'DHE-RSA-CAMELLIA128-SHA256' => [qw( HIGH TLSv12 CAMELLIA 128 SHA256 RSA DH 80 :)], 'DHE-RSA-CAMELLIA256-SHA256' => [qw( HIGH TLSv12 CAMELLIA 256 SHA256 RSA DH 100 :)], 'DH-DSS-CAMELLIA128-SHA' => [qw( HIGH SSLv3 CAMELLIA 128 SHA1 DSS DH 90 :)], 'DH-RSA-CAMELLIA128-SHA' => [qw( HIGH SSLv3 CAMELLIA 128 SHA1 RSA DH 90 :)], 'DH-DSS-CAMELLIA128-SHA256' => [qw( HIGH TLSv12 CAMELLIA 128 SHA256 DSS DH 90 :)], 'DH-RSA-CAMELLIA128-SHA256' => [qw( HIGH TLSv12 CAMELLIA 128 SHA256 RSA DH 90 :)], 'DH-DSS-CAMELLIA256-SHA' => [qw( HIGH SSLv3 CAMELLIA 256 SHA1 DH DSS 100 :)], # openssl 1.0.2-chacha; auth=DH ?? 'DH-RSA-CAMELLIA256-SHA' => [qw( HIGH SSLv3 CAMELLIA 256 SHA1 DH RSA 100 :)], # openssl 1.0.2-chacha; auth=DH ?? 'DH-DSS-CAMELLIA256-SHA256' => [qw( HIGH TLSv12 CAMELLIA 256 SHA256 DH DSS 100 :)], # openssl 1.0.2-chacha; auth=DH ?? 'DH-RSA-CAMELLIA256-SHA256' => [qw( HIGH TLSv12 CAMELLIA 256 SHA256 DH RSA 100 :)], # openssl 1.0.2-chacha; auth=DH ?? 'ECDHE-RSA-CAMELLIA128-SHA256' => [qw( HIGH TLSv12 CAMELLIA 128 SHA256 RSA ECDH 100 :)], 'ECDHE-RSA-CAMELLIA256-SHA384' => [qw( HIGH TLSv12 CAMELLIA 256 SHA384 RSA ECDH 100 :)], 'ECDHE-ECDSA-CAMELLIA128-SHA256'=> [qw( HIGH TLSv12 CAMELLIA 128 SHA256 ECDSA ECDH 100 :)], 'ECDHE-ECDSA-CAMELLIA256-SHA384'=> [qw( HIGH TLSv12 CAMELLIA 256 SHA384 ECDSA ECDH 100 :)], 'ECDH-RSA-CAMELLIA128-SHA256' => [qw( HIGH TLSv12 CAMELLIA 128 SHA256 ECDH ECDH/RSA 100 :)], 'ECDH-RSA-CAMELLIA256-SHA384' => [qw( HIGH TLSv12 CAMELLIA 256 SHA384 ECDH ECDH/RSA 100 :)], 'ECDH-ECDSA-CAMELLIA128-SHA256' => [qw( HIGH TLSv12 CAMELLIA 128 SHA256 ECDH ECDH/ECDSA 100 :)], 'ECDH-ECDSA-CAMELLIA256-SHA384' => [qw( HIGH TLSv12 CAMELLIA 256 SHA384 ECDH ECDH/ECDSA 100 :)], 'DHE-RSA-CHACHA20-POLY1305-SHA256' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD RSA DH 1 :)], # openssl 1.0.2 DHE-RSA-CHACHA20-POLY1305 'ECDHE-RSA-CHACHA20-POLY1305-SHA256' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD RSA ECDH 1 :)], # openssl 1.0.2 ECDHE-RSA-CHACHA20-POLY1305 'ECDHE-ECDSA-CHACHA20-POLY1305-SHA256' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD ECDSA ECDH 1 :)], # openssl 1.0.2 ECDHE-ECDSA-CHACHA20-POLY1305 'DHE-RSA-CHACHA20-POLY1305' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD RSA DH 1 :)], # bugfix for openssl 1.0.2 'ECDHE-RSA-CHACHA20-POLY1305' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD RSA ECDH 1 :)], # bugfix for openssl 1.0.2 'ECDHE-ECDSA-CHACHA20-POLY1305' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD ECDSA ECDH 1 :)], # bugfix for openssl 1.0.2 'DHE-RSA-CHACHA20-POLY1305-OLD' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD RSA DH 1 :)], # openssl 1.0.2k-dev (patched version) 'ECDHE-RSA-CHACHA20-POLY1305-OLD' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD RSA ECDH 1 :)], # openssl 1.0.2k-dev (patched version) 'ECDHE-ECDSA-CHACHA20-POLY1305-OLD' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD ECDSA ECDH 1 :)], # openssl 1.0.2k-dev (patched version) #!#-----------------------------------+------+-----+------+---+------+-----+--------+----+--------, # from http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-01 'RSA-CHACHA20-SHA' => [qw( HIGH TLSv12 ChaCha20 256 SHA1 RSA RSA 1 :)], 'ECDHE-RSA-CHACHA20-SHA' => [qw( HIGH TLSv12 ChaCha20 256 SHA1 RSA ECDH 1 :)], 'ECDHE-ECDSA-CHACHA20-SHA' => [qw( HIGH TLSv12 ChaCha20 256 SHA1 RSA ECDH 1 :)], 'DHE-RSA-CHACHA20-SHA' => [qw( HIGH TLSv12 ChaCha20 256 SHA1 RSA DH 1 :)], 'DHE-PSK-CHACHA20-SHA' => [qw( HIGH TLSv12 ChaCha20 256 SHA1 PSK DH 1 :)], 'PSK-CHACHA20-SHA' => [qw( HIGH TLSv12 ChaCha20 256 SHA1 PSK PSK 1 :)], 'ECDHE-PSK-CHACHA20-SHA' => [qw( HIGH TLSv12 ChaCha20 256 SHA1 RSA ECDH 1 :)], 'RSA-PSK-CHACHA20-SHA' => [qw( HIGH TLSv12 ChaCha20 256 SHA1 RSA RSAPSK 1 :)], # from https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04 (16. Dec 2015) 'PSK-CHACHA20-POLY1305-SHA256' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD PSK PSK 1 :)], 'ECDHE-PSK-CHACHA20-POLY1305-SHA256'=> [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD ECDHE ECDHEPSK 1 :)], 'DHE-PSK-CHACHA20-POLY1305-SHA256' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD DHE DHEPSK 1 :)], 'RSA-PSK-CHACHA20-POLY1305-SHA256' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 AEAD RSA RSAPSK 1 :)], # from http://tools.ietf.org/html/rfc6655 'RSA-AES128-CCM' => [qw( high TLSv12 AESCCM 128 AEAD RSA RSA 91 :)], 'RSA-AES256-CCM' => [qw( high TLSv12 AESCCM 256 AEAD RSA RSA 91 :)], 'DHE-RSA-AES128-CCM' => [qw( high TLSv12 AESCCM 128 AEAD RSA DH 91 :)], 'DHE-RSA-AES256-CCM' => [qw( high TLSv12 AESCCM 256 AEAD RSA DH 91 :)], 'PSK-RSA-AES128-CCM' => [qw( high TLSv12 AESCCM 128 AEAD PSK PSK 91 :)], 'PSK-RSA-AES256-CCM' => [qw( high TLSv12 AESCCM 256 AEAD PSK PSK 91 :)], 'ECDHE-RSA-AES128-CCM' => [qw( high TLSv12 AESCCM 128 AEAD ECDSA ECDH 91 :)], 'ECDHE-RSA-AES256-CCM' => [qw( high TLSv12 AESCCM 256 AEAD ECDSA ECDH 91 :)], 'RSA-AES128-CCM-8' => [qw( high TLSv12 AESCCM 128 AEAD RSA RSA 91 :)], 'RSA-AES256-CCM-8' => [qw( high TLSv12 AESCCM 256 AEAD RSA RSA 91 :)], 'DHE-RSA-AES128-CCM-8' => [qw( high TLSv12 AESCCM 128 AEAD RSA DH 91 :)], 'DHE-RSA-AES256-CCM-8' => [qw( high TLSv12 AESCCM 256 AEAD RSA DH 91 :)], 'PSK-RSA-AES128-CCM-8' => [qw( high TLSv12 AESCCM 128 AEAD PSK PSK 91 :)], 'PSK-RSA-AES256-CCM-8' => [qw( high TLSv12 AESCCM 256 AEAD PSK PSK 91 :)], 'ECDHE-RSA-AES128-CCM-8' => [qw( high TLSv12 AESCCM 128 AEAD ECDSA ECDH 91 :)], 'ECDHE-RSA-AES256-CCM-8' => [qw( high TLSv12 AESCCM 256 AEAD ECDSA ECDH 91 :)], # from: http://botan.randombit.net/doxygen/tls__suite__info_8cpp_source.html #/ RSA_WITH_AES_128_CCM (0xC09C, "RSA", "RSA", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); #/ RSA_WITH_AES_256_CCM (0xC09D, "RSA", "RSA", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); #/ DHE_RSA_WITH_AES_128_CCM (0xC09E, "RSA", "DH", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); #/ DHE_RSA_WITH_AES_256_CCM (0xC09F, "RSA", "DH", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); #/ PSK_WITH_AES_128_CCM (0xC0A5, "", "PSK", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); #/ PSK_WITH_AES_256_CCM (0xC0A4, "", "PSK", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); #/ ECDHE_ECDSA_WITH_AES_128_CCM (0xC0AC, "ECDSA", "ECDH", "AES-128/CCM", 16, 4, "AEAD", 0, "SHA-256"); #/ ECDHE_ECDSA_WITH_AES_256_CCM (0xC0AD, "ECDSA", "ECDH", "AES-256/CCM", 32, 4, "AEAD", 0, "SHA-256"); #/ RSA_WITH_AES_128_CCM_8 (0xC0A0, "RSA", "RSA", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); #/ RSA_WITH_AES_256_CCM_8 (0xC0A1, "RSA", "RSA", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); #/ DHE_RSA_WITH_AES_128_CCM_8 (0xC0A2, "RSA", "DH", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); #/ DHE_RSA_WITH_AES_256_CCM_8 (0xC0A3, "RSA", "DH", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); #/ PSK_WITH_AES_128_CCM_8 (0xC0A8, "", "PSK", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); #/ PSK_WITH_AES_256_CCM_8 (0xC0A9, "", "PSK", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); #/ ECDHE_ECDSA_WITH_AES_128_CCM_8 (0xC0AE, "ECDSA", "ECDH", "AES-128/CCM-8", 16, 4, "AEAD", 0, "SHA-256"); #/ ECDHE_ECDSA_WITH_AES_256_CCM_8 (0xC0AF, "ECDSA", "ECDH", "AES-256/CCM-8", 32, 4, "AEAD", 0, "SHA-256"); #-------------------------------------+------+-----+------+---+------+-----+--------+----+--------, # from openssl-1.0.1g 'KRB5-DES-CBC3-MD5' => [qw( weak SSLv3 3DES 168 MD5 KRB5 KRB5 0 :)], 'KRB5-DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 KRB5 KRB5 0 :)], 'KRB5-IDEA-CBC-MD5' => [qw( weak SSLv3 IDEA 128 MD5 KRB5 KRB5 0 :)], 'KRB5-IDEA-CBC-SHA' => [qw( weak SSLv3 IDEA 128 SHA1 KRB5 KRB5 0 :)], 'KRB5-RC4-MD5' => [qw( weak SSLv3 RC4 128 MD5 KRB5 KRB5 0 :)], 'KRB5-RC4-SHA' => [qw( weak SSLv3 RC4 128 SHA1 KRB5 KRB5 0 :)], 'KRB5-DES-CBC-MD5' => [qw( weak SSLv3 DES 56 MD5 KRB5 KRB5 0 :)], 'KRB5-DES-CBC-SHA' => [qw( weak SSLv3 DES 56 SHA1 KRB5 KRB5 0 :)], 'EXP-KRB5-DES-CBC-MD5' => [qw( weak SSLv3 DES 40 MD5 KRB5 KRB5 0 export)], 'EXP-KRB5-DES-CBC-SHA' => [qw( weak SSLv3 DES 40 SHA1 KRB5 KRB5 0 export)], 'EXP-KRB5-RC2-CBC-MD5' => [qw( weak SSLv3 RC2 40 MD5 KRB5 KRB5 0 export)], 'EXP-KRB5-RC2-CBC-SHA' => [qw( weak SSLv3 RC2 40 SHA1 KRB5 KRB5 0 export)], 'EXP-KRB5-RC4-MD5' => [qw( WEAK SSLv3 RC4 40 MD5 KRB5 KRB5 0 export)], 'EXP-KRB5-RC4-SHA' => [qw( WEAK SSLv3 RC4 40 SHA1 KRB5 KRB5 0 export)], # from ssl/s3_lib.c 'FZA-NULL-SHA' => [qw( weak SSLv3 None 0 SHA1 KEA FZA 11 :)], 'FZA-FZA-SHA' => [qw(MEDIUM SSLv3 FZA 0 SHA1 KEA FZA 81 :)], 'FZA-RC4-SHA' => [qw( WEAK SSLv3 RC4 128 SHA1 KEA FZA 11 :)], 'RSA-FIPS-3DES-EDE-SHA' => [qw( weak SSLv3 3DES 168 SHA1 RSA_FIPS RSA_FIPS 0 :)], 'RSA-FIPS-3DES-EDE-SHA' => [qw( weak SSLv3 3DES 168 SHA1 RSA_FIPS RSA_FIPS 0 :)], 'RSA-FIPS-DES-CBC-SHA' => [qw( weak SSLv3 DES_CBC 56 SHA1 RSA_FIPS RSA_FIPS 0 :)], 'RSA-FIPS-DES-CBC-SHA' => [qw( weak SSLv3 DES_CBC 56 SHA1 RSA_FIPS RSA_FIPS 0 :)], 'EXP-DH-DSS-DES-CBC-SHA' => [qw( weak SSLv3 DES 40 SHA1 DSS DH(512) 0 export)], 'EXP-DH-RSA-DES-CBC-SHA' => [qw( weak SSLv3 DES 40 SHA1 RSA DH(512) 0 export)], # FIXME: all following 'DH-DSS-DES-CBC-SHA' => [qw( weak SSLv3 DES 56 SHA1 DSS DH 0 :)], 'DH-RSA-DES-CBC-SHA' => [qw( weak SSLv3 DES 56 SHA1 RSA DH 0 :)], 'DH-DSS-DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 DSS DH 0 :)], 'DH-RSA-DES-CBC3-SHA' => [qw( weak SSLv3 3DES 168 SHA1 RSA DH 0 :)], 'DH-DSS-AES128-SHA256' => [qw( high TLSv12 AES 128 SHA256 DSS DH 91 :)], 'DH-RSA-AES128-SHA256' => [qw( high TLSv12 AES 128 SHA256 RSA DH 91 :)], 'DH-DSS-AES256-SHA256' => [qw( high TLSv12 AES 256 SHA256 DSS DH 91 :)], 'DH-RSA-AES256-SHA256' => [qw( high TLSv12 AES 256 SHA256 RSA DH 91 :)], 'DH-DSS-SEED-SHA' => [qw(medium SSLv3 SEED 128 SHA1 DSS DH 81 :)], 'DH-RSA-SEED-SHA' => [qw(medium SSLv3 SEED 128 SHA1 RSA DH 81 :)], 'DH-RSA-AES128-GCM-SHA256' => [qw( high TLSv12 AESGCM 128 AEAD RSA DH 91 :)], 'DH-RSA-AES256-GCM-SHA384' => [qw( high TLSv12 AESGCM 256 AEAD RSA DH 91 :)], 'DH-DSS-AES128-GCM-SHA256' => [qw( high TLSv12 AESGCM 128 AEAD DSS DH 91 :)], 'DH-DSS-AES256-GCM-SHA384' => [qw( high TLSv12 AESGCM 256 AEAD DSS DH 91 :)], 'DHE-PSK-SHA' => [qw( weak TLSv12 None 0 SHA1 PSK DHE 1 :)], 'RSA-PSK-SHA' => [qw( weak TLSv12 None 0 SHA1 PSK RSA 1 :)], 'DHE-PSK-RC4-SHA' => [qw(medium TLSv12 RC4 128 SHA1 PSK DHE 1 :)], 'DHE-PSK-3DES-SHA' => [qw( weak TLSv12 3DES 168 SHA1 PSK DHE 0 :)], 'DHE-PSK-AES128-SHA' => [qw( -?- TLSv12 AES 128 SHA1 PSK DHE 1 :)], 'DHE-PSK-AES256-SHA' => [qw( -?- TLSv12 AES 256 SHA1 PSK DHE 1 :)], 'DHE-PSK-AES128-GCM-SHA256' => [qw( -?- TLSv12 AES 128 SHA256 PSK DHE 1 :)], 'DHE-PSK-AES256-GCM-SHA384' => [qw( -?- TLSv12 AES 256 SHA384 PSK DHE 1 :)], 'RSA-PSK-AES128-GCM-SHA256' => [qw( -?- TLSv12 AES 128 SHA256 PSK RSA 1 :)], 'RSA-PSK-AES256-GCM-SHA384' => [qw( -?- TLSv12 AES 256 SHA384 PSK RSA 1 :)], 'PSK-AES128-SHA256' => [qw( -?- TLSv12 AES 128 SHA256 PSK PSK 1 :)], 'PSK-AES256-SHA384' => [qw( -?- TLSv12 AES 256 SHA384 PSK PSK 1 :)], 'PSK-SHA256' => [qw( weak TLSv12 None 0 SHA256 PSK PSK 1 :)], 'PSK-SHA384' => [qw( weak TLSv12 None 0 SHA384 PSK PSK 1 :)], 'DHE-PSK-AES128-SHA256' => [qw( -?- TLSv12 AES 128 SHA256 PSK DHE 1 :)], 'DHE-PSK-AES256-SHA384' => [qw( -?- TLSv12 AES 256 SHA384 PSK DHE 1 :)], 'DHE-PSK-SHA256' => [qw( weak TLSv12 None 0 SHA256 PSK DHE 1 :)], 'DHE-PSK-SHA384' => [qw( weak TLSv12 None 0 SHA384 PSK DHE 1 :)], 'RSA-PSK-AES128-SHA256' => [qw( -?- TLSv12 AES 128 SHA256 PSK RSA 1 :)], 'RSA-PSK-AES256-SHA384' => [qw( -?- TLSv12 AES 256 SHA384 PSK RSA 1 :)], 'RSA-PSK-SHA256' => [qw( -?- TLSv12 AES 0 SHA256 PSK RSA 1 :)], 'RSA-PSK-SHA384' => [qw( -?- TLSv12 AES 0 SHA384 PSK RSA 1 :)], # from http://tools.ietf.org/html/rfc6209 #!# 'head' => [qw( sec ssl enc bits mac auth keyx score tags)], #!#-----------------------------------+------+-----+------+-----+------+-----+--------+----+--------, 'RSA-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 RSA RSA 11 :)], 'RSA-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 RSA RSA 11 :)], 'DH_DSS-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 DSS DH 11 :)], 'DH_DSS-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 DSS DH 11 :)], 'DH_RSA-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 RSA DH 11 :)], 'DH_RSA-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 RSA DH 11 :)], 'DHE_DSS-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 DSS DHE 11 :)], # unklar 'DHE_DSS-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 DSS DHE 11 :)], # unklar 'DHE_RSA-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 RSA DHE 11 :)], # unklar 'DHE_RSA-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 RSA DHE 11 :)], # unklar 'ADH-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 None DH 11 :)], # unklar 'ADH-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 None DH 11 :)], # unklar 'ECDHE_ECDSA-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 ECDSA ECDHE 11 :)], 'ECDHE_ECDSA-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 ECDSA ECDHE 11 :)], 'ECDH_ECDSA-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 ECDSA ECDH 11 :)], 'ECDH_ECDSA-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 ECDSA ECDH 11 :)], 'ECDHE_RSA-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 RSA ECDHE 11 :)], 'ECDHE_RSA-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 RSA ECDHE 11 :)], 'ECDH_RSA-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 RSA ECDH 11 :)], 'ECDH_RSA-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 RSA ECDH 11 :)], 'RSA-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 RSA RSA 11 :)], 'RSA-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 RSA RSA 11 :)], 'DHE_RSA-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 RSA DHE 11 :)], # unklar 'DHE_RSA-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 RSA DHE 11 :)], # unklar 'DH_RSA-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 RSA DH 11 :)], 'DH_RSA-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 RSA DH 11 :)], 'DHE_DSS-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 DSS DHE 11 :)], # unklar 'DHE_DSS-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 DSS DHE 11 :)], # unklar 'DH_DSS-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 DSS DH 11 :)], 'DH_DSS-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 DSS DH 11 :)], 'ADH-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 None DH 11 :)], 'ADH-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 None DH 11 :)], 'ECDHE_ECDSA-ARIA128-GCM-SHA256'=> [qw( -?- TLSv12 ARIAGCM 128 SHA256 ECDSA ECDHE 11 :)], 'ECDHE_ECDSA-ARIA256-GCM-SHA384'=> [qw( -?- TLSv12 ARIAGCM 256 SHA384 ECDSA ECDHE 11 :)], 'ECDH_ECDSA-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 ECDSA ECDH 11 :)], 'ECDH_ECDSA-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 ECDSA ECDH 11 :)], 'ECDHE_RSA-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 RSA ECDHE 11 :)], 'ECDHE_RSA-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 RSA ECDHE 11 :)], 'ECDH_RSA-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 RSA ECDH 11 :)], 'ECDH_RSA-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 RSA ECDH 11 :)], 'PSK-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 PSK PSK 11 :)], 'PSK-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 PSK PSK 11 :)], 'DHE_PSK-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 PSK DHE 11 :)], # unklar 'DHE_PSK-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 PSK DHE 11 :)], # unklar 'RSA_PSK-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 PSK RSA 11 :)], 'RSA_PSK-ARIA256-SHA384' => [qw( -?- TLSv12 ARIA 256 SHA384 PSK RSA 11 :)], 'PSK-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 PSK PSK 11 :)], 'PSK-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 PSK PSK 11 :)], 'DHE_PSK-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 PSK DHE 11 :)], # unklar 'DHE_PSK-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 PSK DHE 11 :)], # unklar 'RSA_PSK-ARIA128-GCM-SHA256' => [qw( -?- TLSv12 ARIAGCM 128 SHA256 PSK RSA 11 :)], 'RSA_PSK-ARIA256-GCM-SHA384' => [qw( -?- TLSv12 ARIAGCM 256 SHA384 PSK RSA 11 :)], 'ECDHE_PSK-ARIA128-SHA256' => [qw( -?- TLSv12 ARIA 128 SHA256 PSK ECDHE 11 :)], # from: https://chromium.googlesource.com/chromium/src/net/+/master/ssl/ssl_cipher_suite_names_unittest.cc 'CECPQ1-RSA-CHACHA20-POLY1305-SHA256' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 SHA256 RSA CECPQ1 91 :)], 'CECPQ1-ECDSA-CHACHA20-POLY1305-SHA256' => [qw( HIGH TLSv12 ChaCha20-Poly1305 256 SHA256 ECDSA CECPQ1 91 :)], 'CECPQ1-RSA-AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 SHA384 RSA CECPQ1 91 :)], 'CECPQ1-ECDSA-AES256-GCM-SHA384' => [qw( HIGH TLSv12 AESGCM 256 SHA384 ECDSA CECPQ1 91 :)], # === openssl === # most of above table (roughly) generated with: # openssl ciphers -v ALL:eNULL:aNULL | sort \ # | awk '{e=$7;printf("\t%26s => [%s, %s, %s, %s, %s, %s, %s],\n",$1,$2,substr($5,5),substr($5,index($5,"(")+1),substr($6,5),substr($4,4),substr($3,4),e)}' # or better # | awk '{q="'"'"'";a=sprintf("%s%c",$1,q);e=$7;printf("\t%c%-26s => [qw( -?-\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t13 :)],\n",q,a,$2,substr($5,5),substr($5,index($5,"(")+1),substr($6,5),substr($4,4),substr($3,4),e)}' # ) # === openssl 0.9.8o === # most of above table (roughly) generated with: # openssl ciphers -v ALL:eNULL:aNULL | sort # # NOTE: some openssl (0.9.8o on Ubuntu 11.10) fail to list ciphers with # openssl ciphers -ssl2 -v ); # %ciphers our %text = ( 'separator' => ":",# separator character between label and value # texts may be redefined 'undef' => "<>", 'response' => "<>", 'protocol' => "<>", 'need_cipher' => "<>", 'na' => "<>", 'na_STS' => "<>", 'na_dns' => "<>", 'na_cert' => "<>", 'na_http' => "<>", 'na_tlsextdebug'=> "<>", 'na_nextprotoneg'=>"<>", 'na_reconnect' => "<>", 'na_openssl' => "<>", 'disabled' => "<>", # @@ is --no-SSLv2 or --no-SSLv3 'disabled_protocol' => "<>", # @@ is --no-SSLv2 or --no-SSLv3 'disabled_test' => "tests with/for @@ disabled", # not yet used 'miss_cipher' => "<>", 'miss_RSA' => " <>", 'miss_ECDSA' => " <>", 'missing' => " <>", 'enabled_extension' => " <<@@ extension enabled>>", 'insecure' => " <>", 'invalid' => " <>", 'bit256' => " <>", 'bit512' => " <>", 'bit2048' => " <>", 'bit4096' => " <>", 'EV_large' => " <>", 'EV_subject_CN' => " <>", 'EV_subject_host'=>" <>", 'no_reneg' => " <>", 'cert_dates' => " <>", 'cert_valid' => " <>", 'cert_chars' => " <>", 'wildcards' => " <>", 'gethost' => " <>", 'out_target' => "\n==== Target: @@ ====\n", 'out_ciphers' => "\n=== Ciphers: Checking @@ ===", 'out_infos' => "\n=== Informations ===", 'out_scoring' => "\n=== Scoring Results EXPERIMENTAL ===", 'out_checks' => "\n=== Performed Checks ===", 'out_list' => "=== List @@ Ciphers ===", 'out_summary' => "=== Ciphers: Summary @@ ==", # hostname texts 'host_name' => "Given hostname", 'host_IP' => "IP for given hostname", 'host_rhost' => "Reverse resolved hostname", 'host_DNS' => "DNS entries for given hostname", # misc texts 'cipher' => "Cipher", 'support' => "supported", 'security' => "Security", 'dh_param' => "DH Parameters", 'desc' => "Description", 'desc_check' => "Check Result (yes is considered good)", 'desc_info' => "Value", 'desc_score' => "Score (max value 100)", # texts used for legacy mode; DO NOT CHANGE! 'legacy' => { #--------------+------------------------+--------------------- #header => # not implemented supported unsupported # #----------------+------------------------+--------------------- 'compact' => { 'not' => '-', 'yes' => "yes", 'no' => "no" }, 'simple' => { 'not' => '-?-', 'yes' => "yes", 'no' => "no" }, 'full' => { 'not' => '-?-', 'yes' => "Yes", 'no' => "No" }, 'key' => { 'not' => '-?-', 'yes' => "yes", 'no' => "no" }, 'owasp' => { 'not' => '-?-', 'yes' => "", 'no' => "" }, # #----------------+------------------------+--------------------- # following keys are roughly the names of the tool they are used # #----------------+------------------------+--------------------- 'sslaudit' => { 'not' => '-?-', 'yes' => "successfull", 'no' => "unsuccessfull" }, 'sslcipher' => { 'not' => '-?-', 'yes' => "ENABLED", 'no' => "DISABLED" }, 'ssldiagnos'=> { 'not' => '-?-', 'yes' => "CONNECT_OK CERT_OK", 'no' => "FAILED" }, 'sslscan' => { 'not' => '-?-', 'yes' => "Accepted", 'no' => "Rejected" }, 'ssltest' => { 'not' => '-?-', 'yes' => "Enabled", 'no' => "Disabled" }, 'ssltest-g' => { 'not' => '-?-', 'yes' => "Enabled", 'no' => "Disabled" }, 'sslyze' => { 'not' => '-?-', 'yes' => "%s", 'no' => "SSL Alert" }, 'testsslserver'=>{'not'=> '-?-', 'yes' => "", 'no' => "" }, 'thcsslcheck'=>{ 'not' => '-?-', 'yes' => "supported", 'no' => "unsupported" }, # #----------------+------------------------+--------------------- # -?- means "not implemented" # all other text used in headers titles, etc. are defined in the # corresponding print functions: # printtitle, print_cipherhead, printfooter, print_cipherprefered, print_ciphertotals }, # NOTE: all other legacy texts are hardcoded, as there is no need to change them! # Texts used for hints, key must be same as a command (without leading +) # Currently we define the hints here, but it can be done anywhere in the # code, which may be useful for documentation purpose because such hints # often describe missing features or functionality. # TODO: move this to %cfg{hints} 'hints' => { 'renegotiation' => "checks only if renegotiation is implemented serverside according RFC5746 ", 'drown' => "checks only if the target server itself is vulnerable to DROWN ", 'robot' => "checks only if the target offers ciphers vulnerable to ROBOT ", }, 'mnemonic' => { # NOT YET USED 'example' => "TLS_DHE_DSS_WITH_3DES-EDE-CBC_SHA", 'description'=> "TLS Version _ key establishment algorithm _ digital signature algorithm _ WITH _ confidentility algorithm _ hash function", 'explain' => "TLS Version1 _ Ephemeral DH key agreement _ DSS which implies DSA _ WITH _ 3DES encryption in CBC mode _ SHA for HMAC" }, # just for information, some configuration options in Firefox 'firefox' => { # NOT YET USED 'browser.cache.disk_cache_ssl' => "En-/Disable caching of SSL pages", # false 'security.enable_tls_session_tickets' => "En-/Disable Session Ticket extension", # false 'security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref' =>"",# false 'security.ssl.renego_unrestricted_hosts' => '??', # Liste 'security.ssl.require_safe_negotiation' => "", # true 'security.ssl.treat_unsafe_negotiation_as_broken' => "", # true 'security.ssl.warn_missing_rfc5746' => "", # true 'pfs.datasource.url' => '??', # 'browser.identity.ssl_domain_display' => "coloured non EV-SSL Certificates", # true }, 'IE' => { # NOT YET USED 'HKLM\\...' => "sequence of ciphers", # }, # for more informations about definitions and RFC, see o-saft-man.pm ); # %text $cmd{'extopenssl'} = 0 if ($^O =~ m/MSWin32/); # tooooo slow on Windows $cmd{'extsclient'} = 0 if ($^O =~ m/MSWin32/); # tooooo slow on Windows $cfg{'done'}->{'rc_file'}++ if ($#rc_argv > 0); #| incorporate some environment variables #| ------------------------------------- # all OPENSSL* environment variables are checked and assigned in o-saft-lib.pm $cmd{'openssl'} = $cfg{'openssl_env'} if (defined $cfg{'openssl_env'}); if (defined $ENV{'LIBPATH'}) { _hint("LIBPATH environment variable found, consider using '--envlibvar=LIBPATH'"); # TODO: avoid hint if --envlibvar=LIBPATH in use # $cmd{'envlibvar'} = $ENV{'LIBPATH'}; # don't set silently } #_init_all(); # call delayed to prevent warning of prototype check with -w _yeast_EXIT("exit=INIT1 - initialization end"); usr_pre_file(); #| definitions: internal functions #| ------------------------------------- sub _isnummber { # return 1 if given parameter is a number; return 0 otherwise my $val = shift; return 0 if not defined $val; return 0 if $val eq ''; return ($val ^ $val) ? 0 : 1 } # _isnummber use IO::Socket::INET; sub _load_modules { # load required modules # SEE Perl:import include my $txt = ""; if (1 > 0) { # TODO: experimental code $txt = _load_file("IO/Socket/SSL.pm", "IO SSL module"); warn STR_ERROR, "005: $txt" if ($txt ne ""); # cannot load IO::Socket::INET delayed because we use AF_INET, # otherwise we get at startup: # Bareword "AF_INET" not allowed while "strict subs" in use ... #$txt = _load_file("IO/Socket/INET.pm", "IO INET module"); #warn STR_ERROR, "006: $txt" if ($txt ne ""); } if ($cfg{'need_netdns'} > 0) { $txt = _load_file("Net/DNS.pm", "Net module"); if ($txt ne "") { warn STR_ERROR, "007: $txt"; _warn("111: option --mx disabled"); $cfg{'usemx'} = 0; } } if ($cfg{'need_timelocal'} > 0) { $txt = _load_file("Time/Local.pm", "Time module"); if ($txt ne "") { warn STR_ERROR, "008: $txt"; _warn("112: value for +sts_expired not applicable"); # TODO: need to remove +sts_expired from cfg{do} } } return if ($osaft_standalone > 0); # SEE Note:Stand-alone if (_is_do('cipherraw') or _is_do('version') or ($cfg{'starttls'}) or (($cfg{'proxyhost'}) and ($cfg{'proxyport'})) ) { $txt = _load_file("Net/SSLhello.pm", "O-Saft module"); # must be found with @INC if ($txt ne "") { die STR_ERROR, "010: $txt" if (not _is_do('version')); warn STR_ERROR, "010: $txt";# no reason to die for +version } $cfg{'usehttp'} = 0; # makes no sense for starttls # TODO: not (yet) supported for proxy } $txt = _load_file("Net/SSLinfo.pm", "O-Saft module"); # must be found if ($txt ne "") { die STR_ERROR, "011: $txt" if (not _is_do('version')); warn STR_ERROR, "011: $txt"; # no reason to die for +version } return; } # _load_modules sub _check_modules { # check for minimal version of a module; # verbose output with --v=2 ; uses string "yes" for contrib/bunt.* # these checks print warnings with warn() not _warn(), SEE Perl:warn # SEE Perl:import include _y_CMD(" check module versions ..."); my %expected_versions = ( 'IO::Socket::INET' => "1.31", 'IO::Socket::SSL' => "1.37", 'Net::SSLeay' => "1.49", 'Net::DNS' => "0.65", 'Time::Local' => "1.23", # to simulate various error conditions, simply modify the module name # and/or its expected version in above table; these values are never # used elsewhere ); # Comparing version numbers is tricky, 'cause they are no natural numbers # Consider for example 1.8 and 1.11 : where the numerical comapre returns # "1.8 > 1.11". # Perl has the version module for this, but it's available for Perl > 5.9 # only. For older Perl, we warn that version checks may not be accurate. # Please see "perldoc version" about the logic and syntax. my $have_version = 1; eval {require version; } or $have_version = 0; # $version::VERSION may have one of 3 values now: # undef - version module was not available or didn't define VERSION # string - even "0.42" cannot be compared to integer, bad luck ... # integer - that's the usual and expected value if (_isnummber($version::VERSION) == 1) { $have_version = 0 if ($version::VERSION < 0.77); # veriosn module too old, use natural number compare } else { $have_version = 0; $version::VERSION = ""; # defensive programming .. } if ($have_version == 0) { warn STR_WARN, "120: ancient perl has no 'version' module; version checks may not be accurate;"; } if ($cfg{verbose} > 1) { printf "# %s+%s+%s\n", "-"x21, "-"x7, "-"x15; printf "# %-21s\t%s\t%s\n", "module name", "VERSION", "> expected versions"; printf "# %s+%s+%s\n", "-"x21, "-"x7, "-"x15; } foreach my $mod (keys %expected_versions) { next if (($cfg{'need_netdns'} == 0) and ($mod eq "Net::DNS"));# don't complain if not used next if (($cfg{'need_timelocal'} == 0) and ($mod eq "Time::Local"));# -"- no strict 'refs'; ## no critic qw(TestingAndDebugging::ProhibitNoStrict TestingAndDebugging::ProhibitProlongedStrictureOverride) # avoid: Can't use string ("Net::DNS::VERSION") as a SCALAR ref while "strict refs" in use my $expect = $expected_versions{$mod}; my $v = $mod . "::VERSION"; my $ok = "yes"; # following eval is safe, as left side value cannot be injected eval {$v = $$v;} or $v = 0; # module was not loaded or has no VERSION if ($have_version == 1) { # accurate checks with version module # convert natural numbers to version objects $v = version->parse("v$v"); $expect = version->parse("v$expect"); } if ($v < $expect) { $ok = "no"; $ok = "missing" if ($v == 0); warn STR_WARN, "121: ancient $mod $v < $expect detected;"; # TODO: not sexy: warnings are inside tabular data for --v } if ($cfg{verbose} > 1) { printf "# %-21s\t%s\t> %s\t%s\n", $mod, $v, $expect, $ok; } } # TODO: OCSP and OCSP stapling works since Net::SSLeay 1.78 , we should # use Net::SSLeay 1.83 because of some bug fixes there, see: # https://metacpan.org/changes/distribution/Net-SSLeay printf "# %s+%s+%s\n", "-"x21, "-"x7, "-"x15 if ($cfg{verbose} > 1); return; } # _check_modules sub _enable_functions { # enable internal functionality based on available functionality of modules # these checks print warnings with warn() not _warn(), SEE Perl:warn # verbose messages with --v --v # NOTE: don't bother users with warnings, if functionality is not required # hence some additional checks around the warnings # NOTE: instead of requiring a specific version with Perl's use, only the # version of the loaded module is checked; this allows to go on with # this tool even if the version is too old; but shout out loud my $version_openssl = shift; my $version_ssleay = shift; my $version_iosocket = shift; my $txo = sprintf("ancient version openssl 0x%x", $version_openssl); my $txs = "ancient version Net::SSLeay $version_ssleay"; my $txt = "improper Net::SSLeay version;"; _y_CMD(" enable internal functionality ..."); if ($cfg{'ssleay'}->{'openssl'} == 0) { warn STR_WARN, "122: ancient Net::SSLeay $version_ssleay cannot detect openssl version"; } if ($cfg{'ssleay'}->{'iosocket'} == 0) { warn STR_WARN, "123: ancient or unknown version of IO::Socket detected"; } if ($cfg{'ssleay'}->{'can_sni'} == 0) { if(($cfg{'usesni'} > 0) and ($cmd{'extciphers'} == 0)) { $cfg{'usesni'} = 0; my $txt_buggysni = "does not support SNI or is known to be buggy; SNI disabled;"; if ($version_iosocket < 1.90) { warn STR_WARN, "124: ancient version IO::Socket::SSL $version_iosocket < 1.90; $txt_buggysni"; } if ($version_openssl < 0x01000000) { warn STR_WARN, "125: $txo < 1.0.0; $txt_buggysni"; } _hint("--force-openssl can be used to disable this check"); } } _trace(" cfg{usesni}: $cfg{'usesni'}"); if (($cfg{'ssleay'}->{'set_alpn'} == 0) or ($cfg{'ssleay'}->{'get_alpn'} == 0)) { # warnings only if ALPN functionality required # TODO: is this check necessary if ($cmd{'extciphers'} > 0)? if ($cfg{'usealpn'} > 0) { $cfg{'usealpn'} = 0; warn STR_WARN, "126: $txt tests with/for ALPN disabled"; if ($version_ssleay < 1.56) { # is also < 1.46 warn STR_WARN, "127: $txs < 1.56" if ($cfg{'verbose'} > 1); } if ($version_openssl < 0x10002000) { warn STR_WARN, "128: $txo < 1.0.2" if ($cfg{'verbose'} > 1); } _hint("--no-alpn can be used to disable this check"); } } _trace(" cfg{usealpn}: $cfg{'usealpn'}"); if ($cfg{'ssleay'}->{'set_npn'} == 0) { # warnings only if NPN functionality required if ($cfg{'usenpn'} > 0) { $cfg{'usenpn'} = 0; warn STR_WARN, "129: $txt tests with/for NPN disabled"; if ($version_ssleay < 1.46) { warn STR_WARN, "130: $txs < 1.46" if ($cfg{'verbose'} > 1); } if ($version_openssl < 0x10001000) { warn STR_WARN, "132: $txo < 1.0.1" if ($cfg{'verbose'} > 1); } _hint("--no-npn can be used to disable this check"); } } _trace(" cfg{usenpn}: $cfg{'usenpn'}"); if ($cfg{'ssleay'}->{'can_ocsp'} == 0) { warn STR_WARN, "133: $txt tests for OCSP disabled"; #_hint("--no-ocsp can be used to disable this check"); } if ($cfg{'ssleay'}->{'can_ecdh'} == 0) { warn STR_WARN, "134: $txt setting curves disabled"; #_hint("--no-cipher-ecdh can be used to disable this check"); } return; } # _enable_functions sub _check_functions { # check for required functionality # these checks print warnings with warn() not _warn(), SEE Perl:warn # verbose messages with --v=2 ; uses string "yes" for contrib/bunt.* my $txt = ""; my $tmp = ""; my $version_openssl = 0; # use 0 to avoid 0xffffffffffffffff in warnings my $version_ssleay = -1; # -1 should be always lower than anything else my $version_iosocket = -1; # -"- my $text_ssleay = "Net::SSLeay\t$version_ssleay supports"; # Note: $cfg{'ssleay'}->{'can_sni'} are set to 1 be default, will be _y_CMD(" check required modules ..."); if (not defined $Net::SSLeay::VERSION) {# Net::SSLeay auto-loaded by IO::Socket::SSL if ($cmd{'extopenssl'} == 0) { die STR_ERROR, "014: Net::SSLeay not found, useless use of SSL advanced forensic tool"; } } else { $version_ssleay = $Net::SSLeay::VERSION; $text_ssleay = "Net::SSLeay\t$version_ssleay supports"; } if (not exists &Net::SSLeay::OPENSSL_VERSION_NUMBER) { $cfg{'ssleay'}->{'openssl'} = 0; } else { $version_openssl = Net::SSLeay::OPENSSL_VERSION_NUMBER(); } if (not defined $IO::Socket::SSL::VERSION) { $cfg{'ssleay'}->{'iosocket'} = 0; } else { $version_iosocket = $IO::Socket::SSL::VERSION; } # some functionality is available in Net::SSLeay and IO::Socket::SSL, # newer versions of IO::Socket::SSL even provides variables for it # ancient versions of the modules, which do not have these functions or # variables, should be supported # that's why the checks are done here and stored in $cfg{'ssleay'}->* _y_CMD(" check for proper SNI support ..."); # TODO: change to check with: defined &Net::SSLeay::get_servername if ($version_iosocket < 1.90) { $cfg{'ssleay'}->{'can_sni'} = 0; } else { _v2print "IO::Socket::SSL\t$version_iosocket OK\tyes"; } if ($version_openssl < 0x01000000) { # same as IO::Socket::SSL->can_client_sni() # see section "SNI Support" in: perldoc IO/Socket/SSL.pm $cfg{'ssleay'}->{'can_sni'} = 0; } else { _v2print "$text_ssleay OpenSSL version\tyes"; } _y_CMD(" check if Net::SSLeay is usable ..."); if ($version_ssleay < 1.49) { warn STR_WARN, "135: $txt < 1.49; may throw warnings and/or results may be missing;"; } else { _v2print "$text_ssleay (OK)\tyes"; } _y_CMD(" check for NPN and ALPN support ..."); # SEE Note:OpenSSL Version if (($version_ssleay < 1.56) or ($version_openssl < 0x10002000)) { $cfg{'ssleay'}->{'set_alpn'} = 0; $cfg{'ssleay'}->{'get_alpn'} = 0; } else { _v2print "$text_ssleay ALPN\tyes"; } if (($version_ssleay < 1.46) or ($version_openssl < 0x10001000)) { $cfg{'ssleay'}->{'set_npn'} = 0; } else { _v2print "$text_ssleay NPN\tyes"; } if (not exists &Net::SSLeay::CTX_set_alpn_protos) { $cfg{'ssleay'}->{'set_alpn'} = 0; } else { _v2print "$text_ssleay set ALPN\tyes"; } if (not exists &Net::SSLeay::P_alpn_selected) { $cfg{'ssleay'}->{'get_alpn'} = 0; } else { _v2print "$text_ssleay get ALPN\tyes"; } if (not exists &Net::SSLeay::CTX_set_next_proto_select_cb) { $cfg{'ssleay'}->{'set_npn'} = 0; } else { _v2print "$text_ssleay set NPN\tyes"; } if (not exists &Net::SSLeay::P_next_proto_negotiated) { $cfg{'ssleay'}->{'get_npn'} = 0; } else { _v2print "$text_ssleay get NPN\tyes"; } if (not exists &Net::SSLeay::OCSP_cert2ids) { # same as IO::Socket::SSL::can_ocsp() IO::Socket::SSL::can_ocsp_staple() $cfg{'ssleay'}->{'can_ocsp'} = 0; } else { _v2print "$text_ssleay OSCP\tyes"; } if (not exists &Net::SSLeay::CTX_set_tmp_ecdh) { # same as IO::Socket::SSL::can_ecdh() $cfg{'ssleay'}->{'can_ecdh'} = 0; } else { _v2print "$text_ssleay Curves\tyes"; } $cfg{'ssleay'}->{'can_npn'} = $cfg{'ssleay'}->{'get_npn'}; # alias _enable_functions($version_openssl, $version_ssleay, $version_iosocket); return; } # _check_functions sub _check_SSL_methods { # check for supported SSL version methods and add them to $cfg{'version'} # TODO: anything related to +cipherraw can be removed when Net::SSLhello # supports DTLSv1 my $typ; my @list; _y_CMD(" check supported SSL versions ..."); if (! _is_do('cipherraw')) { # +cipherraw does not need these checks @list = Net::SSLinfo::ssleay_methods(); # method names do not literally match our version string, hence the # cumbersome code below } _trace("SSLeay methods: " . join(" ", @list)); foreach my $ssl (@{$cfg{'versions'}}) { next if ($cfg{$ssl} == 0); # don't check what's disabled by option if (_is_do('cipherraw')) { # +cipherraw does not depend on other libraries if ($ssl eq 'DTLSv1') { _warn("140: SSL version '$ssl': not supported by '$me +cipherraw'; not checked"); next; } push(@{$cfg{'version'}}, $ssl); next; } # following checks for these commands only $cfg{$ssl} = 0; # reset to simplify further checks if ($ssl !~ /$cfg{'regex'}->{'SSLprot'}/) { _warn("141: SSL version '$ssl': not supported; not checked"); next; } # Net::SSLeay only supports methods for those SSL protocols which were # available at the time of compiling Net::SSLeay. The support of these # protocols is not checked dynamically when building Net::SSLeay. # Net::SSLeay's config script simply relies on the definitions found in # the specified include files of the underlaying SSL library (which is # is openssl usually). # Unfortunately, there are situations where the assumptions at compile # time do not match the conditions at runtime. Then Net::SSLeay bails # out with error like: # Can't locate auto/Net/SSLeay/CTX_v2_new.al in @INC ... # which means that Net::SSLeay was build without support for SSLv2. # To avoid bothering users with such messages (see above), or even more # errors or program aborts, we check for the availability of all needed # methods. Sometimes, for whatever reason, the user may know that the # warning can be avoided. Therfore the --ssl-lazy option can be used, # which simply disables the check. if ($cfg{'ssl_lazy'}>0) { push(@{$cfg{'version'}}, $ssl); $cfg{$ssl} = 1; next; } # Check for high-level API functions, like SSLv2_method, also possible # would be Net::SSLeay::CTX_v2_new, Net::SSLeay::CTX_tlsv1_2_new # and similar calls. # Net::SSLeay::SSLv23_method is missing in some Net::SSLeay versions, # as we don't use it, there is no need to check for it. # TODO: DTLSv9 which is DTLS 0.9 ; but is this really in use? $typ = 0; $typ++ if (($ssl eq 'SSLv2') and (grep{/^SSLv2_method$/} @list)); $typ++ if (($ssl eq 'SSLv3') and (grep{/^SSLv3_method$/} @list)); $typ++ if (($ssl eq 'TLSv1') and (grep{/^TLSv1_method$/} @list)); $typ++ if (($ssl eq 'TLSv11') and (grep{/^TLSv1_1_method$/} @list)); $typ++ if (($ssl eq 'TLSv12') and (grep{/^TLSv1_2_method$/} @list)); $typ++ if (($ssl eq 'TLSv13') and (grep{/^TLSv1_3_method$/} @list)); $typ++ if (($ssl eq 'DTLSv1') and (grep{/^DTLSv1_method$/} @list)); $typ++ if (($ssl eq 'DTLSv11') and (grep{/^DTLSv1_1_method$/} @list)); $typ++ if (($ssl eq 'DTLSv12') and (grep{/^DTLSv1_2_method$/} @list)); $typ++ if (($ssl eq 'DTLSv13') and (grep{/^DTLSv1_3_method$/} @list)); $typ++ if (($ssl eq 'SSLv2') and (grep{/^SSLv23_method$/} @list)); $typ++ if (($ssl eq 'SSLv3') and (grep{/^SSLv23_method$/} @list)); # TODO: not sure if SSLv23_method also supports TLSv1, TLSv11, TLSv12 if ($typ > 0) { push(@{$cfg{'version'}}, $ssl); $cfg{$ssl} = 1; } else { _warn("143: SSL version '$ssl': not supported by Net::SSLeay; not checked"); _hint("consider using '+cipherall' instead") if (_is_do('cipher')); } } # $ssl if (! _is_do('version')) { _v_print("supported SSL versions: @{$cfg{'versions'}}"); _v_print(" checked SSL versions: @{$cfg{'version'}}"); } return; } # _check_SSL_methods sub _enable_sclient { # enable internal functionality based on available functionality of openssl s_client # SEE Note:OpenSSL s_client my $opt = shift; _y_CMD(" check openssl s_client cpapbility $opt ...") if ($cfg{verbose} > 0); my $txt = $cfg{'openssl'}->{$opt}[1] || STR_UNDEF; # my be undefined my $val = $cfg{'openssl'}->{$opt}[0]; # 1 if supported if ($val == 0) { if ($opt =~ m/^-(?:alpn|npn|curves)$/) { # no warning for external openssl, as -alpn or -npn is only used with +cipher if ($cmd{'extciphers'} > 0) { _warn("144: openssl s_client does not support '$opt'; $txt") if ($txt ne ""); } } else { _warn("145: openssl s_client does not support '$opt'; $txt") if ($txt ne ""); } if ($opt eq '-tlsextdebug') { # additional warning _warn("146: openssl -tlsextdebug not supported; following results may be wrong: +heartbeat, +heartbleed, +session_ticket, +session_lifetime"); } # switch $opt { $cfg{'use_reconnect'} = $val if ($opt eq '-reconnect'); $cfg{'use_extdebug'} = $val if ($opt eq '-tlsextdebug'); $cfg{'usealpn'} = $val if ($opt eq '-alpn'); $cfg{'usenpn'} = $val if ($opt eq '-npn'); $cfg{'sni'} = $val if ($opt eq '-servername'); $cfg{'ca_file'} = undef if ($opt =~ /^-CAfile/i); $cfg{'ca_path'} = undef if ($opt =~ /^-CApath/i); # } } # TODO: remove commands, i.e. +s_client, +heartbleed, from $cmd{do} # -fallback_scsv: remove +scsv and +fallback return; } # _enable_sclient sub _reset_openssl { # reset all %cfg and %cmd settings according openssl executable $cmd{'openssl'} = ""; $cmd{'extopenssl'} = 0; $cmd{'extsclient'} = 0; $cmd{'extciphers'} = 0; # TODO: Net::SSLinfo not yet included ... #foreach my $opt (Net::SSLinfo::s_client_get_optionlist()) { # $cfg{'openssl'}->{$opt}[0] = 0; #} return; } # _reset_openssl sub _check_openssl { _y_CMD(" check cpapbilities of openssl ..."); return if ($cmd{'openssl'} eq ""); # already checked and warning printed $Net::SSLinfo::openssl = $cmd{'openssl'}; # this version should be checked $Net::SSLinfo::trace = $cfg{'trace'}; # save to set $Net::SSLinfo::* here, # will be redifined later, see: set defaults for Net::SSLinfo if (not defined Net::SSLinfo::s_client_check()) { _warn("147: '$cmd{'openssl'}' not available; all openssl functionality disabled"); _hint("consider using '--openssl=/path/to/openssl'"); _reset_openssl(); } # NOTE: if loading Net::SSLinfo failed, then we get a Perl warning here: # Undefined subroutine &Net::SSLinfo::s_client_check called at ... # Net::SSLinfo::s_client_check() is used to check openssl's capabilities. # For an example output SEE Note:OpenSSL s_client # Each capability can be queried with Net::SSLinfo::s_client_opt_get(). # I.g. all checks are done in Net::SSLinfo::s_client_*(), but no proper # error messages are printed there. Hence the checks are done here again # to disable all unavailable functionality with a warning. Finally store # result (capability is supported or not) in $cfg{'openssl'} . foreach my $opt (Net::SSLinfo::s_client_get_optionlist()) { # Perl warning "Use of uninitialized value in ..." here indicates # that cfg{openssl} is not properly initialized my $val = Net::SSLinfo::s_client_opt_get($opt); $val = 0 if ($val eq '<>'); # TODO: <> from Net::SSLinfo # _dbx "$opt $val"; $cfg{'openssl'}->{$opt}[0] = $val; next if ($cfg{'openssl'}->{$opt}[1] eq "<>"); _enable_sclient($opt); } # TODO: checks not yet complete # TODO: should check openssl with a real connection return; } # _check_openssl sub _init_opensslexe { # check if openssl exists, return full path # i.g. we may rely on bare word openssl which then would be found using # $PATH, but it's better to have a clear definition right away because it # avoids errors # $cmd{'openssl'} not passed as parameter, as it will be changed here my $exe = ""; foreach my $p ("", split(/:/, $ENV{'PATH'})) { # try to find path # "" above ensures that full path in $openssl will be checked $exe = "$p/$cmd{'openssl'}"; last if (-e $exe); $exe = ""; } $exe =~ s#//#/#g; # make a nice path (see first path "" above) if ($exe eq "" or $exe eq "/") { $exe = ""; _warn("149: no executable for '$cmd{'openssl'}' found; all openssl functionality disabled"); _hint("consider using '--openssl=/path/to/openssl'"); _reset_openssl(); } _v_print("_init_opensslexe: $exe"); return $exe; } # _init_opensslexe sub _init_openssldir { # returns openssl-specific path for CAs; checks if OPENSSLDIR/certs exists # resets cmd{'openssl'}, cmd{'extopenssl'} and cmd{'extsclient'} on error # SEE Note:OpenSSL CApath # $cmd{'openssl'} not passed as parameter, as it will be changed here return "" if ($cmd{'openssl'} eq ""); # defensive programming my $dir = qx($cmd{'openssl'} version -d); # get something like: OPENSSLDIR: "/usr/local/openssl" chomp $dir; # if qx() above failed, we get: Use of uninitialized value $dir in ... my $status = $?; my $error = $!; my $capath = ""; local $\ = "\n"; _trace("_init_openssldir: $dir"); if (($error ne "") && ($status != 0)) { # we ignore error messages for status==0 # When there is a status and an error message, external call failed. # Print error message and disable external openssl. # In rare cases (i.e. VM with low memory) external call fails due to # malloc() problems, in this case print an additional warning. # Note that low memory affects external calls only *but not* further # control flow herein as Perl already managed to load the script. # For defensive programming print() is used insted of _warn(). print STR_WARN, "002: perl returned error: '$error'\n"; if ($error =~ m/allocate memory/) { print STR_WARN, "003: using external programs disabled.\n"; print STR_WARN, "003: data provided by external openssl may be shown as: <>\n"; } _reset_openssl(); $status = 0; # avoid following warning below } else { # process only if no errors to avoid "Use of uninitialized value" my $openssldir = $dir; $dir =~ s#[^"]*"([^"]*)"#$1#; if (-e "$dir/certs") { $capath = "$dir/certs"; } else { # no directory found, add path to common paths as last resort _warn("148: 'openssl version -d' returned not existing: '$openssldir'; ca_path not set ."); unshift(@{$cfg{'ca_paths'}}, $dir); # dirty hack (but dosn't harm:) } } if ($status != 0) { # on Windoze status may be 256 $cmd{'openssl'} = ""; print STR_WARN, "004: perl returned status: '$status' ('" . ($status>>8) . "')\n"; # no other warning here, see "some checks are missing" later, # this is to avoid bothering the user with warnings, when not used # $capath = ""; # should still be empty } _trace("_init_openssldir: ca_path=$cfg{'ca_paths'} ."); return $capath; } # _init_openssldir sub _init_openssl_ca { # returns openssl-specific path containing CA file my $ca_path = shift; return $ca_path if (not defined $ca_path or $ca_path eq ""); # search in given path foreach my $f (@{$cfg{'ca_files'}}) { # check if CA exists in 'ca_path' my $ca = "$cfg{'ca_path'}/$f"; return "$ca" if -e "$ca"; } _warn("058: given path '$ca_path' does not contain a CA file"); # search for a path from list, use first containing a CA foreach my $p (@{$cfg{'ca_paths'}}) { foreach my $f (@{$cfg{'ca_files'}}) { if (-e "$p/$f") { _warn("059: found PEM fila for CA; using '--ca-path=$p'"); return $p; # ugly return from inner loop; but exactly what we want } } } return; # same as: return undef } # _init_openssl_ca sub _initchecks_score { # set all default score values here $checks{$_}->{score} = 10 foreach (keys %checks); # some special values %checks{'sts_maxage*'} $checks{'sts_maxage0d'}->{score} = 0; # very weak $checks{'sts_maxage1d'}->{score} = 10; # weak $checks{'sts_maxage1m'}->{score} = 20; # low $checks{'sts_maxage1y'}->{score} = 70; # medium $checks{'sts_maxagexy'}->{score} = 100; # high $checks{'sts_maxage18'}->{score} = 100; # high foreach (keys %checks) { $checks{$_}->{score} = 90 if (m/WEAK/i); $checks{$_}->{score} = 30 if (m/LOW/i); $checks{$_}->{score} = 10 if (m/MEDIUM/i); } return; } # _initchecks_score sub _initchecks_val { # set all default check values here $checks{$_}->{val} = "" foreach (keys %checks); # some special values %checks{'sts_maxage*'} $checks{'sts_maxage0d'}->{val} = 1; $checks{'sts_maxage1d'}->{val} = 86400; # day $checks{'sts_maxage1m'}->{val} = 2592000; # month $checks{'sts_maxage1y'}->{val} = 31536000; # year $checks{'sts_maxagexy'}->{val} = 99999999; $checks{'sts_maxage18'}->{val} = 10886400; # 18 weeks foreach (keys %checks) { $checks{$_}->{val} = 0 if (m/$cfg{'regex'}->{'cmd-sizes'}/); $checks{$_}->{val} = 0 if (m/$cfg{'regex'}->{'SSLprot'}/); } return; } # _initchecks_val sub _init_all { # set all default values here $cfg{'done'}->{'init_all'}++; _trace("_init_all(){}"); _initchecks_score(); _initchecks_val(); $cfg{'hints'}->{$_} = $text{'hints'}->{$_} foreach (keys %{$text{'hints'}}); # _init_openssldir(); # not done here because it needs openssl command, which may be set by # options, hence the call must be done after reading arguments return; } # _init_all _init_all(); # initialize defaults in %checks (score, val) sub _resetchecks { # reset values foreach (keys %{$cfg{'done'}}) { next if (!m/^check/); # only reset check* $cfg{'done'}->{$_} = 0; } $cfg{'done'}->{'ciphers_all'} = 0; $cfg{'done'}->{'ciphers_get'} = 0; _initchecks_val(); return; } # _resetchecks sub _prot_cipher($$) { my @txt = @_; return " " . join(":", @txt); } # return string consisting of given parameters separated by : and prefixed with a space # (mainly used to concatenate SSL Version and cipher suite name) sub _getscore($$$) { # return score value from given hash; 0 if given value is empty, otherwise score to given key my $key = shift; my $value = shift || ""; my $hashref = shift;# list of checks my %hash = %$hashref; return 0 if ($value eq ""); my $score = $hash{$key}->{score} || 0; _trace("_getscore($key, '$value')\t= $score"); return $score; } # _getscore sub _cfg_set($$); # avoid: main::_cfg_set() called too early to check prototype at ... sub _cfg_set_from_file($$) { # read values to be set in configuration from file my $typ = shift; # type of config value to be set my $fil = shift; # filename _trace("_cfg_set: read $fil \n"); my $line =""; my $fh; # NOTE: critic complains with InputOutput::RequireCheckedOpen, which # is a false positive, because Perl::Critic seems not to understand # the logic of "open() && do{}; warn();", hence the code was changed # to use an if-condition if (open($fh, '<:encoding(UTF-8)', $fil)) { push(@{$dbx{file}}, $fil); _print_read("$fil", "USER-FILE configuration file") if ($cfg{'out_header'} > 0); while ($line = <$fh>) { # # format of each line in file must be: # Lines starting with = are comments and ignored. # Anthing following (and including) a hash is a comment # and ignored. Empty lines are ignored. # Settings must be in format: key=value # where white spaces are allowed around = chomp $line; $line =~ s/\s*#.*$// if ($typ !~ m/^CFG-text/i); # remove trailing comments, but CFG-text may contain hash (#) next if ($line =~ m/^\s*=/);# ignore our header lines (since 13.12.11) next if ($line =~ m/^\s*$/);# ignore empty lines _trace("_cfg_set: set $line "); _cfg_set($typ, $line); } close($fh); return; }; _warn("070: configuration file '$fil' cannot be opened: $! ; file ignored"); return; } # _cfg_set_from_file sub _cfg_set($$) { # set value in configuration %cfg, %checks, %data, %text # $typ must be any of: CFG-text, CFG-score, CFG-cmd-* # if given value is a file, read settings from that file # otherwise given value must be KEY=VALUE format; # NOTE: may define new commands for CFG-cmd my $typ = shift; # type of config value to be set my $arg = shift; # KEY=VAL or filename my ($key, $val); _trace("_cfg_set($typ, ){"); if ($typ !~ m/^CFG-$cfg{'regex'}->{'cmd-cfg'}/) { _warn("071: configuration key unknown '$typ'; setting ignored"); goto _CFG_RETURN; } if (($arg =~ m|^[a-zA-Z0-9,._+#()\/-]+|) and (-f "$arg")) { # read from file # we're picky about valid filenames: only characters, digits and some # special chars (this should work on all platforms) if ($cgi == 1) { # SEE Note:CGI mode _warn("072: configuration files are not read in CGI mode; ignored"); return; } _cfg_set_from_file($typ, $arg); goto _CFG_RETURN; } # read file ($key, $val) = split(/=/, $arg, 2); # left of first = is key $key =~ s/[^a-zA-Z0-9_?=+-]*//g; # strict sanatize key $val = "" if not defined $val; # avoid warnings when not KEY=VALUE $val =~ s/^[+]//; # remove first + in command liss $val =~ s/ [+]/ /g; # remove + in commands if ($typ eq 'CFG-cmd') { # set new list of commands $arg $typ = 'cmd-' . $key ;# the command to be set, i.e. cmd-http, cmd-sni, ... _trace("_cfg_set: cfg{$typ}, KEY=$key, CMD=$val"); @{$cfg{$typ}} = (); push(@{$cfg{$typ}}, split(/\s+/, $val)); foreach my $key (@{$cfg{$typ}}){# check for mis-spelled commands next if (_is_hashkey($key, \%checks) > 0); next if (_is_hashkey($key, \%data) > 0); next if (_is_intern( $key) > 0); next if (_is_member( $key, \@{$cfg{'cmd-NL'}}) > 0); if ($key eq 'protocols') { # valid before 17.02.26; behave smart for old rc-files push(@{$cfg{$typ}}, 'next_protocols'); next; } if ($key eq 'default') { # valid before 14.11.14; behave smart for old rc-files push(@{$cfg{$typ}}, 'cipher_selected'); _warn("073: configuration: please use '+cipher-selected' instead of '+$key'; setting ignored"); next; } _warn("074: configuration: unknown command '+$key' for '$typ'; setting ignored"); } # check if it is a known command, otherwise add it and print warning if ((_is_member($key, \@{$cfg{'commands'}}) + _is_member($key, \@{$cfg{'commands-CMD'}}) + _is_member($key, \@{$cfg{'commands-INT'}}) ) < 1) { # NOTE: new commands are added only if they are not yet defined, # wether as internal, as summary or as (previously defined) user # command. The new command must also consists only of a-z0-9_.- # charchters. If any of these conditions fail, the command will # be ignored silently. if (_is_member("cmd-$key", \@{$cfg{'commands-CMD'}}) == 0) { # needed more checks, as these commands are defined as cmd-* if ($key =~ m/^([a-z0-9_.-]+)$/) { # whitelust check for valid characters; avoid injections push(@{$cfg{'commands-USR'}}, $key); _warn("043: command '+$key' specified by user") if _is_v_trace(); } } } } # invalid keys are silently ignored (Perl is that clever:) if ($typ eq 'CFG-score') { # set new score value _trace("_cfg_set: KEY=$key, SCORE=$val"); if ($val !~ m/^(?:\d\d?|100)$/) { # allow 0 .. 100 _warn("076: configuration: invalid score value '$val'; setting ignored"); goto _CFG_RETURN; } $checks{$key}->{score} = $val if ($checks{$key}); } $val =~ s/(\\n)/\n/g; $val =~ s/(\\r)/\r/g; $val =~ s/(\\t)/\t/g; _trace("_cfg_set: KEY=$key, TYP=$typ, LABEL=$val"); $checks{$key}->{txt} = $val if ($typ =~ /^CFG-check/); $data{$key} ->{txt} = $val if ($typ =~ /^CFG-data/); $data{$key} ->{txt} = $val if ($typ =~ /^CFG-info/); # alias for --cfg-data $cfg{'hints'}->{$key}= $val if ($typ =~ /^CFG-hint/); # allows CFG-hints also $text{$key} = $val if ($typ =~ /^CFG-text/); # allows CFG-texts also $scores{$key}->{txt} = $val if ($typ =~ /^CFG-scores/); # BUT: CFG-score is different $scores{$key}->{txt} = $val if ($key =~ m/^check_/); # contribution to lazy usage _CFG_RETURN: _trace("_cfg_set() }"); return; } # _cfg_set sub _cfg_set_init { # set value in configuration %cfg; for debugging and test only my ($typ, $arg) = @_; my ($key, $val) = split(/=/, $arg, 2); # left of first = is key _warn("075: TESTING only: setting configuration: 'cfg{$key}=$val';"); #_dbx "typeof: " . ref($cfg{$key}); SWITCH: for (ref($cfg{$key})) { /^$/ && do { $cfg{$key} = $val ; }; # same as SCALAR /SCALAR/ && do { $cfg{$key} = $val ; }; /ARRAY/ && do { @{$cfg{$key}} = ($val); }; /HASH/ && do { %{$cfg{$key}} = $val ; }; # TODO: not yet working /CODE/ && do { _warn("999: cannot set CODE"); }; } # SWITCH return; } # _cfg_set_init sub _cfg_set_cipher($$) { # set value for security of cipher in configuration %ciphers my ($typ, $arg) = @_; my ($key, $val) = split(/=/, $arg, 2); # left of first = is key #dbx# _dbx "arg: $arg # key: $key # val: $val"; ${$ciphers{$key}}[0] = $val; #dbx# _dbx @{$ciphers{$key}}; return; } # _cfg_set_cipher # check functions for array members and hash keys sub __SSLinfo($$$) { # wrapper for Net::SSLinfo::*() functions # Net::SSLinfo::*() return raw data, depending on $cfg{'format'} # these values will be converted to o-saft's preferred format my ($cmd, $host, $port) = @_; my $val = "<<__SSLinfo: unknown command: '$cmd'>>"; my $ext = ""; $val = Net::SSLinfo::fingerprint( $host, $port) if ($cmd eq 'fingerprint'); $val = Net::SSLinfo::fingerprint_hash( $host, $port) if ($cmd eq 'fingerprint_hash'); $val = Net::SSLinfo::fingerprint_sha2( $host, $port) if ($cmd eq 'fingerprint_sha2'); $val = Net::SSLinfo::fingerprint_sha1( $host, $port) if ($cmd eq 'fingerprint_sha1'); $val = Net::SSLinfo::fingerprint_md5( $host, $port) if ($cmd eq 'fingerprint_md5'); $val = Net::SSLinfo::pubkey_value( $host, $port) if ($cmd eq 'pubkey_value'); $val = Net::SSLinfo::sigkey_value( $host, $port) if ($cmd eq 'sigkey_value'); $val = Net::SSLinfo::heartbeat( $host, $port) if ($cmd eq 'heartbeat'); $val = Net::SSLinfo::extensions( $host, $port) if ($cmd =~ /^ext(?:ensions|_)/); $val = Net::SSLinfo::tlsextdebug( $host, $port) if ($cmd eq 'tlsextdebug'); if ($cmd eq 'tlsextensions') { $val = Net::SSLinfo::tlsextensions($host, $port); $val =~ s/^\s*//g; $val =~ s/([\n\r])/; /g; } # ::ocspid may return multiple lines, something like: # Subject OCSP hash: 57F4D68F870A1698065F803BE9D967B1B2B9E491 # Public key OCSP hash: BF788D39424E219C62538F72701E1C87C4F667EA # it's also assumed that both lines are present if ($cmd =~ /ocspid/) { $val = Net::SSLinfo::ocspid($host, $port); $val =~ s/^\n?\s+//g; # remove leading spaces $val =~ s/([\n\r])/; /g;# remove newlines } if ($cmd =~ /ocsp_subject_hash/) { $val = Net::SSLinfo::ocspid($host, $port); $val =~ s/^[^:]+:\s*//; $val =~ s/.ublic[^:]+:\s*.*//; } if ($cmd =~ /ocsp_public_hash/) { $val = Net::SSLinfo::ocspid($host, $port); $val =~ s/^[^:]+:\s*//; $val =~ s/^[^:]+:\s*//; # TODO: quick&dirty } if ($cmd =~ m/ext_/) { # all following are part of Net::SSLinfo::extensions(), now extract parts # The extension section in the certificate starts with # X509v3 extensions: # then each extension starts with a string prefixed by X509v3 # except following: # Authority Information Access # Netscape Cert Type # CT Precertificate SCTs # # Example www.microsoft.com (03/2016) # X509v3 extensions: # X509v3 Subject Alternative Name: # DNS:privacy.microsoft.com, DNS:www.microsoft.com, DNS:wwwqa.microsoft.com # X509v3 Basic Constraints: # CA:FALSE # X509v3 Key Usage: critical # Digital Signature, Key Encipherment # X509v3 Extended Key Usage: # TLS Web Server Authentication, TLS Web Client Authentication # X509v3 Certificate Policies: # Policy: 2.16.840.1.113733.1.7.23.6 # CPS: https://d.symcb.com/cps # User Notice: # Explicit Text: https://d.symcb.com/rpa # X509v3 Authority Key Identifier: # keyid:0159ABE7DD3A0B59A66463D6CF200757D591E76A # X509v3 CRL Distribution Points: # Full Name: # URI:http://sr.symcb.com/sr.crl # Authority Information Access: # OCSP - URI:http://sr.symcd.com # CA Issuers - URI:http://sr.symcb.com/sr.crt # CT Precertificate SCTs: # Signed Certificate Timestamp: # Version : v1(0) # Log ID : DDEB1D2B7A0D4FA6208B81AD8168707E: # 2E8E9D01D55C888D3D11C4CDB6ECBECC # Timestamp : Mar 24 212018.939 2016 GMT # Extensions: none # Signature : ecdsa-with-SHA256 # 304602210095B30A493A8E8B253004AD: # A971E0106BE0CC97B6FF2908FDDBBB3D: # B8CEBFFCF8022100F37AA34DE5BE38D8: # 5A03EE8B3AAE451C0014A802C079AA34: # 9C20BAF44C54CF36 # Signed Certificate Timestamp: # Version : v1(0) # Log ID : A4B90990B418581487BB13A2CC67700A: # 3C359804F91BDFB8E377CD0EC80DDC10 # Timestamp : Mar 24 212018.983 2016 GMT # Extensions: none # Signature : ecdsa-with-SHA256 # 3046022100C877DC1DBBDA2FBC7E5E63: # 60A7EAB31EED42066F91C724963EE0CE: # 80C8EBCE8C022100D5865704F32487CF: # FF021F1C8A955303E496630CAE3C0F18: # B8CDDFD4798365FD # ... # # Example microsoft.com # X509v3 extensions: # X509v3 Key Usage: # Digital Signature, Key Encipherment, Data Encipherment # X509v3 Extended Key Usage: # TLS Web Server Authentication, TLS Web Client Authentication # S/MIME Capabilities: # 0000 - 30 69 30 0e 06 08 2a 86-48 86 f7 0d 03 0i0...*.H.... # 000d - 02 02 02 00 80 30 0e 06-08 2a 86 48 86 .....0...*.H. # 001a - f7 0d 03 04 02 02 00 80-30 0b 06 09 60 ........0...` # 0027 - 86 48 01 65 03 04 01 2a-30 0b 06 09 60 .H.e...*0...` # 0034 - 86 48 01 65 03 04 01 2d-30 0b 06 09 60 .H.e...-0...` # 0041 - 86 48 01 65 03 04 01 02-30 0b 06 09 60 .H.e....0...` # 004e - 86 48 01 65 03 04 01 05-30 07 06 05 2b .H.e....0...+ # 005b - 0e 03 02 07 30 0a 06 08-2a 86 48 86 f7 ....0...*.H.. # 0068 - 0d 03 07 ... # X509v3 Subject Key Identifier: # 84C60E3B0FA69BF6EE0640CB02041B5F59340F73 # X509v3 Authority Key Identifier: # keyid:51AF24269CF468225780262B3B4662157B1ECCA5 # X509v3 CRL Distribution Points: # Full Name: # URI:http://mscrl.microsoft.com/pki/mscorp/crl/msitwww2.crl # URI:http://crl.microsoft.com/pki/mscorp/crl/msitwww2.crl # Authority Information Access: # CA Issuers - URI:http://www.microsoft.com/pki/mscorp/msitwww2.crt # OCSP - URI:http://ocsp.msocsp.com # X509v3 Certificate Policies: # Policy: 1.3.6.1.4.1.311.42.1 # CPS: http://www.microsoft.com/pki/mscorp/cps # 1.3.6.1.4.1.311.21.10: # 0000 - 30 18 30 0a 06 08 2b 06-01 05 05 07 03 0.0...+...... # 000d - 01 30 0a 06 08 2b 06 01-05 05 07 03 02 .0...+....... # ... # # Example bsi.bund.de (03/2016) # X509v3 extensions: # X509v3 Authority Key Identifier: # keyid:5404296FA293C6903145C03DDE2BE20A6980925F # X509v3 Key Usage: critical # Digital Signature, Key Encipherment # X509v3 Extended Key Usage: # TLS Web Client Authentication, TLS Web Server Authentication # X509v3 Subject Key Identifier: # 1BA42D9746798AE2AE91D60AA60BE40FAA8A299E # X509v3 Certificate Policies: # Policy: 1.3.6.1.4.1.7879.13.2 # CPS: http://www.telesec.de/serverpass/cps.html # Policy: 2.23.140.1.2.2 # X509v3 CRL Distribution Points: # Full Name: # URI:http://crl.serverpass.telesec.de/rl/TeleSec_ServerPass_DE-2.crl # Full Name: # URI:ldap://ldap.serverpass.telesec.de/cn=TeleSec%20ServerPass%20DE-2,ou=T-Systems%20Trust%20Center,o=T-Systems%20International%20GmbH,c=de?certificateRevocationlist?base?certificateRevocationlist=* # Authority Information Access: # OCSP - URI:http://ocsp.serverpass.telesec.de/ocspr # CA Issuers - URI:http://crl.serverpass.telesec.de/crt/TeleSec_ServerPass_DE-2.cer # CA Issuers - URI:ldap://ldap.serverpass.telesec.de/cn=TeleSec%20ServerPass%20DE-2,ou=T-Systems%20Trust%20Center,o=T-Systems%20International%20GmbH,c=de?cACertificate # X509v3 Basic Constraints: critical # CA:FALSE # X509v3 Subject Alternative Name: # DNS:www.bsi.bund.de # # Example www.bsi.de (06/2016) # X509v3 CRL Distribution Points: # # Full Name: # URI:http://crl.serverpass.telesec.de/rl/TeleSec_ServerPass_DE-2.crl # # Full Name: # URI:ldap://ldap.serverpass.telesec.de/cn=TeleSec%20ServerPass%20DE-2,ou=T-Systems%20Trust%20Center,o=T-Systems%20International%20GmbH,c=de?certificateRevocationlist?base?certificateRevocationlist=* # Authority Information Access: # OCSP - URI:http://ocsp.serverpass.telesec.de/ocspr # CA Issuers - URI:http://crl.serverpass.telesec.de/crt/TeleSec_ServerPass_DE-2.cer # CA Issuers - URI:ldap://ldap.serverpass.telesec.de/cn=TeleSec%20ServerPass%20DE-2,ou=T-Systems%20Trust%20Center,o=T-Systems%20International%20GmbH,c=de?cACertificate # # handled in RegEx below which matches next extension, if any. $val .= " X509";# add string to match last extension also my $rex = '\s*(.*?)(?:X509|Authority|Netscape|CT Precertificate).*'; # FIXME: the RegEx should match OIDs also # FIXME: otherwise OID extensions are added as value to the # preceding extension, see example above (4/2016) # FIXME: replace following list of RegEx with a loop over the extensions $ext = $val; $val =~ s#.*?Authority Information Access:$rex#$1#ms if ($cmd eq 'ext_authority'); $val =~ s#.*?Authority Key Identifier:$rex#$1#ms if ($cmd eq 'ext_authorityid'); $val =~ s#.*?Basic Constraints:$rex#$1#ms if ($cmd eq 'ext_constraints'); $val =~ s#.*?Key Usage:$rex#$1#ms if ($cmd eq 'ext_keyusage'); $val =~ s#.*?Subject Key Identifier:$rex#$1#ms if ($cmd eq 'ext_subjectkeyid'); $val =~ s#.*?Certificate Policies:$rex#$1#ms if ($cmd =~ /ext_cps/); $val =~ s#.*?CPS\s*:\s*([^\s\n]*).*#$1#ms if ($cmd eq 'ext_cps_cps'); $val =~ s#.*?Policy\s*:\s*(.*?)(?:\n|CPS|User).*#$1#ims if ($cmd eq 'ext_cps_policy'); $val =~ s#.*?User\s*Notice:\s*(.*?)(?:\n|CPS|Policy).*#$1#ims if ($cmd eq 'ext_cps_notice'); $val =~ s#.*?CRL Distribution Points:$rex#$1#ms if ($cmd eq 'ext_crl'); $val =~ s#.*?Extended Key Usage:$rex#$1#ms if ($cmd eq 'ext_extkeyusage'); $val =~ s#.*?Netscape Cert Type:$rex#$1#ms if ($cmd eq 'ext_certtype'); $val =~ s#.*?Issuer Alternative Name:$rex#$1#ms if ($cmd eq 'ext_issuer'); if ($cmd eq 'ext_crl') { $val =~ s#\s*Full Name:\s*##imsg; # multiple occourances possible $val =~ s#(\s*URI\s*:)# #msg; } $val = "" if ($ext eq $val); # nothing changed, then expected pattern is missing } # TODO: move code for formatting to print*() if ($cmd =~ /ext(?:ensions|debug|_)/) { # grrr, formatting extensions is special, take care for traps ... if ($cfg{'format'} ne "raw") { $val =~ s/([0-9a-f]):([0-9a-f])/$1$2/ig; # remove : inside hex (quick&dirty) # it was quick&dirty, correct some failures $val =~ s/(keyid)/$1:/i; $val =~ s/(CA)(FALSE)/$1:$2/i; if ($cmd eq 'extensions') { # extensions are special as they contain multiple values # values are separated by emty lines $val =~ s/\n\n+/\n/g; # remove empty lines } else { $val =~ s/\s\s+/ /g; # remove multiple spaces } } return $val; # ready! } # TODO: move code for formatting to print*() if ($cfg{'format'} ne "raw") { $val = "" if not defined $val; # avoid warnings $val =~ s/^\s+//g; # remove leading spaces $val =~ s/\n\s+//g; # remove trailing spaces $val =~ s/\n/ /g; $val =~ s/\s\s+/ /g; # remove multiple spaces $val =~ s/([0-9a-f]):([0-9a-f])/$1$2/ig; # remove : inside hex (quick&dirty) } return $val; } # __SSLinfo sub _subst($$) { my ($is,$txt)=@_; $is=~s/@@/$txt/; return $is; } # return given text with '@@' replaced by given value sub _get_text($$) { my ($is,$txt)=@_; return _subst($text{$is}, $txt); } # for given index of %text return text with '@@' replaced by given value sub _need_this($) { # returns >0 if any of the given commands is listed in $cfg{'$_'} my $key = shift; my $is = join("|", @{$cfg{'do'}}); $is =~ s/\+/\\+/g; # we have commands with +, needs to be escaped return grep{/^($is)$/} @{$cfg{$key}}; } # _need_this sub _need_cipher() { return _need_this('need-cipher'); }; sub _need_default() { return _need_this('need-default'); }; sub _need_checkssl() { return _need_this('need-checkssl'); }; sub _need_checkalpn() { return _need_this('need-checkalpn'); }; sub _need_checkbleed() { return _need_this('need-checkbleed'); }; sub _need_checkchr() { return _need_this('need-checkchr'); }; sub _need_checkdest() { return _need_this('need-checkdest'); }; sub _need_check_dh() { return _need_this('need-check_dh'); }; sub _need_checkhttp() { return _need_this('need-checkhttp'); }; sub _need_checkprot() { return _need_this('need-checkprot'); }; # returns >0 if any of the given commands is listed in $cfg{need-*} sub _is_hashkey($$) { my ($is,$ref)=@_; return grep({lc($is) eq lc($_)} keys %{$ref}); } sub _is_member($$) { my ($is,$ref)=@_; return grep({lc($is) eq lc($_)} @{$ref}); } sub _is_do($) { my $is=shift; return _is_member($is, \@{$cfg{'do'}}); } sub _is_intern($) { my $is=shift; return _is_member($is, \@{$cfg{'commands-INT'}}); } sub _is_hexdata($) { my $is=shift; return _is_member($is, \@{$cfg{'data_hex'}}); } sub _is_call($) { my $is=shift; return _is_member($is, \@{$cmd{'call'}}); } # returns >0 if any of the given string is listed in $cfg{*} #| definitions: check functions #| ------------------------------------- sub _setvalue($){ my $val=shift; return ($val eq "") ? 'yes' : 'no (' . $val . ')'; } # return 'yes' if given value is empty, return 'no' otherwise sub _isbeast($$){ # return given cipher if vulnerable to BEAST attack, empty string otherwise my ($ssl, $cipher) = @_; return "" if ($ssl !~ /(?:SSL|TLSv1$)/); # TLSv11 or later are not vulnerable to BEAST return $cipher if ($cipher =~ /$cfg{'regex'}->{'BEAST'}/); return ""; } # _isbeast ### _isbreach($) { return "NOT YET IMPLEMEMNTED"; } sub _isbreach($){ # return 'yes' if vulnerable to BREACH return ""; # TODO: checks # To be vulnerable, a web application must: # Be served from a server that uses HTTP-level compression # Reflect user-input in HTTP response bodies # Reflect a secret (such as a CSRF token) in HTTP response bodies # * agnostic to the version of TLS/SSL # * does not require TLS-layer compression # * works against any cipher suite # * can be executed in under a minute } # _isbreach sub _iscrime { # return compression or SPDY/3 if available, empty string otherwise # $val is usually $data{'compression'}->{val} my ($val, $protocols) = @_; my $ret = ($val =~ /$cfg{'regex'}->{'nocompression'}/) ? "" : $val . " "; $ret .= ($protocols =~ /$cfg{'regex'}->{'isSPDY3'}/) ? "SPDY/3 " : ""; # http://zoompf.com/2012/09/explaining-the-crime-weakness-in-spdy-and-ssl return $ret; } # _iscrime sub _islucky($) { my $val=shift; return ($val =~ /$cfg{'regex'}->{'Lucky13'}/) ? $val : ""; } # return given cipher if vulnerable to Lucky 13 attack, empty string otherwise sub _istime($) { return 0; } # TODO: checks; good: AES-GCM or AES-CCM sub _isfreak($$){ # return given cipher if vulnerable to FREAK attack, empty string otherwise my ($ssl, $cipher) = @_; return "" if ($ssl !~ /(?:SSLv3)/); # TODO: probaly only SSLv3 is vulnerable return $cipher if ($cipher =~ /$cfg{'regex'}->{'FREAK'}/); return ""; } # _isfreak sub _islogjam($$) { # return given cipher if vulnerable to logjam attack, empty string otherwise my ($ssl, $cipher) = @_; return $cipher if ($cipher =~ /$cfg{'regex'}->{'Logjam'}/); return ""; } # _islogjam sub _isrobot($$){ # return given cipher if vulnerable to ROBOT attack, empty string otherwise my ($ssl, $cipher) = @_; #return "" if ($cipher =~ /$cfg{'regex'}->{'notROBOT'}/); return $cipher if ($cipher =~ /$cfg{'regex'}->{'ROBOT'}/); return ""; } # _isrobot sub _issloth($$){ # return given cipher if vulnerable to SLOTH attack, empty string otherwise my ($ssl, $cipher) = @_; return $cipher if ($cipher =~ /$cfg{'regex'}->{'SLOTH'}/); return ""; } # _issloth sub _issweet($$){ # return given cipher if vulnerable to Sweet32 attack, empty string otherwise my ($ssl, $cipher) = @_; return "" if ($cipher =~ /$cfg{'regex'}->{'notSweet32'}/); return $cipher if ($cipher =~ /$cfg{'regex'}->{'Sweet32'}/); return ""; } # _issweet sub _ispfs($$) { my ($ssl,$c)=@_; return ("$ssl-$c" =~ /$cfg{'regex'}->{'PFS'}/) ? "" : $c; } # return given cipher if it does not support forward secret connections (PFS) sub _isrc4($) { my $val=shift; return ($val =~ /$cfg{'regex'}->{'RC4'}/) ? $val . " " : ""; } # return given cipher if it is RC4 sub _istr02102 { # return given cipher if it is not TR-02102 compliant, empty string otherwise # this is valid vor TR-02102 2013 and 2016 my ($ssl, $cipher) = @_; return $cipher if ($cipher =~ /$cfg{'regex'}->{'EXPORT'}/); return $cipher if ($cipher =~ /$cfg{'regex'}->{'notTR-02102'}/); return $cipher if ($cipher !~ /$cfg{'regex'}->{'TR-02102'}/); return ""; } # _istr02102 sub _istr02102_strict { # return given cipher if it is not TR-02102 compliant, empty string otherwise my ($ssl, $cipher) = @_; my $val = _istr02102($ssl, $cipher); if ($val eq "") { # tsrict allows AES*-GCM only and no SHA-1 return $cipher if ($cipher !~ /$cfg{'regex'}->{'AES-GCM'}/); return $cipher if ($cipher =~ /$cfg{'regex'}->{'notTR-02102'}/); } return $val; } # _istr02102_strict sub _istr02102_lazy { # return given cipher if it is not TR-02102 compliant, empty string otherwise my ($ssl, $cipher) = @_; my $val = _istr02102($ssl, $cipher); return $val; } # _istr02102_lazy sub _istr03116_strict { # return given cipher if it is not TR-03116 compliant, empty string otherwise my ($ssl, $cipher) = @_; return $cipher if ($ssl ne "TLSv12"); return $cipher if ($cipher =~ /$cfg{'regex'}->{'EXPORT'}/); return $cipher if ($cipher =~ /$cfg{'regex'}->{'notTR-03116'}/); return $cipher if ($cipher !~ /$cfg{'regex'}->{'TR-03116+'}/); return ""; } # _istr03116_strict sub _istr03116_lazy { # return given cipher if it is not TR-03116 compliant, empty string otherwise my ($ssl, $cipher) = @_; return $cipher if ($ssl ne "TLSv12"); return $cipher if ($cipher =~ /$cfg{'regex'}->{'EXPORT'}/); return $cipher if ($cipher !~ /$cfg{'regex'}->{'TR-03116-'}/); return ""; } # _istr03116_lazy sub _isrfc7525 { # return given cipher if it is not RFC 7525 compliant, empty string otherwise my ($ssl, $cipher) = @_; my $bit = get_cipher_bits($cipher); return $cipher if ($cipher !~ /$cfg{'regex'}->{'RFC7525'}/); # /notRFC7525/; return $cipher if ($cipher =~ /NULL/); return $cipher if ($cipher =~ /$cfg{'regex'}->{'EXPORT'}/); return $cipher if ($cipher =~ /$cfg{'regex'}->{'RC4orARC4'}/); return "" if ($bit =~ m/^\s*$/); # avoid Perl warnings if $bit empty return $cipher if ($bit < 128); return ""; } # _isrfc7525 sub _isfips($$) { # return given cipher if it is not FIPS-140 compliant, empty string otherwise my ($ssl, $cipher) = @_; return $cipher if ($ssl ne "TLSv1"); return $cipher if ($cipher =~ /$cfg{'regex'}->{'notFIPS-140'}/); return $cipher if ($cipher !~ /$cfg{'regex'}->{'FIPS-140'}/); return ""; } # _isfips sub _isnsab($$) { # return given cipher if it is not NSA Suite B compliant, empty string otherwise # TODO: } # _isnsab sub _ispci($$) { # return given cipher if it is not PCI compliant, empty string otherwise # TODO: DH 1024+ is PCI compliant my ($ssl, $cipher) = @_; return $cipher if ($ssl eq "SSLv2"); # SSLv2 is not PCI compliant return $cipher if ($cipher =~ /$cfg{'regex'}->{'notPCI'}/); return ""; } # _ispci sub _readframe($) { # from https://github.com/noxxi/p5-scripts/blob/master/check-ssl-heartbleed.pl my $cl = shift; my $len = 5; my $buf = ''; vec( my $rin = '',fileno($cl),1 ) = 1; while ( length($buf)<$len ) { select( my $rout = $rin,undef,undef,$cfg{'timeout'} ) or return; sysread($cl,$buf,$len-length($buf),length($buf)) or return; $len = unpack("x3n",$buf) + 5 if length($buf) == 5; } (my $type, my $ver,$buf) = unpack("Cnn/a*",$buf); my @msg; if ( $type == 22 ) { while ( length($buf)>=4 ) { my $ht; ($ht,$len) = unpack("Ca3",substr($buf,0,4,'')); $len = unpack("N","\0$len"); push @msg,[ $ht,substr($buf,0,$len,'') ]; _v_print sprintf("...ssl received type=%d ver=0x%x ht=0x%x size=%d", $type,$ver,$ht,length($msg[-1][1])); } } else { @msg = $buf; _v_print sprintf("...ssl received type=%d ver=%x size=%d", $type,$ver,length($buf)); } return ($type,$ver,@msg); } # _readframe sub _isbleed($$) { #? return "heartbleed" if target supports TLS extension 15 (heartbeat), empty string otherwise # SEE Note:heartbleed my ($host, $port) = @_; my $heartbeats = 1; my $cl = undef; # TODO: =$Net::SSLinfo::socket; my $ret = ""; # empty string as required in %checks my ($type,$ver,$buf,@msg) = ("", "", "", ()); local $\ = undef; # take care, must not be \n !! # open our own connection and close it at end # TODO: does not work with socket from SSLinfo.pm # TODO: following unless{}else{} should be same as in _usesocket() unless (($cfg{'starttls'}) || (($cfg{'proxyhost'})&&($cfg{'proxyport'}))) { # no proxy and not starttls $cl = IO::Socket::INET->new(PeerAddr=>"$host:$port", Timeout=>$cfg{'timeout'}) or do { _warn("321: _isbleed: failed to connect: '$!'"); _trace("_isbleed: fatal exit in IO::Socket::INET->new\n"); return "failed to connect"; }; } else { # proxy or starttls _trace("_isbleed: using 'Net::SSLhello'"); $cl = Net::SSLhello::openTcpSSLconnection($host, $port); if ((not defined $cl) || ($@)) { # No SSL Connection local $@ = " Did not get a valid SSL-Socket from Function openTcpSSLconnection -> Fatal Exit of openTcpSSLconnection" unless ($@); _warn ("322: _isbleed (with openTcpSSLconnection): $@\n"); _trace("_isbleed: fatal exit in _doCheckSSLciphers\n"); return("failed to connect"); } # NO SSL upgrade needed -> NO else } # all following code stolen from Steffen Ullrich (08. April 2014): # https://github.com/noxxi/p5-scripts/blob/master/check-ssl-heartbleed.pl # code slightly adapted to our own variables: $host, $port, $cfg{'timeout'} # also die() replaced by _warn() # client hello with heartbeat extension # taken from http://s3.jspenguin.org/ssltest.py print $cl pack("H*",join('',qw( 16 03 02 00 dc 01 00 00 d8 03 02 53 43 5b 90 9d 9b 72 0b bc 0c bc 2b 92 a8 48 97 cf bd 39 04 cc 16 0a 85 03 90 9f 77 04 33 d4 de 00 00 66 c0 14 c0 0a c0 22 c0 21 00 39 00 38 00 88 00 87 c0 0f c0 05 00 35 00 84 c0 12 c0 08 c0 1c c0 1b 00 16 00 13 c0 0d c0 03 00 0a c0 13 c0 09 c0 1f c0 1e 00 33 00 32 00 9a 00 99 00 45 00 44 c0 0e c0 04 00 2f 00 96 00 41 c0 11 c0 07 c0 0c c0 02 00 05 00 04 00 15 00 12 00 09 00 14 00 11 00 08 00 06 00 03 00 ff 01 00 00 49 00 0b 00 04 03 00 01 02 00 0a 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 00 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f 00 10 00 11 00 23 00 00 00 0f 00 01 01 ))); while (1) { ($type,$ver,@msg) = _readframe($cl) or do { #ORIG die "no reply"; _warn("323: heartbleed: no reply: '$!'"); _hint("server does not respond, this does not indicate that it is not vulnerable!"); return "no reply"; }; last if $type == 22 and grep { $_->[0] == 0x0e } @msg; # server hello done } # heartbeat request with wrong size for(1..$heartbeats) { _v_print("...send heartbeat#$_"); print $cl pack("H*",join('',qw(18 03 02 00 03 01 40 00))); } if ( ($type,$ver,$buf) = _readframe($cl)) { if ( $type == 21 ) { _v_print("received alert (probably not vulnerable)"); } elsif ( $type != 24 ) { _v_print("unexpected reply type $type"); } elsif ( length($buf)>3 ) { $ret = "heartbleed"; _v_print("BAD! got ".length($buf)." bytes back instead of 3 (vulnerable)"); #show_data($buf) if $show; #if ( $show_regex ) { # while ( $buf =~m{($show_regex)}g ) { # print STDERR $1."\n"; # } #} # exit 1; } else { _v_print("GOOD proper heartbeat reply (not vulnerable)"); } } else { _v_print("no reply - probably not vulnerable"); } close($cl); _trace("_isbleed= $ret\n"); return $ret; } # _isbleed sub _isccs($$$) { #? return "ccs" if target is vulnerable to CCS Injection, empty string otherwise # parameter $ssl must be provided as binary value: 0x00, 0x01, 0x02, 0x03 or 0x04 # http://ccsinjection.lepidum.co.jp/ # inspired by http://blog.chris007.de/?p=238 my ($host, $port, $ssl) = @_; my $heartbeats = 1; my $cl = undef; # TODO: =$Net::SSLinfo::socket; my $ret = ""; # empty string as required in %checks my ($type,$ver,$buf,@msg) = ("", "", "", ()); undef $\; # take care, must not be \n !! # open our own connection and close it at end # TODO: does not work with socket from SSLinfo.pm $cl = IO::Socket::INET->new(PeerAddr => "$host:$port", Timeout => $cfg{'timeout'}) or do { _warn("331: _isccs: failed to connect: '$!'"); return "failed to connect"; }; ################# # $ccs = _isccs($host, $port, $ssl); # 'openssl_version_map' => { # map our internal option to openssl version (hex value) # 'SSLv2'=> 0x0002, 'SSLv3'=> 0x0300, 'TLSv1'=> 0x0301, 'TLSv11'=> 0x0302, 'TLSv12'=> 0x0303, 'TLSv13'=> 0x0304, } ################# #\x14\x03\tls_version\x00\x01\x01 sed 's/tls_version/'"$2"'/g' #\x01 # ist TLSv1 # 14 03 01 00 01 01 # client hello with CCS # 00..00 # random 32 byte (i.e. Unix time) # 00 # Session ID length # 00 68 # Cipher suites length print $cl pack("H*",join('',qw( 53 9c b2 cb 4b 42 f9 2d 0b e5 9c 21 f5 a3 89 ca 7a d9 b4 ab 3f d3 22 21 5e c4 65 0d 1e ce ed c2 00 00 68 c0 13 c0 12 c0 11 c0 10 c0 0f c0 0e c0 0d c0 0c c0 0b c0 0a c0 09 c0 08 c0 07 c0 06 c0 05 c0 04 c0 03 c0 02 c0 01 00 39 00 38 00 37 00 36 00 35 00 34 00 33 00 32 00 31 00 30 00 2f 00 16 00 15 00 14 00 13 00 12 00 11 00 10 00 0f 00 0e 00 0d 00 0c 00 0b 00 0a 00 09 00 08 00 07 00 06 00 05 00 04 00 03 00 02 00 01 01 00 ))); while (1) { ($type,$ver,@msg) = _readframe($cl) or do { _warn("332: _isccs: no reply: '$!'"); return "no reply"; }; last if $type == 22 and grep { $_->[0] == 0x0e } @msg; # server hello done } if ( ($type,$ver,$buf) = _readframe($cl)) { if ( $type == 21 ) { _v_print("received alert (probably not vulnerable)"); } elsif ( $type != 24 ) { _v_print("unexpected reply type $type"); } elsif ( length($buf)>3 ) { $ret = "heartbleed"; _v_print("BAD! got ".length($buf)." bytes back instead of 3 (vulnerable)"); #show_data($buf) if $show; #if ( $show_regex ) { # while ( $buf =~m{($show_regex)}g ) { # print STDERR $1."\n"; # } #} # exit 1; } else { _v_print("GOOD proper heartbeat reply (not vulnerable)"); } } else { _v_print("no reply - probably not vulnerable"); } close($cl); return $ret; } # _isccs sub _isbeastskipped($$) { #? returns protocol names if they are vulnerable to BEAST but the check has been skipped, #? returns empty string otherwise. my ($host, $port) = @_; my @ret; foreach my $ssl (qw(SSLv2 SSLv3 TLSv1)) { # If $cfg{$ssl}=0, the check may be disabled, i.e. with --no-sslv3 . if ($cfg{$ssl} == 0) { push(@ret, _get_text('disabled', "--no-$ssl")); } } #_dbx ": TLS " . join(" ", @ret); return join(" ", @ret); } # _isbeastskipped sub _istls12only($$) { # NOTE: not yet used #? returns empty string if TLS 1.2 is the only protocol used, #? returns all used protocols otherwise my ($host, $port) = @_; my @ret; foreach my $ssl (qw(SSLv2 SSLv3 TLSv1 TLSv11)) { # If $cfg{$ssl}=0, the check may be disabled, i.e. with --no-sslv3 . # If the protocol is supported by the target, at least one cipher # must be accpted. So the amount of ciphers must be > 0. if ($prot{$ssl}->{'cnt'} > 0) { push(@ret, $ssl); } if ($cfg{$ssl} == 0) { # this condition is never true if ciphers have been detected push(@ret, _get_text('disabled', "--no-$ssl")); } } #_dbx ": TLS " . join(" ", @ret); return join(" ", @ret); } # _istls12only sub _is_ssl_error($$$) { # returns 1 if probaly a SSL connection error occoured; 0 otherwise # increments counters in $cfg{'done'} my ($anf, $end, $txt) = @_; return 0 if (($end - $anf) <= $cfg{'sslerror'}->{'timeout'}); $cfg{'done'}->{'ssl_errors'}++; # total counter $cfg{'done'}->{'ssl_failed'}++; # local counter return 0 if ($cfg{'ssl_error'} <= 0); # no action required if ($cfg{'done'}->{'ssl_errors'} > $cfg{'sslerror'}->{'total'}) { _warn("301: $txt after $cfg{'sslerror'}->{'total'} total errors"); _hint("use --no-ssl-error or --ssl-error-max= to continue connecting"); return 1; } if ($cfg{'done'}->{'ssl_failed'} > $cfg{'sslerror'}->{'max'}) { _warn("302: $txt after $cfg{'sslerror'}->{'max'} max errors"); _hint("use --no-ssl-error or --ssl-error-max= to continue connecting"); return 1; } return 0; } # _is_ssl_error sub _checkwildcard($$) { # compute usage of wildcard in CN and subjectAltname my ($host, $port) = @_; my ($cn_host, $rex); $cn_host = $data{'cn'}->{val}($host); $checks{'wildcard'}->{val} = "<>$cn_host" if ($cn_host =~ m/[*]/); foreach my $value (split(" ", $data{'altname'}->{val}($host))) { $value =~ s/.*://; # strip prefix, like DNS: if ($value =~ m/\*/) { # * can be anywhere, like a.b*.some.tld # NOTE: lazy check, because *.b*.some.tld is invalid, but works here $checks{'wildcard'}->{val} .= " " . $value; ($rex = $value) =~ s/[*]/[^.]*/;# make RegEx # RegEx: missing dots is ok, like a.b.some.tld # RegEx: leading dot is ok, like .some.tld # then $host must match completely ^$rex$ $checks{'wildhost'}->{val} = $value if ($host =~ m/^$rex$/); $checks{'cnt_wildcard'}->{val}++; } $checks{'cnt_altname'}->{val}++; $checks{'len_altname'}->{val} = length($value) + 1; # count number of characters + type (int) } # checking for SNI does not work here 'cause it destroys %data return; } # _checkwildcard sub _can_connect { # return 1 if host:port can be connected; 0 otherwise my ($host, $port, $sni, $timeout, $ssl) = @_; local $? = 0; local $! = undef; my $socket; if ($ssl == 1) { # need different method for connecting with SSL if ($cfg{'trace'} > 2) { $IO::Socket::SSL::debug3 = 1; my $keep_perl_quit = $IO::Socket::SSL::debug3; } # simple and fast connect: full cipher list, no handshake, # do not verify the certificate and/or CRL, OCSP, which # may result in a connection fail # SNI is not necessary, as we just want to know if the server responds # however, SNI may be necessary in future ... # Note that $sni may be undef $socket = IO::Socket::SSL->new( PeerAddr => $host, PeerPort => $port, Proto => "tcp", Timeout => $timeout, #SSL_hostname => $sni, SSL_version => "SSLv23", SSL_cipher_list => "ALL:NULL:eNULL:aNULL:LOW:EXP", SSL_verify_mode => 0x0, # SSL_VERIFY_NONE => Net::SSLeay::VERIFY_NONE(); # 0 SSL_check_crl => 0, # do not check CRL SSL_ocsp_mode => 0, # TODO: is 0 the roccect value to disable this check? SSL_startHandshake => 0, ) or do { _v_print("_can_connect: IO::Socket::SSL->new(): $! #" . IO::Socket::SSL::errstr()); }; } else { $socket = IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port, Proto => "tcp", Timeout => $timeout, ) or do { _v_print("_can_connect: IO::Socket::INET->new(): $!"); }; # IO::Socket::INET::errstr(); } if (defined $socket) { close($socket); return 1; } _warn("324: failed to connect target $host:$port : '$!'"); return 0; } # _can_connect sub _usesocket($$$$) { # return protocol and cipher accepted by SSL connection # should return the target's prefered cipher if none are given in $ciphers # NOTE: this function is used to check for supported ciphers only, hence # no need for sophisticated options in new() and no certificate checks # $ciphers must be colon (:) separated list my ($ssl, $host, $port, $ciphers) = @_; my $cipher = ""; # to be returned my $sni = ($cfg{'usesni'} < 1) ? "" : $host; my $npns = ($cfg{'usenpn'} < 1) ? [] : $cfg{'cipher_npns'}; my $alpns = ($cfg{'usealpn'} < 1) ? [] : $cfg{'cipher_alpns'}; # --no-alpn or --no-npn is same as --cipher-alpn=, or --cipher-npn=, my $version = ""; # version returned by IO::Socket::SSL-new my $sslsocket = undef; # TODO: dirty hack (undef) to avoid Perl error like: # Use of uninitialized value in subroutine entry at /usr/share/perl5/IO/Socket/SSL.pm line 562. # which may occour if Net::SSLeay was not build properly with support for # these protocol versions. We only check for SSLv2 and SSLv3 as the *TLSx # doesn't produce such warnings. Sigh. _trace1("_usesocket($ssl, $host, $port, $ciphers){ sni: $sni"); # _warn_nosni(); # not here, because too noisy # following ugly if conditions: because one or both functions may be there if (($ssl eq "SSLv2") && (not defined &Net::SSLeay::CTX_v2_new)) { _warn("303: SSL version '$ssl': not supported by Net::SSLeay"); return ""; } if (($ssl eq "SSLv3") && (not defined &Net::SSLeay::CTX_v3_new)) { _warn("304: SSL version '$ssl': not supported by Net::SSLeay"); return ""; } # FIXME: use Net::SSLeay instead of IO::Socket::SSL if (eval { # FIXME: use something better than eval() # TODO: eval necessary to avoid Perl error like: # invalid SSL_version specified at /usr/share/perl5/IO/Socket/SSL.pm line 492. # TODO: SSL_hostname does not support IPs (at least up to 1.88); check done in IO::Socket::SSL #dbx# $IO::Socket::SSL::DEBUG = 1; unless (($cfg{'starttls'}) || (($cfg{'proxyhost'})&&($cfg{'proxyport'}))) { # no proxy and not starttls _trace1("_usesocket: using 'IO::Socket::SSL' with '$ssl'"); local $? = 0; local $! = undef; $sslsocket = IO::Socket::SSL->new( PeerAddr => $host, PeerPort => $port, Proto => "tcp", Timeout => $cfg{'timeout'}, SSL_hostname => $sni, # for SNI SSL_verify_mode => 0x0, # SSL_VERIFY_NONE => Net::SSLeay::VERIFY_NONE(); # 0 SSL_ca_file => undef, # see man IO::Socket::SSL .. SSL_ca_path => undef, # .. newer versions are smarter and accept '' SSL_check_crl => 0, # do not check CRL SSL_version => $ssl, # default is SSLv23 (for empty $ssl) SSL_cipher_list => $ciphers, SSL_ecdh_curve => "prime256v1", # OID or NID; ecdh_x448, default is prime256v1, ecdh_x25519 #SSL_ecdh_curve => $cfg{'ciphercurves'},# OID or NID; ecdh_x448, default is prime256v1, #SSL_ecdh_curve => [qw(sect163k1 x25519)], #TODO: SSL_ecdh_curve => undef, # TODO: cannot be selected by options SSL_alpn_protocols => $alpns, SSL_npn_protocols => $npns, #TODO: SSL_honor_cipher_order => 1, # usefull for SSLv2 only #SSL_check_crl => 1, # if we want to use a client certificate #SSL_cert_file => "path" # file for client certificate ); #_trace1("_usesocket: IO::Socket::SSL->new: $? : $! :"); } else { # proxy or starttls _trace1("_usesocket: using 'Net::SSLhello'"); local $? = 0; local $! = undef; $sslsocket = Net::SSLhello::openTcpSSLconnection($host, $port); if ((not defined ($sslsocket)) || ($@)) { # No SSL Connection local $@ = " Did not get a valid SSL-Socket from Function openTcpSSLconnection -> Fatal Exit" unless ($@); _warn("305: _usesocket: openTcpSSLconnection() failed: $@\n"); return (""); } else { # SSL upgrade _trace1("_usesocket: start_SSL ($host, $port, $ciphers)\t= $cipher"); IO::Socket::SSL->start_SSL($sslsocket, Timeout => $cfg{'timeout'}, SSL_hostname => $sni, # for SNI SSL_verify_mode => 0x0, # SSL_VERIFY_NONE => Net::SSLeay::VERIFY_NONE(); # 0 SSL_ca_file => undef, # see man IO::Socket::SSL .. SSL_ca_path => undef, # .. newer versions are smarter and accept '' SSL_check_crl => 0, # do not check CRL SSL_version => $ssl, # default is SSLv23 SSL_cipher_list => $ciphers, SSL_ecdh_curve => "prime256v1", # default is prime256v1, SSL_alpn_protocols => $alpns, SSL_npn_protocols => $npns, ) or do { _trace1("_usesocket: ssl handshake failed: $!"); return ""; }; } } #dbx# _dbx("_usesocket: $? : $! : $IO::Socket::SSL::SSL_ERROR :"); # more info in rare cases }) { # eval succeded if ($sslsocket) { # SEE Note:Selected Protocol $version = $sslsocket->get_sslversion() if ($IO::Socket::SSL::VERSION > 1.964); $cipher = $sslsocket->get_cipher(); $sslsocket->close(SSL_ctx_free => 1); _trace1("_usesocket: SSL version (for $ssl $ciphers): $version"); } } else { # eval failed: connect failed # we may get hints in $! like: # * empty if cipher was not accepted # * contains an error string if the connection was rejected or there # was an error in IO::Socket::SSL (i.e. timeout) _trace1("_usesocket: connection failed (for $ssl $ciphers): $!"); } _trace1("_usesocket()\t= $cipher }"); return $version, $cipher; } # _usesocket sub _useopenssl($$$$) { # return cipher accepted by SSL connection # should return the target's prefered cipher if none are given in $ciphers # $ciphers must be colon (:) separated list # adds all configured options, like -alpn -curves -servername etc. with # their proper values my ($ssl, $host, $port, $ciphers) = @_; my $msg = $cfg{'openssl_msg'}; my $sni = ($cfg{'usesni'} < 1) ? "" : "-servername $host"; $ciphers = ($ciphers eq "") ? "" : "-cipher $ciphers"; my $curves = "-curves " . join(":", $cfg{'ciphercurves'}); # TODO: add to command below _trace1("_useopenssl($ssl, $host, $port, $ciphers)"); # no { in comment here $ssl = ($cfg{'openssl_option_map'}->{$ssl} || ''); # set empty if no protocol given my $data = Net::SSLinfo::do_openssl("s_client $ssl $sni $msg $ciphers ", $host, $port, ''); # TODO: hier -alpn $protos_alpn und -nextprotoneg $protos_npn übergeben # TODO: dann entsprechenden Code in Net::SSLinfo::do_openssl() entfernen # we may get for success: # New, TLSv1/SSLv3, Cipher is DES-CBC3-SHA # also possible would be Cipher line from: # SSL-Session: # Protocol : TLSv1.2 # Cipher : DES-CBC3-SHA _trace2("_useopenssl: data #{ $data }"); return "", "", "" if ($data =~ m#New,.*?Cipher is .?NONE#); my $version = $data;# returned version $version =~ s#^.*[\r\n]+ +Protocol\s*:\s*([^\r\n]*).*#$1#s; my $cipher = $data; if ($cipher =~ m#New, [A-Za-z0-9/.,-]+ Cipher is#) { $cipher =~ s#^.*[\r\n]+New,\s*##s; $cipher =~ s#[A-Za-z0-9/.,-]+ Cipher is\s*([^\r\n]*).*#$1#s; my $dh = get_dh_paramter($cipher, $data); _trace1("_useopenssl()\t= $cipher $dh }"); return $version, $cipher, $dh; } # else check for errors ... # grrrr, it's a pain that openssl changes error messages for each version # we may get any of following errors: # TIME:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:.\ssl\s23_lib.c:177: # New, (NONE), Cipher is (NONE) # connect:errno=11004 # TIME:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:602: # TIME:error:140740B5:SSL routines:SSL23_CLIENT_HELLO:no ciphers available:s23_clnt.c:367: # if SSL version not supported (by openssl): # 29153:error:140A90C4:SSL routines:SSL_CTX_new:null ssl method passed:ssl_lib.c:1453: # openssl 1.0.1e : # # unknown messages: 139693193549472:error:1407F0E5:SSL routines:SSL2_WRITE:ssl handshake failure:s2_pkt.c:429: # error setting cipher list # 139912973481632:error:1410D0B9:SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl_lib.c:1314: return "", "", "" if ($data =~ m#SSL routines.*(?:handshake failure|null ssl method passed|no ciphers? (?:available|match))#); ## no critic qw(RegularExpressions::ProhibitComplexRegexes) if ($data =~ m#^\s*$#) { _warn("311: SSL version '$ssl': empty result from openssl"); } else { _warn("312: SSL version '$ssl': unknown result from openssl"); _warn("312: result from openssl: '$data'") if _is_v_trace(); } _trace2("_useopenssl: #{ $data }"); if ($cfg{'verbose'} < 1) { _hint("use options like: --v --trace"); # print always } else { _v_print("_useopenssl: Net::SSLinfo::do_openssl() #{\n$data\n#}"); } return "", "", ""; } # _useopenssl sub _get_ciphers_range { #? retrun array of cipher-suite hex values for given range # uses $cfg{'cipherranges'}->{$range} my $ssl = shift; my $range = shift; $range = 'SSLv2' if ($ssl eq 'SSLv2'); # but SSLv2 needs its own list my @all; _trace("_get_ciphers_range($ssl, $range"); # NOTE: following eval must not use the block form because the value # needs to be evaluated foreach my $c (eval($cfg{'cipherranges'}->{$range}) ) { ## no critic qw(BuiltinFunctions::ProhibitStringyEval) push(@all, sprintf("0x%08X",$c)); } _trace2("_get_ciphers_range: @all"); return @all; } # _get_ciphers_range sub _get_ciphers_list { #? return space-separated list of cipher suites according command line options _trace("_get_ciphers_list(){"); my @ciphers = (); my $range = $cfg{'cipherrange'}; # default is 'rfc' _trace("cipherpattern= $cfg{'cipherpattern'}, cipherrange= $range"); my $pattern = $cfg{'cipherpattern'};# default pattern (colon-separated) $pattern = join(":", @{$cfg{'cipher'}}) if (scalar(@{$cfg{'cipher'}}) > 0); # @{$cfg{'cipher'}}) > 0 if option --cipher=* was used # can be specified like: --cipher=NULL:RC4 or --cipher=NULL --cipher=RC4 _trace(" cipher pattern= $pattern"); if ($range eq "rfc") { # default cipher range is 'rfc' (see o-saft-lib.pm), then get list of # ciphers from Net::SSLinfo if ($cmd{'extciphers'} == 1) { @ciphers = Net::SSLinfo::cipher_openssl($pattern); } else { @ciphers = Net::SSLinfo::cipher_list( $pattern); } } else { # cipher range specified with --cipher-range=* option # ranges are defined as numbers, need to get the cipher suite name _v_print("cipher range: $range"); foreach my $c (eval($cfg{'cipherranges'}->{$range}) ) { ## no critic qw(BuiltinFunctions::ProhibitStringyEval) my $key = sprintf("0x%08X",$c); _trace($key, get_cipher_suitename($key)); push(@ciphers, get_cipher_suitename($key)); } } _trace(" got ciphers: @ciphers"); if (@ciphers <= 0) { # empty list _warn("063: given pattern '$pattern' did not return cipher list"); _y_CMD(" using private cipher list ..."); @ciphers = keys %ciphers; } if (@ciphers <= 0) { print "Errors: " . Net::SSLinfo::errors(); die STR_ERROR, "015: no ciphers found; may happen with openssl pre 1.0.0 according given pattern"; } @ciphers = grep{!/^\s*$/} @ciphers; # remove empty names _trace("_get_ciphers_list\t= @ciphers }"); # TODO: trace a bit late return @ciphers; } # _get_ciphers_list sub _get_default($$$$) { # return list of offered (default) cipher from target # mode defines how to retrieve the prefered cipher # strong: pass cipher list sorted with strongest first # weak: pass cipher list sorted with weakest first # default: pass no cipher list which then uses system default # To get the target's prefered cipher, all known ciphers are send so that # the target should select the most secure one. # Both, openssl and sockets (IO::Socket::SSL), use the underlaying libssl # which works with the compiled in ciphers only. Hence all known ciphers # (by libssl) are passed: @{$cfg{'ciphers'}}, we cannot pass all ciphers # like: keys %ciphers . +cipherraw command must be used, if other ciphers # than the local available should be checked. my ($ssl, $host, $port, $mode) = @_; _trace("_get_default($ssl, $host, $port, $mode){"); $cfg{'done'}->{'default_get'}++; my $dh = ""; # returned DH parameters (not yet used) my $version = ""; # returned protocol version my $cipher = ""; my @list = (); # mode == default @list = sort_cipher_names(@{$cfg{'ciphers'}}) ;#if ($mode eq 'strong'); @list = reverse sort_cipher_names(@{$cfg{'ciphers'}}) if ($mode eq 'weak'); my $cipher_list = join(":", @list); if (0 == $cmd{'extciphers'}) { ($version, $cipher) = _usesocket( $ssl, $host, $port, $cipher_list); } else { # force openssl ($version, $cipher, $dh)= _useopenssl($ssl, $host, $port, $cipher_list); # NOTE: $ssl will be converted to corresponding option for openssl, # for example: DTLSv1 becomes -dtlsv1 # Unfortunately openssl (or Net::SSLinfo) returns a cipher even if # the protocoll is not supported. Reason (aka bug) yet unknown. # Hence the caller should ensure that openssl supports $ssl . } $cipher = "" if not defined $cipher; if ($cipher =~ m#^\s*$#) { my $txt = "SSL version '$ssl': cannot get prefered cipher; ignored"; # SSLv2 is special, see _usesocket "dirty hack"; don't print _v_print($txt) if ($ssl !~ m/SSLv[2]/); } else { _v2print("prefered cipher: $ssl:\t$cipher"); } _trace("_get_default()\t= $cipher }"); # TODO: trace a bit late return $cipher; } # _get_default sub _get_data0 { #? get %data for connection without SNI # this function currently only returns data for: cn_nosni, session_ticket my ($host, $port) = @_; _y_CMD("test without SNI (disable with --no-sni) ..."); # check if SNI supported, also copy some data to %data0 # to do this, we need a clean SSL connection with SNI disabled # see SSL_CTRL_SET_TLSEXT_HOSTNAME in NET::SSLinfo # finally we close the connection to be clean for all other tests _trace(" cn_nosni: {"); _yeast_TIME("no SNI{"); $Net::SSLinfo::use_SNI = 0; # no need to save current value if (defined Net::SSLinfo::do_ssl_open( $host, $port, (join(" ", @{$cfg{'version'}})), join(" ", @{$cfg{'ciphers'}})) ) { _y_CMD(" open with no SNI."); _trace("cn_nosni: method: $Net::SSLinfo::method"); $data{'cn_nosni'}->{val} = $data{'cn'}->{val}($host, $port); $data0{'session_ticket'}->{val} = $data{'session_ticket'}->{val}($host, $port); # TODO: following needs to be improved, because there are multipe openssl # calls which may produce unexpected results (10/2015) { foreach my $key (keys %data) { # copy to %data0 next if ($key =~ m/$cfg{'regex'}->{'commands-INT'}/i); $data0{$key}->{val} = $data{$key}->{val}($host, $port); } # } } else { _warn("204: Can't make a connection to $host:$port without SNI; no initial data (compare with and without SNI not possible)"); } _yeast_TIME("no SNI}"); # now close connection, which also resets Net::SSLinfo's internal data # structure, Net::SSLinfo::do_ssl_close() is clever enough to work if # the connection failed and does nothing (except resetting data) if (0 < ($cfg{'verbose'} + $cfg{'trace'})) { _warn("206: $_") foreach Net::SSLinfo::errors(); } Net::SSLinfo::do_ssl_close($host, $port); $Net::SSLinfo::use_SNI = $cfg{'usesni'}; _trace(" cn_nosni: $data{'cn_nosni'}->{val} }"); return; } # _get_data0 sub ciphers_scan_prot { #? test target if given ciphers are accepted, returns array of accepted ciphers #? scans for ciphers with given protocol only my ($ssl, $host, $port, $arr) = @_; my @ciphers = @{$arr}; # ciphers to be checked my $version = ""; # returned protocol version my $dh = ""; # returned DH parameters (not yet used) _trace("ciphers_scan_prot($ssl, $host, $port, @ciphers){"); my @res = (); # return accepted ciphers $cfg{'done'}->{'ssl_failed'} = 0; # SEE Note:--ssl-error _v_print("connect delay: $cfg{'connect_delay'} second(s)") if ($cfg{'connect_delay'} > 0); my $cnt = 0; foreach my $c (@ciphers) { next if ($c =~ m/^\s*$/); my $anf = time(); my $supported = ""; $cnt++; my $txt = "$ssl: ($cnt of " . scalar(@ciphers) . " ciphers checked) abort connection attempts"; printf("# cipher %3d/%d %s%s\r", $cnt, scalar @ciphers, $c, " "x42) if ($cfg{'verbose'} > 0); # no \n at end of line, hence all messages print to same line # wipe previous trailing text with " "x42 # cannot use _v_print() because it prints with \n if (0 == $cmd{'extciphers'}) { if (0 >= $cfg{'cipher_md5'}) { # Net::SSLeay:SSL supports *MD5 for SSLv2 only # detailled description see OPTION --no-cipher-md5 #_hint("--no-cipher-md5 can be used to disable checks with MD5 ciphers"); _v4print("check cipher (MD5): $ssl:$c\n"); next if (($ssl ne "SSLv2") && ($c =~ m/MD5/)); } ($version, $supported) = _usesocket( $ssl, $host, $port, $c); } else { # force openssl ($version, $supported, $dh) = _useopenssl($ssl, $host, $port, $c); } $supported = "" if not defined $supported; sleep($cfg{'connect_delay'}); last if (_is_ssl_error($anf, time(), $txt) > 0); if (($c !~ /(?:HIGH|ALL)/) and ($supported ne "")) { # given generic names is ok if (($c !~ $supported) and ($ssl ne "SSLv2")) { # mismatch: name asked for and name returned by server # this may indicate wrong cipher name in our configuration # or the server returned no data or closed TCP connection # or connection timed out, see _is_ssl_error() # no complain for SSLv2, which may return an empty string _warn("411: checked $ssl cipher '$c' does not match returned cipher '$supported'"); } } push(@res, "$version:$supported") if ($supported ne ""); my $yesno = ($supported eq "") ? "no" : "yes"; _v2print("check cipher: $ssl:$c\t$yesno"); # TODO: should close dangling sockets here } # foreach @ciphers _v_print("connection errors: $cfg{'done'}->{'ssl_errors'} "); # spaces to overwrite remaining cipher suite names _trace("ciphers_scan_prot()\t= " . $#res . " @res }"); return @res; } # ciphers_scan_prot sub ciphers_scan { #? scan target for ciphers for all protocols # writes to @cipher_results my ($host, $port) = @_; # FIXME: 6/2015 es kommt eine Fehlermeldung wenn openssl 1.0.2 verwendet wird: # Use of uninitialized value in subroutine entry at /usr/share/perl5/IO/Socket/SSL.pm line 562. # hat mit den Ciphern aus @{$cfg{'ciphers'}} zu tun # IDEA-CBC-MD5 RC2-CBC-MD5 DES-CBC3-MD5 RC4-64-MD5 DES-CBC-MD5 : # Ursache in _usesocket() das benutzt IO::Socket::SSL->new() my $cnt = scalar(@{$cfg{'ciphers'}}); foreach my $ssl (@{$cfg{'version'}}) { my $__openssl = ($cmd{'extciphers'} == 0) ? 'socket' : 'openssl'; my $usesni = $cfg{'usesni'}; if (($cfg{'verbose'} + $cfg{'trace'} + $cfg{'traceCMD'}) > 0) { # optimize output: instead using 3 lines with _y_CMD(), _trace() and _v_print() my $_me = ""; $_me = $cfg{'mename'} . " CMD:" if ($cfg{'traceCMD'} > 0); # TODO: _yTIME() missing $_me = $cfg{'mename'} . "::" if ($cfg{'trace'} > 0); print("#$_me checking $cnt ciphers for $ssl ... ($__openssl)"); } if ($ssl =~ m/^SSLv[23]/) { # SSLv2 has no SNI; SSLv3 has originally no SNI if (_is_do('cipher') or $cfg{'verbose'} > 0) { _warn_nosni("410:", $ssl, $cfg{'usesni'}); # ciphers are collected for various checks, this would result # in above warning, even then if SSLv3 is not needed for the # requested check; to avoid these noicy warnings, it is only # printend for +cipher command or with --v option } $cfg{'usesni'} = 0; # do not use SNI for this $ssl } my $__verbose = $cfg{'verbose'}; # $cfg{'v_cipher'} should only print cipher checks verbosely, # ciphers_scan_prot() uses $cfg{'verbose'}, hence wee need to save # the current value and reset after calling ciphers_scan_prot() $cfg{'verbose'} = 2 if ($cfg{'v_cipher'} > 0); my @supported = ciphers_scan_prot($ssl, $host, $port, \@{$cfg{'ciphers'}}); $cfg{'verbose'} = $__verbose if ($__verbose != 2); # remove protocol: in each item #foreach my $i (keys @supported) { $supported[$i] =~ s/^[^:]*://; } # for Perl > 5.12 for my $i (0..$#supported) { $supported[$i] =~ s/^[^:]*://; } # for Perl < 5.12 and Perl::Critic # map({s/^[^:]*://} @supported); # is the perlish way (all Perl 5.x) # but discarted by Perl::Critic, hence the less readable foreach foreach my $c (@{$cfg{'ciphers'}}) { # might be done more perlish ;-) push(@cipher_results, [$ssl, $c, ((grep{/^$c$/} @supported)>0) ? "yes" : "no"]); } $cfg{'usesni'} = $usesni; } return; } # ciphers_scan sub check_certchars($$) { #? check for invalid characters in certificate my ($host, $port) = @_; _y_CMD("check_certchars() ". $cfg{'done'}->{'check_certchars'}); $cfg{'done'}->{'check_certchars'}++; return if ($cfg{'done'}->{'check_certchars'} > 1); my $value; my $txt; # check vor invald charaters foreach my $label (@{$cfg{'need-checkchr'}}, qw(email aux)) { $value = $data{$label}->{val}($host); if ($value ne "") { $checks{'nonprint'}->{val} .= " $label" if ($value =~ m/$cfg{'regex'}->{'nonprint'}/); $checks{'crnlnull'}->{val} .= " $label" if ($value =~ m/$cfg{'regex'}->{'crnlnull'}/); } } # valid characters (probably only relevant for DV and EV) #_dbx "EV: keys: " . join(" ", @{$cfg{'need-checkchr'}} . "extensions"; #_dbx "EV: regex:" . $cfg{'regex'}->{'notEV-chars'}; # not checked explicitely: CN, O, U (should already be part of others, like subject) foreach my $label (@{$cfg{'need-checkchr'}}, qw(extensions)) { $value = $data{$label}->{val}($host); $value =~ s#[\r\n]##g; # CR and NL are most likely added by openssl if ($value =~ m/$cfg{'regex'}->{'notEV-chars'}/) { $txt = _get_text('cert_chars', $label); $checks{'ev_chars'}->{val} .= $txt; $checks{'ev+'}->{val} .= $txt; $checks{'ev-'}->{val} .= $txt; $checks{'dv'}->{val} .= $txt; if ($cfg{'verbose'} > 0) { $value =~ s#($cfg{'regex'}->{'EV-chars'}+)##msg; _v2print("EV: wrong characters in $label: $value"); } } } return; } # check_certchars sub check_dh($$) { #? check if target is vulnerable to Logjam attack; uses @cipher_results my ($host, $port) = @_; _y_CMD("check_dh() ". $cfg{'done'}->{'check_dh'}); $cfg{'done'}->{'check_dh'}++; return if ($cfg{'done'}->{'check_dh'} > 1); # Logjam check is a bit ugly: DH Parameter may be missing # TODO: implement own check for DH parameters instead relying on openssl my $txt = $data{'dh_parameter'}->{val}($host); if ($txt eq "") { $txt = "<>"; checkciphers($host, $port, @cipher_results); # need EXPORT ciphers fot logjam # TODO: calling checkciphers() is bad, it may even not contain ciphers my $exp = $checks{'logjam'}->{val}; $checks{'logjam'}->{val} .= $txt; $checks{'logjam'}->{val} .= "; but has WEAK ciphers: $exp" if ($exp ne ""); $checks{'dh_512'}->{val} = $txt; $checks{'dh_2048'}->{val} = $txt; $checks{'ecdh_256'}->{val} = $txt; $checks{'ecdh_512'}->{val} = $txt; return; # no more checks possible } my $dh = $txt; $dh =~ s/.*?[^\d]*(\d+) *bits.*/$1/i; # just get number # DH, 512 bits # DH, 1024 bits # DH, 2048 bits # ECDH, P-256, 128 bits # ECDH, P-256, 256 bits # ECDH, P-384, 384 bits # TODO: ECDH should also have 256 bits or more if ($dh =~ m/^\d+$/) { # a number, check size if ($txt !~ m/ECDH/) { $checks{'dh_512'}->{val} = $txt if ($dh < 512); $checks{'dh_2048'}->{val} = $txt if ($dh < 2048); } else { # ECDH is different $checks{'ecdh_256'}->{val} = $txt if ($dh < 256); $checks{'ecdh_512'}->{val} = $txt if ($dh < 512); } # lazy check: logjam if bits < 256 only my $val = $checks{'dh_512'}->{val} . $checks{'dh_2048'}->{val} . $checks{'ecdh_256'}->{val}; $checks{'logjam'}->{val} = $val if ($val ne ""); } else { # not a number, probably suspicious $checks{'logjam'}->{val}= $txt; } return; } # check_dh sub check_url($$) { #? request given URL and check if it is a valid CRL or OCSP site #? returns result of check; empty string if anything OK my ($uri, $type) = @_; # type is 'ext_crl' or 'ocsp_uri' _y_CMD("check_url() ". $cfg{'done'}->{'check_url'}); $cfg{'done'}->{'check_url'}++; _trace("check_url($uri, $type)"); return " " if ($uri =~ m#^\s*$#); # no URI, no more checks # Net::SSLeay::get_http() is used as we already include Net::SSLeay # NOTE: must be rewritten if Net::SSLeay is removed # Note: all following examples show only the headers checked herein # for CRL we expect something like: # example: http://crl.entrust.net/level1k.crl # HTTP/1.1 200 OK # Accept-Ranges: bytes # Content-Type: application/x-pkcs7-crl # Content-Length: 1101367 # # example: http://pki.google.com/GIAG2.crl # HTTP/1.1 200 OK # Accept-Ranges: none # Transfer-Encoding: chunked # Content-Type: application/pkix-crl # # bad example: http://pki.google.com # HTTP/1.1 200 OK # Accept-Ranges: none # Transfer-Encoding: chunked # Content-Type: text/html # # example: http://crl.startssl.com/crt2-crl.crl # HTTP/1.1 200 OK # Accept-Ranges: bytes # Content-Type: application/pkix-crl # Content-Length: 58411 # # example: http://mscrl.microsoft.com/pki/mscorp/crl/msitwww2.crl # HTTP/1.1 200 OK # Content-Type: application/pkix-crl # Content-Length: 179039 # Accept-Ranges: bytes # # for OCSP we expect something like: # example: http://sr.symcd.com # HTTP/1.1 200 OK # Content-Type: application/ocsp-response # Content-Length: 5 # content-transfer-encoding: binary # # bad example: http://clients1.google.com/ocsp # HTTP/1.1 404 Not Found # Date: Sun, 17 Apr 2016 10:24:46 GMT # Content-Type: text/html; charset=UTF-8 # Content-Length: 1565 # # bad example: http://ocsp.entrust.net # HTTP/1.1 200 OK # Content-Type: text/html # Content-Length: 68 # # meta HTTP-EQUIV="REFRESH" content="0; url=http://www.entrust.net"> # # example: http://ocsp.msocsp.com # HTTP/1.1 200 OK # Content-Type: application/ocsp-response # Content-Length: 5 # # example: http://sr.symcb.com/sr.crl # HTTP/1.1 200 OK # Content-Type: application/pkix-crl # Transfer-Encoding: chunked # Connection: Transfer-Encoding # # for AIA we expect something like: # example: http://www.microsoft.com/pki/mscorp/msitwww2.crt # HTTP/1.1 200 OK # Accept-Ranges: bytes # Content-Type: application/x-x509-ca-cert # Content-Length: 1418 # my ($accept, $binary, $ctype, $chunk, $length); my $txt = "<>"; # this is a programming error my $src = 'Net::SSLeay::get_http()'; # got an URI, extract host, port and URL $uri =~ m#^\s*(?:(?:http|ldap)s?:)?//([^/]+)(/.*)?$#; # NOTE: it's ok here my $host= $1; ## no critic qw(RegularExpressions::ProhibitCaptureWithoutTest) my $url = $2 || "/"; ## no critic qw(RegularExpressions::ProhibitCaptureWithoutTest) return "" if not defined $host; # wrong URI may be passed $host=~ m#^([^:]+)(?::[0-9]{1,5})?#; $host= $1; ## no critic qw(RegularExpressions::ProhibitCaptureWithoutTest) my $port= $2 || 80; $port =~ s/^://; ## no critic qw(RegularExpressions::ProhibitCaptureWithoutTest) _trace2("check_url: get_http($host, $port, $url)"); my ($response, $status, %headers) = Net::SSLeay::get_http($host, $port, $url, Net::SSLeay::make_headers('Connection' => 'close', 'Host' => $host) ); _trace2("check_url: STATUS: $status"); if ($status !~ m#^HTTP/... (?:[1234][0-9][0-9]|500) #) { return "<>"; } _trace2("check_url: header: #{ " . join(": ", %headers) . " }"); # a bit ugly :-( if ($status =~ m#^HTTP/... 200 #) { $accept = $headers{(grep{/^Accept-Ranges$/i} keys %headers)[0] || ""}; $ctype = $headers{(grep{/^Content-Type$/i} keys %headers)[0] || ""}; $length = $headers{(grep{/^Content-Length$/i} keys %headers)[0] || ""}; $binary = $headers{(grep{/^Content-transfer-encoding$/i} keys %headers)[0] || ""}; $chunk = $headers{(grep{/^Transfer-Encoding$/i} keys %headers)[0] || ""}; } else { return "<>"; } # FIXME: 30x status codes are ok; we should then call ourself again if ($type eq 'ocsp_uri') { _trace2("check_url: ocsp_uri ..."); return _get_text('invalid', "Content-Type: $ctype") if ($ctype !~ m:application/ocsp-response:i); return _get_text('invalid', "Content-Length: $ctype") if ($length < 4); return ""; # valid } # OCSP if ($type eq 'ext_crl') { _trace2("check_url: ext_crl ..."); if ((defined $accept) && (defined $chunk)) { if ($accept !~ m/bytes/i) { if (($accept !~ m/^none/i) && ($chunk !~ m/^chunked/i)) { return _get_text('invalid', "Accept-Ranges: $accept"); } } } if ($ctype !~ m#application/(?:pkix-crl|x-pkcs7-crl)#i) { return _get_text('invalid', "Content-Type: $ctype"); } return ""; # valid } # CRL return $txt; } # check_url sub check_nextproto { #? check target for ALPN or NPN support; returns list of supported protocols my ($host, $port, $type, $mode) = @_; # $type is ALPN or NPN; $mode is all or single # in single mode, each protocol specified in $cfg{'protos_next'} is tested # for its own, while in all mode all protocols are set at once # Also SEE Note:ALPN, NPN _trace("check_nextproto($host, $port, $type, $mode)"); my @protos = split(",", $cfg{'protos_next'}); @protos = $cfg{'protos_next'} if ($mode eq 'all'); # pass all at once my @npn; my ($ssl, $ctx, $method); my $socket; # = undef; foreach my $proto (@protos) { #_trace(" do_ssl_new(..., ".(join(" ", @{$cfg{'version'}})) # . ", $cfg{'cipherpattern'}, $proto, $proto, socket)"); $ssl = undef; $ctx = undef; $socket= undef; ($ssl, $ctx, $socket, $method) = Net::SSLinfo::do_ssl_new( $host, $port, (join(" ", @{$cfg{'version'}})), $cfg{'cipherpattern'}, (($type eq 'ALPN') ? $proto : ""), (($type eq 'NPN') ? $proto : ""), $socket ); if (not defined $ssl) { _warn("601: $type connection failed with '$proto'"); } else { # Net::SSLeay's functions are crazy, both P_next_proto_negotiated() # and P_alpn_selected() return undef if not supported by server and # for any error. Anyway, we only want to know if $proto supported. # As we check protocols one by one, this information is sufficient. my $np; $np = Net::SSLeay::P_alpn_selected($ssl) if ($type eq 'ALPN'); $np = Net::SSLeay::P_next_proto_negotiated($ssl) if ($type eq 'NPN'); if (defined $np && $mode eq 'single') { _warn("602: $type name mismatch: (send) $proto <> $np (returned)") if ($proto ne $np); } _trace("check_nextproto: $type $np") if (defined $np) ; if (defined $np) { push(@npn, $np) if ($proto eq $np); # only if matched } } # TODO: need to check if ($cfg{'socket_reuse'} > 0); then do not call do_ssl_free Net::SSLinfo::do_ssl_free($ctx, $ssl, $socket); #{ #TODO: if ($cfg(extopenssl) > 0) #my $data = Net::SSLinfo::do_openssl("s_client -alpn $proto -connect", $host, $port, ""); #my $np = grep{/^ALPN protocol:.*/} split("\n", $data); #my $data = Net::SSLinfo::do_openssl("s_client -nextprotoneg $proto -connect", $host, $port, ""); #my $np = grep{/^Next protocol:.*/} split("\n", $data); #my $np = grep{/^Protocols advertised by:.*/} split("\n", $data); #print "$proto : $np"; #} } _trace("check_nextproto: @npn"); return @npn; } # check_nextproto sub checkalpn { #? check target for ALPN or NPN support; returns void # stores list of supported protocols in corresponding $info{} # uses protocols from $cfg{'protos_next'} only my ($host, $port) = @_; _y_CMD("checkalpn() "); $cfg{'done'}->{'checkalpn'}++; return if ($cfg{'done'}->{'checkalpn'} > 1); # _trace("trace not necessary, output from check_nextproto() is sufficient"); if ($cfg{'ssleay'}->{'get_alpn'} > 0) { $info{'alpns'} = join(",", check_nextproto($host, $port, 'ALPN', 'single')); $info{'alpn'} = join(",", check_nextproto($host, $port, 'ALPN', 'all')); } # else warning already printed if ($cfg{'ssleay'}->{'get_npn'} > 0) { $info{'npns'} = join(",", check_nextproto($host, $port, 'NPN', 'single')); $info{'npn'} = join(",", check_nextproto($host, $port, 'NPN', 'all')); } # else warning already printed # TODO: 'next_protocols' should be retrieved here too return; } # checkalpn sub checkprefered { #? test if target prefers strong ciphers, aka SSLHonorCipherOrder my ($host, $port) = @_; # not yet used _y_CMD("checkprefered() " . $cfg{'done'}->{'checkprefered'}); $cfg{'done'}->{'checkprefered'}++; return if ($cfg{'done'}->{'checkprefered'} > 1); _trace("checkprefered($host, $port){"); foreach my $ssl (@{$cfg{'version'}}) { # check all SSL versions my $strong = $prot{$ssl}->{'cipher_strong'}; my $weak = $prot{$ssl}->{'cipher_weak'}; my $txt = "$strong,$weak"; $checks{'cipher_strong'}->{val} .= _prot_cipher($ssl, $txt) if ($weak ne $strong); # FIXME: assumtion wrong if only one cipher accepted $checks{'cipher_order'}->{val} .= _prot_cipher($ssl, $txt) if ($weak ne $strong); # NOT YET USED $checks{'cipher_weak'}->{val} .= _prot_cipher($ssl, $txt) if ($weak eq $strong); # remember: eq ! } _trace("checkprefered() }"); return; } # checkprefered sub checkcipher($$) { #? test given cipher and add result to %checks and %prot my ($ssl, $c) = @_; my $risk = get_cipher_sec($c); # following checks add the "not compliant" or vulnerable ciphers # check weak ciphers $checks{'cipher_null'}->{val} .= _prot_cipher($ssl, $c) if ($c =~ /NULL/); $checks{'cipher_adh'}->{val}.= _prot_cipher($ssl, $c) if ($c =~ /$cfg{'regex'}->{'ADHorDHA'}/); $checks{'cipher_exp'}->{val}.= _prot_cipher($ssl, $c) if ($c =~ /$cfg{'regex'}->{'EXPORT'}/); $checks{'cipher_cbc'}->{val}.= _prot_cipher($ssl, $c) if ($c =~ /CBC/); $checks{'cipher_des'}->{val}.= _prot_cipher($ssl, $c) if ($c =~ /DES/); $checks{'cipher_rc4'}->{val}.= _prot_cipher($ssl, $c) if ($c =~ /$cfg{'regex'}->{'RC4orARC4'}/); $checks{'cipher_edh'}->{val}.= _prot_cipher($ssl, $c) if ($c =~ /$cfg{'regex'}->{'DHEorEDH'}/); # TODO: lesen: http://www.golem.de/news/mindeststandards-bsi-haelt-sich-nicht-an-eigene-empfehlung-1310-102042.html # check compliance $checks{'ism'}->{val} .= _prot_cipher($ssl, $c) if ($c =~ /$cfg{'regex'}->{'notISM'}/); $checks{'pci'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _ispci( $ssl, $c)); $checks{'fips'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _isfips($ssl, $c)); $checks{'rfc_7525'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _isrfc7525($ssl, $c)); $checks{'tr_02102+'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _istr02102_strict($ssl, $c)); $checks{'tr_02102-'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _istr02102_lazy( $ssl, $c)); $checks{'tr_03116+'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _istr03116_strict($ssl, $c)); $checks{'tr_03116-'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _istr03116_lazy( $ssl, $c)); # check attacks $checks{'rc4'}->{val} = $checks{'cipher_rc4'}->{val}; # these are the same checks $checks{'beast'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _isbeast($ssl, $c)); $checks{'breach'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _isbreach($c)); $checks{'freak'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _isfreak($ssl, $c)); $checks{'lucky13'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _islucky($c)); $checks{'robot'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _isrobot($ssl, $c)); $checks{'sloth'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _issloth($ssl, $c)); $checks{'sweet32'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _issweet($ssl, $c)); push(@{$prot{$ssl}->{'ciphers_pfs'}}, $c) if ("" eq _ispfs($ssl, $c)); # add PFS cipher # counters $prot{$ssl}->{'-?-'}++ if ($risk =~ /-\?-/); # private marker $prot{$ssl}->{'WEAK'}++ if ($risk =~ /WEAK/i); $prot{$ssl}->{'LOW'}++ if ($risk =~ /LOW/i); $prot{$ssl}->{'MEDIUM'}++ if ($risk =~ /MEDIUM/i); $prot{$ssl}->{'HIGH'}++ if ($risk =~ /HIGH/i); $risk = get_cipher_owasp($c); $prot{$ssl}->{'OWASP_miss'}++ if ($risk eq 'miss'); $prot{$ssl}->{'OWASP_NA'}++ if ($risk eq '-?-'); $prot{$ssl}->{'OWASP_D'}++ if ($risk eq 'D'); $prot{$ssl}->{'OWASP_C'}++ if ($risk eq 'C'); $prot{$ssl}->{'OWASP_B'}++ if ($risk eq 'B'); $prot{$ssl}->{'OWASP_A'}++ if ($risk eq 'A'); return; } # checkcipher sub checkciphers { #? test target if given ciphers are accepted, results stored in global %checks # checks are done with information from @cipher_results my ($host, $port, @results) = @_; _y_CMD("checkciphers() " . $cfg{'done'}->{'checkciphers'}); $cfg{'done'}->{'checkciphers'}++; return if ($cfg{'done'}->{'checkciphers'} > 1); _trace("checkciphers($host, $port){"); if ($#results < 0) { # no ciphers found; avoid misleading values foreach my $key (@{$cfg{'need-cipher'}}) { $checks{$key}->{val} = _get_text('miss_cipher', ""); } foreach my $ssl (@{$cfg{'version'}}) { # check all SSL versions @{$prot{$ssl}->{'ciphers_pfs'}} = _get_text('miss_cipher', ""); } _trace("checkciphers() }"); return; } my $ssl = ""; my $cipher = ""; my %hasecdsa; # ECDHE-ECDSA is mandatory for TR-02102-2, see 3.2.3 my %hasrsa ; # ECDHE-RSA is mandatory for TR-02102-2, see 3.2.3 foreach my $c (@results) { # check all accepted ciphers next if not @{$c}; # defensive programming .. next if ((scalar(@{$c})) =~ m/^\s*$/); # -"- # each $c looks like: TLSv12 ECDHE-RSA-AES128-GCM-SHA256 yes my $yn = ${$c}[2]; $cipher = ${$c}[1]; $ssl = ${$c}[0]; if ($yn =~ m/yes/i) { # cipher accepted $prot{$ssl}->{'cnt'}++; checkcipher($ssl, $cipher); $checks{'logjam'}->{val} .= _prot_cipher($ssl, $c) if ("" ne _islogjam($ssl, $c)); } $hasrsa{$ssl} = 1 if ($cipher =~ /$cfg{'regex'}->{'EC-RSA'}/); $hasecdsa{$ssl}= 1 if ($cipher =~ /$cfg{'regex'}->{'EC-DSA'}/); } # additional BEAST check: checks for vulnerable protocols are disabled? my $beastskipped = _isbeastskipped($host, $port); $checks{'beast'}->{val} .= " " . ${beastskipped} if "" ne $beastskipped; $checks{'breach'}->{val} = "<>"; foreach my $ssl (@{$cfg{'version'}}) { # check all SSL versions $hasrsa{$ssl} = 0 if not defined $hasrsa{$ssl}; # keep Perl silent $hasecdsa{$ssl}= 0 if not defined $hasecdsa{$ssl}; # -"- # TR-02102-2, see 3.2.3 if ($prot{$ssl}->{'cnt'} > 0) { # checks do not make sense if there're no ciphers $checks{'tr_02102+'}->{val} .= _prot_cipher($ssl, $text{'miss_RSA'}) if ($hasrsa{$ssl} != 1); $checks{'tr_02102+'}->{val} .= _prot_cipher($ssl, $text{'miss_ECDSA'}) if ($hasecdsa{$ssl} != 1); $checks{'tr_03116+'}->{val} .= $checks{'tr_02102+'}->{val}; # same as TR-02102 $checks{'tr_03116-'}->{val} .= $checks{'tr_02102-'}->{val}; # -"- } $checks{'cnt_ciphers'} ->{val} += $prot{$ssl}->{'cnt'}; # need this with cnt_ prefix } $checks{'cipher_edh'}->{val} = "" if ($checks{'cipher_edh'}->{val} ne ""); # good if we have them # we need our well known string, hence 'sslversion'; SEE Note:Selected Protocol $ssl = $data{'sslversion'}->{val}($host, $port); # get selected protocol $cipher = $data{'cipher_selected'}->{val}($host, $port);# get selected cipher if ((defined $prot{$ssl}->{'cnt'}) and (defined $prot{$ssl}->{'ciphers_pfs'})) { $checks{'cipher_pfsall'}->{val} = " " if ($prot{$ssl}->{'cnt'} > $#{$prot{$ssl}->{'ciphers_pfs'}}); } else { $checks{'cipher_pfsall'}->{val} = $text{'na'}; } #$checks{'cipher_pfs'}->{val} # done in checkdest() _trace("checkciphers() }"); return; } # checkciphers sub checkbleed($$) { #? check if target supports vulnerable TLS extension 15 (hearbeat) # SEE Note:heartbleed my ($host, $port) = @_; _y_CMD("checkbleed() ". $cfg{'done'}->{'checkbleed'}); $cfg{'done'}->{'checkbleed'}++; return if ($cfg{'done'}->{'checkbleed'} > 1); my $bleed = _isbleed($host, $port); if ($cfg{'ignorenoreply'} > 0) { return if ($bleed =~ m/no reply/); } $checks{'heartbleed'}->{val} = $bleed; return; } # checkbleed sub checkdates($$) { # check validation of certificate's before and after date my ($host, $port) = @_; _y_CMD("checkdates() " . $cfg{'done'}->{'checkdates'}); $cfg{'done'}->{'checkdates'}++; return if ($cfg{'done'}->{'checkdates'} > 1); # NOTE: all $data{'valid_*'} are values, not functions my $before= $data{'before'}->{val}($host, $port); my $after = $data{'after'} ->{val}($host, $port); my @since = split(/ +/, $before); my @until = split(/ +/, $after); if ("$before$after" =~ m/^\s*$/) { # if there's no data from the certificate, set undef values and return $checks{'dates'}->{val} = $text{'na'}; $checks{'expired'}->{val} = $text{'na'}; $checks{'sts_expired'}->{val} = $text{'na'}; $checks{'valid_years'}->{val} = 0; $checks{'valid_months'}->{val} = 0; $checks{'valid_days'}->{val} = 0; return; } # Note about calculating dates: # Calculation should be done without using additional Perl modules like # Time::Local, Date::Calc, Date::Manip, ... # Hence we convert dates given by the certificate's before and after value # to the format YYYYMMDD. The format given in the certificate is always # GMT and in fixed form: MMM DD hh:mm:ss YYYY GMT. So a split() gives year # and day as integer. Just the month is a string, which must be converted # to an integer using the map() funtion on @mon array. # The same format is used for the current date given by gmtime(), but # convertion is much simpler as no strings exist here. my @now = gmtime(time); my @mon = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); my $m = 0; my $s_mon = 0; my $u_mon = 0; if (@since) { my $dum = map({$m++; $s_mon=$m if/$since[0]/} @mon); $m = 0; } if (@until) { my $dum = map({$m++; $u_mon=$m if/$until[0]/} @mon); $m = 0; } # my $dum = keeps Perl::Critic happy my $now = sprintf("%4d%02d%02d", $now[5]+1900, $now[4]+1, $now[3]); my $start = sprintf("%s%02s%02s", $since[3], $s_mon, $since[1]); my $end = sprintf("%s%02s%02s", $until[3], $u_mon, $until[1]); my $txt = ""; # end date magic, do checks .. $checks{'dates'}->{val} = $before if ($now < $start); $checks{'dates'}->{val} .= " .. " . $after if ($now > $end); $checks{'expired'}->{val} = $after if ($now > $end); $data{'valid_years'}->{val} = ($until[3] - $since[3]); $data{'valid_months'}->{val} = ($until[3] * 12) - ($since[3] * 12) + $u_mon - $s_mon; $data{'valid_days'}->{val} = ($data{'valid_years'}->{val} * 5) + ($data{'valid_months'}->{val} * 30); # approximately $data{'valid_days'}->{val} = ($until[1] - $since[1]) if ($data{'valid_days'}->{val} < 60); # more accurate # The current timestamp is added to the STS max-age to check if the STS # max-age exceeds the certificate's expire date. All timestamps are given # in epoch timestamp format. # The after value from the certificate must be converted to epoch time- # stamp format, and then can be compared to STS max-age. # Unfortunately there exist no simple method to convert a human readable # timestamps (like certificate's after) into epoch timestamp format. # Perl's Time::Local module is used for that in the hope that it is part # of most Perl installations. Existance of Time::Local module was already # done at startup with and +sts_expired disabled if missing. # SEE Perl:import include MAXAGE_CHECK: { $txt = $text{'na_STS'}; last MAXAGE_CHECK if ($data{'https_sts'}->{val}($host) eq ""); $txt = STR_UNDEF; last MAXAGE_CHECK if (!_is_do('sts_expired')); $txt = ""; # compute epoch timestamp from 'after' my $ts = Time::Local::timelocal(reverse(split(/:/, $until[2])), $until[1], $u_mon - 1, $until[3]); my $maxage = $data{'hsts_maxage'}->{val}($host); $now = time(); # we need epoch timestamp here $txt = "$now + $maxage > $ts" if ($now + $maxage > $ts); } $checks{'sts_expired'} ->{val} = $txt; _trace("checkdates: start, now, end: : $start, $now, $end"); _trace("checkdates: valid: " . $checks{'dates'}->{val}); _trace("checkdates: valid-years: " . $data{'valid_years'}->{val}); _trace("checkdates: valid-month: " . $data{'valid_months'}->{val} . " = ($until[3]*12) - ($since[3]*12) + $u_mon - $s_mon"); _trace("checkdates: valid-days: " . $data{'valid_days'}->{val} . " = (" . $data{'valid_years'}->{val} . "*5) + (" . $data{'valid_months'}->{val} . "*30)"); return; } # checkdates sub checkcert($$) { #? check certificate settings my ($host, $port) = @_; my ($value, $label); _y_CMD("checkcert() " . $cfg{'done'}->{'checkcert'}); $cfg{'done'}->{'checkcert'}++; return if ($cfg{'done'}->{'checkcert'} > 1); # wildcards (and some sizes) _checkwildcard($host, $port); # $checks{'certfqdn'}->{val} ... done in checksni() $checks{'rootcert'}->{val} = $data{'issuer'}->{val}($host) if ($data{'subject'}->{val}($host) eq $data{'issuer'}->{val}($host)); $checks{'ocsp_uri'}->{val} = " " if ($data{'ocsp_uri'}->{val}($host) eq ""); $checks{'cps'}->{val} = " " if ($data{'ext_cps'}->{val}($host) eq ""); $checks{'crl'}->{val} = " " if ($data{'ext_crl'}->{val}($host) eq ""); if ($cfg{'usehttp'} > 0) { # at least 'ext_crl' may contain more than one URL $checks{'crl_valid'}->{val} = ""; $value = $data{'ext_crl'}->{val}($host); if ($value eq '<>') { # TODO: <> from Net::SSLinfo $checks{'crl_valid'}->{val} = $text{'na_openssl'}; } else { _trace("ext_crl: $value"); # may have something other than http://... foreach my $url (split(/\s+/, $value)) { next if ($url =~ m/^\s*$/); # skip empty url if ($url !~ m/^\s*http$/) { _trace("ext_uri skipped: $url"); next; } $checks{'crl_valid'}->{val} .= check_url($url, 'ext_crl') || ""; } } $checks{'ocsp_valid'}->{val} = ""; $value = $data{'ocsp_uri'}->{val}($host); if ($value eq '<>') { $checks{'crl_valid'}->{val} = $text{'na_openssl'}; } else { _trace("ocsp_uri: $value"); foreach my $url (split(/\s+/, $value)) { next if ($url =~ m/^\s*$/); # skip empty url if ($url !~ m/^\s*http$/) { _trace("ocsp_uri skipped: $url"); next; } $checks{'ocsp_valid'}->{val} .= check_url($url, 'ocsp_uri') || ""; } } } else { $checks{'crl_valid'}->{val} = _get_text('disabled', "--no-http"); $checks{'ocsp_valid'}->{val}= _get_text('disabled', "--no-http"); } $value = $data{'ext_constraints'}->{val}($host); $checks{'constraints'}->{val} = " " if ($value eq ""); $checks{'constraints'}->{val} = $value if ($value !~ m/CA:FALSE/i); # TODO: more checks necessary: # KeyUsage field must set keyCertSign and/or the BasicConstraints field has the CA attribute set TRUE. check_certchars($host, $port); # certificate if ($cfg{'verbose'} > 0) { # TODO foreach my $label (qw(verify selfsigned)) { #dbx# _dbx "$label : $value #"; $value = $data{$label}->{val}($host); $checks{$label}->{val} = $value if ($value eq ""); # FIXME: $data{'verify'} $data{'error_verify'} $data{'error_depth'} # if (_is_do('verify')) { # print ""; # print "Hostname validity: " . $data{'verify_hostname'}->{val}($host); # print "Alternate name validity: " . $data{'verify_altname'}->{val}( $host); # } # # if (_is_do('altname')) { # print ""; # print "Certificate AltNames: " . $data{'altname'}->{val}( $host); # print "Alternate name validity: " . $data{'verify_altname'}->{val}( $host); # } } } $value = $data{'selfsigned'}->{val}($host); # may contain: 0 (ok) $checks{'selfsigned'} ->{val} = $value if ($value !~ m/^(?:0\s+.ok.)*$/); $checks{'fp_not_md5'} ->{val} = $data{'fingerprint'} if ('MD5' eq $data{'fingerprint'}); $value = $data{'signame'}->{val}($host); $checks{'sha2signature'} ->{val} = $value if ($value !~ m/^$cfg{'regex'}->{'SHA2'}/); $checks{'sig_encryption'}->{val} = $value if ($value !~ m/$cfg{'regex'}->{'encryption'}/i); $checks{'sig_enc_known'} ->{val} = $value if ($value !~ m/^$cfg{'regex'}->{'encryption_ok'}|$cfg{'regex'}->{'encryption_no'}$/i); ## no critic qw(RegularExpressions::ProhibitComplexRegexes) $value = $data{'pubkey_algorithm'}->{val}($host); $checks{'pub_encryption'}->{val} = $value if ($value !~ m/$cfg{'regex'}->{'encryption'}/i); $checks{'pub_enc_known'} ->{val} = $value if ($value !~ m/^$cfg{'regex'}->{'encryption_ok'}|$cfg{'regex'}->{'encryption_no'}$/i); ## no critic qw(RegularExpressions::ProhibitComplexRegexes) # TODO: ocsp_uri pruefen; Soft-Fail, Hard-Fail # TODO: check: serialNumber: Positive number up to a maximum of 20 octets. # TODO: check: Signature: Must be the same OID as that defined in SignatureAlgorithm below. # TODO: check: Version # TODO: check: validity (aka dates) # TODO: check: Issuer # Only CN=, C=, ST=, O=, OU= and serialNumber= must be supported the rest are optional # TODO: check: Subject # The subject field can be empty in which case the entity being authenticated is defined in the subjectAltName. return; } # checkcert sub checksni($$) { #? check if given FQDN needs to use SNI # sets $checks{'sni'}, $checks{'certfqdn'} # DNS strings are case insensitive, hence values are compared lowercase my ($host, $port) = @_; _y_CMD("checksni() " . $cfg{'done'}->{'checksni'}); $cfg{'done'}->{'checksni'}++; return if ($cfg{'done'}->{'checksni'} > 1); my $cn = $data{'cn'}->{val}($host, $port); my $lc_nosni = lc($data{'cn_nosni'}->{val}); my $lc_host = lc($host); my $lc_cn = lc($cn); my $rex_cn = $cn; $rex_cn =~ s/[*][.]/(?:.*\\.)?/g; # convert DNS wildcard to Perl regex if ($cfg{'usesni'} == 1) { # useless check for --no-sni if ($lc_host eq $lc_nosni) { $checks{'sni'}->{val} = ""; } else { $checks{'sni'}->{val} = $data{'cn_nosni'}->{val}; } } if ($cfg{'no_cert'} != 0) { $checks{'certfqdn'}->{val} = $cfg{'no_cert_txt'}; $checks{'hostname'}->{val} = $cfg{'no_cert_txt'}; return; } if ($lc_host eq $lc_cn) { $checks{'hostname'}->{val} = ""; } else { $checks{'hostname'}->{val} = $host . " <> " . $data{'cn'}->{val}($host); } if ($host =~ m/$rex_cn/i) { $checks{'certfqdn'}->{val} = ""; } else { $checks{'certfqdn'}->{val} = $data{'cn_nosni'}->{val} . " <> " . $host; } #dbx# _dbx "host:\t\t" . $host; #dbx# _dbx "data{cn}:\t\t" . $data{'cn'}->{val}($host); #dbx# _dbx "data{cn_nosni}:\t" . $data{'cn_nosni'}->{val}; #dbx# _dbx "checks{hostname}:\t" . $checks{'hostname'}->{val}; #dbx# _dbx "checks{certfqdn}:\t" . $checks{'certfqdn'}->{val}; return; } # checksni sub _base2 { #? return base-2 of given number my $value = shift; $value = 1 if ($value !~ /^[0-9]+$/);# defensive programming: quick&dirty check return 0 if ($value == 0); # -''- $value = log($value); # base-2 = log($value) / log(2) # unfortunatelly this calculation results in "inf" for big values # to avoid using Math::BigInt for big values, the calculation is done # as follows (approximately): # log(2) = 0.693147180559945; # 1/log(2) = 1.44269504088896; # v * 1.44 = v + (v / 100 * 44); return ($value + ($value/100*44)); } # _base2 sub checksizes($$) { #? compute some lengths and count from certificate values # sets %checks my ($host, $port) = @_; my $value; _y_CMD("checksizes() " . $cfg{'done'}->{'checksizes'}); $cfg{'done'}->{'checksizes'}++; return if ($cfg{'done'}->{'checksizes'} > 1); checkcert($host, $port) if ($cfg{'no_cert'} == 0); # in case we missed it before $value = $data{'pem'}->{val}($host); $checks{'len_pembase64'}->{val} = length($value); $value =~ s/(----.+----\n)//g; chomp $value; $checks{'len_pembinary'}->{val} = sprintf("%d", length($value) / 8 * 6) + 1; # simple round() $checks{'len_subject'} ->{val} = length($data{'subject'} ->{val}($host)); $checks{'len_issuer'} ->{val} = length($data{'issuer'} ->{val}($host)); $checks{'len_cps'} ->{val} = length($data{'ext_cps'} ->{val}($host)); $checks{'len_crl'} ->{val} = length($data{'ext_crl'} ->{val}($host)); #$checks{'len_crl_data'} ->{val} = length($data{'crl'} ->{val}($host)); $checks{'len_ocsp'} ->{val} = length($data{'ocsp_uri'}->{val}($host)); #$checks{'len_oids'} ->{val} = length($data{'oids'}->{val}($host)); $checks{'len_sernumber'}->{val} = int(length($data{'serial_hex'}->{val}($host)) / 2); # value are hex octets # Note: RFC5280 limits the serial number to an integer with not more # than 20 octets. It should also be not a negative number. # It's assumed that a octet equals one byte. if ($cmd{'extopenssl'} == 1) { # TODO: find a better way to do this ugly check $value = $data{'modulus_len'}->{val}($host); $checks{'len_publickey'}->{val} = (($value =~ m/^\s*$/) ? 0 : $value); $value = $data{'modulus_exponent'}->{val}($host); # i.e. 65537 (0x10001) or prime256v1 if ($value =~ m/prime/i) { # public key uses EC with primes $value =~ s/\n */ /msg; $checks{'modulus_exp_1'} ->{val} = "<>"; $checks{'modulus_exp_65537'} ->{val} = "<>"; $checks{'modulus_exp_oldssl'}->{val} = "<>"; $checks{'modulus_size_oldssl'}->{val} = "<>"; } else { # only traditional exponent needs to be checked if ($value eq '<>') { # TODO: <> from Net::SSLinfo $checks{'modulus_exp_1'} ->{val}= $text{'na_openssl'}; $checks{'modulus_exp_65537'} ->{val}= $text{'na_openssl'}; $checks{'modulus_exp_oldssl'}->{val}= $text{'na_openssl'}; } else { $value =~ s/^(\d+).*/$1/; if ($value =~ m/^\d+$/) { # avoid Perl warning "Argument isn't numeric" $checks{'modulus_exp_1'} ->{val}= $value if ($value == 1); $checks{'modulus_exp_65537'} ->{val}= $value if ($value != 65537); $checks{'modulus_exp_oldssl'}->{val}= $value if ($value > 65536); } else { $checks{'modulus_exp_1'} ->{val}= $text{'na'}; $checks{'modulus_exp_65537'} ->{val}= $text{'na'}; $checks{'modulus_exp_oldssl'}->{val}= $text{'na'}; } } $value = $data{'modulus'}->{val}($host); # value are hex digits if ($value eq '<>') { $checks{'modulus_size_oldssl'}->{val} = $text{'na_openssl'}; } else { $checks{'modulus_size_oldssl'}->{val} = length($value) * 4 if ((length($value) * 4) > 16384); } } $value = $data{'serial_int'}->{val}($host); $value = 0 if ($value =~ m/^\s*$/); # avoid Perl warning "Argument isn't numeric" $value += 0; my $bits_of_value = _base2($value); $checks{'sernumber'} ->{val} = "$bits_of_value > 160" if ($bits_of_value > 160); $value = $data{'sigkey_len'}->{val}($host); $checks{'len_sigdump'} ->{val} = (($value =~ m/^\s*$/) ? 0 : $value); # missing without openssl } else { # missing without openssl $checks{'sernumber'} ->{val} = $text{'na_openssl'}; $checks{'len_sigdump'} ->{val} = $text{'na_openssl'}; $checks{'len_publickey'}->{val} = $text{'na_openssl'}; $checks{'modulus_exp_1'}->{val} = $text{'na_openssl'}; $checks{'modulus_exp_65537'} ->{val} = $text{'na_openssl'}; $checks{'modulus_exp_oldssl'}->{val} = $text{'na_openssl'}; $checks{'modulus_size_oldssl'}->{val}= $text{'na_openssl'}; } return; } # checksizes sub check02102($$) { #? check if target is compliant to BSI TR-02102-2 2016-01 # assumes that checkciphers() and checkdest() already done my ($host, $port) = @_; _y_CMD("check02102() " . $cfg{'done'}->{'check02102'}); $cfg{'done'}->{'check02102'}++; return if ($cfg{'done'}->{'check02102'} > 1); my $txt = ""; my $val = ""; # description (see CHECK in o-saft-man.pm) ... # lines starting with #! are headlines from TR-02102-2 # All checks according ciphers already done in checkciphers() and stored # in $checks{'tr_02102.'}. We need to do checks according certificate and # protocol and fill other %checks values according requirements. #! TR-02102-2 3.2 SSL/TLS-Versionen # use 'session_protocol' instead of 'sslversion' as its string matches the # TR-02102 requirements better; SEE Note:Selected Protocol $val = ($data{'session_protocol'}->{val}($host, $port) !~ m/TLSv1.?2/) ? " <>" : "" ; $val .= ($prot{'SSLv2'}->{'cnt'} > 0) ? _get_text('insecure', "protocol SSLv2") : ""; $val .= ($prot{'SSLv3'}->{'cnt'} > 0) ? _get_text('insecure', "protocol SSLv3") : ""; $val .= ($prot{'TLSv1'}->{'cnt'} > 0) ? _get_text('insecure', "protocol TLSv1") : ""; $checks{'tr_02102-'}->{val}.= $val; $val .= ($prot{'TLSv11'}->{'cnt'} > 0) ? _get_text('insecure', "protocol TLSv11") : ""; $checks{'tr_02102+'}->{val}.= $val; #! TR-02102-2 3.3.1 Empfohlene Cipher Suites #! TR-02102-2 3.3.2 Übergangsregelungen # cipher checks are already done in checkciphers() #! TR-02102-2 3.4.1 Session Renegotation $val = ($checks{'renegotiation'}->{val} ne "") ? $text{'no_reneg'} : ""; $checks{'tr_02102+'}->{val}.= $val; $checks{'tr_02102-'}->{val}.= $val; #! TR-02102-2 3.4.2 Verkürzung der HMAC-Ausgabe # FIXME: cannot be tested because openssl does not suppot it (11/2016) $val = ($data{'tlsextensions'}->{val}($host, $port) =~ m/truncated.*hmac/i) ? _get_text('enabled_extension', 'truncated HMAC') : "" ; $checks{'tr_02102+'}->{val}.= $val; $checks{'tr_02102-'}->{val}.= $val; #! TR-02102-2 3.4.3 TLS-Kopression und CRIME $checks{'tr_02102+'}->{val}.= $checks{'crime'}->{val}; $checks{'tr_02102-'}->{val}.= $checks{'crime'}->{val}; #! TR-02102-2 3.4.4 Der Lucky 13-Angriff $val = $checks{'lucky13'}->{val}; $val = ($val ne "") ? _get_text('insecure', "cipher $val; Lucky13") : "" ; $checks{'tr_02102+'}->{val}.= $val; # check for Lucky 13 in strict mode only (requires GCM) #! TR-02102-2 3.4.5 Die "Encrypt-then-MAC"-Erweiterung # FIXME: cannot be tested because openssl does not suppot it (11/2016) #! TR-02102-2 3.4.6 Die Heartbeat-Erweiterung $val = ""; $val = ($data{'heartbeat'}->{val}($host, $port) ne "") ? _get_text('enabled_extension', 'heartbeat') : ""; $checks{'tr_02102+'}->{val}.= $val; $checks{'tr_02102-'}->{val}.= $val; #! TR-02102-2 3.4.7 Die Extended Master Secret Extension # FIXME: cannot be tested because openssl does not suppot it (11/2016) #! TR-02102-2 3.5 Authentisierung der Kommunikationspartner # check are not possible from remote #! TR-02102-2 3.6 Domainparameter und Schlüssellängen $val = $checks{'len_sigdump'}->{val}; if ($val =~ m/\d+/) { # avoid Perl warning "Argument isn't numeric" $val = ($val < 2000) ? _get_text('bit2048', $val) : ""; # FIXME: lazy check does not honor used cipher } else { $val = " len_sigdump missing $val"; } $checks{'tr_02102+'}->{val}.= $val; $checks{'tr_02102-'}->{val}.= $val; #check_dh($host, $port); # need DH Parameter # FIXME: check see for example check7525() #! TR-02102-2 3.6.1 Verwendung von elliptischen Kurven # brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 (vgl. [RFC5639] und [RFC7027]) # lazy allows: secp256r1, secp384r1 # verboten: secp224r1 # TODO: cipher bit length check #! TR-02102-2 4.1 Schlüsselspeicherung #! TR-02102-2 4.2 Umgang mit Ephemeralschlüsseln #! TR-02102-2 4.3 Zufallszahlen # these checks are not possible from remote return; } # check02102 sub check2818($$) { #? check if subjectAltNames is RFC 2818 compliant my ($host, $port) = @_; _y_CMD("check2818() " . $cfg{'done'}->{'check2818'}); $cfg{'done'}->{'check2818'}++; return if ($cfg{'done'}->{'check2818'} > 1); my $val = $data{'verify_altname'}->{val}($host); $checks{'rfc_2818_names'}->{val} = $val if ($val !~ m/matches/); # see Net::SSLinfo.pm return; } # check2818 sub check03116($$) { #? check if target is compliant to BSI TR-03116-4 my ($host, $port) = @_; # BSI TR-03116-4 is similar to BSI TR-02102-2 _y_CMD("check03116() " . $cfg{'done'}->{'check03116'}); $cfg{'done'}->{'check03116'}++; return if ($cfg{'done'}->{'check03116'} > 1); my $txt = ""; # All checks according ciphers already done in checkciphers() and stored # in $checks{'tr_03116'}. We need to do checks according certificate and # protocol and fill other %checks values according requirements. #! TR-03116-4 2.1.1 TLS-Versionen und Sessions # muss mindestens die TLS-Version 1.2 unterstützt werden # use 'session_protocol' instead of 'sslversion' as its string matches the # TR-03116 requirements better; SEE Note:Selected Protocol $txt = ($data{'session_protocol'}->{val}($host, $port) !~ m/TLSv1.?2/) ? " <>" : "" ; $txt .= ($prot{'SSLv2'}->{'cnt'} > 0) ? _get_text('insecure', "protocol SSLv2") : ""; $txt .= ($prot{'SSLv3'}->{'cnt'} > 0) ? _get_text('insecure', "protocol SSLv3") : ""; $txt .= ($prot{'TLSv1'}->{'cnt'} > 0) ? _get_text('insecure', "protocol TLSv1") : ""; $txt .= ($prot{'TLSv11'}->{'cnt'} > 0) ? _get_text('insecure', "protocol TLSv11") : ""; $checks{'tr_03116-'}->{val}.= $txt; $checks{'tr_03116+'}->{val}.= $txt; #! TR-03116-4 2.1.2 Cipher Suites $checks{'tr_03116+'}->{val}.= $checks{'tr_03116+'}->{val}; $checks{'tr_03116-'}->{val}.= $checks{'tr_03116-'}->{val}; #! TR-03116-4 2.1.1 TLS-Versionen und Sessions # TLS Session darf eine Lebensdauer von 2 Tagen nicht überschreiten #! TR-03116-4 2.1.4.2 Encrypt-then-MAC-Extension #! TR-03116-4 2.1.4.3 OCSP-Stapling $checks{'tr_03116+'}->{val} .= _get_text('missing', 'OCSP') if ($data{'ocsp_uri'}->{val}($host) eq ""); #! TR-03116-4 4.1.1 Zertifizierungsstellen/Vertrauensanker # muss für die Verifikation von Zertifikaten einen oder mehrere Vertrauensanker vorhalten # Die Zahl der Vertrauensanker sollte so gering wie möglich gehalten werden. # FIXME: #! TR-03116-4 4.1.2 Zertifikate # müssen die folgenden Anforderungen erfüllen: # * Alle Zertifikate müssen ... # ** jederzeit aktuelle CRLs zur Verfügung stehen, oder # ** eine AuthorityInfoAccess-Extension mit OCSP # * Endnutzerzertifikate dürfen eine Gültigkeitsdauer von höchstens drei, # CA-Zertifikate von höchstens fünf Jahren haben. # * CA-Zertifikate müssen eine BasicConstraints-Extension enthalten. # * Das in der Extension enthaltene Feld pathLenConstraint muss # vorhanden sein und auf einen möglichst kleinen Wert gesetzt werden. # * Alle Zertifikate müssen eine KeyUsage-Extension enthalten. # * Zertifikate dürfen keine Wildcards CommonName des Subject oder # SubjectAltName enthalten. # Verwendung von Extended-Validation-Zertifikaten wird empfohlen $txt = _get_text('cert_valid', $data{'valid_years'}->{val}); # NOTE: 'valid_years' is special value $checks{'tr_03116+'}->{val} .= $txt if ($data{'valid_years'}->{val} > 3); # FIXME: cert itself and CA-cert have different validity: 3 vs. 5 years $txt = $checks{'wildcard'}->{val}; if (($data{'ext_crl'}->{val}($host) eq "") && ($data{'ext_authority'}->{val}($host) eq "")) { $checks{'tr_03116+'}->{val} .= _get_text('missing', 'AIA or CRL'); } # FIXME: need to verify provided CRL and OCSP $checks{'tr_03116+'}->{val} .= _get_text('wildcards', $txt) if ($txt ne ""); # _checkwildcard() checks for CN and subjectAltname only, we need Subject also $txt = $data{'subject'}->{val}($host); $checks{'tr_03116+'}->{val} .= _get_text('wildcards', "Subject:$txt") if ($txt =~ m/[*]/); # FIXME: need to check wildcards in all certificates #! TR-03116-4 4.1.3 Zertifikatsverifikation # * vollständige Prüfung der Zertifikatskette bis zu einem für die # jeweilige Anwendung vertrauenswürdigen und als authentisch # bekannten Vertrauensanker # FIXME: # * Prüfung auf Gültigkeit (Ausstellungs- und Ablaufdatum) # * Rückrufprüfung aller Zertifikate $txt = $checks{'dates'}->{val}; $checks{'tr_03116+'}->{val} .= _get_text('cert_dates', $txt) if ($txt ne ""); $txt = $checks{'expired'}->{val}; $checks{'tr_03116+'}->{val} .= _get_text('cert_valid', $txt) if ($txt ne ""); #! TR-03116-4 4.1.4 Domainparameter und Schlüssellängen # ECDSA 224 Bit; DSA 2048 Bit; RSASSA-PSS 2048 Bit; alle SHA-224 # empfohlene ECC: # * BrainpoolP224r1 3 , BrainpoolP256r1, BrainpoolP384r1, BrainpoolP512r1 # * NIST Curve P-224, NIST Curve P-256, NIST Curve P-384, NIST Curve P-521 # FIXME: #! TR-03116-4 5.2 Zufallszahlen # these checks are not possible from remote $checks{'tr_03116-'}->{val} .= $checks{'tr_03116+'}->{val}; return; } # check03116 sub check6125($$) { #? check if certificate identifiers are RFC 6125 compliant my ($host, $port) = @_; _y_CMD("check6125() " . $cfg{'done'}->{'check6125'}); $cfg{'done'}->{'check6125'}++; return if ($cfg{'done'}->{'check6125'} > 1); my $txt = ""; my $val = ""; #from: https://www.rfc-editor.org/rfc/rfc6125.txt # ... only references which are relevant for checks here # 6.4. Matching the DNS Domain Name Portion # (collection of descriptions for following rules) # 6.4.1. Checking of Traditional Domain Names # domain name labels using a case-insensitive ASCII comparison, as # clarified by [DNS-CASE] (e.g., "WWW.Example.Com" would be lower-cased # to "www.example.com" for comparison purposes). Each label MUST match # in order for the names to be considered to match, except as # supplemented by the rule about checking of wildcard labels # (Section 6.4.3). # 6.4.2. Checking of Internationalized Domain Names # 6.4.3. Checking of Wildcard Certificates # ... # 1. The client SHOULD NOT attempt to match a presented identifier in # which the wildcard character comprises a label other than the # left-most label (e.g., do not match bar.*.example.net). # 2. If the wildcard character is the only character of the left-most # label in the presented identifier, the client SHOULD NOT compare # against anything but the left-most label of the reference # identifier (e.g., *.example.com would match foo.example.com but # not bar.foo.example.com or example.com). # 3. The client MAY match a presented identifier in which the wildcard # character is not the only character of the label (e.g., # baz*.example.net and *baz.example.net and b*z.example.net would # be taken to match baz1.example.net and foobaz.example.net and # buzz.example.net, respectively). However, the client SHOULD NOT # attempt to match a presented identifier where the wildcard # character is embedded within an A-label or U-label [IDNA-DEFS] of # an internationalized domain name [IDNA-PROTO]. # 6.5.2. URI-ID # The scheme name portion of a URI-ID (e.g., "sip") MUST be matched in # a case-insensitive manner, in accordance with [URI]. Note that the # ":" character is a separator between the scheme name and the rest of # the URI, and thus does not need to be included in any comparison. # TODO: nothing # 7.2. Wildcard Certificates # o There is no specification that defines how the wildcard character # may be embedded within the A-labels or U-labels [IDNA-DEFS] of an # internationalized domain name [IDNA-PROTO]; as a result, # implementations are strongly discouraged from including or # attempting to check for the wildcard character embedded within the # A-labels or U-labels of an internationalized domain name (e.g., # "xn--kcry6tjko*.example.org"). Note, however, that a presented # domain name identifier MAY contain the wildcard character as long # as that character occupies the entire left-most label position, # where all of the remaining labels are valid NR-LDH labels, # A-labels, or U-labels (e.g., "*.xn--kcry6tjko.example.org"). # 7.3. Internationalized Domain Names # Allowing internationalized domain names can lead to the inclusion of # visually similar (so-called "confusable") characters in certificates; # for discussion, see for example [IDNA-DEFS]. # Note: wildcards itself are checked in checkcert() _checkwildcard() $txt = $data{'cn'}->{val}($host); $val .= " <<6.4.2:cn $txt>>" if ($txt !~ m!$cfg{'regex'}->{'isDNS'}!); $val .= " <<6.4.3:cn $txt>>" if ($txt =~ m!$cfg{'regex'}->{'doublewild'}!); $val .= " <<6.4.3:cn $txt>>" if ($txt =~ m!$cfg{'regex'}->{'invalidwild'}!); $val .= " <<7.2.o:cn $txt>>" if ($txt =~ m!$cfg{'regex'}->{'invalidIDN'}!); $val .= " <<7.3:cn $txt>>" if ($txt =~ m!$cfg{'regex'}->{'isIDN'}!); $txt = $data{'subject'}->{val}($host); $txt =~ s!^.*CN=!!; # just value of CN= $val .= " <<6.4.2:subject $txt>>" if ($txt !~ m!$cfg{'regex'}->{'isDNS'}!); $val .= " <<6.4.3:subject $txt>>" if ($txt =~ m!$cfg{'regex'}->{'doublewild'}!); $val .= " <<6.4.3:subject $txt>>" if ($txt =~ m!$cfg{'regex'}->{'invalidwild'}!); $val .= " <<7.2.o:subject $txt>>" if ($txt =~ m!$cfg{'regex'}->{'invalidIDN'}!); $val .= " <<7.3:subject $txt>>" if ($txt =~ m!$cfg{'regex'}->{'isIDN'}!); foreach my $txt (split(" ", $data{'altname'}->{val}($host))) { $txt =~ s!.*:!!; # strip prefix $val .= " <<6.4.2:altname $txt>>" if ($txt !~ m!$cfg{'regex'}->{'isDNS'}!); $val .= " <<6.4.3:altname $txt>>" if ($txt =~ m!$cfg{'regex'}->{'doublewild'}!); $val .= " <<6.4.3:altname $txt>>" if ($txt =~ m!$cfg{'regex'}->{'invalidwild'}!); $val .= " <<7.2.o:altname $txt>>" if ($txt =~ m!$cfg{'regex'}->{'invalidIDN'}!); $val .= " <<7.3:altname $txt>>" if ($txt =~ m!$cfg{'regex'}->{'isIDN'}!); } $checks{'rfc_6125_names'}->{val} = $val; return; } # check6125 sub check7525($$) { #? check if target is RFC 7525 compliant my ($host, $port) = @_; _y_CMD("check7525() " . $cfg{'done'}->{'check7525'}); $cfg{'done'}->{'check7525'}++; return if ($cfg{'done'}->{'check7525'} > 1); my $val = ""; # All checks according ciphers already done in checkciphers() and stored # in $checks{'rfc_7525'}. We need to do checks according certificate and # protocol and fill other %checks values according requirements. # descriptions from: https://www.rfc-editor.org/rfc/rfc7525.txt # 3.1.1. SSL/TLS Protocol Versions # Implementations MUST support TLS 1.2 [RFC5246] and MUST prefer to # negotiate TLS version 1.2 over earlier versions of TLS. # Implementations SHOULD NOT negotiate TLS version 1.1 [RFC4346]; # the only exception is when no higher version is available in the # negotiation. # TODO: for lazy check # use 'session_protocol' instead of 'sslversion' as its string matches the # RFC requirements better; SEE Note:Selected Protocol $val = " <>" if ($data{'session_protocol'}->{val}($host, $port) !~ m/TLSv1.?2/); $val .= " SSLv2" if ( $prot{'SSLv2'}->{'cnt'} > 0); $val .= " SSLv3" if ( $prot{'SSLv3'}->{'cnt'} > 0); $val .= " TLSv1" if (($prot{'TLSv11'}->{'cnt'} + $prot{'TLSv12'}->{'cnt'}) > 0); $val .= " TLSv11" if (($prot{'TLSv11'}->{'cnt'} > 0) and ($prot{'TLSv12'}->{'cnt'} > 0)); # 3.1.2. DTLS Protocol Versions # Implementations SHOULD NOT negotiate DTLS version 1.0 [RFC4347]. # Implementations MUST support and MUST prefer to negotiate DTLS # version 1.2 [RFC6347]. $val .= " DTLSv1" if ( $prot{'DTLSv1'}->{'cnt'} > 0); $val .= " DTLSv11" if ( $prot{'DTLSv11'}->{'cnt'} > 0); # TODO: we currently (5/2015) do not support DTLSv1x # 3.1.3. Fallback to Lower Versions # no checks, as already covered by 3.1.1 checks # 3.2. Strict TLS # ... TLS-protected traffic (such as STARTTLS), # clients and servers SHOULD prefer strict TLS configuration. # # HTTP client and server implementations MUST support the HTTP # Strict Transport Security (HSTS) header [RFC6797] # FIXME: what to check for STARTTLS? $val .= " DTLSv11" if ( $prot{'DTLSv11'}->{'cnt'} > 0); checkhttp($host, $port); # need http_sts $val .= _get_text('missing', 'STS') if ($checks{'hsts_sts'} eq ""); # TODO: strict TLS checks are for STARTTLS only, not necessary here # 3.3. Compression # ... implementations and deployments SHOULD # disable TLS-level compression (Section 6.2.2 of [RFC5246]), unless # the application protocol in question has been shown not to be open to # such attacks. if ($data{'compression'}->{val}($host) =~ /$cfg{'regex'}->{'nocompression'}/) { $val .= $data{'compression'}->{val}($host); } # 3.4. TLS Session Resumption # ... the resumption information MUST be authenticated and encrypted .. # A strong cipher suite MUST be used when encrypting the ticket (as # least as strong as the main TLS cipher suite). # Ticket keys MUST be changed regularly, e.g., once every week, ... # For similar reasons, session ticket validity SHOULD be limited to # a reasonable duration (e.g., half as long as ticket key validity). if ($data{'resumption'}->{val}($host) eq "") { $val .= _get_text('insecure', 'resumption'); $val .= _get_text('missing', 'session ticket') if ($data{'session_ticket'}->{val}($host) eq ""); $val .= _get_text('insecure', 'randomness of session') if ($checks{'session_random'}->{val} ne ""); } # TODO: session ticket must be random # FIXME: session ticket must be authenticated and encrypted # 3.5. TLS Renegotiation # ... both clients and servers MUST implement the renegotiation_info # extension, as defined in [RFC5746]. $val .= _get_text('missing', 'renegotiation_info extension') if ($data{'tlsextensions'}->{val}($host, $port) !~ m/renegotiation info/); $val .= _get_text('insecure', 'renegotiation') if ($data{'renegotiation'}->{val}($host) eq ""); # 3.6. Server Name Indication # TLS implementations MUST support the Server Name Indication (SNI) checksni($host, $port); # need sni $val .= "<>" if ($checks{'sni'}->{val} eq ""); # TODO: need a reliable check if SNI is supported # 4. Recommendations: Cipher Suites # 4.1. General Guidelines # Implementations MUST NOT negotiate the cipher suites with NULL encryption. # Implementations MUST NOT negotiate RC4 cipher suites. # Implementations MUST NOT negotiate cipher suites offering less # than 112 bits of security, ... # Implementations SHOULD NOT negotiate cipher suites that use # algorithms offering less than 128 bits of security. # TODO: for lazy check # Implementations SHOULD NOT negotiate cipher suites based on RSA # key transport, a.k.a. "static RSA". # Implementations MUST support and prefer to negotiate cipher suites # offering forward secrecy, ... # # 4.2. Recommended Cipher Suites # TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 # TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 # ==> done in checkcipher() with _isrfc7525 # 4.3. Public Key Length # ... DH key lengths of at least 2048 bits are RECOMMENDED. # ... Curves of less than 192 bits SHOULD NOT be used. check_dh($host, $port); # need DH Parameter if ($data{'dh_parameter'}->{val}($host) =~ m/ECDH/) { $val .= _get_text('insecure', "DH Parameter: $checks{'ecdh_256'}->{val}") if ($checks{'ecdh_256'}->{val} ne ""); } else { $val .= _get_text('insecure', "DH Parameter: $checks{'dh_2048'}->{val}") if ($checks{'dh_2048'}->{val} ne ""); # TODO: $check...{val} may already contain "<<...>>"; remove it } # TODO: use get_dh_paramter() for more reliable check # 4.5. Truncated HMAC # Implementations MUST NOT use the Truncated HMAC extension, defined in # Section 7 of [RFC6066]. $val .= _get_text('missing', 'truncated HMAC extension') if ($data{'tlsextensions'}->{val}($host, $port) =~ m/truncated.*hmac/i); #$val .= _get_text('missing', 'session ticket extension') if ($data{'tlsextensions'}->{val}($host, $port) !~ m/session.*ticket/); #$val .= _get_text('missing', 'session ticket lifetime extension') if ($data{'session_lifetime'}->{val}($host, $port) eq ""); # 6. Security Considerations # 6.1. Host Name Validation # If the host name is discovered indirectly and in an insecure manner # (e.g., by an insecure DNS query for an MX or SRV record), it SHOULD # NOT be used as a reference identifier [RFC6125] even when it matches # the presented certificate. This proviso does not apply if the host # name is discovered securely (for further discussion, see [DANE-SRV] # and [DANE-SMTP]). $val .= $text{'EV_subject_host'} if ($checks{'hostname'}->{val} ne ""); # 6.2. AES-GCM # FIXME: implement # 6.3. Forward Secrecy # ... therefore advocates strict use of forward-secrecy-only ciphers. # FIXME: implement # 6.4. Diffie-Hellman Exponent Reuse # FIXME: implement # 6.5. Certificate Revocation # ... servers SHOULD support the following as a best practice # OCSP [RFC6960] # The OCSP stapling extension defined in [RFC6961] $val .= _get_text('missing', 'OCSP') if ($checks{'ocsp_uri'}->{val} ne ""); $val .= $checks{'ocsp_valid'}->{val}; $val .= _get_text('missing', 'CRL in certificate') if ($checks{'crl'}->{val} ne ""); $val .= $checks{'crl_valid'}->{val}; # All checks for ciphers were done in _isrfc7525() and already stored in # $checks{'rfc_7525'}. Because it may be a huge list, it is appended. $checks{'rfc_7525'}->{val} = $val . " " . $checks{'rfc_7525'}->{val}; return; } # check7525 sub checkdv($$) { #? check if certificate is DV-SSL my ($host, $port) = @_; _y_CMD("checkdv() " . $cfg{'done'}->{'checkdv'}); $cfg{'done'}->{'checkdv'}++; return if ($cfg{'done'}->{'checkdv'} > 1); # DV certificates must have: # CN= value in either the subject or subjectAltName # C=, ST=, L=, OU= or O= should be either blank or contain appropriate # text such as "not valid". # TODO: match $cfg{'regex'}->{'EV-empty'} # TODO: reference missing my $cn = $data{'cn'}->{val}($host); my $subject = $data{'subject'}->{val}($host); my $altname = $data{'altname'}->{val}($host); # space-separated values my $oid = '2.5.4.3'; # /CN= or commonName my $txt = ""; # following checks work like: # for each check add descriptive failture text (from %text) # to $checks{'dv'}->{val} if check fails check_certchars($host, $port); # should already be done in checkcert() # required CN= if ($cn =~ m/^\s*$/) { $checks{'dv'}->{val} .= _get_text('missing', "Common Name"); return; # .. as all other checks will fail too now } # CN= in subject or subjectAltname, $1 is matched FQDN if (($subject !~ m#/$cfg{'regex'}->{$oid}=(?:[^/\n]*)#) and ($altname !~ m#/$cfg{'regex'}->{$oid}=(?:[^\s\n]*)#)) { $checks{'dv'}->{val} .= _get_text('missing', $data_oid{$oid}->{txt}); return; # .. as .. } ($txt = $subject) =~ s#/.*?$cfg{'regex'}->{$oid}=##; $txt = "" if not defined $txt; # defensive programming .. # TODO: %data_oid not yet used $data_oid{$oid}->{val} = $txt if ($txt !~ m/^\s*$/); $data_oid{$oid}->{val} = $cn if ($cn !~ m/^\s*$/); # there's no rule that CN's value must match the hostname, somehow .. # we check at least if subject or subjectAltname match hostname if ($txt ne $cn) { # mismatch $checks{'dv'}->{val} .= $text{'EV_subject_CN'}; } if ($txt ne $host) {# mismatch if (0 >= (grep{/^DNS:$host$/} split(/[\s]/, $altname))) { $checks{'dv'}->{val} .= $text{'EV_subject_host'}; } } return; } # checkdv sub checkev($$) { #? check if certificate is EV-SSL my ($host, $port) = @_; _y_CMD("checkev() " . $cfg{'done'}->{'checkev'}); $cfg{'done'}->{'checkev'}++; return if ($cfg{'done'}->{'checkev'} > 1); # most information must be provided in `subject' field # unfortunately the specification is a bit vague which X509 keywords # must be used, hence we use RegEx to math the keyword assigned value # # { According EV Certificate Guidelines - Version 1.0 https://www.cabforum.org/contents.html # == Required == # Organization name: subject:organizationName (OID 2.5.4.10 ) # Business Category: subject:businessCategory (OID 2.5.4.15) # Domain name: subject:commonName (OID 2.5.4.3) or SubjectAlternativeName:dNSName # This field MUST contain one of the following strings in UTF-8 # English: 'V1.0, Clause 5.(b)', 'V1.0, Clause 5.(c)' or 'V1.0, Clause 5.(d)', # depending whether the Subject qualifies under the terms of Section 5b, 5c, or # 5d of the Guidelines, respectively. # Jurisdiction of Incorporation or Registration: # Locality: subject:jurisdictionOfIncorporationLocalityName (OID 1.3.6.1.4.1.311.60.2.1.1) # State or Province:subject:jurisdictionOfIncorporationStateOrProvinceName (OID 1.3.6.1.4.1.311.60.2.1.2) # Country: subject:jurisdictionOfIncorporationCountryName (OID 1.3.6.1.4.1.311.60.2.1.3) # Registration Number: subject:serialNumber (OID 2.5.4.5) # Physical Address of Place of Business # City or town: subject:localityName (OID 2.5.4.7) # State or province: subject:stateOrProvinceName (OID 2.5.4.8) # Number & street: subject:streetAddress (OID 2.5.4.9) # # Maximum Validity Period 27 months (recommended: EV Subscriber certificate 12 months) # # == Optional == # Physical Address of Place of Business # Country: subject:countryName (OID 2.5.4.6) # Postal code: subject:postalCode (OID 2.5.4.17) # Compliance with European Union Qualified Certificates Standard In addition, # CAs MAY include a qcStatements extension per RFC 3739. The OID for # qcStatements:qcStatement:statementId is 1.3.6.1.4.1.311.60.2.1 # # } # Issuer Domain Component: issuer:domainComponent (OID 0.9.2342.19200300.100.1.25) # # See also: http://www.evsslcertificate.com my $oid = ""; my $subject = $data{'subject'}->{val}($host); my $cn = $data{'cn'}->{val}($host); my $alt = $data{'altname'}->{val}($host); my $txt = ""; my $key = ""; # following checks work like: # for each check add descriptive failture text (from %text) # to $checks{'ev+'}->{val} if check fails check_certchars($host, $port); # should already be done in checkcert() checkdv($host, $port); $checks{'ev+'}->{val} = $checks{'dv'}->{val}; # wrong for DV then wrong for EV too # required OID foreach my $oid (qw( 1.3.6.1.4.1.311.60.2.1.1 1.3.6.1.4.1.311.60.2.1.3 2.5.4.5 2.5.4.7 2.5.4.10 2.5.4.15 )) { if ($subject =~ m#/$cfg{'regex'}->{$oid}=([^/\n]*)#) { $data_oid{$oid}->{val} = $1; _v2print("EV: " . $cfg{'regex'}->{$oid} . " = $1"); } else { _v2print("EV: " . _get_text('missing', $cfg{'regex'}->{$oid}) . "; required"); $txt = _get_text('missing', $data_oid{$oid}->{txt}); $checks{'ev+'}->{val} .= $txt; $checks{'ev-'}->{val} .= $txt; } } $oid = '1.3.6.1.4.1.311.60.2.1.2'; # or /ST= if ($subject !~ m#/$cfg{'regex'}->{$oid}=(?:[^/\n]*)#) { $txt = _get_text('missing', $data_oid{$oid}->{txt}); $checks{'ev+'}->{val} .= $txt; $oid = '2.5.4.8'; # or /ST= if ($subject =~ m#/$cfg{'regex'}->{'2.5.4.8'}=([^/\n]*)#) { $data_oid{$oid}->{val} = $1; } else { $checks{'ev-'}->{val} .= $txt; _v2print("EV: " . _get_text('missing', $cfg{'regex'}->{$oid}) . "; required"); } } $oid = '2.5.4.9'; # may be missing if ($subject !~ m#/$cfg{'regex'}->{$oid}=(?:[^/\n]*)#) { $txt = _get_text('missing', $data_oid{$oid}->{txt}); $checks{'ev+'}->{val} .= $txt; _v2print("EV: " . $cfg{'regex'}->{$oid} . " = missing+"); _v2print("EV: " . _get_text('missing', $cfg{'regex'}->{$oid}) . "; required"); } # optional OID foreach my $oid (qw(2.5.4.6 2.5.4.17)) { } if (64 < length($data_oid{'2.5.4.10'}->{val})) { $txt = _get_text('EV_large', "64 < " . $data_oid{$oid}->{txt}); $checks{'ev+'}->{val} .= $txt; _v2print("EV: " . $txt); } # validity <27 months if ($data{'valid_months'}->{val} > 27) { $txt = _get_text('cert_valid', "27 < " . $data{'valid_months'}->{val}); $checks{'ev+'}->{val} .= $txt; _v2print("EV: " . $txt); } # TODO: wildcard no, SAN yes # TODO: cipher 2048 bit? # TODO: potential dangerous OID: '1.3.6.1.4.1.311.60.1.1' # TODO: Scoring: 100 EV+SGC; 80 EV; 70 EV-; 50 OV; 30 DV return; } # checkev sub checkroot($$) { #? check if certificate is root CA my ($host, $port) = @_; $cfg{'done'}->{'checkroot'}++; return if ($cfg{'done'}->{'checkroot'} > 1); # SEE Note:root-CA return; } # checkroot sub checkprot($$) { #? check anything related to SSL protocol versions my ($host, $port) = @_; my $ssl; _y_CMD("checkprot() " . $cfg{'done'}->{'checkprot'}); $cfg{'done'}->{'checkprot'}++; return if ($cfg{'done'}->{'checkprot'} > 1); # check SSL version support # NOTE: the check is adapted to the text in $%check_dest{'hassslv2'}->{txt} $checks{'hassslv2'}->{val} = " " if ($prot{'SSLv2'}->{'cnt'} > 0); $checks{'hassslv3'}->{val} = " " if ($prot{'SSLv3'}->{'cnt'} > 0); $checks{'hastls10'}->{val} = " " if ($prot{'TLSv1'}->{'cnt'} <= 0); $checks{'hastls11'}->{val} = " " if ($prot{'TLSv11'}->{'cnt'} <= 0); $checks{'hastls12'}->{val} = " " if ($prot{'TLSv12'}->{'cnt'} <= 0); $checks{'hastls13'}->{val} = " " if ($prot{'TLSv13'}->{'cnt'} <= 0); # SSLv2 and SSLv3 are special # If $cfg{$ssl}=0, the check may be disabled, i.e. with --no-sslv3 . # If the protocol is supported by the target, at least one cipher # must be accpted. So the amount of ciphers must be > 0. if ($cfg{'SSLv2'} == 0) { $checks{'hassslv2'}->{val} = _get_text('disabled', "--no-SSLv2"); $checks{'drown'}->{val} = _get_text('disabled', "--no-SSLv2"); } else { if ($prot{'SSLv2'}->{'cnt'} > 0) { $checks{'hassslv2'}->{val} = " " if ($cfg{'nullssl2'} == 1); # SSLv2 enabled, but no ciphers $checks{'drown'}->{val} = " "; # SSLv2 there, then potentially vulnerable to DROWN } } if ($cfg{'SSLv3'} == 0) { $checks{'hassslv3'}->{val} = _get_text('disabled', "--no-SSLv3"); $checks{'poodle'} ->{val} = _get_text('disabled', "--no-SSLv3"); } else { # SSLv3 enabled, check if there are ciphers # FIXME: should uses $cfg{'regex'}->{'POODLE'}, hence check in checkcipher() would be better # FIXME: TLSv1 is vulnerable too, but not TLSv11 # FIXME: OSaft/Doc/help.txt ok noe, but needs to be fixed too if ($prot{'SSLv3'}->{'cnt'} > 0) { $checks{'hassslv3'}->{val} = " "; # POODLE if SSLv3 and ciphers $checks{'poodle'} ->{val} = "SSLv3"; } } # check ALPN and NPN support checkalpn($host, $port); # my ($key, $value); $key = 'alpns'; $value = $data{$key}->{val}($host, $port); $checks{'hasalpn'}->{val} = " " if ($value eq ""); #$checks{'hasalpn'}->{val} = _get_text('disabled', "--no-alpn") if ($cfg{'usealpn'} < 1); $key = 'npns'; $value = $data{$key}->{val}($host, $port); $checks{'hasnpn'}->{val} = " " if ($value eq ""); #$checks{'hasnpn'}->{val} = _get_text('disabled', "--no-npn") if ($cfg{'usenpn'} < 1); return; } # checkprot sub checkdest($$) { #? check anything related to target and connection my ($host, $port) = @_; my $ciphers = shift; my ($key, $value, $ssl, $cipher); _y_CMD("checkdest() " . $cfg{'done'}->{'checkdest'}); $cfg{'done'}->{'checkdest'}++; return if ($cfg{'done'}->{'checkdest'} > 1); checksni($host, $port); # set checks according hostname # $cfg{'IP'} and $cfg{'rhost'} already contain $text{'disabled'} # if --proxyhost was used; hence no need to check for proxyhost again $checks{'reversehost'}->{val} = $host . " <> " . $cfg{'rhost'} if ($cfg{'rhost'} ne $host); $checks{'reversehost'}->{val} = $text{'na_dns'} if ($cfg{'usedns'} <= 0); $checks{'ip'}->{val} = $cfg{'IP'}; # SEE Note:Selected Protocol # get selected cipher and store in %checks, also check for PFS $cipher = $data{'cipher_selected'} ->{val}($host, $port); $ssl = $data{'session_protocol'}->{val}($host, $port); $ssl =~ s/[ ._-]//g; # convert TLS1.1, TLS 1.1, TLS-1_1, etc. to TLS11 my @prot = grep{/(^$ssl$)/i} @{$cfg{'versions'}}; if ($#prot == 0) { # found exactly one matching protocol $checks{'cipher_pfs'}->{val}= $cipher if ("" ne _ispfs($ssl, $cipher)); } else { _warn("631: protocol '". join(';', @prot) . "' does not match; no selected protocol available"); } # PFS is scary if the TLS session ticket is not random # we should have different tickets in %data0 and %data # it's ok if both are empty 'cause then no tickets are used $key = 'session_ticket'; $value = $data{$key}->{val}($host, $port); if (defined $data0{$key}->{val}) { # avoid Perl warning "Use uninitialized value in string" $checks{'session_random'}->{val} = $value if ($value eq $data0{$key}->{val}); } else { $checks{'session_random'}->{val} = $text{'na'}; } checkprot($host, $port); # vulnerabilities check_dh($host,$port); # Logjam vulnerability #$checks{'ccs'}->{val} = _isccs($host, $port); $checks{'ccs'}->{val} = "<>"; $checks{'crime'}->{val} = _iscrime($data{'compression'}->{val}($host), $data{'next_protocols'}->{val}($host)); foreach my $key (qw(resumption renegotiation)) { $value = $data{$key}->{val}($host); $checks{$key}->{val} = " " if ($value eq ""); } # Secure Renegotiation IS NOT supported $value = $data{'renegotiation'}->{val}($host); $checks{'renegotiation'}->{val} = $value if ($value =~ m/ IS NOT /i); $value = $data{'resumption'}->{val}($host); $checks{'resumption'}->{val} = $value if ($value !~ m/^Reused/); # check target specials foreach my $key (qw(krb5 psk_hint psk_identity srp session_ticket session_lifetime)) { # master_key session_id: see %check_dest above also $value = $data{$key}->{val}($host); $checks{$key}->{val} = " " if ($value eq ""); $checks{$key}->{val} = "None" if ($value =~ m/^\s*None\s*$/i); # if supported we have a value # TODO: see ZLIB also (seems to be wrong currently) } # time on server differs more tnan +/- 5 seconds? my $currenttime = time(); $key = 'session_starttime'; $value = $data{$key}->{val}($host); $checks{$key}->{val} = "$value < $currenttime" if ($value < ($currenttime - 5)); $checks{$key}->{val} = "$value > $currenttime" if ($value > ($currenttime + 5)); foreach my $key (qw(heartbeat)) { # these are good if there is no value $checks{$key}->{val} = $data{$key}->{val}($host); $checks{$key}->{val} = "" if ($checks{$key}->{val} =~ m/^\s*$/); } $checks{'heartbeat'}->{val} = $text{'na_tlsextdebug'} if ($cfg{'use_extdebug'} < 1); $value = $data{'ocsp_response'}->{val}($host); $checks{'ocsp_stapling'}->{val} = $value if ($value =~ /.*no\s*response.*/i); return; } # checkdest sub checkhttp($$) { #? HTTP(S) checks my ($host, $port) = @_; my $key = ""; _y_CMD("checkhttp() " . $cfg{'done'}->{'checkhttp'}); $cfg{'done'}->{'checkhttp'}++; return if ($cfg{'done'}->{'checkhttp'} > 1); # collect informations my $notxt = " "; # use a variable to make assignments below more human readable my $https_body = $data{'https_body'} ->{val}($host) || ""; my $http_sts = $data{'http_sts'} ->{val}($host) || ""; # value may be undefined, avoid Perl error my $http_location = $data{'http_location'}->{val}($host) || ""; # " my $hsts_maxage = $data{'hsts_maxage'} ->{val}($host); # 0 is valid here, hence || does not work $hsts_maxage = -1 if ($data{'hsts_maxage'}->{val}($host) =~ m/^\s*$/); my $hsts_fqdn = $http_location; $hsts_fqdn =~ s|^(?:https:)?//([^/]*)|$1|i; # get FQDN even without https: $hsts_fqdn =~ s|/.*$||; # remove trailing path if ($https_body =~ /^<{val} = $data{'http_status'}->{val}($host) if ($data{'http_status'}->{val}($host) !~ /301/); # RFC6797 requirement $checks{'hsts_is30x'}->{val} = $data{'http_status'}->{val}($host) if ($data{'http_status'}->{val}($host) =~ /30[0235678]/); # not 301 or 304 # perform checks # sequence important: first check if redirect to https, then check if empty $checks{'http_https'}->{val} = $http_location if ($http_location !~ m/^\s*https:/); $checks{'http_https'}->{val} = $notxt if ($http_location =~ m/^\s*$/); $checks{'hsts_redirect'}->{val} = $data{'https_sts'}->{val}($host) if ($http_sts ne ""); if ($data{'https_sts'}->{val}($host) ne "") { my $fqdn = $hsts_fqdn; $checks{'hsts_location'}->{val} = $data{'https_location'}->{val}($host) if ($data{'https_location'}->{val}($host) ne ""); $checks{'hsts_refresh'} ->{val} = $data{'https_refresh'} ->{val}($host) if ($data{'https_refresh'} ->{val}($host) ne ""); $checks{'hsts_ip'} ->{val} = $host if ($host =~ m/\d+\.\d+\.\d+\.\d+/); # RFC6797 requirement $checks{'hsts_fqdn'} ->{val} = $hsts_fqdn if ($http_location !~ m|^https://$host|i); $checks{'hsts_samehost'}->{val} = $hsts_fqdn if ($fqdn ne $host); $checks{'hsts_sts'} ->{val} = $notxt if ($data{'https_sts'} ->{val}($host) eq ""); $checks{'sts_subdom'} ->{val} = $notxt if ($data{'hsts_subdom'} ->{val}($host) eq ""); $checks{'sts_preload'} ->{val} = $notxt if ($data{'hsts_preload'}->{val}($host) eq ""); $checks{'sts_maxage'} ->{val} = $hsts_maxage if (($hsts_maxage > $checks{'sts_maxage1m'}->{val}) or ($hsts_maxage < 1)); $checks{'sts_maxage'} ->{val}.= " = " . int($hsts_maxage / $checks{'sts_maxage1d'}->{val}) . " days" if ($checks{'sts_maxage'}->{val} ne ""); # pretty print $checks{'sts_maxagexy'} ->{val} = ($hsts_maxage > $checks{'sts_maxagexy'}->{val}) ? "" : "< ".$checks{'sts_maxagexy'}->{val}; $checks{'sts_maxage18'} ->{val} = ($hsts_maxage > $checks{'sts_maxage18'}->{val}) ? "" : "< ".$checks{'sts_maxage18'}->{val}; $checks{'sts_maxage0d'} ->{val} = ($hsts_maxage == 0) ? "0" : ""; my $hsts_equiv = $data{'hsts_httpequiv'}->{val}($host); $checks{'hsts_httpequiv'}->{val} = $hsts_equiv if ($hsts_equiv ne ""); # RFC6797 requirement # other sts_maxage* are done below as they change {val} checkdates($host,$port); # computes check{'sts_expired'} } else { foreach my $key (qw(sts_subdom sts_maxage sts_maxage00 sts_maxagexy sts_maxage18 sts_maxage0d)) { $checks{$key}->{val} = $text{'na_STS'}; } foreach my $key (qw(hsts_location hsts_refresh hsts_fqdn hsts_samehost hsts_sts)) { $checks{$key}->{val} = $text{'na_STS'}; } } # TODO: invalid certs are not allowed for HSTS $checks{'hsts_fqdn'}->{val} = $text{'na'} if ($http_location eq ""); # useless if no redirect $checks{'pkp_pins'} ->{val} = $notxt if ($data{'https_pins'}->{val}($host) eq ""); # TODO: pins= ==> fingerprint des Zertifikats $notxt = $text{'na_STS'}; $notxt = $text{'na_http'} if ($cfg{'usehttp'} < 1); # NOTE: following sequence is important! foreach my $key (qw(sts_maxage1y sts_maxage1m sts_maxage1d)) { if ($data{'https_sts'}->{val}($host) ne "") { $checks{'sts_maxage'}->{score} = $checks{$key}->{score} if ($hsts_maxage < $checks{$key}->{val}); $checks{$key}->{val} = ($hsts_maxage < $checks{$key}->{val}) ? "" : "> ".$checks{$key}->{val}; } else { $checks{$key}->{val} = $notxt; $checks{$key}->{score} = 0; } } return; } # checkhttp sub checkssl($$) { #? SSL checks my ($host, $port) = @_; my $ciphers = shift; _y_CMD("checkssl() " . $cfg{'done'}->{'checkssl'}); $cfg{'done'}->{'checkssl'}++; return if ($cfg{'done'}->{'checkssl'} > 1); $cfg{'no_cert_txt'} = $text{'na_cert'} if ($cfg{'no_cert_txt'} eq ""); # avoid "yes" results if ($cfg{'no_cert'} == 0) { # all checks based on certificate can't be done if there was no cert, obviously checkcert( $host, $port); # SNI, wildcards and certificate checkdates($host, $port); # check certificate dates (since, until, exired) checkdv( $host, $port); # check for DV checkev( $host, $port); # check for EV check02102($host, $port); # check for BSI TR-02102-2 check03116($host, $port); # check for BSI TR-03116-4 check7525( $host, $port); # check for RFC 7525 check6125( $host, $port); # check for RFC 6125 (identifiers only) check2818( $host, $port); # check for RFC 2818 (subjectAltName only) checksni( $host, $port); # check for SNI checksizes($host, $port); # some sizes } else { $cfg{'done'}->{'checksni'}++; # avoid checking again $cfg{'done'}->{'checkdates'}++;# " $cfg{'done'}->{'checksizes'}++;# " $cfg{'done'}->{'check02102'}++;# " $cfg{'done'}->{'check03116'}++;# " $cfg{'done'}->{'check7525'}++; # " $cfg{'done'}->{'check6125'}++; # " $cfg{'done'}->{'check2818'}++; # " $cfg{'done'}->{'checkdv'}++; # " $cfg{'done'}->{'checkev'}++; # " foreach my $key (sort keys %checks) { # anything related to certs need special setting $checks{$key}->{val} = $cfg{'no_cert_txt'} if (_is_member($key, \@{$cfg{'check_cert'}})); } $checks{'hostname'} ->{val} = $cfg{'no_cert_txt'}; $checks{'tr_02102+'}->{val} = $cfg{'no_cert_txt'}; $checks{'tr_02102-'}->{val} = $cfg{'no_cert_txt'}; $checks{'tr_03116+'}->{val} = $cfg{'no_cert_txt'}; $checks{'tr_03116-'}->{val} = $cfg{'no_cert_txt'}; $checks{'rfc_6125_names'}->{val} = $cfg{'no_cert_txt'}; $checks{'rfc_2818_names'}->{val} = $cfg{'no_cert_txt'}; } if ($cfg{'usehttp'} == 1) { checkhttp( $host, $port); } else { $cfg{'done'}->{'checkhttp'}++; foreach my $key (sort keys %checks) { $checks{$key}->{val} = $text{'na_http'} if (_is_member($key, \@{$cfg{'cmd-http'}})); } } # some checks accoring ciphers and compliance are done in checkciphers() # and check02102(); some more are done in checkhttp() # now do remaining for %checks checkdest( $host, $port); # TODO: folgende Checks implementieren foreach my $key (qw(verify_hostname verify_altname verify dates fingerprint)) { # TODO: nicht sinnvoll wenn $cfg{'no_cert'} > 0 } return; } # checkssl sub check_exitcode { #? compute exitcode; returns number of failed checks or insecure settings # SEE Note:--exitcode my $exitcode = 0; # total count my $cnt_prot = 0; # number of insecure protocol versions # only TLSv12 is considered secure my $cnt_ciph = 0; # number of insecure ciphers per protocol my $cnt_ciphs = 0; # number of insecure ciphers my $cnt_pfs = 0; # number ciphers without PFS per protocol my $cnt_nopfs = 0; # number ciphers without PFS $exitcode = $checks{'cnt_checks_no'}->{val} if ($cfg{'exitcode_checks'} > 0); # TODO: $cfg{'exitcode_sizes'} _v_print("---------------------------------------------------- exitcode {"); _v_print(sprintf("%s\t%3s %3s %3s %3s %3s %s", qw(protocol H M L W no-PFS insecure))); _v_print("-------------+---+---+---+---+------+------------"); foreach my $ssl (@{$cfg{'versions'}}) { # SEE Note:%prot next if ($cfg{$ssl} == 0); # not requested, don't count # TODO: counts protocol even if no cipher was supported, is this insecure? $cnt_prot++ if ($cfg{$ssl} > 0); $cnt_pfs = $prot{$ssl}->{'cnt'} - $#{$prot{$ssl}->{'ciphers_pfs'}}; $exitcode += $cnt_pfs if ($cfg{'exitcode_pfs'} > 0); $cnt_ciph = 0; $cnt_ciph += $prot{$ssl}->{'MEDIUM'} if ($cfg{'exitcode_medium'} > 0); $cnt_ciph += $prot{$ssl}->{'WEAK'} if ($cfg{'exitcode_weak'} > 0); $cnt_ciph += $prot{$ssl}->{'LOW'} if ($cfg{'exitcode_low'} > 0); $exitcode += $cnt_ciph; _v_print(sprintf("%-7s\t%3s %3s %3s %3s %3s\t%s", $ssl, $prot{$ssl}->{'HIGH'}, $prot{$ssl}->{'MEDIUM'}, $prot{$ssl}->{'LOW'}, $prot{$ssl}->{'WEAK'}, $cnt_pfs, $cnt_ciph, )); $cnt_ciphs += $cnt_ciph; $cnt_nopfs += $cnt_pfs; } _v_print("-------------+---+---+---+---+------+------------"); $cnt_prot-- if ($cfg{'TLSv12'} > 0); $exitcode += $cnt_prot if ($cfg{'exitcode_prot'} > 0); $checks{'cnt_exitcode'}->{val} = $exitcode; _v_print(sprintf("%s\t%s", "Total number of insecure protocols", $cnt_prot)); _v_print(sprintf("%s\t%s", "Total number of insecure ciphers", $cnt_ciphs)); _v_print(sprintf("%s\t%s", "Total number of ciphers without PFS", $cnt_nopfs)); _v_print(sprintf("%s\t%s", $checks{'cnt_checks_no'}->{txt}, $checks{'cnt_checks_no'}->{val})); _v_print(sprintf("%s\t%s", $checks{'cnt_exitcode'}->{txt}, $checks{'cnt_exitcode'}->{val})); _v_print("---------------------------------------------------- exitcode }"); return $checks{'cnt_exitcode'}->{val}; } # check_exitcode sub scoring { #? compute scoring of all checks; sets values in %scores my ($host, $port) = @_; my $value; # http # some scores are set in checkhttp() my $http_location = $data{'http_location'}->{val}($host) || ""; $scores{'check_http'}->{val} = 100; $checks{'hsts_fqdn'}->{score} = 0 if ($http_location eq ""); foreach my $key (sort keys %checks) { next if ($key =~ m/^(ip|reversehost)/); # not scored next if ($key =~ m/^(sts_)/); # needs special handlicg next if ($key =~ m/^(closure|fallback|cps|krb5|lzo|open_pgp|order|pkp_pins|psk_|rootcert|srp|zlib)/); ## no critic qw(RegularExpressions::ProhibitComplexRegexes) # FIXME: not yet scored next if ($key =~ m/^TLSv1[123]/); # FIXME: $value = $checks{$key}->{val}; # TODO: go through @cipher_results # TODO foreach my $sec (qw(LOW WEAK MEDIUM HIGH -?-)) { # TODO # keys in %prot look like 'SSLv2->LOW', 'TLSv11->HIGH', etc. # TODO $key = $ssl . '-' . $sec; # TODO if ($checks{$key}->{val} != 0) { # if set, decrement score # TODO $scores{'check_ciph'}->{val} -= _getscore($key, 'egal', \%checks); # TODO printf "%20s: %4s %s\n", $key, $scores{'check_ciph'}->{val}, _getscore($key, 'egal', \%checks); # TODO } # TODO } $scores{'check_size'}->{val} -= _getscore($key, $value, \%checks) if ($checks{$key}->{typ} eq "sizes"); # $scores{'check_ciph'}->{val} -= _getscore($key, $value, \%checks) if ($checks{$key}->{typ} eq "cipher"); $scores{'check_http'}->{val} -= _getscore($key, $value, \%checks) if ($checks{$key}->{typ} eq "https"); # done above $scores{'check_cert'}->{val} -= _getscore($key, $value, \%checks) if ($checks{$key}->{typ} eq "certificate"); $scores{'check_conn'}->{val} -= _getscore($key, $value, \%checks) if ($checks{$key}->{typ} eq "connection"); $scores{'check_dest'}->{val} -= _getscore($key, $value, \%checks) if ($checks{$key}->{typ} eq "destination"); #_dbx "$key " . $checks{$key}->{val} if($checks{$key}->{typ} eq "connection"); #_dbx "score certificate $key : ".$checks{$key}->{val}." - ". $checks{$key}->{score}." = ".$scores{'check_cert'}->{val} if($checks{$key}->{typ} eq "certificate"); #_dbx "score connection $key : ".$checks{$key}->{val}." - ". $checks{$key}->{score}." = ".$scores{'check_conn'}->{val} if($checks{$key}->{typ} eq "connection"); #_dbx "score destination $key : ".$checks{$key}->{val}." - ". $checks{$key}->{score}." = ".$scores{'check_dest'}->{val} if($checks{$key}->{typ} eq "destination"); #_dbx "score http/https $key : ".$checks{$key}->{val}." - ". $checks{$key}->{score}." = ".$scores{'check_http'}->{val} if($checks{$key}->{typ} eq "https"); } return; } # scoring #| definitions: print functions #| ------------------------------------- sub _cleanup_data { # cleanup some values (strings) in data my ($key, $value) = @_; if ($key eq "https_status") { # remove non-printables from HTTP Status line # such bytes may occour if SSL connection failed #_v_print("# removing non-printable characters from $data{$key}->{txt}:"); _v_print("removing non-printable characters from $key: $value"); $value =~ s/[^[:print:]]+//g; # FIXME: not yet perfect } if ($key =~ m/X509$/) { $value =~ s#/([^=]*)#\n ($1)#g; $value =~ s#=#\t#g; } return $value; } # _cleanup_data sub _printdump { my ($label, $value) = @_; $label =~ s/\n//g; $label = sprintf("%s %s", $label, '_' x (75 -length($label))); $value = "" if not defined $value; # value parameter is optional printf("#{ %s\n\t%s\n#}\n", $label, $value); # using curly brackets 'cause they most likely are not part of any data return; } # _printdump sub printdump { #? just dumps internal database %data and %check_* my ($legacy, $host, $port) = @_; # NOT IMPLEMENTED print '######################################################################### %data'; foreach my $key (keys %data) { next if (_is_intern($key) > 0); # ignore aliases _printdump($data{$key}->{txt}, $data{$key}->{val}($host)); } print '######################################################################## %check'; foreach my $key (keys %checks) { _printdump($checks{$key}->{txt}, $checks{$key}->{val}); } return; } # printdump sub printruler { print "=" . '-'x38, "+" . '-'x35 if ($cfg{'out_header'} > 0); return; } sub printheader { #? print title line and table haeder line if second argument given my ($txt, $desc, $rest, $header) = @_; return if (0 >= $header); print $txt; return if ($desc =~ m/^ *$/); # title only if no more arguments printf("= %-37s %s\n", $text{'desc'}, $desc); printruler(); return; } # printheader sub printfooter { #? print footer line according given legacy format my $legacy = shift; if ($legacy eq 'sslyze') { print "\n\n SCAN COMPLETED IN ...\n"; } # all others are empty, no need to do anything return; } # printfooter sub printtitle { #? print title according given legacy format my ($legacy, $ssl, $host, $port, $header) = @_; local $\ = "\n"; if ($legacy eq 'sslyze') { my $txt = " SCAN RESULTS FOR " . $host . " - " . $cfg{'IP'}; print "$txt"; print " " . "-" x length($txt); } my $txt = _get_text('out_ciphers', $ssl); if ($legacy eq 'sslaudit') {} # no title if ($legacy eq 'sslcipher') { print "Testing $host ..."; } if ($legacy eq 'ssldiagnos'){ print "----------------TEST INFO---------------------------\n", "[*] Target IP: $cfg{'IP'}\n", "[*] Target Hostname: $host\n", "[*] Target port: $port\n", "----------------------------------------------------\n"; } if ($legacy eq 'sslscan') { $host =~ s/;/ on port /; print "Testing SSL server $host\n"; } if ($legacy eq 'ssltest') { print "Checking for Supported $ssl Ciphers on $host..."; } if ($legacy eq 'ssltest-g') { print "Checking for Supported $ssl Ciphers on $host..."; } if ($legacy eq 'testsslserver') { print "Supported cipher suites (ORDER IS NOT SIGNIFICANT):\n " . $ssl; } if ($legacy eq 'thcsslcheck'){print "\n[*] now testing $ssl\n" . "-" x 76; } if ($legacy eq 'compact') { print "=== Checking $ssl Ciphers ..."; } if ($legacy eq 'quick') { printheader($txt, "", "", $header); } if ($legacy eq 'owasp') { printheader($txt, "", "", $header); } if ($legacy eq 'simple') { printheader($txt, "", "", $header); } if ($legacy eq 'full') { printheader($txt, "", "", $header); } return; } # printtitle sub print_line($$$$$$) { #? print label and value separated by separator #? print hostname and key depending on --showhost and --trace-key option my ($legacy, $host, $port, $key, $text, $value) = @_; $text = STR_NOTXT if not defined $text; # defensive programming .. $value = STR_UNDEF if not defined $value; # .. missing variable declaration # general format of a line is: # host:port:#[key]:label: \tvalue # legacy=_cipher is special: does not print label and value my $label = ""; $label = sprintf("%s:%s%s", $host, $port, $text{'separator'}) if ($cfg{'showhost'} > 0); if ($legacy eq '_cipher') { printf("%s#[%s]%s", $label, $key, $text{'separator'}) if ($cfg{'traceKEY'} > 0); return; } $label .= sprintf("#[%-18s", $key . ']' . $text{'separator'}) if ($cfg{'traceKEY'} > 0); if ($legacy =~ m/(compact|full|quick)/) { $label .= sprintf("%s", $text . $text{'separator'}); } else { if ($cfg{'label'} eq 'key') { $label .= sprintf("[%s]", $key); } else { $label .= sprintf("%-36s", $text . $text{'separator'}); } } # formats full, quick and compact differ in separator my $sep = "\t"; $sep = "\n\t" if ($legacy eq 'full'); $sep = "" if ($legacy =~ m/(compact|quick)/); printf("%s%s%s\n", $label, $sep, $value); return; } # print_line sub print_data($$$$) { # print given label and text from %data according given legacy format my ($legacy, $host, $port, $key) = @_; if (_is_hashkey($key, \%data) < 1) { # silently ignore unknown labels _warn("801: unknown label '$key'; output ignored"); # seems to be a programming error return; } my $label = ($data{$key}->{txt} || ""); # defensive programming .. my $value = $data{$key}->{val}($host, $port) || ""; $value = _cleanup_data($key, $value); if ($key =~ m/X509$/) { # always pretty print $key =~ s/X509$//; # $value done in _cleanup_data() print_line($legacy, $host, $port, $key, $data{$key}->{txt}, $value); return; } if ((1 == _is_hexdata($key)) && ($value !~ m/^\s*$/)) { # check for empty $value to avoid warnings with -w # pubkey_value may look like: # Subject Public Key Info:Public Key Algorithm: rsaEncryptionPublic-Key: (2048 bit)Modulus=00c11b:... # where we want to convert the key value only but not its prefix # hence the final : is converted to = # (seems to happen on Windows only; reason yet unknown) $value =~ s/([Mm]odulus):/$1=/; # my ($k, $v) = split(/=/, $value); if (defined $v) { # i.e SHA Fingerprint= $k .= "="; } else { $v = $k; $k = ""; } if ($cfg{'format'} eq "hex") { $v =~ s#(..)#$1:#g; $v =~ s#:$##; } if ($cfg{'format'} eq "esc") { $v =~ s#(..)#\\x$1#g; } if ($cfg{'format'} eq "0x") { $v =~ s#(..)#0x$1 #g; $v =~ s# $##; } $value = $k . $v; } $value = "\n" . $value if (_is_member($key, \@{$cfg{'cmd-NL'}}) > 0); # multiline data if ($legacy eq 'compact') { $value =~ s#:\n\s+#:#g; # join lines ending with : $value =~ s#\n\s+# #g; # squeeze leading white spaces $value =~ s#[\n\r]#; #g;# join all lines $label =~ s#[\n]##g; } if ($legacy eq 'full') { # do some pretty printing if ($label =~ m/(^altname)/) { $value =~ s#^ ##; $value =~ s# #\n\t#g; } if ($label =~ m/(subject)/) { $value =~ s#/#\n\t#g; $value =~ s#^\n\t##m; } if ($label =~ m/(issuer)/) { $value =~ s#/#\n\t#g; $value =~ s#^\n\t##m; } if ($label =~ m/(serial|modulus|sigkey_value)/) { $value =~ s#(..)#$1:#g; $value =~ s#:$##; } if ($label =~ m/((?:pubkey|sigkey)_algorithm|signame)/) { $value =~ s#(with)# $1 #ig; $value =~ s#(encryption)# $1 #ig; } } print_line($legacy, $host, $port, $key, $label, $value); printhint($key) if ($cfg{'out_hint_info'} > 0); return; } # print_data sub print_check($$$$$) { #? print label and result of check my ($legacy, $host, $port, $key, $value) = @_; $value = $checks{$key}->{val} if not defined $value; # defensive programming .. my $label = ""; $label = $checks{$key}->{txt} if ($cfg{'label'} ne 'key'); # TODO: $cfg{'label'} should be parameter print_line($legacy, $host, $port, $key, $label, $value); printhint($key) if ($cfg{'out_hint_check'} > 0); return; } # print_check sub print_size($$$$) { #? print label and result for length, count, size, ... my ($legacy, $host, $port, $key) = @_; my $value = ""; $value = " bytes" if ($key =~ /^(len)/); $value = " bits" if ($key =~ /^len_(modulus|publickey|sigdump)/); print_check($legacy, $host, $port, $key, $checks{$key}->{val} . $value); return; } # print_size sub print_cipherruler_dh{ print "= " . "-"x35 . "+-------------------------" if ($cfg{'out_header'} > 0); return; } sub print_cipherruler { print "= " . "-"x35 . "+-------+-------" if ($cfg{'out_header'} > 0); return; } #? print header ruler line sub print_cipherhead($) { #? print header line according given legacy format my $legacy = shift; return if ($cfg{'out_header'} <= 0); if ($legacy eq 'sslscan') { print "\n Supported Server Cipher(s):"; } if ($legacy eq 'ssltest') { printf(" %s, %s (%s)\n", 'Cipher', 'Enc, bits, Auth, MAC, Keyx', 'supported'); } if ($legacy eq 'ssltest-g') { printf("%s;%s;%s;%s\n", 'compliant', 'host:port', 'protocol', 'cipher', 'description'); } if ($legacy eq 'simple') { printf("= %-34s%s\t%s\n", $text{'cipher'}, $text{'support'}, $text{'security'}); print_cipherruler(); } if ($legacy eq 'owasp') { printf("= %-34s\t%s\n", $text{'cipher'}, $text{'security'}); print_cipherruler(); } # TODO: ruler is same as for legacy=simple if ($legacy eq 'cipher_dh') { printf("= %-34s\t%s\n", $text{'cipher'}, $text{'dh_param'}); print_cipherruler_dh(); } if ($legacy eq 'full') { # host:port protocol supported cipher compliant security description printf("= %s\t%s\t%s\t%s\t%s\t%s\t%s\n", 'host:port', 'Prot.', 'supp.', $text{'cipher'}, 'compliant', $text{'security'}, $text{'desc'}); } # all others are empty, no need to do anything return; } # print_cipherhead sub print_cipherline($$$$$$) { #? print cipher check result according given legacy format my ($legacy, $ssl, $host, $port, $cipher, $support) = @_; # variables for better (human) readability my $bit = get_cipher_bits($cipher); my $sec = get_cipher_sec($cipher); $sec = get_cipher_owasp($cipher) if ('owasp' eq $legacy); my $desc = join(" ", get_cipher_desc($cipher)); my $yesno = $text{'legacy'}->{$legacy}->{$support}; # first our own formats my $value = ""; if ($legacy eq 'full') { # host:port protocol supported cipher compliant security description $desc = join("\t", get_cipher_desc($cipher)); $desc =~ s/\s*:\s*$//; } if ($legacy =~ m/compact|full|owasp|quick|simple|key/) { my $k = sprintf("%s", get_cipher_hex($cipher)); print_line('_cipher', $host, $port, $k, $cipher, ""); # just host:port:#[key]: if ('key' eq $cfg{'label'}) { # TODO: $cfg{'label'} should be a parameter $k = "[$k]\t"; } else { $k = " "; } printf("%s%-28s\t%s\t%s\n", $k, $cipher, $yesno, $sec) if ($legacy eq 'full'); printf("%s%-28s\t%s\n", $k, $cipher, $sec ) if ($legacy eq 'owasp'); printf("%s%-28s\t(%s)\t%s\n", $k, $cipher, $bit, $sec) if ($legacy eq 'quick'); printf("%s%-28s\t%s\t%s\n", $k, $cipher, $yesno, $sec) if ($legacy eq 'simple'); printf("%s %s %s\n", $cipher, $yesno, $sec) if ($legacy eq 'compact'); printf("%s\t%s\t%s\t%s\t%s\t%s\n", $ssl, $yesno, $cipher, '-?-', $sec, $desc) if ($legacy eq 'full'); return; } # now legacy formats # TODO: should be moved to postprocessor if ($legacy eq 'sslyze') { if ($support eq 'yes') { $support = sprintf("%4s bits", $bit) if ($support eq 'yes'); } else { $support = $yesno; } printf("\t%-24s\t%s\n", $cipher, $support); } if ($legacy eq 'sslaudit') { # SSLv2 - DES-CBC-SHA - unsuccessfull # SSLv3 - DES-CBC3-SHA - successfull - 80 printf("%s - %s - %s\n", $ssl, $cipher, $yesno); } if ($legacy eq 'sslcipher') { # TLSv1:EDH-RSA-DES-CBC3-SHA - ENABLED - STRONG 168 bits # SSLv3:DHE-RSA-AES128-SHA - DISABLED - STRONG 128 bits $sec = 'INTERMEDIATE:' if ($sec =~ /LOW/i); $sec = 'STRONG' if ($sec =~ /high/i); $sec = 'WEAK' if ($sec =~ /weak/i); printf(" %s:%s - %s - %s %s bits\n", $ssl, $cipher, $yesno, $sec, $bit); } if ($legacy eq 'ssldiagnos') { # [+] Testing WEAK: SSL 2, DES-CBC3-MD5 (168 bits) ... FAILED # [+] Testing STRONG: SSL 3, AES256-SHA (256 bits) ... CONNECT_OK CERT_OK $sec = ($sec =~ /high/i) ? 'STRONG' : 'WEAK'; printf("[+] Testing %s: %s, %s (%s bits) ... %s\n", $sec, $ssl, $cipher, $bit, $yesno); } if ($legacy eq 'sslscan') { # Rejected SSLv3 256 bits ADH-AES256-SHA # Accepted SSLv3 128 bits AES128-SHA $bit = sprintf("%3s bits", $bit); printf(" %s %s %s\n", $ssl, $bit, $cipher); } if ($legacy eq 'ssltest') { # cipher, description, (supported) my @arr = @{$ciphers{$cipher}}; pop(@arr); # remove last value: tags pop(@arr); # remove last value: score shift @arr; # remove 1'st value: security shift @arr; # remove 2'nd value: ssl $arr[1] .= ' bits'; $arr[2] .= ' MAC'; $arr[3] .= ' Auth'; $arr[4] .= ' Kx'; my $tmp = $arr[2]; $arr[2] = $arr[3]; $arr[3] = $tmp; printf(" %s, %s (%s)\n", $cipher, join (", ", @arr), $yesno); } if ($legacy eq 'thcsslcheck') { # AES256-SHA - 256 Bits - supported printf("%30s - %3s Bits - %11s\n", $cipher, $bit, $yesno); } # compliant;host:port;protocol;cipher;description if ($legacy eq 'ssltest-g') { printf("%s;%s;%s;%s\n", 'C', $host . ":" . $port, $sec, $cipher, $desc); } # 'C' needs to be checked first if ($legacy eq 'testsslserver') { printf(" %s\n", $cipher); } return; } # print_cipherline sub print_cipherprefered($$$$) { #? print prefered cipher according given legacy format my ($legacy, $ssl, $host, $port) = @_; my $yesno = 'yes'; if ($legacy eq 'sslyze') { print "\n\n Preferred Cipher Suites:"; } if ($legacy eq 'sslaudit') {} # TODO: cipher name should be DEFAULT if ($legacy eq 'sslscan') { print "\n Preferred Server Cipher(s):"; $yesno = "";} # all others are empty, no need to do anything print_cipherline($legacy, $ssl, $host, $port, $data{'cipher_selected'}->{val}($host), $yesno); return; } # print_cipherprefered sub print_ciphertotals($$$$) { #? print total number of ciphers supported for SSL version according given legacy format my ($legacy, $ssl, $host, $port) = @_; if ($legacy eq 'ssldiagnos') { print "\n-= SUMMARY =-\n"; printf("Weak: %s\n", $prot{$ssl}->{'WEAK'}); printf("Intermediate: %s\n", $prot{$ssl}->{'MEDIUM'}); # MEDIUM printf("Strong: %s\n", $prot{$ssl}->{'HIGH'}); # HIGH } if ($legacy =~ /(full|compact|simple|owasp|quick)/) { printheader(_get_text('out_summary', $ssl), "", $cfg{'out_header'}); _trace_cmd('%checks'); foreach my $key (qw(LOW WEAK MEDIUM HIGH -?-)) { print_line($legacy, $host, $port, "$ssl-$key", $prot_txt{$key}, $prot{$ssl}->{$key}); # NOTE: "$ssl-$key" does not exist in %checks or %prot } } return; } # print_ciphertotals sub _is_print { #? return 1 if parameter indicate printing my $enabled = shift; my $print_disabled = shift; my $print_enabled = shift; return 1 if ($print_disabled == $print_enabled); return 1 if ($print_disabled && ($enabled eq 'no' )); return 1 if ($print_enabled && ($enabled eq 'yes')); return 0; } # _is_print sub _sort_results { #? sort @results array according security of ciphers, most secure first my @unsorted= @_; # each line is array: ssl, cipher, yes-or-no my @results; my @tmp_arr; foreach my $line (@unsorted) { my $cipher = ${$line}[1]; my $sec_osaft = lc(get_cipher_sec($cipher));# lower case my $sec_owasp = get_cipher_owasp($cipher); $sec_owasp = "N/A" if ('-?-' eq $sec_owasp); # sort at end # Idea about sorting according severity/security risk of a cipher: # * sort first according OWASP rating A, B, C # then use a weight for each cipher: # * most secure cipher first # * prefer ECDHE over DHE over ECDH # * prefer SHA384 over /SHA256 over SHA # * prefer CHACHA over AES # * prefer AES265 over AES128 # * sort any anon (ADH, DHA, ..) and EXPort at end # * NULL is last # then use OpenSSL/O-Saft rating, hence the string to be sorted looks # like: # # A 20 high ... # # A 23 high ... # # B 33 high ... # # B 37 medium ... # One line in incomming array in @unsorted: # # TLSv12, ECDHE-RSA-AES128-GCM-SHA256, yes # will be converted to following line: # # A 20 HIGH ECDHE-RSA-AES128-GCM-SHA256 TLSv12 yes my $weight = 50; # default if nothing below matches $weight = 19 if ($cipher =~ /^ECDHE/i); $weight = 29 if ($cipher =~ /^(?:DHE|EDH)/i); $weight = 39 if ($cipher =~ /^ECDH[_-]/i); $weight = 59 if ($cipher =~ /^(?:DES|RC)/i); $weight = 69 if ($cipher =~ /^EXP/i); $weight = 89 if ($cipher =~ /^A/i); # NOTE: must be before ^AEC $weight = 79 if ($cipher =~ /^AEC/i); # NOTE: must be after ^A $weight = 99 if ($cipher =~ /^NULL/i); $weight -= 5 if ($cipher =~ /SHA512$/); $weight -= 4 if ($cipher =~ /SHA384$/); $weight -= 3 if ($cipher =~ /SHA256$/); $weight -= 3 if ($cipher =~ /SHA128$/); $weight -= 2 if ($cipher =~ /256.SHA$/); $weight -= 1 if ($cipher =~ /128.SHA$/); $weight -= 3 if ($cipher =~ /CHACHA/); $weight -= 2 if ($cipher =~ /256.GCM/); $weight -= 1 if ($cipher =~ /128.GCM/); # TODO: need to "rate" -CBC- and -RC4- and -DSS- #push(@tmp_arr, ["$sec_owasp $sec_osaft", $cipher, ${$line}[0], ${$line}[2]]); push(@tmp_arr, "$sec_owasp $weight $sec_osaft $cipher ${$line}[0] ${$line}[2]"); } foreach my $line (sort @tmp_arr) { #_dbx $line; my @arr = split(" ", $line); push(@results, [$arr[4], $arr[3], $arr[5]]);# convert back to original result } return @results; } # _sort_results # NOTE: Perl::Critic's violation for next 2 subs are false positives sub _print_results($$$$$@) { ## no critic qw(Subroutines::RequireArgUnpacking) #? print all ciphers from @results if match $ssl and $yesno; returns number of checked ciphers for $ssl my $legacy = shift; my $ssl = shift; my $host = shift; my $port = shift; my $yesno = shift; # only print these results, all if empty my @results = @_; my $print = 0; # default: do not print my $total = 0; local $\ = "\n"; foreach my $c (@results) { next if (${$c}[0] ne $ssl); $total++; next if ((${$c}[2] ne $yesno) and ($yesno ne "")); $print = _is_print(${$c}[2], $cfg{'disabled'}, $cfg{'enabled'}); print_cipherline($legacy, $ssl, $host, $port, ${$c}[1], ${$c}[2]) if ($print == 1); } return $total; } # _print_results sub printcipherall { ## no critic qw(Subroutines::RequireArgUnpacking) #? print all cipher check results from Net::SSLhello::checkSSLciphers() #? returns number of unique (enabled) ciphers # FIXME: $legacy, --enabled and --disabled not fully supported my $legacy = shift; my $ssl = shift; my $host = shift; my $port = shift; my $outtitle= shift; # print title line if 0 my @results = @_; # contains only accepted ciphers my $unique = 0; # count unique ciphers my $last_r = ""; # avoid duplicates local $\ = "\n"; print_cipherhead( $legacy) if ($outtitle == 0); foreach my $key (@results) { next if ($last_r eq $key); my $cipher = get_cipher_suitename($key); print_cipherline($legacy, $ssl, $host, $port, $cipher, "yes"); $last_r = $key; $unique++; } print_cipherruler() if ($legacy eq 'simple'); printfooter($legacy); return $unique; } # printcipherall sub printciphercheck($$$$$@) { ## no critic qw(Subroutines::RequireArgUnpacking) #? print all cipher check results for given $ssl according given legacy format my $legacy = shift; my $ssl = shift; my $host = shift; my $port = shift; my $count = shift; # print title line if 0 my @results = @_; my $total = 0; local $\ = "\n"; print_cipherhead( $legacy) if ($count == 0); print_cipherprefered($legacy, $ssl, $host, $port) if ($legacy eq 'sslaudit'); @results = _sort_results(@results); # sorting has no impact on severity if ($legacy ne 'sslyze') { $total = _print_results($legacy, $ssl, $host, $port, "", @results); # NOTE: $checks{'cnt_totals'}->{val} is the number of all checked # ciphers for all protocols, here only the number of ciphers # for the protocol $ssl should be printed print_cipherruler() if ($legacy =~ /(?:owasp|simple)/); print_check($legacy, $host, $port, 'cnt_totals', $total) if ($cfg{'verbose'} > 0); } else { print "\n * $ssl Cipher Suites :"; print_cipherprefered($legacy, $ssl, $host, $port); if (($cfg{'enabled'} == 1) or ($cfg{'disabled'} == $cfg{'enabled'})) { print "\n Accepted Cipher Suites:"; $total = _print_results($legacy, $ssl, $host, $port, "yes", @results); } if (($cfg{'disabled'} == 1) or ($cfg{'disabled'} == $cfg{'enabled'})) { print "\n Rejected Cipher Suites:"; $total = _print_results($legacy, $ssl, $host, $port, "no", @results); } } #print_ciphertotals($legacy, $ssl, $host, $port); # up to version 15.10.15 printfooter($legacy); return; } # printciphercheck sub printciphers_dh($$$) { #? print ciphers and DH parameter from target (available with openssl only) # currently DH parameters requires openssl, check must be done in caller my ($legacy, $host, $port) = @_; my $openssl_version = get_openssl_version($cmd{'openssl'}); _trace1("printciphers_dh: openssl_version: $openssl_version"); if ($openssl_version lt "1.0.2") { # yes Perl can do this check # TODO: move this check to _check_openssl() _warn("811: ancient openssl $openssl_version: using '-msg' option to get DH parameters"); $cfg{'openssl_msg'} = '-msg' if (1 == $cfg{'openssl'}->{'-msg'}[0]); require Net::SSLhello; # to parse output of '-msg'; ok here, as Perl handles multiple includes proper # SEE Note:Stand-alone } foreach my $ssl (@{$cfg{'version'}}) { printtitle($legacy, $ssl, $host, $port, $cfg{'out_header'}); print_cipherhead( 'cipher_dh'); foreach my $c (@{$cfg{'ciphers'}}) { #next if ($c !~ /$cfg{'regex'}->{'EC'}/); my ($version, $supported, $dh) = _useopenssl($ssl, $host, $port, $c); next if ($supported =~ /^\s*$/); # TODO: use print_cipherline(); # TODO: perform check like check_dh() printf(" %-28s\t%s\n", $c, $dh); } # TODO: { # ------- # cipher dhe oder edh, ecdh dann muss server temp key da sein # sonst kommt kein temp key z.B RSA oder camellia # # wenn dh kommen muesste aber fehlt, dann bei openssl -msg probieren # ------- # rfc4492 wenn im cert ec oder ecdsa steht (extension) dann duerfen nur solche # akzeptiert werden; wenn nix im cert steht dann durfen nur rsa akzeptiert werden # siehe rfc4492 Table 3 # ------- # cipherPcurve ...P256 # TODO: } print_cipherruler_dh(); } return; } # printciphers_dh sub printcipherprefered { #? print table with prefered/selected (default) cipher per protocol my ($legacy, $host, $port) = @_; local $\ = "\n"; if ($cfg{'out_header'}>0) { printf("= prot.\t%-31s%s\n", "prefered cipher (strong first)", "prefered cipher (weak first)"); printf("=------+------------------------------+-------------------------------\n"); } foreach my $ssl (@{$cfg{'versions'}}) { # SEE Note:%prot next if (($cfg{$ssl} == 0) and ($verbose <= 0)); # not requested with verbose only next if ($ssl =~ m/^SSLv2/); # SSLv2 has no server selected cipher my $key = $ssl . $text{'separator'}; $key = sprintf("[0x%x]", $prot{$ssl}->{hex}) if ($legacy eq 'key'); printf("%-7s\t%-31s\t%s\n", $key, $prot{$ssl}->{'cipher_strong'}, $prot{$ssl}->{'cipher_weak'}, ); } if ($cfg{'out_header'}>0) { printf("=------+------------------------------+-------------------------------\n"); } print_data($legacy, $host, $port, 'cipher_selected'); # SEE Note:Selected Cipher return; } # printcipherprefered sub printprotocols { #? print table with cipher informations per protocol # number of found ciphers, various risks ciphers, default and PFS cipher # prints information stored in %prot my ($legacy, $host, $port) = @_; local $\ = "\n"; if ($cfg{'out_header'}>0) { if ('owasp' eq $legacy) { printf("# A, B, C OWASP rating; D=broken tot=enabled ciphers PFS=enabled cipher with PFS\n"); printf("%s\t%3s %3s %3s %3s %3s %3s %-31s %s\n", "=", qw(A B C D PFS tot prefered-strong-cipher PFS-cipher)); } else { printf("# H=HIGH M=MEDIUM L=LOW W=WEAK tot=enabled ciphers PFS=enabled cipher with PFS\n"); printf("%s\t%3s %3s %3s %3s %3s %3s %-31s %s\n", "=", qw(H M L W PFS tot prefered-strong-cipher PFS-cipher)); } printf("=------%s%s\n", ('+---' x 6), '+-------------------------------+---------------'); } # 'PROT-LOW' => {'txt' => "Supported ciphers with security LOW"}, foreach my $ssl (@{$cfg{'versions'}}) { # SEE Note:%prot next if (($cfg{$ssl} == 0) and ($verbose <= 0)); # not requested with verbose only next if ($ssl =~ m/^SSLv2/); # SSLv2 has no server selected cipher my $cnt = ($#{$prot{$ssl}->{'ciphers_pfs'}} + 1); my $key = $ssl . $text{'separator'}; $key = sprintf("[0x%x]", $prot{$ssl}->{hex}) if ($legacy eq 'key'); my $cipher_strong = $prot{$ssl}->{'cipher_strong'}; my $cipher_pfs = $prot{$ssl}->{'cipher_pfs'}; if ($cfg{'trace'} <= 0) { # avoid internal strings, pretty print for humans $cipher_strong = "" if (STR_UNDEF eq $cipher_strong); $cipher_pfs = "" if (STR_UNDEF eq $cipher_pfs); } if ((@{$prot{$ssl}->{'ciphers_pfs'}}) and (${$prot{$ssl}->{'ciphers_pfs'}}[0] =~ m/^\s*<{'ciphers_pfs'}}[0]; $cnt = 0; } print_line('_cipher', $host, $port, $ssl, $ssl, ""); # just host:port:#[key]: if ('owasp' eq $legacy) { printf("%-7s\t%3s %3s %3s %3s %3s %3s %-31s %s\n", $key, $prot{$ssl}->{'OWASP_A'}, $prot{$ssl}->{'OWASP_B'}, $prot{$ssl}->{'OWASP_C'}, $prot{$ssl}->{'OWASP_D'}, $cnt, $prot{$ssl}->{'cnt'}, $cipher_strong, $cipher_pfs ); } else { printf("%-7s\t%3s %3s %3s %3s %3s %3s %-31s %s\n", $key, $prot{$ssl}->{'HIGH'}, $prot{$ssl}->{'MEDIUM'}, $prot{$ssl}->{'LOW'}, $prot{$ssl}->{'WEAK'}, $cnt, $prot{$ssl}->{'cnt'}, $cipher_strong, $cipher_pfs ); } # not yet printed: $prot{$ssl}->{'cipher_weak'}, $prot{$ssl}->{'default'} } if ($cfg{'out_header'}>0) { printf("=------%s%s\n", ('+---' x 6), '+-------------------------------+---------------'); } return; } # printprotocols sub printciphersummary { #? print summary of cipher check (+cipher, +cipherall, +cipherraw) my ($legacy, $host, $port, $total) = @_; if ($legacy =~ /(full|compact|simple|owasp|quick)/) { # but only our formats printheader("\n" . _get_text('out_summary', ""), "", "", $cfg{'out_header'}); print_check( $legacy, $host, $port, 'cnt_totals', $total) if ($cfg{'verbose'} > 0); printprotocols($legacy, $host, $port); } my $key = $data{'cipher_selected'}->{val}($host, $port); print_line($legacy, $host, $port, 'cipher_selected', $data{'cipher_selected'}->{txt}, "$key " . get_cipher_sec($key)); # print_data($legacy, $host, $port, 'cipher_selected'); _hint("consider testing with options '--cipheralpn=, --ciphernpn=,' also") if ($cfg{'verbose'} > 0); return; } # printciphersummary sub printdata($$$) { #? print information stored in %data my ($legacy, $host, $port) = @_; local $\ = "\n"; printheader($text{'out_infos'}, $text{'desc_info'}, "", $cfg{'out_header'}); _trace_cmd('%data'); if (_is_do('cipher_selected')) { # value is special my $key = $data{'cipher_selected'}->{val}($host, $port); print_line($legacy, $host, $port, 'cipher_selected', $data{'cipher_selected'}->{txt}, "$key " . get_cipher_sec($key)); } foreach my $key (@{$cfg{'do'}}) { next if (_is_member( $key, \@{$cfg{'commands-NOTYET'}}) > 0); next if (_is_member( $key, \@{$cfg{'ignore-out'}}) > 0); next if (_is_hashkey($key, \%data) < 1); next if ($key eq 'cipher_selected');# value is special, done above if ($cfg{'experimental'} == 0) { next if (_is_member( $key, \@{$cfg{'commands-EXP'}}) > 0); } # special handling vor +info--v if (_is_do('info--v') > 0) { next if ($key eq 'info--v'); next if ($key =~ m/$cfg{'regex'}->{'commands-INT'}/i); } else { next if (_is_intern( $key) > 0); } _y_CMD("(%data) +" . $key); my $value = $data{$key}->{val}($host); if (_is_member( $key, \@{$cfg{'cmd-NL'}}) > 0) { # for +info print multiline data only if --v given # if command given explizitely, i.e. +text, print if ((_is_do('info') > 0) and (0 >= $cfg{'verbose'})) { _hint("multiline data '+$key' for '+info' printed with --v only"); next; } } if ($cfg{'format'} eq "raw") { # should be the only place where format=raw counts print $value; } else { print_data($legacy, $host, $port, $key); } } return; } # printdata sub printchecks($$$) { #? print results stored in %checks my ($legacy, $host, $port) = @_; my $value = ""; local $\ = "\n"; printheader($text{'out_checks'}, $text{'desc_check'}, "", $cfg{'out_header'}); _trace_cmd(' printchecks: %checks'); _warn("821: can't print certificate sizes without a certificate (--no-cert)") if ($cfg{'no_cert'} > 0); foreach my $key (@{$cfg{'do'}}) { _trace("printchecks: (%checks) ?" . $key); next if (_is_member( $key, \@{$cfg{'commands-NOTYET'}}) > 0); next if (_is_member( $key, \@{$cfg{'ignore-out'}}) > 0); next if (_is_hashkey($key, \%checks) < 1); next if (_is_intern( $key) > 0); # ignore aliases next if ($key =~ m/$cfg{'regex'}->{'SSLprot'}/); # these counters are already printed if ($cfg{'experimental'} == 0) { next if (_is_member( $key, \@{$cfg{'commands-EXP'}}) > 0); } $value = _setvalue($checks{$key}->{val}); _y_CMD("(%checks) +" . $key); if ($key =~ /$cfg{'regex'}->{'cmd-sizes'}/) { # sizes are special print_size($legacy, $host, $port, $key) if ($cfg{'no_cert'} <= 0); } else { # increment counter only here, avoids counting the counter itself $checks{'cnt_checks_yes'}->{val}++ if ($value eq "yes"); $checks{'cnt_checks_no'} ->{val}++ if ($value =~ /^no/); print_check($legacy, $host, $port, $key, $value); } } return; } # printchecks #| definitions: print functions for help and information #| ------------------------------------- sub printquit { #? print internal data # call this function with: # $0 `\ # gawk '/--(help|trace-sub)/{next}/--h$/{next}/\+traceSUB/{next}($2~/^-/){$1="";print}' o-saft-man.pm\ # |tr ' ' '\012' \ # |sort -u \ # |egrep '^(--|\+)' \ # |egrep -v '^--[v-]-' \ # |egrep -v '--user-*' \ # |egrep -v 'cipher=*' \ # ` \ # +quit --trace-key # # NOTE: This extracts all options, but does not use all variants these # options can be written. So just a rough test ... # # NOTE: Some commands may have invalid arguments (i.e. --sep=CHAR ) or # the commands may be unknown. This results in **WARNING texts # for the correspoding commands. if ($cfg{'trace'} + $cfg{'traceARG'} + $cfg{'verbose'} <= 0) { _warn("831: +quit command should be used with --trace=arg option"); } $cfg{'verbose'} = 2 if ($cfg{'verbose'} < 2); # dirty hack $cfg{'trace'} = 2 if ($cfg{'trace'} < 2); # -"- $cfg{'traceARG'}= 1; # for _yeast_args() print("\n# +quit using: --verbode=2 --trace=2 --traceARG"); _v_print("\n# +quit : some information may appear multiple times\n#"); _yeast_init(); # _yeast_args(); # duplicate call, see in main at "set environment" print "# TEST done."; return; } # printquit sub __SSLeay { #? internal wrapper for Net::SSLeay::SSLeay() if (1.49 > $Net::SSLeay::VERSION) { my $txt = "ancient version Net::SSLeay $Net::SSLeay::VERSION < 1.49;"; $txt .= " cannot compare SSLeay with openssl version"; warn STR_WARN, "080: $txt"; # not _warn(), SEE Perl:warn return "$Net::SSLeay::VERSION"; } else { return Net::SSLeay::SSLeay(); } } # __SSLeay sub printversionmismatch { #? check if openssl and compiled SSLeay are of same version my $o = Net::SSLeay::OPENSSL_VERSION_NUMBER(); my $s = __SSLeay(); if ($o ne $s) { _warn("841: used openssl version '$o' differs from compiled Net:SSLeay '$s'; ignored"); } return; } # printversionmismatch ## no critic qw(Subroutines::ProhibitExcessComplexity) # NOTE: yes, it is high complexity, but that's the nature of printing all information sub printversion { #? print program and module versions local $\ = "\n"; if ($cfg{'verbose'} > 0) { print "# perl $^V"; print '# @INC = ' . join(" ", @INC) . "\n"; } print( "=== started in: $ENV{PWD} ===");# avoid "use Cwd;" or `pwd` # SEE Note:OpenSSL Version my $version_openssl = Net::SSLeay::OPENSSL_VERSION_NUMBER() || STR_UNDEF; print( "=== $0 $VERSION ==="); print( " osaft_vm_build = $ENV{'osaft_vm_build'}") if (defined $ENV{'osaft_vm_build'}); print( " Net::SSLeay::"); # next two should be identical printf(" ::OPENSSL_VERSION_NUMBER() 0x%x (%s)\n", $version_openssl, $version_openssl); printf(" ::SSLeay() 0x%x (%s)\n", __SSLeay(), __SSLeay()); if (1.49 > $Net::SSLeay::VERSION) { _warn("851: ancient version Net::SSLeay $Net::SSLeay::VERSION < 1.49; detailed version not available"); } else { if ($cfg{'verbose'} > 0) { # TODO: not all versions of Net::SSLeay have constants like # Net::SSLeay::SSLEAY_CFLAGS, hence we use hardcoded integers print " ::SSLEAY_DIR " . Net::SSLeay::SSLeay_version(5); print " ::SSLEAY_BUILD_ON " . Net::SSLeay::SSLeay_version(3); print " ::SSLEAY_PLATFORM " . Net::SSLeay::SSLeay_version(4); print " ::SSLEAY_CFLAGS " . Net::SSLeay::SSLeay_version(2); } print " Net::SSLeay::SSLeay_version() " . Net::SSLeay::SSLeay_version(); # no parameter is same as parameter 0 # TODO: print " *SSL version mismatch" if Net::SSLeay::SSLeay_version() ne Net::SSLinfo::do_openssl('version','','',''); } print "= openssl ="; print " external executable " . (($cmd{'openssl'} eq "") ? "<>" : $cmd{'openssl'}); print " version of external executable " . Net::SSLinfo::do_openssl('version', '', '', ''); print " used environment variable (name) " . $cmd{'envlibvar'}; print " environment variable (content) " . ($ENV{$cmd{'envlibvar'}} || STR_UNDEF); print " path to shared libraries " . join(" ", @{$cmd{'libs'}}); if (scalar @{$cmd{'libs'}} > 0) { foreach my $l (qw(libcrypto.a libcrypto.so libssl.a libssl.so)) { foreach my $p (@{$cmd{'libs'}}) { my $lib = "$p/$l"; $lib = "<<$p/$l not found>>" if (! -e $lib); print " library " . $lib; if ($cfg{'verbose'} > 1) { print "# strings $lib | grep 'part of OpenSSL')"; print qx(strings $lib | grep 'part of OpenSSL'); } } } } print " full path to openssl.cnf file " . ($cfg{'openssl_cnf'} || STR_UNDEF); print " common openssl.cnf files " . join(" ", @{$cfg{'openssl_cnfs'}}); print " URL where to find CRL file " . ($cfg{'ca_crl'} || STR_UNDEF); print " directory with PEM files for CAs " . ($cfg{'ca_path'} || STR_UNDEF); print " PEM format file with CAs " . ($cfg{'ca_file'} || STR_UNDEF); print " common paths to PEM files for CAs ". join(" ", @{$cfg{'ca_paths'}}); if ($cfg{'verbose'} > 0) { foreach my $p (@{$cfg{'ca_paths'}}) { print " existing path to CA PEM files " . $p if -e $p; } } print " common PEM filenames for CAs " . join(" ", @{$cfg{'ca_files'}}); if ($cfg{'verbose'} > 0) { foreach my $p (@{$cfg{'ca_paths'}}) { foreach my $f (@{$cfg{'ca_files'}}) { print " existing PEM file for CA " . "$p/$f" if -e "$p/$f"; } } } my @ciphers= Net::SSLinfo::cipher_openssl();# openssl ciphers ALL:aNULL:eNULL my $cnt = 0; $cnt = @ciphers if (not grep{/<>/} @ciphers);# if executable found print " number of supported ciphers " . $cnt; print " list of supported ciphers " . join(" ", @ciphers) if ($cfg{'verbose'} > 0); print " openssl supported SSL versions " . join(" ", @{$cfg{'version'}}); print " $me known SSL versions " . join(" ", @{$cfg{'versions'}}); printversionmismatch(); print "= $me +cipher ="; print " list of supported elliptic curves " . join(" ", @{$cfg{'ciphercurves'}}); print " list of supported ALPN, NPN " . join(" ", $cfg{'protos_next'}); if ($cfg{'verbose'} > 0) { print " list of supported ALPN " . join(" ", @{$cfg{'protos_alpn'}}); print " list of supported NPN " . join(" ", @{$cfg{'protos_npn'}}); } print "= $me +cipherall ="; # +cipherraw # TODO: would be nicer: $cfg{'cipherranges'}->{'rfc'} =~ s/\n//g; print " default list of ciphers " . $cfg{'cipherranges'}->{'rfc'}; if ($cfg{'verbose'} > 0) { # these lists are for special purpose, so with --v only print " long list of ciphers " . $cfg{'cipherranges'}->{'long'}; print " huge list of ciphers " . $cfg{'cipherranges'}->{'huge'}; print " safe list of ciphers " . $cfg{'cipherranges'}->{'safe'}; print " full list of ciphers " . $cfg{'cipherranges'}->{'full'}; print " C0xx list, range C0xx..C0FF " . $cfg{'cipherranges'}->{'c0xx'}; print " CCxx list, range CCxx..CCFF " . $cfg{'cipherranges'}->{'c0xx'}; print " ECC list, ephermeral ciphers " . $cfg{'cipherranges'}->{'ecc'}; print " SSLv2 list of ciphers " . $cfg{'cipherranges'}->{'SSLv2'}; print " SSLv2_long list of ciphers " . $cfg{'cipherranges'}->{'SSLv2_long'}; print " shifted list of ciphers " . $cfg{'cipherranges'}->{'shifted'}; } # TODO: i.g. OPENSSL_VERSION_NUMBER() returns same value as SSLeay() # but when using libraries with LD_LIBRARY_PATH or alike, these # versions differ # get a quick overview also # SEE Perl:import include print "= Required (and used) Modules ="; print ' @INC ', "@INC"; my ($d, $v, %p); printf("= %-22s %-9s%s\n", "module name", "VERSION", "found in"); printf("= %s+%s+%s\n", "-"x22, "-"x8, "-"x42); # TODO: following list should be same as in _check_modules() foreach my $m (qw(IO::Socket::INET IO::Socket::SSL Time::Local Net::DNS Net::SSLeay Net::SSLinfo Net::SSLhello Ciphers osaft)) { no strict 'refs'; ## no critic qw(TestingAndDebugging::ProhibitNoStrict TestingAndDebugging::ProhibitProlongedStrictureOverride) # avoid: Can't use string ("Net::DNS") as a HASH ref while "strict refs" in use # we expect ::VERSION in all these modules ($d = $m) =~ s#::#/#g; $d .= '.pm';# convert string to key for %INC $v = $m . "::VERSION"; # compute module's VERSION variable printf(" %-22s %-9s%s\n", $m, ($$v || " "), ($INC{$d} || " ")); # use a single space if value is not defined } if ($cfg{'verbose'} > 0) { print "\n= Loaded Modules ="; foreach my $m (sort keys %INC) { printf(" %-22s %6s\n", $m, $INC{$m}); $d = $INC{$m}; $d =~ s#$m$##; $p{$d} = 1; } print "\n= Loaded Module Versions ="; no strict 'refs'; ## no critic qw(TestingAndDebugging::ProhibitNoStrict) # avoid: Can't use string ("AutoLoader::") as a HASH ref while "strict refs" in use foreach my $m (sort keys %main:: ) { next if $m !~ /::/; $d = "?"; # beat the "Use of uninitialized value" dragon $d = ${$$m{'VERSION'}} if defined ${$$m{'VERSION'}}; printf(" %-22s %6s\n", $m, $d); } } return if ($^O =~ m/MSWin32/); # not Windows if ($cfg{'verbose'} > 1) { print "\n= Used Shared Objects ="; # quick&dirty, don't want to use ::Find module foreach my $d (sort keys %p) { next if ($d =~ m/^\s*$/); print "# find $d -name SSLeay.so\\* -o -name libssl.so\\* -o -name libcrypto.so\\*"; print qx(find $d -name SSLeay.so\\* -o -name libssl.so\\* -o -name libcrypto.so\\*); } } return; } # printversion sub _hex_like_openssl { # convert full hex constant to format used by openssl's output my $c = shift; $c =~ s/0x(..)(..)(..)(..)/0x$2,0x$3,0x$4 - /; # 0x0300C029 ==> 0x00,0xC0,0x29 $c =~ s/^0x00,// if ($c ne "0x00,0x00,0x00"); # first byte omitted if 0x00 return sprintf("%22s", $c); } # _hex_like_openssl sub printciphers { #? print cipher descriptions from internal database # uses settings from --legacy= and --format= options to select output format # implemented in VERSION 14.07.14 # # output looks like: openssl ciphers if ((($cfg{'ciphers-v'} + $cfg{'ciphers-V'}) <= 0) and ($cfg{'legacy'} eq "openssl") and ($cfg{'format'} eq "")) { # TODO: filter ciphers not supported by openssl _trace("printciphers: +ciphers"); print join(":", (keys %ciphers)); return; } # anything else prints user-specified formats _trace("printciphers: +list"); my $sep = $text{'separator'}; my ($hex, $ssl, $tag, $bit, $aut, $enc, $key, $mac); $hex = $ssl = $tag = $bit = $aut = $enc = $key = $mac = ""; _v_print("command: " . join(" ", @{$cfg{'do'}})); _v_print("database version: $VERSION"); _v_print("options: --legacy=$cfg{'legacy'} , --format=$cfg{'format'} , --header=$cfg{'out_header'}"); _v_print("options: --v=$cfg{'verbose'}, -v=$cfg{'ciphers-v'} , -V=$cfg{'ciphers-V'}"); my $have_cipher = 0; my $miss_cipher = 0; my $ciphers = ""; $ciphers = Net::SSLinfo::cipher_openssl() if ($cfg{'verbose'} > 0); printheader(_get_text('out_list', $0), "", "", $cfg{'out_header'}); # all following headers printed directly instead of using printheader() if ($cfg{'legacy'} eq "ssltest") { # output looks like: ssltest --list _warn("861: not all ciphers listed"); foreach my $ssl (qw(SSLv2 SSLv3 TLSv1)) {# SSLv3 and TLSv1 are the same, hence search both print "SSLv2 Ciphers Supported..." if ($ssl eq 'SSLv2'); print "SSLv3/TLSv1 Ciphers Supported..." if ($ssl eq 'SSLv3'); foreach my $c (sort keys %ciphers) { next if ($ssl ne get_cipher_ssl($c)); $aut = get_cipher_auth($c); $aut = "No" if ($aut =~ /none/i); $key = get_cipher_keyx($c); $key =~ s/[()]//g; $mac = get_cipher_mac($c); $enc = get_cipher_enc($c); $bit = get_cipher_bits($c); if ($bit =~ m/\d+/) { # avoid Perl warning "Argument isn't numeric" $bit = sprintf("%03d", $bit); } else { # pretty print $bit = '-?-'; $bit = '000' if ($enc =~ m/None/i); } printf(" %s, %s %s bits, %s Auth, %s MAC, %s Kx\n", $c, $enc, $bit, $aut, $mac, $key, ); } } } if ($cfg{'legacy'} eq "openssl") { # output looks like: openssl ciphers -[v|V] foreach my $c (sort keys %ciphers) { $hex = _hex_like_openssl(get_cipher_hex($c)) if ($cfg{'ciphers-V'} > 0); # -V $ssl = get_cipher_ssl($c); $ssl =~ s/^(TLSv1)(\d)$/$1.$2/; # openssl has a . $bit = get_cipher_bits($c); $bit = "($bit)" if ($bit ne ""); # avoid single : $tag = get_cipher_tags($c); $tag =~ s/^\s*:\s*$//; # avoid single : $aut = get_cipher_auth($c); $key = get_cipher_keyx($c); $mac = get_cipher_mac($c); $enc = get_cipher_enc($c); if ($sep eq " ") { # spaces are the default separator in openssl's output # spaces are the default separator for --legacy=openssl too if # not explicitely specified with --sep= # if we use spaces, additonal formatting needs to be spaces too $ssl = sprintf("%-5s", $ssl); $aut = sprintf("%-4s", $aut); $key = sprintf("%-8s", $key); $mac = sprintf("%-4s", $mac); } printf("%s%-23s%s%s%sKx=%s%sAu=%s%sEnc=%s%s%sMac=%s%s%s\n", $hex, $c, $sep, $ssl, $sep, $key, $sep, $aut, $sep, $enc, $bit, $sep, $mac, $sep, $tag, ); } return; } if ($cfg{'legacy'} eq "owasp") { # print ciphers with internal severity and OWASP severity my $hh = ""; my $hl = ""; if ($cfg{'verbose'} > 0) { $hh = "O-Saft"; $hl = "-------+"; } if (0 < $cfg{'out_header'}) { printf("= %s\t%s\t%s\n", "OWASP", $hh, "cipher"); printf("=%s%s%s\n", '------+', $hl, ('-' x 30)); } foreach my $c (sort keys %ciphers) { # following sequence is important, but OWASP_D must be last as it is weakest my $sec_owasp = get_cipher_owasp($c); my $sec_osaft = get_cipher_sec($c); $sec_osaft = "" if (0 >= $cfg{'verbose'}); printf(" %s\t%s\t%s\n", $sec_owasp, $sec_osaft, $c); } if (0 < $cfg{'out_header'}) { printf("=%s%s%s\n", '------+', $hl, ('-' x 30)); } return; } if ($cfg{'legacy'} eq "simple") { # this format like for +list up to VERSION 14.07.14 $sep = "\t"; if (0 < $cfg{'out_header'}) { printf("= %-30s %s\n", "cipher", join($sep, @{$ciphers_desc{'head'}})); printf("=%s%s\n", ('-' x 30), ('+-------' x 9)); } foreach my $c (sort keys %ciphers) { printf(" %-30s %s\n", $c, join($sep, @{$ciphers{$c}})); } if (0 < $cfg{'out_header'}) { printf("=%s%s\n", ('-' x 30), ('+-------' x 9)); } return; } if ($cfg{'legacy'} eq "full") { # internal format with leading hex number $sep = $text{'separator'}; if (0 < $cfg{'out_header'}) { printf("= Constant$sep%s%-20s${sep}Aliases\n", "Cipher", join($sep, @{$ciphers_desc{'text'}})); printf("= constant$sep%-30s$sep%s${sep}alias\n", "cipher", join($sep, @{$ciphers_desc{'head'}})); printf("=--------------+%s%s\n", ('-' x 31), ('+-------' x 10)); } foreach my $c (sort keys %ciphers) { my $can = " "; # FIXME if (0 < $cfg{'verbose'}) { if (0 >= (grep{$_ eq $c} split(/:/, $ciphers))) { $can = "#"; $miss_cipher++; } else { $have_cipher++; } } $hex = get_cipher_hex($c); my $alias = ""; $alias = join(" ", @{$cipher_alias{$hex}}) if (defined $cipher_alias{$hex}); $hex = sprintf("%s$sep", ($hex || " -?-")); printf("%s %s%-30s$sep%s$sep%s\n", $can, $hex, $c, join($sep, @{$ciphers{$c}}), $alias); } if (0 < $cfg{'out_header'}) { printf("=--------------+%s%s\n", ('-' x 31), ('+-------' x 10)); } if (0 < $cfg{'verbose'}) { my @miss = (); my @test = (); my $dupl = ""; # need to identify duplicates as we don't have List::MoreUtils foreach my $c (split(/:/, $ciphers)) { next if ($c eq $dupl); push(@test, $c) if defined $ciphers{$c}; push(@miss, $c) if not defined $ciphers{$c}; $dupl = $c; } # no customizable texts from %text, as it's for --v only print "\n# Ciphers marked with # above are not supported by local SSL implementation.\n"; print "Supported Ciphers: ", $have_cipher; print "Unsupported Ciphers: ", $miss_cipher; print "Testable Ciphers: ", scalar(@test); print "Ciphers missing in $me: ", scalar(@miss), " ", join(" ", @miss) if (scalar(@miss) > 0); print "Ciphers in alias list: ", scalar(keys %cipher_alias); # FIXME: need to count values } } return; } # printciphers sub printscores { #? print calculated score values my ($legacy, $host, $port) = @_; scoring($host, $port); # simple rounding in Perl: $rounded = int($float + 0.5) $scores{'checks'}->{val} = int( (( $scores{'check_cert'}->{val} + $scores{'check_conn'}->{val} + $scores{'check_dest'}->{val} + $scores{'check_http'}->{val} + $scores{'check_size'}->{val} ) / 5 ) + 0.5); printheader($text{'out_scoring'}."\n", $text{'desc_score'}, "", $cfg{'out_header'}); _trace_cmd('%scores'); foreach my $key (sort keys %scores) { next if ($key !~ m/^check_/); # print totals only print_line($legacy, $host, $port, $key, $scores{$key}->{txt}, $scores{$key}->{val}); } print_line($legacy, $host, $port, 'checks', $scores{'checks'}->{txt}, $scores{'checks'}->{val}); printruler(); if (($cfg{'traceKEY'} > 0) && ($verbose > 0)) { _y_CMD("verbose score table"); print "\n"; printtable('score'); printruler(); } return; } # printscores sub printopenssl { #? print openssl version print Net::SSLinfo::do_openssl('version', '', '', ''); printversionmismatch(); return; } # printopenssl sub printusage_exit { my @txt = @_; local $\ = "\n"; print STR_USAGE, @txt; print "# most common usage: $me +info your.tld $me +check your.tld $me +cipher your.tld $me +cipherll your.tld # for more help use: $me --help "; exit 2; } # printusage_exit sub _get_target { #? check argument and return array: protocol, host, port, auth # allow host, host:port, URL with IPv4, IPv6, FQDN # http://user:pass@f.q.d.n:42/aa*foo=bar:23/ # ftp://username:password@hostname/ # http://f.q.d.n:42/aa*foo=bar:23/ # ftp://f.q.d.n:42/aa*foo=bar:23 # ftp:42/no-fqdn:42/aa*foo=bar:23 # dpsmtp://authentication@mail:25/queryParameters # //abc/def # abc://def # scary # http://[2001:db8:1f70::999:de8:7648:6e8]:42/aa*foo=bar:23/ # http://2001:db8:1f70::999:de8:7648:6e8:42/aa*foo=bar:23/ # invalid, but works # cafe::999/aa*foo=bar:23/ # invalid, but works # NOTE: following regex allow hostnames containing @, _ and many more ... my $last = shift; # default port if not specified my $arg = shift; # TODO: ugly and just simple cases, not very perlish code ... return ("https", $arg, $last, "", "") if ($arg =~ m#^\s*$#); # defensive programming return ("https", $arg, $last, "", "") if ($arg !~ m#[:@\\/?]#); # seem to be bare name or IP # something complicated, analyze ... my $prot = $arg; $prot =~ s#^\s*([a-z][A-Z0-9]*:)?//.*#$1#i; # get schema (protocol), if any # TODO: inherit previous schema if not found $prot = "https" if ($prot eq $arg); # check before stripping : $prot = "https" if ($prot eq ""); $prot =~ s#:##g; # strip : my $auth = ""; # TODO my $path = ""; # TODO my $port = ""; my $host = $arg; $host =~ s#^\s*(?:[a-z][A-Z0-9]*:)?//##i; # strip schema (protocol), if any $host =~ s#^(?:[^@]+@)?##i; # strip user:pass, if any $host =~ s#/.*$##; # strip /path/and?more ($host, $port) = split(/:([^:\]]+)$/, $host); # split right most : (remember IPv6) $port = $last if not defined $port; _y_ARG("arg=$arg => prot=$prot, host=$host, port=$port"); #return "" if (($host =~ m/^\s*$/) or ($port =~ m/^\s*$/)); return ($prot, $host, $port, $auth, $path); } # _get_target # end sub usr_pre_args(); #| scan options and arguments #| ------------------------------------- # All arguments are inspected here. We do not use any module, like Getopt, # 'cause we want to support various variants of the same argument, like case # sensitive or additional characters i.e. . - _ to be ignored, and so on. # This also allows to use different options and commands easily for the same # functionality without defining each variant. Grep for "alias" below ... # Even most commands are also the key in our own data structure (%data, %cfg) # we do not use any argument as key drectly, but always compare with the keys # and assign values using keys literally, like: $cfg{'key'} = $arg . my $typ = 'HOST'; push(@argv, "");# need one more argument otherwise last --KEY=VALUE will fail while ($#argv >= 0) { $arg = shift @argv; _y_ARG("cli_arg= $arg"); push(@{$dbx{argv}}, $arg) if (($arg !~ m/^--cfg[_-]/) && (($arg =~ m/^[+-]/) || ($typ ne "HOST"))); push(@{$dbx{cfg}}, $arg) if ($arg =~ m/^--cfg[_-]/); # both aprox. match are sufficient for debugging # First check for arguments of options. # Options are not case sensitive. Options may contain . and - and _ # anywhere in its name. These characters are silently ignored. These are # all the same: --no-DNS --no_DNS --no.dns --NoDns --n-o_D.N.s # Options may have an argument, either as separate word or as part of the # option parameter itself: --opt argument or --opt=argument . # Such an argument is handled using $typ. All types except HOST, which is # the default, are handled at the begining here (right below). After pro- # cessing the argument, $typ is set to HOST again and next argument will # be taken from command line. # $typ='HOST' is handled at end of loop, as it may appear anywhere in the # command line and does not require an option. # Commands are case sensitive because they are used directly as key in a # hash (see %_SSLinfo Net::SSLinfo.pm). Just commands for the tool itself # (not those returning collected data) are case insensitive. # NOTE: the sequence of following code must be: # 1. check argument (otherwise relooped before) # 2. check for options (as they may have arguments) # unknown remaining options here are silently ignored, because they # cannot easily be distinguished from known ones # 3. check for commands (as they all start with '+' and we don't expect # any argument starting with '+') # 4. check for HOST argument # Parsing options see OPTIONS below, parsing commands see COMMANDS below. if ($typ ne 'HOST') { # option arguments # Note that $arg already contains the argument # hence `next' at end of surrounding if() # $type is set at end of each matching if condition, hence only the # first matching if condition is executed; sequence is important! _y_ARG("argument? $arg, typ= $typ"); push(@{$dbx{exe}}, join("=", $typ, $arg)) if ($typ =~ m/OPENSSL|ENV|EXE|LIB/); # programming: for better readability "if($typ eq CONST)" is used # instead of recommended "if(CONST eq $typ)" below # $typ = '????'; # expected next argument # +---------+----------+------------------------------+-------------------- # argument to process what to do expect next argument # +---------+----------+------------------------------+-------------------- if ($typ eq 'CFG-CIPHER') { _cfg_set_cipher($typ, $arg);$typ = 'HOST'; } if ($typ eq 'CFG-INIT') { _cfg_set_init($typ, $arg); $typ = 'HOST'; } if ($typ =~ m/^CFG/) { _cfg_set($typ, $arg); $typ = 'HOST'; } # backward compatibility removed to allow mixed case texts; # until 16.01.31 lc($arg) was used for pre 14.10.13 compatibility if ($typ eq 'VERBOSE') { $cfg{'verbose'} = $arg; $typ = 'HOST'; } if ($typ eq 'ENV') { $cmd{'envlibvar'} = $arg; $typ = 'HOST'; } if ($typ eq 'OPENSSL') { $cmd{'openssl'} = $arg; $typ = 'HOST'; } if ($typ eq 'SSLCNF') { $cfg{'openssl_cnf'} = $arg; $typ = 'HOST'; } if ($typ eq 'SSLFIPS') { $cfg{'openssl_fips'} = $arg; $typ = 'HOST'; } if ($typ eq 'DO') { push(@{$cfg{'do'}}, $arg); $typ = 'HOST'; } # treat as command, if ($typ eq 'NO_OUT') { push(@{$cfg{'ignore-out'}}, $arg); $typ = 'HOST'; } if ($typ eq 'EXE') { push(@{$cmd{'path'}}, $arg); $typ = 'HOST'; } if ($typ eq 'LIB') { push(@{$cmd{'libs'}}, $arg); $typ = 'HOST'; } if ($typ eq 'CALL') { push(@{$cmd{'call'}}, $arg); $typ = 'HOST'; } if ($typ eq 'SEP') { $text{'separator'}= $arg; $typ = 'HOST'; } if ($typ eq 'OPT') { $cfg{'sclient_opt'}.=" $arg"; $typ = 'HOST'; } if ($typ eq 'TIMEOUT') { $cfg{'timeout'} = $arg; $typ = 'HOST'; } if ($typ eq 'CTXT') { $cfg{'no_cert_txt'}= $arg; $typ = 'HOST'; } if ($typ eq 'CAFILE') { $cfg{'ca_file'} = $arg; $typ = 'HOST'; } if ($typ eq 'CAPATH') { $cfg{'ca_path'} = $arg; $typ = 'HOST'; } if ($typ eq 'CADEPTH') { $cfg{'ca_depth'} = $arg; $typ = 'HOST'; } # TODO: use cfg{'targets'} for proxy* if ($typ eq 'PPORT') { $cfg{'proxyport'} = $arg; $typ = 'HOST'; } if ($typ eq 'PUSER') { $cfg{'proxyuser'} = $arg; $typ = 'HOST'; } if ($typ eq 'PPASS') { $cfg{'proxypass'} = $arg; $typ = 'HOST'; } if ($typ eq 'PAUTH') { $cfg{'proxyauth'} = $arg; $typ = 'HOST'; } if ($typ eq 'SNINAME') { $cfg{'sni_name'} = $arg; $typ = 'HOST'; } if ($typ eq 'FILE_SCLIENT') { $cfg{'data'}->{'file_sclient'} = $arg;$typ = 'HOST'; } if ($typ eq 'FILE_CIPHERS') { $cfg{'data'}->{'file_ciphers'} = $arg;$typ = 'HOST'; } if ($typ eq 'FILE_PCAP') { $cfg{'data'}->{'file_pcap'} = $arg;$typ = 'HOST'; } if ($typ eq 'FILE_PEM') { $cfg{'data'}->{'file_pem'} = $arg;$typ = 'HOST'; } if ($typ eq 'SSLRETRY') { $cfg{'sslhello'}->{'retry'} = $arg;$typ = 'HOST'; } if ($typ eq 'SSLTOUT') { $cfg{'sslhello'}->{'timeout'} = $arg;$typ = 'HOST'; } if ($typ eq 'MAXCIPHER') { $cfg{'sslhello'}->{'maxciphers'}=$arg;$typ = 'HOST'; } if ($typ eq 'SSLERROR_MAX') { $cfg{'sslerror'}->{'max'} = $arg;$typ = 'HOST'; } if ($typ eq 'SSLERROR_TOT') { $cfg{'sslerror'}->{'total'} = $arg;$typ = 'HOST'; } if ($typ eq 'SSLERROR_DLY') { $cfg{'sslerror'}->{'delay'} = $arg;$typ = 'HOST'; } if ($typ eq 'SSLERROR_TOUT'){ $cfg{'sslerror'}->{'timeout'} = $arg;$typ = 'HOST'; } if ($typ eq 'SSLERROR_PROT'){ $cfg{'sslerror'}->{'per_prot'} = $arg;$typ = 'HOST'; } if ($typ eq 'CONNECT_DLY') { $cfg{'connect_delay'} = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLS') { $cfg{'starttls'} = $arg; $typ = 'HOST'; } if ($typ eq 'TLSDELAY') { $cfg{'starttls_delay'} = $arg; $typ = 'HOST'; } if ($typ eq 'SLOWDELAY') { $cfg{'slow_server_delay'} = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLSE1') { $cfg{'starttls_error'}[1] = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLSE2') { $cfg{'starttls_error'}[2] = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLSE3') { $cfg{'starttls_error'}[3] = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLSP1') { $cfg{'starttls_phase'}[1] = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLSP2') { $cfg{'starttls_phase'}[2] = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLSP3') { $cfg{'starttls_phase'}[3] = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLSP4') { $cfg{'starttls_phase'}[4] = $arg; $typ = 'HOST'; } if ($typ eq 'STARTTLSP5') { $cfg{'starttls_phase'}[5] = $arg; $typ = 'HOST'; } if ($typ eq 'PORT') { $cfg{'port'} = $arg; $typ = 'HOST'; } #if ($typ eq 'HOST') # not done here, but at end of loop # ------+----------+------------------------------+-------------------- if ($typ eq 'CIPHER') { if (defined $cfg{'cipherpatterns'}->{$arg}) { # our own aliases ... $arg = $cfg{'cipherpatterns'}->{$arg}[1]; } else { # anything else, if ($arg !~ m/^[A-Z0-9-]+/) { # must be upper case _warn("062: given pattern '$arg' for cipher unknown; setting ignored"); $arg = ""; } } push(@{$cfg{'cipher'}}, $arg) if ($arg !~ m/^\s*$/); $typ = 'HOST'; } if ($typ eq 'STD_FORMAT') { if ($arg =~ /$cfg{'regex'}->{'std-format'}/) { _set_binmode($arg); } else { _set_binmode(":encoding($arg)") if ($arg =~ /^[a-zA-Z0-9_.-]+$/); # simple input validation } } if ($typ eq 'PROTOCOL') { if ($arg =~ /^?sslv?2$/i) { $cfg{'SSLv2'} = 1; } if ($arg =~ /^?sslv?3$/i) { $cfg{'SSLv3'} = 1; } if ($arg =~ /^?tlsv?1$/i) { $cfg{'TLSv1'} = 1; } if ($arg =~ /^?tlsv?1[-_.]?1$/i) { $cfg{'TLSv11'} = 1; } if ($arg =~ /^?tlsv?1[-_.]?2$/i) { $cfg{'TLSv12'} = 1; } if ($arg =~ /^?tlsv?1[-_.]?3$/i) { $cfg{'TLSv13'} = 1; } if ($arg =~ /^dtlsv?0[-_.]?9$/i) { $cfg{'DTLSv09'} = 1; } if ($arg =~ /^dtlsv?1[-_.]?0?$/i) { $cfg{'DTLSv1'} = 1; } if ($arg =~ /^dtlsv?1[-_.]?1$/i) { $cfg{'DTLSv11'} = 1; } if ($arg =~ /^dtlsv?1[-_.]?2$/i) { $cfg{'DTLSv12'} = 1; } if ($arg =~ /^dtlsv?1[-_.]?3$/i) { $cfg{'DTLSv13'} = 1; } $typ = 'HOST'; } if ($typ eq 'PHOST') { # TODO: use cfg{'targets'} for proxy # allow user:pass@f.q.d.n:42 $cfg{'proxyhost'} = $arg; if ($arg =~ m#([^@]*)@(.*)#) { # got username:password $arg = $2; if ($1 =~ m#([^:@]*?):([^@]*)#) { $cfg{'proxyuser'} = $1; $cfg{'proxypass'} = $2; } } if ($arg =~ m#([^:]*):(\d+)#) { # got a port too $cfg{'proxyhost'} = $1; $cfg{'proxyport'} = $2; # else port must be given by --proxyport } $typ = 'HOST'; } # following ($arg !~ /^\s*$/) check avoids warnings in CGI mode if ($typ eq 'LABEL') { if (1 == (grep{/^$arg$/i} @{$cfg{'labels'}})) { $cfg{'label'} = lc($arg); } else { _warn("051: option with unknown label '$arg'; setting ignored") if ($arg !~ /^\s*$/); } } if ($typ eq 'LEGACY') { $arg = 'sslcipher' if ($arg eq 'ssl-cipher-check'); # alias if (1 == (grep{/^$arg$/i} @{$cfg{'legacys'}})) { $cfg{'legacy'} = lc($arg); } else { _warn("054: option with unknown legacy '$arg'; setting ignored") if ($arg !~ /^\s*$/); } } if ($typ eq 'FORMAT') { $arg = 'esc' if ($arg =~ m#^[/\\]x$#); # \x and /x are the same if (1 == (grep{/^$arg$/} @{$cfg{'formats'}})) { $cfg{'format'} = $arg; } else { _warn("055: option with unknown format '$arg'; setting ignored") if ($arg !~ /^\s*$/); } } if ($typ eq 'CRANGE') { if (1 == (grep{/^$arg$/} keys %{$cfg{'cipherranges'}})) { $cfg{'cipherrange'} = $arg; } else { _warn("056: option with unknown cipher range '$arg'; setting ignored") if ($arg !~ /^\s*$/); } } if ($typ eq 'CURVES') { $cfg{'ciphercurves'} = [""] if ($arg =~ /^[,:][,:]$/);# special to set empty string if ($arg =~ /^[,:]$/) { $cfg{'ciphercurves'} = []; } else { push(@{$cfg{'ciphercurves'}}, split(/,/, $arg)); } # TODO: checking names of curves needs a sophisticated function #if (1 == (grep{/^$arg$/} keys %{$cfg{'ciphercurves'}})) { # $cfg{'ciphercurves'} = $arg; #} else { # _warn("057: option with unknown curve name '$arg'; setting ignored") if ($arg !~ /^\s*$/); #} } # SEE Note:ALPN, NPN # --protos* is special to simulate empty and undefined arrays # --protosnpn=value - add value to array # --protosnpn=, - set empty array # --protosnpn=,, - set array element to "" # NOTE: distinguish: [], [""], [" "] if ($typ eq 'CIPHER_ALPN'){ $cfg{'cipher_alpns'} = [""] if ($arg =~ /^[,:][,:]$/);# special to set empty string if ($arg =~ /^[,:]$/) { $cfg{'cipher_alpns'} = []; } else { push(@{$cfg{'cipher_alpns'}}, split(/,/, $arg)); } # TODO: checking names of protocols needs a sophisticated function #if (1 == (grep{/^$arg$/} split(/,/, $cfg{'protos_next'})) { } } if ($typ eq 'CIPHER_NPN'){ $cfg{'cipher_npns'} = [""] if ($arg =~ /^[,:][,:]$/);# special to set empty string if ($arg =~ /^[,:]$/) { $cfg{'cipher_npns'} = []; } else { push(@{$cfg{'cipher_npns'}}, split(/,/, $arg)); } # TODO: checking names of protocols needs a sophisticated function } if ($typ eq 'PROTO_ALPN'){ $cfg{'protos_alpn'} = [""] if ($arg =~ /^[,:][,:]$/);# special to set empty string if ($arg =~ /^[,:]$/) { $cfg{'protos_alpn'} = []; } else { push(@{$cfg{'protos_alpn'}}, split(/,/, $arg)); } # TODO: checking names of protocols needs a sophisticated function #if (1 == (grep{/^$arg$/} split(/,/, $cfg{'protos_next'})) { } } if ($typ eq 'PROTO_NPN'){ $cfg{'protos_npn'} = [""] if ($arg =~ /^[,:][,:]$/);# special to set empty string if ($arg =~ /^[,:]$/) { $cfg{'protos_npn'} = []; } else { push(@{$cfg{'protos_npn'}}, split(/,/, $arg)); } # TODO: checking names of protocols needs a sophisticated function } _y_ARG("argument= $arg"); # --trace is special for historical reason, we allow: # --traceARG # --tracearg # --trace=arg # --trace arg # --trace=2 # --trace 2 # --trace=me # --traceME # problem is that we historically allow also # --trace # which has no argument, hence following checks for valid arguments # and pass it to further examination if it not matches if ($typ eq 'TRACE') { $typ = 'HOST'; # expect host as next argument $cfg{'traceARG'}++ if ($arg =~ m#^ARG$#i); $cfg{'traceCMD'}++ if ($arg =~ m#^CMD$#i); $cfg{'traceKEY'}++ if ($arg =~ m#^KEY$#i); $cfg{'traceTIME'}++ if ($arg =~ m#^TIME$#i); $cfg{'traceME'}++ if ($arg =~ m#^ME(?:only)?#i); $cfg{'traceME'}-- if ($arg =~ m#^notme$#i); $cfg{'trace'} = $arg if ($arg =~ m#^\d+$#i); # now magic starts ... next if ($arg =~ m#^(ARG|CMD|KEY|ME|TIME|\d+)$#i); # matched before # if we reach here, argument did not match valid value for --trace, # then simply increment trace level and push back argument $cfg{'trace'}++; unshift(@argv, $arg); } # else $typ handled before if-condition $typ = 'HOST'; # expect host as next argument next; } # ne 'HOST' option arguments next if ($arg =~ /^\s*$/);# ignore empty arguments # remove trailing = for all options # such options are incorrectly used, or are passed in in CGI mode # NOTE: this means that we cannot have empty strings as value if ($arg =~ m/^-[^=]*=$/) { # SEE Note:Option in CGI mode # only options in RegEx are ignored if the value is empty if ($arg =~ /$cfg{'regex'}->{'opt-empty'}/) { _warn("050: option with empty argument '$arg'; option ignored") if ($cgi == 0); next; } $arg =~ s/=+$//; } # first handle some old syntax for backward compatibility if ($arg =~ /^--cfg(cmd|score|text)-([^=]*)=(.*)/) { $typ = 'CFG-'.$1; unshift(@argv, $2 . "=" . $3); # convert to new syntax _warn("022: old (pre 13.12.12) syntax '--cfg-$1-$2'; converted to '--cfg-$1=$2'; please consider changing your files"); next; # no more normalisation! } if ($arg =~ /^--set[_-]?score=(.*)/) { _warn("021: old (pre 13.12.11) syntax '--set-score=*' obsolete, please use --cfg-score=*; option ignored"); next; } if ($arg =~ /^--legacy=key/) { _warn("023: old (pre 19.01.14) syntax '--legacy=key' obsolete, please use --label=key; option ignored"); next; } # ignore -post= option passed from shell script; ugly but defensive programming next if ($arg =~ /^-post=(.*)/); # all options starting with --usr or --user are not handled herein # push them on $cfg{'usr-args'} so they can be accessd in o-saft-*.pm if ($arg =~ /^--use?r/) { $arg =~ s/^(?:--|\+)//; # strip leading chars push(@{$cfg{'usr-args'}}, $arg); next; } # all options starting with --h or --help or +help are not handled herein if ($arg =~ /^(?:--|\+)h(?:elp)?$/) { $arg = "--help=NAME"; }# --h or --help if ($arg =~ /^\+(abbr|abk|glossar|todo)$/i) { $arg = "--help=$1"; } # for historic reason # get matching string right of = if ($arg =~ /^(?:--|\+)help=?(.*)?$/) { # we allow: --help=SOMETHING or +help=SOMETHING if (defined $1) { $arg = $1 if ($1 !~ /^\s*$/); # if it was --help=* } #my $err = _load_file("o-saft-man.pm", "help file"); #if ($err ne "") { # die STR_ERROR, "013: $err" unless (-e $arg); #} # TODO: _load_file() does not yet work, hence following require require q{o-saft-man.pm}; ## no critic qw(Modules::RequireBarewordIncludes) # include if necessary only; dies if missing printhelp($arg); exit 0; } #{ handle some specials #!#--------+------------------------+--------------------------+------------ #!# argument to check what to do what to do next #!#--------+------------------------+--------------------------+------------ if ($arg eq '--trace--') { $cfg{'traceARG'}++; next; } # for backward compatibility if ($arg =~ /^--v(?:erbose)?$/) { $cfg{'verbose'}++; next; } # --v and --v=X allowed if ($arg =~ /^--?starttls$/i) { $cfg{'starttls'} ="SMTP"; next; } # shortcut for --starttls=SMTP if ($arg =~ /^--cgi.?(?:exec|trace)/){$cgi = 1; next; } # SEE Note:CGI mode if ($arg =~ /^--exit=(.*)/) { next; } # -"- if ($arg =~ /^--cmd=\+?(.*)/) { $arg = '+' . $1; } # no next; if ($arg =~ /^--rc/) { next; } # nothing to do, already handled if ($arg =~ /^--yeast.?prot/) { _yeast_prot(); exit 0; } # debugging if ($arg =~ /^--yeast(.*)/) { _yeast_data(); exit 0; } # -"- if ($arg eq '+VERSION') { _version_exit(); exit 0; } # used with --cgi-exec # in CGI mode commands need to be passed as --cmd=* option if ($arg eq '--openssl') { $arg = '--extopenssl'; } # no next; # dirty hack for historic option --openssl #!#--------+------------------------+--------------------------+------------ #} specials # normalize options with arguments: --opt=name --> --opt name if ($arg =~ m/(^-[^=]*)=(.*)/) { $arg = $1; unshift(@argv, $2); #_dbx("push to ARGV $2"); } # $arg now contains option only, no argument # normalize option strings: # --opt-name --> --optname # --opt_name --> --optname # --opt.name --> --optname $arg =~ s/([a-zA-Z0-9])(?:[_.-])/$1/g if ($arg =~ /^-/); #_dbx("normalized= $arg"); # Following checks use exact matches with 'eq' or RegEx matches with '=~' _y_ARG("option? $arg"); #{ OPTIONS # NOTE: that strings miss - and _ characters (see normalization above) #!# You may read the lines as table with columns like: SEE Note:alias #!#--------+------------------------+---------------------------+---------- #!# option to check alias for ... # used by ... #!#--------+------------------------+---------------------------+---------- # first all aliases if ($arg eq '-t') { $arg = '--starttls'; } # alias: testssl.sh if ($arg eq '-b') { $arg = '--enabled'; } # alias: ssl-cert-check if ($arg eq '-c') { $arg = '--capath'; } # alias: ssldiagnose.exe if ($arg =~ /^--?CApath/) { $arg = '--capath'; } # alias: curl, openssl if ($arg =~ /^--?CAfile/) { $arg = '--cafile'; } # alias: openssl if ($arg =~ /^--ca(?:cert(?:ificate)?)$/i) { $arg = '--cafile';} # alias: curl, openssl, wget, ... if ($arg =~ /^--cadirectory$/i) { $arg = '--capath'; } # alias: curl, openssl, wget, ... if ($arg =~ /^--fuzz/i) { $arg = '--cipherrange'; unshift(@argv, 'huge'); } # alias: sslmap if ($arg =~ /^--httpget/i) { $arg = '--http'; } # alias: sslyze if ($arg =~ /^--httpstunnel/i) { $arg = '--proxyhost'; } # alias: sslyze if ($arg eq '--hiderejectedciphers'){$arg = '--nodisabled'; } # alias: sslyze if ($arg eq '--regular') { $arg = '--http'; } # alias: sslyze if ($arg =~ /^--?interval$/) { $arg = '--timeout'; } # alias: ssldiagnos.exe if ($arg =~ /^--?nofailed$/) { $arg = '--enabled'; } # alias: sslscan if ($arg =~ /^--show-?each$/) { $arg = '--disabled'; } # alias: testssl.sh if ($arg =~ /^--(?:no|ignore)cmd$/) { $arg = '--ignoreout'; } # alias: # SEE Note:ignore-out # /-- next line is a dummy for extracting aliases #if ($arg eq '--protocol') { $arg = '--SSL'; } # alias: ssldiagnose.exe if ($arg eq '--range') { $arg = '--cipherrange'; } # alias: if ($arg =~ /^--?servername/i) { $arg = '--sniname'; } # alias: openssl # options form other programs which we treat as command; see Options vs. Commands also if ($arg =~ /^-(e|-each-?cipher)$/) { $arg = '+cipher'; } # alias: testssl.sh if ($arg =~ /^-(E|-cipher-?perproto)$/) { $arg = '+cipherall'; } # alias: testssl.sh if ($arg =~ /^-(f|-ciphers)$/) { $arg = '+ciphercheck'; } # alias: testssl.sh (+ciphercheck defined in .o-saft.pl) if ($arg =~ /^-(p|-protocols)$/) { $arg = '+protocols'; } # alias: testssl.sh if ($arg =~ /^-(y|-spdy)$/) { $arg = '+spdy'; } # alias: testssl.sh if ($arg =~ /^-(Y|-http2)$/) { $arg = '+spdy'; } # alias: testssl.sh if ($arg =~ /^-(U|-vulnerable)$/) { $arg = '+vulns'; } # alias: testssl.sh if ($arg =~ /^-(B|-heartbleed)$/) { $arg = '+heartbleed'; } # alias: testssl.sh if ($arg =~ /^-(I|-ccs(?:-?injection))$/) { $arg = '+ccs'; } # alias: testssl.sh if ($arg =~ /^-(C|-compression|-crime)$/) { $arg = '+compression';# alias: testssl.sh push(@{$cfg{'do'}}, @{$cfg{'cmd-crime'}}); } if ($arg =~ /^-(T|-breach)$/) { $arg = '+breach'; } # alias: testssl.sh if ($arg =~ /^-(O|-poodle)$/) { $arg = '+poodle'; } # alias: testssl.sh if ($arg =~ /^-(F|-freak)$/) { $arg = '+freak'; } # alias: testssl.sh if ($arg =~ /^-(A|-beast)$/) { $arg = '+beast'; } # alias: testssl.sh if ($arg =~ /^-(BB|-robot)$/) { $arg = '+robot'; } # alias: testssl.sh if ($arg =~ /^-(J|-logjam)$/) { $arg = '+logjam'; } # alias: testssl.sh if ($arg =~ /^-(D|-drown)$/) { $arg = '+drown'; } # alias: testssl.sh if ($arg =~ /^--(p?fs|nsa)$/) { $arg = '+pfs'; } # alias: testssl.sh if ($arg =~ /^--(?:rc4|appelbaum)$/){ $arg = '+pfs'; } # alias: testssl.sh if ($arg eq '-R') { $arg = '+renegotiation'; } # alias: testssl.sh if ($arg =~ /^--reneg(?:otiation)?/){ $arg = '+renegotiation'; } # alias: sslyze, testssl.sh if ($arg =~ /^--resum(?:ption)?$/) { $arg = '+resumption'; } # alias: sslyze if ($arg eq '--chain') { $arg = '+chain'; } # alias: if ($arg eq '--default') { $arg = '+default'; } # alias: if ($arg eq '--fingerprint') { $arg = '+fingerprint'; } # alias: if ($arg eq '--fips') { $arg = '+fips'; } # alias: if ($arg eq '-i') { $arg = '+issuer'; } # alias: ssl-cert-check if ($arg eq '--ism') { $arg = '+ism'; } # alias: ssltest.pl if ($arg eq '--list') { $arg = '+list'; } # alias: ssltest.pl if ($arg eq '--quit') { $arg = '+quit'; } # alias: if ($arg eq '--pci') { $arg = '+pci'; } # alias: ssltest.pl if ($arg eq '--printavailable') { $arg = '+ciphers'; } # alias: ssldiagnose.exe if ($arg eq '--printcert') { $arg = '+text'; } # alias: ssldiagnose.exe if ($arg =~ /^--showkeys?/i) { $arg = '--traceKEY'; } # alias: if ($arg =~ /^--tracesub/i) { $arg = '+traceSUB'; } # alias: if ($arg eq '--version') { $arg = '+version'; } # alias: various programs # if ($arg eq '-v') { $typ = 'PROTOCOL'; } # alias: ssl-cert-check # FIXME: not supported; see opt-v and ciphers-v above if ($arg eq '-V') { $cfg{'opt-V'} = 1; } # .....: ssl-cert-check; will be out_header, see below if ($arg eq '--forceopenssl') { $arg = '--opensslciphers'; } # alias: if ($arg eq '--cipheropenssl') { $arg = '--opensslciphers'; } # alias: if ($arg eq '--sclient') { $arg = '--opensslsclient'; } # alias: if ($arg eq '--nosclient') { $arg = '--noopensslsclient'; } # alias: if ($arg eq '--sslnouseecc') { $arg = '--nossluseecc'; } # alias: if ($arg eq '--sslnouseecpoint') { $arg = '--nossluseecpoint'; } # alias: if ($arg eq '--sslnousereneg') { $arg = '--nosslusereneg'; } # alias: if ($arg eq '--sslnodoublereneg') { $arg = '--nossldoublereneg'; } # alias: if ($arg eq '--sslnodatanocipher') { $arg = '--nodataeqnocipher'; } # alias: if ($arg eq '--sslnodataeqnocipher'){$arg = '--nodataeqnocipher'; } # alias: if ($arg eq '--nosslnodataeqnocipher'){$arg = '--nosslnodatanocipher'; } # alias: if ($arg eq '--nomd5cipher') { $arg = '--nociphermd5'; } # alias: used until VERSION 17.04.17 if ($arg eq '--md5cipher') { $arg = '--ciphermd5'; } # alias: used until VERSION 17.04.17 #!#--------+------------------------+---------------------------+---------- #!# option to check what to do comment #!#--------+------------------------+---------------------------+---------- # options for trace and debug if ($arg =~ /^--v(?:erbose)?$/) { $typ = 'VERBOSE'; } if ($arg =~ /^--ciphers?-?v$/) { $arg = '--v-ciphers'; } # alias: if ($arg =~ /^--ciphers?--?v$/) { $arg = '--v-ciphers'; } # alias: if ($arg =~ /^--v-?ciphers?$/) { $cfg{'v_cipher'}++; } if ($arg =~ /^--warnings?$/) { $cfg{'warning'}++; } if ($arg =~ /^--nowarnings?$/) { $cfg{'warning'} = 0; } if ($arg eq '--n') { $cfg{'try'} = 1; } if ($arg =~ /^--tracearg/i) { $cfg{'traceARG'}++; } # special internal tracing if ($arg =~ /^--tracecmd/i) { $cfg{'traceCMD'}++; } # .. if ($arg =~ /^--trace(?:@|key)/i) { $cfg{'traceKEY'}++; } # .. if ($arg =~ /^--traceme/i) { $cfg{'traceME'}++; } # .. if ($arg =~ /^--tracenotme/i) { $cfg{'traceME'}--; } # .. if ($arg =~ /^--tracetime/i) { $cfg{'traceTIME'}++; } # .. if ($arg eq '--trace') { $typ = 'TRACE'; } if ($arg =~ /^--timeabsolute?/i) { $cfg{'time_absolut'} = 1; } if ($arg eq '--timerelative') { $cfg{'time_absolut'} = 0; } if ($arg eq '--linuxdebug') { $cfg{'--linux_debug'}++; } if ($arg eq '--slowly') { $cfg{'slowly'} = 1; } if ($arg =~ /^--exp(?:erimental)?$/){ $cfg{'experimental'} = 1; } if ($arg =~ /^--noexp(erimental)?$/){ $cfg{'experimental'} = 0; } if ($arg eq '--filesclient') { $typ = 'FILE_SCLIENT'; } if ($arg eq '--fileciphers') { $typ = 'FILE_CIPHERS'; } if ($arg eq '--filepcap') { $typ = 'FILE_PCAP'; } if ($arg eq '--filepem') { $typ = 'FILE_PEM'; } # proxy options if ($arg =~ /^--proxy(?:host)?$/) { $typ = 'PHOST'; } if ($arg eq '--proxyport') { $typ = 'PPORT'; } if ($arg eq '--proxyuser') { $typ = 'PUSER'; } if ($arg eq '--proxypass') { $typ = 'PPASS'; } if ($arg eq '--proxyauth') { $typ = 'PAUTH'; } if ($arg =~ /^--?starttls$/i) { $typ = 'STARTTLS'; } if ($arg =~ /^--starttlsdelay$/i) { $typ = 'TLSDELAY'; } if ($arg =~ /^--slowserverdelay$/i) { $typ = 'SLOWDELAY'; } if ($arg =~ /^--starttlserror1$/i) { $typ = 'STARTTLSE1'; } if ($arg =~ /^--starttlserror2$/i) { $typ = 'STARTTLSE2'; } if ($arg =~ /^--starttlserror3$/i) { $typ = 'STARTTLSE3'; } if ($arg =~ /^--starttlsphase1$/i) { $typ = 'STARTTLSP1'; } if ($arg =~ /^--starttlsphase2$/i) { $typ = 'STARTTLSP2'; } if ($arg =~ /^--starttlsphase3$/i) { $typ = 'STARTTLSP3'; } if ($arg =~ /^--starttlsphase4$/i) { $typ = 'STARTTLSP4'; } if ($arg =~ /^--starttlsphase5$/i) { $typ = 'STARTTLSP5'; } # options form other programs for compatibility if ($arg eq '-v') { $cfg{'opt-v'} = 1; } # openssl, sets ciphers-v, see below if ($arg eq '-V') { $cfg{'opt-V'} = 1; } # openssl, sets ciphers-V, see below if ($arg eq '--V') { $cfg{'opt-V'} = 1; } # for lazy people, not documented # options form other programs which we treat as command; see Options vs. Commands also if ($arg =~ /^--checks?$/) { $typ = 'DO'; } # tls-check.pl if ($arg =~ /^--(fips|ism|pci)$/i) {} # options to handle external openssl if ($arg eq '--openssl') { $typ = 'OPENSSL'; } if ($arg =~ '--opensslco?nf') { $typ = 'SSLCNF'; } if ($arg eq '--opensslfips') { $typ = 'SSLFIPS'; } if ($arg eq '--extopenssl') { $cmd{'extopenssl'}= 1; } if ($arg eq '--noopenssl') { $cmd{'extopenssl'}= 0; } if ($arg eq '--opensslciphers') { $cmd{'extciphers'}= 1; } if ($arg eq '--noopensslciphers') { $cmd{'extciphers'}= 0; } if ($arg eq '--opensslsclient') { $cmd{'extsclient'}= 1; } if ($arg eq '--noopensslsclient') { $cmd{'extsclient'}= 0; } if ($arg eq '--alpn') { $cfg{'usealpn'} = 1; } if ($arg eq '--noalpn') { $cfg{'usealpn'} = 0; } if ($arg eq '--npn') { $cfg{'usenpn'} = 1; } if ($arg eq '--nonpn') { $cfg{'usenpn'} = 0; } if ($arg =~ /^--?nextprotoneg$/) { $cfg{'usenpn'} = 1; } # openssl if ($arg =~ /^--nonextprotoneg/) { $cfg{'usenpn'} = 0; } if ($arg =~ /^--?comp(?:ression)?$/){ $arg = '--sslcompression'; } # alias: if ($arg =~ /^--?nocomp(ression)?$/){ $arg = '--nosslcompression'; } # alias: if ($arg =~ /^--sslcompression$/) { $cfg{'no_comp'} = 0; } # openssl s_client -comp if ($arg =~ /^--nosslcompression$/) { $cfg{'no_comp'} = 1; } # openssl s_client -no_comp if ($arg =~ /^--?tlsextdebug$/) { $cfg{'use_extdebug'} = 1;} if ($arg =~ /^--notlsextdebug/) { $cfg{'use_extdebug'} = 0;} if ($arg =~ /^--?reconnect$/) { $cfg{'use_reconnect'} = 1;} if ($arg =~ /^--noreconnect$/) { $cfg{'use_reconnect'} = 0;} if ($arg eq '--sclientopt') { $typ = 'OPT'; } # various options if ($arg eq '--forcesni') { $cfg{'forcesni'} = 1; } if ($arg =~ /^--ignorenoconn(ect)?/){ $cfg{'sslerror'}->{'ignore_no_conn'} = 1;} if ($arg =~ /^--ignorehandshake/) { $cfg{'sslerror'}->{'ignore_handshake'}= 1;} if ($arg =~ /^--noignorehandshake/) { $cfg{'sslerror'}->{'ignore_handshake'}= 0;} if ($arg eq '--lwp') { $cfg{'uselwp'} = 1; } if ($arg eq '--sni') { $cfg{'usesni'} = 1; } if ($arg eq '--nosni') { $cfg{'usesni'} = 0; } if ($arg eq '--snitoggle') { $cfg{'usesni'} = 3; } if ($arg eq '--togglesni') { $cfg{'usesni'} = 3; } if ($arg eq '--nocert') { $cfg{'no_cert'}++; } if ($arg eq '--noignorecase') { $cfg{'ignorecase'}= 0; } if ($arg eq '--ignorecase') { $cfg{'ignorecase'}= 1; } if ($arg eq '--noignorenoreply') { $cfg{'ignorenoreply'} = 0;} if ($arg eq '--ignorenoreply') { $cfg{'ignorenoreply'} = 1;} if ($arg eq '--noexitcode') { $cfg{'exitcode'} = 0; } if ($arg eq '--exitcode') { $cfg{'exitcode'} = 1; } # SEE Note:--exitcode if ($arg =~ /^--exitcodenochecks?/) { $cfg{'exitcode_checks'} = 0; } # -"- if ($arg =~ /^--exitcodenomedium/) { $cfg{'exitcode_medium'} = 0; } # -"- if ($arg =~ /^--exitcodenoweak/) { $cfg{'exitcode_weak'} = 0;} # -"- if ($arg =~ /^--exitcodenolow/) { $cfg{'exitcode_low'} = 0;} # -"- if ($arg =~ /^--exitcodenopfs/) { $cfg{'exitcode_pfs'} = 0;} # -"- if ($arg =~ /^--exitcodenoprot/) { $cfg{'exitcode_prot'} = 0;} # -"- if ($arg =~ /^--exitcodenosizes/) { $cfg{'exitcode_sizes'}= 0;} # -"- if ($arg =~ /^--exitcodenociphers?/){ # shortcut options for following $cfg{'exitcode_cipher'} = 0; $cfg{'exitcode_medium'} = 0; $cfg{'exitcode_weak'} = 0; $cfg{'exitcode_low'} = 0; } # some options are for compatibility with other programs # example: -tls1 -tlsv1 --tlsv1 --tls1_1 --tlsv1_1 --tls11 -no_SSL2 if ($arg =~ /^--?sslv?2$/i) { $cfg{'SSLv2'} = 1; } # allow case insensitive if ($arg =~ /^--?sslv?3$/i) { $cfg{'SSLv3'} = 1; } # -"- if ($arg =~ /^--?tlsv?1$/i) { $cfg{'TLSv1'} = 1; } if ($arg =~ /^--?tlsv?11$/i) { $cfg{'TLSv11'} = 1; } if ($arg =~ /^--?tlsv?12$/i) { $cfg{'TLSv12'} = 1; } if ($arg =~ /^--?tlsv?13$/i) { $cfg{'TLSv13'} = 1; } if ($arg =~ /^--dtlsv?09$/i) { $cfg{'DTLSv09'} = 1; } if ($arg =~ /^--dtlsv?10?$/i) { $cfg{'DTLSv1'} = 1; } if ($arg =~ /^--dtlsv?11$/i) { $cfg{'DTLSv11'} = 1; } if ($arg =~ /^--dtlsv?12$/i) { $cfg{'DTLSv12'} = 1; } if ($arg =~ /^--dtlsv?13$/i) { $cfg{'DTLSv13'} = 1; } if ($arg =~ /^--nosslv?2$/i) { $cfg{'SSLv2'} = 0; } if ($arg =~ /^--nosslv?3$/i) { $cfg{'SSLv3'} = 0; } if ($arg =~ /^--notlsv?1$/i) { $cfg{'TLSv1'} = 0; } if ($arg =~ /^--notlsv?11$/i) { $cfg{'TLSv11'} = 0; } if ($arg =~ /^--notlsv?12$/i) { $cfg{'TLSv12'} = 0; } if ($arg =~ /^--notlsv?13$/i) { $cfg{'TLSv13'} = 0; } if ($arg =~ /^--nodtlsv?09$/i) { $cfg{'DTLSv09'} = 0; } if ($arg =~ /^--nodtlsv?10?$/i) { $cfg{'DTLSv1'} = 0; } if ($arg =~ /^--nodtlsv?11$/i) { $cfg{'DTLSv11'} = 0; } if ($arg =~ /^--nodtlsv?12$/i) { $cfg{'DTLSv12'} = 0; } if ($arg =~ /^--nodtlsv?13$/i) { $cfg{'DTLSv13'} = 0; } if ($arg =~ /^--notcp/i) { $cfg{$_} = 0 foreach (qw(SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 TLSv13)); } if ($arg =~ /^--tcp/i) { $cfg{$_} = 1 foreach (qw(SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 TLSv13)); } if ($arg =~ /^--noudp/i) { $cfg{$_} = 0 foreach (qw(DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13)); } if ($arg =~ /^--udp/i) { $cfg{$_} = 1 foreach (qw(DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13)); } # options for +cipher if ($arg eq '-cipher') { $typ = 'CIPHER'; } # openssl if ($arg eq '--cipher') { $typ = 'CIPHER'; } if ($arg eq '--cipherrange') { $typ = 'CRANGE'; } if ($arg =~ /^--ciphercurves?/) { $typ = 'CURVES'; } if ($arg =~ /^--cipheralpns?/) { $typ = 'CIPHER_ALPN'; } if ($arg =~ /^--ciphernpns?/) { $typ = 'CIPHER_NPN'; } if ($arg eq '--nociphermd5') { $cfg{'cipher_md5'}= 0; } if ($arg eq '--ciphermd5') { $cfg{'cipher_md5'}= 1; } if ($arg eq '--nocipherdh') { $cfg{'cipher_dh'} = 0; } if ($arg eq '--cipherdh') { $cfg{'cipher_dh'} = 1; } # our options if ($arg eq '--http') { $cfg{'usehttp'}++; } if ($arg eq '--nohttp') { $cfg{'usehttp'} = 0; } if ($arg eq '--norc') { } # simply ignore if ($arg eq '--sslerror') { $cfg{'ssl_error'} = 1; } if ($arg eq '--nosslerror') { $cfg{'ssl_error'} = 0; } if ($arg eq '--ssllazy') { $cfg{'ssl_lazy'} = 1; } if ($arg eq '--nossllazy') { $cfg{'ssl_lazy'} = 0; } if ($arg =~ /^--nullsslv?2$/i) { $cfg{'nullssl2'} = 1; } if ($arg =~ /^--sslv?2null$/i) { $cfg{'nullssl2'} = 1; } if ($arg eq '--nodns') { $cfg{'usedns'} = 0; } if ($arg eq '--dns') { $cfg{'usedns'} = 1; } if ($arg eq '--noenabled') { $cfg{'enabled'} = 0; } if ($arg eq '--enabled') { $cfg{'enabled'} = 1; } if ($arg eq '--disabled') { $cfg{'disabled'} = 1; } if ($arg eq '--nodisabled') { $cfg{'disabled'} = 0; } if ($arg eq '--local') { $cfg{'nolocal'} = 1; } if ($arg =~ /^--hints?$/) { $cfg{'out_hint_info'} = 1; $cfg{'out_hint_check'} = 1; } if ($arg =~ /^--nohints?$/) { $cfg{'out_hint_info'} = 0; $cfg{'out_hint_check'} = 0; } if ($arg =~ /^--hints?infos?/) { $cfg{'out_hint_info'} = 1;} if ($arg =~ /^--nohints?infos?/) { $cfg{'out_hint_info'} = 0;} if ($arg =~ /^--hints?checks?/) { $cfg{'out_hint_check'}= 1;} if ($arg =~ /^--nohints?checks?/) { $cfg{'out_hint_check'}= 0;} if ($arg =~ /^--hints?cipher/) { $cfg{'out_hint_cipher'}=1;} if ($arg =~ /^--nohints?cipher/) { $cfg{'out_hint_cipher'}=0;} if ($arg eq '--score') { $cfg{'out_score'} = 1; } if ($arg eq '--noscore') { $cfg{'out_score'} = 0; } if ($arg =~ /^--headers?$/) { $cfg{'out_header'}= 1; } # some people type --headers if ($arg =~ /^--noheaders?$/) { $cfg{'out_header'}= 0; } if ($arg eq '--tab') { $text{'separator'}= "\t"; } # TAB character if ($arg =~ /^--showhosts?/i) { $cfg{'showhost'}++; } if ($arg eq '--nosniname') { $cfg{'usesni'} = 0; } # 0: don't use SNI, different than empty string if ($arg eq '--protocol') { $typ = 'PROTOCOL'; } # ssldiagnose.exe # if ($arg eq '--serverprotocol') { $typ = 'PROTOCOL'; } # ssldiagnose.exe; # not implemented 'cause we do not support server mode if ($arg =~ /^--protoalpns?/) { $typ = 'PROTO_ALPN'; } # some people type --protoalpns if ($arg =~ /^--protonpns?/) { $typ = 'PROTO_NPN'; } # some people type --protonpns if ($arg =~ /^--?h(?:ost)?$/) { $typ = 'HOST'; } # --h already catched above if ($arg =~ /^--?p(?:ort)?$/) { $typ = 'PORT'; } if ($arg =~ /^--exe(?:path)?$/) { $typ = 'EXE'; } if ($arg =~ /^--lib(?:path)?$/) { $typ = 'LIB'; } if ($arg eq '--envlibvar') { $typ = 'ENV'; } if ($arg =~ /^--(?:no|ignore)out(?:put)?$/) { $typ = 'NO_OUT'; } if ($arg =~ /^--cfg(.*)$/) { $typ = 'CFG-' . $1; } # FIXME: dangerous input if ($arg =~ /^--cfgcipher$/) { $typ = 'CFG-CIPHER'; } if ($arg =~ /^--cfginit$/) { $typ = 'CFG-INIT'; } if ($arg eq '--call') { $typ = 'CALL'; } if ($arg eq '--format') { $typ = 'FORMAT'; } if ($arg eq '--legacy') { $typ = 'LEGACY'; } if ($arg eq '--label') { $typ = 'LABEL'; } if ($arg =~ /^--short(?:te?xt)?$/) { $cfg{'label'} = 'short'; } # ancient sinc 19.01.14 if ($arg =~ /^--sep(?:arator)?$/) { $typ = 'SEP'; } if ($arg =~ /^--?timeout$/) { $typ = 'TIMEOUT'; } if ($arg =~ /^--nocertte?xt$/) { $typ = 'CTXT'; } if ($arg =~ /^--sniname/i) { $typ = 'SNINAME'; } if ($arg =~ /^--sslerrormax/i) { $typ = 'SSLERROR_MAX'; } if ($arg =~ /^--sslerrortotal/i) { $typ = 'SSLERROR_TOT'; } if ($arg =~ /^--sslerrortotal(?:max)?/i){ $typ = 'SSLERROR_TOT';} if ($arg =~ /^--sslerrordelay/i) { $typ = 'SSLERROR_DLY'; } if ($arg =~ /^--sslerrortimeout/i) { $typ = 'SSLERROR_TOUT'; } if ($arg =~ /^--sslerrorperprot/i) { $typ = 'SSLERROR_PROT'; } if ($arg =~ /^--connectdelay/i) { $typ = 'CONNECT_DLY'; } if ($arg eq '--socketreuse') { $cfg{'socket_reuse'} = 1;} if ($arg eq '--nosocketreuse') { $cfg{'socket_reuse'} = 0;} # options for Net::SSLhello if ($arg =~ /^--no(?:dns)?mx/) { $cfg{'usemx'} = 0; } if ($arg =~ /^--(?:dns)?mx/) { $cfg{'usemx'} = 1; } if ($arg eq '--sslretry') { $typ = 'SSLRETRY'; } if ($arg eq '--ssltimeout') { $typ = 'SSLTOUT'; } if ($arg eq '--sslmaxciphers') { $typ = 'MAXCIPHER'; } if ($arg eq '--usesignaturealg') { $cfg{'sslhello'}->{'usesignaturealg'} = 1; } if ($arg eq '--nousesignaturealg') { $cfg{'sslhello'}->{'usesignaturealg'} = 0; } if ($arg eq '--nossluseecc') { $cfg{'sslhello'}->{'useecc'} = 0; } if ($arg eq '--ssluseecc') { $cfg{'sslhello'}->{'useecc'} = 1; } if ($arg eq '--nossluseecpoint') { $cfg{'sslhello'}->{'useecpoint'} = 0; } if ($arg eq '--ssluseecpoint') { $cfg{'sslhello'}->{'useecpoint'} = 1; } if ($arg eq '--nosslusereneg') { $cfg{'sslhello'}->{'usereneg'} = 0; } if ($arg eq '--sslusereneg') { $cfg{'sslhello'}->{'usereneg'} = 1; } if ($arg eq '--nossldoublereneg') { $cfg{'sslhello'}->{'double_reneg'} = 0; } if ($arg eq '--ssldoublereneg') { $cfg{'sslhello'}->{'double_reneg'} = 1; } if ($arg eq '--nodataeqnocipher') { $cfg{'sslhello'}->{'nodatanocipher'} = 1; } if ($arg eq '--nosslnodatanocipher') { $cfg{'sslhello'}->{'nodatanocipher'} = 0; } #!#--------+------------------------+---------------------------+---------- if ($arg =~ /^--cadepth$/i) { $typ = 'CADEPTH'; } # some tools use CAdepth if ($arg =~ /^--cafile$/i) { $typ = 'CAFILE'; } if ($arg =~ /^--capath$/i) { $typ = 'CAPATH'; } if ($arg =~ /^--stdformat/i) { $typ = 'STD_FORMAT'; } if ($arg =~ /^--winCR/i) { _set_binmode(":crlf:utf8"); } # historic alias # ignored options if ($arg =~ /^-connect$/) {} if ($arg eq '--insecure') {} if ($arg =~ /^--use?r$/) {} if ($arg =~ /^--(?:ciscospeshul|nocolor|nopct|strictpcigrade|UDP)$/) {} # ssldiagnos.exe if ($arg =~ /^--server(cert|certkey|certpass|cipher|protocol|mode)$/) {} # " if ($arg =~ /^-(?:H|r|s|t|url|u|U|x)$/) {} # -s HOST # ssl-cert-check: -s ignored hence HOST parsed as expected # -x DAYS # ssl-cert-check: -x ignored hence DAYS taken as host # FIXME #} --------+------------------------+---------------------------+---------- _y_ARG("option= $arg") if ($arg =~ /^-/); next if ($arg =~ /^-/); # all options handled, remaining are ignored # i.e. from sslscan: --no-renegotiation --no-compression ... # TODO: means that targets starting with '-' are not possible, # however, such FQDN are illegal #{ COMMANDS my $p = qr/[._-]/; # characters used as separators in commands keys # this will always be used as $p? below _y_ARG("command? $arg"); # The following sequence of conditions is important: commands which are an # alias for another command are listed first. These aliases should contain # the comment "# alias" somewhere in the line, so it can be extracted by # other tools easily. The comment "# alias:" is used by --help=alias . # the command assigned to $arg should be enclosed in ' (single quote), see # o-saft-man.pm' man_alias() for more details. # You may read the lines as table with columns like: #!#+---------+----------------------+---------------------------+------------- #!# command to check aliased to comment/traditional name #!#+---------+----------------------+---------------------------+------------- if ($arg =~ /^\+targets?$/) { $arg = '+host'; } # alias: print host and DNS information if ($arg =~ /^\+host$p/) { $arg = '+host'; } # alias: until indiidual +host-* commands available # protocol commands if ($arg eq '+check') { $check = 1; } if ($arg eq '+info') { $info = 1; } # needed 'cause +info and .. if ($arg eq '+quick') { $quick = 1; } # .. +quick convert to list of commands if ($arg eq '+sni') { $cmdsni = 1; } if ($arg eq '+http2') { $arg = '+protocols'; } # alias: HTTP/2.0; TODO: may be changed in future if ($arg eq '+spdy') { $arg = '+protocols'; } # alias: spdy; TODO: may be changed in future if ($arg eq '+spdy3') { $arg = '+protocols'; } # alias: SPDY/3.0; TODO: may be changed in future if ($arg eq '+spdy31') { $arg = '+protocols'; } # alias: SPDY/3.1; TODO: may be changed in future if ($arg eq '+spdy4') { $arg = '+protocols'; } # alias: SPDY/4.0; TODO: may be changed in future if ($arg eq '+prots') { $arg = '+protocols'; } # alias: if ($arg eq '+tlsv10') { $arg = '+tlsv1'; } # alias: if ($arg eq '+dtlsv10') { $arg = '+dtlsv1'; } # alias: # cipher commands if ($arg =~ /^\+ciphers?$p?adh/i) { $arg = '+cipher_adh'; } # alias: if ($arg =~ /^\+ciphers?$p?cbc/i) { $arg = '+cipher_cbc'; } # alias: if ($arg =~ /^\+ciphers?$p?des/i) { $arg = '+cipher_des'; } # alias: if ($arg =~ /^\+ciphers?$p?edh/i) { $arg = '+cipher_edh'; } # alias: if ($arg =~ /^\+ciphers?$p?exp/i) { $arg = '+cipher_exp'; } # alias: if ($arg =~ /^\+ciphers?$p?export/i){ $arg = '+cipher_exp'; } # alias: if ($arg =~ /^\+ciphers?$p?null/i) { $arg = '+cipher_null'; } # alias: if ($arg =~ /^\+ciphers?$p?weak/i) { $arg = '+cipher_weak'; } # alias: if ($arg =~ /^\+ciphers?$p?order/i) { $arg = '+cipher_order'; } # alias: if ($arg =~ /^\+ciphers?$p?strong/i){ $arg = '+cipher_strong'; } # alias: if ($arg =~ /^\+ciphers?$p?pfs/i) { $arg = '+cipher_pfs'; } # alias: if ($arg =~ /^\+ciphers?$p?pfsall/i){ $arg = '+cipher_pfsall'; } # alias: if ($arg =~ /^\+ciphers?$p?selected/i){$arg= '+cipher_selected';} # alias: if ($arg =~ /^\+ciphers$p?openssl/i){ $arg = '+ciphers_local'; } # alias: for backward compatibility if ($arg =~ /^\+ciphers$p?local/i) { $arg = '+ciphers_local'; } # alias: if ($arg =~ /^\+all$p?ciphers?/i) { $arg = '+cipherall'; } # alias: if ($arg =~ /^\+raw$p?ciphers?/i) { $arg = '+cipherraw'; } # alias: if ($arg =~ /^\+ciphers?$p?raw/i) { $arg = '+cipherraw'; } # alias: if ($arg =~ /^\+ciphers?$p?prefered?/i){$arg='+cipher_default'; } if ($arg =~ /^\+ciphers?$p?defaults?/i){$arg='+cipher_default'; } # alias: if ($arg =~ /^\+ciphers?$p?dh/i) { $arg = '+cipher_dh'; } # alias: if ($arg =~ /^\+cipher--?v$/) { $arg = '+cipher'; $cfg{'v_cipher'}++; } # alias: shortcut for: +cipher --cipher-v if ($arg =~ /^\+adh$p?ciphers?/i) { $arg = '+cipher_adh'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+cbc$p?ciphers?/i) { $arg = '+cipher_cbc'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+des$p?ciphers?/i) { $arg = '+cipher_des'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+edh$p?ciphers?/i) { $arg = '+cipher_edh'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+exp$p?ciphers?/i) { $arg = '+cipher_exp'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+export$p?ciphers?/i){ $arg = '+cipher_exp'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+null$p?ciphers?/i) { $arg = '+cipher_null'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+weak$p?ciphers?/i) { $arg = '+cipher_weak'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+order$p?ciphers?/i) { $arg = '+cipher_order'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+strong$p?ciphers?/i){ $arg = '+cipher_strong'; } # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+selected$p?ciphers?/i){$arg= '+cipher_selected';} # alias: backward compatibility < 17.06.17 if ($arg =~ /^\+session$p?ciphers?/i) {$arg= '+cipher_selected';} # alias: backward compatibility < 17.06.17 if ($arg eq '+selected') { $arg = '+cipher_selected';} # alias: backward compatibility < 17.06.17 if ($arg eq '+adh') { $arg = '+cipher_adh'; } # alias: if ($arg eq '+cbc') { $arg = '+cipher_cbc'; } # alias: if ($arg eq '+des') { $arg = '+cipher_des'; } # alias: if ($arg eq '+edh') { $arg = '+cipher_edh'; } # alias: if ($arg eq '+exp') { $arg = '+cipher_exp'; } # alias: if ($arg eq '+export') { $arg = '+cipher_exp'; } # alias: if ($arg eq '+null') { $arg = '+cipher_null'; } # alias: if ($arg eq '+weak') { $arg = '+cipher_weak'; } # alias: # alias commands for CVEs if ($arg =~ /^[+]cve.?2009.?3555/i) { $arg = '+renegotiation'; } # alias: if ($arg =~ /^[+]cve.?2011.?3389/i) { $arg = '+beast'; } # alias: if ($arg =~ /^[+]cve.?2012.?4929/i) { $arg = '+crime'; } # alias: if ($arg =~ /^[+]cve.?2013.?3587/i) { $arg = '+breach'; } # alias: if ($arg =~ /^[+]cve.?2014.?0160/i) { $arg = '+heartbleed'; } # alias: if ($arg =~ /^[+]cve.?2014.?0224/i) { $arg = '+ccs'; } # alias: if ($arg =~ /^[+]cve.?2014.?3566/i) { $arg = '+poodle'; } # alias: if ($arg =~ /^[+]cve.?2015.?0204/i) { $arg = '+freak'; } # alias: if ($arg =~ /^[+]cve.?2016.?0703/i) { $arg = '+drown'; } # alias: if ($arg =~ /^[+]cve.?2015.?4000/i) { $arg = '+logjam'; } # alias: if ($arg =~ /^[+]cve.?2013.?2566/i) { $arg = '+rc4'; } # alias: if ($arg =~ /^[+]cve.?2015.?2808/i) { $arg = '+rc4'; } # alias: # check and info commands if ($arg eq '+owner') { $arg = '+subject'; } # alias: if ($arg eq '+authority') { $arg = '+issuer'; } # alias: if ($arg eq '+expire') { $arg = '+after'; } # alias: if ($arg eq '+extension') { $arg = '+extensions'; } # alias: if ($arg eq '+sts') { $arg = '+hsts'; } # alias: if ($arg eq '+sigkey') { $arg = '+sigdump'; } # alias: if ($arg =~ /^\+sigkey$p?algorithm/i){$arg = '+signame'; } # alias: if ($arg eq '+protocol') { $arg = '+session_protocol'; } # alias: if ($arg =~ /^\+selected$p?protocol/i){$arg= '+session_protocol'; } # alias: if ($arg =~ /^\+rfc$p?2818$/i) { $arg = '+rfc_2818_names'; } # alias: if ($arg =~ /^\+rfc$p?2818$p?names/i){$arg = '+rfc_2818_names'; } # alias: if ($arg =~ /^\+rfc$p?6125$/i) { $arg = '+rfc_6125_names'; } # alias: # TODO until check is improved (6/2015) if ($arg =~ /^\+rfc$p?6125$p?names/i){$arg = '+rfc_6125_names'; } # alias: if ($arg =~ /^\+rfc$p?6797$/i) { $arg = '+hsts'; } # alias: if ($arg =~ /^\+rfc$p?7525$/i) { $arg = '+rfc_7525'; } # alias: # do not match +fingerprints in next line as it may be in .o-saft.pl if ($arg =~ /^\+fingerprint$p?(.{2,})$/) { $arg = '+fingerprint_' . $1;} # alias: if ($arg =~ /^\+fingerprint$p?sha$/i) { $arg = '+fingerprint_sha1'; } # alais: if ($arg =~ /^\+subject$p?altnames?/i) { $arg = '+altname'; } # alias: if ($arg =~ /^\+modulus$p?exponent$p?1$/) { $arg = '+modulus_exp_1'; } # alias: if ($arg =~ /^\+modulus$p?exponent$p?65537$/) { $arg = '+modulus_exp_65537';} # alias: if ($arg =~ /^\+modulus$p?exponent$p?size$/) { $arg = '+modulus_exp_oldssl'; } # alias: if ($arg =~ /^\+pubkey$p?enc(?:ryption)?$/) { $arg = '+pub_encryption'; } # alias: if ($arg =~ /^\+public$p?enc(?:ryption)?$/) { $arg = '+pub_encryption'; } # alias: if ($arg =~ /^\+pubkey$p?enc(?:ryption)?$p?known/){ $arg = '+pub_enc_known'; } # alias: if ($arg =~ /^\+public$p?enc(?:ryption)?$p?known/){ $arg = '+pub_enc_known'; } # alias: if ($arg =~ /^\+ocsp$p?public$p?hash$/) { $arg = '+ocsp_public_hash'; } if ($arg =~ /^\+ocsp$p?subject$p?hash$/) { $arg = '+ocsp_subject_hash';} if ($arg =~ /^\+sig(key)?$p?enc(?:ryption)?$/) { $arg = '+sig_encryption'; } # alias: if ($arg =~ /^\+sig(key)?$p?enc(?:ryption)?_known/){$arg ='+sig_enc_known'; } # alias: if ($arg =~ /^\+server$p?(?:temp)?$p?key$/) { $arg = '+dh_parameter'; } # alias: if ($arg =~ /^\+reneg/) { $arg = '+renegotiation'; } # alias: if ($arg =~ /^\+resum/) { $arg = '+resumption'; } # alias: if ($arg =~ /^\+reused?$/i) { $arg = '+resumption'; } # alias: if ($arg =~ /^\+commonName$/i) { $arg = '+cn'; } # alias: if ($arg =~ /^\+cert(?:ificate)?$/i){ $arg = '+pem'; } # alias: if ($arg =~ /^\+issuer$p?X509$/i) { $arg = '+issuer'; } # alias: if ($arg =~ /^\+subject$p?X509$/i) { $arg = '+subject'; } # alias: if ($arg =~ /^\+sha2sig(?:nature)?$/){$arg = '+sha2signature'; } # alias: if ($arg =~ /^\+sni$p?check$/) { $arg = '+check_sni'; } if ($arg =~ /^\+check$p?sni$/) { $arg = '+check_sni'; } if ($arg =~ /^\+ext$p?aia$/i) { $arg = '+ext_authority'; } # alias: AIA is a common acronym ... if ($arg =~ /^\+vulnerabilit(y|ies)/) {$arg= '+vulns'; } # alias: #!#+---------+----------------------+---------------------------+------------- # +---------+----------------------+-----------------------+---------------- # command to check what to do what to do next # +---------+----------+-----------------------------------+---------------- # commands which cannot be combined with others if ($arg eq '+host') { push(@{$cfg{'do'}}, 'host'); next; } # special if ($arg eq '+info') { @{$cfg{'do'}} = (@{$cfg{'cmd-info'}}, 'info'); next; } if ($arg eq '+info--v'){ @{$cfg{'do'}} = (@{$cfg{'cmd-info--v'}}, 'info'); next; } # like +info ... if ($arg eq '+quick') { @{$cfg{'do'}} = (@{$cfg{'cmd-quick'}}, 'quick'); next; } if ($arg eq '+check') { @{$cfg{'do'}} = (@{$cfg{'cmd-check'}}, 'check'); next; } if ($arg eq '+vulns') { @{$cfg{'do'}} = (@{$cfg{'cmd-vulns'}}, 'vulns'); next; } if ($arg eq '+check_sni'){@{$cfg{'do'}} = @{$cfg{'cmd-sni--v'}}; next; } if ($arg eq '+protocols'){@{$cfg{'do'}} = (@{$cfg{'cmd-prots'}}); next; } # if ($arg =~ /^\+next$p?prot(?:ocol)s$/) { @{$cfg{'do'}}= (@{$cfg{'cmd-prots'}}); next; } if ($arg eq '+traceSUB'){ # this command is just documentation, no need to care about other options print "# $cfg{'mename'} list of internal functions:\n"; my $perlprog = 'sub p($$){printf("%-24s\t%s\n",@_);} ($F[0]=~/^#/)&&do{$_=~s/^\s*#\??/-/;p($s,$_)if($s ne "");$s="";}; ($F[0] eq "sub")&&do{p($s,"")if($s ne "");$s=$F[1];}'; exec 'perl', '-lane', "$perlprog", $0; exit 0; } if ($arg =~ /^\+(.*)/) { # all other commands my $val = $1; _y_ARG("command= $val"); next if ($val =~ m/^\+\s*$/); # ignore empty commands; for CGI mode next if ($val =~ m/^\s*$/); # ignore empty arguments; for CGI mode if ($val =~ m/^exec$/i) { # +exec is special $cfg{'exec'} = 1; next; } #_dbx("command= $val"); # convert all +CMD to lower case $val = lc($val); # be greedy to allow +BEAST, +CRIME, etc. push(@{$cfg{'done'}->{'arg_cmds'}}, $val); if ($val eq 'sizes') { push(@{$cfg{'do'}}, @{$cfg{'cmd-sizes'}}); next; } if ($val eq 'hsts') { push(@{$cfg{'do'}}, @{$cfg{'cmd-hsts'}}); next; } if ($val eq 'http') { push(@{$cfg{'do'}}, @{$cfg{'cmd-http'}}); next; } if ($val eq 'pfs') { push(@{$cfg{'do'}}, @{$cfg{'cmd-pfs'}}); next; } if ($val eq 'sni') { push(@{$cfg{'do'}}, @{$cfg{'cmd-sni'}}); next; } if ($val eq 'ev') { push(@{$cfg{'do'}}, @{$cfg{'cmd-ev'}}); next; } if ($val eq 'bsi') { push(@{$cfg{'do'}}, @{$cfg{'cmd-bsi'}}); next; } if ($val eq 'beast') { push(@{$cfg{'do'}}, @{$cfg{'cmd-beast'}}); next; } if ($val eq 'crime') { push(@{$cfg{'do'}}, @{$cfg{'cmd-crime'}}); next; } if ($val eq 'drown') { push(@{$cfg{'do'}}, @{$cfg{'cmd-drown'}}); next; } if ($val eq 'freak') { push(@{$cfg{'do'}}, @{$cfg{'cmd-freak'}}); next; } if ($val eq 'lucky13') { push(@{$cfg{'do'}}, @{$cfg{'cmd-lucky13'}}); next; } if ($val eq 'robot') { push(@{$cfg{'do'}}, @{$cfg{'cmd-robot'}}); next; } if ($val eq 'sweet32') { push(@{$cfg{'do'}}, @{$cfg{'cmd-sweet32'}}); next; } if ($val =~ /tr$p?02102/){push(@{$cfg{'do'}}, qw(tr_02102+ tr_02102-));next; } if ($val =~ /tr$p?03116/){push(@{$cfg{'do'}}, qw(tr_03116+ tr_03116-));next; } if (_is_member($val, \@{$cfg{'commands-USR'}}) == 1) { push(@{$cfg{'do'}}, @{$cfg{"cmd-$val"}}); next; } if (_is_member($val, \@{$cfg{'commands-NOTYET'}}) > 0) { _warn("044: command not yet implemented '$val' may be ignored"); } if (_is_member($val, \@{$cfg{'commands'}}) == 1) { push(@{$cfg{'do'}}, lc($val)); # lc() as only lower case keys are allowed since 14.10.13 } else { _warn("049: command '$val' unknown; command ignored"); } next; } #} +---------+----------+------------------------------------+---------------- if ($arg =~ /(?:ciphers|s_client|version)/) { # handle openssl commands special _warn("041: host-like argument '$arg'; treated as command '+$arg'"); _hint("please use '+$arg' instead"); push(@{$cfg{'do'}}, $arg); next; } if ($typ eq 'HOST') { # host argument is the only one parsed here my ($prot, $host, $port, $auth, $path) = _get_target($cfg{port}, $arg); if (($host =~ m/^\s*$/) or ($port =~ m/^\s*$/)){ _warn("042: invalid host-like argument '$arg'; ignored"); # TODO: occours i.e with --port=' ' but not with --host=' ' } else { my $idx = $#{$cfg{'targets'}}; $idx++; # next one my $proxy = 0; # TODO: target parameter for proxy not yet supported _y_ARG("host= $host:$port"); _yeast("host: $host:$port") if ($cfg{'trace'} > 0); # if perlish programming # push(@{$cfg{'targets'}}, [$idx, $prot, $host, $port, $auth, $proxy, $path, $arg]); # elsif people expecting object-oriented programming set_target_orig( $idx, $arg); set_target_nr( $idx, $idx); set_target_prot( $idx, $prot); set_target_host( $idx, $host); set_target_port( $idx, $port); set_target_auth( $idx, $auth); set_target_proxy($idx, $proxy); set_target_path( $idx, $path); set_target_start($idx, 0); set_target_open( $idx, 0); set_target_stop( $idx, 0); set_target_error($idx, 0); # endif } } } # while options and arguments # exit if ($#{$cfg{'do'}} < 0); # no exit here, as we want some --v output local $\ = "\n"; # TODO: use cfg{'targets'} for proxy if ($cfg{'proxyhost'} ne "" && 0 == $cfg{'proxyport'}) { my $q = "'"; printusage_exit("$q--proxyhost=$cfg{'proxyhost'}$q requires also '--proxyport=NN'"); } $verbose = $cfg{'verbose'}; $warning = $cfg{'warning'}; $legacy = $cfg{'legacy'}; if (('owasp' eq $legacy) and (0 <= _need_cipher())) { # --legacy=owasp does not print the "supported" columns, hence all # supported=no results must be skipped (cannot be distinguished) $cfg{'disabled'} = 0; $cfg{'enabled'} = 1; } if ((_is_do('cipher')) and (0 == $#{$cfg{'do'}})) { # +cipher does not need DNS and HTTP, may improve perfromance # HTTP may also cause errors i.e. for STARTTLS $cfg{'usehttp'} = 0; $cfg{'usedns'} = 0; } if (_is_do('ciphers')) { # +ciphers command is special: # simulates openssl's ciphers command and accepts -v or -V option #$cfg{'out_header'} = 0 if ((grep{/--header/} @argv) <= 0); $cfg{'ciphers-v'} = $cfg{'opt-v'}; $cfg{'ciphers-V'} = $cfg{'opt-V'}; $cfg{'legacy'} = "openssl" if (($cfg{'opt-v'} + $cfg{'opt-V'}) > 0); $text{'separator'} = " " if ((grep{/--(?:tab|sep(?:arator)?)/} @argv) <= 0); # space if not set } else { # not +ciphers command, then -V is for compatibility if (! _is_do('list')) { $cfg{'out_header'} = $cfg{'opt-V'} if ($cfg{'out_header'} <= 0); } } if (_is_do('cipherall')) { # +cipherall same as cipherraw with different output format push(@{$cfg{'do'}}, 'cipherraw') if (not _is_do('cipherraw')); } if (_is_do('list')) { # our own command to list ciphers: uses header and TAB as separator $cfg{'out_header'} = 1 if ((grep{/--no.?header/} @argv) <= 0); $cfg{'ciphers-v'} = $cfg{'opt-v'}; $cfg{'ciphers-V'} = $cfg{'opt-V'}; $text{'separator'} = "\t" if ((grep{/--(?:tab|sep(?:arator)?)/} @argv) <= 0); # tab if not set } if (_is_do('pfs')) { push(@{$cfg{'do'}}, 'cipher_pfsall') if (!_is_do('cipher_pfsall')); } if (_is_do('version') or ($cfg{'usemx'} > 0)) { $cfg{'need_netdns'} = 1; } if (_is_do('version') or (_is_do('sts_expired')) > 0) { $cfg{'need_timelocal'} = 1; } $cfg{'connect_delay'} =~ s/[^0-9]//g; # simple check for valid values # set environment # Note: openssl has no option to specify the path to its configuration # directoy. However, some sub command (like req) do have -config option. # Nevertheless the environment variable is used to specify the path, this # is independet of the sub command and any platform. # We set the environment variable only, if --openssl-cnf was used which # then overwrites an already set environment variable. # This behaviour also honors that all command line options are the last # resort for all configurations. # As we do not use req or ca sub commands (11/2015), this setting is # just to avoid noicy warnings from openssl. $ENV{'OPENSSL_CONF'} = $cfg{'openssl_cnf'} if (defined $cfg{'openssl_cnf'}); ## no critic qw(Variables::RequireLocalizedPunctuationVars $ENV{'OPENSSL_FIPS'} = $cfg{'openssl_fips'} if (defined $cfg{'openssl_fips'}); ## no critic qw(Variables::RequireLocalizedPunctuationVars _yeast_args(); # all arguments parsed; print with --traceARG _yeast_EXIT("exit=ARGS - options and arguments done"); _vprintme(); #_init_openssldir(); # called later for performance reasons usr_pre_exec(); #| call with other libraries #| ------------------------------------- _y_ARG("exec? $cfg{'exec'}"); # NOTE: this must be the very first action/command if ($cfg{'exec'} == 0) { # as all shared libraries used by Perl modules are already loaded when # this program executes, we need to set PATH and LD_LIBRARY_PATH before # being called # so we call ourself with proper set environment variables again # NOTE: --exe points to the directoy with the openssl executable # while --lib points to the directoy with the libraries # sometimes, when building new libraries or openssl, the libraries and the # executable are located in the same directoy, so we add the directoy given # with --lib to the PATH environment variable too, which should not harm if (($#{$cmd{'path'}} + $#{$cmd{'libs'}}) > -2) { # any of these is used _y_CMD("exec command " . join(" ", @{$cfg{'do'}})); #ENV{OPENSSL} no need to set again if already done when called my $chr = ($ENV{PATH} =~ m/;/) ? ";" : ":"; # set separator character (lazy) my $lib = $ENV{$cmd{envlibvar}}; # save existing LD_LIBRARY_PATH local $\ = "\n"; $ENV{PATH} = join($chr, @{$cmd{'path'}}, $ENV{PATH}) if ($#{$cmd{'path'}} >= 0); ## no critic qw(Variables::RequireLocalizedPunctuationVars) $ENV{PATH} = join($chr, @{$cmd{'libs'}}, $ENV{PATH}) if ($#{$cmd{'libs'}} >= 0); ## no critic qw(Variables::RequireLocalizedPunctuationVars) $ENV{$cmd{envlibvar}} = join($chr, @{$cmd{'libs'}}) if ($#{$cmd{'libs'}} >= 0); ## no critic qw(Variables::RequireLocalizedPunctuationVars $ENV{$cmd{envlibvar}} .= $chr . $lib if ($lib); if ($verbose > 0) { _yeast("exec: envlibvar=$cmd{envlibvar}"); _yeast("exec: $cmd{envlibvar}=" . ($ENV{$cmd{envlibvar}} || "")); # ENV may not exist _yeast("exec: PATH=$ENV{PATH}"); } _yeast("exec: $0 +exec " . join(" ", @ARGV)); _yeast("################################################") if (($cfg{'traceARG'} + $cfg{'traceCMD'}) > 0); exec $0, '+exec', @ARGV; } } #| set openssl-specific path for CAs #| ------------------------------------- $cmd{'openssl'} = _init_opensslexe(); # warnings already printed if empty if (not defined $cfg{'ca_path'}) { # not passed as option, use default $cfg{'ca_path'} = _init_openssldir(); # warnings already printed if empty } $cfg{'ca_path'} = _init_openssl_ca($cfg{'ca_path'}); if (not defined $cfg{'ca_path'} or $cfg{'ca_path'} eq "") { _warn("060: no PEM fila for CA found; some certificate checks may fail"); } #| openssl and Net::SSLeay is picky about path names #| ------------------------------------- foreach my $key (qw(ca_file ca_path ca_crl)) { next if not defined $cfg{$key}; _warn("053: option with spaces '$key'='$cfg{$key}'; may cause connection problems") if ($cfg{$key} =~ m/\s/); } if ($info > 0) { # +info does not do anything with ciphers # main purpose is to avoid missing "*PN" warnings in following _checks_*() $cmd{'extciphers'} = 0; $cfg{'usealpn'} = 0; $cfg{'usenpn'} = 0; } _yeast_TIME("inc{"); #| import common and private modules #| ------------------------------------- _load_modules(); _yeast_TIME("inc}"); _yeast_TIME("mod{"); _y_CMD("check $cfg{'mename'} internals ..."); if (! _is_do('cipherraw')) { # +cipherraw does not need these checks #| check for required module versions #| ------------------------------------- # check done after loading our own modules because they may require # other common Perl modules too; we may have detailed warnings before _check_modules(); #| check for required functionality #| ------------------------------------- # more detailed checks on version numbers with proper warning messages _check_functions() if (not _is_do('cipher')); # "if" to improve performance #| check for proper openssl support #| ------------------------------------- _check_openssl(); #| check for supported SSL versions #| ------------------------------------- #initialize $cfg{'version'} and all $cfg{ssl} _check_SSL_methods() if ((_need_cipher() > 0) or (_need_default() > 0) or _is_do('version')); } else { _check_SSL_methods(); # function is oversized for +cipherraw, but does the work }; # +cipherraw _yeast_TIME("mod}"); _yeast_TIME("ini{"); #| set additional defaults if missing #| ------------------------------------- $cfg{'out_header'} = 1 if(0 => $verbose); # verbose uses headers $cfg{'out_header'} = 1 if(0 => grep{/\+(check|info|quick|cipher)$/} @argv); # see --header $cfg{'out_header'} = 0 if(0 => grep{/--no.?header/} @argv); # command line option overwrites defaults above #cfg{'sni_name'} = $host; # see below: loop targets $sniname = $cfg{'sni_name'}; # safe setting; may be undef if ($cfg{'usehttp'} == 0) { # was explizitely set with --no-http 'cause default is 1 # STS makes no sence without http _warn("064: STS $text{'na_http'}") if(0 => (grep{/hsts/} @{$cfg{'do'}})); # check for any hsts* } $quick = 1 if ($cfg{'legacy'} eq 'testsslserver'); if ($quick == 1) { $cfg{'enabled'} = 1; $cfg{'label'} = 'short'; } $text{'separator'} = "\t" if ($cfg{'legacy'} eq "quick"); #| set defaults for Net::SSLinfo #| ------------------------------------- { #$IO::Socket::SSL::DEBUG = $cfg{'trace'} if ($cfg{'trace'} > 0); no warnings qw(once); # avoid: Name "Net::SSLinfo::trace" used only once: possible typo at ... if ($cfg{'traceME'} < 1) { $Net::SSLinfo::trace = $cfg{'trace'} if ($cfg{'trace'} > 0); } $Net::SSLinfo::linux_debug = $cfg{'linux_debug'}; $Net::SSLinfo::use_openssl = $cmd{'extopenssl'}; $Net::SSLinfo::use_sclient = $cmd{'extsclient'}; $Net::SSLinfo::openssl = $cmd{'openssl'}; $Net::SSLinfo::sni_name = $cfg{'sni_name'}; # NOTE: may be undef $Net::SSLinfo::use_http = $cfg{'usehttp'}; $Net::SSLinfo::use_SNI = $cfg{'usesni'}; $Net::SSLinfo::use_alpn = $cfg{'usealpn'}; $Net::SSLinfo::use_npn = $cfg{'usenpn'}; $Net::SSLinfo::protos_alpn = (join(",", @{$cfg{'protos_alpn'}})); $Net::SSLinfo::protos_npn = (join(",", @{$cfg{'protos_npn'}})); $Net::SSLinfo::use_extdebug = $cfg{'use_extdebug'}; $Net::SSLinfo::use_reconnect = $cfg{'use_reconnect'}; $Net::SSLinfo::socket_reuse = $cfg{'socket_reuse'}; $Net::SSLinfo::slowly = $cfg{'slowly'}; $Net::SSLinfo::sclient_opt = $cfg{'sclient_opt'}; $Net::SSLinfo::timeout_sec = $cfg{'timeout'}; $Net::SSLinfo::no_compression = $cfg{'no_comp'}; $Net::SSLinfo::no_cert = $cfg{'no_cert'}; $Net::SSLinfo::no_cert_txt = $cfg{'no_cert_txt'}; $Net::SSLinfo::ignore_case = $cfg{'ignorecase'}; $Net::SSLinfo::ca_crl = $cfg{'ca_crl'}; $Net::SSLinfo::ca_file = $cfg{'ca_file'}; $Net::SSLinfo::ca_path = $cfg{'ca_path'}; $Net::SSLinfo::ca_depth = $cfg{'ca_depth'}; $Net::SSLinfo::ignore_handshake = $cfg{'sslerror'}->{'ignore_handshake'}; $Net::SSLinfo::starttls = $cfg{'starttls'}; $Net::SSLinfo::proxyhost = $cfg{'proxyhost'}; $Net::SSLinfo::proxyport = $cfg{'proxyport'}; $Net::SSLinfo::proxypass = $cfg{'proxypass'}; $Net::SSLinfo::proxyuser = $cfg{'proxyuser'}; $Net::SSLinfo::file_sclient = $cfg{'data'}->{'file_sclient'}; $Net::SSLinfo::file_pem = $cfg{'data'}->{'file_pem'}; $Net::SSLinfo::method = ""; } if ('cipher' eq join("", @{$cfg{'do'}})) { $Net::SSLinfo::use_http = 0; # if only +cipher given don't use http 'cause it may cause erros } #| set defaults for Net::SSLhello #| ------------------------------------- if (defined $Net::SSLhello::VERSION) { no warnings qw(once); # avoid: Name "Net::SSLinfo::trace" used only once: possible typo at ... if ($cfg{'traceME'} < 1) { $Net::SSLhello::trace = $cfg{'trace'}; } $Net::SSLhello::traceTIME = $cfg{'traceTIME'}; $Net::SSLhello::experimental = $cfg{'experimental'}; $Net::SSLhello::usemx = $cfg{'usemx'}; $Net::SSLhello::usesni = $cfg{'usesni'}; $Net::SSLhello::sni_name = $cfg{'sni_name'}; $Net::SSLhello::connect_delay = $cfg{'connect_delay'}; $Net::SSLhello::starttls = (($cfg{'starttls'} eq "") ? 0 : 1); $Net::SSLhello::starttlsType = $cfg{'starttls'}; $Net::SSLhello::starttlsDelay = $cfg{'starttls_delay'}; $Net::SSLhello::slowServerDelay = $cfg{'slow_server_delay'}; $Net::SSLhello::timeout = $cfg{'sslhello'}->{'timeout'}; $Net::SSLhello::retry = $cfg{'sslhello'}->{'retry'}; $Net::SSLhello::max_ciphers = $cfg{'sslhello'}->{'maxciphers'}; $Net::SSLhello::use_signature_alg = $cfg{'sslhello'}->{'usesignaturealg'}; $Net::SSLhello::usereneg = $cfg{'sslhello'}->{'usereneg'}; $Net::SSLhello::useecc = $cfg{'sslhello'}->{'useecc'}; $Net::SSLhello::useecpoint = $cfg{'sslhello'}->{'useecpoint'}; $Net::SSLhello::double_reneg = $cfg{'sslhello'}->{'double_reneg'}; $Net::SSLhello::noDataEqNoCipher= $cfg{'sslhello'}->{'nodatanocipher'}; $Net::SSLhello::proxyhost = $cfg{'proxyhost'}; $Net::SSLhello::proxyport = $cfg{'proxyport'}; $Net::SSLhello::cipherrange = $cfg{'cipherrange'}; # not really necessary, see below $Net::SSLhello::ciphercurves = (join(":", @{$cfg{'ciphercurves'}})); $Net::SSLhello::protos_alpn = (join(",", @{$cfg{'protos_alpn'}})); $Net::SSLhello::protos_npn = (join(",", @{$cfg{'protos_npn'}})); # TODO: need to unify variables @Net::SSLhello::starttlsPhaseArray = @{$cfg{'starttls_phase'}}; # add 'starttls_error' array elements according Net::SSLhello's internal # representation push(@Net::SSLhello::starttlsPhaseArray, @{$cfg{'starttls_error'}}[1..3]); } $cfg{'trace'} = 0 if ($cfg{'traceME'} < 0); if ($cfg{'label'} eq 'short') { # reconfigure texts foreach my $key (keys %data) { $data{$key} ->{'txt'} = $shorttexts{$key}; } foreach my $key (keys %checks) { $checks{$key}->{'txt'} = $shorttexts{$key}; } } _yeast_TIME("ini}"); #| first all commands which do not make a connection #| ------------------------------------- _y_CMD("no connection commands ..."); if (_is_do('list')) { printciphers(); exit 0; } if (_is_do('ciphers')) { printciphers(); exit 0; } if (_is_do('version')) { printversion(); exit 0; } if (_is_do('libversion')) { printopenssl(); exit 0; } if (_is_do('quit')) { printquit(); exit 0; } # internal test command if (($cfg{'trace'} + $cfg{'verbose'}) > 0) { # +info command is special with --v @{$cfg{'do'}} = @{$cfg{'cmd-info--v'}} if (@{$cfg{'do'}} eq @{$cfg{'cmd-info'}}); } _yeast_init(); # call in printquit() also! if ($#{$cfg{'do'}} < 0) { _yeast_exit(); printusage_exit("no command given"); } usr_pre_cipher(); #| get list of ciphers available for tests #| ------------------------------------- # TODO: move this code-block up behind call of _check_SSL_methods(); # needs exhausting tests with previous non-connecting commands # needs also proper tests what Net::SSLinfo::cipher_* returns, # see _get_ciphers_list() _yeast_TIME("get{"); if ((_need_cipher() > 0) or (_need_default() > 0)) { _y_CMD(" get cipher list ..."); @{$cfg{'ciphers'}} = _get_ciphers_list(); } # _need_cipher or _need_default _yeast_TIME("get}"); _yeast_EXIT("exit=MAIN - start"); _yeast_ciphers(); usr_pre_main(); #| main: do the work for all targets #| ------------------------------------- # defensive, user-friendly programming # could do these checks earlier (after setting defaults), but we want # to keep all checks together for better maintenace printusage_exit("no target hosts given") if ($#{$cfg{'targets'}} <= 0); # does not make any sense if (_is_do('cipher')) { if ($#{$cfg{'done'}->{'arg_cmds'}} > 0) { printusage_exit("additional commands in conjunction with '+cipher' are not supported; '+" . join(" +", @{$cfg{'done'}->{'arg_cmds'}}) ."'"); } } if (($info > 0) and ($#{$cfg{'done'}->{'arg_cmds'}} >= 0)) { # +info does not allow additional commands # see printchecks() call below _warn("047: additional commands in conjunction with '+info' are not supported; '+" . join(" +", @{$cfg{'done'}->{'arg_cmds'}}) . "' ignored"); } if (($check > 0) and ($#{$cfg{'done'}->{'arg_cmds'}} >= 0)) { # +check does not allow additional commands of type "info" foreach my $key (@{$cfg{'done'}->{'arg_cmds'}}) { if (_is_member( $key, \@{$cfg{'cmd-info'}}) > 0) { _warn("048: additional commands in conjunction with '+check' are not supported; +'$key' ignored"); } } } #| main: perform commands for all hosts #| ------------------------------------- usr_pre_host(); my $fail = 0; # check if output disabled for given/used commands, SEE Note:ignore-out foreach my $cmd (@{$cfg{'ignore-out'}}) { $fail++ if (_is_do($cmd) > 0); } if ($fail > 0) { _warn("066: $fail data and check outputs are disbaled due to use of '--no-out':"); if ($cfg{'verbose'} > 0) { _warn("067: disabled: +" . join(" +", @{$cfg{'ignore-out'}})); _warn("068: given: +" . join(" +", @{$cfg{'do'}})); } else { _hint("use '--v' for more information"); } _hint("do not use '--ignore-out=*' or '--no-out=*' options"); # It's not simple to identify the given command, as $cfg{'do'} may # contain a list of commands. So the hint is a bit vage. # _dbx "@{$cfg{'done'}->{'arg_cmds'}}" } else { # print warnings and hints if necessary foreach my $cmd (@{$cfg{'do'}}) { if (_is_member($cmd, \@{$cfg{'commands-HINT'}}) > 0) { _hint("+$cmd : please see '$me --help=CHECKS' for more information"); } } } _y_CMD("hosts ..."); _yeast_TIME("hosts{"); # run the appropriate SSL tests for each host (ugly code down here): $sniname = $cfg{'sni_name'}; # safe value; NOTE: may be undef! $port = ($cfg{'port'}||""); # defensive programming .. my $idx = 0; foreach my $target (@{$cfg{'targets'}}) { # loop targets (hosts) next if (0 == @{$target}[0]); # first entry conatins default settings $idx++; $host = get_target_host($idx); $port = get_target_port($idx); $cfg{'port'} = $port; $cfg{'host'} = $host; next if _yeast_NEXT("exit=HOST0 - host $host:$port"); _y_CMD("host " . ($host||"") . ":$port {"); _trace(" host: $host {\n"); # SNI must be set foreach host, but it's always the same name! if ($cfg{'usesni'} > 0) { if (defined $sniname) { if ($host ne $cfg{'sni_name'}) { _warn("069: hostname not equal SNI name; checks are done with '$host'"); } $Net::SSLinfo::sni_name = $cfg{'sni_name'}; $Net::SSLhello::sni_name= $cfg{'sni_name'}; } else { $cfg{'sni_name'} = $host; $Net::SSLinfo::sni_name = $host; $Net::SSLhello::sni_name= $host; } } $Net::SSLinfo::use_http = $cfg{'usehttp'}; # reset _resetchecks(); printheader(_get_text('out_target', "$host:$port"), "", "", $cfg{'out_header'}); _yeast_TIME("DNS{"); # prepare DNS stuff # gethostbyname() and gethostbyaddr() set $? on error, needs to be reset! my $rhost = ""; $fail = ""; if ($cfg{'proxyhost'} ne "") { # if a proxy is used, DNS might not work at all, or be done by the # proxy (which even may return other results than the local client) # so we set corresponding values to a warning $fail = _get_text('disabled', "--proxyhost=$cfg{'proxyhost'}"); $cfg{'rhost'} = $fail; $cfg{'DNS'} = $fail; $cfg{'IP'} = $fail; $cfg{'ip'} = $fail; } else { $fail = '<>'; $cfg{'ip'} = gethostbyname($host); # primary IP as identified by given hostname if (not defined $cfg{'ip'}) { _warn("201: Can't get IP for host '$host'; host ignored"); _y_CMD("host}"); next; # otherwise all following fails } # gethostbyaddr() is strange: returns $?==0 but an error message in $! # hence just checking $? is not reliable, we do it additionally. # If gethostbyaddr() fails we use Perl's `or' to assign our default # text. This may happen when there are problems with the local name # resolution. # When gethostbyaddr() fails, the connection to the target most likely # fails also, which produces more Perl warnings later. _y_CMD("test IP ..."); $cfg{'IP'} = join(".", unpack("W4", $cfg{'ip'})); if ($cfg{'usedns'} == 1) { # following settings only with --dns _y_CMD("test DNS (disable with --no-dns) ..."); _yeast_TIME("test DNS{"); local $? = 0; local $! = undef; ($cfg{'rhost'} = gethostbyaddr($cfg{'ip'}, AF_INET)) or $cfg{'rhost'} = $fail; $cfg{'rhost'} = $fail if ($? != 0); my ($fqdn, $aliases, $addrtype, $length, @ips) = gethostbyname($host); my $i = 0; #dbx printf "@ips = %s\n", join(" - ", @ips); foreach my $ip (@ips) { local $? = 0; local $! = undef; # TODO: $rhost = gethostbyaddr($ipv6, AF_INET6)); ($rhost = gethostbyaddr($ip, AF_INET)) or $rhost = $fail; $rhost = $fail if ($? != 0); $cfg{'DNS'} .= join(".", unpack("W4", $cfg{'ip'})) . " " . $rhost . "; "; #dbx printf "[%s] = %s\t%s\n", $i, join(".",unpack("W4",$ip)), $rhost; } _warn("202: Can't do DNS reverse lookup: for $host: $fail; ignored") if ($cfg{'rhost'} =~ m/gethostbyaddr/); _yeast_TIME("test DNS}"); } } # print DNS stuff if (_is_do('host') or (($info + $check + $cmdsni) > 0)) { _y_CMD("+info || +check || +sni*"); if ($legacy =~ /(full|compact|simple|owasp)/) { printruler(); print_line($legacy, $host, $port, 'host_name', $text{'host_name'}, $host); print_line($legacy, $host, $port, 'host_IP', $text{'host_IP'}, $cfg{'IP'}); if ($cfg{'usedns'} == 1) { print_line($legacy, $host, $port, 'host_rhost', $text{'host_rhost'}, $cfg{'rhost'}); print_line($legacy, $host, $port, 'host_DNS', $text{'host_DNS'}, $cfg{'DNS'}); } printruler(); } } _yeast_TIME("DNS}"); next if _yeast_NEXT("exit=HOST1 - host DNS"); # Quick check if the target is available _y_CMD("test connect ..."); _yeast_TIME("test connect{");# SEE Note:Connection test my $connect_ssl = 1; _trace("sni_name " . ($cfg{'sni_name'} || STR_UNDEF)); if (not _can_connect($host, $port, $cfg{'sni_name'}, $cfg{'timeout'}, $connect_ssl)) { next if ($cfg{'sslerror'}->{'ignore_no_conn'} <= 0); } $connect_ssl = 0; if (not _can_connect($host, 80 , $cfg{'sni_name'}, $cfg{'timeout'}, $connect_ssl)) { $Net::SSLinfo::use_http = 0; _warn("325: HTTP disabled, using --no-http"); } _yeast_TIME("test connect}"); if (_is_do('cipher_dh')) { if (0 >= $cmd{'extopenssl'}) { # TODO: as long as openssl necessary _warn("408: OpenSSL disabled using --no-openssl, can't check DH parameters; target ignored"); next; } } if (_is_do('cipherraw')) { _y_CMD("+cipherraw"); _yeast_TIME("cipherraw{"); Net::SSLhello::printParameters() if ($cfg{'trace'} > 1); _warn("209: No SSL versions for +cipherraw available") if ($#{$cfg{'version'}} < 0); # above warning is most likely a programming error herein my $total = 0; my $enabled = 0; my $_printtitle = 0; # count title lines; 0 = no ciphers checked my @results = (); # new cipher list for every host my $usesni = $Net::SSLhello::usesni; # store SNI for recovery later foreach my $ssl (@{$cfg{'version'}}) { $_printtitle++; next if ($cfg{$ssl} == 0); if ($usesni >= 1) { # Do not use SNI with SSLv2 and SSLv3 # using $Net::SSLhello::usesni instead of $cfg{'usesni'} (even # they should be the same) because Net::SSLhello functions are # called if ($ssl =~ m/^SSLv/) { # SSLv2 has no SNI; SSLv3 has originally no SNI _warn_nosni("409:", $ssl, $usesni); $Net::SSLhello::usesni = 0; # do not use SNI for this $ssl } else { $Net::SSLhello::usesni = $usesni; # restore } } my @all = _get_ciphers_range($ssl, $cfg{'cipherrange'}); my @accepted = (); # accepted ciphers $total += scalar @all; printtitle($legacy, $ssl, $host, $port, $cfg{'out_header'}); if (not _is_do('cipherall')) { _v_print("cipher range: $cfg{'cipherrange'}"); _v_print sprintf("total number of ciphers to check: %4d", scalar(@all)); } @accepted = Net::SSLhello::checkSSLciphers($host, $port, $ssl, @all); if (not _is_do('cipherall')) { _v_print(sprintf("total number of accepted ciphers: %4d", (scalar(@accepted) - (scalar(@accepted) >= 2 && ($accepted[0] eq $accepted[1]))) )); # correct total number if first 2 ciphers are identical # (this indicates cipher order by the server) # delete 1 when the first 2 ciphers are identical (this indicates an order by the server) } if (_is_do('cipherall')) { $enabled += printcipherall($legacy, $ssl, $host, $port, ($legacy eq "sslscan")?($_printtitle):0, @accepted); print_check($legacy, $host, $port, 'cnt_totals', scalar(@all)) if ($cfg{'verbose'} > 0); next if (scalar @accepted < 1); # defensive programming .. # prepare for printing ... my $cipher = get_cipher_suitename($accepted[0]); # SEE Note:+cipherall $prot{$ssl}->{'cipher_strong'} = $cipher; $prot{$ssl}->{'default'} = $cipher; my $last_a = ""; # avoid duplicates foreach my $key (@accepted) { # each entry looks like: TLSv12 AES128-SHA256 yes next if ($last_a eq $key); push(@results, [$ssl, get_cipher_suitename($key), "yes"]); $last_a = $key; } } else { Net::SSLhello::printCipherStringArray('compact', $host, $port, $ssl, $Net::SSLhello::usesni, @accepted); } } # $ssl if ($_printtitle > 0) { # SEE Note:+cipherall checkciphers($host, $port, @results); # necessary to compute 'out_summary' printciphersummary($legacy, $host, $port, $total); } _yeast_TIME("cipherraw}"); next; # FIXME: SEE Note:+cipherall } # cipherraw next if _yeast_NEXT("exit=HOST2 - host cipherraw"); if (_is_do('fallback_protocol')) { _y_CMD("protocol fallback support ..."); # following similar to ciphers_scan_prot(); my ($version, $supported, $dh); if (0 == $cmd{'extciphers'}) { ($version, $supported) = _usesocket( '', $host, $port, ''); } else { # force openssl ($version, $supported, $dh) = _useopenssl('', $host, $port, ''); } $prot{'fallback'}->{val} = $version; _trace("fallback: $version $supported"); } if ((_need_default() > 0) or ($check > 0)) { # SEE Note:+cipherall _y_CMD("get default ..."); _yeast_TIME("need_default{"); $cfg{'done'}->{'ssl_failed'} = 0; # SEE Note:--ssl-error foreach my $ssl (@{$cfg{'version'}}) { # all requested protocol versions next if not defined $prot{$ssl}->{opt}; my $anf = time(); # no need to check for "valid" $ssl (like DTLSfamily), done by _get_default() $prot{$ssl}->{'cipher_strong'} = _get_default($ssl, $host, $port, 'strong'); $prot{$ssl}->{'cipher_weak'} = _get_default($ssl, $host, $port, 'weak'); $prot{$ssl}->{'default'} = _get_default($ssl, $host, $port, 'default'); # FIXME: there are 3 connections above, but only one is counted last if (_is_ssl_error($anf, time(), "$ssl: abort getting prefered cipher") > 0); my $cipher = $prot{$ssl}->{'cipher_strong'}; $prot{$ssl}->{'cipher_pfs'} = $cipher if ("" eq _ispfs($ssl, $cipher)); ##if (_is_do('cipher_selected') and ($#{$cfg{'do'}} == 0)) { ## # +cipher_selected command given, but no other commands; ready ## print_cipherprefered($legacy, $ssl, $host, $port); # need to check if $ssl available first ## next HOSTS; # TODO: foreach-loop for targets misses label ##} } checkprefered($host, $port); _yeast_TIME("need_default}"); } next if _yeast_NEXT("exit=HOST3 - host ciphers start"); if (_is_do('cipher_default') and ($#{$cfg{'do'}} == 0)) { # don't print if not a single command, because +check or +cipher do it # in printptotocols() anyway printcipherprefered($legacy, $host, $port); goto CLOSE_SSL; # next HOSTS } if (_need_cipher() > 0) { _yeast_TIME("need_cipher{"); _y_CMD(" need_cipher ..."); _y_CMD(" use socket ...") if (0 == $cmd{'extciphers'}); _y_CMD(" use openssl ...") if (1 == $cmd{'extciphers'}); @cipher_results = (); # new list for every host $checks{'cnt_totals'}->{val} = 0; #dbx# _dbx "ciphers:", @{$cfg{'ciphers'}}; ciphers_scan($host, $port); $checks{'cnt_totals'}->{val} = scalar @cipher_results; #dbx @cipher_results = (); # simulate "no ciphers found" checkciphers($host, $port, @cipher_results); # necessary to compute 'out_summary' _yeast_TIME("need_cipher}"); } next if _yeast_NEXT("exit=HOST4 - host get ciphers"); # check ciphers manually (required for +check also) if (_is_do('cipher') or $check > 0) { _y_CMD("+cipher"); _yeast_TIME("cipher{"); _trace(" ciphers: @{$cfg{'ciphers'}}"); # TODO: for legacy==testsslserver we need a summary line like: # Supported versions: SSLv3 TLSv1.0 my $_printtitle = 0; # count title lines; 0 = no ciphers checked foreach my $ssl (@{$cfg{'version'}}) { $_printtitle++; if (($legacy ne "sslscan") or ($_printtitle <= 1)) { # format of sslscan not yet supported correctly my $header = $cfg{'out_header'}; if (($cfg{'out_header'} > 0) or (scalar @{$cfg{'version'}}) > 1) { # need a header when more than one protocol is checked $header = 1; } printtitle($legacy, $ssl, $host, $port, $header); } # TODO: need to simplify above conditions printciphercheck($legacy, $ssl, $host, $port, ($legacy eq "sslscan")?($_printtitle):0, @cipher_results); } if ($legacy eq 'sslscan') { my $ssl = ${$cfg{'version'}}[4]; print_cipherprefered($legacy, $ssl, $host, $port); # TODO: there is only one $data{'cipher_selected'} #foreach my $ssl (@{$cfg{'version'}}) { # print_cipherprefered($legacy, $ssl, $host, $port); #} } if ($_printtitle > 0) { # if we checked for ciphers # SEE Note:+cipherall printciphersummary($legacy, $host, $port, scalar @cipher_results); } _yeast_TIME("cipher}"); } # cipher next if _yeast_NEXT("exit=HOST5 - host ciphers end"); goto CLOSE_SSL if ((_is_do('cipher') > 0) and ($quick == 0)); usr_pre_info(); _yeast_TIME("SNI{"); _get_data0($host, $port); # uses Net::SSLinfo::do_ssl_open() and ::do_ssl_close() _yeast_TIME("SNI}"); usr_pre_open(); # TODO dirty hack, check with dh256.tlsfun.de # checking for DH parameters does not need a default connection if (_is_do('cipher_dh')) { _y_CMD("+cipher-dh"); _yeast_TIME("cipher-dh{"); printciphers_dh($legacy, $host, $port); _yeast_TIME("cipher-dh}"); goto CLOSE_SSL; } # SEE Note:Connection test if ($cfg{'sslerror'}->{'ignore_no_conn'} <= 0) { # use Net::SSLinfo::do_ssl_open() instead of IO::Socket::INET->new() # to check the connection (hostname and port) # NOTE: the previous test (see can_connect above) should be sufficient _y_CMD("test connection (disable with --ignore-no-conn) ..."); _yeast_TIME("test connection{"); if (not defined Net::SSLinfo::do_ssl_open( $host, $port, (join(" ", @{$cfg{'version'}})), join(" ", @{$cfg{'ciphers'}})) ) { my @errtxt = Net::SSLinfo::errors($host, $port); if ($#errtxt > 0) { _v_print(join("\n".STR_ERROR, @errtxt)); _warn("205: Can't make a connection to $host:$port; target ignored"); _hint("--v will show more information"); _hint("--socket-reuse may help in some cases"); _hint("--ignore-no-conn can be used to disable this check"); _hint("do not use --no-ignore-handshake") if ($cfg{'sslerror'}->{'ignore_handshake'} <= 0); _yeast_TIME(" test connection} failed"); goto CLOSE_SSL; } } _yeast_TIME(" connection open."); my @errtxt = Net::SSLinfo::errors($host, $port); if ((grep{/\*\*ERROR/} @errtxt) > 0) { _warn("207: Errors occoured when using '$cmd{'openssl'}', some results may be wrong; errors ignored"); _hint("--v will show more information"); # do not print @errtxt because of multiple lines not in standard format } _yeast_TIME("test connection}"); } usr_pre_cmds(); _yeast_TIME("prepare{"); if (_is_do('dump')) { _y_CMD("+dump"); if ($cfg{'trace'} > 1) { # requires: --v --trace --trace _trace(' ############################################################ %SSLinfo'); print Net::SSLinfo::datadump(); } printdump($legacy, $host, $port); } usr_pre_data(); # following sequence important! # if conditions are just to improve performance _y_CMD("get checks ..."); if (_need_checkalpn() > 0) { _y_CMD(" need_pn ..."); checkalpn( $host, $port); _yeast_TIME(" checkalpn."); } checkdates($host, $port); _yeast_TIME(" checkdates."); if (_need_checkhttp() > 0) { checkhttp( $host, $port); _yeast_TIME(" checkhttp."); } checksni( $host, $port); _yeast_TIME(" checksni."); checksizes($host, $port); _yeast_TIME(" checksizes."); if ($info == 0) { # not for +info checkdv( $host, $port); _yeast_TIME(" checkdv."); } if (_need_checkprot() > 0) { checkprot( $host, $port); _yeast_TIME(" checkprot."); } if (_need_checkdest() > 0) { checkdest( $host, $port); _yeast_TIME(" checkdest."); } if (_need_checkbleed() > 0) { _y_CMD(" need_checkbleed ..."); checkbleed($host, $port); _yeast_TIME(" checkbleed."); } if (_need_checkssl() > 0) { _y_CMD(" need_checkssl ..."); checkssl( $host, $port); _yeast_TIME(" checkssl."); } _yeast_TIME("prepare}"); next if _yeast_NEXT("exit=HOST6 - host prepare"); usr_pre_print(); if ($check > 0) { _y_CMD("+check"); _warn("208: No openssl, some checks are missing") if (($^O =~ m/MSWin32/) and ($cmd{'extopenssl'} == 0)); } # for debugging only if (_is_do('s_client')) { _y_CMD("+s_client"); print "#{\n", Net::SSLinfo::s_client($host, $port), "\n#}"; } _y_CMD("do=".join(" ",@{$cfg{'do'}})); # print all required data and checks # NOTE: if key (aka given command) exists in %checks and %data it will be printed twice _yeast_TIME("info{"); printdata( $legacy, $host, $port) if ($check == 0); # not for +check _yeast_TIME("info}"); _yeast_TIME("checks{"); printchecks($legacy, $host, $port) if ($info == 0); # not for +info _yeast_TIME("checks}"); if ($cfg{'out_score'} > 0) { # no output for +info also _y_CMD("scores"); _yeast_TIME("score{"); printscores($legacy, $host, $port); _yeast_TIME("score}"); } CLOSE_SSL: _y_CMD("host " . ($host||"") . ":$port }"); { no warnings qw(once); if (defined $Net::SSLinfo::socket) { # check to avoid: WARNING undefined Net::SSLinfo::socket Net::SSLinfo::do_ssl_close($host, $port); } } _trace(" host: $host }\n"); $cfg{'done'}->{'hosts'}++; usr_pre_next(); next if _yeast_NEXT("exit=HOST8 - host end"); _yeast_EXIT("exit=HOST9 - perform host end"); } # foreach host _yeast_TIME("hosts}"); usr_pre_exit(); _yeast_exit(); _yeast_EXIT("exit=END - end"); # for symetric reason, rather useless here if ($cfg{'exitcode'} == 0) { exit 0; } else { exit check_exitcode(); } exit 2; # main; code never reached __END__ __DATA__ public user documentation, please see OSaft/Doc/*.txt and OSaft/Doc/Data.pm =pod =encoding utf8 =head1 Documentation Documentation distinguishes between the L and L. =head3 Public User Documentation All public user documentation is available in plain text format. It can be accessed programatially with the --help option and various variants of it. All plain text files are located in ./OSaft/Doc/ . They are designed for human radability and simple editing. For details on documentation texts (format, syntax, etc.) from files, see ./OSaft/Doc/Data.pm and o-saft-man.pm . =head3 Internal Code Documentation All internal (program and coding) documentation is usually POD format in the corresponding files. This documentation is intended for development. For details see following chapter L . =head1 Annotations, Internal Notes The annotations here describe behaviours, observations, and alike, which lead to special program logic. The intention is to have one central place, where to do the documentation. Up to now --2018-- this is an internal documentation only. It is available for the developer with perldoc also. It is written in POD format, because some tools analyzing the code want to "see" comments and documentation. We feed them. For more information about that, please see "woodoo" in o-saft-man.pm . Note that POD's =head2 syntax is used. It marks a single annotation, which will be referenced in the code with the "SEE " syntax. All following text is supposed to be read by humans! The term Perl is used when the programming language in general is meant. The term perl is used when the program perl (or perl.exe) is meant. The term Perl::Critic is used when the functionality of the Perl::Critic module, or any program using it (such as perlcritic), is meant. The term perlcritic is used when the program perlcritic is meant. =head2 Note:Documentation =head3 Since VERSION 18.12.18 Switching to CGI mode if the script is named *.cgi is no longer supported, this script should be called by a proper wrapper, i.e o-saft.cgi . Functionality silently removed, no warning or error is printed. =head3 Since VERSION 18.01.18 All public user documentation is now in plain text files which use charset UTF-8, see ./OSaft/Doc/*.txt . Previous files ./OSaft/Doc/*.pm have been replaced by ./OSaft/Doc/Data.pm and the afore mentioned plain text files. Reading plain text from external files instead of Perl's DATA also avoids sophisticated computation of the correct file and DATA handle, for example when ./OSaft/Doc/*.pm is imported in Perl's BEGIN section, please also SEE Perl:BEGIN below. =head3 Since VERSION 17.07.17 All documentation from variables, i.e. %man_text, moved to separate files in ./OSaft/Doc/*. This simplified editing texts as they are simple ASCII format in the __DATA__ section of each file. The overhead compared to the %man_text variable is just the Perl module file with its POD texts. The disadvantage is, that it's more complicated to import the data in a stand- alone script, see contrib/gen_standalone.sh . =head3 Since VERSION 17.06.17 All user documentation is now in o-saft-man.pl, which uses a mix of texts defined in Perl variables, i.e. %man_text. The public user documentation is defined in the __DATA__ section (mainly all the documentation). =head3 Since VERSION 16.06.16 Reading of o-saft-README disabled because most people asked how to remove it, which is described in o-saft-README itself. People won't read :-( =head3 Until VERSION 14.11.12 Initilly the documentation was written in Perl's doc format: perldoc, POD. The advantage of POD is the well formated output on various platforms, but results in more difficult efforts for extracting information from there. In particular following problems occoured with POD: - perldoc is not available on all platforms by default - POD is picky when text lines start with a whitespace - programatically extracting data requires additional substitutes - POD is slow Changing POD to plain ASCII (VERSION 14.11.14 vs. 14.12.14): equal source code: lines or kBytes in o-saft-usr.pm vs. o-saft-man.pm Description POD ASCII % File -------------------------+----+-------------+------+---------- * reduced doc. text: 3110 2656 lines 85% o-saft.pl * reduced doc. text: 86.9 85.5 kBytes 98% o-saft.pl * reduced source code: 122 21 lines 17% o-saft.pl * reduced source code: 4.4 1.0 kBytes 23% o-saft.pl * improved performance: 2.7 0.02 seconds 0.75% o-saft.pl -------------------------+----+-------------+------+---------- =head2 Perl:perlcritic perlcritic is used for general code quality. Our code isn't accademically perfect, no is perlcritic. Hence we use perlcritic's pragmas to disable some checks as needed. This is done in general in perlcritic's config file .perlcritic and selectively in the code using "## no critic" pragma. All disabled checks are documented, wether in .perlcritic or as pragma. Following pragmas are used in various files: * InputOutput::ProhibitBacktickOperators) This check seems to be a very perosnal opinion of perlcritic's author, see descriptions like "... but I find that they make a lot of noise" and "... I think its better to use ..." . Using IPC::Open3 here is simply over-engineered. * Documentation::RequirePodSections Our POD in *pm is fine, perlcritic (severity 2) is too pedantic here. =head2 Perl:import include Perl's recommend way to import modules is the `use' or `require' statement Both methods have the disadvantage that this scripts fails if a requested module is missing. The script fails immediately at startup if modules are loaded with `use', or at runtime id loaded with `require'. One goal is to be able to run on ancient or incomplete configured systems too. Hence we try to load all modules with our own function _load_file(), which uses `require' to load the module at runtime. This way it's possible to selectively disable just some functionality if loading of a module fails for various reasons (i.e. wrong version). Perl's `use autouse' is also not possible, as to much functions need to be declared for that pragma then. Unfortunately some common Perl modules resist to be loaded with `require'. They are still imported using use . =head2 Perl:BEGIN Loading `require'd files and modules as well as parsing the command line in Perl's BEGIN section increases performance and lowers the memory foot print for some commands (see o-saft-man.pm also). Unfortunately Perl's BEGIN has following limits and restrictions: - constants can be defined before and used herein - sub can be defined herein and used later - variables can not be defined herein and used later - some file handles (like ) are not yet available - strict sequence of definitions and usage (even for variables in subs) Perl subs used in the BEGIN section must be defined there also, or before the BEGIN section (which is a crazy behaviour of Perl). To make the program work as needed, these limitations forces to use some dirty code hacks and split the flow of processing into different parts of the source. =head2 Perl:binmode() Perl uses various layers for I/O operations. It's called I/O layers (also known as discipline). Layers to be used are defined globaly with binmode() or individually in each open() call. All the glory details can be found in Perl's documentation (man or perldoc) for: PerlIO, binmode, open. The tool here roughly destingushes two types of I/O: 1. writeing texts to the user using STDOUT and STDERR channels note that it never reads, except from command line, hence no STDIN 2. reading and writing to network sockets, which is done underneath We assume that the I/O socket (2. above) is handled properly by the used modules. This leaves STDOUT and STDERR (1. above) to be set properly. As most --nearly all-- data on STDOUT and STDERR is supposed to be read by humans. Only these channels are handled explicitely. The idea is, that all texts consist of printable characters only, probably in various languages. Hence UTF-8 is used as default characters set. The channels are configured to expect UTF-8 characters. Perl destingushes between ':utf8' and ':encoding(UTF-8)' layer, where the ':utf8' does not check for valid encodings. ':utf8' is sufficient here, as we only want to ensure UTF-8 on output. The I/O layers need to be set in the main script only, all modules inherit the settings from there. Note that we use STDOUT and STDERR and not the pseudo layer ':std' or the -S flag/option, because they also contain STDIN. =head2 Perl:map() To replace data in each item of an arrays, Perl provides various methods, examples: @arr = map {$_ =~ s/old/new/g; $_; } @arr; # 0. very bad @arr = map { s/old/new/g; $_; } @arr; # 1. bad map { s/old/new/g; } @arr; # 2. better s/old/new/ for @arr; # 3. best we prefer the perlish one (3. above). Because it does not copy the array, it is the most performant solution also. Unfortunatelly Perl::Critic complains about postfix controls with ControlStructures::ProhibitPostfixControls which seems to be misleading. If there are multiple substitutions to be done, it is better to use a loop like (which then keep Perl::Critic happy too): while (@arr) { s/old/new/; s/alt/neu/; } =head2 Perl:warn _warn I.g. Perl's warn() is not used, but our private _warn(). Using _warn() can supressed messages with the --no-warning option. However, some warnings should never be supressed, hence warn() is used in rare cases. Each warning should have a unique number, SEE Perl:Message Numbers . See also CONCEPTS (if it exists in our help texts). =head2 Perl:Message Numbers Each warning has a unique number. The numbers are grouped as follows: 0xx startup check, options, arguments 1xx check (runtime) functionality 2xx loop targets (hosts) 3xx connect functions 4xx cipher check functions 5xx inernal check functions 6xx check functions 8xx print functions Check for used numbers with: egrep '(die|_warn| warn )' o-saft.pl | sed -e 's/^ *//' | sort =head2 Note:ARGV Command line arguments are read after some other internal initializations. Unfortunatelly sometimes options need to be check before argument parsing is completed. Therfore somthing like '(grep{/--trace)/} @ARGV)' is needed. These check are implemented as simple functions, return grep's result. =head2 Note:SSL protocol versions The phrases 'SSL protocol versions', 'SSL protocols' or simply 'protocols' are used through out the comments in the sources equal for SSLv2, SSLv3, TLSv1 etc.. =head2 Note:ALPN, NPN Traditionally first known as NPN, the "protocol negotiation", is used in in the two flaviours NPN and ALPN. The internal variable names are adapted to these acronyms and use "alpn" and "npn" in their names. For historical reason, the list of the protocol names was stored in "cfg{'next_protos'}", which reflects the openssl option (-nextprotoneg), and the function names used in some Perl modules. As newer versions of openssl uses the option -alpn, and some other tools also use -alpn and/or -npn as option, the internal variable names have been adapted to this nameing scheme after version 17.04.17. The primary variable names containing ALPN or NPN protocol names are now: protos_next - internal list of all protocol names protos_alpn - used with/for ALPN options protos_npn - used with/for NPN options cipher_alpns - used with/for ALPN options for +cipher command only cipher_npns - used with/for NPN options for +cipher command only I.g. these are arrays. But as the common syntax for most other tools is to use a comma-separated list of names, the value in "cfg{'protos_next'}" is stored as a string. Using a string instead of an arrays also simplifies to pass the value to functions. Note: openssl uses a comma-separated list for ALPN and NPN, but it uses a colon-separated list for ecliptic curves (and also for ciphers). Hence we allow both separators for all lists on command line. See also Note:OpenSSL Version =head2 Note:alias The code for parsing options and arguments uses some special syntax: * following comment at end of the line: # alias: any other text is used for aliases of commands or options. These lines are extracted by --help=alias =head2 Note:ignore-out The option --no-cmd uses the commands defined in "cfg{'ignore-out'}". Results of these commands are not printed in output. # Purpose is to avoid The purpose is to avoid printing the results of these commands in output, because the output is too noisy (like some +bsi* commands). All data collections and checks are still done, just output of results are omitted. Technically these commands are not removed from cfg{do}, but just skipped in printdata() and printchecks(), which makes implementation much easier. =head2 Note:OpenSSL Version About OpenSSL's version numbers see openssl/opensslv.h . Examples: 0x01000000 => openssl-0.9x.x 0x1000000f => openssl-1.0.0 0x10001000 => openssl-1.0.1 0x10002000 => openssl-1.0.2 0x102031af => 1.2.3z =head2 Note:OpenSSL CApath _init_openssldir() gets the configured directory for the certificate files from the openssl executable. It is expected that openssl returns something like: OPENSSLDIR: "/usr/local/openssl" Some versions of openssl on windows may return "/usr/local/ssl", or alike, which is most likely wrong. As the existance of the returned directoy will be checked, this produces an **WARNING and unsets the ca_path. However, the used Perl modules (i.e. Net::SSLeay) may be compiled with a different OPenSSL, and hence use their (compiled-in) private path to the certs. Note that the returned OPENSSLDIR is a base-directory where the cert files are found in the cert/ sub-directory. This cert/ is hardcoded herein. =head2 Note:OpenSSL s_client Example of% openssl s_client --help unknown option --help usage: s_client args -host host - use -connect instead -port port - use -connect instead -connect host:port - who to connect to (default is localhost:4433) -proxy host:port - use HTTP proxy to connect -verify_host host - check peer certificate matches "host" -verify_email email - check peer certificate matches "email" -verify_ip ipaddr - check peer certificate matches "ipaddr" -verify arg - turn on peer certificate verification -verify_return_error - return verification errors -cert arg - certificate file to use, PEM format assumed -certform arg - certificate format (PEM or DER) PEM default -key arg - Private key file to use, in cert file if not specified but cert file is. -keyform arg - key format (PEM or DER) PEM default -pass arg - private key file pass phrase source -CApath arg - PEM format directory of CA's -CAfile arg - PEM format file of CA's -no_alt_chains - only ever use the first certificate chain found -reconnect - Drop and re-make the connection with the same Session-ID -pause - sleep(1) after each read(2) and write(2) system call -prexit - print session information even on connection failure -showcerts - show all certificates in the chain -debug - extra output -msg - Show protocol messages -nbio_test - more ssl protocol testing -state - print the 'ssl' states -nbio - Run with non-blocking IO -crlf - convert LF from terminal into CRLF -quiet - no s_client output -ign_eof - ignore input eof (default when -quiet) -no_ign_eof - don't ignore input eof -psk_identity arg - PSK identity -psk arg - PSK in hex (without 0x) -srpuser user - SRP authentification for 'user' -srppass arg - password for 'user' -srp_lateuser - SRP username into second ClientHello message -srp_moregroups - Tolerate other than the known g N values. -srp_strength int - minimal length in bits for N (default 1024). -ssl2 - just use SSLv2 -ssl3 - just use SSLv3 -tls1_2 - just use TLSv1.2 -tls1_1 - just use TLSv1.1 -tls1 - just use TLSv1 -dtls1 - just use DTLSv1 -fallback_scsv - send TLS_FALLBACK_SCSV -mtu - set the link layer MTU -no_tls1_2/-no_tls1_1/-no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol -bugs - Switch on all SSL implementation bug workarounds -serverpref - Use server's cipher preferences (only SSLv2) -cipher - preferred cipher to use, use the 'openssl ciphers' command to see what is available -starttls prot - use the STARTTLS command before starting TLS for those protocols that support it, where 'prot' defines which one to assume. Currently, only "smtp", "pop3", "imap", "ftp", "xmpp" "telnet" and "ldap" are supported. are supported. -xmpphost host - When used with "-starttls xmpp" specifies the virtual host. -engine id - Initialise and use the specified engine -rand file:file:... -sess_out arg - file to write SSL session to -sess_in arg - file to read SSL session from -servername host - Set TLS extension servername in ClientHello -tlsextdebug - hex dump of all TLS extensions received -status - request certificate status from server -no_ticket - disable use of RFC4507bis session tickets -serverinfo types - send empty ClientHello extensions (comma-separated numbers) -curves arg - Elliptic curves to advertise (colon-separated list) -sigalgs arg - Signature algorithms to support (colon-separated list) -client_sigalgs arg - Signature algorithms to support for client certificate authentication (colon-separated list) -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list) -alpn arg - enable ALPN extension, considering named protocols supported (comma-separated list) -legacy_renegotiation - enable use of legacy renegotiation (dangerous) -use_srtp profiles - Offer SRTP key management with a colon-separated profile list -keymatexport label - Export keying material using label -keymatexportlen len - Export len bytes of keying material (default 20) -no_tlsext - Don't send any TLS extensions (breaks servername, NPN and ALPN among others) Some options are implemented for s_client, see Net::SSLinfo.pm , or use: perl -MNet::SSLinfo -e 'print join("\n",Net::SSLinfo::s_client_get_optionlist());' =head2 Note:Selected Protocol 'sslversion' returns protocol as used in our data structure (like TLSv12) example (ouput from openssl): New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256 example Net::SSLeay: Net::SSLeay::version(..) example (ouput from openssl): 'session_protocol' retruns string used by openssl (like TLSv1.2) Protocol : TLSv1.2 'fallback_protocol' Note: ouput from openssl: TLSv1.2 Note: output from Net::SSLeay: TLSv1_2 =head2 Note:Selected Cipher SEE Note:term default cipher. 'cipher_selected' returns the cipher as used in our data structure (like DHE-DES-CBC), this is the one selected if the client provided a list example (ouput from openssl): example Net::SSLeay: Net::SSLeay::get_cipher(..) =head2 Note:Connection test To avoid long timouts, a quick connection check to the target is done. At least the connection to the SSL port must succeed. If not, all checks are skipped. If just the connection to port 80 fails, just the HTTP checks are disabled. Also SEE Note:--ssl-error . The initial connection check just opens the port and does nothing. This is done because some methods, i.e. Net::SSLeay::get_http(), do not support timeout settings, which then results in "hanging" connections. =head2 Note:--ssl-error The option --ssl-error in conjunction with error counts --ssl-error-max and --ssl-error-total controls wether to try to connect to the target even if there are errors or timeouts. I.g. the used API IO::Socket:SSL, openssl returns an error in $!. Unfortunately the error may be different according the used version. Hence the check herein does not use the returned error but relies on the time passed during the connection. The assumtion (based on experiance) is, that successful or rejected connection take less than a second, even on slow connections. If the connection cannot be established (because not supported or blocked), we run into a timeout, which is always more than 0, at least 1 second (see --timeout=SEC option). Timeout cannot be set less than one second. Also measuring the times and their difference is in seconds. A more accurate time measurement requires the Time::Local module, which we try to avoid. Measureing within a second is sufficent for these checks. More descriptions are in the section LIMITATIONS of the man page, see "Connection Problems" there. =head2 Note:%prot Using SSL/TLS protocols can either be done using %prot or $cfg{'versions'} in contrast to "keys %prot" $cfg{'versions'} is sorted according protocol like: SSLv2 SSLv3 TLSv1 ... =head2 Note:--exitcode Ideas and discussions see also: https://github.com/OWASP/O-Saft/issues/52 By default --exitcode counts all settings considered weak or insecure. This behaviour can be controlled with the --exitcode-no-* options. =head2 Note:heartbleed http://heartbleed.com/ http://possible.lv/tools/hb/ http://filippo.io/Heartbleed/ https://github.com/proactiveRISK/Heartbleed https://www.cloudflarechallenge.com/heartbleed See also "--ignore-no-reply" description in o-saft-man.pm. Apache cannot disable heartbeat, see: ?? nginx cannot disable heartbeat, see: https://www.nginx.com/blog/nginx-and-the-heartbleed-vulnerability/ =head2 Note:ticketbleed =head2 Note:CGI mode Using the general concept of pipes which returns all results on STDOUT, it is possible that the tool operates as CGI script in a web server. However, some additional checks are necessary then to avoid misuse. * Disabled functionality in CGI mode: * early verbose messages are not printed * debug and trace is not allowed (disabled) * configuration cannot be read from files * Following checks must be done by the caller: * rejecting invalid target names * some dangerous options (i.e. --lib, --exe, etc. see o-saft.cgi) * checking parameters (options) for dangerous characters * The caller is also responsible to print proper HTTP headers. Following special options are avaiable for CGI mode: * --cgi - must be passed to o-saft.cgi as first parameter * --cgi-exec - must be set by caller only (i.g. o-saft.cgi) * --cgi-trace - print HTTP header (for debugging only) The option --cgi-trace is for debugging when used from command line only. It is recommended that this script is called by o-saft.cgi in CGI mode. =head2 Note:Option in CGI mode In CGI mode all options are passed with a trailing = even those which do not have an argument (value). This means that options cannot be ignored in general, because they may occour at least in CGI mode, i.e. --cmd= . The trailing = can always be removed, empty values are not possible. =head2 Note:Stand-alone A stand-alone script is a single script, which executes without any other module to be included (read) at run-time. Most modules --means modules in Perl context and syntax-- are already read using a private function _load_file(), which uses Perl's require instead of use. This way the modules are loaded at run-time (require) and not at compile-time (use). Unfortunately there exist modules, which must be loaded with Perl's use. When generating a stand-alone executable script, the complete file of each module is simply copied into the main script file (o-saft.pl usually). In that case, the corresponding use statement must be removed. Modules loaded with _load_file() read the files only if the variable $osaft_standalone does not exist. Please refer to the INSTALLATION section, in particular the sub-section Stand-alone Executable there, for more details on generating stand-alone scripts. Generating a stand-alone script is done by contrib/gen_standalone.sh . =head2 Note:root-CA Some texts from: http://www.zytrax.com/tech/survival/ssl.html The term Certificate Authority is defined as being an entity which signs certificates in which the following are true: * the issuer and subject fields are the same, * the KeyUsage field has keyCertSign set * and/or the basicConstraints field has the cA attribute set TRUE. Typically, in chained certificates the root CA certificate is the topmost in the chain but RFC 4210 defines a 'root CA' to be any issuer for which the end-entity, for example, the browser has a certificate which was obtained by a trusted out-of-band process. Since final authority for issuing any certificate rest with this CA the terms and conditions of any intermediate certificate may be modified by this entity. Subordinate Authority: may be marked as CAs (the extension BasicContraints will be present and cA will be set True) Intermediate Authority (a.k.a. Intermediate CA): Imprecise term occasionally used to define an entity which creates an intermediate certificate and could thus encompass an RA or a subordinate CA. Cross certificates (a.k.a. Chain or Bridge certificate): A cross-certificate is one in which the subject and the issuer are not the same but in both cases they are CAs (BasicConstraints extension is present and has cA set True). Intermediate certificates (a.k.a. Chain certificates): Imprecise term applied to any certificate which is not signed by a root CA. The term chain in this context is meaningless (but sounds complicated and expensive) and simply indicates that the certificate forms part of a chain. Qualified certificates: Defined in RFC 3739 the term Qualified certificates relates to personal certificates (rather than server certificates) and references the European Directive on Electronic Signature (1999/93/EC) see check02102() above Multi-host certificates (a.k.a wildcard certificates) EV Certificates (a.k.a. Extended Certificates): Extended Validation (EV) certificates are distinguished by the presence of the CertificatePolicies extension containg a registered OID in the policyIdentifier field. see checkev() above RFC 3280 4.2.1.10 Basic Constraints X509v3 Basic Constraints: cA:FALSE pathLenConstraint INTEGER (0..MAX) OPTIONAL ) RFC 4158 =head2 Note:term default cipher Technically SSL/TLS does not know about a "default cipher". Starting with TLSv1 it can provide a "prefered selected cipher". The server then selects a cipher which is common between its own list of ciphers and the list send by the client. The more correct term therfore is "prefered" or "selected" cipher. Many documents still use the term "default". Some code exists, which also uses "default" as part of variable or function names. =head2 Note:+cipherall SEE Note:term default cipher. In October 2017 (VERSION 17.09.17), the +cipherall command is no longer an alias for +cipherraw. It is now using the the same technique as +cipherraw to detect the targets ciphers, but prints the results like the traditional +cipher command. This has some impacts on computing other checks, like the default selected cipher, the strongest and weakest selected cipher. One problem is, that +cipher itself cannot detect the default cipher, so it uses the underlaying SSL library's methods to do it, see _get_default() which also computes the strongest and weakest selected cipher. When using +cipherraw another method to detect these ciphers must be used; this is not yet implemented completely. The problem should finally be solved when +cipher and +cipherraw use the same data structre for the results. Then the program flow should be like: ciphers_scan() checkciphers() printciphers() printciphersummary() =cut O-Saft-19.01.19/o-saft.pod000066400000000000000000005651331342117255600147650ustar00rootroot00000000000000#!/usr/bin/env perldoc #? # Generated by o-saft.pl . # Unfortunatelly the format in @help is incomplete, for example proper =over # and corresponding =back paragraph is missing. It is mandatory arround =item # paragraphs. However, to avoid tools complaining about that, =over and =back # are added to each =item to avoid error messages in the viewer tools. # Hence the additional identations for text following the =item are missing. # Tested viewers: podviewer, perldoc, pod2usage, tkpod =pod =encoding utf8 =head1 NAME O-Saft - OWASP SSL advanced forensic tool OWASP SSL audit for testers =head1 DESCRIPTION This tools lists information about remote target's SSL certificate and tests the remote target according given list of ciphers. Note: Throughout this description C<$0> is used as an alias for the program name C. =head1 SYNOPSIS o-saft.pl [COMMANDS ..] [OPTIONS ..] target [target target ...] where [COMMANDS] and [OPTIONS] are described below and target is a hostname either as full qualified domain name or as IP address. Multiple commands and targets may be combined. All commands and options can also be specified in a rc-file, see L below. I.g. all commands start with a C<+> character and options start with C<-> or C<--> characters. Anything else is treated as target name. =head1 QUICKSTART Before going into a detailed description of the purpose and usage, here are some examples of the most common use cases: =over =item * Show supported (enabled) ciphers of target: =back o-saft.pl +cipher --enabled example.tld =over =item * Show supported (enabled) ciphers with their DH parameters: =back o-saft.pl +cipher-dh example.tld =over =item * Test all ciphers, even if not supported by local SSL implementation: =back o-saft.pl +cipherall example.tld =over =item * Show details of certificate and connection of target: =back o-saft.pl +info example.tld =over =item * Check certificate, ciphers and SSL connection of target: =back o-saft.pl +check example.tld =over =item * Check connection to target for vulnerabilities: =back o-saft.pl +vulns example.tld =over =item * Check for all known ciphers (independant of SSL library): =back o-saft.pl +cipherraw example.tld --range=full checkAllCiphers.pl example.tld checkAllCiphers.pl example.tld I--range=full& I&--v&& =over =item * Get the certificate's Common Name for a bunch of servers: =back o-saft.pl +cn example.tld some.tld other.tld =over =item * List more usage examples =back o-saft.pl --help=examples =over =item * List all available commands: =back o-saft.pl --help=commands =over =item * Get table of contents for complete help =back o-saft.pl --help=toc =over =item * Show just one section, for example SECURITY, from help =back o-saft.pl --help=SECURITY =over =item * Start the simple GUI =back o-saft.tcl =over =item * Start the simple GUI which uses o-saft.pl in a Docker image =back o-saft.tcl I--docker&& For more specialised test cases, refer to the sections L and L below. For more examples please refer to L section. For more details, please see L and L below. =head1 WHY? Why a new tool for checking SSL security and configuration when there are already a dozen or more such good tools in existence (in 2012)? Unique features: =over =item * working in closed environments, i.e. without internet connection =back =over =item * checking availability of ciphers independent of installed library =back =over =item * checking for all possible ciphers (up to 65535 per SSL protocol) =back =over =item * mainly same results on all platforms. =back Currently available tools suffer from some or all of following issues: =over =item * lack of tests of unusual SSL certificate configurations =back =over =item * may return different results for the same checks on given target =back =over =item * missing tests for modern SSL/TLS functionality =back =over =item * missing tests for specific, known SSL/TLS vulnerabilities =back =over =item * no support for newer, advanced, features e.g. CRL, OCSP, EV =back =over =item * limited capability to create your own customised tests =back Other reasons or problems are that other tools are either binary or use additional binaries and hence are not portable to other platforms. In contrast to (all?) most other tools, including L, it can be used to "ask simple questions" like "does target support STS" just by calling: o-saft.pl +hsts_sts example.tld For more, please see L section below. If it should run on systems with old software (perl or perl modules), please see L section below. =head1 SECURITY This tool is designed to be used by people doing security or forensic analyses. Hence no malicious input is expected. There are no special security checks implemented. Some parameters are roughly sanatised according unwanted characters. In particular there are no checks according any kind of code injection. Care should be taken, when additional tools and modules are installed as described in L below. In particular it is recommended to do these installations into directoies specially prepared for use with o-saft.pl . No other tools of your system should use these installations i.e. by accident or because your environment variables point to them. Note that compilation and installation of additional tools (openssl, Net::SSLeay, etc.) uses known insecure configurations and features! This is essential to make o-saft.pl able to check for such insecurities. It is highly recommended to do these installations and use the tools on a separate testing system. B =head1 CONCEPTS The purpose of O-Saft is to do the work, not to force the user to learn a new tool or to install "newer" software first. However, the user "should do something" if necessary depending on the reported results. =head2 Results Results of checks are marked C or C. This leaves the proper interpretation, if the result is "good" or "bad", to the user. Background: it is not always possible to rate a result as "good" or "bad" or "insecure" or whatever. That's why O-Saft can not give the "the best" or a "proper" recomendation. In practice it depends on the context what a recomendation, or countermeasure should be. That's why all results are marked C or C if considered "questionable" or "not good" (for example according other checks). ... more comming soon ... =head1 TECHNICAL INFORMATION It is important to understand, which provided information is based on data returned by underlaying (used) libraries and the information computed directly. =head2 OpenSSL, libssl, libcrypto In general the tool uses perl's L module which itself is based on libssl and/or libssleay library of the operating system. It's possible to use other versions of these libraries, see options: =over =item * --exe-path=PATH --exe=PATH =back =over =item * --lib-path=PATH --lib=PATH =back =over =item * --envlibvar=NAME =back The external L is called to extract some information from its output. The version of openssl can be controlled with following options: =over =item * --openssl=TOOL =back =over =item * --no-openssl =back =over =item * --force-openssl =back =over =item * --exe-path=PATH --exe=PATH =back Above applies to all commands except I<+cipherall> and I<+cipherraw> which uses no other libraries. OpenSSL is recommended to be used for libssl and libcrypto. Versions 0.9.8k to 1.0.2e (Jan. 2016) are known to work. However, versions be- for 1.0.0 may not provide all informations. LibreSSL is not recommended, because some functionallity considered insecure, has been removed. For more details, please see L below. =head2 Certificates and CA All checks according the validity of the certificate chain are based on the root CAs installed on the system. NOTE that L and L may have their own rules where to find the root CAs. Please refer to the documentation on your system for these tools. However, there are folloing options to tweak these rules: =over =item * --ca-file=FILE =back =over =item * --ca-path=DIR =back =over =item * --ca-depth=INT =back =head2 Commands and options All arguments starting with C<+> are considered L for this tool. All arguments starting with C<--> are considered L for this tool. Reading any data from STDIN or here-documents is not yet supported. It's reserved for future use. =head2 Environment variables Following environment variables are incorporated: =over =item * LD_LIBRARY_PATH - used and extended with definitions from options =back =over =item * OPENSSL - if set, full path to openssl executable =back =over =item * OPENSSL_CONF - if set, full path to openssl's openssl.cnf or =back directory where to find openssl.cnf =head2 Requirements For checking all ciphers and all protocols with I<+cipherall> command, just perl (5.x) without any modules is required. For I<+info> and I<+check> (and all related) commands, perl (5.x) with following modules (minimal version) is recommended: =over =item * IO 1.25 (2011) =back =over =item * IO::Socket::INET 1.37 (2011) =back =over =item * IO::Socket::SSL 1.90 (2013) =back =over =item * Net::DNS 0.66 (2011) =back =over =item * Net::SSLeay 1.49 (2012) =back However, it is recommended to use the most recent version of the mod- ules which then gives more accurate results and less warnings. If the modules are missing, they can be installed i.e. with: cpan Net::SSLeay Note: if you want to use advanced features of openssl or Net::SSLeay, please see L section how to compile and install the tools fully customized. Also an openssl executable should be available, but is not mandatory. For checking DH parameters of ciphers, openssl 1.0.2 or newer should be available. If an older version of openssl is found, we try hard to extract the DH parameters from the data returned by the server, see I<+cipher-dh> command. If you need to run on systems with older perl or perl module versions please refer to the L section for more inofrmation. =head1 RESULTS All output is designed to be easily parsed by postprocessors. Please see L section below for details. For the results, we have to distinguish those returned by I<+cipher> command and those from all other tests and checks like I<+check> or I<+info> command. =head3 +cipher The cipher checks will return one line for each tested cipher. It contains at least the cipher name, C or C whether it is supported or not, and a security qualification. It may look like: AES256-SHA yes HIGH NULL-SHA no weak Depending on the used I<--legacy=*> option the format may differ and also contain more information. For details see I<--legacy=*> option below. The text for security qualifications are (mainly) those returned by openssl (version 1.0.1): LOW, MEDIUM, HIGH and WEAK. The same texts, but with all lower case characters, are used if the qualification was adapted herein. Following rules for adjusting the qualification were used: =over =item * weak: =back =over =item ** all *NULL* ciphers =back =over =item ** all *RC2* and *RC4* ciphers =back =over =item ** all *EXPORT* ciphers =back =over =item ** all *anon* (aka ADH aka DHA) ciphers =back =over =item ** all *CBC* and *CBC3* (aka 3DES) and DES ciphers =back =over =item * low: =back =over =item * high: =back =over =item ** all *AES(128|256)* ciphers =back =over =item ** all *CAMELLIA* ciphers =back =head3 +check These tests return a line with a label describing the test and a test result for it. The idea is to report C if the result is considered "secure" otherwise report C followed by the reason why it's considered insecure. Example of a check considered secure: Label of the performed check: yes Example of a check considered insecure: Label of the performed check: no (reason why) Note that there are tests where the results appear confusing when first viewed, like for www.wi.ld: Certificate is valid according given hostname: no (*.wi.ld) Certificate's wildcard does not match hostname: yes This can for example occur with: Certificate Common Name: *.wi.ld Certificate Subject's Alternate Names: DNS:www.wi.ld Please check the result with the I<+info> command also to verify if the check sounds reasonable. =head3 +info The test result contains detailed information. The labels there are mainly the same as for the I<+check> command. =head1 COMMANDS There are commands for various tests according the SSL connection to the target, the targets certificate and the used ciphers. All commands are preceded by a C<+> to easily distinguish from other arguments and options. However, some I<--OPTIONS> options are treated as commands for historical reason or compatibility to other programs. The most important commands are (in alphabetical order): I<+check> I<+cipher> I<+info> I<+http> I<+list> I<+quick> I<+sni> I<+sni_check> I<+version> A list of all available commands will be printed with: o-saft.pl --help=cmds The description of all other commands will be printed with: o-saft.pl --header --help=commands The summary and internal commands return requested information or the results of checks. These are described below. Note that some commands may be a combination of other commands, see: o-saft.pl --header --help=intern The following sub-sections only describe the commands, which do more than giving a simple information from the target. All other commands can be listed with: o-saft.pl --header --help=commands The final sub-sections L describes some notes about special commands and related commands. =head2 Commands for information about this tool All these commands will exit after execution (cannot be used together with other commands). =head3 +ciphers Show ciphers offered by local SSL implementation. This commands prints the ciphers in a format like "openssl ciphers" does. It also accepts the -v and -V option. The I<--legacy=TYPE> option can be used as described for I<+list> command. Use I<+list> command for more information according ciphers. =head3 +list Show all ciphers supported by this tool. This includes cryptogrphic details of the cipher and some internal details about the rating. In contrast to the I<+ciphers> command, I<+list> uses TAB characters instead of spaces to seperate columns. It also prints table header lines by default. Different output formats are used for the I<--legacy> option: =over =item * --legacy=simple tabular output of cipher values =back =over =item * --legacy=full as --legacy=simple but more data =back =over =item * --legacy=openssl output like with +ciphers command =back =over =item * --legacy=ssltest output like "ssltest --list" =back =head3 +VERSION Just show version and exit. =head3 +version Show version information for both the program and the Perl modules that it uses, then exit. Use I<--v> option to show more details. =head3 +libversion Show version of openssl. =head3 +quit Show internal data and exit, used for testing and debugging only. Please see L below. =head2 Commands to check SSL details Following (summary and internal) commands are simply a shortcut for a list of other commands. For details of the list use: o-saft.pl --help=intern =head3 +check Check the SSL connection for security issues. Implies I<+cipher> . =head3 +host Print details about the targets hostname, DNS, etc. These details are usually printed only for the I<+check> and I<+info> command, but not for any individual command. =head3 +http Perform HTTP checks (like STS, redirects etc.). =head3 +info Overview of most important details of the SSL connection. Use I<--v> option to show details also, which span multiple lines. =head3 +info--v Overview of all details of the SSL connection. It is a shortcut for all commands listed below but not including I<+cipher>. This command is intended for debugging as it prints some details of the used L module. =head3 +quick Quick overview of checks. Implies I<--enabled> and I<--label=short>. =head3 +pfs Check if servers offers ciphers with prefect forward secrecy (PFS). =head3 +protocols Check for protocols supported by target. =head3 +vulns Check for various vulnerabilities. =head3 +sts =head3 +hsts Various checks according STS HTTP header. This option implies I<--http>, means that I<--no-http> is ignored. =head3 +sni Check for Server Name Indication (SNI) usage. =head3 +sni_check =head3 +check_sni Check for Server Name Indication (SNI) usage and validity of all names (CN, subjectAltName, FQDN, etc.). =head3 +bsi Various checks according BSI TR-02102-2 and TR-03116-4 compliance. =head3 +ev Various checks according certificate's extended Validation (EV). Hint: use option I<--v> I<--v> to get information about failed checks. =head3 +sizes Check length, size and count of some values in the certificate. =head3 +s_client Dump data retrieved from "openssl s_client ..." call. This should be used for debugging only. It can be used just like openssl itself, for example: openssl s_client -connect host:443 -no_sslv2 =head3 +dump Dumps internal data for SSL connection and target certificate. This is mainly for debugging and should not be used together with other commands (except I<+cipher>). Each key-value pair is enclosed in C<#{> and C<#}> . Using I<--trace> I<--trace> dumps data of L too. =head3 +exec Command used internally when requested to use other libraries. This command should not be used directly. =head2 Commands to test ciphers provided by target Beside the description of the commands itself here, please see also L below. =head3 +cipher Check target for ciphers, either all ciphers, or ciphers specified with I<--cipher=CIPHER> option. Note that ciphers not supported by the local SSL implementation are not checked by default, use I<+cipherall> or I<+cipherraw> command. Use I<--v> option to see all ciphers being checked. =head3 +cipherraw Check target for all possible ciphers. Does not depend on local SSL implementation. In contrast to I<+cipher> this command has some options to tweak the cipher tests, connection results and some strange behaviours of the target. See L for details. =head3 +cipherall Same as I<+cipherraw> but ouput format similar to I<+cipher> command. =head3 +cipher-default Lists the cipher selected by the server for each protocol sometimes referred to as "default cipher". For each protocol the two selected ciphers are shown, one returned by the server if the cipher list in the ClientHello is sorted with the strongest cipher first, and one returned if the cipher list in the ClientHello is sorted with strongest cipher last. See L for details. =head3 +cipher-dh Checked target for ciphers. All ciphers supported by the server are printed with their DH or ECDH paramaters (if available). ciphers. =head3 +null =head3 +cipher-null Check if target accepts NULL ciphers. =head3 +adh =head3 +cipher-adh Check if target accepts ciphers with anonymous key exchange. =head3 +export =head3 +cipher-exp Check if target accepts EXPORT ciphers. =head3 +cbc =head3 +cipher-cbc Check if target accepts CBC ciphers. =head3 +des =head3 +cipher-des Check if target accepts DES ciphers. =head3 +cipher-rc4 Check if target accepts RC4 ciphers. =head3 +edh =head3 +cipher-edh Check if target supports ephemeral ciphers. =head3 +cipher-pfs Check if target supports ciphers with PFS. =head3 +cipher-strong Check if target selects strongest cipher. =head3 +cipher-weak Check if target selects weak cipher (oposite of I<+cipher-strong>). =head2 Discrete commands to test SSL connection and certificate details Discrete commands, please see: o-saft.pl --help=commands =head2 Notes about commands =head3 +cipher vs. +cipherall I<+cipher> can only check for ciphers - more precise: cipher suites - provided by the local SSL implementation (i.e. libssl). I<+cipherall> can check for any cipher, as it just uses the cipher's integer value in the range 0 .. 65532. =head3 +cipherall vs. +cipherraw These commands are identical, just the output format is different. =head3 +cipher vs. +cipher-dh While I<+cipher> prints checked ciphers, I<+cipher-dh> prints ciphers with their DH or ECDH paramaters (if available) only for supported ciphers. =head3 +cipher vs. +cipher-default Both commands show the default cipher foreach protocol. I<+cipher> lists a summary of ciphers selected by the server for each protocol requested by the user (for example by using options like: I<--sslv3> I<--tlsv1> etc.). When the I<--v> option is used, all selected ciphers for all known protocols are listed. This summary focuses on counts for various ciphers. I<+cipher-default> lists the cipher selected by the server for each protocol. =head3 +cipher-selected vs. +cipher-default I<+selected> lists the cipher selected by the server if no particular protocol was specified and the system's default cipher list is send in the ClientHello to the server. I<+cipher-default> lists the cipher selected by the server for each protocol. =head3 +cipher-strong vs. +cipher-default I<+strong-cipher> shows the result of the check if strong ciphers are preferred by the server. It is a check command. I<+cipher-default> lists the cipher selected by the server for each protocol. It is a information command. It is not possible to check if a server uses C. Even if it is used (switched on), it is not possible to check the specified order of the ciphers. I. g. it is expected that the order is according the cipher suite's strength, meaning the most strongest first, and the weakest last. It does not make sense to use an order where a weak cipher preceeds a stronger one. Such a (mis-)configuration should be detected. Having this in mind, the algorithm to detect a proper cipher order is as simply as follows: 1. pass sorted cipher list with strongest cipher first 2. pass sorted cipher list with strongest cipher last if the server returns the same cipher for both checks, it's assumed that it prefers to use the most strongest cipher. In this case it's obvious that C is set (exceptions see below). I<+cipherall> uses a more accurate algorithm to detect the server's cipher order. Exceptions: If either, the server or the client, uses only one cipher suite in the list, SSLHonorCipherOrder cannot be detected at all. The same happens, if only one cipher in the client's list matches a cipher in the server's list. =head3 +extensions vs. +tlsextensions I<+extensions> shows the "Certificate extensions" and I<+tlsextensions> will show the TLS protocol extensions. Use I<+tlsextdebug> to show more informations about the TLS protocol extensions. =head3 +http2 +spdy +spdy3 +spdy31 +spdy4 +prots These commands are just an alias for the I<+protocols> command. =head3 +hostname vs. +wildhost vs. +altname vs. +rfc_2818 The commands I<+cn> and I<+altname> print the information stored in the certificate. The command I<+hostname> checks if the given hostname matches the CN value in the certificate. Note that wildcard names in the CN, only allow to contain one C<*>. The command I<+wildcard> checks if the given hostname does not match any name specified in the certificate's "subjectAltname". This check is usefull if the certificate and the configuration must comply to RFC 6125 or EV certificates. =head1 OPTIONS All options are written in lowercase. Words written in all capital in the description here is text provided by the user. =head2 Options for help and documentation =head3 --h =head3 --help B =head3 --help=cmds Show available commands; short form. =head3 --help=commands Show available commands with short description. =head3 --help=opt Show available options; short form. =head3 --help=options Show available options with their description. =head3 --help=checks Show available checks. =head3 --help=tools Description of tools around O-Saft, when, where and how to use. =head3 --help=cmd Show additional and user specified commands. =head3 --help=cfg-cmd Show additional and user specified commands. Output can be use in L or as option. =head3 --help=check-cfg =head3 --help=cfg-check Show texts used as labels in output for checks (see I<+check>) ready for use in L or as option. =head3 --help=data Show available informations. =head3 --help=data-cfg =head3 --help=cfg-data =head3 --help=cfg-info Show texts used as labels in output for data (see I<+info>) ready for use in L or as option. =head3 --help=hint Show texts used in hint messages. =head3 --help=hint-cfg =head3 --help=cfg-hint Show texts used in hint messages ready for use in L or as option. =head3 --help=text Show texts used in various messages. =head3 --help=text-cfg =head3 --help=cfg-text Show texts used in various messages ready for use in L or as option. =head3 --help=legacy Show possible legacy formats (used as value in I<--legacy=TOOL>). =head3 --help=compliance Show available compliance checks. =head3 --help=intern Show internal commands. =head3 --help=alias Show alias for commands and options. =head3 --help=pattern Show list of cipher pattern (used for I<--cipher=CIPHER>). =head3 --help=range Show list of cipherranges (see I<--cipherrange=RANGE>). =head3 --help=score Show score value for each check. Value is printed in format to be used for I<--cfg-score=KEY=SCORE>. Note that the sequence of options is important. Use the options I<--trace> and/or I<--cfg-score=KEY=SCORE> before I<--help=score>. =head3 --help=toc =head3 --help=content Show headlines from help text. Useful to get an overview. =head3 --help=SECTION Show C
    from documentation, see I<--help=toc> for a list. Example: o-saft.pl --help=EXAMPLES =head3 --help=ourstr Show regular expressions to match our own strings used in output. =head3 --help=regex Show regular expressions used internally. =head3 --help=gen-html Print documentation in HTML format. =head3 --help=gen-pod Print documentation in POD format. =head3 --help=gen-wiki Print documentation in mediawiki format. =head3 --help=gen-cgi Print documentation in format to be used for CGI. =head3 --help=error =head3 --help=warning =head3 --help=problem Show L section with description of known error and warning messages. =head3 --help=faq Show L and L section. =head3 --help=glossary Show common abbreviation used in the world of security. =head3 --help=links Show list of URLs related to SSL/TLS. =head3 --help=rfc Show list of RFC related to SSL/TLS. =head3 --help=todo Show known problems and bugs. =head3 --help=exit Show possible I<--exit=KEY> options. Used for debugging only. =head3 --help=program.code For developers. =head2 Options for all commands (general) =head3 --dns Do DNS lookups to map given hostname to IP, do a reverse lookup. =head3 --no-dns Do not make DNS lookups. Note that the corresponding IP and reverse hostname may be missing in some messages then. =head3 --host=HOST Specify HOST as target to be checked. Legacy option. =head3 --port=PORT Specify PORT of target to be used. Legacy option. =head3 --host=HOST --port=PORT HOST:PORT HOST When giving more than one HOST argument, the sequence of the given HOST argument and the given I<--port=PORT> and the given I<--host=HOST> options are important. The rule how ports and hosts are mapped is as follows: HOST:PORT arguments are used as is (connection to HOST on PORT) only HOST is given, then previous specified I<--port=PORT> is used Note that URLs are treated as HOST:PORT, if they contain a port. Example: o-saft.pl +cmd host-1 --port 23 host-2 host-3:42 host-4 will connect to: =over =item * host-1:443 =back =over =item * host-2:23 =back =over =item * host-3:42 =back =over =item * host-4:23 =back =head3 --proxyhost=PROXYHOST --proxy=PROXYHOST:PROXYPORT Make all connection to target using PROXYHOST. Also possible is: I<--proxy=PROXYUSER:PROXYPASS@PROXYHOST:PROXYPORT> =head3 --proxyport=PROXYPORT Make all connection to target using PROXYHOST:PROXYPORT. =head3 --proxyuser=PROXYUSER Specify username for proxy authentication. =head3 --proxypass=PROXYPASS Specify password for proxy authentication. =head3 --starttls Use C command to start a TLS connection via SMTP. This option is a shortcut for I<--starttls=SMTP> . =head3 --starttls=SMTP =head3 --starttls=PROT Use C command to start a TLS connection via protocol. C may be any of: C, C, C, C, C, C, C or C . For I<--starttls=SMTP> see I<--dns-mx> also to use MX records instead of host =head3 --starttls-delay=SEC Number of seconds to wait before sending a packet, to slow down the C requests. Default is 0. This may prevent blocking of requests by the target due to too much or too fast connections. Note: In this case there is an automatic suspension and retry with a longer delay. =head3 --cgi =head3 --cgi-exec Internal use for CGI mode only. =head2 Options for SSL tool =head3 --rc Read L if exists, from directory where program was found. =head3 --no-rc Do not read L. =head3 --exitcode The exit status code will be greater 0, if any of following applies: =over =item * any check returns C =back =over =item * insecure protocols are available =back =over =item * insecure ciphers are supported =back =over =item * ciphers without PFS are supported (disable with --exitcode-cipher) =back In particular, the status code will be the total count of all these checks. Parts of these checks can be diasabled, see I<--exitcode-*> options below. Functionality implemented experimental, may change in future. =head3 --exitcode-no-checks Do not count checks with result C for I<--exitcode> . =head3 --exitcode-no-low --exitcode-no-weak --exitcode-no-medium Do not count LOW, WEAK or MEDIUM security ciphers for I<--exitcode> . =head3 --exitcode-no-ciphers Do not count any ciphers for I<--exitcode> . =head3 --exitcode-no-ciphers Do not count any ciphers for I<--exitcode> . =head3 --exitcode-no-pfs Do not count ciphers without PFS for I<--exitcode> . =head3 --openssl-s_client --s_client Use "openssl s_slient ..." call to retrieve more information from the SSL connection. This is disabled by default on Windows because of performance problems. Without this option (default on Windows !) following informations are missing: compression, expansion, renegotiation, resumption, selfsigned, verify, chain, protocols, DH parameters See L for details. If used together with I<--trace>, s_client data will also be printed in debug output of L. =head3 --no-openssl Do not use external "openssl" tool to retrieve information. Use of "openssl" is disabled by default on Windows. Note that this results in some missing informations, see above. =head3 --openssl=TOOL C can be a path to openssl executable; default: openssl =head3 --openssl-cnf=FILE --openssl-conf=FILE C path of directory or full path of openssl.cnf If set, environment variable OPENSSL_CONF will be set to given path (or file) when L is started. Please see openssl's man page for details about specifying alternate openssl.cnf files. =head3 --openssl-ciphers --force-openssl Use openssl to check for supported ciphers; default: L This option forces to use "openssl s_slient -connect CIPHER .." to check if a cipher is supported by the remote target. This is useful if the I<--lib=PATH> option doesn't work (for example due to changes of the API or other incompatibilities). =head3 --exe-path=PATH =head3 --exe=PATH C is a full path where to find openssl. =head3 --lib-path=PATH =head3 --lib=PATH C is a full path where to find libssl.so, libcrypto.so. See L below for a detailed description how it works. =head3 --envlibvar=NAME C is the name of a environment variable containing additional paths for searching dynamic shared libraries. Default is LD_LIBRARY_PATH. Check your system for the proper name, i.e.: DYLD_LIBRARY_PATH, LIBPATH, RPATH, SHLIB_PATH. =head3 --ssl-error The connection to a target may fail, or even block, due to various reasons for example lost network at all, blocking at firewall, etc. In particular when checking ciphers with I<+cipher> , this may result in long delays until results are printed. Using this option stops trying to do more connections to the target when I<--ssl-error-max=CNT> consecutive errors occoured, or when the total amount of errors increases I<--ssl-error-total=CNT>. Note that this may result in loss of information and/or checks. =head3 --ssl-error-max=CNT Max. amount of consecutive errors (default: 5). =head3 --ssl-error-timeout=SEC Timeout in seconds when a failed connection is treated as error and then counted (default: 1). =head3 --ssl-error-total=CNT Max. total amount of errors (default: 10). =head3 --ssl-lazy I.g. this tools tries to identify available functionality according SSL versions from the underlaying libraries. Unsupported versions are then disables and a warning is shown. Unfortunately some libraries have not implemented all functions to check availability of a specific SSL version, which then results in a compile error. This option disables the strict check of availability. If the underlaying library doesn't support the required SSL version at all, following error may occour: Can't locate auto/Net/SSLeay/CTX_v2_new.al in @INC ... See L for a general note about SSL versions. A more detailled description of the problem and how Net::SSLeay be- haves, can be found in the source of o-saft.pl , see section starting at #| check for supported SSL versions =head3 --timeout=SEC Timeout in seconds when connecting to the target (default: 2). =head3 --call=METHOD C method to be used for specific functionality Available methods: =over =item * info-socket use internal socket to retrieve information =back =over =item * info-openssl use external openssl to retrieve information =back =over =item * info-user use usr_getinfo() to retrieve information =back =over =item * cipher-socket use internal socket to ckeck for ciphers =back =over =item * cipher-openssl use external openssl to ckeck for ciphers =back =over =item * cipher-user use usr_getciphers() to ckeck for ciphers =back Method names starting with: =over =item * info- =back are responsible to retrieve information about the SSL connection and the target certificate (i.e. what the I<+info> command provides) =over =item * cipher- =back are responsible to connect to the target and test if it supports the specified ciphers (i.e. what the I<+cipher> command provides) =over =item * check- =back are responsible for performing the checks (i.e. what's shown with the I<+check> command) =over =item * score- =back are responsible to compute the score based on check results The second part of the name denotes which kind of method to call: =over =item * socket the internal functionality with sockets is used =back =over =item * openssl the exteranl openssl executable is used =back =over =item * user the external special function, as specified in user's =back o-saft-usr.pm, is used. Example: --call=cipher-openssl will use the external L executable to check the target for supported ciphers. Default settings are: --call=info-socket --call=cipher-socket --call=check-socket Just for curiosity, instead of using: o-saft.pl --call=info-user --call=cipher-user --call=check-user --call=score-user ... consider to use your own script like: #!/usr/bin/env perl usr_getinfo();usr_getciphers();usr_checkciphers();usr_score(); :-)) =head3 -v Print list of ciphers in style like: "openssl ciphers -v". Option used with I<+ciphers> command only. =head3 -V Print list of ciphers in style like: "openssl ciphers -V". Option used with I<+ciphers> command only. =head2 Options for SSL connection to target =head3 --cipher=CIPHER =over =item * C can be any string accepeted by openssl or following: =back =over =item * C use all ciphers from list defined herein, see +list =back Beside the cipher names accepted by openssl, CIPHER can be the name of the constant or the (hex) value as defined in openssl's files. Currently supported are the names and constants of openssl 1.0.1k. Example: =over =item * --cipher=DHE_DSS_WITH_RC4_128_SHA =back =over =item * --cipher=0x03000066 =back =over =item * --cipher=66 =back will be mapped to C Note: if more than one cipher matches, just one will be selected. Default is C as specified in L. =head3 --socket-reuse TCP socket will be reused for next connection attempt even if SSL connection failed. =head3 --no-socket-reuse Close TCP socket and then reopen for next connection attempt if SSL connection failed. This is useful for some servers which may return an "TLS alert" if the connection fails and then fail again on the same socket. =head3 --ignore-no-connect A simple check if the target can be connected will be performed by default. If this check fails, the target will be ignored, means no more requested checks will be done. As this connection check some- times fails due to various reasons, the check can be disabled using this option. =head3 --no-md5-cipher Do not use *-MD5 ciphers for other protocols than SSLv2. This option is only effective with I<+cipher> command. The purpose is to avoid warnings from L like: Use of uninitialized value in subroutine entry at lib/IO/Socket/SSL.pm line 430. which occours with some versions of L when a *-MD5 ciphers will be used with other protocols than SSLv2. Note that these ciphers will be checked for SSLv2 only. =head3 --sslv2 =head3 --sslv3 =head3 --tlsv1 =head3 --tlsv11 =head3 --tlsv12 =head3 --tlsv13 =head3 --dtlsv09 =head3 --dtlsv1 =head3 --dtlsv11 =head3 --dtlsv12 =head3 --dtlsv13 =head3 --SSL, -protocol SSL =head3 --no-sslv2 =head3 --no-sslv3 =head3 --no-tlsv1 =head3 --no-tlsv11 =head3 --no-tlsv12 =head3 --no-tlsv13 =head3 --no-dtlsv09 =head3 --no-dtlsv1 =head3 --no-dtlsv11 =head3 --no-dtlsv12 =head3 --no-dtlsv13 =head3 --no-SSL =over =item * C can be any of: =back ssl, ssl2, ssl3, sslv2, sslv3, tls1, tls1, tls11, tls1.1, tls1-1, tlsv1, tlsv11, tlsv1.1, tlsv1-1 (and similar variants for tlsv1.2). For example: I<--tls1> I<--tlsv1> I<--tlsv1_1> are all the same. (--SSL variants): Test ciphers for this SSL/TLS version. (--no-SSL variants): Don't test ciphers for this SSL/TLS version. =head3 --no-tcp Shortcut for: I<--no-sslv2> I<--no-sslv3> I<--no-tlsv1> I<--no-tlsv11> I<--no-tlsv12> I<--no-tlsv13> =head3 --tcp Shortcut for: I<--sslv2> I<--sslv3> I<--tlsv1> I<--tlsv11> I<--tlsv12> I<--tlsv13> =head3 --no-udp Shortcut for: I<--no-dtlsv09> I<--no-dtlsv1> I<--no-dtlsv11> I<--no-dtlsv12> I<--no-dtlsv13> =head3 --udp Shortcut for: I<--dtlsv09> I<--dtlsv1> I<--dtlsv11> I<--dtlsv12> I<--dtlsv13> =head3 --nullsslv2 This option forces to assume that SSLv2 is enabled even if the target does not accept any ciphers. The target server may accept connections with SSLv2 but not allow any cipher. Some checks verify if SSLv2 is enabled at all, which then would result in a failed test. The default behaviour is to assume that SSLv2 is not enabled if no ciphers are accepted. =head3 --http Make a HTTP request if cipher is supported. If used twice debugging will be enabled using environment variable C. =head3 --no-http Do not make HTTP request. =head3 --sni Make SSL connection in SNI mode. =head3 --no-sni Do not make SSL connection in SNI mode (default: SNI mode). =head3 --sni-toggle =head3 --toggle-sni Test with and witout SNI mode (+cipherall only). =head3 --force-sni Do not check if SNI seems to be supported by L. Older versions of openssl and its libries do not support SNI or the SNI support is implemented buggy. By default it's checked if SNI is properly supported. With this option this check can be disabled. Be warned that this may result in improper results. =head3 --servername=NAME =head3 --sni-name=NAME If SNI mode is active, see I<--sni> above, C is used instead of hostname for connections to the target. If SNI mode is not active, see I<--no-sni> above, C is not used. The default is undefined, which forces to use the given FQDN. This is useful, for example when an IP instead of a FQDN was given, where a correct hostname (i.g. a FQDN) needs to be specified. Note: i.g. there is no need to use this option, as a correct value for the SNI name will be choosen automatically (except for IPs). However, it is kind of fuzzing ... even setting to an empty string is possible. Limitation: the same C is used for all targets, if more than one target was specified. =head3 --no-cert Do not get data from target's certificate, return empty string. =head3 --no-cert --no-cert Do not get data from target's certificate, return default string of L (see I<--no-cert-text=TEXT> option). =head3 --no-cert-text=TEXT Set C to be returned from L if no certificate data is collected due to use of I<--no-cert>. =head3 --ca-depth=INT Check certificate chain to depth C (like openssl's -verify). =head3 --ca-file=FILE Use C with bundle of CAs to verify target's certificate chain. =head3 --ca-path=DIR Use C where to find CA certificates in PEM format. =head3 --ca-force =head3 --force-ca B I. g. openssl uses default settings where to find certificate files. When I<--ca-file=FILE> and/or I<--ca-path=DIR> was used, this default will be overwritten by appropriate options passed to openssl. If the default does not work as expected, I<--force-ca> can be used to force setting of proper values according well known common defaults. See: o-saft.pl +version o-saft.pl +version --force-ca to see the used settings. =head3 --alpn Use -alpn option for openssl. =head3 --no-alpn Do not use -alpn option for openssl. =head3 --no-npn =head3 --no-nextprotoneg Do not use -nextprotoneg option for openssl. =head3 --proto-alpn=NAME Name of protocol to be added to list of applcation layer protocols (ALPN), which is used for any connection to the targets. See I<--cipher-alpn=NAME> also. =head3 --proto-npn=NAME Name of protocol to be added to list of next protocol negotiations (NPN), which is used for any connection to the targets. See I<--cipher-npn=NAME> also. =head3 --ssl-compression --compression Use SSL option "compression" for connection. =head3 --no-ssl-compression --no-compression Use SSL option "no compression" for connection (default: don't use) =head3 --no-reconnect Do not use -reconnect option for openssl. =head3 --no-tlsextdebug Do not use -tlsextdebug option for openssl. =head3 --sclient-opt=VALUE Argument or option passed to openssl's s_client command. =head2 Options for +cipher command =head3 --connect-delay=SEC Additional delay in seconds after each connect for a cipher check. This is useful when connecting to servers which have IPS in place, or are slow in accepting new connections or requests. =head3 --cipher-alpn=NAME Name of protocol to be added to list of applcation layer protocols (ALPN), which is used for cipher checks. I<--cipher-alpn=>, sets empty list. I<--cipher-alpn=>,, sets list to empty element "". =head3 --cipher-npn=NAME Name of protocol to be added to list of next protocol negotiations (NPN), which is used for cipher checks. I<--cipher-npn=>, sets empty list. I<--cipher-npn=>,, sets list to empty element "". Note: setting empty list or element most likely does not work with openssl executable (i.e. I<--force-openssl>). =head3 --cipher-curve=NAME Name of ecliptic curve to be added to list of ecliptic curves (EC), which is used for cipher checks. I<--cipher-curve=>, sets empty list. I<--cipher-curve=>,, sets list to empty element "". Note: setting empty list or element most likely does not work with openssl executable (i.e. I<--force-openssl>). =head2 Options for cipherall and cipherraw command =head3 --range=RANGE =head3 --cipherrange=RANGE Specify range of cipher constants to be tested by I<+cipherall>. Following RANGEs are supported: =over =item * C all ciphers defined in various RFCs =back =over =item * C C, shifted by 64 bytes to the right =back =over =item * C like C but more lazy list of constants =back =over =item * C all constants 0x03000000 .. 0x0300FFFF =back =over =item * C all constants 0x03000000 .. 0x032FFFFF =back =over =item * C all constants 0x03000000 .. 0x03FFFFFF =back =over =item * C all ciphers according RFC for SSLv2 =back =over =item * C more lazy list of constants for SSLv2 ciphers =back Note: C is the internal list used for testing SSLv2 ciphers. It does not make sense to use it for other protocols; however ... =head3 --slow-server-delay=SEC Additional delay in seconds after the server is connected using a proxy or before starting C. This is useful when connecting via slow proxy chains or connecting to slow servers before sending the C sequence. =head3 --ssl-maxciphers=CNT Maximal number of ciphers sent in a sslhello (default: 32). =head3 --ssl-double-reneg Send SSL extension C even if list of ciphers includes C (default: do not include) =head3 --ssl-nodata-nocipher Some servers do not answer (i.g. they disconnect) if none of the offered ciphers is supported by the server. Continue testing with next ciphers when the target disconnects or does not send data within specified timeout (see I<--timeout>). Useful for TLS intolerant servers. =head3 --no-ssl-nodata-nocipher Abort testing with next ciphers when the target disconnects. =head3 --ssl-use-ecc Use supported elliptic curves. Default on. =head3 --ssl-use-ec-point Use TLS C extension. Default on. =head3 --ssl-use-reneg Test for ciphers with "secure renegotiation" flag set. Default: don't set "secure renegotiation" flag. =head3 --ssl-retry=CNT Number of retries when connection timed-out (default: 2). =head3 --ssl-timeout=SEC Number of seconds to wait until connection is qualified as timeout. =head3 --dns-mx =head3 --mx Get DNS MX records for given target and check the returned targets. (only useful with I<--starttls=SMTP>). =head2 Options for checks and results Options used for I<+check> command: =head3 --enabled Only print result for ciphers accepted by target. =head3 --disabled Only print result for ciphers not accepted by target. =head3 --ignorecase Checks are done case insensitive. =head3 --no-ignorecase Checks are done case sensitive. Default: case insensitive. Currently only checks according CN, alternate names in the target's certificate compared to the given hostname are effected. =head3 --ignore-no-reply When checking for the TLS "heartbeat" extension, the server may not respond at all, which would result in a "no reply" message. This marks the check for I<+heartbleed> as C. I.g. a server is not vulnerable to the heartbleed attack if the TLS "heartbeat" extension is disabled. Hence the check result C may be mis-leading. This option treats the "no reply" result as "not vulnerable" and returns C then. Note: if the server does not respond for this check, does not mean that the "heartbeat" extension is switched off. If unsure, disable this lazy check with I<--no-ignore-no-reply> . =head2 Options for output format =head3 --label=TYPE Defines the format of the descriptive text (label) for I<+check> and I<+info> command. Following Cs are supported: =head3 --label=long Prints full text for labels: Certificate Common Name: some.tld =head3 --label=short Prints short less descriptive text for labels: Common Name: some.tld =head3 --label=key Internal format: print name of key instead of text as label. Key is Prints name of key instead of text as label. The key is that of the internal data structure(s). [cn] some.tld For ciphers and protocols, the corresponding hex value is used as key. Note that these values are unique. =head3 --legacy=TOOL For compatibility with other tools, the output format used for the result of the I<+cipher> command can be adjusted to mimic the format of other SSL testing tools. The argument to the I<--legacy=TOOL> option is the name of the tool to be simulated. Following TOOLs are supported: =over =item * C format of output similar to sslaudit =back =over =item * C format of output similar to ssl-cipher-check =back =over =item * C format of output similar to ssldiagnos =back =over =item * C format of output similar to sslscan =back =over =item * C format of output similar to ssltest =back =over =item * C format of output similar to ssltest -g =back =over =item * C format of output similar to ssltest -g =back =over =item * C format of output similar to sslyze =back =over =item * C same as sslcipher =back =over =item * C format of output similar to ssl-cert-check =back =over =item * C format of output similar to TestSSLServer.jar =back =over =item * C format of output similar to THCSSLCheck =back Note that these legacy formats only apply to output of the checked ciphers. Other texts like headers and footers are adapted slightly. Please do not expect identical output as the TOOL when using these options, it's a best guess and should be parsable in a very similar way. =head3 --legacy=TYPE =head3 --legacy=compact Internal format: mainly avoid tabs and spaces format is as follows: Some Label:<-- anything right of colon is data =head3 --legacy=full Internal format: pretty print each label in its own line, followed by data prepended by tab character (useful for I<+info> only). =head3 --legacy=owasp Results for cipher checks use rating from OWASP Cipher Cheat Sheet. =head3 --legacy=quick Internal format: use tab as separator; ciphers are printed with bit length (implies I<--tab>). =head3 --legacy=simple Internal default format. =head3 --format=0x =head3 --format=\x =head3 --format=/x =head3 --format=hex =head3 --format=raw This option is used to specify the format of the result lines. This covers the value of the result line only. =over =item * C Print raw data as passed from L. =back Note: all data will be printed as is, without additional label or formatting. It's recommended to use the option in conjunction with exactly one command. Otherwise the user needs to know how to "read" the printed data. =over =item * C Convert some data to hex: 2 bytes separated by C<:>. =back =over =item * C<0x> Convert some data with hex values: =back 2 bytes preceded by C<0x> and separated by a space. =over =item * C Same as --format=\x =back =over =item * C<\x> Convert some data with hex values: =back 2 bytes preceded by C<\x> and no separating char. =head3 --header Print formatting header. Default for I<+check>, I<+info>, I<+quick> and and I<+cipher> only. =head3 --no-header Do not print formatting header. Usefull if raw output should be passed to other programs. Note: must be used on command line to inhibit all header lines. =head3 --ignore-cmd=CMD =head3 --ignore-output=CMD =head3 --no-cmd=CMD =head3 --no-output=CMD Do not print output (data or check result) for command C. C is any valid command, see L , without leading C<+>. Option can be used multiple times. =head3 --score Print scoring results. Default for I<+check>. =head3 --no-score Do not print scoring results. =head3 --separator=CHAR =head3 --sep=CHAR C will be used as separator between label and value of the printed results. Default is C<:>. =head3 --tab C character (0x09, \t) will be used as separator between label and value of the printed results. As label and value are already separated by a TAB character, this options is only useful in conjunction with the I<--legacy=compact> option. =head3 --showhost Prefix each printed line with the given hostname (target). The hostname will be followed by the separator character. =head3 --std-format=utf8 =head3 --std-format=crlf =head3 --std-format=raw =head3 --std-format=unix =head3 --std-format=CHARSET This option is used to specify the general output format for STDOUT and STDERR. All results are written to STDOUT, errors and warnings may also be written to STDERR . The default is C<:unix:utf8>, which is the perlish definition used internally. Following values are supported: =over =item * C =back =over =item * C Print raw data, binary in bytes without conversion. =back Note: binary here just means characters (as all output is text). =over =item * C Convert all characters to UTF-8. =back =over =item * C Use CR LF as end of line. =back =over =item * C C can be any of the local installed character =back sets, like UTF-8, UTF-16LE, CP1252, iso-8859-7, etc.. This conversion may print its own warnings. The option can be used multiple times with different values. To reset the default behaviour, either C or C must be used. Obviously, they must be used first. All other values are used additionally. Note: C just defines the format of the characters, it does no further checks on the converted characters. In contrast, C is used as real encoding and does some checks. For more details, please see "perldoc -f binmode" . Currently (Jan. 2018), these options must be used before any I<--help> option. =head3 --win-CR Obsolete, please use I<--std-format=crlf> . =head2 Options for compatibility with other programs Please see other programs for detailed description (if not obvious:). Note that often only the long form options are accepted as most short form options are ambiguous. If other programs use the same option,but with a different behaviour, then thes other options are not supported. For a list of supported options, please see: o-saft.pl --help=alias Following list contains only those options not shown with: o-saft.pl --help=alias Tool's Option (Tool) o-saft.pl Option =over =item * --checks CMD (TLS-Check.pl) same as +CMD =back =over =item * -h, -h=HOST (various tools) same as --host HOST =back =over =item * -p, -p=PORT (various tools) same as --port PORT =back =over =item * -t HOST (ssldiagnos) same as --host HOST =back =over =item * --UDP (ssldiagnos) same as --udp =back =over =item * --timeout, --grep (ssltest.pl) ignored =back =over =item * -r, -s, -t, -x (ssltest.pl) ignored =back =over =item * --insecure (cnark.pl) ignored =back =over =item * --nopct --nocolor (ssldiagnos) ignored =back =over =item * -connect, -H, -u, -url, -U ignored =back =over =item * -noSSL same as --no-SSL =back =over =item * -no_SSL same as --no-SSL =back For definition of C see I<--SSL< and I| and I>--no-SSL> above. =head2 Options for customization For general descriptions please see L section below. =head3 --cfg_cmd=CMD=LIST =head3 --cfg-cmd=CMD=LIST Redefine list of commands. Sets %cfg{cmd-CMD} to LIST. Commands can be written without the leading C<+>. If CMD is any of the known internal commands, it will be redifned. If CMD is a unknown command, it will be created. Example: --cfg-cmd=sni="sni hostname" An example I<+preload> can be found in C<.o-saft.pl> . To get a list of commands and their settings, use: o-saft.pl --help=intern Main purpose is to reduce list of commands or to print them sorted. =head3 --cfg-score=KEY=SCORE Redefine value for scoring. Sets %checks{KEY}{score} to C. Most score values are set to 10 by default. Values C<0> .. C<100> are allowed. To get a list of current score settings, use: o-saft.pl --help=score For deatils how scoring works, please see L section. Use the I<--trace-key> option for the I<+info> and/or I<+check> command to get the values for C. =head3 --cfg_checks=KEY=TEXT =head3 --cfg-checks=KEY=TEXT =head3 --cfg_data=KEY=TEXT =head3 --cfg-data=KEY=TEXT Redefine texts used for labels in output. Sets %data{KEY}{txt} or %checks{KEY}{txt} to C. To get a list of preconfigured labels, use: o-saft.pl --help=cfg-checks o-saft.pl --help=cfg-data =head3 --cfg-cipher=CIPHER=value Redefine the security value (i.e. HIGH) in the cipher description. Example: --cfg-cipher=NULL-MD5=no-security-at-all =head3 --cfg_text=KEY=TEXT =head3 --cfg-text=KEY=TEXT Redefine general texts used in output. Sets %text{KEY} to C. To get a list of preconfigured texts, use: o-saft.pl --help=cfg-text Note that \n, \r and \t are replaced by the corresponding character when read from L. =head3 --cfg-text=FILE Read definitions for %text{KEY}="my text" from file C. =head3 --cfg-hint=KEY=TEXT Redefine texts used for hints. Sets %cfg{hints}{KEY} to C. To get a list of preconfigured texts, use: o-saft.pl --help=cfg-hint =head3 --cfg-init=KEY=VALUE Set the internal %cfg hash. This options is intended for testing and debugging only. Please see L below. =head3 --call=METHOD See L. =head3 --usr Execute functions defined in L. =head3 --usr-* =head3 --user-* Options ignored, but stored as is internal in $cfg{usr-args} . These options can be used in L or L. =head3 --experimental Use experimental functionality. Some functionality of this tool is under development and only used when this option is given. =head2 Options for tracing and debugging =head3 --n Do not execute, just show commands (only useful in conjunction with using openssl). =head3 Difference --trace vs. --v While I<--v> is used to print more data, I<--trace> is used to print more information about internal data such as procedure names and/or variable names and program flow. =head3 --v =head3 --verbose Print more information about checks. Note that this option should be first otherwise some debug messages are missing. Note that I<--v> is different from -v (see above). =head3 --v --v Print remotely checked ciphers. =head3 --v-cipher --cipher-v Print remotely checked ciphers. In contrast to I<--v> I<--v> above, this just prints the ciphers while while being checked, but no other verbose messages. =head3 --trace Print debugging messages. =head3 --trace --trace Print more debugging messages and pass C to Net::SSLeay and L. =head3 --trace --trace --trace Print more debugging messages and pass C to Net::SSLeay and L. =head3 --trace --trace --trace --trace Print processing of all command line arguments. =head3 --trace-cli Print complete command line first. Used for internal testing. =head3 --trace-arg =head3 --trace-- Print command line argument processing. =head3 --trace-cmd Trace execution of command processing (those given as I<+*>). =head3 --trace-key =head3 --trace@ Print some internal variable names in output texts (labels). Variable names are prefixed to printed line and enclosed in # . Example without I<--trace-key> : Certificate Serial Number: deadbeef Example with I<--trace-key> : #serial# Certificate Serial Number: deadbeef =head3 --trace-time Prints trace output with timestamps. More timestamps are printed if used together with I<--trace-cmd>. =head3 --trace=VALUE Alias for I<--trace-VALUE> options (see above). Trace Option Alias Option =over =item * --trace=1 same as --trace =back =over =item * --trace=2 same as --trace --trace =back =over =item * --trace=arg same as --trace-arg =back =over =item * --trace=cmd same as --trace-cmd =back =over =item * --trace=key same as --trace-key =back =over =item * --trace=time same as --trace-time =back =head3 --trace=FILE Use FILE instead of the default L, i.e. C<.o-saft.pl>. =head3 --trace-me Print debugging messages for o-saft.pl only, but not any modules. =head3 --trace-not-me Print debugging messages for modules only, but not o-saft.pl itself. =head3 --trace-sub =head3 +traceSUB Print formatted list of internal functions with their description. Not to be intended in conjunction with any target check. =head3 --hint Print hint messages (!!Hint:). =head3 --no-hint Do not print hint messages (!!Hint:). =head3 --warning Print warning messages (**WARNING:). =head3 --no-warning Do not print warning messages (**WARNING:). =head3 --exit=KEY Terminate o-saft.pl at specified C. Please see L below. =head2 Options vs. Commands For compatibility with other programs and lazy users, some arguments looking like options are silently taken as commands. This means that I<--THIS> becomes I<+THIS> then. These options are: =over =item * --help =back =over =item * --abbr =back =over =item * --todo =back =over =item * --chain =back =over =item * --default =back =over =item * --fingerprint =back =over =item * --list =back =over =item * --version =back Take care that this behaviour may be removed in future versions as it conflicts with those options and commands which actually exist, like: I<--sni> vs. I<+sni> =head1 LAZY SYNOPSIS =head2 Commands Following strings are treated as a command instead of target names: =over =item * ciphers =back =over =item * s_client =back =over =item * version =back A warning will be printed. =head2 Options We support following options, which are all identical, for lazy users and for compatibility with other programs. =head3 Option Variants =over =item * --port PORT =back =over =item * --port=PORT =back This applies to most such options, I<--port> is just an example. When used in the L, the I<--OPTION=VALUE> variant must be used. =head3 Option Names Dash C<->, dot C<.> and/or underscore C<_> in option names are optional, all following are the same: =over =item * --no.dns =back =over =item * --no-dns =back =over =item * --no_dns =back =over =item * --nodns =back This applies to all such options, I<--no-dns> is just an example. =head2 Targets Following syntax is supported also: o-saft.pl http://some.tld other.tld:3889/some/path?a=b Note that only the hostname and the port are used from an URL. =head2 Options vs. Commands See L in L section above =head1 CHECKS All SSL related check performed by the tool will be described here. =head2 General Checks Lookup the IP of the given hostname (FQDN), and then tries to reverse resolve the FQDN again. =head2 SSL Ciphers Check which ciphers are supported by target. Please see L for details of this check. =head2 SSL Connection =head3 heartbeat Check if "heartbeat" extension is supported by target. =head3 poodle Check if target is vulnerable to POODLE attack (SSLv3 enabled). =head3 robot Check if target is vulnerable to ROBOT attack (server offers ciphers with RSA encryption). =head3 sloth Check if target is vulnerable to SLOTH attack (server offers RSA-MD5 or ECDSA-MD5 ciphers). =head3 sweet32 Check if target is vulnerable to Sweet32 attack (server offers CBC or CBC3 or DES or 3DES ciphers). Note that FIPS-140 compliance requires 3DES ciphers, hence compliant systems are then vulnerable to Sweet32 attacks. =head3 ALPN Check if target supports ALPN. Following messages are evaluated: ALPN protocol: h2-14 No ALPN negotiated Please see also L ALPN and NPN below. =head2 SSL Vulnerabilities =head3 ADH Check if ciphers for anonymous key exchange are supported: ADH|DHA. Such key exchanges can be sniffed. =head3 EDH Check if ephemeral ciphers are supported: DHE|EDH. They are necessary to support Perfect Forward Secrecy (PFS). =head3 BEAST Check if ciphers with CBC for protocol SSLv1, SSLv3 or TLSv1 are used. TLSv1.2 checks are not yet implemented. =head3 CRIME Connection is vulnerable if target supports SSL-level compression, or supports SPDY/3 (because SPDY/3 uses compression). See http://zoompf.com/2012/09/explaining-the-crime-weakness-in-spdy-and-ssl Note: SPDY/3 is only possible if the client explicitely asks for this alternate protocol (for example "openssl ... -nextprotoneg spdy/3"). =head3 DROWN Connection is vulnerable if target supports SSLv2. =head3 FREAK Attack against SSL/TLS to downgrade to EXPORT ciphers. Currently (2018) a simple check is used: SSLv3 enabled and EXPORT ciphers supported by server. See CVE-2015-0204 and https://freakattack.com/ . =head3 HEARTBLEED Check if target is vulnerable to heartbleed attack, see CVE-2014-0160 and http://heartbleed.com/ . =head3 HEIST Not implemented. There are no checks for the HEIST attack implemented, because this is an attack on TCP/IP rather than SSL/TLS on top of TCP/IP. =head3 KCI To perform a MiTM attack with Key Compromise Impersonation, the atta- cker needs to engage the victim to install and use a client certificate. This is considered a low risk and hence not tested here. =head3 Logjam Check if target is vulenerable to Logjam attack. Check if target suports EXPORT ciphers and/or DH Parameter is less than 2048 bits. ECDH must be greater to 511 bits. =head3 Lucky13 Check if CBC ciphers are offered. NOTE the recommendation to be safe against Lucky13 was to use RC4 ciphers. But they are also subject to attacks (see below). Hence the check is only for CBC ciphers. =head3 RC4 Check if RC4 ciphers are supported. They are assumed to be broken. Note that I<+rc4> reports the vulnerabilitiy to the RC4 Attack, while I<+cipher-rc4> simply reports if RC4 ciphers are offered. However the check, and hence the result, is the same. =head3 PFS Check if DHE ciphers are used. Checks also if the TLS session ticket is random or not used at all. TLSv1.2 checks are not yet implemented. =head3 POODLE Check if target is vulnerable to POODLE attack (just check if SSLv3 is enabled). =head3 Practical Invalid Curve Attack This attack allows an attacker to read the servers private key if the server does not check properly the passed points for a ecliptic curve when EDH ciphers are used. This check will not send multiple invalid points, but only checks if the server closes the connection or responds with no matching cipher. =head3 ROBOT Bleichebacher's Oracle attack against SSL/TLS ciphers. Not implemented. https://robotattack.org/ =head3 SLOTH Currently (2016) we check for ciphers with ECDSA, RSA-MD5. Checking the TLS extension C is not yet implemented. =head3 Sweet32 Currently (2016) we check for ciphers with CBC or CBC3 or DES or 3DES. =head3 Ticketbleed B Check if target is vulnerable to ticketbleed, means that it returns up to 31 random bytes from memory as Session Ticket, see CVE-2016-9244 and https://filippo.io/Ticketbleed/ . =head2 Target (server) Configuration and Support =head3 BEAST, BREACH, CRIME, DROWN, FREAK, Logjam, Lucky13, POODLE, RC4, ROBOT, =head3 SLOTH, Sweet32 See above. =head3 Renegotiation Check if the server allows client-side initiated renegotiation. =head3 Version rollback attacks B Check if the server allows changing the protocol. =head3 DH Parameter Check if target's DH Parameter is less 512 or 2048 bits. =head2 Target (server) Certificate =head3 Certificate Hashes Check that fingerprint is not MD5. Check that certificate private key signature is SHA2 or better. =head3 Root CA Provided certificate by target should not be a Root CA. =head3 Self-signed Certificate Certificate should not be self-signed. =head3 FQDN is listed in subjectAltname (RFC2818) The FQDN must be listed in the certificates subjectAltname. The check command I<+rfc_2818_names> is based on the info command I<+verify_hostname> . The check was added in 05/2017 because browsers started to complain if the FQDN is not part of the subjectAltname. =head3 IP in CommonName or subjectAltname (RFC6125) B =head3 Basic Constraints Certificate extension Basic Constraints should be CA:FALSE. =head3 OCSP, CRL, CPS Certificate should contain URL for OCSP and CRL. =head3 Private Key encyption Certificates signature key supports encryption. =head3 Private Key encyption well known Certificates signature key encryption algorithm is well known. =head3 Public Key encyption Certificates public key supports encryption. =head3 Public Key encyption well known Certificates public key encryption algorithm is well known. =head3 Public Key Modulus size Some (historic) SSL implementations are subject to buffer overflow if =head3 Public Key Modulus Exponent size The modulus exponent should be = 65537 as it is a prime number and an easy to calculate exponent. If the exponent is less than 65537, "Boradcast" attacks are possible. However, some (mainly historic) SSL implementations may have problems to connect because they are not able to do the crypt mathematics with exponenents larger than 65536. If ecliptive curves are used, the result for these checks is always C. =head3 Sizes and Lengths of Certificate Settings Serial Number <= 20 octets (RFC5280, 4.1.2.2. Serial Number) B<...> =head3 DV-SSL - Domain Validation Certificate The Certificate must provide: =over =item * Common Name C field =back =over =item * Common Name C in C or C field =back =over =item * Domain name in C or C field =back =head3 EV-SSL - Extended Validation Certificate This check is performed according the requirements defined by the CA/ Browser Forum https://www.cabforum.org/contents.html . The certificate must provide: =over =item * DV - Domain Validation Certificate (see above) =back =over =item * Organization name C or C field =back =over =item * Organization name must be less to 64 characters =back =over =item * Business Category C in C field =back =over =item * Registration Number C in C field =back =over =item * Address of Place of Business in C field =back Required are: C, C, C Optional are: C, C =over =item * Validation period does not exceed 27 month =back See L also. =head2 Target (server) HTTP(S) Support =head3 STS header (see RFC 6797) Using STS is no perfect security. While the very first request using http: is always prone to a MiTM attack, MiTM is possible to following requests again, if STS is not well implemented on the server. =over =item * Request with http: should be redirected to https: =back =over =item * Redirects should use status code 301 (even others will work) =back =over =item * Redirect's Location header must contain schema https: =back =over =item * Redirect's Location header must redirect to same FQDN =back =over =item * Redirect may use Refresh instead of Location header (not RFC6797) =back =over =item * Redirects from HTTP must not contain STS header =back =over =item * Answer from redirected page (HTTPS) must contain STS header =back =over =item * Answer from redirected page for IP must not contain STS header =back =over =item * STS header must contain includeSubDirectoy directive =back =over =item * STS header max-age should be less than 1 month =back =over =item * STS must not be set in http-equiv attribute of a meta TAG =back =head3 STS header preload attribute (+preload) To satisfy the requirements on https://hstspreload.appspot.com/ the HSTS header must: =over =item * have the max-age with at least 18 weeks (10886400 seconds) =back =over =item * have the includeSubDomains attribute =back =over =item * have the preload attribute =back =over =item * redirect to https first, then to sub-domains (if redirected) =back =over =item * have an HSTS header in each redirect to https. =back Additionally, the site must have: =over =item * a valid certificate =back =over =item * serve all subdomains over https. =back Except the last requirement, I<+preload> will do the checks. Note that I<+preload> is defined in C<.o-saft.pl> only. =head3 Public Key Pins header TBD - to be described ... =head2 Sizes Mainly in the certificate various counts, lengths and sizes of values are checked and reported. All commands for these checks start with C<+cnt_> or C<+len_>. Up to now, there is no C or C value for these checks. Following commands will check the value to be in a specific range to become C or C: =over =item * +sts_maxage1d - yes if HSTS maxage < 1 day =back =over =item * +sts_maxage1m - yes if HSTS maxage < 1 month =back =over =item * +sts_maxage1y - yes if HSTS maxage < 1 year =back =over =item * +sts_maxage18 - yes if HSTS maxage < 18 weeks (5 months) =back =over =item * +sts_maxagexy - yes if HSTS maxage > 1 year =back =over =item * +modulus_exp_1 - Public Key Modulus Exponent <>1 =back =over =item * +modulus_exp_65537 - Public Key Modulus Exponent =65537 =back =over =item * +modulus_exp_oldssl - Public Key Modulus Exponent <65537 =back =over =item * +modulus_size_oldssl - Public Key Modulus <16385 bits =back For some details of these cjecks, please see the description above at Public Key Modulus Exponent size The recommendations for DH parameters (RSA and ecliptice curve) are are checked as follows: =over =item * +dh_512 - DH Parameter >= 512 bits =back =over =item * +dh_2048 - DH Parameter >= 2048 bits =back =over =item * +ecdh_256 - DH Parameter >= 256 bits (ECDH) =back =over =item * +ecdh_512 - DH Parameter >= 512 bits (ECDH) =back Note that only one of the checks C<+dh_*> and C<+ecdh_*> can return C. =head2 ALPN and NPN The commands for the checks to report C or C, are I<+hasalpn> and I<+hasnpn>. Both, the Application Layer Protocol Negotiation (ALPN) and the Next Protocol Negotiation (NPN) will be tested. The commands for that are: =over =item * +alpns =back =over =item * +npns =back Each, ALPN and NPN, is tested separately with all known protocols. The test sets only one protocol, tries to make a connection and then checks if the protocol was accepted by the server. The collected list of protocols will be printed with the aforementioned commands, or the I<+info> command. Note the difference for the commands I<+next_protocols> and I<+alpns>, where I<+next_protocols> simply reports what the server itself advertises, while I<+alpns> reports what the server supports if asked for. =head2 Compliances Note that it is not possible to satisfy all following compliances. Best match is: C and C and C and C. In general it is difficult to satisfy all conditions of a compliance, and it is also difficult to check all these conditions. That is why some compliance checks are not completely implemented. For details see below please. Also note that in the L the output of results for some checks is disabled by default. A C message will be printed, if any of these checks are used. =over =item * FIPS-140 =back =over =item * ISM =back =over =item * PCI =back =over =item * BSI TR-02102-2 (2016-01) =back =over =item * BSI TR-03116-4 =back =over =item * RFC 2818 =back =over =item * RFC 6125 =back =over =item * RFC 6797 =back =over =item * RFC 7525 =back =head3 BSI TR-02102-2 (+tr-02102+ +tr-02102- +bsi) Checks if connection and ciphers are compliant according TR-02102-2, see https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen /TechnischeRichtlinien/TR02102/BSI-TR-02102-2_pdf.pdf?__blob=publicationFile (following headlines are taken from TR-02102-2 Version 2016-01) 3.1.3 Schlüssellängen bei EC-Verfahren die EC-Verfahren ... und weitere Erläuterungen siehe Bemerkung 4 in Kapitel 3 in [TR-02102-1] . 3.2 SSL/TLS_Versionen Only TLSv1.2 allowed (except for I<+tr-02102-> which also allows TLSv1.1) 3.3.1 Empfohlene Cipher Suites Allows only *DHE-*-SHA256, *DHE-*-SHA384, *DH-*-SHA256 and *DH-*-SHA384 ciphers and PSK ciphers with ephermeral keys. For I<+tr-02102+> they must be AES-GCM, I<+tr02102-> also allows B 3.3.2 Übergangsregelungen SHA1 temporary allowed. SHA256 and SHA384 recommended. RC4 not reocmmended. Use of SHA1 will only be checked for I<+tr-02102+> 3.4.1 Session Renegotation Only server-side (secure) renegotiation allowed (see RFC 5746). 3.4.2 Verkürzung der HMAC-Ausgabe Truncated HMAC according RFC 6066 not recommended. 3.4.3 TLS-Kompression und der CRIME-Angriff No TLS compression. 3.4.4 Der Lucky13-Angriff 3.4.5 Die "Encrypt-then-MAC"-Erweiterung Use of AES-GCM ciphers only. Use of Encrypt-then-MAC according RFC 7366 cannot be checked. 3.4.6 Die Heartbeat-Erweiterung Target must not support the heartbeat extension. 3.4.7 Die Extended Master Secret Extension Use of Extended Master Secret Extension according RFC 7627 cannot be checked. 3.5 Authentisierung der Kommunikationspartner Not checked as only applicable for VPN connections. 3.6 Domainparameter und Schlüssellängen Check if signature key is > 2048 bits. 3.6.1 Verwendung von elliptischen Kurven **NOT YET IMPLEMENTED** Use only following curves according RFC 5639 and RFC 7027: brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 Use of secp256r1 and secp384r1 temporary allowed. 4.1 Schlüsselspeicherung This requirement is not testable from remote. 4.2 Umgang mit Ephemeralschlüsseln This requirement is not testable from remote. 4.3 Zufallszahlen This requirement is not testable from remote. =head3 BSI TR-03116-4 (+tr-03116+ +tr-03116- +bsi) Checks if connection and ciphers are compliant according TR-03116-4, see https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen /TechnischeRichtlinien/TR03116/BSI-TR-03116-4.pdf?__blob=publicationFile (following headlines are taken from there) 2.1.1 TLS-Versionen und Sessions Allows only TLS 1.2. 2.1.2 Cipher Suites Cipher suites must be ECDHE-ECDSA or -RSA with AES128 and SHA265. For curiosity, stronger cipher suites with AES256 and/or SHA384 are not not allowed. To follow this curiosity the I<+tr-03116-> (lazy) check allows the stronger cipher suites ;-) 2.1.1 TLS-Versionen und Sessions The TLS session lifetime must not exceed 2 days. 2.1.4.2 Encrypt-then-MAC-Extension 2.1.4.3 OCSP-Stapling MUST have C. 4.1.1 Zertifizierungsstellen/Vertrauensanker Certificate must provide all root CAs. (NOT YET IMPLEMENTED). Should use a small certificate trust chain. 4.1.2 Zertifikate Must have C or C. End-user certificate must not be valid longer than 3 years. Root-CA certificate must not be valid longer than 5 years. Certificate extension C must exist, and should be a small value ("small" is not defined). All certificates must contain the extension C. Wildcards for C or C or C are not allowed in any certificate. EV certificates are recommended (NOT YET checked properly). 4.1.3 Zertifikatsverifikation Must verify all certificates in the chain down to their root-CA. (NOT YET IMPLEMENTED). Certificate must be valid according issue and expire date. All Checks must be doen for all certificates in the chain. 4.1.4 Domainparameter und Schlüssellängen This requirement is not testable from remote. 4 5.2 Zufallszahlen This requirement is not testable from remote. =head3 RFC 2818 (+rfc2818) Check if the FQDN is listed in the certificates C. =head3 RFC 6125 (+rfc6125) Checks values C, C and C of the certificate for: =over =item * must all be valid characters for DNS =back =over =item * must not contain more than one wildcard =back =over =item * must not contain invalid wildcards =back =over =item * must not contain invalid IDN characters =back =head3 RFC 6797 (+rfc6797) Same as STS header I<+hsts> . =head3 RFC 7525 (+rfc7525) Checks if connection and ciphers are compliant according RFC 7525. See http://tools.ietf.org/rfc/rfc7525.txt (following headlines are taken from there) 3.1.1. SSL/TLS Protocol Versions SSLv2 and SSLv3 must not be supportetd. TLSv1 should only be supported if there is no TLSv1.1 or TLSv1.2. Either TLSv1.1 or TLSv1.2 must be supported, prefered is TLSv1.2. 3.1.2. DTLS Protocol Versions DTLSv1 and DTLSv1.1 must not be supported. 3.1.3. Fallback to Lower Versions (check implecitely done by 3.1.1, see above) 3.2. Strict TLS Check if server provides Strict Transport Security. (C check NOT YET IMPLEMENTED). 3.3. Compression Compression on TLS must not be supported. 3.4. TLS Session Resumption Server must support resumtion and random session tickets. (Randomnes of session tickets implemented YET experimental.) Check if ticket is authenticated and encrypted NOT YET IMPLEMENTED. 3.5. TLS Renegotiation Server must support renegotiation. 3.6. Server Name Indication (Check for SNI support implemented experimental.) 4. Recommendations: Cipher Suites 4.1. General Guidelines 4.2. Recommended Cipher Suites Check for recommended ciphers. 4.3. Public Key Length DH parameter must be at least 256 bits or 2048 bits with EC. (Check currently, 4/2016, based on openssl which may not provide DH =over =item * parameters for all ciphers.) =back 4.5. Truncated HMAC TLS extension "truncated hmac" must not be used. 6. Security Considerations 6.1. Host Name Validation Given hostname must matches hostname in certificate's subject. 6.2. AES-GCM 6.3. Forward Secrecy 6.4. Diffie-Hellman Exponent Reuse (NOT YET IMPLEMENTED). 6.5. Certificate Revocation OCSP and CRL Distrbution Point in cetificate must be defined. =head1 OUTPUT All output is designed to make it easily parsable by postprocessors. Following rules are used: =over =item * Lines for formatting or header lines start with C<=>. =back =over =item * Lines for verbosity or tracing start with C<#>. =back =over =item * Errors and warnings start with C<**>. =back =over =item * Empty lines are comments ;-) =back =over =item * Label texts end with a separation character; default is C<:>. =back =over =item * Label and value for all checks are separated by at least one TAB =back character. =over =item * Texts for additional information are enclosed in C<<<> and C<>>>. =back =over =item * C is used when no proper informations was found or provided. =back Replace C by whatever you think is adequate: "No answer", "Not available", "Not applicable", ... Lines not described above, will have the form (by default): Label for information or check: TABresult For more details on these lines, please refer to L above. When used in I<--legacy=full> or I<--legacy=simple> mode, the output may contain formatting lines for better (human) readability. =head2 Postprocessing Output It is recommended to use the I<--legacy=quick> option, if the output should be postprocessed, as it omits the default separation character (C<:> , see above) and just uses on single tab character (0x09, \t or TAB) to separate the label text from the text of the result. Example: Label of the performed checkTABresult More examples for postprocessing the output can be found here: https://github.com/OWASP/O-Saft/blob/master/contrib =head1 CUSTOMIZATION This tools can be customized as follows: =over =item * Using command line options =back This is a simple way to redefine specific settings. Please see L below. =over =item * Using Configuration file =back A configuration file can contain multiple configuration settings. Syntax is simply KEY=VALUE. Please see L below. =over =item * Using resource files =back A resource file can contain multiple command line options. Syntax is the same as for command line options iteself. Each directory may contain its own resource file. Please see L below. =over =item * Using debugging files =back These files are - nomen est omen - used for debugging purposes. However, they can be (mis-)used to redefine all settings too. Please see L below. =over =item * Using user specified code =back This file contains user specified program code. It can also be (mis-)used to redefine all settings. Please see L below. Customization is done by redefining values in internal data structure which are: %cfg, %data, %checks, %text, %scores. Unless used in L or L, there is no need to know these internal data structures or the names of variables; the options will set the proper values. The key names being part of the option, are printed in output with the I<--trace-key> option. I.g. texts (values) of keys in %data are those used in output of the "Information" section. Texts of keys in %checks are used for output in "Performed Checks" section. And texts of keys in %text are used for additional information lines or texts (mainly beginning with C<=>). Configuration File vs. L vs. L =over =item * CONFIGURATION FILE =back Configuration files must be specified with one of the I<--cfg-*> options. The specified file can be a valid path. Please note that only the characters: a-zA-Z_0-9,.\/()- are allowed as pathname. Syntax in configuration file is: C where C is any key as used in internal data structure. =over =item * RC-FILE =back Resource files are searched for and used automatically. For details see L below. =over =item * DEBUG-FILE =back Debug files are searched for and used automatically. For details see L below. =over =item * USER-FILE =back The user program file is included only if the I<--usr> option was used. For details see L below. =head2 CONFIGURATION OPTIONS Configuration options are used to redefine texts and labels or score settings used in output. The options are: =over =item * --cfg-cmd=CMD=LIST =back =over =item * --cfg-checks=KEY=TEXT =back =over =item * --cfg-data=KEY=TEXT =back =over =item * --cfg-hint=KEY=TEXT =back =over =item * --cfg-text=KEY=TEXT =back =over =item * --cfg-cipher=CIPHER=TEXT =back C is the key used in the internal data structure, and C is the value to be set for this key. Note that unknown keys are ignored silently. If KEY=TEXT is an exiting filename, all lines from that file are read and set. For details see L below. CIPHER must be a valid cipher suite name as shown with: o-saft.pl ciphers NOTE that such configuration options should be used before any I<--help> or I<--help=*> option, otherwise the changed setting is not visible. =head2 CONFIGURATION FILE Note that the file can contain C pairs for any kind of the configuration as given by the I<--cfg-CFG> option. For example when used with I<--cfg-text=FILE> only values for %text will be set, when used with I<--cfg-data=FILE> only values for %data will be set, and so on. C will not be used when C is an existing filename. It i recommended to use a non-existing key, i.e.: I<--cfg-text=my_file=some/path/to/private/file> . =head2 RC-FILE The rc-file will be searched for in the working directory only. The name of the rc-file is the name of the program file prefixed by a C<.> (dot), for example: C<.o-saft.pl>. A rc-file can contain any of the commands and options valid for the tool itself. The syntax for them is the same as on command line. Each command or option must be in a single line. Any empty or comment line will be ignored. Comment lines start with C<#> or C<=>. Note that options with arguments must be used as C instead of C. Configurations options must be written like C<--cfg-CFG=KEY=VALUE>. Where C is any of: C, C, C, C and C is any key from internal data structure (see above). All commands and options given on command line will overwrite those found in the rc-file. =head2 DEBUG-FILE All debugging functionality is defined in L , which will be searched for using paths available in C<@INC> variable. Syntax in this file is perl code. For details see L below. =head2 USER-FILE All user functionality is defined in L , which will be searched for using paths available in C<@INC> variable. Syntax in this file is perl code. All functions defined in L are called when the option I<--usr> was given. The functions are defined as empty stub, any code can be inserted as need. Please see perldoc L to see when and how these functions are called. =head2 SHELL TWEAKS Configuring the shell environment where the tool is startet, must be done before the tools starts. It is not really a task for the tool itself, but it can simplify your life, somehow. There exist customizations for some commonly used shells, please see the files in the ./contrib/ directory. =head2 COMMANDS The option I<--cfg-cmd=CMD=LIST> can be used to define own commands. When configuring own commands, CMD must not be one of the commands listed with I<--help=intern> and CMD must constist only of digits and letters. Examples in C<.o-saft.pl> are I<+preload> and I<+ciphercheck> . =head1 CIPHER NAMES While the SSL/TLS protocol uses integer numbers to identify ciphers, almost all tools use some kind of "human readable" texts for cipher names. These numbers (which are most likely written as hex values in source code and documentations) are the only true identifier, and we have to rely on the tools that they use the proper integers. As such integer or hex numbers are difficult to handle by humans, we decided to use human readable texts. Unfortunately no common standard exists how to construct the names and map them to the correct number. Some, but by far not all, oddities are described in L. The rules for specifying cipher names are: =over =item * 1) textual names as defined by IANA (see [IANA]) =back =over =item * 2) mapping of names and numbers as defined by IANA (see [IANA]) =back =over =item * 3) C<-> and C<_> are treated the same =back =over =item * 4) abbreviations are allowed, as long as they are unique =back =over =item * 5) beside IANA, openssl's cipher names are preferred =back =over =item * 6) name variants are supported, as long as they are unique =back =over =item * 7) hex numbers can be used =back [IANA] http://www.iana.org/assignments/tls-parameters/tls-parameters.txt September 2013 [openssl] ... openssl 1.0.1 If in any doubt, use I<+list> I<--v> to get an idea about the mapping. Use I<--help=regex> to see which regex are used to handle all variants herein. Mind the traps and dragons with cipher names and what number they are actually mapped to. In particular when I<--lib>, I<--exe> or I<--openssl> options are in use. Always use these options with I<+list> command too. =head2 Name Rodeo As said above, the SSL/TLS protocol uses integer numbers to identify ciphers, but almost all tools use some kind of human readable texts for cipher names. For example the cipher commonly known as C is identified by C<0x020701c0> (in openssl) and has C as constant name. A definition is missing in IANA, but there is C. Thers is also C<0x000A> for the same cipher C. Both are valid, first one if used with SSLv2, and second one when used with SSLv3. It's the responsibility of each tool to map the human readable cipher name to the correct (hex, integer) identifier. For example Firefox uses C, which is what? Furthermore, there are different acronyms for the same thing in use. For example C and C both mean "Ephemeral Diffie-Hellman". Comments in the L sources mention this. And for curiosity these sources use both in cypher names, but allow C as shortcut only in openssl's "ciphers" command. Wonder about (up to 1.0.1h): openssl ciphers -V EDH openssl ciphers -V DHE openssl ciphers -V EECDH openssl ciphers -V ECDHE Next example is C which is also known as C or C or C or C. You think this is enough? Then have a look how many acronyms are used for "Tripple DES". Compared to above, the interchangeable use of C<-> vs. C<_> in human readable cipher names is just a very simple one. However, see openssl again what following means (returns): openssl ciphers -v RC4-MD5 openssl ciphers -v RC4+MD5 openssl ciphers -v RC4:-MD5 openssl ciphers -v RC4:!MD5 openssl ciphers -v RC4!MD5 Looking at all these oddities, it would be nice to have a common unique naming scheme for cipher names. We have not. As the SSL/TLS protocol just uses a number, it would be natural to use the number as uniq key for all cipher names, at least as key in our internal sources. Unfortunately, the assignment of ciphers to numbers changed over the years, which means that the same number refers to a different cipher depending on the standard, and/or tool, or version of a tool you use. As a result, we cannot use human readable cipher names as identifier (aka unique key), as there are to many aliases for the same cipher. And also the number cannot be used as unique key, as a key may have multiple ciphers assigned. The default behaviour will be to use the cipher names like L does. If a name is ambigous, the first matching will be choosen. This -first matching- only applies to names provided by the user by option or whatever, internally the latest IANA number will be used, because they have the most less ambiguities. =head1 KNOWN PROBLEMS This section describes knwon problems, and known error messages which may occour when using o-saft.pl. This sections can be used as FAQ too as it gives hints and workarounds. =head2 Segmentation fault Sometimes the program terminates with a C. This mainly happens if the target does not return certificate information. If so, the I<--no-cert> option may help. =head2 **WARNING: empty result from openssl; ignored at ... This most likely occurs when the provided cipher is not accepted by the server, or the server expects client certificates. =head2 **WARNING: unknown result from openssl; ignored at ... This most likely occurs when the L executable is used with a very slow connection. Typically the reason is a connection timeout. Try to use I<--timeout=SEC> option. To get more information, use I<--v> I<--v> and/or I<--trace> also. =head2 **WARNING: undefined cipher description May occour if ciphers are checked, but no description is available for them herein. This results in printed cipher checks like: EXP-KRB5-RC4-MD5 no <> instead of: EXP-KRB5-RC4-MD5 no weak =head2 **WARNING: Can't make a connection to your.tld:443; no initial data =head2 **WARNING: Can't make a connection to your.tld:443; target ignored This message occours if the underlaying SSL library (i.e. libssl.a) was not able to connect to the target. Known observed reasons are: =over =item * target does not support SSL protocol on specified port =back =over =item * target expects a client certificate in ClientHello message =back More details why the connection failed can be seen using I<--trace=2> . If the targets supports SSL, it should be at least possible to check for supported ciphers using I<+cipherall> instead of I<+cipher> . =head2 Use of uninitialized value $headers in split ... do_httpx2.al) The warning message (like follows or similar): Use of uninitialized value $headers in split at blib/lib/Net/SSLeay.pm (autosplit into blib/lib/auto/Net/SSLeay/do_httpx2.al) line 1290. occurs if the target refused a connection on port 80. This is considered a bug in L. Workaround to get rid of this message: use I<--no-http> option. =head2 invalid SSL_version specified at ... IO/Socket/SSL.pm This error may occur on systems where a specific SSL version is not supported. Subject are mainly SSLv2, SSLv3 TLSv1.3 and DTLSv1. For DTLSv1 the full message looks like: invalid SSL_version specified at C:/programs/perl/perl/vendor/lib/IO/Socket/SSL. See also L . Workaround: use option: I<--no-sslv2> I<--no-sslv3> I<--no-tlsv13> I<--no-dtlsv1> =head2 Use of uninitialized value $_[0] in length at (eval 4) line 1. This warning occours with IO::Socket::SSL 1.967, reason is unknown. It seems not to harm functionality, hence no workaround, just ignore. =head2 Use of uninitialized value in subroutine entry at lib/IO/Socket/SSL.pm line 430. Some versions of IO::Socket::SSL return this error message if *-MD5 ciphers are used with other protocols than SSLv2. Workaround: use I<--no-md5-cipher> option. =head2 Can't locate auto/Net/SSLeay/CTX_v2_new.al in @INC ... Underlaying library doesn't support the required SSL version. See also L . Workaround: use I<--ssl-lazy> option, or corresponding I<--no-SSL> option. =head2 Read error: Connection reset by peer (,199725) at blib/lib/Net/SSLeay.pm\ =head2 (autosplit into blib/lib/auto/Net/SSLeay/tcp_read_all.al) line 535. Error reported by some Net::SSLeay versions. Reason may be a timeout. This error cannot be omitted or handled properly. Workaround: try to use same call again (no guarantee, unfortunatelly) =head2 Odd number of elements in anonymous hash at Net/SSLinfo.pm line 1613. This warning from perl have been observed when the connection to the target to check for supported ciphers cannot be established. This message can be ignored. =head2 openssl: ...some/path.../libssl.so.1.0.0: no version information available (required by openssl) Mismatch of openssl executable and loaded underlaying library. This most likely happens when options I<--lib=PATH> and/or I<--exe=PATH> are used. See also L . Hint: use following commands to get information about used libraries: o-saft.pl +version o-saft.pl --v --v +version =head2 Integer overflow in hexadecimal number at ... This error message may occour on 32-bit systems if perl was not com- piled with proper options. I.g. perl automatically converts the value to a floating pont number. Please report a bug with output of following command: o-saft.pl +s_client +dump your.tld =head2 openssl did not return DH Paramter>> Text may be part of a value. This means that all checks according DH parameters and logkam attack cannot be done. Workaround: try to use I<--openssl=TOOL> option. This text may appears in any of the compliance checks (like I<+rfc7525>) which may be a false positive. For these checks openssl is also used to get the DH Parameter. Workaround: not available yet =head2 No output with +help and/or --help=todo On some (mainly Windows-based) systems using o-saft.pl +help o-saft.pl --help does not print anything. Workaround: use I<--v> option. o-saft.pl +help --v or o-saft.pl +help | more =head2 Character set (like UTF-8) not recognized in some tools Some tools do not diplay all characters properly, i.e. some versions of podviewer. It is not the obligation of this tool to fix well known bugs in other tools. However, we can offer workarounds. Workaround: generate the affected output using I<--std-format=*> options For example: o-saft.pl --no-rc --std-format=raw --help=gen-pod =head2 **WARNING: on MSWin32 additional option --v required, sometimes ... On some (mainly Windows-based) systems this may happen when calling for example: o-saft.pl --help=FAQ which then may produce: **WARNING: on MSWin32 additional option --v required, sometimes ... === reading: ./.o-saft.pl (RC-FILE done) === === reading: Net/SSLinfo.pm (O-Saft module done) === **USAGE: no command given # most common usage: o-saft.pl I+info& your.tld& o-saft.pl I+check& your.tld& o-saft.pl I+cipher& your.tld& # for more help use: o-saft.pl I--help&& Workaround: use full path to perl.exe, for example C:\Programs\perl\bin\perl.exe o-saft.pl --help=FAQ =head2 Performance Problems There are various reasons when the program responds slow, or seems to hang. Performance issues are most likely a target-side problem. Most common reasons are (no specific order): =over =item * a) DNS resolver problems =back Try with I<--no-dns> =over =item * b) target does not accept connections for https =back Try with I<--no-http> =over =item * c) target's certificate is not valid =back Try with I<--no-cert> =over =item * d) target expects that the client provides a client certificate =back No option provided yet ... =over =item * e) target does not handle Server Name Indication (SNI) =back Try with I<--no-sni> =over =item * f) use of external L executable =back Use I<--no-openssl> =over =item * g) target does not respond at all and/or blocks =back Use I<--ssl-error> For a detailed description, please see L. Other options which may help to get closer to the problem's cause: I<--trace-time>, I<--timeout=SEC>, I<--trace>, I<--trace-cmd> Using I<--trace-time> should show following times: =over =item * DNS: 1 - 10 sec =back =over =item * need_default: <5 sec =back =over =item * need_cipher: 1 - 299 sec (+cipher with socket) =back =over =item * need_cipher: 1 - 20 sec (+cipherraw) =back =over =item * no SNI: 1 - 10 sec =back =over =item * connection test: 1 - 5 sec =back =over =item * prepare checks: 2 - 20 sec =back =over =item * checkalpn. 1 - 15 sec =back =over =item * checkprot. 1 - 15 sec =back =over =item * cipher: <1 sec =back =over =item * info: <1 sec =back =over =item * check: <1 sec =back =head1 LIMITATIONS =head2 Commands Some commands cannot be used together with others, for example: I<+cipher>, I<+ciphers>, I<+list>, I<+libversion>, I<+version>, I<+check>, I<+help>, I<+protocols> . I<+quick> should not be used together with other commands, it returns strange output then. It is the only command which allows I<+cipher> together with other commands. I<+protocols> requires L with support for C<-nextprotoneg> option. Otherwise the value will be empty. =head2 Options The option I<--port=PORT> must preceed I<--host=HOST> for a target like HOST:PORT . The characters C<+> and C<=> cannot be used for I<--separator=CHAR> option. Following strings should not be used in any value for options: C<+check>, C<+info>, C<+quick>, C<--header> as they my trigger the I<--header> option unintentional. The used L command cannot be defined with a full path like L can with the I<--openssl=path/to/openssl> . I<--cfg-text=FILE> cannot be used to redefine the texts C and C as used in the output for I<+cipher> command. =head2 Checks (general) =head3 +constraints This check is only done for the certificate provided by the target. All other certificate in the chain are not checked. This is currently (2018) a limitation in o-saft.pl. =head2 Broken pipe This error message most likely means that the connection to specified target was not possible (firewall or whatever reason). =head2 Target Certificate Chain Verification The systems default capabilities i.e. libssl.so, openssl, are used to verify the target's certificate chain. Unfortunately various systems have implemented different approaches and rules how identify and how to report a successful verification. As a consequence this tool can only return the same information about the chain verification as the used underlying tools. If that information is trustworthy depends on how trustworthy the tools are. These limitations apply to following commands: =over =item * +verify =back =over =item * +selfsigned =back Following commands and options are useful to get more information: =over =item * +chain_verify, +verify, +error_verify, +chain, +s_client =back =over =item * --ca-file, --ca-path, --ca-depth =back =head2 User Provided Files Please note that there cannot be any guarantee that the code provided in the L L or L L will work flawless. Obviously this is the user's responsibility. =head2 Problems and Errors Checking the target for supported ciphers may return that a cipher is not supported by the server misleadingly. Reason is most likely an improper timeout for the connection. See I<--timeout=SEC> option. If the specified targets accepts connections but does not speak SSL, the connection will be closed after the system's TCP/IP-timeout. This script will hang (about 2-3 minutes). If reverse DNS lookup fails, an error message is returned as hostname, like: C<<>>. Workaround to get rid of this message: use I<--no-dns> option. All checks for EV are solely based on the information provided by the certificate. Some versions of openssl (< 1.x) may not support all required options which results in various error messages, or more worse, may not be visibale at all. Available functionalitity of openssl will be checked for right at the beginning. Proper warnings and hints are printed. Following table shows the openssl option and how to disable it within o-saft.pl: =over =item * -nextprotoneg --no-nextprotoneg =back =over =item * -reconnect --no-reconnect =back =over =item * -tlsextdebug --no-tlsextdebug =back =over =item * -alpn --no-alpn =back =head2 Connection Problems Sometimes the connection cannot be established. This may have various reasons. Unfortunaly this script seems to hang then. In particular when checking for ciphers with I<+cipher> or I<+cipherall> . The reason is most likely that the server does not respond to the TCP/IP request and hence the script closes the connection after the configured time- out (see I<--timeout=SEC> option). Continous connection attempts can be inhibited with the I<--ssl-error> option, which is set by default. Avoiding further connections results in a loss of information and consequentely, leads to wrong checks. It is a trade-off to wait for all information done accurately, or to get the results quickly. The logic to stop connecting for I<--ssl-error> can be controlled with following additional options: =over =item * --ssl-error-max=CNT - max. continous errors =back =over =item * --ssl-error-timeout=SEC - treat a failure as error after timeout =back =over =item * --ssl-error-total=CNT - max. amount of errors =back This means that no more connections are made when more than =over =item * --ssl-error-max errors occour sequentialy =back or =over =item * --ssl-error-total errors occoured =back Examples: =over =item * --ssl-error-max=3 =back =over =item * --ssl-error-timeout=6 =back =over =item * --ssl-error-total=6 =back no more connections are made if for example any sequence of timeouts occour: 0 5 2 2 - --ssl-error-max matches 0 1 3 0 0 0 4 1 2 2 2 - --ssl-error-max matches 0 5 0 2 0 2 2 0 2 0 2 - --ssl-error-total matches This allows to fine-tune the condition when to stop connecting to the target. For example, continous but not consecutive timeouts may indi- cate a bad or instable network connection, but not that the target to be connected blocks. In such a case sequence of timeouts like follows may be observed (assuming I<--ssl-error-max=3>): 0 5 1 2 2 2 4 2 3 2 3 3 3 2 . . . ^ ^____ stop for --ssl-error-timeout=3 . . . |______________________ stop for --ssl-error-timeout=2 On normal (even slow) network connections dozens of connections per second are usual, hence the timeout is always 0 or 1. Based on that experience I<--ssl-error> is enabled and set with defaults as follows: =over =item * --ssl-error-max=5 =back =over =item * --ssl-error-timeout=1 =back =over =item * --ssl-error-total=10 =back =head2 Poor Systems Use of L is disabled by default on Windows due to various performance problems. It needs to be enabled with I<--openssl> option. On Windows the usage of "openssl s_client" needs to be enabled using I<--s_client> option. On Windows it's a pain to specify a correct path for I<--openssl=TOOL> option. Variants are: =over =item * --openssl=/path/to/openssl.exe =back =over =item * --openssl=X:/path/to/openssl.exe =back =over =item * --openssl=\path\to\openssl.exe =back =over =item * --openssl=X:\path\to\openssl.exe =back =over =item * --openssl=\\path\\to\\openssl.exe =back =over =item * --openssl=X:\\path\\to\\openssl.exe =back You have to fiddle around to find the proper one. =head2 Debug and Trace Output When both I<--trace-key> and I<--trace-cmd> options are used, output is mixed, obviously. Hint: output for I<--trace-cmd> always contains "CMD". Any I<--trace*> option implies I<--trace-time> . =head1 DEPENDENCIES All perl modules and all private moduels and files will be searched for using paths available in the C<@INC> variable. C<@INC> will be prepended by following paths: =over =item * . =back =over =item * ./lib =back =over =item * INSTALL_PATH =back =over =item * INSTALL_PATH/lib =back Where C is the path where the tool is installed. To see which files have been included use: o-saft.pl +version --v --user =head2 Perl Modules =over =item * L =back =over =item * L =back =over =item * L =back =over =item * L =back =over =item * L =back =head2 Additional files used if requested =over =item * .o-saft.pl =back =over =item * L =back =over =item * L =back =over =item * L =back =over =item * L =back =over =item * o-saft-docker =back =head1 INSTALLATION The tool can be installed in any path. It just requres the modules as described in L above. However, it's recommended that the modules L and L are found in the directory C<./Net/> where C is installed. For security reasons, most modern libraries disabled or even removed insecure or "dirty" functionality. As the purpose of this tool is to detect such insecure settings, functions, etc., it needs these dirty things enabled. It needs (incomplete list): =over =item * insecure protocols like SSLv2, SSLv3 =back =over =item * more ciphers enabled, like NULL-MD5, AECDH-NULL-SHA, etc. =back =over =item * some SSL extensions and options =back Therefore we recommend to compile and install at least following: =over =item * OpenSSL with SSLv2, SSLv3 and more ciphers enabled =back =over =item * Net::SSLeay compiled with openssl version as described before. =back Please read the L section first before following the install instructions below. =head2 OpenSSL Currently (since 18.06.18) it is recommend to build openssl using contrib/install_openssl.sh Other possibilities are: =over =item * compiling openssl using following sources =back https://github.com/PeterMosmans/openssl/ see L, =over =item * use any of the precomiled versions provided by https://testssl.sh/ =back =over =item * use Docker owasp/o-saft (which contains a special openssl) =back The sources are available at =over =item * https://github.com/PeterMosmans/openssl/archive/1.0.2-chacha.zip =back A precomiled static versions are available at =over =item * https://github.com/drwetter/testssl.sh/ (see bin directory there) =back For all following installation examples we assume: =over =item * openssl-1.0.2-chacha.zip or openssl-1.0.2d.tar.gz =back =over =item * /usr/local as base installation directory =back =over =item * a bourne shell (sh) compatible shell =back =head2 Example: Precompiled OpenSSL Simply download the tarball or zip file for your platform, unpack it, and install (copy) the binaries into a directory of your choice. =head2 Example: Compile OpenSSL OpenSSL can be used from http://openssl.org/ or, as recommended, from https://github.com/PeterMosmans/openssl/ . OpenSSL-chacha Compiling and installing the later is as simple as: unzip openssl-1.0.2-chacha.zip cd openssl-1.0.2-chacha ./config --shared -Wl,-rpath=/usr/local/lib make make test make install which will install openssl, libssl.so, libcrypto.so and some include files as well as the include files in /usr/local/ . The shared version of the libraries are necessary for Net::SSLeay. OpenSSL.org Building openssl from the offical openssl.org sources requires some patching before compiling and installing the libraries and binaries. Example with openssl-1.0.2d: echo == unpack tarball tar xf openssl-1.0.2d.tar.gz cd openssl-1.0.2d echo == backup files to be modified cp ssl/s2_lib.c{,.bak} cp ssl/s3_lib.c{,.bak} cp ssl/ssl3.h{,.bak} cp ssl/tls1.h{,.bak} echo == patch files vi ssl/tls1.h +/TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES/ # define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 1 vi ssl/ssl3.h ssl/s{2,3}_lib.c +"/# *if 0/" #==> remove all # if 0 and corresponding #endif # except if lines contain: # _FZA # /* Fortezza ciphersuite from SSL 3.0 # /* Do not set the compare functions, # if (s->shutdown SSL_SEND_SHUTDOWN)& echo == configure with static libraries echo omitt the zlib options if zlib-1g-dev is not installed echo omitt the krb5 options if no kerberos libraries available LD_RUN_PATH=/usr/local/openssl/lib LDFLAGS="-rpath=$LD_RUN_PATH" & export LDFLAGS& ./config --prefix=/usr/local --openssldir=/usr/local/ssl \ enable-zlib zlib zlib-dynamic enable-ssl2 \ enable-krb5 --with-krb5-flavor=MIT \ enable-mdc2 enable-md2 enable-rc5 enable-rc2 \ enable-cms enable-ec enable-ec2m enable-ecdh enable-ecdsa \ enable-gost enable-seed enable-idea enable-camellia \ enable-rfc3779 enable-ec_nistp_64_gcc_128 \ experimental-jpake -fPIC \ -DTEMP_GOST_TLS -DTLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES \ -shared echo == make binaries and libraries make depend make make test make install echo == if you want static binaries and libraries make clean echo same ./config as before but without shared option ./config --prefix=/usr/local --openssldir=/usr/local/ssl \ enable-zlib zlib zlib-dynamic enable-ssl2 \ enable-krb5 --with-krb5-flavor=MIT \ enable-mdc2 enable-md2 enable-rc5 enable-rc2 \ enable-cms enable-ec enable-ec2m enable-ecdh enable-ecdsa \ enable-gost enable-seed enable-idea enable-camellia \ enable-rfc3779 enable-ec_nistp_64_gcc_128 \ experimental-jpake -fPIC -static \ -DTEMP_GOST_TLS -DTLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES make depend make make test echo next make will overwrite the previously installed dynamic echo shared openssl binary with the static openssl binary make install =head2 Example: Compile Net::SSLeay To enable support for ancient protocol versions, Net::SSLeay must be compiled manually after patching C (see below). Reason is, that Net::SSLeay enables some functionality for SSL/TLS according the identified openssl version. There is, currently (2015), no possibility to enable this functionality by passing options on to the configuration script C. Building our own library and module (with openssl from C): echo == unpack tarball tar xf Net-SSLeay-1.72.tar.gz cd Net-SSLeay-1.72 echo == patch files echo "edit SSLeay.xs and change some #if as described below" LD_RUN_PATH=/usr/local/openssl/lib LDFLAGS="-rpath=$LD_RUN_PATH" & export LDFLAGS& env OPENSSL_PREFIX=/usr/local perl Makefile.PL PREFIX=/usr/local \ INC=-I/usr/local/include DEFINE=-DOPENSSL_BUILD_UNSAFE=1 make make install cd /tmp & o-saft.pl +version& SSLeay.xs needs to be changed as follows: =over =item * search for =back #ifndef OPENSSL_NO_SSL2 #if OPENSSL_VERSION_NUMBER < 0x10000000L const SSL_METHOD * SSLv2_method() #endif #endif #ifndef OPENSSL_NO_SSL3 #if OPENSSL_VERSION_NUMBER < 0x10002000L const SSL_METHOD * SSLv3_method() #endif #endif =over =item * and replace by =back const SSL_METHOD * SSLv2_method() const SSL_METHOD * SSLv3_method() Note that Net::SSLeay will be installed in C then. This can be adapted to your needs by passing another path to the C and C parameter. Following command can be used to check which methods are avilable in Net::SSLeay, hence above patches can be verified: perl -MNet::SSLinfo -le 'print Net::SSLinfo::ssleay_test();' =head2 Testing OpenSSL After installation as descibed above finished, openssl may be tested: echo already installed openssl (found with PATH environment) openssl ciphers -v openssl ciphers -V -ssl2 openssl ciphers -V -ssl3 openssl ciphers -V ALL openssl ciphers -V ALL:COMPLEMENTOFALL openssl ciphers -V ALL:eNULL:EXP echo own compiled and installed openssl /usr/local/openssl ciphers -v /usr/local/openssl ciphers -V -ssl2 /usr/local/openssl ciphers -V -ssl3 /usr/local/openssl ciphers -V ALL /usr/local/openssl ciphers -V ALL:COMPLEMENTOFALL /usr/local/openssl ciphers -V ALL:eNULL:EXP The difference should be obvious. Note, the commands using C and C should return the same result. =head2 Testing Net::SSLeay As we want to test the separately installed Net::SSLeay, it is best to do it with o-saft.pl itself: o-saft.pl +version we should see a line similar to follwong at the end of the output: Net::SSLeay 1.72 /usr/local/lib/x86_64-linux-gnu/perl/5.20.2/Net/SSLeay.pm Now check for supported (known) ciphers: o-saft.pl ciphers -V we should see lines similar to those of the last C call. However, it should contain more cipher lines. =head2 Stand-alone Executable Some people asked for a stand-alone executable (mainly for Windows). Even perl is a scripting language there are situations where a stand- alone executable would be nice, for example if the installed perl and its libraries are outdated, or if perl is missing at all. Currently (2016) there are following possibilities to generate such a stand-alone executable: =over =item * perl with PAR::Packer module =back pp -C -c o-saft.pl pp -C -c o-saft.pl -M Net::DNS -M Net::SSLeay -M IO::Socket \ -M Net::SSLinfo -M Net::SSLhello -M osaft pp -C -c checkAllCiphers.pl pp -C -c checkAllCiphers.pl -M Net::DNS =over =item * ActiveState perl with its perlapp =back perlapp --clean o-saft.pl perlapp --clean o-saft.pl -M Net::DNS -M Net::SSLeay -M IO::Socket \ -M Net::SSLinfo -M Net::SSLhello -M osaft perlapp --clean checkAllCiphers.pl perlapp --clean checkAllCiphers.pl -M Net::DNS -M osaft =over =item * perl2exe from IndigoSTar =back perl2exe o-saft.pl perl2exe checkAllCiphers.pl For details on building the executable, for example how to include all required modules, please refer to the documentation of the tool. =over =item * http://search.cpan.org/~rschupp/PAR-Packer-1.030/lib/PAR/Packer.pm =back =over =item * http://docs.activestate.com/pdk/6.0/PerlApp.html =back =over =item * http://www.indigostar.com =back Note that pre-build executables (build by perlapp, perl2exe) cannot be provided due to licence problems. Also note that using stand-alone executable have not been tested the same way as the o-saft.pl itself. Use them at your own risk. =head1 DOCKER The tool can be used inside a Docker image. To start o-saft.pl inside the Docker image, use following: o-saft-docker +info some.tld or docker run --rm -it owasp/o-saft +info some.tld For more details, please refer to: o-saft-docker usage o-saft-docker -help =head1 BUILD DOCKER IMAGE The Docker image can be installed as follows: docker pull owasp/o-saft The image can also easily be build from the Dockerfile (which is part of the distribution) as follows: o-saft-docker build To build the image from the Dockerfile with docker commands, see: o-saft-docker -n build For more details, please refer to: o-saft-docker -help =head1 SEE ALSO =over =item * L, L, L, L, L =back =over =item * http://www.openssl.org/docs/apps/ciphers.html =back =over =item * L, L =back =over =item * o-saft, o-saft-docker, o-saft-docker-dev, Dockerfile, docker =back =head1 HACKER's INFO =head2 Note on SSL versions Automatically detecting the supported SSL versions of the underlaying system is a hard job and not always possible. Reasons could be: =over =item * used perl modules (Socket::SSL, Net::SSLeay) does not handle errors =back properly. Erros may be: invalid SSL_version specified at ... IO/Socket/SSL.pm Use of uninitialized value in subroutine entry at lib/IO/Socket/SSL.pm There're some workarounds implemented since version 15.11.15 . =over =item * the underlaying libssl does not support the version, which then may =back result in segmentation fault =over =item * the underlaying libssl is newer than the perl module and the module =back has not been reinstalled. This most often happens with Net::SSLeay This can be detected with (see version numbers for Net::SSLeay): o-saft.pl +version =over =item * perl (in particular a used module, see above) may bail out with a =back compile error, like Can't locate auto/Net/SSLeay/CTX_v2_new.al in @INC ... There're some workarounds implemented since version 15.11.15 . We try to detect unsupported versions and disable them automatically, a warning like follwoing is shown then: **WARNING: SSL version 'SSLv2': not supported by openssl All such warnings look like: **WARNING: SSL version 'SSLv2': ... If problems occour with SSL versions, following commands and options may help to get closer to the reason or can be used as workaround: o-saft.pl +version o-saft.pl +version --v o-saft.pl +version | grep versions o-saft.pl +version | grep 0x o-saft.pl +protocols your.tld o-saft.pl +protocols your.tld --no-rc Checking for SSL version is done at one place in the code, search for supported SSL versions However, there are some dirty hacks where SSLv2 and SSLv3 is checked again. =head2 Using private libssl.so and libcrypt.so For all cryptographic functionality the libraries installed on the system will be used. In particular perl's L module, the system's libssl.so and libcrypt.so and the L executable. It is possible to provide your own libraries, if the perl module and the executable are linked using dynamic shared objects (aka shared library, position independent code). The appropriate option is I<--lib=PATH>. On most systems these libraries are loaded at startup of the program. The runtime loader uses a preconfigured list of directories where to find these libraries. Also most systems provide a special environment variable to specify additional paths to directories where to search for libraries, for example the LD_LIBRARY_PATH environment variable. This is the default environment variable used herein. If your system uses another name it must be specified with the I<--envlibvar=NAME> option, where NAME is the name of the environment variable. =head2 Understanding --exe=PATH, --lib=PATH, --openssl=TOOL If any of I<--exe=PATH> or I<--lib=PATH> is provided, the pragram calls (C) itself recursively with all given options, except the option itself. The environment variables C and C are set before executing as follows: =over =item * prepend C with all values given with --exe=PATH =back =over =item * prepend C with all values given with --lib=PATH =back This is exactly, what L below describes. So these option simply provide a shortcut for that. Note that I<--openssl=TOOL> is a full path to the openssl executable and will not be changed. However, if it is a relative path, it might be searched for using the previously set C (see above). Note that C is the default. It can be changed with the I<--envlibvar=NAME> option. While I<--exe> mainly impacts the L executable, I<--lib> also impacts o-saft.pl itself, as it loads other shared libraries if found. Bear in mind that all these options can affect the behaviour of the openssl subsystem, influencing both which executable is called and which shared libraries will be used. NOTE that no checks are done if the options are set proper. To verify the settings, following commands may be used: o-saft.pl --lib=YOUR-PATH --exe=YOUR-EXE +version o-saft.pl --lib=YOUR-PATH --exe=YOUR-EXE --v +version o-saft.pl --lib=YOUR-PATH --exe=YOUR-EXE --v --v +version Why so many options? Exactly as described above, these options allow the users to tune the behaviour of the tool to their needs. A common use case is to enable the use of a separate openssl build independent of the openssl package used by the operating system. This allows the user fine grained control over openssl's encryption suites which are compiled/available, without affecting the core system. =head2 Caveats Depending on your system and the used modules and executables, it can be tricky to replace the configured shared libraries with own ones. Reasons are: =over =item * a) the linked library name contains a version number, =back =over =item * b) the linked library uses a fixed path, =back =over =item * c) the linked library is searched at a predefined path, =back =over =item * d) the executable checks the library version when loaded. =back Only the first one a) can be circumvented. The last one d) can often be ignored as it only prints a warning or error message. To circumvent the "name with version number" problem try following: =over =item * 1) use L (or a similar tool) to get the names used by openssl: =back ldd /usr/bin/openssl which returns something like: libssl.so.0.9.8 => /lib/libssl.so.0.9.8 (0x00007f940cb6d000) libcrypto.so.0.9.8 => /lib/libcrypto.so.0.9.8 (0x00007f940c7de000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f940c5d9000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f940c3c1000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f940c02c000) /lib64/ld-linux-x86-64.so.2 (0x00007f940cdea000) Here only the first two libraries are important. Both, libcrypto.so and libssl.so need to be version "0.9.8" (in this example). =over =item * 2) create a directory for your libraries, i.e.: =back mkdir /tmp/dada =over =item * 3) place your libraries there, assuming they are: =back /tmp/dada/libssl.so.1.42 /tmp/dada/libcrypto.so.1.42 =over =item * 4) create symbolic links in that directory: =back ln -s libssl.so.1.42 libssl.so.0.9.8 ln -s libcrypto.so.1.42 libcrypto.so.0.9.8 =over =item * 5) test program with following option: =back o-saft.pl +libversion --lib=/tmp/dada o-saft.pl +list --v --lib=/tmp/dada or: o-saft.pl +libversion --lib=/tmp/dada -exe=/path/to-openssl o-saft.pl +list --v --lib=/tmp/dada -exe=/path/to-openssl =over =item * 6) start program with your options, i.e.: =back o-saft.pl --lib=/tmp/dada +ciphers This works if L uses the same shared libraries as L, which most likely is the case. It's tested with Unix/Linux only. It may work on other platforms also if they support such an environment variable and the installed L and L are linked using dynamic shared objects. Depending on compile time settings and/or the location of the used tool or lib, a warning like following may occur: WARNING: can't open config file: /path/to/openssl/ssl/openssl.cnf This warning can be ignored, usually as req or ca sub commands of openssl is not used here. To fix the problem, either use I<--openssl-cnf=FILE> option or set the the environment variable OPENSSL_CONF properly. =head3 Cumbersome Approach A more cumbersome approach to call this program is to set following environment variables in your shell: PATH=/tmp/dada-1.42/apps:$PATH LD_LIBRARY_PATH=/tmp/dada-1.42 =head3 Windows Caveats I.g. the used libraries on Windows are libeay32.dll and ssleay32.dll. Windows also supports the LD_LIBRARY_PATH environment variable. If it does not work as expected with that variable, it might be possible to place the libs in the same directory as the corresponding executable (which is found by the PATH environment variable). =head2 Using CGI mode This script can be used as CGI application. Output is the same as in common CLI mode, using C. Keep in mind that the used modules like L will write some debug messages on STDERR instead STDOUT. Therefore multiple I<--v> and/or I<--trace> options behave slightly different. No additional external files like L or L are read in CGI mode; they are silently ignored. Some options are disabled in CGI mode because they are dangerous or don't make any sense. =head3 WARNING There are no input data validation checks implemented herein. All input data is url-decoded once and then used verbatim. More advanced checks must be done outside before calling this tool. It is not recommended to run this tool in CGI mode. You have been warned! =head2 Using user specified code There are some functions called within the program flow, which can be filled with any perl code. Empty stubs of the functions are prepared in L. See also L . =head1 DEBUG =head2 Debugging, Tracing Following options and commands are useful for hunting problems with SSL connections and/or this tool. Note that some options can be given multiple times to increase amount of listed information. Also keep in mind that it's best to specify I<--v> as very first argument. Note that the file L is required, if any I<--trace*> or I<--v> option is used. =head2 Commands =over =item * +dump =back =over =item * +libversion =back =over =item * +s_client =back =over =item * +todo =back =over =item * +version =back =head2 Options =over =item * --v =back =over =item * --v-- =back =over =item * --trace =back =over =item * --trace-arg =back =over =item * --trace-cmd =back =over =item * --trace-key =back Empty or undefined strings are written as C<<>> in texts. Some parameters, in particular those of HTTP responses, are written as C<<>>. Long parameter lists are abbreviated with C<...>. =head2 Output When using I<--v> and/or I<--trace> options, additional output will be prefixed with a C<#> (mainly as first, left-most character. Following formats are used: =over =item * #[space] =back Additional text for verbosity (--v options). =over =item * #[variable name][TAB] =back Internal variable name (--trace-key options). =over =item * #o-saft.pl:: =back =over =item * #L:: =back Trace information for I<--trace> options. =over =item * #{ =back Trace information from NET::SSLinfo for I<--trace> options. These are data lines in the format: #{ variable name : value #} Note that C here can span multiple lines and ends with: #} =head2 Using outdated modules The tools was designed to work with old perl modules too. When using old modules, a proper C<**WARNING:> will be printed. These warinings cannot be switched of using I<--no-warning> . The warning also informs about the missing functionality or check. I.g. it is best to install newer versions of the module if possible. A good practice to check if modules are available in a proper version is to call: o-saft.pl +version o-saft.pl +version --v --v Following example shows the result without warnings: === reading: ./.o-saft.pl (RC-FILE done) === === reading: Net/SSLhello.pm (O-Saft module done) === === reading: Net/SSLinfo.pm (O-Saft module done) === === ./o-saft.pl 16.09.09 === Net::SSLeay:: ::OPENSSL_VERSION_NUMBER() 0x268443744 ::SSLeay() 0x268443744 Net::SSLeay::SSLeay_version() OpenSSL 1.0.2-chacha (1.0.2f-dev) = openssl = version of external executable OpenSSL 1.0.2-chacha (1.0.2f-dev) external executable /opt/openssl-chacha/bin/openssl used environment variable (name) LD_LIBRARY_PATH environment variable (content) <> path to shared libraries full path to openssl.cnf file <> common openssl.cnf files /usr/lib/ssl/openssl.cnf \ . /etc/ssl/openssl.cnf \ . /System//Library/OpenSSL/openssl.cnf \ . /usr/ssl/openssl.cnf URL where to find CRL file <> directory with PEM files for CAs /opt/tools/openssl-chacha/ssl/certs PEM format file with CAs /etc/ssl/certs/ca-certificates.crt common paths to PEM files for CAs /etc/ssl/certs /usr/lib/certs \ . /System/Library/OpenSSL common PEM filenames for CAs ca-certificates.crt certificates.crt certs.pem number of supported ciphers 177 openssl supported SSL versions SSLv3 TLSv1 TLSv11 TLSv12 o-saft.pl known SSL versions SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 TLSv13 \ . DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13 = o-saft.pl +cipherall = default list of ciphers 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300C0FF, . 0x0300CC00 .. 0x0300CCFF, 0x0300FE00 .. 0x0300FFFF, = Required (and used) Modules = @INC ./ ./lib . /bin /usr/share/perl5 \ . /usr/lib/x86_64-linux-gnu/perl5/5.20 \ . /usr/lib/x86_64-linux-gnu/perl/5.20 \ . /usr/share/perl/5.20 /usr/local/lib/site_perl . = module name VERSION found in = ----------------------+--------+------------------------------------------ IO::Socket::INET 1.35 /usr/lib/x86_64-linux-gnu/perl/5.20/IO/Socket/INET.pm IO::Socket::SSL 2.002 /usr/share/perl5/IO/Socket/SSL.pm Net::DNS 0.81 /usr/lib/x86_64-linux-gnu/perl5/5.20/Net/DNS.pm Net::SSLeay 1.72 /usr/lib/x86_64-linux-gnu/perl5/5.20/Net/SSLeay.pm Net::SSLinfo 16.06.01 Net/SSLinfo.pm Net::SSLhello 16.05.16 Net/SSLhello.pm Ciphers osaft 16.05.10 osaft.pm Following example shows the result with warnings (line nr. may vary): === reading: ./.o-saft.pl (RC-FILE done) === === reading: ./Net/SSLhello.pm (O-Saft module done) === **WARNING: ancient Net::SSLeay 1.35 < 1.49; cannot use ::initialize at /Net/SSLinfo.pm line 481. === reading: ./Net/SSLinfo.pm (O-Saft module done) === **WARNING: ancient perl has no 'version' module; version checks may not be accurate; at o-saft.pl line 1662. **WARNING: ancient Net::SSLeay 1.35 < 1.49 detected; at o-saft.pl line 1687. **WARNING: ancient IO::Socket::SSL 1.22 < 1.37 detected; at o-saft.pl line 1687. **WARNING: ancient version IO::Socket::SSL 1.22 < 1.90 does not support SNI or is known to be buggy; SNI disabled; at o-saft.pl line 5905. !!Hint: --force-openssl can be used to disables this check **WARNING: ancient version Net::SSLeay 1.35 < 1.49 may throw warnings and/or results may be missing; at o-saft.pl line 5934. **WARNING: SSL version 'TLSv11': not supported by Net::SSLeay; not checked **WARNING: SSL version 'TLSv12': not supported by Net::SSLeay; not checked **WARNING: SSL version 'TLSv13': not supported by Net::SSLeay; not checked === o-saft.pl 16.09.09 === Net::SSLeay:: ::OPENSSL_VERSION_NUMBER() 0x9470143 **WARNING: ancient version Net::SSLeay 1.35 < 1.49; cannot compare SSLeay with openssl version at o-saft.pl line 4778. ::SSLeay() 0x1.35 **WARNING: ancient version Net::SSLeay 1.35 < 1.49; detailed version not available at o-saft.pl line 4806. = openssl = version of external executable OpenSSL 0.9.8y 5 Feb 2013 external executable /usr/bin/openssl used environment variable (name) LD_LIBRARY_PATH environment variable (content) <> path to shared libraries full path to openssl.cnf file <> common openssl.cnf files /usr/lib/ssl/openssl.cnf \ . /etc/ssl/openssl.cnf \ . /System//Library/OpenSSL/openssl.cnf \ . /usr/ssl/openssl.cnf URL where to find CRL file <> directory with PEM files for CAs /System/Library/OpenSSL/certs PEM format file with CAs <> common paths to PEM files for CAs /etc/ssl/certs /usr/lib/certs /System/Library/OpenSSL common PEM filenames for CAs ca-certificates.crt certificates.crt certs.pem number of supported ciphers 43 openssl supported SSL versions SSLv2 SSLv3 TLSv1 o-saft.pl known SSL versions SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 TLSv13 \ . DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13 **WARNING: ancient version Net::SSLeay 1.35 < 1.49; cannot compare SSLeay with openssl version at o-saft.pl line 4778. **WARNING: used openssl version '9470143' differs from compiled Net:SSLeay '1.35'; ignored = o-saft.pl +cipherall = default list of ciphers 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300C0FF, . 0x0300CC00 .. 0x0300CCFF, 0x0300FE00 .. 0x0300FFFF, = Required (and used) Modules = @INC ./ ./lib /bin /Library/Perl/Updates/5.10.0 \ . /System/Library/Perl/5.10.0/darwin-thread-multi-2level \ . /System/Library/Perl/5.10.0 \ . /Library/Perl/5.10.0/darwin-thread-multi-2level \ . /Library/Perl/5.10.0 \ . /Network/Library/Perl/5.10.0/darwin-thread-multi-2level \ . /Network/Library/Perl/5.10.0 \ . /Network/Library/Perl \ . /System/Library/Perl/Extras/5.10.0/darwin-thread-multi-2level \ . /System/Library/Perl/Extras/5.10.0 . = module name VERSION found in = ----------------------+--------+------------------------------------------ IO::Socket::INET 1.31 /System/Library/Perl/5.10.0/darwin-thread-multi-2level/IO/Socket/INET.pm IO::Socket::SSL 1.22 /System/Library/Perl/Extras/5.10.0/IO/Socket/SSL.pm Net::DNS 0.65 /System/Library/Perl/Extras/5.10.0/darwin-thread-multi-2level/Net/DNS.pm Net::SSLeay 1.35 /System/Library/Perl/Extras/5.10.0/darwin-thread-multi-2level/Net/SSLeay.pm Net::SSLinfo 16.06.01 ./Net/SSLinfo.pm Net::SSLhello 16.05.16 ./Net/SSLhello.pm osaft 16.05.10 /osaft.pm Please keep in mind that the shown version numbers and the shown line numbers are examples and may differ on your system. When starting o-saft.pl with outdated modules, more C<**WARNING:> will be shown. The warnings depend on the installed version of the module. o-saft.pl is known to work with at least: IO::Socket::INET 1.31, IO::Socket::SSL 1.22, Net::DNS 0.65 Net::SSLeay 1.30 =head1 TESTING When talking about "testing the tool", functional tests are meant. So this section describes "developer" rather that "user" options. Testing the tool is a challenging task. Beside the oddities described elsewhere, for example L, there are a bunch of problems and errors which may occour during runtime. Following options and commands are available to improve testing. They mainly can simulate error conditions or stop execution properly (they are not intended for other use cases): =head3 +quit Stop execution after processing all arguments and before precessing any target. The runtime configuration is complete at this point. =head3 --exit=KEY Terminate tool at specified C. For available C, please see: o-saft.pl --help=exit grep exit= o-saft.pl =head3 --cfg-init=KEY=VALUE With this option values in the internal %cfg hash can be set: $cfg{KEY} = VALUE Only (perl) scalars or arrays can be set. The type will be detected automatically. Example, this option can be used to change the text used as prefix in each output line triggerd by the I<--v> option: o-saft.pl --cfg-init=prefix_verbose="#VERBOSE: " or the text used as prefix triggerd by the I<--trace> option: o-saft.pl --cfg-init=prefix_trace="#TRACE: " =head1 EXAMPLES (o-saft.pl in all following examples is the name of the tool) =head2 General o-saft.pl +cipher some.tld o-saft.pl +info some.tld o-saft.pl +check some.tld o-saft.pl +quick some.tld o-saft.pl +help=commands o-saft.pl +certificate some.tld o-saft.pl +fingerprint some.tld 444 o-saft.pl +after +dates some.tld o-saft.pl +version o-saft.pl +version --v o-saft.pl +list o-saft.pl +list --v =head2 Some specials =over =item * Get an idea how messages look like =back o-saft.pl +check --cipher=RC4 some.tld =over =item * Check for Server Name Indication (SNI) usage only =back o-saft.pl +sni some.tld =over =item * Check for SNI and print certificate's subject and altname =back o-saft.pl +sni +cn +altname some.tld =over =item * Check for all SNI, certificate's subject and altname issues =back o-saft.pl +sni_check some.tld =over =item * Only print supported ciphers =back o-saft.pl +cipher --enabled some.tld =over =item * Only print unsupported ciphers =back o-saft.pl +cipher --disabled some.tld =over =item * Test for a specific ciphers =back o-saft.pl +cipher --cipher=ADH-AES256-SHA some.tld =over =item * Test all ciphers, even if not supported by local SSL implementation =back o-saft.pl +cipherraw some.tld o-saft.pl +cipherall some.tld o-saft.pl +cipherall some.tld --range=full checkAllCiphers.pl example.tld I--range=full& I&--v&& =over =item * Show supported (enabled) ciphers with their DH parameters: =back o-saft.pl +cipher-dh some.tld =over =item * Test using a private libssl.so, libcrypto.so and openssl =back o-saft.pl +cipher --lib=/foo/bar-1.42 --exe=/foo/bar-1.42/apps some.tld =over =item * Test using a private openssl =back o-saft.pl +cipher --openssl=/foo/bar-1.42/openssl some.tld =over =item * Test using a private openssl also for testing supported ciphers =back o-saft.pl +cipher --openssl=/foo/bar-1.42/openssl --force-openssl some.tld =over =item * Use your private texts in output =back o-saft.pl +check some.tld --cfg-text=desc="my special description" =over =item * Use your private texts from RC-FILE =back o-saft.pl --help=cfg-text >> .o-saft.pl edit as needed: .o-saft.pl o-saft.pl +check some.tld =over =item * Use your private hint texts in output =back o-saft.pl +check some.tld --cfg-hint=renegotiation="my special hint text" =over =item * Get the certificate's Common Name for a bunch of servers: =back o-saft.pl +cn example.tld some.tld other.tld o-saft.pl +cn example.tld some.tld other.tld --showhost --no-header =over =item * Generate simple parsable output =back o-saft.pl --legacy=quick --no-header +info some.tld o-saft.pl --legacy=quick --no-header +check some.tld o-saft.pl --legacy=quick --no-header --trace-key +info some.tld o-saft.pl --legacy=quick --no-header --trace-key +check some.tld =over =item * Generate simple parsable output for multiple hosts =back o-saft.pl --legacy=quick --no-header --trace-key --showhost +check some.tld other.tld =over =item * Just for curiosity =back o-saft.pl some.tld +fingerprint --format=raw o-saft.pl some.tld +certificate --format=raw | openssl x509 -noout -fingerprint =head2 Specials for hunting problems with connections etc. =over =item * Do not read RC-FILE .o-saft.pl =back o-saft.pl +info some.tld --no-rc =over =item * Show command line argument processing =back o-saft.pl +info some.tld --trace-arg =over =item * Simple tracing =back o-saft.pl +cn some.tld --trace o-saft.pl +info some.tld --trace =over =item * A bit more tracing =back o-saft.pl +cn some.tld --trace --trace =over =item * Show internal variable names in output =back o-saft.pl +info some.tld --trace-key =over =item * Show internal argument processeing =back o-saft.pl +info --trace-arg some.tld =over =item * Show internal control flow =back o-saft.pl +info some.tld --trace-cmd =over =item * Show internal timing =back o-saft.pl +info some.tld --trace-time =over =item * Show checking ciphers =back o-saft.pl +cipher some.tld --v --v =over =item * Show values retrieved from target certificate directly =back o-saft.pl +info some.tld --no-cert --no-cert --no-cert-text=Value-from-Certificate =over =item * Show certificate CA verifications =back o-saft.pl some.tld +chain_verify +verify +error_verify +chain =over =item * Avoid most performance and timeout problems (don't use --v) =back o-saft.pl +info some.tld --no-dns --no-sni --ignore-no-conn o-saft.pl +info some.tld --no-dns --no-sni --no-cert --no-http --no-openssl =over =item * Identify timeout problems =back o-saft.pl +info some.tld --trace-cmd this will show lines containing: #O-Saft CMD: test ... =head1 ATTRIBUTION Based on ideas (in alphabetical order) of: =over =item * cnark.pl, SSLAudit.pl sslscan, ssltest.pl, sslyze.py, testssl.sh =back =over =item * O-Saft - OWASP SSL advanced forensic tool =back Thanks to Gregor Kuznik for this title. =over =item * +cipherraw and some proxy functionality implemented by Torsten Gigler. =back =over =item * For re-writing some docs in proper English, thanks to Robb Watson. =back =over =item * Code to check heartbleed vulnerability adapted from =back Steffen Ullrich (08. April 2014): https://github.com/noxxi/p5-scripts/blob/master/check-ssl-heartbleed.pl =over =item * Colouration inspired by https://testssl.sh/ . =back =head1 VERSION @(#) 19.01.19 =head1 AUTHOR 31. July 2012 Achim Hoffmann (at) sicsec de Project Home: https://www.owasp.org/index.php/O-Saft =head1 TODO =over =item * new features =back =over =item ** client certificate =back =over =item ** some STRATTLS need : HELP STARTTLS HELP as output of HELPs are different =back =over =item ** support: PCT protocol =back =over =item ** Checking fallback from TLS 1.1 to TLS 1.0 (see ssl-cipher-check.pl) =back =over =item ** Minimal encryption strength: weak encryption (40-bit) (TestSSLServer.jar) =back =over =item ** check dynamic HTTP Public Key Pinning (HPKP) =back =over =item * missing checks =back =over =item ** SSL_honor_cipher_order => 1 =back =over =item ** implement TLSv1.2 checks =back =over =item ** DNSEC and TLSA =back =over =item ** checkcert(): KeyUsage, keyCertSign, BasicConstraints =back =over =item ** DV and EV miss some minor checks; see checkdv() and checkev() =back =over =item ** +constraints does not check +constraints in the certificate of =back the certificate chain. =over =item ** TR-03116-4: does not check data in certificate chain =back =over =item ** RFC 7525: does not check data in certificate chain =back =over =item ** RFC 7525: 3.2. Strict TLS (for C) =back =over =item ** RFC 7525: 3.4. TLS Session Resumption (session ticket must be =back authenticated and encrypted) =over =item ** RFC 7525: 3.6. Server Name Indication (more reliable check) =back =over =item ** RFC 7525: 4.3. Public Key Length (need more reliable check) =back =over =item ** RFC 7525: 6.2. AES-GCM =back =over =item ** RFC 7525: 6.3. Forward Secrecy =back =over =item ** RFC 7525: 6.4. Diffie-Hellman Exponent Reuse =back =over =item * vulnerabilities =back =over =item ** Ticketbleed =back =over =item ** complete TIME, BREACH check =back =over =item ** BEAST more checks, see: http://www.bolet.org/TestSSLServer/ =back =over =item * verify CA chain: =back =over =item ** L.pm implement verify* =back =over =item ** implement +check_chain (see L.pm implement verify* also) =back =over =item ** implement +ca = +verify +chain +rootcert +expired +fingerprint =back =over =item * postprocessing =back Remove all options for output formatting. Use a "postprocess" script instead. =over =item ** scoring =back implement score for PFS; lower score if not all ciphers support PFS make clear usage of score from %checks =over =item ** write postprocessor for tabular data, like =back ssl-cert-check -p 443 -s mail.google.com -i -V =over =item * L =back =over =item ** Net::SSLeay::ctrl() sometimes fails, but doesn't return error message =back =over =item ** Net::SSLeay::CTX_clear_options() =back Need to check the difference between the SSL_OP_LEGACY_SERVER_CONNECT and SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; see also SSL_clear_options(). see https://www.openssl.org/docs/ssl/SSL_CTX_set_options.html =over =item ** L::do_ssl_close() does not realy work =back =over =item * Windows =back =over =item ** Unicode: =back try: cmd /K chcp 65001 or: chcp 65001 or: reg add hklm\system\currentcontrolset\control\nls\codepage -v oemcp -d 65001 =over =item ** perl =back perl 5.10.x from PortableApps does not work, cause it misses IO/Socket/SSL.pm, however, checkAllCiphers.pl works. perl from older PortableApps/xampp (i.e. 1.7.x) does not work, cause IO/Socket/SSL.pm is too old (1.37). =over =item ** Windows =back on Windows print of strings > 32k does not work. Ugly workaround using I<--v> implemented in L only. =over =item * internal =back =over =item ** move all configuration and code for commans line arguments to Arg.pm =back =over =item ** use qr() for defining regex, see $cfg{C} =back =over =item ** print_line() has ugly code for legacy=cipher =back =over =item ** "Label" texts are defined twice: o-saft.pl and Net::SSLeay =back =over =item ** make a clear concept how to handle +CMD whether they report =back checks or informations (aka %data vs. %check_*) currently (2016) each single command returns all values =over =item ** client certificates not yet implemented in _usesocket() _useopenssl(), =back see t.client-cert.txt =over =item ** (nicht wichtig, aber sauber programmieren) =back _get_default(): L::default() benutzen Generated with: o-saft.pl --no-warnings --no-header --help=gen-pod > o-saft.pod =cut # begin abbr # =head1 abbr # # SID @(#) glossary.txt 1.13 19/01/11 00:04:14 # # # acronym | description # #------+----------------------------------------------------------------------+ # 0-RTT zero Round-Trip Time # AA Attribute Authority # AAD Additional Authenticated Data # ACME Automated Certificate Management Environment # ACL Access Control List # Adiantum ChaCha stream cipher with Poly1305 and XChaCha12 # ADH Anonymous Diffie-Hellman # Adler32 hash function # AE Authenticated Encryption # AEAD Authenticated Encryption with Additional Data # AECDHE Anonymous Ephemeral ECDH # AEM Authenticated Encryption Mode aka Advanced Encryption Mode aka OCB3 # AES Advanced Encryption Standard # AES-XTS ? # AIA Authority Information Access (certificate extension) # AKC Agreement with Key Confirmation # AKID Authority Key IDentifier # ALPN Application Layer Protocol Negotiation # AMASTRID stream cipher algorithm # ARC4 Alleged RC4 (see RC4) # ARCFOUR alias for ARC4 # ARIA 128-bit Symmetric block cipher # ARX add–rotate–xor # ASN Autonomous System Number # ASN.1 Abstract Syntax Notation number One # AtE Authenticate-then-Encrypt (see also MtE) # BACPA Blockwise-Adaptive Chosen-Plaintext Attack # BADA55 "locate weak cryptography somewhere", Bernstein, Lange, et al. # BADA55-VPR-224 improved verifiably pseudorandom 224-bit curve # BADA55-VR-224 curve useng the same prime as NIST P-224 # BADA55-VR-256 curve useng the same prime as NIST P-256 # BADA55-VR-384 curve useng the same prime as NIST P-384 # bcrypt hash function (Niels Provos, David Mazières, 1999) # BLAKE hash function (Jean-Philippe Aumasson, Luca Henzen, Willi Meier, Raphael C.-W. Phan, 2008) # BLAKE2 fast secure hashing function (2012) # BLAKE2b see BLAKE (32 bit) # BLAKE-32 see BLAKE (32 bit) # BLAKE-64 see BLAKE (64 bit) # BLAKE-224 see BLAKE (224 bit) # BLAKE-256 see BLAKE (256 bit) # BLAKE-384 see BLAKE (384 bit) # BLAKE-512 see BLAKE (512 bit) # BEAR block cipher combining stream cipher and hash function # BDH Bilinear Diffie-Hellman # BEAST Browser Exploit Against SSL/TLS # BEAST . fast block cipher for arbitrary blocksizes # BER Basic Encoding Rules # BGP Boorder Gateway Protocol # Blowfish symmetric block cipher # boomerang attack attack on BLAKE # Brainpool signature algorithm, from BSI # BREACH Browser Reconnaissance & Exfiltration via Adaptive Compression of Hypertext (a variant of CRIME) # Bullrun NSA program to break encrypted communication # CAMELLIA symmetric key block cipher; encryption algorithm 128 bit (by Mitsubishi and NTT) # CAST-128 Carlisle Adams and Stafford Tavares, block cipher # CAST5 alias for CAST-128 # CAST-256 Carlisle Adams and Stafford Tavares, block cipher # CAST6 alias for CAST-256 # cipher suite cipher suite is a named combination of authentication, encryption, and message authentication code algorithms # CA Certificate Authority (aka root CA) # CAA Certificate Authority Authorization # CAA RR CAA Resource Record # CBC Cyclic Block Chaining # CBC Cipher Block Chaining (sometimes) # CBC Ciplier Block Chaining (sometimes) # CBC-MAC Cipher Block Chaining - Message Authentication Code # CBC-MAC-ELB Cipher Block Chaining - Message Authentication Code - Encrypt Last Block # CCA chosen-ciphertext attack # CCM CBC-MAC Mode (authenticated encryption block cipher mode) # CCS Change Cipher Spec (protocol) # CDH ? Diffie-Hellman # CDP CRL Distribution Points # CECPQ1 key-agreement algorithm; Combined elliptic Curve and Post-Quantum Cryptography Key Exchange # CECPQ2 Combined elliptic Curve and Post-Quantum Cryptography Key Exchange # CEK Content Encryption Key # CFB Cipher Feedback # CFB3 Cipher Feedback # CFBx Cipher Feedback x bit mode # CFRG Crypto Forum Research Group # ChaCha stream cipher algorithm (with 256-bit key) # ChaCha8 see ChaCha # ChaCha12 see ChaCha (aka 12-round ChaCha) # ChaCha20 see ChaCha (aka 20-round ChaCha) # ChaCha-Poly1305 Authenticated Encryption with Associated Data (AEAD) # CHAP Challenge Handshake Authentication Protocol # CKA (PKCS#11) # CKK (PKCS#11) # CKM (PKCS#11) # CMAC Cipher-based MAC # CMC CBC-mask-CBC # CMP X509 Certificate Management Protocol # CMS Cryptographic Message Syntax # CMVP Cryptographic Module Validation Program (NIST) # CN Common Name # CP Certificate Policy (certificate extension) # CPA chosen-plaintext attack # CPD Certificate Policy Definitions # CPS Certification Practice Statement # CRC Cyclic Redundancy Check # CRC8 CRC with polynomial length 8 # CRC16 CRC with polynomial length 16 # CRC32 CRC with polynomial length 32 # CRC64 CRC with polynomial length 64 # CRAM Challenge Response Authentication Mechanism # CRIME Compression Ratio Info-leak Made Easy (Exploit SSL/TLS) # CRL Certificate Revocation List # CRYPTREC Cryptography Research and Evaluation Committees # CSP Certificate Service Provider # CSP Cryptographic Service Provider # CSP Critical Security Parameter (used in FIPS 140-2) # CSP: Content Security Policy (used as HTTP header) # CSR Certificate Signing Request # CSPRNG Cryptographically Secure Pseudo-Random Number Generator # CT Certificate Transparency # CTL Certificate Trust Line # CTR Counter Mode (sometimes: CM; block cipher mode) # CTS Cipher Text Stealing # Curve448 signature algorithm, aka Goldilocks (224 bit) # Curve25519 signature algorithm by Dan J. Bernstein (ca. 128 bit) # CWC CWC Mode (Carter-Wegman + CTR mode; block cipher mode) # CyaSSL formerly name of wolfSSL # DAA Data Authentication Algorithm # DAC Data Authentication Code # DACL Discretionary Access Control List # DANE DNS-based Authentication of Named Entities # DDH Decisional Diffie-Hellman (Problem) # DEA Data Encryption Algorithm (sometimes a synonym for DES) # DECIPHER synonym for decryption # DEK Data Encryption Key # DER Distinguished Encoding Rules # DES Data Encryption Standard # DESede alias for 3DES ?java only? # DESX extended DES # 3DES Tripple DES (168 bit) # 3DES-EDE alias for 3DES # 3TDEA Three-key Tripple DEA (sometimes: Tripple DES; 168 bit) # 2TDEA Double-key Tripple DEA (sometimes: Double DES; 112 bit) # D5 Verhoeff's Dihedral Group D5 Check # DH Diffie-Hellman # DHE Diffie-Hellman ephemeral (historic acronym, often used, mainly in openssl) # DLIES Discrete Logarithm Integrated Encryption Scheme # DLP Discrete Logarithm Problem # DN Distinguished Name # DNSSEC DNS Security Extension # DPA Dynamic Passcode Authentication (see CAP) # DRAGON stream cipher algorithm # DRG Deterministic Random Generator # DRBG Deterministic Random Bit Generator # DROWN Decrypting RSA with Obsolete and Weakened eNcryption (Exploit SSL/TLS) # DSA Digital Signature Algorithm # DSCP Differentiated Services Code Point # DSS Digital Signature Standard # DTLS Datagram TLS # DTLSv1 Datagram TLS 1.0 # Dual EC DBRG Dual Elliptic Curve Deterministic Random Bit Generator (NIST) # Dual_EC_DBRG Dual Elliptic Curve Deterministic Random Bit Generator (NIST) # DV Domain Validation # DV-SSL Domain Validated Certificate # EAL Evaluation Assurance Level # EAP Extensible Authentication Protocol # EAP-PSK Extensible Authentication Protocol using a Pre-Shared Key # EAX Encrypt-then-Authenticate-then-Translate # EAX EAX Mode (block cipher mode) # EAXprime alias for EAX Mode # EBC Edge Boundery Controller # EC Elliptic Curve # ECB Electronic Code Book mode # ECC Error Corection Code # ECC Elliptic Curve Cryptography # ECCSI Elliptic Curve-Based Certificateless Signatures for Identity-Based Encryption # ECDH Elliptic Curve Diffie-Hellman # ECDHE Ephemeral ECDH # ECDLP Elliptic Curve Discrete Logarithm Problem # ECDSA Elliptic Curve Digital Signature Algorithm # ECDSA-256 Elliptic Curve Digital Signature Algorithm (256 bits) # ECDSA-384 Elliptic Curve Digital Signature Algorithm (384 bits) # ECDSA-521 Elliptic Curve Digital Signature Algorithm (521 bits) # ECGDSA Elliptic Curve ??? DSA # ECHO hash function (Ryad Benadjila, Olivier Billet, Henri Gilbert, Gilles Macario-Rat, Thomas Peyrin, Matt Robshaw, Yannick Seurin, 2010) # ECIES Elliptic Curve Integrated Encryption Scheme # ECKA Elliptic Curve Key Agreement # ECKA-EG Elliptic Curve Key Agreement of ElGamal Type # ECKDSA Elliptic Curve ??? DSA # ECMQV Elliptic Curve Menezes-Qu-Vanstone # ECN Explicit Congestion Notification # ECOH Elliptic Curve only hash # # ECRYPT ?? # ECSVDP-DH Elliptic Curve Secret Value Derivation Primitive, Diffie-Hellman version # Ed25519 alias for Curve25519 # Ed448 alias for Curve448 # edwards25519 alias for Curve25519 # edwards448 alias for Curve448 # EdDSA alias for signatures using public key and private key formats, like Curve448 and Curve25519 # EDE Encryption-Decryption-Encryption # EDH Ephemeral Diffie-Hellman # EGADS Entropy Gathering and Distribution System # EGD Entropy Gathering Daemon # EKU Extended Key Usage # ELB Encrypt Last Block # ElGamal asymmetric block cipher # ENCIPHER synonym for encryption # EME ECB-mask-ECB # EME Encoding Method for Encryption # ESNI Encrypted Server Name Indication # ESP Encapsulating Security Payload # ESSIV Encrypted salt-sector initialization vector # EtA Encrypt-then-Authenticate (see also EtM) # E&A Encrypt-and-Authenticate (see also E&M) # E&M Encrypt-and-MAC (see also E&A) # EtM Encrypt-then-MAC (see also EtA) # ETSI-TS European Telecommunications Standards Institute - Technical Specification # EV Extended Validation # EV-SSL Extended Validation Certificate # FEAL Fast Data Encryption Algorithm # FFC Finite Field Cryptography # FFT Fast Fourier Transform # FIPS Federal Information Processing Standard # FIPS46-2 FIPS Data Encryption Standard (DES) # FIPS73 FIPS Guidelines for Security of Computer Applications # FIPS140-2 FIPS Security Requirements for Cryptographic Modules # FIPS140-3 proposed revision of FIPS 140-2 # FIPS180-3 FIPS Secure Hash Standard # FIPS186-3 FIPS Digital Signature Standard (DSS) # FIPS197 FIPS Advanced Encryption Standard (AES) # FIPS198-1 FIPS The Keyed-Hash Message Authentication Code (HMAC) # FREAK Factoring Attack on RSA-EXPORT Keys # FQDN Fully-qualified Domain Name # FSB Fast Syndrome Based Hash # FSM Finite State Machine # FZA FORTEZZA # G-DES ??? DES # GCM Galois/Counter Mode (authenticated encryption block cipher mode) # GHASH Hash funtion used in GCM # GMAC MAC for GCM # Grøstl hash function (Lars Knudsen, 2010) # Goldilocks see Curve448 # GOST Gossudarstwenny Standard (block cipher) # GOST hash function (used in GOST cipher suite) # Grainv1 stream cipher (64-bit IV) # Grainv128 stream cipher (96-bit IV) # GREASE Generate Random Extensions And Sustain Extensibility # GRØSTL256 hash function # GRØSTL512 hash function # GROESTL256 alias for GRØSTL256 # GROESTL512 alias for GRØSTL512 # HAIFA HAsh Iterative FrAmework # hash127 fast hash function (by Dan Bernstein) # HAVAL one-way hashing # HAS-160 hash function # HAS-V hash function # HC128 alias for HC128 # HC256 alias for HC256 # HC-128 stream cipher algorithm # HC-256 stream cipher algorithm # HCH Hash-Coputer-Hash # HCTR a variable-input-length encryption mode # HEARTBLEED attack against TLS extension heartbeat # HEIST HTTP Encrypted Information can be Stolen through TCP-windows # HIBE hierarchical identity-based encryption # HKDF HMAC-based Extract-and-Expand Key Derivation Function # HNF-256 hash function (Harshvardhan Tiwari, Krishna Asawa, 2014) # HMAC keyed-Hash Message Authentication Code (aka Hashed MAC) # HMQV h? Menezes-Qu-Vanstone # HPC Hasty Putting Cipher # HPKP HTTP Public Key Pinning # HPolyC ChaCha stream cipher with Poly1305 and XChaCha12, XChaCha20 # HRSS encryption algorithm # HSM Hardware Security Module # HSR Header + Secret + Random # HSTS HTTP Strict Transport Security # HTOP HMAC-Based One-Time Password # IAPM Integrity Aware Parallelizable Mode (block cipher mode of operation) # IBE Identity-Based Encryption # ICM Integer Counter Mode (alias for CTR) # IDP Issuing Distribution Points # IDEA International Data Encryption Algorithm (by James Massey and Xuejia Lai) # IESG Internet Engineering Steering Group # IETF Internet Engineering Task Force # IFC Integer Factorization Cryptography # IGE Infinite Garble Extension # IKE Internet Key Exchange # IKEv2 IKE version 2 # IND-BACPA Indistinguishability of encryptions under blockwise-adaptive chosen-plaintext attack # IND-CCA Indistinguishability of encryptions under chosen-cipgertext attack # IND-CPA Indistinguishability of encryptions under chosen-plaintext attack # INT-CTXT Integrity of ciphertext # INT-PTXT Integrity of plaintext # IRTF Internet Research Task Force # ISAKMP Internet Security Association and Key Management Protocol # IV Initialization Vector # JH hash function (Hongjun Wu, 2011) # JH-224 see JH (224 bits) # JH-256 see JH (256 bits) # JH-384 see JH (384 bits) # JH-512 see JH (512 bits) # JSSE Java Secure Socket Extension # Keccak hash function (Guido Bertoni, Joan Daemen, Michaël Peeters und Gilles Van Assche, 2012) # KCI Key Compromise Impersonation # KDF Key Derivation Function # KEA Key Exchange Algorithm (alias for FORTEZZA-KEA) # KEK Key Encryption Key # KMS Key Management Service # KPAK KMS Public Authentication Key # KSAK KMS Secret Authentication Key # KSK Key Signing Key (DNSSEC) # KU Key Usage # LAKE hash function (Jean-Philippe Aumasson, Willi Meier, Raphael C.-W. Phan, 2008) # LEXv2 stream cipher algorithm # LFSR Linear Feedback Shift Register # LION block cipher combining stream cipher and hash function # LLL Lenstra–Lenstra–Lovász, lattice basis reduction algorithm # LM hash LAN Manager hash aka LanMan hash # Logjam Attack to force server to downgrade to export ciphers # LRA Local Registration Authority # LRW Liskov, Rivest, and Wagner (blok encryption) # Lucifer block cipher (developed at IBM in the 1970s) # Lucky 13 Break SSL/TLS Protocol # MARS 128-bit block cipher (developed at IBM) # MAC Message Authentication Code # MCF Modular Crypt Format # MDC Modification Detection Code # MDC2 Modification Detection Code 2 aka Meyer-Schilling # MDC-2 same as MDC2 # MD2 Message Digest 2 # MD4 Message Digest 4 # MD5 Message Digest 5 # MEE MAC-then-Encode-then-Encrypt (see also MtE, AtE) # MEK Message Encryption Key # MECAI Mutually Endorsing CA Infrastrukture # MGF Mask Generation Function # MISTY1 block cipher algorithm # MQV Menezes-Qu-Vanstone (authentecated key agreement) # MtE MAC-then-encrypt (see also AtE) # NaCl "Salt", crypto library (by D. Bernstein, Tanja Lange, Peter Schwabe) # NCP Normalized Certification Policy (according TS 102 042) # Neokeon symmetric block cipher algorithm # NewHope post-quantum key exchange # nistp192 alias for P-192 # nistp224 alias for P-224 # nistp256 alias for P-256 # nistp384 alias for P-384 # nistp521 alias for P-521 # NLSv2 stream cipher algorithm # nonce (arbitrary) number used only once # NPN Next Protocol Negotiation # NSS Network Security Services # NTG none-Deterministic Random Generator # NTLM NT Lan Manager. Microsoft Windows challenge-response authentication method. # NTRU asymetric cipher algorithm using lattice reduction # NULL no encryption # NUMS nothing up my sleeve numbers # OAEP Optimal Asymmetric Encryption Padding # OCB Offset Codebook Mode (block cipher mode of operation) # OCB1 same as OCB # OCB2 improved OCB aka AEM # OCB3 improved OCB2 # OCELOT1 stream cipher algorithm # OCELOT2 stream cipher algorithm # OCSP Online Certificate Status Protocol # OCSP stapling formerly known as: TLS Certificate Status Request # OFB Output Feedback # OFBx Output Feedback x bit mode # OID Object Identifier # OMAC One-Key CMAC, aka CBC-MAC # OMAC1 same as CMAC # OMAC2 same as OMAC # OPIE One-time pad Password system # OTP One Time Pad # OV Organisational Validation # OV-SSL Organisational Validated Certificate # P12 see PKCS#12 # P7B see PKCS#7 # P-192 Elliptic Curve used in FIPS 186-4 (NIST) # P-224 Elliptic Curve used in FIPS 186-4 (NIST) # P-256 Elliptic Curve used in FIPS 186-4 (NIST) # P-384 Elliptic Curve used in FIPS 186-4 (NIST) # P-521 Elliptic Curve used in FIPS 186-4 (NIST) # PACE Password Authenticated Connection Establishment # PAD Peer Authorization Database # PAKE Password Authenticated Key Exchange # Panama stream cipher algorithm # PCN Pre-Congestion Notification # PBE Password Based Encryption # PBKDF2 Password Based Key Derivation Function # PC Policy Constraints (certificate extension) # PCBC Propagating Cipher Block Chaining # PCFB Periodic Cipher Feedback Mode # PCT Private Communications Transport # PEM Privacy Enhanced Mail # PES Proposed Encryption Standard # PFS Perfect Forward Secrecy # PFX see PKCS#12 (Personal Information Exchange) # PGP Pretty Good Privacy # PII Personally Identifiable Information # PKCS Public Key Cryptography Standards # PKCS1 PKCS #1: RSA Encryption Standard # PKCS3 PKCS #3: RSA Encryption Standard on how to implement the Diffie-Hellman key exchange protocol # PKCS5 PKCS #5: RSA Encryption Standard on how to derive cryptographic keys from a password # PKCS6 PKCS #6: RSA Extended Certificate Syntax Standard # PKCS7 PKCS #7: RSA Cryptographic Message Syntax Standard # PKCS8 PKCS #8: RSA Private-Key Information Syntax Standard # PKCS10 PKCS #10: Describes a standard syntax for certification requests # PKCS11 PKCS #11: RSA Cryptographic Token Interface Standard (keys in hardware devices, cards) # PKCS12 PKCS #12: RSA Personal Information Exchange Syntax Standard (public + private key stored in files) # PKE Public Key Enablement # PKI Public Key Infrastructure # PKIX Internet Public Key Infrastructure Using X.509 # PKP Public-Key-Pins # PM Policy Mappings (certificate extension) # PMAC Parallelizable MAC (by Phillip Rogaway) # PMS Pre-Master Secret # Poly1305 Authenticator (MAC) # Poly1305-AES MAC (by D. Bernstein) # POP Proof of Possession # POODLE Padding Oracle On Downgraded Legacy Encryption # PQC Post-Quantum Crypto # PRF Pseudo-Random Function # PRP Pseudo-Random Permutation # prime192v1 alias for P-192 # prime224v1 alias for P-224 # prime256v1 alias for P-256 # prime384v1 alias for P-384 # prime521v1 alias for P-521 # PRNG Pseudo-Random Number Generator # PSK Pre-shared Key # PSKC Portable Symmetric Key Container # PTG Physical Random Generator # PVT Public Validation Token # PWKE Pair-Wise Key Establishment Schemes Using Discrete Logarithm Cryptography # QUIC Quick UDP Internet Connection # RA Registration Authority (aka Registration CA) # Rabbit stream cipher algorithm # RADIUS Remote Authentication Dial-In User Service # Radix-64 alias for Base-64 # RBG Random Bit Generator # RC2 Rivest Cipher 2, block cipher by Ron Rivest (64-bit blocks) # RC4 Rivest Cipher 4, stream cipher (aka Ron's Code) # RC5 Rivest Cipher 5, block cipher (32-bit word) # RC5-64 Rivest Cipher 5, block cipher (64-bit word) # RC6 Rivest Cipher 6 # RCSU Reuters' Compression Scheme for Unicode (aka SCSU) # RFC Request for Comments # Rijndael symmetric block cipher algorithm (AES) # RIPEMD RACE Integrity Primitives Evaluation Message Digest # RLWE Ring Learning-with-Errors # RMAC Randomized MAC (block cipher authentication mode) # RNG Random Number Generator # ROT-13 see XOR # ROBOT Return Of Bleichenbacher's Oracle Threat # RTP Real-time Transport Protocol # RSASSA-PSS RSA Probabilistic Signature Scheme # RSA Rivest Sharmir Adelman (public key cryptographic algorithm) # RSS-14 Reduced Space Symbology, see GS1 # RTN Routing transit number # S/KEY One-time pad Password system # SA Subordinate Authority (aka Subordinate CA) # SACL System Access Control List # SAD Security Association Database # SAE Simultaneous Authentication of Equals # SAFER Secure And Fast Encryption Routine, block cipher # Salsa20 stream cipher (by D. Bernstein, 2005) # Salsa20/8 see scrypt # Salsa20/12 see Salsa20 # Salsa20/20 see Salsa20 # SAM syriac abbreviation mark # SAN Subject Alternate Name # Sarmal hash function # SAX Symmetric Authenticated eXchange # SBCS single-byte character set # SCA Selfsigned CA signature # SCEP Simple Certificate Enrollment Protocol # scrypt password based key derivation function (Colin Percival) # SCSU Standard Compression Scheme for Unicode (compressed UTF-16) # SCSV Signaling Cipher Suite Value # SCVP Server-Based Certificate Validation Protocol # SCT Signed Certificate Timestamp # SDES Security Description Protokol # secp192r1 alias for P-192 # secp224r1 alias for P-224 # secp256r1 alias for P-256 # secp384r1 alias for P-384 # secp521r1 alias for P-521 # SEED 128-bit Symmetric block cipher # Serpent symmetric key block cipher (128 bit) # SGC Server-Gated Cryptography # SGCM Sophie Germain Counter Mode (authenticated encryption block cipher mode) # SHA Secure Hash Algorithm # SHA-0 Secure Hash Algorithm (insecure version before 1995) # SHA-1 Secure Hash Algorithm (since 1995) # SHA-2 Secure Hash Algorithm (since 2002) # SHA-3 Secure Hash Algorithm (since 2015), see Keccak also # SHA-224 Secure Hash Algorithm (224 bit) # SHA-256 Secure Hash Algorithm (256 bit) # SHA-384 Secure Hash Algorithm (384 bit) # SHA-512 Secure Hash Algorithm (512 bit) # SHA1 alias for SHA-1 (160 bit) # SHA2 alias for SHA-2 (224, 256, 384 or 512 bit) # SHA3 alias for SHA-3 (224, 256, 384 or 512 bit) # SHA3256 alias for SHA3-256 # SHA3-224 Secure Hash Algorithm (224 bit) # SHA3-256 Secure Hash Algorithm (256 bit) # SHA3-384 Secure Hash Algorithm (384 bit) # SHA3-512 Secure Hash Algorithm (512 bit) # SHAKE128 Secure Hash Algorithm (variable bit) # SHAKE256 Secure Hash Algorithm (variable bit) # SHAvite-3 hash function (Eli Biham, Orr Dunkelman, 2009) # SHS Secure Hash Standard # SIA Subject Information Access (certificate extension) # SIC Segmented Integer Counter (alias for CTR) # SIMON block cipher combining # Skein hash function (Niels Ferguson, Stefan Lucks, Bruce Schneier, Doug Whiting, Mihir Bellare, Tadayoshi Kohno, Jon Callas, Jesse Walker, 2010) # Skein-256-256 see Skein (256 bits) # Skein-512-256 see Skein (256 bits) # Skein-512-512 see Skein (512 bits) # Skein-1024-1024 see Skein (1024 bits) # SKID Subject Key ID (certificate extension) # SKIP Message Skipping Attacks on TLS # SKIP-TLS see SKIP # Skipjack block cipher encryption algorithm specified as part of the Fortezza # SLOTH Security Losses from Obsolete and Truncated Transcript Hashes # SM4 block cipher algorithm # SMS4 see SM4 # SMACK State Machine AttaCKs # Snefu hash function # Snow20 stream cipher algorithm # SNI Server Name Indication # SNOW word-based synchronous stream ciphers (by Thomas Johansson and Patrik Ekdahl ) # Snuffle 2005 see Salsa20 # Snuffle 2008 see ChaCha # Sosemanuk stream cipher algorithm # Speck block cipher algorithm # SPD Security Policy Database # SPDY Google's application-layer protocol on top of SSL # SPECK block cipher combining # SPHINCS post-quantum hash function # SPHINCS-256 alias for SPHINCS # SPI Security Parameters Index # SPKI Subject Public Key Infrastructure # SPN Substitution-Permutation Network # SPRP Strong Pseudo-Random Permutation # Square block cipher # SRI Subresource Integrity # SRP Secure Remote Password protocol # SRTP Secure RTP # SSCD Secure Signature Creation Device # SSEE Sichere Signaturerstellungseinheit (same as SSCD) # SSK Secret Signing Key # SSL Secure Sockets Layer # SSLv2 Secure Sockets Layer Version 2 # SSLv3 Secure Sockets Layer Version 3 # SSP Security Support Provider # SSPI Security Support Provider Interface # SST Serialized Certificate Store format # STES stream cipher algorithm # Streebog hash function # Streebog-256 see Streebog # Streebog-512 see Streebog # STS Strict Transport Security # STS Station-to-Station protocol # SUF-CMA Strong UnForgeability against Chosen-Message Attacks # Sweet32 Birthday attacks on 64-bit block ciphers in TLS and OpenVPN # SWIFFT hash function (Vadim Lyubashevsky, Daniele Micciancio, Chris Peikert, Alon Rosen, 2008) # SWIFFTX see SWIFFT # TA Trust Agent # TACK Trust Assertions for Certificate Keys # TCB Trusted Computing Base # TDEA Tripple DEA # TEA Tiny Encryption Algorithm # TEK Traffic Encryption Key # TET ? # Tiger hash function # TIME Timing Info-leak Made Easy (Exploit SSL/TLS) # TIME A Perfect CRIME? TIME Will Tell # Threefish hash function # TLS Transport Layer Security # TLSA TLS Trust Anchors # TLSv1 Transport Layer Security version 1 # TLSA RR TLSA resource Record # TMAC Two-Key CMAC, variant of CBC-MAC # TOCTOU Time-of-check, time-of-use # TOFU Trust on First Use # TR-02102 Technische Richtlinie 02102 (des BSI) # TR-03116 Technische Richtlinie 03116 (des BSI) # Trivium stream cipher algorithm # TSK Transmission Security Key # TSK TACK signing key # TSP trust-Management Service Provider # TSS Time Stamp Service # TTP trusted Third Party # Twofish symmetric key block cipher (128 bit) # UC Unified Capabilities # UC Unified Communications (SSL Certificate using SAN) # UCC Unified Communications Certificate (rarley used) # UMAC message authentication code based on universal hashing; aka universal hashing MAC; optimized for 32-bit architectures # URI Uniform Resource Identifier # URL Uniform Resource Locator # VMAC Universal hashing MAC; 64-bit variant of UMAC (by Ted Krovetz and Wei Dai) # VMPC stream cipher algorithm # VR-224 alias for BADA55-VR-224 # VR-256 alias for BADA55-VR-256 # VR-384 alias for BADA55-VR-384 # WHIRLPOOL hash function # WPAD Web Proxy Auto-Discovery # wolfSSL SSL library mainly intended and used for embedded and real-time systems # X.680 X.680: ASN.1 # X.509 X.509: The Directory - Authentication Framework # X25519 alias for Curve25519 ? # X448 alias for Curve448 ? # X680 X.680: ASN.1 # X509 X.509: The Directory - Authentication Framework # X3DH Extended Triple Diffie-Hellman # XCBC eXtended CBC-MAC # XCBC-MAC same as XCBC # XChaCha12 stream cipher algorithm # XChaCha20 stream cipher algorithm # XEX XOR Encrypt XOR # XKMS XML Key Management Specification # XMACC counter-based XOR-MAC # XMACR radomized XOR-MAC # XMLSIG XML-Signature Syntax and Processing # XMSS hash function # XSalsa2 variant of Salsa20 # XTEA extended Tiny Encryption Algorithm # XTS XEX-based tweaked-codebook mode with ciphertext stealing # XUDA Xcert Universal Database API # XXTEA enhanced/corrected Tiny Encryption Algorithm # yaSSL same as CyaSSL # ZLIB Lossless compression file format # ZRTP SRTP for VoIP # ZSK Zone Signing Key (DNSSEC) # ## end abbr # begin rfc # =head1 rfc # # SID @(#) rfc.txt 1.11 19/01/11 00:05:23 # # # number| title / description # #------+----------------------------------------------------------------------+ # # url base URL for RFC descriptions # # http://tools.ietf.org/html/rfcXXXX # # http://tools.ietf.org/rfc/rfcXXXX.txt # url http://tools.ietf.org/ # 6101 SSL Version 3.0 # 6601 SSL Version 3.0 # 2246 TLS Version 1.0 (with Cipher Suites) # 4346 TLS Version 1.1 (with Cipher Suites) # 5246 TLS Version 1.2 (with Cipher Suites) # 8446 TLS Version 1.3 (with Cipher Suites) # 4347 DTLS Version 0.9 # 6347 DTLS Version 1.2 # 8447 IANA Registry Updates for TLS and DTLS # 2616 Hypertext Transfer Protocol Version 1 (HTTP/1.1) # 7540 Hypertext Transfer Protocol Version 2 (HTTP/2) # 7230 HTTP/1.1: Message Syntax and Routing # 7231 HTTP/1.1: Semantics and Content # 7232 HTTP/1.1: Conditional Requests # 7233 HTTP/1.1: Range Requests # 7234 HTTP/1.1: Caching # 7235 HTTP/1.1: Authentication # 3490 Internationalizing Domain Names in Applications (IDNA) # 3987 Internationalized Resource Identifiers (IRIs) # 4518 Internationalized String Preparation in LDAP # 3986 Uniform Resource Identifier (URI): Generic Syntax # 2104 HMAC: Keyed-Hashing for Message Authentication # 2405 The ESP DES-CBC Cipher Algorithm With Explicit IV # 2406 IP Encapsulating Security Payload (ESP) # 2407 The Internet IP Security Domain of Interpretation for ISAKMP # 2408 Internet Security Association and Key Management Protocol (ISAKMP) # 2409 The Internet Key Exchange (IKE) - 1998 # 4306 The Internet Key Exchange (IKEv2) Protocol - 2005 # 7296 The Internet Key Exchange Protocol 2 (IKEv2) - 2014 # 4753 ECP Groups for IKE and IKEv2 # 4754 IKE and IKEv2 Authentication Using the Elliptic Curve Digital Signature Algorithm (ECDSA) # 2412 AKLEY Key Determination Protocol (PFS - Perfect Forward Secrec) # 2817 Upgrading to TLS Within HTTP/1.1 # 2818 HTTP Over TLS # 2945 SRP Authentication & Key Exchange System # 2986 PKCS#10 # 5967 PKCS#10 # 2313 PKCS#1: RSA Cryptography Specifications Version 1.5 # 2437 PKCS#1: RSA Cryptography Specifications Version 2.0 # 3447 PKCS#1: RSA Cryptography Specifications Version 2.1 # 8017 PKCS#1: RSA Cryptography Specifications Version 2.2 # 2712 TLSKRB: Addition of Kerberos Cipher Suites to TLS # 3268 TLSAES: Advanced Encryption Standard (AES) Cipher Suites for TLS # 4279 TLSPSK: Pre-Shared Key Ciphersuites for TLS # 5081 TLSPGP: Using OpenPGP Keys for Transport Layer Security (TLS) Authentication - 2007 # 6091 TLSPGP: Using OpenPGP Keys for Transport Layer Security (TLS) Authentication - 2011 # 3711 The Secure Real-time Transport Protocol (SRTP) # 6189 ZRTP: Media Path Key Agreement for Unicast Secure RTP # 4309 AES-CCM Mode with IPsec Encapsulating Security Payload (ESP) # 5116 An Interface and Algorithms for Authenticated Encryption (AEAD) # 3749 TLS Compression Method (obsolete) # 3943 TLS Protocol Compression Using Lempel-Ziv-Stac (LZS) # 4680 TLS Handshake Message for Supplemental Data # 4749 TLS Compression Methods # 3546 TLS Extensions (obsolete) # 4366 TLS Extensions # 5746 TLS Extension: Renegotiation Indication Extension # 5764 TLS Extension: Secure Real-time Transport Protocol (SRTP) # 5878 TLS Extension: Authorization # 5929 TLS Extension: Channel Bindings # 6066 TLS Extension: Extension Definitions # 6520 TLS Extension: Heartbeat # 7301 TLS Extension: Application-Layer Protocol Negotiation (ALPN) # 7633 TLS Extension: Feature Extension: Must Staple # 8449 TLS Extension: Record Size Limit # 5077 TLS session resumption without Server-Side State # 6961 TLS Multiple Certificate Status Request Extension # 7627 TLS Session Hash and Extended Master Secret Extension # 6176 Prohibiting Secure Sockets Layer (SSL) Version 2.0 # 7568 Deprecating Secure Sockets Layer Version 3.0 # 6460 NSA Suite B Profile for TLS # 2560 Online Certificate Status Protocol (OCSP, obsolete) # 6267 Online Certificate Status Protocol Algorithm Agility (OCSP, obsolete) # 4210 X509 PKI Certificate Management Protocol (CMP) # 3279 x509 Algorithms and Identifiers for X.509 PKI and CRL Profile # 3739 x509 PKI Qualified Certificates Profile; EU Directive 1999/93/EC # 3280 X509 PKI Certificate and Certificate Revocation List (CRL) Profile (obsolete) # 4158 X509 PKI Certification Path Building # 4387 X509 PKI Operational Protocols: Certificate Store Access via HTTP # 5280 X509 PKI Certificate and Certificate Revocation List (CRL) Profile # 5480 X509 PKI Elliptic Curve Cryptography Subject # 5758 X509 PKI Additional Algorithms and Identifiers for DSA and ECDSA # 6960 X509 Online Certificate Status Protocol (OCSP) # 8410 X509 PKI Algorithm Identifiers for Ed25519, Ed448, X25519, and X448 # 4132 Addition of Camellia Cipher Suites to TLS # 4162 Addition of SEED Cipher Suites to TLS # 4357 Additional Cryptographic Algorithms for Use with GOST 28147-89, GOST R 34.10-94, GOST R 34.10-2001, and GOST R 34.11-94 Algorithms # 4418 UMAC: Message Authentication Code using Universal Hashing # 4491 Using the GOST Algorithms with X509 (GOST R 34.10-94, GOST R 34.10-2001, GOST R 34.11-94) # 6986 GOST R 34.11-2012: Hash Function # 4868 Using HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 with IPsec # 4785 Pre-Shared Key (PSK) Cipher Suites with NULL Encryption for TLS # 5054 Secure Remote Password (SRP) Protocol for TLS Authentication # 5114 Additional Diffie-Hellman Groups for Use with IETF Standards # 5288 AES Galois Counter Mode (GCM) Cipher Suites for TLS # 5289 TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode (GCM) # 5430 Suite B Profile for TLS # 5487 Pre-Shared Key Cipher Suites for TLS with SHA-256/384 and AES Galois Counter Mode # 5489 ECDHE_PSK Cipher Suites for TLS # 5589 Session Initiation Protocol (SIP) Call Control - Transfer # 6040 Tunnelling of Explicit Congestion Notification # 6090 Fundamental Elliptic Curve Cryptography Algorithms # 4492 TLSECC: Elliptic Curve Cryptography (ECC) Cipher Suites for TLS (obsolete) # 5639 Elliptic Curve Cryptography (ECC) Brainpool Standard Curves and Curve Generation # 5903 Elliptic Curve Groups modulo a Prime (ECP Groups) for IKE and IKEv2 # 6507 Elliptic Curve-Based Certificateless Signatures for Identity-Based Encryption (ECCSI) # 7027 Elliptic Curve Cryptography (ECC) Brainpool Curves for TLS # 7748 Elliptic Curve for Security # 8422 Elliptic Curve Cryptography (ECC) Cipher Suites for TLS Versions 1.2 and Earlier # 5528 Camellia Counter Mode and Camellia Counter with CBC-MAC Mode Algorithms # 5741 RFC Streams, Headers, and Boilerplates # 5794 Description of the ARIA Encryption Algorithm # 5932 Camellia Cipher Suites for TLS # 6209 Addition of the ARIA Cipher Suites to TLS # 6367 Addition of the Camellia Cipher Suites to TLS # 6655 AES-CCM Cipher Suites for TLS # 7251 AES-CCM Elliptic Curve Cryptography (ECC) Cipher Suites for TLS # 7507 TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks # 5055 Server-Based Certificate Validation Protocol (SCVP) # 5019 simplified RFC 2560 # 5705 Keying Material Exporters for TLS # 6125 Representation and Verification of Domain-Based Application Service (PKIX) for TLS # 6797 HTTP Strict Transport Security (HSTS) # 6962 Certificate Transparency # 6979 Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) # 7366 Encrypt-then-MAC for TLS and DTLS # 7457 Summarizing Known Attacks on TLS and DTLS # 7465 Prohibiting RC4 Cipher Suites # 7469 Public Key Pinning Extension for HTTP # 7525 Recommendations for Secure Use of TLS and DTLS # 7539 ChaCha20 and Poly1305 for IETF Protocols (obsolete) # 8439 ChaCha20 and Poly1305 for IETF Protocols # 7627 TLS Session Hash and Extended Master Secret Extension # 7905 ChaCha20-Poly1305 Cipher Suites for TLS # 7919 Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for TLS # 1135 The Helminthiasis of the Internet # 6698 DNS-Based Authentication of Named Entities (DANE) # 6844 DNS Certification Authority Authorization (CAA) Resource Record # 3610 Counter with CBC-MAC (CCM) # 3852 Cryptographic Message Syntax (CMS) # 5083 Cryptographic Message Syntax (CMS) Authenticated-Enveloped-Data Content Type # 4086 Randomness Requirements for Security # 4107 Guidelines for Cryptographic Key Management # 8032 Edwards-Curve Digital Signature Algorithm (EdDSA) # 7710 Captive Portal Using DHCP # 8484 DNS over HTTPS (DoH) # 8467 Padding for DoH und DoT # ## end rfc # begin woodoo # Some documentation is plain text, which is DATA in Perl sources. As such, # it is not detected as source, not as comment, and not as documentation # by most tools analyzing the source code. # O-Saft's public user documentation is plain text stored in separate files. # The files are usually also not counted as source. # Unfortunately, some people solely believe in statistics generated by magic # tools. They use such statistics to measure for example code quality without # looking themself at the code. # Hence the purpose of this file is to provide real comment and documentation # lines from our documentation in format of the used programming language. # Hopefully, if these people read this, they change the workflow (means: they # also review the source code) or adapt their conclusions having in mind that # statistics can be manipulated in many ways. Here we go ... # # Disclaimer: No offence meant anyhow, neither against any analyzing tool nor # against anyone using them. It is just a reminder to use the tools and their # results in a wise manner. Measuring quality is more than just automatically # generated statistics! # end woodoo O-Saft-19.01.19/o-saft.tcl000077500000000000000000004562721342117255600147730ustar00rootroot00000000000000#!/bin/sh ## restarts using wish \ exec wish "$0" ${1+"$@"} #!############################################################################# #!# Copyright (c) Achim Hoffmann, sic[!]sec GmbH #!#---------------------------------------------------------------------------- #!# If this tool is valuable for you and we meet some day, you can spend me an #!# O-Saft. I'll accept good wine or beer too :-). Meanwhile -- 'til we meet -- #!# your're encouraged to make a donation to any needy child you see. Thanks! #!#---------------------------------------------------------------------------- #!# This software is provided "as is", without warranty of any kind, express or #!# implied, including but not limited to the warranties of merchantability, #!# fitness for a particular purpose. In no event shall the copyright holders #!# or authors be liable for any claim, damages or other liability. #!# This software is distributed in the hope that it will be useful. #!# #!# This software is licensed under GPLv2. #!# #!# GPL - The GNU General Public License, version 2 #!# as specified in: http://www.gnu.org/licenses/gpl-2.0 #!# or a copy of it https://github.com/OWASP/O-Saft/blob/master/LICENSE.md #!# Permits anyone the right to use and modify the software without limitations #!# as long as proper credits are given and the original and modified source #!# code are included. Requires that the final product, software derivate from #!# the original source or any software utilizing a GPL component, such as #!# this, is also licensed under the same GPL license. #!############################################################################# #? NAME #? $0 - simple GUI for o-saft.pl #? #? SYNOPSIS #? $0 [host:port] [host:port] ... #? #? DESCRIPTION #? This is a simple GUI for O-Saft - OWASP SSL advanced forensic tool. #? The GUI supports all commands (Commands TAB) and options (Options TAB) #? available in o-saft.pl. For each command o-saft.pl will be executed #? as specified. Results are printed in a new TAB of the GUI. A filter to #? markup some important texts is applied to the results in the GUI. This #? filter can be modified and extended in the Filter TAB. #? All results and settings (commands and options) can be saved to files. #? #? Result TAB #? The result of o-saft.pl are shown in a new TAB. The format (layout) #? of the result can be simple "text" or "table". This can be configured #? in the Options TAB. #? #? The difference between the formats are: #? "table" #? The table consist of 4 columns: Nr, Label, Value and Comment. It can #? be sorted according each. All Filters are applied to matching lines. #? The Filter will hide the lines completely. #? Saving the results will only save the visible lines. These lines are #? saved in the order of the last sorting. #? Some informational lines and all header lines (see --header option) #? from o-saft.pl are not shown and will not be saved. #? "text" #? In this format, the results are shown in the same format as returned #? by o-saft.pl. Lines cannot be sorted. The Filter is applied to each #? matching line. The Filter will just remove the text, but not hide #? the lines. #? Saving the result will save the complete text. #? #? Help #? All functionallity is documented with balloon help on each checkbutton, #? input field, button or table header line. #? #? Examples for filter #? Match complete line containing Certificate: #? r=1 e=0 #=0 Regex=Certificate #? Match word Target: #? r=0 e=1 #=6 Regex=Target #? Match label text and emphase: #? r=1 e=0 #=1 Regex=^[A-Za-z][^:]*\s* Font=osaftHead #? #? Configuration #? Some parts of the GUI, for example widget fonts or widget label texts, #? can be customized in .o-saft.tcl , which will be searched for in the #? user's HOME directory and in the local directory. #? Please see .o-saft.tcl itself for details. A sample .o-saft.tcl is #? available in the contrib/ directory. #? #? Buttons #? By default, an image will be used for most buttons. Images look more #? modern than the standard Tcl/Tk buttons. Tcl/Tk does not support round #? edges, images as background, or different look for activated buttons. #? The images are read from a separate file: o-saft-img.tcl . If the file #? is missing, no images will be used, but the simple texts. #? For each button an image can be specified in o-saft-img.tcl , example: #? set IMG(my-file) [image create photo -file path/to/your-file ] #? set cfg_images(+info) {my-file}; # where +info is your command #? #? Copy Texts #? All texts visible in the GUI, wether a label, a button, an entry or a #? text itself, can be copied to the systems clipboard, using the systems #? standard copy&paste methods, or with: #? #? For debugging will prefix the text by #? the pathname and the class of the object containing the text. #? Keep in mind that it also copies the huge text in the help window. #? With or the #? text will be copied to the (ICCCM) buffer CLIPBOARD. This ensures that #? it will not interfere with the usual copy&paste buffer PRIMARY. #? is the "select button", usually the left mouse button. #? On X.org systems, the CLIPBOARD can be pasted using the context menu #? (which is most likely the ). #? #? Help / Search #? The help [?] button opens a new window with the complete documentation #? of O-Saft (in particular the result of: o-saft.pl +help ). #? The documentation contains clickable links (in blue) to other sections #? in the text. Patterns may be specified to be searched for in the text. #? All texts matching the pattern are highligted. #? Search can be done forward and backward to the current positions, see #? the [<] and [>] buttons at bottom of the window. Going to the next #? or previous search result will then highlight the complete paragraph #? containing the matched text. #? #? When more than 5 matches are found, an additional window will display #? all matches as an overview. Click on a highligted match will show the #? paragraph containing the match in the help window. #? When multiple "overview" windows are open, each handles its matches. #? #? The search pattern can be used in following modes: #? exact - use pattern as literal text #? regex - use pattern as regular expression (proper syntax required) #? smart - convert pattern to regex: each character may be optional #? fuzzy - convert pattern to regex: each position may be optional #? Example: #? exact: (adh|dha) - search for literal text (adh|dha) #? regex: (adh|dha) - search for word adh or word dha #? regex: her.*list - search for text her followed by list #? regex: (and - fails, because of syntax error #? smart: and - search for and or a?nd or an?d or and? #? fuzzy: and - search for and or .?nd or a.?d or an.? #? #? Note: regex are applied to lines only, pattern cannot span more than a #? single line. #? #? The GUI contains various [?] buttons. Clicking such a button will show #? the corresponding section in the help window context sensitive). #? #? OPTIONS #? --v print verbose messages (for debugging) #? --d print more verbose messages (for debugging) #? --rc print template for .o-saft.pl #? --text use simple texts as labels for buttons #? --img use images as defined in o-saft-img.tcl for buttons #? (not recommended on Mac OS X, because Aqua has nice buttons) #. --tip use own tooltip #. --trace use Tcl's trace to trace proc calls #? --load=FILE read FILE and show in result TAB #? --id=ID use Docker image ID (registry:tag); default: owasp/o-saft #? --tag=TAG use Docker image ID with tag; default: (empty) #? --docker use o-saft-docker instead of o-saft.pl #? --version print version number #. +VERSION print version number (for compatibility with o-saft.pl) #. +quit exit without GUI (for compatibility with o-saft.pl) #? #? DOCKER #? This script can be used from within any Docker image. The host is then #? responsible for providing the proper protocols for the GUI (i.e. X11). #? In this case, anything is executed inside the Docker image, just the #? graphical output is passed to the host. This mode is started with #? o-saft-docker gui #? which does the necessary magic with Docker for protocol and DISPLAY. #? #? When used with the --docker option, this script runs on the host and #? connects to an O-Saft Docker image to execute o-saft.pl there with all #? the selected commands and options. #? In this mode, o-saft-docker will be used instead of o-saft.pl, which #? must be available on the host. #? Note that o-saft-docker relies on O-Saft's Docker image osawp/o-saft #? which has its own (Docker) entrypoint. This means that o-saft-docker #? is responsible to provide the same functionality as o-saft.pl does. #? Adaptions, if necessary, should be done in o-saft-docker. #? #? Summary #? o-saft.tcl --docker - run on host using o-saft.pl in Docker #? o-saft-docker gui - run in Docker with display to host #? #? KNOWN PROBLEMS #? Using option -v causes a Tcl error, like: #? application-specific initialization failed: "-v" option requires an\ #? additional argument #? This is a Tcl problem and cannot fixed herein. #? #? The markup defined in the filters (see Filter TAB) may not yet produce #? perfect layouts for the results and the help texts, to be improved in #? many ways. #? Note that the markup is independent of the results and does not change #? them, just "highlight" texts of the results. #? #? All --cfg-* settings from .o-saft.pl are not handled properly in the #? GUI herein. #? #? The busy cursor does not work on Win32 and Win64 systems. #? #? Selected coloured text will not be highlighted. Anyway it is selected. #? #? Some Tk widgets seem to have limits. This may result in errors like: #? X Error of failed request: BadAlloc (insufficient resources for operation) #? There exist configurations as workaround to avoid such errors, see: #? cfg(max53) #? #? ARGUMENTS #? All arguments, except the options described above, are treated as a #? hostname to be checked. #? #? SEE ALSO #? o-saft.pl #? o-saft-docker #? #. LAYOUT #. +---------------------------------------------------------------+ #. (H) | Host:Port [________________________________________] [+] [-] | #. | [!] | #. (C) | [Start] [+info] [+check] [+cipher] [+quick] [+vulns] [?] | #. (O) | [ ] --header [ ] --enabled [ ] --no-dns [ ] -no-http ... | #. |---------------------------------------------------------------| #. | +----------++---------++----------++----------+ | #. (T) | | Commands || Options || Filter || (n) +cmd || (m) +cmd | | #. | + +------------------------------------------------+ | #. | | | | #. | | | | #. | +-----------------------------------------------------------+ | #. |---------------------------------------------------------------| #. (S) | | | | #. +---------------------------------------------------------------+ #. #. Description #. (H) - Frame containing hostnames to be checked #. (C) - Buttons for most commonly used commands #. (O) - CheckButtons for most commonly used options #. (T) - Frame containing panes for commands, options, filter, results. #. (S) - Frame containing Status messages #. [+] - Add line with Host:Port #. [-] - Remove line with Host:Port #. [!] - Help about $0 #. [?] - Help about o-saft.pl #. #. Filter TAB Description #. +---------------------------------------------------------------+ #. (f) | Key r e # Regex Foreground Background Font u | #. | +---------+--+--+--+------+----------+----------+--------+--- | #. (F) | |== CMT * o 0 ^==* gray osaftHead x | #. | +---------+--+--+--+------+----------+----------+--------+--- | #. | ... | #. +---------------------------------------------------------------+ #. #. (f) - Headline for filter description #. key - unique key for this filter #. r - Regex used as regular expression #. e - Regex used as exact match #. # - Nr. of characters to be matched by Regex #. Foreground - colour for matched text #. Background - colour for background of matched text #. Font - use this font for matched text #. u - matched text will be underlined #. (F) - Filter settings #. example of a filter #. #. LIMITATIONS #. #. HACKER's INFO #. TODO (7/2017): #. - "docker status" button is a quick&dirty hack #. TODO (8/2016): #. - need to check if ugly hacks for Aqua (Mac OS X 10.6 with Tk 8.5.7) #. are still necessary on modern Macs, in particular: #. * tk_getSaveFile -confirmoverwrite #. * package require Img #. #. Hash-bang line #. The usual way on *IX systems to start a Tcl- script independent of the #. platform and underlaying shell would be like: #. #!/usr/bin/wish #. exec wish "$0" ${1+"$@"} #. but above exec throws errors on Mac OS X, hence a quick&dirt version #. exec wish "$0" -- #. need to be used. Unfortunatelly this does not allow to pass arguments #. on command line. Hence the initial hash-bang line uses /bin/sh . #. #. Data used to build GUI #. Generation of all objects (widgets in Tk slang) is done based on data #. provided by o-saft.pl itself, in praticular some --help=* options, #. see CONFIGURATION o-saft.pl below. Output of all --help=* must be #. one item per line, like: #. This is a label, grouping next lines #. +command1 Command nr 1 #. +command2 Command nr 2 #. Options for commands #. --opt1 this options does something #. This tools relies on the format of these lines. If the format changes, #. commands and options may be missing in the generated GUI. #. Following options of o-saft.pl are used: #. --help --help=opt --help=commands #. A detailed example of the format can be found in proc create_win(). #. The functions create_win() and create_buttons() mainly use the RegEx #. prg(rec*) defined in the CONFIGURATION (see below) to match output #. from o-saft.pl . The code in these functions may be used to parse data #. from other tools too. #. #. When building the complete documention (help window), additional text #. documentation (beside that provided by +help) will be added before the #. ATTRIBUTION section. Hence ATTRIBUTION must exist as section header #. in output of "o-saft.pl --help". #. #. The tool will only work if o-saft.pl is available and executes without #. errors. All commands and options of o-saft.pl will be available from #. herein, except: #. - all "--help*" options (as they make no sense here) #. - "+cgi" and "+exec" command (they are for internal use only) #. #. Some nameing conventions #. - procedures: #. create_* - create widget or window #. osaft_* - run external o-saft.pl (and process output) #. search_* - searching texts in help #. - variables: #. HELP- - prefix used for all Tcl-text tags in help #. f_* - prefix used for all filter list variables #. txt - a text widget #. w or obj - any widget #. parent - parent widget (may be toplevel) #. hosts() - global variable with list of hosts to be checked #. cfg() - global variable containing most configurations #. cfg_colors()- global variable containing colours for widgets #. cfg_texts() - global variable containing texts for widgets #. cfg_tips() - global variable containing texts for tooltips #. search() - global variable containing texts used for searching #. myX() - global variable for windows and window manager #. tab() - global variable containing results of executions #. #. Codeing (general) #. Sequence of function definitions done to avoid forward declarations. #. See Debugging Options below also. #. #. Codeing (GUI) #. Images (i.e.for buttons) are defined in o-saft-img.tcl, which must be #. installed in same path as o-saft.tcl itself. The definitions are in #. a separate file to keep the code more clean herein. #. #. All buttons for the GUI are defined in a tabular array, where the key #. is used as part of the object name. For details please see comments at #. # define all buttons used in GUI #. Note that the button texts defined there are displayed when using our #. own "Copy Text" (see above) with , even if the #. button is displayed as image. #. #. Traceing (GUI) #. Tcl's trace functionality is used to trace most procs defined herein #. and all created buttons. See trace_commands() and trace_buttons() for #. details. Tracing does not yet work for buttons created in sub-windows. #. Traceing is invoked with --trace option. #. #. Traceing and Debugging #. All output for ..trace and/or --dbx is printed on STDERR. #. #. Debugging Options #. --help-flow - print information about program flow (comments in code) #. --help-procs - print all proc definitions #. --help-descr - print all proc definitions and their description #. --help-osaft - just print text used for help window (help button) #. #. Notes about Tcl/Tk #. We try to avoid platform-specific code. The only exceptions (2015) are #. the perl executable and the start method of the external browser. #. Another exception (8/2016) is "package require Img" which is necessary #. on some Mac OS X. #. All external programs are started using Tcl's {*} syntax. #. If there is any text visible, we want to copy&paste it. Therefore most #. texts are placed in Tk's text widget instead of a label widget, 'cause #. text widgets allow selecting their content by default, while labels do #. not. These text widgets are set to state "read-only" instaed of Tcl's #. disabled state, see set_readonly() for details. #. #. This is no academically perfect code, but quick&dirty scripted: #. - makes use of global variables instead of passing parameters etc.. #. - mixes layout and functions and business logic #. - some widget names are hardcoded #. #? VERSION #? @(#) 1.191 Sommer Edition 2018 #? #? AUTHOR #? 04. April 2015 Achim Hoffmann (at) sicsec de #? #? Project Home: https://www.owasp.org/index.php/O-Saft #? Help Online: https://www.owasp.org/index.php/O-Saft/Documentation #? Repository: https://github.com/OWASP/O-Saft #? # ----------------------------------------------------------------------------- package require Tcl 8.5 package require Tk 8.5 #_____________________________________________________________________________ #___________________________________________________________ early bindings __| # Bindings for simply copying text of any widget. # To avoid conflicts with other common bindings, we use Ctrl + click to copy # the text. Unfortunately this does not allow to select texts individually, # but only as a whole. # Bindings need to be done very early, so that they are active when Tcl/Tk's # wish uses dialogs (i.e. tk_messagebox). The called function copy2clipboard # might be defined later in the code, but it must be done before any usage. # Hence it's defined right below. foreach klasse [list Button Combobox Entry Label Text Message Spinbox \ TButton TCombobox TEntry TLabel TText Frame Menu \ LabelFrame PanedWindow Scale Scrollbar \ Checkbutton Menubutton Radiobutton Dialog] { bind $klasse { copy2clipboard %W 0 } bind $klasse { copy2clipboard %W 1 } } proc copy2clipboard {w shift} { #? copy visible text of object to clipboard global cfg set klasse [winfo class $w] set txt {} if {$shift==1} { set txt "$w $klasse: " } # TODO: Spinbox not complete; some classes are missing switch $klasse { Frame { append dum "nothing to see in frames" } Button - Combobox - Dialog - Label - Spinbox - TButton - TCombobox - TLabel - Checkbutton - Radiobutton { append txt [lindex [$w config -text] 4] } Entry - TEntry { append txt [string trim [$w get]]; } Text - TText { append txt [string trim [$w get 1.0 end]]; } default { puts "** unknown class $klasse" } } putv "copy2clipboard($w, $shift): {\n $txt\n#}" clipboard clear clipboard append -type STRING -format STRING -- $txt }; # copy2clipboard #_____________________________________________________________________________ #____________________________________________________________ configuration __| if {![info exists argv0]} { set argv0 "o-saft.tcl" }; # if it is a tclet set cfg(SID) "@(#) o-saft.tcl 1.191 19/01/19 11:46:44" set cfg(mySID) "$cfg(SID) Sommer Edition 2018" # contribution to SCCS's "what" to avoid additional characters set cfg(VERSION) {1.191} set cfg(TITLE) {O-Saft} set cfg(RC) {.o-saft.tcl} set cfg(RCmin) 1.13 ;# expected minimal version of cfg(RC) set cfg(ICH) [file tail $argv0] set cfg(DIR) [file dirname $argv0] ;# directory of cfg(ICH) set cfg(ME) [info script] ;# set very early, may be missing later set cfg(IMG) {o-saft-img.tcl} ;# where to find image data # O-Saft means built-in set cfg(HELP) "" ;# O-Saft's complete help text set cfg(files) {} ;# files to be loaded at startup --load set cfg(.CFG) {} ;# contains data from prg(INIT) ;# set below and processed in osaft_init set cfg(quit) 0 ;# quit without GUI #et cfg(HELP-key) "" ;# contains linenumber of result table ## configuration file # TODO: add descriptions from contrib/.o-saft.tcl # RC-ANF { #-----------------------------------------------------------------------------{ # this is the only section where we know about o-saft.pl # all settings for o-saft.pl go here set prg(DESC) {-- CONFIGURATION o-saft.pl ----------------------------------} set prg(INIT) {.o-saft.pl} ;# name of O-Saft's startup file set prg(SAFT) {o-saft.pl} ;# name of O-Saft executable ;# set to o-saft-docker with --docker # some regex to match output from o-saft.pl or data in .o-saft.pl # mainly used in create_win() and create_buttons() set prg(DESC) {-- CONFIGURATION regex to match output from o-saft.pl -------} set prg(rexCMD-int) {^\+(cgi|exec)} ;# internal use only set prg(rexOPT-cfg) {^([^=]*)=(.*)} ;# match --cfg-CONF=KEY=VAL set prg(rexOPT-help) {^--(h$|help)} ;# match --h ot --help set prg(rexOUT-head) {^(==|\*\*)} ;# match header lines starting with == set prg(rexOUT-int) {^--(cgi|call)} ;# use other tools for that set prg(rexOUT-cmd) {^(Commands|Options)} ;# match header lines for --help=cmd set prg(rexOUT-hide) {^Options\s*for\s*(help|compatibility) } ;# match groups not shown here set prg(rexOUT-show) {^Commands to show } ;# commands without explizit HELP section #set _me [regsub -all {^[./]*} $prg(SAFT) {}] ;# remove ./ but prg(SAFT) later # causes problems in regsub on Mac OS X if $prg(SAFT) starts with ./ set prg(rexCOMMANDS) "\(o-saft\(.pl|.tcl|-docker\)?|checkAllCiphers.pl|\(/usr/local/\)?openssl|docker|mkdir|ldd|ln|perlapp|perl2exe|pp\)" # most common tools used in help text... #-----------------------------------------------------------------------------} set prg(DESC) {-- CONFIGURATION external programs --------------------------} set prg(PERL) {} ;# full path to perl; empty on *nix set prg(BROWSER) "" ;# external browser program, set below set prg(TKPOD) {O-Saft} ;# name of external viewer executable set prg(docker-id) {owasp/o-saft} ;# Docker image ID, if needed set prg(docker-tag) {latest} ;# Docker image tag, if needed set prg(DESC) {-- CONFIGURATION default buttons and checkboxes -------------} set prg(Ocmd) {{+check} {+cipher} {+info} {+quick} {+protocols} {+vulns}}; # buttons for quick access commands set prg(Oopt) {{--header} {--enabled} {--no-dns} {--no-http} {--no-sni} {--no-sslv2} {--no-tlsv13}}; # checkboxes for quick access options set prg(post) {} ;# --post= parameter, if passed on command line set cfg(DESC) {-- CONFIGURATION GUI style and layout -----------------------} set cfg(bstyle) {image} ;# button style: image or text set cfg(layout) {table} ;# layout o-saft.pl's results: text or table # see also comment in gui_init() set cfg(tfont) {flat9x6} ;# font used in tablelist::tablelist set cfg(max53) 4090 ;# max. size of text to be stored in table columns # Some combinations of Tcl/Tk and X-Servers are limited in the size of text, # which can be stored in Tk's table columns. When such a widget is rendered, # the script crashes with following error message: # X Error of failed request: BadAlloc (insufficient resources for operation) # Major opcode of failed request: 53 (X_CreatePixmap) # Serial number of failed request: 2223 # Current serial number in output stream: 2255 # To avoid the crash, large texts (greater than this value) can be stripped. # The default value of ~4000 is based on experience. set myX(DESC) {-- CONFIGURATION window manager geometry --------------------} # set minimal window sizes to be usable in a 1024x768 screen # windows will be larger if the screen supports it (we rely on "wm maxsize") set myX(geoo) "660x720" ;# geometry of Help window set myX(geoO) "$myX(geoo)-0+0" ;# geometry and position of Help window set myX(geo-) "" ;# set myX(geoS) "700x720" ;# geometry and position of O-Saft window set myX(geoA) "660x610" ;# geometry and position of About window set myX(geoF) "" ;# geometry and position of Filter window (computed dynamically) set myX(geoT) "" ;# set myX(minx) 700 ;# O-Saft window min. width set myX(miny) 780 ;# O-Saft window min. height set myX(lenl) 15 ;# fixed width of labels in Options window set myX(rpad) 15 ;# right padding in the lower right corner set myX(padx) 5 ;# padding to right border # RC-END } if {[info exists env(o_saft_docker_tag)] ==1} { set prg(docker-tag) $env(o_saft_docker_tag); } if {[info exists env(o_saft_docker_name)]==1} { set prg(docker-id) $env(o_saft_docker_name); } catch { set fid [open $prg(INIT) r] set cfg(.CFG) [read $fid]; close $fid; # read .o-saft.pl } ## configure GUI set cfg(TIP) [catch { package require tooltip} tip_msg]; # 0 on success, 1 otherwise! set IMG(!) [image create photo -data { R0lGODlhGAAYAOMOAAAAAAARAQASAQASAgATAQATAgBwLgCBNgCBNwCCNQCCNgCCNwCDNiZ/AP// /////yH5BAEKAA8ALAAAAAAYABgAAASE8MlJq6o4W3W1fwvHfZ6oLKRmfkKLmcnTDlRrv6IEBC0g 2YXMStf7CWiPnETUqAl8suNylFROilHkanh9GpEME9cInU3EVvJ3gkB3umXppCHGYM2UeuUuP4/V WRUJHAcZfEgpgHh5b3teUYsmTV1YBDYCfhwGTlgTA4iSFANQJAccKB8RADs= }]; # [!] 24x24 set IMG(help) ::tk::icons::question if { [regexp {::tk::icons::question} [image names]] == 0} { unset IMG(help); } # reset if no icons there, forces text (see cfg_buttons below) #et IMG(...) ;# other images are defined in cfg(IMG) #et myX(minx) myX(miny) myX(geoS) # see gui_init() below # myX(buffer) ... NOT YET USED set myX(buffer) PRIMARY ;# buffer to be used for copy&paste GUI texts # any ICCCM like: PRIMARY, SECONDARY, CLIPBOARD # or: CUT_BUFFER0 .. CUT_BUFFER7 # Hint for X, in particular xterm: .Xresources: # XTerm*VT100.Translations: #override \ # ... \ # : insert-selection(PRIMARY,CLIPBOARD) \ # ... \ set my_bg "[lindex [. config -bg] 4]" ;# default background color # this colour is used for buttons too # define all buttons used in GUI # Following table defines the label text, background colour, image and tip # text for each button. Each key is an object name and defines one button. # # This allows to generate the buttons without these attributes (-text, -bg, # -image, etc.), which simplifies the code. These attributes are set later # using theme_set(), which then also takes care if there should be a simple # theme (just text and background) or a more sexy one using images. # Note: the key (object name) in following table must be the last part of # the object (widget) name of the button, example: .f.about . #----------+---------------+-------+-------+------------------------------- # object button text colour image help text (aka tooltip) # name -text -bg -image create_tip() #----------+-----------+-------+-----------+------------------------------- array set cfg_buttons " {about} {{!} $my_bg {!} {About $cfg(ICH)}} {help} {{?} $my_bg help {Open window with complete help}} {help_me} {{?} $my_bg {?} {Open window with help for these settings}} {closeme} {{Quit} orange quit {Close program}} {closewin} {{Close} orange close {Close window}} {closetab} {{Close Tab} orange closetab {Close this TAB}} {loadresult} {{Load} lightgreen load {Load results from file}} {saveresult} {{Save} lightgreen save {Save results to file}} {saveconfig} {{Save} lightgreen save {Save configuration to file }} {ttyresult} {{STDOUT} lightgreen stdout {Print results on systems STDOUT}} {reset} {{Reset} $my_bg reset {Reset configuration to defaults}} {filter} {{Filter} $my_bg filter {Show configuration for filtering results}} {tkcolor} {{Color Chooser} $my_bg tkcolor {Open window to choose a color}} {tkfont} {{Font Chooser} $my_bg tkfont {Open window to choose a font}} {host_add} {{+} $my_bg {+} {Add new line for a host}} {host_del} {{-} $my_bg {-} {Remove this line for a host }} {help_home} {{^} $my_bg help_home {Go to top of page (start next search from there)}} {help_prev} {{<} $my_bg help_prev {Search baskward for text}} {help_next} {{>} $my_bg help_next {Search forward for text}} {help_help} {{?} $my_bg {?} {Show help about search functionality}} {helpsearch} {{??} $my_bg helpsearch {Text to be searched}} {cmdstart} {{Start} yellow cmdstart {Execute $prg(SAFT) with commands selected in 'Commands' tab}} {cmdcheck} {{+check} #ffd800 +check {Execute $prg(SAFT) +check }} {cmdcipher} {{+cipher} #ffd000 +cipher {Execute $prg(SAFT) +cipher }} {cmdinfo} {{+info} #ffc800 +info {Execute $prg(SAFT) +info }} {cmdquit} {{+quit} #ffc800 +quit {Execute $prg(SAFT) +quit (debugging only)}} {cmdquick} {{+quick} #ffc000 +quick {Execute $prg(SAFT) +quick }} {cmdprotocols} {{+protocols} #ffb800 +protocols {Execute $prg(SAFT) +protocols }} {cmdvulns} {{+vulns} #ffb000 +vulns {Execute $prg(SAFT) +vulns }} {cmdversion} {{+version} #fffa00 +version {Execute $prg(SAFT) +version }} {docker_status} {{docker status} #00faff status {Execute $prg(SAFT) status }} {img_txt} {{image/text} $my_bg {img_txt} {toggle buttons: text or image}} "; #----------+-----------+-------+-----------+------------------------------- # Note: all buttons as described above, can be configured also by the user # using cfg(RC). Configurable are: text (-text), background colour (-bg) # and the tooltip. Because configuering the above table is a bit cumbersome # for most users, we provide simple lists with key=value pairs. These lists # are: cfg_colors, cfg_texts and cfg_tips. The settings here are defaults, # and may be redifined in cfg(RC) using cfg_color, cfg_label and cfg_tipp. # These lists (arrays in Tcl terms) contain not just the button values, but # also values for other objects. So the lists are initialized here for all # other values, and then the values from cfg_buttons are added. # # array in cfg(RC) array herein (see also cfg_update() ) # cfg_color cfg_colors # cfg_label cfg_texts # cfg_tipp cfg_tips proc buttons_txt {key} { global cfg_buttons; return [lindex $cfg_buttons($key) 0]; } proc buttons_bg {key} { global cfg_buttons; return [lindex $cfg_buttons($key) 1]; } proc buttons_img {key} { global cfg_buttons; return [lindex $cfg_buttons($key) 2]; } proc buttons_tip {key} { global cfg_buttons; return [lindex $cfg_buttons($key) 3]; } array set cfg_colors " DESC {-- CONFIGURATION colours used in GUI ------------------------} osaft gold button lightyellow code lightgray link blue status wheat " array set cfg_texts " DESC {-- CONFIGURATION texts used in GUI for buttons or labels ----} host {Host\[:Port\]} hideline {Hide complete line} c_toggle {toggle visibility\nof various texts} " array set cfg_tips " DESC {-- CONFIGURATION texts used for tool tips on buttons --------} settings {Open window with more settings} layout {Format used in result TAB} DESC_other {-- CONFIGURATION texts used for tool tips on other objects --} choosen {Choosen value for} hideline {Hide complete line instead of pattern only} show_hide {show/hide: } tabCMD { Select commands. All selected commands will be executed with the 'Start' button. } tabOPT { Select and configure options. All options are used for any command button. } helpclick {Click to show in Help window} help_mode {Mode how pattern is used for searching} tabFILTER { Configure filter for text markup: r, e and # specify how the Regex should work; Forground, Background, Font and u specify the markup to apply to matched text. Changes apply to next +command. } DESC_misc {-- CONFIGURATION texts used in GUI for various other texts --} f_key Key f_moder r f_modee e f_chars {#} f_regex Regex f_fg Foreground f_bg Background f_font Font f_u u DESC_opts {-- CONFIGURATION texts used in GUI for option checkbuttons --} --header {print header line} --enabled {print only enabled ciphers} --no-dns {do not make DNS lookups} --no-http {do not make HTTP requests} --no-sni {do not make connections in SNI mode} --no-sslv2 {do not check for SSLv2 ciphers} --no-tlsv13 {do not check for TLSv13 ciphers} docker-id {Docker image ID (registry:tag) to be connected} "; # cfg_tips; # Note: text for tab* contain new lines. # now add default to cfg_* as described before foreach key [array names cfg_buttons] { set cfg_colors($key) [buttons_bg $key] set cfg_texts($key) [buttons_txt $key] set cfg_tips($key) [buttons_tip $key] set cfg_images($key) [buttons_img $key] } proc cfg_update {} { #? legacy conversion of old (pre 1.86) keys from cfg(RC) aka .o-saft.tcl # # Until version 1.84, respectively 1.6 of cfg(RC), the variables in cfg(RC) # were identical to the ones used herein: # cfg_color, cfg_label, cfg_tipp # As cfg(RC) will only be sourced, it needs to have the complete definition # of each of these variables, otherwise we may run into some syntax errors. # Starting with version 1.86, the variables herein have been renamed to: # cfg_colors, cfg_texts, cfg_tips # and also some keys have been renamed. # This function copies the settings from cfg(RC) to the internal variables. # By doing this, the old keys are converted automatically (see switch cases # below). # Finally we remove the variables set by cfg(RC). # _dbx "()" global cfg if {[info exists cfg(RCSID)]==1} { # cfg(RCSID) is defined in .o-saft.tcl, warn if old one _dbx " RCmin$cfg(RCmin) > RCSID$cfg(RCSID) ?" if {$cfg(RCmin) > $cfg(RCSID)} { tk_messageBox -icon warning -title "$cfg(RC) version $cfg(RCSID)" \ -message "converting data to new version ...\n\nplease update $cfg(RC) using 'contrib/$cfg(RC)'" } } global cfg_colors cfg_color foreach key [array names cfg_color] { set value $cfg_color($key) # keys used in version < 1.86 switch -exact $key { {start} { set cfg_colors(cmdstart) $value } {closew} { set cfg_colors(closewin) $value } {search} { set cfg_colors(helpsearch) $value } {choosecolor} { set cfg_colors(tkcolor) $value } {choosefont} { set cfg_colors(tkfont) $value } {plus} { set cfg_colors(host_add) $value } {minus} { set cfg_colors(host_del) $value } default { set cfg_colors($key) $value } } } array unset cfg_color global cfg_texts cfg_label foreach key [array names cfg_label] { set value $cfg_label($key) switch -exact $key { {start} { set cfg_texts(cmdstart) $value } {close} { set cfg_texts(closewin) $value } {search} { set cfg_texts(helpsearch) $value } {color} { set cfg_texts(tkcolor) $value } {font} { set cfg_texts(tkfont) $value } {plus} { set cfg_texts(host_add) $value } {minus} { set cfg_texts(host_del) $value } default { set cfg_texts($key) $value } } } array unset cfg_label global cfg_tips cfg_tipp foreach key [array names cfg_tipp] { set value $cfg_tipp($key) switch -exact $key { {start} { set cfg_tips(cmdstart) $value } {closew} { set cfg_tips(closewin) $value } {showfilterconfig} { set cfg_tips(filter) $value } {resetfilterconfig} { set cfg_tips(reset) $value } {goback} { set cfg_tips(help_prev) $value } {goforward} { set cfg_tips(help_next) $value } {search} { set cfg_tips(helpsearch) $value } {choosecolor} { set cfg_tips(tkcolor) $value } {choosefont} { set cfg_tips(tkfont) $value } {plus} { set cfg_tips(host_add) $value } {minus} { set cfg_tips(host_del) $value } default { set cfg_tips($key) $value } } } array unset cfg_tipp global myX cfg_geo foreach key [array names cfg_geo] { set value $cfg_geo($key) switch -exact $key { {minus} { set cfg_texts(host_del) $value } default { set myX($key) $value } } } array unset cfg_geo global cfg cfg_cmd foreach key [array names cfg_cmd] { set value $cfg_cmd($key) switch -exact $key { {minus} { set cfg_texts(host_del) $value } default { set cfg($key) $value } } } array unset cfg_geo return }; # cfg_update if {[regexp {indows} $tcl_platform(os)]} { # Some platforms are too stupid to run our executable prg(SAFT) directly, # they need a proper perl executable to do it. Check for perl.exe in all # directories of the PATH environment variable. If no executable will be # found, ask the user to choose a proper one. # There are no more checks for the selected file. If it is # wrong, the # script will bail out with an error later. foreach p [split $env(PATH) ";"] { set p [file join $p "perl.exe"] if {[file isdirectory $p]} { continue } if {[file executable $p]} { set prg(PERL) $p break } } if {![file executable $prg(PERL)]} { set prg(PERL) [tk_getOpenFile -title "Please choose perl.exe" ] } } # NOTE: as Tcl is picky about empty variables, we have to ensure later, that # $prg(PERL) is evaluated propperly, in particular when it is empty. We use # Tcl's {*} evaluation for that. ## check if prg(SAFT) exists in PATH, +VERSION just prints the version number #_dbx " $prg(PERL) $prg(SAFT) +VERSION"; # _dbx() not yet defined catch { exec {*}$prg(PERL) $prg(SAFT) +VERSION } usage; if {![regexp {^\d\d\.\d\d\.\d\d} $usage]} { # check other PATH set osaft "$cfg(DIR)/$prg(SAFT)"; # check in PATH of $argv0 catch { exec {*}$prg(PERL) $osaft +VERSION } usage; if {![regexp {^\d\d\.\d\d\.\d\d} $usage]} { tk_messageBox -icon warning -title "$prg(SAFT) not found" -message " most parts of the GUI are missing! !!Hint: check PATH environment variable." } else { set prg(SAFT) $osaft; # found } } set cfg(DESC) {-- CONFIGURATION internal data storage ----------------------} set cfg(CDIR) [file join [pwd] [file dirname [info script]]] set cfg(EXEC) 0; # count executions, used for object names set cfg(x--x) 0; # each option will have its own entry (this is a dummy) set cfg(x++x) 0; # each command will have its own entry (this is a dummy) set cfg(objN) ""; # object name of notebook; needed to add more note TABS set cfg(winA) ""; # object name of About window set cfg(winH) ""; # object name of Help window set cfg(winF) ""; # object name of Filter window set cfg(objS) ""; # object name of status line set cfg(VERB) 0; # set to 1 to print more informational messages from Tcl/Tk set cfg(DEBUG) 0; # set to 1 to print debugging messages set cfg(TRACE) 0; # set to 1 to print program tracing set cfg(AQUA) {-- CONFIGURATION Aqua (Mac OS X) ----------------------------} # Tcl/Tk on Aqua has some limitations and quirky behaviours set cfg(confirm) {-confirmoverwrite true}; # must be reset on Aqua # myX(rpad) # used as right padding for widgets in the lower right # corner where there is Aqua's resize icon set search(DESC) {-- CONFIGURATION seaching text in O-Saft's help ---------} set search(text) ""; # current search text set search(list) ""; # list of search texts (managed by spinbox) set search(curr) 0; # current index in search(list) set search(last) ""; # last search text (used to avoid duplicates) set search(see) ""; # current position to see, tuple like: 23.32 23.37 set search(more) 5; # show addition overview window when more than this search results set search(mode) "regex";# search pattern is exact text, or regex, or fuzzy # variable names and function names used/capable for searching text in HELP # can be found with following patterns: search.text search.list etc. # tags used in help text cfg(HELP) aka (window) cfg(winH) # HELP-search-pos tag contaning matching text positions (tuple: start end) # HELP-search-mark tag assigned to currently marked search text # HELP-search-box tag assigned to currently paragraph with search text # HELP-LNK tag assigned to all link texts in text # HELP-TOC-* individual tag for a linked line # HELP-LNK-T tag assigned to top of text # HELP-HEAD tag assigned to all header texts (lines) # HELP-HEAD-* individual tag for a header text # HELP-TOC tag assigned to all lines in table of content # HELP-TOC-* individual tag for a TOC line # HELP-REF tag assigned to all TOC reference # HELP-XXX-* # HELP-CODE tag assigned to all code texts set hosts(0) 0; # array containing host:port; index 0 contains counter set tab(0) ""; # contains results of prg(SAFT) #_____________________________________________________________________________ #_______________________________________________________ filter definitions __| # array name {description of element used in header line in Filter tab} set f_key(0) {Unique key for regex} set f_mod(0) {Modifier how to use regex} set f_len(0) {Length to be matched (0: all text; -1: complete line to right end)} set f_bg(0) {Background color used for matching text (empty: don't change)} set f_fg(0) {Foreground color used for matching text (empty: don't change)} set f_fn(0) {Font used for matching text (empty: don't change)} set f_un(0) {Underline matching text (0 or 1)} set f_rex(0) {Regex to match text} set f_cmt(0) {Description of regex} proc txt2arr {str} { #? convert string with filter definitions to arrays global f_key f_mod f_len f_bg f_fg f_rex f_un f_fn f_cmt; # lists containing filters set k 0 foreach line [split $str "\n"] { if {[regexp "^\s*$" $line]} { continue }; # skip empty lines if {[regexp "^#" $line]} { continue }; # skip comments set _l [split [regsub -all {\{\}} $line {}] "\t"] incr k # scan would be nice, but splits on all whitespaces :-( so we do it the hard way set f_key($k) [string trim [lindex $_l 0]] set f_mod($k) [lindex $_l 1] set f_len($k) [lindex $_l 2] set f_bg($k) [lindex $_l 3] set f_fg($k) [lindex $_l 4] set f_fn($k) [lindex $_l 5] set f_un($k) [lindex $_l 6] set f_rex($k) [lindex $_l 7] set f_cmt($k) [lindex $_l 8] } }; # txt2arr # Filters to match results are defined as tabular text. # For better readability we do not use output of "o-saft.pl +help=ourstr". # A tabular string is used, which is better to maintain than Tcl arrays. # This string is converted to multiple arrays (one array for each line in # the string), these array can be simple accessed in Tcl. # A filter consist of all elements with same index in each array. # This also allows to extend the arrays dynamically. # First (0) index in each array is description. # use map to replace variables (and short names to fit in 8 characters) txt2arr [string map " _lGreen lightgreen _yellow yellow _orange orange _sBlue SteelBlue _lBlue LightBlue _lGray LightGray __bold osaftHead _ME_ $prg(SAFT) " { # syntax in following table: # - lines starting with # as very first character are comments and ignored # a # anywhere else is part of the string in corresponding column # - columns *must* be separated by exactly one TAB # - empty strings in columns must be written as {} # - strings *must not* be enclosed in "" or {} # - variables must be defined in map above and used accordingly # - lines without regex (column f_rex contains {}) will not be applied #------+-------+-------+-------+-------+-------+-------+-------+------------------------------- # f_key f_mod f_len f_bg f_fg f_fn f_un f_rex description of regex #------+-------+-------+-------+-------+-------+-------+-------+------------------------------- no -regexp 1 {} {} {} 0 no\s*(LO|WE|we|ME|HI) word 'no' followed by LOW|WEAK|MEDIUM|HIGH # NOTE no has no colours, otherwhise it would mix with filters below # FIXME no must be first regex in liste here, but still causes problems in toggle_filter LOW -regexp 3 red {} {} 0 (LOW|low) word LOW anywhere WEAK -exact 4 red {} {} 0 WEAK word WEAK anywhere weak -exact 4 red {} {} 0 weak word weak anywhere MEDIUM -regexp 6 yellow {} {} 0 (MEDIUM|medium) word MEDIUM anywhere HIGH -regexp 4 _lGreen {} {} 0 (HIGH|high) word HIGH anywhere **WARN -exact 0 _lBlue {} {} 0 **WARN line **WARN (warning from _ME_) !!HINT -exact 0 _lBlue {} {} 0 !!Hint line !!Hint (hint from _ME_) A -regexp 1 _lGreen {} {} 0 (^A$) word A at end of line B -regexp 1 yellow {} {} 0 (^B$) word B at end of line C -regexp 1 _orange {} {} 0 (^C$) word C at end of line D -regexp 1 red {} {} 0 (^D$) word D at end of line ? -regexp 3 _lGray {} {} 0 (^-\?-$) word -?- at end of line NO -regexp 1 _orange {} {} 0 no \([^)]*\) word no ( anywhere YES -regexp 3 _lGreen {} {} 0 yes word yes at end of line == CMT -regexp -1 _lGray {} __bold 1 ^==* line starting with == (formatting lines) # DBX -regexp 0 {} blue {} 0 ^#[^[] line starting with # (verbose or debug lines) #[KEY] -regexp 2 _lGray gray {} 0 ^#\[[^:]+:\s* line starting with #[keyword:] # ___ but not: # [keyword: _ME_ -regexp -1 black white {} 0 .*?_ME_.*\n\n lines contaning program name Label: -regexp 1 {} {} __bold 0 ^(#\[[^:]+:\s*)?[A-Za-z][^:]*:\s* label of result string from start of line until : perl -regexp 0 purple {} {} 0 ^Use of .*perl lines with perl warnings usr1 -regexp 0 {} {} {} 0 {} {} #------+-------+-------+-------+-------+-------+-------+-------+------------------------------- # ** columns must be separated by exactly one TAB ** }]; # filter #_____________________________________________________________________________ #________________________________________________________________ functions __| proc pwarn {txt} { puts "**WARNING: $txt" } #? output WARNING message proc perr {txt} { puts "**ERROR: $txt" } #? output ERROR message proc putv {txt} { #? verbose output global cfg if {$cfg(VERB) <= 0} { return; } puts stderr "#\[$cfg(ICH)\]:$txt"; }; # putv proc _ident {cnt} { #? return ident string set txt "" for {set i 1} {$i <= $cnt} {incr i} { set chr " "; # . #if {[expr $i % 3] == 0} { set chr "|" } append txt $chr } return $txt }; # _ident proc _trace {args} { #? trace output global cfg if {$cfg(TRACE) <= 0} { return; } set cnt [info level] set txt "$args" # convert from: {proc_name arg1 arg2} enter # to: proc_name {arg1 arg2} { # dumm } for tcl set txt [regsub {^.([^\s]*)\s*(.*)} $txt "\\1 \{\\2"]; set txt [regsub {enter\s*$} $txt "\{"]; if {[regexp {leave$} $txt]} { set txt [regsub {^([^\s]*).*} $txt "\\1 \}"]; } # just keep function name from noisy leave message: # {proc_name arg1 arg2} 0 noisy text --> proc_name puts stderr "#\[$cfg(ICH)\][_ident $cnt]$txt"; return # more lazy mode, not implemented ... #set func [lindex $args 0] #puts stderr "#\[$cfg(ICH)\][_ident $cnt]$func" #return }; # _trace proc _dbx {txt} { #? debug output global cfg if {$cfg(DEBUG) < 1} { return } # [lindex [info level 1] 0]; # would be simple, but returns wrong # name of procedure if it was called within [] # [info frame -1]; # better catch { dict get [info frame -1] proc } me; # name of procedure or error if {[regexp {not known in dictionary} $me]} { set me "." }; # is toplevel puts stderr "#dbx \[$cfg(ICH)\]$me$txt" }; # _dbx proc _trace_add {cmd} { #? initilaize Tcl's tracing for given command or widget trace add execution $cmd enter _trace trace add execution $cmd leave _trace }; # _trace_add proc trace_commands {} { #? initilaize Tcl's tracing for our procs append _trace_cmds "[info procs create*] " append _trace_cmds "[info procs osaft*] " append _trace_cmds "[info procs search*] " append _trace_cmds "read_images remove_host www_browser show_window theme_init" foreach _cmd $_trace_cmds { if {[regexp "\(create_\(tip\)\)" $_cmd]} { continue } _trace_add $_cmd } _trace_add read_images return }; # trace_commands proc trace_buttons {} { #? initilaize Tcl's tracing for all buttons foreach obj [info commands] { if {![regexp {^\.} $obj]} { continue } switch [winfo class $obj] { {Button} { _trace_add $obj } } } }; # trace_buttons proc read_images {theme} { #? read $cfg(IMG) if exists and not already done global cfg IMG _dbx "($theme)"; # if the file does not exist, the error is silently catched and ignored if [info exists cfg(IMGSID)] { puts "IMG da $cfg(IMGSID)" } if [info exists cfg(IMGSID)] { return };# already there if {$theme eq "image"} { set rcfile [regsub "$cfg(ICH)$" $cfg(ME) "$cfg(IMG)"]; # must be same path _dbx " IMG $rcfile" if {[file isfile $rcfile]} { catch { source $rcfile } error_txt } else { pwarn "$cfg(IMG) not found; using traditional buttons" } } _dbx " IMG: [array names IMG]" return }; # read_images # if {$cfg(TIP)==1} { # use own tooltip from: http://wiki.tcl.tk/3060?redir=1954 proc tooltip {w help} { bind $w "after 1000 [list tooltip:show %W [list $help]]" bind $w "destroy %W.balloon" }; # tooltip proc tooltip:show {w arg} { if {[eval winfo containing [winfo pointerxy .]]!=$w} {return} set top $w.balloon catch {destroy $top} toplevel $top -bd 1 -bg black wm overrideredirect $top 1 if {[string equal [tk windowingsystem] aqua]} { ::tk::unsupported::MacWindowStyle style $top help none } pack [message $top.txt -aspect 10000 -bg lightyellow \ -font fixed -text $arg] set wmx [winfo rootx $w] set wmy [expr [winfo rooty $w]+[winfo height $w]] wm geometry $top [winfo reqwidth $top.txt]x[ winfo reqheight $top.txt]+$wmx+$wmy raise $top }; # tooltip:show # # # Example: # button .b -text Exit -command exit # tootip .b "Push me if you're done with this" # pack .b # # } proc gui_init {} { #? initialize GUI global cfg prg myX argv if {[catch { package require tablelist } err]} { pwarn "'package tablelist' not found, probably 'tklib' missing; using text layout" set cfg(layout) {text} # cfg(layout) used in create_tab() and create_filtertab() # it's hardcoded set to {text} here if package is missing, that's # working for create_filtertab() as the widgets there are created # only once at startup. # Changing cfg(layout) in the GUI later does only affect creating # tables in the result tab after osaft_exec(), and will not harm # widgets or functionality created by create_filtertab(). } font create osaftHead {*}[font config TkFixedFont;] -weight bold font create osaftBold {*}[font config TkDefaultFont] -weight bold font create osaftSlant {*}[font config TkFixedFont] -slant italic option add *Button.font osaftBold; # if we want buttons more exposed option add *Label.font osaftBold; # .. option add *Text.font TkFixedFont; # configure according real size set __x [lindex [wm maxsize .] 0] set __y [lindex [wm maxsize .] 1] if {$__y < $myX(miny)} { set myX(miny) $__y } if {$__x < $myX(minx)} { set myX(minx) $__x } if {$__x > 1000 } { set myX(minx) "999" } set myX(geoS) "$myX(minx)x$myX(miny)" set __native ""; # next switch is ugly workaround to detect special start methods ... # it also does some special setup for MacOSX switch [tk windowingsystem] { {win32} { set __native "start" } {win64} { set __native "start" } {aqua} - {Aqua} { set __native "open" set cfg(confirm) {}; # Aqua's tk_save* has no -confirmoverwrite if {[regexp -- {-(img|image)} $argv]} { tk_messageBox -icon warning \ -message "using images for buttons is not recomended on Aqua systems" } else { set cfg(bstyle) "text"; # text by default, because Aqua looks nice } set myX(miny) 770; # because fonts are bigger by default } } set myX(geoS) "$myX(minx)x$myX(miny)" # find proper font for tablelist::tablelist; MacOSX is strange ... # usually we should have: flat6x4, flat7x4, flat7x5, flat7x7, flat8x5, # flat9x5, flat9x6, flat9x7, flat10x6, # photo7x7, sunken8x7, sunken10x9, or sunken12x11 # if no font is found, default will be used, which results in a Tcl error foreach f "flat9x5 flat9x6 flat9x7 flat10x6 flat8x5" { if {[catch {tablelist::tablelist .ttest -arrowstyle $f} err]} { continue } set cfg(tfont) $f destroy .ttest break } _dbx " table font: $cfg(tfont)" # search browser, first matching will be used foreach bin " $__native \ firefox chrome chromium iceweasel konqueror mozilla \ netscape opera safari webkit htmlview www-browser w3m" { set binary [lindex [auto_execok $bin] 0]; # search in $PATH _dbx " browser: $bin $binary" if {[string length $binary]} { set prg(BROWSER) $binary break } } return }; # gui_init proc create_tip {w txt} { #? add tooltip message to given widget global cfg if {$cfg(TIP)==1} { # package tooltip not available, use own one tooltip $w "$txt" } else { set txt [regsub {^-} $txt " -"];# texts starting with - cause problems in tooltip::tooltip tooltip::tooltip $w "$txt" } }; # create_tip proc get_color {key} { global cfg_colors; return $cfg_colors($key) }; #? return color name for key from global cfg_colors variable proc get_text {key} { global cfg_texts; return $cfg_texts($key) }; #? return text string for key from global cfg_texts variable proc get_tipp {key} { global cfg_tips; return $cfg_tips($key) }; #? return text string for key from global cfg_tips variable proc get_image {key} { global cfg_images; return $cfg_images($key) }; #? return image for key from global cfg_images variablle proc get_padx {key} { global myX; return $myX($key) }; #? return padx value for key from global myX variable proc str2obj {str} { #? convert string to valid Tcl object name; returns new string set name [regsub -all {[+]} $str {Y}]; # commands set name [regsub -all {[-]} $name {Z}]; # options (mainly) set name [regsub -all {[^a-zA-Z0-9_]} $name {X}]; set name "o$name"; # first character must be lower case letter return $name }; # str2obj proc notTOC {str} { #? return 0 if string should be part of TOC; 1 otherwise if {[regexp {^ *(NOT YET|WYSIW)} $str]} { return 1; }; # skip some special strings if {[regexp {^ *$} $str]} { return 1; }; # skip empty if {[regexp {^(HIGH|MDIUM|LOW|WEAK|SSL|DHE|OWASP)} [string trim $str]]} { return 1; }; _dbx " no: »$str«"; return 0 }; # notTOC proc count_tuples {str} { return [expr [expr [llength $str] +1] / 2] }; #? return number of touples in given list proc theme_set {w theme} { #? set attributes for specified object # last part of the Tcl-widgets is key for array cfg_buttons global cfg cfg_buttons IMG _dbx "($w, $theme)" # text and tip are always configured set key [regsub {.*\.([^.]*)$} $w {\1}]; # get trailer of widget name set val [get_tipp $key]; if {$val ne ""} { create_tip $w $val } set val [get_text $key]; if {$val ne ""} { $w config -text $val } if {[regexp {docker status$} $val]} { $w config -width 10 }; # FIXME: quick&dirty, not really necessary set val [get_image $key]; if {![info exists IMG($val)]} { set theme "text" } _dbx " $w\t-> $key\t$theme\t-> $val" if {$theme eq "text"} { set val [get_color $key]; if {$val ne ""} { $w config -bg $val } $w config -image {} -height 1 -relief raised } if {$theme eq "image"} { if {$val ne ""} { set h 30 if {![regexp {^::tk} $IMG($val)]} { set h 20 } $w config -image $IMG($val) -relief flat $w config -height $h; # always set image height } } return }; # theme_set proc theme_init {theme} { #? configure buttons with simple text or graphics global cfg_buttons _dbx "($theme)" # Search for all Tcl widgets (aka commands), then check if tail of command # (part right of right-most .) exists as key in array cfg_buttons. If it # exits, then use values defined in cfg_buttons to set attributes of the # widget. First build a regex which matches all widget names of buttons. set rex [join [array names cfg_buttons] "|"] set rex [join [list {\.(} $rex {)$}] ""] _dbx ": regex: $rex" foreach obj [info commands] { if {![regexp {^\.} $obj]} { continue } if {![regexp $rex $obj]} { continue } if { [regexp {^\.$} $obj]} { continue } theme_set $obj $theme } return }; # theme_init proc set_disabled {w} { #? set widget to disabled state (mode) $w config -state disabled return }; # set_disabled proc set_readonly {w} { #? set widget to readonly state (mode) # The definition of "read-only" here is, that any action or event for the # widget is allowed, except changing its content anyhow (delete, insert, # etc.). Selecting, highlighting is not considered as a change. # This can accomplished simply with: # $w config -state disabled # Unfortunately, this does not work as expected on Mac OS X's Aqua. There # it also disables highlighting and selecting, for example copying to the # clipboard (cutbuffer). # Hence following workaround is used, which simply disables all functions # for events and sets them to do nothing. # This works on all platforms (*IX, Windows, Mac OS X Aqua). foreach event { <>} { bind $w $event break } return }; # set_readonly proc update_cursor {cursor} { #? set cursor for toplevel and tab widgets and all other windows global cfg foreach w [list . objN objS winA winF winH] { if {$w ne "."} { set w $cfg($w) } if {$w eq ""} { continue } # now get all children too foreach c "$w [info commands $w.*]" { if {$c eq ""} { continue } if {[regexp -all {\.} $c] > 2} { continue }; # only first level #if {[lindex [$c config -cursor] 4] eq ""} catch { $c config -cursor $cursor }; # silently discard errors } } return }; # update_cursor proc update_status {val} { #? add text to status line global cfg if {$cfg(quit) == 1 } { return }; # no GUI update $cfg(objS) config -state normal $cfg(objS) insert end "$val\n" $cfg(objS) see "end - 2 line" set_readonly $cfg(objS) update idletasks; # enforce display update return }; # update_status proc docker_args {} { #? if in "docker mode" pass image ID to Docker; # note that docker specific options must be before o-saft.pl commands or options global prg set do {} if {[regexp {\-docker$} $prg(SAFT)]} { lappend do "-id=$prg(docker-id)" #lappend do "-tag=$prg(docker-tag)" # FIXME: need to distinguish if --id= or --tag= was specified } return $do }; # docker_args proc toggle_cfg {w opt val} { #? use widget config command to change options value if {$val ne {}} { $w config $opt $val; } return 1 }; # toggle_cfg proc toggle_filter_text {w tag val line} { #? toggle visability of text tagged with name $tag in text widget # note that complete line is tagged with name $tag.l (see apply_filter) global cfg _dbx " $w tag config $tag -elide [expr ! $val]" #if {$line==0} { #$w tag config $tag -elide [expr ! $val]; # "elide true" hides the text #} if {[regexp {\-(Label|#.KEY)} $tag]} { $w tag config $tag -elide [expr ! $val]; # hide just this pattern # FIXME: still buggy (see below) return; } # FIXME: if there is more than one tag associated with the same range of # characters (which is obviously for $tag and $tag.l), then unhiding the # tag causes the $tag no longer accessable. Reason yet unknown. # Hence we only support hiding the complete line yet. $w tag config $tag.l -elide [expr ! $val] return }; # toggle_filter_text proc toggle_filter_table {w tag val} { #? toggle visability of text tagged with name $tag in text widget global cfg _dbx " $w rowcget $tag $val" # toggling a list of rows could be as simple as # $w togglerowhide $cfg($tag) # but some lines are in multiple lists, so each line's toggle state will # be checked and changed only if different from given $val, this avoids # unexpected toggles # FIXME: checkbutton in Filter window is wrong now (if multiple lists) foreach n $cfg($tag) { if {[$w rowcget $n -hide] != $val} { continue } $w togglerowhide $n } return }; # toggle_filter_table proc toggle_filter {w tag val line} { #? toggle visability of text tagged with name $tag _dbx "$w $tag $val $line" global cfg switch $cfg(layout) { text { toggle_filter_text $w $tag $val $line } table { toggle_filter_table $w $tag $val } } return }; # toggle_filter proc apply_filter_text {w} { #? apply filters for markup in output, data is in text widget $w # set tag for all texts matching pattern from each filter # also sets a tag for the complete line named with suffix .l global cfg global f_key f_mod f_len f_bg f_fg f_rex f_un f_fn f_cmt; # lists containing filters foreach {k key} [array get f_key] { if {$k eq 0} { continue }; # extract values from filter table for easy use #set key $f_key($k) set mod $f_mod($k) set len $f_len($k) set rex $f_rex($k) set fg $f_fg($k) set bg $f_bg($k) set nr $f_un($k) set fn $f_fn($k) if {$key eq ""} { continue }; # invalid or disabled filter rules if {$rex eq ""} { continue }; # -"- _dbx " $key : /$rex/ $mod: bg->$bg, fg->$fg, fn->$fn" # anf contains start, end corresponding end position of match set key [str2obj [string trim $key]] set anf [$w search -all $mod -count end "$rex" 1.0] set i 0 foreach a $anf { set e [lindex $end $i]; incr i if {$key eq "NO" || $key eq "YES"} {incr e -1 }; # FIXME very dirty hack to beautify print $w tag add HELP-$key.l "$a linestart" "$a lineend" if {$len<=0} { if {$len<0} { $w tag add HELP-$key $a "$a + 1 line"; # complete line to right end } else { $w tag add HELP-$key $a "$a + 1 line - 1 char"; # all text in the line #$w tag add HELP-$key $a "$a lineend"; # does not work } } else { $w tag add HELP-$key $a "$a + $e c" } $w tag raise HELP-$key.l HELP-$key } _dbx " $key: $rex F $fg B $bg U $nr font $fn" if {$fg ne ""} { $w tag config HELP-$key -foreground $fg } if {$bg ne ""} { $w tag config HELP-$key -background $bg } if {$nr ne "0"} { $w tag config HELP-$key -underline $nr } if {$fn ne ""} { $w tag config HELP-$key -font $fn } } return }; # apply_filter_text proc apply_filter_table {w} { #? apply filters for markup in output, data is in table widget $w # FIXME: this is ugly code because the regex in f_rex are optimized for # use in Tcls's text widget, the regex must be changed to match the values # in Tcl's tablelist columns global cfg global f_key f_mod f_len f_bg f_fg f_rex f_un f_fn f_cmt; # lists containing filters foreach {k key} [array get f_key] { set key [str2obj [string trim $key]] set cfg(HELP-$key) "" } set nr -1 # lines look like: 009 {Certificate Common Name} mail.google.com {} foreach l [$w get 0 end] { #set nr [lindex $l 0];# cannot use stored number, because of leading 0 incr nr set __nr [lindex $l 0];# number given by get set label [lindex $l 1] set value [lindex $l 2] set cmt [lindex $l 3] if {[regexp -nocase ^no $value] && [regexp -nocase ^(LOW|WEAK|MEDIUM|HIGH) $cmt]} { continue } # no colour for lines with ciphers (from +cipher) which are not supported if {[regexp -nocase ^none $value]} { continue };# NONE, None are valid values set col 1 set matchtxt $label foreach {k key} [array get f_key] { if {$k eq 0} { continue }; # extract values from filter table for easy use #set key $f_key($k) set mod $f_mod($k) ;# not used here set len $f_len($k) ;# not used here set rex $f_rex($k) set fg $f_fg($k) set bg $f_bg($k) set un $f_un($k) set fn $f_fn($k) ;# does not work in tablelist if {$key eq ""} { continue }; # invalid or disabled filter rules if {$rex eq ""} { continue }; # -"- _dbx " $key : /$rex/ bg->$bg, fg->$fg, fn->$fn" # finding the pattern in the table's cells is not as simple as in # texts (see apply_filter_text() above), that's why the regex must # be applied to the proper column: $col and $matchtxt is needed switch -exact $key { "no" { continue } "_ME_" - "Label:" - "**WARN" - "!!Hint" - "== CMT" - "# DBX" { set col 1; set matchtxt $label } "NO" { set col 2; set matchtxt $value; set rex ^no } "YES" { set col 2; set matchtxt $value } } set rex [regsub {^(\*\*|\!\!)} $rex {\\\1}]; # regex are designed for Tcl's text search where we have the # -exact or -regex option; this regex must be converted for # use in Tcl's regexp: need to escape special characters if {[regexp ^(A|B|C|D|-?-)$ $key]} { set col 2; set matchtxt $value } if {[regexp -nocase ^(LOW|WEAK|MEDIUM|HIGH) $key]} { set col 3; set matchtxt $cmt } if {[regexp -nocase -- $rex "$matchtxt"]} { if {$col == 1} { # if the match is against the first column, colourize the whole line if {$fg ne ""} { $w rowconfig $nr -foreground $fg } if {$bg ne ""} { $w rowconfig $nr -background $bg } if {$fn ne ""} { $w rowconfig $nr -font $fn } #if {$un ne "0"} { $w cellconfig $nr,$col -underline $un } } else { if {$fg ne ""} { $w cellconfig $nr,$col -foreground $fg } if {$bg ne ""} { $w cellconfig $nr,$col -background $bg } if {$fn ne ""} { $w cellconfig $nr,$col -font $fn } #if {$un ne "0"} { $w cellconfig $nr,$col -underline 1 } } set key [str2obj [string trim $key]] lappend cfg(HELP-$key) $nr } } } return }; # apply_filter_table proc apply_filter {w cmd} { #? apply filters for markup in output tab, data is in text or table widget $w global cfg set _layout $cfg(layout) if {$cmd eq "docker_status"} { set _layout "text" }; # don't have table here switch $_layout { text { apply_filter_text $w } table { apply_filter_table $w } } return }; # apply_filter proc show_window {w} { #? show window near current cursor position set y [winfo pointery $w]; incr y 23 set x [winfo pointerx $w]; incr x 23 wm geometry $w "+$x+$y" wm deiconify $w }; # show_window proc www_browser {url} { #? open URL in browser, uses system's native browser global cfg prg if {[string length $prg(BROWSER)] < 1} { puts {**WARNING: no browser found}; return; } #win32# [tk windowingsystem] eq "win32" #win32# { does not work with ActiveTcl #win32# package require twapi_com #win32# set ie [twapi::comobj InternetExplorer.Application] #win32# puts "IE $ie" #win32# $ie Visible true #win32# set ie [twapi::comobj Firefox.Application] #win32# puts "IE $ie" #win32# $ie Visible true #win32# } #win32# { works with ActiveTcl #win32# folgendes funktioniert, aber IE läuft im Vordergrund, d.h. Rest fehlt #win32# package require dde #win32# dde execute iexplore WWW_OpenURL http://www.tcl.tk/ #win32# } if {$cfg(VERB)==1} { puts " exec {*}$prg(BROWSER) $url & " } catch { exec {*}$prg(BROWSER) $url & } }; # www_browser proc bind_browser {w tagname} { #? search for URLs in $w, mark them and bind key to open browser global cfg set anf [$w search -regexp -all -count end {\shttps?://[^\s]*} 1.0] set i 0 foreach a $anf { set e [lindex $end $i]; set t [string trim [$w get $a "$a + $e c"]]; set l [string length $t] incr i $w tag add $tagname $a "$a + $e c" $w tag add $tagname-$i $a "$a + $e c" $w tag config $tagname-$i -foreground [get_color link] $w tag bind $tagname-$i "www_browser $t" if {$cfg(TIP)==0} { tooltip::tooltip $w -tag $tagname-$i "Open in browser: $t" } # cannot use create_tip as we want to bind to $tagnmae and not $w } return }; # bind_browser proc create_selected {title val} { #? opens toplevel window with selectable text global cfg myX global __var; # must be global set w .selected toplevel $w wm title $w "$cfg(TITLE): $title" wm geometry $w 200x50 pack [entry $w.choosen -textvariable __var -relief flat] pack [button $w.closewin -command "destroy $w"] -side right -padx $myX(rpad) theme_set $w.closewin $cfg(bstyle) create_tip $w.choosen "[get_tipp choosen] $title" set __var "$val" return 1 }; # create_selected proc create_window {title size} { #? create new toplevel window with given title and size; returns widget global cfg myX set this .[str2obj $title] if {[winfo exists $this]} { return ""; }; # do nothing toplevel $this wm title $this "$cfg(TITLE): $title" wm iconname $this "o-saft: $title" wm geometry $this $size pack [frame $this.f1] -fill x -side bottom pack [button $this.f1.closewin -command "destroy $this"] -padx $myX(rpad) -side right theme_set $this.f1.closewin $cfg(bstyle) if {$title eq "Help" || $title eq "About"} { return $this } if {[regexp {^Filter} $title]} { return $this } # all other windows have a header line and a Save button pack [frame $this.f0 -borderwidth 1 -relief sunken] -fill x -side top pack [label $this.f0.t -text $title -relief flat ] -fill x -side left pack [button $this.f0.help_me -command "create_help {$title}"] -side right pack [button $this.f1.saveconfig -command {osaft_save "CFG" 0}] -side left theme_set $this.f1.saveconfig $cfg(bstyle) theme_set $this.f0.help_me $cfg(bstyle) return $this }; # create_window proc create_host {parent} { #? frame with label and entry for host:port; $nr is index to hosts() global cfg hosts myX set host $hosts($hosts(0)) incr hosts(0) _dbx " host($hosts(0)): $host" set this $parent.ft$hosts(0) frame $this grid [label $this.lh -text [get_text host]] \ [entry $this.eh -textvariable hosts($hosts(0))] \ [button $this.host_add -command "create_host {$parent};"] \ [button $this.host_del -command "remove_host $this; set hosts($hosts(0)) {}"] \ theme_set $this.host_add $cfg(bstyle) if {$hosts(0)==1} { # first line has no {-} but {about} grid forget $this.host_del grid [button $this.about -command "create_about"] -row 0 grid config $this.about -column 4 -sticky e -padx "1 $myX(padx)" theme_set $this.about $cfg(bstyle) } else { theme_set $this.host_del $cfg(bstyle) } grid config $this.eh -column 1 -sticky ew grid columnconfigure $this 1 -weight 1 set i [expr $hosts(0) - 1] set prev $parent.ft$i while {$i > 0} { # check if previous frame exists, otherwise decrement if {[winfo exists $prev]} { break; } incr i -1 set prev $parent.ft$i } # if we reach here a previous frame exists # or i==0 which should never occour and then will force an error in next line pack $this -fill x -after $prev }; # create_host proc remove_host {parent} { #? destroy frame with label and entry for host:port catch {destroy $parent.eh $parent.bp $parent.bm $parent.lh $parent} }; # remove_host proc create_text {parent content} { #? create scrollable text widget and insert given text; returns widget set this $parent text $this.t -wrap char -yscroll "$this.s set"; # -width 40 -height 10 scrollbar $this.s -orient vertical -command "$this.t yview" #set txt [regsub -all {\t} $content "\t"]; # tabs are a pain in Tcl :-( # insert content $this.t insert end $content $this.t config -font TkFixedFont set_readonly $this.t pack $this.s -side right -fill y -pady 2 -padx {0 2} -in $this pack $this.t -fill both -expand 1 -pady 2 -padx {2 0} -in $this return $this }; # create_text proc create_table {parent content} { #? create scrollable table widget and insert given text; returns widget # # create a table with 4 columns: Nr Label Value Comment # the Nr column is used to revert any sorting # the text for Label column is extracted from the line, anything left of : # the text for Value column is extracted from the line, anything right of : # the value is then further separated in a Value and a Comment (if any) # lines from +cipher command consist of a cipher, a value and a severity # the cipher becomes the Label column # lines starting with = or # are currently ignored, because Tcl's tablelist # has no "colspan" functionality and therfore do not fit into the 4 colums global cfg prg set this $parent.ft frame $this pack [scrollbar $this.x -orient horizontal -command [list $this.t xview]] -side bottom -fill x pack [scrollbar $this.y -orient vertical -command [list $this.t yview]] -side right -fill y pack [tablelist::tablelist $this.t \ -exportselection true \ -selectmode extended \ -selecttype row \ -arrowcolor black \ -background white \ -borderwidth 1 \ -stripebackground lightgray \ -arrowstyle $cfg(tfont) \ -labelrelief solid \ -labelfont osaftBold \ -labelpady 3 \ -labelcommand tablelist::sortByColumn -showarrow true \ -movablecolumns true \ -movablerows true \ -xscrollcommand [list $this.x set] \ -yscrollcommand [list $this.y set] \ -font TkFixedFont \ -spacing 1 \ -height 25 \ -width 150 \ -stretch 2 \ ] -side left -fill both -expand yes # insert header line set head [list Nr Label Value Comment] foreach f $head { lappend titles 0 $f } $this.t config -columns $titles $this.t columnconfigure 0 -width 3 ;# -hide true ;# line nr $this.t columnconfigure 1 -width 50 ;# label $this.t columnconfigure 2 -width 25 ;# value # insert content set n 1; # add uniwue number to each line, for initial sorting set ssl "";# TODO: ungly hack: need to detect header line with protocol foreach line [split $content "\n"] { # content consist of lines separated by \n , where each line is a label # and a value separated by a tab (and additional spaces for formatting) # in tabular context, only label and value is required; no tabs, spaces if {[regexp {^\s*$} $line]} { continue };# skip empty lines #_dbx " line: $line" set nr [format %03d [incr n]] # integer must have leading 0, otherwise sorting of tablelist fails # no more than 999 lines are expected, may be more with --v --trace set stretch 0 set line [regsub {^(=+)} $line {\1:}]; # simulate label: value if {[regexp {^[=#]+} $line]} { $this.t insert end [list $nr $line] $this.t togglerowhide end $this.t cellconfigure end,0 -stretch 1 ;# FIXME: does not work if {[regexp {Ciphers:\s*Checking} $line]} { # +cipher header line containing protocol, like: # === Ciphers: Checking TLSv12 === # TODO: matches content, only default settings detected set ssl [lindex [split $line " "] 3];# remember current protocol #dbx puts "C $ssl" } # tablelist does not support "colspan", hence lines are ignored continue set col2 $col1 set col1 "" # ?# set col0 "$col0 $col1" # ?# set stretch 1 # ?# tablelist kann kein "colspan" } if {[regexp $prg(SAFT).* $line]} { $this.t insert end [list $nr $line] $this.t togglerowhide end $this.t cellconfigure end,0 -stretch 1 ;# FIXME: does not work # tablelist does not support "colspan", hence lines are ignored continue set col2 $col0 set col1 "" set col0 "" } if {[regexp {:} $line]} { # line not from +cipher set col2 "" set col0 [regsub {^([^:]+):.*} $line {\1}] ; # get label set col1 [regsub {^[^:]+:\s*} $line {}] ; # get label #if {[regexp -nocase {^(yes|no\s+\()} $col1]} # NOTE: there my be values like "No other text ..." if {[regexp -nocase {^(yes|no)} $col1]} { # lines from +check # split yes|no from rest of text set col2 [regsub {^[^\s]+\s+} $col1 {}] set col1 [regsub -nocase {^(yes|no)\s.*} $col1 {\1}] if {$col1 eq $col2} { set col2 "" };# if there is no col2 } if {[regexp {^[!\*]+} $line]} { # warning and hint lines set col2 $col1 set col1 "" } if {[regexp {^(SSL|TLS)v} $col0]} { # summary lines of cipher checks set col2 $col1 set col1 "" } if {$cfg(max53) < [string length $col2]} { pwarn "comment for '$col0' to large (> $cfg(max53)); stripped" set col2 "[string range $col2 1 $cfg(max53)] ..\[stripped\].." ;# see cfg(max53) # FIXME: need to store orignal text somewhere (notin table) } set line [list $nr $col0 $col1 $col2] } else { # lines containing cipher, like: # AES128-SHA256 yes HIGH append line " $ssl" ;# add protocol set line [regsub {^[ \t]+} $line {}] ;# remove trailing spaces set line [regsub -all {([ \t])+} $line { }] set cols [split $line " "] set line "$nr $cols" } set line [regsub -all \t $line {}] ;# remove tabs $this.t insert end $line } pack $this -side top return $this }; # create_table proc create_filter_head {parent txt tip col} { #? create a cell for header line in the filter grid # note: txt must be the index to cfg_texts array, we cannot pass the value # directly because it then must be converted to an object name also, # see next setting of $this set this $parent.$txt grid [label $this -text [get_tipp $txt] -relief raised -borderwidth 1 ] -sticky ew -row 0 -column $col create_tip $this $tip }; # create_filter_head proc create_filter_text {parent cmd} { #? create table with filter data global cfg global f_key f_mod f_len f_bg f_fg f_rex f_un f_fn f_cmt; # filters set this $parent # { set header line with descriptions create_filter_head $this f_key $f_key(0) 0 create_filter_head $this f_moder "$f_mod(0) (-regexp)" 1 create_filter_head $this f_modee "$f_mod(0) (-exact)" 2 create_filter_head $this f_chars $f_len(0) 3 create_filter_head $this f_regex $f_rex(0) 4 create_filter_head $this f_fg $f_fg(0) 5 create_filter_head $this f_bg $f_bg(0) 6 create_filter_head $this f_font $f_fn(0) 7 create_filter_head $this f_u $f_un(0) 8 # } foreach {k key} [array get f_key] { # set all filter lines if {$k eq 0} { continue }; #set key $f_key($k) set key [str2obj [string trim $key]] set mod $f_mod($k) set len $f_len($k) set rex $f_rex($k) set fg $f_fg($k) set bg $f_bg($k) set nr $f_un($k) set fn $f_fn($k) if {$key eq ""} { continue }; # invalid or disabled filter rules _dbx " .$key /$rex/" grid [entry $this.k$k -textvariable f_key($k) -width 8] \ [radiobutton $this.x$k -variable f_mod($k) -value "-regexp"] \ [radiobutton $this.e$k -variable f_mod($k) -value "-exact" ] \ [entry $this.l$k -textvariable f_len($k) -width 3] \ [entry $this.r$k -textvariable f_rex($k) ] \ [entry $this.f$k -textvariable f_fg($k) -width 10] \ [entry $this.b$k -textvariable f_bg($k) -width 10] \ [entry $this.s$k -textvariable f_fn($k) -width 10] \ [checkbutton $this.u$k -variable f_un($k) ] \ grid config $this.k$k $this.r$k -sticky ew grid config $this.f$k $this.b$k $this.s$k -sticky w create_tip $this.k$k $f_cmt($k) create_tip $this.r$k $f_cmt($k) # some entries apply setting to KEY entry $this.f$k config -vcmd "toggle_cfg $this.k$k -fg \$f_fg($k)" -validate focusout $this.b$k config -vcmd "toggle_cfg $this.k$k -bg \$f_bg($k)" -validate focusout $this.s$k config -vcmd "toggle_cfg $this.k$k -font \$f_fn($k)" -validate focusout toggle_cfg $this.k$k -fg $f_fg($k) toggle_cfg $this.k$k -bg $f_bg($k) toggle_cfg $this.k$k -font $f_fn($k) } foreach {k key} [array get f_key] { # set all filter lines if {$k eq 0} { continue }; # FIXME: unfortunately this binding executes immediately, which results # in a chooseColor window for each row at startup #$this.b$k config -vcmd "set f_bg($k) [tk_chooseColor -title $f_bg(0)]; return 1" -validate focusin #$this.s$k config -vcmd "tk fontchooser config -command {set f_fn($k)}; tk_chooseColor -title $f_bg(0)]; return 1" -validate focusin } grid columnconfigure $this {0 1 2 3 5 6 7 8} -weight 0 grid columnconfigure $this 4 -minsize 20 -weight 1; # minsize does not work return $this }; # create_filter_text proc create_filter_table {parent cmd} { #? create scrollable table widget with filter data #################### experimental, not yet ready ################# ##### table ok, but missing: ##### radiobutton for column r und e ; probaly needs to use checkbutton ##### set variablen in all columns ##### changing font or colour must adapt cell in column 0 ##### Tooltip # global cfg global f_key f_mod f_len f_bg f_fg f_rex f_un f_fn f_cmt; # filters set this $parent font create osaftBig {*}[font config TkFixedFont] -size 9 pack [scrollbar $this.x -orient horizontal -command [list $this.t xview]] -side bottom -fill x pack [scrollbar $this.y -orient vertical -command [list $this.t yview]] -side right -fill y pack [tablelist::tablelist $this.t \ -exportselection true \ -selectmode extended \ -selecttype cell \ -arrowcolor black \ -background white \ -borderwidth 2 \ -stripebackground #e7e7e7 \ -arrowstyle $cfg(tfont) \ -labelrelief solid \ -labelfont osaftBold \ -labelpady 3 \ -labelcommand tablelist::sortByColumn -showarrow true \ -movablecolumns true \ -movablerows false \ -showseparators true \ -xscrollcommand [list $this.x set] \ -yscrollcommand [list $this.y set] \ -font osaftBig \ -spacing 1 \ -height 16 \ -width 150 \ -stretch 4 \ ] -side left -fill both -expand yes # insert header line set head [list f_key f_moder f_modee f_chars f_regex f_fg f_bg f_font f_u ] foreach f $head { lappend titles 0 [get_tipp $f] } # TODO: -tooltipaddcommand, $this.t config -columns $titles $this.t columnconfigure 0 -width 10;# $this.t columnconfigure 7 -width 10;# # insert lines set row -1 foreach {k key} [array get f_key] { # set all filter lines if {$k eq 0} { continue }; incr row #set key $f_key($k) set key [str2obj [string trim $key]] set mod $f_mod($k) set len $f_len($k) set rex $f_rex($k) set fg $f_fg($k) set bg $f_bg($k) set nr $f_un($k) set fn $f_fn($k) $parent.t insert end [list $f_key($k) r e $f_len($k) $f_rex($k) $f_fg($k) $f_bg($k) $f_fn($k) ] # $f_mod($k $f_mod($k) foreach col [list 0 3 4 5 6 7] { $parent.t cellconfig $row,$col -editable yes -editwindow entry } $parent.t cellconfig $row,8 -editable yes -editwindow checkbutton $parent.t cellconfig $row,0 -fg $f_fg($k) -bg $f_bg($k) -font $f_fn($k) } return $this }; # create_filter_table proc create_filtertab {parent cmd} { #? create tab with filter data global cfg pack [label $parent.text -relief flat -text [get_tipp tabFILTER]] set this $parent.g pack [frame $this] -side top -expand yes -fill both set tab [create_filter_text $this $cmd].t #if {"text" eq $cfg(layout)} { set tab [create_filter_text $this $cmd].t } #if {"table" eq $cfg(layout)} { set tab [create_filter_table $this $cmd].t } # create_filter_* returns widget, which is same as $parent catch { # silently ignore if systems has no fontchooser (i.e. Mac OS X) tk fontchooser config -command {create_selected "Font"}; # what to do with selection # there is no tk_fontchooser, but tk::fontchooser or tk fontchooser pack [button $parent.tkfont -command {tk fontchooser show}] -side right theme_set $parent.tkfont $cfg(bstyle) } pack [button $parent.tkcolor -command {create_selected "Color" [tk_chooseColor]} ] -side right theme_set $parent.tkcolor $cfg(bstyle) return }; # create_filtertab proc create_filter {parent cmd} { #? create new window with filter commands for exec results; store widget in cfg(winF) global cfg f_key f_bg f_fg f_cmt filter_bool myX putv "create_filter(»$parent« $cmd)" if {[winfo exists $cfg(winF)]} { show_window $cfg(winF); return; } set obj $parent; # we want to have a short variable name set geo [split [winfo geometry .] {x+-}] set myX(geoF) +[expr [lindex $geo 2] + [lindex $geo 0]]+[expr [lindex $geo 3]+100] # calculate new position: x(parent)+width(parent), y(parent)+100 # most window managers are clever enough to position window # correctly if calculation is outside visible (screen) frame set cfg(winF) [create_window "Filter:$cmd" $myX(geoF)] # FIXME: only one variable for windows, need a variable for each window # workaround see osaft_exec set this $cfg(winF) _dbx " parent: $obj | $cmd | $myX(geoF)" pack [frame $this.f -relief sunken -borderwidth 1] -fill x pack [label $this.f.t -relief flat -text [get_text c_toggle]] -fill x pack [checkbutton $this.f.c -text [get_text hideline] -variable filter_bool($obj,line)] -anchor w; create_tip $this.f.c [get_tipp hideline] set_readonly $this.f.c foreach {k key} [array get f_key] { if {$k eq 0} { continue }; #set key $f_key($k) set bg $f_bg($k) set fg $f_fg($k) set key [str2obj [string trim $key]] set filter_bool($obj,HELP-$key) 1; # default: text is visible pack [checkbutton $this.x$key \ -text $f_key($k) -variable filter_bool($obj,HELP-$key) \ -command "toggle_filter $obj HELP-$key \$filter_bool($obj,HELP-$key) \$filter_bool($obj,line);" \ ] -anchor w ; # note: using $f_key($k) instead of $key as text # note: checkbutton value passed as reference # TODO: following "-fg white" makes check in checkbox invisible if {$fg ne ""} { $this.x$key config -fg $fg }; # Tk is picky .. if {$bg ne ""} { $this.x$key config -bg $bg }; # empty colour not allowd create_tip $this.x$key "[get_tipp show_hide] $f_cmt($k)"; } }; # create_filter proc create_about {} { #? create new window with About text; store widget in cfg(winA) # Show the text starting with #? from this file. global cfg myX if {[winfo exists $cfg(winA)]} { show_window $cfg(winA); return; } set cfg(winA) [create_window "About" $myX(geoA)] set txt [create_text $cfg(winA) [osaft_about "ABOUT"]].t $txt config -bg [get_color osaft] # search for section headers and mark them bold set anf [$txt search -regexp -nolinestop -all -count end {^ *[A-ZÄÖÜß ]+$} 1.0] set i 0 foreach a $anf { set e [lindex $end $i]; $txt tag add sektion $a "$a + $e char" incr i } $txt tag config sektion -font osaftBold # bind buttons and keys bind_browser $txt ABOUT-URL bind $txt "search_view $txt %K" return }; # create_about proc create_pod {sect} { #? create new window with complete help using external viewer # for advantages and disadvantages please see contrib/.o-saft.tcl global cfg myX prg # TODO: does probably not working on Windows #tk_messageBox -icon warning -title " using $prg(TKPOD)" \ # -message "$prg(TKPOD) will not be closed with $cfg(ICH)" _dbx " $prg(TKPOD) o-saft.pod -geo $myX(geoO) &" catch { exec {*}$prg(TKPOD) o-saft.pod -geo $myX(geoO) & }; return }; # create_pod proc create_help {sect} { #? create new window with complete help text; store widget in cfg(winH) #? if sect is given, jump to this section _dbx "($sect)" global cfg myX prg search putv "create_help(»$sect«)" if {[info exists prg(TKPOD)]==1} { if {$prg(TKPOD) ne "O-Saft"} { # external viewer specified, use it ... create_pod $sect ; return; } } # uses plain text help text from "o-saft.pl --help" # This text is parsed for section header line (all capital characters) # which will be used as Table of Content and inserted before the text. # All referenzes to this sections are clickable. # Also all references to commands (starting with '+') and options ('-') # are highlighted and used for navigation. # Example text: # ... # QUICKSTART # # Before going into a detailed description of the purpose and usage, # here are some examples of the most common use cases: # # * Show supported (enabled) ciphers of target: # o-saft.pl +cipher --enabled example.tld # ... # OPTIONS # # All options are written in lowercase. Words written in all capital in # the description here is text provided by the user. # # Options for help and documentation # # --help # # WYSIWYG # ... # # In above example QUICKSTART and OPTIONS are the section headers, # --help is an option and the line starting with o-saft.pl will be # a command (not to be confused with commands of o-saft.pl). # # TODO: some section lines are not detected properly and hence missing _dbx " 1. build help window" if {[winfo exists $cfg(winH)]} { # if there is a window, just jump to text wm deiconify $cfg(winH) set name [str2obj [string trim $sect]] search_show $cfg(winH).t "HELP-HEAD-$name" return } set this [create_window {Help} $myX(geoO)] set txt [create_text $this $cfg(HELP)].t; # $txt is a widget here set toc {} _dbx " 2. add additional buttons for search" pack [button $this.f1.help_home -command "search_show $txt {HELP-LNK-T}; set search(curr) 0;"] \ [button $this.f1.help_prev -command "search_next $txt {-}"] \ [button $this.f1.help_next -command "search_next $txt {+}"] \ [spinbox $this.f1.s -textvariable search(text) -values $search(list) -command "search_list %d" -wrap 1 -width 25] \ [spinbox $this.f1.m -textvariable search(mode) -values [list exact regex smart fuzzy] ] \ [button $this.f1.help_help -command {global cfg; create_about; $cfg(winA).t see 60.0} ] \ -side left $this.f1.m config -state readonly -relief groove -wrap 1 -width 5 pack config $this.f1.m -padx 10 pack config $this.f1.help_home $this.f1.help_help -padx $myX(rpad) theme_set $this.f1.help_home $cfg(bstyle) theme_set $this.f1.help_prev $cfg(bstyle) theme_set $this.f1.help_next $cfg(bstyle) theme_set $this.f1.help_help $cfg(bstyle) create_tip $this.f1.m [get_tipp help_mode] create_tip $this.f1.s [get_tipp helpsearch] bind $this.f1.s " global search if {\$search(last) != \$search(text)} { lappend search(list) \$search(text); incr search(curr) }; search_text $txt \$search(text); " _dbx " 3. search for section head lines, mark them and add (prefix) to text" set anf [$txt search -regexp -nolinestop -all -count end {^ {0,5}[A-Z][A-Za-z_? '()=+,:.-]+$} 1.0] #dbx# puts "3. $anf\n$end" set i 0 foreach a $anf { set e [lindex $end $i]; set t [$txt get $a "$a + $e c"] ;# don't trim, need leading spaces set l [string length $t] incr i _dbx " 3. HEAD: $i\t$t" if {[notTOC $t]} { continue; } ;# skip some special strings if {[string trim $t] eq ""} { continue };# skip empty entries if {[regexp {^[A-Z]} $t]} { set toc "$toc\n" }; # add empty line for top level headlines set toc "$toc\n $t" ;# prefix headline with spaces in TOC set name [str2obj [string trim $t]] $txt tag add HELP-HEAD $a "$a + $e c" $txt tag add HELP-HEAD-$name $a "$a + $e c" } $txt config -state normal $txt insert 1.0 "\nCONTENT\n$toc\n" $txt tag add HELP-LNK 2.0 2.7 ;# add markup $txt tag add HELP-LNK-T 2.0 2.7 ;# set_readonly $txt #_dbx "TOC:[$txt get 1.0 end]"; set nam [$txt search -regexp -nolinestop {^NAME$} 1.0]; # only new insert TOC if {$nam eq ""} { _dbx " 3. no text available" ;# avoid Tcl errors return; }; _dbx " 4. search for all references to section head lines in TOC and add click event" # NOTE: used regex must be similar to the one used in 1. above !! set anf [$txt search -regexp -nolinestop -all -count end { *[A-Za-z_? '()=,:.-]+( |$)} 3.0 $nam] #dbx# puts "4. $anf\n$end" set i 0 foreach a $anf { set e [lindex $end $i]; set t [$txt get $a "$a + $e c"]; incr i _dbx " 4. TOC: $i\t$t" if {[regexp { - } $t]} { continue } ;# skip glossar lines if {[notTOC $t]} { continue } ;# skip some special strings set name [str2obj [string trim $t]] set b [$txt search -regexp {[A-Z]+} $a] $txt tag add HELP-TOC $b "$b + $e c" ;# do not markup leading spaces $txt tag add HELP-TOC-$i $a "$a + $e c" ;# but complete line is clickable $txt tag bind HELP-TOC-$i "search_show $txt {HELP-HEAD-$name}" } # 4a. search for all references to section head in text # only search words with all upper case characters and preceeded by 2 spaces set anf [$txt search -regexp -nolinestop -all -count end { [A-Z]{4}[A-Z -]+ } $nam] #dbx# puts "4.a $anf\n$end" set i 0 foreach a $anf { set e [lindex $end $i]; set t [$txt get $a "$a + $e c"]; incr i _dbx " 4a. REF: $i\t$t" if {[regexp {^[A-Z]+} $t]} { continue };# skip headlines itself if {[regexp { - } $t]} { continue } ;# skip glossar lines if {[notTOC $t]} { continue } ;# skip some special strings set name [str2obj [string trim $t]] $txt tag add HELP-REF $a "$a + $e c" $txt tag add HELP-REF-$i $a "$a + $e c" $txt tag bind HELP-REF-$i "search_show $txt {HELP-HEAD-$name}" } _dbx " 5. search all commands and options and try to set click event" set anf [$txt search -regexp -nolinestop -all -count end { [-+]-?[a-zA-Z0-9_=+-]+([, ]|$)} 3.0] #dbx# puts "4. $anf\n$end" # Now loop over all matches. The difficulty is to distinguish matches, # which are the head lines like: # --v # +version # and those inside the text, like: # ... option --v is used for ... # The rules for head lines are: # start with spaces followed by + or - followed by word 'til end of line # Anything else is most likely a reference, but there are exceptions like: # --v --v # is a head line, and folling might be a reference: # +version. # Unfortunately --v --v (and similar examples) will not be detected as # head line. This is due to the regex in "text search ...", which doesn't # allo spaces. # FIXME: set i 0 foreach a $anf { set e [lindex $end $i]; set l [$txt get "$a - 2 c" "$a + $e c + 1 c"]; # one char more, so we can detect head line set t [string trim [$txt get $a "$a + $e c"]]; set r [regsub {[+]} $t {\\+}]; # need to escape + set r [regsub {[-]} $r {\\-}]; # need to escape - set name [str2obj [string trim $t]] _dbx " 5. LNK: $i\tHELP-LNK-$name\t$t" if {[regexp -lineanchor "\\s\\s+$r$" $l]} { # FIXME: does not match all lines proper # these matches are assumed to be the header lines $txt tag add HELP-LNK-$name $a "$a + $e c"; $txt tag add HELP-LNK $a "$a + $e c"; } else { # these matches are assumed references $txt tag add HELP-LNK-$i $a "$a + $e c - 1 c"; # do not markup spaces $txt tag bind HELP-LNK-$i "search_show $txt {HELP-LNK-$name}" $txt tag config HELP-LNK-$i -foreground [get_color link] $txt tag config HELP-LNK-$i -font osaftSlant } incr i } _dbx " 6. search for all examples and highlight them" # search $prg(rexCOMMANDS) if preceeded by at least 9 spaces, these spaces # must then be removed from the match, so they are not highlighted # FIXME: stiil matches some lines accidently, i.e. in DEBUG section set anf [$txt search -regexp -nolinestop -all -count end "^ \{9,\}$prg(rexCOMMANDS)\( \[^\\n\]+|$\)" 3.0] #dbx# puts "6. $anf\n$end" set i 0 foreach a $anf { set e [lindex $end $i]; set t [$txt get $a "$a + $e c"] _dbx " 6. CODE: $i\tHELP-CODE\t$t" set s 10 regexp {^ *} $t spaces ;# get count of leading spaces set s [string length $spaces] $txt tag add HELP-CODE "$a + $s c" "$a + $e c";# start highlight at $s incr i } _dbx " 7. search for all special quoted strings and highlight them" #dbx# puts "$txt\n[$txt get 0.0 end]" set anf [$txt search -regexp -all -count end {'[^']+'} 3.0] #dbx# puts "7. $anf\n$end" set i 0 foreach a $anf { set e [expr [lindex $end $i] - 1] ;# without trailing quote set t [$txt get "$a + 1 c" "$a + $e c"];# without leading quote _dbx " 7. CODE: $i\tHELP-CODE\t'$t'" ;# add quotes in debug output $txt tag add HELP-CODE $a "$a + $e c" $txt replace $a "$a + 1 c" { } $txt replace "$a + $e c" "$a + $e c + 1 c" { } incr i } _dbx " 8. highlight all URLs and bind key" bind_browser $txt HELP-URL # finally global markups $txt tag config HELP-CODE -background [get_color code] $txt tag config HELP-URL -foreground [get_color link] $txt tag config HELP-REF -foreground [get_color link] $txt tag config HELP-TOC -foreground [get_color link] $txt tag config HELP-TOC -font osaftBold $txt tag config HELP-LNK -font osaftBold $txt tag config HELP-HEAD -font osaftBold _dbx " 9. MARK: [$txt mark names]" if {$cfg(DEBUG) > 1} { #_dbx " TAGS: [$txt tag names]"; # huge output!! foreach tag [list HELP-TOC HELP-HEAD HELP-CODE HELP-URL HELP-LNK HELP-LNK-T HELP-search-pos] { _dbx " $tag:\t[$txt tag ranges $tag]" } } bind $txt "search_view $txt %K" #bind $txt "search_view $txt %D" ;# done automatically set cfg(winH) $this if {$sect ne ""} { set name [str2obj [string trim $sect]] search_show $cfg(winH).t "HELP-HEAD-$name" } return }; # create_help proc create_note {parent title} { #? create notebook TAB; returns widget _dbx "(»$title«)" set name [str2obj $title] set this $parent.$name set alt 0 if {[regexp {^\(} $title]} { set alt 1; }; # don't use (, but next charcter frame $this $parent add $this -text $title -underline $alt return $this }; # create_note proc create_tab {parent cmd content} { #? create new TAB in .note and set focus for it; returns text widget in TAB _dbx "($cmd,»$content«)" global cfg set tab [create_note $parent "($cfg(EXEC)) $cmd"]; set _layout $cfg(layout) if {$cmd eq "docker_status"} { set _layout "text" }; # don't need table here if {$_layout eq "text"} { set txt [create_text $tab $content].t } if {$_layout eq "table"} { set txt [create_table $tab $content].t } # ugly hardcoded .t from .note pack [button $tab.saveresult -command "osaft_save $txt {TAB} $cfg(EXEC)"] \ [button $tab.ttyresult -command "osaft_save $txt {TTY} $cfg(EXEC)" ] \ [button $tab.filter -command "create_filter $txt $cmd" ] \ -side left pack [button $tab.closetab -command "destroy $tab"] -side right theme_set $tab.closetab $cfg(bstyle) theme_set $tab.saveresult $cfg(bstyle) theme_set $tab.ttyresult $cfg(bstyle) theme_set $tab.filter $cfg(bstyle) $cfg(objN) select $tab return $txt }; # create_tab proc create_cmd {parent title} { #? create button to run O-Saft command; returns widget _dbx "(»$title«)" global cfg set name [regsub {^\+} $title {cmd}]; # keys start with cmd instead of + set this $parent.$name pack [button $this -text $title -command "osaft_exec $parent $title"] -side left theme_set $this $cfg(bstyle) return $this }; # create_cmd proc create_opt {parent title} { #? create checkbutton for O-Saft options; returns widget _dbx "(»$title«)" global cfg set name [regsub {^--} $title {cmd}]; # keys start with cmd instead of + set this $parent.$name pack [checkbutton $this -text $title -variable cfg($title)] -side left -padx 5 create_tip $this [get_tipp $title] return $this }; # create_opt proc create_win {parent title cmd} { #? create window for commands and options # creates one button for each line returned by: o-saft.pl --help=opt|commands # title must be string of group of command or options _dbx "(»$title« $cmd)" global cfg myX prg set this $parent set win $this set data $cfg(OPTS) if {$cmd eq "CMD"} { set data $cfg(CMDS) } # data is a huge list which contains commands or options grouped by a # header line. The window to be created just contains the lines which # follow the header line down to the next header line. $skip controls # that. # we expect following data in $cfg(CMDS): # Commands for information about this tool # +dump Dumps internal data for SSL connection and target certificate. # ... # Commands to check SSL details # +check Check the SSL connection for security issues. # ... # # we expect following data in $cfg(OPTS): # OPTIONS # Options for help and documentation # --h # --help # ... # Options for all commands (general) # --no-rc # --dns # ... # Options for SSL tool # --s_client # --no-openssl # --openssl=TOOL # ... # SEE Help:Syntax in o-saft-man.pm and # also OSaft/Doc/Data.pm and OSaft/Doc/help.txt # Note that "Discrete Commands ..." in cfg(HELP) are missing and have # no description; must use that from cfg(CMDS). set skip 1; # skip data until $title found foreach l [split $data "\r\n"] { set dat [string trim $l] if {[regexp $prg(rexOUT-cmd) $dat]} { set skip 1; };# next group starts if {"$title" eq "$dat"} { # FIXME: scary comparsion, better use regex # title matches: create a window for checkboxes and entries set skip 0; _dbx " create window: $win »$dat«" set dat [string toupper [string trim $dat ] 0 0] set win [create_window $dat ""] if {$win eq ""} { return; } ;# do nothing, even no: show_window $this; set this $win.g frame $this; # frame for grid continue } if {$skip==1} { continue; } #dbx# puts "DATA $dat" # skipped general if {$dat eq ""} { continue; } if {[regexp $prg(rexOUT-head) $dat]} { continue; } ;# ignore header lines # skipped commands if {[regexp $prg(rexCMD-int) $dat]} { continue; } ;# internal use only # skipped options #if {"OPTIONS" eq $dat} { continue; } if {[regexp $prg(rexOPT-help) $dat]} { continue; } if {[regexp $prg(rexOUT-int) $dat]} { continue; } ;# use other tools for that # the line $l looks like: # our_key some descriptive text # where $dat should contain "our_key" and $tip "some descriptive text" # so all multiple white spaces are reduced, which results in first word # being $dat and all the rest will be $tip # multiple white spaces in descriptive text are lost, that's ok if any set dat [regsub -all {\s+} $dat { }] set tip [regsub {[^\s]+\s*} $dat {} ] set dat [lindex [split $dat " "] 0] _dbx " create: »$dat« $cmd" set name [str2obj $dat] if {[winfo exists $this.$name]} { # this occour if command/or option appears more than once in list # hence the warning is visible only in verbose mode putv "**WARNING: create_win exists: $this.$name; ignored" continue } frame $this.$name ;# create frame for command' or options' checkbutton # # pack [button $this.$name.h -text {?} -command "create_help {$dat}" -borderwidth 1] -side left if {[regexp {=} $dat]==0} { #dbx# puts "create_win: check: $this.$name.c -variable cfg($dat)" pack [checkbutton $this.$name.c -text $dat -variable cfg($dat)] -side left -anchor w -fill x } else { regexp $prg(rexOPT-cfg) $l dumm idx val #dbx# puts "create_win: entry: $this.$name.e -variable cfg($idx)" pack [label $this.$name.l -text $idx -width $myX(lenl)] -fill x -side left -anchor w pack [entry $this.$name.e -textvariable cfg($idx)] -fill x -side left -expand 1 if {[regexp {^[a-z]*$} $l]} { set cfg($idx) $val } ;# only set if all lower case $this.$name.l config -font TkDefaultFont ;# reset to default as Label is bold } grid $this.$name -sticky w create_tip $this.$name "$tip" ;# $tip may be empty, i.e. for options } pack $this -fill both -expand 1 ;# delayed pac for better performance # now arrange grid in rows and columns # idea: arrange widgets in at least 3 columns # we can use 4 columns in Commands window because widgets are smaller # sorting is vertical (horizontal sorting commented out) set slaves [lsort -nocase [grid slaves $this]] set cnt [llength $slaves] if {$cnt < 1} { return }; # avoid math errors, no need to resize window set max 2; # 3 columns: 0..2 if {$cmd eq "CMD"} { incr max }; # 4 columns in Commands set rows [expr $cnt / [expr $max + 1]] _dbx " cnt/(max+1) = rows: $cnt/($max+1) = $rows" set col 0 set row 0 foreach slave $slaves { #if {$col > $max} { incr row; set col 0 }; # horizontal sorting if {$row > $rows} { incr col; set row 0 }; # vertical sorting grid config $slave -row $row -column $col -padx 8 #incr col; # horizontal incr row; # vertical } }; # create_win proc create_buttons {parent cmd} { #? create buttons to open window with commands or options # creates one button for header line returned by: o-saft.pl --help=opt|commands # cmd must be "OPT" or "CMD" or "TRC" global cfg prg set data $cfg(OPTS) set txt [get_tipp "tab$cmd"]; # tabCMD and tabOPT switch $cmd { "CMD" { # expected format of data in $cfg(CMDS) and $cfg(OPTS) see create_win() above set data $cfg(CMDS) } "OPT" { # add options for o-saft.tcl itself pack [frame $parent.of] -fill x -padx 5 -anchor w pack [label $parent.of.l -text "Layout format of results:"] \ [radiobutton $parent.of.t$cmd -variable cfg(layout) -value "table" -text "table"] \ [radiobutton $parent.of.s$cmd -variable cfg(layout) -value "text" -text "text"] \ -padx 5 -anchor w -side left create_tip $parent.of [get_tipp "layout"] } } #_dbx "$data"; pack [label $parent.o$cmd -text $txt ] -fill x -padx 5 -anchor w -side top foreach l [split $data "\r\n"] { set txt [string trim $l] if {[regexp $prg(rexOUT-cmd) $txt] == 0} { continue } ;# buttons for Commands and Options only if {[regexp $prg(rexOUT-hide) $txt] != 0} { continue } ;# we do not support these options in the GUI # skipped general if {$txt eq ""} { continue; } if {[regexp $prg(rexOUT-head) $txt]} { continue; }; # header or Warning if {"OPTIONS" eq $txt} { continue; } # remove noicy prefix and make first character upper case set dat [string toupper [string trim [regsub {^(Commands|Options) (to|for)} $txt ""]] 0 0] set name [str2obj $txt] set this $parent.$name _dbx " .$name {$txt}" pack [frame $this] -anchor c -padx 10 -pady 2 pack [button $this.b -text $dat -width 58 -command "create_win .$name {$txt} $cmd" -bg [get_color button] ] \ [button $this.help_me -command "create_help {$txt}" ] \ -side left theme_set $this.help_me $cfg(bstyle) create_tip $this.b [get_tipp settings] # argh, some command sections are missing in HELP, then disable help button if {[regexp $prg(rexOUT-show) $txt] == 1} { $this.help_me config -state disable } } }; # create_buttons proc create_main {targets} { #? create main window (the complete GUI) ## main { global cfg prg myX hosts _dbx "(»$targets«)" set w "" pack [frame $w.ft0]; # create dummy frame to keep create_host() happy ## create command buttons for simple commands and help pack [frame $w.fq] -fill x -side bottom pack [button $w.fq.closeme -command {exit}] -side right -padx $myX(rpad) if {$cfg(VERB)==1} { #pack [button $w.fq.r -text "o" -command "open \"| $argv0\"; exit" ] -side right # TODO: does not work proper 'cause passing --v fails pack [checkbutton $w.fq.img_txt -variable cfg(img_txt) -command { if {$cfg(img_txt)==1} { set cfg(bstyle) "image" } if {$cfg(img_txt)==0} { set cfg(bstyle) "text" } _dbx " toggle: $cfg(img_txt) # $cfg(bstyle) " theme_init $cfg(bstyle) } \ ] -side right if {$cfg(bstyle) eq "image"} { $w.fq.img_txt select } theme_set $w.fq.img_txt $cfg(bstyle) } pack [frame $w.fc] -fill x pack [button $w.fc.cmdstart -command "osaft_exec $w.fc {Start}"] -side left -padx 11 foreach b $prg(Ocmd) { create_cmd $w.fc $b; } pack [button $w.fc.loadresult -command "osaft_load {Load}"] -side left -padx 11 pack [button $w.fc.help -command "create_help {}"] -side right -padx $myX(padx) ## create option buttons for simple access pack [frame $w.fo] -fill x pack [label $w.fo.ol -text " "] -side left -padx 11 foreach b $prg(Oopt) { create_opt $w.fo $b; } if {[regexp {\-docker$} $prg(SAFT)]} { pack [entry $w.fo.dockerid -textvariable prg(docker-id) -width 12] -anchor w create_tip $w.fo.dockerid [get_tipp docker-id] } ## create notebook object and set up Ctrl+Tab traversal set cfg(objN) $w.note ttk::notebook $cfg(objN) -padding 5 ttk::notebook::enableTraversal $cfg(objN) pack $cfg(objN) -fill both -expand 1 ## create TABs: Command and Options set tab_cmds [create_note $cfg(objN) "Commands"] set tab_opts [create_note $cfg(objN) "Options"] set tab_filt [create_note $cfg(objN) "Filter"] create_buttons $tab_cmds {CMD} ;# fill Commands pane create_buttons $tab_opts {OPT} ;# fill Options pane create_filtertab $tab_filt {FIL} ;# fill Filter pane ## add Save and Reset button in Options pane pack [button $tab_opts.saveresult -command {osaft_save "CFG" 0} ] -side left pack [button $tab_opts.reset -command {osaft_reset; osaft_init;}] -side left osaft_init; # initialise options from .-osaft.pl (values shown in Options tab) ## create status line pack [frame $w.fl -relief sunken -borderwidth 1] -fill x pack [text $w.fl.t -relief flat -height 3 -background [get_color status] ] -fill x set cfg(objS) $w.fl.t set_readonly $cfg(objS) ## add hosts from command line foreach host $targets { # display hosts if {$hosts(0) > 5} { puts "**WARNING: only 6 hosts possible; '$host' ignored"; continue }; create_host $w set hosts($hosts(0)) $host } ## add one Host: line with + and ! button create_host $w ## apply themes theme_init $cfg(bstyle) ## main } return }; # create_main proc search_view {w key} { #? scroll given text widget according key _dbx "($w,$key)" # following are automatically handled correctly # Up { $w yview scroll -1 units } # Down { $w yview scroll 1 units } switch $key { Home { $w index 1.0 } Prior { $w yview scroll -1 pages } Next { $w yview scroll 1 pages } End { $w yview end } } # FIXME: Home and End not yet working return }; # search_view proc search_show {w mark} { #? jump to mark in given text widget _dbx "($w,$mark)" catch { $w see [$w index $mark.first] } err if {$err eq ""} { # "see" sometimes places text to far on top, so we scroll up one line $w yview scroll -1 units } else { _dbx " err: $err" } return }; # search_show proc search_mark {w see} { #? remove previous highlight, highlight at position see _dbx "($w,$see)" set anf [lindex $see 0] set end [lindex $see 1] # $see contains tuple with start and end position of matched text, now # find complete surounding paragraph, a paragraph is enclosed in \n\n set box_anf [$w search -backward -regexp {\n\s*\n} $anf] set box_end [$w search -forward -regexp {\n\s*\n} $end] _dbx " box_anf: $box_anf\tanf: $anf\tend: $end\tbox_end: $box_end" $w tag delete HELP-search-box $anf $w tag add HELP-search-box "$box_anf + 2 c" "$box_end + 1 c" $w tag config HELP-search-box -relief raised -borderwidth 1 -background [get_color osaft] $w tag delete HELP-search-mark $anf $w tag add HELP-search-mark $anf $end $w tag config HELP-search-mark -font osaftBold -background yellow return }; # search_mark proc search_more {w search_text regex} { #? show overview of search results in new window # $w is the widget with O-Saft's help text, all matched texts are already # listed in $w's tag HELP-search-pos, each match is a tuple consisting of # start and end position (index) global search myX _dbx "($w,»$search_text«)" set matches [$w tag ranges HELP-search-pos];# get all match positions set cnt [count_tuples $matches] set this [create_window "$cnt matches for: »$regex«" $myX(geoo)] set txt [create_text $this ""].t #{ adjust window, quick&dirty wm title $this "Search Results for: $search_text" destroy $this.f1.saveconfig; # we don't need a save button here $this.f0.help_me config -command {global cfg; create_about; $cfg(winA).t see 60.0} # redifine help button to show About and scroll to Help description #} $txt config -state normal #_dbx " HELP-search-pos ([llength $matches]): $matches" set i 0 while {$i < [llength $matches]} { # Note: $anf and $end are positions in the window of $W # $tag_anf and $tag_end are positions in this window set anf [lindex $matches $i]; incr i; set end [lindex $matches $i]; incr i; # compute surounding lines and insert in new window set box_anf [$w search -backward -regexp {\n\s*\n} $anf] set box_end [$w search -forward -regexp {\n\s*\n} $end] set tag_anf [$txt index end] $txt insert end [$w get $box_anf $box_end] set tag_end [$txt index end] # build tag for extracted text $txt tag add TAG-$i "$tag_anf + 1 char" "$tag_end - 1 char" $txt tag config TAG-$i -relief raised -borderwidth 1 # bind events to highlight text $txt tag bind TAG-$i "$txt tag config TAG-$i -background [get_color osaft]" $txt tag bind TAG-$i "$txt tag config TAG-$i -background white" $txt tag bind TAG-$i "$w see $anf; search_mark $w \"$anf $end\""; create_tip $txt "[get_tipp helpclick]" # TAG-$i are never used again; new searches overwrite existing tags } set_readonly $txt return $this }; # search_more proc search_next {w direction} { #? show next search text in help window # direction: + to search forward, - to search backward global search _dbx "($w,$direction)" _dbx " see: $search(see)" # nextrange, prevrange return a tuple like: 23.32 23.37 # HELP-search-pos contains something like: 2.1 2.7 23.32 23.37 42.23 42.28 switch $direction { {+} { set see [$w tag nextrange HELP-search-pos [lindex $search(see) 1]] } {-} { set see [$w tag prevrange HELP-search-pos [lindex $search(see) 0]] } } if {$see eq ""} { # reached end of range, or range contains only one, switch to beginning set see [lrange [$w tag ranges HELP-search-pos] 0 1]; # get first two from list if {$see eq ""} { return }; # FIXME: round robin for + but not for - } $w see [lindex $see 0]; # show at start of match search_mark $w "$see" #$w yview scroll 1 units; # somtimes necessary, but difficult to decide when set search(see) $see return }; # search_next proc search_text {w search_text} { #? search given text in help window' $w widget global search _dbx "($w,»$search_text«)" if {$search_text eq $search(last)} { search_next $w {+}; return; } # new text to be searched, initialize ... set search(last) $search_text $w tag delete HELP-search-pos; # tag which contains all matches _dbx " mode: $search(mode)" set regex $search_text set words ""; # will be computed below set rmode "-regexp";# mode (switch) for Tcl's "Text search" # prepare regex according smart and fuzzy mode; builds a new regex switch $search(mode) { {smart} { # build pattern with each char optional set i 0 foreach c [lindex [split $regex ""]] { append words "|" [join [lreplace [split $regex ""] $i $i "$c?"] ""] incr i } } {fuzzy} { # some common synonyms, then each char as optional wildcard set regex [regsub -all -nocase {ou} $regex {o}] set regex [regsub -all -nocase {ph} $regex {f}] set regex [regsub -all -nocase {qu} $regex {q}] set regex [regsub -all -nocase {th} $regex {t}] # now build a pattern for each character position set i 0 foreach c [lindex [split $regex ""]] { # only replace well known characters, leave meta as is if {[regexp {[A-Za-z0-9 _#'"$%&/;,-]} $c]} { # "' quotes to balance those in regex (keeps editor happy:) set replace {.?}; switch [string tolower $c] { f { set replace {(?:ph|p|f)?} } o { set replace {(?:ou|o)?} } q { set replace {(?:qu|q)?} } t { set replace {(?:th|t)?} } } # [csz]? and [iy]? and [dt]? is handled by .? append words "|" [join [lreplace [split $regex ""] $i $i $replace] ""] } incr i } } } if {$search(mode) ne {exact}} { # we have the original search_text as first alternate, and various # variants following in a non-capture group # Note: $words has already leading | hence missing in concatenation set regex "(?:$regex$words)"; } _dbx " $search(mode) regex: $regex"; # now handle common mistakes and set mode (switch) for Tcl's "text search" switch $search(mode) { {exact} { # Tcl's "text search" complains when pattern starts with - set regex [regsub {^(-)} $regex {\\\1}]; # leading - is bad set rmode "-exact" } {smart} - {fuzzy} - {regex} { # simply catch compile errors using a similar call as for matching set rmode "-regexp" set err "" catch { $w search -regexp -all -nocase $regex 1.0 } err if {$err ne ""} { _dbx " **ERROR: $err" # most likely regex failed, try to sanatize most common mistakes # leading - is Tcl special, as it will be an option for regex # Note: Tcl is picky about character classes, need \\ inside [] set regex [regsub {^(\\)} $regex {\\\1}]; # leading \ is bad set regex [regsub {^([|*+-])} $regex {[\1]}]; # as leading char is bad set regex [regsub {([|])$} $regex {[\1]}]; # trailing | is bad set regex [regsub {(\\)$} $regex {\\\1}]; # trailing \ is bad } # else { regex OK } } } _dbx " sanatized regex: $regex"; # ready to fire ... set anf [$w search $rmode -all -nocase -count end $regex 1.0] if {$anf eq ""} { return }; # nothing matched # got all matches, tag them set i 0 foreach a $anf { # tag matches; store in HELP-search-pos set e [lindex $end $i]; incr i $w tag add HELP-search-pos $a "$a + $e c" _dbx " HELP-search-pos tag: $a … $a + $e c" } set tags [$w tag ranges HELP-search-pos] _dbx " HELP-search-pos: $tags" set search(see) [lrange $tags 0 1];# remember current position $w tag config HELP-search-pos -background [get_color osaft] search_mark $w $search(see) $w see [lindex $search(see) 0] _dbx " see: $search(see)\tlast: $search(last)" # show window with all search results (note: $anf contains tuples) if {$search(more) < [count_tuples $anf]} { search_more $w $search_text $regex } return }; # search_text proc search_list {direction} { #? get next or previous search text from search list (history) global search _dbx "($direction)" set len [llength $search(list)] switch $direction { {up} { incr search(curr) +1 } {down} { incr search(curr) -1 } } if {$search(curr) < 0} { set search(curr) [expr $len - 1] } if {$search(curr) > [expr $len - 1]} { set search(curr) 0 } set search(text) [lindex $search(list) $search(curr)] _dbx " curr: $search(curr) of $len, »$search(text)«" return }; # search_list proc osaft_write_rc {} { #? print data for resource file # print all lines between RC-ANF and RC-END global cfg argv0 _dbx "()" if [catch { set fid [open $argv0 r]} err] { puts "**ERROR: $err"; exit 2 } # TODO: print docu, see contrib/.o-saft.tcl puts "#!/bin/cat set cfg(RCSID) {1.7}; # initial SID, do not remove package require Tcl 8.5 set cfg(TITLE) {$cfg(TITLE)}" set skip 1 foreach l [split [read $fid] "\r\n"] { if {[regexp {^# RC-ANF} $l]} { set skip 0; continue } if {[regexp {^# RC-END} $l]} { set skip 1; break } if {$skip == 1} { continue } set l [regsub -all {\$0} $l $cfg(ICH)] puts $l } close $fid # print other configurations in simple format, see also cfg_update() global cfg_colors cfg_texts cfg_tips set qq {"} ;# dumm " puts "" puts "array set cfg_color $qq" puts " DESC\t{$cfg_colors(DESC)}" foreach key [lsort [array names cfg_colors]] { if {$key eq "DESC"} { continue } puts " $key\t{$cfg_colors($key)}" } puts "$qq;\n" puts "array set cfg_label $qq" puts " DESC\t{$cfg_texts(DESC)}" foreach key [lsort [array names cfg_texts]] { if {$key eq "DESC"} { continue } puts " $key\t{$cfg_texts($key)}" } puts "$qq;\n" puts "array set cfg_tipp $qq" puts " DESC\t{$cfg_tips(DESC)}" foreach key [lsort [array names cfg_tips]] { if {$key eq "DESC"} { continue } puts " $key\t{$cfg_tips($key)}" } puts "$qq;\n" return }; # osaft_write_rc proc osaft_about {mode} { #? extract description from myself; returns text global arrv argv0 _dbx "($mode)" set fid [open $argv0 r] set txt [read $fid] set hlp "" foreach l [split $txt "\r\n"] { if {![regexp {^#[?.]} $l]} { continue; } if { [regexp {^#\.} $l] && $mode eq {ABOUT}} { continue } if { [regexp {^\s*$} $l]} { continue } set l [regsub -all {\$0} $l $argv0] set hlp "$hlp\n[regsub {^#[?.]} $l {}]" } close $fid return $hlp }; # osaft_about proc osaft_procs {mode} { #? extract procedures and description from myself; returns text # for debugging only; mode: PROC or DESC or FLOW global arrv argv0 _dbx "($mode)" set fid [open $argv0 r] set txt [read $fid] set hlp "" foreach l [split $txt "\r\n"] { if {![regexp {^(proc|\s*#[#?])} $l]} { continue; } if { [regexp {^\s*##} $l] && $mode eq {FLOW}} { set hlp "$hlp\n$l"; } if { [regexp {^\s*#[?]} $l] && $mode eq {DESC}} { set hlp "$hlp\n$l"; } if { [regexp {^proc} $l] && $mode eq {DESC}} { set hlp "$hlp\n$l"; } if { [regexp {^proc} $l] && $mode eq {PROC}} { set hlp "$hlp\n$l"; } } close $fid return $hlp }; # osaft_procs proc osaft_help {} { #? get help from o-saft.pl --help (for use in own help window) global cfg prg _dbx "()" # get information from O-Saft; it's a performance penulty, but simple ;-) _dbx " exec {*}$prg(PERL) $prg(SAFT) [docker_args] +help" set help ""; catch { exec {*}$prg(PERL) $prg(SAFT) [docker_args] +help } help if {5 > [llength [split $help "\n"]]} { # exec call failed, probably because PATH does not contain . then # prg(SAFT) returns an error, most likely just one line, like: # couldn't execute "o-saft.pl": no such file or directory # as this message depends on the lanuguage setting of the calling # shell, we do not check for any specific string, but for more than # one line, means that $help must be more than one line # if it was a problem with docker, following most likely fails too set prg(SAFT) [file join "." $prg(SAFT)];# try current directory also } # FIXME: workaround does not work with --docker _dbx " exec {*}$prg(PERL) $prg(SAFT) [docker_args] --no-rc +help" set help ""; catch { exec {*}$prg(PERL) $prg(SAFT) [docker_args] --no-rc +help } help _dbx " 1. collect more documentations with --help=*" set info "" foreach key [list alias data checks regex rfc glossar] { # missing: text ourstr set txt "" _dbx " 0. $prg(PERL) $prg(SAFT) --no-rc --help=$key" catch { exec {*}$prg(PERL) $prg(SAFT) --no-rc --help=$key } txt if {2 < [llength [split $txt "\n"]]} { set txt [regsub -all {[&]} $txt {\\&}] ;# avoid interpretation by regexp # add section header, hardcoded (stolen from o-saft-man.pm) switch $key { {alias} { set head "Aliases for commands and options" set txt [regsub -all -line {\n} $txt "\n "] } {data} { set head "Available commands for informations" set txt [regsub -all -line {(\n)(\s*)} $txt {\1 \2+}] set txt [regsub {^(\s*)} $txt {\1 +}] ;# pretty print # each key (left) is a command, hence add + } {checks} { set head "Available commands for checks" set txt [regsub -all -line {(\n)(\s*)} $txt {\1 \2+}] set txt [regsub {^(\s*)} $txt {\1 +}] ;# pretty print # each key (left) is a command, hence add + } {regex} { set head "Regular expressions used internally" set txt [regsub -all -line {(\n)(\s*)([^ ]+)} $txt {\1\2'\3'}] } {rfc} { set head "List of RFC related to SSL, TLS" } {glossar} { set head "Glossar" } {text} { set head "Texts used in various messages" } {ourstr} { set head "Regular expressions to match our own strings" } {range} { set head "List of cipherranges" } {compliance} { set head "INFO: Available commands for compliance checks" } {todo} { set head "Known problems and bugs" } } append info "\n\nINFO $head\n$txt" ;# initial TAB for $txt important } } _dbx " 2. merge HELP and additional help texts" set help [regsub {(\n\nATTRIBUTION)} $help "$info\n\nATTRIBUTION"]; set help [regsub -all {===.*?===} $help {}] ;# remove informal messages #dbx " 3. building TOC from section head lines here is difficult, done in create_help()" return $help }; # osaft_help proc osaft_reset {} { #? reset all options in cfg() global cfg _dbx "()" update_status "reset" foreach {idx val} [array get cfg] { if {[regexp {^[^-]} $idx]} { continue };# want options only if {[string trim $val] eq "0"} { continue };# already ok if {[string trim $val] eq "1"} { set cfg($idx]) 0 } else { set cfg($idx]) "" } } }; # osaft_reset proc osaft_init {} { #? set values from .o-saft.pl in cfg() global cfg prg _dbx "()" if {[regexp {\-docker$} $prg(SAFT)]} { return };# skip in docker mode foreach l [split $cfg(.CFG) "\r\n"] { # expected lines look like: # --no-header # --cfg_cmd=bsi=xxx yyy # if {[regexp "^\s*(#|$)" $l]} { continue } ;# skip comments if {[regexp {=} $l]} { regexp $prg(rexOPT-cfg) $l dumm idx val # FIXME: there may be multiple --cfg_cmd=KKK=VVV settings, but # there is only one variable in the GUI, so last one wins set idx [string trim $idx] } else { set idx [string trim $l] set val 1 } _dbx " cfg($idx) = »$val«" set cfg($idx) $val } }; # osaft_init proc _get_table {tbl} { #? return all line from the table, except the hidden ones # lines are formatted like result from O-Saft (roughly, not exactly) set txt "" set n -1 foreach l [$tbl get 0 end] { incr n if {[$tbl rowcget $n -hide]} { continue } set label [lindex $l 1] set value [lindex $l 2] set cmt [lindex $l 3] append txt "$label:\t$value $cmt\n" } return $txt }; # _get_table proc osaft_save {tbl type nr} { #? save selected output to file; $nr used if $type == TAB # type denotes type of data (TAB = tab() or CFG = cfg()); nr denotes entry global cfg prg tab _dbx "($tbl,$type,$nr)" if {$type eq "TTY"} { switch $cfg(layout) { text { puts $tab($nr) } table { puts [_get_table $tbl] } } return; # ready } if {$type eq "TAB"} { set name [tk_getSaveFile {*}$cfg(confirm) -title "$cfg(TITLE): [get_tipp saveresult]" -initialfile "$prg(SAFT)--$nr.log"] if {$name eq ""} { return } set fid [open $name w] switch $cfg(layout) { text { puts $fid $tab($nr) } table { puts $fid [_get_table $tbl] } } } if {$type eq "CFG"} { set name [tk_getSaveFile {*}$cfg(confirm) -title "$cfg(TITLE): [get_tipp saveconfig]" -initialfile ".$prg(SAFT)--new"] if {$name eq ""} { return } set fid [open $name w] foreach {idx val} [array get cfg] { # collect selected options if {[regexp {^[^-]} $idx]} { continue }; # want options only if {[string trim $val] eq "0"} { continue }; if {[string trim $val] eq "1"} { puts $fid "$idx" } else { if {$val ne ""} { puts $fid "$idx=$val" } } } } close $fid update_status "saved to $name" return }; # osaft_save proc osaft_load {cmd} { #? load results from file and create a new TAB for it global cfg tab _dbx "($cmd)" if {$cmd eq "Load"} { set name [tk_getOpenFile -title "$cfg(TITLE): [get_tipp loadresult]"] } else { set name $cmd } if {$name eq ""} { return } update_cursor watch incr cfg(EXEC) set fid [open $name r] set tab($cfg(EXEC)) [read $fid] close $fid set txt [create_tab $cfg(objN) $cmd $tab($cfg(EXEC))] apply_filter $txt $cmd ; # text placed in pane, now do some markup #puts $fid $tab($nr) update_status "loaded file: $name" update_cursor {} return }; # osaft_load proc osaft_exec {parent cmd} { #? run $prg(SAFT) with given command; write result to global $osaft # parent is a dummy here global cfg hosts prg tab _dbx "($cmd)" update_cursor watch update_status "#{ $cmd" set do {}; # must be set to avoid tcl error set opt {}; # .. set targets {}; # .. if {[regexp {\-docker$} $prg(SAFT)]} { # pass image ID to Docker; # note that this option must be before o-saft.pl commands or options lappend do "-id=$prg(docker-id)" lappend do "-tag=$prg(docker-tag)" } if {$cmd eq "Start"} { foreach {idx val} [array get cfg] { # collect selected commands if {[regexp {^[^+]} $idx]} { continue }; # want commands only if {[string trim $val] ne "1"} { continue }; lappend do $idx } } else { lappend do $cmd } foreach {idx val} [array get cfg] { # collect selected options if {[regexp {^[^-]} $idx]} { continue };# want options only set val [string trim $val] if {$val eq "0"} { continue }; # unset # FIXME: cannot use 0 as value --x=0 if {$val eq "1"} { lappend opt $idx; continue }; if {$val ne ""} { lappend opt "$idx=$val"; }; } foreach {i h} [array get hosts] { # collect hosts if {$i==0} { continue }; # first entry is counter if {[string trim $h] eq ""} { continue }; # skip empty entries lappend targets $h } # check for some special docker commands; # TODO: quick&dirty if {$cmd eq "docker_status"} { # o-saft-docker status has no other options set targets {} set opt {} set do "-id=$prg(docker-id)" lappend do "-tag=$prg(docker-tag)" lappend do "status" } if {[regexp {^win(32|64)} [tk windowingsystem]]} { putv "$prg(PERL) $prg(SAFT) {*}$opt {*}$do {*}$targets]" set execcmd [list exec {*}$prg(PERL) $prg(SAFT) {*}$opt {*}$do {*}$targets]; # Tcl >= 8.5 # windows has no proper STDERR etc. } else { set execcmd [list exec 2>@stdout {*}$prg(PERL) $prg(SAFT) {*}$opt {*}$do {*}$targets]; # Tcl >= 8.5 # on some systems (i.e. Mac OS X) buffering of STDOUT and STDERR is not # synchronized, hence we redirect STDERR to STDOUT, which is OK herein, # because no other process can fetch STDERR or STDOUT. # probaly we also need: chan configure stdout -buffering none } # sanatize $execcmd for printing in status line and results TAB # Tcl uses {} to quote strings, which need to be '' for a shell # finally we use $execcmd for execution and $exectxt for print set exectxt $execcmd set exectxt [regsub {^\s*exec\s*.*?stdout\s*} $exectxt {}]; # remove exec .. set exectxt [regsub -all {[\}\{]} $exectxt {'}]; # replace {} update_status "$exectxt" incr cfg(EXEC) set result "" set status 0 if {[catch { {*}$execcmd } result errors]} { # exited abnormaly, get status and sanatize result # dict get $errors --errorcode looks like: CHILDSTATUS 9498 42 # dict get $errors --errorinfo returns same as we have in $results # because STDERR was redirected to STDOUT # Tcl's exec added "child process exited abnormally" to the result _dbx " error: [dict get $errors -errorcode]" set status [lindex [dict get $errors -errorcode] 2] set result [regsub {child process exited abnormally$} $result ""] # more pedantic check: #if {[lindex [dict get $errors -errorcode] 0] eq "CHILDSTATUS"} { # # do something ... #} #else: nothing to do, everything in $result } set tab($cfg(EXEC)) "\n$exectxt\n\n$result\n"; # store result for later use set txt [create_tab $cfg(objN) $cmd $tab($cfg(EXEC))] apply_filter $txt $cmd ; # text placed in pane, now do some markup destroy $cfg(winF); # workaround, see FIXME in create_filtertab update_status "#} $do done (status=$status)."; # status not yet used ... update_cursor {} return }; # osaft_exec #_____________________________________________________________________________ #_____________________________________________________________________ main __| set targets ""; # will later be copied to hosts() foreach arg $argv { switch -glob $arg { {+quit} { set cfg(quit) 1; } {+VERSION} { puts $cfg(VERSION); exit; } {--version} { puts $cfg(mySID); exit; } {-docker} - {--docker} { set prg(SAFT) "o-saft-docker"; } {--dbx} - {--d} { incr cfg(DEBUG); } {--v} { set cfg(VERB) 1; } {--trace} { set cfg(TRACE) 1; } {--rc} { osaft_write_rc; exit; } {--image} - {--img} { set cfg(bstyle) "image";} {--text} { set cfg(bstyle) "text"; } {--tip} { set cfg(TIP) 1; } -id=* { set prg(docker-id) [regsub {^-id=} $arg {}]; } --id=* { set prg(docker-id) [regsub {^--id=} $arg {}]; } -tag=* { set prg(docker-tag) [regsub {^-tag=} $arg {}]; } --tag=* { set prg(docker-tag) [regsub {^--tag=} $arg {}]; } --load=* { lappend cfg(files) [regsub {^--load=} $arg {}]; } --post=* { set prg(post) $arg; } {--h} - {--help} { puts [osaft_about "HELP"]; exit; } {--options__for_debugging__only} { set dumm "" } {--help-o-saft} - {--help-osaft} - {--helposaft} - {--osafthelp} - {--osaft-help} - {--o-saft-help} { set cfg(DEBUG) 99; } {--help-flow} - {--helpflow} { puts [osaft_procs FLOW]; exit; } {--help-descr} - {--helpdescr} { puts [osaft_procs DESC]; exit; } {--help-procs} - {--helpprocs} { puts [osaft_procs PROC]; exit; } * { lappend targets $arg; } default { puts "**WARNING: unknown parameter '$arg'; ignored" } } } if {$cfg(TRACE)> 0} { trace_commands } if {$cfg(VERB) > 0} { lappend prg(Ocmd) {+quit} {+version}; } if {[regexp {\-docker$} $prg(SAFT)]} { lappend prg(Ocmd) {docker_status}; } ## read $cfg(RC) if any # if the file does not exist, the error is silently catched and ignored set rcfile [file join $env(HOME) $cfg(RC)] if {[file isfile $rcfile]} { catch { source $rcfile } error_txt } set rcfile [file join {./} $cfg(RC)] if {[file isfile $rcfile]} { catch { source $rcfile } error_txt } cfg_update; # update configuration as needed ## read $cfg(IMG) # must be read before any widget is created read_images $cfg(bstyle); # more precisely: before first use of theme_set # FIXME: prg(docker-id) is missing here; hence cfg(HELP), cfg(OPTS), cfg(CMDS) # will be empty if O-Saft's default Docker image is not (found) running # workaround: use environment variables, see o-saft-docker set cfg(HELP) [osaft_help] ;# calls also: $prg(SAFT) +help _dbx " exec {*}$prg(PERL) $prg(SAFT) [docker_args] --help=opt" set cfg(OPTS) ""; catch { exec {*}$prg(PERL) $prg(SAFT) [docker_args] --help=opt } cfg(OPTS) _dbx " exec {*}$prg(PERL) $prg(SAFT) [docker_args] --help=commands" set cfg(CMDS) ""; catch { exec {*}$prg(PERL) $prg(SAFT) [docker_args] --help=commands } cfg(CMDS) if {5 > [llength [split $cfg(CMDS) "\n"]]} { # failed, so we have no commands, no options and no help text # checking cfg(CMDS) is sufficient, as without commands nothing can be done tk_messageBox -icon error -title "**ERROR: $prg(SAFT) failed" \ -message "$prg(SAFT) did not return list of commands ---- $cfg(CMDS) ---- " exit 2 } # special debug output if {99==$cfg(DEBUG)} { puts "$cfg(HELP)"; exit; } gui_init ## create toplevel window wm title . $cfg(TITLE) wm iconname . [string tolower $cfg(TITLE)] wm geometry . $myX(geoS) bind . {clipboard get} bind . {clipboard clear ; clipboard append [selection get]} ## create main window, see ## main { .. ## main } create_main $targets ## load files, if any foreach f $cfg(files) { if {![file exists $f]} { continue } osaft_load $f } ## GUI ready, initilize tracing if required if {$cfg(TRACE) > 0} { trace_buttons } ## some verbose output _dbx " hosts: $hosts(0)" set vm ""; # check if inside docker if {[info exist env(osaft_vm_build)]==1} { set vm "($env(osaft_vm_build))" } if {[regexp {\-docker$} $prg(SAFT)]} { set vm "(using $prg(SAFT))" } update_status "o-saft.tcl $cfg(VERSION) $vm" # must be at end when window was created, otherwise wm data is missing or mis-leading if {$cfg(VERB)==1 || $cfg(DEBUG)==1} { if {[info commands console] eq "console"} { console show }; # windows hack # cfg(RCSID) set in RC-file set rc "not found"; if {[info exists cfg(RCSID)]==1} { set rc "found" }; set ini "not found"; if {$cfg(.CFG) ne ""} { set ini "found" }; set tip "not used"; if {$cfg(TIP) == 0 } { set tip "used" }; set geo ""; if {[info exists geometry]==1} { set geo "$geometry" } #.CFG: $cfg(.CFG) # don't print, too much data puts " PRG $argv0 -- $cfg(ICH) | RC: $cfg(RC)\t$rc | O-Saft: $prg(SAFT) | INIT: $prg(INIT)\t$ini | post: $prg(post) ARGS | argv: $argv | targets: $targets | files: $cfg(files) CFG | TITLE: $cfg(TITLE) | debug: $cfg(DEBUG) | trace: $cfg(TRACE) | tooltip: tooltip package\t$tip | bstyle: $cfg(bstyle) | layout: $cfg(layout) | BROWSER: $prg(BROWSER) | PERL: $prg(PERL) | SAFT: $prg(SAFT) TCL version: $::tcl_patchLevel | library: $::tcl_library | platform: $::tcl_platform(platform) | os: $::tcl_platform(os) | osVersion: $::tcl_platform(osVersion) | byteOrder: $::tcl_platform(byteOrder) | wordSize: $::tcl_platform(wordSize) | rcFileName:$::tcl_rcFileName Tk version: $::tk_patchLevel | library: $::tk_library | strictMotif: $::tk_strictMotif WM : [wm frame .] | geometry: [wm geometry .] | maxsize: [wm maxsize .] | focusmodel:[wm focusmodel .] | system: [tk windowingsystem] | clipboard: $myX(buffer) | geometry: $geo TAB tabs: [$cfg(objN) tabs] | _/" # [tk windowingsystem] # we believe this a window manager property } if {$cfg(quit) == 1 } { exit } O-Saft-19.01.19/o-saft.tgz000066400000000000000000112126561342117255600150100ustar00rootroot00000000000000mD\[ksƒg1IO9N2Ȳͺ$[À0xbdo=3P,M3==ݧ3>m]8^_.>Ϟ=vR{_z/=rSi 'dIB|~\⻉tG?G,;c?,dT*GCDs-V?rmqxM&s' Rz o47~D3?i8A)&Q,VQ&K)R"RxΪ)"YH c'dzlAm1lp\W.R1"C)@s,eL~n 3ZAčX Lb\cEEQHp%B)LlCȗ3'N#$%$]:qt{`$]mb,R+Mk?B.b$ x. 2B1;Rs?U֤˄heb3?]5OC"Ot‰S"QB . mМE' h Xϛ@-b ($;#jz~$8Am% ɛ~l]Vwap%,eLm*߰4J$% 0\1㕘e. N+x_%L޵Ra3YMcgɪք\88mj x Dl/* 5}>a8h F/Hl;(rT\»0ZLbr@!mϛ+<DRy@$ YM؈ƏHb/r^@6gLbZ.IJOVI¾ DDk9œ\~#BNs9r ?DfJ:\ >ץ5 Yzזz*wJ6-G2hS¤ɐ<:> ]5_N%ɗ~o;#g)JJ#E̍t"zL8΢0R gP6})G0h{Ů`oAJD?l ;C& {Y(Dr$6Q?>^v{J)95!S3FrɠuR14Dc,| )6Cم\QdhSֈqG[>r~xpܲ$0c[܌Kfu{쒔@s(&گq|0eldCVE6J1[{Ħvԧ!)BŬw&k[efyd?tp<6~;/vĄ#f8YW6& }M_SX25ə%bAT%Q禃%4_nD j80ULiJ#=9+ħ)D\:~Β6{$+H)hzACr2٪Ą6uI:|K&9͍-޲ !fzWyVz𝨾jX!SBϟuEN^Ts/G?_ OOxnvuķ*D RIэP:)NXyRD=@ A͠W.z|e,aMr5˼T?j? ~NWvNJ)H'VzW~2r mβ^TXX.:ߋo~{(}zӼ!Vzѿ̣vg /@n䣍Ŕ*ɵQ{b5lU XjU揄0\!(S./b؍.vH|AHiCxD ܎V T^"r/G<'H{/;?~zbb8Ĝ_TϢ(0jo5sId1Hkwٝ{6ﰘ }X2Z<'/ckJ+жfS墹߶B!e4%M@(vRʔhj\ {bhgD;^v!h?4)S )5|>(|SB5ޫF;+*rJ|jDnհa?7) 7%P[(evVJ?-u=iK*~"_qQqF۪#uGRq:_9ضE ,4])(*h2}JyPUcQn :>Pk!7<0¥%1R;[7P+ /]]LP5&2Eb.u]s'Ԝ..ёUMKPg/R%~e5@hNXQ IwW>W~7$m)6KE*Uo1軁pweJO5z__{_1GoAƱ;9n)W~r1ޡ`y=W{XDwzt}ڈn\lN\UxѺ`^4lR 090vB4?>SZEb#-́|q#y.?EnI&u9=廓z"D.ź y E^ j6cЪQۍ1]mG0j 8O!ߙ nR-$IȘ覈"R%`>i2Gوif3w C`E~rI.ꮦ0Z|JXc_[-y#<7B2?B9 bNTPhɔ~>Y?BtNmhQw7Z=낽Ucl8BV 7ljnx4rA;|Ϩe _#1!4"v'iҎN5$(5J+Sb| UP&|A5KO!5vG|x v!ʫn??S q#yC'Ǘ>CbSny!\*?)TKy,df(M0A꛶'~Mt/kMhƤt52yxGQn|jŠe˦L$)5rWAAĽDQTɜt*'3MVGvWlwU#"LD~g${ Uյ,0p7]uc0c "}nI2cDK@!kǰz&;LtePb;JQSKuTVi!_(3,|#;DtqPW/9o`Qk}|znSGkc*]>TM]lSbL0K37EaGEg.U,]{pz~m9vS9GjMKnUJ?]9Տ:'¶nN~CA2I)t:;jdB# `ĺzzaw2!ec3ER 5"]2[ 3\ǣQx!W 94_';+OJ@Ӹֆw[mޟq$?E8M Y<鐔ݽ-ja2 דn 9Ve kmt2#ȈObLY3o`dAlr H=fFe>`hBT  H;v!d$z?~)HPgDmCm4k&s÷C+CGaLu&1HvF؆ԣ,|WUdXOxsݛ?n-3=X]BqXUیئ,ZW5@,kCt$BC 20H@ ƃflo6ZmNkmyfFm',y gs;xу0xz78JoB~{' qF |\e[-0t-չszHe8'sڥc`m)jW4 /):7-Jhפ >⓱jD?b,6͇TVt᤭tg!Edj~ s]sT`f]?#،%ܫf數2HJڎrHkkU$}4}a)y1êvj >ub@nĵa(OTS0C!踛ʍuŷZ%7Ȅ: A'C N7h@>ҺAM  mF,eC e zk{_Ņ<S/t;/z@k/^\3yzb3=V ^ыV֋v֋~V~8I%5N~t;F|V5L>%ezP/b ,AAk@'I̚!V125-K$nj8ejoth✯!`,Ք:=r"aY!ya_7BB|i!ZZ-;BR[<8]>:ei@lZ\* =Q:25_[ꙌRpV .ew Ǥ[)J!JX*ó$:;q]"tD1b4N]67.5i6y|' ! 鿀M|WPu`QzS4yQA[Fڑ!Ci@ \d&Ϟ&xf_\Hp?〓讏+&dEo9]n.pz۹3 C wOL)PF|rBG9;yN/#oRMވE /IwծڛNCod<.;gc#akn6_=b"Շ*= ǗriO1.FX[0 LUb‚=qnaK8=9xB 0rMI(Y0R;oWX+.gՊܴz֓i 5i~'<Hv6$\O?.IrvI!Ãfz(OI`YDDmBgKr3ߕbsI!a)RW S?k>oh/o`x{{h![^i8JW6>'ۗՏza{ +4opn t}0-o?vn5|a KrцeJ r%hNjpV.i`¸b%q0`?kO_m.jd'HvMye= &9|߶[EQԭHZ8.w|.^1|SF_픱So9O_u'Y =_Ot)N4ݻ lWش@jtG|pќPN !,•̨b4-ArRƓ)UH@/Y~i_[4͕C*LsEi;.ٝ) OJ NRU&SܬlҨg;)*el3]pmIgO jU!irvq> `go?@U9qGSO.N1)/"6g` ?C/C4Hd7C \0 SQ*Cߤ3q4#|_.#YzDROQ?,)Yu%nf  6G*WnvKDkg)\[?RC]ƶ µMvwziK ]_Ѽd>1TVЅ6L`:3t/.,@@/]O{WT8w YBg>vWܡP:h ra1RMjbGnLIbս( JaBKݰtObUǾV9 Wn+wAA~s%b߁RE/HT?MVenh{)WUkET ^گ}Q$hr*_YƆh]\ȣ\K*JT1b5 AQ]*R\UJ7E4 g|NGUb|!UKSɣְA:|Y>  ͆ 6 څ@ЇW[z`-ok =ś-_Y*պFIV++4LGQ.oóYZ^Z9f>}DŚ54^łˊVdπ/жU~9+`mU4=[U>'?4-iej/o\_jƻn|k[,_%ߡ?Q8Ţ*TJRl핽d$+| f_Ϧd8gbwFOOF`6?y&v G3~F_iL1u6-_ HN2Pzcg:^^SJt[~i8a|zhn6ZOU^,dT2g.rla0A.[ igt" :*>2솗,-s랲 Y|Z~C5QḨN/*,LE=TjC,7r /BL\QT7AF^_>t⵬왂Qˍ N,jB${֊8\a};JZw,CVfqW=b/@?^awhKt._*+MbЀeWpKhMW8Яn^7\pĺe#졓 C?`T= ΋iK4Xٍ^xS_ϡzl%$6MjYWe_ɢ{L&.쨬GZOw )$uen~zݗ+*zVi) $&u1i/$x'Fa`|seA‹YZyn [j6_aQ|ɍery7_¢r֝hl|2(Ȏ}S{%^mb;4P`06uu/ZlA:plQ`|c~X@&-r-HЖ!Jм,*]vҘfX뮶`Yh9c(~5_b7`/k5Txrb+&L)Wάuz,PUTggu*17[pn$O>:{ q/TijkhƓ;w~p91UV?ywVLsFqTSi*X ;~@(q(G`0LΘ,k~ k#W2)QjtL{( xOSl(vL5XҤ5\+ 8 k:7W)<8B,/d i\~qZw4_m5ukž;Ϧ_>2I~/I藄KJk%à8aPpԾSTµ R*&B?}1S&5z78@(|Q%ÎQ93t}9 s)B䡜@ BBQT+L6#yݪ-i M=f:foƄJʱł7 +ciqs߬32Y̪2FTWxEƌIpaA6*CaR$|o~7ݮSG71IU%sGQ Ǘ՚[N䂒M 7aE3fPA81\=H9EN8@FDJPLMG> %%F!,q}1~0ItD1`zǓw `z3P r' F&ʃ{\h3+W US{D lw):V.J!|p(7¶ff\&$şqhV6ΤqT¦s6dAґ# .M&sPlʰ8<ȵͫ\,u:i=lT޵b.Z')/[;z1w\10^WKcM>M^VqGkUg󤘔 VmvQ{RwNj01Loz9-N['sh6,itb}-`?uĂ+%A2nDd íNӲq4.RΥH7.Nv\,Qn|f+D +B?>k,&%Y lQ5z[[O\T Uv!PP^8j؉JIX=a\p }l((1 oz&,k~8qߜ2{1Ɏհ E-%Us?TK#-5 5f-|m2f?Ű@:Up՘ /'l</A[_ = O`BP8GnX5q]d9э]~2qB#'φ RoTfkطq,t;x!0C PSl5f8 Ad6Q 6)t2;~Axɕ.gaxůp"O<ɘp@*cH^ncXz0yCSX4A#u㈦*j|YQxjVUT#1օ0N2 f_k\e%_P_VQS,|cq-``üƶ,1CNC"2MQ̴baeD]|smYƜ~cs@x2Fj*9LpB&NTbytP4CRLTn"NIHBa97# Mf'3qt(P*|{R9{~(-,4٭LdleYM.7 3%k/_yRz"s[^r \zɸ2U#fΩ{pz&*ccE$s'ImN~ TB7'"j'oI`1n+;:y$ӱ<􀎽{;PΕ5KA[?ݵ62v9аhm$M'0\w߽;zZYAX|r59[}ci?+*#srX4i4Kʿ|k!#XqP7^jnx y[zvRvz>((]j.+,]UWPtb>'x]0LI=8⋼ iilR<0FSuE~$P9,l݇8kx-QI xv}>N6ߵ 'L:؞>^ ] d++ӳ~| ӌ/[ rQkJbĺ S^,{x(Qԫ0.錒$š]^".dfݽ9 2F]¿Uft9 8[_up/ME^xY.%')Y`=I|C`* _#m hXIfڠp6(tDTd( 6hBiЮ˫Tv j'hX`~L<(F#7RDp@̆Ad e7&*eSlhrC7DHVv`A`Q@pV@=FS)} 4p[ܪFșM㆓ۈdF g"% ē; kx[%b+,2aq3:pWZeu'd7Rب9~JY }9ɝDo<"q٬}`Ǔ nc\1[rtd^Ġ*>iN.L)^+eAyO/i{ơTƭbi~Y:*غud Nz"-oKl v*mtңTBk4:@weCf`FǨϚ,L>d6ǬڏX;$JаU zX-i|E步i,6X-J*sLw[˫6өzv-DN^Y]OXiF=}{h\tJ[7oZɨo@!GL/[r-iLB.~ЙFT8+l%i$lXEfO%6nʴm*L2SʴR*)[LSҩcyixdʑ,|n2SM$4>²yQu2͇m iTf2*M}2-}Ji{ER&ӟM,x 3@^{TKx<!JidI(n._Z`.6j'*^'k=4Jh6 ;aTv0ȷBO`ʧB<<<5Ӝt0BOuA#U.ڠ˝Y^ 9&h2rHρ*Ѕ.rK0E*W)]в{ҼF ~ASr)|S_)#86>Mre|(x;lwO=݌t`TJϜJiR#[.yI9\ZN[y>}B^bnFy[5\GR%ܩKv%ihAglSO)/, S1AJoN(G~.-9+R%S?eYXvfvF6%ueLLlfsƴmfg5m5̨紖,y+3+Ke e5+%v@(sp !ˉ^ͼB RE5XW|WGѢtQFiJ(OwHⷾ2dqudUp$e^ݔ^&ZdOS)\([ Ѕ*IwCI] $/2Jٗ w T({D݀׹ȱ k9ȼ*țV𭧰}u ˯@ɠf&冝V6xyNY'!fBycTt8% R)hcI4S""E!'&kSXH𶂬.4)R@r1drH2iCc聤Kitku4qEyɵ˙y7U,[إrNso>]GfkULv=7Qxۮ&N׳3pmZky^|@UNY9ڎ1i̦MtW 6Oԑ.  QU06,?)e"do+]p.bhӶ:ߙ;ӴQ7~˒X\[K]eIEO*IRZL;\RCKIsh]طc G`b7ZZrMڹ|U"zE$44¢ıC,dLJ d0GNnXnt0:쩛?95 n \)Qr$9Eχ1 <_\ڼbW_|a4;xYu+ȗeOҥN%])X+ 0`&RBNծ6gOhDCwFȺH F*w\ؕҳY*QlZ1ETkrL-{&$ubx{$ )g'C{WӸn@xUMV428db{ ҰUXm̴b&2xɚ.C÷U4.\D6fpRUM/Iᯂ*t|I\{W):b 6Vlp ,# 1 c91+)ܚ^FV~ATI@~^DaI=Ai?e@ll3eS.h`ÇY]>rm*N0F go7(:VkbS_s$"${2ˢJq 5 @>5$38:i*}~&(<O:BQ4D ̃;8@F/!?ۇ E.-Ƌ-q c% [G06~%`l~tsa~t0ڲ/WPe"8\+,KnF1cq#Yf0Tk 3CGn-s& )dقw?nh; Y7OEKuV V`Kܲ L p7bs\d`M ,ʑ*+ȬJfUVl?` p7\kMOLT-$r<7*E[!r_q_kLJ7UyPM;ϣ#=$1ͰNtO}D#7U7ʍPsƓmjݍ& '2$rU56U WWF2ю2cxAᓋn6բ$rp(#MUMYfEuF dɰq٨aM6kY+@LfuN,#ѮMrvfwEN؏tvɠ@ g5 lT]|kG&oI֒ sHQf1ĥM9@+cRP#v!$v I$6]Fae6bށ?;$H$k b+7Ö4:J*pVX@抖Al&ݡZHY_id@"b޸XR([{WO 3%+J/ŻOe+뗪<>x:dj< ;WvD-i*ش7QD -YC Ƌ`.#mڎwL9t?"j0"= Eއpǒ>ms?AQ_iI03^Pc_Ɣe ńusJi0E#7T@k,2G&NS7L5ݯ5I;ւKΪ!҄ S+G?2 Jk,jion7 XOUB{%Ր7ġϫ_FC?S֦Жg'KTn!9/>:kɸM@ ߁VTdYѪp^|$IK7okcl"AQ8 /{x v%;d\E#8ܚC+6T@0H]aXwe0c x2U&\է% µ YŹof:/>>~qrpp]G!atJU#3@f2sVDzkY5 ױ٫wG*.kbnޏrv}\8{<MhK7EDJ O9e)e"14tj2[:( E(h*yop&qu~ { oѵ 5I-џ ^\>ubLU% Šcz>BF*Q&H H C" e1wtJus<U7H2^U(uT_S2nM#[mn 4={QcS2@B~ 9Uu(g#QSs9D]!N!AB .-! 4PA0dΞBM%R?|0RCUJPDDU$ΐly,b.-w?Q\ M|剥rII0%A#ϛ q'k;`Bl0 *e[2^OU{ ,gA956YDbBMF[ 9yԧՂ龂LhAȮ{Z?|qaA@pzt:! [bO7o{tፄxޡ( =rf_skT 9p)пHY>v`!ϥxXo8fI b~P&&m7 𜒵2 T1]0$ߊUD~MTNL$.X4f]hCbK&|T[k?t;}8+`~qn_l1Y&=Aa$PMѱgc)K&p^y͂7 2慝MHxGv/lR紶AkNޚ2z10^au lbl r)*Wl$KC+Fr:r$i-1:9ENz$)[n6rauu_zK;jTs!a/Hmڭ6',@I!a|Q`fƜSH͙MJ&^aS6 !({~MxZZv}^V%a{h(zIsW?8񚻓xm߇;v 0_G +\29jVoa0GvsJh48 Ş|oN,~I12Q >+ ᝰ R#= d>.=; =; ۜY!$&0˂שMn}ltON?l{);lִWZp i_mqR wl*˥`gωKW[\]pqOK ޺@a j}- [. ;wN)/6+p⸰!*|X-_-|X[RHm 8[&beIJ9`aiB,+;M+^`}ݣT́(~^U|^fo b6fbV@D7l|a ()0/o@oNI]Og5Xa 5U dɆQ`3W5BvJoXdJ Z!X|e~ƓJzTL9FE |crH!~!̵rpFfpN v#H왜Rl,띢ZQ5H7]GYXԺZCհ Yd҆%^؆9"!dU v`0sʀ{6$]KͤQ^isoaAXpD.+y˅gӿ+QK 1+ {- Z, &qPϏdVW~íd \f-WXfhaj[m{݃0lak|X[͚0/IJ5[v)v؏J^Bir؞~x~;|jΙeZYX*Y1ٌ[V/]%˟Ã7ׯ|wkTLfr)Mez-i3",0=r^ۓd0oG1y.l=t(2,ov?;=k7:~ٕxy'~EW٢2`n& $fl {&a·-1Ʌ0wy(hd3F6$ d Qm\+D4I%j4~A~?[p"imr co;{dI!g#1om`8I[M ˛ՄÜfSŔ4l-65bX?8M g5Ed6_QVPA7.$P/gdnW=|&ݑr/|(a3,]˃-RsMdZlf5֣ -7KEJ7iFMe5akOe TM6Nu2dkɾ&z_f}(ƒ}(}25;K6jTKHjۗ47]/We޾M\/We73x+Zq|~b˄Ly. DOFm&g*zT8Np%af jfdhFX}4$7h2+d4#Ha+7hh0]ΈQad֒rז?_9.qYm=x\JGq6ՒV@0:oO u'0 TTal󷢚qhpͤRW`T*oVm2t4(<~oc; 9-D?HGJqw?r^;lUb Жҕ۲L/&Ɖ3f/TR=˘3ͤ63L9A_3YMr_Y"<׼f2GMF2ՌLd/1uͤF$T>c4̛Jyh aZxs%܉lj IP&v}7h&bG&?ȠDhN"`ѨfOFf|欞f(t6;Gf, =lmdgm#7MB[|hqt\e4yT.e))2eh&o)64pվ6*kY |ifxIMf&ѬhnF_s-s^+]c|ٙcΖAa ۊKZ9z#8c8Eǒpiey+yKںikƲn¬.]͋a07ժ TZuVi+FW9 $E},::cO\Ah%{((JrVKf+9j=d]27j[)] c^lXjO<+s[Y[p1,#TN3B<TDiAe\\ neTΘVTF+6{|KZ֘5cY7E,>JuY7F3-FV QFQ⼁?ddK6^},VHl+%g;qrڠ7)lty\ܷTf+8YY<<jt {h<_h1j\N&P:'#f=(l )aM™~0-6a# d.Аð,i56DdղpNBnXSQ}wt4br!5^9CQMWû ,qͯ:pwbQ_wB4W|d6u/"$ʟGOh<>ho4{T{Ԫ=jyiWvڦ?}Yp2!,?Ke^ЧNYKC] :\ /4MfZ-uJ5| ܄X p(@\E(;p1p^DCB5J!yĔ< dezhMg?:C_aDn8\'z~?a8gBY_Ob:!dŸ?`p6I&]?KNN˩^@gs`+IbDA~83+[_-F&{\t%et '; "H7yй@[=xFX6^`D="]^F;bRH /pîv `6a#Y:vpNS"|z~  3L<׽8GN팞v7r$'e8歌uW<^FIV Pbݓ7ݷgщ  N}MܞjX520 9T?Q0+[5|;YiM#9sn 4lggG&{{S,3 X$`{[5 |qvcGq94$Քܯpep6s*iઇl+t0u͢)]GaD;QYx8sdPu#›v=idWchxˠ G9|u {R_M-  CYK|Rei@<)O#`ewx`CqÏǓ&1Q-9\bhQy6Nk}NnxZ.Ђf, _kƭ-ZAD΀b~ R2-~bKĘ`ByL &U$Exݷ/^wbiGǧ\$r ޾]vO_/ xvƾݙ} i $D̒RݱPnr ߅5pAC3%!8Asǁ{Gt>m :$>x2 `8KdUBoLu>b10po!5,,@pm􉔶BjN`䷱Yb2}=ȅOy0d>^g58J}`+VPYDTԡ$x5^'g.{rb,F `C# QૠhC@sD0e9P5D .Rb1 #~4;l`oRBGRWW%b6g fjQJk1w@<#@R0@G.y󻆚wG: &&g}/n$9G]Ă i>Et͎1 @.uíۢdlr36j :9I.apx]/GE-ݯoȳd^XpO޽&WU<8ۜԚ}8~gO{#p!/{1BBYVp#D ]+xa ίFv]FE] K4,x!8%J#ݩv: 5 էT,`hX= .g!D9,(E nH5P x sC{՛Òk_edD߸/3ɔ~25<lDl@ ?kOuuy , frZ1dD%{/ ݛGO\S. ΨTr;m@r߰kCi[7Gphx hH#{S;F$Dy,h2:l.`zqpdX Xg,PKA@/{±fNrqOR좏4Rx;2`Hlh;`'`2twedЀ؎aỿ_5a<%x|h4$[S2DddwC܂ -8H>آ!@ǜdܘ%&}?|3W60vD ^y;_bh^ hGĀx o0P3 8>x' l r-fu־dg2M l2&x { R%Md>[X~hVѡx0(gX3&xiڀ78@rzpݷ|.>~EJI>jZRrPn_Ua8\O1O]O yW'+IP`Ɏ#6!q{pa!lSZ>^f3.wS:|\]^gRxD]ж|zϐU$Y{Հe~0Q,^^ѹԻ糜Y,XpY);UZOd5*d&?k".漄,E!I#L២\vU*clwetN'x`v:og{<$X.rG<BN]T;x.fs2(OZD" 3g" $@h +kshKֹ@`cwbp=9yw%ͭA-1B ˔(:а\ -7$ሃ=|m+cdF}ӄ( $EAc+:GA]^\Yae@N5ECIOؚgƶsg^+SF0s⸗+okGoOeW-Tvy)ÒRHW< -Ǧy}=9`pϠk,.g|)ɟvG| ˆ*@))}䜨=lY LS3f, bEZNa_wzʁX^\E}z,3ܕM6*x)׉6!p8;ok8noRX쾪+@oMW!le0bt'7Â?B.6-U5MMLbe8,c\tlFJ,wĊwGSHX)"&t 8Z]XVڊ yً`w=SZi=ӭqwOO`'~=άI/?DTN39@\ \z-LxPc:Zz6ի0L`,5MdK,UҚ3  pᛣ GF㱩(0)? B.,GSNRn56Z.(4EP]|"M3fXeӡą(PCEE,l* w x肯᭞'j4gbY2q5,4Re8$ !-^)bI2Dj̬hD:*ei MJVRE)Z"bjUbiQ0%(k yށ kqՈBuZN#6ԨaBV^RgbT]CC8!CId~t~鞜{+XE +ThC!xrrdX ֓|Cskf!(+/8dsn? hչ$ɘv[K-TG"R:{aT~p`(=&iLfGa5^* > nfpnGLҔ]O,# fDB~Sw{i:A&ZArjH,D%aFmcKRim$/PSe32.mVl+6u$(5sTIhy1Ђބ{brJLR}vs"{zJHOڀP`DKveb}gN-%Ab$WIIBM 8]Ε͑3$ gO Kj i c:GZ9AqCtWTQgkU7GO.GڲALoqаx԰ۣJ$yL?L?f\'f #Kt> |l5S|]84+uA^Ca+m(IE]6e"G2|㣫FN=A8kXcu)bLjʪ [\$z ס=:mfJ ӌXv0q5&I ` AD&bL1cvtXB)9CFfȿ }0qA@h^rn[; .Gl'p.N"pr׏oۅ|i!_v p-o߸!w0",Ɔ$Uz#G Bݔ-:1_̮X_ulfn_GLʐ-Yz.@ycc[$o iG B]&N0 6o/:cTo!zK/H> bKx d mC|%I=- 5Ydd$+gmHD*&4rhKx,ƒho l|^s`1ԥ}~dGND8AvlRI4;Q5plm5}K)`w Yi5mDoNv'EĹR˓sՑ=\khsP&6w{9R*}`ɷI\V.r6K&61&r,)Tjd7kBz &td NQȚPuoPBkߤY|2cb=iلŕnQ%L)eT>tMm9JJL],%Vɺw87H%¯i$՟ao;]ڕB鬄}ʳgl$Flf/NSPBvZ`$Jcbw9i)-j6f h&HOyk cV"n-aۍ ŲcHb>Ni9[ "Wò*;ekXRp-]\-Ϻԇg0q3_ty'skBp~f/A5h=(;]CMXdV(o b⤔2b>xrz(%V/_:[X}0[ ߎFڣHQnJ"SK~- # &7VRwO<;w<֓=ނJ C şhO a? ]$20,(1LQj#M"'=ϽcJ ہX]b)o4VQ,) :^FK &gY7R?gQ`a*ǩɻD6b?As=x鈒hM1^cP>EZ鳳q޼ڢJa@ iB9:rY_A[6ddCDAwGƮOq6gcrㆪ̛~TH^S1OUrak x.{ -՜&\Ӟ́KSڱ^Xqc%?_,f4ʼn Yx2MYă|o=׭s;h*FExfPJ%dX 7ʍDh9J^4"-͆8#6<Ӝ4Q; 0th/!GZeO/Ph2(;N4v<," yH@1=BgF{/v)ilׇwU0|1#d`Dha?ENjDK"i+STҬh5[-RRtlwe} ]E#yHu/֑n/z(26% e#pEn0p@K )T LR 2H栂 rP#-Ѱ)L4 3uZl H̡G?} @8pB3zhe㞃*>7hbXFQPaouطDjȍ#h.S`!PuRCWU}s8RFX˨"Rbk7a|kj2Ehp$- \u{Ci {IZl/lPrxk|EsgWK,® )l,LOG@1.A5'2Ch^r9 :9>8Y. /SL >Ks~ ?iwU!<8*~pX\ήxeeG ]>1%Ac-?((X5VBR 0F/U=Rn~hFQHS)8 \V}HJ#ȸYԲ2zSZJN]\8jBOjSEL%WGIuP=ƶĉuE!.>=Dsġ>v>$( P=8SrW k1h.^yA1GG)\ɾr.3y"X$΂QVvf'L)2j|ъ Z/''[߲ YAf;EwptɣP*=If6_vē0H}b'nDI0 y?5SIL^HX("nb^L Xy?*;fM4~  joosXj=՟S')}[MDx"K(m눴 8K8X~|1Qq4OT<4".:X:8&?@flE"V۰QfĢLtK&^h^:ߖT\ eVoV{eqIӄÊf= !_}Ƴ"YTX c71h bpDTGqF}N\o>I2wI6HwܩbНpc-n+/*FlWS3vg%,681sB#<:vsgpr.]G.+wuKɺjѩ`k.9/V2^TF_Fa (,>( &9FK[Tnpnv뒹gC%[io#PskBS:?,R]VG, )TU ZmUNN6S*ɝZԵaae)rL{gI4@-?42*LyBY ZXÎ{FCxTs7Dl렰*vvi2@;"x}]W6( Pu=#,AˑzM# ㏲gd'eQ緢DS KIN(\3Qd^e;\0U) qWJA{T/Q !>BM#0!UY1%K+ E4TqF5׺J2 a!EeůfQ&FE܍mGrC'{ [ZSî("8[D&dmbIla g~k"-Q&֔QqCfX ƻUbT@Ȉw=6FIAJNdFF7vls)%+8%[RCUIlkGef(y0_$<7:Mf)9 H}}~T'QV;X"ےQc74>}/Qj~9K;(CB5GoEY.QpRl~P=T:$ R1Mg!@ iH~yç6C, -`# ӇDŽp*`lN)%s! \\`-#Rce!e# tacLӘyR%~qp2 'ܱ?! ƭ!z<ʉ@Y36Tq1Q/e4&9M:L6:г)clNp(~ $).p78aN+K$Ǒ$daa&d*tl<پF)&E0OBȀGǥ S-=j M KA H۾S*}ȣ9݂F:11@9ҎϘ!_9gs.01NAWms!AIlVxpsHy,t _e/`IX_>hbrFj,3Xc糦;TX"m{˄V]VϳA6񷲨Xuٳ*h,WSmlmg */xyK@"YnԴW"AyٸI`LN8g\$vU6a4]#hzb0zr/eW@A}P b%Frv! Bvl.y,?Rq(ReхpČlte HINGij)G *8~1eֲ 6!-4>єycopX,Ӳ.]є% .#Ѹ~2\x)'IC|RtʞqV-`X; `vZ}eo-<ڟPGEeȄFF)rC&Ŭ T qo|4cjN2r& >ek%뵨^nQJ(fW.Q)h1ʪtjR%4=lg'+rntkk]o U_ooG*$QsP i>[׈(7AUrD.s'ǒE?cw-L@3Pb A|/%Pz(QV6Elh23}TÆCsxg)LUiarn4D@ 8&;DqGe^E-s%y3Lk"@ITD:6aw}ۋ6D}Y.Y&220"ْt:'퐯F~ ?v|}@3u1TX%8tdK0_%<{*t]0|ߓA0u8{ ބ`bh]Mjc@ND|8{Yߩk4p~!Iũp=<~M b޻lsTRf 'ɤFܬ:;*y bN>H84xXQE8=Q)W1* Q& 4 nDtdOb;p4w$r,#s9TYK`ߩ+ogFBxcx_\G͑L,l~Vv2cJ=DZYs3;'h:k`\ Fh|d ͢j9#HL[ yI~*FJ9*͎g?™<0E 0#ņyUyҥz۾]/qRS* {ORxK&]0˗OO?|dc'%X!3uXmܣLb/X׿O,ArD|IrP(Zl)Mj{4kw`&Ҥ=';Y5^cG"s eds/JSNn2eF+EpPD{a5ɠr5.4XP5U=G5'F$YhxNRF7Gdj >.V'Ǭ ʭ\&M0=|j]bO?jETNjx .ľ£ قez4@iM8?M:NY|byRFhotG 27׉ AҕM@n/C. \*>H|Fk52:Zdo$HvN܋ҝr׮kPvJ\1Ztt6SQYi ]+-t4ǵl%K=9$mNbܣ@u@yTYb`ִ23H؀ZJ#+5˳)iqJGu$yv SQO{dB_H^:`)hv#K65RZ5\R"{Cs{- %po;J9H! {0MX''vkiQ\̛ B$IU)ΤBOÇ#M7h&*d礭WZHY"(!nC 5ˮBv)cPYlNR0+C9=|wM(/fZk'61‹v?-Nb5#O?Gοt՛Upc[off}37s&o~/Ha~;w@,:c,/*[\QUj׺ 2-q$nKx&H,g@RM1LFTLK6L‘ͅI{cT8E8Sҥ =e0inh-]ƙ7WTŽO޻j/YPGK>PiĉO&')nd7>΃fMb:{zvgjc:L . mǾBޘ j"и+ǣuBw#D,MI{HM&H7@z ?MÊ:$kͩպuΚhUˡfhumXrvww;JcXJb80֒&%s9&nݎzrh{Ak{wr{EEnwsa_>]pY`^|s[OOnp%"% Φ Ңߍe0E{6;H3|E`?G9=ۆ4mdxmnżDBP~}OjbYRt7s?2 k>ӽbawۘMћ< YFpFN{hooonoml7OmO5`LlG'9X'ϬÏ̃y(b:Ꞗq |V=O2z6gMbD/yqݪ4E_O.񑠢GGͣ͗΋NkݜO^uulQuyxb{{x E :&h4v7vs󛳼M:0gRA+=wfj6w^l46w7v;/Um67 Vjn6w~yytŋ`^v_|y6Ӄͣ֋NA0[͍. b࠻:l6[t{n8xyyr#cF}b|im<}q><~<(8Í-k6_^|x=i S`AçݭFnbm0mOۛۀfâ$ez}q9>mlo=Eh:,fȃ-إ noo4͗ˣͧn k9ɏ~Q %@r?-!1f&A&z.Vf;d7L[)'Y qCF&`T Kˣ( ~*}ؘI ;Ƌ&0s/^nlha)^ll|ڃĈf{{N-;ĈQ +mO?E|2KA(oEį%KH)XPx%!T5F1xjT &тA^*d/WNᾹiػR{$*aB9iú  } 2<1a~y8mn6 \_tmo?L9Vjηݧpt0];0׻ھܟOw6Zv :a9 kٸ2ھ# = g4xCQsVkz8i'x_CiZ~m?pfxh\8/R1BϣW |niN #1dG]eq¦nm,9qq0Bf96Nh-e =GL- 8 ~ʄodLAH"kLpiDXf^q?|fgg} ml*181lł>>xKq겡haO~&x| njʘgO|c40G\o)FuG L3E&%6h%#a 煱xpq\6rO`8·a Sq&.yӑС 46ѥ`%SԅSfp8eh/M(6s> L&+-Yf%3Yr6l֡:8|s.YƎ DR dܤ[VnP1_ףK4f){֯81k V sYKY"z]G{Y v*B]s QS}ltIbY GM>?"3ɛv91FYcHz Y^* !)wX¡$C!p+a{K a`9ׅf|Ņӎ+9Ur$R>0' N,(kQI?uRx Jq(~1~*+֛J ayNHP@FGE|F"8o^ *}CGP9ųdx D{EG9Cz JI*(`u\!݄OSdb_2Qf8G'!='I>T_ֹ\YF"adTR ,,0 09XBf:c *Wfլ@\@aέ Ij*5 /*yا< ~U ~ f)*v|p>TlH~j^@&|$=Tɥ+BMFцgJV5@@ IY8f\STdCAҨXwk_q'E>lYyªɁ@(߅q8x"*q\-y.[OF< c^ {pz& jIiZgPw` lX҇qŔ{@x֣*G-eD tX$O gI5MC뻵5A,)yYdm(]sZ&Ft=p|One S sL՟eu(Cbkއ L}#P@]q^`x2S06n)kBq>Da쫅Mal/W(%S8Xr<17ku::O :Ԍc0g *aІ3c0,,vDaS20Q4G%ge-nG\ rn593P.(;sUJ 1'j<  ~uW"j! dBZFbqz2_8mM.%J[!m,#rc u\cxO%yA:r3~%κhHLr(0_z ` k~ bo1,ߊJHNeRQd #Dü[٭]g['/UF|fBe~J588ش==EZlV(adP 7-^ 87`mW-;jA }='Hbl󺦍H]FOnoV5y~>xIφj:ītiiI:[]`Բ4VFcz\Va82E̽(%j&PGoq 3c/_T*B=ԟR⻘GBGjV ۍ0 r4n7%VO. $:K/ø|_dt6EV]+1ډ[ >J`;Y8`0V"bœ),q(Й]‘7ڭ<XqI0BT UmDޞLE/S,Hkr1l~r[(sZ8ww:g)<0Src9ƻp 3g4wN!*7Ʋ[rk# /`rHy"҉;NtH=x"QH) /Ӂ> VQlT:{ cÀc$ˍƿb@E4nLf08LҘ5^G-ySqV]}Z*RSAB45b"[b)vb\ӆwm` ݧ+.F@PL(u!>wb \Xɣ#ۢM /pu ԵcWyJU.զ;+s,l  bשHmBjn݀RW7+vfH7MnSAMU^8Wo[Zl=9M&uq!oR95yZ]ƦCmr6/lqi͎읁")wΩȝ|j x[NEMیy 5/Tubʤ d?LqШDj<|,ڻ㟑d,H4JCψ04 Lr SdUJͲ C[3WüTq4)Y>J$DѳdJG3J^/4,5e4r"j*:k%ژ_l5 Qɬj4,-%+Bgʭ=]BQ[;x◖DTI߃%vx+%j1hq0#hPsxP[m|qOX#-9gu~`#YIR+Gc?Qj@%8^_5)d7D%cЄ@ V1%PaҩF@6J/º}XUZNώ''QQl/]*l^+1IO>3?{w|Goox$5?JkG;] QD .K 87,S,<l@;/]h2N.I(q@i~īϰ*+Je3)8`Ɇ|L7kIK=1Q[?P y)mk#8j ?h S[׭ңv~YF\ v6) cDVwCɐ@l6(ʭ/"xPJ8FUHv~h9vֆis o] p s% WW|8ظ (؂]IA({C7Q ⤑-Ǣ KY Xbc(unQcXm)ueHJ@`1E s6Y\;鈕/FlRSQLԲ )HێȤt( KjI򯓧4l/)7 2W&2] ?W&ewR?q?EөLpܕvYQtyE; y]kZ_@hx9L1# ln< $/dgp߬Yl6 :GTPOE$,x^׬eBqJd2]R.m>!0uW;T+1Vmխrk2R/bySpRV,op&8ZH-=^i a<<`l_ aS(g1߲ l0!. yLA* qhMX;2h}rS.Ds" ,RgnLO2 9zP gLI\SXpʓ0>K2Z8͔N$g!wY\@4-`|: |e Ucmzq$̬"vc=3mSY<*f:+NjG@Zo* NeזsM>&4ҡnG:y4^eƗ%C+ϛCCo/:x8l헬٘r ~0WjEdy TÝvl`8Gq03Q.h&3=%Iwz!;㏇o;Ϟ)p2=]Y"a4g"';ؒ$ w0ǰ$xOe^Ϧk?>^g*XAw7@C "h?n`h|8H/̗MW Dv-xXE P4;jc<;}{Pc#2c%z؆M&V E$r"^'h0Ajnڕ;Iq i5ԯ,a>p-ȶ Q8 h gZEcѰXaZt# jt:u[dоpY|>hoF=$+8R9 d̵J7 )||ft@z8.RIΡ: u81 ŐlS*' D쮆wB7nNO%wO RWdkZ @4vb1ԛn&4*f)UlOy^࠹ 8tB_JGJfP~м?- Km t\. #։\MG7Jcׯ; o@_{OuF ^0_'/{mߨ{0twriEa!RKf 8U Spoj|$Md}6KimY~[Iihm%OզΌDCڏD!3IE[ _B6* .X )[Whk,Rsܱ"-Th1>=R瓙4DM"pf¢ٌY,p$UurXf,V1I1)bQ*G'C IHX_iju8f:r|[ֹۯ1QvnfTʟ;mf/\[<ńɑ`ǖWbJ-ف-zih/>PokwA^0ث"SyT&PpIho<YW|G~*%uJwt-Z0sBLTε I,7^ KorxuXj6:Dw:|c9bܶLyJSF~nds/Φk`uz|!\qbJdVN RO0͔"›|sHaSǢaSq;7-Tb68]G~6+x=28K,B&h9"})"d*YUƏ]vMu$BTDZ>эk}=tWCao|jb KOi@2@ԹVF F2?,e?ds+iZShK|ruCޢk֤Ǖ_?kFKS ھnJbR=hўⷛ;5wRMhomY>?i)Гڊj?o*1H1O-=knCAE;)bx'ڞ1) 6ٿ>c4{Kx2Sx0 Hx&Z@k2 xrr%oAV2XG9]iVW_xjUtjT7І>~<2@ Nx6v1A nb^!/ʭq`١̴kp:{y/'=@?C6 䗕*7woԅV}&a_Ya 緽YHԦ卍[oAl5F4)Ag:[3Ii%߄9"{.ﵡ)|L% IV5' Wz2X 2RZo a'}O/h>*J>DW7!қL_$nC.@V\l| .S ҂UuDo$}66h 4^a`2Lɜ%]_,(ٽKʼLҾx(SzUd] ˪&ǘvJ5݊rkZo;~+Y]oЌƚT; (x/ >{z] 0j 0< ^>Bs:{Bcg0u8T( TYrldFxO? h;ܽqf;va|n!Kczr|y8;c yi=}D骽. F#~QR=|jzsw=ٰfpimoNGiMxehmvmNj_K`s4|TkȡҟEϛIxJ{w:@ѯh~HFط'2]}wjo椤GȢ既CT3 SMp\Iq-xę)>0[eYc (3& E~ QCV q0 I2rvr{#Ԉ`w&D 7Bl1Ii::Gl_'jKRFO13D#1 3blAϤzj A@GT-~mB XԬ(с~ci*g}Amv^08}4 NM+*[ts /h[w]l 6 3T3ᮛ?4wQ„b;+5OxAORHSh[U@ߟeE A#J9%VJqrUljij˳~iO0}MX@Ȉ}%EF=UB 3{z-XF9 .&¦8*hmcR}i?q/R1"Yn*@Wb&_~sN^_lڕ\o5U b^Gnb:m p %~fWL AtCQZ%:ZF䘗].GŸ)i3k+HXU 5*jh*1TkҿZdAhOL}$#-VSxg,WTV$bdvZX9 #H09#5eSFG2B@zc0w7G?iyMf8v aANZt&dQbK]I@{zvWP5[[8IӇb<#*b<y!H|kZg3q ,~^&/u(׈B+Kj@`模)Q́@xaI}B A UDf@֤kr%1!@^8 CùS,e/;:bJa܋hfICWKAuc:[ӉC[npq@mTMH+ECpٱq[$ b>!bu[h$+䐙x@L;:ufVwUS6+5|zjW]5 ?l 32\ܤ|\ȽSpR ޲ʀ0}j 5Vk<6K@A$hQH1n/rٷD5)"HJtP|4I5!37lrl* ROg dzjrBMhbûg(~aHKD9u"(a77w61IS*P*G}h,CC7\~i=yCַEzɌSE4T;LTf{EtTX ҝצr< éZM4Di L{v74/MW?ruuc4Uڕ*8E}n좃S ğd|) ZCC3 9eDdq*xoפ ([H6QOpO =,SI+gAmZXS%OS}Oonf\7P9S~/(U[˛98p>O{;!o S8'chlBfH؜-)WjJYK:Օ gBO6bt`et2MlE*H೛Z<`eDk !\uP$#/^C^b. :z(W+*IâA9I@PG$&@^Wp6  c : '2t_elM}DX/Ei%BcNv|=@':'m];Ӹf1+ v44,0/FbTKst%%zzIH'6ET|]xN٥,g'V>|sTFp)W__ Y.NMR6h% &pL+{f: { C~(ִNb-ԮwGJ 6^Nѝ4!̢KuN`RQ'<,I-b`kb/Yi3vHb&_umAèh#:LJ`rzthtzL<aOnpifBl0!#S>"y%|Es?~;Ð"9|&-px\5 GNˊ;COM(V>[&Yb 0 kV㶚VRWIFMv/jBά/f26"K* H~2v* qbMȏGI8㨡g,7fp*ދje?޿;9@hVSY-حy0 gY"˹VS$d9dKL4`I1ʨx{wMG3+7d誷j;(PܱKgm'w[na#’qRU&Hsl80|?|<ǰG(TOkz2vMc!x_j'fMkFl,$4O8jBiaf5#;ib g&H(~' gl3}j/G5݃qfNlc }mÓ\'83ntk;DALɎ`XVu^ṞPF|6r]"qfF94'kx.QE<z6 |,ZX̆'sxWN^s%ŀQEK>װ0 ))[eHZd`|nŌ2$M)0+$ӋipA0z C%Y,)E2ƞ{pr\Kp8Ͽϧ| gTS4'툂C<;n-NXhFVvް4+emEukSM@puXBp&֧<5zzTo~B.桝py V9E)oOimHML;j6r!L?Er6?i=u;O cedlг[3@Y%C8W0w_(84ټc1ƝM/llZQԟMŜd6h~ssS˭͍Bcu:Vߍ8=0< y bwshn:= fUİV)b Sq0[Lwڛm[dq8p[[KDžc'{}qz@ڨwǿN/OJjK=G*l g68sr`i_IHフ<.W&r9sx[z?&WGo͖BTè?L* AձTݺ MkN"F>l.ghjH2ŲRc|`&lGTb V 2L"_<`lFe8y|}?V)Hz@Oƪm2g=~eW3Y50f^5-SȔԴ%ȰJaɱ1дW&y[Vm|m-I=;s|gNߤ-OW9a/SN呢h3拸&~IՊ4PNĩ= R6dZ+L!Ȫ{<=;8pQ2$a3)Aď,w~k76'ܠ?_ͪp(G屌,K>` Rn a7ZzѩWRcwǂ܍t-1ʊ!#/bUՓߚ~/9@ڧX$<|h(@2ş"'wR{)g[j1mH \Ӗ[! #M>!K!d?'0 \)E+R^fr04]rƬRU k'=D+75&QGX"%[#7cJld|>xc gN^NZs#ߍ.ۅ@f(Bp~!Yx6#)e&>RHT\_,Su;]#OfhXlƀX'H^P[. ߿ljao- [jeZ7+[-qA⠑p^x"X8Q;F|0=Yi%ɘ?4$OrN82&^Ni'`I aj;ϛ eN0ѼR1Ψ8[o"Q FW*=2x:x5i 8žRK8b椕*NY/d t$ΉB"U /=0@A ߦ!љ:$V C:eʙ+mEkv+0G*)*sat6a9m.g%)Mq}l.A)1,.LqQ.my8hYH9^<$3]ut~{<ةut2Of 3Vs|Z̑ahLVJL3KfUژK>GJ/R' >胆Na p;`*94pjvQMAm7eteZx2cwA8ۅL +1Ups c)U&`ʔ*M k;4VU#^7!`um9yJ2tX #Jf+QDЊKZ.*״dPL]2\MΤň`1Z܋tjTd&v-:ݙgL|8e6{h LY8 Ѭo:ͭ} \87jVAD"jJm|;Ytų($r*+i2S@G/9@+!/a(C~ ͤ]7oe**^cuMA\p:Hh|{^MfG]vmSEv j-8̂5`uO`_9LW/ѫd=zmcx,X\N1M> <q5۰BO z>xFn=*"{ڱVkAcƀ4j!c s"I`Su6n%CPhKi?.CsuN,(`YmYS)fvgF&( j:O6T3p2z`& LLfg/|# /O$Wb'$?x{&WCVX\Ov;jh.0|'~kVUV7ݣodEʪA13zL4; pzp^^|{@Z@y-QnC_*/|U^V9U9PURؤC]9hgnVkۚď̸uSC ? Rri-X=3dhThfEi,Sd*4UBmk4YB;XJ{pM-E"M?yWH8`jt遠 ι#}I96Gh6Ya:0b@ɘPz+}:xGEF.AxWCxHUY1JAKu : N&TyAC{j>|S?}u.tU}wcbTڿۺ7^:e5w]( NZQj1c+8*&{Я,gkoB"ULJ^yǝƹh%yt&,nGj70pl8:l0apؼ)gqy\.Kzw/Ih:xzJO)E2DEg=ilBn#Jmz۳~SmxjiLe) .v0b{Y%h'66)г-a<9eLQ;>)eҝץ9AY>zuAAQraݠ$}xsEa}[tk 5uށJn)&pr"\*!ο uV];ڿ{HT@ e}7Pf*gԒ+S9e#u'`Z"k7Y. %bfGke" =:u4XHd*rWll5C޳癕<hLgaPค'Z[r38ɤǓ_̩k]AE6Y&'eSlO]B3A8e 2֚gܬ4l0vVZD71F yZN%1 @:"EQwɱ[*;Ѹ{,+׈1vFԏ搤W4gkGHx^SJ-h,E-X8YEly: )a(A-1Ϙ s &r!>BT oBՀy.xp:11Th£x~;{1 s)V*p# ba"9&IZU9A%[> Ð%gs4 ;ד>z0 Ѵ~_\ᕌ҂sǤb.3>23Rr`?! 7o-aG$l=70 7g &n9#޼y#Ug41et"L, Eðp0=&3pK:mi0V#;]F<?0Ct3~t(P2u< arV/ HH٘Bd'qp(R8(72<o0y,P,.)ȇskq-b9I=c~S7&(ۑb)##*:1{j6 dj c';ө}S,d?l~h?Zml_K~ݚM @krjQˆ"DPlM%=%FLl.UˏG8?'53~Pi4?ad@=)H()hGOƪKDO` 16lrm My(T+$3k(M.T\EM"D)<)m= ㊂o᥄`dJ:h/40QVM10t$tσyy$>.}< 亄fPPᏹ2æl|ۼbL *SB 92;͟$qA*fMJ»c:Y2EH{H(q)dtbz %Nx!8ZRnXٝKhĽA3DSjje5yNqk58p-2,$}sWÿw5܃ŴdʊiWZ=]2 {lQWlhZ#\p;98[`!~0GzVYׇ[wUfHhfDH 0x#4Jdd[]dOU~.C)Ư{p*akLGb c175<;#eVjt * ݑ#*9{|:M #Z /䡆s>NҹA$GՃ%#r.2pVgj! dTaiPkDq8GvyZzGGZ"k遍y%6TvL7pGdQAҍ(Rx,UTQi,=2s0UG9憎;d2ٻWE:gMeEυdu ZΐRe|LJr"ϣ a1VĄx<Ӫ5<ۇxkůHp*1h ta_(v+e>aVLgxwl~o=v _yj ^5A9#0}Wj&$%yh"0{i.Z5 p StU]T1VP}1T/oSOV bzkv( wJEb'U'h:*_i>jlugg wb*.p8`m} +9.(ծK sfׇv2/6VnG]J&q4Gu2^|O¹?o*P+;ËR;xmp~&8(XKjuf,fRi0v:A#+Y,M c&4eO00*ŷ]lgIw%˦DP, 0 FQldz 5NrNe^d:5ݒ*)*OՄ/cOg<4@lL>5t¹/d R3m-)' }";M%1]ʂ͑=ޞ;J'~)vmO#벇4Л|*+0a/V ζ Tsrs8I/'jdŠ_:Y󪽪57-bON.A\ث`64÷ ~C'@Ub1nFMhjFԩMFKhwG؀X (ZM /l|h`8\UeIǡx2!wzICoOȾ`1pH3S6HMk^Lt%W$/_`{~9<$ˏ<P73sYTPߔ-^GoIG#,ko՝E0wͧŏޞj hMc)̺gXar!BM>9OHj9@$W L;eeri@!(W+*?Oje&LK\?^[k} ~{o1qǏKvbRwJADkD =6MMDZ$2(*ȑSP3:gO«%Ȯ*IoĀǓ93A|eyDӽk5-zS-{IǏԖ:K59 7<bw׿҇XJ|88/YԱKSkScy pwNɅcx Ԅ@f: hs8NKF4+L,Jh|]XuV[2t`.ٽ Ȏs?m2˩+gbϚTOKYAkpМwb~2 `rH6BE%m4vw7tֺ, lon57;;;?c[FA$[l!IlC9h5R=-%Kn ⬹ќ1RwըۨQcF[(tW0Eݵ5xLZu T[rOa@]`B貐:]5`rfbl9OC=>s.0mȺ=v;eeלyܩ2"yr#,CJxf>iyȸ`/4E_2K4t| 6Uh[0 E] x4N_rpYΖW8s8\[c5GweMn/oʦQ]I; 9T!!* (`zS80H:v\Sg`J6'8rM,{'-1ӥokPS'i3l灥X0oE$=Y`OtrHeDbfQ$! 1nq|ÄOYJ>F՘CYf#`.B46>7c`*BQ'ϟo|k7p*|$2\ȥPx{āw TE"cdU^{nn(%;$C㵭 ' <[=N/ϔ=Nm#L]9Y?* *56;OVWŞoP h55'݊]ًۙ9O8% 0V1WVbB)V$>b6}`x;tفatM;ݶp9DEpP|@/6^>!׀p;KlW9tu<$@l8w4,e?9Ym9p2 ZL`S/ 甠pv9v%E8%gO |+([l*qyp#|zz v}( ߞq_vD]h7s"oMlG+H:Q"ץF1!AHDv=$@}\%nWh@H,%⹰( v0SiJblھ ]ۡ(Ô}W>U_ȩ 5:}O P F(Ӛqc.G`wRQF;$ʼf,=%v"̇IV:@5`& F3!;{{uz-Q|ɜR'9T!ȻEd#Mӭ:z~0$ ]-*jP\:Q'>` 8QnBiђUb aj.M i8@;&.XihM]y{uۮӇtaNENW_ϒ 8 lpY4jBu8σr  TႍA  G,Uk  !bh9 ELaf0i4]_{W68+Pd\`=a,ZȆP܏/kbt'u҃4j7]+SJS/1b1(| Ng$/&ݖ`3W磎z7/6@8Z[ꃝV/ {UJ4R뺀1cPG|rGb̶HaE ̗]W?_"tF{km3;ѥȞZc:Y * ޛ(_v_p X u2t ^jWkĢ.+v`,Dzόܑh)b.+cqw]C€ʏ!Q,gsh9WrF(5RuJ]樋".^.pYN\J '!˕lug mi'[LW)la0Hf]h92)\LP΋KG%/]WiC=>jO8Y>{PD0u'nMi,7P۫g4,I)>*tAaHMBw iX{lИyQڇipxU c@'_!pM3yUѸ9 (f-H4J x{`T Fql<LVM#-2Qnwp!#쑖Tݝ=\yL|WhσS\KzΨ38 PwQbB OP`z*3Θ=iS `v&.#~+zq(ŐG,Gµ\^&1(x},h g-[jb"距M5򫺢"t&q8@+V{QΧ75-[AW6F8:#FpQ4at)L uvs ړaAig**S&{Ri=jc[v{@0Ń%XeކE?+ wh ?0:A:VGHiQK8T_uNlH9ܯ 6#4i%s~ iLI1g=m֩;3fwiS;#(Nfgcl4rf!nj7XC1#|ݏjPe%xr[L}M7X{=9>i[qO;md ;]rܲ{W@<<8>QUGؑV'3z;}v>$Y^+Qb1K9KԥN7ʏ՛R:6|_bjظt>l|,\eL{ם٠{L:|~4ðt}: ^B_MQxW ^ܩtp3n`ޤdb?:'eG'(; 4.BQaj25m !+ՙ[ȧmP;ǻ"J1BF/f:rQV ?%p^```,*e@ƕ?#12Ľc23OGNp6ʺiMn7C^J TH|!cOgSm=CgGZ'nsu$;Ic`yg\v? pq?a;.8˃X" 'F>qdB5 >k6y໐f8(O) U)ּvxyRz47F &V;mY;;ip;Ⱥ>X7'o>dT9Q < :5h:>HI1HjDOCTs]S,ʑA?#3v.z5wdO1D8C le^Җp-kCNA!XXgIBPBW4@B= yT[πIK訍R 2l`&ġkE"F-N} &IpVQ牦6Ʈ` ߆ !I]&n?&/dDZSPk 9Jatd0ĠO04{0#Uq97~Oڠ6Q\ :ɛ y7-g5yq17f?iCP̜y劦IoWҒ҉00eBg]E, 8⡑&'0N lFAklIe23kl=o%HxZS+lJb>h|CqoSu潭5!xSE!\eQF9-/a21}fQL\ )zHȰU8ua>@3+@/~<= ;Կ0l%;;Ž(R(gQ⁀<%`vr$yj*C-[+6A|WE2sal3q ܢQqOiML*0RM2Hݘ_"](|Wv`n5X(OE)'Qi {.Xӻōw2Mܞ^{-6Iӳ^[0jt%џyS+Xҍ(Ri&W#ִLp^E-Y)AU>fDg MJqxi `1Mk#FM aPu^c- o,[2"*lPKb (u-5&l \rc;Ot\8–j sWRfa./)Z-m\[;↻OpNMKe|ිm hc)Ybhw AL'/EN;RI &% \dsD,\ÃR: `84r;%'HmF`AhAYSm -Ӟ/ba'g0WswW[tr|{W*e5Opa}|Xu; ZEV@讣P!sGBR"]RKx7 rݑ^,R3h hk“ih5j)`C9$"ex7)Fث`uFl4O}u׃;}mUbs`B ]]K`.U[[ԃ&o~>-ȍqÂN,:9Yׯ:.ץ~-0 EaEߘPXUX/]Xjֳli: \~&02 M CېL?p{MFWrS*C^)!#@R7DZX$[fw2^ǒEBJK/^,br)$Fȱx' pQEg4BG8w4#˕(ǝ1o& ]eD0%dĉ̷B!G]l6I"@ЕPD~Fb^0?}ro:/: %\R(fKWX3{VԦ23PЁL() W YhE:G[86ۿ]gnދ`?`9ކW FmH,Ȓ9U-d h8Fۤȶ_FCï_Y ֟.EM}(Ĝ W4ZXΤ]@Y"!7h@y^}$ovy/}qD&3PsC!Rv?q8DmIW(Yv<^餰 Ɨ}JGOmL`8 } ǟVAGWV{~Xm>,6d{oo[2L#pSaJ0%a)! W_W0#@C d_g'e7Z\0Uph~x5XjU.C ߈yJXώ>18PvlAp C]!Idx1I[[19GX2szI ƛ= DwMigUdrk8N 2FĮA)Erbe4Yg@Z7HI/>>vĎ+R#MwMO:|- gvZG웨>I1>?m烖E|G!4F l"C0N E9ʭۿ,oxNhnbCVKS Е#z 4ELt--bm'+:s )U4Yf]ܦ@&Fjg8=$T?ar-QaMK0KlKopjz(V|DKV∎`rֿ!ƻ$!I݄6luXWr.ßAIx/I:c.@E]yL/v1MMB_-ޟ@bD-uť?]]*;! NA,Z/-\!0A-3h*Yi=3k$dEF0cf7&鲙Y?BTT<Hn!0;!ƶögfwv<xkx%P? ecIK[cfi1b!ZOYXo8NcOm{ Y2^Miok Xįa m $I|Lbѫʋ+ .4> ZDMI8 &3+[j$#Z*V.qiwx82h(r3/| }0aPjK1 E-d"uqi5Gg.iF2EӋxMGEbK+*]y+V@;om2;!M M0톊.Qa%nTˆܰNaF'mZ\qF)@h -J&Jn#`Qnj%*pP ^toZ';h Ji{Ay0ӣǣF-r<p\=T[oߺ?":4+l4221]5HEDo_d[!א3:9JGj6Bo4ͯ^]ˍrAk]q G!Rǀkmčl^$l8 c= 7o^.kPlnUgI*[88%Ջp4`*5BCl,))CF xJ%i^D!VOI,tXo\T>sF.zDBKHSE|k\:5lS+LYt-mlի_S6R i[RxVԾ]^xMg 18cLU7T޷Oof[M(jr+$XefcvsB`cr"xTpzqu;f+ *5,~RT@i~>Wc2!JNʥO*H@X)Ț}KD9Y I̡rf>#㱈;Uᘬ- jGe6 .8>,S.„:y1["mM#u}׍նz~Isٹ#M[/,=G!mX-1fr'C\y'02 l=Kv\:Bb3bDf}HB$%a.$̥swB̶ϼ̀eOTqUBH+X/방i }Q&O A1I. ;~Mdw`H@U/!Xږ͹X8F⻜kN?.0ͩZ#^7y;{l 3&kMf=4dԠZk;^$gc=lf@c߆*Z|xҼ[E"DWAͽrw{\֡@04~crh+$H'~U&It,p؀p2h/ $P$ JS2]DB)DZn\s\t95X?68QuMYAժяDNEzGuzk n(X GgtV` (<*_%AHKzsfznm}^~^~.3!pi1}a1.,,Vfr$EY w9959:p"#.V?kk-e/]lX"h{o e]uqe*Ή4M|7$ft¤@0\u{; *)z%E0?ه,!j mQdO 8tR-?Sq2,zފvQɳLsT-n|EbBZmPfHK&gS=ysĽ 3t[%#Zȡߩõui:!2MZ8;ldh}Ž ,¶N,Ü]E,>v[T}I[ |]cLъDa- O3KF4 1srz%ttq䣩 v9 e%=JdAai*U1 4TxGg3+P@***kݵc6lot/%Я:ם[.PF<4 -^},,|8t>ph5gru?DCroJR-+:l#M'}–7CWu{xՊ Gt}@{N"E]K={1ro F0W=ȫ {=fIHɈلF &:3/|M't[Y̗R3}XIb-rais]vy8&brրU8nz+0Oc,$b%\L܊+u*}l|,Zvx)Y M4aLj+ h w*ַ MW$Xg]lʺaZx>˜甝P7t&2^e1c9kCH.J&ܬ1kiqB0B`,[;OXF3 +I)U0K8h1>iҟF ~ZK4(z^_8,j!mk_@貥v:sҷt>לUWvBvšC@ q@r=,^fQ* M8 -Y9g؃{nb;Kf>S|̨)7HnCŴTK֙6 qp !;nF ,79Jښ80i;ZwK%&͕2ad+ 5-l#s}[V.@Ej@Q; wqzw?;L 0w0| Fwd|(:1pIy| zogLM4R-:ׇis8 L w Occl+n4_wa/&B}'y"(p*h!7gmDh}?_C2vt鍪s;9;:[tRkN Zq>P;dZ֩Dv^]t呓h\U= w*߿`]:SEMAJ,m]ZZl3f Y<`xr0 x6# 1s7$IBl^*cqdžA1k/ qi8* ~~*e`բ_誐N2$ᱷ"-8഍6vD8ZRύ !.  diwއO%C-Dwmu91d5XXFG- M+3[FAuIF0] gFi8a Moy"8+eɴ{ QJoհž N<eLVfT\xE75̸Ӷi/mG0"2dn9 Uw.omgӆlisS€unJ2"hQ%8'RK=R;;r@6;>zQM'KX+w%#FVt7`˝lJŽ*wugY)l!GZ zΞ 2a/hm˖=5[d6_*mx./2BVA)o|FytZ1`a:?pX/n&CE6͂ۦzYdrE>QLݦBKea-e{LPt-EQYƽ,I7<&MbQhkIs o௃T~qeww@6!1o}0"۴WĘσ+QZ ܢȢ^l\;ts9 9ҙ:I&ϯNo޲cx-wq#Z)ժkpp33Mbŭ=-J:OHtplMqxIǓ^V֛ޜ 1> isSP\qvÛ 7 ݓc,Xmx@ezbrѾ$,-u)2~*R -C*VM9!ޮܬ0,?o#d@S.YDoy~<<6I7mY ^wO"rvG0f' ކ@N֖23I\>WLP3GZ3g :HǟNJvSq(8gH 8)\vmЧY8XAֆ,k: !3%lnӋcBv{:XjFhؗkυ㓷}$+,Biv\JGBp?P!u::NB{dFgV<(j#9I1*w0=Zz?rx [A S/]Q=ZSK} 3)v(\| /hmBiÄ^gdEȱܱ /SA1C\jޮ=`bBpj bv~f#cSA 6fqEyU^7^Z~u=*I2ƴ0w 3:/ZLyB[(lŤ^:K:h4dF EyC\`5/gc%%PQ}qJI2Υшi,́tRmpTkݞ[Dv}S??M̐oqCPH=Nr<6bcXZP9Hme /zT?(^i#@Hª}.Ѷn.VX!W,tԓ+13l-ۑcJ=J@aனgP2W=2ِfhz%=<@=5Ix0%zΰ| gY6vO{F䚝18<:t8:GADX8%PkpZ-t"ۆ,ۯQAڼLw?nk縡{S|2wUܢW_Z4:Jg_j{+h*LMҵ rmN**~fO+{g7,'Z1q_%9kl1Khln$ELӧ˸:r+xӢ#(/aUC0#Ĭ>O=B;?hRAɇM -Zϳ‡eDZxͩ}:n~\[7LoCg gXfWj`˗`92A`9%4:7ˢ [4>jYҖKaG-l ͡)m GV`P|#0sW2:SMnv71 $h¡i4a,S,Wj3LdeM(ԺNYQV/)hW}J@1h/P[M𢲎㛵0֣諿5q#څ5\a(oh2&Qv8^o¤ua]8t0t^dX ޡ—Z~ˮX*[ \Ӈ r{$m绂%+EΩǎ,vbKDJs~ӘS  -%Axѻ -YmydO~)GMeYy#Gx`>֗͵ #0gT ߔYv$@p42lFpi\Ix+ vS0U(e [ma)TMXm# k݆), P(XZ2oz8>4ZV\R8/1vS~:Njdޙ>~qL&̹E;w9ũ%յ3%7cExQ^qeБ/IF ̲V̓`&X{}RtͫaP/]}NXM++/h w*}儮M 76#OunI[]qId-4TRBƨTy%l,e1Yjޮ TV-́9YE9u[wmfq:tbJod7U~\i[?6(:o!O;\wߎO޾9Qu_}Nꀠq~';`8a=ΖE՝^]P"j՛_D\ì)u. o% *S t8IgR"f+#Yc1,ϻno窡W+(Bc8 ?AՀ/7'7Woo~" S<g͗ukpu4ɥd1ƪ8èlJllZj;Sv5Jeh26pɞp.?xo꽞=laNBMML0.^CbG'dw$S<]4z?~lfŻu5 jV[(L$һuyzg7jC^F(̷/ѴF@o64M{ l Jk]dp[dBmr6~F\J۲+8MojialeGvlȊ$>*`sV:d?~se)c EA`WߚV㐿5`2K"V-qDu{ɪWuLە\םA"qm2ܽv~~u0s%hjGJ=OIs .0IcE(\cǥiILAXH ϋm 2Mf[ׯwSme6~hv/>@F L^Iex`{jkVJXjܶ9`rpc{c!pp9l|1T+(3¶l#d=̗o3Js*v‚7QJ!2"w8hG);Z]0N(-9*cBqWcT݋7|!QZ^W^In<\ȼQ7{8N&\X&)ܚk┭'VdJyY82*،صQ\be?2 ܳ Ձ28LqbH_ }`ڥ" j^a>Q{`y]O ŔѠQon.+L3Q T}T6HEk޳3P0E4Q<M췖 C/OoWM#p\c'30o~9>R?vZuQHμ{&>flԑ0(+Ƨi_%|/_Xϸ*@~eXSc?~_M!p}S-Z4ZeG%ʇ?z[@땙70~bMqעer`ayI*Z7Ps\kdFƼ_)!+&?z8Oj2b̖;l}ۏۼDVkižmvHdClkb'[QzGL@R&~-6#SȌz* mK,Qλ~CY%M߽-m酯)y}[ۯSLUgmg+]{ nc  swM\g @*lx+n>uYb߁Je5SL'ؙRK Bk =`kJ{}&Y,hhvլ>c4mfK>X??|-Tgq1ztdL1;(91[FJAf T`VDM> FDO&90a1.&}NF.F*JF9 ֳb).k')ڜҐ;㣝z<;of[κ399}ܛb2 GK';#M'H0-NSxs.&DߋL/$ u2ȀSiIQ?yϙ)̊+ ~Y { AS_$'V0?sjRvJs5VNB6\q~Fv+ %{q`X,JְQ%rʟgk\owcX&0z?_zT~iXŽ4g@ld41tZ48FGD}mj;TRk;tت5IQ>( =#ؔLP]sO\ˣӟg NT{`mk%Haj7tQ(w-kz{T7rm:QG[!9ϱ&@ 9AV*]*۱{fc6]/pұ9 ~kC/Ҫ#ʯ$@5Vk ]pՈ;$Q^tdѲ*UЪ6jxN[[i (Ph&u1c3eX$AmD|]6̃C0XZ^8; Z@'=&a\-ү*${Z,k,iOXͺ|bQb=w̘|4my,R, ?P&Tz{a| `qR5@q]V>Pg;ݵNB_˻/~ErN uE#5 Q)B4 wVl0)K0Tj)Z&$ПDͩ gS᧺<5ߊv,T~Ў}aukgBS`:ded`bAj, xz=Iz2=Kt3,ešJ`پ4TeQz8%6dV6UN:xQ kQ@h6 )8`;Bv0J$NzQ)]N<NiA3A\hVB N&BWe~c'hp3[kF2]֟=`sndv'P9yn/ 2HIYJ#Y.≠m&>&ѩY3m8hp0P x:4sE1%f^=a|Q,-C1 V-i:)HËfOw/N9#=ٳltI;`20N p p1c`&0Cp?qu8&C b-jE!L .58c9Z,d-ݲ*H '1˛Yeǟ.(<jFƛ-v/"r| QEvЫbֆ"x@{cez|FRKZ*MٽݓҕWBƣq4s3Y7u"!Kf03BgdM=֗30n;F?4ZO 1:$8BS-ׂ=wRy9{,5;Jֶ8 zG3=M2 6 E\]6DsMj -8կ[dqӴQmm^4aΣu"~I-r[ߪOʹ %hz5xz n1/͸zjt9]Qݓ[Wեa:>+<m}Dizn60&N"ǽ](g X\27U5{KG` JjK^Fm5əNwD˖F:/=M탵R"6/ "),|J/p?/Htg7rŗ-W gO\h!mوZ+&IJTG)9L^+iV?B`ko֝}u ̽~nDx؟l}\Q~-!t?c13-J:O Șd-)!~~+=,VbŜ,炘UWإr`,oGoCE]%x6r h:`ڼ*S1Y;K'"p"U"Y%/L*b16I9Q.GZ mI,&6iV|,ñsaޢjMD&K'ǥV `U܉+p_6XnS=gt8vI|⤏g񣍻-V xCb{@IXBvyӕ^8>~YG{kBb--N,sSrB2kN[94"',|Ą5n8Gy3P7*ҽocXi> @rY˂1!T/̺bpt@slj{|;S?g^$^ d'yY=92 )v`| "zZ<,Ǒ>9X$)8Ge}yChh1MF0[&@6="j\YS>ypQWvxBpÛSz򤱲WV[pQ*ib6dg|-:Zww؞垆ppi3__R~w./np~R^E\p~=;)V' 0EPo`%[2W(px_L42J4zMaQ +5IfY0nw1u&"B#@Q>U bC4oVY&S6>hם?*i: @qBvg)Է=O{֣L-#~ϘNX axnpm O?Za4KwP* {h4-.:AO,&{:9 h7ۿ`8*BLds$1±B-{S[-]&'F".̪5U58U_E$FeTeEQJb8 & n1tP 4*2dy50+N_9̇k dmlB&t &C2](\[agp{Pfdܮ \ڦi$x'5[tN:9|#J՛PeSRrOm`Uu5dVp3΅!a9?}L=$+d+nĝ}}YDŽ'8b8W{얌7ĪU\Ln;$i4ݿ λ2Fx1SHQLg<:{[j[ ԤӀ^"?ѯ{(lP 5v5?H ~!̀vP.5V ^))>E:FFWwE7Լp \]WUl.4JqbG̒VeuRbت<ê[Z DfZu9qm.t[*gE o ܑ֤k|cդ@h5>O=u=!ץbn+6BŢlMAYN*E^3兀a+IS%`V8~xHzx6Y눗e:#\<%tB2QX(HIZNi?`)~IU lno{uxue.7T,R-5SgSh}^a32pS Vas -?}%woY1{κ)՜I8&I_K_QIs0q掟 #KyeSl{:SrJa<;:/(3Tvwr l`(R$;t96#k95LQ2_z2 YPdW=1yN,rءt4!v^vF&3Ξhl#7oWM!lceg><dPicLvoFP^{t昷Y-IZX?-+I TϜC{MY4˛@_AE,yutRGadQ?`gm֏F2\fs6 ]d&ĢaqZhNzJku\A듳^P~xux.7UnW}Wؔ-Ƴ0w rUG9 <|LX3 +$n10)ס l)A:ݵ~9re0w0w + Cu{Ap0(r%Y*V`\ ,o$:z:\Q\Q_2!yGj*u4K + UJߪst-^~u۝(lYv;Ԫvf}ݤYş/7ϴL/&VmE\6{I7[&c(1'e뽢D͞!?e@gV: oT!A܉{ͅar+K_| &I4 X5rySdez`IШAך8i'Fg?8p5Yj띯CYUes&#<>eL@l1-.<`+W{Iiܲ TofSݕztG̥\YLw3\$/5t^?*!HcFhÆfzzCǒ6?O<ہL`S2Mk/H/ix1&U]\Y^cȉUcvX>ێZ|g̦ ljӏf*c[vm 2Āi(?BI~YSIpĞr.5и}̿˰_r'n6oodQ*S?uZ%gT)hth忑_ߎ!2wޕ:+9.Q2aD^MfIce۔NDyjF#/[l-,j D~"#ݻkkCIHr~ԐINoB7>n k7NiV[L*bjk[wѻUKqYM- ؛ K ۧ&Ȅ'?eE_9P.K*f1)i`'av1tJz}*nMscbB%c*Zm;n裶ULȋ~u#؉9N訯}e=glȸAN[Z.ԚkhWze M=ۂk&%-DEuM͙iՠ 7$oQq~ $N,cȑ^q8m\ODf@f"P28o)V AK9 -[Tpvmą'~0Xn?qXJ^ S0;F{=cS4=6QZنʡaGgQeKW[@gVǿlvhc*WF'%JS eSTMB D蟿?'K~G>vCE8qT!{[];CRP.{&O"+6Uz Db|?OhH "NPOِJ-$eCym!& FjDt:Zo<,ʽ+pZܘ& NmC 2^.d<{yS$T~\Y]vVWUDļiֲ٬6Oυ h:bcDUGU n-LR dFIU!,,53%J^y`Ph85$^zq*pp*㛵?zy*˜{RpMǘ#; LtuKb0gijG7+[#Ϩ4<>2Ֆ-"8>G 4IH0]_7F Sn-U=7D,}딗(eJe=nYQxwɁ$ ;APhL:ݖ54%kYc-V]0qB݅D Eߧ:ޙhzt¶D/300T{y7M?c7ւ,X A'Yp#yC9u-]w8r"4%crT2zj ט)VgD\v \  8MfP{kmLPW^IVMԴPE$Z;*;;7_SRz+W0w"E(cO4UӊH>aC9bxVBZ#zCio Y{+wW[ OZAZ2E>Xш ;Roz_`I}lͳo٭yPnik?O,}Ƀvf+܈ؼG֑Tai~rGk[V'TL?Tӵ22L)_}!"U&}٨f/G-.sG [R&U \;gYv|IqZ[[mEhSuvXQ}4IQ6=obZ[qR2V!eD>}([o4΃K!in S%׺Nr_ClPAa-U_X }L=Sz)k`Şs]n~:-Wp&DNѧI/XxE^Lb4ѦZU_$˔Q֤~ߩYgF{ov -Kc/ʆGFDc_uX+xu;%j=U5fkym&H"M#AO߬.ĉ Q{ެS;iЊaQFW?_aԢ+}rt%%?Cvh3K󰏡\s3](7{VߢJڲĔgHmo?lҙd|Qd]"&PYjF јz)ѯ[ӔMu='-*wWGV#FIp 8~K&=Wr&yI}re98z_{P)Գ0qߝu~ ;qj<9K`[X5UԙqT: Æj0 rX ^IaE8$8G.h[,T8CSx2߭u{ӗWk_/{_x"|8zeA[AX k1 8 CqLKQJ-dcw_Dt]K9RQ)j~z 1\FBԣzY=mŦfjv>K q(l<-"5E)Ɲf}]֨}ӯ`?bJ|XyLz@SBz `<{~uNR.NI@CT HGKw/$ AnpM6&cTA5?>i۫'+hSyRTjhz<=Z4I^̠UC™%BQ.7rL,OCdH}o.>^_q=тbrbL:Jn뗝W?COєغ%vEj,#@X0ߙyPԞKwwxrR> Oo>a{>śB[ }oXe93cV{Aph5v=(Վ6DUM(iJAgggC\j'06@n|bl'g%2zw:qGf.A}}r (A{`$hmfF!d!ޕ)J1J[g9dmx9줹1XAlQ0BM#ד!C"E]n*$Lڱ(>Zë BPt<~>"W ~Gh}hv5(q; ϙ\4%Ԅ&Φ-0ƫwD^4HQ*8't@ ] Z\LRm@[L3it.䏒d,j};m-PL +s gAS˘ E@ÄGg| fAi 3,$w0gD2#]Gƣ}Mx(H`ӝ,=@Z42"= qE>ޱȎ>dAʓ?MRM K5Z$ꀄC4!]=821zY3$IO:c'qLUM?M3a\RKԞD7G'oVn!MJTf;{R/<q1)3: C-js1l]l5V W)MVY-:6ͬ" -Ѥ *n ܾuZ!nȏh3Z3oŶjLHhf A,?nw=jm=D04"ƵN#QU &`< qҬ). <tDa&ِ4߷ :wܱ`WZ bvFdv%xkZx2L#{j=v{p[ڃ}1\6,lt|J5 2-|̙U`f`J4u04\-/ o`0Hu_tֺ O_1@FZ矵_~x& 7V"lV{Ӫ>C7$czvN!F3 ؞C ,a)fNU\F>[F|"4daX p\;fj]  %%Cz%s1#Y_| ; W&t}gƒhurz_\4ΏI'81s`OѸԂpjٚYGpC|J@?b!>oU ( &GGoʔ8mG? Z<9>0HYVG<><8yyiQi:gǻZ9! p_ngFp= lw~sǃ`L1_(Dxxɰܷ'og.otr}6H烀{K_7fIo߼C+ω.Sia'oNJY朁g)a8 縬%=GoߔxÕ0~0AGK1_m J.fz\nwΓ??g#-ךBzRQ{]Znri[r,TTQYAzçiY .Ƿ{u/K0PlK|e*Wm.ڱRYlGŖ#Z:y9xF ~U }Wa#ޛ 4QvXehڢGGiV,ȠA[p`<îwvFu6)k+6hӢ9br|7:'Y$v X6a:oV߿pC.YVoJfƉǹtg-1{gD3?/ݷ;?/iԑtf)J>z^I$"+o?5F VZ6l]Qo/[ɐPI9smD-{&[KVVQu斈Q=r,E?*Mh#GF݅lr㊕OQD0 F~U] >.iz&si>!S6 K HFibn!PN88*hw %Y`J:QB95Zv * KjêZͪ楖qeOhῪdSWobJ.'vvLf'ϼsV6caϲ^ۺV*]߷n4{ olbQp; L`߼?G}lx?dx+]}o뜕0є\ƺlt.R%\5  dl93pqrB Hd Kmqtپ gY3pr 0' Oθ}9%/x+}؎f`4i>vqw0%fs ymW;q)8䚻A?9 (by1gJX.&N*u#kzhEbDmZxYf QAtRηL 9q3lC3Krb3-̶ER٦Tgw J_Wk!<1em0[b`^DZ?5+[O;n: -8Sa$d ]5E4>#‡Gh3N5`Ptn+bm }"3 GsxzӨ1K(@@th.2x"ll`! ģk` ،7+_TTƅ72M Օy~{~ 3aN~kQ oQKH:q_mgm儥AkO05zGҦoVSz٦TM'3Q&$z0Y(4A2]:W992#?wF0*ǿ((#g?{Eуx۴^8\fX͌ȧ 1.L 2Y=)<A-d0 c:pn +fQKŌ : 3lnEU |Y[ԖAb;N.1s3v,2~1; |r>Ȯ:4gEi=r{?Q,ÑlC7*&Q*mAaZ{k1|6 &\f`R]#K'cC~" ۴| Z %ЫI F*kg/6^hxv۝ޅh@'wlIz 2&$_mYwI$1./9J0<ǃ@X64d @Vf]ԅ(J5Ny|;,# 6L0ZOs_Nv:,h䰆R*X9@Ǎ𮍘6] /\;*='~(i!4ivD*')NY5&(:jVuƣJyq{N# @Q4?ߵfh 㻴Pρ=9v"]h&<`4 9x r< I ?&p g%eº!V{]%){$I)ۄ= w3dwC @wDfIrLAݵGK?d~y޻k'u\2Q}}iPgx K3< ף`F'!3Z{: yzʯ'1KXG`_o.nQ7NKNPh6Ei:+#QzYh~Y :"p?^ȘRbu9?^YT^/>86!׏™ $=dyyO)q 돑x,iͶ-#kGi. ->{NXBk9ZNZZ.¿*vb fT2Nr"T*7_J$P@GfBOO:`򪶨CYYK&0wdrzrY^i.H$68)t`9qt$q2?H~_ȁ$³<$*~ ȡZi_p.7ND́ė@ZrʇZ|f>DPʧJ.wڪUgYbc>%؃wU- \seO1ClLҡ_09no_ybJeLO tuH̖?FeH s PEy遢άt4U.g/ϖ !20,! aid7PrFW?y|e b' EKE2iaPxErP^Q4=͞p%@4K7`X/PrkF]Veų"b> CкۼUvwdbVfL43B*lj(_̋gA(B^9N2[i'{5A(EGo¬ʆBaK %3]qV~Ʃ%6}-}J+kzǹ BݼP(}o`P&/J]0Z {騁PC5AܱtbnW/p:ܘ~*CY/(P6BKGtJ鈎A)CFʳ@y^ \Wkʣ}1Ci8M3]ˣ=~5)QǭVsqe҂W}C zݭB=]^ލ6F#H5t6ȖcUK3;6f_TŹpPҾ˄( [K3ZTY9ma3%oX_,8~( a,(&7ς}TK2P@KJ,\ % sR1ƒ9$8<Ϭs)XWx4}hYèSh[V!Ա9fqB@@:[ ޹ؐ͝J `J؀|ai,R?'ȠLI{b;7L0̅VeSR~@1EJ-KL9B_LgtsDS}";5Pg q:uHY~w?OgQD8np“K z%,E1t e"^&EC-[hn!Pd-"?cMQcP6*0?^+ ձ+O4͜ J=3 ǢSs7U JaG7 zFd×"2(`ϳ%*C~ xrg>2 e8fbPWw]&ÀWz-a295>K`M`W",nQXiG:tWBqoQ}g".,i#\f 9QVH\U Û)Y vXtx(xT.{(in<ߺ]@\/QR.2GqAr*>.2X,;~vm{IEj@夒rdP`SnWؤ9- rp`0?sZeak|J=^lyXhjJ0m!xvTΦ.T9"!c."Z6U 5y+}O( 0|#ks(E0O/&&{?r\47M0* ;XPh || o/:~ ;\dU.&w7RgI>˪*%w7QLGTrL$Qc?؛X*9 >1B̘" 3ܫF`K/ONKJIPf~95(Y6ɥljNؑ$tpfe 1ȏ,? 'kOeeќB;MVoMִ1΄?uxEa0{>BazdAyzp:\ުOVu/n0$1VJi2`d$I+])Wۖץ^LP'v4}F()5Ű%*xȮ8NՖepbٔT #aALPFCh,a:f_St\cz;3䢅Y')gIG|.An;fFRrBjurr2H<%rlg4lok4iB)]0OY<ҳxkM YUX4F`% :O@ooFrNʃFR4DX ;͍GhF<v?3g/­ [Ѯ9HO_8Pӡn,a$J6PQm /L݈E92paZ^=\X>91Ud-gfLZGk~p&&a"rUe"8;w*gzĕleAZ /B G$#@,bV^)J!wi-ל=,Ӭ㐷%/8-3ڝϿJh4| Ip=ZJPsMsf-RM9JEj(0O/4F;\]"EmJ Jۆ4ރdo(>B8^= G6 G6.4 ތis>A@5ͿA2 qC >A߱ϵc)> kr rܤ Uv˯s*U[l?z=S=Wޕg}Wp>gJŋwctW jm#"=[[/EE湹^zr- jIm^ʆy";#bIa(d[JNVBz#'MhsM1g/vlEU{_5^p0":.BHs\K͓ipNF998co͕-QWƇqH5lǗ}v pm?/͗*ƋU$Ne(i W_(yŤK)!ut~;N*)ɒxM]+1 t޺/,+9vkVv*QbM{J+oQ.e2fh-# )ҽ_<U1U{c5_Jn|2b{d<;e{k'/7PN -| :?*ix,. RT6.jc>cRݲ@ͶSl~p60v*x_O37Id%DϺoxG#p؅ Ta{N \4sp 840٧M!K-!핃-?@Aa^KS ln}\&@8ac<TJ>kԾl?KOL^~sYin߆ɧ0۫MV T\Ij,2TW @xTR}q_jftZY#ƊVԙ+-ӜN1My[AO=$nuP~<"Ӡ `perpf%USl_돎yK;m5\'MIѭuL)o ǨJ>t:ݍ*A: ,&=f\WMAƄH@KѻN:ْmwP:7`$Nf$J2[xe8ya") lSn%P+gwP=äQׁoY!5zodMOhElX$!MP- ^ `*BK>Ry|ձ5;Dav\ytG֋#q¼i"%f#`RM,7cX@ܒE<)ߦ>23s> ǟVuT{ӫ&&5v~U*ih R([P=k5cM,ԅӴb`pjP 8sî6#'`.EKѮ+z\B@~4N=ClZ frr{qBգ)ekIfL aJ|.ir@΃$R#%UW̒T3g4/.i]')M+-9dq8e)Alx(Xa:@]j 9קwzN"r2ww U4Ib UF DnF>Eh :g kK0O&x2UxAr!(M8k3 i}(LYL)Βc7 6KnN$$!Si(oykb wL ~‘=Dx [ ;pw!N$ \9& )6ձ,ŦvR+ 6 qeOU.[B_H\PJ"E& rh9/o_w@خi Ì"gd)@`LL{ xFÇRi'?{zrS9=Hߓ%@ ӆ}iWFЦƢ !-54j(1lcTĄ97z3(r)/RYv^Qt:/2n;8oN{ǽO*(mj e O/ izlB"Ptyw`Ht ̢ADA73 -|)Lzu۝ӳLa \uZI1j5+TJmY??J(q)ԴR sʞ1Hz!81H:Og`5O& o 1>XԒ CѕYCl82&IKL$*!RX@K6r ̂f+Vyp@bm4C { - a0&9#]F)\V'G 1{I/Vӊ{N3*cN+@I(|<;G7b0KK5w)vBO6䌘rqWj AA'.w|#O:KdFM$WFC!HH^jY4d\>J0mV;cXGztC#΍F2KTbsV?nm^(SqE(u2}/RPє ]T;י9Eg5RYWC"*jb)WeO`ܿ) E"<"IҤ޳$\z={ /!9LHKX^t8Bzѐ &+mЮD:|\tRJI̐b$ Mv/4!O^`~4Le" ?m4YsG~@TbXDr^hUQcj+gqveN G}QBx.{t.tK+3>YN1)'nZ ,TvS+ٽLf ;3b h,,uw)jWh1 <tg=*/?qϋ!>huSŷ( W@eG@zU, &Ĝ/B_iU{k;$qL ̚슧njIl ٹ zan-ݪ0ƾU5ai͔ Z 5yIM=fuTuII4S:Ã"}Kk!|}iتeWKkdjhYPP*CPyQ1 P|] i.8Duሃ_~QVqv4W+{QRURxp _-Nvrnuɋj[ _Te+>8U>/RZHƊjyW^T :d#}0_ Шu siE9`[|=Ȳ"|̳b"fV%q͝3KWĄ_6.i7xDK@jq**-Phd\`[G󱎝٧ǜ TJP˻1o4 7#՚rW`i_<p<)<:T} Fݟw~>65Oy@m?ί2BRU=o$|qAz[QEh̕muj>qgch(o7mo]VHCy{Xu+#:0fcDѓNggg8sz`<ve}+h Nؖ > yMIQswE);u9ڢ_FW"qx#+>C؀u"bc/M/> ,v$5NbRs ''}v-s`-ZޤrbCY2&Gω@4(lSZ~MiȹoU]u1]O(O3{3CgN^Xm) ɿJB@ڧQˊ_uR/˕g'F4PSH+$l$_Ċ;EEi6-Cp|:u@Qy2[*bٞ>1%f?+T(0`||iADo849 pF-qkG4уR" # CYfDj~4'Y6Z:iޒe 'cg T5Ϥ/$_heٍ1*FWB{rAR$ٸG׊:4geQY6Cr ܗTxg$rM_.G DJ^$P}RhtG;VQN 2~2UbM]4|laK)-c=], >D:3rO. FwpH-zޢv,=6p_G6NWk&Z3U,'m[lDd]=; g-8)r ߵPkP,/EǸi%Yqa?|&Ƒw}ȅOb閳HFؚ0>\ZǁnȃƜl oK 7~) i>A%Лĵisy@IT͚kD&Հ){?eQM72/}%0 gZZrd:G6 +uTHCxk5{xI+11i QiPL6Iw_iEbMG!sJ05=EbGEp#n}u-[ʎNl S <ܼNg}>akD9 !$6ˌȟhݺV`g?hI-VeݗaI1^rm8PxK\$1wՍPGsQ 'Q S\@NCYB=rל M ;pl,“ ^aj6y2 fZb6^?P#=Wd2xL ҿpdm l֫J&v9"n@TELHԐ(c%89 'gLI;)Ӣ[* &;L^$81Ow>-h+b(|y# qUUhMlxI#v2D#puԗlNS{;p4+_k^4`sAQs38!Y_x:%+kˮFP}|-NCkc7xӯ,KJJbq[X$oGg_ryH`Ff37^xR%'S2{-Dťq܌;OI/4l@>> Y9c<}Zg3J]@"7O㪇pIe!J3ɀxܚuaxe{X\9Yn"nq}^TF#<z.(afkM B=Adi$ xW 3FÄMdϝ0$ E7 1s#~cʸ)Z>_tlw:Å@DqzrY; iLccË9p\)#r-̱{m#C>L :h>dݜCøR2Mfi&–u4MX$E*,mF!]e㄂< Jm y3ZSżoι.VθڦraT( 2qIʲT\ДK~ASo߼m}7\/CܴTv[o %;M+ 5YnKlqr? Gc4p/")#9\ `Q h-1ޟXڶuڲwR}s/z^؍\KJ^s7ʒ !"&LUOp @H[1%!Hkn}eZ(<5Vd?e@/'XTw XL"[<LpaejĠWq8]Ku|Up(Ԋ(R{sF\n/w8LԠU HnŢ.{ȍ3[ Ixtk+A* `aTSQeͫߋAJlf!Ef C^-S,ZS)U [ :#e*Ně)(;Wz: 77|VzX+XaC nm|Vԋ dQ.QE:d4y"f:ܥ/2BRMJ53S\I,3}{&篏U-\foi@e9\9C0K. A_c`!>_j˟c4Dʹ45m4aUqKFmjR1t(Aaddy| p[MNLa0(@2 44|ב9gm|,[:Ĥ!y߆\W#} R>]Ozq}2v:Єb g`ҵK#8뢒k=LABuz d"IG4Q 57l C6/5m}XV[,5QN׎x 誻56?S_ʈfz{N'm:R4d1CUza7GE"j!_հsKbw(q1`+|8>9ف/Iي`vcٷHyo^2X}ҡZH3TKK[F>A%x<]g7D͢ROCqP9u}KYź9wtpZcщ[ю:d )e:W"qAg`Di{eae<1协fk( c 2apaBejWM(^0Q?Щ?80*,PP~r /nZ*:Mu6I.-dwKNNEϲXD^ Y!Sg9![dћ=} 0XGl~w8TO E(ct^E0@Ӏ;1 ƌU8z?*--`ȬQ\$c@/5 } aY(x*\h(etM@} Gr殳5Ze È\zj3&m''{z2BʇT'ka`?nl3{,bI?(L=Đ#ۥgX@ sSzKˎ: fS7l"$&I { x=?žSEȱ.Mlj &ȉj ;$xӒK H5=R5[A&AZx]h!`j!eDd/]auaS('@%y+y}m ָn|7a/sSЩĹ)"Fy5AJPg}9CR%AKj$yt;]8apPB{ U:P= #FB+|kTn"I'm3  pggSt 1'Űeq8)ZF;tG;(h3HL0'?_r&eިM"pHIHd&IK$:4YXu$\7;Koadm0Xw:jDt)MȌ1F{Bϔ9:4u@ X"4LbEtafL4$)A.qKWWbӴR3} tV( q<[ZOa{$(pJA1Ӭ0#BqIdDƈ8TZ`=ʌ 痕B,^1"tG)3Kx7BBN6lz$xwsT&MKR0BnlK*P>_`NzYʍVo񀼌nw)ᕖ9PqL(J9XReAsW,e2[T,Rt/h/ΆaNF36&e&gAOx+tt)ꉡ38 ΀1k2v#n huY vx݅ w3ȿi~a`$blQCbLSe5E)S|ŒތrgPL`A%ma#ArMn08#3tō=mULI)]'GQo\`mI1ҶWvftv 't]M0.{R I!Ҧ9x`<5e28w 5`n'cE*tqe,j/djYƭ}~$hYiƏ@`) JBBMmtkJxBFϿ$ /_t*zj μ⧻ֻV_=³3Y CZ@wRj14,k',dlҒhk>ҲA2%f6'Q/ ax[Ay'@Y9?=D ^Ց_ /2YrnqRBDdŢ؅`_#$FW6XNQesޱg'>rdȯ9@[Ey(5p~#G& u C;$i4>|@;4M'ًK=P)Y2b᨜ fӋdkȞ 3ytX`yr( G[\uGb$똤LŁ1~880܆.؆h)ir^-dx,`UFa$'8FC= y2ۙ#?`?̩5K'p|IBAYR#m?gIP;QDFJtxiX7:#(k 5J>ʩ,O1 êh2zd0so`'<> )x aJ09&E+[e ˔]th-X۬Dጳepe1 5¥%Y@'_")#1&Dk&f60B ʼnGJ)_A8Yi$dp9p'U$2 IN^6& ߦHNA @}z1‰@%YX¤=m FltaQʧgb:+DݥW2i ;c%)p0I3&1ݮjN{65$"x!jw$SN^z^(Nlygӑ1]JHTm#T-&jtƘmgmVZKlg~_ UcG U!6%o&:As1C'1Ai7j E2Tzp0& nXI݅֩x$f#8tCk1!6r چ%>IhUD6 esOZd#>q&stiH@IXIyP$x'S&F m~F%ݡYdhܲDAÛ DI/ltUc$0dh;QS Z!u8%$̺E'0|J!.tԎG /zeҶ%7.)M8G Em$#R&~Wts;N($]äf1GAj&'{o~>'{oߢ5,HlFiviĂMZf5eIaX;&8DjKG+IӋ_Qǒ. [2&K{$a(p4dx ht HF"LѣHv;ƼrjYȇ.,bЛ8 oP!!AadCtF- FUүE:xskr(,1D x#Y:8  uX!}G-6v8H=h{̡A u&tJᒮ`Dz(8Gi0׺,.|u(L~j0> 8$7̢HC"$5;SoQ|RMKցY",H0>@1|![Z֜#KZS`tbtD'5/z!PKJ @֌ڋZˋT(wPOmէ>Th׫jI%E[y UՆ +ʧ"~@lX,8O?Sweu(A|x`n$,P4:3=In-ES-NZXJ 8<0f F3bg _$=Kx: 3t0# 5 (,Y Qµ0h)+r?aP0qVBihbfKi= FSx6[5fΦR^Z:w4MMsjF1;͍aY5!?Xb–MJZŞ]VlPREbNZYW53;!"JginL` 3:6ZBr~eג=^ l*pwXȉW/N Yk9̓%g(zR,!5擌E MynnxE5AgGK=9'N٣!{ӕiY74(~53}r|9ќ"ϥ0`t+Ӽ[5'aFB6 gN(#ԽPp:5SXzzZG@r;oڴli](EΝ$8?DlS;5Ok#JZ_m0"u1QX,C 5у$.Ct1=Ì`YыH)fZ:$&ެQ0@1 q' )2"%NAԡ%O/HAhgr$z\)', oU^d|n|mFm>'k%d%:nYfX›KSE4n ;niP![$D* {0Ih᫶z.ddҪ`H((/o[8.xV6};O5 5JOkZqc0 z㮍^x+Ѝ'Dkn ]9uôelVsJS3R :׈J .'#4D"Gc9Ezـ-G" Y5VI94wذZ,!pGֹ~iw םߩ2tT@5cFu"ifP?Z&=p~Smy>i Zsʰeo˥:;EOP q=*9fC=S"Oğā%gQAô@, 4HiC@me@qC]9TRi@|BNieQTt863#4R wA[J=_0=ND~\)nm{ۂu/l>*]Jy/וG!moIJr?׽,6<)\*}0\vʽ 49[NT3o'Ҽ.Y3h#P?/Jrf4 u`y`\Yt8]'$%VbN0prEy(z= ?M3L~WޏRNw{ n7Ͷg|&@ES%ƞg-^Ӥ`c+ÊTjX≯^j'J:ϵDA4 p0ck`ĦD9nuV;4xRJI. Ǔ^Ij!ܱ| ƵeBeȂI3 !^~pR+Кr7w'.'*G>af˳Rn?jD~uVWIb5}:e- 2ҽMnzY5`)L's< ^ Cg#'<-KĊkPit@ɚu)?)]Bbюy|j>)Np$%"6=h[1 {P2Hn~.Y:v?ψРHAGޤo1.-eT{%:\G,|\R  %zg'?QN9ԕH9V]jz}si}++` RiSpfZRf.N["6vgbm.pG]u b#:2 AW&#!6?5:x۫eJl; I}iʠXeX ч.NR,)G'\=_0t* IM( 5K(j֔BEJE|B8AIL@*8&L9 8Do|ͱMsd}SN/8 AO Sy++}BScFvՈa ;oY;z9Bx=LHؿa6˛g?gʭvUev0@ ;3Ю,94ҡrN[Lnx1RLWvzAk 2c!tiB8|xK6иJ7ag) =ަ摃<G Yj|¹x&87WMM4وo7ZhJكU1Dn1@8MLo-c 4Yc(j<5VLzp$͂R6a@^&ߝoyA3k7i$AL3!`^Z_F2uQ :OCmRy2@(Q#Q!QB-G(-깉E,)hCNh vQ F=Ut~P?9> S])Ȇw:5N$%tЄd rr$L#C C`s~%үo&!{R񔈕(ZrzM٘QmdgT85c BCYנוI1spni~bSßUo!RT R&Xj9qs1=2?a* 9ۼCﰹ~(/AdܞNO#c$g.;fgPC,s +[NQNr%в.`*.Dֲ>p>Tn9VJט?3!%g%c4K"BWch;0NR#~1j҂VٽHA05܏$#Z!G0f=Ud%OE%P`:"m WB;+;,.Lj2bBXmjPb+w/r6 Bw,T쪎H!pOgu9[ B߶$iY>!A!]QIoL,M&jzV h1 vl2a+?1+F#Ԉ9(j?'yO7H+}ĢVU_t E$]cOCj(&d,v`AXsڄp17`ClloDP0C|zC2`_ʯs.w/wfoK.ZBxc=`N k~% '^>ZMd9vxx *oyUFb!1h:X<a*^Tk#-pLE\a}:Kgpyuɉ',b!ZXYXPX$We2{!ݵ4=k;}ef`uAraίͭ-m_.9c!p5dv<ZR:-hfl?p꒢z6i|D|*+/OM]iMXil\m FcCCeRvhF^p5ߛ!4$|vq kRn~!\)o_!o wt.=*|JS "MZ/FRqg^=跁vHcܯ)璧$;a9!0&X[ INH +"ʳ (륡;0kq{d&TV{R_aMpGloӞ:FTCGZMF,M˾n ]NL U2B#JiIyIciPHuNI~{ZgJ|-dx^}CO=p;RcS75Mܗ*:a;+/۴64S\V𝘄ŌPz˪; HxCʐ{'GTFD2̚>5؝(0y !u6R܎ [jww Xw>RHdr#t K`!ڜ+6>jD|9 !ƫ6 ƥH l Fa. Vz[^W>AU5P㍒1ތY3pHǚ$ Pu͋iVg}hw5@c+SD_ ѽH>aD\3j#U7c3pJxdO b!cH䳶m0͓IXUMk<L@J>Y7ЬҺ4حt䒜V*ם"-ܓم˯DV`ʉ2NA̴q%r.+ A`  74}7&0u(:f@bHJL}e'*܎A߯#p>!ucFu/>y/Gi0xyR8bUJMCfԅB4L :tSʹQ毑V+f(~\]AB ]I[ج``t"V&!~+%9q'&q^ ݊ ] EqR}[|{en0^!m切:F  Uj]zC*:sU梘Fi'UA4OSMb\I(Os!`_˜oeN@ܮtז}n>bf 1= #M_imy!Yy]"|0$k5AKmRc"#ʋ >>K|[J ;T3R:l$1P֎yQ WB0N q%%B}TJ.R?6f#q֖Q9Df_Ö PD%uu&-5ˤԆKi;.GKn~n4"h*B& ,@|0ޢC^n%4Q8IAEHEZWjG'5Vn/~uPSA[R܏{qF>#@UG>H8A >&@dGa[,ҍ}K[jV5۫R6٧VVM4YCy@'H%rAGP5srDEI4gMx#*N'! wAUluV#r@69 K7k @ngp p HQˑC =Aߧ7Z{KIk]vJk+vP#qkXt1YKTI h IZi` _aS+:2rnrN33xR[쒰_CZ'Ń3עaK9KS(^L&~-cyko*?$ ] V0QJuo7RW> COl0}!k, x٢zi TDˆUn+~zX3 t%JftKf*y}b/l뎳0+u{(GqL0h##+=5Rr9ٹ5FC 3 X.p\=MҤ[J_Hd^.NJ@&Xfi}+7k8m3aesN 3lM:{Q|,Z[ yp|ry,NN6\qae#A'F2,Z-B.3|F E*sRoP8)\9cMO`zOY3e5S?tZfQo, _(,3]r'HNCE5gA~DKDq*bcgLW{dΖ?v"Cȯ|Bo v𽥾Gq?gR/'WY|=Oݝ;8e\F;d ]鲀r0iD)REܫ+33`PWYu6NBK^/6+8 _aOVs oty`)3N=[2PRi'ZL'.^#2ks?MW1 qhM/XJʯaUnHPR\r`\We9R#YȽt4GPf٩ȉѨT(\+-,:N$T=6>QBpg rbp}Lo>G&0 ; Ktҋݡ}zfz7}e,ϽM'&3O#jEy Bi7Z ݧA`XP k~Z|Ѝ %!Q xpdAL&cy { \uɛ"tע ۹ʲSy)"1I0,W25RNYVT)(7f/1Bpqo\5 Ί2C$1.5AnmhWMjXWyپ36o+P=TƧ.JmȖI)&>7&emɂ~]zFJ_~D9K8Mi͚*TMrG#P;ft"oo[a*:Ԧ;JL00lȥ6U Bp:Fdj!|J}vf]ף ĨPB I'aE֋3"t͟aY ZWQ%A֗ 3+݇9alcV6c]Ns]qsciM[$ ;/)ɡ#$D {y'⅌Uߧ:R :\t5)J2] ^>Ďx?}{ohzq$e"GǎW G4DUףH.ր2;KlL50dVAo/v|! 5zӶbb/Z(:}R8?eSUHRa%Ôd2ԝN;RAS */-FU.]Ut-̦O2x Unc Huhe`AUiU".Q_2 c +5L|6aKnmR&r(ܢ:Kn҄2K 9y {N{dKM6BuEC{e4*]m'mP1˕|  >%8,<31@R٭&&___"I*lTF'[*פnf  ,rDjž<)f(TqljI+3T4BJP JbÛh%&sPŴKʫGB*ށZMoٻyHgM/:]kalfHX K Lht BcYGc`*ow av5A%|#.6FT@\Qy7hC+nJLX98:XSO$s9UXW1Ջ__řW :N^Y<" Xbf|<~#(RSg% w?ⱤmA<ڬ|-W烮Zopz0Dp'sP}=Rq ]^6A?OM UEamzg37÷Ƕz%rA|TSÁElڠ%R<P8Tf'~5kF,oȯ%uWuWiͯ6c 73ԐvUeX6;;.g*gm!iy 8A Ji&i:+肳~[1hCZH<e{r7pVMǫ͹jO>eE~d>]a3'6dW#8QWL6M9-g?14[LjHvͯs5ϯ/./.tֈꦦ4I7g Yi`ϋsy`O{QU'Tg;-OAit :$hgE>ZPVЖ$Xؘ ! -p$R}Mm/J:GyMS4[UDރIK GZt*; 1ycZ|]-!M 4ơ!6a? Yc"+MS!J1iWi* 4 $dD 1Ě\3hh~)ڱb1qh6@I!ЬXzkENLZÜG䁶{BKCpP4H.uD yݔ0լ(Ebp#e;8^*YF_˔ֳX {,7c!$htPi L3?izzԔ4Lff$"4E9.Js߽qZ`p[C;{x.JM l ܭUp,?y(jF~QAJnTXժ:| S 򿨙`œqt -Yg3uxuDomy)X#ռd*Wc8 p?foĔ̏OeOFq'UvId!A` } D^'8;ֹ<:8մ?~3"e"Wxs BTGV;?ڏf+8۽JKV /$ 0`Y4 >Y՟n* e2[X)as3vs;xФ6N.ϷIL8Qu;FJ'[2%M١Z!4g6rʓ"AJa""1dE.XװbՅV#΃N3'ı#ŀǀ7_4x 3``Ƌ㇀09K[ݠNO R!OY'L^}ہ6fx_x]S1Vv~N7< cddԎ^jAnPW*rzJ|.xաs%a|[&MRGu6WcWS 0UdAWisuC úCkǨN~^__؅X̭w<;" 3:Z> uU ڞelcOsLxIHCG[Erט<{`k#t_J" ?]Q> Z^׮.GB1̽.V~~~PdЩhCha%mOh!KPPe l[O\s*䳐na vBΌ\.sC:@A %f.}㙁'>!F/@?\֞% B|n~aey֍8T*P= +RBm|j؂Kud;2Y^=Rzȡ3(v)Mi*܌nD=B}Tdt?lJƤ]KƵ2.& 'PIlxJ&'9pК DԔHÚsuGXw5uo|01M݄h _=fO_hd{]L]Pjf#P%q0\B@Ir2}{c0LT v4Z+ܐ^Fڠ^yBɳ^+NePj'opCK}hБHMSGsKb1$[a8)r5@nV? B" G t,=j 'G'>BI[*461oX,k [ܜ$7faPX-υ͆|{nxp_;ga.m5zۛX;?::Wi{tqWhQs$hz훵Zu}Bvsav?_GI^6n* }s*}\ wKF?/TgS&2hƘ@RR]_ :\ŋzyB2Ojǩ D`!6vH0/(S0 ņM2ʛzZ?r۳J4a[+G F.jeAO#BII|.-͟TƲ(&![!:Py"O!u|[J/[Uڿ^.͋+g)-/'-|>dͷK\.[yIBpӍqтLϔuߞ^~aN{Zh /rOHiV+ p1iCv^n"%d sQ[Nm8+_ Z&ЕIT'VFh;=.CA!Yb/E*NMN(y]+h[)snRyP2 㲂hZ$0䔇s%Z|6i"?ZXl0UG5@ILje& MH1%F8nbB+gJ1+"X8>5fNLg';AM+23qnG;EViSRN鴵;nw۝dsJȋ¨"IH-r҈?X^bd$64 4ARHXj'/q6*(Z?%Pq? VF)W0 aQ"JĬv>,d )!@s=򤪋ԗȤKME| HӇm8B>(A-:X7)A ?D(a?, 5%jӡt\?Sw%t^ijx14:q[DS-3ZS$xKCc5X">& #pG8."7LKDB@IL0 4A (g -i,Ah'_5RqjHcy쐪M$XT& &|#!c(NA6|ou5dwxsOT*^HلThLMrIC~sⒼ18yvM$t&ruXIV GbP6C[eubQ\óK㍲z,<\j.'q/Omj0gltH-E{6Um/6Ԣvg#Z .5}%Rç&7bT H:ǤDԢf0$Y֚\ 4c*B+6/cۨ=[Kruɱf25~0ـ&ru^翓iAqFArـڑV~IuX[(֎HWtn KKNei#7#-bTjWVOQsB{Vlrn P0Z]h4Xrp&*+;FugY3=2B\  #yD᳴2kx(: ܛ }toU7Bw M5ׂ >P*mRaC }Ri|* ]T B+C+wԝA͂EZUly"j15ƞtcdc>*TcNGKЉ$)jN0zJ#]\ lih>AAdO(pKAg҉]ꗜ"/L[1U2'1 iW1<\z(55Y~u6 %IS;3FQ :%eY&]$' NʐϬ, T2M+;Vh*VBr|׉diUa O ˨\6pCxagB\_ <㤢E>!(k,25?k U-@ C?l遵'5UM D#])BTB_*hPCĭst䚰KRv^ta;QdneϏ*ڮޥaXx5B854 Z>5Ϛ },٘balLOdDֽ:4 ++r2b3*aXj wS)Kh}TԔ2,@qQeɰmTVkYZo :*RLr(ƎCb,\_ɔ1lD.[|0x2: <11#a}tsXעu2׀Y-sB;c@WAˆtɴ>:W NU {4k\q90p9kcrtm:䎄ACo-vȚ++[PBfOSӦ#t͑%B#,Clt~ Y@U_EQ X9Ym"]BZ樗*D@6;iI'k'͊CL>\>C`x(@SM7P8vc0Y6;"DL?C)5jIZR .8f( 5l6{վj3"*6RQq76uO{JBsms:Ubӯa !ZJ x 3JԜ'2RUfCXX$ɯ+Ekm =-^C$+wP[afژN aj'WwF:m/TZ{.Qk ȪW0{f kki_c+3k*4iQ&WVfbe^*3KmV,M2̟Y疦Y{#Y=03MDh{U ˤ֪L^7!i K&KtpGjc1sLrõ|jt42(~v3j/93W6{6#6ڋ?ueދ?;^rیz^l> .لOY34??>j U{ת='jD߿axnKk8G)Pܓדk< eFQk`BHbn$`R5ĔDISlr2u(OP&+`䟶]*&L_DPڃȡic| bv~kʙZT^xm[W,.[0CCz< 6) 35FX=PGqFnr: +ݦ$OHm XE\LuEJh(T`.ŸL.w{֘rya:*/٢/ԜwJD{JPW=̯@:fC={0G'jW&)3Ê,"XRmY,Gxki)?Ix_"TBBY!_dV0Njuǥ(IOOP U5"* v 70>+䜹X, 2G8:8P~ѧ 'f>\7}6,:/0\Xƣܑ0W\pٴlN4l'')< ;=9oneJ})c@ID+݄ ('fip9bP ¦ïa<^/J]5 gH ̪B4܈!1m:r7ñ^լiIj)VBʡ>5" ARG(/d+69آDoICm+`h3٪E9"4 K\5";PXI "E=u%[}׵N. \dhn@>do5}(Z#zvDO5pD; =.9zSCdk{,%bdk2rR Bu`&3(>2 ,dB,bVB-FKWtv/ΘOhDa/ڵ d p|7G (*&9*v}IB .)۪n#t3tb/`7D&Ԁ8JCMfK\\7uYFꆞq+vOӆ.5g./pjJm'yh< P/HaKc/&H\D<- wDj [mV,܊Rz9Lj;*9[ *|;SP+kme%O&3H/QiuSօƽzzz"v'4R,*vP=HF®6i74Ib<$CvW-$0udP r9R8VJ壅ED G UX)-TO(+ԎZ$ZmJlhU;91l]u4@^S33ք$O(؀gTSMӦy1;E{)VofY_- KyWІ k2  02k=PӐ*|`J$Eލ*@)`XT}b&HN|}$a:^}gd`^X`y<9[|72iVЅcBF˧S[VO%ChZDڵ@<  grBxM77Uu~=֯KuWE\_Wt{rүGD$:`o8 f'a`:Nv}T!G 0tp ܌jIfp;܍qWI *ނ-SfŵIx6&Ws~X6NY*oo8[NH@`r݌$ ( TUe?͑3 |k񉽁OWI0nwG6OaCIؘ)eU?=NU|BSk{ɵ Ղv-V4mqo`oaZ406T)Uo^ΎUs c?Ĵ2ZX䪿\KLRL7gkGaJ JMnt0U7ұd-ń[V]gm%ZtYU3WgTxg,w?Wi{|>r=-wDgVݻ4 ?j ֤XPL~k9<;\?X ɯ۟˚ji ~c<.c Jñ^ T(M]|M~{`+RR,XߡL-NLUF%&(z,)]k!|/Ooi800$b,i{yQAš'EhٷX7Ĭw'y6&.='r8XyQ.!TLrJǻ RgB]]2*R$P>;;9GFA5UMo~&S>+SŶ;%7F*cC7 MV]cjUm_)b_]y4@릈*dGTFO9k5:;'$ XasNɧ7d^.^#L^1 lOl/*t4{YvN'Tٍ:vׄk?ON!u̧YU1kOx",ԭR? o oc)򫫼zO7ņQyT_Ϧ\H34C"iSNH;Ibu-۝  |I֡ڟ1d~f_w_y~(4KMMgFjK $jd V|u;=-v&]_m'"gPIlvȗf(mIE7("*SQ4<6 p]yJ38]Ջ񅘈Zde1lxo]-1r"Sׁl| Sd. <z/Hr,\.Q’r[*;BYv.'Ɏ=+or/iWK\hj4Z5YjY=['#T`o *D?t dacC܎HѼb}[fKQ[d89ԞÇg8^mѢp>r@ǨIrb&=s5(W{Jd=Lem)@GV?lG~g*U?1T37ޱMQVY!? ؋C"IYΡBķ23XРxЄ5"4 Jя- TU砮kBtg+@EV)$iRD)&ҧhyr+,~+U_jcXк|;FkqZ j w?:R6&u c;¡LY(0^;Df`rT,"L4*:=":l܎f@4:A;J3:y1g8dZl7H}Iy6ڑ+nmj{OLZip:a[7 3ss6`lvn!{kKGp5hFʧB{ن7Y<~E?3y~ɿN2w!t$T 3Utu|2AD^6Pg}t4bȔ^1n=F"[.njћ0bWSC[NQMEEId*5G{`aK8ͬ2#kAɁeG7B|36g6kG^+c2FJɈB7bS|-_U˂g4},H 7Qf+Q\†5N/%p$&jArk/e5:vIU(@n.23Sy2 7fPy"M4Gq"T?M"OtX-㬨^d''u׫_M "3Rͧp7a)(jtz_ RZu Ul bǡ >#Ay: VPkp&z[Ȭ@̜Dk@@|-ǰ '>[骻Ŋp3mQvp(K49s]Lg t((_A遶@Lł~ q ȦoIhb}8Ko( U9*,$;zP1€9eS`QAhbNͰBkLLy* T}P⿊)dL_u1,bNA{Lh *⁩Z[[KYF'ɦy׃i)GQ!.Hi9r%нZ%G:;$ab"ϹPj[8R|.?9D-T,axya^A akk "7c~)/Ѫ1păhRo!m[` bG ;y&#3AiоQ c6"3ef2Q*p@?)ym(.cq–qJ$ ʲ xKhEF@ я3cIKDyMb4OmCk*hSB%"O}f/Ljw.y.?,eI}Y/%!,\saY}a%ڷ~{|0/AP@# NS((aRybf4JW wHGuGFL*'c4iDߗ.y+fn4u-&j|'T]?Q76HέAY:)^k8YM8:#U88CRToz -!70 Ӿ]ċPhKYu}r.|+ 鷚7fsJE 1^޴ ((vnŔ|HFkbB[XZIE4T&EkUj,YZt %Jt)^Uu9jR(v)Qco2֎L1Q&{Aܬ؈P2A<`ϒo,|eTyc\ 9E|/&1Qu&CB) :Vz0Y,B)`#】ԴDLh ІpZZԔ˘и'DHj $GZbM[!:bBCHjq'A+5kKAb&_sbO:DW,tnxt*7b'Vv` ܕpPfEܚR1pQ(f epbrL.NٷW-M*ǫW*CbݑeZRa|y*3L~z@3ebGN /ze|!0Gfx+ubd!#ʭR^1g| ,MB0yPJ>Ig%B#dØ1;+`14 ɛ0*_,FvƕFǕhcT{ 04`S6mO<ݍnULR:J& :=,*CoF08&rK LP{t61)L:%^) 鬲ډ$4'40oneɚ% ^ʣ  %p% ^&%pmf^y&m$'R2k#Z\:ɬ}a:P)HQs8$(6؋.?5LmrFiH M'q }W8=#5Yba8wrN2" k~&%o0ѩd`3Ƃy gDd0,'G/{L|ZNFytAVJ섦j5A:sRѢ'7úԕ$cĴT`6l ۀڲ^i`އqz(-R@AÄ\qε¼*P%Dȵ4?{Vl%oG4GnűۧV%QMvi ZdRdl$ +*%Y2A  ogoPm4R8йwE3pM\ 1Ai䬠BwKX g-C" 8einGiGJn[p&-20e;l.i9d\e2#<6[v3t񪔁®:V ٧7_PBhCK:hs,ad6$QEf퍢qÎ!-jءę%"%ͧs"!f.x+8  ]oܮcP?JS ,ϊgJCg&;<G0 Sy2!G 4N)AITO=|2H7RsxNM6% *Jǃ4#K*2ꬁw98'e~FKm k EH_4ԸG3aAÜvVXZ."81{? >o0lέcPQ+S@2nM$:М ,C5?5j&OR}RbmMoQ7!=&$p^:2E=)oV [WW܎=N|@^#b?9.C}ίU/Z|:aAN|=ZZ:x_%e@eJ2wbg1' imA=d&wdض-eQ AЧs¾^c~G &YMcqA=M&vUAS ꚁـ|[nܫoIYNAbO!!:,l-[.9N^ 1|Vr"^3fӸ {3BV:d ډ9~>-}RNJ}˔ OrL)M<%qO vSCS|ŔI(SpҽWՑl ?^I+*'2 W\VLWWPk$,8Xd(wzL2K  #WKˈoj| mRn|c,S? ?6lIOQz٩H<-ǝ7,DB3ԔѩxU}|\@B "T РY3 pa n:ͱ15PXCi1J+[ZMڔp݊R+ ;7AgxG1=~(ӺՠERc(=T V\F9A #Òidhg);6 IRj?p92,@)UPW nXN)t}]>汏C)o/[RS,[wo[LT,]ykw(*oSd uw Q 锯oϠc'yuGp2EݿaȇqQm3 }wqyyy}"2,em7*h> ):)MB֭'1/|C[[7)]J z1!! s2\7)N޶ EVCez aT@c6lWh$vc}g ʑJMe;}KZ\1= 52SK5,Uͬp0H[Vyt_+FxSqĀ ,)B? TLh)l B/ԈU`$ I<_?"0P~ӏx:78:3(hW;j>?]_{=h>/Yـ=yLDvF~קsrK{QJ([tB9)]GccU:ݒcb50Uag#tukd$Th3g)Yfz$.йWAv$|tVdN V;mcZ K7MᡁP&.KuI#T;/dOa[PC%FǬA5_qn iCG?|R#7UE-] 8\ %PzSgG9Gar^[FhDaBO04~:fB'0[8O+^<VkKmO _7.TGnTXE4V˜CY&%a[Siz{]>y]ɉ̈ p::q_s„8ըx=MRNd@b٭-V:r$>洧۟1R\O,^-j&:a׊JzMba/EFdC+.1ΑgLж\'ev4waQc\ch[)^'yRR}Gy-G4)6Pnvz6}RF'¦6{9/~)' 9 b#Nìzx1i(F7EUyپc:Nbnf]f"od*oLy(:/vq)1vq[Ƹ F< D)P.Tϖ2mٳ? '[1$,B谈ǯ|FG-ySx?+ :y(AŸWW2SLzE"L!Xqf p b1ĩ 1{. &-+&`ۘ07sNz E qL [pr$CB];+q$A.Bb۱+73 osT$6"6=yH5U`Deh&]X`R| 'K'7|Wm1~{8x zOm:(Zi|^`0IϞ3 ԇ,[;T[ۀcYX eĝ * iu;X/J[Dk}nQ{7/yc $B7amm͊wWa`m RwHtO_iUw3iA@]"0h MҺdyƚS #frJby76= K h!rN_(I신V6c4cJw,$xNV)JyxP؋D{Jl3 K.dǃҀQh )!πr|rX0TtRSsNs5|>+7,+˥MȎOzWQMO90?X}L9Mnv[?%(v}];Wͯڗfqp9";{`}<^>C/-ai!-~9+y1E v Rnb7aQOo`y 8IR6@aNYUYn>`Yf % poE'D׆iT`_4B9QgpRȃ$tq9 Tj|0 L@@So,ޠ|l0QIgȁhSDbdFiCRD0.%O NV\#tG^t$VN< [Gv+zM 6'=d&YR9irxXlY%HRA9Za`,33]CY#wJKn7Ȕ7zFRm/ \h9/ ,[nk[${A'{vLcT&#'ֲDB uocoUɃ ީ52B bsiL-P$Z총NYw.֔kA7*X]XxM- T!kj!o츞hzR|5fjAzB!iwz5hO8-s̈́) H/POKK^r/$,0%0Dh'Q X-J]WoUyu,lx^rIo @ՃJgȗfeԔmm=<$4I_ީΠ\y%劢\y-mFӣcR~qLG,?0S7Ӂr p طZII=u"zp@'gl:9n9MgK;e#L˻JfC0`][2@gܖ{)(K =I,)W*aX~G $NmqIrUnfyO;ٳ6N)l)^ ȅaJ GSn/܆B쐏wO)׾Yց,A>sYV$oD!(BYmRJPot4Z LCh\wYpg9q,GкdNȓ̹EV4?+ث8kS 3K7KqMO롧)x2?`h(o!q7yN}']:&IK^.9%EÝ B D'uUe.H, }P7J)` p])Q@VXS!̛݃46o2oT_7A 8@Mۻx%U~0Y9L:s<)>\K1~O4&4!LU^n )a}fJ64@`z>{tQCEoUJ^6- F:蛙։0r aVdj`߬ѓz?>OHAGR^CmWM͞ $y}P{((Gn>ȍa:@GG!g@w $/6Rc/%+Qj%,"j2s!b&1,BVԘEDlQToq44oNG&lW [M8Wv)hJA-hh{I.k?;Jpm=RfpO4?ckGSb!0ԲRva+3p˂|5<f%ocj?-/fNq3OI&! r | ϢnA^(8迭7B"l ,pF ux|)=^(= B^Pi\%א ϑq| AtLoW0̦C{R !7.Ͽn0&k0e(#ωP^)3}T$ܭb a]},粹'b+ vFԎJuFFh,FI2_>L)dc?b_Oe{)\6OL:[^7cg Z3HZeƯgN<0//"8#N`'N_p%*+g b Q'!Ø2nrU}5rBvNh`rԃ: 6U =f@-Tx׿7w3ٌ!nG6TCW)̍IHm[pVqIAEb6q8eѤ#_T:)ۨ!,|D"'mVDP_N rP8ĥb `2Tԁje d@X ֠";9)\6& 'WK`(G ] 5㪑TCR)}`eœqIngW  R|v P+gJj&;LWjH]Φ9Džm wFCM0|Z MLLxN~@Z;A 1,G[#ٱUWo,/KcQQ"Fhևa&t Vo o,%I]/2iRLyZGނH8^_â7^`Ybb"#9lP*%0\Y̟1D?ÞL<ȏ{AYEgE'ux׸_kj{#}Q6L9WyEˬ]S(UgR>9 Q%ڕl0J7k~ ™̽>#_*$h;63f^L5>0?] F1zWC lM^0f00H4q6:>"TfmZJ]ÔٟXE&6\֐RwdG olaRŷ_j56N4"z0L5=Y=۔%W zgI^,oV Gg#"'^ߴX<UyBPάxɜŮ.@O )?Sl`?WSWTrœm.CӛG -2o+ BݥA9b5i] 5Uu/tO7H:@YrN/>Q7A 5rJ|Myx寭(7ӳ B$* OK&#EH!3kTMJh=(E\ͯ u-.W=۔ zğG;խhQbRSqJ\ګWLqogf=X,%&`:7|x[:zuǗ(T J$+Xˊ™BiWĎlaTg[Z&ԧLT=W4LA-gY@ar cbnm=kt;a4Ȝ8%_~7mD`/Gazy&e?=iU9;7K UHF=w3͑iagqFɔc;\Fs#C$C %aD:8ob@ɬz58 k"8wX,U0:j[]Vvbʩ|f9Iz=K١dӴcU` 7J* ֠]aA8aEikP_QXiAr4c2`RlE6ϹNunK @); p6Hma" X41pshQkw@ bp7x(y7p:uPJ9٦N`SWHf[fArPL'R՗gDAG M+<ZV*$$1mr21 6Q裑6&I}V3ۦn@\%+]LQ(UtΨv)e(Q9+*HOEP1 ۶}<,fїF"WAk XZ >n&H<1Z{n72QlJǀ,w0h;m8}`;CrAKf:b޸I y ^q& "V(G'F䴄GT8E/; $ӴE':/[9JOgPhޏzyRN>\2r 5%;#I!3$\"HY/#6:A` pԃ^V69!O)dxnt4;aoa(~x80yt3!_#en8(hOɞ'f&3)јrsacx壜$6٩VC)79}#mRw H%5 `9T&\e{W?sl۷ufKY{^˳m:q>rm < o;{wRv;!goXGS\s"4T*UUwO4bj/f Asdql)A`I'* Gql>$, 7K^K@:{U|Lg#%v@ MohGbko70 oQ9ʺ|+vFн۩'vHZLT^!G x_aywT4pK[C 0G(^(qx!gOB0؛TTvAӻ)|1p-Rc{A#xN8*Eoz#pHe|)(XՆA=J̋ݑ $9'\Ծ Z8MAvN!cQjJ5(#FKKNF˂u"V3T\xi #C9+vж~VpFj?',TphWPG!nt1nSGʵIZ,TwyL]lv~:T$^'Ks 1#~v˜AJ|ZúXmnzJ 11}~] V2߰1oĆ6Jp'ߨiańRd՘Pi9eYjuEmi]W=VMP,}AnkgZU)᎔/bLnkϓQ+`vp/-PTWBڣb<()CnhUtWMB 3[iuDe>\hX9c) _4>1[:u'cϘS?9A!Yh]j=ӓ>nfOCJ:욠S|r~5 _J^yKlaGn>rK5},uрU<3ۑT?D?ݻ(\U HT J\*ȡ$y:/BDMaLmr.~e$:e${Q #@ >kGt%<5i5?xzb!'?D7*GI~j#FiY IVxT5~YhF5 NRh ;o%,5;'sOؐ"ǀOpPbq!e ˶&50nkhLwOJ.+eo u4G5FW_-9WO@aк"^K[y.%.X!2t(85  7ʒ'A\h#gH) EnjR*wyWWP)ౕwsVH$*Gx1ޯH<>תd.{R=nk$$$Zpt'|E}?1M cH62 *Cؠb煝Rڱ:Yj%j,TG@.spQskben}d.t`7)wAWLɫ@(D⫵3vio.>ơ-KjrIȪhiO-b *hJp]]K[;x]+7Л*;x,R F R(L-~,m) }Ꮿ~7EċS;OV]j0UU3sL&G O{Yᨆ&z?Zn .Α&~緂l)Fz4 ^3(4cp lUER(H↘gcQ&MeR/IK iC]=pt)g^1]c KlL6cZ!fQ5*Al&3ٚUw1`V+Nlƣs nPÈ*3@GrBHutE)C"WzCt ^ھ 3nF(M Z)/E"BtVZVtБ<_Ϻ :㤬mS;0(0VN)X@<_NQiwt_Zc6[E1f&O]5z^fVx mN1t alzuU·W'^(;1UY(X72FXë^.眿]O*Kc> jxZ8v6# `Ks!TaCR'} `]aaqў .WtE1{X8r1nB3ڀ$W}$;d r<M(qmw3Dᮡ7If4kўa|&Gx/8S7!N$b #hA \O6ٻQϰL5GQ^*X< (#`{sy- kMRGjDSx$HtvG|1Ie6ւ^ib{zNwaz_^dht'w͵s1}N aR Z*{DA'QK@|A'vkvFdi㻣@z] oh1ǘa[&KRYy}AK> r_k:Ah ևZ185._*==sK'.Kaǭޛ<_՛ZqT~ IN|rxZs}XG.Ɓk 7Odȫɿ[38γX },2 z˯(  Jh˳"x\d`| ~n=PN@>q士7Rŝ;AYLAݲ:xy R6ۉ .W)bM^M ̶W3R`"LBIm;K\20`ek~T| .3D# 4ise8fD<J5 مy wb@a>4  8_:}<>"ԓjEK2%1DЌ«4A %ܠQ0>=n4;̣፠87 rΣ&&GCz?'#kuu=zJ@N3NAo7F}R js9vw'iy*[_sy:%xG NpIwZh`z#BR(Țke.|c{`1̢.h{[*UZZϦi :٣hX ߆բ'*eOE%Y0hk(C݂.rZΧ(΂rn38?2SYcmIMWۇZ*:V94۴\{@[XNaj}ڔTɜJҥ:hQR.:|tHs"c؛Hc#Zԉz1]Bkjo~Z G5oU4ۚɜ+W2G8?\qs# u!H$$+hg^W >lĕ=4t7^T"K:mi3]R&V m1d`LEmh,9~RcRô^+r#²݂{x20KpRF5">:+Wi4Z8-P0Y4ZL3ڤuT譬\fP~ :pMuZp_f7_yhx!9sȾ` 1Fvr mw(CeFszS3"*&w%"~_a+Q!J! WVu.qz !9>8)ET~,Dq CWIa;*nQRY JNk% <1Iiti).UQ )E ʀz{NC$}"l3}{T_U6z7` <-(^,4Gyl!3_ͿZx_'9i!R9)JV$(*8 2cBq򩍼*:$Ѣ0 9O/嘨ԁaDllQRlP`5<3:t~]BohlH>Nz1be!K. Bi6'C>KW@нʑlAV zgA{=z-MΜrEGR IǛ)^Y1 dR:dک*_\Fh. :!( 4m&A$ZAњ%gVĝ76{cTc&p^uZG3A,jrU^Ќlqg7iC%qjݟ.Ѫ1Yŕ䏩t*HM?9&h$?B]59NcuǏx9O_N$4ԙExA-v7,ݗWy^+)*-`Vزei;(E| ta8p V76[N1rVnl A=eP|볇ӽΠq͢],#=e噗fb&)v99(;D@^t3B@gh~MRbϻϫ-`Qh?EdEek=[$f 4?ݳ$<%JJobM`SSm'5߽'or?4H0`LAk'mzC@B,Tlew͟&F[^8}JnZo;QkMjhV*n1)f,.SoeYHo;h"CX)+bK@uȰtڿ92lӰ>lBi%aUe_ph;Elp<ԯ$f9us^+gMMk+ƅLEFPa+(ǻaWXRT!*R]#g8l,N}v{六a˼csIۣ]BєGfvjMJH2AݔJ.NIw:ӊ eq_yͼ<3 5< evqflhx?wԿZ.Qq%(xE;h)}ݯzmKB t d #tٙd|\CŮiZtō3Ȇß`':,J N37esJF3BR+5ucuyrfK =Ťs;߉F@`ʄ-c|lE2Vg\0j~,CEgmab (vo}(-Np=F+ @]50}E+~{f֨'Mr^>;~/%4mk&6p,p(byUqr.>EeP=\Pnb GMӆ@eb^ptQTpI=kSWzקD lkoǁ͘ζ;qRsSЧ8t GH]D^&`>O0,jTR)yCU{4nC0,NkQ sv#RdhP-q'v쁱|_oGO4N\S|,\l%N+WOWeț'i 98%4,FQ;s).j4T]0  7xIǤ @-bUrRc361;PaKŹX[\[󯠄TCIWf.ujDzwU@p\DzXA?#mxdTXoxE8FyfT zR`sL[ׯIA0ruث# Ś @ޱTP5>b>gɺl,NF~%]SWm͕ک B)Bp@U;i;BxhR(ז\RIPU}~|7EjBGkW*`'&&D2R\_HD%hH4#n-HS(FzB-Pj;wF }qHB><2q|(9ehO;Z1Flh |zA20)c?vM(n.4A2FKPݑ8T;y+)m sŇ)J E2,w%(*gbi$pnEj xwGi +E|Y(\ R#h%xz;\lRPxϑRIhE-SC]~C+"eZFdJoԲv, ^0R֦]ג]ȰkP(g:ME"_]o zJhz>_U/OT'IIA!S co'Ad)ʉb^RwՃD Q,DT=H$ q\IVc\ŃK_MV3R !QlGʛ iML蜙U#ZdbVI>gy_ᖕ@QC!IxVLõk&&=t h#(&pev_xE^X18S~~zh;\a "(G%w5Oc^S | FdYЅиQP ,F &E6%D 4cǖn3~sȑ.Fi[eV:rAFG'Epzkh<=e<,j/u >0I)ϧΆ׆ױreN[HG0h!)n hS ]/ $TJ G(/ESTv+fo&7!V:*YT?Ämy6 4~ `r!|O[AYT2}7;R&(0x5f)+osF~ZMe*@ 33a& 96i -ڻwSF1i^JYsc˥ItTtdQOa*f6V.CjHCz0{EVZlN3sx6nIQ$K}:EM /|~%#pxIdwJaOd + QDR:ݺN#r~B/iL'ջPB * w#dD8R; /' `]H[F㠬qL(G(vx4u2kdʥSc#RSiEJDUOV v:=FDW4s~,%Cn+::Z'2ea,# ㇰv/7rJͿ YGJD?hsXVLEqHRget GS(C5! ?/F*]̫kp{51|MMaxX(GxYh#ˀoٵѣN/! &;(B$q:03yl|l] MAVG e'|#o?(d9]ХYׇuSV_,HN|TGT2'^+^R?}.ϤGTW?c)9sADVDqu jiH=}[7ݹOW+E|:\9u?~lT>uo˟>o-ւz7=8Vr^xv>*Kgn088՝Fa.8\>{.}6O˅|i=ivI~cߝtR0wW~7\lϭo~m2U_:/r<ٺmç|1u[/WZGsVn`t+3bnBwbiwh{7Tހ52+?]]?l5Vk|*>Hr̓۝ Fw~غh\ԷwZ^T|x߸;~8y?G?ܿݓV^q-hgí͕oǛpF|mkՓͳFi~z0(p@Y;>X}|A}bt:ʗQ=wV>xv.W6NdV|v"Wv vq.?h?WZtɥŝvƦ~U/\>v:LIR^G+gW+̟_'w9ŋ/pv}X .V[h|u.6s‡F.~Q_)4v[b8:avͷV$(lvwprylY-y \鷓/ߗ{Aq%[X+?u֚5'˃˻])|??yh> 7OC._t6޷OV>t:խEggùsZjZm6_Y>>mgNO$ŵBh+[ NMpV|'yŷMrZ#qpzz)lamV+ve{ __8EXfmaV li]vNa--4C^}m~:=Qn8:?rᇝގs*Awsuwsw\w惇v}dhOەp~Zr1X.- bP7?~|r;n}m;;l,}/~n'm>|/ T?N7_ξÓBn[}?>;p,+[sK6'oO_?T6=!ws~\:|4u/F{_KwA\_[?Zz_}`e85߇!-tOo Alun\hVn7Onw} ۵q!,W;~S};~L$͝.|ypXzϗ3ǟO<5<-|B4ר>޾]j,?Yj߇g^l7+͇\M{:?k6oՋ"K&?T/4sk7ՋÛ߼:xws8:r{X8lHS:Y}o?VJZɧCnˇo PJ᧻BퟯK[սV8=^qt=?LsVY <=*A82h.ZƇNZ/l~s˷_ֆ/i5v>T>b*_[Žpaծ 6F.Tw?V a-W}w{X7]~szy8 zõqX6_/۹bivn{)ܕnsK>Jrޜ9;Kg>点Ow{GݕB嬷X,5 JEpqVa슣fqvt=V [żVݻ>YeΰEpq kuYI| sq9_::Uvvo_WϊF.ɯN/ŃFͿn= /B_8kWwfn;}y?7w:8KKkKWf>VΚ{7ۃy6o?t@~8.zGڷ۠o}_tY(,}}p>>o~n:ևχgŹ设T-?mGݕfa>/U/GK_L{sŇΠ~R{a۽pt~uskT5y/?.ZmlLЯKťɨ3;?}}ںKrۮwpX\ڼ >y&ww3]qyYwhiӇq4(k.'Wv?/-\;^sxZ}yi~;hJJ~_iKvw 0*氖_-vBg*{s݅Çq} ~rX W濭yQ_V>Us3a?mZKL~ngT/_?o/JY6W3KZޟ>anioosf~CQl}][=-~*եasVvtak|#\;pfr}~{ve6) 3g6&ns!ߛ9ʚ/هJuܧjqnx߹l'so4+uj [Oᖷ2SX_6Z 'NÅ3oݭ>Ź͙F9۪O󹥕AX_F/uۈt ]ջw?Rܛ/:֧+RjoK+7ڣFmS}ytq^X8:h˕Ë/vn ޷vJpYpZ8ٜq07?-_[$Ȍ\gu.n6m㗳{fFn`igJfxSou/~{\5}w;*.W^qyZj|Y8w[_J[CU\>?w^gm {ӵ틃7'k۫s>?7[Gp2i-8):GǙ^m~P|<:v~{{!ʩ...~p_;4ٷBjg;ai{u|3hebʭsOkZڻ,zV.߃~#a}o~qpq'ɟ7?kG/Il<.-wIZޞ pσ/wrNwG'+ayShpC).»ǽG|/~/7Jڬ5N$Cx. {ûh?³Ψ[hONSlpύ~at{S=k~n.lKna?n_z߾7K{߇Jp:0\Tϧ(\[÷Iz77sqtyg~TZ%?}pN}yk%˛kgÙ>VNWKˣ`{z8?ۻ<.:wfͯȵ9Fn>Z}.Vv>TpY/τnow?ϟ~}z?S8_gm[G0Y' 3ʥrc"b$`3@L$fg{ޒLr!`Q!yݐv"I8TXߨzOJI+@BtۜUbһXGpT4q3Sբu/ՙ$!ںsZv Wr!:X=ٲ35xO&*6LcLFr)sA(87XG:ݲ]j;7\tilVGZ6qwdiN"ܢC#xKyh{HǴz7fΉvKxqFN'1L~90!Ya +, YxS͊(Jy %$6܇3CDI P7kQ֍?Q֞ZoP^곑1Oj-zeg.=vPmOFQc&OLϘ'.J}2l 3YB:]/ G=O]\A, \iZ<2=tik<՝n?[\ʻz|9om8?2eϺ칫]H7@[(~))0,1ix\6pO;Bmi'{m܄dӽ9t"~Nj$G pt~v]8/ i5F;%ƶ-IeZGiIVĭ64`H2]&@Vd(<)%"?h#ޮU-5d6EKNɍ ^k6@LgzD)=E*[8GPfQp!‚n4l^E\vܸ=4LzBA(ʂKa𛣦?ta!a<~awaes M& t=D1@Ĺ䭪`O eLDoс OfX|*Otw Ӎ`;[MslM[wYY|vS,XmƢvX?UW6WhzeZGϾ'L;}1&kݝ#KvuphYɢHB;|o]`&x),uZ5㻫6…=W{ߏyss cQ|hL蝑xŐVĎìntW'72|mi"W7Jϳ-;h ߊ%SWGPg7FShD'dj)2:*W&-mVj^\1OBf92M􆬿o0l615qSFs\\'Od[횖93i^KH{`W5mw WvG)+22g&sZ+]h)kW^)}* $f;*~abgJA7r0$bwlF 4[ 4QR}unJ;(r:F׌R#o)YJȔX1;F-[O;e 9[$̽r({.&}{,QǡI=X+y`hPZsP& +G[9WW'߫'˜t#Kdu|\gĘRA.Pq)&-jسW==kֈ DG`N ʒRS- Cy&)L.yz4o/4 4v`O:üęO*DD Whz5 xe'~n9,{/dzrT'EudFμl%;2| o&Q8G,m /IH8z,}u '&l`hNʚta(|/rg< S4̨c$80 iMHsB* $!.cTNsS<@T,,'`RUA!9cq3;W Xf-6drKͼ s*=H I13Z:>8s9ƵxopVPU`d!􀩓>jJ\"6^e &uۮ`hyl/c]] K7$w۸Sјp]򹞺gs s)XCŷ"R]Vَ2"|ǵl/ :V4 )]0k(΂6x8Nm D5KS=@}){[u{;^\d9鑀QMi EYu{b>3A8!p\#T622qD?-3.q;Y84>n4@v)U`{L>R1w=9;r1r')sLIW,(hnkX*=No։rwnZNѭ]Yr-/YHkI}onvFxxYشr)׬pЀpT佁0W8lZx4ÅvMA'/D^DYbZж&ˁ]6v\|Rt pB%aM]U:ΡKgTFHPR~0i0&^nRI'Ts!>,mE/{a{'9w/a|h$}tU\[v1b]7h.ZzWxP34ȓvzY`:Jjs8Ķ8jJ*cfˈyhU`C;FT't+M5!3D(,m.O:PEs3crs9fL2*$%rHnILl_#IJ y">!8T3-1\nC_}ߪ@ڏmeYf"A~`m}12ΫtM63Ҹw[H%HVI0۫IQmg1dJ 44a`Úu6qsRqx.y[qK8Lb=OA<ӓS 1Iμյh f-ìDSȜ2(AUS=a|;R8opyJ[rxS{:Xf+jK8_'m$s>\Et<'//R.#Y!Gu2^;}Э6eo&>Ldy szar8זc7`>tv٥4R* +4Y,vj?7&ffATXnTp (sK- MRxm&qJAפO&zd1:8w &[OEM6[,S'R8Ro"LKX6d.vHZmR ;A*?Mw8i[k$adRqˌ.UYοW6*'0;M=:(wINuw*rQh7{dѾ8bx9*F{aЩL36C.ߖ cH.$ 7x;֘VZ+_3(Ö Ȯ~.PTnbn.Ze+aG$έ j:W,׵^' EqqM/wF$Px ӣ -y&d/ mn45%кty%NYE2GJS҃_1 &@X~;׀ Ĵ [so,Ṯ`lKV.uw֭׳[ymy1Q+{ETñUn9J ~MK2"pg{fZUK3-ӆXa7Ѷפ.2INDj'~S9;AJGFA=Z' -ajGP?ƬFRp]cCzIab1QUg1S;_\1H;ig~;zF#Ԍ5A/¼55at :TV}1fU6_>1`RF(TvGm%h$^8Sɤ^uh4Yɶ ͪtSZQ]BSR~~dy%W=; S8vA;E D;`F3pYυ%B1 {}SGoҀ@ƨ|pvCD[U9yIu 3^zR:o8Y 6WӖx{YOz{*D>Ҿ8axUF-f-Hh2MxD "an<#wapqs Oם8]no&#19wҁB'kdnV•(bKsPm5҃2դ/ws@O Gi2ZU|O$bHȤۄiMPm*@ԙwGg{Fˉ[ӹ\DCQ#ȜUO"y'u3zz!g`@;S! YĢkgX Ъ<9סJž0v)7D.w՛ ̒I?lYރ+iR2iTCL2w7IG^o %5jbM݀_z&5_ŇÛ^ DQt;LCuC^=pU]U.7$ %LaYp,-mAIݺɣcǟ1- TG+o9õ⠦l]ط(y(q>rR>8cId`,Hd^.iX>.;@w '{-͕@۞k5Ex?m4q/p~BC(ϙZIe98c'5n@ZhqBd&WP7ov̉twΐgJlGq˒ϸ`SAj65^r C7*opJR/d#݉q=Zv 2% &u[R Hq==i\u0[G*Sꑹf-.ci55/kz2Tɰ#\g(;I9"4C˵6N[d8`ѝSZ|VvU9:DL:$]cpF@v4HucP,嶤 , ɗՌ Yb{ *X;e!,F_i\ArNPe.T'2\lA?A /:c;߸/,-Bj5jݹCmsN&8ݗj`f$sA51aJ'nõlw|zJ1u㱒'j̡-8 ˦Ǥ_6Pl1'6fYF Z%F1S XF[q 5G0dPtP:>.p?FҊ|tt?g}OVdcwD)5FjP )$mU9-p$怞›;gz Ga! E%mX;oR|r" R>-ޞF\6uLYZK|o0w T3>~췞A˄- $evG2 Ll*!DӇ9X)*E"9ٳ2/Y~n<c\bCu*Qӱ& u=\aR |9ͬRXCa0 7́:;w6I nJvhq$8阉ֱl'0I Q4".W# <0a[ߚCC(ŎSkmu&ەfg̸dڢ7}U@7^"і_R`$]Z֞;zMzCu5l[̣ҡ%<30f"N';b4bC(fFAwTch]bޯqžfBMg77OQǡ?.|֏=XD-[RȻ1`;cHH^t27L:p샛?vT2Iut[onk^FQ.9ǮFr#'=a7T []Qqp/m+wj']&>޴@IN缸C(7F_2_V̮E":w&C,;ԤkR)u I'9O@CA*և R'Wr>8alS>j{HC-Ӟ}o!zċ'vagS4~U1Mo|Ys;ڤ:d-Dtqj9T4TS`nLm#4m,co|$yDljt!َ/Bz /QuvNP?VPflqc֒D `Sx̨Us[Zt9~w֙įI]hPHP=}1vc+wљ;k;q>c-a[ģ8>2s +HeMyD لpz;G0+rG+z@\r=$A:.w0Q4D{, ?sp,%TAi`Bєtb-a("HdM9@ȬM?PX,u=Eˍñs-7N,57%$_FǹRn>LfiSM9^(PdT/=a q yB@r&U_0qv΃!WS|X M(L2V15¾@TNl#,t֝fb:VX`Gd(.nSrE#Yi},A>+qhZ[Q\b^x E3&ia=" 4a'v,*t_--:.=F4 u*')ߴCM"Mzo"~^n:J…s8֝sj$l-TNC5Y=+:b.s&7 xm\+*~Ԓ@WS.J1AuR fg U_نaOM ,)()*泴\e(OH9y$"zݍت+r>D?b8#nQ`RRP=SYyN.`.)oZi*Y»;t55mە4oڀEHa 瞽X='b;^]c"ay͒og6#}Le;> #Czۈ;DSs`6r<8h r{ &T *Df8$:9C) B5ڔ{J.F_3(s:gov)CwmҋʿlkWݝ:]q*w}]ŝ;Hbݥ Brш류E/.^f!ZD10;%[9="5٫`zDHj:ɧMp}SN,.qhf_Gu˨SD9cvȶYLY0GG7C,J)+!fkJ̈ƒ w:p4Z3KT5T.YUY탦8 aT_AK o>;=xEds0o&z?Mf 0 TߜہE~$-*`b!MnJ^46H@&+-"|1C{#ls1gBBSK7=7U(y,:vpqeLf7?<.us%.=O&-jgdf'P<əGu6!Q%&UgG,cҐiyzN\oϜcT{D܄{$9e,$&3қEא[} +J.H{e;|=^6fG@ !14Y$UY"9URBݎ*j;,wpué C豟R}< \&} uG,F_ͰH;R""ShfB/> ?-2z,rafjT>kOYϓc-U#6˂%9!յЍKKk[b^cG]O=?c#Lbk ç!9u{A>`s=1rt/\wd3^J\,mBhW{/Rĵ_{E!&kFӥG!!棞/E>"v/:>gApڛJ%˨ r0E7&FHRjnG7 Osql5NGδϵbɨ$1 dhr/R65#[uP Ľ0l%?:M ~sy]KMmgd&nz]m+2C:gƑ+8j*'!A^wr'Iz#Ǒ~HuƵ? D]ћbetdz3;sIl1X*/ҋ0jE "p?m ŭځpיSM#No;,G^Np?JaV_;C8hI#XQu9zǷpÑ\g>W&i)Q%S`tͭ=h6BnAɺj:pLWE)>Xr/I[ u(1L̪J^ec#'H ǭӗ'3"͕ODD|Yޱ[nqI*w`Qڜ]Vao9%hhV#G`u01֞e sC^v s7;*ƱWLI>iۦj}L7Ղ3wtL4m ub;#U9N[lu>qtfv[2I@N:bu} ͏[!جj|[*(cm40msyz i/.Cu;7YT|]Yheޟ&-b퀡f%3Mn?1BEaI@YS}зa+ȰAK\@Kv &&9)g%3juF3p}D:K`M[lXE`k:9Wy p)LkgsEd{y>uY\a8`/ ja償༻ hI%;1흆Fh|!6iIXʨgA9 IETd奊-FI5[>>8N@\ +^϶=7iJY A1n§EfZ`ӆZ:"ËQW@^I Sada!;)C p]?g()!iJ"Ӷ_oR?cى FiIݔ/́Ep;aztV*Dᑆf`sSKnkS#؞ =ǚvM~sԏ٧{\;۽}m6ƍ)6-xķ z 02Oܬ<ї9ХTɧL< łL Nf6u1 |^_Q;ItD&))'ts0TN:SZbjmm6.5 <%8f= @h.z{*6l4S^De@AfpН-"2c@-tQz4)rYhJR62qNΩ^ ΃S.v+(n.x DX#)D/9ۋKq>_2W¦SrRmL# ,(]grLY8T4;Ů2z Q/sPbzgL !G]}R"Udhq 3;FaU#*A?(mrv7!j[5 Ie̘j)i /Z>nUsm/J!!集hHuQ:a&JbTN"eBx$-2 Axl n5)|O mwx((lq>LE# ,qkk{&v.C!ړ 2*n&"d}r'-J) >RU8eӋh 5 \mtGa5nxg=Jh~*[@ULzuUK.#x 1&vuyhU^/5a12< ,մkN9'vɘwE;"в(v auz?Lh_q8JClDxEnq1K1Pe >7~Ê\uUh{iSPxqӮ5&ORS7'a8W7Tƭ S'?xxZ?˴o]'i].ѿkʦ˚_/}=aw9^Sk00PM0!oAh);zwt+WN7rIoWN1ZE5lJL*h[p^m/5uzCsÃE5o'6Tf+#_- exRgGQ Ru;i|X-!~7ݨWMaܷ>$T˰{=Z)v%u9݁` 7;vxt1Y7#]R,]4%o6ҭR[>'# Ԙ.aPoqjz+JaОu֬5]ncuvDxz)Xļ&p[`< e!6% <6WA5p`X=68 Mq n}5v3>Cm+ F`=LUzk;?3g@F&X {@i3pBRW8a͝J}x#d^gBٸW.׫Y /60s.hKk\)ܲ>1m7nGiЉ}ˇDo͜ n,I^Qtiajf,+7`'îg9t@re\q5=6i3Q+r3#*2eݗ S Zr0 z+F~hW!rW,۫'2 pԀgX]f{#\}w_d۩A:uVZ\zlʥiiHsa ̵`7$iVI̯C-n +/22XWKQC0Q$`I3wP=Pz,W8o" =|mS" ##zCI/)i+Pq*_q(4w67g#EWtNn/ fV/~;|iMmFloclڂ(ܤ DwlXy6E4Y"sByʮ$?%򁌸Ns5BU_^}O,@=v}p&o8G@?TInt^B3D8)v &iTHv`H'{gvY`ء*-aem9PaOͪ6HkzEfw1`d=|: jmNo'1m!8&U%!ƙ JL\7S47sJ/y^R-Pbdrtx4;FGx2EiaU: љVs7-@ Ƥwܢ>T>W$*tkusZ@b&Ag+[ P00*aWsHlXlRwS(4^F %i(&c8Y;;E;24Ӗ*sǵdEJkzL%oa]Y2f9H. jQw(˥̽J%G` &*ŀ 趋1[q1Ღ>v< ;=S(F fCvW'׬qIMN}vty{2>J̥to@ v/3|( T7AM4L7 dؓyOV`\f'g>lݢ^%krc#=owZ;oI@|~aҋ56ֲx `e A{nH]\Iv4in*9P+}>U̙ a @^|m6:G {+^+h5]oz)Pz lǴGT؂``6#In{JMx)P\2: =;Bay9VFƉٞ@n^vwGsгk,`6M4;f\cdیLi(3 X}N^|THBSrPu c(I1,n{F$hn xK+Q:wĕY[S+a/0qm?$ƻs2 c/ @l,6h8HFH -ƼNeB46LÀnvy[:nKroJ}6;8(kf5^[,e&ubCm1{n£8*rXe]h|sɳvg7ZB@Qz 6Ć+^c_'Tzd E qci>Y#bt5A fj$X#괿Ք#Dk,P|{H^8Fn*HQ!IC;=LK0u<͚E5/^iQ {gƨMoCʫp&{+;B][rIF"N` 0U~xε?3[5A&)nv2omQ׊ G}ǀB#aゝ1b߳[ڎ;ņlIdl:۔k66-N݆2fj0\:QxNneC=)fCM+{2:!fisI?]Xyq852\T)0 IeKtUY;+-d*E"bL@]㭄&x@eG@cܦDHpr/%"v&0dڛoP%?iߟ}L?2͐rv~Y'.7K(LWK\JA*Wnƚ-bܐ6ײ#uUHmoϯ:L5m'+ CNQ/VΦo󨑣^>^QV/4[ڏtrlrgE% %^hq9i8캕>n:Ro])2&W ؗ6zj^I8mE!` Cw.3# Lz-_[?.)}78R aVƪ$(?IX:W)-Za`)IڌpT N90TWdȅ"<S?z_m'fPul󇇒s-V'}A]{2XA۔Zyj%D{h췢h%rswQzkRn.i p7u7LV72mt7shp0D R_ eamC|'%]B.UP7B*&rg|DCsws}!^A\x IeI6 c<i$6DBn^(@CJ5l:paM~f۴RlhXlWVmrd @IS.GŕEP]S9Ѭwx*/I6fh9\ӝ_@lJ]^#!-UZ,d0|' 6+ p.7t@c>i֕,`c.Ge>j 8"NA-NC a-' ºv?1AE5<"t\fϯƶZc5&Oe9xڬ.<@JB}SsIFv1H @Zw.JʿY$b-K8ĉ05F2yDyk.!gx(Ma:=Z=l=c^*rV)bWhZ [V'<P ab䙒Q`A?1 \!ikEr(.H ùE;@\hg' f.DuT9^`LDhD*㘿Fn$Y6u_T&V{S㙨}y](yBXW.N4]hɾ|Ǐ ahgz'L'G:yPt3|h1Ry{Ӟ*Dl1a輤Ev:w (x'u7r'6ڪ(!vMBkJ;aOF |^$ |ziȷh!ftxޞnKIo44@\Va  XDž{hÆA E߲=$"閮<56pMVq';9#!^DQj8@q7rYTHc.G8%7,פQuMLƇIp'M^ YwE0I{Z&SC,$Ws9L5pN=jC5UM#!"Br"&8*}"y}M#lF )$H_!@Yl '^za>@lQݹjZG$pI-mk|2юe} 墌9 "esKeG|mqI|LHjlϟky96"Q3>wu>Y(tus{qw&+ ާʹ -`ܲN!KF 񍍺V_bmS1A}Ex>$bMJQ4Mڤ)b8Ƃl80;Hw\YR 7Wk-Kr(':kXv%Cǃ3|O{Z;ǭ+_ϧ8LO\rKduot;U6,lܚPz&C,ȐE,m$=@P{qjO[4}=: X͵.'Y+f40?Փ`#>ڨiy]dq?5 Q e:佁OývܘAA+]/Kt$3Vjwɧ? ,܈lSr$o Q!%i29/IU6ub06tKPD{S'ABv(QneoЌYzKӍ& ;P2MRV}'TC KM8ffӳ\cDc7l0 5X)"B\()B w;tƽV$Z\zԬGtQES氜h=F39Ve돦#Ll?.ˆw °<.85Xn|K'$gqP` b0Ǩ䐦bW̷i9(rpd=rce,{\glc1w=8Ɔ}YJGz>=OJ̶q\f{ ?{wbB$jU U0C1:9B@b^힥Lj ƅ5"ywzcg EXl $MEZSqSQ?ðbulZ4.Q j>tpN鹫G>Q9w3DKw;'l,i v+P ;Lo0\]L~wiSfïKdbєnm3>_/Sg ,|-Z臗xq׽4S޺1y kC)+uӿy@4'{&1Ufa򒼯WIӂ}_& mhoMt_1.)%|YSF6V1O۽1=z 3 K?~x5]QsL?}y"Qmf Tb>kn1V. V| Ieu 5h#=GpU"΋q/^Kxy,v8̓9_4M?÷tpz+~B>{nƺ뾁 6j}eª -TEOyfovx?z(O/;|߃ n0Y󟪼ÚLj]Y<W^EϺ"]3a6QU觗C|r/IB@?|%|\(ITOy˛}e-mn`Uf˻Vˮ" G~EJO74z.L^^G\U/q8>-:3V ]'P> 0A߿^}{3m3?~1}mmկax5M͐f/O 6Nk  }]ccܾwl.~}YE뮮4. 8f_uo`la7{YGK5x\6 1M1ܞzY߭2[<[WzxT_lhiݏ"߮}oOǷ ?e,R5`%?W3b?<?e7o?~d h/>'0跆|y1|]{/?]H~~gIʟÓFo]wD_ݥ\GR'1ۊq>u=ax}Oo-elfYi e}]D$_ƯD97ik_`Jo&`Z\B/ f~.ί?1K-pI`""h`Fo#` ћ+xu?}&]L;&`5lr ;A SWv_[aߞx= -9ݻ]۸op^,fM3|F`]6E?Hx+ w;\֯͏Yw?6 x?-F)W־ ֵ!]~s4"k[Fh*~_\]q^oW\!]t R7kD|?kRAh''z͂ȻW|7_Vg8ػ5O/o_Q Oj+M> 0z@×ps~z?0Q"/_- ݷ n:N< ڠ FīzkyĜ}k_u^ɿgiӒ=sM7a 53 @qcLZ?뵋0T7ߩn(:S{ &o G:_]g~8_ŕDG v /v "k xs|~ h?F࿿=\or}4qJo/]==k~/%A׆׫4~~)lv ?cLY^3OC7Uk&8\?:x&ޣO 0'ub}|Jaau*$,Ly5h3)&wC7У>auKP6aG+y M7K5~1KN$9Cu_^D>Xc(ѓ=x_|.^+'Fu_{| z0|/`Yurb]) X02T~RӘw{Є|ys#l?Amjv????c?w_NN^gOoҏOoNI5.~"ǟ܂^/ٕ_ΉlN/uwO3ؚ[辩˫ ,5ꌻп' @Gc71I Xo_};6NufیDC(`S ^vv :] ~MCB=Т&,5z.[A|Ͷ ]\&߯C"DjU] e-~}瞟?;8z9 ;B wzc1Vz]1G.7g+?:703o<ʫ~ ^O36i}ƻ1}^;x>8ˏ .>+>pCݮ g軧zp=_F %H'q`1q*`aqARIcCCH5W)-K?¿~$W$I|yM~__ L?%r'^Tl2ԯ.m&<`HU;+XkmWoO"qa>F~z?=- X,#zC35o8ɭl ? Úy]s/ĭi\DC;{+>;S}KGmy xWRU#|I%̵u_IfԬDe]x=Jf,οs-ֳ_޾ޒu>]ӏNZ{sOv?@c=c]'0ut{ ПJh_<7tojʬwV>NrjH~-}9?OUĬ=n_}5nՓX] }|6K<=~WcoΙy3x&@s^߮XMx=]-GoO5o`aVy]8O6OWxW x=-N7Omo/9?J?s;Plvj:U_/?\@r֮g5͓D<= y t-Vuv>_O@_'Oz5{nOm:^g(l?s\yo뺖b|2?w/77Y?~OoYR޹i}S~<ҫo>-i:zG{"ë?'jLyRr>6~B8:m^;\+8{7f-{4+Kzx⼏5]M Ъ? oQZ Xi+xu7~kG|N ۗoe3B7`rM`}'pt]IЈL~>Zr^z;[Z@5oԬWR.ç\{39'#zGSmݭy^`' C6}[k*YtܻJ'x^f=(ag`e߼sM=}1#1]F;emONO?:"~|I'/J¾F|( OeMx7Oӿ]ߥ^VGޫ7R_O75~ߞ~pbz_Sn'AA(-_J?|}9ڷ"㯇ZFo\ժ3^EY/އJ\?"Y' ^#^lGO-_xky+k[8~m /߮E;~dR߼ς~A݁INo9 w@~{X࿗<#˿|7Δygi5:뛗kˀiG??^+^~d ZOybz^p}w-Dc|8}ZܶOyxƷn>?Q?O{ߵ _3|~tCge;w -]_!NV/K>ޥnuzA/w*:>޷UUs;_~# G~{9뷺C{Rxi䉵(>? kYKܿ|pPyvŵۣO6_߷wznjwY0XWNxY ןܳmޟ_ގLۥJ6$aߺH7  )Cvk٘"P$(KK+}7vbɵ* (Pg MU[ddDd,xX'{h},^b+w- zj[V#Ff٪uF뾼5rkz y3݅rt)\ԠOݫq,\z?kBo>o[+@WD|Nzk"Z.z,2W+CϘxz%XXF,~b:UW!QoHjUW|5$ 6-T6`^_~5OmnY_3FfF`ƖX`W'6-7-PZ2 K#B J/P_ oݶ,[LEbdYc,}dZ0~WHm;4ґ9) W]ܣD e>k = ðm(ѬDžen;Dlh#e^hI\CX:xsnwXBGRzM# Nm,G;w@8"kKA"*r{ƱbTGELh| hwc_BUڢMsӐ+9M3qbV2S6rx*3[#Utvzs*㷗5|y]0IBf¡;FjcO{&伋᷋x8SEN"F9[鹴xׁS۪=IC ;K5<RQmX ƻg6J),*R+P3qQ8ay`bFb\~W߁e l%_JWLZF{YcqQS>D޷m@)K9=ӓfYsyj)}oWP"_15UT'IyJr[&ԋ҅5"ƃe1t?l25_iLR}R;T8ʳYфÅC\&a {:;'']۷{9;g5ybO.+ֺ|3/0O" M#* p~dzigC+sܧ\HA0[͊PeJz\U)d`Abj``YH );/=A)yӗ‰I*L!׿b~qyC:vK|3!Boz=~ S9Y,u%iӒx'3!iْ\Ě(8ED[b**op`-|Tz¬ӟ@"67Dڜ&gw! ХI DZW+oHcD4Mx}aHϽG|϶Ak:|hۛ&=osjq9W/=ޘӍh1 GkGn`!Ǔ;J+J8]ECz|q1 F#̡o0GVo_d<s$peJoEqB1 ut4ҩ0?`_͈"&m(.cUv)x#^"DRmab"| .9Ho xPV$, kO?e(P<?s^ɰ7h7QS'  a(4B F2Lb 3a8ŋ_!xl997BD9)b2N1!ja1حs ,Up< 1M>51\#Wxe;Cz>'5qrN3O@ǻ%,bti>1s[ n$zbD㲣e&h+\B /\2ZhЦAwo~(P?n~8DlpWv01Nli4‘RRAh BG5@. t]ͤc ųg*֓.C#LW?,AUGqv;#76 ouY^tO@X6O_~_fe>`#-$]hYl^L %2Pw>1y_cۮ`d"x_8%8ӨASGjxj+&3p?P(3(R|QfҴ m)~V@&d>{OtfΈ?yܡu85d$΂1#'pc6jWЭҍ` vg|NR:.}}@+C5E8^G29 jRoA&D=iO>#|Lgxq8;'L_E3>qł.bY"X3^ߡŢR'@( Jj48P(f˵%-S>"ĚO50JNsMpV- Qu&bh';=R477ѹL@um:}!Fayd`疆*eΨuuzN04VZ=4&]NMyzp9œc\gs[{0JJX%[?zn#;<td!D7[?Y(G̟0d@/>M{`34Vv"'@OE#]rϖǃY{+(%UEe Ƃ|>-KHR ggvqud!IJF֛e-)}^oq"oŔE:6eBJ JڵRѷ-V LЃG~_(%rű/TH4tGk0 xCJ$t#K$)n~0@ 6S|W$~88Skv2jS&a.Id^l,R-ad졓Iw1G>[-?_M~-rߡ 0NC-QNSSr̐CIu#IWMYm0QIX$L43̜y,xyy_o/77$"j98 1@#l:#:4vפQfmdR !+aZ[fʋYvt^ХPݡI/)IMb(ӕ|?rW|,앁jo$ ^ sعF! ѓ͞53b݉ή08%99:~ZdDĸTC,ڬqvDܛ _w9 *pJԩy{IE /)_U0a El܎B]ԢT}84d+a']Dm)^V6M1ޞ:j ds@:$oJ&UD""j xBDoQV^kdkl۵6u$<]ZvW#ś*j۰r9!=R TYW.ZcDŽgRtzO`~z[VF,RąHfd%p>RI;eVk^SIv e? #VRq?"!!C8'G/2Q80 )R^TAb@Յ_oXz%xGTv惂kN(riTZ1&Ei7^ r7ɺUd$n2cMhr \E75eoJjlTQl";t@>.3_lKĞ% S Gf|JJ^1:_ݐ"8y[fj $ +!}Ѯ|I8-WV-fy1-H}6. @^"s$}S9l$mH53,5H)TL$H2u1dH2hL(s]D\FV {ly)j/$j!S<\TDo>aTjȧ"gM `4\9Nc,j^˵-IZ1R@)](ɧ'{ D0t9%‰ܣ45ꍶ(گ&0gtٻ' щE?F?0\ӊH}QK0faHǤL]D#?vB\T!bN8 ·/MIhNdKd3gpJHٜ36@uR-(zr '~tHE2Fjf߿{bՌV{xW60YiX-)ο Lpռ ["]"(5V3;G}?,=Y^>T[Ͷ9Y׻ł~:??]lf,sQ~޵ j+dd#A% 4xI 356:lt^@:Y@uSOwappdRHj??FdGI )^M"p7Ѓ7cYLiˬB߃ MaSH;v!x$z7_(HPgF'GVFIl2=|;dȱ2t$TFȆԥ,|UdXOxsݛ࿳n-3]X]BIhVYo3b*|++ _ !:$ ɘ~zQooZƶMsㇶhn7ʓxX2~ (DwPZKudpPu\xADp|A)-'@Z7( ܸVabxV,D6E^C2 u`QzS4yQB[Dܖ!Cևv=!v i.2g?d [Ѷ& 96 lVuzSL S,S/; ,J"PөX&YH.;EY8.ilu !91a؍DUЭJOMT2YK>%#TSXE=I׬`8GՔ-}MW{s:dFxMlnG+Yӡ5AOPc9ֹgJBm` *̮(bF z>r <&kӚ &'XG_`챥;u˴f[4+=ްnTWhJTQd`8r8V\̪*?jn;##'i*}$<Hv6$\O?.IrwvI!Ãfz(OI`YDDmBgKr3ߕRVy'2;O]}̤VPI~R%w>k>oh'o`x{{h!;^I8LW6>'ۗ_1|_hCnٕ bD78C79>0膥E1oò|iOn4y8--/6c 3:)?htNwlŀ8d||˂e8eN)h3w_۝d/Q́uyTCm l3rS/X @\r! zlom0h׻R免Z83q})aGʏ\~EAq`>ӅCO`>7e 4<]|CcA0n*;XI9GW˯2ûD`p9‰:farvɊT>o-_Yy䂢(`$-̻UyoHl>)#˯vXͿᇷz'˯Y4 ˯TI'^Lur6KlZr9`W#>hNV(2Q,̨̕|8ArRƓ)eH@Y~i_[4͕CMsyi;.ٝ) OJ NRU&QܬlҨg;)*el3]peIgoN j!irvr> `g^ܞ~Łns⠇")(սB#cR:^Dֱm4 ;d~@^RfCdDo`::3VIgiGGpݥ:5Ϣ^SOhT=V&(5tF\9?S-OpeH]v@& W4=؍O]Jx <E 󉡲rM.f"Y +~qyWd2Rͨ}u*XǽxҝOsgʯ?< N:}-*+, :"`m*yє:v,vƄ$V݋<ݰ& KLPK72*6ġ]GV嬀ݶUѬxoVt>hI+`W{y2TK6Quӟ[غ`\.ɦ`)TPb;o #&_a_Wx`tbMv|:wln* 0ebp?S~l&TS`yȠ-u=l=Fˬ}&%=5Do>CJ FgfL˲QMvO,}^+w/vqF=Qzgw!ms|NdtAYUҖ;esU!KӔuBoF6 F U>o\z|jT2!Y>S~H#QfQS8[Ny(^Ɂ3jF1Hn\=S0 rvS>щS@RSCUpOZ+ ":wG6V뎥x@w,NaC9kA0UW;Jn4 p+r%IqKW79bkI{0thNf4XV%s/*ӯ/zl%$6MjYWe_ˢ{7(M\QY:R|)I$Ir'sW$[U:J-VYSNAHM|t.I*(΃(5N zFUH̍; /!js6+/Rp'\*U spOn(ۖ˻q۴>Dd~NvܔK(+j;tۡg]ɯs`S~)b$*T0eۈC5:{ q/Tijkh;w~p91UV~8yOsFqT⽮Si*X ;~@(q(GߧLΘ,k~ k#2)QjKX:T`WP|)6T^q,iҍzq5bG{Mw3@+=n mgb0i^v(h.k)5=zw!/.p?C`7q~P-+/1B/,~1w_/[xME}ξb_/2KR=%~I)0(f&p#ũ!G*JVTJW/=ʤFSGP}@(~/*aؖ18^÷G{}F9as.%Y_](<(A\(TH=j&bd:/[1)@gWѴ_͘bvPCI_9X0Va`e1< 0nΈ⛵qJ/û/,cDjOK<~Wd̨}Q 9N(m:L0_=6-Nfw:>9eKjJqqTB8wptYdH.(Y`8pF\Q0C^*V îɅc/YdD$ %~SʐxQZbbOwa D'M6ac4.g,#Q:r2rdabԀT>UxM DU`:| ㈴l6*Z~6-ӔILԭJl`5A|^pkKcM>MӠ^Vqkg󤘔 mvQ{wG01Lwr9ɵN['sh6,itb}-`~8uAL+%A2nDd ɫíNݲq4. aKn\˝횵xqEw̛BX:y#g;)1J`7[;[Fnom!$JGC>wNpԛMMղsѕ8<0؎QcdL3 Xfצ.q F= F$;Vê,LtW9P;,{÷ TTw"~n6_S ԬRU WYryMG|0XIE+0 1LQ k&o,'/B&N}0]JAEZ_y}kB[>#ȉ<3h 4Ŷ^c6Ap2G&lK`RA'- \M|p9 ī-~}I,}Ucx@Uujg4xATͫ zŢY$mG4UQˊ-܈S#*zQ6.,oqBI-16X.+1jG z`7pNk͜}{6ed t c4 +&|$Ӟk B4p5RTx,c%2q* 넥ΣK_ƐXFbr|`fvJ*tGZ s͹)ih<}֟ѡG#CIJ^KK1,?Eia9a|Dtn%Lg"c+jra)!][}:uȓbsآTsLƕ13M=uN͗3fx%WBm+:$? t_KT-PѿTidb\m' ?%me`G'y6s:ؙcбWOcJܹ׺^`|`:z)hާF+CaVd<{76')PC6ϒxv`oޟj Ƭ\y N^ Խ1 A:9 n 2NQl!@+ǟTV '@G -"Ya0 LvjrX[}ff5a W)@j1(c՝(xh!Q=5}$t1n&AVѢt^&l7R/Xj-Uy\$*7Brˮl{.mvM۱oqML3 L>Ԩp .E[8@Ӿ\h B:`rf΁DًȐg w9 3zqA,Q`ݠ93΂Bc~8|xrwa~s9͂N\pϚESmݳxr`@y)nH"d (v}Y`x> nt̶3b},u0Kɮ/$64CB!$)hw$A#r|~TF64Q3S5-`l a]D֫f,(Qd߯N@bBݘMf|1@mIJW @UZv^aP{ ϶[@:X$s)Yop#"odBZ=#c#],Ru/DfI6w*r0?YغMs/Үق⡶ Fe'%U"FeY8*~ז2P0`Spa{{k$tn0dLz24N3?n.uTG}(Ly1q5~D-R3Jvy=㋸7n5g&鍟 пni)"- ^Af}sg!\(alm/)([D:G.QְI{`U2 swdiK "2:`Fr &g{s5y(q2 AZ_B$y]v!F`z"s!Z`I@ LEipK1]X`P^`hv&/0'k&0NyMu<ު!L/㨿_!v0/#cZbfM<n0rXxfҔ,3''*NcJ&injV(˨&#c.K)S1f߇U1Y,a$Z`;Af,d  f[,#,e#P F83*Sk_`羥Uy{nj5(}7TPА)./@8zP.eVp UhMevn;T.~8"'W: vNw !x<aSut flKrst lS n7W?6A;=xe5@p *Jl''ڞ|厑 Ƀrk4r#EJy}1IO 7Dl4']vh<Po8v&7tj}Ld@PQܪ7; (C$1MgP9q< VF7B\@plZ7xLl`rVY"@<36(ٱX"R`Y!>c Z}e;U^w K&~y#ۈ.D:yM>ML|G$>5!h|#[bح|L]K>a1zK0kؘg8 PEwݔr^+MBXƁhJm:)c[N[GVoyX*gY.vTv.k7.ӦJ+= LS t~W9dft s_3zo]չC2 ZU^ѮNJUٮjRIɎޝ&nA W4mZ8ɢiq2Gt-j3j9~iwHUX^Fiwl˥\ ufDr4(gLЂ t/"iDVRFRH*0{*qSmSAݿg0RRA"e"NˣL#Sdts†On%]@-'t \)ii6JGNԱl ^(eTX4e,ۥL%,i'e&aQ͋2m?i>mLB's0PoiSH(2,xhbk)#ʥ\ tE6&xQJ{$,L:@tsi?B*sI!eS>Ɵ(VR>Y;Q8Ei`t Xߴㅩ@zS>ᩙ椓)~zS8ri]Z1AC.g|Tw.tє[)JT.6N낖}>ߓ0Z 8_KrJLAyi ^VJ.SpHvO%ܩvO/,pDw+YޅEjiREn-E>}B^`nFy[5\GB%ܩKvihAglSO)7/- S1A oN(G~.-8+RS?eYXvfvF6ueLLlfsƴmfg5m5̨紖,x+3+ e e5+%v@(sp Q߱!ˉ^ͼB RE5XW|W{ѠtaFiJ(OwHⷾ3dqudUp$e^^&Z`OS)\([ Ѕ*IwCA] $/2 ٗ w T({D݀׹ȱ k9ȼ*țF𭧰}u ˯@ɠf&冝V6xyNY'!fBycTt8% R)hcI4S""E!'&kSXH𶂬.4)R@r1`rH2iCc聤 itku4qEy˙y7U,[إrNso>]GfkULv=7Qxۮ&N׳3pmZkyAZK0VE-sjcj ӘM'  l#]p3@c`l5Y~vS ?ENy5e$c!.KS TzOKyŎhvV/ !K %% F &׻RֱV,aL'0]9m30Ÿ0tu 0-T+g4 U c\.7"([vWMIBHRNvBq݀J(duOixe4/p*>g~aژi)MGej5]oVi\j|%mp;A*Pg㷡ț$$__UvS7$uNyCdqS^"]܅\nUfbR;-aKW|AQʖ,W!e0$ VSԞ {X`O]-+7vL-$ `|!G/あ KH'/]q쇀`+ c`xpcN_0#­I%am.lApnD%yWIt9ˁ:SZ˞Qu(B'pI fvU]8D)h4XMM Α7Cp,*!gTT*7X\N,Qrtk[71OH!:lw@B p=nޜl4el< `;`[IG[3dwQ&]b]zxdV%C*lx6z8 pM i2ú9JpŘd]Rf<ņh*" @+_MU^5T(HIw33SQ}H.Mٍr#*dxt0y=Zw1 /Ɖ`e͇nC5Օ L.X]CYEf7jQ9wh],,_3j:E2dXU&V N: jh&f}w;O"YG]񸟣ٳ6*.>p۵CR·$kI؉_CrT?qiG]N0 dئH F`4w+ {FMDXټrw4wN9R#xqͰep2r2>rPj[p5wV4R76nnnj}7n,-oH2ծfCӣgGxiL@KS`bECDY**Ͻ.82^Da@OŎU];QKZ 6+6xKPF>H CKuݎgax[L!79H 5 MVDD{gE *!h?ӄZ[ނ+~6x-vVwB8h5);u=N?1St,w~и;ٽgyPRw\6^n <l'j/hh#cC;SN0]vZpD?{HO=HQw $Ϛ@v:;~w9餃V)y1/c0@OPh`:9%4!*5~`z~ nhjnzMB\Vk%fgUEi\ؕ#|{xL5KM-k447[+y3tmZEw%YV40'IpR҃{,zÉ{%㊰Cę3쁼F2J@ 7Eyqyԉ=z2W$h +ÍK/<3卲9F#}LU6L:y5T%$DA*ށc*-몣`ydo?eݲP%KWөZES;,:,F6+!ۅ-X\FqNȨ# =X2gLV6Q밯ρsC;BJD 1\Z# 4PA0dΞBM%R?|v0RC P@DU$ΐly,b!-jԌ(&>R$$n˒Р M}0R6 -V[Yp?8z]=Y=}}PL MQAQCcFi4r:+A?V_,>- jA; 8+ph+[@o;G?1<;v:GάcVkb}u\3q=i [),^hy~8 j( ෲ el&`pS )Y+KCb@T,"*kBbzgZu%UmBKxѦ[QoEWxit ȃuǹ}1dhW> VrHhB ;8B|$NE۞.;ya/"oeml/q`/#n^٤́Iؘ]wd[0r[&uNkH[ZF4f+.aM̡bVnZ;Yʂ^{y~``b%؈YR/ƫsi-1:9ENz$)^$lL n,5եݗwj<('|C^N[mN~C~4͌9i`y9=MF 31;PM84y'I lg e{'lCͳ*='&<J* ;AsPT8碯~p5w;ھw|fa<۸Ve Tw&&`ʥ_wNhV q=W &iػw*bd&A}+W4‹ _;a@iZz,Sз}]r{vPCs"zvPCs""gŷ9B| ILLYanP}.l=19fe%|q:~,ϱSw3Y٬i4@828u-2.㕃KΞ ;$v]0Nz[\H KVoqWغ}⺰Ή5{Cv>W ں|}K\ [cRWYgrBB1I)>gEXNS" WwP(t?GKh>/aSf13GT6_Bf>So77G'ͤ.ŧ3b0Eh}UٺiaT#\@H lm,JoXd넚J Z"X|UW~ƓJzTL9F΃E |c 7PC5*kC*k4$͊( g엔b3eQ]e4XրfAu<_¢mr\gm`"K6,6'mQK$Zh&M(Vzͽ1a +r bq3=H^o.Z._Vjc6c5jmWm͛ݚ+U,+$5|xoS^KzF,LjOz$.7%L-˼N!l=t(2,ov??=k*~ٕxy'~EWޠ2`n& $"ImBülg! {7Gxli aUIby?Y<:ςQmy4F|{w6mv)q`KyvzI7ϧФ$_^wO3R{X(Hԗހ ]|~pj.l*&ᵷɣ&n$PwHɎz(SM#&_e5QfX[P]*@XɌ4xo?aI+>Sޱ<7Ɣw,(ǒ9cCɽ.+h( 7h>ʖ7G?uɦӫ 顾^Rp|\Ym,N[mP˛Co6E\ܷTf+8YY<<jt {h<]h>]ǗP:Cf#60gt )AM©~0G za# d.Аð,iumeQᜎXzwt8gb|!5^9BQW G4}qͮڲpwbQo޴C4mW|x:u/"$g{i4] g5cwqEqT7*JtNvޝI &"vG'>Sl(85*r{a7€(Shqx:d5̹1$|FҰ>@P/O5`mǃk owD/ iٍ3={X\ҐxrTSr[XΩ|.Cǯ|&¸ ԅ#x4&v)F=g-DfNwm-.~٩ogd؝dt្ ^i2oO?/NpO'V;.@35a0 4>[ 37^ "IxR8F*Vȡ4/*qoMbZ. 2@8] z8 I1@ ?,bNh!9V U(HɈ*V厊i6OFc90 ť3A@cDT=w 1"K`w|9asۏKsx}wq9:8& q/vgp5ГyGx3KRKvFZrBZ^s*ܻ"*;YR t痄Hp =,gΕUэFnõIM0 ,$ήU 3T0ڎN^`, ¸"YFDj԰ Բz>'Rڊ Ɋۉnk]f哋d^ >g{ş N2^8@*XACg)PQ.#tbO\ :X <"F~ $-WB%0ЇRaF37jbtX]Bb4@F|-h w,.@\E+$!ǽ9>Kt2 ( Ԣvb|oxFTa04F-Z]fw55C޷aCL(Lw^Is˻|"!lc\*^SW[6EfdDtr\(!PGZ_9,-rូ LGq8 QԳ95sd~9J;LÅ<잾>pf EYY DH.t5pa]:~tNqt9",qbHYX㔸 +Tv FրTP8a0xK Py7 zӻ #H`@7- o z~Ǘ+|BCOOW9`+ b:QK_J3nW` D6# l$:Yc%#*ٻ1`,} g7mrqFn] G@G@FU_. LۺY84FnpD؛!-jDBtZA1R|&Ȇa!Nu:0$t )id!`:J ܝ^Y oG&qi0q$7폇ߺn,|gC&q_ۏkd`a[’Ln}[p8Rxґ'pq[4՘jDѣް(L]E)xibp/Ѩܠ hGĀx o0P3} 8>xN{݋ӧ l r-zyѣ/0pLu4*^Þ½c,ne2O|Utt1+b0<7 # |څ6 P0\Dϟo_~88{ o%ETϽktXBi5WpUNOvSCJ1T!~ Et@\{X.btV8\.L?m\+k yХn"W7u u;8>+h! u3,qxЯ$1cm,;Ϗb\tx4ϥލ>MC`)FsJىz"s T:s7X*$HP2]byWxCD=ٌ#䲏߷ۧc<0w=`sqWBD}!wJy }3a Y' "Du  4o 1x{b1cv|Z?qzv휜?Vj!|e NP[sphhp.pz l#gIB} TQ` Ģ1 # ./.,2N5ECIOؚgƶؽ^Wda2 ghq/Wzz;=_^%f,3=`K F-b [s_v`D}gɃ1P\?o|-`g4YvaFVM@L$DY$e;(NH|1fѠx&wa_ @(n< ۧJo),bI^zMbpW4٨\'ڄ `켕ᨺ;<8Iyb=6] ˆMTgs.? ڴT451MOhǏpѱ= +!+=. O!b`Z8Jl5lwaZk+f/2zd/iLyc)LY>f>N{Y1^+"g«sTׁP3~S 2 ="£ =QWa,Xjh%ȖXT5grU.ƴG\0 5M<5 J8jD:-EtEjԋ0!JD/sUU*&^av T$2R!q5JHڇ܃j;=_F=ۚ毂Pm# ^ER@P=*u^;' =V j)o\ jrosf,^=D}el΁'CwfdsԨ"&2ۃ2%^ 0qqOhFEƆy<ؤm[.)RsS0[>Rמ=KqrP.z>pBr}ԡt_HDBxZXh8/AIkPCwp6DCVgZMWJ8DY /5]|P-63Um6Uh/S_n\#0;ж(Gt49^>fF#l+GLbx [bP`ndy8 /"$\)=M,g_vt|GwS Beip 'P9I}N݅25*[P==B/qפ٬i-4[Y>!:MK"шL4>WЍ=>O,I:%)BݯX:ѿ$q1i8?Ts 1,)U^ta~e׸w{ , =|.{  Q!|l2v 4*o&*x1^okX㥲#̀`VKn'v$MkIZ )<`JJ$7x/f! 41`8ޡjE!ب"؊@$Xf4˸=!6Ku]fѧÂN (!P+˨sõz#Nl#mYE^ falkw8hM^1 );1$-[eem>[7:(U)A%đ2NnP݀ken;)N'`$+ :[[uMDB<<kVtEM|x!Өƻ~zs\-sՑ=\khsP&6,-/ﰵ2s5V;tUF0o\F! mvhY4>l2cM/2XRroV 銙ɺ9*:nb5ס~M\־I8";xz+Ҳ U9(+ݢ.JRށc˨}؛Lr*92q{䣲XQk'F\"ݧvVT}etlW s)6ޟHq{"";!^LA inڃ(E]IKiYvgWu5f@SF:|[#}s/pkxnTMϖ+Fv҆0N͋^q jXVxl`|K yYׅ?j29L\ r~9]=P9_젚EYf!KS3vep7ٌJqRJ1]nCxZ>xrz(%V/_:[X}0[ ߎF8G(ݔ6!E@+I1櫳Z LK-0 TyrwyB'#˷{&@> ?՞J Hre`XQb8FrhEm{{ǔ ہX]b)o4VQ,) m^F%K &gY7R?gQ`a*ǩȻD6b?~s=xi^cP>EZᳳq޼ڢJa@ iB9:rY_~[6ddCDAwGƮOq6mgcr톪aM{TDZ*$ml-R1OUra+ x.{ -՜&\Ӟ́KSڱ^Xqc%?_̧4ʼn  4 o&,A\HηF^8h*FExfPJ%dX 7ʍDh9J^$"-͚8#6<Ӝ4Q; 0thϣGZeO/Ph2(;N4vF<," yH@1=B槃F{/v)ilwe?a|GN?l.  C$ٷ'EVY*Xk:a1ZX) >loFij_ m s^PdltKHGኜ1a*PZ!Sjڙdz.e,FA UhS|GZ2 BaaS$id-& Z#2C~<>+|j8pv2(g:H5F;)ʄ=U|o>ȱ6o*ՐGX\8.B.?O)W)ntz ˫p >dQE2&6*P+]"3*W%A:Zrܹ Z]f^2*䱇QACC#Dќ'uɚ9 ߠ58숲g4Ċ'kI5wATQm#V -Bf#shVoކtgė%Ht9rYn䃾^y 3?l:Qܳ2 vUG:<%5G'hK` S8[i2dR2KR7ޭr DF5qv)0J2,/Pr&32Y H>Kg/]1@-ْtZ-KxWf[bO]f@"yL d>6OAFl@3ˏ<ئ>j%ٖ tGy/  d6@*FIyBdST"HL*Hp4QK!-ژ7bӻQ" 1$L!\FU':΅43>DLDpqq܎HfgO\.e1McI= F%0(Lor.P<0('RgϨכ"?FPD 5ӈV4h3R{kgS֜6P.EXIlS ]opfVIQ#IR#+9òL* Ux0}v] tw,l?A #ߞJOXs8,\}TG7B!r tEcbr:1C sOg~]`b"EC&ҵ"ج֕fL߿ 1_Ɠ?* YNg666gMgw(D ѭgl&769oEQ*);eX,-,Z@T` d_XD49XikDT32LE\qJ)pp8فݳ^I,IlhX;F`tP)_˔zb.Y9١ J*,m9B@\80Yz8}P, $pČlte HINGij)G *8~1eֲ 6!5>єy\ >t)YT'E]£ kKf]G4qx̪tԨS%4=lggq"8Wep׺ -U_oo;G?U<{IM.i/@]&Q'_侚loJe$lյ[#Mx7zVk[ֻ{U]ԎSQуjv 7̊(Q( KyW& Ssp /@DPB4Һ(ӃP.JЦzq.f zz&'[^o$oьZL̍H;ɼ:T*!Δ}1c ;%N#7"Ǵ8i.3*J4\̲m1"_'P-Fx};್~Í  Lp |8i-Hg[]n2,m!xpD2!]ѱ`9a J빥R2IE@"ad ? ooY8U]| DpJXa.X7McH7&cZkZJw03lh`j21ӁF>FLD w#r;yHT8,>7kqЧz鄢c0} .)C)Dg{@!pm].06;cLaRJ xs!,h1a%>8-;0(j+ɛgZJ"ձ ~T^rq69=TNwXn|ň5K@!;F+z DW!}ȍer,.)ǡ$[*S *ѭP$#CoR+@r'R駳W՝rBa(g\ҭa!X]\RazN;'Wo:I!!޶?ϺWP5mtpN\^=tyʬ;8tQՈUGr;Q>oXI}>k"|]c]h#3*U ;FY!D$؍Ú2Tl-$SN=ed`1G75ܖ<+s ;u Hȵ/o|՞old*2n gz%-ea_PS!ҚQع>AЩ L$0\cghjfrEs)rF6)奣 8lUsTnm~3 )ZyxJp?{\D^Lyi:g !x1Wc _U #tik̨7WT4*|hi: Euv6g;OUf7&_`(;JdlҒ_l žg'/.VǬ ʭ\&M0=|j]bO?jETN@\Z}SK4!%} ip~t< $<gzރde toګAJ1+^\T}&079kdtH_5n%HvN܋ҝr׮jPvJSc4Tlme>uAnV[h,+=J4z2+sH(hG>T%fGVk6gSZ&$4dIyBULk>P jL `? PA:}nv*Մ8<t=`9S6\K'"Fl6L$kV qL$ $¹(m#y쉫OR4%bQߞz|حEq}3o"&\ ݓ 'U8>`N = ?iE6VDD ;'mu> @ϠDA q#*Up1^v%ӌOA*M .D$dsB:|b8'Xx*hҨyvi#h-V3b+IskKW.]Y.JYe ZqT85f o73x3So??e獳!ngEGqbWE~+ *~XMtڐ}V淅T9m) Hʻs^2Iר Twi؆I8wt/:kn~tqNt)dCO9;le[2prs{q.h"eqӀڋ!lT{ђUqs0I#YͤO Y8뜞nN.)K8F豯"*P97B/g4R}mA_n)IzB=qo9899iXqXdM֠9u^ް:]Y y9T Kn[ilXtђ6[ ?(k]QR|*cf&_ke/jY,@׶ea1rA^e7G~@g!#8sfxtk< /AWzos$O$0\:]B^ܬ.*+fuv<n]N3se8eN'U@˗B%L)'T*t|4s+nU;Xx1vGpl‹e~v`u ‹aOԈBڕ$F JP!+|7¶bI-Si'@؜UIo1&U׏{BP$< >|00V&%s9&nݶzjh{γAc{wjz=~r0>Q.,0/_=9jn67;vsYYi<;|sd]]DZ &h&c)x6̳6}0l@tt=MݘHʯ{&B5],Wwy?Q- T;%β`! 8~&e*W'wvT:Zı!]~o0˪lw[Hlpt]c5b bI; ݍ/泫1#frz%ߡ=_0 ! M?<=3 U#ԆQo:ETom4 %?oR xB~ޝԾzwnW**C}١=Nh;AN& eze 2ƄWNK9Z`Έx<+H5#~\RC# a|#q3[?HNfMQYklv6Fh=k˳ZU׃px[76n;M:?1 k>ӹ`awۘNћ iFpFv{uP ߷7[GۇgG[γ9?yч,}Ql'6OÏԃ(PF#tT=-;? Q}5>z6el 0 QBuT/g}3Gu^6/ԏ6_l7;/wG;muh`ꍣdã۝×l(zlЙT47E4|HŏomM%5=^?xVO_^ ٪onכFU?mtv^Zo圭gNQ~٩>{Us˗`^v^zu6UAk9 f Zͭa<g/'fíWk`n}wryeu<<~^?9ak WG^tZϞ;;FAؽ n=64_<|lrvĴFs٬ooô>knnEagt Մu<|̫Wf[K[ noaU#&vthȷGZN#[?]W`ހ3Ӎo; x.溆Uۻf v;W\<|TzR{]sU T.jU[0lZZMAG}ӆ]E]= Y $[ pblmfg.Yof\<0|F D<iȭs\ 5 rh4 ye/6&d\lvzYfnm ۛ×&,˭W[g$Fl5^57ۻ6wͭg@l7_^nno7[^6 <#11t/k41RD,#`{bC񓖄PV"DF j7V{l^;Rcz$H푨 H# Vmx@l`[= 1qT;~ `np{jln[ \6_vmnL9V*yoC/6G6<4:#`/;@v`w}_?<ۭ5Zf : a78 kY 3ZtpM_t 3u@S]pVkzi'h_]nZ~eaOoE#V%߄:2`*aY[c;a,}4X`d9Х{m_h?(`erknI4~xmޢIEоh.Tʵ'E|M:Nydқ;(v2UPb- 6vn3&; -̪=ս"n#p2dR@e>cdGg]eq¦nm,ps`!rlZ"Pu>S zv!/3϶4,=S+2f!3gR b x@I )lW)'s$2/)h ^ˆa=&y+#=gৃLY6 /Spῥ627d24晔ڠۇ6ŵs(Kq7O8:0KN}XCx}bNGB27DF2LQNț9㔡GPm2Ag}!LOJV k[dJft: CCup11]:p,)4I鷬$ݠz[mn7֛%IIÔ= xeWNϘ5pDmQ9,zb.7B PT; `P9)bk>iX,Co&wPGGOYəϊMбG$D=,Al/Epܔ_?bp(P(iz6jRaXb:<؂o3B|i*9)b'vHZZ &.cTR_?l r*F uaBXꇯ3;F1:Q[d)JJoxc.8^@^@Q`7zW:A/@%_0k#P9B8 $·^pj @asBK6\l|qz"JsbMtSNezkeQh@()F6Me/1+ϒ^r # 3% dsJݍ0rEvL]Ms e Ƴ<rreDyz2zxHD6ͽO { pTSixP)Gσm$Ik|/TkpO4KW^cdxNdDSj7K$鱠O.^j2 6%-9SjbpllOʪ1Rߧ"sg RF5G־XyYvW|qYyªɁ@(ޅq8h,JqX.y.[F< cFspz& z*IiZgi;0 v 6y,Éba7ހCr^h(auwS,I{|=Z[9\M *o:o;oߝu ֆU?gebD'Ƿ]Έ0+<<0XAT1J@XH''?cmz(`&~ƾZd&Jw_ OO^?rPO.GqZ硃sOM98;{0m9#;bGOY9/ F#xQPB!Ho \rݭ^68pύ8~\S0RsԚWgQ1[u : _ұMoi`in"la-F1(T,A^{  Kfܨnf T)b&c@j &?:CN u0;|P=wLG#;R˽MrpnΚ^;8@,@Чմly,A3C>;rUJ 1ORo95y- ~uW"j. }@2!Xx-W#8]e[mM.%J[!m,#rb u\xO%yA:r3~%κhHLr(0⟹z-V~ bo1,ߊJHLek)(BxDX\aזhV̮Ӌ޳ȓW~]}mޥ؅qɿN 'eMl O7r-ջ޼yڍxz YlfN7E#Kwu@q*M%,h4w-Gع΍D?Vj>tB_UWI3!2?LQ?lZߝS2J-6ŏ^02ۅG̛OSY5 Y>WodblA󺦍H]F9ooV5Yq>o xN7Hφj*īdiioI:[ŝcԢ4{%VF#z\VcA82E̽(%j&P{oq 3c /_T*B=OS⻘GBG*VڍW0 r$}*n[+b  l6$S@él F TOa fә+ߌ>I#8uHR'4%NoVB7SVW6+Ţ3+ :>LfD4ʯ؃hon51sQ*j5ܜw}zٯ~w [Ps-)Zmk7{P2D{5eW]VV%,vLK/$,f,31גƖ(P% +4a(ͺV F;} -z%,`vDLni*`Y_I`Ar%Itkdˏ##:k2r8j ژxR5SNk(v) g6e>qj2=G^ J,ž }UǓoC\rxXvGh' oc&\Cl{(:g! ty0M sƧġ@gFwI Go5myd`T UmDޞLE/S,Hkr1l~rݛ(sZ8w޷ۈg <0Src9ƻp `SC ˙ ~+" OTBꩅyuSTW&\TAc8tr/iDh@/ÔnLIBM2R{O=\N~rJ D#yH%x6ƃ,? Sg,wjN*7Ʋ[rk# /`rHyL#҉NtH=x,QH) /Ӂ VQlT:{ #Àc$V_1 < XMXZfvK#S_)9>mQ.DG!|emֹحݾ=Ϛ'D4]S;i]}P E.ijgMJhl_;P3rA X&ء=]c)gmT^NNEjR[TդwK]ݤln!7 *M7y& ; F,7.K4vaYQ KKzܚ*[(E&~EѨlPT.C-.Wj]A:M@>p;["h]ؾ@wEB[QBY| Qfg&I#[h)EA@6PJiȣ ǰ$iIiR9ː,b1E9mW펷66E݈Rr*JeI K Ž1gm-LJgNR0kYWC < `Œ 2v-L`^^q?ELpܕvYQtyE; y]kJ_@y9T1c#ln< $/dgp_Xl֯:GVGcTPOE$,x^WEBq G2v)6|zg{ʕTV#8똌Xg-\DQ#I2֨RKWB>!7[(z./Yķ,9 b "`Bi^eSpJMj0G3};%N %LZ@)st٧qG I^St@7}'DጎEo Y(x*$\,8HI % SMo-zJ'z,QM`~ n0 QMAvsu2p`~_PH{R6M{=x)rf1^nfaX dSݱ.], xC3:+NjG@Z* NeזsM>&4ҡjT:Y4eF%C#_4&3\:t q/YmU1^%~ `* ^E9 *;%2`lOaԕ].MzgzKsQFCvߵ?Wd`E  }RDQ'hDNv$%{SNI 3"?icaIȼʟMCn||>UTn DP;RЄ٠8^/! nOZxD#HGwhsNA 2+wc-|><_,a>p ȶ a8i gZEcѰXaZt5}5mڢ/tAtO ڛQe1Ɋ#Ts8MCCas (_>X 'NTs? ۳TJ"IC(q0M(&gg]Ӥ!C" ݹ0 qJ#41S^8h.H7З977RRn)Ƭx?4M n)uGdR.#*ȁu"WnV!]P:Q{,xM! ;h!_T s?޿uwDn3t(l`o:X\j,!ar ]W넃SR#Lզu)Ͷg6m-B5<m'Ώ^^mh 49H2X1OpJ|XІ];Ze` "!CX1__׺1!SXkz蒛χP{"=/J~ ¨1!4LLV3W8gQ9RZ0ڨ29p#j'WGfT*}9.I`6]r#4 {&LJBNXty N c+QM "rt2!Xy<݀#an Ƿq~j!j[͚lF8fHe\шSL 6pl|,5Ԃ:i2ٛ[ EQqpkPv0@-2h|m1 7Jȏ;YVѡNW{㶮T F|B 8ÙY;+7x]ѽnv^ VMtWsv#m ϔ<~?:5nbOrs8Sy)9 ,Zs8'F\XՖzi޼ZGuu!%} 3` iQtEԵG!d?V@}#b؇|,*MXeed0]'K"kJEݸWo^E~5Ƨ010H!I(T!#tA{le0`$âXCH< %Mk m)@y9b[p-ښT]Ҹ:=W|zhaa_[׍ZIL;;>TvssbTͭ-G}<-"=zRY\ M))o& h1$.iLQ$"w‘sb3rKS}\Si$ēa&papۛPk Ajϓ҅ Զ&Y A% G\¤MKF-r}Ϣ(?>q?)钁^^ɋşIc^q[maϾwBRƏP|k|NwχC)u䛏}>k2 xr_ 9?7j`e y,Z#{-8]iVW_xjUtjTQUhB? gsr'GOQx7ELqxط]fZI͵t8SŽ|AFfUUZRK vw؇fB]>UʯU4$jH` T#mWؤ4ےoBElأKx"{mhuyJ+(.SIeRyƢnn {CvO-%'H!yp;ljk_735Q'ARTއ6Dzmj c%Zb*CZа9&FM῕t+ \5P~ԾD%wvAYea`JS dYvG 0|CGI`4j,[4Bq8[mPTU&I4 b;fۋy! Vc> v폻ㅸ+%0ެnz qaWU8nbbQx;R[<]tW0 `EI 8%F I2րM8 ~/#Pk.mޅ7 xE7s9a^?*ϴQ!y lwx |ةP[L@ך{ RTGڮ}mkƄ5̂^{\\QŽ5s&_ŤۿמqqST JF?Ǿ[QnMxoA׫JXsrvEg@+!F_MfKSVGH!{QR rVs1ylLPe`j2Rn؜< I'C{] }'S7nl㷝6=l76v-8ui?/'gvC]?PjzƳg=^B.ۛR`:27u!g?vκ{;o޼o {`; F3v98|syw&[B;Iu4ֶG6ٕHI+n^k6ZKTxi*)*KN8O1:MWըkP6@ۿƵhvw[泦5IHgfw fkt-I]:h>km4[QZb5ab+f{nZv>mT{RzN)ly!Ƙ/ԛry 9bQzqS: /`ڹUiv(Ut\XƺKbn m23ҜYԐ=U~ LES,W@/zp\5q&yJhc, =VYX3)ʌ$HQ^B n8cݯL#ڽXjD0 .;ţč3@Rw;J!&[ ڒm̌2}799z*8yz,Ìq<3|y#l˰@r۳PV 5+JtEY(jtP2va|0~hl`0o(W>Nv|( cӊ- 9HhI-rqJz@6vp;(`B6r'LU')L 4Zur* J덧}tʲ"ՠwZY{IT%8*Ef4E4'ZČ\a", d>Ȓ"*Y"͆=,#a֋{A%iiiECʶp 8חN)ƘG[Y,O7kLo+L1/9'/j6` ˷U e Ѫqp1"71+6|DW{p鿫G {!([-luuT#r.abk~a"Ī̈́y5W*5_- '&>쿑m)3C}+*+G~Dle2|u-}`${Wil]՚2i_}Ֆ̆PEkEїޮ8]OZD^)"]B{x,sBlRrov#ОpNa<H &+OG)G^Lc;.H;2 'P%Tp8Q'J4"9jlJsg8 ^@R_uBPJxY-7Y.5障iIkH>Pp4 n˶ Ax6R!"Z,o,u\ȱT!ˬdYR2Q>#Z}ڄs*^E*{I `n~`s d Jmub;SD Ki|(= QFsD"*S ]eF>X(% 8f&6O%8/.eł뵮lu_OVKP漼/r^٭ɏj#5M;ۡJf 6d׮∣B?Ƹfl_7j?a?GFP;P6!%…fdž(m60:;m5?@CfD2\:Q45[ifM #9FiM$%O؃>$x$Ω=]GZyHPA`Q0f@LzT4P%"pp$wz*M1ţkJ"]Y>/rT9概YP7-8o‰0f!l uy Ҁk ,8C{a W]>fFT\mm^FݠwM{*qG@BKG>Ihuqš(0 8fA,7YHgO::?'h=zG NX"{ˆs8c.߮W-9޽C?.^}QH9]Q6B);l,t}E8qD Yk,+t%ղs ɱxRk4O;9ҥf}zPHӼ`&ɮ^&4 %-D RRa1tF$N h"(+ϊa~ͣ6uGX2^h( (|ʃLinDJž[$kUcsa,;2 ,)˨݊ȝ6viY!F(u7,enH03aVsd9҂Zo0 6]oξ㬀Y |TVwj5Q',s fFP/bV㻾..8%#[̵MjXx,{!=E1 'e- CܧPc8ccd @RŚh.}KTR!rʚD' GsSb>woYV(B@Om-ux0x7od׮ U G4L4$p{$`jlGm $KQ |dbU )L) %"P)~&]xL8D:Dɍz[C҇%fabDMX9:hšT,yJ#'~zs3㺉azhbpW=l]F/o稧SPm`?{z|5L92[ I !a3jD_)e.RwWWʃ䞉 ?|Tҁ㶗qS4Me Ooh0 1pAiVtx yEdHiL4CR0bl^;' )+5 :"6)@B=-h*a81l89Mdo9i (ckC;}/J+Ŀb6q2:T?9ly_lV75_i9aget}5#Z3+.q7UKB:,"ku.`8KTƏ<÷GEir! |$E/Y0`cZ3g[60LH#p'!G - oFlv;RUM5 %$E\#p:>6!MV[&Yb 0 kVVRWIFMv/jBά'f26"K* H2VzjJ}ܔP}h&TZuGyyc%a6"GGt$0B*!NΝ2 %M)lWkCT k _h{3ѣsu~fv2Zb! h\/a  8a޿"H2@`;!H Nfh7R=ZZ%ޫ}7[:wuKgy^HUNVj:$gmsS"՜j5H|=$:b!4;Qw4@E@xJu "sA~zHa[ LKvtn/ݷMvW]hMk!Vz>Lrr8m$f*PP~ųWyKL#Xb%J^Znr̮ԗ0qrPNpir{_g8ʥտyμ,Fx@}t=4n^_9XdDG;zWGW6l-N)@ ޽*V:d?J-kn 彿 )hXGjS-#2V)e}Vv"vp&dGR0F+HͺJ/)ToU2a/@83fSGj&Tp[)8˒b@Xͨ%kEQd2 ex$-XVtHZgq6$[M D;GY]m tU4Y?๬''GVݚ~Cxͷb)lۙvG 6O``cR^a9˾i (iGkgp!?%|zO;??z{2 us? f27Fٵޜ!{:"t8(l ,,5Mwo2]1f]>na_Io2FgS_8Ƌt wgVv3Ʊad,.[]O*܌5n&i4M8hֶ;$4'kO1,U`/B{!ew+J!eM؎@"'dߙD.Z`lFx;Gzݩoq^[m=o//)Hz@Oƪm6^1z<®X' k* $acj%hKGY"S.SӖT""(%NC^cNZӻҦ[_4#z& ;9]tX<-^uFf6^-ڲh3!I݊9ywQ2$a3)-Jď,;O>n?O o]**~8@ڧHe P@GJ<;s5ӆԨᚶ,X9 2B&RoKs=rʟs;8yN.Z8Z#ط8vwe#*u F4ܮBܻ11ߊ'y \%B3ti&L}ǻL8Dw BvҚ϶nt٦.+0@ »ݰ{l4D|4O0t7%ccFT3%u:yge=xyZIo D9*-.=Cr L4B17 Y܆tQXYC v:ӱ/kk /vA!љ:$V C:e+ ɋ80`h]-÷URԔ(x{vx_^p桺.EhCcp .au:]r m[EҢIBwLTR<$ĤrbD%Gڛޠ򲢞cf'#MIrI%H*<1iW;|H+LNa /C{zS2Ɉ .IƝ֧nu(lwn;ch]bi@f}$MGl\^s>;2.g%)MqCl.hR(cY\`Fᰤ<f#<{|fN6xS(+d* &f.gj#f' *N(1N,UMjc{Z2G~^R'ˆ >胆Na p;T`*94pjvQM_ƶd2fmO (MػͤOv!/aoL%ܜXJ)72¦{ OZ#^7!`umo9yJ2tX #Jf+QihE‰\v- BIkZ2(&.u B&gR BlVi-=%"!β|Xߜw{M9 4|$hV7_>s Y[Zuv. J5 a"^iq56,~?]$>ɴ 7^MJZ>)rn*KX#ʐ_BB3Fs& Z?chUS\N Br=;{/G;o#6ةi~-[g\k{GvhL^½KnCÃdaz|4~W0Iy [)i4/x0mfI?f6Cn5,f{l=YoYJ20R 2zoÅ]yp:0^.qy nAMMpϒq^.֬<]:TBMX z:鮭 ,Jk4*[h>Pi6gV\h XAc Ơ9',N#|q/&B[Jx)Ov/8$YI0tw\`J]zKQUQ{^ˊn-~UTb_jyvteczs|E\PN/jP=.PY=n˭WZe7Te*?V UQUrX_֮hua桹^iu:UݤĨb?ں7^:mޭYhPd>)ȩO}=Wu0FB"UJ^YfN\$e..hY(=LXg6?(gqy֜.KֻS2S<=%O'"" E 4ȃ)6Ԧ^?<#/ ϭZ*!SY}1˒L ApV /&ez24@)gHլ5WFB~m'N-OlmFGJUetunky%EIgP8^rrMvT@\HucTpW71*P0W;ݷ%֭@ZSaj W1G\*¥aXg*#^iD PvwsH erAJ-( 9v`CQ>R\]r$EElύ- [-!L,K/={4u4ՖXHJd*rlb@޳癕<hLgaPค'OE"&pI'+R;eyVޗlȢ,ˤ ʟ$'Tƃ 3A8e  ֚gܬ4l8sVZD71F yZN%1;*["|SuE]GY܍&nH F>r @!'BS?YC_ќZ+} Wbe:`d,zWټa20ڠDgLB@:q2qp}jDwUUc|ӛ_gˡ5Hz2ԵMv?5ycR,φ/ᬐ1V2}#::1;j1 ʖdj 3';㱶])De2¯^[j޿qbmMz׍lR($R@?$ll|lYjGm %Px LBG4v5KZž?RT?BGq~+Gkf HAj1ɀTx>>9zJMkBPr'hJMCVjJDϝ` lxk|,68cl:KE:PW,xmRԽDQL AӬ(n ZMlh-@%La`8K0/I! "L=H3?%:g]Q}YɪO8q6VGqF{֫0k|.C,}6ѧfcW؈!xN*=542fLË[{Q) dzcd;K Y6'<;C:4x0 Fw-u5?|'Բf(ͽd$ #[ѧ. ә_k۝58[O:p.q7M@0}D${OPqC"ZR.goOڍRo;Ir]xd]Oջ۲z_dht"H%1 5I~>9+yWUٽdxt6m%&}jK M48q@QW٘J Ά^_4kn^B{9DJd]eGrfGTHsUCcdn5.w|mޞ-}bb/&GEl ּFڟJH^0S(Y)4&ˏLL2˩+&6U%ѬV F粂ȡ9*ZW3tl7uY!QIҳ )Ji8#y$hzSBMT6[K *dX+UMFcdCzbO_xtSjrP'O֟xd/Bho%ގ^kAZm=R:qc6wÅ4[BNvDB 4KeϹG~8Y)p.n3@3!(YFkxIǝJcWBd7&|Z+ ܍,3(ݔDOa@瀐M^xlS5Xz}kPLPǣpX3E惣;[_E"spT,nɇj3Mn`fQ]I; k۽* (`z]q'(& o}|M ! `+mk5O6q;읔LF NXe؎#KcѲ`:Ib{ pHG*ҰODbfQ$>Ȋ1np|49s/2e]X1N\e 2Ag \A1LF3ijO7k8`>6ן>l.r;TDFOX=TsѶT<^<|{b6~uGɫJxm+ F@epN/O''Ro=JmL]9Y?[@ _k+j' &[QQ+;s {)Z9)GĽJ=f?G*[Lh6"9 ,pu13!ƃcLQ3>Bw.;OΓiv21R?nATlTYb ҆a_ +yGRvGg]2K<'an5-0՚4t_ћ6%KpqN *gñ+!-)8{bh[hrpN&gAq#}!0z_=_@툺KDnD@͛ ؎V $tϚkm$CE^E!eS1sF]%Z"YdQ-,pbK>3MmTZE5lFik<+v2H8cOWԊxS9tߓvqQ7P F(Ӛqm.G͔(DDUk_bxZYzBm$v̇IV*@`& &3!;{{uz)ٵ"#+9Jr0XCw= ŋ^ 4jCBUs _lmů|6&F2Pr]0%ᶛ5{hG@TR'Š7 z4 ! G^ثvI>ܧ sC7Zm?.$gTs?p\Gy՘Y 6!QtHa${zv(,ƔnL\nYa&Jf>qd2̱)ϰQJdo]股Χ7yzg3ΣS['MW{QM(.|EHl 3g&&9U<' 11_X29L' iZ/Qo5q2u:dՐ1OCn_G6 Cݷ遱Or7s:UTO`+Z/͝|KW]`v-I3Ǎ},Y&bR6phҟv_b/_6*"tGAWQW^R8z`q] vm.^%oh./ u8ˏ3Ey*vy_bh8'A Ri`#i4{h#~H0FI aFqܻ, .OmQ٫J;Ce8BoA>ZYdylqV ksI8D2o#7~|Y/ӿDO^#dQ,ZR| W5/@+aؐ&?t>hp٤ݰl<>x^E|Ƌ뛵o>i"A[X_ U|Z >Tv]|LH- gz[d8VeŻ!2@?@hiֆ.=B 'ձ8]SQp^X~vO< ut ^jߗkĢ.$*w `,ŲOCHb.+cqw]0B!a@( U0DF*.uYX] E m w߯kjarT5|KO gY&d2=`ND?튢 T3Mߧ* yT?wW`3'K~<_Rgtp-(Xn%_`=s]o ;n0J]ԏ&g"NOakFb7$:GCg̑)w1A9/-h_*tfQaH'DF&A ]4 /uaZ! Tŏ? ,'µ;G)(x|,}4g-zR5ֿJ&}{s6:D.)H<>b'|dR՞GTeH^瓋ENlP$'UΈQܥGatK`C\f-kgd*h^4./qvE*:z9AV X*❙!ˀ!\&74c"-޴.Wu2ԋ;Md͝?}+j87g!`'b;<}=ޓR)_FyDd W.b6YsKmU)P tQo7Ktl\%հqi?l|,\e:WWWY{0FU!{=ILl2N$ė*!/g w t?]b7 nh4ф۫=ɲ#QITVKmhk@(ĉ0a5`蕩-ش]݃"0Bdaxx#;E-n|_Z|"T \!ya `ݺ&`0} Ʊ^N< MPfKHE\F`ZaK`TA!S{|x7: b`$u)ǚt>'Ԭ\T\zZuoRE+f#0^E%z]0Yo7A7^!0ċӪᇷ΋ ueCű\'+PѸgu$FFqtLi4i=ӺYQWmnuCF ͅ!M#TH|!cOgSm5Cg2r:kT^YfYѾ8N/x{[iB\$zU ̍b[A &')ap9dBE-| Y 4íHV#xx]*,@B% (0sQ{_c%w"*82zs%4/ YbgYrmK_&IF1a%wh "EZPa)AFH jLQEdSb'/WyrEU\:h*)ĥ.;m =E\7is% Nzj=r"HҔQɶ mW |ɳ46*2& ̐ȚQ\Z֌Kn(*c*ݦ=ـ.UX)^fDg MJqxi `1MR>^' BH{-̽=HizPۉ/S5х^&1vQ(Dx03qԑie<{*il׭("> 1K1ʻ{Fc&UH:r8:χwxm[yp<-Tw0/6~W{7aL<kK#1.C;y $QiK ,j]tQ ʤ_#,Zn dEBy‰PY8 E?5KX#`R kQ5dz)i;sWJ\I}I甮"Bkliz|=ffɊLXvAd kqx4.ܿҖ)m}.aM5ɅTI*5 pIAђmaS 7x:ByI ܩI/<VRm؟ͷa@ P Dd|9H%uw xw'2p;qAڗ'E?`2a p(ԭ`8W9G4Pf}4)!B8Fj3Hh F{pZ oc8W`luBam0S>4K1żøݢ[;w^ j0|ąynwFhNY ^GWoIw􎌅 EeyݑXEG:AO“ih5O%*a}Ĺ$C #lUغn#6p{w~zewg siu3*ߝSlL( kLڥbk뻐zV M2O3#WXW=x^ZxE1١yzpo {]j Q, ^(,߿j=\ʼn vkVMF*ב+ 6IN 6i*n\mC~- / U8 SBF$== R7DZXd;^ǒ=[br! F<˻ᱝZz1Hip(F\+ǝ1o&2AhA'boBlBl&c"}%yJ7d-_Eoڴ=v X1n&ZKIөإgIߋJFܪ -z J? a2'yqukSs2ۮ?7)pe)&V>Y\B,fc1k5L\-Qqԋ&vԥI0 D~s>Kbדd Fy[T]I FO=?S@6KbUpgQ2ּ52m Ekm|o`2[CF, =J44P,UB o͑pZD+?[4n< oj{U+YC1l#Rn ZqybVm%^0WX>a?rgywcg?=#? 4di.i^~B.bAH4}'Ӑ`t}OOiz=$r}@H~RF 0do@JP#oaA|sSu̢3ֳ[-Oq7@WpÆ,Uz3QU涸nI'7y,iP֙ІjȞXqH:!zOm[&21;DZ @/jkCB#dg &7%%0=-h#iq*0$:{u )ޠ~?\*8VGlpJ~s9=ix##؞mO߮jZ8(:?_mD1_߀_ PC2)|PRmo: fdܱ8'e[+)G)T t;F;8vYڶryz縏,C,7U1,p+?nuS|x?7ր1 kc[8|b1ʋ+ .> ZDuI<&ͥV6`A@Jxr+Xt޸;oc$uppq&%f{4˯eqCT\ߐU$K rƷt8}vQw~YݰT$~gP;v\cu!=%?)U@Y~>S2!JM¥OD$K d.T%~,$PM/8xNYC8&+D m|Cډf :7"Ɣ0W?0OSC%%Vw( ci Lܻ$c]+XE F@kbi6O&Q77^sq.nNT h8yl 3"kMf=4S Zm;z}ug6vM9gomwط8o۷ɦAMFH˗Aͽ|{{\R@04~crh+$H'~U&Ir,p؀xh/K HH2d(Sc ݤriqs ?Pyc=RVtDTIo4eVJG?C;*0:OzFot؛I֮ Ϣ,;VR xUJ^j`.ӛ-Ͼy{ fkO$\L@o31 BdMͭ$0H4iyݕ.@B7j1vFR#D9 w.<5pF`md h:n*,\+X!([6ѻ\Hs+,4' ŅQ(=(AaUV/> _r)߽qEME /s)r:}TX>#a65?9D9ƣHLR+S=-֌S>͌'E}JrN3}1LLn%#B FGnn$ŷ"6Vj8ޚk~#"Nou! L }FѮ#*ߊJld߷*[ڋ~I/&ZZ[t͙"jܗ<,T7}F`$6k^Fdt3 L-FF~Զ)zuyZd2pόHZݚ UbBZmoPfH &gS=}( t;% #ZʑC鵰SKN]kalBdhu:CUpq4v(rXT_Gmu'd*b񱳅ܢ|KM l 绵4%V$:ڲ!ЋԸ_*]7gGh n3|4E.g 7ԡG1MRQQpLACxt=5\"VW֋U~8>'oTUh-VK6)_yU;"]"5<4 -D?o?_t>v8[^0>ކ٪6u=ڈ6a(_9 a+Jس`QĔŊ4bnQDJ/XTFS4ͱ ",v!J8S_-T[ބq7sOe7LlyߖV6.a ͇UE{`D_$k]Qκ^򢰨4={c0/!V}& 2R .LzhM*/_N2W/geJk/sKc,X.IrvUX* #|%S$)[iz rTlwb ̨mwGb Bڔ@&rt IMcjEaurI*՝m6<ͧI\@֙Ի˽ L) j3Y5g3sV|}~/4lH2/kJġIr]uוTlᵀ63$z|M! kXz;& tB^qVwvb_'tEJ'ibVkΘbh>5y$wʊ%U$Lޒ(XSr5g ([ۇ^-g؟r|nGWa:zjp ~2VsPz>U}2/<*8 9EؖC~W5 +xs˃^gbέO#m|jKdi!BfaQV m[/@,BgRy;PQr~;XKs\}W\ %22ˑҰVx%G%O(-@{6,0g%a>oJgy۩_2I@}ŗ*rKmHݼVji{I:W "H!ć?hBQB?M27LJVRIsLh 2v%sZ2Ʀ:/=*$=jA;/2g2moݢ/-IǷ 0n1| Fd| 91pIy| zgLMFi2[t#{0]_`RooH4`mS]zus {1/=O]p 8 GR+H%o_p288n B6DYЦ[о+Ⱦ(Y(G-ͽ *p̖kg7j| c,*_e%>Hs=ϝi&P*r֍'wz3K%aswa+2{_:#%y5 /8Zs_U2d%okOΑju?vn'gw'gB9@ڻUqoJQ]ԽB|y$Z{"WYh]ĭJODΔuQQɶ>ztfך-lfi]sB7 ٸ첐lqM&I㑭}sAe,X3(z HOt6i8 ~~ e`բ_誐Ψ&25Xl*E6aAk H7(<ԑPO헖} t>~\rl!(;wΉ)D&˹%t ܮ/;aȩQ$~a~683NAkmz!^ KeݫYVŵ}T4UTzdp2Rs%(Į\!]cM|o;jD7c:Wi&=sQzcM$Ӝ{SnD`:|L7O@_IckČ)XH;;rQ]R`5&%O,;񒑇L{ +S$0 rLi-ŮS | =qtH`1e sM$~ɁV*,}]o Z7xs"][-,$U:991g?)qcP?(N8QZҢ/FTZq(/F R藭nA/^o1D dyY6 *G2ANH+oVPDs7mR2Nn,!7oߪ<?xAޛ,/jgMB9H#oyVoC@ q~kkKrl.~%+&#JgU즜ApfνN p[[O=wt &k: !3h 67cBfs:XrF_kkυ㓷]$+,Bav\ REBp,Z-'ǽA$+qcXNb";"Krb4!YH'|?d+K:r xҢ#ț/aUCo8=Ƭ>2zv~изK@zFjgUKW(oNvڪ`j~:Ċ:U*!pN2~EU]+=^KC&aYrO Eh}y:S1%QF'z\] ;8ma\@i/_%]>] dCOy6objsUl9HXaACNPjX XT6UBg tuQRdxS:_1,_R^kMX/')2|c`_7DL𢲎֣諿֠q-څ50}(w8^o¤u a]8t0t_uVPJ*~kUa+ []o[]nm+X\1NVX*N׭3 Z.c`my \yPuրDN Qehh RM!vf^6PƷڵZ߅dS*W)ZP`)/$#>xx$c[¿3jF}vMՏpvK%zfyny l߿p{Q/tN=td{[jVg%VT&ZSfo iǼQ-Knݒ[}jǭ,?I%9d<¿ŗ`e9#Qo j'f$57m;J#uQTI(cj {PH)*Ƃok^V*ug:C%`}vCE+*hBK*G%Ԕ|Οwf;_\-I smh-p`8Fvq¿ıv_zfv,Y/d\:tKlပȓD+?}/\ nT5lJsK rWwANO6ExxQ/5oWuQ-Q=8<;'DΪWo~qq: bs_+QP FN% Tr$ŎH譌8>guŤ e߇zà뽧V+ 3p6@?^_,(owOo*v_"sS-͊tFXoeH' ibשGi"9U 0dQG. SOgr__Y4ϟpUL;eX]c .H Q ~ twPdbw^@9z'8NX})zIh?$r20k3Bx2tv)6j5hc`= Ɵ,»(җ@M8)m\>~x34tr͝dRq , ͧ9rX:!)NX(mC[VJBD?*r^lBD 00~!dr A.p܉`<5eydzwօYQcE/bhr6g6F,hdu)ZȚ+hCnINQ %QFO僜E6jQ}[XDQN߀_p8erNxNJOAjV~/D%;Mt,<=ͦ9΁7Qu#L%qHZ >,i!3M)jҩK<<݉tٟijt cL*更+5E]GxK5=w3'Juzs]n +l*v,Şعn9|_7;t`c_xpN{lgዴ(ÍZBy5T+r}tuhfqhe 5;A-VZJ%[`] 38LՉDP3.H` ΅G]B d$LyUdOTC.z:b',gf@>AQo*3f.$s|G7N!/ A Ɨ F(oC׶eOap(TV{~;|E_SCnUrZt%#E^wA|'nQJ yJ*! 'QsJc>Av1=?WS-hVf#\;aZkW8l 17ʅ덧@u(zTMŊմX^\z0;fY&d kb* 6R*އS EChZ~W 7xI9,FvVYJ#\Ar9=M|LƣR(Lff޶q!^B4E╩x8 CMx{@{$zu(,Z1g -/>q8匸&g'O^3dH;`r4~@a0(sO@E~!A W 9M5t'ahh)W(arU7Op,@[gzd]oY9PDr;)iofe?UdU{Qx )L0[3PDmn-pmWF[}ֆbA_,}j/y_?5U6%큔7 vɪc):J1'Q8I] .lB!]}1gv_aő[Da1PH PSj=8XH/*sfU+hyQSp)=N^5[@jZ'1 p#鋝l4K4 Gm2X]tʮgv@1NO/j!*k DVlot2n)|pCvxI읢(e2Z$;td,ex̸_n=x%5ū-ls*]D tLZ=yV ;E@5V훓&&Z䆷i™`ڢ U$7fӬGwyiŊS5]砹.G'OwO`]. YUwo;De%GVhcscN59>锋[ɚVm?KqkW'ܫ:Mjj+}E`JG/'Y !bHgØ;v=AI-S2feY@KJy_JOC׋U +m1' {FviId}D(p-W[mON X6 ]UӨ2oTtERizgnv 6K&̼f2pw(u6vQ-,: TӬXc/y HIi?.E2~x~<|sEpB&-CO  *Op`gʲn6\|=' &VU%DͽmoG&y;JD ftPzgE/I+rbzD eMVtoj\c!(g^OGp.ʠq$- HR醬ש8aR:'4@/V+X==wZ2)28{2~YG{kTBb-NV)9^.5EjCG>bBs7B~#4Em +8 =DhS.k`Lo*O3~C~z]1AQ<8s96q dpGy{E@RB1ȷY5`HGK "!ȳreKŠsT&ΑfI0Ӥb[ fKdFpGD\\k?BGWDu٬ao9'twXV?w?'YZނvW&:-6aCC=hATU#/{Oⱨ '퇕__R|,.lβx|\\E-;VheN`+\"(70 +eR8k/&jwNh%?kt5I8m+#1/Hc E")?EtF >5bC,oy+Ь ҩ akG4~Ãß4Pؽ7@\;#Oin{V{O#; !^[03j\At\gbL82Y;(0 fפoN#Zy!KrdR'ֺpp碲UE l.)ҠwH>uْe~bD(qiaV-2RDڊ, ʵ|R!:]`FXMg5Hp+'z[O^yC? n]Y +gn2yΦkO0Q ,BrΕۃ2#v`Z`V6u|';ޠKwrt(\ UuJʡ }6a9?]9?U=$+d+nĝ}CIÄ[Q]1JW{Au9nZU˸o);.dAw1e|LoFx1=]Hң*xU/x$Ms;̸EI~R<aPן}$Q])?&c>cMݜeW-jiDV/ zC=v*dc rW ߒHj8H! ]Lk6s~qYSS|{:KFWuWS ;($:>PQ86`O-`LY.OZ Eaݢ$<|Y}L3Hǒ*.^`K+#vUɀ;bFlJ<0&X0ca_t"f]`&p4lsnXm/;x_*Gz^f>p7=zs㛷| u=e5aaW #+&qYۛ ~2{DʤGe_Q<8[sO@Hd%2)Oq ͩG%0J ;_e*[;V9 ]MR0`$ #k95tQ0_jrxYPU_{iyE{ U'°]/hYyڣFJ}z a͜D}0PYcCOv!oP^{T昷Y-I3-X^Vsz2A 3% })Zj*fh*"Ǩ!_ެhr *fΫÆ8<: C%Ϭ2w;{nat4f$sqP}ZZa}@0&R%ƕR?I/tΫ鹼NzxM@)( ը]v\ F]cS24&?eq6MP!uk0H.xY0/f`bYt0X&qsI0w׮ fCP zjc9+%c!=e0^$gHX[svK"p)FqEɐ[PSYmYADЗPVWh+ɖ{h䥠e'|#o Iao"A~;2k`˗;4nUcTu Q/s)nazMH RAg>/ԣ\P!N4f6lh G9DX|tKEiC`;cFXi8tMŔ6'pyi ~irƠܱ|ؙMGԳ ުwO?it:ȆJcNg50ەmK@# ,.*XnF;8~eˊOQXUP# Ge]uɝل⿾aǿ$͘ ]e%]ޡRoN1FEK|,ȝ*vΏ3dYqNblƉ<̨fIceV6hSj8uZkZXTYE|Eܻ+kMIHr~ԐINoB73j7rȵZUG gy"b1nzmcmmwm]gWzazY\Sa,&uzh}t M`RhwdOYWgʙ4,1=$.NIOEM ޒܥG6 !S1K\}67Q~Z~xE?KJ|*|޼ճwu|d\ 'T-e]˩Cg\2!93ƺm:J墢IuM͙)ՠ 7$oQ9*((KdK:Sxj낎!Gz9(qA<91b@!d.`OBZqܲEg˸F=gJkNދ=ar&j(q}rt&Pa6RE-]ny$R{1ƤTJNKe692S.\_6e8Q)#-ωzxɯ3n#4vյC8d je/@d)ēJLAH,h 扤  Ԓ|>r1,8$$pī#TZ-qqMcX^m7I|5CSvг=_rt.O.~Y9Q; \KX*[}_*o]I]rqq%@9&v9x Ұ0+%R9&NFMRّ> "c*F mqcʞ·`aǪ*jM۵59ӈ#> c`K@_g IAx/wv_Q:G">Nwet04etɿkmc,hls|nKpxMxSڇ~}yuZ^_eW5 [ B;^1Ym!?6s06lx`K8WV90QS)a`'E%dĚLRO(Y{A>LG#eG G ߬#,P,oG tdgi3Ζ}S F|C]":]AZ) ka>ʾQFflkᰯ>Ֆ,"8>'  '`3"o Jg.Z 7~"\u˨(E_oLl{~r]|gr:RY I ( Hr&n˚`oa{oƚu,@ULPw!#sZjLhjT¦^ 00Ty7M?c6Y4C|d5õQ,CfWi_N=Sez)- FS]n~*-Wp&Vv[Y+4](BBN iu*¿$\]g_,bɅ'2.Re"+)1rU~ia4 T8 gg{*j̨"یDƛZ>"uJX9\AFSyNA+r~F%kU^}K!EW}<1~HMqfYtw1Wb} f㝟T~UYCL. - "f4z!3^}ы(YC 7th0S/8h4I_t] ~sUH)m$HG!x+ yD/u"rpt>ksPVggu `:(˾?kΓ(z|6mFƪ"tjWI{lYTPb25~뗔돳!A9`/Ȅ}?AgoxrszPᴷ )>OO͘c|Owg߬u:/^o=yy??>9BЖT>Vš|2#Eg1O5dB6v( QBW7D-E oe P(ay@_(zZS\lj&f-ꡞAP$øS}'jt`짲_";֥<&sUa"s!0K;agq<`$h!*#w/dD)*Fi4ݝv$4}ؘ1MRU{5~_kw۫KdSd@)z<=ZI^̠U%C5 7bBNO =DA\1v6ա)nJhUE7D蝐 RT쇈 HWGVB .&Vqk)6\ -4DS:aX6[58Uص鱻:h6&5Tuwf?fAh4*,q8tdD09#7z:2#eCY͕G41-_kQ3Dz}qu]keu֢'?ELM}(M9H5dky9 DtBd82b=ߊ\lvK|rloX_!?$RF&pԏYo^N(I0``@>0h7$1d')(kQDAyUl j62r]TA0`6rCd}9`Izll,O` Y{Q[6q,67)s|?0!0s?tdN?,|W]4z3ls| jhy}H˵h踞T^[ցRt@.8B @OΨܬtwڇJ~ZxV"  -DAݟ% R,7a%cv}kQiK2Gw:@#8^CtPbtAt(O;24a mѣXGiVZ A W 0FV{`j6BdLsX7Eq̐uۼ9V4>O & YY^_5PgI|&+k'"mf[-me6DLX'L9i~'F@e)"YxDyz^ZcT`+|%~@>OodFH֟3v? \S5oEcUGL`n#.R8_$mH۽&\>Xq)8KCc7pٵ㒍։,3Y/dfW2(Q-j[ '[QL{AV3XGԴP{N]ʰRjye\ r|,ä~UŻ~]|]þF{Xk+#3/᜕MXk߶emd-FZ 7U/k5k%?`Ʊ9)F}v [M1 ׯbOuBՇB㭂碨zt0="})0 8hrnN'@Y c# -CKXB!L4W| 4bO3|s)`ErTUlXZ/1$haNMLXʊi‹\Sq^"(HQtBEiE4^E|QZS|_G}{^f3PVp6m\V+xc{8qy'i4X5X[[8!"L9PyM&GE=BK%ʳh FHk.SM$#O;}_!@sB.ڹ4KVzj;]d䬩rtv,DŽ+\M %)%jɩ$p&R-v ,UM!z,4^ bn8mQj(tu#:r[e_>>roKe٠zԈ|{RPѧsR\Zx T>pE5WwH' ow :ʞf[+QKa{1ZS1EvNk D:z- EzF U%g:.Ajkۇ1vPo9Ea_nFzFQ#7V{_WRG:̱<btIm.`WpaIF+@T#z$_=2O09M*=v~\m{\08Fx Xoy|L6CT(eS|~bw/)]`SScw"M8䋛锣bK X+#>Ys̲So3Y<*T H!vxK! a@_-5,t^)"ZNc$3Nx9rf.FiS S^-Yz K󤵍c{4Spz~f~iK7GTVܓY5_fևm&?f=>;烝#>D'|CDZb8nmZccrfY.Pc&6S!lKV77۴VT{gj Kj-6Dr'fQtK 4ETS-ұKXr'ֽ/qP!'pj1=, yɮV${gC{3N5`Ptl~'#FkRB ~0gPNnVax$ GJQӥYa`T&IrzTwRR u 깿= =_?g먧2O[Cևܶp +O4zGҤkVSj٦Tu'}48LHHAaHQi"`6LUT}r#?wFbǿ7{G}KMs%n%4d(V+A>9Nq fZ1L17z/h It7Ղs#%P"_7 &(f !e`{6ѽ`}U-E}n+R5p8Fy~vȵc攉Ջ9f?~|]1tinzxz{(t@C{EJ~U?(b66PQ?ɬI|>DB.a3M).*0۴x# T^xMwz2tt :0DZ 3!r$d%Eĸ¢?9J0<ǃ@X@T vtE B3ڮn Y<  `pk&9 gv*΅h䰆eֲbs*ǵ]?^jU`{Oh1P} )Y]TO),jvAD+ZA=Vcռ~wXmfM}i5d|Ws (z=Hw e$[]V@@p~y?@>eɆO.0ry4O0(8QrMf>nڶrъ|3|V;mD=t7MFF лAyTa( <٠W0 =hn*- z> >n,*3dܓbi4IUx[.L4>MR 8Y $fE||uD3Ɇ] BƔ%@2ȿ͒2z n{9 ~D !S?%[cġA&?DⱤI7۶ ZsOf^ [|}JX@ܪ9JNzY-DRvֶ&eE0TDИ.蓌<*2[[~>mrSΫڠ96bJFA9ke]zY UE@&A!Kiu!xו/݀a@I<0:e IgDĪɑo'( Cn|+vwczL43A* l*(^̋gA(B^'iV ^BM< CQ@0P*kC>@]srv[k;τ+ǹ B݂P(}o`P& J]0ZJ(:JQ˚+ʥqσc.n/pDnFֺP F!ŠP-8"R8GDP Gtt=)PByB)'I5BZrоh,fF3G EOuBmk k~#hy9vLWq2UZY{JW}C z9ݭB=m oǽDR?%4t+7ȖU7[+6N Prp12/eREBL^Ұww\bg& LuoX_,8a( a,(:7ς}K;d,CrҺ/y8a(p+6Tۗ<0`_!)!R ^i »i6PVηBcsl-IG."X,Oұχr+~v2IiI',4(0zP^RPv^*E$cÀo 2\eLW\E&]K]Z7+i}=5֛U*dIIcܿ| Bmn;ԕ}PfƹPm!R"OF#Iqѵ-K }e:F*R_ɛKI Cr(d_ܗW_/y\r(2X<KH{){@69<=1*RDz$eqNA2ld8b(QwӁcV%u:὾=ؐ (Rj}vbEj @夔r()\+6ECAh:gp@ ,l ,#}` 9b!)CBJ4(MUtyx BG/B"Z6/! uy+ԒzA@(~bp|(ob׽#OKs^EAuw@G_fw}9Pv\Ă{g.۵%^{]CJݷnil^tzYg6={^uz+εWⰚߦ ),\E_Tb,hQQ dQ6  uMǽ|tneϮ84j??n'#Y"tQ Afdp;}w{-<gI43F2;@JL,WZ8 K%ѧ8ESŒ&w/R TBV) L_i`N(I)&LMҊ[2 btB #OڪSYY47NtSUU5m 83a*0U;P|Po^9TV-ٙfIl+,7c$"iE&ÀZ xT)!o(Ʌ+ʍ΄NښaXd (vLٕ"RL(eMYa=0iZth:U~Gj Y:_0ΙJrT)gIG|.Q nZf FI2rBjᵼ2o9[9HdתaʱA,~q|dUhU^NJ21 S=2(F3H͊ך>r VaI't%XV$ooFrh2c1 zX2I5,Ǻ.@퇶䏌Ƌp˂GkG}x%F`sJ*õ&sjpi7~W6~`AN)w=~8`YIWTy- J_:Ld *v(=* q+k \Dˑ2wcEWvʭ2pl]e5w4kD8l)f r R4#$ -Z%%9m)TC&RѬ\^ccU!P滬 mx2L< v>˅U=-`|`pL.`0}`BS:nx'TsS$rol 6HGbd`X6(f7qxIS\K1RsH)F rqAR |)Fǣy,QR #:5\ZQ !e^_[{xGJ>ke[O^8m`8\9'5\IVן ngwbޕd+ }+I6wO(<7Qs7=yR@֟='%yrRa|_d|dSL3:#S# =Y)p% HoQࢳm.)`q4YŎ,juk@&.9y{)l8G"x\ O9}. 9.7WҶFUfprs!U^_vqٽ3w2NZ.;>|>]}Q{"ih͖7Q,oL tR']#ԈXdR\Y]-EfpW >\#bPW)JSmSZmMD燕?2OcD\F^HӍo|Tfr8CRrG>}GƳS&qȹ7vR(܅rBIxS wž ^2E]\p,],X[Pvʁʢl*5LD]%,U5l3l4DY1/`L]4b.Hx\--?pj2p ׶oPpȓCK].|撳M)ä8K $k:RCqd=DP.uDpq_%K#"[:EM~J?p1P]C;(o5"9A0Z"MFPM] E&qV_T:+ kA! 2\A [XT ],.z(EHO5N2<ϲeQ!~36)ǥז YusIauw뛶Jmkgץ_}^nOs=^\pYc[O MT*lRټ٫@/* *C2mܼuUKqs1|Uby.GحD830[(맞QN 1M?b¼-'PX2juP~:0W )P9`0HB"h YN M6MGE{yK;F?1^leFKzGW"Qf.bУ%<'n^a`ox3=ީXE0]4&M)[WuH#ggf  +X[\,_\,iuXx)XV~@N M`K){ݣXxEƅA0\,^,ߦ- /˅;>ݴ7YVq9h%‹6bU{g:H!]զ.X[^\F,`l7ɺxxO+8Zfαa2@ߜ}:Xړ' $nb/>+vqٍpBsN[EIEF:ɔ7䅎cTXk鮈P`2^ɐg4u&D4{$9-٭Jv e#yL&TݴXzlx:Zd잫jsBA/k@$\􆓅04 -=Z5f0( 3y0'yk(AXvd6_8y//($k>Krݤ)X9C!'!)$CzLD4fR7ȩpَ[qR6H9IR(%م3q!4{(G5D9F^PG($g@iIF.= -餆%⒤P 袔*P1eaQI3(Q뛚MIK(g`}$gȲXR, mΤ;6"X(ʁ=Zbm%Lo#.$GbfRfS p!yQcHm<$b#57Ge_{2~S,қ߰PjE]4jie[$mLbΠ-r;[t=ZtP}wUozǡ,~'C[+:F(WED5-HՓ>8z] cr-.#=!MO+*BCFj>Je`p0fy @?ɐ̀@}n̳;L(yVU𜗣߲BHkH+/zZi4CD0x PZr .';oON^[#Hi/y(j~$W2oʢH`bL1zUDzx [r"?=p̜ᷩOU{N|(H#CU08 Psv f"Xl݀XqԭC<;B4Noݰutl֥.qkRS ۯ T0/3nqYu= >Tf߯|&m4!ʙ ”6tg|.ir@pA&JR3NGJ&xTx..JèaP\R:3KzB#=yѾrWLdUp)V0Ži%Ǔ,L"ebPi6%[788 Vw 1z!>Rj 9ץ#5_|\]=]N y2ww e21ʑ+ 28A">SH|'t,9M8l o^]TፚBɅ"ɀd-VqeJ=NqT@tЎ70~LXw#p"!1i F鼁|f/pO8'W(աб'xGz$H8PxS\5R# [;+Ǥ <:֒eNfe4@F !DfKk\r4tJ5t s8֣ß?W9]*ՅE,=ՏP#P. '=T,2t2/ wT{?; Je^O~<8:,g zxOZK;z2T mJXjCH 'eo' J [05,1aE%6.FƮ[T GMj=C9q 2Yv^Ar:/26) vnYq@7ޜw5׏{ ǿ'aU%Z<>&?00QwOlc=E}:AhSH0d*Ы{g* ^PA-\CBz}n"Q A3N TXX>sPx <%}044Q7\04uD3}HeBUr~yrPn6M𐘎F ir&"DjU>pfbEGH&Du6sL~=lA kSt.KH%omA dXT^.&hDt'玕Ǜu-*NxT*! 0irtJ׀ "Cdzi9͎VnxujXhNr> JJYd/+9Di^TkŨD}/9{ ]BJ]<аT\+-y4I0\-?SkҖɣplUkyYaVhKAtPd dz dD1,B];`/)R 7aR)͘-VEbx9c#GJa24B[1HQ r[#Tl<>7 FMZףs3DӍ %]&XU5ժ4nVJE0]J+![٢d-5gIykMt廒wK}d0&s$Z&\G\Sǽ椗YqMq)]H' ֩~J ¤QJ>W<;G7%bd! ߕH[%R<ҟ!m񌘕rqWj A](0ȓV+ʫ{LC$bDRdӘqt#iST8B՛ȧcqpnY2q+$@I:(e@؀^fwWrCUf*YrՐƽvWe쟄N}&?J3WIcHzpg 8 =^8o|72#m,=Ǫ":%UdpD~GfC6Ȉv% WɧGwΞ}y3Ih}]hK|z/0A&S̲uqͅWVj4xܒL*R_,"ܼ<kLm嬞;N)Ҥ9?y5Quqš.COuobKU@ɡcG9^T~j)JS*QUͲ)3] ar]bWY6ktBQ#q}(o2# ~a2+3 uG$#Xb [GؽtH$wt 4ͿK\~v9CFä߃{v ttvB^[K*TUɏjfyAM=fyuIA44)AtᅵbZjղi25o4,]URA>J P/ ZC/JaKϯ_!4E'h.q/j1îz̋2g7{e=QNNe%Э.72DJ͛λ̅!nة ÐWviMdaX>0w+Z|A 8L]zN&_D$ '7 *ޛ$]᣸cvcc\P"+)e2KlT[CQ H;0n|Alj-[f`EDcvZa4 jo~$IbCyn_Jf}@E9R95ubM@]:wJ_Q𫼼DQBKFH|\;Ni`Gqrպm#>*l1zCenG]{ےҠs (?V8(l@ 7zګaȊ/+vA`05$GQ(]uYN:cdkt[~H8$xY)C`$fc4zOglzn{#+ ޏ:Yc4댴6ͪU.2W { vy 4kh xNHVV{^WfyDZ)H`f0T$oMk@sgB1sp6tXhC^S݆jGu0bI|.c4г?<qYm!h2H-o|y+ x4@W4N = FKLmIׁ8)mGN}iHqCG ouլNGɥl6ekhu}VEP~זrVN-06Y7ʰ-@YGS0Et | ZC_>x5ϼY"tTpD0S6g6R!ѴuK8:{QYpa‚(LȠQgs/NuHѲP| 5?c؀u"r_^^D|%-Xt3Mx:#V?:Eku&XX&MW_fI `d,ۦ<0H[iȹe]!cO$(O3{ 3CgN^Xm) rO%~!WIFA,W"̣3`'^D|ˉ &gA&=c;nM[H zPW\=V{$B!_d|L/³z=VR_=INCdfdl-P !C6?7E%0)2:$4Lkvc0:u պ:P㞜`Щ IlܡkY:4g䲨g,9h9\VˬTxg$+򢛾 G DUJ^W|(}R`pK{[VRN 2~2UbM]p?0 12±w ϲ9Ѱ rICE;HN"R%h#;Ҏfuxsmtf4PŒ0܉$]+Cb/Uֲ->\` grylb!h}-H+  J=*kZ<..8U#w;d;awz̯׈F %狲'G4 b+w}veE%d)CUhWUgȨ a`Ϯޛw$`/kcsiz׽^mNw}~C9}4zP?'MKeF]88 0(0/w`͈Q0ݿY_8^LG۲ڦ9?zO,W{,mOS+oeOdc\@3N<e;lLQ ̜Xs?L张> !Cj㹍qzx`5齶fC5LL_6:K ܳLdr`!\cum{CovPUɹ ؑ@lD_([)%d;p+ARp|5-yB b٬(-bKeIιG:D0"ս{r(XK\] gfvo\z+x뵗Yɫw*X ,'~.)GyF\ Ԕ ]cmѓuT;afC'Ѷ]coʻ!)ubt~i L 8_ sB\қ"\nm(T$KM8S0U02tE* p6w%N1:r4@>iA Ƙ~Jke'|X }#|?="A#`=l)>>df} js75sn\ܐ,j*`/ۛ?*AtSmighMOWxP #%? .I+FE-:RjX?벗4bռEwLX( MG$#{:`|N 'WGUWiJhw[νhȍ #C);vlV8t3~eONvd& &s74{ACPƇa/'Ɖ8\eUW䖩^:m1*lvh̭OrΰrREf^29^&ڸ*rM",nrג,@w"3:.ge7ݥ3)_fA8^[ ww}DVJ$(=>y_PEN:BuO77Q1KN-E=\ 'oYnCӰOZ w4Y z[Ы!Ň 3aGjvB9hlV^wYjy r_=j~b3m.:oF{X$.,}H_0𔛑_aԂQڮ;og>7:ȵJzyҦd;ɺ~i$^긳x4p&w--pQ8ywT8 VТ#C/٨ԤizU~WnZ Vg-:$|xI;t'^ypGDsުR:ǚܴ p-w_Y,"Mˈ_ROW&BrYl)lW쾕)ȁ]JF~TgW u< ٘sU7eU<{m9xE78d_Ge,E!&2podʀE Csa.i5^c%5ʯ ae'մJ2F;ڿ[V+ڊخ>qrKp(yM-r@\u&υ8a?րsET^ʼn梨1~YzGL\HpXRˉs^:i\ Xc42>f1V]R<3Lm©H>K;(->;MO\@ͲamKb8WȖg[Ѿ#ı\^]3tA@yN6%~3WfD2 Spm{@\-v6*s#a(1Ur-O[G?H8{@uCrrJ=Tٱ I&֗F[U,VsRICy `8*hj3n|;)u)O4|:Qmn `呔1(:{8NF`C\"uвb6GNzDӖ*hkt˸dyGiZk2 ]c yH\.NH*djtNo)`UY`P&#&|jתgtI-"u͂4?/( k:rf/٬~zxm]#qmn T\5WQp|Ym"4ޭݚ\M#T&ForIr H_7 :>*̃9- c$ChaGU4}|$2d?0o䆻} EsJ_h|C[Czj3VS. ? )O:s 4rSq8{,f1_D_iD,dKKMt()74ԥ?/Ày~?.Rm=lsMߙ ޔ_*fV6^=J` & KҠ  ^ 2.c"SA+.xƌ~0hWd|+G}2_՝uC+׫A;KWgW&'9[APt#iP[n)kȀ[ *epywi:ƣmt40LU>> x<G+%t4Lmb;&Dk͑ψIU7Wz:wikhmxs%3grɁX7~H؁T̘5S5aQ)sys8“Q1`%ᐍcr-x7FW4?YUdR/QSIO !mȋ} LÕci(#[3A9)ә* gtسZ)Xo&mi#D_u .hzXh>]erVLpm[_\dG#fe 3~|U RYHhKSk+i~칎/H{jx-^i=o_QC4[mO{5/i)i}hUԠV~h*ڭiZi4eb~xbf<ۜ$!m|6eQe"lKbA[l" P!TuFR*xvlE =_fE@DVM]ULXP,5J:GؓV8BY'rJ5R-r07Qj [)T{>!Z9LA֫V@C ]M%.>O2$cГН]N|8wc\]Sλ EFb!dIuY(`8gYPrr*KpiXM]*5`oW9w_) 6ӨfXt9O%"')w N- HhaZL% 2`IcLA<) P9/Ն)cTjeY',#yc>,z0]5)4hD %JlA 'EZc~=,$ n:,w@E_v$Q'/mGrJOfK(&KHvjQ(U@\NE) 0^UZwE${:i6"1j gX'&WjJ1.3ݱ xӞ  g/l #hSI(/έƾ1Ƒtٌd~yVz8o,MT@}RM;YMqMԗ6ĦSzk!a*PlW7.B\dn|޸-@F2LHIz]vW,B[* b0?'$~nj8[or`ڦ%>.%6$eKO^d5fHa#f2 W!P\%%-Ramg)ih-m:{L [pH[M5PXWqLC&\[*+$6:Y43# /,ZTV iJT@uLn=J;@"]2uvfahcp)t?-[n7c;&LV[,^9(X"D{}X@wsrEdl#n#b M"AyMT$~ m:Q>*nE.#/(ϦIt,ұ% iQ#5ׅ$UNHvʯqSTFmU))zBZ-m6Gț*fS|Z qXL:G߼km8'( j8W"NVD[TY`k܆V" +tpAu43ҟמB}[ﶄDã1ussqBVы<\Ga꠹*]' |Lrk:OқD&љ3;]RNa. ݴ\*,0R;3wAc Y5D˳eVZќ|2>)Nt%sD-//Y=WѣPgz/ݠJ.x_7ߥ_ = qRȟYmawM^ԿE//xs-w+{w 3&WY2AqVښQ^ _ =In$|Vrd1R}*S,,e01[?=|C+|N'tP :8:V^y. q(WA+= \S2"o2h2X8eŒL%$'y4:d76(jXН/wopJ͖bt(`+$mfO%B.q7Մ~7e1&M$.3Ҫoa$=\*2{lډxJ.lUcf'L!mkLbAFwh<'4{>?(Hi`sxMIUao-eS5{#F +D2ʳ铬&hX`"ٓs=ZrTv2?ZraZ5J_OS-*L2ϣ^31ݳO6؅⚛#f.}\ϼu?bt;;5s9<}\,=}?*yTl#~y]JsǪU;Kp4↑PvxTؚ̋j]o²4(c !x:"1:skPX{ÌjEыMk K+YZXx̝\]LXF`NAա%O/X4DW G`Z#a|c,ckpS'ONG1r#cZl)Kc=T<^xa8> \SOC]ӁlY_ X!4 ʂ&p6J-e(pg@& t 4@`BjVߜ'ZáR]=t2.6 eHg0&/v-]g4j4iEXCIqpu%# %3쫛? ej ]$t7sfep>gPeuҝPieuҍM+\i}ӳjkje<]uOOqͫvkCl]VE%2-=m!v1Q ryhb3G_OyoZP uud^Va>$;ݣtiyVL9MAl*xQ0I|X *C7$N &bcl+ݒ a9SLTdl 3g2Lݕ>ybƎ 7 V%($?b4@ƞֻϬT _3;KuٞզƢO$1Via/$%"#?5֕Oh\re9B6C'Tc5XpȢ'p*Վ?+i'- 5`SAÜCT<j3Lz1%v=SZ%=cz:H}2?s Űdظ m<_[|OI{Z .o[8ɛ[t;ql:G5T;~/;U>b=;3B9TQ"ig:G& 83-d]N+K0S}^?˽ J-PM5x&5 oNyV dMτ^{utL+P[g <[.r+Ɗ*1,n(E!3L8Δs^|t5Zÿtjiݥi>S(,v>U&ӟd%? o0Q8Çîګ D)clZ:y6<.0h>Ǵiagsa]VU_+s:c ڥ#!nY/q",sKamůBa?!"/0HtjzPtơ'dz@BI9.fD URe};'b8?zr.)ِ=ŘQb=jʩ]p)G*rO{xq!|4NN},ӈivͺ8gM(ه^ka@Ϻ8ubK CnT#16t_׿{\[޲Cc[Nhɼ|eXU^3j%#-̓_2c7J1 j?i bO;حHw:owGݭN՟#ZRc?ß̠΂fN*rj_ 7tPv #ղ'E+,$I7-?mQW˙@`Y Ix;fupH@XKAHTTGM$]`qvS^&b~ 2!Ҵ+|Ab9q[S/ӲD˳ qլxjr9q'3!>ĵrm/W$̪K3">NP+~MCGд'55j#;vwh1evU!@ȱl9[&lLcJ:fu]AieX aE`mcqi>6&ꭦE9 c0|b];M{5SaA1x|(=_ x)5¥12Z{!7#J̐nVN'YFHpRcfk\UR 1 [&Nn%g!c ol@#LAFfM}(.+l{h% J~X`}'gt'R `t4,௷DgL5(Cm]L//t‹8 C^#KH^>NM8M'3^H$Pm>TwmyjX9* q( c:,ZOQR#iV z_E>m||~8ȪZT:_7 M'}^]q,}<60ѭM @vL},gt2Ɔ]RVSJѴB|6gSqgԗRC33}4 4/S\q@ͭL)XX{a*J2xeh'b6([ELQ- >P^ }r?M EnԲVJǝz{I`CFlBVXaX5D5FWVhP[0ť8Uң-3ǹr3u&CĻF}J~ Qc4xYOe hg:@(Zi䀨qEnȑ e_,D_'+z탐@^}!N_2YzI!v4ۚjDxVŝd9;, Yh \j~k;z!hm#p4w!jԳ$1K:iZ;?񩂼<}eOX1H(@#WceYn_0qkYʯ허Jڭv1_|{6D_|qi;?V_!X]zeY-5oP[;2ůcةp'YDn|D+$$쫌gc)̕VDqzbg=f"~Z.|i5|D83 `d7=m3s N?zӿ}>pEs t͠XsTLJԪsM 9 ҽof5|6y2A(978-opE]U,vos!ߊm~^Mbl0Us utMn;(͂4Pv:ko@HDJhQܝPy}ۅAQH&Cv|Qv2ZN6B=;E.!܅Jb*gaGNMRa5VZ᫛7$z4GX)k4BL}ufAC.Fږλ~a"g]Saa}V'VJ2D]h񣾺ۢ$ͽݴMKSc._q>Ib^ OXZ/7Qrgl3J89N@r4&fj _3q\[B; "hsf=ѱTY+$5dqrTN96Wx(=e[vӻ?ѻ,وix5m_1pTjҲqTVe*e~v$]fB!4v+3/7+iẃ1i1gK r4O~/VOaz2E_{uMr:> n=kU\^]Y^i++kkO:[V_4yI2Vbp=;YXK6mѣ'˿_wF9]~[J7RK?l,__K-o審&\":o9Lk1Ik[t%;i%hW蔘8Dף}:_-/q}\,Ӧ_ M_'KDIqL v !wnQ'g"{4TZOFb*)*.CT/&~Z]>c3s(VxKqqٯ{Da qaeQ>SX8 Ǻnƒz4v(xcå|ʟ;Eƿ矮&r'E?ZO>{pw]z[qe7ǿ׫?TAMBOT8۟0۱_SSդɕ,@ŅYWrLaJ_"%tIh'~B̆ǣ$^p9giG'펯߆lY'Am>ZB?tI"kG+CTӸ?UN?x,{ <ח'ssDٺXԺ }g^V(y\uvH6m}äQglھ D.n6ӫtʝ/aRn%B$^#>҆?LZ$hESE:=J_?%`A/o%8'՛רk|:>t!`<{ d]Cs sUg+/*4/b );` ưWov7q_C~O=#[B#D5H{M|Wse|(㳎tX^DE's[a3gRWvW8)CCXG,9Yl\j^v7b[@(i*hWW&([-:K}ŔhI@pNS&L%tӼ|h 6fӳKdcrMdWj#),G+aC^B~)}DCaLJxr5jJFkOay7ͪڔY|tD"YH\ ]P''V`d8Nx59FZ[J~yW_?~n?~YW_oYp=~`TŜ$SSKԀBր8X%;L+"5Z ֛';c7lH4Oe-} iuzcZK̮ttcYJrc56 xu]5r4 ư՜ƕ.t{3&mIHiM?IGo͉'"N<& cYuc!aK֘|if6˦{Krj83vY!'VDj;lɈKKbD'F V .>Zpӥ=sH/˓Kp 2 bZO=R+Z>k>n-?ƶo$wrӯ?K˫!|3Dg7һ⯹kmqC3xc Rz/GiX1{66$ˆ-* ) jŖz3UW]o\} 5jCd ‹ 7N<*9wh 1A%AfA)'Kks69mi Q.M:p"x%_=^C]|~R GHrɴӝ{ǿiJxYǎu}S_|H OwmSm/#(>믐g[|U_Vg 1qicaˇK& @X;ES8 R fE@=SK}h- ,aJ;3IWصZhla]MMy!ݺhuaD]IS-of['q{__H9U+f#c4YšQa\o\޲$OS֔S̆p4xY!1]0*;v h,1TI(hA`d83ި \_UX7aƪ"ݥRZR927`!^ KhݏT|&"tŁ߈@xjVs'ՠ7l1'wj()h݋X>u-h]orQsq}edOXWޑW%t>Cv;z_g :Z(yf*7o88F&wx9ID_Yas \辷xloy9_}?78H^(`az]R{#_I/Zc^vwD9Dm0]̬~t˶cFSyϟ$J)#vE{Iij> 3\%_jm6Q6$Ǹש;Y@?Ş|{F\dlI>b`,^aqzX#MЯs߫,*qo@lZ4wIp;cNwhY(:E0j/tUlֈLppgW ƥ^y4fbLt: 1$+ij Yk<9g]3 +-:x=)]R)qҿ-+O8B o[gs*iX늼hVK] }U XY荶{[s縹yZt4=ʇ$ln{Y1>sOg_V4Ѝt;E{M BcV ѧ:l7+^YCz5+拴=ʹUzfK9<87B6FoOt۹'p{w̾cSܱU r8♎+.ֶs㟉oԜIs߯/VVW3Js3B/|0jgyg Rپ5!ON}>RCoF=c c( wg>ЉϹԋ_|v/˸A43Ckh#= Td,ƄEUDt9!'u3tJr?9>[CZ]\ZAlU_:ݞOcFij9+\|#>zWtJitDXUϨ澫yq ^ip6K-nguk?=~<7T; !SW5:Lo~ՖC{ /U9DFan-Bt׫^Ta]i2/Fo,_ j_ZUpKt}_o-O_cYGlkYU-E#ⵣF>MR퓽G[G;l2kHP~LNKi}J[A!/-vVS,^EMD;#GuGLkDؓ E`&AN>Fwu=n Y O\R?z^k?_]յUWӧϞoy?3TZEE3 /ƾt Mt[OBgؗE*{;)DzSͽmH2x jfc7-$ZLQ;ִҧ\\b9hY 03k0sIn-ǂy1>d5h n:(HKnlWDBdOMk␜3̈&,F}l< JLM1DJPψ%2 ^.RUi(KgDK }ph8m֬B򏩢KI }_ [0^/lvI 0MTᇊ).pP_;y1(Bz=ͳb0%*PT2@jrƓE}K?ᘎƶBL?M`AoD"k{ԞPi>jx}/=¹=2|K,qkYHʙ܀)nI̮>:c_QQ:ƃ6އidU'#h[bhF2z{b Odi"=yY?A V~+ jZ[oK\7\XTB]tQ 7`eI|)AIoKZ0dY!}}jKoB@bv&CNrDY,aH[49N TvhK>(o|~E7Ҋ;*]ߘ xfyn ^IEdO+;bsln"\x.v7b6# ȋܣ QQ݇TSm1o֧wPSmjz}"[ij=+,G HqP4ZH0Olێ+T[l@j峕tJ^[_]Y_vIG'%]ZǞg"p(,$|Н̮)|}x3Egǖkɝ:R>pP{3K~-FOKx^ Nuщ_?mJ]L=yB C}䴦Q_>niɣG|F@uVpjPrB象/:*P:?y#aq Z/-ih`ny8n/y߹Nx7\뤄atEğ {ٔ/ 4%ףFPom vl[hF) I}z}]2meFBC޳yOddzf#  +ְͣ,:1HrA9_`EVMd\P 䟍'Ҕ^?O8N"t?z 9)*AtZGqRT]:ywpIQ PDvLT;Mn_5T F0߷GI^ v yKG-d2Rłtœ+$DQe$(81$sr3O u-Ft2kut#: meTSp\NI1"~!O }E$(9?]zouF|\uǓVdHد ^Iw6T6P|GK$˩8X b4вȐZ"E[Ϋo6e/pJ&WMbO L[& ꌱ=2Uׯ{utL0cI cxVmnCf QHxᱶ|K(u.\vΪ$& "ɓ{Ÿ!h>T.آIi-pZŗ7fI6fF9v%|1skRXS'D`h>cg{2SUc|-5 w6aX@#[/[0La>,! hECkTj }pO~ך!_K&^7@xD:z5\ |t7O_ӟC>}Xqx9z,0XmR9{mf0QUAǥ0[]Tύ$:|&TL, \y9Zِt!4b[K]/DN\=}ЛaB bq[]|crU0<##_8YNtw75]e/ܵMtUJ _ӥmS:Дn;^MTf~ ޸?I?qMdIA/3Nlp>ysa@06 朑Sf8!yF(Bkש+%,gie e)q*$onOɑO @^7`=3: JM Kp$zv36wGB3$eS5wrDBKu?Yy ̓bZb׌vyJoz=FQ NЩREQGCazI9F6o˃]}:%9PnW3gu$-mFpj`I%Hɱp2T#'lIbS9aSF)6f#x>E8 l45na3wIwXt0Xc>j½EnBI"PE=/u\&hH((%c/DVMYcrT-0գ83,eW4r _H7 28?WS@7pYMUQB4YR#[̧5 dDu9iUR9ՄWH̍#]B4.k@Rݑ/h oÅL/(;r)4Щ),5Uow;io;-9wI:dR(kz̯5$}W0 0@#5`Kaw⒧tJZmGͲ'5L¿ !i^Ò:#!Ir{&$yu7 ؕFu\0' xL$*ň1cK%i_jt; `=d1dT0:Ey}Uu{[7`R\|(ݣ; _@v})]J.,ϼ*H ɓ-3a/)g-'Hp>jVTuT_⢫[`3')ͪ>3wv6&J\TIJP7ڮZ81q2%qq1YS3va ӭS_}ˆtvT*H!ZwWxBRɛ+\|jFg`9707>UdoT>UMNޱ{F@柵>՝V4|׈ PP;zCkփIf5rCWZ[5br>4^AiVW[gju^{)1DTww靵_oַ+wjo{PzoǑ9}1)q4=&D0 KyN/j C &U_7$rxAĨN]`S E8:#i?*B2M- $t%CN5E.Qtr!J~]t~#p0צ)^t  U6cXˑ8 ;V^A1MNxfrZ=szXͤlNUό g~zYh~j%pyD[HAg\bArK1QZR֠ڮh=L d_mu %-½*U@^DܯOԚ9hhEZѫ- &} nC!'R+R4.B8cUMu!3Дxm?{Rz| tmY WdN,Zvɦ΅iqm:AiU6Qgɂ\[n]wL5 7tFng{OO;[iql%E-}=U+Q*$&qV `gcDavLJb:rm¨O}½~ ĨE:'ǧO҇Ã㇖Fb>fev;;A|Zjֶwu>Sq|ɤV[mLIlݪ(nd 4w}+SR ndtBRqN6B7*l~8m DySY^v}hSL TDfV:bs뙯Rm{{rat3h qʿ 7 ;6ϹWt^~w[ApHd:_܆:18f܆ ?IBwv {/uhkZY o#%Inimd 2sxt Мg _\GЭɌ?}Ǯx< 4~$X\m~ĤE񝎕] ve[}(O{w%"IZ}9λ] Y; ew-Nr>%9XJp۲&I\S*IlvG}M l0I#/3U\ w 5jqlNa"[_fmt+:#IHʜQJM<S[XS8:ׁԖGPű+Q!e|h9| Xg4U=;!1`l[e2͠$Ewz5Z(X?E!튱it%_ծ13i bqoUT1aUK+|ҜؤaI@_`oFG`DO7V"-ODNN yuƑ f5ׁd, ;sð鏌3D'FS6_+q0 WمDdOfPYaGf"q*`+X.z<7P0QstíVd1cnL_nDq/4\ ^ G}iv}?%+s K{Z\'ͦh,xGc(a<KUUn]%wOE+Uw>zX(:}>~fk8g$#9*pZ ^]i7&>o>lA΃G CǸ#Z7w^,9펞`n 9@$ϲ^t:D8r gGu9! 'v)eE孽}w Mo4 N۴xS&_fOOuۏO1%wf|,n N\CW X6ف-c~իl0DoF$| .o& ?^cq''))$Co5'ӥD>dtULӼrIu90$@ǹX*BtO)mYXhc{A GHGٔg÷;Gca99h X7zHy /{(Q7cP=H>͙0Js3GVL^Ul+6sbHIcQVxG&*&%_7D1 EnTg]TI`: w8/IR}y g^X Yzݑ${"R):9/vC..yHF&BKZָ,܌}sNBEnF q0[zgioX3os?\qɘӑH cqY@bob]YH`(|Bv@C5t3) ș}5DOq5W(2TQF\QOÊ{ S\FWcyq HPio&mQMםjyQq c{ͣӊ79ϫ\w&TR@.G,+VIJTT;X5+Ѣ뙬BD=z:ibY4`0W(CSL%v4#D»#Gz4E-0fbw 5v?K47IK=}\pi}쿀hW]|03ry؅˰6yH JUsM03EjZ/cɣʩ )tvWn g%jW9#x+gk9lr[8 ZNDJa܋x gPRѰ^TA87s6;n0bٸ' FΜ@w̍7o^\oxhỹ@Ɠ  DZ!ȡ#ᥰ+F;K|A?)bR]ԨV- $<ߝlsX#⎗E;3} jc$IS"CNѬ8]>X [y]KY^rJt5't\;)E5npUX'zڢ^8&<ՒOW0ZD+ 4*jRKTXZCs:s$Dg~ u%kqqC]ջ\T{CWx>0YZ +,JJ-xZkS#5׉ִ 3g6<&bUi Xwn0;_tT0FAs_1˥Ȓ KE@D`tx׈*/̒_F5m&,6kEa`v` L*#h;UJN2J3wq, ]"߲ahr;i\}1+[}؅%h}I֭lA\n3uQB%bcO"Y!R^꜑d<~CK&z9K^^ 'Bst$= ŗsܱK3+I89৚WX1|mTc5+𑵜ĥҟh3gW)HZ|#ἅ`):+YşJPzI?3W?~,=RU0N,t2aUD;WNp1 ;?Iҡϲ!}dQPAv D0Ny9[A(| VIpVn3ӿ4T4^4Sפ+#st9Iu}qz j{SgPmn++]iec7H~ߜ@Tl~l/b0wE}X^' zz+0Ž?,qqvL':Ӛmyw;G>{*ªUU-O(.:9cc"s)zM> P7)x~㬬x`U ;=DHuYx[ɏ:LZBAiquFsp+$I!*]:6(&SK)QnVo~1NCGB26Hw#0q\#Hv>Tq+ l=T{`NSG0#Q|=쫝伂p;CF ѹ' 06/G?G͋yF Hw{*_@ =<ؾ՛w9JUC|qǤ\M"AoDT/?1뽝w!cDoٟ,PβLavo/MpН"$نc x2`ul#Ǣ]|Wx ߻gқ}t7Sq:;EI_kD`RB7 l8U|^JHCqMAA} cx3JiUY~_w99ዛa?GcWSuJ˥jȵı]R} sb9}AC4[ۃ1-s)y4/{­s86kbX&8wT:V}Zw`@]ޥdD hFZ3Vǁ!J: %o@fZzwuBTnj/"=Q_)hWW9;6ʝX2*_P#zFiIt5 ܬƈ5a1|[x noHh5-?OOQ7St<o%UuQ̒Խ޾ZӨ'Oooe?xcA DIbu/A. x9?W4Y,?'_o\/tS 0i6ÆJ\p5w мc&tJI9Nj`twLJrkhoGGU z#mt1t 5Ԡ6:<8\o h[mSaCӛ\9]gO _ZN L KHt4bB, 3<&8cu(Sa AȀ8}FȓpN]m5rc@qFMKa3џ-??]$>Nϲ"̿wz[ϦÅb6CKYq%؁Ʈ$݈'']dߚ⟾k2<@ykN1K1G%vNzYRqF*GZ MPo%n[RaQ¿"Hs'S`(pΗ$]H~ H7V)lpbho9-Jx4v<,R-i2gby{P̢9:&W\5 &pnG\Haå6YJ%yC3"|%H{nM(13Ww#yj~R݁o=)ʇ7:c F~?nm@C*u w\mM!QgRC xr ] a!Et< vk ^EH܅9Or;&Gv[ߥ~^y,g 1D7*;I Z8'S9UDD[ Ä9Js{x`8kO9CC|L\E]$ 4#6*Awd|h5yPQ$h@<[C. D U]~Od ydfslS:n0Œk^yUOG H3=٤Td N"T @eq%9̫R`6mo*)}GO-b{ΤZ(^UXq:d,5l7LkOyw[_ ;7+Yꘌ9|('}h!Aq$#Gq4ɟlish14qL379Լ5bjPh2?ޔ'E7&?+1I bga(YO:$<!/E+cK|dlf0dTnFɱj$o}1v #|orM!5lK2ϳ݊h7 T䆂9i|ݺ2,i/>&F!{ GG(f hrMJ/K_O'ކw;M,>Qp ^ZVU W&@v',/΅f}s1Q'H?`8|7ɍ_=\ɛÑNtvt!n9~{[>)\,Zn27oS*Ur`AےGlTXuĮZ'u˞iY199ZK+p}Sg4&K+^ߖ X\;CxZ=ܛba6+9 c JbFy z1c5K2ErW70l^lb0+lڪlYUwuZL2`]zf*@[f{懓_1\ISkXYanjQikV/G H& r.-]}Rs7c OBZ/i9`wUՒۈNuup6V*IZ-lH!8NSB'tl$Txo,ț^~STOI3 ZFLx%Ƣ ,9$ay}ieOe9OUt|W& @dY-vH3sR+0%a1N*;>? d}BO޹yОstӑ*ȹ߅IB5#c`aPCp&]x8ΦZMkV0D5L#1"jj0lVTH"TWWc FZS( VYxw@3| ]sT"m9vO~=~{ryz~y}h݋+VV{EL)QкQ'ԉ&HAjKWCb<e"U:vso;is? !İ9a!J;vZWzbLi7pj! oYP-v*SAۀ^-JaLKF)dKpZɆ..G\wiv.1>YY ;p)!7"b;wȇ #pI\"@S(h0/{]C 0:'-=0G q]O O%=$Ftrb&( Tŷl(KL_d0{|,2vu{)3 B6 i_^&Wؤ(.4,ON]:qV( ,HD׸%OwB(DUMOVEbaVp7U9ȓSlW;)CE<-Wc9z_jjˁKvqk)C,T12Q;-+=ftл*J 7ۚ# k|Μb-#:v9jڝLa?N4~i@R/Ұځ4!̐.CS"u<zdC)㌀ҢM.HmH!5.OHꪙ  x3MaǷ4pnQ"kѭE Z @Q(/rAlWW#E7^%gJvy'tvOaMرb;w$dvş̉㕰o^j9_#4äO=}`=c> \W:5{Y"2P݂׉\i#ѓ-L slܮ.zwǒhE",^y/k*MwUFҸhD {AN/=jʵI,S6aB̸5*[]ei2YgP9vYSR0'OF.3~%)10S{6ny9~6 bWإn"1.lrӞx3BC; fZٯĵZ-TSa$n 6"P@mS/F| \->nʳT-T9mYqcي`8}]E : 4w2@9Nw ngxg{SbL~Nw'jgrTt`a>3`U7i!D!bvqBQXi<*l!]L\$)ϣ8˵9T:OۦM(OQA'qYD2^7>P9y'@P> hq ̗jh) Ґs\DtibC2CǧAv!]K2.mfo q .o-Zig{3ڟY]!.۸Tv:u8jyJKkYs -O$yG}YV\e)xy59m_%#)Mg'cUq18|'4R}~?JNI1_LWR/Yjdps^06k뽘z C;5N!}q7w׉/=uzwsNS:PδxO}'Jݱ&*'uPC%&GU 5+2 [.$*5h3tɟ(43:kHvxpK3*HrM>w10t`״$'ƻKP IAH2Dho@LGIv99UGTc`5!S8ZOV$Kqח ˰n3V,l%?wJ (qК 2t6*fH#ʴx"f&4Q&`2wk]UOrS 7h߫'.*Pyix%jlB^4a4(yӎxNLSk:zbI02?RSQ¦>NVO@ @+ ه9дI9^L'j Ͻ/iݛ685Cǎ%bIcu}/S3~t4 q څ6iHsEcGz&"Wg} Ÿ {YS^Zcai˘6&N01(rtP.Ue3m0_CP ݄=F|wdDϊ͇֬דּ ՉwV Q Ͽ`ءy~oC57W'h_S3-vw ]r z|o?JH^D";GvG= ުvN2,`[C9*HE\$5~6Oe?cByr& JU3Œ:X@ugX$9T&*J2?SoX/l3a"T;@MNJ=ܺDa42E9T7У9  B> fCk|3F%vuz*Y 9{*?﷩}dYdM0(ף$-LiҌu/X6Ժs6: 1p:|AZ[jiC8v`-RvY5$ 5yeco*~["Qs_GMqܷr,EӒޘx*L|Q3gnH0/I}2s7YDgG_&q N8L ju+C%CwvT#"w3(wD}5Q-R(j-)x)U a4Q0Ѹ($o1T;K@K O#)j-c}ˁo׆խjABgWp9p* is>m{l.H>b6c^=ջotm?^hjT*UW${9d2ޫw[]9¢J!M65_c"N%;_Wۥl*їk [ nv(~?Lп|0z79AGL+gsck= ]z3d V>|H?к=?BݙGU\$^XԧI@ ]jVN'#\HWp" `r$$?|VGUYR D\(͚mfFud7;~қ Ϫ0QYh ]wAo?=@wZ)ՆqlO\ Gi6~ 9~MY Ў1_%OT˂Aq!&0U&Y-U-ћ*Al|^yFz|wZhhk+&0 vOF2t|Uʕa "FXTЀJk+YMEYX I*.!OxVz$ 5bJBth*fdH}{u_1kw `LUvr_m+{ӱp3xI__iNaӪXĝnWřEsZԺ2HvmKS(%?Ng'*oY5GG\7&NOHF4YVfxL 2vZFTRWQ}s B7+ tF>$| kwz>PK'-%[#6jB}CkXTͤa &.ڰKVC[ z @cWK&%kϷo\//1yKbAbPr99wyM3O4!1%-SBۇ3zHcи}lhq X|?8zt b0ԫڧ|(X Jd.(9Mzl#ArPt'.H4gss~'Y)JI,!3O!l+GիdāQLz4S a&򯸖b}_K҇?@7 }.+ o+7GKs%7PP &Ib#sOl7X%PBv㬷|o͠~exGU>l5%1DfJpTvFDi%QxRQᣂky_&J %V^o){1!L%wfŖ?# aXg>u ǩTPK,MVl.To i݇Ahaz|&r|~1 ߗCv ߗdk8QnXCIHXʥypyǭ${ 6<.haդ׭o =_y1;u}?u߿.n11j.O0%pOGnx &}{ӆ\e>y#rzjG,9ɓIkн"%B5J2mMxmK=P>Ru;ǙE:Cjs@2?c ؊;>Mu"^9~S9I ai, J9}1NOq?^1?6H>'",,e{j(zV0=Icrw0M0rf4󈽐Hr6.@Oph<2*;Jk֛ߔ,4-6tovpF3 l j昵P `vi~;ܓ =/O;%깓FR rv:N߻h*x%Ƶ{L=)QGžE[uFT,Z4}@wbN oʢ_ 6%wum0xJ 6MS6FW'm̶@ pJYpq E[}&w??ykRHՋ6챠'Dv4>$5V__^Tُ2`O6NCՆsaqH9@zhヒ b#yʻfuwv.X8Btc=S:LB}wN5j$٣rvYYeOR6OTTpxx-;Q9oL`!8aO:%h~+9urzΈKV}zP;.޺28#S?̃j{16 }PNԚ%t<}@uG]m ?8>a$u OnŐNZu v(Dl-_<Қ\0,;]F~{m>] Ke]D5hKࡕ&-病Qѝ :YΏ2VW(L\BIE^i WcL;&8 ͞L8pi}̃x5>}85hB>.s3$]1);.͢{78~g2YKh| s%-Y:&n&.psC2R8ps Ц<2T |($=ߦɁT|mbkx넨s5ꪔ>"/hrx3(a+?8рgּ ZAӣSZoU6.p{W@|ItXU;LnѡA?2V}WN'knJV[x:4Y̠.)0uuCK h[G7 F3\е]Q+ȒC/BNOeڐsV3)>ڗ?H}t]+ORp|bݑv[ll"uNN{KyL28$ q2}TU,J1cO*WWGidDاy 14]mEP7|Ο1LIzܙf *hʇҵOEeW+lJ&Ǔe NI^OoBp)arR]CEhy5Mrݮ q{/im=/S_I#/[h(ڪg de~9FJ]bK"yӧI$Q,U2)U; bW2BD#}MbmC a z6i(h6d6=5nC4֐:ӣB3cpyS,5qB)  Cml|y#ZJvewYq;0bG˟G)48lnݷ[m֞FGch`_`~ s&sBvsϚh&pZ J @g7 W&gk*7K\$_bNJkwxfTz'ޢ>BX3^^'LPoXfj]y)Sa;c jDO`)2hy06y&P1&%ŤjGB'ـ%Z ``Z l!C0x}7X}UGN 0+".ug;B4 ZX8ztHuW}jqZ fֈR:kܝn/s3svW3;nRjg^V20~llY=FtuqxHd5m{`dIt+Q-E@21yLK_d'^P09g)ѱ!Oh8Զ&1up1ÛݭzX=pʉ|ABIT8.}A7j:Mr>mDƾsLͨiO4t{G@z¦ s)N|V hx|]Ou76· ^~7%ԩ#bruvۦf瓺-'=!3yr l`rZn:gc{onnZ >aWf;I\4l2ôj2ݳ>u8~<Ģj^#/t,+6Q~>%-^rШRQ_VV=ᐽQ|HL]d +={ C܊QI"Drٰ3([Z2{5RSt`|N|oYd<=׺9{5T3vŷ/p =T@,_](KXxBaa U EDjK,8:6v L;\K23'{7u$n?Z *gVVaߊB;]xNƚPWϧqE7;2,@W3Q~F"t*R=u4{U6ߩ O:UJiGS_S# ]MbԝnsKc$"‡BS{s%RQȩDS 8) 9e>ʗvެY EBϢ~/[ꪸO2ƚٷoYE 6;4՗D=r$VW^|te,ܭ`>/P}wnrP +bJ~oӻG@"=ZmkCmxVPe`0'#R#'hxP܋OHL9[;4/(f=Q( dCtNmb|Z=1PlCGl:~o'WŘdwN"bM]WF wI7{ -ʹgu1v"J+tGFóP`G{Ls:Nė ъ:tW-l.WD¨깓5Wm>=9L:~{uO'$ǟZEwJ^m>2QSzP}a.0ta@Yk/U #|1N2 +]PA_BI+,[JUS iL?7'X¿fl`D4Z ca5y={~w5 Ag+ǶxdJNӚF_HLt' qE_'$DHB?EY2͎}$:4W鰹}_"ՕiMb(w>4.T[p2&V }N/7hġB~ yi}j&QpnNwVJ b9}mQyqz帊8O2\&K>?&6txQyxB\F6!DQ1NsI0@eӰM|>XnYlRLK7~^ ʯR )o:)w=q/]gj-D|bPwIIgeG@[h$anΈn{6qyigzG /罋Ab:h MUEt8>s%WI͓ L 'e]R0K7~ZK "&Y!tӤβ IG?c7H&w&>θbz0KG/5|lxa +5-m#PZ.9^5,. 2`rsyu6Oe>Ψcs+'owOpy|]{~Q_b-OL$~c~[- G'myR6p_Pu&? iy1!/LPW{ ֘: O+O$P܏@C U2;й>R"k-w8CBm`g/>r5;*:ͭYqB^=c+wF+ϟ@sk؅Ϳ >ɚ[ ݁#0TZ\y,WQߋ5~Յ=^xq58Epx$A*_pΰ.+ pT~i=ˣy~IJyn0 xRz.D#7k+§KG6}I#i9{oQt6h,4dVKh(Dfɓ _'Ot"ťMݳkiy\iXONt5LVAUltJUջ B$|W{ @j|2D!Y mkj/AKDw,.p:Qw_3\_\CGJy|Q(?v"Ye~9LB@Kw3+^vׯu(%;MvPڄ>/dv?+q1621ߩaj^ѻ-lK+ m;a-AtkzYݕR8pp3$# usVW2N3ڥ8wy.B &V_LDtiI66Gv?^RDoIUF]o8⒥۠DbA$8ݪgٚάOvs h*.1u?x;:or:7دlI]cE8|/xC h {;nJ erMlby-TkV%pqduWB߇!4c~~ lz8}nu~a|4*R͎nмdǸSt3Uc,u';`g%+9ʣ76j\` EunP3t5\Ao{?Nx>һ5}Sϸ]M@䬧Qüa\?4R:^w,g+UE-0Zrӊy2#YۧnwiLD4˜s1{ f/.T/|sʹ/߾y\x iFɻ_᤬(ܴ=2em54"ʖՖSqxE\!i9h0 >c8S?IM6 W]QE9s5xw`0ۊ@ٶv׺֨74q3|}5Xa ҧ)OD7Dݛӡ &{ WhDk~IN1U:z"? o{;jq*"RC!$MlR7՗nok]dKě8rdĐBVDNL-E_H*fF$qZ)zTqalGIUƠq]WI80Gz,=R)o.1tVK;uُè:>v:-ŏ6ҧzZ!QxU w)Q/0;AGOe#ZqKS2-EAm!ܚѣX NlC% ޡ9I~af6@}b],*~ o%..U qrsy~B(FR,DHY~1vu?>|,ܟ JNT<)m_HF`Q` l=Rn CĚj][,7\ v}m |>GٙOH[zɓ;&{\NT=Ȃҍźh9ϑcؠ´w'+YvgtF5p7"8JS7r̝檝e(X~xիWޑdssq; 708Y )1Ar5IrIÅE!-n3UFC?صKc&u6b/54P'vm(Wjt8ZFypah^'2y>l?Ll ,x.I,I'Q`Fh !1>8Cw,%b:]̈B`Kj#&xN]ݨ. G Rn|zÄ:dVUbǗUcVuݭ#yC3(#q!EiURuΛEkYg =1lIMd[iJ6\wee8 %+rvQ;hTDf~VpΦP._Ch;&J\;H֔%DNjOB~ cC K9jUn[M' es%kn`Gtx{U݊$XP}{syN6a⚔P\kΎs6u:=Xh[Kn2 4\A%-wMjO99flI(ƷW9.T铄:4K#YfKh- ۉL+JJcy u] .w^8%7Q0)3*k*A.PIDR@ZK %ld B.itPE}ɹR|'dVi.6'>eJ{`WDIFq"+:oYzi]SӪgDoK.z^e%T0<=2͓^T`]^ jKFH/FVT8NV4Ӝ"d VGdvIF|~6<;Gݡ,ݟKAa>ټr{_qe+^t[;Yi~h}X՛ȳ RQubҨ~p0q+%4p-LUBl~xMh涯pq3BKįkӮ72^\B]:YTqļf'%)*0NUssWb;<1w虔4 yVNr{ţ^w29v(Z8zWrrػze20F0!‚0q|Q+Qen94c-ٻh~ƃ4PQj} MikJLDD75(I}(*i)*zK9֌D2%lO6:*s j\Nq摬H_e ~~iQqWS!&Dxq)-Ql/> DQ=)8 =5Җ 'wnmiTi)2ot/ _I4ԵZ,O Dl|3@2tG~hͣ,he!ʧ: V#|,.g 'AIkLPehbY왅p2[KU#}ɀ+Ƅ^D_%*@lO`D4G^آU9{Zx}i'eP Fkċ܆p_4W ]FLB|QxTcp+ $҃[C{f JGZe~ Y< "54q}!9Ϭ#]/u# F ]HϕI맘c0%ij7v&tC(tNAb|Š5E^PܻˬV\fePOEa owv-.F񈩔HeSK84P ҨE"a_+Da$j9qQiV|txA&%e@tL΄-T.xst: Vܢ/]sT@>J=1yLC/Đznk+ % >2J4]*B1uSW42kGqؖJ=< R"$rM>qDJlRl"y!H,~VX`'YMzӵty.@b6p<TIIu\$r87,ƙKlQR0_2i_'AkrZ y.BDW뽈{ 4_H8 sAgx'.U&$8PI9W 8&om;y0B =rCb*ԒC=6 7xeZ{(ϦĜzpG},*e4ev%& {-F?@<&K+rfNU-rRprfgfmحocW#ݭ-O~_Z__is?)n 9NZNK)I~= gUR8ߩ T5?IG-YOl?JFNxkO\nIv%?ΝL/7!( "%.+zʭh=bQf?8L\+|IsZrQIST6HDkWΥl3yxo;KL#D^\ Nuu^c/.KD!=wsS |ZiXYls ׇ F>NVmlיִP'?=AI&iɖP/@ 8MF !G-y+ gZ{B2&INCi6dxp`gݭ@*)n%@TǍ+%jz]ZGFc]$cgim|ֈB5l_No=m!"? ]'y?_;). XTlAwO7&}?;~ s!钋,9K.)Nj,~3 j=< cԀk9zK֭?Dv&|,ɴ7S?KzĚ D&O_ۗQx 5hș~.('_L`-[w>2$j 5Pm—DTW ??hyi63dzq2G";>dp)]j[m,HL75MqS 9VOUJ",9,I' Aިn~3)oI"LZ4D2ژ_xLZZEe4ɓȗ \8OJ1nxhDY3?'O~:a]uЖVFߙ! dyfC% B POis }YP>⴨y s:$49s%r˃឴o1GY$I!>KZ` "~ ޵-תsٛ˛Mt V@8$R#Ah&S ?՘kAס ߇U_^?k*Ǔ^P67#Q H]]5ElxZuIsCk:?}jzb/eYFɒ8O*9ppʸ75xVVO` YJ# V>VS>} eje^@| 53GLk3JP#WHvcW0B}L66;ğ6[$vCz\ap1[cCLMYh;AE5d&dB E<"6G:w&& Ѳ@ʆO^127;aY8e(;O-B<;k@*,PMFKZ9 guFHX;2K2 kWhfSplxQ0:bۚnoܷ鰸^_}A'_${W q#gdهkyYL2^Y-rP;)K2A̜͟I՚12|: `7Z z?g\:-+}q }RqL Spi \1GZM\XGQ 6/0E+uXI}Hw8(tf4ʼngWN*o?Zˀ1ģ(Lm OTKOx-&Xz`/$6:M 3{y0Să0=qdkSi-oh GaJF!>BzO|$@ϬzL1`L? )GSwY6F[ćIl+i >达\?N-2'YZ˺>16_11ǂ"1f NlH u- Af]445DEe!3A >96Nͼ-L T%bk8.B 3IB$i擦UĿXtl`<)sL^8nl7QM*%]Z;5Oe芙>p{>'QqlkgwPw|V 13ih ӰzJKKPM$x;;WDkVEù/JSG?fŏaST3K>nRO ,6[1k\ha:U>2NV8^f=g燖\]Er6fPy`6 "uN F,^3UuxGe]@\] iK]V$c7 FOi A2yh[hpNX/Lt܎De6F`)SeC20 иr0Np Th`m)hhܾ B1˒(0P%w&] );Y,&r&Uz&MdjFyd҃(]® ^uu`_x,4qxp@,98ôM.< 4U/@BK؜X:3}'npana3ZTX.V2 '8 +Uw%|L-^%XR{ u;PO.cT"ӁXrJε*P^ᲈu\jCYH —vp9P%Ky'+7ד1ƯWy21 JY Mm FgQѸ0Q=LQ!mG#N0[YzٕI±.{FȒh%^(8Ĵ!pwn2J9:  sԘg@F:SB-nl+/0PWtg~G s'kU9ϺyUQ p'7 {' rؠy@I d""+R=ЭiV;lUgDBW7 e/:Ѽ |i4a&wg4BVaKv=ĵld{OCL{sgӳavTbN['9}\biXxeY-])Tu ;?/dG)–2һ41D)Ȣk;!Xu?6y rG?#{4wLˣ\P:uJmu"1MrMhLF2S.O@iKB ϓspٱe_ao$쫒24V6'1?ln ĖXG/'$N&4ia֖ګtyTffu<0B$Vjb CFe\ t˻|)8w?XM{a2b '!M7(]u @ J/ڨrblY9RdkND@ 0yRcj~_tXP%]i27Nc^@O =7d7-}@ zIψ mOȑc`;IWIҪT&O 7ߕ0ᛛ/O fp(_qV`:E~K*0.3@iD.\O}|b/E5-E!<-% W/ 2*Al{ ~ql0u9ŠYV90N̨l,p|>l1_)MeKi;kMfKZ>]w􌊷mi%Y {M%g(oύʁR;)|S%>"zMh@4q$g(פjtKNAcJ01b_4tOԙyղ]:/x[nmmvU+}ndZ60zŴ-{p;qx <ˆf5!#n!kEgDmR#&Đc$Z=+Q^g_B+VN+VW|TMdF'|m?ًOLҾsvX͖X E쵉FZamkCdlS1ᦴX\ܱxٴ܂бe 􆷬H !;z ?p?Umo-tX_>/l{{^"3֏ \EG!&:8ǰ-=}sO.4Re\ᓒ%L9Jg7藪S_,umMX]fe.sVrs%+P" Np7)eh,#f&> 45sea-v _pw{w?뇔@YxXƒ3 ǣk_@.C*Nkc[ILaNon${J!1?m.r5v{>_`4K-xK&nˋVbf;3QrK w}-v[{:~9-V}䪝+wvocIA=lja'pTH CRy^#rM4=c:Z䒄Hc"Y%TEUCCHM7ԳVD"+58/ۥ8:ϣhky{Q\NV4##^U:1'1ąlOB-+ Tid_\7ȑYLj]@[t2( 18Vqz_&[E](N0Z#@bD0d#5g#( vPU_0P]0*aa9_7K>_2FzOUrK}MnX%q ēhޱBBęz`cH<92=Y$ͳv&J`m׸QB؎J ]\09R)2X5{w.)=MK[)>ݝnlAc|EOg H܎5`ϮtEGF}ջJu u:>_[{1\k]UO&4zuozBO';=9E=.#^J=+R>MW]e[ m/-?JxD lll*'.DǕT!JBg8· K~g1NVu _ͩG}Zkŷ%Ғs}4`ԑZ,.fSj9钨u}xUrdc-Pȧ=f? $'ͽqr,|y4N]9'"<:v'_mgLHɌ2E~CwcI)KK-^Jިj(l 9&ςO ҞPȷNzR9NK|.saxgFh&K"Yoŋo}'#N?=9NV/0Pp+\1ͳ5wp=>ksAo^ zj0\[oHFk)Rd:jJҁM嶽!" 6@`w7s;w}s?ܯ7O2q2HnH 3L#f:ٸ؅| 'i/\/E(H +f>p( OږFz5$0C13+*y&5{6Of s3pɜ:JB>b#|'2T 6B[ktX0bEH(Fqaꀸ{(!)E[ [p17 Lkٜ-@n [L«-]\*Q9:fF+FMyXcD>ۚއxq$kǽP^spWY% F͋4޺v.:'gTZn+YeMLZc(}ySbaxԶw(1 ]01p¸,K;x^XE7x\n|OiCNM&H QoA#JFZ_H #74!HiԄ;|4u}u= ruUKC`W@Ej?>}E4\kztuڪB4ES2+(iQ" +m񂔲5Kmkh? ݆tƥkXt$ǠlXN+Z+}{'=KK$*N e"{8qv r G 9 M݇Qx;[r FZ.UcqaU)<Ԏ\qcrt@D&hL7T7͞F#PQ.%T6ZV>hO!g&p9݆(-0fֹ7Dy^DpL,шnF Җ?D_jk#јER (G@rALe x1)燡[G2>ZȭJb %(@Ȥwxص{ϭb*dz'oE) od6vBk2i3}JT;;#<\DeTtE6#is&&ֺq~VwU@7`Mhnijgm)Qrr dtB. #QDjb%C#d|&qgGi4gto]9E8xQ+iR@%pUݴǟw.õbj<%s)A4͏(1!I!\Ûya<DLLHMJ6*$-X>+k c5̈́</@ RH_'tyxqN` CVՂA@b E"Nĵ^yYJLJ1T-H6b/XZ##p `,(eJb~VVQېjJIZGedžtSc5D\ EUp<ݐAʘ)flŭI[%;a{)ޤθޥV&4ˁ;d I dw3@GsQ|hqf(7;fϘ[EDKV+pğz( fㅒ2dt!IKz%qcF8xLStq#.07݈L1 ׆OlE1'\h#ViAtj}!i@!{,7u{$R q (nHÛ<@DZUtbP(%E=DfʄQI|4MD@Ǚ mLpv30#dNn,鹊G_~~] :adW}X& ɗbIh<} >tߝOTXU,Y/'Sqz1o-CJK^(֙"l,DJ H4v -oIFx҈ބr۾wl |L#SD,"'(hy⻣OŔX7VB>LLǽqnOWOҎsm+5Ŏ$ kĮ$$0$GbF<򋽚$JNxh9'0Rxjb≼S d2z z|V#p mJ}iQ2܏iNοxvm1M ɎT/HN6]qvgDFN*i@G˥Ҿ;kW$Ԟo"q^]7}jNgIWSCհnE)iB RL6DcL\1,ЬNƢ(6~jlȾxbb*p-]3d< N*rU&&)09W/|;0*~^D~de;vj%`@ZD\KNZDH/:RG67bG)Jn6vLE9)(uыxJ (´Ւ1AZ-TN掸fVR6afG ]d^L~`0 1+Ri髄2rFa>#m!AQ@㦘|L(!Bl53k$3y QrXy"- UBXwaRI# J7ҬeD>R|a) NwȄ6K]`7HV<z{.M,ɳ`Y@c V l žHpnBqP8m3 j7f帴Ė"/T7`O@Dͩ-2$%m+w2Y"CY!Cf +y|UbaHBfϤ@dP4ơ`/ L8| ^Ɯb3y~ Yub =:TT(-mh LI" Չ4;8oDB FUtK;&ݑZQ:E/l/1[(ؒ2~#F0GJzL&l3BdQ+9,?0;`;\Sl$DE +SK/(4?8zD:10` E2.' w.u[䜙oCHwMpZC&!]%rp*7EV F -뛐Id†axVDa,H$ QcP_ 9Yr`ȳ(j~SXA c{asJM&BT/]C"8v& Fa7c|.NKTeVf2EpB dB0fGvvJhJQxM)H+]nK0RQȩԫ- BxSb0Ë>lp)׀Z^AQ+26ehĄHe,E0uCz /PPJSE8I!ĉ& *_lx]ZUd4M9 ˜|x^~mXf)a}QpҬB_t0JGFieC"cikwCmTN [^FiǦ}ZNf'# -Lx [`xPB.> ix Ga֏slJ`T\"OxÓL <q:Z9 @+CDZ(avųl{ZEhV4seD#k3VVt>id(lCa JS/s!£EW؁/]$yKqp.;ʳr_WLbPvc6DbˠȎ.&ex7qo#@tmֲvyE!c MBs:dJBh+hl7^J&͒A|1`@##'R5y' ˴f̤ϚH(Ǖ0ʕwey qx`vֶ`Mݱ`)%3|b}< kVi7PY*"U!cl]~6^JsgKYܤ ER\^,aR<8W_sruהɩOmØW@<αt,  !Ւƙ@U 57cJᯓ޴Zv99!otFiݎ̼!(RN$`:!"4(++Q7!bIW‰QKEė՟\ܯM\)Nȯ*Y'T-U,5.U5<|+L^6#?-%H9e^JʳKVQ4FNe"oG,@/&tdȘףZ]{hI RIkySUT阗71au@WBG.EFhhcbӯ6{E;x3SΟS eFfǷRhNY5F0# 7rzR3Yg[-1>a%ŁX0ASŐ˵6v2p],+&޲kN>7{m'bhȫ=[uHo-TA6 K[S0",]=ܞaO "ߠfsFcyxu'm7@,Ί7(i*cvtճz 6M!$Z7tt2 ENմ[{94dL5Vl׫] [1Oԡ>κJeHC[c{;y}z`J YS\ZsH8 Fʕ=bpo:9QKC$IFD!1,-@vt ,j$Jm%X kqg! dJ[\uܨxqs@i\ *k$;j$N*(d1]}A٩.  cP2B V8 ,|nt[&SD=ºo̅|fV52hH>ȂqZug!$1|Jes=eDBnѫmv:`0;H}AX d&}/M3&oiqn8MSb0/E|Rz*v&"Q-ah/9JJ`;;088tIٓ}퐦|8wJ:Df:[@ٰ0!#{V/4O:SU(ܥy[. >*gĨl w>~,bV]ph;q$RǧνP&P8NT޴$P oDZ8uf7db=^8 aB6XUA rJ"~[>_877^aa Dpwx5%yQd%ؽx׻Sߥ^`bf⽞x~SaƮ V\0olu{kǪʕR ӫFR^lcZѝ;N %3k^ 9 AGjSXðsS QXw-ۭd`8b++ WIljQ™[q9AG\ Od8`$n{O-% ','vV19099n=瓝T@ ==.ٮbXۨM :/<߻k;#nГSB;Ζ!HdVRDJU_;m"\P=lDC釀\@;jczf h#5H3 t )}|#򕣉v|=yw2x7!+b3T+k+kJX?ơefI0}FEAJU m 0ioT1Vۦ˩Ax*S^ZւT;V 4O8ki1`.i_tr"[0*R=8Z#d9Gc:x3vb9͵l?j0_o7y ß\uOsN(F#=qZ5GRϩ:>)3$>>(@hd*qRTO^^j3c:(HӠ{ZpABV ;Cq~oZ+JCGNJBΎ1P\+ lOx !PfK_:"ؓ[7"v=l0/O>r6H,`qzQ?Mxi6'@E+TS?{0!ѣKBG˞/%wR%׺F#! ЫEZ+)2!{Zn+w|pBeG*;AI^@+o9օ"?܃./Y;a 3 0Cj0DQ}kU4%_.fmշͺSy ?caf}>7*Zg-51gEyq" ] UV/P au}pޗ/2󡫔Ɗ^a^tH=ߣ]7w^l)$z=ܸ].HYמG AD {$AZ)"gXy40Q Ɲ,Hq%ɑA 8"K6]0][N&rWhNZڭ9h>Jop2پ~.EiuY2 vvPbOoݔx[F? X;pqL˩?% -zb Q}(;&(V%p.WN"OBմۯڶ^/G@:YrԴڹ5tv Ѯb/70[EN|~ ras8zZN-/t Pѷ{zac7`[zt o;+9تE;d)C|5IŢզQߗ$'XmAfȾaj zCT.J˓pUOg|-ff~l= >F޻wgjz{9!'+;Gg  ٧ +.ڱj5V0P-'V)eRX[%B/4rCFKXv:&QNVnߪThWj 6m`> =>Al⢟S Nnon GA%.銣pSeNF]v1/S⃠PVHFT{lJ!G1I^H{'6pڌs@:—\*Tir)_3Jժ\ ،R:j]() v ep)U&;=,Duq˅ c, $-H\s/3 HCws YNP)&Z vQq"V SJa1(t 36l;Nκ}R/I!錪 4Nd68ӻ |*q?Iۻ|ҧY$Z(ʒ4'=Z`"Qz{{ .H>WCV7)/\Tq$%BbѨܱ=Vz vI2{%,)s_PE'ljș_?xeG4=Z (`Q_|wHҔY{xܺ/ǠA.3{;#7;ݚb˦8rv7Ğw\}=O}7vE10q]C5U JQ<"*2(~E__ PSXe _;ǝX|3_G/Vm7J%L>AHEDH/p}t;Ϲɣ& u<ŏ󭨸jo`<2`Pn*:s~Xޭ8iWn8?acTk%P \B0pV`$v$8֊];HR;[]@2C{ 1SdUq(zɫ/qWҔ [|f_]G{8Yb/#Mz܇ặOFjҚM+ X"J ԝN$5D!O{fI7 E1Xi ^[(i~Os C9}yy(X߯Q8N>|vZrbj=l";?|O=xMjc댁yb-|GV..ŝ_n ~'iYOX̞ !*ijTQؓE1VZA\ShʽwgqAߢFMJ\-D7YAԂK gE;K6R B0°@C"X["B1B0exN:AlJJI;w X'399`IQ1nD|yN@pZt{ b5G4i1ګqwKw찿)tD=b2bba8*Z}&=do0˨tX>Ce4 7et9A`gB\_p3Y7HۧiUmK A*v>uzJw2OS QpB i(}b^O@R #qZr'X] t:]"i.um/zwND夞sq#G$Vcx8p'Htr<` Ń3=)KvwGm}ŗ.{|-u|f7g2xZ ɅQt cvΑՎYWhÑ|u"!ʉ ;mr-|ߚ:dEWP5C?a¦f91|1~s}+Xd`$/=ENQWma=(n<#N78:tو-,^Pk# p^P3sRGz^؝7![Yv Q'wGhЙJٓs$M(#>MG90u>Q@UG`wxƻ`nf[~ Ɏ f|^K"WmqmR"$?+qNws)ڛ<_l;[_:9 jB|^TBׂk`\(W]^[>H`/2*սȱ`I#A9MTop BxYzhAvEРG3 $P-m+6) @Fax.`Bbt~qm$\j'9hp G+%"M:shh05<QW0 sg`f7|}sU|5wGb~vy\dV@BͶ ; i (g>,r@G5qfulPl> s`IQ(=ua}uݨTt 3[6wtHQf,gK"dpdomf _ kQz4W ^IQ|% DU=`LChdeyp̓Se}d.\LC;q} 9NΡYMdz jML ~xYj[H%tS\+~-]pLEz`ehoGJcIjHtm騄˰`}k+P3&0d#Y*ܙ\0nz~ u.; S|}ENؓX_a. \Ew]\r]B~/0ю_bY- HLG(.%:*nw($w2 RKZmTjVW@E+v]^Hva{$!cQH"]Vϻ'.'R}As.кS\?ט''B!wnr"#:>GʷG+8^alSرw ;|;^L IA֡8^/Kw%0,K8M2t?AV\@U8GJ K!l+]fwO]DǁDpł./~H*!U?sVs" Z9Boȴw)ܳw`Uz+\$9Ǯ=)0F7{}Ĉ!R$/QOJͺ.HTultOicꅘg›k5bvkUj 0QǷ^TѤ0x5~F>;߇欄ߐgXh3Y^zg}0 ]֐k џxZ$sj]^u0Ez\bཫAR#U] `R(0 8f%gH1(]*,~. +(m(G eF# Bag'4SA `(npN\ڛxO]Bݿ%'dTlyM2CL>:XR;/E:>f>I?ZCTˉ%4!S( paP\8VNT~ݷ<ʋl<ߵG x46[8礢hMڑ^} k~S.:tJ#78]VZ4oz;4FnN7'xg[Jd-AG2htmޑ\v"}#08)Vm‰")"vS0*Id .xG[яr 3ϑ3BobpIowfMx$5;`|G`^mŵ-+Yt6},`*ѶO[98T5ŅwŲ-fGA9HS]98hJZeR#h5(Д,Z[Uaty"j+.TL-TCaIO)*DkY)PR ?`a\YըߪcSY[.kOfm|AKŔa0|F :V :8;{Z.ɷĵyUZ+ ϴE#iL]B nnzÅ +$mqD! U:Q9 ")CHf-nxW쒚Eصd?\,VD\j~P/$M[4c06YxL~ydϯѹ{NjV2j֟pfQb*/:l4zy=A97$6Y.!y}y*a{l9: >d)x\{I"^Dx ݠ˲ 9D΅W_5pRl_$~~Yu”u‹A -UsGcTjBұB dKŎ؝ZOk' ;AkF.;Ek3e&?Fl e!Vn~cgx'ϷĨ(k.|#.댅b?E_Gĝ=:ض}stz'@L!"aYX5]R4D]PDFb@0 ZZL(v7i5CQ"``(K'bYP9x5Djh2j> 9E('\]|k.9T^\6+~hl0JN%Ǣwh4`QUwz߽w 1wL%!x-pPŤͲJ >Mӹ 乀kF}bu3u VÌ=hnHFս_%Lm]C XZ`D:}CEǨr>&b:e%+4>Égl>Γ%а=W5vl-%_vꉰʵ\8--8 PӳyqT.yB2OOW0R/|BgOqxHOгvnĺ!ZwRߜa E徇&HԊaaqĢVNn 0,\ֹ&` DeGҜlG QTD!?}8n>Q*HIjuϰ FX_h_04gG9)H I 0Gj14BOqmڲ`8?ߌ1kCdҘ4qXm1|̹y-kOr @i0 ,Hވ ,n(Xۅ}OF1(!KQV!n\^6+ PRxjͦ1&qp1e&\TdHT%V6pie뉲>5ϡA;k]œa>tOZRL9f5X ]#~XB6: `Z1Uks7n+b.[QQdXU)/;Ȗ JՔR=*ҝ^4qkJf2QX Հ%%]Q1oMJ3FFePO0[ǭ.7Ьm`vddXj}"Kf)U/7rxw] %fG 8Zgb3wF2b ק`P| ntk'.̎|_]`aÝKs}gX>kjvNPY FB`{ZC\ƙ06CeKQ;&`Z;?+pEpf+i_}!u#N9;7Ƈo\ѾϐAsO &~&dt.Pu&U:jH_^d\yMUDLa {N L v'GFxqt!~VN0S U Uy=؋Z:Ij/.FROh3J|/]EU*C]x񗵍L1C9dSx6ޮł#Jc ԤjЁ&0A\}6ēug.MnZ#! Ȼ"P۫2k6"|ݶ' rVܙΝI=*G?H]XGiF$F+˹pHD!8;%Xz/ЧQMp+h5/—~@GsbcW:G3S){{TN£"w9+($>pMrpko{*7 ae{fUnVh^4br'v5l;#;fL7˔ێp-Yim{fRwP U#ޣu>`u`p9K٪L.v9AXKk/) ;ZT aD=, b軄wj6uf?efz.N|'\LU&ģrt'_^)&,{%݁fʉDEapy=#!UH-q#NT6{m@°E7TDp7ޚ[ؽ8`"ʚA )XzW@µƞXBPB`{}- [*<"q)'u?lroW"5iH}%I3Ԙ28-:H s tȤ[jP3a%Y~<#3LC \rJI@TfQO3R8sTA0 f `yQ~Lqߵ/E*O΃]$>5A",r.X_c/_:>Q!,iPL2+&V` 0t(;-#3utoXrsz f96ZP"eфcu50i$wR 1!&\<A@v{;ҰU,M`l_qÎhoFbӪװr f1 9ЯѠRw -K դvXUDLv)G^>A=zGNv8ds5fj Zs/Qa1l6֕jz XPfiH IpmtՂ*Š C`#Y-S\pԈ(ph ڿ!C]_[J I )yJfC5GFފ6FGeXtD FBOLJ_CMF"bic9>_:I^Ф^c":%*̒^VsD~c;2!0c~4(w"CKYPO Q~Z6fYM߻=k9bZ3C1)@U*5򀀋; D)Z7[_S2]M ` p: xjl7IZQ3yٯQRWr;3H1~eL^Igx'2(/H{X;e)p:|,7ΛK&2iKK݀;Ny5 AwJQ=Tv",,2FW)F C[vU7| ,1Aư%Vw2Ah臅AU\ W6RF>bλtƉ;*bAk@%ةnoE1ךڷ.ʙl=!Ca#SlBn96y"區M+4myMgr9q:yOKc*1q)#˥lIori&6 ėa& }$"9\rLvu &(X.In|dDk7چ9TGxEבhdξǎAס(iϕsâ)zA<8֭gJ00@A҃ٸE>yk 2zQ(YȶS)FRKo./a8Jx טP>YMmaoˌ2!pe.f>BIV (90@0 ѫ!-xEFwr-ЫYfwUkau7~Ǖ~+Eb3b&!o"% f^#V6g5|?W  n vtG8/pF P:Uw1wdef_G0[.n7N~uP/[ PVH :!A :tvL^f?\^ug B$"YٲLD$D2ry76wNJق=x>>ȧ+4S;qAHt |"C-oubJ $l6&f쒇@_komjcE;tF`R28 J:7OæMVwapL&V8t'7rhBdTl2~\;#y':<+=N1@ Cq`g/DK_@" TC Q]޳2 N$:(A|}*;>۽3za7s輴[l4$wEjcgN<@now?@~湎¶ĆJ-ؕQm9yP6vʶr&ӈrq%&v}%+F-÷6UÒ%w qLI&U3Z*Zp +''9.XZsLgL=)oa>c&tmәuoT OZG! B<xliD5Ac DHsys7D!l=x*)IX,8#_)-;<6 EE:={wZO@0 4=BB'ŸE¤(`Ąsl"LlW)=Zۨ #Z"Lv$`AAg@x}Wi@ʭalH>ɨWbhv=e#2a>;]#\J"urC%vd\US(׎lCgMTe XYi ۻ\ rl6yΗr m;STzs?[>&= F zP'@4(CfR$w8 0@}q-2C$}qO%Zp8a0 c'!B@Z$/gs%6Җˀ`WD6+PAa "(H_8"B.񾉱,FBVI!z1h,&Sp rKF$sozg@AW+!x}4`Of{&s6_Ií.@ >;Gdu>ygThB;C* ^TOB$wPRlێTe< pOw@:y6/XkFTZQwƊ_,]|͊6PfkzVꉹ#]xHi$Zb $nS7FM*RTUUx܁b*-9/)&X^#CJT\Zb|!4 y"OgM1+;T.7-2. E?JF?+ИnC.D#U @i(Kt cd8!)#_ew2=G/TY_+?q:*=lq?lpyu_RUlZ|tTKRoɉZǻupX<v>l[8z?;A̬U2cZm۷Q`Gq,g㜘zytgÒj_cS{z,Iڨؑ۝Hv4|.mj *v=qѸgP{~s0z6j^5])Ha9Jv=zo>',Ya Xknk ={amw2qnK5fm_5jo8 ӝR mS ؙ7n:vܮv#2'j7ٺmȆJ [R5 UzkL%o*BUNfR'k7RGaBjTHhc*0k(*Օ3 lȪgǏBe]O=- 8(}w!: Uu6rLT4z+Q;vJ2(j(Of+]cuȨ]U3vW C#]KB%{gXZxXJoOgc@V G$Va*DDj;cG jSZP!Zqtc^ެ,kȪq}d;-PaOa9壍6R38ŝFL3 ˼^+X"3TJj-8ZF 7-T>q5ur;9VĒ`Xp/ZZkh[$]6A%&*D#j 4e!LXQ8VJG0ȘD^y1omu'3 Z=8 H)y<<1rNuVa~!P1D!!Cs{XacIȼzUjL)/C.dr vd-0n{[MPjE+>J~#WSVaf"S}|E]hVK;Cاh0HZ RDB@iJ֪shPZK10K֊MsiYsz*QDR&#ƝPUËPs*\Z-E3Z4XfZE }*ku-S(OgCW;9Jˢ|3tt9oj')epXʣyZ94H2ffSޔEПE0*i0*JAfOqQQ0q|& ⛺IQmѱ*$@ HRU%o{ݔiFq5"a=777 RM$MzC$rR)!6&yW0QeR@ej 5IASq8n0n9ݼy*v+e;)Jl6T? ` 4CjFcx+V[ELR)WXuSFnizۨTŐLtH3CoxeO~s2jqJ?BKDA. f! =/ף @ lG~a,a4xs_ }^OT[;Іsc+Ssmzr.9ll1\*Ѷ#NjS 5rW)z L=L]3Tـ: 85%T@[lNNDޓN&p>Ac:M&m`kBWCb)#KdYN[reO$&%sXm0CD20AXfZ֊q!1vHʥ:\HiWo,us3s`&nnhEŚz=X=*_905jprt [8iG- 'r)Zؙ,P@>"+)TTuj_  AB* Ij)r><<\{f5+(.޿G̗?,^(g(,gҘ"YcV6aTUͬ5jVnКCC/ZZ+j)jVVTVTVTVTVT]b(Q8E@=i?~vBzStbO"r# e&a-AQ=_$&=I"0F`xHz/!ޘSd(MۤFߡ^z,(:FҀȞ@#lސߊd`:At53g$4_+kMP'$gE%3{6e/q,l.Ҭ}+X |_xC]Ð JZ*zI-k=ׁ+t*I% Fx]~h=Ȟ8E_fɞ75ښ DLߋ_gZc鹘(WΧ _wZ$EakNxbZ*ךE( ڴ${^_&ɞ;WYPh**zz=7?Hv,\av= \J% x-:9 Di "T.g֧Rj<+>kEM=XgA_}V.<2z0mͫÆqCiub$-Fpk UxNϻJPŁx|-ж=i3Z2]o{į FSs52h7m0v57\/ |\̹ 8bQt3p>Iw~]41";sU^wYxsSjE?եdOwe.%8ࢺyζ}z߷}4zUu{鱬^0URjt^Oʣxo3T-0UZ?l/{B1Y@DB:3VI9@ӁG܅/%ZxXǀgɷM/7_sЕcV-^YwڞWud{  =ׅgzd0:,)78 Ӳ.QMrt\c8 x&Zn& oתhZBf&;Sqc"6H$E̓oERmVA,+1)ƤH!pNb+jjkY/^Ӏ?Fw-jfDf :5u S$@Ӏ*jZxZ;7zzWOK#HiiUARVz^/hRV{_+,<` | z|AC௞`O$fWOK%%HxGe?o^7s~7޵;;3I̟4k`,!4/z#:Lb%d3|id3Z=J9|W!$ZLb>oi9/\_))NJkUPOw;mQFV.ön>TpEnа?u ) D[5\JPOhon\;nۢ;;.>z? Oa{o`S6K审뚮gUxXմ-_9C4Mle106=F+_o_l 򋍯RhV,$T뚮f5]g9wٳ|e8ONzY4$mκ}g{P`j"CxK0_%:ko|XTtDO>&GClvtnn͆fSF`AqM+4*J#3])no(@J 0?2>@H팛wΛ݉7ih&m(gV]fըbM T-qZMY@)Th髸lnTRÓ~ZW*⁑eCÇ2lTA=m6W`dnQoj9 вo\>m-hgc+'pF+b5Z7-̋|XʯbW!GC1%D?v|#b ѱz,`Uk`,Q)Ã:*|o_,XO]o0sZo)Esѹt-q)DZ17ZP,% 96w9TXjë g:m &*Y !H _F<_ q ߭ۂz9!6\س;C\M&΋RXo`9E1_Nk2Z[)k&mb;@3K{j!ǒ>SûMr4@#[x6\=05U)02glU.*ekF4soѝ<kT"ux*·K מ9؝=waKhAPgϞ3E=Y_OƽK '^:3}vhK皋`Yp;³ҥu`<83nI@Tm hDò-@ilE6-U87f,``_9[{ |ol1^t(]9џ;(wȁeTL] #q_o lWvݮ@W+< D(?.}A*bfNaX*FK}Δ-АX_Qzǝa㓲T5$;hzUu Z|)ӆ;HTMӦ납QڝN`y g~# )5,A,i*f6h$^vm VZw?@Nzmok͑}KCo֯ [2V~=5@h`OukQR݅;YXbCr}CA.=Z ` 'I4 ~ o-Ǔ'~vںp}ϣ=M[c~! Ͱ3R׶0^2 ȞyV"|+FKbC 4o߾M0Ò1-!SHXoҀ?5IQZI@xJm-97W.]r3Yא6570U,7E4n?3ՕJXIz}5 -&n \@{*uՋ%aLG8 jХ5 >0cf|W?[{%;,qk9#&;nGlIPzC#е gxjȡlYGo"N, mnaOCPcC3 Yέ1lv"R!4: )_JvqQbnr"O!Z|F=΄CH|ġ+"|(+wnHE>}R#1۝;1f׷wa /Xn'\zs4Ïؽumں/Y4Cլ Wޓ&Ax}h V!ԥhSo\jGtMh\(Y6zΑũȬv78;9k>f[ye!G Fa悱(,?{д7Rmf:w@.9GxTX6A>[}};5Hj0M0F?Kuo-7N3L 0`ElQ$a WgE + @)b9đGwpTOSdFk$I/a JOί/X)^ ^UBoPTV N}6$xԽ V@zprPT y6Eŗ.C)`cm<+Ln#5Y1SK$uK'8cl@J _ߪ 1$ t@w Vjxjq]S*Wc[+mr?(>m-#{9v%wFkR3Yr:O6 VOm.:g- ѿ'g׮?8_q,6.vR%*uq [m4omkm%~\<>tׇcBg*X{GV+I8y ]uފIo!ї' Xlx-f#h +B P'c )E4ht :X>8:UJEAk2Wu6OF!|a݅g] Zw6H}׎3f""؈e0 <^vU>pX/gUg5ϕ+@`9EG$+'* 6 Zu!Xe& ٍغp~N_q|i(W*_,4,7j qDߠ,O듅tbE5ºm 7lɍ3Á>ώ]BsWx~!xXecL2ZOdxKwc 樓d*#/Q&P!%[o!G96pgHhQU=>=,8qk-o $P᧿^nZ1`I v{ \I6.M+X"Sk֝3 ūMK.lvK%Y[e)m%H.؞poL#~rc;AM2  jḤžܛU<"`PPr3=, N',i0*" 75O !啄U&Or~bD+@rրiJdQ *T((l_K,mxT~X?$ Ob^NZuZl3V (IW7t2 oEG`zWYΆA96*p Vv\-{rPv;>+&)4Mt? ,Gwr/Rܝ)Jx'Bh:>--0bqbZ!,H*4*FhG&hEpQS%Fe.' 5 i_XpÚ@V%EcZ8P\*V75X5).3u )̽$9#RIt3'ޯ=Ime`to: xu -> e2u4I4G'Y=f"Ǧh7:iޡn0 ac!3&TjW)WNOex>M  j7Nd1[P66eLj#hSwU(Syi04fk; ~ճJ{Z0WB' z4h/x|23񪞇FZď4z&f~|o'G;998HLsT:W'oegxz?L0Sw3uwe3;L4QFWWt p$FqU7HEz=R D*3IErHEfύ+gvJ?mbJ܈Zћ冲\Ԇh'bȐg1MŀG^uMP+Zχxeb᢬hmN.~MW>U-ķPىHFؙhEU󾲢+8QQ?"0pڠr;T0C!T>N )Nf>quN3YLcj^$^y􎮀:)}M`L}$n `/9UV!mf"[M˝Di[ښ'fmM 0KW[Nhܚ`֬Afm=ԭ__Kd\?H Y[3HY[%L}˴V[E<}-9x!KLm^ѷW[;_WWt}l~(X&6dbvz[CTةk+L*YiNt:@"[FSzCSн E=pƐކ2)j8BSz$ .^ϥDXȈN=#P.4]ppM}]W9g#*mwU~ gD)}Nc.gP_EJ: :؋c5|m:cZMIoa1-kJ&HLŴ*&h0T*,R%D JRI@GC_є):Nҗ^їfv4sg¤9d['1i"1F,1Ҙ8iqID&l"⸩ ㆏7QTM0;>3|-C ^(4 I ǚoqڦieuX_2w8ju f>ǵ >gm$\&7,Hk`?J6`>c ovb}1s{'hu@^BFUŮ"C;,JAe-ƾna>Xp.,N q%WRaa"+fW'k{{lrOp-iBf5=mL34ʆ)N׍ӖU!B#ڄ a%1ҥ' 7U8hN9N'z+앮RhHbq|2 T5m|a S{q >:68 ѸXi61L(2'ֈDZE%zDd/գ僨\ 6/4j81/)uz + kG jg^:$yFBOO5(58ݥ:%YPbLߌ=aw>JukSSWJ5 +5PXEZR(JٲDߤm-hNٷ/k.:b|"u5kkX C 捣oh#jA$ 8ݺlͽ06˕pqЯߴO:n2F4Ġ9/19eMYf/4JipNHrm*֞%2(UMl"/p2m^[UMX2M+F?k"i(WrdAJ#`d)Ax *諩OzzI)/ k!k~P!BUuM[MI_4L:nfiV$zͿ$̕ZЃrpWښЃ QKR54s&Wrr&M͚ܘsyVX'#2d-1KB;)>YN8Y>NDFXixaI, 6\>*Ix"IM<%ؿjӻEn]eP2YN2 i3k<ˌm`gfӻEoMi}n]n qv0E?5v U ] F#q \MI4cv)Im"5&b#Ik"&~)jbj2RŊ&jz3ik!Im8XD];%0*yF1I- g& 635ZЗ4 c-2xɾHri#I[HtF+0%U^Q5qln°3M(XD'sk'+LVe#FS?L j,؉HGik1Aʖ۪&pW8^uY NOLS'dE]Onc-z:62Nw~'#[*NcY~|gEݽjKNۏIثmbsY) c0_'lz[IGiK`wd'vcj6b ~&l3ǼzM77f7~I 5%exyjKv?RGm0)0c>$|&e f ǐ_O;a B+oH;f B+o 5ɳv'g]5i̙iWue<{M{|#kڿwĊ3# ΈЈ!# F0p1-C,AIIMc+#*%᛬Xvoa)gkg!* +xHidHOu !~R%kC~R%C~ 3O^g? cɾx8##kov*UcHOeƐmKV$7ϊY<'0_!t: srUкfߧj:h9z隳k%>#7J>awνr=xSǺsS@ .nqTq,{x_ƫAv1c-glmNu躞 r6rŝ:( uqڼ:?.n&g{Ͷd|ږ oL|pw uP b@˅ hQ.sGw}h,<5q_?cb?!lO=1#Y5Ľ!̩cςCԭ^C+I)y`< 8h(pXۢef q,gLHi+] ?UԹZz_89$-@ZdV2}u RY ^Eɝkw+qpPSWw2c`Z#zZ `~뤃GZC9ʘ3։AI*-HIdjٚ XN5"B˳LP㭬|`jyzT9Ҋ*U㔩1c@L1L冱e HF316e7qQ#~3'S0i2dtcX@TnW[۷]VT.Uc`Rq_f2psXw&P/9>M- FR**ǍRA*'o2CM”T_yžcP Pcv*gPrَ'JuSlD-g2\ .s!o Ԛy 8Rw:gBE)BR/^7"UH70_ J#No34MP]o%/z2lIJʩdքvʭDeíXΑa[zIr֧mLj+8l]^]l݀cIoc8H)V>^z뚓!cRcl(JU40_Z4\"V km#C3 ﶙ+ͧ: 0_x|'XNlM`ay7 ?8N(TN-}tRݭ+?_+X^8gʰ4ʙ r.WZSV|k|Wv}۾=-X615c! ."R.Xx%Vc;ۓ/|`EvD1W XIC= ѝ5sGw p~t7s; %>;.93ln>׎;í@߬Hsxe/[v& !1ءSF/h^b~ plf}l,\,35|a#Nʼnxp|(Ld]Y]XBJJ+,^M`Cl~&nQ*ӧR JPi*{ZЬ:<U`fJ8Dтu\Ӊ0q$7!˥);l4}b8 3#~gAk"Tw#_{ wo1uu,a1ƓBpٓ-$) OM xbgE9p\rlBkޕ>~8{ۿ]"6'zlneLvQwИ'gk;@@;!4|*ኊ@ ۇ c?%-ph_;X/ qQ =|n`N ߰"5,H0럍Xq.>~iD ,;wN~@lhS~vޖF|``6l|wt֑~x IER+#ytFK`SQ_~Yk`}>{c}eBdI=H`J tp9@h uSa2*:ˉXZ0p71{}7O#@@%L8hcjoS&ag3{b۾K[o"39+@1e.-FFwz uM|b1lQ f l`sEع^& AJVJ"7XŅqE.ǵlӠ4RFΓ(JXeܣ"BR) (TǗଋ*Us_R^.L-sdF6S M`9qa8#;pG8c(juH&ǯ /@4V\zWtxZ@Oțwt?!~# /5@ puv߽2 1?.]}K&Si};]]b/qس ft;\¤ l>eF&+Xs HR&`,%C)1 4̄;g+u2UA0ֈk-$tƱdV -۵2agI1W1($@N a*4 sG `q4@TȬ`9ZQk}8M#, c8M+HpHS~1EC@U_<#HVi.:FV{;\μ!>d}xL)hE_൵`Ş==:`0Wed ӟl`eAX?t@R睋s̭@?37mɽĥ<ûi `"lЧgG|!0Y.=þpk@3l!`l융6r'!&@[ u5yXySOŞs&VRyN"}X͞gjњ! H#πzEp!Spܦ QY,cXu%{yJRb^Jz_Ղ&@RKpGE  !῍Q-g]U+I|@;@ȉʷ$J<OQ;CN2}l]2J1pP&:xY 2eWE@=[x@\aC?t$I[q: 0kts$Lbc."S) &}4%a0.I'Eh*RA H,C!59R,5 yYEJ ?6e9 ph-ۂ9T]k5X6XՑ \J1Ĥ7$;nGĥ$ (?B#nC޹ŗ07. cVycn^P VV`bU 69v.-<+Duc$l"33Up$7W A"ve᮳Nj`.w^˟`Lwkv۠%i*7DUhkXFvQY41>Jsg~)E즡3' 7*KŅ]4$!,vI,%V: A>Z2FlJ+\KXd&IC_J$S7\tJYzip$">>dM()cM_@8uHP2壳A#&|ϻXbt0X3oS7dMƒ؃jRc奬j>ӁQm&3vl`{pló[&ίք7{"ja(jA8I&l+lX& wXg1=!4"ӈ|YJ7^, O⃦&d&(w/9)fY)$.k':i\݊lA 8 䍈#9$w:t\n !#@ק .[dz=W0iJ5GV`4Euku-K>4Wk,X]`mus Xvtð|Rnk (\U.k 1/Sgl09{ eúf@eaiϑ j~ȆwhY(ũw ,Oc g`ZZXcH'Z:??DC_;d$wzӐْ6=q`Y*jVXI! 9;5]A!n9@^< ^]iegc<3F17BH܄f [ HALuEKG1Y@P LXe >R$WkaN(Q6bͲ`D$Clͼ! b!}ͷOMǪj@ boF +V@U>^=\k_AZ},gpNB󫼔dcr{-5Q??sY [|Midnĉ#FmrNCh4`Ghhh9oLV6&b b4j'$MUEMw4=ec " 8U2ZS1򟈚aR( >H2(g@&\ aW:I΅eiq:MWR{'}'q6hC5=98my %kQ#<+t\ <r*ѕumh03H|VVsď_CpOrP7e_ъ;vlm0P YW{GVl%|5/՟zj xawj|wJGU~]Mb캳VRORa<p*%Jc_%t֪wq RY"0S+5s+WRŠD+BV*yC+fVuX5L,"(μ~C*CwvNퟶ*VïEJ~Gh NiVDW3cܬ:Uoh8oXSėM}[;q1bE?lȑ 'x{0ejE%zR5cnHN&hy;;?1F^;VNA;A'`>E"|ɣyd΢ԧ/:/P)OJc WG^Q #ߌ¢ 6FBZ/'@kߢ9>zmr>hmݣ IF#ܩlLf {u@;8LձGwbhnڊ#DZ{fTjQtc9@AR{36T!AA PjQu)[5n55`?[IkYM2R `/^,i|xҤǝKԧZwKdOO)ZH}(^^e°c4}0U 8-Z5dv${{cB:p؞PT3x{`Wb" v#;Zќ/v'ҙ-ѻDlYepW 믿yw_zCQ'w"cy ~lrS靴S66eڪ+=.ה7>!T ]+w ~W@=9dWEkBW{jp13SAUhIG%} Jz&,=8}&u_mUamC1.rʋȿu6dyq䩀C:`^sȭO/JՓ ڥeW֢g|T>֊]os`5}Jv,U%e>#kN ]*gR+rW޼dDVkzBz+wEɓ^()d#J!:$s ~4RZQXJZ1%զ6k"e7v\9aS㱚ǫhEZvc56Vk*6֪f`[Qa+bdKK$Ӻʏ[ ˒mzPG& )PKBI9Jm(zWNK nXY`1dgN&$gthMߌlJҒ+J(yDd )scRF =ˋ;30 n>(khO5c8kϪ!:- ZU}x[k3'kVcDž3In)W#kq?el}4ydXP 0\~2ƙqE("dvӧx?ɩs53BPdpn9v|OdWP_ӕSu4@~7ayt EŠ O Dས~ o"XA+jOL[ HOk7Oump\[&E|RԯXoH-K,M!!13@\=>2iґiۼ$ (X8!]Pх|>H`, 52k7P $A tt8-B|e}T 0JإΧRE͉χ`-vR36zy53ȿNi4:-:Zn:qɯB?έkԸc5w"H+ LL=G$qdE"\fpK11<_Ѧ>L_NPHZΙ-{JgKv)>DFc(O8r/Q`4 )Q+L ? 6Őbk T`q8v *!.(&RSp]R4$%RQ0fÙHq(O ?kR9 ?%1\l(ۣܖxeY=jF{$3d%>Z'Ni0`U7^ڰ\_ߊV4WO3=1g0u!j:`i{3 =Y !t'@rErI<1k!,߻9' FYԪJēս#XJ^a1DHH4 Lh X \&,0L8#'T,+ȅkFa3V¤bQ-:Ub;vѴ\w 89R/IPɸe] B^B Psut=N@~G7Gɱ\XE, T{Mhky㉃[,ژq`oI;2@ݐelrp/=k:DQn(8&p(_0TLqL(I:P5D$9 0.̹.63aK\}(f՞p'Ȧ9Eko8CAQv=Ú$ο:*G9(4̮$f&Tsh"m}P2&CMe}ޠB gn 6!!zL$HBY$^8!q1:◑폵_NfJ:L4\ ] &23ӭk6 Ff:9 It"*zh{,MZԓ,T³Q~2pQ!GO8i<. ;: hYEoy8mx,ڎPqq!\̆uPl~&ylFP(mJ9iv3!3|8IA?Ws5yUPRa nO+QH=@D%^eNIŲVVٜaqI5sXBk{+:fO22ҖhSXS$;C-Tᝣq*]{y]B| Gy_#r7n 8֘<0.{(Uֺ^䭥^7ڕq(*[ ib2Aiˌɞ^bIAqg/M̮ Q5"Ґ&14^.6nFP[ޙE?Yc2U8sڞc]p#Gc{Nyn<َ 4e:~ Жkq:!(ˏxH{%la5Q`Ǫk@0;rGtJFʔK$SS1FUS E@7/8bv!^ :\k v)CQ" SIIOSNRTL↹ˁQ k|7b7 ;I)](/4=এC2Ϡ?V"::禖xhچ3|541BlYF}ieT+U W5HPDIe%Z6ø%ƒf (CWnMdz"J,{[ ~9Yi2hAtj:̪\n|ɨ0b 8 9ܢ@<Y!;}}kC.@&O_0ﵳ.`SmR;GHFN0jDqde\(7J}Ӈ<f!- mDY^8!&@VPsg>TaJ}dd#8ٺ(@ iCA0 *ssikw2b1{ 2 A9M5t$6dTy][dtE~Aɼظ-^HQ|͓"w& F؆M\a!PA(X&"O g*N|Y~KKǯpUE5}ؔ(QnZdS WTG'J2-5gQU0JIr{޵|> L1%Q~o Tշߪi.6;ZӗT㼬9X]dėUc..3B^7a~/_5GwaUռǧϥ,^^-pomR҃)$_1%ySG/Ia8Z# :ATdH;?v&j tgKZOb] h<@c)`=H6$+(}mD2Bt\,fO4/V@D51BDǴ8s)MuQ}KR.5/R^z{71d`|^ե1 YEMgGAZZ2/ yȫ z>M ?8aX,^b ެA8!+E=; 1odwRco 0^[ s:tSLˡޥ$ &K4kFzY懝asyw58k 8<"Ϧm|h33O\)jb5e# Owi5K8PI9BgE@?6GD!g֮JxS+9˱/m@EG:}=9"2G9^܍?i#L8۝<0~,+ݚ&A3X'@kOr[Jt@c^n,r?~s#1{3r1ϼ?z|·Gγ Xv3MgKn$xv{<8->#e)}]O?G8L{gň.+VokoR m%X]\}|?y^.nAЪU1 f?Ebm#{Si936h(B]oٹ\<[Š,p}ڲN\?vv/sxd36Cy z J#f.&3Q6񧯇ş3QCEd-VD&8X_GG|-xniY #ߤd}C aSC} |!+e Ӗш{(q ֟O>vMF8*6aSaGJ7JV_l~b8okyO|sܡuT|ev4nBE\o 7JtfgAm"ӎss$ՎdrH/E2 /TEA1|gYТO^ 3.'lycL@&Cgj3t\iyUo @ρyvEwL&""w 5n(܆ԏYH[k^SǠ(DTBӧ yA<$ {;oq*g ~Go 9r|CP]1J3$~E?T}CY^=_mHhS?I-YNaG@Py.yb x@ fpyeX#Ja-͟'gjNAz'q2S:UBdQt:$7g12S2GJI 2N?oȬ2H؅f Ek[/*/.Bkp=)똱bAL^6:pJN{s`TdP-9 =5ƲtWE':=ZjB'dȝhZ 5r8њ*@( ZhEXlf֞y'Y*НV?ChD`k*:*%5lmEӌ޲~UTy])Ly^6^@#^%-@pϕ*REu~58&h Q8n٬/%ɠ3ؙ^rjȮ՞ubbVLέm=ebWzbwOM( Zz+R3~vC~icFyx˰Y=[8OOO%ҠʳՇnChG%LJ!st/1- M^])ً5ƺP3xqֿPU殲q#Tࡎ?௼ow*qG}hj uJo%5r+r>nIZ6PQ5Ukπ2T`6 c SQu3=rcǽrs׻*r=Xt?*ul#O?T@{Qkb:X)eR19w?;OoJldS~t۱|TQֱJT> <_iH *WLjɇ`L0&k"Ӷέ?>;Z{F?ZT́.Pi|&_[3T3U{x#szzz|w0P,V냌d]/o\ 1 ;¶2o?"q=iYC 5oK?+o*?s86lkoKܿ\ǣ|ZY>h*0^]L S^,|^<(TRK]W7g=v:Wrv[jDu|-v5N$d1 VA{ۯoZ"2*JKć1q8f6$WgKs(~ڵpgmBO8$kpoS›#&OY ~yS}L}D<|B8bV^AW4}àVZ?-i\v)',EDɲn8l׳-lrnm`4 cc$kɼ݉P*|y›VRܼ>3ys21)hķCRԷ@*9V#Ŝ;;T^:JTvڛUϳ4@9ncĺ]U~U jBWG !週ѸjY)vlP];.e7.{vq񏳕q)f̃5W6nʩcR'gOpBdd.fã|)vw_k-MR/=xuBg^r" صvY5r>8۠`b,K˳+ f7D@ଶցm&"01.Cq{0˸ |1..uX`e~QvIy)V;\%`n,v"TA<,ei-vi&/;2*cK MQK ڐH[Vڀhr1RGA^*'/X4H͈u`ڞ$< }Vxx;%h5_)uKɮ5[*\.GqA'jm?sݔ4zU*e~]വ i&3`uovޭ2*ΓI~wrN~\]hXAaGHC 䇛l/~YnۿmC0VO{NꐚXx '};@UkHD)HB͜uI]u؁lwu`,R.UH[2K" R+8RCg6M Տ93mSE}c? 8D-i9ӘFZp0xe&w[{q+k3=G1#ĜW1܊ubZU]ul;S[~Ƽ!Vs+P}4*d +}ʡi|yfo~?8|,N Ou..1ߙ+QGm*^β]X%Ǝ3ޟS.)U{jU:FXIqVѥ"vMHoԈ:tp"B#Zex{vC ʢ5`nG\)KW#F ᣻8*D*unK1\"5 b-!db{U-AS3eͩⰠBh'`]6KzTv/!pzsJ'/.:Kv~^R˄~n,و` /-1vyfj5.tнڟPL#J7o>y s%s$[-+fLYT GjOe He%pLڄm}r{| H{UFb uYy緸rFtxյpV{7*I#H -l":8XBeҴ]&'N7ALvWxvt %{A-5G@b4\ګD^z<[Uz=(qn]R4o Y'K]Guq;BD"s ?k\Jė3=turXLK[M҆bi%[Ʒ+BŮ}bi]Ͽ]/߮X#+oɼ)oW,ogoW,ob@H+Zٵ5?. V {*_6?m4)V7YB5^laSȕ݂`$+l3+_hϨ[NB K@}&}h{l* (OQo"Q&dD6ŅƘK@>2vE INPPy*MwQzJ ILTZ!tmWEz;zw-AaYFUQjazOh:,/z OsPSꐠ>"z-(h:BC©?`ַNOpPZg9S H#HTryVu˸Z-1,rEbB'°-= xDP uZ)Xib\qDF%o[ϽB]6Y豻q6!ysn"V2J38j8}]b jz5W \G)ciw_P%Kph"Gݍ:k+3 9DW 5lM{[SK xr@s/n0kUxSUGxB@ٽkxܐ򲒋3^-Dnj$L-G3?f5%pyP`=(zWX|< e;#(okcD4w'h>殡y;qY6s8|!pj֜!\;RfyvY"Kv=nf_o}D%ѯ!㻦qe}PԌڨv_JXcWМ.JuVthP6DWg!>j#TrSUKcьj-!ԆHEx/K\o!E!/ּLP_we< i"x`;0AZR? LvNI@$o?o+ud;W08Mrۍ5 -x}ƐgRue9\ϯKctI4 Oh^d/]\3W,_u$@z pQ06Vŧ 8uű岠-_VuZv7 GQsG)|бPJ,[Q}pll}|VLrx3,OW%ЙoMBiۿҁy68ɵv=޺]^E r1OIE#(-wTcMS@q qۢ &3pg]`N&a+\Y^"8nNvM?[U[(JL'NRi5އB3NV구Bu>soWrzVh3)q ǖ@t^(,S]n"?^3Zc;溬{viP}; BҁvuGmn*]! Ebbx]p\Ja]]BG/)b'tWӑؾ)L)w)Á{Yj01`k݆ lad PQjKY`E(I8 T)(м߾om,#1y z_*wލ3:,nFʘb.7OQ j+ ݵtJ=I޺= V;EW* UPÊ3cO*>rg0iNE*$?\KT@(P_KCSvgV>?w85*QuJu~u{ POJם:o M(n 0Ďnxvs#:.{\T uaƂ]<%RtAn8,0yÒ@I|eRj:vp c)a+00>30Y9،v_@Б,pӠ]ҍ9v+:2`Fgv9ǻ/9vV__'j0=N_-.pK$@AYr8ΦuƵ~)Rm93yWcO-%%v밂 F;up뗕.z G*-ԑb,X7R=-ڏυts!nz:l:ǫ!2t&`v%Lvmv4mI=Ee1Al̂P1άe-1dخv H0%"tDN;dۋyknG"e.X9BQd v#/ǯ^ĈŞ{{sjM3i&{.1uMۙq SX:vvΟj:0cK0S*|G1~%&EloG:TдR;+Sy%;fSf0ŕ4RJAm-%teު%QhB7R/cF186m?]،UQN1e6Q5LV{0F_aѕc90)<'q:n4)מ椒NiscbĦs\Q20DĠr Pml~1 =+1<(zޯ0Hɹ^zk8Y },F=3qSNO6M00޵#/4'-=(n`VfoI3#(<e%oezK*/{!5Rz gוpcS =J#.(]L.efLȥNՌ9F?>|6&AeK J1n8\0WC=X|S< 5',W`_~V{o.\ :xWIĻI|`+=?1%9&ƿlOf8t҈NJ )pS}8'M c)dN5?"f}D0 -3[;F34oC RvKlE|('D[OucQkqFw]fF6u[z @o]SHb:%Hlh@A\>mml*Xy@y bЧ4AXn"΁gw4|dݵ>᜙H%?o1c?5>}ms݇=dhW~S]ɷ| >ktmAI&|O<{CAlT~ᷱo?5m~"= ~|.^4R> #Ioj7:j4-^,+&M `PY5gU|Qk-Pxb^oϟ+ e ۬d86׵Bsx|dABF,rp@f .JYu ͕?`[%%`@MR~OI@,ٺ'`0Į ű:ΕDdTt/IQ^6iNpUL?:~22bhqW= 2 V*z 3V}5i!ZY]P;;ӽ!s^H9:s]=s銒BŠf  D0o_ԃIg!hٙJ1L:dz>N'hIl.cǗɽ opVyMڛ4ZCc="Xgs*WfJbJ[t v>Ƕ6ܹM82~8AQ@i?<Ɋ8%UuU}yX,l<M;p1`j UCވ~i h{7-ye*QS~vzc' $v@\^Ó-ebrC:knT:ꇈ2WG}G78;CM*hh=?>.Jj y$A8_;(ap :{)u5,N۴8zOdڵT"[]웬ZZr Vwg8 `­b@,< -̴k;5H: uWvBKkP)ݐ0 8-XrNh"7 ĨdB(nAŠ?v3y-v<֖ "KjhUP Tv`b  PHccH0zhJ,r6x.ROv)+/)pzV_Uϟ7W @+{kbZQ R@WD?iu>6J_#>YM'?[W߶RTELJ.T~Wygh=dOB)\&iߵNh#QϬkqHAA& Y g-PùdI΋e}[l]ɝ3æ,I%yH.+/It%b%!N u(/7wly5OcV} % NHGZԅn_Q^3J3:cX#%wOBE/ږ[4z4”SHSj/Hpr+?D3\9kc*cRm`1Aĭ9jixJJARmڵxm}8H <>9<<*2P1^m /Q>lm M!1=Ń;~3"5tM'Jk&^ÉbHTG.vKOK.倊1 8=M_h!Im|N`^VPp4Y>' hj4MtIhqLWXgR|6 N.N9š~ 9e;5lOhYJE(ф1d>;E&㞈TI>jr/i@<'`_p>ƪDTЙ1s}D=Caq8aξsJjjj3PVMQR\g(b4(5wDYu5 0f+r¥4>ˎwǿ?2ry֚d$./ ]-dp(-YkJr^?/|خJ&Gq/P6M#%4k~لѼVP3Xd,w A}`о # k}*\YJ"z+TTI!.Ĕ')_1N8ݳe):xJ>YDqa?A!=FR?l-73=w2)$\ 6OޟE\V8b`^Y@ 9ixP44]Y,"LgJe] JSZggU XjAYdU d޼7s8IΥГAF3rJuh])p;ǘ{1=6'5_,xT#x ~Az%6{8A $AtV<랕J}`+jUqEx+0i4wߵJ^;2R?8SA('c`+pi]` Źv,FHVE‚VRU)agyǧ",u͖mN%_J㡦uEO1У %X>h=ABVFIqSL B Fx ;GH2Wܿ?itRE4F{x5`3ϓ̜{Go[Ǥn?=9|n`D~mkw{E=QRB0Ԥw{Ldu:mNNN=ur Ov!}wG@wx{z)'v[';{GLM߃nޟv~q:IBg|qtew@d²"'Q"E EBɯ=c=h8Aђ&x^N]ya_n>|3juvBS_!\(.xmd^8Nuvb,H=K̙d-^)K_0=23:鄬kzVoC e;* =qQÁUT>5͔laxq>HJRka&3KyzrEO7ۙ.#l/ܛГ(֍͈_Bl[qA䳁~+_Zq ,P>&Q8 d88- ҦHѬUB@tBT] JMcP)N29lNUERԡˌk3Î3ܺ<BWr3!5 BV8EqJO9s{}i(87RڷDr%CN٠j64{JJJh9]$gtMPAfd:Jl'\wl*jVx`\`LQq >.hU:]1v4nmcXj͏fXLW k~&Y d!bdVWupڥ6{ZqEsKZ(cjkS{Q:{eY% iJPÃ^rU'8TMg~P1xu! σi[J"bb=Ƥ$baz t./tũ/au=\w$*ho^ý̋ Jo[(sJsVj!#wbN`4ѐRFiןExg:gMIJH$o)yQwD0a J.P!ȋ˘/MQlywY )bUE̊1}]9 M-,h5T*[須ƒ[W?'/gt>O4O[6QL:)9I^>Uk'mc-HEi׏JY2%9/$y␒M/A9Q,%rו67gS +sHcb_ Z c;kTBqSV-+$9Qt ixwE,VVb%[f_~W&5ZΌOL
3\x(_@dQÆI0Ao ['}4 ",bHtN/rH9F3E@2^COуD ǑN ݛo[kF P!2>~#vʷ_Z) xǗv{8 LAMGn?X>5<=GI^[a/P-%!EL44H2 5J/jԫ +c(& )HԮB2iHs~{W^`Рk f2vo@MX|Pӵ/zu@"9FH{?Y %z@O6GF|A}=e I5TrL.ۋB,NYmLNܯCN;l"} տT+Pnt9cykP}:'_u :~:d01,qvdytH]^b㛄ȶ Ih F :acX{87*@Eh-ucj䓢&97!1 Nj7x.;i7@OMՙ/™/G}_E/@Qdӡ Ayd| t˟nhxE+>i#ڈ|\KHƄ,M~`AxS< 1 [Zu ,cxDFH2 %a5Gh{:>>,5$\CSy4 !9y{|Wht1D vsHq%ːUF*G#د{Y2O o<2([avÓӥC a90!!:kNcnBNaxmh_8)wqI%ٸ|#kA1)Mr 7]fl;ֶ9V %F' ;&ݺLjGnq Xxp V͂́n5Ʋd'@8Q2G+ (q4臿>#& WX!&qXd"oN\rNLN󇆪T[hhdIa}2$(Jn +x#[SfM~˨RB8TԬԚfy0Z~ ?AEp4 \S:׏NJ6M"+IÁg3fl 9#s CJ@Xºsd:AMcXA1x䍑;4yۢ(O9w Pĺjaq3סrcnsz{QJ `K{Sa޺u/M(wD.(IKHSH _Eq| Ex ULX(#WNcZoOOٞËְ`.+eX][v R JOW3yPćcѯM}hO,{IY?N¦N5$ ԡ7WzoB6LptBb+`9BX6'F cڝ2BCpa(Ln p9\T~Lsx⺟1ߞۇERw*v6>kXFNsY ,RZh P fx{s޿QJN{/WWféZ967kZu8SO>ڝts[Khk?Oa &>o86sYÂFg UEH|Ed N/NU%ʴ[7!F)-ma֒1IX./21 էs䫻.&Yyn"P&wM3^^!WݤnUo `PzYa)Sv{8nU~9}&HO@~8Rl6؎%ׂpq*OXŝhX̄vP~S,x*8UH5KѓSeM׽ l9X69FEqKrjk 6LVH6jzk|H:A԰c9&KwVݴ,Ό,{GOsU? )u|J=S;?"9}Yk5@&؞qҭr^[tzt쥙tMCѰ2mOl5 d?3#9E'l$>fOp}3B"\t@;A$`XLlՊ _S-^4 y h q0r%XSYuNгWπ_-Z0Xl* ؂T i|cipy3XZM86Bz,~1UVѤ?>#677qGH[z٤ke1(9lrh <XCi"%e;45EEnKt9Y=͡s lǷt&los* ^ 'K+ãTfg^7LL l+<&}t q& 8YJɪؖoj/K!{u[gu"3SƄOy" f̴OT<|$$F{qp$\$X=ћD&^!; WTwp."Ky=@`c/ԁ\M~ ^igbHfds{&$;rYXIpvCÙw+B*? ]4kӁu U;uM W+;ke.; $Her /cGp:ˎ05qpw\v$&$#{>IHp!WZ܊IHvC^2%9` jtܴ2sVg&0VnM/ Ki{)6z2t1/rcuuթ3)η"2jy2+6rE`͹DCBgG0;.01?dM8>t=YVZ(szNGa }tw}K*ԹBݚo_Z6 R4JdSRY(+}F-zlq, lƟQm=#rHrEZ{~ NsFk~ԕ8 H.o܉#.%zEp b:n1+%*FMky7H-W^}ƗABI=^?ḹ:UѰ:Tڟ1Ow&2l՟?RA eQ!*VmUKjEx7`# ٍurb~wVp/Li9Ƨuy^4j6F] %/ %Dh+jؓevIܹ>6d~̢ 4NDw PUpTJǗTĆ{:3lzһ E`0sS׿k^CZWxpK Bi0uh$Ŕ{g6ᨹ&]?J{ZRuWZ/Ldxs>\5a%g\G`b:Kt27y>kt:တ)jjm8,k\=,ڿM䤽@ [w>]LhiQ I6Y'蠰hKe$n1˺so!biQ.@'7cj_s{d/jPTˉ)ˌi-4(,'z@י9B0cM-4fv@5M3M ]VX -|.EҖ36>'h޾Q g[K|߄!^oCjMer߃&k3 !u7PC̱95tΧ͜_,{A{¨9{ sڊr[;$IލWd$yR5NR SlR1T*^kb:M,:=}Z aTm+Bl\  LX/\VrJc^'kɳ$ZG+r/]d@d𽈟4Y@l>8X%Вl Kf$Mj/%f~MaTj:NƍOHyʨ{$M/.[O,Z1:@%6ĴƁ}$cw\dl2|hla^*LP*KGZnsM`;K7axhG,G\罁{Z9vWjk|-܄eaMbaQRV9}H?hy|n4-&9S}EI"Ah<ܻVc JY 2y EkN/z,  KH/bAH1v:=K dIT\+Dӥz3u{:D9޻0 Rpۀ#+)6LkhUt%7VX Ø3F @L 2KrsY *c.y^ȹLn4#FYafȩGiN֑! ->Fʹ8Kb$]+cRHIZ`d`cѥ35=K/w4-XՁL|Uv•Ct|x b ):}o$M5i6)9[;4'!غ>Vp_Z@'bt(WQN1-5Cgi ¢+zJ#|bYAeMt+#|F;W $Küa!w js[z:cm}I,rmS.G"楶 mTc( '1gw%P3:b3XS }Ps-l-ԗtB<>5I)5Ev2N03jg.q(h_jLx:@-{?azdTH%gmYnTA|ȲϻQ>wM4ы7>{EPyn6tZNCNcS^Sj `EJI?\7_췆i&>xptBXg$=YMꙉۯ&+5GI)Veɳ1;Zx%xGx΋e6:4ʭT D Ks`Q)`FK'BOM +u"Rɖg2_M$Qjv Nb7<|4Ε5 ן^Ꚕ廗拇inx~!%ΥY]䞞W;ktPcTZiq8F=X*LtpCVuA \J,kPf"HlD~ %Q&Ftj$eZF-A}x r?Rut'&nig8['u%TVU+ E[,xAAŒ_)Pk8lj@` |s!ƫ ֺA')J6d`p6X\Fo\ dz]Woͱ2*l'UWo'?AHKGVA'["8VL.&ȅ',|ܝ:FKB4Dm\l07CÛ+46ʹʣ iNO^"qLl@S^a|MwP0a.|S|٬ܟ=+= vo2l0k˜H/1gAQE4aȭ ES~а(zԍ|W6i/˺%|(ѨϢgzaN Ҿ|r\ fZĘ7/"&Q>w;pܛvVʾ9?$_p5R9g{MjzGn$jl*~HF{V'J呐kns2NЁ} zyNCݡrN ^@.A&;"[0,Q;$O1)bU0urA6K(/!k-5Bw==D3yX+ v4;a&Ok8JTw(;ީoQ vbZ|g'lQ6( 3 ("zU7}(suNӟkg{;blWs(8*pX|'=6RΑZLJ۱AyN[DhGLFJ:?\z)ts*<~%j5 ^j!9xJX휜x{h1=%<$A5:J-(r\B>PY!c}%1;ž`&}s.W ;E.AcVc|ѧ򤼟Wπ$:c=Cm棹01j|bl8: .eZX*S=ՙ^n۰ڸ x9c¹ϾF# /R/d'O'AaL>.j,Wuz.@iU5ymU g4E: wJVQf{[GO(R1W~-|t/&>^01f .p5[hG5JOJXDGq":R/& a=QL#^Lb5ռ|\+4 0zM݊qw(ӆynQ*G7Ih zr73Rjê(>S$ = XvtH d[EN"WF3uUމa(rܦo^(\%lgqz]XnUF!6MI۵6*t#f5$ =AN#-kcf792O|2< `9w ,0E\3+ R56Y\0A‹b2ZOj㳒03r%>N]7|0oIiO?&18WbQӱ먭|uʐ(H&0G!U^xY^]fy^GfPܓNoRf$x>ʾ'=Kp1Gmxj/,sD9p(ji CS5z]Wph <+joX=FΣ7!ŗ=;[דMMܗyCYc FOS%)?;Ђ븹^X/6n$6?>>S%ݤEQ\Imˈ:Õį([و$ͰQ:tfV͊EZP@,6VA^26>"tVW~fL-VtP~pZuڅ8l`LM@9v;* 6L+20 JCڊ)~qw4D.<$S6st 7/D5={:B<wQ' -Ÿ[쵳. G4]ު#+`Rj3E /T KZ&j[1&&dVE7RFg@^gyf;iҺAv-RgD;/ JA2foio&feѰ&I##X.w #MamB (ـf#벝PXSON(GS-?~d_)&l(#Q#ുġ8!-d縩1H =CIp>ZcĈdRdwT]OJX"Ӭ d،eKnڴ4gyv~A#:(EG'2t|%mNlѮ (!@NwdK :vuYFׄ}JOB33H ?ze5FH,7Yn,^`lT`삑,ȫ;8 Inxp!s5z5cP!Eɾm.*|O 0OB/t V)$Wuޱ ~%_ZdqqZek$ xؤ(ͨ4IyA0{3Cωޗ%$p%&PsB'5іV9襜H0dSY$brukB.4k_I rVK+dI vyoP 1hU Zʿ\ʫ7^c&!d:c T¨ Ƣ(3Vȍ"|+IHQix ?!WH&",m m؇~db)QpI -F7!GN~]ɣz]M_$\ ˀ=(Yc1'sdMR`ŏZeq*SEƘo>kU7YIs<Vf 7 wd q*lJHٲᧈV-GnŬ;LEagζL(O+9j8ST^4❳ «-^!({ӎP @ 4j%s s,;䍡 '5 P,B$ xKVeGv:E>-e:"ӻWŨ󱺂5 !GA6WhqRñM*=ۚCbKLg5baAoޱ\α\|JV5d*e%K5 K.2T̲e2e4D$RdWPhZJSH͛;c ~~A. V耠$҂Qۧۤ/,'d\ZSr Ae~D\pOj`]؛$ڻjՑPbeo|z1fhH,$~4M} ہkYLC܊aݑahzp` CTWh_$=䎜̰\p<99f`. "PCRz>{zMǣaDjW#8bAypK&;/>n|0㘐r  r Rt*bLrx#I@@5fWJ-qg8Ptb56upqJ/aŠP.h@L2g]~QMsoBu9kҒ芾[KPςlZU鐸2<.9@JN02w8v\|p}KҦn1ާL 0csͥSYSj.Lᔜ6x&7kh@JIkk,dzŸN@Ýv[0vC:*8ͽG'$\fz+FsA("*tIaƁW]/Cu޻łFk7~O x/}q95>NǏJߵ_M{}r3ߞ^ǞGX2 iZ,~+NUy$>SGV0f]1ȷބrMIӰi$QZ5'NOGj,Qss$"S)$(>Ah v4"׷|yY_g=F4v\f3cnSl_@K9;*Wk 9vf޵tfvih>+# H >_E4&oWL;_)Ng2Y:64Oc@Z;lFčECN ErKj2 С ~nk/OO>_?k ׅ*WSQm1NC9P]1#c N$/ hEH*tSg$R|W_߳;rBsPCa=V]I8 }{Ԇ!; !軲WO .!.slO`F  |7ƄN7m&~|-C>#^t:]s җ'(hdX`Ɗ%]6a:RJ-ah7ID\)m9VY Xw7&l8EN ,U&I 8lTYZʷ[jyS\T ;8$ĖMVsޙsN2[Lݬldql;ϓޒE mHx"]<"&GOlf7%v:y5qTըT//3A۳%!_xrlEyNE,(ssfy7 ;8G^ev %E+[#nbSEmgwqYȄ%Unw$FC'lIX_HcsHnd 5r%\sdT~Uo_.܍]ViҨCQpǘoaB4 Z(0,}ߡK:G75C_ݺ2G,oÝVYZta^sɈruwUo0 _AIp3a£Lv $|P rVk\/{NRQ1J]$K! "+#P2K"mUxIm0(GJf0B͒/Jydb;bz Ni"r҈碾ˡ:m"J$;mG.A1ݩz=E@6[7Ӂa'@=ds@%GhOgGIWK(ƾ/GkcQcɎS昂h+bMQGCRԫd AEkI#!:BTO:# [ڶkY)@,V{Q#Ԭ܋w_9(Jb`Y|RS/^$˭ j>ژXNSIFJ:=˩aoP,gF4X﷪uRUG \MWUA@tqtx[=8HHg^qgy]I4o"bwNaXSt44EI|ZӮ  j\%Ӻ;]wRX'1ֈg smvzf֨|F7Wdp 3f J; ߄F#tX^^h+c33H#8ipCYmoNi𢘒jeb }ȼb66C쀉7Zm+nӮJbr^ltg:Fr :c18W.ZUEHl-ގ2Ơl~ĦnfKM`0G\C%?ѡyqSZ<0%yX c97cX'ô WkNjYƗspe11ͣҥILEK"e]KN[8|=a$W;6l'x5{}6v)+zPh=B;o`n)tM>h`O)fe~Tnzbގ{m ϻ "<u` : bd*~k|zͲ^l+ty+tၰ p:iFx9]VcS`Nպ:/cD~\}x٠ 0Fwx%⡮Xw4xvb"+,ZOIVȝ+ hjاMQ猈F`vxIkxsзW JuLZ_ "קO9ۘMdc6Dq\H](0pv.p2(L6A<$cn ^KQ(eI.W`h[Ǯ ҆ UV?5Ѷ3u%μG3OZgW-J_0&WC\ arm8/,-z))dwb.MzemgpRvR cKPBM'~]a[? Et{%wX oCSF>>"--d߃Wƒ]L?>B!KQ!`(Sh+aB3ڴ߹t[\CO (r=B3uLGw7/f_w;Eq?=]|VR-g*u?!1Sw)4YDXK5_6/e̠V˽;g !x5.:GSm7Í,;Yfd6X{/,g+l֊~̗M\Qٳg#o,fTwtV1r"\?-x ٹ)Q^#{/FLQΉKY!q8N _| G F'3NAvH3Zf EEnmֆvHqWMKaEI+K+xm?N*$ exumFe+%MpW5 営p*D Kfz αZߘ@GlA7hiMТ/>8Vvx,'%L/^UCl0P> .c?VYCG1hCڔ:u4'<9E,k_dW.y=1JB{},AjH"<~5p=\ͬCoFx,scPOuuΡdر,i=ȱ 34b;YFsM-%8 ¿ГC<% .mÝP `[nL5Wr:t6@@b BJ4kiLqY🔾 )͓(ٻ>Ŕ?XAZ,ZU@4PYeC.Z7?v~̑Z|62fe_m>TKC ߣ iP3񙖡6ހTZrnR/űœ% 봤H:|ږ,ME8f_EZ$ jh]m)&SE,dѰGc^[Y:^P]%w4/P7)d /'s5 VAe XnttFjSJPҷ8@IN| ^6a֛}~/՛#QitXd-Z<ľns/R#:Z\nxa0mDcR+-TцtNѨ:`Ke )Dgd^LIP(rW_[K-\!5 XVjGNy_Tj_ԯrVj< T1$5kkѲ(xE[tNT(0[ity6] FŌ`dvFC!zjcƒYTp{wje9ܸ`ӋLÔU 3P-tf+Y˺0J3Q3邹EKxisg*<芎GÅTƗˢ°gl@×u9v:ba1t@0`I#;XBfu*HKcP)Nڎ#X Qp u($JRSH+˒Wr%,!y:]j|eNa﷏6 0gS/E9 `zboS6Y_> Ν*r=rڡg.m8pf⻽ǵƧU*Zݽ8m,Xǘ0XO'TNKHX$SM_;HѬK%H$_3&do2u޵N[^(DDwو~ ^ԾQ!5+ .B5ө&jDPYZ:n&;mZ)c6( ոA{`Wȵ)Jetչfù[/)G!trG~^Q6˂!vf NѧZ~;-UWYm:[[zmb% ږҦm]1G9_ YҢXQq?R=<9EZWOEJ=APOZ·2 bȭ(%!QH\Zd+ C!4Tcy7)<9dG랗tmˈǞ:5D=n&MBGPD@$2"W M, V5m-<RFp,sIZf[;rx6x\+y0 ،+,4*X;lw'X:Avp5{F>pQw?O͚F`홍^l?|C?Mk\cI1ÀEN{::8 Z"3TQLʕحKYK/E_ȗ2 ,1-^x4$(Ʌ܋l`+D&ҡH2"ȉ;$x4'݀]=던ьj^dWa.d/x\̀I2Ek ݨef{ AUk4"vi"y<"tٕL"gk~IDN;L*N K5}lK'$iy{j9,Z!OJv@ȯdgGg@jvJs&?_㻗j}HO:BP 5z 6˦򯒽r{pOuxrɣBJiEPuJE~0v_]J*]͓&MEGU)ӷ6}C5:rԑC 㫳V?J{dj#mdD9h1YxNCBb.E{y  PXZJ0_0or.9jcy6yz4V(x^][A率8"+&"jb*]M)qđXNy{z]:M$9~[1M`m`=P3VeCN$Es,{Gs cU:qӞjjY@o~=Xy#kȯkiLg8GHHоY﹆JIۜ1-^k'/wftv/6e52f(Eob~Xndn9ju9?5]8#:i=6R<0Ɯ#m *;!5VKNº;[|0/y~݃hJejb͟svļS}3RGhyU**P͕^0ݑx}<Ƒ`0 t3{w}9EIx(Mͬ=wl"()_c[OqI+Ȯ ":g؍C)La9)c GSv]zt)Ltлmbj'sS-׵JUw>BD"G < ü]TsRx.aPl"T)fymQB{,9TZA*|G!;H-%Tjp$]ճA.8#L{,Vdh;t^ [maX<0ҝE%(M? ֌7 žV^SE[TkkUdRr 3Nvhg[H}BB@Z"P֦vҞe (gN rF)Ɖ/-12=#堔 -43Ke?m G!%1 h,\"5FiM+[lk-<;+cj3i뿬LU&'NY9md6(7kQ>+Cpڢ^{V$kp7MyTHu,_#imr̭{yqWs3Х*rA0Z8d'q:mc9MR7w@$*tF?{)B!׫e5rE4 \1fG ^rq 3"cwhh?l#6JաZSb&H{PvjZ;If^נK{TÐ ovoA}"Z:l!p=cKKs\mLVo_ߴ܄g%O[ZBE .6Kc|RF:_Yʫp:GJIR>;mbN RzӻjH:VN/2H.#F"ѩU{P{x0:8ߩ(xhNL>qd#"l,oNa9xwNynS$МъQ pBcfFPոfIY%&G}X\&C O,*![^Ux1Ek+z^(.%c2CY(^&,mM5b'ԣ8\BGĎamF"BJ OɹBS̹9%Ɠ9vBA9\ 7a͕1=m A\Xd띹V)ٝQh(zpR`ӎ;e\W FS׽XTL5vwQX8`p4k|AQ\*@báIJLUyyM ݋ULf4=T3 m#  H ?>+b{\ekl`<ʧnkskN[>^yDC*;Bq+(msx\ܬJАO7JXX-ũ|$OjZ*q)3 0|-%PuShq"cDEY-&8M&Df)kiv:S(1N>W*]̣3LpL5(X BM.Eh> %l=Q2RHk`U6VXj/3n`-^Yp>+UDV}TML8iH i ά5uYZ~SM™khiԜ3vi[ŒEB\t5ETR3DT^`XR! $<zɭoT&V4L"4 o9)㣯I/o}P`N!mN< 4Ԅn픤>y0Y;.+X܀Ev/^ '~\ IUXabξh64 ?PeT "twQąl? #piP/&6\Hol* x#jm/+әu9<89>8=,r)4%-" ܷVxu&]$jI .*#}IDA7ՅkGr@Zw":%$/S:ʏյjBYq@Q",m-ΧzY PK͆rk~ԚM|t`K}DW;pkY[TxVQ݊^vۧάXncqʕS7A" \1}䎄F ߊK^$HD?ב%%z%,eaSw郱ZKXˁW{e2ALީA{0o0)ď[ǿ##GE:=9O'ܚke3eNqs۲pqܺdts['>1Qɖk9emv~;mrJm'E̅S(sʜǕy:nBI"O(r4x)=ǭ8JaJkd^㮈'iԻ~}q;Nt됰qON.(8l&ޘCrNҺvP(d{spxPUF)л6a} A`V ۟9w9+A*:sJRȬrOz:)BYI(32vvގ6s' Vy+5b^x2ΜXN LWZ* ;'| |N{6O XdǤqZy=pAJ?Q\=SSɞh3VZd͝fY<6#Atˢ2'Qre&ue,mfsb2Ɍ阕Ldi ) HtD4="F+#CV)m.NL]9 ;j.9yZJ/S܉ )L]_?GdoAmNG2>u~f ux)|ԅ;#2r|%Н1v CK*m숮P9APS"!j2[ Q #w?C슍}É{74;a3q\ ]&.(A=YPvEf2>Gʁ,{hS4e&vz=z*bBwl-`,]}hWF<9'/BYSzdD'Xd/q޳Z0j$έ%M'枏F\ZZ`Wd>w:h31+κf VI-Ϣ-#,W-TВ*$%v L*yTݚPTp#|{oUtٙR5uIEDÓҞ֘H͸HڞȀpIҝc$.2Әtmj0污eE7[,lIiEiHT'YfXt-q܌O W+ m$dhwTtc`mq`Jq,]g,f&-O&6mXrOX!t<4x)YK{OS0ݏ 5a fy;*G*FA!I+;ᐸe\y|6@F :tuE~k ]RGڡe%kv\YUt#cq`7=!aXC[Δ9 MhM.6?i7"@kމ{i7#I6nHpsSiп ؟[uF # m###TVɜ¯|=G@tߡ?|8*͸=0iո7}k}NY\^wu؇.0po2gMG@bBR+5]xkpZN7 B<@ Ԕ_UIi1A.lݏBSOEe:c/ ~g&&,KJQqQ0w93SҺO=%2 ܳLJLzwp9HTnaΐn|5.n, $-n ǍNcq4FD/zg =8-K1%Дc{*qcY6 t,=]R*{[$(g"8pR_M:we9PfLSYc:fҪrF=YYdrҷ$ '}D%` OeoG}2:|Žzs}oh4螩sEF7+஬\Đ=-*tD]" a 5Cլ8.TTa뛲~Pθ@:-d0i!Nw :uX(Dh[u C)z߷[~3ǂ~5o5Fؿȿ fSVvFȶwx fTQN{P$n~21n:TDXܽu AbH]iR9LtGwR;m7<-%횤?%esU6UjVIh͵W~á*v|puDVɉCt !4p-8^D/6D/Q(wQz4tr:A4߱Y;Gut X+|qM"J܄vi(2o7(pN#2nC?w6Q[&0䓽\loZFH葡G(iaY(A1 _MSUoѠe{*zzbrc̉ h&x`yEBKjakJ@ ëoo_+14ʶjݢPF4 =pR[[!8;= -vrcH.Uq cb;ωJz$ GII!t2=#-=[E;$" W"?1VN' 2͡LSG<${@=+L!JtMS @C81]a/Aϣצ+[e*|t\皖Eu\9E/uP̩anE\ RjҚR̡8(ϟl.QاW2<3|w؆-Q kGtC73 k>ÈFz +k;а1U,;"9, H(IENANDp% ĒS:VFT) ;"*@>lٶ5Otf7?3?[?߷{qWV0 +ܺ9km ea& c/@N6OS#Wh]H0\ê޿ywficႊU*e;='Mf} Hfkla3^mY!xp AKR(!pz&u8m)8-j!E8pap>3r;=i!?(SRol9#O _$OÓ60] \*=uXZ:2W% <Gnیy{ۯ_S0R4럮)C3\NKK߁'9)B pV)jK%;=L$.G>d 6vxtݳ0 &Wq lt&J5!RnUDu?#T;0ٟVb* t*ǰ@Z$sQϠ rO!K\=01h(Ț5y&w&㐖8Ts>{@ku6As<ΝI C#гG 3(}:H,$EUv w{ K07`[ʾin~h }9*q1#nt,K$Ca[lnh߫ӝ#ظ[*) qUhm%Ph֊gj!41>M=S"#Ip8e- g%gdJ ]3$U~ϖ+A.<56完$E1b p-WQL :˘L55xUI7TL<`ඏO):5(**Rd3ѩəJwһЕ's障t!q۔n8m7+St̹v[)/&J<t䉲|Е"su:.)2u{ teke)SgMrGMkCN6^t6jcH`M9; d CЂw4 ( $s0+n<9؋-@eϺAJs*6> z]aʨ,>%ZÃ>+F<cR僳Vr czɗ꿀d;O9x3-i[m],#RF=s#K!;T,ޞ9 Ik+Uxד,K`]oxrhW-=~zV1@EtBq0aXKxuqǥGD |Ċ2+#{;n{?%Y Vkj50kuW*xii_p ,IX)x.ZQlQ1B_FEi x,k xu{ ?3M{C|3{fm&4wh?_3r/= 7Al*Q2 \TWQm[DFСD,d6 HZLD~G G۪;O׹B=+pK!t6w }6)Mx b%R,L)p#P-cSHgGq iɏ)hJH F-6 |ig[}$CǕ^Dv!r$h PM-㎦H!s}v)|DDY;B@*eZ$TJEX;Έ|_MĆ^{4UK%+2/*g#E9oèWeK\UibN u ۄ #8r!CDdsdD4yZ2 8 ŴOzv11cF\#4BU؃7mp>CٴSŲ#C]_Tp)6 3(ٵ+ȰeIJMx\kTAo/Vjy4U|aY'1N֫ |004Ilyprf1 NSEPOte} ŋX0lnnoڏϡc\{phti$uPeytig#QhBnD}|Фn:ni2po)t)4| '&P6yE-i~u:0O3m#Pڷs[{ҏ> IDP:LYIDi^NYQK.: ꒤ϬU0YlrVe!!+ܞQhVQ/fìd%k3[;89k8MK02P) ߐMWZXә(x;tлݘ,1?I=pִ7jtv|'n9}E;qݚjs)UZRbA'-ՏJP7QǭLdI2 疴VDoB&TN6Σ0(2 <`d(L$.֕-j"WRD;A6+;'Zm@[Vɲ,TB`VfRO:RaR|4 M m LVeF0X=wݛ):uD@{)P;`<[k*0'z^SuR4;혣NSdhx6׊ِ={C6&ͰvXh}j_ >!;y]٥׾,:zk@7EO$ 2#Dz=^m/pWsF-ia~Z.5B )*ܣc'xW@⇠}*~\9+UWjg_6*8ڿa`BG>RhwZvA OH=~;{OMŘ߶cuC bχI4#]6?QO6擁뵲f@*̠W`z^2]i4d1PFz st#vVV~>>;x4><ڠ+u2lUo-h B(5qիUUѨ{WA65y󠡿< H}Q&ҍ*,ǎtp9(Ф іNӟ}TLHO<- v]2t5Tj>h$@w߰=q>i3#2xԩ@.S4L$}E)# Z V6?C? 4g֖Y~RE}5ac:1Q_DL2#d^U]Ъ89COO#,xHZyM jhچu>0&nq*ՒPoR\]6N7Tr֞,QaABl܁I,d<>e 4"[ut;,yQo>d\wɞٳbK19+[d:Efبz17Loo fԦۘ4$:bYY3Q3!qy|1cDoO`scݸAT.UDL0gXTf‰mI y̖dmxZ3%&{PV;lb1:iǦZdsN[6՚(!.(7*N3YR}R{}ڼ?S ͆!0>3[ۯL%Mx ._֙JsZq2b&qԻwS.a$'tg5+y9<$;['$RN-%#!hj4U5N=)iw2lG)YшJɄu|:)R8 yfWM/7F(E*GwzeF98|S)@!?m2Oʶe@i9͞~.FsdC@Yޔkkcj7-Y5X&:1Ljk9u4h ># ">c9)eE.b@!AS94DIMAXL` 'P:zC_\TƮۤfqe': g&I"3!N !-{,㴆i 8]N? D%\#Kc6CY^O5ŧS4+R .sL)$əVbYmY n vA'~ҪR"SQQS*ǺT^qWU`pC6il<):c1M!| $OGW 8k6 1EZ` (̪*43cCu]z@ltU  +ՐEX% ./cqW!S}D^`JZP;-? y}ïQ٘/mqi˺PL?haogԓ'Ӥ,Y`u`eHN8l/u]>Y u$#6il=;]G<ɛ`& fs-2t`+A{KTvG眡j݊snpnZN'qp\suさ̺وcP^ itjx>׫鬒+ i| wh8iueEw>Gö BrfA~P. BћA9)DžBJBDjGYvNT2qV YV2eE|ǜ嚏v (AcҍYpc| a4ޭTӛ:AFNY3.KFzi[lx6 ~ \V\N'`iͺ͓sֵdsx$뮻KC&AIО1z}҅?\Gf-ny}#m2!uʻnf/[\Ch@0 h+d't 1|cã~ѻÓקI{oxQH޴Rlt:nvN3Iޟvo]̬7h5 u8d^lZۿW\mNۻo3j}/ivi7DwvكݗtoVb vNvg!1wۦ_7{䫝Qi0-)3ɝ@PmdN)\%Uh$`چqRi=q|-O>׳ߤoJO~ɞ݃syp9PY]S$}w R̘-Ի>&:誅+F9P`7ѯE;ĜE]2!"N ޶Ga@F?59tƊ5r mac&|G^r]V AC8t"$G!6ʨZ<f*D$bk"4ʠ ^=cQ_S墙ܓHdJ""l*w8$`h FbڼrC%dr<sU SqsK8yJ=)y  gmݱRΉ{EQtMb 4(7mXxM:2Jx)֣s^;D ˨ߵR߰Uq|C6]7lpGƭo71 o7x%ʁS0-rߐ4}ϣ>.3 {tjSF׮εZC&i-˞<N{$MԻ 7[ICni5`)ť!%y|mkp1,,$83fO~xt&SKIΚPnmOםmOY`uk?P`nXۀkF<5ِ{E>#+v 2 1^`Bu0"([w۷QN5( >cd`MhQhP#lʢqcCkܛ-&O(!Iؿ&cߚ8!3ZрXT`?`JaIQ!i3pO `3x㖹cR 9avuuQY;;&ZfZs 5\B*_Az T/x 1AZ[tKh'+ _~!ν /^_hy-Pn~MK9AG`&N.0Ps {0]Wksè'z0B{+>-:#=E)iwB'P 1eT~V+.ERaAH6`Gv: #goSɷ h/``kvdk`f@ s AXvVE4,Q",B'?-S"RXE3q)/-Bc}=/z.j\( # ؓs 5di #hX NwVij!GzpLaIܹdjC*0"d$+~QV?₺Vnk1R\zbHv(A0%c S@M]R_[J~a Z`2g2D]cQ-n`Q,!f9 Ny]1Jc(;h_)4LkX Va3Ħe?FQ#+UDG[)x0\7(t&q0FA^;7KHGG_(8bL;>zaԵ %+[#]δs1dc6ÿ3QTo ke@F`ޒ^}L`,#P:Ň1LZkg**xz~y$ٿ⼲0ƃI'C`FQ־l\E*`@t0mM?_+;tȋ)pK+VҺBc<%Dㆈ| Q`HDfa{y ߀?m:hco^1uG &eWn@A: Y&hf~c)a0ݪJH4gӓ*cX+pW$-jWmɥ)TXEkтLtƬ@Oi431_czK~(L?ZI`qe q8X/)y)Ll-,IfFY/톗sJq GQw/\ zNeXް843AʗH]: ʸZqDxYK a" XpQgmFNF.>PL-[pvߪ#]$jßK#QIj:g-R2(BlNXTaLHTycd 4"@stc3(JF}srz(t|^ %Pͥࠏ' W0N0vO'tOc')0Px2=^e|Zq6y>rHN F}z"|"5WK_!"8ƒ7dEN+m8Px0ܥ~I&0&Dan$K1DN΢~.2o9KJ/h;ef(?LPlU5Vz֧]cus݋27+&v0X%mhdeXl5u-궮pɀ6,Dx4TPY ]kmcP}@?1P֍[UH14L!Y!WK1˘O.^;98ڢUsgV1fnqfM0b|g i|e!RBc]Ԣ ;E a_p]i #(|zЫϧzك%΢KКOMgrHͧ5T1f'j:R3wI!0=̫u 1Nw ugĂg`e gF'8^zbjz>&U*='||e'#JjyiqBVƒY(R&ͱPLv]1r3_Ԉw|f# 7mӒ-bSyj )l6m|ٵ9dKY nlG{!Ǒ]Cvd!6hx Nqd6ӄ׬bfy߈rї9"N~sϘY}Zr7֔KUYSz} 75N-X=bt*En6JRjk)4q^c[9کlw_[<ߎ5R[> 9,iUɓSɣ] (m71yQCI ]!QH! РEqo* q* ֐+Dpھ|KFRusW72E[8VI_## Toaf= n{8PA?*ZEpkfxCnC<+rћlK?ޠXP/i6a:| ;ӹxc{Fvc-]{w5Ncg fX_]} AV uuXhfҘW|f\닞_Y*񍋰 *bil`1SK ZhO@Ffl "{덌2vFa˩]D e:${Awl( ? HmɾDkp3NfRVo8qpG7w"Ѭ|Ùlq@@4\tʲA\7^jAb xr rh~aa `K,^CcUݿxn|C⯜Z)P^&,Ǜ4ëZhM 5O쮛ɦ[x,obRFd)_Ο_sJYr$[n 8}TOrCezVs15tbPK>J>zOg aA"81Aq^$|χ8 ri/:ivyA)]/UlZ[c+8Vl D7H/'=$9ǟś,:%?E)|QL'8XC$ں` =9.r0 ѝ枋K-uA q:42?i es?R?⫱G<46.?޾EG۵ZnTٕ WՓDdh 8{Uc'&,dHzҶP!G`7K9} ^>ILAQ_U'?x\{JuS,gܓdqoAT;ѰB9 I{F+с5'{^NӺ C>$2ȓAbT6byn'FD-TKGhu♍i>S|԰xuECbjңY M~hƋS6=~j!^nM/[äD=/QaFeBoFG퓃zy)G Qgy+$avMhT a>`pa\U梢pH46Qf?}fߞef;=yfl/2alg[K?َvl1H?[=t&ͻAE]qɶ S GUZ/~5,qn)F3K'TddB`ٰף!*1 + _:Jeo*ْݸ閰&5ne\܌0q7cnο-e 4(<ój <͂ƌY0q~c6c6l|%cZˣژ?ɛB{"CCg}Ǿƾƾ}_;yLjTʘ~;ӎƏR41T>beQPi;H8h koxD9g}|+CF#ʯN\M97vɛUuR,ck4I< ౝpQgܣODf3^5cڹrV 7\obi p,je,LkHoٮҷjva=MEzJx.nje-B" |7J[D u/~c2Fc (Di-:Wug<^^zEa4O%hIsB=REob4)}1RtRqaq0;b5JkI~+)]*I5i͕#vC.,m>ep\ {ɲ l M'횎6\F^rcwVQ) G6TKR rʖ _k[ɒ0~~قI$$n¸f/{ݽfݚB*BR$lec'.yR {<)323222"2.[~5CףNzg0aϣuSb yb07!7V /r;Y!#{L@\9?entVu aa<k/Sd@]F,cag-,%%|_:"A4pN\IJv,^;ED+:jPvʫGM~L-B KOdz+]x"*Vjiľ_Wx&,u=noTÙ:-gh6؜JG;-t%\jvf0…Xw&?AG m[>o Z|_#JAV,G߀`e6!n{Xg{B$|X* 㣘dB  ,x*α߯..x&$7ب>($D8iMÀ{ꡤ C7O;֪4jC<{@>0CQrOߏ^@I.Gf{o[G?y[pP:mgm8O@ޜi)DmY ?n^J8?m#g]gbjWuzh17!Ż8 <$Sr;Ikkedhr1t6/$#=K|:8eLt8ilr/+U+j&ښ 7 ӓ?ɓ`_ո *5/%0}u,)cS~a鑘 }|ҿjenyS4:$Ql>΋Yă~֯]$Tj1# sb-XC sXh>bj{|n]F* 7<bՋ7_)= `*y9T(whs*C~NdôCՍVN ~uvΔQ8[ގ,Q%mYvp8 X$\ǀmE:؞$C? S,RF?X?秔Z,' dxjgJg3U kgAPȮoGW VW,PE0q]9j}-z\+XU >щ4{O@`5YvEW7ϦbjB'Ijߘ+7 w7x8+$+pfvKnRQҫb>ܘ)\/" /S|;@!(6 ::|_ jo?|v6v~9jb\E?e2Z)h]yo\'Nӄ98>Xʱ$L˄F:aFep(|>*l t ur'H9*6%>y\(UJ=j*d~!ieDO_$uj:0Cb6cx7sp(=ɹѕRgGc؎G 1 4#'9=eۛ?1 3֬kMrQm/֫欬47=DcN~[rM7E_aK?fWKfZfZM҅:XSn.1%ȵ :FcNwJd wA6or)uO'=_Eq@[tuoͫŀ|\(SVI= x 8^[8ej5bH 4%ӧciO~<"~JJY PU&6"USLMXλuF2N)i^ViDz"]z$̍!_b(d{t NsrnߏV7i[Jya0黥'bȭAFhh02r% x(XE-9vQ6:nOCRcO"k *Z@D3ު_S_AU" !TlIEV/$Cz_HWY"3F*)>& \1ʮM"PR: 4|82V1MG;1,Hpсe\kƂES鐵&$.o$|ݘ^]hAc9TNM@ةO7&@f`(5ܬa) &;>e@rus`ӔQ1a'j1Hc<ևC.>Q#n)6o`Wn<92C0'N]P6WT ŁXp7N#bmnSۜߌ?x?KGp5ix,uNC/90zw>I3ֱSڟ U\21aQ/w&L tWАڋG6$.LDCY:UYOBZ, XԤ%S}Z,s@t?Nbs@ .tCe3NcF2{ ;7 e6[' p #H=!SQ=a㮵vk1[̡sj:;4^Z4שM8稚a)c@-u Y4Lv_KTίNu{z6==g; ߛ083hI" /Df# m&F{6,4\Ó1@Hr[5Fp̺f9jV8},g88:ȪK_UU)zԎyo@b9dGO [/(FgդH;{7OjiuWe,|)Aˡ1q!mMFJ:'UJHMIFDiˬHtdu46{bVFRj[ dII5bfmL,ӗ}'mk;s.~rɆ <{GxU5K_vz)HVVo"J?t3<,&v)R2 B.K _McEn^Y9cNΌgsƈ7@-KViOS:)h[EH'`0x%1HOBd(0:>it!T6Ch 0S?yXpR\ʏ{C#U6PxHk#qq$QO\biÆJ*)Ih=feʱ&܁Kó211O0ǐykTQ 5*'fYNKp`ϊsģuP2&1 e_䆹[_ eM+҅R{ـ!?Nĥ[ŝ4GtzЩa& }'ݔ"cڲ.A28D=߈b{ }fsAOrSV\HU@ EWy{=1f+I'KT.hJYUfN?E8->;{{k7u@ji-,)U$R^r'vij o*ON&rr[ŨLמY|S]niיPs'ͧ6BR_'{0M *^'5h`d_)3I_B6JUMjhqV-I2^tom<-zpJE)J3L#8Nkq@2*ê="ֱ 8juNyptL8o r~^ơQž3Lx}(.D>zj>niT^`pWt7ڝ:'+|0L1i#"n2YJ^.`-1kczB9揋(OYy$~!bo|lu80e^uM%$a.#X*h^ PY9*Z!̏ԗ: ]ƣAVkՓu+Wt.+5Kw%sJm'3ީktBgr?S(CuQcPlrAm:%3),SN]h}^^JZcZ #3E`[%k<( ]xKGMv @f'χ靑ҕF.V#ԙJA9l7pW%0]*6<, 53ξWRMU;=W Z| P bKf(A* gsR%lT %7iQ T}Q^8; \M֏~UejЕV=%x .̧E%ҚEv8 EiXiU+n~&͟NFuë*]z B[-bfG 4Ul(VVNكQՊ`HA Fz WgCVND`v2d. ahfgsyJ6I!Cv/OLF뷿=\ћ6zξUt l {4I)1ԡ^D 'dQ-[j۞J=$kr~kIAg=hok2ޚԚzrf-sFpb6bq,4~ Lʕ2@gR_}F׊~*Uy~V`$%#MC3aACM{r-C̱ށ$Yq*DuAtOIͱp=SFr-(YGI'o-o;HJh4vvfB #؊VVU7ݣlRz<=i 1MIzɢ*މ0T`((7`X]JqCH|YxAy5,dyOz+5Fޚ0k ^ČUԟlGJY3q8A ꭊb^ D̬je<' }u} ֧|*P.;-y0nOd1nWG\?7'Λ([J z=Hpz( -h"C, $lm=[tْQ6'S S]!y9tڰK}!W,wp~>;$'!Pi!y~FblO]zJdI}qM?ȋltկޢ0;Y؋4Oⱐ̜{ws_}s%ZZignUe2D<.j}wFBw@2j@ƆRP|Dp5 \saeHIk!+2hh!=ZӷA^]=Ho^<]#< D@~Yw(]#Cĩ<]tYkDƽY_-"8?;Lޓ|ถ@[qY0z/$tc-0 I<D   $m g0^Zw@D0C4E}{{l|ZxF8&YfdƴM";IV`s/ؘLzu2I.Fƿt{H)BN1qmru2gN#tH!ajX `zuyz:85I; Rd ;5+>ɖ𢥧±,bn_HV0~[X/&u *2m]Ϟş@HH)>˜45sNZ?+=䏟|N#a(nq2X%=uG8giC?]*=xgaQ1 9{?;iHݖT ^͌b'EKRdAa$QD͝栢O68e ݄ˌ| }'PX7菔6_563ld'.s'l$Լ4P_<}w\|:VvPy6|<cTh)7$#?̓k` QWLx3g2Fۭ5@+u7Z}޽mx :~5gI ||! V{<Զ.?;ǒUk wKZ6H%i5 iWhR euV#ɋ Q' .&$-pjx.?rTfdȪd Q:b1ũ]o\ʳgHv@[ G(*]~DإrC~Q_}&`Z)F*)dr ;ܯ&2.O'r<$t$zXj@rmm/zUzx*(u0l;Ok7K#B=BE=Sk=cEUh1P*0$ kU(h9kUr¬$g5@p]XH{!Rdl'ye4],/"Qsa| !ްw&j,nc|`v:D}je.y ?R{ h$ϻud7e`y8*4Y7szYyܟݧ4`%`HP?N?SMV$k2hDpM s}ceٗ%@HgMp{a^ )_Ʒj2dh^i+yzPƑr?$|u݅S^NS>B^JJl),jѡlu_l˧ho΢&̳u=_cJX9ʒ U8qf5$՛2_AΕJ ʺ1 :0`=+уn#c?yl +Grtm7DuHtÒ1zbԨGsW5_4TMS~1zK`d+M_SmHBV`*XE&v'эowk7]絛hwQNWK( O+j(泍.KE9$]*YvPw皔M%jӧO6ȧ.Ѫ[voavsл0>M3j>OҊ@G!TlonL(1=e21k|:ǿooanF|{|?\J9[C`UlBj#ۈQkAvECЇT G"EU ?5c6tjyJ%q_گ D5N5&x嚧TDIsJA0…tFw“LK1G7Ba1A1eF]ίZ:*]JG.Jc$@/[D߁9}0xie`sYˀN@@3Z- z?;[n>lSޙL&}e0fе}ܫ5K<-sRᔅ`m=Q%{sV}>4C4 X`p\gq\fii5ߏ}Pg*Wfh󩢑#M= {!]Ŋ5JŘ֩N@ZV(BFngITx :fUoaE22eR4> T& |O*Fe("ZI5%,g ;CKC%CW@AsnhU$P 4k У@=uD@)81+~cFhF ![٫R!2)OoP}0K`Cģ cJ*Gnf0u'Fg5櫀VsrPR]T8 l!yUb*'U&W (6XJ?AWO!UP4Xwˈ7DiZKh Qo2X5p gXrnNMɦ1ٴ"g<(o[< J$,ROӓjTo凲T1FȸʗicQ lcK^(~at-{cx0ӥgT X;C0ɖ7HAT[)75kGG!ct"U0\r;ic>d<ˎ9!O:+ĔR@Mb p Vt,|/}(T\@P03nFO-U=]ZβYOxwE{ Nf 3f~yD#[2?]vFֹE72*?}_G ^hob2$weJlXUlWLi mB ^[̭UG(h#ޞ!-3ϛzlU@E_!S7,8(G5, h}=1d"Z0B|v=&}{nnن)6@-d~89v|.7TRh ,.(Q73P0c~l6noR+R2_` dH&M&cl7vOOѺ+cu{צt'V3IoȦ`r֫1:yRW, s$ɣ#8b/tZ۳ʼH%d ĸ5h5 xu{EV.K9PĀ|ceWA#DUc ;M&1d?SK%Վ@T41%=،~鷜h!ȉ e/]=[Vluo zERz.:v ͓.1vg#ۘE G1GBIlC񮹱w_"|@58E% ( &2yv~<;j²Ckp_͍̓QAQuxsydwsg{{w6~Xٟ} , %Gj2O퍧'[GGG[/=}rV{{gcg{v總Ձ)oo7tv^>}ΓOڛ[|3;:z\L W㑟[L/pI4k"v&(.nC/:y )ql:*7m4~*Is\R$dhT1c%,r\Q\^ޕsi`~Y| bho'bkC<hC\H<OF_\mB|~ђ?VtA<O;b{KDOxI~ #vb}qD\tLZ`GZ-TlM( ['.AdoӬ 47 q` ?W Bԥx^| BЈMMq5ṕxDD3'vdj?B%-ܮ`O~޹Deٜk5;@=lΛqRrɤbƋBltgc8ioG*K#z:g.˛,pcx1da! D@@cS{+&2q%3}pQzuHGOWݫAw#Fݍ.qw{Ѝ K$06#,o7 WS̵ fTvyw :ѽK<ռx*9♶vt3OazsNa ~I9QFM eSdo+`a' ȢPhn!Uszոevฉ_~tftRd-0arBь.clnɿY(y J⯏襪o=NI? y~DjUcf^5S0, ;/kt~dΗE ,aMm^]/IsfAn51rxVFB !mtm i&Ŕ|˗:@br1?F֓BO+-TUœ\3 ۻS`*6Eo PQ:gr;g2I*i}+) %@MyaLbFK2Uќ3 +m2~X= '+V~jѠ2(CBTodRa $:hJ4EH7/ ~⿌s]n(eptu4 }yqMhk{kkӧ牲f~ 5Nt+~zD( ߁08Кdr2(o{dqv~p=?/ KD(**(6Flۡ]S6|&0]">YV6 A vEw L[˭ݗ[[G/^p|tA`weԲ6(l>b2RU9]:Qm<kHd 4d<A3ߣ>;&Xlj[+ S :]T Hmh<̧;?+2`"d#Lf5B?^5pP$ wEt1=~o6BZ̒dv4n>~ ݲ jX'~T9\-n_ί`G|fM}OsEԒ~@vI2CHHVDlKC^j271h(q${w!p#>VU v6;O6$ \k2oG^4YK~04w&t8Si!.J?+pEU2t5W'rky.,km6]L>Qn"]-X{2. ִZG}Ϊ(iL[U kDP>kŃ|iyThA#ˋDrmxȟet_Ȯ?r_5]UR]7̙m(ZEP..֣,;NI`zڰAκV 19F(bGXtˮqE]wFQTy_g)sc)hz4qf`"7"glc |s~s[2pL3w\  '/&g3chFqŬf"utʁXyz?S aڰGxn N+8keg~dAGUrIDll2Y2B1ɼ ž<к}`Yi0F9F5; E]r"/ԋ+i/AWG{#7]>0*DMqDJ;牤Ugds.5Kw~Cl&|uE-y lJ\pTn (I (amP+| tzxvn_(o'Uu}=u>i"B/)dG U(dHθAԵ7U"ToA*g0JMe((CrDYnq?WV9y݇X҄gq"ODǸƳop7&5?`7%^Tho85FYͲ9q E|dmf*i /ASRWoo*37c| JA0KJVd쑧ɳ5gMe_^[4hlIөL%IEZ_HK$VndvpE5m= DhLV~IcrFSl:#7Lj*4o5B=;4syu+ӝIi@)ctۏ>Z Nwc(O: 5,za*\>?!ElEV斏-8230 ݑA@"񙂂nuZҺnn TǣZ#0+"}tCf7:|Nr 肁,/dGJQy~ܹgx=Q5k>%iRdSu{ȩY,ϭ剳w}s pG q1٧pd`L9&hO7IPٿwI΃IHY@4Ձv2;Dc8GJLBjPKx,cКaEtx(X"ZU jolB K޼fJ.tL~•=9Y"jF4 Sue ;]JLEӀhnJ ~)5Q?1q21O,/[+qNb=Ӵ{22\2.p[J a}y@Kx> tv9^2CYTdEm+b(IU#Ya n- cXߋesI,`@4!ajx0(! qWuZD:`_@H!@{hxI"-Lk oVZ7L r萢(wQyNHy Gj9 | `BϹE2SIr$5z/'v^cWSmŎ%ܚ*AሷHm3.n-}H@Gc(PJ'֙m49]o(- QË?,> j6 FC,F+z+՞@sv<->';*e&LܣƢ$x*abN䟴ՕUp16ka#ӓ9]~zyP:dN`{Q)&1c2S7p{J6ewc?q](o\54Bp?- 9]xHy&IWžټDî= ({ocDsHYgX{ s[e/Y;LO5 -V9ov<ˆv";Yo;Ycixˤq3!:^q"dp]uU*M.HwJ%˔BդjjϦg)5w~nݷv褰@bFI 0֭9mc+k#*O#|goO>Ŏ(u6n ԮueAAcv`klW0L9(b[qܲ^tiKm34_g 49X[0@nxstNKfx/: LLhWt='a*B]9\Hű',@ujoWxtz('~JσӦ HyagdwjE7ǎV ixP kL]_\RS3\T^J[3u"8UZ8GamXt!kݗ]ddkz.n9$yr:[iv9xryHph _~a߳+/ v:<_Cٙ`Ĝ݀ŌkysH968iRLP×II>lde2a8<[tHRwӔlJ肰bdh1FWvj 2һ枴`S2Im!ܝL~t8G]0;_un\ʄL(7ެր#iðGJ3D-o 8k0x%;pSJx-FLJ)c2%SaF#&9Z+ wrUTB}&Imo ?1qSzuq\LjYݘ;0FaSl~Y]?۷y~קd_?5'C¯uLD"M'3eB]V ϐbYm>}^ˏszaR7^34'g?JoGf7݌jKc6b,T#u4x5)a&YC֝vs34| +\V{u@" /γFi:͈_v>.|/ƠP"2`&+i8$#Ia(F_ݑa˱2DJ9xi gԵ<)φi(z`;WSvbpݺQ N-דC1'4sVn~'pX3EОSem Q3wzAp5+N pqd-lxpZ4е=SLtZN%o9Cqy#sWoi_}MV6+>d9y)xƪ$GyynQX"wƋv36OӅ36X|Xy"p l'o޽>~s|zq|wPbm )ʒ^.dقCf{,Bpl18鞳7[ N^,ʢfELPbgbB)͊k]!8i+g]8-g6MKnyAn8>fbt ggqY-\u͊vָnifRJ:ȚvɕNR˄?u#cpB܍4NfzO< zj&Cn  SgdJa$s=7ј 3Y9-~Ȥ@m ,}.42RTyJxeW!b<{X=t_ ;)_ѯnW50J$rw+&~蔿)W.uT?u fC mO&a>%.ӯEڟD2xcbZV^&_IWN>=B4uW6RӶ A]GMkʪWU!1]WwfDk6X"ǛT cám ᳵrtqv%W^_7]oeO/i ;daq3fɰ+zc2 'ȥ.h*vQUPfSxU`v }ȯp0U#n߷2͙q)?#ST_CR1Fo?A>Q{XPGt-6q=jT7.d2iC4v8ܬXK%KgXHK ('u`yYsZעKcU {YJXRψ32cۛqNV/̥3>mMSpemY}UT踗/mO[Q@ϊf |SאO3a6)9_z|v{OO/zoOtf9^TRZX'M'[rP[.J:K:>;C!G.qt||zt|zxr|T}mNn7}\f5]'(t#4cqSrJ{ͯ qV_]F?RI?C*>3`0,KJb)C%0ػÿ|g6[`9u ު3`-)GXhN :`B@`7*'5YSJ Nds2()#QL19c&" n1;"a?b_rB(=U}/|$Sgȏ Psi:bgm8b2F2?|ɩkVgp0:%'H̱K6|Ayg1Ophb(iF+ャ72 Vo>|Yfd$A{۴?$uU)R;M$:_'&c&7߰\NY_OJ%KI|r} nILJ~..DPN MᒊSh _9Tgq=G0ӥG}L[~Ol\S(<_)u1=H•i .!ы87&Cҹ ]Z;9Ҳ£nĻ\`] vJ^RI|QB5ZH34yh !5G5$Q$yH,ңF#>C 3f\WM*FBTOb;*ѧsq=?N.j<8hƤPJ݊٥_zct6(cPsu!ٕo] $):i+= ƯraQ⫲,~՝UmZGw {Ή"U d TŎ-с\4c0=dHM OcZAZH+DGY:"o{EOLnPttԢYmik1J'JfzjPlsz4z$I7ESMIY&u C8\aJ["h;+hH-J`-D1{4 xuZ2:}8J-C<}LtoȾ76X ?@`lMdR,/Cm ŝjK׹A4oE|߁P־-fVzаAOYһh/% k0RCJqK_T*y\R$h(#UM+s u'"IZ[G#BuB6& a*2򏊸?0UFVN/m>^1_G 4d3HJJ%lC+S/J.Up:|G4,Kq7=+=}y^ C4 ^%VaYXĿrpR#-lU63l )d(5^9kƎZ_[muV:[p5YN- ,B2vz?Tm{N߯(Y% db-񹡅 e.#@=iwaQ'[ߦ}¡ɄB*ZcnHc5uuPE 3dliY r[G6J8{mN_S6Q-T| ~@*)}i2c58N{ިtvlvvv:ol})B`.7g)BOgq*gq :IGI7ix7~]Ĺ79G >vȋo$D Νۃ (r?n_׶@qP 4w=EFd :ߌugٌQU"AKiK=YfH$EXxj1,m`je5zPNb+NO4VlRK z2ɭ՗(X +Z[j<&`՚=[7Zd î3%vj >V|Dk͘&fK(od4VBr?]7Hm%ł$jEz{94 q}hH{k C*QhJ?.!mSh+V3';9&svq *7C N!Jw 8FȚǒ!-]B%n|!o =5/he/6>V|6/:y_l}_򋯆Wr~|ftjS3*Q,-4F&mLqY?#]I Z5)6@O=/zDj|Ja4"#t>gx\o}5 Ukpi`x:TRa0~`TN00K⏪ݢE }={\z\dLEڟ&I,d6}u%JN::bH=$uD2;1m8 ˘C;o䯬؄#>S6/#T;Ԑ/h\CΦ3PۦNr@Jl!L0RNZa\v:=5c?eTy@oYXqEL a]ڒ0O kWR5UMA,Nu&pH=9J̪Sp"k@E`vָ +LH"(;MTAq4 |\ϧ6cX2){ud!e?+r쇠(){lS/~ Xw0a=y?rxOAM(F~n~ $cL!|1p?8Ln6&]a[Gߚ$Q{tKOaܕ)rg~| S,($b|G$`D"B˺Ō>Tgګ:p-4u)P5=yn%[3-X*y]:ߕ>5]3m`.l{Mls ߲ )h?ɊeUU^ב _q:`Ҽ77Fs?F{yRԃvzbn9=;X p̞>`{&0q}-uݩWUsk[X8Mg_jMZ5s|F7W+JQWm;]^=I'@)XOEvQOv$"]Nd| ;TGͻ#`{XʬPm!Ëh>.&Z$n \]dЖ^Vx+2V}5q)e/SW_3K7n/YuվjKEE'Wy&w^h^ۏNF)WrĈ7zØ9>$FF,/ekK |Ν$Trr=NzLå:ZMX"e[;fY %/lX[4sU{FW3k{2xhLa '>ۯ K9`'LHFpN/ELjԹpP~%n@ б[]@}+M~IAuP>+[a/ L^f7_}_`qb>\W~uSX\V(='{o\++b0Ze_>';3DÏ.rL)ZQ &~4rbOŭOT̨}]Xuْjd87K/gձ th]bWQzc]Ԯp;]ʒ)M@X; izeaw)hiz.[TZFX&4˅ҡk)#3Yzdyp:s+?V ~]\^~\ZbZ~.'j}mqAվ%QѭZ_¨a*Rm3So)o_ʔ*5kd"|`OldW6\~6F,3z灣wS)IJcW=xs}-'E2gO-10 vneLwؘͲxwQk,5i`X*\_vƶK%jXǶ:ݶj{mӾ*#5~zh>-¡})_CG:TU_;T~{eou)rE` \O'KIpwzЛ8.hK]QL?+Q_^}2!;E@Gŀ"oh b>zOM(w1p juɥ|T驜edd?KO/x S.B3)$^| G/Y#[uKi_ꢅPbU/5i_vs<9 +/C"W?}frzeǸQL2Rvge bgC7(^)!!aӽ9wo_lMDzm<`:ei6ǩ]b&vbxzq&JFLw^qRֶ*R}!GT35kW.b=kI){t >'r, VCb>\T9.<_kB DŽȯdS#q{ g.W\w,}9*iz]_֮GU6J+QRNIH!}!}!F:u}󒃪D̃VՃUuˮU/2g{pT%6ۗ1 n$ߗ+xpǴ%#8nڗ4̜t:K˝F_H8"M,KЗZi_|D,J}}e&{ׄnCGvUe /[;䴌m`s4)GY֢z-9g w_rDX /9fF-`1FnZnG)Z>AyvԖ;j?{"?1hPP+yيCdl#E&(lY~_ªj4ofm{DT4cū+\M*Kc,/e Y\ż~qZo4_c3j~;N'_=2m_\c<ųT~X d w+S: JTƊ% ը)Ri5+>UR#Իɑ0U_Djiwe"'^me8tW X IGRDBUIy,`x M24zHW=sEސ*C9'Q~Sx>Q֣+2gԾI^\ JǨ -%N'|u}sʑJq|pTb88pt]odJ.hٖ`8qf\S0^V© aƘ)^IĈDSj0Iȷazĵm)&+h_?) nI Ԭ qeE!LshsrLAD̄xKl'@"ub|Dv8CQq%~WT A8Tfa{$xP-ӓSS{Zvd+WҸ p(-Y%AnЧr*e:Ć }=7C~E}; & 8"ʷ_CK|8R# uY0bpP 8URa-ci(+8ķvkU`K_MVs?붸9.?ϣy G7 o>c dB;w.pi6# _b8{y۶|Mi!Lp)hh_vz7Mht7{~)IySOg;x84K}FM0Fog{{ BbLtʩ>sd~ًGļT-Z; ǺG9Kрv&ofXYr6g-/s$G :XBX2\`8 CE Zl:Ra ߂@ no tw},гI])]5VEI5 GpyЇg q >'0`1 8rGo$˅nd򫘙Zx6 K@Te5Vq 'x'B`Ar̢XM(,)_nJ!#.fn"dr88'F2V!VeY;l5v>}ro1j҇gbլ4eˆ܈S#Q6.oĩd6@jX}-h_\qm 4cq/qh`/|cYjf2d:ܦi)U6MHƵݐ,^xx*r68h\$:a:4d9|c6b f2;'+ ڔ649ıG#cCJ%,ʕU쥚L ǓwdrIZX?+ ˙ʲnXfFI^_I2R~"kGޘjI\zŸrM#4ӫX|q|p~! jhcce$s+ " 58J&&2@NSܖvtS̙Xy`]F|x^F5Ts)`t?p|_te;9hOt6}xx0ݻo^gbzne@/9go__[p2tHPR.hA\Xp rAUt HE=$:'S%rTю=1bP`V;_X X|ewlnU#^֒"x; d֟#JZ0V+܋χ#7zOT>&w>ͥAl :8v@Pbvwme:w.ĂylGw6W#.Ϧ "ՓRhx:0ٹ{3AIg,53GQ~|;>;x~6Ι\Æ`2^4 9^<{{v/aAst|G"Tx|O d_dn@QCN3i\xб+ 8LCi PJhXh?Cr9hfw@99cY?k"TMd1d zyj_>J5tV\ 4ٴ7^x Zzq֤͍PbPPfS~VغUrAYvU Ru4%Vh8H(F.3R0]3"ؓ|Bud~.ق⡵ Ec'U*F6dY892qV"PV0`3po ln2d"2 翆^(tTg}n(Ny5qUFZd^iEW$-y&q!n ] ?apZDN;T[<} BI\(ql "jLJG.b(oYz`dW}^0S2U9Jwi;K"1.`Gz_a#M|Vg7DhBLF~1DjB$4RS,Ҩ3idEVJ= :˪x{nj=~ 4{zqFJ*t -@d*(Є mbSaqgy¥G"@%Ūޥ-!α!ssX7,t01rr^ьs PB|PAw !_ut$Oؿ4qկP/5?3 ۸hOIX=*o3nE~̐Tl *@DEnA2}*v;Yh7Mff%auv䃌@4`p|0<hFʔ0 _a nr1h2Ow9MI @:9 Kɀtɟll NQ d>O>͡v3|*3U 7-kS8He`PZIŨ!oPs+ 0/B`y)>gbtD-(2bE[4%b hQp[Řr0|j>̖7ae԰q1p ?Dwʹrv`, ^bphUvpX8:_Jn.Eţc]gHGV%ehܴN*;(T* N*0]搛da Suz3ΰwΣrV ɴ,UEq^wUJNvtzT0Ciֽr&]WY+9UVNܠZ_o6\9E5w#aaVkSMtL[n81߀ BfQ4LZѱ܄s+%$lZM< ;76U{SE)z)U/R+R7)lx䦝 VWb%V-3+\'R-NSs7JgX>Rà ryf<[MHYRr}}|mm\"lhaCA(?r vdyKʸdV>45Ly22!z" ÔiMP95;\6οrl5\oHݴapF9MA5oVhfb*tsf?H´8LnG!]6Aet3 Ll:ۙ84`Wa6B@7d_}eguC˿_{if*ow?˶zVQMЊן<;s;+a'\JȻ2s'f6s9wc7 :bsF\Vˉ2ׇH q9dhxD2>BP#V ,+ӾjLt)+65?Ve紧7LOs&zW:oJ^rn*VZm.,S`ڧnmε[B;G7JcB[ ֠y]6ur_r߯%i)~z:Pk;̔ܰKժ0S&/id1LnjMWVEbiC/"cqXv2Dd*d1zm& )V#";ʔSCR:W]`~H/$^z[m]tcs<+߸T]WûCm.Ӗk;>->bW ³v?w][C_s̳w4Z`Z5ܩv5L654)]##C@0u0>^O閟?rLKq5U-2rr4eȔ'8L3ϹpZ{^AwlLnwrC3;TLXQ+OqbA vt7:Zp]L.dlN[ u~s%y>>xNnp'2 qJ;t%/CƀTƳr;{.k <6-y3:u臱,²ڲ]i7-[rJ-i[MƗDocv:JCV;-˼&Yş,Cލy|U*z$4<ʼn,b@es2u'C/|K> s\˟>JZvɤER<)Qj%&%φ) _۲~lve :Xn%7VLwecX4DŽ OdLrO>e^`?=(9Əg_0pknͲ4.ӟm+~ZTLAAm58]g<ԃ{ZTO>NૺZ𕱼$ ۇ$_+ ;Zjqx/z_j:vS.|jw*m&$'L0#C6耕GjnTS5Xim/͖/Nzvs)TӝG:K2BnKUUmj>f`{vIDr6'"}9|^PM7_*f&.T`ƱRhW s3'*?WijI at=KZbd0kwZ᥷_:FvSv""Yyu0Ts (B]&}BOAy= ]Z0 2 prbNߙ^0£I%aati$%)Ey2PELٟq S*)KŸ֦Qu(B'qfG>`ӲQ?o"12'++{0igѱX[]#1WQ1'4ޓUUCL jR)']t藩(3A@ Lʒ,U.vu ђ÷ E!m 68,2 ƶQ!MgGM9B<=r/2 PU"?(*2FYCeTFkĘ#Ƕ{t=u碣>uvVv`Gܶn_pw6͇!j%=>-fS]YbGfW234 pU iºjpXd]rxjPbC1!0?rG_qV[.LJ7]yL;/(=VX`:>ӑG] u7ˍPUBO 蓶”zߎA`#6{5Zs.G7ݕ Y& v|(Bz?{aS/*".w&3DWKe׌٢j>[ _X[i f paq޸6aOw 4X z<c{ְ Feqm0A_Kl͇01ekO\і^a mNAt6J;]o'̨ ⥕-;I/+O.[C7[n'< ۆ&2U.B/dh<܌?hV42w?~߷ uPI5uv5z4~/M"8}5R`-tzljϳO83`duUN7b]{M=$R4/#l_|]<dtGgq4Jcq4q4&ei)6ʈh2ԞaQ%DŽP[ʟb&u1{]MҿT!c\~2@AO.fSA%ekʝs4yGِ,qB/TlǓ wlh ', h#cߏL;|(EG ?M4@?4?z" 0]N;9=?>G_aǗ4~y~<+|}/d &BjoX0~Nߞ9xͿ4Mo+ mC-yӬoyu+5ruΰt7RVف%d7Oudަ@_"`BPrBVtyXt­.R;bgOdd=u]+674TʅeI$8Myl&wxQɋ;zZ|]f51XG:-18tȡ[2ɩsO[p_z{ fYxeeޏXQsQ5>bR=^lk!R55NF>s^_V~#K%IGd,WԐyFo%>.^ֿ .97"Ό6ON/puCPj_ |5E$<,86?]S1S_ `ctRAGe=II]ArJ@Y\8֎nV.1P' (Յ"P7-^Nu&И:a yY@ks黗=:5FQ=oG{Dñϔ@C\_DMyHuU O8 b2o^C9SȣsdG Pu?}1RS*kLI!ىvEԷl][&+?*(_xb\<[ei{(c}'g;BnpohO?a~5Ei^5Al:f@&L2˨8ŔXGt:pQ9WA- ե7_nZC71ݞNjC' V/9í曣m϶FBTwh,JC??>>r͖U_pg\%pO#пI.H]>u`̥dT'B(K Y FIqPƦl&7 9kebbк`X$=JULyGT͞LdSS-if2PtǑaUbI'xsPPkbe[e ?=gD&@Atmc!#)D[tml,dp .Y"Af^܂Y{kȮ`厖:?[Fƈ,e+.ap`UPVi`g`#{^xX 6RtUBr g|Mj/fWŰ4 [{XڰvN_fޙpao<baqpof Nao<70 fald#y5J\$@7]{ʇN)ذ̛Q.8*^^WJxz O\Տ.S|z__,NgwI .ZOMZ[; KF?nw[oV%a4B)2wTW_58Tׂ+r(⁁U99%,=篔y;7hOc}|ؼmyb4ݧ?Aى"WoCɁt˃O`Kgo< s1lIBo _GxlET# 61…h!eH' HRdB^ v.nQmNK=σ|y Yܖ+pCk|mm+ƩKjX_Xx$Tj}[kJX{xߣr{CX4L9+ޛ QYz%VcMa,Mb0ۛy,=f0Y'\g{Ͳ)7qu<лp{mKs9,3Lݛ7,?LݛRrexRø|`Vz,W[-5+xۛr\8K4q0^&p,JɄKaAP Q,Ore͂Sd"MdmUAiFh?n@\?&cZwB=y-5L^VVeJ ɔ~[v5P^ylոÄV| 80Lqa<) RZ,=̒fi^!f&#ƿ}~)w6Q,;3^p|N@QYVƑ,8+ ê[`=eW*o冱Sv5e)`KKK,H51KdkIvlo/>7?ﱇѸ']45FL 9F[rr*\θ%*Di+)se'C'Oo_}h;QDM<2AI Ζw?Z?VYb6VϮ"YLY6$3χT L0mMڙyAl'S,\y0v w;0p- cIho)ba옊Fn|k0E@Drf{K:;-qF]ٔx$wľ-S_8BqppP^wv(7+Mr}c=2.Ac=c,9L9kIYK Ek}j2̱hf0SwrY8rYi. -fGmS\I0>[D"mP-bQQ^H2YNٵx!>s,hkۗ2|Zr\1˱= 0 j *3\V-S +;vfHX<72YU]qR;GWvQ%F_"JkT-wKaZ(K>X~-_Kp{yB ue(H .d*vNr*3\^aњ^T(z*?\^]NiEbK wXH`l`Z Xk*ePkXRJҲA0i9ζl2Z &˯%_k Bvo\g(ߨ ,`=˭܍Sx8tHn+ߢrG 7T 7ΒT@9T@9TM+MuߴQv=C˝ v ]߿?mz<2p?߬:=^Y<]'Gt'x*Fmdep[}+g /ѐ#,7DpnR PU0/vJD;|rƢ6ϯouqi4c2>BaIEN~ݍHәx|9_{7&U~NJ1mhUkF#_imm]HFRU;VcU9T\@̌گTT>MM*38aUՈE˄%n=m({~o/F6jrBr>́:0apzI0Q~Q8?ľQjO"XxJXsѿ_@ H'x$e<h <ANډi4&lfC\݋t>A?x5~?Gq&mxoA|!-zL , _dg3`;4qmDA~M4s伭w5coH@R(=Oѵۓp_heo3-cN}Ulf%iK} &o2Se2T9l!O"L "vg=|ooVNӝpkTk-1\oZh VM\}pt.#oǣS@nGR :ێ@10Lv7Yѽ@[]=d&Xmr{~Dd?=}IL%˝d8GAZ قkwgb䧗`08cceJjiF)tjwaT (c_#9O-^w@$+LsP|N^) =԰kaAryoo}q1:dUM,1$a'>yGPO5`mI;@E鹅 li` 'i^4$FJW{96xY9iইb=W~!*ԕ#hLVL>gD-D;6i2AG7+ t៓ ^6IJ=Fx>a_G{P8zK᫃ӟ1ϼTϗq3'!r,X0X?Ʋ+9?Çβ W$"Q Xf%=xE%tǣqE|&)Qm'4R{n}?FZX?,^5a J&Jl@XM z/LRj5&P]t r"qR5&/\L.}|z, ?>A]^Eמ˃N(t:=^@b̜YZxu*J m^/pYhXtIq09/)x =lgɕ?ܛ>]nõ/!qgŻ*V'Df;yAP/d6ӆg1iQ6:ȟh+%+zӤ v6+?AqL+BOgY4d9쫒j' /p V(ťg P(.#txr'70 @0cq;2)ʻ1"m9@9D\|8f?*&Dd& zDH,C ǣ~D5P pCg՛Ê㗉QBKONQ-KV V?rj C~){Qs]޾[ $$a#],uKAifIC<ӗ j`,>67lPag[Ai2EwQ2R 3 O?Uem&*9ɈNyfS0@/J{N |UyeNdr,. ^wL[ ޽!@f;?-И :}\=9^@VKUz81d{]hآKpJM'puG4͔Z[Zv8L=|6rڟo7%͍uhWJwFog/&~*c r'v}oee @<=yRT> *LDtƹ}Dy\VT!-%v 1U+sF03*wh?OajGrfW`VM~"4aZt@ \yyAOk%K-Z@n1 6E &,VM@M#R|3ӘlY@ _3y-jwrh Ѱ@b-Y=/F95kk}>|)!(p9;ʯtOoxpyϾu &,wmVl^vrzXrI,աx;! d`@xD7!+>=.Fb2u J1'Dh4̸fζ nnfFv>dOi2&Ҁe熠WzN9Ob_lh>&PӤ] ;N g#XȔӘ.nmJg\P pUC#-[khRB&Ji0CU2 I*&gMA]gE&ьH Ԥ%qXH7E QV%:?ۭ>޷K;ĉc @f7 S1B;K2B0SCP{8U4WइO(IA(MtCgûY* ߥm kn󓷧f]6]MsfaC 'mktK"%؃:5> ]0qqlpL tK95ڷ\ 5RWepSqGqVDIFv8hCDQk[j4@ٹ. mp_}ȗHk+PKSC; D>DC VwZCW j8D ~/Uc}DY>tB5B]-ދJ3l7 Pt[#{;FuBNP3hytU@"RF&$1|`QVY$8iFFY1/(x>]WihD¾c"Ng@:_&Lfs] Ju?+0Bk@JMFgi}rgtU|>R_1I :0ē84y_NGD/ժXl *].ۘ{|u{lkrFcN ?=NYڨYpǰ`"{|`3J]>wRѻ Q H Nu<"q Uj r8{f@@jo_@ |O}P-$'f<d?ֻ]#zVHS,=HuRķ,Odגt} yjFk`+$9hRIu4Rg_mFK寲v}r 8d 44&女*6NS|:KW%Mp"ϝv,MgIh*)hJF$7xg.pf1+  4)P8jE%W٨!؋e1`݁Xd͏q{C&mx uC¥ϊ-S%Ef& #ZQTԛp_\- $Vm14Upb{%* ӏxۀ`}o3=>SRƠg)>U@yh~6 s%,I|Gh)5`OImT9m9E2}sdS1[Kϡ`^:JsH2jH^h[AP6HqZ W =R=״_s .mao+\{vܕyS?Q@tpL3h|o6AP:VP͋ D|xeV{iVv=zpl8'#M֣kfj\ʫS8wc 9^*ugA[|2gOY,'轱9gD?$}‹o$(V%`2l 7~L%d)mTm*LyďQwߨ CHrkԖo-`,nn887roTP:Ies!{*j\(MnCϧw y,/s&Դ_GuH,ڽ9ccWT_ۉI@ B=6"۟:c fG/Ȁ>ݧ} 64<ڎpYJBvZZf<bg*g}HD&&tr|t(%Ys _wb=We}9[/:W(MA_wd\?7z!IJS X)k?܁\'ռa'Q`=}N(ǟd *}{r/o^9OjEzk2>txoM|m%x񄭳;sM)c27`~Ӳ $]FdCd:KpȌ7ȔcR#l33us1Uv8=Fbkn@zxÎ&ȋg)(WgrPWJ]2ǖSuWKq4(9riwWeQ$A<"}NO<~U=|tnws bg]|$|齅%"% R j(IKwn ;&i4'=e=z"Lv02S˯{Ě Gs|~ Z>slv(N68neW>-m-ZX|ŵtqZxQ^i1_v(eqxxz(5qx߲"zO0d{˲ l>dTqeP~DQ| _AIJ#~ףغ _=@$; #m /l DR@C{"XX2 9\RpRF n BpޢLdhAO!u$2pp-B(5LQjO!om/xהѥx߻8J2h YZtjjpUbY7Z(?ӘgQ`a+liȷz/M q \F)tEE`5w2-iWj:j]QK+d2zʱGmOxc1!ڐQK ]).!ñjjwQծ_]̛yUT}L̓yzcޠ๰Zda2DDž_&\*z <щj>%{@M<R|xTDbƌ!cʲd`dd&ґL#0JDm~:iՈ<>{%vOi >#Bp FdMMfsSDi:HľX[eE`|h|K%=SHa!vcg1Y_e[Gndя2ccH/3Q+ p'DB_RdLmhϞbEG/54]PMY0 Mi=vb%VIF< @!#0GF1)(^&TAk32و&o~%jdvCya:r{yx WwXq,;{p\4á8xwb Z&)4ة@%ׯlBϤ|3w}msM]& :"KKsncSyJgKZjo:!5rҡ)|%3TK"SjR,!YP"fy\gOd~#bA avzO>i:>8Y! ͇SB >}08\Fmm.NK,lˀx 0ͥ.T,`J(i {Q c|!c-cog,Z(rK ?Ԅ"̑,+VUZ1%{w9=2*aſ+@h?312oF=Aԩ|3m5}kY'DJuԛ*P c|K\W"w_c/G/QT#Iv-)l3^Ԙ4l~]GJ}Joyږp=ÊM,ndWA(~yzݦvXecalE9 U@jMOpLЩ{y8MMgqR}cnFIarELx"?HX(¾43R8 KAMB}GVלPW~6? DNZOB'fql_ ɄFI+n:rUyweKO&KEc {!ȬgGFlCuSaB 32?$QtKz_hT ޖ4\ e6o<ý&4!AEUC1kȚW@Fp<vĿ Nu8tX^`QD R]m$tE7_ $ 7 aWe57a#N-n/*&OSSg%-68-1s9B+2tsSuSq:wKW ˑ*hlFtz; p+tQF:!QԂ; _i [*6d83uQɶŧm㢠ahT8F~+_x(.oj 'mg{;z@}J s6"0yrz6q,Tn <̓A^Oꒅ9Lߠ58g4̊>N rD ! 8* 0W9կ݆7lgԗDt%rٯm=?^%G5Yp6^EopITKB9"?oX;3;EWrE{,%)W%Nyոګ$T4 )5^̔X~Q"v44~c>Ci dW%CժH33Zuq{ m *[5^rFDcn ' 0폤po%2"(ENeUUbupًx t5CA\OD 3zC&)9lJa9U)ּ$q0W*AgToqC jF!9&ʭ1R&fLlBw(굕24J/*3RqƀH5u'7 :aJ y>K^''+?G41&:4vi܋5A2LȧY,hG[D'2l}Rle  UkF,x y~*XP rS}ʀQAsPg}#0˺.}2O(,4Y&ǒYcՆ G}=qP…m G_E#نF.1pRn~Fb|*NII{WY0`F_u#nC*s-`[-\F2U'f΃43D Dtuy܉H#gB.0eǜ)ˤJF50(\osǞ.T0Xֆ R`g"?fPD ~j56 ˜mv)c|[Θp(,ڔAÏdg $Q3I2#+= *tnٿF)E2x!`@~ǣJSuV"dWmi}zՍPis#Bљ@Neϔ\5-(KGՐ9ǔpR ͺ2L7^,! ;| )Dn#!+fYq+N,vcۤV]Q/p@G[UԪ &ns4VG>Շ+Ut?y''/5e5#'L6U6)Xȉo'3;{+}ߧ[WA^?M0{x@ѓK͖|_fb6ߥ('''EI] ( G9T@N>]Y$QhL(1( ??N#aITt$N3GI)>ZNАY-i)d:Ds "]  FRa3X?j2yO!tEG/̶ G2sxy:mꄮw oDܿl]޳næoewT7G']{>fI޴ Hi1·x?E^O1Fo>M;6;ۛ;=ԫ=?uwڻzQ]8Y> Ea))Qj 8VNj~H7KnG += TZ S}q-fz Fz{mU_sHhƬN.&Exy4YW׊c[*%ĕfAj`D~dCOm}"Lt7Iٵ&β2Lr [ʎ銎+ApUZ$^d['^ >]2aezƬp$UЄWJsiZHɌ H(t\0"yX{y __SVVC9!Pֆ4dMv"3+~$S kRNT:9*yǎFEc)qTsj{<Р6@!%8_ %!ʧ^Vvurtpi3)*}2l=R`>'zp[MaP42WR4#cZDr]"u{?7m.*6\ݨ]ddMUaDӝ&[%v8!?1{dٝ}cN=rz,.ơ[|Us`L*1PƤF#TC:nRh@.Tes^mr7 0wlkz$V7V8J/TxuOgA=wv|˙LWc${A?ͧVj~/2ޱ -6x"Wa~蝉u&eD@>J]V~:X:Wr,hʪЋ|A6.Phtwu VY%?`KkoN,If"JNsdKf]ۧO? :Cl zܣJbp.ֿO,Az]DׯP#PPֽ}S82L)LhԥY gX_w k1sE udHW㋮TMȢvX"(̤WA&tJ' X(i84$E@ s"J$EVQڢ%61@{-OK:>*s[49w@4m|jCbQNkCLMnx!.ı5ZƷ1rt,@YDM&*S>1)GIك5d1iI )# jrxYrQ&gҘ΁?-[2slk.T;Ԡ^Ǹk,|2Q:rX韺"C++t2ćlە%I;߹$m)ZQi{>M<wrzuL̚QfaёIPQKvdfzy7c@QN OQ&ji|J@ɑ&Ù K SG\x붚>|GQ%ɕu3 Ν>KE96U^U 69JHhI(%k}Y(XG 7eiNĪdw?bحEu}7w3.#IR0'F/gGGo [ī\&`2]z6܅;y~DA)q#^*Up1vM5LdLA*M)TE_%!^  qFFс@<~nV D6F;^0bK.k ެX-ܪ2Fj?ܚf Ln/_;;/ai.Y 'X>lqW b`uGIhe}[X)A^Kx.Hlg@RM1%qwi#K| 8$&aΝ{lsq6~Z xsXuuuua1*'S|21in˘$#yhMo[8؉GK?ۥ[c}.1bM7sKFNnv| "%>mLOn{9$fmj#N xeN&ӶthTL^W*tJ*MpI ]Eܸ9<1 KjVR7mwq%<ث:!ez^2Rcw-H>=U zCkMI'Al r $Ohk'c6jZmcRvb2P,o3sEdu[)ppF9E]2q/r.o;-}=h F o[մٝٳh *CFA@~Ydxtjsoʱ`0X0N}PIqz=?x&˴Μ/Q6 ŠfqptŹgJ8[h q¤Zz&{xy|./D_[Wr /]?Ll%+S+?`Wl;r4eVTڗ)D끞?Z{fT/e3&ތ<_^@8',nk@9fp|VN6r8U{lx3&މKfLHAjXT Kؒ/#T{^tAEd}S^?Mςځ"nc Xo=ly* Ӓ.YMmm6T[ZMժwxNj8;-lib2tfhZ˵6ylfײ-ֺaiw\g{X0`l|~ Ɓa 4naMv:>)OaZ,MิB? GI~>kyL,ݕd*gg^RHjViUiF0KU+=0V6ljjfx-Xì<T H32 q_Dac?(jxNǰU[iڨ7:5,;oAbxdAJfCVP0j ݤ2 IG%QzOďk+G0%jZNƔΑ2nH>FX <]QʭVTKIήBI;:ӰՎٵ-]m:M45 s oCG0SN6q4t;幎(Q݀w@ME@7-2W~}i"N3(AJ-JXMC5-U5UmC͖a7SUU5NNn٭橚j9꺭cuzKmv;q0Nnׅ65mxF SUÃJuUUʹU- ruձMkdpJm:-RSk֛l8fغZ9fF5f9FT;WS%M+ݰj@@;u܆W,#',Նech1uղmnC7[U)Ms\2:Uo@#: օݪC/5`%jYڞ]-o't;f ַ\G) ӽOͫrL`>f^;Oq%bk UZSRԦU1Sl(HQ L?Vo`UI@,F0ljjUfAjPMDw z7ѡjUЗ#! 3r YijY ⦟ Y'AbEd['$fD"774!kH &Bn(>Ҹ&5ozdt-PCS8nejadeD][-kZM]7`aᘖk,Ю_,#nBX8$W۵1>,%w=bɒX`)HY_ [&_%֪ ~{"{[Sݫ%鰸W ZS0ED[ǃ } 1r"W/Qu?㺿zzpjhfU X\ꎧ6 z?ls*uRp]m˳ˣ)F7oÑJڕ:ogL+֕pI(!*xݲ0(f7K+RYmP%-!k 0m )mOWEJGJIнzP9vy1/n|DoNRUѾEBM![;P)U I]{;Mf61#Q'L߬Yu4rd̑̑p هfEսh)7NH'L*6>OYa>:Tf8]v 3 L<%v;'6Y!Y '4S$8}<_ցqLx͐$X΍h!Y@r " tŜ\?f<\#MA@4 ӱ?!ʯ I/eJ11I:|0MYf.*:Q/Lp6TO0eLyetz|ʇg^We#,!gl g> ,(]e+n670dr sdWZ1j R2-@/,ްKYEڵAV".iE W 4Bv6v 2 o/gѿIuДl]V$0,NaWC4U"#1NJ,t/E0)__*ܡBYׇh-o5v2ېی?!{>|L.;0NG8,c@!z%'~]gM)<_sJV4P^.7u ɱU,KtB8 I(1w8'^!EstTiK7T^| p>ht\g!{tLo6r;!Ft$pH࿐>QB˗b6ǧyH+^>yPERT5V̿~tyc%cdCDT lʳ aC`s#APnA R :UHU.TeT|t HEePx@'sMsSݿ%'I{BF#- -u2sz^WkpO:K /Gu hVu<'{|hc%\HSRk?uՃC%-&XPe<#. {gA㭋Hٳgߤa{/_ {&X5R _3tmF*Ramgi3tTY!l5m |_*(P Xg L2Oe>IKgq;L |%8cI+a7!}j{%-З"u)D\sgI9 _?׳]y$7҈;"ѻ;qH*5-WjtىDS22|"^2= Nq\3>w9`>O*YB% PpSݓ}mc|(`W.f"P7.׸(n OKyep5荛^Gq@V2DU&/PjB&t 4}%1BB25C~7)R!e}#@DMO_P#lyy5QJGI_efBQ4cz/x`RȝZlVlW}_]q j?f5Bس ?5GTMq)տ7+Ar0{*[*vSazg=MMu ^]ngCV-̛7?ݩM5D5o2Dliw^[> @&_le50,p'ȓn % ::Jd'\n}#1ΦS;R)B!/M6}ĨvꚂxWlA, DU1cXie08Oo["? y?]y 5o9^TLJjɥf9!],gxpM?|$Muа2E4bXZYCJkQ>)#7"VX u> /1Vq6rF]?b< e}^}1FۼW9<:/[F$1bʮR;{ZTǿ}؎2S9+qN7E5e: B)5S&IEӛ&5r~<gѹ{tҫh:c'*H}|'DJi8x[{ң؞N]A-?#$GV:o;j[jh=V&dScD㺮#pst5^\/n\+c8_v3~P}6f0gx]O"]:P@K*uI.1`j"۞OqbX̀ RYSTrx4U;ȍ>,*JiRe萏 O!4Kn1`$gB_-J1r%[ڲ}Ŋ5Qd)XQ77VΆ|IGn,M=HoS*I &Ov0,_4 a!wSI+za[fkx˳Htv) &EeV7)Lhv(v1Qs:r7^Ӊ_Qދ{<B~+r N %ߗIX/ajx`#bR zvp,+!ЏCK9ѱׯ'أQpr$M g˕AnT-ӽkb9~MŸB RFQߍ:5(Z;B:HH6}-])sX$j8xnsx hOY0ޅad5y<8n`N*1 O) y+=Iܻxz + K.^c~%{d oWUgէDETj 1SL0ƩxxP}!Z}:"x?3]t ֞c~Z 3 EӧnmM a +yto:Sp3 ̮)U9Tj_v^<}]b)g mԀ^NϝV;ZZ|_:ue}ݮ :Q'TqMotG<6mON&Eca TupMEj.P[ [|읁")wΩȝ|j xkNEMnjuƓ ʵTubʤ d?pШDj<|,BH2D X$7%!gZWa&x)%ifلa^*8sJqFAb+< +9j,9242zl5 ˢFTDMEg DVKѡ$ *w6Vͦ%8dUlTJ~f'~iuD+ih=Xbw1%3!:V5wkqƷ[4yi9;u4kJDFh^--f Y?q`UBvMTsMUiCY &Zfd"їUvwedoH%6EݬOfکO{͛='>a_F0% }%gGJ8Ol!aU}J>%< (a%9vwŁJ7@mIK)2_F2icZ_"kov "m2I?iO'`>nɪ,>!%004JZd{Y{Ւԩ_ҕP;.lc^UƧtpY ,h)}"%faೕ,vA?|*8'{`RQuAr7p;g"XϞb\TrPVl._ ()qZcQ, ,1_V:5(1,IZR)ueHJ@Yc1E5s֞jw|m+o_((,1mARؑr#--%gF"ҙӢ,-?Oc`odLe~L`^~|&y-1+[vYQtyE;y]kz_@hz9T1gc#*ln< dgpժ[l6 :Gh41*'"NYbV@j8AF%M72v)6|yg{ʕTV7x9qo2RySpRv,op&8Z,=^i a<<`_m aS(g1߲ l0!. yLA*MqhK2Z8N$,QKL`~* nz ;Y_b8ABMؒ`,!t3R񦔶M^<=~luX$VuٮTw'{mIcW8 GL`QgbQ[ ㄊSpS. M-thQp%`PL|Q2ZY<43¡S]akdUƔ{hU44R{-B S`H$CKdѝ ٞe#X'_OGU]7 N$ݗ.Wd`E  ?TcT01 xl2CȏcX{<'2ngSsеGO~ PP9R %#BU] ϝ(&:qq?$ô5&pw5nNTQl B ǟ ' 3vQUI\&i8#[ɟ$ S"YMp"̔::i f BG+1Ls DhoNM$+8R93d̵ J7 )|rnt@z8n2IΡ* |U91 lS*' D$wBWnNϘ%wO R+dZ @4vl>ԛn&4*f)UlOy^࠹ 8tB_fJEJfP~Ь?) Km `:LG.RU ]D&ɣklAGΫW]G7[OuF ^0_~{>QapZ6Cť2 q&pE88iN+ %;)>" d}6KimqYWZKF%TI.߸a2dRwM9c6EȱtpB@ך(AFD(Íl5\`H>eRI 焞$9n͊ˍа* 2f(i 9YN, ':h(W8P)?& x'Z̪#[LͱNPI ˇAu*ZEj|;~@Ce! — mչ|#u>ISOԴ!i&,dj w L`_^pY,eV b|D>)&pCGTN@<0˱:Op$LU6Vެr1_s2XbI)Q)n&u:R|rW.ou@4b&GB X:_9IS*fN 9xtZBCQ"`n #*&faW(E6ޥM(`Ih/Cp,+z6#?Jnd[F:]MR-)!&D gZg$ _w=[Ty5Xk] +ҵ1n[@}2$!ժ>)ܥ7o,W }xd.7Gt8=x%)^?Hdz;m@ƾ(&s@Ɓe2Jj+孜|26=Z!ָ̨`G9>4?Y\kgJw6gU;w6 ڴ1R`-&Ո&]=|[gk6)=d4Gx:}[}%<64Ժ v{㥤'%0ެnzKqaWE8nb88<ׯs.:+$mpf1$Ri5`ơگ{>jxͥaxUgUҌו{#p9{ݵ0Ə3-T]e^$!vt2TSP͎^>ƹs8e/rӴҸMq͘bT9,zmPsF7MR')I?50|,![V2w+ʭi=-43hj<_mЌFl*ڝB^<?.  |5 a?/MYmc!q?xG½[!\3B:*FxbI,JasD2#' um4pLUh޸mN^wazA.MGg~7!m~(5Nn"JOt)e0[vKGez'#{{/_ze7v3V'w>[?zcl $֙֞ }d]VƚzK=4DM[JFƒ IGSL:@zf;2hk\'6֟?Xi q&&qn;M9e7K@';ϟ?k?Y3hZ?>OKb#,\llZ{ݶ[j>nw3c/ŭm4Roj2r(ĢzχtZK]i4%##tp .[^&dfg9)%h!{ vFLES,WD/zp\5q&}Jghc, =VYX3)ʌ$Hh\B $gݯCL}R#Iߘ\zSVT'& E0~GCMJocSdH`I wݺo%L(2ץYN<񄗙 $i6T2F\nUD tNYV$>B־#Xbo-W֬2=WF$@؅!VBF,)ro>Ul o2¸Mp16mT=--ZaHn="՗)(r++er _͞z)f7$E]uV*qQ0?! Z# f &&ZݦjRn6wȔDwYrP7Xm rSW<^QY9h1ŲLյr2l,#t5ػJc vWk<> (s'k]l( UQVyHv_AuL%(U,';;mљ9G,MJNwm߮`#ޠI>``tr@ e}9fゴ#p[NdjƗ\# R||D+Y[!ʦD1z3 $Uw+*rYə$迆y( e8NApw t:%,dz7gԒ`1'xp6֕r]#RuNx&#UGiN ̻<% kZ "f\cD#|9Yb^IGq*+dz_DTS^p*&Do8]Uuen4s|6WdFVM!^Jvj`|,'"6*ThvTИmq( Lp7&%a PH lb M:߅ IΞ,f#dUS.J$GhK5ax9Qg'$xĤΩMہ <~$b (3 &@k*-&TI띾}GGLh:RHua26˧x*ÂgsS,hf7DY3Ӊ֌: <i@tG5 }0+BJHCw3'Hg*߀py G5Q7j]SxrCJQ 4Pe>ґO&Z]ptq( !Y` FUxddo'oOw^::?hf!b,X=eCN91o׫ݠS(p$ۨdj!݈`p6vhپ"q-Q}њ|D/<=kJ"[:r,hqr0+GԚ>=|M$?vt8O\ӊßHPYs*RqwF)莥㮲4S6&LGPby*U'-cnv@4WϠʜ6A;0LI͂=UrI4GiHbVaqe-H]=w<(,Tv,n"^J7h&kUp-kQⰩ(I0Ҭ:PV Ka rĄq("ؼbO"贆;: DEOLS9M $Zq[j5&r#7Xceρ|RMg`'ɮf'4)%-D R$Ra1tF$gN h"(+Ϻa~ͣ6um Dx,\JTr/4k~p{QORu4hX"MKzZpkiN lw¿Q"%`[F.ʹ01+a$ĨU4Դӥ̍LS{=n5@_F#-E)FIzcvg]ΒnD尺Sl>w5R6+5lzjW]5 ߭ VS2\ܤ|\Lj띚½SpR ޲ʀ0}j 5Vk<6KAB$h,H6C#jYldF?ԥnST͌:3U~rr*+‘_ukOI4 c0SJ<&(dF;g2Cf nIRS RwWʃ䎉 ?|Tҁݓq34Me Oh0 G1pAYVt"2$4]!Y1Au\ P 6cWUEsړB塎H | )Q81lǎAt+t~ANd:?7XY}Dci,J>ywInG+bd~Ni\acx>}a·HjYΜD<:@OY/ 泈jᖯp+Q֩E9ؑJR+AQk]v+x9JS`J32Mn F>E7בdRӣG;rO?u?r: +rFm\n5+UC_tZV}j Fug7҅L`Q༐_66׵@D*(ݸBN2j°C|TrfW=}5ጶYRQF 䡺pf*f.+[6#W?W܉ ,Pq_Oت[n#9M8a~MgJU(L+ Zx-sŞn&J͌p*)SN)FA#Lh]6i#ǥ93%84 NCDؠ)vUEjPiiEAȆt{$t0R&!Nϝ2&L ߩ5}*B%C/s6tB Ѹ^2,B$iHD33 'èWWśx'H(2XN@d.Oɏ!n^GMvn0P]hMk!Vz>Lrr8m$f*SqʎbQƽ.f+PZU3kfq\\YF˅@:Á+(:;TV.E{mpj|`W[ GCvN1E5Xpna,,,O*IFxiϻxV]涜)!Su}޻WJDZe W1?HmE~]J)rQCoi&1S^TU=(훣Kf5҉ ,qI%ѻkn5U@ISIA=M/$ E.m_wj7h~ ]6 wZ).ag㉓ۑLaIB8t)*$96\ naQqM<-4W#6KlVHoSPA(7e>m:8emu _ßk^3bc!ٍdo0T{M 3#W줉$#IQNf^j/pfN|c }mÓ\'9sntI.ۑعÙ]I 5*cSt͂l { ę5МuQRDfOxVJ(,Ka5 aaF=RR$ᑴA|oj2$L)0+$Ӌi+pA0zC%Y,)E2Ʀ{~wtPOp8Ͽ&| gTSvD!g7 ph'GI"UvDD+h;$HNXEHE:㌋)&Jlbg A8*,o8 e <9yn޵kyYhg2|8qNPJ%{s?ypR_Q.Ӯh['OD&x|> h烝;?ޞL8z؏ctBÃy,zvm(`z1 'KMݟ:8?cƳv:q2>0>O'8<ͮǡ?筵K͏^Of,càIX ֻ|7Sj<`zppѤmowo0u' K` c~t]"~~}xl" g[N~j<+Zލ' Džc'{}y ~mjU:heIV)ޒ]a}n_tŻ~)CXWu52{~`[+YF9XD F?h&WGoBTè?L* AձTݺ MkF"F>lΧhjHɴrŊRc| f~#*1+ w&˯Vlwk۫V?>UWj+e%PouXawMPF+pc0A_DcM$.|M~t%225mI%2,RXrl =4;4U=v߷?~i7jMh&GL>Cov;s.*mxZ )pxYr+,͓N &5+C@];:$jP nQk.*/1N#mdqWZːlEHTDď,۝vժ '(/\ ".9ρRm*[KT+{'~) 3y pd j%aCʆ HۯMVݢ뱐ZVO2A^jq c*rx3t6Ɖפ720qWȊLs-1HL&!y#'vqȐf0G;x9q$uu0hle;Fj8lTD-]w(nȰ$x5i 8ƾRK8b椕者NY/d t ΉB"U /=0'Kauq%i ld2q{i +_\N4}ne JqhQdqe7ҖCY/xdG;̚Gy"1{8eN wy2+/|VB}Ӫn 4@+d:uoĤ;1dV5>IOp`qc}zyH,:7 :m*5PEXlGYkY]G5M2\$!Е5k]`|Z/xopZ ~ ;Vvc.9RL)65mX;gx:(rڽ +Lk,'|1SJ=y8 [JQ0_NVN Xmr T%bR!lr& Gmcr/ҩ29#Yx/)>{ϴ*ۼ@~N!kK΅3cAf9L+-"17Q؟NW<2-_ձʖ= :zY8Mb^ y DK(Uh&Hvd|+WQgs j DB[ XƷggxrǸإ' voڿ_ ?`ȏv[0x ^{/ u C05j^%(`l`:HIԸᬑDF f njYx1Zh:N2T䆑L=\=~k.ʃמ 3[(jn:{M%bj.YtTHÅX1lku`/Kk4ٔ*g[h<Pi'V\j XAcrƠ9',L6UQGV!a&_L9tS _rHT3Net / jV}kTXX3yM{m &( j:6T3pC%اDB'ݲٗD[uNAYIY݆qfUm ]hYņ 9sZ(jN_Xq 0~Zd{pgR̊4X(Thg~@b)5D4ii] ]vwv Ȏv8Z\M@ ᬃ7=~Tdj,rm*g{2tכLժA8T԰xYeO#<4v۝gw_7_ ]UML*6ֽҩwm\le @i7ҒT#)D㨘$A򜭽1bWr #w碝NRљⲸVn`HٳIExvarg͙rmTm{IzH>G S|M)#P(:x pC%&Yl/8'ezz24@ )gHլտWFB~m'N-OlmFGJEetuakY%EAgPO8^bЍb vT@\ucTpgobT52`w" o[";P-,%>xB>6RK%WΪT|G~UwK(搒L圔ZrQbs4L}.tLKDv=%9>7[jQD`Rl ~bR.f/S<ѰܣqmVf!)P]y4gV>l1:@:hoEL$OV:#|1vrw-?x/de6Y</J&g+{P ov$`dc [ B'|CYkqҰmYiX-&i##;xpPnMQYveq7"#)!Ȳrmk<MgaIJ~EskOhI$_믊ǫu.{< 䆄fPP\aS]k6TWmlӂT|)CgN'9@\GЀJc!YR$kxL^a<%Jx2q1^BygAA ,i}-ڍa)OsWA%4ޠ"^I5l<8tb޾ݗfQkiɔӮl/Kzлtlz3QOV僲ZLH9 n)~9w@3tqJCZb$JGUnHhnDH 0x#4Jdd[]dOU\2R_HU>!"bxwEW̭@T(@Ļ+GTr:" :8F ^0C Y }>zyޅs+=H F)̠YY~چ$@QAu% %i i6ZdxP  *n GOTAl-06sRwx]w+.l˔+>^#$@eVLg ߙOS13TzQUPPʷ _@Qz 4n#CBJT V8kBK2|:uUu+\c*i%Х~b^feZE9HQm{!niXs%8: "L=H3+}VyJ u^vuye%>NW4[vYͻ(XۀFÛ]JU1H霬|L9~]F+M.8:HLQ/'oWUaYc \^ϓ./nќL|> ƮCO:(Uzd%kiddl F6ٍ, .dHb*%R=@a 2S5%@fM0 STK Zg^[]DuRXu̧vbsYx6Yo4NeN_yQ7ًp.Ɩ:$t V4Gx{^7zaO3Ɵ&Gei7\-*+w+؋EFgA*9P)$cy1ZbPOW y^՚ݛLh)gOA\`:4N9Tx;N q*1U7^ Dߝ45 gI3 Xx-%G蛃=Al@`ANUv@*6zL?V4TT1 ij2X[u 7߻-/XL%( 22S(]Ca*ޠ$},wx-("4f0N^JSu/NB墣C$<\}:?s ,A\qT00!m:\uدC]Tr^O`2〈]GͰ)ll=5-8Ɠ˶"CEde$R)m ţU:J'(zB:گH:yU!m%@8be4Dj4TI-1yɲ+r>G@a P^pSqhuIz[}d@ɬ9VT^Vqe(q| YͮH>]{̌' 0ݡ h܃L,i춥Hq *rs~l=X^,]iyH!zW®JѰYORo5I[bes$,% 2WMIs(\S hJHpJx1ΞV"\Pl *Yo\zi!00|{]u",7H 鴟4Zm$CE^E!eS1 F]%Z"YdY-, HŖ|"g۟FtۊB!b1n$٬1 dTSPea¾+j xS9tߓvqA?R F(Ӛqm.G͔(DDYk_CxZYzBl[b;g$+i@]j0Sv#̙=Cƽfㆭ:n{vw@ AgN*D]OACWf#MZu:%E+,wLWlAq%OP}Ap܄hђU\v$]n\vDuQ DK5z A*k{5.ӇtaAgEf[&g 8 lpy4SjL >O3 &$6,֡gnj(Ttcbr K6 U2C#aMy{T&~B :?f<9Nm4]1n@4ܻ '0dl[mW񜬹3`| bYA`6dH|t1 0&C𞆌ٷt}bЎ?p{4:VaG_ƚ>.T^՜~=W^;4:;.7(!$7VKSlMT)4lФ?3,?b/_6*"tGNWPW^R0ez`q] vm.^%4 :HPlj"liޗDD>:qc`X.HLd2Zj`Z$((A#8_ ?Ii٧(U` ax8B Ҭi4֟Ug0-6tCDXa,?rCkZǗ%[LXN1 OOtx҃4j]+SJғO1 b%1(|%} Ng2v6LuڳuF3m)ᓵ VG;};^@"hܟ+ʒ SKvTm;:<{E2 #(ielG!t{kdOpR,G5*γ3t2NPWk!QZO@}fK,X)$_Ŏ5^L {XriRee,69W:$ @b^_@Tʑa0j<"a ,PqE\WtTSsT?_K5U?>J 'T!glG߳\ۥz6Kf ӭE`z&ګ c$Vx'9:cL9)yqNȼӆ+*7odz$%A:p3@-Lʼn[K j? ΒTsΦ0IqğV?gJdE)TXQ<0S`: `1^%td<8|O?! MΛc{Ć4ȳX} 7yZP5,; |$Dy6ǙG QE4DQF_Nt$1~<߱q,\53lpFr!G#u ; {ԩ0LGhσS\KjΨ38 PwQbB OP`v* `BngL HM0?.C~+zq(b؃rAU#?= `pGq" ^*4 B3SR5~ֿ{s6:D.)H8>b'|dR^DTeH^瓉XHJO # K( :M:`Lbk'd*?hQ4./qv*:z9AV X*❙!ˀ!\F74c"-ߴ.Wq2Aig - SMv50q>5,횠{@0Ń%X%yޚE?K wh% ? :A)mU3J$4cHGxFCkR+Hɔ9 ?q4&ͤ6mT՝9;4ٝ!ejOt~6CgBvuC:2BOv5UWPrNg]6h?_G;;Czqr,@uqGoE '5?u?:XExlF/z:rnL8/z00^C r@Fʟa֑Aƽc҉3OHGjfh8gy]Ϗvy:iC 7҇<32,8P! \ =ܶ =8Pu-r{\;G"t9s? ^sqa;.8˃)X" 'Ff>rdB1 >7igy໐;(O)%| 2\Yrk^Qʋf;^͍QNCbT_4: vd]ze,\ћ7 qQЩ>Es ,$F47*yΰ.88NdhQ32cR[r-IL I0˴%|˚5|&y(4T 4(d )WB](uvY4Ӑ7+p N 8UQ3R`0D¥$L08򸴉7x F5"̦} Ўӭ M'3,ۈo9g64L 9KJq?y2!zŖjv#6(! IWs s?k fIķ n=&IS0Ԧc;k!N͌j|^yݙtE@5yLMOx-Ő -3g^ E╴LD0.d`ePM'1N lNAK53ߤO& ".b+kO[|$oIT{ZS+lJ-b>Y^ θۏ:{V)62J@}[s-`<1}eQL\ )aQg;p¼fVM|{v`Jvv PBT=( =%y!J%XI(R=7\ KQB2YL<;MycD@4\ˇ<|^4ICf4ydgI/L~Uo~<-(ְd#5&ĢUy)r<IJ*O.5Wp6)E\7is%5Nzj=r %D)*mڮAxgGfȀRpd(.-k%Jt\|Abl1nSנo 4zVqpWh$Et~aAbe'i%˹ϕG4. m&n?⑛5=V)-IJIE&$-FB.A>+O|,Wn"&G ITZsCz7 ZjfDg MJqxig `1MQM4,"kR#}≙o1Ӗ3OI^ sonRTvTAtᅗIL]ʨ0{8o`0ud,BaxJ,[u&Edև}.1Fyw`ܤTj߀W5*/10f ;أԠnfˀΦN'ZŰWm+0&H%|'bwwF#˺;RPAD^0Ȣ֕L$ LEz:RK0M_1*јc`@= Psݹ?+Us<ʈQ63xąP@=tN:/۱ƖƩײhf,1E~ G.޺G+l xcv&p:-j箤J\ҟS`[m!q݁cpʝjKo%u!hcYlK N܁ID&͓"n_D.y29D,BÃR*^6裱N ; 4RaDF+X6ڃ+jV8 \zl3L:<j tnQw߽z%L.E€ hw݅ynwhNY)"AAWoIwLKIAnt)7O,]'0KuG,ӋBt5'L@kASǢs>I酁x7 F۫c#6{p{o~zeogsyu3*]PlL( kLڥbk{zZ ԋO3"`(@{콤T%[%"'b3C}^ATBrX&?'?BQXtp&>{sKֺxэR\Gox#ܻF&:"]@8IWurhblQd$} (7pO2Q2",d!'z.عmv:/%ħJ:|za.F<|Wԋat"twG1\^RfR!+~t6q"Y((f6)bWtÓ gNoRh!EFDvxohr| =ޑ)ΰhiiҘhTBZ;d &dllPqC7mr~˂DXQ7IF)] MT7`-C'o?RMEp2=oA*7׵>Bـ4nʒT 2dt SJ $嘬sJq)!9ۿ]saދ`/0M G! Hό,RRM Ҳ?]"] HPq:kꫥx뻧V9/ittI9=gB:M^#/}͡QF#2A mD fLIE$lN LɼKAR%]_ǯҷr.7Xvm*C>V I>Rt*B7vYa0¯dBa(fK%.B^w: ςy^aºYG1X({W0RIhIIʫG^ˎj4Hq@vȓ[iпS]'7!qel:ǰ]ǪP'9YP TE1.V? I{XR|0!U6#D 3R*Zx1(a*xfIJpaٍedqiu,_< `~KTϧ'T~eNպ&ޮQb;{SgؒŔ`J pSރ) 3L yoطJb_| h:;/ѺGZN/s@sF9X(U..C _K/9.)cu>;/bG HB*B4) 6!Idx1 e[[1yxmmɇo0j;cʙ뎭9@[B~>ۨ݅Ξ76SRs`l({=waT42rh΀0nē^.ȝOgĎ+PCM6J]Zy>A 35"`MT$NCnFzm >NH Ҏ1`#F `uqW )QjaA|sSu̢Vbլg+oqÆ.Uz3UUر[$ӛ,N4(,lhM5dO8W]g=6&21;TZ4_ִGt#_ϲafM%%0=͛h#ia8o5C-_h>b)-S8bNXI*&6alwd  o&2x&<駑GĞph6DQUЋ]L`SSPү@AV f1uť?*8ԖGlpJ~s9=ix##؞mO߮Z8;?_D1_o#1H7L+7dKt-TSڶś4 ЯYRf6:mѠ2.G-'Գh ЖAV@KuoMPڥdQI#3%VXź%ODP&HFL^(1?!l̟0)+~KF0uj ɺx.뉫(m/!:@ty $ Ѷ/4nPxŃsX5_}r!J0uqs(njGm;/'gqh?Ģ~ñ_qjx hM nOcSlįa m t<-1XD*F+/,ҮPd?<|k =hԡӦ0`?t4>7ZрIH+^U\byhqdPZ y탉Q E,Va2ReL..#flх= ?׈qaLA[[Z:lX$6ZֻV.Rp[y#hk9L74 #k*ZF6J w[TraFzR1&9{ {Z:~^5KkS@Y;; /vxek /ѹ#^EƶWlyVF-"1_5.תs٦U[ TbiH*msEg@DJYv-řDTS!^~%,Cl6%ǩ g|K'Sgu {8IE{[رO-7@j~cKI!ϖ5Y=|u(*<þQF=o:J6~PD ºY2OdhWWV2an<5v]/v~KS6R[_xl[3YDfY =R&b8,gqrft3[zR Q%PRG&"]b% k* g)$1eh}EQcw*1Yʬ%Zh2Ԏ,0e6V .8>,S.„?_rp?Al.$bj sX%Edfne!@I#tSSag.5 ni?Mp2RwarFpvԚsK2DEa˦;8z.LrK' ŅQ({)ۃܒ=@ͫJ(^"|@aCS{-pv]AO/s) F)崯Rq{` I 0ybbZifif2,W 5ӌab2K,?|68r t$|(x:Vd$鰖YI7!F-aQ7o` ݷmBe '쾽h?[V^hEMY3Esbq_sP >(۬y,fD#8Z,m]SJip=ϩׁtXZ-a/]l"h{o3y]uqaP{D`2ɚ:SaRH_:w )z%E7ه!j mQdO)8tŸt,zJ턣>όHZݚN mbBZmoPfHs&gS=}4ǽ(Kt{%#ZʑCߩ%õuI2T!2MZ8;ldh}Ž ,¶NYsZqBnQE>%m&Z~vMadI%l{23J׍.hbe4'#M)c0:(ҶU** :cY4Z eW (;UUSUZvu89jPF'U}~\u,XwS@\wnE DE,&&xhBZRy~,,|8t>ph`RuD{=$dĬCtTӗ/|M't[̗f `l%c;șc#X.itvSX* #|%SD[q| r XټE ̨mGa Bڔ@&rt IMcjEaurI*՝m4<ͧI\@1֙Ի+ L) ݪ)sSvCaSNˈ{-+$; !Y;3w+fYsc!HRرh($K鬂&SJ5,]vRak sV-}|}/_R ؐe^C̃jin_{3G&h^Xm3Cw6Gc@)'+nm5?xi'v}BWt(ik:SӱmGrG>~*i &oTT]b%qY/-gr|nGWa?th>x ܯ;MXhpWa9wWo~z WI)¶Կ!n,2TO_=swa}i=S["K f7əZHh}b:;NxN"Zӿ⊗N.8_$^K,8*1|Ba޳ g+ y{T<[NDa>UL Ք]HnCTKK֙JmA8'>ABw܌YnrVgoOB0dJBhrky ֌MudP\{NU̧,=ja?/g2mܢ/-IM')0n1| Ftr0:1piy<3&vNi4:ׇI{0]_bRow֤}C0G.Q|9鞧.H 8 GR+H%o_p298  =B67EQЦ[,׾[Ⱦ(dY(G-ͽ ʳp̖kg7Jx c,JuZIW|ć4{N4TG33?-=JTcQܺn&|D?l#cTDxtWg$"YGk _UQz9P{kQovrvwt $8s H ts%7K@miY {.E{'tN^_.rЏ6EܺItLQɱhl7ߔo9L$Ztk19{ zaS_rK_kXڰ4wr.WAhs}Y4t2}B,NOI~Ct@sΣЊa% >5m2dQ0UdZ[6CR&Em!y=L%k=5B PI_^RTnkkjj[ي&O0 쨨VkIs _wLEk X7H9lCL c:ab"W6eW"E9EDvrdir2u MW'7G,^ ]c) rP)j%88ՙ ពJ OH-wp|px_HǓWVjoNpS}@ޓJ;\"'>?73nLG :9x۵KiE2e=D0wԥB;%hK9W7 ̷TB,pv#^ 'ە7+(L"ˏ6|-i7``d񛣽#Ã`#Ժ{ӖŸy]q7_I("Z)pw'y6w귶!gNybj9-?}~_+In9nl> Nb g2K7ڰa2<ި*m2& `s\8&$o4fSLX)f}F\8>9$#Yarjp* {wSl8 & ΰ'Y ANd;-ҒtŇ٥)ق R/&چwEl+A BCO-].j١pբ;i$="hmBnÄ^{dE sXnZvgA1c\j߮=`bɫ%Us$|˽15#cSAU26fqEEU^7֞$J~(YvIQ]$icZ; 3:/'ZL~B)lŤZ:K:dh4dF_ڨEyCK@ok_bJ{Jb֡"H.2dΝK!EqS:yQKQi] ʦ~~2I0ղ6{D(S؈oΊmiA<#-#s4X9Sdz$9B"!3ʖRͥ’U(<}){HU0 m4$ j/Iv.޸GqYYP}dpDNPRW]ِOQ_f >w;u4 x.+٫*Rx0ΓVnvM;;!bLqxTHe[2dQ9 "2}a(t:֮G`زJ6d~PA$r4o _>kՕHge[Q#悒ozʼn{iпX#0Ca#UZt\]t7ttOR]07U}ɗfV^iwK }w\GSa/nÇ땶Bo@}}cOK{ۛŎ8Ȓ5%g8{7" 2Ġ܂3ޫH6KXkй< 1̧4n)cyȖQH@UcٽʑQ<ͩ}:n~\[5L'COV3wri,JW`?,T&_,g>1 Ms}J,ݰE\Sԙv)ُZ/PG >ыMnˈ5إʅY#+0(q+q)&]ML@u*-8+,ph MK=ƴ#dnS.J j]'KV5K+b)eD5Eo T'h ^Vֱy|z}SR]XH/bMWT].>o[]ntWDu8YJfb8]2_hݻU`sqVEMwI)/D3H5uؙ>{[Gj׺JJ<{BMj\gVkAOt"zq[%z(=gԌ<@ DJ:‘}.!.1݂e'ڒ'zYG19Q`2UlY!SXiRo Sp|jcF%$#wF5/rvKfSV!ܪ"ٓĹ_JQS9Gװx`>Z3B*& pv 8HlFXu)TIx*( v]0UR"?R j*+ֺ XZQlySSѢR!%剣NjJ>ωU;G]/$96H|pt80G#8ıv^zfv,Y/d\:tKlပ %91ޯ|h_(ݨ,~jج+FK r_[tfANO< `eZpanKS~?pJ.~ϒ=ȓ\AVMUۍ .pc8GIb$҈tM`eI"RQ1O&ҸJa=a1jѮ2y*}cs`ssEH;n T79zsh?A';3 `8 @TgKTOwud[(YͯN".UaV\u. o% *aȩA:JصW_tBadשz!jUj?Y(lQ%lj~~SL c3- =P嶫d TvFVLrtC*PlJ,1gow=;vv!s@# uWj[sjҷ,cSfIr59(yK^Uv2ugѸ6>wowNb6]򩘵fT|j)8*d=wR{+Vd5&~\[2 2Bض$Ӥ%߽~swe<.l+0{]PF_2Q}^".ݜ*)G Sv ;dkYF)mR۸wu}ʱ(FF9I MhPHH[P- Z# vb0_!L(=LU 1(BH}g2"dwtЎv73t<Y ]Q;p/4NLCJU-QUcqE$[%yY*Rz)x%0NE :;uG~"=]:0tbCQ4F<@d_ `o[Vui)J}wl)7N3Sj*Y0g*Af q);̩R:\[m}Vgg\`ix0 3Q o-^ݬFg;Ʈ0o~9~+Г~ŏuԣ4y* M2h}ب#`)Ƨ{/|/_Xg\j~ N?2rυBAɆ.o0@BÁ_A+Yw WpkhfOi#Z-3_"qdl맲j.kl_+zX[obGIQMfQL}Ҿ^s:coyuםȊU*4t M&Iy\ЖmtAn-ђ`^xg2PVİϥ2#J=SPFZ^vl4|{_K{Wane_ig.CKÂe>=m"S0g)kSֽUXVܼ_ l߄Jy5SL'ؙRK z b=]d\TRKIo GؒGGG[r:@,.F΂lv|e)fecFQ)R *`V}, FDOsreab]Lp!wp:vw)6j%xȡc`=OYuq]d@K&6.?htx34v8] 2)\9`,H'o< ,6NC(ouߏ s9+6!^u29ԠQ 8N0n )5eydzwօYQcEϋbhJ6g6F,hdWc-dUg`$((ދAƢdi u>,QSlf7 ݎf֮qpW9aF"^ۥSnK8mQNF OOgDss~MGݤ U@Xю8V $yD1|7`Srxx2]eTqyv4A5ORw3lV ]&w" #_pPoj=w 'Juzs]f +l*X=3r'ov8Xm ~? !iEWQ2@53{Mp.8jƱV^etnЊ6jMwZp' 뭭J( fp2,6g*}]6LC0XZZ^8;Z@']&aP[ү"${rYl0Xq:>a6Jވn>k2cM2!Ll5c?eygц2]Ð/P[ #E7ξkۢէ0*l{n5K~C/(+?pjȽ֭3W .hHq Ӏ.0كwVl0 K0ዬTj@B50Ʈ#dOs=U|%mWKYTn0Cl5;%3ۂ|Lr!z)j2^20USc⠨p5vaGy@ 7r]k O R6Qn_[ @\2nzoY-MB9\HȪ=S:oŧ 4}4pmZ[Eb+0ðs[M{Ӗ듞Yru,j&6J=IVy}U)d8<'ϏUu~ RAcOb{+O\ᐜtGTt=o(5yZDlQp=b,}J&zϒp?/Htgގ7?ͅ ϲ\hAۈZ3&];r=GG%kM+ y|-o%kZU.!kF>g s .ժ>Vޏ> tܸx0g-!Y9cG3-]d0\! cV%tÆ.4tX9rs bR\f4ˡMݴߴ|oA.1l H>bJuo%WE:K(OEXd,awVK}jcdR$qLr]eW.zm0fE9uK}Z7d%)M ƩK'뤌-!ǀU i9 AHep-CO$ *sggf{n6\x= : %DͽmooMR<)4 NFKںOm}eC"{^I=$桧? q䜄9d7]Ne΁W( u;&!oM#btԛ%d5eKs"iQw9ڳ'&-8Wq#9JBq$a(`=f!e  m ! 2(9+Wj2?#OY1Y]YCDS m]E}H't,[V\2u6A-&Z0+IqC}0?8>jQnrfMBm ;xsxL(TW:ZނvW6`C6'#=hATZNEo1O= ϧDT>pq-]_Rhl|lh4I8mDRƲ8aD&|"Ć6I8}s$ ҩakC4~ς &(e~OdL vR<GF-R#~7L',dxn̨pm +O?Bt pewP"<7F& K7tT]{/',qiGH[=Z .{]e0[0eh2&jiP;$ʺvC:nD\j&Jpn0d)JeAQorb8ԦL鬦WSip/ TRʉ&Cs`ЀWu=͑JUCzY(JY/AkY qv IXћ';|#CR@G]&<9QtDսnTVʦ괈I3Eto4_cX])^G. (K_cnvq fslu-){\THzlO\c)Wuu*eKIHT⇃]4P5 㪜>d/_V lPBn`jYB\ KIm"C_R*g@eqjL_\Qd1w9Σ!FUǕ;)fB(JJf%pv5hT!-S0A 6='Նq0DnQeOEE6,{$ ",*zCKR: ʘn>E2`Q! Ov~>V1w0A869涗 e {Q67=Y?;x׃ܵp߾9{]_ pvł^T t(dm4iC_;.gShǡ^Wa32pS as -^ɻ7uǽ OTg^jA_4S)-Np AFXO,bQߜ.FɳӰnUFJ_OWӰ9X*G 6&9gN ݺb̗A"g%9iW=6yAZ^mRi}AS|ry` n|׏ehcmhl#⅄w̙OD>*xlI.dC|`65iKrrNπ\tiPBL4L)Z*f*SEN!z9OPKCIT;,Woom*|&=+ Q4#YVc؆ݭA cB,U2,n\)CiW(*k12^]=ϞқP*kԎ+ҨzlJ,&0w S@̋y X1f= &V́IC`RA?5 AO?C_| ϧi4X5+v2A]KFg?/q0J8;_h 0s&#<>*x11_v˫etǘή9U6:6IVcx\G To3ՕJ"TG̥\&VFu=4 "1K52S2A8eҘ!ڰ.ڮycIG-j6?M<ہL`5:6c&`|lvfxJcVW9Ũ.X ; ,U@hݟ"}g]Ɂy&6Q͒6( :d#˧Z˝~5"Zۯ²J.rO]Y+h2OB6ttOrz@sqYl]W͚ !f3SFmduQM,BBў˂\}67Q^o6G^SVP%NVj:KQ=rWcGerBExQQ%Rw U-3z1h\4)I&*Ttݜ)R Z%Ն-*g\%eyL}IqqRM1U8+eΉB"`3F 3(ׅ+V9VpvG"lQ}]c}H}gJknދ=a2&j(q}rt&JVlJv$zt: zfoxVf7؋6&=rUjtb_$ɑr!ojm#\S">~kNkK~hG>vCE8qT!{PK[];C&]<$LB "cJF oqʞ. ÎUe̚6V@4}+1wIlw/](e DuEq:[-K)K_>z)R[O h Z='Y˅g/oijW V? j++Jg]EP/Ho.OZl/wTt]ذቂM/ 6vIt\uZŰ DO@LiD%B5e>ԭf/Qʃ Eͩ)|K8N΍~7@YCG"YZr" 1!&*,wx66Hzt0*Nᱯt*wgI)K3nd`;~Fg--ggN-~:P 0&}g/VtgaK3(Qa30ЕG1Vm]Bi]!:{C˂aeVِS^T RE1+&i>NG 'ӂ`J1"o J&.Z"yjҩ3yճ)/nzi|S+ez\` N-;$'$JHJAmFsdt[SԾhLcꬺ`℺ )~_*RcxgRF+T"6d_ihq;̄yoq..ȢDC$`E?avJV\"wPiwT1[>*im=kr++"n*xff}ۙm-rOLJJakbao5 JΫU5y#T&ΖDW̝]"I' ziH`Cww)l3<+!-|4|SE2N%q 0ӑI ]]k?e4F$xԛW+@&-zvc%E^* Nn5lwh6Koknໝ 7"6udr0TX?)ģͫ+[ *ZTl xN&KyzV)U&U`YIeHub]ѤJ_zC\#;]*N& &+CU-^LTs5NL4GUHkb=I\N6g%Ӑ$%%׺N:0vkKZ0ر  9dN)VC~r6+X|ۻRQTYL|ډneHLp>EZl6Y(HUy,SlHD&f:+0"5wXCu Ohqe\ҟ7~KV6YMC_f^A]x8mPPn0IF爃 (opzViR|3%͘ޤjgV |}dYIcv-VVAX kٌ>8tQRR ,]}P=7yTA ,_cCE &/}Qh=SOrRBJz:vCN L.p>hWʎFbJLv<&s UQ$s!0>|XȰ0KS4[w/dD)*q0ݝv$4}ؘ1MRU}4~~󏏺JmJw((UE1R+;)Jt\aFlCi(Bkv`9&!Jd>$tWt{eryE/5tؠb||WbY2µp"O?||Cm[±3`4> *N*lm$ŕ`iX/Q}ǵU#2k1/ftEc9cRѳ̴%Qג\-of->5VEuU’d2iJlvܛUa$fX퀌da/أo') 'UVHuC >&+RpB WTBXDA.fYU WR:L[(H1{5RYtAD%Ƣ,S:Ӭ$c?ZY|bH M6 hx#bIQcm1R (ZģiuYcRz 6ܜ'@QZ2 lɧ~0 n Fh&T0=(I0rrPl="扸#dmoH7xSy %ߓZPLB2ywhdΫwS4evE ^,|<jϥ a;=9s_V_5IԹр5>iO[MpZraòڑ FU@ScRY LM?[XlB}ZQ;A:qGM})1%AP(HД lfF!dS!+i'Rb ms4=7m󰙤ƨc]E7 E)r3I$4@;G uxepZ OS5s\L}zNM"%#r-GjWfWns9+Z*Djٌ_7$4"y"ȋ)*Cң]+aFiuGj. {0x"vpi-Pt) }gASKKb k r*Fvf?Ax<*9:f2X"Itw2ᡬJ#IfZkQ5Dz}q5]ӴȎ:dA“g"H&|dx>Ҧ@ugylh2< iB"!2r{p1z^=$IO c'qLUu?m&`n7% =)`oޞ:H[4)S7_Bv(}y^cI ix9LQU\䙐8ª>E-̧bZj`BEiL fJ4pr3D>j2`p7p!+-E~]eGl|+UbB*YYbd_nGۣl!) 7Ep*J0]@ZIਐpY  '&E0HV0ɆmTP}I k%]Ki3L6Ɠ ^!“Xx>2ÿzgo_n–MNT(ӂ -Ȝ)\ f`(HSy?_S"@Ǘ|i˪Qt@M &"f\kaU8NhXl5=}4dpXH1gx@V5%qP=tC?l'h]Oo9TϢIpBqb-Be䊧6"HyX7r݉' [חĂ,q8v9p$1 pw+ 1S<[ 3A{'$ RknX_N^%W1? vN:9z34. .(?wU`4@Pa2D D {T ȿ*F #o߾9Sȷ=}wL'p j񱯇A< ;.@.?kK⨇J8;}u܇՘5]pfK ĝI?vy) Ù{rp8s)x Φ79?Qgc.pt 띿i7(Ku9A+ϩ.Oޜ'9{\p k|Bs5!';G''ӛ5aa{ٵO_ՂRD ӲvsN1V |3-?6-osEC6gZ?6-bnxIgJ^,:ХzU(zLH)s+ͬsak:Pg*뺋F&NH dž8 wRi,oepmdkk<2qQR펹'i]x+ZO:]qᵽ쪨 _T+t7stŽFĘ϶n{=L.CM;ԥu6y24TU)#Ox4xqR7$a`&`@60h7(1d')(kGAyUl}^re\.pSS/\0kKyh2k~T0m$ӹ?5 L'EgTfVлnqvZxV -^_e R,7ac[v}kQiKGw>@#п^*CtPA؈w:08 LJV0uQ,#4+-ȠAYp`+y#]s+ W?35rAI9AR8fȺwm@I&,k0oä_IOW?|xM.)d%z\fl˘ųϴuo;4H*LY%A/>z#u+ h2 !Y\o3=NVWUeFT1%v0Kx|HƓ #G#mº6sٸbSDzwȧ9pٵcFH GhՙW#2e+Qd(VO-Ψv@ [I#jXFݮAea BeXU*Y5ټ2 @:m9+Js0z8uZ.b`+0_o+^)J|bK{`e=6*ekj`95}ƃM=˚EƚrI7_i[pX>Q;-ʘAW!맺VmCCОVsW-}5 }d~ \`hfI"Sg1f E%սsY,Tj&\O+FQ'9"FWG;>d*P6,-ɗG0& wcV}+LSq"(HQt|EaE4䚩zE/>(,lڸ~{`T<쎆XO)|ͅ~jdip;h.Y/DQ\;w1*_ߔN)`i(>!:kh]÷x,Km)|*1 *w7B`YJZhrꕥd4DjárҒt[ t D:y $SQ,6|@[Ga +]ȵ>)$a7G[mɴ5QJݓr5>:RKdܠ;d-\]"-")i!_BhpǠiT0j),`3Fk"ÁHnYp>Z^̚Hj4ah;_kTij[xL%Si73c(Z\plv:]Eh֚U6Vڍ̱< Ctm.`WpaIF+@T#ĨzF ~c%=q6M\vqqx4`9 q2YQ!oe>፿kvWS{S駦z L1Dq6A ]79>)Gȉ䡱 WJG|hgYF3ON9:d:Pb N3 @# U he}q>: 70Qs2.4=uw&Ѹr٨9*B:@0#eP{ & kK|øoPj,D_0q[DPwejڴq58=oχ$ `\V.6U#;IIN21G8)op|6v2:~z9ٴ\;}z᭴Օsf(50eӹL1Kao8T-I1/!wgD͉ RF2 6",_f.FѲ}2ճpr 0'3?(x> 7lbG|.ő]+ql[stKQ]rnߖ]c:@kl嬬#Z\we1?]927u3gɫINn{p>Hk֐#ijC|s ˭~6e*>y Ǵ\>' XsrQstoiœ'ZF?-́;|w>s*5= >S$$zJVx8*>99N;#1*ſ7{GI}*O*s%n%4d (V3A>]9q fZ>1:z? ~M](> pn G a]l?DgtWN >uv8xzyȇ͢vnedڱ2j~$r2g tinpNww?Qp<álC5ݛ@*Pl)^bAX{k9|> \f`]CK{bCUn~" i.5@/&1SدG_5i#4.E%dؙU5`q<_x/rցPN2 d @Vf]ԙJM|;,# L09s(^M=U eˤiETWbVcGZsQ@fxi*I8uCǐF| '5#2Pٓ Mq dQ 5Yeל k'+u{m# nj+H!e6HTŖ $@2ƀa{Nj2Kr2V$/Q@[Y{?^ȡi_r.7KD-_iJ)* hv$z>DPʧJ.Eil?6m̧WsL᫘xn,ݝ觔7hp3y& An7/=J1h2& u ΂]*cmMz*x%QEivR"9I~(8 'Ey@Q{sl+,:'"'Fw YhۀQȹ‫?Xc_<^K˂t^7Æ"嘴4(rYwf>(F/+=>k%@3,TɗnhL_4*6:ek"bȷ=~䇂Ap7i+ wzB43B* l*(荤^̋gI(B)NҬ~ }yꇢ/BmeC9Tֆ̶eu%EeqJ8ZkYNL``I( R, X B$E)i/8 Q\*p"(B /:BvyBMԈZWJ'JPr-b##"(#zJgDPe#ʆ \ 3r/i˥G-p]˃=~Y񵵨)a f}2]:Vi%?'{o\-0etzQ2#eF&Ix-Yl[AJV$Zv|fj;ٗ)E}q.+( ,/eBz0ͼҴ#;3~(ErVJ[XKA1He8EgY/?PNR:՝Wo8J *+[$ҳ(tWa8“K x%,E9t Ue"&YC[դ%hj!PZ,&Y8~(EχaBY+  `{.\҆/ T ()IҬ7 ,<(k4H E) YEP2;B!1m}vD"|ȃbm}n %֞UzJ s Q8#iPWw]&CWj-aҰ>59K`M`iW,,nYXI{8t]âW.KP#lsFOFFhe "y䂋Br%BGVB]!^Vo2 P^1Էv844;9Je{#R(N0 ^e_YH(J{ s(kP֖"$: >#-h.Xۜk$m=ȧ-̄/SEZ{+zZP8L>X3flg,df%P2mK㌈o.@P5|qY餌YyP].;  [ \faA"3=_OQ,ddz45 BL_TZw*qbRJJ)7BF/)8~(|8LjZ:}1:wEhݓ,2 ,<(}Q,,<(E}ѱ<-38~(E#0gPY'SErųԭGxߋ⳱ڑW0.H~&Vs(s厢6ŨPņeA_<ʝaZ N>K#8r%~Jeg'_l" 7iFMmY4Wx=%`6&(kOv~4q &m=}`wYtbw[]1ʖ+b ٴ4Vs"ܥ=| 6/t.5 J7VNpW!u5}ˏI=qtl=E V\>ӊ5Q-] zÁe* ϣj!`V-dLxs{7~X-S هo^:߈ԧ,@]}w#uZ ID%'T&ओ+-Z:J΂aP)MW#M_'R%W%i[tv1~/(&7fjfؔ84ˆbY~N~UIw9wҨf u .W%„?C=N0+H5~o1[0HSg^g1tI+^7 RW&ۖץZL yE!N.TZIۜPn|&tzbG#T0kȮ8Jf281lT #a.@LĦPFCp|@8% ᜩ$uTv>rF(zR$)h2mt()'TR5^3;^-gˡ} ǃñLZUL96 o,ꝝ"WфRbA3LTC } xf%ךg>r Va킡I't%XKy4!0czHd$ְ$u.G`sF9Ln<2R}HNG]<[?/_6xL?{Ƒ,UjP>mUM)9HIyۍ.EZ FضUYV{mʌ"##"c nD\j Go(=ki*Ѵ ժBa clv_4@T(!.ӔJctr.}j'觍iG]Sv6^[췠]8rhO_9PWC< 0 /nMHlN:\e8q`T#b2V \ GFI8xhpQ`' \pO"k?840K%dRUq ,8r^1W3G f<x_̂C5Q.HY:hD1"`啝rbzr2-0?y[B:FȷAY>'84gRE U|)EPhR eu|k QcczU!P滬{[!P~d._}A?S|ܭL8^5ث '6 '64 ~Ҡ}zjnɀ<5'6}#?jd`X6(s'7qxR/hP9)e `5\EΕ'S䢬œ6RG$)FpD /+K1 rpRkE!2|_:5^f$|*jn \Aֲbpn; S=\]~bpfkWp9v 7_Rpͭw6wt 2pN \AB6(<Qٹ O[ ]{HpkrrRaҾHWfuFȧF z2-e%d!ϓG dW;ս/}K wKx$Z 8'a1GJӨ*LήQlvTo}|a'7}Iu{V{3wN,䎏77_&aP@b47fmn{G2;7 &_:NAW; ԈI7%&78\ݥ8 AڵO}}OY2n|rFjhKRm-ڴ紲/Sm"EV>>n2\h sG.?VR{omnv|Tfr CRr'!}^G+&xspIӗ*ixެ>$(m܆m\}.ǂejSl~pV1UtOG-af.aI^~d%DϺoxG#hڅ Tq/\nph2mTpȓO'0;ރo0vY"򙋯A8ll."l:폛:RSqd=EPn6=vw+ J2Ql}4)!hO qFy\radpM`M}X@ IY}= K_a-Oy r,U.tYSpY^h=jzex -:]$տ&^&OjA߿Ƈd+-pRw:G,6SJ/T ypfX =GV1`{>pIC\FP:KJ+u [1\צB뿥6\("*Ƭ, /ۧ}#Sc&X/@# po':o%1WD}dB|`~!O%BW LW~&WO40e\6ai 01p\jz2"z_>+n79˵_^ܨopIy=/0\^ |)ѕk]$v'4t90V`.H)3~rا2 B!&Iwp¼=GO@ybI$ BD\@e J:Ahm>*w4oD-Zx1;]f(3j\=W$LLe)FA`Zófp ^..kmDIzU sGlTvpu|GC98;0drTXb& `)*`OR|E Z+-rZ ld-}BW#zW-_d`\x rUmڊ`*`oE\xC2p3ȀM&+/^};z 9 vIO% ԷvZbX<8EwWьZYwq P99,!UDWOKA3ݯ>^ݮ;( Wc;S9Q"kdE&уuL)o ǨJQ6ZFcD#(3f2d1_h " >=]Yvɖwwf(C0e\SvӒ{ҳ#:I ls\}E92 zI!)2Bg}KS\Y3  S<U/ !w""M2@D{|@GӜr*\v-8ŃA) IR(ɭsg'BJ?ԂbT1 1b, uLrxt{V>Lzh$Cٛj r8UrkEqtQJUi2(Τ(LJLJ(BnQ `Hd>eX2LW(FrԱJ_EQD/XAc&.$G=bzC0Y1e5F%p!%57GeM4ޓ'b 6X IxEcAAZ~!=ggЖ@ }J轚0T_wӋs$C;M8eIhKxEHer& uRt j1b>U=!eMO*BM"%`t}Xe2͓&y 0N-@FCne̳;L(yZQ[!5zoMOhFlX$!MP-! ^ `*BK>yqyp~y@"3L;aL*ّ8 ^aޔEQ%#`Utz ), nYP^<Ɇߦ>23s3m>(H#AU|`p'g ~TAZYX6n ʅn-(#DCw7zztl֥ѼK:z5y2%Ps N B9㶸\G!~3؇2$&D90Kp>лpA܏R#% xTTʟ˖I LufG(4C;lTe%s}O˫d6뻿nl.'\~e ]D|o!M1ʑhdp<"~SH|'t:Y8lo᝾5U EYNj:&' 퍢a˔z,PQ> xb ?C0 6CD0J5,[d1慻D5pdg1xXO;ҫf'FAd9U 52rL*0A(Sl0c-YM$VFdpmY`#{j%t-k\r4tJ&1jb`sL8UwoӳśkvE[Tf0&C O($~SPeLewμQ?/hP*Iم'4S.=)ZTK;z2^o,~#fQ_2*]B.w^a栗SsT}ܝUͼHAA]_SMeJ 8hiȏ\VطR~# ]?ԭYf,2(&@SȰ#RJfs L*5*H /ldVR i}ښᑾ3L$0sk5b%-+>jVm}*-t_,GhXV{J]n5ps6 eb -Iw!N,&xzl\\ʼnrD.~+Q r[#Tlnբ!"^T!kdB} gϖ2T"K:`4# m8~@1ȄyY..*4Y;IR:ED7v3{tWYsI8%8+kvݣ{@&S\r')x/MHiR_(E`kK=enjEC9H}΁X,,Uw)jKh <tqϋ!>huR<蓂sV%r_"?՝VJ`昢<+jf^{aLt&%eVNԸ5"YWߊ|~| );zMXY>"sdvoHb8t 4Ϳ%k?SFä? 6#ō zo-ݪ0ƾSUan̈́ Z35yNM=fquIN4i;苓,}Ssk!|}nUˮ6έEN~PeF҅Z,Cq$ AQk(E4"u.|y) jdcʃG,h6_rH-0nzKl'Z!Ui9AɌ.H6+`!Ҿֲ=fϭF+9jHU-g$vYYuFܡ%Q\^DQBܥ au>Md0{bD88j>ʶ\fc~_>A#j<̯,2G9‡b}k!K;^XchJuM^Kpuu[RtNF{- ȍ ^{U9Yqź8ـI^ֱQN1(r\Q#vbW]1*ltKWr$/+%0_&bF1Xm%8^y܂F~u<^gjCѬ]!{"(hhRlȗ@ڀ'5 OQ `Ҫ.!=IL"Zbiy:(O*۷Mk@3gB1{p|6tXhC^}i Վ *meB |jjVF!Yhj gOrA6(Y/o[>|0}+W(Pɷ%rڒq7>Rڴ1^CZxxxM315S5yr)ۀҲ5x4:`ȭhٸ}rhIq|N*ö$efc{&g,+vh 5G|IRԁ ,*.Zm7'C@P#`U."ЀB~UȈ{!S,]) [1 ׼ 6Vxv |rv Fb]\F0lHȍNɀe[*YzPtx z7|H+[dž Z*JVk0 ̐P)n4Gpmu4ξ=&jX0eP. 崫8if@[r3B[!yuE*$?N/W'GGPy~džL᷽.,x(ƏyaތވQX0[S8EvM+1cҬ=~LaQ,&ᒘ-c1\u@Rd;F ,`x%;j:{[,b)+ҴuK8:sWeG=lNd;8+I I-XSFH&0VhθNz?*C5)zLX/ ~AK$JRv-@n%ǡ}!1>xVJtuɒiε iz'8`/&O0m^(.)#ڪ}>9lx2RKEsVmAlŠyZWY#%b Z*pK&Uy{J( wZ" aף M 0FO2_\_sN@n Qqg<⤈ ᫈GʛLKY~CP'5]|s+qPͯ$2_=hZ5xRegND,UmG{\9nqFԚNƤONzs-s`-Zޤr>CNY&g[ z d) -R4\s_W'!c(8>2~XVB㄂~YD8;I05sSj<،M:Bٓ-q1 uA4'r6{Ԉmу_gƣۣ ڈ6B7Ic;28kt J^8g,|ڗsАт? ,Z&oZsjwedbԙyPT̗tGe{c_b# ; `o849 pF%qkG<у" # C>Ö^ jA)N³ltҲ%3 'cc |=b/_$2IXin FlC/bqVjܓ3 : I_Lz.͙9,:Fxr.i+%+2+/wC`#S"VR7e9M%'E^FSwVN;)3bW7}tRӱih,Ԕy{wUp(`,,5HA? 2Ȼj'i "\"{63=TڱlBտ:om.LfX$O.۶؈غzvrn qR5 ?HkP,/EG)%Yqa?]\ߝ^+­y/)86\9rIo4Oq:f@ ;M(No؝U"S-{[޺KYeLَ1h u\۔6:5nsg/8՗7ֈtS'5Qzoe*_Oy#(Bw&سK8ijhə|žYvswT6!}yǕ=Ak뫽Qz2 kLb%C$`" ;X/4Os1磈@05=Eۄh"t-"@xyΈ~|:3Tr,3n7>?9Qu&~ОZFkk/^c&~8Pxs\$1wHEsQ 'Q \@NC&U!pk8 gf$HW<3-c6^?P#=EDd< ~rU]86Cy/mAqR{'v9"n@TELHTcg%ֿpsNg-%PjLQӋ/cbT Hu=f1EEz&H֯k130|6xM:AkAvy<R/HFۈ}=؋ugZ [YXsA-k(_˫esJ`=U ]k Z ݹJК&f1idt3,Ȯ~F0.-Jb_ ,yD սXD] k| [lYS؆y4inU;׳yU)2*Y0`.#Li!yU`ԏ%!囋v.Zŷͭ x4IǑ@rvqR#Beh[Hkit̖IyOaױ9|!jEe̹˒oV7vX O['-cMhNZ-1 +`Qf^ bMQPw|/N*JOH_}/K*LMW?S|#͜kAĞSYu2E$,3e ߇v/m/ψ3ցV]]z6ڢ, ^6g2sWqc8C爐'F2`/^8&OضOdh]>2GkN빠[[]_?W՟>WkV86 o4CeE5>,wt@(g4R2cFb,P3|2k`4I`4I" !=zoL7Gs՘Ÿ1T."cԓjUHaۥ{P.$ظЗJ~l`MlʶaeaG\GWm%-uXTnȄ!*z[u|Ҭ[":Tfam6 y:?|< 8\9`B(6G,Tj6oEח\yg+vyƿraT( O)u;I0T4o(hmyZOh^OѦ4X NZqT);Tq%Gz7>>8D8j#˾ 1I=1וi_BODӾ&F\_.NAl"4LvtYzUp)HNWK4i(joxs;o;MϘ(9&*''߰;G uPֲy'vdBM =xAPDՕh뎢ϴˊs%whנpvī'D Ԝۜmwr`|]n.t$h67 c$!g5;^;Xo:$DvCa>Ew(|x!]|.FOV4 w*}͉wz^7&/X S54wA?@;O(bb~Sx &J%'*Ќh'x~@gwQԙқ?8pLCz rJ@ss&kFXD'nF\t$%b3b\GQUSMLvGJzaA VH7~ c¡Q(.,\W1&Tv%d&5s3S@:|UrB-Nԍ.(mEnp =!dRӅ{p{pj4=FT'_ΏZzt)MM6Y F~Q->+4)P8s>ŦHAvVbMnNmfRprCH>j{j9f"һ)Oa#zՐ19 iqXڤN_Ԫ9f#N,Œr(AiCOoKe21kd4u@ "R"4Lwb|tU1E1ID E{ q܅n4m^xwiZt*EľE0k\Gcܕܗ†FL0)$,P@j8$a|"c*-H8bdQ@ UB&XbDcSfEKxU8h1& %0lH(<өLdNW?R8BnlvP>_aFr-^ٷx@ w)9PqAO(J>(I`AsWR/e;-Ϸ5ͅ 0Lեdݒm$cYcm.6| NB9@`JR=)L!TS >}xte284x5`ntOÜ*dqeDv1]3/ױB#}<$ ïР:V3[[2Bl~H%vX>;yO?Շc t]hZ}hw<wh_vc;fI4yybb \*ٌ)ًH$!Z N3~'H Fw5wKŝÙ-ݎKbU.L,s7w"&-]$R!"8l唠Fz}Qw,ʼnϴ{PVQJ4k8 M|l5qW@ @O&U<N8̒uڞ ً;>  Odi<ʙp1ٓ!C'щhBIDyCZ3x{b$${рm8>;`v@y@l_=BbuΙ~MFLT{| 2ƙnW5A3\u-!w s|èT㘡μb Lԑ7b -[_}AK"*D"D]zU-81|0W$A۰ė>m%gFQ Hٜ7Y.38IGN!< ( +i1" ICm40CaWnfe,*24 دvo9ό$pᤗRJc$0dx;o"L%hf4 գ C< 2XTR vj`-;]-zG۔hݣ9>~\Z֓Ɉdqst? aO(%]̈jd ˣwWw~:82In$;sL}ĸO,&9G0 PSDcGsBW6Hlu 2h1GTu,N%c8WEL Ix¯[QO♍jKd$? ΁߭ǘTN: Y8| :ߴj8GTHpFuyH%!(J=^Hol@]%3@\hY`f?N c  m0%pZ9TNBsXSU^a"@׬t+zTfbPh@VeiU4cJ$IIH(:3"fEI*v#-JL7U[f]RE.C  ̇$/7lcaniYs,JI8M)RKTrmEԼ#n1C-//*)Y ѣVˋD(_^36 ~{GCdc2nTk˟W0SiXQmઢ|*ǪĆĚL.Du;X# K't_(+Yxnd&VJ(pn$yBa , Daaϯ|xV|蠡Ug\Pjn @@Q(_[qcVµ0 M2B %,ƶTzDfO"e%J 4VxHbq!Z-#y8MwJ]ed+qmF54(̆¬ /BU.e4Zs֤򩬔LvKliuCU`k6vъKj?m0[@Eq: ^K;$sì|H;n%CbTj1>_j- A%4QRQY CPQΡۀy{Hlbn ĘⰒ^N^'zZ7=W L &d4  SCUSR>S:kWB;]ﵣ@ ¦!1${i&,W4фKL19=΢#V$ueE4SN̈Dz6 4b$ 836b362z5 jun%Jn=9CЫsGOKd Fxb:*'CO?*K]ݐJwD\d|`,A,QvKQxʛ))*P7O$ ,#Ӳ+c/RfL)pOQ{dC*H+_*ٷӒ֓2t(;<9({D[ Bl=e%Z(5PwPݴe(kƢ"hR+׻X,`"3TCM"2->L,A@dv(iIJ/5u G`H;7|R!~)sk?Lܡkv,89$фN> tʳho\WFO ke~ف]l1}R<8]0ؐA#fI`kUl~l|~j4)!m*ۖ~mv rnt3Ã)ixȿ0`$*I"uG o-^U'hvgFՁՑXr*6 ؗ$uY:{t|7lR檩/DtqFh hکm /qvz7mVyԔ&4EM,qff{VV*qΚ5C"T*nO@TA['* {0V]d*6u}oҪ`L\źrdW#vPGtMH,f <>}7][%aj> ƿy-{.f%y u3Z?\2,d&d =MպOEO9Ahwz%op~ 8ȵ6?bl*ku~FL:d0'•]')GctIQ-ib98I D Hd  рeyXX=;s=x~*{*O2w B2j[8B ]ww|{JV%Zy%ZRh:T2H>G^_ym {;T؆_ ΋g( $6 LA1] ڣ3$ɸ9X<^wJXљa~TFMVOuB؃J5SɞJB.ӹtE3!B<80䮃#wYB yV)냊(1s'^prX/ztt2_cNٺy4GsȏPʓ61󾎰mdlfrDx 3ñW%ڈs(qyd =2{%QGrdZqdtvz>Qђ,Ux:V!lQY&,P:tF`\DwU{ Eb-L];"#&0]WYJKׇZ)fS%MDOմV4DX4zYC>u.M8q 8C€߲ڛ C# 휦Ns^NܮR;Kzkl6H~"P݊YCϺ4 JPu!ād6bl^NQH/f EǒeKc1 8?zR*FH~oqXbzvDVN]p˱+T\giާ\G%CJ; )P:>N͹ ;tZ MIoRwdC/5JЀtq0{Ȑ%G8ʆvؖ*xVHj%4:h+CDcf?*7bx̃[tK*[FQNy(; ]˦VQ `QR^R ׏ = W |71`UEauIh;ORG :S'"#"?nHT~rd'шby`*RJƆ1b NJcYY)Y)@t<:@_m^T;p̲0HKiNT"mCUbץ2 S'iLYk+* U{$K2y̶7'̐1XH6ۃF<8D!CQ嬜rU΁eukGv;pZAI4Db9fKQV:Yz(党Rae+"ͯ 'hBAEF*pԛg㌹FJ1S .'Zݝ帱*H-&HeX)7NxFGCR܋  =f)pR LcQ۽u0gø!$zyKR"Ρ h F\uXmwOOf9ykKlNVD=!'K+(< ESEBJBڪ2Ml4'^gtѠ gUv4C% q `^I5lLW{uއ#@;ler%9j;'8H+sE"[E'^7ζ$jRfBoH{ [=oG1.әCM`senX5alLTÊ#=4& vRU%VxL5PgG *̐o#x+#.qG{>bfI]QRi'fE,ifQ:pb;'oސlFֈYaIY\}FAL:lM\HE׬$oVlLuDtl2Dαt4 ,?08udq;xɇօ"~H8C V# 2)|26-x}P215X\F#1V6O5UyR!a 7ZxbI0 Wa1 [pLE89Ɨz(?Lو-X Ik8awOh[am< *Y qq;рyo^&h!îvDGW9 Da) Y\ׯƝ4$j5.) &⎍ٙ3uxsw8f5CSjo`4XwhvPraaQLɹiNH.)f۫5HfaZ5ҋU0ZUvtB!fHpf6熡ĉf$,OTAuhc")r$rbC"b0NY#㄄t-M+2{g lKT{XLw\l_m[,h|D1ezx5ePmnv6z%Zfhlw0 -` z.n0ӳR}2}(ߣ4-SY~Jxs3O M46őO};FlouRVKe/TԶWh)N V-{l( kecg$XOLNUCUUI)T7\}htX$PSOz%á[nQsXsuH˪咺~DME.KN]<5W4Ip(2n(8IaDKi^:Zq Fet0\̶m+yOw`J6 :#^r2kni777j7[]vjolZ6봶4?wG|Z+NGڟ6Fr[Z{ N/7ӑS&) bЋ_,NF?u }VyB`!gQ< .v~e ާ a 'Pȹm'6ꖞD>ԯ:"?LkHWlf欑Ap3AwG%gQyĽ"zoj '̳J}`!BV=Û.LB,PPjbIxc-Ue_v̗wNBR*>V翬4k;cҙk)%Jl;;1/Y nrmޜ-Oٯvfs|󤡉y"&YcNK.Ϗ IE i(T[NQHTWTiMIDdpA&d]㗔]WHeBۆQ|9S̤m- &jTu>sEH-i"􂬝wUΓuFOAe6qBHqұcl^lL EUAbd9Cdx r"r%>LG4c1 O|Ce`G9XBsi57# J?686$$Ϥ}(BCg/!ciQǩ4Sծ(ǼTU@c0NɊ9u(S?C\Gfkg/8=L[\^Жxoqh2Ѽ.77wGwkųФW]GVCraUu!14$+In:ƍ㤎&1~PsR&$01nlXbۇd" ! ~ȧ-K";˜ǐ#_G邵_!>9 sΙ0-qiG`;Honi%09P7 5∨\2Wcc![̒{#i`369)@ pQF)-f uؼ,0.@T)Bp#j9L0lJ2qMyS@Tt@-,:i4 -"y$M5nsIkC.y+y7&R8moקթf3-FĻ3Z,68u06ҭ!y:X̍•|yo5q'53)ik/lNÌq@ ty60tZM&TY*h:_ıWd;-)Fu@wu`yf9c՝hB8?=see-ltlͅs_-Z3$51j֍4R][wFv6Znl{8xw鹮ڮ}1m|vJRIlzk Zw>KhU̢~,k8|*)Dt{m)To?C9G+sZ>Fz䥡&'ݬK%}xP$k9!6V0L^s0|Tj4p|:n-,$ŹN!VLYl\kTX*||jr;G@^#k'gޙpetzrHHY*p25LDĶX IAF 0f)ێU&,_d)0kDʶ 7ZG׌etY=>JDq4\FnTTQʱ+ oLJk%P\d `bp߉JPnE[^}pfH'\{Tï~_z'}+=oS9GZLy/Z˪^JG/gϢ$(H|Y8ݪ۪&ehZ`__|?#y/DI&X6!0Oa3s,r/Jw4 /Rԅj  Ð ( Ous29ٟ3Jȁ)Du`"7Ax)'ER# .n, `jrywʺ*ӌ*%zf>?2 d $wm#6iy7nƫ!gJ@Y  0b"EŐ<xn"l5D1!œ>]δ-6݃r_l`C ^8$ $ ʒHwƑ=&VL>&]\k+h#k&w+Vb폷zQsB!vҳ\4DPPjtX nu,`MWDvMV \_/sa]4wL8Ft@Wgf4}@$V):%|TʲՀ1sEJ< S-}PfoJA 5ʊ/.o`ɍrEwN2SŀWэҬoքވNj.ϙJkBvClqvu ޻~9ys9޸)S񍿮H6icׇ (oO5o4YhH>po E o8EbaV*PRm|zo3[kFVbnYi <ʹ tէH jҍ<*#-6d/x,QlEHC(˞o'{qgQV$4ͭr%v <,x^V)HyeLBeȷ jDoƛ6c3Ik`IiϤX^pblIj*~9S,X/8Lwn~%?c e,C${!?4d]) "$-qԟgr<7_~@+X_`3z8e ] A+o}|ѡs$斊1f;>OX=<&Yl0 Fß9?S x !xƏ8q5LjVn4Ϻ0tDXX*VUZ59D)5 *Fj*_mY0z\bIrpEZ&Y R3P&H# M?rixj~8AJAxBЬPDTXZ^+βr[+ ɪF.,ݨWNo.bAW:SqxϯObVW9Fl\sc,)4e^8N(W8V!u4J<8/U$F@TIn:⇅o>:ƺ1d :Cσ2RSeɳ?O$ٟO^UOzHA`q>[̓n-kZqa5Զw|XHOc( QEYtVV< ^Jќ0 }'m%FS lHBq.'*D+_0iN=CE94Aqcľ`IZ#/\uլhe2ysL@+m`;\JOS5x9C?NL-G|Xxj2'q>IBmɹ)Zg 7&헉eL(̔g㕡0瞁X 8m<3b+B !YQ R`A!4!؉ӳޝ;3T+l6q0qǔ.=ɢX]ّlcV%$({>T-6ȃ E-65wVXzS΅bh!a9=<<5.ݫD)$Fj=`/85^=8`MږH6xQbfpSX*WaC!4)Ur02zMNp3GvVND{̬6}d.UVT5r1Y)E6[+!sxdskJc[eu;B/6}lvH{ ͭ! F ʞ2r0E o}4 oj \<%VӋF5JK6-[1;oLcLE0#K .,upֲiv -:~DZ3Y (InE]-yt]ahUgO0~./%sBHkbεyZE) GR؅wVtv Ɗ\!Ë!ӑax:jp] $@VGj5Ql'²^ۃ#-ÔH4(r$ 1aH@S1NتZ  TpPyA" 04|uLlJE(Qq-G7wx^X}#Tbq02di8t WKprGcԏrz&$DC3AqPZ&hvrXj1*l6tTY'h>3)*?T! h)7}ebE}_nHH! AS-)w+9馷;/'/4NlXCyvr̈́>Fn5c>-+:?wBشVJiաh`/}M('B0(x1yU`$SAHkPRmL i/{H)<`r;<&hVǯJ%xT+#s {$ 4W(1sn^ />xKSB,e Z-'rSLw\\ ,KOe+ \%s%%^2y5WeHꋇw/|au=] 'EhR,0DىHlHV/A HQJy׳;Ţ0e~|!_5`ߤSTH}E|-;N־/"nv~qy1Xn9('=66 ~~f`_HrgOyO'[,׿$$RV#KxWufbiUȱv\de<0'i (`Flv;N4 7nu6vvz7Vwݼ4Nx괛CKgh>vHt8Q6Zf-*1;!r`)'t7.6.߼9i0@hvw h5e*^ë}Kۯ79}9C9 ÜF0V.yv~;e#jNZj;;˼cM_=E̻B y I@&ڻT~E0v @*ͧT*mT~%,%ae p ks 끁4i=00 ò-cXLpKX=}^ƢK(ط d5:ǪKpһAE2G2%GL&]{!Ful3ި_<*9Uz8%d4oS'^/Jޡ4Q~Y4P;C-ԯB'뛾0*&K`$QVY0BRګh[I BJV9*ګ7ak_CXDxJX)IfEW9C`Q} Y1,f 毙[8"`-F$((('5 PA EqTϠ~+ ;ᳬ8aD8b Xq_˃fy~)SÇ?q^RK)A/_MO#( (^ r= PU_OFʸ8WT^n6;SY'Tonm3ܸ8!+:c'3r &IP0yiSˆ'<O/^D](e۠rjZp382|)7G\`g$eeI9RB(Oxq=omd}~(n_;s9k)woTEjy+x.c/KF&WZώ 9]8wueaCg<^} "QmS_J\ .?80 /kBp6zN#( =ݳ0wlvD Z5Nw"vf1n e9J)||J-{~]|A^O븱'cڇk*?5=ghQ I.м[Q'irkjbXyx{ߢKMN(+ v-^-+^\6VO. vj]Zɠ^Ɔ sgx z P":r/|TG%yťapwv`j=Ѡ}@[rC(wV @vv̮]? ;\qAEbt>}[~$A.zW.{fK M_ ޽ֺ}3q xdvkGi/(kP+ =[FO8#*m?Q!a{~cE Aai V*Cyq膏;,l<A#z uMƗ{ΣP>kSkOYg=Tٖk]l ٖ"B͊P UVҾnG83^hPG+ 3&D;f5GJkM-:J΂̾2¤만Y=%9*x3Ԟ{NEKPBV:sJ.=5ÙvƳU6\5mNZCX3ɔ]BSi&o憮8"r,Igb7 WT/6@B>*hCkzRQ3Xԭy".to$Pb a U%h_+VKia~~/NߝLF٢A+ xH`C3{qb::v)^~B+P9 J畢$>? N~CH}(u*~iagNhWr'q7pn\{U( g)!坰Lʼnf)qE}4虍ؕagK8=l0 :6_m龶$YXZ;xu5rBUǜܶx&RT} Sߪɽamsg3cY8,RVU9" ԋ/kgGW  F ]d" 8bGh>VG`UPRB>4v?c+-bYrINaJz(ayqPm~a\)0bSzI,g,Qؘohbeg-$t9Z;I8Dxϛ 4f^]{2X5h{1yo)#ː{oƓ.zVA\Yk_?vKWż/柿 vsw:fKow|q݂z.1Kڢzc^Z2W՗q&V7:EMа)s_οPڟ*GxNgD$bQNg ib>O3ͼ=2Jtk_H3Tal[v׊ e@8A&t ގo*e͛ "\ 0 Oid@`8+4Iiғ%S{Qmɕ`> @ x t//J4BM ؑTGE 0ztsSHn=ۓe>Wɕr%Y30>@0X(0w"Kc2$/sqS>0|Z@_ؠh XjP&j.Hnir̟*hbخ8WG?6!x~bex!/vM?]>,\hwS✰'g>ni ьʝTKGs\jQ17 E}ȻnPq7`{$P6onnL9, @mоAq0l)nK)6SNu}#֊^s>US2N[aN?yLkb~yQ#l\T԰d:aGЋV\wPA*CPFɘ6e s̙=[s51kh|7~x3R2H:0!FAʂ|5nnvy}uiFuw6p f3lzk -K1cwF(}gSG V5;i\^_aԹnvwfw9܌vakv[V« :g +( d$idTwZۃNt!nf;^v[uؾnommw-3^ȅ{LXn4hnvpkxvv:nv7[N{{6p=j ZObYRvz((bN[ g[ڙL\hLa#j5;nȝ.pe7:d@LS#"rAko}!A4O=2kʍHw˅ȁ`$OG^͸3 t%>n%ϞkY]T\Բ$~n1kGݑ;sVta׀CK"k-B:0U4Nj" A ETFB Av RԗltX%"T8^BYeF3My8|Zi˩V%ibQ|;Rqg6Z|d9UO( g˜=I!f|qDed:k=;L㠲q~prMo#T%NJ`|lp ݄JCScnBW#S.S;M¾=5_ H g_ΏvUzkųgֻh|Ao?(~{]}7dW78wX}+I tO@a^7 v}g~8{'gINE4yY:M,'4 kPұ)g2ϭȒHIC}%H|<'sэ@ak<3:^ǡ։^Ego/1B%x<->ݠԯώZ ~>d^ 3+0|`m@G{ D&pRWQHW:d1ub֨cȮ72:뷓mיUfTz˭똇yzۭ‡Q=K}.VoڞWĊ, 0#vY VXKMgoæ=ar 9nIQP@nWэ;h";1֯vM b8*Vܔ[^1yumwT*vNT?'ZS4 c5CTq gG~ [[MgmfZg)3κ/ B"'KP?|s?w~og_wzo8}@Vjy81c4ˑ &a<);qNtqNt͓bF2cX:d2$eO%)yqji>[?'VgY` f?VY6aBik1/=2?-F hWl.qԧQPɮmuJ$_@`|wyp79~X2 vmӣKӬqNSSE]L 5!z?9- 5;}8üM*+$t SFb?-JP]7sVSwF.=2(:F̋GLGϣ9>9ܯ;J@ aw sb e)TT5MʊNc@oڊlT{= ޔ*I [!29}9!t: (H)=$G;mZۭ&XHJ:<iPiFrE |`5G(ri>ܳ2  Et\`| "@>6Cp9}( @ׂ !R 'rADD^((|D:wAhJu Uy/)<׀pظk<< &NneoH#(짎!4NrMG@VodK?x-zlr_|r=jU8 1xxCh&Mxvz~?ζAx%1'cZ.n&IH$a:za=!hmֿ-"s7D@*e\n043r\`T  B8B#! %^Ĕ\$f4X4 DNPk$@o?U?7wͨIob ? }_0AAA$ie >S7b-cSEo. \h)Zή4U! ޜDkuU>*g9u[ hxZf'g.GVS̀x@v ȎŇ$@DȖ  dGv.ȶdz@v,h[ɀAJ/:;\rR$|b~O qX,0.p;p; >mמ9ׇz ;h1t1]:Gȑ :PTI m.]: 5>:8qx=tɁn7 hnQX\1rOAuk euq y-ׂzبo{GւoOOy ^'5uRfaT=L{FL8F裣aV<,TQ%y aMAruX֞$|j:t!j\HuFx[9ah UR14C;фV@]YKUA.T] PZ-)3Z{mHWQ4QA=;#HF]K$,Gl/EL'aW[YYmZLYG ƕkVac%W6R@c:,&]rkkn#m<V~]*<8[1P 2P4>rDX%5"\^>{}TѼ\AYwVIaU;e!TgxI$A3\s0>V~T*:^ ANa 6:B*ZIla/` H]|MG$[e-_ ʕ >>rG,xKM2">ZQDɼ|Fްr ȋ6s^t,Xhr`@_v;m"TKU}?r{Z_DRĺ[NTkNEwt4&shhΩ-16[G}']ϝV73wwĝrӧnQ݆7.WZ(o4F*L3 ˼[ll2 յk)f6Śfk7-$ZqmvA϶eX v)vvu8IҟN˻滭`lZ < Bcq HkQuѐOoLoQA t'~$;j<46]$ aUu1"!}{[ 6jM&P`FR}3U;]O|4jC5Ukhw m7޶3hZfŧ+@oolZ}kacˬB;v ՊSvjY"Gnm+O-$>@Zg`%HWVdzAEn-KL,[!2&&s&Z[9*5kI|6Fq&xS& Oa:Qޢe3?ŠF)ղ$;)ePPdlM3˃|ʭM Z/fyQ=I^m!w9fM-h/N=qpHE?%sNRqXPmZv2fnJ٢MgF+S݆50hSW~.45 <%A:a3F(]ﺐ:V9VӠҕv!YΈH̸6 }͵MˁԱ Mz7Yp QRڶ5Fl&y Waprv":trb\ +A ,ܡE;)>`'&,pЙO ̛e2>k&<f%vAB!a]7F>WWk~EL557}o;;]~{jܹACXz3Kw+]4Kw.]fݚ=j..~ĿA. f7V ؃fLO"_F0vz ;-oG0;;ma{sۑο`~LInmM{oM͕V8 ϡpAێ8*`CVړ5z%0b0] @PWmtTm b@[. 4-\@kl^rYt2IDM张y* 64uxFkOb9ӣKd6Y[fk[x !YfCd̂oxXU ƎA$3 bD5,^ݯ\ǥDvuI6])FD'5K-Y6ino6bV^)vuM֮Qπ3kCBq*j.Vk>0{S@>#+ʴ˴]j_>#I !!`A=%}#!]ñydqgn>^(oceL֬褍"#1ݭvTF䃁ek k nY;Sh񡧇'V]_%,\VZV^VYV]VkWkPi*@e'Dܽ;Q˟zjXkDO:<%|!+xυBdj&1y8!SQjDhҿ|{)ʞQF_^?XPt "FdBx z< :*]HD'[?sFK_JBӫ;U}4a=94 +Z9>89K@4cF:[ E+CA`ȄFn4V,K]Rwfx:=7dc"Wx[vg|N_eZ^yog豈s(mΧ YuZv;dŶa+NxfZZ6WPiZ}=wwvkCA4iw2i|7١V- 6p+U3A[srxn1?-"T\?6PCgY~mW=h7vϚ&dLvaPY_mD7 vonsM2s<yke-m:U18ӕ9'M* ڛ94%s0Ͷ3NMvGxl?8o0_ x䤁iIo͖륁C9/Xy|̹8bᷗ0wM<cvIvW (ibD3_PA4D=I.\ 7AAqnCI( Jٹmuuhlw(E7jC_η:T 4$.p+?\+.pm.vc]o@蟅34zu=K/i*ZiB?J_XBQ7) ;T-ݶ*Ѝ~g=1Paˌr|+" :t)芁]og?muG)Y3r]^< J -`Ąn¿ӲoΨvk̕:>9;x<-([y<--KX |WG9k'WpEme1 c|%6tr+KlVɭ,vs[M <|oiYfט|GeW0_҈jڮ)NNkmoov@YC ;FVsE%>A5sZ4om Vlp)L >A[ͭ%Vi>ûz4{TZ.;l*6D%rӚUxX7Wo[>q[7ev0KOhtg~A66V=[OSk]tD7g4|?IODwS;>6 v(.Ӂed;ɲc%S=?eݸhU48MYLufw*@WvR]lZyJ\^Pw[)֗e/mK}N %r nW70M=f/Me+5jY`mKKka7:=rAhZ*mRd@7*)VwI}'gy ~6ZCÇ2ٲvó7K02KרZ%h7l{9Of '%RΈzkg6_;%|syѣdOuej?仱L)!̆ XC:ֿzpׂV-wkAnՂZ?ZMxЅՆ vb ֟C'Nxo(۳7Q}DS >M4fߛl)fQbL`,(]noa{40O5}!IJnm!Æ88;49m+6..Nzs;WN>>XK];v@@i֯YU@ p{E4y`)`:`)v7v.G&hPfRj!Gw!@Fkcܺ;yu/UX֞ i~PImZ@ѐe3[{eKngl_Bƃ$\%ߠuy>! 8+Dk=0~n9Wy%{l/g-~r ܝΪpg EUw9`.~bL9\!;n4[u0S <ZC;Vgƍ_ b(Xw*|м|2֦9P!NÐl)jeAKNSs s)sZDM&rj1 wk OϞ CGP&ª< wsEy`r#,'Z%Y 9S06x:1Sɭ7Vzjidr>h|*f=0l༏g a8Pjg8J0AǼm?ȇ uLX3p/\,2i:⛊bpxw41-f ؃0 \PP@!jD-F' h{Q=;~;7mR Вq#s6y Hϖ]!Wb@1rs ;]X]t&kj '*qs2նWDwV[k1{M(]wP=wWoc~1J8JSo sE0|G0 jӥ5 ̌o1?۟;;,qkES Fې7t~ 5OPւWo"K,K>*Bl`]%Z@f.\Y\(CJqm8ߝzNE/_\.0*+\)22a t悡,@ zޟQ8hھXJ`h, <;$ЉCdFK0fپu2JR| c{UA t8Fvc< N޽yC_,q|i(W*4 +i@^Hߠ,ĒjuU 7:n ]8{KhoO6bݔŦWW/%"Fk_jxe䅒ٌkFٙ@w =/7{[$#EV-``Q4'HA7 a\ׇ́տV bb]xa11'6אfօ$ D| wca\?}sT: ~VGh~q?q#RCu#kK4̶5d1g[d , ķ L#~rc;AM2N :Ḥ“Bɘ^afp>`Ẃ UI<2@nB5O>±!畂q';?)J f_?5k4 .N*cwSQQfsYQDX:}p|m *,E,TW@z:ӆ`zt A(9ou <@X sm7p!n;u lt4ӝ o`9% ۿׯۿׯosܝ~e2 [$Z|OMB:}pm=o];xS-vA xA. n;3<*p9adH;NNJh`uлoY|O"\8<(Rw7dn0ػ.C`ac!?&tljjo{ Y}x.l eHPxk3^^> Y(? <]mOOx!:Zs=+K{EYȣGK;QoNvw303uI88(~~`f.gvw]W]]`z%y=RL Zw3ThЫ\>R^H*]D* {%e_Td{o7go~ju )WL]}2GzEȐfRzzaTVa0؆A,\%m< /zsiz Oǝy3 pZoj>o-K=G G/5UY BͣYPtBQLՕsZ=ly@4tπ^ݷyC~{K>'I@m\42@ww wg.9* *:2;|$dnݢ;y栨Î9i7Sh9Uhda.7g!|D^˶l=@?B̹w!n,͠ t`Yb+蕴J3wȀ,iSP YSPN tg Ri7 ٯ(A.Rٌg^Po{&i\rdC,fw f͆XζEPw޽Eƽ;-C^:RH^/k<'2TNi6UT[V>0m!paHRLWmKM^f]gQ!NuM;nϖwR]L@睽༽t88ǩ;{9 9TVw;ou-pux|v3 +B8zoV_AaJMɮR# PToބh!ugP(6*Z |ᜆ,N* weWraa"+ftѧk{{ luOp%faY!e) fӇ[ 9A/hz:dws;B[G~X7W/ʄ a%ҥ '7m88N9Nz[쥮)|E$1 ; T;o|a S {a ~n%wezq<rX`4doc4h~My1znSvF7bjVzc HKEџ@x8g>9sD2i.B7=pZ8v ;6L  pC.0xӘ&5C j[ 6mm [}1UMW(WwBRsi<-ېG~T-lp2xg}/&u]%ЬA"Y`)l/= vA}#R;ABw`/#KYKނd~jN ﯗ o.޼yup] 3?ŬKdƱuۛ~sYf'O==;}szy|py|zuҪ!;YG.g%;qe+Yˀp3ˁ9QycΔ,uef$vfF~e31r3|GV;>(GL<؝CA*mk7Ow.qi.SSGMt7f׏'.rN轫t8Yli;wN^*q _]U{;;o?fa/?YeDYSϺgdʃY/|^&ۋ=S_=|Sd?5ۿ7mTտ8nM@pP WsJ6:yXXSJ]fg* uUry=1QuK*m~^߶7y5Vb*墳 ;bNu{qdP>:'p J$tozjIKԧHH@`* K#YMT- TuQZkx8eOM|PAe>G+1eitv3D-kAh;>Kr@ÿT'Bz1-it1Xtӓ28Kf2bL6ۺ<;io=˥ߣc}=G?];X >v=1oW){{/`A $b]v#O݅-}'3iLT\$o.Γ]1|`~]5b:ocr7Cdꎧtjʖ @ov7j:yav {jbkxȣLn0ogWWdV $v/1zX48ɪ^ETC,] f~#ߎs+wE (ҏ0[-?5'o,&ףc6Z ~Ll:r@*-' kgm-<"uCP*,QUOXa2*¦ʚ-ŻۚPEE'顛NZD̲5M"lf{xnqg>u~4 `6~ Lߠam p>&|ݣ^yio%z,cUCX@\PR"~mX7lM "υ%8!┭#åt )4rVr,KWϟTY0_Ŷ(P+z+ r#]﨑8kJb4޶)ˢ*x֠n<_bә{ˋ:+t|6շF*Ѝ`n2baͶQ>ԣs_Y.+;Em4pg?b cu /Dp׿^ioИ:.IMp RL _,C{0ҼU@{n`߯? Z,`0VF1܂{U흁Rն2ߖ?'c[?a&nb[J~SF4Cnu Qnኣ,K.S'`iȮ*\l@hG,EnAEB{ÈGIW~Ȯyo,hX_fJG/T1 1Ar P37O>X8d{R> 'P6Db,n !dw~Iz?):Pj1najME_Euk/!ӫbV{}[[}; Ȩ[)z +o8X cC]f X>Gw -[#ki O5:hǧH8k&t7@%BwATbg -CĞ86ZfR ~,9Lc)^mڥ۶"]ֿ[枽ܭP[g F1G*:n(u wg*crlv: &Ov34Xj4QU*&0~`8#پ-M,Lڷ}Ei{H3| 6՚f?짎}J2hAivy 2TR2uGX@m, *ar]j €OK%n6ⲗlGM%վ7dBĽ)joW0A_>J4s-ɔ9}QG*M/^t8)ky݇ sSukI]*ƳU!Q4P* n``:slʓ*d4hAWRRGCv͘ADnħ)WrțOZ@r*y L\­{+`: vV9HM 68Rq4]yP4M  {6eN}&6e9I&g\ QYh䤅JOE,Ҭg +' 84AOk2NҪ*etQU#^GWsLX7*N^AFTD Ɲ`iS6f˫c^ =nsͮoFW7zdVe'iŁO3??l)h`!ZHr9N |2 $pI6Xt}r/Io&`L_rzkBN Wβ#)]0-!9bFV&S9ڡTU@" %ll \ LF]{]d$Έ}VTE֭ȋƺp>(~U!M_ : sSNM`7W0el&S+X; y-t #DEXm IjV;SHZLU4 щ~ ^X&UZǙne2G0`ptaSlSv~6 "d2u܃FGWҌӟ4QnDŠ,wqy~߀I7Y :+Sr]} CX-q͉߮;kC] =t)XnyY&^SJv^wfB`8C nfs@! hO.aa Wˌ8|jɉsS ]e> ({2& կ! gQ ֎fR1Ų}4: be>y Gg.&uz^kolkmoo4adp"t@Ȯ6>29XY \EA&9N4I9B@0nj&= z]pÇ" q Ai{E$p~Erڨ[j$/Lʦ8ꛕk S`I>h颵x١&4zfI+\NdzqIx@:bRmK%.唥L&Ntk ԉ !N?ea526[A0fM?8!,rc-!(!v![])ZײV!nF/o;<b#*7f ڤƑ@@z˒Jȵ밴ԕM,GߣCl^PSr/Xԥ X\pƗ:".(&ݡ]-?R$`|P$0 ȹx Wgũ$q\nJrPDFtHV9.qĄcn ǛjV,fffk=%#=zt*J${^Eý36q%hԤJ5H bsۧ\sF7SyAt<|C9KZ4уS6'qDC1K]N^DE2|Kk*4%]͠aY_ZU.JN&?^D35)eCqW6N/YS{ɔV ɱW*L%̇SZ|B,zԅMx_:&.srtT0%VoxSdsWH>ؤTc"6=\DzneGrt|3+NXVg/3[p[cyc㜱7ӱ]Su%WR~Yla) xFNpFQ0%D75$l*:PѳeyS5\@̇3Ui5{ /Y5τǤƫBJOʳuDK";pMP S@JZ'6n ߂÷jn8YyVus)(V'K%y%\`}>rx˱ʦ.ۢgHWa#k9+>N[X-ŽM?\7V>6qnfMxZJײ_RO}݌83yv̥KxƾKxXop2,,+DGªjT2xU-i tz!E&JTkk9j1#B_X ءN0I-܆z}:eCՁo_lN{}Z`!q7˱@r+4y1pc#ErkcWH.6" .ĝ`\6DDyT?ىGG.9gc5D};c\ʟwWͱszB#Wo) ][2÷G#{oi¿CSP#O? Uz&_OѮ&H_'{Z43\S%neH~23V]td@ q*1d9jG;nܧ1*̛t)Ae?r3w{L\{^z1a vp.T=1#\[ kƮPMEv51Ht?O#Y*zn@Ȳ#Ӷ#f$ҲCUY nj 2#ȈDT ti!G % rWK_lm#:+D)Ne02a˲߀PWIrXhTq;Jn~ 5Vwը: +H5FC I؝J!'˽dϚn2;A$᧠ UH';9j2|X|c_&jE=;v<F4õϲG]LpW]}x~ ~~|_zXCyc,O/続T Lz9?jmd4>OկP&Impr4 h#X| = $|zƦ"wP.ūiꬊY]?{;@Fյk VT5r}UISDEGؙyOcEB˪G];PV}QrTZ=,CNX d^g2FS"72[:&@P[`hMe6 b`h<2 1 i>۪NHp0Pq\S%^ [4P=:`WEcWj`/ bdb£}0YwvtJ9B7ps)V} Vkic1=81=MXCI]㩀m`fk+\~Zq*U&m6o}e->}jK{Z>[uf{wq:vw =ͳW űWy}jE%=͞fjьc@z*OeɣY,6ɒ~7 +ep #S)iu][QXJZ2U%ۦv^E"iBpse]G=\̍vSCU~Y̍-ӪgߊMQY,#[" &O)ݙR&m61Bv|TUBI >Jk>{jWK- nX,1dݳ`+o:G(y(uQE)SZRS>;4Nv/p a+*e@syzsd&D:uU}: d_";!܆mg[Ӳa@ժ#,SV\+?!Z4?bՈq;駌UeoCx8ؔߔ0f~eW?x?jz@)33"a "Tr8~#4cʌFOTʩJ:#ߵNoQt!Θfpr!_&a +ΘZx lP=@23!7lػWD,qn» zoja6>P?0_ɬ35 VY!83rIxPnȱOtA8-~g盢C7#&@A|/5\,ӛ|HP`-1,n#97nS¾Ԅ޵R$d~XoX\VOľTB LVPqp>}m>U0SГӋߛكV4uV+"פ*sXp9MG5-FމzHdn,ϐxg `y7Twt.W+[mU*?o݆e:6LO pe@R\=Y%4C,CJm2(ԟu>\RO|]J25]>'ԊJ0nUZ'k%Zx_D0ebb H$IM<ӈJLVP^~z#OCYAr&Ƶ#&,*Α nj`3Ҥd&aIvʨRvѴ\ppDsve LQe-t{:A u4齲t爄7V_;WF뤳.Ao|qA˅.@xn ҩ-ƣQbAS$)p|NHԾ%1lS 4)cxv6e6Q9as ] 3Řb$1y:A8yd $'p HL1‥I8 oFc0WIv3m \'OEݹ܉ZaZ~ߜ䱶x[J7G zu畾TW34f:%lҞ@CGt$Va/FCe(^ʠS%RPoPߎ4h%\G &]/>h:Lk>h>b&8'\ioN3[WlDK0Ӊ$ {ey˅Fc96+ ԝTިP*PsyBI#-Ox7m-1 ]Qwu/BٟѲH"9x"Z^8S`С 3'o3 _A}j2F+cq `7 A$wS<6L@\-wQ'c1 (.d3 D cOΘpEDx . WV|5lMB }J$#NVӌW;^xJϾ^|AǵWg%{l(`{dƾh[⽈.1J%V;;E?{ CCe.|$r*a*Knt;&@$'%i緄NFnS-o ެ0yզ4_? Ʃ9)B=0>R쌥{SⓈq}K0xdlaXMzhivc OziycOo<>[𫻮+#Stx1hc\`B,@A,WEr9m!K%ϲ԰7%Fw s;YP)MP(PDg :yxr ?rIo*mhqZU{yk.BY!|bvFIG2l[5&>nxέ)kyK=v;(`'D`9hSJeAqfs:{sKR?׍-sYwzWZE Y75"ʐ'1^4q^V7)KO37Ode̿3,_> g"rt Ƅ47r&4Z _ڲ1Pp%}2khӻ|';D5v ï)8h4٣l>OΎttRԪ4K/-H.o kk2Dw^]vL4^L.)\9 6 ( T}+*H (5P6ΛJȲFdF!](.47` eGZwENT#HIcS+[Kܴ#gyqJ}aYF}ieT~Z GK$Ҹo%qtm׸$!<az|ȥ)Ld[Oͪ[I_Gn6Q'&4Ұa[͚0un-NC^qlQX"x|og04] 3E}yi*F}Ӳ'T 6 .T1Dn|լ8:X'5cLEq1JC죐gB bNX&J}zXΈeU]]{WKtӇgZ*(k蹄0* `+Xv~60^7=]tU_0aeMocaIebޣT }+X_O jۺ{aM!ױ $,U.y'޾j[:YTlHyzFͥZ<mp6maܸ^2([g̵owl`'e _(8$6K@&mĞ(hT%RN3 ^YN(IMq| JQk5 3 _fC[E念Vt 8泊Eq=d.Rw(itNƙN4Rθ= g8+ U^ܘG[(ռ96]\iljߤv~p~PPL'r\&=ʎxǺSSVgI{ 3=!#DRfH2Znl&^@X"N#,ˈQqJ\S"`uHT nl#X u tLC=BܚT! [rU:u|Ԩ<5&!0/+p6] J"130>dߪٕ1"a$kl Z 2/2exuACH%%W P2 #1͚Di۶Rܳ# 0$\v&aR;v܎cCv9;ݔYcwe:4;IG\NfͨYN3|yq㓣SRd|4b8Bp$Dو@ wwe5KX$Gv~>ZRg=J ?gd3!YfvJ8$H\kۛYGD/&k ~7Lǰr< yZQ!E}Fg}uulLA\n;^@eWKB.O;La)Q!u zޝE pVW)"&3&EX:N7ZH4-2"dz"rV JŠ"?tJx$ፈvSX%۸ 3IԎn]%I?Tr :DK3KV'ũÁjP.x5k8N0. GC"YJdRX`b\2ފyS~QÛ&ǻ鐛#/ӆ&R?n_^BvV]o=+,F $[HPɽη.Z.Ot.uMt Agi\H($֖|G p,~ ĵ&a Y_6|`x8,? Q C:Qp1" j><y!(`(AbP[?h|&fq&Dg,YExp$N 3M.zH\HL6*m3D# UN8XD!{„zʏh"kkBG=/h?e.Fᮈepd"ci /~0[PhWUL$a9psY$TU裭ۚW`xOCaY" [iW{X?@ +B@ qdÎ&WZU9g\cYPG9r{QS}_;A8Vv<*G=U(0Dnѭ]}}դ!cCkPQXVD`]?e; n9ULo s Nxd8RC4( QPE=@[+>z?a7d.?L5Q!I Z cy-|u6U˕/+dbPc<ěoH[*~!$nGO;Y?"qd]Vg,Z\>?;O˻'x?'VtV$$W ȬiOO kje)P4_nnPЂfɝ:P@-3]#.UZ<$8] י`DDiS4OH :uⰫ["k݆1'u*5*>+o_r+: \6FѴDQ^).)չT .;t ,"A-hye &@2#}#;@Cu_-N^*l0:j^If& E%je7LY*!PBumC:aޙ~ap=CӠ~~\h6߼/?.Vyh6MA_Bc SN?V܅T'{Eɼի<u]_]蹶r'Pr?&0>O+& #t@;F?FXfg Y s? _a~QbjE5DK}pX6TZRcFnKf1u%:D2p4H%  vo#Fc7!}(םsxL* 'ocN;^zVyӫTD#S}լ.0k.R3G+glī ]$d{b*DNZu ΛdA֟uf Y_ý#]>>r]gmm#y%sdL"7r[8+E`xzWu,goRԋ`7IY{H'SV[bO_ƦeЋd 8oTQ{QPI?֫T-(hF4獺:6ERE}RZ 7Mhŷ;~U.~) <3-^Jj(m=(e,[E"[g%zJ.6',=;j'ydk gxE1kYg͞ևIb6x;~Z~gPl-& m u-#ytNOVymSmunur=]x4eG廸w- \#v tyv\[%8o!غWL)vٍ3}}91|<Xg 'Ӆy*q뾧M-=ƙ{ |mN5e 3'z(Q'k@X/V/S Ԝ;,;}K.RT[Qaq&nRځ=霏ͯ\.K%CJ+ v xx=w2N_5}" jLZɫGx7zHXc,)S{?ǭ E6tujUEF\q8NEEZI:Jp?:>k+嬾nIZ6PQ5d9mAo s`VAUzf9Nj Ŵ5HoyC5|yW./*חwO6m1(J=B 6udGkCzr9^~,Hҍ8y~A4)`e!bcvo~ JlΦ}\۱lvbc&6hr {& _N&+/Aݰ7e|4v|4v2F0 oF{O-KYOVqɶ˶~'eɵ˵@<{.͓/ӇC~'ߞ/9>N0XZ B0ۻK Uv˥*o2oӿ /KU #ag4uŖ˔[]r[I^ߚW|LbG²K$wufrYY;?2Z"21[R.!8l3 ؉ޛV)Jv> P ZQJ\2M8C?t2]dO .M 0yd|BwJt@' gR\Nif.kEݿ mH8XF5lr.rƢDb? &s+ T=7:%ܼ}3r*1)hxϷCJo:( *ǢƗCutyIaDb,Ta?Y*Ѥ?}$J'3)Z9gG3U@d5rH@ w^gΈpk:i?+Lwn}Csra>R#0lIM>F.qіįС,)ƨ<[%,N-: IDTœ0/F,J6Ksb|)u/̸[x*ox͠&y#DfpoV%W%= )DP_y?*b.]Xv wMN&>Z]v |7:ݜua|ry~` /n_'7?2]\w8!R;+^ã|CIxϷ;=м#dۚ@pV&UsPqA'*?Ym"]KfErMmyi&3`}?52*Γu뢕".Dl\.T aA#s$rW!M6x,oۿ_nC0VOц:x /x鄇W*tcMToڼK'7mAZMCn7˵maSڭ[&rz0/p^|SriUa`;@mq5siI$i! $ĔrRw=Ѻw֊6/ 3"i2-K_ieu2 <2 <`0䪩XE/捋s\՚n|kN*WuԻikLȉ{.V1U*=<twOmj'h;+7Ln5q666Vq/1" yC6fVHƜ趉14ϊ>jd-8za<~u F2+s:@ˠ+B3=ǂ1#9p+ "b޿Uh cxxvBaoW9t1:/}t"}fm 󽎱uā, +>LώEXho^bdb9Y{69˜2^AweWDT0 &u&ųg]*oBFzwFq㭐Qa@Dh B?1? ?ȚAo&x` "ayEKtc3.j{~hAAjou/@o w‚r#dW#F8{8,lA+ݖ0rIk ![wSut z8M_[c/ῌ9Ut2Im" f)~r>⢃d%LFܒ8KP2`hGgnRI߅-V]8ӈR3Op^¬kM_?'0q g"S*3f5c@&P^. BuEeP=AiQedl_T/Wܩ"3.^{uM8ލ |a/u+-6R1=(4X!eVDz^ g} (RxmCDz3])n0RSo2" &a'I &aשdӬIl,mj̙koHn$퇵 E$7 qm|j*r^P+d?S[ϒϿ E,R[Lؙ_?=,s_37 O7۹ @@D›b̯$.o`jE+1Gm*.L<@܋Atۻ7q"lo͛}D-Mt_< dqƗrJn%LZԆeˬ,*T4-IN/6E};B+`D;ꆽ U| ytD# C1uB.Uq/=X­? o% ƷY'K]GUq;BD:~,׸6/t>$cQ6b\r,튥lb߮X^ K튥ewnby5_;߮X#+vr2:-(h6FC©lSj[Gf8(-31Hy^u˸J-=h,rEbBGҖ¨K xDT x,4 lnEY"_#]s-^w[.,Bs^8[sX7a`C+3f=8j8} 6c͹ST6~"^%p1{ AjG@}Aɭo i 9 nY?s{P6c=qF6Ⓧ{VbՒ ' [=yԵa*| 2x(y(#|. /Yjx9|!P~(s&eި>ީNWʲK5jb arHq9\&ڭD05f)?h EjTP\1n[saC1 @kƺYZZ/qslogTtU|} %Bii[{-_pZ5!K!挓ͦ:P']U5+ƴC 9YUE~(.zu??8F51w@vYw0,1r B-R ]!kx"u \@1Ee0&PO+Q%6uݻq&rsUZ#ϧ83@^*(Y'_IJA2ԢuY/1iڬJiJ4&\&"p~ԨVw7lqq ?:Rz*obW| bֈoZt5E$&dGr?*Z *YVVm azFG`l2!Y{bKOҚ#^LF8 (N,&aGJ)iMd<~u/)s -'-,uU]#a2-0JsTPTx bjgZǒՍh2jSL%YS0_DwGB.iJBw5ueu TN?)EwE>ce7sv K-h# P0hOX\#$1dH(? $z(X݊ *TB+BFw֓00|*".mlt6Q jZB2åѱ~ HSk٤uѮlGG}I2WKlD+f~#Sfs՝,DEbcU]:J@+= PMJמ:oM('/tPB;/QopEO57#2YDM,(2hMW;1ؓϱ'@i)Q0v.֩7L\b.sAtjiv:?l(ǔBaU8F+Gq]2&El7ogM ?+);4-TCw'#;Y|)k>y`NÑ/)$͉KЄ|4>^4-\&q2&&8H?'&JȐ1\G3'5hg%wk'$o]/8=5L:u)OyЏaakx20@T8jوX)I<|0{H-P6o>0N58(LSS0 oL=W*~NR6 1jYo6~[+'/42%ɀ@sd+[DEBp-9zLո?)ta#?J'2h0[NoL,5i _'^.{o|N^hN[{S8ߒgNq8y4NKb84Tt(1TAy_=dJ xу}|槩iwo"=2r|wEn?nH _iAC?_ ,/HԆy09Azx(fp J%a7zޗ? ˽UTTVRŝly ۮBe;_WV]/ PyJSf[w2?obgrД9TM>r3g`i.B_45xo(`c` 2U>WŗL)m{kOvX>U7VI|JSʼn-cbdCgV  uX<06!uؓI gR^_¬+dUcrc}|ft|(ь57!*)K;%">pSR[O1(Q5y}_{ ,3\hM])MIdJ6Ң#x= F?Rƶ6vaxdR3;i.MMx6۩va0W!QUΙT snntmB)bg7liBl\-s"61ߪYUVͷ4b2޶$S}5)<g ߜީT:j-^,+&MގA0FlV˕:T?Vwv*C}gދW敪_$l=_떇;+5T,7&=<<6ɳIF(\uIba]!ci<M!ȨN^FytYAxna8VhAH_ Nl= eT:g7!Zk2SLCEu7$tNU C>k B5#yxtqJ%x*+p{󋖁_16EJY2k' h2e\̑<x:+8v OJ%]H-0QjCTrk)gޢj vK)/Bg&$a6pM["m4ϟ)2)"^G.{O[rt;қZCwtEIbPC=媑ÃӕqM~s_ԃIgd!3u`lulkv5ͦhI/c듛w^B78fTɢMG8|XHz\Fd L CIqExup/Y]nϲϱmǧwn&NdEк*iÕQwTkP-&7lNJAѨ[< ox2.#2>2R ks*= %V)oZhlvZu ;ʎwn{zt} spGm3V|b+R>H;a:Vc`jE@X 'bvE"=qu9&l׹̺$PnV#N-G|pavƫc`mԭЋ:'* Q`x[8u5lpvX?rr!_n}[ьQ䉂׆$1<[(\cZZA+0鈌*r`NMMcThKN'K C8~Q*Gݿ!]*p_5b ͓pj( qerZ.n~ZvV%߸ ]_t_YNl΢UoH-}oAz4F{cX> 2Oט/I Kik:QSiPe@D %E ^aXeCϧ8Bt(!>#HԊxϷ=(Xi˒IȁX& B޿S͎TAQKcyԟQS -cć{pj2\t C 2z7I=7-b/$e 4`ѻMH^ B )nCj[UEx/df V zp0vGS dTs$Ǚ9oa3g+Q8"b9,]:HNOgo>UMz)t׾8#Z gl5[sF,??. gt򑕉6obT6h0.rD8+>}~+,B㓣Ӷ‹14[+U^`'LI"dNnPXex]oV+/b8FJaΚovYGxO󉤭Cz^QӪۢl\٬<J QuVq0dG(3=5}]Z„ +"Ԃ(Q,?МXmQISDXvY7PN L{/gSx՚r '@D%!GK8]e4hRMNp8wG>I᭓<cUcq ygHӓ&)keE*DXj({jmRoI7?#1B!UlBDHlp١56[|I`9dy K5_cylb֌k)!ڑKXv{A:P#$FQDPS>pe=ۚ He]>XJ[> ˳/錂̀ZAVg5yZl;Cxq띂ѫ7 {2R`) #<<}wA/A܁őJv*di)xs$A,xO~Z[k14.}ʛ<ށ|"9.iZ)*$]zavxFlB2)C8k4@ 1hQ!hvh^ tI xHі'_{9䅴R@pzGaJ L@ .J9tGH!;C@vIu_ݔD9A"/ w~_A?M\@0cWuΤ l{Bar&"l:Ŏzv,6!eG~3C2'&[#s2C~R,q=4sT^_ڞUu?d,{]*\/UᨍDXf_Jx&P;u2ho51We*G NȚun:wFIHK?Z*Z\Fr{½HٱΥS!,>[!7_AcPϽ "؎a-1r~rVϰ} 9VG˘"*(My^#3^:Y85ʡ f>R?j4i_wE `bz?`˟59y#Fc8%=-PC7= ћ$6M9[S.%E82lbы89#jMS҄d{T0"{ϔ\ 7 IPc Kj`!Ațe#Y[j)baIQ{o DU2dW?P0)iY. 熌 ̻Msz >4]d!]KuoGG܎bX3sV k1*kZDA[Eʘf˹C-];Id" DZi[&M}l7m4^dT6zNg!M:gU*z@࡜b4q4K $sP:9-@ϺaW2"6쬬> ޘ^a( eȔIO{mΊ֫þbJζT1U?$_>[X❢ϴm99 w %GB+zf2sF/C*o;e "LxVɲ $23nxά&Jz}g(rZ"`aÊ-t%ۈ_6Zd(J쥕غKn/X_PWʭ_⵵7MT(&f`OQfj5jt2lTNMg X~2"9`*ǭVCДJܫ@S" "GP/ϲ(1A4n4MJۺX'|h՞9u4COk4NFCqN_bJT5 7e#R8>όR~+sM76L.&YA86a˖h!q`-5oH\GuTo_񾡥a̔.bKRf/H!$$U|֨$uMJ|]'!YU^ѝɐ0\>Ӥ=0EfW|=TD9#cEPs2-I nmYr_{.9%n˂oezS>hQ5Z_ʠ0!`cgXJZʦ dERVraON=g积4Z|d`XLVmy_5 Tȯ&#F"P<%CHӢy4(찬{/"Iicx,&a7$Tvs#2w4Wǔ4]Ҷ1($j8ue!0G928I:m^Kw€[~MF =?qE059/dSR E A J!Tʊɓ-)Wneh ЕN.sQɫ.y/񢐼"/ l!pγ:=W {lLUaκ;Mf0kئ,2c:Hhjs͌k8]uYl1b#p1uBS)䝋U\KQmکew$ho3 {M&ȓA=JAdMbZ9&U1 ䷝6yhq%L?+g-Eg JѡL*L HYaSѧ6q77:(jbB 4NUZ0UUƛ!ۜ7/Tk R+yiߧQGA]&4̭LK`>䴞K-j_?BF!]Xt*z6+%CNfhwLqa5-lC@4XN~M6,nf %蚺+\(Tor%Nn oBPlh Qڬ̥Mȝө C3+}KP._Êd8~~G6tLe)EơA>^xrxj |Gݵӽf88+05ugTRtI1]_'s M0.Or9,\~bug@qAdm^>=~N2 0!kF[vOPQDgt'n9Ca=G}ݚj}):d=sY4[{JPR.[ek4k&81уd%fkmeCq4NЪ#~1!>>wEa'`7Px h* W v(Sbm -2?6;;=+Mл!N"@1MLcۄ7cHiI>тw⼇wW#\ϐψEe:S')/h>gMmwo YIQ}F4mPM{Qtw5im$8fG~DY[!LzztQ/f0Nγ`fJϮ>m&@(Q~ݻLv#6'7-gUgNWa`:b:ES4eQFhܞMzEmi΅֠Kb gc4w_0Z1} 6qf0yMx -J CSsTisJПՕ M >fZzM Vt)G߈.wh&0 py{r5/[ak{< a沬hoOzZ ٭t@BOAp5>$D-=xW2Iy^[T3Rl+fMn '8D4cvreq}k.EkXkD8u^#}Z#2ut& o4 2#DmC޶mqWF%iZ^+n+q(޵X&;+C6@ءz!r\KO6/8+_cuf 飫Ah%n7m6\d-7'w#z3B=ƾV=p:bq!t:J)~t J]\ziGQQCD: 17 lW͟Od\Aj =prN2]1ߺ8CI0~Mޟ^O; hd|< O+:9Р",'# q;T]nb-H{qQT>Dh\f o7gvyE,UdzkKDHh],U5N̴[zQMVM&sHIc.ڛ-^mNZ^0VHdȶT!L>En1Yg)-7JlXPpV; 䗠LsDnA ͞~O'VRrY@^[pveC֠Bz4KP:[Rbx,P պ…b8]BDglxrxuRNBOd&5W`- |3=@荡JzcMҪ/y[ VԄX wRo%%Jԗ>qZzV.pxL$$l#c6C0O5ŧ9yJ͊SJl^\7ѕe܎t[Idʌl ?Zٔs6Dbf(T=wcEV꯸䪔V&M ۇ&P=:c̓O\ug(m%ƥf%Wv=+J$>P OΉ.mZ-LLW p^OX vnG W.j&hNCNtW!S}D^`JJPV;-?5 _`*FۦsT e_o (|D_n6K= ?u; f.2LAdllPpҟw&ѩGP5 5$oʠyμ"Qv'"UEZƏfw+e2*)/u'Y# #}PT+Ljݿ݉ORuTQUPڗ}FRQW]tz:4L/$ϨPAU?wyw֠oZה/l4O׹o8mߌ /TW)_J֩&܂_{í{;1-=>BD*GYvNT2qV@6/77C)1kEnEbИxHfh une5)i12p+26Ztl%\Tdڰft֬<k]LnbѓБ\k{>MA낊~^ta҉#Fh+ȹK-:RwwuM/Y}+9 ڹX š"JcE&7JfY/]&quztn5[aջNFn͓To?_)ٸH%u|g1z ы7o!OOh9:jSGvqҀB{Wn77O.ڇSj>I{igUe_S||=un=}t^-Jik~{.qz17>O֋4[v1:%f8>=Qj{KPmu|=,Nm;qh*NK}u8%*ɉP%`I#͛Wu/'֛OՔ[.TI{N+Jo뭟gj}x2w.6ߞ..NOL⪚yɽm<0Su*y^/~n*P&Y;헉e5o~=iwrUX4ٰ'0N O$ΏOϏ/IK.IDBZK#>îF5'#@7nk K92ytU0<'n܇C`_,SCHX"Q0c}y@{&CBtTݾ=-/ HK RX Ҏ"Q΋,Y{w*f(d?S? @F]Y# EDx?$娸ƫ *q߷U W2s5;8n^r:IsuM$s"ۖ.D fPH:c.NS ||қFY+ByzRЕ@D9 yhUlZDnzp-2xaIE^JW/B0؇@DU6b=x@ C7xN,Www2q3L*YɚxB 8y0Jz͓ ($It"K:''v7 )w}7#zPY@Y}~aZ.-&zuhiklkX9uOY ^ԌZ7lU(ߐMW ܑq &z0v!D9pFER^oy7&7SGSvqyk rכZJ=<z&} Λ)ڭx󐛃,8H98o_b|'Ϳ7i-lCcvHÛsKLINPvF}ڨZɌv`%s\ }0N_SܷΆd[H:r;aownao<.GU9#4&fKB@(c0Bxx6њo_XǩuJ24&(41l6qcCcܛ-&T&X<}+RBW/JjgĠSj5K QkO?̴z 8ܲ|LJ=ޗr(wLHY@eCh!U.ڲ UmB*_ANdB% %U]B[]dr m%ёCh B_^>˹4TT~5eW-#ZXvȢnY˗6J&\@!p:-Mu-l@3=#tb<ҟOM,&P]\@ud[ph`n @D".YD5El-Y<`+% <:h3".Epd_^ GH,.?q/R5-a i͈x&HoxN( 6)6:7_x\ڐ)?: 2Ɋ_\P7\utm=AU1צ-A"@L]@E17\zYܼbT` }J#5ז_}G&fc@8Du7c(ۈGԜdߋn%2jduCd 4\kX Va3Ħ?ೠ EgW9* Y<)80\L`z, ,V@U?Čwx-t}p2è+ JV KGМi0b6l&":*IʀfMy/Q[ʛZu#@S>V)YdmZ3SQ3xu#i'!+3 c<t}(aQo4{c[ol ӓAVC^LhkL2(A:QBYE˴1/ٲ.TaJ"K߀ބyIR vuK1e'3k99x)ѤԌGxLT۬ȩtUPe=cN_QxDy~FS7kiڭfĈtt>`}t:J %7v@swˬs/T2[f$/3{T:T&YdՃ`ecu9NOnp`Ӳn Hf9G6Zg\E:Tl$2[^tnnF9!>x7( XTf~ V6[룂q*,NƑR+ej!p4SR8`vEڰqL $4Y_{t '0U:l tr.?(1Y\XڮIO=v43q@s(vPz1YO>J'h'U% c+p[$[TC @nûM?=TYpe+Ѭ ~Ƭ2igb<=/.uP2/5fpN6RRZ[ X̌NzɝY y/JBe% +5= )=+ʰaqif8+Otvijy[qӖ%E1k>ی\|Сx[6kc&(gf;G$Մ?#j Go!9/뜱D,%eryT(lo6Y #x5o/\ͬL?OX(ub6?dYxxkN&W;yr- a2JpެNڳBs u 1jdMgFnz?oeg-iPRO,5\i6&}0&Pj=02P:FH:M Jg $x&s(N\XN8j6-י͓bN 8bZy&e1T٭a>haQїm ѧoOx8qwָ{!b2:t7:陃hƤy s吠&Dےf\uz 0L,e.t֗|)KCFbA+&s/SA8cqFH] o >rC`)6j',Km*0;&q ˎ;$q*K ywɢh1HQ ň fVߴ.Zno;AEzP1 n\ꭱٳxryShlJzo%[ n}٪MW%bjPid]K. []Lup=En6&"[ *j#{ɚ~umI6XO1Nٳ'{`)K[4ue#㤓d:U.%j"~<DŽ9d˚Jd+ VluבZ@vkU]{SvK|Hef& |O )g`9fW"`֕ %Bu|c#りXdJx&+X0f zCA uI}_T vwH+H 8x^z#cDc;%ڍe.E"ƠA>CYމ`tzمb|MZ??9>f8GW jmB+X&CC8`:̀N$G =;E, T7c3kѤG`kaMe@,3ٗt92 *Z ܌E=T>lҳx$L{8f#dM4~+RqbF+Kgr}R KӀRȡYF&-x ="er%QAM1A'g$wTZgL2a9^X%X[_lN`4'浏̉2n4DA]BO&jtEbchJqdCg9&1Eٰei@)Tf?hz8!gx`[kt6;&jr`K" F1H//u~@|ɖ= kb㻌y-~H,^R&ƽFDv:1!pfy(S.), XcAL2 C9Ĵ ɅyC)2?.?llVb sJ \FOL DdN( OR{HHo8ߪ|TKĝy~1 }HD[Ÿ ϐAOsh!g 6Lh$ApnD Ӣ ,N7QF W# {Cc%,#8Ur̶TX%"Cc W0B"m#*R3Gn]deR+p3@_ vF9<\J\Aw-Dz`3Hx0 *xuz9>t\&PHWױ1uDٺjeUV=^Xy.]_l(Ez>'6(E`QZx ƕZDZ\)mƼ@I k嶬PDX^ݩٙVftmn3S.o>V+[ f9q]dO _X}}!hLRC x3HΫ}BўH23ٷXnn,o{P;V/:[[ڣTg9+$av MhjU a>`paJU`碢pl $zS ޝgMvM˶7vjY/Njcljf{0KR "lD6ҙ@6u9+[?0wf>* [|94qn>F3K'TddB`ٰף*1g8g#EVWT2%q閰'skܓ'd/>y3 Af2+# W="MX I02t{ 5,Q E,À7c/(%\R ]"i4z!BJㅎ!eJF,q$!vgӅO =M lLg2!qo|gFNbF_s@boˆ7ŋk(UP:_Aǃ}SM|i,6ld99 'M2."p \,Չ\4ҏ(%YT*K־Smmu1V)PH;āՈ/6lݲyJXb.+O* ++RwLg\FZM8kՏN?Y[@ ݑ ~A½EKEjl\r^r؜R!q_N 땫*$p'-ކH`> G\f'cP?B"uC DA PagUȩ(b0i!^c+ً-wb|I3[z:un~k(CcV'z2*!m(*:!2Sxp&*8jRj RZEZv.[d^O8!K2plzJF{:b-r^2#L9G׭w,4AaO #M":P}'G.I_ݟR)j4eBݷ]KO֙I!P˨obD}}{Rq$f)h(ȧOWroxDL@QRĺU IZ"FYnkƞ.d/d[W^S2!_&%UAZBndis3pt:e~]Z_4^ӱgMX=ZDLDWGu,I\@Dm NN<:fkySaw3*%Dc9f9)>9iVF>ZPtD*7`, <$p ؙz I`L]%CtNY 8l@&s6im BDHReRE}:ϩz4K{(nu] ,8:^^ }:g,`jWbc˜կdLyTG?zPH<ʀc_|-c_hӯտ2lD4)xJiy41Y>eQPi[廸"g4ڿ.oQbrވUae~k*fփOeȿو߻UXa)Z9e6wU?CRJ%cI<޳^|&Gc0 <xjkV,bWK[߈N2&0)7o]F p~86:9/[:O(;Vƻ9 A]OAj=;oZǧ'Ѫ 5&f€| 1 ,EG6ªw)ꍡEhsvܺB>VpV^^U$ʳ}8@0F7bB%"8weTox$,}duq`e28>{-l B};dcgŹTA~_D CKC m⚸+MWU 2)W >F #nxw|rt7Zjt ƴ3x5țU^ވ/ <>'x,o=KOIAlPc߰*u|1kfTL^v: WÍQn$ysc2+XbM nR&s'xB{Ѹg'Fq+މvN56Hǽ.?WԀmwN`O Ao4,Z&;%o!ԃfdȉ1Qn&AJc1 pZj MW|  Fi<8d;l;n ex &9i؆ۍE<˶yr>D'lh~T-uS| JitE NЦgғÃ^׋, \!dc=! {] 1 nÝ%>I9X11)\FB_腿]jnUۅ-q8+> <-kMS(mI.2W:|kE6O nѹM;+: y:,Acc,}IASI{`^ [ؤH,6(E*%./S$+ɕ͖#oC.,]>p[a<"e;jVR5-=lu?cwVP}>zS l7^7?' Y(lWʍ@Erc'95D}עNZ3p̢z) :9^,:1*0؏wܸ2ōK!138t[tyYf'OS/UǏ/qp\V! -q?'9"YJN>ʽlRԎ߰'<%7[)l"q\M"~\n5q>RC%;Z­mTEU!+Zg<)YEs@q+wyO[袈wv0gMHL $ung:/LJŝC>g5<}SټQL4Ri罉"Xq ?G]F,a'5,KkYʤpO"cVsv O+L:uR $Vmȫ{M~]8.3aMY'lYJ>2>FA[pZf =<3e]XsihMicCCOsP#&STG&G#PԗCxxc,:'Y,841QqR$!RJqh`7b=)sF7r֔!w_~y$o 20 es1$ <(Nݏ6,b:2#r?f;Y |vyo3‡¬6[ej]Nv~%ÿH rbͩmLUlCq<=AoAЋ'QF뮝ӳV}__\x*l>({I00̇uEWXE# yɳ \-/\c]\?P.fhSf)/z$_Q }kȕAxS"Y lJ;/AfHsPg\'F m|y IHOlw aw@skoUTp>]Lbp6Ox l롮&O?_[m~Fl{Yu\6&Lع $%'?3Ƃ_}!PYJK${?*ag>7ðH }(|ytK[T U$# y cq ?)LC?ۼq;!a'2frUnhcuօS93dÌ}E'0&tp%{>i GA4>ufC5:x ].AM&5˓I0ɛ^PYB"ޣlxy%˿op =B_ qfW^ u0u_\:j[%kk uCa^q˹/6zp]ePAs9*EN)YScEL)$M5" sSo&STJcȬ _X˸n7Qh%օ"'Q {;(Psum'ū!M)հ!sD%?qjˊ6(՚]iyP#n@SwӉ" TQ,ކqF*V$)}oHY"3C#e$e=Gp{SR@A+®$.hP, ?FH&9Q݂ M- d_s/wX|tX0YEVEˊ*~׉ܫ-HS@%T9FdH OQ)`l:X0!y΁uS`FԢۛ@фld!]OzOdd(! \#;#h3M{P~"8W @rU ,Sb+Zjh8 l D:iݎ>? RGp95qZNԜc[sSB=.^4CX9%ݕ W\C3uOM t>y/:9tCd7HB?rXlH~2o<(X1!٤- +A5j2lc SLi1!ҝ)43 әi΅uL0fT/30=SWD8?jl^Մ9Ge)C?II1)IиzGeV sTzTdu'T6;),B''dn)':KJ2X#+Z-g\hD<3c]/EI&;Rȫ`I}x:祗᭸ĎdR|].!R@!8s !'!"JTR"<1x2yAhCw}yTq*y-\hDs ( 瓎X%q?б2 $'#Oh;TFVG‚#b>[G,l6/`f^t:㟸R2 j<+(솁VCL9֔w Gx]p+C(1$nmx cuh'YQQ#NJY:E~ؽ;4*uR%bZ#g zAgF<{-rwc`r^s C%!S=%xXȽ7Ph]6$$lj_~^ vunԁUR٬+y+|4Yȋ2E89u02f]ŧlCEѪpZV!Ԙ#~\'GlZvARyTyiL7k.!K\ uB3pR9Lst[g5Jghaqo@e4ˡV<lݢxZ2Bog]R^PlPg6DS0KfEw`@h+>Qik\Q̉2}FqЂHƎ.뀫 \D(qIoqQC2գSwN+PN3.:j\  ZZ 9|+&,ƴ^A!4ؚ5{7cGlAV2:8cN"d7` ^ө*V8oM6OAAJ2d)͜x@!@[[/epUL2 dg*U Z `z4[RFtpb,=x>Ҙ@$P3--Sg _c<)umi ^#Q'` X1E-HiG_\)xd]_W[sڋUݒJ^i(b-.ǜdbr;;]B`#흊=57>-+A t_*(!…}f  TٸhsQVq >FMZ3$}Vp󶴛6Uz9/eO_ΎϚxѕ=՚uQiWGQz0Lnl?cT"sB!7ַw hYL/f*4I QL [ Z -ڀD$JKB]lYCaMP}"bF]a%4m^Od,؁cYQ3ݢQ;`>7?o;/IF)9^՛B0fĠb)&N^~j\Z5N]F  z3ްY} kkHm~`/d ]3f-*Jn 2s1.HJ' g ,Gu49rV8|*OHT\jT]i5v^w< pmIiC(gqHb;6寭SPXK3Ap|)4m$ucKB [v]/g"]/HHJ0hSZ[;~nO.CJEn8%q65Ћ +U-tp|3?UqH_֎veahjkuzJޠE63iEMҿZ˄\zXɻjRvE0@ޣ^vPHgHt)>: 87ri05ک (7X$u4o_lƃڄ3ƻ}} +CY Yr%ߞY"U8nzem0"AHCl0VMZmmb2ZX±V5.k/:߅K&:?]ù$(,?VQd!!Qn *{hD%#a`V6m,R?WaԽ;%7>(3AؠJ= UPW3hQEːרu׮JczI.>AMZ3A҂+uMZ3[ޡ%g܂~NNhP,Ƨ*#r.dDfxlo X1bhש"KFR*2$tX&,HyOqnLnYW8g}]j ]a/\Ԥ6K-JQR)AEV%4q;5VVQ7b%jW~2 `CO'h\sL4}=;Q܉H?D( Cc%6vT-:f m]9#x;H2@"_l?Rnu&7|fQjdd#Gǟd'갼oq vduWE>/hj!_5'' ~t| Ƨe P]ꄺ(^ӥ< 8tub0Qgfz;od`*v#k}ˍ$Űhɑ,oUIz TMVpy uAQۣ+"vk\]eAag&x"-~rH!B%DD(HRgS&uTw޵.6k:`-vI $1{-DK7-3 ɽRQ=UطåBϚoɕ8. !d`t8 31pKR<1GD"5ۣK+qr*r^&ƚͳ. 0ʿ|7:! GFrV:BaI2+M=OrgC7722,(cq܆mmkݗv{c^&a$&$: OqJtz:ʋuDtDZ?t~x 5ey:oCWϩOrJrgM!v~d!F^{z֏9d۠`LzpHbd>2տv:e^gnML{{f6)} tx9__fsAv8d ]X՚dJxܲ9,oo/d+l_-YQZnLr'=:_8i Z^ U.8y'%a _Zwf$̀>d^:YTЗiWB$-# #<"}4!'w IQV/ n.Hza^AI~!mGIoJ'@z>m'ƅn긫|t K{'K5v0*AZtRE$̓(#M` /:C7sVO+JA`f+5,5q;kohrpi"+ݽ~ mx]mл =>E byIFmI=gzVef~ 5)(#׵.Z1R/M UC/?7 dw'?zkɭtGDǫEF4Ψy, 4`F0M2PQ g\^5cK@)AV9b > P;d{*?s1T 5\wɵL̹FFM dK|{}.kKhXNI@|0?CF3ޫ%lHvWg ,? prx&ގ͝RYp*|TK }ֽeE`p=ė1b;ܜ_3J"Vؤܬ*%3u5Ň ;˒u wСK \I%=i6= tiW\A,ϡOgϧz9V:7'*i9FGC G%J&KYlWqը{O7nåWAh<lǫVK׿\ktU?ZL$~/&"S26gJ[IV+|r\O8kؽ]Dm^Rz\*}]چ*tG+ lz\y+e͓R W DPyiu'jun.=KIϭXTJQ;[;;xvg9tC ǟGlk͈w/Mo 6xZ3"mFġ){![$ =IAHtDoU:5BG pZy{I'|u<(vTƪRLLOI!Ut Z BCF+3pJw' KGcLf4%j )=8\0_Nm|y㭽e!ph!*i|dP\1DqBZ ~X;lXaJYFU5fuJhvʰw ,DpCDбG5ɠzZ&ᔆ`c"-M}9qWu#T_(:zI=YYGZoLЯhȱO=hnѱg$&#SmDi_p!PJ´SiCjăt|b^) l} D^A"2h¦ɭM ܷ$߰j*}^e[)qm&SަK*,U?#5Cf ҪoUHl)y'h8E4zbyjqspJH3ϔKa.tqžOb{v(ZJ?kږ1SNh@ZVCFxsHXU8E) ٭NXk)ƨ6A7O^GW#0hry[5ρuR4\3X2Z M-1jœz $Z}?+_WBhF !9KCd OҜo`hC斃TKJI{#j8j%Fmg%歀fS0KK)/¾rwdJ:6Ð J1nP02ٽZxBeS·V5hkTJWvy,vasDhZKhzmRmzPm l2'X7p X2.VdM`6m;B%z'J{*yjBe'R_F?Еr2ҷT|(+MK8?U=VOs0hUFCv~aXe7HN[)56e)][*K)%)%ZR1 \yR|TkR>C5Ru̘1n&?Puk;Kf^źJ_]pԛWм z xiٴ,`(~ Q5FCxrr<&}[ds䖶 x*R)' qGc#Jyut#|w?Zx[߫cB߾6,g0ks3Eka<Nꭓ8=>D.Z**_>Br;k2ͽ%$!7g"O67 X&rvá-mDmW8Ew |:=ZHh:9zUnf sܣ%ӸBiL͛UV̔6vJG٤ݼA9iS$DIPvX;SH9ڄ`l6tl6z=B#OB}` psptF1K]1SU O.4O yBtqcQ% ܵsk45*Tle87ʾr!'RJC`<>E'_bp[kQt4Dq(fcsr. #,[ٽ mTQ t;*BTJRW A'=]&DNLV")s;PF}6g.d|s \Sl.Eu5~O&i\fU/7l_"bZ<۪[JU;ʻVyӽݝ^i7Q/vw%p"^Q~V.WUΫ[jcQ99;;~mnwv;ۯv*ruU.o=={ut{i~Uށ[>: GbrS7iZ?^r4tuNF\\U|\Fi L' #e?f/ŴG`59U=YѰyꗤaSE#b(oWb*^bP,vij[-XϗW%)|+HzxV;"x&vfte눫jOT!ctQz*>/-E%*3%J#@\uv2 A+* uEL 2S"Ou93w] A]QRG]gCգ6Bm]QO]OJT‰kؤ>JߟGzGVO:@lS(~OlCH $}X*?zkV>=,Ϟ CWqZZP^>O+Cvjݻ/"~<vCpFH)xZD"]"pK`y..uk=nI&.)zI?C;U 8o":; ] w )R_:@乧![bϛ${> =[;՝-}Oڃs1 @N@SL+oC]"ϳ!kZG/VTo`2Xc,=- 'W+g{;{ݽӭ%r廠|lw NBםk הpֱ]]ѓ<_$Zgp+c p(H. *baF}lAZ&5RHb9~h&;lnȂ=b$ Yn (̽]Ԁz7aLej^ LÕ;ծwjZ5;jP۩mպWӭej7F C~0)ghDo~j0_Kh3)l7>OA4ޙy dyhwx Us`_Z+ՙFBxsߪZt .Lz+??^z~T|Z qBbn{ĊX%}X?gsL0~.GbdL-<YAZh\,IH.!T9$nZKO~w-tⵍ&<9!Ɗ~xy!>*ᜓ N4bk]m73C ګp2l/ MKw3^KT:ob@R{ oo]ORb]G]0ZƩTmsr>Dgmwi |rTފ{lB8;'Q8 tj\I.}1BzPfP*A$i#q-0KY#;53j>[60VzMFQ`FbȠL RyI1 Io7 +Q i"XiN)7NJPhR: Y}|qϽ\5޳g|˪ոwX& cd] 60 ےkelAx+XC&Ǣn$Qoxiz{͎dQ 9tg}klW>ַJ]8\'|%n(6w<97eazmnFKr{7)ڐX,?fvs( l:^`'|mzJ ePގUugWqު7أŠg PGإ$DJy{q؍O_%>$.|LW$˫*9H!;yrp o%P N ,A?g(~!A>$ [#R46iY.!$js=6?8[owW")KꛨE{ CYWdxe@f_W|ux0nRY|{jfӆz$LBPy9!A$2nsO.TQSq?obB> <-ЗFpW̱{Zɫ"o|RmTd[4 k0jaˊ( &}>+gomR3tv<qC+4Ӓa|LpJA%aeE~X6Ej.T e& AKQL1<9o4:8_"lRrq_3>1EnCF_yI `Ⱥr1es//Hj9se_mР)ƚQiL4a],h~w]9:l:l4w_yV=ڭQee8UV}V~}n+ VwwRQC, ^1Dp2YM\7Q`$ݛ*oC84LXO@~BLd 1bqU7A*\|ΐJjGQP 8PY) O i^jkDssTN_,O;RtA. fSE\AaH; ;6◘:Sn*ZXD?RVxA QZt4QJ&*,f伏[UKeg(~`-Coe![XEش4/˓ T5;^ûD2?^~й C_- N:R[X[!=uz:;M ;HZzN^# ʎijEZbS,yy/G&<*To9^YfŦ9asG}q* QV|T1KEzqb&m**R\} @$dlC7/..҄ WWKhcܘ !Ktݖe58*V :"Ʈ&`\w8ɱ t&o Ljֿt-2iDvR$p3lAe> ,IIUlt3 $L7q+ +ֿ.v+~Hӯ4cc(}$}/\꧘[K!H\78}%-t:-Va50gWW(rnx5q Kfħ'83"49(/9}yT*Rf+"&lTN(Wa sWvV@>#IDb{)"C<^Rتz#._s}wKhL*6@k"Vb*hkihx񂢀NjHݒ_:2P-{LmJ"1S_*^p) H2w5VFvZC-O@8Qq/Ml6q ,j`xOq< ϡsʮo='<b#1NU1o ҋ+>u +)W!Oa} @4 C;6pҵtHN1%YGf-xiA (ڛF>2%:IGɜ '^4:&ZbJ,JBۯ )sḚsP䌠xtɁxy-%|ݻN/5XAF+YQliF"WmD<'6 ;Y |f|0:aJ=l\B*U iHwJefSz٦ۅL7Pk&HixXL11%,e7Zk8WhUo7RD-)8'sʫâN0ws;BJ H #[!'E?*`S֯Vm0\u%0)\HU1Tcp7aAŎ2% [WJY)P^Du(+"kK$#}#-_>)7}zΘ%W%OXeW|LW0Mx#y8w6j =*na(N ]PtfB\x>t`ެ5l 1\{*BY1 zW=T@G]!qST@6oA:#_%ɦ2 G)*}2DY.k ^1zThYӢQnFΡIaZ ~SK >@{ѰjiJ3C*_lx>Atf:r&cp ga7=Z FNQ:4ikYT:>=C'"eEF斗%V 5wf/PvKm4k rZh\tSׇQSyKJȷ;c9zdX([hH$)ߺ;4z]:` V/\,p~ܺ]QU>}uH7PE9@Kwshv6 Scybmc71{l}! e9 ܽǺ1ЧA8Hڽs%,]^#9*!Mgo&`ݱSPi,tDi= 6Cݩq[{~5ĶoL|U/%ss\hL–}=9Y"[> 7]FlnH=(sjAfW 0ZMn?ͻ!lwjEF&_6#!)4HZo+9$nx!{#av0(!qW<`yȿ{ o2!Г΁SixucgrV&¬kp Uz-!hE;Fe_FW=AW!6R’Dz!C <2\k#DPyDRw@]uׅ6r%P޿l'!L80fvicl/d@.+yU\AMAjz B5r˭@wtv= W!I?+=V$Kjldx O?ō7h#[A ]R+bwk' öUҴ<05dy,)cRC;DL'i=B'%(Y3g(f %:IȠf0hLxVx?LQ" d`&Vƀh}I6rAatKhI_ma3n<ׯ|wt|s\q.V{$ڣY8l&8ã), 4La;CmNǓL͂Q}eE-@\!V/+%]$^|$u8MxxQM-\S{[|J>1/?a%?8O˥1qŴM;9SM#xLØs^w^KNJ4iKt[*8,bȚɥTx pK[=t-(tYsxGZRUjMnV4sLw-ވ*;MCNB xt pp!SI 5],A,N0}_jLc8;ŤN)&pM9 jގD<º<3Cg҂JDH6a TO.$lO? fW=ԫhøyN|vEq(x g:uuH{E$"oLI-R* 5ν~"$1b-ho- /Oҹ9΢!Y Tcj"5ZDQ#˒Ե$oɋEZ32 B'Q@BAJx "mIakkC^i&VS.m:^/-n _ p) #J(8U&b0aL0H "ATl2D.,j)o=.ghqo*oON*С+oMN!'>ARb>/ $aȵ3jcREBbQb~`qA&(U_7d4iC4'ӣb-a8^#Ho/Av /B,SjL\ina :}Q4'd2͖mwr9؎7;ZjNn\.+oKe#+EX 5}ScW@h4 0kKoDG'(2#A6~ɣimwڝ9Th75,܋2Vj&l[҆~W\7usxB|+3&vkv<в&}:]Z/绣{IHAɠfB`znxP]+rN(c$/gghhw蠢~|4f%FQg ;js|e9FQ .^֘% SA \Bunάd#gtZ:7-^N6rZ_UcT"f 31EV OCI!$5b4Q 㾄RޜG`zmlyT}[$E\&0)f\]M1@t)A$Mk:ă%~f/A1M>bL<Xw4F Qy,uBK]zJ#dz_>2%eJ}p8L.ﶍ*}VVVGVVWOZj֨6{IݢapzL.Ҿy4]>Yȭ*EQ(å| V/wl!QIw-9 582 9EhhQe!&|f*{ЖpKp#K2s¦DtWfBf*;:E%pN6: \EG.3s2. *s*!lY8S I1JYd>MB=/"W_}A^@(T= eKF(X$oS>fAį^~ɉ,+H H4(=S0`qJ~>x2̨?J~XlWjIޘ}l(1RZC.$CL|>j ǖ - J>2?Ɨ1x:.3WQrGxTD̮Ac(q`` Dp Y d[ң:61 e,ƴr`,"j㠶g6؟CO%D8[e Nq=2jOLӎnP D%mנX @o;{s7&l _BH/臗2s0j&Aa 1<@j<&szөx*2\@d4DybV%rL.c?>N;>([߃Fȫmxs}PzvE."k[?8=b\Dx>=8+aeiKLˢ2UP}O̵R;R_J_g9 ,PYwmdEpa$аi*eb·'UB&F"0P:(Bx؀IJ 0Z0S(8/O%"NbEt Rae%"x=mX.t1ؘCy&]Kh*(qLSR/{p6+hQq{@;v#oL/#r,7!n`B'W*x՛aԌzFdktt36r3. Gx1u9ERZNB5RIrzI'ٻCCUH{#"jz h[wۻ/`jDy\Te1;6ce&Aa_¼iL !d^"͵X_ę&`zpw,taJӽ8K*2muם;59^JjD5\NFp;A3D~w;Gc%L!gA s050C]uB:dky܁]B0,^u:n}omN9ZYa8!xb?EU;! 7('a[6>lokvwϢl eo!EnNe)A=D޾%ĊR]!~T@{:RPyjgI'&(3fCP+iL!^5=N)ȹ,vLBH]̮x1gf-'\ ˦v"\J[v=30>;$`N ݏ77_a%H0\ar -<*I{>N,8[aNJ f.Q9\Xa$q|6a N7 OTM+yK+[Q.B.(G5ZyLZ^K.:v(F\Y݋Vt > {VdicLܒXE\$4%[c:ׅ\ĉ9GZ}hU^K^eL+Z [[I u xLtr`.t*?E{䭸E ^m2qÝv 7~\0iOUGGCXR x=;$K\) 1:+PƐצ1ӡ!&pUfa08 mmn+o1 NP+D5?qЁk!:bd\E7l"6MR2#W|H&|H]@@anA0.Pd&/R_YIbŠ2Ϟ377jPԖ@E悏4ѽ0l/^nqq5#3+7F ]7FK4@M,*9lA)U"‡NK &OEhR0)% z$RZ˫^BAhi;zijK0,Z5([M*EҦ7P TϢ' R`Gy[|˖sMS ^cQ5N> u/tM5"eY= pkFUG&@ VjJRH {nMuPi\H+Cnm}?~抭 tCWYUލ@Wy" p;T;Y+pQr] Z.W4(^֤W_U 8ēP-Ny@~x" ^W xQq~FŘH$UVZƕj\ d zZǓ.oO)c,׫fRn\My 8[߅ !{}uz9` tiϹw4ۨQ R NB7ke%ЬT/ؒU)\juUXx>QV5&#$)!QĞW]1׫Wj֟c%!v_0Ufszt9Qmk!$'yRtB!ӝBSu5Cj%ˬeeVFjL,SKe2 L_+ML3Yf,fjjK(1(Q,* (.]d_.Eu.Uy% ƻ?:< p1vjm\%DjOFZ3JN&?7:j~? a?>:Bb6$Feur$e@ᰅ, qs<|6apaO;7,ԇ_>;+T$]_ykTH/lMFwUIb5`fS+l x5bJ}Mz0!\#Rw >p82AΟKv vftyͰ3SG?n*GJ!8ߟ<ڑ!n|3UY+?̀Z^U&%O\P0EO5NƼ\iwbQr;/7yABrl 0oo/V" 5Ы~w^ʳ0zE#içXLGfG0zQtW*hk.C9.ɏuKZwcs-=*3`39ǀǑ)Hj})l~oh\u0 Bkk4|\.Cs^\\}FYF\0X7!Rꅣ.D)F-?yy:vb.Slrw8CW݇x᭐t;eT%3SNjP/{ F`4yJ5 {:V1/2 -rZ?(C$Ɍ>%*] MX(hYM/O G}qK^Kt|wĜ)ɴ!*D^m[vCK|ԮԈO%]oB (]glp',zBלFkZ<Ce[.k\ޔQڔp pzb)9,n{s$;ZZ-^oE_:Bu[ݽݣml6״bB+BfsZŭsx:@'6ĵ23&,:&[1g‰"8-ԧL/!kiZv(/Jw\h5?Xe#Bڊb8(FWGi-3>6;eB䊇}}Ek U5-f|!yNn6dc\B^kehkQt|_'8N :C,yITuRv/vj_Q<>fVq9b72t~=J˶x:\ck.SOV*4 x 9Kt-/^׿lkN]A)q/A๩f3?D&"-"Ǒ" A`'gPnު_W/!==s,}G_% _[) AC撇{iߛ"bs?mΑ!$O~ZmW@nz4m2(0tZL7;jiЎ^n9o*UehV^4h&j՚)Nu+pv^_TVknf5 mW2(ℏ %ec(7s,OjL?ia<6\:u`M,ƮiـК H+U ebHm+lRfc$`u+DJ~@V@ݲ, 4ZpQq3`Oh.lXݖv(@o|S}RlvuNO*̘o3?Ђ踀 w7~Jt՜P]C#Ik 2]UfN:ԚNic2e+N1H*9n>Ox-P&@|Bh0T%%rb2In ɶpITu, 98>Џ ւh} 6 \vmO 4W51vt̺ir+ ,n'^YP-6mP hEU74B,CJJ9!Ѳ˹&yϠYqc ' {=I+1|Ubӱ73Pbɣ2&un٥]u5V^զ_ q( +N@n:haEV;r>8{uF}.6Pe,^ C n0@GG |jL;[^jtv]VE2w{ٸ0?%׬ͷӕs5 =2H)"i7NMն^$$[IEJ $-"zN=ObؔXKϷ}|==o&缽ծS}֒v- Mjzvl& elC)j["a,(hL+h+iaШnr&U*R?h(*. M´ܥXŮyAcn{6`}WMYO-+U+`_V> :zG(庴v^m'i0L[`{A^{X-0 L"v-doāEr UI -͊ S<ªr8Z HWB+'r) :^QрXOlp"Z3eiW h)4gli mOr"['>)CX) }C^ Դea?Xu, n2pmŜiC5D bۊ \c5V˜MۿmSgME \r%V=lG; :'@NTӁbRN@vUVCu['M1i. md0Ngm'jr#J@u/')\ӆrpli $P;R{yOm('+:`Y س4jpp Cqa}YT5RȲ} c; lba$Jʰ"mx2%5k_h6 K|AjQmA_8kFu367ke=mYWEł ib^LN T.ԎRTOI{`OnЩӕ;]M}Oww#e, @Br[.%Zm1g>&Ynkvm2]s믞Zљ=._B2m0N*\kօd΅Ⱥw[RhqQ3vak.[l!3j/.QEWQ hYRA/j󭀲KO>!UX]zȣ*ғG4Mm(w7n.u˽@_hT.B_ˤvP]YϤzP=ʢ~bWyE3ɮḬV5 }/b7>~j YZzppxya7>S˂h h-,fJdLE; /F I \wНZ ݻ5a2#! 5 Na2{[$ (2o[pӦQ]Ӱ#iZ4@v۲.\fuh~w.gى],tO#î/Y,,{rqm[v/n}-}'p-u;;?^m!M | 0Ӏ*t" /y⺤g+- Qn_k.``H!uvo249y%5!EKBI$z|As^/o>.r§~8tR#'ۓR}جR; LEk!S - 8=fg? 5Xn(tlcfH~Q0`AI IJ;OrXpVy74Y.XF'fn8 }׶PMcf7:b_^E5Z/ ] GGn(mÇ`ڻ+?ad:ao-G`ypl02clj΢^0 [dgkPqs_OhLFы=20(92R5;Dkt+NgswXe >3Jg%lV Kd(<+o$gA5;u+ybfgTK`ZX#hP,p:v|a!>Z C֎u)X,֫v`x\nWsSt0OWu;mae69lM;0 `a[qK N6 L)Y5 LVUj?Pzp1\;IdLylҧ܆ϸU7 1۴ ذgbV t J}MB5e!HL=Ѻ8Emmцܺ6r (a#Q}B}OMspPӣ5EɄ!S?m w2hq,5%c@w84מn92c7wj4-O4a)eZso dm0sv=خwXeι&+@7wdrҎ_T2iq+@>vi ]߶ Ŭ䅶ڐW~ t_ Ϯ!ֻc.= L= dmH K/EdjCl~)bS;Z8jV,5XHgIgb֫p<&!GawgWq+pa.T8:J*Yi yտ>@*,7]p\ςOc3C)ä p C#zED2CLƳYafLʋ't>:qĉgh Ԇ ԃiS>RK`i夬 2լpRybs\SXVcL'^I!'N6,^^oQ5<pp8bLYX<$G)z}U8IǦH8ICw !iX$HX7k"3O^&&`ϢR"e#*g÷ Dڬ+9?I"z[()Z5%܁PCLNeɩ8pN&lyjo|Uc qhyan+Uzdf9U$" d)кWX65YۆW416Oa܂ʊOi}ʊWq8y~Ul#*O|m3"Sm#-a"jd_x5[UX& WxjĥI)hp|Ru :%U`XC0qt+C0qqN#S+!TCEզyxi'MHȎN.j )u\h"@Y7պ_ȊtïXxpg;XuH:ÍUԝ #uqHݺR|RwN >;_\uHI\Z3*mZ'(z*N*j/>>_|k )px7 RlUH_u'`dDt*5P eV}cTr~}ԅNZ 9MΘ*@8%\/Y'p8}p2?Y8R˅ $Y,)®wR@&A&Gn)ʶ Q`-WPmjnʉԆk 1X!Lq% QSO&Z HǬK, AY2늺aB}uՂk+p6^uCs,~ ͂ ;4؊ߚ7i-|2M pXH5+4!#[d' `r8ϳJlmFL0P{ɣ&- Rɳs[)֌;v:?nuwvGTHww`4x4?%i4G$V}c0)tf]٠7H|yYS}! =Z Gcgc?I0C@`bEl:ǭΟ£:Gt'i8OGO|z3ҝ6X@[/gVk/hbZS-%(ozȀo^xpF /X6<\,0o6kWto<Yd1*N{? zavA*Ʋǻ;xjP%kQ8 Gyq踯qQ%Ktvm}mU88 l}SwZ%K˴dEӡe1c*Y{lvZF4磀 `H]ԇ zѩUe'cZ2~ZOmdY0͆QrE&WҶ({|=1#ѫUDwPTV\p& \Q5o :qӋq,`W~21^T2bܙNS1W)<W\V̩P W*Q<!o[|k=_Jp(Rց]E@eUWpJŤ,&PP?f\ja2_]_$?_K"OSGeơJ/./h\6k\+o?=B~* 0x&Aqtm8o)M'ܫ~x$#ʩV%(uÍh:+wQ]nRi_2-Q%59mhoZ[wc|2dѱС2!%hd }9]ÒI> fֆvFr?DՈW?T韫V*A%b{XC#Fy,@ 1HTlV8^O5phMBy 40]h{.M"*hI)3Y(QhУ [C*0x;No¨Ԋnz3E_a{&oNO>1ͪp ɠz#elVK)אM(lnwr` Uʕ (N 8LǦ+OM`_lw%}* $E x ʍe׹BJuaX7W -ǤZEWq;iY6( 98{/Lk CNH&' t@wb~Sʫ<ըNZfJl=+ATfL+4 gYlTŗ о NlC JJ/V!.DJ& f2jNF;YrX0 T\ O>Eꈘ"J>L}F8䗝ٍ ^h6 ZJSb J:{]RLfۭWX zKU lIZ,ƫD/+f"_$x; iRj4JppX6(1(_(fn4 {HP?Kd| `D0 iq;hhڢs_bf5 S#3n f%`zMX)113 ]N[ 3L(n_l&Z_Z5,֢$#6llﱊa?̦^n$ai;pR ETmn5SI$f,=(\"6}mݐ)f]@>^!^5{x1X"H髼L%̡[Rﴔ'7p \[wF-no1,u[TG8ӆ@ 5>y%k|EmfdDRx4"1y=v_u= =>U J^. ]FMQdS@1oޟَ׫m?,w? M6$7RK@1Ԏ&QۇI\xނ S|~=/ g[jy"}ܻ`yT+.W`&:}gÖMDT{WCxð7VLZʴJy6,Zۉ4?jQ-_e*? .`upU``_$ˤ2tIJ%5:+z%iHuMX~ dnILJ?|؆XR:[!g|1s :LAde0)m/(D5p0bhKNtWp5*?/Y|T1^wrLMj.x1$LТKEBwmq3/ I$t&$.@U˫?z,f[ iZ< J,(("Z(:LKIPSQUQtMpH-]A,)2UF )PQ=Azb\([p`Z)!@oOhSx6 S˕Lj`$8ᨕq|߾ΏY$ Nk1ݠo}KbkINk!tQd IrZ*4TPRG bN@uu"+Q6q7ڥ&EbSlSѮG;YDzW|'2 i#"i$ kYs<^}4|ؠl[a{ 2qAsŞZdz~bFRQ ϧUcLǧ4"i:?"'|,fQ4W)00e>oV{]z8{ztBm"Sv `e Nza.lCx4 *cDh J4M-[.נx(pER\NfI#p)bl.T#QR0>K硴=ۙ3,WZ0.\bdv΄z&~+abR,-jU;,`%cZ+FI溽)Mؗ%\&EkD{i(()3bQjX)yj/% <.*kl2)qyZm;]*\H4$W![?# aI٤Hu)\`!gD3y'/,5`!`}](%] RQ]G<~)CpGELC09Iź oz%!:bgT/hF}$454tD%/zyQDXlqBP{d2s[ڥ8kH0&Q?7G8T8n([' T> FAUCa.ƀP?{cIm3#g ᜀc:H,EPƤ;e6G s<ω/<^oRLXVxKGtjXṙP},Iʰ{eG`a@ۣ nܝe\_N{p.q$1́w$bLoks>GMh8GnANn.8ˆCut*J:ʌ>'Fn6"A$ù8lQu;݌"l|QMvo4稬(?cHHq-vk83;8Kxf;rs%Nե2|e=+GێԱ@g/e![GύNx2qg>ʉݩ?NL JB>s_aw56o5l՘ds|k*˺zeư}W*7Hv%0 -va,|e+:Q‘y0%8fwҾJ{q̧k9;yyZ}]Щ,vEDnf42n՘6h%`(zem9,Laŭ0Im&^ل$gc4~T0 |UHTHg?ɫ .Q|G#t$оt4uܠvZTDJ¸c f:8m`}ĈE`Ee$VtbTL`ث2E.):k|8#[lKTAR >5ZпDRrv6]%-7ZĬLs|AfrY7 Š1|yZӭ! l;b2ȶq"DX cmXù%ҁl49-2; ڔ*2qcsc=q$ L0hA4ݙ"~=<_i$VONY@wj:`oPJHzMɱ{AYx!wh=% tUȱ#.$KѢȻc r4K|ix;l=UOd lZg[U-<7"kxЀ=|'O̹>n4Tk:NWJ2g8ۇCJrTmQ&igwGMs;Rd47@ 0}~7n<G3@) _+|En`3ٰ๕ ei(Yx,jr[Ⱦ'7V:iL#,r*|ITm=[Mhdž>-b^雬鿵ec^VM_n7ZM4 [dI9_ ^o,r mWsLeW!O#) Vlҹ E u:tzU췊6ZL.al\ ?TU24?f3it#8M}s=R2A*(KOq,GvJ@4!@Z1\o<!]eA@_fx#5x)d*-QC$|אŘXQ&;<$Jg?3or 6p_>MW\aM0;c:M3m_뮯SofW%T4 Q؋ĀtȁwACܓ836g+znT1LV[!6"8*֫m:U [eՆB5alO DyP>@Ⱥ@c%_TҘlVNbՁBX!}yOGWtvt%Q̦flS霨KI['ҬjT6w|m9 eJ4|w\CZ>Y/etk擦VjTT덷4mR:o.˭[k +*9͂+&xy [>mo|>~EK֩"ξ\l` C3n>h i(3SVXX' 2-pfCDv&kZ ԌLsl =F6°eM0᫝MR 3WXPNA88]N_Ba*1}~S>7v[T6n ~a ~g -r~gOZ!C./đU e'G./ʑAƏ ;܈Sq>mrDO/)+ `-ө迱m21;uNNm/%~O}, {L!PԀuK#_Q;ȠZlŊF_9_^yM5I~ŢHۉ~_ %x:}R)MċWt,|- W&f 鍣қK-q2kFhzy?|"ѭgb!,BP~bߜH *>c[jߚV+~d;c?E?NAN9Hij\X4,@Z90@2l hqPA M~YߨHYɋ\\FyY''eDg-/SИ_N3`$5o&߶JrfRp(L⮺ O8.|arCv:ۤViT^S\I*_7EVRޙ“Jq~=~In|#jg6.Dk%^/*ݠ[/qG]k0- zrU\UX;ZV+JWkVj nY^& ϓ5Omܒpm PtNN* *~o!z%2 [hWwng^Wg_ti5py5srթjBO3˨?\zq4>t| >%Sq*硣ys{b" ]Ak%u>`Z`J ]ɤL7uK2Wd:RjV>7F-v"bn1 MSKSK(pz/uF%Oʳe@`ח9Qھ+[ppkV$ _y8p;S=e8`ˠLc t+a9) ~cվS'tL b^x>.O'#G ia0^>[]^zvZ? V֪a vq,,BSƎ[?&{c2H#$(g ad 憡-8bޢQ˦SXQ<[.!rn  @ ds_!'|t Hu7(:] 0!HHft"ik>!*cu_ۦ1M$_GFbyD 7O$Y# jl:\l| ů&x0iH i>)ήI!_·A r"SО˃Q*`3ؔ mztzaZ"ϐ\TmIJ֊Q/ASW++ Fa^0vx q$+>Oi=r7or%oSH܄o.HFVV? W8fq^c϶HYp?ta&rܟ$:/;^K ^mMu܉KNKY }"|iӌ2$X{@q?xvwcvZ_aAЈ(H EBʖĺk9UGAo8"ugK+v"aݫBc/ Ѝ3Jò{LȈQOURKLjOk:GoYA}dά ]ot$ v-l%02]bH=D@⧢3W 4#8L[ p@Uy( ~]d,򿵲>BV@3̗򵕼Wk(/bn?<|XBO1G̬BCB@5>cCT}zt7* `V#Nje$ *ɚm/80) q2I2mQ X1Y O$3 eCg<7M^a91!1Ce͗F Y5m&mBR4-`"'ٚ >"EHo*ф\!qGB RI&K4{;KS ggU\)œF EPmuƓ TrrͿzo:U˽ia<jbq9< !U &a=C&l|OyqX)\k@W&߻( oֈUۂZak1hmGC!6Tw+O-M]峭Nc GH=9,0#Sd`TZ6L*OܩɶxݛdK\$qK9m)ZKU暰is hy(:P";Wv7.Agn{o>kQrٮύXT\Zb.-h Ģ} PxP#u*iInՊ`J`ͭ Nr?ꝝkM?qBTL)ZBMg,B ,iaa0]P}L+8Y*K46q-u*ls +6/О<#"OHd0ƑaKD([4݃s.(Eٗ3[x1RZ5p鰘77 '+ZMhqh~fÂelˍtvTU Q>L802KҾ6e,RjdJ"I"|?)_kqO1]Hߟ,r*N@Ye8#[#;2}œw?)%*otUt*9 !un2#^;l˪M4C1ˑTLd CcrKK .uL 9i^]@B 靻 02 $| 3oP~[⏚%udž+R$ҷqx _8?$-AY7G؅T*-h5}rFc{(U3n.U5prm$R7:J;0# !AظxN%x &ZEXle;Y'XԼh ]<6`ΠʾŒT]VQwXJXЦu 䁡}Ո8> [N!2Sp8Z- :'Twb0n1Ţ7 \Yn;< CC !R0kӬRїb.J9^,XDE&nsV>^Y.(us^ ա i^Em QH f|Jҕ$Wq 9;.F) [Zt`wQ"U@U,V|[jK(1d0zl AHaYK}!f𘅷[F|b^ S 4t^u:n}oۭb󀹧зZ4 ɥ|[-K~Z'IZN{ZHB%Ҩ?Y}ok13$s]z%m,1q&ma4Koʲ`, REn$*<6;:,ҙhYM^s1/@bx2x(B&F^KTx! B1=0~&+$ dq !rfߟo R$XwzJxTGH$1R~!x1x*]P┼dc.;g -TyeN7/BMUI$7YyQ\ҕk1F7%q0UbGE*q ":˅fҪo'EH[3Qw4Z/BB dƁL]Dl2IF*V [/䃚b}irqfh kYh/ߖBo;սquo<vԱP!XL;,0&Hi? LJ$[/$2dlTG+y3I=:3['='w |8}?Ds`ƿ w2.xODnn$kQ+]R)i*M5dRC"y E :tv' :47?|`_"TWߪXaKC^Veӽ4dؘIk5 l8ǙHM{ emݧYq$2wxn%w/ zyM gG'ƍ}t0Hw߶/vy&|w$3_smоÙ3Z3=;j==վ-O5x[)oX;5,kg'':=5zfAgSё.\~7ff>nTn )⟕p3 v*R䩬y,lx1l;5$*}Qz)bnfJ.뭩{%ނ ~[3H[ .WٷոؗݥXҼSD%,I3]0!+Ø<7,BgFb蘗}ʷ*}P#1gr[1D2~^w}tأ-䬕pbeLiKMS~VTo#/E%ۦ.YߎK?%kKw;sZ%K!sq*%wo%ݱG3ևs-Cʭ.b08%|^ KsF׹2?#·0W畄WwfRW+_jHXfQ>J% bBV#y+Su re1a#Srè#ʸǸRւ[@g5^ Y9D:WO7̜쌒gd,`AuA| |yct*b)?}ch~Jq"콃oE8y;hp9~=$* *#թj{e 础 C%<5@5jLpk8< {i?بha8VI3AD4XΓ;֎5ʨ)I#B)~D$*2|c,ǣ%v8 =:-V`D \4`_U9 pKttet/w~?J{hL@lqn e {?Aė뀒tp~&;"gRDn4 {-r/2?r^fK^bA XcP: .CYdf4.$ 3F*jիjZ/џ 656J$$Ds&L6p2]ZtQچ]f<^x@"`0)*sbp -rL9BLƲƱbt^]s>x`qtg o8KOWh|_ :o {Q'I. %S VQ=RZ+]ae!6K'-_PmL8O+IL=}iQr)li9w63 &)Kx9χh+C|hUOv:O6 ְ[۬[RtYrt٩V1d\O\ u5Wס89mVZ_iRا"0dYOY`h3C>uv} i 1o` m `0W(\$AD¾BmX O$/*@Q@׫0\Zń3?Ll&|ٹ 8E"niEPV3r4 IhrXǼI=X΃,l`RW AZP(q[1 > WLJto\)ä‡{iz|lU YJY%`Ø>Mt!wt~[>ZO <$8Ao 4v98ᡧ=L6t4Ru_Tށb_148.*_.WD'ny=z6 S7wL NNA8G|ed "1H'kEy뾻O\x# xnL&e`#?[ &Q]-e BG ~U%MmI &wt m0: Rw=XCbIutQi<\r>`j.JIHu.l8u^/oZ:tMbH)_(m.=2R`1({ºkQ, 61R*ӏ(\XwEE NA8%LJqa̦b4&ۿwJ?Y"؅ϔ8K[..}]BxD0$,W,02lXVK PL㳠ixLߑ@K C†룺:}uJ:A'|U_:z::";P0".[Gt1/Iِ3@:cφENм{ #GPa,͇C~4E[$)A#;D7Q,eqvDxߡ)U[O D56_b5:x cx57OlMF` iRdh^F\?إ̍EC,o~,c!4 vS= AO2KB]`}gTЄD'2/Q]i4_0nRA|s GPH#aC>%Ξ$㭊yh]G"n?q+ކ!@[,~)XlEB f>!4Lh% .e˸r'w$yN1 DT&Qky~V.<_] '+(g0Z>O/n8p6%~e2'SƔdx,A7ð=}f풒pof4l)4eK\uLѭRB}Fwx1'npYS]wGHl2LB:{SM} 8ad.6d::niN)\-˺&Øᖬ;sZ`] [Ӳ衶83}6,r Ǩ)s`Bǿ<|USς_&0/H{N\Ku ͍>&I)8EQxJȡ:S*)H\[`4JWjRIHO用#cryj]l&hkE<*%Ti <;a9P6E3"w^G DQiT+ξ%o>>`[$Čv."m%4%Xl|(%Wo#o;s3)ɾ[“Ǚ.<>)eIv'6f]P>*YX 2[-M-Oj4vÁG϶cU+eh/J֫cqNso,?=Hφ'[r6ob6yg͵cV8hL(Pٲ@6z+a]aJRY-EP٭whDƗij{&b@/6%ƭm("HyER2 0U٬6 ՜Թn]l|} LMZetj~r7j҂?g߼V`F-aUhwYM|?CMYSJ d܅m\]UZ(s\^#aLwdGW}- ћ]SOZ'W4[K$Lru#3%µuJ#?NfW`RK4RwUPEӎ1ԎEEi{iO;W3]ML:#]6o޾x`WA Ϻ0Z(ĺ׊#E[! |~"2_pw/ܶgZ$d9-P_P=}o-!KkcWͫPq$+rn鯋Eq]{=^ȵɈ@Axh~ɳ#|~0 DpHa7t:?E!^($fhQQx`5am0pgO}|~yy]QWII9Hn7{AjZY7AH'lCz5K$C9"2,gלҤdH|'s?y 8?B4ƂŎBVhƌ:BǔD($ւ-B1wGϺm1]~tɋ!pi+}Ĭr" +H7~_$˶aQlol qgZ& J-־"Z(*.hgCDPw|Kmp9zxdGoKx--aQ\U8#S!(D(.]YX*(󔭂$ 󦡆O>b8iVoTU&c4))Ȑ`k `cbeWF5N>-m XTdܶ2 CzKs$[N$@GHo5Zxw&\٠TYFl,oӉ1Iȝ1Oʰ7"]6OHru21J 'DZv8)a45ҐEmȢ2dT )1%KH8αv{uŵo=eR|GݟYH𪔚ղEj52m梊oIۋln#a*ྰ6s #y#)n*bfzvz1^wzTAn(BsxcA C \RjP?"  I2%|ǝE~-`ϒ2F_6Yf#@^LEq蓓Mpm*㪸(jn T >)] ݂׵=6d z$6cXsä{v1. #d 2/o[]#y&u+ RVIPϲ!׸-II:ce9< 8K ʹRKcw<mx>}rnqߏ?f<δu+b\B f7w Ru~~ Eu,Ʃ]>+kq09#3A" sgt(E]! CD. -&2y2Z JAwڤc+M\vFvK ~씆 a9|cK4GaGC6.+l5E<gg & Y" O Omh r&,-(?Q˽&KUwDU5MBWx$oyvUW3ַ2PfUG33_YsJ0w=T6Mw[\T )}2t/OiIpȗ}?~/Wě g+ 7wSWn?&}a0=$,ɶSc4DԂBn# s^%$R}addSaSԓm k?_e98H{:U=tzc'ޒYX%L&hj9凪q$I;fRɵ4eH`_!@9ы.KGhu BGq兤w#\f{JX xn[3?G&a/E\]cpM5i*ƿG،5R!#\yRS"%|f$iqaB̬bQ$~ݽ]G`. %ۈ ۗY,f,ra}0X?%+~U U0t9deTeiCrI>l)NK(Ǜ>ewxc#4|)אRC;6fez%!il\IΕo"g1Z 3:\*֗p3EϒLOӜk5I؉ˆ#^3h_=cP6 Y@Yu!_VqQhU`Tb4)/Щxv)Z.Q@V` r5l >wMokn-<>ugq Ϣ" gPgc}+pA+o`bav{ ;S!n qؖفۓ!u7Y6K  e ͆S)9my- SSurWY9'b639iEb4cE ̐Q-gceȓaDwv!g8Jp)D:18}Y 2V>)N)9ObmSfAK|gӝ]N RT8)BQ+*AjQYbs ( -ĽOKoY"I]I6Td z-I,y'85S7(CA˽M}-m ԐEP~kHs:痳|4BiװeKTT[Aʲ2MϕHiSfoue8%Ԯ+ÀYKK<#ѫF(wO FZ$KD;|2Z;ŏ¬&"P{t\) ܩ5 P bjkZ$LLTlCp''+uE[& ,3mhJzK*aaXx6 ;>;Jm>(tk~dY0:6]/ Wmt8_LZGhcḆ]~3DTۡuY]7K :k&xLq<jE셤0=fD2ɀ QC@ 0b2~He&D)&NDO$L?$Nj.EO4{3[Ƴ`hl :&JB<,Q}Ө% 'oRk(-k[IX1 q-ȏD4?eII,Aƾ$d5/iS옺F^Bz!xc 7 u]&W3c]0(U`:?-nfE:*+.#i:756[F`rK% GjČ[+)ʧh!L4xA $ցZ)ӡBz85!& l{@PG!Xv,jfPڒ9LTkcQDzPPjIvj3 PR8~h)iQ7~l8V*fwyuWZ!d}he3:afnz72B-lf-M$J^˒3oxS{Tla#Md0S;np7jI(28F15fAL1!]&/f>d!_` Y17wD6+hXƑZ6_P]Z9"z3Pc,d"P ҧpCz$VV҄pYWJF'bd{)S^U1E*ɪxH6a+dVCp[/GtT *7\t6Ǩ,D7DfX"JXRSr>C (5Y]LǗ ag`|ߨ7WV hdr t;Φt̉h9d3! iJ@|~~~?빟_~?EgC@EI~5V0 q[VZd ܔ_Ae-'(FP hΫɠ]}z§EYb"{]lTF&2DŽ5\mGpfwFZ۸VqSz Ww86n*H(WL5b+zK[:Lj*6CoAŒfCCϢ}7R(sKq[VT;B]2fg CߙlCV إb!J[UZ*I]7շUnR6L ˿xrʻ6u/vXDlMn|Fyb?=vxv‹{JYSi$n)Iv=flft$w"w6'mti.:nAߞ3R6Ф_.];yėt& Wrs7wwVwƌ~wV^x~wDw!&1#qћz(x R1(4 -=|Q p/*ҼIUܳO_;-*_ҡ\fMlp خ)/1\{g)e*I䔱ɔ+l),M"V$$}mclbcT8?Q[z9nG{2!7LOP)9 ǧ%PKHQy/n7ϠCl(T`!pxĨɬCpJyM]Vk01#==s(^#ItT#}鎠I|=.T?/ҟ''ˏjWQ5yV)0 YH&(W8b'NFζ8vI!6B  *e-lpE0{*SF؏(8U&vTk!%'3,VeLݵD(Q7! 0 u{bʊg]AӁ|?D*?/Un[siDkA`RּboIh2Q,r:tNx\fπS܁I]|bAPVÒOGe$,.Hf%^Zqt&m,jS)CQ<,8},RscÇT,.H'%&&ߨ7VUҢUHDQ*GV2 ÌlTH S"xO>_”x=9D7 GyQQ؛Sގg@&G`YPqżF}?N G5'ȕ_EQ] ɮs S'f\>ll꓆ @@2UG@;}t r>?~LZVUܪJO\0̅jT=/$G97mR8jV4΁Vy}pGyxwj>ݽ.ȑ,+[X!vkǞ䳳DKeUk[bNnBew'5 oJ>=6ҖYt X.ڞAuh[Xv,T葜0{V/SRaj|UY3Ǫ?,ؖ 33( G pTFS݈` 9`x>R2;bOGPE6[`RpNYhjAC~D儕YkQ1C> gn'%Dݙф6nHg`q9Xq@ؕz|L]޲P`#x˶B9vvvjJ#(3ǻ;䨨Juq?KG/Vjt67 ~_Wo5S79& 789_F5WN0!x#L'704HܵNò8Tn;(uġ^Mי+.A[Yr+Z?L *g6;z-6dn()$P)i'l.)!H2Ōmpv[;zaY"g`4 හBN咡JRQCRNmi(iWJdyMh;whgov@s<)xA  >5Bçq)Nb׏ oLrC_Ę)b3]XC1g]Dŷ>`&*?\k* i< )W3 /rSDŵQ,Z*Rkz ʪ_NUIQ" jQ@^,g i3Xk@V,ruY.kL5F#QhM^c=Yc%mcUXe5ꍔ?5~d5Qcƺk`T8e5zFOї5ʓPe g֘V6jrԪ\Z\GW5>ju^cJZCc%G mQ[5mQ[5VVmQ{"k6=ml%9q+Q- U[ETchB( jtNh2XT2QVQ8 DtBL zBB =NjT\:$u`L鐫lnQܧ=5Ej}j2Nv3+PT*:>Mqr>whG2ņo\siN1(Txz֗z]=c8AKTU,w{e6ڛpCr'vx↕W2'P,ʩɼmDag p*gwyjGt>eܸ7{bZFil ;,mbD[+k0d""^Nf4epJ$}IAFli % Uחv/'lOlA}r>mhjW_[F~lL}EtzQ\] ;W 0_HŽeH g.ci-aSTLcE J.;!G~pMQWx5=5,sЂ岊3_wNTlp " ^RC]Q>+g{F2?`7H/QJΔQN#59E 3\1axpC1Q"f?$2%YEBN.(NF1e#Ɗ1vx43d=ݣһDz^qYWD`6 &ײv ǣp#.lp x`q`~JIH_x> pZ;_6rm`|(e.:TK6h}K^s!5c<+]Yjf_E:-6.V(τGɷY8gp w{p 9}ޚWQ[(und<򘬹Wv`g *J\g3lfݞ g #T&f E>!l1}O\АAmeh}!cc%pRY~r-6"Ӟ`fYDƗ/N ,198+'], G3q?AxGX,DӇq>.O`"y[sC9!$Xv42E{~4%C_LE/p3䂯!7n?J.H%h:J 2z28gi4 % LŃCWk">6kF6km!) T^Hq%bbF6L&[&aIBI&M1PҜd'YicQlP@c:_4XaN+;@.e/a*oyps%QK[NS3*2%TKPmvq#!vP|4X}*+<_ݨ G8:&{d!$A4e㏲u)28Ї sOb2OGt7PA@v+;P26ͭGUe.i_"@e 2^sxx}4AK(.TM R<օ< -DVxÊ\/Hr xzM)@E6!Mbi8zH&)bCcc{Iwoel<B|0CaAG~Mg"w7Z-r- Eh`@c;~ͪ^1^]Ȅ%/ce>k]J_㼧kb!A0B;o[f:9Hw\,%]B'D ?߶|#wpg'0I3Iy;|})b!nb;BH ذGKuVHVNC=eJdFvxLW2|H *"|Eܢ3ouFf;n37ޑ*֐G~2{4gy]2@qB<#$mr76QIUMիjZOF栓y$.3 uLfWQ}גfUfc0MbX 1}ް/4q@G! ?Nq8JCg+{M^_g` 4m0\83e Q\9Z dZ~1ҵZy<^^XZ?%J.;P'O$ȭ盘+xMa΍Zk>iQ0Hnhb6p2riض *F&7׿ m͔5[LaL W29.v'{5= NhC߳jBQ0cc@ݶxP J:)u85/E} TXU;hOCS&@R.ǸɗKb1|BTx[+gZ ]`q7CKҺ~a͉ Nb7G[jW> }oA-ڢdMMN{S~tD?؃;iq0M~kVQ [?v$[?b:R(1|n_SaS+SŎvMQe &ov_=< O6o*Yb+ YgGPg0özO!7&9;3M]7n9k@ 9]zpƍŮuS}hz |ސsr+=՝*E}Hx̍`sSNr7qu@;B0 M5+ݏV}#&84b'ݦo8t`MƼx)Vl8ۘ\Q(R]dYhgJָ7$e<'Blga(ɮ.JJBr B^ t9^9)g2v\XU8po/ Iϕ'}_~AtK4x0|j3+(ыaf7pp]V&}􉧶"+t؛fD/L7hTޤ -~*5#I˿ /]dqH"|hC_z m:o'З[IohʀtYPuVkk׻ =,c3&K#R5'ʹUD1Zv/yt<8(#+|r+'gy)E7I{QA>Fksx[/[}1賟2To:jw,ޕ-[A,3]Qe>ߪ-ƱG~0QFe6< t<2xc%b҈ T{`=uqe~$:'A/+u)zV |>,/q`*,}͆0_.SJH^v4!B D/t罯u$&s&SV$x{CB6y]` o#<ኛܻ\*<a0&K/4,dύ&܁$'E(ܩ"e#*R-mzҵ/80J濓V HjߓM.FtíD|B=djT|* Lz)iNν TŹ| GH|]yEfA92H@=c) vzG!:ʞBѰ<9򕛓Gya>[` ^eǩUu'BuM? 5u M0o2*sd)5с1ZGRl˘Z3_"dtK6!3?s!1̙S@ODiEʹCVq׻"d:ixzLA߽i[fl "oI]bfe4bкQ][O pj4BN+}6^ :duZ4 $2Rj|<:clLY@l>ꉈV\r܍8`r-"s%HI꘸RdǒZ3-Ew5B i7x%VҒNVzDDX^$drٚ}Ku:SyVk*20dZ1I X#+~PzxTMBxaQ6#0/yß:S f[,w.Ԋx㦱= $ypR3U*KKN3Ϭ%BHaBRtN V*IsMÂť`^&Ft;Ky"zv וLk<}L>i8"A8$ΞLo/^| _^3Gt61n7mOؾ‰vhnfտkL81~zs&>D KÌFhyS{+OIR`4 H~Ugynn ;tw{V/(6 7&s8cZ΅ng|{w6] rp>ex32.G٬2Ѡ5٩'(wඟ ~x#l\X,:?A xgY/\VO,3=t~h7͊Pu^wЧRm̭Yŭ£4𱯔pLg GȠI+z58^=<םyJ pgw3桤5g@xU[4,>Ë4|lzqwaVM,OҷCxSF\+cݭgoT7%9oqI[ӝǼ;a[Y4d@bTV=cZ)+y8#$Ch(Dq ؠaeMɐe )-TU#NSmQ_69yWD-MHɩ'd/ ' `sSIZ7Y9.<TG Z|]4jP=TƘ 0S3dt~y8 ҂GE fA[RXGQ '"ysm@k(mv0 ;/5]a_̂&6k4=rqˈׄ$`b!-&rڋ]3y«uuIXb|,faR@g^lO9{xT &ߞoGDn?Nlщ :G'[~ ZLai7F}fx6y 2  B~ WN{V UX*)5w!7+D^DlV2j ^QL,6h7Z3|;a(LWY*`gh"&ooC&G(jizGe4[8buf%u1&F5QzkCXm]_odLc* m"Ĩ1q0i z1 8o1(q>+R.;2>5%. C@Xݽ Gon~ܫ 7VB3t=pEKQ։ R ǗYw63{V[ϰB")dU~KP=YHHBrBT{'\*me!AnQy  y+1>8>ޢ*؈ڑ@XCfIWK ioòk1>c޾qo ->d:㴓gW\&1y<k5Ivk_C1ʹD6eS)Ÿ̱<%Y蛝VoNڴ&޸ȿ~5|ٗ47ЎƚLvE|)JdR3fWD0dkHT,Ϩc%Yjګ0+Yl s,-)k&#3WyʬQGH~AUkNUA`s?_Q"S Frf9ۓ+jr(h [oiFeښTwA_84}.ؼ%xuU( |G愿%A]chX $E5,#zTtӍSj!,A& vV""gzjZёJg9˸qv z9ACo9B"m (&%y􏤊e[FqBy[\@~&tE£Z(Nd h /qkD^v~gW)#*0 ,r!I@]a>1wE9AHw<:0BO:ȇp 7"ltFyps>?_䞂c +6.@W /@::嵱ʉj$IxǏ b>Jٹry>H oL.$Z^*峷Nڧb{T;$^Te灹>k4אSjal޵nqd=5Ri 4ƀ--]razh]k8/vo4 J3$}];+Ep&?H>X&n﨟G8ҵBJc$"#IY"E>m=z6x1)ofS<I!ٸVȠ8[*R& '!3KVRC%C$Ir*;() ijhހzU (.]JOEgb%C֔P _OH%k_L%G˗.9j/Fx9#S=I8jFY2((*zfUq,;k[ZzOjgɾX'MO.y&{O=6zK/J%\)VCLvQ?K䤺؛[);M6Y uUE5OkC~]G|"B,3I5q_{D4qG1.Wˠ L3pH_ӰD"͖+g\tT7:Zqo~¡Io ;D+OWwt|֎Buq^h2;~{u@" ᷻,,?^hU!~'wyvclp^]Du&΀GW5GU씦{vŒ\q/,+*AL0o"qzW$j4wl ύ>**^UK56Tߕr{^إwv\ڰmm|'JO: ~$wr 1?I0Z=@8\w9d|ra01~5Y ԚP醈~$'v!iS| 2&5+"DO!KV])މc{"!SQb53_iiٶeohLse1FX Ɉ4oV҈c"Hw,(BCx+Vb)VX9\_]e-o$nmзK!6666/U1;Ynmbe]lٺ{=KK#w() eG-j/O:g}?p/Y c_1}XW,λ^n vϺĥ{O y. }!XiѪ` %ch鐤e +?@~;xYwZvOþB9B@ Hů "GZX͜|$2Q 4$ν+j5e~ bhg[uUۦCծT׶HÓOO:oIszGRq,ǯm%WC3xj7ŎB$)v>^C"k%H[V=0dTIyqّ}6(Q'VGHhi {79L6C FBr-QXD= `$p $ٕ&S)_LĚn rஷkG-^MLz 5) XkUta YJL4@̍2_q-K咽Q&Qy| d/{4vФhIf UcLrASvg S^C/;PI%d2Qh$x+I217a{/jvy}ޭNU2Nag*nw{~t|CI&-UB6 ~xwͮ>XM%~%Qfq_뱱jB^@!Gqo"yu+mIJR M!sҡ5(Syt~OO@ۓK{V 2OUp" {byD2m Ji5+ҝYlȟ(0ILj)FIدMͦA4 1[S&֔F 2g @Va%C%1RcΒ%rG YМ>[%~'nCsdoH@쁔FJz}yCu:O+7.b!ga0j\SJ#sN3^ҏ@!g#! $B%3NA]!$4ũ]%l7ŸHm!eޚ{qY3XS ia7wʂqTkEa4$)qqPz2 T4?8\@Z҂ 0Ebb>ĦYz8Vc9(1PXր\0i|QPZN.ЍALrh H"!١n;̃4G HhەC %lC9^.MlE R3j+eR;pEiPTS2,$qcY̠'҈ihXR(kXuوiY gj--1AYs5Ex77„mEle/D%ıHlJ>#m} [Ri#灃!Wc䰾{RVV} WZ+ƕ&.(O 0cʄqkXODO$ԳnSKN^؏ 32¥VLЖ)x嶝J ҜL'Roϕ@4X 5m0ʴ;EI֕!]xg޸a{U 海IE,LH;gRF3(#  Ek_z1s69̈́$5M)vHz>ZW+'Cp)4骅.TPc$n 齝]sIU3JX"njS~NaVߡ-f>|@+wœA]9zAvyv} Ф2Z>< [(wh62O1 LThB6c:[ OKH 8qͿu;ŏ?Jŭ·?Z~XuL٫9YuVpdž3|]b)Np>jU~ϿtX{r6'cxBOemqb죌Z/=y"Q@ǷCd哏RRc y0CDT [v 93eB|⍔- b'9FJ2V"W9l^_/؉b >ā%$2NW kEb-tґ *rVB)l•BF 9o KBg$0LskxȽw!z.ʦ͔Lf ؿI`U,hxWΰd]+PNv6Fs GrUX=6qZ&:TPw}ąTwrؒH!.pA#`r50U*X\~^L `U5%k%ldّJS,DB"leN#?pLq\?]Q디L[4ׂݑEmI1  u7"6tƮ)uwk&4!*/Ō"tmd .}۝bO:;DFw\PCq ZW~iK3 *U&Nk(ZwTbv 1ٻP,!SSI4;Jb o8"aVE6sTIY?VQ+h#S;r&p5O( F׸URB. 8q\<Υcb{Z-`lۄ^{9`?%bV*|tU%ZDߤ ua K9U-EZ25k|)И*̒jj>^ )KYȗ؊q1bd>o;z{pi %/2.a*P~E FZж`i=DzaJ{)o_a=Z##yOiyPǎrhK˘#MaAhw5&S הr61*aD/2BqII"P!l($:Nw;fS^輩vR70_1DlоC4Ԕ6̍3|9c0)0 )C)' UaXOa@S0jտ˳A{|Dw ez|w,~%8,ǵA(A f`=_WƮD?*C7ǐ޿,k=EZ–uA`n36L{,C3 *Jӆw!Gy$'ny* ҽ\m[ddDd\]c81\6ZffBTh-NK9ziK+ɵL!wʓ', ~WX+PUCQJD`i4L7r+[Z2udyS%½{ĨeQ$,j~V^X"$Z9kY}QX_za:BjVSM6 :!Jc LG5vPL"VDA]e4&4(80~#+ZVqJ t/̎҂Dcu 8IW45M B%̞-sx DiFסd^K=-lqsQ0H\v$Q ]#Y5J~琉~?^Ɏt+ _Bddd$[/>~Vy1v/=fe{\!687:k1vY@D&&ZLnݦKW̭+sTbb)K?>-> /8 (<%3[ YhF>S7(w]);$9dOd-IjVҹtlӬWԱ=dQ{asBT7|5 dkπBe/ |taU(/M̑ڡAt0ܖ*Nv )?.T+tp^pcS둧=E!y1""k_0)Y:̄f\Q<]0;[tY4f&GIθ/%Z\.H"ĭjoc0P2U״)ʛX?}ƛM`G?xV|x^yA< ;=(?g~T=&;t|4d(n9GX5eoj꧍7A>i-7P@6DU'g$'4BY@]د5( e÷33|pk`ݖ>n[&8#G n[>F1v̹35cZŒ8[b< 1>I3v@\IAMyyKO_ ܮgI?x*BaLM=95ݗܗW3wLٙlݻxdӤ%wK껆  zjޠf24%}-̘ބ{|ڦCА@>^ B 3943)3gJ<^b%6 ;# w1L{ߣR̈'m[q[uEL{YFH=B2kޜscKb,Ä12BOYuA(:8OFI$+-e0@t#5UB[cb9OW>jYgo rTi?CiF|<H} 9$PT!Ҕjar# 0a2{ s/ XtOl[#KЖy088m'*bad8G)zFx- 04&Ggk4G&&0XG=EQlhb=vqoe?qyҦ/b-FmV`C\虰:,lx`]6_=!(ó qVW?S`lElF/>Hl]++Q%xu6jni|-5M;ۏkkq>ۦ0&ly)9?Ӓ:/!{RkLUQw^)85WɁ=%L-W=\x( 5O c `K~~T c/ i7gߌ<+$a_BO276]j˃,3oA y}O6sa 3O:tGmHemp̑::3r;ߜS3I)8+KսO?.G Mk[;_& A廾 p3HwB'>+887Ĺ¹!} qnnsjC܇>߅Ji_Fkf&Y",>j>cX4gN3dǹ{,BԵ!&ghƇ2'A?c-%;b>>hM,sicʏ.F Rn:)΁оi=vͺ=ʜ#dSm2}k;Oa|$Jo;!U+2`]N J).nǟo1UA#hM,<'q kkCi'11zZ*xo{C^g"yU湧rAӦ_MAq+{5MfLSioT53/%TyLN@}v 3&NAQy.Ȟ]DwL xl-c=|K|WuVG0: tM{`6) m7Tr8NNr甦8,jl &C$D KNm,֧[+m:&>HAb#Ȋ ~r q$r.},l_Y JwcY/<>s{ RPGq<gR]yah& rER.R뮳@As. 5ES:shxo5D3+K9ς%|B gPk_yʦ\CsH6)YQ>́ RX ú LJR\eϻ>:Duâ_>o8B357Ri{?OF2<"ՙ0[ǰ;0S8 2,L VXb>[^^ml9$qa<\Dul+:%lhk >@V(˳j"ȼ*Wzjymy1ﯘAf//)OP9S"-)6˞%|ڍ˂@zјTJyLA*G|p U櫭:vnf<8=;-YJt<-Ӊ~<Vrf?p6}vdu?-Oc<'t;No&prMY&>2ÿOV+aBW.U֩54c a,;9K1{ukM+H^lb-MDԒ&TgOr2bT`_g|t$8KNyWǸS4-N!cxb<'.੎z^<(ٜҔE>}rC_0δ@{i~h.qT~4_CoTyAbٻh2At{j5Zj^Np|lhs؊rӣBhd^תDnN̙Lgi.}nslZCNCy {2.?Hrً 1 2yaV.-xuAi5lP}5O)l^,zj|OPl6?.,ER0 -Y `o"rʡxpD}bJL1}bOԃ0G'Q?_8!vǛ[&n[!m䯮7 o>nd'=/IöNYSn}c <͢{:8oRft_z<{|/XDM?4)Ͻ ?Q9'ޙKo66MfiG>K2C]t.[ bWG>y0ُ-:5f`-N ,gğplK7 7'u#i/r(N9n{)auNh;6%sE?XOܪ 2vo OHV d=ܼUuBn>މ u}υ?Mm4!3xIɼd֧*G(myH$Jg{ ؾ>'MD}v}tt5\oϝw cZB)Ӝ>RJ,`EN|E3Jg_zx~R7"(ܔQwvs+J]㢥7br0B.f4XS91Q?Y_!` ߿KeZy!~r7cc4|@l̈́8Ó< OLs0<gB@|2IbG=>]yvbˆx3ia&dߋPRø\ơ{#͘ayovB+V$7>^T iY'kӬ^P=J_/gbb'|4Xk2Np[P V9!ytafs&ubz(!p+q4:ةO7!^q/B1%ّC/3ULMB/3UM/äzOQNdIr:A۟BAӒ~n<>_XPR A?zt-BaT Dkdw䵦kz{j#^C;*3{~HeTgN+9̡+Hc mS(9-ʉ-5^ kq ry4WDBs/,]9F?ilLX(SM}TErVj)材(>,׌3[O =fg-B Qۈ!j# 3>Dt@8yDt :zrZv)2T6Y}_){QЅ`6=hÂ)u76r\ӗzt$-|0RwP;xW(,_Ѵzֻхz+P dH$sPVTWT/K3hz|F<¾^|6ɓ-><^zoZO{ZO7jN`߂咨ݿGt9IF͓h@Vկq/Q(2{ޘGXUUu<[~ΠR97Ḣh4>T;i'ځ:]D6"VSE[d:"[W78_Z1(%aNv*ScS6y(Hhe+SE aUh|O(XkC4E9׸KbV#%0dǚ)Y-uZF>[SMƀm hI4@9@KrD5Ev;t^xAiE asGӇQ4ƓtSD{6Ѭɵ:: mԿJ˔D gAbq/E%zFeȕC;@@FܜַB w+s6"cL OIYAH;'hǣ5},,)[&fy< O1Z}}fn\Œ" 'G?QBݬs[ĻD[">>Nqac$J3hs6<)"\Ѽ#'ٜ X|xp̪<0QkJqܐKrhIr29;Tw<Q4VS<r ڑUXqMSJAl rBb@Y}daGLwz8XW9XؔK"Rjhu-&ZFbbPm!>9\$maә}y`ߢW-*@+oq4 יBw9RH_x0a~'r}b% oCj*v4/%ؖE!]YsJ} v-P9cELݰӪLZ0v痷ݚ |`1r )!}k yު땸zvk׃+>{FFH8, p,[ ٍ5j̷̣K=˼W5}-1LYs;/vwv~[KKK5;{mQ0 tJ14ZvLm~{3X{[{ c873t:wfhw㾜w6w_2u9:$U۞!C6y[l'+69N  1^N?㼣;ymlODI")r4xi}6v63(=!o vbr~zӖ4uro7[ȷxMqq  p(4;Sm =ggQ-:&ddYRq7<576ckM^l;4Q gMrG춛hv7 ԝ4`V6[2[`DY-RF{*R#"miL3M$Z ZC{ Y"9p˻pE_~D#y炳[n>pK1^*?lWE3hiAu>39?t\)}h2"洎r\:`~IJt:h, .V-o,˝3&2!ӸJ+Ūuߝ?Ѣ*ꇆi.ДGAJkUYZU%Ͷ(gAc;B5?>!"2cs-WAmm%oBg^ s1}4,E.mЌ, I~\䜄J^tNju:\.FCFU$GϻP#/~ǦkɔS:jl ԩ-;Er[C1ٶE%Ј0spTL፱%z.bvj0eyFOu.Ϩ5}xrSKϲoxJVF8!=[x(*u1l>rS@osrԣTT$L)bhX'?G {V ľ#+Vv!ͬܳh;9H7O0fu2=o:Yy-k)Wf~b(=+6'8Z`4T ܱNVi3h=GPT$Qyƣ?`ɛiu[Sw]t:>'g<_7 Kܙ͸:f&}zAv0i?9/2+Ȗ2Ϋ[V3.XiJ4d`jpjQFk]40$=P]}$~4wϡnjy l8iXY+3}eұdh 5IhY] oOji9*sLeh 3⇃o _aݡSv:Wb=ª*&\A[C(U BmR+](Bj/!b} UO)=-$39_]RBSOEm:c/ g@*BmEU1h;IxI:eɨ\P.`)˔Y)Q<v vAږr;4(f6#ew~w˭TnݿTo7C#Cqy j #+0g`7*D(Q?iP/xЦ9ݖqo&p!5af>u1K|0N jJ\\F}RF*7[KT]{ f$6g?o :cуmRtskcoru &pS(ybh騃3ӍmMXV/-1cT~kX1 RSo} O18j)F)>p&ރA nٔxt8{옳]SeNJaj҄[r/;ߏ=JYV7^+,K"bP"Ijne\#ұ1G $F`$R3*~|.$qMФ> |4Kf,֝UfʘOMfL.PO_\1m$?qIqwkc{5r'cr>=eXbh$OHnQ:COH&'8H `́S3pI*cج QX)UOSVZOۭxT$pOFPێ_s|#4Ƀy=SQȯ˫S[Q24[i"'ІHׂ>v*%" _CFH 68yA:{7e?f+pS̀m%>asv0E GR3+I>vGX W` XwKj r8>iXLf"sQ7 HD\KVGVZcZqNhh$b>$:z?ŚRSl~֪-^ F_$1Mi^U p~hUs) y/XTP3g `@0ܕ8?ցyaI#eΎ@܎o׃AqYtMZG9-*ZηEYvzIfu}oR|OsSC'A NpSDCۇ]JA3EYk*;STcpL5VMo^߫,3ɀN%z$?!ciT1=Dz2?2]Vqp\QdJCMyF ©akkŌqe`UlQ:þЏ38 01IP'_8&hf>|\';UmZgݽ ǰOMll6sД@T, F iAO.,pΰr|C CcrBDwhƉj5cB?Gq>xJnQqi԰S>#O؄>sK ۿjτ&@7xok&^oZ8܁Fr|YFn!Ւz]?;LEtVDJ>Dƀ$(dS*R0SY<[1eISs+ b>ru $T>^u5r8jSzFʻ>_~ft2[9$G9["; 8Lltjۨ~-F1Uj%A,lgYq0P k̔gEbUS Bz<h BK:uQ7|)V焠W]M/Gb\UB(E^V2/kr&z{a8{$3vR9Fm^JFxl-l L)>HWbYjLw.رSueH5Ms+B$kQTEun_mé: 0U=׹Uُ%iv^S'~mZuy=:Y3e9P5SSc ]nOyy=*fbusܺMkV^Ϫz.4#vXW/UjŌ1c7k8wt۲~9CX+^t*{㾂7:eVu5Pfih̡BFV)y >6,@Qv|q2i-K 8d^t^ZbEr1 o䴸0͙'t7tR-$O9#h6T:0ɵ^jؗA\ wU,ۮmA6- >is}d8)lWfz!q%E%=" I9pmAĎHZ1 |֊)p/'xwmj;MVZ#?rlWWcv0/fG'InM|1f8 `aɉ+ϩe?3rNӝ5(]*ʭe\9UU>E  ?8!-9ROmk^uSE@\]9tT9:X6\B09yT2r JgꌚӂZ%~Tqۂ8_-@R*NƜjtwnL"Sq}2>/rя%;謡v?ÏV0SVݑ3,}r3 U&4@BNggAbqbB2$B( ӕ/>bxOj+F%y NdS&L݊|vPb[Uu(7KvG='fLsq?9/W } s[5%xJd]ΫmXٹQU1mXmM'h1즸oTI !f^r|LG]ү?<Ɵ9 kD;\NT_#Vsw{9΢K4-aDrwM2T!iaXj;jQkKѼ ٘~憌 $ad`'`.ǚ`@iB.l.;f =6_ s xv3άeEeê'tj#AOhTҕ:z@X`WtbΗA?yc.(Ml* pI>1%욥å~NNBfBq҂&`Ee7#rͧ(Re+>[ dư2[&lMWBjZ~C5JTR2bhgZdml9 ,,ʧY>`qX.*Cepi)u%n -6obf[\-.?ŕyZ4?5 ]_ x9[w|%%W~PHp8P x ˈꮎ"?i$66ݽxײycCdz$D ;Imᢶpk7fj W^2<#v5`RSR}.,I6f% w蕷'r  VZUc?,-U1jm)K "yGj0&& ΠsU\,r"П_ `rmNKEDi\"C\Fᕑ.O~Z pLFCXk)0v{# E#Oi؝-Ł# 0  K#;@NsrncR=] vV{#728fO;? rSXxu;LT炾^sUIX Azn?΢h/{ 5V^ ~=z5Q`\4 3O$ ˷+/hZ>$(mUx3=|}`iKbքvVBEAFd/kXL#8$.L'9u[/w: z#N cNh ڒ Y*"Oƣ97ȹ qz_6(< ?k.6^d*yz!^#^{h.XsMvRqEtk*ЛOqꪊyktcÀgV;Jq[_uҝVd Ȥ ϫzs3RW}Lo kȟQ Ibj@@>!& *NL NdVOL9I`=Gsb/3^//J_vh˪L3 YU^nۗw!LiX*I'!fX.Qŏp?ǀq̐;4_DI‰54 e֤zNù\CY M' w(xP3: 8IF~p8> N/0z};^%4֧&xJKYbڛ`mQvqlf1b( k)هnly82ѴksEg&'u>3r] C6Oz#ؓ+"vj7$0iaoȋ7rGcJ؁@C7o^5!%C}ZOӺ ]ʍ̽: Q5g %"?|a0<ϽN]9V\@~ِĈɱteU2I`Q/~X`GUyЫr0WT2z} TH(!S9-9'gN+t')" xq|&,c=:bKhinO}G5$Ʀ#s%8C/`DZɤ:Tt^tM=:#!Www6mrՔ0-O0`Ee>(G|ధq& t/,Uwa=ceȅUUM4In+xbbHV눏Xu=쑄|ˍ|[nra.nwm;9UKj<&p+?7uwK߭`Vˏ9+>0@!l?hch@*~IGd z/Ȋх^Dג6&|"hJm03n8kΫ ØLdbˤ@%+QRѿB)-ꯟ õt;qS/2r7M Eo"HPVhY/Ƿo+34ȨWv-}g_Hbݷ6[ uUk Te}tqC{s`8js$\Yyj7W?dX)bGZ@/(FsW(WU Pn" bj,|˪\ 5RWsTPj56N !B'$رliKzzWt Hh{x}^c6ÞTe1rPw,jt<܊nhm)i8'g皝0D ̔}Xah/T ǝ}S}z!E?!N8~_y DLO*N6>k}c/aُV~*[<gcol`.@7TllnlǍ:@Z ͭEU1ͫJ#5h&71H ޸W\+)PiJWxz{>-'AP_#|0[hC(ݎȾͷ!ϋ9Eb{,n&g̱!3g29KÊ<=FuWH/ n@b]JW3z@`W'@gyZZD=WBMz̄> Bf͇ZdsTN8'8'tOaZܛ"Ԧ } =n lHUGW4ʂc]p ="^w2yB遦g`z/:=Ձ\& s] 8rg]hPZ >b$Q{iQ%qn4w^Xn;MsG{V55ԘdwGi/5kCtQߖO e aQ7rmT;>Ay 8%\O2c>*룠M#>XO΃^|ES5H<`a0a}ԪLT#E d'jT͂ kNw QjN*視g:ۭX7WP6`*\DETHIh,񰽄=zZP-5u=O8h9{װ$~ϰxCкE2dzfϢXr d ,+=;m=@ Zwr[}"-*09GSLG?B FYw-=X>;$ˈ"K@'WQo|>wyBge@9}f>3όwH4 iæ$nڈ; 0gM]Sg1ֈXڬȞ;!g\8^+^x h :|˾^+?,&+ffA"M ֝"GŅo=$ )>H1CmAR`cVkg`\jE&oZ qoCqSqDrڳWpva k_t+A-)g,F-'RFoý[ȚwWk\k ?8ISG&○0_ [obAU^<3kR9 K*Z)$zNQ^kN<ә%V g i6AA~p7U4,ɭUAwE&_GfDߑӌ-K\o`+ qCOk%iFυ%6B.@8$02kluֳgE玆Tpe%9N4b:>xsc %:}eoi VMM36#tmRvhL`$ҽ%#"պ{rLaZ38TzVW=iBBjZEEĶʚTُdOe?0z/Y?"@"tPe5R6>ef)p٣ GW[[Rb_8-ˆ }6l:35AL~wtljt?ahed\̔ø$=7߁ߓRXͭ(M NFC4 fD%qru0Vhh7dtStPp]jzP:аx OSKyPq J9h+^rusVa?fN{T;)_eoۊ@ ̐n$|FdaV1e^3*ljOϩ dGUyռ;glyǎ2>| ?H(;tX8FiAz[^T Q.l^!|/W`xHkB%$R`19ŘՋ5*-1u$:an3}̠oNqre\iX:rk 8 ?30*YNqxm=ɨmx%g >&)=o C|tjӍ_α3˩ \Z'@hmD(1*˝7+&N kaflEW+h)v*IYb5 I(*nvk#N6xPD<ݵ[ɼeӗBY:}qQkYXc5jv%D&/`n=9LE%%RdOr_@uCطL #9Ww$?i߽\4w/V\B ZKKI<=9iv6隡)4:L.aDxt*Lpp ?&PEau4_ qSֲm2a4_ɐ#LmM (&Q^ߏ\.D߭=U2qʪ 6TSK0wd xA g#Y4R {ה?26F84Gg62vXqk] I ֆΣs! &b\]>F6?{*t<ptPLtqQ@iI/>Hw{@(xL}әD2 wFzqy3K~gJI(k( <r18/zu{T0Ck :Y餋QܕLZStuR:m  w\ _T7 No2 u "'*,Y8qDTmbxq/W%x@_JGu`hMJh*k ƢCɛ[PaY3]V)w_Fi_M$&w")H!!iC̿Q*ED(&vW捛UrNkd)82Sp >#>k!%oC Ltäy J̝G]6>>ÊjRa(y^N > d޽~ېAR\ K<~jF+8PzS?LjPށ}SW XB^ܩ~Ju rOyڞS0S+BD.AÊ]z/Z򤼟U6+x:+цX~a 16QcLׁCuMӗif&F#TgW@X,!IĸԹϾ@#k^3S_:J?{vaN\TcPR0.wZJ 但1; yfl+%l.ۋ(Зz\y_S gy R1f .-DfX6 XɃ0D"Z]@HZ!CGZ0 nW3,PS; x%j2菰oryfQd9C&MA㌒j& E{AL(^ 'f>9&(idGEN"I 7ը>P<xej"sAgZ z\]ՔebOifve.-2ԚYr, 滫ou:l:Ȏy 3;+I`1w)cy3D4eCW5amVL@9ra̢+TQ?zT]0̌dr|┪hҐ"ЇAkn_gYx-RqJJn42}x> k3E#S`8]ڶM_V d-09|g:Cwh%UtoSUχV"񅙾Pz I nq֯9[Ʌ! AwA j(:nehV۵C#UO)QeLdLhI )ɩIpQʳ!IaL$(̮ևE>_\FY p/kSNzZW~fJ`Y+:rjïӖ.0e#Pdi.Nwކ쯏 0u1!L07ݕ%n?U9)E$\R(:;CMWf$zSCFC.fEUpvp\y,cwGBuxԚѴ(&FSW-å`Mԍvv.WLrQ1F TČX79Z! ᠃>#붝L1'gmL(Gv/GɁ ʷ%i{`2@{@,5ڍ*R7x_Kv8ѳ!<8(HK3r-J֑G[ (5c"d +מIp?5^cƈ)2ڻUbG.Hw[ӬLdج%jh=̦%vyA#:iWtzU}lMlѮJ<˄QbvqSTT!%/"%Tu6N؋UwzXFA`BshmWig" w|HjPܛiJni7C[=٨#'gѩYX)QR{/7p94&eP z߂Vw̝;@bdFQ?Ic'&A"vMbdAN3z/t^l;*,F 6s&&[.^reY \jM lY1mŎd`,@!lRg.J'/1u<[ RRIFQhu,PjVĚ8c%1)Q58yE' Ѐ$3D%[+i8)U{aQ2դO#θjT䖜kz0F)8o^er:1 INtW6}^KskndL&4 Wf?{!,]_PFCNd_䓦n9աE]ޕ:˓t=j,"F!7ɦ 5 _plFo ώ&%{Zztv}xs;sӴ$vtr+j"0/XpPGeTt'c`\4e\ZRi)qrO!7ǵ#_%ݚy*h+}4W"N~N2J| ly EXWY r<@z^7/sphҐceo2|r6fH,RqHL1~$M}I,-Ir0ƣ8 K@ةDy)рE # c=&'3a`:Wcwn{QB+4d(e.(/8gd4RI&ɝZKKۜuYY9 Y9~& XP@ÐK'fRUfkA)1+0GRpG!2i$"j"E h C{$JjHذ2f] } QTDܫPt_hxm qJ=i>j@#6()GBݍ@9csmT(r\n- 늾ה[K"VM050д!pe(.ǜUd L1,L SvwMJ{h15/^`هGģ)M5G]6b&%0赝̓X86OW? ;c&t08 i⡃3 'hͲOQlX /0 & (`")8jd!``2L# 4 S?&eg -7l`Yf}^S^N=At^j<4|,)NUy>0uץRoRj3xc.ZȔQzZws,2R(ԊSJK#fBO,k4]q cVa?B~ h3ASQNlV9y:l/Hvz"SuxCȟOw@)(aă}Yɼܨ )JL+Z_yw}ݿ (*'l^<,tU Wy`қ=Ѡh҅Q5JM#pT1"BMGUJ4[?uYu'N 3Ik5kF8&Y 6 yB䂗9maBe\Wn6޿lпgT0^M$br'h rWF-H^l"a[%ΦHGſxM;rL{Cf`:s;.$܄.;!軲WK.!s`A 2¤|o @+ߚO:LV3 AR#@:^GBTɹms֓rtD4S2(0bmt^GhXNS\ӂ:F JrP!׉q4,qM&n S!g]BT&(@D|M[P(Ϸ'#u||Û:ʰGha[J|2Ef)tTq{haIEz%gC#u0nv+R]dɑ#ó]o|uh=POE,2{PxJX MXƬ_xBSqg`0z&Ș cGd1(<;m{SVY^X p15)=$SOg!M+ 3jzp$NU$IED9=jmLHt }ko{筅ovMv5(.AwI1 tBf! /{q£O1 + RAHb[՗[KejZO,\s0n=@>XS!NFO&8G" ">!f8›rL_ F+v R9(DB;䭿WO1о;v.gzK=(壪Ƅk&fV *4c?᜝Mu$;hC4$'\᭢pv-L)cCHav;mBU$J=)-_38Oř}^uV9/ Cc[l&Wb6JԮ-AXe~QfU*I7_|(i@0N=L \8s!g;9*D 6zsXx-ëa a޾{Zw O}>ۂ ?A#ݓ57^ld֝Vmsk?[m}|Gj"t ^0K=zgublIMw#syYUlIzZHcsHպzh u. p΁JS z޾&NHI7FMa9=ęڅJA*#Qa*;!}% +p)n]# ,oF&;խϣy4yc8>CRA/o ̂cu8.)W:(< ? FlǕc[֔N֪֯0MP;T6Fx\?B5ګ_D=袱]ɧi/ Z[Ѡ YO=mN=E{@:ڀH`*'a7@=s@UGLgGIWK(ƞҫty|T+t )HsL{1̦FF)UZEAS2s g$9nZ#x"dQGhz3=6^t`5+e[^ԕ5S-eI6,'T'F{kwrbR(:}=6Par3zTX zѫWf&ױktE](<gg 4a:Zl7Vϫ>+y]O @M* #K$Y*uoqx9yBtu'VneՖugQV W1,P $w;NM;n빍O }9SSʙZ68SDoL\.67鷣~ dҖ%7DQp~Y{'t@Fͩ܋:~k|z^(t?V[-&'d|L-tY[ziC9@kjc/_6W ω:<rx88Q2?!u nR0CdM6Iy;)J@s%<L** ֳ)(4c:q1_b6=87~[<:}[|بGuKP;D8"d_2 Ɨٗ<2eP+YqO`aP9sopcfT;^pjÅl5  U?k6MFdLQV 5?:ь7Yx)A3jMigކyL\_!ZIIG^&昧ך:[>Ppd}R8u\ Q7:cNorTۖa]֎9NwGQ2vu/-r$b"#/HftP|"6  1 Yni'YaKslFbkbȰ7揜m"6mQn -^.2' ǩk[ %}JF3810 qv#;j k\~ Z}a\z)hrO0!LJgyv_$pɻݮ:F^*E!5_dl%uEitg7y x,Պ2fǠ`. suˎPw-K|< ֑= ȱ fM(dV5ɶ!՗l K Qz~r[!QI59ulrMɼcl셥-hHtPH Fb-m}6/ 31y<fggc1O_7[U@e4l˦4!]ޙnbO3WjłhHD7^$.$|zof`gZDCKSl١,_js9U֩ixm>N,d3"/Zw~T[Xh|њ%#K kQ-U"0#X2&Ll} cb$)֟)nS@hWr z9;ZvW (3?ٍ)k=z^(՛itTD  jqyi5 6.7q:x0!;S"1|AR-TŦtId؈G6לBuNd"3{J&]1]ͨj ^TE{蚪xZ2՜2l^:G$NVƫl?yS]`gXTGSY$:fll"&|0X1lZ ^TLf$E]\ ,gQL2حK0^?1 EQX~/uNW}2{1Yb`X?IQ y,68&+5. H"HA K鉗Is}PZk'"ѣ'Y1t1f4G507Q50/xJ퀩vT*Q$r LTUcch$ kˮlGf: pH@s@~{1!XQXONr2jq<)J%~:;:;rS~7&`MI0~^́'7#S 0xYw}>pGgx`/z 8ܐCJ^ yT]52NߴW_wy\HTE};oF",E>r8MEOasdI 'v|`dA>ӷ7 )[<8Gݱ& b,5cPj~հ_% ze<jXh"σը:ʞW%&Yн% tSi#nb*Miz+I%+|.S69~[1MJ%ЦR|GF/M7N9D #ST2ʞb2Va.6i4f?wtς\7-E7@8HXI 70pB ^j3nK=5EMX&@ 2u 7IWqR/1뉼LqX(urM7.IqkO=1'H nHè%IXO`s/fa'׽MLs5U)r򳻷}ei<߈{QZ)|fYE}z(Q^=I>gLOpОztyDr<|ג9J"v+VGijv}깫`3L,ȍ".e{0w(~Sc_ᨪfdDbtΰT4]0MI4λ@ dZO-z\4 H9P6M%ƶuR& 82̊Ibk[i3:˞V1P޴JR&nY52`Qo'gKN'˴M9,7n ':b tḴsGMEBk6funC\}'d7;m-JR*;Y,t&TT&I:ٶIիJeT8y Ni#}BXszM 50z͵烨cOH?vFw C~'Yx85R|n;||9_z !t|G:źs|jȢrcnD}% (E4Σ=͔BEzfpiSA$cD%#5N^; 5 Sȟm A-%\0+e6GJ#,2K#ƃu=bQĘ5$FF&MG$,Ѵum)׸P `S@6NqlsT&p0c{Bq}_[: *>=:$ ĴbH(?(!$rU&l{6 kk٧lz}ō-P5L #MV4æA5$KdH$ nc"b^x /Sy)`MQls8>&#6D5D2\)`J /z"QM6¯NTzDF]; JLb.J tQ . &+.ܹɞhYm(Ev@;3^ɼȶc%"[|UJ2| הP.*!e$bFhJᗤR2[pk(HhaEXtevD_TN-Cdw.))yQsbrB!#gD2YjV6 h),6(5 - mdv>T0L`$/^MN󊱗C0r! ($hc2ݓh4V%]~TFPjtj IY;+!dvVM ʵ,=4Wp,aZ ըa>TaX7eW+^ ;1^4:=WqTgM@8vi5|QwNBc&,>&e5T~ԍQui7=zt _Ybě&zD["]>;gn7XP9{ߑΙJwzHpe ԗR.hP PgA}=b=D'P7dD>Be:O4݂Yw@տ7gNs{ѻB'vsYoJ1{K 7oqmWal FS YmяhO; ?p5 x.l@$-M.亃D= mU15ݍr"1D X;,ewQrߐ!8*h)-W%MKƘ ~$f5Pϐ:p0a_I35GACY|3aLV8"MLKOq,8w \P ROyiX<`-~j5VlCi9Ʊcs4['dMeuimpI,{QV4"ZIm>6KX c E 3>k.HvHoys*8>?za=;#q#ܴ6&]Ln3(T3!p \S#-H&>B6-*}p;kJ3y鑱Izbo(oXuB5[_p36@DIfFN=۔xLWAu[7:TsjBva,!%7F^PP/vgS-kj %n6l7/;/;[E oq q+aq 9<`s`NMZ1ixLJX#vkØ-m"$Eqdb ;|sCl÷%SNcx%F"Gi7dT̜k7Z;C}$M+e~P| ƛM?jJluA<:3cIHLbooez`Y?U7l'-$D0Wէ[sFohY&NМqRwJ%rG5M<:cTU>j,VZR!܎:'5&fJ1B!Ao3<ݓ{"0qdp@xKa ˾"ݧhcژ9H2uݽAsȕ39hw41@3{?K%@ })XXe_ qc{8*z' SLjg ok#d<:ke8c x?^8"\TC: 1LΞ?jV M٩x%rS 1 lz?+0qj3lrNgu%)93ξt]8 q];d: Af@0s6e)8vEK@֭C:V8CUC#h&1 g Fb?&Sn==}o:[gW[~>]Yj?K{Ogd $bUd0`rU`/YzsC #FAw~m/ݓJL7gw7xvx裔p ֍BL% SϢˈ$V& t̜}LLob1'd(yч=qd/{ZƵ(ɥV"mf0͏]ubl[I;i2BXai x}j,)CLN9M9A#Qdl`FJ+tV?n/~Bq9.QIWIP?;w^+®18\M\|Ȅba'ď/ ')d$=%&مΙ~8d?5<Ԛ4PkB~]>AH3Χb.at*骥3 GXz:MqgzTJ׾9|: SδDN %icpSw%Nh>Rˬ9 hBE{DŽB3N9}nB?dɊf vGE:Ho߈\0o Qi#ؒ3FD+=S6(F \̎16D" }3Py~ X1pr`B%]-a/BI>Xr!50m(?^^CFQ]D@ FzCT9k{Ve{b8ACs,ip꟞vCh*&] }= @8C\nD{SOYB SPKy( aՍ1i|]ЦC˧I&5L%(ge-I%IkŒ<5RI em,V:EfPV0o)Si̊_s0dHi@% rURGUjIcaS%j6B$trq64Ee!"6ͯ+=0j.T%}j-=сr[O ZCOI6؎̡%d僃אVn 4ؠ{k%ǜ,?km ë^. f^Q'`@M]ʹ!0<5Fcl{f4"֋w?mܼګQuk>Vۗ?ۣ|+H̚ۻHC?oU 8wۯ7Ё7 S*GwInv;āf`iH6ͭ_W7ܿgCAg_1uwR$=7n{wpno7.1Ir.;;)⤫odRSHZR2dKD*Eo*UgWkgO^Fl{/HI'y qğ)tWJ&q7Qiw `-h'9o9)OZkæ@7q^FǂÂ5]ڃ{IYv`WJHT[wJXdI#9yFkaYhK1 ff9\BѢF+~VTn,~Zh^$R:nqdflG h70\ a/CYd,A -fVZMTDw'MY٢2Hpp!Ysa2qo1^GdUԬb >F;PquIƕfFX]I G^+e[45AHUxpz{Ic'{%e&*I<cDT 1%!Soڥ5uNW.A0띐\ uJ=O&.d@5csM>%CxO+I)ϷIhob8)/p*_.au=\ut%xU|;=FSyGfp7]soSϝoYQ-u 䱆:_3"_b mg>=P 8cҐsޑ);,U$8Ϲ9EqR}͛k^2`ۀernWu:c`繀k!SݵF7Ȫɋeb֩O{j SNrAD.i)X{K- {׏,S ɔ:8T$hJM}7{>9JU^vK}̸F\iH"A戁d{=q,PRRA(TlnըzG+_uԖK53맪 Ŋ_^1!I?N#DE*X㿬ns9霓)bow'KQoc6;% jujy *eM-MX,[7xhg%j(QNQCj^GiĬs*&h@\??y[2h*~3jJ64&OZp7) $b`ai`3 5#]L`BUQgBBJf:BbLHA@s!66 fSL4HB_XOEc&m|HW,Ps4OQDaRok,["Fmm^lER街AŨf+l*0LN$81R(DQAW߹42߽<'&'ݠʨ =Shg8Z5[€@|ܨ>BE<e0Re*e]U3n9]XC5 gUuÞ0E"ctC@Uʛ`18V T6 ĜBT d~ i*0[ lJq 7\逡mT,-GWǢT1l *s~pجxwWW3ʎJ& s6gWO- !^5 mΰ' )!g(Vd@ zeԛ4seV݋ʓuVGaƂIIVND ` ~ʖm2hru;;s,[i,a4"4c|Y[*lRP"¶tWLAwo^x .C~=$ELNr.)i O;PZRV #[w]^|%re{V'Kgu[L΁`d0]e&ΙN)-5vMLƹt:sı _̸+l[w#,"%_CNòL6 wLMXܞ5ק 4zHܚ j\$YE J* D;ؐ!:'Ga0"Mu D0-TbOPq\DE2LJIkoCCvJ2'F+ Ap9Ksc#?!=Sd&:XMi1?D[}cAӛJɻs%VI"gnpNF|%M)(щXΘrۑU}$F>dpMjLN|kǤ)%a 0"lLbO)6^B}ݭׯ@gѭV9QE+ ykbڙ@lx{ s)i*:С }epGI0I k qU +2R3UQi4IbMݤ^הcv\bUkJf$< $ prx+5+\`8 B+> *N󧍏UxK27FD⟞P՞P٥sCкoۿ@v)RᚸӮ}`dr惒ц'aSƻUΒzf$)%eJٿA޸eYaleZ"J\eZ,}zu䰮I\cvAMhc飪.99:/mOBIJ6rԵR9A zJB$n\yTAq NLZ}Ym@< ~ߤ"[G|ty@ 84 1()$lJk0S1h0G kNB̲GrX&P1B BB V"/8G@w-"evѴ]zy]enqj'v2?b}kX}2a?GtoLFT+g<@CkG }:|mK!U8߰4模dVX$(\FfaN`4DWlZ H=|lWb7-P2rf?jhzn~BK {<$`ZٰBI FamO\}^L]]Ph߉Ԛ]P$sInqDiY:H:|㠍R͘r:)_p"UZ_'Ԣ )n]u]qC4!'ipY Z@N%e3Bw.ZY=ٴ[+W &JP먴tdƖͯK/IhHMXiL3y_itRz/I)/f3bp"cz !.ioKK2tu G>VK/ X>=wfmUF4H2y6|%ڑ#ڏz Y**4fVA!\5Nld*0tRZzZN56S)јxmg3~8ay1G EXUp >D~لHӭ8N6ƥWߢ^ bl=-9){6x^nD2RvaW_tt~p9`)ƲN/-x!an2 $l&l0/WV'z7B| ĸ%9}\GGJ!E*/n0j((LY̓HG^c H!RQ\! `T,MS:qmLDp:eoTpA_J_SYX^=,b-m˵V(>H>=Hn1HP[X-@G.Lޚ:qU8+JWsveVUzi!(^nԯ}P| ,a)_Xb~fO[/=}0HCROR&;lj9ν}#ʪbGuM_'PH70݃sKfVr QuF6=&.8>'uFNMdy<ʉR@- (`P'`Tou 0@aňŵL4B תqv "H];(!LѮz:[ N;[mU5 5.y?#O~+(.;@}1iu9/7M8n98sm I(v3Xʢ.ߺ7xleG#k?{׷f_?x'GtǞ1ͩ )k*bYT JFfJ atbӮΜ64) 5B\YXlx0N6$tcbȣ2npttuf>7eo<9=M|Z؞%wK)bY;cNeкIg^y9QvViW2:TqV˕=46N',lCLx;az3 4B;3%I'@ 캯wq.Rb0o 2ߩujlU& τDep?c /z$c?vjPM%txGDUM%'if@5G GJ?b>mD\Echh,AH-ŀO[șt!TLNo-"@^=/m㳡Gu/kp WF$l9%/O 316(*{)p7p | }Ȋ5PceYB״')He uX"r+;2qY4qy7#^KYK^0$tvuوL"!^L9 3EF\{&~zk|-,[2_ N_g ] tC+ck+ 2 RcFNKc Af5slIu@T xYB]!/hp7)fE t C 8*G* `S<'gڣdeEAXv订1aMbGJQ6D3q.`^;f`0Ec|ZWHO`8xJ@q=% X{_c'L9zP^p޿,JH-aY9:_&l!j˘}uK66ڟr9*Be ONt3CYxmx=J, >\8E?f6u=ꆘXq.[ ,k2|Y!"4LIr0~GF6cY#yy[6֞zk5^`$yR&8ؙ583s&7n3WoeJI\^Q+mWUuҿڍCDtв]ǰ[$bFmQW41b[f7CԗL5S.š&.Ŧ R}MD|L.(udpREH44]e1رWiqڤ䛔M ]i m-LBq< xYC:NGH0a}Zsn.fLBias.Կ%TiQxd|6H)'3T֛U\t*o5 ZC6^ y'rAAOQ^ ⲡppgv ;p!y1H@\ ;|``^=%`߾ԕSu|Cx-! U'6BzF랹EonUǯuY/o[‹{/wWQѧ/61}}u T._o?yrA `Xsv%U^@[MyQ!Pݫ//?'*0 'xB= NF͕ʪXUCAGjOYSs '4+$ "e ,fp rߛT~[E}Dh8D* zדnZGMGFKC{QSpP/ ,;EAaTe] }We1WunS=}{}K缄[X!퓧^{uI[{܍2 )'/ʿD!0)"pW(l}c@uvKO rNAG.áD Tٻ"FE&x1]`Rl(9S8Á,~qK?+Aχqܿb;$Xbbok}F !cq.EDS JQ~4{n 3l'd d TfkvbНU]o\78dFoymʪ.XG),gO0c'ΉA1L/4 `W2=dD;{nNh'+' &Ч{./f 28C7q&o\W{{OL,Ƌ{] !Fa0:R1*׏,X1d.Oͺ?5Rַ^V߯zPrOi^]A{*sqh'nc_(9@4%ܽ'# 66vu6a=0 U 'X(t1%bɸՆm Qo{(` 6^5|= V~L?T\Rw:?K ,bLMUF <ؽ듥ɍ7\қp(t 2;]doQ1[LcBۨ{=ULB]pznڴPd)4:x@acϐֽ`wpm< -xO ObgYY2E(1Y+'Lz1\.dZ#[[AK:a`^{^ZD]?v6yln$C[h <뱁`0-FX@, {GvP|ZC!y![$$*{~w[ t׉ Y% "˹k ƁX-g K% z~O>sƛ`_SjrA<8?>FSE0Tmɓyfe3kX#u54 ~Eh꿄g!Rr#{ /ͣ)(lEt8;֍cg^ be6Q{w $<}ۭ{o Aw0^aMGW `I?6)nD:cRk"Su7w_LyzۄC? OM ڵ,d5.;Z)K{ )/ɪt@"$ѢAZZ?f}|ɜs3xbޛ }oBP,a(`2OJZO_!̋1.-!j/(tXMD \"NMtJR{rJcmKNMkc"YߥObh}1k%ʋ4[֖:17pMiAQ[i~Jl1P js&(վt^Q룷ݝ_5v hvC,?]3N^>LC ڳN:iAv!&vIϘ_GŜTvg 8`\e ϙL/Tjӫ,]&:h 8`"L.HC.c\^`5ʔZ#=%-)l֪9V,N3&? g(.p$IHWUwFVIN]eeD5wd 47@ձI17U?siSLɻeKҗßsimޟC;M%z9g*K68nE@)k`G2D+*RK:ӐPUpPpOHnM6V}ZK~zbQCƩ9oNFr|c*N idk[?A3gӺ%}!y2>p71,64N<}6gWqmNn΍1T/g^A}:p~W؎ v[[|O2kȘ|jR`~E$ [?`*G zQA~O2׭{aX ,yZe$/?I Hӝ]/1S\ԕO^twbFnIv:"[ M ):J/F\ Mv2gBWߟsv @VP]T2R*oȯC+v5[7ICJꔦb/>>Ӄ,Wmw nNOVqdF0[8i@[)ʶȧ%W"PEQq4yvY=UH*"5@/Qt£eaL^ 4'ߝmK$MFtK?Rb7њMDVeIg1èL%"I!2{LE#9uRߝAw(,D+c[Nrf_/o}|_ p[6A4+/!VNj 1Kh3Lg 孷].])/Z->k*8ebpG S{Յ{B {cCO~ڠ~?g֙Z+a|O6O2w4l9#^ Wy!V)+δ0)T TyJV•_ ;7$m>Pت 10u'=-_%eY?FȥUшBnխQbΎ;p4gAcu0`ۻ6jWAc|.@!ttH nly=7Z_'CaXB3j^*tN5ZUߗ΂mg~g|&9V*7Et]7uc)uf!퐧-rMN0Kٰ۳H4WH„!STU{f!&=wgavs- ].zݭbS,v+%R/vdi4x\8:[ 5[mtpAg>/>PN 3L_sᯚ&F9T)Kg4PHb{bh-IH(P)є`*㏉ }ykss5[~LBCEiE40D> W_[m0|f(,Ӻ6!/4?:onM=~2:]׉=ȖfZNn>f*9DžYu0U|k[YFƂivByR3` ޳"׋.Ҿe `cf4>J8(p ] ϛjPU.l0ۯەe+8&pe c`S'HAt !hYY-mar}ߖrJ 95LkN㿗NO-K œDzK=30wtަ &&3(/(J.@S| ǡU[FmpsP@;(>EQ]ݜ#! M̨3R&|'[Hse`:W#JG5JxU]oWęgR\'6^8h,cZD/Z=Ц mk`iMI]zb&boA+yRUeF5bE:;`f$3ۨ`/B<&D0MΜIœq* 0NN:<ːqgG~k BYcU[1(?HPTr-~ i!­\n%瓃m^J8sc{TM?B"h2T#c v.!h^u(k z{/yr>& Cj4[ŎG<5sgnɧMboi)?}ֳR~.g+Dk,5zNp7,Z)JD:l;@'IzFckq)s3:1R2=[&Uz2{k l:o:Ů)̀uAAީ5anҙ+A_gː`CH/ 9@hGӨn)67o)ަ+] &ěmVw#eݤnfg<m:&BwZc9Bw:Zӫ7I0yP] ?T p1^TP4_bӈ8Z) kecݕSe]ߏP ,ԫev2RUC?!.?j~ }g%=;o1{EKBnv'Nנӵ ůI j qЊ=4wہ7[ NKٱ*u&!,͹<=`sf 6.يC< ucΙ|^ԫ:Bq x$H.;|)E~| 7A^l;W _~Jv0XyWPR}4X%#Z%:ظe_ϭI/‘F;jDWDW7Eˢ*88~3lX3S% tڸAO'z3X*ϵuKՎtxBKk0_ÿʮTi> %+".W,mkGW˾6J{>" AyFo磷'ѡ % VWq8(C^zY؍tE˟?ڴ>+L.,VqN\'Hȫ6[:!|=:6~ BXjarats|*)FJG8@;"͙k$(UD 뿒R0gU > j 슇."x`Z;k  t|RAv D}B@`v5 NB>Y&z#+[Xe!{ı"QiK1 rB#l0C2gUۿ<-λcB!kس̢9s(gF!bC nvLEt+lwe؛?],e،2W>u]z\ śXˆgwj!&fW4r[G"f]Ngy:0 +gz1Y`V1<<~cX34jU4:g4w8LEջb(ޮ WRJ 4b'ΥU6\jM.~iˋț|hϔ!] x0 [J)ܮ?p<;}`sw;z }Ƭ5 ^t]/,k]݋$!l#;'cB8u.T FǴރKKַ[qrفs+S[^Ƌ;Rr yd0[ uc(ΗxyqTP7rB%(E`Bi?e$αX^._"U\yYxL#tD\S|E"bM̯,TYՈ[bh{nn>Vhg Dъ۸" ŭ| f.LO@s2|a "MviINu*G*G%y%(DW|//~T$jν~bIr.ej %yBMyuq{Y#^ڞ$~/v▙YnZǴEȈȈ/SĮ@1[ZMXųq‰Wm5 {-%1t3l%6S z*bGcB.*gIFGlvo:Y4EPHR:;.^+48~ }g''> K܋Vs*> Т7R(2Og|K}mw'"z}Aݡ=e^jJq$s}Yʗvj~c+?^t-IO}_ Ots0%z_^|99J޿ ~Oŀ5pQR6sba]S O C]Օ ^BjM0dѻN|ipS8pK! ǽ΋/ Gt}&|~NrQ=b2.G Td ce,ՔKI?()pK ~[f=~ ?0nnnlcvQQQnKvu5lWV;G=؆7ϝ)JQl"Ѷ?A,yD]\X S~;Ƽw S^e2Cj,Sg3V9l`f9dRT"XXO͹e1FNE?4+'\;soo3W8}}:Ƽ+ON}?Q/?KbcCS$I6o3)LT49u>I98qS2LRS4Cd.mݑTtKxUplGn L"FA [ppؓg:omnSQSD&GYTy]ԛJ. ZjZ/5]/ccvO90o28=Wy=]ern%*.ޤb%NJ K jWS;ɏg SRdW >]资hP:lr{V*|<h,G, t^!r5JQ#ʋp ؐu%U&|lt&A.r w۽|&)VQ^dh=ކ#}y##3]h!i:4%ǐgO'NZ/_Y|)0]dg NWnz-葇?n~H[ yY0ptt 54z5~l7iJs}~oaJU;D̷S]JMh|mR^|º٠pz0iYyUYT <;8Ir,ly䉯Svな,W|00֟qJ>` r_ʫ䏴F#iPLm4J˟H҄k:Xe*2x0k l\gY Nd0^jZKR* 'qn :/EW>t"̷5nR˰aav*F8x 6&l3RFs _Z0op)'? po[BJM;nfdd8CR,f¡L n:Bp[D?|b$S2ru7joZה~=@ը;u}CbB6kXL$Z&JtJ`QW G)q]ɕ%<LJs>K8PQ#lnے'6ҔD, fauyGTCv,ztyom3WJ覆 )Xȩ^"f*|(7cnDk€Y;o$~ : |YX?_% S©iv$/I tiJK]Ւ?qA$U麱<1喟gu0-CVr^uuo3gw-ޖl[@*Y;|KeAl5İ-DD3MFX遺Q!LVdl(0a?6q7IpZ璙0I]E{ ^ժapn*ރwEv"%8.~ȝ uiĦn[Ԩ%j&NxlmM*勇IDh`>;C4`PyL]ϩ34EMO7p.4W׽ve˗1ustЀW'՝E15 .ouuB:Z g0ty|±prv_ŋ3Vӣ S/zPx[XjCWd% 5(u$pd$L\`EUB?pm 2_"9<͓@(nlsoDqw9##m:ϓ37Ni;ހ⿀iC@(fꦻ)̼e)j}R>MŀW .+.|_gxm*gJ1q2nV5vA)2AB3i8jȺM cp?1nTWPlj&~49GpP0z, N(ѽ!lsS:H9GSRѦu7uK ¾`^ \raLD:tɣ"69BAL/YYૃcyVYi_xv؉%Ϣ1kWb3Qh$4i#%|͍_2glY?;8Fgf-7!Q/|2>0o-a Υ4+Sڴ!Ř˵;֊@ /Õ`2MeveNN{lO %t}~ W Pw>Bo^^ 3[J9&s& %Dnī?2k:F"Nz<Ԗ70X*yvR3gu~YԳh|w|$f~Pa|UUVAi]O^`=e -(%I~9e*eq$ZlGQ yXH&Yke_e'~f߀ w"QoQ&|zAg{3CfGLsܑ,܋W0k Ɓ=!)餮tVɡa(˩%lpWhp eκW,gO'Huz;Or_ 99_$e^Z[βySwGqvzWr2J5o<)+f8ÉS^S3E>7(NE$/>[r~,!b,;="5|eHQiUdYoqpiifDr `Q=єүm 8GgQ6 9 /h^t=YC5[QW6m()Yqwi}< #9a'z`R[!>Z@ ۱s{+5(Pl IGG^R9 ˹-@z m+Xz5r5qg^.2 eN[12kO'ojL@ȍ[Cwn7#g=/[1Ѧ}!3# /",]k)-Rs-:2:*;ټk5c3VQ:6^"y`cn1!ŰrL8:'wXywoްу3Oa@2\eMo4zMqG`_瓔s!Lj76N%K\|³|o6RH )RoATxyUȝ,(kO5 ] r5zβMKQ,GgƟҊ8˚u'̭mAÌ|uc Q8ύhE poUТ/Tg}ge+V`;M΋+>H3gi٧k{?aX[Yyxڴw#S$H0Qxny̕s8(!jߕĪBt-L\TsqE OIXS& +UkmQj/rڅֶw/z˽94gg)Srf&;Ex x @ ݴ;#&w+]WQCs(TR>dxq3!oPYjq#qKM=.5^)V1;P;IX"N!mͨ(A/P `ÅDf/<^F0:vMdI!)O$w%5$bDT2{&IT7T?QE[Nת$yvKcTrM9{*(nT%iWQe邉&rI+2K#foa(|O;h"pd$5P/$$b_#?c?\/>EP0ЋyN2@=/!^wK<@ڕ*2PPfF|^Y3'CV?錢&RbUV^0Y$hH3CQJ=z:R۬rIzMG:s!,>Q@.a @oF8ْ:GS& Gm7>xV@RӐEY849RV2݃ޙ58fPmHJ_b 8.3)Fҟҽ˪BN# 6{GNDԖ7[lhxl%,oyNr2,GkgY%ˡ^xKs6.X'? >*ә!H0^9)!`p2N/sJ7>!6*|p9' }-RcxA*PSI5l>YwH"),LȦ)m0BsYi!%oA.(-bUy H.Mf17CYѢlA(ƕELm L2Bt sw:m6` :ؒi SoRcbsǚP Zj$'R}qSL!WKM ֩]" IJs>r(X0y| mk pk$6#:[{Bo0"gcwHhr{|qAXF(-xuP(`OHSe)){R0&~uc]8m2E n${΢{ͻ!1t*Mg zGFں@ Ԣh?cZt(ĥHİ*c|'ܾi⣗6V=F՜\)H.H sPz*{C64|BjA@PFZvy^H1ß6' F tv(uM5^3=#Vl+=6T[$С EƢWZz8B1_X| c&9\M_7E!@|>VJTj,3j* >9G|/ XVp勞L^\"YHc(MYQm6ܸwCib?ҐfЯ%Nf=+fEmm"QeMMkEOy2{S,mHY2\$qXQKMT~Y6bqNps8GI⁩,%x"(TK= ۪{ ⫢pya9}"^PA|DهnjoIS"jupyBgq@= 5M|CbW`{?'g%n2$0h t(uVNȀS^~VZBý?KvnRJS5Lpd; "qTDm{ H ijA1$뜎V=ԙlYW"{(4gq7)&"fY$Ng5Iz~=J =??: [Fe AdwDnacGH Cu8I[,_>q֏ݏ' aibۏ߂"j7ّ^_>iG_Hvdsz$ދ//gmʳj6.q٘#$pA90g 500,%*ٰ(8Nコu*6d- 8#eNɅ̈́AluLtਥdFd!z"k}]l/À!BZL'MC|zpZŨoƨDjnOXlC(s> tR5,6/D1aC+aPY??WY./wŵW.z$/$Pl5mێw#Hl=)mK<2eJRԼ:֤#|Cwzj5mqH`BHLGwY[yd /Iəx\@m,^.Thp3) HQ)('V9 DrXP`5s"q0jVuLl1 uS% eSTì@-"'dcj~E#GCM|㰚~W,Uܸx[fro_y)j> fP ɟw[){(q--w[Ǐ$Yx|%#kǺu"e ھGFۑ@(eLtS<:@SQmojGųA}Z &#ʅ?3om6$PFy~L.'gsEyo2irM:H]Q[VS y*IhR`S.@vx a/)pg1^rj>/&l(S..*̞L|R8}1ojzG B"z\q,\isin&v pdQ$IAOIeNђX{ uNpq0&rp |{"ʧ? r mN\3^DoiC2Y=ؾ|;Ig9/DJI9rfu9G=ODHƞB_X *[MGx2.1g'n 4Lِ'8?Gs8ܳjoR |FS1!A% L^'9Ŭca}c>ŸrX46@UgX"koZ֟Od[3vMPi̗߀o\F2e_»9=}@?^;u3!7KC Mƪe OwWߡ~KB2&Ҡ3V37e̦_t&|low_|>8߿8n^o/e͍&lo/+߄v.@5haJhء޾o R A6ӜM6 a:%$UܟhmsX[OD\rdrJxB*nc*&#/Ջ^]x3ܒ1Uhos*9N6#ޠ䢝0{P}y)0lƷY:4;'ctJ~P7@g&h3_\@1q ӗGȬwsu ۲L>%4\O #kx縛_bQ'簀*m䅗bl)zOs&R-].ggNp䎺ndd'@@JYjFgm{mؿ+;Vgw;ۑiF5 ؃Wwez6~''pXV񓒏ŏ֞"!8xn(KBE1T^\{DrU!~^]5TjGۂbQ gYn`5VQ Li <a"v#3Ύ6ĊS)Z" Gz q,gIYޥD􎃹J}r 6߿Cg auĬ9X4bBF1P$ԻhOm]]!ϰ5Or(F4" +U7%uXvp":M6 EFcVGL%^b1Q&L1Q+Ig[ c4Qk):ph\VAۉRIFݠc~,鿊õ81=\EQB.W 0*kd+O(t xtnʊBH7COYۉM)ؚ^ArV#(mgѦD n C#1ҿA6{Fiփ,V4cڱg0^ǚ;[Hv{_΍zy3*aE =eXx/V,ec3؂-9#:$3 aG^.nQ*T$XZ[@;9.K`:chCGXY 8@w;'H;ww=P@|%Av qs~0| GYx,ΨzN=@+7 HǸ;rY!"aVbV1x-w_DഏNe SHfyJP6s -g 7G.mJa%+%hGI/deϘ7& &Flp)JP Z8Jwe_Wat8SRbV/GkzQ=w NMuݺ)8`-7:)N0|k/&cSUg Om+l4DS>VC)0Ct|ބkvWs!];z2`ȓs3㓺^\%)U_'Z!CHǘַƅ7ُ̫P(qi%gYf{~t^=K{ɂ'u䜅𕊟.0axP Bt2A+X؈GCA@¿eEJ"Ѳe.Dޯ5sF; Uf 5QUy{` 4PUܳ`kw0^ wtzY^`ETd:7E8;I_'b5vfI~R1?냬:=-No(g )=(ɵ&w=d%c?Fl"mR۳;̯ YOocۦ w#>*a^osR)j2n\Xm,:qXqSn\yQn  k;;T`o*;2a˧`c!NRlvKtm~=N~=In Ժa̐ILJ7Q@Vlp2:a6Gy Y e:NcRX1گU9wEE0Iz3a~DzB|q1߁>Z%Ma!$qcde<%a'03w<|Q` >K/\7qJMRz,kx& ~ vwk5Z" z,Rj{D2'_](w#ho_`@dLL>M3+k*^׈PtgMFnLj|O#N5j+k:di_R 3B~0d BOϳ^Tɰs4N&W:eVR%c~_Kۼ?I GG5`o("Pz22b9ˊ| =gCdu+zgֽs#/7l¨J׉i{=' Znnx+l;}d@xh$p8"becVedwin]fTM:yUL GN,l3lrλK3t-@Wv<jZR%hV/aiǴ d 'u'bfAG#}K??K'8#Ct]4KFUljWBݛr.Z-"H@j1KLYD]֯ʼ=bJr84XupNA"tDL7vs7+Ft~Wp٤@hòuqWLh 9'gCX͢.a*ݓ^?RHaQw$Z{5O1< 02d)b+RHțꀹ8w31(V:}],\K^X,ZAnE}]5V} /0BATC'9c i!91MF IHM{" D& XN[̶=ݛu;zDt@dobhl JK'͇YGo>ƣQ*#3I> fa}#|<|;;Gm"0u-իFL($ڛ(~mh Ga8[eX|źi~^TN[+?ΪwE1@=-E*DN'r< y!ݷThˆb9h cvpDBeD[r`? !܍R˻gP6\6mZ0rfO]̙)L$h!:cd&fq%%z?TٙœF,Ie1Jۨ}K=Hlٔh?ER޶b6Wa~+,ըB_̽ 6 <-9 83k }40*2a6j#<꧳tkOQz^ۘ'u0<.QI5'y6N0Q:Q RtuԮ +kϛpG]f,ot)܊BjmFa&M\ FVDrGAKm.>KՍ{I(9%kSt̻W܊"h&"*YSr3n% <<0lEtY="}Pe۟5`djt_#t}}2ӿ*S[ Əޯy!$_ӄAr+qާkufy=};?|Iv5KBPPU;Ou0?{[lJR:_MN@=+Һ݇-1+$÷Gt U n+.Iax5J.r~쟟<# `tu!{(苚ggEy֓‰A+Y>#Qg ,, ňty%]L5"qur0"a½4S!yąJGpҜgtwE `y0Qr# ~KU0ب̆_W.󦛋D&fn1(9'1ZpDujOYt;bZZoDIvUy{*'gh55fb TpjQՄ_rQ٘ij*>s :fp9ez1; 8_#^=m.y|J=aQO,GOTI2NpN.g~_7.'Q >6bYګZ<]Jl0S ]\]V.Qƺar׍'gJImZN ""aHIe;Κ5M񮽖nuJmzJA oJ*2Vɣ=ew']AIVyalP͢U76C?7ӐO\P/%$sr0y$NeItЊ."5^uV3Q6!$)o؋彑u\55Pn/#0˵8-RW|`G#GYN(F6|R+mO5:p&!Tra[rNWؿT?3klZg3Z/jOG V;k`W9\".~3~801./}Z]HCb @9W ALQIˢGxap~M4j?4Ρ MА9½Q/zTƹՔݔ{{zg>oiYQY#iENJ0+/D6ea+XZI9S =uLrj1*t5"Q dk]D@$m'[ᅤ &yGR>yM?_JlB:}KA JU|p6L֬CQk{tYX߇vTప49)6nگ^}v׋J:] fEL ~6v֧ FD5ξ6 $6`3.X+Xj,ʯ_'_nwCl^a_+l,Z|˜S5M Hŗd,ϊؿ(E!gJds4Fmt/$ވZp$גM@)ș^ Q a r>LM>A㮉^SBΟ?\lC݊!y:fYӬ9I[:e60އأDUlh}Hd$s9Z,O.D$VS`>'g p+Y6/QcXg KuޛtrȻ"UI# l6&Z)ܡ` 0^/ίJR:s+qrVpnT"v-xdGE)# >ke^}8+\GaMz0sF)=py|co4&`w$;@*zZfN$Me"cxv(0uBE\~;WV}uǜCoP@{贜6 e$ 2䙉at\p-DԈk<%ը EOȯl>Kl|[xPRrJ:чFt'ZJ8?#/xdZѨy*ez`Q.GSJ:gOl)-5yszr ݬ!ɸ$Yvqճ'疨]^;N74?<9߷=AЈ_ndƹƒqww8= .>k&ۻpW 4?p~=yNE 1buJ<. q h]aAK 9%cDÄ.c(~@k_2Px0dtD<9w {5k?WڅzpC,MD{s'M1g(5)p!Y2xN?{h״„}3bJf%x۲י!~^o[4M~lggʺA\31_5UFWtFkoJ*+C'^" AQG|Hc<ZK TK'|:|>EBMԚɥd`H)W SIkT.HeŠV 5&xq`u^Y6kҝ BI~ HCbR/\xSq Ҁa^q~2Kpj܈TjdϜqULq/}T$-6:!$Ņl~eF>JϏ qbL#[ A[B,Z\Şy)Ʀ/a^lΠc,At]rwy_yF'JfF/S$Qۄk,ԗV}M18L_qo?:AN挕8o-PVY"#nZ\Žg12~/6A+V9'=Xs+%sv8`Rνz=$yQd1_7HXb::jƳc%9oʐ/gdR 6QEŝtwnP#JG,ADmgv?W/4H!%2(ZlV\>hb{K AG@2'W&E}?.S|C.4Sto$ )t)/gh0cJ[GA `킱/ZD PA 'p^nWS?X`W*pSzkMa(yt M<Д$u'\$/b 8s54ԅ+|aD R…g xp_|X!wZN8ގ0@u#,yv;VRF3K]lNk@]HU3zRdNczkUwf3l(81ʥ@d V52Mߒ?'Dڊfs|rqbU=a;+l C@27$7 srO=snUOnz5Xc!YG%\=q"4jT~u*"UV$"T_[˪ʧ[}/c{l(E03ĉΜ9( {ρ^.'e%1>ߺ{F9/:O K9`ze#mNd\ mu~UIvK{[=!\\T.O@3Xp*~͹Ys3 (,M^SFY㷊A Sd5O@5 Q$G$e,W$0 P95m9?7Va{8,+dۛi"(e -.՜t=([4g)H7TJSUtU8~|)r*8Ӏ{zʞ<:V^>G8U6#[\a3)}r%"zO _w5@gNvq+ĩė (UeV^^C9tL1MzojMD0撞d{) R"-bOn=8 yX ˜NtdЮmizx8Vۘ8BU,|j )v\%[.r Z[()@FYh2As:8d;m)Ts ~1l37md7%SRg޻ǧo ApsxkЃ(yX=qSvNYg߿7Nž~J:6vp=Gki*BOpq-LيY8T5VW=a.t UJR>3؃*EaT3>M3[199\JgΈ{Rnŕ=&S: !.=l5 Aィ\ Ãި&~~_y`Җo޽Q#ŀ`Ap5`&ˆ!uњ#=ӎc{mx*%R3Yʯa;:g F>2R1u]A2㼛pF';#|O5o4[e$: "K {InY:qFTx>֕eXO2*/H%#8714$: !+C{e8nsSRES4)!%޴ :xu~.|U5tY/w}yC A0w rH "nF4?H:֊I8v6֦)repUi q=~O'S~;h"asqj'\]ݽ۷5 `߯zy1*5"xRlNK$UlL.otueVپG.cMaB6,52ێN>/$`DžF6B(AWAV #z`a/l7E+U m@l ʡFoqri<͓\Ldޕ]`+bȦڀlvjU~oT ?&=yr *#{ QAt~Vk[v]A+8+D# WQ2[ÃE^ڥ]FeDHrzk([2~1.i Er:k'#1\ e^@,yYDA=#|f:@NT٬=d0V L$ O?^GZ2O]Y,U ew KrCKa_cl7@~5 ҭx<\OR4l8ɤq~FbŚt8r]s&`5GPwa`ӌ#&Bu0[Fׯ=Rݺ?? >\*뙀@ VqFUD=tF>KA,!Is~锍?3O< @洝X `o5ư_N3o [o6~stܾ`GnȯKʀ|ްbK82'jʼ6p~tVtEu&W3uyxf1R%==XI Z͘,|xY<م O@#BـY0&(xY-ɚMλ(h 5be5@yxFFh-VÝxi7YLnѓks<6ꬷDp hHrͽV h.ݢ]@heA#\71\/a"o e2ҎF ?Y+eIW35rѶ]o7 V_VYW Knfy3EiY>2L`5Mj0c7fa-.̲nL%?3U-pAzBw^*q|u8ʪ*wtSihS%SNl| UUjZ%|)Ֆ<)UJWnoG ^Q _H5գݎ>ޠX*wie#bCQ4}L4$C4$ԐZ ;iG6(B-?JSSj/䋜2:^9;ܶ5$j5"t{{+[%C!]xa(a")Fpϣύo$qkj˃ G&V޷kr ΃q:Jъs`}臒fDh]{z>Bݦ :}W|>C)r0,^@/-sb$sڌ$zVr }G * u[. }Tb|!;ߡ82du_M_6|H6-S1^|-Cdd8D:L&.´Ɏn3ꢨi'ת"/R_a/jۭhLs:YyyEO.V-\PCMtd>"Wth!-ȅh oխ9=R %òx^W1,$ׇj:0>GJ* NGY,ﱄ/O8+@F{OyO0`{a@C,ǂe-I(> v/ZKP~DUd0WdœL} Sw΁fE'. lי\(-d$,\3jgIIJ-49 ^lkI[TqwЕCe(֍:Nu<{zqmRz6kn oΊ޾۔dtӆ[V|.$չ-x}VΑ]AVeZDhw݇|,Wj|&w+>ͥK3B=p{j!c0Q [Z͜+3+xYkuq5vWJc2$Kakh/}_. !D.~IbL&E!G^Q8 ]s0h#:ѠP (_ԣw.=yd ȍx0gyye..P]zQSd+ٽ8("8lQCuZQ߻ ?oeRL9I[58mpE%O\oGhM_CCrnҼnR۝Kz?ye+3Ga%TkI!1&o>{gKFfrcx8:102htlJNxR?H`ɽ*_ȭ?8(M=#P5NFXj,0.r./؇d9Cg=_S_'7F癩[5z15DTԼ?%Ar6U.cC3LFs.-0iP;V\jE9Ț86&1;꩕1@Q:U$M%l=܍!0Q pI 5\7 :P> w!/2}t*8grQntU{呲lwk/ Nx~mr񩙬JNf\SEZ^L2r}Ɯ@5sGNn^ f|iV" $DLkvs1[Y)ϼkV, P z.&h/OإVEg2x1̰pbsT y2J#lE>3 5F/Bj"lm929՜')$^N5׷<6ݣCLP5-L{RVwccǾ==w3.dK2R#PoA IUt<84ubĸqҫ c&/F(tyLD1O@DMb{K6eh^wh>#aÄńtfw3FL.e%1t; e (`MO(MQqjD./d 5Y M}M'Âۄ[K:`mCLa쎥q9$?woD l?Ȫj>.0 "F<%B,Gi +TTK#2?]\H8[P8Il}c k ǚ [ 帠y8atD0-5^&tM97YuSrxnb݊)SCu&Ѷ8<οZtT)}Nʆ8 c&S`s2]@ gihsPly>jyGG㽾)S-at/ѼP5cN'wU :T#ϋ?2i 552Ȉu;j.nSiþJY1tGw=ǰGÏ1iXg?TbE?8D:X#jzaN?vMDn1eO'ڤ R`hyueձo<=YsIQsH`ɽ-E0Cvpp69[f=ʈS4oI"Nwob:Fx]ԃY2M3v 5* XboMܥw_$T tףho/& 5"[ 6aƛ ea),FJιA6#L{P'F3Bgn/ߑX] 31 2)> ^.i  AÂ?8Nʙ[ ޮӳ)mxh 9sJ8r rܦ*c5Ã߹Iu`^ݩOJ^.y4"}xmlŦݪlo QdLqnl$70 DXcKnꌔ,B1>zF&h-.fg%100QȁВ) d5c֑t2d@0V'&3lz$r 3Nc&swɬ YZz/4a=F@Re'0Jni LK]޵/z{ {|iLs aaSNZjRoR#f\WKg@~tx*5?-لAc2C|ő6=sZ:R1 n!|[ſ0.nZSf7M]&0*0v_,'/wh>Vj.E<&=K?~hlv OWr-DAȾzױݞ,bWzƻ);Pf w_v t^xo\9s q.r?%I^+ei=$0= ~ng疤!,/8+MTLqgޖ&L-В+ 9=}:e \c.!fR<.&XN=CˬE]@?K |gΒ+<(R 乷1n`3W/2}V݄'`l*e2"R r .&jVY5nxg4ﭠ;:+ݤNqM@( )Uj_c08UQY8~.A s!OTˮ0H0bZeRs&8k/N nzAO2UE<8m\W"nf\gY[s]tM1x4wą'T28= %ReM8IЄlFG]A;ُ'ӳ#FZ 6 L{Mlj>`0ˌMG-4|6ʱfkӐq|_xHmytM9CIf_>O+^@A<11h:-J j:N,dʵJ~1Ϫ}հu* իϝv$71ߛGF^Xͻ$,Լa]+Xgm@n13/I*uQqJ}GdjAǢ\@Ś҇);zbz@ V(àse JQ5o#׉*ҭyh sv*2CS`May),R6R@d[atb]d`rZVM(1Hӟ܈\v_M.cj1,.!Hc# d{]y,٘cSfqzIH}ko!|B|ySMrUֹG:%l陘{습MRg%\VӧMgf2p0Z}w-^n1C+nDi@919Tm p}9zH,vn`Vh{° 1'N',u;yd\3$,i~c~!8%x$IaHnH#rLo ~s K q2o%C}z]CZ"ssU 5ZwMnr 2,Z ӷͺR "JA`|~pGNQ/V1Y*u;!p3`?@ 4Bst,I,짛\UF-:!:I$HK"=d64g21`l8tODw![@g-hbٌ6?MJD a =;}ݢjCm_78mC{ipxk |aCǜ\s spLj~SUX؋,F0up#.\mNЮCFs izgR!TD<tH*zd3 ;8|ݏ3B=rq۾$wuqɗl?\x"U >3.>F;Fk-:@V$ /0Z2%>M0zM{k}7]  $pakcK{13Х:#̋buQw&oPqtϝPjb -l*=xFk<{z'M7~:ΉȄZ̃[jIG&KT1_v9E%7aׁHQNl(;xҬ5)|h óFϚ=wdHJsv(dX,PbTœk 41ߧwO;ZOg͛5P^$ڞbOx'!<4K4Vh90NCt|HctA/EY Aбn]D^D%8h?- ZԦC!nN6܏B:![Ӝ.L}4/Xb Zt$:50)Y{FVl Q^7Suzg#إV&m,a0 r[b͖w2xfmP"xv򹚐ĐcL 0ct:؁ɚQ2i0F}td0,2{W%KEy }P}bDY+eU!^M% g,3گr0G}إm[8?[U>Iu u㫄3fz%/{>͏Lc|WN~69"/]3@VSFxŢ'C%2OV$>#"Z̻nKLj  Ejva2Fy$T7؄`q!8;o^Aeǭ2̒w,wX0Z3̚RNVGWďVPjFIQq&(]?bUER͘ԣ? e&֬ ˬwnHĎ5!^D ]Fcj|%+Va"k_W{UT#,94 K"@g~eD"iy]d5"6er+0;U$Wɕ0fL%QfwOO#3)TP(Ehx5J *piL)`Q嵤 ٭F i6wjt0A.0p+m; 2 %6|Eȧ+Ύ$q6L+>i<ziNSFqG('z3*X_ w@ a@W!e-'79:GN6o3ghlan_l sj'G]R nßR(jVmH&S1wz6:7cCYS4;hUy[clh7S6srq @3H_DߥiDBDz`x)4yA:فUufI*T i'dI?sx&0ZgYL(sdÌ%_[7_PV68e NϵH4Pnok)brlﶡnHx ot!f&v &\?4$7os؃;ps%oe—B_J!@qRDrϽ] n]NJ/T;rX;̩SÆ>p!Ҡ;w}oxfBU>ȓL; υ@07TQǹ+G# 1 lI?kr*I0u]?k~1HW\}W@APcTYDʽ2 Xb~Ā*GC2 ֒12_-18dof-qg+ c^0DYiPF4xp> 3鸩AA s\(6_z h 9O'xpusᎪԢW4k/+~\"~!&Zj8ל'*jY{6f/ QpäFT6N6P7@Z[KH+N0oJ>~2ήi?lj([lL*{k 7 -ܩb~b ]NK:ҦOF$ܞ&!h+jj镄v h -S؂m[&&I .pM>MPY2@aI:r<\Hf#LB3ԏzB꒐:ދ1fřZ=Sh>lўFvAiS}!T$1jpw;w4&%OX]&H L؀_0xi[5*KJE}8è#n*SwqsxxNKZzK4 t~t3Ts1x]tQ, -sk. C4qh,էV܇;Nk(ZUpCf\ي\;i\-dK쫉,7]NEfsϡo|r2h؈4/0%Va3U6eDB2%ɳvSe+ YM\GQtJ'Z XVCS$|s0&sXSV(2Ug]^V$ꀲwP%ŐhpNdv$@Y{b\!F-VB~Q!eڱYѽ`8fJ9Zhpv~f5DDn:c|fx !͚jkؘ/~<;8)6#Op5 G½W;\| D֛u|O$X.ЎCa?FɯCg@~W7ᐧbucj؂5_N!*w&/A>uҡ)M-}ЯGC(#fewq>m07HVzhw.` DBK;=(Ic۵u _%uq1=nڅqؾB>33:dw v y<_n1k|[/e *>Irzv:hw)M4srXP&#/&KRPk)O)N1(-q :M)d9YwFLup̖#j, h4:AkJRaKZmIdSa:j* E2sDńВ KK&?~MXjm2ܮۇ΀?S9}nnJbb6uARnI`0g\9E9p'#9ҋpL!WBFT_Xt.BNgj!<"m+*~{O[ˍ4筘@“+9v`15\AP>GOM:\%4B j߹NHN#ںEiw g<8-yi<@ʻ_]+l2zkZDak t Gr1 :*=Am%"K1tLŇ?w oy/cS!ґīc|DzVjca0kyObwkA<;|l7oqGgZAʹ#ֺ [He)}]niJ,!2e7FN ]}<&b]Zj>v~ʽEa5;|&@)|QgICwy%jZ6|@*MW8fGUwlmxa{2Pok{?F f S f|7r(h;$Ӌ͋~[^^t\[Zw;:~εgqRR,+,;$XP*~tw)%a:48Øc"Lxȥ`*[U/ gwD3m |-Rl3esXdV<uXi$ʄykd`xXbSH>h sV vJIE4"4*H]eo䮲$KPag&Һc~Pֺ@qC ㄘ^w-7Fe(wnl =+R:C)t7vl4&̈5 Lk1J[47X/heoKUܷ+>Tb5˛JK{%\^ySxdrQt?=}8pub2wpݭEՏ{=ߏ·n-ct!.dc~3!k1g+]@Le~6_,'R;>DTR''΢?FV=GPOWAz؆ZA*Fg#tz8ڿzu8.2p~d1`ӂgic$q̊A8Xh)^wpVQl*rX I7O#͆LGWюQ{Aӟp2 =p8k{~qBX5qj'fxbj<-P~Uc|• W{ QQRJr =USDJ󊅧*=9:=|{ٕ|Ѹt%o1k4&3U8ce'|>^8KOb_2.S QpVZX 9dV+%}iv'T2Qn^СK 9C0\H^/℡_"-,^8ߥRƝ9Tbl}|qJ0e27 m|/#߿EM-kWoz;@WkxWFf mef#5F`c5TR͵ 7fa:Z<Ér2 $ɯ s/{ R _߉.%I'r.sEltrظ1ܶfZe)HykSBlf!oUS,uzr{]Fiz*<+Ny F iL>*4u6o@Zw9K,Uc̏2Qd萲#t:qv|?YG;qW< S@Ch _П းl#"#*ǡgN#}S_%Z[v`1cq`: x1;j(Q`2 CFGK22a>4|p wEg'>xo4a҃zL- yL_f;iz~3.MiAr4@R]k:Kj&2#JG@ۤjWj@Yj GBXp' Qhɕbsk8k/ ?w-̾JSoA;Ƭ6KwY`r36u \Tur`#77G<.^ 2-8hT )>['&trAvpGK Y"Cϟm=IErmb*}.A1)/wl 7һ8"].(Ayvy+hOV 7@V %U.ZS{>+ >## DZjdC$;+ytpA,MRo/Mfө Q!l%$w9Hʀ<-E^@r^ӚIoQ zɅr|s\^>'ze& ݃,cvVժ#pĭ! w%9?qTdo]* r>4.DGz-XutbJҊf9f+d&=5X7 ThF!NoDzaRMv8syr]!rHԾx&[X~{sb|Hb⸊ -NE+)me Ow x _ΫkAe VK҃-PZ&{1oFV ɖij~[-ޣÅ A%)~Sȷ]͒i1wҒ2.>k y!NOrIaf0=ʠ{fC:K^˯Iצ)3* b.8cGò rb6n$:*Sa$_)pЏwVmӚ܅r@%r"5(| < tfWeX5 T'u9ˇ8PT%v[{ |d \7QsSEI"Atze!( yHΑkbux{}6K"ԣf5jFgvs2{:g?]|.@^͛4e5 $x#䉰h`J ZC x{Qa8~g剰1Aa"`Y 2'A^;pR\XS EVsYY O-{N(M0ƍnq͵ 4Kf񬃍 bJGxk̃ KBMJa!u q1xu;>Qp`q4ك>pw,xj_(2 ai;,R#ʝR cLtc.!m1јaFQ{'w,6o&Y(^83a]j h)OFcߢp5BaV]+\agL'2҆F 2nx`'4WDRx:xV#ʜ} OWr|~kbPސxMɡyoIGl — X)bͅfSB Xo_n# 灛FuRpdIUb]h5M$"5nN-3)\Iᦕ :M<res6Vj#'&7KMzǫ؍oXg`أDK5VWh;q\YtAIA pWK'z%ouRCrr&Ha6!ZwYZ_"Jem9UUE P9n81Y41; 5x^3l%OrRuIJ9Or P˕k NdU*-?ƀBf'!!)k(b}Zߊ 0;ct( 7ℎhU$eX7o?E ɔ}ּG7w~ uhzZG0)'8.-*Q+ e~m ZK'E5p6!磍8?FSr<֌L*ΞE.rRs^%x$kRbzsK,#zұ" x ;Wb28& J1+vb@Qqr3U>M%пGه]fDvH=Vxea)tmF~ ME&?߯"4)Haif׌4_ 6ݰKjeQa6~_Oht$EmYr[j†M,frԒ _kvD9Km CA>Wdsoyuyɘ9~ÍFp-v%!d|arz4|~5NEISc;L{GJ#pyX~kG((G#عL`]"F|O|!ĝ{!F&,D. z*,ӔZ?#UR5!b;6sQO'}Iao=s'A f"Yz1}*iqJkp@ms^7S$<jr]lDje? }:|5QA|}ob,&4nA%h Oγ9ɆhJyhdˤ}1g$FM1L"nFC徼ćJ43eAr/L%-K|ⸯ1mƣ>mS%#8:ΧEwkBL/Mtyp2z@Ih>hLDJ"Qb q 9߽8NQ؅ 'it;Wy,!r1Э#/CJ*T6{ cY17K0^ U_&҈pbN4L P'q8y"b$8?QL&II)%wSrؼ9އܜIV3։M|LW2/{GQ}EQjˏrٙ;_: T5~xpeCFCYئ2 Ö<~PZq[&|0hTͣq.%vwwIǨp35*IAT2BI߭zIQQjȰggwfm] 4o777lnV%x3{MS48:ZFo>Z]d(foo)p膵MHtRrU֫6ԊT?T6[ٽ륬">ގjj:B1H/Coi@tH߉'pk4%!w#-b,v3, ;i'վ6ܷ3̜]HDrvlfBcT>!#{a%Ⱥ=U n(3* O0l إ i0 !z󦤚s+ \-m𹗈LBR&Db)Ig׭{ DŽCP]gZ0Yޛ\i77I._>TM5]X5󡧿ntfp PƋd$9+;Ezoe)e@7[_F{KAtEkAq4zaM +KG +Z+y]韒ᆡqiTHOC ]o6%3U -Ҵ!O󆢰JH 0ӷ`7 kd[5[L l[ۡRBApQʘ9=~vz@5Ck_Ps7??7*>>Or|h }m2J;_I?quTK"t:yh"F @J;v;l~CҪD~ALf5E b?|.y4ez+=篭@b$6s*ds~|m,sV|ml{,Ev.~ig. =oxwoPaY#EʓJv7o]#xZ5*Q!.?ǘD>V!͂?OB"oQըfE,Y$]qݐJE.kQҋ qo+ob9鈃8g漁n[F8e i 5Aɫx=Nn4Ju v=u~#߸,7!&>9ŊIg.okno=G Wӿ~-`6Fyʨ_< \u(>XjH^xJ Q `%prԏĄ>L̥rI'0b W,Hrͭ8BP=bV8x6;1xFB\YY9=3 ʱO\]ժX@^b:GESQj4)*z8=`T5䊾u O#( K-Gz@_;F j |kj-5#VC{% 5cYJ=}G1KA!h+:D=%O `aL=N<&T%:.Zkj90')zw szh}I`80.sbqE _%gCn8O8RU-|O^K2E =mBV2h>΄1E]l/0!o{6]q{s`D.WaKcp^zv9{V'/A{D~?}uvKkV55 _2D< ?Pvqg*l &KlKȷtx ' :8-mzXkhz6%)& !c;eƜ&2lZݳfI"W  q$"?>X4Oҧ#IWT1`Cx<=XB`+_?qht;E!hgS4+'i'(H2( Q|[ ';_Z8NPF "+kZEiaBn)gdx%Ⓢ*]\G`%*S)dQm1 G΢}SzrC\;z+\y+K`!,k\3:3x~wh`WMX7Q)BO \^DX(  L¤Id^aB@bZ2+/5.25B M@E*I;.?.Xm ̵Y60Hǣ?bq2C٥c?D,EH(EJoD%QZ̓`fgHS&V+Xb?)i/v\]+MyJڛKvo`ۼχ$Ug𜄘"۝xײK4\g5`4/P*x"izyn=kh,߾OL- |ĹUZmխZ el-6IxYˊ%]'I66eyVׄy$p(索[D\Z)DD/gᇔéM̭S5ع# &XA`)yzG]q/d% uDZzwa[A+SI@˨)Sy|RBud>KA2Ȥ/=*h%'kƒ'lԺ|q=Tݎ$g@] B~JexCe"h!8=nk,~ 8d."jB<{S6Vx| 68÷41}6 J3/=0 'eaZyIAvʁ7Wr}R7C_:\a;O`hu>*wu; L&dY=2&4%!Ɔ$_ET]8W*w0Bl8A4$xnP7+ |&wQ4imzL|r#_׃E?J`AǮ(ˣ$y%+\c8!ܢd ٦Q2NOQTZիt4JgW:p@G.cW|8O(  !O&6B㯃n>9 Vhٛϒy6aAh<棝^ 2X<\0*Qn:w{=TO2VOV*9hrw}4MI92=2WQ}e'dwWp9 g<4gR >I@bAHݕk4' jDu-;F8Vapc\*v 0Z=j$]]o(I()?9ny'g{8Ii◕u؅Ija`\A4_hjxkpWP ]x\z?sh &=fXfKwee*"U4Oa' &a t==Fsr_V]霟x~prRl9gByNxz_&e3P6q&k}: sؒ| $C߹Jwwעϝ)YC-JjNt@-AWN ?.~_%m >פs/+mG%N_eΉ|γYN?Wc R?PJ Fـ$[%Mi~)Lϲ3,hCz*l!C,Ƹ/S^DC83!6 )U6RD$kx|`³¿69M0PtV{ߨ+jFkxU)/@Pl޳5ǹ|7 *^ z:94: V ڳIG . RJ !I` >6Maׯ=Z^,<,/sLROcn4;K@gZ_iii :?8i;u[( :-/ (ѽK5t;!wF,ƈ;^-@l9 ̓$E Ѯ303P:g)ufzF/NoIo9 (PҪ+r|"58~fO?CPn6 z0\y22!՘$:Ǘ=,9j936770MWY22 )Q-jJP(x01L$(.Dkh\J~¨Ghbs YO81^r8(ʰ(21wTMgx+^~t@XD =b#;'/>;zYAN z_G) %%>ŏ "g;f5~YLf3 f;_xFd]@@h׆kt$t CstuwˮP?(yyFiT7xPZzI_@ݕ>NAq'u߯>1\fFkuZGNt{yOFߓ`TdOqyqoA񑈑ŞR a}?gv2׹#39".\`Uv&tćK+Av>b, =%Zf~2S<=Kp@Mb||P'3`:''I5uh% Ax{re@#qx9'6NoֹxpZ9 J:;'y,5\vUc [9Fy?LJjLn>PXEW(<^\w>ߤxic,Qa<|d1?,^6hP6߯ 2flnDZȭfsZ7|li]gQUQwآge?{A?p}mGwf|;w;m/k> ݽNyԿN3?G^tJxAd.Wī6'S$.BB"#$NvWpc4W@ =!ꋯ9Kl KyjcL}1Vn5yFje/10i eE۽nBi{h |K(;9\>gȦQ3Xfڬ~g'ꌯ@U_߀O0S :# j'V\Ol4FJgp~1L-P.-K-dž5׏[}Hv|"Ŗ'IX| v@Ӆb MVgØ7~BrM=3wƛv+(yk`US(Yt(e,Xsf9<=ֆ3J |DBŧA%jY ǵfy:%$ļ"6vSj47_X曵 V/-ҽ@ .Q6G|&@#Hp`aQ( px6ۍfjuuWB4͜9u>W5ZM2%A-6֮OA+ՀXJzuZKf_q2[0ݵ$&6u qNǗ96hHڲֆό(bnk 2Q(3y5FTѵ)fUW7u6CGf5-pݱ!2<[9V^l&J# h*Hm]Vu'۷Gڀ4441U=ڤ~~M 0+j j`ы\~?^4@2"3z[x re:?iQC_ibATվɒ8ђVgm`&NZ'PYk|flV(\n c \dϧJ[9JnicWFc?|xTo6k&!&=tg-OՀ[2-;Il t7v-]rޢTl2n8ˆoAJiX@(٫u8%$.ad= nt0rtlo6b9R/h4vcG-w:[[xk˲JtƆ0"fj,D=C}K?Amv𢿸 ABP] 6&]X9Z;~Ip"7o+ 7>[o?' #i7TX܋pDi;\>Mx6&g &Kn?s:IrNIR7/@ .-X⺄sd ~5/&0"$ Q>B a3ʮ!8‹CoWeQ8@M- YMO.ͨľ60|.M),MR^CR^F3Zn`G985V]b) miߖ։4'p2*nxL~jd#{b@ ah56nR+NlN ^AcM5@b%o+~x#XH`۵`>NX e z/iO;:Y }pЛqbԄq|䳓 38t>@>>]M @yl%U^9\ >Dr]St^𚪯|kz0Cf8NhiNޟe IWd|ߣXrFB}nٻ$o8#YZA/Ghin#@_c7DOs6/3ς3KP k_,ǝlb:} ı0\1jKp+z}H1g=&xB4 #@.3v1\|_?iB)WĊ:Kmj"o@}4D>{d1֧ R 򽘆ИtJe,[F4p?~ ?7i>}ziomV47Z?fQ/jEG5;f .T4xd<.`;7~_#t`9 p“p9 [x}q|QIf)$Uh˾eHkq`t.EbܪMr:n^o/>_myK o6kmj/T-DǛ j:mjlr^b{sy7|וok_z%v(e * bĊW(ҥ&MFhuc5Zc L'a癫E2WfŢys|t/"ĒfClo9}8ֶ_Mm^Sg1oA##u]x$ه H8o$^cL5zcvDki'nm&$ۤ~ 3ާJ;Щ? Z+A}8!Ip4P@YAMoubN֣~NU;&'5K@'.je1s5S,J(>yFJGUÖ]@OG{P1nU5^+-C.v"xE1'K lMgb`_bn%OD˒ ;$R?blnYlbsq{1sA:~ːGmaEQ!,8 -ХZf }Mr#_3wL0EM~KdżJ>d2)Z@ 荑Q']u|Hj4XHTJ mDoaD^Hp>I(Ka?CHhoCt%0cjY4zrޚ`>K;prh S|L\s>+epBq|hDpp-xz'W:y!s_QlhF':Іxvȧ7Az_ރ㎼G[Uk6ܨbYm]LeL6KneAKVx wjoۂqD:%bHIP.M1"/c㼷߃5%' ѻ ]{?m> T?B&&YD)1~J%b$.TZ/n0ߑB9],C_rHu;j@A|loi KuT2Xi>pEN7H]4>%8Tbƅʉ( 3o74^6nd0/ ?XTқKJYX/LZRכ&AX4 jyY2'dQ:PfyưJݟq .kSL`cåe}$KN8|<5/XJGX!06bqg}e7a]ϬNlrv˾z[ROxgcFE{SldIJ*%gv:2HX<+V&ram?ί AvY`.ڛͭ%(T5P̾qADw'4;82F:0N)ZX a%Ciʬ8G_**A;?"3 :y R'Ϣy#l#Xv'1;'Xw/~쭃jz-Veo뮑*-zf-!lxF?̲Ŕ9QI,(XMQJ<ҫt6w ~'~uyï(Rvsy]GmyqF̚}Ro|F'U{v;8m"rc\z|gCnD]rKM*xpl X)7\?EN6uGqY 8V $ޣX]\'PԲjwj{I K3% .s'xnnP1;D_ (;gp4$62Pm{3 ;c훷aKx]]XKN}:R4h%v3,OI BFUη)|>xQ8Ylag Û0I)޼yм!Dh?KVmL"GLnUl1#˻ݦnf:Lݱ) VzʺwSvAln7_@L8zɄ@\J"Z;m4Q +`-x+ƺ(m-B,"F 8H6"a@+)~!$kr5eRnBG.<>Kn3 I` :nD2$G~Pm–71t; YoA! e +[N B ֨ɞXU8'X}NF[o:KÖzC/o[j.0\lmޒ^9Q3ΈG'7O,جw x,SW67AHza GAr5:OX{N_~#BQdvpͷ:ᢝx3a?j$ۭRl(R㏇ZFr,`( G!J!4v@YmS\SivK?X<xHt\{Ltr G8~,Xs86/]QUބ^ڿojɾ{O°FR`ͺѕ75k k$ bcb P SbqxJ/> nQ#ׅsX׻KVXB[p=>Mdž:ʊI.U!Uٲ>bx2K Q11^sf!6-å|l l7o6߆9 l@xE@ RͶ|)an ߝM^?%1";d<}'t6E,nRk7o_KvܙKI3mjEiI^o \މ7-+W &k  ;mI;K?wp 6q \DCS^^S8*&Ns',w/(3K hsYl6F. l^~y \z.~-"A^hP~ql'YuQx'S19м4nuum~{νwnyVfsKpdSKci=R}$T lsp%@3wjŖ?a_ sB9 CgE??0x)5-*(hlC>QЊ*w\PPڡrxۭؔK);P )9gAMm]]v8e7ϘQDxʃ `98#FmP10f21sVsPWwgk۴B?߇wqj^({oۋݲ~t&)#ePI!2=Bm5{$1&J}@TK~ mO!XbI2N*CY1[Ӝ)8#mR8iHsbalfA w08Ȳ-ˢ pg<m @֜6,<2*FgHZzLtϐ6/˰(cj)hު>Ny78#oZ:#j (Ӌ[ +}9igtCFC:!{=h"rsDl2)FmfjZP_[JrͩlcL>3#M#l=T~)ͷ!QC\ɂ.JZ'΍"ȦÙ869(9ܻDyx+(7QYFaˡg8>1~FYk6B@xBFwChN)s@H-D|' h8>Xy5$/AePU5  HuG#,J@l}6heL+W6;6>0SĈDOPдYgG/`zvțǛ飤QefUuz(orj;%B78k*QY,E"V> !E1g #Q& d!  O(J L{lW,Xk)DZ;:TZVؖs ٍoٲ+=6m )h>u^ns9+G-h*X=6Wk䬌!;q\{w7lrSN#=G'Pji>\VT߰y=o٨ެX-LJ dXNQTNQ16$b AZk"Zhq\\S 2 .6m(%C\8JlNKN\*K"la'M+5וLj/a 5]  o7HXgBH3h^6>@E$YHDƙE!ns97LA^5~щvhZ U݃:.Ho.>|?+*|Sǒrht57ӻTwX#afф1پAxn8&[;ퟃdr&Ѿxђ'+ /[<=`a#vkp>ē0!d=1,::Qn] Ϯwcj9, X3nTWJzFIæ/9o W'{O-)gxD:8qTñpjQP;Gވdf惷' ,UXɼ+e_q 8&̗b(բg̈́$rBƂIf V\d LJNi Xg1)Fo2" Ya$SaB2@.;v,nJF7k]YʔIMK N4u7OX-W0v==8f0E^`>D QD:,K->CY!nC"V N]jؚoRƖNb&a1{,)\g 6WF[xa-ZDL-TFY|a8YqaI I@kf.$O=F_T0!*PP O/Ẍ́+]dz!Hpkhu'\́pP$QQF6pwhg׃PAPDjb< g Q:mBlj/4(:[Ab  `qE>SހS:?q;NeR4Xт`[P G -Evfg3KӨL4c31E!g3)\[2ğ>cb!6c4,>fU^2 M1e~1ڲ0' *rp'%뒁)u;eJ]4 {f،Tg(*@L',D, w( Bl Br!}~ 8?6 T{s%o!—j q.]6Bw L>f9a&C$eEb6'SUrO0 z;N9n[eO:/,TgR.i) L־[}BÖ;73MO7q p%.Wn&qqt{J\lkA0U= 䌣D*&vl?ތFuBpfeɄ0SRi1p2(Kr  @l0z~,x1_p`b_D D -&zxi'Ex] Fhj ,N=+aQxԛY*AgQ 'Ңhg 1f(S5{LCeӲB-9@pA/a䉀5 zSr0=IԄȚP&\چ!Jq\"A`{AzYL }h:tdu$TͱKAFsB 7l ~ŕ B[g@amblñ>"Dnd .%XX?M X">R! &uqY$`HHQRr\DgF *AC$2=JGn8,BK@V,L Q2L*V&m,D0E4 3Ʊ !>E/$x("#G^J|M{L'ߛ')WFۋ`XH k"i1|640[ǢZrBԐ'!!0MzŢ ~ѻg~#A7@gvz>dVߥ곣r,NbFSu }_V `WO~Cy'!l}ɠ,eOGD-< ئ /'g&>.\tPHR$dR$x4KEXu4mae_?%~#`$8TkPXEh-2-5s>S_ wTWWNЮ1`KS-5!?ˤRYs`[: p`YKJv5%_ ÄM,SQcq"Ae(ݛ6S@U[aȒFАi_~B}įBrNN <&D1M􃷢8ijTo$X H0MtEO,7-':@LY U~#HTQpdbku>om?%|A!I8ʁXPs(ڦ^AW`W*B;.í+\<Ά<Aqnvu]nqma#VJG![wN6PDnls:Fat:l=n=C>C6%v.' P}wl D2rZ]B繧T=)K8Be*q`s݁sfOՌTQ ܇ m<B"If}M=Y?GAk~ԘA|# zaɝ2)YL!WMXPMZ7=:2p "HX۩51&ޤE 1Ө2\ ,L`pȜ#[, 9ԼǛ43ö4ޮ,*ȷ~}MƣlL"0o661dʔs7D s$5;ryڣ0ZQۅf 9LQ9p1<(Ym7Xj 8Xqw T~e|ނVkc\| Ys.Iv+ .VLqQ0e6D85Pd x8Q[B$doM3Eπ, V@`p??(_@E-d*D(Igs:Z'1S-)lT)++E:OH*BAl*n @c (cnѢwL7.SFGrV[YY]8:XeِgRI d/53 +EZ螺B) 1jIo | xaɾX)ˊ9Lʥ?[ڀ<S!J)"t[/(AD @8VwG(US!B/ >I Y!4Ô>|{l `8Lzcے9>=kJE ړE ӚYMm[cfyo,:9(9^BAxM+{dȓ2$CVK``bu2'Fk;KVb_TN;WCQ{imcKP{0l֤؅eD}'6[e0AdT{~fi4`\@Ș(%^FsLET6^TFE1ۻX̦0Z'`ůyv]n>M[ԺZ(!1=q=8cM)7T%BhDIp&8/GhJ3HMs8Rv '^Թ8"p0$x#) {"(I+PǴ qLWMUW'*5pU0SQT=aҤIp$ӜPY{5HeMP^OUf'ׅD#FdbuUEe,XU N=IUp9iReOMOEyey82fҤ U `ͤ |yJb_" lQ[4^'r[$j;A`8|cʗk?_7ZsR6_aʪ  'k*`P6N 3220fMz_l  ݵF3)ԫx2tfy͎b#EE?k0VK䟾T nQ cp]9(ZJ,lm 0PAp'܏;)uAQ E!ohP4*ZxwN;LdC `>nc9leJ]] $~lveUU5Ͱ\6"U Et]uf~9ͨomwZTKrF`% fQox`+&r/|>$QngJ62 lAârg>eYe(0)ꅩ3زDeIW ޮf{uJv]h]SCg/1[:qYJm2Š_Zj6D$Ѭg{OIOn}Y1"8%$Y'ҋyFF]sՌa Œ~m6<"RQ.eWj  *<( @>G5c,,לESaP]63hKd0 <B2|؀GdW{{Xf0BM!zSbQ1en±521D) #jlLȱ4D*Z,ڼDX{, f7']At_[ ɉKJMm&94N\>!/'E^c\J6M&6$ Fk&mݝs;[ۺ;'ikf!Ge[υ*='/]bkɄ '"|8V8[d,F8͑0N1n*Ӂ|@ZGŽ֥"9pٶU[ }15~#KSA(3UF !M<~$$ h LH2ٟ P"z\iGXxHeb?\78%JNVMʩF'cP(>,"ao\ ThRS_8LBG'8VhpYP<ï:6eWH-];s{mGr  (5$,u{BD@ntea T>-< =Jvl$L( 2ʶ5 e#`XG[CUUPN*P%!M6x.:X`{HV'yzpfmx$Ө%<11E5PE|jg|kw{sq&u'Ⲭ,h45,o\,C=TdѠ,,̥*:9b4ހDhDlۊ PnEs]jtUYxn4G@hn^Jlt仁8(vq/G3gBOJ?]E2.GH_]!"TPvXM{Œ¹l xA 0:aO[Wh2i-*miKme&ҍGg(R0JW3wP($9BWP(vSaYYN(%0؟dD8^YcNDDc-U(qs!tG+e ?mqk*[g4k4^[K֪5ŊE魂(lLF⫩a IvHY!L fkETuA) ; +A68n6iK(S1fqeMJcِUtxOVщ3v @AlRuT#Ц:Y'Be_T:ɕ8yo*q-$U@ܗnUkֆXUN뻺x*5*4)8$xW╹YۢgCjH +wťC4"xQ.;DɎ ^N:GKĮ|戠z^B̙X@Au8uQLkgkΆj;@֌JۙҗԜS]'hqj]w[mm*iS}!2 FcCR9lB;U2踨\NJl6 U %E"Edk b.0!ɘ A H LoBE"ۤȄ ?w^jcjzZn<)kl(.VGH+*QX/j-䅤 #Q_l iD6,] d;@A3eLg_9mIBG}x!0/Yi-0JOFg_KT#j|kbF2(Tyـ$ s˜W5_/Z=yXA(l`ͨ谤OTO[ixIZAjb-r( b ŏp8"2riFED%ZFT<,Qi&@:K` Q^bH7'x4"~ڦNovd;OF<@Lۅo {cgu"s±E2-͝uaԽ%~%*REΫm,i] K @]J]R"8鞂~(Ap%KPd " z+e.7w ȏsUfp!YKx{;GN_S3zh6>_y"EHt/^/{=.I` ж=STT[kCY6Zds'~f [dL6vHسq#QjFn@n0 õ(.1Y❸ǚl!" @3=$nA8uT />%PÚݶ&=\lWxqM! yCž"^8MiwWA\`-f0Ige)alDnXا$gL_(ªS*-A$~!okezohjf KS?'kgǣx)*gd2 ;v" UkՁCp$B< WTjtHd(hX>g܀]{$AˌHLnĢRiXٙ.v[ ?)0gxP.<ÆH;((\b̀ Nwvw=Ċ=" aɬ4>yu(毚=9cYGRҟ"[E:Gh!wJ/cXA&=FE\ސB9)eXP-M8|<$%lxe)DPo49v:x^.@CIxyQVV$cJR<=aȕf" \yܸP%/LP?kN&At7v"ꫦs1ô&byM/;lX uBC"QwbT*)0"(^ܖvB=G8D!HCcITERɨp``ccDHz?N7y|(R,s$3j˚JpN״ +E3I!0A80r^OT&J< #a0;ې@7!F0]LL]`5g<.k 샔z2UHD tZ=g >,!M EՉGz>pe/   Uޒ W$HP{WE^Т֬Bw\WOg9(0H vgF2.Z+O! H}B;RpEܰKehz.5SAA赔5MHsPqF(/@f?}[9 өX`g7][E}01ˡ&QDnR 9p>T\U 9pЙgxnKsڦ8]VTi7qBbyd{)*pMUʔ~3M6H &-VRbvz'ki82(_9B3ZB%t$oJ}vln{ATq^'{znUm%Lb@CɌ0?IXpK?;Po}3vDxttiBb~ U4;6䃞2PN #$ qJ$ \A'yo6l͆Q$h\Yl(k.+Ln>4áZ1&1>I!!9+}ws+&$L);XbPڥ*hl+fQDpSGQٛ1"̕IORBL$xo4iȐlȶwJ)H͕n% ʰg5ۣm P)t?Y#4O~q6ۛ0=7~J]P= Iﭧ&16$Kr'?  TnwO~(>ppt}NI1(CBܰeU;[Z(~9Fz䣞(17}!=&JN@وQs?@O+N#(qLIcJkaŗ=ťK>u$+cvtAݧ0"3S)WE4egsjėv;E.E2_Ȗ;qnijqgcDNG񈅟>}3& /ʧ̗!2/VLP#qJImNȽJ{O{D;L̻i؄Cl.p19NAquw'AIrW LQ,<^Tv7L1s(e{YM)FNtwv/[Bh+hKŮ o#1\Yn'RA)֔yJMՄƄA6\#FcMojMH.TVW )͍(G=k˃_pw "(-\p7j $F7"*]rڸ/`݇`BB Áu.FnY'19;DX-Ɏ5*2CW̆=$/;Nxp`nr%fVP26)wma`[]+7kN0MKǺn(ZG7 %>} •–Mg[G{ taԀri*!{+& HTٯڧ_$6RPqccAk9BE>@1+AeO{ xh%}9rh~p,#UJHre0; mVwJ%ȟ:UPؤH@"y 5Q`'Jlx @HmPհK׸~Q֑M;\0B>FO\UnJ db>h:Av#VM91}Eh B0\ Bx bʔ0ukӽ`$BYxZGsgu"5Pp%ZwD%j8d95γG1 =Q>WX.ǔֶFcs<%Vn^,agN*ݮi{+scьb2PvɈb_φX[$ u5v}ϲZC*j8ՄN?uXavt=Жhx[eehUmW/Q&_ LN'IH 0|X/O"xșz<9Z^aVCQwi <۹sfCdKܪ#+)b]l[ (b0FO*w `%J1uF<:|ܟ5wX?hm9%^vB3j5HQRN%ӴpBٹpo2eA\fX LVnidf`τ7${zK<;mGAyy`QBkr\,Wr@ 1ȳL:դ5Z%+-{Qhxx[^(B6>sp9Lg~usl6JZNe?:^5s>Y0B@NV<>"*m*Jyw5x2 s qBՓK*8(4BdPqOzVGxF1ZM/QؐI-d4#6 6^k5 i[3cN!f pJ_冢5{,= a0K C'71,WqP&ʝ<9MNc1;q2,o@|'G;/ tTWW|('8:x԰XEG4R Vvi.Ӕ/F 0BjsWѩVUA?^;,b> @#uWQp!,%*b=ԅd}FM,` .avD ~p46LtiBَ E>nw:@sbQYt a#vhRrP/|I!zXeLi8I]yy^FO^Hp6]'`zb(d?tHOl\[R j.L9i"i4)5*aqgDt.Y^H=ͻ+jz+lT;GA6X@!5.=Z 6lyR>](HhE] tHO=49S$9 JNj =s`y ꏅ"95p<)zjm*EmJ#S "i>VФraO;6ŎF C(vB>K(E 2QFqCְ/!;UwF x؇El~AqሗoGbN=k΄ k7@B>!ilIt=r{$ \`h֏.P}|THPj כ/:+MtLw#+Lo>uTgM-^cij7\uJh cN S,Mˮwq]qf6XSılq25B_ V=0I֑ϙ\\9+A7[XdV^eA5M Cw_aN-u5a~IxΕt2 Z4v#S9D8ŴA?Z9ޏ9Bc(3*ʍ[ @X]1@9~ZQN*J2/=Mkĕ&>lN2-]°LںԘx9G SE%myzi@ˌ~l*O'*gcS{)8"fnAA=k]> %^lf'5W' ,G"ziqm`(5 -זwdl0) M r6a;IMhk'W%A(2#Z;_RPmxrdڷ&o'D*hrl*#@ىU5 GqC VAfI` sԭ|@}`Wcw!QJ1Jno*G/bC7DHR|y4s6VhvJ{ \Ow+:H”HtHq-~w^]Y{IS~g p\Ë^*%٦YGLAHpb!ZeU \(Iq2b%%ffyg*tE4W&d\j9hoPQ~8PnPZ_jC)BC 51򼜷oFK~?L' ,1TO%m*=;Ni2r8,UYyeDB?WRNktQ8 c1[2PJ*pMF)* VNX.^T=<Y.7y(id=H*x$<D!0M@l.vXsUhK-Usq1ds:X/_X5&vC^3v|Y]ɜr"T]?}VpszXJT[%v=7oB}Y@KBXqB*PQ**= ? 逯_[nHqyHO}5GHԓ*y[jW$BclRJf1ă5U+Xqus#'q&l{Xek\P܅VD91d0j->isxֹ0qYk,D0P!z"Sc6 z]w;èUK; M(|_>auHAZZ=mFq\LҙLBE!4,Iȳ'ˉzjKn) dYePkQ(zqn y6/YfXOuESY[Ve5,0w/B ҇YjHo&!hShO^;莃T(Z’'W\ QYϑ S@f8DARμX~~ xL{*ȝMrM]y<t;D!$`ǔ5C\id< 'Bf䓩=k@M-_2A%ij'542"nON 7 nrPrX57ʀwQneuT}]]m Fp?@ba fls .2X\=HzFJ~rrBXI4EZanK1&yPKŒaN%ⴗ%dz@j6HRA41&JET!UT 3ۚJa]JL LcU.}^fl?a}#X/29bIZVJ5PuuRb0LhU&A8䠥^+?)6 ^ӝNtPjYG$ɆbLkŽk o8o\Woek---3l9蠃:|XoOOoB?x(~ƙͻ~ n#i]<=rYڻ߉J;u1{=fF[>w>nQ摝|f/#Uo:|ux֙[;bƊ-gT:ws˄S:=;tʢ=T=}~lDkδypMےg]-wwɟOxWOq]=#9#]coax5vo}N37÷)C'r;>>T{~dHd.SJ.C'm}.xomK=]ѳO[?=svO{-3wꬢoᳫK>= O/jY;<WƮ[3'*t՗g=Y o%yt׏>zޞ{͟ .]zܩrg}םp\pՙw\xså\wU]|㯗vqW]|M+]{WpͿ]qǝwt3'?-n{w?ٳW<|O_};'޽ѻV?s]ֳ /}\3_W?ǟ}{?#;?{V{_xуyga>-/?=nⒷV|h{۟Z{ȫ5Qs9?GMFM+Ə{M[U%nlq놿~1ǚٛPֲ7mX˯7eĦ{?{9_ {6=z7m?6MxmʒM‡~bY^ne=_wl}7>d܁ Μcb{>43?55tyO˚;QK3o|ۡm}u%ߝwW0'=l=f0}ܽ7>ɿ 4\V껻>d'ܱk.t[zcԟgMQNS]PDӲ&;v!_0'j_9Й+[\9vnoOzcv|_uo3vqMǦߩg^>)>ٛt1 zn'6ԲWW.Ww߷w:UOOͣ׽/W<~ei-~꨷x-4?ɟ]Nݟo{/?{\y4ߜ{y4fœGϼe6Z^sk?1ng; }ӵ^ӺS_~GkӂX-Q}>⺦?>Ư=Xf)[:οlrKOՏ}COn?V}xʣ<76n|ඛFOYnӏ)yz{}:'}{>~Bɿ>W)O_z#ov^e>u_>?\9*s]qG/ /Z{`ٽfyv<˯z?{/56mn=jݢ?pԛ}&>Y׾O9{ku'o6~j}myF많Zjff-7Wjn%+fW}Mϋbioݿ|Ưn7۲+F#ۛכQo[8^JVwjyK{YWuʎW(Z]4r31㘇_掆Yʹek3}>~Fx[]\ჟ?akoUQž[\HV[.hz7b7ji+F>~w+κi.MWk|f54cַv=οTkWVW<ک犊=NWnS^?ߺǗMoٛF藷lpJX9rl qQ3o}B{֏;r:~߇i[o^uܹOk;||~컛-=zLjݷިi#Rn+/|['w/sU6PڽI棖>Xsfp=^=u]uT#'m>zIOXtc9n-/Jz+ߨ5+i }W^釭xݺUkO-siy4n>6ۜ{/xu{5D]ּ󅧾t ozF.]aCj-JlZ_E'^$27&M-?;Wf=y׿b=5wF6:<:qȨ{G\veݳvy֫6fO[=]9]&{QqS8yWYy=7b_Xa˦>|Eo6kmg.<:k2ǭ4loե3ۮs>=vUUG|ƭ.į:->xOO-xt7 |igޢPk e_01 -ݡe'玹Iw˻_X_g݃cN[1,?{#~ =k>dvkN~^Y1iT/vm|ؕ:Z -LyMfb/ޚvUlYG2o[r寏l^ gԶ>>wͫشg7\ֲzO_.}ku'>暭F%)9q/O4򃓞{̔mL(7e챯y__=Xŏl=kuk8an40tʮ|v~®Q7vܥo;6n o9~U+nK|!/8xpn9;o;p6~>E߇?5C‚_yѭGE+:rۙgyd+^9틒}=wsî|r7=^ldunKv߃.ye!_sq{:vQۼmOoAܧJظI_M-<\r?p%{Gʎ==-̍^~ٍkFS:he.y1熳s[u7Mr EQxCv ܥ&E>9HCmzLC.zX;K"SD[3-6mJ:&2wNC; 7F9$ icÊp 4Fwx H_1jJfPUb ߀ʭWavcjta(-J"ckO,+zLMVY^S}w,)(Wp<6My*^"}zrvl[fuWHp2$2z>5$C}.2`sVMpU.ìdǠfɏ6 -t nuI՛fwpE nVԸd:ݣg=[/uF5%X9M3&.yYt)M8=( Y0 *)>~ܝRP%NNSmU׺68Ú=[&+*:GGIȡBQ۠ƾRY(qVVKsSQFqn,SJC~y+8/!) u,aZ]X}eqcvONPLN>:z;ou.QXD;Ujhq黃\9S`MV}j.ldRd cGs!Xj8.]_Mt܈Pz@ߓUfe, %G$ujS?; b(rz*f!z[!طCNk8we|\Y'pN?ؤ] 35S ]jʼ<"XAE),Nk)V-  䟦 Q#df)993zsCga /,`u$Efkl ̘kU&%AlcSKa ?)n(M3U 6ēN'sunF=J ӠF '|`f뭘F{؝H~UI‹T AX3fM+l2/~N2Z9Ŋ)6gV|/i*1I[l 3kK H}0#5=CHܖc=5= a^]C0sMDXOn-Iq!Rjޅ7EJ븋Ε6x Jz\ߦeRO;KMT1њwkeOu<&N(2VZ̓=Rѕ׌4DŽ['>(i|[>FfIS(lڭJpڿ@04Ԭi돩K3Vӎj6|LeXFW1mƣrjc4k IyU?7ЅCAdE =A4b'B_lBJ$l| AԢtAߌAc { IEH*-~S!vЃf[cISrfAq@|U#D7WH<\Vޖ{@*TvI|NJnԌe$ e\(%͓ 8Uzh"ahi,k1jfGL¬DnQ%c[,%Bx~A˥|Ep%- ?k] ,Χ ^`iutM~WIM[ 68P3] ֋ş5)P+,PRR:b,W͠SO#ۧ1i}bq,n':䏬__$$yAӅdc;*kت7A.jt?: fc7 %䆔P9L#]nC-j$Bô+i$lЀkO(+[r$G[wޟRB67v3K"Ӈ\|AdO߇X~r%J 58%:P1\Vu9`ʽr! YiH;w56Ȯ텦Y%&$#ݛEL?Y$o1Z-/4^/ӔWܠ15VUVUV/Fg.;IOa2:qpUE˂dNg*EGq{kRNWi>>`×gaYA f;3_\ 4]!e =Ox짘|ӸK/GH+qFY ^D-a̼آE3qxϊH-e6nrEgO뮳'7:'aPlFDݳQ%Z멳ߔ(24Hj MZ8saL߱IŅU[4u5f0O5˭b`  i4v$ Pb%"@9^`"e+pF[^(%j_~_BL{&CtF[aa'RZ \dQPXq%MP5E 5MAV9Bqn"UU#QTbD432HVtD2\Q(n<ln$hlMDc-h\2_YG_|'b~́^䏛7gj9o+~l(o[Sqܞ5%ًrݬ)P*Qٗ#d"2@+O V] dQf,V3p C²P8*gQ5R%ʀ Z z@T뤛W}_sU"WWڽ6au@Ƀؤjm„Iŝ 4~nbӾu|Drs`rE=ٜLcHEdE.\z̴;:KtSz0B#}G N]#ݠs"scA )D($= 5yuIjF?"<TѰW_I#|Z8cb!i 7NC+^ǭ,|/Et氨-gOxdqѱ{iEuV6WD-X2.ϊχ q^o >y!\6 ")]/פhX31uG}<WnyX9E?7TewaG=lҺ0jnЎ` =Э*șJ +zkTO\̦]A&údOBz¡.EkX(WG9Aga%%7\#ƞe)ʔ!HuΕ+/gxWbD*f?{F6MlSˍv+㵬'۵N86NNuC^v[O].CvۏkH@sOjU!̘eWMU4.cWۿ/\z\w}~E1l_Zu]tcxve<8?tuQtqMzD~l1R4Tq@ZI_U4m0uOb39Y~"1i 5u靡HkZA ؒ<&hY ]58eK aUVRTa$/ %|$oZd QT rHw!G?ܻݓW X[B hwvyj`rM~ho>ld tq$"l<بۋˢѵ)=xd+Ba/wRSFF{;fPIC|QveqT%骞]e]M:kIII;QtoZdT @1P˿ixLDM,6yM̵ZW.F`'zERdžFgQk,W|c)iHBu3qm{ϝ\c͚?o5!~ì>H~䵃9yA%;wp [hW溩H0 a/;J/k>Hv:J8is#Hg~:!_0fK m/St8 le]ɱS^DG8pJ<B?&gz)$"_9x=laFe1`EAKf*y87/&CWjؐ)<#+gn4 e3WnO}m7vŅecz;$$ϙ_?uveAvmblG狷 zkz0!!x{S #ړ)v#mrYHrZaeKs^sP|vDc"Qwv[!%vOՇo:hBG%ֹӵ3ҝFv5j4buJ挼< 9!z$МYuągPU[*@d̲M˝J8: ]4hQVn,a1xXQpgS(՛{ve@jt_0MY%Qi/_Hj)&S-?j|[< ;Ji7d'uKu̓% Rfe閪yl_v1;g?5=j`yubr4Mc͙hVUHL*Zr2L`&X  aͳ­V^UMfx u%(<69cY:oOk yB{ WBt?y`vt顯GZc]& 7Ͷ ϡAZWu17BJz< 5TA=C ۘ-VF{aYuu6DÑ+~@E$ZFlR/[6J&{^ۂ4xjś{"R܎,桄Bf 9]}BRUOMɧPqpES7g=VkOftɪϫEPhlktzhsv3JP6k ?QfFþhOKaXus0R"~`[3RA.WTbugo |KҜlGP(?vc;}EzGD.epH=$͌\V(9-aTmhzfeO(W_SG_ .l W-H εaH?db%]Lr\`8V;m=l3tuzYH&<* uj(N|x Dm<6hm\͋SQX&>7[=; 1j ,b{žkR"6I2Gg'8EЃ{u!Q*\#-_5Fr tAKᘵ֢I7 )zBViBB4Zи0jmqg*jƏ7;>U53˹z ӋB8,݂cU`uԬѾҍpb!KO2=s1BfO4t6\XTnb@woK7q6.#sHǓ!M8 Zs.N,vW>=\L<إ N+d'!Bаrni"O;~G-@J#x Mc)>Q-y'QE KFhڡOm<[bC_eެ^L{lRl 厏1jLşB2wTEgeLDэZ:f樭J:OY*ajO},0 /{3[p@Z濋 n{ E;̬,"BttlB%l)_V 4) CH@7߯p[ΓyZ#pI#D^HC~A:k$QrGnolX%_  T;=o!ELR@`qs2;kc||2{skܴhz-X L xU.ܗe2J~vFky:LJw$t zx>nw f5͹m==u@x4Q׻dR%!o ڳeasab5e/W`o~,{p \5ZwSJVDGgJ,KC|bzp&VDxP)7dP9IJJ=ڌ ]z8xa'iU?Ӓe(``߭C3"!qxh$2l* z˕-Є.[=fSʅXiav[X'N{JB. Ew%UXB7ZM/ޞ\\n.B\qz[ȓ&piICb- eߛm#~!vp9Thb"l;ftq 3lSiZM^wL՚9_{0 wXM9lEWa]"yE}Z*ZjX8HZuN]-|_)c,NF.~5Tط`[,~aafnڋoU-0-‹~}4XKw#uÙZA[-͇S4Sm64Rnhϋ?òNY]`wBH^׏֢v< YQV .YNji_^]r5#Ƈ^_| Uv7@4dg}/?},t| vr,j#5?_Xȍqb=!ҟ-QrR@kq< j+^SC)~RYP#%,̈IW*iNl _jՁw` V[~kZj[׹gU\r_JVcIЄ3}Sm[nGBmZ.U\?7f*Bv, Tӻ1b\,4yO&1wgtf6d*4Qm؅#J/9Ej  #^!3-U`tU8Dhg$Sb yMb`.0wHX1x"(WXԠ)4Lx ^ġXn$/-+8CE1-:mnhFJma8!3Xl.p .M}@S;Q6ЍuZ(*R2[j*˕ꂠ$3eLbq`ʇ+8\U'C(?+H~bwߨ^6#V1n䉡֠<$0i.u^dS fMg-OAB8&iLE XūDE_OO^d[JE+^ ˆn!%$J8p؇.F'~ᅹbS=$AZ~,2ydR0Tغު$Mb88屟G9s@ό<2fb q&GnH צLl2CsVM l2a"Cc RHfF6,o楨Bcv4~\|NȼEʒ-eQd8 c)4lAK%Ic7#O*0Sɓnd{DSyBҨpW$iz^*9\H`I}!/KW]Aj$Z]1eJ0dmw֌]/2/5m4H@H`dG",fƒ[,:nB/Ȳ6|41d,H+[Z 54X|z4-L[䞯+r*4N$0@#:K}9tE6n;8Hu-ނ ,I5̇MODurjOS/?7=*GH4UVk[./4ITBK256ƿ)6N/S[_-s^t'XdCr#T S d1 Zo!?ʠHcnK,ɰHqR!u#'bmvBKGM%(f~&vȂf18.?*6}>+|x!qA>ʕQQmrH n*IVië/CHo &]!Y miXzCvypV`h\Ql/sX"j80RnWyHxRjjlߩ{ZYZ&:Aaᢣ j9 =9A{\*2]Q@3sxЛ_a\ k&MB>NRP:R4Fj8v~&Lf1YSLxU,h9UGL-q*MUS8z3lymA&hD˪%z۞o2/$\h&.'i?)h>]xFڃcy7(_ /{GMG_B.nS\nD}NނJD*aV[z3}1B>Gm}:_ !_o_R\l|dgb)(eeacffbccup6H]C+NUpJ}qMIlݩR zdԝhՒežZCwpo36\1 8wd9P<-u(-uNmSazr{ob'Cщw#6j2A]B9o ꢚx~qD6/֓x%˷ S0/Fc&B' 48h_lӋ?Y]@%Og*`\qץGk-!4; >/{} ?[J6lyTƊD1 6zkXSðc&z )b;<$Z6D*=&U=z,犣 #ٙ#ձZ >dRAˊž{{5!R'Pu *k{2 00 31/F  k"|~__WlOO̿#`&4F8#_4 f7|K͘0I23Liq翲?&Oߺ_i"eL?U71aL3a7a+$1-q<&i㌟P~e6dLdd//_Po_%}eJ/fb2nb¯ii&i&6n2>n/X_>M?M>/oE/_@ez *+_15iiXEW_" Wg?F3WY7_/ATV%ȿ5}2b_?񯴿j_?/׿W9_f7_ K߂jߴI -w;2+w05&|DWS)s1!l_Ӳ =W+ ,$"=lpnoiO P-DAg*qKuط!̏w|N@}/8Oj:.a9&Y¦ SaldT ;{5zqT<|}=Q#@"VWWER1J^||u&]νK]pZс+,YdtS!~ NJFp9Vav!o='C]\>ȵ Ѝ?< F2DpP٪H׺Ǭ ?h*̹i 5,ؤg@~ݼ. IN"T5I߳D\D,v׎Vq()wkDk PCԑY+ISLIWR실^{<RWJJCȉ.>g0]zW%-k'N-aEۢxhL]z$H%7:#g!4lK9ʞ99F=ffȫcT(b%CcG!=gy PAeIX(XA7*ee+9$Xn>FllTw$$_]X6k22|ݱ =;B,ll ,B ,LlBB^(.5 uu{_v D_"jcC ܂|؄HPoo=]-m1Mu 5U%eyEr mS23S#b#BCÂ=d=]]l~ZYYjihkI*(c)cPVd傤f$C CCơeE.BMOD.&N@!,Z {`:C;NSTG0.D$wg}s['-fYs2u55POw`@0}G mܒ{d2/ OпU-3a)كEs`[dL0 A W^ˌ`䝤lHQr 07Ma:gÆa0 ."TIO~aW9<EwØ|<#0. 5YRixߓFފQ): Out7M#ݩ C`h̯oRV.B 뒁Z%*XJX&<> s ćY5basyP% `vxMdH l-KE`tG2:v%oR(ƀ/o  KrP vEO:cI`x~OR9%0oX,֮4zh|6m+W<Pao*XJ&۾c8575sl*{)01 `X̞1 ]}|Ѩuۭ&C s3eج9ڊL%+[ۇȊKklT0Yٸޡ+Rc=v؟O·[+Mk|4jBƥy2_guZ>vVÚ`cHnmCTdBftռ ]҂NԩQj_!t94t|$>ބtlyҪ+<kMM 'u-Z PRD %扒: W G6-\ej!kV#UޑԸJ)5.ۤkͰ5^ 3~B3bٜW~L+yk$78b,"#O0rsm4ɕTX!Pچ{d*#:F^9?0.F":D)tsj[X/oNˆUƽm̝~WD,^v;u XP,d_ߜʗF\i}iUU%% d{#V8b<3 iA' oI?%FzveMX`yuOUzHRa]GDuUT!AG|獠yy"%ƿw34G$t[eM;KfiQ5g-Mi+ NRߧrcqQ6ni: mt>: %֑Bc.aƦzdJ-nhE|n)$!eߡdDw> IjF:i}rr/dER(-܍U>Dg  y1UQ%c(*"ߨƒ?O ;ca*`dMx͏5)$oEJ9KpY)枑~}BF #T"P2"=.*Ά֖pKv-s_>g?6~/:5b-RcCrQ Iqi Xnu, eD>x; 7WWGCd%ROLTr`$<ֺG$. KP_3Q s{'!HIpSLښ^<8nW8ӤW{olDю$c%<)X;E9.0ុFylĢVH@vϼp K KEdǐA >CǖVM|3z_ÛGvTO" k(6?*uſW&s(VRu߬OLT_!G21c% dZ?jMDDI=!s(d6d_=n-ŗWɚ=P1qqER;yc }!wF!uu+ƅnC$ߟ/ɪPJēG]4hgKWFH6 Aa4ochoHv] 0'nŠwdQ?Pa[9)GɯHޏwwx|:9\ mklhX3w?oIIxdS\g |Ǎ*u}G'Utc"ɿfKǫeEf$^Ċ4V=~$(7>#OzV-sCdVwڌZtp1Oڂ:Do{iWf:uXoRHPQŗb҇eaL )Э[$Ev+ @02 ׯ|0(otgQeшiԓ>^+@Y^ ے)6NOm@?"qh֜1Dwa,LK rڊ?AYi~L= MvXK"-x Q+A!sM~le5%U; `L[D)u3sHHBUsJ6Au. 6;hMw,0COpa^i)оԑ@Ca#Y)x7YB^Xv 9˹/&H_EK?}(Y(LDbB(#DM 9Vm }Ap[JRTD̎l 5mS R\4Nz `P1IQCCg%vm=15S:lcs77x?NfXбsN[/+ilaCjĶ`"dHԎ5=ݟ]}ڌPSص*ǨΪŀOѤC;I7Ň]l~ Ǒ֐p&_N>lOjYm"DQtZ<@&iii +N(xJ\`]9|'S^uVgH3fٟ3`cEJjN:3=lHX!LXdKCRt HO#k$&6:ε.b.6U1,,KcbDhZɔGGdN ep1.$JBm/H2Fp +p5loA}hSgH[v)vؑO4=zđ70YT鰑~c =U }e $|2jd}q?jD/81Pֵ ʙYܙ%tQw92H+14IGFbB]1i( ?G! JɋG {i)N|)h*s`͘.+&Ȑ 7.+2~L@~-^ d-6z6o-_nc_FU3()SdmRa`{S򩗕Ҳ(0WOG7'K V'KvW6hђKMgA#*w0 y(C. )_7dN=e՜-jS@41atv}Nc'.gwa1N`cܧNI~COKBqPU @vP_̉'~lvt?WIit%uZxLSɺ\YRJ&">>N3¡XDX!D]r@v(ZC+)Xojj&Cs LbS'}\~-CyyyAtёHc|ZiVV`dfFFp #~n #7-07IAdI){лRFػcaP~7t8t9z6a@G0pQjITEQH@ m? :Vaco3)[$iGcN&B?Q>~qnn*:ñU֘ʜ2&`QRc@*_[\v=aWW]kU ?x޹S"ljMԓwwf}P GG+:H\%V|M^:ml'z1׋y1 qiuKaˢ׼@,YgM0⻁[-x틻!_8)7Sgmǜn{BApx{H- sR> Ac !z%bͽcAŅoT9cǦaT2sx 9µ8!dޫd忱NsVHNQ"ߑcMZ>ADh(ujطebܑ9 .iKYO]ZPg,M,$od<c wgP̺!o~j"?WZa}KP٣YHԂ3f9hEhB'\'Wx[Hڮ$2Nfg-[9JCXwZ^=;1 3~*Oݖ2K8~,L0i?Đ*Jl\yx15TT]W/ׅAf9|JZ)8/i6cX0Ci;x2evc/a{؟4NvM_U_Jz*y0#12VZ\$83WM&e z^([ݍ>ǜՌ.=pY/,3Kv> oǽE9> \6~mlSgzĴXIރGjqvٶjՖ3>wJL$RțdO)97㉭TT Q]R&*Mc6RaߒGPN%hHUi+ nv1\U|H~aJꡧ,.c(/%V(ykҟ%^c+H6n>TWԿ+ +߲F]HׁFI yI!q`ԝ^ zQbcb0o>~hu;#^' %1h%۰Գ)SX>.mY>_dsdy igc{~|e`.=QTn!TDg+c”4*]=1$ \Ba]BzHJZQt2 "zs5QqحY1(Ѕ:[럦l.M)U6+Y"++- 3udASNt|PLwG%Hksz* \GXZ)ZZ~r,(eJfk_:0 FY?K8QbU؅:~l<AJczv_Y8wSMinUn! O-&6C1ۖ4> 1h=P\I7T$bw~T%*x`I9^WU~&l*,uƵʼn-HD\(S[(w6]Қz9;x㈟Q98$Xdq3T** ΨtKwo kWHqFG4o-%Y|s NG5Jฌi80x橩;>^}:W=UJT@ -vq4C pd"-)0lvVh;87tC]W~IeJV3*BϳtHvL {_A4=V\eA,TqpA]~պ!+ 9%?v)5fOi^HO6]?-٧̗-h-nF U*c>~hc>\)53c.-{2`υ+HblxY쟎*4/Hs)c)]W:KI8a {+5([pfSڏ]lm?Gf_퇐YKP ЅhRO>V?膡|m0"z CT#&*浵ʮTZOlf3K&vQCd9kw5l9uփP[Z ]ԿBj]]`%e' 9> _͠ JE]2}}ũ'~c,{"wAJ*ʾʼnQ@̿ˆItIpv^O+0©)aMlJ[wp}*较v38O [-l b mkO.ĚfrFLJY]Iqܓpe鮇feoR6g+#f;yBx } 8V1A*IеV|oxmLeOWN_NQY6QBD\ >/F#r>j@ZP' πC@@B@CAACCA     /,| : $0ي` @H(h/ د/"_ЀA!@N@ H0dz~yov~( qykzfvQ oH ~3 %Գ)9B@Ac& 6)c;%jX8x0qN.j\<|dU5u I)nZ:zbS3s M-i^>C.nV:rL!a^6zE>J/vBXу1bp;8kޙ" 7L$u!fwД B%e$3rTf-#ۻ L,lo!A/1o `AD^ry.ϕHDTOږYX| :(>#ܭz f 2>=clHm ;^Y./D \1j64g*s- ,yzҾ f U`+V٪ xD^EVI:+"priDubqWZk1(QR8e,ŵ\s:DT\[򅎂ijhkXKJM,C$2 |Dq-ĶO* M&嫗1F$,&?阄0`ꨳ»?CZa5] 0ThVlcvB:=8T|P8IE7=2*$ mjb|zR qWsڈZ={ɊQ>%K$;98ӧM9jo˫0i街B`PTFO@/p64*}m2<w8ݣVC3Gޮ2 ]~[h%[q)cL0Ix OeWie T07Q`:H'1G,|Y~\y8I{VwetSkvv\ Wi)X5,e9< Gf5u=хvZIю ~͸' tH#ǨUiE\)i .p` ƠJ ko%'GBbRZO᩟-x4|DLf:SPwB0.k%'5k=<{6 Ėaa:rtMNy tDo>N~& ?21`bx[H -ť]QY avK*~E'`Gόa[;rbˇ ?o֞avC,vytēW,'YX #r<2츹L^gҋߕcdŽ-'s``VQk4W rnζQ'7 7@ƧslM6`Ay! %>LLG q;(ӑ;!EޑyeݵUtk:͂[ģ;vʺ1JEP_!TaSRB|"6}3B6\`1t1Ebcf?V=?AyYOֱ,Nse?R~)DiMQڄ ĜMKvӏ?7h#JIf-W$@V+pT!hܿvw@_=zp8ך}w< HVjnDCV=\; M X[2a\* !$RWDy"L*gHN7417\hK ڳE)\!&L1C"MIɰάC|iq#mHt7;Ef'KU.R"m8C4_ғ5t a׋Yr\5]R|rO^=Z"M*PLUdǫ`};zĬ;CtYб!@I5k |Fa ;/c8[.5,X+4Z=־ڿ8FJz Bηduۀl}EcMU7<|]<~*Dw[Q N@7nK8( _WKvlb8YQ#0zVK=7}f!(|2ʬx\ڑ0Rە6$ZYqiYuYHiNh:C6rjd\YI+& Bk2omA}!`wa?]TCK/='#wUݮ(C:^vrsP Ki,,9xZ/OF鋜|gt|񠆽Q{)ܾs2sLpB/[[SwMU6{f^(^zTŝ7@}ߜ961Y=ڣ1ŋ(@H,{;iVAjpen$ʐc6߽X{p™hOxT޵-FaA[Y8|UK"aΩ@2F=1什}Xi|X{+}ׁ/H#>e4xxS̎Ym.prKa! H\x{vI R^<ͅpP` xi #GR"j'aYkءlvCPaHS*fF~}ҲVkyǍ Jb8-o~o,y[{7һ5C%yf>Sl# ̫&S.[WUA~ɶÛnF3;/9ͭ1j9ʒud5d*$xeD&1ɾ}KYH|gv1\rEfhTU2YuUOaA"a.1ߴ"Nf'hPu,-VaF 붍_V=׻d ' ({Lm~љWl}A-p2c4=~#2D0mD" l.܍cx>*enmZYe"655pB,SSV=4_WW&|j[@'!$ LJ%f/-MYWb810/ԣ䌋A }2qq(* 9qܓcV'@Ұ4lwfVf* nҒK;:ϝݦ?#2 |=\|zf>d#l}zH@zLO~-u?D‡*6z]ȗkp̥\ZjEĪV焏#!8} '=yoڔB|FJ+d$3˄}iCSBR/ԡswB{7{3tP:œ+l}eQ8@Eh ;K@xTs'oۯCk$\\27X=ԠNkwiX^T>=Y{WHM-+1=蚢R;6y{N:?~,vDksk瞢C (Dy bddb00ڇ^N !wZ"4D–i ⤙Ջ•CdZwbWz[gR[٩40q@Zq^G3x ē釶b|S(ވ"짺c4v?WkE'ld D'S w zD/٢e/neu_C>BP>*wW]1D%+d).wpZ:04XYE/I y.{%/Shtѿ_r6xj>2:\9d5Ǭ)8bwMa\S|Xj8!IIe4;ɷdLjK:x2 z* Ο9\&AƗd|s~`oV3 N۶33َ8[uy_깸-YD%5ol᳝0]Ã3U n*M#'lu(z@9&yBnw,'uW_nn_\4jɫ<‡&̆qs^~+ٵBBww8O4fNsL"ԒВg ~ԽCeKRI,򨴞Owuu<^߶$ {{5y?_D!`J1y.>14)KQH"F ?5|Ir5.oCv=2>:ʲKjf;씼_Ukz|X?k;!й;//\0(YIffAz1]&W?=={_ N#±UmPsċ7 yFmolK3ONڼ*E[nquSGN9YA89z"绽=LӰWRCsY(l=Ұs!:WoMЏ\~'mz7D\3N NKʴgJ2NÿZLK霗/!i0mЏ' 7.@8"RdA!#PuA H'_hkUvi$` ْ!`^LOQ7Zq80eȹ2_A\-4qr{m˅mlk0bhO^2qjXMRJ|1Dg6{u!mʮGWrSkxæ7WFRs?nq!_k OJyּSOsR>]+䰢Ki4UVJC<=Jzb5ΆP=[ueŃ.A Re=/9~GuOWߝ: oSS-R_J &ȑ5w{ ,wqxѭ8׊IɘPӦvxNmZ<VBՒ zXq;&DMwO=v Kz?eVO<7D=18^}ߨ~K?ï9+J\:=Fh+6u}+Y©Дl}V]51DhiLˤ6X){3r!Yrri9(Y!r^:4~E`LJzd=m+c!KH534t!)Zisno7[ݱ+nHYN' EsM< Ak88S2B+f4> v9.Nނy#>DWM7`U 2$z=5Lh-> c@q!qcmNؖjy=RpΙ~OaB!G8 H( ;0 k.9.Km6Dq8ufF8's,%Bӝe XQE ӦpIvRH`"wzuhg5c?!Ny;\xo 91D4YDy| < s=oY 8-s0Z$㆔+cU:/bIF6WyoNa-fyoe"- W).j3LN,P.7 Ňg:2]۝xP0:-n$O~Ǚֵ?n%u&{rIw(ҀP灏-Œg{Wk,˂wPXzN2"Ov ^[.1δ=U+wd~1ihX?"J/(3?"[[abde]pr:ǀCXe0$#`Z|+AUHzσ,y)E%Ji T% E &Q| THqcuxQ砻~'waqRcEN>@YEiE)䏓\0HVݥ?Zf5A@ 7Pؼ75F6W|'eq${.O^[iy *! ~"4ᳰ/Ae;qNr~I Lk:4o: C@5ҵ\LtFGq,;'MӹsۿqT6-;22u<p .nYz]r^RyRZiRv fȨg?g9`IsŶ3h4#*0bQdUPE U 4˔܊|[*dLunw=!W"]Mc:NU`u^|^LJŐ:ɯŐFeB7!_YP,dkG_ERb~`>6h9ZySG8|-GEuBFݣۮ#<rI0sf>8|Έ$F.; cN%Tæn&,?ͮ2tpFr7SN[R(S-xwHk#xň(/T z 0]ҔҾ+|Q6 qBB0RFVXhbtMBnƟgGPqlJT)?$iZ_~Zj@_n+T:(fQ>CR W%GհQ@;ɜ(1D lECc>d C- *^am;JH[ށ:5"h8ͥmpUEc,DI9[r CVj miH)P@qH["" w)P\x!hwVX@2gf={_=נ2}2>W{J)!'eGZH3{2J>g;UT*ct>g>TNvVlHZ3lk:@'o0IOloJ wM'ͮj~咽/JǬ8AaYt3 h2|Vd2O׫TZYpa}68LCwRYB;DŜNH%}aYh9Y`8jk<)*Buuo tTH`yo}&t>` 0&}#<*:Mx#랹-5YF|l)j\+[TXXWNp՟ߕAr|=fNZ&28DΩ‰l!FKaH h\b|Y詰%Dؐ6;߄;ѵԑ\p).~ HZ,'ci ̫/Mkx:⾣YJ?O‹k;h "l5T-P_p!Ce:5_iĺk.MP W'-E)$07{kYFf*.S2^=h: 읹'$|ս{M;iɜ/q 9FիVׇMJn sIʼ'x-}O5.hk'!;Dca;!^[*ߟ?~"Y je{KJ5-#jhihkWm1JM]lT_K߿j146a-siVCvyq\zG(>T)hu4Y/+ZDG#Ћ*^\z]WYp%YCf |,&){[ƴr`tmF٤hkfA:U/$9dn~7E֚tL˰ٱW,6d穴/G޸c |bwmފSw4XQ,ːFNM`{a%24&M*<8 >旞yay5Z21iܰoMӫ㸪ʼ^Q5g'' :M{DɈÀ߮Sh5єԪZyK2fOg讼t]԰P?5_`@,EJ>5HTxk,6^1Y2Y.j8]v0]q\TX6&ҵqD۱*pXn껒L }&W򐿞PCpK$">ᴗeF01QrrlIkf[P>T5aGr.d*Y3뛓Vsu}lL ]n]R$8H"F;z>j!Ǯ4~Î7'ƽ&hɨɊ@^2~KJ/ɸBoW(ZM,yfkL;{5Rss^nm;1mV}SC#kg)cBנr7he|%0е#N6rz0r\W)#Ɇc|q$J'( @e HN#Mg>lmhI$Cu T=?[j9|3e*5.ֳz9+ݕ[on$fcK+}jԚAbϣ- W *rl|Nώ]-?0 .ծ\/XT 1[GNEZO* )rZo*'?tk!wܬ@Ym_ZbQQmtne@ 1BJC raA۾z}SDUU"1;˷;i$zND5UTtMx^CRwUd!\6DFl0dS(bmk )p9hpRL0H#o80f%o{Ǔ ᄒFU/ _LN ?g.ZF-ɐNg)+$4o852I6}įt][>}7m;A~ؒWd vH,$Lvy"krqbUՠ5Aj1YLK {A Fv 0b;ΔYI~~ٛ,(D4rXUp+uٛO0mROH;@YuET)<נ1~& g|kzN^N~6OeV4&mSZqXу q҅l`t⨰KhZ<d}8x$4j]<&A`M9 '?BѺ^ $}mQHH^=ɖ 'ioZm07\O"|R+KJK*to\h7PͪZ-TAϓ*{.HڌQ|~ݗ8b|1$VvPQh:Kz% pO1znS`sǻP5wqf8_7/IF]"Bf$[TSaF4#Y*?JJP@%Y3xݶI>a`JwRagF9wC*N%FN!'k06 pR|d{yv1 RF%ˣLm dAĦzvkiG;Qrkld ]CAnp\Y+v:\#2s1J|⑲|6eWJ3c+Q_EA][h^3j<g\~a0qC5uPgCj _n׏"ɆdB|ǿ-Y$ CFۥ65T Z9QWJJ/4RMSt]foOc0T%eGxu }RQ/x WbJh5@a? Ui 57_;}(yn\hg _M۰*u[joBŬ/*ɫS!71Qmp ; ߹AC^:{\΁5TKЯ-[fb {TFqK)S=L糥<4t`faoǘYV6rcVBtBfC_51^ E@ZȝrI@|.B|uO+%2h'dI0$d2:i]W=(/p־t/0m 1r9\t`WwG]/lԥy ]Ms|;J6_4,7ݼkVj]Ik^HU,= //Fg'`'nV{yzcT)RQ=^"̛?%me/MrLs xjk hT g~H4hʷŹuS܅븩bdZ^ $ihBPkLRy;X ̄",ov8+R8`c狣{ ~r[)_lo0Aicɝd FΗuqN1|} H&\i^ׁ~fEhW}1fNut?}-]_T=ϭq\)Ks3_mbdvQ%Lb{!"`Ar,}.,epQܩiO!wn>m+6;֯GⳗDtg]O?\r䵉<]kx~qrX\L9E/}`{,< 4ߵ S9īKde&{TFfLԶCm;l!\alwFaܬN3~ώƀEpI+ByDUBYFM 3i9:b%sF,bv nOsh, J "N$9_i߈Hʊo=P[6gMSs+3=qrr|OF |Ͻ~0)!=V`uCIY ~w' KNõcʼer)Mݡ 2hvuF&t O*~V/['_ a;M,hE]x+M\W@Z%"IxHvybo2f{k΢]Y+f,2xcUCX/ R..dF_(*AS:Q ^,9WD@T;K'REܥdxLy>}IeaŖRiTmasaR/4^K?o9 8sHaAVmg8G]N7ڻb̰~clߪ)\FL1^9 =9nowqwCq m],iO޽u\j.;ST$WHt}oug+ m} rq&&>rd2L Sٽ؀0!?tǔtB܁,] )o  yyԿPo3W S h\.{^s '*s_}0kfb휑x~\ ̞ULֶxFieGM͋b(+enߜq)`NB:ƾ(08H)wPn ɺ-LеhߺI=2:LLCJ-Z fQ^Oyz83h4*e=}o'9l"H&s|Pw(ܖՋG%{UϞkU/oZoE0keCÂe,>i9zl -TLGJ=B%ĸ)ĵ19m BF'@ [F힃> sΑ -r{Q" "dH``|{*-CKak:frY)r:yTFd, s@}u9 L[/ XLկS h[^Iڝr~ˣJ}$[5)u×GY"FcK~c1DK&eFDŽPP};v2iFܻkTrϿ?{]&}o2+BȭJ;t0NJgrIɸ-3c_qE~㠘rT=!~!^ӵùN-g=u\pxIX~|;+f7uN8d_R-ZčNfyWԾvTW*ˣ)5Z_Ԗ1cmc/W>/?ۛ񦁶ҲPI n` KJM?*)sW\I1zX>@F=7aՂpɰpξ蜣yknYUԾ׏uv}wu5yoVVHވΪo,ҫqZm5;beR/hX~x cJKFK_;a}7jrXsU#a/w;SE<p%>a7{sq⚿܋d{(9%BAOyfA>-rKjmTn'M(SL~vC\0UKUOdJ=κ8a<#wf x[e}.̓ÆGI_J~0?UCY'|&f=r&15MS!vKF.Z3"Hx^0!R56M;όŭ'quV)uq}LL̼s wCam|FXudeߘ:ıt'',c c_zuOk[{ y ॽ,A Dәk&ijV=#ܶzO0[6r e-r09^q-~ɗɷM 7"5^ڐT£z[trP'Xt|/=7}#CE c~9^IP\ ݿzNױwϟ C[S~l쏉jI2bc|"tÛOa>dSˀZ &fdL`sۣoTxmmh^\ } f؍B4(t끇**)_)D*~sZhXЯ׬=^ 7k67lwDz|/U%Dܐ5b1s濉xflf#3/??F MiL$nD~S Hݏ-NX뚍ZYS}7m^[E܈vp:n2}pfq1Mjݷf 86Tn@^3V?3>;+˚'XKߘ@3 Ã+pG#( <Wduߙ $+da%WI};Xw*r)sl6ToFv,֨ho"֘ay% Mea\q"`\i\bHLo&s"4ķn K'tӁzuKt7G\gEjh.cĩ(.,"yC#suvg:Y/}i/ *ݨXT`fFl⒓mL+ 8S@"}w>'1C=ZI*nԬ^:.ah bHqx]hC M^ KjbЛ ["W+R4vue?1b'7(OsMMwMsXHUxXZz꒪qD}O0FxbٵOsM.Nb .'M_QhO8 6R ϚՀH$l# ;}-KUqtmw|;tU=Íy:֕>?X \za!U>axN1Wm0F^_arZ8 ?nh,kWjT<,sUVkQ*, f*=7I,\@Xk%'{gO6Qk .!1dz 0YGXk14繬J##^> Of3zGo_ErK,UM]ir#k6Њ9B]L> NGK>\Ss͏8'Tvi>$)r#ytW7Qj*5a-/Kƒj᳀ͤUc2Vן/׺ F -; ZiLF?]+F4vre Nwu;&2AL ݔ4 -X6!h&z0L\\9tz Gq\0.Ɇh.!;._>nx?gP zoZ g>8;|FlRqz8t/O˂9-T'6M9@=obBEE1R>07EK&-7cqV_Q^fmx1/@JɠZVȣQ\L&c+UG~,Jijx:ImV$oi"۹p!x-X0ZyQ2qsPV#ǣnɽ+Uzth,)%AY9Cq,86QbyD&,9CI)rDvfx(v.m恺$uDƴ|g+‡%^ h2Suj##`ͱaP'GwW% :z/SN;nQ;wFbN ki.*kՋ':J9M|Ƃ.7ŭcPR *U/bOt?Zw.]ꅻdyZƒ{A'4i]GG]=uPsmlQ3e LNW?U{Eܖ,zW3 +(扱46loܽmm*aX$jS!\WoW#V,f wle"~ CERJ (o'@;~H8El^&-l{妾g4`悀$8kJy2'AnJz\O)ϫ =()v3{Y5F>p|,Zk/6gN(Hs<@ Ufly\\֦W.`:,_iz(& l8ՒSbsU*u'Ӭa.GPxo[hf"~4^5Gs4/EoQ8y nMEWΖ:vu޽RvcM r{_#em15 kU9hh'Ud&^#XY/+ntey:y^1TALHǍ: "9><slq|Sm J҃!C xp3/峬dxI|V6ƈ@օˢWh)NdXON7neⰋ>TZ79 WQT4[B1vѰu"u*>Cȳ?<Ҏ?)@Gg *[}Q;Nॲzp!%5'W0:y$ϱנ鼇02/wy•J[C00"O )IFCZ!ụbP`lNoKs~CP9}MkX,o8;٭6k=w̔)X6+8!űo'TARo>)4͎@[IS~)ޤ-1T+{sm_݅P'̏C]8̯ݍsw~6c3-mw5㣣ZS^"+4o~r a*Nވ، waSr ux4N-+p .12p0!K政]#H=yඋ71fٞ >;hR\@B6vS[z3؍7;j î+ޔ_OM`_`ӽƋ5jbUa(At3 j H-ܢ-s|%ZV}"W?zmXǦ9d.gYU|T%h9δUɌxVT>\N#⣏8YljUdT W$Wgg :_;SW;Q8 NTkuș%"x1`o@Am!1XNQ?m/zިY%A$L9+8R P9wM`CډݓddTߧJ%EZT[=,牉f&^Ni T\$;"02d=o-¥ҮiƮtI>P\ gET]Sۋ_:L& ik w>mA C(l f*gb@}{k5BWEz5` =ا"CFC \mvn i?T\#nU3+mkC#ȧӃ7GQi#M߮J߃JOQjDƟ 0VAL6lZ%4t~t^ŷ.zk=0yidϱ? )hg>R>CMr-╘QگyiTkچ  xJmTf>(Y$ Gbi1%Yhh+# Cfa͠vsaFy(]aeWQ~j>9FE>85.k1 5|Ոlǝp.-:zK V자[>ݛ$ {'l$c D8nh,X[}6O]D6%:}{ԢC>ܜ+ZW }S}gR$ L!P ½ŠH$}WRɽVe^/NTc;f$fDN>;4-=I>mHIjS:^D{G$pWdg#ծك'U9Lqgjb)J{'!#u#Do:[`^4r*+\vϽ/I";c`*_`/l7vd͐P>L+^re$amGjp5M)'#=>W)g0!*|5C;v; ͧÅ Ք>9.8RKQ{^[j,!b\1ϸof}E2ގ;<?Gj );xa.;z.뽧8 + (\cs qLqSO=?c/[b :l50{/pwFq; ~xe;d#{fWO7燔>ɐªVة觽㢭,; v߇/ Mw-.:U]H ۭŃݮ9 T與a;%3Ebjk 9~Hʮ2RZRm$65 e,T2L9'}X8Q9eT=I5^k&~y^-ۮ#].X"}ȧn݃x>G(q@q9ypv^-xPV|eJ|okH6G@͘$6Yg=ⰸaեL"yX#MʿH"#\` h{H)[fBKrwRp|>!T=bp+PW&܆z%yiA`o?W|Z4 %!>J@rkVc'wj] ZCT+vcT2 F_ֵ.~?Xkɺb6hߑG5OEp pR}Xfw|C"FN H9/b o;Xu'ZJNjU^͇3#"_Xr&>*)bF{46p))tvi','EO6h Hͻe' R[@>>U :.ǫWcÎC{/yS@$Ek32 -*CN0Ap߾Iqq #/l-#dxzal0.=YFloAO0JfJzQJjEUsH=Pչ^#|;U5N,[=&q~ {@{=Et hx4fk=A-ᙳwgMCi0϶xlҞjBxP5$]WIG "^Wm,WGo6̘F4. jJ7#jO:}jdz¬} ]iwOk] n_W(>/NN*4"W- zx\2'y$o?>~#m5lTDVo{MUP(L4/!8vh}l̅*V)H> R uZҘbѢvb:=Fg9OT|&b@1LM*O d w<@տMrmIm?Ϧ9Y+M JJ\b[\PlҦq\d]tdZ~nAdIx0'!ms|%d.lLM@j=?m4)KP:=;S9=˩|鴧,kH@HK&RQ"pf|)njRd @=VL]=G(9v55`fQX[y0]yܾ81I?odLd2rqzMJw qͅFZgj*piڔlF%%3FړCKVw ^gEeI2!SI݂Q0}iq/Os2[ˁИ@=Ci[uxvv޳RY[:b z$fL>ZoiIgo64DŽ!vu‚>?ɱC7$PΉ^xnRK #(dMי]0o5'Gwo^:mEoŝ{Ynbm uVJA_?>-/Y,5;}6)~ ,>-4n7OG*Oy>s&`hZ\bnW74*)r['mX Ӏj:*eB cOw5m ϶7:/,[zͻAB *) D}Fq= (Jx,$e +xrqpC}2j'z'{W zhoQ]MGXU B4RG%SRf Zc"៻[dkY `wbb )'d3KKFi|S*[(bvB&tE^m @yGkm{RwGb#\1zB (ޯ?VJ۵ѻ^uX Dc"q"l;x89_{"E6-98DKccL~2{7mEg_q` (uZޏF񲬲oQr.Wpڍxzdr͟,>ǽĴRmxoTzYA]- J{P}iv苹RoP@`Q6j< >LG}w{ٿ k6(9R) }2* T/м'-;LEeQ/kO~W峊oђ\g^0nUF:R =G7{Z>dimsUV.bZ]yP|:X b &|$ٰhrJU[sq=Tld kc_ͽtoaJ,z^.!oX_4EEo}!$Dio 6`LZSߨ#v9{b]}ƵLΣ rܫ&׳+,Um4FwzKZ(3:iiw%w^u}*#]8y02pN*Wgs(yn -ŒM+}SgiBl8*+uԆI57]TYTY)`DEFo6ogAy4xM19Kȭ0?!%~;܇r`7MG6Z?4ڂ~P&/gy  :'oNZǼBhu{nbKdthUXZJCG)6ګg+ ꬉ±Kΰ|s2m :s2:ژJ96ׁ+t? 4 e;BxvA71eV[ykQ!y!rCUd0uiY֛=a&>Lh/hrA5JϿ?hy ϔIHxq%;;9KnQhц8d"^%W;k "<+ [M)F BaJWB t8R`ϋL' o-T%v醀*W/m}Sg}tUVvmorpa h-B06Zj@FmbF'w5ogvQeU?dsG z(Wr=zGx-ZnKd oC>Opc<#+aT-{Ff⠲LWlM_;~͡,ϔ llS%IRcjzl !,@I̚M Yv7Gq:ݑ9Ρ-.2b+[B =.M6ףo -^/xlgZ/]?hd ${7xflH4 Q‡mS \E"?2ˆn wͨsfa}fE("g9li=jRD֖,MyKax㜄̫ }~ݔ6c ,mߪp*=֤3М̀۰?ße|`4\D:՗? sI`~ڤO.s'ԛ1x@%ʶ}JsqPA!iHe̸Dm!A>E淐6s0 >6'BSH^D"}ƐlGxDOKܹ\2`C̢Fnt, !6vՖ{B|+;mAfJUB/ Ky=̲0q_fxTb" hohCנ.0'Tb X4]Iev"G&RƨS1F`i5ڟ[HVi~&w=\.|')y/s;|e=hiE$|jG/":+^' x_/|EʰՕm[T*/]cѢ\o^4;5ΨyM,5Z\ǀUsI㥵/z55ҏ6If WWwUmA?=) ݒԢ9F;t~akEjFmdh‰ zXê(Zjaa63[u*d in!üTIsVh*`7Pdt 4z[ȍyxO(ç}To;>yJF͐Tְ?b3μa0'9mu^+JtCQ紋3}x6&fx8hmۊ1i[m@+Pk,n<oN-;ƕw'㷋ٝ)+jOK,֪H۫t?RKpw JST=?vGG{yz AϟhǠ~항m2mkcWY '& `c(;__nuSi~мm3YP;_Yf>S zt&CWL_5pD |U1Bm7cٞk;h srW7f9 rr~;fr۠fpűlMYX  {l1~hsw1> 2dKGG~rpr*].Z<'ȑ X f'HC֓AL๟'DUq]; j ^5 6 ZG [:p?CLhu~u'wHb)_W4Fun&{*Z1]]=sC~սv-zJ'hmq{m]$w srY-t$OZe4WhQ~A&EOθw.IL"ݴ,W7_H)s@HI^%g6gbF&lym8=!!M$_{<7h5ڥPlIDŽǤ+Ǎe v*U"\L{u$bG[k1aQh ?QL'Qha ,oYkRY$yup`0~Qj;G0u#kQcgyΰ{'Y[FE^4&uI9ݬn. GSGA$d̬k~7UCV(zh`XöO%DӞw:_`Z̀S+7`hm˺9wl*9s>7'-;#H͹+3fa pDt.j#C9XfA]QoZ}֥HBYuݖnw򽻆"^&7-Z=%/nv1q_,Eģv9( 1`b[>"YVZqK$*D=đޥ }x%UkyI1^%| w@Gwyn'kM A\d'1M/{9{u`=T{N@1%gp}aTK-4w\~|w槐)%rbAQ˿!@Vf=_~ m#Ǥr=ZKOvjxpKa8 ;яJ',B@~ V'!v;ݢox%E/l@/q-s4f2mxٗ*\\8"/7ϦN| {!Z5큏 L"]^UVN'C;Ip ᣒzwLw3=/ZLrK6iKu*_ :.1)D? ljZVt9~+I7PZ WJ?⸽t;=&=EO'߃d9n%1XOLm3|:m@sYZ[-0%{ CאbGX u.9\jC^?V)tm|ȩF(SuY ޣ+++L0\=TCCy4xOʍ 4hkZkeިjv1̱P䝤i >Elh}R\Y%Ief@ɻ595ل"8v ^T3a>Fd;i%,҄si T1U_ Xi1i3mEDR'[}mg(}oI8|2gǼXjoKԂP,Dry"3V*AI=ѢgxMGߧTw70е=4Oifl1q@nj]? 6_oe1Fr ^xD6ao?U)MTHPG (t:˴lRe=ɾ@t 'xE1.rjc,:Q:Bےcpdz烳C;=V)G}hc2~WcnP3@V]nyEO).Eh4.Jԋ.OŇUW@xcf @ u*Z2q=R`Kty~>;.VŒ-n7'![d953zOŁo7hX(ύVnBcM{= doUPW$<+^|gd`c-}7F+ /FE0s47ͩI Hd~j2c;XU]Y>aqepKߒ+d &ˠ9C 4MMkھދmGdg1?sĜu|{oA= I{IY0 g[&sX88~d{ko96 ĔÊAsn[Vaq6) +P"ammmJ?qfQSM.yYsTf{4 g~ւU6#8 /rd?t+REI}:^]r< %@1ڞ1ho`7Zxf;ʳ|m+`O\ {0yxUI+ g+g+Gbq@ D ;~*_'B^RoIG$U-Ff^`!Z5J.~0Ң(5NWt'*07H1/u,msQVDo,rUBE*шE hqA\b OޠWdٵ(wĹ4]@o8D l]G, L~ ο;#1T踗x6.  :m&jՐkѣfLB[|2iR@GHxK玻s鼮U!1J%g݅l:&)Rw"N,AjuV B|R;QIpзF̝ m))JVbe[e87&[#&)}n څz j30{&姄眓 #LM{^LJ'[U!+SkAY 8śNoڼwξSLEڈǖ ҽ=~8,4HC(U}BtWCʲ=Lc%5 Cqfs0@i6~U`Jiϙ\v:TR7K)1 =ڿOFjl s05hFumrzTdUq[<=)]OLwl8f 2YTمyG{80r8{nU6zKPw۞|ZJ r߳~GDk>hl'Sˮ弨+a*GOrnQ!Ο6X%T7_F:(X?d\\,dVإǧ׽vsN-E{aLH`|Mj=FH!#2Ujg{)lk/ \Z:$7W-{"x M?hؙLu1$[P:Nt8ϖaQQJBv ɞ˻ۢܯ4|uR{F73n@_ZpORKq ш ֡]G^MV0d G2Cgo{^\k=1D b^7m⻷㉌~c#K_X٠$NM}^G[#V-5~as{tYHyHqDJHžׅ54^y O& xzdz?Zjfv~y32v|7~jǍt&ⰦEEIBgUUdF> eHPdl\,* 7-O&`셉9[?H=6S+jmgyU.PW&Nﳄ30O 1/ o7zxC3~AMbI!p0gq{ț8GGLRmGÓvhVnB~PgibQóE scn.ka"qlUi:?M oY4Ϋ~0h&tri L$zlkN靖"CecG_I1h4x[x{:ԽfJFri@ ڸW<5@Y ;Km4ĕ^O}y|~:5p?.K>Iɇ[ÿ6zc.G߶wӈ12sl Xa癍bidljګ* rل)2j|2d }'Mt4f&.G9UP-B83ob vv_BՅhAd[Po^s"QM?ò <'8X-AIJ\Z,0wǹ`p'owb79R{g 5[I'3Y %j ~ D6(Tt ghIY  D}VXcAofeu KEkc`hW4}Ë}o_DoAA"F+da /@ȞOR,VI>kc>jD_WGG 4'ry|Ӆ,rK|Y;Xr~,ozM7휶{-(9lg ajU{&h3w<eaC bY.T{jqUѫ+l#he]N/\;=TU\WbNN7}{GG ?ᒼv$ 50-m7c@K~ok6tW0:n+dиaw,-o]a'>q~>7蟪_L?So:Y֍u e἟lD@6: sJF);:cc)ݗ}bF/͸+YhC1>\j'NE.Ee&>wFH }=g^-VDcoKsn~ѢM#;u%~¸p85~Ոy:˥>|'rq!_o20rcc %w3ޗOoMe)LĚINGxI,[ '۟? ˕%$,8rLJ|6tαx:԰UÎݫ7>D.C[aTˏ*i%IQ;i+d.+X3;ӗ 7#7P&uh*gclA[9 ƈG;pG6;$*ǂN2e蕫WP5_ëyy٧~iwE2OTH6&qgl1ؐ[lGJKl8󨋖I)b`] R&<<+'o ѰݞgI緿?jByodJJK$sօjA.Bbw{m׆,9_{si&2g?J^]*/Щ[fK͌oZsɋљEU~q?iR1ΣYEfSf"̐7փBٹޱS'#֦Ķ*HQ`*To&1܉h*ȏhBjmrY}F8߾ù%Q]# cH|]WߞYISRh`3S!seO,?a},B."kB!/$~,$/&GMUľ7ØgtQtDxݼ|m\E*F{MLB\d񪗰>Go<9ׅۆe+uv;WW;yOlX˂,FG'gtYS2zcA.8'aU $.(:>"x/ޯ1>x1V1{SEIR)j _ܫm;D[K0uXf|4WiK*Xh:dIl;t#¿|)(/QWhiÔ뭧ѳfyd}s^;j|aTނҫ뫵ÜakHĦa'ޘNhnG3\2;.~)bq>4P*"' ho'yT Jp8y @"w7] VY~8P͎8tb.zE,Uml+E=O˷#ߩungR >'%{im7Ic=U/zC]H YīҡЮУOz9d1%)Ԕo ?G}=I/1ׯ|Z~K=q}?c;x'`3?^)$jEMw."}y݃sc.\,;͛Tn:99-jx_xA)r'k=]k}[ ]?.pug efE`l=HF 4!CcRZ$ rݩ4ڇɳ7KE׍]Cvbi? Z ozdhĊKڂu!z{dM \=wh=+C!C pǽ*MY%^CY&_TA6ӌ?o]1=T | _;Iҷf_jIQv8|^}dC66U.;QىsL"ףŇvBЍՊ(Xk'EjjWQ^biO7ǒr-ӺH׉~9-z'_2.qpcy%CnhWegb}씒VꬮtJYl3qO.VULPpQ@6ihzOD[G1St1Av`\WUwwɧ^ZGhYRE>nI} 71jO `3D=pD@9I-_/eeЂ3δ5gub;vY҉4.ݗ4Xl:q^eȪGw0C=+g+/O*:*'z>+j_K'':jEZr뻈L&A#Y{jhY?E{9C/l1sq4,emLtstҖ^ƒ^_uc?6{n`Ef=Wi tVX^#D뵘'i'}i; P$ 0cJaHNcN?eaLW;hTʻOR/D0f>`PMФ׸ǩ4|Y? ka,ZeZ8; a]d̙kn<$:z ~w$g0 ?DA ˞7stV~)Քm\}gAri@@ .s̮gOB |9p)ujroU:=6Pg. *m.B'vVͣtC~[0U`B%weǜY^I̶0F_{!bÍd=Uv8Od WlHevj-%FWsGotpsqdnݢS 3CPfC?gvpٛ9kx8P֞ז0v9[Xso]$*W!wA]`+.-}R{n (*DwIAf?5Lff[HXj; +EY (ټSl#&89DQshUQ>$/k"F]. b^&v\ffg@{`{I^ܽ!f"hz[k=ZPF\z;/LTU-t;3M2?<,As<UOD9K.҃Qi)%D7/Q9^1|ad D1c@:F$JplD)իoqLM\CݗÆWMcOXٳE kIu|y3T9$z>JQXn{Pʫ,lRFYwIE?%j})_ 24}<"]̥&d޹wL6r[lPa4b[L:|lW6zQkù (˽, Ҥ1n{?,ixg S \|[-cvEɏ#Εs;ª'%jWW.8y*@ T՘DŽ?hdI5ELNwv#'m$UwR^ '[k(ӕc%$) 'MbAgW)RWVB<6q9[Ȅ|!n15Z`Em 9(#f#֭x Fx[q5 qSp^If5C1Q!37#\;S gqmLͲԣrHz=} gG(;&#>D&t,5̭']N9)r1'[֪ &Z7(9oiu{'& Rm8@ ]hCuB:?ռ4t5/8LAmb{ d2-?qǡ5\\ҶY l$zˣ&`QgO ZKDEr^#M$qڈMIONJ3/ *^9=URAF5)F?Ur7}0!-ZuNjMgjGj`7:{9Ѭ|f:T{  %'dJ@ vXZ-"tJK ?*vc[|v~3VIԈ1Ƽ-[hrr{Ne%aR4WSFÉI⿬gj?"IFLAWnI[ܛ荍[zQ9cQ\f-RfrZFLUe3'Nכi-х.R.jeLNDfy66ϣ3>*am:CGQ<tfgٕDf]F&!ݑPTmL~IHuԑwƽT'B i֙ڒ|u'Y$A @;5}Vr.(peg,ǀk%D]YV5*TDbn 6kSoZ}PrD)]x!!~(䬺)T.]$A7- /b* ?)E(QEޅLy`nlz"˜vY aѥϚ8= :zs10O/Z+˩;!)+Pb%7H(sOIeJF , At7X U_ӯ!I9@*rMHI#dRpr:.,Ym['(8;W'YU ;؈fT(7'nbw\8os4~M*Ԩ&yM92vspz"/g ً q ?b߳)=7Udv='xwO5('kWVmyۢ@^{ `ik,qiBׂ>X8#r7MoαAbþ⒗y.35Hfw}1`i#)X܁j#lkq0Ieb(.(uS%M)9|rx]KycHf}(] CBQ٤%aKש+}[+:αt_6RώoL^!j{(H p+*Z>:~EN^ ڹ-HT<_5_iy0 4NZM<&!Ȫ{6j4rk?EW?_qvyL6S=[쥜G_*.!SQ 7<+ZV=Uv%E1닁#+Pm,|BQT40-=J烧jI BkIEt[`u4窰0l5{lU+{S%B9F\{1h TBLAbę9LKREvos}acʃ>‹ c񬱒^j]j_ҳ7k+^+Vgq& (:A(!B;Q )fx/ B<+]g(ciÄb5TC֨Ko q%b,FmG <eiq(+^7(}PpxsP4dTHA:rI;]<xY4Jb8?b?O(rY;pKAe59+9h8,լAH\4B31@[4] 0qϗ5IbUý6޹w6x#e@: #gqӮGv"cфr7+l3dh[)lDZM5MK:jNL'Xs.!!ntn'?>j/=?*O"ΫS6&.I|4N7i*9tlgwrzFUT,%a%E҆cTJX8-CGF%&:l '?H~elmedJJPW [g$mo(˱h Q󰷲R(J~ݺh3rC)~Fv*=qATI}:^1ch7!&Qؗ|c~}8"YQDۙLD2d?f\ s2^8}~<+ݮrqxkgga8,}(2u}M #-|ښ\1[Ƈμ坧B N3ygg>%XCc/ aeTlC;K1)zF\æP/5wxNcR%. ho>\d!eSpFl;+}~pP(’dXh*؇v;C,?J ҂t% oWI4;IkC6ϧf651Lh|fkqצbnD!Gz?$H Tv+paR #cva{"ؘؖ8-NG)8"j%Xׂ~նܛ4 `xlpEl2A̻f_σ?|[ n풂ʹ$q9_-+1KOɕFy!X+ ӊEԛ F,p>f|!וv rqV<맩/`L'VO&w~0Go&;%oG $:e:x\.L9^ގ% q-fb˒K;s 5qଓͫԁ,nmΎIv,(j~蘟eXj$Wf rn:T݂ZҊHQ`w/?i 6 W=YNr02yAg Jڿ¼3f4ͯ-uP$,㬾 C?eˤS!?`xm˃l# (7#ܦLw$Z= 4U6X_+kHu|E WXQk`6벎QdGV '(^K -Hq*t ffڬtt. hf[Sb"Gv@(  mANi}5^-/0WDڱZrBb.ǾҹP ǀl9_D`ȂeMLC:zQ&O^+m}lN -naX @9>\$+z@E)5 ƈa4*ΘLzT"6)mz5NZdi3,MN1Rz+oM KkctbhyB͐'jI} 5,b>1eCw'h;k KC{ ApYpG4(U=$8s|WkЌH6}f/h޲3vLtm]/3eU@ŷÐ9yn щ7FsE٦[<2ZF'iO"1g "L.(;cYrmԲuL%eLH^$L,% "PN\2ڦ`SV%6s?ZjmD"(0!{<ne{](A-!l,`# WKJ<6^c؉/~_?ߒY7)RW+>K5oQ&q}#B]r-(?i$^># q3`b jX?{ڧUH8c.q|lrT0AT<P T'B!QAAo<%7+Dni4|t^'NJ%#QzsT'uCI[!!MfpA/b{~^/*QHL=tc7gkyb|r.و̓DVX떗\вgAJX#bBAh!W*vN=!Pa !x?<`dRwtQgpF# D \1:~)aoe!W5-k (d;!%!äLNI΁p("hyCOea*v\Wh#"ngU=w",rE&zS!_!Ǭ=ș@*5aetmtaIZ{mX::HIZC!1!Dؕ7b>DIg*> ځ@^Oi uCOG&T6P1+wBWc8RNLCiE [MoU'*a|'!rTǓ^j;"gTHX900djC&kF3ƯO]5̀[nTk표%7LXizwQow#]M# 3=5hտ ŔK쐜 iR#_](5Em#nߺ Uq;;R)!f{s9c#"e?LzAH}9BI!"oو"i7F,5crɬ(q @q8{D0,Zʉ#$(~J`^9.leH݉9 #^c-e~!LB/򗰎[Csڞ=ڿlfKA]vϘĸ4HȐ`WdN~~Gsm>C>q"l^φUAF6f"|XF:߻2DVoe'jM$a' a_ wqxQRFI`@2R/.ᨹSʨza!znO௷m;xw@dʄm+B=2^+WD[nRu:|תuL)I-X gk 9Gmjއz1x42i~;$-:ol)>D0-f%E+䠹f#F ´0/]JritF KwոrrT4gp1qL<| OXt! -b'Թl_^|EL8n}O+[& 3zsk7F A 0lN|F,pluC|ϭX/oVIr";D%UplSVW,r`VShL4(I-b݀i䚭XGNp% r-Y݅}9&2/31w2+_|+A8Q_gr(ӃJIXү=q7s (  ΀Xtr7nHfFCqtކS$ttU$7=tU *?E`wk1!7Q.d'h"dNA"^#Ѽx pk|.M+/y2KmK*;lH2(sGva˷yFڧfTA_)ni!? ]I&Q}Uc)Q$Z` sz/^/1 $DQ<_3 ;Uմ;>g]O ">  * 7_'pOжRhzǹnzh 9mK=W~}\q'b~qn#GoJ?_ũKVy:j6XlZch/P!䙪ǰX2͸gซոC+LΦ7;2SިE0XL)QUIw拉\2d2ƫD5#iZ;G^* }a0n=WIXn2hhBz}E4F?mmL-;ެ ( HBYRȖշ{ճ뻑ؓ7FJE%ʼn4LtVkVNFe.EAd<=ix]->iΗ9ozPyP?!ECqP#<7-SL6;B嶙vR$F4biLqhXXet~}cd{#_kGQiv Drx㘶ކy^Ub$ >q56Ĺ z |8r}=27r* Kq[`plpG~scVPN$F!GA!C2LPU%Ni50|U.lo <>0'Qb3cGL15>4c49^C^p6!8-hRA+:"jNɔ12vf"/ ~nƯ~@erP$` j8Ee$D.#Fz yzlP,ɕbuM/W|ג^;2af Kᥕ#u t8:(("9Pȶm QƮ{ qI-9d}S/E _i&O|݈LC*WO3' qr+bj98/<$m*H><ᯥVify7sڿؙ}"Kb kY`dUGX1ow6wuG]_sGޓDGws̀6$i] aM&LUq;_fS'~b}D7csИHTU"С31Kyq| !ޙ E>qca9NQl[pBf:#X S\d*hd`tT:;0cq* Es⃟v%LH1A4ǁf'JívI+(J*`,4V@Eg<c1`b4+?0Ӝnu9u=\5RYT/p!;nnwCRt͵ S)Lߘ;N*B0ZI}!#|;ZUuph*e~xao  c<](fV̦ad拧|T) hW:D\z@D8޻9%`\؍7Ⱦg',j7E؏ E}[ŗA$7 M\IC0KnC3nCmb G mkzAP0xBZ&^_X:Bb,ز~9E;l I(Ԩ)μ6S^$?Q."THARAȲrXX.µʌmX(Qf"Y]tQI5Gt _ܦN[6M,C6_hPUطn8֡Pޑ5J:9""xΚ 'ӵ޳)g|#Wѓw @ҏow[ڄ+x 托=Q6emSn@c~*˸,2DX9a0 x%HV)Ee}9D;.t֋KBql ׻#zȲlSf%kyNeTREP(1~.Y8m *h˛9ZKy͌(\E?B-]M1E|L܋"Qy:@@snc26QunLD~^)d'8_չNOi9p# X鲨vIt2YC)tK,^0|8w8#NdR麓d T\Z/Eեyuab^~N왊0Nei*g5|t_0>hNޟ*B hPgG!B1u~ :5jQ.-躣YShdNs7v73,dY]0" ӕgM 7si*ADk aᢽlJ80a 7Fog,-FOO=8IDg s$Gу\_PpY$9Fa =a3:kv40)":`Wo]o2;ҩDca`i~QpmvS|; < _s%Q%bqEn2[5.Em/? T]o=B?WϩTb!1q#U'bZ*YoǟV<6ɓ8o>G*7g 4̓t6a(KIQqɢMɤ)n Po SG#MS^O c/yOV[B6G,pV{~mр"dg5Ȗ%Q!MD$qr8P,t㚗 aAir~D>z9!Hr!4%X-f> TyxL*7< LExB:j+ F-Bbi(X !4Jѩ:DCBb}sT}RBjVGnfzLS7ߎ IFXb4uun~Ō(dI@^a8un!T`F~zhY675Ws8@1ǫno= S"l8?u#cK$3xJ8n s_y,"*jK&ڋ|0Sn>@fGֻϼ ƅOqIC$8\P ?c_ymO:.ofM:?Ts,vr["Il`W'5YWà"aS@+|Oר-^=!3 /`3wÝV_YE'_ Y95(A{^Tj+̳@8Y }28. |bk $Uڏd{~x[y㞆 JXBG$L"z/ f=6.ɺ1W[<\{y;icp-MfLg,Jb8iz)lr׹vV񹽾}BrFI?ʖoL:Q;^_g{K,ו\΋qGbJ>*:!Dk?;DO$-#dS`n<Jx%TXD޸Ern̻~zwv\ ii~۬Ɋp@C7_oѻZUf[V*`?J "n '#m` 1^^La+h@AzVQ[pF@b8,Ws+ 1>⡲yšn UZD \Y=W&sPں; -s.\~@']eݒ((2NoŨPMK6˭tpI"+eZc3NI(k)$N˦bN8;z24WvwٳPde0hPx$?_gG|C}R"gmKޏ?FAa%Ӭc&Weåšϲ5x:_pGs*6-t`a:ͷ)Zy#V7׻ShvnX<uE!ɚh4T]`^rk)YGYĒs~~Vc*daDCAwy  5`^0JKjz5;F_ 1K_X3 owҳw tKehbvl Gq&8[\?Ƶ>6q,(/J/FN:.dۇEu#Ol͛!O=/<}8ҭOz6LS !Ú \$ lTڪXҪ_ϔI*n02I 헗 Al6UBV% b"-|UXPO;~kEQ* i~o8As_-kBЫPe! wcyC^|rCa 3zYy*=C<9:uk&YO5qcʻ2v~M~=T ^ߛ7T| U{>vG)U}l9jM_|]+,>lC ٌW*5q,*"S`[7>s\6Yv|#ht't-qvJa}`Ij,ٷ}o&hU|g$g8-ӂL \!K{h]|rbʩ[ $Mؒ)E_=q.]e曌y19;ﻔn_eN)չ) jqػg)_ȥ{O⎐ oEO%zYOT8N*8T3#gM4Eqّ]x,#T,ˮZF푈g[1:>O c sS$O??끰TX=f&T*ၐ{!"Au㎼.?T俉[Hr}$}X+M5턇䖫D5&Č(sA{u ˂b:S+ 3:u 3 gOщ$'@?Eo*Uބ g̮U%ڳ~zPZ. s4yרTa WkF{1raSk" Ռ q/VZb"='vS VC;}:+o7'Аm"%ݮOnMf#4,_ g,K`B٘TJ1ه aQ\ޭp=1!3;ƽNIWO* am|GFVvtr݇iSYVmݎv[ϢyCr+,">lzCe9g_XpѻG,.%Ox ??$;)!&ρz珲tݳ)=Y)%?D!HdJq1xخJw!j8dzl"e a^;$n{&Ưx>xJI[a +[QވH&ONc_hZXt,7gD2bj/^ uhL[dnK@:~Bȓ.dB[[,gIY"XYuG[{ FAm(K M'Nwh8_D # n{Ґ"8L&|+gA9/hYbs5Kp˜5%a>1Ę;T=Q|cs.BLhөu E3f .#l=;i"7K^'Fϰ CQ]ɗO\7*)XcqЃ Z<"ŔʿAa'K Cϔ+e2ބw-f/9Jj!)S)mkzkJdNR5-%SF* zTKwF Tm&ׅSlɉv.64}]w(hɆqS=Zj. PǗ)tUAS]@%΀g^OPӵ_~$OD9vZ>l~mc{K'm9!'l{0L~SvF#wM\q k.Ř*__2;Qá~d5o75~Pجg#ݳ+ϴ^6B> j9]a}Bۈ'Dwڬ!y&RZ%<Ijۭs/Z,.y/$9st퓯¢o\ Vr u%&DɃ3%R0@L}5VIֻI4s`uˁB x^i^wُ?,㲭xO.Gk(k$}|WilRg~, S_mD]S ocKH i\#ё~q>Zfr{g8AAYd*${j.$PiU3RyMR ^8&3ƌəOp ZiX:Q-ALLNdҰ 4<}s3ʥ@*e  \ogCBPq{y?m?T{p;Ubߵ7sem@95wio0b*?3JzLcʈT`Do6~޶wvL8@5Ro;O|8%,lVgE2o_?W*>(/rpO]jY+w❢T7\L3^Eeydch?ipFm"G&H e3Y¦Ⱦ"{˗0} 7垩bȖ~ہ)` EbN@DZ2 'FQ>ڊUx@A.>Oa*vX ͸-5]= ˌ $6D%F1Su\H5ym>S: d+➖,<$R6@\ĹTQ@e3Fٌ Dv,.c3;!tp! eߦl|3T|)O) CŬ+ʞY8Iy6Q=|),6JPVGXTOx̱pn~ ~v_[ =A1cD^aikI"03ڮӦȨ¤oe.Wn_,mN]=^p Ư a1rJ3?4}y/􇰦n 32Yk'iQbԒty7ZObsj8'[=0TS`_@E}+WwO]W-ߗ}Z}z2.zVpefCñ~qwLy s%dV(6%ꦬӔ;TbsnH`4WS gBL;t5 hl4*aNNg%cpBU<^Tjfm=.F!* |9?Vycf"#Ue-6Nm~#'cA+27nܘohpoc=uӌ% WsF9A5Iգ W@SxcoDC+^Qwe{;viZ:)IPz>꜃*"U/Ge O北v +O fԶpP%6F:7 zB:ߛkIlWjR/t{?`Cdd".>1*)AiWO|mL[̰Kћ{Qp.ĂƉrNHJ8@\sv̋ʝpj!ą=̑EB`yL9~e 2BYF7EJO[zŅ>$%|s6rF 8 8آK"^,19'O-|kݫ Sٗz^MeT[uf#o*a>iٶVt, ]& Y=94LP XD9òH#[ 2X ۉM, Roս͕v_ш;<OLbTgyRo[W=l-pi{j R)q]'j_w08 A6~KfJ̅ qP2'[:F87 +)H8=le;bz{ BmGYEd Ӝ[O屟YC` g+ۣhvl~yRaVOP+ >l&ʬˮ8oS5g9@"S6rNC?3B.1eiEDJ Q'W(>:Dqt@?鷯+|}U;ߎ:UHۘ6J"@hY (ZSX̄s'F?%?s%I+|n=#2AI$hX: |MLbTmniWSJp9Qu^HP_dEEζZ֧gTO&Op*oyn[U. ʷ wg5.0H;NL%O`镶ϾB/`/xOG.8+WMPw|סb=BZnHTvgـ*3J1nd3!駣= Y(`M?i;I*&{"[y57MG!weduj?(S]ow<*(F4Ͽ_}Ƌihfwj]]>ޫ3XV4 s;KX8O 8zJKۯXa#/Dӽ/.nDf$SV,1ÚfM~\b> ՌC`ŲކRWLK'9aF^Ic?~XF! œ(T8ϒȊ^<՘ښ:Q:IH{m|"y#p j\k#@zfJF>s;{z*`K2f@F;ح|m 5N#xͿ耄k=IBFARRKy,dI \C9cN6xH`d-W#v\5$3J䐗ga8<1t }gO!.f&Z>甯yPU3a XS>vwe!1#2i+xBk}YL0I”P>B qw;d|ڳ/W7 _敄&n@@#:1Վt|ڼ2>#z"~w(gtb5XmO֌JңO[W`uqn$0.=UI_Mـbhw oJu7(cFS k:c}By=sg뼃fv{#|c?ڵ|T&e&ًr~xbr;|ߊ΂a}=-yǨ!<&.;9Kk f%K^W(Je8E xa^ >g¡V^ebRȷgI3Ƶ,dW Qx%9!bH plCg1ݹqq݆G ;T S-|[C.֘dd9]UĝnMʥ~F*nеWI% 6  'm m@NN+t5-cB)Ґ#Eghg|l!Vę`_%\ 񩔶1'P}R%xI4c<$Bm1M%V.vǑ̙!%@,ɩ A3XI䦭ׂR Le^v[R1-$~BRz.X9;43,dAw4W06 Nag)C/.5mfħ!j#kY_?&"3+ +8y#T4..g)Ơ`/@mzx< F[MUemzPTHQIxBDlDQ%Bdk?}{^ቌ'?GXf3ΦqTJhM<=٘&^kwW; $<_p(IO0EBlK?J{g?7zbpj'A?'9 ɘ7.yѨ]'tBItr&v8oi!$S$sac&|?,@ǔ Yd19 DDG]v,P̟Fڣߜp6=u6$_/_HJJ҉-GE#gCIcƟn<Υ tj7Oum߅~[1-/n63p;^* Bѯg\@ ާw{:oB?&߮vU_ϰ\7NpJݔ9Y' >r$u>}8v0̷Knj+UԴʑfPwUD/QZ2Ds7 zsėŻ vE>Vqčxe#e O # ȔSX3N]k|OIHJ̵,O[Y{߉wÏ+XWwǎY6lpKTiFbt S2ծ /cQO Qͼ44G8nz_U|<t⦳&Y6%b-T7H(B@-?o5 6j ef"ީwu+'QE(oV]6DxNKK;8f$.R MԦCfTy/vb&hlOsz-"}K,J4eXӃfYrrͻPcK-83~lɰG(o188]Չt,[X@9sWr[Q,MŐ!|A(2=#%^U(OyaqR)үSr)Zcu,KΰH %(U& O}. +_{OO7\&ɜ^.)A~?ٳ8^o) ๡IF֐:?yHGeB Wa#ĝ F;9CƯ7{$GȬa~FLQ8[baDa?X=: y*:)c8|W,yC_AI֓[`onX*]'x{BmpҺ4uϡS,jcd3dZ~EhRgD -#i\vh&favC10"d[Lf\tX@%$R~W^8 =~p(j'H$j $V؎ HWp{ЕP7t59:D`$zUs51֋ڗ8cщ/| FK5$?N# L?19HDR$o3}l\G5㷽1ee-?0קםх"^X6hCBϻjMq]pfGZ`몼=kɂs@qJEJ dtH!ρ\Ei%*D_V$qjzkOh[t(rp&':OE(|軗DgJKJM5L޾(eZV ttCUؖxo!w-Bjr;Vđd%V) fyX bUNcv3ȑ0z }@UP:SGƙ"u Vy/u{42ՕXV~*_۝rf&\[>%pJVkŴ-0ɓz'w-%}4|*Ë 7h>Bmpw 5#t+u#>uL\(/*~́:} 4S uj;eG|9p,;#@0'u!W)֫MFy&^8H2D 3}Ko>yΘ^破Qq{W+'E΢$4Q^AS/ ==\$[;D9.}uūXώ^ 8w٬_J#G6_q:Xu8Ј9P"jxUfz|Iedo6G1- QU QL\M#|.\&C|Bحkr}F}^D)6̔{ne~tQE ýmF6E2 Y?𛬙 kVBk[8Yȑ2-ĈDMh"'[0$%zBwS-ǯ3b+ r߈epߤ(IR?JQߒ#EXRi4#6VZb$zAㆺp9gu FI0t~6/k KB |ga9L4rm?9O5u.t,#{ßݝ9{0|DBب>Հ*3u|p4PB>ݛ-$u Y1yO? ~`Q%AtDMgPD5<^|Ծg۞6Zto[] `s1TMctBԏTHY|U|ŀLK|a2t@6z/u;EGMWwk$mNB<ږ}` Q7jJTђJ0<;?H:ܷG= V5f&syx%:7_7X2uNl`8.US`\*/ AՑ&,M 6^]/GVaMj<θۍ7*0@)7e$ZLBxw_St(NfmL/_TړA"2(b罐v'R[x%zd&Eꀻ(4̈~Q?Jo(Q 9P(wYK Y'vt({Ż{bD͚T,mnz܍CSlf3͇sWςnnQC`|l4̗Ξˁg\WG?%ԗSV!bO쵾Y!MHQ~dTߐ󇹜YG'Ub܄3sVljX%pat6|̄r<;!OwS-h.v54hՂܒڋ$NF8u7<%ojm=yRa(xr4U˒cbX(<O R]&c4ۡ}^fHkYLP(Ѳi xؑQ C 5ɑΝkv6។x dSs6ҧe$DʙUED FmZۚw(AVD/ĊŻ}rpt5gc|)+aw" Aw ;(/øX qt8!?4wXڈRUς ~ۜ }SWO}yoC>tI:.SCh6PNݧ)C@(YDJE"?aZ.xթ$^*LG]qNnl'ϦOu ğ]nt&"BKSQ7Mx.,%4s$=Ne-}:_ݦ}.?Xmp45=Rvo>`58\:S$D]+eq浠=}JXmȦ#kfII7}ĆץYsڝ;^߂!#]3oܶd]l1GHMV69J- 7:u#욷?L;pz 0᯾R1U+7̓W2$+K`1S}#sO6*%i{ًǜ|S71Ya}n_O\ 1R ,'^3, j"㝒ٰ<M` T[[E֋ >^&kZJcWHl7H2~+Bi=6 ,V!"-yaHJne ?W`jJ1g bc Ԩd8B/yM"[=_a`۹^*-]bzE!4ndކ|܀aCu[!&P'+b>%Oi. 49d9 Y9ƙXŦ$mL zj$j@ HXXۇ$0JcX$ >cSڌy⾝ 'e:!Bl"'!mMPAT(w]}[z9+/qw=~47ƽ' AW܆sKϛLkm$Tt2,oˬlƗ'ۤ[VgivNPJP*pެWMjbcd5:~MWqXBϸPLBpR,ۄ2wXD."*aVN2|.6rer*8(W'l$<(˨YLk 6hŶ^6t3d0(%q 2z~aދ}[ R| e[gl'B'߮k$?y}+#g$2 ŹZ< |9}5` vnw!/9H8t=^7[7Uc%X}Ztsr=VasUϳgd*2VsW<~o@.tvS'at'fFYēh6ODI@ OAg aYʐxGL:?FH;  kZVir=f.yRDB 6+Ɗ,WG|Ϙɼ\nx!6L?A (g+ʧol>?n܂8*DcFMj<9&6]zb7R|'vCE)\y/FMeYw\۾ BGH*Z>%mq Ξ͝?i9XZq"Zk1 Vl4N|ls:GWBC_n|kxn5Pc=<"LVOTՋ;O?^G8MkK.Ǿo6|1[~j/y*K%9Sk|FɼgqLt p]'[7p%=P{kՆ!VƒݠKkzVǛGb:ͅ y1EZP"݁oi<6c\9¾=esQ3$DM1@~X{;]q>Iatͩ{\S?MQҨ[@^kt =і$L]`՗"˖ۥp1K٫['# +a|?+*K=_Aڛ/zr킗lC4-wv_ ;^CHxچLtma( SCjBp-SFaC}1]ߜC_&P4 "C6;$+mc 1u+-vفޗSꍢ!,Q(RРݻ#ce_Yw^PfvLu^J# ll:!ZTH&p{!YqxaP:T$Zi 28/l3 ^uC$oV@Xw [~JX 0DeW9ݶ|b}KV1Vi…WCDQPBn7fY.t0;aOY<\F pDKۮO3a=֋h/EjKBvrpfMlV~͈/PꢜBqwnuȓ#c[AGiBnULS1b^ܔWI)LX({+N)cr.o܈Zobc56I4cqwq$ g(GS+B'|sWD>S]~@JbwsUό+z'H8F\ L. 3(-jY)5/]K N(n3>l*ZN,9oTl0Z3!^YWɄ]F ,^d5} z*d3NQ/!x ȇSaz8a={%=0$QEJEqsZHpRJw3A$@Ul4Sdtw..%R/#)xTVv,ėO^/ DnpH`?9Gm$} /ȁ_-'xhr:6fO{Ok'65463vAPR?c8L Jg0gX!rcpqݸPFuS74x蔊m?ӎ=U }.\'A0 +-iEm9+*g-Gx.o,I3Ip?JB`zzM/08}FW>PEhVkxx7Q`q,]G}(D8)n;4дZ WMSkMUu%3" b)AԊ2nzӸ՞m,|vq B<-eiPmtP/}GiC?,,C.S8D߭v"Ep=n(BR Tsojt}[S4^dLx`1qr>nh]8p؏}8:cJ6{5zp&W ގoc;)tDQ )T;=# )h[ɏ3pnQ lsg=h#賔~? ٭ɗF}||xDJcau 8DuY|=Ҹ!C ?ܱA"ifRwHd?QCiCCOį*`LK?F\̰f5`X|i6_П ?1q/<,;fcez:YTg~xC#Z}=dF}HAHV %9>*iDu}hr|t~AH.G}"- b/\`AF^o !#WG1=\ZsiCL㓳CT,M | :*Y'jn+Cq֟d =.?5r'w4ɪCL|kMW70U3]Up$#t&R~>%(Z 6<1MG:=]~<J5βW')1E6ѿx7>鴢uLx {[< 7َ&¾'N,sjN ~ \=4i_eIfp x  PkMR'|j>:v4eG@[ A sbj`{pš(&!3o$`gZrϊnkUP)J0ގzh]Zw7 A9tgkU1b;1 hsa;&Rs<ZjGGؙZJ!JrVgB릳ԃ$^4IJ/$p1c;+TC4E_z{QFT%C;+=8:ŷ&4bXv>`ٸn\!y>d.*A%S"<ٟ4[RYxF{+L\F:hOQ(Nv5a%2IQxg?V`@$)O:DE `eSVEݔ PVIGE4_sh:ncbR BH~lPrC$|Y>Gli>T5U)ڡJ;);Yj!/e* ܺreW /U*pD"<5 (bh'd9Ӄ@R:npzٟiT! [xn}2k7_H,P't% B5 _EQVo;y_k &+vD]kWlz=onYF2h??f2"%W `dL֘z&1ʌD M,{JA6(4|iaO|@?w(֭[C8M`fm`d{οӳy>R\ A]F9o;~9d"}mښVzw#O5fu|r'j o<߃ƧW8-UO,494cC$D!h}RL& ˁZ< ֲÝ?.|:SxJ,zi;Ⱦ򶗌M*yӘBR^bPBEz.C'w ERt< W-,b|gF Ӵ56*i7 Q[ h 75^!lk{rO1O&`Æ2C Dvb?Z N-끋Lz_]v&F%w8ܾ5z }vi$-!SzK%k,eT-cЛBLÛe}= 2l;y-X 1ˣf(*eBC,Ywzm 0Sa@Y;7!Ҫ S0*f41(б`+R6D.1.\U،%YS6U\jfQp{kP>s3#ξGBĈ2P1P\sl[/RSXG$BrMJ5ۍ5#))9p7j`H%zE%Qُ3橦cg_!}P2kv.㔑2=@?zphyrUêl{n1jĊ_ͧjf5~,@61u_LMWbhlz`d6$Cj}L%㏢FQfyA{ +55)etjMYn0"Qx+G]nIښSg$OHWs\K.nkRmtOǷl jkKJP{i LZWE~@ h1pDM(*򒙷`~t>.6ˊp>Fظ؋Nq{Afm^)L0jHOuz\'TipL}Y HE!zD~=#]З"A*FzeoZkq*<969L5~]MU!S2 WYf]m/c23`WA˖ n;Ox/'ruhuE 2Z6]&Sw8Dp`I)4U=oEMjWCx-F<X@9 ).-ގLjy:lxSD7ʝ$&i&hf6@IߞC$E̮̊jԤ9np͢Fe*I&v~rR+Hd 8Mj#i>k;eɌ"ݜy9 {L#eh9^壠AqU­VŚkݻŋ8p~w{җ%7FE2b76PF+B; KY{%-H6RuyA3)j/#|Z`}ˎ 16hl'd2v;iI1r}OÙ|nFVpq()ܹSJZX0îgfV>5܄n=ɕ Wlaư$O5MuVKV9"A XORMiwq{8K[u\@|ŢOxOpT}\d1wSBt90~>Xq;Z `(rV e`(r%4mx㪥*< 3|D 8~k?AufQMf\1ar%O %+6Kz AI'ivk{ݏ6jaӬ0|SnAScyO쟒CH)KK0$rCm5l7[( z;IȤ0,xlPIr>FdΉ<|cU?nhTh;\I꾕|;6cJ-"*//-{a\ZKHh[~|aӥt_P%|{B%8 q.Y52e굆33BJ&٬}ΞVkOl{TLxs$Ry_#"cD_q`ڑyT_!iCXzWg9cnGy֙N`USq 5 /;-/rm/rnXzf?M?v{_=89]Wf,GUZcodv&k[7Y: ڟ+=ICا;߿@?Ϗqn]81ĊS~3̈쏴yY\yqht⽉[߫(yUZj8#i`juūD;]nGߌP)%iޞW<;p&Tu m7 OU^p|k݋*2Aret} \KyCL} *m9l]cn?d6FSp)||E8`Ѷ^L˹’{wU͗_KW*O]ݥ>Xz þZ_C9b?i[-g3պsY򪨩QTn .>Iv64{=ZJΨ67oӫM'': (֬a3g?9sdBFZJS{+:C;}F:TcR0 ydЈ%S0CfRkR>c9`tmN?`hL7wYHjf%JZ 4b%vI#x)YZ5#w2~k+L_,ZlG~|=5At^N%Q.x㏘lY#]di:/%Jr¼CzE4λνj,qE5+~ml^]G7cfgj *;o>@<*~ !yR%(b*4VlFxޜTs0u@ڻ6V~ܫ_+<{<4\9&B5sYnC{3{P?pw9tj̤=M,.YIv;Y͞)YPtӿ5ܗցl: 07[b[aܝ#+js5Bp9H6ix~{`ɺ0\oq1 8fcm>b;o$d} 3vJ Oicp~)Qa'QZC(ln]k( M.ױ0%Kn-Z)#pzOeX>i8A0 B9xSL_(Fe>^%:rpZ+~WFg~|,W貙 o4I$P5=Jfԝ6̎w\ZXS]vKcsSKؽΪn&`ѝʬE7t?vŸsR{`?Ȱ&7ny 0:a7W*U,xOLgj׻QwXrN*ش7Y֚`FQ?0TtKV-u{> O-:S`dA m411O}^AP חş >t*Ұj!NpA %  FGvOݤuHgAP}t0.z&`MNC]:KfzXk䢥/hu23~%8222n9IqEZgߩ_8|50ZOrRGHQ::}' y{ 47/; cjXnPn{'+ KXLM\}R0 㳱kl9H|5R1 ~@re;Lrnk3ߤ'x_,;ܛ_ὢȤrE#›޾]YMwv~J]擒Ro_l 1p] (Z7˝H6ӕ!)Mef%JUL+mLGPp78+U) 9 ~}@UynfR80娟T`k]u[ogCkGD 3B'׳zϽEV=مE3χ+Y'!$ij쳠86` /Rʬ.,6hܕ ͎YrG,_]MB)cp-Cl뫷l^-kŀ׵ր;'yD\ey|J?IKB9$?ơd>,Z(p7.~&ͦ6fE}d^Eq jؽ┷Td\\*d,*Z. AW/qarʼVsWxO$2xx'Hr^O'?\TEh6=ďΤrC daSqA'SBzrEڰo}ٲdhۧB]uWխ;%(E@q 0ˏBR= Y5qIɑR<Κ\-ڧ]=?\plo^^^M;mZz8oӶ$k V́"/ntM ^y1[ )DP4ްDH{ۻ1"C;}N 頝!/`)\#wEࠀ5ޡùO hc:uGuL@D~{ j:gFR'<Ѱt5xِ|9OS9~C)5 Ua&|Z86)j60iЭJiIuZ'~Nb>.ij1L._l|=] @N 0w Il*|7aR 6a-7L}3+u3$ZAv6QV%Rs7TTIwO0>5xv~G C T7{6(ESRY[МMze0!2E[36v/}u1'@{ѓ07aXeF`/nSY͓Eo6qX~ ^EԶy %A8lޠn"lv~^¦_"XXVQluZɳN;h|~8F R 㩽;'1Ni6SRDIp3 ղryVL8 'A@-ofK!Fa$=i }<ۧb,:?( M@?9N:]u18,zڴ#Sԛ>̟=y )|t?^:5F!S܏8VWx:M_0d% Ose~o4H iJ7#{)8:jW2TܢyF)YQ~=| r!MKnuE AM7_qТs{me{9NF %Lݼ,4?[^Ic4\8 x< [q߿:T9N Pԣ'-}= /p]n.~۩`.}^}Wiv+Kuki}ԑK9O`@뤠PCm\q =h4P3CL0`o'|eN+'#1>̫ӃlYʿ_=[e3 )ln^{>Lp=R%SOrs'hӃY2S{=d'ir^ۚQ<K׋Q+ C--tSƒ2!#FAYZszOdTP!~[#u9¨4K4F,miުwAH1UB4d6#k1[iòJI^Η6rf{N:.xQ`,Yc|e5cDXo[@DE;:F|̜rА'b73Î 4 .JZ N;(_AF׸ѲJG6oΗxGDAm*Cgэ5f@ff ̖*|  {[Hgw#YZ`5Ue$ILI?:7 ĐB_RϷ8 4qd)r 7NSڀΡAA02/P?ٸxYfXSs@CJF`=O"!k=eCYKcuN[ }O{%(1)>R4O78nbu^~ ~Et߇EWܖ|:{43:P|6B7ndMzQsпo8kٞ\td;n)q>wp)6\YL#l=ikJ-0_jΜ)Γ6)j:nc#j>Z#ʕE?-ƽoB aPdƄ,đ~}?Wn#ְq^"O[爀g wVW}G>:F:9?gǐ :KpANlnsfJ5]]`F]'<֓:&Zc(FnM1U|PM!*Yga܍*=s@ &1] jF/H8^J֓L^䉂D~~pvwPaf*LM[Gb\l@:(v %\ɸ2O mVŧ@uyQFӴ&7v_T C)l'9$trW5s"][ÁCDXk7#/z&?^!!iV%tx6!}×E y=޺ᷬq9Jz l>i,rPG#D̾7m@_^r3sKAiUHAg;TO8 rqfϰuBKk ._lQj(u4qy(u@ߚLC}]_Wm.o47o3z~Ut+$O$*Go`РMF9Ǝp^I=p-SۀG#tym{samE:7BV?T2ۼLP-ݲ.|Pߟ\$Dd+|@@ !!WK &of``kdG@qp|腄ٳ 1 9'XZ"xuB!Kޕ!GϰYӃFʌ *OG5zu._~G8||rm[շd7f-G)9ԑHqJ[Ipfp(9Ӓu ;IdY+B?dC6PUx >OJ.ZX[K׍ Pc3h-v]\'%٨k;]:'=܎ԓɆ Xr;`", 'uǼYKTkP"1tx":GrH>)Gc4uTYQ/5̌.NTVHtA`+&XNHff` aoJmY'0Q_qOZ>P c Nm2Sj=̔{8C~d(M{׵424qD':(YSbxrlC}4#茬aE8 ۰UuSiFNt!U ܙ017& # *| R\2 ȑgMq##" F6 ;e_8I$L3.dMʵ3;c vxs~d(xp>['s='$^^K r(PC[TkDcok5{fywZs 4y7K7'm+r7@DXwb |aw@^X\w)$ FBZ˸a‹,n*Q-KF+>VLyMj}+g8S^ Y(S/),l,, "¬_9i*˰.h֭q.S`^a%Aۍ&Dhh6-hyޭ=w&Q w;IQOq Mv=T~%(C#Ԋ`mhٶpբlpZlWV8ttBvE-ůY~egچKNbKq <ŌJnIl2RwBm ǧn~U=O*e0]Y P8?axJ1KFHu n`vxmdco)m iW}ׂ۫ Тd0ioHf^Y!xr{G-O(_sYAx8鱩.qKǹXc:̑\KNp pD;'lI-E\~+uFv::0: ~Ow5> o~u 0f77(80*#;P^Z9T(?NcOɱ{#NBs k%CtK> 뷐D?"-rT)cZ{xmNЯbOzā5ሶ)'6>gy׫ )Cߖ) ͞VԫV4T`eoFLJכ7~ oXk4EdjJ]y~M1J@Ap=2yg#,j #:L b> DY2~d}tc{Wvd:|Y'6|Wa1 T* VqѻFJ8TRPiP>۷%P/e/5+뼪P! U{[ap5'!FD)b.w\F%":/=xUeQa9p>[{5|9ܪDE޸Eor<#DEw \$'\%ђj{^%NFƁ=twOA]Њ1<*N;ǀ˕gp08ɚS\6nN7y|(މMy{V"~md!@`tz1@]F6Iݻu۠ί ֚Ny.8& (;<9j yoTs _#(lD܊F5=ҡ@0k:NP=atB*˪o6ΞNl q@e㢮S"2*?[pk:$1aڵM7SVHIw4"V׺\~p_BIz{Oy u𹠧TW{b#c4Q~So@E;&rYw_U%pc6S M=ˎ o* BJ敝~&g`(X;?htLé{{g?V$?${]U mSYD7 ZAQ̥g4:eI5>- ifH.;7ŎU爭aHzP=3S4ًq@Eba=c29)J^"QcbPE5ȪrH=IӘTn0J ,iؿK?M'\˹LlnJN]-&N;=}96)PձEб1YHiW9ߝ_n<.բX0!) $QiErV:IJjjuӝ ۞J_ "4r"dg, &&hNe}BX+\+ghuڈݳ 0U0 Q#D"wwe[ taذi" >\r&X,6aTCB6MoN{:Z}mzI&1zmY?2AդC5GnHrǷ W;>|oya;WKT=a$Vm1M-L|pBZD4; S-M"3enLr뀙BtTau=;Qpt|[H/>s.hO&{C3YeofeXEڶ6IK 0}#K1ՙrRsѕEL^^Ù9YjgMdtO9BuisʦQ_9\oyb*M=1Q0[y$v|h`+xw!_pe|CsV#^+O|]>Ef$hB3lsM/`-^OlК[o|sĠy_J^=Us '*$Ɵgy W.Wׄ>=3ߔ} f/ݥnVV}-WP`4:kJ\1^$zBNrprF:g>zn?候 krYXYDDY׸[I (60/38!#AD&bOJv.f[. R$Ria:Ј`t9uD056at0̞Eqw/?}gkAXhkm =h QߩDԹM H f.ϔst=)h 8^k4uC`?;.䢟-@?.7< X7yl}5gh8|F7]i*şstosIx : LC~ުHDA`h̭2lP Ay[/@ 钁&5H}>`i@z+оX`}?> +-ǯBʥ4OZ1!@A:w*|6TZȖSHTCTq8#H/A(@uGst"%:/5|9_ٝ iSgR.f:1#?QK'f7ɣ$SOP\n1J2sX!܋FH-(I^ VLJ70 UZW䨤HBuX OV_j^@ԯ}nɊ(V7*nڼTv_L*_~ *#:+}PJyTV D~74Պ^י9EmdC+ƤQCgʍ"(xj1'ViiTFx0W[0jLja,-HBmT5}|Db/ЖZib"#7z޲Ѡw*ʓllm5J`ԄUi܀@5i6*UWFFӠU>ϵ+,m]g1 uUvW* \ ؾ?++ /9h:cLyƌ5EsdwJӚ{p/?wn 0"C`@گ<[扄NJNɵwK)ٹej';-m#dI|nc#9 lIPI|qt2=en&_Q3aTI-D/+k)?O"#nO<%Ra[[Zr7Ҷ4 uehOƍo]3uPǤG,CѸedDg'YY8+ e-0WqLqF)+憝I)&\:pel[dbY[KOߺwePvc_UJ˃.DC&\}T T1H>WM^QTTA+[NCk+*%sƽh&ЅJi? w&B%(gPtvf\kMRRQI3% ckp1,"dq?_>ѓIxgM/%O:0A}ʮi)RT4''ie-x~g4yv47o)2'v+1W&Ao5nCb^ky|s-@D9уB0$Kq1F*3yP%0sRQ .eTW`' e0=6;qڜh<Wΐٝ@ %h91t1 ϳ<g)ctiɆSCd!E+ 7:v'29l)XW ;297$>HOMKfs zcn_'+nfp2od(w 5teC=>^͉q v K07";X2>3V$}#!]OsUHLLV84nUbeP*=#h0J&ww _o6&7隵J7ȐU=ԅq8 - TJo8q1ɕėq]#wU|xdQA˂rJ"!/ھ[yh"EQb<&{6%g&7Saomz&+^-LsF, 28e$ B *,%w'}UF7dHL\\ѿAq lmHd%XƁD%%1ᛠ%ϲʓug?Al.)r')WAȌiMO?3fT u-{Fd9P=1#̋m5#%L#';~zsˡwOw+:˲_׶tFcdd+сd>ܶagdKÀ0ET_`}JSbNUe0PAӯ 7ӯpe]nؕ2V-HY^)޿7'Hi]~pIbW9Cch.( 'UΕ`=6\/(a(I|{hb 3#L?V8 ^Ef8 5X+@T%(*oRt3([\g&-==w!/ŒTrO?G~}84haC9wiX9ً<>8 YٸLR;& c{%PF2l86hqF@4-~@>bܛF̮)bs`\2džGdS} [~R|V,dvT`/`qc GEVm]qU_UХ #73ޥX'vFa3c.k+^:WSN7CdICԎ p\~¢2$qhWTRbzO+Ł*P&Khш ;H7Ć\,o|nF6I£pKDuX>c{/t1XGX@nzh%Q/Vo7G@ڿL-Ry Y $2%,[EZGudyc(ֽ _!LTވZV؁ &-Cq8\q Ɉj1\NqxdH#sk%Ǹˆ[EHq ʙ{, m dQIHFz#!kgf1eI_dž*10`j{ "M䟡\7nVԙ0Ùuhz5B_ftʄ iI@S}KOs!"K$N5LܓEN" ]"q`6xi+o S`80;~-ƞWZ] HS11qtx8>HICD> ʀ}q\/yA+B7-Eܱ7 My;LɒR"9 ,)^͍mlO#|icX}ER;XEcY0qԳ v7Y H=Z AJ'oFH}.^o_\3,__*'F6S1> rƘ;^^"XDocX/A/D0v@;4h .w+JBˀzUkuV3g$\;ilď A2"pLt  &054{1Zr .;^lN %KORebڽ6M dj2gft}pϠrm4Vm0H01StkxAї Fv&ATa\VؼH;cXlVa\#555DV*AeZ2po\<ׇ5;/&^abAB؊Ip`;S,xK8J6"~ٻX:[Zkۮ v\*?D/+IrťeHl梛퐾|&̓&i[Ɉ9sn-2Kv753*צҌ4g;*'R3-oŤ2\ṯ2ִENe\ʢ9,X: э17QԢN&So}8o5;ӡjMY4їxMkͰɞCJyëu=rDՆ5BdK!iCVzE}Gj _M+OKϡsOx'Gk|t^E羈C]ciɒr׾8\ZvăzL@PBJ9do_vTn`Uqj5|/T";Y 3"Mڃ1ts(֢jUwؙOOJ$EyrCj$g!pE{:$pHs+5c,Smm案v1.̎XZ,ˊse~ {9[*zCvPiF̄pDT=6 Exq&"?pGI$2ʓɦnm?;:р!sE|&.~ Z $:YYL35$Uz?f*Cye1Ef}+ :" C٣yr!Yw6߳Et9ЩK崣Q+꿩ܑ89n[dEeM<(8`*=kzgF ^ZC}`I5gD2Ƿ(NY׻~g},D\$^rQ{֫Gx82? ȠC}3f ~ ]&8MQ 󸹪$?̾8-/VΏo0Փnշx PsnQ?iVZH[mV=3~$(vnʲRg{S<'eF0p–[~iEe9 e9bQ))yLt9V;YfDbd: skk:[">lp\BO]NjzVN%8偽,@?5[i2ҤKF '8G7+FbLZd%]MĹ~dZ4U?27*rsW"6Q@qh *5˲1/*e^csXO.U $rp%*ۀz,|=>_\"DΑ.1,BPpJD~hMMnx-xk1rO/1SaXsy'rs~>PUQ,H@PlE U>p)|A4cM}34?V61!%>$( W_ܜ) !_CrrBngfb22B,lyr|r̲k;d&Eم[?PspK}-LSsd NDS4egķ'A,ݱ)+Χxe9TDԆL` FM D.H/%1>f>Mo\O1`;1 aV3 EwlV[$ڂBf~p>Jߋ4ZEvNݬ:QhZSP쨵.MW4VLҼGa ajM M-˵sRnqćL"O;u8moN3__ז#T<_#t5.?;Qe]) s\*1i#dSI8Oǩ:L+.ZWb{/XzhW)?%6-Bu?7X2ڶ"/ !T2!ȑ 8VN&GOX;="מ/$6KA04E19h6 Dfk܌݅|b (0,?~I3+dtAdhW ʍXI:]g.X\G :7"<@Xȣ`׺42? 7Dzp]~h7Irlβ_35cǫb\?u͙"0zS puXNW/RŕO=1&dmelf`oofmeHgckmbkdgKߖ F2!"'[X>FF?o^(BdD~ HȊY[vm\|dʡ$=B -!EHG3bUT$G܉v&/gelj:G.P&RG3cWWngu|s˱0#˕ĉʙYyr9 92ioԗƗ  >;\yۨf e1\>֎(gòZV~%hBl3L&k!^z޼X---`\7jA7uKz?g]IBc{yT]FL +Yr O {B ?&[*j j5Է?6`R$j^*8DI8!=ބ!+H;X&bᏉd!p_2z h@ȣ6b KtWU ' DfBHN[ϡf4#eУG wG/ʀy}/{0$#jSy9BŸQj4ǚϞnۗQ7kėa'?M8 썬^gNJM{Ǝ 1o i'1e#%$"-Nmu I[b;*mxsP8年soW^|^&_=m{yݾ/jkmfkmlvtx<5.nmhoxy<\Z[jYw˰ݳ[;]\xc7^ zb>t=[ʆnv򼹜%1~<$=Effn6>Ë>ɖzx~W['8yettZ۬!*j$[#<+_wg[ai tojr3K )W{^ژ92OxA-9 w;vvs[PZ{GS{Xgyyi^ū`eLK[ӊk񃉕,ﺀ@ - urPw [e&-uQ8Sw&[a5_(W k7a3e}|㱱ePG|enDww=*-csMPqUz{t atX|Ew1ij͋`cϋ/||#j6ӽ ܻ`.u y)*{܈y6Y+Xix_H>{>l7Uz);}n}ɷX~{Tl}QsmS/10;co4eRFp'qzVg%ƽ֞s t1ëq9?t uVrKٽz%x@0J KV5`zrvpr7;9uXx*t @oΩbu77M7fɎPůmv^-t^&E5h&^T){ㇳ/^YrIlXV88aLkvT9*xuƮ_ <{Y[}܃cTnlZ+ꃱlnoF>6fx'i Cd^XόZEO>d>3LTJ&NdMTܫe}rekFhW8T{%rPcC|?EYIDYѭ9Qhqv:7[]_^]@*MWbP5w0%~byaU:::h6Z j:pg zl2|"\*5cxi^uʗu{??l쩧Rܖi Po0޳}ܤTrr:^\;tNezf|X)[ɷfﰲ{sxJ&mysqp<zvn acqݮxE-qQ 9_GLPSwF%g$<6從ɔnk@6]y)ssuU,֚XqerFΏn~2v4R5~k(Gs$^cQ^/wohr\(B-omUVnA O(,ܸ&#h^,є29@2JN%[d6k.0NdmvEtuf|MCٔ7SΙ`cfl%g ~OyyagkLrJr~Ayy:ĩ57(DQUģN(Q XPfߔw,(u,Z1g[Tj" ,rlִߢ;c;/}!A|>#^W ;\Ǡ1lXZ59#FH:`ޛ4I \{T|핕iQ./.G:'M-OITEq2/?y%gJ?13ū8Ddfw\б6^|C6:ɪ\eQwrC6Wh !{f2Qȶ8YÎ|1v?$mQhfI.3xdC5邧v&i/gk s`ɹVn~o.^"xJA9 3tm9+tɝ*w2$UZy#UwƸWbHJ.ıKyDIgk巤հEE%6Bۼ[nم[xm5^]#bXŎ){1OEN1ݭOqcΌ{MuINLJxPfoW+X?sT;ft^ggLjF=xmrA 8;hڽRI9^57uRĈXSGe{By#8Ď՝-ՅW+}#Rdr-M) m&ۓoaAuk |$!x9۠z ֢uE0 lQ$3e=xDxzmmU%!;~qvɝmqӛ^WJR-pI NuUՋ()Yu-m',˙Z΁Uŗug=GW"Թksmk2zd /hX${$ko}4H~Pם;Nd_9uеIt)Z1}|Lw#,w T[h}[hK p TW[.۔>">~k`|Lw 67A_:ծurqtsޛw?(e{mĩsio!Cw<\]ˏFzwkLי6H&X׹fqs=ʝJYvܻĨjmmIn= s*~c0%p3(\Ζfړ-E-ۇT1ED\[?Da[ͨkwqW*:vm\"8:*8ZCB>I1$w;&01Ǽ*MLZtCy d/pWĈ1*SP Ϳd>} ͳէzj`}M܁zq˹WżoYk,1plO8ufj ! xŴ$;̲)@1I\m<駋t.Ώnw'nȼ=>^92h0-͒˥tzv||!.-Xn,}N8cU-UZYRUv)]c``5[]{hA<;v}=-ީf\oV;1FW%nܗtAty;!z+[GTpkRyy㵗y}4~D L9=fZ[O^\mWF { cDMpYzYk@5{n=|z. -}>xx>PH"XՅ(ظΰ>UK[ito.7 ,> Qt{L_fm𰞽gY/w^tr9yF8?g)˩7ӱP"v[AP!"{IkUI:R=qmͧ{cu/tԩ1 idt7ovP{sCw)O ѫmC_Fm0 x;!HpwKpw Nwww ww] $ksZ~|9O1fS%~_L-ޚ\x/3vM_/> =~foJ&kd_R32k^%>WI.' |o 'yElP~qmGOF8%MfyZdn8]^5)J^>ć-įuasDmjr9XCTpWۈ6M絍RZUX emXb&-^j3Ł4/p R{3Uœ,گmwTϟ&*BiݿkkIe$n0*qP>F KPCr{3Jq*c4O PW CJaczV@ׂMM >RQ~ͼ|bYukx|ctQFBV0b2 G6B3SF-PlzF`/} NlbvjzBO_UG:ۏӔkzyOv dڧـ4 -#uT> َ AIuY @kA~?EOLԯ[ns̩fI׆Ic:hMvȮPR[mXs*YJnpSw[n+ irnw P"!xd(z Ҟ(AWyaE%b0dm,A#AzԞheU(a_Zp%rb֗pimmچfWBvUg`e튉/MpbPwyIi J8>n5Mp^A |l*],+x|<1  E@߮)xG:K ) E.4 } XKs9nnW@ᔯv,pk(fb ]Ȫ;z=yiڢ?V]oH=#/2r9"AUX`۾9 #*?: ,S&? E[n2n0}v\9,XvSBK\ Tѐ`%䲨fʂ{'Z8%B *]mWϩ*z3RI<<>[<D!m@YO-L}jiS3p"&`26ծӤ*b PrqRAuk_BU8OET#L jP&5"z֢,|K/|+ g&¥u}=bXNfl6M\[/ ]3c(6>Ⱥ {>+ [r;+ǝasHyW6P-qg;d ׿zzll÷H݇'FrKnUm\OW2@~YuFCHۀhs)sD^8~LilϺqLG?tlqU1& [mnz>Y]/:FWC961mK c"ǹCb]J^hYa#ya` >[gb9`-С3gJ- I/㨽~Efp ~yhyȖl.R%ւq͛;f6|{#+Occ\mhFjצi+ #Zޔ/` (gg U.rT{ n45Ǝ( K)(ݿCZqi;]r|D癿n - :tԘKNfb|;GA3B#sx/&tj7Jñz֟rZ{m456]>6w}DlJ*wd:h-h۔2`ЬѶ9[3 Hi>UN?0U ;-b_ dlMkJy[^ٷQX8EI™{TgmZqk>izб%n%aJq]5d.P)BP\Yy@Z@)wؔ]GbNOڟ4@wr'{tڝ-*$yq~䇨XUMW׮a7.jdDzYUxjʥcX~zz,HTF[­9|ٕUpZw_&p%̑_YM`5hɚ@#B$^gKpڊkrOq= &:3^H G7;P8yeg^=&XTS] dUQ E^[Zվ> 3sT0?8< S PC"#b8"#] zZɀ -S_bK3W~з^5@3&f_Yak'c"^FO|(> VX_^!_sȴxMm-{Wߔ0'P<9!/N\nH]mٰCN=[b ivuڏGCwd{U![!@7k,,Ԫ&[˳pנs#"BjGDŽp컭\ "WGpdx2`7h|re)}l3IÑ4]a5r5{Y`RK_ ruCy,juXڹM$#׾̕.VuSUuGy&;Mܛ"4 ^ "3 "Uz4XQ|( u7QWJ␞Ry@_K4I(z5 me&XC\$N*P KYo'TyM볺ΰC/1qQUHWҊqgII#pbBi2-ԕwh '_Ga*)id TB{ yK[+#3nV<4Ƙ׽ՔP4I! -@]sb@%A<gmzq +._˶2|IM|.@ueL?V%8o_vkd#-f\ryhJwx&qx-fu-Hc%Y\"zVjx-'* HgDʽ߳ 1H?"lyHН'jF/zSHvcwo ɒba``C> \ IĻ[hrtZ;[L\AxEgVbXp|T3}LҘ )ug@XD1ir jh.$.Zޕ*RkG6lhsɊ0lFuS@! 1u* G:SY @Uܮ_[k&ySLjrkfƓiT|n郿(ċ^y =憖9H!#:|^P~Rwb9^K}FКyAYYy0Zsƌ߄D[)eUw3 k|w&~vw_}y"5aS4Baڬ?sؼ^hl sna.)C =T@ ۇcVts6*(9JK\ߪٜT3^)4}k 93 6,k kRQ5,vO6C 4Oc?{&kFݽ焕X9ɩo&%Gg&m%/-LO,w/~`zw?8JyX]bhki=%GPbݷaM ?gC?!7#4gOhcqXK뷾>]_*P2!?o xjOۀ[E %}lN>*bW(a(ldL{ܲZ$ިY}uFmPsIYlTc JI $.iD)D,7C[.QP7VJJWcs#*|f >|cs:$pp^DC- "lsǝ.v%d{s+ ^UGߑ,QGN_=BZ G=΄HY]aPSegӼ{XJ$t][XT-PQ IS0\CĊP߻8μQ"Ĵҁ׭&a,U10->p0ʡяt@laD YWl0:0IoŬ9FGð(C2"~Ք[ުۂ"F'-!Q#ErRXwS˿Jc{7qVO}qNEr7͈4ͰȪ۔)=~U>oM3QDr}bщ~Jaev7s.S%ud5eQ{aq\2no?ɶւ0}VJ Znb^]L%\]3h- DWW.տeZ[k\>Uby6sDɅDžB87*9We9 չ~,N󋙌 fcT#+~ [8'75áv'rQoc Q]R0H"^Cھe-Kp 9qПsTݹn2z TZZ 7Gh.@Kt.QHNoT׉r(s+n̶ .>*b:-MTʍ2z\GU:0|鱔D 19t>aᝍ O@8mpm{ Zm]B6k8 Y!d^c+qZG_m^ TՆV1oݠ·LKa;0~j>sy$59uyKUTվ= Qu4=q#S * 1S c[%ut1ENA^U EFaa ŝ{,1\}ࣤڝ}W4=yfv"^D w2(ՎZ0fsuD~L.ҲUӪY--LE4D[[ewPG!Kep;,i&ۄT#'xYVHqq}QuYyӾQ@9 vp/,Fooҫ|TB9@`}李e~ pA0@>~>gI"&D]+IeFBsvNvAI\z*WjﺲMftLP ZEg )OQp-^sv]8vF_ 2IޮЙ6(Nԁ14,6_7-2jsZ[FY uXWTm&)1 MqwM@qy?;8tM@x"gs9xyg*`-+6SUx:ch{쁜ui7CxW\Xt>R5K܉!;Dle Z8oI~=8>/| 'ʟlj7JI:t/>zJ u9Lu, -jف/ڢd f({oN}?! jhJKY}[2A3NK抉^ZM[ 'x8sUFYlC~HEVDBŌWk 6=n8SB"-߭=\Yv~\>D%^ 1CV:N=;V_$Nʠe9 `=`u)iPD$WPyAMgin&Na<yԖwUi @x ɃLn\ b-^ڪ9Skkplz. kh@(F~;43IQ]1* W6\6*J#1RJsI`42CD.[>dMOpJ>J!FH6 Vy[`,&̯D*JA#I>EL냫9Ujŋ4:#<:o e\nB{ly.Ljv_4Dcm9Ph]/ař& j(,wZv%t>Nvu EB @/Ҡ7[*Z2p_87?Y fJ#nc%]Gѵ?뭽DfA^^Bk,O{ ^zP\xBTS$#.`wB-C[ߎ='9ojwBHgl7*1ZA|WKG}9xm2$ fhB?L؎"k9#kT-ɴq:O5Zq,lfޜm ,X>rUdLIB"iA-C"SÇkg{,Yhhy$.RjĪ 3D ,>#<;bMăVd+6yگGq RHc B+һ3mZPn'Vx$v[j=#f*PA=q]!N*ԯNiP}q+QV`;y#M|]ƀ Y?=0uf5F-M<(edڇR/mP(JDTNioյH@)X%eSZ4 iڼ5Kk1f>L&&fbJjlq1㰩tu]I`p*Z[Q4,uǟcfw{M>0+q*PABq,eBҍ4v B25LkGΟZRWid~'E E{}7-w19i_ho(154x{`NFYLV,Pgh@cٙIc{E\BP4gb-v̴ ,pUcPe5~- $;imΈܒ^hp=$/Ic&M"9OOa7xC<&"45K>G9asB^u3M[q[f.J ʐtgRDЍ?&2g\cwt=ƅrchwwgb"' L"bc0]kZ$0:ZQ!ޗ|-.]?[f9yġ{|͗;pfҖ(vJU,!{>A_9.z.\5#+s/ʟ1RgXz,=m98H/iU3WYV%K'ͺV}@&W.iIjJ~3S9b챯`E8mϐoe /ϢJf%)&[JI5Ge hn'n deυR˫BզM6 ^YS_&ts;<>qR}M+Ke4%\nʥ:(T26ЉڜcYsʼp4M$XiK`mk6leBO )x.[kM4K}ַv~|}}\{`nd[cjqhlͲΝ?^T_n`2H$Z(Zg]ay`Х ҀRʙ/L߼9N{$j5"dZS 79V[@E.Pky)ުFAO|4ʪ%T2X8;y+8w:> BQfQ֔|kh8؆fa-2X%1k>q`Ƹȷx@'h^O,\Fu^füj[v[8%a3ܶH&P~ĝC0FqUtWEsL|xV -QBٯ( {#nob$U|?έ_ HݤN5{Wnr4GF-/9.Rb0B/{j+!jGMKr }Uu՜qmi7T`A?Uz.; ȥ>Rssqm %s O1ef*KWx$dpWH~\{rF#9``D uXIGKO u!QDМ~;'d\)XԮ\S lnss|3GQb3jGvC-"E`Z>% =l4KB燼~Gb@f0zBPdSWkBCf Y"#&\kW`e*g.,99ؐ+ &{Nn-:ky.b)F PHdyq.hE9jԏyUq{jӎd٬7`z G7$9ꓱeH7<$-q'"YP7GR=J!Čs_}Ǣc w3E=] g,řO;L}\H 6R(27B-m}cG/(?m̶NwԒ-GgL Od^1]=ѡX>xX.B*lMcj1Srhh9W(V!LFoZehRF,YLFcO 3].77nkCDn!)+B2&8A;b/kth]~]/5{qqv_Ðݵewd I_/V]gBE"0)3 bgTOQ]=Cr('Ťn揓Z_C`V2nD/4n%(+Q|%.Qd ?K1ٳy1&VIf|\Cu>9@VW\oC*2.Nn`eeMuZZm$r_7U֢Ɵ:CǁƝn5*b`;wre5z>#[s{SWW{Tp7N+[ >GY'g6EK -qQYT( ҊDp">&Wwv>b]Lw{j6f˨+'Sh?e՚~;xzb&OwzUT9ɰ9KJ7O^,_Uzb$K=p:=ؒL缲|@&v"P.0p(]؏`O~T^W>2?l4]=VqqAZxз-ޘ<C! Hg>溁n3*Hy"=gK ߅G Eg[1`<|L@=T9N⺮[/e,E :h:{cfAq4gSg=-B/> 6l?6O>k[zƔyME-vT<:/B|M_0mn|D$pſOF~m{Mj9ch to&l]W%lɞ[tE0X(Х<@QC,ˀґ}"}gS><{s kkyk2ȶZ%WK5Z![h:׭lUgw2O_;M>SϝW|8OIs,$.G]R=nyıvC5|LKwRx*ZS&`MZ j"syT* Z1?G:mbђ[?Nyh*º5-Oo>nS'(S23pr;v[L&((=pI`:]p[D@kJjz1 #;8*7J ݽ?5I_6F0ר1ێn Fj{VP^h,Ay uIܧp<"Յ@<{?ͦ.Q:V8mѶszqܙ4t0[8'C7u-璐"3G+8oI=X9-)*-pؚXEr佘WlePHb_Ʒce+ 9øֳ5B]׭Dvc5fB%"D7 W5?TʹyP&}l ͦز@FR [6M(0[Ԥs\o:oѿ,nZ[<;֣FM+Cp!( R,L!k`$%rdz֡wO g$0y25 Rؘ7?͉ܩ^#[ZUy }LNwͲza}L!k^L"zEhR EF'vΦ P*+>@%9(TSǺ_U99^n8)0O d+HG =B!GgYWe`!4X2s3q iH);Q/xRB=}hVΰ<''dx0䵺\LLrɲ=5sFbkX)v)%ݑMmC|ʂ2U!&k^!;n} ZY[ʥUiLa-BҩbfAU =HdGC;qq[*M*DVOsZk- [l`]VG\%Q-.'lUNa0'Y,zZT;p5 Fm\t!y^nӦoߩsVۏu=gJ |lQnvnqr9=c$S>t?6Kddr{7@"V 7 ‘ >}Ȟl`w[:O܎yyM)[_[]1`Ѥr%Wwrw7膦<Ś/iM(bCo'> .{qrڹ&ku {|X3_ΓX+(HNû/N(27q_nXsz鎱DK JYTew; % (&PIrSҕtĶ=k*gdFُ-8m]}ͷdL4<w5un݋C5/Sj?[zņӏV l űoiu"l kV ]y1ذ}0ftho)p,VZYLRՀ!?<@p?6C{j0=rXvQnVMvϜnl|}.7Կ9;JƴT57 7 gN1׃"r4-Fa)* I{?b-R%եb){EtWbܐWv\=7Juu\Wk:8|]kX*.VBE *P͕Obkt0#2Z)4AYߩF2$GtI~^ A9[Eڊ߳e] Vq_n'\5Xl}GXC%W[mhrΈi+8b-Mǒ['S%56f7oξWNdDibiܪVg;܈t|vM-2M h|RR)w)7@Ltʁ-فqEC@z^Ϊe49؛9nKo yև. f[Ƅ?, x;?,e$8_~$ӬG?r89*q`J{-Ƌ̵$"t24! ')kM( ,KcXbb։j>+ywPxa>$ i̽wR ]VCǪJΧX!׉͐rEC@G@xHqrp475v& Ƣ':w(F# p h"E2їSo ~2bD"@3Έ~E>V&ʽAOm@Owd~sw=u:b`’-zp]&pFl+,n/8vu2KΥ#Gs"늨87GtL[&m;mn 1 sMyrwCTB yحO'/k[K!-ix"1(MڸG"2LߔX7pXpMz;j8_Ӑ?4Ґ\oRH" 7IQSBEs|a[SLl[ǀ/n\Bw9j K+bhY1ː Xp?T夫ˆ;20 nuW3 \4)$*_,Fg,fՙʢ2Y:)[o2*j4gȶfjkG̸ԩgOQ\w*xZU:{rܴD!;TO.vrcQC3Y8ro1jgEZۨ7@y-i2zpX2 ̼+E5PzhHϿ:#pybW$:*_껓\^foG?QJYm3Ú_Dc V.I-6~Ҍ2V^:`mW?Օ!E2;P1ΰ-(XďwT0dJn7h`"ќ7E'0Ub+QNj5ڐWsrHϜt:(-&\i D?ZY/l _40]x>~gŖS*;&N%ѩ|-ͨpU|\JM8 ^IAo;!9EqhvC !1ZF9k; ,s>ޚKA MCF"玵HM9HMi%{ރv/C;BHsi~ YPU.S_G;2"iC!R=Kq=Dl_oϾsW~ڶ#VKod)2ʂZ!"4c63Vλ%^-l#ndSOiŃ=ӯ֘᜛G- "-9E3AvKqmN% A#!B<0qFf;ĵWH¦!@l$^b8Dͩ}&Fem@^e=ٶu@]bo\ N; 4DYz34KϪj19$OF43[;p18Gx/^SGUt)l SLb΀Ę10|_Ot]tlzfQ VK5O:&|z15CY]T)ŔoCmBSdilLkܶ7-g"۰Cd7jgh&P<4n:K;8C:Xj>iqӖ #*H՝uUAXYtT_Q/]5l~z2[$ MF+q[#=aOc4amY[!Y{~ |0W9(aӔSlDn7DT2"}م峂dn^I}&X僩N*Ř!>"tFt+ֻ|' 1>JĥRv4R"e5vdgk`L_Ira*gDXLL;I֡l(Ru% )9QauQy4O;[ ٨춇#D_g01-ȊBg5-E,s{`WH&R]ˆ1RepnzDž)IdujQno24cJWU&'%Ѱq23,./"] $ūE%c-Iۯ'Qغ3mGBy?h`2PyIDW) 㿱tn-G(`xLo\bBP-V:iχ Jo`ȶ°ȼ~hqП! ݌fG[Wϐ*ZH(Uj톬Tt|=NbK٣a,YiDZ`x*.Р? Buߕb݆dneVhpZU+GIH$;#lB/9`_ ל>N y%#Zru?4` YfcL9OM2Hnj]r0u|Ԙ45,Z֍d>w`ߣū6|ow}A5&$V>LrpRBcv l<ѝ1uR;pgUg1}>dK{YRwp6mmqx1lFIln/[᠙$ZJĄzٯ-VVs|@x'md$*! &wځo>:Qmn]GV#,IN&Y1zZ[yx|$*h~-(EՁ6%&9{Y  Gx|0ebhOs`K+k#o)>M{`2:7>=}m11Cd#|JmOe=clU;B8Mj3j_-i㞃0}m]03H&|Jv[O˛XT'>&vgQ )t>H\֒" n3ЕN4Fb@}T؉:'azy:(A5nǸsL;5@0}ewuW͙ǟu|3=K1hZoHޜzD}bXXɺX uuEU+ ֩\3_6"W}Wi'P:W+D-YoE֭X-o+%jb,0—뺾),U 6-AWvK֋Ӷ 0vKMxߠ6^q;vOet3w2:T7cl?o 믇x-d0GQX.uv e3o52:%4N&}C;Nݗ -~܀kT:8=zoٹ`7@l887 2t a,R%m"tvWu-MӻQuh!3|J0.!.tx9 =;K,1_ܮ (y)dk\=5 [N4o]ar2~XskY)sp;>AQT: /arqF##~r`a/O魥(K,G 8/ɹKez{C\K{|<ݨ0+8HK>F-{|QK5,ժ R޹3o؇ވC l'm3d,豝QIyY<C $Ѕ՜?QS_WfWq-A蓣 KTvx)16j}FcX8^-oK&TJl%~[wn]\.OQM-vg7cS噝Ԁq ծLL6m %cNj3-TkO-` OYG <~wI0"_I[*D'-'-)%i0B)qIפQiizA JX}?kZDp$^Ff[?.rAMO;5CMIW͈Y{*]w!jxuQ5 գޤĝ9;޾J 7X}CiÅ]a:+R%F,:='dA)xfE}jا0$XafT\WvBRM[\ f[T =xˠޣ\^v`ƒ#ѵ-HN=%pLPMʕp Gh`%@0=~n%[DfulSEWWh;f(h۵M4͹޶M}bwh_6FsKՍ;NHcmv͙o$n,M@57[CDB;z2?jaR^O7D9Y8:d|Dx(6>s|}rѸԝHǁ=άoYCɏ:I̖Bŋ1cRךp%ȫX̚cĢ^ S"-!v|N5_N@M=yPvzҘHu)@7EӑAQW8fbƆQ<=Q͎6RdKt+@u#:d,nSXm\r;s|~X3SՁ?:ɀZ4Õ/vv kz&s _ǣ!~w怷k1SK襩u9(Š;Ohdnٹ-bxu'2`OUg! K!6xnphb[ͳ 9RvhhfK!ͶH}e>ݡ5iZN`e\cwaJyfy eAd؆]Q#+ =~Npx]ݥ/POf Yn^f/4m) l .PȁZ;m~.7m;r{4(я隕uQᨏO8 owT_SYa!YԧDyV\ ~V+Pӊ$XnJ_$8x]~ސ97Eܳ@]cLieUv/8𒃤Wd{MuB<8-$>}Bf<-QnӸިsd `Bc Z|1%jQY ݙm+.{1^mNPty6J}7[teX+hTn5b_FPz8H,WKdC(hzώz$`zҗ3+e|1+1@*x!h*z۵I58$h"H?UOL5lυ!&LSj(*czL hG.|̌R=Śt!FJ^dR)B8` ESӲ||f6qmkj[:KnN ƮSe޵[Z0GT{  `rB0FROxRv<:g;(Af[b7)ׁE`NYw U&J3ӅAkui$E"  ^Z7_IyQT@?l䳺KOQg͊,i.K4*NI_FFEeN(Y&`"pi#QMf@;.t9>LF   F?U8["!^K*Ry_B'耊0ʭKQi fG"IuἜ'/nD.eQ,}2*WR\"8mń'up.[s=mYzHT-bg)Ḫ2X̪+0(Z"IVC&͌2mi}JZ]J'^Zj6^In'eO3#!/̌L; g 7[{Sn/T6yY`zAv^oDԤ`f>b'T7,Nl]-*s٫(l|$%R{.f5 FpP/亵[cRd`Yyw6_$z!t2VO֔HrcN 9S$C!d(* 1])Mj#q}3AuiK4U0ZfӜF#'hr.fU$qL xuO^'zUہx|;aW#ّₗtr~Ï>5dAϴdGEb^_U$߭D#64 g ,m0H. &As^GLӄZ`99S95t0: twޱ[ތri];7|2[@A_b_ ' z|ϲdV6 3'p#]"0m˺.& 1;~Ϯ~,׮ڋyY5q\<imzI?o;Vf6B]qM^֘lEvW^ !-Vl\ )u`MGjI=Вo_Ym[YFvfw:HBq9ta#Kk_|f4_)"= L`A0t|l^ n+oNY^z>8 xg>ex{9Q֟jp8;0؟߻Xmsi2:.F:UZ[- ^8fɞ Dnd'E`pv %CDEzk;&׉\~i<{-g)-G]b ?:NGCw"yX.s<*u?NhCn@n4T/%vwSw=.G.Y*6Z }Nnp ٘޻4ȃ;7uj. ;y9(mz"nZ2zP[GO -.SBdw, u"=mkrs6K科5WKڨ_UHo~̹\2NnegtA?X [lce̸M=/1BvĿWSɪu6$di#ƭϗ_?vĖ~[DNyqscׯ?_OWLC_ /.%)$f\k?\~jBHP݃|{ڴٽ C>S'ԯDB[UAU&ې"ʊ_E!7YE/~7yA%_J WZtT,UĘ̙HQZ%.+mR՟}p{"V_p ӚV(o"|h}q3fv zɵVoi#$enإbX]u?%n5V7 6;c7:]_ډ ,{sucQ{Lԭ=r,CN eÏ? I..+qs!8$5uD :_21&1/B_Ę.6n}>jÎ11P;:i] D5<f(4\z,/q>|4ji]isUHV|} {Ub"#yO3] pMO_e +6dܜ"eRQ4-ǪPV|ȣy$T ˞Uw+^ԗa;+8yi !łgqn^Q^vvnqvnN^q6l?!\i AjnQN^^.vN^ V^Vq@>@%?/dgq/" (/OW+yxD999xx$ ls",̟|9D$y988yDy$nE=q1ʡeE%-.#)-#W?!BS@wew>.V^.Q.6 p͢Mh#@b!&l"H'M#ts6vv8:;Xhbb?Iׯ`B/R)s 9g9C/rhW9Ɩ/v7vtps0v5]!)Ʀv/7![I2T*_?p_(/?9b/r$Ed%Y. _PED%5&}aZ7*ݡĤflb`;ܜ0l/O| fcba`{ypsq [5p{w0V]Ll̜(}}}wLlPYV8^HZv/[_\X#3y":L2yV5V #yn&&p# VLƧ /7<7k' Uš_~=tZ:+`__|ϐCkxEc0|Z}?OgCyIo|*!DQk_Sy~A#,Xtsmֳ%fS{V zv@o!{\DXKN1zzw@^WGdY.ZUxz1mHx]2Ke_j+MmG' أw;N( ]L_RO]9X!!LM>e2E0=}d`ȓ5;ǑOA L&2qG3Md\I5ZDϊ*zj.m!s#za/]~FVథʫsT'|DZqǵ;TO'䷌[gW4N$J+`CBFO:ɄC/)3!߶2Rr$Gl]a@Ìfe;/7J_!}^ҎE|ʅ_!0LK_h7]Wq:86kΨw/RߑgE[1?żoStTy'![$J[&㛭I6?>Ȕ4 4mFMEͻ< &sWu17s'WwDfc_(Rn@e)t)2E&<\LDONP!GZzV)J=, .i!KZ6Y'ą۹QOA"[WS(7 6Q}iK*0,*_#窫k9G\{Dbɐl^-rpr=DZb|5Yp72/fA2~swf;GOkBѥC8C`}={^ La(1R^Ϲ&wHfʏ}є]1`2VI% SQfB*y4z$6k'$,{H?4x~=:N!#х`ԣRWs@?f! aAC83VF),|v83.Wv̑?/я ΤheFUד$[M1M2E!K#ܭU%Xܝ_t0IFϛ~c/mɗP*1 %bK\q^Ew%ʹ{t hUyd_>M& H%sĕ*4v_/Üm ӠXl8M B1+/ȼ*Lj!vd׷ :ݝET}[{~+{ *$\CO5^1KySPe{7O-m4W ‹Q&Bey38}:]4?W$d7>QWPzKn-+sBY_`*5a)\&4 IR#8v'=H |Eb~ͳ*/*U#p#q{[+a|U T,@LƸ>,.eB`F5V@=ɧ[\%KCgh$owh;Nf6ұXq31>0$H󃻊ٻ!w_#qd(S\ůA$*سYNELH h_)<")H[/N\ Yl,[xOSyP\kA|z_\ܗ=~A}٤8 ݓ,Uxms,tMU= uoT \zLT)Z)_}vzr0QeXjQS83ق_[4Jxͯ; }hD&3ځ|ږ!l>·9ױAM;sm;HFTKc'bMgQ5s.'%l!}“){CGw~")贸?t_PǼ\Ln)d/ ܎&bΧ^PgA"f,WF=ίF&ʍq"bF6cXעV  nG4`էnG &ɧuYNSόՠfU`(́xǤM/JV|0KӬsX>*.Ws]}ٶ_7Ê=B>67~G0PMM1{)^u. !)9}C3龶~*!1i{vK=W--BCSChfl n:s9vCz/u+]\ỳ5M @9:1}5Vȉ5ATo-mXۧ~ڷlѦI$Um_^8;?ώ ¯ Bf)Ri e Fp<.:D8Z:kv~vyRGq1Iz7_Ұ`M=IϬZJ7oqci_Q_})B(e2V甏p >e!L: FsPo<r!9?U!T}6W+kw t'VY ~ltk(fLh`?FJYkA8Rս!WN~s2)[z3ydkm1sګ:vQ3ACN6cKz)*݆lrlGɦ{̢ TZBmb{@$O!uP! eVo&|B*I$܆kqD꧐ vaL (g| >+QSdFⶂ8gGJ|ҧU2DX;Xqm=`D'kb)m&Ou0IOK|ٲ Y!⏊ 6}w87!ҟW:-fbK&.'avCE>6Kԟw8y$gD CegcVYd+8CI}JؘEm쇡ust>Ll0ؖ) E.S7NEy_o*\ $kC¼@4΃E3O5!0n||t6I#n+~VLsP']S~Dx6#]M_9[,7ܰ6)EbI_7GcVkx)'jZ~L}_OAS  HzQ٦N^wx z1!u`j>nREޔ ^ 7;gu@B ;t_,8Rn_[is`@oPB"IJc` _|-7Y ~iÝ`JζOgyz}TP z-mII|Sy˄8Th#d5tw4|Z4__y~g.H<4#͹!WG;ga_i͖/!뢔^.̣AjSnu/±IXQJ[__ֻ/ݣJ~']x 1%4 rr'(FvWA(=A I_r\4zxfyAFޭ^#6WӲ75(/چђQruSÄl7I#Wrڷ'X\G.7uS>m ~oYN!ދL&aS-]>vء_uUG ݑsk]|v??.N=p -56kB=t<~0-rܬ4yw+ߌ5.W`7]6l ;' sD"o:n3F8H)e%z`*!2ee'沌F1D`6M{2m۶m۶m۶m۶mN4{9 ( 9Pÿ}C8</OwxdžzýG=~!7Xi[8|z<>`߾7G fuy5_#AB;QA oe\[NP?v ~u DxknD}n{(zxx,}ƽwnA)f3p9,Ch 4_o_~d 슾m+}5Đ~{S<'HGa"=aaICJB=0́qd{ko}73z݆f{+# Xw֮P0D@M3Bd|/w -$H,-ƶ4^7֯C(t;BcW|HGo 9}OX>O ഁ63+ CTKc~@P?5t,! AYTۀ!jH,Dƈ)Tv@\"(4cݶ,uJg%i,LvFIҔHfi%3ǁK$[oR {Kdz ,Qӌ^6i)Ю5Aheˎ =OO7k#oPH 8{N`1V0c1c??>W#3Gc{4 ^8\;qLTy)NL}shB?z1=Wa}@[q,2.Gn`݂ s0p(,=ϷɯGx)3J:! `/EF82%tbF?{OϷ7B .8Ӑy{][ýpK3딴hH^Z$`1ג4mUsxE1hF#暉g*,;]3y]*Mk 30%h(+ڃ mbzyܴa fX$eЈEGR~wո~%HC/vAzmSZDWƘzꎷ}ӹ㥁l\՝(=^^V0hyrPLyZL^a׬M]uR72P]Z,^M:.A % bʂQjtP?eV6EGTIc[\\4dc1vH{x0#=F'&"p }y?HAFĆ /Qo8%s2!m Bd5w OYM LoVJb)@ (l/=(ct+[-(/Y&\M؂BAd=|3H3pDGڪzlXHK’?'ˮ=|è~( @ iqn pvTzJGw#U?@ߍ ˣ^xN[:N{ 2 }>4R{z"pqvMW#-l(eF5H}P[KFtu._CM{i*vNS'ҧ?:bG,>%2Hg 2BNy2èCd6BJ%9tYZ&)50|TfՋ"huS> jRh (iT^谐:(t;nfvf@zQb(؜ІwqQQcm͗q +jT v$CH,H R&PvpLitX*]*` 1R{R <)tMd1M`(T(PW<Z@֫9~ĩIa/>aI%c_béjiŽNlk;j`c5f0yeo~vN%ZHXY/+i^E95fl "W_7Qn‹! ar+҉O!tK|fwVHw$č/na?>N[d(Y+պN`DE_M @qmX$]Qΐq2iVrwcgVJ=)bcP8 5}T S[@Z"GY-H(XHW\s5H-{X:Zo0 ,`g(ڬJy8.Yf\c<`V߮mC:L˃Ʒ8vA$ K8 Itg$Tnwi#V"Ě/>8d$ HlǷg =_ ?sqWQl Hu/:$b7qB$Dr MgSWWy_Nrod._3Rh{~(GЎP44ͺGѮu͊־[&Ma@mHԅ=W,.( 30v֘K;G&+RUOi?OD[m90}D?$5\iLPep.VnS:7/ Ka䦋]h>ʀ["Fvl gR d[?l͈[#*ziD21%թHh%Z/-{`3O˒B.́Ymh}ܻHέPd~kuB kWWߗiŠ{jXbK֧q,s7AѦFnuOJdgM틟u&$1=ܜϪpyPRϏ#c*`#"0ݳ +׻`< `!mQdHMp?;hg ST֨۩|Rn|:)d^M?nLq]T ̛Uڤn:c7;Lٌ_}:NtaO9]3^԰ʓΜL#FN*ogy{19 i;oj}棲<9&U\hFYW o+]MjRs6QkheLȷrKmb hy3v[ H>%1Nj;>bG'%Knи^:\M`]ree01Z%ɯD6󖣾T#y!Υb1,57e.w3iQg m&f/S2MPY\0B=##zMj2+VnҎb^g.6WG jHehv4Ȥ-.`ZX><mMnДdft_fEƔU_eT"*ofaYfِ""~7E8*9eԋ)^w.3[JT("NZTm=ļU/r"(|йΝHb58wϼY+{9 Ӭ 8zJ/۷59(j.%n`-a0? 'tnBZ.x *LL5 5y:gBwX-{VRd0: omFrGQ,_<\ } bk\%5kUqtޝ|E|^fAϺL!vxM O&}e̓@ ]Fܮ fteNAYZ$?-*Th!2 v- ;30۰l!L&-ږiv௪!X0aC*7\}i-i&l?<֛=&kMC]TԹ 1q,wahxܱ[I'WFEA M*^F$Qqat:u#95k8)[:j pS-mn,-_?Q ByK? /݇\|?@C`˲} ƒVvv(_UÕu7ZMDIPu U+,p%g9;ڲ#^aR͞lL%JF[%mi,o?K-EdfP TG\ý+ͧd iwK.pəꍽ+m-H >KG,TEÜ2ɟ\EQ88XD:Tx=v7f& o >(,[~NJ vBDd{6q„ugRByG[ZDEEE ͆1߯Sz`n3C.U+]ݤ81|{Fi{u>7Y}xTi<>UD=ܲnK> Z[3CRclm=hk4e4mTDy\ڊ5>jݞxy-=sBIq}8kw A 9 _ٳkӷ閟YFX/{TjOFDp_MhcHc!68 nDb6٬\6#VYlE;FF5Xh18b glbivLrd%e!+v1R Ƚ`ǦN6_7 j+ 2ӵohlQZL a5ܿW8&m!`uCuhbrOEPcrv5Vbs8Nb0 8^bZ}=DZ j}g&Wf]O _o:1vxBټ3|ޤۂﺌ#ts/~1"!g7/Q(O8uy&`(&j6Bj6^ )cCN;vDq;@鶾L.!n?l$DC -S fO*M}{}t=./ rhϝ(}g?f$~NO~ǜUG϶~ýW|-sX&0ըmW{9V蔘 `x|"V&^3,pOCxir8yp8_fm(=X|ފ)f?0Ʀh?:p9b8o^`I gުG>aܑ`IQ"FtS尳z@tj.<ɱݳ ~ix@q#>Jf7 c,q>`~0l-nh:WM~*ؐ Waϊ\bB|qrڽu*Cܴfծc獿@bk,~_A{S"Gܰ'lV'2:nepW˩{xJit,{[]kЦ :ÿWHSu@FhQzEi0Ѝc;LymT:o:z=io$[ PfU. vV ?ƽvP ALܤŝQ"h # ITc+ OiԟnW'@@F@p왑iGӘqHQc Nn8IV8A[$P8 Vo, U[Z's$[ڃ8WE^&+C Y/p&kps%tŸ1~ZEؖd!P2U{~?1J41Ȥ%*Kkqbt JzU)"Ab%\Ҕr;sM0Orb2{tMndgH88$υ3y0GD8."Tcl;niD 0V6#?V5E ڳQQ]nϊw[:y?yԳA[ln@gkèRsIJXd -`ҘvGֽ[`?/D6Y3m.i=F}OOy_·ToeY7Mq DOeddMŏmqXƭ[Vw泈]s& EB rM\5mA,EEYCHÉ<*VsNB|##Tnȯd]搩w0z Ƹ—Aj[#4}+`'*U ]I(8I7AztZȹЧꗪ%h2KLMe6h [6Ut~84}%yoƁ%N:xA$Ŝ'F ' q6D'8#8ZJyv6)6)TѐrgaOj)ڵET>%H,r~q.{+22JqG4s'C9wj ~)?e0m`ik\cSv`˳d@쮶aCV.37skUF&2outyiɏ~)-,/uz;y r qXޏHRޝc3T0NWXRuRa6C8" =. 2h3@F(?e$4Ւ˓sJQWAWq'֯G 5[<5y]GC%$Ģ tI*6F6V'_ɺRST5Է!ܠuH:$]ޓTɒ:(v)8i=ʵ21߭ro's(BRcɠsu>_c4|v.%tڥ $ȶa1ҟ_`ov_$1Yu_4@WN3ho)WE*"*c9IqҲ׹/c-Hc)u ^WqdM Wn"IդPSu9v?ԅݙ)G\ą*Q. %|Z Ÿy`c>K2Ao#)Ni3Wk;K-h4}"m'hg+r͐ NLgV qj3d-cc\muT%0nD '? a;I3yTZf)l#*;:ʋE vao*\˶FmA&͇>̺* Xӈʒ*\)ZV,)Uk c0H hoPR\*chASV*e sG1bP$Wjo "G16BsȩZma*%o}K27P"X!rblQWAurFsQz>^GZ/(Y-4%2E`gzo̥q5}1sE qS5[S2NzV"cuBّr\-v|=ndK*P yA8@ auɠ? *SbѢMeG}$JF-r̗qMަHַw? -\iF?8R%\C|'Hu(,NU @q|;"l:mc&*)To0֝E&4J^pγ˴7!|g_5qwx^K|F;*tw"I k#Dla |_ćkid|dz[{dCdz| Zkl['[J؃wM X>LjyËfo@%3ޗw'j#X7?Yt\ş< ″ݜoC^`cgVw44@kz]&&m*jIGbSQKָϴ5GZǔ''PGȸWW>;l*>)9+l}#\ )agouRgI^pя z1GcK׎ve,wux r LϢՃcn\Yp^ 4@u0VXT2骞FA0C%#_n7cn0n K+J-f-G~F[bد-۹ȊT1_n$:-L 8j-qZ _+Ӊ ۺ)T ՂރoC= 4D('lۊ= \֬sVFwѭseZ 44Rt?UP}Rm^S3̐Etlbۻ#[e6On$pRfMϭr\oi)S2r1uk:R2N ;cX&A w!xu:{ WUDrmaGS؆ 6eW]˜m2eerV)lƓ$"!a5ZrU/j1HUȭ Ûk|M$/v5 V2>W̼1nMDUՇC{fiPFUsAt/XOۊp(GYv 8PQ@Ч:3Y<8{;lIF om)Skϣu 7ည\tIŸ|Vi>Ag0W, 957̩_ڝl11SGx;t[ܡ nje¦/ %h鼩 5#3=pkK&^3G#ԾA*I9fHO {薭cH𤆲%0=?bm㬵ڂIg18 I& ٔ)b>B.Ru IZ~bN)Vo@(=ANN%6]FQj8`u:1)v7.b@c(OvQj٪>  6=2.:5 Tm/Ğ  "aGyZa$]b@ow@C'S-Q^C\ ҿ5>HNTcbNU3tLjfB(>cHY>V7mѣNBe=Ƽws0 Z( )tiHi!vu{;3EaRrsAWkoIJN'`ؕq <>U7#=EaIȇt(bZ|1Bfd0&=\z2ž 0[!zuN YQԤ&>-ɁVQ@f; Y?n)p7iۀS\y/:[^`Gg'm#5*iҰ5V2,QǺ&V &mnAHJ1uG\>>w]jg.YISކ 뽟n9F'FJFl,MTq.)~@B%OF\wETRQ_+Q0iVnD(!u%fZ3 9ju<5[F"|N02)D\:QtOWfd2ȸ'Yw_K }etll/,}NjGk5j":Qb`o,wr%3(ɟ#)Ya繹PpfpHa,ֵ $AlF/lW_(kuJ}UaِSY]AB%8i͉ˍmM BdL+'dV(z/xinXO!ԽO d7'4Uvh,@?ΏXr;.Zjm쿄dDXCo[&#a%q8sI#;&4-R~A*)$* 2@MfODnDT5. b# z拡hKF-^g5H p{-w52uI?:{w0 N0=7 -Xv;:jolE}p'&Q{naU9r%ysaA`eVMJƀ*Zl}E(Q*rBEh;Ć"86r^6*gD8p5NZ6pu^(=<90ېJ8j{L-`pB fɪ?#omI _<[Ka/okKuZQֲFmQJsE[@poIKRDYV -&|o CTd:{Qc Q"S "< `rۍ{2GF0%2gc(GUbIMUv aT"[ErmʀXxSch+}ʯ|V; }duƨcBaWr`Ix ~R&qUGQ[Y;0V"ըƈ¥X Nध~Pr"DL!Β&2uCpAI1O.Ma_&wVMdPHa3Y:Y_mZ$Tqr/LEaE H2H XK%S2n᧬ q: 0wS&Q-$͎8t-jը$cl[>2ZǛ:F1 *Át0K:\GXC3ƁxapP{*cG7*D9{!.d8|lFŠM%BLhw~x=%lu 6@ύ7Srΐm;dvCJp}Q <m&J;\{Z3 `m*5ZpUR=62 B( 4`d5EKMT6#ī&"?@j';]K5k ^m6OD' .ݷ PT M%kd Q֊?rCNef܇w`S=YQZ7zN0%'zP-q=6(%|XcN ܩh(pכD0L.al@koRj?6WYc*_ڿ﹀s{^>|>»But#*r2Ba:ܼ4@ms̛#r9fRT? J*H6pC^ j.X2>(~\̞}ggS  _IFB?Y%% "brԀ ^d϶UYW}"Fa>GhzbjKdtR90DkV!" ؿ[}4 .ϒQkU=8ԧNyFW?NXs8޷yF A i "a4=ҵwǫ[,G9JCPG5^sIߨf>bjqg6ktY;/=*`cxYn xX. >=_̧D>ܸۜ%jCarPY9mt6`eΫ Hy5'6B&U(Ɔ{/<Dɽ{؋o)gf)x4VyZ#n(\[-I/Bz/a%⽉WOŢwgG*a t[XgxSƒ}F &-ŸKTDžrA28 /j:zx腵"+8}6K_>A#Uep'߫u2Qf8sGoM8 e],W ^"1N3_ħؘW1idř=T[k R@Rޛ.c^lSrZ;(OCz`Jd"ZnVCV<ʬ@``AӉ 'ynMQ`Y.@=ťeI_+ڏL2sנEy;e٘aw{OgZ0 l2P=e@h1?*k=[E7gC;U0ŽnӇ0*c_/P]٠~϶Ppk> {w0m8>R(뚷;&3qv,ɍw?39y@ghn wuUqt~iSmSƍ20ƾ:mB5Ÿbs()#LFƁXTE:/w|3vh5/P4re%}/Shee_岧 ?zӑ6>^ LR+E%RםrlHx'(" s~|[j;|l⠕Lp,8"s,iyW+^'Gˊ|::6GP5(nT,9O%I}Qr{W D7..7 n=GAlR9͘Oc4:? 7?ѓ 0U*~'vr2D@,68Dh8EDkx0ү\jnL&MXUힸQ7'KZMc|w1bRڧKG.եMkZPK #Zzjnä̤r1BIt O3=BKw8N[]z ˏR|x`5Prצ[M6z{ 좧 N!&ldF5, 9M:aGM%1%ĈXQh SNokC 'Em jy ]$-YHVu$I7'{S>|,n|;|Cia&h,e[|晇0Jo^|4|$hV \ cg#dŬ0Ȃi"_+J*ȁ1% HGvQ35}yC5 GL8n}qj~; -OM;yLיeS)6 jZ"քn@n^ 3J7V4z$1R&jk/hJc*AE(tۘ=f#YglxǢ1OPP2kOМG ̣*9qe'IۼR<$^CْG!eoP؝P&YkiKfH&Ru ^x^C =tdtlO/W ]@\C.fjsaNX}T ?ߔRL _GָHA2%RWeh5<Ɓ܉ <42~?-55%|6fNVy{yc B|qEYvq f\#A2qI3G,Q>L[GsَxtQƮV%|jLZJ:J&jVBap1}hoIBRN"G.Zm+D\2/3R"MGnjttk9}W ~R ( & VP |̦77̞6$`ˬ C v@g\Vh+Sz"{¬<Ղr@%FIy?o XlBPcO:$}1_ͺ|| ~ǸWr אַ|V7LkW q*|)'%yݞg*ҷzk,̒AY<.YlZ'97 ZC@b"/t0(зoym0Y&O' ׆I?y]٧ʝNE˶x.OpPJ%BCKQ/@qtg9~}TqjdgUMp *(:D8YJe*u3){C/f)}9e7g\ڌ)w4E(6wy 球*i\Ҫ[H b4\2BWEI&2Q"V,ymDϓN7.=R}4 8``k1UW+ JYO oJ,Ԣ$|MTI#CSv%E"0xV}o^On\8Zt3( [Xƹ߱t -|VS}%xY6S^kF*{JEtb2Uؗ`i@ ُm~Z%@k-c΅w˯.`γoRpY#2bO<*sKP%>௾({h޷nTqpŀֵfUtHϛ|Hސɓ t49l[$[93>C6x,h8&jcɚ6Y@*9'*]]q1vQ@9x뿀hPg[(V/Z=U`F7Hyھ *_뚘c" }0=3lǂhmE<(~rMK9G^4n1=Eٖ,8Z<Zp` 'WL&(sc&+CL|S*Vp2RK({GwO> 梲€?g*r//JEڪ@kP)K/ h~CuDm(^E|M!mU@K:$n<݁){jbҼs(ЛHpg |;J /do%Ԩ8fP |L ]:j"e#nuKn\0+Δk Oj(7%gեzXۼ7P]gXGi ոj4rZ胕$O^ W,])@ 'T9+DGՎ'/.~h)RʊlTb&L.=#|lɁeUr$`D I̢&1w$ 6;1od};*FƧa*j#+sy~'=>'[q)Bɿڔca3bT3QMmˊM]&z H8bzR+@Uv{y)RL(sĺ|"csLmW+M{~e( tSp["7YS.Cܓ6JLr}DAv xK gΠgZp4gK;E 4)]aT ÃzŸTN}7{22H`Zl{>ح_7"=yI?D&>>`etȅ|a|UR"RF7ӠfeÚ8zaiJhcqv9A\4)kHUR*J\yX3k?1`˫ijYqԮL %싣T_<*In:µM8֔3=w;rɺۉ_`ŎFtՓ`i^cm2淤&xa7|>2۷ \ ;o FSIR|C\pSQx>-+5b~u|[-A(+$<m' n<\bܔGA ?r$Auszϟb޻oǎl6~^}pG oˍGc;eJ T"IrC:dihj^\X=|*Q> (*L/9jR6l8Q%]wE҅0O?iSk9b_/>͙>}v:oH=f`/U4a8]P6֘MwHNiHEfVCg"}O5֊\+6scNjT[\k4GonjLTiW j[ i6mVyTckn 1.x3]4DN<|wfo+UYeەΪLVJe 1Xa 24rar>Qxc٢rCrɻx5?3֟?{vRM0b#o\c߫\}Ru_〽~ edW=9-ؐPɞ /pfVg_#R'E:OD[%R@_a.ف?GJ6B\K,9_ZaTY|+J=Ism#NHV܍->"Pm !Z1$ MQNMz8j^I6;a>mY8R.7 OKӒg``70&_FfY}qK`;TYDʛ-.q,2BHiW$Eq(8L FY)z 0T6m.8.ߨon\E;Ea"Ig ;Jn^ctBHYWhfltNXn3yVn~S[t tgDQZ|'=8x1'<<#c_b%$ol2}\_`V!Ec޿Gw$ iȮGci~f5p8s W(X\0Oe+#zaoΩ#Uj ^x7&(twQ\隩9y5<'5MWa_|f>oe˄QYT4RjEt08QC]롍 hVE_§R.żOI&3 5.Zt0-C w`Rf'΃5IAGcvq.B)vBG>&*-,ʁ 4Jui pA8W KԦ5Ќ@)ϵS?tiyЋ p"+zT.<_Mėu<F`#c3i*TQ첩Y߁Σ!p>?*1[gPdYMa-^ IěnP{!ߢ<6XL"4^1%s6Xi6ᖌnSfw)歗pZB/Ou+[sDpVT|!(Vʖ/TøMyn>USq*~poq`6{擼H:§0 4Idܣdm\bSc#ŗ8lk0icq䱽Qxmп\vossmv6ZSX>9E1ćLXzD"aC7=(R=> q{Rg@!" DjxU%HFGo"sB'xVk Z DjZ#tKaju BQ^S3M:8ma|ʢjOOQD SĞ7O#d%B}N&;0#Tdʹ0M}ժ9ܪ˩pC Q?]!*Ddq@]`b&( TmÁLz*^ݱIJ\FRL/'Lc3p zzf oH+H3meolFyc=&XuZQ*JĶ 8q5BWpf[^ЃZ_V$Fe_;ܪ/|kŃXԤ8s"stY}|a9R}f}0jmX6o%UWqs ,E0r|esJg|oL[^`] 'A\l4\^"5yLE4-Ʊ_h۹ &v%6{ Ϯn!D$€*Cލr8Uc_CQe)V@BzcP#IH~1{a\,VQu=:?I\6RݧגfžrZĶ\k7Zѻu-V}ep4#NCmLFњءw0k =K-jU w7̸}h7tP,~S-w ~(v,{hϫ}:NZ=7t.A7z 6 򠧇56_*TUUwk 91Zt_zDU!i&6.$aZ0\X>)dX&qw.8i/ʈ˃UMaC_h F=۹JF9OQ0E XKAYcpnA?"Zǥ WG,3=EZ`u'TC!:& ( eEmPb"3ಿL<:9]yѝ㯍A%#NQ@za+qwqf+ru4q0x&x|fEyئRҟ6,O;cҍYi_<Ò]>& ydzJ YI|eKk_0A[% $XHg%jb4_]=5Hᵤ'48B۳[#0`;0!ݲt[j~=E+nfNRH]ʔdʘՊ4vﭱH-C~Ju;WM3, ԗ1V۫ 0F"{0ТlUhhNŢ(:)A\T>AAqrFx1TqNxίP dPUPӎCȾ5(05G #g,sut"ݼ+rnHsۦ G;K9y,dl :>st e΁$F7ے5U;֋PP4Z. /yHZYg75@Ji_H1\ѕwS!jhUμ1\>95g$o:Ib^ub @S#xX54pb\\e'ZhMOVOjۡ)g @%(v= @u(ud-E$쮐] -ŰNWb̤G؝=c[6"V=_j8HRa©'sTE4'0UL%PY'aݍ@(9dpK7q>^rCίRlFG~qr%/rlh%d@zsʸ'!/D8<= ܌ԍ= G|& plT^!nZXv~*v c'1F0)4m,UJeWCkhPmsb1tn Mpez/Mk*&ŋݪL78Imۭ抵^ONfu]R֭*"CδHf)|ЖMOHw,5.\IԮt8 ˑW)C񱕭@Hg24I9z۰7iuQ@8j3@.WΦVܩ?ąz4Z|;OEk ;WGk˒Y1J| Y̱TNԁƏZS^`^ynPBybHJ0v[KܳYQb.Dϥj_u y=(:$ƿD sM~n* 'Q.)-O%j•UHumZʢ8V#$ w^?JĝGˬr.9K\`{NOˤt(1[6tɊua倚4v=@{Rυi=xjC*1C_Id P,6,Ņ`Mમ0(=[Tr` \:C˶C[-z ~YL'-WՂ}ՅгxcآP9a(?ńA{H\ꦱvtOz0pOR8lӏ K 62`r{6P.yh$@8%T  ʔǠ&ӱMZA=9H;U14ߠR}R=E#C O*~tR =ɴ-Ln1o_1Ǖ(ƞmk-QRy߷&K1ZdHߴwA65/͹gIIkx.>8BeP_[w\S5 ES:2ꡀYf4j C>t"5u`.|M KLFS@jVyY']X1n4C~e3!zqnrNjG_Uy|f^>u ++1Lk:?+%ԶnujZ'ܴec+"~pğݘkW}s\aPb RhR"9aA`I<رsv7t/ 8Y"Caۂ6&{k`bdJeےT)a9T|jof -8+b$M.O#_cma4*7# >Sb:r  @EɨS#ۗbm5Ty2(t+;ޝ`.6svny|ɖ˛6" F!5K“C3G%Xp Q#:QFxCGhz1Y$MXxnO)nQ(@Te\j Cg!j l׍F 1]`'OfjJ5QjeDhUEYqюpIG%$zobJ[ BF+Zb QYupD0 TKR~rXGUt~BYmPOjN;$eYRv,.E _~,P Y( %qJ^FQ&z) -c"Sx-__QLwm=R| hWPʅ郇[)RGm`+rv0/S("/ZOdb Ɛ25rzDlmAçw`?93X\H?V y\?~ q6kevNRfo &O g5ڦɆ@cq'SG̰4ګcE@^dM-*_`F{/c{> !N#B<}8HeK>b\Ewk@eyfHzI^%2}ZGocWTHV(!YC1d)yXXX׮f 7?tJekS!ۛظ$ΠiTt #5Q¡֡6*fC YaNӹUQDJkg9FҔX\E ?(SWC{!cxRXQZ: d;IKDXn'(fx I[aDdC}oۺ0o`pFij{[_jF˟Q:S{~[W:z,k( bP* NQ>rE̡kf\N .5 @+&Ϊ-ZyaY.(i!翥X`݃I"[0;t>71]^zkq È2pS Yf /PvY3`%8­8v䍈3Ĵ4T\՘!:ͯo+~pGPZqqصIn/wc`mbBM[q8 pzUǶ̳c jtRE!< Z>Z1Ln=ꠤD .6$OnI8BJg$?I6ku??`I-ؽ]a㋪Z,@aW7broh TK.ݓ̙qGEb = Z/4Gzz+F#RǔI1?!]G"U.[WHRKAJGDfqpHGq#̔E1L{5uѣWW#Y4 & faZtp\2 lч0-O+{(lPTxv9Ɩ=k`m}WVRBos"pעWޑ$!X[ZXN}]<޹5B4Ҫ Qҽ vg24%ؗ?[k]I6d!j^t8ƻ2L ϺN=QͿ|j4גHiR]U}w]GBZ,) P-å_ kox*.eOz-Ki˻3}?I_PJ>@6]TJz ")~ʕ͜J}x;o2M.v7Q[ǟdk^s8!{D* ƍO" P=Z)Οؓc"Q=6`(Tޮi΋i0*S /v5hp8I!_Ԑ~u%1$\ 9lU%޶-3ї1܋П[.?$!%6$~~*aF9`>K\15֥tGt]9ߨMMpTOVu09|c DJqg (7aV;*q(;3/$ŗ$:wNZud-E) +* 'U?wy^\Zs t4$ZH\UY08"\\Dg2⃞w,̮ @@e#dN4cf|@>~#S+?HAa!lۖVV@3 GDfIQD)h1Q[2d -[ęi3 GLo"4B*VBS %sm8C}A 9ו.E0%]?`Ne8Uy&smdψ ?}c"DS5'Vd1QܽHIٿ!7RT菢^)RmN.bb)HVIʁⳖ/s,\F?Mʛϔ/զ_S|ӆ,5 j):Ќ5KG-T:0.rD^l22ޅdi :ţā85 wpdV 'B`s&⎚I3ebxI8gh"'jxeü#N9ivb$RkNSm{BnɸqNgZפR+@G[+07-~o#R˰J'E,{]~j2P&,楊'fX[ճJa-sf*X+/MPx4r)U1^PnNVL_.-橃Xɦ1*CVwA ޘ^@fP\npX.+bB,yZ9j{٦4,^+(n0S,a;YnV/K5+E`KR@ُTOVlJP,~Mpd)-]rN5-a&>2!=">)Z9FɄLRxۀq"W*D,GFl=`6qZ ((1N=nh(? ϫk {JF@ZucVXz{V-,Y ׁ Gt#7 :ƴUX,dYXtZ!0nCu[J7W"iL,S-fHXb4 eA mĠ Wd\Rj*7IKFG<R\'EREԹrE]}\f&t]hA3͠٠÷TV`2L=6\ .I_,tDV@rTSf3֎:lэ8Re'ǣy]5:-@s +}YAC2 7eSc.7N6We9CķmpG?$rصŁwRtaZf њ4be$0t^๠:Eq!F^OyWeo&k OXVeү0\Y`-&kBI@zYz7h xab/%1Z~{RVG ,WRL=y)FPM1tZ%{NFc5XG̽No\pWJ´(^48KC6~{uNSCgkp9 !c>˕ٳ( ,PR\cxu 1E_5]8(_kcBPbywEu TxT݄ؓ0 y jDULPFjCاqߢ1I>!g22|i1 >%XFM1tmz5m6 zO;cwcS1*UZٜ $5@ї @T@KE'9o~*X?R~Xy1m$ŽQ':ET)o_.TUcÄUR}X9`Fo{! BrG BRE,\ qF7[yMꩺWZpn9 k NQ-1ߗXHs/IOiv7_w?l[$۴*Cn+bQ ׋<80(e_9۬7.πL a^; PBVӼsV6㸖+a`s&~#yNmj  5@ X2:uƷwWƲX@bJCDaZg*WdH^In.hj*3SSπ! w/n)C 9p1&hĶmۚضmNlv&mﬕ?wwuUݻ_jL(g7hPP_%Tp mjcqT Vv߿u HID'M|)^I ~<֙FOQ?=w`M=n(P8ȳ,7Gcj+.jOnb9m*N`_6d5 i2zRI7RڅV{cNd-@} K$*3кL*L3%ZR\z+-R tQ4ɓJcF8;g[o YMfdjR*cBEvF6з>sTQ p24%FE{.D-]r5'cz;iP:ZMb|ͥ=&@E,,@Jՠ2/ލF7y\, kܘ3fހxņmm 97+R;|RuC ߫d e)\lZ!e$<)~}5/U64^VX6A Ex4aܘXMSur/Tlq%:Z1:kE0yT)6!MfدN>"0%ߍwsJYHFjvu4~wOS*R /tѰ^q#0i =+b )Ke{WGVZAFWk2v!XJ~+Dj$6ܾH-_+qM'_V4UwvE#[g 6&-eÅ5PGsqZ ϹF3Z{2 # s.RoYFT)`V9gSU1 Hh(גҊ+! jMY"'g0jC: (2DJ5.G2AaqEaHt|ې\.nZؘRz+H&4F}#`^\v7tM0AK5㍣MOr|RRx,6@f+*~ڬD hD.:UGB%5jKf5-"@t{Pg"Ao`!ZΪ$[CBXTɵxo,qrwH%vMVS^@7^~kڟ ?Si?a+*Y(g\>p/glc1ߦȕƋ801lWKXݨpKUw/ Z\vCh}~ېşHnKgkN1^ +82 D#S}İuQu,PvsJ gStk+*<xQXj#r9xxj?"WV^Np[ B9S :#"hY9Q,1\1[Bfe 8 z{h?N.~%U+&|\j&>RT2+ϪnD^u`, '(*;+sHto{j\46n+InXSA;gZJEE\ {6}rAw_SI>|i}%5R k;¡XK"S M^F Utҙcucy2|PͫKhDfY_f((4\b_Z xO|o^~%*d=rA'T9|S?{{:WW?ORK >},l?0-*BICoVviN1= &w O(Bu)#$pE.(:4Pb=0!j)5mr|*ěLzoE'GܗZRX29Y1EbU{Z&j̎^;PŶ' GkϵGחˆ 1R%Q+N'UDPd8Ek%}+d8WLԭ4ewHK3K0C6,QLrS2F¨O+moo͗>ΛD!bَj`Քg<'̃Vco C@&ꗢӷ덿 X&/tQAXW#Fv8g!D1lTj:s f"T;|E'E5>7+@@ P޺ry,Hː;blQ3l$<8ƃ7l!\Ne#9 TqoR?ֶ11aψd`ПcI 8J2Z-^ߦkK%|V΂f-.Bl\G3M62"FZSFtfruaDʝA3;A 6=_U` |Sk{sUja)1Վ,w8QH|^JS»o@k6Odظ,9laij6(3*s4nm]W<r5@xo`q58^ܠ@E.5$ra$QuE~eۮj ~@ K4b Rn2]`pRGdN}ϩ[ MVܱ8(>FXaП9cfT5{ "iU!xwgxgC~*@(!l[F6|Oȏmk;5-Ý'z9X?f$ղ 6"M=L%;\NA5o@ ?'L&ONrA&6[EҠI3NO/w'D3 Oaգt}R>@`L݄o$v * }kOAaB tw)]9Ew8u ]8#ު 4^*amj4Bj9oauRnm,jM>iIB񙞽vkK6*{fX6Iy̯+AHz\{fRY67FEXBI刡 ?;ŲIA9csR';r |+39j#ƞgZjV =@|wN߶LonU6T17a8%UΚrY<Y"s;{kj_fPUӮPA[PLoϊFF< qKMi8~ً==B ؘQSg \(r- &miN襲f+2^ߐz. G.gdAڗA-l(.#>;Zb0y4bUg+J?mADE[D?l!__m'Z}+WFʡe9\yg epL,K'sBOI!7zKa5ÕO!>dL2R6a[QReiQ]  2xޕBD/ aȬ4T.8/"o(Wɍ-VJh+zQJ ֏Tg+7}gUP*@M눣!ך89Ӵ[|~~O)q^܋ƀͥ\Sn餼EYFoSqc%$@;^CtjL:IK^#umAY gc0VgӢ*֠nq2uGj<ߓūu8suÕϦ; 2; 3<[<2%Ys]_nPWә h.5S$ky^&Ύ/֗VK?jf0oCm*(1TFRT4y[1ТL1ӌVqoK|6Y%=rOs+sV]ZmԅB I^IDY9(UxdXV8ǎ8Ѯz*`DgV3,ִfun|ad_֫iDguа{]m)zx7;ߊ*ʮ4|(̿ rڢX JYevz;|mi$גQi>-y}37S%][֊|g>q3DK=s5QΒ#IޤЇo*LnGw:j+\ 4\Dʓߑb Qi` w䯅8~ߧZa7*閝[-|克͏ 1n]:iBD"!{E=OZCfjo#Mg"$k?;IlZ˹>$*SuFv)lʛrWt[S%z)-Pu_: ='@,M3 _Zuŋ\qUFH@Z˸H;Lۉz `@˸(0e#aߴ(o*)Ӵ27v[Ԏ-Đ ܇\yq^D͡޷p㔊ӑTꜟʕECxTRVbYw`K .k__:f?1 T(񒜕Mg뒲k\ZK#40 ^q!0?\D3.*תT[?E"=i@3w [QUoJH `Bv#?oP&99Q ͞9d*2}8 lM?WtQc綨QCC]{C-|~Җ.BH#ޫY&?V烑dU?O\k܇3kbzґp݈W^=ܮ("$`3ϵSʜBb")*7 S$7vѶK"-lETHAW"S}V;83K^]T5xqC M;\CvS"g^F: "V؍ȔoUB*KZr@WඌOX*>pc(EɴS-ewDC+iIЭwKu+Eh볖pU$VQu1D)@߸j^!mj;C@KdurQ/dg왂'8ʈ}BӢzA}EO|W?qYN"]L l+eRei`N%}'R0BՉ 082w]453'u"qJ%&fءNqS"Y< ק:uf@`mc"4'̽~rIf =z!ܓޞ]2n4dj<dǡi3~3#Ύo*7tBbSh;]KMGH|(kwb\vR[ 䜧ݯQekl*|;\X~Ub-D&0%NT IQqL9TwS n| BSe{9Uv[Q`yVe))ՆMJP\l00zKU\+sKQ֛+Jt6Dn r`Gza\Zc:by2.ݲT/w x%`:T[y݈C4|Tm bz0J oѺ_L@f=PQ>g A&A(}̇~:#qA0O80IQ>ܭ{ P3Yp> K{9EWH)>Q^ȬwZR[t%:=BuKrDqX*-XW+쉾ip/_F$r3+CaAdz(gCPǭH"gV2uhU1jµBy兔ѱ˪/*J5&N T,ۓ98$v\%j}SpA+Ib+TM)-ZbLSN[)UU)ޑJi!S%le("1<_TXOቯ\>YX/YB U%q4UJs/uM?|1d9tBiP tx6%kx5."LZI@VٕߠI D)?*tMGG vGSrPc[IJ|'m-ߡ5EK20Rfzf|,q1]탱%tp7u:GoR 'z ߼p(shBLFL߃6+fFW23zOU0q2^7ֲ &˷Hf8f1[5<#Bn4oLs2w{<:29,߈,J:a Op90ۉty)\8ۨlkoפo`c/ȓ&jD¹"Ʃpj.ֿ\\V,sT `w~^%Ed Yh s#='L0/J7m_>B9<~*Gvr+J^6±-]A1O$3Jjs#ABHj6V32~vnBm")B؎MJȎ-`_k~džre>R"W)G 當)BJ3/AݽKB%rN|)viV ߯G6gb cz BR!F⏁cHz!1jߍ-UL!?kG-.-S\q-Y7s {F-[crp[0hʨ#P_8-Wv6";I+g{^U+VoObyl 54 Z{μ0B&{u5&){nA _j}+~Ac+ }(ʦbt Vh*/RrvYå3۽l!WW%hۋ^ثC酇/O.HK*1,6Ֆxh/+;^kCZb{M ~lc6X'WVn ڝ*yS$~fv)5 evxDĉ7.ꏪ6 Eo:Ŷ_~_CSZؒRz ck/ߪ"̧DZcqVVʷʉW~浲{.4@'.%Ut;|^m-naiJd#i9m/3#,Ko>᫦D3v;Vѷ1l\?!\6FxHnN2N,} ❘DySsD1I&IɡRp9uIWi."#? #9bd`_]hG*O2`}=ЏY,_M(ikb`6ރ )3U;D%E0\s6Ew&VeH2gHԸ۰$peӎɲZƾ2S)':c 3%kJrR|4s_eK4+$*BPlT6=39t fsS,vn?+HAapXbyd;SD"Gfߴ!*ESg*Z3Y0aP(9']VjK"ʂ-NQjTTlGF?(ެ#cI"K5,o2&ʟ\EOX]]LtuQQc_|m4Qr:on=#s=CrO.kQm*=6(!A E_92wgys1LLm20Mw EnL*5..7&~i;,,O,#3\=L>1Ed|>  -Vlz*5f:'#o^*1γ0 9VZѥŏzur#⎜GAXTe`uA`qA-I[*`\RE`<` ʝ~}Qf ||^ן(' c y驓'Y9a`-\Ti{8`lYe Dq@J}wx!w^ wVw_bV Ɗ[:9 Ϛ=\'4q[yy ֎b5k1a3F+E t>N Gwº9$Q>%x_ge =6D y=C Y'mnZvb&}p+sj[%l75u !Y_:ԥܾΨCIutxGJX\@2Tx'$S< fsT c+8!S{ig7ήP!R/~{'B'RRF)hT&tx-#dm%֌@=?z,PSQ$Rjܑ1!d,BK/h|o[SϸS\N%QI$%lN16,H7mk6WrIlEG`'eB{NX5CHDa ?gHf];27,R28ҏ^Tl{ѺRH[j?/@.2ȨJʣ^E~v+ %_au=)kr.w iKJvHFVdfqpu= Nn361ab00na)vWRExRZ ͪ~[9R,g [2 Q8eܐQg_!E<&J ̛ᑽ1FcDx)׷/ $ſpު8%z~_G'kk0c 1;JhQ$SX^cRivkXNU2Jwhчڶ =(ۆҬzNUݽ 9 &ہ"!"kEb~թzRsK`m!Np0Ӌ r'GKWAu??~rS|6H 2,2~9]բ"2Iy li2^VsΕ5_lcmA_Pɷeࠠ@"eZ% ~{ˆE3*I}B/ĊXWAKG{И0znwNs:q@[{€/vjA7|0ŗtL^) (YU]-nelwA!}yIzexD-tji)=$|9 \rpR}36R pi c0|pI9ZQ 0dP]D><\b`dIU#DjHQ݊.kU"tt4'i.Ien~Yc֧t暀8: ʉ{I$ɠ^̨alA8#G"u-T ~bASO,ͮ~BXlhwl7_*f Wؤv4_̏;"mD'Lz$e\X_ݓz4Pe9@I<?0ܩ>ER'2SȼC-{é \x>X!N+siY"(( qO̶ys.N`W 6\hO:(y0dZ3ϗk[PN 3&z&irKbEP`u; 1n~aPB[e+;tg^-VZ"݋ 'eбih {ßURR=x "> ^ 0I4qXvP1f|H5b hiP܄M&[*3q*v Gu_t``\+ŦOxbƽ-ޗ_cI''S٦*$IXE\9;oUQЁdɶ;Ceyi{9 d[ܗŪ#ڃݣkʧ'Y*^A}+.7)1,"? ^C)Yܬd_-9֗[dܠ0qZ1mp)O9Jҳ׷nM!r jHi zv-D|gO^"aȮiěz=T+PyqJg&3:۱9EW_P_@qf( muY(ڒoX5c5B+26 R&ܕ, F͐I#ffĠPh7#g\cnCvJ!H,ەr/+Xy_T {NbRߌ{էgX@C/E]ME;ÌЙU5E)sR+K)E¾ X|j>xl}_c"M>`WL%f1a*^5rj4Dr2/)tC=Tp)q(ɶ]iHEU".h*#jI*4MBLgF1?M(i8}ML#/KNZ3cϝO ;4t0XC7i1^V_Ge{1"*n/G#rpv`0Ҩ Op6`ciQkeXiCmj68vM.tSnGG?0cSZ4f7*1g:UhRSd5"t*eAJm#cGHFrf}<0x-l'8w<y㥕 MT0OmzµZGDT#Sv`)ᯈlV7 Nreʨ̰tJʊb÷E\S/g®0RQ#"yեHwKb/E诬2ݟCs^ c9mڑn/؃'l,y )1U3ꅬ@Yհ{Z: 1ê˩boU@\H?IgI4ڸڽ;i(`fVQMFhV9S`3͏䍻"IG!ȮxN2 7l֯;b@a­S guq fy lM\@ewG Tmph%OyaBi̲a!7-" 4-N0~ fn߱b[JW5+ DUxA٬P šA7V!v} $-DL`.G:/r,B_\XծwO,lY8?q[\#/ƥ;$r?Om>Fd ?іS|v*hK nsc4? "A9<1Qa}x3V(mmPX* Bg92afqhe^OW ?{Q֑L0n  )ǧ˻cOj=T/.V'ǒܢ-ޯOJϋ᯳{G/7ϲ'/+ϒ/-&Jc$D,ʯ!-!;q;idΏ-Q?K9EŮs+TTOg{l_/Sw8PI)ƒEwvKI*Rx|ȧ{~rq?3)M~؟*g4E͖SJ*`;H?=6PptxAy,ty+W[rd>(|(lTglL(+o[ޣ >o_T s.ΖB돳?٨tsa[^CH ́10<VD^'+2.9\.x1i,?oL"_Uajh$?;ӡ6x>G0\N^xuHttdfUױ PIjB° cVxUWwlC\:A?7( ,d";1Gܥ@wu5aM2'XD8"BN0$+*#ٿE:.e={Z1ePIVEˣߎj m _E%ɐjsE9Ge (}`sY]N2L)u}SHzQopɠa뾀eg̞? 7D>!$^>I͑r32e^ڡup `B?K4)D䈠.EY4'$X6.Ef'쑱Q!OI5U8o}pJQI6Muy/GȖNQ|c`9$z`CJpS<0aRFqQNqS\#LM`<:%C'aB/|mePڰ|e>ַLHml;P&/ Bs#Bc9l䂈2c\ I$c _() P2Vsp'!lѵ~PenJ0Kҁ8c0HN3 C4ZN:e1 >>zgU}dJ`6ES+&56h8A6zumm21mnxy4K4tHmrUQwV t%FwzQbE=VҚ m,v`S̳c«0Ijsͥ k!Xҟ0v:4b;6yfEfYZOtPcL2n mGАƍUh@gg9*|/L5chs)FȜQUex)Hy2]=6/ B0mc_R~zRN \#Ib~LIt1xixOpPC54#y1P# C_KTA;H >${y'5"l9SJP8I>9~Jf2UNI;PTvfT0:,W*SvbAfڕ6ې/8].h;R]济MS#NBJ ӨO5P ( sv%L5Z'f{4qitS&f_7NnbdFG1sf&&NJ'IZj=3)GRDHvNa,9?!,/ ͉Nz ,^{^Jp5ar`?Д&2`bE.Sxq0w!x\U0j孠ɷB|rX+?NCL5XVyYN^pڷxYp' v,BdfB!,J5{[&yY^4/w!]KOv&q ,-U0&msR"G=F`v  0ќ0A64|Bt=A|J`Qa}^9|A2Ka_ӴRuL]l9 xk\KhBPmT3}-|V]#\m :dRT(- /&,%e)e/ >U 3&ʽDǹ2Lpj̈OX@f東 G "Iz% PeOЫ! P)j}VNz]oAJ"}cb1~QQmu9TC}Rp=A^fFub9QZeJAȀ1еi)laqiiJZ*Cӡ3@m'EDוkW pޢ`׼(KWOsOdLWV~KRn# ,ڏծkJ ⾺d6=6L♱tgu>Wn8ڳd5ZK!RW`1St@wڈS)C_:͌X?:l/5TFߪf1xU*cǺ#[H"M@wY98!2Ilm627Ԗ D47~Iٺ߽=jѽ&e ZD"-^g37;InjrNfP][ծvpoP_%5qTm='CsҟJӕj>AͰ|hf.A,S4T-0bg# ,}/X]&+\5.\n8u:WekMj5jx<bEq->SX[=H54kLCY0bC-nB+_HCn!\e%DBXXCA]램Ŋry$!QN$[4QzgORTa}I5kjL_ E1ff(f7Hk蜭J+Du(X[Fٛ˰(PQXܹ v$Dsq綐rC&"h@ hAt(i0V.H2" $bQr'UoPB[ U\n.kaҩXS늟pGn+|NX$eR f7[I:AS۫m觋sASV~ҭ4&.DIXvpR$۫ݫ wV/n!ʞzo/fZg@ KП煓>RM /@͞R&^<%cWCN OzC+!!oڙ,ͤ{S`<9ؓw'jǼ%Èw&XtO:1B{'spf#bv Do|'MwRVӛ&~7y:F$0a{T<'̨FʺjbgcVD^0& $Kh4p=krO$EtWRe36O44Cx6QG~Fi#iiL(+S4>lܸK>B}3v4]y}.5&EV~o拳8SHSahEĺ/;r}.rgqG ^‡W%Ũ䴌D7o6dtb`Nh<QVE')'`#d "?Rtc&9Z<(cHk5g"Ѻ"̩ߺzZ1}L o(J7KbIyBQC7 1ҡtŹ4ROo`cv?54h@iTwY?/Gq&ˍ Brv0p6rZފ^#5TD@B"ٞ8Aњϑm9 l 9WT%-Tr?tV0PNb!*#+Vc [n"_֬;JB }}୅\RrqU\V=h Q;W a`~CǛѫx[3ZDG%t$=pSw檟/e-]P) hOJdsC$}h(@_'cAd`Me\< S1OࠬBR)>H(T^nߴЩt՞dta͠^wjh8BtOX8=>W,iC_3wʕ{EGmwaHf. ]cD &}ibhteQ$o-yAUPv`ъk;3gw_d6u\F:B4AY.}9*o_xiG"ȯYLQUBF)hOgqRd3ni"uPKfZ`J5?6#/JڬZnq|,PZmh;E#*-[EVkP'Ȃ:V$YFl#%?ʆ`!0b2510H4truB+XLb"4݃ vD~7AHp#cB>bx ZZFXRUME LP\/)] dDy|/R]U2*n\p8^bfkvGHW(;"O2@ґırTB~73짠bOzF[8v:L"u{H`ڎ'4z-uLM+ѕ!ǝYr !Vvik+*,IN,>뢋,QFG}='@mgaʆ[PXWj?˰?u8n^YceMR,]&"*Ԥ̿jqj("PdJT5!"^8_ bŝ~coLy8JヸPyZQeވaIΛjB`MxΘS}rk{8&2IiS)ԡae܈%,z%M(Ri#NpB'}$aj/0)b!&R#?b;:>=PǙ.nJ =%;׉u+7SHaoBǏ6r0{%ÔrOY*+>k`Z%Q=Я 3":12|` ٔ٦jl} dpz e)t#*E])C$ߑN]?nl'J8b7hnZ`r%| ɸ}_q-#ԖHU⧂WU66U| ɂF,h[ըlǣ3&lZ9OF_儻X#/^@5Ť[ l]_n{ ﭝ;/|g9,%/PyN05 Y o |9)72_oY N 'ZLQ|+s_b>STC/ z D~vy/X2jlhO|\˽e#wDUR[7-#WRƙ\'UFka)MO[M;i>MAQY'φbn*hHbV#^ ttSh\Nvtg9Q$qjn,4vPx53x# 0lWJ2L%\MuR??wmB/o9/HjoJա2?CA,ݟ'l Mւ֡96Gi0% c9$N,[Fl0d9 A麳{hSL_v ?g-&dXh ֬sxtޘd~߻h3'7$z7 ḧ́\ǽ].gm.+cߜk IOa ̮&v +,Z>/m"G\S5 OsH%nAq"w&E;4Tj^S$s_8g+;*)F`hcS u6ХˆΪ!t|9 Ɩ3$.Q( ;?N}z1`lvvm-`Io ^ꭋ#ղk ||5PPT^"ʷ#ZٯುvlDwBiF.299tBg+ ߥs^Z ? 7['9gnR+o_E:׺~p7$/ބbNm/Ƿտyo.V`(?P) .unC҂סos,-dž#Gf+W[G[fyG"CuW1tFӬHz{;b<l8pXCh@%Y/°Zkסk@)PlkZL{Gvϻ+Qu+*aO&:b^AI tBU_ꮋ'778Ckv,Y-١q }b<[,&ܺx7rCzqSց=P%Um KMfjFyœ]cƂu"M{C/}SGkX-_iFx\os\aG#K)d1F1v>68E5dfXJfIYے3~[B+pPЍiqM0)H!Guw&^ b i9F?5$̆:{(K# ?Xaٌg2J< gh4b4L=J7u!-(\s=Ծ0Fċd8C@HA.X 6f,^[ia.9v_}1QBB(dA74g;ЪKx 2y!;Ո?jǁ;X!i0'*-G[9Kf}J} T[m9)W,XMEbc# 0^| Ӫؿ\ {1ע2*@!lu5]GrAQ ĕj ȯv/K mwȩUL&Kl›=eve fQf.N-#X!b{.k>276u*g35+ijh.}HmichZA`#19iXVQGgӈLcMM[ebEX!`4.ܚ1"js~g[7>U#:\a}$= C|wTfő6c2čR)N0UvO{S^M8mh5 lm4#O=f[)|; ::DMSzvG='*'-?"5qG@^<_ ̯'/mc/({웇ԵF@nRpKP`ѿ2CdCB*=SGpHk>jZ{t rhXŵ4$DU Ku#a.mfE;1Ll\kU+AQ:z1LW& 4 Qp]@EP5Y%H4F7ۓ` t%U_6_} {R4)LMqJt5"Ha (\l>C'L-Jz|;K: ?aj6M=8ۨc0`:{ɁQ%1RӾoc"~"F+% w}8>2`NU\ Ր@>8) c&(Zd'vImZi0뮔vfJFވt pa"JP*0]1\ه%e:̟4؎XTZ¢QO`c.%5j]H:6 QWOc`wH4NqL7'~LT]0_&p]Xڇl+X L6:dVrSZnW-ķ&|Bg^`[)E n41030߀?(vh8?c"hD.5fvxeiS#tGtVIT*&46>ƒi=ҁ$ > 91/ $&7+ZɹK+!uQt@: [ fkvyVDP}nz%c!ї5 ǎι”b6q(U ʾma:I&U N,Q׾ӻڵ Az(5oN(]1 vʆJED`Uj]e?SP۱&Ί*lƜ\xhYj}Gae uTX< r)>(S%)W-W /v%Y2O/Uv/FH켕E(n܉$3mtV"0݈2/T>M+9D`I)(+8Zgzej : Wcy&kcQ2SA }ǒk3Nj [Ba9WQOd֪z3h#:ˉfʜfU9,ТYޘn"-a.U9 MY_[=V^O$a?s17 w\p [;$SKDf-*# y/J5uIn$cQ鍕8q.w(@[ 26T`䍩zTՐ]3%&Mc,VÜ>BZhhx^oeE]q'wZ2rs.YkBBE7ܫlGwcm~$dv 秎LԿin0kl/৒=255 ǂyJ+Kɋ}fP$\]Ly+S]⇀6f~tat?!bƸx,*RLA +* cu[w@:E{,Zڿ y| u2(FbߛzwgLC[Y"u3;oj*&kE[q ͿMZM?q}]~W4lYxs_k*usߛ=5l2okVbk: t:V&SݻٽW݉s1fI0%K4Fp'm,2q5 P 4DQW<'H͵"([m#T2˝R!-qjn`]* Vfq8ŬOsՃd'TOI\)lTbDW6 wɔD5wN(1hdjTaD˷61bQJ̺iWQߵqhT dXkp2W)2vU My]/]w^> _a>P}8 قؠlν+<A4Wخyj7+sJʅ]`$NjfhC}͙zw.%Ŧ&EmMR^o$&0 b7_cܢ\tp'Ni Ιm'uĨsIH]j&U%ȳpdL@UDIc6ڻVp/>.P )?]ٯ#W<(-̞jwQ1Cs3u͍<,m7Өە~Y@>mo&j rZ}Ԃo ـPSԚ?lU+O`B7L䰕̆7#{t*!'T$WEu ~+tfc/aj)~3ޤ|430ǫm&j[8AOMNN%8p1oE2fdҌDb̤A.sQI+XfYVBf~cqMvgso T4чu&e5?y;:=/%aTRG$;iJL ȯdAϙL$˽eVT2 jV<F S3|2՚yX5E~UC9FVLȏo6T֎ A\.4[r̿纫wͅ-.Au Cf +u!sk1CSfE=Qr8,XcQKi]nh+^2e£KX.&k\v~#kp+42Q't՞c-z˪&ڡÌGxeT:?&IQpP3729?*؃S Jc4*<8QRrQb=m^?]PJ#8oPVf"ˆDS=(jևo҈ZÆ̚vpnZ~K1-} P7ʎs5cIo&gmORU 8%9Q7ԈڻnCBģN3$M3B, *6QahwV`?dy_#Ȑ }|׸oHe JR3}Gty+J.* V4lã5g?t1>2&E#c'f0CE0#O7iHmh#Яbt C>KDmt4 <;!Kϰia .ɰγD+WV| X҂bd#!Au^ۚC%$Pf/Mdk@ <HZ|ǦN #1t7%V}ՒtČ|im)W_QΜo%S2VZR=LLo*u_J>ZIx ?^o\>G!**|{.Zp"ƞ{mpf^D4ggrP&i`[dV0AGq½WʢNq*hy1!>w +'>c.%8! ORw/ xX/J># 554$>kl%A-zP}$gM1[ͯo󿦀t6q]EͨY +I?p$~!PY ~w)^$FN.FeCE^h+ZPC˦TI 򏟊jr<ʫ-eZ *CQsq#gOGG)ТL9X}nZwsy 0޽[&^[7 KZ-deShQ~cli?i\A u⃯M0㇫X\X%}+)gQX+;v< oOኈ.E1}{xVn'͛X?΀bVd2.t!+kJ;8@Wmd/C,AE~8G۶J@ 6ԫCKO3HUmWLd"V~/GyJ\ѐl}(1E0v5NH%bFHh'\E>9|㵮!V ʹ6<< ;F ?Bޅ*‹RnYҮF`Er6;RC1!g_WhQd nߠF$= Ѕ,z )[nbݰ.{=!n 1R?]Fa0@i` e?S:{XWS=zc>@xT]cّ/%w:%w~I,Au%Iw%\dH\ |u"{2ɍnK7sK=;?lu A(͏E(DQ)"dg[RH4| ]IMxWnd:i){?xBgHN#]D!^&Ϙ*>`upIb &xu 'wE/#'-11I'ІB 2ڔjĔW2>6-( $֍l^Ip߁Mf37글V1JR"dqOj|Ht_baܯrN3;WSyxr߀.YBhʴ;崻y'S 4dA!}5+AWE[fZ«E-q6GYGcGy^4\a6G?YÊ B^!瀡;dcw^T4ݤce#wO}{C˝b?3R }wyo,' ,泏tWKS}m`)ÔO03qd8v.U˧=عUծ[p!sYRd$,(%p &EnŒHN$SHgW#JZZ<%Y@F=_e UgAfpHM0?,]r'r},cf$%}rN5HG-$=Vx);7q]G@[[s_mYMb[Zk4 T~V?Xt2 +<[I e.c27rхW8+$ɊBoDa\"!g>JX\': ~vLbxZ,Hko~cF NNX>ɏYn˴|hUnp~QwGim$mܱ**BKNEvY6Z*g"+S^s;aoq:s ]<moܯg:lnFWYrk06eO)ca[H9LN'Ke_Aĺh"*"]^T1P$?8OaAkܝZ G _ni5ȏO H "J~.ox-vTH+< \cw&]aWi%'YM.cJ0*~ߍ˸,R)!1kgpFy` ){8f<NqbnLKo˟{m$}goKf gQO _+gtcw~|7E9AX> w`Cf)T&b}0c(3@?Qn0sG`n/BH!u 6<Չ[)nDPNw^騡/[ys╃QQ; Gk`궈Z.zP ;soߗ?Pd. 3!(03yfW8b͍mGt@Q&YMVw;L6İ%Xz\}O6,t1(']pd"Z:| af'.(J"ͫs%%Mȱ',Oqʸ[š="yº"k/mq$x&f˻Ee1f1iiW0K>Þ,jyBg^QF7oᇅ|b5^S׹CcW"s?lt8d//gS3v،K5HۿEYR %Q% f1&? OWk$ )8b9vy #|=Fc*\+-S #Y6"vw*-alES\H wjtM 39ɇnWt꽴m^kH\Dm#[%XhQ:])~238-UO&3١& tq RNz;5yQ'wټ{,6F = ~qlD dNNZ.yQ0Puh}. b  nEX@9HewGaI8F#s!pg2mَOL7І,9'Xr>*e:i-}jXU OI:)-WvʢR>vkb۾_BٜD݀4ޜ\ 绵N)D׷)SCBJإ.)zGozQ^P\m PPc_wN[$S.MOHQ$-Gm_'YT;\[:=Ywh',m4&`Ig3l &DTL!cV *ps'6Ut hՖ6۽T?o~~";mQu y.ɪ~Yz w A*K'x&ly^Ȯ9<Y(\ܴ_):Vp1܄)I;[E4"j3hi4]Zb"I"NQ !iDvx5r?5 `gqJQ%JZT#aJ5YYC<g!/yEǴ2D9=989Tpw1p=Z[*+?M}>s+?X)Udd~ ˍ"ϋk; =#WpHZN5R{&YWM;&Kl633Zҽ{+^߯w}Z?ŵ4 %Zo$ 5Q Mt\LX~4V_^#F mя;rN}VoÂφ-/BFa,IM}:bO4 ?p|d"#ueB$KOn8O.T$QS,n©-g]$w#e8reZzg AOd2Mohz(?.^6i iv0iUcYV "غ\ R*9L"lyOɣ+-CC!ɋB$%:&"'nv `ʓ#nKi޶;}sa־ӜF_ o]p2fN >x\JU2u⁐4sG1t}n\N |"슝\Ba[#GV?͒cR0D`ˏV+d]0b[pZZ0[ONn Wr`o?z)L uƵbiI>av_ EN霂DC#۩ICFa'T(] ݲͪgmyź 3L(d@.XPI(i:}B)!RDzjqCJUnA0V΅FAUV'YNHUoaz!m0|cLjJ@!hٜ4~%9.{ I~Ef7밭i~U!Lt6+~ 3+^jKS5"kOЧ~HK=I%T&kV*[L7 jlvd%TwTlHT$.?:*W:ak &sȼ) FW^1q#Z(,)_+PAL u{ux?Dޙ9:RTT "ְh6qzep7|J]PG~8ڣ^gf5[$f[:?׏VV?#yjkӢzɠ}9ƩG8G݌a-82h{q[GϷv[ 檮 ]tVfLY! n !5|R1?|rK[/)!ٷ2Fp1QW$gh‡ǺMTZBL]C~WTi.3U(ҩD%|GD=&A~'z9>zfCi*}Մ28G,v%DduݤLC)oՁIWfR]Z {%d@  T0shxZByc%ɶ&Upo}TlB,n2] ɤQ4Jk!KZ}t= -~*1Չe!Բz 1K~uL4e]K1ϑ'`P784Q鵽/I'|P^>WIo9\p'&٭֏%Mo4Ե(NxY09jpU^Лl}EoZT˰"sü>V+[P KPC $9 Cj`EqvFcZr \(HBc.A% G-ҘPķ0[a#P'꾠PDl~GBKDTL(GſP/Vt[rsN܁Sux^0fRJKG;GOFjjmىbC[Ry)SΆW**b|ijkc6p-WW@Y:mR">GayТ=6&0vp ©83I=?qr>CkRmL71W 0ꮴ0ljR8Hq&u"={rƭ#gĉEn9 ֱe_ MJQE6ت Uu]eN3"Cse'H*#hQze5 p5OQ~,6[ΓI}#ރ4YNm=L;{ EA̿S˾T - So@H!J'_rG4и3q .iL/>chyn8TԸJe}g61h%E5dН\b]xIֳSs߾v7I.UØh$dH|n9RVZ.(lyiybj(|bŘKqz-R',i&^$O$a艄~S.[5~HeP0F"pl l2YfN",^- PċأBHy'pӡʍ O<8‚4;}qlMO3kS(1д"L1`V~'G$%3=a_jZI(iy'x׹ښ29ijj31]$l@758s[ZM<TEb,:JGN'ZR9obsiN g|%=\$Saq 0Wlo*1Ɗ4(Ҍu3ڗx= ѩ)ec%~E.08nྍUsؚZ?{q͚[,[ܙ(bqǡi,K9sK%;E[mHRRM+,c>r[el ]U"E$ 0G~WC4R tpxhb-\M@U|\ N#'Z,\VN#4-1h>"e'aPȕ5eAI|0&l-B!My2V|K&DV% (JG?: "˽33#!@:PLCJԞt_%eISTc(JfFhQHe%.jJ.0G։:0ٵBͱx ttj gB(GJ?A/Y y$ݯ^d:P1 ݜ KQKDpIlsm 28~p6ԛK/3y}(mY~֐&lѲ7hY@\њ֧Cce2Qި;]iWЋУo绿ˆoeǬaCݺRǭa*Yl5U7) Eưk+\ar`O-.Dg=n~)[gXz[< 0P$2ՔS|9HN dV 8d$]:P5}"Cbjqw, ǬLKsϿPVrш lH\+onFn l`ϞJmfo9BHk)9A+Cx}]g}aٵgէEkHnl8ݢC65#";T]%S>cfg 94]2/]1|'TPOҳ N=ZsbC_M5 lvy#-+MDFR?/(?HШKڍe?c:U[d}T8É`[!7j^/L/@O Wl>ږ r۴|e/ژx /, $^rB%BS kS+nm(4`Nާ k,Wx 8t0Qq+l+C,OFZ@(z6oVD8t<Jd)e??WrAg"fbY "yF(z7l=PAv]j ɖHuQjFMY:F[|lYz4|j Bs͡AXѳ˜pOE3?͙8. xl2_/|Af") ""(_lgYKA[1LZVz.LmSݷ9;y4Zz'(}$yﰯ*8[(926_EGnUy@&%+AxPn)͈_ 0/\<`g츹W/~b]\؅pm f )_-]T/ .e?$E[s_A΄ +!Ew[ȱ;n4OCD֟ lv|>e mD%90P`pcG[6V 842#LQHTps[uw{>&u6Ct:}=nxaށh4XGKP:|0'̫?ID@3yWC+9._vnD倎t] ȀX'l| ]ɻboU.:߉ӈrwwzCDKe~X<;X=Jb)TI>7a+ d2<,ՊlLPeu2Vg}r^mL2؞ҎFVM#T /Ke\CX]9[H,cBWbTMzpIj/%Y-ҍgpBbb`}p#?vY( h=k;Zeós`"ԁipmul|ONoJM>8zRԇ~S\n9=U` UA֟ipYG^NEzgE3(1p2fwo![ |L`T@Ϯj9Og"yђfЗl j|Su:Bw*(2xeQ&\pO [ .%T(S1I9Z7Q>"Y4oLIwAZ_#Tt|<.tM\fwPxdEhzGPouZ1|:8p.2儺I**Xj4?bCBzZK=GR87>άÝi3Xhf rj@Rzp[z+o-%Ԋ|g*vKs9O!BZFMn-v@gxjְǮexrS#y7n)TKXm=;f|z?2\\ͮ.֔WR >`ePHF12L+}<87:%A;nNt9V /@-N¼q2 zxlx;l(#xҺbua]>.Ikw3otpE'_X]g84CҔßHt,61Z nrrΛq6ڋq$b4ƽb!mw,EXgǺiےr9sMxR7grpsmI@v4g&e1> ;%9mƅj]3M}h'LJه*v`Rbk3έg>/c f%6ʋu?m-fyHRRKKF|H>~}3p;- WF#)T MÔ3^JO ?]]mmcރ6\{zv}.}T";;T1U"C5M&|=rq ]a;чpv> q;k)24|/.76_"2.Uk m{~ E}ooSI/{ h2"`z {C?%W1bs݁~t.#ww޷ur+amͯm"nuU}.>kF=s6+̡pm5z=b):mrv BZw@g':4RgyqG*vvt!ĒGS;y@<$P]#l1>bv"arTBn9X}J34ν ={1%CPwIF |CT_gٱ9<C֩kKg `1koL4ȿCWM[vC!a~J~c㋌Q%3d5P$d1&](2P9m^k. &oU%` V%t,t'GǞv5;5#4nQN C~uCUߔ?!ŦFj`;7^+4Į- l3R_s۳0pH8/^nyڨ;ocyʞ߱Z79Rwv޻:^BGQ7R!U1vwnnff M.h(!˓D#|"u SK_24kɮs|h݅s5aC]\ƛ# qYUJ]-<ʉԂ빆Wtn'@/@96lC_` NND4 J?A}-~4u>5V' j8i+w'^TM>a MkH2 B:d0С%G {FU-K}m)D^YMPz^J-heSuΜ*kwHڃÚ[d4!O˺A~2`rNYPfU={uncX%v}b:k.LLQI?Oz~[$9p%7ڍwj{ &*t 5Q6WHqiypXJ]:M~-$Xa&ϯ-^l a74M% /?t(p1]d*ڛ\.n]p:jYE#Xb=#էEt9ЖE#rNXoN l>?7(q>]%춪 z4hoн`ɼ%HFͻ+3OT&_p@{O.Y`)c)P1a aJRIbi3Ê.'G̦WI)saG\7߱V@D-Y}83m#/Ӣqj,] w3[ x Hho(7;X룛@P[0j@&2T- h.cΕvko•T2?XsyM{hkTt0Qlj!\~]Y4*[M؂4'EN;xj}!DARY2 ?Ա|^ 1mfecg`؍T:cӊ5ωY V N?^cV:9BӎM?-e~7%w"1_O+ùuaO߮lA/N]GU7QGM>!9 ^K]wRk{ U^6È3ؐ'֧1`kWr 1s<Ao18!.q|~_uެӒ4qZt DEw z _ b_)MԜj77F {Q9*w$ j #:[ ]lvMJ27% Cq[xjcn:A<'%=Zq4~;/wB߽ax6n_U'5~(H4g,(,Do;lc!ؓJML.e`YcՖhM! r.=ut;\5f'=/v0uK Ч鏞'|E!h#h64|y7\ 04im=ׅwjiuFs-E^/An53\=7 guT;"VrZz+_DgW]KDeJXMaaF;IJ~B}#a@rPw Ua+`i/6iKB ݫmLa1cl$?38&2F0Qm7d4{yb^ݕ~<{VoM20P2LIc#hZc*i:ձr|(Qr(K!Q"H%yP1Uˋ|llneI+P+i}l:'}jL!'oqڂ%SiϮESOp' /Gŗ5T܉Hp ڲl38CS:l}m<69+b@CsiV+2ôי깜Rʿ 1ꡉZ먄=!x@/.֍N4hٚyk0Rݷǚʒ~nY0&K!CL4d+A!.R0/MK/ԚιvGAC0siQxpp%KbSqKлbD>..]\"X%#i8x-/SjS~77!)USvB"|*,}C?mTbLnu$韺dY ^6Oܳ%%QE-bGieHkfPɫWdJE:\ek_ }@:+{YT{ՠy:i2iQu9z  Nq"An8GXۏmcsćsoE cLnx`؎>3|~ۀ*`}ݏq0%rm1jKpoeď-y'/)00 3L=Meƅs [〭u6UCxs]#`p4d_/<m졏[D[#6"Tp}|5zq+;II"a#zlHuJF{ʌQĒ .3q O=<3FZ7 5LƯWH|R@.ғmL*$WŚ^{`Б$"ePӞbTz}eyXU*YƃTrU Mʹ S4e 0$U+nd8QJ֕~rGLRfs 3؛ $Z(#Q>QH׉%ׂm5;KѦbi-Y &ʶGvK%mDp,ľMfJtE:azFn2s9z5J'h[7qc-)"Rvcj2LY,B=[dO0[M*!U!]©mmzN!YĽkxAJ4¹HL*:3H\À'9?e"鳍DYr 4*@p/]ÙME|ׁ+8ג-^)\;Su>VM+2êN͓'6mu-: 2h/?4qo݆9s eY-UhT<)CC-!0E2E@@M Lؾ<* *R\^"oUb9C`05(}V5 ރdP 6STuOHvJCxn[]ELF'ĖUʳ8iup[߾}F~Pr Ŭ6VZW\Q{;s\F?s:N&ŋȩ|,iNz]=_R2Ed߯)B đ=x1!bhZ, ^(:PV}}UK*sH"ԞWX^1b8u2p6{PʶVhi tj_x%'J[ZϵŤcFf.ؿ稌Zӓ 4nzq:,ؕ: `'m^`tBF_aܽ7?JZ$ojӕ.5Sg`G\GX^M/n 4M4`O[Dxh"<[LEVfVUˣg=H^YEcgG\!Y|ҲoZ3TŠ ~Eb`^n1#G,16SQ]%bm٪^+ڃsCI0uc"%Hn'ϼZŤӍ39^ St?b[3Vi0▣KՒߚAq^4J2dyzU.j󈓃%d!xH4L YW"i9d<3bh@eCTw<m5聧 uu _{/Ebj?IW * B;^q!j7^Q-o#z,m-ZߖW!iiF4s@؇D(K}f"GiVHDlK|>}ى2(RIphwH ϞTM; ^UAs~(oHG0) _wEwb2y_L=6'h~_7.*wy)E$nJMSKlznW cs\_ZI~DgQp&T3L-^_t?] @VE@~U5kk2 F7M$ FNZ} VIR]o:<).ց RQrRTUTc5eP~lbIR-lxЎ 5"xTƛNSWS&٩kuhշgJs98~ $0x'W>.b5:tPIUE+Jhg) Ѝ8\.@+sI*`O?lm,O`X4;oĞHw̔r>lIXZ/N}ZRgH_PJ-X~m%7u/@3v҈gTW I3 NbYn(mOI"3!ŵ-X~˸td 0dL0膽:jcB#,x?Nf"_w/ Q"A)gmMP j͡n+bD'dVIދhF }~}@XQ Gy4B'S"l\rhpN}d%R֡:ZY@?hYИt\iLXQpD@F׬R0Wt̰$gfOOdS{T}F ^]EXf(7K8`(hK{YF.^љ'6AtXU'3"13}\e+5/OcQ1mqA/]b_79l6vۋ\/(smsB暊@%}o<YPq K*;9jN[ A*(/1^Ej{CyG}$wUw(TخRC?(dwo|=񬊆er{Kw3WDf xĄ?VrR=%Lq2:$QNƝ~QWkb+[?}L̀O)BfR"ӌL-\z,_D$ŠMׯHqв̺7NFI=R^*fpcd=)ߵ9ȯ2X']˜K|y2V+0Ӄ~?J*|*Ŧ&N@6Zc:RXeWezg-}^)]emX|*o+B7Dt%i*w)GĪR*wRȢ훅Gr ò;)c;=@ע3yL|J0POa.QnF '`q̡E4^0oSb4HkFT7UyԓRiW󷿯?_~M+WOȿQḑĠjm!)2Vnp3GԾN %D2Dn"&rf]GU~CZVFr$:.j>_)+^1B"jo})1)I%pV;ܢM6?5~' S1L,v@X22rvoJ{0Ŷhw$eGc[TT!eXX6xqط^M vHK49ix6<1acLfbo|FFS*g֑cGGQxTSzq qѲrl{ \.~SͦgEl 9uܠ/+7g{X\h֪->K`Mm]]gz jO7hu#mK Ђ|K{j.DX<"]t:7 K1DjꞡEűA%muQ?aV "Md/J*_ &mƋST_" #񇛵 X`5rAW<+N#w†ٹϵ<*5Tq] *b=to^+R|B<3Hl(;8ԗ1Xɡ*;Y:c"a>Q*yԆсHWt<(-AI빝G˽Sn2xa4jӺ- M)r-:ޕEb X ![מMMuRB~ؗfa+2.=rjC(QEjBGvmgnOm{jB>7X* lKx`ËK++?wna,y>(TXx\]჊(7ҧ [Ҭ<,ώQIi%ˀ|XD{kO+ A@ۦÉv@9!%́4j9{PTa ]ڪWH%x8x$-ZnwkT:a}Z67RhI%x>8xc<2TZF%ymŚ6uPꉄDuP[uKOغPxޱO{ fZ)u(zQ\҃ 5/%Qr@ نC; $ÝEB UkE^6G\H|WxTxdUNg%^;E%#Yv9C/MCo aX ՜Rq=` qazMn#$ӋpNU3v{ucDH48CGlPw?߿Z 3 >WǽǼ07tOulx/OFBFb1X)T_Ked:0 <ϻV7kd! 5>AڍXbe=v !VxGUblDG jȼ^}%ZUP_DpXx7Ʃ3GK{\nv5^ ) ɹK:)SmJwrC$ 4,n" 9tbKMu qjC]~? =jWJ:Zf!uġZ~kT`2 ݾ%1JCHe{Cn-+Mϝ||e|1-ά"}C-q_befÅȝJѸ憆0I!Βf:Wh}8,^C)=a XG|Ƒe00 UveiXlƙ&j'8-j!VB ]t]YO>Hڡu^&XAoy\D![`=d2=,!;8 /OW ^nPl"W UI#ˎ4idy8YT$~3V(u`%Hr:Wjuu kCdX((K̫Y!-|D(+Yݒ}gME~kZw*AMO{$#{# iw:iwl k3һjK C!4 zǥ+5|]cTt_TTUOhcgrC4E߃]+x8\ L$,Ta9.̅ɩF ay}f0zS6Uw4$u(^Bj囡[ @q3xkZIo.'u'TfTiX0+6Vwff} $($6Yq@S=|g -iC \#mo-h9ȿB BW),ˮ&YzF.@Fx=OoJ # t#"F%ެPO3P;;e<sK6ex7c xc% Wsݬ" &NJ]M F]7r#IZA}K00+MPFd{ͭ[ @fD&(OO}!߳l ~;.suR-v;>ߛYC6W_#F` ~;1̜O-?ɷ!$u~9ow5ߪ_?Fh .튛|q^k]OcH(L [N#$ GZ}OWeyQ?>숡+`Nɟ2u'em܏}?^^Hkot{?Bä^r=X ˛2DЎDC- ɞ+BaP&;nAV%_*GSd}1xQVÐq鉋"0O׶'Ѩ^H!N.;jeJ'se,dz40dUY3 +v_"❥ӧ- @:ŗteG;gۜHp,{KhpN@{CGnhͿ&8R6>W' 6%iln{Yc!]\5Y"/0T"Qgu'-I{ hv2 Xl_d _gx;;^G埢=꿍eJV"Up^%|-0Mxc@q}cܡdA12I2sM$!gxFVC 8h"[~&( J&Zyޅ@!Ɩ/S#ZXJcji3 j ڎf-s #SxO!!?X{t2"(;ɗ{TX2,`1KΙyoי Apݠl Sh2sH(L|xpGƳkswg0}oZғ ]h6pTbK-Nh<̬:v4\O&}ً1pPt]wJuh!49/YvQt'tx gv€a2bP9VC\eᦆ?jx/3bXHfE3Qt>3IR.ȇ7zt%jw:Gz?A+o Z}1I I_yff ⧆?2GlۖY :K3u<4 5p ~!/ó|Q70J?mZYrxFM&$%7]9:D-ZlǏ*೩,>LbZƢ7cxf͔V+| IiɯE0O ?Ϭgai'H[O"v6޷`jM~T#ΌaNK 33v(ZK'*!c߬P!#e݃xZh6!A.u O C̟'_J̝yv&)̺8Wn[?K~3E~oo&C[xݲ5 K(.h*r1m;t2KРif0?|&2m .,'5`(;~G82362mNW Xs'_USnhpI@ۓRr ]%0,N]\-]U ]699mb(FC-V8h|JgI3.-!o\b6J~bT·0C>>nV:t/)k2qnħ`] !a, <V~jliQ ]y9Yُ=ÅX+twMdh{=?톱 ﯠLtheZFze(>GΎ͗<|3ZE z+ oK35WO~֩]!~SJN\k z5dڐl|H0G}R㘈0y6QɏӲH p5(ePBM=_Ȥ6QsEi&gd}2}Redud{ǂbsh ӵPt5M߶6q9$Ax ğ-Xr*񽿈s_1̅zPRRc:`O.8B.쉙9" =X:2ި~1L$|\#J3; ۽ ߊQӾJZaG=zG+*_%g<i?e4-;_;Fo cZeG@=@ "6;K4<9kzA{M%]Ky׊ ޗ*Kn"1_xqQ3m<`օe| BʀO@X 21#t%xítJ|bM&[dAdg_;bINl QNK 8ovR0̆X >)hȩdqRM$d"5 Y%P{dj.-E|\ZGV9ʀʹ3]@% $ɦ}btw:G}9EMYaw>tZ}SAH fByϕz DgL)DIZcBpXU_|fw:} HAd{""dY"(ܘmpBUXł;*E@UMJH2y9'G[ сI\O:Q%{ ܞ7 6U2YJTnFsOLM_`Pܟ7Eo~4#=J iq%R WRUC'dVap}bUW9.m#I3=QdR|AV&=F/-FrbMb _UEbݹ +)BOhJ#ҭ8|xtsp f_:6Ң psi)whM2lu0CfQғ%4#̪?LY?~TΆ2y3 QHʗbj'|IE VGȈugo Fɗ֟k~.$xS˸33vD9*{+L7l(5:Yme/:px͇^8DhF&-Zx]Sڷy@U:d>ueD=LE)rSCg %Sߜ>T7 ]Cmc+.&ŝ>YǗS=g&M%m QIUǒYKM׾ Y\3"NdO``U1)rLj2 ^&kGN]?U0mR>](VL.W74j;Ozp&{'09?%Ny!(3ÙL6lLT,b@tlbT^TɳK>tKhO;1Z~2uߞXM)ey,Ҫ.2Ky0:}al5cv(UJq\-iWbU>2s?iiWmf,J&Xcd"[#XqD@a@ciU*+fgu`}LUcGH9A s}w>u ">=ZKjJ4{kYs/۝yDPi-Kd]''݊\>_! 3(NSVn(f nVD (zMW8j|UՍ\'aEbAh1YE&#a2]kA˫ۢ M!VrCw3Rg ]L/^Kn:}djƁT.pFE4_Y yo(k/At{:]-ujͬM;EbrMFK1A;⬸UUyX)_3K#)nP\vL^dt6:Q f1vp\vy 0K *[@WM0z7V ukefޭf r?ba\1B2T Ptɫ5Wvn\zE}M2Nnd{)!mweh+Ѕ#xvMjq 6R"eXl4D΄2'Iy!|闯,@"'UE+ҥY;YCw3PucΘ?'*6YeNUy;xڐ/äB2A)w8Ɇk}L+J(6_{ xO=eg>4췓jlk5z(2,s̓b)VO\"-8/"'ЌVZ"K)zl9}ˍ&3$~ky_rPr} ;.IU*=$.~dɂDZ|*r;PWIP{-AV~39&=\u2V4'd,(q~|\@zڐrD8CU P@`8O?n(e`4Be^P(^Fv_[5\%^F ,roCm"-BcV7<WҾ5M繍_zWV؊01k=~hX4fJٯL%ʜ#KTTI}5ps-Ya|<G5^d}'ze_;""7$2B~+&k}lq.p ߫lxy.AH-Vi?q ,7<`WV.%u ORKABQ!"bp $pq_X5Ezs)|?L*jȮzkKWDGVD{%nP5-(|80>L.-΂HX"(N q M3hqa %EG1 M0'DO4f *"WL hPTu>Ovԥ8ieJ1fUMs;Β'rn¥%LZVYX6T%EEι_1$_O0ryB0 uB!UzqLUBt΄rlo7DLk4Sܣur<{?@*-sX򟮸 Ҍ* \d?HuK7uƜ\)*_i+`w/FtO,tBbB;@HpMZKlB4߹p.}w'p6d8vXj&b|8eI%^ \['>mr+}j·b;~u %732\(by%țvUŰt-ݒOME+PDԒٻLt8GT1sXxl|"!T@mHff F@+"{#='}dvBo)U?N[fq eO\:QuL\-_B&CƥLF. *|&#Kv>K~pN򓴁e<GOL)XD>L)h|¥t(fh#ram+&</d-yQY)V:&?(/D^MA1NKJIh%ο̠nl6^ *VBblw̐)dtFpI"+9SN>mkҳ^ xhISe<>gj0;7I6yYPfe4O wmsp{XR8Q?e9aF=v˼7FQ]4UMTAɑ)$\?0?= ~ SQA!ɿM{E&a\#O,%ʥ6̊%<.6CaM81 ?p3j-:p8nET~rtN~8>*b8EvF8NȃrdL/nhhUrRO H>d/؍ " e0Q}E }z?jҡ['0MHX̊L?OJh*T#-7BJVKMڶ]_e?2*gИc [L Cv^M oZv~y((L;;\];4)=ApAn-caD[Ct1Eڱv hL F`lR~cXH&1"V)#3I ^J1Q'@Am*,g}?P.JIqfErL'2GĈOe?ؾGqNSr g}y_`EHS>|yeT&1dewUd@?aJҩ& +\yVz8yHMO2bSA0]ߋP~{="-V\ <}L謴qёaɧy$/_fnaŽMV幞znP&!l!;CY)z&? ۏ gpxtc i)oy)E 'r;u9 d#DuʟTř*tum3Ԯ]D}J}\vh3UO˪8;sf#Rb2@7O!;.-/E)[1|+@:Lڜ+8N5̄86;>F uP5n0/%Q7bzcOVbLI׍mQr_TXhVa,#1Njˆ9:óPVeʣlRnc5 a> Lj\vt=ZETfIXO >{aoKI, k3{{ SR#;4l)^&5 oHQ5̳B|W.ԖW$[K¿3OMjJs+L9ݹN^nt|(<,̽uǕ\X@5 ~r~48OkyX"(t;@|),ž\v6T'ǿpQ݄#T٧0yLV3A-4\{+g򲝲Qkb{MJ"eY7+wS'_{+ytk(^9h"ĤG|ݲRVl[?hqH.:+4u uh,gӏAkĂbH{j9 ?\?d d.=0!hy_ϫz,ĥ\tq x CV\$ww${B>'vUC?{ axUJr$ n{҃#ʴka-V _Ji>+f }=ᚍr>Qjy^uM.$~<şp1z_c 0/'}'/^sg!!SrۙYq^SG^1YKz GQmgRU k!!NR$Z&DDsBܜ 9hMÃHdkb/XKFDgj-]G uL3.T@^jx@+~ O.sˎHtJCSr);{Kxt?ЂfNu)]Wi2@Vz?f>xݿ45y_dgy4RdJ_룼zEcWz]w=ʑzqU3%ի'ma _רDaZހ`ϱ]RW QgD r a?CΙ(uH5{ڃ@ΞSa,'yK De`o<a}}^n@EK !Dm>}}`3 VZ" |!Z:=oJه:$AVVrߞ?{ AN CZ$몚-`# =M (-+}|./6OIQV3<=gͅyqݽ%1--fEDqxxٶߍn 8 Ͷx:ng\zԐgl Ox ay0XpcB%cZ0vvcl]E8|o`}j B$U|m) DBs&o 80-Ù'<ͦؿaL{k 9Fk@](\picwP׭SU1".D(hw` "BG%FLb:ݻ Cwvg(]d:y(=>kvoc! êİ7il(-[K'^c< 3 0| yʪ4TޛD]ӴdyT&.w?V"+P/GhKhWJS1TxP^PP;;8LH5* $vRnQAyݝN=+CEͅ+96k9\n?x*wyݻIAb=ﱸzl/W;Al\z&1UNuG1ϳKf5ҿ%Pr/R@g^`<X,>l-vUW~GPL;tJ9]ܤ[^Tv"QR\cj>aRMa|7~֜jހӳZOTҦiV$}<ւR3i>~w'ͥZY{nx *w+u' '_̌6+4 0L(+@tWc2%wB[Mqfn%$҅vݜc r=* 7n50RG#3B}fH{GX LwrdK!2#z轼N gGq|N S]IX֛l(Wtx:( i>ywwv@߭4VsbwǾ*3yA}5wgST 缣ӫY<VqtiVn96y8yy?*aUOQ,V t2XG)禓W3s=%UHJqC$k0o$bVmc3֊Al}`:h~7&:B1,Ҥ5o K"rk+kR,#58kA幚$b*.`B^$ef]_ƎD crz7 w+#粉>nUZG=+'?OSS&6Sgv~ҜבS$E|Vz(&$9g̎2mcf:8&W_S4ygM9>]]0眑p0ŊUFR `1{4+6NV^Ydo. k8n:LWyIa΃]ےcvBm׸QA4OpV7:Xߓ>f%ƗyiwYt+p!o ;kb{jW_]0P?;\V Rų/<+C ay;[`k.򦁰Z;1O k9JgƒP6h8CՔg9Y>#Iߚ4@~әNޑ߶weCקbDNL[ɶ=~GL -VnN$Ӎگ0#lePۘ=eyOj5o{\>8X'#={]ǚ &"a)TDjN/Ⱥ;-ᙨS0f*naUչi V8aldatʧڨAx4Oݑq і~(oS0e4BD+=:N1ߕ oC7ٔ7mGM->enm⑯ e-tˮ~gf/F9򟣶/uc甽Xk1I(TħcEmm'e˿̷ON*IL4`~}nOm">CDCAedx4uzTx]+#M&{_5hnvM\>)3qi^k.#sGܢʯ?}*k=g'\K$̐-s몝3ס~GµpExٮk)ּlu.-y[Δm&AAᲴ$={.l :& ϗ(OsB P+Y!bG|83ҒSL~\Dvڶd8'_I\O BYoD"giB*<|\ȆsΌܘ 44qrD󑗛5fI(%287~pC2b˨<)IgIH\6,Jݝmŋ X~Q'6TafN1?M Z噊!Ed97fw4f/_+[Y&|d5'i)6f:?rKN*bj0,Î~`c:Ck9`3IosۄKza;|>fEdd"e+>5ٛHq +ɒwvjZ+lSUOzU_y %+p%eQMpg Zn&y7ۉ7]F\u[mmRmKdmjYϾ dTXyܫ֏M G:rܱGV,١|tȜ/)be8#7c\k`i`˲* 7!Im9sq }WRD7g9m3,]YǰL{lظPr]@ ~fS=D]\!CixöI-NMW!_f: 3]gD, eh`oUw@CWg e\}dۑc6\TL`#)R+BM4I.,,9^s E8-h m fq3up*rwtGpL;Zm?=VXH[XBp6MoC Fko/dΫ'3=@ ?[B'cjZ߾٨'^ ?"wjgl Hw#eN7Fy{hhU{fGx"+@1q|LN'!Mӫ%sr};$B! -K|[Ijkjnў Q\Oa&%dZYa Az>S1fSk+ξp)DTF,/EZhʥ/ #$Khz4A}օ$ħۣ6O">k/9 Q}%RV qY` l(w>,q QH2_ @Vr ŘB` I>uhTʆ7r``Ujښ=Z#ȗN҄?zEbK9mOz,DJ 33n== 5ÙYI;m=}2X_FQ+!*H0%=簟Qw=`6).!j#r #T;dHdZ†fk-7BrǍ["exgIfpK(Q8Q9Dj; j0s [G]l +huoVA5`I'+!98`̯w6]h1F8\|*$ Ud vEC4nPƋ <äU"h_Ab7)1\}t7bȊ""+F:oo1f^ p=nǻ`c=wE#S#QA1k 5dB~I*j49vKD_!Ro -Tf~)=Xn1V!X>2?4) hBFMJXL '̝4=8H$g֡4X_1~ɳg`צ0u L\2vQFBmUOz!Ct3HiE.ʜHQd#Hyb&6|㗪SP*`>M|IYHq.L9i]ou7$)Re 13UQ˒lHWU1(שzqIߤј[&$SdcQX"NJҌt_v(_9kH: wO%Cfpcu#MTziz<=p")TO[۶xHj~E`[nnl^bt3b3z~ egJ/=J/ sO.8&?I1{H YE wGXb_H¢)fa&OO貑4l;dg#O?"4 DFS^NC>~Ƌ!UD}W_njf1|?ZaJrMxu>)5uEܵ$!5H;44Y׏f裧&孜y|IAmKO!ko<\H刪+ ;Wx86^ᣍ9V{v,V:}A$aCa3U_#,[USKkp!})\S^ޏ*w \f*poȃꌹ\u bCaR_!]EfEJ'CD?qKr'ݷtA?(i~?B> e46dsݔ՘+_5 g}Spdj h;N͗Έctd"B1/Y{,&T qTfKR6,eZTf*nnVA<9;iߜ1c.h?yY/'k}OJN]Uխw, *U9=`T;k z1Q;ԟdS-:LoRvCuLs/R hu~;%)5y^uᡵL ˾XhNͅelc] G56tA= S'qZ P ٘PF|6ww,rPeTŽ"u:/),2M4ɖk,_(3z\mKSLԣk2ƜC,tѕ x]s+O".^2F;SJNe -3h'SW|%x x_3Ʊ]tjiϷx R-V)=оǵLS1CGS#1`"V@,"B76 Ir@C\_AP5Ŏyù؈qQ~PG=BZo"_?ԯ:H 1>gu>%! "KQ( CzJ}u,)0AZa̐VR̷9ѵ >6H=\kkU U&K@6œa;X}커xى6Vki=<,4e$#:7a6fڊ\Q dJ zA~`r̭]֘ry7׆[\%- !.CtQуh)41d_eIWr"' 3HL\nPz/ L!6آbY'R)! b\SH R1,P0C>Xpq3143d͞$җM1NuM4r Hd~`H '\mivH9rchclXHJխۛeyv[c.ƟؿC\D]5\(v)M$ySo s>D(9*'5𶖆+ZUdf7 E E4:&Ƌ(媭 %r~o[BV%hTŦLF%ƹz>!jx_n yCSߗ@|o:?=|p z;=my4_3{ai,eam;:>aqW/#A=3a0jTrqD ZsBQGݹ%_*tgi$[A _.d{ou^>i8Ţ,fVD[;!g/Y'R,zD`)Yu72:Bnj4Q`xd4?D!T0%Qx"E4BcټSd)k5njJb&2zs2꾜YDJj;nQLɷ(Uԫ;ims| 8,Kr> 83iB ;DNt !+MD%*dӌ0)\hg̱xg~" jw ݂Y z:̒oKl˱EY!7aǰs>É:vǤ"ӱj[-h%=Ӟ1c&zmX.?sלb*[OOegS6昆Gzˤ ;Vt!67i:ɭ$L'mim5@Ea)UzYS%#Y50{-#^BH/F}f:fmYN Y/nUmc 3~1jTu~18>#=2 ?xh "!Dpnʿ<ݴRm=1әZ%}(kuXneU&VnP~'`MU}]MAeҜ~[щö!,c $~Fi/'1 oަ$)eb38y ?k{e4'c駢ڿN'BX.ryC:.v-<0rSf-Q,'LmkCwMɒ)rvS3 S𳹶{K kpfzCZY:WiƙaPu&ܛO9d)},h]F_iG@TYJF$$k$zɕj>ߍ͖D;1ªtF=[&&3~DeU(`H# 2῏`/&C.-JoL(>RO6~FYl Vm3o;5 @>֗'zAVⴖNֻh@˩bov1a__-bmr,2[F}+@q)QJv~] 03&1ƘխV9߇l:<@L7',;C0E/kr&;ٙKf3_*p00*egsµnm3Iҕ=9[1KmY7̇o sT] XI<)j&AvQP% sD1uBLE=dehqj4J#By_Ԭl o)G O&4ǾrD4T*.hx3jRKΗ{*Bʋi8 &-vI<8.⚸2 _he9V:ovcy؋Pi5iDnjf#G>6T2gw`͓xմ. c; =?_f5PSƃ7#W&q4ߋ٧$5F%ھV 8PmNVPCPkg0xҦRuF97ωzAl$aB7MT1Db=w('oCd<$-x1 S0V“FD}o*,76˭ƶipgё4箞pY閉J*eA6Jb}Wf1AboOv֏.m_XOL=@k |r3{(} `Q77#T]b*A]$މ1o݊yÝh_?Q'wLbpl'xjlF)0+Txܐ{.;_Dԅ;+A|;+۟8C}/T)`A ʭ[9+n,g/N\uynGNuz@*Ӟ?[޻J+se06y3+d]_ՠ& [+\EH4<%.j}ͮ|r̨Nw:RZl Ng.e>L.#wh²fF}8p.6w[5;sa:a8}Y n)9x%k(2l(6r-xF˯i~i#Mvs4Ayftv-g$:nՠ:jyu]Q#1u5L`V<:Hӛ:C/3ӡ*[Ʋ2{NRA`,"ְ [Hiw('yG&fS\]`gɽ|&Ʊ;g:'\hmϨ=+m(r)^8/M+ {[2ET7FdfZ G2DZD*IneRb[!3]>ΈK3*$ _xz`/S*CxZ1̓ը?yHyhhZYKTTJHlTkqbͻ~*}m$e|n~6xk"͗ރ%&2|PhC:Ii]sUPoni,mv6K AOfj1<嚾||I^'xt3#!T=`b+F&gf"Ag5_ɯ\ ?uQ5,x'/2kf)%YH_ DA+c͏Yj^]ЍtG^LyrYO(:Cok6ўC!g$'+UʢzwԢO~5ӪkB;"&"Ư( '9j$<4&ߖAF%AέoV(ـ1OOY<ΩGyEːdRF߭o,-(#IYRc4TR[FNg8 c.ZN{/F辎GQLRۉ3d25*DOR/>rvn1ąvHp AjRQeea@k\.ME\z*8j^ge< e*)ÃJIjN!軎[%lzq;S}!{+` *95~۠1 vZbQuz.Pn˄=l+Zڲ rhɭɏx2a}, ܇B|{:^ݿUv~UatCluvq-; 4#< 3514 v?ϋce(̗6b_rl@6ex>_Ɯ^Q-^"7 8 0xN-س|,&m-bW,p@Jd`iep pɾ*vYb>ߦ! ;EON~泱SrL)Y w[Hs `;<G}M=0h:;vaE?i<}(Sܗd iC2T{$ga~1ЈCk*`xU0$ۛEYّ<͠[bb4S1F@_3yKhGzDoJ%I[6<?pleHJƭY؄'1篭>P$g6!!&5å2٠3~(ا%C: tB53 mć) o3KQ#|0]AԦ[J !=ĠvNlh mq.R e>2Ʀ +?8%dSb=a钓!{'9³N~<>>ۚ^#1h]Eax!qdvOPf症-/';Zh!>rI M:w+PyTĘ`CM֒09< b?y dVY>![6__WY VE6~y96j<~|(cmV?f/R$K2lQ fD(@q#"FʵM'-hty#J$N0dwGEu D_>&$ ,5ltXf&A%CMŞA3';5:$%b/d/}=cܚρ㌱80!UZnuYȃs:+FʘaM 1d6)c¸.t˨&V0;4Y[Qqa"9r }$z ض"Oە.|D` Gqy?K." s xtICTLM<,:CL|xں#2116f+M=5ilArNO#i:A$7S?:/6%&K%l}HU`pE-'Qp>*L3wD=x%oŏ"Խ d"-Hm;L 0n?6@L(0JEn?{.+ʧ&p3A ycGuFo6Dx{20Y~&nWƄ n>=~|K7O,Z]*RR(ɕ/lOCV[0\29։Pq=&E-[7J7>=\8HnÆݜݡGRZ80MIYgîM Di637qM|KZgV OZFzō3w( ۑIͦLw(.c?p&W:;ʻ]GH 5-8TLÖ\M:vBSkMReS: Owuv$VBg^DweokaR\pOM`W\u;Y_ۙx.bDkz?vCx<+|t4S Ệau7y*??Lsw}90Y5voץ'ړu ?4C;:EӧaFp}W1ZG?t\n!o'Ve9vڈZY2雛Sz{&xByhiE P/Z4œV}x} ҲmwZJ(V5=&ԑuuS%o% "kM97N-ѧ݉;M5O~<wG}ֹᬶvmYr q,/wͣ5828=~ǮV':],lfpj?F*a@du|͞>ʆ~#ݎ-yj@OI$bVL9 QuRiZy=w%+1:+s'[_tL3p=&a7"ƒ@lJi_DCںM+:|N]!謀޻1eW~AùA߷K򿣫pv7^ꕯȓZ DˋدZd>T_-lJ}nfjٜkbxdBZgM5[R7n]񫞵.X} z&#l/L|1V<_,(v:{gvWBᎡ0hk0a }Ѷ's;=:PP1v" a^#XU•"`g`K;Q6X{WoS|DSY?N;EQe%zkD9>ogMg6VoOx)'.LEa%[\ WC']8薽::e'&(5'ZM.HiR%lwRƯvv鬚pn0t6u xF<Ea{v{ߜ4D_ٺ!r ̍'u+N}#Ȼ}Y /9k@sܓJ0w,K'9cFT] 3A0}Ldz0B[nȫ;?# pbwƠ ⳸]uD׈_?;"c. 𯷧> bFWuf4.1g+tldOGw}_1[~!A[q Rɑr-}]iτefʃϴ_;O&Dt`HD~$dF]f nBM8U,SEq$ɘ)^ ®ȇ}: `qCֱ{qI^1q[^7f [[]Eab_Q~-\Fe HŃrL ^OW8gF7FL#%,8] :k`^k:]^]}sua.5 ]AC%:[-6.:hm6O^-8X PyYa74^=`>Q(Y賔|ڏP%OQERz)7;_櫩$۾PwjVEW<RJ0o_ݾ9q>!J;d?y XO(.@HA6Ծ2"0w> U/ƊyJ} (#{aQ '1CQ¼›%4X?@3\0knO1}J`^'ꆦ 7z BT{Vt{Wcd<޼mr͍% nS@It( k+DTgTD3Z[= }}ŗt7ŽDLҽʎ7r-_a)ƴm9ab59zc+fH?aS ?z J#}J|6rsx&UU8.EA`y3} 6 u%Z v*;0/5܉`T ]Zrsa;VzKZو8v=pH&Pߣ͟N8W!ݴ.. *e,e^/ώfYWw$BGBn/L+'?@ۭ)el£vK_{Y9Z# l^~o~ lj{Zn[18kbf ij!pz)gLg{B!&hú˝ziR6f4c9K m鸨:Rsl޴)w4)Sn,'NgCjbMnp!̨Mgw-ΩD(ڦ=G'ɔ/'NA µٗ{5#AՖYycβE/e00-7Rh\x&[[="VX 3²TRh"F}l!ɿJ" =~ 7\[}YBR~kf}oTft s8c ֚D#}m>;v[B׳:+^ՕBP^aW糓fݘP/>|1ˢ{U1ZXEpݝ!f, _/ӃQVaYST;(x@N76ixSVpQ|#_' ::)X@T6ey$b>dWÿ_QĀ(U %{*XiDi!`! @{gٵLQa@3ՈS0ZZTtw'{_$Pzfȿ@4#nO"c)Ndm luӘ |+M#=_%mqs&Gr{ҁqA%N2rcBdb !obf a9i ׁRM{\ .>N6waǁdn]>wzg6!56Fw+W19y1M:(NġC5 x]U.%` nVL{} Fnv?+ }*}Hc[#pR[kT R+yQ=1n|W*yqnMSXf%|FXd<ɮNDfT]rZ?jWGDZO$ o6UV[. |q@ӗP_'v)4';h1$xWT >x^]co$|dj;ݜQ Oo-? #UgL=F5K#c  ` kV; t wrLpͅB\Gwe6!J?{ZՔ zI? @~l&l?{\+<α^!X/$nC zG1Êa*^TΙ`b&tdNRO(漒X]{5 U.H^$뉽u|9REWC!ΐٻfn.DA[]R=_mU>.{<@NJ<#, _Z3m˽ϟp`!!V:_ΘwBI*@M7Tݞ+vMѿ‰킐UT#ĒB!d>P6[& l4 hďvNJDٮLvgl{qgXi:h]7,\zz~:r -WH!'(" I7 NJ@W&}]ד=.ī>s^2}]S=c\4_m HH3ևOo^Av^ ak固rU6A c! 0Z_G: =z&ܝxۼ?A==1NZzÍ5y<}=%B@ЖJ^ ![!# +TvE*Bx"Cŝ;%7U !l'V$Yeq%Vmahnk'ǼIg`T :.9y¨İ`CGp/_* w<,®,_P? \?M^짭#%< eIo?A PۍLs+ȮeGBbag%wI˰0U4܀AjNfz~/$L$ q`İ{(gg36Q߈?.J(9]n }@ XxRɻnUo:LmA+seTn:69O/W {/Zk:C|g4/d I-: S#  ʏJqcn$7ܫKϋϽ@s%nl* dDxKcwqGR\ Xش‘ZML*Κ5vXs yMRU՜O=GΜ[ v<_a؞}_5V$ѹ`٭i[0(|hY't\k :- jF9gk` κ$z*Q9l1 I{{`{/?0gz`(L?sUW$F_e G"Jn-6XWmVSԛ? 1̱sVc7OaP6C9L\Xe/͋;jګ f:@Ev 9rù'h{O:0+pMx[a*`sĠiAEUqg<:{_`Blݷ-Ɉ;i?6{,&zr]%H#\>l)ZI=c?d]XD7m~1nT7u_0,ŧ0PPgz[}z> 5DvIg:?]4,}e\- 2?6Gܚ9wcr 5ͬ_zc^?Ϋd2JݱV90:[ս{)tĠƤJ1i)4!,O.cu3?qe9>F3nŽdjzaoV_2_LpSŸS廐qd"qJ _&*DO<-Ҝ26.J+I P-q,u@2rC94@]=?߳\Es]M-Mj?MVTma M1GetO߮;Kn[WwGFZa|5&Gh}Ӎ+WJ- N ܎ (|+aô\R01$*:‘O>uA!lw5.ٗ=f-v}a:1:S+_*azjDRм/YY MXx>mYl}ٔՌ8 X%rwQ%e$K\}NQ%~j˭gx"`0SD>3`<ܙEFg&8 KT#C`-ﴡ2$2X [av0TKms @q 9ve1xռOXjUÑJqإN5~)yܙFzcg> ~7!˨=In31?b6H7a9USa4zS}fU'Υ`V()};+E|Bz\;!0Ϛq7}Psӱ'Ai)C ު\[ĹVǭ^e0 AM, >=g?׭-c!w,eU?&m6H:"'R<ш )TlMN7P漺(lj۹)ҩ\{zh 7BƊCede"CxLl!1[hvm\G*|S X(暼?]"V1ӺFdH >-T3G]лǔ싨rLq.^PX|7.Ma8 誻d F}Mõsk-QHY-RXN,G4BJ)K䗲NB_L3b >&eTTu^fuqjq(. ۹fT4!iر 37o\.,arr#.*ul'FiZH@"(0?Fj1 @,Oٮti!+2 ΰf6M穹GOT2x0n+誻@uf j`.gգz*&ё8X(>,N[DATU!@U}I2l2:8`{i /(T T 9UߟǪSV\~DL3l{)2&^qozb"5le 5Mq,ъ90'1Q@b i<5=ORK=F ϗ+ʠ؅ɚ>+X' KZM{ dgt@Bwi06q3%%@ RK9(eWcgHBm9H?\enQ8it:(`i){x JivlYVGY#zFgE5u˭*'&"DNBӌ3n^buV2FL:P< ;4$9_XTOu1NW20X!VbilF*7#:-IhWM\YWJgaaW7Bɤj|DGx("yTyOV0J޶n,n:Բ`PωcH+gz 4A$q7ULjE{4iL]sۊfzqЁ ƒ![|^T4=yqX`AjNIFlGơw%ٷ`巏T>ٸ8\?U V7 ƠywQf,I[T&5"#_j&̣N4q3#qmt۶M!,͵ExLp܏l=9˛j ,HP =9mY W?CK5B^ r_UOGLBJ,wGQB)*wHPU803O) s27" '< A~ Wߵ2+eP:S^ųb1}uCHRr-.X<}]q% k1 f骫#4ĝ` 6dLs9Ǻ?|bHg[uMӶ;C;Y;;m;m۶m۶m۶ݱgvܙT}_tNӝTMpzHlĠGiJQh/b̟wDߌ&>Yӊ3%˄= L2"C+-v\^nB-@W4H:tiݲj^ԉL Ўj +P!כɻ"S0Q$m7T70L78p{~ydJaՊ2+]JV}lCE}~#K;#cy\t٢`ESȘ5$NLr%Sc 9uyLG63h59S<=QU*߳[TqPQ F8Zr9b 1غlx_sb7N]9rUe KNWZ/88lOE ;9oz ci{eV<\LHDL 5׀]dxW *9WkƾCfpA%}#6\i-obLeB%'^i {wa05]1M )a!R$U!Peu6 giCd!Ŷ/Q\B7VxvY}n#EJ?G0j8LcԺ aci !l79ۆV/47GvrH<( F)h}lc}' X:( m J*&/L޵u=2Mҩi&'zOc0T(.b ̪s̥TAx 0l%\=!V Ae><`,MqR`bx؞ ȺG(pHⅨ=pnoikCQnw q11ƺG>6K $Lq©7ԮZ3$abcjB+kD@ R'ȅ^g,L| T>ja$V#͔raj­@&*Ubpux"lk9VI𐁤?e*njpjEפd%IC;_>/Yt@`Ŷ,S uVe=2*ܪ 's%AMU^%0 = 鴉DqArE OU*D$ˮ]:tA Ä31S HNxAthwJ /Qrv7*]O8+2M|5͝zM ?!)bD$C@+ zы+IRVPr 9gf# -2T  iKhbC0@oQ̈́6iuʥ$CxCKTXGtfYЀ6'ךjm[6c+/IY=Zm\o'9ۚ")q-ډÅְqA/˫L''ELԄZMiXmJoK'-/Q\J ʋxi@T#Tyb\0XY do^]A^S36nSjTGQME}&҉R&uSaAIܬIW}ɒ{YAjg-nI%Bn`_ Ǧ"`Fr$ު*$M\TRR~_<)}I*YEx'_P5ށYYuUL".h몸MkSۦSMZI2So%85Jp5,VM-Vq\aYu|I . ɮ9\_(Rۇ$5B k4aM\s0=n%xG|(Ԩ+@cӣȶJ$ = "qKmX0+~PKſk 6C%VWś$PK\wnz#dM7QECe3Ɛ~9Ĭ1y&F|4M"[EJZk,+~/W}Kn'&]T#5~LuW}چ{hJFl*r @`m$Ɖƕ@9Z(\F)QaԄbmNCRK' !XV]i/ď>elTc"mK96D3)'c HBݦ-_S6gKJ?ht8]^JL0!R#S\vԡ tA5M_0;"^J-,@ qN1U݇T*\0WSD[9Az6@IB|&a%R"b10):D?~²6ĊȪ55HWQ ru]Sn}@ [mC;,3%'iTT`D7FB*eS.D'DYr?@+<cLtG _91QTE{D#F\СuTsI(heMso"4ʉ t΂U3m8Ƣs^set&jyk|3emd H.#*TQmBЀ&Kc ĈPQ9QFe- $Jg*$LV*LyIP=4pR:YT!~{J( LemQMR0EF\DzCIYekeNT4|#4DlQ^.-!Y3KLļLְ{'bV@&"Ɖ63;r\z(Rd"K/D.- AΉ QA{ 1iDJh=D9A^4X9Z.ITBm> MujJTK:v- tREb+aFүN:X P*Fa.ev(P,ke1^+`_-zhco`J]0θJPQ>&\UUO¼ɾ 9!n_뿮݃|?"yR/v;%?(^n_N<>o-O~]}!?~|!~]ݵ^/(+n(XZVz)"ǞLx"*Dr0{+^: [3^f rE0ڡ5ĜodPjaC7)BtZ6jK0rᐌ; pY9~+-p!Ƭ n<8[ĬRo3{|QTAZ RRhFx|m2Jc;0ܒx`տ/_^au+rF EN3L5H&g{|"g;0aO l[6cSQ5Yg7oS##蚬kT3/zN=[n2YAlPɹYpiM6$|zVs'S\Aؠ@6eɝDpNf@"Fo}iwV'eDijxH:ԟ4֤Fj"UHmBWCN uHF%vd8I<.Z֛R֣p59uw):W 4b \=U!cipn ބXC_COp !xm,nLhH\m\y't/u]A  2wEؿGNfN;H 'Pl(#HIi>{h8Q^<;'\v16Ae$ey`Gۻ3 [FI!":+Q`8+\C9X_2au@lO`)t"_r֟0o8RmWepbgy+8o$VIFZ!\Vr{}U1}*JЎ뀸d]?_H 7t "Rotjv&8?v0Bw&x|lV@o?#K_ayH#0Z=owޏ&ː~jI|>TKE} MwB GTw>2:3su数2_%sLu]ZZ/+.*Nwc؟Um+[Y.Ί:YH@;C[YKԂ<9WuyTw:@ CKkMs,害*P#%F>~_3ȰliwSNW/(k]ߌmͧj^n;mWL}*ns5nWWN_Cy>(x|:4`flV>Pend="{Zga+^`EwIXs!E㿩 E t֧1RQ7r7=B}6M5=v/6'F.UzTJj::dߛ6w+Cҫ;|3ȺojognuaJch0(7:,+1}ʛw._]Pgſt?bEd /ɹ6n\?WR<Ք{$D29.ԡjUu.#O ύ5lJK;ZW~VG)LBnWC!\2>Y]TIc؄o=U]5:?uyC:`!a\HyS/le>4w}8bI XvEm)yK}+qW|&\grl*2%mdSjvu&󄏳]= 9+~hiԼGՍyzT{RXZZA5pfGT/݀nهSoOB; OK®m>XZ6RG _]I Ӑ}/kWRwG+_&b,Axӯy0F_LDJ6^_= (sQ4"gm8.vP1VBŠ ss>DG-s jˣ$ bn#H^;#(.<iN* bV6#!)</K! "}k!!;Āީ''-P w&iEbn. X57]֮|!Ɗ.l&("il4\H)K.WXۀHX`|g ]$ kVȫU.crpBMg9yNg'm*4EU"kkZ&t1bjX];f~y?׺lO9)c yE)ܐ .w[8n @[)^.~*; W*W|'`h9]a/VϮ`faXOB8cx#N#'Bwb8c^m W4f1("X&S ޏ Ho2xj#&* P6UcbS6/Ic-5iʐ hr:TE3F@,-#"40NE|,(Mtc2gkDGU eCHh8B83DФu))l<T99VX|$+Ð<+3],T v$F 6B&A)UA9VOwVOX!T mu|Mx<"T,DD yQ˨ "NwK;g)'`Hʲܧ7 WC|My\E!@t hFLoX FH<1yǨRuoTT$&<8(z 7V e6MNDF> \&N7k 2@#5V[ǪԁEI,I 񧬜Anq6H%)lSrp2,cP~ ӟ#֨7;D`YYm05I oLB⯨dsW+R[6pѕoqS1DUέ" сY4 ½'uuAjD܈zyA :\ #ף wJcS'Sze]^,)Uk!j1(WK؄#Umƅ%q8/>'fܰ(c2d]=yXHKYX~3Ox=B-BL" VgDUg4{?5Z#y=vc;#(+ 4B-R;au)c1?06Y{rfTz nd[;1p> Kـa8/KZw<]ĵ@~y"97GlI{}ncO۠ΠU?<ǬGCs9A6;: 'r%Z;ig1 NN3pëN;Vs QCްo|`3CaulA |uݤ]U o)6gBL[Y( uN6,8B/@m8{Y\uD,stUYpX30#a2#2 WQN!B41dLy #@Ψ)GeL="[O8Ug˴La9)OGժpZVF<+r$/ x.-uPQ:"+#"I:}DueiMQy_UssJ̡J8d/&> bt,>Iϑ<^ Ga@DU _*ұ=w˲Ю k.J%#^L.!%+^ c}Ȃtřȫ e7^uE]pH~Q3N?L+ :ҩ^'۰y -"~ R/p6_gG:?]k'wm`"SF3]sp})DSFvAAi;Bl-krX_7+]9`O;A}E#{ !u}_8>CYE1ZRJXrԙ`ƌXaVwu'J‰zRv"1tkUnvn1{*ʎܵq_.` 3IgAGfnin#s#&$`abl5 SbUߊ;d:lFZs3"=#΃WkM[=6WnboF|[`-.IZY0^|8cS.\ P!xs#`~MXr2Fcd 2XR%ik*`@$tP`vԑ O8f*Klsd_0EkOwH qۡD~R$EKɩʚ+bL5Hv~;5kD2!F>"b =;+-e8aD]}|$bRqCtg@AW ?w'y M.GҘkb#U4 ٬uhV@C{l;HϤE5r+PP;  ;v5 ĝ>9g l.`:mޡE J10ԕp+Whg.Fg kT( bQG+!GXqdʝJ`~8F)?.iprϬ0-9,8=L NgwyqTFk8@܂͡p" nQU"&+Onf>S)UyE .x:Yڑ`މw)sn&ԡ|zcUnW[@J u!K_eV14Xbtj?/oV$1N.>D.,hPG+6ٝ8qW| M^*^&DkXzA|\IK|s]9h Yˬ'a`Nc%9Л{@C7]cS2w dybFx#B3#[™eJodSDХٻ6ĞHxWwvY7K.pl 4pMm-dPpTXGq ^z?{ [ܘDGL3۲]5N_Bcci .̗y "Sdz)3ZhlNʣ@T('{OR=h!QuZ'qPgt 7I1$+{+^撯O18<ߴ$ h( $fJp;9u GH$vpE,ٕS7UyXpq*# TŚ^TZPɶ!zMG.W ڀ.Eo)3q^޼mk/Texwkvq5Umh{X: ?^U 1K,~8桸H3TL=*mqIxp|+P5IPg^Mŵz",gŵhq7%g>3@R.ݥk{Aȳ?sf1X["9D 'M^qVᜡƧg#> /27:%vq# f:W~myX0 : ud(Q9UHوK2I?5 G}ƣ|2C< . #q*/ EL/y mPTx2;&kh{TgDih ڈ y0fa{[2W{ p&]7n6CU/JڂLo .5q;T*{(Ap5I r}+{o&[h3nQչ"#Xԭ;wlK7 MjS C s1Vg3 ve2rs2i|^,BIH,e?*I19(sU +31It62o |`Q3τ Zv`dɡT<$(Dފ?MXL-$W؟9#2V?U+=4>!~z[f/£ f.&d/R`QkN(gfA/"uւĩLgsBI]KI޻j,ȍCJGG9*dRhD"1'C9&םr0_DA1*fQP6` 0`ckzKOb:_LC3loOJ Uv<O< HaJYjR,uE4(4rR^7`eXO?E\`vϜz%Tٓޮrnd,n I!k^Ȁ-,5DK ! OZUΦyB8 6$e2`>ʗ?Ma3 <߲q䜯LPgdtK q#<\116?ܷ_A'jbPňz6 -q=e|PZڴ9(J1݌"vnxL7&<;̯ sTs| fڠ{%"={1~1zMҦdvbѳ zbgNYCm%u4 [6 !_KGP/ޮlpFc"`\l<lBVp* M 5%Abt&'*9`J4$NJOdOf"a=ߟQ>MD'LlLQ=O]8 NbcB=5Bn`P%UYbb*V%E2B' (0i6o=3|N6_!Cyh\St uPx,hzEGěnKxRI4ІWvN,: qȒYߡڪ K60#-^ҁiJ-[ (B),lJЖ@bL"Ԣ+WAL1؀υ#NbJ;cҖ3Q=Zb昳+l-D/P.sJ-8c#nҬ{$!Z7 $&tj{G?>ٿFy{c [D @S.d2I&Ȋ=-uQ"tSzRzByHA?vN%)I ʐO? **\fq){tDxNWo%L%I6wP !??8uz A=-Iss4b,5|ndNd }mto}Ya{qQY+69xN'MSI>~jл2|2}Ua!kT!^QUb/ 4Ӭ>{<~¯;/\[Y}.CĺR&c]^BԯZY ؄!`_w.bW@ʟ4lٯz30q~s~K>eT67{XۊHg 1Z Ap`MoJff̹rm nE.ڈDG`ۉK\C.ᰚs5uB֬ I(}Gwg (ۋ=}%D-Ѧd=d^)OnLmNHrj~5K'> wjC%~ZSYg^Bh4['wXnUb_~bnϮ{-& FDmQQLl=Ӱ`@YՇ3oo􇗤8<[rxWExTͩ,6a q-NXÏiL]P[\7d#+1Xp!ԳQt\=|\x{ae[f<6dr~]a(fFgE^ 1a)1ql;Z3@zU0$-L)5Yc>ACEcn*b_@ȔshkBI_'˹TH,|O!-NJmt<ג f4n&kG1P>_/R4Ε-BdG2٥Ԉ\"(x z]*~*[PrK } S)H:;j@맟*@j*Ðpe#ƾP BM-J$j%M9D歊3FꃘaeF 9oOXǤ>jH8[^,i~R>6)'bxe'0j`"T.,0d8peWy;RV@BˡۍYfv=#!6vU:P_E=Ԧ LUt]y;bQX؋#NZnԫj޺3hr*n8uMhҬ4Fu;~Dpv;L& 8(6nU#P; S L[1 r`@q_Z i7M)t4ͥhWjUfvs oJI\;f=>05>^s(+:qhL_^xe?^˭sxa^Ŧ"GSRBg$ f-"B=)o(uy2XLLLpHaG.9?2eՒ7R`GjVPfhdt!J #5nU, M[!7AIнs lnS g  Fu\61BF3Ūw->Ԓ/t+ 'nh Ԃv{Tj9 0a[,e1HB aڣ._emW\\Ƨ;QҽPc:O{b/mYD$cI%ֻ XuD)j l5!(gD 8ga WB-ނ̟HaLqUP*ʖk|T20L!Ҟ5#=>L_HKe01hG6qs):&MKv Jg1QbN풒؈\`KԖz&+ikӐ>cp?`-1\+բp=W|5ͥR4'I0C QA7n'RBI q%=f}xџIvy!\iO U^'e93>UMz:½Ҋ]`m vǺt[bM&CDlK@Ϲ`I 拡g,PjG<0 09\H 1𾊃,4%*~& _MEjUjhaF>?[d{׽>1`FW\.@/P`8 ;`TtIB=0.J ݹݾQ!6Y7NͩitQ2rIÃvxOrh@]c/!0Lm-eFAi=LJX 5x(`c2\Jl1PETi[4WAOg;%w ] yOR1;汬L7 (d/Kr+@.NXI{yPK}O|0<Bmr|ךC<䛛\LwT6~j uDW^БNz2d UPjMFB" M7z;5?|ywvPZ w1:LO T*y!|ndI^d ΃0β>&ϸŗ8C93щ5} ir~"pT`"1lMS2d'#5V4BZ3'bg ts=`$&70kp&pǀ .VTƚKG'0PVbF=>i5} RVt E>ڃ$B0h'n4#<^ANGê&3{iޅ CFSI0CE/ɳF*:: 7E=M3g1Tt횫?gdC6n@j.vbHfC$he,F{IUCYfJB&"Tk1).ćIpjϢ%Bɜ%y3jb֡<}[$,f9Ճi&R^grQ}vBȴTL+l'li~zQG?P9VW\?ē|]jw9W؇MU_;CBb1&zh ʩ&7,:%r:/_6h>5ebT*SuʛvU{)=\_qbsB C'rG%4 U6АZvnj"#CTK%@A8sVOxiUG2VYi^ƅ|\gf 8l>}gH-Q@<ƪ 4/ޠ $kTab- 6`Ъ+4u'˨| yv񖄗y' G`p\śE((cd+Y IZMsE|(H:g*mA ƭZx9U"#{q}t]&ʦTˊ8's]i/6ζyL*q1M5.t&{|Vcƨd "=љkUY@Ue<ڴ ҵo[ υ)_dN$166OxlFUD, K;˄6;)S>s_#x2$';-W2(e#,5VE'89{xm'2v}d]ʍkƋZ G7̝]mc rm"0OnκRDoa%6o<}Y98ԙ꼢ip @YWix6r՜&4. y$@zj<`佁cXp"!_B-|M^i;! X9;xدZE.;]R籜y;>vdc`R ZgUQ-Hu8̲IA4pT+2f&R ^c<r*$V]#ɩp𠲩*ӱtAs,6 !:ԊB@bRVN'NWA=W#><.i%}O^snx0]ld%LߴuFԸKޕ/4= r Ϊn1)n4}&CU.SgBa^Er BtՌTyJݥʫ6!/ FqEu+˫k<# =ARVxZgok"i_1PYG!RGF!<[&u])h|mjtc=5 CFQtþ~rL NȒmY lkX )yŽ>,]^ ”HlEթS]rbqqJr/J^wN̜(fD;\CO[`g) %b^,|9K[cVWE̶={]j$OU PM^}VVu'V2冷ˆ̉F9sϽj+C"ƈB5 Ոf=:8*W@'sKuV{!JͅE)ʲ ?,El{禬 +aVN`"ozlJ t%%iByZR [`E4NfFz]5Ø/\In22 ~ulsCc-'\_p>?F?_3_?Ij>ڿ.?y>_ k??ۿnNdHď)S~H'+jvUq(6ˈNJuK*.$W0^/O։=4è ҅OmC3}ҿT_݂c#<i_?8i·Fs>:dҎuw5@K؞28$A /6GeD9#M{e"=f@U8`/K6C객6A|x >'q q3,n]íoRa퀖sMjTtKf}94\"wEI9px"} Aa4pVV، 5A p;UN{(}TƑMx2MX*(H}sݠx^I63 '6m(V>%qHi1j 6[VW&Iz?#E6GeivQUl6j)%P#:ju[[)_UvG%/:4P zupo%{hؑ!Y6KIyyãIHȹBmA˜GTʗ6Hڗ#z .AV q6K$s#r'ApUL3LƐtGĴP| Ls#n]}ZtTͣƑ-ôoB, #˸rC,vӑƭP4$*{*mߡR6fGp_Jd%ari63k6*$dm([teܸa>FOS~vZ+ZdcBw>v ,W;&sVΩ n[GLC>)㈧66)cY@dR':f\_X'X.o::utv>ξ Jdݬƌmk$w7Oirv~ew2vE8;Sd99%\2oǐ(ȅ{P$wP/miV69ڢkyN96i[xNQicr5w6DQŠf%ְ͚ ;r{eN]7Uo}s}s+=6R7eg6·UݢcjHg-z2 Rur $KioZ7)b"M[lyz_,.m!I k*E"%7/!ZW^1pɉ? |\*;NLIt)XblHq~[t<,/JICg'q %,,Q}Inj#Uusz ιպx6ʶ;3ѿV~ [Ys ċW!p9렳|yTBR'swJ]QXqQ9&q/ :-3No;3ߋU˖)&'^L׊sOe:`Ǿ![t숩R𽲚|&‰aђdWK.&F# YRfl+|Vm}VG;)w%! ><& [F8RA"5^t2QPu3B,R8q[liQ>E98e"0SVnpf 5|Dz!Ajɍt~|Kb}nT6 8sIx5t{+[)Ar3`v`.ZlТWŖUB-T 4mzXJ!DUac //a٬͠eU+6*Νpbz-¥$BR[!k6+VWf4턤4 ;pLz-j6l{͕'ʀyZ"y)؜xw0A ܴ=ޝ6hAر_izT#ڱη#2fLXz*V]PNZR]x]vsgH9WZKawR:=;UHWuf.wj{-sY(ĸXbU^)kpi e\΀a9$ ,%H=l} ;a&% bPg7jX HZöJ byLgdd{rM(TrvGyOIH9 Gh^ _i٦(#4:3C~AmsMQBݢ6a8KSiKmA\epeEX.J6"ĀVzF%>cKNC5U-3OukCin~wq؉K'jM&}A>$zP HS &} &:SlrڅLMVJƲRxdt+V0 OĭZaV41 QH& PRrY=R=SˌW8uf [4&KX" @5LAKX>b8G^!Je\ ?nE(iL bdX]ߢVP4ʥ<Ԋ̷(qݷlK$ɚ:ց9{!Fzpr.Q%ԖzpWSm-'CoWQ! ]t՝b,!2y2*ɦov@.t+mAW:oZjJv)ZL*f*"QSpDU/>D۾zxmߢaC:TUHUkn0Ƌ5V[<æw`2uh% 'Ul7@%`wDE#6QjRh*VM ^|(6@|͛z 7Q=Lx9#K86: ?4/ui/Ȕh C3ML6Io<Ak@j'MW S!4Ζ&-G%&׷(xٺ,&2K$J J~w3;jVI pUX-HN{IS/|Pv\=ncǢF}hK5cBn=;!R~ܼM fL; d0-i9 r={III-?~usIo+ =9`'.6 Q5[Xڌa:[C̨[E~^bj4)eѩafsŎ-g8@Jbu_ lcSHo"HpZ 3:?uܳ熛~ׂ,M7FU RRs\Uq#'iO$f#G+mSpI7'K+[m.#9>V 8hWt6GC߇Ҵ䟧6t7GK9ZL1y.`/ Gy=kZaZG%bT1G>`CO-;JV*47fh2{MUuX}Wz䫧!RD&z0 sbiFSڝܿػۊ$p]E!esecO3jشC)y/S|q榋 N0'N``R$d&}\#2=-h]j\GIx&QvrGf43VCȷR~=->ڡf9t[ln.MѕIEf2zq@uUC͝& 36Xew 8.е-4eU 8T/Q=ָ \Cnn~ɲ9pfcEr@sZ5B/uŗN&9`3Sg)Nԇ$D`wA93ft-]hWbV5G/[hٿfS!V0!β&B}·yw ;[>'x# L$u*|JswlTwGd[sDmxSbNj;ݜXzX8BZ7拜͊!^Z]`mzRgg/$47dCّr&qڟLuQUwUnŠߢ Lg 9 )fl3eM+SFs|EoROJpk84vTA*?38,T\yV}?2K0r{nPeP|1\`3yͻ!p%G>Grz-Z1Dozah~C]O:l7[b"f%i) >"٫Ǫ)4Z&D&e p.w2 ㉌M3v5aʴw_qq y(%8h.L]@hQR h @ HPQ_l=犳㸤duwAeb?G55쁔r'bzM")fS` ':#kIPCqIShԼv*/pWnwbN<x M2%,Bw>hwh -Bk}M]<>b9M:A;z:/x_#4MG p L`B~;s_&&:?7>A@|YByқ49+m@?红v4e 3]DI]v-SoĖc `K ^9jJ TѳTi-"L`}7ۇz01VńŎ?<5_wmѭN̚^#.j 9mz~8T տhh4ui YCZȢ04.+RX%BWq:ށo '4oģs`?".3 X o yQ&MGCJKhLrc5($ŏ3w >w=庖 vHYjdĽ{ϟ oPѓRTqsT`e][E;x4CLSOC8ʁlGE/(X,N|?duKhD==ɿe o)B# 5N|?1-2_)#pBa6#EF}E>^o01 %tC +X') (*e"#}$^ }B,l;0 Y2KͺwHQ긇v`i攪y1FgW}Gt {08 sHc+N*-+`b]uTR n^S"Oso뜁E8J,GQJsWur<ۓ&( jAP5Ӌp",` z2ۉr^Cj7lvVN XM65/8 ZfH~FG XéT?=T/9!#LJG*#*K *3j_@&Fry6r[yGUv0ڵ:`*1JtdwE=M(Y(ntxEHGGHT+ee‰1AE}c:*J$#lXsẍ&G@OI*ޡp,p+6l_&8K9=Lr*dN \,^֮S& DHTL1Y7Úv&/ \Pt?P1RsE@/(C]RoLK ȸA,;Ztvsh]@vjI>.-o4)P\r iCvNjì:Jp~\Å KUb(WSJc(ju_xN?Q jTvjG|4ni*ůB?G~GH'iq"1&#H8NitՒy>r#hO%ϞeB[yf3CA޽Jh2e[Ox'"^UzDS~jfNDO|>?>_+~9"XoI)[kϡu9|ܷ&h7?ɏ(7Dz˲rmi-+^Y'0,.}ZqAbQ?`5e;x,dWlm6!莎vŻxBpsOdR}{ d8Rl,mc#i׈F#n[%aG+۫-?[- y*kQr =7tkEwxnon^k(Ri].T(_=ykī7D~ D*w(#zg(7onwܩ [g|jNMu~VNW͹>|tkS[Ҏ>,#} FW*5G}i-yy/+=RͲS՚lԌ׍8hnۈ7q oF_lfF27\m,|P#`Ps3~OJqx fOA4)֯O,-?j@a\~)iz]yM kU,df`(hH1Px)`[wƍEyfŚfŎ'7*sk)gxJ-|m2cf;0+BmڷٹhٸBc M TTqpifM˭#EM] ެk7(\Ԟi܀!ADaf#7yނyU('ԯo=!E qRN8ͣR?7%uQ1dKgŲY'O/oGyfǙfǍ f[uFG%oICں~P`a>jvju#"= rNj6>-y  +9.smaM\g˭`cvYk]1<5('t+_NwC&wj`foAH6y%ELޮ~$[WMҽ>Đ<፪Ü50to_Voz& \4BVlSbĆʡ\>5{ң]ƭYiNqӯQ.a*r҈, P̻C'Z,Dt} 4;T)~LxnfFYn7~B735zr#M9x/7mK1\_#z\b0]d=BGބ:9^"<%_r rD1B=ϻWֺV'z)'xIJ1pT#LnM}i篅I%VfR{Fyܤ?-r$³ Os*@΋~#Ij~KEZ]kβuH)4--:)AgODHb}*YusEG{jRbڔ$Hn?oK a25(JT!r:ERd r&P_R]tPH6?sW%(A/Qd>[= h:cn':qwcC{Y*iNdH=0M1ԉ-ib%sP﯎<<[)m1M_$%#Z2|WG!ZO$r^\kA' txG0YvFQAXYV 8/ifKzI} [;C!yʈ a}UEKqLrFzKS:v9D_ntzt">n{YƜBzbtѝR l'|Ãxaɪgଂw:T)2XqLZ,7oؓ/O*-]# F&ӱQGA\r;9Hp [Yb6'nfTh!fuY "U<߷C2+u>`r-bʕInsv Ewr텉+:Ex X!6ʐ #ЫIF]4V+#kw UޯrKJ/]<9?Ksy?ۗ( }WTAſ97W$F4 suف1)xX s&.)1YvΙĬf5tL'ssiUَnF#ei".Kf?h?Fjc j4}H>;8L==ҡ3LАqϘ匨 %I4|5QQC8Ev!M-l rUd%pf.~i:5҃\/dQ0=dS^;B}dM :A)[ҠU~1yG !wyxנڲ  .6 VeQs"7 嵅^+17nO-C3b KXEv*r0ݥ5:YV@ t*,̡-s;ڄ"Ū+8b0؜- 7is1]Tm57[,Fb%2v7wܯ3ӚGhl0d[urP ´ƌ%e!C.g(k1JZ<$a *5[b:Ɇ:'o?K6#BvurBlgQ#U5 cfV1[8mضʯqy4CZ!kؘ0lRr\PdQau!j>$҇1 $IoHj|d|=`QvƶmvX'mmv7s5gyٚ936i-h,r 3ۛTIٕۢB`2 |L0E.$/1j]sGNC "b:性F竓ZLAop^YNYA*>JB)(u` 7#$ )ݻ\ywuKlO_G m" z|N@U+>W΃y!OYcn4͗g 'V +)EqVͿ0F~AA?j9JO+E284!AEz;0;Ae9u]*MnYEp+Ӟt{*kq4&J<qӞJZݼ>~M5q9U|t&B[*s> 4f%E: @={] 8|L \ENgv[tzE:UӺ82*cI@sg8ZU85fLMj|jm(E$MKcy5KiR?u,gݜ]%Hq]RsۺOlS|@ Ih@&ozϠGshaC[14M0mՐe*#25K7,31Vx%)ox+Í \bO|+^o(TX+%xwU]l]H^ۆom-6K՚pl 8'C? /D@W cs03;9ڽ{ TO(1$Kk?d=T䊧 ^-`h7!h`;t]kVfatY(\W L3*9Q&#zJzeP& 8%S(J bᯘb]c?NccZW~ǮCK30E9`]lx Hvok5I&E}pJmR֖9OdˍiϬi4P0hZJ̲z-{p1 &tդ5J\%%~ ?hYc8KXw֝i e@zuQq|jS+pDꕸ꘎Ka(ᒨkNs931Jil)˔}&L@?k +,֊S<^ؠD@ЭN%a|[㾡9$QpG9lʂ=K4wC P)6Mnb+~'4[c2R3o/fn-aR9a•3zE9uqS;P?ʕx2V?_PWs<2 u3h C0[P$KB^5Hq j.g[3ux@HtUVz2c/#J9$MMv1Ds**^fR##M3p>*aBf7_Э.lLgPC|HYÇ ٹn)/ZCUI4~`=29DtEj(GMd~%Ma\˜b"˿Mw[iB{s܋p*(XFaiw]#|;C/(1aCsY} P-*x;&t!%M>_to*MԒ_R\UܡK%c/? r ˺0ڪ>E5qu_bbp\8|`ykEtƨ(d5(ȃL7 u\ r-~ߋ]] 4V*½nl$bK-7UГxy 1d.! ւO:ܩ5 R:|&b~`$vh]b5pjǹ nc^+v3v2!;s ye/hX:mC3$>-JSrޏt{SҖLe%פ!(M2h x 'm3H k2_ S+;V oPT7qr+Pڎ" (j]LRoU;[V6Rb/*jG݈ }V Xq7q*]hXD+tj+?a~PRG+0|]U㧩dfR`]5RG9&j& ߔޢ}9ut by3fH ˷1ńSA:‚&^DR'D@{5%?7a4Hr ;@hK_wu\[6xE(C\ČuZav()>0rwۯ4C[TGBhCacJ3+JL(;{Zzw>+K0@h#8q33@K|W`%xȟ5h7j+tk6A |>xsCjXa\vc[5pm&('X~pd.nui ;)~9`ȧ_O#%^ඒ0n֖K<~ma7PCv,LwIDU !;ᖤ߿fcLUIhψ2a(>w!>TE~qRzQ"[Hn&G-ts#C([Ρ0 ^e(aW;1${va!a"k h࿧ >yPr(=5X+j ֆjj2Eu_ BS9h R$bmxHpƾ >'\$M ?W}=}| O}LwÚoX:} ĵ@wG:oM^> {X3^\g[WkGnJkw\ęxP6RdQHg ߘGy,τtA?\k735Aꎿ| #)惆{{.!~I/.Ni E _4IN;S-5Lcw3kT:fWFI+&k]c^Ѫ:C&\8oCRpc-O7RGsgVE_udo͢ bKV0֫P[z6|ѨUlwgw&z ymXqwUR)}f~[qz渲@O>VIAG]v>Xeڑa^!BI)rŷf`;>FgȊn6zDZ7^.j׺XdfTA^ \XrP0V[B$"mqNNӍryeyFz~VXmP& bYف 5Z2c[a/AnJGA+`}lIzq\.>d $K`mmr=pO& 4J5Fjܼ]/brQd6Ձkri"d8mzEA!V@'Q^Z@$, ,=b`7-Rj0R:7SsN`~^lQGQƴ.1l6Ԭtf | ?VZp(Gxvm/w-heKmk|uHsX0xsn.h9qf08Z0`;iu[e WҋϒbDc9pgŠ@@&(j$-ؒ$y{C1!-q¡=ä, d]{mN'S^ͳ~ \viNM3Tk3U.a(4 ·f,drgι+8aⶔ˛Q2G:Az RauRCR?GO/(rRyBWNt +w3`ys&71dےp }qF8r|!FM,Xm Zǰ&p'{X[">peUq({LDGg:s}q-S|vq`Qx|4q4X۝U D#Z&ghF{6 ѷ߳]Jh8m-U36 3sާV^nd/ra<ʓ1AWIHSѠ 8D۫l6$nB\5̈TV.vyp[`Uy3UX<6 r< ^ϋggEK~CoxQGO!s}kPE(T}hki> wÝy$ӺcoJO:KupF8D̞1s#ѩO]a) b^}82EQS9Т kihW5!P/QʍD5}"0OwѬQŧRk&/TJ е቉쿱]w6Ӈ4ƲJt>9?67S օH:|_ $yoCꃑQpLBl8u}1 l1IᓆÓEeQqqf@esL5#En*zdA#NB(߬u,K@0'UtYhϏO)/."mj03_; -j90f0t OYTd㻰q=#B9}0M`9Cx|β>9mOtqvE,bÝ_|yZ듳ܼЀTQ Zuwpo(#N; {eTpr[ۨ),8gxT60\L:8h,+pr {~"kLDzSIG1P޸i={*@w7o,U_XB|{ z9~ k*̳ܯ{;,6JDTE ڎt/s@1#Ȏ|nY/ % o?~"d61aשjN/7H5?v0JM8^o-anhi`^p"X[C7#W|νLWPP:ZQŏJD;a7gi_#8 ]"? kLo+HT5= v;/= ICHkS~|$yh"6lFw9O㗃 jwH(RK~Dx$dOKzZn~ڐu='vC MNr k&7qljT_U8o|P(}ٴKR:g-xpf@! ?t4VK0  ^p W: LXlu4=9jtMМ5 eȌnR7_,|E}ZUELT T0}:%sψޗJl3Qz]rr㗮j538q]QTײI:Z\BnrdCvɴ>N^2 qT<$z^6;Ǣ>TSlny.SgL;U/B3PZ'F/f&(Ae5t_=ͤ7-bijtdvoBDʼ ֺ:T4p |b '1I fdHkh4C%QS 55BI#P1E>YKjzG Vay7/v"eJUrT&Κn| Ӟ,7&![01gWִZc-0E#QZwA1  XB E5mJ_pUІ;穵}@ @y>w0*xLXcDQ@l.0#2h3_R/lgS QCIgqϘ#;of$@*v޺@tQ>X_&m|ޠ~+ Å6,W.pMx+ Z6}><,@k/#U(|41_U%QF> l(֠R5q/:=NEmnSf /p&5$`|O'{gO5˝9P(ȸ/fr4O'؆Baf_9g^ՉcaYS^Vh,.#^+77Zˈ'FgeGT>( K\L܊'DU$5ȌmR,k0݋Hs[C[:T 5Ee _tyBroFNuy. 89+O첢(%6uR`j |6ӇuF⏩)$FybR,&bv$GտJ&;j"ɧ&BsihHTn)Cլ9CBR?[\@xP[F~>׼3)~E\Y۷ST00hYY^nәbҪ륒iPls՟j`M>us?]~CwJ N͂ri S{d[1bP%|` zNɒs95 aE_/H.K=w.f~jMX/*G6L\]&O#҂qMBVAvx@$ H{LST(ܻYǗpn HsKP%]0(UbPO3 Qd!%( vm寔\.45]&fj1ş=1E,Q0)&xsQOVabC0T%ױ ƴ/G, t`ظ: e9pP+Oqwh{7E0;0%ǖlNDf#CXZpNbq?j>?*ŝtUXsç,O,)]bńE@k4Yi7e  uE|2+,8[tG,"Y+51/Jݤ!8}PxQT?-MODu((eo #W5ӔZ+xhUza>x`A7& n 2 \4sBshlhtۘnz5TmBGy \$vTB,hwJ=CA4@l3%yQÁjxv&7a L"a“172YNWS0Gy=EU1UfWQ,oEQN,Vko l9d?:6~҉"NۄZ5m+^V ,yEWx` 3K)<s@Wt~ i) ܡiD}&eih;u>y# ~fJΪ(ԁϳ(<8bl'&nT3[)խ1b[|;EgY;EYb+k`3b_NLF|DOdMjaJ;*r4 ~vz8Hq_rɒ<:`~Οb2VPDw'֒́>:Im2 C"J'O:׷`,q^E}'&[7CfUF9EMZQM8·x^*ٖ=;7j7 PGR7v8a^&߫K!@;:ǵtLSgR6aG(FIcNY$WQꗷ,"p )h @Q8_LJDJ:[UF]:# RpH:ۣ׆#Hewfd)M1Kd#lb.Zoҥ*$PM晊-Ld`l=F?iE' l.) (jF:v8ѓ/+gW0%0\QH,WW/0ۤø4kշRPl/)ELBֶlPEMau֖,"X_~=/  |(hX>޾z?> ~~_~MzL77;7_z7~DfWJ>>\n?>sn?7>m~}Uaɵe=T$Kx}v^?~+p"ttJWPX,U{jt# uFK { ~_ὙƛN4D`ө!;ŕMuzڸڈc*[IV_P\y0%E/%mT&\i;HOG/q%1H)F_(.gzVw~0eCV YwCNNe[8DIONz 4`Y #//#0ϑJ6@u3.h(BrL' 7iO4<:p<:~l躳P5gX@xi~pRN d"{̒tNT+Wfb߉H;&i^)I *zhqD8F]Pp <Mѿ>wz âR'b#9Wwi<&qx;Iu.z0+ cߺ˗Ld]ZTǎ#%_&.ܠ*B/YOL-0OmDOm4_T\M?7eLS`VzdC)/2M忦Kvie>C-l8 >=;- |l޷DŦ۲YrJuh 5:,&B5 ?E#S)b^Ӈ6w-ݐpR)"[{ŐP;CB/)51Kp`3+o𒙼b⪧ƒ%8}ҕ݊[ff}Guӧ9#.?<;q;vReN.AGvJ[+""K{qEful2ebpK8 q+g}bdNuHq}neL/e< W1 dJ&2/:a,S|ky><YwCL O`=yG=9=UK= v>jSGlŅJtܸ(s=)t?-'22 41Aڱ~To5*{I c@qV̈́oLA~~dX [`1*C|Jv/cY3Լ5E Rz!F ~ۮ3w#a%s elI lgL9+N˳zPTbK.ӟU3C=V:T W5# Ԧ݅ wo@gv;ș5YB$@b$d}Xn<xѫ?P*Qt2*]T]AcuZ1)#.otdsB'!OQ2 o{5Q4!|}Gݓ c "qӡax|? Xf$]5Ѵ%q*:?Z{%nq }Gyt Xg_“iLZ_B:խv\YG0]Q0J"K [ !jb.oH48?yJ sClC䋪zD*um+GqkU5T5,)-|XYI=fQΪߊUnLLz0*17٠}i_R"K)SxQZ8M![Ԉ゚d3|ar,*Ҙ8 (郙cn)+X~3tp:#F2wD1~}X-zR2N0=wLQ\SQbnCr+;Nib?};4Dd"lU `[lfq)KXPq?zr Q&I-bC։94b[F,ӝD,ZŜ8}091hbC%9L3pjHG?/am'=!}ӬNzK+qG%2#Bϡqh Pnh.RyxA%f\x)pv.{1+LZbŇʌ">N٨fΈoѣxk4@;™8xg߫d6=`Yb.7]NƇ5k2L#Us]#e/D|Yiz>*dS{%u5Su6m j2]#Q֕*{}$85qp+F@Kv۹LLWwDwE-Zz,)1ȭ/f4]hj܉Mv`_A00ĔS\apZ#f3OTY.1 cdYmmXxL-'?m* Ш:/tP\29TO!Ԛn[adi=Ш#K}]|R8͊5$u>B@I}НբPZ1 CsMrY&Zneg_T"ܯ2'[o"3Y!rAjs}|,e@ƹO'O&v}|AX"Z_m-D[hsuDWJ^ o0YW4#-gA)( 47j-}*_8' $緩Lc`cj3Lc θ&BջTkɗJ\23(ʊlWp-٤dYLa,x}/>.r闔)! Yk; ‚`E@7W$,0 ډ k7Ppia.Ѓ4b_m]"y*̴" ESڙ<4hB3]ܫ¤`EM 50H@iIf(xU `]wσ$ |TtM%:( &'J#ǭ(6K8W=, WVfID^EeG|UPi w;H`54(֑A2fY ^Q{JmVwIUXRA'YjRJ*D C_kP+uWj(L`V9`H4(ǻ`DvTk'gySx :O:?F"{*hC]y7"ǐvem+"AÿjR;o|S+y DxF7LFW61^VT5yEa!B66U·Q*3n%)\Kτc3rplA5q k~g%PlWq{v?qԕ]߃jqP $+((yvm#$ʬn! 㕲MoĨHh0O(-]^{ z*Qt.|8+<{T]QeӋ LeQHbOAKuoH9bw! |RR`G`n A3Ϳ_JKաciY`v)-J5YSͬ#k۵)h̍ Y#na.؃׵p+(1j~M"]Ҫ A_V.p ҢqĒ7ewЙU#U'!龛\ CTW*go௨xpzO7A.JӬǥ  c&!qZp,čd=8IZ?pYTXQaB0W+K_d}w8Rgݱ) C]]F TKWwר<]^&뾸tVvLP<#a/G2 ?aോdJX"L]6o^BɓDp ULzk%H`j[F;&rTO0hQlGfIi4Bָ$28``@atPƶȫ?TNtShxa7s=c*>(: ܔss tP‹N2oz}cx\ѵ- j$vͩ>;CWU=lH:!|ZENfT\ %I&S ע.fs=Fa?H%^Ppz?blj[M/rr-D6:I1'?rf(jZ`.!юL9%/ zJf2VaƎSޖH;xMK|C {L&CtNb4oN= G7gvt. _S9t>CpA7- \5j8q j&T+-(/W njk򜟸<ȱR$J)K4EluV ~L7~G>su?ж&s娜?k DjFJ*M.D94A5OVh⇿mnr[E텙Di m5:4#Fmt)MCYr0/3:X0 t?Ɇ~1'+3b 1//J~\]կ 9Sݧ1BHVJ"x]r6hYP&~<${ ڎj 1a@_,N um/3n&#BRr7 ;|ƢvtdL9 е57<2t'O:~Ё̵g70wmQcۯCǙb-NIj**Mi?28Q_'cO'׮.,R\r:n -hVw4qt-8 K!fyb7 9Ӫ z0";[|_nF/Ev]T7qcvDrPpfZqc]&4]M䚦[9ELMT# iqM}t4.'2OAcË~i:B`vߔ]A`i'ن H/<|W_ r3{g*ihŽѹC;!XOӉ9A?X# #o̒؆+.| PަH b%"?:pKmj Wzjl< g~z$"{!ΫC 4. S]Hi9 L+=BXز_~S>yb19 ,]dڗ_x?K;As*5 &EE_bH%q ()w_QR+mj*)sK;i, ` ݾb98QO:p>$*&ukyMϔ;aiCe,;|1݌zs7BZŬJb3My7Eye~*盷!Rkcon kByH 4bx227uN0SzjC ']/v FdNANrJh3IS3S֏5mHPRxޔEWWl+[v_G%Se)G!)+g_ţG]wRjg[^z;ȋByCـAU] vbV8?__TQa0uxAQ_og/ tP6f4ڲ&2@%תäRn7jۅzPEaenqޭ?ebZ)āPFGAWRy"Wa8PjNqa+[*'&+W+e7<:$HpKxX Ɨf9.v]zέҦgyȭ* Z!i!T95b9:.@++i"]Tjxx`YaXa'ɼ\86 Y MxT K=~6oP7>VW'g5̮)nU\YX6kV2kD)v-lU4$)ΒnI uCc (*> Ѵ)= .)Ѓ}ݙUIM:٦FiV;|oWcx1fBJVR ljX&9 6'| ;8ֈR+{_Q\Vz<޻XutL&yXss)cW]6Dtv>𳖞[Ƞ2!vNig2œCخT} ~cꛢA 3_A!dol > 8 yZv>ɘ38ӫ;8黕Q=GNnm~S:HǦڍMĹƦW] sw6rQt+$,3&rP+ޮƩɴgIP zFkέlDc^CENruy#ݯ?Yq2c$o+tp_m?# GæSpd+cCؑ ~_zqMַ hRNP`⽳3mo3"+f1A$-(c }ÍA#(H x'`Y:Upn3k74~T:\sP< E-1~ϺzCHc01cxg1ʈK@t=?xNB8I%:ATHٮ=(:p;YcL^; 9;"VkP]řuQү wQCB$ qKD4'Lu-.$Ma$cpv#443>ynɾS~ (2 ߃  ݪ EnK!z`@JKmox<$^l4S^o ; ITFJ*rb|5ӣ Yn9 e 3À|D[8ń9 +BZ(w?Mv3CR?ҾhK)UpDU4 : Rgx#d[l3항\4 odTF&CHq0f;Holeå,|l84]hT @\;6 ufb1nu +*VHfit`(RW/ȻA#AUPK 5*e ٽ+' SCjuhj`Gbݎ= n^%JRz ]ǬC|_=7~LQ<}frⅣg6SڝxB`a+ v/ST%3l"y;)uSW(Z3s=R95&sR9`KQsٜ)uv.xD1gnKS`LH3](] ﴁd\TMFG[W|Ra(_IQsbKDZv/0 O"OCߓ4 *y4Ѯw*;{#Eƕkx9Oz nHe}A+Ut5^|V9WAR^ZiـNJ"N_rbY/t> {G /aYjl38Pָ4xs۴= tdE4JS$:.Eؠb4:Q h釟792a"1uh=1AAA _׺0  @e>SOLB*D#hv+RpCL5.7[="TT4çRM7QS6@Pћ#.a0XKwtxG10ɗ>ERkHdZh1]S7 ܪOnkRc5zc]Y[{wRw0}Mˌ. T>]c:hbJWw?o&;u}*"M#"b6j)%Hķf6{|NO!w{ZVR>HoUDUosIξrM%|El@MQ=3ΡʢQX֠ȻJ%Vl<o44@¬*b)Oz5_tB v*l+*} #$hm^ ʶE97žʸm &ns&5#=y gg͏"U7NpP[}[C"tcUd3j}8S[1F|c ͷa&-V] ;"V9ם J ' -|xc@( ndxM&rP2oFdOS"\yU<T$1tZ7+0;Y ;k.!t%ё(b&p!QxQW=ih- ؘ&bڦҜ)d}0ZvvD !`=B슟tS@I]T|CvaaFws뉮d:{aƯ ErۿW-Y>m߽UYG؝"J^e},xR`OV%tt.+̹_]@Pc!~KĒgK7H]̼9^]@XFt:kkYơ5K/l!25/gx Iە憫uKXV @o_9.эsЀ9I>Bٲp'czhĘl8W;-^8$;Nh8^Ipx>Oi<Ҹ}H4dTZXulN~dXƒ*w5lW _W"  naBc!XT MXw6QQnc4Z┌g&n6\͗SlQa|v?M 4H T $B/y{3 P*%jh кJĻXRЩL{h:vd-ZClkez(Q};@nt}z"scX `:ATZVXE\pNzZY*7.EHUزŸ3kP BLZTREG>!㇔o3xjVx_yTDHIylbe8 T:!(KHp~_޵N |'}B“N7Ӕ}>7 D)Ynf,6}VLWPyF_X:F*+(5#VIqJ…`ٖr#_E=%W7T5TMsc hšT:ʤ:^=n2a>\[A?,V)M[_L$M97 nAZGp!8Dzȷ5պ6BfOvs)5X c$1QMĭcDh1@>BEk[ Z̜,[`(\|* H^B3vNӃ `5ذ.7c~R#.\_ ,Pxx#jg?tŲ>e¢JsɑW~afůcX*V )!qmZcTքWz䋘g)[mJ V1 arm%r/ [AEؕg̔C)UHVh6ӮZt Lye;Hsܩ4>P%:Ĵ^gNIv'D&mekJdM,dqN_ϧk9k[ X08ڔA#8'"&IeU%/* j,F3b#cw{"D. \5yF̓4`{&A@> Ke{W3P)78]\ G`{ea|ɺ~*TS{Zĵzq-=شH}u8B~,k my.gPY>e#EdRtMs0Zp@5{K1L1+n?ͨC:{CSg'Kk!K98L+))DI3RxzƩ'ʤ{t1/8]b[SZ]vJRD{ mrt5ǙGA'@s=|N˵#tyt8DyI+A4*0U_Haj@kX\\S )5l P.(4кKu~cY"Ӂ`vݘ-fXQ@'(/ZĜFaRiqtir#TiC35 Ѱ~M)xTwW$i!ܨa,þ:3$V5ߧBoWw|5ư(Zp @_hFFkJ@XvߣspmC^]t&Soz{*>% UDB1A<%].T:/l(E5%ΘӤ-l"*ī/:fYgм= 璼9(_aUL"'GR>< -ZPnNžʼW f BR¨@uϭߥ ?& Ջ Jǧ{HteT{ViDvTa]1Sتq=-^^FmZPZ)]܈O,PgOxQ$u08;EQzcR!A|̓ be]dsr](fj.z"h؋vXLNR>By}O59<*VR&ߧGhKSV~fa2kr3ъuw~$iЬK^*E(1A6ެ7 VU6[~Gs`0жkYHƢ2U9W4TGtgE-=}Bq@XGNх-[PGOϰfxqYLgeydϓb>@? ¿~x( Zf"+rʵH{6Mj@S$q/vx4'?EQ]~<`#[2ΧWFDcmћ3CgtQ9-i_E1$6L% sla>Xz4ind]7l+/?b=>vƉ&*y'J{9|u,sG WDM\#|fdTfej(D@:S9yCfoR^ 2tuYDi'/]1tBL"uEݹܺ9m궖ꛦ$TO]@zV4bd0GmR٩anw, Bj-TS. g1_X[+h|};Yi7Вn"zՀ0ob49*x$;fԟ@_^vuA;M+S[T^[$gi(1eY>KsPTiӰ\Ҫ29=AJ\*<׺dCm/V!l|u\Ǎ36EJkcS s g21[7]&) ‹sߺ%MlLSJ`ՋaU:LMrO[@ScCB &n;.v#+g?85w%nW*x>a67\8vGu.20X^^dfO]iF%F{j^yJFf@?|X'!wFHq~|9:o*ks0⊃n`lnRr4ϐE &6µKYi+Ai1ejlGzPSbvZF~2[,Ve 5ssl0Rg_n4ED|jW9Ź2socu|.\]9fԮ,u[/$B#[Z  c2[&*~ zMptyuө86HpMW^̯8wTcz`1{ &= υovI!{p*iefo9d wO:)(*|aAFMH a <㟟` y9`nP1A?IyAK˕EKn̡00Іt!|3ޥʹ["W(+|249ѥ0p?>gE[K c'>3<)lY4U6A)2g{7:v>ph56/ƥi>umA / JcSn(IE? -0M$uyt;~F:b}% )4SelGQEܨ]Jg BjMJixɍDtL&Gg.ة$$~IC&zkmeA@~‰^",n3N/zIQ{ڶ랍y sm C(ۈ{ׅ =3qC~-kM@8ÍxNYgxB h), > :DƿhY`W nh۩Ph7.=MH0€qrMuE]PLOZ A|M=CNUFV%|c%xK$%iW d3 yL䨬SA^PgiAKhS3.}  4ZP+:"O¿5ۓXTB$$:".W?mnüH$ ,&v8h`/1:d@r9HKjh*rdm:؈)5g\@~{#u!)|Yc@NaI Ar,)2|'8P=t/kTrIⴻe] ~\-}0,"٫6KnKO$ _*5 Ee+q>J-Ý`a!2Z}ꏵikn~NT|r~?JKć;| '@IaY_ľ$Hk'xL 34bu>:jepFGkyQkɮo&ҎƣR#2`-p-*jٜA.z=PX9lKY _KN Eou[ ƪ OTr/// |wpj 2b+U o6,Ez/"3DŽr-j˜jU4ǞPș:Wx4z#݊EwS#GEb~7>F@rCLmPGV&Z[Mݯ8 H%O2 "max::¾Y>^H͎u^C"9{D*SC rz@M;ɰG̐c:%MJL, $ `mcݜXebv? dFw>hȫ 6T!lq8=^"7$HxgjAlhDZqs{)rbVu1ZH%ůE%>}5H-RP=#}>I-nK^,QsGNא+nUNhҤFmTU68%VWćNSbVSG(0<;H9Hcr| c#^&8lSjs#T$r Mh< h!f~+Gx*0VhW ;Odhe}o*cN5yhbߢU7<5^AYڥ#d%cYf;K 1<6~CvK7gwτ05||$A섞pXlxM>}53Lp{'54-7dHው|r豏]dC=5r'q~Q%A$^WmNg~u,!zGZCZZM^an1lK8lx@΋ _{x}Ȩy?WÜk sXev'`,dift aqY'F]Э>J\XԎvX 72KvrfF+l\+겝CU&ꄳBH㿷!6Z~ 87y< 笹o+Jv {Z`%tk|b}iv &h<&ƝȺp2P[nM;Dsk\4V)lw}z DLت|sS2@I0U\EY>L&PN;"ZDu|4f{>PwI[JW[?&8yDfc[zwWgfb4k}֨[)J5#0ý̐44x{qc{6 FC)ƕ9gm@1j!" Yb^cЩ@7Id}5#c|ʩtxJƮiɨaفFr~^c60,$Kb^M,rfiI[w#Qf(n)iMY TԬXl+oTW=]HƪTVhbLPOx+n:~1D鎩ϩBW~ADa8ݫ"| /<>E<8Oj; W f>31P&_{JY8oʥ䗏g^c}(`onw:ސ׭RGF,&JUFY~Tku.k }t2~}zZHutkc t<m}ю:`֡%?AyrG;YqMSPeW_)QG&KP=X]ۉ_ɰ1tWi+\+"׍#6a3ckM*>|ʅڻtz?5$Ua$րħ2|a dMX5${dH?SɘxÄ N cmRy@WBTǻ_(Zp,:݁~-hR; iѴvsDAW ΂@S̕[F JCaȾy3IEYP G + 7c jf` ^S~o!_Sa? ^y}M*zɍ<\an)eQ3-cL=tx^B&| N 6MDQ8azۄb71˩8><CP$B"w)Ka(C_؉͐8CI홁_ CVHњKX9Dk;yPKLТs~W[r~?/hG$qܩX?~Xnֽ3$GFs毻b6Yϧ͛<>k7;8=NFw6()zR1~p)o )UeIrVog㱩d-*EU1"Ma+]є˥% 2&Q6ҸehP CʋŻCK_A1zE#@*YGW*bG⸵^PF48J2 dW9Zhx&vu '8Ztc7h\f钎"xyISo3Ma+!*5:Vsb}+w> xegZLK\UL=hu±6S2ݔIDږdxt]5%Cg`ypIuFƝ=@cv1[²ӡ;vH8e3v$+N-^ *ňF͈2~> !Syjd# ˇ3"k?a\8jeKC 08髜'\!RB?N 9jѮ,l?ީ`a*a(Sh}2f'l%ϫȖI-*cy(oT_M*A2ʝ@ 2EVQ)ϱKAvP_.0TigpAW,oaval\-=Ӹ;%Ϲy4L?X8+pHmhyl8 t$ S@/;[;>6]68ԝU;r-܁vΉ滐5]C; GF;CujSgl`Ve$(Bkx\daSYy֩HQ)o`A"wkюƨq);Zw&@2#>F/nwLeýWÄ|?|(UUC-B~j s mƥԱw5)cJxe.Ջbek`" N8jc&&\wPL|6st&2-7S`yx`Ah09a0C{׬S-2葯haf'Mb960"u 0R9D@8mn@CL]#Ԫ+ژo ͻq^v~=ؤonan^f)A94esSh([_YˍXJ0ͫ0|3ZQ 7)ר587պs"&0vq4zbeƏ\ݑ#WCqgfk?QK`9Z¼V暪M:rVW؃06._8o[KPhY7ƴ;/xٗ]fQn6jT/*( . r{zGzsHcqQ37%8,1*CffL;ljDDgvGҧnĖVZPզCmdQZohי.4B_G;Jl^c|3pLFyiǐԔv_%M} ZKɥj=e}N,3-3:ߨBanS?53'˶5'/l꼋ghy uԓ++-;I}ɉؚH/|Kkz"unlsaR0P ʗ1?8f%M J/q]uGDŽtO00ms֭HGk%x]'Ja\Y!rsC芴iVЫVYE}.r.SnׯiJ\ٶSP4Z$ =B'.,$#ɐTWj8v-4ِeHcGfٺf)],4"]Tn׊PAZx-:0Ml9OJ‹$r*T3M)wT*5RDt I3|Q"i@(KxNaBP~ynX-L>]9 Ktt26,' 0wm5;qޑ,8Ua9+f0U!h݀:HFPl8Zj'W/SuQqYe:!Z06j,  Si_KD j mޘR, v-fώKYUfH[ l ' =OH v͏f|xn=L7p!5ȼsReˏhlڜn#IBT\2 OT\QrDxWKڧщ*‘a?F)FX:>?u>_Y崋L+^cݬgzVݑq4=i,2yux`d?n ]\o@5wOUŪM[VN IV;-6#[rrq or˅ KuQ<Ng!&Jy:s$x s5sJq$ġKSz 乥y럎̘. Jumn?7d=/ ̙\0p$X@t|XM zM"V1``i7v~{\8H<;+ A8J ]RW bomIǨ L[I2k|Vo].<]i~QzHUhRt#/ʅ%*c={U,\{+y1:)3+"s0(nߨ^H)w$(A@V+y bm2Ŭ%GPÚP,@FE<:ss|Ee&nz, TxKLob1Xn˛VAXV#dRPt& %e"']ť2۰ϱhK\$j9DuoXJ^"veA@w>ȲsʳuDN 3G3S η3Rmn#LUt0kЙtǚr]4Kv kVBdcmzQA!p-\ii$i5~DAIȜF{uSOnhD(+(!N9yY-7(>aeí\n>Ѹy)bo೨1(:‹:xޗ)6A|xv©Qxt'!dD1Uj>#ؿ!@Wヸ_{9bc苯hr@ %}|L ldei ?Y.}I Z^(RF1A?ii#WQx]qOoi;n.Ηi/dRiRP: :l`|YǔR|^ &p嵖]n;ORLeoAֈfՑ\;UFEQCZ4o &g.YgZ>㼊3c|fѺd ooTAU)8x/AmRJLYMqvaZtBP ,CAa:hp01":ߓ`ET zOBd_5Შe_Ėxo^a8-jRrOI·gf?QټЀx{B +e>0DJNxDrD K޿ģ=:lU\5sucV ` C ߲,{9^ԩ/ړ$[Sgh{FZ$MaU6_#0T-It&}9 D\pVXB+m\ݳِB|6Ѭ6z+$!n舞jm`r"?Jqz+z;hfN=3}!ٺ.v| $ ,)w+(wQ_rbOX06Rig|$9\OTi^꨺A("E98)01 >J`+,xePԌ>85F锥,o~BP" 0o \ި"&쬿>wF7@@Ք$+ϔetW5Q ٛ= ;O)caeZm W;1xo.n@]N] ơ&l63uR'6e8-Ttnbqt>{$-`:Z |t |fE7e|9UꓼٝD}ի >b o~?s=]e]NbqߋG$y*Y61K8ɯtq t>aJdmM8}!MY3nǿ%:(eМ>5)7TF+oV^NBYæ%ϷdwRdZ;r [pGgwS,wjӲ; ii@pﻓb-B$:[$Y0!ư(A'!j<#euE(Y$m0jةS4kHt]ڛ< ᾏ׻j`RN:G/=&u6lLZG3k7O@ LN3D'!~WLf\ |,d9Ex!ٚrǕx~fw,(~uju!Q/ύF~JЃ|.ͰK>52>@NPb+Qᰉ_k9Er+$AAZIO>7y -Q{ڮ6%z> H)=J>7ot:l|xո-)etBsP(O@!u:c=vZ>xPSRxT#,B7R#  Pq%l_1, ~}h7&o.Z% +JH/[\EztWP."u$NG8I.+z+JL=Yb6:odnXԘmq]됈CQ;,H;\EאIՅ0KUsV"&x8QVV_Y*Id[C^AY;7Js):1ҵv/*q*=nX$:j0vtM BQ 8&:#v2͸Ht1 ":KV#|+Ճ3'[%VEmg0=B-)Bw̙3sx)&aldMn &u)J7n~G)oNfFy5v %?AKkihrj}T.3vm\͗qݞM=Dڙ֤!2ħwv(H) Q.&kUASqd :Ƙ")85k,#+z)Mt_ ٵڴЮJw =ܑ3#X,[VHIT@wrR+:sng,Dfѹdm\6#pu`)Qz:0zsEHLk_w=Q`yt'UQkW%Dd/Xu>u"6+cNzJZHRkK(Η߸cIpiS"CazG6TS1`j +Q &QĬc@6ج< u+Fs_9>Ȝl/$@i4=IiuKS}EbQ>my]Dz c4~P qֻV''my iz+0S:ьTgE|N#LD)ue)rizNACl?*m^zى%vV=& -]I$Ù/߯tgb~lqQ|H{'q45woI^W\ӿ{tkv\,\p___y0X v2L_QlJmX1NA3Gb 57uXx }1>ָ1Vci.zvXz8Nҋ8:ja$T'~bik2gm}IuuE7˥>VwoFՎثZ.X$Oa}36; =>Ŋ֚㙓Y 1k9[ĒpZ(aF"}V}>zeD*coc|qVЊusȸ'q|zcbc[#Ȁ &B)ǗnUdHm"S:CjK-ꓸvD7?\uFNq~k]"_)HIE e'xk]ߟ}, xK6QO^nc#9wbG;@ |7c3Œږ0 3ۖBH#ư{V ?Y퐭(8vD@iqi섎xvmJ'_?  6[ )͖shl[]fsnxeDx1:+ jfQyieh-r|SS~5@,D-C`ƭfcA똳VԠMS#>LQi֦/麝\Y;Ē7}C^ )O0͟dC)0ޑd}Rv>$Nzvq:d'mh9j00C|z&EwyRD^ P<|XMAl#QXfB̮6XݮxCBNs[xl#ć%g; O_Ӛм%v s\fExLXXOȈSª{ױ-@Aⵯ;(!d9pfo#B{w@ f!< + ڵ)."'*Iw`8bB2b9b;g||ER8>EZ4W6_ y7[`|z zz: bдs=_0_JM0ڥ>٩F98,`D)Y.AB$2a㹯 CzO 2y5Tx&j;jTQخ%x{迃iCID~[ tpfmߧGg8MƍD% !?lȱ D9e4DZB=*/w|S]Gs̍׉4g p+@0A&@5WѳÜ#&0tu" ߓQ8 "ٽEĦ Bcp]MYY̿#?F?#'TC զ6 X|.6zs n`=wGƓof̞6ߖި&]`)!󒗃 }%9eK{](|a՘,XqJ/Eݻ{dW~ݕ`؇=R#-3˰^#Ɍ| ~4b/:)mbKHkW5YʔC}sղJ-vgyΥyyP8A?D/n_) r9R<$z]c|ƿB_qZap i[r%zHms kԋknf?UzùT[X^oHsVv+Y9 L4۔)>IpomNlUKQ!XWR(bNa,|ЭN<6񏙤ܭkE6..SS,wX%Lɺgh,u]W GZ4rElu{7}s#q9+L;_\5v77@tK:A90vݔ\H/]fR\Df7ҮP>OSϋ*zgRrPUo>=|>ub..&J}6X8i7bgHԏnHtNzFkM8j[}c'=}39<0Y=XT/V,iS8[G>dS(ʽvۻ)(z-y,7~5r[*ԎW ͬٿDEhDWg@hCd~d5b{ȌaSr#cl'pU:DAs D5euSoBj(4U2p<+0RB0nT:z[{ю27h &蚔ڧA[UT΃3-0/_."=FMBsvEk|$LX~ =܋\sBVӽPo'ړs_Cl+=#c^xxOAOYw @mEc?Er.OEO^ٯѺ{m)0r[ZSrHE|Ǹz'h25M~Kqb`-2zۿ2 ;;b ÍE諯%].WtkG&XxΨZ݇_Z^S^btO1[JT:Ш_o#+0lQsRDdHyw)d`nZM BB!tN=[Pg%.|ǨC Ce$ Pnd q@0xv6 RW6; VKm:'d 6'FaAK)$R;4T@ҿN FP|2R*GM}"/q5{U T[윐,,PS}H>=twC>oEk^T㱼qDMVF/ ǫtphS~TaMSm֥1Ǫ))'ٿM˴us\:\|S^׮ f?ڒ GMoXEdф%{ӈWY3kj@{pc|o( 6Pܩ+ݻq-Q5y=*- 1o*\c$܁D>8ʌ01p3|\Ԉ\=N*ѽp5axQ< LܧǻuKZHFV]PBhg+XS/Q,q)TN̐bhLه)*B;0唴򤁱[T .k)lEQ TaIaۅ5" YCԐB,"g|cǛ&ج[t> $ԗ5-cX[ƪ ,z¦: S)Xo kk(PBrSHQL(c"?vLm*Xεg*S#)+R"'̦!;@ 1 v: SbhAwDr/I21;F,o(kPϝ/fJq09_b ZM@фB,?}=>Z'=CYH胧ՂE}lLA!Ռ.>J%OUfhmF>-Hoɣ0&9.4X8pީ,dKᗤ~[81 Gy*(` |z VHF0,j3zWOxP\urk Jts,"4ө?H B0=&"3Ԇ,TKLN[+<ψt"nǀ8^(4:-?/ψ>, nFzi'P}t7HDJHHLis"u$ZZrP_|WU'1fKsTRuyiR))'Q$u9>%5ZW*ѝĵN`wN QM0t_冷8,:X9}$HN|2;(u@{!\¿ kǖO2:ҢWZ v =dG>e_' f ؖFnJ䦒ퟖ:(uOdUQ%%La0 ώA;b6k@ߴUod6۰r$[H&Z$Lܫ2'Ϣ%qiSV(өc#JpD &cCZĮ#T ͇vru511H38!C'gq[i89n"؇ݒ@TUZGyѰd QcIg%垧j3l!Ot F*c}}.,|8L@Ζ,4pat)ru*q`펗0r#'=[lj%}sFYԟr{ʈ@ :\{,iFXeCzq+]-4:AZ9qMJ?u,^ ^B =GY_M䄰 b'gK=-H!1.|^&zQ#Xe!'z䤋ڔOZԏ.:Md.a0HO3 {U?) !)bF+JRH@9%-511TSP^_Yi6ۜV H#0ʾ.KE\FUξF9b-"ܣbhic88894=M駺 IK_bդ($.SB֮oVKkhC;dFK&P8fIz9N&!\mTE|6 sGӑqaGMbREO% mkOJӨ)}I,{"5} q;t5Q  FtɏZ}i;m)v#k{T/Gi:`YoSʎՓv]&=ļr; 34a@?@;/X 9?>|=7gq*nMyw a,s~RRxg^s)V|gV#͂MʣJW8+jKzgb<ީGRA z mϥ ,Nxfv#hGM4P=VI;U[Oyӯ kcz* @cʌFw]n#_b&}I4o( 6eU6"{;%(ej׫(ӻI&h/#s)[Ssngw.h8?R8|2z]zYbq $}qu$MdCArj5J vQZY@e'ǹَbS-X}2m٥;Poٱ`GfCx bޢs4Q-psg.b̞RӢ T`_vn4J÷p-]n~stbMU66Id bMVl\]8KSFu2H]jUPK lOD?G:FdA JW%mP&JZ lWFQ͢}Ztz+?$cMW=)nd)=04v `LMe|@!V5dKhE(6Z[F"20m F2MZzz"n=kb@ZjU/Cb 3^b"6p_$CW<֔ykFR!/N^R(\}(U}ִ#A. F~MiҤE \~HĬ 4ʩ[I k2u2p[#iٿF[?mr40OO Ktj>算">D=Ueijn%/9vMUL&W mCjGǰ]Fikޞ_E6SHkN%c%iU-305.ų9& C *$CCldK 9d 41Wɰ3QtKʌ^o 7ݛ,wYMr_RQ ̑ǰSS_cBRrGLѹȕa kJS+)0,wV)τ8!i罉 q2%婛 5O[ԋ [UiR&vՃ[T;kM;P_2yiY[Xs}Xސ)Ȫ탞4)!wꓳG:tŊ8( 燆aFUS69\mlo⊓%\LU`45]NѼz1|EQ6f{V+Ds[Ոp+f9`[JI -h-JP>+BE;|dn+[M S}TV(YͭEv N씫7*]-Bt`5"b3Ugx,VE95b&W}wF}LGFS">H Y&5`0jRdI1`̆+ZT {{=.ɥz[:c>W)>;dv;{kS/rrvJG&.x{Ud8q:uUZ IO$ZvoAhnp,J90́kTuӕ|CXeW0X/%)h,ց`kVdNƂa$ɇy.2JBdj"=cO~. -RWw-HG8x,L(ؒJf-WlNgfif4,b-u-kqeUIi&&Ȇf]uW}=Sړ_ɽn㘦 S HgBE3DUpTJi%*{4UQ؃s685h'>BƒXapT⪭a[a:6&Vt=T,\5]-Aw% CIRaÁ C52ACB,+fYIgC|Ng~JT.zpO)6Uinn~F^` ";y ~JOh qicT_ڷ7|!Bb"ՒIYV!hأVP;61` y;4NgEd~؞]eezCD(3t O=gǵĔ }>6xUW:6oEρ1Z&8ƄPKBl;^m}=G o5[jƟ,Zjɪ= W' AQ.oMrDcAtR@Gzθ0*h4nN)`Ҿ$뫲e8W9D(>lKR'L21E@[pm=x(+g~w+e*:kc+'"aŃ檉25f?OJU50?Э2nmPqy@뇴r00p*ӯa!%8/ 헞v.r)6 #gb"Jtԇx+/(Y(͖0xV=fi \nWEx[DJ{I֧ie0i!8O\yjLr [=Ē'!lG/[Ki> @ٝYº;=W(K!Rn̚pƦw ~IH)zS,"I0` ]9u,|-<1P8r ,WJ%zT;4BZ 0#bnMH^,/!867 :)\j7/l;}w2;&)$i }:t(Ɋ"m IlrVQa,bpD/I /#7W4&/qJ3oQ*cKs}_󋦆Ul4)>+5O)fMz0eWt!A/j-[.S ,~՚u'SSr4li Zk:;4z>D[Ԅ)Y홐+Y>Mk<~¼+G]B\k,ɬhF&XdsZX@d1S 1K\5♙`&8l9ւe[f!j9=vk4 Z?tm9hW&:4TQ"lW.)5?0=98Vs"D@/0tLh*{(RcQʌ~:˘RLtQ>Z6lD/"r[v6G Z?Y.,~B;b5Ivbu-,rƆ-3Xw8Ezqt[١sXy_&dll߮q=|OnMrա1j?w[< m$/(BKabٝl$BPof2scz)m >C]N'lkkuiIIјwSi]/rVjZҙáZYz3᪔LHYӺh+t<0'p L蘌>s5);6}l [Wm![avE 7PK&|Z]~9  XY!;hJk4gKt6u-Ish0P>) 03tgBv٫")J_[^E)C(g{!nfWOC]oOZ45vHQJ"8Mu0%>IDᾇmNMAp39gKd+tV5.e=)=so#M}P,T2XXV!nR' !\ @'ZUN5yFa+Iq)ǑKxç\AqeMr>lp$(;ri08ƫϬ9R̩xZS"u+/qWDX&1?#%N/3F+ڈ{c9jOEؠ"ʝ(;݂Xb4!EU;^L7Xl4k^NL>ҒRbyNs7A7aȘKLd a(` >O)Ȓ5ffG\t[!&Wo"ŬFzvô@t]nY6!L^Xk*zGwH?bv;U9p8v^~Fq<+Cwj5u`iӪ}-]sJf-[4>ÓpTjlӝ7 &o.mkcpIme)s@n LH~@븭A_£A `3}. 9IDyO( AmN{6rc\o#4nDJX ̳+ƚ"Tk-+E ~aʾo#ՈjmԐ}X7? k,Wu(B?Ձ81( 1K4B_PW{+%CR5w fk q܄8-\,`߅_Kc %8y1yfoy^ޯmF(]ީ`n, L{iϰ߯e~Q9nUVrGRɪX!$ev;S_~"*U"kq ޿ sDnB{EE'Qiob񤍺ɗ=U3 ~ Ex8[B ۅL}2aKH0@=A6&'nNX+fNCGH`Qi8=vR30&+νʺVޚ:o@n)X&`i`MԋcmT07ΏF^JַKnRFQkR${%_Ȁu,YKPoJwe(Ym2c`G}gB04z:ܻ^B{ =2ri|<:[f+B K-YVa*H6!GO*$WPbBfcd'#EYuM v.q7ѩ=䘥\6!q&hҭZngI_11w0b `;fۋnR 1Le|$/pH6NĻXi{m VF2]5Ƞo/xr tŗˇp6-۱DLK㦒+urXܢX7Q cpG>R$;]S;ӵ@O΁/Mӝ™L-Zߌ9:u.hsZwGj c3kd09gxn4&;G䆒 g5W;U9ڒg'\D&a}VV,\*aZQkM8kw{gFFerZEnsb:, NnC±*oz#-bQR$4#6.wvQUQEKDg[Ny Q;~d4c h^HoJD1psUȞ`K}#OJ?Oa.NTJ-c&="l34گdmaZat%:rμOⷋOVM*=^vEJj;LYϪ5KL+˴\20Z[kg-yi1e6\^QVQ'=)w9(ωkQl3っAط=+78bP]^wvFt>qiXBi $(/* _$VFa%lG5.p+#GwVlJqu,,ClCW;COe+ힴTVظ$;u?-![d0j܀޴CSt}[(HEIb.vS$L6|P(mυ-GF\*-\j/t?/%j^"J65ا,l=B|WVX!Nc# dL{>ZqޅNkF" ,vձAr9u)/K(12"pJ=8avMA(5J$ɔ8JnzӗӲr]d,ȉbof)Ŏ_ ;JJDCH wj*KӔ&D"@]ط".,ɜm6ZqbئueñL𕙯_%]oRvϡEoQH tDq%w']ぺ l؈c 0sr u!︥XJꗕ*V4h1!ܱMr+( K@+wmE_~N ]qK2)M['+xzK^7&ܡնSX\R[nV}nnӨ ʃ uWƬ(޷ !&HNjfAE-o\ZY9 ۔w$CdjZ. _Nhk՟7w׺?W^*@R,t?.H9ȓGP+MӲN^{XY >#1 zY :ѻO %zuȆL Yz?n9BVC5DžY7,( ֱg>ējW 8 INk8zBe˒W5P߶ oU.hV [5I5alO6WK߹"6mk*잞Qk\׷ًNwsAR~ˇEVR*ֻ>r̼ b݌\7ӛM [,/?Ru&%*z5{p~Ȃw%mKT1㽕Q^JKoVUA; \YO`T鏤@ xf@fn:՘1@R?=UԊhm1K29AKDfYדV\: P A͈a idAũw :,~r.KuoD](U9 $呐Gli:+XҀhΏVckw Q5YFn`2]Q}a\*> VK{ &s=\ҏSOq_/׈ I7OU_pW>fw/wCY:ǰZ?}Sez?KWɢNE @t4!wHY5Mk HJEô:4nRdar.j)KS)qL5& [iiï@_0s*L/W8[xG_B/5T/ -GMpI\W]6CL eXsp#11!^CKCx" c܂ gP].5|Hsު}Rن07x̬R{YL g >dir6Ut#E$܅I"vw< A5ӔN/ɦOD""S|AVօj gv: s.E:Oq>jEң su I$aN)GۉLۋD_y\"$OBIIa[ZBCWPR~ZC%VUۖG991%cU&'L׵MǦչn%&'u"sma ɲziʸsj̀M1ra HLc`s6r''‰ j79/=>G8_2wIo1#1ٌ5lSa!dH~KMlOfO"#G$XG$\\6|S;SK ~Voݔf(ʋ kRTLNy4d=:}PDYYU 7F?_O(M\o9:7t`A Dz]L!Jκ>/BДK ׃[KGw4grYՅYޟU<0, t)էdKl g3g\蜍:тa0yynfж@EˠN)dqMUMM#dizp$p74l7Y˹s'qKEm6,!>#:H,LYTH$ގeRUC}5Ǐ G1J8JShkO&Ep&_QMKW>Bha="ՄN=`֍ $q4?ݵzd}ʳD~8@36W㮶emPi"Ot -tY!v-u} McD!"4eϾ]}/O=զ&\JI)-{!mNUgkգh |I=(Kӂ6," Թ ~ٟ]mEԠNL>8>.mD+ 65ߖ+2V鄷zziT7Z<+[eGӹ$Fꮶ{ R2bD5${xof*ՃUɤ7odVC|G* YE&=VC]O/B/ylхs/?7ob)D,2|z.j5 ',:`^VK-Ǯ'nG'> M[O( ?3 KVo_&F ]ikKehKZ!sG|%;|n;`yP$+hG`HKͨ} S8vf__Vl\~֜W8SIW$/~p2_XJnr oGe78(*G&3& r )i3ed3A|\GR6R&fr7qZb*.M/.>fɛ\/l)qEA>ZpR+s"5g%V|eADlϬ8d'˝ǍNA_FEq7ƒ-r?f޴_c¢m< .i*}sp)BUY5"jk ;a+5 !ġONFmfYpņvXk*'[0$4Yn_d71F"ugیgGBkg ΫD'K~e@̃)lt!\nQ #l0>?Xu4JmҫѦ;VKCVou#f@b3 Z+z0>{GZmxm ۓ*“]h, OH"A k~/arߖr3PDp /jcV)v9g,N&z67 Jm}V58[_I燺HUh!%qNx- z4lF7m@r ߿fnh4,Pt=ĝ-UDtTl$+ڒ\^=qΞ >9 uՓS'LXe3T#ѱ#[WqSnP§eH/$W03HrDcO$Dh}Q,@t RRP1\s:?au eԦ;rN"#A}\6}f9݄飔:؍9\ djX%c\,dHIethH23,2jiOStEK+m`N-tߓҟl`W X)^x&#Ӣ Χz-d@LH|[EbsH *9e[Y6y[ezfԪp|9X cY}.VK–K=aeFpyrR&|Bl9<8¬=K9oJժ!{Gh5r_ݬ 4]ICc'͖gPXU (eY G^ 1),հ ,p=`hvopul< QI\E=|pC ) ~M3cZg!?n.r .$D2Ac.׶1J1U杇"#5[ӇLá?Z3+!i"N2 ho~3@ gߺ=xj̱r$I=9$d(yFT= !<+%0`~^J| c%d…Fhx?FE"О*BGsC >W} jᦷH),?FB͊zfQ^#L .x5CJA\ ZbqY+iKi]IŠ1~_AWO]8MCˮD "e͍J w;u]< 3Ն81L+V۲6(YZ}b%'* w۶mac۶۶ƶm۶4zֻ3gf(:a,`/zDt^4;3G> 5evHxXQWS#.\wo#B'3;1y Tֳ<(sy#aQ~'cA91aAK4"`X}nEO=#sR?_EAagۦhb@OtgpgO.15vҭl I ]A u%r#bM mCA*2oW zVД+ {' 8]_eQ|:B}x>WE.! Q0_hP):18/QK0.ɰA<ِM⦉-ܙeKkgc}*sB%|~ q%etYzY6{6"P@HP&S5Op ǃiwu;*!0X k.>O$XIDn&0 ,],L;{{|2#܄S0h*j! BM+>2h^vfBx,t+"{VC&A:S흨Zg$M@~0JwPqHUOQwzZx8vX63 딍Cۉ{ìa*ևH܇Lxֳ4δ~|fwҭQ>, 7-8N >̘s"JY sVֳP9ޔ ͇vE iZ/b-,;mS.ha ay$S֣r zb,w8uq P\uaNNѺR0CH+%"ʌw{(Hc(:ĕDW(hܷmg񟳷A h!\ߍ\nLOKsa2ulhݕ_t%!41܅u𥓾*Dŷ0(pٵS#-`ӎ_ ͙RY(m \ |Ltr˻2|бk*pC ]n`qӣ/خt)> F\(i0ؼ.&?bJjGR/Q-uJ_bxg'2}C[ڙ^Wp/Oۘ 4pQ-h80E/QkxųYw}C{[6r n(\YS)9_."I^:?Uv|#x;c\Y|ꭊϕ//Οq S:1H+i&Z\8KycZtrSOivLFB1^K%S Ak5a/-P)3 L1'ɦ"xzm'橄~N&HgrΑҡ:#5}x$tɂ#5.rbFHD9Miz=:)c;2Uyw#'wF3nķ+|f7~[s0-GU3Ec뭹M>n*~;gCo3UprlCn۴kwfjl7߼|$h=/P/|] Y;_Aُt=Mr8-95gՆks5j qiu1nT"p!-*-Bgp |cpŎ4O8 >VK/t?2iL~5r7Te.W ȚtI_F =dP;} 9_F:7lҨ\x\sD訷j8\r/wjf>@Z *w޵n{ݮOF,j~c)}Yְ*4v4 rY|1fɄ]QPhT{7pQu q6bb T,.="q?tMs:\gzZ’ (,lNFC EZX^ o_ Ӡ~b*_"@U;_ W7jl` QdT>eWsdl;9(Vd s l s!I4"Dc'H,g#iekx̽KTU"L>iZaGch@L}?`;b:u?_BU>N=HWV? 9U\.]em_V/y6CS]i ͣwM:-G[6\7 Y"EUP|Վ.e6m^KnοHȔ7u8՜ۜb}1ڭ"#2k>V~ʼnm/P,/(H  y d;᷀l/wȤF [Y/mD srȿܵ:ռӿ1$y7~E5.~o+ hl^dHy_s=IyXCYSKYקf360zX Ú] ZX Ú]%/Lٙã ]>_0eFnK~dF;?481%133 ĹF#8\w`pnlٙrSoVZ ܪ>/ 2ߞXi_ ַqsb&r{`wv81i J^!Jatbߌn[柝:Apg#i`r?qt8q9A wY" `IN/0{ Brp/K_ab&X8t\V F@@ÄbE*eJlCe3b6r*6=$bF`~j]C ᆾqOE'JCSDq~ \S e'Ђ܎[uނE]^ӱgO]%aQ}5ig]e;\ )8lԮ!Vxx|NO-T*a$ƫ^?M( %97 꾬5Z*(ӿxqe c!dP:0soq,*@,JIfx,ڹNá-rcѮՏ1d%p+*ci.R19,Z+S۶'G5:\^ Qir1m`oCIPS+ .w]&`v8ApZWV?iTuO#XI+A$Bm+<}V;ITvs;w]<+aAo:iӖ}WHl n#`Hd= IذE(M6cϬ@Ŕqqkb-!,IɉV*[uiqI8>G_)* u, A3>nT̄9p?涁ҤlqtmMKlRh J5g7rk;YcdTM`M.)2M&Q ҢipxSu|8!"]e=-:]{&piBMi]M{"wRb\IhjdMyMUf52#HAuq%QBeJzzu͉12'Ggb3{:܇1?b>֍t0\E)1;lXoK4rrqx'(*懧ͦM`~R^=rN)'lnm] av9z&Ŷ娦'f,Ku+*| E"*MD;)*'Z]PEjpN2Qg4qh10:0:uSL&'Krs)$Tuy_9sKv@j 'o 0}2VWw4rE]^z3yj~$^Kqlж2aXk O?kUn\ ] Ƅ.6S?Ri RL2/REyq {vG`(gJ4'ykǹ{=wJ{SZʋ4+(ꭘ 맟IK P2$٣(|sPeycdm=vWP"+-}Y$lUieqm@K%7[ra7\rl|5'd%,J$zsh8[o",ǝPgHLGJ| *[4{H\ɒd`wX؉.ؿS2KH_M̭|׎s{ gKrP Oʴo[!;8!2YU\oș h:Y Ṋ̉#Be,sr<3x7%7ۢ9 VV[A\n M٣ >׹.inz9Fe^)n{Y~L/GQKpCKy24'"+&fT<N,2͒B>wV5E˓:S:v_Zc)a֭87S6$v֏#&! =RG})Yo6:[zU|A-IЛ!O,`4T}ŋ wkqVc^e B9v,߿r[BuU,;w4{!(ԐQsCDJ˶`ăM<Ҿ%~Qs3pDrRLMBjGs>_bqQSN[\KKͣM ؏FRcG 1'#쐏1 DjN7YxvH& K uQҜ^>d%l$wf]DƎc 2j(>3̬3U͂B0#_yX i2PID& +8T6vdq{!4[P6lZ/j ~HT}LQw/{"b#|\oМHP{)<ΰo4r_2Pus|P"[n\QcOGgDBSł{ T{H8Tx(?Jg5aHx\yo\P5xagrXqJ ńfɖ_a2$fCD.^(4k畊 |QM,mG$-ysG;+S@a Ѿ9G6~+)6o3qC\jH'j 6CXm=Lﳊ- m&LƱP_~Ա1yxup! %& Chf$;LX^l$,VFORbA;y>D -WX_Q,,zL~ABuꠌx{ )#<}4ˣ՚}\\fBhsG.޾y1u ܾ͌r wBZeuυ=l&LDBҷ<; rQA ,UX!#e|WKN9_aMr ܀_ Kg^;WjY`zY&"$QS* 4xP%:! BSa(dcUlqQTB3u6Ӵ/QǰvGETxSV1W]A \-dIA:'[eG4qώH9]a^m T!|w QVP+`\||`G@G2,ߔ $.cW__\*+RzZi 5|7b|A.0'&@{T*pɐ#ZfC 7b[UF KЙcodzwӄ :'G3j{h7ez}Z4UEi^%F\$\;sڨ^I؂Xїdo~0dr gL "zvhř9fE Qi)¬-Y 3)Slqb0lx0J#ᩃj ;[hXΔI-HkMሕwiuA~zX21dPT#R#oPCb9 @]Y`8bj8¾hx£YyYLAjDm%70o":Tp^M 1dȾEx<Ju[jѳ~ˡ$kU7ퟷ>:N NM;Ko O44 gk Y"<ۂvݨиFk Qǔx(nE$tC6}+{T@<ŻȦAv2h[f DbD^_frHQDრ?=챫Vxԇ2-C"eԬUW2PZ ~٣PդFbwL ժo!Dn–SE1 /"=\d*NN0+:y*JѪESL SW$$Tl\wBT 2s S{P3`EJО: S->KCܠG<,i,TM@"*dCFׁȀ8>`J;824Ӛ-50yU`#%ZNoyCf,5]Q?߾ɋQ>n+'RcB̕s5:`>=vS~Ͽmy~_q}i,x2|o<)cv}%czs\J>v?>6~ ~> kЇqnF*t= &5R_gMvAyyp|ylvõvbZvma ɓ_GgdT_>?_o?_Cpo!_)EQϸCbho>$/o|hK^M 0-6?{jgZ .Gd)Or[V6IQᥑȞI;6*MߧjY*.4n}F} =еۥZ&Eqχ\{ S93q2E?7|>nQY5ww6?鷟i?s>Qe腷]ΟmC.6Nn_xi^ez]}+Gors7=O{k忼C#eH&ɤc'1ѩl6Q zk?_ ~JS5d|?tw?%|4vϡܻ{5K_R=~v>Lj|tV;*2?nJKO:F2}kcvɸI^q· &'|xnXkǟ$YbϯOܝ:YA2ztxw}<=t iL:@)3H8M4[OmCٛw4:sH_h<.=NlA;R\^8Kh $pg)~6꘠} cNz:]oy)tKϋ"f:wm9ڍ7<=ĺa"nj:XE U`9j%uT;7s OR[D v:%)UmXkǒ]ڠ0Wsdtm\cSݧ7^XSQ2^9v AY[2k=>x'lGUq7g8 IymFП:em()<|jGFQ66HA+UöYx[7Y"K9y 81=m'\$a#\#OukSl>3YV?8iD!mt }t)f/OF<= O3Lʖ_* k dL\6pnCsݿ$C! q x tC1/ݒ%uh惻C7 CݒZE|m8*%Ԣ/PK/fHGg,)/eJ֬~즧 ƕ ]TE|( DipcA#Ѷ|EV,Z*wΌzKgfSֵskkQ*R[dQ8huSD*7~u_R$`jJN;-`f 9ef6磒q^[myT5ۙEXxe5:B$ ^F~J[iZVjJ/Aex;M'_eޔ.UjuJ-.5pe֨5{yM.Q# Nqtvb}殣](Xe0<85oGV;Wa=FHbv|y|La$i嘜-,n1BQvm}?G4 x?(J6]7c>0kÛUm5+}|y :Q4(j!,ymukSKUU*ܸl;<+s>?wvbڼwp)"`_;jr{М†B~3#3T3տA6t `5m+k2 ՖаSt7~nGȶ/V2:^3?\ͻѪ>)zn;}3ަc%ՉlK7?RQ5tn;曙ZٿOGcw\jyco 9ǡ%lWfл1p?`uZ?s^ ^Mz? ?Di`4GX&Xk!sA Jon4]L(FMOwxNˌ^%ΨtE2֌h?7ڞ3? ?h=eX{L;+4)X[vu3_L6.vFۭQU߲5^F rF<zOhK=F]q)AFbz-9b8$R@8~ qHbN.Eoa "j²} Wz "3O_(m?Վoth]IJIz!yt/ZzOپ#)6͓&h& i_?;c{.,nYyћ ]QCcWE!jǷR3塟Idw e |dQ`{t*ZT˺PBߋZ #@W遶mJǕ:[) $/5STBT~z'kV[CyqlPSĒDjҹk;*X:x9FI0Ǒ?2`Cl*| ;$ ,ᐈ9x6x%Cfh{%\S%?2XGP͉f%ۀ'wڟ:=eszʔHؘ͆3eo;$* %HI}mS@*1ahbs%ɋNէ3\x4+D҃i - !d"iL{4L`ν nѩo W_+TJMO`.\qq.I`0 *O qjQ%޾7Sdf >!U?v`X!s}l+Y,|R`(ps45a ^= B ++јㆷxcUeKEԜ#\i`v2cr2ҩ&u*8-n2m.Cr|TRsVK3Onw+w vz7NH{#K1=ÈÍ"_w7a&xتipdhYƻ:yq _ˢв\9pknb({ #Mf-W!@r9FT}W %[_} t&x o .s[Rk֥xL<ҝV͂l$L _`7gpr%,nrrKEHIatgy:wBc9hbnavfp%GIuZqقZsK9Q a`:F n4a*]Kj/{)kfҽ~A "1Ps8frtX0JT.?5 >I#m cc)aߖoܺB߸YBₛCO^{KKÀ/ A0GPgLܰuS* 'EN&K ,!~vV>%Hsp)PwLmAN?]1gr^F&~+oD`vanK:LpT{cmwrT^wq/P*!aII!.ջzrCIF0~o?\P?BiSjDTli,M]w }7L*DfO 2gL#%Ǜo7b\@MMZab$DMCu[C)IZ=+_ϝ.4&Ŵ; J*`硢/{9g@Fхf13B}G/ HYƚp32>PYHXвK~,:??rOk1%<z)gSJ2KX VhM]V,;UWmG޶ ą*@Ϯឩf1^h"ذozI5PYG ZGqaf2P,ܽ|m'iݍs¾ن^Ma#E'AdQ&~AON5sWsw*6[{h "2#bv*b[b%J"4mql*3RJ<8l"Y\浧}ftM=TKћcօa;`~)S<\%?F+,dIXVW­{xߴ8[*8x3m /|cC\*0a2vW s@E9 'a ClΆxn`QLb;<IKrrˑaw@Q `n=)ImhPyUի4sgIg,|N?bOg1XvqJ SI\MBj sF31ط/N 91r#yƿ,ߛ1;u56!I{W+Hc~n-Z[ +^_p|;z,am|iq).Amݺ\]>c[=f|]刂ORpC*ҋucČ'8BXHA>\ƺm )Zݾz.}3Xd` oJ"| ۷V3|d_˯EPߋ\VL{\Yt<=psQi8&k?7S?S/ IÜm&lC{YH_m~ե#t?4\xp,uK+cHp?O.1ԖʌrM3{@-SE!+@edhGQH ~_OU_4CPdֈ WW`nL\I6RL"6WxuD%} 팕'n*:?9H;F *CZm|\S (XdWSR54$>~DF.+;Y@]dikݴÜHȣnsSӥ]] R0K):YRុmMz]~)`;ڈ$d(LtS`8sqbj^UgcLlݩ=\Qo/*O4zJQ,M0%E??`b1sBNu*X|<Zۗmz{Qr`Iz6 =)0l6H_8|T Ct[1j~aP)lP~O*T H:P 06)GӌZU. $9Q5jK9%*+d~]& .Ҡq"R/ax:DuZ0!jq" #!zk6g M;"^X"ɼcjKȁ$BJZ]bq7&az͝PV}Rf<%a@r8?r _?^!Kp_=,O f A tKHV9KO"in,96V hF! ~q,bb7J&ȥAJ]UB+H&\8"⸓+j-L#55]vj]e|]=up {uZzg8j(( YLU-.jmkPaK DKUVP?W`~XriW?f$xFl4Aۡ Zܼ 7,Qm>\%4DhzCX1[/膠޲Yv~62Eg= 49rOYa :}oy9y 4W`øfkچ>$ijzcqE8;OlhT 9K@m`]NQ6 A[>;ْ.LV"΃\%LHKS@(@?7NQu?4L`:VCi?8&UBj:V"ԚKbbY.NZM|#|P1*-А-)tl hTSw#RM؍:Vቀ!j_7HM9Ih|kZ&0 yR[wiSgi_xj9=`Jhu#C㷅گE{S+q72Ŀ2qޘ5XฉK#r+"/u6(ƛ+>oP'_'<۔/GrgJ0\ noCx;~݆ ?ە7= fJ@B k%% Ya\{ָ&Y9S0``JbP2"#xzaS SʕU7bf]&D9wNX-5Oct7}[큫LBw!v>c[^˪)w@4r"p5:Cg|!F /nKYDw `b #96^)C ZIu\8Kiu!255к9labo]ؕ=7ˢs\iyѠ3!>Ռ~&ND Pt`itPdw8wNv8s77偢RͺZ?5`;*Zy%Rĺ? ˍ OӥtǓ g hJ`5즪2[ SkJ6R1v8A֜-5ങF񁆇1. M ZN\=91 nkI`U4aDZ.ߊbZ9kCu(KFC[B8qskS|~FQSˁNWl>wa;iqؿzU_'-)OJOGT.pч̔" 0Va0^_15P|dګ 7 ֶѸSW"cu=w(#M)\:3^2ph*}EǠ~4~4ְ1[_J(kV@Bwfxh _[4c߮<I0 џ@IJe,ڇDkqpw2>゘Bم%R`5lpRDy!ܪ~u|,-e~3/_NϝG|~~j_U͗ȮQJVϿJ/kw _q0gģ?p/gGN5w_jvKXJ3(cL-,ߵ`&hs<)%kQ 3'eDuTO8Jdчijs]wͿ6L_0%"Tm@ pr6kUF_#Tv|F省ʑc%<8߸sE<Ē}tO9X>G Mޒiê[)6LLKQtYg?&e~7oEǛE// mSpEݷR}]f{7@ݳoȩT<f.^,^ddR:(RJehʨL=%YRd{*1[CJ<~Wb#?CW<~Ubȱ \ 6uЭt_ dQdU,E|\޷=`"#\.V'tU)@:D@:R5)8h<^_ꤜ,RGP:sL?$y,rZ;p\?4G`9>6lbh\EUuJohtwʦK|]ԃʘ=u&MkUE!C&Ĺ*`A%Ive8&E懵?L)8pd2+OC@*1a s0*=s}x`Dz.4qxeKB^Չ>ͷc%Ch`%)K&h2y3jlx?000U˺}/\Ju  /4钬˘DrQ/dIbE@66һ7}B@dq{tixR,%1 A}{X+ezsCGg hm=2 C6AIW\eoQޏblߣײ,zdpy]+NvP+Ufg&$<(_r+=!G g~H,8+x\U#а2 ~{k Y>"X^ڙB1J'?)5!d܇dSm_;#*uR60L_f{e4V`,>K_'H=|'LVḯ&h T=$"P]/#l+ cPfN.D+` ]t>&,pbŮu炠UbjaP - PN.j8ɭIs(KoELa ķ1v8uc3q(`<"[&mDHĔ&NCfEֳ~J, C!.YOw5ԂΓĆ:>9#U\ӑc13vS@+k9Ik"̙:EcR3RI?mz;xڢSg{ ~_)?CSW;K@4bk ͩsLQsw${d(l]<'K\+ap:>>ߛUf77b I]؁"~5.FN>UmQCAaռSVN CA^,\(v*譆?Ȱ̹B(y1|TLa"VKxA|="Ffgޯ]r8 ^Q ϥd^ 8ZT}kc$Ayo{>ޘrT, 묅Dꌬr.NCw|bPT IAQ ysHpꁁQ._5$ ;kYSf.is 0+I=gK Ƃ3V&dO:O~μGYJ)`\'&̼ ?ȣe#ESYYASsm!1_ѿ65p5xrcYaJY2gRpv-9b4rd{}:q20e ;Wo\{%4 ٰ*)er (H~p OҰ3Y q:^%f`ߤ@蒣\>CENMꌩ&h/tDr,Rﭪ{%x8ZIb6T+f=cQo[wQ?D9E,)ِ*jRnP.$xD$Ud[fn Bf -0HR_RXοӫ`g{km&$ey pDBgR&H6zLՔI@CLJ~  ^ÐSIvP;-sU}w_:GDMT-H?\t`{~%PmJM1FHE1;zC@~rG֏8A|% ~W{ĤTyoWmG@[7%(R@pBw¤}^?؏='le$(PIXf}%!ƕy}&\m7)rhsTER#g}Qٔ>F1aC2'Ry]Z)L%<2ėFv,x*ۇOud=]/z,w~⦡/bzK2L(Q唻V\fsp90F%wҴ/phdI>^3U.15Zn֏$vѱ'_V]\L5We;/Xӏ]Ō?#I,Oq;k:w3L}DyL B&##,^>RXQ# /~HD藬\ `F(-* Mˤ6}э 翚^Q~'RnyD8nRw+1i8s=TT]+]H{:X;Knj>)b7]#C*u72WGn7;>R?nv/J3n`UP19w{]ڹUU3W۶?e840!1#j8Z &np#k`-`cNti;gV d>_>Mv#|ֳͅ+&Ya@x DD p".\f·h|!%&gj ͳ+PS|ž*RCCzB1G]UWoSɮONustBC}2֎XcsY g79 Ԅ *mS^5UXi4ei%0f!g#"|d硦ULܦ^z)31w9+Nn/U;4~*x"'+|jpb;/5b4*K5'Sbyڑ=j+PK)Nl,DD{&X'K\U8y$牾XC4 ZR&0Eu:VC{$e ,^p!yb *SM,TN2110GrVdR s=F16be < 9g?A^SR#4]H^"DCxX\Y.I ҚH76!UX7k)4+H#Vnp'RWK_8V -ͨ1_8 Fw#+p{ G/|95=a(yJcyk`i?Dv]uhޗ :3ɬoӁhtLdq ;PVo;vu@IЕrg͝(,;zWA,lNpz/pd::no̙cɾƕ_ $5Z.Qͭ|X+/몷[&GF{b1WyO _VT)O^r]-T[zp#Ä.69VS맊?Qk@0c#xǬFc6QHr2*d]mٜu#0S nTr ш{F:Ap[ʹclB̀@-@]A?8Z u|Y<<=3x.N;{r(?+/Cgah oTec@Jre"о_dS܅! W(eH"s5'93`Rc k6`(`XeEc8d u POU6e)3` UxZD ySZkaA/xr\O46},Kꯖ:!ן9=FuWLM>XCƼPXQRp'(Ƣ!mM& zLR_$xF>߰1T"z,g G,~V=Y%E'좽 jj\Ur{ lIBKhQ(T>BD3B)%$TIB2, )[OiWVVTAr w5p(u뙨hЛi!ҋds,Ƙ,MQ@}}jlr'*  }MOόfwz"Jms#qN`j4:^ӷz‚ bPw#;<0a|)&;fe&tG?v{t0c;چJϴAGs|?E<ݠ/c/ 0.씉C\yKo4TxFuW:/SQYRS2thS`J۩*ec\bXic $ cr CILUt3޶2T CI7IߺxҠ̄% %n[EU{lV;bY"9~V-^q;L :bъӹJ~:>ЩSk.DCLn7SR`x]z[Dgiyۖ#V™# TG,ep&K<&r)&t]pljnEۃVfa"3&0XRyL~ZL1.#I 7~qųT|RFfvZn`v%ۛg')?]fۻpfy}<}}N|>ߚ?t>׳>t/M}}AU$D{ Y;/cUlVqMʖ`{ g.RJƍhRc5_9a׾)^&V5{q*]@0QER,W#uR02Fk1J#9=ث8 ,fx/G/tl369M3Oz-R#?xun4Gʸ)"OYTʸ1 lا.+ue~/#ʺ`^޽֛ a/3?r}^74#,h %Q7uMl>xdbQ]wB\o!@׊]\Ү9#ⴣ0l2O,bP,Af U?`|z+ɖB )w{x|.MPxVQ*'hԎtrq<"w(@ҊlV5P{',3wTS\F_8p]'Z3+z3NAy8 jBX*P*W9ܴc}h##sܴ(.hޒoBAܥ4=o[ q dXI0+,$ױR]mr +~^Z7 )M][/H5wӆH)AjOǻǗŪB< i*\WK~* 6_XG̃ U)O2U lN"^"6TϽ0 _Hqo=HP$'j{bhѕVZM<>oީk>7^h꜕!oHpEj`aauzK ];ws/"N?ppf+>~)X497%f9n[q]=+Sfp1[Wwu NvzRl {߭HslwNRrɘUMN%D3أ-$lrVOa!:EM s8ܱ>C[s%RBWI$Y @+ !(-6P4145hg'R88sͬ37?gX.ZU^әݻflߢ[C)^ (&/Xp[U/2!SXh+Tm'va ÐQ r U+e*E2yMvTk-v0d󯲃 NNvclzTfN$K (b{9Fl,<1̠&S" W|VD A.(,;zCjcTfQ.j \xx ?Us[qDj2DyF_#(VS@gѳwh˷h_ozƢq73}=2TLcwwR*K''' ;pYEka7IYǨa!tF`0pcX C oKaAǚݵ8jf5285+tb-sg(˰uPxJB,}f؇:-)P3V[@&sէ8)A쀧ζv6B̋e/H䠫@7mزwL`) 5tkއQUW5 $2 ƅ)R-aFI U8&Hreb{;cb}Yᄉفwa"I>ֱE]D%.dȊW(i,B'p85U#AxB _Q<>x'n}e|dXaibcos%1YK/|RpIq={HCn\w ˼c#w?nxq{[VjՋjzQU#"E mu %It`ϱ$/ PGzSRGZTqXrC`?=]v]O^2^:&G5Յl%NNo [y`< z}D'Rԓ̐xmMmdZGa? (>s #]fhɂ0^oei5"W8˓2=^ZS#q]B=ͯa|Z 0TnXMKMmH\^f+IP Smbv'˷H8`uhFP4/<"FMp9`%<<*OD\~ϓy6 x!'뱞s5˯2H[`]=Gi[Z8$T` @8N07)E8oaħCT eX$ELeMXǒ[a<$G.rJ+\p= OF!*oڹ6l6% v jܷ^sY]o^eڣٞ%*~V( .t5Py0kfuz#܊ Jg- L5JRq80uA! uA"V$ʛ S̙#2_sae-{Vvu0 tӵM{i>~iaQA)BpJ0ήD*dgrD0`>h+|ctԍ<8,\ju"QﮇFB^_N끸P{Ŝۧc{:K`q# QaDPXXt OiBНܢ5ɇz |ޠ:$๕/t}} 2ȽrD,& Ɓ`}z;@H 0R`dxw poaQ0L)K4D-Vew=UUJmOɎ) j |IK( MCq_ѳvp" 62:=ANuP{Yx~7;RgOTp,&!4*kHf߷<d&Yă~>FdmLRqb^}caHrQYM;/ݝRX7}v1slfBG_Ec$#6Bcil%w6g IH^'V}cȳg, QyBэ~>jM,JBJ>#TLn8NE(m( 5Q<0P?=7 "14 v;F9֙cu GE9zDڢA٣ 6.PYf&UBGTzҙDO!m"$uE|p8õD-͎mD6F4c:ZG+҅@3Wm~|pq@5ON~p|TS-4cι.Ɣ* ׌! <6!DEW.ԘWW %Id!,>WaWf VC=Czy؀BMT-h)/Ş@ߢ]ຈVTZzVq&{N,iXYC( ., K"0}MagM' wLN`$1ÄD G?8>m!Dّ, Yas2tGf#)Yt& ypڬhX-WA Tmpsj/cZ\x<%]o40+"Kdv͸v{n}>(.,?F3q:b;aqX}e(t5J⢴3Q+h8s%Jn_P|Oڡ{oq]%2rAH +fBr{ojuH4uP lT=o3)>Z2Ϡ vz| 'K MjU:(yMGyD6 7ⓐgʰ>)x6TBJߩ΃RۃXIH'Nl!2E(%u\҂`Z꛹.Ud;*YloXGo5Նjf $m^_[{[Bs-:fĞ ij*8qH25q$#tA!u!hiTlXRN=lbk4Z $͗_,@.aTYpVUjc`bK8,j0**̃yĄBкo ?!%H[^wE!j܏ UZ|qFWݚ~0>Z3 }f: WzNH =jR0dc0w@DhR$yG`1UϷO_A"j] ƞ[jڭ;#3Qpq k[YX^T{2MeɄ~z-veѯP@\ n@+âQ>"8Jd)~;Lވ^BFJ+رÌC^08w@u煤7nÛČ~݈?By;:Ą_q8< @sٲz} >4` ڠR6>F j=/}o9I((3+jR: o$f=13i@Si. YT))MgMBdg T IC OtxH=B>@h-[FkmZǾ>]>EcCI*1,fE*NOzR'/iENyUډ[o:0{ebOboa6}=_k f9aBS5k 6ͽiS? hZcN0zC&5sF9*m(^?Xl$WnVGOͻ'er%hhZ/m.I\z*/ɕ|{뷠\噶tp{0).*@QZ1juuX=z}#̧o4d3N1a$>$@ddFGoh 9h^$A^ qT6pL5ݖ>&zT,L-h$?s ښlfHk G_®J'G |yoوy7o)oԨaN\Mzy"V04}5ٷ$"ZI@ edR"YUOV iļa ,ןPh3_x ^E$(GvB\}XW^7T-_O:BK?.v\(}@2ą9Ѱj,LE𣺯vxn1e2|X8`OqɂK֨M jZ8w݀W+&2{qii,}}ˏQxu53*Ԇ(s}A q! D(<WfU8kC>K# zDJSU%^&7QTNm~W7ZzuQ;q3տM,eVYkw3LvAʶsKxfq*,ZKDhYC nf#$D.dk ^-h3>dczFݙ]?[Y.ׁٗčUdJLL T&beBjaGGV/RY'^|YÊ q\vJg&MYxPAsΑMbi,F#`rVŦr&>V`Arܑ ;j95%Zh}ӫ𻸤F>{yfkk; |ll_đEӽOyް?/ ")ZtAш: ٽ-鑖IbҕמXTc/ Ԁ7 $g9zۉO&dT hzk?-?7gR6ac (Nb1>RP ?[!$gaeX˛!I BbNeDz:ݱl`J|F5^`·k"e 1M42uy*bm`mMrYS!I]s~R.1}'LNRQɾ'Avw37 MF=?X5.06'Q~Ȭ[(B:E|?yCLp?@fcc*|9PV-8qN\i2(=>0nIz߅ WK̺-ieFeh.^3ҒLɎ#5!DG}C %YJ*fa'!1-1]L BUGaGW޸%*)h$rJbJX6uš $cnb&C+2,gI缓#|U&o@JwI=Y4 $C~y?1H9.m܇6ج Se[s=ܿ 0Ȳ\^pQg|+aj5>IW'FR>8k擺txrC5y%|,m_3E%qU-yn>8(~f˦N~9$z`п٪ᱸ.W{zbg ^lo^GKf \@*~h$Ff#YÿǾіM4ŵrC7zbu4nJ)$."뜁1,5Zmdt}Xt(;԰8Q7ɔ)O b"^_^ʙ NxzQZvo hK@:tK A#F{5znɤOb!,fy&“,Wit>SԱjޟ;+qFOAYnN=U9@ 7u噡D9jV/O}g9Afw1[I9,HxiSxݰ'].`, φ9]G4lr|RVRTwO^~c{dqʝ[O g4amzy86F^)Bl>T-f@u'UzˁH1^T>iV}1Lbq^lL͇`@067՗Svwe>fE~i?-G&U!>Np$@b)GJ¤X&bR1M̄.5.`h3}5zG| 5fUi\eJtSTnڌ'c3F-k,}dOHU$lݼ[YZ1_H~/P?(pfgf9^e)skyf:S꙳zP6hD$RTv޶HFo8Y7` dO`uv:.ꛄh[% -%uU:0s`{uT}8$ c9e > ZOurHl]oaIfa&X<"MvaʱM En{2+A wHJnC˺=r[*!=2$+b7nS ;?Uv{~F*`$ݟaiei&fx["? 1'T]9i4..S^XpQpOS޴:j3euViܠGcI4i3[G `yazxIgQSvD{ KZn Vd{ӹUGdB|W_a2N) Jq{F:)^8 Mϵ*uu:SU*wSVF5SKz ]82r{2] fKQZ!jV^~t:[ҮM?' nƮKxIρA͝4F1.`/`{JL #/V\u耜hc M4v]_YU22 x 2g?:$TkMp-I]KN֓TW)o h@PImxN|ΉJAaeAr)Lk+zݱWnmȂUNxt\v٢5x1$Mͯ> rfCHyzD ,1֖K1&= <ЫrO=.+ӘVm"讒0\]ցRYcQ-ş9|ɝ<B>%JC]ftkݔIb!R sqr-^+ߤ[OMcu:fcUucf QRE Q F>4ߑ/]S*PM劻)? #֋\?/s 5l5"`=Q7c)Dv`2&a4!jޗ.Gn&Q:@/S9%(M۫0Ro ¨=hsbϪ\{+QaTt~ ,jJ`Z=Ym2SEFKحKeV9s̼drWsUgLzïMd3cC\|"Ic IѺ@Ԣ/ݫJv;9ܬ29b6tWybv\ rӮF8tA y S>e柗 ]4]ZxO&4?/ޯECnYm`wWCN~c'# o:x%wAwpj<+uLS^&QusVՂ)$'&cfz#hI1hF^}mX:$V˲Vӿ##R˗&SX"ySO]oM2jB/qM_"zLb&Āԗ +c3k'D;y_35#*o"qYD2Wvl*ambTtt1|![qcmu 0䕖+/L )DC`xsYW1zeOⵥ2,L' ݌G>__݌eg,VT*Ya;Ct$7Ls&+[c~=b㺿>vh8aZI |&.pl1e:VBs/gʒEFG/ 9_(UV9QF}1s@/@dl iL @‰n `${:߀~"bԆU@]:O_Oc*>RgISA)>DA'>]Ka!>-C (Ůtab4 % $HlSEev rfXo_E$d]-q^{GqQr=m\)NfK3O)2>ONSgxE#ލϨ!]97_B9)9!X 1 BW5 ["XtPkGW2]T`i*G!U[J!(DADBj1*+/F;Zc5"~,5i{N6uPYnhGb>UD60$:&Z%MVXZ; ho-%4U %V 0uL6?Lji,= MoL*<@e_1T Lz#@G+U)(VQ9#CK|ͨ0#͟4wS0$0h~t[ ^%wzO6h}!mbƸiVѭݭ<@  YUHҬ>+v f7:r,g{ AeV@&Ok=0>/vԮ>Zx0y5VȊ'FP-Ɣ(^4 Da73Gʽ'0]i89Q "^"U^v&1^X/"R)t?/;4GRl| (< ҹ[I謪HSa]BDLI{ΧLMOO)UIsxFy/XtA-AӉ#mChx-EْGu~?( En5`s53lҦ!Ϩx6*D UZ9[Ly1rΆB]N!$a :2~l!5 [9mϣ:(pۡ0?YKh[~ ׅ& m3lnDJV^O$H$"W$=Ǐ ͞vmiCl>SEi8ǜ.pCZ/d #qMZ>x ײ;aJP"Pe7B7e=2#?03o /Ch} %/ dHygom4Aem!%|##(J@/Qg2\?܂w%MԮ5")83yH>_ $cD6+vtFP%TSR|79wv㮑ԡlQSGX"ZOF dHlh}m%hѵ 0#D7]/Zqpkˆ'4PE..tXDWCR9 k?Ĩ@˜-w,F櫝 aҸ5 =)@}p8>6H%3=s`w4,־9 D[r_ԻO?@Iu03L+j%%!K_ ܨh5>/9u~aj؍ﺿ,jx1? Х?[_pl?|NO%uﶬN-mrzzyU㈆؆}N{Hdp?&{~˰HϼNޭ9 #O7NbG 剭T7~/8UW.Bdy<[d-;=kރKEv>?7y/6q^vYg Y_MW7yT BK͕ 6{+{ @GeSkaqMC^),C'\yg}љ9m+"%m<>Qƃ#VE( 4η a7᳚/ x<* {Y1W]aD/ +7ET'' G>d7-Ҭβ)ql(\n+MS/A#~䁠{a? Z|T_ jA-ԊF})GZbdemC gc^`E=e`M+P_lCt@ֵ+&!iPXC&0#dL-\)Qb\ß3-[e;{OdAu }xgW%W:5b4t!ccfC`Vi HTa]|Mp˥]:y8xl?eLK2=FkgQ>> #Rsp5_+oJQs9oKܶ}y8~GpPr4Mf#Yh[ ]U^VN-ELˊe .Erj-ܼ=53`Z=*p{dwEB>9vi꒠O⯹^l[t 7"Oq!CUBzEZh:uw1hAx-4 -+c١KR EIv,[egx,UxC<̀a*8}5e|ҒQ dwvL9ضcZGeC.dv8⯇IVqt`|bچc(pϚRudSD6u?<;[2!WȤ Ƀ2Zd\80QtA}W]yZ H$ubk$6ك@9WV>%oZPNp+l-dFu: netblU&ԏZC%z<\^(ch߀(V[WZ^k|MlQ74AUWSS3#~>N|X yޫ|.:eMە:#8"vhͮg2\kIQP` "<׳vfG-F7NgF,B,X׈ٖ n]+Awz-nӶ ԭ`QTh̚ˣZ K n.MŎk:L> 6޿:w)4:z^bo50SSqw吢n:hkmko`Ȏ3[[o ~4:"[9^!a]HzW1ל0 /)~;Z4EK'^™ܗj;do? T S4iG]Ѷ .xVD WHsl#u|?.V{fK:b0i_sǩee~[D~>0.jĄ`^SWqAQџ|F-}͑7u|JVEKkcs4cE,nmZj"br;@Aӧ;뤞jK5tsqF$wnd:){¦#lnYL~-VQA@p G5"'&A<qP kgv{6̧%@K1:"#%fÆ8 ^G0\W p ɵaw¿0kOb&o-4cJ,*/)3?#R-.\9[f2rPзLY㻎m%uWh` ѣ?HMCQpsՑfL6c ٷQbNXRD{v5jz&\MdDЏ:3J6V8WNy:17jO g8Zm_nH ~ͬ霪o1Rj-:`MRU%LL:4Vu]Pc"3|;4$dz{b?崲ѥ*Y[ej&ttF#Z}W}Hqc]5PM b>*En%2.fʶGϐa5XAo*|a [H>i0 CHjx@).F8}UP&t{LQf&Gtbس@,)y#T7<.pׂ 4ׂCrDpI~&Y$xbHĴ ui-) NAHYS~j/p I-CB}ԟgaW3vvb3:ZUv#hm"Ơ#HC>#@N5GhԞI\3!6ʊ94;7 qud)ʓ`x|͉@on$7L%m=ήJ<+\O̾<\v:5QB&\vx !^0uegG: wAuO9cf/#|ShT w!ҦjTy%!@a킌OeDV9t!'B#e@qoj>vK o  nz H%m8$B֒ʆ&b/"X0؀jqZBvV} 7.o5k[7U&j3:TgV=j\ҹ}>K]8]3gzוֹ\gW]Ǔ @Oc#/.AH;ۂm;Z?F/ʔiW٣@6͖RS D9uo<" 脬pSU~Cw=(\i1?@JO Ӟ=sEڢ.TF@'rXK0dtLHQZ"*PP z.tRI}de ~]yqή90^w~]3e'|]y MiyJʕ.05&(ۍ._F i3<42ʯUes $9gUޒPNXFwexHs񹊜|LFBp 1Jv裔E2bFMv8 *Tsۖ#$ͬ61I$!<Ĕ!*6UZhdsQ<~?<MəSI4U^O„wRbeK%5aw}1hfZ_j]!2 {S&({* ?w]9f\75NGŲu?}@%T{G\5 oAv胛֮osWu^KzIzS4 EѴ,m/{A5A,Z'܄C>ХqmTHmҒj ;8 Ao,h5 <=6HOQ]Xt?kӦtmhc=D;X$xnu/ڏ>.pqIKB |b:ʻAaTCt1LZV@*`%);\28=V0 Y*v*F:2sR.F onm6͙?!PdtZ"A^Gt*6#qI,af{?4i6-+hG*(tK]ڄ&N]^ ]'[q*E7ܦ?d`Ib ;*|8+n%\e`3 "3UXIE)O 4hF!Opz[h֔+#-AMh  #Ym?Ϡzku ?4/ 셣<77P`A;k-^?hU1J>74>k}+ xvͻN>׬p qHYԀo._S,;*yQO! VߤH"9 ]PQ0(-OCu=A<dXZ6|dv'(C-x?sL(N遣OyTy"߳-!DG:l\ /^iqWkIѩ(EU |; 37<0h#\ k75'*g҂))|6yZm~򩄛X LBgtx`d~`3iO?omrݰ#V}wEB~3i!8)cܩ|Z]LHBw63\nƘUy:VFC^|©* d Y_2eߟA?~Ͽ7z/~ϻ,Rork~5#@k8aV ۹h hk#Vg㳉pojk`nk2:w81t8}'%}`++>~ѬvA۶hs[2jw@Dm''-vUǷ9Φ tz=7ìs+"x>+c쨌J,J[H4G.9Bxה37IW~{|!ғ&I̦*3b4!O6XL2~i)Lm/7mťZيx9:/ˁq=Pf٦%vYZYgv+S:Y[;Uol[&FPk^$]x:>ܾQ/&i]xpQ^@㊊9d JOz h'x*j[/[θ~'<5ElK&Z-zda:S:t'mlLjţ ~>pu r&<#[ڞ y`)6ᖗ>z0$%H6.]',.r;Nﵵ]C𓛽B|^Ijt=8]xh@y3\ܭ";%ͫw]"^a<̃wkt ’ږKID/'hܾ`OBs``јLx#&(]l' ʼnGi :s414-tfZj\fȑ}`4 U=,Z>/^|q `-|ve|hs`T)Ql$ 11oKI>i>.4ub511|.罛Aݿc+m)VC #>u#vqf{ٺsrGslf5ߎ/8uy.d_FӀWw\^9pXٕsz<{Dm^X __eȗΠfnL'M 2/58FX˵ -}qò{#N0o`Jʃh|{W Ͻ`zi޳!)_իGV=R6{ف) MӴDݐ/-]h0٧ejQ7ݲ?Cܹ"dAbIOU } ͭqsdԇ5~p rP/fy`3F݋ސ v5)õ1[AsbH[$)8YJlOZj`8|J2>[b6%3iQyWpEJc .b&6Ͻ*T~A!h4\ݙi/rCL9w@;`OC4mH{l/Kn/CLj'PmPf<"eAAS7,9*C}oM+b "EK#+ea3L6\пKTac\ ElInЫrw[lp 9PQK;?L}͍r MmŊsE8=~@.ps ZG }:+IګW xSU+Q;,Qgs|`Get}oNM9]RYVFTiK[K9(r&K+ '"L6^b?W&l,le,?.ABc`e5*۩8Bw]9+4.-bxcM6ؼ7x"UXS2KT.jxF6.T9J\-^#hVY&9g ]V[Rf)gZiŸ-@"pwTzdIQ??k(F$.,{0+$ }Gc$ OYw+@);(hajB(r'*/|#v$Xs"k*wWBah eյ{{*[ްrR]t:>q SMYp1-X'WPH U&KW{/Sye#@_2%Plr PDIjTv U$B`dŧUhX u{YenpzS,}[,G"QPbPg*QHŔrlWAaeh).KDw@/AA^rN|6dQ4H@3 E֡xYF-4 <ٱ2BzF^~jIW.#4Q`؊ُѷ=:U| ꠮01?vU1(~ؓGhQ϶B,vԼ䈓x~-&ڙAUjz:0f6\9k1} d)4ez1dY%1+|Ġ;X"=MXUc9Jj;]2r՝GnGրq&6{j;\]1Zn7/t$tϴ7f<(Ld d&}Z,q;gilq~GFQFe_')j}S>guU%])xKQˁ3%GRU}LFYְV:n+:&;٨N/:%Z%ړgjŕrTyUZn 0z3rC\W]-.܀BֱN^of,7mj>m5w+xWB=pK|\gjOf|tdòlA6Ka~ )ٿ97Ixg0TkRvꍩ"oȋo&fsjbHJ;!F$dLw$E@H`DP&v3Y~NrIAS16eixO/Tv~']qK~f&cPQySϓKܧQSe9p hSCa8!|\67(>pUQ!a>la̿ݚa(8tƫ/Z_E:1D㩆[_l4xݶA$N M-(b 7Ƈ'wS$1N\mPL{Hm@]]%{SYpbɊ ӵ@x摑RPЎa,(W+ .-V<L8j"%sxb;Fzl.\ w:ZP8=M#\\ӑ?j ˯9 Bɞ?[JZjӡ32C]Zţ:8/b#*/n߅Hf6i  mbyRʿ2iWF^Ͽk!%e[ ׻N* tjez+) */Zj)&poOS6,{z͞<ܰ tB}u1YןcϿP'4s@CJIzy9ٿf8ᣃ߳ѣ3Zt2mvF<}isŅt@d%%눶j94KX êJv 7rmP'P%N{":eE_(e58{=#aAՑƭ +=MЦDvk[*bQHcZuj:y,ThYO|2 ]}+%n;;ɡڝjUDIʓhN)L0RVo *-0Ȋ>.a\v;JDw3b^Y1W]?Z;|?NWEg{̃FV"YhOQLUWMZ nR+= 3~ሟ˟)3/X+Q2vKou0cAPvjdՒ]1`VVyQ<5{Lˇ6lɯUTGO*Hewo0KUM l6&M 9˕;`HG{:~0A[JdPUL,j?ScGo!q~}_VN3~|8% p، =c jW@!-__^ypG0E{L e;$3eC$xXȐK<޳1| ΟgQ^Lof֍?9DGT{?+W4'kQxɁQY^jO`uiI>њ,a8f QU-}(p$4hw*o-}6gdEv+I taʊM7~qJ`eɟ%@Tԉ*8&XFѠґ?sI&B)bo=3蛆x>u+L WGɑ5jiEw,WomSrhaѧۙdgl\VdUpT)|Kԏ ϥ1| .v6NpHEHl}`/=";CJ pdFgN Z&Ff[bGIF5̾^7©`\QB-R-͹Tni`[v ҂ÙZu;w(6LK_S-VAhDqQjxK4 kp0&5>?; r3szlϲ8fM̶H(6ѫe+ SP%(5;{*st <8^caQ-̾zH+EYќ;aW g }TYޣZ8~ 3 &R} 1@ojLhTwT,vpjDߙ@ =u>\x 4jP9!I 3E;" m^VD &'cG'{q~(`!vd7Ar}w{K^Wn+F&ڼj.ݹCI+W݃nA#PX lXBSL+H rbΦY/,JސބK`46#Cc>0_= 9.$;[،>1$"rAoȢje W,E׾Qz 9i֑Ò@2DQ '.Vҫ856Ӗ,( k6#L0>M,3(OTOٔ[ r 5&rjA&: 唭Q=Ɩ>iۃb ۤY#?(bݖ}i[qE i!F{4G ,$.`0pe;0fPk#A'; d)q $n,(=+]X{䊸_ְ7Wz^[x=wael4.^v ey!N Z4 %}$q-qnu 0V_<ھ`bcGOj%a._+(˜]DG 8 GCT9ZO=]0tp+@Z`mwc ".pc1juuYq3huӏ#L 640nGV<`f?'V4 [`jOEyUY~|;[O<ɹ(%>DdcG?=^RP{⮲,I /bdsGK\Jw8~$iwvLC/A9+ BB, 0樌t63J۱7IB.:Eg=6OURt i!U{ 0?u$REk+".NA"Z89$Nt gg2S.iBތ/bg]:,mNEpƵ$n_&4DcQ vSeέ_=埤A2R)e\?ؖlBE&EXFW2jP^JƋo:HQ7B$ҬAUv.Wo/jj}aL84ql_yD 1*Ar5+|=(yhuaS9coP?ZKB9i>q{.2{`SfmtB}_b^_zّ &)_<-|yWO/Yfo%S.&Y6E;dkF^ Yqp qg(M?UW8ݴ0M!qH-Pcm:! BHfi*hz2g+˒ykci-~^&ej_K!hQ;> SY7!fwC9WcLm޺`lP>fTR=5}od7mɛ;5o5Z|_\~5=7's&myww/LK7Jr>}}۟վ>׿޴zhut]j ޛw>sBrdKzmMojWƊٽ0~u' ]e^vSMA؋^_bgoȘruaYӸw0ugTCZP,U3 z%2=$T D@ջ]{,UCC.j) "6ñW>b><yՕM ǠSXp  f%1Ϧy nxXZ9W dcքc`[M65@kN\)V%oJ Hy" Wڠ}ȴ򇝲ae5g*uȑhzYh%OoPiayxEf GMBk  G'`6IB0$࿚W uSJ?$2!_d?:_ߏסv;ycBఎD#ߐvTizyAǫ+d ,Rm{½ި'aȗ1Y(]\"j.h A2#8bՊ 45'J _V :;351b4vҌa͉5m>}'8GT}p}Y׊nQf3mY௚\ݭewoc, /%#P 2AYM11DֆQbi?SܭpJǑjL奞*ĪvԾ{t*,Z+L4o l$0YqO🖿2.6t*&7{$;rŠOl|dNUO3@!Z~l|߮_%@% k ^;V& Ã<HOjݹ8WE@ISYv~PjdmY2> *4VBL%j=x'.U zmªH4XMUl?xPsIѾ\4Y[PN ֓u -[]9TDPg=%3LX:jmeEvmRbuH[3{dfZ#sLmy$rX[Gg@ۃ |`@d?V"@S`Zl*bMexNwL3*ۂDFtfg.>Ndl~+ M^=)Yȕss[0RraPSG▵ OT/O@ߊTZ<'Gk^Vͷ IZ3, ђ#1ZеRk7r YcAP"# knB,1 H0YuSQ[p&V`’|UZYJ[.l<I=*6a:f'v禡^3xpvTx2q`dǁ[NQEБsT BU^q>?ڵ*fC ͔Z t>*VHG֔uYbD 6cg& پ de/(*;x>ןIPe-]KeYSY{B>~ &t^:+(B3yr!vh+jw2OA]QEmoWO[W;@탃'ъs&쉰'b{yΉ'9'tE+[_$kݿDTSk{JSo A^ Mlp&sWSYx:~b0ˌ8yIŹi2,F[Ie4v"U%ߡ !7w#Wpn(QΕYDqWy9.wдQ^۞tz7Q"5#Ɣpq5c-8JU0[?1<͵j)DŽ9 yJ62$`Z:8J4ޠ+tњc!1 {?gDys'uXCm48qʤ ȉI|8iD췤vgzx̟W19o&[fn9#s>,U@W$++O jҘdܧrp=3MO5 %3?)0e!UZYîQOS]+]Bd|{>n\~oeXR:²Vt@_-fPTg 2)t,cAm{&L-QeIZϒ3LHv)9O%Wv{_ {(}Ȥ[= %~*1ƅk2bp@(<#,Fܕ$tOys2ƛT‘y%q\ɐV]7ՙL/ N 1PNN xD}_w7W'pIT ݠU5~?G܎@d_?*jL3`o/j:1=72D(c|j,F_,umf&4gsSu%[X9) ?^z䈯wٲ%;U#6]>nOq2]ޫzKw*_Ox:uO<,uJK۱6ǭ#uejZÕJgj8sVFͦ5$jK˫PDuv:ʴk05API9CY= JǂV\WܥD4^VCCKl4In,?4jݪ)"hV75 ~~bVAqق8IR+JN95DHQE鴥rbRVTS)*%eS㏴ؓM;CcbUgvMi/h~yLIB`"ˢM'r5j*U4HtSa`LK{>|9iyyfthSӼ$uO“/HJNtnҾ{/}7&lj>Ԛq8l`_7[Է{Tx,<82>9c7}BFx>xCjl r6GdNIX^j/>8C,̎lT) xM{t+fx]{tjkQP1m~)&NoD%W73ayU؆UpEa%OG3RoJz=Y' I+k>^/yZg $?92K[)g QVNXU1&B/X#4ZUH',z2Sr6\VeblBήd9`=eU?&֯+ 9ܙ _!֔^?+mu=;~쀗oJüI&ʘUVXӊ>C|F$}ÁsyE|#He<dN :w6cO3, jԖ+lJaNx&MS}l2AӔ8 #9lr7%شZTFR7C!8kgޜ]cLčaj9@FEU~G\_kו 0C45kթ>)Q(ٺ{sO=WCoXh 0qÕD|4DY"*燊W2S =Ě8L @>_tQZpT̬Tt/ى~~N tI%6'ȈoIx u`hM{Vp]e&͚~,Lxs|6k?W\@ŘCJM>WJR{F|`J%yR xY}3+9{cyFBgZNJR3n*JDWX6G,jmkDՑNOb,tzwbӽYoenTvS[~f@krgq7<ZXeD??`G/==IEh06aiyIdlu~i=εڿ2Еs/4f܎+\hK7c CyBeєh_;g.,aQоsp泌Bukp*,4vw]83NHLC\FQA1'?,#L}@BCV?w}ʫ%.QJį~SM18m4;fR?{BL>T;<չbʹj4]| lЂ<{ lA<[H%TYIl?!lT^? H}Х$NKU@uPeCgd3@`nJhnj !+ 3\zm]е] ͤ@q Cz~#ac/躮Q-wwIpww Nww}?UvWk1RJ\S5TBMu81xn]V}-dV>{ie>ey*z&8bFϏgmYY˲ˊ%عB͘͢ F,բVxAߚ'([)w*)291)1S} se+ҺAuӋF}\I4f^@.$%kк7Stҿ4+XNuJ&ZvtUWQT! \p!ub'p_Ft`Y M"ɦ FX.> X/;:TK^!mgpmՆl*J)ݠa[{ UrӬҒHc~ӅKx,"n_uE|<ҲKkV+i n$VתTa;z0Ka v2_<ժ鉯#(>CP {krF6ixLT.z`x[݊vtNDFBCdTӌc0uIu^?:lںW'"ª+ ={'+E(OGEq}E'@a7%.Fb:} H|_3TZ-i, sS:/(NVj.% œ_FY}O **0O@F$=1n/S>܏b!Rbp .|vre Qw1.1>禂vbD v9NZa}gT0KxJ)8'Ca]u]JO(FgNuWշf{׺\EǷ}5&Q;PQx&J7`A0a&Eoqrw&Yn'|?mDEYX40DDnaISܸ3 :+W-En[f \; dNaL>-7%Okx ~MZj4%d>)GVPd*c|| ۓXh9~~L||fܤ,I.*c/(ڮ7ldc 3\%5|# NTO'zc蕸];(uU8 mկco9B:کcX`` ;4 Jڿ+xNXum#:8cn97T4ѢHa[S~:Ph= ai|1Q DG*)@A'p!ixj=S 2iJ)hq)S4mLwzՈV)S4z P?6d=TMhSyb䏈1ٓ=T-[νU]A\Wː ~~Gl)qJu5i1YCSr\||d:}*NJBՋ*%E4ihEO]|rپ>i,nH0 ~*J_gT hqﻍH!_:TC aqw0_s!x1҈z{%Q,ml-JMc0GmFTaӴk9@X? 9 B篦h뎜7(];Gg-C`KG3x2x@l-\ /B q!~y|ڽ|[+|xyw_۟/SY}#:䷺ʎ~Gr'Z%x߿~[ xW}~~}x!0hν]X9)e}'gemGz:VP<`9]JJz ۭk^'I?ZkWí묗; 'wuW'+Yw̮_Xk1N(dxWneNX7.}87.>4]{̶+]L^hp%9oxVx~kc>3{Nꁦ3>1'~+ﯧ VVVvam?~5a&d fdez%7;cz5Y cCGzE'Ǐ[ӫ9qӋ92s ;: Z8rKۘddUfnhlOJXȘ^^NИ^X %?'~ן'j]TοLO εJJL[l)k"\ADe.NɃۺgmox/-}kuҏ |,Yhㆀd%2̻lB#{υg(Xp"v:)a?ErWrTc&.V]ٳ!Rētj1-+LlgRDʆJɼncby[z(y߿~[2;k=S,b>3lJn>GQ}vцXq6#fp@~*A̩)aI?ylv!+IS rʲBeyj-ƍl36 O 5ݤf #17Qϒ 'xνggCF-xc;iI_ \O,Z׌ɨKkj6hujqijbxM5,#MZ[ChVie[eCC55qx{9&hշ Ew U^޽ |{gkfs^ xf9aYT'/Dg#]b v9[ E6 u_8R}^5MN./Vi?{$PGb7TO"xM.r$ +tZP$ӼO ]P钍g@%o]2T.ɐ|Xk 3P*28:,I3;n:kh&J _f%N._AW> _7H1WD,s-iWpX8vEG?oܵy5QܺW+7Ӳ;s[8?.n{.>-eVo,70z{x{+Cxx]qq{ޑ|Ms7ou!CmRO,Mﺸܟ"SY 9E-QyQqdr\CĄsSVv6{u ;%lb_&l^$ ~f`Y#VQTƵK'6Jء,>/wn߼>tfT^Ҙ5 3oU 4LiVS Kqxc}Ax㦑&i݆)>N,:xK9|piFlrCh.n6,ЎB3Sjy@z<fk6e3͚dUO˺k *SNYtM*3RoHp_5Ҋ -7osLu:!0-yM/ԼV+Ve- ok֙7z6pNTFEц}>|}?B6:bIr7k염rju?oqVCcN1aUҞ¢Mރfq 56%\C~Q}ԇۑ B|$!q(s˗驾TR횒94MN1Q{8qw$1ԚKI͖xo5GB8\->ū_l=}sG &B!joQ1{}rJ N@\ٳg5_2a5nA9sWn}椑o-ŝ=uD4"rv<dvl]մպ\@7Ni8M(uYp[;OS{ls(m_  H lkRwq-y#7qðˁH>9K,2ťl7x{_1df,}% ,N> QOl`itq睯 'L0:|~n WKs咽}+%2W(zlZ'kQO>}*2;T[+oC2^M'3K[~gOKmq#*}E/! /C,7|6o{.WׄOA?g0^'tv85n}Ln[W[YuDH# @_2M s5]S>,9gX4K7!1".Lק?=_e : ޮ*[/͆PD?\l \ou Ǫ{kFn0'~p_}w< QU}i3yqlUb}<:ۿR<+t?MVeҌ2<ÇWq]fn>[rlISZlrH֕WEg=N?茽Qk%zqz5:!z,6uʇygS9r!sj׳}[$=r5PkZT^*O,_z h)Sys!`k;]f~˵`SM/?= g$U^>,1ꉍmImfUy GbESv¦T5]qcPk V.jھZA|[_R Cn7}m*Ӊ^~OHb ^kTZ>Cr쌱'rr?TRc#&7ɯo7=' >໬<]CupL%s\Dveo]Uo:aD-lm͠b.ۥj'{1U קּtfv]+sYMM]Sl =Ad|lPh4}@:-?ULnSW+9if>yroNe+g3W2_f[Jc@[ղf auy8b6Ig0}XUή'͂;R1]I^aKYik{vZRп/Kj <[~klr_s<)W(̧U^GܰR7XoTm,tnSk2ʡBݖLDd{O tV< p2 bWw:Wînbϰ4E_H<{H!X|!1n5/0)t%"A]V"0ZzP_\] tx=7 AEcOMS\:%"Rᡡ=@o @Gqsc٬545WܮiԧJ_HܧQ.ABAE*I?otxE?aaKQ8R4W%b}Qa71[6Z-[Y[[ijK *RS2 wߘm "Nbfo{lnʕq`rf\:\$"~1`/8Za vv.[F=^L9"(|鐉k~`-.2ج333OW<GB <ߞKA-HSAzX H1 ;Aşw]Or-'bbb4 liZ8l8txߺ͆ >$Ej ĵX't@]J*5nA#펤A$з/XT1p< }ÖttȔ9e?4#Az-Ƥacɥ9>fWV ̬ۍN~z]l>xJv(PRXl0D|T(_RhzVثRpj7*J>("M g(ޖ@j7:-j[nUg$B JQ$n5?9di 3=o@Xixx!"J@E{>М(,^9_1KQ*-כ”/ʯۧZчVgpo$e}OMMQE5ise uuuI&/`i=LJTz.p@ /`>0bTvz_rUTߥݧ4+iQx-$uyKb5a U& (!@yg.6Zܝ(3yB7XQ5zkk+Gs"#GNv3 PSbǕ7*2M͝uȨX,QR ?o>d) =^3&ga.UX V7G \`igFL9GQ%ˏ -`a 6*.T!zKe+k ](#Ȋ,,,KþD2Mz?$qM'2/6|ɰOԁ%؎~BBSblPa]B djOțf4# Ǘ2b_7=a!{B$܎x4*P|rF䁁HSߑl3N h3xUeT|!Yzx NjqUb"䤋GRgp 4SSH t%~U J6'h\dZNs7&CHW;NKMM9tƢ\ G &G%.:B=y8Mvr7$p z/h{<;! j` @ x}4`qx9䊅RIr'`%r{ȷrN9$IZ >N CJ$u ~ 1ŁIf0Qad{;=)D"a$+˅AٱtVLK}}}kk e{0#q~IT 1}O}AǾeuBGGG=&iQw4 ij'o~DJ-ELh?4#-O"]SE+܍-1/ ʟ0юjJ .a=@zLy/qh8H 1{'4+ DP# pU UBń č0i$lb[A()dx_6ľ5VHy1 r OBob#Y*I~Ll *~Tχ In Kqs$|oˁ}[ªLHPPΕ- #сjMx֌վ'ν.gzY'`!+qިGEӳ_‹6u5s+UFA-ﴰY\|81On]v^SzIگuC~h3*gf_iu"\KT6:B=o3bp~u> 'u}?< SdV9H5SvcY_`p"};s/Eb/w[TV^+QxOx`kc Q!\u8M 31pJġљ'bMa8npX%ڮ?z_$$M6:KZs EiVhXPK: VCu5.P$x~CET q+Wm sݒ^mJ&kE},Ϛ̌[{fc=>`B\F)dv^m/t+',38DgߗC]d ލ>t"Ӟ@&kv"aMw*`&:҈+|- F[#N|H;=)$G6pACw~DӡSsFЅyңw z4"|qa>vcoNY)c;fó\XqgOKˤV KGUdmP{G?v`%:͕{ZkXq_uKvoҟA%F$̵[Ʃ̜E٥>\{{]RZ=¡_u8͊%gKg3D!f m g4nZxMJtFOvƩSXag&%zrH5UY^`_8T5F%5"LUwBϣ f7͝|!=#MF'-Up83> UQ.oթt ܤ:ۘqI AdHx8[\R ϘԺ?Lֶ!C1|SmJĔ~UM"ko Q# #q:8<1;OGsmq|/- BnU~6%]A` €Vs/ŧӞ audozλOHGtL[U+{|uI;LRۡt+kVř~ [ɪ]/<.v>^il&h-{C9K{6%n~ ڌ>Ī~joohs6DwݱctBgMZGhLjsZrڭ r3Fg?^dxYZ\-TwOa0v~7ÊǝMs(~pǽ<1wl~逈{fo2wtU 8-Q @ݢ?Y<Ӈ$<(; -{\k;I,ږi>6MJߕ]3P>Fe$M g&Qlv{r&;5҄uMOO)ڿ.s2JH äN~ʾ;rS/'j+aͤBɾyj[nOz7*  $4paK,JA#s1Ƅ|ayB5z+Г쌈ʏaa(Fm ^c\L#"U6>sӦ{O}9nr] &W_oC*l% \2:N^yB )*8V;dzpQPmPZ |j 'xo:Ӟ 1:+˿ Gr<+VTt9kGɧdf"fG󖼠jنD_n-'IupbREu߂If砀r)hzi_I;˘_[/LK}?D3]kp;TSPBѰ+InKzz9^j̦02ZV!P}ܨZ3HrŠf xsD/b=Z4(<}hiuNʞHW{R--Jo` e#RYxmGXO>=81in~{"Kx2Ii+_.bRY͑0{,A|\4v,3ycQŭk࿺u>6S]rIiTp;tm_@|M#:_ż@w:j(.Ð߽j8\dn/yJuJ:F=ߵ5:AhҤ1bŝtͬxS{Ѐ!|fdyv%'xy* %dݏ<=Y.̧{N}L{>ٽ2?y㱇?4FnZ,vO"NU˩?PW{fpd(i~y:WM)Kct3,}n $PʹV"vBy}^'vQ6R&oeyt6,U@bU^%q7A%7w_ ȖƝÖ$x;Y[=XV׋ +X:m d#vv,+W~~UϫwWG]s%X{PlJIf7}| 3ps߸޿{25eehmX`Ui3j<)w0euHJe˄?[#}$f|BJ}D( ;'&9o`8guA()ͦn/ytڶ8 #-B$ǀtb2\7e2P?<]k8}T͏{o'}Jt56 a Dj1ФK~\Mw/cK+(Vl~ch3Gg:atQ/Pڑ_.=Y("2k]1(Y%,a;nrLJsc.|_v8T %_ Z]XwffZLz1K3ѵ$uUU_s%=f~؛$E\/-k軰 #̿B^!0~Yeq0~cn~El؝] `JN$r!J:A8sKHy_d;Is㦂 ^ &E ZuE*ma KCdABgIOOٺYo' L5,Yf;EUDZuMIbUoX͍-0۩q0% ɛ^NŃOI~c=Vg{`' be_s큘?-)rz:qzP5cѻQ _\d3=3SJiF K[v꘸瑙?E[N?`rX(T!oSJpht⮨H8lGމRmd[w䐾>|,_[hIuIZo1y~HN[ؑ'J<οYI m0pQP|(35/๴%ӥâӂuiI pPz5,Hv0p {r5y[Mv;7{I+ۇfJ3V!mǒ ؏蜍ô]]2>RW0?;>ߟ[9܌ybq9wNxhߺ`e{350\ߓ6}0"ƫe{zYU@ZeeΘANz8D.[ƜDEzR!>dƴP.],xw M1^eS;3t|BB\ޖYي4nM.RBW:4wB5_qshE/'Ved.6BWM=Y $>sc51S"͗@Nd 0X(~ߘss(PZ6r>%:b9%O84p[6JZ] N{'fc֬MSH4صk#8[MQf2E[v롤u{fhLN}e7i(;laf7]Yާ̣CELE204jVzlp~׹R|B/g\,ܷ/Ůѳ ܏2TqSXT_dbiFwiI9[tVKdƔ8[ї>Dက~̚vL8 ZwPfLVVQ7پߤ*D# 8԰"ގWޔ8 V.7=k8w g4w]rDu~G?;s [sc?m(ob-Fkk2I2YֵV Q9=8AoQƪ<to2[޷[}}sZPsUz,&mp^;xU2)q)U$oNVtNSEz8bF[:kE="Brݯ$uK]O1ZGco?W{n83ˋH7Ǖ+khR n[zD{٤@mNduz庽2pc)> ke9=h>^N"1Vu.Z_pUo7-ٛ6^_o)nwlDNUtk;yccTh*%Pg|r]3?L"=ku5$Z0GPc?Iy_w#9ԖJA0]g5co`仓ma=F-FD:Ex=͎ZZAZU c}v*$XeU8%IKa1ot\&9߃THcdnD,՜t2-~a$]wieܨʽy!ɩũo?]V%3ƙ|:.E񀓓 aB>%Av~ Z)FDJ a`FGfAqG*&X.ly'sYFqkcxC9d[0ƍy-ܣ˘i~g_הsޓ{FK9`W|qYrjNo=ݼ>gp^s}:~*YXzB\m|T_1.c|Yۉ־m9HtP8-K%rN#;m-n>ON†q$ W Ĥ:sȠ o͈-FpA5_i,0[[`~Zw`zax.Ng+~,XjN,o:=3;_nv9^ ǥ n :۫n/S͚?5ѿ4}v8#.fRehĬHCr"&9ww,ɥ/D($P"^F=Su2Sh?%'i)nGdS'*BY IK4[Y 5ozy㵣M]%o+݊aᾘ~ _y}(Ep{áԊ?hLU]t5~\jƀcIL^)SݪrCp^6?gJm({]D,f)9ca~ !}-6qDzL-&4:൚ݴԙl2"fN9NЛ(3$El?g1FHhfXA5nHx07 C൹]#ѻ XZdǫ#p…NiJ (ͭ׵8zCC 0(Ǽpoʵ8v~in D$ͅC'mL 1G<{m\ѵW#uGqDR?G,3ϱz^Vkm#nJͨ9qkpx-ƣz Jv $14O/Y~+3̩GaYvĆ]0D6P?LiGs r>{KrƗ#(vk#'٫C.f"B0zX T],7XjX6I___Cۿ.xQx]JGiwߥu=6(d!>^$ف Vа>2?9~y-,@K6f,x%A/t _^Z86^sh[ViFr"U6=jvUN~v1ܑ]ַϐ>͉5F퉹 6kf D0=~ߎ{ce/Bn磽fbÅ fO~|8IWx$%G)LokS9fs&WTK\nYRV3aMu%nVF o\fbSuL}#d߽IDq+yNwbpKj6٨Vi1)8M``TI,$w2`.S/S*k(@m/e byL$&CBcޕ ak ie&Dry;zt,RN8}! i)ښ]2{+Mm/|$p;j\?bz5zE%:GUhO-:h^^:7=x ,NFE߮*'Md-A2 c@O|fzo0r \$ƨ `Q~9 ̞;ѿ͏ BB\E:(n,=ϟ?p)gĢ21"W8](3~}<.VD4]#rdVpc MO)NE|ynI A{ri ;A ~_dǷ;0~q~ppį&'KW]r8o,}vA-3nGAg&2o?yE2.>iRL1Zj|U,Oa@:S)0;)-_Oa}vbwb:_ jwDP}+W5_f^Y+כ#"""{>YZ$)' ׺ԏ@<$UeO҅?@ݽ`*JUx{$Sh5΁^خ`gǨ2WPB'CB/ Q |tu5O -t}z-1q5`l֗dx?t~4;0ؓ4HKkVoҺ9.?j3#,HEfx} xؓ?*qUw }șO/n@? _b W~Ƴ.BXrJy_; f=D1z3^P 1hsÅDպ0Lސa4$榠@̲49!]0|?%O'Dk8 \__WQQFFI @:c>AB9\zRF'9l }vzZ;柁ڣU89.??L[x8#]?J/>4&?Jb[la4̲=:OIy0&́4zr_9~Jg-W" \\YTGO)  ؀خ=h7ǐ00(tvo<ߟ#.[ߟ]ݦObƖj~B2(2~~~̦;*lҨafksBMl[_ws`yxDj|NJ,*rRPyOF?jk㱶v[=l~$vaA։4Hx2I<.%̙q968=TALl>/쿧''73n y # ?d =`rkT D0r8z!#&`1.PݑzsZHDDD˜HCJ 4YLH,@<B]OJYq0BO"a 8ޠB[w[, t/_ ;@ hc!p z>^` C6hr2]\  3̚$hE8%$d`` ڑ52Oɉa`)|H"t(/"9n{{;lUK(l&8B p^1k+BVób XBb1X.ӟ}MQ VvTr`dK$'e;JX̧=.r r"xw[t0}e:*\hul˥q0.*sمEPd*JKHI"07A>Lݚ ,<q,S~\WqƤfgjaHHH\odTkĔ|H xM,q&p-?AF\h_5Z4:*d'jp0y=Ncbb^hhXP}ZaHjGh3ʡ jHP~=Ij4F3E-&ck' p"F_+ 6=C3Ho㯈LzwZ]L_zW`<Ap@2qxא4iQѲm|XYX&M, 3QQR!@i?q~)2It,ReYy̯.J{&_יޝjV² M!J d) -m.\ҟ([KCI O!H_q8Hv0 kL?Cj6! -)N$na:%fGwwoJ \\)n]"I$8b& *[nj34o=]4kwAVJi<9>o+Q$MmVBZ2t摮2+/w ZR8!RՕF@β>N%<–4HD Vw ǹ./[GN 21[7|OF2P${`mV}#R:_(,E(^'Xވ2{"E$38| _QJܻrZ-Mw[fBBBUlRHCwvXeXB[ -bL"_*I–X '\LMMJ)XXΑOi :Nd s8;2Rj) 3 [8\"ʉ # 41(9b/Rk#b% )߇iʆeբykFw-/=!]J  HT:-LHI$?$?`!e9rUNcDjPd~n\2J8cG/Sl?;'\jE4/mU3ڹ%+ .P&X/VWC8cνŒ~pskn}EC$t>P^)Cb#F@_SFµ|\7w gPQ4.w@pH Ýϴ MM!(' lrRXy5G$rdp#A.*Kg?RRHޚt<>OL+IDz:ˡi3ϻX(Ʊs,(oHk?iQ5 EDPQ€Sݢ6 &lU~&aR z\ᐓn`872FFpPP%Z-La\NT̯f Yr8J|Av nǁqA,Fkss.R?1Oμ| dZ`&,赚PCCBq"ǐ EOgˑF~1dS˹^+ EJSR~b$v'xњ,D8(FFF┫- IFt$ttV,s\tv*Q=E$*9W z|-p*ag No0ڿ&Q Җp8LEK ֩ Eɟv(JҘV@r _)P&U!3/'@5kB$N7|R`R댏pCp{¹\,04Wχ]ݿ߈ʓS ,^G1*VKpu 釹I$,EK3M6t# wAǐυj)pfMC=@xW^eetJDA$Tq'3?"[̄@z4u2k*~q, Q'>_ COK\"j7wvY 8C**LdcigKeۇ{ ֓:;"ÀDPyp2Ψ@Rل<)"ѵ.Z}\G?ƹG sG-uD 04:mWWᎌ#!* ;ls(he 1W4C$J7GC/ty`F ЯP\tJ l1:wxc]sz#(*Aj{&~["Sb6do]k4 Q3  NTnG*LI" T^_E|h~)ݿv#QKK"[<עA Η_W{cπ,U,>jDd(g$K>)>&z_EPC*&&^97?'јX!Ovvl96 ?^DU EL8Ųpp, 3vre]G>~UDng1u4nžv3?XV78nA_0`Vi %Ӯo^Z=bYo{xK9H&^F v\Nz땻7zyOi1~f[bi u} fSyttt߾"‘/fgQVMNNV5drZ~ j;;;xqTw[ttadj5>."6 q{[t8,P0i#2) ZL<;{ͪZ[4.4m_I/HP>)ՈƮ{|rM_9 i p,*-Nњ+X8$VN'D|BYH gv]a(pX4 cNN M-f5a)H4M,P>N;D/TiooQ `Z,Tb$_vLQPQII-%e2%gɎ >ٮzgjs CNwЛ$PRtt4UjXO_@BHVi=w1.ūzT?^J)P?H;6|8X S9lR"1'L|%;rhҎ' WgS0"#zs0dZǢQ*2l>/.\DLbkkk 3P*NK¸Ͷdc$ZZ$(ªdRv");e?GZZĿ XPqo^ ,|l@(> U*)ς JK.`ЅL*$nTͽ=#i+* P+ƨBa#;M͍iwzM' 5 І5T "- M4¼\lׄ5$|aAf (6 h5P;7*IG nTRڙʔ"""9 ,,'OëHI ɑ*Vlv vArDT"2BV&B.}L9/i -%&#k@bV"@ Ba~ #5X1qQяliD$[1>A bJ)1.S'j\ xޮfRtFwRHm= , b/9gGP`Hk !U+ 0t6$">z7i5.PcYdtӦÉ_lp;~luuwnJ5 -]N~(+ԉN~ ]e'4h<iV4@ֱP.k ~j1W'xUcNҐOi:'|G<AS: O4J w(fnnc7i#&ttIdZǛ )uc`}_cwsM@w'u]lKUJՙ^ ~%׊GK8=^0Wx̓Yf˖cfuEw_&O jdAe&gG7^Ac9Ǚ[ tqmZEMVONw'ꕯⴹ,..$;TqlBZ 3sbABQ,A,VWwD v[k9[ ꖋ͊q}CRP"hA ̅yN9YJ;D@N:-[ 9o_*8khdLĎc2(jr̞(@g6XJ`;jk¦J;2doEtݝbq32U%D͊KJ @!=|}JHɟ*@j"BDBSOh8g3[Hi/i b C#eg@e7SNxpX:Lyi6UIHg;`β{; G| Ȃ6| $Hhg~PtTPp\2- Hkf}c$.&ʉ K,M[EQTAӈ$&WK*P'S eZ&Q`IkT;U_jBY`ѡx]^_c>mܐD,O4?H4tCG2_C@4m]{5;Q8WD4!JB܂Pi18AqيJ15{KjJXT+N> -H.՞iI]G|L/4ۘTe!F4۰8yaJ>K/^BЗP$?w੽QӔPq&hIAK 1'9(SvZ,i+odq'nʠpR0i\"2O%@#ts4&cִtpyIH\oߢ`>Vl9 Rw} '!\IvvJ)3oW)|Ӂ-EMԽ9wJ؀E uZXT'FcID# "2وPeu@HM6vV{c6|*D#c PD/#5դ>& RZ8ʯa:F:2A(7 YȽDEPKG̰+o#.j!Q3߹,%!JD ԓ.v$b ꠏ7cnjdABDº*}2M Q(V36ذ `x!7j0d-X{ Z3o}B#<f{+oI s~"<+V,Rdvօ! !; 'xD>!J6ƨZ@*:DV2j ܻ·Sk;X_bKƔތXDvBKIdt`Ê|E/Ĉ41:j9uy)X.+3I^|i?/a?TXD*ba@wXl_r9_qN߷3x4!'-s5ayrzj9_! ,L_}`s *)RÆ h@Ii|D zr `إuu8? s+ "v &inVFX`[B_~1?'pd6+s=az"'j}8[YS֪ 0޿xj#ArDz}@Pх-`oqݙ9Yn&ߤeLEOF IF0!,">&,"#E0ֹs U`JBHt`-R(@w g۬t*[ } ИIpH=3m48YV;QFFly2I]A5~1t _9/dص/br!lnA|1HAKg`;}}Z?ٯneJur{G #:,쇃H&wS@@VOkٴ)zZyTO 0q2o:=3Cu/r~4:jEdq9+h^ `3vPT@9bw$e*H O ~C  #-bq +M %`M3H"3jTUTOh4Л~xb>5nqC!ǭmeF3Ųoiq,ٜC &v 㸡=4zz~b`Ο8Mvw?M\lY\k[eh[+4q'O|\\&xpp,7'Uv*4ZKg@H{+X:.z4٬}Lɘ˨?#BHP"9b7YZMTϏKPB:WSDR `/=Eapߦ>ȑ=j7R ʟp3MI 1+}a(I>p)|X qPbPRY1p )L4*d? 7">[@z7+G 76n3BIxgey[F}Gx$ LihlOΞ {Nvxd2ؤ-$ @K%zPB57gk+W\AEPKc9IJrI))K̦" ۙf_ WP#NK9y lֻN.B T!5rjx&9;[ )dDž^yLJ6k`%?t B[D>$QnJm2[2 dCHr}l 5-%1eC!Lf{j xe|s05y?H8'eёFL+`MY-f}O2Ř~;ot"2ڝUq md M+LR ppjD f|cwߕ#| +zp'k) Ub '!q kXKjѨn̹ s{pf Mz1}jjj0铞Ǘ*-gjhht744P>*J!X?Jd [7`SUb+.N /'N&.u04lj hvw&&X > xЧ!}Mx@]npÄ˶DI=l'&gj|KJBkIoKq—JHx,I*tݩDPo0. S"3])\,<m#m?gNjEfƿzs:1=tN`eba!'^8OU<dh eHXNTX@(֠ yZ[蛅43y2"I&MM*e @F`JVz/_h@l?^ɔ(!x-f >p䛕r +s`::i;,fY 8bw؏t|,*I ԭ`idJ\9B7B_Sseo,\Y|]@L''>'xqc{EoFFGp x'ZVcϽCc&2;pp$=d㖲Wn)B R9~3G;$ x+@-S'vǟʹ Xc[fGA,[ ٸ,8wܝ]B wA{pv~˸}ۣh>$]kYs>jU-"ONÐY P545ٟ뒘aϥp/C5J4Gx#$6y^ڳ#^U`Y !ei<>t`wjVRJ6UB$ndf_qDb+u |ϿYW4]P36B@Ozd 'X2ɨՉֳk?LjNm"ԑ@]4d.ɯ^S$ǎ.)9h'%|Mp:!q|q? 2J9'F#  ʝr?t."k>Ov`~v q,F7 M$e҂1yV̷PD ECS`lfy`Miӧ4ˁߋR[iqci5 p#@~Ci fpe娮Mz-!'ވ V! 9Ѡtfᐚf0K@=R00&dD$tS~GXAGPm*'Aun~ayi\=vlk:]Ts|$i(ϑR$?$(]`atG-z뭹-GI>m9P /)"Ȧrę"2})),%-Xa%Ya폧zs < DqdN8omp ?qkYMLN@Ghi,Ř7!s~!g `lf*JѥpP8@Dd.艢s٥P;MLT]{$ߛ$&mRbX=<^ Q}S`ͽ*ʶ=n~#m<3焩ɯ'tUA pYW6 Twynz qnfA+L޿nI#Q'o<2)Q{Kxgͮ{^4RISq3 ͑OzNdAV+A\qdeWRgkL^+&JW+f#u9B?YǺY>zGn(-c7U#o,F=?W =_Ę|Q:_[$)Fp'*W٠Z[[%SbZ2$5W I!W_ނfcK%>*wXx|:QGS+3~`.*L\,n}gzK!$PBՎ\$brW!Yu&bNsv[mR?lL&Y D+nу DC6r'5<j;o2sctqT h@fKաߚyVZ,goRe\'P~pIiAΏlFRȲh|Ỉpa2]ʢV!y{yZ2?Ašieh ,X/SI4ʵ0_zUO/!XrB`Pfx҅O^~O3b\79 vv \숹t]9Bz]F \8RƯ$JyA}NzpW'ܸ%ݴlj`]>yO}>ֹ`F&ʗ/_B^^EZ}ƷaQAkx_}ǿc~QҒ10_4<>:=] A@;{DJI>4['yiުf^rE َ)x~Q!mY&#hК_]E'J0|- a)D[zNAV[0{VyDbɌ^]sɧ066=^b`ĥ\QKʺצ Obo5VEt[N!o7z-R' %o]u3YVJVnJ?XMaoe]E(#ea,爱p9:.A@dc")pBCD{WFz.!PY'UfAT^+=>ܿ/ Է:  HFuu1_g=CPp8ͩ!8"-ƷW&*W?|t˨Fnf!.,RS /m}%#Ay߸k{zlf?wlkqf//zE[6B-) ĥs dJeԷ|>vc\2g7CGGG7XΙ ,urX-8S#.)K {5%ba'$"W u<@xr/;gaa[@XPVRc\3πoSHx}Va=.g'G[M rxfL"s4Հ n=NyXʾZ t^^m;L3Yk*PSbxoK)a S8-E U#%TAJ&r'&NxgI/AqFz5:4x>qPgMA$ZOk2Lkj.*hFy3f1; ܫ&,+ %\=zZAC7wa+<8 N,GR9KD߇=%Ws,qFd&691#*/BԋisT%OpL6y} Z_QkPB)([///{c<Ƕ^Eê:RCU,M.M2ދ_wg‰ xfCYTB$,Y?)/'h++307Olc2`g3IZ?A,4J ZEpf \BiȊOs"X#34YڝPoH>M<QYSzI\##2h?\3h˩y{qa]~j^ qy2_ XcRMR* f&M\B*FK)eH쮴|@e햪j|U6w:Z cT`TMg3n9PQw7oKjgUwt8L<3'X?+Zx4 Mrw_jjm *e"gpLN!҃@P.4 77K%G@-'3mR$TQy(+Q:)49`.YZ`PێE~K,Kv\E.`2#_W|X=ʱ7[V=b32B@[@+c֬78sjE%`dl@Dd.\fhT/A%օ`gSfҤ`Aä:Sd&Â5"ؕ`Ɵ ɘ£>BHK3Q,\$u-"BKskRSD\}dcX۝Nu‰,CW?[l8Dhqwxd>;銎=YREw B34.$jF1_s²7].LAj$﷩#AIʏjhT<ک=DjӅWTT/RX@4?mb"')>ҳ 0*yh.z JԘtc^wO9O-i_S̿bеǎ/!'6)i Ld`=y1]Y&WW;8AtrzɅٿFCЦbHXwqZA-ݧ O CD ڵDwQxq3Ex HDG;@,i(*P?Gb*-?0ň:." = dE ?/FHdՆ* H0J|GK%:ԑ̊jϳe*xABMamg2!,댛*5@%9 ] CP.qZpu$\q/$]_9YsVf~Tlr易9\cfZJ4ԉs>ѕQNč1RsvQ<;I:Q8=y{t3'=sbӮ0;E1#n"9Yz4堩0 x[F!]yt}]_c]@a@NNr]fTOzr,;pnSqZtS ۊN~&vo^X& V)T$90r+ڭxKĮ+$J,dPM p -GS HƻS ZiUd%Ҫ6<߯PO 7jQ$G l[awOT> ![jhgJ5AW2 |Fp?YEJQz Ad.@;2MgiNbiP&Qbtx,󿊆sC6JD,@;X[ii:̭n* lQOٌ ̇l7˩B?h%٠g Ē"I K TLt\S 'O2մ6X?n QU\k0Aku2#> }:?|ݯhg4L7 bJ9bZp#(Tr%Sm>͐y08GADZ\|~ey9 gO{3Dk95֎H  ߾|~7.E7덜(_ TRƠڕ`ʠvSqgZ<%H Fl(OdDCbc1E 訡k\/H؜ D .,&].cs"zl @Tn0p4O{Qd+$A)f4^gGL3-O Q|Q.?GX(?6Ʒː+~"6]sT122%~MBJZmc) z awطǚ<_4v'0OmTT#$Ġ!m_>*|̺Bޗ$.$o(O3iHӎaslVTa*ފ"A_%/ג?~Ԟ.:P̢iŧGj wdzd7ݙ6 ጂyĒTa14s>}4 +1|ZJ6Zhetڏ3=WS1R1 tSDalllnW+ԮVtj' De|TZ;&-/ĸG Xjq `@\)!C+kbK\=^Kaҡ&\Qu/UKU-7>
-VNz«|CoQǠG|UUUA#boߛ}BӦWחΚHΎ1I{eMR2 DCPX`HzpVh 8ѱ)<VA-F<~%nc Q5#RC>o,nr;s$\((e ٱC$c/E fbD\`nCG_7U_s)t41 }͜g@QZJʿ*Iz07]ZBJōK&T*nC)))2Չy4Q^$Vco7}t-u\0XKn\j;PҺ3`bMHO"b<*fKH@爐rpk9Oɜ{O!PDOOB9\ `@cLFSVCHT0#@OL4dCGg!*LA'xI,^7IWn !) z8jhh982T(e$.:ҹK%BIE>*d0z2T dAL!ބhf>ػ:Y7y@i_IwJ}0!u. Z!ZzISf4uGo+-/~)f?ڼSk.vƃ8sC^s7'AB Ƨq8EHHSЕ!2.Yc10ĺRyKy""f&8VwP/o?XCW_oG7nͳuO h*\4ͦ!02w@ J=E^v帛4JKKPm|KfȬ{z=I8O]yE1 _^K@= z].?.oy=k$!2`D + X8 VO%w5h轢oj|dx7t104AwvZE >+$k4q?9$bsvklFW.A/;;w#OnG+&_0#"H22UJ ʱr040__JD0fYV)̺XChXX:T'c4pS/XE<NfY|Ne1b?W{ ;$O%=%nJwg)QdVY@zK3ՑDB|x0^$;3~9Q3ru !C[a&cdEU&FW-W.$;?7_uVE گӃwlU%ⷰ*\KMI/i JꭧtVcz\@W$:c|Y9tى2gm*Trr)Ot %a$,ksQ 3QAyFP&i1Û\~'P6M1_Z.}w^ت@bP2R}ퟕGܛ|)  0ZƎ)(~:AAA0fg[`F)^P$UrO>ux\IP)QM"U&gLRf 7P#E5M7Lr+l8*#'Ϲ>(%}|X_ ' &EmNiIIH4lrˡSZTƤ'F.\^ }yV2Q[$0uF\LY`Q7kYTԮxߞZ"\ 6r{C_Mh"0"Yͣjk&?vo1.*vqf01F]\΅1.;uPꏋ֒|7Av(jg֍bu!\voR!fY79~cXXEWi[}Kn"âL6'p^[%Xvs| K7I9/]Cf%xj-cRXRR\/$9ECw)+XJN&Je]$&~XQx)[4@rx@,UuRɵ83 =˃Eљ?\k]K129|./gar•PPMz300 fAQ<~"AC9بKiZs!,uf .ÚmZoH5%qdP`L&!y{i"D+S]){htxh W@O RdUCd}1TivL?!oZDN5`.y% NaRZ/)&-AVlj|%(%ZV0n&Ҹ3DPBD͕U :If( |&Y!J}LK^YLԄի΂@nbЍ~:2ӅYJY2Skh@\y-wGMS+`N#!11nӞCgNd,sV/,׺;@ƏŤ_ϗNWa ZR(ZBX/n>"0PSS#}ˀ\SYƜΘfqŤN&5u3' mZUd&cbpfC}qkH5_ݶd] TYYY fLGMEp R6L2V/%:*Q`C?<#CzIqZVeNoIH {A$0wr3&P_붟_QA g)1HdȝJYIϓf 7sľƏ k =*$֔N}X 3˖Y: 00 * jMО )wliYWuww3j K|L7vss z̔FQ0NVaaaAeMA~Z:-L%`C Jj0QxDş*Q𧥖ޏBA釓X9 d@R2hr'Ab NdWȑ ܴ\F2y0jEe'rը1Xຬ[籶j n{{j ~$s]%%7bɋxV壾x o\pX&~0"(!J+hHpi RсP~/<&lLJRփGPjr(ߔ4ӓ}{wW~QAO R7׆OL?_sPp|(`aoNm.KցKN=Ԓroc0R$_3,7{```ns^{†&P"$hhNo'Vr MTN7G]'t t#?qj'AAe\ +-5B[°3El RS0ڼZ'-Y>q9?i+<5>V*Y)WRje6F'\ ==,ȁ! pyb7R lqSIz*J;xbqI`#$=[bQ7V\:`DLz ֵ#JX"iu17R耞36y-!&vf0Ouj362-J9 + nqaSНN9ayKEFB@@@L<`tH "mqDc:+2s g!BVވns~6%!f^h!~a!&KAVJo ѯT * nc,16O.ő ܳ#j4? *f/,̔ϧUJR {?7k5%ûJW y#j%8[|O'P`pww7RWطs_X #>H{ pw9+} yH>sUʏ|{誜z"5HQJ?퀈2g D*QRͰE|+aG.{R8]Zߏ$17YV}Xagd,@F-?8SԒeũ>Yx-T+wV}ֳnӥiSީ˛ELT$ .Gv΀w| J~ <\-P"EjVj)wzB5 l9dB;Iå{ b0i[]>]eѰ ͹y>+] Gy]vq2Dtw8le(%c9$$mL%,kq㣣Jq|lru#S-n)VnֳCoӪ71,b)k'l%=VvR^qDt5 E#hXЏu٠6kf6%x]X[ZZjb3FÐBz\' Qfw<>jQkNzS="? Ӌ+bV|miH1C>E]'F^C4)J@F~E/7v78`!#D!'!Sn؅dIcu ۘ[74 ZփIrGfnf'$oX3P!_((?rTԪW 7Zr>n,]EK@tK{Ss"%]Ǚ g/˽R}'ď,"n*K s!w$"oZ,uDž/V YY Iﴦk'N b%KMHVY&畼!*XuAۅ.)O׌Æ|S9c| ?<d-MՀxX:a"W nMc6qlmwVRSaZQ^C)sKLTQ)wwbnfq̵HZ?b 0|i%[2+Ay4 go5>YzcTswgA `Nm.Y EIDRqoiox7漰T4^C+: 1SC2xD|<+Y p](j8A8XN¬,u4͢XzW"i>/J@=@B<jJ!2.n v嵙anS2 )7 Qbk蜏ښWO" 9C0/ JT? '3<Ωw?^5Z[10j!riu$ Ư rP,,<#ImI2!A"pz[̤5a0) KZԸHDը-y"M85ҵeH"yeea 3W`#Fu̸›҂RRqxOa܅ov.honn"{ٓFkͮ{2R+ uZHEs/W{} e`wgY?A8pڕ3;ɘ@UWXfs Vr5VܰG˫A?+>CGC*$Pb2T ē>^&qW8E܅ nE9$FMF..pJ///\i=<:%5ء0FVa2!'S隅'MApgѼeQ@$3nwpn(a(U1 V,\Ƴ~T=/$ KeY~BaӦh(JKT8->;X p#i2kPֈQ(dp.nxivBSd@%3rWO9A1_z&:pDt4{gmNuʅ'{RA?l_&ZٙE`vkC.ґ> 4iOi|N +yd671t@*a{=/Z%į`"T6#a! ԁ-r$?FX6wMbCb#ubOy&ڈIgNf$Wă q> $M?o᭍u .3gAǴ売^ qy\$ɠ'baAT*5 OhûKEމ–3cR2/8p-AfoƆ262!G#m0L7 ksVb$*X~o:O2z)ϧn?W|jdÑ[|2Pa=5&rߘQտ=' Lᅴp+?5,U0h`B(D`LYZx:#>餠yt&gֽ&]GGP/ ?Q7rJKK#%WovvC :gy|"r2gὒĠ^4ׁ-kai9!(~cx-#o'+#CZ܁唊a\V/+ҹ c_+#B[ NajPgs;d=fP?d5֎ ޯ1bYG8loq WWJ ǡH.OQ4d|;{sno1?̊slFU"mVc9B=V,N{ʶtrD3NU=^AyxpppbB͹>ύ9a(%|N$',>9~<}کgp? E19TiNPt6*eNkeXNr>gniלd|sb=㲵`~D .ڊTitT5V`sQr8&K0{轢 5uab#|/1pOa!66laa7ㅼ/!@o7+ΰ7)))[ώTZQ"ЯÀ?p; LnϟN^6u%9~%V;m#a~B''p0 -o0)/RIO8/u햔Bx?̾;Z zL=i#U5@ ;,YI{0?o_ER.ԗmt %H1Κ2G} ZYNd+áJTvFhp=#(8--l{qr(%nKo=c ,<|1IWW3.ۃra~cٕ~7 ۼ$ya`AS޺U_]] %ҭx?#Lȋ'qwZSNQk UVN Re2Bu ?tŴ6pj#Ox헾*fxml6ޫ䀁9NUÇ_nv]?rԞqw濵W+LUUl wH^,Ѫ-GvohoXAy@ !c "Xޯ4€aYf.jyz+&ByУ.+4#GH8L{+[Pr Mn!*0_ 8#;VsF+ry$! pR:J_79'Vς<ћ/vcx2_s6SEרԻHѷ7f9:/xNr3;UX)r˫#b6>EG7N %_/yZ[ޗ'q v)ɭ8d N_2Pqx(>k<_zI`+7ߟ\B dQPfKΔuO:WsKm'_Dw*@?lU>088vبpS3Lɩp݇~ !F8haCj1 [#a8(,IqL3KװS@QQQo/1zNneI<^쪶md"4hfRTzCgd9Ϸ$tN㟻喖 qp}ѲpJx¸Y*] s{4 Ut=AavFNZ=8춏F_)ݠU AD+Nlls8jC͂sA-q[^.)&'*J䚡<<<@f^.~5,R*vmS:יf7n렴H 2,8*e-6JU3a|2_*&!wwfvdUms%v 2pǟu*.9Q ]pi#eUkhǏ=IX:t:G?HK1l?.D6Bg6D00L_Rw˫ɴ:H!];)CYAApn$s+\wٝ4P_dرOW'dhrc rt%gyOf'en;gW0eDŽ>Nʾ=J Zvg⅍Џ$\+`g4l,\/֍كA4i'rLRhu0'ᄒ'FsD4|P|wb\&wc h\p?lr %uq9q} YCG;k-XȉXvnpo!, ,sJ~:1 [++dm|ͣ촴!r}jYdБAL&ӗ86I δe"sG+m-SFxǥ޾J$xā'+?@5pixt1d=?/#'$hen ;ڡ#\,VeT _ը}DWzԗwC{xDZmd9 1^x`b$pj Ƽ@`;i7cin5P tcF!Ag't'l ?P}@7u7)vb^һu֯[Wf HΧJEΚ8J,W1f^)/lEM`y=շLK̨xi>5Y{BDaQeysOD@˄=͋f])1j55ތ@Mb:;Z;m:}H'N风KSsYI #6HM&Ƚ Y]t % m/[z"<뽝ڑV_ b*Hߛ#I2Oߜjސ|tí~چYFD mm||s6x{Bm4-K؅ܘ2f ,9~RW^+3cx_rDZU.퀄 m_AQr=yʌ5Bt_ ϩ&.|QlF^׊ z.Ho\~wik&:_dؠblx)ys]~櫍:mfB<./``">G(|c|.0]%Sb ?A.h&Qi7dnKh>\G|p>] p2}^~-eZ<13uI4:/w>p%̤ ';]1*g"rdS "R8{j|)dry V=uՆ!4X.?)Umz553,T7nͳt2>AzOIO/ݰ>ap\[FF۷rr3/_ݻwϒ@9V'nh(-PlQ#z&7YV-k+_dr<=sw@% jK߳hl}`5 P$z?6H1UEs#NY6zkp]tGކ>>hzwy%U#QQ9D7jָ x]`"zi\~]l#FYHqI]=,U14 y'm?sSUW9 |v:EGMy}_}}il!<ޛ]ctULN͟^F 5_0#"cgbp۝ &{B8='FG@?@ 8q }U{\ntc__q yMA}[JCS趩88է@g֌CGoi e o2aZ"W7BJj%?|hM|*,S C9bǂk=-k6<[pV ;Z2 jB GMC77A;jy||#M@½u "vń8űM=`WX9WЭ6G RfSˎ9 3W)[Dsf0:5nq$m8q-ef/DDg{)5ج`LwqS Q2I_ z-W2*˅"IwE "`A5|7\8:x8T27xxxsNh8L9FvHoJR>Nv2}%LU v59-tfA /]ȾҚPJJnE4+ϒU<ဧIҲFu=)@?}L?cGr q0":%rw)3>`5ta^]Puxk}7o,hHK;e ԓd3K'`dJገE8pAXgŭnjy.$ч4ꔭ̜suDۘbqh,D㐸ێ/xjFiǻN+SqzNF◒L5ND,/%QVr1=NO$]Ik 1P(h#rYG 6nUcbʹ!waMzjzf7U 6d>U{"*gIc_r"FDZbv"žBw}՗ӧO,d[K۷]h_.g'3jF;;>m1a}z>ysX]vY!"2qez6i>:7+!a?W6~0U!Ɯx{D܄cbF{B_.ȋ2,²],Jrgh p^kPj{78\WydGk]OU*kڷS:S /U[^]ebpi3gd<ˇUp*䝭qh6 Z8Fh54P?#b:2"?A[إŌw/]Oh7 vt[hnΜ%_@9J_ٕyfy~&.>!o&a95D3 >M4X'V3Z+v}-G 4ϹwQl>\~rny(1[([Gn>`̻i3KAf?QkTs.?wֺO%II9SQxqE)EZI>۽~,r{fi?ʼ2KD˧ڻ?dD*kgߣz hDixn?\>t.70N1;5o#wQ-͝],L)SkTTn> v h%_ dt`Q60saSw5u^ڙXZi[e|BMY镃 %ĪIYٺX8IٚXHX9[rupRw41`p2v2DeW } p0꿪ym e; \ d80;U۷ >B9_P$>+4H'IM_*&-N*(.SLCWRx'-jʦhlNjKteSy?ꓥ(R| G]xs9Yuhy*jxM`>| =9 ކ - i PT ݓ #ФNjX6D]ap atIbf:s$q1@I)AR#@I9@#@}q@K cs Tx$10@r'H:``lHv(BN" S)D6Eѥv|6QB, P FAs2Cs~EH hN[hPhfv !@M1;C%`}]xu)4O2#% nYd'e`SidKP42qv2B SB ю$#Ȕ2qK$ SB đ $# ȔP2k~wB dOQdU{2@z b ȬUϨndV29h@7H?_Vei4] /-i4M _V4 O-cMYCG3]y 75]a@xՉG.3Hy=]vR%>~ĻN"K}wqD(;Y9#N)8کj!6p-T5~g碦5~3T5&~K2>O~o 45k~# Q;H2\]}gQ\2-gmoLZ'a-N2I#r"rD\PlBf":ytANd[ ;L`'O/ܢ4틈iښVZ'\& 3r4 #&i:L1MUъK!C5Dfhv%)Σ0ElCR:qt LuQQ"6!5\Nxa8yIydfMHJD'n.23C&EHJ`'n8 ˈ>ښsaZ'jk8&1SU >H '05^GIt( BщC$k\AGQB؉8ǤhڂRq@Ss iH|7' g#fڂ\q@Yi|?g#iZRAQISiH|0g#kZ\QIYi|8ghZR2;M%'3nNn<;5_ ӈqsp1+s:p1v9>u؈*v9"u 9_'4 sBph-}dMgQ!nɝ|N>mh<[J'6rt"}'J4-rt-󫂩>:aD-}HDѱ#ͽ3CeG3#Ʉ9i836!qNΌ/➆6n 5N?g,%B^ڙZn g< '7);驝:L` wSX &%b܀vR;  ]:snl .)^d"1.)^ d"i0S@x\& Tv#@&2+('u7"j@ ('uL4%NL! S:K!@0)I]_@Z) I6@_@\8IOʙ@_@\IO ʙ)_@\$Iʙ%Ȕ[[x nכKN|k RJ̀z 7vJhN=hNkEV 3mi(贠Wp[W" HC3r?aa H#B. AAr1cDnp)Q]0"G~~XGUIOh9lA{D:8d{$ڈj{eGE o^ckc@"_;wFNhi>@sCs0Jd Мs g pdD9K$XFnP FT|i0zvFnP FdA6c\ꖟ\29A&IC9drt0 S`TI&LN 32rPN2*T@fx1('u)uL* 3<:2D@&=9W i m@59W iB @[ SӬ L-k S, @[ 3Ӭa M @ܹ\3{ -96\3{J~f\msHf@_*~9x\3@!G?B !:k`gpRۄޯJH2n_dR{d"{d_ )?Gp2~*M{iGd3ǂ8gwe G66:G ;@ 0 P - #:[">:]"G;+c4K Gf.>o Gh.Q̾@ GL/B.ŒG 6|]'^p* Pw _. ƶT ]_ȴ2k 6{`\Hd"8R}2ԁLBRD2qBh| ndd"|2q  @s dK^jdBx"{Ȅ$Zhzn/2!Ox ¾ dJ^(dJ{@I Tڍ er n/MIQrP EcI.UxD;pofֿ*j9;?(.n6AwBT/9ӹ1|k8Df1XxlWO~k\w"ɸ%QPRQ.{g5Tw#({;G[}m(r4=B'SI-Ӛ*yt~g8xS4lln]?XަtDwGwh?z|:XRӳL&:Q'r0<@`Wo/?W~!t'_A7]QTq~'kA9 2Z og:ԬTC=fz|x哿mW>s  Zw|/Vq86@Vf&$@7= #`#oûs4"Ļ0Z#}.=F 4~bovL>3&2Ѽbz<<9KZ>{z9jnwAĚ(7y|HbqThy#;ג -fe6[͟fD\qĬ H2XV=?ƣ"߅:TՆ79>d z_uڗ:"7j8 #8];W;Ywf2|P c4D 3O1 )h?V: ts.f3N\Z:1`A{OJ{NJgҢhs-dihN1pؓcݼ]v͟A[DKЕ%&*ᠣ'[0˲m W) Lߜg]`81 &ZX}}qx?;cPUx{hՇ)bvSL72F%W%:`{(;4&  =}/VqTuJ#3+"zn+\2Jb8lO?8JJGU)Qöy6s_bgt`4tJ_uQs91vp#'W~K%M4FĴtT*wwryJ%:D?zv>ɍnЖѐ`,eG~N]ޅ$ؕf~3DvyŒSbH_6I+.-o!z/*GU z'ZG$? 1hc{r롦9.Y6:?@8"Y]}1@`O~p,?ވJSh-~Ɔ}׹Y}8m-@!3 5"6t{S(ȼKe~5^㵎_?7មك˂2o`#P քQXxn3*1AAjb4>ƿhw.ӨJphEY0h<#7.T> ݫw"lpN!aDb/*x{0d;U>ĺ-KAAΙ_^'?&ZedBvzsF%JԅCאBzGoF{NwS#)S4YƎo y[ڢCy?^65ͪP_x)r+ ~[ uŐ "ǽ~9J݆RYE[lJ{q% H8g# vwb*>m~Jdž^0M>;7Zk4aVO^O _p >\\{ѤarpwNpmY0J'$&m_#D)MkgDz`M$P44bbVɣcԯ̇/,{`~=إY[%R0n\nG;ݛ;mXV6|)wXKۤ}͈=$wvT6 #i[NGӦ67rX56YO2[n! zZkV*!㺥m9[nb3Q/u~_:j7b:= z(R:\+[r1a }.ѳ1fx8`Տ̲\ƎeoSn 9*y~L=U޵fg^ooR+5ܻiYfP~d%IU3%p|l#%= үo罶W?"fTYO]쮸]mkF? :ꭈA"Ek=_S8 g٬_L?LnX_̓|87v |pPfZ@zS\єc 1G/hA0iq;o;2i%M:O2_& IGyf(DRz}nuhFPiZmrkl[=ӯ>Q:G`Vr-$ )ɨWK> @ v:]H9,Kײ]p|Zjh Iʧ~,BVW}U2/a>p;{"(r}o+TiwyojLP?7bX@ v׹@6Ov޻!ן!gQfRks-HI$1#_cN];cUvllh[^vF2_ V`ULEoJz̎ƬPF#D -QTom°{  @/gNi&"Ess-hzg`n]FZ[dΏaZ4L3(TQF <Iǃ2YT5xz9*Ft+=fǁrFDBu0⫨̞D:[˸Z#/|gu,V@q;,u]\xwܳ7]M;H)Sz&vz6: \:k>X\:ShjH`L7UۅAIJ߬5{xZo?³:pJ05uɪo`?렸(PD wKp݃$w apMwݪzA>֧L2TCz? b|POrtQNKQ8[>sF͋\ԖGSb4V:ZxlE$ vh鼅ߔ/>Bl4mV<9f5!"F(O*(u3dw_8o[âkŘ{q!ͬ?[8Odp[v0[L #JwEuCS„$JoL Aݗo91U,J`´ {mI4&,a|QԹcG&W;oi' 66(|`XluJƦFLc'% zqRwD\qәQUb"');X* `1h<1*v!wLr~܍vr/x (L?hsl#=0%L_7s;"2*K?@,edN `9 RbI2 K|#h5L.MyQi'$P%h[* P@< `4A~7QW=2'O8UJ)3&]!ՇAO'2ˇB?[~9~v RPv%ሟi,]q*^|oq-F3mq˄) 7?$J jKm *;ѿ| |jLݒZ8u>u?(_" -4Y䁔u};J |uv ^V&ykV*NS(m YAzzUg{7wo?=Y4R& $Fg',& i $TL|GBI]ko c@a^sSQ*cu%_Tl?i^!66S~BE"D{X1}E-.~?4';G4N,/YQ{?3?7y"&9ʂ_hl/Z?l`i}7JwF£;- MxDB3Jk[{}W ^/)IsߦLRn'9wۅ8%!,"WO-01BJĂ+C9VbAKp5jKt9ݡ]c6:)AgK$N$w/^oBV.,3%0D;15f]F;?54,RȓC)tJNp'Ǖ^ h\#}$vͯI;<S|; s ^Q}#S v^D 3ekط326Kfը qo5Kj©"\+u҆(ėq2š PGUMvly)0}lH |?h̠\  UMZ.-qbc` CO\1O;] , c9%ԋ]+ },ZEDwue VxW4v?吾dBvt+΀vSׁieY9SoFf!с=ƟkgmL.< =i/w15 koI%, MJ4)~[J8p ,+wZ"dn-Z9?GӀ8E B:[_ޠyo&:~%C: eeI~C]@|UQ3ɀTR.kvzfTv}\ Jά듙4z\W;o~}@ H)GS&Px,l"AȏN.zk 4EYto9+A+(siS6UgY6&H =YS{P3߰2 [)f:qT D[C u> uw5{HmAJyaH%TT =@$ M츜D]o楀M{Qagꂮ+* dv}P~zU3q6ma±< />H5i%kE`b%|j VQ ;s8ĒTy\ qqLzyW*P@:2pb=n'ež)8J_KˠQ =@N!U _S]}/O])#S쎫FSY&GfuF;±p@ { 奵IaYD{ʥ|c|%R_K#NW9VY-`+eUs3Up/;;~0;N98D\} J~egBlc?ݮό&ؤJ/nK(g*+8;ICI=uϤ/8|*,H[WMmuzKl)1'ʱ@57olaFx W &~7)EաѤ|>iA:O̊G@W-Y0DF1`%-ůMv-ޗ 6j^PAowfC:SmT42/xI W]S9&"oF8i,j-qȀ,E!+~?*R7ᮝQ.WwAFzxj;>[w*ё\7m&GY8OBS¢N6n" W'kӚeM>`ӈS[Nxcn+n,Ԗ6Vkš3)xU dj#hD<9uѬ8 B{o._k H} x֑?_ e2^06o cD}ϱhof{t^ߒvkt >&:u4<`v^Iڟ?itOtFp3~†'O :6LzSkS߮{v(_tP&3@b obԸ@8pi!`4QVI4zޥ΃*8ve+3cyo {nqy;ï\8Ff2!* FȬ֮dy1 yvav3E;ڽA2~L:Avu47Tb;0x.@ =7@Z?];-6hfi^¥ݪ)*W伔^{=}QX֎(i>(}aU'9FZuv|E7?uAMpd^'y-K9ʿ1֗Z/7q~%c& ~@jiojbϩБ!;3Uy͏?|T'e*ݞ5QlTOP"2 l縛@gc*#; ϮIq"rZe`"Ow])#Ț*t pߥ";ݻ)ȏP6lI 3S9Z}7^@/{_Ǡ P\@?8OpCoL!!D7V$ؼT! !_OW,0:[TxI'q|LvDRPFq -8OPMr Q+>ZxL?ੈ;E E#-X񪦎HڈJ9.]{eyE(Qi.&b ,@@(N'pr6h8ȝqo}ܒ4J61ߐX\o,JkkV̿J}#`p?_i06D.U6_ׄة̈SS$2R[^b_An"MJ Vky$BMSE7y3LqwެGϤ#?i_gZdIw>s95!*}@A>wߩKTv?":@&<O4ɸkvPUɘU5}mN|ѕ>ĸx 1[|M#R<~&gW&h]¾nNWs*_꽣JW*#Gt_S]m=lxogWIĮJE8q0?,ti֕s 1]h, 81fs,PNJmRlĈZnAۏLG:\u1`[V׬] a1*:i˜%#m@1c~B 2 P FIL:RQ8r6 {РX2p-(= J\جYquuUq{GSxZ`4FŒ~zuz\L)o)`ռߤX* ACt63>^͓3S>z|؟%ٸc>389:NUoz9W7cYX6m;2 # \Ϗd9rO'%n9>`CMpH̡=^ܐ?^r 29/?Neti-GtUhdjJcC Yv:CQ ?nC*NMaVԨ[IT;eTֽBrd^Q;w8$~ *jir*p1XLlbinOc/6vhx1Q;*{b_`Fj\9_1AhW͜cF @C'=ߋ9HEѩtjM߮ E;'ljyɀViOnVP쉟Ɯxǔoؕɽ(B5C 2eOFL]9 cH߬X'I}(0ĮvqYiG0(}z97Ei0_n8'|!+ȋ+Q RF7!fq$@\~k41sQh]>e`*Q 4Jy8$t ūLtH0ğx4/"zΆ<N>uR+wAsw3nFu3C,9TZ#Ѧ]UbO~ bƤ]Fj/%`wѳ?;t{,9Bgw?kXXBٛKW'G-5^:> tZ9${/snq@*(՛)(B j4yf=yp#;>T }6d*(3t$~gxnaPXhq}(n+\ 0`jUሣx7zWa|$C "B "Dlķg("ΥQζ}r_?f30~k<\|\p-py9e94_4CO/Oqxwgտ^ѽ@qO11zԥOZooHOiv7 Fzs3cqrozs>+``[8MֻI Ǿo0[z`+2V `W8(H8*L 6c`L+7-6q;pې -pT̶Y \p4r"C WqaxkB%q2*sV k:Rrh'og޹`:7MoowG}߇bD4pvf@3?/\xp۫ZCߟ1aȥtρg+{NtLJR5rhR όp/%;N>"W}k>1}a=e.6BTzὐdhL{Ub[ZoFk&>}o\PTwb 3b3#fHS]{޷&):ƓL(@R7zF{q$Z Ґ$7P PzY޻LkeT{TC5,i+@Q` Pı'joC/k^V(vk13|Է8#Z.!*Y}x\/ Gw~F~EA( "ٷy:~0( x/Jz;jQEEʲwZ.K?AeO\؋ڡ8PQx5GǾ&ݞ 1׼"G+9t\w E!sŽ]R쪁}0@Veѱ>AoMXY"ۅG2[8+umK"P&xBBo]"0( V'  3@]>'Ta6o1~"I0T7?1X=U#+my=U͌#-LmbƓ uZz$ϊBxN{ vyCF}?"!xk]NvQx݄=bd9HB9>zL/D^%./Z7f^7: iGl T{6y)_+ĹW, 3s? CzSR |  9EU7*.y{О)I,~NoZIH7'~oS:`GvB 9=UXaVx |owMCJ'?<3@2Ro cQ)UVwH,)Yw`ڀ meV7C/g]6h-O ߩ Ha[ (`kP>`O^ W6.W[r|3A>իt>j0~Y `r:V Zj&|7_|{: 'k5OgrWC^4}Tcj.t;$A%-Խ#=;Y֖1 F%;|;H*ZJ8ڐ=; d4H%wxd U[N$aJN'@?d~>N$QC@wǑWBOe=@ZoN @ g!LroۚNFϗJ q $o o!?~.Bo#] h(Ao!s=&Pz:$_77FʦlB(oTKgн767Fe%MڄP R$9Eok>kWAUMx_AUM^@UMx_CUdM>ূH$ U4K#xU0IA;~  P'_R€nO"o+d;gK=C|H MSxRE„%Q[ #s*D ˋFdhK{J3º^F]_evヌG_Q}{!vrҺw{_:e[܊Z 7l||:Դn L\kT Htfo"6TaTKlR=hQ ,A ugB@*w`!̴n]q`9g4W@I٤# KP?eV ;y%|"^+*$׀,U`Gc듹yU(Zw GVA "0oxVxB)x >7/Pm3ҺWBN[j,RWQ0 :/9ے0 ۾`x$ƴ$` &F%q#` \ct"~:!op; -NnNt,;Fݽ ^e凂[/>AA4w>h/@>Ӹ`1}p Sٵpd󂾸Kb%e{Zˆ{G + W\R̬۟oDEDDRP"x3>Bó5S.<yU*o&nǼ1_'ZӾlhX9ae_e7^}W/]]h|_svsc ;vEwJůאf{𬭥EJ;\HfeUARUxw/BtR:J2:P5@~f<~Dï#T:;ndCA~wRRWi6e睖܍aU?hh&/LlNL1N6w {v#GQFVF NG3\nʙ\j?z:#ieXZ'| 2C= U[Ja`/)*)B~tϬNe>?J[M{I*6W VKaT&{4m;[Ob4KW~1´[vB<iEYD$}%Iqyh`m,apd1Ǖh*CKVZ>6R4GrpOT60&i47VͨbJy>vZ+s!rncO#!trnHg nҕpض-_⌯~ 3MVTݑX>]Xw5+x'"(/yh515k0iTGk4»h۾`<^8#>;+*ryGcD [/߂q5!Ƣ#^"%>eQJg4)KizwF^׳gD KN5:xq\EǨ'gՄqɢ u7q\ \#&8B1rv`+PWfN&,|nl6;RឞpvnߵQð mDZ oSri,Ա@#ꜰ2ePh O3:? 7\œO:QB"]Vs&"Uמ'/X'|gxmXvDzvA*n=\$N|N m'Zᗿ ?&I!_ x^FKUTjB Q\Ĕo;s]h{ZDžz0^am0T.| z1Wb?dg;.n&O W'{(4k/ C䷁/(0Ub(9 Rڅ8 yš˙A|_fwr~*n +wAP-[4 a3Q2ҔƶkxV^EEk FM\ J3Ma%Wy[m˗wyl= -EGP0heyM@4 ZYmS/huJ\@B6Wdne3:ёi+ڽ5qFWuuzj88c-=is)5C]jR7-\ ;a-6Ȭ=,ͫ]T eeWl."E; eU)Uq FF~;=Xq)kÅE="Ƽ_49MuӜM9.gߤЋM/_Ef tsT<:Ed vӾ?2~1@ʽ܅b 襱ԭT=!-?hv o>)n$.vih7I96/O+"w荮JJQsLCR2DOm;jdr!U_ZD." A}v\”Wꦙ深V*!95䒦-TUk sW6qEmqiʻ{+ = LyVqg+߾w (/ '\AWyPg_Bz_EDhMVbKPaPsk)I׫y;j`:6UEeG'EmZfB(UlW[O<$%Iz|l=x[z,23m--:*% !{`ETXbyO9 @!  Fm@$Pg_s;'=G򍗳-N!R ಣPtcӜW >+\M^!zekyA%Nl3 fZ jq1\,~mB@A[G:wPsOZ/-Qf8zw+"Z|9ۈW|)sSl!<"2Af5ld60驠r{jjWfe]LQ]oXù{O!(΅v'=> L-:O}@L߲3|v3:~NKKh=g+3*m)c{nb]@S}xq倅L 4ӚF|G S[QĐo%+l F؀هᲂjs87Pyݑ>ybO\nԿ $3vz\$XX^0$5y-kp<>TD @/NtABeeFZFld Ĩ5񀁈&;4Qbg\+>Kyb9Ab )!Ӈ_ F|ï EF3~1sK*#QL~N~]Zs'132u*&\w,_u2|_ǣq=%YWδ;u)7ZBt2Bpyx)BǷ#G7\ǛB|]_oX_ ZAXo#~90x:eb>܉Ww,^&zף\P s!Fu3ʒ1umCIҢ0ܟߪj0Z K էE|(g?w!/q-[+䓤.w?z><&O+Ii6HmC<(pYAsӈ.Qv} QdXfDĜE]*b*2=ˉr_e6ͪ'_j%F6kP_o)1;C _t+L?>t+|o~)B}0jw06$]W.ܟĽpQq,ۣΖ۱5j҂B:ߦXZyHLCgCXaBmXiO~,]"LxKPf\]9r/V-Xz/KO_VoR^n[#mosJ& yًkG6[7h_Z}pA/xj5ִyi%'\Iw"3cYYCy.:BW\Hgh杉㱅@51R&eL )^hiN6}w u^M2Wԅp4<4]v&ӽ#/XUNc1$fKi}?(=.K_LDX S~Z0ct*dqRM{L,|@YJ/=@+DTE 0AWz=b2XbKir A(&חiM:.[ܨ3X'%+\ m-[ڝ n*9H[V]Qt\.1úz5E ׸dYF>U>n,V:ѹnWamKrq- a ŁπcMc8Q| dmax. p*?U*Y`\X'V|#1X`l\$lN"ϨtaN4_yz tB: DFZV|XdӟpRT1I`$Gi1E~uiM׎X5QYK=EzExn;z9B~<DJK =qP3t6oSp*FDz{ꓯ-as#+?ln՟L.KLʺOȓkdpyW| )kV)VE0ޙhKSZ㪵}ߎ ^TݙFjо_bBCܷH- gW,ʹ&YF\,;A2N jS^9- @ef,<Si 5n>m vhEWQ 9^=VYɢmz#j YeE)o-QZ>]TJuֽV{#鯌%ZSg29YY7ƹ#PUW=V`Lox1򞳹$rz{69x|Eoxe0d"1W@zYb9n2J_{{Ѻg|(E enQ>.?"pЇ̐* xXD -XFSK3o-jXNo w=/"[RX_yrwv[g:\k9^/MHT^ǿj$ݼc89 Td9Pn6LQ+NIA}oŐǁ N; UK{~dWPqEpEk?9^"Kfe qgu>Stu{LY85YY!kz)^m Z ̎+FYa N/_m `ifHhfZr-Lws-Vj< :<@kqP{HCoJ16=AqmKk o[]2lY.Jz/5'c7IK ;wD g'׾3:"k *G*AIFmܫjG"o6#ztAz Id0h{ߎ#'v)}݉OYUPJ\̃ZKoe} 4ݪr cON1cN7=|X݋=_`@\!c3u SɓCezqrB0%ZBtK+]"d@z46KkdC&X3X= aUv$)_OY%z[í;MrVE)Z]Qy'IZ.nf[jrO m j1Fԥ-D/V_xp)Q})%_1t%g쾃\}_6'HuR9tՉ&-Fx͹Y"-A v7Ʊ;˔? Yds"ǃ#9~C2!.}+t C]Z-0B]$d)8֠hHхzXH= mWA~_7UVU]{ĈSK%^_-(EFY$XQ%ka D20_B4I$YDEz|ǰ].ߧ֟nv%-K&wOc,95Vnno6Ht=!L@bcHBa=n]^Ԏ;A ϶ A[Cif2GHU|Sć)dszsiz)nĚH 8ebq)$w'izxL$ູ zKoi歊G>Ww02? >GWt[ԑ}dsv 5N <6Dm7>"=Gh-yкMPk(087^#S%im/Tqdp^'`.Kb67援|B'>RE8TkU2~6th%g5_dHN=XB+Ub( =b$φcDɁ(62Ե)-1s(T&xu|~5Q{L[m-2SrEQn񱼌ay;] NϹt%C=%UiuLM]^[|Σ|Uig4X[Z^l7Ĥv8<0"{ n?-|DSk~'̟\]5,caN#*Vx1 1!CX}I"Z@xПDSe= Ԟz7^2ʤ@4JʔQ8KAxlL)< ]ʁ@%/<+G49"8[k9 dЖ7%Bc= lW7͕AwyeR,p0Qs29HJc`ti+yHa4 Ľ>AWC)rߋNMe#))mV40w>oU;ՉhjY>WBu*`\؞JMd@qE@Hb=ޟ K_%khϬ0IvSndpG2o.lS%4vstȣLD&Gu؆"цȮQZNa泾?BFi O׌}ZWvT ;"巟 䍟u SDj (G /2[$W/}feIW2ɚ1 qt%C3y!@d\qzs4St, ψSM8"H&oIYN9[7I%L ضKSj0?l5:'HԮw&PGt&7;407'3iTXAۆ4OzvLm߱Muۀ{p[#n}<_)o:5BV zQ2"e$%:ã}lb:~8J/W9>AdH`l,/QO-gXg$.^"0g-^9KY*͙!Q٤Œby\ARUFnjW倾r')s;YS7?yTs0 '"q@ Fy3oܰ2$p|{$7'N'r.\oStZ阃57!ßo5hAg:V1Ol #6T)a<*ԡ)aQs($+Q}6N(w:끒3K:8LḿoDmϐšSN_=ʧEG ,k.I%鲥gj4Ua1;d+jߖۃufUg:*!0ebEy 2x崢Mkk;lvчqwP^nKɓ;sj78Nq8bqFRL/./OhB?_ur I2Ǽk36RxI}}Bs䏬=į%:\ :Y2!LFmDqeW [\Иtz#9̹ZXf?<Â?YJTCt> )6fQ2ӽ]:l%? ƃSӖhYd8S dmB"¥{RWz:@yHぁ nţq3fKXBn =HKAʷKkA$ڠyg ѵKځ\ %?2 ڹR"K.G"_u/?ˈM ψtZ#"w FϩR#7tF=&SUKkg@\NF/~Ajx=F~ m 4NBn^mo2M&.r<(^0 /~FF Ko{ ݵ4iɐ.x8,N8D((FVY᝚RW~%i9ϺO Da2 g& e*ʙ$:+0VȺ}6,.fT=.y&_AYnaZAqaAڑ_g &'[qfs&–87G[:2\ Q~ `Ԝee7 ٰt2n{Qw;;0nk5'`Ra >F/;אַT_&+Y_)Ü,)>i! _ζyWOH5Pi ,8 B;IsT)?oYxR^Ԙ3rݿI.GñɀW? +?ӅX'?K[)W=O)6}6Wȍ @ZGC" =څM.h+Ti8K\_^4~wkHmV()L$,Lǭ $W<҅lasژ$VpѫE I_3(&C Mh) W(6MG~wK'p&^Q90HLޭ(GX]4f6>ӶUv BTsY\VX5 mJvE6uw'C~?Fy:۽$-B*L$4AKVbF`X[(gr"]`M%&Y~$S0@hYX U\w=FW鲨l7wϓhes TwPz|G ̟gk=qgz@?AUf˟(4 b ~ޅL2!"($b VL;E ,>s+z>* $|cw"YI7*w kө6|∼Z۸N쬠A$z_f3wZ<,p. D?L]7T^}p:^)M_^,4:, DkJ5 ~vX}e/r@~_NaްVu&^vS7Za--1H_O?_c/cxӂ MB`ц ͙WֈMcVw>1& وU/H BmЎhn^7'vyGZN;=HWaPb}+NMtÑ;ۚ );?KтVذ0uiAgnHrSI$ TƦQF-IVRk<95p ${EłĻ;=Щ?sLߟrG(ZSg PY~>)K)\L،t>sr~R`ew2R }K'dkgƺi YIue7NAcGI eI77J1f\,9GSj"giuLg" LMӁ)rG+ϊdUu,Ϣq (% YH޸C^;gi!mlEz['Eޱ 2_&65ARۢOxW&""l8d3H[#W{T(Qi<.%;#'*=2;O2.)=-ũ1J Xlv^߅I=%=x/>#'@|?+S̕"D,~͊~*q0Czd"Tqzh[K傖Z)? 'ieR.>2g|lI| :?S6;3ْH%LٟUrE ]`tw2`:TYo*U|袺\}{Rie zftS3q>j`)0܀L+tc:?cG^|! Ĥ#D)'1{fBp_Ek.W†NIҗQ쯖rVa5*G &gO1?hryiG>.97ܫ 6UVξ",V(lw cyl,6I@`Q3ɵ\Q+pQ>+wW%C|Z21$|.F갩S?a?뇾; mD0`9Fd2}g+gDV5ҝ ڍyOFm'v}ZrIJ3m7o%l\! ^?gడ_6W"3k鼓 ;h.'bm~fLzKJv'PVTF ^{rUطcr+BEe'' ˼XNX#79("75Td n 1c`9Ie]$^eyڧ<&ttN]c/pjJ̩ h^jRequCI,K@ͻ2e5BR$e)Èr,HhTHkcGLsRSs&|Ya}C~^¬ 06:q%,k(jgV_׌ɣf ;&W*O܄uz(~,_:ba5@n]Ĭ8yN`}4X 3cd0}as]TR'*n`\hɘtس?#|{oN:ӣ;Шg4B DM=f5^yGi`!IdUv(F<7Lo7Œ̂%q6Sޞ4OrrAV'bS$)и7P"L%R3Q-qg0Vf[5"SOv'C@=m5νEV}U[ 7ٌGf\jk>'4l$bbo"S`8?>R*|& ̞z>{[u hj<_/nZN=_@|=ĸ܄SԟK27E&Aa`hr:Yi?7k4avl`Jj>Mo vilHXɘf6h(j1+~ٕxvwZir#b]yjHĢ]Q{DOkwT ra TԀ>Wk ~v30fOW cs ex׶F߶gCF3U  utyGg[j!6ϣ?۳L2GGG㌃)ɚSlxcv*F?UFm!֮%u!†UsoNA7dUBVv ӣJgAXؔERA<|:1&AX {sq~ސzTJ%LWSW0y.;۠ 31)ږ ("}p] n(xN1AFlJ$1ɯwƿD9J%+uul;577tnEpD r=౬ PyeYkEᩴk11묬,W>[_|ηcHEk,R2*L0QeP([*̮񻎆8R}A>gTmFm3l8=͟6١w; \X ɏ(xSj~ e^Z^rE&d᭠z+Kу%l;o;(CrH_Wjvv+XW F](=@ʣj̏Y0DK.5v0C},%+>LE.a!&[B̭BSǜc9ڧxU @o3ҫQ2ZF|UL٩RyUꉲcjŕ'φ⧸p)i`~#@!Zˏ =31S[ ݎ2%_ӪntQ;QtV;AW/QK@nk&;ޘHuկ!yL]_j9wRωHc ρmyG$rۍ4ο78SfJHxPպ&_fhV_}WSBzk>} \8wtZOg?fKatVV`bo1IU9feX[_A b'z{cwhYJL@[$TmgOi\\pb |ش )`[Z UWx8$P .bd塖MlpMu/iSy][y[ZyI=ł9J`\ajyh=JڢZI$8}[I%8Lr3a:ȻKY);o uS^+RlpخVmhgt4gH67_Hl"NXi R!ˇג dYRxC:ne\"OTQx#-Du+rW0bJACsP!rwh+ 5$2_X\YwT㺾Fv{C%r _eLZK in-;VQ]޿o$n0s."~a 3ˆACGud^巜R0P$YĎ'iR<BW~i^+mF(A>\*鸂 "4/ ݕ5ʇɁo|4q^׷lO3 YX}V4Jq1rB"t36~r\** ޼ԑSf튖P%6jNiL |mNgN!s՚Ốߍp|ɒi:=VuS'~/7upu"mDp$` bdy;g|ѯʌ-j`$l^w!)0l_x}̼lof*hc=8?|V 3lT0_WTP%|Eb\x5lfAA!IZOx#ͨw':Qp>B`S MJ4/9 K06ChuoW )b-p@ q>\v2p ^ȹ;9J"28{Rlͩbg_UOS!=|Lnxa;?8H۴PcP.cnʺ\j@fR(Y(L8JtD9zj%"ΔÜ=ѲՓ_Qy?9Psblu+tTG9U%M jQh"v?STpYc xYD3jڸv袱 ´zn}_{9S A FabϿ{G>(JkdK~IJ-Mf vFie7d W ˡtt4Ҙߜ2 )61?,T`kN*o""%0y8b! j_ZE!-4wmGR7 H^B 22U[ z< E_#}D4_pBzd m_GGdab@ߞ'Ѡzr՗Y"5 cd,E"2$D_YZl|[,,:ʒk>DFYsbN/n}9]@ێ{xka&R' X<<9> iGP@Ț4Ԡ-=0+Y$IQ2"F1S dK1bhP4EȚ.ԈfD5ĠX|!JE *9Jq( ߦʖHA I*lN7f5Vy b'( 7 gGzXeD=eCY3TuZ"eFH9gSs-̇ ^Eus8fiMN4*6[SdAv{9 }=^\qJB}B6 M'/?_H%S $Dxx>D'*%l03lhÀYLAiWq-( GpiZ.Ƴ yMP&^TST^3{l@<~3`Ӟ5l^ݝ<(?ES5۩=|AgR=vsrK&v~`E [jrW&Kl <+CB^m_r Ay4jWHH,KpC "Et'iC (""KjJ_qitcTqO} 5s~E(n2h5[X7kEj`c92>_ dLW-5]_ӈ]kNb0G7Jh0AtmojǓ c-B݀З@A #7Fۼ=,,ilY:AL];_J5(π)-Jçs8̹=۽{)[ŰJ~qbKzdU dKAQZ@|p︅0ܓ u=@{0D{5O!C]?&e _ȚB'i-U>7Ǵ/Q,4QB%|5Q4Aⓞr~t9]4no6t< Fy#ƠwFЎŵKN@oJlm8o._/]Rըn@f暼.:NݥD=.yg~^}Yki8Z˨T|G6~83RctmjJ _kF;_WWZj"oa`Y^Ax4W[*N3Z!se5g{жl85dz[&G(͓ŤSGεDdvh" Sk5hu{ɠd]!}-iyyGٲQ̡0F&]"%Ľ(~ExT“8ĐX!]k5v3Cղ)mnF3t+wa{TKbfҠl 75~?2NR^J$I@GUv 8FT0y _vXgQn2c#𷅲qVLb%:G#т 3ㄿ܋!} ?F[| ,yTmB7t$/,v[hV2';"]K,|B~(".˷a 2-b\`,ڛw?$y("v(̨GI'dhWjŏ8ZHK~w`X%ۻ0ؒ@"CJDGW,5>uKU S#ylWޣLQ8p?ĕ6k2%S3_qM#~ޟȿ)`*˼Tf5U# sF`v\0qa$GΩPbh:'65@:Qr~DF@33W+YovaϹcǭhBxץnF~ 5Q^>aO\v{Zh_$Txt\v\ŧpS2ݸcS]zGѩ?Wj`(EOr:8t݇ ilb@}pn_uKW.rcŇNsLTJ'0YӘ=X]SK9g~+ϥEr2d3vǼݩFӽ =9)H6jt-m*y?֝h{e^o޿ࢷMg;j*kd&WCh~X)Ŝ]72ni짤{c[Ob C;`JS&LPgv/{٬chܾ^ <2[O+Bsk5KR쪵YgpSZdԵb xN@~KA,P:6NCNuڥZN6k-5<ɦOZk/:o7 ҧsfp;kDBez#e/ԧ%P= C^Vْp/[TXbhLZ4,1T}zcA$BŪy$#m'|+pO!VoEYNRǕL3f4Ek5'vExXjd< BIqjqҊ皵vQ@6vؘYxF/J+dQl–5YkҰMOeZd)g][|fq fUMi3&=Oӷ# x^j *5 Kx Sι7gW7>OK6T5g9vwY7觱*;O|ofˇ'VΏ%A?sMmޒR 4EQ,b9I(Nt{/AA72t| r!SM'{堫~.~;F l6ܻ{J5hst@y %8k2b-l*Խ"Ţ\~-`HZsSRF((*]1eպ~:_mtk'BX%fo׏f5A C1ō4 (H&n{C,xvD)?l>!"{MY%6t-^{oodD&~1p׫w+)YM݃&з'KY+bG^[   |KVMP0"ac4}f/D E&q9_twF@\ lZ&P9@i>ߕZUUt\kA8!{uCT][)4.B~ҜyY:u;(\/+o.@6v7ͷҲ鿶hw4WiвrrKu tQ:yn]Ľ<^1#n'ɸvum/gO}>wUor ~ B' Yz5nWLlQ2bqݺszWbDfu&|?њS(eݒd \+-3#oKwoOqa;>Rii8DG׿{ZdUbY@!B)=3N1FKȖVx{|>9RW,4$`K}};V`ըXi[: #c&`'Bݻ蹹>d Oeh4_8Aӳpa/Lؕ-.!KEeQ_Ȝ|2ז9=½ #y/9vzSPKt(F}vtٻ0,DS#.9g'gjAvq>'H_ Bwcb:o>gn:_R;#޽?!/6:M<$GӲ}=~~U?6ezD ]0ᙥf.r`rD0CJ<q^>yk-*b ks{s<1-R&Mi,2Dӹ8#Ep6:| 4bJOscJ;3'x[}N;'u+V\b+N?yJ $ɽUk /YYs5Zg>׮XC2׮ >)c@2Ԩ5lż;hmGm빭Evr^k,X:zŽ"ۻvx=Ϥ z%͸/IA0ӞWTA##D0ɏjW1S*8^Iő}11XB QتKX>šH$'ɖ"]7uU}0z9z#QrT-)-R~7|J"ϙnӠ-78ߒzQ OWSgO46CZRK4 U<QܫYNF@9*о1Xi1.:p_fW*{OarGM{=Do T*⽶dk0C~/tP0/,ؠrCt?=on[R{g DDCԱKL7 |_<a Rܠ:2V0 è{@ԁL͒iI/l׭9(bw^cmm)sU6$T|.M_|Z-{[wW4)L=Q7/kZwDkf0IP z6ھx}/BGƀ>*eį:F4znȵ\wH`x;XI?:׃~8= D( +a1Z)kYX>PJbavI:P iN$1o/0lw Oz`}Dҿqzsʕù}pnziޜ?p}a[uf2oGkkNUD昧)WF MM!2WWd/¹Ffbjo 8hv!ͩ7<Mr-c Tn]:ƒ2R`viiJ:q+Bƽ2fxKClM "nLHoCDGM"ޖ|D"= C.8 4oS0_{Ej[7P/}-xY[1S~m' S"WSyDTS3AJ| 4Oe@o׿UmBv+$E TBFxzr_?A(Kv gyo;BS@ 𒰛H0\…9~{ '>"]4A2$d0B "!oMHC$({xB,E8NwLehsctad@9jBb_gm~!Ofx2-M;rҌ}T9߱ mޒ0r%)6x:OO }y nݤsG{nG0b{.΅K`2~ `-s}3{GrB4~JO'k8^ eQAr!Źu7eU\ .l#M+yTğ߯WEv-zAJN򞒣MVV "! /3jdx ѐe}L- :+`2a/,<myß'H])T&"&gz#VLX+,HV2m1lnKŰiZ11SX>n1͑MiFH^ᡝ/a'>%(mٰvJbC27CBTYMYL˩"&Fכ14E|why%S:ӧ@),aijYs<3*}8V/TU0j=j7QH^;% uR:,_!W@],ҿشH䋛 5<&#~U2ώ+6'b*^ hA[p_dZ৻"+c߼zǥ c uˆ[ Udע\>c y,+͔|)bF8M Pm:90Uq!^OvkjZ_8Ӱ.XEvRxF$]*de!Ӡ-Vi;p㜬-hKlrjȞW*0,i `["NrHxVFkr%zgMC )~R!hIi Xq`MR8ևSe1^J _]VHLn"CJc?+~3LMH7n' ݬQ`@Ӹ'$2ck6 {z_JtŋAйhf hִE12[r U/g=7_$"E0 +M|_7ΕkAI^=K,Qu%_ 8X~NJ?h,R7KŦ8+x;RگƀW =u| q< z|rV9ªlgVze}&q!G#Keq@ᅈVƓUWr곪5ѝr]ĚprKLrC;wwޞ/7{UUUߚILnI[KPQQ?]Nʥs5ܘ,m4{E_.ݧ.'/_gR䛲a9wQ(,[\٬ıQ`lpN~!Xc^RZMfTzn}w6ٰxzz>| $%U6WpEn84[}ktSq\Ԯn ܈Y.a@@Ŷ] &7b0}BnR2Uܿ *-&U&1>fjqslxIJ<pQ MB<|p6>X ⑊6, R^q R( "}.2)^+-swEE*ND\`ݑ-pyxx y٧_o$VStb&]5: Iz{NGCc ڟ/"CccW ivM'!h2Wjԭr?c3uRWe66AZ"=kU00@* T6.Xa̰9F[8L(k_\8tyHt(К&?c>-׭n閈buill ,#7w01\ >r)M]ձ\mp5_26jelqN.*E!A0W+bU4>vFU=G4,_If+X7eF#K9p+ ]MIYj[.KD2L{@ZMP7xϛ k _3,yQ%:&e/0BEn!= )&?pqd~7x] hmȨ+~$4v)lK#wmI˶5NM %El@Im?Ў? O>_R'Ja6l.͚u-j9ZEp4xc9p+X(;/:*E,W1Qexrd~cwO2)L5>[{GAv0O'{R@G{2P{d9B?FdbwYÒu#? D̬X\m`G/fW*›LB(}Sx:YR0{q` i6QhRņ'9( ,O}d0])%mo!Dۇ Cr*s.Ƀ4S\:bSh3St5ݯ~^R$Dt.r-8B&4kJF*Lˠ2KvgZ:_,p'k2хm sؠAAo`vbG<ɒRs`qǍupLN2K[0(L N;Ee1 6t`ց={Mmg=0gK69GbJ*Ku6‚pKF(s.6njzuɠ;{`˔߷OXGéZZ@W ${S9ɾ\) 4^y0O5ݦ觟^L1b3?UFt-Hm霃JWMM5G <*h$+;i1iCĨr46b?A#\VE3fArWz{!~_9R#]ԭ*zs8: srgJ${z Nփ|md䉡{C6!F3Nt? wC= yר3‘8G'NLFל Bz@ J놧?##hI"RNtttѾvcץbuM&mɦiW_/\/zex eP&::|fh&E荨_ESN59Hk,W ,vQLn$)s&^a/X[NWA+![2YTW$y |6/+\H"p.|ObL8_X2WhT=.(W7L>T.47~f_ym 'xh zK.mC~44e(A@L6׃/KK(x[h*6eA qƴ~bJ{M@e/naQ/[kC@yS>"21izUW{d&QȚLq21{+X'Œ'@w~n0+_AgRhuf+$TOWrTS`Uv3>Kfouxϔyξ.G v\Y 1 \/D4#NDzH nH>}& ADA8'Uj0穦TM 93ߙZn7KΡ c Mi4; l|̂)eEdbiD-HB(_F[_4W>9 ?Fij\HvlA3 -)) ͽ=ϐ8~(~BO0H}Ua[W6R9"~GJHwg&0@(@Òuomҟ|_eȑܭb*@lg Y3dʬq)t<,ux46X K=r2Brd bVkf] h0dwoR-v͖ۯ4L lHo뜇c4qXrN@b \ՙA>.6LiW-AS/?4Ι6//͖kV.~ /N2K DkQBWDٻ8O!Ps@"p Bo,P9@h kڣ9@~5~$&eǕtqU *\cf \5Q ͉Z/!: ZkQ@"wM'Crs:Nׁwn`ڙ yIM ԋrdGRt݌_:a=\ d -0PڥAкVGِlSU %[BԹPTZ.>0%&j(W^Ш.}˨Gr,DȗT71,"x ugx׽G2/Un`+H  M-EQß2ϴSMk\؈\ђҬ+J~*0He )m04dbto/g+τ;?Q).my-R gF[X&wJ|@Zfq{,?}33 ~-~k͗즐/ErXjHv1ϥ1qP4uE8Tnnh\;wv 5څʃLqyo< ~<#%kcVn{{6 UrCkәio`GB$]\ C%n']b(j4 ԑ:A%RL wO=1e-%z{M%iN̯sBX\sxwN%xx@t- ,\õ.TL{6L)-6ͷ:HJAÃR¾i/XQVM@R*vA-1wErJ\hO_+h9?pq= dXd-?$M]ϽO@~ Gdu,(oClDFﺐv(p(Ks\pCeo'o0J?nrMUZ;: +xtnz:I#I`c ή;pNbJNN&/!ׇɑXsNF?/( C5)[q_{P?anO*p[o֘ /;w>6u{q,*@D4]_ :#20V., o`*mK:8崥~m5awx* ;744b%y|f2PmRN1Ώ(Ejd esbg B)Y ퟧS`3iƩwo&c!C` fыnՙn[>ڙ 1L*  F2uʬ-qV_ 5gy"sZ!nq#P *1n/x (3)Sv)dC*teas;(0Zc>Q%$ޟ٥ sqFmՕ7)xj\N*jC.X.)4sm"&{IvDW0#Z{ n} i(j+9Jđ2G͠Wc<2A@YPDb?k#qjΜ!E!\rbs"=XCmd?uABBDWۜ% P<"f@hbʠ^@MprQw_4>'a297.Lq'bgaʼH- b]OF #hp<΃&gn $@6خT%NEKV x݇kK22زzaz8&)"tMμ4))-ݞ2,{]2rPLBdf hM@U5nk0xmO~檎DHW3V3r͋ya,#FL7b}Χ7.$U\V{E&:Wvz=c ZhF6ߴEi&ֽ# mRYCoIax/u*yv pScəJ ݼ=\ZЗ--M&~-dã7~F"+yv~Уtv[;T 'kGqNt=M!ʩ Lq+zswQ鳥-PMfxY^AhI6\2b5R>6*"""&[FNѝk:5eO?du뢛6KhVn;Z13vff&A-Zۧ!!!dʿ: []FqkgF)Ĉ=l<Kbbb,Ʋ/.ml)69K la#Uz?d 牋OI잮jżXs0O ~&U\V1ޚ%YdTeReDm*;gvhɏ9Y'`}ĮK g)o(I_=6PQ̎҃PN`>~VU`7l?vWø8n6̺Ϻ'ϩW{1Qϼ|N1mmEFBZ D y;Ajb*,W. W $ 44 44,,,,CB@BA"!" cA11ECG}[Ax R @Aa`AƃǣPD \9B@1 +C9br1ELlbS8]P՘8wQ'r`tOnP}(.QP1Nwu3}mTX;sc\7{)iR?w%ei`~[Z3@\PYWiy횶Q`#U7Q8k$4T-}+r3 1O& ]Co^U1SQ6@kQR''(5 Do6|wiL:3t)[SrK;R|KE\cNH{U1Cd''ұCBj6IkWHS'ˏSDBߗûU):WETSb aA>ԃߘC[ϛ!3ͺ\]5D6t~YNJ`D8, i+oiyl#?׈˛>8f1WgDLSy!SmVҔʱ# iȡvzmܦgD'7O9Z"J.Kڟ$gnda ښbOmlJfrQwI yU0Ƨn׹#AnϘA4/r> )j~#mZ.>E{KwOM`ÆlPTw%-50-Zl+^ԃxx" ҅cl4$t?O-fN&T UV);&18|JzU"|̈́^~swSc. [<55zhXgbpUU 2طGxeyJwO6۪0+aJFu 3!8΀54.af1m_F,ߙMsJхZJUAec3,x1ZQ<3upmؙ*^/^>~mwLpekX%M4[-?n@1]ůmmR~BM 3v@S|hnЬVR![Zߞ4L|.$C6k |^*H5ClF\/ h%3"5~g?}|$eí5˼IS" UqG/S򈼿:Pȫm^rcÜ@B^ gz2t#Cb~yf+5߫٫Hi0$Nq}~M !;~;jYÎ^xŷ)zN%j3x \KmN**y٧,~d@;mYG8WtT#A[Z51gҧ߂ FϰzS(r2Q5vQ 3a8(`5s߀2Q+9'*{ov EH!j;8ԂB, 8x-uqO~ڕ*m?Xδ=|C⇙h4[SX/ XF@~vW<՚wм0/km+,mzQ׷,tIfC)?VX/q(g%pib7'@/!uyDlԞOcp|Abh|CΌL K|GҦS9l=T7vTz~&HJ3]hJ_0ypٲӫܘRܮ?1d؄d=/</!f,b< k*C uV'4n39E!]sZ_2YkU\WuN,1ț#ijқHmΚH NiObY_>)XjPnOlĬXVtfPK|QM.Yڻ6ʯb5F'ٹ*t7Gt 6ݎ~aF'~~̿L)~&-#+\Msan{m\yBhucrz֧MOMÈ 4RN|sˀNU5"5t/Q<†z DdԽэ/AiDo K0GtSC :7:.#Īa*ЋgՋm 3],D! s"a?Nm*NaLZL<&S-l<E$]R"i1לXC Lp[ɄbZ~-j; W{+U z}f q]!զJ .&ir }XOk> 1 C2lJȁr=VJa{@|_[o_i(Uaen$c<+  fntA&V5S08d_2W^bmyuG Zf# b l'@5K#(`P?N]ynwQ繃osa H8$b5ѹ`R͊]/}2nHj.#"6c5X)rĶ-h``8.Y˭rh7P\T PKutxGO&sw.AYZZZKMK6԰2Xq uR&NU;Pry0smDQ (8Ja*s <~# 9JvF*ɳcL3=Ppq.Y9䍬'iOtyF0?]ZS:ktJb%ˬZhBH(\%G ò _h!OaHNZ9Ih@NV;%SƓmҦ$۶k9稒X=\ITmi2*2ꅃ֯IJx;V_cto !{Yê -#n$,gpZgtrAv}&Lldlq_p{v![ԣMMd4o8t$Y Wsf.B$( {}=oN)6*7W"=˸_h:n .g.H#ⅰ!! +A.9)GDv~(Jz5흪F;vuY{WI DoKq]<UƤՍ]X׾j_1 ACR^m: ~.YC7i B.ry4r8O¡2&xFOLoD{M.aI37MQzs~pmAzhnzb/W`+ӑKvufg=y")й}粫x&~+V] 9(e)kr-Np#1pKGSKHZ>߇$qg z/҄V DfiT5O|0H]ه17[OPuЭܭN: g .PN0Pjو[9 v$m~hU7 ^  v@k7AG16 %4n73l"}hx~;LHy䬺Yt/6A uuEohԙxtFDZ5Z bF۩qCkM {Oۻ2&=Mu~yo os/nSiU R*ܸo ̪nzW S?BLP#U/O`9~߬úF->W|Um(T,go9^-_LWxrK~|[>Ⲁ C{XgIYD򘔐뾥Q6͔MzgA@طc`/ڹj7D A*\oi\(hǮV)Фż}26ɗq(4sO uuJ5J@(tL2bYu{-n ?^W, W\YGN.U{A/+@yKPCBV"8ژ>?M009<^t˶TkJ t/J#m[h{ڌ)qPaqrWD.yQ@|71Ɯ65u@U=$&ysNxWyzBozʹ2V.!H' '(!ЛW9mrIֹ+U7 dM~|O.I* FeoYr d;^9f&]zڔENeiOBO%X&-R魋"l s?nvF)q.Oī݃2'L [ڕl3$$xc1>(3>?o\ѯO%E rVKy3^YY[gu6QM!rlI5j f Ɯ;)Et<ʊO-)TܽKH~ sD5_:IB^bh3Bɓ!vINlgIfIqQJ$gS),$[i!*yC…-K+{%ִJ~_5X`wR LI8D `)@זd/ 5ŕLKi ةĴ[.oV/C#8Ed9&<<.<7PM]yJZ?a; ϥB^Qn5t 08oPvUc෷}_*DBo-CY9ד&ـJJyн"ּTNuU܏[*eIiԵP"PM"F9ܛM=4Bhfhixp?VCG.b $vxCs!ۨdq+qDes EQ*:,^M= V3񼡶)vwo5q"+yz>85OZ?BO^18O}Xyofm"sƀl1]geCr]JP!IձPoĹQ81$-'+%* )v{I_m,شa\/F|SNdK.}W|Wks_%*\e:S,R9"LuI2d? Evvc_:j(2; $EoI*8Y $C+&V#j")a-1Qx֚}%9@MP0 ޟ:eN2/oN2723q-%cxJ3PS)7-YQlETTrvXkLTq%ڑb@÷<Ι/C.rko&մ/;[lNqH[3V:' pnT, gsp|xUJhhl如\(Bϋa~2w=#޾|)s3}@2w[zXmeܑs¾hLZ6hXdZ<$I A.5ԐSspB0Z]}ixv3!@qQ%^xIFzm%]"u)a'3Hi\\'oWOj77 C탴㟂ivxӠT:ֲ⇹pr*|~ZC$2&+wp@)3*-78⌙w1<|Q A`kdTHHs_-\uow|UqcYk'O4?IK8818x蒰133p0r3Ymn}8FI'29;6r27dUOeI\\H>?}mUaU}`m˥ ,Ӹ8D0TJwү¸^H^&?)0 3 q _/ ߬Gedd jeJ$g " )'0pE-8XI 'B~'˿HѼr'Itx[`P"I c T5>/>)Kn\uc4y:Omg37"L'vVf I؁+vVw!7v`abFp nF00䢣zD6U6@ 뿃33 '33QhL0b oRfG=4?:1YPc ɗ旴[O.bv` Bl Bl@D841VвqNԗOYqLl6xPs?~"K* B@dXp{X 'Ѽ_` 3R]VB.VpT#9OlH9$tx=|~kϬNi2[cpgHY?C"o0 ;9lan17bglae`b4I,,QW" ,UjY-ea}Ww2I .@qA{"2݃Ծ/F:N#c]e塾׮^;!2"y=@ o)0 1OmYF`Wt#(S0C_K@Qy0X0&@W *s(X98ߥ cxD2XE)xsEN^4,ϡXj'ЧCf3x߉8/pN tѿLUY-feoVx$VvVG2] 3P猉 ? wQB`6E?~>ji"4QDMQťrݭR'ohؾp_bOFVpc(/):PLy}iLPi5F4&gϴV H_\s:޻fo 3˿nB [-B{pBzg$_(\A41$6]ۊ<ݩ"=p 7<)b>jN = .1ou>h<V>U ]5w >'?>:kzT>_ewy>?=Kc\iZY2ߞab"U̾ȔX(PSVyIj6σXxc3l4ba=A1=Ik:nDT]{.^K٭A,qdVb [ic nT(z%Ca4EN)@g(2DɛxT#:'0Ue$6 /(+N1,r݌0UhI;=k\x[Ioʳ˩cXi0"RYɉ>x= uB+목K6P3HgF|VzT,xUՍ8]P#'Y iڪC?wg۔-U+gwG=2594nqUnIgۭL0$qyIyH-@\+M޹}*hn$/sEQi̧1 eRTSJzvI[Y0vN̳v, /2bJ.$~{^ RG\!}DЈ^c Zw HGe(XhtD] PBt i>Ш|I.O6aJ<wYǖpB#b~駼kczu$A}?Kڄ]ˆ5rBqJ<JFt5_yEq2UsKiu`!=~?$rUT)aܝrIn;4K\D~::rH/$= S.pi?`5B<ޓ[7j3:z`gւ>N ٦cKJ D~\&WEP3̮sfzgcҸ -m}G Z>79*FNip \nd*2+0>|VG7z߅)3}wEQ2?pC_]eBAl?:uy5; P.۬`MJEuO y0,+e}wYvz.}`e{f5 n=1#?:[# *ĽЇ@4:wߵ391ٽ/֟kn,R)пiϏSQD NmN{cQ`N$Şsڤ~liAR/2+A! L+ǀpuk}VՋ@)(%XUgN۹*}g\RXٔˡ!k" ɐC) "/Aj:/Pkt3STF)斴v_*ԨDg@h1҃'U5/| 7;oпHY5YjVBmf!82M"uD!„f7,js2P<U~jHۖ= 0o|R,oT6ޥ\ \KeE eBbTKWZI< P#ԩI1mxEz݆.Z6ݧ$ z4Q4Q0Q$i`>^ !/B=ՀEo똉yސU}֌߅վ(rtN}*]xR6eL\߸6NFGyIE46fu6F~)um &qx!!?a-iF0Ra@xELOfJߞِz'O(^E`=c/4s3M#*$B,Z{yp%(w1Y. 2/dK0S%$X$Sz,[w~h^c,uUZnOnS>ړfBc o*3eXt(oGIŽ-SܷzDQ??@G"΀c@{hTNCERKWZj5%ϐ9h cE~a`yRH9$QOH9ٰ?0W P6!IRe=BƸ,X0G\Cp=%Y.G0"|4~gUc٠Êf6q9yXЇu.½^}OD,7ō_,*j_kvw*ٌv}I6ז m8'Y:w8Rq\z/ii_X ? "8H׻VK簢++G%9d>oKy(k0A^d H?Gn# }?|dbM.56U'7Cr6o>2 *hJS &xif &k̹=&qSG;KcR%酎]}$$Wi19!MѦ²\nL9dQwJc6p6gv\R V}gA@x޸+5~E`CHAT?r*CB9!}@=k(ߟNhn#Q3{Jck*vOadmxBZDa&#&;O{C|Qcei>߯X 5s Cՙh4.$O E_OĔ9{fߡ?kr.R=q6>׬ )<0q6B6D虞1lG&,%,ᴄ jP;httK>AtPt&= Ic\j{iuq-̋|ePU[b&:]W{ى) y&0;!Q=o#p4֐w7ރmd3j_{yh4l$噜,5kWp/fqrqxQ+ZAu$}TT.ݧP_E3N~"tT2ԥ`(,80Vt3ɯŘ\,dY\jå0 rڍ}cr$+хDdwdI,8bô7ɫO\p8 `R C#rGvu;c.c*}*<?AA4zDάG:%=D :'=Plq9ZiDAߵ7rڗOŔ>@I,oGBg Q3l BL|is:8M'aBJeB>l#"döM q$ݙ>ęWɺTKd+s;]C,"*<8W{{&{??gL;Rp!„7h9`sMdh`D4PՒߔ (Au՗cVa(-B0M(iBl$3FbRœGv 'ɼUIM" I{׳}ii~nZs3JޚFD=%]žտwZnD}}I%yYs;~Zk,?yhB{k!לfٰ_\eW3}9w/>1c"[K9Bt@$ :8/2 >@34(*ۿ9}CͬL! &8C6%Zc@!Mvj-om Aw 38^qVѭ,= N"|~1-n_Z c([ƝTg!D {@Oy`)QE=_%DH.6Am!93 V5iW|l95! &h.҅-H}_CB0kneH"+Jth&R15<~Gy&΂xU'G ņN^B"Ky)җ$W &~F"IzLyQ=偏2'b?h~TˀSF~OwyYPbVB𔍹_8 >cŽ*}=^8+En#|#fCql^#w*WG>^G;S R 9͉@" <6 5TZCP!Ax^cg dP#Qo6H|]ࢴX?B!s ,Ȳ@@Ttx2c{+ B/S:]CnBz2FcnTCl 'h)}{8LNn2U#WSz)ōj{"0ָ7j`#پ꺬u7NffNr0}lffˋ\ ^$'q7Spפ['b;y Q.X(j@}Q\>ȝF*t n[/1}Pbvi龣7Zd;".ٛo"+JlK]*}19z3"qp59 S2emG4S[MBx:f֢z$;$2RJgc#`q5~|K-vCx%74%%!3 RS;?`QrjN:)&ACz\=\-x0hprw#r;f\OO=kM.u^;wsz9j>ߝ¡%Ʈ[ c#N#S3ϡߋ;2WaBU`~Ll$Fbhq1$e=3tK8,!DA>Y_ JeA]I1`T!<Xe k0FZDjUǦ%umgDI V7SJA%t/ 0 (~4z*Ahf]@eNA3 w' RѨ"/~¦UZgB咃ӈ >t0eY,4!&wPKw86 X>ANUT0[]vˈ)GbbQy2sz(@L?.mP iMk}o3o+RtctڿP1ۆG|>A4L#G 7cn>pX$;D]XX[Bi)iFA钖Ii)Ag㺾x-g{Μ9s>3sWZʢڅԡsW攐Ie [vMyI׉dѽ%o 4 Xe1w[5N>nQnyM9Њ-NJtҧzS\K|)JABQNQ,h &# SWB@peCC0ze6Be~jD;$P.(WOwLaT{  Cl_&,y-IĖbKaZx:&RIYc/jʰ֢-J^立Mj>Vlf͚!V!#]9YN®Pݬtb.*Wv˾^lFl8jdЋ>hCŕyB3;QksA:߳6Rҡ*seFi':CrF29_#[߼ ''vj~aOʪY5y;k֮<FÄpjJo ?їRHnԞ1liEPl|4$=cr}!-&uFksRyFJ]+Bg+c: [+[32C:| fY\>_k?ۓGf.GGmd ,YTT^Xخ  bftr Go6fy+‚ԘեO-8*%*X|,alX ~v§R$o|$T7HgrucP2o\y3"г0(˧ibmQ?ݗώ$@:6?p}cn럝D yH;89`3y@H"͵ GoRpψEE=9|OUPtSL*G5|j:#L9SpٴG8T}󣜛{I ɅG˩}1/9IpE{'kvIwɳ[WRi}οRzϮw]yyJxJdlL\ ICD."UVd砿e _E!kVQƷgJll2v M 1ZwINS.&Hm~=!H!zIYl+2 fPߌ`+8朵k$Qdebc$U(UMT灼T_Ŗő/[R(Zl'bϑ,M}̀HΫ-?H_zo6CR D೩_- + 0,l*42" /i0G6)dy#Yyw|6rQA%cC%nY%D9 #:$^3^$7R[ 6ӳo^ZN)xT@pZ/zb}Eـ{K:A. jaZRJ~F@u% Ǥ%v|9[̾J%e uwg_M|8[blզ7mՎI;ȉ+x 7ׂMһ6MG^S z"0N#'~i՗%-,lݔ*M23ћGYT*Ft 9Ok\S?e FQAqطam{v7 /zm22b%L3p+kmj-25˓0 i +WB.b@8yG{gѲcBQ頯3ZUOgjV qQ P&mq"OP?Q=zckF#"i,ջ1V锲p,f"&K=]FGe\%%6b>!0lڐÌk*bja.s L+flP7Dc.nZn(n 'PzK{:N1B}Zt)ͣ ˖}V&׳\7Dl,6Z1?2_*[3QehJxhU}zϸֶDFi=U^"2>TI : QVCNlb#@߄*<Fz - %5p=x~rk@VpoL;^caxё VZ!Fiʤ:*#$1q_]MrVactL<7^2#5R!өLA.ē*C ta(J<(Lrn sReu.qfR""S5엠Q:[6oS c~<ﰆ~|NI:l?g]Θ`[S'vG$$ė1סrNj$jp~rEPmBm}ҽ5@_gweǡK+-P)L6K.,\BU -rrNQ4+odᆨBkt}JZgtzXgӋ2!zxFI5bߍzaX}0@ WovOTX;3oKT:~mݢH倸㺊z@ōFvGcQ+8nR_ mq vJC'0M]T~Ё)əͯ?ncl fZ{[ٮ_뷯V]VtJ.e9p 6~P\͞2+ 8(ɐޫ71?6%2yui_J*[ U|젌st:t,b5QpNXLՇ˾> CuL;M # (y8_SVS+}$1vBeS&\\/9z-stБj=yod<*&TNmTs_7%1~Fjzh!MѲ5 ym;yP ꡛg6QۙXK@J&jhsqkE-7~V%<6JO7#V 1B}vPU/~LZrGDǗJLe:TV^9 齟:<}0vuyf :5c/-a7u|13;2e6_ltZt{<5pfz%aӽKxF=Y[Is!UvJ}'2Y\9ĠLB"  E r_[/U/2qt>Dg΍WPFF Iw˪_㘝DNWV>ڻ,3Oonk(?}&$^гJQ7o̰Fa1}Ff^WzF-4FKadr>F)SJ(BKX>S))8\s޺&lû'.5/Ymg/Db0ք8x͕dQسyNUx;DЄnj92,%~W2^wc)y--#e!%(/G"6M#kw>۵.U&4$UC̻>vӪuSE4;]=YЪCGӬFf苫h.fzOHt*JIO9.#'[:QۓT]=S%Ǩׁ9TOy3ۃzMVH1hBp$0hc\X,?׮\03i~]1S^`szT$ \:sd!)xn94>}>vw? d|˲^k~H82ㆸ|%TE"`[0ߜxrpdGwV?=Ϯ!]~A.$]~[.O֓N)Ny-SZBϋU&WvkCO7hq;_87eqPqaOL+~;&Yu㑥Izcfkϲ%V-6S dܘmN [7fACO7nq[0KܠOLsB䚠 vMv up/얠pYlt׾@r1~Omhcy9$#~'̪XlKyՌa-T墬;q6@'9y (uq>t'R]JD<$+kӯQMR'M^{kJg{BE{c&BCI=OdsEdbsP-3s\D1DH[ Ϫx%̀HͮhlB]fr|D 3_]Օr^CW*!,D}:0+~QHj f;e&]FoM9+0מG3i` |EjnCkv~,GޞNSirSbSAba̙Bq&ts28`c 2JRɆxUZhTKe`F}F+DTy3g>yh'wáBx0p[%wr_hFB$u= V "CɄȌUXz~ƭ|8l#<'*‚p@9(MݍKX٢,ʅf {Lυ |>J]qqQ7-ޥZ}$RGÖ}|J~ $:3. ]7;i{T,il1 Uwpn4&4n eBA`gćo}{kto= -7in",rY;J*HyY@iuVSdžnDy6:\i~lV{/}%,r=h|$* OZo)?sXUڒ@'jaNCpz첧"쵪x 7r/0\3ۃY\$Jʀ^YSDn*L*+ $>qL%2> )Z@MhʼI^+_LlV֭QJ`&h+s9] 㮨];Cq&̶ȢFV(#)UM~l(MɆoeD5BFdax3ZG $/UY&biU}2+q+)Z .Zg#xuOq#FY.0 V<-1Yf6 tw*kzl:%j즾B>=_:Ȃ VKoX)n*SOv:gTpJaxڹ7 XC_x`yW8S9Eg7Zo"~W,瞤e< OFkM68[LR:{ Ƣ"C/{>Dkpz:2f\s5nrI٨ R=YmeDc4 'bsojV(s= g|7=_ySyMzu#~frK\T:18e{+r -4)- M+t|pͳW[bP5"\y31Ċy#1%AF\͛-$Hm*EXݡq׶5np9ӍzO &š6yeU<ǯՠB X(Y 8>gY9Y,%zұ p7]o0Wԏ86)2-]R;v3E\H.|,ӫ]L _ڏz&Q3Gg@ݕjf:n*1LcR)Ej7p21kWF+Q+ OÄ:\cF\V3uveK Ѕ::8^;hY0Ss9ehN@njJP2mπ D8ѡay"#  %W"lH^ +>Wȓ;P)ƧoɓI,{rXEP~r %}E( TbDg9$r >Pe(> S$j g2e ]87H} CN?]z!L># =@3uGs)eH-3Jg8lU^ɮdҢBEeK͇^;蜰34CZrjsZdJJH2OPq0.g aFgƒp |RhIݯKO%6"E12zig6PhcbVG\OȢs'f{“w>3D2B#cI^GPf3\hT'>;1}]iJ|y6J=CCIEia I+`94q70B)cd5OdG-'W=.ykG'R<4ԖٜRX)ڛ%($bTU1vC,;(<ܨ~Xo Ĩ1;O Q>nrՊ. -r{vIKXƄ^ЕaD"}[ٌ_:F*]̠YLU:R3趝'xum!}{/hvBE5Z=DVyLU*FLJ[kfCh齀nd=:N f]g">űEiO0?X+Q{;Fg/u23X[PG/8{LT9͡% 6ch30,_&/P%Ŕ0'ߋa.7|ՕnnmfbunjRSa.d'b̎s OP'󃓭vd:RJJ~Ncb lq^;,K܄g0d }XHwaB{)@&]A_ƇQPU>Y tΪDn?ĖopWwk_ÿ ːG`J9`uhEbmU1\fRSv-Uٚt%{CIle>ef&cBdԸ8d^Ǩd''S{ۼ=ybz[Fwr)Yxa:hnnDk/mM0gP9%T)e*o8nQzd7meV_F9|?ؗ!0-ԗ!Ax)°_2ۍFғ)L*?"b#-q5xّlc4zt8[@\܋Z;ܜ{;SojC>\>/}Fk{H}wt6K16] ٻlL&L{+Sww*tbcs[leżpIUE@ $Us>=r*& n#MtK,ecE#M|б\DLx*-ƟniJJ5 `2Luj_bk]4,+/l5@4Ja5u[E11NeTFsg ߰uWXBK]jhWso |)yk<xS}:Bf"m"Bdgk+ug#EE :Uړc ygDub1+Z:8z/pwXt+mł]$V}odi[=iW`N?5‚;LP4UX| vz: >r] [9; W~C C{^?w(qOoS.Mn"ej0$_REҁiΓqu@ϑ5UkѵTq}iTmܿ=V|/|v/rbtrjtnV"/{̛).FSη;G|'׭.xzFvך.H37N}UR9$?t-/zw6^Dr-S{T$(JSΑ۪rJQX> ǚ dpXex"^ nd-\%ZOҥv@XQ#s#WBY1ʋ 6`CaqǬ gq.WP󹈪ŋ* L2#U[ sM*])!ӼZ.[ V bc7,DiFϻ'Lu]{q>)ShSsM$/X%L*'Op -Pr&N1lS4x^պUG\hʌ}KIp011(bIbС^ԗ%n -3)}*IlH4Sf>gcKMr73 ,cqRW u2K͸V 07mM"A(`"NUA؜fwW>nUNq';xLN 0Ӧ c ׎XKo]QVB*\*,QI]h9?&jpqʽt e$gMx~wb:46q˜(j<5 3n8[1Ir(.Qgx-j>vR{)6hby**Sar~8_׳i]__xP:i @B* b*JCj$IdZԁda]VbRhsV@Vf,2XWrw 0Tc*W{&:w P !A.N+*֚g@› L&N u'DQK ) o8a;L\w-ѤoVQtx֏1mdzE$Cz &ȆyiZ,!m<ޝ4B#ȌԎnoܨqiоI)-m$޳-9L^Z;UaV8qALYd=swem>l)Nq[JW]&IYϽh#rnO4=DssX&C\p5X٘Le"x^~变 5 Jr0=ԟSue@FfhC I=\2;T:4WZ{d3bhϺyAV`#{ңm9!7S1ZnaI!@)'=]i}~!GJ]G82rABYRRşn1yu_n+$4&ͤizn8_nz\%k)FvtTTm"SjakZ[ѹ#kP<gZM#?'ݕEbe-+GosA{ʰL'{/@VCL|:^̍3QKҒ#>rbm=bWR1eUz0ՋuhА3 ډXJʍY)!X0Ob"&%j}uۢz"`UG4W2 ®U@['߳1b =lWCuߙ 8*S3^(,\_\%g ; Z+->aF|qX)T ^+:vrv^ˀk;~̛4h"kw cw3dok} o3 _R}g;(O#g3qz Q׾7n~LC\%BEi2Š&=BV,o\8ȥbvbHԫ&S_ZBEUXW>ٻn z mj+ID1&R |Pc^"ğPZʎ$cAx񼯵F)Jă9:V}i> sR#e%UPCodt}yRLɄLL;ܼ](Dz[%q1`Sj̀b2b|x]qq; 't΂xfiF*WtV4K<Áz^dm= vAk~AZu~`k*g$|t %L)'s@U7+фnKL39o?xɴ0I /?ce|-ұZ-k؁F.׻#'L H!D^&9Iuv Hz:Yl^̺Oԍ U͌J_l'>pCk \^gBF L ܤgqߣkuKEͩc//߂/:?г WKSʪo': d!$91=Kɖ(SF{rLÀ%ON^$S'_N ΡEXh݂#HrL#}ǁxbr / rR)r>+r0RpOꈲTB2%ݿj< J6 IɔwhcNoɐ…|vhf!eo]Y~&°`"٩i'y+VOHJvγ}]<"\ﻎm=G6^RSnvU3%sIaU|mֵ?τF>uw!T϶K_P0{Qc 4ۮO ųYL2tٷ̧⼮-ðr4e%ҝs?M*mvv'VTE򫛩IN[CMQ D[ygI9k.\ٳ~+d(Ǒbi,S&34pOC,|bˣ\?q; ~?ζK~+W X(Oͭ[&'fX8ƴ8`q8>|77@wwHZ  @C^cA܇ ?I;(kq|w~ wp\ s\P}$##KwqUN-'#9h-N%Xf*"2NQ϶>Vw8=zM]ߟORp_oC#__}T <*UyͮmvbѡbbHx;"x ʙC?%.y߶AMM~C]*8>jJ|s`/_oA?n Py+'ޫ{߁"矉_ 0X`c8TН031ǜ(V>1\A{bj#aU:[Sgr->`Sq_~ο݋ҟyf/RĘ_~ǟJ];pq„kS;|:S% _ Öo8K7*?\V['wZ?=؁ *!ؿ7wvqzҺKR 1-S¯1~Ɵ]?;{;;w՝ϛy٦g48Lꦏ಩I&qɫ/]tFhmm&?ǐ灯DՁ?:9W_8 S GB|a_EV:LlQ %KY"3evJzO{y(0b]1[F*!7~7K? Ns̒wU4:FkV.jؿMc9O- \Uq lSb/ 2=GQ?uHOy6(?r˟.E؜x[~<Z9 ;Wlw~ ҟa?i@e`=XQ+:®<%\Ś=r]b`l eN”~^췘I(dx9zLo(2vd4{>2RԱ4=ԠTՏ?Ir3-N*9-_L(p^+_h3IsZ7}bh>~v/O/|go2%\2 d5_h$AgZB ^?ϸ-aP>LN/d7ω~Xc̽k\r7s`ͱιs.=k\focD0\pæ:8SԷ8Xucn]TF%*O|, LiRX I$~BBkx˿2?m}5k`Vp \_&*0?Ӈփ`~ T _X:DyP{!*PovAȇ$^ox&6fI,ξ@CYg;%RVpx-^oQcl` j~ح`KcA_U {hEj>{& v'?S.%\.;5.C?HqG@Cێ^`ɫ9[LX}r\nUMev:_r}d+dIIνUHӺZ6Qo-oX M0Z9`B?dS(${a0B&?}ِ)K|Jyd&<|eÇla&Y_uG",p"QOc:ydg$|OZI;C 18tm 5mwϊe:ɤl|2f.vz$UUt風Տ,]?ûP?ev49Ȭ T{VSA./;჋h`veü:6gV> ţq: U9nSᷜ]"x-ح53b57ZT5S0v!)5%|Wx,ۋ"5ox7tw/(vET<#Epב?aTeWI!#m5b&w7EG\oMv*eJ:g?.O};ezdXW*? #zOgSb2*Y{`;}?oI٘][=U:dVTi;Upo{zyU^qAQޫC=w ,B:YXzz?|P)K`m,ªi3ѾHu_ͼxb2nA⦎ sbN= 3y r"~zl.>jIV{~6m _ A PvʷY",`\ExyY4 'nFk9KibYDܤx َ297Ug)qs| t ;f\Y"UK_wkdZ?ey3}s! Gg2ŷ|:&@)Bv2>A32n /)ruM[,?Kna 5SPw ۗUܹݦ3/ˇPoϔU#M{]4BwV,l\p|vwcr=iUYs|MmWɅO&֞S6[0k)ލJEN" WN IK#] zWBo@+t>;X8K<ƺB ^[ܙYÏ.!6f<"xz^`—ݼk)Y}!AN!4Fg #oH ZU툒R1{;s[wq7<&6$;ϣ^V_t2D`-ڜސ2eUp |=~)q/> |d9#1;F\湣VYd),OP)r=qZ00c懢=ZSD!"uN[ PڻLGDP_<fwޢhY/9S`͕?mZ@GUa4יv1SQU7Bn$G}|^4hSJtMXdl(OZ"hrGW놃$tJ폞NמAM2|ChH#?Kp$bx$°2uy3)l+v-x 6x@w,Jm̒C?ѯy理=8a<\m6$"7z5x{By3}7yM]ΑQmS9~>۾^>GH=pJwToBؔ`Nĉ:f#%YS|p06~*G >ڎ.<3sTKM `#8E 'QOK1A ;oډ#o?.ޞD=?_(s HFP Go| ,Y܉KuE\Ih0YB&zmEMm.!k4wxY#z !o4 {Lb rPʈ;k 6Z#QopM?j)D ۗOno>xp+CB3XafeM!~E&j d4 'TպN MV q ^RW-zks>֘@S65f2kNhMfKe8~#\G=K9vrr-^e?]Wڰɯ? N+ G0׊f ]Pֺ'ŝJ@t /*h㗕's 7D=&P3TՂ qTCV\M.d8ix 2.@QZsIGChpj"wEXP[v29q͐angRMOi٫E-O-pQ VE%?/W8ATAC, ܐUZT^&I} et; ^S=d1i@ H7l@yC . eو%\4fU/~QSWޘ|i\٠"5yT}WD j08U謾v{׈5B$c4jD(,c[떻T%3Pe7#W wi,8N"GܬOJq[jzt*38*ÄLx_1-IV^(nO,(DnWP"Yщg< Jߊ r~SJ#%EC`4'Flɋ5nX)̫e- RGFؘ*lNQ:]G{Mޗ3v1ߜ[zz:4n3'.3])V!mqWRvszG\.w<!M_&^+. "-dXVzZ?O<'Fkf׸g͛>_;̨L$f|m;?&nmX gR<۬av8Gx!x2zƑN⹉yAR~@,;kתýswCj?Iqoރ0YVZ/8v+g;@7nYQG6gw\Pͼl>芣 /{ޢҽ# ̀rw)j-4wJ.J/R $ˤ-K:%SKuĶ׾& FI7ޓ4BELg_OaY]vE0Ks[i|1)+2f9*Ƹic_CVQk6:6?.=j- ytnj7pbvĩhTv5'T^ I}.}^ۍ4g/8ň@Qx&G:ؠhP{>x%4svGn߫񱣾B%*֯#"<vEC)DIJ2ՉEgLU2x3"y0 Ʈ xт<@vwp{K+FXo h{}#Nx3LCH$!fS!XO֝Bp]gYǞ'@ۖ6ohɱ%E Uo]RbNkSS2ВVݞ:_GrAf7)Z^@E sJZć͜Η #qBl]Hݔ ׈Y(4`}:YoE'Z8@T1 6v;xqT w xtlZ`[WbN04_ MPLPP% `E~ <"oR :Z{ΧS_or{R5؅ʖ/ }EV@){eIJa}1W7H"rc άI֪'mNml739wn"V^#qqYf:NNX=)_L qElh*cY92|3hڬ򹂤]FT~,aa+>՛s =-DCVx2ź0GK_WX{w:W3}GWS07~n"Co+׍WE2QGMMWlT:D%nZ};h/?dxVf ͢V-!︆ԵKOY O7Hb5T=J<} >!*T\d!ךaBaݪ>-++I?Wv%JIQq:H-GPkKWYHFJ{$IG9l +sɜ&C.YBrĝgc/^|bҵ̨ l x㸈)W)̴Kt 1KG+\֓o/RGĵDa ~;xy-Cz>3ipt S˫_$ͽ=79Ҁi,n(ЬOr)ZURݣL^xhwoAVC!E+$G3F8`qA qT^ċjlLm Gԧ'%-|G۠?QۮDdףqwyt-+־1C3@QUkbMħ`-^5&o9Toъ:EY*aSu-cU Y OIv`UOdq/Gi!C7Qi1w$jN"^bX1Q$xTܛDy@`knvY/6=QéԌ2y;o^LTl6"9O3yf4{79FUY)|":A&gky9!,UG~[=>vD9z|0۴=Μv#s 3y'sy'OpZ">|U8`/]/ӥaYh ^S9.:hJ6Y}:p`E! @M?H69cdҁ\e1ƾA9-]1JGGTcx}<-8\i{;tDIwv}t q`ZM"ݬhM7&\:js )k>`0鰟Ny1]G,M:+87v<2׳1egh3|<ެx㖃E#h-Ҁ>n)Ӝ_O JeaBn)#L=b=8.%TB03R9j#fKak#"}3Mo}iYvCFx|;YH7$0Eݝ%YyB^!9]ǫ^q|$1K *lRqŮ=d(G {,l!x m-o6=[t}S &1ոrG3Dz&I9toe,*8`i :#f!iZٟ,R^Xg3}{.nns_ T,%- \d5[x\Bry+@HV†lѭV|ڞF{ƞ2ɢIuEUS_:/|!+v)w3' 勛T;XeF~Oo vl5r*k2xeaDk7NӕWz.{.SGMXU?a=Эi.t%xV(_g=B~q\cY7`}׍:)>+jEάn%O:iZbJH06tOeSJ^ysv5)mU"&OQ@fn~cMa^1:oEUŅ"$!B?:\["ol$V f>|C.oJ4}Ȫ]NyNR)NVZȝ3AfKTcOqD-wh,~hcNDK׾ee-+ܼWvdO{2|Y}hDIsIDw%3)iJ@'ąna@'vӇ=S_g\KC2ha}t_P9@FT /7Ķ˓Ar])캙OnbՌo@v-5ojhZʶC=eUGzAjԊ'6qi>4_7snwG5z-A'j9)Cן͈%UkgV#B_{dTa=|:puRi)<.6kch`vn~ єJ%0q` ZTՉ"\qhu +b4ɋUZ qC>4_ k855n&˼xqΡDH:2Ö֭Ԟ V_ Vr^.1SKO]CF=ߐ|+|ӹ=5b*zj<IQ.7Ʌ}ZtQyarM^8:r3ybjҫʸomrggͬcBq|)2#]f &_藑aEbd#xVbi\P -$51龈aRTKCV?%;a!>En{czV39X]0=v|l:13͒hF1zlDE81D~'hϵc߂o?Wjo)؇)xΓ19~-CRF,kH?ףf5~3QRKO ~3vzTDDi\>ܮ(+-M޾/P߭~4[R& iKYnvҤ̤52gB7+Ҡ޴Շ( h/macޫSmek g fX('Q%m.(P@Gu;i A f%[[˘g+w!Z^G؟ݍjmNϪmR(w?U0M 祛3MR7} u?%ZB4:ec_ru3DZx-s>Cu0=f?y^sFp~P{Z_b,j^̠OؽY&.O寛k"Vm칻b1̉V[( G<@-ޝp|>ںl̓WA[VP,5 .5யQ _/yV0q[Yæo.f34YJŅ*L(%1kP\M:)Sn|{/scٳ5%֌jf2ÚxDC-pDE;;֜o>lFd|}uKN7- zG\5a^.QIxo;Ra4JE@d0# y,AycTUf/z+{dة{V6##^-׏3"?oE78SgOmMA"Ź)oMYxps9|A|])ѐ+ʍ-%AjSzrG>zS|yGDirf#,Ӆ(6:;IλjչƆ|Htۛ 0y>"O?AVjDDެ>L 88:= %>x{M,`>K2ː'm )Ia)X2u_*(aC*F7#y߳iCӊ~fHR:5ibyVB"m_=7Z]zןnDoscv!%?f G?3U 3R$2QauT!)-!AfPgqI]{A}˧têAcgEa/>flJTdAix΢!j Y"*~wcdzz9uF5sW,fL]p4En}O"m9<{_Ozwޔ!@5B=ʎ(L򶁁;}}y"3 z }F{#I_!/XS7*}bSa c"*T63J3u>>wI㈋T"~鲝}[wP{Ҁ }eN{{E}̗M_4ɏV?G,7w,no\`o@݊0[)hZe`l&fz]Gtg$fgyaD(C\j_QΰPx'&EK$񢦍>l87tsmKN2iM\'i {.Gof`+Vѯߴnz{h4b[鏑V["59';3,7(¬9(@_.$ v%wMj[p܈^KS/΁S_2? D2yE}0sA/y#>7)|nRIi IoBS(e[|>>\'wNĽּm#|2G x6,Rf5#_UzE5].||7}4 "LLU)9F3!滲4ʷ4d,5x"i\\vi\5sԆ|[Afce]d< 9󡞜yLO[pɅqO=/M_#F%>~$6'k]Vb0E1O0Kk.b<}gLi)-ZUh @0:w׊ȫ(ΘW_fc6؂m4-“Z,sLStt, Z[F"*A ̼I>e)Fe@˝TBM$k>QMZZ$`=eOY umTB:o|͜t.pU1y./ ]w_=+A̻st3[ifm*Ef6P=Ւ)@87t +c vQgXh6QQnG7y& k^Bi|tǞ-nQOn325ZBi$|ig˙ey,ŷ(k`ucxz{#oaDISU&!eTw{v%h\fUwq^8T2?ED hx VLgnVMaQfuCmqrA5zefMo,!U̎j"WW*B&k^#醂ru ѐ NKV^RR"TjQ#*f$^yg W:e(>orgkXXTIt?ZPQ :Ed#fQ;i$O OOVxg(%-z'N, Yru`=#,E'Ab řҶ7s$<^XV@IIp{j\'R}-v~{w~ i!O4M8K.zgmV*2!vQ`q\cjZ,4ҺmmºښF b/-QZXғP X4a։OHa˧̉6k "lfձ/ OY%E-NEwqiLiPTL*O?V^I3Q;sW.HK^8>WuB!tL>?ga$ }q,s )I$28u ]"k_J4NK&8h =T]]PND]lxckeWpisGEձnw۷Fso\#߸@> ✊OH .♨!)A#z5ƉVC+e!W1-F&pP!,➉"K aC@}] *a$Br(E)U+:9ݰ;FժVRڅL?1~-io3A| 6̯pTc]_kI -@?s?yAԎCJH߻a cA4[SnSR(z5>526"iNo8P%;g*inZʖ ݍSMqt[-oKa9󐼥|b{:9iȑ"Wm$n}NiW0=k>9D>\p18I AgZ|D'[ R`I0Y\f|'I `-._<~zQ "8ٱ:|Dxa'}q>d}x1ThJ~%'I1 Cyf0JJަMo6Y ϊ6=?{aEp:l%<dz> WdɺֽD݂ j|p\'G@j ۝3}᳢֓㱪sI;yי}w*WLظ:%p/m.7_HSL]%ݷGJ)nO<<|Ī.D:g/7; ?F]ik9_,:5`́ Ԧu)ɲ3cêY e8 ͛>vJUMwKWtýQ@p+neB/g:x#5gN{4J(>ZB%9fA@bgc`LˍxU4AZMΦa:d-DCƔDl)_J{UϕܷL?d>9qT_綧XBv=GG;q0)]O{z6޵&~f/N'X{hϺH͈"$blWcD3*;g]7Zw,:u1=}ciz5!ֆ'nxDdxExba(+RoS?mk{{—xaScS3u.A)iv#=5a.J{(:~0mc(|8}B4F! 94;?]p8\^ivZv/'0 @^_ȕmwx>n7V6yJ9) @,LZU ! ?:doa;{Bg1BEMgBN:uj3gu=3Kمġ{%;S7_>"S=V,^o_ګ\̦\F,oOroV& Y9gBf/, )6Ufیx|!>ܸ>~MdĔ|QoWoe9]$@z_As^>œ0^QG[~ xs(7p=\8<@"-zU_ oaa0ea?, oP{Lm ,XtQ%{|@՗?wW___*$lP\M,`Q}-Ux@.*F.3C|qAqxC-^vᅤ.e9.8vP!շ[/C0b?`~9~R9Y̷O@?d?)?SI vE g/VZ:g{@o]8d8IJg8T8RRI⸠$~䂒I 'I(şa(?рg1@hB$(&?a1?sQ~ ' ſ߿sRq #D(?!yB.ص?CꏼІs?G~dJ7:VsQT ?!T`T?2sC͏\T?2ÄŏٓGG^:ry~֟GfB n**h֟s8t )5v`2 -4997 T\x~aFGF^a-(-hAU 0/@ÿ=9.@2łA{-5L jMWRNշa0 KWPœ0tv _*:|[gJgP {g/T '(h W레 IvT$4Ё٥Ġ?q@0tI $ t\ Rq$I6PŜ'-W@W |{~ٶYoռxf{Z$ĠSo ^$7gllI 恿?ms}+QthC'&q^  @d߮! !TUͨ.㸠JL|bC3Lg{ݿqB3t_@0K'jk^N׺@qẚd3^I⸚5 @.q tKu8Lbw t~ 0 Wqr_W|5  Sl~o\:sWJ_)j:0j:+pAWps\q0JXϕ _Aׯ8C ]:\M_I q%/y%k:/q_1冊AWAx~Ņ*ops\9и+E ~и+qsA4 :a~R0'׶xUWy884 _pprZghׯus Td Tr.@y"xvm@u s'y@Wd 4j]@ qW_9< n W\mTvWи+|yenI+qܐx@Wq]<\_@\W Wp_8>\!.ȕ7Zĕ>+\W /TɼR7~2p_8+AR.7|\\m/t])xENp^)*N4+78gjA>< wEp]<\Ǖ2ҕqN˿2@~3ANt.R _A8@W4Ḋ *.TqPV ǕWeP'~CaAW (?[j^W9 7yX+UwEB3M%9 ř o@U+}\Y@|u7KrA *7q;\*ޮM#BӃH˺ /g S()Tck3X,nUv#G0FJzhgrf[髹'Bkw ?,SZsJI`n9+Ja?SDi(*W:j}VJy8tbb _Z +T6b(%EqFZ˘bHVsnZ%y 6h ;hw^ջ]iT:rފ$JJMlPP`&v=0T=.)tlSqz\Pٲ@c| DآiMO gvu@,1&K2}Yͨ6NKn~vL(-:Q)e$rY-w:a dEa'1# ޱv\`EЊb!L+K0n框oHiځ%+wb+CzyyBJ={N],OgH18EY;NhßWo'>}ESDP(XX#QvtlȺO`#֨c14mWʃli'AmJIZ?^3맂?$ʧ{-eCae` |(vͨ:unCZ"ߎAՉVй_|{{s{)':0f;f%W7A S\R5fhZF7ā@^ Ri @PBP("/7"zO ÔbtZ$Iq5k6 sVG"։w1<abb { }ObOv[ Q9'<PGHtyYwlj)!Q Ra2O?Jp$ঽv+*,6(6#@EbE3ZUqBׁslk]J\>ZDoݹaL !:ةϽv V J;JVp7m`Q`Nītym.T"TIP[VTČ_y.^3{)VRNJ L9:D|JQ8"9wR3n+| z2Fܖf&+@ix,SWUX%1f͵㠣JKk>!*!>j;]dz Y3WK'v1U[=&9i# QlOUm,1paIu8̞GhEe5" ",4- %\`n'"21@9̉L XCVu0߅&E)e%F@,OΧ% 41$lSE P3 pU#/EP切?t('y0,9fSi'd4|a YNXs /gSV1µqWC`2< >Tzdx*q0|V$Օz,n! > xmcq}1<H7m΋􌥼~ળRaW\K7_ )C8${ *o7O[;E%C‚m.R+ҺRL3o$㟉KruuP6\Z8QTnBɘ,Rځb>EU:F@mS #Pj1mZ!̂"1w@O 7 xC٥`kվS|Kk-TPC_c7vC8*] y4CԬ?cm y᫼Zg.dǤ" K2GpoUvbk+X\Win &K칉*ktH1s@L5R\uqKj4@q毌`g(0BeiI]r"A, Q`qA#򩳡dCd~7SᅺkX="Vh|Qh$xykS'7tգb!(VJ-K(&mjXNT1ԫ{^if8ũ4|OZ~mv;/l:jsɼ6 rV?Y&dzӂQ-pwY,Q)'q6_?xT1wEKh@μ%'^hIZjZ+̓pCq.Ah|+JCxHE*̔wbqxM3)Fi_^}?Wt?8S<>LUIvq/< S#B]C!]e.UvjV8Z2Y2MM1AIOw4 m﫷8'8!Xό sWߒD-SB2ycO!8 z_ z5A3zUK"'@u]&2ݾ*0~aV+:K*AV8:UW⾪@mJ =`gtx=ږ-jvt'[9=kI^tp?ǩqƩ91Q o { =OK}#ڿ.Fʁ6 7H#@ IC$h agL2`&$p.MmFxhTR\b܏i=5#|b%vvr|q5~AnI ".]K[F ] ?@v:{/qcYĢx`MkcE-n_Ĭ!r֟SDl$:zM0uvk.}BfՌa~<?}K̳3(2O\puGi۱PML2 r,z2.c4yU[Ad+p@KҨs˪8:cWӟBt-x@2_QVXdS4J L^A;J/7LO໛`ldHP,%a RAjl*&"\RN*TQ8j#75򭐶K?$yU}f7fZcЫL(pCS4BK5) )cc=4~tH͟, :|Y}LAt%Yv9ݝc/97 !] %H[D:DmآA,mc#u%Y㤡d@&aO)v-CYɂv!; xjZ/6A&pt" 6u(s)Q2z#萿@EQaJ4O#} 7a^y)ZT~CA3`1/pm%?NޱR愨`m^s(E.WZ4URJcׁNo7考@R7AZ^ U4MT)@(v OW{(0 D0s~TΊ d 싣 3'rjT ?~ \&ӊV85u0>TQ5+Ԫ^1yJ+`Z歼1ifWkZ W%aGE !uq%Qb^O`2mpVn|ׇN"bwG{-KD]m*?|XC.T3 {=IpctM6c jW ^3M)OK] ֥*9hDJGL +Y1DrQĪ@:?M,dKE-x(c)G.<*?*'Z_SՌ<~!:!zt4xb,i+cy`jhYFAF W]nֹ䕫¶.6n1MԅTiR|5pHRMcHΨX5TvƔ`cw}]EbVv7zMjAzI/W5nex7EOYH[t䎶 qK4Υ+0 [wOL++8"If(=p!^…VѴbKGn,=S?#A:3A^LB=BtoSrp?FqQGpUt8cPmo< QQuIxٙ=kEoRL9#R.Tmd?hƍ\bWWCQI70wl'F9ʽDfz<>c* kAoS2 #4| :;IY]Nv1TOĮ9Bl4Wh2 inYDxU]i?stX](VڬRÒD5j"iذIHX3&{XgM[7Lz,^ 'm~-!/=O:IXFfhHTs83g܋)jKxi^r@nDi[i[>z퓍 iR`O3-{oi4dֳoY ŎўʙyI~tNV;5`f6 R`⊈p ,ʭYyyj܃<+}_,Sy?g* MmnQfl25\Pi]JqWJIiU{]q6s:ZXrU&l> .0gĨ7 |mV>ht0UF}$6dh >UYl}xWԬLY,5 _b.bƴG`Cߒ p9|ۤ`n@"UY-"`=-58 Y-,֠T $ GpُX䍗GԄf`K 1m#a1)^&At\qum6 b: j'n;QJApEvVI%BCעJ@}{Bmp '^ x"̰=b|Nj$oW Ҭ+&.o']isZ0hOYd-T|4,Lv}*iX^-70}4l7^Cv7~Zz,8}D0omJ#ẍ́FQ7~ez\k,BZ.f{_Ӻ8ګI[sj;C{Dh5h‚[E~)G]XWcERB~=E S q=jɣAYIVDn,ypN"ͽMd&dltۑUb(x SSݒM. УcFI˝tCU>M.HA~ќכ _gMkl$^/$NjO\ +.Z"[h3̠RM; sv:E XyT OabH~kh;1; ]6ؗa2Lбxm}Z,XAx]聯(58^8;XB ?~&oA4uD‚nG(\]#Ybk>g蹯SWW*VXgj͆W&7)b׾^  Q; t5>`vġ(/(ЛQLrp3"f6Ȭv!BΎiΆ^}(a<[J8UpG\bt6Dx8ԊE)$J ml^#!!u`,/sATn&DX?Tߎ,&f?;# F~4(ot'1..dX`o;  @Pџc;&N*`ݜ/F*w<&>^ EJ7M`#%713,0. ZOb\@F.ft6Xx9c'XOa5ԇ*dV1-`tuk("1;C9ֳ̐;irG=(O@[_יfFwxxq 9Y֔@LZn Z[RDzO 3H;҅FU~҆3FftS eۍ3j ]{S"wozrR n-L%AK \:P~ۙ HK5v; 1ASIw !dZKb>н*3ͮP8'E}C5$ĬPۛlVyl$5C_FXΨ*wM$UEk &fR@\ +_o欣b:j,6؋,Mda٩?`+pJ5Z ~II 6Z*n`ƧrrEn%Da88̏&O7̈XN>"EAu7U{f}K5HNr& .\*j4A2n- )J]_)r.@i%!vxd`./ }ELHΟ)O߯ dx1˯Gi6Nrɥfպl| >j䭽PfSv)oOD-|Bt Nzk/P P? gK) io%dSvPgԄi}xPY=JiׯOwxa4Ԓ%~`FWI ӵk,^?tWC7B|@ӊ+a{""djVÃ+h77\1[~ ( /P(ҢQv7KgȨdx N|ۜܮc2Ẍ́ d7JBYݟkT?kFMq:"UUT".n䕄u_ߴ_^ء,O1#O)ab 7C< >1sGUO=a~_2V%)⁝ͳz`M\g+P~_K*tv*%}\6kaeGH4.+_#%1fw=xI/W5nmFe7#= rZ$j|4 Yhdy9>|u l-jtT&q?^q$\|GVug^V]Ia<ֿti|oc ѱ])T6bxYSeʊT^FRQްO.rpr6I( E6(*%d+R7u|!4zX42MiڦVD%h5d[`WHfnޅK`^=P44BL2A:b Ru( }xnꤑHbgP ^G^l}o=-76QwZ.n)WU5EN.-C9 XipCp`Lڰ'(pGxK,<'r96hKC Q4.xK?Bj`0;/*C1:8|M ݠ;6$2=D-`O\zPk9kQa_0rDd{$ ]bQE}uM3RFCC6VkwB4*V3sO;DZrk"+IB^fR?}̀;0&nJqz",73e׭CX袦Q^= Cd%RbJ8@\J%@y쀑.oq%W$$҇aSY\ 8x ^7&/Sga̰=!gH:9z]WR<ҳq[cشŖ k.%@Ȳj-% !7#c:tHozr䓍)uG$ԋڡOHKI!~֭ڟֲ.`M/"d*"@ȯ4E _r=4p2:m77pLr(ms̟bQ="XтZJ/&7e@ 4.L DJY+"3rT~e&MTi2Zuؙؔy1ðF٥\?6 > iX ?\0# K鴮]ito٧kוO&`|l-d;S:xON磎Δ1lN"ch*N47# iOM;k ai)9byGYm̓ghC[$S%K` ~9OJSzƄ7ve)Lf+R-TB6n(PNZ}d5,VM1 O+t 򟞰YkB*ópF˙ Kfwwh75?dj9T1XˀFBɚg$2u`۟\ Wޜo#w `~ݵ:!YDd н4b~IbPQ`1:*$= o|C$w~Q f_0Q:@=E |C#dSqc+-}"B.0 A,8% :G`q){@3Q)?$mS(q-5hF'n |c]c0NQ|Y`SNw}+QEڰ 5[.*݋cBKDk+/{GC^&ή."W!SGR,Dk#n3^ɯpɭ˲d3[>!AJgƃ.-byLYLI,IӨb|44Q+OB~eI koHxBBʤٸw_H{bBKL(ET8YK!x83k0"%ym'tecK%pߧ>02D9-h_GVEd*0`U[|Lqs$!LD@(V EzRnkZNs֨ m0'Rn(ċeF=fP=4g㨐6\wo_SJnSoM>Wf jI6< {uX`?_<$U=I<1GHbՃxr[Ln1ݣI9$MW> KhJj_fPEb`mu<T7OSP.E92nS 9+[0-cU!J oӽ}q_Fl3P> O J'k/Y(;vএd9s8zίnB N|o1_!Zh/y~}7w!ݮ۲˓ȵ4StT$v ᇇSiB 4(/n4'oDx:ژ)s}.nw?8w 4>C^2_x׫ 58d窒7Ǟ8h`PB-J(Y>t R.d lrʟZ|yو}?pB2F*5,NK]f3, =+ c$?Q׉G3's{^v<)?I|Ni(-0ɓ G-H~hq؟!A~-$3h=<~!h). D3M@8V'=̹<ԀbZ njN"sU{ʊ׽i/~zɴʲpE9m"f!=fTqiyq΋ x Sw@PԖ "#-Zj&bѽsl(lB$$c]oۢ(<*M} n@4ag0p4RT.K] 1 ^Y$J qCuek+>w2 ؑ dBN|,s\,{tkw 6 cP;-b*-"kBHH3 z= lJ\}6]$R?_P2=XD_"'&ذ v7MFC`XRsrC&([YbV nr՘{m0{4yur} >Zl)xN6G{S2X&ezE"cB[amKYI.}R"$ ZЍB)㔹wh16_+oto<_pG#~^ipWw-`иM鐪DKfYowh[R=K9KO $:;́e%>Vso S`&h ':p?W&!9"v>S]Jq:?56Ň_pZ*A'=|rgϋlȺu˄-G8jqҶXTξ sl9h%#Q~.灴3ӏ?}A@} S2^+}-PMmG)nxeV67s} .{~tz` dIy oZoN 4ŠMi']XYl*?elRn0 wa8efh/sr;"Nkc9ݑN;a~(|]QsOB/hS]ws2V`Q/b*#Qj#Ĥ'zOt* c.>󁗨>um[vB"ZJ`k\0/yYbz17u#?.og!*dT_@乭O)e ;:( sKNS7`Rɟ*MdŘ @Jq[(NOu!qԉyX.-NM5S4ϋ3N@KI%n1vy/1KA CK.k5 9)2nME1 p).OzrĞ0S" d K"Nzh'v^ةg x-O^ ȕ )@ʂݮ賹«1;"v jEthr#V/"~{>1ګ^N 6B!dA#}`| $BK`@*<_zM gO"]ÚN׆=V g&:]'"j=l|RN1E U0H]7c[g|+uw[J%;"f s&yA#_ި9r$X2|=Ȧ},e̳QrRϜ F;'?)yt8O_WJ;CoL3LdxXJ79bk)SgaVA%;+"UĂkzrS6h4ʨx6tyH#WܙФH u5>ǫ*ռONc^nÔRFz޷!'e  .TS+>pɵQƩN#WTL{a$Ϛ0)2y~` KLK:zX.)  1g4apxRјD VA1sifo StYRLJݵ!#UxSObղW:[&YƇ_/&>eFQxo:׍GCޙLx#mt 1}X,XKR`cHz;o%&Mհp<r>r+% q:awI< :c_w# ~LHIY|{gFT%T7}qC lր-'1ۺ'A'k(h=l{=Kc.4Ec[= Fk!3k'tΪ Xmi,ʈ rD[T^"@j_ʚL␞%C r,|s:Į뼣6#'z&apY;^> _h%Xa-3E&g{Jjβ(" B.Ȑ.GRHu/y՝aL '9qc<3 ]xFH||7oL\|XnaАYB/8{fY&x{ѻJI/τȼHfd:B0cGUAt1WIN \Zw\DKp PAr'x̱Ei W|"ܢ>EhQS_5P'irooy3#ƴgB`mhrY H)&@\/n8\6tܾCRY.{%r"1.Oj;ѱ=+hO4(\?BuK&k$JˠP 7o3 uD-AAt"M};꼬J(p9/q;\sz"?ox^g8Zn\8CkpElqh&㘳3!z!5cw6E0<ڬwRsI0Ȧeġ%UC4w# ewb(Ohos`M3k.&vcV*D'>OPm>v%[=)؛2/and?uR'>7Ʉ08`<[{??OuE-#l:'g V`OmVuO݌S# ØW+"+ڴ-Ygh]zGRZ}DusLtpъrAxE^f lĺD1 kRŌEQ[=͐qz!gzل7 No%z,~+W[7DWv4}>+{*+y|^*<(,"Y꒹'%c7Q̳vx 7cx"b70s4.o }^>ʞ48zpQ 8y˨p:j?p *f2e? UGJ~ (<Ǖi.\diEjQFb6*nl3[} 5E,ה*u q{a]TCÉZ:O=T]s=ō:DHV[{&Cm_ A$f N` 4POݚ*-yLHԡpd[b,uWX )hl6bڧ6 dG`$|!l/}#u_LF,R \$mr)ǻ6{sT&xǚvƳ#?T'0 XYlP` ݠ[Px]k_u:|1YP*je,@)NhIiv+Y(T/ C)-^+$z]K ;ct+D> ߸"c|F h @(˴MRd]"*`an/ BЬWPzJƒt &3S"U+##M_Ko '$aOU #roA!F"'%PEmz~MaM4h_3z~ڼNaʹ.S9kAd\l*cBڟj?ă”R.0l^}6 5S:a'#B߲7RوDf~*Łl<6\ɥ`[Sګ4ls)t9w0r mk]y#-Q$u#h#\#O\1a@܎ e)RFqפzj'*[Ǣ&{).yuY_@ί+sQ@3!]Yh/!_j Q."oh'|DA]!Fil_˝GQUjpa_yEr2yɝ/l;ۊ.:zhLٳE f %nN8۵(P*N9Cʭz1Z=2p/ $,My2W/hBsϛ!95kEgм7bTW R`&@^u]c<L|,@Ų~D{UXn[Tͺ%Kk*9^A"dζs&3ҼRFЦ/)8HպH~Q&D qѴmb.ouS&~'*G{[MuuuWKb9[+{1 .( 1Sv \RH+QWX7+ HWDliB%5\1}񖷕jlR@4WBgW9?Ng5L`W0qc)m[ϑ! 6U^߮)sNb4J%A|6 kU$mK.2 O@8ѕ( LVG i}:Vz#aHC۠+'Q^p :{~,x]D0iIPIuRgo-h l PW)s*'=dO)A\C<C"ծgm;7 ˍR%Ś%O+o#opodA[so蚟u ;giʕL/`E_؊ϗץ!VL`uU.=Y(ᬹxDRxo)C"0 HW["."ԉfEǾ\n Shz\;2X^=ӃQFa_8R ۡrm $g) 9GVI@{stX3^G"tz+;T0f_L#_9t80݄fl E@c-g4DdۢD/bG#`3z.nja;۠ϫ4kO(MW8P9roz@{7B{u\jEgtRdWvlꤹti*2iJDދpE=P0eT.BNujs Z8ϳs & 2+0H!.TH!vX$orh'X vn]DZuCN= }o˯8ECI>S0l@* "22=0! F7I:"j4YENHe ^S*M;!X.PTVܪ3q󙜦֤ƤJy8M E7 ^X*%w(V.g<1:xdM k$2% 1I+茆2**Q" y/ 2Bd"@nLA E#4L-6ߏ=aDBQAiE}{z5PFCB3͛Dxk* n)|dLKZטn,s? GfAz4SˍGrNY~e7[A~()qeTǘ#ͯяl|`¦x)>ӇB!.s*fK17뀫}'U(d]S7NYRZ]E"}[.86}"fibqD&9ϑN83b)2op[Ʀ*s;˯7IJB:5fsIJUǓ4Z(#Kh߁dm |=+57sN/%v90yذwfA4j"|6 { +2ިl`ݎv_Bɳ/Nf6W)'͘0JPw_8eh_FYZJZ\rYXƇ! zЯ]ӴނJwnQ_bOUs f7$g謞X ~_׈59{˔l( Y/_y ` iw::а6 {}͞XH&(Ktm(*.*yoR1bڈT*#pIʇO cPJ "/r\ t,]9e*5cR\9q UtW$3*kԞ'f sܦAz)d8 ;Wֈي{WnW޻pth|<\:|0򵰉':fqUI6y:a83#9u+y7Lݨp'Q>.K[Uo=z]CgU\̷(Y_7|py}7W6T#4#UL*9B^ڦuorkY8^'Xj.bCL^k_)mB/N튯yx綦1 -Q}F3<ֵe 'Kog7H^ΌJ"l^bSgU>Ÿ-^ATc=WaR~=ͶJZz 早as(LQ$ḣ7xnk ]&zYPV݂ORa?ȟs[i 7lgU]r.P-۫$l;^Qі_p\Ȓ)lpx!C'TD֌GEZҬ&lm'h1&hbqΗCRDz!t5PeYsZS\WgkeMYl.%Jq4''=ޮ  1WRګtC:5ףt6k93:)[N&g[꼴Wm>.Qi1P>-pS]*w)0X@ zG U.QUݽU֏rMD6DCC&uoj|K>|ZL+-|2&pj%iiki>=B ^ki{isF\[eT`yiy){I^y^X%*#j!v>S*U~`$͌ud*-&d>m\!?Sӣ-^~{{bRj\{ay1ˇϬQ:]s$=rRa:ٖ=}3&e$O瞙X5\Bj,/\]ELS\]:ɲ߲U"Q{ X)9l\UØ?B|G!KvƧ ٴ{˶0- g=S)~P7+x? TnyNLt!IւM#9AFw8ڭ^2螽Mb"OV-x/eRTnN\|}A"u!8qϴoFGW^О狦ZqwTՙEz)ڌtЬ#%&joiW5 %gWޝ1.k*.ZHzL14Gu4bmo/6cZH-Û]n=:@mMZܖ_ћ]2R{ǽls':[!.^ܐ; GzO ]"خϵum3t~z6yt~loӛMڝ}[~ó4ڍk駼~}p뷠U rk'0[9{ZN(4VOwdz(nk&Q! -jd/b>Oaڹ:|_Z;3 UOzA ϥ|{BC-im\gCyMu7A B"6w"O_ Oc\FD,!zk4eohCBVp4 Sw&8ul 9"kY  M+`w:U!ZW¤&oGd=spTt|VVk|hYu f&ǐBA}-@;aOįvqjۯ9cUG~>'u++WrdSޅ=rGb;"ijCM ä's%.-Q( !A+ܮ^+re>s֝q[kPYEc/H5ʗ2KJ 2+Z]2D66ǐk+'*EoXv: 3 G0q=ӄf!l:n5?qm~xR4|S]SMcS5 c_CQ;قk)lYP|э5 lxs+ u[}ZN4.jldLl܄A;Lݸ:7 OX>ؓ.hDjZm&nҩcZ<7-QktiC+,C&  fnC~uS 8re+,vٸ\/_"+qвT[qهku V9u zbB9Or4xuNhÒ/ӴZfн*-]w.1GiAHf$?#KHi@|E3et}0W[T8_b QԦm';>@1TRld &Uh3Pعa[fw. E!BE-@fEt=cNJAԞaP-jDucmx!5W\XsC̛ ^tc?&dU y{eO" -/KbUJ'vU'LA&RU b&Qq)bdT)Y]$3G q8eݜi*#~TOb>ؒ.k>h`@6|A+{9w^s3Ͳ?X5QHĭ'Z:zL'Oʶ62yz͈-UUf@gYvXfBe6'+|"-UUAN4N &qǥ"dz<9K\},sQC0:ZGSV=X飁UL9pJJa=*a2&[yaE2b:Gp+y9[ebx2[sł\ޥ{TȨixOd P:WYٹJT8Zj0 b^^m=ȕ?f|HD+XwNƇ$0AS KZ Q#~-GڼmD/ 7qZYZ ]3]W6nqx^[ſEU?>PA}us}M>{;XN+ڗ2,I00(%>e~>7 > UQp3DM`a$lhusv AU5_K(cÅt 4H1 g`;rZ&!7B{S{e Q͏1ɺ5 U|ǫ9,}?wK I@=/-}p ]'ka5|˵M!۠@N35.ijk;9@wƒ޷}EuK(瞢}.+@j4Q Henf`He _a8q_33=?5g4 1Sx`U?+|qWھTY@KWPԞ}/1Ս>M%{ɏa۲E;(d)h*6JM?LgRq$lBK@[6#j!)"/S_坍&@h`oB0T^ @?]|M.@l*n\T|ubcJ%$4}{<@=nihA~WRFDYڂX54bt<* :I웂_1MgaLK޹IN=l#r,=r*5OP{ ߰?\08"+\p?,yծs%H%~P%\@\Ұ%k{Ri:Teߞ+a22r LC--psؼapCqE2!ׂ~@zc Z`|Yd|+l %UQ!lWjmqqjÏ_Oq?{v &CӒ.^53"Τָ;(k뤚1Ѣc-E=(c黎42+v$YWC/6 t jZrp~!cyɢH3 vj(#`Ckb qQb5rB03cl%Գ BP@.gVABF1~FAs1$8C92,~J[;- pfҜ+py3Y'( 9[+8n7,aGHrϹDݻ3hJ}fWNU|йc?fmh)DၒPO' @xeAROQ2Śc^Iw%/[lhpCoNk$9E`_Lm5 -t>?Ewe=go{b2^\>V2{29ߤeE| /u^;k  ͊P~,n_ip϶5OASvNM^iJ:*pWN@.pSjB \)B$=|VO;B0 B??jQO{@HhsWじAջ4Zs%lĴfMEyzqUTy!7kIoD jw2IWB.@|+-?|ʑU'[zM4s\ 9h( 9GN/r/㰠@S\WDJ ;?P̨#& Eȫw7Cspyǻѝ.X\uEQm]9F'a 0ڻlwђ?hIL+Hݧ{. gl'Pdxf_-H7x/*?wh˘ Mu_y;f0trx*6Dg1LpSgɬc&5l"x\rh:[ٹ@db;VG4fUP\,c.55$'Aw^EaH>m x QldM?#6֔#}7MH9دOK؃.6UQMۜϐ4~7:%7<8dg{Zd"VA @dd|@`u#UV8jҸՀUr<"[Ѐ1M,:A- 9=`iL ь gl"BpP%P]A%Ȕh9 0Ҽ.X MǥRi7L&ⷫz; 9#%lW&VQr\#gYPdy]dN)=)bF/4˳a,.IkiۼsZУ{K30ݥ>j*|&5SgNj*jC,yoEMZb&b+quz:ȆᤷwǂI_㻲2ODeaD4HoY@zKc?[[~E!ώ P5p@ *1qmzZM6]wOf$X 7 LcB׆V*ܖ`g%p |M_(q612$5Z I75.2^&<zjA f: _R~Owtx%xZSˊ@uVT$naAMlk"1BɈ@}uC@/@}paWJls5䶢;q6&P77 [goU؆P/"CoC6̋(k!۔cqD-" =g:][9!`2|Ysrj} M̴S#z<\j"氹BB8.Y0%c|h}ֱ܎OwBb[p+̩@acqm 9Bw, ORei7yMAC=/۪!|djs1Yw|.W+NDӻ>,lcn7  񕢵l;Vl-(M&;>>2*vBQ+`]ޭ8g} G>)q7_IPΌ&m_CA=OBr{G!G4٢,*,_`blóޞ?,ڕx}8x~\#E=xa/ ݌)w%{lە's3г@ LSl*}>,ǜsi[9ѠSTyŌ*1gG$k!}Gڮ*WT@]T_Tf ma|yeBL%4%pH>{BعьF yLغrكžcvtM۸%m]V#?FA?0yB3Hr4YXMIQ#EnU#t^ʴñBUT=|E 2䫣w' eMṞ;Rk 2Xfi5kZ6&Y ;99J bGj2Bff$h|2GKIL9"1@jΧC'MN^r~M{ %o,-DtLM<ֲڃ3W#LM7iN>Pe,e04j|`唣qeMCMsD&ƁeYX3 Ic*lbzU4A&(m),!@q7bxxz|&Z"4+ )hjcgVFͨ')Vңn8'Sx @5jvLc98X<˳cSHh)`.gi 9:q}?+n N{Z&Jt33rە/ͱ$`J5HC;kn/|0X5'nlS^ JPb Ifw~D1bcVXr{(Z09t} 0 %dNAZ$+߁4~nQT3Wp2e18+| `Z]tw wv>Od liyJEĿRog7aaI%§ָU᭕R~u:oƃuoF) W_ES )xJ<L/'ԣr֊\-#3 sr*Dʄ}K R.24#j*a"Bfoloy/I8` Ѵ[N5" ?j2Oo&-,D 7Drf['4ݝMƘTSԺv&@>(\zQ!< a2[2{Z\"<lfՂp `d,肛J=-z1Yɏ{Ls!g"%< h 8`Z˩#b$z\GeB}gCJ^K#G^^ ɽC?luTU5 ))ݠtl@` Jww* n8;c耽ֺ9]޺p)'LJ{dEȂԛN=K~D_ГrQ U+ĺ_n{ǬJ/>93~g|.ቚ! 㧂 ]L@+A@*oB?M%-O3)/>z Pa w EnC9JE&Xb3TE7LBh[!: kqy:?q*pn"ir0xIqQ_~Oe5=6\g,֫Kqׯ_'UxnjhVL)/ZƝ_Df#{p\m?ʌ /D`,Hw(k]KZ eWV,bYIě]$izK,ϙfGY %j0B3tcL\6Sۃ 瘊}O>Ůyer?."g{4(g8"ⰱ-K$FtV p1{V>dT̵kZȼU 3s,ޛ_DML}31o?)TR#pF`δd..zY#CleV xo/,*斔O;|׃ IC; t9ա:9=JS~XzjٚNMFN_ }3CBs&ȵJ{ތ4==Ԏ HZ do'Y冭!/Q``-7+dW+[ zFkmL2>ԆSF\U6(kJcR%$}"U;D.N7ǺZq82J,Xw1b^lqyCV[GNXnQo;#uwJ'A6Jg_]u՚.|*VxbUpzCk!J4 NNVZ)S[}c+*澱 ^`kKQy;6t.) !&zlX+8G}?!ոt,aDh~1avAA)W>@K ei -d~um$Q+Q.Ff$'xH[үL1墓kRSieUk 1F=4 [43ëR0aZ oۀ|Z_ʅݝsu?>K3Y5~t.=H! sjzo5G"g _/B N+T l0 FmJ,t5*.0P8xlɮ zK"\ë<(^pG0: uG̳u]̻V _@,!iM̈)kVWtU5LR5aCbͰ<)eLVvni=RZEP@;#H[zZ|riŜP(,(mwq-}M>ލPx@@@L.8LZw973$9TY#J5PqH-n`ͱUIQyխ.$֦ʚ" 4L@c-Z$::2O+oX~(92\0zTمODz2B{ܤи=Z<~#^5h!")Jjo!+:b#/{dNz^/#+`W~#N~~ \%(52aMXʹ/o+/B}y wlAn` 0@HJ.=htv㮓}[t+&ôC4GpXaOhM!m4ã<Q`85ַ-+g׮Nv*g%2$ⶱ0,%(lvkh!3 ԍ_2Y{/җ&O$#,",WyA惖`_NWy]o6qv( )mт C5/"6t%&eΏTH-ad͏2_B/+Ove /p0doEpKAH/, p0 ~DFAXB|*qer4iY#4+OL]iQk3beN#ԣ Utzr24Q5GE}䳓g*T; A>-/}a$ϥsYs:4X( LmMysEB&=!ayeRdx@|(Z͝I|tW"ϣ+'4rh-Ir],s(ÊV=ijxxAד7|jDOp-|dXZscq߄v ,!e'_nm$2a??4jz[}~fm'v3<̎dZ]A4 귎<-|/(h2 ǂwW~QJĝM5<,'$gjƅ鎽2x2p:jۻ"C~l%P-#њ W+ӜKn# Q=GuvKl:2/z a1h!bh]RPttHH14[%sxfSQ?  pQȆb<'!c..<=UE%hIh'l}# Lu"u@VJ1aǣ3.„8{4)d@̹v< 4 Δs2drX=sr\-|yz ^6wXG L-2oN03$7shzUN{tF^^^+-@S~WWDtc4:$)=i:`hXI[D߁ Q٬S u1$x*t|d^2lƳmL<2*Pp~~"F$;"M+9E#=k1QV Y!Yƥ{܇z NZ0D~oro𿎫FHElM^`UzfRj.,hGY9peyYr Ԓg^zW nնT$.v"Vm_O"Q}ެ$./ÚG,# COJ OqdzkNivmҥ0Qg2 :!Ɔ:jڟN4{|r\T$^я(sN#R' J&1h*k:NA " kE;؅~=̚,t;g{4ݓ:k>bd150!k[Plw;SOFչYp)Y$md7m>,9{}b^3eMd7bL鑧٭U)N NSgSu$K29%<]jc8HQ\93噲vlc&[2yTd|/hAl$gYJm ~uB.a"~{/=0k-{4/))鯧|i&@YTpbP3+P9H^OQ9MKuo`"4+#ZGN+EE+F)Y~Ps`@FY)ZR$IJi%|uȲ,2un[(cO9M<e^;#}Ʋp;N0$tskyL,Eny]{ׄ8ٖ'jB:ql'L0 U"+5zB(p}ݳ6CnzK "&` Qnw(̊ LX)y R k5{B6"'*:|1$ݥvKɸ|+FEC1/N^I< h$6aCe z4?+ {y˷܃ٓ~*ehhq091tCk=o;Ҫ}J'[ę| #g+*:qMip&do&ʖ ?+{8RodJTp#~v~?1[ j'9QOs*c6J؀ao/;+F >S۶+qzjg M༽4}HCV6]9ѝbLb` ):Mjfkk&G ney# Q\Byh?]"M7f㬔VT̴j,9JT]U{tVĘrzr+9h>RH.A}QAi[tư~@jח"ͥT8nijay=ܑ҂64~tD;ʵ`ğy͉)J? +geexh p>0ټkΣ~օ;AoN*I$l$ތ8WwІԾ鄲{i~vU4|9|?E--f8q槥m57z,eCߟ9n*RZ1bvmZdZ)VI$Oa/e% expn[ܼ`b/B\CL\Oۻ~qQA,z/;}:kp?S-.Ar~?p&aZ$_տDy$LPfb}Q{~ܡq~61]2jQQk4A pci 4DUVaݶ;X8F@'?LZ VE=Oq>373v;WVY^ xt! e&Px63ypE ScO5;V4֭dYO*&A&`mͶ?̣N _]E 0u~@՜3_-eMߤ2?eJDux{RR$^@.4Gny{|$pL5¼l{E% 1 p>i)NU$IEH4,/Jrb3 fūzśR *-7Էs:3|+{!sZW Ss[EvK(.ʞ f:<^/;_?: ZV'#N=7`KŽ~>T "t}V|JU < yK>_0AHUy/n\H*Wg d?zʚi 376 7*R/t'5G[~J8^`SȨ>PnoxNWz1bCNj%+Bh)6N$)q_A1=2ufQ܋|Ydk+` /)Ekrr0΂<%gӅ=3m"JoHS~)a?xvyLe ;3Y#Fp~7up_,Y:ږ &E# BUѝux{6C(4:"gKڙUt/*viK.Θ0$\qI?$ƲϨ?^"~˷X=0#G~}~U7@:n8a3eg ;Qe @n_Ou'+"zDAŹ}H[JPDt{ >8.;V8Koh/;cͅ;k<'cJ_.bPq1H*xxdɟLrVPXR UQOض<$ihCLF \ւP"v gQY@SRPe#P $~Z"?WJ2GJMFL_>h|" F4C qhXSظXUd!곾@7?Q՜m:3Ǧӎ?|3fS;㨱KT>YӶD?93qOn7QOͳ:Fi 4^vG᫰!yٺ o—{!/JT =TcvW(Mc/Ikvo&i'xi U#w0*$[\ȔǛdXҵ#x%],-(Ş`]IQ࠺bV ?\n^,]bPu+sm,þVÉ@qB5R*yDuL^6g#ɷS+'祶E1ȭ')C5YXy)ԘW+~P) vB+* fh'Y! *ywҽfL!$U)g18`xt?Q-uց.ӮqRV0y v?M2Կ1hEN;gV7=~YOg<rv$ y|B/\ r ʼ1ΰ4{mVoL/ K9yxs!ZRA/t#b˫ ~)% ~)sRqf@R @A, u'R%ޱVϷBn.8)r2"1_`!HLPz čvdOO_Q]ԓK?͊J!t#حsҍQ' ߓ_fM Ԣ(Z0(Bo\EUrdԛW9D$l1@DByFBpt_Y1G<ĉȼVW/$7Vw˅R'P˚3Rd<20~ TV׹riI# d><Itp%Bc0"%pל}VɋhHw/mEpr`FKl~~}ܫacw?9)!zWːج]O5qW%? ^WGrw֗ݢsRHQg, 1ې xC; و3 9i#9esIia)g8pjI@73PN?(+cTNZx7=Nm @,yU˒ QkT;:DEܳG͟@|+x<-65`|GQ!"4|! r~LIzoR`]DL':8u-&Ýf`9ܨok.'s jiooԚ@'[q} Bwp[)[/~x r $Ub5p z *7~q~ތ(A~QG2 *hq(o"7fz/"ݣ{*9KD:O,+9bJ@f=wlQ`-I[ yZ1nZ[UwO2k})whFRgh|L#銇7S nvALS%/:8%SĄw/WVsṔ-5l^쌡խ|PsBJ0U2GgN qĂE5%H%6u ]NS ʻדe3>W׀=WP^PHSCC %sJ`s әM}`$ֵjE舧WɿNmH7Vӧѧ$`RH`jgUCsnJ3AfQg# څ A@|X0 ŔV|ԟgd:bs4SE!'ח M z1p봢l8s=m![{zy*oA~QmWzEtsxwsQRc+m :x y zyr 7|BRM:>z҇>ݜLB?Wv`|4Q ]֋,]Zv̈́:VB_]x&Ow=:_3+W D_!RϚeӴkG)U FQ3U+ۢ׻v]ɸ A 5z|M+SL Cr.6JZgFuS]6N>U?D\y.Wź֍~{:CD!-xMm))qƜ髑ݡ ۬ 5k3.UM#ƝgXkr~KT֓j=s%dϺK\Yei>h :[5o3`!K2AtՠbtM)mg Z)/Kz t%Um ! \v9K:Ts;ȣb(vMU$.ᣘPmV3Σy (TvLyU㡾^m TC[a]QB۳r _Oe6I_a:J/"Y>li $cωQ>u]#A_.(vN!f{C(᫜SSωUh&K&+f73kf(3 )ڿZsU)+TQ{VMMʋԦ-SfHXԃy|.[j.է[hIMl\Gj˲ўfp?f}O1W9ZMUݶ9)9 ٳdGZuuݣTWw8E* c *3V6.]_eG5*(OP6].gmp~E~v+\džS]Q˪/Vc1{Gv#~ϘΕ&RGƏD{cڂ> y_`vPhTŃz^\Af=P}d=#OЉtCuS%"HQ N_ e3cϤ [CΊoiݪ =*>Regԅ]fJmsW2 gTק0"<+^}TBae=k2>EU%ڷ+Bdg-ZJdj/|.2 WGmw- @Ngq,A;lhZp94˦LqWͥޢe6AЃHMq4uƲH4+΀25Iߗz_OTb 6,1fGT-M38?, 0(Gv9d?=D-te<]9QpѴlŠι2b2\ig tGg-u tgubht,3]Cq@1vk#Pdl*PI$DUm$N 1~zQrlhI R^|k:#| 5Z|Y~_l*?ky$7P$-aX88ʱl趹|)|hF$1=o\;~"kꙔes̝|t2 ;rXh4OntwTźU&o̬| fCRr;/}~4x1`>0Œn*$kiq7:gr755ZFUsnugM #_Zb:3Y'\#hLKN^ɺRkwg\Im7Ԗe1l Ƕ [28>_pl't\i# ;Zuߦݴq.I?Sp>QauͦQHe㾤_$/ZE`x<mo5ݣq9Ndzj5 k9ڵqqA֭O̳u COToJ0E:.lY|vp#xZ${ju#;萣A.l!niÅOd^ns[2u#Ɗ^, O>+3uY{?smt3@2*Jֶ`Ziaxj@|.SN~,N5+˛jm(#*Vb̒d|իƼeF 5}iILA翕!ݵ5wVJ/VmV:cRⱐ~Q؊"AǺTEo-G jN<>H=9!K݁SwMfo-+6C哫暳{S)㛏\;DgFQegM+LJw2nҋ9r8J&ǜm)̎QؼM)c=eaQOG)/biyBX؆^XN1a{ fU5n`VZ3H_hGp" dB{H/db-|3U.Uǜ|?:J۱h]Z] "/w6'7KbHK׍hʀ=,\{Ө)Th bZ(cL쩁Y,aQҒu!?RRkʫ_9[cN5ttȓʁLtv9N>_c| E01*ũl漫3n_]#m:VZ&Kjm<,g* ';7p.f4nzLB;LGru@#a/XU0 tM.VyNwѿ) `VW>7TI77y`SC+0T (kPT^`h Vywu 0RUdȿK7 Mﮞ NK-V6eՀ>!bQTm~lBs܉[翻nU -UBy^eŨjf#zzMRUpTPᙘƓY,笿$E{,RI8JJ(&[5167%B1ǢCJ$0$ seJ2podtT<-ʹ9|` `lTΌ>;鼁DaښeWCC]9S!8,Jd=:~;kM@,0jRlj._)kr*BoV 〔QU1=P6|;m`Q< F,5еlG6O^ ɴAiCaw+p&+Gp|EAuOt=q/r%2pdx,sh-jBS ofTl/K _4tp 4Dػxy'grdw${jn_bW6!1>L;z_yDNP pY޲̠Ri {:F~IH9Y\椭l2c 5ejtC:;dTwmBOTZL]$*{Ĵ stv  x0c))GV4ELSFG( VFXט?l"W{qgF :,d[r,h"0ifpűȝe)"&4IP$h?o)~YrUE!:~x2Ի XPb.2tͰ kDNAsΥil=\6k 0,j|.A8N*u#14D@y_D2aad$G^ٍ̋LۘGЊRo"keGLj@U'*R0룍'!K F51l\6LBұ\{ @kȒGq4R6 0Kqh0&}(9i)[0c fPhd|i7ӳ㙰2R9t==,G"v_$l\^4Eu@ @$bjR\&DǾB֡)k5Įa>/ᜑWH-,Vk'7Zݥr{$ c~kb-bԒ+A+TNW9 R#zK #y7F'HT{"B˶QJaqշXML34]8 ,L @E Bio 6oF34X0aэɄpn9wP|;"젿-KroߺhflnoOբ7&R)r`nTDXޥ`I3+LL<M)R(W3*-̣'Ѥ캿qbdܽaof|5{= A<{Hȏ)z}o(7֊b`kVb7G?EJI!~fb#bBfKKm-ym (դq7XM.a}#hBZR 77:+֛k:vm0KRӼ)lڛxC3zlB߸OB ]d Ѿx/8[?D_qtui?D+$y/1šfP\BNE/1,LxN=G_ vwL(?憾#.J'+:_Gn!}7m 2yE#߷>-RYAuEIvB@>dj F /G~]Y9bm,2qJf=L\Zٍ*7I>g1(% 6;6"mv0Gg&zс!dc8{b @4F1MGv.f{Ft2hh*EMaQE#őCm˜ჷ+iCR8A.ڶga zdFn:򞅔rv $3}-8 Vu#oiU4o V{1W6\{QsWmPkDier4߮AǗD߷#$1-2ӻr鰘1\G0ԇ%'%uź V,fk7ӝ Fb Vfo;Z!t%}]5c!\UGSRC3 ElKT([vlB uk$lB`9bF&?g:.h ƟgR4a:m't ie,$~.-& ?GX0w 朷`CRI8\& |CF2cifaB>}'MxvjՅ*5IJXr2>I~lyB}"p#tϹ(y6}S*#DCqXaي%C68 hWE~h3˚2/sO\Í />{^bji0_aDE oRk6{B]{,V|`-TұۙGP%S # vF^(RO6#PHZ9S[2b#i )0k61[ @^OAYaLT& S(SOnx&ԊӤu}tMOؖ<)ռ4.?C %gΘ,FbywxבCͶj*shl)Sr#L`uHWlWEh&^(8O±}x[> ~̊QKJ)uԺM B/`R1CIw_x80rk0c"a-0wG&>yua~`qr>?ئ9(3HB0eHEwJc _I{؋k|:uqy"#.a4mh1bSk<"t,J|K󱼈-M:ZJsrg״=mVS:JHp*jc(;G96y`[f܋ g!2l<-Gfhr$nf)~[SsuU[KO*+*BI1-):UDӢ'ÑKϨiƥ/&&gGwC8iG7v#z/rUs.7#ci VOvqB M% \4nQR7"&6gN}$q0ȥi)stج*j 2i싗l̓RʉR 9: 39_Ug4dk\ 89:8".uΝ[u-^͟Bhǘ!7t=l}o7aCgd[WpRЋ"XF}J|=i  ޮXE~Iyj4T2b6$uQbMשy?{QPg+oǹmΥ#ؑιFTm,t6K~1!7(Y[Fd;OA;;uv6d7p0X;,ŷ Uvq [J`W0=83ьvδ.p6%*luMxBxFb)ݑ& %DI@c͗}Nփ2箷uee +j8?=Lm3yTʰ޷,T}#08a޷QqXs>hI9|*A{u,{9zfN їM4柎iNA.7w⸵TpVogP 9~i=Uq$# [__:K[Y"7~8:+^Ry-ڸ;ft9[(CHܯ7c!_6 m4cܷ%߯O$ૡc-e]u:Q z'S ;VP<fb(1yW*Q1kwkҸT _ں5Kd:FIgvظ }Z`w4 Gt3065`!=G0+(0ׂVFnyz%?!|չ΃;e!Hj't74أڭkF<~ f/ꮽi HQ˙D Xwq}̊+_ XT?~[Hhp;~(g1ltG <},}v^C}0`KIRCz{]W Ϳ+R_6itZr%xgtDhdظp{N zWû$-@_udA{ n8fhxWʆg]hV8THv9z)x+@ʋDTl"M [s}: @aF&#-d:“v.A@I^h&)+s?tqA&]9rEf@]ÐYUVPwor*lPG#c\r}lCXZQ!1n1j-8V+l@ n~., W%Ѐ+oM0]wJ/gAmoH"{>D5Nk4B1v1,C}̛9' cD3` )>ΠU4֦"vkKXUA+N`[mn KkCB Or XJ,U gE$W5:FS8V xv*OY?z6DvlCGŕ.7P㜿=i(!> yC*Cg@u:ʐ}=-n婈83-VҧPҠ͝ nbm?:PpquΙ8G-z恑4ʬö܈P 8&_"m1l'BbOV(m O'qV)Y@~xQt6! &J&UHrDwn4YtbxKɊhO)-<Խk*oY91f ˪6'Y?ӑ"H`k;in^`*^L&,r7B >-Á༝oiXOs_+gXEoiڜ<P!I*NY.͘pbhhDkR`7jS !5>YcttfycTtΦH+>|xS9 "8+q4'+jXϐEw]EMoO&ZŽjz;|-وH2TGZEi+h>%G1 oB~sknNsS/SX+و<C#l_}Y"5?ƨ,f<3vy1{~IJvnBa[@M ,;pAЦKD ,MyOAF fv!Lٚah9m.q?gԺUDZ&4&)i&}1׎kQl$X!8b6jJjMR i7b`qԕ8` \eY^MH_V\_\6"*ePӫJ3lk >l~n*!JYjPC_cQ콵6lmn4=C>gt1"Y|6wOz%]N%K;BW&cdO9NSn{fJt}y. OpR%쮔K .0FRU?2;Q ln0в0~J"a~}+cfgba?Qϩ+s2pb9kX[Z :'Y.? ax0JPx@)3OuB~;p{@: D FV7BgRǪUCLT=$T 2fݼZe: E pnIy׿_ӉQ,;!7:Eh yhWЛ E=η'> a.ilD#U םdj: 3IH=<ɂ@Qb9 HcZZGA2\)'G~Ε'5~ù+rB+ިF!_-O&$͓4e9#8ZмeRZ4<,g`Vf4_{1QuDh>|6a#uYZق/_`  Qe(Na:ypNAyAڛhcc7!+it* s) cX_$I Xf !뎱+:hE@+sordLBDߍ,@+0ԋf-X9fΡ#b;ۄl{& X*i[ n,̀::1䟎,m0Kk)險-LqEf]so$ @5ʞW%`M~89"ϭH^K,g76@,@ HL_[c$9\I;S tϢ9sL8?>8cɣ+n,".!"(Aǥxhg$P5pkRʃ@n2{_`+](t˺#@}J M[(și +)6F#=+yXjJAY'j%AƭCa~C?Ib.K4D6HRG~|ÃP}%S_2_"G׮\fc"λsKȕ`#u[!qTrhu/r._CGMz,<1sJUXo[5]o[WU)Oΐ$GOM(NNș6MZ]7sqL)R:GTQwQEAoQa"c"C/aMKR R(c^liO~>wJbڌPu!Y(0jMMxEN̪K,\bͪ&aRe-1^xJz)vE[ $zZ[ry?9ӷ; *-896TBAFϢySjԉ K'Ek)φ~4%Ln>r<Gp#&21F,I[R o 7bƴ6ϱe^Wt>6uh` 5_$(M3zOөj7ҧ טKP%^X,6~Or }-sFh^[+i }-RfFc14q򶮪6z:UJ'O38kSiТt^a,InRE 2*zR% Lv ڊCPZqb1mhmcZ w g ug BZSӵ re,7(-N(aU.LlbYD\ 8L)n|iݾX#% S:ކCSAHU_p2̍ jɚ&EĚʊ`*HT=],3$Xf+Q|e1qGi=K#7cm^C 6,\K=)2L.oTȨ^4 uM~Ϫ%8{UxUƭ~}1J$ ypu ;lfMIS;j8:aZw,HR\Rˎ*.2'i23e`0UĨr+ c?r%Yѷp>Uj.,be#ѳ+cFr.IfXZznVlQt~/VjMGq6K Ff꿋&G,=^s䳾{*Uhk?j>(y?UMf%d]+Ɵ\O'7?q_)GY$KM{N (x-Ƽm6dn8^vbG ͛&k0ԛ)B`讉sco&ki9 0$/kPX}xW6& .iA幘.gATuڊ,?h~\*P"qEQ"R^u!-EM]&6{w[? +m}jdH|SdL$lcH.I.Y*)P/(D1zhғ97<7I"}MӦK͠9 ?ӟȍ"ĸ@eQzP:1S}Pm'RPQ u8 o6 <ް[Mq\rZڬ+فW%+C)M i-SS0go3k=0&k\wop|I! ?"BIB7Ʃ~'HjFZ#` +å5ËIT]*#2&6DFYz,)U #DğӶMޒs݁W6.ht#l\hvhߊCiNB 7iВF3Qڨmh@L>(ߜZD{B!_X E,(B4+M[>"7ѳ'qZ;iS< i(p`ޗBͰaʡa:.;fTqgPŌ[%ug&a?#Q^5pY6l\&ŏ}^_Hivi'"jzo:jyAa|95ES8L<|v]5p)2&}+s)(ga ;Nr#R OM▙THf,m<$ `qDǘ`V7C HcHgmVm킩s'QTZ '+382U-X.e@M$A7BX nٖGcX)&c?=m`TcG  +{?|d3ɝ r.'_zk$skۍU~93Y}$2q2<[.@rX+!~>wHWVKC.Gq4X$*EN|庂J2B,~ҤP4,(Qzseu_FbG0X D`4ދ pP5LvDk$7@`?“\1j b,[ֳOԦC@L %1'̕%`A?O'D>5҇tFK#>DOQM T5ǶzՕ"T&#fI8AeE#ŲϢcP v]-ckKuHH'km&GWDU;ϐ&nH,JBBD:#j0ZVM %\&,*AXUI3ԦNc,)R{ {ƮyB Jx Vj),~$MPhut65Nt}4' ]&eψRX/i0m0qZ\ٳ> pe Mo>*D[.P` n)Gwq*1 Tn;"㼆?̭Zƃ|cZ#, 狣07wZ6SRLobv aѺ|ޔw4 VPňq ,~ {1#G{k?3ڳiPc$A$'.1So_8:kPmsZp24 d8otBߗn06;`6gb-RT"򕧍[Vr fl wжڽSE+6$qy3-~hncp.a¹W&V8RNr*4=5 ~g@i`c }aO SV~:r:J8͍ ?#oxER) {0 =o5yakvM] j3Ǐ_&q,T{ !,I~d"{^z$}jY 3N&M2zd\wӓ[vAqoX٤AJ\*®倫+U_9QWT,eJuN>1'L6DP T9y;hO + b1x6UUeQ}WNSggf]X ]-v9a-ʬy? UXsũ)|%Tp5M\\ cN8{z ! \UE9^cX,LxnZƊWBmE@gHwUaTL5Lhm|9\fA@2qT³*WH |Z¡mz3x81g6Wd6o %<;vmDKh\Υ}^NLޣV\u z ?CH wkűP\3os?hA?=D}UƿF$DxW 閝4PfU"Q(?Ļ9ćv]!w,-0(PG\ ?¤r+)FA%o'5S %l*##?[u$Drf.[A>w#sRC?}3s>Qq 3OiYEQ|nryFKdW :n<OK d,|/ ɕ-blMVgl@g@joII6JPl ;K6L/ͫP%c(Gz,:.2%/uT *^j8MLGJyG3"Ⱥ:ǢF@G0y',,AgG쁯, yr]ԷWP٭~hcXt- vDz!! [v˱CЌNa@Db; hBV"~x͋s ͹\u2@ZqOhX՟":u>!ᴒ8" E)Hԏ@LؘoŋF^|{|ӮsS!jn;@\(Р[x"=]x.u:E{w4JgCYl |Iy85t^< dCWd_qI}z@AxJ΢JیYȡ\|ԑ%=l JʔRlw .>,M^h7*ŧ-%*u@=^ #ר缣 EYO$Ss 뼢ʂ3/?1U{2s FxUҙTf4@uDԀCP#~Nd˰m=|;rN+ޭxTd+ Uj"$vx?zMSEnGְm,FY<g=J%3P*! ԩT@d(%QED~9atxfCl, m/*!HQ}r7ܝTVdn {#hqgX{Vr<ݣăe3g4ew 5*h]тW:ݢ U 3{nܪ{(G*ޢً>Y7xB1軗ҨTI/cj)R`Cr+HLh|9(k!þEp_M@f!w* !Sy߯UߞwQ+Pսq޺~`$)͜5,~YJ4C>;uQn_O} cv*8O, aYw`=d LvYIEd`/"ͮg}b0lg8^ק a4z2es<{j~Yop~Q+sGF?=\~ 6bص6:˜ԝ",%Nc`\?XO6[WȞl QE#xVg$,(0#H4G>1od39Qa\{OiXZ< +v)+ օ}إ{`/7d4nґ~s{Ȅf}0e\>:gSbdzL~wk8g:v= 4gs ?.w bȳ7ʟR75E%  P(8O2Ob4H|㡰7?xuCY@gjn4X HwL sRwX.[r߮XZ:u=_(D5+SuNa%EbdQHG gh70ypꒂ N;W1]TLA%Uz 2JŸpRRu3čm> /݄KTf ה׋Gtg/4'<+TWۼwyQN?LuW+Cވ\B,Y#ؗvADs4\i ρO5D^O}':^ VBwͯMO:)D5qqORL5qOwwB#FDzO3nǣQOיɗ[׿q1^/F/umwtD!gQ'?ҭG;ލ<.6 =HL<_v_.@rtfNUݻffLxm>E;m٧'/dZױqV'Q'RQF) > m[yqT_#ɐ˒,K $uci~_rSa6rW[Ѳn'[l5V C|>"DZCFl@0cOn^rUIxZd++2b/|xڜ Z{Ur&SRr\] L?:v;:7&b2\s<R 7ܧօ|]lZEQEJ:n8}"Į=x xht=["d6m|wqaЧu o]V{l2^GJ3<¶/}+c' 4L'|.7k<lj]b+9}N:YׇuYpt"Kr]{\36~ofsTP亓b陋+NY^~#L@, I7M@HC+PcTo`Ё9kxo͖y/ pC^?Vpd?.}@z7Ǔw6cn\cpP' k?sSMJJ x,{%B&:AgM,B8esTXH7Pt-_,1IT!9}ѕ'{$ ,:v#? dXAD Gke;$qgRf`$ҡ:i hj>$r ܲy}ί;Bw֡_mP4Ih)&f%v{?Áѱ~fp bŦ`Q bλ3dž|rZp2:4'< Rԟ䙗ƈeG_\NHGnsn/]PqW4$-j"sZߖXpQ003앸xvB9!<]?BG ~۽I ftx ƮV߹S}bhoB֩tGm럕T i{eҦ C0'zu+љiWYEUNxtՌfA6 h>RaѽgbO i7<夢 x4g+dWB'. /Pgg=?I;y mQR+ɶj93Oŀ N}.\8GJzm^pWܲ[S'xμ2.v'v[{j+"7'vN^mq/1> ˬ3#HMI*Jyɤxʦw^q>:Ӊ|$ Kr 7j\Q>D\*1Ÿ/;$b^I= -¾{8xc\#o ȗˢTM+4v04k%UӁgЩM\ωDf.9D~g0=XN:~ٞ;@i^Qڳqx 7Qb(Cq?kTAh+7`d[XFX-]ɹ,z;~ 0p;k,RFIer0()Zxυ9ndTWb:[9=_7x drWZGez6l_}X<3l?#}Q 'B-|]gL*GcmD;<4LП Pjn(k]x" 6!WX?/g?읝%|EXJVHxgY%S2*]=9(y'6aG$.soMll#] ֌Ew9n[C}ۀG{Nr.X #)7XsT"EXRʏ{+"OmkSHi.9>zIRZϋ~8ءﭻBPVZj y]??LD0%jš}[%ʰ$) HM8*[hvAHR 7wXiohڽ'!?;HMSkmmF~Є$t[܈457;w|i[dr`ë>WL ݿ>C#VcwPF*ڹ>Mg%pyGsp *e=*@ecB`*ɌScv=6e A}޶eL"kTı3es)>3!UoD Npwwwwwww ! =@Bp =n{:uΩ_t +GvO D3{o;eΗaV H5p0lhz+wDižVϭ d2,R'+)'i5#@%:3=Lg;B9VI`9d͌nxO(sH@!|p.2м9@sPMXNPShk;f:pnBz%:ϯ`B'Xl eϧ6:Q5r#@q \B\`bà̄,4b0Χ;/ $`00/qjMbբٗ;C`-xaɨR? k] #)**5 DI>`( |CF3 X;j QMnz mBPCa)glΐ^S@NhM!sWĔa`jna $fi_ג5Nj @s̵ hPwAW8UvVtzmJ*ZZb9lkzkgzN{]y+?ab&FBa~mH#>ئdg!Q7o d֫v u`- Soxa ީ7'?bi L) ]4,%6%[<$ %)? Ex]ݻ Ҝ `_Uh. ?: 48=)һ`Ok:.>0;S>cna **#ӝd{j^TIDceWW_bo6"k $J yAa氲^ }Hr'6mȧ&aa%:,;̭*!2p{*ZlE'/9"t=  jB؛f.~H P >1D`xH[/[<(+AC1>?'.T"I"难"Y] *`1 10:R2KmX(vƒ (]~RT5tS܁Ur 㭈B{[Z>4ٗ +KgOXJ1Ւ-W3{1];M#ٹMNY/^>q}G)#F{O(n}楘!tC)tpNBPIԖ˝h`<%7$D YxvuDVT0{/3ŨO+s˯G+BgJDc4 1"9|m ]6JZљ-n(kѯ"Ti{~@plKyH^E>\(8A(BՌ1ORljPJ@2ECK 6`\KLr%ZcoƾJ ~o/ڮw8$@댺O{3(镀l;L?12VH&`D2O WF%a5֕CϳJ+TZg-;w05Alvh͈K9<@]=H E$N 'ڡ+0fOĠٗcj%YلΟY PLc֗n;gʫтA.6_'Y'3䨼.`0CQۑS)f 3NAt3gwu]YIiǬ˰*fwG $JՇ![9mnTe{@=H,G]Z0yKT['EͪMx"Puk#M+T4vaD+G8\&K|4f oQ }>xO'"&'K蟥Q9l:CK=܋OeFU~ƏG!$dM⯀m!Zt=ȵyT`RD-QZb*͏q\'u].шn* rŗ Iߑ.ni 9NHԖ&!| &935(S΢nd =,è 4CީRޯ~ xYw! xrM]uP78,롾l:׼[5ޯ{GS =v.? h A=q&!L'!ߑHUa8Bמ*6{"~mWb;9KȞVag݀z_P1ϧRCj^0[./P`{v؟cRtS뒹kiƃ=gFxb&Dec#8݇?t9"^[E:㯨_+\y[䪬CKY#DO>V2B{;z}BOP&/^[C2LW\!K9qJ(kh/O"z.b_STbdz։=޳c;RD@PŇQhlSzcucή0YA DJܓYAsg~)e9&ogmX0qLvr󡯓RHLNm )o5 &U's0)SrTGJebb,LyFe7 #$Hx#|V6 ۟zLN| )V2M:|>Mtab38Y_3nGXCO}RKj`~%=Fh'QƮ.Kս?]}h6s;G-\{dJ`u&$oNh&zjc #U٣TxͲSjBl`%*T0_uCrlt <Q(״7PS:֘TOa\үPlЋxƑDҡL7}0ZHw“3glћkHq}ć%~5p֍Pw8AjMiuwRįh2XxS>V]PE)]g%ɂR粩Z ^tuujM 0Q[Gi;Zuqyлŋ)ז~Mv5鸒geT2a˺ߝh^S.Wd }%`NvAc|”m.fOYabetb*\h)*1 m8*67H.k槟XB+C'Fv,IRr" |CK^x2.ß2ɷ pWʅ]*zCΛ+ݜ ԓu+hs*2XPԲ|}돴W:=)鏸&(Uū)hKA3x̌7FH%߽DE3x%3Rz%rVk2r_2ZDdc|ˠS->xz fuZLfW!~ݢ= =ITW1X*SMA>ʤ d& !zH#*el|5TGH51^2Uԯۚ6?q{ds|.C-wocVp"lN_p[4 jC9pu:lU{6PhbBzl*VZd.h(@'K0tOBm0 zӦG-ֈL%`bboѨHubh.*=Zkdؿ: مq&&nA}q"zrtB#6 kc8o/wzR8/Rº,!F~ȿNkxBMԵc¦âמu_%11V;? s3w!;K-::id W٠ J SX][E%ͭ-* pl@ #'-0ٜ#:(Ur) PArly^v"J\ U(`ݪփmDBMw}e=j?ћhQž)ۛVQnade\GI q5Nbw2#]H'+ba{94FDOͩtJ,cI'l7 F JүfN?m>i,|)rJ7Sls4ZMh=>ўOafUT'8dR)ϳvV{ge $"=}޵aqkړsF F,o]I熌9K1]eZ#] -LN<un##Љ{d' ^ Rtܢdڦ4q`d3jyS*?<`3{ NUHZ22 w}XE*er$8cuUd ep+&t朢9f\iID*\™h} ͚[}ld͚VFTMћ|Y+=9_95' r2`Q]xǧCꛈE}UyTaP5ɂR` \PPNCD@& 1#?/4.뀁5bD-43p\&X5Tv7Dj ex0$nc5.s7ge>16ޖj(Iz5>㚦|8oBxujB^ {$_qTf>R R[@,eP2XmapBW6ݍ`,)Zr$ 2VZM!eaae^-UcPL#ЗNkw50SM|M1jz,R=jl5;}0$ 5$##UJ-GA,M.TӯאYi;z:t ! g:B\q'%\!ab~R0`F;TSPkO k엋ufGvԇ3SCO:e{ktEI#2̹(p6ډA.7V&kfP ^PN2)6v@alOx4O۫*ZjW.tnn+m4t+{j$'!m:WvtWj;1)m }p9<=Y vƜ-0X .0uN|͐5[Z<~ . ?xd3pfEG2r2Vgʧ{>q]M{ytQb?9) @EV &* N3U6rew]~Ud:Дx'ROr5\r^=d2"=g <\@7pF˅PvrξLfyh= fz :%qFD&SHzܲ5rmE0a^f_C*TFmWk7̞EmzZq ]^o.Ҝ*׆q׳lNF=kچJЬ<സ!x6$|]ŖXuXzQA^O"P=\0`5C<,֢e}r-6zu1d]N_5XnhMΚeϩW!Փa"?STBŘ\! B#ߠsJ&x_U:Do`'a؝Bf{\'vIM\yߺR<-!r'ٗ( 5Wc8`[84!b=&\1[+?\Bf ]ISTԞMnLC7]}ʄ?]n=&z}(TXs6^AyFîRҺ[}ٴOCJ+֧c ?eޣ|cԢOį +㟗QB.lx݉Y>eUϫbCQ%Wߣ @w?2)>5/bWbI@K04ߠOOybˍW3.ˍM@r'<+Lo6K9hnuH%oś* `+hX[SmK-[ 8_UgnsL,;-kb؈fv iY"z C~Bo̬jJIcQK,p_DRKEG3/G#M#8sR\}}^{wj~!vin1,Q*A2ĈEU!ǶY]jEnG Th~5^ng673HX(Bk-` ǢXOv.1fB+1"K,2bp{DNB7oy/e\+LH ?C{\x쌕aW[X¡ed3BH?d'< F U uFz5raC \ZcNWCd6;Fbg.s+́[0HZk5gD6佯'Us_yZs1(Lhjjr}QcWCq)S lX_.-e*l[^SMŲ~"}KkX,/-Pn䧅El4 JNijڑG7i')h9Eݱs(ѱhl]hnr4 TpJd~˴Xĉu%dp=LJD(9u|5Z@a%lߦܖE+d;(_׿1oL' }\P^~[BF>Lwߢjimz[U7N\qRҁ{|KUxOoa; xikb澁0mPcQ wPi˥:rp#bJJ@@Mnt}trZZAV#!6` [~wd#?.x6,l2zjH+T-[n*z}kg|xv0 2 5Ύ8;mO_SGaʸ?;_/Ԯ*i3ϊ  W<|x 2\spK~^Q 5 V#ѡOKa&PA'˯PqJsE-M2X}{-QZw`nE O/nU(z!̉f6e'7Ns.ZoGkӃ^F`cA4s{\ :*j"PZidpp?o;3V;^&U%1-pfllOU5Z'q'ErKr7Pe-"zG +WZ*FPN~d~(Hzވs*;e%Ig\yBOqs͜mMQ({g؀Gzۿ^ۋ{{9#`:62je6Gg6Z7K'' qi%7hIǁr*"-M׾ڠcֹ;&/v:op]h'"lڨ ??\&Zj>;u}a`-&:#(d%jsgM.'hq ISܽ,\h1] tԻ/-8$uwfL_Lt}˙Eu !&̑&nNםg9e>;x{E*e$lۉLP*DER#g ׵SG]qU1%K}!.oN@{Qrak}Oڏµ?^FhfyʩFŪ($uI\Zm}D Ⱥv {}NzRI^l;VnT$eQFL-w~-ۇ*44|m6 w)ٌKutSfz-߼!~Ys Blg;zU`Қh7CطOo;j?^ȣ^n{߮n.aSR໋l9ouIA_xDTʢ?ٌ}(ŗ` BO-K,F~( :,[IMsNfe_ԜsB8xO؝}~c{?SG M͌}Ԕ/Bp!2_[?+^cwѩTo)4 (%ʻ@ x{jKeQ׵> ԜK} Fg$^i<ȩ Uy||f~t܊g RL'VW^FqtrOZMmc b!hD@1 $&"5%%ۆ1bP( qEfs.pq;ReUSҀW-oAÉkQw͓-X-)cDސ0vVݢ3E(7"wxu湪x;RR0 N-#ϚgsZuޙx` /]͸bgpj vHC.sX0fru-9#U_d^rΪ:l| 1pc8!B)DjĦpS.UuI\T,Ұӈm;Q EJѡ;|b~n g0tC]0/fDѹܘߎayIXU,l-qB-^"7DlUdEOoXD9,8+{G3 x\R#c<dSٓc > cO")%aHP0n % >֞!p=rF( 8}Zd#}\+6R=ۧPCΗfP"hU8R$Xxl*F2 ؅ReMo 4![ImXN9/<=qhJ@srEߗ[rɪQ$OhcMoZٙv/*f&_Wf*.mDKDݭ/*epj&l%RLnD^:[+n~#!K2+[}1t^ʩNy)Y(>|>2$WR91 9oFgCfAarȜ5NȄi͉7eS1.@nqpx{@t3AƢ*] |uL-l[ D4 -4h5A=׾5_% @ȫ:~U7N&̀쑅̫E"R"|_ÌLlQ.s5¦&ߣ!:m+C F盤bDC{y~ ]RM2+xDe7C3wEk:o9yZ`B΄,%&JC_"* _B&u~B ['XfdZCa^ G\c!!In<|:Y>yï;-`K'|,Pq]<ȗ\~SzU4O}|UHENW˪1Xdr3mrmy줄j?PO0̋ iZ i_W /%l> ͯE/of(DLQ<+LcmM\xvP5u)GEYFFtFampdHs@7RuMpy]6},gI:@?͌HUV2  \Qn{:9p˺(.x{hl" ›T~T -k^}(!~r]7>3aqD/O)3Q/MoF8 jѕH[Gn˓/=B7BY݌t$P|^-18gzMV\\ٗzX)`gVD9Lm eUk"iLtU&3$5'0c\xG`Uo. ˴~]+g%vVyiaL7/,vdZۗ<#Q 0~OF?qHM/T02\!!Co@i,"E"[,~!o bpy0&GM_A0R ?Q͒Xz xyt]hs,\`Wj[UOEXɊFX[%yx6̠,ףKb*gEsU?c8zJ~(UjX)%J#T!Ǟz]ҤBnAZG<OTvko~JܘLVDyzBgNbʼV6{!v6lo偰VB|C#Fl ԰L:>dʚ-46'Q P>S7i< A.U$8Ho: n*S7|7E0 [ޡNFۏzڄvƠ/P-[~k^}@wYPgPա^4+' &ei#BJh r\ֲx ;EE!JbajhƆ#*.7zP^jЗ}B-? Cư63 KWyFɿ0CDwyw&2 =ȋca\ff'l}s?d];B*G38fd>DlxxPݖx9E1{= X¤a~A"DE& x4|=ӓV! WB9Ψ]b!i=@Ŀw4C?>Ug&P''ε$vJzvcVxnR!{t3jP(IcF`b&ׁ˜<Rx`~}E⤗hvI$׶נnLJ^*h(<$}/&5SP7m[[ 7h=n؞:?f*VX69քIN xzcE=~!c& =OJ΃]W[|VhIjuD:ɿ;_.LtU_l߻vޏ]~qUѐIn?K '4$m?}o;L 6X2XH?&=>y< p?]1YLPyq]A2++w9v~i𝿓,֩MIkm~_+0[YesӅvͨviBPLmD !osY{ fzcj|#bUa9bUhd1^>$)j3rM )r4X{%n3r݉ -Yr=[&^n`ąl^8uoZ rNdKKr !0eF{a]po&zڄ(p0Ʋ?Wۅos8<6`-QP]*CKѥ֯.Tӥgo*^lL ~rYlP?P!@@Oxu  =qL͐& Z[+}O.w},{ٸ/ݳ+#bE!)[!ܒNo@B7$rv?sB C'jݧޫ]Yeh5&C~*SX-ȐKG"hg˸ĢQO'FtzQwo,EQ[DK++W(෋~)&|d0r;r99m& +hh]<[kf_B4KGݍq’b^KM^y6??_xc3Z WlG IQ{K+}4cV" ?c9r$+=\rL<D)|N10Nxj~K}h)#"Wd.._?nO.+VY"h4{Qlyt0?=}s4ى}Uxs:Z>B'Tos3U݃bH&tRt +kӛbU ~вQbSLBRKmaT žwQV(ڎaZnp+9R%uyy\x{Y{=S}{7|X[Jklw7!}$vY*?m::C.F(f懌3%{Dsۋ5bIlջ]M? ͊,W&b+#ܹϴ.[OE}֞?}+oU}#u%;\ѱl:9h/n'! fom9;OO$3b;'!fSVY6ItmI,y#TYv?yqDZ~Q=[+l-SdB'Z37g[q tIe]},iL:+HE*RIPa7(F9L&$)nkt$\$;jr_N}dV1gJ;T$)==ѳek+='}?x">[2*dEqCJExOD%0S:189>|ơc)2}v=l [\%-{0TdJ+ lc_sߨ؋e8)J"RC]Oc#G6uRVO8޾1+Mw hIklILG$9 Y1Ib[bPk93_(&>:PRt "/AV ީcbr<])_|-UP|Na.Mdr#Ct/29> D8;^{Dw*O⎻>ۘ#j;4nn.ߨ“i7?q1h9g*Q':T6\3i\qbg P;{s$~H*K=29cl~ mݵ߆YNByfxhY}JV_%_ }-'AL)y h -:^t"bJTv-2k4޶愙w 9oOe:ZSBx!UI{nxǎ.GűK~s |w^yg9' y܇=BaǴ~}) 3>bRє7]̳@Sv:OВuf j7' T r̕8G;}ض\\FNq򬾨R[*oq×p6C'fY꿵I-[*F<|SkMjaS|f?M6?Z=<8$ @ cATi29 B ra5>i^';6} `eL%*9>@s韢?C^x;/7y8r,K l:f Ň0gYevݕref6Be ,V)PstɿA^p{jDiSIU1(Op ~J3q'fkJCkiyA~Xd)&*!) e t:{O>Lkoŗ􎬊RN%(m]kc<&n0̷CwIK)= &me&jRf&ko$-6YzEP.@ 3 {B iЏ֚w 0ÇO3bqqh_6g3~+k05ܡ7hHeQ&Ur9p)!P*jox8Á!$,_:йx VmQ#f" >g6ς`[?`=}^qVHc2~@ĻE5lX~25~bmo>ԁ(N3_Mvb_:9\GњBlN.ҹ&' t d3+$Sb1 b+^JOw6gX0N+LLV/ZZ*l_&:UuGر8:Yd<]M> \u.9c*E:[uu4ګn `\ap? clfksU^γSB$e&I-Z@E3dhDcEr8+kI5X Y0^> >E߲3a9b @bC=,R3>*g#ci sCߩjF޻/RgR67Ucsc5 j8:Q[&@|`-HvfNcY*Lr9{k"i-$ RQ\q^ҷQEnBEeGEơ "V# _sӑ%`|7O3N9l}g r*Y /dcGf˔WgA:8Pe@qD8)u jCH,˽M);A0G7teɈ^x0rps7ᙎ81_y3AgH5Bt3 ;X{,8%NLfJ5Jp phxy's3pWLP'MEAP%\IB7mxUA <Ahf}@Ϩ1h`se~FU Z.1)eiY_aB`ۙrdug$HQb3J7?>=ξS|:m;r`^dU&iqhԡ 8l=Ǔ!_6G3mc7;lܻ ?Nhr\%QTdmbYsw)e0}fW9)  {QRf^&Gݐ7#~'Nڏ= Ft!?l)i`:N. ^j gG!EZ>70ؚ1 Zd{&D'=Qgkhm#qTUّЪ u2ƘQ.c54S"΢mJˋlE͂|I%6N .~Ozu@NT5M qa~Ya 6Mӧ,@ƫEl( ְS,,4lq$+ oJmI(n3g[y]v.8(.B9NH$ʗZL>t͔JwG*tA>~:hŸ<(R0BSFMV^pl,py2پ)\lgǦzɤo/\y pL4Z78~iܯHm}&Xe1']ا:,۠nW|_ѥ/W#St4{3!ð%\aS ;'S5lmIAHEÇ ڍ`%N3X%it ۂTp59Ƒaެ^{uľBTbB!˻U6ևWU̮[5vB Ȟ"~6 ]*l~laFrJ+-Ftѭ_i!~"W&aTYl7D5/5B΄ 7x8Z<1bY7ZZ3w9JUU[8kHٶ1ij~Df%vYdBu7ٔD*:_'aEZHi[ʇWL 37 KwNcR-ޱBf۾ r~b1smaÙ BC#buW[%Eπ'h4~W>Z0SF;\ɓgo7WL$]Ͽ4D!8Vzҭ#CVAAH%'P3I2M}dM8x0= |aq49Tԯ5R]3OG.6|G ۟L |_Zr{{ſoPi #uSh;Ǥ] .~[òo~*M=¿c q[ wn0S]}nnf>Yl*h h nb̅>rKԜ]bw]]J}%*|̅ ʷaqꄔQnf5DxB?+h`@4t4 CUWiOө8?~'jtТӱ n89inpT̀-%h(oD{;X_~*<Ĵ9 ky8ޢQ({Y<X (ejﵖ)~9Yhrqg ' eoAeEx||@K],6 3z7XP_\>i]mRi|}:3p\GgGMvm1O61QW [:A3v.VB(~-r\Cq0byP !I"e=0PAqRgY[3I1-$\Bƣ|xjjT.P2BVW"Y4dcN  201|XLQꍵ^Q$~wy6(X4pm&MM4 H^ )UQi 'UEKF;'.-nѭbgicDžIl."ǡ8c%pa@QSŸx,k|t{,H{ՠFf ;Euˉ#ēʂ@P^0wp +*v 8~GړoțO-<-. d<'ODeԕxzujJeϔiXz\_OKCӰt#E@jfY1\jZG9T w2H"Z H0M"n9–0g.e †,mŹ2E{֡o߱̑(1@$rkҶ'MFuVPdjK[A.4ImOtbtOPlZrHvu8K2b]6(JC]ӥLxi]F>s,!0H-Ƣ2/'R. $da&wM"Ef< }X [KN!1V i? M9Zo|֛WO&Y'gq!Z$K?lhYyK` iOli D봺֤na.#ևp6 V3?2+fH\|"$he=bq'ݩ#|,[nu6鏽^N/\OV^؏NgkdCTo,8OI/9ZQ3|hㇽȫ?C >[%`/epLQC EשԒl-#F~/k 1f@-Hϧ ',X6 lcpzZL󎴑&Wc=pu?$-u=`>DBu6 vkJ~(y-#R>ʺ9B/6g4[Gc&%hNM1C  ;1SWn'7~sZۆNtz'쩜~Z)3Ց3 StL%I˗VCU՘ b9HN|aGQ?߾ &I1zCK6{bB>i3Z )-`\̂Ѧ| 5P3͙A4!~{ X€ULY9i^<ԤUu`u'qEVsk Hp'E%CFA zzҐn2N5 ^?c+JF_la'%,r`thZ`9W15ٝVRS8k68w-Ub>{Z01Uъ:Рmh@[^z3r+5 T&Gk.~.BXr&xd23@@ktRo@(Va P[T+VUH-g! މߞ[[-m!&vhcB[w;!6`ŒļYHyNTD`2OGufKz]Hi!e?kJRʩ.y㾯Bɐ ZG &}x[֢)l5J)zZ2HX#s/f${'ᐱ&ݩ!U]jj0ܟ0@?2)$8x6:; 0~i$M&#;?]1ޏly@c~X -CT-A{5d4׋`2u'#3.G4Wr{ڽPW6;+JN& jkZDWWJB+@U!p@5 froM)zgw.T" l: =a:zu>4ߧ=3E%@G-n YQ` ^)g2HۮۿI?$hie~IIZ[̔['KősB+b_MgO4\v?Kf7mN2gV%@ΗX/ h94b%hd1UgfrgeG9gBGzl;wq<xId,??hPhmGpo9QIO%xpB%Z"u#^wpt3j['cR>> 5>2q]Ow./x4FW3(ubN;h4-@U§ 6MfuArg-%M:_5# 2o{kLSʐ-<y}˩#S__ʰ=NG Ӆ&:>nl˒` xlv-2PglhNoIֆ5$X.NRJ9IIrB~!k'1+iQ={ Q#6Wnfkj}'3˭#'/_͋o7\`g0)n{D9ŃQK6sk9Jr$Ȱ"[9 v B3vX*5ȣQE}K \SF4lwܸO&@- ~?堶ZqK[ja_3&M#Yc:##ÑYVZT9zk_i7PR2G+?Xг'i^R˰R֦֖?d+в^loءf7wJ(2-Ck.w@Lmf7ƷB9.+yv`0qgbv2-Oz̺"z/wF_CU0XY|-T|ڬ}bL*sU_sFMMbhw;-EIE;?G^*b {cן[i^D _-a-DGb.& qY(TF Qqya5vضaQނA4a,_O-EOO祬y?ٿ͵*x;>z _@n((& % hQrVMQ+e[ZMѪ@!,(e8:DHKמy=1*Y4?-H,gE[mWlNV|x1\ >vc+^DAW A)ٰsqip2!w7PX9Z5e_ iq l䈴rJ pQkpc5oxXoFw 1@eֳTVgIߩ:YI0Sy=~m|ȵSIiɝ̕0R'B 1jqܩ^zl"ŸV'˫S1[dru233@uK[2f5,ʑRb A_Ks< ~r2\8#dH{2(n2HD+`p}۔MYgOp*ǒVh5~wί~LciܠIΫ\\p{^;.*yߺ}P?Ӱ?itag-n6x ̆6*է'!pļٹ\:MzNu ͍*)wk^,_44>DUWWa1cD#;Ư8ZMGC6p?'ߩ] F̴f9Ԩ27.1¾' X>^G^K쐨Tk5YBMDħg]&okp$|1lL]F:<]% ti p3FW ɠږ WfS+o6׶!zf.ߊwļJ=P}گK{BTFCn -Kj0\ I)i<A}.矢n)" zXLq 1D4:zz֤]דFJ26ZB\CpT6Q8 PZ |-*=Ug %GN)u5cIs5(1s5&Uyw R,Oɂo+TpuV'j PU-+3O fNmGŸ!+bm\&#<۹ӏԳ3Vb00}6(#RJ|Pv K'LK((ʼ 2eTBRE,oK\dk#cC5SDBT5d_ cG@NLOŰ(w%1?s1n/nt2Ch,+ʢנnΊ.߯? 1N!Z T6 Z8v )3WrqdJ%Q/o,%moK8|% KBfeeGPrUw6PbzjLY,9XopK g)(ɊM'k_wxmPhHFb~F}ɓ NI5Zfʺ\yJin)`5] וEQlYT9axb`9#"2[w N0NhpR!ېWМv?3C4hlϸX&YBP_%N* S ^<c](_u)\8{!O(ž?:~Hk [[=<\zsRiڝ:b ܞ(X%@1X+_^<78]ɦ}rf/ZrUK't⊽g|) kЍDSj [N-sj5Wh@N }Y|oޞeNcͻA F+LcwV^? d`&aYlD7?D󤧐ʉA<$ d_G IHi`m\.Տ$ hi)ǧ^y "."_ MA.p~~wWX0DlDx}oc8@FLR j-is"n`$h/^!SzZ# ޡL8p[.:eܳwt(BαDBs0I+s~% 440" NL&2%8Z*=B¢OSմF"6I_2{sƷzLw >2}˅Ql#yg;XxG$+E%Ch8[`{`'Op\ײQr`pAg2xǗd3B`˻tMuz&cV5ͯnkrf2ktyh *OSO1M/baѼyg(E;!;SJ Y6][;a4K z?TL}]~Xk AU Q'Pw$^ _e/~p)x܆uӝ¬%p0(7Lc])ڻ !yLYt{QXoȎmK.q=Qd?EfUz넄oExN8貌3 䪽));Up?IUl?" ya#y}PKH>IR6z?¸_ FE/͑G _+wzr;yǔ?P:44r>% =LW1oℾW0K´@z2@Zx7$&=(98SR?YɫC`1;vnm%Kormn+?"jSBzV$oC]>#휢XV VN9}~<=h4v7Y>Ziwup/32uR>o˴?,D/hI9x*#/ja]399*"`JJ(C%i.i|&%:,4 ME=yPTDveWb9vQ1여SIpmnEJϘ48^o%ÅR$ǩ~JJ!RfQGOĤVs1(}RKV42ry{QW}xRޖr Ձݸ&{/4t|]|[E<<4S{ԇĚ i LfR9c”'QנЋf5Fn7i'%5ZV˟oVWF5Uu҉!N{̐&\ܚMu(<OV(u,6_QDtȋrZ-ʙp1p=7eY*pŴFg5|i77i4%~%{Z>QF/xo0ڧ5x cp<)}ǸxFʡJiGI\eR=3td?zY.kDlnTT9)rWkr!hgA0P_Q{r!=Gx MpopF68a+Et0iN_bɦ`)9FTR,*k* _1%^D߿ t增!9)!Ytq7 %]! "R ' H+]Jww~wafVXͭJuU%O ̹`^0~񂅠ס'E{2͙^Pªv(/eUhg(EZO)Yx;}(G 9$p1|KBڂ,T2|GvКG2Q1H44OǢhz# [X,<7ӿT_/Fܕ$-_؏rI T8b?/D| Siм4 B?)tKXl"tuB&**ӯ9ɞwX1J H}t>" 34-ouciѓM&V9eJ&] 3H:xie 11jE{zG9Jq#dZ\L,TI2=ѫtd]G˞$mS֌]!kev';:F«:Dal1(@Hշ P ^"zux{zKZ"Eʽw}~w nT3r |م1u94+̯@dnQ Э|!h-;"B]7VVE,c;yٵ†hzX?A^=hWp:8KY0 K7qii=""W)woPޟ! ߄NvܒFbPy S-J*;#L{/oMruR=C)\R:ʕaEs&/RRQ 8('ͤNuӦw_mϙďOwOW ;r -?|I/b.c:6:&H|}7:2+יIIHz }|}go[m[О<2<*̒<m䲩:7Hbu<+Qy&˽e-Yo~iaG?gw_yIfϯmߎ e .0Ųy.ݯfB5R`Dk)nGtnڋaMXmf|x]?{hg*f#^tvCr30 zET ' #\}غ5sm|g7`G> !pIǥv38@ϣ2wW5fjF<\%53FUT+O[*jN17g]8 T]8c;++!2{.fPg^5|4 }HVO^;zuX{lNw:.G%4Hft[4ի~y}i"-2D VQX?_mMM9o xϒhB{wQ؞} 5vsIXbKrU@{eMW] LQmσܟm7g{ UW.쯌|>7yvD?/MyGԙL6dh&L )M5`ʠ_yܼJ~=?&?rXEvoBc!c&a~尷ob_+a>6Ѧr"ɢ5SNy1׊?Pg$ީ6}^j+pRqn-,Wb 6 W&aRv3bT0 <7bhv.V[CL}Lo';fu>jf@U6'ɏC9*6WņJ7G@1SDK?7V3}&]3G6=]L ƕlv AhБq!OQ(STiKKh'uoЛTG<"*qOe&YCm:8H@%A e73[)ob_c?yє@CY~o823+șcOik/)W^JbTTx8br#+} B6C6,QFZrwkho9a)/Jhz|Tj7-qĵq4iH]N7>U=ı& ,V`}ѯEڏkTUʬUֱTb}VH7/ZN ly$Pvɼa Yp5$r~K1O@S#Bkd"q4zeOvֽY oWs8eE 3MПW"hv&)K VTK˛] q?E3T:8'W)?ză=P7>y9_%n$<.>@,yNe8<|CSpu$p&V?z"evAXJ齃C$`+E>}6*}kJý?wt  KfñǓy/瑈.H0u}NtUg4䧼Q oy^z&>Ju s?N%Y\N>;@9ZzA,[4G` ZOYLcl4>?[[lM]+_nsbLF{[:sy]Z`3[|o&?i|}?rC8} 5aLsbn?꿉}KS܅^ضf}؛4ݜ;hb߶M1>'닥|aETVSuO0ڍlK߿goptOLSmzR~`Y,&/>YDJ?:NҒs,$XW9~MSe3zEc~NcrCV1x{ň~f(%*T~PM"u"#/ S oALC(|@{ц~Hd_A=^\SN|L{F״n3ȗƁk?YjiduӒLi9 Y'SoxG'ӈREItDX.+ǨSy6|ZH,E׉.%[)umeFdMcS^Q9ρ]ԏp<(HĤNH Sv{7EQ'Bwf|p{ 1Z[5XTK\%3vD~w|A16WpQ $4-쾀4zi~ŶƂ#v#63Wk a-2v?o=;4k/4rI ͦTȨjHw,=!PS|;Pv)*hJr5FNcےu<c`.dDS$1BNZ[8`z'} vJ*vN\w=,?j;h>6/r@!L Gg5.[S8; ϒXwJ3<vd%,#)Xd!{4sg@.ȡj" Gȧ&-бW#?$)OuW-;I᱋!&bG}.Ĉy#/hyz2{H|TSL4N`^s(/5/!5sݗIϘ`!,&Vsݶ2:nA6DdԠ?ij<;7M5tU5-vr>v}rglf!4μgz'& 8 _"; PAɗsjj|7/ njM] m49Rzv ŊJߧOGxpޞSW k3r $2n1<@*AL.,f[=W:ja~N1+S)Q7JׅJ_$@>pJ33x #6A6{hr=aՄ?D%aGF7~N%޹H"s lԻ̂n=D`$}5"߳[[ϫ-5oЄpde&K> ~ t*|.&3 deW, NR!% d&zaůC7; "%i2e%>n{zL+WKn&;S?$)0 |R9dһcٴE&5aю|Z-Kvd<8=IuA8b&씑졢S_!ڶ 88hBhgM؍__|x;]&㖭~]D$PbF#Cmr󁘺P vNm[x:>.qd1Y|Ȼf5$Z$*b9c)OseUmrj#`EXs 0 hh, b_BQJ[;9I vJ>eڥWUuJo7Ku&6a?VqlјGdvA*5D4=_tm=1 6zna7a/'G=P:W"N".-Ƅ}n?&_9go0 Arp0,/e 7!/IJE x bh`9S\V^L_ínaɿ_yGn|e4Eٗ1[I;W.ە&[t h( ~rz"grSID n/uE'Crn 'ӥ! rک)aČFd'781GMj wRz/7O\͎\=ZaŋǞJ ']To%ŋ핊2.:@GGm zL 4 Q@Y仮ܽ5 UZ٣3"ԽĂ4 $Z(Ƀ>H'{Q=kiKq_T^(a@P-7Cb_t&Ģ*,kek 6XSIr@vI#.B/`'*$Dm~!d%[zFogIߌo/3ςA_ᡖ&*|qDP2 o.x'Z+ӯ!4)nI;b} pТJ@ >jEs|ڴ[wb$_إ%/sV3` YL cD̦ MaR/]85Su]oC>X:'++j Ұ.]To,+ݶ.,*@+fyvT aB* O>a}/rcЍX,tb'4P4yGZȍh"[ RDqÕ,b![O*-rCLʟ9͏Xs}k#M4u XA{ߦ}vG Cu#aܳ1򆓬&>M[ݻ@&ULemeBQ#t(Ps"J 4]_I< 0z~޽|2 ȽQTqiRa/t43zKc¸Z?" AtqKY"Yuw 4$rs }_;oB^[j뙾aRM )o€9@VVUrܯHa85IQnBd|[]4c {[AD{eibw(`f,!Ü`bDJ 4(KP\>PEvxnȀ2_XWTFߺBޠ4މ?tHLy>~v C.nۑыB!OZ\u RIO'_8g5ׁK,"2 DJXF @f<3CAܛ?;.Bem,i RA] -?N9Ӆ3e>>O=FoV ]^@P0֡*_"N,H@=/j7m7Tj-.ߗQW%)ꒊ(#ѡҢcLʺ*7)ڻ>%WqSp[4= ]%0,w g\:EgeWgdq1dy' '%)nLrF+ #Š؅WV'8˻x w1u>Em NfW!j AN_tOh̎\w+z_"wIƵ0n̡y;;N,%}yԠآQU-yÞVK'znnvbíτn;qOE=X "9+3.ԘB~S|ٴ^1HܟzYa +ߐsLsj%ex)1Czg w)N8委ώv6OA\%g(>L2G ozeqo7mS"8g?=L_;x|LF]!.PSWz_ qJU\S]2G܆f:Iִ;VKH/WCF}Z\]9DJIKO5<.9~azw8>r-Wo3Punt6QWK:)=?j`姕إǫu@*.${9L7RjZmLxs|rg䁼M6VypgOJ &B"q|8sB4Qc4K(BOs/a"ixkC,ց֦s1ꗔu>y-,Lsoir#SpM6)vILd)deM)T2!bn'gH+>Y#p4ᮜ8py56uZV0=m ERt=qчV. ӀY S;[ܞuK!˫rۃKuWTtw&bx/L+Hj+Es5q#eqGzXQs9$|7f; \KG|= kD$TR!|Rcx s$DjE~gl I5ޅg]"oP(/lgx{ѶA Q[qM/76@X67 7Bj`Xk3_xKe#ӖCl9=ZyϠH,pu9Z`D.wFaSl졶f*0؏MuYN2_aYگjw<3e)dA]QCrv*žׯm^NDF_s}@rMj@TMO  ۟rc cřMuC,q{/8~U2ghˊМp4Cx0~V@8X`Ge/>,xunLa4 R&ճXrS=drI7H0V/U>sac6Kڕ^"w?뼘B3#HBlOc-0FV݃S^TzofۮKet;8ږ.h 8A۴+ bUFsu#Z5TQ+])xQz@//fv1`퓻(za?(rf\R"#=0qV?,uca"ئ#ڴ5 sY"0h Hۼ,;?C.DyS^20ۅFT\?F[f@}Q@'BlBI%IȱU,/ņ}ܙt<遇6Q̙+S%> ifn@PhRX{C3Ԕoc/78 v~98 !6gɳl)`oB}uk b*ٿBs#gDF32$JmG /uĠV= |`h.ΐa@Nfcm@&t :gA :aieƎڞJsȃ^,q[dY;2|7Lĭ%6d☝"H YN2H RfBLo? nˡE߉ bmMhb$SR̲LJ_1݈a!᡽أ9Lv)f)WNwGp7HƑWGC4Y]hn 0CbdBȝ\T""ᖇeKYi?6'1F Y#yr aÝY'S$+)\n7dHi%ThS}ttɆ@uT`<:q #HP.C}g|R[p:RHabkI$jVG3Z&ʟTx*vlw]߮.3S|~rit Is?'zd'Sfz'^?Kb[k3NNlQ!Б^Qm{bZ=H^ZȥcV]Z7{72g/ʨXbҺ]{O{5_I?R]n"wS` Ѿ7QzJ(ȰM446|N~{܈R%#ۥ~|odbvTVvM&{=fV[y-D$"}_-j U!Qp͐5b)*_i(T#eX~{ 5YuSF%Ⱥ~Ut Ŵ Tޱhf z]a_i?=& ?Pnש%%Qգ󟼽!Y!25^5UC>eO+a3#b-hqy_4CrR)F>5sn@3ZO2|¾s)%I KЋ}tK_6f>/iGaU>Ȯٜ##]`H8X^5sH J* #㩅z -M sK?r/xf3\PSvlE:n8uAz'F#OKq:5i-H+8rlrHMQm !KF~!BZڊq±{bm(1)."̙8y"J1z) |lF!{ҹ8_bqS餄tk:J j?|@mr LJ1cEjNd<֌8|`E cqLVu:+zVvZ!.֖ + ɘEnSymi -`㦪>Ɔk=\?'"lmiDt|6E^QTHNI8syfX56R}s<:KJdfXA )Dٽo(Neו2S,bO&rs,jO7|I,\(Pj&v7~gNFs/(lqy2N%ݗFh&/NWJTBX+&ģAJ^:"8Cp #1C16%Ko_lo)[ f(b>?0koixH3؂AzQ kb6Sg"fk _AQP93/b6ҦNXj~i2#޷ OW}wsp3k">kH?B&fF2^Fd7?XaKt,1NoSD9@O^x 7 ƨCJ^YLhc \Ņ~z aUbBؔ/1mJ7z]̰f{gL%Z q4\ݑ.C;Ks]ѪAJ[x?X>#L:Vjmw1O0zȻ XaFB9^~[}j޸nZBϔrOcQ*.Qq+O|9Q}1:FQͣ8a]t70[egF91?.Z_oZ & r.FA_Vi5qBV [2^jqN1ju̘ \^-ޏr|bcų{R6ZeRT؅d 0삼+G8I_6:}!hSf~I~_Gb_5^ALMוV? =_65eibJ1ލxӴ NMƝ +)$.vϵ egV0"3,cEGR~KfhB h?  l]~?xHmD i/]1Z_g  :M|L}nďhP,{R]tp:Gw!ub➟9oS93E D y` q) ,lERVTkr3f{$zEttTMpn)^o6xߍ RldU0c .c( p,.ݗ(cU )^]ϽӂZf#:HG(,4݅Fu۹W ;uJI僋p"Es:k8r0{% \0"c{'F^_z+ߛ$)KGr:^?;.9~SV ~u@529Y4-O2fWc6%*XU&&)ZhѱIP f}Hɍ+oxP^pœ+ܤ_E]A]\LfZϚ|5H5Sf7,T{̸xx|LĚ i('DJE'?up2EcSu?lR.FH[>Vm~ͦQ/+IѤl% !3Z6:T@R˚#r/ߦ_^y8ذZ;rWUGefj~)dUfBt["#mV""BO*2)…޼)hTTD֕TO3k<h$ L%D]H)sd4I{h` ] @"/?MY`?81)۫Ԭw,K^QdH7ss `w&`U!c+ȧQ[1$+I;5<2( FLE_\3Wa;c|m]=FU,i&;5-TZ*xI ="e:Bd'cqpj+iTiCw|mwwB n0=`=Kp0cqvnC!rȩnb]qƱ(tpwAd[ eꏍȸŝ8a1V-? ឫ"7t 7"\ĭmv)"Yq?d M8ؿ1CV$E)Ā_ /?[ȼqOg(6{6AZŃ=4"m"ks2 FŁ.xj&"\W1 #4r?*pSHDdrG[y_q{auyzX* \{dT}t%ohF$:8N˕$}5iEL{oPy󙘔4BLaf^֮EZiIo0MMܝGֱ5R=vw- U1CKB#1xu. Oi]B(jWJ 8X*W+@VK _?OctQMՒ2'1  FZ!!RU1LǍOA{gj#o.TcrQШsiIO*Ӿ6ޡ:7gyf|3m,DAkd]nU } *2Ȝ%})DKMZŴF&?c&UA+>.H!T;TQAҔ z&`h,<18?_6ݣҌ{ExX1A$oK yrg0bLc EL 24g j-y]|aAp"N䞑m7( oX˧}&mAJzJ} 2jyN;i2;>Xoě;KY*1 U!.B>PU)5+ k[HrAX:k@Z_Gvla:rTHcrGH(NQV40Cj2Z;sZedjR+.%n%HUT,@꺌DO$,NLJ?ڙ+7%Ž9],=F& Lmu%gBҾa{T/t?9si. ,W*F Adv>bS-+aL.K|:.4 t_RWR͞xCܵ_NNetAs{NpbJ[\a[ً2A*F5{G˒@DoUTUdR3`IBCF`_,㔭oZ?Sb#5*КY͙Hr)R{2ZN2-?3g^󘷂%oHGzk~AtD)fT#KB@P2OĦj.aѧA¾w>Ba|+J |LքFN_eChmYsAZSxݳ$a:?Ux5ڨ}! ܉U%ҁ"gl%e,:1HjEǘ쀿;C:!0۷I~RDgQpnu#j=31f1,GXμߌ##x8 Gn/21O#^x5[}0 H,Lv]b^CDW2sdO r]Ï6L? >ZD(1dت=B"fюšo h' 蝪{p0F.uv̝W +/S~>Z%թeg):C"_Aݷ6c[ (4=_-Csn?=3>7>07<>??f\?==xܦl}zzyx2~ܧ'.N>?j|w/in|CyW^0,4DiIa9Fu٢9(  ǥq]wg^S}rA%?L[ˆ,_g;+t/߇ݿJ'm͇rIz?/X9"d /6ugjO=٘5{xpyOzvJ# aNʥ6 7Rn[Ht~G(7eOקdlճlլ*GѳҽgUE6.K3wLaB>#ւl9+7uUOk3T+{lQLT Fze%}|#럟˳UbOJg *f[WobAooJOtdݺoKmKo$޾|ڞhzl?Cy{LaG:9)-$a$WYMζ=Mw7 K}Nx}>t=+cE\YZNdk?91>yc{tΤ鑺=ɹ}Ao¶&yZ&G\]{*G*Y<` F}.~:qY^NkX]V"d MFf^]O[9;9ju:ikͬRR~50Jsayu wπTǏQU '4xl+GWa1q l0mݙN-wJbSЖ'‘CpsC?' "\ >Օc N_9ݥ5]VgE_ 吙\/ dL9$mӹ8;IhԵהijuɃ4qO̭o g7d߂_]PAl P"ڠQ[ T8'TcvHwrMhׄܥ7\ÚIŒk.MQbLx{muG LjWg_vC_V-,mPݝAbu) ZX OBOEꗄn|M'FW;"Fa 7]ْEFYQbnr/54 XŷZcCVZ$7l xNb s.dK(]͸蠃 -BXe?_TG]'waõpCP3u[ZׇwJת6=#?ex{Jꫯ&JMep&݄KXJZN?q8H.aXƷ:09z@/瘸L^^ߴ=_JF@3&91O4 wwZB9Em!`'ֹ*,אe" ;O$y9f`J#5d2,q2\ /HTGJe!b'Zګd _FZA~U-9Z+W M*$7!LKv;|-,K(Q=s~nfܱUmlMP[ C/ɦ3 GtZ-&|8Riwu\j"m_lY>$~?B&ݔo",5+k?Zc{p6qaT>?[,5sv?#@iQ .ɼQ:G63@>ijm "^O3q ͖}p9؁VaצȦ!p6F=Y9*z,c`$t*Œ aoO~('yv.ѡLyyK?q}V)X4 -R>xV4/9xǓ"OÉQ ^?"y$NݾcgS:zV9}v:ߡWYOEN׽fQ[A$o2BەmcшՋ0lŐ]+㳩/űCoVw 8s E }i*a7*U|'41HptR_oVW,"3{P>M4L>'=]Ҳ~>5n-!Bۢu9?{~%Pvc;]S~RQtNc0Z4tCå+HȪa@|`sKo(TL<+`wS?SGݓh[;{3G<,r'|7ɫs"H̥%I혩8Y:ɖt{ KGmxo#͋AB^V>^%!;S~SL2}ؠ; z8O"B|.;j1|1)e ˲ы}si7ճƧұ\Qdo?*`կt%XKH]%5 lm>"K^#f;FCsF#eZk{cӸ3Yq]~&6V| 咄6(;q0YS^K;i,(x L[b c,oKsw/ F'6?*BTH[1\.M*Lt-=V|||H;嶞#d^o.chiܐC]jCS7j"4& ËrgkyV> d+ޣAy"vg4;\q ,F@`/od8ݑux8G>ۭ.^oQՂڎxv_B*B Yt w4%Br-42Lt/N/n-qGm3.њ!"Fqg,,7nm}aco,ȯORbq384Q+]brrd ]Taco=i\vm.z亚߇\۝'8xVwdfXJr IEĬ{.ow <N3f1,;"עEX6LP,8Od qQB%W~waZ/ o)_ ,)EDքV;nwn*;ҟLQ&Ѧ76"0Bu^t̰M 1 c ԙfAdf1=9ɴW V(x&?BAiuUDtW&ɍ{+\E+2kpLST%DĠ"2d!;{2{9jX*Q$AM𘤖{JvS+M/m}Բ/d櫋v;&?eÝ{uxdtDƱݯ7԰6#፾ؼ1R LښL#Y8 ,zrVW]z%{4L$!e>VEk ߜFTȤpAeTo0s t+7 MLʞ5iݸ7+Ye\ z'=@ f5%^2T"Etq7KoV/QGr(axr'f: :O@#YyQ+ku ><EIdl.+j`QrX8 KAb@7KAё˵] " pDϾ|nZC@!^9׹AB7fE9RkL;_u*櫁-Dg؂+'J)1{3vJ#NRO)9}mZi*&a(Al(%E/:W f.)֜g[ yD|RM—SD$dJt3h :T[~)Ү:\GGqqmBdvY&Y|X5Αtut_IEi#ҍz>>9x h5!dN/eie cJO`+rY$T+^標b{>A%S7E4_|\<3B6_nt8F_-%VզKPn$ь6rElMԀeDF(׷mu(Liĉ;zR-¼Q@Pyd`rJ%[{ՙWPe/RuX%&PׁB1>QY ]Rf!2HD%z[ e+4ZDfК(fl.&NB8p$`FpDIBȓAf%N?{) *x^iMfE#ǂV|9˓zi&BѕWnÕzU6>rF!F i jN$Ƹ/ৃr.>)VQ)) ?ϱ@.jWL7h4~;F3b)b^zʶ k{v 0Q'/V5,*9J|a2@kb:z$&CCZ//24Cz1ҬVmQ:'Yl5I _!*ˋ* zd s# 4q'l9חQ4ɑN{o28]չy11 $6ˎ7쯷31%oލ@Ӡ7A9 LUUG$Wbyofs#2vDU~y"{FDZ!p`dy "+KUKypȴ(gIxYexd`ucZ]4օ~!2 G9-' >u56K?D7~lK=6cZ€dBVMcuzIEڷ6&-n6Iyv;KoYv-9v M.S4DlP:MIeeۦ^DxG,QǗ>$110JUpm{/V2 C],^ź.bҝ̷"([,_ދɴݬ3P fk :~'o>}ivYdȧ,~zqIB =1Ҁi`|d1Ps֞؂gdz@Opb[Rl!48#I&)݋EM{?FŸ~z3*+,ԍ+j3it6#e؋dbNJ[3?B nk`T 6`_L]P a5#InP1\ZSЭTNd^2h>\DHQ#p.Qb~IXjfvF&ЍС m=P-#nXbZhmv[ry{PR;pw$oE X UTG{6EϪ03fli^}u>d-_,:+3NT`k=ȬҨciao߃Ʒwqשyi7>iwae"qB7*6I'5wS>50q#]{Nj>a˵:5KmOccK}]@_곈X/y2Stg] j3ٳ\}#OlmV}GaսOCS,е{KoID#./umoV0[e2't-cq$3Oo7+6Q7 lnFٲ5g.Ysp\,x~+ġ܀q,L)M,^ 9nZDZaK2vfa~;Ua3_PfO(3s.}+]3PN{Sʷc%"V8S,}Ekf$bӗpYvղXJģ;^/"{EW"W^CyUZuZ3O0WJ֎ *ziMb &Ilz7> d%Leڄi= \%{F_WhUY~Q YZĨミ{Do3ݾQA2g4`GU̠vrRR,jOtL^j6DYMN93@kOMm- 鉧H{ =]Ls>qNթC׸@{ TKpb#GeCmHDXQ{WC: ,)c쫅ЫS !zVU i1y.A%*[G|8)?bMrc~&D,\ˍ) Hϫ,jXa 7//d#6EI 4ϢЎXC#HQJwUYwVzqo՛ u7ի&R"7%:ңM"9Ezݒb6 eҦe"Q3h1OD5 >~ި파Bw?]NjV0 jH G}1[,jSی^h aN&Ƭ)%GcѴr2}&䙓8USTW;qq[Agpx{Z xsv ʣ'* ;(}~&zj)gԧ;jv_pW4 P b'Ħ!ޕٗpox/\J74k\-\Fx+x܈Y^$BpExYǔGk4CSZ*Ǚ6N(,⤺\ |׀CK?/c٘#4$DU싉M #Q9N& ׬77kq }&|.X4;,}"a `BDm:#Y7~!0B L|mc"yӰ"RgG@@8ы ['. * `YG%. 1&>#^vU}9gMkёBh ^ek{ڒ;A=KDbYiT+0r'B=4G]+&Q,)IcâvH'll,V XU"bw\j T>WF>#vp L%]|8P*O'QiN[̇u>o $2&FW"h"ְ Mv2-ѯx!3!5 ݽ-eG;'c #0bd=2@D&¾[ɞt;>=V]_!|o(  wXբZMoXjj QH߿e3Ck47]\־in.ژ-ڠ!7e^;uW7MzRdw#iZil#ČK9!q`*FB#}iiiaiOJl^U`;GO'@_ "Fs)!; LaqG]CXiNXxWc>+@iFWIyj=`whFKBL7^_Dܩ*wq4i{P{qsͥ*KJ8FZÕ "ti]khDvmͦ!h,xip-`Ғ:ß=ނ&ÜB~oVcq@ڨUܖW^zfPRTR@y =砇zJ:;QtuzBI)RaI]\? ޏdIPHh7# hb;=湘J.X|MƒaÝ\AǙ6*?RLڠELoؽaQE:-PG4~1>se\+t^DBnMt9zE|b6V m<>Pg$0n/ ~F=Tlj&G=5hk(/ѕ2GW>R|>[<^(.4۹Ce?ӿL3E{$h#a5V|{&[2&>;KHQyLz;l1ͩ$<̭mrRllyZs AtlO$&YWGGSoL#I}Iv}Aďw%6r{VIy^\U5 2ew+Dr5&1Fs?(3k 59t8b2gXֳ^s ;G.f^ⶮ(%v}./nVNæpaԤejb{X rA_psJ1[FiA0+Rks_yԁ #fi`yo|[S|$gPhz _?υS["c-Y`HxNh#w'.x"-:"Xe:b$Qw$2R AvyXL@auCV֡s FxNESNEO8 YNAJ(˷XLVaխ0q;2vf.n_w>^e.vz7@RQn,tږ)'׉ĝ6U[fZV>y.A$rex+tۏ3,d!@KWoC`kHo ;c[Sv΁<[o\~MY$@"U@(M..I0G%#jw kuߊ()XH&@Y~ Nu("EL ć`c _+F.)#Rwއp> Dn` {]8l8 3GHvAeNOq @?0bM h),;a%UӗRd/ط`_S9m`r7~LƷ6ōO,am/|~;GŪxl_N>ȷBS1 6P2v[JƩ&nPP#T/<+?p5ՙ2ș7}+GO3og,*F-Q<ý7\ T1`Ԥj\Uٛpb7:ڂA^ X!{ǵu ~@m|:YsntF`+J/PLj_8mrT"lFn*!8]wmn楂L:c@_ƫHJڌ X/Q@UT7Aa7/7>W6@ ^pdk1">T9vZ'ߟɽ$B 'x6[ *JdÎCa B+PNmu _'.˜jMRO93PqpX⏠M I/HIW+WL$ߖv *z-~Iї՝+yϨ@O ;H=ICv[qJ0b~gG # d9gĬaj\/FY!P6Q?x ^J%ΗR;[$\fɟ`Ϭ6{;ڱ) MGuQg1S%Ft@ڠKmbns.°M){$u|gM̮}1Ҋ\+qA3#9uynpinR`7XkNq5?Ki?ey(b)$b,N?hr:Z,zЖeY4;:[J!%u>dFRѫH}Qyc$;WѦ ɚ?zb(ъ[vNFY=H3u= iI{f"+&OgLlb+N-Ud}rg8h3tDTPW24!i@ya@̈6g" r)Ts$SypBi)8:$RXiDN}S놻}ܥ#V尾NhdJmR".9/BbtOn _Yvd[Rw;,5džV{Y<j\[ňYQ0EU xZ$m69JÔu :ǣ^l7и!R_7pc⿽MXnae#:DK8׳bzQg֤,:Q~ ]%9K]/9R0j]0{Kh QQ4ɰdIS*B;SF9X Zڍrɢ y[o#Oi.pML?Tu\[K (Rݽmq/Kpww+N&wqz>${OfYz!Էk lsd[tD*Tr܁yQrDS+-ª?9˱;҈kbՒu,!i1tr䘂.xJt!;AT?hǶj6yԛMhg/[R`6L@םQq.#5(qQYTFo pg-'?Hv8^ڮw?8]kl`}BU`ũ69190"7 6݄[eBRM>$yo.`Y#lM 'X40Hm ^u* E=^6]499UMLg6 S856O(1ݔ k=ޟc@FJb|(z6l>`;ai!1#%(`›Iu0RԼ&*d)g wQTM?Q] J(g@R>qܖ`jk;Uã++q :InC\|C9ߥ/l3v c:cǒKY;HgTd:x*y(ٙ0*T@.zxL{{-QZ7JK9 Հei/鴸{7 ,k)H͝fp`|ǰejMxVaIas6s⳦JX?U+NB?GVgPeCb@.>i#ȲThmϢky9OњdmtMm7NcYX!'/p9gc=[_F `ctzM$ KE@Z 4C]Ǜ \%PLQF +nt񘀪FXN_6HIe|ėXս 0KW3# 5 ɥLR#+K! nQCI@bt./CjBFԝž̿ˆK c qUI@4G48X՜򏗬zBY'ڪ(PMkM1h) }4#YYZ|%f7GN,ޗ̗HQ%^˱𳪮S^>x>Od[b_ G3PQx_Q1.]]2gV+qp?:\Ӟ*װ@dK>,vV%m8%.R--KP\yF\T@18{yGsUZ!C dRl4 ˻VvT G]ꔚaMr!0 kGW+G+`*IRJ|-xgC]~p8~"󣚝y PJ6[Bq8isNN)|H2cvuU. f⿪S.-9xCZ* ~`H?*UXP/f%o'O&|3E֍_U zv "ѷn޳.|fu,C]947;*Tg#vF1[m/'ـH yv3FO qaotQaց2eĜP8@ro"udɇ2"`U龧X`j]M a5#ꊟL [fxFVů7M!E5ͳ8]EunUG/j|-ib>NlTc;ۿ掼JVF*>ei=iQXKʙY;BPCKј&6cŬubk]!Sc~`߆B9$4'nVKT5.`U%N$Y g\vPwCwWZUMqQV9,hbIr2. Ah^H~En19K{Xrd·#BQ}5`NI>βѶPjh̴pFL\k/TVm*v[6BuRK#}9۽p8!J,Y|LQG]Q}Y}dﵩO.M a`D/Qo¬r N&ҺB-zhOuxl`?*1l|L7KAEL0S_Q]n'Ijty6c( {&+Q8 ڽ%]%Hs-Z  05Ҍ`Bk7׋G_An%,ϯZ.4-7:(> gF:-8 Gj{rne j" VP8Z~.wX gjDAz@ZM&&;wA__E0-f&}=ԦZWQ衍s*Fy֑{H".)KHQv$i~j2PVmΚ >.=)N A= o܅@l %PDNtPTf*wLz>J%Z#I`(\`n^OzKgJpzGX,>>9t!) 4#{P|0,>A #hQlE,C F. y)Ji$'[mc=x7GEw$t1?1;$di?M09Jh`O!CCih~<*}%#)L;)ܑC}1jx} +;Ms/ -,X,ξROw2*$'Su|y⵩,^+]߳ba>X`*ૺ¢x '7m6MLCgh5hğ<*Ɲ{>DrBA+=Eg.79c̛UT#q4U ,P.A+#)=MWs} +% pP(.Cnr~@# C͟ hAp Ez;J՝D3痈JHBk 2!mj P+܁"a-}0gxC^/bԺ}#rtB 7s?B* *x20Z*g<۞E!QMnl[3Rտ!D߅>.v}+{&|2fhNu_HQj/=3Н}t\3\ *g%aBLxqҟ Y ߎFj߉E'j~Tֱ u)~630^g)}*`?5}9}TSsNyU/C Y,Z}}>@&tm  V.军tr3Ԗ*$=3ؼ7$@C*L4RĮ-X>/Ę@Sq!ޘT}7rQtj_IďC%$n A rƉ:L%:=mGKoI>OCA'^E #'9Fx&W@[aa1E x;2Xԇ@ Z ,?` 7`trM+7x@lwfwKQGe-HdX@z}Ca1Stw7##BXYYYGYʣ~B~9 X_l޼Li%s{nNR[ǼusxWYYrxC{&:j_+4Y.&=^ub>QUUS]vn:XED:]{ߋKz*wC U2塨})h7 0oz+bh|I/ ߡ0nWO)gvϣw1ʫ<&}'/P:|1NCBǧŮnWYI;> wI傍Q.(. j./Kl!U)Xd)re3\_W4_6\.&n}~ J@W$|qwxvMq 1 Cv|liq9?0T) 9r3T"L{yw4u$5=m᝕@bxY.6+,3I溢HXXTD}lт9=?TJFQY r: x\Oxiy/M#k \: e -`-?s3dCTJd5n A.C B{޸yXV[~f87= ҈M^0GvvByuPQA2c tji/bErk+v*%OzPV.DxA`bZwfɩRA Ҏ[:-1[%7s=ASeenjɩTܵ8L& 77ʈQr+p1R-LHbyO_K VΣt9.<73#)+y?[:'oeOw +>"./;OM~u;2f>_tKM痻u* fm**q;T>xNx qߠu8*η35eZAV Ʈ3;8}]C,DX^F35&g Z"*9{0^؉5{۟\JU2*lָB_AEߞ1jLs1jB*Gauo_V<2΋-SBNSXcQP{TdruÿF;xj4K9)j~{.EKk&qrcwm3fab~W K'$_[\i&x8w2~틒'iȄʔ~˥7rtnAAE CffXjpy/ /ɹ/VyUiEѶnƿ¹]ZW3t_64D/LǴWDzX>\u^~ `Ғ?DtG;ޗhoʀ>Xb\8%g^VZ0xC9IC*t KAda̓u"SlNr!D(77L27 gi`.Dh㉵3I0YS~ӚX&.fctr1z5)r)S$ S Ow: =LIt!z0>G7TbFfQzmR\g1ٰMUpDML:Y &":2X-); 5o+l5.hI)K9x#>TXҼc"?1) 4E.R?GSg݃>KKO 2kJp͘Knp3M w!#ϧ7X€ AJ0ߵq P*k|RIۑGu.g@xhgN_8vH";z?Cn<pJX23z$emyUda|JUb;uR &?< )8.bx'LIQ>7")r;X,OŦh1EIZGk%yeGE6e+ 6wUgW;vIse3IS=|+P(R"V0ڿ@뛀jd `syu0WraojoEnyAV~Ƕot2n# zL)*l2+Ud?6mk^Wd0x PLEZVmI%dv9$~۱nܔu1@R V=՗}yܱ 'v?yƒiF0咱_Bn3HGƙd e 6 j_)x bbj d>b!E&=$U[>½̑HU";b^R81'WI@͇+x^/R@s4QRS] t&VTaF LBv ;0j}߽fxF% ?N1 ݘ[˾ h9>**HK|ڻ/ )a6чsFwƛU7R8{R0,4XX*7Wd+À<׍)BD!j(n! 7KR= @Ŀ1 ܨ5=!u@&O<k6;ٶZKʕZeZ2!d,peyv`KEE^}%DTo3SDK%ž R;}% |R;@~m..tJxr\Ў0jCKO. tb.Zp;LG0u8޽F0XR+0ǚIqV$s c}Vq|ۘeT&:WDԝDQίQ넂dbr5 {b ƛΣ󤽼?\\؃Z}D `qWY+u#qq5JMDȊ?q^,z!>H5G<>&>BCμp:A(QA8km44!EI 8>XɅdLd8@eKWDVWd;C/rʠ8/s2qXr+!4|E: jh' !I: nƛ;71w6۰\tG9yV56rR.XpO!mL;?Ž6Rs!W(ԣFdž/ZSW(/Zba2 *a7zmAArp ;KG5h0|mZS`/0\S[soH)4)hS<ڇ~ᴀ-J5[|T9=znNZջ6rS`0;Jmq!vkԹdJo",Z1x!885#y##a$Uɤl H>\l y0UM 94=htzo麚_jo8 M ʹ!ޤF_H; F+)]5f{#q5\ª3nM"@D9!` }_>]_.w iEHM$=8 A.Wc2xƭ3 pqX ~fxZ m?=[cDpEO%X("?׍E&FA6dnYӍ,sߋSI5z;aq A SD{>_65}n:Ir`z_.cNH̉*:~[XxRˋd<#/RoxL^pb -W._-c( 7igU%K5Eda"}F>콎4NegO1 ?0YLT{ ibic69#pFE *9#% Qf(߫~q3Z AkReh= SBl}AD߿!7r R"aAZ> 6 @[RD1y?*zQ Z³R of`ǨFwqPAs7 =j+٧fr,BBfGjYk;a]3N'c*$#T_U]Y1m2|k &Hat1+Pb@cm~Niwjx!(xnj9x\pf/æ/|@kdg@oq3( .5*%y +Nx^"@v5+M%@~)|bfٳ :1;A"V?O7uX&tXF q=R-i ⽟{hC NYK y~e>Q5!bPUS%چeBm@\M*dOaȷ䠮+1Jc,!)Wzb+l`߉ɐk;A  S}i!yg~vӋDEe;9FGOz,^+X8xπ!@5p㰣 BȪ?_o!\7T\h m`vˀw.;O\#aJ&Gt9EuhYTOM{ QO_`dSnAPxE >6^&9OP!5"]2̖jZkXPIVMHm@7z7gs2t-D'd BpUC7f=&jyusD9NPQ*ck]fA=Vp9#=VRbBluQv urSs^Fm[`ZYwQӘ6NKoM#&Wn=߰)$f5;qNUtX!zf3vJa]yQ½1#߈`%ڳQdT!qX!{w=망h󓝃ε^ODs(%cԢ=W>ԤHMfw[u xHzC}V)c'"{K9Wxjݧ.H=@(}lyxNH-8Kywe¨Ya̓8TK_^!::{;gt)lcс=6//oD|SR0 ~g#z|DA4ؔNIIv9pY0F,ōah VEyxo4mUF1]n*/BUy->ZƎ5+\ZM\N_ koGńe k:Z;0?K)E~Q>▏CYtBJ4"hԙykyoE}UL/+GjA+ Uc>І_R<3Uprauetp}@ң}W]3Kr9ƚ&-Sǚm1ǚ^nU Kr7Yr7ݘ[5a}cE 3/MD:}hR٘2[#_<ܶ,(ޡ W[iJU23嵪? &3ထ ej&k/D6X|g;v_ nʏᕧK1\,3>Oiҗ[(˸cf3nR$N5ZL0Ep6urM/9g-j |GOd: .8As4'J Z %K+3QUa@W3^&#4> \b̘.mKuG57 w$@7cx* ¹6N1J%WwᨤٙwIl{_nGjWS[DhQb ?Jz2`y^nY'|Ps T,U'ZUCv`ڹ^hlf,`B[h n"n>N#p?>Lx)rܞ·RpzQΣ2CyA;uMh#1~'?&.ѯsvsEL.nI s7R~߾SS!NgAhDzz`?>$ӝBݤ2h6f֊"'BY.RlJNR{Qg24ׅհv/T7JeaU&-f)|/8N,"'WiYS-^X Yx ?0"b :OӚ"1 2\lkMiJ긡;~qE79) {$n){cݵjXLq\O Y Tޒsu)*ζ/pܯTĸDƯvK}ٝq~& 2 ۦ,qv8j"~Xr,?H&B4:aW9jBAG@c3p0 J_%vJR?58Y?GP{R3y qAaT8X0Oj2M2%UD $F}N[[(EѪw0B jӑ{sLI}3q{J; N~dL}BYdL;K^o ^+sO#_ +4܁?UzV&T.BZjju[/dd*y&[3wtV].7_ݧD2]+п/@;(G-l@y ȠBQq Gw_N}Ru$lU_A¡bolNC~1XY 1nێ.~Vœ bz6ѵT aʏf$v-,br m20s#e^w%)h=q<0ڇ  { u8l`dL=x6MnKU<UóMh z`9x5~$ [QT~ևxcfZXg5.%gg:i*%<&vɀթ72xpEzs"H k!|Zkr0"5|ˆ=+cM@m7/%E/E!j EZRxNS !ʞ0l4T ȶpaSJB.B뱬u1|Q;dfe1p0[FGx\3@yGe(v"N~$"# yW9#`!Q ' $g}t 7it?Q-/ۭIB[|G'ne>ݟZ4Y#~ͺ8H^l0вy˄F,dI*cѫԑ$A)y:7 ;Vԝ2dEF|l3yiof$+^P$QhMA;;(w!Vv h)xɜ7AGk]MxQJ@9 m 4vt\TBP,zL3f fѧLՠH^N Y d ͍Dh\8PY5U < iўe87_*#>Yz̈́&HH|qie釃)y6c5(KL}Θ:IŴ%ῐ)>Г-vO0 %Uxk$Q"cIH MӮZZM/-@Q. <3aXƁ+o+ p 7%-.Dl*gr`JNwejJT[` z3/LāʠH* R:dȔul?+;W`fyjBaJU uY"F0!&_XDJ|aiv(|5etx\R/lAGp4d pEuc B&K!Tha22rtpcژ6CKi5o 0 8&Ĥk|f $nz} w8r袁<L05QZF8oE.A/#Id,;4Ԗ\hk&zZc8BΉe;$KyA0o%0 dNI"(swx\Cǫy~Q8%~ŏ#4J?jQFEzsd2A/)??ԴQj"Rri!8"ּhB|q&0\gʡbH QcSN^pP@ lMe2d,DsSIN$ '3CLRKTv!zv"'ˍz|J\a r3fJ3&).h(S~N6>D[OBY!!tv 7DK\ubrUK@;J)dո@U;3~e3էi fLsulMjހsP%jS3ȃ^dÃF"<jc5vėZa ZDY O[#},Mk,T3fb]$&k2ѫJG:.S TGOL7 q`u9f]#HhR]iaU8l}+慛I4sw.Sߥl];ʆ(ْ2B55 /H){LaQ o} 攀R ѭs|/^ 28uޫ,,͘*-J]B'&y胸 Q 0Ev9~lǨ(;zÉl\IޒZi!a |K_*uWMSς"#KhFW}ӼMba6`w0 G&}5g_^ZL&UW4a "a-n l(yRVwRux"x9-| ѭHeng&&X4#]gi֥ 0Qw w}~ҙ9cK̅ʝL գeiL/`A@N}鰰fg~ ^0 MeR&SxK^)X,rgM!L}8t©{ ah$ x'NH.G;z%8/wNb+e"cc[ y")o{e^7Q O&6J71n yS0Aa>W{^MYNIf/~_$9@' [jҾTd3=:L*8\{\H}< }y2οiݖ,Z~G }qS".a %#RPP=07\0AP7AoRde'0D9n.؍Ħy) z=Jъ"j'5&DT0q B0< 8 R/E l+$Shl>V"iL8l֤ ڹ >9W0U]ܽB`LC',( l)$ZҲѵ?%vpt%΁(!;8$S;>%HQV/sb{&N0 (5m yN2_'6.6UE*`8d/nX1riİ vcby̠lh5U kA84\)Y` $s*=a(x?D-[LV+SB861EjyMb^H/GS]:"(N稛hGW'9\CݮhA914&_<8C`ݫRbiۨXG-VAiC4.Fhs6V՘Ljg~r l\CX)߾!83RĻKo>pE֤0""E9uX,oK}!Ij)IUŵAGi1?GE̥{BXbS t'OuP9Ѩwd& "AR͑Մ)\0^SS\lG. Aň*\\F+fy/Ar*S`Z+>E~Ek,(0ޓ%-W%W\Ʈwʤ~N !ڋ9 s4XSK`:H.smdrk7h8D_dFLzn,{A ˶1?-de ,WYI4B9 ޥ1 Tġ{Bl40K9 {a^HT4fKd/k#~|/eijiB_F]j4[ES'%ȉ%P@F1!G; `d0HsO_ gqNt-A{jS8ח>٨JFwWЖwL[DJE;>m$ Z@^sЌ1ZAn li 0JDWF'mSPkcq[9ɁZ' vJ6u&" /b ZkϿtyR+BNlL4r+-?{#xmy) s0ٗX8aXql.PSd_k-G J龓h !Å!1PQI Zihɶqďr*\OdC2tpxPh(B !K: Z':3jvБ&ohzl  PJM&9[Q;qo ($:4zgWFp1RůI M,Cy7r'PۘE葲DZXr/Z)ZB{4 ldp[ju܋Ie #gE4L20M'R06qY&?áģ6j5,(HZ2󿝌bVbb.@c0n }+X*%K&Jtdp~!^g)B7{6SњL?*J\*Kpp{P_~̀推q(֡ʕxw'#PNtr34S&E29xPJ虹4=sa8JtgCg쳛) '#Q {jE%bq}mt><$bYNBal\(pc.9"4btKNf:ym[g݃r8/"\s|] F5H6C^Fϱw㹴By1ЖD ɬym LYKYSZ+?T$ށ5ꯖ1;Wr(VzdQqR_a U MxJfG=zQY(={a'+7$@@/Umi"/`%- -5y[8sRyHo4ji7媥 D4rŪito,+ 6o-C1i{0ֲ1>邤0oH S8#TٺJJD_"I'ǫ,=ʡ61d:4Fz_-9;.#q4UI0L ih֜;P})>,z44n'xq5$)Kz)fݓf*IrIE%5XĜT*]s;EU\J(wÃnCN8Q$TJ!j1$"`ht_@GE^q#;S͟RPn*79 c6YUN YNo_5#Y;FwSkhF*&zȻoVM %ĄӃfs-+˽a;ޝ O`wtnyaπpnIkd_YVƛ |"ȴ8,bm$ ?*_ClZwHnr[Κ)2\ro{59g96tS{qR.v;PR7M~%ĬxmM:$\<At]l;x->(ܞ&f=Ĩ7aJ၏T9:1qb씡g _E)9A/ɳ8@}B#s3^ [ NjoA}J# (Nrµt6̮?eA)&lR!3gyj5GZl'߄$ZNwDCۆ8,9ω Ҿ9(tqfq:sה( #0Ah p^" 0G*4׆ <ÝUPHs+]P/[>t٠( fKZjWM a3B;A  ͖ouT5? dS,*"`lϿ %b+ض_G 7nE=xM[7=`tГVCg}rZkߖٽ .`>5;b'՞M6?5mOcڥX̳sm{VG 9(L{7fCRob7/>hƆ~1uE#վŒxW\}6֚:uLHLHeGA?<A>ؙOFu?S.;k[}ب}߱~Gh,#@\&e5zod^Ie[_cz`r]yʓRvNI pi{}~GF^zD Sc>.VEc~Diғ\^ F>~9{kp$˺Yr٣|ssEMznrW=P><#2u>vocVgIJK8 C3ޜ7ZT>QּˎNiCYzݗ7^!U,a?R_GԺ5WSSE',3wa[/ tKx*|s6|}ϴ͏ Hl O1ؗynyt~ U-h{CyOC} MZ,;gN}vi6*=;܂h8w=]"R$2v$y}x*0^L,o{t<7rt`xb5f*˯8HaNxmΒZ׶ÝCYptn/Ƕf PXh .dW84nNOMCzG>1uH  }Ak5&Z)i֮4}A9bX\2 Ǖ>AB[g)8dB6} Zߡ3dJ$*a~[1aq$"LLߦʅc5j6a~'!DB;W娮Sw̛iH̄gw&ucn ukE h'&!)gxR<m^T9 zw*x?Ui |/oi)z&ǔ,ڠ[+g)%buYCC|dJgc*S?&leȍd]`!΋y0y0e/j"Kw"f?_LiTj $ ]P{K!XҴٞÂ44g>_rY(.¯6 f$1wmm'=8:.skShƒG<]֖o3p2N{;S} bf1UKLN*D<]IQv Sn VC2u,,q13oJ6#|/93=\כ5d]NBȤnսQgQ2Y/3O tu@-Z8t}sq2pƺ# Aafq@(ry<;"0!*:U0Nwn߲kq-m<1&Ao):$_^[Dy͋d+.*!N !F\E3DmY7qKֱ:q>:]3Xʕz K'څPPn)1F{u%ۦn~S(!t럄 1X+B_Qݔ ~ yr.WZD_0<-d5#,bzW fa%6d8Cl ws5s`? ]oʱ'y(H^jor-+ sGu;z* 5lw,aId8³B_Vi=ZBWAN%/ZGFa[oLɿZ"'>Mw]1~y[43ISxL~dK;򙲯;)״2` gʸ[ _%U(pqIwJ*:\C''{/=Zl\7 ȥxL]*w>Q"OΞluĊB"{kUR%ξ@m4r)FssC xC N88 9JvNK[_Yخͬ<.*n: UqQZIm17X&!~- Ć˝C_W οfEX[V aPVqy\-xJ==?jF/Z~l>oR-P);f )i{6䤅f}wJ)qlj3'~v|+;qp=o/\ s]12$Ij5g׸KobnSiw\{;)' !^Ԍr5hYJ?fO T ,A=}bФoiNKD4gxٖ] D9NvR޺*!̳+ywdmCq6&qKL2*1CV*;dmƎx1B$|k&"Y^'g`kp|#_paƝ[N$K3cA`ʑB*O*0OdG[)lAv<皢kطOTq _=t;:W~j/T4ͯ*0=6m=|Km=RK-Ivm/&~t9ZtCr =[ßuIΡh1둥hdɚN\f0gv=?AZ;}d $ |M(}ơuikdR&Htgީf@$ϱP('muVGWq$k}Qk7'/m I)zAкe/y̺U aGii @rB(~OE(}<6T^l ̑ȟoUҧ-,`d6^aLk2GQ=kbêq i)+񢒉X21JiV6Ɨq5uEDx] "h/R]&Z4شbiRwPjVF9>(_'X sU\RE?g+wr~̕L%#i#1I>,Z}cK5Q0̲KI{~.GvnkbnjWPɶqh,$K5Aɹ7^(J2adcf:40ԙ %(v]+h'MjCcJ,!!Cx}d]d@ژGfo5LȦpҎCSXW'yJ;Hay*0FظLR߄PλRrX-L.n?<Ċd@!?.k5댂 &˒Y|"P]H>s8dk t9*ep<{<E@"XKv58 92R\Α]rV `ST;vJ9'"ªt< ai:b9#V!k !Tb˽{߃oV.z4f+swPm"WL7F[j_VsscA*wD_Mp׃6w?fZ\1U4V'B $15 *(wcr()/H\8,#aI؛XONSWW\O^SpjQKrb=p"훨(W<$!yxd ]8S9hSO|E/cۯterS ܧlqR4_˜oT4+D2F>3 /6YQ&|t~|kHvΙŶ/; 2md;]EImRjsxiIY~DbY īxs0^E):k:ڔ12Qbf=ᘝbؖyXZ$✔"\axjILH6`H5MR>W ƬJH<32-Ѡ%3H%TfU ~ )jf gCVD7U| @\"Ylۃr~Spˈz &q= ]xDXӫE{-JXHa(Ksd83̶FM.]-bbp 7#d7; i?[Tm$4:u* +xVM9zw*kLn#QS~Lub”奖!U^6(ZI^F| uRZALj'B ?fċYAFDX ʴ8Ix+趍ArxĤ8˳A)=aG eM-oW`no8*Xz~J*o&.0W+;t@>уj&rH$c-gótrYƣxS ! %Ʒ |@sb'Y#=IVo5,,`LyV08_Vf"n%f RPe;{F&[U؄Ã1|[;N+um re\a*=<6QSc   4_-' JY®(jH [xsxD#V:]MN6D"-7U,"qer}, ]h@ttӃS߫•pfåHYpX JAG ܘΔS/z*ҚI Z_iO6`s H|df"M7AT`AaRT?^T`*LdA\Y[ b\^&(C`7@? Y~>m1r>f. /*B{j;hs}^F a?@]TPL72(W?4U\4ّL&%#Yo(q[+鵹.Z]"ϷaTAqan=kށ\d~ǯypK*O_ycV=cHkPtb#$9@H&)YQq4}J`+p(wuAKq?jQ$Q:Ŏ|.2;Jt$V5Y рGѾ+(D _r«Ag'ܥC*dbߙ1^pK1T$,a!V x8㸷tpdxfEwhblD< ˶r.; RaB\><{Jlx5R!So$L#Q1 (\RXܑguh&x?#\z r;L)~>mpQ0džQ.մHlaE{.&$ 4 gP4 +H|nOTߑARn V8'Q6#Oǧ*pđJƦjqXeGt Gϐt14`։&zzSXfprբh-$U|Y_#$58^nT3"ZC5" U8Q;k*~Dh52V,"rO~%q0Feqo AȤ^槲D@s>y1BnA^'epp@{6lyB!xd _A]iZ_7ws\:TA'>KgZo\Pֳ^ Z<8~ %PR|Z+( PVa#ácY;ȇ:Mots M bx@Yk!b;"$:>7 *v@}x%w>(_1⵸8 %l)'2d<^>lDBP-:?vc`/psh!hFh=]&*c^aL 417G.\{Q8CVK֎Ew8Ρo.HT3w_N+VԲ6o@{CR9M3|I*Ju:?A.Ӱ|#O1˃8jsnSu:suՠ!< &+顙ڊOK)sIE8x+. ?%ks5@أ#sW6} зc:M! Q1Vfz]]}e/l|oKǹNAP= TEu2ޘ-ZHe 3 K7D$]7.Ԡ\HW$Ik<&.9E|jtr7/0% K:R sZ{5C/Tjqcq]:SVD o\qa­؎ ְ씾my{~:'"c%vH~e&q=/>-XU!<|$Jku NZ󦻉ܞgm9oyD3Eh}2I6䡭\ОfoC/V]FU}6z!:JY TrPͼˏQq=T/~?Ϙw'7'H' ez#Ri=ؿM<CP#i| Y&goŴ( /d%] ib&$(j$ſNōZ p:&xd|w !Bf89r\4Ã[ ^r8cj?XbMȪjUqGLɂP!Sn  ]vqQؚhf;Ϙt,F31tBse)Qt;ɵ_KY~j) .<_*+; 4hP!{&GXhh@ 6Wc;vx Xs:SY[z͊paΰw>y #bS|5|[;L[]a3%&xha2Yb7бD}Jd*)u >l͍>r"]W T-gЂAeܖ'>['K̯/S+#\/Idɭoj1_0Ȣm2|^\`4^&FL!5 O S+!'ka?&ޒF (tmPV13]Fo@(ko$A329F~V neҊ2trS"r!a|J£[Q$f3L9173/bغm8w>c, V e`2[^mn5vfQgǰ$K 7I-K cJappA/N jt~x)Z;;_|z+žg\b(/lD`rS${Kz@^yےL֠>Χ=탉nɛ\R4g$|8\8k=FUM8b޶fR9a5y;#B*EW5;%6]I& ˁX/ Ol)o) }zj3S(Pֵ?L`KH՘Hz(/W:a蔐ΡF:S:;AAR83<=\ܹ+ 3Sـ6%TIvgzzx^B" AҺ06/u{.6si`‡3/1!+%}[B. 1\@ &~A3O8ALPKZڇ7.UOMU𦫍 7GK%N#K_@}0:v8[6N)Hx`:;$*6yu{>ݾ@uka_gہ-FVX5I ɔt6ߒI QvVop2,YZ R[Yq[:PI&/[_Ȥh1NL[}v E_l{ҷ{\mC ,Yއ/EN@*9(D"D0o/w /޷$AҘDmn#DG,A'TVMyxx~7M7E翌)-vl%X57 !Iކ_)緅S:׻D1 ̦9 9T:֠n7azbֽ]n_Zҙ*?R?ّi'v%IV^;Q9鴜j}sЙ-;d>l (nk:&0ʻ[g Yy$ 6\W_@Ni1k > B߯A N-ԦlYu +شЊH{ͩS.KϻO[̜H,Q [̵B:W3#-jJ3ײxӘ{ rĮNf,|'nx 'ZȲ-BN$<3ESО wq7Vm'pۯ9ccr_Q3 +o1T>?_jHA\-)'9=~L\r se Fx1_&kD_sM] Ki-OWVK 2.jOR׈s\ 2O68oqbYr =* >9vp-gdTwޅSZh)=QAK"kK-p,; cPƮN8ߩ|zs+0nԓ],-7 h=ua]om"b Ɲ[E0otI9R|9Q[@)O<#=J>q:gn5f}xge9i[4Mnz!+hCWd>S04e)m9?,ê61F%aISQth˻GNSDaڿ_cGA&|EV$кV%F,g)Rs U ʟ#V<)?nN lQIѠiJ/ϾR RtpE&# P2;/k`޸,V.ȼ27-U!`/h}vGX?TeV%Qa(W_V}ۇ + @B򿹩W;X7Lꯏ&^(_eq ъ;-= ˰bh*i1ܗV Q c}lٹ/uo@ˆ{B2R {WHAԊPMI_7Sk_,AAfj$~ÐYjBlr&In$:4$(`R_tXȫҤ8iL+߼#T]Qh'M|u''s\%SU5ձ%+7A{rNjO}hp 5R̕%Hj+v-?!\M8wfgY&в&p/ukQE޹ڈY"zƴCLo61VSK*9W;XP?sCS-1JGxh0: :fxqWPCLļsIƦj-*a4JΗK/m_P Ǜ2J.V֛iy]Zwq6w(hP3)_g4`%C+مQTWX0zo DǮxd/m/d}qԣy ԵQT]ںg5KNkjgvg shǗY3X>sRT&;R?[Ƒu}Pp=φ@%Petc$#5 *W=iuS(S ystVzd^Ğu<;Wg4xi (B#E^ALmgV'T> R`:~D(nӛ25VMyw?|1,D"4yݐ%EtV怤i [S)),;Z  7 ls|+I*h;nU)8 uY-]\nimѯlORSֶ=p_;;'򅹓c]eݟ׍Xu5t/2#Mlr_i,[F$qNtS~3rc.3*!5|O㖓uUYܱMpEkrgC VBwx_Ј٦MZ!S8ԕ5\ZhPਵ(CSv#2midU4lI~9qsŷ^~\vB>xC_DuYmfX'!V/tnzYrѧwF4M=Ƀ_|ֲJ# Oż mF K0;5\b#![9]Xb&Htw985!5DƎ0HW˟%玖bEs젋#O*%,'9gCTA)5yAe3ozӜJ5{OΙFK>5弩cmLҁ۳4Uf>:q$cckOs\Q ?>?d. MQ*[Z2xٝI]DcUP[]h#.:B#xЏ-W:dqRyDJ@#tr!axn.}lVb)S2>5D~.KI_jڍXр7Zn*$RxRd&#fTUu{,\K̔|JJӹ@/ʾfaAʄ'o-c?)(Fc4Hf<k_ eS9s/"q㖚)QDo{谜bՆd܃7 ҄rY*څ&5 Mώe:GFC?nØϿf6T FX9qvr0+œ_)tLD\\nW~&ד@G:)kAљa2cBJ[[2 !@[EHtXc`awbn@>t,=P >jhOZ=[Zbꈱ(wi1Hobp呝3IxC'}@Π\bBG .A 4=$pYܭPMFY!8s/›-m9^:vC7P?v08 =C#HZk:L7%4 ƇwT+\yAkjVX| M8ݡqg=՝{ L7׬- U)2Jّ9|;qg=6>+YT6@[nvw1Iyױ5Jm-Vw/Ĥ*J\?W;p , UQ[7Esv:4(}E:(rQ6xO{Q:/a >#/&71Ki@ 氫+'wAs~JwdJuT5\A. 1CyHBEwFHabCi!2k62]ST|3a #=9% gHl_3 U?(A"ٳeh2Kj!?jCsBЏ?eAzek/_7v^A%$.nүZz2Мin:Ҹ$㈶8Z1?z#^9`$Vb@UPY  ~\ЫjiC"UT~NNRwQ2H>DLN ~^ "QP"2I4ŸL[<Oe^U >6#P,YEӧC K0! UM $fIkL\zLa7w&HºɈbuPRӓuZ^ZW$KcH?9v t{kֲ5$ޞli]?Ac%owX=0]xu' (r v>ـq>ȫ%,?JxC=sU6CSBηLʱbe;|ͦ@Zx:1M\գlS1I -,5`0MҲDX B)=*UdMGZ$+Zk r*|xOqp'y4"j ZH;5M&f[17 @9 \kN 'YV?^,*4fÊ!V2pIPwRqb7rvs/Ũlkoqh1*\ n'~td%yT7q9}dPYl>k}5^8I>:M]݇If6{h48LթSYc7B7;.>r$O Sڏ>[䅦P}QRvRuk@2;C#9Tő{* 1 uwPfWNL Ws9mT7w'KMqZ_(de쓋]\Mu ]:C}e<7Isdj|wo|0 J?{dXӷ䪘 $eϩh0 Au# )EEL$~+,ۖQ`Eg 2!S>r -)@QR'|F?NV;!PŧbQjbiF0ANӼa-])@ ,d@jɫj(M2L f-Wyf ,Z47S?5PI]EΖ{eƈaڋʑ KZm2A hQ <Ƙf3v4)HgH}]F$)oz҂;Sl~T&pGm SX +|LV㌤(XijCŘj%Q'J8jK5< J"Qz%[ %e~S*bi?+~zXx~8vѽCvxG6Z{粷3S%zT2qqV0Hg>˧f ]Zf eR+/*>/讹ZXb5#]k͍곱&D)qg9U$hc뚮/Rim(Z;SDWb8._7+]2hh)$(7 LKb>\"ֈߺzAo Xyu!FȵqW폮(3m͝a@gl;u4׿:M\뢌FI[^$jħw¬uŘgnC!U5\FQw.;/0288Sc#K> mzhKj /Dj%}xZӦ'ڌ:t !: *8 Ǣx lh4hӈR}yx9I),t}qHl-P_9hx/'Hr^U>ͷK^ՃG ѐ> CEOnUhD]A$l #0=-6`6.|^V .Q-XNqwCFP5|LyN#`֐@Ax{vA@ ˢG^<-] B_ 6Ņ|"㒘&Y>DʽaX_Y&$O-<})4.٥Vgc_h`Jv2:,bg kFT/f#i)'=Oͯr;mܩ{"8xG_]{zFGپ#A~2窨섷]Ha-ۋpvWQGҦA[b#꿳l&q)#ZxyL1=Sw>ЅP3X:`ķf:0Go-cv܂ wnѩ{?‡li- WyF7%[}-{?ҙLyf;h5m˚L:j%? d5kvn)YXO\ƒ]&0BF2G%CєRh/7x*衳^A7>YTD_!JAʧi7hMB5 H`ɚBp,t2k2GbN#@tn.}a~?M4ާ<k-p`{Ĥ@.2hah!92* ּ^4%,go_dNF%͗6l  ݚn篶zhTO*rq2VNGpQhy(R]gW"Ѕ}xSom&)NC6s\8#_qaO4rWGgH:xH&o3Q( En34Q!9]۷z,&wvYcw".~~N^,6`-G_ma)ͫ(vS(bev=[+ݦ˛ܞOWUa#)DͪkʭWL?_2i-海L΄w-^s=qe`ǝv?S J5 {Nȶ\o:[ R=6L52}^yȼ d8Կ&4#A;T~1jv iI]` Vk}8޺[P;J-M%RoFGd$~zH^gN[iL$0)(G%FMṫ^V+V`P8^NzͤZÝG'3O"UCGsrw j@RsiH.z0mў= trI^cҬKJJIJMX.~QO~`'}"F"X+Rn?ï\}k7S(D qruGdxGؤ///RK[/B-~kɴ!pwh7ד 0/ٽ *A良ߓm-_}x'nfQBK ĶDT/VԤZY@.!Du;HՋGuTTdֹFMZ2_D-@g[l"I* LPQn~V;k歪. TXU3u8=H'h̨02@ \ "ZTC]jGp5AF$7<؊FXK#/: Ah+:wX_\9mB\(4 Df/߽IQѻ:@w ?fz1VN?1E#a'yF3O[NKdr{)$b/U*~dQzj*Q̄E9\90(w%S??AMcѴ&iqH^-JMM?&0C?c< .:WC?5"V츱;2, ,ך^*,sIeaNt4mxgQzX #tZS+̷]MD+TXK[??RL£O, Z@`˓k3Îbj3-5}rqJO~\*ܾ2b͟gH#9pt Id@U,!Q4{_J1Wշ#kΛ$3ms?2][Fԓ._,xx i$/N7<.8~6`ļ_z棳ق\_x^(bsɏ!D]4}~:0&XsHd=$ee969xA`X'r.^@i@80 ںG]j~cz> Lɏ"_?]qx_=JyI2h|{Q]}+18{,8 |G#EsRIQwJo8Ĺ()@4vjXEӧzI<t:IMMY3DT.uGAo2fǀTmm2o8{hk3uu4Fٱ\!F}c-[ANr8uߟu~3[ r")/쑈ĕS] λM*z$]&*U@( s1E/\k߿"RPd)vD\)ǿ}P,%xL1qFmC^@9:kj.+S!pTz2mwސ5(]Y5.DAT'"CP[O" 'oqJ| j*Laf%^N.+!(dF n|U&ߐl)e@ 0vB*#o\^-1 IG*3 LOh5.R7Gڻutl (`x?W* 2/`H @`!Ɗ{ ׉PV4PR+UԚ 劔H^h -c MoGu~[ϢzޓSmCS;"ٟ*Xq-g"=Vl $ڻm Gv̷='k~M}Lk9Xzu}dK_ꢛqKA4[uU&AHq{w,SK')>**j"KQ^ XPȖӜg$_C~Ձ߆^e%c&[laXKy5H|a/k;B^KfHXIRt෿3u+>`m8Jn:0#e϶5 ^r~7ILIa=8 kp>:7X$Rt0;^ʕg*-OSAkhqvuE[(2.n2cкRMBy5қ''}%9-(`>ץpo1>qz`w}.ݴ:l$l< JPv0iTgT%Jx.r\ }*\9{eݲfcx_sd8b][NN.s 'ͪp_DC7 A93?1A-_]΅iJrf0̧VtK]0P.+_?!.וTWo C@_LȒj羲VlkX]j}/OKʇTt]'//UCd`x:*PD|!_Xx*fzm3 U_Y-4\gEx2JV}XjOCNɼZal>Ax4WRZ+㨤h^J55-p"~6k,?J[8~VtRS0V:+h Bzcs6oge E<2iSTr5cS\|%ou+Y.4e KMP&6sm} 4%g?t[8{_G~}!PhKJ1002 AR݁ry}N0XMJfXK b.-"ūt+p\ SYuE6# hWxa%?RxX|>qWC^C,\wb$, y}*\\h%5ւ!$X8Ɨ`YhBW4!T,t%+?gntMw`6ƽԸ -% 6pκ|@?k{hM{"XCNJ YGӒ6JGvF`fħwH@8a. vZr F k:pgZk]lE|s1GeUaBkFί|dM`OWjX,{iT[)\(_Yn^춁4+|4h?r㴰^O.ٻE)0hyዖ-P} D fI wu 遼C]# [)x0G8F 7jøQz=Tj+ .hnEEMrojs,1_Ru?k( #JQɊ3<ٸ,l~1ZTBC>L}1I| 4L5$'&h3D"T3ўOC Rycwy e 96mr*G_΋PIْB8fX8Ooa 8#kP >7A%:D8ע>#36]H:c ,K3EaV~5jQ¦Z QQxv0;zr%"L_8OHO[9WAE:8 @2NhB_A83he U7>D5lbCo,YP5@\]VU~Fj_`_(cY2 J{ 8 u2n1̡Q$9>9g:A'"Ÿe6xa-K{P7ė⦰~񴫟 {&AU\pkfLчh韚4ʉtl`AF,8dH%I1|էW&U}='{n*N6"ާ02 ah5b0m-B\;Sy븴<)5!q4r{ GeMR0ArTz1$|0l|7"ƪmgIdK|P $16\C.W?^҂ 5Lcv9+(mzE#$;{$|e K{2AʲFB3ؘJ}O~~qrZ~ ?J<4:qRhGu9q{KA(fz<{*^tNE0}nT6;hy&{\"lCpjVޤB32Ph7iܻvQ08eCagAT?7I Yع5`Wܧ&Z `vѬ̲(Tt(,Ǿi9CjXaMtxcpuzg&$wWeĄsCxBGu=toc&[Ecuk>[?u["<b %|GfϾnc:8Pr1,ۦ{3?mY;umY3V՛~}Rlxm^V3]-p*\e4 _k|&&1nbِN#čD m[H5.䤥p=%d US'Z *Ė{FYcGA#AF^M >Y&OVjB`B<*!5v3 tdb0PV|,~_LRJ%Z:>gj~@<ئ'!ceV5?gP%"6H@f+,6Xl 5>d,)`O/pWD<,VC2e qő䨏FMoc@\6 A&7~aԂxNL6.vFOb2]%~diM"Wb- ڒOqx ,ErY@&Q]&Az!qVn/6&K&uTK@kERu ]0MqHMx74%Ze##{čtKMӈHf< `BG9{ {*[g;16˷xa!U2[[NjNߴ2E187ߋAVeM"Ȇ3vEpKd >=ؔ #G6?*NfNI_IZ6%T|GjRLKL'UtfUub\\"@Bg6: ~YHxyQ; JΫȺP32 ¯TK󬑞ߏ5=%@k@6A:gxoDvLT'g#Dcë' C`aFţy(2Xx5Jr_^gtç:Y&ı9(zsYAv0>axbxtХiJ(:1U=5P.!VXm:m!UlGăNJwO"k5̩ 4uy9ሀz%Uҁ֍y Е%CĽAklJ,pbKf[(FZeDb*;yꅧk}_,Avx|/tlFVpu*bJl"v@=t<ExBS:.q%K`|$U㳰]7tˈB/d4́߿)W6iaEY'ē'n3+Z=37ȇu ʼdz**gRPrv] w[>#Z#KoT)IG?ď Ph+HV3uPXs3OimCGEu-(=Z/32v5,H縳/p``fu+0ʮ1|ZvˬTb]d~ D[Q C^b֔,dOhܭ\׮)Te|:cn,Lm> K"E { #"Z`mJ\Ig}FM/re xi5ZևoZ I}Wg6l}&ڤNH ^ ^by;:^1J}XBz@R0'Z) ŕqQ^) :V}!Q˅K¬mwMX_Fn)F#CK!/0n)U]|^1"5ưўzzǏ x^Uʫ+O_xr|dpl9SL5:s,6Xơc#[s.dQ,&#X:7AֆAIACWlܔGʚfЊWz[h(yE{#{`;g6XU?"%hZ+5 o`.ȷ 'n4v"sؽ!}p0w_33j2:j1%H+xIw"-!6MS7+B8f(Z@1yǙAh[Ů{zkz)m,3cȖR3jπjh=UN=#1^~ 6JN =EoH]IWTfT "?6D ?z@wz y\Twu ,5Ф$߁E2-ER/*2461脧~TZx.k\91탖34WM?}40)3Y@˛tϩ$D"D #f}\$th ?@[_,as @nS=A_bP7 \/&1j${}Z/K^qe],(r@~a-heAqJ;)j x9_6+}Tt lJE\2*&x b_p0I uU/T1<1"Vˍy +UGq@kDlD j\HbUakHϫmߎf20\ : ~Ks3nlIFBqgAXOq+Kjws YQбB%Iq.KD/^/(\)Vۯ:Mk-R^{ SܴhtP ODŽT4y9q]~IwХc]_i-^|@!Wjɝ0I,#0f%+baFb0ư~vnqu5:_I ȺاA>/ \'dOt Zh SuIq4zQM2ĕ# P&!ZgMJ{k܉ewBTf~q lԧqyPw+a\9{7&6T`Ց:4LSo<`Z0CQwe캟:5p67s|.NfR8dc#}'X`QG50e3狩ゥ O+,6>ظ6S!9_j/F/w$^5M|h2]HTݞua0޺cGN o_t`ꌕ8+C8PhMO.yEzo)i$H#^Z_FPzLbͯ:-W]A2` ur kৌ&6tiWB7AR(N TDzmrur6$,:<#4UgߚHM%nUֹ [ &ηOrv%v%ܥSĀi<Ω=(ϋo,"}`wWb5 TQ0 4?/.>;m- 7K jrKӚ JXdvTOJ<,QGWH̐s#KwLZ95cJHOLgƧ"Cyu#bύЙVԓ{J/edlŮD>IlA /b;OAAg {.fg` '9;-r?_6 7c˺rӰ"5=u77CGtӤ~PiDe0B@AN+}<  b-K{ 8!rif韀`#'%7ߵcU3FHGwذ0cg]Ù9EܜBvB?C+VW,Όr&m,tJa]*GKKuIՒJ6Mb}D¾|d0jOpY"6Ǝ}UHᯟ:Y#CM64y 6png̗e)#4lͲy@d~8ߒ޸ޤg9|!f)kL%]cHgyMT% /Dם VDM͈٪eN`-~6od+)Wtr|/o6w~ Q5$2(HchV^㙀:X%Z((( `Vٵ!ly0,Nq//*(.;QuůN;9=̷}׉qòLԐ=>U?lGwpUx҆9j,1ȏ6ODNF~R≜Ր"kG#Cܱ"S(Q uC|/Fn.^4皁"B?mu`хҘb9kE`g/۱||JFs 2T̥ (/G=YuIuA'9PSإeatzRWY_kPPQ^x%_>:u| %  )S_-ܺ']Z>ݞ9MSU7#IS)ʦsd9)ɜ& @i-_匈-eAGŕoc'k]jї R.]Qr~æC{ VI*w ^^ŒmrcܓG$N/5gYӒ{XQ=Ypci2̽OآI,n՗EG/NiiutqP❣35A2pmij1!`6m>NNjB{(A _5`pIEVk$5 P3;z@:3 {+Ts% F 5n\I'vwN`Ԛk#`1N8rT;!2͎F >\O}T 8 -R47nG <x,r䢄D⫉eS:IH  eժ:?FYp@H'h »9XWʵ7Q^/=A*||` ꥯ{ƾgX:ز`%ٱnb]Iڝ0r\Ϟ1"4O`ԥtݪ7=ه12].>) [54W-1Mϗ>fs>UZz-W8SEWs-kqŊr8]YYcuFwDZCd) J;OR *HiI聘DWek*љk.3+!p6//L$6d!`5pXglxxZY"ñF3po[-KHƊ pӶ~V3BV`i *v]nji緤!Y1IR9ϥjz%Y;M_R9z0#ލ$K =uOpLZfWy`?],VSMWJcIs)#]Ƕ00AWPW/g]o)t$_)ީ3 OHNђN%O&qhT RR崝 ](M W=Okg17F R@CY&\݉񔤾kĈw( !߃%8'= i7F吰ԇⶱFN7 {uޓ,F FB:e':f(;cc̽0=!k@P0E@}24 Wѕ,}+;g㛞$i H1%*>] 1/̩zɍ3pWY"GV0,i!)A1G/bOtu'sb+ȉjM0Кހ 5pJle+!D_Klu}5]CYPkIÅt_MX(oO?U *]J"2WlfHB)@O:b+BӖm)*yzNyqQf:+x9=$*G*>!@Dqʞg7N%Q*mtL*ì`&ׂ:e;Μ"#EؿGDSUtgh7T<޲i[B淍|Rm/,xa~/`5 fIieB$aǹ!f;og;o20t0uzbN >[ h7o"TgT(nGa3b7IMBsK~4Od`DN:$Ga&WE6P +҂-_b@c~:}qr5?DDC))9c~&pZɬ5}CRW9!\Hӛ ;0EW'sQr;UW(ަ ::S*F|IVa, W99eڄMiU@t#㑩SL| ҒfsƶA͙  ɲMSmL`TH>vcÂUWث[ L1?* n\#^ ,=?,$<8ErSz(TM?6/oc:$^XL{{v'P7H]Ӯ ^gBM%u>tпQ-c-{m1i>ٖtQe1_:Y+ԩHHolVJI1e18m?e9SWV(_Т3׫sdA`s$e\ Cܐnِ.ǏY/F ,ON9,R,{gp!\] S ^MI.ا PWҢF ԧϿ5iĿ.K;ڈ@4MZ稳qڡ3ۑpPojok_]Ob|CTKNGw5ę o/0tn*OU.^0{#ɼʒ߅/F956cAG:|x] V*D˲ .ڠC*9nt I<]]v,*kDC7<1S|04#DG;\xlаJE=#&B|H87+ePR@C'w?,OQƕe1fk2GΣ.Pn\ؾz`*N=3]*]D2z޷L3EVWxnAפ^P4JfԊHΕL*qeql'塑gf,0W6Ez[QÎ E~|<YQ#IK'Kkj:~]iFЫuishx;+fJ&jfL<|Y9_(ÞtSQ/gWL#;_WڮXnyRbGd^Zw[F 1@ȼ'%!"Qs.9hpa$8TM p؆;u9 P!ʾW;̽Px2f>qoD425CgTl@ ӯ 5k%bD3@-D{̈5 h^r@~τZ[{G0ˊnk3ptZ=:_]I. ӯv.c$.p[Pۊ1Nv!!e n7!NȯA/3@NGG:E 5k9*ү.hMCuqμ~Rg0n 7\`iCg0 q&UAM~$);MF'1],bY][H\EGT6%̤4v)BφdO 3[˲AYYGcdPxp MKS`󍘙s\`H"ϡ匯F38uBu\ Unr3Oy\IuCu؅k}|..d=GV>FS*_q,W;əO3wiiDj9[sܝḫ<#}n3qu7]y*+޹G嗟rȺg K7ߏUBp*owLQ]Ųo=D5huc{OfOk }ꄇ%wXO[͐fq˧vjñۧPxsw>`7 rhPˎ# N:@0Ĺ{ ~} #~JYjᢦ WjB@mR^hSUCZ"ctLR#Yd ٻZ>Kh-|[ 2ꢮ~] A=iP" ¾馕;RsQWŷ{IOy ![\&?ͧAA;hI3PǙKWAXua.=^y6zejw 5U RoOk+$DY} 4E4EE;܎p{Ik_`tTKP9R^A9^gJ^tq1a!/WUDo;r-S&4sk凷K#.ʪ難W[>׉#*-X!x e(|9g fh(QCjyFiW5tFOy92 % ^ïj65\)IEI"#EGR3_@o#xHJ-DǬQ?^ח?Xd{]/ԉ؋1Z  EoGalfsv ܬ2CAin6&=;nSͬ9_A k8G/SMbBuPXyg/V Ka-EQؾ~ ЬQi_ pw¦ƒ5rlMwԓ<'nj+,y"L Di۶Fa0S3T&˘X_mLl#x3,q5Cz;)ˎc397OG`C@CsXz0-LhUMft&.#bCYls_dO/M\L6` RN/ ѱ4MIp#oz= v p|5OA [i1?oncyNlY<Nwl3-J9 7]@f=*?>l{0L}=VN#s <0 >"`V: =xu76>PI&s.X D ꘗ)_[{lШH&>$γdy p9pxtPDZ_2N5h<l]Dtxa?_U`<ԻCy].lF}U})E3z.92tQ:?zƮ:^J/i?q pYX70o:~|͹60Z=80chK^:|'P ].p3CȽ,Fz@cY?9&ILw:&tiOgV:7K pQlIQδ?pz_8/\LS|)@yL *OZ3-gL1ݧv}Hl{s#O!HE)MfQ e|~p{jpV ~zv?&DnAK~/yI|>)dg\}.].D9iKq?oYy).ʢ/,ʧP?wR[T[48_of(R-D%XKW+.vMZTm-_est춖Ovϒ!=tOz V lL9ӗmޏ{b^%w-uj1TVϣOGD_ LP.qa:,bw6q'7lQX<{+>q Gbb&qǂdgyUOj-F{kUu %gf vxe}&֓Heþd+FHGeW٫xHD@x#^io\:ɵ(LG`LG'sh':P:%0J㫱T? :6uyq2ϘU+rH}8ux+9,6>l2Lm~}=\eKQT] b7g0>}xlvIqkѭﬡT _/ۻ}ip x+ǬB߭ E2m l~B,^)\ȯQ-5o& ,Qo ҘkW Dg%I>&WP#FDD흫H*bc߂?eS'KYa}S]kr7٫ϋ'"#+lmՈv,1,=W,c䑠zV:&+US\~##9p ,Fѿ󯽎QX"fz s" 80pC!^JYx )RL|i  NF~yd_`뷋ZDý}a̓ڶ"ZS. g`tBڃ>&wA܍_;\evx;g~Ł>_ =U|vlT4ؽ);[[BbC B;G ,o֍Z-\<40 /ŶQ RM }{GbĶ=jf Bj1$ڪ,2.]8Y_! E{_K&E| ^@M(!ýyP^W{ H*a ?^7hq OBAl,Oc\>v7rN[%|{+NOӎөW%G]SۧY5[9.R]N0 ED? 2pˈDW|x{1B9 ^0|\Qe)dqwT0zy7;r 4ߥFD%8oy|_ 1F7 əBUw?5@Κꌡ\~|0 G\ NR!<]xxb:b Z`R66OmILmC.XC+^+[9skű6?7'C(Q[$+`,WQ_2-! M=VPa6Tt6;sË))d߈5( z˨8k:k ݂www \$;j~w ~P{%s]50 cCP BB\XMDK᪈#Jd O`s\.<US7i `I()PB( (B3wo}5 P'/>%h|o *KXO*kMqZmڢg,@~XKaSL.3,h^֫9/ir(j~IyhƿcTmO_(HuSM[H%n㻥'pbދ[II9Ve[Yy#2=jDE~$񐒶|pP 06XV'"e[T?HX ,S`Vk#|h{g߬cTn$I*h4| --(G[jf<[QcJ ˁKGUY?_=v ?4U%WOݔ,_ `Z;t̛i 8$UX.)~ݐGA.KqQ@=64Vl;d`' Z?[>ɷ) 5d؜~//ɜ˂lbT轻i;!*[#U,>auZwGۃþV@w&VlN:O[`$:f;GX܃&sP4U_vF,yK7m{A5n`6? \E*oԳT(>1D0[ξ^@9t2_O_{ϱG@4]D/߻UxAZ2j`q`VP)r7Do|~L$|qQ[l?,:Jk*=,w5Bi"#jzw{:$9N3ɞ%ion50`ŀb ĥsj=ˍ H5Y,ޥ-pR cCR)/ +p{s!@ YDQ"sEmⵔV᝱  9h,^)>?}V[B ;.N2ؐęko7:k։b,U/Ê(QOSPha:+} dS|Ae_2Р #KvZN$UU#)g64C qMX19t3|0^V/u:`ʴ3ŪfxЛ:7ʳlLi"A-g fL _U? sʱ݅)~|AE"pXzϗ*]|A8\KW?H*(h"< &y> n[-X̃p:g~oojc`Ce)ITog顑K+Id/ ǁ^n*f(Xy A(AR$F>-LWDŽ'bbK-̷(jYp`+0eks$Si|Xԝ$VM'obwѶjK)ojwfoLo;>(:'[bnjXTP8矨ET/r?iqx_' WEPR`6§Y/G 0ZT*?qOhyHU=u&I18se YK^` 7ٵЇϡ&XU*@@uߐuW8_.*>TEIab Rh{-eā@PzMJ&w& H;NC ]MBφ c7Px,Rl^ETmF b[k^?5pI,4 1܉dQeDUZ=;+MhxZGqI ohLdOg4 XQHհ_2Ej/oi7׋ytoj[)OkѮ̟8/vBݝi5z M}!_YuekT s9&o 1t9.qΜMaX #'ӣ&K>&m֔4ea~u\ARQG|VuD[c&B~|&x9}9oU==3:[lt_rjy2^%lB:#* ht8,?3+j(CdV\(E6і9rܝooo$h X(lna] w68Cqށ0M"ݝd g+4n [Nu;|1xV1L\o+w]9{+ , ;sBe+ k# %*ڏQ -ߒsH]K>9t0͡oVX7&jAwZ E?lk7߱bt܆L+c~ +Ɩ9#ԓ3bY=Q+w|vݑx&:{H!v(D4tnx2RQ)Sm$Ym5_iK}G>H:[eU5_zy+3fj3ֺt5^o8ns>ךR?ήP>FjF1Hqxه;S_-2f;Ug HԊE7.6#cYJ$[Ms:9-ΦqTAc{7[[>EX%Q4ZFYM)Et^O4A0sۛ 4EXVH>C=] BO<­nd;)TPmUׂ-*$Y| uH-ᲑI 0 Ć)-I˅ 0 {GD wyH<| vAT  C`v;+W uihd6})Tz~-Ǜ,W!<2|F* 4ӖF7(-;nAhD5N:F3x CB+۾"vEC(BTJz3;_oDfJ6vcw0j+K4?__ͬk x„*ﷅ:j|zIbgC!IqymvC !LYb i/Y],1JG<1 ]?/o8~mmB VnJRù|ұv<8-?d/#.zo}5[ܐr y?:! w9 ѢK@.&=O9b*I]+Ķ~zdJkҴ4h ,QG>s0 kiFw萱ԃJ#dV*3Mj΢OF?dz3 vYCч !s{ҹi-z+rUPp87!P&rMfK=PH]=&,(TG @F3I$J3^Noa [_ uLesR|\?l=j3fK 7»RyHZ"xC&KP5Fmeu.;$2W'h(JU UErrKC'.Yu"-1͌J?D}2PeL 닍|ēq)˅|xo4ɹ`Вþu`7|{+/ja)Yl7̨'M,ts|_4w~W Ťc$%Uq^G>G527xij>珀2B@v%X& ,(d+?|%KS}k$"gRQuvߋy?P{SM>1H-Z_W2cMqwr{ w5ӷQ, ޑaKzWFάǥԅGu=t%=X`Hy[3vꢈ0;L " ^'[yvޱ@m _PdSڛb! @U4Q*V !Z3+[8ğw;~rZ x>oICk;n!4> *3[Ί=j^4z!Kˤ|~1C@٤azQ4AhY,+sgO05χ$SW OF)P"..Qc~p 놬fpS*D M_Q*'<P|^JN(X !2ɈoC. Z .s;HxwT uTi?%`![Ae.2spVdDItӆyUεӨ }3]hXgx8A`= RK(Uk⊠-A^PZ;:~FS#6{Y>NG;t)dej歎a d˯˙'CtOJb+LYF>"9`WnUuTi.SUe\Y=*b!N.YUvɖ8^`)6$u?{0 i?B[=0^[Ns9P9ƴ3)CK$J]/Nۊ mުJD3ZGMt'6OL"J&/ʺ_و Fܷ[g`3BS*$ Bm}̻] xZR|PؗOJKBLCVQo^,h($+ɇJTU52"ǀ4~}-#<Û;@.58װ|% 6F$xƾV5"i/(]lII"Qp !,={cpR/tm/!3#@KvO~HϯK}V`t\f09 Oߤ1KCʮ95;j`u,AY@+O52L,ETњ 92{45I놵EQUwD:I.~Df /Z|~6V;O- M?%ĉb?Z3_Eqn+lGp\| S'O3[}8ΪkMvNqMфp9Yo [xU"8<<%34T魿gsrKV_|8]_OYL,L|,6gm;S?C=#bǶ*pKɩW$o5J$C`Uc3Ùrn#4P3vr- 90Up#~ZPC$` kH{a_~1[gZ|Drv_S!T"3tJge_{NHt Mq67vF.ͩC|bRr ]LoՀGdc J,;jXAVJCĆaqsz<1 ҫdP'ö| g }Wy?<j,}HK ^Vm D =ix:i?Ҕ!kS#Ġ۝8l8YiOUE;A/&YJ+/S=\BW"I%q;.Z2G`Uw'&)ndzNIX}sXP~DݞӥV xLyTm5!cbOHܛ^dƨ]("@g>.ǩjB=r ¢I $C@"#}<\S`1Y=a{mG#6ͬw@I)m'5Ĵ`7d@6JZmz;qL= kb{a4Un ,OHz %W3 ʗsViN_")#,/(|;4q ʥ~>eOҒ1OWD]I*=]9k*4;,6r6p3zLjp{X87磯AWl%Q%;zHYD҄#3НFy/۟;W1x%/>Y59i];LBe'qVd&j0yAeI/Eq]\#W[YEf,W<džXnM9޶+~ O{dE.3~n'aЊN·rc'O]c⢕Q pC V鹺ϚVZfw)jqTBJ]Mlı0B Y M}&|7{NX9Ys7:'3r wfB⯦8 tZR!s;KZpM̆?lVeKV_kPs?h>SXr'֧oOc B(«w+J}ny#Ro :(Mizh YjG~uhcZ5J̨"=F)ILyaz8^8h3!Whtݙh Wg* ;f#2!aHI EN!T2!ߟ5&U8L=z4}nT}g pLٞQ.ޯdN|f }yz.b}rۻ!ߝЦG&[ʔb𬾓w]dZ+ӣT:N R|Ѥ.MQlĞzYAVa )|I"WT"N}mj* N/Js_9%T5Jq2k41𝁖8M\yLUl:P50([cZd N *+QMI2#t&Q:R, ʓ2be)reJw;^טS*t(ڪPтl-űjN{׭:6ͣ?$edq8㪕>pP(`Ƿgjdf#ΨQ3߻<Ĵ_6e!E66 /4[QtyH!O UFZI:Q hRe3Bya ,=XJb%%~t#(& / Dj0> fp61 ޏFmf}?# a4ܺ'{xULJ|ࠌ& o! Π!|`{`LΝL:䶤ߑIߊ±rb'UiDwXNYQМ{T,4l>KJXחs!؝h Q0(,4Rxr\)҈mH~߶g lM~RgzBq[jbͪ ò 7(Sm$KˬO0f9! ؽBk/厄xalh"6&bv 4TQO%+<%zU*#KgCz$EY.f"q(7!"ͮ؟UʎǜX`65PF>%`~Qk=_Sg%{7?&5fNa JR~EߚITē9W[ʞbۉ; qu:fLka3zi~t!`3epj6Iw^()E;ô](hD@ sT_+lE_KPLeԋ_ScBvhbТ4GM0먃ahI(jmX";z3#$'2MerG^&}R`<\,: ~M&/W|h(ބLn@ +[7y6dm}FFROJJL"~gI<AT Og+GnL#;wb}4ħ,Ց/&e dSy9)bɞ +Vo"2y(*=,jy";oP:5LJ9Ġ Z\$ &m6DKzT("ο. >utC|tnv=|o#UnB\]KD,i>1(B %wՠ  ~#5ɔV!|ʙ^IX\ș FuoĹ5!_;x)lrk]¤"d!᧯ gyßN| zBMs]=zD< _sN}EmЃ/-0'%.%sYw(MokLh`qnT_,Hv^Z[VCrfHDGZcYZI+|$ݑ%}CyIpQSM-G ݇:.eKFx:K:m.d^d8yҺK7`jeL+%|f?pNEz+0/Wp?nUJ/;CNb {R'd %w%"- ђT"qsX7j%QjWB\N:;0 f-ZY~FB!V<}),4|&Oi@Txfn׎f?~ Jз{st9:JW> (5k/Q#-G 75*$7WbٮbG?FFlԇ`,{#Ѷi-Lp<(TiL"Pتϖ[J 6ܧ{Fs禟5~CkG$=C]+B:HL\%gG -۾o8ZLH%op@[0g͕`?Ϯǃ.qO\nuIg$/_dԵ[Fum2N#= ǻ?p>I}I4Sn/(v` qcVЍuXMG'1b4{};uzNJ>s?DȆ :-)}*JVAU,ފ pM`9\Wgkx/ ;ؐ^0!Kz$v_tcf!4Ɨ r|~< Sj%Ͷi=J|.X yQ*-9Noi>{$v) )N_hnLlLEUm~ e42\mjHob&tDÚ<$ih8lR5:zb >$n*|Yw(ֱڞ ]}Ԏ¿F<8(#\d4m@Qv.o/f6eRuɺPAc`4 ov0V],TڤOh~GYUl?0p^P4ˢ왲X>$3BJJ@?*Rkڀ)P^~OJDvmɶ mR):c~/?Wp`[KQ6/*oEs-Hٔ<[ze(p>^ :s(U(oFAu qu$zh9yiҥR{ņE $m2nrAq6К lG0LX{OO*ʤ%b_@M-E`{QFF}4z3 >loHQseVmZ]fĪ%#7U^˿hǸ)\`戟g`K\?ux](p,|ɩ'z';} I> IwQAle 7)ggq]:-TEvG@z)<"y SūmGMzYѯ3c&T+Tj4Ds$OMm, c?96EJnQɴ._J]~=PћSHWo +>+xIDUL?NљVV;@Uaf+)GoҵAwO] DqpGYw)׃Q~WXKAgO!yۃnWJjL`ŒG}~ClV?lG ) 50 RyŸdQUOAwffpH}'gB"] _l|/*YV?_[ %ʄ$\o<'ZݘU쳿ά õOx,HyCHu䡳W-߃%GLs':8'.Q:bU#t ǜBDBZP~z6oKYbՆtύX "RB V].E.j&42W 3Y^&( PPT=PDDFNb"++@f3~o2]Ԑѩe'+H#Tѩ4?S7}E(G"/6 ayWE疂Vx1ҤĢa3-$-ՄKVvF,x" 7KdÞ#gS}؟DdSoJr׻Pt*hcuj#u'WQm=&-﫨 T"مxDuaqEJ[W.RBįwߠ<e?3:B;bm?Fujlgb`%J 3bEvcׂ]{EPU!ZPo,f>KZ/YA@ Yf0ݛnm,`^t}:{(OMssHf힚WN%tF!´ǐPk[j:_pՓ$FL-dJΈd~A`7?9 #->)_,ipp=ݯUIc 6R`2GRjR]lޔhjRK_TGPbPXR\߶\d{EGnLF};Xkmwh_%^p5HiF SsDF* #GŘu"8?.peq|_n›(q5,"ݷqVUƠ%-Gm [$쯥7ySܩOs2O+9&9rʹ.!k b=X Vܯ]VJ>?8!XÌ)XJ<'2S (:= u;?J<ƄRPNCږ qtVr1׌ZB #ߢP6P/}5[Bt A RhIի@Fֈaq%DD1&"]y.nP^/* Su.[ڂ&.] d:X~](3p*r'd杳)gd(2lz_"u (Bt9V1LM(xz8P4{ )%G[DQY yhhC4MN%7N퉞r,߰`5&c5۳ގVBea)w6 7ΊQj.HJVՄ/a"X"l.i[h)|ԚYVnKK{geL?QR, 4c=֑-8uV|oD+{V{KHwO^)e00|p% &OL^?1;wkz:&O4M8 jo5ӭ>LjEdlvޮb:ewwP1JK{Ձ=ifǯ>|kn'}_Uwǎ}8Oi:jQ:ҦQX t/%0Gw8 V^N7lnƙ*=t߈^B?,T EH&_mn]x} )JQ=ZМ-ܾ| m9Etp:EGs-2 G(Oԅ%>TY\+*UKBntn\"C9c9EVWmMק@HI;_K w Y.\ FOfT^b58P-'}Zf6'}f*:JZT߻244e!8V@v0ZXO|U?c|lAj2C^( <g7sO"[Xw=QKCkO]RbE|+GmQm ;~/4/s{wAMLR{Dh6 Q\ "+b+eȉf6^چy (181?45d5/w`=6s p}l9KlmBABxwT$D((Ȱv)E3 Q?3})]Ua3 -'z3Iޥi^%tMgdfɌA90Ť! j2v\\ f~w|촗ʊ;9'**JC&KpN}n5'6U~շlG{_~݅i /i9ն;;Qia)PYDU^mb7>|2Un?$V";|bb-u׼*}՘ot|#oYKaA˺7W*k7곎WCZWT`G2͉G6\)ŭcd@DϜj+h3<]c=W[ӃbvZzr&O_oBjUNhlp,_[`F=,pFJDO>cL1 fQj>L9oWݝ5q1e/wn∋)NJP?f݊ NLk0+rH}IؾYFs#0vƆ4Mm[ZK=*I4kI/_q{ͽw7AWg^ ,dJiGD0M撔dFHAlIspop&# yk.(^ӿ MGer缰,yww`R;)E# f8ٓ+s6%D0kXRӀEfN\p_ p (nxԟL9 !ı`}n`ɕe\GO[f>ަEU>!rvv( ~VL?|6u瓶k uj22u_c9QT[Gظ ሢ0g].yJ9tק|ەm{!Dt D4tßk]E~bWo_sH`*mM%^nѷ͐@$? f9QdW6q߯.:."8KƒC{(3Ή 4>JT FAWo#vӽ4NTxoڋ aU/C.)娮WXSoVq?;R^]3^p!>@]_!BS\;S4/,cޝ./utH0fu O;zx}@|)^*{Y𼨼i9)y)yt-PK#j{e k_9"AtK#x٠RQVm[`/yz8ߐj 4}̄&gZ'9[ŭ.1Ԫb)ʗ RQSn^w BfXo$YEnoC_D5;6++ݩ_g 6- Q_$&L yNF,sNY=;#m#I7̶r/ :5g[8BAҬd8vI*elZ;apk/#,Z]O(ss<.ܡڡ* wa?n;֋ Nys~D?yэ`EB'i͐HB):mP;B0+R1xJ5kBqwwD<S\Eb*+ܪp.C:'oy5HX7l ){wYּK);){yt2 @& NUV$J{2J@՛Yy;@z3, saZ^[f̂{}Ρ^N lbϞ2I6ShO7v&}x>I{·#~q(w]bkJF!DHU1cZdG-8N{Q} D] n/ywBLVwRQh8.<ޝ]^!6#9tG(S=[T\u\J#z1^Q`#PʧWښfW 3ssoN]_|Qqc׹87yIer7qVso nğ4ulo!V,9E/f>`l#?=vvz9V+g T3n$Pk*66"OkDkn*^tBux_ t>'~FB0;!>'h\G=Sa!d/9f7*U d>y9T|&fOfOs/y;DE>hl:-G9<Bv+H.ʄ"AM)ړKeHHc5>~:n,Xb M̍Gi ->?4-|@PiΑS6Z!d/k^EjNB\p>VЊ.y3n?/Mß/2-cpWn}_$cG,]us jnoc^-zWz2% nnOIOhbmI^tGx΂ߙ5^fPel/6FֆXK+%g=8*Wi}e}3{lH7f#: bȼZa tx1",5&t՚ADDq7.M(9]!Y;LpHT:7꾜Ch.;j,.!Tc):So\7o6TE;D? JKbT:UvD|h^29 S`hۖB>SA*(L=r>zJ"%䯃B#.'׼:f/`5Tƺp mbc,+ vBK v"m3Q'+GͶəz[7=dTZnJ?l:bEPd~g#X/x,2eOJ}G^3ݴNޟh2t~.`lNHTJENN8E cj%u}HV$}`oXI+vf\F/|քi9yzd(Pn&i1g(n6^@ /;O\5Z9[EW\Qs \AeJBidPO ;B2M El9 ?.s݀"=B7at։$w|~(==@@q2s ⍑GhuBQ[·R g?G] Mh>\~n0 pEjax#X̒HUd#qu7vpHX KMnРPlFЉIZ. fhf?XYiL06@3AhH`%lfrTu.u!d}̂0PS icO:Sc&YǤyqлum?Z;pg\@?7`݁:R-t>rkd!YgN SFh<>H )D xqc%<dT|q&LSg𭱼5y{+EuBj.yyu Y ̙d˨gFSJZ4s4HH"q Tz 74S0w_==U2NzeO FjؖXR)zBf ̀`m4<1 ]!-@YR#3/&>9FV1ke۹/Pǁw= 2rBŇe4K&yCj9[e =P-+FmlX&{^T6K U%-sћ@!ٝex&3.%Qktý{&raGF4=*d2'xP7j o,c{% ^;oEțhSo,k2fm/2N,55RWq2p89Wm`wL:9r#<$@]b_qFY5dxp7Jtü!PP՟F@)kyc >̹!1|v`H,o]^גE-PVؗXA١um_5.a>x7=63(dmܩV0|,HɩjO*Qb+j[&4}M= ,85(Ž*{)2Jg{\V-C|i{T#JY/ #BWp jVmwLH:0nA䙺n̓H]{u[e[y^dO^iꥪj9N@ɭ2hh$7i5}}֯ydG62ygP: R/Gt Mx)Ykd?t 4.eX}okq|:j#dav;'Qf8WⲲ>y/cGDxE+oB{{^= ͢q[ZfTaeWsA&O eQ&bcI0}U|Mlj_McoxIs|'F]y` {wY2G^Fh{W饽F4xgR D[/hرޟ'1!qlza{sFtuQ,P3]58Av r+)ن5xx/}A2Nb2[n_\Ov&裂RAw8xx)u8S~8T[z*h[ .^4/N;{،FNM߭)*A~S~M&<5 Uڳ~D  !Υ)EC>MB[aroֈ_k'5Y*mJ_XʳJʹPNDJQ)%f8Lj@{IeQgQ3n<ț^+Wܫ6v韪ϙPG›\pƲJ} hpj𻲤 0ƺN`͖$O6q_N^Dt}wUMG t~&p)$&I> &3%Bf܊g)Q(Lufbdn]]̲ (i,_"Y6GS1 XSOvGջu9}'jL$ ' u,1bz@U&/eB< Q"`YCܸU,FQu_PpsB/egۣY?'0fK!2﷯sLhEx=l.ΉM$vICwDK?׿ gdVso0ԖxK?t҈Ecsr0R|tk_8P2b~LKA(xt+^)^ZpX4] S*"L W8z*Ѹ M5W3h:Igtk@ϧߔV$|] K>6t>s'lE4'(,-^ڳS{ ϙX,Q:WfLj}5>H<' GO8 _OHmZC[L],ѕԡ%d˲z@  :ק;'Ef9[(n,RY(=8ڙľTS@F,im]8(sRc7} 18yV*GsWws(}t@IP&%,O+ B BlkamYebGcXm:#Yg'݆`V299{GNXeG#h,#:ɠ,5L#G#}>,l[Y봼.0 ~Ϫ1^9ˆ:VωozrH Z5^,pJJaCN&Nņ6i;{&5%v4ND]qϿ q9Z/,k/ V=ŅIGWg0d)yǯʑo6 "WV}(O$f44> @~#LF_[H ]oVޑ%{FK։b ԛӦ7=Ewle6isr]7PŰI8Z 8*ۺ'O B;!  ݘoo~sw=LV䷈s7V _yGU( )oǷ#vՑ"w> ,Gbp  <M${Lˈy`J8ҝpc䐫3({w["/QÎ'Q@#M lV?N7NFΒwp-3ؗWj<kvLneK=)4|KefBn;kkE|< Lz"E띬)6h}wzGPq2A9(KvH1~ 4[Vh7ޭ6~#h^i(ީ7FkHߍ%JS鶸]Zþ@G&S#LRs_=~8M3R%/+BEM$<+j%:BF=w|3^H} ^+mԇt[Sf4Vr!\-aNpƄUzOEOǥܸ_d,+*hC:5Q=54b6y,)%A7>P57W5-Uߺz&fDu?0 S;<:3jy3lBEU:)'g"|aZtTCX|eá,ryk=7^Vk?+Oxk!j1|giϻaL.' ֥Y6+F7m|_ldg!NTiF )ѣZ.֛ocj eJO Jgtaq/+(Yqp5t^LQ 7S=A᪹۵"{!%®n_gW:V ȽFufp*8RtTX@K%^9ᥬ v ֣XocHپԇ9$ƙA0$ k |clpYs`קSU;脣R,_1inȑ8 8`;dBۤA{KW& f?!hkYĤw7?G 6#iN^Dv1L*B /ɤ & CoTH2pT7_ @O݂ QaY"I(.i̒ŰWJeo~4z=6>UZrRN,7 >> Fsi0v:< @yYwB A>=q?"_se}EU^f{#6/g#{8q_ݠ>/AdWpAY$Up*&[^I쨻>X74n3*M Փ4TX5'=T" 8@:x%-RrD)Cc4cԓ>G NV{ZG$o?~ozYzؠ;E8,R;]BO.B? }pU:0ҴwLP98po ]m #{|zG|ʾ{7\Rjt?q)gܛ>(8]"ϸ@X\ק-[c.)ُVN&v(ɕvN-4f%0^ﰉ bOC-U{A?#p̴][67iӤ~_bEfnCh~krk0[c8T^6t?Zud[غpBM+)KwHmG?ViH8Kc2oߝԡ0vkXԱ5^ "|̔ݑ$j6DgDFzksY Z+ַ&֖,Pسߣk<&k!68G6EB|U8_$G>ͨ.>H8k`U_{z=o+hʪ$i4gQ㧵ڠq\ؠ-X$&VS>VݲİÉ4A .t>Y}_QS쇰^He9cۓM.C :K9ՎC/k{Πaa#uSŀLs5U°dA 3,Q{#7x)[.|){cֿz3 PD$ ^BŎP)mX7.ᲗK,YiF=4(`B0zֱG|LW SA%+f]yT:t#-"1529dQ p癟+,Y`5f[# =2:4ˈ = 9jnDW/NQ3DDbY =&;Z+ 5Ƞ;b,HS^$LlOX'?xG&N_̂ 8)?+B鄚nK{x`[? U}!z٢`=!j&H ^EC݁G 2} &W!ЧYcBB7G8#%V YI8YV9wjO h"]dh(din8<%'dsXA2*0*_nx?{a׉_V10`MQy $I҇Q|Wi6 }qK6NϣvztHg ӎ21n3BO4(%ػhw@G@I[)CJAb[\?1@5Gß!`dw"(n:~³u*l%uQ>!z-.3㛐alP2JT>g $ psqd}po/ Ϣ79|w 4;;~䈣/4__"I Gf`5[>8y;H_ȌQLh/Z0^Cٝ'A@TboFQ~TY+֒l8E)gɝ+d)[5 ,!`GX߂Cdmn@:?y= pg9ϚbXO3΢~ntzm_ y4"P?iz cGeO|LƟU iXd4 |wO6ѨKΖy/:]lD5$s1ֳ6M4wIx?v>x6-7҃k df{'Z<rFXЗI La Ft|XV1rh@q hro9ق0)EHIycdi, c::y{Q}2*sO4>k&{yY a{YC;́h9M_Dn2]~>6&$ d Gзת(W4U3HLRfجopXm".-'h7:2pmPUA m fɺ(0,(mrUF^QLT`֤;P;I>FUTST6Tzl{;- CwwE{Z^SFh]U|ͳף,K-_eE!mm} 8 >{.+ORYz* ;Q:&pS5zɞ#?lx#Et\~in̜.nEzX<ZY0ժ̶!| X$s*nnr%P'E?TXR|!:2Ƥ5G)g-dWa!'U=RBb7i"kj;b&r$*)֊Bܗb 8n-{5í!iV1_Y}gj[+AXƼ/K%,J爫;gjA di>]Gqm6He:BrI]o c?H33ĸ?TupQj ~=ݷ$ r!t,͓n jKL.jûHc 5ɠ][FW:#(Rd5O>N[on | p6{F}卻B0OoU}ɾ?6-o-BoDwp7yϸZ7N.("= $j=޳J{ah({_B(}Jb &cBI?CTٙ2$RX4+]KԿqZm  u)kȾ bZ"|7 z]E[y|f}BTg{8:@V"j7`TƏ^qHVnX+ AT} ?p LnkgGjf{9zYQa"`?u2WgutVgD?R"/5@:ӧAa@&p;~t'-҃C=KLsR:>lб6t@ $1!X([-۫ѝ7\&+"$LLYMC#bp%}at*:ԂFU-sNPYx9W!lgoD^w2kaVWk]lFwV:$2y5|+{%33%qt|_[=m zjKPf7<=2 iAX%b:g+P A<- !"SZslczq2{pJ25鎺@Sa_I|}<:pwKowDZDX#, kY ٹg^`Ax ,b^W<7g r-dgiurFXg'Z||_MH#p ?'eςCV?" ?RiLhB OPc¤$sgn{{׌ Յ\bSkv4|DY P_0O%_f|?~Qu9~-So?~ڽhlQ?ݭ]o/(P*@pPs&trpÒ[q`JC n@sđkO}rhb3M1&hc֭S]iˡ8O/isLeKJ0yY+[&Y/ʏ*ϊ\2ӃSv EO='AQo\X|beyC+.zkOqvc/\5Q4! =H݂{BpwwMpwwww|ݻ]-(Rgw<Bqi+ܛaG~Ra L `BmƲլ&zbw%9V}ÛơjW6Z3Vm8̔)VeSGC{wRG,Wy]Gbn^f֨D](7_uvS{"Snۥv*04G7I7'a%Vf( JxE3*: Svvzm667熞uZM~*ifHblWOy>k^mh@Jι?@߽^:* yde~66OjB&5{OoX B,[eш=l ;3fJ1pL~c,xP~aQw ̋48s&nƪ5tG` (|swsQ+s;#7g^g$'R.ǿSf+ЙbyZpm)Z8ݹ;sĚ WrDaXcI ڍ`Bǵ[J`2v~%eEۣ࣭W@ƅݘKŁ>STAYׇ$U庢{ikǫ fƹ7E?r~ ۡ$\hΑ1v;=|i }VQ,uRBCw&<ۅFq1=K@vWusw -=Fy{A }*FvۭU# 7p$ac﹯]R]]yQ|]_rTfHqrk/\8[i,],,\@2F$A- 旴6_p]H$)\^}SWܜfN_50})4le&(˂ů\a]`xY*.4س,[~V5ؔ ϬpzS2Zi.4m =E`٩:?\vS41$4~:V3Mitmw#&k4WbUN~|$m)-m7,5PA1$] (ݥ' Q+4GfyQ\dQhۨrGǨmq~=k*= I՝߈j /\˾l`lr=tPgk4ݤ 6c;#mrqMhEք[-Fži@8q! юmJK+e5V~kۄmU 6YZcT޲ 0 u=duƴCĈN6hQ%,iF|}*A>H1H\B!c7x7#V.*$bC[b_G„5ddosG>!$[T9?5Ph5䙜1,H#ua؉^ c)Ě{y/kP[;QX\&Vt>wJ+8NubڦG^06 'Eޢ19p%𹫠p+SmZB'u̵:|!dזdoX UCZ_ܲ}o˚3qjOo efK9ͅjD^SE,0.5\؅39XWh")#tÜ̬zeN͈A+Te#vg?AJ5]Xg7TL3[%s[.јxH%T~ DZVzp6gyv2m\QaFU^;wQ.a[ |[Y~2qST*r-$F) +tB}pY\ްpy+jO\`Yj?w[xhd'|o̕7;U] w]c ںN()/&fM$ RagmrٮdnbA$N &MHS>[HgTW,yVi9 ge K 1HkWǸ,PIT3H8쀋$ IL%v4Z] 8 O6hζ{S{\waٷM yr 8Gt9+iÜLP"Jиwop7HM@#$³ÐpjWy%UlmRâݖ:ȇ NH^y ;:hmJYx)7ވ*sLZYpt݀z{Klrc2Cf[ C[yg@oO ;ۣ)go^1LWGoF(2gmEho!2Gi?4;m`/ ]: ósp/4Mװ3;D'UB ?F͵/$VdKn|K%!❽i_4^KE(Cdŷ'oP$5|۠QɆ\aQ^rtKzœ!QaV4xz?pM9mmv6dē[Iݜ]l.w681$Q*yWI.lOڐ5::%`݂l_{z <QЭ;Th*@uŝD2{߆l1^ 3z|hڐ`,w>zP%+F9ka pZy2 c˴ Vm $c}1.Ht K i cq?35EZ<ԍ$%9#N:z{bX_K#s,({CKMe+ L1Z_Xdw:?y {?f$RpR:c%CbiC˥`6BgM906u TyR#UR 냫gq!HUjA3b,tWoz>/*' >- md A.LІ\t|àP OpNyBljdır[5J.Q}{Bd9qz!sԴI׮ĉu|C37`pg][Q, J.*!0JY; iSf B釅kS1S1ӌm$eX<֌b͚M%-x)E>Qa'7gm X #?f\z/RlѼH\@!} .7mH$x/vb)Vzց֪UzTVރP*#|-&]pH_+ 08=a HzZ8՜!M4ҋ1mB1T< SGzh#Q/muaL*dS!rÏ~L2Ͱ h(őn8ʙ{.´]6Fq--ŏ6ѐ-vR>H5$Xіp1š//}9^Yz'2%ʾAGߠ泆DT l[Wڠ< &2E .9qlYS%prBdø (2Yq@'rc .!l G 7\KZ*.~rcA/-8ɞ!֓^FDt &}_Cfx}b1ZhlSo˓4G.EPDL?;U'tb })dˌ] yC1tDR'|<(rHgЗ,ۛw&Jzm8ImJDbHT |gTT6s66 \+Rom])~[ұL!вR\*@v ։\H *iEǗDPuޟZ^l;u9 (|S$ʯcQeG 6fAU0] ANIZ ĀSsγLas:2`k9O {,A0:HGl 1:Tsd[m\A-ft!;x=U%& oOJu3voLAF2mڇt IR1ԫUAm'Ҧ@D*Ҙ@H[ *ޯ|/Mm:4.+_pg㸯"u|H,`kL UWƫ@V@h֖M4UhN't!oa%'kh2ZT]/Ⱦaj6*|ɕAMO IbD:8TohB_2^@)ޏЧ I5y|N~| H&Rs%ZFXͿ̑9`T΢05M۷}N=2p7t{<=Kr¾TLhI ?1Q=) ,,5O +) dpJMrA -d/4iDЕ*_kf+kX5G34" /Y_oM@)zg _[RʋJ Pʎ(c GF=:'}K{J08(9;kZ)ʼn;Bv (> i?2$YI̠TE.l8Q)ˊ"bCc$I}6$ޗq%-Y {PYd|Ͽ;ܞyDlhL0Tp ue-KZ[*dd$Djt#eJXtUm;6`!!URV%ŪZG02uȯkOnFzm |84U{knk#(@YLye0Mt(]8l\fU c x*o^+lQOݦ cU,B"@J=ճ9vE'Mߟ &tS4))vrO dT#Z?ehН,#RyPn0'u,KZgk2襁ɺ{pF*ݜj)T cwei]рS /WUa'l4n_6 +yUo}6伡 "$5;]1GjԸw,Fhе(eTQ~JR+7ݥmZ " Kȼ!y, ph,Yb4GtoRսX [i᭣.~Rcmvg M(F7)g.\k<9KйbeEe{)u=3ǰ[AD7]nsוsY*V߉YZaW9hhaX;wTzZ@v0^+Ow4˲7;nܿ0 {\7f}\O2MWϤWN+n&axTQ8˹Z8m$潻;_} `iRd-|q}ˡRNqTz o: " q'sD~Ё}&||x{}6pTH{~nP.qkgO# k'tXwsKԛreHU7}կ4"0j5Ϟ2:\\8@K!4477߬X,iMe_L|'`R!Cy٤Ru1ZDcRƏN&?t\"ŷBς r̅NKLCTvnHfm6y\KPgt*z,!w(= Ԧ uI/6|QW09"͘0RJ4H%ƐZ/9 лC<=BZlSr}u#⽎NPXn[| K| iA4ɈjԺT9'RC܇_G$0C撩i-n(RQ`̖P"hZpQĺ1)} Ϙz_KḵuzA_"TӌU)JJ|˭ _޹k*6''H=K!Ġmj\260@q3%moV պԛ!:Ur=>ml:ظ,LږIj$Q_b¿¶>/3>m6 l&Z=y)v).j9k- zu4ؐ  ּ ,W=&֨  0dk2|j8N8s~2( G sp7T+Y4B|.<L XH@7?6\܊|v9%L]} xKnoʗ-߃ 0laNӁJQ%X  yU[*eIrJҹ!A| ,1*BYL(˂Bs[̢a1F^U9sIsV*ƍaV+[ąh9+Q-[.C 67d*cBB8JMƨk!f_.Wm '4vXwτg<-lǥ'ehCcZwJO .vRD)3-Q.`i S  !d2gVm& ʰ'_413h`4  ]`6(oUwe=6o t*jd/J0jE]Rڐ!ԄɅdX~#wvq J( K|mF) Pioo5YPJ"5$Z=-4bGO$i2@\*?խn|{r |U'{[F/3[eK/-1#J2GC+ Hڀ=k;_,K;wvRLA1<|cZEkU,B}5AB_gBF6kCrl6a@UF M2P>JIjc"Y+nyEDAĮ=x /3hA6,L HGOk *Z땟/}>.L?|k_mZOoz * J/R`,d.OB4%.@=gœ-0IgQRU * | 쭼s{+2{5 t6; >Ei.ÒI |>6rP"*Wy8箏@Y7-O")f\\lN};*RbSKOo5ujb3!id'޳eᘬ4Du"9gg&9ljҹxJr8all/q҂IOKIJc)NBH Etҋ9_JziՉ(1 ~5Ol;u_GlIڠ7uid|Qtd]e"pH:,0T4v9R@GH HuÒڇkրӽN嵭蛰?la.EvhVOic ƺRAWLә>g݁m6%şi,J6"~݆tBNE0u&$5autp3~G`J +HyԞ3pAd$;d}qЇ A[joQe$9Gr ,K; 1lBwҵbt1@A?F%Pw Pbcz>c3ԛ!r6bmvvuTh>sݨsCjKRV׵26.!_c^>T-ٜUĦ'YrHimpޜD,wM%3`5磄!@WOe_hpJ?K;nҳnPfl ^EͺMs;?wZ ;9 (nI $ (4;]WVugsE#X(gmZs^C(!GwC,~7j 7@d$M\bO'ܷqq.҂]1=rw8aG9WP@;Ψiv^fǕ|? =~i-fDR-fmV־SD8+1u[TsUŬ!}C;IKҩHŭLqX!h)t58yѡDJJ#)~O!/|=:RyZd-tF_7h)}9or:WN03CI -pso[{FӯY]^@5_O]K#=DmGFDLNfP#y Յ* ɖV-j4Z1w=iR@>qRBTKutFEV#GrdKmR<1Dv`F8}I6YK.hpw$0O-5Y5uepeKFf_T'௛0zySK \¨6zy7)p+Gv{0h>L@熓I/5\N;a*=Q魨ȚB;+JDGh^|1oQ& NqIAx[{ZOt=XEci`@?u>/iR0kxY&kwOMet`(4\*#9Ѩə0.`3Ũ F0D}-Xѻ%c! /loײ>سןN w-r dR;mCsHj~n[ڴ [DžlPQ&!uq,MwWsjg!rU#/wnAN[}lّMx4a~ӂ%)JU[.v^ gHSaH`b[׳k)`JC]c>Yp 'MSg8hXvkL{zIq8wF]SiYUFwMXvl^JtzSF5d[\KYj(dqU"Yn= !8`+vC_^6~#0Vs3ul5ɂ=t MkD/4hF_<5 [nC ܀d]-n@B;F[G^)-RĻ{h'N"EfN{N- ?Sk|$_łWYrY]2*Ԫ\ {&~Cؕx¸4[KgLv>6(QY CyJ`Q|Ek9I'b Dv05vgif!),/Ƶl[ԯLx(;`epp` |kv=|'VɖIk) AR[ d̈W;*5PԼ5gAk5D(7Ȗw2.-ؠT,m_aԾbIo`NoN,z5?;  H {'Xc1O>JťPn{]ʕ9P"(V QTl_R{|t' Aq~$c1퐡Q)T5B4'8fn|]U91~_XE ܽ NkrE^7L f>Xǥ!i(Ln/qzhѡ(Pe^S4Z(Jh3D 0BD! ayYSJ-Klωh;<6RD _tM,5cIsTvd@y <)pT?;:h|=GU޶Vi#\NYjJ|rjQfʜLyaq G~WG|tr5Dpms^?8r}͌x!#%!QB^>כ%ݫ-na{ίiYUNf+I~3QiOO|VVǡx>*niN)++ߙ<_!c$@+7umfeO(Uv_/TtBO'pg6*1Z*³S -ϣϤ 긦3:[/=nI| oP\? ԌRPTFM]M5?#7^FK54"& }soP>KLOQd&*]V 1r?\r]+1 w˄QĄv[h#uJ4f@ZʺlG|(]AĿsJ17喸`LG(ZѪ_`n(znQCoם7̩ 4WpgMd^p"BQ۩d_^2ytuZ%nevDB!## 8LX#48 _!?`O-Arh_#iLrJ1<]q,J!ЃQ~~bKT>1fs0/j9R)DZo!\f y(V옭r+&?8 ̷Qv/h;3Xl/oJ_^qcRr7yhrӘoL+l\'@a7yBr99Br:wr+'d1%g?dWvF;BzBz4﷥]sbJ,*,ɮ dWFSܱϾ]) ]KB0a^*\ׅ1'ʍirm O?mԠ[ ̩!Ӥ[eXl3!Y+!m+u'D@(Z8 k-fcfFv:ұH%)?:WXueFm=tk` =i\ 6ǫ;˞wS/>ƽc=G?JY*KjEАWmȿ_V=*ƃvU^x@"`oth9RYcfOWPpl9TY6QJh0MJ(]ܞm` IсK3gBtg`b:pUԄ,m"b9^Ɓ cD! Uyj?>dىXѡK\ poėwwr>}&smvN ՘qk + E<Ao홒 "DKy:#,_K&Plp 2SJ#$W6:evJ\`VuQO +]IB#qUx$в"&h9Ф|`wN/㮸Ї f,P^"r IiHrqCP*##&-vÑ9GYg ZmH/7/w& ƥ_[=Gp\gDw~"tl_vVWm5a1I㖸ƻ=`]Wi"YCe VkyhiFtm[ߕUH#F!rvNV u "ܑ#% q_/͘VaIxEJe86cu<9;F^W><2/Qar=B?JQ>mf gJ T1m;54; ͛>p"0&_PE%=8%޼G,^Z(a$)K#y%rԴ>^{0G"AqV|{x[, ~h%}t-p8z\Nj[{ l3Vs\~*{瓄iFvK2D }Ӓ8uBS rJuXNf\peH_SfMӾ-]⸽<{>yЈOREG!lHRZwn]HK:ԶʘtQ71)"GD"BG}?̅ ɆJn/DQN)3^[ D]| "pVL v@/wMj*ʀzkjt0jPۺ F~hyƠ ы{ kTU8i34QxfG_`*X>fr-q 6iZ+g7fԏwe7Tsq$X7f54 cRiH#~dM)͸.,$&^KiZ4tx&BF$h. }Ʌ1ȮfbDY*^0j϶/P;j*h@D%jG-<1."Gg!<pS :տ#Ѿ 9}|\YDT d\MxbV$O/ա(NMIJGT6f.vYU6TELHx(6YcAݫ{?zDϫuIpkQ-İB!k9o-^/` {idH0&Sg0V-a,f9VU/BdKKѻ\7d9,b?'mt88lZ9rͣ)i0Ov'.q=wcuyEDI"GlYnդ5\e?NěNð";yN݋/WY]G{ŇSЋN>y x) MM}c\jߡutmt5MA̵iq>^00|La?㬬TTZF6T2Z6BT :68 T68 4T܆6֒V<ff68_DutT&6VT&6:T<&V2ںTvںT2b8t4O١0?iy̡i_^M6M`WFZ%c)nBl2\rDF#B׾…Hag*o.̯Cz),_Zk5"q("jZ#z O0noQ?߭$`7:pj\3qecv=_=w44i^ſ3yw47|lqE[haѯaU:U[To+Tf($E_:ґ3 7D1a^ ]l7B{&EJ1I~\tn2,b?9ޘa=B"Ld, wRrW:ߴµ=ś:a4dpKP䲤Cv|h,t?6wB]kHB{u9 VuY*FިO' Jhq.e.kxw#T䰇AîJq='4!e~sr?u"kg⮒e6%Kjp4VhκNHE1)+ YO OZʛzyp]BbOrz~'k3ǫ#ܮ5p_+L<8r9쏯S^*F9)x:U[A=bxDRT&H_ q\k8+lDcSxF>k ⭱}nq@% pPT:bqWZOvMv-[v&+#$ U$3S-"2‹ہ,2*aS=vv+rm.&1s|J>ja⏊*Lt'Kڨ:NU~)sAu!5L{OT!6kbfm:X4ag s_Q1 ڗTpڐ`PDh/n`lׅF"Ó^?1#[s_ ! ONjShhk+!]"z+~l16V+(uyؙKrOf"G1Uc`#o gݫcH6au";"ȳwTM_>oԵQeM׸^J_vOoq`ͨ|/ђ@*9.#`p5 Y2]kQ M#ZۃEKV13l ?XyvlzgQ]\StͺɖUnVFƱ#U ̺vh-+6p1GL^P{:L~dTɲu D{q\=}׸_Ak`67ǒg60nq]-|py τ^EAAѪu692=Alc+?ND,5Cyd%لv}@ĝq5UE#2],m;sK}o n*Έ+BaX jOAFiʺNIP˗3{"NY8Z؉jK*"S8Hw*JEzaBa-RMocB_1D-s{YB6W5ش#2bAk%Y5BpLp=Ϸ Ū2BP~G;Nsyu-Y,53sEa R rS@'cb AY:]<'[_B?OX_Hv vPvƗQes|c"xKt8~P'O[&sX1 pBIQ7ئ/^{%QOW)l^}FV?^&bA2B>i(];l]\T^-E4YlVj0_)y :W毑,v?=vi[@WK@|:!60Q!YoY[lcukk-*?ϒNr{(a ;G_`ܚNm nd7lZ Wfd]֖\[gT0T@W$>|AW!5~tUcIV_u9Ofu^4nMN2XV ht%񇯬EH^07P0^ p; AJD5N"ƋsG|#,o)<6lPkgby i {@IhM$pp$PP= 3ǢclJlF"bfI׮lm <@ ĴH5tbdNizThW2%Py6l?#',W ./Ù)L`"\?]} hק53 *=!n B *c͊XE?Wj2IqtT& uՂ$C^4s9\0NFjݦC^-.ȤrD, R eXW6X&O& ? H&H~-V@Eff~a1Wۉ{АZ'`*O~Y襌k]o>sHRw(տQ7%JEװYŢ k8;-ȝ|LUi/ jZftX>qBS ,q 5d#}ÊСZ?ZTR\42碉3̈́x*sEƒNbm+n@g#|rvB~{` DPVH:z[s}]dٽD5KRgZ-Bu"7T&us H?< YJ-fE_ 33RejWx4a1<TM9iH0_IҀ6ma{:%c,7.b Py 'fegP0&$kf|i-#u S MqF ?t{ X mD@ 4;tǀx BCΝm?2T lnm8O?`J.qlKsR.ȿ{ V \&2G 6"#Loc7I_Ӱ BoC邁SO s؉/BYzK YYFh4Ș0~rvi,ULM8 !8:`FMpB%Bf ~%5IXQrI($6j;XVQ}=]Ā4P#\Cvft+C Cz 63 pz7SD.dQ_lsViipu^ 8 +UvJ&Z]?!f~9E۩Y]o^˃߇GC ;˔_ bg  %h7@߻?,oQN'`p kTJ/,@W _ cMktmEG"x:E ItOtT J#%@ՒK'©(_Oa8>:kS:A @Z˦E 8oqH#(vas ~1 c< IM&5dO|h<5]f碭{ML h]Tғ%,g8ϳ x/#0N/bdXx}[?筺CFb k$ P]nfD_l^/(cuCs`lOJN{:%xI =W(57@D|`u nlpHĿn_4+Y rf5LL`Ϸ_HdSLcgH*@/;u|]nQ% G?r.s$U PGs0Y L>QTDhHð>9B k;'©W!(72Sdh'm̗4L X3Ҁ] uS@A\4`Kzvf4Q 3)O> $Skv ?1 2@+V&`Vq`L&g~WZ{ @GGef ('EFF1V`77NRgwO M*'nJorMZ\+qHSpGq/ k?`vBCS`ęГ7C`u2F0 ?D l.pqMd j£s&AJeގ# #< >xݿV82#gaJ c[?)+1OXQUGGO?)11H >EZiW_[m./D XoÈD %]>"@:hZ`X%熮CSMCPJc3c%o?ZU/,گ| )ʣ ^ :fَS_g\Z>_ /s+Fl@'nm^D:\kL,Dt$PCɇw%ByH,J":LB *P/z .@پS'U 3joǟޙwi"#讚 gP5`Q[,hƛ < 2 />@Rxit+̻D*4JqUhu49~Ikl\S}`'C8P7C=+l8pg`-ceǏTx<UD/paFvUO6$ ڌ@4t@/_ܖ5bdG?@ ]kwSL*W6>;~+A Є:/ueJX{r +|yVƴ6p(;ג Z3_me .ӁSK IcJ^AUq ֿȈ/kRƓzbf bV$P>}aBWJeCDj7 pKm;(A_B D5ʿ$%1ԣw$TEEeܤ˷' oM;uq [aބʎL3/+EJW tmD/MDoO/BRDTxjT ̲*_M4(p>5Dj=&`g ?*eoثO/a~~rSNF؈`o"An tBA$vDr!_hKG% ֿY,;PY>n t=/{L9 w;CjmVCG?٪w8+*lA)މڽ y1W X`4!!@^ mA cKg?%-ݓƁ¨r8x?1m5j&jG/.(!`>V'vp+QbKl Pysef ã3v>,)ťoW6R _WzͩO2 h2(U)4 aveJ  ʓ?G`o'PZK*^&h) m?4S _AȮ'x@ێ7HǔZ4}2)*8<}= h h| _:Gj uzg^SBD!G,!qpچ7 lcַ*D=SloS0b3PۿD8h}.n ߡ.ELn[>o2JPH sQ\X[HXz`9rrqоrzoBYMuYxXα{+X$Ho0w>9w:3ẎrjխFi9ߵx]w0ٛγVbpf8=$#me#~O k"דn\$mˎE*fNEvsιػ3W2Qؽ*ݫ nFhM{7&μǘoCM8Qw~p޳v"Npj.˷ S_+\Y\(ޟ46s:-H`Z:]853FAȗju<,-Ŷ 0T,凢ݫǵtEn{ԷAvvZalsփ3ƇӗēD֮7`(8WHgnq{jyvU5kwUT/'}~O2:7`?-2 iZˑ4tU!{*K?|I1Cr!=~bJ{ۨfo^'~/Ob}/">WcƿvӬ^t{zޞup#)>)v(Qwh=ơeU1{[_cƷvM>ysYw!nyzNٯ^[8[ %ļ];5:{5ߗ:LV;ϱx$,]Kf0׸Q޴{zo\ػT/IH۫-VT0MJ0%w۳Y j6԰Nٻ&Z71#R8 8Xn/ۊL#^RbQe49ߨvWCd;E#=-\jt6 {WAWo!x0%l<6W*tQm#VTyR3XѠGo/4;/=k_piTkPT(^rjώrq=~Ӡ+qP}Q[kv_LzUoV jsXNkRϓ7\ئg5XlN nk\ؾT*dIt[Vڝ v))a IgP7ju555v{^ʓTjp'VldNwW|e0}ⱪXg6liuHgun>P$ )aC4οtZ̢HlԹQbw1lik@l-QPVZ 0BuPǻIK(̲#J?rSE߹NbV-T U4D^ۧ}:?cM!sVvteGvؽCZucw&Ϟ 'ʓaI|&e{$*r6TcRo ۖu<0ɤ9+U0=7ug-p7}Al"Jw\Q W0 u6nt.0v*U|:#vG)ǢSyR+$u a;+W7J" $ꓲ q_Og`L4GAEYzhu \o ]yɘ1zB' Ix77Dk lP@=pLwaqvE8y^GX3MT-%hl✃4VT/77.l"i)TN(ۢ3YM'[y׏VbZ q!,-5;?x%;–~~Tʥ vuUt0@a [ÛU92SU_?38zj.a=MT&SL1l''eޣahV_Ui@,sާ:yj[ÕJDBJOnu~ScؗQ ]UR7[B`&H}n&֋OM@0Hp$5o) ͩB&)ݻ O ,siLg \/\5̥!h^T*ænR뷅CH8Z=__΁J[_iF4([e K[Scp tί< hc(r 4CM=Hzc4ÊĤMLY3Db]AJm8Iw{k*ni絝4vlj5]Hc݊riP5.BsUp5uD)+TQ9g^ S TFq>F8A Vjܩ<8HaF]|?|WxUǮ$_z}j;价qCD:Wr9 wT p BqQW+B qW:I q~Wk֝5T gyu'1L4g1ʌOwb(Txdm+CLA1K*3JZ\9:MS-SM&J<w; \ׁ7]dh)Ո˷7AFE͋xJHzz m].[Ю!P7HN9ī.ζ,mQ7l)òMtkI {? z{5գV^3-q?* G OKQeq)o"?Cko-yG#Ep茿/р2h*ga5d/!?~gaC`F+4 ld`˟O38.Zo!?4 ޗ_}hw= ?42>4?kn{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{n{nylmQ%~ϒ0<7=7=7=7=7=7=7=7=7=7=7=7=7=7=7=7=7=7=7=7 GHwnէ (5_[ց?ʓ$Lwwwwwwwwwwwwwwwwwwwwo<1)g?3L̔Q=}_~V\QA7tGGCFS ).l)'1 ]]]Uء7/"G\sA*S0G2߀葶 r ΙMDwqZo &t?w ڿQ {-!!& M[JW:Im*)999ZP0XӻPGf``9W"j%$m u:!%s2%bg_!$΅"Y/3.4_lfa<ʉgЌAp j\lH:0  nGDj5QydpK-b j֌b-lvbCp |bTfg4Վ宔1JNF #!r_%wbd= 5S|HʃQR5+R@f-ƌ\PO_QZ e.p=N(v7vN 6YFX1:sm^\H'dȳK;gݎ<j'$Lj?~U}&.ԁ؀KfUKD(K"ţKuܟP5I~3PhAˆ୷|?AmWPHߴ0,`~]#SMuAMs4#Rk)o>j]-yH3:q\~Q=pƝ{Ns~X@+>QX~j6JWS/0 XAiB N_S*#!3E!Jxwf.|+ZSC4.7n[.I ,Jp~Eη}a-!?ٚ"Ԏ.A ajj|yY ]up~E 0ҵ S963n:'c9q"LMv0BGF|}PJ9ux rV)KEߛIubnÅIb昒196k,fHMd RKeޮŸQl [L*U)oJ`dɍ!lM NlMk#E n_;1],2wW|&E+~ņWJ{³kq#z;.DPIIT#Zw]jkq:'4"bX+ү̻\ȣΖB&i\ P™Š7%LCuZ"h?,B]P`r=2e`1nşٻ8e|&jԌW:_áaVη?֔VߖЄ+I[: ]Dr!Rd!ӫrrg@ZvdG^_q^`BS;tJH}܈ԎA\5m¢AcDŽPUix8J8 rU R8b  [hC%D=HN VTXRF]¶rQ=%QlU)"KR~e{т#o1) 4>ieЭW]iUK0|>6?GNaģmcc}'},(EM]S Ezui6 ̕sJX9Q&/OzϺ~8'@$sPr4Ɂç*:*f.f{)=U$\rLlʪ*6X۹A*C"i]F!gvvg)(įbЮ['Iv3ʼnjtH ZdsIāLA so" _l;Y,m6 ݈vwFy1'[Bp}6jv53hrjţ'CN!2=h:2˂ /(m-> v0*T^h v!dx/Y'+7dTf FI抣;wpҥύ{ ?([Ѣڮ ΈBO ,*2j;FcNYOv;_d tS ~0g7$󭣃:2ڋ-^0ee]ıjOWG]:5j2rQuyViqn-'`aFEeR8l8\\%0xӾ%ZbBgÚ8NJ60\i~>] +J/'>^Z_ ָSNX|3r8:;Wt@H,}IXf͘{4l[Fq<06.!&&&FYFprpN…HSD1Xnlldl^nd-ZynO-}ǥ#46({?yR*X|=ƂiYF[Ì6ViV'7-969iM`bזJ=]gSNZzjWJ43|?jۚYQ,oInɽ&SKm>?796#tp @M4^,J^S`fMz~J#"/R +7^u8Ϳͳ 36ΑE M8(Eyl-SoIV.CjKJ*!P}I4칎OM`?0`gJL}v.i_#I;#;zvKVGw'.&N&.fެ=X\-gZR1*ۋ.rO Xt&]Mq4r6!C!ѡ}F&ы-1,tPQ:WdP 1r6Nv>>>$rrrV3?^? '_f[CU{5Ӏ￈;ۿ'  ߇[de25OHy>??? '׿W?CEߠ.>?n6,A/ " ^h"3PUa7(8vE8A#_gA G ? OpJr/@iZݏ|O`ov¡w|G!r38(Q8Q@)~fA$&oў]|}}T>LC^k~O4)h@\kP/IG+owW=Ǐ)g8}aW|rJoZ}[D::ƞϞVӞOZEE<~=̣s c_}~|v$.s]ؚẃx/ kIl]#ڹ~i@l=NSR'{pgz_'f뭱k]=o=,HȆIŧW^Z.ǧfP,.Yf˔?JLm|U -|x1$h Dyu)EOD}}_s?J6gJ=;'.Vy6U{E}wPc= [f͢Bl?E"sIF1mL:h{& Vgs3vo> )&mS}NJBjRF6(Sf/s?vt\y1'9q[?b⳯ΊhifĊ}~cf÷wj['~wz18SF,*9mwZĪpF6n<v.Ҝ:C m:k1zǬ5a2 )d"qW`yL2H')yzRb|tbho2F~G^@踋+:BCo|lZ]?sXHo x+QJ䩄+7vl㜿'zY}#.{q(ׅ$Qk5x)g9JO?I<O G^$2/qf67dЈ7>c}+Ya@w*舓H)XqoĜB F WYe|B@4G= uAuX*>hg$=\%2|~OLIyVo0zvp6 )Q%م=*x5 l"aY@s|%u<* 雺P\EoE2lɡ0F6:@J'v5gt>FGK0љ_8IG/?Tf.-حOxV"؂7^=25."FN⍠fx8oJGFx n -9bU_ފ`{y ^A pމm^Spů黧M4ȨA86@Hwm sGWuFQ_ݻӼ>>V rY"MJkXݱsƮ ϐMNbxV_-ԏJ8Ǿd"Shު[Tk8k aָ Y_i~ofZ<ٮ|wyn=؇ #tc R:kqoۓ [ yGxSBR1Lz^MeE?5rTSK{gF "2KO,j*!+TNTabBȤf_;V`k>FܫmJnJ|&1a$ yy }7z/>:V"M1k`q+fJ{D*zBk{3cP8@N:](щߴ]bIO'JO $ws,*R?W!`?C3b;mXch  N&GJy+d&;/fZ˹3q6cZ\*/4(4si `?7 ȣc>\Qvf(ߦ5tP <~Wf[PrRlRI2$Wuu{3gbv(܋iMD;YKᛚBUzs84Q{ ML)y]+OlToK2,9 ;~A6q 7h-[!HDfF}j\H?g/MܫNnMET:K"H:OQp5VJ,Q`0|`s銼yeNKabxflKp8؍A5A ď"b, KM:&zI1ao 4ݠ Ig%a| W,54co3{MTBD-ʯDo 5wvvChGeJL&ON*N+ʧ-Ƒl>wh&.+*Y]n.'1$)deR/Xc o>q Y4[a3poAC@ďc H!\j)tGu9`m@iř}&YٳuӦ@Y{Gp_6Gzlm2ƪ\?Qte^OW#H?߁~Kmd5^\&fFTk5#;*iǩ>^DT??1 ~is^о2zQ39K8\EK=Xbb&*MZsݐ(,KH6qPmĽ5=U ĉ )A=ܗA,f㒹j8y[}fT bnZ36|A7uu`%WtAՌaN ǿ-%[ZL|~ph}E1p+"zgkO:ov5 x&: :*UdnqVPݑ(8Y=%&hsrT{`+D0Vԡ>Io%{.FBVAV?&%%Zi9ϩ&xq һ¼6bf<  D1j(8"ٱ<*Lw7 kMH'Kh}h6^҈a"!.} "]lb9yWf<[3F/@Afk&2^<"P5=+݁bJs)K{bk=KMثJ3G;brE %]Ą}e0jUtFחh옠r4$fa^<"nt9_Ԉ@l$rc(NobP~AߧǘqVʂFe`|,d_84egT u?BÀV!@W,⥡WF`^ NJm>lasݝHRVL^n0\U9u|ۯ{@ҙ-Lnkر8ݳS)i˳#Ÿ`d`\&ˀ%s}?)9[ş6]!yMz )8_2`.wlL 0.mx 83uD~8¸ֹ\X|Hq4ٶcM2rpI|D&NF/_Ef)N-#1A͈&B*>8 ˂|Ζ8Th(gF0َcjP^ƈ蟮f{"7D,F9}6x  &i"6JY gC7vD ASX0/K {7s\Z60K-ݫ!].@Qo_NUyy*헚+Av>L}m<̔)@Ϲ:Q1ƐFp<4Ȝ P4hPz4Rx]}<'.FIܷC\Mt+ǃDVi t# c] 4[s@jbG4EC`I]dPfg@݊UKSNނ}Uaηïv߱:BO9ra# =rv ̝v XLUMTT(~Kf;fg?poJnXjD)~+١#ϼs#eh9hdC\E9P1`*$oZ3:̳.Dw X?q&&ńȄQ]WGar=G_hq 78WvȲ$O\O3'Xv(k\<⋙[wѮr< f,dvmcZ4,0!B6cQwkW'6'ZWHFpDzm{> ,j "L;%8%Lv ]z/H.{afQX5)̛RO s)qS ) 4|E|}:r bUw=9\>MƬg>0{P.AWe)i iiWXwbp~O>b?rh2vc;Fdv xA^J w3ʗU+⃩,G=cl@. bL m3t7̇xw<3t)נhLZs~Rge)zK.OZ(Me I@X381Ǥs恞tP-DmZc-_i^S֚kfp9-7x\Q3ʓ7 %@o$!.텽,K^O P57NSq ?Ә2X3ʛysVF6-`9sR5m-K3l\J< dozvg& O dB gh'vMl2Ud56y<_cin1yxRl. . pIOR Ԧ:*=uԆK0Tc_Կ~*̓Gi&ִWQ2s;BiKN=+hߩ+҃FYQ!B/fS8a#(ݣReut) ;u+)&YTCF$KvOV7]jqG~ _p=AEӐ^R!5?b5L-n@('cgIAt狒ЮˢS?ۃCL^XCzpN-e_'$Y;d9{ͧD6/GGÞkjM'H3VTtsF*cRUӟL(,%,[BHb!KT/5)w[&8-+c`X_͎7WXt7:b)"VT,5yU9v̛"7a!FbO tRjfB*\oa8_˼C;0{۟MN$.Ϥ/Gl*tfK-)-?k/~]{h71K~ 有 aAt~C0OBwtl=]^O#0:D{V#Q^aIoq^Bn&`U_n 9aPx۫bjuArd) F[F)s>A2nO"2D;S sIݴI.]`zrSvЂZL,nf.bQc_5z6>%0!ɕ:gH\B`.!Fcگ @2H)Qd-Ak/w?Hdp^ϠeOW6YZݩ 9_0hBr{;]~N ~=jSP;9@Mcx#. ,Xfѫ25xxmt IѦ:0C/(rfޫN1cKe{6 gv|xl82 pZrJXfȨ-o*, kCqaLcB)>}ƭSL9{_[Z<<>vG \ƓjI*|U:!5J_{ .1ܭM d'pb6I߻;׬Rn?i(n&=^C;\J{62۟,`8My,R!{ +Ao ]KI9KLs4Kl{{ fػ)=x ernf~h};KԽzTxAŖa(Bۄ ѵkߥ$%6~й(Z@0gЩ6)X$o8/S\HEɎ+ͽc(}R%K 0ko= }bǧюW~p=v3@Q4I\Gn7L,Y'ា.MPtaזETa]Hn>`+vN"z<|FkbTNj>3Uj7딘*WmEC*k{|#>. ?>X`&aܶAk,tRߧ8 Q^7GPY"-_/P Dw}1ћ/`YʉWږ=qL4–hT$UbrO L/S)Q,x^~WXim5OaL5805w}sb{v-W#{,]FٹhָT l~]V1-ڟ~o*v?lWO{@EU$x|\#<#L6bemuEb=e}/1y ]T<K/~ @a ѐd{%fݪg+/AҀyG:.GO* 'd;䱍^Aº2?}I82L)1&uf{S*zk޴rbNJp_^e$I.A#oW PFŌh~5wChIM#:~ srQI-4)'O%Q¡+:Y>lq+4F{QQJ>sl{KHC*w*G /m2t᝜P 5 01KC>Y<ܷc>5D Ñd-ɈB7<XvmW󈷭kYP? %NR4sI9;ĩ%Ԏo:[&,&.O Gm8Yep<*2rOEz](ɜFg|,d.U5sf).ɲ>iZ WM=gKv"1j;n>(=,V<{y>N Z" ;!U.bX]WOCLYfx F̱+]Y ?,a=%[0LJw1AEg" wV p TyQLj3IgV0~r'U#\ Zebu}I|!gn ͈UDݚZaGh#[įHA|XJ:YEIjf˫y)UGX4L6q`m~gbj~Rr@"ІᮢF(in;T+#AUpDL ^߉'}ل}Ko6 ×aߌ\u rƻuwtli4A颯'5wqT6Ճ4dԿUG/k# H!T#?Ń%[lu0'fL 9r?/+n¹?ScB;^@K0srQڱLؘ{maJ:8qD sxAe[Z{nXAFc6qV9aS=1V+m|8^3 %ix99iQ x}Hӓш;'j^zPJ޽x+ Ae*q&.T,}LHҏ/>IKmݩV\bik3 (8@BWEG82_۷׹Ӥ^{ _A) I BޠD(l0rSMc&@UHh O2 Xfi yD¸YSbӲV !Gk)eU:xOf}0J( HB;pT/SBQ6h蓣ܕw+BQN# >b[UUc^¦F2Jn9H4͚Ƒc);?J+Fi]76N7Ӵxv}:P 1'3(A8\ZXRaYxm@˞)z| eC+*ln "|Vփpjv- (ޭ;~i[nbX9N{.jqw6 !kܢ 15#QfHOg=n-oOH UnJdH*8So9}s 3fpY 3zW%|ӖZbcGЙ ۞eֲNBAky*Q+#'B{8sL}4[Z[pD&R0븗^Q&W'~>YDʀs0 H~XB~W_*,?dM7n]m_ftqk\5S@_<[,d2/ʼ$Pn}-?*2m~4H.X9$԰8z7Hk1ri HBv_ lR] $\H jWBZng&#,-+1upERЙm4n"%Mq#ˁ[(5IZ|o?2l:cIDGFmd6m'ůQ&JXsXQӷ-H!(3pM{#vIu{'$W-O/ JxjFap!zyF1f". P{y 0;ΈWyQܪOZ*D?ޞe"ex`jj~?g`m08-aL pы:ӎ'K̋]ey3ӵxBh#HS#')3K/@ȼ)*,,JB! Tr#Ӯ:6AL@@p2t bc`bh{=-%`Ҳ:h抳z6o=MBEfle0|CWM/}.װ$#%P$tGJ6{әΠ|Z!Eyن $Y]kA3ܱX2**YsmgZ2C!Dw9Ƿ B[!0s;Ϙ@Dߑ&щgAda~]Ώ IXfE-{/I;e M`iNjїӯ=3"k}|ΙW KӋ PP'fo:iҿXb@ ya_/g|FW TwG<3x;+PN0elt_ ~, UùK' Tҥ ! ,b |ZV<@RûGDm"`4puHj\_ _$]䇴OJn&%}GVٌ)=}*E7*ga?|Á-3daЍXT|G/UT1Ud`ZaYRm,yˬ1mX[XKQ<־%}i'*f_~`K`Wʍ!؉G<Έ`X"b$BcXJ MX|(AQYa.0@lUJ^d2P՗G !y?sѤ2 ^tte1 EObΟ7,ikJ~a?96W֍;ex5 IOɖr*{!AZь|lq6 R^>zcU鵀 i#MYϸ Rx8G49)6ɰk`#s}:{& nQoBҁLv^Y gg`~>]qR՜}iE ѺYZwoә#Edϋ߹4;?*|J%*O->ŶROH֐&&~(mCc]-ְMo6/U91ip3i3[?Io/7ƃoG*ԗrFh\e̜|ksP(B*L6jqzQ-͂}Բkr37}Տ7eӒYK~y]'r #5I[Fތ^y6suzӟi5sݷ,$ sǴlJϼ2VڍXh~i0sqJЌ8k˦xa+EF@͟[q]ܚgp 6>5'yk59>dޗCbѮ8_F5yhY}Q;7R̒~ڨ 7?6Fa䯝}6I^`L]V?K޵LSڴ#8'qs>J5Cv{zXcR2ypQhR7hFqlꤜ_M 4v4}Q* _@,씲 0q=| KΉ CzP ~!TrL O{nvh3Zd3^y$}%F1hZCtZʰ ,S\f fUg;Z ǘF2F")jOipX?#nNtkiawK{w&OR 0&{;qc ; ꐐW{}:wWM|pD[RC<ť 2mZoM,B)9#E߹< _\0) Q;{xм PXh{7錒w2>j AW,C !w.Ȓ,JX-~n *ZؽYZQfkoq3L,gHK3rg%`^7QXFb }U# NZYD_dR%&0Y%wi>e67~ڧ2}4;JmE5ja3] ss1"QVgJ$("2ce> b-dkZ&)a4,qgY Hpw&^P/6 0@cnW}YW8"=q'fX0B]d1yaV(׶p0Vj\̊"װ8FB>b?剺ut =0F;O~l+vf-LWr0B48>Lh"hV$Gl)Y[c]ɲ?:s|Ig!IqH>G9.;"%@aDa8#2Үi6HF|,VQ1!\Y Gni}a%ݺo"J<9&Ф,prH1!AQ'44 Sy3h2dM3\xlz{mSޕPCkvޜj{ᇸWr|mfݚ7).qK8}[RL#lR?O\LNui2ݒj{t5ʵ -[ e^^A0rƌ{&-ƞqnqd^e q5#"~15ϭ) Ȉ&d>w> ȝ'o,\JB18ON:[[Kq r&9O!kP]Lca ӟd^C]U͗h{2cwI-ZM9^"=7YތuwÆ{^9φ,={>.V:0h.g}Q|vXjȩYqBޡ8'0Uzf q)q h&;Y]4l6B`7Oz0^7oFneRybJ1 V޶=~Ԧ 5Ҍ0rkk)&1o(AJ%b &/B.ZM>5ifAc/]MzEO=Ƒ 2ql÷Ѷ{ tgJs>zӰ )(r]ju| /kJ&E$}IVO lChZء(9&4˄FEB-&*Wcq1;:fU?ujĽi@J(IڊjcGMRQcZ:-ǁ ͆"(:Brf^QTz\t6Z;}؃xZTV9j/KrbHc-‡םq/:" SS%)Oko{5+P#JF>"lbCYDȬxJQ2Y3N[@vLHۆ&yB+h͸^^=8! -^R>O;dxbJ-x@GkFTnL{55WI A|eqLjGۀTAEY)@3NY:6&~<͖bE7}tk!ha92z.#M60vaDR!9Y0nu/ |8&iH 'oOD="/qn$(4EI^h(GS}U%!(֍Ή̦'J**3iN3%dpE٠QƔU3H)H3hWտrb}R؋gOq&DiSQ>n!ؽ;(%'?>~kt7-FҌq. Ul8&<[ D&ZͥzbyiXvZH`m:tGGR;M{h/)5_;(H7n쳓? (:ZYKgȟk7IpS5G&DS4Rq+Q#.s)J0gJє^*_3݈ʄIz\ֲ B}.ý9MP)l̝ T]"Sh\mpOD;';3ciT _%2դ}_2q㗏U@!r̪D/Q^f>ӊK}JVnecʏim7v4T,]Dgl7m⍣~y\KsLI-VE?4]6.B>9)V=UJ}X_Gn\. `>>D/ Dmf~tyBD/OhcMk$*$LA= Pu|  z?$|f)=m vLzG>UmGS30E:\.5u6Ŋw~`9[La- ׵fXqN-ڭM2VWKY%5*MK[2)~:,ϓ"ER;pa3f4=4Dl%1)c2N Q.`.GӑzI9̷<9͊jHxV˩]ƽB+b~Wo'Ά,w ŽT5 4̓~vy^Ihkg[0n=D2 6|CB۾ɠR+>$R;>:m9&OW"ǰ 5u*%8yRy39_nDZY@IJf,i4D~vqS]5QH[hZҐ/R7).!=_xJ/鰛/K_ʷ\f`Ζ>!}(HS.qn\Q ﵪW }+E{ժNQy] s)wB{ E 4#)t=yJ7Qy]M]kw/CRu!.y"µE/A'$J{|܍wT@;ݙĚN}̻Ŵ5оM Qaymwצi'ANRdLNf< 1;p|3mR{D/W.t}* R۞&H4~-y8<#NQ.u85;# ۼ=ŻaԒ/|в]ܷ?.hkkKP*+(i jjbsX" GC8ǻzȽS씴PSQB7~e$(aeklC <׎ }V`Ӷq:+{Rs:)Polp3Jk"s jlx#O5\>K7A.1pnoT$ӱQniqRt:b2c2dBP)M,UE/a:fF# 87u(+o0tp.?E Es填iI@8ZM^a,6 /U%o""cB2?ߌmW@ыRh!]FKTc# RˍM1~*fkB QS0G:ȃn/.< PX0hL7ݤE {䈂Wj o>^<ؐEF_-|'nޞ;q?زhU=W)J䗪 k{FeF_<@f,rY0hzQu%^8/ώC#4aNn"VURt}(: g^)%Ӹ*pZz G^EvC_I8\,aS4A.P2.λR@=E 8=)y mF7R/ծ#  (Mf"Mz|~d8$/G_8 m+=)_`A7kϐQA7!/@4Y22XfcfzhٔVij/b= uTVb\F ۍDYRm> 4c$8)K>cA̩$UUYL ![ںHN& n0yTb$`T 1'M`?a$vF6WP&32;Z=M[*̯¸JG+ ,C|pڋCl5:w cC< {zO9]wSeV#~iϥ#`p)d',)LNr{[ _ME`lzˎy</TaFO;~ TItXcĝ.5({QGOUz>9wx2i݇xi#i`ܭwQxEPgPޢ]4}jXıB3`v irKſr(XEx,tdEuy:Ia:Uj&~(Un[Кp} KO P.;[KtDRx57K<l94ѓeBԫ}G+llp4#1 rB=i<,^#2c53%{2X^d% Z| Hy[ Z5BjB^f9!\u&9+-<)QQI?T=TY UB;w+m a8ϟR*.=_o~Y̋/} y7(8%"|}L,yxbdHourt |z6vs޷عzxzݷTv ~8c}m%9yxy:jğj_{~ԑ胿[}V!%r9ܺ6Ѽ>|rH4ud2 ~}?ه(Ӽ"cULRhIuKfA{!6pJ$XuiqwGOl!tqV׉/4iLΩRl'@/#XtgxLx# ]J773%Caq*ӊ3xjRLA0-n-GW~}䩳% dΪ+? k*>qZ3;7Ny[6+Hm! 4JCC^~>ֹmehAFf*unLG~ۗgl~!t;oNloLHAqDԜU׾]725ZIMإ)4""tfwLvC `Zx)=^\Ax}N)paTeje d"6m&~[ ج4Ewb{T| 7q@[N 5H5 5~ya< ^[A㥍Qu.0\l8 K]߱l/8(7OaT AQlɃ9#gxGf-NR* 4'o?j߾M#"?r W^ s6mp7 z}LuS}c&|щߨjH mGI+Ak+a4&qG8|eqKb2*|獿;_W Vx&Iѽ n 'U]4_11W8{E}'~jQp{%_gjoYz n"ն{L,ֶ?15S@ -s·f[\A$P8P8\7aEw眭A/~ ohS:jy Pؾa-!oN@s\jYԬǙG { 6h^ |E%A.-e҅Tnf/6Y qMfpmMF#lu\N,Nq!oZjU/o:X}'r^nͣp|&tB^=⽬(:v|"KЉR+S7ߢhaޓ3n|u+vۂ~1{8"-*4FA{X>l &8J m~7"d,уD3ߘ=yL\V_أMxkԷ~e(-1Jov>ٴ| [n9{"\ -Hcax^)q_R=nËpAs;`C 4pY˴H^].~LWs }lfc/`| xNiԶކ%FK'(hyWȘ:+?pQ=]#(㼱8=chYgHWpmT=d>m;ʷ+l3fx;˯547֖?+|I=#4+]6|Jc*ؾޔRØYڪJL>B~XNR~"}: K]yvXt^ u!aEl;V}[NQIxa~LuI(au FAlq2Vu!üʓ9V1n5X0. ,<xKުw& \vҚ) p"#Ʌ ՆmJѦ1زlN7UnзqkJ)yN?zmVJ'4w4Qs'0vׁ7Ҫ`}F /A0iOaiBu8:O^컉 Ʊ‹G,R1j<2V3v\_X9DyǗ8e7 ?5cF+$(~nۅ!/mB Ur x*:܋bs*I97؛9b?F}KSXk8@vTr o`j q(MGis\Co'ˠ>_a*V"e)Qi0-ّK>B}/_z,gw5 YOXxVטITv‰_ݮMǬGS<5ߥ,uz,dW7~q;4-;!15;*նiK׊(ް{Tu)`M`sN_NĕR@SkψʖB%2y;iqtpܓnv*i u(nsL ֳ8Kʿs/t9q5>MJ\JM&0Q\wk%q&IVh>3'wr\A{&^~zp^*qKv&}г[5֦1G/K[{VpuhMk;v o~s׵WzP{Վ'2"Ch-JYG\ϙ4I.]_ڳd@ѳ~+TD o氶 [Y$8[K]b3]2y0n+_徝ehn;>OYŽP鰗|8ۊ0pr# UdiC=R2$0UF̶{gTp$]NS/x9r1°7?R"?f(,8Ic]xSTdOF#ǛmEb[ TFiĤ2v{9IRUײφ`~߆QZrv~u)X9d՞.^jF:<c)U Qx Nx@ TҒ>oDej<=A8hu*[5qvLd<a[Ԧɥu.@,PԤ[GEK,)HK=rlr"+cczm .E__՗.BS<ټ];8^i4֤XN)**IA E A w.vƣի H߹oߊJ8o\gU:#w? 49>lYY}ׯ(yH}w _j"Wpw"^_37o7s9^Ls\bRd:|i GG5%!]TQ*1DCW􏦀?JY왲í]~1-??vXkcCee]!V)~ZXXd;MUOl@uOr~/~ B^;vƤucy/chm+'@¿hMKeVW:nGd w=A3qMq³^9ߛYp2@4arxd >oU՘HĻD:t*vkfN[2ʒPYQ@ d"Yx!vUBmNN1 2pKEdĥN1[a=Ry|>2F?Y6JC&v4Fv3 Ha1q jn8GNǨKa!+;kc4{;Ivd(R~ܥ'q,fuͲo}=^k/fੜS %uş냃ķ1OA>oe3R+qP mrQ@v'|1ZXmۛhNǎQֹ%JШy!J֟SrGgHcEPHyD4U*_iGi^ǯV-wa2qYwĀ[TXTx o9'2i;XO %t*{OaԜ'0.~;nɈPDKVBR4^|1["R Zфd`UPׇu.75*$CR@U>8s_8Ab ِ+yFP6Li:kn,O['JfJ6o_hwɸ.uHC9d[A3I|epOgΒHq@Ο8MHQoԙZd/YɓY^4n@x5 9!D*oT=v`HYՎ q,$7R&kn' `蘌a+.Vf.m %AQ <,'ObDפW/.TiBPRǠF?)3$AFUf*5_0؏JՀ,'ÿکׄV! 8M?ݽpf+;Ep߱*uN6 LBX:D])$e>*7{~#fl G8L\CC8$b~ڿޛr䤱$Y&8vPg#ELIբ [f\Mf#IqbJP [\d꟪G!.P`!=[9v.V.p*=~"*4^ȳZA`\ Eш+#^ApO^m/^ |$7Yps}܁!LW0^Ycy"ɟ;+}{HJY\;J_H6h$Ð=+?I<*_%!0(OuOC,1~unfC]šReܭxگ-XI 8qfҹ.`e[֯j_E58&Lky&heT*{5M>_T# XEGZWbQOwWbŭi3RgD H4NPsa!q!;YGe w"$ I `5s7b~iͲ9d:O#o {~HĂ)VSjKRFsϻ(0A'MjfeV`:2\ $1,vh\[3ט |"5L5bF#(U^Jb( ՞>7)6m tk$uj8:sabsw<_h{"C>æ\0`VLS([g&F+ Mb -<}r=#Jъ;wj=H\GϴKp"*K={ 9ICQ )FzW=J )6`{}t)|665E?˧ϷLC؆P[]],LL|U^2hW؇-phv( 2br7{6`BDNoJZO5ba@`IZߌ1Ko&NGӻb )@?Ԩ b~CCDWq>`5 !_ZY4KQܕ<%Qy=пt};`^ = +U.4eh&$T<"2%F|=5e 2)8'H(MX2ƔJ'_jH{ ⾬E"Xښ"£ښQ?Qp&! Ŭs29!TV \!o-ODBmD16瘸Q;/΄ژ+3 BHĔ?/ AdfgIw=XT+$CWA3ݎ>ukjZx@5m;u\reFU ] {CPEKfC92eV9ђcDik}[D#l($T J M tpCA '%,}7+r*w}aP Y/ Y}5E$- K!z>?jlFzTPbX>SjcP>jn#|GK ԓ ١ӊ?  @UwɲMc1p[sܔ%@ߧTLIf;MRܹ2HM6j>}s[ P91?8EpKp@n 1'֐YR-u^UPὄ8y@,;&MP#'ف[ABp (># wl UրHX s- {l˱$ʎxКO l(Y8:$ V}d06_zI:-@eC%kTsyI@CyvJ+p(bm;ݏEya>j{(Uj&?^)ATN9Ґ+n曜zY&S[B1fA&qzF/76Kp"izdv"U1͕RCA.N6۶[0Dk V};|Uc0}\1Ϳ|w -e'sgy|>*2@ÉOY ≱i~u-c+vIJߟA99N,sd5ɣ)/1v3H cTvpcb6J&nE9DL'4RoD(yYߌÌ~)T NOYæ M}yMhyNDuմRn}5wiju|[NZz=vaND'oB|<޹8 r3Z/qQ ]k\-pzZ7} ٔ6 +QdUK4 =ZsY9C=/|Pu&XL>ꚴ]X'=V}sUbt4hIi%ICL̋2 U$yMin\GJǴi$y UhbFW ڶ~q#5,%q1Q9Io8ʠ?<+"z"߹p_,'mXO,M?Q\ Xy yc?5x?K\ryYK WyB*ЎjpHeKK7`?}"#e[ GB%2?a|.1b?B+2=І|y8VvZv L.szU֏MË}Š}#}M=w=KwRJzwȿXNGɟ';##=` 6#6 ZcEr![č $}LȦ]Kp {:#8{w`iWӹceVX0T TfI#,s܍' $$:#Y6TWXINgXi/P|>??(CR$6t^`AԹU@M8i0~3!݋ˡ'dClOAȄ[jFn%H%yYT"~2սqR?+dMo&SJ)]1k,Cp-{KgBd@!qcL6(DUEUMS(Hn@ܜz-)l:3h˩9K Y/zzUq&>+\7Q];"y1Y *dPZG 35L =_,ڈͯwAXeO=҇v}l4n ;?`UMJ&gL->#Nz1oljjġ^RHO$ݭWfQqy0MQɢM`0P\d#K)jtbhG"Yt([Us]yR=7{utgD#dxv3/SA4f!`FUHA1X7'f Wt8mhb 8L vh<-}c=RLB:`M?RsvF*_5.l4B.P.QiBk-$E2׈&yEyr|_I'TJE; : AkayKLEL?%9 <l/>UEAPzG^QV]Pb0[2?I6-*wqR_=vVDheD^LI7KF=U(#X=Q5v4kD.ovweRmUrƪ+]V=Z_Yt1*Q6p4u}z/to.j -XG&Jws?VɧO$k%8M4JZhcLӎ;νI}%o8.2 {/ ;ԋL?T߸c.7l<yᛄ,_wCZN{`}| 8+ƌÎPzYK^azO#(۪JGQBCe}yUbչD1ǧH,_ԉ;k~Wq0$nO4os*'nLŀVoQ#B45Fm|x2S,!$"^"cbwIjHU_)I;`]0+5Ao±Saq䗡W=Um}$AF!_QB+RZG%B|+Qf%i-[C @D}@؈-b jTT"5+eC:ve a1Ν€bd>fwJxYDN1,oګ rOP9˪mS!1B~IcS§ы&ͩ$%CYHK pyO"'W[C"vDhU-\;X+NGc/t9>" LJ'5r/BKn3׎ 3 ^͝ǁNД$g#Hߵ=^X(#6h6~Q;,3_1lk*sZmOPR5]:ȖoP888f^6T1ӌINO98j]/. 8dTipyf7y!fAjqxƿuge|5C*Fo!|Rl_}/ϽN:er)H|@˒R9jr;,+ҙc^BX}(`]_uZ WY1wdT_P>%=PJ2̠ 3Nf/c@uA8|z^f }"Y~/()>MmhY$O3g41[h|X7GZ%avbL!8 +'; b-?b<,u; -DX-ZocIYyRF]i #XDsߒF$8Pa~XCiW:dqIlO%MxE$P#>2HLn]^v,/rdsWX`fM4*f !^V$ǦpI!8s'V+,A^q*vwu@I+A7=E }j̜x6X71QTfz@n@ mÀ~nOC+3a- 7O0ETDb[x1]AΫ/dK08Q }dT nX"Ǹ;oH8%$7A-_>gJ\5 qKљnszފ}wҢpsbU4%vAY>/}w%@dA$ppnE\b)l/΄(9K(2NdE_*|^}нȔsEȮ<;O7ZpgɎe\?>c/B2 8*!f*$vm:16 ˥*{-|VG-H" 8{h*$]s('@Z1pB?Sg EVy a| `wl'bzraufyvv!l~l$V.m( +H^АRF%0wK rw4i?`%+]Y-/=a7C.Õ0$3O,0l x3|C LW+t¿9)d3:4'Pwծjh@ SNK9Z$n>CM$S8PF+x tCr+C;e&Dr0 rvlΏșt|^%fh`G!OVhU#BbB`Ⓤ9IJ} <к;os-O9$V3#C@EM>!,*)Ob J| }ϊw0Wsdg!$YjoR{&ey[-Kb åC#Rz@ LoDVDYDW#€DZ~=z@?oNTHH0 C[խE[øS\Kq(Zݥ8+PܡPݭCq7=߿sdMs̒=B,*?.fZv{<`}z0R1_Tu+rE#Ap3ƛFFiЀ`2AJۤ@MK'㿋Ae̊x͞nGEw|˓p@/E|%hixϴ;IR˱Bn3U9IF,סFuM#,W&Sl:NrrN;T8a\/IRȭ,ePCfjykTXxsiUMd~, V*iB {r>8*]&O,`in#qbVrkqH;ގSYC#!|$*mn2˞t5RRMݭ鯷!]:I/A}>, ?Hv54SLKm(T;Un|lhf_'Ytbȵ,].k ~=ߎ+\/:o]}x.S)efo*g ]+>&I¥ڰg/M{u,#-c4; gq Q<[%Be+WQ+#%$Z~jDP:t|%x 1)jޥ(7F%K*(9POQl2%0@ =2P'aX{RyJi%J/c}Hb)f>˗~NVIhG)*ҊwY2Q_$qM_8t&}ǚ[OFU?kû^Q4T%eN\ǚDw7Zlx7!Z^G"llb}5]>,``b1bRkoJ)tpAgҪ2J,G崚iՔC6fi$=K ?~ENqEno(kXBsnVX=[L,D;:\> ߗ6XTTitxke^lnEҏOPeOBؚ2i䒒ݣ ^w%(UI"ܴUıFN7:6q NJFq8߹T*7h`.ƋxT-Y .1f ~*D=1|r_I<̑֯dVvdnfvq|3fr>A;@ʢ#T&՜٦tzR]"DLFYu'ko$T742i|oGdY B/R25S[떿dZujg&f|.5T{?u$uuIQCa6, pӢuVi-rF4CQW@&. >dUka*EY3Q45]4HD5JSIS/#fd[3+⦺=MR"a0bY4fO GzR,eg==74}D|fwHtc`ܞAXT^_ CHXc%eƥ5mϵgs`t(~Q# QF?)IψK?̡ߗ;uk黵e&.{+) t?pIܾ1p|0-zm#í.T@1~'R" r3^Y"R#uXޥ'ͣ'u#s((~PF'3s\R~=~h,!t+?{"^X+lKZٷc #9z|*;8z z#OC8VcI|T-?pGreDoEd`_]EO]&EC;2%ƫ'hSۏd?M02jŷ0gMwq,`"q(Dw[}* E֢'vaAJ>mJIڻPywAb7g\V1O[bsTP϶Xu[K!/z J>Ѽ^)qDT(n|]ȑ|vR3xxpK Iz@ {#kڇpg ~٣ŸO SS+0! f@ D8#O}Ңu?Cb aНnG|Aч dT"/tD =:Z޶SlލP;YM4x}Fi7{.yAԽ5|$^{"G p„./F78aRgH|x1mc f+(it>!BAE SiOH{QAiM1uFC!Q[e6S]'x݈]dVFʣ%:J;ʝrh/L-i0DOY -&$PJs]h pk*:D`83lZa#wI>MVҶG?ΖG"\/1sB͔~Y hc|hj ہn֙uYw<vtAڣxw O%p5a<:LT67/mSbum =R=UU \Rk̀򆃈.OҰnS{0խ.k2#E4R%y#g+i.}@cg3A?0y cզ;\Kbe ,ۊq$_ձΓ.1#;gT@Zx1…H \0r}Co x }!I8ѫѧ0,tzrPx0X&HK07,[47ɪ^5XkS= e:Tիu&MTAirU4QAȽSq˟6XTm%b\MfL ;)z$2>bMȓ|0x5ItT o-KcSRpZKŻИ3|}׉_z]dnǼqHT>MM| JrJ>4~4NdOH)X!hGʴFNڢZSΉ9HIF 5@kQqu#GeRHhPHzY%BzLpNp+E-# aJ}nV C,CKײ;4~B"*q#s= uW+)<(],r&6I[<&[|t9ϲB \[l#E By9LnzXL2&22=DtոM(BM*g'tb8&^W' 7IDa|4u!\>ֲÖ%Ęׂ$֦wdadEۜwMk={JDTa`Ij4i+A&D6tS UMJ틕K3eZg?XSyбRsD+#g@>"JqZ@ J_ tEsYt,"cHO> 2!ԲitJßygM4`P:औN!ZNNyğ,)`@lڅ9qmAϢrL- PKb66s0-l/}3nVH(B@-Я j |( -J9vcyªl՛j F\wˎSg ׷R:Z?Ϳ} c}tT5r⺮&H;ʹI)bpIz<%*cKC,%!H!Ν"0{ 2'<$ǖCּL =eTC^4z z'Wq$ -Xsfഩ‡',Ȳ>5vMa}[o/y F'deMiF߅ &ԫцM;:Lʶj1کq{YFWY5ʴa/";^yy 5.xxKKI&>$/l}S) Œ)o#ÙO3߃xM ֽ#='\u]xKY\=QCq_D€:HcI=8"8( P;,.Gx\mʜJEFC#%* ¥<&f?@  Y$`cJ׼ Q$s#y q,%rcvz]EI9(Wq^Br޴a)=7uJ\ґ=w4=po r-D,܇ۻ!KRŸ́ĝU@^oqv8V6ǯ:PVdVvߍ5nHwl(gM]\RM8[v*6v椲ot\" 4xN0^`Ӕ;-}J6{C$/ o o@%x g bAp[A@FH㹲 _ 3Ye|AܠיOjm .Ec 2 >(H"_Ȝ Ɖd}χ3iّ)w}\Fʍ iBWXrY3M{zJ#`uCW7AR9G?@+x@zp`'uM^[Zt #Qd9CZEq|/&9R?) {6ax,S?}|Ȣ?$snSv:|/3| J†!dai~<}ai4L u7rO>}u=0HIu\kC }gߪڽ]ҷ'7"ۓ۶i\gg˶T/pT9~2.[xbyl~p-qԽfKZMm4f=fO2`+#U-v{)dyp{2lxW8lׇ%;xZ3ƝvcD̓'T5V@n;>ԴxdcRrR[vd`ϫGJWvp zߴ9zD(Qnɥq^SiĚ1Cc.+D}~=nI'hb<<_U֑%K|r`llh?QI#d6ѝ$oPaj{eJjHg{;cܔC vp੸\S#{tzU?mPw*T)hmݙ]13a՚brTS ]lR K3DD*SHʮ|CyN`'&5;#˳C1miKϴ\#' ,lsAMx?ӭG*:*EʛC\\+6JI;V~TOf ^1=& DYhU5z6 N?8ω!*7XHz>"R3fc}vo#'|X>z&RʷoխgTŐTuKLNtS72 &2a\vux =ѝ]-H *f# Fրd &er:| ٬X!B]RTn&{UM3?UsGI˨cZ1M S̊q~ ..[NC3,~NK_Q;xFmZ\$ o{8b˹XGj 6t 'l4FP_ZG:|c 8ZvT_@2p>gu~h=_6A[g3Un$@'p>v_-b'! ރsIt:# xM= Y]&='MyM*} $nňaDR5gQ5Ñ<5LsZ*t͉._F\,/sa*w0MQN˿= Y3.9i r{$['/`@ Ξ='?g@<{5-9'߲63x{t).[`ejdiۢ0[@jlmJr*6we$rtL=OJrׇ$;u/T+\J:~|yYʑi[oq▾%,7dt=ޭ-'g3ouӍ2~Jc^VPک[5ʜ]~܊E3 vxiCLFONw͛u3j2&On ٘1R (/ ] ZM1h:(.zcx+7'ue|tz:W{x}2mv=jX;\0ˉ۱bO$czLJ~61hB'.w@?P}yKXNU[F, 5sE:Ǵ܂#A'n/uɧξw|':&_J3!0fz;%t! >& 1vui;Gp&\l|"ϫrTN,a4-˯tG]vW)+^\STgv~60iQѥIxК#IۙA$4{ԗw)Gk2o9FAE6|+R(vLz9Tdp$S5F&u郔OKOڮ1I̍u $-\_pz݋jg&z;B3?΢܇ pSnW!2ͳF1ᏒC"rzihsIE( my1bj\C"G oi]Md>3LwQcz`LүuWR5ɊP߸sph:#|L~6\5jm<5}k WR~CW ܢN05Vzfa_UFajh|FO{>( C_鿑dRNarOX cu֟ |_Xb=Bkw+##팈ڄqϾ1~y9Ag ISl&y C!B~&R [Kl؄U>#q*g-KD8se7: \w`QZ|s66_Y[R 8O x^Emm-Fq+SGl;} VH!/Mw ZC;5W V.B| G7Z'^h*yVzimةn~:Mk~kgL{ 6jkLoO*lεLj $;#(miNYk5.'Phuˤ&GuXgebxfA-4Քj`0"(RLKѵ{1c8PyWg8\˅yj;]eJvɳMRq..tp-q"kD5{XD wS!ȏsxb87:?)mcyf׸JD'gBo3p7E+phVz(cˌYn([w&9VfatÜej~ME~[`l6P葞@IWNĝ (2s'RD̗C=riVTy{ M4[n 38bk>O3d^1a'",ӓ_EX?h|=uዎYp9<>(kɠA+m<̳"}5gǨSxH& 78ah0Ul XOD -fh.jj8 G}*$aX)fKbA8Rtu2PY]m]&>.\EOECfyXdGGy\7Ū>eN`W]7>[%`q-ןT=t6SȺh.g6z*۾.&UO5-4 / ŊDpcmtLYE:>EDsa NF׍gmoXGʫ4 mjȌ{ pV+`i#ׇŤ\NB !Nu*0IŇ@Fpē9EGKEx^ῗDhc=(rpZ||0QFAfF5YS&in쩢ɷZ3^GN+yxuHަL)TP&*i NӳϳJ r3j鎢+|^^hW(67 /ckB%QiQw38lIOHꈐDa>WF(8-PH>A5J:2~7tĹg]SZ  ˟.J~REVaV@+a_ֺs[!n-JZJd꠪Zf d2tց+%2Pc0Y ;7 G^#^B| r*r f ]-EzTJ̒3sϨt@zT!.Ij,QꟗzT:mDS;]U|iflU(E+m?$⮡M2ɫLl󂿥Q(1"t]EC4S^|sLAL"AקROU0_ آ>jJO_q) IQƻzRL "S LYBf,8*vo:p ];!`) ..ؾ܏Xeg ;=k)@I?{WрhS=&ȩ2C LVpo O' pd9 K3KImObHl@!u$!Odxl =1I~W݁a%C`_m4_gȿ.hlҟcpܥP<&X2[_ .ZlNfG"й[?18 ǵη3sh%x̷$!RtN'63sIx)dh4Qה-SXˍɃ1ūs /aVf G|kY*fBH(?6wxE7dI~90p.mWv ^%V](ֲt_teNʚR3R訹xїnZjFV|>xxQVbW+a ˔,n6G F^_ aJ%.ƽnzg&l-{ЇUH xĥ`?n&UZ:)@cTAWqvѧԏһc(U^.42 c4-''tYw ~GҐa}mVPR RIO+64bݘԼ)M5԰R hf!`?dzi#=9=n Sӿ#d~JcBmupVO')xG3XnA5Tq4;$*{c1 L, 9 6]q_ #&45qr 3t_z![] Oi +Ήq7M"ns.[U)HO"M2Ur;0K+A⧈(30A0Azxq36) `jE ;РkMYAye`E/=( Q1njMt #<ڎg¢/ g]ap@ =wQe+lc`c`.Z]DzN#ڮ؆1>i#Sgnrf`#)th+6ɂN$|\zt! qz|h1 }Xdr5!ʇ/5 YG+{ 1Wn^ƛ7Ȍ1?afm6/ELo/M\;'1 $ad DLm  `HǯG5},%lЇ//h /ִ@{B?5Y(-Scd,?o8?ngA`O̊՛#6z$d8Ie4/ @wZ.Dk .Owd5SޙGZȡ}MV-&(ۊ{ɗ7u|:(&[}.S/KMT/t\m:B pxUbsg +n%VE8A:0- 9̈́ @QyJγBA>f|Y3dIگ`2 3oK5#ʵ#;u}[}NX/yֆ/|>c0k|p^HÜ66*4 h!b9F4cl=Y@&pvHAYw -dz˔{Lx^L8t>9ZWO /p_T1ʢ;۱NzK/պ.oշ2ƿCB5Lj S.Qˁ ˟v)VbTu55\žַ߅x߈MPKI;K.fͦ)MMBz ϐ9pJO5Yu5dZf!лA!͡e(p,$/-dF =DTQ8J[.?ݒ%lf:tKa}.J[$0-%*xLUnh!|g2ҴYި@slёR#omCI ^B .FPp4j#V #V ~7^$>gR`W @AZ{jcyQ*tb &7">gb`B$FeʷG@yZ7N:ܨʌTH3|"&qۉnJz E2cяyfB4PlU$bF^<{K3cfwy>Ϛ+,I P/T:s82 .Y3׊iX:@;ԐLC̾3k8*]*s-f.,}̝ɒP{c_ MRjpW!.1O: d H+`Dt6;k▵(-:Q \XNaؓqI0 c<{JG|}i3WC~&TΟ~nt9M>_k$Ç Qĺ9F`{OOZ* AVZ{h ै) lӈ9[–>֐Czj)bJ/E'lBj[,_C`*\ɶx( bКUtB j `LPÉHM.0LF8\`p͉eӉsƋ;.9"7 JWB|KffBd@nyVZ`o W%G's=ߒ=g5МC`Dyo+S'5U:2B%D]9Wx"w#hw"HA3y:Ş铓}nقDt~q]1jf1n2 Ap$BBى T{bP,mxCb_GQTG/Gy2Ex?Rl"믟''*=: Bڍ$\l…(%"/.|?RF r44H:d}Wm3& H/~쌪z5&{+eJ M$]ZU_7(f$6(a="2/Tl[0I\j@kW'_e!&pwf_v{T*6 9$,XI?BQiN>u1 U_k9TEWԭ9ƇW>50HL 0ZdFK62 \3i+bH? KǸ4:9oSD ^~dm<&Eg>9('h@$[¬[͛}pRr sS""-o=ѓx`Uuw;|A*i:5d-;!SF<~^g-FSJ~Rk0ROIMg;5#IN86_^fǠ}(kNncg 8zD a(Sh̽ Y %׌3„_bBVj@zdǷҷ[:FgGqf fm؏@Ƌ`ɬԫ=!vJeXfl&[5*,-]-]"~f$'GH]uDi\(:7 DŽԽrMwG upQ`lEt-"ejߩ ]Z\!&5Ӟ̧?c 8KUS89ԆW |*Z]I;8y}q+{0@W-HE)u?!rZqH"+oLWG8ļwau$cWiVLc:6D!R16O6ڎu`c'.§\樐c5L&ѷc$=ԃk#oup?gx7gĴ0K)P],$J2s2a 5VlQl>;nym ܭoFjnd@\U yr^ʳg^P鑓?,i u=' T[x^"Xeq%>__Sr((bȚ 'U+ Hh] Z){S1~1iw?4L/[֏xHeBMX$+zhXLzƪX2"cn 'ԳcVq-hem r;LenjY&KsȕKDT\`bT Ŕb7|*'-U 2GU9Ttn"hmf?P.3u|1zSR2UDKʖbi=Փkٞxis|Xm+aܮv؍߼ҍP$rf1e>?g96ѳj,I۝iۚdPQzth%R}: ?gyN.NJgؼ)Z[Ni4Nv}| }:89A"8: l3mi~4 Sn9j)R/nX(*bJ Z`LlHycy\RYa_,YtA-G4cɘy+yYP>gSblsQ|hVɤӳZ}j烃򡥾N Io+-*-D:'_dE\ 6I 4|2COvfM PLnWx~/p6Rv{Ռzz3d!O&MG` {KWMID r*&j.2k|K+]xH'#Pso~E] I.WDuM$z񉇒r`/тZT]-HtNM?4d,\I! "~(pNOOa7Cۺ3Բ,e}dV`KmW. }YoA4J>RU ץ/1[3XI\On~'7%6Q]3Ά%ҋ ^u-UJԒI]b24bd:՗o$c;K©É34fO!i i\4/\QPu$\?cD#=DI#iCY7&YI@nL#CkwGR4QO fdoy`\u851izȨ:ھZnESIrOii#?8iyd*XH&BH5w K;Ve#l h )}CպnQ54('Ș^1[W{RP3䃪^a맫lђ}y6PahFE35r"n}y 䕒Ʉ+ Oa%u<1Ae+m/)_;s3oO#9y cgVd+<1S 5n?a}-y:9c$ <Ȫ8(_.\St-Iɪos&fcO4|tc*Q ) [JzIMC@ؕ iʚ!- +Mt+XHh{nB-7B|iOӱί2Q̕ s2~5wSz;fz8ijV;Z 8@~P\1ki+[Y#d@X'W1koOF?^'[K7_in۪L :1)JT&-ULP;p=comO|o Z˷r[|zc8/@R'$fݩԖlKѓ僳e,c6WF ]ǎ}Ҋ߼Ju7ǹS~2k=*<]G_$Ibҡv)wx9oxl^EA+P{ȠZl<_ \M%kUj>ȋFN>>ۦFS U?/hH;}~.i:0wa0-OJ#FK2[EJ)RRz{c1EvM=P-CK&ҪC% ?YY|C@5䌭Cĵ\oBJ|@ .5R^^²&ZXn-Eм-<>l̠ /<&6hB07>!nց[(aJo6% ,f*G?C 8/Kv8trb I57å e}\!'6T8b>C",]>,l}"q=H?ɛȣI%&A="mb$;K"*p)[iCrJm[[4:9h56wqr5Gi!H%/͸S4;b/Rk7;_|Oz#}ywW B6 =BTBW!;A:(fM#B=OvT,'Һ +废MfW1(}6T4N)[/z;o5U~ͺ^ 0l8V !SE_G*R G4nE]!*sp 盙zTQny mB*޴Oswq݉*k.Ox)S?$flOq#\[[u~1D~&{ciUGI/D/jk|?9 6ߊ3$8(~+GQhkikEmg+ZjڪVeʂE 眄CU@Q]v~GXƸc;**⅛b]:duƗo$bYe 0r[4__v)"!cw+Jwk[喁ԐsuvPRBe 6Fj\7:-˖?R);Oo㏵]\ 6m6{Zkŕ5-/wM'4vtiR[H{mhmHoGp>yg3~x\Hۯm(H(iz/Y 5~ r 4aqbn?n?qp7M-M] RRn N\/aO)oRSC窞ZLXtu=OH?>k==j?Bgx~4b72"ԛ-5{.b]+7&Rݺ±Y>t{2Qpභc Ck4d'ŋV4傁g/Ou<)/{,_ߵ=Nu Pg" B{ |-,h{}wGl?WUbg(t*})gt %us9[~B{שk뛒:ݱCrsIkz ~j= ow Pz?ȥ:Goq'9AXPl[8Nv;N],_zH>dz#] M֖)+ޤaDpB\U>wi7qoE W,r-.$bm30;m:q/l6~iGJ_BK;Yr.stEzp_źf֡Pk|yF (%zѰ]՝tCK3J˅vtOw9?}_;>6Ͼb=F۪=Ri[0xU]5(x;M$OGgB*qCS\ oAw~NG '8MA ^Qc3"&-}Gr|1^q{@ )HdGX!AUQ?/zˤiG'E `b8AB.^uLU2s R9ՓN:zm?R"7O#M+mtuqi>-wtpIĐE)+mܡF6|Ϝ#m$#LBz.^Po\I&n;B'MwFw# P82c <9lNodhZl40mAJUwx9Qiؚ[ V6H?IY?@S  BBp/7bGFŃ/r 65_j9p{6{EȽe’˰̀v4eC:P eCfEc>[DBg蟥Wgb (i%RߑG,ubn}πW'?B͝9C1y9UI"g=^ >#!+!Ai)C:箜F_䪱5V.3d__2`lLH]GȧII2Cb#q8 HA]Ӟ- K 84tuq]!lb1gCXF\}Gpll:`_iV%_\yY!jXra04ӣU?̳&OLIO SQh !q=$zC|53'{1QRMT{jC K_<<-KxJLˏ#KQ_UPKJz Sr# L<2lEotFrJcb?blrd17́QUIbvUaZO@)d'$ x|+q@l;\\"/{zRNNpjde%\hk3|u3 eII4njq['P!al f=llM{ҳ j Wcɫ|*|8B{|yGS99PGZ5"~"^ב]¿B|䮴fW4?©C~ڈ=zvbwh?WxhgH8/:+1(7TN҅.z8@-7ƚX^Jzˀ 1B]GCZnA⚉/թ_M5O $A*ZҐA~/yy糛Sޚf—_";s/*hG笁Zi9ha[x4' yzҾP(qŪQ`/t ,'֏Vܗˁ ZaLY|?ҳGHqI,?-?Ɵ6x#Ql!+SiD0?>:0Y5U3M'h:øD)$گzfFLI=fv?\ >zk*x||z }m]=֤pex(S|?<ĻbV,5;8ucM4AHHg@ 1Bܜbvb=~? QX,dB'V8f4Ȍ~!x:,V#& YI )Fmz|q Q9]n*gBs^rI<.AA=?TGMU cbd'?'E=~2oaKRd tV#os9ƞTU79LԳB9'.JXE1'+ WIR>l}?Ձ-|I#UنE-uye_Y-bC{Ar@ O6XӜծ ۀZ ݙ9MtmIFL< nZJwzc6rcl=HSJb-!k7O7iݜDߤ1sn9gJd#E-[YE׆JaϹ$I %/"OPStiyIgcˠlQ!„77;$$jhqa!Q̨[uW2s]j:QQo sH : uz>3# T֌^xCj&]c?w~eؤ̭VYMRB 8 x@!\]]rdD53:$QHУr26S)m/M%Luq,9Qw|E,&s=I-2YT*sdҮͣaZ}X"MI 'zsL#ޅl(]1^O8'n3 GwOo\9խo-Ae_NKb4BQ/Ӷ7To3]|(-CL?1}@ry(cGk_.S%Rj(\͘MtTl'H;EEwsmvXav#J)5,HHFI Z" FyG^ۢqof+zEhfK|?3_^ア{9N:V-mnJ?kQ~&S`^x Cp2j^}ۤB>P!4uC`Q" +~`Ӫek쩃,ǿEpl I!r3|i\0QFMɿVMl#AY+aZec ^*7PB` 7i:CSDNi]彛, Wmg>Dȁ. j2'݁XeQo{Tܤ7 "]9"D7 P>r\h^)H0rej?k#Pp[2|EKR z$JF۵] ݃8pHMRRR"`Y Dԟ (fwX$;[8R)3Fu+{MBWoB-l&AkV l ӏ TJBy o;WIU\-ױ 2iqv -< WN7xX!K 3cy#ݚxrԿȹͬYZ$ѣ( M"a1`b6N7AK59P5zd_$nuro(mӮ:Dj#x=?9q%?,)NFPbUA1BIbj?^y[*20~(`N">uD(LUC ,cמ8aBp4^n;8e i؟ ,j-B[[e7>x*8.7r ljL*փѡ`f+AX?2, %H ;g@p݂KstWWmYkP$H"pC/;%3@tYLj >¹5qjq*B&t[cJ{v{Im- I%M !&PeeFLK.g5$1CMmN-zby8?yy <0վ2zM=L-E~&{bE͛Jw&cC\6#L>*\km19FY_65!Mð(rח~mĎ q ?Mǰ1XnF Tff9@7dz˕q[ }o?RpH~C}*ۿDp\-mGNN̯XͲs(9-(}<nZHPy8qf; ~N}-7,r(Sǽ>=f^#xmޙ?8q,Jv?va%*-n&'Bxq_رlhqt>ÐՉ2_S7 =.49g~]$I&*7<)78âLn[~nfzkׯTkxz٥^ϻroXxʤIkeU!)m&=45%v"wRrN҇:&37; d;]p.+MgzLRŐ[\~K~[w-wOwLG{q$2qtB&"p?^nn|;QGm\n˙?)xrWÿpH<88M!8/ Vq>>~bM4r>ʢ܃$g}1ϋ-$ߔ#n2zra[ 4T.}|YS֕_U: {=(dJ!M?-OY-sO-9ېNOIU'w|\}3bNGp'ű*'8AI&GӳaV0/K+ۢL_IJf|bLb7Xt_̠ܦYVmT!7d;LLՔj0px|̓EҾoHO&Oh&.GWD|f>XϹ:àqѷL09 79}1G):-&B{@t ܈sB-+EaÍI5o-˲2%& c-!Nagܒ. rT XbC>]W󷉲OE]:;aw ½۴TIlܐYEOn>j3P}-M$AҼR硪7tNAWa\~,;y*+UqH֞ }y):$r$"4e9ʂX7GfYKeU ,>㇥-٠)hawK3ƴ#,Ep5>%S%~3{iGi8gߵE@On]{)QnVɟ3$Kd}QLKm%*F_mx2^8$4x/y/rTd-*Ecчd|-orqrU(ˤ!̟"d:ɋ-zF!j[HJj >xP~#uFaY<ͳЇcgnd܅'DX})1 2idFIiͅ^\hqZ}8\lGQQ,+/` F5{fGl=brD 0bT( [0-t n?2!՞GK|;#ʢu3IeK16mz\}T+izEt<6c֡ҕa8>> YaX i}uK$hN*X/xըLqסŦ8Z* qĜ[ Hg*;- GngO sSYA.pX4@.`#a b.elnT#( o]kaZd-[-dxPԟW?ک!j7KgoSnF”&T:|A7sW ph<ǻ^#ن_%=}rD.=뒛FM"/GSf݂k^O)h|< T]SALwPioAx)Cdz $=/#<+s$13FA߹Ci3yn%(("|pDx~[6'Zs =(r^.3`Miϖo۬eՖXGGD9+ ׏A8y1?cP5 1Iv0bQ4|) FG<mR:MtcaHd3~`E|>_\ڳ/_o:?́ Dm9+|-{n>@{ܨK) [ z_-(kwHqu<9 N_K&՟yaFO͞Z.(82ԩ̛RW~3Nn[LĹSѫw' 'Gnkɹ7 sּ-KHAQ˜2`1bс')k'q p`Tna "b%$죏<ňM+ On)xeJ|ł b%:#?UeV?B{$fjW03iI1ŀVkav~>疂']J7wAZ`sFL/Q$S0eY:yIgZ/Bnm'9)A?I(5L>:٨9k7ʾa 4?2tRXm"SYtSaoeʆOI,372=pؼHh\D՗A.3?sZؒ58EZFH9'a\ ԏ` 4i[f X2v5az4^83T~1Pns(DkR^ )ŁD0Rd]@ a>Laj2bIʛ)u] O4poh P/k}ݳC8/"Z#<遉_g^<$4AOESTTTgt?L@jCDZytKIzMSL7F2s5;\NPm&uz3vTk(3W,W JJwيȯF8Mpҡ ~3 5uA438BURA3Kl `xM< UV6% 9=޿A~=ET/c)r2kr8+=n)]"~O $6>+ɍS'NjS9LI. $OGS}' ^6TKkE׶&پLR}q) BZj͞8^@97Ԇ;0S/N^ nu?KOD Ju2Mwn3(kj(Ȟ$ip~c`F3%)uix.dVAr+ {aWֱٓTRp'Z1mY WL ԉݶo 12\P:B[gP}и$%vܷ&1͟JPDfPp;}Я8dҜ-fPivu4gL)"䏥[Ses5ڣ L2Jh,f= -M`gx(%͒=ӷpI&[ڹ-!6ԟl+_' mY)6&D]y } ҡ;xijD]5M9sc/AL(s-SaȢ?R-׌FniZy[yL1+_N<^Vgؔhj =klٽ]d +ȍ &G3?5cu-tPOR?gz ʞ8,ydoO ٿѐuRI @֋~ۣθuV|CwX6OFnLNMKB8+3Ra_o US371Jwu* 2?q(˽OwV*P*So(|4KmHsba"}K> ûD=򾯥K3W66=SQ%9|垊ϕn usV&'7X(hK*gy3őRMĂ} s :&ZǷ/eG?o Hc9ʣȇN{Sӭ:n/ f+:g%Dw8wd [Ƽ6c?(xt5ϯ@zmm`R`fkc91 ,_X 5]Y=9Ɛ3*յj= /ήW:&sTM⧬u L:7Y {5aˊEUWrICY-ܦ% 01ʐ_r,)==+vʓXi(]E~nZПR=2yC̹.ydu[՚*4SA^u ]9B%B>юzF"|;xTMөxeX_ʑӊe\.?v6H}Ax83u%# E%YO a$.gu $ i]sdq]PcoA Y]b^qySvhr67&:D˄7{ (46D\]T[}&?#PBg=Ww?g&Zf~oSsdMT =7F\QWugU J}_dO*'^&IZ~lcw "ySH}Kx- ' ɡJ* ,bBsɱ=tI9SZˆ2f#94؋(ʯ']rwR 呫C: 0 j1} &#A3Y쯢C uJ̮m TTEM#-{˸> }\b Ϳ_Kt}Mv*1RGIBeA]ISZlNc6v;~wOM x3I| |.… }MAof'au6ȕ{0ދ'-c*)ŷ@)47(`eo[gp}rO?gp8(qyL"Ph}Rz{vq# < 2*q?S dpwOh}Z#8u$Z0ABTOjw|.d(Rnd:pPMǜje|dK9O>"6-) Lԑ A3T[3-ǿI)W#-o:ôiW͙ia0 `kHHe,l)y`8ڒ?wgfٖOiXvDl"VhxbYZ6dU.pigan GX٨`)iHvӝO%q E /v@^s7䢸fTFдx܄בx=Dx2>s7lEM ?IA? lONM$ -Ah-jwjl@#QƧ 晡z=)I'0 imǒ0yxyв܅YJn] B+T䰯Ft+uًbaMF@ΏS [=O {!ߖD~'9>ݨ4{hs 3 8)vO8~RaS\}ق/m Ɇ|lh<(]OV q9M PK-x.*6NN&rȫ^zc@ݮHGnz-; bwPPB bYg~zF9u;=Wk|| z'o܈PH["rt\CQEt5~ӿtyVyO: crotv>]`kX4D7*ޯMEtN ҅S`2ף iOV;dltC,a%@+cڭKj8BI$R4ː} P 14¦3Qh{HW *zb>1X Ͱ:QHz+4Vj7l˵!eF\ؼw1œa~6*U[.7?- X di>_],n#| Br$ G>O}+3o7j|~EaM2R K-ٷ ZN~, 1-McxقC]CSR WK#djPSD3'&T,Zឥzt8&۲t.IyȪ,>p_x8-iv'p 4"FHG&Fr[# Xxq ?ț0~$1iB4VV^+A2Uק)vQp&Kp ED@~j>q~xJ'-UUY.3_'P4uNZhVߥұ͖$ ֓eṟNF쌏Dp3&?aK z+.uJQ) P%5j3eh3%~J`cOFzzsK`D\U>/vPevg..X 7F}UHƛsNojITJmu!@A; c794}3ܸsGjub8PSA+m*ٜXvKccYQdNUMo="ִH<(3ѮDSiyg˴.z1VaGh UB&KKd3hF[ fMZv?Rg (K;c:nE$Ǘ*[3XA% 78r t!)j>;*l&jFhqO[I_[BG_6SU"u2T0٥~Ipt(/u6"daIDj{g jG}`SY6RLLBUkKX~Sx3]^\ӡ1ڑ 4`HBNV!3-H x+@p QIG/5(uM~#s9XP*gdf?/}c E8)U4]E5/ (W VJdGUvdtm$>jX|#]Uբ$kvt\e+WW $ksD&eS8t~'=&,aGtk𱡺I<1V2D%&˴j%0j)@a9m1Щk-+V ! 5)מ%w)IWc AI|;gZf 'brCѮZD`=ڪ\v"`*YE!S#gְ6o*6۫V*dbJ,[b}o2e%}g e̚4n9*H˩?Did#j*.݁0~_-=T(;{x4LN੾|cLTS%v/f^CvpVJ).8B jz6<3$W `z+B"QǷO`6ufE ;`|Ib=/dk[^sYE_͕Ra3Mh69weR4Ii$(31 -S;[ d."WYLJz7rFՓ?AfH_H*gYlr8\՗bBF4BBK3{(]MԖVm-P~˒OCu^}o,KݴA T仿ƴ$\KMlI95KKaRz1YGAD/n1$`Cvc)*p}^P $"vuZl]G6>N{5EXDah> Mf^ȭy<1v0R+QbMg3 d Lxa$JΆEڸw<'t4?MܩrxӔ ~ 6ۅy]9X0Y\ W;'Nx J\yG6쭍sEX|TsWzI'őzx6R3K{Pq t\qhðW2 2Wq_:J} Lptab=CF\t%7&.)h 횰2S`ڀh|QFˣCZ#T|E$>aX- v+hշĎBNs7)g?p#t,~(xLVJ]᙮~\G 4GVM`3V&yvNI# k^mhj6&&h?Zd]R}s4@ISWH Ee!bQ7f),IX[pcJwݽhp!@AF?1;ytv,R34ʾs,2S;*T Cm˻?"ْڃGװ86#q d+@ +S%/ {f P~eSKDK(s`քqR9܃4gbGC П BѨ% 5^dĕcKnթbip(kUhEDDcYIz*# B| b5>Z?:E'HbB.Bbr0oEm |Wa}㦀QG*Ṟ@G1;b>yZ$u}=~?u_4 z*( G c_4tLf4 etLmf 5(~X08mkCfis^.gGOry^`<Hz h^ycNOyӫ#ʀ4]xvp3Uh,8H2z)bn~K7okj` PCv!{hsi*W ]Q]i.Z- 20WdOER\y !On@kABO:\xDk˧(*zD=iZM\S*Ƃ%yG0+cCqX++J7'2{ڴlj94|p| v+Iy󅽒ky: W"haZaԡ!>Mcx{yݞx;>uy`bA;籙-蒲]1gCOީ].bt;(&8pzkjO"z|՝؆[h[s?&ijvZp [S:ƛK;~|/C 0M>>,'%@1siOX7kޕ=ܬĜTϱa`MMo'T*QP5niS7˫UوE}bJ۲s{MrW>q ktT-K [A̓ר?Y92;& #֛ ;6G?Z}Y2KU348#xeixBq7zc =W3iia.}D%뫱u3G'EeޛJhb)zg%Yrf?Doj7\i!}u|wPٯnc}񉏍?Fo_sbN$6D$ JFjS Ln><9:[=cd|Xm@=1冰2-U:;YSʄH[ٗםLQ~ϗydv_$n8|HFy>X|[0y |\ ~ٞp  } f!O3 DOCUmȮS'ds%|>JG, ܿ1 gH7Ѯy+ @q3G X{c偾l8c_W1m)n`Z]&֡ qbLBL{gҀoa]vog)/-]0ɦx.25èkR8RnS?X+KN2-&=-@Ѽ {-%pa|a*8J!?|+?9뗔s{a໶jDpιraĔ ]<͝HʒDC7IƇ^$:I8?AYCa.n?"_YTL_3 [UvV•G] Ǒ`_+\^IR^e{g*?2HdYt^g|vScVwJ=ɔxU,ۉ;r'rhT&-6vͼ 3+!IaILl;vXѷК%urk}$8y:kM3RVf>\tZ` u6=ո<1[xT !H|A3eapeP=Z\yCK;)Ț¼KukΚa8V6ŒRcS&v ÊϪ]fkUNYO^#JÑ>qwχZɸ\(TGlX` 86~& )>lR*ߎX"+E-p("{,i.Tjcn^e'M{P/X܋@cY+̓͝B9\jqjصBNɵ$ACѲK_Nt-{ ZEB)ʅʄsU7 hvzv\=IpBƬ+F.Ѩ%OAhl8[gp=]d߫h:@Rgg5IBs1䩛PEb,ugzP.,]4Ss?|~Gyq66635#1z@gfj/@ߪBRt)N~I?*Z4tᩩ¡7+*Q&mc-v 9.}Ӗ$÷I?ͧob :81@:-5v; ",΃wk8;-4(E]\ɳ찈HtSIP~Lx~ҀWgzm}+Pe㿔N%O`UU¼ dYAAI%5LJ~m:19?,(|511NiIFAQQ%mνȪԐ\ 9Lyk69d9:<) "@n5P4i#2@.IX٢M9!Kb$$;U(U^Id!yPn4逎FfVj]P^`->r-csNQQc9pż=* PX?Na5'wya3^0_S tWb]*bԖ9SH)%@jǙW4T>X:w"tB=RF<=̢Pt$DfNIaVFW?@^x dmN5:x^`z!Cp?u;\KwQ'bpuxڠHuL:[7C|mfV(TJ۱/Mϓ- fb}g1?XIo1oq^ >ԥ 5WZ3p82FH#%Q6Zk*6 5+y9SPkhGĴYt;@E™VANDٷnx|Wt *|oeIit#~U%}feCĮ $oͲOo舟X[g dzQABl%$?kAu|QTC~ӑj;yO؟8(h~s+Ƃ'uNj,!V]el?.FA; & [D~mYd۸)#Xl6>+H*MM~Nyop=P+NP =ÙՓkWJl.q{4uK/v&yl6 sgbaUL}/0qfm9%HèI%\FhS j ͛- i6:1QaIuƤq ~b 1o*-d_a?Ct=@ ٠jBI"!}ɳN>!f0Da*̵&ci2\#.,]\7UNF@@]fM|b|O(41,=S/$9O |;)0 SM&6йVeNobC A|y@ '-0C~WĊ@\,_; ADW/T\?8Qeeg(R y%!Kr)`jbE8zuAil:dI L {jG Hq~2#Y!I leUٛCi(^y @Drck~JK0'b=ae`j2x]lrZe?'+D:&#zK*c7hd.XU7 .cB''Kf|E%MPJA1Re)H}YUU4 HsR 0,ӔH1Crd4꒽-C׉T=~o-E}ēI_([]j%mpNʱ*1aV̠Sq[H e`*s=15u\ߤ`V˂jZ?[вP5X?$Y񄃴zVTzxg)TG7y)>B4ۆn$ OH,Kn<@‘oTLG^6,ϡg8_8>(hnwcZZ%Tސ,'h2KrLdP_~v/(l/'*eGWbBF z%HO[FUKb"`CEb,_V;6(LOQ[EL^Stmn/d%FAk+:-3l%͍T+Tɉ2ЃBq0l.Wxwr +)) !Hv+_ROM7|P`*BRZ JB{񽐖rox{u@lpƷ`K(|e ŏ W8mta-feC$T+@:YBv\ -0%ЅrJ̀h@ʮROxim(24T>6(] ר|9>X5E ;֨cT$%:\Sjwyi7ѐ ` z6Y/a( JCN_Lyv9պ)!E)W"CP*:?TBWj>L!vC23Q|[ÞZYjocNP`^XV8<G/Oۯ| Ӆȝc zG8βu'#'76Hn~[5ߴ?·u4beAq90xuz1p9Sۼ~)R-\٭]G*O0بaS(_f&)݈ `ӱ)1C6mbVcWw ]>1}E91dN+lN¢0YiySghseoBPA^֠%?_VG!۱d?9 N5XY,m _b˨Τ|pZ,a:#Uv0HCB,6E1l53r[F3%&ep%qAhYdFp@J0z`:.sebNO!>٥ߝH)05{ӗW?NzFvY0_T},tFimFIcj[3',xo,P_Zn]Ǐ՞)f3'&>"8z\C[m$Gh$ёnvZRW^/= Ǽ(f0?Cq ceS{km.jb*li=fe]Nsx+Ѻi`Ƙ f [kZi=EWf%sL/8mk ZL^MMcSI?v{Dd;_XY(xm1T_.+@bCq}TJkS 8ztSߋ26*@>WA=*p,:zFRW3{4Y)P ]~eDliϤe o+jFFLy*Ełr;;"s%I~f.㴧ui -^`7_z'РdAy_Dl<\bJ_WcOd&6 ~z/m KT3i) \eu^Q=cu_\ZD1%-d! ~@ <`I#$~<O lb(Ҝ2Y${}KET&Plf ɺ=d S3iY:wݿljFѫx)z\ם+w{`I5 7B@漘X=MdL.!t7?WF gi {F%% D{~ E?[}t1ʌߓً9D9ƫem31Eп's-Zoz:dQ'li BB{ wtzi~_r[@t:c\29To iyE֞S\@<5ˈ0}@T@h_S1JxfW- TK44Mb3:yAMi*m+bD f> BRzk@c0 Ƴ-8Q=Da:d/*%pY)2dSz"r'-"Zh7>a3Xt6PTx5jrTn/ri<)rjz6la1u'fIR(ΣY˘R~A@{:Q(@\<ϹǗb>>?•9.F/ ;|&}z*7\SXo}V Ww3S[3N 4 &jX\=t{8eP ,|}h"> m[Q~C@g'qw1:ƃXȫ淯Kɽpu9R#UD`NH~ ZH>sB'1.%YQgqn늑5 zGqq ]3p rf%gZ&T6D׉S^Vz+vV OB6{䙠oTD MqA Da'ĥ%p¿;'1@֠0K7HHXW45b ogI+:n˴!'DP|FJxj;կ(\THڠ XN`Oo  tȓ~(T.' iYﺜhS?jr!~RrqևrB OA^;71[_uWy)W"(HKseثj89}\S}TiҨTq*MGfNP<6<#@8‘`\hEgt?D=@m=kMh})8I@Ll2!{Ve1 SI;0%yTEk1$S[1j6ե܈g)P5jd4̼c\6aJN z߈{p))<fS.8;R\ IjzA_hFS|KկZ`DS&8U\eʈXHbeV2JWjcs$5[5|VjQeP E.qŪ9GVyѲv=guaWL̑S+TH7nZȸ6IjSJyJx}Y_Nu?ma؄MNA"dYZnQd`XGZLOFαa:'Uj0aJ2$IC_T4zY7W4EiJg*$8Rbg5cjv1Fg1O9(0MOҊG-6LKMD'_bV؁MZYhm,Q YzpĂ0QmE~객i7W-r;x2I6Q f߳*Z7ϔ Hs Aa ͨ8bcb 40Kgqi{(YnT96B2KM`+b[~#]H aS{VH*MZ'@h2\SrG1Jttbj Q?H"|sV?[bZ9zُP4_HKG7 ~b8\x0\yM6}bDo$JsC$v:]a3Q>+$ ;uPlZމJj7OZ6V2tGb=ύځs4xXJIPF'p] \O@w7s}URܱSC^d=̲ S7uIr@|VQ>z HDYc\ȼ-DM ܥ`"/IZǸxH%*]XЍv4ҶH)7O!=@J5;&ǡYuIm2)%NX@t͒M4^ng% ָ`/jb{o, RHzcys@= שRUq !pxĨ@0oB@eb'I0p DЯ,Sws$TcchǴr$l>£ Lюk5u>P](-An?nx[P^_b#V7R:a>}+<,K#QIib\l4 {>ۀ`4/Д!R41<“ O@Hq0 - g~Xg˓ P1H@BIZA@φ]7-dqoڤFhg:Sx"9Hz}oUa"TЂg*A`HV(<'" sб5*w/֫@ ~lOI*1dd.}NF>9^1#l WW3lpj AU}Xa82Lf]npsW l2?[Uy7.^ !=ܰ.iO^7|VbjQ^Bj0GI;Ohx]ԟZV9qw s \FG9_P>wGԔVo⋒xQ֗W|o'G6_yk)ZۥWTyDѻ$"n]վ%u2䯝Y0ߥ,f ٽ/6Ge9m X@vg)j+ܰIWIr/K[2޷ld%>} ԴjA=ýgBQM& 5d s[C S$֗TT%b5nNjWz\n\FDđ~K8l˅+9wڗ59 vn/mUپ_]9[ʎŁLo2&F KҴx^ohB~\t[Tshr%CÅ"m}ȮzHbnnuo$w\syfߘ5qCU9JO5[rx8 N9y/_ pn 0 $MxHŞM:h͌%ysޗ̂QrբW:3䬕)4VWK܌$5~^S5ݲ)p21P,֙o>߁l I3J1. $G?G(KpH*ՠEn܀xŝ~7sW5f|i;JըRK%o^Sӭs;1Z6kkA.v]]dׇ9B*/th2Ʃ:-R)((=X0Э0+(EbZؽ1i02`7ձ3Er &"X)-y`:}Ϙiu#զ"X4 7Ӎ:C-.L4AW4P/ ~xW:ăFӅ͘T" - X>ѹbҴ%8Þ%#ACTJF~qp&YBasX3yU&r,2-)lYbIrEmU(]c d6?RdH6/wWv [*Ma5g*.MQA>eԜ|h6$\,4b9x/ֲ$$׆ݫtM-(َ+smYT.I&D \RdgpajX@N46SG]9Or&H,&Ř:^I$|ZqHJQ[(7oHSALږC;ZXאyWyk`x.&j{h&!Ƿ*E+-N$c (W~ޡEA2LJX/gxt SQ/r8sbS<԰+<4FUR3QONj#*E'Nh|lmֳٔiu.AYhKK*Ebx*4jA\%Q_i;Y5z?h%:' !dkVpxxlXg11 إve/RZ!i?!z ɾ׏C0ٰ}lb@6qw%Lȡ,UL9jYq"^&Ȫ1T_ F)I̽2_–G BGJX"N=Fe7jHKQ6q.lI?Ljr'f;0(zTo,quR<\XGRkUeD*M2S xGú_+](WTo9#*0Tܓp73:m/ +\qq>_Fq%F]!b?F|\R%qB[B{@:?.|;;`k|.+c ߀HO1B>Rt>bdyz;&3ijٞl0^ɄC)᳊hӷ4(rn6ވ;vcbM͂PHڜp5CrbrN߾8W!aXNxjLܸ@6OO9`T0 ]l)gm/$b7BvlD`yT̐Qc޳)v/.Tt!&/xy:(99 p`}o &T?70kuwXYpW-M:#u O8UPT")חz/̃ #d3{?Q˶C_!Z%yȵ,D_+vNՀT/0#TkV87n+x|FM61(Tvn=#Bv  WsېOz mU@gE%CtP6K*O Ât ]yzǾhZ${_%h37*@ůw$<0T,]2z꠪m:FN)DX*uM2W?/5p&m<42|HPrΛ-J;;ԶG୮SL߭s ZESlȖ}ᯕ#?{hz%N55jq]WSG{'CTPv"&dg1j>j& >r? 4}H]#C0L㐄\pa:6>gW8iJ@! ^rGR:#&fb3R)nb8P*g'@}m%+842P&C=qlQ.% WR냥>٩KQИEM訇 sDU~T &a,}DKFS~Vc2DNe*V@!=_ԲA5Al_!mҩ*'5ٹ3*ǃ&jϊz|of)3r9/zD+SqXV:F+ D]!Qɂl5qsWs/VDclW7R|ڮb2܊sgĔ }ZuM50E*5}H<Ƶ ,xyHf;t Pzg0FTcLH~cϴ:2#U;~&m#%cIloǬe:Z͇CE< ]GWĊ?=SWҡC9YϠeJZk3i]4J_l>`&mu?,O<`,6$lP?6ȓZ3bWʆKK~՟z^Dnk;a}"9- Ҵ *}86gh Hdc. "S"dV" j:LDמ@SBFZA,=1q|*j6C<hb-!eC~ZP(xo\U=ߢ SJÂM*H; )iUJV:;G2 ~[C,>k这q"o*CaVp [62F#6i{y Ng窩n#*0!%ߎ#9DdO)7Ά(ü=!oXrA& ݰlj7+4I/ UoԡI-_ۏV$ek|.Od#3m1ilj 9%tf7-a%ŵ?(WQ0v_E0c+œ .J>eQl+"W҇;*do6e֘C%G̷j]ѽy2+BZly `H5nrR-& CswKyER<maO`W UD6k,<*YwEpvtQ˃]N ?Nٟ> #lqO4c|.: {ז*MCqoy1i$w*jWb %:㏇<A&رic3T A_{LbϷ!~A) I잀?1nwX0U!F3lRBHOؚۂzeFZ[{-nMItTFV6gZZq#Fc( -R%j8]J5\4MЬtf TqYb>$ϼQa[' E.Y@(&ғ{p2ZV([oO Tɒ"1 f"L"$ՃܬtF0 Qע><9S-)tg7$x Ms#W -)((^Q_*"0**sA " P`gbP+ɪ'I'䪪ʇ$++b 5FTF`c=1=ҫO' *x%E&+?S2W"&t)=J UtgvfrN]ۡ=x`Dq[$"ըTN_lzW߸A0lA]Q)I9uL-Eex]@"39hC#EEVۘ=FMS2A>T>ⷭp85su!8|RM2]qܓfh4-[L7Ҿ[RlK*jAَY%:eu_^3#J4(!tشw=5U =>P'_O鿰=5 *}j]b'EaM Dxq*pWCw5eRБNoTI)ޅͨ&~.90p.67Ge;%ʧT@.mU(QM2~Jv95r$LysJ@UN~ "wlfF7`*7y|5b":%F@}׵8T78z *k˪ 22^p"jCۖ^7aؓ#Zs=І;SU&X\cKdKy4ZY$"qeG/,-E/Q -:f ) lvUʄ'.J%QƨPʃze[`:؈Nګ^ /q/X>-٤jC[$?o* µM#"/+ݏ{x8-^^M\:oO'б?K*K,\@} lX&A1.D㱖d4f5'ؿcAQ9ʰO0>P^].A$e8Q ȏ'O}CӅ2*7g{x&TpFNq7l_KYlmܗ"B`KYM6ܾFZtCx=$P>L>%%w7-4fQԂpۗoBUqX^ _b'7.#ݓKjPwQ͵0_z]CK4wf>]%|]4ԡX$HIw$!נɀ2\1dE[~(kyԍIP%׆Tq#ԾF:_J구7V}ܧ{nLPV*d ~ ?0 pcCHm0odWDtn9&߿qs (ͤ=_HmM܊zS^,co^-s_>d>%9f:}.~6~VlW^ l"?}||/r~&)~>[Ϥ~S_fx85-XfKN K`LyFQ9?.M ͦiFd夛v]&_O&{V>&C˕^Ny ^ҏo&u}_xwrWewb7ֽ%Đ2ѽ$NM3!~$ˎۣ4o{B/ꋁn8 '_N<#csb~ Ɔ ݤRQv⟯I֛yc; mMMnBjm΃2UD_‰Ͽc[o_nJ օP7SOG f]YIwr5e;fB@ X@{JasFbzt1 3+;ak;)]hiʠ[g5K|Hia1ӭT߇/v.)9\}wOzhn\Lz2~Wk?YێD {stSoto&cSFqA]% ,o(Jiz "8\9C1mU'Y0S Du%u}$ÌLk}])?tr,ۏ f|&zbvbvaQIO]qr bߤ ?_:CdnX&}0 ȆDqKnCg˿k4HYɡs:i WY _\̴ƀNd4TЈ4sHW ;_]ek#o`{a8Q+E"ʿ˩Y)<\ 4o[s{4Ţfcku ČC6:5w.tJt3Ck=p =4qө?yֳ!0>^P)"/h'~n]X&%e'նp+m>t,eȔ/t苴 =z(n= Ϯ?r[j`\13a=-JKmI|.oǙrvUlnҤFdo5ۖ](6b"Lrٯ=q|CȞRdϮc73:Nf!{B~ʜrfd; ̚׀ʶ:e!XО]ZL;,LtiURl˗؏r^$q$Uw{Ɂ߭II^<e)F 5rRd/꾿yXߘ,9_ "ޤ/)CH_y 3Ɯ諈7guyq\|eHX><߁+"H Ozњ:%Ŀ"'Zޖ6[)z~A_IMLjݪ]L;*2i|#A |K8M'Al| .;2X {N nN y=b( ?Az }Z߇O& j}I;jDP_&A0(J'[O}%3',j;]Z^EoB9ל?Zy1uK9s%YWpaҰQU}7jy8HttJJ7Hס䀀twJwww+w>;;לkk}^||L]]tmX8qxO3`l}^%}sS٥,]o3NߐK34wp,Mz̿=F.*$(O4vܖ1UȻ^)*ĺ3LyI=[|ix0s3;8쒷}ޢcUèPVjTcdS}m`?ZnJ䛂εFZcZ^ģfz\oN~2ʥjenyᏻ+>EĜNkp!@h}y_cw`4.Ƕfs w}l=/漽ֱׇBbi?ff=5ǕT2aO!R|/°iw&=ޙ{jhCk飔GӌŵuO}_cbQv ~KX\0Lt,ePV6@5Ř_iD6}h8;vNWC` S14"}洄g,eGe_~[ձͪ/%1'4'[&O[\m^c$2п+ySEz`av.x]vG5uK3c2dﮘTmyf(@Rv([?.=)M܂ߋSf GaY#f ^^u#RE{_?ZK/zSԚ7+[vwt^vk*sÄԒ"?0^'WDN|ן:M3ʷJe}&lZoEf~4é_=t\TV=x<=$*V/ͺ]*qz=/)Z`z:{^r2u0R_Z%o"mUzB>EP'>P+$clEA`Ăy<1,'n9 lCL<%5; Dҩ^2#=K3Ɣ>dw;=#CT˧phY * R/L)opU Wͷi םYϖ$ҳǎʐ'$(4͂kro*OX_fkn¿uԳ=hÌ 0ƙ3uY$K!B>aVE Ý7v)1U싖!8?Oj%:@a/k*mu #59Z\O~[y6X֜OfVlx5-Iy9f$V ShޢsyuY@Gt}0]+moł(YY'hq睔I\эQhSg &*1|7H/%y!SU0G4,\g[ͱj(6Dxĸ[u)0>si}e=ƍi;x3\J@ը҆ѡyVmPDz{DqRQ{J[!}Sű[xaq:Y2fb/ZuVQ /. '̀>([^ e^lp|>,KPaI:2uB@* ^`_ۻ[shH!;x;ֆE+֖=\ ybBT١_߸!umM؏֕(7UaOdIng`:e$BѩUsQ55g ^ۡLXH0jڻp'0Cx(i;,<5pt%$5gfYs/ ֺC'e0 nӃ X+7nZ%"FJoh)@ 0njbO8νVlr|`o9}ߙ#fM=T}AF{Hh&N}2TuC"3dIzyypF|LJIPF[!ڳ0\xX郲8Ł *iĭj37ncc)JBNF%BcOQ֛ٱ\:AHod6[[#C4`wSpKfSKٹNa e;Es00!{>bҟ۴ _¶vBq w OB>R\?_^sxmbx"wĪo: gH«LiJn0Pΐ\U XJ2$9)gϠ-pc,V1*=6Q'CʘN-Qo+[;񙭔SXaTɀ0T`ST1p)%DkGt."_=q;p#ؓ]#qbwԀJ#On Qhd ->Y#. X;o/cжn'oaoJtb9f%D0>jZҙԢ-vxh9Hm1%k?)0Т,[f'wE6~*,xSn.ý@ :K c,ɗxf ?tvj3xGYsc5ʏݔ!(NK6`߂/W/b4HsZgrL:%a'X#A=Բp|;Wv TEyҧPUE+M$1p76zηh/}Nk`Y/R&5E0k#VF(#܄zd]m(9v_tH;@p%.P&J^qV6qQ k%0ޏJ\"'}!NNQ: qYcNsb&Gxt.(4]磣mأQxRK00[$W0&[.F5[]^@C3k([sA{:#1_(,)}f}F6d35j^!yV9\ПS1w4;lzN*8[qLMF9/+&uo _O^-pte;n.^Uwm]JGD &Xw-UvR곆/dwU'K0yL7 88mjMhZ*}&q#tjYf)ǽOLB$؇7\br\Ƕ$!nѧʤ-NJ t~[;! ]ƇtvV<6dX(b ,7dQۨU=FEK>WQ?} ]"9<&pPIXˎ'[nRT˯67xA+DKS]Te-_9507Fn*ViZ_zKVhʘ] {a>QDbcGmi f~}F˔C8=ƭ.#?U|V8H^*y'P"S.StzHyj4`5SornꦸfUӷcv_]@ ̤y_'g̤E4vwɁ}51Bk|#G`fSIЦ2?q6'bՍL7Z{bמ{w\z˞Tu7҃[D6qHKlξy?@&(\UZf\x$Zhfsw,z5?߾a}оd=E/}{Si?_;x| 䈩T5U7(GزX.^rfnTQ*MWMT%RvxF\UlQؖlXhw}QSNRfҭ41ʸ?֪AEIa/}F[90Q \j1Q+JtFE6()6o]QzWĩ.KXlϫH4񺢿ZbAM΅k| x`&FW``73Y4IA~I[X?"J48탆&}&.F /-!|W6\ cB<MaQYO2q Kv ؉S1y)c.68(FvHQ)D6XhEDK'3ڳ\;D++8>C36ͻ-\9 pL+3t*7?e71IR\o#uq޿gۄ?V2L0&"!#Dinڲ'K)07 Er98nDb`1<|q_u=KyQiK2NרUS:4] o(({[v 4]}3Nyk0 5_]N~Lt&1 >0NY^S|/گ@Sy%yJs.?LF;H|_0G!w񯋁L:H8mtEfo8V~;t\U|&/2A7 yL%NAfa߈B?5P%;/ M2d ՗%PZd!0jHƿ.`9AFb?z\D*i8sd wfEa )f4<L펄lTD֘T Zʄ&맩yxHދָY(BH$W*[ړtdE?߃wKR8.TN{l0B9egA3Kl|e: |R[l{G)$ЦQ+; PC7fBԔ+zg#^^`2Lt=hN*ϐ/ KTسM o0I-SYԬG(0aΜ(b 0T1yȚp)K P%GoC$W&zeT.pT s"_S͍ѹ*vh1x/6Ӄs%g908bXl, gl-`ib.SEç0/6V ̦ NgCCev=+\d Opepy!y*+K:l:bp%Nͳ)ޒ; s> 0'=д7:6@k+L z}o3[,_;6i@:*(_/XG3lvKwU0 4ҡ{aĤ] t{.c`oUyb VmvzTAn̫4I[1*tDabe vY"eЁ#|3N톴|N(eufVkCI2K;Z2sиQ^̬7LyPLTCv<̲{B50od]b1` H` >Rpd 5U_¹^8A twji $bxZuې}g":RUjw.tT7 ļd869|M#!`y\ֽZ|R!t Z'ʿRê[s&@HAM aܦPa+heR2vVYQAjz ;>%^cymiVZ0X)qR"Q:/VTBp3G~xfc`^=33Ÿbg,{F iY%#ev%+IRQ<6M}}e1T# KM)<t!35ߵ w7 yL&݄BwbҕAl E ־޹TFnEo7RL>>f;#Ax6E杆>;Lon׮jmFoj,\"53ٻ Bئٹ{q( ´br TjczE2:]1ܓs*` m@YL]9rw'}`a1/u'xbn#+ȐςuxPnU֌DEI>PEVH;h^>k34YbR[Ã. p7HhIJTO.[9[![.J˳n@-r\1|ՖFPkwM|x u:`s0ބMjzrv o憴G[k˟#XkEP~Mmާy+' DGVJͨi_UcVO]'+m_jeho-2E-”$`6]jٜ6CV`,^CjUeObDA~1ô' _ LWDլjOk77oޫs-UO.q]5Bjخ;`v"SrM)&12R*7h.wLO0n./}{3GS"`UUR6zW$TG< %]a,-m]Fsc@{X5 8x#邋>kqaQ] iYVs%&>v+ui^53]"V;u=Mn1qr)lǩk gcD_F5hfRxjdꏎfy,tQ5]mѺ+UoR.s5ΐYNz~uf~ŠM9:e ƧuHU$74>#y3zpl<=IyQ|E33*;,Aq܍@SwZO"W.l޻7_0Lhݑ>+(Q:[umK;S 3x+5 @`7كr֪=_3J+> 6h6:VX%sl9Wα S"g++C<&$a Hrj !A Q.Kjk:w ΚC.n4#{mdSt[)Z-[;:O'ՠo83nhߥc6 3?YGޣ4=^ lm/>zSZ?bs/ B\Tot2EC(ި˒Aa NW!ߥȅ7THt'4J, X@m.g$E╿\ixb;aChBj@p6"v=z]oR\]W; f"$_^+ ɾNG6|%䞓jNu3a/07OvWTůEJe0-Eh\Q+ 4nD]踪q'YwUGޘk<,bba\hE(%Rb 3 )JPHKBgYk!-`Aa*o&'x%^Qn:_߽YSvsSf}EVsjBLd$z鲟cIHEY[I !dc{=R 1 M^f1lHA ԡohȍw@)J J42ܨ^TWLS#>3LYkS Br߇!qV5)c&t_%`<7]_XW:R1Ftk!s!Ph x)O?eE]+L6n̠("@gѯQ<$#!]<54zd@PAiRg Xp4a_[,\-J|ѱT |f\~tPkYIZ2WPEh&(5RyPa_7C*FU5;w8yT~%_jluxn.%/B^SW m oV W}H.#) &C||I;3䲚w$ը*3SpSkXدʾp)H3E~,x:Jq`4gրbnuYHm([\B+L:qw%y(M~C5PGE<;.Bc;_m Ic5@**9ZJpicDz_cگ;Cą̎Do$_"qיHMrrP@LKꐩE,vr PtHX 1ߜ֦Yv\65(1W*heQUKsjSlCU.k^|b)oqWB))\WLh>ZrN_eT@%.TY٭ ItWbJԗ072͡ǐ|by߰v ꐮX3 RTkg;=P5&8JlDR+$-/l/ Rnx7ŦMw=P2ڕkJ f֎:ygBYġZڲV 6mokx6nXoI&IJ~ Óck.R#+qNYYzpPj&Cj$ߚdQVGoejt-䘕EU qX ąћÊߖ,^kS@c)Uzרp*)o;$ =(5rr)6F$5Uޝ̀:]#&uvS #a,M7r9/DJwO^N*HOlC,RM;K_ެC]X7*| -]1А1VB%PZ^2d/h)+8xnPF8^;d#\9~|ϒMyIXIFCD콜q!^+_H`+e9cľ}~*!oO.DxKΑH˳0-8jbU]pk`$Jr'4 JL*fɭ10zO<]kF꧖Pyt 띙](z@ng OZYې(3S +͘&މeU- $ $C+XCԘw ?߳_Z@r>eG[4g} ޻ `0; m)fA2'Ga0Eԁh39κ?8c(Q}e"`q:ЪZXyI$t [Xve6c ś|LO&qZhyqò !ܔ.s1,/;BBhS}}vى&CX8yH'2NDGڦKeqvŽG7mܢuVgh)bjx24C 3('x߻[Ebd.wp1!iQ}rK7 4VQr15HGwNJNzt8Q9^h$Gk|.d6LnW7 >(X)t n6+g'#D=zmW!r!p6{=xiDKqKβp !'ZyFڬFHly0癮JVI 8~uġҖprK踐'Ɓvm4c:'&r6-aZ'ΣO&y1o#f7ug=Ck%4fh^] zPGk(-E 9NIwoEP; xbn$J1+Oh=]Ӯ1j!3uNF(&T҄h$.RZ:%Á hWm%QW&ja8)uIP.uѲy|,92kPqUvхy\V.=%UVCZlS08~sN'=S6ϙ~Daˆɵ_wi:OJJ2jȬ}lt]e:&W'{wtǿ.rAgЊ-oQCKZ)~4~5?vx=vqF))$'e}q|]зyuC`l*}y›6VF(L"Sۍ26"`y[>_w4ʟ)r#]NI1+״Jg;i|v"텳n7Gt&-!sZZ- -R6"_: wTd& H*N, GE2o}Lܛ'bqtQ5O:m2Y*]hD/ VQՇd9,x|ck`<~U ߁ j學d!&3Ŭ!0LBՌ!]+ZKc!fOP1"p5m?$ƻwcI)k jKs+E;p$  fG ZIO1v,Yo@WxeZEus-V(W^虵YzĚ(lsI_ʔwV~+LV]jsU{X79pE4kZMZ"sj>gfY_Jil(5t*4̙_y.S V_|b)ze޲eXI_0gXhb*zqUIHE:hl_Z P)?iJ#)B'~]z lQAׁȳ"A19P"Bד-Zbu5Y.UasWI%G\3a\4X?jgm[Nĭ}ٿ{5#͜g|;tUYMk޻!L/t.g0|k-(.9XKKLel2*:FXD-[ 4FU#X%9aNJʦR҉6Q)BRa$@Dߡl@QGTD@71P7״2RYʅG"5]$KFidpUw7syx]t=}Hgb^{<۰Sk=2UʔrX!lim"imbdcs]̤(jѠ[(N#{Ȱm1ӺfUfZ[VFل8 Nҳ~ ʐ7k"E \˷Ul8t5` =D3y^2Aj4&{($W,E+=p*I v'.h y J9Ŷ}f&+Z.Z}S獊5``^ %All aNץ&$aܬLhb<{Țb[ƴ/؎R \e7>xȆ5 tU +3:%OWvIkE'5(mY., Qwm s\¾;`рI:al`h `mӻyg&-SS~-2=I죻s̚gz{uGh3dYPZr|s{^ijݬTvYqS %6`Jٓ(s c^v w}[gK= e^7ES%.==" SfsQc(e-k>)܂JAfl{7bigu3Fޏ}ZYS[܉#N6,+R%TJ7{y5_3V8l)@!a?mq,(ǣq>,x5Q܃Oe?1+b81;upClC JdRN xr-T]U5[Fk7&ˆmewտ&~J3å/ {c3ߕ>U͌/:ӵujYÊ+|QXʃ׈jSfouZiGaڞvD.uԽnݑ?X]T2ɁP3D%lLpuqpLcwp#+:7;q{8]pt$ #(7dO"0JldՖI*5hsAL,O)+:JF4y_ ~(oWÙt p9Az vPWF:x[W]V]mI.7t6x*˺{)Mj#+z>ZՔ@ EX.8p̫>\3#JDa'<+@ J&3Rg(>8fUNF s}8玲Q3VunPR!uwry`Qe뛯*Mp/u45w.bS6R<=&8z BCxIy]fi.k2sn\Ѐ+ }D6DLq $ 2U3 Al?F2 8F9 F %[ngf^ܼʹtwpőb)nZF?+%XWYSeã/0Ӹt(5ȹ(VS_"ǝzmQ)V-ptL2c1+\`72 {Ϲkh3jLh\ԇdc~kx<:1^W={߭ \˖!BpHUW"h9@s.kg'̐!M-nw<۞tZ>#y/G@qQ>I+is,Sj|-?iҮ޻q[' A3>/Q*gJ1 >l7Q$2i.?αx."lvUVlV ָCfr%7(~F,L5ojo\.vV<&@lxlW-׻rhښ- WPJWHp {Q]} E%é޻SA6CϨ#aԯhi3R whqW.5'0ޖjgyWR٤NoGކ28sumkE -~=D;oڷz;^Y',놼\t۔\j=Vzg44yKª퉢!}eԇ2Ry}&2ɒUKm*lԯeܑɞ-֘S#w%OgS|%?io'kzn*{sSwf39,Uhx!*XזJBHK/>0Nn*U[UrZt/VsN}bBu[!Lf n,0$S\l 4JQ,`X;d;d&Ԇ^f~qn6[j~,hT+e"0#qqj+w^ߒM? 袔t{Cݽ H;oqL0!. Gφ n{ɓoc`xzTx/zxB$r-rl]?YP]U[ fpq(}\.ֲ UxW=A |)6ݘT>Tٿĺ;S8a˟5FwdR/žM[˽Sod*4Zj(Fك;[_+ֵ֊VG4m0R EG](QLMϥFYP#bpiMM.N)åyzJBmw˻YD~1׋}U\蜉Ù#6[AXZ?/Tpoׇo[*7{Zwfs+ &z;q#1p'ŤwQ`,Az6Uԡk.8E@уJ*4XOYi!*]tij_*Gv?JXҷGKڄ(F6PuF&T| S7!4XÕעO}7ߚ{fY| pbMj=ԖfM&I#Mϛ0m L+!/5ęNLx m qx6q tJ)XKδ2˕6o nU (: GzgTzjg 9 _ړ90Uac )Z;'Q?7s߻͠t"QWW6G$SB Xm.e@ANoF I|=&Ȟfu'7<QCB6'p`#B猜꽈i V|(K W?x蹊 bN!2i*v^S~\6 Nd;2d \9hO(HyOߪ{MɇbnrȰNH#@f\T sl^%>>7ۯ*?fL[[Txk5Wоyaի5|Bƴ'VͥȤgY y؊ˁH$nPCN 7˱VCI^@(ޖCm͢Y|6(LjV2[96A۰/N=N:!onSʹt^\l!:iw?r\l/R'6k4|$մ 6!&mZ DpLq'q)uI ܜ!4'I7D:-Au4rE+m\0)V:Va7D`J8O)!9,LE[IGĻNq :Gҷ,>Bh$[g\w݋ !v;C~L|1LF7E7Nk~u|P̿NW Gkν #u) I0SSžPw̜53_ƅمg6֡k(LM&DʀO~ܗϦ) Cݴ4*uTҴ2G"D\^ ^wy69"EIYX`͒vYت &"#V DxK kj}ZNrQ&D.PLWF÷E?OhFNK yWPbf:mnےcv8^_Rv>Ȃ+a W~&#+gW^1$4 K"Ͷ#YG߁ nS WV6[C %eP+cxy(v Z&/tqU_S,Zqn}R .ADkbB#&^GaN&.B,jў pEZ.@$nMկaqQh[It_sGyJ1 l`lP$CLgkv6&œ[Rz985NC䪪>u_7KLT-_rђb|L%6AA37HdY )Y,`xeaW"ֳ`҆/{`.R6 M5,2m&T 9&ޟb24 05X{'\;CQZSLեYMm4 ݎFrםgY{sju*>$ه0&pkvoIq:~UңGZ&:E53SY?t \s!l0fem*G䷱.M0VQ$ 3x~C {L3ry`"i(T'E$@i O=? a1&G !xq/QPZ\)h&l)V379 ?QXLX$QoB_'& ٿnU&>3g:E dI# AzLBd-nNYd`:Jekjה_v __!E}Ȇ=\ d2;^9c6gP(TZ>/oxo@*kbjH@a!#cR Gii5wVRD_{q8dzb{mY!'~co˧`V+{ƞS Ѐ_jb&|*Z/J.QV˴PBùzʙ]e{jP-BfX0RbuXWvft42GY}9(AΦDnB,N^~W+K -aEקMܮVM# F>w «ήa[6rP ˷)j+zA8j:kowݹmŦ%I \/8&9>o:zA+maݏX@qA1{C^v@uhՎ^@"2hʀx%fIgɆ9TfT,Cn\Ň*a>r87Jdy+OBID/ mK"Li)za?/c5ֈ҆y;[g/meWbESO/ pW\_oKm[|4NQAyPU;٢-;B7Gd>[+r=O^%I/!M}&ZxA @w.ՑONSְ WcgQ Q֢> A!|9oZEY`Ќ͈ Tn@6š Z_6ݱQtʤסytQ@rQ!)2e 7x3K9d^&k 3;5ye(J l՞Oh/KDpzET sd' MP)W{]D}x{a՛ Sr~VL6 Bm|槾dX K |VieTb(c0d`6C*qƃcgMO&;)g,a==@z^tФ1&W@G1އ#jvC0!/KO|ȍB+0f%!};9o 3Jצ s6Ui !$锑VJu^c|tvv?6k*83i؀xYN>֦mK68~`/>,S + VG?^!b<`k'J'ڀ\ua7XaPS]O߁D J{P~Du} xo%Xo IЊ ż)G:yW)R*zd ;3h<=Bhjk{]rg`JjW=!84rg1N9tJsz Y@hIE&gIv~~\ ȩCy5 k: !-J1.E+wS!Qv%wfo9]U?-hk189UBwmtjγ[o_|.L/5Dߵ}CBU.Y_=˰[j zyfdsȳꞭ$Sm{.86g=Cz{^hl|zV7 r۱ ވ ` =—)Y֦FE?<ԯ"դX%E80vk_:G:(vē[7o/=v]pXVhޚ喼<+I ~I(1iV] ݒ!>|(^G+L5= ӂ90CČ[,tFӓG+Hlo_]bi,8<4} a`dE\m2ߊ9 te፺apL͗MzLJ7RF. ׾V nIZYfP+L}vbjYs遧Qp)ʮ9_R/N ?aH帯N_P"c㢶˅u 5@߾c?v" e9AX ZFgDYqJKf4 'r69 *2W5Vm7ko|inu1Z,Bp}ej74 iKCXrAډ_GNK(z"Q>X}V&-Cq;^idYi8;hGdc,˰h S2s2!@MD㨆jB<&pB- xadU}z!cYC;5R:C270I!'S[?g^UX_4Xl"3\?"-`Gn_5008/HrIF< ltjܗu:3agv۶?:]fj?1o'l،r|!Q a% &&o%b =#c{.U8NiB5*"t^=eI0].V1؈2۔@2ʗS,i"t8⬰<K9?kfhjPhY\ѽaoFvʆٻDb/+{p8:V5SDMaP|f E8SAa6LW+.tBRB\⤛{Jl%%Ā8hf ZS-TrW"μtOfϽLF'SN#"I6:7Y{ec"c_Cm,Kɥ/@(e N6YBZ''c]LbH.+2 z:!̦jmUh8qT4 wRR5SOo@az}]KŽ lo;]vh; ;S{#R'/,ȡ~E8 *Ѱ/!9º8,w)ǖ*؆h ;CiuYX%00ƭ%A 8>tx9d"/+s>٫wiUyd{>*)3#,%ӀywŽ<.rf-g߰J7ee/ ub#0Ýu:IU#V1!u/s3i[_fc QƤoYllB36h\aE,БB-$s=6#7v^Wڊޔ77Iι4ѷ)[_f9: aq9q+_ $^>O-t7Oz85= siҬn#'6IP6bȔ-~80ӥ9.#JzVt%緹oMw=LA(xK#`X9YDz5s)fPu=P}6tU[WNOl,\/ Vu"ɑCq>%x3Y5Z/>p)eo"I ?tsjVoz^n==#O<=_6?/:^Į^A,rӨmǕBង!n$ 41󍇸s6Pڮ6>93-d*xxG䞭Jh0`_"Jq;rJ=-ہzҿ# IZQͅgΈGnQNI뿖싂7W q!Agy(gR/IlG.|>LY2e{U󫄐[?@=/i)Wo! nީL+@)3&gl\B߶Zu-Ukn[ >#8AqCWKNLa G1+6iY 4 [5+T VyIk F&[]P@rx_uWXq{$vg4H8٠3&m uzgb iIk~YoL#*%;`(0UQTm!-~$dP=ڌ?s=m ;g`]7@.蝩 (- 9A qǯ VS/Qwbݿ8>LY-a=Ý>4jYt%yQ=MÕ,;2WꭰHHQXR*l9g툇W_gJx[`){ˋؙwGbK ɘO29&00@!d|йd(Hxz3p N@F"!^O`GמBdda䢰Vz{ۅ>L~O=q خ%SH3-0Ϡ J_Az8:xntEZ:3l:s̨@,=@p9V15l[vت%lk-uv&U`օwD{YE4 $$Z:w *]J7BO?'XnD-ͅ8tX4mtD~-bmofH7\0 L%TٷFym&W'zyJ-a$!;)@Mo@!uػ `=51RP=u+*^7z6#l|s<-IvZ% vݱ]m>{zQP(뗇-e*~_C;ˎp<ŎL2 l|b'tYMIҍ6P-:fLM`Pϼ2rTVD`XiafwIa| E~$m1lYZن<' *(;-#xJTZ1 DFIbS6U"@ۿ )9!vz~PC8!M]w4hfӾN)k*+z>/ޮxf_|Fro%kb `V0!M,+.3Ϡύ!F4,~lޑŸ:kk`dE':0/:0C 9*hWX#ـ\`/зJ,ok~eϒ))@]y9D0._,x yq%Aܘ.mCӠ>N>&|} 9T 7G_Sj3nqՍcŖڙ{-EC Z|}hQ*GԌDBfSLK.$Bl _ͧ0PV+p.%\|,~28c͇@unWG,7̶7@St W& i{5!M{?rV0”5M%(#O@vmD9qt0D+2sꡚ XR:tTbXe&>1D.A,M ̥(ݺ '%Z>r^d#C9>BzÍ#Kچ%;ҡq_V<ZEPkB4{=yu֨s %Hsl)| (yȭ%هDI t8f9Kt.kdu\tiߪ]}c[T||K%/U2z}[GYeuuo'[Qmۀ`9ѐnk,{T(&'y$eI6Ys򌸀1,0Ǐת" i^AؐbI }^Ek?M)9:5{ ~p5Hog>#7cJ=l4ǟ7rɁ2 Jѕ95ikme[c3 go 2\}0d͙Qkp}a:bАO^:䓊f3%Q!dh9#Fs1K۲4 k(2e9ՔלQ3.d)󭙗_ FѹBkl#ݵ9,XvEwV`%R(&9$P~)[D䵚!}׉=pēnF=Ap6W!#`%I C?Az|,GT A"7+rjh@N:r! e&MpuLHSNt#ۉd-;DR'Jz0s|j*v$ԮUd)]اc&i~Rk/M%BHDR1. -!A+B'׿ɎWÏc^Y Q0{e#dr+߰zz6dDxR)ր̪5S jhFѶ 5re!3P>@*ZDkܿ:+:G-mH3Lz( T\MA3ل>RЄt56M_(7`BbAA}Ti{. qBؐ)9c/̵/.mABAV\\-.{"¤NЊ,SLw:;P#2_ByN"BJ]͞ @S?{K"j!\=  )6ACKqZv9Uwsj t#^M:xVrGGU%/P»[Ú[t~5~NxUS+ - [C[sRROPɗtVO?n;xH'. ~6 {GdJl.X _;`3nhDx{ĂoTz1Z{bd'dn;};&ܕ+TeIe*R>ad kͯL?ё $c 2f~s# F7F4#50t2U<ًK bT.FHɉZ Z^Nʆ!XmhGXk,Y}qiRǔ[5~anۯ&@`s9iGKΔZj";L^,t2uZ.Y^YHo1/Y(3@famJD2t<q[9=x YްmejS7c"0tu6_*:NX~) 1{!Lr:R@O(kfG1qɽqHBe D詰EG$XAX1HUό#/ P:pL1ٓ;bY0{*דǿXfcmc7ۘD9` *EY9)$7 Z04zd9l|Z )5E|)/{T d0"rXdN&Q=F%҅ïeE)rWFw(FU{ر˘x]nUY8/XEB|^%vdD %4^2WldavfH.Ö210v$${=EW~q=v]ո-5 TP9Evm4 ":t(wWl*IKzUH7^yZ󞐡O b :_n< tR$| &h!ZÄ.ʌ.BĪP8:g-;o-9:?QP[ٖ(V6}[Y>UgƁMZDi٬}1ƻMx8kjmxC1&v?C9$.aUq1x4 ^ z +~񗻓2f5$34`GCvϣl'!m3dP,:l_0Xiv9olJbt}4DB-TF輽9! 6Ѧ"Eɂ Fv q_SFuF][1|9m&h{JDK*;P0ݳNXU.]^X@p}7!:%xḯkTUP):&᥇$k7S_Z9kn3))4KaV[B׈,L>ϲ~8 {PBjjaf- d(ħN{d70+9ջoadm ;oKҜܺCQz%j={?-֢I |NV_\)[g9wBZ=/`ƴ&i.(Tw]Y*4npjq*jkakH1p ^ldI&G78bWT8 pf Ghx޼B"ߌs7CcZɅzs(tEҴn:k%!ܧ!K>+,&}3e@ʠk۝qLBӾ G@u1ot͠,Nt>YfD@3=,S JTĞt 9Z f.3..i\iʢNKǽk?={x¹ҲǍ'YHs>_SW[U 'I *|=CMrUq͇+i3Xo63iܼ0!pW̥-4lxR]=o.~+*r>c3-» +.b_>?+r MwI=`6fo-s|7֒Gc#Ouc~fKHpG]3Nr&Gn(Hҟ7v-OnSHU" mBS~DbxG  AlX+zZ*2xVc`eA:S$$nVCiz|cc>g֚k.=g/Co1\%yyE>H_Dh;>4Sήt`͟cM[xd FmP`%I z?O?:bUNJSikvFe]"\Q2.N%iEZ?,IoqN4[\'6oJO7F0-g{߮>nOWEZLlJo)|hvXRm,X1U;Oeh{qp$+Txz~\'擄Se x4+4| 3{i^RgcwXwȓ!fbYz̃N` kQwNW|;nWgu*Ty~i H?'ul,}X-ِ]s'Zd Pǐf,J"Ȣ>i!F=GdANskB{u-M(,W|sb%)y8/%΂{ @Z8 xc) v-F͎ [gyҙ^鮱;g&(ks}FhV(%WHTe܆w0iUo ф*UoY/q²vXlt9rsj#V0}U'u$t- [չިhMJmDc-wZ;737L"拆`*Qcȱ=4ė9ҿ~#K7rG)9yw;_K z`y{%0'GIbN |]LE'6-ȟj_iNu뺲oSaAOb/cbFbp:-X|Vcz4 Q=봓=Ca"[Q`PzyI3N):..Z"u6ҍpHVf*Ы!?ϫjX×A.^p Li= zö`vQzo- _VvTm3Ȅ`ɒ )ʤb wU ;,@;ʧe?;ʣa=6C&;|Hxj`yW{*ن0xTGYlv$\: *HԝU5n*4mfdeTH/î:DU4ć40rlhmRC)>!Nʣ^LLz/@R<I+: X5e6 _tSGuȷa'MT*#g"~tvԗ#xPeJh|zJ h}GJ Ȑ7Sx}B1 6/޿~ÓFvUjx#fe?D])O"F!kO?56X ^TL?,FIzD̍~L2hI tS~w)a}ב'f )p=R.^s >_jPQO[%|_G/J>ǽC^.cQO\nӲxk&.9zDiJbC2}\C &HP0P!e#QlJWfGd6m}8::57L=b?0E&p&h]YYsJ#ሀhu){ڑ OJfit /Nk7 c0\GIz Ƿo!&D@aRD&n/щ73m[)Zeb] uLav:,-8T+o2tz{ܸk@)r#4VZT|9{0|2prkw%)7 p.s/by3񀟎{,xf/[+xtuuR#S 9$5)4E~CRg!ox]ui)C/Ӓ2Ǿ@Sxa/U}G!VH%HÚŮK~Ck}SPkFqPSx7kĤz[|1%]I J_}/F.ӺMiA6W<2z$wlQ2^x?xs4^iRiy_h3QM?~ CpOeI˾9e˼ЏsI5n+zδ2)+6 ?!ҧB:{|=<\~z*/NR{$yAK2;xۗgUD!6~vLQ=WfHXII9FroǓ(Mu&#ۡCP@Bf 1z(7C=KwsziFMIQ&P}8egqNp,\mLTYmNpa3)<|l; mmp>;?69$LtzhF-0[ 0&0'+#Y;k4Kz[أT7ϕLߘӝe2u?K@1fh3 vO7$w0 s>ΡƔ\Ԡ} eBG_WR1׏v;>doOke)Qp1|DEOJ .3 o7o4 Jƛ|guWtߌ/Lb'k]+ު u:4<%h:}Bkc%^dˀ6[5c!mT󇦎/R;:-z\hdopD0@}oYFY8YPzCv~h=48:qڢB޾omII^3['ՠ@h_~5e⛻k=uӅrj_bض D۸,*̯5D!(qy6~-jϪ9'H~aB0x? >MAG]r[lgx;w1ߨrtt*t4ǛjԮ^N\ҕs~)O0 詣핫w﹘Ajr,x9Aܺ-܄d<dȘY~ޗ٩(mʋtf.j|olƒax2xКK`RY2>)mQa-o:?LbDȏXiHSΎN=2F=`eUsbQfLʶ-4a:R,|K6{ȣrv921rE׆0we-:,& U TSA*Kӫ!; G#yO,oP-ּmvBc׭(漶]~}"GX:mA9 t';= |_lzUJ'*]o -/4GJⳓ*-ΗSd69xM)"\*kc9x_>PRZu@ DAa/\d_w=li~)J dOtB˞iԗp㓠67~;? 0ɒ>%%v1_'К3 r9}{#@Y -,ܕbe^%:qe ) 9s5ژU*)`= ɏcVdh,ީeEu_s߉#B :P,חɂ+_wv¯_uERxFN1=5MHb{E׹lpFx"qQr`]]W]_d{s/t` =YƶѡLgBAc\)/ח@2߻|+&zLyCoWO J oyt#N{"QtyOvv WOxxm{ּ:|/u ԛu§*$usÉ{|'d cd(Ezzr%Y+m[i28ָ;~.fb[l>\~z{zܩgt{;ip+PPnj@ 8(w_K=5?7Ԯ[Юkݭ;LC.f5џnxx/*T^*NQ/q$ȇȹZ蝟PIx {3إGb?CվqK0+<![9i\|PEnDfB;KCQ 婴恙!GC6jKq#ߚKqKnԌjަY#yu؄O *DP:f' M65c z$:XcԬŃF;d`*Ϻ4/xFZX :wr R}w-aY}lƑp]X5INĠZ$Bto/iS(p| OYRWh>ۻ7ߙ:S#DaW7ib{l.t0lIWx%(Sg`j9M0c]D|Xc3"*:R35NX+HTLŃLuefߵ;Vx | y ߢ5_pffVemT$`< г4A^d>2]ݪ7hS?_"Q/zZDx;;#屫f ` ʹlSvs2ܝHp_pY=ҡ~ƨ7HuXEV Gc/AB5e.1 ]Bu*B<Ձ]\x,'/Aܿ f'I֙㖣owGrXg?9T-[TQ*)(=w"g7о }W |U~N;[x %#x%{g%>ID fW݃ȫ[g_Áŵ! )׊عK@XXYjk[;e]?Mt̒d]!'CBt +0Hל4ѽH 2F, Ѷ|!"2*쭖\ߨexGO%07QXY Qi4H f+|[*2+f+ٟ}5zN, +aɜ,?(:ChGmxᗛތJQvIZ!z|OƋDS$6 X73F~ݐds jK~0NUe5mg4xtKB3hr#g4X;YowW ^(ozxt |JG,yBz (I2P'`|ex<##u~kO3\HR{D$ޛ2D:ŏdfQ:6bqUVyKXJ, O5Fp LfzO,H]A.dVRת D-&o,{C,ayڹIՑ >gS| ;?7~~&iTH~6)ш,a$nQT au7D_;ݩ]ܨq\ x3Qc GbIH)zf(*vNW)= Vi|$phVu BdĺeD Y<6 =WnJ79Uf:Rsi(HuՖ|GtPL"V W3ٹ=|alWz(%Ga+>s/3IulP 2Cq1S~p2`GTb Lm= k)3*_,呔pDgi- NI1t31t4n6kI^j1$4r:%7Y#̙RܐKrS1&LeZ^`,<+_䓠TH!jO"N N"egQN ^&ǜŁ=fWWdN=@ c <^|a oA8QKBm. /~-ݞ` ˏ~`eXHTB2m.<#`6MrD~$C(9)9j8>ޟ&F,R~G+@@B{UK^ d?3:9,u҂ d uB{g$+Tr_[$Yykr E7N[2p9~RBbѓ̠=ْ~lW)o@LYV3>/q"hA}w A@p>twp$&1w -gfL@d0 hj9@\ `J9D`)ê(s]IMKXl &%A͡MF , A*?'a&vEׁ8 .l 02u_۸}2V\/?eKag3 jv^ 6aelA1yH́oeL;*ڨz5êɁK Ȥ.9JzmC.f!.JYfÔ8C*TU5zȩSߑ8 #e4ءND̀#te$N%<4ɢy>m&kO* tEnlorK-\5ʎ2k`}Xgr; |CZKi Fg 2M놣AYsł Q)W_-5+>m/Q|~JGԽO*d:#{OȬCPpDPDܑ+!+A#A{P  wkH 3͒RDXmk -^"h@Ba UCqg] !NH&4$ ̢ͤ.jyuAĬAWOr\4SX9]ApNVDl~4*.dC3n['ÚPiAJaPn^{Q>ĩ'Y^+u ms =EQJLT `J,`I =$oVB >?b?~@vDD a[!_gvK cDv".lŻFP \u 6#X}D'gs%N qP?Y+ ynHE. g]TJK-!2ykh6tb]5%{M=6{[XrsDnP@2!PIyWgtqŔy֋q ((DtS!~bPBnb+dj?>-g<.W ?;:=^`D6aq!ѫc]E?MQd3+'0$f=܇4x'b҈_ PT$;#jXVWRT VA!Ѥbc4JI,x;* Yyfc|U7BLEo?g\bN/bDb)CA4`BC3`v%t--aJ?,:[$<8U(Sq,B?jPJ?\:BcByW9\q;޸NcQ?ɁHH24@=q@O>/Vh L801?L焇p[+8p›wh|׳פ{{F_)ղ*EZ[O״{pQ"LjxJRDjLAyɛe 뺾B!kRɯ\woQS_-k;N Y<Y1~R1 't*{EOZ>ka=& {Ym{Ѓ/ڇ&2OrdN!HVG60郝DinM6B (2$O朅\W%\6+7%ӂ2h-&SۊXFR4u4Y<#2yoY*QCQNk<){|1=~5i(Mmq*%y">*;r!\mxR߱e4ENrD|eg]I;=>w;4gJ wm>o| Mo#|E~}u'$!9zh~E1;->5(s :K{~Fpizl/VJI팯a^9DQCcg{_{ژʭ9. O4ѥ?]:N2O$<'/VϞ/ ?9bmrZR'gֳiLFBf57t",l悞wwµɥ_1_ &Vdxfiftä' {1ɚ=9pztnmht0w`f˝ 8gGn.3z5W꺜ʮX\|5dIX6J&Xp&bIUBN<3)l{<UR'.WzMܗ8ãbm,0NN_x[ApDP(C|<%* o5XE@U=CRiF XJޝc_M**QNc܅P"B*v70gN3OTyLxY,pmX:FA yM8ڹP!M*l=~WJ~_@~cL/ pc~C Z*BNV~ 4ᶬW |P 0eY+!cƆC 7mhðĔo!"7C|4Ea`]!7<6*aՂ?$vTu,{E5dՄOPmY:~^:tϯL[nra5og/GD|,JKyɕHJg%!.UG'uB ԁn7Z]Suٗm'G)G*EB'Y᦬233RB|bw"G|β,4zfw" g8ckO&H4TszG R^E'0W$="&oxkWWMZV2E ++$ҁhEao+]b43de̾wǒF,cMQd"ȣBqV8|3Qam֍ϛ Q Se%ohUᐈCV 7/ڷSKJWj`.ӭ˯,~iLA )߅-h2_"UN$ o%x_#e)wӴ [Nȝ?B'&0צȑx$HqS^#fA_(YOL=Bv'HN<>[KHP?t`Ms_ך)(_2% trfd 쇄@cJQԭ"6n=!W"=!h~9!WPZ~VcjĊ nmBTy2+ek MS Ţ(jd B}5zcQ9{J)&ҺѱA~0miMsʫoh=}2ƿ [_cY^|ʱ_9Bu]\xTf&u1/'g \Xe4&&nk3r L2:,0j1ۍ z4uȅx: r|B`ZɈŸw`rF}!Zfoxwo!ȣAk:nAZgDF\8f*ۄAvMx#F]˛ѩ󡘤a44cwvCѯ @\O {%Qo&[vmsTwkո“",Kb VQs$oG~qMnu{4'z xhVik(fK*)=P MYoy})BB[()~LA`=9H0 Y3ؔk^&X omMXp,S)opj#**,f|dn9s"zS:SjwB`H`F:g_mLS(v/iމjX23oGu2hօ/lʦ[4pA/#m*; }wWSB-Pl~Uplâk_V?1w@VAX4j0:LvjF+DL MLڀ@' %07@:~#!p/ F>~hXO!e'@Էe 4KW/]Mne>0mINð8kc0"M,$ qTQ(pi _jM*~w)^ёT3P]J̽*®x̃]%E 7@b/?x& A"ܽqf'DaVMg?OC!HVW&S"(v ="! Dy44YzW-I$@u kʾu+hЪJKxmfu.@@'|Fz ?<%Z 9;i3}_aŪ D1!#L/ Z2;gMCkʱ!c1)[j@LW$OZxsTHʳd௖2{sX} xcTy$g&gnM.,Jh~"FR(]i=N ndC*k>?y%Sd&q ׄ쉭 x{| MYޠRxs-ڪ-=q!~2GKWa2i+IHcs5Z3VQՈӟ .d@RScjq;r1Wt@QվK8Iq4doQ`H}Ӫ~xgw\k9 Zьaᅤ˖MLK}8L"rWWb!$F˭8kTSd{N˵&g`#WL ?|" \iPX!@*d|ɓ5"6Ke%ln}AZ59H(b0TD͂ qɱB+S|'ᩍU\HyQj9- -m!(񖃯uyR-zyٱѡbP;q;ܽ1pyPY9#`T0;y'H=/AKmSUq~{EЗq['U$'"F'h`kdȈZwxmr=Bu7AըVиyqK_,J={>攬$4m9d;[jyDΐxH'J؅űH:! UV7QZ]y쇼 ʱ?m(ٴGPh%f{r>3񸸧N8(RK y=ĊԎ,G]&C@.֐kj$_꣕gUGT1Ecذ:Ʒ,U-hفDD^wb4o#w$ aJ-i >0k{Ōƌ|[iҹ/ ~so LqB$B-Gl7ÀR\%R/f]jQ#0"6 ]Yojk&zl]/rFE-<Y B{za Wq|`Q<-&Eyw mȠb{2\ƎR[VCetyjK5n`qA&QdPI &Vwy]<~+LtO7LW A A9[|][>l[(^==5J ʶx3z` <1/6n =Xp|B~='In& }l_0f䛂䙞E]??ccGjVoӛUOKB872$Q 2Zb_a2I ?Y: Q1i[4<ƚw։ m}%'kTZpAyFyrВI_2y䯾Orc\ж ^$]"X)A:({^%yF+M`=vBH@T?k?h ֊I+ׯUܚfnъ7zÌо+rO+P#zH>VT*#jqF_7r׵?3Rxᴲ>{ۡ?8&n,μ=^Tf$e-R/MIgcAp]#Fَ,F~uUžپ슩.>)2_Q- nGwh&q*G=?R8K 6t0HqsCHSa4ΗZݍqL4"g}XT(%V_(ĨwZ%W*(| q;X Bo C>yYKR*Ew ػZLɇ%hAPQg$;`T R +ȃul&v;Z`![ntDM~1IG[c(ԪS)P d٥C8\?H>M_S"؞1bܽW1w`b-|UCUUʒ' WGY:얬S䟚)$DhX7KyH4J2Q3WgbƜ]~E]uΒbJA2:c+Oa߅R~ f_wJ gK V|֘>BnBKgte]RNVO} "g2}gs) P>9Ov!CJVJ5@VЀz|<(FIZ h"%䳜AHlDx E*rdtx.AUtgۄNI44ƅ;^NCM.CVmۭͩOp7=0lUו9gn`h ,?꾍~Vs `)2Kk$ly1M-]t 8O*LlQn˧1;sB5@ǒΧL6,l~6 @R? ‘GMh:7SXdTOo}$J)0 RsOo'M<_h K5FF4PE9*|[ OUlPhFmhW!r5Id#gip!փtP}[ws8kSF& b005)+y~}6#B!ӝ{BX-ʷV.N\A mvyVCQ܎eBDc1OK]poiNy֡դpSӏKYKff|I?337M]&v! xʁ>Xu!U޸FWtXNUPiyix} w%ݱ4Miq%eR,đRa~ -7뫽U+$Kbd=]78#y&QE>(h%ZIcrucGF:(*+zvK .Ʋ TTQCiR|F b6JjgOh4aMhbvTZlh{L`I,=pE՟҃-}c<(o(N~Z0#dN \K9ŕpkQEX|L[+ %ҚwlZ{CBX2j77SǘH!g* [( 7zRwHZ9gB ĞiYyU=8E]'E^k6=CYx_|Nkm!rj@31./Ir`hLڊIXvZp0Ң9vY/+tvuYD>ȋ㙨_̑-i @Ә΢S_v<=D3-}{ah>r׋{9"p)ê_p 9+$Hgtĩ"ߗ]0)I4qCY91(&K@9g;X&FPjCM&b'k0M4#*Mp1[5N 5 ,Jo/V0K.BL GfG:RrZ$jJ5I /Bou!rC"cc?EUkn?Y͓L˜x>hֻ4j! e7D`Z.mM|@vvyk2Bw؛.)vN/{̑=z <kId}qr_RyXL}̈;綀M> gG||x-Edd3p(BRDi" Ni jq6# pdL sɊ=8GW=~/6ajNwB6;˻4 %C}PɁ+ND=6:k{k}h b"7P. ¿`OfDTvm=wG]OZ9-W$Lj/':N7L >Fqz \e'Iכ_!CmWXx9˪NZ(dvc Ce4]Nn3@tE<%OOB5S_K~ 6zؒP%^ʽUc<2T'm֗u'2;{q:_v1o^Ǣ};/ W$\BSʺ4(>kcvtRZX-K>Uz,RBһ.;Bh+Tmeun#v0&dנv,XwFJzsix<ʟUY`XT|5E1j0/bzw Wh10ܧwYF %c;P*I샲["7 kv7 /b *DuGl0b8ؽ0+ıL]iCIv} g88OÏ`DlJr%f(ߵJ'iT}6jdkjrSx )  1n[{D8K( _i)$~#hw9KS"bH.?a* [t0D:)cM \M3!0&8Es^lwh0 u?rWV?wẄuuɉ9pY[6R%HN~ x$^|qZƵϳ%ߓU]&0M9mbl݁U˾lH& b\;SL   BH)*#N-d'XuQgjbjwa~8Ye`o }9}[j(# Nql #,C ˟k\v/jV,0sW:[0jQ GBZo?&Ն[L;:|fȘRKCvEi*;s"tZ'8kYSвE#*O~_ hQ%e7M|l@3`*E4ВcQ<%^S.In Sy3wNnJW*^ fG3^4n]2'NuEƞ⧿6$mBdƔAG$J6D$p{ H/ ouBE$`t vry{yx] BtH 7QIrBnCCfGL,bъ(I+P8L'JR^~[6w,ukP= X`~x詹.Y=eW`4dğŞ$5 6Ƽd>qϳ%~8WŚ|Xz21әS'ˋ }?pj6E=1T?{QOaw|CP굏ߋ¶ WQ7sǛ`o?>}WesWW^^w/ kЛ}pFPe O> Wmb6 i%&W1ӵuP5_v.C ۫>R+-}zJۉj'ko=JwŕCTxcN4|,_-^_OgOA>DsZ@:ى9$pJ%)g7~*S}7m.D5\tgm qHsbIOa%ߎCŤ>l엾39T=7Y;}ZX/M0ȡC"Z,ٟJ̢C?$кXJ5G&=$$P=[ad:HkCsbsZT1 ZaxaVU|3cϯw\g8S?}9E޹ZuAf}TWRh_Tg[<]K5fX*A_46:}M[ \|ot' 1_WS#? Bl0wyKw菶 e=,ĮAxl3jCkT~Kyw]o썻j3P)hkPr.L9T{n^7{К74љkPq{jL <g+2Ə ^t-I_cH]#{By6+$X'^/=OO('=ݝ !=4)O;ޜh=glA%Rvp k='Fa|X">%x;< =]AiS ߃֞Gg>$>QI}ZBg~);||VOkҭ$78ɵJ#P' Gng[kqqJr B1Ag-*Zf| N̛JPLQLr&h haL@ l(:QQ ԴeuNr)w&uj^cZ8BEOm 1x#`޵pgemB3#u:2V!\F:|_ӊ.iϓZ msTJn9dScOlᕮs_\[/yEi\kn߅r-A"?9_9*7"ܴDki6M6y=ƀ: 2`=lQ{0vTMaB$qesIiTp.X"GKa m.\țQy]s+{iPQ'Y"_*Bܒ ->?qqGsqk]RQk1-U\?brFRKdoF:KZMp{_ۉ4d37*؝OW6S\NJg:]c_}Kx: };&;.3S|Ȼ2"z{%qlJ?o- 5BA41Ypl.3 i50e!:Qj ϭ=\[>(l^yڒ~ [I;W!C:soL{=9ȃGVÖ.TSX|HxIOa3;BIS՜{%|yZzWٔ1:' Ŵ,^*BE?o+U']_3SIm!O3{ oiuW۝H^I16>Mb$ 6k p`T gꀞ2c3ݟcY&GH ++d&H(nϰ6Q DO;ɠ> cv0)ZƐMj `1;u?i*3 zD[&W;sdSbhƎJϧ0:[%ݧxR0&f~K㠰䩰.+L2 \ _\[ ~|Kރ v̉[BҸAje_C;-p )57=TRggO| 3u..!X9?I'g\Y6 ]2Jy1HaYob շxž"ΏIvb[Pre@gAsHط9՟?bS4\CNecUwʒ4rdFLDlꪋTw#~sĵlf(a%1]qem+;l2g?{gOiհ(Ό\ pAbK}I s:D=8u!)1V{J۬JxV=K҅J~Ϟ [wWh`OnUĐjQ 7gߪpHy4W=M֦c4t0,\`;4nb%f/ʌ>*WS_0+4JW(rZ''׫켇& LF2շtm`nf.oVvMbc'I/WV/{+^$_}6>8t Vܡ?:)rk3BI,KKD?2C".Ex$ X#~j\D*̿N:^>,W*-®muP -8ח]GuQyUڦH!@Vfږ#㌡ZlcA>|,JwY5,Iv{TPo ¢)xH"Mj\ץzC3Ń/hǶ*T0H'v Fvg3E4o4׿9Q:ª9/b;O HRoQ7Q8(&OzWcXzKd<@AD,FB@`bWߙCؿ؆b *`\D.,a5U?8y]3@;H1oK#jfʡLُXLlٻCydmSouȎme)[؇D,Ff8M 2b39ZqH g0cY((q&#eS~xd1C^Qbq22M*Io$ N8a[$$&̦7|yt6f k^14G^@"܁mdAx9 " B(e+hcu` Lb$'Y\6/ANBdc'޸y@4r6ņJ`7;ߦ3sB4?Co]o~~O=N,%̸p%JI ˘kQe$j)hB87X*E!|[5`+]eԝ\&( ,}l! +gPڤ3#]X\͌nr pD3|vpˈT[7P.M1IKA)͇ǷKt3v-9 < QP2эXɎ)ޘ `fZN7}'[Khb -SpcRS2 zhmpS)唉@;76]CHY/]״lՎdL ! ^xdGVq_#V)EI#, s9L Ҟlr2A2@X*h;lC$a630ɩtVZ3tqꠊ1$’qVLM=!`xP)!Jn?fe yIAHbNEU1p0vL3a:!=oG>!Vc*F&MUQ h3填bT%fplcFZy~Rh;tg LkP=Ŗj(ծQGh>Z%B3_)c㇏ U0ɥ?$2k7FƗ BsNʞ9&[\O\;(2 3&ZN_,'b:F%3:%OWE;ݡb7W۫XbFFN " Ϻ'k@Q"7Oh3rDp9)i&9N ,Nӽ0G5"-s6kMjL 'BҡV gXMN6l8cHnԙu`-prqbt~3k"^Q_(T2RUdIgH{7N/!WPGR4xXvLj ar,4RU\`?RaUR y0߀9*hO"?jhE 5qm| Aʝ f@jy๐x7xGvtDH5z'~CKF0;ܬ/ZU7 >6=wd ?lE]Cu` Ah@N@C ~lbWN9$؁"fD6}X紭J2ͷҠ!5BE~,Tm )%G{cVaV}b+"LrAU{7C@b_Sp X'Bg=ޜpQJ9L@s6|- sSnªZZ40NI[QJ+8=zEj [{EËCp'oBaCx{Tm|M" [ uqCx߶Oؐa1\?\ rKv'Q50 #Иo!"G) Gft4@);?<Jvꨃ(V1ނzHt&|p2ɏp5θ=eNHuoAUM[z(9[kXRtz;D~G>xKZsLhC(`L8}f)UdJMGL w1 dw˕e?ǪNHM} $޽n,H3x^{#w|=%ּq6J1c6ѩK+sn+eM 'sRCFqiLV6)-RZ$4|F&8fs/.IxG~,1to E'(]za?$ıbCLQEDp .rKrx85l$NX^ Xx(W-F8Ldv{/GY~-ul{G[qeOiq ɰ UpsrnfuSp(~SjnA΋W&vy?b™ΟU6x= *-J7ށRDskv. KL}r)p[r,n :wLPA=ؕ;Axb{5ACa OdڨeͲȱK%F#v$lkgR3ߞh$-X߽1>|>9\zAGb~UrNo2q@jHKuYvߣv][~QYCw:\a'@ў$'Nkv'g=*Dԛ˛}ҺO}ͷQ~tcKwLE3@MP+U:CEN=%kkfJY'jsBUdNBc:{iwsS2/4?5,vgiS/KWimNN _Iw\ g&D5[i$ P35Z6`>dgݧlB*^Y5)\' } ʤ/.Q_ҙlO]87L>zzdvgᑌUvgw] vL y6D2|wIq<>|QReo8*lf@Zy4&{4|P_1m7,$9$ hicrߛkÎioBծ?SC [>||J}8SzȚ+]R#&p0IfIr7;6ARX,y1k5V8\^=idjo%\Ѹl."b3n`)im]caD_=E^~/7#F< =inrcѫ@ b+$׌bN1pd{Jiĵ;j;jÍ4rq/2˜#-`p.EQӭB@@Uwd&`ɠ& uwZIv IlMwd&J?#?h\:V9K2߉}ؓz' M+JɎ`/{d+N;R5qlQ̭ pCV:]rCْXZ[;?~070MFNSrKL|3;]C<lKbSմKRxg0;fA9L*𨾇tb|l_uˡLHj!wüD׻'K"ij \sFD| % oGcAJ+z0{r,n>>ɼM565DG1Žt—^ZǏ폷?зWQ,\%YjF zc<(3OND>|ن;==ߓ^(o7~;Zw+DDsBGHo"qЃP7l =MC:Kj*>6υՓa[妰<; ֪Af`2hF,'o m*ߣ,3I0pW{r'ӓ2_=1!ƴKm¯Qڳ\ HŝgD3}{F/&x54v@B(z}i$Fd4:UHGvkMD9u0/-g3V0Fg`)\H>uS;k;.}0pČ#M"J p;N|[OW}l\HB i\v(uI9%v iM]~;!EWpl4q' }8qSQI}Vx$U?s z \-6 ߫F7L]+F_Vլ)G#cYIDR0~Ϊ>~L22a/M3i>#S<&~N-eû{Do-?asb_ Aӗ7 JREN%}|B^Si|TRC6H}LJʎ+rҗǔ|;h≃!B&AD8}3i\-]sx|lLΌ8cKt@|EK_d$FGM%a΂ fv(2AE5vmn#|lQ7'YΨ~R ^;v=b'dKEج/[ ̹YP#<0]IJ2P`5Z&$DL!'@* B@C]d)mY #2A6Q&(-V!8A?1>_R"6qGm5a<$:Jeľ)> =qw^9/T2GƟ]-  jrC>RTkڕUcK/ c=:HrIXLa0"Jt8aj΄C5qy ߛMsC@uY7ӏ&M#Oj~zcxܾxXE9%z!vi*|K8AX).}r)c_]:-I& s1>$<~Y'}v>x=dD{ TK6l$!m^GGa/fN?{o0A)F` <|A'1ENwkQ@%Gg~MR ߟa?L]9#A5D nd+a=f@S/f#ܗB&(Ui$`=^|y-|tg{)O7ɜ#21o[3]ѠL],L/R \Q*1qB&8i֍]]j~r-1K'$aQugHa0*N^dVOdﵘ9;rqq-q`X*zKbO,PmǶU1<䏑0cZ TrtVc!&l5ɃT* ¦ (c1 t7Rk 0ӧ41L^O@Ň5ސvv0*{ա<{h[=?B8VϑHxeFS<E77]WAȳݝˁr25:&j0%_l,9f2~id @hO*RA/0H}oP>)Z hlb}^ wCj_|ɩ2EBzTLbg UJX]A -Э0;l4 e)v.1_`0.eCb ^KVw[TD-~[wZ5Y&a*طS:y'=M&U۟xfz{Mz1/q1e!t|ü{AVa.6QM'jaUEĿP _rT$ n;æ=j.PiZ3lЊtl7k[uu?| -H|Ӌ{̬TJl;aMd-{r.@j|TҌ[oRt$,5vś{&:qEj< q $+)I1x0o"?쳋,=k1ohD;ծyፇ{ǽ`y6擴N: 1_ Xҫl?!l$7@L1.ٵq\ `'euI˅2V"4_i.LkqmK\oGu#6nvH|I1s;5v^Z<3+EM* σڇo N';Uy@;=IT.*R6K& Bgv>{3^<Ւ:z G(Ouk=.+a;#z ˞@F;[#EPT73.8e7AlD!kZ_ՂO$(^:y[z'3:sx;6?A|a`OPł(B~@wTҮoa0p'(`68|3NKy-,#:%Sܳ ego*NuݢD:h=N)TMCgz~2d_[1rTƓoU3(Oe7Y GzESIƫ;"9P{YByM`З !Ar|6#y[ԏ:K쯸ý1*8{XiB6Y._]-kF1O#[:Y{M{xa*iMӖhU]pz8)7iBZG&f_53J0a]&/}6g|6.}W=277ҽ6N!SkoiI<ħGK.oHؔ |F~ c[-8ѧm|MkđΟP ? qLOKWo0N-0mGQ%N~];b>˖]ڍ>sC,]XޑWnK2e哠#-coEq(DN//Ig2#wplz'fxO/ٌ/P9{Z7ݫ^Y\F{ck(N[QlZ&*-ˡ;PIfzmd?3Ubbh"71a,; PO)f2RZYw([weʍhwszz9)C>H@3Йu6.*nbp.rEYjv<9(tHuD7FxxPNawiƇ#>耬2:O +PF_f_0̔"dxI Y`2{YVE"G0+5*?,o*?2 Ʉ!G˲JuY" EyY.!|+H,/|̄"Ծn{f9>jS8ދ|a f>OqH`d>TC%m^WܗܑTÔXY Hјp.{^0ڢA(OYAmp}-/VcHHEǧ!Zbi鯫D_F"7&`}݈0\72^E1q8+ )2q!굣Q\Ĉ6jTgf_^t W3FO_Q\G 1fwz#LwiHG*L:H0IOu, 0%&rvDK}cPڷ|VqJ9yxq neFUmJ%OL('U3n;p:3i"_V Ìlvs8s7PK3R߬YW^\>Zߥ,(R*fn9!;h{){īmcfU3B!Ƀ>o>1Ň(7HĚK.1ߤ^k{FxRè 7FpSxVL+Ȝw4/ ]@T(b/Ug%&A`ڬ~T\t931;RbxQ Ħ_&(}]w񆊴ћQ3ӃJ*ixU^ X--K9ƍ`<Ʀ0^[bb01,46#2zA#oXv`Y)~w[jECae ?43G ,_v`' }D20YD*X['tXGO#4lq(H8(1W8Z$ )F(ZNYewEx~(NH*4bQxb@BO)6pz}â*[;vLkĔ=ò3veRXJnN7cC+ȱf.j`f$*^7 Ugw*Bx=4/D-i -vx 4Vp\O DAtooHXQ$쟽;t!)B]tmhp99: GrI!%b3[dƢu@ \`:P3?,>:Dq?ոe]PLĩ6a4LOjNf6YOе- yV(rR2+)U)i4f1;W #ڋE%S3midŖѯ$l3h[E/r5LǒBjn b(KСK"lTfh&c#^IqӚݣsW7!9PF&ߕ?I{^J!`T+tS*|h!zQR 1%pgW=}IkMVi{MrKek:Zad(pSUb)S6e|UgaXᛱPzM@f +]-P9a~"<0Of7G2@ JhVZ R kWUF0<בe-zz'>5hL"?r oLc?Uæ4^QIBE5Wuaa`_ms]ѴR]ďʆbD#ũkG+0eV 8Bm &k)jF9oGj> <8ZZ aGHXYJS]`SV$tIf)W ګʠy&/}P3>P-_p_,:g+1O@+XòGִ4O>гUc;+6rJԇ& ,sLο6DA}#H+F f{ >T@<dfOt?o\PS woQPJ)N_##z)dlLM-8Vdg?pI)(@$Ptnd̊ń( [E[X&2ӡ<4 < 41 j~-PAcPGߎI 1܂i+$(tZӉSHJYT8\Mm0- 2_ ZԾfOiH; T v_} S@jƌT!)1sN= bQ:<ܸjw{qﲐ`my*̘q`Kz!`fFM8R~gLG+ 7NBxRZҏZC͝N0D+ 䪙sX9O4LQNBĆ+$"-hAo@SYt?vR>"֖%ü p~[T6g;AԶI/}dtCR-w}ǸnÄJ7Mlb^#RP ysHh}=VGJVֈ{?5džum k¬=i-)#{<4{ e[J~7RΝ6'='5q1]h6{-Ϙ8rEjWs=m+HSB[%!UGAeꔍ\92.Tm~48)J2om(zeDa3aG$Z]?I$Ȅy4ʋ#Dz%_ 瑿F_*?L%u_EI\qjCwSM\fo?ck˴(@}5Bwv72eJ olCILf k CtHEeM>QØ{{rqw/㯙7xqiu'3 ďb hX:ADJ=G#E8vcTٶ&f&WJ>. 03u iVoF *6YCc9 Jo۪Vn% +O+4"x{u`ZZWF㣁¹( WwXY*3T':#+EL~!$/1Ǵq(əB$'?M\U^WT1KA-7ʻա擤=oF Oat|łlXTQԃ&zL:$UؙU-s9@EsWݢa|˔t_𰼺G6{cĿ.f I,]O܅yu&#GХJ 8:UG>QTEXHnǡ-ʏzh;I}b=iLx$Kw^"<ի&gh|i1;2IsFEeTuiu&TyxB`?7e¤&g54jQ]hI!_vޥ_xwz(z$*8R1+Zƍ+SF49|:-qћOڀ [Bb "ꏩJ +{w?hm6JS2sXbIgG 7y9 ͭLlPπvNJ#?6H+!LwzRQTwب+͌J.艪b9Lym^RHk}r2a*Kst@R8<%RTs+kRJ3*0`axW$z<#a@=- s:-1;~c硹$t$3b ZW2Ri֦4,;T]"RDzS-?L tHe0-;%6riG=ZOgdwGj OT;bWO=o(ZEҫ)!jqc)S*PdOPZR]rzE VR ~3l\)FqJ5Kp:C+%ƪ1C?7-"{NE°[K!ȔЙäUH@AHw,p(A}Ezw"=}䕜BJ^_O~آ=~)OPMyQDDۅZBߠ%-(WjI kN}DJXn~ g;VP6S~ F_X)R-Av$ܠҀJyXH#kF5GzPV9~Zm,{(*SE i]< GzDZg+\g*9?E~(F8"w_3Lģpfg2{^@ťzWI~O6a=NX {YAq <j_A8pu.l\b) P ?-:[؂)(\MSݪL0BRK+C~B1 9DPw%ˮ;[׭;_yE: wY6bAu(+2'./Hף eD9EZ$4?~ ĝ:A4Po"? ;d3#w+?e Q%?GN\ѫ4IZC\yQJ)*)4QRfRxK.OSaQI#m(F3*)6:ӑಥ KJJя;2ds_ } /2Nt߀>R_QFM /YzXVUt>e@*V+ t \06i\[(غ*A[ڈ $`)[XS߳R!8 R{ vث/v*O]U$S<\t%ٜC:MaXoꤋ _MV%/])M?_jeN=47JPe?$4 @}ېxᙝl=ߴzy&gwvBȦoy^;lt;-\Iޥ۾t=JN FUk,3vj9w86v$S^+\nT9h]85s Y.O 肾e)yrWoGZxJ]>މԚxeۜ<{=uMxv;w*8zٚ|^ӻ1mb{vtC{aޭS8֧#͹} ƕg=:́ f#ƱO^%) FО{mn_wNv$o~nm|4C?UX*\>t_:E`pL>{#xϺVzApi+:R:ӗQ2ƈ9MeuKvup1^D[mܨ3"rϕEwRfw#P/Iuf9Z 4FrZ2 \ٛڏppc2S{!L.iG}ҕY;]gviwhCv- >ݴR Mg Yb(O:Z Cy$*L1;ـ2pt+(qMSھmЙ6P+˧/ֺ<2:Qaa fJR;Q@sCz4,uˬ;yS gzn̬}K0%,u UWĨѩ4iiL#ט /Lia9?\ n=ST,SuVi\8i2y|Gr'CȜYRx>FfB%ǕEb=7'kxv!H 󬾹X>w3gE7 9Q˗ [J bV h4'K.С##_ TǰbEdž(Hs0y *r1ȷV"4fc} jz 9C8l{1ښ:`mzJȬh ϧ'mfGX w?Z1o[g6lePoG8"ss@lf4+ U~;p&f-7pP X ~Fu]u\('dfhmj^zA 4SR0+ef"_Jkff;IdQ{;} }g@E-alEVEp1QMcIwNIwQz #i'UJy?ꝚFrnF$}9'3kd7 _":E&V'oǺEm?W~X8&yQS>+>pMf2GD1|tζ};g PMh8֕(nDƋ#Εb'N%V?\Amoڑz0x`YģjfETqGh35b`$'Ot&!Oϟķ/9dxM"N/4!&^4$I$(qvmMH,ch|L#:˹TL 4tC cF-8%z t+l:pll gi44$~z|ܳљ$fq&n#35cS`a2KC*I,2JW`;pO3">m[ŮMtA3kbeԚ 7կ**Mkӌ~4w6WvZޝ鼂AA!F ]\MMAX3|G}}訑uzU0+s㱘4/p&<~L4,7 1ersQܷd9zas x?l;*]>&t\7Iwjm:_*-qwވވ&~pRF07x,nJ)?z׭c=1m3@X^Dʖt/!x?7%Bn&uHw~0~SzF)6Hk𫁇̎ Eem\AS]U=i?*u$[^^v^r.]tx$S:\[r1ױm[þ!<+ |C@jkӶ!D=rQ mWue4^[׷nju-۲qⰆ(A&x2DGd1ۏШmJKL~UHm]oF s7BB#vj^x)q>u4lHDK/Eiu`Ql#`r8}Qo='$DFI-!+>1dP?&Cb{r. !k ⠍(o2̭U6hfJ q!QFW("<Rna|%$ qM7AqM!(74dT+j88*6h͇fK^7F; @(BQǎ{mCV/kSlJVک JJH6ĸRkRraN6G+>d~pt];}9RL@sOgsЭy 'DGBJj^RHrq.?^9,….iQaVN#7"sR5+4:.c-=:񔆢/ˋʉ_%^7 ^dIQ4(Y6ڹC iI~\Dg.Gݱ,[@.Q 춐(rڒV_sL'=gIypK=N%kY RGˋĐu7I T)n~$vyB#%,?]&%hFg:L qtsh=-X3Y28FCԀu\iV)ڌ2vP0FJedloSiקN2ѩЯHoETXmÑts;]:5lgra:kA~]^iG:Ym "EeÊ%ct,^6Ŝ6)\p@DQL4v̅fCIw VE"z[6V(x5W¾+`5%Hů0p*Y%dB@\ѳꨧ2l jwu!%e\9IP ILE F2[.9Ӽ49'β[5j3c * ԅJP+r0GlD ) :^ur\OU>?mzϏw .;CҞ{YPzɿS (Qx"D,Xh(};^?Tߦ'֑O[y !U/&Y\$z5urj '(wa5_ í4^#XyVVȋ<`#WŢzFI쳽:YB~]A7^NNhMH(7=B 4W0ΓM! BnĖ󂺍@h$|4z^'eͣVkuAxHjOdP uO ~]>Yve" vxr1qGK}m n$5O@}_S d?'`Tg10:buz>ns k?Rۿ\x 8"{vЮICO0HL萵eo5/ŘD/͞~ƪ(P1ޯ;:^J6#[vaAз^ _ו 5^|N}Z3T*g|f QlY}حr;<'ˎ [>(P׶#s: !_0M?"]U2i|PT:  xv4#tϔGF_$|Rn;e[lq\cp Ime& zGzQ̿y`RشY]WO.iq@|Wu#\@Xo,PU@ N9,) g: CqF4M1C >sQEQY!bC~hLF?{4 (.M,3Z]yȸ(!,;+e@z'~ɜ(BTK+ZPI8ƬKXqct!^fJ t*qY֕q+RQW  3v}-[5]G-CcqAI0'EX~H`5n;&W_$AxaKrC{`*bLjwޡ0A:/Z*1"fK[`9σoZg!MM zL)s1]pIm8)|EEC_ 쫢,A/ʾ9#.ga\'5:ޭ_h|5.dpGUSqRJYLMBHfHzvbŮh>8U9AlSqi&WȔ?mP+9)OcХt"/ {t#E4ur Dj"Ue6w{?@a݈ .-m7:.Pj&ܪZI$df?770FO0}xlI~* \;IL~9y% Zʼn>2'AW 5D 1BZIP&g|3 !)^<~e`QiŸb!Q[;{8)- 5X 3Cbݖ0p)LVrBV*/$5xt͘T >ou5QtP3:ף¯z%+ c#ThRv_)*I eBnx͡ܬ%uWz:7=):)xAj"o i' "%k!b̯6E\My4?7?PIΑ+=>pn`Ud5ROy$ƞ$awH:ETvRCПYYG{؜; %{}P}\uFd@Qa>YafziPdazظbr=AB#_ᗌF†fx{Q9uVgJn.֥W'9ΛRqtb o]Mƅ?^8&o;(C%(\+Ÿ><OJlK'am#a1H^^ڃ+کe?̌}aὴcp9LXdy^x`p4 ]73c&"~26qԓ-$nkYcQqL)& n4v"c۾gJ_&t8!u tT1Ւ|l m]#Io2,FW\Slnq\NSjwQ/7l}EkcPbcϫ02{9q9?EX>"kkO1eUh.e|m7ڋYo/f\:Td[?%4 vB@cQEB9.2 N:8񰙽Kt{.ZZ0_|c \lF '$GuqZ2 Qq= K$Cfx"]G=&vԽbK$p5,ME?)_Ӓ=Qy3PؙEcܫ__otIDbdRY0e{l#«KoAOQ 0ŏkw?Hݢp7{'v)r7@b8urtZQZBTϫc:I=7QT"įQBS'J-^&t:L+*^v%(0MԼJF-=@|.S$O$Lmi0 Ÿׄn"1yٔ^(LPiջߢsqp.:M)Vh)tstk9L*e RtX <9;w!0>D|gȑ5@мbksQ=8(zХW񏆱V_ױ]Jc<~q]Zn䚈ИJPP+7|652A}:鋱~Ůc~H+j 7mB}eq S!}沊c>= zC)e/Jzf \kX#_t OOcxz0U)h~ k(}t-Y~QB}g%>det'Ufy~Q#q > C㐕dt[##gV={\ ߾ɥ3r;`(Q/+uZ*6OL@$)%TN %#x{L0b%i=i۽vwc+Oj$}^hlh拑*ȺtS8)g,=7V@б+n'}NBO "ǥo&)6З{Q5kLwi9Gnғ37/t#2rXs >#;1N2 lIcG7-M>n9z#-Ca* X=G$3gY&&5,ex]vH ],ʥqL+AKvRǩsy@Fg 3!z̑()  J۲ ixJxXK}g>2!J.jl2 1ќ3wOazcф9#2Y]s3R2 8]t]Cj-~~sʛp~@hCV20_tg8tm &+c!@S'>]V4E}ׇM%O2;Ґ\ԷDŬg.MxH o%,: DK&˫|oj{[Cdh,J긟 Ĝi䴋~L5#b"5G{,#}s0kH,w!ո,.mDb`'ƠP~FY=C C~,37@ i|4q~hYYhj)A)ȿzs~ a &# gRm(Lh6>R%*G}~x|rł/cp2=je4]`-#OҀ|5[R: uCL`v\w}n5 :t*}DxK/gD4 ԯ% '[,0t.SMd,0m!%=~!I?S>D:RGQzIGraک_RN8ˡ3%x)-n F} f(94,@ #ڈ;MX_);W(lt}5 xTO@l*FriľZDv̧Ȟ+3OlŐRq5aH3_[r7 ¤aS ܓ2u@ Ó(㱚Q׌hV W$uRR^a 卽ٮ`㋰1,`w0ƍ!g-#؆msHX#MN%N S%vjZ(ucJY0q Ldw۹WTUy`V@d" 6%fE3Ph4 ہqc J/s#䭭?cH@&!k#L4. Ar@ /NC%8ΟTf:Ȥ 5c[)mZW:C~')z_@~ezR>^yٺolwZFZ */_uޤ%be@? ȹtP!{vX_J-{ҮW!8H &bvЎyLɰbk Ke:?!Ow8rIv8"$ }7ޣ}eR?}0>CgZaԣ莈:k+]Zw_ "ξt"r=k{΢ }4 &C7b-z@ʔRNZu#jl Ajc?>uTd0ktq1Z 'ڎ@q !_ޡILl$hw,4.$E1Qh=ZSͨ\ykH]r-3z-YpZ_I#ӱ좇(pZ$)"s[߹siH<45’_4N+\ p]a7w82Vva ɓ[8L2 W@Ǭ. $W(nqkG?"uԙ);\ |USK6:OxhG K;dGa4fBj ߜxo6I?b'~ػpk b+/f"O4.YN^oz#̬S]ϡ/-x"{R//G"_2e˜>9i7>(Vv旟UcIEm`¿!4Ubpe]?eLբ3VLsPm=}w> j;4XO\: %PJS3Ub/)vJ][-w#ϭ>G/_W+,=dR,17_ }'4K½ܧ9?%S_5;|d,ŹJ9ܘ_^a&s0)ɞdwy2D*%.jAm0a WI@6'<`"y0bkQ_NjWG7O y6o>g^.X]u)֬{O#n]/C= 7#\z`%̢n^bdHIzLWvJ1^{ݘUt{O^a8rZԿrajJU}Хa,"mwU糠'Ɯo5 ^xs#qzy1#D;'/JlU=?>|BB1S^w( _Sx}:.yX[z㳿T/>n1xUv [j K> oPErIl"3*|J3}"VvX5-#:9@ꐷ|eVxݭyJ8sS(;Qن$g"Mq{5;ݱ چ]\ ^&ϓ`y?$t~ e{ދ`cSW&; D|O)QaVT[OV0Yc{aXe=Q#k+ݟ.S[RFh"!!{4K{lD.PrNPr`E7/C5e$:who ٩H3ei$5fw̗Ig'd@ci x5/+{CGj[1~qUPm"8 Skd!p+{5wx 覸&~JFFrJ33[ 麐Q[㙓5$8v 'Mg<=NZojw|4` VV$j|FP0HzUÔ]绫HoyrH14cQeX4BGrQV>#Cd- #艳UD tq r1F| "-z9RSX2ASG pM^Tn遦#Xėz.[ϗ"@b©L[S-1p(@2qƏy^;*c P=ۂh%!㐟lH0I[Ribw͑=Wb%OֱޘDï h_~){up`$C09VKo OɋƄq-p"/cX ;:\2a pt;DJ]99yu+.ФsREH"o]SWCk5taJ7UT%E]IQ'| KKEQ  MQh+Gh)BC`0!_7[ Fy}nVn )T6BbRiН c66:L5Nye&bdwu)  iRЂ S)2][LP˹;d(]W 'RRœVwdqH"jaǶ0 &l8>?hmuK&ߘq.ILdzAEy%֦ u)H=1\;hW0˜@8h_+ʬxA8a8!Qzx\P`hDs{'Dh$cMY]2ꨪ;N u/z<Ȱn페`6!1}w\Rwv͸« RHv4Ÿ?{ʍroc%ѵdUox{j*P,iqV_n3<3Wv ^Gg2Oզ8JN|Ԯ-4mY ͡^-ڔQ6h$"&fj/OٓƠ.uVPפ/HAkZɞn9!XoP:`3vH" hPYM3o)R "' PܾnpW.(F{kG4/h astu*-L"#+eSѥK kr*KѶ4ǶSFG|'4Ai4CO)`22 ɣ~vqop_`Yn+#ܱ#TY{aY:#MOD8q2+s(5~O;0Hێ^7Gͺ 019Fbgz~` "ɑsc< \xv5=[{G'U-!l@;`|s&]8Q`]o=EjL߶* #XiEuT?? ~u6"79M`a_SHLΑWa fIMlOzU>*@vDpR7y䶛_?GwgHDW[^(= )mHJ{YS:, /v۽@SD :a2c2k/OEZ'R^G_ģ:06L+?Mϒ@cܕ7fD^tyk0tMtn7E6QG`!W+,8Ä4\1+7{ucV`G\iH.`\u:q KQ`BQH;RuySjH/Cm޵}hC'TwfZe"^9F6d8?ؖ>{BԥV㾒h a'\rQUp u¤}ÊVLcs82!glߌ &_"U22?ȜR-ﵴn džWG?ikU< L1Q $D,Pߒ{T'NlD W@PK}b"-P`eCP0mrhFm wAupTC~揆3qJGSt5i}=nSEM--Z> ofOӾ~! }IO - `]X>I^hMs@ |YiIK9V !-_>bVL۟9s]5B\jw I!tEkv9v˫@',_z?uȂ)婔@5#eq+TI>R2xŲثQ$dedQmه71"a<ޥªت&?Gww+B&ahȄ {NIwq_!*-?4~PMwZw2brL% ,/"u ̊&j;UiMxJr9-TTtԍ:/Q7v%Eo ?ppEh\w"&wXxHQ=CMs(ڧS<@^0;z u@d5x*dFKk&R9ͼ/tw&yF&s&nNŗ>{t׬iiSPmo!^O>7;=!%.5+G?ؐ$y2.7*$eN 'q񦳦 EQ:uNE$O5GYըWy$Mۛ|\""U+G:liwPϵ5 0 =E)AhJ=yPMҕo%@9YԾ"eL+NXp/p¡RZyOA3r3RLl~W-8vk[1(y8Ae"8_#" 5{lS0RFƷۦ+{!'qmoO?ܩn} )XWYK#5?hT_JV wK|a׭eS8k=뉴K}SZ+/]oť%>'ߐےwܩ&˯D/xUp6Q݀oeC8(Qzk|SOy$P)hOFxn-hs$h kA%, *jmf|v\K5L+)ErㅧlZe?g ͈cO[l. }bȝ'k#оj7W,pS +/>vd/Ԋu nF2dIwH GqA-da&t#Z4~nOQg77s4"5o?j4xJZ4!1z` !h @>&9 [X+>^ēR$C}XPbVi-\Wrt79@N"Pp|TD=siH w%x +G.FlȹdT燷m~37!u\U_eCxOW=4eGYO{Ҿ?z}į͢Xߗ/o\7FN`NnMP;%o_G}J;w6_޶f|_CN|A,o[Fo{{WϣoWwovvoBODDo;ooS/>YU{<ԫw{'ޒE,7FOo7DDo=\î/گRo!1o܆M+oҙNo ogL2z,dfy'[t/O×o->o1o lϭ/}Fڞ&LlL lZq! '+M5 -MU l L5,̉980JX;}aprT4qngkbD(kbktdgFUcv2q`6p25136asPn`d(jbad,! eg~TX%z>T)$?2vi;=?ńooGE9#ڝ;L|=izvX-.s3Kji*W$;/ho{:oR,oGQH>}ۓ|bRS+G_ "z6X SW !دxℌ^y$,VM ZoG6Uǣ&4~-h\6b._#.zf!eӞ:\B|43qA\M\ژS R+Dd:]y7 BZ2G uJL pѮ9}7/wZ{p)Vc|)daqb$\}6U?M"_-pX0/VxΕZ-VuUe+p[5<b-u8~;!Ah`=ےm!2j'[|vmIez+K=aO\F Qc]٠קk6aS,Nq5+:\'IHqֆ֛61&#y~q8*XHh>]bu =߯;߭^3z:u}]5`)IvYY,K!r\Ԩ\wS ;a27F+zk*LTy=m7p;ګ(WlM2!L^+ %Fؿ DŽ1urHt2a~NdQ4/4SQniQu8˫j1jI;%oK0,#){|EXyGZJnUݮXXs&\N.KgE:DvNĎ۫Ng͟;oqkifԫ#/(Q/vZ 1'Fp%">8?U;+Ezҥu$˝`iqfo1x%jdz l;{#`Bd(-pcw[d >vgePRVįů*БY5˻dUH{MOoez6Yji%mJ7楇zl햢vv+xVᬫUϦB/ >5y|@*k{ q}4v(o'r:9d}>*fil[K]]Ɍm:Md^Mȵ5Ie}KRdCVnmaA!\5`>mR5^{V*jQ W\Phʡ&^fkv[hHEcdt}BK_-R5?rgqfpEp_d B@:JH6PFH*9'I`dt3dTjI 4Kčvb۰[^o Vv}xai4βP1RcIc3p9[v>zlhu<.i/繤P}1αge6%315v$cMVT4ξIȒIϱI^Kz.Fgژ"ُ=z׶CCAdžZSnNΓ쁻V{&"n$#D dBBˎ{qM.p<.gdFuڍR?ӑ8<^6<'ּM[SI11T(|+ M>Yn"YkW*Lo=rpkK<V)2(4EF]wq;|\ Y/*Q׈/-R`١G&$ Ac2숻ic\m"Β3$bθ!9+dó񈜮JP=]q}khVJunnN{uP:A^ PhGZ/uZ<6G|q$ k4 jw} ɏ(3(Ղ9V7F:z85%GRZJ/bu]oC"G ,u1 ΥMٱSmM6LtyF~79:P7)It\w{ =SnV>^4k(QzVXVjUɩLCXȥ.ZmL 1 U~m?ύа#mku?9JNQ Хl٥/Ĭ\CZVF,J5];qYCkbrč9䫶U !ŰL\!y8rL%CH|͒BF ѡ>fUn'*(tɸW3|/f/WdK+%D%nbVNROj8qv ty[hS}MޔR!ǯJj QK=AmjX|\^#57&|,e](G}V jCRXQڵ6ok:tU-a^A Us!δ]fVO>kQ24&F<}G/ݞ#z6K9"!4أu<'cWPxlw2d{U5 ֛Oerf^z|yᘌR9t7xڼŎÇ~!S '71ׂ-f/kBb[$>?8zޞ~1xgxa퓿Zt Mč#w8m";§xN4QB7_o:X/V-tg1P&#y)?M`"կ4;|=tfF.X~A(Zw! 2RO6vh" ۯ00wwGIo'~ͶW$%]us=^gG֖tb`$9p՗K~c *ZKʜ\ d e=<ԋ)']a>zbțI@TCvT &U-vCqvs[iPe5e5]  ) _ɶ{ z&E;xmRL>]:R^9|m[=1ld^t] 2_\Kg@Dvy= 1 `Щ4߈gR ǤODGSQ+lHG}2T8:M\Aj o- [Zl=q׶mM\DqXN%ȘmL L~)NS[&*?Y/G{t>W2}KtEڝjaύެqʿ5+";U+Z;EV^n"7Ecu58Qa P[Q.x==y8~j3Mє䬷uD@;+t2xb\bfF 8 \^(J2Ne16alHumO$>:dsd]Yc}xc,Qb՛7616>{8V6'mTz춌`V#7*Ⱦڧ%"*=|\3rnӼ+!K2SyVnc@x{Ψ#2=w(6Zۜ'D#O Q-O1llvݾoFSSX"n!~kFC"g%B!Ivs ?.Pb}>K-ɕ+HDq MI:pi*Ouf~' %5lk̴ff{6+bbK1]M=KۖmNw,N.`p<G*rK@pR7_^è vvy Ē⃛\::{ٛ&?}BUk#L.'(H -DfɉAՁL"2tg/yW^bJ(ɦ~럛c}}~vHˍ>/XXXZu2}pCDVUq_iWk՛}a aINndO7F_j‚)Xm[07KlB=C$BdrEk-K(2aM06MLFC;VeuX8^w^};&,>mj=%@̎5V${pՖ@PI6_x;2$\(uɤH<VMm8_oMiiZ:/HHH:djw=INv#ɶOчa @ ]K0Y̐!eyPpE*[ZtZ-2(/:99}(kdnnxXLhAɱrZkB.# RQ91n&Y]ʑW!?5-үPۊ'Fǖ\o{+ߊSXxV30r]?nѡJ"_\X9J$ی\w>EO lr-KE&J.''@>_RH:*H*o}` I}*eVIKwEya" x6H(,~߿<߉VϏZ gyy`qx?mιg6f$'q('VߐBI Cߩ?@m6\7d sG7_m. qE޿Dy^͑Ҿ8l5A}{?Zi{=(G'̻_57bS=:N Y ‰EțoQG>V >067YwN$.}%v˅wl%̳ G&֍G&L˄ NG:u" oLkI"NЯ6#߃Jı:Obe *Z8_Q5EK[j7ЁFO{Φ36T`vk陷BN#HуfH'ZOf6Atwk) "mIہmP7ipgkrO]Jn爱RDw=O4ӕXmg#"35wB]a׳nw? =. /2[p ,;,!85wwnNTu'\s=2OyXmޓLq,qp YtQ5~`ib=+0>ǔʳdy `;m׺nֻ'Jr(A45n^YFڃnY+E$P"fnq"/DQldҦqU&[e>J%\%զ]Y2<Ϫ.o&G[6hә T͚Nm~Ȁ /ւfG ˷? }^¾1`G jn+`z0پM 5˰]qv0E-#b<רDZ7ng=I~<Տ-DZ -72AĴmfc :d0LG0NISz?*fDK79oNTB;ܲǬĖ WJJM1e,蝄]\`)\D|Ɲ'D[=3(BOF4FĹx~&}zfXZ#ADԥmOgKWOP{RR+ fP>/*rJG6;|j(K]J_?q i@WT_h[omRMwVB/MTp f藯qM'b?jEӛ!o8>zV0?W.IIYצd+j?5$iIM)7}p<hBԉ"ҷtv3_:}"خj%"x"):5*Y,(W2Jx/`#lJCI;RM}m R6@)GNaC :K }()2P$3 *}a^!d((5([*}aTݻk!LpT De榃3K^Us7H88K|Vσ4@'n9AS^\~:nw1tQZEKbV9@V١OWXesKDX<Rd~FiwVο>Q4׺@_/p ?b{da/RK3&3&\b̖_qpVPvnS`ZxzCZ}prZḤ%%\:SΦn+D,CcQY}#ob}7_ OgnVqcyvalB݌b_3GF~[0q0F跼!Pp+ɰ`?I HDZWzE5{ &If_ 6Ū)7:q>lqxo6|J3@G,=a)#5_u6Ss:^43\i_\U`333ok.Wh`;Q}<^f-y[bܔ2o0Wj=..A5vʝCfq@f'/c1tf9s[,~{ gְc1r1U#O<-Fq0 jJ~VVD/Ro'k˃c4)Fi*U,a#lg>C&aZr4IFsw#ah, |p+G\qS JۋڱeX͊H5&gBS^FW;hfAOxodvǷ -+T B=iq 8Jh`Jl* pIX-]rq mhNd [e47^HOpdA9Yq{߄<$]H ;&[ AYNyOk/Gv ߛ%{i?YgOJ\M~*L/4 dу^e"] XG;Y/8^A8\'U$ڰu6Y=6܋m[Pi'_!k<2_77n8σE&>WWc$Z"W~Fr#~Fkq|嫩(76Rε3|A.rvN7]J%q; gK yhgCyǏg]P_3qHL{;@ =64){1v>X]'YQ5Q::ʟ,/wk|}^C:uOJNnfkM$=!qDK7F~3fF,>qtZ$]'/!kMlJ~tF'>3B l߃s UlCHFq\j\EeF] \aL˂wCÖWGJyĥr&AYն2x`˿\"(6R_T>YR=rtG"8wo~WsB5"0|^ᝪfZ\RM$,@G@k~BTw[<{NGm&Ѧ2=8ԹQb}p5a}$ /j( l'GM}gYPs2'TEmAUDB|VhR#?yډgh#\f dm^MOwcd3O756~m%nMj x'JiHp2ٗQaϔ'};5h#SP&OP=.m{)Ukia[7W/& Y_b F)A̧o~p4b K.q'OUwu/Jd_GYa񑽖8XY.*ݽ*%Y ֣S[vC_s@<9\ax&RMġ-/zw">g8|oX:8yMnh O;0 ]Νq6s87S[d,3jJ蛼|qnSmY =7ux;j*]޲yHowb ^紺خ SmQ aYZMŦ#&ýujbnRRǬI:1ۚ1߄:.jr0aH@vhqSu'ܛM.͓8{'A󮋱:vRxPUqF2t|\'bcR"u=ac7HS#KX?Ƙ'…D eB3Io.CyzMT{ hq)?q+R/p1,o+6RFs:z,Xa/Y'Ul'4m*C]<:=Qfzewll`uM9<wp(|*UXFac=ULw#iKƘ N$9^E*msC¬SIw8VDNMk>Qr2< \ @F^5zX'PߥpK̎׿?x-41gOg[E{'G>6myjyeqwNzȲBrV 4dqKv㇉M/QŘ/(~[ Nz.bQ7oY|hw9ޞ*6Lq!suB|!vj{;i`x?p4"0H exdGljs_=ֵFev%fLK*paG_ дɇX:ٱtm]bzMv[c| 'rd*ֵ}ɶe[A0rt_- 3 .)^@OGԱON+ħ@V NQXN/h[~peQY]Z<2Wo^׎K+dĊD*$N4ȳXnS--l5cH &Eq{j(5{8rWu)f}T?}1fā}0rǗ6svw.37\HyߜRfWB϶gnÇݠWeOOC3bTvDx?NO}5^}b,5xY M;3,)P0aqDc'G& h:GPT7%zfe>\qC֡ϱD˛P Yk'蒷^t]_8YgVvŸ3D*npcY=̍feWYItZpDbz-AƔة!R9X9x14Gpy]H(L⅓wNMt9i]uaX=H̻Gtvܙ|/t'V~//Hj )ϒ4-ئ 0{k46nɳ)4N~̪Z.3ٸyyS!s/W ث&IסS=p(oY6˗'"4W52ey֩LPsrXv]QSZ䠏/Gg;_ 5lٮ~fܒQĬOԸIkYOӚ? e.Wf%/~\kLlv +a̦Գ¤%[ XQt7@'F(+]~WC!RO,`,!hjQ}+L!,mkoN`x/gB<ݹ*#2n*/v՜ Æ똞 HO'1uwbg,-rM㢦!i%R1'n}`Q4M1=o7q\er8b㶞t勽B唜gV|K汛]:z 0(/W7Ѻ,~RG# OS#(E~)O>КFwjY;̪,Y:Dn/>c6Z۰v[l;;m'ğc/uop5'ŨHZ'yqʹ5fTľ$&ʊVFBk?jOΧ’SE*,*Bu׌հiEtI&cJו(W}=1ɬ'H GZIO ܔy;y;J&2:>J*30&Hڟ3&7ȯn5yopi}:)ճqrIs0Dn-,TWIiszx?RzLG ȓ̥^k hlSf_u-Z䩳0"HA\Q8*vJ:Ue%Ge\zb1Vj" giZb;#4rBJ|uwf̑cmV=U ~.^E32&V$%EjJBG,-=u)#;vۮw|=]̴_~ںzdݼ=5L]fPEn7ĨMN%<.pF#Bt{uII?YBtS9M? m\T cXE =}Q]h~]^.i?iv( x^__PC{p!Rhg}^006.cJzp֡nr{cGE#Y`IlhUAoY^`feb %޺q&V-ԪWu]LN\ _kjXl  $l [I"Wjs[iۍZk{lr,71I#ڵh q?|tЎZIG1'~r~l!Xje'T+TG.b}'䴌4զx"!1EQPʸJnbY$Aߴ?eϡN+~{TgNxsXdWHP-M]2OVg{mv17z%gc/ƅ'?T)¹a R,/5HLn%9+Cb1|-1#ˁnx"SetY޵5i:qtAzt]l}GF)|*a_X[)*-pue|a8cBϱf-ȲuqTv~|q:7-.=N)uKNJ[^FJY$Tt8\JĈ )Y'Tq]ٿiԾ<<=Sf>2-z\z|䟷J=9sov 7p^zf#ynt۱Grs&λX2]5}%x' ąa]O?4tL*7KuyaVo=jU"8O:NdGhL gj_"GJXsJw4ڮ=J *@ͥ5i?Qv8yp S=ʹt‹Xy:HNfDNk_^,B jHq&(Srp썮Fv>eRNqߗo g yj)NZloy,p5&2w=[k><.j<[sh=D^jŶZE( !s`q=6 K7W^o9?'1%@vx4&"8L [LJᄦ^+#k (bb"˃ vkC֏6DSuf"ȵ($B^ؚßxBBBu0/ oO\]";q}zzu<~D4!|:'2Ƈf!h߶vC)\46EࣤuJ]bsrtkn Oo?ZOs\y7 ҩ=X揀`=;#C!Iз#䈤XbyZY8rDPTGJi@);=9~vFJ!J5`w|ҠC+]^\ ֊oĮ/]O, S ȟ}|kDtPmXCa+rXfox` N&̠b~|8 2:tzlTՒKEB=n#ڧq&##>}S⩹ =]NSR nsYTT,Z%&@>_ B|hH qqR)75kvT?Sbnp;XYm g̕G㛼ʒ, ÍV 0I"nf"2$ 6I6;߬ERH(%<yvgsSKqjYR A2P$+ҁ^Ƌd ΀h8(5JO Bqvo P ăy!Fyr=5I%LvMLY >%`m>8I ϗ"qsB  ;Ox:㟜jy";@Fgi BAԸGlGN6robHD@)$h3 2K~~]r1W;~Y,RD3&ƣ_FZȂo_G"nLRp「MX]ߧK)a -Bos ۢ`!dØ,d^!(I@U5<8J$V:%hb氳o,Kz4yr䤙M퇸K"]y@꾕PYˮ|@bTݧ˭mN֒I\+_dvKZ~sw&oUZxȇ 篟(/֬/mm E&W&XJm2xl|()NI9+? d;Ä+RJ!ME&[@IBV1ް?WV6z~< '\r~ h"\AT?tL@h bѩEAludk|0s`jr{``>+W];F&&ЇN=p}>/H ;[a,)Lt-* sʁsk٨]1Yӌc“IJ́Viϗ亪Kp>߈j {YuyĄ*C)bt?}W ;X."`2 gSXLd |H%·HZP>řN3MS.zPG,f#?'b1y~RA|BCA{,?He{n!$BxjϦ !H4D^NGQpJ`n~qa߀@V 0 E_ A8=T!2S<GyA1m(5(xPi?CsWSJhXb"Yiۈ$O]c$% Z&@_ a~JH"ZsAlfv4pdozENvJ稈ߣ 65 r:tVCJLIQWG:>KHV`֊UI6]{l) jk~=nm{[O-f6df+rGlY/ 0o@K(w0-:~-Wa0k{*ař{'aY؛uBgnu37P h8>HM^h 5-JY%rljjD'ˀ؋A7n]h ;uU.4gSz@ɻݻW ?sD_֯HkwPװic;̾}5ŵv׌Mpp5T?+~.ف,0hЉ֐rݏINm@dNmn.!{.f دjaw= sIt +E%w߼h>qA1z?sQ~r]k=pN-bQNu"gbrv%V!Y|Wl֚άOM&LoDrg`P z*-K#y33^{9ŋK|Y O? )@m=CY &|l6:;Үj F9Y_^| B?4ս>E [ݶT/S\~,&Dx;#TH ^* \,!~J)_"-pa'|\_dmUXyzVye38 q5]n;~ BHc*AW[VA`|oǨbvx\XIfeO%WΎև'2Rm~$X^2lq)g}SM~)/ϓy\u28\YmU`_d  +9 (t`:2F!jVJtUi-z-U U :,&vl/uʝ&_3#U**P̀3###q|p̟ђd0^ͭ\UyK$Ww" |:wfۏhwͷ*>5BK =^Vta@š8Ob Gq\L 9$p5 9>^"BMR\ivLUX3tI8XĠY(Z5ñG T'g.h$_%cp?//OFI5@-qr )Dه-CC> ErC@@"pS2c_a;~(O(C<.bż("y4apq6fC nTyy+׳*T89@E '"r _uBjtw1̒v\fsΧ4>\ce{pv V=,FzO١a[W)ws&O;I&d9$vG}^cCe~#Abҩ眘> $f9]iM:HhN@ ͬ y3 `pUZ&$M?/)}nTGVtUkfxj6VțG茌prnNohh um%ʇߥJOL1N,6++D!8FGO>v1 c I-G=X<2131LLJnr{m֙95rpL9X\ao^tVJYf+p.KϤ}Wjk#(TT3LDi 2{w#<]L3Zׇtʅ"hT)B_ob$1?PsnZ᧘B ~Ʌ~%A]H/ +NQ/z[!Jz!fjjcPiEUfjG:dY)zO-#Jw CV"EIIg;rCXұLL.։RR- )hd,+Ofc,'IqԯO< BQk_%c}q%pVEbśT6@?c$Cj|Jxii1Tg#GpL:v$o6جH>C- +#dAؘZAjon# pcKV~M LN0R9/{?5 Xٮ4])%diյj\Kmuu^FԤmD%Nd|V|[j8+LF[01o||@}|;OD" 64DDgaq 1Lk682?t5<m~pNJ' N6x, EV5=b ?޹t,svsGXNP\S%){=?VOaB0J*c#0)V4/q"-_3M '?%hr,ȅIPG|kANNG&C͂A %_<;v@TTZ?>!D?aAЇ<%?3Ⱥm =u-EZB.B( G}qa!w67f{mCPklG/((H e⇈rxoDQۦ(DY8zT;YyH  Vx=p=~g Ex8,rejJF淢dokg@vCglKxX +++}S4* o9o(r/ vjxOHH ʅSX%-dppmMȇ_^QG70T@|PH΢wr6@7W`>@JG;R*IoooCNÍ95gg8yF*i˗- {?;ת%s3œakXpix~]|^O: ǏS}> D ?-(#bˀX/klvvBgg BOnV><:YF[;Õ,2S# I_ ^:4B4111 H"4 b@)-1&zKß7lq\-gᛏ#"13~P}C-s,hfc tg#Np26Q0ͮ5;Rqs7]lmw*4`ķdw#Ӄatr霨 !ss)Rxӧ3=N8|֍vͷN:EڧzTKuz&3ijjBLy8Nx+dB9o`ʦdg#- o$|/pL teu9uDA?#pbm4cM{6[ebtPSZuC2t#* Wd͜Ts8wL2'C"aCsJ('GȇHFJh xRZos&PMƕz.*A%楳+"J 8}[ۏ~r@؞Cs!iLMQE¢ Z ?s  Nrcy} đ5QDEyN0fu ?A,q79Zϰ]L\fLa=q)w9$.3!W~+5ŒT? w![8bTa\HwPEEIoFB*juNL=qΆoXnHm_ɦL&^*Loi"*1Aӈa&2`7#Xᯕa`Nީ"];3 (a,d+N ?4l%5.9쐹Tt4O@ϸpw $c_"x=zޒ,< !] ᥅148y4t-S%+]}_?jR Hw{NevuɧČdp>($gY7/c\jJ ةDE6|$T~:`RJ" ^̴qTLb%AJ9euRJMę{GO|#ܲ/&.>Ӕv>~Ar dSp,$]'ރ$IF%@_;:ИC 3Ž\Q~۔xq'$€DdsyPR|9FF,~TzQ ȔqWx]=]gqTiن+xWc0\<ʆ/C3w0 &/iz%$ i$6_eGJäG>v0_gEjX%9b*Dl1Dǚ>9 ͙5QgdU/=NCNT I&wgp*b,(@ʼnv!F91 \oo~Sm#dm[v]kvRX}gV"=iA)DTy0iQ9k|ƓD=nj/7?L1jphMq.EqJegVyio y]3>7$"ߞExyԬ5.ybIRtzO;u&Vb#nq*bP68?tBXd]S"|et "x/rbr/H1P*sw"ޟpkP;6@Ewy"z#bĿLyY`Pw; s-%=HZ̢Eܻu=93 =y5ܠiV0J}T % V(݊ f$Li* zW Iv# ?Ff.Qfqʼn&2|[ 6N(2xڐϜ@h5\n{D݁c gہk~QcTnhRx" w->P`v El3)rCO!fU0Rzqf!dLS䩼{Kx~0jބ jRhtN}}QN@mq_*c-J n8?=WZ`էA׭ޱy`RQ_mH/RÔP*1~C!,JLKSA,((5Kd KnC6%q(R7:4HAjyFV3!t"-np@< yes*1P ?횠2ʼsTꄱ*RfιcWSvTu@ Β[X=2,36pIJNibưRdx>Gi3# pG 0p'U*o9tW5D|݉0;hݶXM j x}L%n`O햖+9ע?OS>&2Kp{Z^wg 2psοޠፐ=zڦ}>8˺qqkUd K<6WQ6I2'1; *xhOD9mH\llQc 3 mZ{}]} %  w5ն}v|xR4j/2VK}m#$ujh~BJ9mA[Kg >L*KyO2^ǿϝ)/gQч)Э?+*A"c;ɦB.MAڃ:?IhVIaALYO<;^0"+x_F0nIO}~/Pd.Eg ƪv}'<\P5% [^wg]^Z^W: /K_x|0]SUC-oY$/Fbw|>Jb9 Rgڞ- RI_}@`9z`jQXXxKED(+L_rfefTyl1e.C(J%Ql3͈K"o/_wF!FvxM ^<ElcbRpvez:n.;h =+$d`0ܓUzo0".hQ@PıImJ<2qh;Tò )#du3V(`ʎE(|g:yks@P^rxwtN t}stI}? #ր8%OE|Ξ;'UyҼ}YI(#Ŝ<-@Vk =ϟ`ީS U,r:iPw!HHl:>YssT9&@bD1΅_kJCն@$=D^*oJ ^~V1t68$iUICJ, g`ث6kкH+Wb=K~e=z%vJ;F3mȓVXd֝;?\qzFwqI,LKdlBX>l(䦒K;d8 d*lNB>1Uu̹핂%ɦ ~*zOeu2s"z҃-J}0Ȍnop }J=;(u1 8^"^)iBƼ SW K2 axƄ&n6s᧗[!YZ a2|.17R͂9LIZ@Zu=m;7M 8)wGo .UK[;FIaLF3l/ œY3[)/XrT6 a*2u#ёl%]z6PV+n@,q,*$%T%7J?Kh"5Em)9h2]Dz8[;mܥr (VՃMP ?`u_ AɺZqy{7ҡ MSp!K/Vs,++ 3ե ⷷZ^/jgLj.6I~-W!oUQ=PNʎ(!:ycB 8Z+HgyVV Ee `.Hn45MTe/Zmg~#+F-r;"@̠p3kfh? VjEЇyQuEVP}<ˉ5Y.TNOt,o +*lX3蟍RH>%S9q;i?P}?t 4ZiTJ9ͿVO -ԹVTHc^ֹ ,t%)⪬\MeLE% M,s>6] Ksc=~|xˍ5VMޘ8. 7dgT)KZGW6ZUG'4v%HV=7A^H R(&k)ֆn%ޡҧ'u7=^iYha3>H:?(u'Mc̉Y\z[g5SsO}=?NE *p17ЛcS/(P6eVI0|P!?sБ>4&Oѭ)|j^Ra!SK&i=\B 3hՙtXJ-vQ(v";YCI5Tݯbx_.vnS#mJ~aEX?aY(GT%M<_@%Y>V^o 5BV@@N5g3HERi@m *4g Y+z gkFOj۫ZѾ9/mUgf}m+[a>. =ϣBVmhK@xAG|[jwGw(7tfŝ9!8EeKrN)vBpy,1291 2`~}w4U'/OܙF^/ #avᒑ酄>|Cʈ2`^4 zC?!쇣듊)%-%W|'0np>LgE53%88Jv o]NVr|\}B.qOWۼvV:57CSŏIЍ|n? `iͥ_N ;c9!xfj܇C"Jҋe@űhSRFqMOs.AX*﫩{ LEY'x6XrvϠzVnXl_5@n iSI'^FBKMknB@)c77\x IдU<^o0'rR6Wm ʻ,sߋMl>6@ ;UW3$Ⱥ)V)'N>5<o2LJZڡX vplbEi&; (YG 5mPRo$+ez)1}#: {K/rzZVb4kε _=pW{Yzuy|FgWj3?gK Qe$̼Is<5/@Xto{ uyvNDm1)5ߦg`?1Ԕ*IDeBJKKWS=UUh*(T?W,76"!g9vxtt4{{ msw,C q>sotb|]~K[ ۂ;ifWzf5$ZBVCRdZ;$:ukP"ro\b-Ϟ@ wΪ-Niq/D|ҹSSRcg@@{#6zիtui'rNOO:]"qڤ3_VvrraG\F-'B鄆(=t=Ι~W4͉V 䒈? 2rP"T JP00"t-߿cg@f`2u@>ov !#]kcz$85 lu=a8;{aҾڢbM|kɩ'OOQsyE_MNr```}DAem_͙(a-iȞv8H :-ly,gGK[[dJ50X?c"ES8lukMF#D/6ooޑ@#EvBwfj8<b!~XL '[;*i JצE FYhʞ!K[?#C,SRRrqY(§# }Hf!DjڞuttɅkC' y32G…K"EJtVl@E}}b/n0A l@E,3a:B \_cTR Qmi]%joEoy4餏4+4j4FUdV)HЀQ`9 -b0kzą/e~*$&-;/QPމ<ǒI(P1dYB|nE榠#Urz̮z ZTjCjH̅)ep=5ʼ;[k?&]373h6dTGؘWmNV ˃חٲׁɌML3vqBPp`Hm JGOh=Ler,ʬ%Eq8n+Shŋ?jAwN1ʗKDiamNgx쳬ܑcǡ!#NVTTxOO>@!9 a;O4$cBd1J$8s/j)n1%S@,;mgz\  cuxcm`489J%AH^Fv]$$DEy>m[CUV,UkV xp3ׄEDHlx$IF05g&|^xْ%e*K'3HyBi>WDiZ%cb³z'[QHȽחGƈ`4@9X~R7lZ@q3 $1!˙NMK((%x4!"Zo֯͸wzS+;1& =V9[lש4"ИY\>rr\k'n[vKJws&|$R} Ē z'Y͓R9EʍºH&4P"IlҢ>{+#-%|U"Lx(wh׸S7 nP:j/1i*g5|;oCЄc{g8 um:ũe 'V!vBSkv0NXNKO$)Ȥ=uj*VWڙbJTs'2uFsw[;\ue96=ߩpCT #Lir{gXR900T=d. bfKU*!MȄ + Qh1~d>?0?"fmsǮMPO_tq:QLԏ&ns.N#ь~8dpKcEoM&?LCPJxC_@ޑ={ү5*%É ׷ݢ~4иU*،PNoc %#ΦLJ*S(EiV|[O_?;139YW2V"99=i}~~ʱXͮkp*9`u8_x?l跛bЈ]簥pQV\& ~ H^VS=X4nYr}yszH"D09S.`ruWFG Xt jRgYP(f' 7h*6s |1N`,ʹ&ھ>rjTI*s6u_-[kEoOt@֎w[FjPq>i#79A>^ze @>q=E+9{@Β5Ҥ$?1ccooҸ0;'Jؗ ;3-_!4 3ҽA^wB 3!;DEr#)BHJLׇHW>>>/·3S\wGok~+Ny|O@Oh }3`wڟ|n?džf؀cm>71m8 D=v.^nl|U[ ec jEWH~ͷu/vy$k j+Moa!l>>o)4 `M>w [L0,oTbeZBlkkq=H~bDsx,HA%l'ft0]DFI3:ȽJ)ҩ15eAZ%RA+!rz!-CJ~j+OFȠp 2zT(F9 ΦT㟥^h6=2!9DL~L Q~AN!Ռ}Xg|!R=3B@+䛑!9PזZ6} ^]q[򳈛 E&cjY91;lOOP]М8mǒm$oGzpd:G`r9PoB魆 Hz~M3(]8r1;D9I;[\j\y{g>]v!\H]Ч|ڻ?=>^%?>jжAIn۶A u8({8U k6d;J},xaGΜ+͵48(&[fqL9{M' זP* D%bD^YQQ9[1J˰菻i۞;DECjqQ 5^{30dr= }\;uB ?=V1$\2P sL2Hlk brJqpXHP^t{9w< ) ~"`FJА1 űzQ65xz1ޑ̖e䣾0a𦱘tj/wU&1&}gSmׇPOˍlx$VkZyҖH]@NNj,u8@Ńv@[?P"! *wJU⢭nO |C }tZ]TZ qE5eh{ad%a" /| $TXz+?rrIYĊfv4qJ` V9 /#Eǖs`h`gwsoI-C\9~vɩC1xp6 sV3 b=Nu|E( JSeNlL=XZpP>wѧNd* rz8߮3U PK˂6ߋ=>Qr'C@T D&_@"۞G1A?/.%]x~)xF'P*T@ZE^:[ k a"|0/;K?Qڏ [Đd~<*-`"m9c7AF~P} A0kUV)7F-Z͂RtxR>`2(?l7VAMv`IY=VV@h֙XťS xί2ĤTut$ ۟/?yD/uӐxR:gu&v*J;9f;;3jODQ5֐@\'GJhQBBL| ;3-V{5>m>~;ZoR `<aEj|F)D")+z"%?;gTS˘DVFt;{XsNR $gbn6YּrPڋ]&V֙3;oW!Ӿfgkչ)U+пI k*ny?uG,+p\)"$ȍϔ:"áL9wcjj L N^{9"0:~yvqƎ7ff8l*B>glvZQ^jw(b3P !3E>SALyEl# %kԾ Sb6ϒ]SmvjA&,ώň$F|%o~ (9vRAx@'CaS}$[%Wb9̂09?*Mezh>ikep;JD/n9sHN̓`JxY_CrR>obHYYفBӍ©"qmF"_kj7y rͥE5&ĴTJYJT 0g58HGrD h^b"676{ aZ`rCc&{P$U'g ?2m?'"}{U]!#?~η|`fGS4#i;>>EJ/?o .&Z1 8&[EJ0R Q%ݨXVC[ǙRCqC.-s)ٵtubb*ePWğohP:.Ω$݈vѝlV +,>SDz$ej埻J][#F$$!H @q wҸ{'wwwF7nH~w7k͚n+4Uu{g?>]y!Lh0KmU y c-UDLS:[s.] WSdܭr0/?s/YV2D(Yܒi Mp\^s8* 6tG&Wg_gFޞ &0'Fض tH;"T\lHP硕 w 2(@ē^>"~Ob0Bt7a0 Ô YG HgkFՕx:gh91TT3s^K#Nv\R:,_s2r5iHNōtJ6fd˾P#S8cڀZFy4:ٮ#\~"wHZZZ6]kr%Pt& _ ]v%}E=ښ"7WKX`q`I_~(H$sDFJ%;GcF!q1rW/Y?=)>NGIt!]7NZD4 JJ$/f**M^]nn ? >}G&5Q%"QC<̝R~REIIIӈ%Jf9@zL:j!p1pR. 2_;d,nߕD1<Յ@v)PxW:=_%Ǟ22hzk+fQf>*yʎOӬeμkӾ??/8Xh. #l`,hd JHpB !JehbZG/63`L ⵭ GHO<7|sV loiNq??B_'+BCիo B* %uwޑQSSP~jv1xR4C .6*(yaX4 n"W)ם!|j̍th9#HiL*l(hXFN0& 6*rˆ@ԨTc(ZUXwBBҳjj1ߪG}pCH.a;1-5:tw-dA3e%㣌ٙ9'g1 9V~ .qп4TI]&;\G|8$ҹ׿zF|h[5&O(7nWYџ{@W᢭ )L| N5{ k>0{)eNH(t 3X( GvD)^IJJ.uc?Me'˧ⱓg=ߔ*jNcS*81_y .G]mbo=3M=Jc>04Z8Xg^/z*R^c7pQ8}sc U7Y$/뚌fL`.`2G>lX[YyC,N#ot#: hg@6ɇJ_ ĺ@U|r=䵮ͭ@7&B&dz$ØVuӄWc_1o&8e-w̽ջDNa(t\ {;z"]4uZ_S@\~@roQQGy*OC&Oo744:[i _zl~|@O< %If)(@VKZ+ B?{v&X"OfhMr$1pS~l"+D0b;xkKi奺(ߓ7kԧ*'QVvI5%rsLc$#zmm_oA+_H=!REfl>Ŵc3fVٿ2'J{r{|,wIvc_ʀߦ"d첝wЇзu@Lݢpmuj5Ko"|6k7AR6?|Q)z[]􈵽WVA_ܮϾxrEFp?wbc:s5&56) YgM,4"5.6}02*+*8n`j=H$2wa},k\K ` 4"[$gVvuEEE@HѩBJMwu.7"0{?e]t,+v5 LǏL6gf$}h$J`s$So"KiieFT༈ 蛻XWpB zW>O0|7Nn%ge 8қ|09N7@¨ 1o:|`bypg 33Vn_ neR cSABزF~w:S)"J e㿲cdyM_!:,,~]x ,᤺=|||dI;2 "W@&F E+-TC]y<8DypދkMxt{mBXP85f@T_~bx 'GN'5OnB8:svސSUU7Ⱦ}8κ3 lSg_zՌLͩ 1d6SYyu$&e f! #t>R ȕǫJ@58S Q>Y5DΓIIyܛ[;ҔرpNfJxFG 'ڛS;9_)`x,[%׳Wc /~XԖJ>~\⩽B?eqxtmrO/@Sinq`XN$7~è!Rd=a&Oz#OܜbS{%Cve(/m< VK\j̳OB~x0} Lz"3Dgޟk?,@<:Oa2h{@rVU F#)uzC:s_ Jkpuvqa~mZ~&mu=򲮮ZNNXHN:wը1g#SuitnI>#bi=*Iz8_@3&ƲG'=58L3|'Ÿ,5Q;"uPht? D'a7vW3!r {G\c&¤vёT4itۆC gsqaʈ{2y=(w b6וGHϫJ˒٧e6Y@hCm}}iBvE9 (!L18<:ijS|{^r*`wv=6uԤz?&/@δؖ[U09}V(>w1nvBUգl#+js8 2 疗.Q)VSOŭz{++o;Р0#17T=[sy6VSN/\J,~\<\$͙˧5LFaPBWH\bU9z IXڛQϭ `͇_ճ}ڎu5%S\[$*xlKJdw^.N:X!J'=`<] գr"[@Kuf*ϟ?) 3 ?%ڝԝՔw5g-AV3p|bÖ3w,`H///Es_L"[F]#^`ƥ}G%O1e4̔湋&E,l.B }groZA FNh:OJ7tZ·{v5fe+Uڤw"bbꏯyp".>j_>_:$>4^ϑQGCdLDg/Dv2{^N\ YprqmSsr6(Xd^PؽPrV&YCkaV|Zmycr#u>I_|pUL{hH8LhN%9 +Fx׻ }"lz`Cs$LLՀ/4tE>4[:@bƮߏ1ͼ PDFuݾ'kG"OqzD[VII_}2y-++h\)7+5La'6J d @hVo_1 eTZ9ĥ1 ;s`\ dQĶI7YÈC- ]w?paoo/@+ާzC;qY@@ 4̊׎3bP֑ȟb۪̹G,WX_@P9q.=IN>" 'q7'D+ 8BHnA`1[Bes[Տai.6b=ex#\x(o%U< b\aKS󎈉(Jz/]fOw'O>U wƼ/ 'ּbϪ l mwCtCN'{~8~xFSqVz(vc4V(v3B] nMT!pƸ~ujjq+ IKN-aO0S;FO,(jLk:_x^@7fER,FyǢ! f@d>RU]EUvHl kYѪ2VAR2gPڅ5\,_WI>V}F+6)aͲMs,Jx( ?N+"vQZ¢;[jKQ#koMR5S<*xOg^R@_'>$~ o{Cb"fRH0yc0z\.R9>P9fdvz `4ÍqWS"RS7-"y@4qɤ]>v甚3Cs*SOqmpu(U\ ۍv,\Ϟ/?ݮɚ6J1i ͬF놊rMʁC75V؀=q(g4.9y7}2X)҇oKJ/>dU]UvnZɦxNĿfnNNL5vtoNfH/?6˝Z 4Xdp 8va+zgɫ7H m/ kB%f OViJz=Md~N_TTq)  @|<=JD_MmwdN~XjsVVgAb{y#%%-mAkf_G@o 论ԿR ;8|n<dG]^@Hl7s@^aۯ|(^X,4dW|{*/MrHz$ ̺ZKV;jo??y^$v@Ź9׹s?ͮ{jmZ?5g$uVSp?n榡1<*[p^BeT(9]np:UcF|wc7m_=Vs."z I|H''ePfy|ђ ɕH4ѓgna)\7a 7o}HD:&{㔺z,, &z:zP6SQ8pDP\3D.khLhItcS"Zf1o"[Ʋ'Tr#[D=SbӢQij^huz=Z$;K0sgi"{Rv3я%Ӎ˼<:9f$?oorvO>J%niQx,'sŽQgcjDn0jڥ?/KH$æ@Jŷr  ,:E/~)ZT+[1ks&Q Ucmrnl^}# K8 @!511-4Ԓ+ygq҃_*'a(J V/}%/rʲS]8bfߙHCӟ,Pܛ8^Q%,MqЩbMT1 ,^Qaǻ-1=Ox CNߞzfjKW!zFKk&Gk|'͉cbbl_W?~;Ji &E"bnPŪh'31!Y4(/^f%lD 7ËJJlh & CTioݑ0ڸ.{NedE[̐983yl{f|~lPBNXĠ"E-,Mr3EairTws$H|\c=!'ߴv(l-|)nzf( eQyp%Kkҽoλ1a-$A7uכ⢩_ʌ?G۫g{x!U=xPV$J|M衤'UE$gF2N֕&@m[# s9 ǭ+^XP1$\_Z'A(.)cW\QĤr9F- @S$),ds(QCKZmP;"o[ӽN%4$JAyMl)q|bzVoR߾oJj哰2D>^>j.;B>I -,+)HLzϗo+TVV.wn9HO =,A@Œo#(6 iތhToȴO>gj'ˤ|%ӀJV:Sa]Bo2%pm908RC{  [6H6}o//}dT$?PkDhyVڝ*07_0a?ϟoHw%(BjH/{~ mv|1p0vziA栓><cW9KdTcD"d%fK܌"hTXپj>'~g[euCSp ?_}x5vˇ K1ǹO]#:,d"۫g wp3'VGJ;/#F2S@sb[nc0F,1GeϾP~a[5?wa{ n&Mh,v b{Cu*AÐQvb+R$%C}Å36"A!4q TrF5<&)}רFdh2ZsZhy/B VSֽ3!oG2рYW$/0mt(MN}g3d6(q8r }J :%7lF,b:%f0a6&~e&SP8_7@KX,Ut#2yo#= 0b)&55ݼfF\U;'PיfG ϱCK?vf sC ͍B߯.^س)wdO.+MT%% FtF=\.R)o'lAdY j׬pp=A}n1#e5 _sFxܪnD-J։P ruqmp h\zݞ`v)-+_ i99aTaԦR6\㯤TjnU_wơ}}SU8:FhNJ͸)hQ9xZu+j uMsU8(]._9e2os̗Gڋ Y5rʱ8(Μ:|M˪t8%T.@]}dRr)Hj|*nĶ XCiΔ"5cև]BoRcCz7mTQp`n^eMY=oV1 SkCj |R}bq#pc>P&W A~" w"_lRkLͱ"_iy}hmyPH8`be*\MV$넴/X2OAzH䛲=C={9:6".[ReBo=SDp"\Zwc m1SSoF\Z )9 c!N1ӒlT 8oOV۠Vm4O&YnϱL:鿌*y3k'_ӱU-/O(Z.ϓu kL}?O^凌Z:p9I(Eo~E;Z ;2#j 8ޮr"+ ? eMrGY,b ,a-fǁ:u9Jʌ)#BFCuHYtO'ṠiUtirhIe_7x7r˰V] h k1ʗ҄ܒP$kf Lw; 8]+&[U;kw-J*Lײ&(ϴU5G5K%"(Nbܸ,z@R<)nS) *&]aKiu˻e7M*.RwįhhH0b?><{M:ʟZ40Jmm~/D#7pxV/~<)t0YE[߰\_ŶI~}a+ ʢP9$ƒ}Ki7X9^`%a ŗofWfs ]!!Y;$165fRuZ4|{Zg)n0>\]y@#btQX2űSİЁ5 na5sB? K[7ў< YcC?yڞRA &{3b=qf[U/tBFbX;9Gn"sHjuD^|K?Q<,U*G=?Cx7ǂr duUٜ}2۷4EӷfD%DRB4J\VfpW¥\ /|^,A׆sc'R飨WoME.v_olB 61nk>ѨT"hwt%}WAwaܷq@x2o;!8s}wҔY\Y3E31ƌ}n^~xן>̴0?rzF}K?Dqqa{".4a.GW3MG%;>`Nd2!q~r2_3ުS@A#z`E8mqyaDx;ٝ[nU|oqQ?2ԨΝb,2F Rmh_mQ0ݙYc##ʎbEyys-kWE.aiaۏQ-4$0r3(F|i#g?'ǗH@Hr7ݮjٚwںZ?,O.\lCvE1h>M%C)!rM[]Zɝ|u<䋡뎭&a fΊ_mOk[kDYy S'4cnOjnET=.w| qCZzXGb)2Ԫ1||o%IЭ9.9HRޣTwsS/SBo rX>[ex#\p=n>6uvn7 \ZK׸tesʒoW&3$ Vk U/[?CZNF7ID~.> ͷMҐRd~puuL0oұ* 44bSD!Q- e;8+ԣ o1b۱uYv-S&VKqԕ UFg T?{BXإDӂ݉Z7/I=>=2j4YWBW3Abg+<d@VIIR_٬Ne$=:jf.,|QZ&F͝9 %Lf,Uq3iH-/8mKT YWSNF,J>,ɿF7{J#]T,VMG=j{)̣B.7x(e _3RPf)rJ[ *8u%&S%Qj ɹj@0Yb{7,9?Y|H|yr/T~u{B&^:WnAfd*b9]{C-0hK,=M֗IS{e?Go3OU/ ~{B`iɬ*9HjPm;4/@a4>Rh| 1][e$dumVtFj8R1}@;?b3?0`ߵO鷹q+}Y>xA4jkw~2PQ6f±%㟡T~`5߁_vI.I6ݠ))/oR9*k2لK JZ+m ư0ɦz&Jg>G!nJs&A31}M!`<5Yؾ<E7}@6-$tV Ink"Sd7z{QR> wcaNV:Q nl #Oc9|E9m¸++Ğ/Q.nH0ÇwB[oDWj;BLjrTfC:pwW^$ΛdBO(%QG@ߏ6#9vT+Q)Ν'#Vt9RRUr,qHP -4601M#W(.sj>V&,oIm 1"VV6ubJWKMW홒dKKqʵ yKTip)I:$3nNuxwr z\Tt,IA} Q/iۃP@Q{C2 a /fx<=HYB޹Ӂr43P;E@AwHW/5MF%o ç`/SE5tXϐoÔёVW4FDmlwS/~)W+/Ndb7`]K9~gGM>Q#Nɾw_8zd$$s삱I?{ w%{ʦ_?tJΰj~wBNW$Y鼱 Hy Yڎշk4:aTj%h>c5JV {1 ,er|Zri/<q$M `Akߕ"mk#c|":}%S/Rg:]UMS^+ZGH*KB冢d; oc%!eǰMo 7#SG(?7PGFhF ,~dW9gmw1+. $\N8N˵h|vGb?FUCPH֗&.AAfrH\d*zd.p{Wο9f֧pMc}%!ɽCP;lz'jY/a cܴ^}VWfxh^*NeAץɍ!>vXӆ_14?J/Lm&(Q1^!T"0EQp>I }D ѯݧďEX J/ MUao^ZD d[=\wעSB/ř NE2cW13jh:G`%KqCS=ὤ)lݵ?>)(j*is t Ew>H6Dm|M|Gv_[t<8 G4EpN]ȌtE_EIn^XSXFt8q:zݭ0־^qquGYP\M}H &=Ap&m?N/?#ܟ!X?~5EBb'fz/5Sp2S55г׵{]\ȀND3 #gf&:~;[Ks+K  ϬtF_!сM lf:vztf6V:zt&zrHH)i?QA~646':JkXŢO` ? Y4VWjAJS k;7þDnmn4G 7HUVaǠ0SovIUCk7VrYyR2 }haC`v7Î|t O\(jF;}I X,KrU97>t-gCx1ju&8 pЛbCd#zay)#f٢Ng< iN?gS e@"*.L6E̓K̿BD ajݞhٌyw7y%ha~R`OO^^9"ґcUY3cH>Î${R8kJ$˿nOjkt/ժ6]O [Q[#dmhvӫsaIh\z(Ggs]h4@q:O Ɍ Œa5u/^cY~a< %HP@ D_3?$xp5h1]f%kV0#Uܱ7sf9Zf Cxx.SXL=(by3M YN"꟭AxF].;rW#((X.Mn)Ip v̊1q7g(k,i5Gn܎xaȉ֐&&^t)^mWBb.TǢ! ]딭[ ɌE÷YbmSrfWDr>f~7A NSinD4/!8OJ/vփ?}tui{& `''9r `b! QVPڲ4fXdCطHuh9bda!Nli9%%INޯֳ{J#|N?mׯɤ8$bW{’9o&!-v+j˪M9[ngֽ#<Wqҩ{mRԗ7eqRb-3B|mRYy}HFYub<+Y1ld~ݾA4Q-!v:*>|\fmTk_䪼yP:YcAf;JTk,9:D1r&8v#/ wUȗ՞Ա4OA!L5cIAQD#s"D 7-UNegܥdRkbFFo*)UqbŊ-E,9/Ll8FLƴ[ͤRo}xtl:75 8U̦Jfee}fd=]9߿Z;:d5džr#2lyi(&ҊVR$..ǟ~+}6W}Xp^E([ YWLEx^~ OB.\/ҩ+JInyh-E-8g]ֶߗ>'w.ۿ>)I EPfZ>Q 4L|rYT QKdVs.0l:Wp7&“\;:WffW<]<(랪feӦ`9g&7x{3`~QvE9ִ{{<.C1PP~M3w{;6Oy %2z=a;H[#hsjBW75q}Yr9qIQ~]}Ŗ;^XAَENxRՂiuYbyDz*v?ʭ;N\7+H75.4dg/OKr ۽P oA#~CR*]eh  d2tq:ǘ2z?nRTX^YkD=]somkFpkh sy"(e-ML#h456iS;&7P[kiRHckqw~/"MUTImv?aoR 7H,]уUyo gҏ5-;fL `X"#vsDQVs; oqio/x|782h2t~ܚO\EO'm˘6[|ʮ3W>ۮܞYhX縉E ^ε:|G rur( xG&}/;ѵX±tW)w-?.q=B]zu'׫Ƽʢx&(NhK\@>6*SDtB؜X!N6zf/Q=X}w02)#nY926=4+XAUN=ȽK|hq10o0rn}JmT"QU ٽx~|q$R "y :k7T0g{s>x]O=L'uWLxvnVhy9`}fK9;kk7H.-K}Sz| D[ĚP<ëĤ)$D!\ }cutQ;Q?%כf[Hpٞp%&,+haBP)fead˹dlF7M@Ũ"KbJ=|Ag{Xٶ0ҽIv m ݆z 8؋,ųR-(>;I'`iLO#b6C}܊N8L?C l69# p 1XZlb LU=VC|Eu7DTl e["Ye cUcfAڪJ/Ybo LBos,h =6Vã9> 82Ձc 7C- if,&G>Zu} gL ]FB`2߾C*VwF(0ZTv «҉ֆ20*L +76'A\*E|/)v w YCtiA|6cω砿z=>Aa*ypWfh 9%pFJRccc6CEo8S"epP|6V6MfH JJj! ֢{ϞDR&No#)\bӜjԐGq[ʂ^0݃4Zd˷x lSqE2FSbu>h3M`6gwB)|khhhaa'o `?P*`QPzw+<%󾫻{zVCT hDS=CuAmmck2!+_N?TtVcf~^B jш +aVɑ >7ߟ",SPɧ(bIr7 &@S/oNef ~|DzꇥsyУ !_ hF E?Q@U&Fl 2DHeammĝQzA""oԪG 2crpJ1ˎ+k$HAAANkeM B$i6oe&xnO!vj&o.vS9+,'Fd3[<Ntt•6C L۽MN+KT9g֞+<_ Fً\ NP3_i4ccg344#!##ИD<?15A5p5dz%pQ&HsP~>~&$ _@!V}V}l4J`m~{6 ܍|fɿD>$oX(Tpܧ e= O[ ЁUn_>>?:d} e1gXT2es}!W:JLTF!zVR4#,a{w:ube+fMgu+NFrTZec/qOHվ$ÿ|8nm:Ih0|D Ԓٗ Z !NE"/u-!3J fO~+`<{ٗJ}Lnkj;jj Fj^< D(€C>ك\ X/Y99'+MS_F! : fC* u GecWDp~"(d<m Ipccj pί$6[vǃ7< !aY\;hYִ} Wgw¤k-^/mdWGW/SxܑY ^$'C4l^~n"Mwv~~ |]O;fc]]"o` dlZ3 '-@?mk7+-oK#Lj"̨%`76bS* aU10-Nu7âQnt:ؠ/6V ˓NhA~ ī@"9[lY :[CS;<|lұ8Cp 1^%z%AL)"%FyhsbAy?P*{ f)CC]6Y@@ 5^-nSn՝O0w!AF״^c4Emۂ騧|~FJ'1i :(@`j:9_h8nc c̀.2]zG+ʃ0v{Ep)|za oJGltioM 0ݛu-e*K=P]mE~5^,)gcRDW !_*}.z?r3r=]ɝ0!ugoÚ@AJQcbPF!wTVRmjsw'uJ KAg +@taR䲹Ȃؠ 9~4xlEV˜Yx镉EK{=$V,^KGL8<掃Qf޹B/NM FE $JK}=u~{erW5T‚mtŒh .T"Ŏҳw pc7Q0b@PjwM mSb]q]uNM'B钻%`)Dqud*^א9s KK| O<~|0UeM\nA-a\c7LX;^Ó FO a?S& M"ʤ#AJ'ٞ-յTR#q /|%ٶi9X/:< n즧Rc)pMr% ̢v5/j S.!3{R)P9(N&jh IgdPnK.sˠ>ׄ8QtHwB sZ8=#]RN 1zREȜW XK 1ՍȮs*fHKfK]AQr&nvOrQpO((wqG#ߣAj,l*E|w~*6,G _zZuH,{0tģvAeaWEd(=! SgG琣7bO{$}}KZ%-MYIoNLt VɨK a=bCA(Cݞy!”`w_܁4ݜۦN8ݩugrۼ2L=XzXE 2E'S7,X<Y<յJ85XL^Ȳ!ZK͙ՉVO$ihi! WCyo+r=Cv ^l(I32دPk.kV*HmrzjZ>}FRׯrS;“ [AxX_D%`+d`5T_WӌE޷U-u^ۿ*H9Mz֒]#y…3yy%&B\b"[)"i` YVcA}I҃g*&C.*^RjY*Iqʴ4eF/A,f$l^iG^KQWh.fVxbmuuJ]0A;EM+Y•:Kc5Dl~ i~ 2DAȹ+JnqW{JC=!:(oAϫTH?nnP:JW k/QHpNoX7hoSIuk5<߹ò9ZUCd&{Krg ܜ8J["?dhv*>_xU.uP9OԪ J;s]?Y[:;0P/o"' d"eק&?bIP$j5Yc Z9/$WȪI} {]璸*9i~KeXNߺ5nxbb.J>ӆ 3Lk3ݽ^CPK"[J3P*S<4*Ha.WثQ \wUCL;QsEe 5[hAB.t(*مop!-{+RmX}g"9]C4=_`?/GekGLˊ[JǴMtJ(=O'[_򎚓%Uf'8]uku ƽWH?bN[s;zr4&.*MEln}b2!"#!" H{UY2lS$ڮyE=YmǫCR3lUz.LTf{ڗp!!}:Ą';5﯏z;R.EuvdlA `?cZv3]vwX.Ю B':D!dOT;򏋖R>Lm ]- -Rhg8ҴNg F-Q@M=4ckw%`wl~zɣ-W $19GVpvP)Y,ϰ{RBc@彅iԝ[~n@"ri&>^ h[廖N/qKmdJ[UWï=2W`7, -Ttp-w:.^wGR4.ԅXzW26=|@Đa0w;msV2aCHH>C}a)Ȱ㹅zńJ(AVz4Qh'<@ya@MvO+OBsMҏX+%8n[l;& R;}/Yh>K8/2t, ;ieW::nѐcNuι493rslu rK4-BgYq4]j^ÜJTW,`(-FJxu*KnaԹ9@1wl+*9᱉n,s]ʥ(HWUt6WWD [na=7z1=ψ%yD̍GZΥcl]U]{c [[?kDFyz쩴ۏ&2(z30gtIGbу*bɖV"^H)걶r `ثN9-}d)lnHjꞨ#*Ng[Ϯ5R:=):o`hAMM@Ǡ K(_-ڐ+a$%tDIGxPrIudu .q8J>0ѠVv+f鶸+ZJrwߋ4A_]\cqMƾ4YqMj,nޞHS.jSda+%1Ȉh o+'YԭhL'ӑwCJk6<4v )9zNAh}Z}8d$ vj/Ca9t!Z-w M8ZU)\T#Zc50$ZeTt郫 *]C3ZsY)/9`!J/n@JG#oŋupf8'HEU+p3lZ}7⫓~7:{Zq"n ysR띊A-s]E~b]o! mjxңg2S~fa¢ݭbA1#fY4sc=k"b@ܫb"Oբwc!|=?.>RoSLx:G*RWN!{"-K`\Gás7=?>,|RdFZQN{m h*^{'!F8@t>͓s7JGE 5U:LpɝPVV.NQ67b,Xuj, LXawu*-&:)zܚHLTe} VՔ?/bN/Oi`&M1:L4c`~6d1)ld@" $+Q |+j9wlTnt_8_۟cjN{q;+~&f ht2sb.cA*gvT*;/.锥Z{{%,Q넊 I]vҦ+Ů[߂05+&`Yq}*KZkUk7xӦXحv=,6B"fD]RLl9Uc2!۶u+bQWф] 'a@ gteu?.EDk.ZC^H[?*&fS9!#bwTGŌS3:f7ͬ喜XԘkCc5VH #XW2߱hM=m:*Y1Yl]-9g^lŊ?a`鐷~._,PΠTm +EbM4558ec͊-(n%M^/~hcGhP*uH ׼S*-L5_3N)Z'uB{DBI+Uʛ2;{ R`F+B+}evqG_hU8n{l_EVS؏SuPMcfTWQu"sb+4`V٩ݾTl7S_7ubZ;G"s- o2l/nXƯng{%$ɼpL3er xHO,}Ҏ\[)XyU jA7KYsa=Լ9\;o;BN`Cmp)!֫c"}qsE?NCZ% E]Q 2uػkQ{WA-cveχ@^-C*\Dag(4]]u&!nwE7 0ULca3DC,}tǑctηNmr1Ȼ'nd*Up|b,avb>3gDo_1Dwi <'ً)b_hk`>ĆF6-ئG+)4W)s6~k(pAP K~F5Nv&*[zh_^X:p d'+-~a \K B5A ,p'+QTqQͩISADvUU@`j(f8\GBLlG5ui@3xj[QZoMᘰ ^qw)"7i],= [WZr"|lhq앰ԳpEv9GEg#=KԪM˙*)TMۍNgJ#ӵɀ90l\Æ?~0\&UVw&nwGo瞎)zrKg8DkCQ rܪ} ioq`>o[P.&5H}vzo1,C*~@4m J(9y\jsez볈lL='lWӁ>dN-L;= Fsxnc>[[Z/omq}_]>]IGe2M%AڡGgMx)iKfQ9{2YjE - yT%]q5AF(pm齵E"?XTjf0OW];OžLF)(m2oov? Ǖjj(ntWesOy(t[%1Ezm-xy"w~2ל07 k[VK] o{cڥ7E5:|Kh|[ˍ?X!!잍IC'x9Bs\ 5rp4W(<(t_S|Eؓ^k2D֛\>}hVD֖;e7jƿ 1<<<p*W #vyК#i+TsF޻9R˚Ere.\]mq;VW Æ ?p54 #o/n{oZV(2='Ƶ`}+c/JLaKt{`(ٍRgjb+R݆cnY4o{ChMOkFO#Ef>ާʳ0k!6e)ɱ{,N^ݼ XmwawZ؎யM2'6U8-5}e(-`竵f{#]~L 7JegiGG$⠽戰RW0*)mg"ٖ٥'e@ ǹ{o/ޤC==u@@DCK\vCRԎ̍kRZ?]Iz\jCvB8ÆiU]~ x\Ct+~k6j ;6 b#[._L }  `߆x+s{GHB3Y(**+73) q|yS *"YLJ nƓ_,'QA,,_>wرBe/|ɓ8Z4N8x9kGZe [M~wk`}vgo"9!μ |9ձ<6_H`}@G .-|z偨hԟWs&&eִG;>}iSϠQt-,JnN=(^N&eF1BϕcGz7lG-p\d*7Vml׌D`%y!"cRF_*WW\vEV3\xrrr~sdi khh~b O7ln\ZJgZ2!$Z~='XfnǐxJn0>Wփtkwf8^'$n~{H4.M@P3(ʎ; DE|ZǷ.dffHiއ 0Q͵9JԅGn#j7S~ws1]ZT6]b7# H}-CA8_?n]x6zc@1KZlaT\wڇBb2s`0D.^DJaii/ɞ qu9fQVF0! k洇6͌6i5묽vL$@ƲrhrŠDC kqʲJrt|ެb4Qǃ=ğdt&..\$.s 1c =KvKSGOΤ2ۙc4D%U-ίX6gkmȻ^xki.~^6l`L`\>Dn~N෨aZM0P 9ا#"r=}ֶ}zĚntq }\OX}OK-;;B尡@|=yO%}uE P:<\h;PFEGWqgtZM"\.k\CDd3wVߑI=g?VLWqwXa|21uIΚ( ²mL W,Pw8G;Bѹ.r{f(f'7kݣٷZXIvMh%}])gom\ fnNnۥ( #'wwww@pw݂CpH9'nn*THo?ӳn!Es[ix "vU.5S@xl+˼~}djHW-2AUz3fv[L#Y@]-ĤBҋb1-=3T|N̲,etK,jC4C\ļ-akjqk܈EIAA~lPp"ZY:--rHӬpyHd eI$''g̥@ gdm3SqX9snK622Jd$/!p!a\,;%& fl+.L"Uv ؙlz"mߴ?mԳh8QW91ɩdtCbXPZ 喔=rx ϗ%/kfLUP _x"x4bMx=W13 y/Qk-uudeOAC3.,bhTX. xc4h6ϭ0zZ.~ownF=ڈ9WWİ55A r?:TI$ɠD^z=<&z1Ew#ZmL P.c=`ժ3;ʼn Ð}Ԓԇ:660\)Kt=* ]|䴝4.|Ll) `U{=xRQKc,˞lb;? ϶a۵.z1:MPH~$]1xz3& '?T@fp5r?Oɥe <7u~׺ꂣܳ '{7;zIاpSQ#6L\su*<8[Yٰ-8a{q٪O⣙ K]bK'*h+&bLM$aߜP:? 7"r4ghXhhys Vl?9_>~Su뽵Lxdž &0 DD(jy:}O[[ #d uvIJxoݓ POQJII1ſ M~S~lK޶Ёh;,;&_]\X,7BsrpuD 8>)hb[vXr%G"_kw<V)[P_zc+`   A+8@!2|)Uڳ@ sutwZ<) h@dgaI>k-<@v0ػSUNSRwVks`q8zP4%*{ ]:O&$p'5$nCfSC&ٕ{㡱}`Bh @"wZ]?41pjzR~ `Jݱl4x@5݊4o .U6Li}h֑sAN>1崿F򰎆a۫JD~/NP K }8i҄J,aDIkAd=?/J0p8aqb Z6H]:>:#֨| σD`wJ&Dp2XE &2 % ZZ̧rvKMuN.b`ڋp6|>P-@-0b:%"/EM(U5Z/sXdAX^et&2*} ،_9׬IK5H!}~Eu|"F|B~k4370#X6e pw`&6z\O\n>j9O`suUPr~O8IFbCӀYy֏@փK0? #[&|CKcK9N-*Ʀ|No)`PS@d\k 6$SSi?.wn)0iry0+jHRډqJJP*c`aZ#@~*b(lso$ v󙡨h`l$y#;GncU)šй2&Se({|w;88keعg]+HTFWJԟ-l/:%EJVo:v/ \#@^R`:hG0gSA9Q55-(PȨC2tt}?Ĵwn)y" .p+)(0p:2p:0;{B22HMBOCuݘ>"O7f`H`-Y8̦sNX=aN/_3ɯ(i-s![CJΩGJ^{T;!oWvF3^'ej77 S?a!7,jPLAyw1ofבD0FAS`@[O-/nX! ؠCB+=4۷jiMDLGbLNC~#1KD>c ='u>kB)@*\&~>k@穽$Rswy8K3q[W[-K[~;//QR¦;UǓ5]lqM[^hxdVK9Pc 2ڬG54w4. Y2 ν]`'G w0|5|w l }qԲviWcKKCJ3%O4tJ+?R'Mw_p`x G@Z ɀyScoY!bi)Ol"uT0}{1CZ790tʺnj~&QTT<뷼F:Rqa]χ> f!ߞnNB7ћN` [uK%2Xifٟc0Ma63lqft K%`X[22rg5AOy2<1_32j|d`KSc{*$ӈ]ZЎW)./Q{r:^Ҩ/F351i<&錧$ QزKVkP\&p,hrկ䖜xZ0 C/AZ?~?)ϝ i4D-bCtBږh2\/Yho)z(~| :-\~C}# N/y=Q@|WDLNw⏃D =6\]B kĂR>_'~yP!d7o)[Y?(^M",Kʣ( u{ft? c*i8ɬW]tn~ncBՉYZb|8)Za–~Vu/ e$Ŏ`X3?q.=ZsrND%֎( f/*;&-ф9}}} @FQJ*XK},9{r¹jwlQ,,B%ݘ & ['HZ_"sx<ąw[Ixrn[^8% qoao]Iq{LL3 ;bTNόQh2^h׎N$U#& "Kh gkM/LGVb '꧀1*qVyM 6f*(ŗ/_@?``{#(鿣UQAȹhsX-OIf"1%tMQj΢kno;<J2eqWYpz)WE-d.5ze/+rcwMDRbpq;8FKqw4;G[@ن:;2Vol[fo!۬';6۶P*Tz_56吝ܤ (IxNoZ0:#xeŜxE钔9/{?'; gmR8>\6m+͞>?>2߅V첻(ci~%:3ݸe%j*56%=eINo&]e8LIߚn",ɪkj"?kgT[.q 6ܷ 0k?6KJLdF8>Z*"-6{8Q|KLSp4"JzFfO4O2s~3'=Ք3gN2%@,l4m3.:ަ|m%/lVq> NVe666F.#|pP ;AP#Q 7n1[bSNV'>cf.vp5nZ3`"qs[O0~P j]o="<==y׻&<ȫyt?盒~D}5w~JՉL"] *ϑ8ir2 󏷏Tb=yͯuL|UkUܲI9uS ^FKK;+A-}Ll;@dZUɿKO5=2bպdOvPE.7ܝf/<$d6y{cׁ *db\ :f6#.Ȃ~jtm@T]~oHbL^`HvQUQk/ pAtrbvum||8}(e>u:hIy/eet7Y{u*+ @۽~Y$TmPdI`ߢDy "W/eBP?x4R] Ù2>aWfwrT/<N"} ~ (v+FFE(2> w (ˢ5nh0ks'BvtwC?9Tᜑ/ AK/xouW1elmO_x*}鍆e1d̟ VQ%MW/ 鰴aх  QH:D;\ eL00?V6\l+tis~gأ/"x^,^}) g~V @d Vx8hhHXsiX4+P%{ށq } !in91.vǝw`gW Apb}MpbnhYwm62#C>hivg6W+E*N5L,h'(+/^(~ Se]@8avZrЧԖ8D Sm2C!/<`{:*qs`Q~VP9ggg9UT=~J?9-cį+| kJJN.ꡰOb5߀0iH/D p34w?jW}xJ CCCv~&(RSjj*B [$/ !O0՟e`I9~n^~"c_QX2EɅ1lwiߢ'y^F7;:WMs *<ڕݐIMiӒ^|3>xw3̶Ȃ,&&[CIRuma+JpBl)]L ?Od4KK sjj{Wu<|(ԇk_C>)o3'=CB`1o.ͦ PUO\_FM sfUl^@$R{WWDr 7*kj..0j'vRߧYԁC/j\ @F`wRBN.1S1pW&DZH|3' p *ߚ8S?4{D]!]4 O?PQ rdȹrq㝰' ]7HEn |5_>U*ֿs;`/Q2sxQ~("W-KKƜVh4LXP8cw4g!4EWLf'KInp4;0f !t#57 'lp<,*'5he/̆#$mn 9 ?yƼJe kObVheFySSJ;NJ[]JLj,(2'22_R!=U!1OR)O`҉l`V) @8fUO߼?BO p ɬfH 6)G{Lttx,ř{Q88_Lf]Ka|̳InjI8idx fkYhئzZ ճ59?ZL Hd4WM 7֙6 Oʜ%ptmNhnvh^v/Il0u>oo:>uD=Rf-|GB k 7*Go=TXbo B~VQagc#"*0:;D ɲZ Ї)3P活Qi,VYqݟCW7ZzaZ:cb\jwL`ڲ\`BR=b}1!DWxjT U3D k'#[َ)_gŀ__ˢR\Rϊ7l+G(xw \4/MXA/,zVBs`s%=1'-nv @`Rbk L1g$ێ$S!.UVmA w9(8)pd9 FfWW\iTglqI27]' F G@D$Xou^{tm}921'yEe$/Y? z 莎ƴqߧDY_|K<.F`F(:?]8x`?\C<{{ΌSB2F = |`&&& x"2=#3K}lDO#*&?oh;zemq{" YYguqrFSX5"7P} bd`%[ye=cd(,! Q~SДg׻ZMM) _*-g8LNV9> /tf>?j. qZHg[{i "=_C 2f )Iuutf[hy5{v!fY=Rn^Β۳R*~ @(o|O,RUU&G~RC QeMXNa]b>EehdA4=Ԯ.k4 ~Jf(/܌- F)vt6T)m^V@.qo[z7/sjK+Tֲ|.3tRi0OKBG|sQiUd~UJ9Ҙc9k&*jYXYe7r-.z vLD iwcBτJl\_<[0-mC1ƍFwe;Vź6ٓV!Z+€w• Bhk/*jQ')2!boRӮFn$]ݭ .x|2 Y|rH[ ke8 d6npS+H7%)kiQj-x#XFa `annMUVzbBa"_#0JH[O MpwY/ w̻Cy;X?h s>/Oxd^0o5EoaCtVYB}'w- o9F3|vnƫ?2%evy9J@b5pR"W-[]S:Lr_||&K4"wvui(]udį`g9΅z*0Pzz j6 ̔UnMϝjŒ茎, P1<M))y'󰚉 _!Mу`^\"~e3Urۊ?xw)W)eug2-fϳl L$ K{soi!! ``kjr,:U h2:S4j5:r= 4$9"˕> !DKDT:kVdf;ww.Tz+ #D]ϟ} .Wyxm.ƹq{}NVp=foDP^G;o1__B2<}{I V6/_nYP}eq1ZeLبeXS]pLvzpHq3sz(bʲ5ٌKc&ӯ:ϡg_hlSEF3j;-WMwᱎWF!SP`Q+wq9!r7p-7e]{f }wzj{PCA([?S-%38hYtsl˘H\. <fx 8ߔ >_Q}f Oc&XaڢN`f8U3FDi-̀u] Lޟ.Z ?>>%jp3Ctxbp2 ~t=[yes)h(0r%nDx_#idָQ/;َe5OWw@ś_td2.]en6CghI `j6q=),JȹFB\'NM)n``Ș:4 Ǿyq] DSۤ6!-,hǿ#F|fD*5 _*vwWLSinn.?A@@>^[[ zurrg薎sŸ#XHeRyQ?W}V*\ݹF$<Œe珟fϾߚ8 ju+C>A>u_{ZbX/ e ;Q>«') F'y[U/II;utx andP"ROX~YnTItUl>#&ĢHUeee;fҴKNt?r(g`a֬0hhK%qڼS04hZI@K_>. wp$t`qQdaKPf9B)=-_<KӼ"qk0V {g4m%N.OjE"_c@-ONGWJd_ΑHRFPn'%Rמ9,Ų*Jj4ϵ~UJ|6/_zw~| սt(eJ46iQ34HaÑ&܌R<ɦbR]q z}GhM:1i8jF=iEnck"w-yØ~\(+gstJH[`LgxU16=0X&e1ok9ʼz )O`{^&a"' _ş$&W<1!>>>Sl A\F|g̭P:绹<$~U)g5eRvva!YO';v(F^LRc3tVjR8NubCĄuXfV[3/phhN**Q޹? D Q&+CJF}!qk_MvO6Hj\5|`$:UGv -}g93T0@HxVQ-`s2%f4^kܫO"%:-~`*jmyDvgXPH=UR2tPz6-={돢JpkNj@]]=22_j( GSJ\ >w!2cf&dM@jr}Mb..5mC[^鞎2ݛ޲Sw-"gPZP(? M9!W4Ii҇ Yz6;ϰvdز Jdg=dI$YK&g"« @Ǽ3<.]Z0 *7')KYT\,8eXAk$r%|釟Os# GGe:eH`az|\ 3~}s:>zǜQIɥ8j-?h,d^T\\\\(T*:q]'ÏZxT5I7[go^7$2;W~3!Ej>__ n XxY% eov ^(qcҍo`-ϣ 7@I:']=КUz</5=MՇ'=dg0\n~R8GK*Xa"EEťP@xr$1vl_ V]tc4d/֖B>/\`.߮{q]hL + Riqr *ez:8&i-y(#b ,JFi#B7_Ϟ^HdTO9_N!(N2@H]- Km:k`GxëVpe7Xz*Cx2K Eh⟩0)t) _@@e\I$1aXDyFVt9g;0kοXT0KǓo;`Lpp𲲲"qDùz}?' Ȱ!\6ezX׺PXdiČ][PyMԲD%:/0بetc)͐ڶxw߁yO0_ZI}DG}W#3#N3\7Qm~C"sվ)g`?ԷVRgfv\'4e&pܗ%r49W+rx4k9Wml_.݁q69vy41s{ RMG\vR_4J=#3^Mߐ@y0?j!r),Km?O{g:g\ZitKL~`3XE}vb?y[O'ė Gwnjbe(H=wy\9t3ۻ(?yg_SS9M✋'[ _״1~g9$]EcqiXYfbȵlo\p#/O| Iaw$=Ց1'3SG"bz5=y[dѝq^$~֞rC2g1!VpfFB-w?m>E*[OvC` .Z<<ݠ~5:Krz)$8X\Ld|\\jtp7z'kuRx_\)V!6ڴs޽߫-ז7Ӗ?{~>/I\ R_JrmSy:YUTc%yNS=T>v~i@Rrzo-5Y⠖;W BńV'=Uld}z۶[| F 6\$ۮ^Bװ '!C~,k 3̿pe(h$Dxhz,䨋8sI>:p6]MGGVqE@ky 6^9L PA(t8sPtTT*u܏ʱ8LVi lb|tOO%A>tK nWJ\h>0?c:; >+Ϭf*502%2_(R}+Z!+,cx ðGהLqleCJ Dh!4h4; IQ祤o*Nb |L;=sS:Y8Pwҽc<u8[{H $2g6]X[WղT_VcЙ|3܂  Z_&ʈ#?z)CVh]VYe /uv۲i]O8IY񏍝&eDrt *PgEX+[??/I'/D,q@eu)&Hq"Nר APWW&`4j1U흙p?,Kxޞj"bil: E^#Q'֬[_ oYͤ5'M\&LA^S{DeN" R8fCO^TD.UZO-,, iIV9E*QYr>:.5* ='pal6l)&p&>w^t7J6x*KZ'Z/=/!e(+y\ll Nݓ ]7;7RYruU4:^'g--A w\@F oJ뻜2w4qî/*#'qOTטol2`2G+ԪT_Y\^We6mj,_f3Kdi@LO̅TCrn~6V5A ]Y0KP劯cC S_ (Q4۲[B?{?jlDR.Aprs wckrBe4 ‚ Ifx!%ci?IJ%%"%q0r/\zHn${2#1zmiAw암w5 fSGE09dC~z)ly |`dQ=S+mEBez3|d|5e4(1Y ڱ13eV<'jG*R]a:Xwߨ[4x Dw5 .R^sUU3`)ˢmdp&%1Y13|6SnYDyzzj:I˭I`>UW&e>}6f<)"?B~Wmc(:6Ig#Trv16Uh;:%ە/궚v~|N%i:_7As_kXgEX ¾QNK9⮫!PwD,;wq*e 0rG:.`4|R]*%l[LrC903# ê5:3+25^{^O#oJlQ$O^τ*.O+83fp7셙h`Xzx{NzM5O#[DbPpfZI@ƺS_\?(W[:O}6&{cDW bU$[$ܻ)+4E ̩9F[ڣ aTl?:n0fmVp.\?CG1'IK,f"Qn+v VGG}gs: D[oP 96XfQ"#^VC&m:VB.JBi^ B>LCE H ϹQE*էa=A(p7Ԃ S.J_Ul* (!wi%?q}?zQ}T{sk鼟p`jhZ#goW6EJQWh7x 0=o`3%9>hM:u`㌡PzԉLD#+EHx>)⸜14sEKk.&hjI7-9{~rFFZM.;m9ޚaVyBxTTg y_21ioL{SKxCR^Χp+.fJ5`7(/kG.pWO O>'mcЧEҊ ;E-s@$((2 4I hz?I^[Ifn_e&e&XƼOƅP;}e&,Nsؐ6#ت0AqUB/̕Q8q4-uw=5jvoI'DA>'W z }s 6(NV+ w҉^PɇK^!y!)9*\Y L:#Ac<\{7D:ݹ0 ^ts S^tv2u*xD:տO7UdhGqUE x*Uж% ՟@_$jIDkڽMyuo>$+o4g{I{@TN!) j9A"@o[#}wz-H &qTIzvoKrJU5ȠO3ڌ_L@Tv38 !@To#\fXi[rvMsptY5Ǿ1n*`~"2\ ߻5  wdJomբ Y]7gbj͙( 5_6"@"K͒(굅G). ד.X 9dp4#CHM1o?zvk7ĒNH|fwdCQ!9"GWwUc 2H\fɉq yb٫򵂒. cr녪!nP`X!T^aa3:cfG1 B|ͣ | ~IA:0<\sBaU4A4L τ"){9cr*crǞ FE@bLhW'ZA[X4ȶG&rؠ7j-o=*u\U&[jS54g6!z^[tQX<oi:oPٿ(^9dj ݡ`$mGV W|hL|jڣiT6!xywa^y#uqP}};V+>V iY#| RDT-_̼dPurKo # wIdЅUE_-A3"T)`r+DN.0; bfu";-Wjuv6үG4[?kx=\K)yrz )Aw7H,Bir(R ,9fѨKr\t*tE7Kܞ>yh&U<,8~U _]Z- BmS1WEe6QY F yxNniέ|T7P kw I4=yByGkOK_۬PG f%1;G_@3=OMç772I/νc>B?؉)Tz8\vnlw9lɆ#jO'y8Ljc]EE7+IEY"c6 KQSR7AV=J E9JKd6_&[vvHuJ~V Up0wg6[G4A^oT DT[)6UBC2//*Zݴ({EF۟q6ZA_mIr~OuvaD^pK! _ڡZ x}ZF(}9+_K“ XxA{GaȅQqc24;{GLu0]Y7C5MrՏ)ήihƵQ JىbXGWT$ Iu>~FS@E' }Pnf@<C8Àue kG_z>JFHl ?lrE:u6ȭRDѯ c"PO#k,,] nYK 5ԴY[B nk KgakORZBCEFAq;5\c.n I&V=wBY'\eeV1eS)Ht}ccfBL|hg_F*ǿ2\y Gƕ ϓͰz T O~$SkJZ %j5sW.'@$s*5Y[Dkdg?GG/I7 ddFTUs4 $E%mnѥ<~IgpUU6.Dk꺯àUT,k^uȩj?[=R B+ŒzO`[ .sAwΞ9sLR࠺6D2Ε! U`eY^vps4v%A$bsq' ]ARY%f8'XjTlUhd!K<7Q4o #aN;lyC9$ڎ@I~cשAtg6E"O6^%uJnUARZZit$8r_#lh^(yp3s2{J,w3#G7_!%H-3,X5X+B%EU',PLf.K"zr9,c(n*|7ɈZn|d5i AsJ-s~1|dzi^42"l̽,WGwm8z]98b`[m9+ɍ;x=+n<$dDhGzz`@؎]ki:>8Loq!Tfм3wsyf rϵpP.Q;'Ϙ'-l0^cGq5Y ŗ6LTxd%)' ]U /'.'^4ź8ݖJPrQ`tEWthL\M=ϳāa7V즪5ݕgC[|-,fd"_pKG}^WtP8yrL&,դi'C,+7G arb1v0C-g#令E.sYs С*96*"_ԬR~[>^Ytq^%z ;IRh Pq_[*4)bR`Wrqx|t7xC_^քUHz7}߸A>(AV('XEYɅnƠpWk ?vBI4 NE`ae]9S`A&r"8{1fIGגN AW~T"tQioZJ=y`o8K> ?A2ڬUY.˔ S+T'\Kh(X>~Sf`7vxYssFjis ܡ<ƏoB%VդFhl,S@*>Z Xx珖CeNAg*y8}sʶb?R꽼b58a`bi6$h9- C2 2Dαl}n3_&łP. mDMs&(6vׂglJ5 _֍:!_XpBՑrtE]UDtE>o(щXӨF<;#1\^%Q#Unzޝ UDԎ]ڻ.7Zk?B1GyR6rQ!3Rh QbvoWK 峏VbFٍg#Y' K3}coLG nx]8 }1PO#aoߪǰrz9ˑ[hqD FV~#ԕId&31S2"IE2ev&a=%De Ʊ2Ia0~Sڲ{ή,a `sSszQ+Y#cq%\?똴YCD\*s3bH cwit c@t/C qTJ$";x"<,L'oNj=uy Xc!L^\z_31糑tD &duyL ѫcZRLj y/0h,$f)ALyhD{-;46!U涓GO5>U;Z1bv CsITM|[?'b"q^VvC{ٶ0[9l23,hvc)/!;6Xz|$~M(HpFR!6v?\3e6ǩ{fܧ[}7C~VVx>ׂl'^\ݡn߬l92 JvXgyK2[z|WaxgF]Zxu2 jTTlY$15rf8Cb_ 8p݄5/0ܲN]1b)C+2ZSi+i(aln ?wwZJJI!9(ɨG4i}sXEf@CygN+|fIBopK$A|vOŸZ8g_8c_2㕡 ā .]t~'ɻ=ؒ,Z175F$R#ݩoܣEx엌`J~Jh6:%Xl N߃,u^n8QE;&-|ӷ*hGS@kUe$)Il YƁ7w4L.V(tݗ`[ƱܢsеE^^;?J1[;{>ck ZDNr?mzzz<:fKG_@yq?>WZ$ A-o`iex?_3?2p  ˟)&?YCsG]{H [/xD|tmDo'UK UTDq)+Q4I9I-<[.R6+.J.]gNirtQ 9h"}q Yuʛp1SW8j=5K!Qvʱؤ" Xm=&ըQN9wm2H"R"5+(A;pV̳ ; 5tmS: 26_zf2 fpW`'F!3$hP )GS7“{痘H%:<]  9͜EvqI9t^{>DoM !w:sTW'gʛ7Y!k7C@:U!l;30,>Y3N[s>>A#| Zf8Q70 zLhrWZ6<<؝鴆7ۜ2BHK|?#hȑwzs[--u/ &&6'rc<Z|&ǝ%;d'*ݪFR'u.kXO&-. vM*|0V_WFtOɯ@ku?Ͳ /܏.:ۼ=Yu|< )-Px;98FwĈJ.7錤HeQ)fT[ 2KL!mY==hx5q&9t|40Ʊ T>TWHECxnRBR]߷yr}j*4DďB)=/5"5oG?#U'T\e>qy2#C 6cvR(fqIM["_>IFb)͏7ק8-Sb56Q;\ȧ`o] <ɇ\P 璉b7U5an]WfO3P2_׵Y&69ISVV}HƧSZE2ě}ω@#nǨRAj1 5 5I+FS\nZ&3Ni Fϭӏ~*VM ᰒ~a aHL 񥔡:#@͝S[,yܓ|EGVDVR&egJKַFڜ 񣯬%n'WR!HD1J|0q )ICBX+=/K*kX &CtV{ŵ瘗~0NŵE.A)$[l^'H|wR)VWee|%n6iF긹iBalQ8 7T9UA޹mʅsf2d{e{] q}0R yt%}!TAN"pGolQKꔩ<\ WRz5f;,;YGnq3F852Q]"PbU c3DMuN75<;!M8 81_qhLPPѼ=x`fNt}3Ջ1ig׆1.r +$"{әalbO|Z/Bԏ-${K~s^'#AjYJ'Yٽ}ӫQmB7K7$nHίcFYK> y`NgyYh,T@+U盒v-[ a@(uQL1gEz AIoCVΨ"qp]<"z B{ЬC|YJXsw9nWKRFU|Y+El+-:\R:Tl3Lj+z Ab"(d|Z1ܪHMoPF]Y2d|bƛԧ4$E{^ʡ K5C?w,)Irm!5QQ&n2@Rhvޥ*JGPO֕(0 S_+}i`i>`Dzݣ]I5!v[jS #ZnJ׆8np==n{NP&O6iڎe3j-wWjݡ1JHjSn ngJcqlqþS#햃/6҉6MW#rЈC“ Ht lKeM `+Vtnmx/BU1-3;˼ᬎFʼDhð^#й^ߝl%VJXZx‰ypt,кo: Ӕ*NB}Ǫ ,:&SDc2GdڷBO_EQK_B"G?ڞk7) rr8$w .HO52I)X6Z~ZZeWG9b[̭Z9a\O'"bD3""JJ!2CDg[f O 1 1yNlF:E7O#msbExcp_2!l&q/+ll* (A_kR"C/`'>s8~g%O=LgHUFCV `zu}9y`t0,9}b8\weپqM饮O|MđH(lIHgLǢ1knݦU(;v[c #[^lHvV)̗ I!w `Iyi"e=bQ؉ Ma݃+eaiA ͪuDzuח挒NV} M85o,DeLhSt5O?sOʩYEQq]-s9^-bcNQ"_wm&`࿳\ߒ :A[X8^'I*3'Qˌb$y0Q% c=ṪEgڮ*G Lq7mXJ(`:۠ugLC+u| Z͵Amc_'F+G\py)Tu/BuG~$jO7fIݼQGQR>|= vxMy[/M'}V?!qwTM{xLBW!}Ty›5(P+öbhP~(+ OvF/{U9 3T1CRUmo"!5pq|]2*E \C<XGGmKƜ:iW哵c'cu0AU*(S5 2}w^z)QH4mP>u %w;,E7G(b^QDpV.$64"hJqκwq~,y?F,ANbI^s8b\J2/[ [%8Jֺs=>Cp苅1[녟{hf&"%O},rT3nՠ7(|Tqk߹+.-wtAYDPS:R /$ lJj0L8]FWdž[hH~WJ4yBje"le ~W3{&giAҘQД^v^A>q%i*TG -ۢB<ؑH2%3&{(F@?ЁF# ( R lFPu~+{MNW_1t B_jb?kMH:y(b HCDjF3rHD̻m4SYEVJY8h& O8yUؠ/4J'o€# ]o|ΩnF`{\wS>"9v\(I4j'ȓnrpz@tX`gZ&L YDTD)'cކvceE\k#Ү,FPY^\ :z NE~D#cZO?L.dPyƷ%|\FϾ3{̩Y6>VNx=㲥+06jK"Hr1‡0᳌%4Rq{Wɒ>Y!~$=Z<Pp<,@kU OArWsenbmƐEFv%ܼp`[ K eqygqYu?}|!{ \quN$H@ED:rbb?@}EkLK~'NqGr7=B5 ~-xΕ跨% B"eqm{AFYcBN8&uHR4 ~yuawPیGӈ(K+vҤ#]O'cuGp&3FX]-8%HvY g=Acv- ?T 17j`Hem Yceu.7zߍSiQ/.g4f&xWMבDG ΄ݷ>Z?jkY9^EQǢb6CGئV:ٖID8MNH WPpPPP:!(( o>C{>mr{:o |h ??0yE?g{q=7+.엯ԵoluO~1o{B ]QϿԐq'.xoKyo= s+Xx)]J;J~out[O#,~1}/|o{XU})C[{qgMݺ3Žʦ;K-mGTZZ|ڷ坳 GW5mCmͭy,YetUsTߍ9|}tRwOVųz=\tIUo\_{t[kq¬#~ǨGͶt?}w\mOI_ݻ{?R܊&~9.xt_~ӽ]q|{ho'?eϻjfO{ >r^,d|_O^?nsgɦ~qOϝ2߁?lӝg\W~3S^Y-|U,ڗ?KNvz:r͖_Y^ 7r-7h,{gO\ֺK;y!s2״Ϙ{>?^'ߏ=B9_۷ց+?{n\2hMϹ,si}dE}OZ=a)g^x7N}sSE]v{㋮|lУ{Ҵ޽rdvsyލWy4/7r=#^-cn3{]svA ל5DO ݵ0k37_9߿7{syF1{\Os䈑-ug8/ita.|ok&iwiG_#_ͅy=+䂛ϼ7_ucx:ۚygc?^|*w.`n_|S~8ǦO/:s(g>fi^]st^^~wܬ+ զV^mQ{?jU]莻F|'4vYӦ]{MW;aiwGǻ /}e֑ιzoM?3nC7yIJO/Ѫ^~F%_?oiG8k +U~o~`| [+߿0ҽ{fzg}T l=on-;=cozgהw~oi݋{⌥T^t/i>Od6׆5O )Yis6ʼYtNշi?)>wpEfn;Pɞ?>YNo͢+zϙ^smgu1[{Pr֏>&_*- c^R_{'蹥i?8Xw9ͯ/[hܶ͞io Z}ɍ?oQZ;mϦs>{mZx^oiŀeX|K3pqʷL.)=v?(sc[s#=[h>׷rt/co{)/&w`kӇOfQcư'fKymc-wl[_}u7n}Ǧ/H2Wӻ W_\z'_=kY?=g?|yXKޯ8Pxq.Yn#&mmU|W7>W~Nǫ9,6^2׷_/7|;;*6웣v^s_H?m}p랹,m{eK?5~ eWx}ݾuG{;ڞuѧ~=䝛:z|Sf8]>9+uٹf=Wwot΋~4i=yO=?Θ4uI77L[^ :uu;?s7z;G{MKal˼ߥqQue#{6=~o/8!|?6vyy^v=\ڴ=kNGW^ќWڳ⭃rv|퉷]W;[g{W-%]'/ɷo=וgo{e7wa۱a; wtG?v|~ w^kKN٫Wm/^3mmWFߵxmtŞ֭~/Wvuv]ïm[Po&7u|´̣;;v+V=i;{gwʑ3[۸\cş|b]KB}KKG,Nn<1|[є33˾Fyl6]s͓[I~}Oz/ծ6׎K1[wrxF]o{~韝|ΧlrkKW2|<[2zt̴MI7^xִ.%w Cvz ;6-|yr/Fu V~Qzd?W{n-wRMzֵWw_[,)?,Z)8q'ψ\sSW>wf~-_Ƨ/wߜkzή97zxg3-=]S~yb<$JOyS!fJKo[.ܙoO+v_ybcn)`q~ɺW|/6N>}ȏO߷~WW=#Zs^~/nh3 ttƭ캷LX8U/ySֵ䡷<~}?מgrϛ_-G=Vxnu[wc_ˮtos2{I{hn53޾ɛW>~Mg/}o;{\p[-,Ԧy`ւ{+;4mVZsg[qe7={ZQ+ߪz^ź=#= /}TwШ_!VO\JPPr|.Ox`:#/q]|ƕv\bd5b%'gHeDS6Cg|욨q`N6N2P9퐀_%e6|qo^f~P^4pӑD*1y7[`65TCIŰ,RC`/ P(QEQ5$EJ{IG$Z!\]N"!eiUp+=|ǰm1۱\-$AQQv(0o7Cn#mI'j[,ǃY\hq.΄f(|>83ln RzI+˙tf̳s.ra" @\0sA6, v(\0|tQ%s9PLדb\ӓxY^"gIw4+i;;?Yҙg&ڈE@PQɬ Ac.PcX`yL3S!Lic%fspvQUV~ʪkHSDU`$ JZe"_\%(j(FF8#1 pnؚ(`[ d8M 8%X8"Ia"as<֘'fU;媢RIb: 7Cb5Z #e_ rHR.f f0+?JD*\р(d%P>51YRZTBU5uu8CՕEU%u1ZUMa_F~6> -;4`hFP@9hjŵ5f|p 05(A# crrv{'k02r8eؚx XF[;> !#Ї0x@؂l؉?RQ}`jn dgZg)6qC`C(2t ֔'80MF6ZWZ[^?F-DNFD<< N&Tn%a8 WOm>;N":001`)CǸYGHcB($Ibؕu$\**QTYSQ8 W:>C ˫@VTLLKe#Jf0F%#"<(z_,@]0@SYURڣZ #4x"c3 3"gNidX08kPT¸-T CppޠFCjāuH/Od&W|Te|45(ҜsӃt-@_x]C 4.*`CjSZA%켳7)t0 -ވG$>MXaNOA47QJI⡸ Y[FxM4R3/[lńUZ0UP.4*@8:PC>fX®:wȄ ; ݊*F~ duomMa Za -)r{8I9ny1jk劆l &tҢ1 }&09Cn HKLu@죙hIdg<+U`aҡXha˴N":2¢amH^AJ$ģGsCS#$2rCBi?3 JYmnԩg 6b'O)ˑ, ম,gN8(ZMZT#a,bn xAǖtՌa'ii⨒)6Y9΋VK咽#12o %i>ϝ7 cTQF44-Ln ,12}y:8 fG`AJTUI9/!zgkDSEݬ0q25Cm2i:>0Vt&Kk;mz*7Z]7IٶYNKGbOܿчϢ>.{WrdSGgIMCc? Ƅ(8y僺2ȘE$I ϐwz]lZH GnV 9zEVHG%!i-1H_G5tL^<‘=haL6J&&zR#ZR,L > iidi%!bFS qJjQIWqֹ$C&D3`0pbRmvgV__M)1IJnnZ` na+ז @ df>HQ*Qᆆs }LR5C}UJ<{L]6)} E9'S:LjTPd ca)Rqtc".Ipt583 6|hpD(^Z4ASGc}@07$Ĵ] EKdD *s _`{;%z%Wxn )1uא,.+<Ƙ t8R#(ڱV*h\LE9P1 2#DqxtgN[$6Өt "=Hܷ() z }D)5 .1t_b |"O>1;X="{AKNNRH4x̍ eKu$\itlwɂ P4F%OڄM1Rvx6 )qmF#ndY"f)H3lgvhFd왡c} a|[z΂udu> :szjOS 4äS@,#H2JЍvI.$`)=m'ѡPW&'Bp[IH$\0)`>5n˸ s[ SVQrNl2КȄ5e${J6n46Ʌ bntX4}in 7=ZI(m`#L[p Ä4]T?G I\ 3I#w\2dȖٓ`]@`s=-%qB(kFHk*&K'ţvjTu&eNaGda- bJaq`%D n| fObU54*`%z-0$khRNo'Idq_ Ux : r?Dh`S I :bCvaFTx9Z,-lVZ[GY!_C>b&B?qZ -\7-$טD%Ht|8~V$fgZXC~NSk0ā4 1Śm&B)l_m751OXuUSԓcUCft E$#fPaqAMa)U!!,knH$(K²ZilB ^%tma\жaKQf)R=%EHX U =qCh'*LYrY}}~Ӂ[:,~$;MW܎:a>БVqiJi7&L@Yg"iV ,Y-\bna#SD +AO.p@LHw4%3$pu_D q_ B6~֠%`h DF5qd@8i˴\m`. 3p̵*L/61ni(ᄻ".b {6wJJ|ggIuQN3բEU0E=OM0(s ̓#t;pZ7<]Y@>HȢ{lh0(HիmKlI\A tr֞rf.ݯ `PmA1 X: W,~$%̻ό NvA* 8bL._ft/Q4i31> xKD=F*%PK7"Dc̉M)CFT򉒽O=k=8WSS&Ц. u8k`%g'ZJR:O0@z4RUC (qM1c$R˭̲"0uZ;bx5pLdQ:SA)ݍ&D E~%A G[M«,8N$`+c4tFI0 eF2%Cć42J\KS,%3~H$֔Pfϰ2.@j!ꭔ)l[*pH SL4h³#bO> $N[7棛!tI )q[4#͐?,4ܤ6 [X %]I >pC+KqCX1p|Ht:0|cL[db%f s?X:5I3@|bS,R6]͘WҨF0MsÂY,!Y[%S+BD` ҍGg㫅+>6izP]``3,7yK/f±f%*/"v7d=,|dI}MLS5 2t M?E}c\y<~gEh2Ņy'Ѳi fNo%FaM etִcH,Ž/~V=ERe#J@. i{-LtYZ%蹥s”H0lMc2/ e$-qV4},,9NW6ut`Zv @l N'NlxFɫHIg)^Ef2]7QGih=jfK$SKuV > 0v9M.t.k[`\þ-.al_SR$HҤćGoa՛-WRU= |WV <ix>NQh /K_Q^Y^_$J(e SNq]TjkNy M /@^;v} =9_5zFl4ě"ȺF%u ]21e-fI~U Otl!Yy \? %aj D& b.{ uǨ #r]Kt7Ytˎ |` :(- m]oc*җ $k8(`:˘|'` AҜ O@T[{Mk|z`Ym2q6$KKPPNdC&֋mGyv%\#dXVnԸKӭ١C <Z҄f .i<aVMkX" ځ4,N€7Xv.OERk,|ߊT׎,1ਝ6X D Oh'J?b[|j<)OhT1WE,/JbZzb@+`f 0PTWwaA ˶?ב}Ƥ 6CFRVH1Q%'i e@ 35ZSΦȕ*k.$^CaG 4{o%9,?G8fBS"ニ>T׸àB@-am*J1+=iP5rg ,ye+GPY8r+pav%+ v?h4&8aPԦb„x$@𨎸h?UmV%3Ny(%<ۙ7%AC0 Т3ᏓA}Urˍf~5z>\ Ccat+d-EX vF`ݰ'!L]dY~zqnM(KV]o`*|&8 4Z"fK%h=+=D榨1 )4:an.EFh"H17%VQ(]PY}kjh9h?Kޮ|ѫLYTg(9xȚ1ŽFF˛3x412/鞣%3X ׹u(u_Fd~ +Dd7mt>Y*T 6 } <1jgjH: ^j}D >$O5̰drUVS !EYG1V+SAMvfݸEe+-nj%O.&dov=<cܜ G9+QwUh3u0Í"T4"G6<J} I]v'il&`6kM;eM/oLutfMc! 6]uV* M"A59ѡ_# $Mf/o0S>Pzd?(8,[*.F7ygS")蝿G۟8J'5+/H͏;GcFҝ*sBӦJTNUZZyA0t!Yt7@ˆ~SQ5GؤJ&jMrYjQR)bFz&xv$HHk޷llTE3.PX47?YDF^ KDH pƢPFR0&k c$3IRTS.EbiviVbzׅ96 GAY\b} 2XxۅGW,+)7vo 1Z1)n)O#Ѓ.QU>z@mL/I3]a5P ^Iw4JVfAp+&7+'a5™jd^깱#Kol@yWo4pBj QWR[ꈍ-{wlL|7(G7->8X'.9YbaLGDZ77v7i20joQ& VPe/5&asQGJxPZG̊ ԞIZp4T E:CIk@ib)Vs'曨g_Hs{^E</Go[|9`(+ RP؎IMΎ)i47X#O\BY ^!V.YА!rZ%jHYj'qcqKԭ}QrVd> &0NJ^[ٴ$mV')z~¶*e7;i jx+9J-<:RX]4r™JgwdzGiu m6/,򲷺qE22Awf4@+s;Td.(D-_f5nN۝p{9Ӂɟ'CYPI^7 ؍]zOJ'm:1tAg"4r>PYZ_V]} 1-B\R/J.iS~Y7oXEu VL߆Keq-:p?g]ޒ Z/}!ߴzޛ!cXO10oLgٔoH"H\0_zml&tTf-#t6M#@hl f%nXFj+W\RNz%SRI/++H\Tk Gfhi!kK&2CP,jF:I1X3?vJ(1r0PӦ"KYd˽bNri1udsQ`e%<-.cm)IN6k[ܯWk[`&Ib@P L@RNoVabڮvCTkPy[rFcK %Zgש͵3}9}X-Svf '~{#܏7Ed4#*Ulh3}<DOܔ{Y9hI6wYYGk$sr)s' w>˻UYeRE58}dpD1R/YN'>~syas'Ƣ=9Q-#Rs˲ kFzL,q~?EMMY+T&׬`dV58!F F_V՘ᢥ3Skb5e=*K0ޝ4Qu>9i*eڗEk벱{\4/dQQ G7nԉuF#!Ҿ-m R"O<4yr ݈O?Q$&,D^c.@~#Dq(S"4:Z(跬]?-x*SAۀ^JaLKF)d+pZ 6G_Fb]@ @vR*CnEĶ oG `*D2We HFA:(r;s`jn*Lғ;b*L''$EA0w5U-[r71}_;=Θ{mVuvF~c)k B6i_g16$7 x`9 AM#|̲ӾzF8_ahՄD$f" kܒWkkR!"ĪIugQDFr?I)fW;wٔgCE(Wcs2ߘ*L*eulWL#5k*%Oٟ}1?Q[њEQcm_ack1Bn=}[kTz0͇ZCLE0) סZƾx|$&*.UNaPDDEQ]Ejn *]x67-u#uwܝoӚSLNyiڝ L ;An<܀ͷ^~K~362 E ee  0!J1[X.R˃M-C&wһB1!-& ^=)]9ҊjL„eAp ͚|J8ajnQ" [ً,2@]9#_;= 18ڷ˭7h{)9ysgWܖ@lD[9q׽M>`~Z͵^&77Wj 0SdOfbkT.+~o-یHK q2P>~>>gDOζ0M 񑛹]7]П%Z[% +iY |Y2rqu̓:94uLTyY>>G#n I_ Q\+0^`oP7ZV.lW允d8YLYTuκ,)d)'3.C~%l84NQy*1l*uLs"\mpX()7dß =^;fX6U H\^H5LJэƄT}Kn11d*e(OBr&KD<o$*|A6!٘:AOWbg=V bryEVvI.2 V PuԀnd.~X;b Q)ͧxE439u *H%{Hm5)RTҋ\wp|aꦏ9V3ġӂ@th뇀6:;lc`z}EK4c vlwvu+ Vzc4 )gu{-B`P-(Jh*l*]2dr`<]=͡#" x@PR[f4[ R# ρ7[IF^4`~s4~ "QtT\;qTLV@z8I3 G_T4O:gơ)CGyRw)_7w|(fRʋe:-8 P Mx]JszI#1/X6KՅg6k=yT=jTjcm79zE׃*_Z-<Ғ}GtfeR2Γi 3~x~e x颭0sL$~oK*/Qaؓ U3;U-NRU-ŽAr.H?,9=w|lnPW;kI6| T"CeVgnV#:ncEs-vkxϜNi 5G)rZEBxcs˓yf$yGs}Y&{)^\տfr`L7m|-O٢N#7ŕ"$"KZ62ܝn\uN!o_]:xu>Q'w4]ʚ2RK3VXjhu4Ii3U=<O? q*s| (U}%w;? dv0^|œ<AXfn* í4ك0Iy.slR;Xdz3V8^vsc.Bë8*x[p&#xx)zkwz=^O;?^^{ v(nq?_{Ƀ3L67JuihWUXe5-9O\i{,[U/cMDuvcC-vxьP~MHJg2֘qhnWݲpAxco:M6q{pWQ'Zo%vn+>Ynb6x2D7 oK#!Zz;>Fo\ DhZAW{A ̄,XlfPݤfg p,$o R 'Sϻ10t`%%ƻY$qٓ8,p>F=8bE3b&9ڐVS1 z´2LQʙkQskf%?wJ Fl5%dlΐ0Y'F-iqDMd2yzk]UOrS 7h[OGmܕbs"J~ҐOv$!phP9;-1@t8lŒaHd~2 =z8i2J[ ~zgn׃x>̹M,t2p?G D 5úbO sv-^NAO{oG ɋ(@Wd翆K#0& ϓd5}/ <ecPcd/{vXW &J8=Dp$ @cQ9l%{rEw ߝ&44k+&0 `wOTF2|Wyu2ګ%l V~!;K N˒uK&CV} gXEqr-4vNՠillo&W_^ jݯ a\w`fj!# {0U0V5\dUyOn*2u~闆Uq $1W86Xh$p;RMܨ2SV:f=an)n!m~"YY848lZ- I;``5V`4qfQ=XoZ\1TlP0"!2Rk}~~&!DڝYjt| g0V-PG~#qAqvW}oU9bdaZ |fFm08iFcFNOC㎅!c21/C“ A-RSҺ{RPm[V)hM=]VUGRl4-I@t`+9XH/:k0IUdȳLq$K[PeqT [P4+sU}8de1\DcDz賰 A r ־|C5ȍO=L',|&dI&"f a=QW8I֓|ΓkK x%[.A)׋K. YPDD9䢷yǍf|P֨fŌ).9l1;ŷ}X9F vf,! T'G/a ןn^.{D ZV/_`,%p9Ym䓄+ L|&r&MuUZӂXV.Id}[Q.Yq4q`F&Epj 񯸗b {A/I:= /tYadVxk]9?_+Bu tב΅Ef20'6Uљ~}$I,5pƜmh'ƦF[; Yo*j^#_û6e7 k8QY}IHXfKnɭ${ V.haUO׭ou S䊞<]~|5'NqN0'FA,S h^99%)r+~5Ж@u٨nX7Z6ڞa?17^`(5no3Ed[w-?B9]8q E%h>P/x?ίZhb {M/Yde5V][3Qiwի`O] 5$K%񇋓.)类geQ ֟3XOٸP+M(NP.e9h}VǺR%ٔ 8 eG2J6Qr-CXEQCq~8u%pY3åi.=96t%^_)[8IȫF?@蜟?Dmd5I38{޳)a|mB"F,11["o%j6!G.*qm3‡R3ҪKBO|mcz-29[PU{#jxXmV `(.1ˁTv0B)FKkuֈԮYx{ B o^,ZӸwjjeQrsMYZ&md)dG7DųdN8psĚM9 FjPqe"QxV Nw:VZJpEWFwMGA'$90 0pt<7_!@XbuÂ5m7Ru|t#͠0y'y2%5J &.Z[ 8&>lf{W@|Tip3 6F[]u#kc$Q=ka73hY̠6&0zuC2K34|0PDlͰsAײ7tgZ@@a9BiN~sFpB-Ԇ9HѾD2k3\ }/i-Ձd$ز8F&K䰷$CB|Ka$3WIYł3}9 nq!k~y1OOZJ:Oj_٦ s3T=)F7`fdsg 2Sv] *hʇܵNEeVٔL&5 NͿh|/LkyJ~ W" 6ѯ*Gy;&a0[K^bIy perCU^6^"\0n%~~l-rŒu_[WXub=ui@@mېb_Z8c00PAn^3l3RF+Q0Hs$@219/FN`:o#β)SYw`Z>q٩sUemMlc窏֥&b Gd vZ*UK+'Ac INQxp=Q?E$ƫjU'A/15:ikAGWwz¦s'N| h8|]O銎 ^~7%Oԩ#bru-vLM-+=!59r l`VsVn:gwe{>ӻaWS$.M8VaZ2=>uXIt?PbQ5olZHԕ+6"qIW4T|TU ǡ {Y=g'YnO?:-B$w[ B\׼=Hd H=LModvOO{Mc%H^ `^נC֠_©3PI6]>j3&\{jYiB;r~C9(;rVܕ{$ѝS!J05re->laOJ=n{{@̝X;KK!r@O  @6[c?ͲBO 8DIz1&X#bWҢ@]$aBrn.R|o'}wD}3I%&㈃|_iN<~ ZqI眎yijԂLjoa \sT=K_S5=F^=Q%iҹŤ̫?=Ux\0-ӕo<2Qdp{ W"Z@kXXMGE;˫ ,;#Ws4BbKW^ĠW.OQ:OMlfǾyZe+ S޷ÈSoIt uO81yx9X 9ʭO8=2-Do-8jȎ& N/#a؛jfġB~ 8Pc3BavDù]8ݵ]QSћ׆8>c3I:%áaeYOX0 i>(YԂ~Ylx^>kH\9* ̍,!A8iF:x 8ON_Ӳͩ@ckuFH8io#؍*=l֛i{.j>2("  Caiuʫ8d΋+V}, (qS)0mKu@kiX֘?@ Gewؤ,-1h -G8F.Pf /#S~AS[˞ø  <h~NX ~JU4H=x|BQSQAֽEуGk5f>%DyoG14jqv:Gq4Z]p;x]^^ =1WrU,Wp Z%ydFo͠ۿd!AU[Ae~`nɑ@KEM'>θ4tEg%|Nl˟mgf}C;Xw35Zсzz7 k]tdfBw nz8J{-'! cTέ9a3|vJtF0_En|/7i|UJý82vc&3+^t%Wi a 9#}DM?Q0?:rn4As9 ^&JFJSpߜ_[>mB>"ΰ?7QryGSs.%C~OAf}!kz\DC!2S_:nyHbLk></wWV'ɰC`ҨH 4);?BS.sW랞d%>1i#p'6qi} un]Sw_B\_]CGJy|QUxi?GA;GFeu4Ċ4ګ_ yo#ה[v!֠ ic㕹6vJ9Ic( N l֋5zwB-~ICD-T jzYܕkϚ^.c_G dɺ: 9+5xKqeu!RݞZoe<#P* a: gF8 \_Xʜ-I֠ aޱt8H,dz[g&\q5B%%GIW =0bڲ%u-_yuj NsRݗ*%ɵlK!Wۊ!jZ B8cuWBׇ͘Op'>fº/LTEc64LvܬNvBJ.uWsGonTq]k ⋶n 3255eż:H"9_Is[m_v5W'}:;fBWq{}nUѽus>&iEuͼfԬza κ4&sN" D!wr̞3/.T/|󘖡ȹϛ痯_<\y Avw_Lm{NsS5{dR3kT}eU-Uq8E\!iqPө00.\5Â!ojKjG`ꪌ*T9Ṕih@k: 5Üꫨ- K0z xj%xnO4]):`W!&!Ih\Sk^}i/ כh4};.TEٝBHzyHPWٽw [+`$GF ɇ0g)~E [̈$C˅*y=Q}ƏG1hGlxdV+?$LEV4w3$|!n#+'w셋TMY%Ίg)'кYU'GU77` U;Ue8D7 JA.9jy&|?舜`KV9Y+q+S.dNBd5GKdYC% Ρ\~PWvXoL4+vvD\]"!,vx~|"OF,DX~1vu>sDI1 mdffɄf0D1Xͳ+'|]gc-sloq2uW=ùs [wi'ͽK&\NT=Ȃҍźhr#Ǩa~.O.˳lϠ#f-mř4Fziں^foy9/ QP^'?X~#);&HVW$ l4\X1A2x`n%M8WT+Pa<Ķ_㩧OF)P[_ ak,ëEz7&.jLA^Z̄I6lĜ/Ӧ:e#ix?  pʆK*3 k!%ou%&x.yw⺰IHeӫFNGJcr+9fE.r;740RtP^%UY7P= 1R|S,Yz%McR22~a{ڒgg[L;hǨo>ͮSY;ukwl4$.Tٝe$ӔIdR3$ .Uz5udzr.&+9,X2}u+&qͺl۟{CⶁQɖ=,w`&67TRs⵲MEEJNg,ZInex|6A@J#炷Mĝټ={ŒjƗQLpzkuo,[lg3~it^{]VYD}gs+7J .ZBCw0 YYo1p m.nFT(dT68]BuUpڵ_gQ}CKMC'k`Uk8bItْU0Ns\,wc"3)i@8&"ޏ'ţ^w0K2.+O z #Ηaq5ʀV9fҌE6MH1`(U)ThZ_AY\۴uOV4LDD5(PTPST 8y ";d&g~ . hG~n^,8-.c9 2yDM$Z|&Gx~)-WCY3/@cNRSc-͒qS-Ãu`"-EHj:!k%ڳY-֦ɚ0 Qt/w=F2!=SA+S?,6g eNTtʙ̚BfF2Ğ0NfkRnaHdDc / '{Y,5h:d8BWX)y<돿n^3*eX*@<AuɡM}x:FTK:M|R0lFmIsO8_٩y+3=ˈ [(0'!=5A -ecAЭ玒ʡ=O3I'.KQ9$%1xߎZ&ucO /(RC#/"5q`c\6Χ_WoGT\D~9 Cҝ]vTvMk:!:NgW@\ǠqQd4ьb8"/h2+nS~ɰ<InpMoFI2b*%R$b4Ԣ,a_LI-H$0s60l#3FMJXtL΄#Tnyk|wZ+nlsT@.JlV75w!i+ % r2J4m*B1uSW caT8f*u!hr5&3̿9C4RA$7֑:CxYըDQYi̮'Dq=p/4!8jzbk_,ϡ<Q)=~+}OcEԘN±l$2MvAAV,R٦~EOUGlY# }D}T74% >HJeDjչ4 sP0$" /G^uW0ǖ_]D$2 ze}czTb(\|*l޸l7/OǽKZ%Ӣ1i =.W_HŕlZ6•[o}mJ[f4 <$uaB4MoH7 k  V,Mn]U=$*E>bOzȖ1_ץud4;fN2v_g(TU-!نoA^҅z BXJ~Gu&y5]s. L3˾T7e4GmwU bΑ"$Xq9gɕze'I_q_Y4fD$zxD ,Y3;eQOq^!|JXpER09e/CMA#gN,f< |\Ƒ] lh$W!5ਉ/eQ]Lyv~vIuӴm$g&d1@:wfp}+I:Wk/'2T4M#+ X]%v%TSbǰUH\1_EgfhةQ0wT!V/-a.{1DCϤ H'&ZwPpⴎz/s4ǟްDnRookaOh9n(G.jϙځGK"Z<*2*kUM0 ƺWTW[3A1Œlm( ]#J9V֋@n-aݒL.P^,y@|aW$s(;w3ڄ7=_*1Vb͓,k]#e@׉j*IfiUMh* #Z6IRhsUeK<`ecIc,}Vd2Uqy7urMW$IyQfa P<yv,\=ivՃd478C26D!H/z %>0KӍI&4#>/.ipYrXH& ^ިntc3oI4ȘhV6:?ĵ1𘴴& D$O _nLyRҤ̧'gnLyqv|nWu&*4(AvK\3 MۄzJ6x>x)ϧ8M n~/I&$&MlǜeֹpOڀcqQ=LE.$bW/$-`ny-~սwvkպMLy@pK~ o;J2oΖYu~1ׂxס,ſާSvM9 f{󆇲_.;^L .i`nOݭQ$TɊ0OR |2 YUT!oj)?[IiRYJ\t /P|橕 D7 _[9 gZE9d95,f`i!mEاiggӹXF̜6'ȶfd ﰡG6P7xLhY.YQO^02ѝU ,\^[΢S>wRR{wZbol^)Pz$=u{,x 56\,N Jˠٯp\ QNbdrqaz{sIWP헆vGB.| y+ŧv]FWPϝi@.;PX1W (`M?r/P\xC{ ;b([k,k0`I^I&SM^.`2uŐ5kB~ciM}}g?H`x"װ95*9*zedNI MOUaY4D{St(DB:e|'#ԃf=xƦ,ͺ{VHE:CE8h[f5C达"_?N-2'`Sl?.jYګU }3b-_11AP!HqdpGqFƍ,dL?5Tv UDVϬPlZ҃I&t/&:3g)sL~yq>Dh84. ?NԸx.[.PPEWS%^zxb^/w)CEރY:c)zD s *Z4l59^"Q<dr;"\sҗ>fŏa;X g}Iv6 n NlFՏriQg*l l`O$yǤ-WgqG{FgHcPy"e6 "uN2 L ι}55qJeʺP:l2bBp0T=_:,n>Kꛆ+35jŵ=gIռڍ뱀E*U0Y9֒Cװv\x4?WTgǫec^5@wc;3L7-nf~pzN2!W{暁 >_Eo1dCQc9ߢвfLb V9q}0;UDSpz8_ Ϻ+L#8/"`.H/~]x'(ujtaMz&bW$rF$;!'28:aK#Xv?bk,+;C7f OL1&4F8g+K /c$y26gIWho&q]-s,ԛ N': FM`G Z,n$7bCg*/kMgSv2]LLNZkȮՌ]36+TW+f:Rlc;.{GnbBSƃ]EIXHsi=O M{;S-̞*g =sorEE+%}C]m~|\+IRΑi.OUiB4Ѱ9pS] rtРwʗ.Պ#:G8~S䷄bcn2V>4ƁȆK,~A-o(B3DBJ}@@%u"{Ւk.Sc%Ώ`őI -cv(=Ln>dl'71@x.z386r6VPz5/{;:_\b\"U s;L ?dڽn;vhu/0JN4٦zj)o'& a[duLZm~j<]ѥ_D"i9-a]`#MfK`3Xۢ/mS ߆4yMI πQT#J(J4&8:=U(I #6M'/کٓ. =_h"[ ֫|eW |Ut }YiG_%LٝbnUf?FT}nKi*ț\-{FC>:tZ0tK _"u'">aջY{7hQiYmR#K!ǒ4Izŗ._ӊz/$H/j"zj{K$aƞEYWf✑jXC!26)X0FiRXciб􆏬H ![zAZ >zp?EmZᅱx=[?~{?㭟_ڷ'^"0֏ q0,`[{5(oA%%+p~0ʡz >F?Wbuz4 `tP"Y]tA>;hse{ɊȺ4A!C-2h,#fzM|hjJ[Y<9sd@Y_3 ǣk_@.{>@LX1Q䊭$=ap*777Dv/_nOgMޒk:JVBlFf~>,2oѕ%ߞ~P3[io 2O30NJ]Gee$۞0U^X* }eS9^3GMweiz%zjsMB$G#vJMOUTUE9t kA.߳`2}\F9i^Sk4y+D~>ۖKc37\ftz\NJ^fi[uv,񡋶H֫هU&Pj{Ԕ,}\cSfLmr"C䶝Ķߍ9o^tm/i8 0mH#]4?5*Wl.4'Mp`mivq): (wk>##^U:YPo82lYOb& kg(2?\#|Ef/ 'F1c{!.q~SArLN_+xssgcWz9\̘c|ۍ \dkv j>`z$a:^e-שQެ4r^BLj s=wT6jېK<6YHan & *ϚǯԻSjo1vC(m5s-?VI=ԧ~ˢ\[ CiqwՂ Bs`TJz'^6zǹ+Iz!l贮ԕd|H >B-1BU2Z'U1#983\Km${"ޢ3GA)ı kq qU.l"E[/,FkH(P(L _ȑo;\ K@t˨Ojmlm$|J;~4tO0d=Igw9ږFMb<ڸ`,峎Syl`B/]\Szh6ö\J `o=V}\/ s;bՄ=dxQq+nqI^_~\{:ܬӆ'NcU- %.?uH7<^x)|N hw$P{{ʉ$zH%!E_8· K~gw1.}+4#ɾx{pm׳$$ {ũ#Φ as%Q{wpl*YSzKkd(nzR^Z6M^<_%+W$Icre|Jfh/SÓފR^Z ~P&hfvI&A?~1^Y BW> 0V0O&{=ݠ㤿~}w}ܸs4^xj: /ux6o|z9"1p|uy_66^qa0^1u縅g^sۻkYo^, gk ai}F:M+ 8Io8{tyS>xW>`*RW%4abx7>:Cq~{/= ed&f&M䧀Ѭln&+8,īQnKRU/ WƌB:Fs6u@^W= _-lVft s#23Q(ƱT^7l9Upf:)# %#id>38 'IךL+1/7|2h??De5Ub0jYR+Az4;3;O>-Ow0_Ykvu->kLo?S>uFc\ލbl̕@Lujd6K_" ??~$u|~vym"xiI%%b;:?/XuyyAe W]Zxe-ulCX|fyzN\z,i)7}ӈ*!MBA`Ɗ٪%HaA-s˚_쳣ę 1熓1 !mQg61,.D,IƖFս .+?7U/VK$S”Ez-p"aVqh?K!tk"4OMZϠ0s] l>!VcﻭI r"Įjj?=}q4O3[؎BOq=Yd~*~śޭKӏ<])[Bd}A&~YBX:>0bM1SP}q,(+#+pOHLduhp;/V=$݊lRnu}AȨq5~v3 v}cUy("0<ԪY LnLתaPo Hmj5i=%@Z8z`q&tnC{ ԙX6,Ly^AgH NtSYh?*5A)0n' :A4ͩli_ BNL,bKC2&CwV^{CU)8ЖgnB!gg;a<jw'7("|@_ Y/ {Uɀ4wBs8li߹YhLvFT#3#LLyLZ{^#Ip Ж[A~lHWFdjwp6}`Ќ%^2s&2+֐=83Lzn["ktrjrp`\gN?ɏL-Z3%ʈ6|^۩9ow ]Z >D54pӚQyT*x[˼?*f|M`UHgerJGe'f(˻Sàf`=żO0Zh|;%H@I$vM. t5On_+ +uph2.%WȽćK0e©sPp||זy7Pƀ 5*Yf"+61e=-W3u!;Dyv5\7GFoXwmʻE'}NOV:V<dkD<5`+I oz%S P,:¹+ɽ ڸb)LI~O"Dӡl\$eת)\5bfƁw8!WSdSy6ry![b+Sj9IlHC{ m[b(Sڼ``K8J bM*:6[ʧy"Iy96fz~B8O'#R Gp3Ǝ/)%Թ[ cH$[T,pR]S.[Ef'x"]^V^6(k@qXIVix}wL1̼m1V+pG"+ģ5y>FY⪥ tOm_@FH,_ 9U sȪ VČϘƴV#h1&*/C"K0XpS`l$5;'pFΖI0 *'&%1{H[D^e%;CՒ;PX2̾seG 8z8[T_}!'o/̛[\hdiHÑJ 3 ";K\ƨ&toͲ'`VYU~\.jH,Kj޲.WL5pd>|쥢](AUYDrhUU eAx")onvZӲG10sˬV/;CȈoV /kti઱f~9վ˅&k7%U9(4? f cȸ/^.q=&r|u^o6[ȶ%OUхL+G8g^& ΤtZ M kXo"rOx-_ű-HO c(:ECt (f=kjgpU{5OnT9,qOħ1eoi" aǔ`+ XYMdT +!0av-F\|׶(?&wDrݏFQ5)FO8$uӗLE9S{A*dd}k[nN.g(E]B5ΌS*%ۿ,N~m: H5 nDAQ5:;C,zܒQS8ʑbJ>.z}H%hǤ%elZ"a:WCi7ZnQ|&²,.šgO`2\xLGA1%Vp߇l>X5*)0'l!"ꢫ]VL50?]S&Ǝk1DVsf2Cpds@ J0..|I%U{ēmAxjbdL0Y6y$Yg}k; ;!d+FZ%!iNN ]~P Wzp=&[3qR5q֬ rNtk4 .zuUi/H|yzk3ϫ : (SAdpC9?Lk[/riZ$SfƂ;K"*7R l UP* $$٧INL%pm€U :Tsl^V`J^V٠T(iCI}@={3g/۵A86Zl};mJk [y&9FۀpQGHǻdVϩ©FA- ͣ f{^3+`9]<]G|[l1S+'0e0j֡Y--xyѤ쬪Y<3+2qngyD״Ib&/2f 80-?m"5dPY="5N< h  F͘|IhSyd5rO(e<fUeUs`ś8\^Pf$~[F&NKQ lrb4mZA 0rZ1eC\l g Q bk+jЦ՜1ofF5b^|uCQeE21qEj0:?;sjkF- P"ķ=39-؛|٘*2 Z5T/Us`k l7r\Q;6h NclwL({F} q0eՓzS.-hs? ;N)\FÄ]Ə)H)8ܸp y{K1-0@YBr^y$M].ģ}bG8)ωLrN(A1H1A/fu{ &=Pn6cۺe'|eW`57"[$a]\GjUet.OkD],֏"Id(6UR{L* 3`Bk(,BYۚIl10&CB+8H_OXZjaPR!-c0!r(baF>4@{kqͮGkE6pBMq6$1aRKhN-gCohU.IFOy^ac;YͰ4>pGS{WB&ִ J:±LCIkS$sޠӧ7+or!ثBgC+lH ߄jEKqI.;γAÜG-@ѝ2JؘЀvSCI$Mbv+A)5fx˺:Jj*#_wވz^A;X m.R[FԼz+!͸%z$`P#E`S)kF`rz'sL 6\qWkle1;CP_sAEY~fSW*+>O@P9u3kXߪ5v'U!(cTVpyrk U[ 23Mɿ[*0>t_Pop_X*݃gzV/zkD֬*tJ,p* Fy}p̌P`\2(yfT_efkQI=_*u@*IG}⺗i^|kk'b\9۱_~1ӓ!`.V3}4>.rҚk|/.|oMk^ޟLb /ZLMb4 㯠Ai}ݕKb!/ZÂ@]{'W94 k65q'y hEZɄ26?q4M u𰪟['--'rj`l u~5YH|-^LK/PB"RQ[lEtN~ν82Oqeiڇ1, 5w:"᝵A8!Fq56v6}4kUI_%}K_7/I+dEcPd5 ylZ-}2$/z?#<YsM9&(·[1.WV>PiMJqEխ]k/$&sFߪfrX/z"V`@0*rztE٤X-8[8UBwۍ^[_vǞ<1]TQyMJճ]a2]s$$P&ܕ` 5 V<^E bG7$L?׃{rL%uD^h9уd"Oެ&^$gI\nBU#| ;6`R/ڴa:C@r[~ 1iH\šS4|;TY`h*z#!匥3rSULu{^ P)S#h*'àxd?@cg.|PlN^u qIS`K[J }ez_ |svfcRAzHESDXq$@0WV'3LWh偮hYn4A8>_'>֨JxUpW9Xt?c޲Hń.~، ?ՒBiڮ>$t% ε|)Ss>)^*9D1T=r_vp)^n=<85ݍd~,V^L10=lX% h<1qA\. +~ǿ# 385I,>U< (hx6G/29ˊF+?5I<q4a*g%cW :g ЀHZhWf$Opn%M`v㳺s4L;n Z4P骔jzo?a*@m'ǷUĚ J |@dN>Sg 3b0y'ô}~%ڇs(P{_ ?5£db\mxi+9 ~şZx*pb'2GN/H5^2I.r&q` Ѵ,0DgbAg0No9" >ӔSknѪN` )iFeGV՝Fz$^a߰2rvC<슓E/_vMĖtj\݅4 5P\OzX5(Mi팵lZ50jx]_oݞ;:(7uņFwQr}MdT*4YLV;np3@Rߎd[:|Q\Gt6TW2tn8' .Ȟtn78jЩ5/GF'WYatP xtZ=|ai, QDn.tV;R> 09nD=Յuct=:Low(?l׈Z *&idq rZ ^GwfW@{Ol'qk󾳨* omBw˥( ߱DFO5rpmp fbR+F.]ՀnBzfNl䙐I M)yp_Y|p,^i<.yfOxIrm?b6c.j뛍Nmk7ߚ@ˌYVr{cWjP v@IzcN+V݅E"JgwzRydT4[m8Δ=Рv>~`uy; Sl`h c"l7Rﰞ0]*Lf[{:}Vyt.$F}HqՎep/"aQ:(=^Cxc_#XvSP8>ޒvP|Sf(!@2E/'G.AXEs-խz ='I?LdBa~*k<sq ao  mx(~[Y dO&~snl)#{aǀwȾ<˒ eF Cr؉d^IW{"@m^m+Ff }@U+8t]7IB;۠s䁋w!Ga%0貀3xϫx&/u ,24DΆz+I.;'w/ by&hgahߝ% $a,8x'׷zO3Lv>#"FFSbww\Ru `/I`uiSDžaC͑q7 Qpyxܗܪ  ӟG BUWhs]-C9]N-фA0MY (Sb y*$5I u"7 b2*EmjaZфp*\6_3S3 ln|ζ]/]!@GMAɷ}AUF5p[YZuhW[QY9 ʼn9!g k΃}͚"l9de ɼDTbbg7?5_XIx WlȂbM>N!NOxjwkZZRQ"'%[F"N!N PeZ+ղ[xm7vVŕ l3 RKlT)dg>_zA/yեqrNR)߀闹oNoA4]k&0%b\Z!5& 8$cx,Tұ&ɀαy)ۇ;j:̫ FAuH7t5fxXk4I2z @5H+M$:TQkE,5: $6}%hL]lpnpD svm/=9)5`ZjNLGOq8JېU5H{&f-Lm>?I=8*5GP f#zM67Jj mAstț!3'QLOZOA@F=]vkꖊu$J)R-%$C;<]W@<*^}*5o&(2s ׊V¥P-tsVj: $|ĕ:BgOIR!ޠ;hmm8 ,чUyxx/R +fjHDP[R?GB${ƛ~JKp(5`4XƅM5]Iͬtƈ6[f-Q e<9uh͎:tA]As{)Y%.}dIVH'n2#h:zj; ԊG c0N #f ҅vy+UOOp] 8햼DoN |tK:zVrwJ7:~diyqfHF砨V퉛 uBMBLR1uaIE4ALã8{SY/ZƴQHwPLcgYƎ"uI )E|R;[\ym MQo(C+”|~X D{aJbIe yA.N2S~ݛei]ӻhJ e{N@ h.;$Z`vnQNH>"An.(bu!t، Gq4k,}ЋttYv}t6%GE2'ٻl9}ZWġK EE27,·zz2@!=OOrpQ{ղ t\pp(* ikU1?.b!2x]*Q2urh_}2 4ڧ?`xL!HoB50 c;AMOs@2OџDg#iX{xװ);vc4MӜA=W?ϷBqVniJi [@1VGo$7]n{tKYn[(C@KwT,mω8PoN, [l\w#`Ro:̖(kRIGMX_tH.)]SZmogպ)KTv?%G[#} <}*1%Jk>U&#ꬄ%|ܙŶ2LmJ~<;O#!BbT n U:q[C=Q4ru-35:p|Tyni+b!vRrѵ,}¼Z3O5h0ai!75Ym8((FwrO 8 Nޖ ]KB[N@l2͔/Ė9ۃ\uk$g֣2cJ-a‘F#і(䎝ԏnd0Xs܍gгx.#*&Hĩ@WYBdYFLW(2.4^RR~j yzDjA;̂T9U\iq Mk&9s~CF*alh0AܖGrvOd0[ѢY:nw5hvf-»i]H\յ} Q{T:R=%s8-?tgNo~48͜Ee+KH5Lh-U-۴}CߦoOeV4Gƫ|;~)vthiЄqz",ߺy' }Gm}1 *W/ϕfatԤ:\'ͻ=cƫR3rsQ] ?a% ߻ _[pgοgG **n4K &5=GU֣ƙkjΎ GEI}`FBxڑ46< 1sV;/;M2If7Aթ={=Ur]+ 3c#{27?8,CFUOl:x8p`|-amn}3zK4#qm5x?Q4!J$;L =JeQ^'w dN K kqVj|G;8>wj>n@)ut햊~v)FkaȀj j iJ9D|v b6w57ycZS6Jj\[J\ l6ߟv\){ ‚{6w>GsD5u6 >͘x535[y8zdEW##G *v.e%,QG~9s$ xt>[>XӘvA'bNѢ!do#1߷K*;ڭѠ4+=Q DQ!Lר87~/o-O;$P s4/($=>W:P$_4l?ODhM'te u8@71phPONNJ'M}JR Fmƀs7)[:iM!p'~3JƓ]I)#TÈȸ`D_6 dEtм2\|IK?'4Drө8~ oF-h|X^Y?&Y  =5@$ǠYz~jik9׾I[y:,1G9Ӄ9_>hm,+l8uXJ,7lgby+y?omX bII(?!u2  %eFvc;rlXl<7hn:̳5,ttA1%Qĺ G M\Lh+Z 5a)ÁٮnXַ8Q2Zןሶu ˰*9 Vq/8wj< ?@yQM( ? ?`~'ݥwRņI(I JY LӂH1VJq5Ɗw'=z'ِ:I&t/o%M`IUueeu6b{t{{.Q2x80"jgrQfS:7`k]N89o-__єLϕ݆%\ln0&ьSyy?O{yEQIJtWg\tWJ"I*~ItTi>gwgA\r(lEZ\"}?n[Gwg돝6WIl͚Q ez(P.F.%.Q\dܸxYc;/ߺ_^3@jt{rOC.bX2$R""y r<8-p:9ax‰޼ R//J V[t]f#^RX%հUͩe& ;somڭlnpK {;kM/ LHl>ŭw URyI,dYEbJ<>^/}1p oY ^>ԦF>[hݩ? ꬷQN7KsfwK8t~?=Ѥ005QL8"f%WJV7^v.fQK=Q.nYt0Ӑ\ uBf$P1$srJvAxnA : xJͣ6gd&qyn#]{Sr*u;buYHFbS!%Q SfE&[9"Ǒ rEImKpaW( `>Rgqc}}{Օ_~V[z4Z{<7>:dn s*PԑPnyt?]>}Kծ^hbۢpt)ioZR cɠ"mƢO8l dΧH__SzƎVćpI]F`n.FŦ\ [$֮Αixctv8t9QԇxR8qI"m1ۄg#M&<#iR4ur$MԘz KPB[Zfn߉%˷tcM"maYC}W\zV[/~( d!4MumX2~DS6Lͧ6W'Eo{!\r{gaIyN %a_P҃vDW`#W`_~F5@{O=1S|dn>6߷᩸_DiWØ8J\$8>3kyiStN*1Ǎ¤ǧ 3]ŘrfƮ ȣC i5x;}A2 >r6Iur>&z܎8= ){Npe_7R _-H/@$͒ ezܱ,מB (q(VC|.J_CI,Z!^MdjR"/M{r;r MDɘ]MhJa/getk9{y;RƵGz5<6JXLgǥAݳO%T{>dN9Se>!6;9hÀp4ݴXݣxQ7I#"BytvD靷z0CQ-4U3YDǓY%Krp!JQ4uU_@>E/YI|P^'2L˪{4Šj>>5u<=`ƞڿ s d"u>҇0ph{u$ ٨<*S!u &v2|+*n &Gv/9hI OVNAIm>ӍY3>M.NKX=P띁Lك c_(&Zʱ0O;%[Oa=G2Vv\ d 3TId|ϧ { #&5Ր;PJ'ԢIActYh`~X#α@?w^G?n.w9x3A'Z->?OA!!YQ?t03?=(lX5LOil LOW>?!ӓ|DM'Y݂VT;sQF?9C 5#^,jn(L17Q7'|-a@>EhPwR D8u?}8h~v*I,hvQFzWkt{b eĔQmGb+*]@^no? }m /76Kݼ &b)vۡ{@AVmxͿs|٨ԦW"8__ δރuD7^gCx_Mbt36Qo~26̳PxX6vUK]N<Ļqh'͎4C *­ ,5[ApbKšSxkk}fg;'wuQ^)3t! FI_r;ɈuNY1tU0ǾJ=+޼&Y9~^%+>47V]C5ֆ|E†PhfHo*e~3ae1L1W'?D+.uKyxY0!wGcOњ+^ 9TJ^om=ٹh_8?⏍;dK+QM:%RZodlW7"W1'*KZ=owm3ф8$`.+Vyπ7UWר}w+ʻή^h+"M>ÈȕU7H/ >V+)]efT\8u6hUנMz]BVT|'9Q4y:Bb ][z|˜qQJ3C6K~p Yn k,?p (u$̝ƕX\6#N&e5:tۘF?Wrg+WW/_+ȧ~:_`F0x@S> ;G\<m+Y\:TZm<ǰcYj!Y)ܦVz^'RSǠAb]BnכkwՂ!psp.NVdTcUQ̣Fy;/IR-{nfC"9: O3-%؁ZęC3._cbkHN-*#oM}[Ue n$H[ }֬ER(MA5jd_›/<و=!U zY{E[jȈTΫ="˦ ĺԈGƏH}nwʤ bCw ^0֙zIVݷW[2#xR99WۥC\!.9JK@.YZ~A\CI>iN'p#PNOd0S"s}:],"Ыzp^FAr$fE`Q99btԃ/B]!/!II]$ٝ%6ѹӗNvF#Fփ kz"5nf@ X2,$HŖ jY/@U2\dCU\s;DP6&v%P>bWGTʖM0x&) { o?rL\ȃKQy#Ъj&g4^h(B!~&TBSƢW] M Bphv0RGCؿn,9ot3S|d ⩝TƀXZQ%|׮CP9\jDuDdOEc1(#o:TnvY lh4A'wS%COZRK:~6ogg뿬76w_Iilnm4/׉;%X2l, /r)mѣԿ798oirzt>=9n+Oށ<ت7DRZl%XQ‡&{._qk4^05k{+խP uGHlz]{ ss?Ap@O5?ҏtOP Bhw7kRS(06*`1w^&źx"?ӽ3 qeFy ` ^⚮^L'Ů~A[+Wg>/j % Wˁqџ/~0^T?poPG8[L<0Qg) G/?fʋL^*+nZ`5p=6kkNLi;R+ 蛌d%3toEѺ߬Q7W n>b+#E 8W^r|+~y~!G3gF~_bj}!kz`kk!!C ˧^xLG6*~ьN2e_g֩iLͩd*/x`[mAq욿=9$[l$'m4Hc&`K}YLT!&?udA%# eW$r1^H2 m),AcI/uESxWZTkkֲf0G*d#ҷZʋq!P u(F~!OHVZ} /Vp#;c?IDEMef\7(jDuBy`"`'c@݈܃\;=0Rn˯cL/FvM`AgjK$}j^fn|jOiwtD;HG@S; _y'c Z%h+n'ͷi]6ވ=;'Ɍ] UYX=MǗKZp62gCT ̓` g@33 Dl"kZzu\B/lq'Pǟo2B5ڻ?~8VϘQৰl>DP c^1'u1nnwtq3]3xȺo'BB T`*u/[P-h|>yҝ>٘Լ2?!G~(<=AHB *üt fA\AyQu*bBh%R㰩Wol j qse^DYn*Ok4)%/b10U~HfJT7׽x^oF 6ju8]u$-M62@M}!SmQI \D7/cc~^[!bBt38 yt/0hލdM?򗺌GZP oQkqʲEy̺E[7JlSVѶ2qyPl~is獗8n4빓&,"d/]5Hq2uwCW_hBڱ+-_48ϚH>.{$f6by^1i(L|^љ[k3TVd*t͚a~9f&w&ՆiDw?$;쮏Kw?R7'ޠQn-w=L$*]U_ ̜4^G(}[oGw$3ˎ.~">PH{p4=DU2HTnLv#/vW5>@:Kw7_`$\ۤ}uћ7,9QhPULVVU0Y-#F~^{/ar_R[jt667Go(:\:w(Ik& 5Q$=iT㲻tt-ۓ]/Aۺ8ϴ/Eݲ\:s&,:%ɳCm^YaI57ǦhqX̙n8zu6T_m{qc^kFp6u㙢$V`c|уdzNsmYv?OOgݠ^Ks^!gW#:Z|{oAKSmNyCMl8/:V-H %\&О1J)2UhPԦ{WdVȇ 8N_Ua; coU;<>xdV q\^vUSesD]7=w/ekhncQ=G$,Pc}׼v?B;o<%RL2!wWP+Ûjk݌ n-lC+Rt0"g*XԁW-:3I}FSu;p?jY{pP x^GjۧzLVi \׮($LmUِ}s]Rg.mkj MMyma; `4w&{yMv)9A 'dWΓ =\ 7xv+*Wnl_NeJޣ=~/wmyp^ j6bR=|2} EKȘR=m+Ԗ^\:j-GxϼnR]'t0 e*vE#5p8،=}u4ɼmC2o?cH#!?Ը9u M ^|ƘWz [.{EFg*!1NW`rq$|x)sQׂ>1z@ ݭtj'[~K>0+&!:q1+`JRصpe 3l8;L|urmm7?5O;'m|ʴ_ߋ$6f)|FISDg[lyt)یE G 0ײ>S\ E7tj¾Kof \% ~y3:H~v_ &I*[[pcwSamFwæ`5.sǓdS[ zT`gA#u̐["[0ýTe8 ,Ҙ{;ۛ4 jRH}7aekp)LZ4}㑽Y62݃ɝ%>gm9Sф{:ߥr<8:x 5tH\ V[>xBd|ks@]1b)BVEll8cܛxq+ : ~й\i+O%ϑ$U?$c L(3׷:RKDex1DN5%%Fd6©ф¼$_Op1ϱG/Er,Aw+Oao4\j&Rp UItAMwo78? :Z^L:?k;=c1_)cbXaB|Ko4 ME~2Y!>-1wHBGCĎCyYOu <&LUFV"\5#22:VFџP;}Lfvs?П0͸&6E@xN0 `#tn~Yq҄ΚcLʡ*A823ټ oU# NW_d&>%K. \2vbٗ)wQ XmK^X=G0; 7gRSzdԆԱ;fV'[2sؒKtS-T@_cO -A~__}ۍ:65UqXAT G\ç)OT,YմfgA.]&ϼ蹆I*i!d<0,l?+/n&pԿ,y㎦OV_)S1D pjj+lZq[xynmn+N{|!˥x7׹ԦW>@횿\]iKm.@48٦D;[ +"FX>B8k `wNaw B\͌UU|6XsRRvZdYUٞg& ̝׮%9C<4ﲯ8xbKcŬъAݕXgp6bI, kBM {xC+E٠7ES_Q7'(́zXAOuc3}i!!7TRg]G٤ 7q-OnM)TO5 =1 觔ѳ 0k(4u«M]譃 RZ)B:rK:ri<}#_kDPpn*\eWQO[W4W\peC4}.@rE8PёcUs L NE4OΏ}[q'92 ƊUKj\^A^ gdj^  RpΛTSyXAβȔU_'92Mctl%G`S FlpuuXznݏ9OgRwUfeK3$[4ܝL%1*VH.y<~u@,h&m@`aaaT3A&bp5l絸\-(\2a1ҳ&%TA?^V񶻺D[P>WKW!V[VC5DgCE*f5puQʱG`7]8oLWg'kW3Gcw _Tfm6rB7&Ngȷ m{p'ػ(t g=Je{wu]_v767[8{s{su%Lg?Ĺ 5ܷՄdX׏cuP5AVAl/ ?$.CBkHFuf\pN F% (;+A9 P™? df<46vլf^g d{0 A'50&VM;QXj2Dž˗ۑ"7V5TpC+r*rRXhߎ [#C|va'Nq8qMnJTr9@rNJ̃N|79 u@2.$p#218P$V}fbDYǬ#!B@t_Žfe1\H᳠[k!nʇ|>&˚CZ/uJ{DYLm`iHGjdhKwN..՝R:*U[PZx}l@-fۀV*UFS$qV9ZCVi7jB_\y;(e|D6X+F<2ij3({'9Y蘠S_Gs2*J,~+v1M`jdOmrTf;Wj^O)5̀urMXE6۞esk}y3p3Sh6yXiZ8}uǘ iZ@҉cyʜ.XӓŇsT0?dvV&`=L;5$, uh`>:@83 "NHwّζjyk+I[cV蠫 W{PgNkh!(w9Tl֥]8D?&O762tSͭNOBtD\mvom>PC#ɳiه+z~6\7wg>ѪjVXȞ@Ȭb9L|(eD+aܠ͚ vܻow O~>/pfJ8Z@kCiѰXpzJkN>.sP($FYWkW>tn⹺aЭaFѾi%hH?Ka!@Y- r{Cۺ:άsP3(Mxx0;ŕgo834ˏ Fa갹&.OT=S E>3j`_x҂8!`ЪYU#!$>i,)AZ52.6TlPn湇gPgC]7*ͷ8.#፼So3zK7@K)(H(Q,FA kC;BR]Ec+lRMoDS@ !΀Cդh˭ ѼzAmھ~`d ufyR%!#g.G9Dqo5qufdooc S3лhx#6 w cOB*p*Z.{4UwZO4k&3{liӑ~-|ToT|3Rm|q#ߗT=S.[nN>78/Iѱ~-  {@1M=lZa~c![?86m)Z=s;D~"8:sn#?.E °}IW{rimXx CGkl9NGh]7:O#N Z7]\aP$21+CG7Xf7ZS#mzUt.(-۳SIgyOaZ?)؜}2M M]UcID0'JsJ_q?^GD_o-x?@\[W'x:go8qf'#u{.(Cax^:k8-uS`/i}?>8@*Cs(&p_mue$~4B!~wd?5<I}xL" F븲R訸q=qe>\.v6#g 7PӃi ghm}[Gp&xJ6SCw$ok| :Niy'uBƎТ֍ZU|2y^c(]v&m[J|^RVnbS+uOvu4bOjL~RW$_ ~aN1 ߴ۹\n0ش6WM%ZA+XOp\$ϝI=w8DD$9z/OJӫ8ݻ6z8pSmyU]a4:1|Zc0z:̂|ǿd?LFИ٭ZX@T%w:SށnEm;Pu[>nM)0"6EYf Z'QNh<<cJ{`7x1Rm|+؛ׯ^mvO`%&gܫ8o)fR`:tdʗMcT&ӵ|6DAx*`@ [m~č}}r'R5b[ʓjRn9b:fOE\v;KoyژBy>75K󝥞ﹽ-2?@"G rB?My)#C쨇r54=4JEQ;$E<޹lkwX.}+XLqbXǶimqvxpSjV>|z^EamY Nj!xq~~x!y7zǬ-w8+݋$)wvWuav~$dOUK֞C5CXY6C$綌gwO[Νq̽b~k{qmW9.67sVffC랧VSzWQ9ܶPS0Iά[xn;c{^e PN=jZvere O;ބ{CI`gt wvW)$_;w67Ycx]:7|&Wj%p?l;dvȝqjDbnS315%w-&8]qrAg҉5iItVT?nܰ%`foX&24uV&MwHJ_7t W[pso_ KTLz7`+HV/+݁ 98 6z S +M fcÚQ1Hr~upn^U#FUS6^~ T%usGEVvn%uJ%_=Sa1踓 UZk!wM8_z. iZ1@ikVVxV;O/QH|ӡg'w+P ʻb=Eʁ`2 ɚMR6O~@vT[!A~YVNj\:B{14:OoOJw3: bJnP#@:w59H*qCe9tyA kgC~^_k  N(A"[&^UN2<(1qպcOktj[0@Zlo+ޜڠ@10ǀ&b2tX; Xr>JuhLV?z@"z c08#KFCZ`냮`KfH L̀J $ L_'w =(V54,+^34+T'b }~QS:3 ڦ64vRT,Lv׫uBִHvL y @:IDbʦTi/A͢;9%.ډZsc'D]/"Qer&ao#"lj~z3†-[аSީB)PP׮ZR&4v]:淬3Mpo~wSjZ"[δMQDR`Z!W׀89V"w. x\t{ROÐ3l{P32%I23rPAhuݵA601_ %bhB9XJC/iUtEqkKJJ/$E=E 1Xa`3ֲCyit2Q!`<^J ՎB0z/(`)єBoi8}#dPPF՟ȗਭ#]a.Á:8-ER$ jQVV'hՆ-z0uV$;#3g)'#.oБ)CYLSVt"#[ ](*JHV3( <~ZN[Zyס5ذ}(os;i܄&OcJ$ m"[)z UtfRIVlE9fi,.Һ8IL=([aX˲Ш@|Vmwpte)L-Z5w٤_F'8m/GxƅΪ WD9 t@SC:۴ej:ZxL,) ܂e Θe1 TWLXkQBENJuAz+TAoJ(8ZT9YX)Ig @23F_Wb[ 9>E`X_60L1|e E='cS\B{E,<)HVj@"C5Or$_ԙ4'n%>>9?"SHT-%s ЃbzJvfC׋~AC'x^tRr 6jd,BEı{6;4,nlv[3nϫԓFsW'?g񭫺&y+5q?Yfx7d UFSIֶ\s_z P0Cg@QtyPPPf!}^;S/<ҳ׬9uߺ+RbkROw3Olym8 JW\fm?kջ^|S_.>n^-*U!3esuwQڙtĢx0>B`m0hT-d vx^,L`D9®"8˃ӣ=M9(Ck4&.]Ϡ/=Lbm+ eq a{j4B;'gcSCEso L*4KC 7@.^'\Ub]0L֍垵6nk Zϑfq:E3L*ЁxGzUۥls<l 4|S4{6 y4,~r# +sU ®^x:q3g^ԓ. vKTZ 8ҨX)F]v<%Vu~5Q@| ug;,@N<-{俄mvn98&آ󺃈8hRrsc3u gg 9-aRS| XpC݊rwl p >MsWGv]{f(g˱V6dz燂z{1 .?0A K?b0Pp$4!?:aA^,^ p3!Â=}s{Lw>[~?N&TPgby#bbDF _\;=p7+!+IcBk~byU`U U>UGӓ'R.p\8gjuo? oAӿ PWB~?O9ݮf1\6C;LY囔\K7/0PϐN)؍Ƙ_WWקWGϔUG?<(#2 "5؂lL?п =%tWbr&]}~\ yͫ[^\ir_Ь*1(@g'.@C\PbF鳅'< ޳oo3B 7 y2G`'ca?_mBP؏ax?fXte3V̪qhEG1Ql*?Qof;jGyL21^Unu,ϩ$ l=aC $- ÒJȠBhW.a)EgƅJCEd9#yiap82O<®/lBIU0_ ^.jGs%:| 䈥oQD-@Y=d]I%fr+r?-k^ )֩J\k>'&PF"00-Zgj6pxd^7 ]Lf AiUi s:b JaڃS4Eyy\YZcgLq`[) xwQ5ڦ[KeUm ^[qG|v]imlUW*^V^gOzJ6t;[Շr8G"#)FgEfyةǫKտxdfp(opuN>t *>s}̫cyDh|W* 9v6y_XB%+pY^D-U2R'N-X&ZUC8p}^Mi!RT-;3ۅAV*/6߸ zoMf!DV^>ePdaM;w'm^^_l޽l.Oͬ.[/I\ ԝ<ߘ }ho*Z2r#dq;Lx4xQѾ^r$$J)WxR@ O b(A䄔+C˸Y7'-z!TT`F!a)6?P12u.szLs' $4ROG1{fX΅n`uy5hSv2}+u-@UͲ=Յ62gJe214\u.xJ:%;-kֆAd<*)ܽ =u"رK'u\j^mw;;j(AvR1@#RqtEȠZ@nE~l\+uɆyd*[6=$Hs"!@QC>hW+bo_3^*sFc$du~vbxB{3baa!"{9ꀏ C,b/)`:qNIMiR!鰐6un _h"XQTLzꣁ[$ާy6E[!,r~qt{#Id% |E _O4dTɟ_\C:+\P_6q=J,oO(䁭^4Yi KF6P_$^jQU.zժ3E:"[xYW>9Wt0۷Rs0 ByW(|6Wi 1eVizbԏ&,.i F4puF|en9 P&#SVt=7eyIN݃=C'@T*)Ԥ e 8ExM]EI vɼϒr]}+su3MzX$ҏ6j,G" %neTY`~@efTBs.EYL+ G:FQF]udt56h6([YJPDT3+p 3n!߆/K5m'fD8XzC3G燮}v}ÒpIRej!zK#qxn Ӕ(64 ?Z\1Q uJ0 |Li^7jat[Կ?FqZaU5q{ZVh~ rW/6z 7Ҙ>PFhk rG>I*qG*ٛ#_*$Z-z'eT8!iXNq"0u5.Li\Nlo&򂙑Ya5M spd6Pk DFDV}QnǂyO RPYcnN.RP!:M$OqyLJ8=ƌzgyvMg#èg҉)F\/:NJB٤cTuZ[Ėe#\լDF1.ɭ[Ӗ{OERH`]n!@z2wHvy :rض,U "s:M;l>}U AVƸKmXAܼaCXg2|Ťzx웦#=~8|x/K %AjVC)fHF#}Ҥ)q/?d-$tM |;^DH`쵘'?hKK%m2U=y?qWbb`#'5Й+3\჈iu^ 0C wJ+c&t,i.bLe`NoUao ,Xۮ.'M=oۇ/Cۍ{"0_AB6S@-:^+Y`fM=i^ؑT CMVD(ZmVVfVNv[nt6epr*`Һ1C<^oZl9X@-|X@ 30"P"0aCņ 86tl؀eC͆ X_WMbSF@A""xa0f~TX K4,LI7J?+g;ɒcޠ]I,=wI$G@-zH8IgA#̪C6݄멚PGZ4%0I9`BC)1=( [;?-:к'9!$"~)7 9]B@DEDo'FddH#gwFh5` eu y l&fNX*:^}Vsws 0m3==< ^C/G sptv}t Fz<BoU'arje?#%ڬTp"oAlW+R'3#u,!~ 2f*~Yޥyй!8\bu<O^`.F 4 ^cb9m#Il"y†hFZ_P1^уֵXj\e qB(.W#Uxxvj]9Y_$PY~t>.b3i} SwE;4uZ3Z5aD]bkJ!Na>!+9r)=4s4^_>U]lAf+{gLNj:a0NAqY@DOHJdsxpZ-)FX j/E x9-j T|S4Ξ~A9h_k{Tmߨe]wYpB+;D30$ fN|EcPF;R4=_5ɱϯ]aӏU_mǑTVc”T Rf=0MPK˜@ه۰RGBd@2>R,p+1r RP\|Sj\\Wgxh8K1-s04ypYnI4QD @%Y=Vµ5Ә Y98w?y&M]NEA|T"EvB2@4P*k%M>ɖ>{A -0W4'O"xp*Qw `fh`n\|dɮTLjEHU<~X ,기vdZݽ?Ei/X ~ R7zr mq̈́~n~xE y7#Yz{Z-3}?4oNNэXdE$ +@:5~߂IwPN@ ͼi\/93s}QJ"SZ=" $1L)vۡī@My<&2&Nl|_+mvrX Ϯd!f@:Ye҂¸|g<S1IK:*%K%wBrŎIk}Ս8LRmj<8)<)VqV[E6fM~^}UqVZASQ3`- m 99 oY+$rXsf"w֔= |[5Fcd0(0. VOEM 'teqrGq\AN%7N*|ckэh͍Mά1x\@7u2) tFÒ*U'pSn2!'R/\ OcH$QxH 1s;CҞg44) yZ[0݂lz>0:P}Fډ9)rZ Q%($CgNKf^ّ ?fr:rxC3u3 pNAQX#pX4r x[OG 0XA W|uИy8YN5ϩ1?"jFp&jP;į!8B>:B65z#P*{z*f'r0|8Y!UFm8#oq_ΛC{];HEAhQAW_In抐C=f=gW+{7<Bd`x \Mfeaٗ`Jt-#j}s8D69ѵ6E 3 E3nU(Qa2qkzxὸ̜)R QˇR< x-9Dզٕ6u0TRTII\жsy^k77DRGdK_ԢBSl#;ڤSssW%n$g%JM~+⊋WEaEM/$xeTPsr\]0V|< P$Wϧcp \]a x{{ʸbוs]^}ړNF~L(9ȕ;Q?9F9hJK/i2T"Zܨc\ksZr;;Ə߅]8Hp j?VbՅ%ķ5w 30 ZV4PEl>=D[: Y^}% vUu258$iͳ>CA3t+`b͔S:58S>^wj)JU(dgqK|CCX6J$Crtk(=\ɮƣ2 hY LP'0PsmMR"bN((klgRpB3VdLgS*S0)lg$ 0DHqh+i/nB_9[ɑp~.Vex'E.sO!e~IX31ZU "XԱ)nt MQw0B:;Cvl7rDK5zb^<fF۹ɨ:oaF#?(z*x Ȝ%_fC T~\T yvbi#͌%~`lnwpN G8ӸXa?xv9V ,\ (uh=G5S~"f9\%' YāF᭤f_t mg dFf29QzPW]tP׬ J LQNԽ=>6X,lvUC3(L{q~ji4U!_0Ë 4Fg/ǝetod}Ќ`E'łD]0TuKcN]fB;ˁ?.Nl6{VQvjIs_>Vh\4հG :ouS\IzWrs^]MظpH=,/Eŗ$I Ƈ/J٨RkX} Eǫ'+{Ο,"WV\UW^nMctCcYj8! '?ǤҐSݻ =>:Nr<\+h#@5̜Sk̭gV`cR ͧ66 Dn$iv1MwWtֱeOMGe?^ſ9)G| L_aъxlܤԍO+|5@w [^|PGz,P@1QVFFGؽ:8<SZwPI#4M+"7áV;9ukGsT%󾹁o-E?QAnsüTJQ-Q$Qg`)<$ŮK(j *ڣvv1V3HW-<9aeqn'/D?j-ISy'tA64z:xbQbyTL m`x!CTiyt6T}9o8J78JTr61:w Łޔ#7ÎC轇b@h 3p9DԞA> Kٕ’?YsB\\]azf7mb. PѸv5({&G:xzpj!ݸbFh`ɬ ap6QQjpヰSx8gwsuncz?M;џrdT"66x7Xd0 h=Q=E|yХzLK/Az0f12]̬y1dS{:ԱZ|AS_7au$+fAw,MD ]E֊+nB#5 1Ӎ%u~8>>w8x|wVR݆Y6^=m %V'm+YoS6@lBUCs~]E I}eԣZhMps?%Nq@O@`R*nZ(#  >y u'_s9+3,N'0h;oIߗ]!2plH0 NVBgjg{]ېxQJSϛR'`ÜZ.lt Q}Cѽú;}+iqU qʇ{"}‘tqрNSՅQ[zSw,JcL1_`T,g-{mFa}}fN$gq,XӗI[𷓴(ܺξ5 M8z4L ٵ/Yy6qh]ܷ^!:'~.5_Rx1،&F蚭Hf X,+"9'GTGhרz#Y S,o6h5(pgw&ȿxr#"OpvnNL z g@؂=T{ †zjL 1j{xZ~2 ZdiDh[xcxC;>1*QE&p>nb\uUjE25N=UO7;< ,N ZZ_՚gYə3R U&j?H2]S5jZ1;!RfTlT/7=slY8F-_/N~hoq(|Sq%d,(aR\uOR L\rSaw/c8nj][ornLkxP$`(~俍hFg' M8:E:2DR&Ќ0/'WHj"Pol+L_EMqlܹȳa&_H gco" x_CkMڿ{"9$ĎxPL(R}yB 5&2N/k\Ch#S} ݩO n7M `oO&^ ܳ~opv~q;7U/NFӠ7 yK)F\]H(I^E8M$>4!vpMDGdW@9L1Z;Ni-r I H* MA3U }|TpW<58\!7&$a1P1բ1ߪ׮_@ʮ|N o@{Pckq!]4CukWE |$ɉܖ7&zmTVMC&Zɤ%N 7n[{rS{b,BCVėXۯk&7?jI̞eV넬Zܕlg}]WJ l|]w!]FaȶlDxxu*|Q9ԶItS*V;y%>vf.7M !'nL]4w,^(Jr%76ȓSzOU_]/?6k;R] ˀniS*x2EV97*`AAɇ frNhAEE_Oڐ=l9O$s0Lht"M.P'n+ľ>XW"`SI)uCT{ j]'W^gZVH!UQ&|2QmlnԤ|]LQ V1J잪;k$g"&U)f%p\~%,[ȉd 5H*¦8<.\MP>ՌwPTql|Ǥ67P>0 "ev~}bTG% T1%F!(/Vb+*E( n4$W2kӶi7%\/\K5J=3~~O ) S2e)tE@MK|}ᙓ Sgr:;,ȗvHۓZgm'doBG_[YSbڻ]o?Lj%L@t 2U͊jz6(e2_%LEbeܪ݋F]ecY“)դP}b_T̃a]>{o@p[B"{c\[ZeUybI ̅WflfjގqxJU ȫ;3OBh8e@З;:!b4~v::Cմ97ŰLr i~$]z7NR5~G1[@aX!8s!]Gz 7M5M pu'e3'_} r.naP"V2uaj4߆;kV!jr&[m~B}z,emoʊp,s>{3%lӏz %eLrTuӍIW}@ҏ켾 t |BXIr1 !)1 ht~VD>>kJ6-89]zŎ/3Bj/cD,_= Vv(.du(w B{dըaȴGXD(<$/)ȃ3(܌IlSv=kQbĬ#+ųmH ]IE2͢ߍ7}03&?03Nmyނn5naEE wvW,Q6(W[mtޖJ:`jOP^"F $&O٬nAPbq|nٮVid,[Jk2[d6`+y^>fo 'LC~q#Ue ˇZgG= U3 /`yAjez? sܕqTRE)힞TJ|w!>Ȣ/EQ<d&j޷NN-t_erN(L* SF"ΥRKB!®;կ;00 2dä@^ )yַ˙wpT-NO>\sĄbjBҴY]vu}Q]:^-$`WA>bNh2?R2`t2ND5-)J 阓v,7$h ӡ?nj:Q FAh(DK!G+W^%[hr߅r?Z+AʃOo̠Br3$،V)Ptc>ʋ":%H0^ N"]/Y9^e2RDNV]؂^ ˫'ڴxPb/10 8Xv`OZNFt0yΞ".|bk6TG}6 E!_1J&IG?Y1.$Xե#MmB;#iN\ދgbZ8Wv`t fQB!0O1is^r6yf v5(6*v8z ]CGZr I4{@& ܴ^ *Ay+5!I6+En+|AS:kMiB=:(:z":oX7zJGުg\`dQʕ%>-Ĺw B& q {)&ylMҷ{]}[FCX0plxzWho(E/ApjQb6[Q,/R9{+˜3}yɎ]*Xp' nAt]o]t~xNzQ~*U3鮛W6[5!AdҮY6G>^!ZoZ0~TGʻ lPUWRsEk&Kzht(~_\dT%NOg#GQ8F)R$p1xvm3NP~ yuKHS2L 'U,=qun &#Z+,1IbFH488ix)]Dחݍ͍!zn'SS (XY$\ uvؤ XZP̓1A_2"B%D'y Nr2Myh>xjw]-B~pK揓q!ôUY+yviq&Nsq*Bmi<}<1@u { ?!wnl[lo7/6ANrp%ON͠"t1D?|T{ A c;=Zyr|T0TD&mD,"EpI6𼆔ꊢg\\o/)~Ӊ؍U* ݰ@"_}/|)ŧIO1-I{dkp?ڴ#HR`ݟM,Ð4$ѡ~̈ūP7r;"wHe2\('B  sH ^kVHn+)[{?։MB`F=|[q;\>%=.!k"eU?+9Ex b)ḑ|t8o?Rg>&MpRrY|:mxЊ}yh: {YIPOndy?)e#02;T:HqK7ݑ N,_(ovE6R4q-FCDK> c= <ӄYNKi!4!+:T~k+8+.(H'*{_ݎm>R (~eߨ$0 0uF>I,+ܒ<6*6l6Q)Xp{ 17(1A~tu` f7ӌWUܩ"-:=8E =3yDi]3y/4v ߉^К )f85ni~@;wW~UnO}1 {UꇏW6P` aUuC%s#/+ U\M4~3!qTZU=/ue}⨘BO|)XfKF"/_ATvpyzev"â!Ob d:1 HaK׽%Ϙ1!4mmE!{ 6/&S3ABh3䤰J>Q5|cߌ']$(\W9 #h#t<9HqFEA W&HAF"b&:9Y| Pȑi\%)0(vy9%U#5KtnOjt eeҢsYJ%bI6̀%粩+x:Gya2E=V&dLEuʠ 1Δ FсjP-PB #Pї"UKsu J-THF>?%J^b$ a'B i_"T jk |f/zb/>rӈc) d3-1H }྅xaʤƆrXZ; "(s?g#\j^X:6gu;}RbЩgpyƾ\q:_BݠOLΕX ][c ad7`{Z)%>뀦݅Iढw;Px5N5q\ '4TCO۷^{{EU!/PjT<@]nث/2a3?esPO1BB]\,SZ[t Ks^C}$VA 5CVC*&K$ZwǵOOr(C~N}.a֫&L՟[sƃ|Az"0X+/(:O!7v.am&^[ RҫlrM|jD0L 2pDނxܷcFw?Pz =Pr୦F@q.PS=m66l:/Huh:.qCNŢsߥ-V:7.yWR*ƺȜ֒wlB%1w< h Y9*BS nB9ǜ5mgš:Nd @.4DA)Xoу\y36)0Pg2jH*Հ&O00&:*mB] ۤn&_8X\id 77ժ3mvʆS9(X@y/"1%+b5Y+"S>ֿLA`%L"rxZpʈȽ/"6C6$ju:X.)q]\pƤ\(. 3~hS.ddm _vZ7Jjnh(?kx!yhƈ[o&?2[?+`Fp//V;qؐ+ \1֧rQ5$z{Lï5ץ{w4qDt[Db+yC2/r8"IA|5Q ~kФ6p f{ =w$$"#Ќ{(`2=p{zrum/]8G|ye%,%9'GExa EK+:^)}Y!8e=^?RMa[۩1{e̟H[ 8NZ Z0ҡ`q}lͧc 2-Ej}5ɍ1+\RРP1д/R1X=4HC,' )sg@~_炮pbkvkI:b!e Sj Qx.jBb)k.in"EeO R.`FKfHnZxXÐSy]ɄNzgǐ*ʏAfpabg*Fj4).?$(-)K>}l5aDi/ِ3?'O70.XvrֹdKYs\4e?Z)t-, 5AZU(D*<8L{YȶU30+:$񁨳ݵ, !CxD\:{&DGTAU49,&U &>AJH&-q_7A1+1^N_=Τ[5<\a؊f 52Ps2f^K&N}l/O$jI 39=<-O5ܬOC.e;5:*42Li%; ,rG`HYu}g? B>m0eO7etKw&oS0bƬT̺}Yp@C%5VQm3յkBހLh`+H ZpdQny-TXJ?EX(aFs/Vg+_~;΍PVrц؋j&E:ZNplX +u/Yș_4hGG Q/h#vq}gSHwSf42{{p] 8A O&ti:X<%K>!D)9K5N9QcYYu 2xb3:b=iӘA~2{ÇÊ"-b9R-U{_5E RƹE35r8:9X,Nj~Im;zw,e•`woaTWWP dP.V=0q`K~lSԬnAi̎ަX3;vD%ked d$:&4y*lѕv |>!L19H qTMCPVdn<85lB-v2yZiKΛ Eb&jlY|-Qn !ņ*b?تYh `Gׄ=m"<԰tj˓3ޖe Rh@wGddf;51FI$]:!ܻ@EWΧw1U?ƹ=6H 2:h 30fH,~BcZg@ ׃(us']gVR0[ٳ?_dg{BG'R[<2?k"]ƩvO? e;eDy$ e6u!j[s㐬RVbyrҡl2DOD(|u՚p0B^5s}^# 2 XS9Sܬ]sl 0!HQ -r]z9.6'hFW mmln{03fQ4'H f; ܮꢁp.{V9YaA3 ]1ȼ b 8*EU,>'2+CDw>w oL8)'p)'9/xFxǷF3ppiZ]Q4`ANc{H" ⴏNI<?P˘W!L)*¡ I;H\-W#izyxkI-wm6 ꦌS㵏V 0oR r]8H\X`k q-!%܆ Bf{]k'776l螫 #Pngo6ߺ9:<ھQ߿"uAanTMRrVO$B*qe{yO݆٨DH9&w}hZj -`ޣB xPPGᚃ U#aBw78 Es(32@ŅB=ƞ(ʕ+OȚs{%3G:`55]r3,Ż$dj[)gg9`Kz%!ϦOB,DoInQ#ttxl`'ILJ$6v:T ICBR:Tp79*&i=YI\kZr 3.e5Z1ʳgB#:YȬ-Ҝ·)ɑx@|fJ}x} T 2Կ7GC{דְ޵v~vc0|%G$l~{@$NJ>8Ԝ\)#u`Q}NfuZBypNM% UeeFO-Cb=!0+o?>*"L-@ch ˞{p9،;~NoٹV3t@?=P {*惺"MP7s{Ϭfe9U͌fbQ+SXH~jf`tM}帠d=['&HSfE]8\z,"s kuJ<͇I q^ , G3L*`$]WuV8$ttE M):&C "_ӌBNX7qjaRҠ?[G-w0B HGI2٨vP͜'f rCu.Fmaej\aPra,i3`*F"XR=tjb-"њ_t|bITq6~F#|!?R26 (=%>F;Kw^~C$B|4atG[L aqY*_xb[saKVrҬzяH_>R!,a:k L"n3ᵵ)r}Ğ{>Ea!4~8^i$H !b[nUKO$3R؂ (H#HʂH ԦjՄ>A{!Őh=.}]ƺr HCt0 ExY+7Dt>nY#-jlIZ00( ZjjWxΒr]{?Bu*D0@\}7腈=30.y@F%4)Y 9#ZrjV١1;$|ܡyPxx p _N=ul5tپ r(ծH| )4~1HԑS۔>H')ͺ.:'-8Y)-̑q82jJ'tm:YgX'`}2f9b BnT8J$>(`UhJB=B;~Qf[*nFx ?*Z?n3–&8#赥NjGZx4AL F'j P|ێX6\'\\ (jD+Vj<:&^>y_SZӑS +Jx{ ?^U N:rX_JρMA iqj>jF`!'z!SX!su3Mzs%y#4Gwka,tB\d EP 6B#|-Ts]TSIw BjXg dIl~[l՟/5W8l͞ 6nn9Wۯ5"VKgAf+X*'K1gZN+l3`g#+"޷8etFӚ·y(=}A`$xc`e!7"QM1bh j$lttN 1Zz Hvۨ,QZSB8}քi4QuV2YW6vV6lh, jTZ^Նs3Y *yפzY1pKhWubVikZͱ"jtψ:Agk  Y |6Lox2m\LnW\GBZ@,c A!g`mbm%I>lq[>XTSfBvhL4Lև=X@}8[2gZ]y.sPPЉ"q&_ IZ}qJǫS۩PIPxx]@hA{{ؾqyV1& 452ea=ٺDqn?B%3DbP_^Sߎ/7Cyc*l$V$zI u)H/D{NI-qcjsӛ^] L=%/?sRjF`䆡lQfCou&;˧J1"EKʬR䶇2;-Eeeb$|"7ۯ(iH090)A&!xӖAv;E%Aۇ!j),1 5{߉09 2ud4yPQgb־1z{-R

    JNej,ws- <@AX\vWeo!Zw"̺ zϋ0S rV;V]ޒnu>ZFA K(YdEsŀzG=wXu\fBU'|8,=jqmހhU*>g .;\Ep_BPZe>N?^p#-+-~EvFs]d`G8³$O0i5Ǟ8L#]D=dݫ|ڿ@7m=%0wOsvtF?LOSnu=#7~Nxvdž``Дi'J.-d T1šP 6󫒶+ sנ4VsVGzyI(zVu;DJBH{X;gIxLi 4 ǀ$`^з!D8o<<&7; /^-bj4mhMaAM6irEL*"_MÄϲ bI?ΰBy \Բ#_G=٪\Vqn a 9&R(KY[$| b/A_oudOc"C?sL5Y-z";ήnF] r΀QdWnaZËmF} d *!,$8*SPMԘ[2 3g l Z 7D:Rm /9=pr/D≌68 mFX0JXWSkp Eq6 5w!ȅ4, n/vZ)ޚJ j-50NlF6S(SZ0\x.mQ 2wm-&4tUdc0k=1m݋Kh `^AEP%")F}8?j~kdTmv`ȇNL($յQ:|x'-7%'zSQa;-lɎlL͚K>Z $Koo)lp AD5Wt+)G<+C$A^8$/~"Aa:~=TU bٮCeoJ. ['(iAY l o c]ώ;#PƔ1ķУܓapŝS4\LZi|u}Q#Ftm+%eBJOxWc ~YG-κ5类iOIN*:,}@UІx]A|;2a l**ē^%oQ<^a0v<̤$n5 <+ISf@8(٠0 D:HeX>$)00^EQa祍FUXV1=>Q:7>p)hAeM'`FpL&1T4 ʑ%#6-쯒ʇp`窱ը{xQU?h# V8Zk~)1W2%*>@p_vrbҤF2)(7C)փO Ɓx x:պw][JD6儛U `2ep =(yrvuzzC|OE{)ksɳif.TW}-+t0cbAR=A%vp a{\ɹ7oѵM=59^B_} 8H܄["K,j7ixk jGܷޫʤF>gO5 fkW.L`(04ɒ`Oʿ."hXCE%,kb]4{(oh|*1ϑ()j.A90q:j;UJ0YDh~d%8V%>T*4_$5Jf|:MäVG>#()=6L9 4%m) ~ULȸN6J2=<'b;C>BNŜ>ѷBXd  A]^SI.*@F&5wce9r=kziW hx, KcK5{,)J::xyr=Sca2P'cft Fn&O멦x"No~x$ӱع< \i~tay^Piw,#TaJ1).SU躝[~O~A>d"׺өjaV\5 !w|;EB1ZOVqaC!.fD[up#&c!=fЧbF7[׏?}X{wKw+f2B$h}*j~07oOO9ɇӛ˫'GW-Ƈ8L*j3hm6~VgWQv{,VMؽGfyjDHk<41/gk`)_t1OĎ3xߗ@5E7nA{:Lb3%(vf`o󻙦E9yv0迁=ݿ̀.NZ=>pq T}ZOLsrFlK0Mi6OQiic0N6IpBhHhDs\2bhS)Et~]_6RO?)'UTHZ*4DR, z %aP4j)X=cduӁΜG8f(Up81I*(=+-qJZ՚(+6Z0\w:X\HT$)`j'=瘟 1B P.NMXdm^ J@Y%*9Yh&,v[̪r.MoQq(vic@qՔmsEu9Kka#*t/:ZJt3nmh UgρXGQ9ڗ : LX ҷ"5)lN}r#=n(9U"Ï߽y><Npmma[vKzi_v Tb1<̙" Av>4/_`u1 92$[,Lv>K2icP`DZ] qīAN+@%[%!X45^Ǻ2>oZNM-%դTbEŽLP!֏UO!G<2%jT|&V%wrLCu(}^HWb"+1Z;;1:bn5E݃;DӾ R}22b9}_lbS!r{p*S}N-po`-z*ms]]-i;PR6MX щ:pu@C/O^ mSno _CutXb;Lz6"ǣK  MX?-ABD=.r3_ld[})cs#,OQE4m.Cs'QW1lN̓wp9FƎs=ka-܄ h=8pa#F-G1;6`̠ ܍&~Kw+cTѡ74UZ5!E%C.wSpҬ7]MD7Jy֌I:(4r^EW猒O ;:7;BwCwÂ[n]],:ˢ+-?0´'3wtSÉQD'g5g"\x*v_ĭW_ߨ# k* RIF SnlV|% kfRn]f.'OrhEFk*#yZIHҞ]4 V7kk)VD )c,Yu(fVa\N vR\e⩞su&@XHp%tЇQ/r؝׵|Q 7|քŮhNuu+HKMn-Z} =%?4+t6wGw\<,8O)x/fR:@9ҩ1 )Jw:AsRe3焤0H/!5#' !U&8p0[1cHrDy%'zO_((u"+BO~pa&#H$KzY19:q8>K)ut#!s,9m]]_ԫ3TH 3ܡ~4Hj:/yet ԅ@M&I2> <*n,?&"s'&94OeNT߽5LA>S1)c[gb#X% g꒻ b}MN̼TGΗ,٢^:Ywu\)r"EbXĒ*M;q|cE1uRkUIUL<`%LCzϧcBkJZ5s`>GMq$Wt8VCjZ~4In S䩨"Q (zjSgtbj9DwtkV:0Ycs iáWf5MZa*O۠rS"g~:]_UQ b15H6zv"t>_xoG߿_mBfdz|;LdS2E+߷/0fG^7~8xȃ/t_frȚKʇR)2.7^s-7">̫&YFk=AR2&NZ\mW*.{Io:Àa<}Ct{7IYޡ|A?M4Ĺl$){VҀx1f~*̠+祈4>9Iz$wIԴWk\JjUQ_Yi]װ8jGq,_>'<]>*G5tZALvz\Q &XPQ+2zXZ[% #Ef֒5(=v2)\HϱX z9ɋBbDKPԯzג15MW_ )XڊF6#I8bEx#g^߉ Ӹ=V@3} XT.;Qdg3Z*y͕U$I ?ܷlTpQc[q*\)GۺDI(ܵW1U}rz$Sn ߸}BuU >2 /@~pŝ Yρla,#/+PjȌ.ZЖxFx45%Ο;DׅD. PV AV:؞n{V`igf\+ⲽǔ*3!Wk)7,`J8!Y3ʆLkaf4H;wb9\zᦋ9H`UVpmk ~?`~Ә x!a׌.ijTM҇;lZufN< T'$dhǫJBPaMi/qCWw%ޓP# >xݓ&qjƈ{ z͎'MJ! ]0ܖ9oP*E]"{xKʩl?)*1o6{ahb$T 9'шC.Pjq졆SlQi7uނQ]6T`Pe4&Λa_r3aN240<ڔZ}5O~ )wkW9XIu Sh>:2 ku&)o M2/LBPn}9^iL7~^[37H]ڝhp1"8T)8Jrobbr _&ƺ3-\s~:ch~]`:Rreo;XXR+Zmv=X/9W]gx43}l1V.ߙZ4Bп:j F9#u7HR9]s ;1b>^YKC8 F<)IcJ(``ܶb Wp뼻JxJ7df (B!jQ 3ۧ>sB` *}+;vk^Wbn xzL bAC| lu'ߍ7?qo:l@pcYT.`q T1׫I____DķӰzttW3EN3,}pk ?^- .bk[W gplIv+{JjE;d@/:8:Šl)80k^u&6շɟ(ef@"S B^vHl֟x)Ns99mf;;>l'JS7u]"/@{?4o>ѵMAz|']Ɯ!jslWl}U+LXɱAtF檦i\&p^L^&t4>Zbs MdE@~6J! 1y=I897b֑ȃ g䋅|VxRV"]憾 顂ӬZJ/!/ՙj4'EgHrc5 d0 %)x5*BH1`]qL:VhnlN U7S*k,_h}aP2 x%ܵӇP0T;Z]#VYS4lt0I WAml ZUݺo)\aXVjewDZ^H}X\[~V׺@YO8zt':#5V`쏗6 cs7ؚV(` :ȏUO$ce[ű/liu}wImc-)pyV|b1۠W[>yb%`:"7Kڤr/kK-Q޼0 o6~^a`:,;g8W|!}쐿vȟޕD~`^:^T:?TD$_wR0!O?o޿oR'Y\#mYFj+ZWz!L,˯>} p~9/|XЈEZ&7(Zfԍf#mRrp]7_U5q?mj-"{.OT@gٱW4QmdllFBnLX&|I{h?[ zA)3몸r׉sEi5k?< zߐ="&ZӼ~Jzj[ԬֿnE$Iҕ%"xyE ¤+j6[Q⾀dz6'-zL .h VC7l&.s6ljo}wio]`9f I7R{&{E ZL=N厺r2Hk ČσDhʻ<{DL3+~N9Hei~o9s~̛ _~<{f:zЮ R8H]%N&񰋎uݭqro~U| e4|WW2u>0nϗr%|iWm/g,RV ّjƍ/dZ_dU1䌵/%Ot^ z ̢4hl%ϛ4RNO7 1we:X4>NY|OsC;&"PCY^Q[x`]wPךбgNq+F-!DGn xʩUrqUkus:iWc GaWW+4ƃ;@-O]ǘ&er3Z/aʝH"uQ,a!N,}%T%  $N"Nׂbco.8w?xlYup|#m(hfkMTa4t'oWATex?z{uN@EtTBx W߭&鸱Y=F<.8bx#w ՈlX]+GkȦytx,rrwxx)?b8z);C?L;ʲ~cI.g<ܖOsɩzN_Xnu!& :',gQgy$յ'0.(ovIS4y2$tfDIۤ y-!=OֽRpMMWi%  H wDo;8o2E*^_nw DQ"-gS٣ՍhPwe|1  ŋ2nExKoZ^rM1id/6;g8ڈP&;lrfGtrk\`y:fTGCz?ՙ@ L9@z|}V `쥥`rF'!cRz|wq2xo 7D^Ae Kb=鯴ZhH uI46r+I~ԇ,נ4}z󺵿KTUdHMvh@ a]4XAm*j%wS"RxΞܕ~k%seB~ewUxN98mFw4QƼs`3'>݉IY`x< |,W|͚b+>8\ +ŸK_C.uz! "3C5] ,!WH8e~:`A@S(r&ͳǧJRA~]gyYsHoNJ,=FUv!-JX )㴸zYE6 zIMAoB^𛙏8xJu8]hq٫.Iz'HSB$;=Wu3c3V`(Ѐ%X}&=/_E66{77{[.Dh4Z5%x d gXVX!ɎC/{Y/oסjcov7[#z6__zj]&36 iM1%"0,o/SWa EJPs< mH&Ux{+푿DQ>6gq3ͦ lַo äܡ-?߲z?>x700 n~G^~?ީ_[|rksۍo_/7GeeьČ?o{x~pitA]_y`}^7Gg+R&H/\gYp9̷QL2FڅYh%=`&By9~"(:W$ j@GoW6D̵tt4omDFa*dM>8@ɜlSfU!b7wW/FH^2'/v7q=ӿb kbI Ѕ?/K%ܐJƏqYD/HF!+'~c wE1^e6LS"3:4}WA3k%08+`Z7w-U/bޟ%3] VH]DzWx6uOEE//rLaSC_kz_P^Ň "'RFYEM}F tYԱ8ܥ`h)_ӊ2e&/_hXׅ+j3[4E߈ Mk'8_cuY#-t*xHpAǿE3jG>$am tNS2ޢXX~dz;!b'8w(|Qy t/S?R@_-0=Ct`!g9(ī遵]@*\|\v/Nn׌zkZN5zysI=P~< Y/ɀ´gP1ۖV~x{o:X Vdv{0$0~6QTn;_)Ox͛f}ny5{G.fׯy,%p-@}5"=+(_Νb:lyqՈ's+lU)[KAeEK5+ߦ(a0œt3ɦn}cߥ֩9-.K.BW}DwJMtiw/b0o6qzsoe#~#$pw 2δXvf Yۂ~,uX5>jNBE5B .{;NƳ58XBwW˰/33zGuˏKi 3sH31U-'SM`3>چuyF}^~-?Z?[~h(bc:~wl- \} FK[Q;-F;hwj5@'vWXftuf+蔁U|0Ino+QqR횂QdZiÝ^\Tʁn蜑d?|՛ow4z L/$mJXrz]7|5hP] K_Wﱂtq^`Zg-l<"=w7Ʒ6)m+~:y<`w.Gզ܉T'AzusTZ{hM0NA:VZp,k6fSGz9Y0ܬ6:H_Ԇbἠ];߮}_倶 Frtx%ijPJOsηk^v@x!=>~_n Lةd87ƳIIfΖx"2u@a@+w&63i1<x|oz~~ dM("4^|vxBK$0b.Gv|0j"c'X7 %eT+sm3L!q>xEYa5J aʞUiQ"X9Rup\T*^3ŸH`` _DfkA;JyY>Qo(XZH꩎pIbmx5Ka !KQ57E:=>O;r \F nv?:c,R\ACkxL%yl;SsrLWZk9c+S;W(to5:]`r#Șy2V}UݼCܚz 'CWyp;ʜ[y.+{o;onjVW1cOr}SJ%C$TK9&öFjnɰhobs8Kh !u[ѳnS7syZQU iuĀK&O:W])YJ'[MxZQrAS* D8{doU$Lf \ ='}nYB-"Up;5l2>b?f{TXVABC{_c0͓q,S_N"q`3'JeNy}|%V"}r>T87*We4JfJu9e[BBI_hl#A(Vs6^F8(w 9{H!K+z`t kutK|*fsNJraQL}2㑣=U?d2v`N& 91 :#UVE,F^P':;w)bR?m!q0a?+=G߬bH_f7G*)z^K6PbGR*P8á6fxNJÀO2.LG(V Y }sSH/> *d^_L]V$3ʰ; |D裆<>݅b4Jlz1 rnڄ H(c0Jʚ SېMsE AYhZ)54[2jE@^wFMDJhT E -R2B(P-_6( l  }S,Pg!EvóVp$GMod9)ێVԢfǂzL$6(ŗ l$(NNʦù|FlQc 7lҖ%)ґGȍVV[$~LN:h(Zl_-[~Ms#ܧъB^sA1T"-L&b7m0uYx  b)ryAbiGe42+樒bl- UDMn])3-Miͺ.KOH<Q[\U#J.ŨV.dkm]vƟiE6aVPVP@o6Zp6a{? {5!5eHZ0(Ws~!?Ef[]ѲUc)yμhrW1`م nՠ^d~ۣ_R,wծ*@r"Mx޿@| Uj\`|Lnќ“Yݵ7b@3c!nĤ^r=5r.^'&I<-He鞬h \:X%[cMotަM7=/>/\M;)Pl\M4(;6mߴrz'~{9;׵R:VGѨ8YGg(óNT/Òڄ7{20!"NVw nonh ,ff.? 1 Rl}rnn9?y~ZNJL^UPRbȵR?IIZ\ܪ`w{Rԕ[;Dbl>E!J$Ne]0!_b0؆ Ѝ0KA+i+*.3ڶx( kgXîDW!0&E7-d<0Da7ꄻ,*lm(zñAmPerbnҫ=w]oVvX<.rhWUݓsp'LPpk&G>7SW ,y_E5G.D[$C ܵ:m@fBH.FCr 5=88>p*ncI]LJRVQ}P!:WK7^N3a?*H$q rᴆ&DThr:B& KGjfYQѢ="m,!&PB.Zq[h%E}@ up$TD :ƁPS4o.WX-*WN,CnI0YWjNw6HhX;0Z5a$w:'F}/{U6Nd+j>SC\EE5M lU,k;7S("{ t.Dr# m"`SWM1n_Iʚ,hй߹W2]v])EH B!:X'D%IcHF<&:ëJ%pitO2 I3JŒ~?|Ou2g{ZL\dL\H5+N-niDDڬV+bc-jY~۠10o~ .qȡ:M^S6\Aa9:`#TLAqlȻt 9f3efybmu&l〨Հ urGr͛7La:މB3@{O׾5e=cl0!J>P_ vՙQgH>պZhhcXm!@_Z;~n ]S+ sO "Lm25@ -}sA}njNvF :#ΈtF': A'/ }|+DK@]4*/e6jـ}k6 -l8?xQφ$`KĻ%% ,!BiQNE9hPoX\D F>h{}knxmn:٫Zf./%+o&,AW{p^T^(o8l#g/? ^=j6ˊY+Nsvl,8CU=Mxjŕs?NӬ M =ݗ=h4 sqrUm:K&dB=rO]gGopw E(56پ^ 9 *^|MqZOH0"/8px#Ux>F16n\-qc}Vh, h(Bv֏F nmӠvIB>bǂ h<o&~#%' wU@Zk"޹xyf #}"(קmOtHC=i,C0.sykģ>O̯03ooj  \G֯m[fX`mK8Hn݂oz/:g+HRpn ٚ7Hz$k&- d3L W`JZ &-<xtpHN擫f݋ &VG*HV^HVKxoDȯgx9 uq&N7 W΍r7a[9!gCEzA$KՖpI]NîSxiN-9gHznֲZ"ZKPjy9IyLJ2/f%WݳVV`>/׾ˆ:.0^a?4_hePoTtM:5f A~Jb;øMf)ݺ9Ќo3a0vR{^hF5GM9Ib̏.j`fQպ tP*O!ӻ$9h Vp#m{C@jըˆ'BH4Joݸ B iNMӁke+i_6MaŚ{M:pM ~%uNo7Mp=M:pM ~%u0xJXעe^/>bPy!ԡfu:4I-rV. wޥW[B-&QW[QWZJaU5 psĨ7 V؉^Wqo D`JZ6]nٚ6 k͖5[ fMk&OmAԾ%O[$-oMyȑ}RPz)GVrqY+4 }xD&rwԒW>b+FMVq:ro&_Gkd(gd}3 Z6d+({WIrWDRV 'Y6Ia Ĕ};ʳ?s3<'_a"dK@? o|jB,-W}yJ&VW̎Ց t<$qC@c<ז1^5<jU@~g ozdMzL@+}:5 S &_e WMhh$^AH?~I4< BC7.cy-w!H*N3u9^pk|گF56+C4?$>8^|X>F+*|NQB^BDh7qdVGWh )P7F!A >0HmCu'8RXU-&o8Fdh~McsVK+IŜ>ӂЯift0w՗@>ߋ3"ua]Ϩ*5K}5a2"lhі想 q+44Gk H)F(n ̡E~_},'HNWn|K-,bbsD+Rb(Ј] +pYޗ&LL fw/L![&dcx}xh^h7ޭ5 dQQ+.}W o}`ao]٧!9\ܣrZEWjͭvJ}|;Aͯt?4ߚ@=!-Һ]h=RafAᐵ0}3u[T3"*96zhXV)%~ Y;FBƴz8lkPWSX3ԷRZ.ɸc1e ҞϷ>loԷR2i\[5ީ̦́B$n ?z1!䑸|:M.`3ף7߼yӢbe Ld-4){pZ R=? p@DR)$E#HZc8>Sf4'jhqE~6eeCócsN풆k%}$44sWw\/M:ӏFa"ׯo:ڿלxn~~2Oa3bԟ7.$kcX'nT\DӿGÈ͛owxbD= $v7i9P˹&?"@b/MܓWoCz_ABbρRqp!P^KV.s3BTAP[;$s"/~.F5F[;tϲl4nxʔ@<6 Mṫ/u&ѕ ,DPe |"קze 8kM+B^9 U$)wc "/~.F4ᆒ=x|Ss` {_!>dIQVծpmMeqS={~?-B-5:avdzۇh-*wSHyݗ 8%p_JZrw4rk:rw-f%gq[)jȬ9t %qP-ͣ"4dB㔀j m!#1)"9DB B8r/}SI^@,GE!lUfPy6քLL9ED K?Y>j1kAwͦY^0:Sxܾ툨7muڶ-ޒx8LfeHzlE_ӱ |2Dģ}VK>nI{@Wkڏ?;=lI^jG՚Z>j8ji)jMEKڛX-4Z։C>l&M51k0]Utv4Xhk_-V6FUIyԈؐв) CtBs3Y)`<ܾHnj%NxlLF!z4 |Ȑy6 ݺE=?$Et|VY#9ʦ< c]B4^ )@C|u|vzm<[8OGyqI8I\SMI'GKNE{қNPwur-?OH W"e_Dۂ}^HnzKhXcI(z3`4!knW*N8./kaX<O{+>{36,gІh}PJY^M%}oaQ/<Ǭ>ŷON+9gF*GD^pnQ7_|D)xIܾٚX@ 6B~ViCy.mݞO?CգQYB0o4N7X(dͧ"A21# g&+Ԅ F1 Yy4n o&i"7kl/!g`:-yéY06HO* QN)l$`j(Hg oP8B&Aw8L:F ?ɔݗHc0y"P ݗ<>,.ozԄ o&,tӛ|<"\}3PX0mhyKӮ}[0 )\4jx+P~ d b$Ԕ; 7WX}z6+wÆ[FJ0?4 C A&04AMh|HGA4@<#?'®5 +0@_jzTZr4 kn'՘fȄڂk?}oHW3.Аpږv`5-ߘM:B̈́E E( ( Lt)' ,}qؐǍޙ:|{U&eqz ԕ};pV[o[`cbr%$+YW0f\Za/fZE+1;仢g'qHH5pC1 FGu FGY!82::^`B q<~OW6LE+z6$w)VC d x ɮnuln '尷փab5HozG 1EV5ohF>&p3:jM 4YT׃bh^ Eգp ɺ f3[ְǯmr~7ӗ?޶;k&ԧyqLK+fLN!2'`ldOV [@xam 0d<`w(" o5ı~x[j Zdh״7+&@kr 5 IF:e ^t1g^NҢ6̦<|F7(%2ɹ50&)<Рx|lS0ZV8$"/`K_~]gLE[= w ƺВjE@t^볍m43T ntZgl8CāɔBtcPl OØAZijXjt%V U"azu:`-P~97(Xϣ] `Ƈ"}8)94#:JX `(: N^T$9y_}Nlti둃`(jD\64^qdWV8=\m@c]!5ڇek @6FC#6=]U&1 l'ҨƕͭSꑶF78yp#*l/Q7чVbi]g9 .hj|ki,RLiT$/+HLMPe;®4 6ʬV45=Zo,U 'Z=ƹNKʉJυ4 +3; څ~؅y[+jfUפ[m[Jc' 'xtMPnԪMg 9[2&r(on:w=g J+R̍ƨc[L+ 3x^?xؒ£]\iwĿ`m1H]g 5{'F/^]7δ<R iV ]Lx 'On0ހFsCPu28uaVpq_EX#LQ3ʓlQ-и|y+KHt{.EuvwoaݡDZ"]# m=.+\ SZ[ZHrL(~amm5 x7+(/;$tcpH[DjkG`E)yʂnMf9?:~s-XuXݿJAnUX(ݽbz<tL6s&u'Jw(v9Eٳ L\܃ z,M\-Wt۴4#HEQ:HB4f9YhPxqCECG T5qkɧe2O`{C!TK9n,ŘC$cld g&ř ^fBf frf"hd&ȚAd,5: y޻YƏ/8'd@4c*@dt> &IQ7.PˆCeCDzY6+Z l Wrxrq\uEV=^'7a&\gGSV`7KNfJ v \yxL"Zfg^%7pVDUI ak9p` +.2d I^@Wh}pDY}$}#+"k'?(5τ|N@Tg`N`ئ 8xZTfw98>]Wr;DA7u4;EVEضc$Iv+"p|MBsX'^0rbήĜMHpf'Jrv 'q# O>R}%>q,_?V?NY\IOo,|KaA=hs#J?-wV|9{5re-"Ԁ./p1,@pxZ'adƿcyf㑜X@|!5h2hg᢮\C#0؍k5p \Pɴ=; =Apom8I)[dlBwJhуI=<.F,Z8xQ6|{P8(rXEw}^-)?^Z]$F{a("s8IEZWkUB:04LQUB*hd<¬>G={stG6QzU d/E/Hn?z u^h9Ī=' ='yr dM~1b1tz t& P' 8qƍY'Jn'"%xwhtqLdXlgFݣ+=mI,ry[Mחo,[б#{v:i\k9;=M:>}.3l7œMCpfJp~KS}C8ǑySM&ejߒ<'g}>Cy3|CZ3"z>#hl}>#HT};Nӯo-8AQky;vN=o[u}gfMM PfcJs$sNXn, uⰍ^Yg9eQZ'(kENO9u!gtd2D1:L  1 T0׍g2 =D-Y_fo @lzK6A8-p+Ȱ@>\opO> {2Bڸ0kI}ՖD<`8K ;rg)8h!`Oid&'=xtvaU]%@Үh kY.^#~E^#SWcw»;G"c&B\5_$B7tS$QHĥQS_idU4(fE4β?CYz4ʢ|wl4$۝fap50[b|AcJv.RE,ϓbM3{CZtM2)2%XSKקK6t/ VB DYQ?5/Tceկ !acvdA@Πw& _/"E6x!N`z.z\0˴96a.Xq@|Ԗh%)Cj5m %9R=HmV$X]پӗ痗o.x^"jZi.gڛ1QJ"(ۃB:}+u@GYF1/Yk)vdž^"h[6+7n[ l***r<]V/&Fu;~m޶/lǗL4x߂Coo%Uu*펻iѝ|/ {6ZP:-$=Vvz)†8~K.KZA L(8*s??K猾;O-q ]qZ+^9(lI ^iDqtRE/:cfé \{<'hc/,̍>zKXB&TLlϖa)xo^foubF=r;u?!^!Ff{V FVÙjRԅ d=mS,*1H>@p/hTӷ7*M77tuurnuoޮcsKϙx^Gx@~_LRf07qZ&Ӏ9sϋxVsZn-yë!\4N5ȚK(v7_"2rCh圉oh/e ZyhMqC7.h8M 2B.6G>zneӌbʒtKIe I!8fN W&h:J 3DXd x2_w0 լI)zlqGV*,:<)D,(ѺKC׿ +xݭΧCz"-dc`a)1(x!c>i-0Cr 2<׬R /ԪA ӆA@1DBSz'z5:`UEՊ4Yt`+9!aЪGKK՛֣ jۣoJ/i)7v4R[c:9{<& w\~]d-!, ;Y¬DKC3z<;(b0dc:NeEr eT(5VQ41(Q1(̙cƒ4KFl֣}U֚7 />-Lo1`0Z*SBC|1Evı(w:/ 9';@dX{bxJ?ddeʃڀB5AօOHME2.қ)hwL~X6e]zt6Ju>O Orwyɶ5n\&zm=Ì!=ڃDx ]=A{|[pn_Y[~v/IF0v%˘rHŻUHԫrߴۃB9L1r;ދA4E0 [Q-P\~Ojɼ~c;ѲġM7U,šУ/EwEfJ9^YRJYTM; q:LUSYjY8:ٸ"'J;CSFN&Ll^CU$ӻ4Ϧ II+i*ȭTU='k.Hc^.L! TzЛXfb2u9>nh-A3#:q/VyQeχ\LC) |Xz!lP:L(y1/#%Xظ8>et|hp4`اkv[,ţYf"5 LI2?N̓ ]xؓZ]z[6W{g[7[F,)+%b_&d,L*?;ifNAdU:N4)ּ;Ť )YPeAhMJV%m;`QYJz<|OS`ZC{'o_B$F*0)yj_X\?O&҂n_A]N E[=B6E9+.1Cћu @kPg9\fGi/u[8.^"WYYME`ʭL%";":7/&]MuPhօ_@J٦Aie4MJTוKfۣ{LMʡ>JCpڴ O0[c?PܬyD&Pn`i!$Υmgh@n, qTsdC7_\F՝N>O%TVVlGQ!,`e8L?'i1uz0) bR}tS3*Wu ,FZ)DZ:!KNxVlh%9[aeU$[($tn&?!XfLVr6*ۘII<]T4pY8Rl6Po:(V0:P!\ful6y!Quqs+)ZKtcIjO:J~CLW28o$+6.m}M@&@<>9#S٠R8NߕJC"@H[չOJ p-.7sn>G ^lj+9GHc%мG`gOw-i36"=^7XP#+XiߠݔQ+ȶ8oiႼKhkDk`^c%Eh ~AIRf#;Z 5*{[щ?>ҙ@/H:h;%}wmfCI"a٫knle_.4Y0_1ZS|T- `a:u1 zEFVF|:MPC\ Fu *tBn5j;k:ۂByIQ¹Z*u( $HXjl6F -@dd!+\oF  ,|+2ٜb%ѫDP6ZPskx _?8&42$$е&@\P֧1Yl*t avE-tp\"sW"J%U)JQeGZyo6Y!JsP(ؘ! Ԝ?*>6Օ8a\gkv!6}2k% 4?ϼp) +pZaTΛ]08pL$$NO)11 7 lMw }NB^0e&ao{vkkNmpWkgZܝaWkcOscMn!-sǽH]%wDP0כjfo9m-羕ܷm8qߘsۮ]u׹w?5j=QF]!6NgۖV0^d* >}p>W;'&<8> ԮRA(M",M\$4֪tTL 9Ė&L&L#?ֳw' 1KWT܌dXUfo<].3&5>sOh[qXUÍlrpÔ;t-y)7I,'y)/ӤUs&u #q:짩ݞLa_JBUp9 Yd23n Vz :ёtк^(G$f:T?pCqO'"戉jV~+RÁꄑ%CtyNʬbfWs[/\&O>"Z zbEOj+Rt>=ԸiM*6 .LmD5t] &6Ćl9xװ1co{`Z=;G&׎IJnsAt %R|PX vTU|p;SE=gԓha^mU/RwyJv󸚯|Aꐦ`6M-ZO-Kk;W:"#}Sgd̝QgT3}F5uYP5vSnjGdl:#;|}u._c~#8ԼM fJ2&Hn7wS<; ڊb>B)J +X(K <_$*=wpd=l*rr'p'o:zg D;$GI}>GZy%Thw0s.N/,MMFq?z!|e(P5!/}AJaGU7;Շ̽O ŵAtV)xI:coQã3jh`ji]&Xekg|~kӀWt- ǔ˦ eUA8 `՛(msoˆ=oveU$yCLn܌Cupz4yzcTD?n#~BK32B#E_6@oˮ.3sG _OR 5,Q`#Z܊ WpHI/ H5$~.351$=m40;- Q%FTՒ7-$=T5 ސTIAtoo|,6 U.RFz<1)X #٥ EPX(#3چ$`ц F]z3TǤx+="!j}]=0"'TpdEmZ/[B JH+$GFU;hX9h͔ѫ&@3j34↿'F?rFg- l6 QmrBT!B]I22X܂zF)$N3,@5RJ8 zVds:RYV$cl|Vs05_~q1zϰ_z7vqvH/.6 hxɆ7$-1n|<C=b=2n跏+[Wy!A^ҵ^J!^hRU E¶*3 z01,jɽQ|ZpRS)*LPvVˣ/;}GާV\X UZ>AlhSL1oU$n"N WmUFLBlfc~ї٘ýs4ttQ}zw36۽#Ec,ikA(U#qm D할z_KV `U%]I풕7 pi1Ec?5s_sR,v#qeMן}S8}{ _MJhu`}lPUy@$(:12ۈB x͛ fPФ}-LbdKơl0()U0^$<9~8ߞ9z{tryth7fBXn{dG1[QU}7aWOBtu~S/}%wwl@?XGJ5ÄVqS8 ^ ް[-}1:瑹QHTcL$x. J8. Q6OXO!vXD^уQ>滀>UHok(q+G.ٴyqIrї> Ģ*- arV SZh.<ca ' G 6"p򛍃iuLCG$**MhJUTnf/xh@MC,|/F@P}߱;BAR-^˜LH!RY &/[-xeOZTzk}A'&  zվgrڜkMGzVYZyCR=T~3GFd.b#X)V}@ԅw q)>_P `c4P]|/hTic|5LQzR>PIOmD$f p@S*3$ t|v$*SpFj(f~$Y.b}& {Hm.uܠ]EL}/x7zs=B+g] e󲰭TfB\+a#v)\֮nVX.6֦.>|%-64+Y^ޒu`=x^pBp`u!_w3ijp'Z9'!M "{r`SL) vo!oPEztVua| b;Un.4;J0C4*=ǯu=fZܦl6|=8^ӛ[l OUow;I!doFMͨ_؟ko-Nj`*Y<ÃЁWk:K7^ -u I u5M*,0?1Fmc? ^,ت+}Z8%<" Zf6h6JMOgjg?v7PA!]׽Y'~xm**ߠ y]\`KPT:}IYI,l]d:o*֓@>OCmh8QVA-װ^2NMU#ߞ9c\>N䊍,.qe\;Pٮ{~>'AN>Sg`c4빭MS)=f 3N@ҀD 6Gnñ/<=ap~tr[sT9"'7RCFV2^Zwd\/Gb8iqG.F\arn CL&Lg:ɵk U*ܨdS&G\q;J/pQ0*@략BKWW4oઋC9Hjx?Nh>ǤąC<MC= lkCqMD5ctTL\Do!0bvpm#ByNf46BPgDEOx#6,Q;BvDkz԰CY`8"{=x摪kcV&'z=*XC鋲2$<U(QuD@)q"S S[A40yրm|y$K[#DUNFr )Sߋ ^tqJ "-)J)K+D>_H1yrpc<(ߩY]ѭ[Fl2srPqd@' ^Rol:ut Z]\ ]N} I8Sm$O˽ܺ~ fd6W|dqe 0b2"8F B{붲$L}KQϧt`%(i ]ޛAը!:dT5ShnߞO8a2(e  2 H]HCv*imcI>LYr z5V Axyiv?R8U)8]8l5@iP h;&}V☦Wa zMSO:Mhre4[FI1f @*߳nu~'M OU+<}Z@Ճ1Ѽ5gvOӗ\jIr 6sjs@D0I+#;GENOŌXɩ31Ss= \~(:h#/&U˒-?KD.N4#"݋ E°!f,Bg6%=(jaZkb]i6$J_'R1+*+m(J٫<>/B19&>]z߳kZ,ִ:jj}L{}lg`WW8-H!2.>2g 2%*VQ7^&$j1qNz}W1O93f՚V8DZ)C !~E1磴xW*wxE),i1aTAQ3o*^b .؈6LXRa,/K:%uo VJ~~v7XBAËZź" >Y@hհ<S`Zo{mp(d9-_M}?(wu/ ;!\}y%\x'&t waNi` SALu*Lb4rcp?8E8&w뢀lebb b {9bÌO-^w2b&qو&/ޢY)lf{khCmVo*;iKUJW:AHH |VnZDtC?7)iu$Nqe)^BLRx>`.G#=y_t |n Ps%r f=n;LDH{v9,Ft3 LL!x<ڐPWa̒H]#|κIչ7ԽěEmtsg<Hp4ʕ[ǨOc/΢a 9o,,#He<2Ye1OQK֙ˋ8q2a DWu9>$k ljs[$;MY[bXkmSަaV-Vi԰Jx,I ptAvs0BLBvSr″NFUz7n,@mN06S p6ɘ栙':&f&D%) 8ns@/MWr g|3RpdT"hhq;#ןԑXY=}ң-1xpA b <.̖"(ĖOasn I+aApJ>0 My>-d?U@vxg(eСrζE[]SBlzȪaP63ΗfYܮp`n7"ح'(c09 SDoBL; nZLn3:DsAl5#puOWqx=`ͫt9m*z,plu`_ Z[=%[jҙ*wt_X4 )}4A d^l*OEpib۔m p RW7.[P5تvcN wRqAx6hGcVZ%QCB++wCA+[ oѮan֠}%lxq5kk<7~eݬTBtC/\4-gu~pH%:= kV M'!p(9XI;q[ݒj+?B  b_nEo t_~.N 0L1V2n1$Yr~Aܳ'53V@'*Pcu:[Ae^^ B-`s;`taup 5i d.֚ cx>-QN$8d4,8907Xbh0Ղڨ IӨz Cş3BnU6tA忸<wM+sZUUH:ck30vIZx1 㴸ȳxA.3g;x-44y"]8xd!Z1HW F*ӆ ȻXņZmNX1F*u7FH.k%Ap+|2xw`EP*>_8O7.Gv;ђ# ݈]>{smmu??v%SU-Nv &1^YQ\*eFTL1.LiMR4KW$jY5^ +?S>î}EIb pR0+sfLTyV^̀(9XԂU)#G# ,SOÃ#xPRBA{m 5ޥҋ.MG e迢gl"9kue20!& B rI3a՝R&멮(ZE)#]:4!܃?õڨ43hges'şnMaJtd|Nsc-w2R-3nUi4^Q!O|ó|*sS:r4Ƹ3 ]r{ /(!ccHU˟ K\"au/J ,K"[ρ-qϰ'_ck/iR[zѷ`;)UqڔT.HGZʧXbӏ5}.Έ t\ &B%sOCr2q}ļä>}È#4ea9#fЕnafc#8.gV#MϪT0bIZ_(K*ߣY2#f9-G"ct@֣1Ft3۞bk9h*2tœp E\~(Ǥ 7Qv5%ʦ@iOX9؊[/:*o t 셚ATwp||ϑť؎Lm>F};%7l]lrWd$G.M>#hhނ\7oo?v^{7.sSb]2i.!rdVbKu} #mψhX–OE 2q-(nq hBmԑz.Gлwڜ훤WUzQye:?:~s5{N,㷜"XzP5?aC T`|m&:$:E9A't$r,e r@sܲXOieǔ_]PԺŧ*ZXY,v7VA-G&bLchB# m\p;( c"[ڣj~satytq<,jL{{ttz mzКzQ+Zu_*V;Pos&Ci3eNߕZ΋T {3VXCk~C~ro"@&AE2iq'($"/qЗhu U]^_~Sh(%fr< [A_#*ɦ{TC}CD<q@R mCR=phj9:4H$tӗݻ␇x?.^:X ].8TlB/AAp eWO[ԗgl D" 2>}~j;֢ՎH~)20Ka x+f7$BZa#TEi.- hdAΟjĥhFO#:7KdDHIw|B ]B> x  _ * }!LhAiĄtRA›hG\F hQ2m /6zE.>r@wГwοHG=U=ϧךE-}5'jVw8NA`&(4Hn " [ uMK߈#]Z0@Y`k0E8Pj!vmJ.: t`}ՑM|hLFA3\$vD̓" y8f h}nR,{~q"҅7W*0WX5v@b K/4~پ3tM:A:aNz0}kY*YYD4%t8θ7z9\%P'z&$S˓*ɵwGI\DxY/k>qh2BZD] Oh?S X\Y0؈cbma^ Z, ^ >9: ,fDX^KouZd&߷}vv*Cb`D&ju@/ Hyh{%-/Oߛ;'Թۋ-zO.\ѝaY}dFU:[ x:y0b*wY®o 5P6 d4S&/mh@f$`]4;ى#% h't3њퟟ|] 7`뻼|=EEؑ| 57BoCMyR=VS7Q%$ZW.-NC2ǹ ]FPB$ gt0dqy#`)ph'CuC"Q;E2dI`((oسE|EHn,ʍY6mN>kƂ$G'>连bQxSdFw&l덪/%^(>?=$ W\(ꢇ+ޕ#kGCL݈[Z =ZiaK)q7 wYsZQb>:C6_xl%wS*n,%`Њfx ɒK)+kQZ8_yɒi6MV^rp$`l: *'zz]qBL@G}0~ -1ꝃ۲9t^Fr h-}6o=˽e$_]s7XmF-W5ދڍ|P %ME&kEˈxZHlU.X9#XKtU(l܌* ?;L1ILF?UwY툻Da.TkxFwY:n7b3H‰ԧr\m:+Lʀ&+NXRrK!cظai~cC`Ս+Z܊"̲"-^-djcl(qy}*D0B԰h-akRav^ll7:UE}J^glA'(`ᵋa6{`S("F_O^C A^U6z`oɸ㓋7ozoP&>ևnc֧n΋?A[mTF -g EԿ翋6`]-n z`e;{& .B48'g:֏|)( 86x/edx| <qpdFb0ct8>-HfzwaܭXF==Ykx1qw=( HӾq",w jCr\b϶tlukd1j\/x/+0 3沄J+mToNg4)G-mEr~ͯ^DQo#Op?</=aC?j+xH.^b#/⃣g5_~6 $ӫ Ύիy(1<(u7kk|S)gMhyZ0 v v [G뇉[czPY ^ |}h)l g9edߞ9%!hYI0F$N]gh!?J˫S9ptPsLʒah4L)^0!$/3-Z쒏0Mb^뷡v`?b-QXݲ <=<ݕBAPN8MMgHLaݻ\x4Kl:'#={q^-92 IGjx ծ③b 紇aԝk#O=瀡yl˹,g87i<ΚAxGg=*Q}{t~/_>_s֋h󍭭MnmsYglwhxNF~4OԶ@ǐ~)m.Keo|_}>}~h1,N~lv^׉äwi-_["ٞAl[v^4wc e#ӽNg HbYEy`Zl̋|ίKK pMl/zcByy2mdCxl&vo=ds\s'˽Nx,Yq ?QHev}qF!wT|Zo:2) HgF:SF҂<::4_ kedʚ1[ê@hL3क़03TkɛNڨـdi&gZ]c+3H:6wv~z3YoN:K8m\ˤTQ@(;[f HԹ]1ZfݔfS 3^©}gyØ,ZޮDIzae;8Ntnysc7D+ybgcg /_bS^te =>:)peS|B-|Ј|5/_2%Qlz#&6Yr\>$.JGEj't uPZ$ x@#vB@Mۨ0a :;/Zcc8\q Kbl%H\&kPEQHJrW)Rågmz].`zZLb6R`lQg6M S_|enrwT}F(:.EDգ܊Gyzs[=.Sq| a,}_aӳl(RcčkKK4;OT1U x.V  !DZ8q) N>V֑u$1EVi S։AV x*Vhaa+&u #0LR8w{p$ `Bi`hZMh@"1:|t~~z+&ʞUیJ\\]~ EZ*lL3ΥU"-=NY;만`c;xoL-krhfg/zGboO')䦢̜fIl|.{SXCm)&׈O.-ofgrzXy/Ϲ}u7ɰuTu svu5iB\W|fv@)Ef3#yzw<46 ` $/$$@=Қ))-+ueN7 e^-KS*Y@ȂhEyƔUN$S0x".FXZJ|osiIbq%F[Ntr*YkE(Cgk0k/IW->H)Z ֝ -ns~h{}ah`uq}Px傎g^ NgS?`_8?8>,"FXҳ˯/WjC|Qeu hԀТr=b-cd=.l8] ^Eϱ /x`j,Ṉ^ܮ}!렯Ʌ,%1]?< !K=' "m?BN Wqaf։<ay¥?OdE-K쎓hGu]QY_^Y KZ`Kt>U7 u(g'dS5 qz;@/|_Ql(Ic(7?ʒ^Q(M+uu6{oU MF"l 훀BE+aDSG Vc? eIj-S4͕hu(Uۢ 4.48V ph=Z.'! LȱLsXuo } 0Y7֒ZĚ ?CMfY^!To]=3r"O(‚$* ?4+Hկ+&B-u;snr՜i7ODt Ry_Mph]|[ is ]GD١wM;(#$d)Niٷx <0XԾD4lx1@ak()2|[43ۯKKt>4~ .fu8Lmox#mo} Ķ^|)\=b3lbx$._)3EV 5cu= pKZiG϶mlͧE6hkO޻f.zoK0N:M|1__bPY7Iov!p=ч9 7~ RmGH |n ts %τֳ<¡KB$4aa nγɂl4/ &w4bycy@5ɒQ`5>1 `]X4Q&_\KzɌzɄ'5=?I*l$~dQh|,~ԩL|T1*ݓ"h6yLg9D^YOM[Pu r|~$)o3ӭP̯"Ox0:I[:WX:<֚OO=0yDI[2'i|&e>6!ytT/H\|A!V?rC [C'RYh Z 6g ToK#P_0x/M5YKal;6r{6\%qbLRzW͢U@*T;Jf.$buZHO@dhen…qj qU i6,EYɴ%1YiMPj6@*T!#MJ"5Zy,Cǜ\Ș/ߞĂ _ Oߧv2$%zsu$-] Ux x@fB )+vTJɔKElDDHkFCZMrZաSх fJH.lƒ_|iD߉ਾB( ИJBj;{*ꍳB Wi;"ggӇjBϣA3Vmbca눽U>MQccnB,ϊ3FvGZ^gE 1NNdFZ۝NދMADi{ 7+Qo4^В9 ;[ZfEI/#ng!mxpRhH:@7__T Qb dkgWbfr>W_3 _b3f:Zdc?A2^"lIw ymTgXS*tBV&RE-H7?DփVP bݥ"MG c]|vt~GϺ8Gv[ԩQw( 6KH=ƅDyОsթf@ώ޺_X.}/ L?YՐs&M8$8y ,:U,H}Ìc}{|p4?!,qy~tytp=Ť9>:d`ol|sfFeu48|}-2tw3:hz)E@?E"6@S(Ct =jZٞVU8˳k<: ?o(GgL?l>|sw  k67߲_MddzSޮ.J,oJ({EkhȞKzLeFv7bp!cD 2Ο'=5 uĺcw djmzmJÓ G?3G`.4R(rO vgo:m QvhTk9$F:⹷=̟"Ŏ/C}sqn ^Jq ^.thA`$c9K$W W_3%=88>{sp, &~t7.>9:t40gmݛRk@/^|0IgiPkbCӥK22DUSIE,+%ˑVU ?Ջb5#>KcȂ38L:asyai:[cDy7Gitx mݻsJnxONc&.m3i LJ; wtJ$k8;UZN} L 5E!g~Wʳh܎3gՋUKQ{N1o`~`nM\'TElL|sdBބ`L\ٷH]0z }-G|C䣑q -%sX\8^>3`o4e5g0Pƪo|, >G >dPnЖFp0dR畼w Fm@q|\_G>v6QF5P8ḯ[~yFA |u.T~ڇ6'bЃhH"ާp0y4s4 2$lo&r66$:膃qAh@Z qP +EtXPA<VӪśtkT>y$$0Yg0tS5t\k禽YZpH/[@bRWeKn} vKi4=|f8|mm(_9E3pYd|e0}7y[$4 "6?ȏp;p LLAuףetu#ud+eIpĶ!-(^\o|#Wbb6;BiF,FyڃH8",DP%h>9xe `") 3q \)@Y`p=ԝ EkhX_A#ZN`+DVU1rwbK˦k_ F05oC0=*-tW1Cpx8.EeV)]丶3Zȴv"[p>WO d<Ć`|aŀM;eȱ'6pr诂G/6 Fk߮Qt.$jJj3DGlJjٟtjO ('#RnR~ vb^5vU냰f\Iɖ<6d wr~~~} TN>u5'X{Y Pڨ!rVMYDm[0tO.L'g8-y_:yQDSTdNLj-,nP%'d^vW{_^{a_-@%+8wQ_,}:%ݝo$X8 Aӌ$:0g o8th-fCpRq"A|Μ@kF{'dXg7'.hʱy:;fla=kAZ87dB@Y Eݨ1&ʹ\5C7ys͆ %(Ύb@M!?V;HN 00D5C5rLs>9?x!kE^6YQ_>Ie9gWS `5Lh,3lĥ FH_Ǡnl]t>x VچZDW:e֦Ä-|yx}NnCTw>Y;jƼښ5{#Zf9Xy^kcsj^d 86^ ]M:tҋ!ωkCm aaSC>:U )n-¯(6G &CHo(e?~j]k}!WO }MBY"8À Ȇp_ZD~ @(S@T0庆 jD .T04ZEDkm*k<\2 $.m .8pWYͼ 9˳*-Ӈ\3o.:Ȝ3H/8NPoě# cNTPY#*Pa8P0&nL&O8+ \.̴L&ԌL>f`uH;4/>xG *\rm`qsVP$A4ԩ3˫l\^N#P 7t>Qԥ۩Ḷޕ-,-?R9F*)؄ 0nE4Ba2Wך+8Ua5ւpPc3mdO:U!8/@U!Y!灍%K<EZ4zk@8*RP]]k:*S>M)7O7؀ *>WY \ai*Syc+F6ڂkj+ AFgwh2 #vY]%Q bo >Ol*xI%5ؐp_xy2],Ǡf;1=c|ȮTHx)2Nȫt .TL瞉GZ)Q He҅9pNPkuwi<$& ں6^dZt BLCqVF@1NaܸU Iq/V s 7ɀ+Gϐqpk#,m| H}!G:҆0Gs0:C<[r`m,\c7xmbb0NOFely Ұ+zV$ :sUL]uK  .LX(M`]/q+ ں 7Σ(@Gio>n4ݍ LkDZ W7kgɦ<}Y,٬OξiRf irAͦ1bVtzxEMRXsE5-ڪ^[Rkfxm5Hu:F ^[52r-##Yj1iP?$BQӨ[Pyv-T_xZ_;v͔^dJmO)%<8~ӳbRn9LMS;$wjטR{{;~kοԔکR;L)S3vSj=οƔ/j~JElR-:"O}耚E%A' JO 5rfצZur5G# 2ddEl0Bsx>*}0;ťvǑaцuPD-"#͆Ȗ  H#ؒ׆d ;ˇGwڻmշ<2$uѽI]sIտ$vꚱlN]3vxQ׌fhߊVk w+u5Rٻ0{#Yz=z>^Ri㥫8IF ̠Gz6Lpqgø*S|T/0a1kwk!*q:ƌ/yzX0/vg CG=vg/W]1q)3'yqf]1 bf|i(\kŦJYc+vTZJYc+qUZc+*x=evX` t55r9W#k?=:ʄԔu7֕u^"$l,kX!`fo;2R:,@ej1-G p9. FBjl2U?p+߈;㽨'Yuy̶ѦL]ʷyCX(sd1w}фA"sF˫vk?h!ր`5ΫR5j:>;.~U,UBuQO0 Džz:׊ t{6(_:@j{GdA0GzoQbV!W%meULqfZ+Um9HpChu0!tlR`k+dM[ é@XXtDK/M9c4<~/V].΄}yM<֤f8]eZx]5`Ws4m ?i |R,ӛ2)d[;̬W^)k2Ԭ!j($6c329Bh@*(;-*aY̊ ́K~U{r :("^9 hWnɘ%'5جJS¥ƶ5}Ԏhn C:P E{Vȅ EA2ڐr [Z„pe4O[ !'eBqDPe~%n,}\o)1&K1X}g W]jX~]K,;pH۬A> ^E)zeWE6NJ8:hg 1jzT=/0ԻײE%iEKtOloTiGh\l)gt:CV4gZזi:&MO%xTG_5yzSW nS<ځmWM nS͎tQWi-|xhQϧz o]{0E={ɜ -6m)dk@wfW le:s$,o% 0+wY*ƥME#ۄU{/dvk<ne61x)\֊h˫o؊߃ϵz[^Ť"[_Jp-wEHG"` | 4qeS%ezA;2`X9?_#e,<pZ wcߍ ְN m5tm{y)H^HJ@ߦzuIbgHGgVm„UZkfT748X4b üLWl'+ҞcDX!XjXUE7̐浚`̢5 ǩPqe$BjPuj` ղ-:ہ `R€ȣ#l0ق !EנiMu,A\ f$@Stc_a4AkwFlVo&.O 3a_$qIOSh"x[[huAi:|mS$^c 1xYsrdU)EȈf:|t~~zwdRBJvo& #Ripg">/eb+׈7Z5W &4 CSA`TU~_PV*ױJ85-y=,-F.%xV#d'n/NaS  /hcS=0KsPHrŝ_2+q5FcC Q^X1FFn4F xƃUdIJOUm4a\1 BZ~<)qPO V+b ⡚l,+}848a fQHͭ1 Er^8H"ao!m8i}DhR{WJ_web^#AG+;? "beYh}h"VvP};9ŠXAmW/bTi`@#v~HWX8beqtN S:<ŨaaՅXvUp^UF .͝Nȯ0clb!Wp;W(*k a\0ʝYt|z!Zr\;vW>:Kdwdl5D]9XWxѮ]W/՛NuPw {[iT s. z)oj*",^6cټVڗE_>Q?ZӋ#qEh-oMhn'Ehr,w=gR88>TrIh'U|Uz;x8Go^!jǷ>i nѪ5ml!jQdžiHLꪑt,[q-L! 6]ù#23db&omIg7dw0\Ѽ=ϭ uxpƚ$"gQ:%.˃/k욍ﺦBox%9cS^4+8?CP԰9$&_8gq ):+$qZ(R;7L'%^\b7=,0NO.Ϗjg+o)ǗT0 `gw (620|M_]LPtDD0 D$bf](eA0 QG\'nO-2WR=x-("NHaؤ ` %A(MhSy ==]J'|%OѷGnkJl^!V6s\bnouGɰoI:flJ1o(Etԥ{WTihL}Oald(Sqlܯ0)`Tܕek9 ؖWAS{MLFBYf--f ɁnwuqNjɸY]|GKKi^]<ݴ`}xn D5[h@U6R1,|sţZ, l5h%ѫ59QŎ6Z[:9ZNxiyqo 4Ǝd85LBN;ܦ7@sL˫=-ԑE4 Q8g/R'6}ŹJGc Nt:3]%[^^d0hM[*5 FV_=HNIi΄ip8vCtrI?b `"ŔIg;\|J d~~LbΏEO>@t4د4d,hǑOK\i'x7GAFхUԸٌ7Ќ\#NZD\'¶֙zRˡJ2S$4gLIk<1gxU`1an˝>d"? \Hj%% XKՀUh.fF`ŧ>|T>*pb>+eXѺ ZLwj+K=Kg?!sJKOeP\jE6ct-hYF:4$WwU cY?l"kjo{鍕5 ƑJg:wGrF וu7Y{in,I5ɎշY*#b0fZHn+y?bޖc%|( 3kl褧?g(LP{SZ Ksd ƞf#0mjČ1@@7ʄ/L2[ի&3 "`qrv|HҹJ 4CӮSi-AqKE3YհK1ͤQ2aoj$ԍN5=$G 5ryrӲ[xUAȓh*v \W5Zi] z˽4av<ٖ!ٴ(e֌LmGem K1Ek4ʺ~)*|7V`eC0&y\H o! 7 Z@t 䩞$ >3L43A3I#-yr򐚟 *Q)8A֖[*]䶛,BH}r B(FesEP06˄(eRT%suu+j)RW@/\ DvztK'FʤNNp*.b>|Kl_8{F S[*h+b]t1C)=`OHlbl!v.D+ŗMP_.j/Wp>#|Z>,q]KO2$RZ[(<;!'@F?%wx,^FKKr0,j Go/"c%Yԝse//.yd=ʢ_b:?k[/iuEOUؕbRoL `eݙ?my5|P`qYLIiA_uwH1KwmA8!Z1ۻpjGf˵hMWJl'+LZܰ)ötز^RN^FLgg4ĺIUBFSAxF#tϛ+e#oHp]R sA|BκP1`L+f > QXUqmtznxJ<P5+ ,#[]z*\˽7)0>;z~Lm})._,/>;pZu~ic@FTvKmCJBgեaCjL|{'|ckkcs*{CR?O[x %ڽOGi˜ M^MB)8xzE]%7;ou0 z|@}\*c-IC^c.N ,+R\h0c$"kҵ} c2A#E~'cek%:&mAɬ| V`1?Q ˱L—5 v5XcqʣC#q8*ʴDoVz.(WlɆCk3 oDM5(adHWbR^ a WWk(eyzoyy9[? q^VU~|Gk ? lbaqj:yxWZvk'g١ گ/W`vUA_2RvsoP(};{}z.J1R(H,%"gRsܙ7WLCPwlio0\hs: W &nDK_4 BVX_-+3~^v*a`m<-S;0+,GŐ.+sGS[6I}Jc3}K@,GiEхMAEbwx](H!SC $g38^%e 6"I%hTgQ]u(qTCVVT٫+14oN. P d]m;mfeSqRfsn 2vePi8O`4K,vK:GgcyK-~:`DN]+K],#cm6K@zbЙpEhSh` LKȌ,!wK葅Cr<^<Y}DI3sF"tvxmk2} $ Sx#UE]Zs;P56p{aV3i؍tzu$|J&<8oēno#.^uR};`sz{e9+v76h7 g_m^LJ %z7?wEWa5E]Ō\^MGb'" 5`Lnk b5Cśab ?tCa+ ĭC>t"Ρl{x*UT0hls]$[T0Q yyQJeoIcrnлjaE8 A u,l #{pUܢ@^,Yk&:RkMr ,ܳx>Q8̦KIRj$mk{%g艦#]j-`Qgr jG0躰wDZ˗t1RX6ns(x_iQnhEXSJ:ɯ M-+kPHv#H~] R  mk8 = ڠϨ_iAzUSGW? !~hͮN0zx5}F6>4&2cDŃiZrݿDl_'4l@jtZ иLwl+1KfG` b!h/ ~.}8(`EeBib Q\ha*zk 5\8S˔a?~K&mvL M\#8l)\Ƨ@ \!flϸ Q)o$JDu)UzI/ `*'2KuD1](XkHlfs`͉#Ɖ*SXy&p_IL`YzJ_i+!z2*[.FeE%}6I!\vY" RF2YEڀ7j˪GT[bb7z#:CKL"w@b4Z.z@^z.+_LF2V@Nbj}&I/BrO)[ 7ޥy6%c@[;/ #@,{qa)b. _%sYqmi/z(./]G ncMp( ZI x$ vL0Zzؿb˝2Ώ h"Q$.i OP_V\A(R lPНND3㱉T>N{n,2 ZdӚ?+u,mkgnlo?loBؿ8oŤήXT|踤V*qʵ5K1C֘zߞ9p'fRWp 0+vEޓћ8B'X"q: G–3$h7KFZ۵t=" w 'ys"Ѱ"5;-JWS6#&&*U>^ њdE7 K~n U\fԘg0!&bbϔ4#ylID Id1ػJn1E|V BT3F4 h1}  oE,xJNjzS(.#^(Kjx֤ -2Z31TÈܞb cRrɁJjnl>VUJ$MzR0i9UpѼ8dM@ T1oQmD"R/:L0xCbЈ^ keX 8K\@ A{FPB 0th׫(*Jq v`a%󺵬eb`&de /|29F*b_#[L/skoeaTOĩ7- lA9Xc[H68yh6OaKJc7(:`AYoŤׁ`~t,$eImQ!،gza0gPOyi"NF 2+"dh ̕CY7Ԗi hs kUQUޯ-^?!X EWhjdd=G,j(נQb :$DɃ5j.6(y8᫤O"&YYQB bB5"݌D7A٣u(U 8f.lBůש2P54 0$bIN+0 $A1FxPq R NJS&A.`T j,y]R}xw@@R&/pX0_ǽ:_pYf_XX5z/.+~^elqxLꡍnV.'<;&AJJzÓ/SK#ָ,l5kV19"`$(d!Z55I] )Juw6G֗W?鲶V#2 {޾שHpIG3Z>cĵ>"p t HSY `)g(c5C( :n@:w_} h\LX]Utqo+}E9xBEnsv#Ssn+2-KVpѣx.cMeaKQB-0pN50q@s)Z,O n~8\G9 Ӕ_/uvp aC!c(,8f`PDM !@!^_08Ҳڔ_`cRtgl ?԰:a<&cl.W PCOɊ!=Mql&\Ec&]N`eQwJkbsv;o8#boةI{HnsۢIsfDz<dd x;aaFSp) މ>j"U3:naG3uxULSxmXBǺ991\Gi&kqtsr<Zhlfv53{*OzFs)IR V;~ԉhc}n3!?׍X1HCp!A{Ѡmo6[絴ϻ,n}z-gE,+a Dq*ϐ}gȠP[dҵ_.ء$tV- Emnm- ND#ӥ(җ;UVлzgFqtZO1"d #L`Xt/LiiVS4%l7wطr?úwߛ'uyd U\FlCЖn:wcF wxNuVE]# 4yVCԹA8qj~f:ji&Z}WB$Ӿ1 hU Z"`˙U*h! #($R.!85*3Ә ?/N9kz]Yڮn1P$BNGrq'_~W1HG8yuZCKY䐺!Օz*^pR~rR%ĭqR@W+* LԱ:i45AMBJskk w''kkX ϙypf>:WYGS֫oWNV_s+XW4hْ^M[;''ѤwxKV #%US`^o>% /2)wE-N˿QۿI;_xkw{ڇOv{w_''Wz#oPX#tFoha!sF!,H(?\ñͣ˖4ѧ-J*Z"pPv{ONU\ؿ”3z8Y}k&6+M1* nf)DY>Ǿi>'U7 x!t{GF|# r,9*RܫJ}]Q>JU4y#LHӢLh襓?Eux=(YLm1! 6>T\֎Ң H-)׬Pv. q*.93vIJ߽(eQ3g@˯ۀ5*qŌb}CCG>ɕ2fKbOyXbVw#Cz9CQ\lZ &u¿fJ!;p3ӰD|_TB"KAqϵ~xtn8k&3&KQl0 ouf*vٵ:EUdx?Ix(_VM,Y&PptDeƭ_Ma=OtDK>Jn7a,t>d*VrRp8j\"! +]$< trn{W0sJp<y۝!wx>V9DGAr M.Gڜ"RbPH8Ƃ !biUse^Ɛ ~Tg*@\2.;%v3ZVLa7vw`VHƂG"JܚAə$o c̍U䋹ji*h+xjJ`աc fi2R wZ* Nsװ 5͝&L+D\7 -D ɍƦ4Q;Ed1Jdba '8;UϯqRdƖ"5 ȂN 4v%rJo[c0հt0k6~;E7ѮI\\x6*lt LNbh1n}.,zH~rg6qTZ8n;0\mփ>Ǔ0^hB6Aj2MuDzg>I'^y0L)GޖRn;g, }vS7="T%c*Ƕz1M LV;@@G%W/;wSQVf}{S$NxLh0_-7&ЉEi6^fI:a`}5r-6DFEL߿OXՏQ22v 2A(89VI'վ^g^ij^7V٪eGo?ӭl/F A-np A`6RǹXq c hx3==zC*rUEn1ϱӼN{Ad!Qvr&!w#yɾoげ|X[eoSM:U>`OjgUh: 0wwRTؼ\U΋G-zF +]v,-օ5VeGZt3[^ C5bcS|4|Hܼr̺k#7mg ȓyQCX ~, =N`Mш=e"pxgҴݬt]qtJ-'FVHKzYX4>?&Vt^< *x2 ^dՊ@)]=k 9T ۑwctu՛RBQZ][UTrairyz3-7/7rTv\ ođ4ʼnihA3--b26_)* [ёN\/pz[-G³T&*4n@ć i?X9n*?ttj+]meWz*^G{!ac蟣Ѵ 0h?~0Z,l㓓@Iv%<:j qfY3y&8Npt|v={OrG6uNŒ-Fyi5g+&Ep@H8ӻI\}2`D,V;D8Gm$r;Cƈˈ(͉gl4iڻ¦"L@/)!qnHB)*,y;eN tLhT1bCt}C t'ҭTޡ9{5)v0E/ lH[gfi+ GT^63ڛRlGg]AM`i 9%H>&C6%9n!ͮM;)Hps "HJd}Xɸ+nmiLi6*"9ui^$}cHtq8cȗˑln@- f|EN /IA Nln (n#oTs=X99Hqj;H+71 a9_iL#h+xrZ['trfa1x%CFFɖGT5S] GtBz`UnZ!}7leQmJTZ|cE?9ùKQƊ<y~8nAgM;)|s2?U:_H^ %g#u1ؤњ.Xr?ёVH.8] l -ǧ,uɋ=ts뫷g,YZuEPv=DeL=񒗺q~%ӡ1賸(W'B'tt( I2W3I NA AȕmQ{W|P_sb=]L5 <'#*.'ֽ3m!i G0#\V$`T\)ZGt)/'IA[ "zE֧=DBcJb~Y>vdx j,}C#xBEZSz  .i 5Si7_02#u*^6]j~kj~)<\ _([yHbJPN-,#I#eXQe:r+/~^Έ-)bw%.R1,9? _9oㇺ47KEɆTC W (߄M9Ń:#) ^tYYrJShcci0.pnD4#⍄ Aq;oG CQ8\V9}Wژ$*;=k}㓃?o`l*_$[Efa =MK%M|+"ȇ sly&$Y+z(y,$Ir_@d}ZQ;)OfÒ܄;M\;x=C St 4ɼSZvN1DD-E͚$-YA{cUWFRǤ#ɉ29ĸ{v#5N)uZ"y[&B[l!hyDʩ>vNyq7 , 'ЈZ.@2XwUI'#Jn~]5}kȎrt<Ɛ/%\N@DH17JD)Ύu0o,ksKC g5D6J<+n58^>FS[V$Ns.LwH3-A?~4GE;:0QY sI.1QDu}P?0u i'̺s3|RL*QZYZ~YzVc[ܲ(aJyVc-Gie1\m,=Jm5_(  qыGÙ/ҊA/R'ӏGnQ .O /Nˑd)dmK3SצyVTNM{CG/?>;n%(^o{/ˍG/C?Mb]u`9Y\R!#s=Էho#5\{pTsäoiscwK t<*7a@?CUc~8"HDjL<@7Ys@#fOɗ!\88tܿo P!09{sS+_~] !Xv4E|FaXrtAsjb`delV3Gy{yxpC2(ͳM6Z &zZ_=mUX#gSI!WDueɸن"ET4$f, FIqLo I }, (ay֕2 Sı/%18XϪZ,㸹J;$e=9S@R`cc:&Z,YB"8% G!96j; '!DSXxA:UT9qN'4<@܁tJ _8+;ه7i;w s2`(>~֏TrFmC+ E͉ESw)yO\٘0m:Z)r0`J0EVҾ]ㅠ lᜍ9eɆSAN.zmc|iB8%DZP!g/Hoy*+-1$j6^C+*)$.0nxU.O:m,GKGb+QqcV6ixa#'2wfԁ mT5*F:*Vfq Jq.^ԁ%ẂBmG;WL20/ $B@=TW5MdjLXU'r\,au]y?E`(阼u.Άo>86]8W{*&{":'Ro"~kǎ=jďP.2/ twO`LǖMx$(G7f\}6'7tAU|\{&!(ÿaa^|/q.<ٚ`]7ZSe K7Ms,{RjSLBG81',$9hvYd sl9-<(!g0e~Xq5~bx J_̲7 ,v4GTE7:]WȲG`>*8p2Mi !`mMļ#^cx`4S}wVW8RdEčc4]:C$^"v&ϻ̢2~wLSٮzD!* (Wew\dyL7(Zw^kJ9Z(pbik$KN(y j=́s~TIeF8ۙ .ϚY4R,Eؿ+I)A[w֧Aۋ; 1Z2()G ="t֪,bvQtKBR<: "|E7zWfFWoN`]*DnK(b iΰF4@Qt*7^Ra; #6!p+*vbdj" c|l9/zqeQqC۱wm Ki~yuJ\qS]/(sؗZG R:I}!Yd ^j I\QKoG|iɀaB~8 jɍ3Km 1-W; 3N)pܢQx,Ŕ9&a̩uN ɣ:No|鸑-̔zX\_t=h9u8nm0V'+@gR+~rFZ2I^b\U]3qajJn `=Fcf8[95ȠCO1ɡi۫Z:OQq;ồk;vvsj!\|1 $#͝ӵ"YOwIv7GS^)*6sAy<ĝC$ehHNDK.A4e%Qv95rwH W| 2Jkx\V띥D^gyӌR^M#CWQRܗ8٢lwy*qbI^%1,sǩvsaqIkjV_Q<^y4Ej6hr6 ]#'ѨEnFĒ!Dkԅ=hѥ?f[q/;,9`Lk"e{kG&1"C0K#Y ")qIY4RTfmEs/JVtԩp,+u_+J`QN !0͸vxKaIIDN:\u: e۬WvGیa^::Met0rMˆd9-_`,)Μ9z/92ڞѱ٥#Kk@"[@L+۬yå(t8czOq9[i<\$~YDr[:A1pJ #)EFbJR!Vo]h qOvAca璳iy ZdN)sS3yVd^4V@QnA'ovn56p̫95TyXEg]$BxD.ܕ%Kڤ@Ork1@Y }'u9ho,Z;@yYvZ76S/H 1?wm)Zc{nn}9>Nm}gJ N7hVԐ%Ÿ3KdP}/. Ӗ6'}!\:#O#P:Jl]5^kdD73J\J XXdX|^d:KuKJ9m Yd> s>_Oq{! `AcXHCui:ڭ0!Wl9eho>ⲙNF #haק) ݞOEa``%P2d[ [ N㪍 3f|@1ICw“ H D nI>ߜE~0\ryU"lCM:{*:^jW#6qC."Ag;#:ƁnS0cbNKugPAȫYtsJ*lܟ+Cgt6?P8`ǃ/ϗ嗡v@c|Ӛs!^yA,:B)Z܄~dk;24"|j@0zΊ_<4iOЯLY>{ò=C$DH,x~E~|Nu:X $_2gɒEgj5Z<=ܴ7V/%|2Vrv4G;6\C^'J9>I6'cWߪlo_kɖjڒf bK7?Oi?, U,@'_DosO-ya@%{_J^l9Ѡ6-~ӎ_K=)1If:7 UfAK}G~lsO0łiTrvim6TxytRmʮժM/ j8yG48 ' _Aۯn4VQEyn5u5.bi_i^źG.>.{xΟ N:Q7Τʚ S'UK-biгazʱX*2P, 'ˀCr|^Ke`iocҋYŪXH€t6.m߲+)ܾX?a}Z_Od+n:7MM[qVl˚חWk,Vƌ1r"\ po-N^bv:!](g!egY,@2[ftQyph*dLIŋ+ū c&N85-^XiPדt- ޵n7l}*P8sqk8#xhH޿WXjOĞ%3hYXF!vP9C.^HԒ+2 lB"fj\$wK.ME(kOPN,Z5PK+ѶbԪVO!8-4߾ oڰR-" DI 69ķyg KO!., 6l^ah;raƻ҇_[H-PC-w/ĕɈdvn]Dp`:<1'OA/w^W+Ja-8u]Pu]uk~Sn]C[&ӂliiB%:P[\>/%{:23QZѫb>+ؠiF"kna&Viֶ 궳RYA􏸻%{yݭ4Ǐէ٩[Znn)Ln%^ˮW4\y{8pqiO26Yǡ~v}[ofNfCwDZ2]\i˺?Q"kSC!qZ)οϏ8&xu&p=l4z2uxd먮8ӅJ:R|S0w($ dnYuQ.ߠ?.  7~0Y|3Fva)^\î-,ť^}' LB〟aHnm՟R <.T,Jl|ĎDݹ}w Vxi=IJ+Rm2ĢF@tR/kԾO嘷d<]6\'iC&@3܀r>)cA AF6MS`20 o20e7<M:ˠtdD#5E#uڰ_'HOa`'d?0!s_18R:R)jjڌy̔1(0DNh72&1uI,h 2>k"#Z%~xtnʣ &d\M%SVMj4"d &FEK’x"'i^fzsiuSj9>d1:"6u{wa\|R,=!KЯ =(PηlZ=ϫ[;)an!YͿ +oLؤQUoHM0unP̐ĩH1Z&PvKVE0 =,d'faKu>ItCZ3'Jš1XI&k6SA;Ii̽|SDF;xIC"SMv܍ Y\46aZr4c1v- K]ꔏ,hTz_ طAW'rRLiۙ _jU`փXl_Y=Y1Q \Mf/)]Muҕ<\0^t]ƒv :vI>l)\􎫜j<.#(p]ܤ6q̹w iV7{qr3Yw1YSDgJtr*/ЩϪoG'xg`KMiZޔGGcL2zK-oӊ7KIJl+u~lI>xAMsU9>ߗ'!uch{v|jfr4= Z*{#S2T=G[}C֩ G8`~Bk*_|$˧l%SE4חJi"?7ײ6ւrjWԫ0Rd( f|la-@FK:N ˪dd8\_iߑ u3XNc@,uHtga_ Nr+ppXSkJGSW|{II/o4uA6MwݦѿrŬSDN^hxuDYXX-Pܥ BI3zJ5UYtwٹ@R(h5Ω'A @R6  mA{ A zB  $HsH3 dҭ[Z^Y^>ԹHn%b[l-'*-H~3v ]qꥺO0-־]VTOUzU_u8dDgp, };j}]rRERr?>p|WZ:$ral]Cr9okLLƶ=pbhhi pl[@zd#-S?]>q?͝l֛55g|j%O}v%۩ںתo)#Sv23} 3?E/5Nq$gJX'W}L8@J!7s2Gj^B$'# b9snNp4w;ѐRK`YUUը Ho:?.ĔH֘6 1q΂:xm8FqN 9,kRQI8.ILS].=Zr! :w1]F;:bĥ368xQQJrnl*I =Yy4DIhFz$=SnMtbA`Mf@0(N%7PʈΒaqEZVn6*7vHU2ŝ:irr*Yksa!7coH)H%L/9K`QVRg|q8h|}./d@y }/>%%.[LGpV< 'rW>el$^3X^Q_o7nJ7Zႍ-{`u~fekc*ۛBSPjoW=GonGuS*ҿRW.NR^bt}JM.뤟e.ܽ{Aڂd}ݿ5h-н NhmQNA ۨ5Ws0Fcә~y[˿Gl)56MUjV>ЏP~Ckv$gzr\MNY΂)RoL–Nlv[0Vd bpPLUNZ'-ۧsȓZ}%c=?5,u~&@}-{VNh6T,?>?O>6y M2RF{EaѲ+lz{Z^8ՖW^GuEn(A0ս`h7j8Q5g3.M8h':vR(YJy-8Q63wJ.n}J;mOk|"][1ߍ\6I-6)C|k,Ar6ʹx ,6= nM{ͮwTmebĿKɩ4a%&C8|O/qztvڈ/İ=u#Se9't6h^>& :GNֆ^RGGOU}@ l81m4GpQS6.g )d)oZ uJLO~pc B:XWf$K4!pAS O>D{CUT$rE^+ OtEY|#Q]'cZb)ڕHkOrӰ3 NT<ƋrG D\Y"WXm+2z;*re(0n%2v4#aEzYe(!ƍF [`*+pfML.`:h f3<73DB"yaM?0l3-^dEVTa]*\`}֗ *R:Ŧ4hf5S(TLLoF~uW^Υ͎rL2eʕ@_e!uˊ$Idp23he5 e53"NC&hxpwI i'_UK|lE`hᴹ[x ,RĸeR-'_.<8 E.FkʞNv) Y$xMo1W3ZtGY<Ȇ^N #M3@plg66 ŐxF*4cfnS"}:!>\fe0f\6+x 18zop0Wk^,^ލ7ʅt[O=aJ(zTRsrJCYjWH&b< IpW!^!Zl=NЪi"SA~801 ر&PqP'eQrdEF.riDf o sdhY{q"S eY,gTdR,i^'îus (g62u h;j஧/fYc^u%xwJZW=(dvtVwgA0_Gx1RJ ֿj_Kr߷݂)ֿ@}kxƿ24__:~M/@ަʰIg>޸ϊ~:uk̸֩I0gnug%xT[Ƭgَ[QYa kٷ͜8R%4[0||ջnq_.;vg^khrWGVM[b`2. f^'tz;VN\vS$Rmvc|K].{z8opVTT'^j^CvS:mjzT8'7$> ʜ umXkTdNCu:W¢L땹q@s#NA6I|2n#v{pG 4̺¯ӁUZ,ux2ys_gיd PisIEILޒ@8$ɋ\@&N6[oݤml^Jv",1b(~"t Pmh17ώ,8; 9x9 &0 n@lrQgS%#-Ю_fP(x}/,,7ZoqF9@S0Ei-.!vv%P.S?) x_SZt; x-,kS4ZjVe3UoWzHZtP m'=iC/OɓjљtU-qեnE:F;8AÜpxleSf8$|KYJzZY|tF}b0*d9Х3  Fph9@w=T?|ƀ9$b#i-&N(,a1apA+r@+M}s9C;F;QIq׈)N P*`(J cxLΩI+sY<vҸFvSʒt G1-׌p Gs5Re0=;EMes8(ͣ!.>2*G8(: z!>r/zђ3Y.ËsIT1؅o{v4ڸ%<2c 6jCZ3+QmhR$?T 0'26 tv k|Ww5Rwq]/9sI&wijlzS!g|n$N:% ]} l3ΟJtJF3[gl4 --52F <_t:pFCꜼ>;8^ Uď! ]NC9_2lS_e=4i͛q3 SdC|uHi(EC|iv Dq(;)j 8؎/t*l,4h! NnH~:B Ơ1m$NwS}\eܲ<`SYJK -?hR$ I.ހ#>x> U'sxl3ɿ:I$.'ZIe];|TR"CZ ZjaoW&h'Iy}~%X$P,Nd2X$9^RC'%~u*ZO`Hn[l3 =l}po>G h=!˃k6WİZOqH1o.U|10U]{vfQ.!J?k0gҫ=xfp@KIP݁/jQ r/}{z|H|omo0n/|E߉F6)ԼMtiբ՛.7<ȝÑ?:z ?r/y.!ۤh>Go8c'HbK ~MԊfcZa4>ޙNEJWt>0f ?}et&R]x-욖S~#R2xx=g 8ZNqag6{?3pP.(DWwwhSR {4ca7jɭ8rl޴$Jfb~Lnq$SX8 8]cZ#q{Ƃh8 vtx5wXp7KZ805d|4qd8xQ_adX}{ 3[.I(8=\ft6 2l eRƥ%EL1v/qF8GMp/q$gjS vLm<5\\ A- U8Jw[ru_Vna"èmUEMJEyJ?(5(ѻ9qNYv&ƢA$)#?W#[?R^q/h*Nt#0l,z08a oI K~4,dV1Zh[*ԻJT/")U֫z!rV5m}[Zc~et?$Y2|7%|Pо؊1njy7˰scFt} X:M0F 8:V7EP1^1 HAc^f I. ɗ]̞(oK9axoG.tR)D xLpF3T }x@}.d(u|}VNl@|D?8E7VĝdBg0Dc@GQtg(b&r?^"Nչs m!](6O@#|pnIuU1'!<0扐b/H˒2"wP9 0ݨbS'ʐS@GCe#Q%hPs^\ڕ l:*huWRDҡ-CF /`Nٯ:4kޥY 5͚̑1*jUxQ+?TY .cL?L]-t -`iw;r\-  ( ;'J]9pW^A[R.~%*tpSJKJ*ҫ]8 qn I,d#-4Xtǂ4RJ X!nT҈Y=ƱCܞ$$wN-DNH2xmt!Ƨ~cJ,htۣI%u!mn-%ׄnm<|=ּvÜ|߹x.[LE*i79ŦHrlݫK@P=8|Rz׻{wW ޛspÌ $f)^(UM]h1;5<6/qԥrH;K+Jt߯)$}b 9r QUaLA V2H[-C,%Cł滲~RL !GŠSg!&ȝj8\sww`qe Z8ƣyL8 x]Z{hzCTRuE˓.5s.w0Ir̫3 ް^S=֖'\vLQ+~@KMauUk1OqNC-23fB'--aԇVvq,׉\[N΋U1t T`Ǫ|&5qUMqt38attMި %(z)cg2 ޘdӓ܊kIU/ݡIj-}a:u( {wba_lŽOIH)ohַ)gm7sgs|?.'p׹H`V$6 8` n=̷]'SCc45{QHU҅җRݿ+Hz'Ƌ*Zl4uinlnlYD3"rc*os8$tK%_{O촎Cwuyyg9tbK=@Fa QЛ7A7A7A7A7Ҡ?n"(N;, Q&+Ce t˶2HCB=K"iΝl$2ڼ5UFkY6c`mW~5e~#^sa9p4Ʊ{X&*faCVl1*1ç)TR^Dyv$/:fcg2ҩTd0,UW+92zjHruqijwQZraL㑨o)۷S^;NX'R\(p#g$!ozGf-m7~ydvn$R!KWͯI= _F vaKSz8|p76-InP]eA詽dj+G6FI漱÷hHVK2(td ;іVr6QMC@!\G-ŕ|XHpBw"'F>_UQ;&G^'dPMpzϨ 8ީF{mI={{:@^lNZ޴L-VYvD3}^LD 2>6>FG q_ZEިm?vHQu=Vy~VEXZGp%@|n\Y$%ÓYTN jۯT.4nݢPWsi iFЇ49MShN3>9hBs,!͠m kۢ~`3+_P1v'*:Mv?-y])g&uUͼ OSW3+aiIe1=C{!*'O~8*Y0<x)v*=cy"}D`OEw{-DceUB6?U[Ժ,鬂]R8S,6AR qD8}~3q3q#%s\櫎,ngUpݩL ᡨ#iK[*H}$T,͉Ebts[T7^eoYݗ;Ꮹ]"gnb2ނ,odd Mq, {)fRi>弟(ڭ3}~׷V7Z-K\MY_bVI(ۍSkf5g|j3L@G ܀fQ+q(iQ!K[vi1/=֭H 2fTs(z]ӄ2fO h6Æ iySt]'l~LBӡ0'sUOXs~ՎmY8ZЃϜ Ǔ K#Jh#c]jcp ΅Sy'y {YZv# ڈ2;;kE NQ*0[1 8LCra.&r>}>]As ԜF}?tI&qrْ߲ୃwH [_jUjP\m dVR+ ΛY 棼᠘zCzV[_p/V*Sw]˗vܦj}Z;:xL쎺s?R T; Iw(QUОFQ"H  wU[AEp \`x*-Qr+Vz FUnLQq2ލ|&P?U810x}&<≃ [:S5/'j_gڻj 'meidz貈0*2c^P?s8P_Q](Xu78e9 +[)Oi-({͖`1*~-f[u1n ̙oP.ȨXB 0ŷV_}n ssa$֠#LA0?WGQ8 +0:h9Na  { $J=-]}:vlu%SX,aI̘  \-vnrKRJQdѣꉢePO-H+H}xo頻E%WljjDy:ɩΛab@h Ū-ߛ41yh'cX^yiFXž*\Elx +F(<6[zx,İ h$Du=& s"蟠x~e;| N9f,Vck͝W|V!&Yؚ6IË6`0L߶Е2iG,Q I:Dl)Il;N\pziWhePr) c&uP4c͇iXy??o6 UGè51e +"o8$@lX1`F L^bǴnzLA\SW3=F>,P+e!RRn?c288%[X۪{;R[P_T9hc?.DYK zcX7 a]wۛ B#t̝˰ qehR *-h60n-S*[^فغ};Prud!$J~|p^nj'_؆|??1DЋ&Vυ{rYegM_|ے>҉rll$-k_\`:ϡ ! EHfdra8I;p3q,a'y}J\gpM# MF7<4`ɴWu${ڽ* ojZZmY 7n ::xߢB^{W[]]7 3$mgi7,U6u! 7xaLxrFRk02SUS1 rnz= PB B)rzVAcTuUͭ\(q?c8d)F? m|O.E#L7CKmk7a^dW ί}庽Iۉ+;35YCoeWb8DbjKm&R9yfV*ŠLVj^zy 80QA󘫀?Kϥ[| boіxV~Pm@nwFm 8e9n30I3Cee>S 3Xt~:[[h٨onnm0c}#jg !w.'+xF- z6hR{I*/<cXXfh fꝸ~֞^C3̦#Vn $vG8L/.;YGЅpԹ$~knx60E\Uh"VWQ׬:`SIn"΃ocrpR}՛tE8pr}]Z`2-[P{-[ GpuſroGِs3}͏ "r؂R*axWo›-B5`xZDAlْo"^Ԗ]e_4lfFU ~3nu37x_>Pn%C(~J~AZ  _:ے zѰ_5XC2E jbۮ8XєkJ4OjtT80  Vjhz3QʏL+M%<e.*_2a/}c~:76j־) yb6 L;2kxuey~;"*zDN l"?5/5nmni&Z@pw1Mh2W\dߟ8B\L-s*b=rĭA|{龝UY4 * Z'U :{ M.I*|/ 32uQHJz {o/ţd4g%Ap: KUH˂T-@N]6ѓt:LQ)vX3cF֒ݛܯ 8^xEUCqlC(m3p54QaME^}]?#oyS$=R%I2] +ѣzIuG2OFgpUOlJNà& vih򼿯=hE039癜CRojq四-L79.I>CXyXUP.əu0,ǖDK)ަ&GV4a`{!qaPF3 #Z 1AJy˃)*W)/ehnb2˽z7M' [e7}yZJD-zE X4 |U^C/[(1ܨfdP7OB ҡٍKgB4ިK\)d яn0Fg$4=:OMb;~犒`ϧ@^ dzs2i2k 3<a& cF9Gױ DD"g1޴@^!N@@HXu 65-gY\ǰz|_/rt%,#-F=@`[l%:6d  ɀގ"q8# )aF]fW!/xH^Gv{MS^QGڸea@]v2wDAb DybHkEGn#5Ch'tg8~:~ripN^ A9/x^lOc#nx8٢1ͧ+#ULćtF.ǡ.U΃TO{d!0|7 [B97މ7sBd#⑐\g,EQP\3E9bF+Vh Y,輁o4&rbWO{ӷ^ӌBc>?Ч LPD&-̜8տ] #`KJk}gFkrڹy#4 qyG^Q3_&|Bx¼+ @UD Ms3eX@K}sy8h\9vƍpLz]>Mz:#av#IKQG#B:y ŀHt Yp1X%*îG0-i.OC$ Hw~6z]nO4JjŽY1 H1K6,k|scX}r:X G0H&uw_{I0iK0u`ZC@E$ [2Pe4.>}TB'! MC~zmJ68Qଇ2wr8fM*@.j;c&ۖUHk@01xҊio7bD61I0 /(Y*|bӘC7/tYi eIY3cb“鈲.),}Cȼ`hA0 Y&ZП:5Or1UhGXA O*OqyJew|ѱQsϙR]j+-78\礞B9m6EOAx3tyi̓s (>j`td+E`)4esOQƝK+Nct2V{M%tKX{:.?m~`9+ nca13` 5;'YuSL%w3$"G`+{$6ǑX z+1~nZjVFIČ$bg$>־Sk`(Z_-G2(t(w aYN34//`-UZW~ [f/ފϜ71'ՂL"N=Mj KQQQ%0|Zbr4d<& @CApnS3Ac>d=k,J~|h (ms_AԖltWPkk'xɥMn=ݐtV3R!^.N%XJ9?HWT`Gֱ([N}ﷷ_}dxȗՀ_蕲MQ<8.ŀyKho5Z([: "Jބ7%姣l8OFY~t]KDM8@11L0/qZ\ gΧ k4 A0}^/8lϊ#)n3Q0>9hp={.`ߦfU{aM2%Ӿ>ޜvݨ r|Wo01;Z/4 r}R KCjP6_.sy*iWNG{03LN.gSOQvVZ;ۛ;ۛ[5:M=jtc1؃0z "YhM0֫de@'x:8V?<} _J_S=ss-1*'{|D'4ḹ ¡.z6ȻSN>W@GՀ:R,z/w/q/w;pFl!’وnѵ4v`3pV&;_YƄ odvvWeI=_&+b&3ݿvMQl qV`E&v&9sx ƦEyʔy=PtAW8 z±k)w!3]EV#V1f>4ٍˆ**P8Ed~.sQNEDh#]TNTEް^v-3p]߇n^5D?::xg,zVrmix`PH.fr+۝FmDs++tO}ΊB~pR(I¯k[ ^׹_WA;B ﹕޹0z M]E^_m瞼7֍~W#(R7ٰ7W7Ľ_~χ>Eqm.c]P4BfE˿==䖽憿+]\pe`;G@MRZ;7R7]V<r ;ndtNa1Ѫ=ִWuyK/Hb5P8}^CzwUzک8YIg6 M0%85 R[iRY_nr+F(聕A[X8y++Ur4QGUd'Wk.3i b maYDzsx|uM_NYգj1ۥfL=7єN]Dx͢rYߪ2VɓK.s$AMŀjHf;*P&P~$ 9[ur2f>)MTTj=-L0y"}6 @$)_h%?nI=:Kx% S~pISAڀ Li)>(2is:$ۓNת}q/Vۯ%~bf5IBw*j"T|0D Ji2#P3H).f^SR~wOi~W4 )7~_<|VzT7''2/{1|k5~< $L'оˇyX+ ?@TŨ*wJl!"L+$RfCwĢ^801bb5H(*}4@$5\,I.j0yK-MOHݮE>wʼl<l<<FnJh3;J&)ZqTr{3@#rk-.p<Sh_[P0P@дZ#LL(Ql֑%Z@/y3uf,eRfj4HngzS8{k *)'{hvy'45L u54G!r=)P/ {brdxtYQJ\s&LN# I< rc6_VJYrQf`^p1E-!Q5K!z;sP1Lӧ+o/Tb=2zDpQn^]`9A9)Kf bˮ?L^DF[ǚRG~b_=f_fs{gks{﷠w/_}gwW oc G%o)" I$yGbb_ ]c:&t e^4w:J[r}nbq7@bu}VO7"M"1l-3?8OO91k{I鼾FSN_ цu|-rsmez|Lѵ( 6FExŶc8[++;_7Hw+qf4T\] N!{|e¤TGr- ~wCA;(! 67/w{E,.BˈK"O9ȭ0a>[ iBjMkg̪٤W-Up4,ЊɡMP&gŚ{a(OYp(-*ou2Uv]_21Β+څ~ǔ]3aդ>;`w6*ROz ݍ`+U>SeLCC䔞et: ]l/MgQC[.\[Ճ?l/{xX4n:MS]rӾz$@2t֬u7߿\ރ'Z)ݽ}Ab_7YWӉ*N@"#0g8g^xFENèᏛ!yGRULɟ_1zѳm}`!BJ2&q09apcҀazTiIִb.lJZ$˷޴BiT?*d=]scT i;V]Q4669b{@ٳCC:Sf fJ:_T:)rs[D嗹ax Hj,^jsEn*NߌyPؒN ܬI\ag$ rY8iB$̾m4n/hBΘ 2L)0hN?Fb, 2Q8"Q允O R!ZW1YfKioÁ]#f7B]$08SU@5G3*;$[%G1!-%2::?I0_'M$72K'Kzr01J,8"[ Pd6GkC{*FiWTN!"ǬvXŜv}D菤ԍ4t$Ncw3,~F'N0O_MYx%-BF?S7.P^KTRLx %K12zt?>8LnDIO'Hyɔ?J*yۖunrFևPcU~ 'oim.oF{G[u#T JӁ{uP`nO G??vX*AcULCyB𮧌#iM-ld&˩ښ_ Ֆ x=]lɯ׫<|A;'OQ?&m֛Ng8ĥGnIJPxA99n1N=y#\+U-(n R- L?27~ڡ(Z>d8 ]VGh? k=IșApI0RGv0#wRʰ+ Uߩv-Ufpm F>~j7\θT|l`.0^Uͥ܊&`ǜ_\yaV~Wlc-\+TE&ޭ""+h?K9y]]pW#~,Zk*2GEpA#0 M-d f x $E`I L )"@G4VeѨHϓ8IOc8q*>-%ѱߗ# zR<:.9eA_hercQ;$ҟ?r 8>f5@c&Ў(*!kڋ3KZ]Hƚ@VWG%79RRӫ8"P4ZC-4C5@Q驣Cޫu˗3=jWF,r!Q,p= {gB+ ?F}`|\ ]醶SLC̕˛G("-8lN)Vx/C` g]RV*)U%궕|-Son67o֛wkl56Uv}4j{϶g%QRChWw_{'7olnԷ=i?yd{oޣ[5NoVF5ƀyXqDjl]t4+574oܿxsޫmm>toޓۛkP[O{^܊٠UzxKWܻ?ܮo?R{rosѬ=~xYH]]BO3UzոߪQ糭~xv IG,!$p;Y*E28[?G{䆍[V\\CFmekSsDGOٷI)MM0<oo"F:RG<`v;A\<?WR p [4}VJ;N5j}+qԱ v?pm5lbhl_"yũK7+V*SݫֶSo'beovs]M;Y_0xJx~49Y9@q6k!YޥWËh7C+;"6/f3F򃤴F8 S9×{M~[5;m V]T⨨oP( e&!0CԪƩ5jҗ.֞1*&RiHa`w9.^~cP&EzM]$( &HByCx abO}Ga؇)@XE#0%!Ct2̧N8 t u':09_0v8șl|H_g&lid[]h;{ LWk!{;l-՗`-.ѴpFD%r6a=νxDLDǗ磓KI [R> ݨ/k #ӛwsڧ>i\(_f*FԙTgѦ\Oo-%I0{~xJd4oUgs<%˂ݼ"0KN{Ium "}v^'qjSX7byFҔbF`4"9`XG_j N$,֒ruOh%J/hwL"a0;?bqOCwmkКdiVuUOL4u,[lw6ub᳜glY̑EcSq$W ᗳidE{`6@Cdzo)!\IDr~_6dS [3DmQA'GnESs# m0mi,P~j`mZzgBܐm*;f[lbt`D*sGkuAF6#8/ٻ{'Eww{g$h|s oRRe)Is8² -DW.b`1p?8CvZ,? 1-y?^+&>^0pP(OyI 5B@xWs:MU_ltbU[rc5gt4h) v|*AoXuY YX9 <\_:LZe&-o!k6FJqyAV/YvV}*Mno5~y1I{wNhGiѻ0¹]婄Ô&*Ob+% ˗_қM(3VX^YJ.^<48uxpxL<4|#@}濫~|{U kl8]»pׯ^qFsx}{W}LRFxD ziqE)#Cyf@'aa&^2tFI()94n9$- 4qnrxCּl;eeLa$'>FfQl6,XNeJI_&.|pp:C-#=`p"Ntq\ ! 7 5 jPn<lbGMUimn&#?vmW]?O?=G+]ƑԠHv㕧 X8I5hA܃7p\r?dA{ ۞ SbF`#Ɠj7XP7`%ὡޕ,~TH*\U^ E$c 6!ޔ:hlUrM>Qt9xz#˴IDvi/YX<={91rba"*jVfo?9.@Nye( )5G =F3&SS8&b,ӟ*ZetᠾrP]zfJGna硾LCmOY긳NlDRX.A$LXݳUM2TfMXݐj2W=Zæt&xŷ4l]urɖjؗxi}L' xŽGP qaub0k z%?&;N]m®iڣ˽\,'#r}F}Wخ1@6-LPo7S4vD*kɡهћOM7쿝^k~?Npi`9yen3obY)l/Ѽ*Aa7i9@âi#J1:T{p8#H&jd,m;]mlz IMr+@_^U4Y_a_<7eg%n_?[H9t[%b@<.d`NOeEH|I"]x'w6L9YmLkdx>ұ'lpD"zcXӪ<\Y$K/=np Dq8Xqp@[*U 4Ie&K<9gy4DX DIbIs`i,`/%U,W`]DW)|E K9D`t؄p%^⪱;^[(}ߋcDG (-+[R'X'}(qbGne1q!Y&HPՃ7uxd] T֝ 2Z#Z~t.@] - ,3`>L{R{#'}&|c?8WxNL?E y J?B]M7ͯs|fY܎m辩h)[B> j= .Pg?}; _/&7|#zM>*81e϶OcSD;u[j~,lY @9u#m,`&@O\y 'i$UrO,3rNB<( G xp >Fop8o %l3 ʩvGӠڂf rȴm 4 +vphࣤb8V0{`.^M)hj25q@Fͦ= f볖^Dzdړp0z˹#l-sM#;LGɄǓ)LaS]Pz`4QD,B[TE6Nx #LM a& g|5ďo,}KI1F>kR'K!Gg՛0ZsTn@aup] $>?VN{q{`xyk':Ra7'JZOaVeOf#jQRN"_h0'F>Lu;%=c&#Wg?k5wec@2^)XX]u+ɰz} N9*Yʗy< A(NO;e8 pcQ|hu &>rs9M1m.$ NI4OES&ij;#%1YLrxILSe+ݶ'!r>|p)mM"Y 0k0rVx2TFI*[Nz3njChsA3풛-.QIH0[nHt>4ll4z=KXOcK< 002tQXf ")wFX$/,?`p:~͹; fMulRpY@ 7#&΍ۛ<>EOjڌkK!wfݞ#:KI4:U(A+zy^ˤh{D$ͭ\F%luAɫːMP+ VȁY@tpj΢nH'CC6C+wS"5a wq9M ̳Ok06`G^ G;mKe%-[ZPm(0wΓ\ TѠn]!p+Z/w;VF %n:M9dF1APJFݵURp&] ۮ%Ҧ< 4,$y8k;4sg$)dKs+ T*vA `bAu~ 0kL]Ðz꾭[!aܷu~m]45 C m~=: fˇq-tnS϶㾭[N0pOC 0A۱f$p CEEQڽ=_EֈnlIp~ ^OM:qg* H)&{bDĸ`H!>䜟`vԆǰOO={;O)y,ynJ;%yx Pm@ƳvNyrҚiIl %OCn >j >PVk&lP@Da87"_ H|3Y~6cT+,? ߂䦔,Z^<oŒtdջ X}V7aV ɚes̻ʨLC ܶA ֗mJ-UH3L^|AuӦ\C H:!$N:E洖tHT''&Mo|5))4%!8X%aJМ)<@IIYpY:|gi.K2)ˀ3iޣKLZi59 R ű 4grxʚDu!8'*V[%TɆCq^XkV1{63{JjHEʓa~QIB^RwHs+m,*t|U*rܗU;Oe4VTE{k81ئ͒9t ®zgυ"U%!;/J[.Xr"YE=mrp^ ^}E[xexXAWZ35xEhEWwZ~1{Q2O!AB^ '?$h+ӏ^q20`~" "O&q:l{->*Az(@/MDS&Fjx^z^oA,7>LV =Œj.*R`!uSh,\%r ̍1znB!Ļq817z={+8DdQw.pCf)+rZuB}߿Q<^S^JYF%E*ս?M=l2\0pjѼr1T^$h%V8RXm^ި2@ nzWk]T_Z/ z-kUrNwU!mN`Ewk]s[\T\YĘߞDߝWOJV/No?~u_hIaW_a0$%>eDp+ >P!{Y\)+vj$)3R?R@~a՞dU2i'ݻ%`\Nn$M\!ޯaXeM3_fu}Zh>j^"Z"t ټ"έa.Q+8~aw8'BJ*^x$9vDqř:3qǛ"J5C1=h I=|0*O9&HI{KƬte288tDkˋVU; 1$q> TĬ0DxaKZmaգ<-@GIޑUґ0 7xcoe5 cD!2_^f` Ks`9H X-́]?P,K`m6~р'a9M,q4ѥn1'^J]O9PYDž/۩dVwֆGp S ~yzô+?K3DI#y?T3][<^ek*z5ph6^ Yzd7C(L8> Ǟ>u$O+NMz,U斮Km |U\9F)T׺D^w|R~} ~Wz_\/8R05Rc]GO)A=n^- igZcBdڐm; 2^q% f|ȌzU:GjZaC50}mʸMMmZQLw5, ,Bm-"W5F%%m=<w;V|. 0 zn4 ?D~4XIl "X@+IXo0ŶTBw[lsl!.lJJ#jt_l)^ٴB:$¶¿PO@:&%Ž/}aG !gnU*:4{U<ɢֵNsoGCΒ?}]5yge:ꭊOC1 tz΃zc+o8r8 5^^p0qJFg0hT. 8RQg2THw*j0@)zlL/lovc<Ū `iw ؄ èT֩\x='.mu.´"F/_|sbd!6bq6qpX7Z,d]R@)  P2 T1CcDD鏱V6X+ϔQ՝] Wf~5-XlnMa|b چfSqf`\ '<@IO@@DSS#L&ȣ' s+iBŻ ԺHazl}^PۡϼnϱI=_[H`dBo^7⯵ż)ьplMx!0(t/MM_kXBLAi56gIlxy&J?\^qC\#"udS,47C*ܘS#D”?[F^ 0n@k6v &I@z1>1Oi(HisZƓz -AIϱuG>6Of@ 嚺" Aj3y<kAT屒} pMLb wqo6 `˘M=i1P"G=V 9Ga7mc&Bxr;EJp 5R&ʨ}L|Xlh($Z ,Xb @R''@:<ı/^/isc]"sdV\ H#K_ C-@`jT:F`2\,/Ƽy2jqyGV%nMÇyώSf&֯MIʌ"d90g JQufҊS uBxU2-RZ~=Vp3{ Z Cox*3>ݮ74_}q *Aa8[N[ a%uv 4Cq Nl$`WznUdTͯAd;v3z`q[@V,/ 霎 b7w#eWm=փm)|j1im{ zSj_ctb, bnM?:'fفϷ׷vhl46lo55ڈtZIo4q(^9gý&3&jyCy5ly[tw>HReI~ٮRw7Ŷ@昢7d!ҕY\kxHV%)‰ulH1mNdP4\\z{$ t<$;Qgw#흟;Gφ*JHds5 ix-;Ё5al$NhhB "hz=8z&qG~\O7%3*Oq8v (ס8k"TA Mj>^5&'H{:F‹sFUcá3 pH $=FS؊=5cf4(u_?bwp YFGW=!Չ֠7* $oƦ}R=ӫ?'x}ylGG5vMh;ócYyryNXtn]I&lvu:6MGtHB>W {ji_[(0&Md^ ^g%Fu]5ZjxړV>Zj⎣icZ\.Qǐ,'gġE%8xUBۄ;xC-!lV^Zo?mGv|BLw`d&@Eb<;~y0a1u5vL 9ad.]eC_0cU?^V ]Gٌ0 zêy&l|l^hqR*WM=zdal&Pe:,&ɶ N,h8F@sci8| ICPA6%4ύ e@\>G^9)8GLRseċj6/!BRʐT1.:HRŝ4H\xZ$Cr۽u1jG]w CS!ؔ+wU5aP6=0^x`^pf (/մ ~Weas٭(O⩶j-Xho>0Smz|G oGP&)7E+^%tR )l<3 ˣk9~abgt1DƺY؜\v7=A$iACE8OK[鳿?:3;)'Vd'n-фY߭-n DDW9*G@> ϭё^~8lǬ^K7Iex^ t{!FjoNF D1 %A|׈,,(1 X Л$dݮW;YoжXhi^`ܟB@9nMxIDw4tA ' M '>0jTZ}Vofhg7? 'y_.8Y*(*~(ßgR+-|@v›|#n}]pr?N ;8^m`״ķ4w@:g0C/ҟp.%夽&AĽؼؼ8~Yr`jOaġRAҜҼ:zSL@DjUJNYGrd(otwWQ:,+5 OZN7w$߇7c6Hdvexc8fATDħ bjᐁYut ؞'pJC+Zhը_} ߧB:ۡyqW[͙|sR Xs>~Sm0%6 /h=@m,S\@j":'kܔȋ:#=)-PӨX(@-Ѣ56ji V`oƆAP"y}.ex!o95hkYR*1IHQU{o*6Ņ̃ 5j8wߚX%,QE41ՙ=Pfi<.Jl#g4QZ#b25}^#AʿIiT݋\7Xy+#c^|!1,TokmuNطu};R't--walo \kb 31+h!VL+/cNc>ǒZҒV Ùv$&wdsmLRYw5 z^˸P8$|Ԙ嘿5o6u|rAzH:H)tG$s9t2o<[lU;sf$c>}h('1)U{ŕՖծyA^u Nm1?ڏ9Kp /*% n!H!87 瞁6;ԡ1`0$' I {iq CFn0jW>/{>;,N8cf (W{^n۲pqGl kP,S[09T=$ˌڸjup8* W ,1 p k KnC&E@}B^Bl`-C@y8S`wOJr{~lN& ?4+f鍍js<"PSxl<>y顐{ֻqV;zҭn'`@I/ՀH"55P?XOt|Cr6U8kfʻЀL9H!^T:_j2*R3>E7UG4f^6H?uX#cyk=),Ft!^ X7jko0R{=!))󾻿s™$aAZ303@5TTd!@iLs{58H*pFG9PTɈe΂י>-r=X^E\!'k<Y+ Jld}#q WD"cfa2wx5ƻ=.-c[jMIB;P艄Lz6U/{U@/ϛvSV0=O;X2|;rv{  eә;!ƌ{Dm#zӻ\Shvn|CR$Vc~j+ D4OU-?w ^qAY]&V:Z}ؠ`jEg0h qdYʹ(*9PѪs;q%0a@S hKdx14eX]ia|w|X)lXLo="jVpguFw;G\DzWWW7WbF2m5C<ơhTզ8Q5Ym w)y%99L7 X@P|*À۽ 2[6 oeI<8I`!r0;J<&^Vl,ذMJe$?y%MV<=/8#*@EӮʫ%jMem<B")BFhY%֨>nzg}cM.+VmŠdq^i>82Byaq`gn1 N-`8 Fm.JMH'HtsŤ%G.{Hdr,UMfҳN1jc#!tISV{yG4^﨓;:WG_o Ϋc hg`nOxŵXT#_Lct+dq?2˖DpH[bY|o K_NGc.ꮩỸ{Hq<'T}MWpǢCa7#k6eCI[k1[`C40Jr[-踕m|=:~:vjPce6 ( lWk6L"UW uUL 'BxIWP,x"Y=4w{@}5*|kɈv*Ue}*<:Y!)hzPt>d}ow9 p{[I$\`ə[zTI>g: }Zx E8CR!KQ7Y x|$& & _#=t|yNp[[|qOp2QXLzӒG*7?i5JbqqoxYv|:.%H؍e@ pn{ vrU*atZÛ;I(ګګ]O;j)NxMsS*ǙjM*TqɠJdIY_[[}\yOV~X4ǍUѭեٮ.Mx8֔iȏ$ nHZ:㲶&V@STg u'^Ww]xݕݕ'MoY_]k677zk+Zu4F~ *B+Z]JnPЎr0({[B=W~k!{]*YԶS,D]Cr=Goc%Uq0R_ӷV{SdO_2{7%.AN^2|bQ7`^ nNПyJЮϴ?Z<;_v2L`(EMЋ.i'2I.h$,)ph9{_FU(2gP-f3'oV[Kܱqf3IO)^PdS\0܂Y[ͼ5P5 ع@=a\v̜ۗB(7ĦZ\w Fxqea}a08@\%OVPU|AsЄ(,Cт(4@M ݨg.I[f-/X}.1F_y8_,crvȯUDL4b3"ʤY/VKiAZLiTgKV*dV+ΊmViFCUkZܕtCz5dV%A<%}80MX!oVF|GƊR'H2v2fiv|(Ad2cafKP FVGdC(s&V(`&90"|Av'FᕱV$G{pIR[UHU@t5P>F|b"B^G8(ʦH \)J*=?R:Q lۃz+xg*k{Q%f;;@  6hkݽsv _$_ho} g440` 9dL16BSZb8XOk4Hg6pSY~\ޜy):jNqʛv7`}= 㤍e?ٟrE. H[aWti8^eG?v+&7*TqFaeBBc/q :S3.1ӒH_V9r9vel6Wh\H%B*CӒJ9ljMUYaB֐/Fi'/ v`K4j=Qv2B%nQjZTtDTW;4GjDkr(š ٹπ7H@0b{Iz.^Oe#*Mb.+n f3eʎHѼ J?(Sr+5nu5mo3s<=78}S4?AoecI:qg}suLjȧ!ƨI@FMw:BNvTqϝ^g{%H^cWF +U9b[zѳ ^ :Ex F8쨤6beuF!*>O* M^\eR0brIk/pD^໻zoENq)K7`2f5,h~m3">hO񐗧TaU]@ϬbN-Va|:K4Fpxb/YNfJ {4"(+fFz w)f xǬHuh2јv_P:J':iA qиbB+0WCŭ>nJ` W13P(N-L4vFэ[m>j/3i&.XS0%!as+KN,WO/9Ͷj/JZ-eKE2FZ__|,#ݤS>k=<{>mʋ2Hxm̰]>ݯz0csA/XU,+-- f;vP$!=cXReTOulr-Qd|u\eݪ1PYtƷmЛ55 XHYǞA2UV %)Uϕ(d-< x+ɟd`fU+Awle{w<"[+ER%dJ%_aYKў@+m{ev_le;` d=8®Puyw(*v)#&kSΨqC5e}סvܨ AN@'ʃaxaVtLhcKM3bbqǼFeu+ϡlRIE4 h=d4s48RwFUEV 8I25';8=S8)%"H_͓7{"Nid[pV qN*^EA|N[20}34$3‘jvΜWܯ;'{[kh/šYhPǵQ-&WSfjk}]kMPQn}j2̥aQbnMX?bWzQð(~4~4ٱ^탈ȼxdؕgЍ"ro6v%p)/7K7] tAA"=4[S輨8(Ab~^S@ 惢z-8Øh,Э6ܴ̇Tq,ZmwRD @MńE+ j%<}x-R2 c*VMt~3},o'WfltY*Pյq%EqX|oE5Z#mH H fڅduK!v Ȥg [j+k9@M?X[ȣ@vc9ytCdZ95-[C:]^hi(U`t^OUΠU MRƒ@⾷"â@{1~NGd>La?-_(\ӱF84 3\WEmrl͒̎ƗLT0> 4\L1iUBe&&nאBln ke2.\C˴d dRue%Y%̸vmn]Iɕ=}Z Oʛ7`b,Nb52$xC2$?xtl`SU۪1U3j Ŷ4m/ub:3 -b s5\gtbp>/d۬]y:UI_]ܘ=y0`n57Vi^9Je@@!?,#Ϋ?)4I'P_:U{*,<+{!곒GAE[ d"]7)'N|N+QZԓ3^ENÌж׬ *.{XB;?FHz C/뗈UFL-zH)$#iC2&‘2[n۸|ZxyjgY)X 96ƆI<}1e6S\ 3I:XG0Qew6<Pn7%l@ыx A$90"C.YGĭAcTQkY5ɷB˶IX48Morꃬ_:ӎgF+`Z4OS vr8&؈R  K?Ý;ۻjKOi]+IBws{eQ~G3MXMkյVCs +7L>`24n (W\Xv^ >!3I$OF:7.w羫"WfȬ4Gd"4V*c@TǸ\[vdB38WYf-eԸOJvduЁS1Z9uZsl}Uܼ*Qr'N﫫pB_<翿l0i;q8`fdqe(x9HL&&92/zd8b@N|`Y$-=ڮ0vy-w27YJM I䝬PuH9}r̢Kdu 3w!@O;S(6ީLJ(a$=ircveێQ1xUB`8gl=C:~9NF׍z:ep]{*lDŖ6"R Ԭmg>ViQ ~O:WB-,K4#WV~jlṠe_`<5]$b>S&kӤ!#bxψy(jz#2]vonTMzO=.+{w :Q KNDl{^5Tmu݀(LMgfG32X@3F cJkmr%eƛ'U2.\C.\SD $@Ѳ5!. 48E6q01ȤJ,I1Cuʧ1?yI3skZ5*Q qĘ#̐93Wm bha~HKeNIµSs& U.iό%Z/aNGC" H3ZI!TUVaƵ0~~Ky>zTkmy{A* M;ܡr |J~Vo\D= .8%kN^yч/E+>.TH+iaL4#T;&8NiF$܋wixyMlVPhP7B|}Y~CQjj;l(2['Kt. LƋ=`:."t 4֥%3k6y%.21- #\p=shUz*6;c-W;ŚDXYFi}EHL'7cgy0*[j@jd8|kΝQij#Ϣ(.ڍꓺՕ M7,"Kk0P?HORH+$p &u zq"+=_$@TXh ,e(X˘U1Uj#q0rZ\\C3 TK N/uX=:mq@FWV>^ M NpPZn4䖲L߭;Y }i?^X7I-fP$πЩmЌ- CW)?gY]>#y񃉗5nKYxF@^\h=G<ܔfVѦc`5Cl M&1fÒmQy;U>c/ !VpCx3lq6ҧh&#|)E$hQUn 脆qSfhrCsvXxRsȼda|>+ ٓZ4bHPcU :?R+ˢˢjkws$O]mxc4lV*m}C.tQW;,+cT;nA^gA@֤Uֹ$,j-ݾUu5&3.KtÚȽ^(G;Fͷ@4> ih>Lʽ#[I6{ҘV,QG56jZsM5WZFJr*+;s*NjDZ=酛?r>ҸATὉm0.C20+׈^I؊tӲ_4Vo͌RD$|+Fd`cqسי䦔NN4x z(%-w|#:3jඁ/x*gγdL<]4~na2Mc][ۨ7OV^]kzO oe xޠ6V{7ݕƠVJWhu;5͞S bY|{ϟ {t3ŗ_w#M1N5Wm *Nީx2Ɖ]M}w|5,EK0G])#z|5A{{<xxZq bj[q?cQ H$#hrXCXaM'd"o0o{u;&c0~1Sdf#b5{{&5#G]{PHOoX,Gx U+GWӂLdmT"ق Vh> ѝ*JoZ,h{x?EY<y~OlC;k;sl rtbL2Ѷ#,T &8ɉ!2gAS@؋Mn`Î0;%X.Av&Gb .08<æ1AGTުg+80-J|-cID=?]A:U'%=&@L޴v!/tz8 fOj+u6+[ynߋ@a*'WcEPjխ\^rBK:@*띣;'Gd%Î aŲ*/dosvY`rxr{ O2{*Mc;QK%{^tjSBY cot?87i~bU]hj0EwM㋉r6tSHK"k:b-%y/ TMT(XAdRx3!`d VՇocS(XGy9RAXmQ=dZ}ZÿO=8\t8`f n1ޓHpWTHgimtXԺ|ꔒ=c*rF톾?Iey`2hևqch[7m5$BUZ8dio#ԧ3n@]t*Q{F~tlՖLkeL)6Obo8CdyXCB $l^:}"[_aBʡ_O' ~߯'߿޽W74֏{v7ƻiMJIt"O>\wol47ktsޚ IJdWF|VsjUm#`o~x.yRڛM5'xo%8Jj"< ݓX]4ph9P*Q^)i,*=ьu_~.l _;I8Ga,dާɉ-J|O'lIgǠWp<=K|X>9b?L/8[vQ!]ƒGc9 }J䱷.3#rpD@#uO$<1#?GP*NbUzsrc1*kƼJ1Ѝ rVM^2C 4ktX6"9F^]aL=H^ gͱ!URJqO&ɄQRi>-{ e npK+t+L-DZ0 EqfBz!wEd4wՒ]Ia&KòmB𻟜el>e<:}Z!1P1C/bck:@qTk8?+Cboc Q-:<^^d AN a` * #4hE|A` m S5P?kH q1\/R8ЭP䇛ji6{PVB;O ucP-¾ºkgF~y!ZxuĭӇ<~L3 g*JAO${UA'*N"OD)8gU$ 1,qJȥҀƒ6$8X,Y29+Y[6)G>e \PxSz;:Y}'WC8r p cR%uM7V\_D#kjC K2۪kyKqsHSX$d::?xjkb[,qMK{w, 19<\nD\wlj0tX]Dw?/RD*(b߅f;AxE v sJΤVfjas &]@a6΂WP|y<_/ϗ|y<_/ϗ|y '19.01.19', # official version number of this file # STR_VERSION => 'dd.mm.yy', # this must be defined in calling program STR_ERROR => "**ERROR: ", STR_WARN => "**WARNING: ", STR_HINT => "!!Hint: ", STR_USAGE => "**USAGE: ", STR_DBX => "#dbx# ", STR_UNDEF => "<>", STR_NOTXT => "<<>>", SID_osaft => "@(#) osaft.pm 1.164 19/01/20 23:15:11", }; #_____________________________________________________________________________ #_____________________________________________________ public documentation __| # more public documentation, see start of methods section, and at end of file. ## no critic qw(Documentation::RequirePodSections) # our POD below is fine, perlcritic (severity 2) is too pedantic here. =pod =encoding utf8 =head1 NAME o-saft-lib -- common perl modul for O-Saft and related tools =head1 SYNOPSIS o-saft-lib.pm # on command line will print help Thinking perlish, there are two variants to use this module and its constants and variables: =over 4 =item 1. Variant with BEGIN BEGIN { require "o-saft-lib.pm"; # file may have any name ... } ... use strict; print "a constant : " . osaft::STD_HINT; print "a variable : " . $osaft::var; =item 2. Variant outside BEGIN BEGIN { ... } use strict; use osaft; # file must be named osaft.pm ... print "a constant : " . STD_HINT print "a variable : " . $var; =back None of the constants, variables, or methods should be defined in the caller, otherwise the calling script must handle warnings properly. =head1 OPTIONS =head1 DESCRIPTION Utility package for O-Saft (o-saft.pl and related tools). This package declares and defines common L and L to be used in the calling tool. All variables and methods are defined in the osaft:: namespace. =head2 Used Functions Following functions (methods) must be defined in the calling program: =over 4 =item _trace( ) =item _trace1( ) =item _trace2( ) =item _trace3( ) =back =head1 CONSTANTS =over 4 =item STR_ERROR =item STR_WARN =item STR_HINT =item STR_USAGE =item STR_DBX =item STR_UNDEF =item STR_NOTXT =back =head1 VARIABLES =over 4 =item %cfg =item %dbx =item %prot =item %prot_txt =item %tls_handshake_type =item %tls_record_type =item %tls_error_alerts =item %tls_extensions =item %tls_curve_types =item %tls_curves =item %data_oid =item %ciphers =item %ciphers_desc =item %cipher_names =item %cipher_alias =item %cipher_results =item %target_desc =item @target_defaults =back =head1 METHODS Only getter and setter methods are exported. All other methods must be used with the full package name. =cut ## no critic qw(Modules::ProhibitAutomaticExportation, Variables::ProhibitPackageVars) # FIXME: perlcritic complains to use @EXPORT_OK instead of @EXPORT, but that # is not possible as long as constants are exported; # should be changed when "use constant" is replaced by "use Readonly" # FIXME: perlcritic complains to not declare (global) package variables, but # the purpose of this module is to do that. This may change in future. # See NOTES below also. use Exporter qw(import); use base qw(Exporter); #our @ISA = qw(Exporter); our $VERSION = OSAFT_VERSION; our @EXPORT = qw( STR_ERROR STR_WARN STR_HINT STR_USAGE STR_DBX STR_UNDEF STR_NOTXT %prot %prot_txt %tls_handshake_type %tls_record_type %tls_error_alerts %tls_extensions %tls_curve_types %tls_curves %data_oid %dbx %cfg %ciphers_desc %ciphers %cipher_names %cipher_alias @cipher_results get_cipher_suitename get_cipher_suiteconst get_cipher_suitealias get_cipher_sec get_cipher_ssl get_cipher_enc get_cipher_bits get_cipher_mac get_cipher_auth get_cipher_keyx get_cipher_score get_cipher_tags get_cipher_desc get_cipher_hex get_cipher_name get_cipher_owasp get_openssl_version get_dh_paramter get_target_nr get_target_prot get_target_host get_target_port get_target_auth get_target_proxy get_target_path get_target_orig get_target_start get_target_open get_target_stop get_target_error set_target_nr set_target_prot set_target_host set_target_port set_target_auth set_target_proxy set_target_path set_target_orig set_target_start set_target_open set_target_stop set_target_error sort_cipher_names printhint osaft_done ); # insert above in vi with: # :r !sed -ne 's/^sub \([a-zA-Z][^ (]*\).*/\t\t\1/p' % # :r !sed -ne 's/^our \([\%$@][a-zA-Z0-9_][^ (]*\).*/\t\t\1/p' % # :r !sed -ne 's/^ *\(STR_[A-Z][^ ]*\).*/\t\t\1/p' % #_____________________________________________________________________________ #________________________________________________________________ variables __| our %prot = ( # collected data for protocols and ciphers # NOTE: ssl must be same string as in %cfg, %ciphers[ssl] and Net::SSLinfo %_SSLmap # ssl protocol name hex version value openssl option val LOW ... #--------------+---------------------+-----------------+-------------------+---+---+---+--- 'SSLv2' => {'txt' => "SSL 2.0 ", 'hex' => 0x0002, 'opt' => "-ssl2" }, 'SSLv3' => {'txt' => "SSL 3.0 ", 'hex' => 0x0300, 'opt' => "-ssl3" }, 'TLSv1' => {'txt' => "TLS 1.0 ", 'hex' => 0x0301, 'opt' => "-tls1" }, 'TLSv11' => {'txt' => "TLS 1.1 ", 'hex' => 0x0302, 'opt' => "-tls1_1" }, 'TLSv12' => {'txt' => "TLS 1.2 ", 'hex' => 0x0303, 'opt' => "-tls1_2" }, 'TLSv13' => {'txt' => "TLS 1.3 ", 'hex' => 0x0304, 'opt' => "-tls1_3" }, 'DTLSv09' => {'txt' => "DTLS 0.9", 'hex' => 0x0100, 'opt' => "-dtls" }, # see Notes 'DTLSv1' => {'txt' => "DTLS 1.0", 'hex' => 0xFEFF, 'opt' => "-dtls1" }, # " 'DTLSv11' => {'txt' => "DTLS 1.1", 'hex' => 0xFEFE, 'opt' => "-dtls1_1" }, # " 'DTLSv12' => {'txt' => "DTLS 1.2", 'hex' => 0xFEFD, 'opt' => "-dtls1_2" }, # " 'DTLSv13' => {'txt' => "DTLS 1.3", 'hex' => 0xFEFC, 'opt' => "-dtls1_3" }, # " 'TLS1FF' => {'txt' => "--dummy--", 'hex' => 0x03FF, 'opt' => undef }, # " 'DTLSfamily'=> {'txt' => "--dummy--", 'hex' => 0xFE00, 'opt' => undef }, # " 'fallback' => {'txt' => "cipher", 'hex' => 0x0000, 'opt' => undef }, # " #'TLS_FALLBACK_SCSV'=>{'txt'=> "SCSV", 'hex' => 0x5600, 'opt' => undef }, #-----------------------+--------------+----------------+------------------+---+---+---+--- # see _prot_init_value() for following values in # "protocol"=> {cnt, -?-, WEAK, LOW, MEDIUM, HIGH, protocol} # "protocol"=> {cipher_pfs, ciphers_pfs, default, cipher_strong, cipher_weak} # Notes: # TLS1FF 0x03FF # last possible version of TLS1.x (not specified, used internal) # DTLSv09: 0x0100 # DTLS, OpenSSL pre 0.9.8f, not finally standardized; some versions use 0xFEFF # DTLSv09: -dtls # never defined and used in openssl # DTLSv1 0xFEFF # DTLS1.0 (udp) # DTLSv11 0xFEFE # DTLS1.1: has never been used (udp) # DTLSv12 0xFEFD # DTLS1.2 (udp) # DTLSv13 0xFEFC # DTLS1.3, NOT YET specified (udp) # DTLSfamily # DTLS1.FF, no defined PROTOCOL, for internal use only # fallback # no defined PROTOCOL, for internal use only # 'hex' value will be copied to $cfg{'openssl_version_map'} below # 'opt' value will be copied to $cfg{'openssl_option_map'} below # TODO: hex value should be same as %_SSLmap in Net::SSLinfo ); # %prot our %prot_txt = ( 'cnt' => "Supported total ciphers for ", # counter '-?-' => "Supported ciphers with security unknown",# " 'WEAK' => "Supported ciphers with security WEAK", # " 'LOW' => "Supported ciphers with security LOW", # " 'MEDIUM' => "Supported ciphers with security MEDIUM", # " 'HIGH' => "Supported ciphers with security HIGH", # " 'ciphers_pfs' => "PFS (all ciphers)", # list with PFS ciphers 'cipher_pfs' => "PFS (selected cipher)", # cipher if offered as default 'default' => "Selected cipher by server", # cipher offered as default 'protocol' => "Selected protocol by server", # 1 if selected as default protocol ); # %prot_txt our %tls_handshake_type = ( #----+--------------------------+----------------------- # ID name comment #----+--------------------------+----------------------- 0 => 'hello_request', 1 => 'client_hello', 2 => 'server_hello', 3 => 'hello_verify_request', # RFC4347 DTLS 4 => 'new_session_ticket', # 4 => 'NewSessionTicket', 6 => 'hello_retry_request', # RFC8446 8 => 'encrypted_extensions', # RFC8446 11 => 'certificate', 12 => 'server_key_exchange', 13 => 'certificate_request', 14 => 'server_hello_done', 15 => 'certificate_verify', 16 => 'client_key_exchange', 20 => 'finished', 21 => 'certificate_url', # RFC6066 10.2 22 => 'certificate_status', # RFC6066 10.2 23 => 'supplemental_data', # RFC?? 24 => 'key_update', # RFC8446 254 => 'message_hash', # RFC8446 255 => '255', -1 => '<>', # added for internal use -99 => '<>', # added for internal use #----+--------------------------+----------------------- ); # tls_handshake_type our %tls_key_exchange_type = ( #----+--------------------------+----------------------- # ID name comment #----+--------------------------+----------------------- 20 => 'change_cipher_spec', 21 => 'alert', 22 => 'handshake', 23 => 'application_data', 24 => 'heartbeat', 255 => '255', -1 => '<>', # added for internal use #----+--------------------------+----------------------- ); # %%tls_key_exchange_type our %tls_record_type = ( #----+--------------------------+----------------------- # ID name comment #----+--------------------------+----------------------- 20 => 'change_cipher_spec', 21 => 'alert', 22 => 'handshake', 23 => 'application_data', 24 => 'heartbeat', 255 => '255', -1 => '<>', # added for internal use #----+--------------------------+----------------------- ); # %tls_record_type our %tls_compression_method = ( #----+--------------------------+----------------------- # ID name comment #----+--------------------------+----------------------- 0 => 'NONE', 1 => 'zlib compression', 64 => 'LZS compression', -1 => '<>', # added for internal use #----+--------------------------+----------------------- ); # %tls_record_type our %tls_error_alerts = ( # mainly RFC 6066 #----+-------------------------------------+----+--+--------------- # ID name RFC DTLS OID #----+-------------------------------------+----+--+--------------- 0 => [qw( close_notify 6066 Y -)], # 1 => [qw( warning 6066 Y -)], # ?? # 2 => [qw( fatal 6066 Y -)], # ?? 10 => [qw( unexpected_message 6066 Y -)], 20 => [qw( bad_record_mac 6066 Y -)], 21 => [qw( decryption_failed 6066 Y -)], 22 => [qw( record_overflow 6066 Y -)], 30 => [qw( decompression_failure 6066 Y -)], 40 => [qw( handshake_failure 6066 Y -)], 41 => [qw( no_certificate_RESERVED 5246 Y -)], 42 => [qw( bad_certificate 6066 Y -)], 43 => [qw( unsupported_certificate 6066 Y -)], 44 => [qw( certificate_revoked 6066 Y -)], 45 => [qw( certificate_expired 6066 Y -)], 46 => [qw( certificate_unknown 6066 Y -)], 47 => [qw( illegal_parameter 6066 Y -)], 48 => [qw( unknown_ca 6066 Y -)], 49 => [qw( access_denied 6066 Y -)], 50 => [qw( decode_error 6066 Y -)], 51 => [qw( decrypt_error 6066 Y -)], 60 => [qw( export_restriction_RESERVED 6066 Y -)], 70 => [qw( protocol_version 6066 Y -)], 71 => [qw( insufficient_security 6066 Y -)], 80 => [qw( internal_error 6066 Y -)], 86 => [qw( inappropriate_fallback RFC5246_update-Draft-2014-05-31 Y -)], # added according 'https://datatracker.ietf.org/doc/draft-bmoeller-tls-downgrade-scsv/?include_text=1' 90 => [qw( user_canceled 6066 Y -)], 100 => [qw( no_renegotiation 6066 Y -)], 109 => [qw( missing_extension 8446 Y -)], 110 => [qw( unsupported_extension 6066 Y -)], 111 => [qw( certificate_unobtainable 6066 Y -)], 112 => [qw( unrecognized_name 6066 Y -)], 113 => [qw( bad_certificate_status_response 6066 Y -)], 114 => [qw( bad_certificate_hash_value 6066 Y -)], 115 => [qw( unknown_psk_identity 4279 Y -)], 116 => [qw( certificate_required 8446 Y -)], 120 => [qw( no_application_protocol 7301 Y -)], #----+-------------------------------------+----+--+--------------- ); # %tls_error_alerts our %tls_extensions = ( # RFC 6066, 8446, ... #----+-----------------------------+----+---+------------------------------ # ID name RFC DTLS other names #----+-----------------------------+----+---+------------------------------ 0 => [qw( server_name 4366 - )], # also 6066 1 => [qw( max_fragment_length 6066 - )], 2 => [qw( client_certificate_url ???? - )], 3 => [qw( trusted_ca_keys ???? - )], 4 => [qw( truncated_hmac ???? - )], 5 => [qw( status_request 6066 - )], 6 => [qw( user_mapping ???? - )], 7 => [qw( reserved_7 ???? - )], 8 => [qw( reserved_8 ???? - )], 9 => [qw( cert_type 5081 - )], # also 6091 10 => [qw( supported_groups 8422 - )], # also 7919 # 10 => [qw( ecliptic_curves 4492 - )], # TODO: old name (see above)? 11 => [qw( ec_point_formats 4492 - )], 12 => [qw( srp 5054 - )], 13 => [qw( signature_algorithms 8446 - )], 14 => [qw( use_srp 5764 - )], 15 => [qw( heartbeat 6520 - )], 16 => [qw( application_layer_protocol_negotiation 7301 - )], 18 => [qw( signed_certificate_timestamp 6962 - )], 19 => [qw( client_certificate_type 7250 - )], 20 => [qw( server_certificate_type 7250 - )], 21 => [qw( padding 7685 - )], # 34 => [qw( unassigned 5246 - )], 35 => [qw( SessionTicket 4507 - )], 40 => [qw( RESERVERD_40 ???? - )], 41 => [qw( pre_shared_key 8446 - )], 42 => [qw( early_data 8446 - )], 43 => [qw( supported_versions 8446 - )], 44 => [qw( cookie 8446 - )], 45 => [qw( psk_key_exchange_modes 8446 - )], 46 => [qw( RESERVERD_46 ???? - )], # ... 47 => [qw( certificate_authorities 8446 - )], 48 => [qw( oid_filters 8446 - )], 49 => [qw( post_handshake_auth 8446 - )], 50 => [qw( signature_algorithms_cert 8446 - )], 51 => [qw( key_share 8446 - )], 62208 => [qw( TACK ???? - )], 65535 => [qw( 65535 ???? - )], ); # %tls_extensions my %tls_extensions__text = ( # TODO: this information needs to be added to %tls_extensions above 'extension' => { # TLS extensions '00000' => "renegotiation info length", # 0x0000 ?? '00001' => "renegotiation length", # 0x0001 ?? '00009' => "cert type", # 0x0009 ?? '00010' => "elliptic curves", # 0x000a length=4 '00011' => "EC point formats", # 0x000b length=2 '00012' => "SRP", # 0x000c ?? '00015' => "heartbeat", # 0x000f length=1 '00035' => "session ticket", # 0x0023 length=0 '13172' => "next protocol", # aka NPN # 0x3374 length=NNN '62208' => "TACK", # 0xf300 ?? '65281' => "renegotiation info", # 0xff01 length=1 }, ); # %tls_extensions__text our %tls_signature_algorithms = ( #----+--------------------------+----------------------- # ID name comment #----+--------------------------+----------------------- # Legacy algorithms 0x0201 => "rsa_pkcs1_sha1", 0x0203 => "ecdsa_sha1", # RSASSA-PKCS1-v1_5 algorithms 0x0401 => "rsa_pkcs1_sha256", 0x0501 => "rsa_pkcs1_sha384", 0x0601 => "rsa_pkcs1_sha512", # ECDSA algorithms 0x0403 => "ecdsa_secp256r1_sha256", 0x0503 => "ecdsa_secp384r1_sha384", 0x0603 => "ecdsa_secp521r1_sha512", # RSASSA-PSS algorithms with public key OID rsaEncryption 0x0804 => "rsa_pss_rsae_sha256", 0x0805 => "rsa_pss_rsae_sha384", 0x0806 => "rsa_pss_rsae_sha512", # EdDSA algorithms 0x0807 => "ed25519", 0x0808 => "ed448", # RSASSA-PSS algorithms with public key OID RSASSA-PSS 0x0809 => "rsa_pss_pss_sha256", 0x080a => "rsa_pss_pss_sha384", 0x080b => "rsa_pss_pss_sha512", # Reserved Code Points #0x0000..0x0200 => "obsolete_RESERVED", 0x0202 => "dsa_sha1_RESERVED", #0x0204..0x0400 => "obsolete_RESERVED", 0x0402 => "dsa_sha256_RESERVED", #0x0404..0x0500 => "obsolete_RESERVED", 0x0502 => "dsa_sha384_RESERVED", #0x0504..0x0600 => "obsolete_RESERVED", 0x0602 => "dsa_sha512_RESERVED", #0x0604..0x06FF => "obsolete_RESERVED", #0xFE00..0xFFFF => "private_use", 0xFFFF => "private_use", #----+--------------------------+----------------------- ); # %tls_signature_algorithms our %tls_supported_groups = ( # RFC 8446 #----+--------------------------+----------------------- 0x0001 => "obsolete_RESERVED", # 0x0001..0x0016 => "obsolete_RESERVED", 0x0017 => "secp256r1", # Elliptic Curve Groups (ECDHE) 0x0018 => "secp384r1", # 0x0019 => "secp521r1", # 0x001A => "obsolete_RESERVED", #0x001A..0x001C => "obsolete_RESERVED", 0x001D => "x25519", # 0x001E => "x448", # 0x0100 => "ffdhe2048", # Finite Field Groups (DHE) 0x0101 => "ffdhe3072", # 0x0102 => "ffdhe4096", # 0x0103 => "ffdhe6144", # 0x0104 => "ffdhe8192", # # Reserved Code Points 0x01FC => "ffdhe_private_use", # 0x01FC..0x01FF => "ffdhe_private_use", 0xFE00 => "ecdhe_private_use", # 0xFE00..0xFEFF => "ecdhe_private_use", 0xFF01 => "obsolete_RESERVED_ff01", 0xFF02 => "obsolete_RESERVED_ff02", 0xFFFF => "FFFF", #----+--------------------------+----------------------- ); # %tls_supported_groups our %ec_point_formats = ( # RFC 4492 # http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 #----+-----------------------------+----+---+------------------------------ # ID name RFC DTLS other names #----+-----------------------------+----+---+------------------------------ 0 => [qw( uncompressed 4492 Y )], 1 => [qw( ansiX962_compressed_prime 4492 Y )], 2 => [qw( ansiX962_compressed_char2 4492 Y )], 248 => [qw( reserved_248 4492 N )], 249 => [qw( reserved_249 4492 N )], 250 => [qw( reserved_250 4492 N )], 251 => [qw( reserved_251 4492 N )], 252 => [qw( reserved_252 4492 N )], 253 => [qw( reserved_253 4492 N )], 254 => [qw( reserved_254 4492 N )], 255 => [qw( reserved_255 4492 N )], #----+-----------------------------+----+---+------------------------------ ); # ec_point_formats # Torsten: %ECCURVE_TYPE our %ec_curve_types = ( # RFC 4492 # http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 #----+-----------------------------+----+---+------------------------------ # ID name RFC DTLS other names #----+-----------------------------+----+---+------------------------------ 0 => [qw( unassigned 4492 N )], 1 => [qw( explicit_prime 4492 Y )], 2 => [qw( explicit_char2 4492 Y )], 3 => [qw( named_curve 4492 Y )], 248 => [qw( reserved_248 4492 N )], 249 => [qw( reserved_249 4492 N )], 250 => [qw( reserved_250 4492 N )], 251 => [qw( reserved_251 4492 N )], 252 => [qw( reserved_252 4492 N )], 253 => [qw( reserved_253 4492 N )], 254 => [qw( reserved_254 4492 N )], 255 => [qw( reserved_255 4492 N )], #----+-----------------------------+----+---+------------------------------ ); # ec_curve_types # Torsten: %ECC_NAMED_CURVE = # http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10 # Value => Description bits(added) DTLS-OK Reference # our %named_curves = our %tls_curves = ( # TODO: merge with %tls_signature_algorithms and %tls_supported_groups # http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 #----+-------------------------------------+----+--+-------+---+------------------------- # ID name RFC DTLS NIST bits OID #----+-------------------------------------+----+--+-------+---+------------------------ 0 => [qw( unassigned IANA - - 0 )], 1 => [qw( sect163k1 4492 Y K-163 163 1.3.132.0.1 )], 2 => [qw( sect163r1 4492 Y - 163 1.3.132.0.2 )], 3 => [qw( sect163r2 4492 Y B-163 163 1.3.132.0.15 )], 4 => [qw( sect193r1 4492 Y - 193 1.3.132.0.24 )], 5 => [qw( sect193r2 4492 Y - 193 1.3.132.0.25 )], 6 => [qw( sect233k1 4492 Y K-233 233 1.3.132.0.26 )], 7 => [qw( sect233r1 4492 Y B-233 233 1.3.132.0.27 )], 8 => [qw( sect239k1 4492 Y - 239 1.3.132.0.3 )], 9 => [qw( sect283k1 4492 Y K-283 283 1.3.132.0.16 )], 10 => [qw( sect283r1 4492 Y B-283 283 1.3.132.0.17 )], 11 => [qw( sect409k1 4492 Y K-409 409 1.3.132.0.36 )], 12 => [qw( sect409r1 4492 Y B-409 409 1.3.132.0.37 )], 13 => [qw( sect571k1 4492 Y K-571 571 1.3.132.0.38 )], 14 => [qw( sect571r1 4492 Y B-571 571 1.3.132.0.39 )], 15 => [qw( secp160k1 4492 Y - 160 1.3.132.0.9 )], 16 => [qw( secp160r1 4492 Y - 160 1.3.132.0.8 )], 17 => [qw( secp160r2 4492 Y - 160 1.3.132.0.30 )], 18 => [qw( secp192k1 4492 Y - 192 1.3.132.0.31 )], # ANSI X9.62 prime192v1, NIST P-192, 19 => [qw( secp192r1 4492 Y P-192 192 1.2.840.10045.3.1.1 )], # ANSI X9.62 prime192v1 20 => [qw( secp224k1 4492 Y - 224 1.3.132.0.32 )], 21 => [qw( secp224r1 4492 Y P-224 224 1.3.132.0.33 )], 22 => [qw( secp256k1 4492 Y P-256 256 1.3.132.0.10 )], 23 => [qw( secp256r1 4492 Y P-256 256 1.2.840.10045.3.1.7 )], # ANSI X9.62 prime256v1 24 => [qw( secp384r1 4492 Y P-384 384 1.3.132.0.34 )], 25 => [qw( secp521r1 4492 Y P-521 521 1.3.132.0.35 )], 26 => [qw( brainpoolP256r1 7027 Y - 256 1.3.36.3.3.2.8.1.1.7 )], 27 => [qw( brainpoolP384r1 7027 Y - 384 1.3.36.3.3.2.8.1.1.11)], 28 => [qw( brainpoolP512r1 7027 Y - 512 1.3.36.3.3.2.8.1.1.13)], # 28 => [qw( brainpoolP521r1 7027 Y - 521 1.3.36.3.3.2.8.1.1.13)], # ACHTUNG: in manchen Beschreibungen dieser falsche String 29 => [qw( ecdh_x25519 4492bis Y - 225 )], # [draft-ietf-tls-tls][draft-ietf-tls-rfc4492bis])], #TEMPORARY-registered_2016-02-29,_expires 2017-03-01, 30 => [qw( ecdh_x448 4492bis Y - 448 )], # -"- # 31 => [qw( eddsa_ed25519 4492bis Y - 448 1.3.101.100 )], # Signature curves, see https://tools.ietf.org/html/draft-ietf-tls-tls13-11 # 32 => [qw( eddsa_ed448 4492bis Y - 448 1.3.101.101 )], # -"- 256 => [qw( ffdhe2048 ietf-tls-negotiated-ff-dhe-10 Y - 2048 )], 257 => [qw( ffdhe3072 ietf-tls-negotiated-ff-dhe-10 Y - 3072 )], 258 => [qw( ffdhe4096 ietf-tls-negotiated-ff-dhe-10 Y - 4096 )], 259 => [qw( ffdhe6144 ietf-tls-negotiated-ff-dhe-10 Y - 6144 )], 260 => [qw( ffdhe8192 ietf-tls-negotiated-ff-dhe-10 Y - 8192 )], 65281 => [qw( arbitrary_explicit_prime_curves 4492 Y - ? )], # 0xFF01 65282 => [qw( arbitrary_explicit_char2_curves 4492 Y - ? )], # 0xFF02 #----+-------------------------------------+----+--+-------+---+------------------------ # following not from IANA # ID name RFC DTLS NIST bits OID #----+-------------------------------------+----+--+-------+---+------------------------ 42001 => [qw( Curve3617 ???? N - -1 )], 42002 => [qw( secp112r1 ???? N - -1 1.3.132.0.6 )], 42003 => [qw( secp112r2 ???? N - -1 1.3.132.0.7 )], 42004 => [qw( secp113r1 ???? N - -1 1.3.132.0.4 )], 42005 => [qw( secp113r2 ???? N - -1 1.3.132.0.5 )], 42006 => [qw( secp131r1 ???? N - -1 1.3.132.0.22 )], 42007 => [qw( secp131r2 ???? N - -1 1.3.132.0.23 )], 42008 => [qw( secp128r1 ???? N - -1 1.3.132.0.28 )], 42009 => [qw( secp128r2 ???? N - -1 1.3.132.0.29 )], 42011 => [qw( ed25519 ???? N Ed25519 -1 1.3.6.1.4.1.11591.15.1)], # PGP 42012 => [qw( brainpoolp160r1 ???? N - -1 1.3.36.3.3.2.8.1.1.1 )], 42013 => [qw( brainpoolp192r1 ???? N - -1 1.3.36.3.3.2.8.1.1.3 )], 42014 => [qw( brainpoolp224r1 ???? N - -1 1.3.36.3.3.2.8.1.1.5 )], 42015 => [qw( brainpoolp320r1 ???? N - -1 1.3.36.3.3.2.8.1.1.9 )], 42016 => [qw( brainpoolp512r1 ???? N - -1 1.3.36.3.3.2.8.1.1.13)], # same as brainpoolP521r1 42020 => [qw( GOST2001-test ???? N - -1 1.2.643.2.2.35.0 )], 42021 => [qw( GOST2001-CryptoPro-A ???? N - -1 1.2.643.2.2.35.1 )], 42022 => [qw( GOST2001-CryptoPro-B ???? N - -1 1.2.643.2.2.35.2 )], 42023 => [qw( GOST2001-CryptoPro-C ???? N - -1 1.2.643.2.2.35.3 )], 42024 => [qw( GOST2001-CryptoPro-A ???? N - -1 )], # GOST2001-CryptoPro-XchA 42025 => [qw( GOST2001-CryptoPro-C ???? N - -1 )], # GOST2001-CryptoPro-XchB 42026 => [qw( GOST2001-CryptoPro-A ???? N - -1 1.2.643.2.2.36.0 )], 42027 => [qw( GOST2001-CryptoPro-C ???? N - -1 1.2.643.2.2.36.1 )], 42031 => [qw( X9.62 prime192v2 ???? N - -1 1.2.840.10045.3.1.2 )], 42032 => [qw( X9.62 prime192v3 ???? N - -1 1.2.840.10045.3.1.3 )], 42033 => [qw( X9.62 prime239v1 ???? N - -1 1.2.840.10045.3.1.4 )], 42034 => [qw( X9.62 prime239v2 ???? N - -1 1.2.840.10045.3.1.5 )], 42035 => [qw( X9.62 prime239v3 ???? N - -1 1.2.840.10045.3.1.6 )], 42041 => [qw( X9.62 c2tnb191v1 ???? N - -1 1.2.840.10045.3.0.5 )], 42042 => [qw( X9.62 c2tnb191v2 ???? N - -1 1.2.840.10045.3.0.6 )], 42043 => [qw( X9.62 c2tnb191v3 ???? N - -1 1.2.840.10045.3.0.7 )], 42044 => [qw( X9.62 c2tnb239v1 ???? N - -1 1.2.840.10045.3.0.11 )], 42045 => [qw( X9.62 c2tnb239v2 ???? N - -1 1.2.840.10045.3.0.12 )], 42046 => [qw( X9.62 c2tnb239v3 ???? N - -1 1.2.840.10045.3.0.13 )], 42047 => [qw( X9.62 c2tnb359v1 ???? N - -1 1.2.840.10045.3.0.18 )], 42048 => [qw( X9.62 c2tnb431r1 ???? N - -1 1.2.840.10045.3.0.20 )], # fobidden curves 42061 => [qw( X9.62 c2pnb163v1 ???? N - -1 1.2.840.10045.3.0.1 )], 42062 => [qw( X9.62 c2pnb163v2 ???? N - -1 1.2.840.10045.3.0.2 )], 42063 => [qw( X9.62 c2pnb163v3 ???? N - -1 1.2.840.10045.3.0.3 )], 42064 => [qw( X9.62 c2pnb176w1 ???? N - -1 1.2.840.10045.3.0.4 )], 42065 => [qw( X9.62 c2pnb208w1 ???? N - -1 1.2.840.10045.3.0.10 )], 42066 => [qw( X9.62 c2pnb272w1 ???? N - -1 1.2.840.10045.3.0.16 )], 42067 => [qw( X9.62 c2pnb304w1 ???? N - -1 1.2.840.10045.3.0.18 )], 42068 => [qw( X9.62 c2pnb368w1 ???? N - -1 1.2.840.10045.3.0.19 )], # unknown curves 42101 => [qw( prime192v1 ???? N - 92 )], # X9.62/SECG curve over a 192 bit prime field 42101 => [qw( prime192v2 ???? N - 92 )], # X9.62 curve over a 192 bit prime field 42101 => [qw( prime192v3 ???? N - 92 )], # X9.62 curve over a 192 bit prime field 42101 => [qw( prime239v1 ???? N - 39 )], # X9.62 curve over a 239 bit prime field 42101 => [qw( prime239v2 ???? N - 39 )], # X9.62 curve over a 239 bit prime field 42101 => [qw( prime239v3 ???? N - 39 )], # X9.62 curve over a 239 bit prime field 42101 => [qw( prime256v1 ???? N - 56 )], # X9.62/SECG curve over a 256 bit prime field 42101 => [qw( wap-wsg-idm-ecid-wtls1 ???? N - 113 )], # WTLS curve over a 113 bit binary field 42101 => [qw( wap-wsg-idm-ecid-wtls3 ???? N - 163 )], # NIST/SECG/WTLS curve over a 163 bit binary field 42101 => [qw( wap-wsg-idm-ecid-wtls4 ???? N - 112 )], # SECG curve over a 113 bit binary field 42101 => [qw( wap-wsg-idm-ecid-wtls5 ???? N - 163 )], # X9.62 curve over a 163 bit binary field 42101 => [qw( wap-wsg-idm-ecid-wtls6 ???? N - 112 )], # SECG/WTLS curve over a 112 bit prime field 42101 => [qw( wap-wsg-idm-ecid-wtls7 ???? N - 160 )], # SECG/WTLS curve over a 160 bit prime field 42101 => [qw( wap-wsg-idm-ecid-wtls8 ???? N - 112 )], # WTLS curve over a 112 bit prime field 42101 => [qw( wap-wsg-idm-ecid-wtls9 ???? N - 160 )], # WTLS curve over a 160 bit prime field 42101 => [qw( wap-wsg-idm-ecid-wtls10 ???? N - 233 )], # NIST/SECG/WTLS curve over a 233 bit binary field 42101 => [qw( wap-wsg-idm-ecid-wtls11 ???? N - 233 )], # NIST/SECG/WTLS curve over a 233 bit binary field 42101 => [qw( wap-wsg-idm-ecid-wtls12 ???? N - 224 )], # WTLS curvs over a 224 bit prime field 42101 => [qw( Oakley-EC2N-3 ???? N - 55 )], # IPSec/IKE/Oakley curve #3 over a 155 bit binary field. 42101 => [qw( Oakley-EC2N-4 ???? N - 85 )], # IPSec/IKE/Oakley curve #4 over a 185 bit binary field #----+-------------------------------------+----+--+-------+---+------------------------ # unknown curves 41147 => [qw( Curve1147 ???? N - -1 )], # http://www..wikipedia.org/wiki/Comparison_of_TLS_implementations 41187 => [qw( Curve511157 ???? N - -1 )], # -"- ; aka M511 41417 => [qw( Curve41417 ???? N - -1 )], # -"- ; aka Curve3617 42213 => [qw( Curve2213 ???? N - -1 )], # -"- ; aka M221 42448 => [qw( Curve448 ???? N - -1 )], # -"- ; aka Ed448-Goldilocks, aka ecdh_x448? 42519 => [qw( X25519 ???? N - -1 )], # -"- ; aka ecdh_x25519? 42222 => [qw( E222 ???? N - -1 )], # -"- 42382 => [qw( E382 ???? N - -1 )], # -"- 42383 => [qw( E383 ???? N - -1 )], # -"- 42521 => [qw( E521 ???? N - -1 )], # -"- 42147 => [qw( GOST28147-89 ???? N - -1 )], # -"- 42147 => [qw( GOST-R34.11-94 ???? N - -1 )], # -"- #----+-------------------------------------+----+--+-------+---+------------------------ 65165 => [qw( CurveCECPQ1 ???? N - -1 )], # -"- ; # unknown curves # => [qw( numsp256d1 )], # => [qw( numsp256t1 )], # => [qw( Curve25519 )], ); # %tls_curves ################ # FIPS-186-2 FIPS-186-3 # # Aliases: P-256 -- NIST P-256 -- NIST-P256 -- NIST-256 -- secp256r1 -- prime256v1 # # order_for_NIST_curves_by_ID = 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14 ################ our %data_oid = ( # TODO: nothing YET IMPLEMENTED except for EV # TODO: generate this table using Net::SSLeay functions like: # Net::SSLeay::OBJ_nid2ln(), Net::SSLeay::OBJ_ln2nid() # Net::SSLeay::OBJ_nid2sn(), Net::SSLeay::OBJ_sn2nid(), # Net::SSLeay::OBJ_nid2obj(), Net::SSLeay::OBJ_obj2nid(), # Net::SSLeay::OBJ_txt2obj(), Net::SSLeay::OBJ_txt2nid(), # Net::SSLeay::OBJ_obj2txt(), # all constants and values are defined in openssl/crypto/objects/obj_dat.h # print "nid ". Net::SSLeay::OBJ_txt2nid("CN"); # --> 13 # print "Nam ". Net::SSLeay::OBJ_obj2txt( Net::SSLeay::OBJ_txt2obj("1.3.6.1.5.5.7.3.3"), 0); # --> Code Signing # print "nam ". Net::SSLeay::OBJ_obj2txt( Net::SSLeay::OBJ_txt2obj("CN"), 0); # --> commonName # print "oid ". Net::SSLeay::OBJ_obj2txt( Net::SSLeay::OBJ_txt2obj("CN"), 1); # --> 2.5.4.3 # print "OID ". Net::SSLeay::OBJ_obj2txt( Net::SSLeay::OBJ_nid2obj( 13 ), 1); # --> 2.5.4.3 # we should use NIDs to generate the hash, as all other strings are # case sensitive. get NIDs with: # grep NID_ openssl/crypto/objects/objects.h | awk '{print $3}' | sort -n # so we can loop from 0..180 (or 300 if checks are possible) # see also: http://www.zytrax.com/books/ldap/apa/oid.html # # wir koennen dann einen Parser fuer OIDs bauen: # loop ueber OID und dabei immer .N vom Ende wegnehmen und Rest mit OBJ_obj2txt() ausgeben # # 1.3.6.1.4 --> "" . identified-organization . dot . iana . Private # # 2.5.29.32 --> "" . directory services (X.500) . id-ce . X509v3 Certificate Policies # '1.3.6.1' => {iso(1) org(3) dod(6) iana(1)} '1.3.6.1' => {'txt' => "Internet OID"}, # '1.3.6.1.5.5.7.1' => {'txt' => "Private Extensions"}, '1.3.6.1.5.5.7.1.1' => {'txt' => "Authority Information Access"}, # authorityInfoAccess '1.3.6.1.5.5.7.1.12' => {'txt' => STR_UNDEF}, '1.3.6.1.5.5.7.1.14' => {'txt' => "Proxy Certification Information"}, '1.3.6.1.5.5.7.1.24' => {'txt' => "id-pe-tlsfeature"}, '1.3.6.1.5.5.7.3.1' => {'txt' => "Server Authentication"}, '1.3.6.1.5.5.7.3.2' => {'txt' => "Client Authentication"}, '1.3.6.1.5.5.7.3.3' => {'txt' => "Code Signing"}, '1.3.6.1.5.5.7.3.4' => {'txt' => "Email Protection"}, '1.3.6.1.5.5.7.3.5' => {'txt' => "IPSec end system"}, '1.3.6.1.5.5.7.3.6' => {'txt' => "IPSec tunnel"}, '1.3.6.1.5.5.7.3.7' => {'txt' => "IPSec user"}, '1.3.6.1.5.5.7.3.8' => {'txt' => "Timestamping"}, '1.3.6.1.5.5.7.48.1' => {'txt' => "ocsp"}, '1.3.6.1.5.5.7.48.2' => {'txt' => "caIssuer"}, '1.3.6.1.4.1.11129.2.5.1' => {'txt' => STR_UNDEF}, # Certificate Policy? '1.3.6.1.4.1.14370.1.6' => {'txt' => STR_UNDEF}, # Certificate Policy? '1.3.6.1.4.1.311.10.3.3' => {'txt' => "Microsoft Server Gated Crypto"}, '1.3.6.1.4.1.311.10.11' => {'txt' => "Microsoft Server: EV additional Attributes"}, '1.3.6.1.4.1.311.10.11.11' => {'txt' => "Microsoft Server: EV ??friendly name??"}, '1.3.6.1.4.1.311.10.11.83' => {'txt' => "Microsoft Server: EV ??root program??"}, '1.3.6.1.4.1.4146.1.10' => {'txt' => STR_UNDEF}, # Certificate Policy? '1.3.6.1.5.5.7.8.7' => {'txt' => "otherName"}, '2.16.840.1.113730.4.1' => {'txt' => "Netscape SGC"}, '1.2.840.113549.1.1.1' => {'txt' => "SubjectPublicKeyInfo"}, # ??? '1.2.840.113549.1.1.5' => {'txt' => "SignatureAlgorithm"}, # '2.5.29' => {'txt' => "Standard Extensions according RFC 5280"}, # EV: OIDs used in EV Certificates '2.5.4.10' => {'txt' => "EV Certificate: subject:organizationName"}, '2.5.4.11' => {'txt' => "EV Certificate: subject:organizationalUnitName"}, '2.5.4.15' => {'txt' => "EV Certificate: subject:businessCategory"}, '2.5.4.3' => {'txt' => "EV Certificate: subject:commonName"}, # or SubjectAlternativeName:dNSName # EV: Jurisdiction of Incorporation or Registration '1.3.6.1.4.1.311.60.2.1.1' => {'txt' => "EV Certificate: subject:jurisdictionOfIncorporationLocalityName"}, '1.3.6.1.4.1.311.60.2.1.2' => {'txt' => "EV Certificate: subject:jurisdictionOfIncorporationStateOrProvinceName"}, '1.3.6.1.4.1.311.60.2.1.3' => {'txt' => "EV Certificate: subject:jurisdictionOfIncorporationCountryName"}, '2.5.4.5' => {'txt' => "EV Certificate: subject:serialNumber"}, # EV: Physical Address of Place of Business '2.5.4.6' => {'txt' => "EV Certificate: subject:countryName"}, '2.5.4.7' => {'txt' => "EV Certificate: subject:localityName"}, '2.5.4.8' => {'txt' => "EV Certificate: subject:stateOrProvinceName"}, '2.5.4.9' => {'txt' => "EV Certificate: subject:streetAddress"}, '2.5.4.17' => {'txt' => "EV Certificate: subject:postalCode"}, # EV: Compliance with European Union Qualified Certificates Standard In addition, RFC 3739 '1.3.6.1.4.1.311.60.2.1' => {'txt' => "EV Certificate: qcStatements:qcStatement:statementId"}, # EV: others '1.3.6.1.4.1.311.60.1.1' => {'txt' => "EV Certificate: ??fake root??"}, '2.5.29.32.0' => {'txt' => "EV Certificate: subject:anyPolicy"}, '2.5.29.35' => {'txt' => "EV Certificate: subject:authorityKeyIdentifier"}, # Authority key id '2.5.29.37' => {'txt' => "EV Certificate: subject:extendedKeyUsage"}, # Extended key usage '0.9.2342.19200300.100.1.25'=> {'txt' => "EV Certificate: subject:domainComponent"}, # others '2.5.4.4' => {'txt' => "subject:surname"}, '2.5.4.12' => {'txt' => "subject:title"}, '2.5.4.41' => {'txt' => "subject:name"}, '2.5.4.42' => {'txt' => "subject:givenName"}, '2.5.4.43' => {'txt' => "subject:intials"}, '2.5.4.44' => {'txt' => "subject:generationQualifier"}, '2.5.4.46' => {'txt' => "subject:dnQualifier"}, '2.5.29.14' => {'txt' => "subject:subjectKeyIdentifier"}, # Subject key id '2.5.29.15' => {'txt' => "subject:keyUsage"}, # Key usage '2.5.29.17' => {'txt' => "subject:subjectAlternateName"}, # Subject alternative name '2.5.29.19' => {'txt' => "subject:basicConstraints"}, # Basic constraints '2.5.29.31' => {'txt' => "subject:crlDistributionPoints"},# CRL distribution points '2.5.29.32' => {'txt' => "subject:certificatePolicies"}, # Certificate Policies '2.5.29.37' => {'txt' => "subject:extendedKeyUsage"}, # Extended key usage '2.16.840.1.113733.1.7.23.6'=> {'txt' => STR_UNDEF}, # Certificate Policy? '2.16.840.1.113733.1.7.48.1'=> {'txt' => STR_UNDEF}, # '' '2.16.840.1.113733.1.7.54' => {'txt' => STR_UNDEF}, # '' '0.9.2342.19200300.100.1.3' => {'txt' => "subject:mail"}, # TODO: see http://oidref.com/ #'2.16.840.1.114028.10.1.2' => {'txt' => "Entrust Extended Validation (EV) Certification Practice Statement (CPS)"}, #'2.16.840.1.114412.1.3.0.2' => {'txt' => "DigiCert Extended Validation (EV) Certification Practice Statement (CPS) v. 1.0.3"}, #'2.16.840.1.114412.2.1' => {'txt' => "DigiCert Extended Validation (EV) Certification Practice Statement (CPS) v. 1.0.3"}, #'2.16.578.1.26.1.3.3' => {'txt' => ""}, #'1.3.6.1.4.1.17326.10.14.2.1.2' => {'txt' => "Camerfirma Certification Practice Statement (CPS) v3.2.3"}, #'1.3.6.1.4.1.17326.10.8.12.1.2' => {'txt' => "Camerfirma Certification Practice Statement (CPS) v3.2.3"}, #'1.3.6.1.4.1.13177.10.1.3.10' => {'txt' => "SSL SECURE WEB SERVER CERTIFICATES"}, ); # %data_oid our %ciphers_desc = ( # description of following %ciphers table 'head' => [qw( sec ssl enc bits mac auth keyx score tags)], # abbreviations used by openssl: # SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2 # Kx= key exchange (DH is diffie-hellman) # Au= authentication # Enc= encryption with bit size # Mac= mac encryption algorithm 'text' => [ # full description of each column in 'ciphers' below 'Security', # LOW, MEDIUM, HIGH as reported by openssl 0.9.8 .. 1.0.1h # WEAK as reported by openssl 0.9.8 as EXPORT # weak unqualified by openssl or know vulnerable # NOTE: weak includes NONE (no security at all) # # all following informations as reported by openssl 0.9.8 .. 1.0.1h 'SSL/TLS', # Protocol Version: # SSLv2, SSLv3, TLSv1, TLSv11, TLSv12, TLSv13, DTLS0.9, DTLS1.0, PCT # NOTE: all SSLv3 are also TLSv1, TLSv11, TLSv12 # (cross-checked with sslaudit.ini) 'Encryption Algorithm', # None, AES, AESCCM, AESGCM, CAMELLIA, DES, 3DES, FZA, IDEA, RC4, RC2, SEED, GOST89 'Key Size', # in bits 'MAC Algorithm', # MD5, SHA1, SHA256, SHA384, AEAD, GOST89, GOST94 'Authentication', # None, DSS, RSA, ECDH, ECDSA, KRB5, PSK, GOST01, GOST94 'Key Exchange', # DH, ECDH, ECDH/ECDSA, RSA, KRB5, PSK, SRP, GOST # last column is a : separated list (only export from openssl) # different versions of openssl report ECDH or ECDH/ECDSA 'score', # score value as defined in sslaudit.ini (0, 20, 80, 100) # additionally following sores are used: # 10: have been 100 in sslaudit.ini (HIGH in openssl) # 8: have been 80 in sslaudit.ini (MDIUM in openssl) # 3: (LOW in openssl) # 2: have been 20 in sslaudit.ini # 1: assumed weak security # 11: unknown, assumed weak security # 81: unknown, assumed MEDIUM security # 91: unknown, assumed HIGH security # 0: all anon and NULL and <56 bit ciphers dispite above settings 'tags', # export as reported by openssl 0.9.8 .. 1.0.1h # OSX on Mac OS X only # : (colon) is empty marker (need for other tools ], ); # %ciphers_desc our %ciphers = ( #-----------------------------+------+-----+----+----+----+-----+--------+----+--------, # hex,hex => [qw( sec ssl enc bits mac auth keyx score tags)], #-----------------------------+------+-----+----+----+----+-----+--------+----+--------, # ... ); # %ciphers our %cipher_names = ( ### Achtung: die hex-Wert sind intern, davon sind nur die letzten 4 oder 6 ### Stellen (je nach Protokoll) der eigentliche Wert. # NOTE: cipher suite name beginning with "-OLD" usually will never work (i.e. # with openssl), as the cipher suite name is without this suffix -OLD # This does not matter when we work with the cipher suite name instead # of the corresponding hex keys, unless the underlaying openssl or libssl # uses these cipher suite names with suffix -OLD too. # #!#----------+-------------------------------------+--------------------------+ #!# constant => cipher suite name # cipher suite value #!#----------+-------------------------------------+--------------------------+ # SSL2 ciphers? # missing SSL_CK_ prefix '0x02010080' => [qw(RC4-MD5 RC4_128_WITH_MD5)], '0x02020080' => [qw(EXP-RC4-MD5 RC4_128_EXPORT40_WITH_MD5)], '0x02030080' => [qw(RC2-CBC-MD5 RC2_128_CBC_WITH_MD5)], '0x02040080' => [qw(EXP-RC2-CBC-MD5 RC2_128_CBC_EXPORT40_WITH_MD5)], '0x02050080' => [qw(IDEA-CBC-MD5 IDEA_128_CBC_WITH_MD5)], '0x02060040' => [qw(DES-CBC-MD5 DES_64_CBC_WITH_MD5)], '0x02060140' => [qw(DES-CBC-SHA DES_64_CBC_WITH_SHA)], '0x020700C0' => [qw(DES-CBC3-MD5 DES_192_EDE3_CBC_WITH_MD5)], '0x020701C0' => [qw(DES-CBC3-SHA DES_192_EDE3_CBC_WITH_SHA)], '0x02080080' => [qw(RC4-64-MD5 RC4_64_WITH_MD5)], '0x02FF0800' => [qw(DES-CFB-M1 DES_64_CFB64_WITH_MD5_1)], '0x02FF0810' => [qw(NULL NULL)], # '0x03000019' => [qw(EXP-ADH-DES-CBC-SHA ADH_DES_40_CBC_SHA)], '0x0300001A' => [qw(ADH-DES-CBC-SHA ADH_DES_64_CBC_SHA)], '0x0300001B' => [qw(ADH-DES-CBC3-SHA ADH_DES_192_CBC_SHA)], '0x03000017' => [qw(EXP-ADH-RC4-MD5 ADH_RC4_40_MD5)], '0x03000018' => [qw(ADH-RC4-MD5 ADH_RC4_128_MD5)], '0x030000A6' => [qw(ADH-AES128-GCM-SHA256 ADH_WITH_AES_128_GCM_SHA256)], '0x03000034' => [qw(ADH-AES128-SHA ADH_WITH_AES_128_SHA)], '0x0300006C' => [qw(ADH-AES128-SHA256 ADH_WITH_AES_128_SHA256)], '0x030000A7' => [qw(ADH-AES256-GCM-SHA384 ADH_WITH_AES_256_GCM_SHA384)], '0x030000A8' => [qw(PSK-AES128-GCM-SHA256 PSK_WITH_AES_128_GCM_SHA256)], '0x030000A8' => [qw(PSK-AES256-GCM-SHA384 PSK_WITH_AES_256_GCM_SHA384)], '0x0300003A' => [qw(ADH-AES256-SHA ADH_WITH_AES_256_SHA)], '0x0300006D' => [qw(ADH-AES256-SHA256 ADH_WITH_AES_256_SHA256)], '0x03000046' => [qw(ADH-CAMELLIA128-SHA ADH_WITH_CAMELLIA_128_CBC_SHA)], '0x03000089' => [qw(ADH-CAMELLIA256-SHA ADH_WITH_CAMELLIA_256_CBC_SHA)], '0x030000BF' => [qw(ADH-CAMELLIA128-SHA256 ADH_WITH_CAMELLIA_128_CBC_SHA256)], '0x030000C5' => [qw(ADH-CAMELLIA256-SHA256 ADH_WITH_CAMELLIA_256_CBC_SHA256)], '0x0300009B' => [qw(ADH-SEED-SHA ADH_WITH_SEED_SHA)], '0x03000063' => [qw(EXP1024-DHE-DSS-DES-CBC-SHA DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA)], '0x03000065' => [qw(EXP1024-DHE-DSS-RC4-SHA DHE_DSS_EXPORT1024_WITH_RC4_56_SHA)], '0x030000A2' => [qw(DHE-DSS-AES128-GCM-SHA256 DHE_DSS_WITH_AES_128_GCM_SHA256)], '0x03000032' => [qw(DHE-DSS-AES128-SHA DHE_DSS_WITH_AES_128_SHA)], '0x03000040' => [qw(DHE-DSS-AES128-SHA256 DHE_DSS_WITH_AES_128_SHA256)], '0x030000A3' => [qw(DHE-DSS-AES256-GCM-SHA384 DHE_DSS_WITH_AES_256_GCM_SHA384)], '0x03000038' => [qw(DHE-DSS-AES256-SHA DHE_DSS_WITH_AES_256_SHA)], '0x0300006A' => [qw(DHE-DSS-AES256-SHA256 DHE_DSS_WITH_AES_256_SHA256)], '0x03000044' => [qw(DHE-DSS-CAMELLIA128-SHA DHE_DSS_WITH_CAMELLIA_128_CBC_SHA)], '0x03000087' => [qw(DHE-DSS-CAMELLIA256-SHA DHE_DSS_WITH_CAMELLIA_256_CBC_SHA)], '0x030000BD' => [qw(DHE-DSS-CAMELLIA128-SHA256 DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256)], '0x030000C3' => [qw(DHE-DSS-CAMELLIA256-SHA256 DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256)], '0x03000066' => [qw(DHE-DSS-RC4-SHA DHE_DSS_WITH_RC4_128_SHA)], '0x03000099' => [qw(DHE-DSS-SEED-SHA DHE_DSS_WITH_SEED_SHA)], '0x03000033' => [qw(DHE-RSA-AES128-SHA DHE_RSA_WITH_AES_128_SHA)], '0x03000039' => [qw(DHE-RSA-AES256-SHA DHE_RSA_WITH_AES_256_SHA)], '0x03000067' => [qw(DHE-RSA-AES128-SHA256 DHE_RSA_WITH_AES_128_SHA256)], '0x0300006B' => [qw(DHE-RSA-AES256-SHA256 DHE_RSA_WITH_AES_256_SHA256)], '0x0300009E' => [qw(DHE-RSA-AES128-GCM-SHA256 DHE_RSA_WITH_AES_128_GCM_SHA256)], '0x0300009F' => [qw(DHE-RSA-AES256-GCM-SHA384 DHE_RSA_WITH_AES_256_GCM_SHA384)], '0x03000045' => [qw(DHE-RSA-CAMELLIA128-SHA DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)], '0x03000088' => [qw(DHE-RSA-CAMELLIA256-SHA DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)], '0x030000BE' => [qw(DHE-RSA-CAMELLIA128-SHA256 DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256)], '0x030000C4' => [qw(DHE-RSA-CAMELLIA256-SHA256 DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256)], '0x0300CCAA' => [qw(DHE-RSA-CHACHA20-POLY1305-SHA256 DHE_RSA_WITH_CHACHA20_POLY1305_SHA256)], # see Note(c) '0x0300CCAB' => [qw(PSK-CHACHA20-POLY1305-SHA256 PSK_WITH_CHACHA20_POLY1305_SHA256)], '0x0300CCAC' => [qw(ECDHE-PSK-CHACHA20-POLY1305-SHA256 ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256)], '0x0300CCAD' => [qw(DHE-PSK-CHACHA20-POLY1305-SHA256 DHE_PSK_WITH_CHACHA20_POLY1305_SHA256)], '0x0300CCAE' => [qw(RSA-PSK-CHACHA20-POLY1305-SHA256 RSA_PSK_WITH_CHACHA20_POLY1305_SHA256)], '0x0300009A' => [qw(DHE-RSA-SEED-SHA DHE_RSA_WITH_SEED_SHA)], '0x03000042' => [qw(DH-DSS-CAMELLIA128-SHA DH_DSS_WITH_CAMELLIA_128_CBC_SHA)], '0x03000085' => [qw(DH-DSS-CAMELLIA256-SHA DH_DSS_WITH_CAMELLIA_256_CBC_SHA)], '0x030000BB' => [qw(DH-DSS-CAMELLIA128-SHA256 DH_DSS_WITH_CAMELLIA_128_CBC_SHA256)], '0x030000C1' => [qw(DH-DSS-CAMELLIA256-SHA256 DH_DSS_WITH_CAMELLIA_256_CBC_SHA256)], '0x0300000B' => [qw(EXP-DH-DSS-DES-CBC-SHA DH_DSS_DES_40_CBC_SHA)], '0x0300000C' => [qw(DH-DSS-DES-CBC-SHA DH_DSS_DES_64_CBC_SHA)], '0x0300000D' => [qw(DH-DSS-DES-CBC3-SHA DH_DSS_DES_192_CBC3_SHA)], '0x03000030' => [qw(DH-DSS-AES128-SHA DH_DSS_WITH_AES_128_SHA)], '0x03000036' => [qw(DH-DSS-AES256-SHA DH_DSS_WITH_AES_256_SHA)], '0x0300003E' => [qw(DH-DSS-AES128-SHA256 DH_DSS_WITH_AES_128_SHA256)], '0x03000068' => [qw(DH-DSS-AES256-SHA256 DH_DSS_WITH_AES_256_SHA256)], '0x030000A4' => [qw(DH-DSS-AES128-GCM-SHA256 DH_DSS_WITH_AES_128_GCM_SHA256)], '0x030000A5' => [qw(DH-DSS-AES256-GCM-SHA384 DH_DSS_WITH_AES_256_GCM_SHA384)], '0x03000097' => [qw(DH-DSS-SEED-SHA DH_DSS_WITH_SEED_SHA)], '0x03000098' => [qw(DH-RSA-SEED-SHA DH_RSA_WITH_SEED_SHA)], '0x0300000E' => [qw(EXP-DH-RSA-DES-CBC-SHA DH_RSA_DES_40_CBC_SHA)], '0x0300000F' => [qw(DH-RSA-DES-CBC-SHA DH_RSA_DES_64_CBC_SHA)], '0x03000010' => [qw(DH-RSA-DES-CBC3-SHA DH_RSA_DES_192_CBC3_SHA)], '0x03000031' => [qw(DH-RSA-AES128-SHA DH_RSA_WITH_AES_128_SHA)], '0x03000037' => [qw(DH-RSA-AES256-SHA DH_RSA_WITH_AES_256_SHA)], '0x0300003F' => [qw(DH-RSA-AES128-SHA256 DH_RSA_WITH_AES_128_SHA256)], '0x03000069' => [qw(DH-RSA-AES256-SHA256 DH_RSA_WITH_AES_256_SHA256)], '0x030000A0' => [qw(DH-RSA-AES128-GCM-SHA256 DH_RSA_WITH_AES_128_GCM_SHA256)], '0x030000A1' => [qw(DH-RSA-AES256-GCM-SHA384 DH_RSA_WITH_AES_256_GCM_SHA384)], '0x03000043' => [qw(DH-RSA-CAMELLIA128-SHA DH_RSA_WITH_CAMELLIA_128_CBC_SHA)], '0x03000086' => [qw(DH-RSA-CAMELLIA256-SHA DH_RSA_WITH_CAMELLIA_256_CBC_SHA)], '0x030000BC' => [qw(DH-RSA-CAMELLIA128-SHA256 DH_RSA_WITH_CAMELLIA_128_CBC_SHA256)], '0x030000C2' => [qw(DH-RSA-CAMELLIA256-SHA256 DH_RSA_WITH_CAMELLIA_256_CBC_SHA256)], '0x0300C009' => [qw(ECDHE-ECDSA-AES128-SHA ECDHE_ECDSA_WITH_AES_128_CBC_SHA)], '0x0300C02B' => [qw(ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)], '0x0300C023' => [qw(ECDHE-ECDSA-AES128-SHA256 ECDHE_ECDSA_WITH_AES_128_SHA256)], '0x0300C00A' => [qw(ECDHE-ECDSA-AES256-SHA ECDHE_ECDSA_WITH_AES_256_CBC_SHA)], '0x0300C02C' => [qw(ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)], '0x0300C024' => [qw(ECDHE-ECDSA-AES256-SHA384 ECDHE_ECDSA_WITH_AES_256_SHA384)], '0x03000072' => [qw(ECDHE-ECDSA-CAMELLIA128-SHA256 ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256)], '0x03000073' => [qw(ECDHE-ECDSA-CAMELLIA256-SHA384 ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384)], '0x0300CCA9' => [qw(ECDHE-ECDSA-CHACHA20-POLY1305-SHA256 ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256)], # see Note(c) '0x0300C006' => [qw(ECDHE-ECDSA-NULL-SHA ECDHE_ECDSA_WITH_NULL_SHA)], '0x0300C007' => [qw(ECDHE-ECDSA-RC4-SHA ECDHE_ECDSA_WITH_RC4_128_SHA)], '0x0300C008' => [qw(ECDHE-ECDSA-DES-CBC3-SHA ECDHE_ECDSA_WITH_DES_192_CBC3_SHA)], '0x0300C013' => [qw(ECDHE-RSA-AES128-SHA ECDHE_RSA_WITH_AES_128_CBC_SHA)], '0x0300C014' => [qw(ECDHE-RSA-AES256-SHA ECDHE_RSA_WITH_AES_256_CBC_SHA)], '0x0300C027' => [qw(ECDHE-RSA-AES128-SHA256 ECDHE_RSA_WITH_AES_128_SHA256)], '0x0300C028' => [qw(ECDHE-RSA-AES256-SHA384 ECDHE_RSA_WITH_AES_256_SHA384)], '0x0300C02F' => [qw(ECDHE-RSA-AES128-GCM-SHA256 ECDHE_RSA_WITH_AES_128_GCM_SHA256)], '0x0300C030' => [qw(ECDHE-RSA-AES256-GCM-SHA384 ECDHE_RSA_WITH_AES_256_GCM_SHA384)], '0x03000076' => [qw(ECDHE-RSA-CAMELLIA128-SHA256 ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256)], '0x03000077' => [qw(ECDHE-RSA-CAMELLIA256-SHA384 ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384)], '0x0300CCA8' => [qw(ECDHE-RSA-CHACHA20-POLY1305-SHA256 ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256)], # see Note(c) '0x0300C010' => [qw(ECDHE-RSA-NULL-SHA ECDHE_RSA_WITH_NULL_SHA)], '0x0300C011' => [qw(ECDHE-RSA-RC4-SHA ECDHE_RSA_WITH_RC4_128_SHA)], '0x0300C012' => [qw(ECDHE-RSA-DES-CBC3-SHA ECDHE_RSA_WITH_DES_192_CBC3_SHA)], '0x0300C004' => [qw(ECDH-ECDSA-AES128-SHA ECDH_ECDSA_WITH_AES_128_CBC_SHA)], '0x0300C005' => [qw(ECDH-ECDSA-AES256-SHA ECDH_ECDSA_WITH_AES_256_CBC_SHA)], '0x0300C025' => [qw(ECDH-ECDSA-AES128-SHA256 ECDH_ECDSA_WITH_AES_128_SHA256)], '0x0300C026' => [qw(ECDH-ECDSA-AES256-SHA384 ECDH_ECDSA_WITH_AES_256_SHA384)], '0x0300C02D' => [qw(ECDH-ECDSA-AES128-GCM-SHA256 ECDH_ECDSA_WITH_AES_128_GCM_SHA256)], '0x0300C02E' => [qw(ECDH-ECDSA-AES256-GCM-SHA384 ECDH_ECDSA_WITH_AES_256_GCM_SHA384)], '0x03000074' => [qw(ECDH-ECDSA-CAMELLIA128-SHA256 ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256)], '0x03000075' => [qw(ECDH-ECDSA-CAMELLIA256-SHA384 ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384)], '0x0300C001' => [qw(ECDH-ECDSA-NULL-SHA ECDH_ECDSA_WITH_NULL_SHA)], '0x0300C002' => [qw(ECDH-ECDSA-RC4-SHA ECDH_ECDSA_WITH_RC4_128_SHA)], '0x0300C003' => [qw(ECDH-ECDSA-DES-CBC3-SHA ECDH_ECDSA_WITH_DES_192_CBC3_SHA)], '0x0300C00E' => [qw(ECDH-RSA-AES128-SHA ECDH_RSA_WITH_AES_128_CBC_SHA)], '0x0300C00F' => [qw(ECDH-RSA-AES256-SHA ECDH_RSA_WITH_AES_256_CBC_SHA)], '0x0300C029' => [qw(ECDH-RSA-AES128-SHA256 ECDH_RSA_WITH_AES_128_SHA256)], '0x0300C02A' => [qw(ECDH-RSA-AES256-SHA384 ECDH_RSA_WITH_AES_256_SHA384)], '0x0300C031' => [qw(ECDH-RSA-AES128-GCM-SHA256 ECDH_RSA_WITH_AES_128_GCM_SHA256)], '0x0300C032' => [qw(ECDH-RSA-AES256-GCM-SHA384 ECDH_RSA_WITH_AES_256_GCM_SHA384)], '0x03000078' => [qw(ECDH-RSA-CAMELLIA128-SHA256 ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256)], '0x03000079' => [qw(ECDH-RSA-CAMELLIA256-SHA384 ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384)], '0x0300C00B' => [qw(ECDH-RSA-NULL-SHA ECDH_RSA_WITH_NULL_SHA)], '0x0300C00C' => [qw(ECDH-RSA-RC4-SHA ECDH_RSA_WITH_RC4_128_SHA)], '0x0300C00D' => [qw(ECDH-RSA-DES-CBC3-SHA ECDH_RSA_WITH_DES_192_CBC3_SHA)], '0x0300C015' => [qw(AECDH-NULL-SHA ECDH_anon_WITH_NULL_SHA)], '0x0300C016' => [qw(AECDH-RC4-SHA ECDH_anon_WITH_RC4_128_SHA)], '0x0300C017' => [qw(AECDH-DES-CBC3-SHA ECDH_anon_WITH_DES_192_CBC3_SHA)], '0x0300C018' => [qw(AECDH-AES128-SHA ECDH_anon_WITH_AES_128_CBC_SHA)], '0x0300C019' => [qw(AECDH-AES256-SHA ECDH_anon_WITH_AES_256_CBC_SHA)], '0x03000011' => [qw(EXP-EDH-DSS-DES-CBC-SHA EDH_DSS_DES_40_CBC_SHA)], '0x03000012' => [qw(EDH-DSS-DES-CBC-SHA EDH_DSS_DES_64_CBC_SHA)], '0x03000013' => [qw(EDH-DSS-DES-CBC3-SHA EDH_DSS_DES_192_CBC3_SHA)], '0x03000014' => [qw(EXP-EDH-RSA-DES-CBC-SHA EDH_RSA_DES_40_CBC_SHA)], '0x03000015' => [qw(EDH-RSA-DES-CBC-SHA EDH_RSA_DES_64_CBC_SHA)], '0x03000016' => [qw(EDH-RSA-DES-CBC3-SHA EDH_RSA_DES_192_CBC3_SHA)], '0x0300001D' => [qw(FZA-FZA-SHA FZA_DMS_FZA_SHA)], # FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA '0x0300001C' => [qw(FZA-NULL-SHA FZA_DMS_NULL_SHA)], # FORTEZZA_KEA_WITH_NULL_SHA '0x0300001e' => [qw(FZA-RC4-SHA FZA_DMS_RC4_SHA)], # <== 1e so that it is its own hash entry in crontrast to 1E (duplicate constant definition in openssl) '0x03000023' => [qw(KRB5-DES-CBC3-MD5 KRB5_DES_192_CBC3_MD5)], '0x0300001F' => [qw(KRB5-DES-CBC3-SHA KRB5_DES_192_CBC3_SHA)], '0x03000029' => [qw(EXP-KRB5-DES-CBC-MD5 KRB5_DES_40_CBC_MD5)], '0x03000026' => [qw(EXP-KRB5-DES-CBC-SHA KRB5_DES_40_CBC_SHA)], '0x03000022' => [qw(KRB5-DES-CBC-MD5 KRB5_DES_64_CBC_MD5)], '0x0300001E' => [qw(KRB5-DES-CBC-SHA KRB5_DES_64_CBC_SHA)], '0x03000025' => [qw(KRB5-IDEA-CBC-MD5 KRB5_IDEA_128_CBC_MD5)], '0x03000021' => [qw(KRB5-IDEA-CBC-SHA KRB5_IDEA_128_CBC_SHA)], '0x0300002A' => [qw(EXP-KRB5-RC2-CBC-MD5 KRB5_RC2_40_CBC_MD5)], '0x03000027' => [qw(EXP-KRB5-RC2-CBC-SHA KRB5_RC2_40_CBC_SHA)], '0x03000024' => [qw(KRB5-RC4-MD5 KRB5_RC4_128_MD5)], '0x03000020' => [qw(KRB5-RC4-SHA KRB5_RC4_128_SHA)], '0x0300002B' => [qw(EXP-KRB5-RC4-MD5 KRB5_RC4_40_MD5)], '0x03000028' => [qw(EXP-KRB5-RC4-SHA KRB5_RC4_40_SHA)], '0x02000000' => [qw(NULL-MD5 NULL_WITH_MD5)], '0x03000000' => [qw(NULL-NULL NULL_WITH_NULL_NULL)], # O-Saft dummy '0x0300008A' => [qw(PSK-RC4-SHA PSK_WITH_RC4_128_SHA)], '0x0300008B' => [qw(PSK-3DES-EDE-CBC-SHA PSK_WITH_3DES_EDE_CBC_SHA)], '0x0300008C' => [qw(PSK-AES128-CBC-SHA PSK_WITH_AES_128_CBC_SHA)], '0x0300008D' => [qw(PSK-AES256-CBC-SHA PSK_WITH_AES_256_CBC_SHA)], '0x03000008' => [qw(EXP-DES-CBC-SHA RSA_DES_40_CBC_SHA)], '0x03000009' => [qw(DES-CBC-SHA RSA_DES_64_CBC_SHA)], '0x0300000A' => [qw(DES-CBC3-SHA RSA_DES_192_CBC3_SHA)], '0x03000061' => [qw(EXP1024-RC2-CBC-MD5 RSA_EXPORT1024_WITH_RC2_CBC_56_MD5)], '0x03000062' => [qw(EXP1024-DES-CBC-SHA RSA_EXPORT1024_WITH_DES_CBC_SHA)], '0x03000060' => [qw(EXP1024-RC4-MD5 RSA_EXPORT1024_WITH_RC4_56_MD5)], '0x03000064' => [qw(EXP1024-RC4-SHA RSA_EXPORT1024_WITH_RC4_56_SHA)], '0x03000007' => [qw(IDEA-CBC-SHA RSA_IDEA_128_SHA)], '0x03000001' => [qw(NULL-MD5 RSA_NULL_MD5)], '0x03000002' => [qw(NULL-SHA RSA_NULL_SHA)], '0x03000003' => [qw(EXP-RC4-MD5 RSA_RC4_40_MD5)], '0x03000004' => [qw(RC4-MD5 RSA_RC4_128_MD5)], '0x03000005' => [qw(RC4-SHA RSA_RC4_128_SHA)], '0x03000006' => [qw(EXP-RC2-CBC-MD5 RSA_RC2_40_MD5)], '0x0300009C' => [qw(AES128-GCM-SHA256 RSA_WITH_AES_128_GCM_SHA256)], # see Note(d) '0x0300002F' => [qw(AES128-SHA RSA_WITH_AES_128_SHA)], '0x0300003C' => [qw(AES128-SHA256 RSA_WITH_AES_128_SHA256)], '0x0300009D' => [qw(AES256-GCM-SHA384 RSA_WITH_AES_256_GCM_SHA384)], # see Note(d) '0x03000035' => [qw(AES256-SHA RSA_WITH_AES_256_SHA)], '0x0300003D' => [qw(AES256-SHA256 RSA_WITH_AES_256_SHA256)], '0x03000041' => [qw(CAMELLIA128-SHA RSA_WITH_CAMELLIA_128_CBC_SHA)], '0x03000084' => [qw(CAMELLIA256-SHA RSA_WITH_CAMELLIA_256_CBC_SHA)], '0x030000BA' => [qw(CAMELLIA128-SHA256 RSA_WITH_CAMELLIA_128_CBC_SHA256)], '0x030000C0' => [qw(CAMELLIA256-SHA256 RSA_WITH_CAMELLIA_256_CBC_SHA256)], '0x0300003B' => [qw(NULL-SHA256 RSA_WITH_NULL_SHA256)], '0x03000096' => [qw(SEED-SHA RSA_WITH_SEED_SHA)], # # https://tools.ietf.org/html/rfc8446#appendix-B.4 (TLS 1.3) '0x03001301' => [qw(AES128-GCM-SHA256 AES_128_GCM_SHA256)], # TLS 1.3; see Note(d) '0x03001302' => [qw(AES256-GCM-SHA384 AES_256_GCM_SHA384)], # TLS 1.3; see Note(d) '0x03001303' => [qw(CHACHA20-POLY1305-SHA256 CHACHA20_POLY1305_SHA256)], # TLS 1.3 '0x03001304' => [qw(AES128-CCM-SHA256 AES_128_CCM_SHA256)], # TLS 1.3 '0x03001305' => [qw(AES128-CCM8-SHA256 AES_128_CCM_8_SHA256)], # TLS 1.3 # # http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-01 # https://tools.ietf.org/html/rfc7905 '0x0300CC12' => [qw(RSA-CHACHA20-POLY1305 RSA_WITH_CHACHA20_POLY1305)], # see Note(c) '0x0300CC13' => [qw(ECDHE-RSA-CHACHA20-POLY1305-SHA256-OLD ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256)], # -"- '0x0300CC14' => [qw(ECDHE-ECDSA-CHACHA20-POLY1305-SHA256-OLD ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256)], # -"- '0x0300CC15' => [qw(DHE-RSA-CHACHA20-POLY1305-SHA256-OLD DHE_RSA_WITH_CHACHA20_POLY1305_SHA256)], # -"- '0x0300CC20' => [qw(RSA-CHACHA20-SHA RSA_WITH_CHACHA20_SHA)], '0x0300CC21' => [qw(ECDHE-RSA-CHACHA20-SHA ECDHE_RSA_WITH_CHACHA20_SHA)], '0x0300CC22' => [qw(ECDHE-ECDSA-CHACHA20-SHA ECDHE_ECDSA_WITH_CHACHA20_SHA)], '0x0300CC23' => [qw(DHE-RSA-CHACHA20-SHA DHE_RSA_WITH_CHACHA20_SHA)], '0x0300CC24' => [qw(DHE-PSK-CHACHA20-SHA DHE_PSK_WITH_CHACHA20_SHA)], '0x0300CC25' => [qw(PSK-CHACHA20-SHA PSK_WITH_CHACHA20_SHA)], '0x0300CC26' => [qw(ECDHE-PSK-CHACHA20-SHA ECDHE_PSK_WITH_CHACHA20_SHA)], '0x0300CC27' => [qw(RSA-PSK-CHACHA20-SHA RSA_PSK_WITH_CHACHA20_SHA)], # # http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-05 '0x0300CCA0' => [qw(RSA-CHACHA20-POLY1305 RSA_WITH_CHACHA20_POLY1305)], '0x0300CCA1' => [qw(ECDHE-RSA-CHACHA20-POLY1305 ECDHE_RSA_WITH_CHACHA20_POLY1305)], '0x0300CCA2' => [qw(ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE_ECDSA_WITH_CHACHA20_POLY1305)], '0x0300CCA3' => [qw(DHE-RSA-CHACHA20-POLY1305 DHE_RSA_WITH_CHACHA20_POLY1305)], '0x0300CCA4' => [qw(DHE-PSK-CHACHA20-POLY1305 DHE_PSK_WITH_CHACHA20_POLY1305)], '0x0300CCA5' => [qw(PSK-CHACHA20-POLY1305 PSK_WITH_CHACHA20_POLY1305)], '0x0300CCA6' => [qw(ECDHE-PSK-CHACHA20-POLY1305 ECDHE_PSK_WITH_CHACHA20_POLY1305)], '0x0300CCA7' => [qw(RSA-PSK-CHACHA20-POLY1305 RSA_PSK_WITH_CHACHA20_POLY1305)], # '0x0300002C' => [qw(PSK-SHA PSK_WITH_NULL_SHA)], '0x0300002D' => [qw(DHE-PSK-SHA DHE_PSK_WITH_NULL_SHA)], '0x0300002E' => [qw(RSA-PSK-SHA RSA_PSK_WITH_NULL_SHA)], '0x0300008E' => [qw(DHE-PSK-RC4-SHA DHE_PSK_WITH_RC4_128_SHA)], '0x0300008F' => [qw(DHE-PSK-3DES-SHA DHE_PSK_WITH_3DES_EDE_CBC_SHA)], '0x03000090' => [qw(DHE-PSK-AES128-SHA DHE_PSK_WITH_AES_128_CBC_SHA)], '0x03000091' => [qw(DHE-PSK-AES256-SHA DHE_PSK_WITH_AES_256_CBC_SHA)], '0x03000092' => [qw(RSA-PSK-RC4-SHA RSA_PSK_WITH_RC4_128_SHA)], '0x03000093' => [qw(RSA-PSK-3DES-EDE-CBC-SHA RSA_PSK_WITH_3DES_EDE_CBC_SHA)], '0x03000094' => [qw(RSA-PSK-AES128-SHA RSA_PSK_WITH_AES_128_CBC_SHA)], '0x03000095' => [qw(RSA-PSK-AES256-SHA RSA_PSK_WITH_AES_256_CBC_SHA)], '0x030000AA' => [qw(DHE-PSK-AES128-GCM-SHA256 DHE_PSK_WITH_AES_128_GCM_SHA256)], '0x030000AB' => [qw(DHE-PSK-AES256-GCM-SHA384 DHE_PSK_WITH_AES_256_GCM_SHA384)], '0x030000AC' => [qw(RSA-PSK-AES128-GCM-SHA256 RSA_PSK_WITH_AES_128_GCM_SHA256)], '0x030000AD' => [qw(RSA-PSK-AES256-GCM-SHA384 RSA_PSK_WITH_AES_256_GCM_SHA384)], '0x030000AE' => [qw(PSK-AES128-SHA256 PSK_WITH_AES_128_CBC_SHA256)], '0x030000AF' => [qw(PSK-AES256-SHA384 PSK_WITH_AES_256_CBC_SHA384)], '0x030000B0' => [qw(PSK-SHA256 PSK_WITH_NULL_SHA256)], '0x030000B1' => [qw(PSK-SHA384 PSK_WITH_NULL_SHA384)], '0x030000B2' => [qw(DHE-PSK-AES128-SHA256 DHE_PSK_WITH_AES_256_CBC_SHA256)], '0x030000B3' => [qw(DHE-PSK-AES256-SHA384 DHE_PSK_WITH_AES_256_CBC_SHA384)], '0x030000B4' => [qw(DHE-PSK-SHA256 DHE_PSK_WITH_NULL_SHA256)], '0x030000B5' => [qw(DHE-PSK-SHA384 DHE_PSK_WITH_NULL_SHA384)], '0x030000B6' => [qw(RSA-PSK-AES128-SHA256 RSA_PSK_WITH_AES_256_CBC_SHA256)], '0x030000B7' => [qw(RSA-PSK-AES256-SHA384 RSA_PSK_WITH_AES_256_CBC_SHA384)], '0x030000B8' => [qw(RSA-PSK-SHA256 RSA_PSK_WITH_NULL_SHA256)], '0x030000B9' => [qw(RSA-PSK-SHA384 RSA_PSK_WITH_NULL_SHA384)], # '0x0300C09C' => [qw(RSA-AES128-CCM RSA_WITH_AES_128_CCM)], # RFC 6655 '0x0300C09D' => [qw(RSA-AES256-CCM RSA_WITH_AES_256_CCM)], # RFC 6655 '0x0300C09E' => [qw(DHE-RSA-AES128-CCM DHE_RSA_WITH_AES_128_CCM)], # RFC 6655 '0x0300C09F' => [qw(DHE-RSA-AES256-CCM DHE_RSA_WITH_AES_256_CCM)], # RFC 6655 '0x0300C0A0' => [qw(RSA-AES128-CCM8 RSA_WITH_AES_128_CCM_8)], # RFC 6655 '0x0300C0A1' => [qw(RSA-AES256-CCM8 RSA_WITH_AES_256_CCM_8)], # RFC 6655 '0x0300C0A2' => [qw(DHE-RSA-AES128-CCM8 DHE_RSA_WITH_AES_128_CCM_8)], # RFC 6655 '0x0300C0A3' => [qw(DHE-RSA-AES256-CCM8 DHE_RSA_WITH_AES_256_CCM_8)], # RFC 6655 '0x0300C0A4' => [qw(PSK-RSA-AES128-CCM PSK_WITH_AES_128_CCM)], # RFC 6655 '0x0300C0A5' => [qw(PSK-RSA-AES256-CCM PSK_WITH_AES_256_CCM)], # RFC 6655 '0x0300C0A6' => [qw(DHE-PSK-RSA-AES128-CCM DHE_PSK_WITH_AES_128_CCM)], # RFC 6655 '0x0300C0A7' => [qw(DHE-PSK-RSA-AES256-CCM DHE_PSK_WITH_AES_256_CCM)], # RFC 6655 '0x0300C0A8' => [qw(PSK-RSA-AES128-CCM8 PSK_WITH_AES_128_CCM_8)], # RFC 6655 '0x0300C0A9' => [qw(PSK-RSA-AES256-CCM8 PSK_WITH_AES_256_CCM_8)], # RFC 6655 '0x0300C0AA' => [qw(DHE-PSK-RSA-AES128-CCM8 DHE_PSK_WITH_AES_128_CCM_8)], # RFC 6655 '0x0300C0AB' => [qw(DHE-PSK-RSA-AES256-CCM8 DHE_PSK_WITH_AES_256_CCM_8)], # RFC 6655 '0x0300C0AC' => [qw(ECDHE-RSA-AES128-CCM ECDHE_ECDSA_WITH_AES_128_CCM)], # RFC 7251 '0x0300C0AD' => [qw(ECDHE-RSA-AES256-CCM ECDHE_ECDSA_WITH_AES_256_CCM)], # RFC 7251 '0x0300C0AE' => [qw(ECDHE-RSA-AES128-CCM8 ECDHE_ECDSA_WITH_AES_128_CCM_8)], # RFC 7251 '0x0300C0AF' => [qw(ECDHE-RSA-AES256-CCM8 ECDHE_ECDSA_WITH_AES_256_CCM_8)], # RFC 7251 '0x03005600' => [qw(SCSV TLS_FALLBACK_SCSV)], # FIXME: according http://tools.ietf.org/html/7507.html '0x030000FF' => [qw(INFO_SCSV EMPTY_RENEGOTIATION_INFO_SCSV)], '0x0300C01A' => [qw(SRP-3DES-EDE-CBC-SHA SRP_SHA_WITH_3DES_EDE_CBC_SHA)], '0x0300C01B' => [qw(SRP-RSA-3DES-EDE-CBC-SHA SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)], '0x0300C01C' => [qw(SRP-DSS-3DES-EDE-CBC-SHA SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA)], '0x0300C01D' => [qw(SRP-AES-128-CBC-SHA SRP_SHA_WITH_AES_128_CBC_SHA)], '0x0300C01E' => [qw(SRP-RSA-AES-128-CBC-SHA SRP_SHA_RSA_WITH_AES_128_CBC_SHA)], '0x0300C01F' => [qw(SRP-DSS-AES-128-CBC-SHA SRP_SHA_DSS_WITH_AES_128_CBC_SHA)], '0x0300C020' => [qw(SRP-AES-256-CBC-SHA SRP_SHA_WITH_AES_256_CBC_SHA)], '0x0300C021' => [qw(SRP-RSA-AES-256-CBC-SHA SRP_SHA_RSA_WITH_AES_256_CBC_SHA)], '0x0300C022' => [qw(SRP-DSS-AES-256-CBC-SHA SRP_SHA_DSS_WITH_AES_256_CBC_SHA)], '0x0300C03C' => [qw(RSA-ARIA128-SHA256 RSA_WITH_ARIA_128_CBC_SHA256)], '0x0300C03D' => [qw(RSA-ARIA256-SHA384 RSA_WITH_ARIA_256_CBC_SHA384)], '0x0300C03E' => [qw(DH-DSS-ARIA128-SHA256 DH_DSS_WITH_ARIA_128_CBC_SHA256)], '0x0300C03F' => [qw(DH-DSS-ARIA256-SHA384 DH_DSS_WITH_ARIA_256_CBC_SHA384)], '0x0300C040' => [qw(DH-RSA-ARIA128-SHA256 DH_RSA_WITH_ARIA_128_CBC_SHA256)], '0x0300C041' => [qw(DH-RSA-ARIA256-SHA384 DH_RSA_WITH_ARIA_256_CBC_SHA384)], '0x0300C042' => [qw(DHE-DSS-ARIA128-SHA256 DHE_DSS_WITH_ARIA_128_CBC_SHA256)], '0x0300C043' => [qw(DHE-DSS-ARIA256-SHA384 DHE_DSS_WITH_ARIA_256_CBC_SHA384)], '0x0300C044' => [qw(DHE-RSA-ARIA256-SHA256 DHE_RSA_WITH_ARIA_256_CBC_SHA256)], '0x0300C045' => [qw(DHE-RSA-ARIA256-SHA384 DHE_RSA_WITH_ARIA_256_CBC_SHA384)], '0x0300C046' => [qw(ADH-ARIA128-SHA256 DH_anon_WITH_ARIA_128_CBC_SHA256)], '0x0300C047' => [qw(ADH-ARIA256-SHA384 DH_anon_WITH_ARIA_256_CBC_SHA384)], '0x0300C048' => [qw(ECDHE-ECDSA-ARIA128-SHA256 ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256)], '0x0300C049' => [qw(ECDHE-ECDSA-ARIA256-SHA384 ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384)], '0x0300C04A' => [qw(ECDH-ECDSA-ARIA128-SHA256 ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 )], '0x0300C04B' => [qw(ECDH-ECDSA-ARIA256-SHA384 ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 )], '0x0300C04C' => [qw(ECDHE-RSA-ARIA128-SHA256 ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 )], '0x0300C04D' => [qw(ECDHE-RSA-ARIA256-SHA384 ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 )], '0x0300C04E' => [qw(ECDH-RSA-ARIA128-SHA256 ECDH_RSA_WITH_ARIA_128_CBC_SHA256 )], '0x0300C04F' => [qw(ECDH-RSA-ARIA256-SHA384 ECDH_RSA_WITH_ARIA_256_CBC_SHA384 )], '0x0300C050' => [qw(RSA-ARIA128-GCM-SHA256 RSA_WITH_ARIA_128_GCM_SHA256 )] , '0x0300C051' => [qw(RSA-ARIA256-GCM-SHA384 RSA_WITH_ARIA_256_GCM_SHA384 )], '0x0300C052' => [qw(DHE-RSA-ARIA128-GCM-SHA256 DHE_RSA_WITH_ARIA_128_GCM_SHA256 )], '0x0300C053' => [qw(DHE-RSA-ARIA256-GCM-SHA384 DHE_RSA_WITH_ARIA_256_GCM_SHA384 )], '0x0300C054' => [qw(DH-RSA-ARIA128-GCM-SHA256 DH_RSA_WITH_ARIA_128_GCM_SHA256 )], '0x0300C055' => [qw(DH-RSA-ARIA256-GCM-SHA384 DH_RSA_WITH_ARIA_256_GCM_SHA384 )], '0x0300C056' => [qw(DHE-DSS-ARIA128-GCM-SHA256 DHE_DSS_WITH_ARIA_128_GCM_SHA256 )], '0x0300C057' => [qw(DHE-DSS-ARIA256-GCM-SHA384 DHE_DSS_WITH_ARIA_256_GCM_SHA384 )], '0x0300C058' => [qw(DH-DSS-ARIA128-GCM-SHA256 DH_DSS_WITH_ARIA_128_GCM_SHA256 )], '0x0300C059' => [qw(DH-DSS-ARIA256-GCM-SHA384 DH_DSS_WITH_ARIA_256_GCM_SHA384 )], '0x0300C05A' => [qw(ADH-ARIA128-GCM-SHA256 DH_anon_WITH_ARIA_128_GCM_SHA256 )], '0x0300C05B' => [qw(ADH-ARIA256-GCM-SHA384 DH_anon_WITH_ARIA_256_GCM_SHA384 )], '0x0300C05C' => [qw(ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256)], '0x0300C05D' => [qw(ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384)], '0x0300C05E' => [qw(ECDH-ECDSA-ARIA128-GCM-SHA256 ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 )], '0x0300C05F' => [qw(ECDH-ECDSA-ARIA256-GCM-SHA384 ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 )], '0x0300C060' => [qw(ECDHE-RSA-ARIA128-GCM-SHA256 ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 )], '0x0300C061' => [qw(ECDHE-RSA-ARIA256-GCM-SHA384 ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 )], '0x0300C062' => [qw(ECDH-RSA-ARIA128-GCM-SHA256 ECDH_RSA_WITH_ARIA_128_GCM_SHA256 )], '0x0300C063' => [qw(ECDH-RSA-ARIA256-GCM-SHA384 ECDH_RSA_WITH_ARIA_256_GCM_SHA384 )], '0x0300C064' => [qw(PSK-ARIA128-SHA256 PSK_WITH_ARIA_128_CBC_SHA256 )], '0x0300C065' => [qw(PSK-ARIA256-SHA384 PSK_WITH_ARIA_256_CBC_SHA384 )], '0x0300C066' => [qw(DHE-PSK-ARIA128-SHA256 DHE_PSK_WITH_ARIA_128_CBC_SHA256 )], '0x0300C067' => [qw(DHE-PSK-ARIA256-SHA384 DHE_PSK_WITH_ARIA_256_CBC_SHA384 )], '0x0300C068' => [qw(RSA-PSK-ARIA128-SHA256 RSA_PSK_WITH_ARIA_128_CBC_SHA256 )], '0x0300C069' => [qw(RSA-PSK-ARIA256-SHA384 RSA_PSK_WITH_ARIA_256_CBC_SHA384 )], '0x0300C06A' => [qw(PSK-ARIA128-GCM-SHA256 PSK_WITH_ARIA_128_GCM_SHA256 )], '0x0300C06B' => [qw(PSK-ARIA256-GCM-SHA384 PSK_WITH_ARIA_256_GCM_SHA384 )], '0x0300C06C' => [qw(DHE-PSK-ARIA128-GCM-SHA256 DHE_PSK_WITH_ARIA_128_GCM_SHA256 )], '0x0300C06D' => [qw(DHE-PSK-ARIA256-GCM-SHA384 DHE_PSK_WITH_ARIA_256_GCM_SHA384 )], '0x0300C06E' => [qw(RSA-PSK-ARIA128-GCM-SHA256 RSA_PSK_WITH_ARIA_128_GCM_SHA256 )], '0x0300C06F' => [qw(RSA-PSK-ARIA256-GCM-SHA384 RSA_PSK_WITH_ARIA_256_GCM_SHA384 )], '0x0300C070' => [qw(ECDHE-PSK-ARIA128-SHA256 ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 )], '0x0300C071' => [qw(ECDHE-PSK-ARIA256-SHA384 ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 )], '0x0300FEE0' => [qw(RSA-FIPS-3DES-EDE-SHA RSA_FIPS_WITH_3DES_EDE_CBC_SHA)], # unklar '0x0300FEE1' => [qw(RSA-FIPS-DES-CBC-SHA RSA_FIPS_WITH_DES_CBC_SHA)], # unklar, '0x0300FEFE' => [qw(RSA-FIPS-DES-CBC-SHA RSA_FIPS_WITH_DES_CBC_SHA)], # openssl-chacha '0x0300FEFF' => [qw(RSA-FIPS-3DES-EDE-SHA RSA_FIPS_WITH_3DES_EDE_CBC_SHA)], # openssl-chacha # '0x03000080' => [qw(GOST94-GOST89-GOST89 GOSTR341094_WITH_28147_CNT_IMIT)], #ok '0x03000081' => [qw(GOST2001-GOST89-GOST89 GOSTR341001_WITH_28147_CNT_IMIT)], #ok '0x03000082' => [qw(GOST94-NULL-GOST94 GOSTR341094_WITH_NULL_GOSTR3411)], # unklar, siehe 0x0300FF00 '0x03000083' => [qw(GOST2001-NULL-GOST94 GOSTR341001_WITH_NULL_GOSTR3411)], # unklar, siehe 0x0300FF01 # '0x0300FF00' => [qw(GOST94-NULL-GOST94 GOSTR341001_WITH_NULL_GOSTR3411)], # unklar, siehe 0x03000082 und muesste sein GOSTR341094_WITH_NULL_GOSTR3411 '0x0300FF00' => [qw(GOST-MD5 GOSTR341094_RSA_WITH_28147_CNT_MD5)], '0x0300FF01' => [qw(GOST-GOST94 RSA_WITH_28147_CNT_GOST94)], # '0x0300FF01' => [qw(GOST2001-NULL-GOST94 GOSTR341001_WITH_NULL_GOSTR3411)], # unklar da nummer doppelt '0x0300FF02' => [qw(GOST-GOST89MAC GOST-GOST89MAC)], # openssl-chacha '0x0300FF03' => [qw(GOST-GOST89STREAM GOST-GOST89STREAM)], # openssl-chacha # TODO: following PCT... '0x00800001' => [qw(PCT_SSL_CERT_TYPE PCT1_CERT_X509)], '0x00800003' => [qw(PCT_SSL_CERT_TYPE PCT1_CERT_X509_CHAIN)], '0x00810001' => [qw(PCT_SSL_HASH_TYPE PCT1_HASH_MD5)], '0x00810003' => [qw(PCT_SSL_HASH_TYPE PCT1_HASH_SHA)], '0x00820003' => [qw(PCT_SSL_EXCH_TYPE PCT1_EXCH_RSA_PKCS1)], '0x00823004' => [qw(PCT_SSL_CIPHER_TYPE_1ST_HALF PCT1_CIPHER_RC4)], '0x00842840' => [qw(PCT_SSL_CIPHER_TYPE_2ND_HALF PCT1_ENC_BITS_40|PCT1_MAC_BITS_128)], '0x00848040' => [qw(PCT_SSL_CIPHER_TYPE_2ND_HALF PCT1_ENC_BITS_128|PCT1_MAC_BITS_128)], '0x008f8001' => [qw(PCT_SSL_COMPAT PCT_VERSION_1)], # from: https://chromium.googlesource.com/chromium/src/net/+/master/ssl/ssl_cipher_suite_names_unittest.cc '0x030016B7' => [qw(CECPQ1-RSA-CHACHA20-POLY1305-SHA256 CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256)], '0x030016B8' => [qw(CECPQ1-ECDSA-CHACHA20-POLY1305-SHA256 CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256)], '0x030016B9' => [qw(CECPQ1-RSA-AES256-GCM-SHA384 CECPQ1_RSA_WITH_AES_256_GCM_SHA384)], '0x030016BA' => [qw(CECPQ1-ECDSA-AES256-GCM-SHA384 CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384)], #!#----------+-------------------------------------+--------------------------+ # # Note(a) # according https://tools.ietf.org/html/rfc6101#appendix-E # following SSLv2 ciphers are valid for SSLv3 too: # '0x02010080' => RC4_128_WITH_MD5 # '0x02020080' => RC4_128_EXPORT40_WITH_MD5 # '0x02030080' => RC2_128_CBC_WITH_MD5 # '0x02040080' => RC2_128_CBC_EXPORT40_WITH_MD5 # '0x02050080' => IDEA_128_CBC_WITH_MD5 # '0x02060040' => DES_64_CBC_WITH_MD5 # '0x020700C0' => DES_192_EDE3_CBC_WITH_MD5 # # Note(c) # according https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04 # some hex keys for ciphers changed # see also: http://tools.ietf.org/html/draft-mavrogiannopoulos-chacha-tls-05 # hex key to be used (RFC, IANA) see: https://tools.ietf.org/html/rfc7905 # hence the hex keys from drafts are named "OLD-" # # Note(d) # 0x0300009C and 0x0300009D conflicts with 0x03001301 and 0x03001302 (TLS1.3) # but works here as long as we use the cipher suite names which are converted # to the proper hex keys by the underlaying (modern >2017) openssl and libssl # means: we get AES128-GCM-SHA256, AES256-GCM-SHA384 for TLSv1 and TLSv13 ); # %cipher_names our %cipher_alias = ( # TODO: only one element allowed #!#----------+-------------------------------------+--------------------------+ #!# constant => cipher suite name alias # comment (where found) #!#----------+-------------------------------------+--------------------------+ '0x02030080' => [qw(RC2-MD5)], # '0x02040080' => [qw(EXP-RC2-MD5)], # from sslaudit.ini '0x03000012' => [qw(EDH-DSS-CBC-SHA)], # from sslaudit.ini and mozilla '0x0300001D' => [qw(FZA-FZA-CBC-SHA)], '0x03000032' => [qw(EDH-DSS-AES128-SHA)], # from RSA BSAFE SSL-C '0x0300002C' => [qw(PSK-NULL-SHA)], # from openssl '0x0300002D' => [qw(DHE-PSK-NULL-SHA)], '0x0300002E' => [qw(RSA-PSK-NULL-SHA)], '0x03000033' => [qw(EDH-RSA-AES128-SHA)], # -"- '0x03000038' => [qw(EDH-DSS-AES256-SHA)], # -"- '0x03000039' => [qw(EDH-RSA-AES256-SHA)], # -"- '0x03000062' => [qw(EXP-DES-56-SHA)], # -"- '0x03000063' => [qw(EXP-EDH-DSS-DES-56-SHA)], # -"- '0x03000064' => [qw(EXP-RC4-56-SHA)], # -"- '0x03000065' => [qw(EXP-EDH-DSS-RC4-56-SHA)], '0x03000066' => [qw(EDH-DSS-RC4-SHA)], # from RSA BSAFE SSL-C # TODO: need to mark following 10 as old ciphers with changed IDs '0x03000093' => [qw(RSA-PSK-3DES-SHA)], # ?? '0x03000094' => [qw(RSA-PSK-AES128-CBC-SHA)], # openssl 1.0.2 '0x03000095' => [qw(RSA-PSK-AES256-CBC-SHA)], # openssl 1.0.2 '0x0300CC13' => [qw(ECDHE-RSA-CHACHA20-POLY1305-OLD)], # see Note(c) above '0x0300CC14' => [qw(ECDHE-ECDSA-CHACHA20-POLY1305-OLD)], # -"- '0x0300CC15' => [qw(DHE-RSA-CHACHA20-POLY1305-OLD)], # -"- '0x0300CC16' => [qw(DHE-PSK-CHACHA20-POLY1305)], # -"- '0x0300CC17' => [qw(PSK-CHACHA20-POLY1305)], # -"- '0x0300CC18' => [qw(ECDHE-PSK-CHACHA20-POLY1305)], # -"- '0x0300CC19' => [qw(RSA-PSK-CHACHA20-POLY1305)], # -"- '0x0300009B' => [qw(DHanon-SEED-SHA)], '0x0300C0A0' => [qw(RSA-AES128-CCM-8)], # ?? some java '0x0300C0A1' => [qw(RSA-AES256-CCM-8)], # -"- '0x0300C0A2' => [qw(DHE-RSA-AES128-CCM-8)], # -"- '0x0300C0A3' => [qw(DHE-RSA-AES256-CCM-8)], # -"- '0x0300C0A8' => [qw(PSK-RSA-AES128-CCM-8)], # -"- '0x0300C0A9' => [qw(PSK-RSA-AES256-CCM-8)], # -"- '0x0300C0AE' => [qw(ECDHE-RSA-AES128-CCM-8)], # -"- '0x0300C0AF' => [qw(ECDHE-RSA-AES256-CCM-8)], # -"- # following are cipher suite values; alias for them not yet implemented # '0x03000003' => [qw(RSA_WITH_RC4_40_MD5)], # '0x03000004' => [qw(RSA_WITH_RC4_128_MD5)], # from tlslite # '0x03000005' => [qw(RSA_WITH_RC4_128_SHA)], # from tlslite # '0x03000006' => [qw(RSA_WITH_RC2_40_MD5)], # '0x0300000A' => [qw(RSA_WITH_3DES_EDE_CBC_SHA)], # from tlslite # '0x03000017' => [qw(DH_anon_EXPORT_WITH_RC4_40_MD5)], # '0x03000019' => [qw(DH_anon_EXPORT_WITH_DES40_CBC_SHA)], # '0x0300001A' => [qw(DH_anon_WITH_DES_CBC_SHA)], # '0x0300001B' => [qw(DH_anon_WITH_3DES_EDE_CBC_SHA)],# # '0x0300002F' => [qw(RSA_WITH_AES_128_CBC_SHA)], # from tlslite # '0x03000033' => [qw(DHE_RSA_WITH_AES_128_CBC_SHA)], # '0x03000034' => [qw(DH_ANON_WITH_AES_128_CBC_SHA)],# from tlslite # '0x03000035' => [qw(RSA_WITH_AES_256_CBC_SHA)], # from tlslite # '0x03000039' => [qw(DHE_RSA_WITH_AES_256_CBC_SHA)], # '0x0300003A' => [qw(DH_ANON_WITH_AES_256_CBC_SHA)],# from tlslite # '0x0300C0AA' => [qw(PSK_DHE_WITH_AES_128_CCM_8)], # from openssl # '0x0300C0AB' => [qw(PSK_DHE_WITH_AES_256_CCM_8)], # from openssl #!#----------+-------------------------------------+--------------------------+ ); # %cipher_alias our %cipher_old = ( # TODO: only one element allowed (not needed in OSaft/Ciphers.pm) #!#----------+-------------------------------------+--------------------------+ #!# constant => cipher suite name alias # comment (where found) #!#----------+-------------------------------------+--------------------------+ '0x0300CC13' => [qw(ECDHE-RSA-CHACHA20-POLY1305-OLD)], # openssl-chacha '0x0300CC14' => [qw(ECDHE-ECDSA-CHACHA20-POLY1305-OLD)],# -"- '0x0300CC15' => [qw(DHE-RSA-CHACHA20-POLY1305-OLD)], # -"- #!#----------+-------------------------------------+--------------------------+ ); # %cipher_old our @cipher_results = [ # list of checked ciphers # currently (12/2015) # [ sslv3, rc4-md5, yes ] # [ sslv3, NULL, no ] # in future (01/2016) # [ ssl, cipher, pos+cipher, pos+cipherraw, dh-bits, dh-param, "comment"] # # # ssl : SSLv2, SSLv3, TLS10, ... # # cipher : hex-Wert (als String) # # pos+* : -1 = undef (noch nicht berechnet), 0 = keine Reihenfolge # beim Server, 1 .. n wie vom Server ausgewaehlt # # dh-bits : DH Bits # # dh-param : ECDH Kurve # dann können verschieden Algorithmen implementiert werden ### 1. o-saft wie jetzt ### 2. o-saft mit cipherraw wie jetzt ### 3. cipherraw mit unterschiedlicher Anzahl Ciphers, z.B.: ### 1, 8,9,15,16,17,32,64,48,49,127,128,129 ### 4. von cipherraw den selected Cipher geben lassen ]; # @cipher_results our %cfg = ( 'mename' => "O-Saft ", # my name pretty printed 'need_netdns' => 0, # used for better error message handling only 'need_timelocal'=> 0, # -"- # following initialized in _osaft_init() 'me' => "", 'ARG0' => "", 'ARGV' => [], # arguments passed on command line 'RC-ARGV' => [], # arguments read from RC-FILE (set in caller) 'RC-FILE' => "", # our RC-FILE, search in pwd only! # following should be in %text, but as %cfg is available everywhere, # it's better defined here and initialized in _osaft_init() 'prefix_trace' => "", # prefix string used in trace messages 'prefix_verbose'=> "", # prefix string used in verbose messages # config. key default description #------------------+---------+---------------------------------------------- 'try' => 0, # 1: do not execute openssl, just show 'exec' => 0, # 1: if +exec command used 'trace' => 0, # 1: trace yeast, 2=trace Net::SSLeay and Net::SSLinfo also 'traceME' => 0, # 1: trace yeast only, but no modules # -1: trace modules only, but not yeast 'traceARG' => 0, # 1: trace yeast's argument processing 'traceCMD' => 0, # 1: trace command processing 'traceKEY' => 0, # 1: (trace) print yeast's internal variable names 'traceTIME' => 0, # 1: (trace) print additiona time for benchmarking 'time_absolut' => 0, # 1: (trace) --traceTIME uses absolut timstamps 'linux_debug' => 0, # passed to Net::SSLeay::linux_debug 'verbose' => 0, # used for --v 'v_cipher' => 0, # used for --v-cipher 'warning' => 1, # 1: print warnings; 0: don't print warnings 'proxyhost' => "", # FQDN or IP of proxy to be used 'proxyport' => 0, # port for proxy 'proxyauth' => "", # authentication string used for proxy 'proxyuser' => "", # username for proxy authentication (Basic or Digest Auth) 'proxypass' => "", # password for proxy authentication (Basic or Digest Auth) 'starttls' => "", # use STARTTLS if not empty # protocol to be used with STARTTLS; default: SMTP # valid protocols: SMTP, IMAP, IMAP2, POP3, FTPS, LDAP, RDP, XMPP 'starttls_delay'=> 0, # STARTTLS: time to wait in seconds (to slow down the requests) 'starttls_phase'=> [], # STARTTLS: Array for customized STARTTLS sequences 'starttls_error'=> [], # STARTTLS: Array for customized STARTTLS sequences error handling 'slow_server_delay' => 0, # time to wait in seconds after a connection via proxy or before starting STARTTLS sequence 'connect_delay' => 0, # time to wait in seconds for starting next cipher check 'socket_reuse' => 1, # 0: close and reopen sockets when SSL connect fails # 1: reuse existing sockets, even if SSL connect failed 'enabled' => 0, # 1: only print enabled ciphers 'disabled' => 0, # 1: only print disabled ciphers 'nolocal' => 0, 'experimental' => 0, # 1: use experimental functionality 'ignore_no_conn'=> 0, # 1: ignore warnings if connection fails, check target anyway 'uselwp' => 0, # 1: use perls LWP module for HTTP checks # TODO: NOT YET IMPLEMENTED 'forcesni' => 0, # 1: do not check if SNI seems to be supported by Net::SSLeay 'usesni' => 1, # 0: do not make connection in SNI mode; # 1: make connection with SNI set (can be empty string) # 3: test with and without SNI mode (used with +cipherraw only) 'usedns' => 1, # 1: make DNS reverse lookup 'usemx' => 0, # 1: make MX-Record DNS lookup 'usehttp' => 1, # 1: make HTTP request 'usealpn' => 1, # 0: do not use -alpn option for openssl 'usenpn' => 1, # 0: do not use -nextprotoneg option for openssl 'protos_next' => # all names known for ALPN or NPN 'http/1.1,h2c,h2c-14,spdy/1,npn-spdy/2,spdy/2,spdy/3,spdy/3.1,spdy/4a2,spdy/4a4,grpc-exp,h2-14,h2-15,http/2.0,h2', # even Net::SSLeay functions most likely use an # array, this is a string with comma-separated # names as used by openssl # Note: must not contain any white spaces! 'protos_alpn' => [], # initially same as cfg{protos_next}, see _cfg_init() 'protos_npn' => [], # "-" 'use_reconnect' => 1, # 0: do not use -reconnect option for openssl 'use_extdebug' => 1, # 0: do not use -tlsextdebug option for openssl 'slowly' => 0, # passed to Net::SSLeay::slowly 'no_comp' => 0, # 1: use OP_NO_COMPRESSION for connetion in Net::SSLeay 'sni_name' => undef, # if set, name to be used for connection with SNI # must be set to $host if undef and 'usesni'=1 (see above) # all other strings are used verbatim, even empty one 'use_sni_name' => 0, # 0: use hostname; 1: use name provided by --sni-name # used by Net::SSLhello only 'sclient_opt' => "", # argument or option passed to openssl s_client command 'no_cert' => 0, # 0: get data from certificate; 1, 2, do not get data 'no_cert_txt' => "", # change default text if no data from cert retrieved 'ca_depth' => undef, # depth of peer certificate verification verification 'ca_crl' => undef, # URL where to find CRL file 'ca_file' => undef, # PEM format file with CAs 'ca_path' => undef, # path to directory with PEM files for CAs # see Net::SSLinfo why undef as default 'ca_paths' => [qw(/etc/ssl/certs /usr/lib/certs /System/Library/OpenSSL)], # common paths to PEM files for CAs 'ca_files' => [qw(ca-certificates.crt certificates.crt certs.pem)], # common PEM filenames for CAs 'openssl_env' => undef, # environment variable OPENSSL if defined 'openssl_cnf' => undef, # full path to openssl's openssl.cnf 'openssl_cnfs' => [qw(/usr/lib/ssl/openssl.cnf /etc/ssl/openssl.cnf /System//Library/OpenSSL/openssl.cnf /usr/ssl/openssl.cnf)], # NOT YET USED 'openssl_fips' => undef, # NOT YET USED 'openssl_msg' => "", # '-msg': option needed for openssl versions older than 1.0.2 to get the dh_parameter 'exitcode' => 0, # 1: exit with status code if any check is "no" 'exitcode_checks' => 1, # 0: do not count "no" checks for --exitcode 'exitcode_cipher' => 1, # 0: do not count any ciphers for --exitcode 'exitcode_medium' => 1, # 0: do not count MEDIUM ciphers for --exitcode 'exitcode_weak' => 1, # 0: do not count WEAK ciphers for --exitcode 'exitcode_low' => 1, # 0: do not count LOW ciphers for --exitcode 'exitcode_pfs' => 1, # 0: do not count ciphers without PFS for --exitcode 'exitcode_prot' => 1, # 0: do not count protocols other than TLSv12 for --exitcode 'exitcode_sizes'=> 1, # 0: do not count size checks for --exitcode 'ignorecase' => 1, # 1: compare some strings case insensitive 'ignorenoreply' => 1, # 1: treat "no reply" as heartbeat not enabled 'label' => 'long', # fomat of labels 'labels' => [qw(full long short key)], # all supported label formats 'version' => [], # contains the versions to be checked 'versions' => # all supported versions; SEE Note:%prot (in o-saft.pl) # [reverse sort keys %prot], # do not use generic list 'cause we want special order [qw(SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 TLSv13 DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13)], 'DTLS_versions' => [qw(DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13)], # temporary list 'cause DTLS not supported by openssl (6/2015) 'ssl_lazy' => 0, # 1: lazy check for available SSL protocol functionality 'SSLv2' => 1, # 1: check this SSL version 'SSLv3' => 1, # 1: " 'TLSv1' => 1, # 1: " 'TLSv11' => 1, # 1: " 'TLSv12' => 1, # 1: " 'TLSv13' => 1, # 1: " # NOTE: DTLS currently (6/2015) disabled by default 'cause not supported by openssl 'DTLSv09' => 0, # 1: " 'DTLSv1' => 0, # 1: " 'DTLSv11' => 0, # 1: " 'DTLSv12' => 0, # 1: " 'DTLSv13' => 0, # 1: " 'TLS1FF' => 0, # dummy for future use 'DTLSfamily' => 0, # dummy for future use 'nullssl2' => 0, # 1: complain if SSLv2 enabled but no ciphers accepted 'cipher' => [], # ciphers we got with --cipher= 'cipherpattern' => "ALL:NULL:eNULL:aNULL:LOW:EXP", # openssl pattern for all ciphers # should simply be ALL:COMPLEMENTOFALL, but # have seen implementations where it does not # list all compiled-in ciphers, hence the long # list # TODO: must be same as in Net::SSLinfo or used from there 'cipherpatterns' => { # openssl patterns for cipher lists # key description cipher pattern for openssl #----------------+--------------------------+--------------------------- 'null' => [ "Null Ciphers", 'NULL:eNULL' ], 'anull' => [ "Anonymous NULL Ciphers", 'aNULL' ], 'anon' => [ "Anonymous DH Ciphers", 'ADH' ], 'adh' => [ "Anonymous DH Ciphers", 'ADH' ], 'aes' => [ "AES Ciphers", 'AES' ], 'aes128' => [ "AES128 Ciphers", 'AES128'], 'aes256' => [ "AES256 Ciphers", 'AES256'], 'aesGCM' => [ "AESGCM Ciphers", 'AESGCM'], 'chacha' => [ "CHACHA20 Ciphers", 'CHACHA'], # NOTE: not possible with some openssl 'dhe' => [ "Ephermeral DH Ciphers", 'EDH' ], # NOTE: DHE not possible some openssl 'edh' => [ "Ephermeral DH Ciphers", 'EDH' ], 'ecdh' => [ "Ecliptical curve DH Ciphers", 'ECDH' ], 'ecdsa' => [ "Ecliptical curve DSA Ciphers", 'ECDSA' ], 'ecdhe' => [ "Ephermeral ecliptical curve DH Ciphers", 'EECDH' ], # TODO: ECDHE not possible with openssl 'eecdh' => [ "Ephermeral ecliptical curve DH Ciphers", 'EECDH' ], 'aecdh' => [ "Anonymous ecliptical curve DH Ciphers", 'AECDH' ], 'exp40' => [ "40 Bit encryption", 'EXPORT40' ], 'exp56' => [ "56 Bit export ciphers", 'EXPORT56' ], 'export' => [ "all Export Ciphers", 'EXPORT'], 'exp' => [ "all Export Ciphers", 'EXPORT'], # alias for export 'des' => [ "DES Ciphers", 'DES:!ADH:!EXPORT:!aNULL' ], '3des' => [ "Triple DES Ciphers", '3DES' ], # TODO: 3DES:!ADH:!aNULL 'fips' => [ "FIPS compliant Ciphers", 'FIPS' ], # NOTE: not possible with some openssl 'gost' => [ "all GOST Ciphers", 'GOST' ], # NOTE: not possible with some openssl 'gost89' => [ "all GOST89 Ciphers", 'GOST89'], # NOTE: not possible with some openssl 'gost94' => [ "all GOST94 Ciphers", 'GOST94'], # NOTE: not possible with some openssl 'idea' => [ "IDEA Ciphers", 'IDEA' ], # NOTE: not possible with some openssl 'krb' => [ "KRB5 Ciphers", 'KRB5' ], # alias for krb5 'krb5' => [ "KRB5 Ciphers", 'KRB5' ], 'md5' => [ "Ciphers with MD5 Mac", 'MD5' ], 'psk' => [ "PSK Ciphers", 'PSK' ], 'rc2' => [ "RC2 Ciphers", 'RC2' ], # NOTE: not possible with some openssl 'rc4' => [ "RC4 Ciphers", 'RC4' ], 'rsa' => [ "RSA Ciphers", 'RSA' ], 'seed' => [ "Seed Ciphers", 'SEED' ], 'sslv2' => [ "all SSLv2 Ciphers", 'SSLv2' ], # NOTE: not possible with some openssl 'sslv3' => [ "all SSLv3 Ciphers", 'SSLv3' ], # NOTE: not possible with some openssl 'tlsv1' => [ "all TLSv1 Ciphers", 'TLSv1' ], # NOTE: not possible with some openssl 'tlsv11' => [ "all TLSv11 Ciphers", 'TLSv1' ], # alias for tlsv1 'tlsv12' => [ "all TLSv12 Ciphers", 'TLSv1.2' ], 'srp' => [ "SRP Ciphers", 'SRP' ], 'sha' => [ "Ciphers with SHA1 Mac", 'SHA' ], 'sha' => [ "Ciphers with SHA1 Mac", 'SHA' ], 'sha1' => [ "Ciphers with SHA1 Mac", 'SHA1' ], # NOTE: not possible with some openssl 'sha2' => [ "Ciphers with SHA256 Mac", 'SHA256'], 'sha256' => [ "Ciphers with SHA256 Mac", 'SHA256'], 'sha384' => [ "Ciphers with SHA384 Mac", 'SHA384'], 'sha512' => [ "Ciphers with SHA512 Mac", 'SHA512'], # NOTE: not possible with some openssl 'weak' => [ "Weak grade encryption", 'LOW:3DES:DES:RC4:ADH:EXPORT' ], # 'low' => [ "Low grade encryption", 'LOW:!ADH' ], # LOW according openssl 'low' => [ "Low grade encryption", 'LOW:3DES:RC4:!ADH' ], 'medium' => [ "Medium grade encryption", 'MEDIUM:!NULL:!aNULL:!SSLv2:!3DES:!RC4' ], 'high' => [ "High grade encryption", 'HIGH:!NULL:!aNULL:!DES:!3DES' ], #----------------+--------------------------+--------------------------- # TODO: list with 'key exchange': kRSA, kDHr, kDHd, kDH, kEDH, kECDHr, kECDHe, kECDH, kEECDH }, # cipherpatterns 'ciphers' => [], # contains all ciphers to be tested 'cipherrange' => 'rfc', # the range to be used from 'cipherranges' 'cipherranges' => { # constants for ciphers (NOTE: written as hex) # Technical (perl) note for definition of these ranges: # Each range is defined as a string like key=>"2..5, c..f" # instead of an array like key=>[2..5, c..f] which would # result in key=>[2 3 4 5 c d e f] . # This expansion of the range is done at compile time and # so will consume a huge amount of memory at runtime. # Using a string instead of the expanded array reduces the # memory footprint, but requires use of eval() when the # range is needed: eval($cfg{cipherranges}->{rfc}) # Each string must be syntax for perl's range definition. 'yeast' => "", # internal list, computed later ... # push(@all, @{$_}[0]) foreach (values %cipher_names); 'rfc' => # constants for ciphers defined in various RFCs "0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300C0FF, 0x0300CC00 .. 0x0300CCFF, 0x0300FE00 .. 0x0300FFFF, ", 'shifted' => # constants for ciphers defined in various RFCs shifted with an offset of 64 (=0x40) Bytes "0x03000100 .. 0x0300013F, 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300C0FF, 0x0300CC00 .. 0x0300CCFF, 0x0300FE00 .. 0x0300FFFF, ", 'long' => # more lazy list of constants for cipher "0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300FFFF", 'huge' => # huge range of constants for cipher "0x03000000 .. 0x0300FFFF", 'safe' => # safe full range of constants for cipher # because some network stack (NIC) will crash for 0x033xxxxx "0x03000000 .. 0x032FFFFF", 'full' => # full range of constants for cipher "0x03000000 .. 0x03FFFFFF", # TODO: 0x03000000, 0x03FFFFFF, # used as return by microsoft testserver and also by SSL-honeypot (US) 'SSLv2' => # constants for ciphers according RFC for SSLv2 # see Note(a) above also "0x02000000, 0x02010080, 0x02020080, 0x02030080, 0x02040080, 0x02050080, 0x02060040, 0x02060140, 0x020700C0, 0x020701C0, 0x02FF0800, 0x02FF0810, 0x02FFFFFF, 0x03000000 .. 0x03000002, 0x03000007 .. 0x0300002C, 0x030000FF, 0x0300FEE0, 0x0300FEE1, 0x0300FEFE, 0x0300FEFF, ", # 0x02FF0810, 0x02FF0800, 0x02FFFFFF, # obsolete SSLv2 ciphers # 0x0300FEE0, 0x0300FEE1, 0x0300FEFE, 0x0300FEFF, # obsolete FIPS ciphers # TODO: 0x02000000, 0x02FFFFFF, # increment even only # TODO: 0x03000000, 0x03FFFFFF, # increment odd only 'SSLv2_long'=> # more lazy list of constants for ciphers for SSLv2 "0x02000000, 0x02010080, 0x02020080, 0x02030080, 0x02040080, 0x02050080, 0x02060040, 0x02060140, 0x020700C0, 0x020701C0, 0x02FF0810, 0x02FF0800, 0x02FFFFFF, 0x03000000 .. 0x0300002F, 0x030000FF, 0x0300FEE0, 0x0300FEE1, 0x0300FEFE, 0x0300FEFF, ", 'SSLv3' => # constants for SSLv3 ciphers (without SSLv2 ciphers) "0x03000000 .. 0x0300003A, 0x03000041 .. 0x03000046, 0x03000060 .. 0x03000066, 0x03000080 .. 0x0300009B, 0x0300C000 .. 0x0300C022. 0x0300FEE0 .. 0x0300FEFF, 0x0300FF00 .. 0x0300FF03, 0x0300FF80 .. 0x0300FF83, 0x0300FFFF, ", 'SSLv3_SSLv2' => # constants for SSLv3 ciphers (with SSLv2 ciphers) "0x02000000, 0x02010080, 0x02020080, 0x02030080, 0x02040080, 0x02050080, 0x02060040, 0x02060140, 0x020700C0, 0x020701C0, 0x02FF0810, 0x02FF0800, 0x02FFFFFF, 0x03000000 .. 0x0300003A, 0x03000041 .. 0x03000046, 0x03000060 .. 0x03000066, 0x03000080 .. 0x0300009B, 0x0300C000 .. 0x0300C0FF. 0x0300FEE0 .. 0x0300FEFF, 0x0300FF00 .. 0x0300FF03, 0x0300FF80 .. 0x0300FF83, 0x0300FFFF, ", # TODO: 'SSLv3_old' => # constants for SSLv3 ciphers (without SSLv2 ciphers) # TODO: "0x03000000 .. 0x0300002F, 0x030000FF", # old SSLv3 ciphers # TODO: 'TLSv10' => # same as SSLv3 # TODO: 'TLSv11' => # same as SSLv3 'TLSv12' => # constants for TLSv1.2 ciphers "0x0300003B .. 0x03000040, 0x03000067 .. 0x0300006D, 0x0300009C .. 0x030000A7, 0x030000BA .. 0x030000C5, 0x0300C023 .. 0x0300C032. 0x0300C072 .. 0x0300C079, 0x0300CC13 .. 0x0300CC15, 0x0300FFFF, ", # TODO: 'TLSv13' => # ?? 'c0xx' => "0x0300C000 .. 0x0300C0FF", # constants for ciphers using ecc 'ccxx' => "0x0300CC00 .. 0x0300CCFF", # constants for ciphers using ecc 'ecc' => # constants for ciphers using ecc "0x0300C000 .. 0x0300C0FF, 0x0300CC00 .. 0x0300CCFF", }, # cipherranges 'cipher_dh' => 0, # 1: +cipher also prints DH parameters (default will be changed in future) 'cipher_md5' => 1, # 0: +cipher does not use *-MD5 ciphers except for SSLv2 #{ removed 10/2017 as they are not used #'cipher_alpn' => 1, # 0: +cipher does not use ALPN #'cipher_npn' => 1, # 0: +cipher does not use NPN ($Net::SSLinfo::use_nextprot is for openssl only) #} 'cipher_ecdh' => 1, # 0: +cipher does not use TLS curves extension 'cipher_alpns' => [], # contains all protocols to be passed for +cipher checks 'cipher_npns' => [], # contains all protocols to be passed for +cipher checks 'ciphercurves' => [], # contains all curves to be passed for +cipher checks 'ciphers-v' => 0, # as: openssl ciphers -v 'ciphers-V' => 0, # as: openssl ciphers -V # following keys for commands, nameing scheme: # do - the list off all commands to be performed # commands-* - internal list for various types of commands # cmd-* - list for "summary" commands, can be redifined by user # need-* - list of commands which need a speciphic check # # TODO: need to unify cmd-* and need-* and regex->cmd-*; # see also _need_* functions and "construct list for special commands" # in o-saft.pl # config. key list description #------------------+---------+---------------------------------------------- 'do' => [], # commands to be performed 'commands' => [], # contains all commands from %data, %checks and commands-INT # will be constructed in main, see: construct list for special commands 'commands-CMD' => [], # contains all cmd-* commands from below 'commands-USR' => [], # contains all commands defined by user with # option --cfg-cmd=* ; see _cfg_set() 'commands-EXP' => [ # experimental commands qw(sloth), ], 'commands-NOTYET'=>[ # commands and checks NOT YET IMPLEMENTED qw(zlib lzo open_pgp fallback closure order sgc scsv time), ], 'commands-INT' => [ # add internal commands # these have no key in %data or %checks qw( check cipher dump check_sni exec help info info--v http quick list libversion sizes s_client version quit sigkey bsi ev cipherall cipherraw cipher_dh cipher_default ), # internal (debugging) commands # qw(options cert_type), # will be seen with +info--v only # keys not used as command qw(cn_nosni valid_years valid_months valid_days valid_host) ], 'commands-HINT' => [ # checks which are NOT YET fully implemented # these are mainly all commands for compliance # see also: cmd-bsi qw(rfc_7525 tr_02102+ tr_02102- tr_03116+ tr_03116-) ], 'cmd-beast' => [qw(beast)], # commands for +beast 'cmd-crime' => [qw(crime)], # commands for +crime 'cmd-drown' => [qw(drown)], # commands for +drown 'cmd-freak' => [qw(freak)], # commands for +freak 'cmd-lucky13' => [qw(lucky13)], # commands for +lucky13 'cmd-robot' => [qw(robot)], # commands for +robot 'cmd-sweet32' => [qw(sweet32)], # commands for +sweet32 'cmd-http' => [], # commands for +http, computed below 'cmd-hsts' => [], # commands for +hsts, computed below 'cmd-info' => [], # commands for +info, simply anything from %data 'cmd-info--v' => [], # commands for +info --v 'cmd-check' => [], # commands for +check, simply anything from %checks 'cmd-sizes' => [], # commands for +sizes 'cmd-quick' => [ # commands for +quick qw( sslversion hassslv2 hassslv3 hastls12 cipher_selected cipher_strong cipher_null cipher_adh cipher_exp cipher_cbc cipher_des cipher_rc4 cipher_edh cipher_pfs beast crime drown freak heartbleed logjam lucky13 poodle rc4 robot sloth sweet32 fingerprint_hash fp_not_md5 sha2signature pub_encryption pub_enc_known email serial subject dates verify heartbeat expansion compression hostname hsts_sts crl resumption renegotiation tr_02102+ tr_02102- rfc_7525 )], 'cmd-ev' => [qw(cn subject altname dv ev ev- ev+ ev_chars)], # commands for +ev 'cmd-bsi' => [ # commands for +bsi # see also: commands-HINT qw(after dates crl cipher_rc4 renegotiation tr_02102+ tr_02102- tr_03116+ tr_03116- )], 'cmd-pfs' => [qw(cipher_pfs cipher_pfsall session_random)], # commands for +pfs 'cmd-sni' => [qw(sni hostname certfqdn)], # commands for +sni 'cmd-sni--v' => [qw(sni cn altname verify_altname verify_hostname hostname wildhost wildcard)], 'cmd-vulns' => [ # commands for checking known vulnerabilities qw( beast breach ccs crime drown freak heartbleed logjam lucky13 poodle rc4 robot sloth sweet32 time hassslv2 hassslv3 compression cipher_pfs session_random renegotiation resumption )], 'cmd-prots' => [ # commands for checking protocols qw(hassslv2 hassslv3 hastls10 hastls11 hastls12 hastls13 hasalpn hasnpn session_protocol fallback_protocol alpn alpns npns next_protocols https_protocols http_protocols https_svc http_svc) ], 'ignore-out' => [], # commands (output) to be ignored, SEE Note:ignore-out 'cmd-NL' => [ # commands which need NL when printed # they should be available with +info --v only qw(certificate extensions pem pubkey sigdump text chain chain_verify ocsp_response_data) ], # need-* lists used to improve performance and warning messages 'need-sslv3' => [ # commands which need SSLv3 protocol qw(check cipher cipher_dh cipher_strong cipher_selected protocols hassslv3 beast freak poodle tr_02102+ tr_02102- tr_03116+ tr_03116- rfc_7525 )], 'need-cipher' => [ # commands which need +cipher qw(check cipher cipher_dh cipher_strong cipher_null cipher_adh cipher_cbc cipher_des cipher_edh cipher_exp cipher_rc4 cipher_pfs cipher_pfsall beast crime time breach drown freak logjam lucky13 poodle rc4 robot sloth sweet32 tr_02102+ tr_02102- tr_03116+ tr_03116- rfc_7525 hassslv2 hassslv3 hastls10 hastls11 hastls12 hastls13 )], # TODO: need simple check for protocols 'need-default' => [ # commands which need selected cipher qw(check cipher cipherall cipher_default cipher_pfs cipher_order cipher_strong cipher_selected), qw(sslv3 tlsv1 tlsv10 tlsv11 tlsv12), # following checks may cause errors because # missing functionality (i.e in openssl) # 10/2015 qw(sslv2 tlsv13 dtlsv09 dtlvs1 dtlsv11 dtlsv12 dtlsv13) ], 'need-checkssl' => [ # commands which need checkssl() # TODO: needs to be verified qw(check beast crime time breach freak cipher_pfs cipher_pfsall cipher_cbc cipher_des cipher_edh cipher_exp cipher_rc4 cipher_selected ev+ ev- tr_02102+ tr_02102- tr_03116+ tr_03116- rfc_7525 rfc_6125_names rfc_2818_names )], 'need-checkalnp'=> [ # commands which need checkalpn() qw(alpns alpn hasalpn npns npn hasnpn), ], 'need-checkbleed' => [ qw(heartbleed) ], 'need-check_dh' => [ # commands which need check_dh() qw(logjam dh_512 dh_2048 ecdh_256 ecdh_512) ], 'need-checkdest'=> [ # commands which need checkdest() qw(reversehost ip resumption renegotiation session_protocol session_ticket session_random session_lifetime krb5 psk_hint psk_identity srp heartbeat ocsp_stapling cipher_selected cipher_pfs ccs crime )], 'need-checkhttp'=> [qw(pkp_pins)], # commands which need checkhttp(); more will be added in _init 'need-checkprot'=> [ # commands which need checkprot(), should be same as in 'cmd-prots' qw( sslversion hassslv2 hassslv3 hastls10 hastls11 hastls12 hastls13 alpns alpn hasalpn npns npn hasnpn crime drown poodle )], 'need-checksni' => [ # commands which need checksni() qw(hostname certfqdn cn cn_nosni sni) ], 'need-checkchr' => [ # commands which always need checking various characters qw(cn subject issuer altname ext_crl ocsp_uri), ], 'data_hex' => [ # data values which are in hex values # used in conjunction with --format=hex # not usefull in this list: serial extension qw( fingerprint fingerprint_hash fingerprint_md5 fingerprint_sha1 fingerprint_sha2 sigkey_value pubkey_value modulus master_key session_id session_ticket )], # fingerprint is special, see _ishexdata() #------------------+---------+---------------------------------------------- # option key default description #------------------+---------+---------------------------------------------- 'opt-v' => 0, # 1 when option -v was given 'opt-V' => 0, # 1 when option -V was given 'format' => "", # empty means some slightly adapted values (no \s\n) 'formats' => [qw(csv html json ssv tab xml fullxml raw hex 0x esc)], 'out_header' => 0, # print header lines in output 'out_score' => 0, # print scoring; default for +check 'out_hint' => 1, # 1: print hints; 0: don't print hints 'out_hint_cipher' => 1, # 1: print hints for +cipher command 'out_hint_check'=> 1, # 1: print hints for +check commands 'out_hint_info' => 1, # 1: print hints for +info commands 'tmplib' => "/tmp/yeast-openssl/", # temp. directory for openssl and its libraries 'pass_options' => "", # options to be passeed thru to other programs 'mx_domains' => [], # list of mx-domain:port to be processed 'hosts' => [], # list of targets (host:port) to be processed # since 18.07.18 used in checkAllCiphers.pl only 'targets' => [], # list of targets (host:port) to be processed # anon. list, each element is array, see @target_defaults below 'port' => 443, # port for currently scanned target 'host' => "", # currently scanned target 'ip' => "", # currently scanned target's IP (machine readable format) 'IP' => "", # currently scanned target's IP (human readable, doted octet) 'rhost' => "", # currently scanned target's reverse resolved name 'DNS' => "", # currently scanned target's other IPs and names (DNS aliases) 'timeout' => 2, # default timeout in seconds for connections # Note that some servers do not connect SSL within this time # this may result in ciphers marked as "not supported" # it's recommended to set timeout to 3 or higher, which # results in a performance bottleneck, obviously # see 'sslerror' settings and options also 'openssl' => { # configurations for various openssl functionality #'openssl' => "", # if set, full path of openssl executable # same data structure as in Net::SSLinfo # not all values used yet #--------------+--------+--------------------------------------------- # key (=option) supported=1 warning message if option is missing #--------------+--------+--------------------------------------------- '-alpn' => [ 1, "checks with ALPN disabled"], '-npn' => [ 1, "checks with NPN disabled"], '-nextprotoneg' => [ 1, "checks with NPN disabled"], # alias for -npn '-reconnect' => [ 1, "checks with openssl reconnect disabled"], '-fallback_scsv'=> [ 1, "checks for TLS_FALLBACK_SCSV wrong"], '-comp' => [ 1, "<>"], '-no_comp' => [ 1, "<>"], '-no_tlsext' => [ 1, "<>"], '-no_ticket' => [ 1, "<>"], '-serverinfo' => [ 1, "checks without TLS extension disabled"], '-servername' => [ 1, "checks with TLS extension SNI disabled"], '-serverpref' => [ 1, "<>"], '-showcerts' => [ 1, "<>"], '-curves' => [ 1, "using -curves disabled"], '-debug' => [ 1, "<>"], '-bugs' => [ 1, "<>"], '-key' => [ 1, "<>"], '-msg' => [ 1, "using -msg disabled, DH paramaters missing or wrong"], '-nbio' => [ 1, "<>"], '-psk' => [ 1, "PSK missing or wrong"], '-psk_identity' => [ 1, "PSK identity missing or wrong"], '-pause' => [ 1, "<>"], '-prexit' => [ 1, "<>"], '-proxy' => [ 1, "<>"], '-quiet' => [ 1, "<>"], '-sigalgs' => [ 1, "<>"], '-state' => [ 1, "<>"], '-status' => [ 1, "<>"], '-strict' => [ 1, "<>"], '-client_sigalgs' => [ 1, "<>"], '-tlsextdebug' => [ 1, "TLS extension missing or wrong"], '-record_padding' => [ 1, "<>"], '-no_renegotiation' => [ 1, "<>"], '-legacyrenegotiation' => [ 1, "<>"], '-legacy_renegotiation' => [ 1, "<>"], '-legacy_server_connect' => [ 1, "<>"], '-no_legacy_server_connect' => [ 1, "<>"], '-nbio_test' => [ 1, "<>"], '-CAfile' => [ 1, "using -CAfile disabled"], '-CApath' => [ 1, "using -CApath disabled"], #--------------+--------+--------------------------------------------- }, 'ssleay' => { # configurations for various Net::SSLeay functionality # 1: if available (see _check_functions()) is default 'openssl' => 1, # OPENSSL_VERSION_NUMBER() 'get_alpn' => 1, # P_alpn_selected available() 'get_npn' => 1, # P_next_proto_negotiated() 'set_alpn' => 1, # CTX_set_alpn_protos() 'set_npn' => 1, # CTX_set_next_proto_select_cb() 'can_npn' => 1, # same as get_npn, just an alias 'can_ecdh' => 1, # can_ecdh() 'can_sni' => 1, # for openssl version > 0x01000000 'can_ocsp' => 1, # OCSP_cert2ids 'iosocket' => 1, # $IO::Socket::SSL::VERSION # TODO: wrong container }, 'ssl_error' => 1, # stop connecting to target after ssl-error-max failures 'sslerror' => { # configurations for TCP SSL protocol 'timeout' => 1, # timeout to receive ssl-answer 'max' => 5, # max. consecutive errors 'total' => 10, # max. overall errors # following are NOT YET fully implemented: 'delay' => 0, # if > 0 continue trying to connect after this time 'per_prot' => 1, # if > 0 detection and count are per SSL version 'ignore_no_conn' => 0,# 0: ignore warnings if connection fails, check target anyway # 1: print warnings if connection fails, don't check target 'ignore_handshake' => 1,# 1: treat "failed handshake" as error, don't check target }, 'sslhello' => { # configurations for TCP SSL protocol (mainly used in Net::SSLhello) 'timeout' => 2, # timeout to receive ssl-answer 'retry' => 2, # number of retry when timeout 'maxciphers'=> 32, # number of ciphers sent in SSL3/TLS Client-Hello 'usesignaturealg' => 1, # 1: use extension "signature algorithm" 'useecc' => 1, # 1: use supported elliptic curves 'useecpoint'=> 1, # 1: use ec_point_formats extension 'usereneg' => 0, # 1: secure renegotiation 'double_reneg' => 0, # 0: do not send reneg_info extension if the cipher_spec already includes SCSV # "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" {0x00, 0xFF} 'nodatanocipher'=> 1, # 1: do not abort testing next cipher for some TLS intolerant Servers 'NoData or Timeout Equals to No Cipher' }, 'legacy' => "simple", 'legacys' => [qw(cnark sslaudit sslcipher ssldiagnos sslscan ssltest ssltest-g sslyze testsslserver thcsslcheck openssl simple full compact quick owasp)], # SSLAudit, THCSSLCheck, TestSSLServer are converted using lc() 'showhost' => 0, # 1: prefix printed line with hostname 'usr-args' => [], # list of all arguments --usr* (to be used in o-saft-usr.pm) #------------------+---------+---------------------------------------------- 'data' => { # data provided (mainly used for testing and debugging) 'file_sclient' => "", # file containing data from "openssl s_client " 'file_ciphers' => "", # file containing data from "openssl ciphers" 'file_pem' => "", # file containing certificate(s) in PEM format 'file_pcap' => "", # file containing data in PCAP format # i.e. "openssl s_client -showcerts ..." }, # data #------------------+---------+---------------------------------------------- #------------------+-------------------------------------------------------- 'regex' => { # RegEx for matching commands and options 'cmd-http' => '^h?(?:ttps?|sts)_', # match keys for HTTP 'cmd-hsts' => '^h?sts', # match keys for (H)STS 'cmd-sizes' => '^(?:cnt|len)_', # match keys for length, sizes etc. 'cmd-cfg' => '(?:cmd|checks?|data|info|hint|text|scores?)',# --cfg-* commands 'commands-INT' => '^(?:cn_nosni|valid_(?:year|month|day|host)s?)', # internal data only, no command 'opt-empty' => '(?:[+]|--)(?:cmd|help|host|port|format|legacy|timeout|trace|openssl|(?:cipher|proxy|sep|starttls|exe|lib|ca-|cfg-|ssl-|usr-).*)', # these options may have no value # i.e. --cmd= ; this may occour in CGI mode 'std-format' => '^(?:unix|raw|crlf|utf8|win32|perlio)$', # match keys for --std-format # RegEx for matching SSL protocol keys in %data and %checks 'SSLprot' => '^(SSL|D?TLS)v[0-9]', # match keys SSLv2, TLSv1, ... # RegEx for matching SSL protocol keys in %data and %checks # First some basic RegEx used later on, either in following RegEx or # as $cfg{'regex'}->{...} itself. '_or-' => '[\+_-]', # tools use _ or - as separator character; + used in openssl 'ADHorDHA' => '(?:A(?:NON[_-])?DH|DH(?:A|[_-]ANON))[_-]', # Anonymous DH has various acronyms: # ADH, ANON_DH, DHA, DH-ANON, DH_Anon, ... # TODO:missing: AECDH 'RC4orARC4' => '(?:ARC(?:4|FOUR)|RC4)', # RC4 has other names due to copyright problems: # ARC4, ARCFOUR, RC4 '3DESorCBC3'=> '(?:3DES(?:[_-]EDE)[_-]CBC|DES[_-]CBC3)', # Tripple DES is used as 3DES-CBC, 3DES-EDE-CBC, or DES-CBC3 'DESor3DES' => '(?:[_-]3DES|DES[_-]_192)', # Tripple DES is used as 3DES or DES_192 'DHEorEDH' => '(?:DHE|EDH)[_-]', # DHE and EDH are 2 acronyms for the same thing 'EC-DSA' => 'EC(?:DHE|EDH)[_-]ECDSA', 'EC-RSA' => 'EC(?:DHE|EDH)[_-]RSA', # ECDHE-RSA or ECDHE-ECDSA 'EC' => 'EC(?:DHE|EDH)[_-]', 'EXPORT' => 'EXP(?:ORT)?(?:40|56|1024)?[_-]', # EXP, EXPORT, EXPORT40, EXP1024, EXPORT1024, ... 'FRZorFZA' => '(?:FORTEZZA|FRZ|FZA)[_-]', # FORTEZZA has abbreviations FZA and FRZ # unsure about FORTEZZA_KEA 'SHA2' => 'sha(?:2|224|256|384|512)', # any SHA2, just sha2 is too lazy 'AES-GCM' => 'AES(?:128|256)[_-]GCM[_-]SHA(?:256|384|512)', # any AES128-GCM or AES256-GCM 'SSLorTLS' => '^(?:SSL[23]?|TLS[12]?|PCT1?)[_-]', # Numerous protocol prefixes are in use: # PTC, PCT1, SSL, SSL2, SSL3, TLS, TLS1, TLS2, 'aliases' => '(?:(?:DHE|DH[_-]ANON|DSS|RAS|STANDARD)[_-]|EXPORT_NONE?[_-]?XPORT|STRONG|UNENCRYPTED)', # various variants for aliases to select cipher groups 'compression' =>'(?:DEFLATE|LZO)', # if compression available 'nocompression' =>'(?:NONE|NULL|^\s*$)',# if no compression available 'encryption' =>'(?:encryption|ecPublicKey)', # anything containing this string 'encryption_ok' =>'(?:(?:(?:(?:md[245]|ripemd160|sha(?:1|224|256|384|512))with)?[rd]saencryption)|id-ecPublicKey)', # well known strings to identify signature and public key encryption # rsaencryption, dsaencryption, md[245]withrsaencryption, # ripemd160withrsa shaXXXwithrsaencryption # id-ecPublicKey 'encryption_no' =>'(?:rsa(?:ssapss)?|sha1withrsa|dsawithsha1?|dsa_with_sha256)', # rsa, rsassapss, sha1withrsa, dsawithsha*, dsa_with_sha256 'isIP' => '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)', 'isDNS' => '(?:[a-z0-9.-]+)', 'isIDN' => '(?:xn--)', 'leftwild' => '^\*(?:[a-z0-9.-]+)', 'doublewild' => '(?:[a-z0-9.-]+\*[a-z0-9-]+\*)', # x*x or x*.x* 'invalidwild' => '(?:\.\*\.)', # no .*. 'invalidIDN' => '(?:xn--[a-z0-9-]*\*)', # no * right of xn-- 'isSPDY3' => '(?:spdy\/3)', # match in protocols (NPN) # TODO: lazy match as it matches spdy/3.1 also # TODO: replace following RegEx by concrete list of constants # RegEx matching OWASP TLS Cipher String Cheat Sheet # matching list of concrete constants would be more accurate, but # that cannot be done with RegEx or ranges, unfortunatelly 'OWASP_A' => '^(?:TLSv1[123]?)?(?:EC(?:DHE|EDH).*?(?:AES...[_-]GCM|CHACHA20-POLY1305)[_-]SHA)', 'OWASP_B' => '^(?:TLSv1[123]?)?(?:(EC)?(?:DHE|EDH).*?(?:AES|CHACHA).*?(?!GCM|POLY1305)[_-]SHA)', 'OWASP_C' => '^(?:TLSv1[123]?)?.*?(?:AES...|RSA)[_-]', 'OWASP_D' => '(?:^SSLv[23]|(?:NULL|EXP(?:ORT)?(?:40|56|1024)|A(?:EC|NON[_-])?DH|DH(?:A|[_-]ANON)|ECDSA|DSS|CBC|DES|MD[456]|RC[24]))', 'OWASP_NA' => '(?:ARIA|CAMELLIA|GOST|IDEA|SEED|CECPQ)', # TODO: need exception, i.e. TLSv1 and TLSv11 'notOWASP_A'=> '^(?:TLSv11?)', 'notOWASP_B'=> '', 'notOWASP_C'=> '', 'notOWASP_D'=> '', # RegEx containing pattern to identify vulnerable ciphers # # In a perfect (perl) world we can use negative lokups like # (ABC)(?!XYZ) # which means: contains `ABC' but not `XYZ' where `XYZ' could be to # the right or left of `ABC'. # But in real world some perl implementations fail can't match such # pattern correctly. Hence we define two pattern: one for positive # match and second for the negative (not) match. Both patterns must # be used programatically. # Key 'TYPE' must match and key 'notTYPE' must not match. # The following RegEx define what is "vulnerable": # NOTE: the (?:SSL[23]?|TLS[12]|PCT1?[_-]) protocol prefix is not # yet used in the checks, but its optional in the RegEx here # note also that internal strings are like SSLv2, TLSv11, etc # which would not match the protocol prefix in the RegEx here 'BEAST' => '^(?:SSL[23]?|TLS[12]|PCT1?[_-])?.*?[_-]CBC',# borrowed from 'Lucky13'. There may be another better RegEx. # 'BREACH' => '^(?:SSL[23]?|TLS[12]|PCT1?[_-])?', 'FREAK' => '^(?:SSL[23]?)?(?:EXP(?:ORT)?(?:40|56|1024)?[_-])', # EXP? is same as regex{EXPORT} above 'notCRIME' => '(?:NONE|NULL|^\s*$)', # same as nocompression (see above) # 'TIME' => '^(?:SSL[23]?|TLS[12]|PCT1?[_-])?', 'Lucky13' => '^(?:SSL[23]?|TLS[12]|PCT1?[_-])?.*?[_-]CBC', 'Logjam' => 'EXP(?:ORT)?(?:40|56|1024)?[_-]', # match against cipher # Logjam is same as regex{EXPORT} above 'POODLE' => '^(?:SSL[23]?|TLS1)?[A-Z].*?[_-]CBC', # must not match TLS11, hence [A-Z] 'ROBOT' => '^(?:(?:SSLv?3|TLSv?1(?:[12]))[_-])?(?:A?DH[_-])?(RC2|RC4|RSA)[_-]', 'notROBOT' => '(?:(?:EC)?DHE[_-])', # match against cipher # ROBOT are all TLS_RCA except those with DHE or ECDHE 'SLOTH' => '(?:(EXP(?:ORT)?|NULL).*MD5$|EC(?:DHE|EDH)[_-]ECDSA[_-].*(?:MD5|SHA)$)', 'Sweet32' => '(?:[_-](?:CBC||CBC3|3DES|DES|192)[_-])',# match against cipher 'notSweet32'=> '(?:[_-]AES[_-])', # match against cipher # The following RegEx define what is "not vulnerable": 'PFS' => '^(?:(?:SSLv?3|TLSv?1(?:[12])?|PCT1?)[_-])?((?:EC)?DHE|EDH)[_-]', 'TR-02102' => '(?:DHE|EDH)[_-](?:PSK[_-])?(?:(?:EC)?[DR]S[AS])[_-]', # ECDHE_ECDSA | ECDHE_RSA | DHE_DSS | DHE_RSA PSK_ECDSS # ECDHE_ECRSA, ECDHE_ECDSS or DHE_DSA does not exist, hence lazy RegEx above 'notTR-02102' => '[_-]SHA$', # ciphers with SHA1 hash are not allowed 'TR-02102-noPFS' => '(?:EC)?DH)[_-](?:EC)?(?:[DR]S[AS])[_-]', # if PFS not possible, see TR-02102-2_2016 3.3.1 'TR-03116+' => 'EC(?:DHE|EDH)[_-](?:PSK|(?:EC)?(?:[DR]S[AS]))[_-]AES128[_-](?:GCM[_-])?SHA256', 'TR-03116-' => 'EC(?:DHE|EDH)[_-](?:PSK|(?:EC)?(?:[DR]S[AS]))[_-]AES(?:128|256)[_-](?:GCM[_-])?SHA(?:256|384)', # in strict mode only: # ECDHE-ECDSA-AES128.*SHA256 ECDHE-RSA-AES128.*SHA256 RSA-PSK-AES128-SHA256 ECDHE-PSK-AES128-SHA256 # in lazy mode (for curiosity) we also allow: # ECDHE-ECDSA-AES256.*SHA256 ECDHE-RSA-AES256.*SHA256 # ECDHE-ECDSA-AES256.*SHA384 ECDHE-RSA-AES256.*SHA384 'notTR-03116' => '(?:PSK[_-]AES256|[_-]SHA$)', # NOTE: for curiosity again, notTR-03116 is for strict mode only 'RFC7525' => 'EC(?:DHE|EDH)[_-](?:PSK|(?:EC)?(?:[DR]S[AS]))[_-]AES128[_-](?:GCM[_-])?SHA256', '1.3.6.1.5.5.7.1.1' => '(?:1\.3\.6\.1\.5\.5\.7\.1\.1|authorityInfoAccess)', 'NSA-B' =>'(?:ECD(?:H|SA).*?AES.*?GCM.*?SHA(?:256|384|512))', # RegEx containing pattern for compliance checks # The following RegEx define what is "not compliant": 'notISM' => '(?:NULL|A(?:NON[_-])?DH|DH(?:A|[_-]ANON)[_-]|(?:^DES|[_-]DES)[_-]CBC[_-]|MD5|RC)', 'notPCI' => '(?:NULL|(?:A(?:NON[_-])?DH|DH(?:A|[_-]ANON)|(?:^DES|[_-]DES)[_-]CBC|EXP(?:ORT)?(?:40|56|1024)?)[_-])', 'notFIPS-140'=>'(?:(?:ARC(?:4|FOUR)|RC4)|MD5|IDEA)', 'FIPS-140' => '(?:(?:3DES(?:[_-]EDE)[_-]CBC|DES[_-]CBC3)|AES)', # these are compliant # RegEx for checking invalid characers (used in compliance and EV checks) 'nonprint' => '/[\x00-\x1f\x7f-\xff]+/', # not printable; m/[:^print:]/ 'crnlnull' => '/[\r\n\t\v\0]+/', # CR, NL, TABS and NULL # RegEx for checking EV-SSL # they should matching: /key=value/other-key=other-value '2.5.4.10' => '(?:2\.5\.4\.10|organizationName|O)', '2.5.4.11' => '(?:2\.5\.4\.1?|organizationalUnitName|OU)', '2.5.4.15' => '(?:2\.5\.4\.15|businessCategory)', '2.5.4.3' => '(?:2\.5\.4\.3|commonName|CN)', '2.5.4.5' => '(?:2\.5\.4\.5|serialNumber)', '2.5.4.6' => '(?:2\.5\.4\.6|countryName|C)', '2.5.4.7' => '(?:2\.5\.4\.7|localityName|L)', '2.5.4.8' => '(?:2\.5\.4\.8|stateOrProvinceName|SP|ST)', # TODO: is ST a bug? '2.5.4.9' => '(?:2\.5\.4\.9|street(?:Address)?)', # '/street=' is very lazy '2.5.4.17' => '(?:2\.5\.4\.17|postalCode)', # '?.?.?.?' => '(?:?\.?\.?\.?|domainComponent|DC)', # '?.?.?.?' => '(?:?\.?\.?\.?|surname|SN)', # '?.?.?.?' => '(?:?\.?\.?\.?|givenName|GN)', # '?.?.?.?' => '(?:?\.?\.?\.?|pseudonym)', # '?.?.?.?' => '(?:?\.?\.?\.?|initiala)', # '?.?.?.?' => '(?:?\.?\.?\.?|title)', '1.3.6.1.4.1.311.60.2.1.1' => '(?:1\.3\.6\.1\.4\.1\.311\.60\.2\.1\.1|jurisdictionOfIncorporationLocalityName)', '1.3.6.1.4.1.311.60.2.1.2' => '(?:1\.3\.6\.1\.4\.1\.311\.60\.2\.1\.2|jurisdictionOfIncorporationStateOrProvinceName)', '1.3.6.1.4.1.311.60.2.1.3' => '(?:1\.3\.6\.1\.4\.1\.311\.60\.2\.1\.3|jurisdictionOfIncorporationCountryName)', 'EV-chars' => '[a-zA-Z0-9,./:= @?+\'()-]', # valid characters in EV definitions 'notEV-chars'=>'[^a-zA-Z0-9,./:= @?+\'()-]', # not valid characters in EV definitions 'EV-empty' => '^(?:n\/a|(?:in|not )valid)\s*$', # empty string, or "invalid" or "not valid" }, # regex #------------------+-------------------------------------------------------- 'hints' => { # texts used for hints # 'key' => "any string, may contain \t and \n", # # Key can be any string. If key is same as a valid command (without # leading +), such hints are printed automatically (see below). # Hint texts can be defined here or anywhere in the code, for example # right at the place where they are used. A definition somewhere else # in the code should look like: # $cfg{'hints'}->{'your-key'} = "your text\nwith a newline"; # This allows that the texts can be customised using the option: # --cfg-hints=your-key="other text" # How automatic printing works: # Hint texts can be defined for any valid command (see above). When # results are printed, print_check() and print_data() will auto- # matically print such hint texts if any. # However, hint texts can be printed anywhere at anytime using: # printhint('your-key'), # It is not recommended to use: # print STR_HINT, "my text"; }, # hints #------------------+-------------------------------------------------------- 'ourstr' => { # RegEx to match strings of our own output, see OUTPUT in o-saft-man.pm # first all that match a line at beginning: 'error' => qr(^\*\*ERR), # see STR_ERROR 'warning' => qr(^\*\*WARN), # see STR_WARN 'hint' => qr(^\!\!Hint), # see STR_HINT 'dbx' => qr(^#dbx#), # see STR_DBX 'headline' => qr(^={1,3} ), # headlines 'keyline' => qr(^#\[), # dataline prefixed with key 'verbose' => qr(^#[^[]), # verbose output # matches somewhere in the line: 'undef' => qr(\<\ qr(\<\<.*?\>\>), # additional informations 'na' => qr(N\/A), # N/A 'yes' => qr(:\s*yes), # good check result; # TODO: : needs to be $text{separator} 'no' => qr(:\s*no ), # bad check result }, # ourstr #------------------+-------------------------------------------------------- 'compliance' => { # description of RegEx above for compliance checks 'TR-02102' => "no RC4, only eclipic curve, only SHA256 or SHA384, need CRL and AIA, no wildcards, and verifications ...", 'TR-03116' => "TLSv1.2, only ECDSA, RSA or PSK ciphers, only eclipic curve, only SHA224 or SHA256, need OCSP-Stapling CRL and AIA, no wildcards, and verifications ...", 'ISM' => "no NULL cipher, no Anonymous Auth, no single DES, no MD5, no RC ciphers", 'PCI' => "no NULL cipher, no Anonymous Auth, no single DES, no Export encryption, DH > 1023", 'FIPS-140' => "must be TLSv1 or 3DES or AES, no IDEA, no RC4, no MD5", 'FIPS-140-2'=> "-- NOT YET IMPLEMENTED --", # TODO: 'RFC7525' => "TLS 1.2; AES with GCM; ECDHE and SHA256 or SHA384; HSTS", # # NIST SP800-52 recommendations for clients (best first): # TLS_DHE_DSS_WITH_AES_256_CBC_SHA # TLS_DHE_RSA_WITH_AES_256_CBC_SHA # TLS_RSA_WITH_AES_256_CBC_SHA # TLS_DH_DSS_WITH_AES_256_CBC_SHA # TLS_DH_RSA_WITH_AES_256_CBC_SHA # TLS_DHE_DSS_WITH_AES_128_CBC_SHA # TLS_DHE_RSA_WITH_AES_128_CBC_SHA # TLS_RSA_WITH_AES_128_CBC_SHA # TLS_DH_DSS_WITH_AES_128_CBC_SHA # TLS_DH_RSA_WITH_AES_128_CBC_SHA # TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA # TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA # TLS_RSA_WITH_3DES_EDE_CBC_SHA # TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA # TLS_DH_RSA_WITH_3DES_EDE_CBC # TLS_RSA_WITH_RC4_128_SHA2 # # NIST SP800-52 recommendations for server (best first): # same as above except TLS_RSA_WITH_RC4_128_SHA2 # # Supported by (most) browsers (see SSL_comp_report2011.pdf): # TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384 (IE8 only) # TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA* # TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA* # TLS_DHE_RSA_WITH_AES_256_CBC_SHA # TLS_DHE_RSA_WITH_AES_128_CBC_SHA # TLS_RSA_WITH_RC4_128_SHA # TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA # # NIST SP800-57 recommendations for key management (part 1): 'NSA-B' => "must be AES with CTR or GCM; ECDSA or ECDH and SHA256 or SHA512", }, 'sig_algorithms' => [ # signature algorithms; (2016) not yet used qw( dsaEncryption dsaEncryption-old dsaWithSHA dsaWithSHA1 dsa_With_SHA256 ecdsa-with-SHA256 md2WithRSAEncryption md4WithRSAEncryption md5WithRSAEncryption None ripemd160WithRSA rsa rsaEncryption rsassapss shaWithRSAEncryption sha1WithRSAEncryption sha1WithRSA sha224WithRSAEncryption sha256WithRSAEncryption sha384WithRSAEncryption sha512WithRSAEncryption ), "rsassapss (invalid pss parameters)" ], 'sig_algorithm_common' => [ # most common signature algorithms; (2016) not yet used qw(None ecdsa-with-SHA256 sha1WithRSAEncryption sha256WithRSAEncryption sha384WithRSAEncryption sha512WithRSAEncryption ) ], 'openssl_option_map' => { # map our internal option to openssl option; used our Net:SSL* # will be initialized from %prot }, 'openssl_version_map' => { # map our internal option to openssl version (hex value); used our Net:SSL* # will be initialized from %prot }, 'done' => {}, # defined in caller #------------------+---------+---------------------------------------------- ); # %cfg our %target_desc = ( #--------------+----------------------------------------------------------- # key description #--------------+----------------------------------------------------------- 'Nr' , # unique index number, idx=0 used for default settings 'Protocol' , # protocol to be checked (schema in URL) 'Host' , # hostname or IP passed as argument, IPv6 enclosed in [] 'Port' , # port as passed as argument or default 'Auth' , # authentication string used in URL, if any 'Proxy' , # proxy to be used for connection, index to cfg{targets}[] # 0 if no proxy, -1 for a proxy itself 'Path' , # path used in URL 'orig. Argument', # original argument, used for debugging only # following are run-time values 'Time started', # timestamp, connection request started 'Time opened' , # timestamp, connection request completed 'Time stopped', # timestamp, connection closed 'Errors' , # encountered connection errors # TODO: may be changed to list of errors in future #--------------+----------------------------------------------------------- ); # %target_desc # Nr, Prot., Host, Port, Auth, Proxy, Path, orig., run-time ... our @target_defaults = [ 0, "https", "", "443", "", 0, "", "", 0, 0, 0, 0, ]; our %dbx = ( # save hardcoded settings (command lists, texts), and debugging data # used in o-saft-dbx.pm only 'argv' => undef, # normal options and arguments 'cfg' => undef, # config options and arguments 'exe' => undef, # executable, library, environment 'file' => undef, # read files 'cmd-check' => undef, 'cmd-http' => undef, 'cmd-info' => undef, 'cmd-quick' => undef, ); # %dbx #_____________________________________________________________________________ #__________________________________________________________________ methods __| =pod =head2 get_cipher_suitename($cipher) =head2 get_cipher_suiteconst($cipher) =head2 get_cipher_suitealias($cipher) Get information from internal C<%cipher_names> data structure. =head2 get_cipher_sec($cipher) =head2 get_cipher_ssl($cipher) =head2 get_cipher_enc($cipher) =head2 get_cipher_bits($cipher) =head2 get_cipher_mac($cipher) =head2 get_cipher_auth($cipher) =head2 get_cipher_keyx($cipher) =head2 get_cipher_score($cipher) =head2 get_cipher_tags($cipher) =head2 get_cipher_desc($cipher) Get information from internal C<%cipher> data structure. =cut sub tls_const2text { my $c=shift; $c =~ s/_/ /g; return $c; } sub get_cipher_suitename { my $c=shift; return $cipher_names{$c}[0] if (defined $cipher_names{$c}[0]); return ""; } sub get_cipher_suiteconst{ my $c=shift; return $cipher_names{$c}[1] if (defined $cipher_names{$c}[1]); return ""; } sub get_cipher_suitealias{ my $c=shift; return $cipher_alias{$c}[0] if (defined $cipher_alias{$c}[0]); return ""; } # some people prefer to use a getter function to get data from objects # each function returns a spcific value (column) from the %cipher table # see %ciphers_desc about description of the columns # returns STR_UNDEF if requested cipher is missing sub get_cipher_sec($) { my $c=shift; return $ciphers{$c}[0] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_ssl($) { my $c=shift; return $ciphers{$c}[1] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_enc($) { my $c=shift; return $ciphers{$c}[2] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_bits($) { my $c=shift; return $ciphers{$c}[3] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_mac($) { my $c=shift; return $ciphers{$c}[4] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_auth($) { my $c=shift; return $ciphers{$c}[5] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_keyx($) { my $c=shift; return $ciphers{$c}[6] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_score($) { my $c=shift; return $ciphers{$c}[7] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_tags($) { my $c=shift; return $ciphers{$c}[8] || "" if ((grep{/^$c/} %ciphers)>0); return STR_UNDEF; } sub get_cipher_desc($) { my $c=shift; # get description for specified cipher from %ciphers if (not defined $ciphers{$c}) { _warn("016: undefined cipher description for '$c'"); # TODO: correct %ciphers return STR_UNDEF; } my @c = @{$ciphers{$c}}; shift @c; return @c if ((grep{/^$c/} %ciphers)>0); return ""; } # get_cipher_desc =pod =head2 get_cipher_hex($cipher) Get cipher's hex key from C<%cipher_names> or C<%cipher_alias> data structure. =head2 get_cipher_name($cipher) Check if given C<%cipher> name is a known cipher. =head2 get_cipher_owasp($cipher) Get OWASP rating of given C<%cipher>. =cut sub get_cipher_hex { # find hex key for cipher in %cipher_names or %cipher_alias # FIXME: need $ssl parameter because of duplicate names (SSLv3, TLSv19 my $c = shift; foreach my $k (keys %cipher_names) { # database up to VERSION 14.07.14 return $k if (($c eq get_cipher_suitename($k)) or ($c eq get_cipher_suiteconst($k))); } foreach my $k (keys %cipher_alias) { # not yet found, check for alias return $k if ($c eq $cipher_alias{$k}[0]); } foreach my $k (keys %cipher_old) { # not yet found, check old names return $k if ($c eq $cipher_old{$k}[0]); } return ""; } # get_cipher_hex sub get_cipher_name { # check if given cipher name is a known cipher # checks in %ciphers if nof found in %cipher_names # FIXME: need $ssl parameter because of duplicate names (SSLv3, TLSv19 my $cipher = shift; return $cipher if (0 < grep{/^$cipher/} %ciphers); _trace("get_cipher_name: search $cipher"); foreach my $k (keys %cipher_names) { my $suite = get_cipher_suitename($k); return $suite if ($cipher =~ m/$cipher_names{$k}[0]/); return $suite if (get_cipher_suiteconst($k) =~ /$cipher/); } # nothing found yet, try more lazy match foreach my $k (keys %cipher_names) { my $suite = get_cipher_suitename($k); if ($suite =~ m/$cipher/) { _warn("017: partial match for cipher name found '$cipher'"); return $suite; } } return ""; } # get_cipher_name sub get_cipher_owasp { # return OWASP rating for cipher (see $cfg{regex}->{{OWASP_*} my $cipher = shift; my $sec = "miss"; # following sequence is important: $sec = "-?-" if ($cipher =~ /$cfg{'regex'}->{'OWASP_NA'}/); # unrated in OWASP TLS Cipher Cheat Sheet (2018) $sec = "C" if ($cipher =~ /$cfg{'regex'}->{'OWASP_C'}/); # 1st legacy $sec = "B" if ($cipher =~ /$cfg{'regex'}->{'OWASP_B'}/); # 2nd broad compatibility $sec = "A" if ($cipher =~ /$cfg{'regex'}->{'OWASP_A'}/); # 3rd best practice $sec = "D" if ($cipher =~ /$cfg{'regex'}->{'OWASP_D'}/); # finally brocken ciphers, overwrite previous if (" D" ne $sec) { # if it is A, B or C check OWASP_NA again $sec = "-?-" if ($cipher =~ /$cfg{'regex'}->{'OWASP_NA'}/); } # TODO: implement when necessary: notOWASP_A, notOWASP_B, notOWASP_C, notOWASP_D return $sec; } # get_ciphers_list =pod =head2 get_openssl_version($cmd) Call external $cmd (which is a full path for L, usually) executable to retrive its version. Returns version string. =cut sub get_openssl_version { # we do a simple call, no checks, should work on all platforms # get something like: OpenSSL 1.0.1k 8 Jan 2015 my $cmd = shift; my $data = qx($cmd version); chomp $data; _trace("get_openssl_version: $data"); $data =~ s#^.*?(\d+(?:\.\d+)*).*$#$1#; # get version number without letters _trace("get_openssl_version()\t= $data"); return $data; } # get_openssl_version =pod =head2 get_dh_paramter($cipher, $data) Parse output of `openssl -msg' (given in $data) and returns DH parameters. Returns empty string if none found. =cut sub get_dh_paramter { my ($cipher, $data) = @_; if ($data =~ m#Server Temp Key:#) { $data =~ s/.*?Server Temp Key:\s*([^\n]*)\n.*/$1/si; _trace("get_dh_paramter(){ Server Temp Key\t= $data }"); return $data; } # else continue extracting DH parameters from ServerKeyExchange-Message my $dh = ""; # we may get a ServerKeyExchange-Message with the -msg option # <<< TLS 1.2 Handshake [length 040f], ServerKeyExchange # 0c 00 04 0b 01 00 c1 41 38 da 2e b3 7e 68 71 31 # 86 da 01 e5 95 fa 7e 83 9b a2 28 1b a5 fb d2 72 # ... # >>> TLS 1.2 ChangeCipherSpec [length 0001] return "" if ($data !~ m#ServerKeyExchange#); # this is a long RegEx and cannot be chunked ## no critic qw(RegularExpressions::ProhibitComplexRegexes) $data =~ s{ .*?Handshake \s*?\[length\s*([0-9a-fA-F]{2,4})\]\,? \s*?ServerKeyExchange \s*[\n\r]+(.*?) [\n\r][<>]+.* } {$1_$2}xsi; ## use critic _trace("get_dh_paramter: #{ DHE RAW data:\n$data\n#}\n"); $data =~ s/\s+/ /gi; # squeeze multible spaces $data =~ s/[^0-9a-f_]//gi; # remove all none hex characters and non seperator my ($lenStr, $len) = 0; ($lenStr, $data) = split(/_/, $data); # 2 strings with Hex Octetts! _trace3("get_dh_paramter: #{ DHE RAW data): len: $lenStr\n$data\n#}\n"); $len = hex($lenStr); my $message = pack("H*", $data); # parse message header my $msgData = ""; my ($msgType, $msgFirstByte, $msgLen) = 0; ($msgType, # C $msgFirstByte, # C $msgLen, # n $msgData) = unpack("C C n a*", $message); if (0x0C == $msgType) { # is ServerKeyExchange # get info about the session cipher and prepare parameter $keyExchange # for parseServerKeyExchange() my $keyExchange = $cipher; _trace1("get_dh_paramter: cipher: $keyExchange"); $keyExchange =~ s/^((?:EC)?DHE?)_anon.*/A$1/; # DHE_anon -> EDH, ECDHE_anon -> AECDH, DHE_anon -> ADHE $keyExchange =~ s/^((?:EC)?DH)E.*/E$1/; # DHE -> EDH, ECDHE -> EECDH $keyExchange =~ s/^(?:E|A|EA)((?:EC)?DH).*/$1/; # EDH -> DH, ADH -> DH, EECDH -> ECDH _trace1(" get_dh_paramter: keyExchange (DH or ECDH) = $keyExchange"); # get length of 'dh_parameter' manually from '-msg' data if the # 'session cipher' uses a keyExchange with DHE and DH_anon # (according RFC2246/RFC5246: sections 7.4.3) $dh = Net::SSLhello::parseServerKeyExchange($keyExchange, $msgLen, $msgData); } chomp $dh; _trace("get_dh_paramter(){ ServerKeyExchange\t= $dh }"); return $dh; } # get_dh_paramter =pod =head2 sort_cipher_names(@ciphers) Sort given list of C<@ciphers> according their strength, most strongest first. returns sorted list of ciphers. C<@ciphers> is a list of cipher suite names. These names should be those used by openssl(1) . =cut sub sort_cipher_names { # cipher suites must be given as array # NOTE: the returned list may not be exactly sorted according the cipher's # strength, just roughly # known insecure, i.e. CBC, DES, NULL, etc. ciphers are added at the end # all ciphers classified "insecure" are added to end of the result list, # these (insecure) ciphers are not sorted according their strength as it # doesn't make much sense to distinguish "more" or "less" insecure my @ciphers = @_; my @sorted ; my @latest ; my $cnt_in = scalar @ciphers; # number of passed ciphers; see check at end # Algorithm: # 1. remove all known @insecure ciphers from given list # 2. start building new list with most @strength cipher first # 3. add previously remove @insecure ciphers to new list # define list of RegEx to match openssl cipher suite names # each RegEx could be seen as a class of ciphers with the same strength # the list defines the strength in descending order, most strength first # NOTE the list may contain pattern, which actually do not match a valid # cipher suite name; doese't matter, but may avoid future adaptions, see # warning at end also my @insecure = ( qw((?:RC[24])) , # all RC2 and RC4 qw((?:CBC|DES)) , # all CBC, DES, 3DES qw((?:DSS)) , # all DSS qw((?:MD[2345])), # all MD qw(DH.?(?i:anon)) , # Anon needs to be caseless qw((?:NULL)) , # all NULL ); my @strength = ( qw(CECPQ1[_-].*?CHACHA) , qw(CECPQ1[_-].*?AES256.GCM) , qw((?:ECDHE|EECDH).*?CHACHA) , # 1. all ecliptical curve, ephermeral, GCM qw((?:ECDHE|EECDH).*?512.GCM) , # .. sorts -ECDSA before -RSA qw((?:ECDHE|EECDH).*?384.GCM) , qw((?:ECDHE|EECDH).*?256.GCM) , qw((?:ECDHE|EECDH).*?128.GCM) , qw((?:EDH|DHE).*?CHACHA) , # 2. all ephermeral, GCM qw((?:EDH|DHE).*?512.GCM) , # .. sorts AES before CAMELLIA qw((?:EDH|DHE).*?384.GCM) , qw((?:EDH|DHE).*?256.GCM) , qw((?:EDH|DHE).*?128.GCM) , qw(ECDH[_-].*?CHACHA) , # 3. all ecliptical curve, GCM qw(ECDH[_-].*?512.GCM) , # .. sorts -ECDSA before -RSA qw(ECDH[_-].*?384.GCM) , qw(ECDH[_-].*?256.GCM) , qw(ECDH[_-].*?128.GCM) , qw(ECDHE.*?CHACHA) , # 4. all remaining ecliptical curve, ephermeral qw(ECDHE.*?512) , qw(ECDHE.*?384) , qw(ECDHE.*?256) , qw(ECDHE.*?128) , qw(ECDH[_-].*?CHACHA), # 5. all remaining ecliptical curve qw(ECDH[_-].*?512) , qw(ECDH[_-].*?384) , qw(ECDH[_-].*?256) , qw(ECDH[_-].*?128) , qw(AES) , # 5. all AES and specials qw(KRB5) , qw(SRP) , qw(PSK) , qw(GOST) , qw((?:EDH|DHE).*?CHACHA) , # 6. all DH qw((?:EDH|DHE).*?512) , qw((?:EDH|DHE).*?384) , qw((?:EDH|DHE).*?256) , qw((?:EDH|DHE).*?128) , qw((?:EDH|DHE).*?(?:RSA|DSS)) , qw(CAMELLIA) , # 7. unknown strength qw((?:SEED|IDEA)) , qw(RSA[_-]) , # 8. qw(DH[_-]) , qw(RC) , qw(EXP) , # 9. Export ... qw(AEC.*?256) , # insecure qw(AEC.*?128) , qw(AEC) , qw(ADH.*?256) , # no encryption qw(ADH.*?128) , qw(ADH) , ); foreach my $rex (@insecure) { # remove all known insecure suites _trace2("sort_cipher_names: insecure regex\t= $rex }"); push(@latest, grep{ /$rex/} @ciphers); # add matches to result @ciphers = grep{!/$rex/} @ciphers; # remove matches from original list } foreach my $rex (@strength) { # sort according strength $rex = qr/^(?:(?:SSL|TLS)[_-])?$rex/; # allow IANA constant names too _trace2("sort_cipher_names: strong regex\t= $rex }"); push(@sorted, grep{ /$rex/} @ciphers); # add matches to result @ciphers = grep{!/$rex/} @ciphers; # remove matches from original list } push(@sorted, @latest); # add insecure ciphers again my $cnt_out = scalar @sorted; if ($cnt_in != $cnt_out) { # print warning if above algorithm misses ciphers; # uses perl's warn() instead of our _warn() to clearly inform the user # that the code here needs to be fixed warn STR_WARN . "015: missing ciphers in sorted list: $cnt_out < $cnt_in"; ## no critic qw(ErrorHandling::RequireCarping) #dbx# print "## ".@sorted . " # @ciphers"; } @sorted = grep{!/^\s*$/} @sorted; # remove empty names, if any ... return @sorted; } # sort_cipher_names # TODO: get_target_* and set_target_* should be named get_cfg_target_* ... =pod =head2 get_target_nr($idx) =head2 get_target_prot($idx) =head2 get_target_host($idx) =head2 get_target_port($idx) =head2 get_target_auth($idx) =head2 get_target_proxy($idx) =head2 get_target_path($idx) =head2 get_target_orig($idx) =head2 get_target_start($idx) =head2 get_target_open($idx) =head2 get_target_stop($idx) =head2 get_target_error($idx) Get information from internal C<%cfg{'targets'}> data structure. =head2 set_target_nr($idx, $index) =head2 set_target_prot($idx, $protocol) =head2 set_target_host($idx, $host_or_IP) =head2 set_target_port($idx, $port) =head2 set_target_auth($idx, $auth-string) =head2 set_target_proxy($idx, $proxy-index)) =head2 set_target_path($idx $path) =head2 set_target_orig($idx, $original-argument)) =head2 set_target_start($idx, $start-timestamp) =head2 set_target_open($idx, $open-timestamp) =head2 set_target_stop($idx, $end-timestamp) =head2 set_target_error($idx, $errors) Set information in internal C<%cfg{'targets'}> data structure. =cut sub get_target_nr { my $i=shift; return $cfg{'targets'}[$i][0]; } sub get_target_prot { my $i=shift; return $cfg{'targets'}[$i][1]; } sub get_target_host { my $i=shift; return $cfg{'targets'}[$i][2]; } sub get_target_port { my $i=shift; return $cfg{'targets'}[$i][3]; } sub get_target_auth { my $i=shift; return $cfg{'targets'}[$i][4]; } sub get_target_proxy { my $i=shift; return $cfg{'targets'}[$i][5]; } sub get_target_path { my $i=shift; return $cfg{'targets'}[$i][6]; } sub get_target_orig { my $i=shift; return $cfg{'targets'}[$i][7]; } sub get_target_start { my $i=shift; return $cfg{'targets'}[$i][8]; } sub get_target_open { my $i=shift; return $cfg{'targets'}[$i][9]; } sub get_target_stop { my $i=shift; return $cfg{'targets'}[$i][10]; } sub get_target_error { my $i=shift; return $cfg{'targets'}[$i][11]; } sub set_target_nr { my $i=shift; $cfg{'targets'}[$i][0] = shift; return; } sub set_target_prot { my $i=shift; $cfg{'targets'}[$i][1] = shift; return; } sub set_target_host { my $i=shift; $cfg{'targets'}[$i][2] = shift; return; } sub set_target_port { my $i=shift; $cfg{'targets'}[$i][3] = shift; return; } sub set_target_auth { my $i=shift; $cfg{'targets'}[$i][4] = shift; return; } sub set_target_proxy { my $i=shift; $cfg{'targets'}[$i][5] = shift; return; } sub set_target_path { my $i=shift; $cfg{'targets'}[$i][6] = shift; return; } sub set_target_orig { my $i=shift; $cfg{'targets'}[$i][7] = shift; return; } sub set_target_start { my $i=shift; $cfg{'targets'}[$i][8] = shift; return; } sub set_target_open { my $i=shift; $cfg{'targets'}[$i][9] = shift; return; } sub set_target_stop { my $i=shift; $cfg{'targets'}[$i][10] = shift; return; } sub set_target_error { my $i=shift; $cfg{'targets'}[$i][11] = shift; return; } #_____________________________________________________________________________ #_________________________________________________________ internal methods __| sub _prot_init_value { #? initialize default values in %prot foreach my $ssl (keys %prot) { $prot{$ssl}->{'cnt'} = 0; $prot{$ssl}->{'-?-'} = 0; $prot{$ssl}->{'WEAK'} = 0; $prot{$ssl}->{'LOW'} = 0; $prot{$ssl}->{'MEDIUM'} = 0; $prot{$ssl}->{'HIGH'} = 0; $prot{$ssl}->{'OWASP_A'} = 0; $prot{$ssl}->{'OWASP_B'} = 0; $prot{$ssl}->{'OWASP_C'} = 0; $prot{$ssl}->{'OWASP_D'} = 0; $prot{$ssl}->{'OWASP_NA'} = 0; $prot{$ssl}->{'OWASP_miss'} = 0; # for internal use $prot{$ssl}->{'protocol'} = 0; $prot{$ssl}->{'ciphers_pfs'} = []; $prot{$ssl}->{'cipher_pfs'} = STR_UNDEF; $prot{$ssl}->{'default'} = STR_UNDEF; $prot{$ssl}->{'cipher_strong'} = STR_UNDEF; $prot{$ssl}->{'cipher_weak'} = STR_UNDEF; } return; } # _prot_init_value sub _cfg_init { # initialize targets with entry containing defaults push(@{$cfg{'targets'}}, @target_defaults); #? initialize dynamic settings in %cfg, copy data from %prot $cfg{'openssl_option_map'}->{$_} = $prot{$_}->{'opt'} foreach (keys %prot); $cfg{'openssl_version_map'}->{$_} = $prot{$_}->{'hex'} foreach (keys %prot); $cfg{'protos_alpn'} = [split(/,/, $cfg{'protos_next'})]; $cfg{'protos_npn'} = [split(/,/, $cfg{'protos_next'})]; # initialize alternate protocols and curves for cipher checks $cfg{'cipher_alpns'}= [split(/,/, $cfg{'protos_next'})]; $cfg{'cipher_npns'} = [split(/,/, $cfg{'protos_next'})]; $cfg{'ciphercurves'}= [ qw(prime192v1 prime256v1), qw(sect163k1 sect163r1 sect193r1 sect233k1 sect233r1), qw(sect283k1 sect283r1 sect409k1 sect409r1 sect571k1 sect571r1), qw(secp160k1 secp160r1 secp160r2 secp192k1 secp224k1 secp224r1), qw(secp256k1 secp384r1 secp521r1), qw(brainpoolP256r1 brainpoolP384r1 brainpoolP512r1), # TODO: list NOT YET complete, see %tls_curves # adapted to Mosman's openssl 1.0.2dev (5/2017) #qw(ed25519 ecdh_x25519 ecdh_x448), #qw(prime192v2 prime192v3 prime239v1 prime239v2 prime239v3), #qw(sect193r2 secp256r1 ), ]; # incorporate some environment variables $cfg{'openssl_env'} = $ENV{'OPENSSL'} if (defined $ENV{'OPENSSL'}); $cfg{'openssl_cnf'} = $ENV{'OPENSSL_CONF'} if (defined $ENV{'OPENSSL_CONF'}); $cfg{'openssl_fips'}= $ENV{'OPENSSL_FIPS'} if (defined $ENV{'OPENSSL_FIPS'}); return; } # _cfg_init sub _cmd_init { #? initialize dynamic settings in %cfg for commands foreach my $key (keys %cfg) { # well-known "summary" commands push(@{$cfg{'commands-CMD'}}, $key) if ($key =~ m/^cmd-/); } return; } # _cmd_init sub _dbx_init { #? initialize settings for debugging $dbx{'cmd-check'} = $cfg{'cmd-check'}; $dbx{'cmd-http'} = $cfg{'cmd-http'}; $dbx{'cmd-info'} = $cfg{'cmd-info'}; $dbx{'cmd-quick'} = $cfg{'cmd-quick'}; push(@{$dbx{file}}, "osaft.pm"); # set myself return; } # _dbx_init sub _osaft_init { #? additional generic initializations for data structures my $me = $0; # done here to instead of package's "main" to avoid $me =~ s#.*[/\\]##; # multiple variable definitions of $me $cfg{'me'} = $me; $cfg{'RC-FILE'} = "./.$me"; $cfg{'ARG0'} = $0; $cfg{'ARGV'} = [@ARGV]; $cfg{'prefix_trace'} = "#${me}::"; $cfg{'prefix_verbose'} = "#${me}: "; _prot_init_value(); # initallize WEAK, LOW, MEDIUM, HIGH, default, pfs, protocol _cfg_init(); # initallize dynamic data in %cfg _cmd_init(); # initallize dynamic commands in %cfg _dbx_init(); # initallize debugging data in %dbx foreach my $k (keys %data_oid) { $data_oid{$k}->{val} = "<>"; # set a default value } return; } # _osaft_init =pod =head2 osaft::printhint($cmd,@text) Print hint for specified command, additionl text will be appended. =head2 osaft::osaft_sleep($wait) Wrapper to simulate "slee" with perl's select. =cut sub printhint { ## no critic qw(Subroutines::RequireArgUnpacking) # buggy perlcritic #? Print hint for specified command. my $cmd = shift; my @args = @_; print STR_HINT, $cfg{'hints'}->{$cmd}, join(" ", @args) if (defined $cfg{'hints'}->{$cmd}); return; } # printhint sub osaft_sleep { #? wrapper for IO::select my $wait = shift; select(undef, undef, undef, $wait); return; } # osaft_sleep sub osaft_done {}; # dummy to check successful include _osaft_init(); # complete initializations ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =head1 NOTES It's often recommended not to export constants and variables from modules, see for example http://perldoc.perl.org/Exporter.html#Good-Practices . The main purpose of this module is defining variables. Hence we export them. =head1 SEE ALSO # ... =head1 AUTHOR 28-dec-15 Achim Hoffmann =cut #_____________________________________________________________________________ #_____________________________________________________________________ self __| # TODO: interanl wrappers for main's methods # they are defined after the ## PACKAGE mark to avoid errors in the # script generated by contrib/gen_standalone.sh sub _trace { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking) sub _trace0 { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking) sub _trace1 { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking) sub _trace2 { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking) sub _trace3 { ::_trace(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking) sub _warn { ::_warn(@_); return; } ## no critic qw(Subroutines::RequireArgUnpacking) unless (defined caller) { # print myself or open connection printf("# %s %s\n", __PACKAGE__, $VERSION); if (eval {require POD::Perldoc;}) { # pod2usage( -verbose => 1 ); exit( Pod::Perldoc->run(args=>[$0]) ); } if (qx(perldoc -V)) { # may return: You need to install the perl-doc package to use this program. #exec "perldoc $0"; # scary ... printf("# no POD::Perldoc installed, please try:\n perldoc $0\n"); exit 0; } } # !caller 1; O-Saft-19.01.19/t/000077500000000000000000000000001342117255600133165ustar00rootroot00000000000000O-Saft-19.01.19/t/.perlcriticrc000066400000000000000000000410741342117255600160120ustar00rootroot00000000000000#! /usr/bin/perlcritic #? #? NAME #? .perlcriticrc - configuration for Perl::Critic for O-Saft #? #? SYNOPSIS #? perlcritic ... #? #? DESCRIPTION #? This file contains the configuration for Perl::Critic, perlcritic. #? The settings are explained, why they are ENABLED or DISABLED. #? #? ################################################################### #? FIXME: this file is a first attempt, not yet completed. #? ################################################################### #? #? EXAMPLES #? # the usual way #? perlcritic #? #? # print policy for each message #? perlcritic --verbose 8 #? #? # print full description for each message #? perlcritic --verbose 10 #? #? # check for a single policy (Subroutines::RequireFinalReturn) #? perlcritic --single-policy Subroutines::RequireFinalReturn #? perlcritic --only --include Subroutines::RequireFinalReturn #? #? # just get a statistic for severity 4 and 5 #? perlcritic --severity 4 --statistics-only #? #? # get a a quick overview for violations of severity 4 and 5 #? perlcritic *.pl *.pm --severity 4 --count #? #? LIMITATIONS #? Do not use perlcritic with an directory as parameter in the development #? directory as there are too much matching files (i.e. SCCS/*) which may #? cause problems. Use list of files instead: *.pl *.pm Net/*.pm #? #? SEE ALSO #? contrib/critic.sh #? #? VERSION #? @(#) .perlcriticrc 1.12 18/09/30 21:34:45 # #? AUTHOR #? 06-apr-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- # global options severity = 5 # will change to 4 o 3 later verbose = 8 # always want to see the policy name #program-extensions '.pl .pm' # does not work as described by Perl::Critic :-/ # theme = o-saft [ControlStructures::ProhibitPostfixControls] allow = if unless #allow = foreach # as the severity is already 2, its okay to report foreach violations # Message # Postfix control "if" used at line ... # CHECK adapted # Postfix controls are used often to have the relevant code far left! [InputOutput::RequireCheckedClose] severity = 1 # Message # Return value of "close" ignored at line ... # CHECK DISABLED # For our purpose it's nice if the files is closed, but not necessary. # hence severity reduced to 1 #[InputOutput::RequireCheckedOpen] #[InputOutput::RequireCheckedSyscalls] [InputOutput::RequireBriefOpen] lines = 15 severity = 2 # Message # Close filehandles as soon as possible after opening them at line ... # CHECK adapted # Because we have more code until close, sometimes. # TODO: lines= seems not to work as descibed, produces false positives # therefore serverity is reduced [InputOutput::RequireEncodingWithUTF8Layer] # Message # I/O layer ":utf8" used at line # CHECK ENABLED # CHECK adapted # However ... # The description of Perl::Critic is mainly valid according input. But # Perl::Critic also complains for output and states, cite: # "For consistency's sake, this policy checks files opened for output # as well as input, For complete coverage it also checks `binmode()' # calls, where the direction the operation can not be determined." # This is wrong, as binmode() usually uses the common bare word file # handles like STDOUT, STDERR, STDIN undoublty. # Our code uses binmode() only for output, hence this check is a false # positive. As this check should be active for future changes, we mark # all our binmode() calls with a proper ## no critic . [InputOutput::ProhibitBacktickOperators] only_in_void_context = 1 # Message # Backtick operator used at line ... # CHECK ENABLED # Literal backticks are not used, but the qx() operator. Backticks are # used in void context, hence the restriction to only_in_void_context. [InputOutput::ProhibitBarewordFileHandles] [InputOutput::ProhibitTwoArgOpen] # Messages: # Bareword file handle opened at line ... # Two-argument "open" used at line ... # A bareword is a series of characters (like the FH) without quotes # around them, or without a sigil in-front of them. They can be used in # some places, but in file-handles they are not recommended any more. # Recommendation # Always use lexical variables and always use 3-parameter for open. [-InputOutput::ProhibitExplicitStdin] # Message # Use "<>" or "" or a prompting module instead of "" at line ... # CHECK DISABLED # The reason why "*ARGV behaves like *STDIN" is described as # "is almost always what you want" sounds strange. # In our usage this is never the case, because we also may get data on # STDIN and have command line arguments. #[InputOutput::ProhibitInteractiveTest] #[InputOutput::ProhibitJoinedReadline] #[InputOutput::ProhibitOneArgSelect] [InputOutput::ProhibitOneArgSelect] # Message # One-argument "select" used at line ... # CHECK ENABLED # selectively disabled in souce with ## no critic .. #[InputOutput::ProhibitReadlineInForLoop] #[InputOutput::RequireBracedFileHandleWithPrint] [References::ProhibitDoubleSigils] # Message # Double-sigil dereference at line ... # CHECK ENABLED [Modules::ProhibitAutomaticExportation] # Message # Symbols are exported by default at line ... # CHECK ENABLED [Modules::RequireBarewordIncludes] severity = 3 # Message # "require" statement with library name as string at line ... # CHECK ENABLED # CHECK adapted # FIXME: O-Saft uses require like: require "o-saft-man.pm"; # which is necessary because the filename contains a - (dash), without # quotes Perl complains with: # Bareword "saft" not allowed while "strict subs" in use # # To get rid of this critic, the filename needs to be changed. That's # why we leave this violation but reduce the severity to 3. [RegularExpressions::ProhibitCaptureWithoutTest] [RegularExpressions::ProhibitUnusedCapture] # Messages # Capture variable used outside conditional at line ... # Only use a capturing group if you plan to use the captured value at line ... # CHECK ENABLED # NOTE: Perl::Critic has a lot of false negatives! [Modules::ProhibitExcessMainComplexity] # Message # Main code has high complexity score (NN) at line ... # CHECK ENABLED [Subroutines::ProhibitExcessComplexity] # Message # Subroutine "XXXX" with high complexity score (29) at line ... # CHECK ENABLED # TODO: CHECK adapted # Net::SSLinfo.pm max_mccabe = 45 [-Subroutines::ProhibitUnusedPrivateSubroutines] # Message # Private subroutine/method 'XXXX' declared but not used at line ... # CHECK DISABLED [-RegularExpressions::RequireDotMatchAnything] # Message # Regular expression without "/s" flag at line ... # CHECK DISABLED # cause we know about meta character . and /s modifier in RegEx ;-) [-RegularExpressions::RequireLineBoundaryMatching] # Message # Regular expression without "/m" flag at line ... # CHECK DISABLED # cause we use /m as needed [-RegularExpressions::RequireExtendedFormatting] # Message # Regular expression without "/x" flag at line ... # CHECK DISABLED # because we use /x as needed for human readability [Subroutines::ProhibitBuiltinHomonyms] # Message # Subroutine name is a homonym for builtin function XXXX at line ... # CHECK ENABLED [-Subroutines::ProhibitManyArgs] # Message # Too many arguments at line ... # CHECK DISABLED # because there are functions with more than 5 paramters # NOTE: this policy has no "allow" option but we need more than 5 # arguments, sometimes;hence disabled [-Subroutines::ProhibitSubroutinePrototypes] # Message # Subroutine prototypes used at line ... # CHECK DISABLED # Contrary to Perl::Critic we consider prototypes as useful, even if # the compile-time checks of Perl are not perfect, Perl may give some # hints. [Subroutines::RequireArgUnpacking] # Message # Always unpack @_ first at line ... # CHECK ENABLED [Subroutines::RequireFinalReturn] # Message # # CHECK ENABLED [-CodeLayout::RequireTidyCode] # Message # Code is not tidy at line 1, column 1. # CHECK DISABLED # TODO: tidy not yet used [-CodeLayout::ProhibitParensWithBuiltins] # Message # Builtin function called with parentheses at line ... # CHECK DISABLED # Contrary to BPB we think that all functions should use parentheses. # Continous use of parentheses makes third-party parsers happy. # However: we miss parentheses, mainly for print builtin function. [-CodeLayout::RequireTidyCode] # Message # Code is not tidy at line 1, column 1. # CHECK DISABLED # TODO: tidy not yet used [CodeLayout::ProhibitHardTabs] # CHECK ENABLED # there are leading tabs only, usually [CodeLayout::ProhibitTrailingWhitespace] # Message # Found "\N{SPACE}" at the end of the line ... # CHECK ENABLED # We hate unecessary characters too ;-) [CodeLayout::RequireConsistentNewlines] # CHECK ENABLED [-Variables::ProhibitLocalVars] # Message # Variable declared as "local" at line ... # CHECK DISABLED # NOTE: Following this critism violates Variables::ProhibitReusedNames # we prefer to check for reused variables [Variables::ProhibitPackageVars] add_packages = Net::SSLinfo Net::SSLhello Net::SSLeay # Message # Package variable declared or used at line ... # CHECK adapted # Add our private modules, this leaves unwanted global variables to be # reported only. # Net::SSLeay is configured using its private variables. [Variables::ProhibitPunctuationVars] allow = $@ $! $? $0 $. $^O $\ # we make regular use of these variables as we know them;-) [Variables::RequireLocalizedPunctuationVars] allow = @ENV # Message # Magic variable "$ENV" should be assigned as "local" # CHECK adapted # @ENV must be changed globally (at least in o-saft.pl) # TODO: need to verify if @INC should be allowed too # Perl::Critic seems to be buggy as it does not honor the allow option # hence an annotation is used in o-saft.pl [Variables::ProhibitReusedNames] allow = $host $port $legacy $arg # Message # Reused variable name in lexical scope: ... # CHECK adapted # These variables are often used in subs, but also in main, hence # we allow them for reuse. [Variables::RequireInitializationForLocalVars] # Message # "local" variable not initialized at line ... # CHECK ENABLED [RegularExpressions::ProhibitCaptureWithoutTest] # Message # Capture variable used outside conditional at line ... # CHECK ENABLED # Workaround: disable selectively where appropriate with: #[RegularExpressions::ProhibitComplexRegexes] # Message # Split long regexps into smaller qr// chunks at line ... # FIXME: to be discussed # Workaround: disable selectively where appropriate with: [ValuesAndExpressions::ProhibitConstantPragma] # Message # Pragma "constant" used at line ... # CHECK ENABLED # Readonly module not used, because it is missing on some # systems, for example Mac OS X 10.x with perl 5.18 [-ValuesAndExpressions::ProhibitEmptyQuotes] # Message # Quotes used with a string containing no non-whitespace characters at line ... # CHECK DISABLED # cause we consider following correct and useful: my $var = ''; # the recomended use of q{} looks too complex: my $var = q{}; [-ValuesAndExpressions::ProhibitNoisyQuotes] # Message # Quotes used with a noisy string at line ... (Severity: 2) # CHECK DISABLED # other people, other opinions: "," is better readable than qw(,) [ValuesAndExpressions::ProhibitEscapedCharacters] # Message # Numeric escapes in interpolated string at line ... # CHECK ENABLED [-ValuesAndExpressions::ProhibitImplicitNewlines] # Message # Literal line breaks in a string at line ... # CHECK DISABLED # yes, there are a lot of constructs using nwelines in texts, that's ok [ValuesAndExpressions::ProhibitMagicNumbers] allowed_values = 0..99 allowed_values = 443 # allowed_types = # constant_creator_subroutines = # FIXME: to be discussed # Workaround: disable selectively where appropriate with: ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers) # CHECK adapted # we use some integers [ValuesAndExpressions::ProhibitMismatchedOperators] # Message # Mismatched operator at line ... # CHECK ENABLED [ValuesAndExpressions::RequireNumberSeparators] min_value = 100_000 # severity is 2 # Message # # CHECK adapted # we use some integers [ValuesAndExpressions::RequireQuotedHeredocTerminator] # Message # Heredoc terminator must be quoted at line ... # CHECK ENABLED # Workaround: disable selectively where appropriate [-ValuesAndExpressions::RequireUpperCaseHeredocTerminator] # Message # Heredoc terminator not alphanumeric and upper-case at line ... # CHECK DISABLED # other people, other opinions [RegularExpressions::ProhibitUnusedCapture] # Message # Only use a capturing group if you plan to use the captured value at line ... # CHECK ENABLED #[RegularExpressions::ProhibitFixedStringMatches] # Message # Use 'eq' or hash instead of fixed-pattern regexps at line ... # FIXME: to be discussed # we often use something like: if (m/^$/) # which is hard to be expressed as a hash [-BuiltinFunctions::ProhibitBooleanGrep] # Message # "grep" used in boolean context at line ... # "grep" used in void context at line ... # CHECK DISABLED # Perl::Critic is too noicy and may have false positives, see its own # description: # perlcritic --doc BuiltinFunctions::ProhibitBooleanGrep #[TestingAndDebugging::ProhibitNoStrict] # Message: # Stricture disabled at line ... # FIXME: to be discussed # i.g. we want this warning, but strict is also disabled in the code # for good reason, probably use ## no critic qw(TestingAndDebugging::ProhibitNoStrict) [TestingAndDebugging::ProhibitNoWarnings] severity = 2 # Message: # Warnings disabled at line # CHECK adapted # FIXME: to be discussed; for now severity reduced from 4 to 2 # i.g. we want this warning, but some warnings are also disabled in # the code for good reason, probably use ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) [TestingAndDebugging::RequireUseStrict] # Message: # Code before strictures are enabled at line ... # Note: # This check produces false positives in module files, if there is no # "use strict" , but this is not necessary as long as the module is # executed itself. # Anyway, "use strict" and "use warnings" is added to modules too. #[BuiltinFunctions::ProhibitStringyEval] # Message: # Expression form of "eval" at line 3117 # FIXME: to be discussed # This occour for eval("require ..."), so probably use ## no critic qw(BuiltinFunctions::ProhibitStringyEval) [-BuiltinFunctions::ProhibitSleepViaSelect] # Message: # "select" used to emulate "sleep" at line ... # BuiltinFunctions::ProhibitSleepViaSelect (Severity: 5) # Conway discourages the use of `select()' for performing non-integer # sleeps. Although documented in perlfunc, it's something that generally # requires the reader to read `perldoc -f select' to figure out what it # should be doing. Instead, Conway recommends that you use the # `Time::HiRes' module when you want to sleep. # # select undef, undef, undef, 0.25; # not ok # # use Time::HiRes; # sleep( 0.25 ); # ok # CHECK DISABLED # We do not wish to use too much external modules. selects is used # several times in SSLhello.pm # FIXME: write a osaft_sleep() which hides the select, this way the # violation is printed only once. Then we can enable it again. [BuiltinFunctions::ProhibitStringySplit] # Message: # String delimiter used with "split" at line ... # CHECK ENABLED [Miscellanea::ProhibitUnrestrictedNoCritic] # does not make sense to disable it, can even not be disabled :-/ [Documentation::RequirePodSections] lib_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR # Message: # # CHECK adapted [-NamingConventions::ProhibitAmbiguousNames] # Message: # Ambiguously named variable "last" at line ... # CHECK DISABLED # cause we consider following correct and useful: my $last = ''; # Perl::Critic is too pedantic here as it is no problem at all with perl. O-Saft-19.01.19/t/Makefile000066400000000000000000000546241342117255600147710ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing O-Saft #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile containing general testing targets for O-Saft project. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see # ../Makefile ../Makefile.help Makefile.template # # Naming conventions for t/Makefile* # * macro names have the prefix TEST. # * target names for public use have the prefix test. # * individual, special targets have the prefix test (exceptions exist) # # Special macros in t/Makefile* # ALL.includes - list of Makefiles # ALL.inc.type - type of tests (should be suffix of Makefile's name) # ALL.help.test - list of documentation (help) texts # _SID.TYPE - version number # _MYSELF.TYPE - name of current file # HELP.TYPE - documentation (help) text for the corresponding file # HELP.TYPE.all - list of all targets for the corresponding file # HELP.TYPE.internal - some more documentation (help) text # where TYPE is the suffix of the Makefile's filename # # Special targets for documentation (help) in t/Makefile* # help.test.% - print individual documentation using $(HELP.TYPE) # help.test.%.all - print all targets using $(HELP.TYPE.all) # help.test.%.internal - print details using $(HELP.TYPE.internal) # where % is the suffix of the Makefile's filename # # TODO: # * include Makefile.* should be generic # * unify test.warnings.log and test.tests.log (should use same target) # * rename ALL.tests and ALL.tests.log (too similar to ALL.test) # #? VERSION #? @(#) Makefile 1.32 19/01/13 19:50:53 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.test = 1.32 _MYSELF.test = t/Makefile ALL.includes += $(_MYSELF.test) ALL.inc.type += test # this is the parent makefile in the directory first-test-target-is-default: help.test ifndef ALL.Makefiles -include t/Makefile.inc # defines macros if called directly (not from ../Makefile) endif ifeq (,$(_SID.help)) -include Makefile.help -include ../Makefile.help # it's intended that only one will be found endif #_____________________________________________________________________________ #___________________________________________________________ default target __| help.test: help.HEAD @echo $(ALL.help.test) help.test.all: @echo " # individual targets for tests" @$(MAKE) -s echo=ALL.tests echo @echo "" @echo " # targets which write results to logfiles" @$(MAKE) -s echo=ALL.tests.log echo @echo "" @echo " # for more target and details, following targets can be used" @echo $(foreach target,$(ALL.inc.type),t-$(target)) .PHONY: help.test help.test.all # FIXME: some of above HELP-* should be extracted from t/Makefile.* # FIXME: missing public (not internal) documentation for pattern rules: # message-%: # no.message-%: # testarg0-%: # testcmd-% # test.all-%: #_____________________________________________________________________________ #____________________________________________ target for help in t/Makefile*__| help.test.%: help.HEAD @$(TARGET_VERBOSE) @echo $(HELP.$*) help.test.%.all: @echo " # individual targets for testing $* :" @echo $(ALL.test.$*) @echo "" @echo $(HELP.$*.all) help.test.%.internal: @echo " # TEST.file: $(TEST.file)" @echo " # TEST.init.$*: $(TEST.init.$*)" @echo " # TEST.$*.hosts: $(TEST.$*.hosts)" @echo " # ALL.test$*: $(words $(ALL.test$*)) : $(ALL.test$*)" @echo " # ALL.test.$*: $(words $(ALL.test.$*)) : $(ALL.test.$*)" @echo $(HELP.$*.internal) @echo " # -------------------------------------------------------------" # TODO: some alias because suffix differs from type help.test.cmd.all: help.test.cmds.all help.test.warning.all: help.test.warnings.all help.test.cmd.internal: help.test.cmds.internal help.test.warning.internal: help.test.warnings.internal help-test-all = $(foreach type,$(ALL.inc.type), help.test.$(type).all) help-test-internal = $(foreach type,$(ALL.inc.type), help.test.$(type).internal) help.test.targets: @$(MAKE) -s $(help-test-all) $(help-test-internal) .PHONY: help.test.targets #_____________________________________________________________________________ #________________________________________________________________ variables __| # store -n (dry-run) option in own variable _n := $(if $(findstring n,$(firstword -$(MAKEFLAGS))),-n) # test tools (part of distribution) TEST.dir = t TEST.logdir = $(TEST.dir)/log # following may be redefined in included t/Makefiles* # TEST.init = --header # TEST.args = # macro for list of hostnames needs to be unique in each Makefile* # otherwise some targets in other Makefile* get confused #TEST.host = localhost #TEST.hosts = # following defined in ../Makefile # TEST.do = # SRC.test = # ALL.test = # defined in other t/Makefile* # ALL.tests = OPT.grep = -q # grep (mainly used in message-% target) should not report matching lines # macro can be reset or redifined for more verbose output # internal used tools and files (paths hardcoded!) EXE.bench = t/o-saft_bench EXE.test.bunt = t/test-bunt.pl.txt _TODAY_ = $(shell date +%Y""%m%d) HELP.test = " \ \# Following variables are intended to be used on command line:$(_NL)\ \#$(_NL)\ \# EXE.pl - program to perform tests, default: $(EXE.pl)$(_NL)\ \# TEST.init - arguments and options always passed to EXE.pl; default: $(TEST.init)$(_NL)\ \# TEST.args - arguments and options to be passed to EXE.pl per target$(_NL)\ \# TEST.host - hostname to be used for tests (when only one is expected)$(_NL)\ \# TEST.hosts - list of hostnames to perform tests with$(_NL)\ \# TEST.dir - directory in which EXE.pl will be executed; default: $(TEST.dir)$(_NL)\ \# TEST.logdir - directory where results of EXE.pl will be stored; default: $(TEST.logdir)$(_NL)\ \# TEST.rc - content of RC-file to be used by EXE.pl: $(TEST.rc)$(_NL)\ \#$(_NL)\ \# Keep in mind that following files are located in $(TEST.dir):$(_NL)\ \# .o-saft.pl $(TEST.rc) .o-saft.tcl$(_NL)\ \# which are used by EXE.pl or other tools used for the tests.$(_NL)\ " # $(SRC.rc) may not be defined here, hence hardcoded ALL.help.test += $(_NL)$(HELP.test) #_____________________________________________________________________________ #_____________________________________________________ internal test target __| # internal information (nothing related to $(Project)) # Note that the $(_SID*) variables indicate if a sub-makefile was included. # Note that $$ neds to be used to ensure that the variables are evaluated when # the targets executes and not when the Makefile is read. test.file-1: test,file-2: test_file-3: test.target: test.file-1 test,file-2 test_file-3 @echo 'test.target: test.file-1 test-file-2 test_file-3' @echo '# SIDs of included Makefile* (file not included if SID missing):' @echo '# $$(_SID) = $(_SID)' @echo '# $$(_SID.help) = $(_SID.help)' @echo '# $$(_SID.test) = $(_SID.test)' @echo '# $$(_SID.critic) = $(_SID.critic)' @echo '# $$(_SID.warnings) = $(_SID.warnings)' @echo '# $$(_SID.exit) = $(_SID.exit)' @echo '# $$(_SID.misc) = $(_SID.misc)' @echo '# $$(_SID.cmds) = $(_SID.cmds)' @echo '# $$(_SID.ext) = $(_SID.ext)' @echo '# $$(_SID.cgi) = $(_SID.cgi)' @echo '# $$(_SID.hlp) = $(_SID.hlp)' @echo '# $$(_SID.inc) = $(_SID.inc)' @echo '# $$(_SID.opt) = $(_SID.opt)' @echo '# $$(_SID.tcl) = $(_SID.tcl)' @echo '# show some private make variables:' @echo '# $$(PWD) = $(PWD)' @echo '# $$(PWD.dir) = $(notdir $(PWD))' @echo '# $$(TEST.dir) = $(TEST.dir)' @echo '# $$(TEST.logdir) = $(TEST.logdir)' @echo '# $$(TEST.host) = $(TEST.host)' @echo '# $$(TEST.hosts) = $(TEST.hosts)' @echo '# $$(ALL.Makefiles) = $(ALL.Makefiles)' @echo '# $$(ALL.includes) = $(ALL.includes)' @echo '# show some make variables:' @echo '# $$@ = $@ #' @echo '# $$< = $< #' @echo '# $$? = $? #' @echo '# $$^ = $^ #' @echo '# $$+ = $+ #' @echo '# $$| = $| #' @echo '# $$% = $% #' @echo '# $$* = $* #' @echo '# $$> = $> #' @echo '# $$- = $- #' @echo '# $$D = $D #' @echo '# $$F = $F #' @echo '# $$(MAKE) = $(MAKE)' @echo '# $$(CURDIR) = $(CURDIR)' @echo '# $$(MAKE_COMMAND) = $(MAKE_COMMAND)' @echo '# $$(MAKE_VERSION) = $(MAKE_VERSION)' @echo '# $$(MAKE_HOST) = $(MAKE_HOST)' @echo '# $$(MAKELEVEL) = $(MAKELEVEL)' @echo '# $$(MAKEFILE) = $(MAKEFILE)' @echo '# $$(MAKEFILES) = $(MAKEFILES)' @echo '# $$(MAKEFILE_LIST) = $(MAKEFILE_LIST)' @echo '# $$(MAKEFILE_LIST)F= $(firstword $(MAKEFILE_LIST))' @echo '# $$(MAKEFILE_LIST)L= $(lastword $(MAKEFILE_LIST))' @echo '# $$(MFLAGS) = $(MFLAGS)' @echo '# $$(MAKEFLAGS) = $(MAKEFLAGS)' @echo '# $$(MAKEOVERRIDES) = $(MAKEOVERRIDES)' @echo '# $$(MAKECMDGOALS) = $(MAKECMDGOALS)' @echo '# $$(GNUMAKEFLAGS) = $(GNUMAKEFLAGS)' @echo '# $$(.PRECIOUS) = $(.PRECIOUS)' @echo '# $$(.SECONDARY) = $(.SECONDARY)' @echo '# $$(.INTERMEDIATE) = $(.INTERMEDIATE)' @echo '# $$(.SUFFIXES) = $(.SUFFIXES)' @echo '# $$(.VARIABLES) = $(.VARIABLES)' #_____________________________________________________________________________ #______________________________________________________ targets for testing __| # target to check for empty hostname list, can also be used for more debugging _no-hosts__not-yet-working: @[ "$(eTEST.hosts)" = "" ] && $(eval _ERR := "no TESTS.hosts defined") @[ "$(eTEST.hosts)" = "from.Makefile.FQDN" ] \ && $(eval _ERR := "fake TESTS.hosts defined in $(TEST.file)") @[ -n "$(_ERR)" ] && echo $(_ERR) && exit 2 || echo -n "" _no-hosts: @-[ "$(eTEST.hosts)" = "" ] \ && echo no TESTS.hosts defined \ && exit 2 \ || echo -n "" @-[ "$(eTEST.hosts)" = "from.Makefile.FQDN" ] \ && echo fake TESTS.hosts defined in $(TEST.file) \ && exit 2 \ || echo -n "" .PHONY: _no-hosts $(TEST.logdir): @mkdir $@ # Testing for messages or other strings (i.e **WARNING) works as follows: # call $(EXE.pl) with command and/or options in question # then search (grep) output for message (string) # For some behaviours of $(EXE.pl) a RC-file is required. # Different target rules can be mapped to the pattern rule message-%. It gets # the message string from the automatic variable $* , and all arguments for # $(EXE.pl) with following Makefile variables: # $(TEST.init) - command, options to be passed to $(EXE.pl) # $(TEST.args) - command, options and hostname to be passed to $(EXE.pl) # $(TEST.rc) - content of RC-file to be used by $(EXE.pl) # These variables can be set conditinally for each target, see example below. # Some tests are not yet implemented, or difficult to implement. In this case # $(TEST.args) contains a string starting with "TODO:". The message-% target # tests the variable for this string and then simply prints it. Otherwise the # check will be performed (see if - else - fi in message-% rule). # The pattern rule succeeds (returns status 0) if the pattern is found. The # rule fails, if the pattern is not found. That's why it is very important to # define TEST.args propperly. Even the sequence of the arguments may count. # # Note: even _TMP.rc is generated for each call, it will only be used when # requested with the --rc=$(_TMP.rc) option. # Note: if TEST.args contains special characters, syntax errors may occour # when used in the shell. Quoting TEST.args is not possible because then it # becomes a single argument instead of discrete arguments. At least following # special characters should not be used: ; & | # < > ` [ ] # # Example of Usage # pattern rule: warning-% # target rule: warning-049 # pattern: 049 # arguments: TEST.args = +unknown_command +quit # Example for the target rule with above settings will be: # warning-%: EXE.pl = ../$(SRC.pl) # warning-%: TEST.init = --init-option # warning-049: TEST.args = +unknown_command +quit # Map all pattern rules to message-% pattern rule (recipe need command) # warning-%: message-% # @echo -n "" # The recipe in the pattern rule message-% will be: # $(EXE.pl) $(TEST.init) $(TEST.args) 2>&1 | grep 049 # which finally evaluates to: # ../o-saft.pl --init-option +unknown_command +quit 2>&1 | grep 049 # +quit command or other command and hostname is needed # for testing the warning message # target succeeds if message is there message-%: @$(TARGET_VERBOSE) @-if expr "$(TEST.args)" ":" "^TODO" >/dev/null ; then \ echo "$@: $(TEST.args)"; \ else \ echo "$(EXE.pl) $(TEST.init) $(TEST.args) 2>&1 | grep $(OPT.grep) $* " ; \ echo "$(TEST.rc)" > $(_TMP.rc) ; \ cd $(TEST.dir) && $(EXE.pl) $(TEST.init) $(TEST.args) 2>&1 | grep $(OPT.grep) $* ; \ _status=$$? ; \ rm -f $(_TMP.rc) ; \ exit $$_status ; \ fi # following removed from above, too noicy: # echo "echo '$(TEST.rc)' > $(_TMP.rc)" ; # target succeeds if message is missing # TODO: need more examples beside those in t/Makefile.cgi no.message-%: @$(TARGET_VERBOSE) @echo "$(TEST.rc)" > $(_TMP.rc) $(EXE.pl) $(TEST.init) $(TEST.args) 2>&1 | awk '/ $*/{exit 1}' @rm -f $(_TMP.rc) # Simple target to calL: $(EXE.pl) $(TEST.init) $(TEST.args) testarg0-%: @$(TARGET_VERBOSE) -cd $(TEST.dir) && $(EXE.pl) $(TEST.init) $(TEST.args) ifeq (n,$(findstring n,$(firstword -$(MAKEFLAGS)))) # simple target for -n (dry-run) to avoid generation of file(s) testarg0-%.log: $(TEST.logdir) @echo "$(MAKE) $(MFLAGS) -s testarg0-$* > $@ 2>&1" else testarg0-%.log: $(TEST.logdir) @$(TARGET_VERBOSE) @$(eval _NEW.log := $(TEST.logdir)/$@-$(_TODAY_)) @$(MAKE) $(MFLAGS) -s testarg0-$* > $@ 2>&1 @-diff $(TEST.logdir)/$@ $@ 2>/dev/null \ && rm $@ \ || mv $@ $(_NEW.log) @-test -f $(TEST.logdir)/$@ || mv $(_NEW.log) $(TEST.logdir)/$@ @-ls -l $(TEST.logdir)/testarg0-$(*)* # TODO: target should fail if there is a diff endif # The goal for test targets is to perform (test) all commands with all hosts. # The hostnames are provided in a simple list: $(TEST.hosts) . # The commands couldn't be provided in a make macro all together, because each # command may consist of space separated words like: "+info --header". # Hence each command is defined in the macro TEST.args, which will be set for # an individual target, for example: testcmd-001 . We have one target for each # specific test case, which actually is a list of commands and options for the # tool $(EXE.pl) . Note that the trailing DDD (001 in example above) is just # a number to make each target unique. # To feed the hostname to that target, the target is defined as pattern rule # testcmd-001_% , which means that the hostname can be passed like: # testcmd-001_host.some.tld # Now we can simply use: $(TESTS.hosts:%=testcmd-001_%) , which generates one # target for each host in the list. But that would require to build a list for # each such target: testcmd-002_% and testcmd-003_% and so on. # As we want to perform all these targets with all hostnames, this would also # require an additional pattern rule for the hostname part. To avoid such an # addditional pattern rule for each testcmd-DDD, the general pattern rule # testcmd-% is used. It handles all the individual targets which contain the # hostname. # Unfortunatelly, this pattern contains DDD_ (for example 001_host.some.tld) # as hostname. This DDD_ prefix must then be removed in the target command, # the $(shell awk ...) does the dirty work. in detail (as defined below): # # pattern rule to handle all targets testcmd-DDD_HOSTNAME # testcmd-%: # # # # remove prefix DDD- from hostname # $(shell awk 'END{h="$*";sub(/^[^_]*-/,"",h);print h}' /dev/null) # # or # $(shell echo "$*" | awk -F_ '{print $$2}') $(TEST.args) # # c00-aa.tld returns: aa.tld # # Note: following does not work proper (in GNUmake), hence the solution above: # testcmd-no1: TEST.args = +quit $* # testcmd-no2: TEST.args := +quit $* # # Example of Usage # pattern rule: testcmd-% # target rule: testcmd-c00 # pattern: 00c_aa.tld # arguments: TEST.args = +cipher # hosts tested: aa.tld bb.tld # Example for the target rule in t/Makefile.* with above settings will be: # # define list of hostnames # TEST.hosts = aa.tld bb.tld # # define targets # testcmd-c%: EXE.pl = ../$(SRC.pl) # testcmd-c%: TEST.init = --header # # # # define the commands to be used for $(EXE.pl) in the target # testcmd-c00_%: TEST.args += +cipher --enabled # testcmd-c01_%: TEST.args += +info # # # # dynamically generate list of all testcmd-DDD targets # ALL.ext.cmd = $(shell awk -F_ '/^testcmd-c[0-9]/{print $$1}' t/Makefile.ext) # # returns: testcmd-c00 testcmd-c01 # # # # dynamically generate list of all testcmd-DDD for all hostnames # ALL.by_host = $(foreach host,$(TEST.hosts),$(ALL.ext.cmd:%=%_$(host))) # # returns: testcmd-c00_aa.tld testcmd-c01_aa.tld testcmd-c00_bb.tld testcmd_c01-bb.tld testcmd-%: EXE.pl = ../$(SRC.pl) testcmd-%: @$(TARGET_VERBOSE) -cd $(TEST.dir) && $(EXE.pl) $(shell echo "$*" | awk -F_ '{print $$NF}') $(TEST.init) $(TEST.args) # TODO: need verbose for executed command # TODO: need to add --no-dns if hostname is an IP # Target should create a new logfile, then compare it with the current one. If # diff returns nothing, delete newly created logfile, otherwise rename newly # created file to name which contains the current date. # Finally, if current logfile is/was missing, use newly created one: # "test ... || mv ..." . This ensures that the file exists afterwards. # Note that all target commands are prefixed with - to avoid make reporting of # errors if the command fails (as failture is intended, somehow). # Note that testcmd-%.log called from within t/ may return: is up to date. # diff's STDERR is discarded (may return: "file does not exist"). ifeq (n,$(findstring n,$(firstword -$(MAKEFLAGS)))) # simple target for -n (dry-run) to avoid generation of file(s) testcmd-%.log: $(TEST.logdir) @echo "$(MAKE) $(MFLAGS) -s testcmd-$* > $@ 2>&1" else testcmd-%.log: $(TEST.logdir) @$(TARGET_VERBOSE) @$(eval _NEW.log := $(TEST.logdir)/$@-$(_TODAY_)) @$(MAKE) $(MFLAGS) -s testcmd-$* > $@ 2>&1 @-diff $(TEST.logdir)/$@ $@ 2>/dev/null \ && rm $@ \ || mv $@ $(_NEW.log) @-test -f $(TEST.logdir)/$@ || mv $(_NEW.log) $(TEST.logdir)/$@ @-ls -l $(TEST.logdir)/testcmd-$(*)* # TODO: target should fail if there is a diff endif # The pattern rule testcmd-% executes an individual target, for example: # testcmd-c001_localhost . The following pattern executes all matching targets # at once. The grouping is done by the rule's pattern. The pattern is searched # for in $(ALL.tests) . # TODO: more documentation ... # TODO: Examples: # test.pattern.info # test.pattern.+info # test.pattern.+check # test.pattern.+cipher # test.pattern.+ciphers # test.pattern.-header # dbx-test.pattern-%: @$(TARGET_VERBOSE) @$(eval _targets = $(shell echo "$(ALL.tests)" | $(EXE.wordperline) | awk '/$*/{print $$0;}')) @echo "# $(_targets) #" test.pattern-%: @$(TARGET_VERBOSE) @$(eval _targets = $(shell echo "$(ALL.tests)" | $(EXE.wordperline) | awk '/$*/{print $$0;}')) @-test -n "$(_targets)" \ && $(MAKE) $(MFLAGS) -s $(_targets) \ || echo "# pattern '$*' does not match any target" # TODO: logging not yet tested (01/2019) test.pattern-%.log: @$(TARGET_VERBOSE) @$(eval _targets = $(shell echo "$(ALL.tests)" | $(EXE.wordperline) | awk '/$*/{print $$0".log";}')) @-test -n "$(_targets)" \ && $(MAKE) $(MFLAGS) -s $(_targets) \ || echo "# pattern '$*' does not match any target" # some alias targets (humans tend to be lazy:) # FIXME: following buggy; ends with command: rm test.pattern-% test.pat-%: test.pattern-% @echo -n "" test.patt-%: test.pattern-% @echo -n "" #_____________________________________________________________________________ #__________________________________________________ include testing targets __| # includes are done explicitly instead of: # include t/Makefile.* # to avoid multiple inlcudes of the same file, which would result in make # errors complaining about target redefinitions # for a detailed description see t/Makefile.template ifeq (,$(_SID.warnings)) -include t/Makefile.warnings endif ifeq (,$(_SID.cmds)) -include t/Makefile.cmds endif ifeq (,$(_SID.exit)) -include t/Makefile.exit endif ifeq (,$(_SID.opt)) -include t/Makefile.opt endif ifeq (,$(_SID.ext)) -include t/Makefile.ext endif ifeq (,$(_SID.hlp)) -include t/Makefile.hlp endif ifeq (,$(_SID.cgi)) -include t/Makefile.cgi endif ifeq (,$(_SID.tcl)) -include t/Makefile.tcl endif ifeq (,$(_SID.misc)) -include t/Makefile.misc endif ifeq (,$(_SID.critic)) -include t/Makefile.critic endif #_____________________________________________________________________________ #_____________________________________________________________________ test __| HELP-_test = ______________________________________ targets for testing _ HELP-tests = make all tests HELP-test = alias for tests HELP-tests.quick = like tests, but less targets (for development) HELP-tests.quick.log= like tests.log, but less targets (for development) HELP-help.test = print more targets for testing HELP-help.test.all = print available individual targets for testing tests: TARGET_VERBOSE=echo "\\012\#\# $@: $(EXE.pl) $(TEST.args)" tests: $(ALL.tests) @echo -n "" # bench.log tests.log: $(ALL.tests.log) @echo -n "" # quick tests for development tests.quick: @$(MAKE) $(MFLAGS) -s tests ALL.test.ext= ALL.test.misc= ALL.test.critic= #tests.quick.log: # @$(MAKE) $(MFLAGS) -s tests.log ALL.test.ext= ALL.test.misc ALL.test.critic= # FIXME: tests.quick.log not yet working; need to use macro in each Makefile.* tests.quick.log: $(MAKE) $(MFLAGS) -s tests.log ALL.tests.log="test.warnings.log test.cmds.log test.exit.log test.opt.log test.cgi.log test.tcl.log" # aliases for convenience test: tests test.log: tests.log .PHONY: test tests O-Saft-19.01.19/t/Makefile.FQDN000066400000000000000000000002171342117255600155050ustar00rootroot00000000000000# # file contains hostnames or IPs # one name per line # each name must start at line start # all other lines are ignored from.Makefile.FQDN O-Saft-19.01.19/t/Makefile.cgi000066400000000000000000000247731342117255600155340ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing o-saft.cgi #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile to perform testing tasks for o-saft.cgi . #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see # ../Makefile ../Makefile.help Makefile.template # #? VERSION #? @(#) Makefile.cgi 1.18 19/01/13 20:58:16 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.cgi = 1.18 _MYSELF.cgi = t/Makefile.cgi ALL.includes += $(_MYSELF.cgi) ALL.inc.type += cgi first-cgi-target-is-default: help.test.cgi # see help.test.% TEST.init = ifeq (,$(_SID.test)) -include t/Makefile endif TEST.cgi.hosts = localhost ifdef TEST.hosts TEST.cgi.hosts = $(TEST.hosts) endif MAKEFLAGS += --no-print-directory # needed here, even if set in Makefile.inc; reason yet unknown (01/2019) HELP.cgi = "\ \# ___________________________________________ testing .cgi _$(_NL)\ test.cgi.all - test all bad IPs, hostnames and options for $(SRC.cgi) $(_NL)\ test.cgi.log - same as test.cgi.all but store output in $(TEST.logdir)/ $(_NL)\ test.cgi.badhosts - test that some hostnames are ignored in $(SRC.cgi) $(_NL)\ test.cgi.badIPs - test that some IPs are ignored in $(SRC.cgi) $(_NL)\ test.cgi.badall - test all bad and good IPs and hostnames $(_NL)\ test.cgi.badopt - test bad options and characters$(_NL)\ test.cgi.goodIPs - test IPs to be passed$(_NL)\ test.cgi-NAME - same as testcmd-cgi-bad_NAME$(_NL)\ testcmd-cgi-bad_NAME - check if a single NAME (IP or hostname) allowed in $(SRC.cgi) $(_NL)\ \#$(_NL)\ \# Examples: $(_NL)\ \# make test.cgiall $(_NL)\ \# make testcmd-cgi-bad_42.42.42.42 $(_NL)\ \# make testcmd-cgi-bad_127.0.0.127 $(_NL)\ \# make testcmd-cgi-bad_localhost $(_NL)\ \# make e-test.cgi.badhosts $(_NL)\ \# make s-test.cgi.badIPs $(_NL)\ \# make s-test.cgi.badopt $(_NL)\ \#$(_NL)\ \# There are no test.cgi.*.log targets, please use test.cgi.log instead.$(_NL)\ \#$(_NL)\ \# Hint: use test.pattern-cgi- instead of test.pattern-cgi , as the$(_NL)\ \# patttern cgi may match other targets too.\ " ALL.help.test += $(_NL)$(HELP.cgi) HELP-help.test.cgi = print targets for testing '$(SRC.cgi)' #_____________________________________________________________________________ #________________________________________________________________ variables __| # keep in mind: the targets should succeed for all hostnames and IPs test.cgi.badhosts = \ hostname.ok.to.show.failed-status \ localhost any.local # range from - - - - - - - - - - - - - - - - - - to test.cgi.badIPv4 = \ 0.0.0.1 0.0.0.255 \ 10.0.0.1 10.0.0.255 10.12.34.56 10.255.255.255 \ 100.64.0.0 100.64.0.255 \ 127.0.0.1 127.1.0.1 127.1.0.255 \ 127.251.251.1 127.255.255.255 \ 169.254.0.1 169.254.1.1 169.254.255.255 \ 172.16.0.1 172.19.255.255 \ 192.0.0.1 192.0.0.255 \ 192.0.2.1 192.0.2.255 \ 192.88.99.1 192.88.99.255 \ 192.168.0.1 192.168.255.255 \ 198.18.0.1 198.18.0.255 198.18.1.1 198.18.0.1.255 \ 198.51.100.1 198.51.100.255 \ 203.0.13.1 203.0.13.255 \ 224.0.0.1 224.0.0.255 239.1.1.255 239.255.255.255 \ 240.0.0.1 251.251.251.251 255.255.255.255 \ # The IP or hostname becomes part of the target name, hence IPv6 are not # possible verbatim because they contain : in the name; the : must be escaped test.cgi.badIPv6 = \ \:\:1 ffff\:\:1 7f00\:1 ffff\:7f00\:1 \ ff02\:\:1 ff02\:\:fb \ # TODO: ff01::1 ff02::1 # TODO: fe80:21ab:22cd:2323::1 fec0:21ab:22cd:2323::1 feff:21ab:22cd:2323::1 # fc00:21ab:22cd:2323::1 fdff:21ab:22cd:2323::1 HELP.cgi.internal = "\ \# test.cgi.badhosts: $(test.cgi.badhosts)$(_NL)\ \# test.cgi.badIPs: $(test.cgi.badIPs)$(_NL)\ \# test.cgi.goodIPs: $(test.cgi.goodIPs)$(_NL)\ " # TODO: *goodIP* not yet ready test.cgi.goodIPv4 = test.cgi.goodIPv6 = \ 2002\:0\:0\:0\:0\:0\:b0b\:b0b \ test.cgi.badIPs = $(test.cgi.badIPv4) $(test.cgi.badIPv6) test.cgi.goodIPs = $(test.cgi.goodIPv4) $(test.cgi.goodIPv6) ALL.cgi.badhosts = $(test.cgi.badhosts:%=testcmd-cgi-bad_%) ALL.cgi.badIPs = $(test.cgi.badIPs:%=testcmd-cgi-bad_%) ALL.cgi.goodIPs = $(test.cgi.goodIPs:%=testcmd-cgi-good_%) HELP.cgi.all = "\ \# targets for testing bad hosts:$(_NL)\ $(ALL.cgi.badhosts)$(_NL)\ \# targets for testing bad IPs:$(_NL)\ $(ALL.cgi.badIPs)$(_NL)\ \# targets for testing good IPs:$(_NL)\ $(ALL.cgi.goodIPs)$(_NL)\ " # SEE Make:target name # SEE Make:target name prefix # Testing for invalid arguments, hostnames and IPs uses following command: # o-saft.cgi --cgi +quit --exit=BEGIN0 --host=10.0.0.1 # or # env QUERY_STRING="--cgi&--cmd=quit&--exit=BEGIN0&--host=10.0.0.1" o-saft.cgi # they should return: # X-Cite: Perl is a mess. ... # X-O-Saft: OWASP – SSL advanced forensic tool # Content-type: text/plain; charset=utf-8 # # #o-saft.pl _yeast_EXIT exit=BEGIN0 - BEGIN start # # The option --exit=BEGIN0 ensures that nothing will be done in o-saft.pl . # It ensures that the last line of the output contains exit=BEGIN0 . This last # line is missing if o-saft.cgi exits because an invalid argument, hostname # or IP was detected. The purpose here is to check if o-saft.cgi exits, hence # the test succeeds, if the last line is missing. # The target no.message is used for each individual test. It is a pattern rule # in t/Makefile and uses the variables EXE.pl, TEST.args and TEST.INIT, which # are passed as arguments to the recursive MAKE call. # "make -i" is used to ensure that all tests are performed. # Testing usage of --cgi option; means that _args.cgi must be set explicitly. # Test fails, if it reports something containing exit=BEGIN0 testcmd-cgi--cgi_%: _args.cgi = --cgi --ok.to.show.failed-status +quit --exit=BEGIN0 testcmd-cgi--cgi-miss_%: _args.cgi = --missing--cgi +quit --exit=BEGIN0 testcmd-cgi--cgi-bad1_%: _args.cgi = --cgiwrong +quit --exit=BEGIN0 testcmd-cgi--cgi-bad2_%: _args.cgi = --cgi=wrong +quit --exit=BEGIN0 testcmd-cgi--cgi-bad3_%: _args.cgi = --wrongcgi +quit --exit=BEGIN0 # all tests for good or bad arguments need the same initial options _args.cgi = --cgi +quit --exit=BEGIN0 testcmd-cgi-%: EXE.pl = ../$(SRC.cgi) testcmd-cgi-bad%: EXE.pl = ../$(SRC.cgi) testcmd-cgi-good%: EXE.pl = ../$(SRC.cgi) # some characters are enclosed in _ and _ for better readability testcmd-cgi-opt--opt_%: _args.cgi += --opt=ok.to.show.failed-status testcmd-cgi-opt--cmd_%: _args.cgi += --cmd=list testcmd-cgi-opt--env_%: _args.cgi += --env=not-allowed testcmd-cgi-opt--exe_%: _args.cgi += --exe=not-allowed testcmd-cgi-opt--lib_%: _args.cgi += --lib=not-allowed testcmd-cgi-opt--cal_%: _args.cgi += --call=not-allowed testcmd-cgi-opt--ssl_%: _args.cgi += --openssl=not-allowed testcmd-cgi-chr-langle_%: _args.cgi += '--bad-char=_<_' testcmd-cgi-chr-rangle_%: _args.cgi += '--bad-char=_>_' testcmd-cgi-chr-semikolon_%:_args.cgi += '--bad-char=_;_' testcmd-cgi-chr-tilde_%: _args.cgi += '--bad-char=_~_' testcmd-cgi-chr-question_%: _args.cgi += '--bad-char=_?_' #testcmd-cgi-chr-dollar_%: _args.cgi += '--bad-char=_\$$_' testcmd-cgi-chr-percent_%: _args.cgi += '--bad-char=_%_' testcmd-cgi-chr-dqoute_%: _args.cgi += '--bad-char=_\"_' testcmd-cgi-chr-back_%: _args.cgi += '--bad-char=_\`_' testcmd-cgi-chr-star_%: _args.cgi += '--bad-char=_*_' testcmd-cgi-chr-lbrac_%: _args.cgi += '--bad-char=_(_' testcmd-cgi-chr-rbrac_%: _args.cgi += '--bad-char=_)_' testcmd-cgi-chr-lsquare_%: _args.cgi += '--bad-char=_[_' testcmd-cgi-chr-rsquare_%: _args.cgi += '--bad-char=_]_' testcmd-cgi-chr-lcurl_%: _args.cgi += '--bad-char=_{_' testcmd-cgi-chr-rcurl_%: _args.cgi += '--bad-char=_}_' testcmd-cgi-chr-caret_%: _args.cgi += '--bad-char=_^_' testcmd-cgi-chr-bar_%: _args.cgi += '--bad-char=_|_' testcmd-cgi-chr-hash_%: _args.cgi += '--bad-char=_\#_' testcmd-cgi-%: @$(TARGET_VERBOSE) @$(eval _host := $(shell echo "$*" | awk -F_ '{print $$NF}')) @$(MAKE) $(MFLAGS) -i no.message-exit.BEGIN0 EXE.pl=$(EXE.pl) TEST.args="$(_args.cgi) --host=$(_host)" # TODO: following target prints "#o-saft.pl..." testcmd-cgi-good%: @$(TARGET_VERBOSE) @$(eval _host := $(shell echo "$*" | awk -F_ '{print $$NF}')) @$(MAKE) $(MFLAGS) -i message-exit.BEGIN0 EXE.pl=$(EXE.pl) TEST.args="$(_args.cgi) --host=$(_host)" # alias for simple usage test.cgi-%: testcmd-cgi-bad_% @echo "" ALL.testcgiopt = $(shell awk -F% '/^testcmd-cgi-opt-/ {print $$1}' $(_MYSELF.cgi)) ALL.testcgichr = $(shell awk -F% '/^testcmd-cgi-chr-/ {print $$1}' $(_MYSELF.cgi)) ALL.cgi.badchr = $(ALL.testcgichr:%=%any.FQDN) ALL.cgi.badopt = $(ALL.testcgiopt:%=%any.FQDN) ALL.testcgi = $(ALL.testcgiopt) ALL.test.cgi = $(ALL.cgi.badopt) $(ALL.cgi.badchr) $(ALL.cgi.badhosts) $(ALL.cgi.badIPs) $(ALL.cgi.goodIPs) test.cgi.badhosts: $(ALL.cgi.badhosts) test.cgi.badIPs: $(ALL.cgi.badIPs) test.cgi.badall: test.cgi.badhosts test.cgi.badIPs test.cgi.badopt: $(ALL.cgi.badopt) test.cgi.badchr: $(ALL.cgi.badchr) test.cgi.goodIPs: $(ALL.cgi.goodIPs) test.cgi.all: $(ALL.test.cgi) test.cgi: $(ALL.test.cgi) _TEST.CGI.log = $(TEST.logdir)/test.cgi.log-$(_TODAY_) # use 'make -i ...' because we have targets which fail, which is intended $(_TEST.CGI.log): @echo "# Makefile.cgi 1.18: make test.cgi.log" > $@ @$(MAKE) -i test.cgi >> $@ 2>&1 test.cgi.log: $(_TEST.CGI.log) @$(TARGET_VERBOSE) @diff $(TEST.logdir)/$@ $(_TEST.CGI.log) \ && rm $(_TEST.CGI.log) \ || mv $(_TEST.CGI.log) $(TEST.logdir)/$@ @-test -f $(TEST.logdir)/$@ || mv $(_TEST.CGI.log) $(TEST.logdir)/$@ @ls -l $(TEST.logdir)/$@* # TODO: same target as test.warnings.log ALL.tests.cgi.log += $(test.cgi.log) .PHONY: test.cgi.log #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.cgi) ALL.tests.log += $(ALL.test.cgi.log) O-Saft-19.01.19/t/Makefile.cmds000066400000000000000000000170671342117255600157160ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing O-Saft commands and options #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile to perform testing tasks for O-Saft project. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For more details please see # Makefile ../Makefile ../Makefile.help Makefile.template # #? VERSION #? @(#) Makefile.cmds 1.18 19/01/13 21:43:27 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.cmds = 1.18 _MYSELF.cmds = t/Makefile.cmds ALL.includes += $(_MYSELF.cmds) ALL.inc.type += cmds first-cmds-target-is-default: help.test.cmds # see help.test.% ifeq (,$(_SID.test)) -include t/Makefile endif TEST.cmds.hosts = localhost ifdef TEST.hosts TEST.cmds.hosts = $(TEST.hosts) endif HELP.cmds = "\ \# __________________________________________ test commands _$(_NL)\ test.pattern-* - test group of commands with $(TEST.cmds.hosts)$(_NL)\ testcmd-* - test commands with $(TEST.cmds.hosts)$(_NL)\ testcmd-*.log - same as testcmd-* but store output in t/testcmd-*.log$(_NL)\ test.cmds.all - test all commands with $(TEST.cmds.hosts)$(_NL)\ test.cmds.log - same as test.cmds.all but store output in t/testcmd-*.log$(_NL)\ \# ________________________________________ special targets _$(_NL)\ testrun-CMD - test specific command CMD with $(TEST.cmds.hosts)$(_NL)\ testrun-CMD.log - same as testrun-CMD but store output in t/testcmd-CMD.log$(_NL)\ \#$(_NL)\ \# To get a list of targets, use:$(_NL)\ \# make e-ALL.test.cmds$(_NL)\ \# make s-ALL.test.cmds$(_NL)\ \# Targets can be executed individually, or a group of targets can be executed$(_NL)\ \# by using the pattern rule test.pattern-% (see Makefile).$(_NL)\ \# Examples to execute individual targets: $(_NL)\ \# make testcmd-c+info_localhost $(_NL)\ \# make testcmd-c+cipher--cipher-alpn_localhost $(_NL)\ \# make testrun-+cn $(_NL)\ \# Examples to execute group of similar targets: $(_NL)\ \# make test.pattern-+info $(_NL)\ \# make test.pattern-+check $(_NL)\ \# make test.pattern-+cipher $(_NL)\ \# make test.pattern-+summ $(_NL)\ \# make test.pattern-+vuln $(_NL)\ \# All following examples are the same: $(_NL)\ \# make testrun-+cipher TEST.init='--header --enabled' $(_NL)\ \# make testcmd-+cipher TEST.init='--header --enabled localhost' $(_NL)\ \# make testcmd-+cipher TEST.args='--header --enabled localhost' $(_NL)\ \#$(_NL)\ \# Some of the examples above use localhost as hostname by default.\ " ALL.help.test += $(_NL)$(HELP.cmds) # TODO: implement following # make testrun-+cn\ --traceCMD # make testrun-'+cn --traceCMD' # make testrun-'+cipher --enabled' HELP-help.test.cmds = print targets for testing '$(SRC.pl)' commands # SEE Make:target name # SEE Make:target name prefix testcmd-c%: EXE.pl = ../$(SRC.pl) testcmd-c%: TEST.init = --header testcmd-c+info-_%: TEST.args += +info testcmd-c+info--trace-cmd_%: TEST.args += +info --trace-cmd testcmd-c+info--trace-key_%: TEST.args += +info --trace-key testcmd-c+info--trace-time_%: TEST.args += +info --trace-time testcmd-c+info--trace-key-norc_%: TEST.args += +info --trace-key --norc testcmd-c+check_%: TEST.args += +check testcmd-c+check--nossltls_%: TEST.args += +check --nosslv2 --nosslv3 --notlsv1 --notlsv11 --notlsv12 --notlsv13 # simulates a server not responding to ciphers testcmd-c+check--trace-key_%: TEST.args += +check --trace-key testcmd-c+check--trace-time_%: TEST.args += +check --trace-time testcmd-c+check--trace-norc_%: TEST.args += +check --trace-cmd --trace-time --trace=2 --norc testcmd-c+check--trace-key-norc_%: TEST.args += +check --trace-key --norc testcmd-c+cipher-_%: TEST.args += +cipher testcmd-c+cipher--legacy-owasp_%: TEST.args += +cipher --legacy=owasp testcmd-c+cipher--force-openssl_%: TEST.args += +cipher --force-openssl testcmd-c+cipher--cipher-openssl_%: TEST.args += +cipher --cipher-openssl testcmd-c+cipher--cipher-alpn_%: TEST.args += +cipher --cipher-alpn testcmd-c+cipher--cipher-npn_%: TEST.args += +cipher --cipher-npn testcmd-c+cipher--cipher-curves_%: TEST.args += +cipher --cipher-curves #TODO: testcmd-c+cipher--cipher-npns-%: TEST.args += +cipher --cipher-npns=, #TODO: testcmd-c+cipher--cipher-npns-%: TEST.args += +cipher --cipher-npns=, --cipher-npns=,, #TODO: testcmd-c+cipher--cipher-npns-%: TEST.args += +cipher --cipher-npns=, --cipher-npns=ecdh_x448 testcmd-c+cipherall_%: TEST.args += +cipherall testcmd-c+cipherraw_%: TEST.args += +cipherraw testcmd-c+cipher-dh_%: TEST.args += +cipher-dh testcmd-c+cipher-default_%: TEST.args += +cipher-default testcmd-c+ciphercheck_%: TEST.args += +ciphercheck testcmd-c+cipher--nossltls_%: TEST.args += +cipher --nosslv2 --nosslv3 --notlsv1 --notlsv11 --notlsv12 --notlsv13 # simulates a server not responding to ciphers testcmd-c_vuln-+BEAST_%: TEST.args += +BEAST testcmd-c_vuln-+CRIME_%: TEST.args += +CRIME testcmd-c_vuln-+DROWN_%: TEST.args += +DROWN testcmd-c_vuln-+FREAK_%: TEST.args += +FREAK testcmd-c_vuln-+POODLE_%: TEST.args += +POODLE testcmd-c_vuln-+logjam_%: TEST.args += +logjam testcmd-c_vuln-+lucky13_%: TEST.args += +lucky13 testcmd-c_vuln-+Sloth_%: TEST.args += +Sloth testcmd-c_vuln-+Sweet32_%: TEST.args += +Sweet32 testcmd-c_summ-+bsi_%: TEST.args += +bsi testcmd-c_summ-+TR-02102+_%: TEST.args += +TR-02102+ testcmd-c_summ-+EV_%: TEST.args += +EV testcmd-c_summ-+quick_%: TEST.args += +quick --trace-arg testcmd-c_summ-+http_%: TEST.args += +http testcmd-c_summ-+hsts_%: TEST.args += +hsts testcmd-c_summ-+ocsp_%: TEST.args += +ocsp testcmd-c_summ-+preload_%: TEST.args += +preload testcmd-c_summ-+protocols_%: TEST.args += +protocols testcmd-c_summ-+fingerprints_%: TEST.args += +fingerprints testcmd-c_summ-+sizes_%: TEST.args += +sizes testcmd-c_summ-+pfs_%: TEST.args += +pfs testcmd-c_summ-+sts_%: TEST.args += +sts testcmd-c_summ-+sni_%: TEST.args += +sni testcmd-c_summ-+vulns_%: TEST.args += +vulns # SEE Make:target matching # NOTE: no sort because we want the sequence of target definitions above. ALL.testcmds = $(shell awk -F% '($$1 ~ /^testcmd-c./){print $$1}' $(_MYSELF.cmds)) ALL.test.cmds = $(foreach host,$(TEST.cmds.hosts),$(ALL.testcmds:%=%$(host))) ALL.test.cmds.log += $(ALL.test.cmds:%=%.log) test.cmds.all: $(ALL.test.cmds) test.cmds: test.cmds.all test.cmds.log: $(ALL.test.cmds.log) # For calling various targets together and other examples, # see test.pattern-% pattern rule # testrun target to allow something like: testrun-+my-fancy-command # Note that we use testrun-+% and not testrun+% to avoid double definition # of the pattern rule (problem in GNUmake) # unfortunatelly this restricts the usage to pattern starting with + # EXE.pl and TEST.init will be inhereted from testcmd-c% . testrun-+%: TEST.args += $(TEST.cmds.hosts) testrun-%: testcmd-% @echo -n "" # TODO: use target _no-hosts #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.cmds) ALL.tests.log += $(ALL.test.cmds.log) O-Saft-19.01.19/t/Makefile.critic000066400000000000000000000231611342117255600162350ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing o-saft.pl #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile to perform testing tasks with perlcritic #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see ../Makefile . # # Naming conventions for targets see ../Makefile.help . # # TODO: # * complete with tests from t/test-o-saft.cgi.sh # #? VERSION #? @(#) Makefile.critic 1.8 19/01/19 17:14:11 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.critic = 1.8 _MYSELF.critic = t/Makefile.critic ALL.includes += $(_MYSELF.critic) ALL.inc.type += critic first-critic-target-is-default: help.test.critic ifeq (,$(_SID.test)) -include t/Makefile endif #_____________________________________________________________________________ #________________________________________________________________ variables __| CRITIC.dir = $(TEST.dir) CRITIC.rc = .perlcriticrc CRITIC.severity = -5 CRITIC.opt = CRITIC.pretty = ALL.critic = $(SRC.pl) $(ALL.pm) $(GEN.pod) # $(CHK.pl) # using perlcritic's --verbose options without ( and ) ; see: man perlcritic _CRITIC.verb8 = [%p] %m at line %l, column %c. Severity: %s\n _CRITIC.verb10 = %m at line %l, column %c.\n %p Severity: %s\n%d\n # same options, but output prefixed with filename _CRITIC.verb8o = --verbose '%f: $(_CRITIC.verb8)' _CRITIC.verb10o = --verbose '%f: $(_CRITIC.verb10)' CRITIC.opt = $(_CRITIC.verb8o) # perlcritic --verbose 8 is default ; hence we use this modified HELP-help.test.critic = print targets for using perlcritic # some aliases help.critic: help.test.critic critic.help: help.test.critic criticdoc: help.test.critic #_____________________________________________________________________________ #__________________________________________________ targets for testing cgi __| HELP.critic = "\ \# ________________________________ targets for code quality _$(_NL)\ critic - check files with perlcritic $(_NL)\ critic345 - check files with perlcritic for severity 3,4,5 $(_NL)\ help.critic - print more details about critic-* targets $(_NL)\ \#$(_NL)\ \# More critic targets exist, calling perlcritic with additional options$(_NL)\ \# _______________________________________________ severity _$(_NL)\ critic - perlcritic --severity 5 $(_NL)\ critic-5 - perlcritic --severity 5 $(_NL)\ critic-4 - perlcritic --severity 4 $(_NL)\ critic-3 - perlcritic --severity 3 $(_NL)\ critic-2 - perlcritic --severity 2 $(_NL)\ \# _____________________________________________ statistics _$(_NL)\ critic-count - perlcritic --severity 5 -count$(_NL)\ critic-stat - perlcritic --severity 5 --statistics-only $(_NL)\ critic-stat-4 - perlcritic --severity 4 --statistics-only $(_NL)\ critic-stat-3 - perlcritic --severity 3 --statistics-only $(_NL)\ \# ___________________________________ single file severity _$(_NL)\ c5-FILE - perlcritic --severity 5 FILE$(_NL)\ c4-FILE - perlcritic --severity 4 FILE$(_NL)\ c3-FILE - perlcritic --severity 3 FILE$(_NL)\ \# ___________________________ single file verbose severity _$(_NL)\ c5v-FILE - perlcritic --severity 5 FILE --verbose 10$(_NL)\ c4v-FILE - perlcritic --severity 4 FILE --verbose 10$(_NL)\ c3v-FILE - perlcritic --severity 3 FILE --verbose 10$(_NL)\ \# _____________________ targets with pretty-printed output _$(_NL)\ TARGETp - call TARGET and pretty print output$(_NL)\ \#$(_NL)\ \# Where FILE is any of the *.pm or *.pl files (including path).$(_NL)\ \# Where TARGET is any of:$(_NL)\ \# critic critic-5 critic-4 critic-3 critic-2 critic-count critic-stat$(_NL)\ \#$(_NL)\ \# None of the critic-* targets is available with the -v or -vv suffix$(_NL)\ \# because verbose does not make sense here.$(_NL)\ \#$(_NL)\ \# Note about perlcritic used here:$(_NL)\ \# * perlcritic is executed in directory '$(CRITIC.dir)'$(_NL)\ \# * perlcritic uses '$(CRITIC.dir)/$(CRITIC.rc)'$(_NL)\ \# See also '$(CONTRIB.dir)/critic.sh'$(_NL)\ " ALL.help.test += $(_NL)$(HELP.critic) #_____________________________________________________________________________ #_________________________________________________ targets for code quality __| $(CRITIC.dir): echo C && exit 1 @$(TARGET_VERBOSE) @mkdir -p $(CRITIC.dir) perlcritic-%: $(CRITIC.dir) @mkdir $@ # All targets use $(ALL.critic) as list of sources, which must be set as # environment or on command line # Note that $(ALL.test.critic) is a list of targets. # target prints command with echo so that it is also shown when called with # "make -s critic ..." critic: $(CRITIC.dir) @$(TARGET_VERBOSE) @echo "perlcritic $(ALL.critic) $(CRITIC.severity) $(CRITIC.opt)" @-cd $(CRITIC.dir) && \ perlcritic $(ALL.critic:%=../%) $(CRITIC.severity) $(CRITIC.opt) cf: $(CRITIC.dir) @$(TARGET_VERBOSE) @echo "perlcritic $(ALL.critic) $(CRITIC.severity) $(CRITIC.opt)" @-cd $(CRITIC.dir) && \ echo perlcritic $(ALL.critic:%=../%) $(CRITIC.severity) $(CRITIC.opt) # Same target as above but piped to filter for pretty printing. # Because the filter is a pipe, we loose the coloured output from perlcritic critic-pretty: $(CRITIC.dir) @$(TARGET_VERBOSE) @echo "perlcritic $(ALL.critic) $(CRITIC.severity) $(CRITIC.opt)" @-cd $(CRITIC.dir) && \ perlcritic $(ALL.critic:%=../%) $(CRITIC.severity) $(CRITIC.opt) \ | awk '\ { gsub(/\.$$/,""); C=" remove trailing . (for --statistics-only)"; }\ /OK$$/{ $$2=$$1; $$1="OK\t"; $$3=""; C=" toggle $1 and $2"; ok=1; } \ /: *[0-9][0-9]*$$/{ $$0=sprintf("%d\t%s",$$2,$$1); C=" toggle $1 and $2"; } \ /^Average /{ x=$$NF; $$NF=""; $$0=sprintf("%9s %s",x,$$0); } \ /^Violatio/{ x=$$NF; $$NF=""; $$0=sprintf("%9s %s",x,$$0); } \ /^[0-9 ][0-9 ,]* /{ x=$$1; $$1=""; $$0=sprintf("%9s %s",x,$$0); } \ {\ gsub(/\.\../,""); C=" remove leading ../"; \ gsub(/\:$$/,""); C=" remove trailing : (for --count)"; \ gsub(/ was *$$/,""); C=" remove trailing string (for --statistics-only)"; \ print; \ }\ END{ if (ok==0){ $$1="failed\t"; print; }}\ ' # TODO: above gawk needs to detect errors and then print "failed filename" critic-5: CRITIC.severity = -5 critic-5p: CRITIC.severity = -5 critic-5p: CRITIC.pretty = -pretty critic-4: CRITIC.severity = -4 critic-4p: CRITIC.severity = -4 critic-4p: CRITIC.pretty = -pretty critic-3: CRITIC.severity = -3 critic-3p: CRITIC.severity = -3 critic-3p: CRITIC.pretty = -pretty critic-2: CRITIC.severity = -2 critic-2p: CRITIC.severity = -2 critic-2p: CRITIC.pretty = -pretty critic-count: CRITIC.opt = -count critic-countp: CRITIC.pretty = -pretty critic-stat: CRITIC.opt = --statistics-only critic-statp: CRITIC.opt = --statistics-only critic-statp: CRITIC.pretty = -pretty critic-stat-4: CRITIC.opt = --statistics-only critic-stat-4: CRITIC.severity = -4 critic-stat-3: CRITIC.opt = --statistics-only critic-stat-3: CRITIC.severity = -3 ALL.test.critic = critic-5 critic-4 critic-3 critic-2 \ critic-count critic-stat critic-stat-4 critic-stat-3 critic-%: $(MAKE) $(MFLAGS) -s critic$(CRITIC.pretty) CRITIC.severity=$(CRITIC.severity) CRITIC.opt=$(CRITIC.opt) c5-%: @$(MAKE) -s ALL.critic=$* critic$(CRITIC.pretty) CRITIC.severity=-5 c4-%: @$(MAKE) -s ALL.critic=$* critic$(CRITIC.pretty) CRITIC.severity=-4 c3-%: @$(MAKE) -s ALL.critic=$* critic$(CRITIC.pretty) CRITIC.severity=-3 c5v-%: @$(MAKE) -s ALL.critic=$* critic$(CRITIC.pretty) CRITIC.severity=-5 CRITIC.opt="$(_CRITIC.verb10o)" c4v-%: @$(MAKE) -s ALL.critic=$* critic$(CRITIC.pretty) CRITIC.severity=-4 CRITIC.opt="--verbose $(_CRITIC.verb10o)" c3v-%: @$(MAKE) -s ALL.critic=$* critic$(CRITIC.pretty) CRITIC.severity=-3 CRITIC.opt="--verbose $(_CRITIC.verb10o)" # following targets required because they are not catched by critic-%; reason yet unknown critic-5: critic critic-4: critic critic-3: critic critic-2: critic criticp: critic-pretty $(CRITIC.dir)/perlcritic-$(_TODAY_)/severity%.txt: @$(TARGET_VERBOSE) @(echo "" && echo "" && echo "## Anzahl Fehler ...") > $@ @$(MAKE) $(MFLAGS) -s CRITIC.severity=$* critic-count >> $@ @(echo "" && echo "" && echo "## Statistik ...") >> $@ @$(MAKE) $(MFLAGS) -s CRITIC.severity=$* critic-stat >> $@ @(echo "" && echo "" && echo "## Fehler ...") >> $@ @$(MAKE) $(MFLAGS) -s CRITIC.severity=$* critic CRITIC.opt= >> $@ critic345: $(CRITIC.dir)/perlcritic-$(_TODAY_)/severity-5.txt $(CRITIC.dir)/perlcritic-$(_TODAY_)/severity-4.txt $(CRITIC.dir)/perlcritic-$(_TODAY_)/severity-3.txt # TODO: dirty hack target critic345.log critic345.log: @rm $(CRITIC.dir)/perlcritic-$(_TODAY_)/severity-5.txt $(CRITIC.dir)/perlcritic-$(_TODAY_)/severity-4.txt $(CRITIC.dir)/perlcritic-$(_TODAY_)/severity-3.txt @$(MAKE) $(MFLAGS) -s critic345 .PHONY: critic critic-5 critic-4 critic-3 critic-2 critic345 critic345.log #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.critic) #ALL.tests.log += O-Saft-19.01.19/t/Makefile.exit000066400000000000000000000076471342117255600157440ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing O-Saft options #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile to perform testing tasks for O-Saft --exit=* options. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see # ../Makefile ../Makefile.help Makefile.template # #? VERSION #? @(#) Makefile.exit 1.6 19/01/13 20:53:22 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.exit = 1.6 _MYSELF.exit = t/Makefile.exit ALL.includes += $(_MYSELF.exit) ALL.inc.type += exit first-exit-target-is-default: help.test.exit ifeq (,$(_SID.test)) -include t/Makefile endif TEST.exit.hosts = localhost ifdef TEST.hosts TEST.exit.hosts = $(TEST.hosts) endif HELP.exit = "\ \# _______________________________________ testing --exit=* _$(_NL)\ test.exit - test --exit=* options$(_NL)\ test.exit.log - same as test.exit but store output in t/test.exit.log$(_NL)\ \#$(_NL)\ \# Examples (get list of all targets): $(_NL)\ \# make s-ALL.test.exit $(_NL)\ \# Hint: use test.pattern-exit- instead of test.pattern-exit , as the$(_NL)\ \# patttern cgi may match other targets too.\ " ALL.help.test += $(_NL)$(HELP.exit) HELP-help.test.exit = print targets for testing '$(SRC.pl)' --exit= option # all known --exit= are shown with: o-saft.pl --norc --help=exit test.exit.labels = \ BEGIN0 BEGIN1 \ INIT0 WARN \ CONF0 CONF1 \ INIT1 ARGS \ MAIN \ HOST0 HOST1 HOST2 HOST3 HOST4 HOST5 HOST6 HOST8 HOST9 \ END # SEE Make:target name # SEE Make:target name prefix # using prefix testmsg- to avoid conflict with pattern rule testcmd-% testmsg-exit-%: EXE.pl = ../$(SRC.pl) testmsg-exit-%: TEST.init = +cn $(TEST.host) testmsg-exit-000: TEST.args += --exit=invalid_label_to_show_failed-status testmsg-exit-BEGIN0: TEST.args += --exit=BEGIN0 testmsg-exit-BEGIN1: TEST.args += --exit=BEGIN1 testmsg-exit-INIT0: TEST.args += --exit=INIT0 testmsg-exit-WARN: TEST.args += --exit=WARN +force-warning testmsg-exit-CONF0: TEST.args += --exit=CONF0 testmsg-exit-CONF1: TEST.args += --exit=CONF1 testmsg-exit-INIT1: TEST.args += --exit=INIT1 testmsg-exit-ARGS: TEST.args += --exit=ARGS testmsg-exit-MAIN: TEST.args += --exit=MAIN testmsg-exit-HOST0: TEST.args += --exit=HOST0 testmsg-exit-HOST1: TEST.args += --exit=HOST1 testmsg-exit-HOST2: TEST.args += --exit=HOST2 testmsg-exit-HOST3: TEST.args += --exit=HOST3 testmsg-exit-HOST4: TEST.args += --exit=HOST4 test.exit-HOST4: TEST.args += --exit=HOST4 testmsg-exit-HOST5: TEST.args += --exit=HOST5 testmsg-exit-HOST6: TEST.args += --exit=HOST6 testmsg-exit-HOST7: TEST.args += --exit=HOST7 testmsg-exit-HOST8: TEST.args += --exit=HOST8 testmsg-exit-HOST9: TEST.args += --exit=HOST9 testmsg-exit-END: TEST.args += --exit=END testmsg-exit-%: message-% @echo -n "" testmsg-exit.log: $(TEST.logdir) @$(TARGET_VERBOSE) @$(eval _NEW.log := $(TEST.logdir)/$@-$(_TODAY_)) @echo "# Makefile.exit 1.6: make $@" > $@ @$(MAKE) $(MFLAGS) -s $(ALL.test.exit) >> $@ 2>&1 @-diff $(TEST.logdir)/$@ $@ 2>/dev/null \ && rm $@ \ || mv $@ $(_NEW.log) @-test -f $(TEST.logdir)/$@ || mv $(_NEW.log) $(TEST.logdir)/$@ @-ls -l $(TEST.logdir)/$(@)* # FIXME: need to remove $(_NEW.log) when -n was given ALL.test.exit.log = test.exit.log #ALL.testexit = same as ALL.test.exit ALL.test.exit = $(test.exit.labels:%=testmsg-exit-%) test.exit.all: $(ALL.test.exit) test.exit: test.exit.all #_____________________________________________________________________________ #_____________________________________________________________________ test __| ALL.tests += $(ALL.test.exit) ALL.tests.log += $(ALL.test.exit.log) O-Saft-19.01.19/t/Makefile.ext000066400000000000000000000113631342117255600155610ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing O-Saft with external FQDN #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile to perform testing tasks for O-Saft project. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see # ../Makefile ../Makefile.help Makefile.template # #? VERSION #? @(#) Makefile.ext 1.12 19/01/11 22:59:45 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.ext = 1.12 _MYSELF.ext = t/Makefile.ext ALL.includes += $(_MYSELF.ext) ALL.inc.type += ext first-ext-target-is-default: help.test.ext ifeq (,$(_SID.test)) -include t/Makefile endif TEST.file = t/Makefile.FQDN # FIXME: TEST.file must depend on targets herein ifdef TEST.hosts TEST.ext.hosts = $(TEST.hosts) else TEST.ext.hosts = $(shell grep ^[a-zA-Z0-9] $(TEST.file)) endif HELP.ext = "\ \# _______________________________ test with external hosts _$(_NL)\ test.ext - test all commands with all hostnames, alias for test.ext.host$(_NL)\ test.ext.host - test all commands with all hostnames (sorted by host)$(_NL)\ test.ext.host.log - same as test.ext.host but store output in logfile$(_NL)\ test.ext.command - test all commands with all hostnames (sorted by command)$(_NL)\ test.ext.log - alias for test.ext.host.log$(_NL)\ test.ext.host.quick- test some commands with all hostnames$(_NL)\ \# ________________________________________ special targets _$(_NL)\ testcmd-eDDD_HOST - specific test target with HOST (available targets see: help.test.ext.all)$(_NL)\ testcmd-eDDD_HOST.log - same as testcmd-DDD_HOST but store output in t/testcmd-DDD_HOST.log$(_NL)\ \#$(_NL)\ \# Examples: $(_NL)\ \# make testcmd-e001_localhost $(_NL)\ \# make s-ALL.ext.host TEST.file=t/Makefile.FQDN $(_NL)\ \# make s-ALL.ext.host TEST.hosts='a1.tld a2.tld' $(_NL)\ \# make test.ext.host TEST.hosts='a1.tld a2.tld' $(_NL)\ \#$(_NL)\ \# To see which commands are executed, simply call 'make -n ...' $(_NL)\ " ALL.help.test += $(_NL)$(HELP.ext) HELP-help.test.ext = print targets for testing '$(SRC.pl)' with external FQDN HELP.ext.all = "\# targets for testing all command for all hosts:$(_NL)$(ALL.by_host)" testcmd-e%: EXE.pl = ../$(SRC.pl) testcmd-e%: TEST.init = --header testcmd-e000_%: TEST.args += +quit testcmd-e001_%: TEST.args += +info testcmd-e005_%: TEST.args += +info --short --showhost --trace=key testcmd-e006_%: TEST.args += +info --no-dns --no-sslv2 --no-sslv3 --experimental testcmd-e010_%: TEST.args += +check testcmd-e011_%: TEST.args += +check --enabled testcmd-e015_%: TEST.args += +check-sni testcmd-e020_%: TEST.args += +cipher testcmd-e021_%: TEST.args += +cipherall testcmd-e022_%: TEST.args += +cipherraw testcmd-e023_%: TEST.args += +cipher-dh testcmd-e024_%: TEST.args += +cipher-default testcmd-e030_%: TEST.args += +protocols testcmd-e035_%: TEST.args += +hsts testcmd-e066_%: TEST.args += +vulns +pfs testcmd-e070_%: TEST.args += +modulus +modulus_exponent +pubkey +pubkey_value +pubkey_algorithm --tracekey --nodns --nohttp testcmd-e071_%: TEST.args += +modulus_exp_1 +modulus_size_oldssl +modulus_exp_65537 +modulus_exp_oldssl +pub_encryption +pub_enc_known +sig_encryp tion +sig_enc_known --tracekey --nodns --nohttp testcmd-e081_%: TEST.args += +cn +subject +altname +serial +serial_hex +serial_int +sernumber +rfc6125_names --tracekey --nodns --nohttp ALL.testext = $(shell awk -F_ '/^testcmd-e[0-9]/{print $$1}' $(_MYSELF.ext)) ALL.by_host = $(foreach host,$(TEST.ext.hosts),$(ALL.testext:%=%_$(host))) ALL.by_command = $(foreach cmd,$(ALL.testext),$(TEST.ext.hosts:%=$(cmd)_%)) ALL.test.ext = $(ALL.by_host) ALL.ext.host = $(ALL.by_host) ALL.ext.host.log= $(ALL.by_host:%=%.log) HELP.ext.internal = "\ \# test.ext.host: $(test.ext.host)$(_NL)\ \# test.ext.command: $(test.ext.command)$(_NL)\ " # TODO: use target _no-hosts test.ext.host: $(ALL.by_host) test.ext.command: $(ALL.by_command) test.ext: test.ext.host test.ext.host.log: $(ALL.ext.host.log) test.ext.log: test.ext.host.log test.ext.host-%: test.ext.internal test.ext.host ALL.ext.quick = testcmd-e000_ testcmd-e001_ testcmd-e021_ testcmd-e066_ test.ext.host.quick: $(foreach host,$(TEST.ext.hosts),$(ALL.ext.quick:%=%_$(host))) .PHONY: test.ext.host test.ext.command test.ext.host.log test.ext.log #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.ext) ALL.tests.log += test.ext.log O-Saft-19.01.19/t/Makefile.hlp000066400000000000000000000123541342117255600155450ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing O-Saft --help options #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile to perform testing tasks for O-Saft project. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # To avoid naming conflicts with ../Makefile.help this file must be named # Makefile.hlp . # For details please see # ../Makefile ../Makefile.help Makefile.template # #? VERSION #? @(#) Makefile.hlp 1.8 19/01/13 21:32:26 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.hlp = 1.8 _MYSELF.hlp = t/Makefile.hlp ALL.includes += $(_MYSELF.hlp) ALL.inc.type += hlp first-hlp-target-is-default: help.test.hlp # see help.test.% ifeq (,$(_SID.test)) -include t/Makefile endif TEST.hlp.hosts = ifdef TEST.hosts TEST.hlp.hosts = $(TEST.hosts) endif HELP.hlp = "\ \# __________________________________________ test commands _$(_NL)\ test.hlp - test help commands and options$(_NL)\ test.hlp.log - same as test.hlp but store output in t/testcmd-CMD.log$(_NL)\ \#$(_NL)\ \# Examples: $(_NL)\ \# make s-ALL.test.hlp $(_NL)\ " ALL.help.test += $(_NL)$(HELP.hlp) HELP-help.test.hlp = print targets for testing '$(SRC.pl)' --help options testarg0-h-%: EXE.pl = ../$(SRC.pl) testarg0-h-%: TEST.init = --no-rc --header # these are kind of help, but do not use --help testarg0-h---cmd-VERSION: TEST.args += --cmd=VERSION testarg0-h-+VERSION: TEST.args += +VERSION testarg0-h-+help: TEST.args += +help=command testarg0-h-+version: TEST.args += +version testarg0-h-+version--usr: TEST.args += +version --v --usr testarg0-h---v+version: TEST.args += --v +version testarg0-h---v+help: TEST.args += --v +help testarg0-h-+ciphers: TEST.args += +ciphers --V testarg0-h-+ciphers-legacy-full: TEST.args += +ciphers --legacy=full testarg0-h-+ciphers-legacy-openssl: TEST.args += +ciphers --legacy=openssl testarg0-h-+ciphers-legacy-owasp: TEST.args += +ciphers --legacy=owasp # TODO: --legacy=owasp may change in future # --help testarg0-h--help-FAQ: TEST.args += --help=FAQ testarg0-h--help-WHY: TEST.args += --help=WHY testarg0-h--help-CHECK: TEST.args += --help=CHECK testarg0-h--help-alias: TEST.args += --help=alias testarg0-h--help-check: TEST.args += --help=check testarg0-h--help-cmd: TEST.args += --help=cmd testarg0-h--help-commands: TEST.args += --help=commands testarg0-h--help-compliance: TEST.args += --help=compliance testarg0-h--help-content: TEST.args += --help=content testarg0-h--help-data: TEST.args += --help=data testarg0-h--help-glossar: TEST.args += --help=glossar testarg0-h--help-intern: TEST.args += --help=intern testarg0-h--help-help: TEST.args += --help=help testarg0-h--help-hint: TEST.args += --help=hint testarg0-h--help-legacy: TEST.args += --help=legacy testarg0-h--help-links: TEST.args += --help=links testarg0-h--help-opt: TEST.args += --help=opt testarg0-h--help-options: TEST.args += --help=options testarg0-h--help-ourstr: TEST.args += --help=ourstr testarg0-h--help-pattern: TEST.args += --help=pattern testarg0-h--help-range: TEST.args += --help=range testarg0-h--help-regex: TEST.args += --help=regex testarg0-h--help-rfc: TEST.args += --help=rfc testarg0-h--help-text: TEST.args += --help=text testarg0-h--help-toc: TEST.args += --help=toc testarg0-h--help-todo: TEST.args += --help=todo testarg0-h--help-tools: TEST.args += --help=tools testarg0-h--help-warning: TEST.args += --help=warning testarg0-h--help-cfg-check: TEST.args += --help=cfg-check testarg0-h--help-cfg-data: TEST.args += --help=cfg-data testarg0-h--help-cfg-hint: TEST.args += --help=cfg-hint testarg0-h--help-cfg-info: TEST.args += --help=cfg-info testarg0-h--help-cfg-text: TEST.args += --help=cfg-text testarg0-h--help-cfg-regex: TEST.args += --help=cfg-regex testarg0-h--help-gen-wiki: TEST.args += --help=gen-wiki testarg0-h--help-gen-html: TEST.args += --help=gen-html testarg0-h--help-gen-cgi: TEST.args += --help=gen-cgi testarg0-h--help-gen-pod: TEST.args += --help=gen-pod testarg0-h--help-exit: TEST.args += --help=exit testarg0-h--help--yeast-data: TEST.args += --yeast-data testarg0-h--help--yeast-prot: TEST.args += --yeast-prot ALL.testhlp = $(shell awk -F: '/^testarg0-h-%/{next} /^testarg0-h-/{print $$1}' $(_MYSELF.hlp)) ALL.test.hlp = $(ALL.testhlp) ALL.test.hlp.log= $(ALL.test.hlp:%=%.log) test.hlp.all: $(ALL.test.hlp) test.hlp: test.hlp.all test.hlp.log: $(ALL.test.hlp.log) .PHONY: test.hlp.log #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.hlp) ALL.tests.log += $(ALL.test.hlp.log) O-Saft-19.01.19/t/Makefile.inc000066400000000000000000000051441342117255600155320ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile.inc - define missing macros for Makefile #? #? SYNOPSYS #? ifndef ALL.Makefiles #? include Makefile.inc #? endif #? #? DESCRIPTION #? Defines general macros used in Makefile if they are missing. #? #? VERSION #? @(#) Makefile.inc 1.11 19/01/11 22:55:01 #? #? AUTHOR #? 18-may-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.inc = 1.11 ALL.includes += t/Makefile.inc ALL.inc.type += inc #_____________________________________________________________________________ #________________________________________________________________ variables __| # NOTE: all definitions herein should be idempotent, so that this file could be # included sevaral times. That's why only = and no += assignments are # used. ifndef Project Project = o-saft endif ifndef ProjectName ProjectName = O-Saft endif ifndef TEST.host TEST.host = localhost endif ifndef TEST.init TEST.init = --header endif ifndef TEST.dir TEST.dir = t endif ifndef TEST.logdir TEST.logdir = $(TEST.dir)/log endif ifndef TMP.dir TMP.dir = /tmp/$(Project) endif ifndef SRC.pl SRC.pl = o-saft.pl endif ifndef SRC.cgi SRC.cgi = o-saft.cgi endif ifndef SRC.tcl SRC.tcl = o-saft.tcl endif ifndef DEV.pl DEV.pl = yeast.pl endif ifndef MAKEFILE MAKEFILE = $(firstword $(MAKEFILE_LIST)) # Define a variable for myself, it is the first file in MAKEFILE_LIST. # $(MAKEFILE) will be used where any makefile is possible. # Makefile is used when exactly Makefile file is meant. # $(ALL.Makefiles) is used, when all makefiles are needed. Existance # of ALL.Makefiles can also be used to check if this file should be # included. endif ifndef ALL.Makefiles MAKE = $(MAKE_COMMAND) -f $(firstword $(MAKEFILE_LIST)) # Redefine MAKE with proper makefile if not called from ../Makefile # makefile given with -f option is first in MAKEFILE_LIST, usually endif # internal used tools (paths hardcoded!) ifndef MAKE MAKE = $(MAKE_COMMAND) endif ifndef MAKEFLAGS MAKEFLAGS = --no-builtin-variables --no-builtin-rules --no-print-directory endif ifndef ECHO ECHO = /bin/echo -e endif ifndef EXE.pl EXE.pl = o-saft.pl endif ifndef TAB TAB = \\011 endif ifndef _NL _NL = \\012 endif ifndef _CR _CR = \\015 endif # also set pseudo macro .SUFFIXES empty (in the hope, it's never needed) .SUFFIXES: O-Saft-19.01.19/t/Makefile.misc000066400000000000000000000174321342117255600157170ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for various O-Saft tests #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile containing general testing targets for O-Saft project. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see ../Makefile . # # Naming conventions for targets see ../Makefile.help . # #? VERSION #? @(#) Makefile.misc 1.16 19/01/13 21:06:52 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.misc = 1.16 _MYSELF.misc = t/Makefile.misc ALL.includes += $(_MYSELF.misc) ALL.inc.type += misc first-misc-target-is-default: help.test.misc ifeq (,$(_SID.test)) -include t/Makefile endif HELP.misc = "\ \# ____________________________________________ misc. tests _$(_NL)\ test.bench - call '$(EXE.bench)' for some benchmarks$(_NL)\ test.bench.log - call '$(EXE.bench)' and save result in '$(BENCH.times)'$(_NL)\ test.bunt - test '$(CONTRIB.dir)/bunt.pl' with sample file$(_NL)\ test.docker - test docker image$(_NL)\ help.dev - print targets for development$(_NL)\ " ALL.help.test += $(_NL)$(HELP.misc) HELP-help.test.misc = print misc. testing targets HELP-help.dev = print targets for development #_____________________________________________________________________________ #________________________________________________________________ variables __| #TEST.args = # is special in this makefile; do not overwrite TEST.args in other files _args.misc = +quit BENCH.times = $(EXE.bench).times BENCH.host = $(TEST.host) #_____________________________________________________________________________ #____________________________________________________________ various tests __| bench: test.bench test.bench: $(EXE.bench) $(BENCH.host) @echo "# use '$(MAKE) test.bench.log' to save result in '$(BENCH.times)'" test.bench.log: $(EXE.bench) $(BENCH.host) >> $(BENCH.times) test.bunt: $(EXE.test.bunt) @$(TARGET_VERBOSE) -cat $(EXE.test.bunt) | $(CONTRIB.dir)/bunt.pl # TODO: simple test, needs to be improved and checked test.docker: docker image ls owasp/o-saft $(EXE.docker) +VERSION $(EXE.docker) +version $(EXE.docker) usage ALL.test.misc = test.bench test.bunt test.docker # explicit list of targets in this makefile test.misc: $(ALL.test.misc) .PHONY: test.bench test.bench.log test.bunt test.docker #_____________________________________________________________________________ #__________________________________________________ targets for development __| HELP.dev = "\ \# ________________________________ targets for development _$(_NL)\ tags - generate tags file for vi(m)$(_NL)\ profile.sub.entry - generate function calling tree of '$(DEV.pl)' (entry only)$(_NL)\ profile.sub.exit - generate function calling tree of '$(DEV.pl)' (entry and exit)$(_NL)\ profile.sub.args - generate function calling tree of '$(DEV.pl)' (in, out and parameter)$(_NL)\ nytprof.out - generate profiling data (for nytprofcalls)$(_NL)\ nytprof.html - generate profiling data in HTML format$(_NL)\ dprof.out - generate profiling data (for dprofpp; times, counts, calling tree)$(_NL)\ code.quality - search for various common coding mistakes, see make e-ALL.test.quality\ " # TODO: if we switch HELP.dev to single lines HELP-* #help.dev: help.HEAD # @$(EXE.help) $(_MYSELF.misc) # @$(ECHO) "$(_HELP_LINE_)" help.dev: help.HEAD @$(ECHO) $(HELP.dev) @$(ECHO) "$(_HELP_LINE_)" $(GEN.tags): $(SRC.pl) $(ALL.pm) $(CHK.pl) $(SRC.cgi) $(SRC.tcl) $(ALL.Makefiles) ctags $^ ALL.test.dev = $(GEN.tags) ALL.test.dev += profile.sub.entry profile.sub.exit profile.sub.args nytprof.html dprof.out #ALL.test.dev += code.quality # following checks based on http://perldoc.perl.org/perldiag.html # TODO: all targets fail if checks returns nothing ALL.qa = $(ALL.pm) $(SRC.pl) qa.double_dref: @echo "#make: check depricated double dereferencing ..." @-egrep -H '\$$$$[^$$)]' $(ALL.qa) qa.defined_arr: @echo "#make: check depricated defined(@array) ..." @-egrep -H 'defined[( ]*@' $(ALL.qa) qa.defined_hash: @echo "#make: check depricated defined(%hash) ..." @-egrep -H 'defined[( ]*%' $(ALL.qa) qa.misspelled_regex: @echo "#make: check misspelled grouping in RegEx ..." @-egrep -H '\(:\?' $(ALL.qa) qa.misspelled_critic: @echo "#make: check misspelled use of ## no critic ..." @-egrep -H ' # no critic' $(ALL.qa) ALL.test.quality= qa.double_dref qa.defined_arr qa.defined_hash qa.misspelled_regex qa.misspelled_critic code.quality: $(ALL.test.quality) # TODO: Profiling should go to Makefile.profile or alike # SEE Make:Profiling # SEE Make:profile.sub # SEE Make:profile.sub*_% # SEE Make:profile.sub% target rule _PROFILE.profile.log= $(TEST.logdir)/profile.sub.log PROFILE.host = localhost profile.sub.entry: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=1' profile.sub.entry_%: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=1' profile.sub.exit: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=2' profile.sub.exit_%: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=2' profile.sub.args: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=15' profile.sub.args_%: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=15' # pattern rules can contain one % only, hence following sequence for _lineinfo is mandatory profile.sub.%: _lineinfo = LineInfo=$(_PROFILE.profile.log) profile.sub.%.log: _lineinfo = LineInfo=$(_PROFILE.profile.log) profile.sub.entry.log: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=1 $(_lineinfo)' profile.sub.exit.log: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=2 $(_lineinfo)' profile.sub.args.log: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=15 $(_lineinfo)' profile.sub.entry.log%: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=1 $(_lineinfo)' profile.sub.exit.log%: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=2 $(_lineinfo)' profile.sub.args.log%: PERL.OPTS = PERLDB_OPTS='NonStop=1 frame=15 $(_lineinfo)' profile.sub%: @$(eval _args = $(shell echo "$*" | awk -F_ '{i=1;while(i&1 # TODO: # make profile.sub.entry | sed -e 's/ entering //' # make profile.sub.exit | sed -e 's/ entering /+/' -e 's/exited / -/' # make profile.sub.args | sed -e 's/ in /+/' -e 's/out / -/' -e 's/ from .*\//\t/' # better use dprof.out below _nytprof.log = $(TEST.logdir)/nytprof.out nytprof.out: $(_nytprof.log) @perl -d:NYTProf $(DEV.pl) $(PROFILE.host) $(_args.misc) @mv $@ $< @echo "# inspect with: nytprofcalls $(_nytprof.log)" nytprof.html: $(_nytprof.log) @nytprofhtml --file $< @echo "# inspect with: firefox $(TEST.dir)/nytprof/index.html" nytprof: nytprof.html _dprof.log = $(TEST.logdir)/dprof.out $(_dprof.log): @env PERL_DPROF_OUT_FILE_NAME=$(_dprof.log) perl -d:DProf $(DEV.pl) $(PROFILE.host) $(_args.misc) @dprofpp $(_dprof.log) @echo "" @echo "# show calling tree: dprofpp -t $(_dprof.log)" #dprof.out: PERL_DPROF_OUT_FILE_NAME=$(_dprof.log) dprof.out: $(_dprof.log) # useful options: -T -I # dprofpp -t -f "(Carp::)|(Exporter::)|(Symbol::)|(DynaLoader::)" .PHONY: $(_dprof.log) # TODO: define summary macro for all profile targets ALL.test.profile= profile.sub.entry profile.sub.exit profile.sub.args \ nytprof.out nytprof.html dprof.out \ code.quality test.misc.all: test.misc $(ALL.test.profile) #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.misc) ALL.tests.log += test.bench.log O-Saft-19.01.19/t/Makefile.opt000066400000000000000000000151761342117255600155710ustar00rootroot00000000000000#! /usr/bin/make -rRf #? # TODO: initial version, needs to be completed ############################################################################## #? NAME #? Makefile - makefile for testing O-Saft options #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile to perform testing tasks for O-Saft project. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see # ../Makefile ../Makefile.help Makefile.template # #? VERSION #? @(#) Makefile.opt 1.5 19/01/11 22:59:58 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.opt = 1.5 _MYSELF.opt = t/Makefile.opt ALL.includes += $(_MYSELF.opt) ALL.inc.type += opt first-opt-target-is-default: help.test.opt ifeq (,$(_SID.test)) -include t/Makefile endif TEST.opt.hosts = localhost ifdef TEST.hosts TEST.opt.hosts = $(TEST.hosts) endif HELP.opt = "\ \# ________________________________________ testing options _$(_NL)\ test.opt - test various alias options$(_NL)\ test.opt.log - same as test.opt but store output in t/testcmd-CMD.log$(_NL)\ \#$(_NL)\ \# Examples: $(_NL)\ \# make s-ALL.test.opt $(_NL)\ " ALL.help.test += $(_NL)$(HELP.opt) HELP-help.test.opt = print targets for testing '$(SRC.pl)' options testopt-alias%: EXE.pl = ../$(SRC.pl) testopt-alias%: TEST.init = --traceARG --v +quit # The part right of the _ in the target name testarg0-alias* is the pattern # to be searched for in the output of $(EXE.pl). As this might contain chars # not allowed in make's target names, . (dot) are used (i.e. for = or space). testopt-alias_enabled..1: TEST.args += --exit=MAIN -b testopt-alias_enabled..2: TEST.args += --exit=MAIN -b testopt-alias_ca_path..x: TEST.args += --exit=MAIN -c x # folgende noch in passende Makefile verschieben testopt-alias_HOST0: TEST.init = #testarg0-alias_HOST0: TEST.args += --exit=HOST0 +cn demo demo:42 egal --port 23 localhost testopt-alias_HOST0: TEST.args += --exit=HOST0 +cn ::1 ::244 # yeast.pl --exit=HOST0 +cn demo demo:42 egal --port 23 localhost ::1/erkannt_aber_falsch "[::266]" --port=22 "[::244]:32/egal" ::1:333/x/ambigious_port_falsch testopt-alias_%: message-% @echo "" testarg0-stdformat-%: EXE.pl = ../$(SRC.pl) testarg0-stdformat-%: TEST.init = --no-rc --help=pod testarg0-stdformat-crlf: TEST.args += --stdformat=crlf testarg0-stdformat-raw: TEST.args += --stdformat=raw testarg0-stdformat-unix: TEST.args += --stdformat=unix testarg0-stdformat-utf8: TEST.args += --stdformat=utf8 testarg0-stdformat-UTF8: TEST.args += --stdformat=UTF-8 testarg0-stdformat-UTF-8: testarg0-stdformat-UTF8 # TODO: vialid options to be tested here #stdarg0-opt-001: TEST.args += --sslv3 --ssl-v3 --sslv3 -.sslv3 -_sslv3 --ssl3 --ssl3 #stdarg0-opt-001: TEST.args += --no-sslv2 --no-ssl-v2 --nosslv2 --no.sslv2 --no_sslv2 --no-ssl2 --nossl2 #stdarg0-opt-001: TEST.args += --no-sslv3 --no-ssl-v3 --nosslv3 --no.sslv3 --no_sslv3 --no-ssl3 --nossl3 #stdarg0-opt-101: TEST.args += --short #stdarg0-opt-102: TEST.args += --short-txt #stdarg0-opt-103: TEST.args += --shorttext #stdarg0-opt-104: TEST.args += --separator SEP #stdarg0-opt-105: TEST.args += --sep=SEP #stdarg0-opt-106: TEST.args += --nocerttext='no text' #stdarg0-opt-107: TEST.args += --nocerttxt 'no text' #stdarg0-opt-108: TEST.args += --no-dns-mx #stdarg0-opt-109: TEST.args += --nodns-mx #stdarg0-opt-110: TEST.args += --no-mx #stdarg0-opt-111: TEST.args += --dns-mx #stdarg0-opt-112: TEST.args += --no-http #stdarg0-opt-113: TEST.args += --nohttp #stdarg0-opt-114: TEST.args += --http #stdarg0-opt-115: TEST.args += --enabled #stdarg0-opt-115: TEST.args += --timeout=23 #stdarg0-opt-117: TEST.args += -timeout 23 #stdarg0-opt-118: TEST.args += --traceKEY #stdarg0-opt-119: TEST.args += --traceKEY --showhost # TODO: valid hosts and host options to be tested here #stdarg0-opt-201: TEST.args += --host=a.b #stdarg0-opt-202: TEST.args += --host a.b #stdarg0-opt-203: TEST.args += --h a.b #stdarg0-opt-204: TEST.args += --port=42 #stdarg0-opt-205: TEST.args += --port 42 #stdarg0-opt-206: TEST.args += --p 42 #stdarg0-opt-207: TEST.args += a.b #stdarg0-opt-208: TEST.args += a-b #stdarg0-opt-209: TEST.args += a.b:42 #stdarg0-opt-210: TEST.args += https://a.b:333/path #stdarg0-opt-211: TEST.args += https://a.b:333/path?key=val #stdarg0-opt-212: TEST.args += https://user:pass@a.b:333/path # TODO: invalid options to be tested here #stdarg0-opt-501: TEST.args += --no-sslv #stdarg0-opt-502: TEST.args += --no-sslv1 #stdarg0-opt-503: TEST.args += -no-sslv1 #stdarg0-opt-504: TEST.args += --un=knwon #stdarg0-opt-505: TEST.args += +unknown-command #stdarg0-opt-506: TEST.args += +--quit #stdarg0-opt-507: TEST.args += +quit- #stdarg0-opt-508: TEST.args += +hsts-sts # note: no sort because we want the sequence as defined above ALL.testalias = $(shell awk -F: '/^testarg0-alias_[^%]/ {print $$1}' $(_MYSELF.opt)) ALL.teststdformat = $(shell awk -F: '/^testarg0-stdformat-[^%]/ {print $$1}' $(_MYSELF.opt)) ALL.test.stdformat = $(ALL.teststdformat) ALL.testopt += $(ALL.testalias) ALL.testopt += $(ALL.teststdformat) test.stdformat = $(ALL.teststdformat) .PHONY: test.stdformat #ALL.test.opt = $(foreach host,$(TEST.opt.hosts),$(ALL.testhelp:%=%$(host))) ALL.test.opt = $(ALL.testopt) ALL.test.opt.log= $(ALL.testopt:%=%.log) # TODO: use target _no-hosts # for debugging add test.opt.internal to the target's dependencies test.opt: $(ALL.test.opt) test.opt.log: $(ALL.test.opt.log) test.opt-%: test.opt.internal test.opt #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.opt) ALL.tests.log += $(ALL.test.opt.log) O-Saft-19.01.19/t/Makefile.pod000077500000000000000000000126271342117255600155520ustar00rootroot00000000000000#! /usr/bin/perldoc #? #? NAME #? Makefile.pod - documentation for Makefiles in POD format #? #? SYNOPSYS #? Makefile.pod #? perldoc Makefile.pod #? #? DESCRIPTION #? This file conatains the internal (developer) documentation for all other #? Makefiles. This is done to keep other Makefiles as simple as possible, #? and just containing the user documentation. #? # HACKER's INFO # #? VERSION #? @(#) Makefile.pod 1.3 19/01/13 21:24:02 #? #? AUTHOR #? 18-nov-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- =pod =head2 Make:GNU some text =head2 Make:automatic variables Note: macro is a synonym for variable in makefiles. Note: macro definitions in makefiles must not be sequential! Remember make's automatic variables: $@ - target (file) $+ - all dependencies of the target $^ - all dependencies of the target (without duplicates) $< - first dependency of the target $? - dependencies newer than the target $| - "orde-only" dependencies $* - matching files of the rule $% - target (archive) member name (rarely used) Use of $$ avoids evaluating $ . =head2 Make:target name For better readability, "speaking names" should be used for pattern rules and targets. It also allows to use the special pattern rule test.pattern-% to execute a group of similar targets. =head2 Make:target name prefix A unique name prefix for targets and pattern rules should be used in all Makefile.* to distinguish similar names. It also allows to use the pattern rule test.pattern-% to execute a group of similar targets. Following macros should then be set only for these targets, like: testcmd-TEMPL%: EXE.pl = ../program-for.TEMPL testcmd-TEMPL%: TEST.init = +quit =head2 Make:target matching For collecting all targets defined in a Makefile.*, following $(shell awk) is used: $(shell awk -F% '($$1 ~ /^testcmd-c./){print $$1}' $(_MYSELF.some-type)) (where testcmd-c is an example target name). The pattern rule testcmd-c% itself must not be matched, hence the pattern /^testcmd-c./ needs to match $1 instead of $0 in the awk. =head2 Make:Profiling Profiling is mainly done with Perl's built-in functionality: perldebug. There are also targets using special Perl modules DProf and/or NYTProf to do the profiling. =head3 Perl packages * debian: libdevel-dprof-perl libdevel-nytprof-perl =head2 Make:profile.sub For building the function calling tree, perldebug (PERLDB_OPTS) is used. The results can be stored in a file, see LineInfo= options. Unfortunately perldebug writes output to the device directly (for example /dev/stdout). It is not possible to merge output from the executed script with that of perldebug. Following options are not helpful: * pager=|cat * LineInfo=/dev/stdout * noTTY=1 =head2 Make:profile.sub*_% It should be simply possible to extend the pattern rules with additional arguments. For example: profile.sub.args and profile.sub.args_+cn . These arguments are extracted in the pattern rule itself. This avoids to define additional conditional rules for each pattern rule to set the macro $(TEST.args) with the arguments. The simplest way to split the arguments would be: @$(eval _args = $(shell echo "$*" | tr '_' ' ')) but the last part of the target name needs to be removed, hence following is used for splitting: @$(eval _args = $(shell echo "$*" | awk -F_ '{i=1;while(i 2.0. #? # HACKER's INFO # For details please see # ../Makefile ../Makefile.help Makefile.template # #? VERSION #? @(#) Makefile.tcl 1.9 19/01/13 20:55:55 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.tcl = 1.9 _MYSELF.tcl = t/Makefile.tcl ALL.includes += $(_MYSELF.tcl) ALL.inc.type += tcl first-tcl-target-is-default: help.test.tcl ifeq (,$(_SID.test)) -include t/Makefile endif TEST.tcl.hosts = localhost ifdef TEST.hosts TEST.tcl.hosts = $(TEST.hosts) endif HELP.tcl = "\ \# ______________________________________________ GUI tests _$(_NL)\ test.tcl - test functionality of $(SRC.tcl)$(_NL)\ test.tcl.log - same as test.tcl but store output in $(TEST.logdir)/$(_NL)\ " ALL.help.test += $(_NL)$(HELP.tcl) HELP-help.test.tcl = print targets for testing GUI '$(Project).tcl' # SEE Make:target name # SEE Make:target name prefix testcmd-tcl%: EXE.pl = ../o-saft.tcl testcmd-tcl%: TEST.init = +quit # ensure that o-saft.tcl exits and does not build the GUI testcmd-tclverb+VERSION_%: TEST.args += +VERSION testcmd-tclverb--version_%: TEST.args += --version testcmd-tclverb--rc_%: TEST.args += --rc testcmd-tclverb--v--load_%: TEST.args += --v --load=Makefile # returns: TAB tabs: .... .note.oX1XX1 testcmd-tclverb--d_%: TEST.args += --d testcmd-tclverb--v_%: TEST.args += --v testcmd-tclverb--v--img_%: TEST.args += --v --img testcmd-tclverb--v--text_%: TEST.args += --v --text testcmd-tclverb--v-host_%: TEST.args += --v host1 host2 #testcmd-tclverb--v--load_%: TEST.args += --v --load=/tmp/some-file # TODO: compare results of testcmd-tclverb--v with # testcmd-tclverb--v--img, testcmd-tclverb--v--text, testcmd-tclcmd-verb--v-host testcmd-tclhelp--help_%: TEST.args += --help testcmd-tclhelp--help-flow_%: TEST.args += --help-flow testcmd-tclhelp--help-procs_%: TEST.args += --help-procs testcmd-tclhelp--help-descr_%: TEST.args += --help-descr testcmd-tclhelp--help-o-saft_%: TEST.args += --help-o-saft # test some warnings #testcmd-tclargs-unknown_%: TEST.args += unknown testcmd-tclargs--v-host1-host2_%: TEST.args += --v host1 host2 host3 host4 host5 host6 #testcmd-tclargs--v--load-bad_%: TEST.args += --load=/tmp/bad # file with large value > 5000 # SEE Make:target matching ALL.testtcl = $(shell awk -F% '($$1 ~ /^testcmd-tcl.../){print $$1}' $(_MYSELF.tcl)) ALL.test.tcl = $(foreach host,$(TEST.tcl.hosts),$(ALL.testtcl:%=%$(host))) ALL.test.tcl.log= $(ALL.test.tcl:%=%.log) test.tcl.all: $(ALL.test.tcl) test.tcl: test.tcl.all test.tcl.log: $(ALL.test.tcl.log) test.tcl-%: test.tcl.internal test.tcl.all echo -n "" #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.tcl) ALL.tests.log += $(ALL.test.tcl.log) O-Saft-19.01.19/t/Makefile.template000066400000000000000000000126201342117255600165710ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - template makefile for testing ... #? #? SYNOPSYS #? To be used as template for new targets in Makefile.SUFFIX. #? This file itself is not used (included) in t/Makefile. #? #? DESCRIPTION #? Template Makefile containing targets for testing SOMETHING. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see # ../Makefile ../Makefile.help # #? VERSION #? @(#) Makefile.template 1.8 19/01/13 21:22:42 #? #? AUTHOR #? 18-may-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.TEMPL = 1.8 _MYSELF.TEMPL = t/Makefile.template # must be hardcoded because $(firstword $(MAKEFILE_LIST)) # gets the file of the initial call "make" command ALL.includes += $(_MYSELF.TEMPL) # add ourself to list of all included makefiles ALL.inc.type += TEMPL # add our type to list of all included types first-TEMPL-target-is-default: help.test.TEMPL # otherwise the first target from other included files would be used ifeq (,$(_SID.test)) -include t/Makefile # get general macros for testing from master makefile endif #_____________________________________________________________________________ #________________________________________________________________ variables __| TEST.TEMPL.hosts = host.to.be.tested # define our list of TEST.hosts ifdef TEST.hosts TEST.TEMPL.hosts= $(TEST.hosts) # list of TEST.hosts can be passed with environment or on command line endif #_____________________________________________________________________________ #___________________________________________________________ default target __| HELP-help.test.TEMPL= print targets for testing SOMETHING # defines message for main Makefile's help* targets # private help target for this makefile help.test.TEMPL: @echo " $(_HELP_LINE_)$(_NL) $(_HELP_INFO_)$(_NL) $(_HELP_LINE_)$(_NL)" @echo $(MORE-TEMPL) ; # no quotes! #_____________________________________________________________________________ #_____________________________________________________ internal test target __| # just an internal info target test.TEMPL.internal: @echo "# TEST.file: $(TEST.file)" @echo "# TEST.TEMPL.hosts: $(TEST.TEMPL.hosts)" @echo "# ALL.testTEMPL: $(words $(ALL.testTEMPL)) : $(ALL.testTEMPL)" @echo "# ALL.test.TEMPL: $(words $(ALL.test.TEMPL)) : $(ALL.test.TEMPL)" @echo "# testcmd-TEMPL%: TEST.init = +quit" @echo "# -------------------------------------------------------------" .PHONY: help.test.TEMPL test.TEMPL.internal #_____________________________________________________________________________ #______________________________________________________________ testing ... __| # Description for private help text. # Note that we use quotes here, even if not really necessary (but makes syntax # highlighting in some editors more happy ;-) MORE-TEMPL = " \ \# ______________________________________________ testing ... _$(_NL)\ test.TEMPL - test functionality of SOMETHING$(_NL)\ test.TEMPL.log - same as test.TEMPL but store output in $(TEST.logdir)/$(_NL)\ \#$(_NL)\ \# Examples:$(_NL)\ \# make e-ALL.testTEMPL$(_NL)\ \# make s-ALL.test.TEMPL$(_NL)\ " # SEE Make:target name # SEE Make:target name prefix # SEE Make:target matching # There are two variants of defining unique targets in this Makefile. Only one # of them must be used: all from "Variant-1" or all from "Variant-2" ! ## Variant-1 { # initialize variables for our targets testcmd-TEMPL%: EXE.pl = ../program-for.TEMPL # program to perform the tests testcmd-TEMPL%: TEST.init = +quit # argument to be passed always to $(EXE.pl) # Set varables for each unique target. # Note that the % in the pattern rule will be used for the hostname later. testcmd-TEMPL001_%: TEST.args += +VERSION testcmd-TEMPL002_%: TEST.args += --help ALL.testTEMPL = $(shell awk -F% '($$1 ~ /^testcmd-TEMPL..._/){print $$1}' $(_MYSELF.TEMPL)) # dynamically generate list of all testcmd_TEMPLDDD targets ## Variant-1 } ## Variant-2 { testTEMPL-%: EXE.pl = ../program-for.TEMPL testTEMPL-%: TEST.init = +quit testTEMPL-001_%: TEST.args += +VERSION testTEMPL-002_%: TEST.args += --help ALL.testTEMPL = $(shell awk -F% '($$1 ~ /^testTEMPL-..._/){print $$1}' $(_MYSELF.TEMPL)) # pattern rule to map to testcmd-% testTEMPL-%: testcmd-% @echo -n "" ## Variant-2 } ALL.test.TEMPL = $(foreach host,$(TEST.TEMPL.hosts),$(ALL.testTEMPL:%=%$(host))) ALL.test.TEMPL.log= $(ALL.test.TEMPL:%=%.log) # generate list of all targets #_____________________________________________________________________________ #______________________________________________________ targets for testing __| test.TEMPL.all: $(ALL.test.TEMPL) test.TEMPL: test.TEMPL.all test.TEMPL.log: $(ALL.test.TEMPL.log) # more verbose target: test.TEMPL-v and test.TEMPL-vv test.TEMPL-%: test.TEMPL.internal test.TEMPL @echo -n "" #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.TEMPL) ALL.tests.log += $(ALL.test.TEMPL.log) O-Saft-19.01.19/t/Makefile.warnings000066400000000000000000000376151342117255600166210ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing O-Saft warning messages #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? Makefile with targets for testing warnings of o-saft.pl . #? All targets succedd, if the warning message is present, they fail, if #? the warning message is not present. #? #? LIMITATIONS #? Requires GNU Make > 2.0. #? # HACKER's INFO # For details please see # ../Makefile ../Makefile.help Makefile.template # # How target rules in this Makefile (should) work: # The pattern rule message-% from ./Makefile is used to check for a # specific warning message. The pattern rule searches (grep) the output # of o-saft.pl for a string, which is the pattern of the target name. # Each target rule defines its own arguments to be passed to o-saft.pl # # Mainly the +quit command is sufficient to get the warning. # The first target rule warning-000 is designed to fail. # All targets rules are summarized in the test.warnings rule. # # To log the results of these tests, only one file will be created, not # one for each target rule. That what test.warnings.log does. # # Limitations # The name of each individual target rule contains the pattern (049 in # above example ), which must be searched for in the output of EXE.pl . # As this is just a simple number in all rules here, the search may re- # sult in false positives. Manual checks of the rule commands (recipe) # are recommended from time to time. # #? VERSION #? @(#) Makefile.warnings 1.21 19/01/15 00:12:45 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.warnings = 1.21 _MYSELF.warnings= t/Makefile.warnings ALL.includes += $(_MYSELF.warnings) ALL.inc.type += warnings first-warn-target-is-default: help.test.warnings ifeq (,$(_SID.test)) -include t/Makefile endif ifndef TEST.host TEST.host = localhost endif #_____________________________________________________________________________ #_________________________________________________________ testing warnings __| HELP.warnings = "\ \# __________________________________________ test warnings _$(_NL)\ test.warnings - test **WARNING messages of '$(SRC.pl)'$(_NL)\ test.warnings.log - test **WARNING messages of '$(SRC.pl)' and compare with previous one$(_NL)\ message-STR - test for specific STR in output of '$(SRC.pl)'$(_NL)\ warning-NR - test for specific messages number NR of '$(SRC.pl)'$(_NL)\ warnings.gen.template - generate template Makefile for testing warning messages$(_NL)\ warnings.show.todo - show not implemented tests for warnings$(_NL)\ warnings.show.difficult - show tests for warnings which are difficult to implement$(_NL)\ \#$(_NL)\ \# Hint: message-STR can test for any string in output, example$(_NL)\ \# make message-Certificate TEST.args='+cn localhost'$(_NL)\ \#$(_NL)\ \# To print all available individual test-* and warning-* targets, use:$(_NL)\ \# make e-ALL.test.warnings$(_NL)\ \# make help.test.all$(_NL)\ \#$(_NL)\ \# Examples: $(_NL)\ \# make warning-042 $(_NL)\ \# make message-Certificate TEST.args='+cn localhost' $(_NL)\ " ALL.help.test += $(_NL)$(HELP.warnings) HELP-help.test.warnings = print targets for testing WARNING messages HELP.warnings.all = "\ \# for more details, use: $(MAKE) t-warn$(_NL)\ " # testing warning messages _TMP.rc = /tmp/o-saft.tmprc test.warnings%: EXE.pl = ../$(SRC.pl) warning-%: EXE.pl = ../$(SRC.pl) warning-%: TEST.init = # Each warning-* target defines its (conditional) command to be used with # $(EXE.pl). If the definition starts with the literal string "TODO:" the # target will only print the text (see message-%). # The TODO texts ending with "difficult ..." mark messages, which cannot # tested easily. # All other targets should define TEST.args with those arguments, which # force the warning message DDD given in the target's name warning-DDD . warning-000: TEST.args = --invalid_nr_to_show_failed-status warning-002: TEST.args = TODO: testing openssl returning error, difficult ... warning-003: TEST.args = TODO: testing openssl failed with allocate memory, difficult ... warning-004: TEST.args = TODO: testing perl returned status, difficult ... warning-005: TEST.args = TODO: testing missing IO/Socket/SSL.pm warning-006: TEST.args = TODO: testing missing IO/Socket/INET.pm warning-007: TEST.args = TODO: testing missing Net/DNS.pm warning-008: TEST.args = TODO: testing missing Time/Local.pm #warning-009: TEST.args = free warning-010: TEST.args = TODO: testing die, missing Net/SSLhello.pm warning-011: TEST.args = TODO: testing die, missing Net/SSLinfo.pm warning-012: TEST.args = TODO: testing die, missing Net::SSLeay.pm warning-013: TEST.args = TODO: testing die, missing o-saft-man.pm warning-014: TEST.args = TODO: testing die, missing Net::SSLeay.pm warning-015: TEST.args = TODO: testing die, no ciphers found, may happen with openssl pre 1.0.0, difficult ... warning-020: TEST.args = TODO: testing die, CGI mode requires strict settings warning-021: TEST.args = --set-score=unknown +quit warning-022: TEST.args = --cfgcmd-is=unknown +quit warning-023: TEST.args = --legacy=key +quit #warning-040: TEST.args = free warning-041: TEST.args = s_client +quit warning-042: TEST.args = +cn --port=' ' unknown-host +quit warning-043: TEST.args = --rc=$(_TMP.rc) --v +quit warning-043: TEST.rc = --cfg_cmd=new_command=quit warning-044: TEST.args = +zlib +lzo +open_pgp +fallback +quit #warning-045: TEST.args = free #warning-046: TEST.args = free warning-047: TEST.args = +info +cn any-host warning-048: TEST.args = +check +cn any-host warning-049: TEST.args = +unknown_command +quit warning-050: TEST.args = +cn --port= +quit warning-051: TEST.args = --label=unknown +quit warning-052: TEST.args = --rc=$(_TMP.rc) warning-052: TEST.rc = "--option=-with_trailing_spaces " warning-053: TEST.args = --capath='/path with spaces' +quit warning-054: TEST.args = --legacy=unknown_legacy +quit warning-055: TEST.args = --format=unknown_format +quit warning-056: TEST.args = --range=unknown_range +quit warning-057: TEST.args = --ciphercurves=unknown +quit warning-058: TEST.args = --ca-path=unknown +quit warning-059: TEST.args = --ca-path=unknown +quit warning-060: TEST.args = --ca-paths=unknown --cfg-init=ca_files=unknown +quit #warning-061: TEST.args = free warning-062: TEST.args = --cipher=unknown +cipher any-host warning-063: TEST.args = --cipher=UNKNOWN +cipher any-host warning-064: TEST.args = +sts --no-http any-host #warning-065: TEST.args = free warning-066: TEST.args = --ignore-out=cn +cn any-host warning-067: TEST.args = --ignore-out=cn +cn --v any-host warning-068: TEST.args = --ignore-out=cn +cn --v any-host warning-069: TEST.args = --sniname=wrong +cn $(TEST.host) warning-070: TEST.args = --cfg_cmd=$(_TMP.rc) +quit #warning-070: TEST.args = TODO: need special test target which uses unredable --cfg_cmd=$(_TMP.rc) warning-071: TEST.args = --cfg_unknown=dummy=dummy +quit warning-072: TEST.args = --cfg_cmd=$(_TMP.rc) --cgi +quit warning-073: TEST.args = --cfg_cmd=invalid_default_command=default +quit #?# warning-074: TEST.args = --rc=$(_TMP.rc) +quit #?# warning-074: TEST.rc = "--cfg_cmd=dummy=cn unknown_command" warning-074: TEST.args = --cfg_cmd=dummy=unknown_command +quit warning-075: TEST.args = --cfg-init=ca_path=force-message +quit warning-076: TEST.args = --cfg_score=dummy=invalid_value +quit warning-080: TEST.args = TODO: testing Net::SSLeay < 1.49 warning-111: TEST.args = --mx --nodns +quit warning-111: TEST.args = TODO: testing missing Net/DNS.pm warning-112: TEST.args = +sts_expired +quit warning-112: TEST.args = TODO: testing missing Time/Local.pm need by +sts_expired warning-120: TEST.args = TODO: testing ancient perl warning-121: TEST.args = TODO: testing ancient module warning-122: TEST.args = TODO: testing ancient Net::SSLeay warning-123: TEST.args = TODO: testing ancient IO::Socket warning-124: TEST.args = TODO: testing ancient IO::Socket::SSL warning-125: TEST.args = TODO: testing openssl < 1.0.0 warning-126: TEST.args = TODO: testing missing ALPN functionality warning-127: TEST.args = TODO: testing Net::SSLeay < 1.56, ALPN disabled warning-128: TEST.args = TODO: testing openssl < 1.0.2, ALPN disabled warning-129: TEST.args = TODO: testing missing NPN functionality warning-130: TEST.args = TODO: testing Net::SSLeay < 1.46, ALPN disabled #warning-131: TEST.args = free warning-132: TEST.args = TODO: testing openssl < 1.0.1, ALPN disabled warning-133: TEST.args = TODO: testing Net::SSLeay without OCSP warning-134: TEST.args = TODO: testing Net::SSLeay without EC warning-135: TEST.args = TODO: testing Net::SSLeay < 1.49 warning-140: TEST.args = +cipherraw --dtlsv1 +quit warning-141: TEST.args = +cipherraw --dtlsv9 +quit warning-141: TEST.args = TODO: testing wrong or unsupported SSL protocol #warning-142: TEST.args = free warning-143: TEST.args = TODO: testing SSL protocol not supported by Net::SSLeay, difficult ... warning-144: TEST.args = TODO: testing missing openssl s_client support for -alpn or -npn, difficult ... warning-145: TEST.args = TODO: testing missing openssl s_client support for -alpn or -npn, difficult ... warning-146: TEST.args = TODO: testing missing openssl -tlsextdebug option warning-147: TEST.args = TODO: testing missing openssl executable in Net::SSLinfo warning-148: TEST.args = TODO: testing missing openssl version -d failed, difficult ... warning-149: TEST.args = --openssl=/does/not/exist +quit warning-201: TEST.args = +cn unknown-host warning-202: TEST.args = +cn --exit=HOST1 www.skype.com # # scary: need a reliable FQDN here -^^^^^^^^^^^^^ #warning-203: TEST.args = free warning-204: TEST.args = TODO: testing connection without SNI, difficult ... warning-205: TEST.args = TODO: testing connection failed, difficult ... warning-206: TEST.args = TODO: testing connection witout SNI errors from Net::SSLinfo, difficult ... warning-207: TEST.args = TODO: testing connection with openssl failed, difficult ... warning-208: TEST.args = TODO: testing +check without openssl on Windows, difficult ... warning-209: TEST.args = TODO: testing missing SSL version, difficult ... warning-301: TEST.args = TODO: testing continous connection errors, difficult ... warning-302: TEST.args = TODO: testing max connection errors, difficult ... warning-303: TEST.args = TODO: testing unsupported Net::SSLeay::CTX_v2_new, difficult ... warning-304: TEST.args = TODO: testing unsupported Net::SSLeay::CTX_v3_new, difficult ... warning-305: TEST.args = TODO: testing connection _usesocket failed, difficult ... warning-311: TEST.args = TODO: testing empty result from openssl, difficult ... warning-312: TEST.args = TODO: testing strange result from openssl, difficult ... warning-312: TEST.args = TODO: testing unknown result from openssl, difficult ... warning-321: TEST.args = TODO: testing _isbleed failed to connect, difficult ... warning-322: TEST.args = TODO: testing _isbleed with openTcpSSLconnection failed, difficult ... warning-323: TEST.args = TODO: testing heartbleed: no reply, difficult ... warning-324: TEST.args = TODO: --sniname=wrong +cn # # scary: need a reliable FQDN here -^^^^^^^^^^^^^ www.skype.com warning-325: TEST.args = TODO: testing connection failed, HTTP disabled, difficult ... warning-331: TEST.args = TODO: testing _isccs: failed to connect, difficult ... warning-332: TEST.args = TODO: testing _isccs: no reply, difficult ... warning-408: TEST.args = --no-openssl +cipher-dh --exit=HOST2 $(TEST.host) warning-409: TEST.args = --sslv2 --sni +cipherall --exit=HOST4 $(TEST.host) warning-410: TEST.args = --sslv2 --sni +cipher --exit=HOST4 $(TEST.host) warning-411: TEST.args = TODO: testing checked cipher does not match returned cipher, difficult ... warning-601: TEST.args = TODO: testing connection failed with protocol error, difficult ... warning-602: TEST.args = TODO: testing connection type name mismatch, difficult ... warning-631: TEST.args = TODO: testing SSL protocol mismatch for cipher, difficult ... warning-641: TEST.args = TODO: testing HTTPS request failed, difficult:& needs target with ALPN ... warning-801: TEST.args = TODO: testing connection returning unknown label, difficult ... warning-811: TEST.args = TODO: ancient openssl version: using '-msg' option to get DH parameters warning-821: TEST.args = TODO: can not print certificate sizes without a certificate, --no-cert warning-831: TEST.args = --testing-+quit__without__--trace=arg +quit warning-841: TEST.args = TODO: used openssl version differs from compiled Net:SSLeay warning-851: TEST.args = TODO: ancient version Net::SSLeay < 1.49 warning-861: TEST.args = TODO: not all ciphers listed #ALL.testwarnings = # same as ALL.test.warnings ALL.test.warnings = $(shell awk -F: '/^warning-...:/{print $$1}' $(_MYSELF.warnings) | sort -u) warning-%: message-% @echo -n "" _TEST.template = t/test.warning.Makefile-template $(_TEST.template): $(SRC.pl) @echo "# generated template targets to test **WARNING messages" > $@ @echo "# targets use the message text as TODO (see Makefile)" >> $@ @echo "# Note: texts for TEST.args should not contain ; | ()" >> $@ @echo "# Note: not all texts my be useful, it's a template!" >> $@ @echo "" >> $@ perl -nle 'm/^\s*_?warn/ && do {\ s/^[^"]*"([^"]*).*/warning-$$1/;\ s/:/: TEST.args = TODO:/;\ print}' $^ \ | sort >> $@ @-ls -l $@ warnings.gen.template: $(ALL.Makefiles) $(_TEST.template) # TODO: Makefile dependency does not work, probably need to use $(MAKE) warnings.show.todo: grep "^warning..*TODO" $(TEST.dir)/Makefile warnings.show.difficult: grep "^warning..*difficult" $(TEST.dir)/Makefile test.warnings.all: $(ALL.test.warnings) test.warnings: test.warnings.all # $(_WARNING.log) calls "make -s" to avoid printing of executed commands _WARNING.log = $(TEST.logdir)/test.warnings.log-$(_TODAY_) $(_WARNING.log): @echo "# Makefile.warnings 1.21: make test.warnings.log" > $@ @$(MAKE) -s $(ALL.test.warnings) >> $@ 2>&1 # Target should create a new logfile, then compare it with the current one. If # diff returns nothing, delete newly created logfile, otherwise rename newly # created file to name which contains the current date. # Finally, If current logfile is/was missing, use newly created one: # "test ... || mv ..." . This ensures that the file exists afterwards. # FIXME: following target should have $(SRC.pl) as dependency, but that fails # if make is called from within ./t/ directory; hence no dependency test.warnings.log: $(_WARNING.log) @$(TARGET_VERBOSE) @diff $(TEST.logdir)/$@ $(_WARNING.log) \ && rm $(_WARNING.log) \ || mv $(_WARNING.log) $(TEST.logdir)/$@ @-test -f $(TEST.logdir)/$@ || mv $(_WARNING.log) $(TEST.logdir)/$@ @ls -l $(TEST.logdir)/$@* # TODO: same target as test.cgi.log .PHONY: test.warnings.log #_____________________________________________________________________________ #_____________________________________________________________________ test __| # feed main Makefile ALL.tests += $(ALL.test.warnings) ALL.tests.log += test.warnings.log O-Saft-19.01.19/t/SSLinfo.pl000077500000000000000000000040741342117255600152000ustar00rootroot00000000000000#! /usr/bin/perl -w -I . -I .. #? #? NAME #? $0 - einfaches Testscript für Methoden von Net::SSLinfo #? #? SYNOPSIS #? $0 [host] [port] #? #? Default: mail.google.com 443 #? use strict; use warnings; if (0 <= $#ARGV) { if ($ARGV[0] =~ m/^--?h(?:elp)?$/) { # quick&dirty system("sed -ne 's#\$0#$0#g' -e '/^#?/s/#?//p' $0"); exit 0; } } my $SID = "@(#) %M% %I% %E% %U%"; my $VERSION = 'dumm'; use Net::SSLinfo; # qw(open_ssl); my $host = $ARGV[0] || 'mail.google.com'; # ssllabs.com my $port = $ARGV[1] || 443; #my ($ssl, $ctx) = #do_ssl_open($host, $port); print "# $host:$port ...\n"; my $pem = PEM($host,$port); # hier werden die Daten besorgt, danach ist $host, $port nicht mehr nötig my @err = errors($host,$port); if (0 <= $#err) { push(@err, "\n# alle folgenden Werte sind evtl. zufällig oder falsch!"); } print join("\n", '===============', "errors:\n" . join("\n", @err), '===============', "PEM:\n" . $pem, '===============', "text:\n" . text(), '===============', "Validity:\n" . join(" .. ", dates()), "Not valid before:" . before(), "Not valid after: " . after(), '===============', "Subject Name: " . subject(), "Issuer Name: " . issuer(), "Serial Number: " . serial(), "Serial Number I: " . serial_int(), "Serial Number H: " . serial_hex(), '===============', "Default Cipher: " . selected(), # "Cipher List: " . ciphers(), '', "Fingerprint: " . fingerprint(), "Fingerprint hash:" . fingerprint_hash(), "Fingerprint SHA1:" . fingerprint_sha1(), "Fingerprint SHA2:" . fingerprint_sha2(), "Fingerprint MD5: " . fingerprint_md5(), #'===============', #Net::SSLeay::get_peer_certificate(), #Net::SSLeay::dump_peer_certificate(), '', ); print "===============\n", "Authority: " . authority($host, $port), "\n", "Alt Names: " . altname($host, $port), # bei 'v.gy' gibt es eines "\n", "Verify Hostname: " . verify_hostname($host, $port), # bei 'alix' passt es nicht "\n", "Verify Alt Name: " . verify_alias($host, $port), # bei 'ssllabs.com' "\n"; do_ssl_close($host, $port); exit; O-Saft-19.01.19/t/o-saft_bench.sh000077500000000000000000000200631342117255600162060ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? o-saft_bench - simple time and memory test program for o-saft.pl #? SYNOPSYS #? o-saft_bench [target host] #? DESCRIPTION #? Runs o-saft.pl with most common commands and measures execution and #? memory usage using system's time command. #? Results are written to STDOUT, the caller is responsible appended it #? to o-saft_bench.times . #? localhost is used as target for testing, can be passed as parameter. #? RESULTS #? Expected results are like: #? #?#--------------------------------------+------+-----+--------+----+---+------+ #?# | time | | memory | #?# command | user system real | CPU| av. max | #?#--------------------------------------+------+-----+--------+----+---+------+ #?o-saft.pl --exit=BEGIN0 | 0.00 0.00 0:00.00 80% 0k 5272k #?o-saft.pl +VERSION --norc | 0.00 0.00 0:00.00 80% 0k 5440k #?o-saft.pl +version | 0.14 0.01 0:00.17 92% 0k 29648k #?... #?o-saft.pl +cipher $host | 4.60 0.23 0:05.35 90% 0k 45468k #?o-saft.pl +cipherall $host | 0.96 0.05 0:01.74 58% 0k 26696k #?o-saft.pl +info $host | 0.18 0.04 0:02.38 9% 0k 25820k #?... #?#--------------------------------------+------+-----+--------+----+---+------+ #? #? Brief explanation (based on a 3 GHz CPU with 16 GB RAM): #? * no ERRORs or WARNINGs should be printed #? * user time: 0.1x is good for informational commands #? * system time: 0.01 is good for informational commands #? * system time: 0.2x is good for info and check commands #? * user time: 4.xx is good for info and check commands #? * real time: 0:05.xx is good for +cipher command #? * real time: 0:01.xx is good for +cipherall command #? * real time: 0:07.xx is good for most check commands #? * max. memory: 5000 kB is good for informational commands #? * max. memory: 25000 kB is good for info command #? * max. memory: 45000 kB is good for cipher and check commands #? #? VERSION #? @(#) o-saft_bench 1.17 18/04/20 12:04:54 #? AUTHOR #? 07-jul-14 Achim Hoffmann # ----------------------------------------------------------------------------- SID="@(#) o-saft_bench 1.17 18/04/20 12:04:54" ich=${0##*/} yeast=../o-saft.pl host=localhost time=/usr/bin/time out=./${ich}.times # not used anymore, must be done by caller while [ $# -gt 0 ]; do case "$1" in '-h' | '--h' | '--help') \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0; exit 0; ;; '+VERSION') echo "1.17"; ;; *) host="$1"; ;; esac shift done [ -x $yeast ] || yeast=o-saft.pl $yeast +quit > /dev/null if [ $? != 0 ]; then echo "**ERROR: $yeast failed; exit" && exit 2 fi (echo echo -n "# " && date echo "# $SID" echo -n "# o-saft.pl +VERSION: " && $yeast +VERSION --norc echo -n "# System (uname -a): " && uname -a echo -n "# Perl (perl -v): " && perl -v|grep This echo "#" echo "# testing with target: \$host = $host" ) #dbx echo -n "# prepare ... " $yeast +check localhost --trace --user >/dev/null 2>&1 # dummy to load modules and alocate memory #dbx echo "done." t="%U %S %E %P %Kk %Mk" line="#--------------------------------------+------+-----+--------+----+---+-------+" ( echo $line echo "# | time | | memory |" echo "# command | user system real | CPU| av. max |" echo $line ) while read -r cmd ; do [ -z "$cmd" ] && continue # skip final emtpy line #dbx# echo "o-saft.pl $cmd " txt=`echo "$cmd" | \sed -e "s/ $host/ "'$host/' -e 's/\\\/|/'` # we want a well formatted table, hence the real hostname is # replaced by the fixed string $host #echo "$txt #" #echo -n "o-saft.pl $txt" | tee -a $out && $time --quiet -o $out -a -f "$t" $yeast $cmd >/dev/null && echo "" echo -n "o-saft.pl $txt" && $time --quiet -f "$t" $yeast $cmd >/dev/null # note: --exit=BEGIN0 is some kind of minimal (perl) resources done << EoT --exit=BEGIN0 \ +VERSION --norc \ +version \ +version --v --usr \ +version --norc \ +version --v --norc \ +libversion \ +libversion --norc \ +ciphers \ +ciphers -V \ +list \ --v +help \ --help=gen-wiki \ --help=gen-wiki --no-header \ +cipher $host \ +cipherall $host \ +info $host \ +info --noopenssl $host \ +quick $host \ +quick --noopenssl $host \ +check $host \ +check --noopenssl $host \ +sizes $host \ +sizes --trace-cmd --trace-time $host \ +quit --trace-cmd --trace-time \ EoT # tricky here document: # We want to have well formated texts (command and options) for o-saft.pl call. # Hence we use a trailing backslash followed by a single space. echo $line exit #=============================================================================# #== output should look like ==# ## following old output up to 6/2015, modern one see description above # Mi 23. Jul 23:42:11 MEST 2014 # o-saft.pl +VERSION: 14.07.25 # System (uname -a): Linux circe 2.6.38-16-generic #66-heureca x86_64 x86_64 x86_64 GNU/Linux # Perl (perl -v): This is perl, v5.10.1 (*) built for x86_64-linux-gnu-thread-multi # # | time | | memory | # command | user system real | CPU| av. max | #--------------------------------------+------+-----+--------+----+---+-------+ o-saft.pl +VERSION --norc | 2.63 0.86 0:03.50 99% 0k 6239184k o-saft.pl +version | 2.49 1.20 0:03.72 99% 0k 6248544k o-saft.pl +version --v --usr | 2.79 0.94 0:03.78 98% 0k 6250304k o-saft.pl +version --norc | 2.60 1.10 0:03.74 98% 0k 6248416k o-saft.pl +version --v --norc | 2.64 1.07 0:03.74 99% 0k 6249344k o-saft.pl +libversion | 2.56 1.13 0:03.72 99% 0k 6243664k o-saft.pl +libversion --norc | 2.76 0.94 0:03.74 98% 0k 6243520k o-saft.pl +ciphers | 2.78 0.73 0:03.53 99% 0k 6243680k o-saft.pl +ciphers -V | 2.83 0.89 0:03.74 99% 0k 6243648k o-saft.pl +list | 2.70 0.82 0:03.54 99% 0k 6243680k o-saft.pl --v +help | 2.62 0.90 0:03.53 99% 0k 6240464k o-saft.pl +gen-wiki | 2.72 0.81 0:03.74 94% 0k 6245056k o-saft.pl +gen-wiki --usr | 2.52 0.97 0:03.51 99% 0k 6240336k o-saft.pl +cipher localhost | 3.10 2.13 0:06.01 86% 0k 6258048k o-saft.pl +cipherall localhost | 2.97 0.88 0:04.23 90% 0k 6251248k o-saft.pl +info localhost | 2.77 1.95 0:04.96 94% 0k 6253888k o-saft.pl +info --noopenssl localhost | 2.77 0.78 0:03.64 97% 0k 6253136k o-saft.pl +quick localhost | 3.06 2.15 0:06.02 86% 0k 6259936k o-saft.pl +quick --noopenssl localhost | 3.17 0.90 0:04.74 85% 0k 6259168k o-saft.pl +check localhost | 3.22 2.06 0:06.09 86% 0k 6260160k o-saft.pl +check --noopenssl localhost | 3.25 1.02 0:04.97 85% 0k 6259616k o-saft.pl +sizes $host | 0.14 0.00 0:02.32 6% 0k 22864k o-saft.pl +sizes --trace-cmd --trace-time $host | 0.13 0.02 0:02.32 6% 0k 23224k o-saft.pl +quit --trace-cmd --trace-time | 0.11 0.01 0:00.13 97% 0k 21628k #--------------------------------------+------+-----+--------+----+---+-------+ O-Saft-19.01.19/t/test-bunt.pl.txt000077500000000000000000000025451342117255600164270ustar00rootroot00000000000000#!/bin/cat === Überschrift 1 === Usage: cat test-bunt.pl.txt | ../contrib/bunt.pl == Description == File with content to test contrib/bunt.pl. Results must be checked by humans, cannot be fully automated. == Überschrift 2 == o-saft.pl mit Argumenten == Überschrift (ohne Abschluss) eine normale Zeile noch eine Zeile #dbx# debug Zeile normale Zeile # auch debug Zeile ##text Kommentar #! Kommentar #? Kommentar **ERROR: Fehler wird gemeldet normale Zeile **WARNING: Warnung wird gemeldet **WARNING 0815: Warnung mit Nummer wird gemeldet normale Zeile TAB davor und in der Mitte !!Hint: das ist ein Hinweis #[key]: Zeile mit Keyword am Anfang: yes host:443:Zeile mit Hostname am Anfang: yes host:443:#[host]:Zeile mit Hostname und Keyword am Anfang: yes == Wörter ein Text mit yes am Ende: yes ein Text mit no am Ende: no ein Text mit no am Anfang: no (bla bla) ein Text mit text am Ende: weiterer text ein Text mit undef am Ende: <> ein Text mit ohne match: hier steht >> irgendwas ein Text mit ohne match: hier steht >> irgendwas == Cipher =--------------------------------------+-------+------- NULL-SHA256-SHA yes weak NULL-MD5 no WEAK NULL-SHA yes WEAK DES-CBC3-SHA yes HIGH =--------------------------------------+-------+------- fertig.