pax_global_header00006660000000000000000000000064143376572730014533gustar00rootroot0000000000000052 comment=d94331e47b15f74e21668433b8daffb2878c5f6d O-Saft-22.11.22/000077500000000000000000000000001433765727300130535ustar00rootroot00000000000000O-Saft-22.11.22/.github/000077500000000000000000000000001433765727300144135ustar00rootroot00000000000000O-Saft-22.11.22/.github/FUNDING.yml000066400000000000000000000001411433765727300162240ustar00rootroot00000000000000custom: https://owasp.org/donate/?reponame=www-project-o-saft&title=OWASP+O-Saft github: OWASP O-Saft-22.11.22/.o-saft.pl000066400000000000000000000332211433765727300146600ustar00rootroot00000000000000#!/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. #? The string right to the leftmost = character is used verbatim. #? 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.108 22/09/20 15:29:29 #? AUTHOR #? 13-dec-13 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.rc = 1.108; # 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+ ### ### anonymise strings in output ### # Pattern for strings to be anonymised in output, mainly used in CGI mode to # avoid information disclosure. # Note that the pattern should contain the internal variable names also. #--anon_output=(anon_output|anon_text) ### ### 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 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 compression expansion heartbeat master_secret renegotiation resumption srp krb5 psk_identity psk_hint ocsp_response alpns npns alpn npn next_protocols public_key_len dh_parameter master_key session_id session_id_ctx session_ticket session_lifetime session_startdate session_starttime fallback_protocol 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 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_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 dv 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_1 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_ip hsts_httpequiv hsts_sts hsts_location hsts_refresh sts_preload sts_maxage sts_subdom sts_maxage0d sts_maxage1d sts_maxage1m sts_maxage1y sts_maxage18 sts_maxagexy sts_expired https_pins krb5 psk_identity psk_hint session_ticket session_lifetime session_random ocsp_stapling closure sgc zlib open_pgp lzo hasalpn hasnpn fallback master_secret renegotiation resumption srp compression heartbeat sstp scsv cnt_checks_yes cnt_checks_no cnt_checks_noo 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: hastls10, hastls11 (they may be changed in 2020) # don't use +check: hastls13 as it is not yet fully suported # don't use +check: cnt_exitcode (for debugging or special purpose only) # following TBD: cipher_order, cipher_weak, cps_valid ### ### 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 compression expansion heartbeat hostname hsts_sts crl master_secret renegotiation resumption ### ### 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-22.11.22/CHANGES000066400000000000000000002122221433765727300140470ustar00rootroot00000000000000 Version: 22.11.22 BUGFIX * Net/SSLinfo.pm: BF: avoid "Use of uninitialized value ..." in datadump() * OSaft/Ciphers.pm: BF: using string '0 ' if value is 0 in _ciphers_init() * OSaft/Fata.pm: BF: string <> changed to internal to avoid conflict in HTML * o-saft.pl: BF: output for --ciphermode=dump corrected * o-saft.cgi: BF: regex for arguments to be ignored corrected * o-saft.tcl: BF: generating content for "help" improved * t/Makefile: ET: name of targets unified: testarg-hlp-* * t/Makefile.cipher: BT: targets testcmd-cipher-+test-ciphers-list-* corrected (are testarg-* now) * contrib/gen_standalone.sh: BF: better check for include of o-saft-dbx.pm CHANGES * o-saft.pl: EF: print number of checked ciphers for each protocol * o-saft.pl: EF: print warning if no ciphers specified * o-saft-man.pm: EF: new design for o-saft.cgi.html * o-saft-man.pm: EF: man_docs_write() (writes --help=ciphers-text also) * o-saft.cgi: EF: regex for illegal commands and options improved * o-saft.tcl: ED: "Key Bindings" documented * o-saft.tcl: EF: osaft_write_docs() used "o-saft.pl --help=gen-docs" to generate files * OSaft/Doc/help.txt: EF: description for --cipherrange=RANGE improved; --cipherpattern=PATTERN added * OSaft/Ciphers.pm: EF: cipher suites SM4-GCM-SM3 and SM4-CCM-SM3 added * OSaft/Ciphers.pm: EF: security for ciphers *PSK*CBC* set mediu * OSaft/Ciphers.pm: ET: test functionality improved * OSaft/Ciphers.pm: EF: @cipher_iana_recomended added (list of ciphers suites recommended by IANA) * t/Makefile.cipher: ET: tests for --ciphermode=dump added * t/Makefile.dev: ET: new Targets to test INSTALL.sh * Makefile: EF: enforce LANG=C environment for all tests * Makefile: EF: remove useless environment variables * Makefile: EF: include t/Makefile.gen t/Makefile.mod * Makefile: ET: target docs and do.data improved * contrib/HTML-table.awk: EF: improved for cipher lists; some header lines handled special * contrib/*_completion_o-saft: EF: completion for make added * checkAllCiphers.pl: EF: trace variable assignment improved NEW * o-saft.pl: EF: --cipher=CIPHER implemented * OSaft/Ciphers.pm: NF: get(pfs) implemented * t/Makefile: NT: target commands of testarg-%.log and testcmd-%.log piped to filter * t/Makefile.gen: NF: new Makefilewith user defined functions * t/Makefile.pod: EF: new section Make:target generation * t/Makefile.inc: EF: new text for TEST.logtxt; EXE.arg-logfilter and EXE.cmd-logfilter added * t/Makefile.dev: NT: targets for get_keys_list and get_names_list added * t/Makefile.dev: ET: targets for testng OSaft/Ciphers.pm functions added * t/Makefile.dev: ET: targets testarg-dev-o-saft-sh--post-* added * t/Makefile.misc: NT: new target testarg-misc_hashbang * contrib/INSTALL-template.sh: EF: copy_file implemented with --useenv; descrition for --useenv added Version: 22.06.22 BUGFIX * o-saft-man.pm: BF: check if no parameter given corrected * osaft.pm: BF: avoid "Use of uninitialized value $cipher" in get_cipher_owasp() * osaft.pm: BF: syntax (, instead of .) in cipheranges corrected * o-saft.pl: BF: avoid "Use of uninitialized value $cipher" in _sort_cipher_results() * o-saft.pl: BF: avoid "Use of uninitialized value $key" in checkciphers() * o-saft.pl: BF: match for valid --cipher-pattern corrected * o-saft.pl: BF: my -> our for simplified variables * o-saft.pl: BF: printversion() improved (avoid "Use uninitialized value") * o-saft.tcl: BF: add and delete of entry widgets for target names corrected * OSaft/Ciphers.pm: BF: missing cipher suite names DHE-PSK-AES18-CBC-SHA and DHE-PSK-AES256-CBC-SHA added * OSaft/Ciphers.pm: BF: missing ciphers in sequence of sort_cipher_names() added * contrib/INSTALL-template.sh: BF: "check for openssl executable used by O-Saft" improved CHANGES * o-saft.pl: EF: use _eval_cipherranges() instead of eval() directly * o-saft.pl: EF: more compatibility options from testssl.sh added * o-saft.pl: EF: _get_ciphers_range --> osaft::get_ciphers_range * o-saft.pl: EF: verbosity for cipher_selected with +cipher improved * o-saft.pl: EF: printing header line for all +cipher checks improved * o-saft.pl, *.pm: EF: @INC improved * o-saft.pl, *pm: EF: use OSaft::Text * o-saft-man.pm: EF: honor --v from caller * o-saft-man.pm: EF: JavaScript in man_ciphers() improved * o-saft-man.pm: EF: o-saft.cgi.html improved * o-saft-man.pm: ED: man_warnings() improved * contrib/INSTALL-template.sh: EF: check for O-Saft programs improved * contrib/o-saft_bench.sh: ED: pretty printed results * o-saft.tcl: EF: improved for AndroidWish * o-saft.tcl: EF: detect header line for SSL/TLS protocol od ciphers * o-saft.pl: EF: print header line for all +cipher checks (to map cipher suite names properly to pprotocols) * o-saft.pl: EF: redisign OSaft/Ciphers.pm: branch moved to trunk * osaft.pm: EF: get_ciphers_range() (moved from o-saft.pl) * osaft.pm: EF: redisign OSaft/Ciphers.pm: branch 1.270.1.4 moved to trunk * OSaft/Ciphers.pm: BF: all ciphers with 3DES are 112 bits only * OSaft/Ciphers.pm: BF: RMD replaced by RIPEMD for cipher MACs * OSaft/Ciphers.pm: EF: sort_cipher_results() moved from o-saft.pl * OSaft/Ciphers.pm: EF: set_sec() implemented * OSaft/Ciphers.pm: EF: redisign OSaft/Ciphers.pm: branch moved to trunk * OSaft/Doc/glossary.txt: EF: formal changes, some typos fixed; new XChaCha*, AESCCM* * OSaft/Doc/help.txt: ED: only historic references to +cipherall and +cipherraw * OSaft/Doc/help.txt: ED: documentation of --test-ciphers-* options improved * OSaft/Doc/rfc.txt: * o-saft-dbx.pm: ED: documentation for --test-ciphers-* options improved * o-saft-dbx.pm: EF: unused methods removed; some methods moved to Ciphers.pm * contrib/INSTALL-template.sh: ED: text about generation improved * Makefile*: ET: generated target names improved; more targets for --test-* * Makefile: EF: README replaced by README.md * Makefile: ED: text about generation improved * Makefile: EF: _CIPHER and related sources removed * Makefile.dev: ET: some summary target added * Makefile.dev: ET: --test-regex moved from osaft.pm to o-saft.pl * Makefile.dev: ET: adapted to new --test-ciphers* options in various tools * Makefile.dev: ET: adapted to changes in Ciphers.dev; more tests for Ciphers.pm * Makefile.dev: ET: *osaft-cipher --> *.osaft-ciphers * Makefile.opt: ET: target testarg-opt-alias--test-ciphers-list added * Makefile.misc: ET: redesign OSaft/Ciphers.pm: target keys.* and values.* are no longer needed; removed * Makefile.misc: ET: target cloc.stat.log added * Makefile.cipher: ET: targets added for: +test-ciphers-list --range=* * Makefile.cipher: ET: more --range= checks added * Makefile.warnings: ET: target warning-009 removed * Makefile.warnings: ET: warning-521, warning-522, warning-504, warning-505, warning-862 added NEW * o-saft-man.pm: EF: man_ciphers() implemented; options --help=gen-cipher-text --help=gen-cipher-html * Makefile: EF: o-saft-docker added to INSTALL.sh * o-saft.tcl: EF: "Open window with list of cipher suites" implemeted * o-saft.tcl: EF: --tkpod added * o-saft.tcl: EF: menu/window for configuration settings added * o-saft.tcl: EF: tool layout optimized for use on tablet; --gui-layout=tables is default now * o-saft-docker: EF: option +VERSION added for compatibility with other tools Version: 22.02.22 BUGFIX * Net/SSLhello.pm: BF: avoid "Use of uninitialized value $ENV{"PWD"} in ..." * o-saft*, OSaft/Ciphers.pm: BF: avoid "Use of uninitialized value $ENV{"PWD"} in ..." * INSTALL.sh: BF: improved check for Perl modules * INSTALL.sh: BF: create required directories * contrib/gen_standalone.sh: BF: avoid overwriting generated code when used with -t option * o-saft.cgi: BF: checks for bad IPs improved * o-saft: BF: --port= handling for single host argument corrected * o-saft: BF: output for --legacy=testssl-g corrected * o-saft: BF: do not start GUI on CLI when output is redirected; detect GUI if STDIN is missing * contrib/install_openssl.sh: BF: conflicting variable names and check for libidn.so corrected * contrib/gen_standalone.sh: BF: avoid perl warning "Unescaped left brace in regex is deprecated" (in newer perl versions) * contrib.bunt.pl: BF: missing space in substitution corrected * contrib.bunt.pl: BF: colourizing cipher rating improved * contrib.bunt.pl: BF: detecting host:port corrected * t/o-saft_bench.sh: BF: +VERSION corrected * t/o-saft_bench.sh: BF: redirect output of time command (from tty) correctly * osaft.pm: BF: some cipher names corrected * osaft.pm: BF: TLS 1.3 cipher-suites corrected * osaft.pm: BF: ciphers 0x00,0x7x corrected (ciphers for openpgp extension) * osaft.pm: BF: cipher rating (OWASP A) adapted to OWASP TLS Cheat Sheet (DHE*) * osaft.pm: BF: avoid **WARNING: 412: for INFO_SCSV * osaft.pm: BF: sorting ciphers according strength improved (added some CHACHA*, FZA*, * o-saft*: BF: settings in @INC improved; set . instead ./ in @INC * o-saft.pl: BF: check for --trace* option improved * o-saft.pl: BF: check for +ocsp_uri and +ocsp_valid corrected * o-saft.pl: BF: set default CA file if none found (--ca-file) * o-saft.pl: BF: duplicate warning 042 corrected * o-saft.pl: BF: ignore unknown options (new warning 029); avoids using its value as target * o-saft.pl: BF: avoid perl error: "Undefined subroutine &Time::Local::timelocal ..." * o-saft.pl: BF: check for +cipher_pfsall corrected * o-saft.pl: BF: check for +logjam corrected (use $cipher instead of $c) * o-saft.pl: BF: better ckeck for ancient Net:SSLeay < 1.49 functionality to avoid crash * o-saft.pl: EF: better check vor valid hostname arguments * o-saft.pl: BF: --exitcode does not count missing PFS if no ciphers offered * o-saft.pl: BF: --exitcode does not count TLSv13 * o-saft.pl: BF: --exitcode-v corrected * o-saft.pl: BF: setting cfg{'ca_file'} corrected * o-saft.pl: BF: description of some ciphers corrected (according openssl description) * Net/SSLinfo.pm: EF: output for --trace improved and unified * Net/SSLinfo.pm: BT: test_ssleay() avoids using undefined functions which results in perl's "Can't locate .." error * Net/SSLinfo.pm: documentation for --test-* corrected * Net/SSLinfo.pm: avoid Perl warning "used only once: possible typo" * Net/SSLinfo.pm: BF: get session information from Net::SSLeay (avoid perl warnings) * Net/SSLinfo.pm: BF: avoid confusing message in servers access.log like: "\n" 400 750 "-" "-" * Net/SSLhello.pm: BF: avoid "Use of uninitialized value $ENV{"PWD"} in ..." * OSaft/Doc/Data.pm: BF: avoid some POD link syntax L< * OSaft/Doc/Data.pm: BF: warnings have a message number * OSaft/Ciphers.pm: BF: extend @INC (for internal use; @INC depends on OS and distribution) * OSaft/Ciphers.pm: BF: sorting of strong ciphers improved * OSaft/Ciphers.pm: BF: numbers for warning messages * o-saft.tcl: EF: generating Tcl-markup for help improved (still not perfect) * o-saft.tcl: BF: syntax corrected when --rc used * o-saft.tcl: BF: UP and DOwn button in help window aktivated * o-saft.tcl: BF: avoid searching for empty strings in help window * o-saft.tcl: BF: result from +version not shown as table data * Makefile.dev: BT: test with gen_standalone.sh improved * Makefile.warning: BT: duplicate warning 042 corrected * Makefile.cipher: BT: typo in target name corrected * Makefile: BF: GEN.man depends on GEN.pod * Makefile: BF: generation of files depending on OSaft/Doc/help.txt corrected * o-saft-dbx.pm: BF: print content of %cfg{targets} instead of array ref * o-saft-man.pm: BF: avoid "Use of uninitialized value ..." in man_warnings() * o-saft-man.pm: BF: detect o-saft as one of our own commands in help texts * o-saft-man.pm: BF: dirty hack to find proper .pod file for gen-man * o-saft-man.pm: BF: generation of links in POD and HTML improved * o-saft-man.pm: BF: _main renamed to _main_man (because this file is not yet a Perl package) * o-saft-man.pm: BF: setting default options in generated .html corrected CHANGES * contrib/HTML-table.awk: EF: print table header for each table * Makefile: ET: t/cloc-total.awk added as source file; list of documentation files improved * o-saft.cgi: EF: --format=html implemented (experimental) * o-saft.cgi: EF: parameter sanitation improved (trailing = in names removed) * o-saft-man.pm: ED: output for --help=warnings in man_warnings() improved * o-saft-man.pm: ED: idention in HTML
  • lists improved * o-saft-man.pm: EF: --help=warnings implemented * o-saft-man.pm: EF: --format=html option generated for --help=gen-cgi (o-saft.cgi.html) * o-saft-man.pm: EF: --cgi-no-header added to quick options for o-saft.cgi.html * t/Makefile.tcl: ET: target testcmd-tclinteractive-* and test.GUI added; testcmd-tcl---gui-* added * t/Makefile.tcl: ET: new test targets * t/Makefile.dev: ET: more individual targets for EXE.osaft (calling contrib/bunt.pl) * t/Makefile.misc: ET: targets test.keys and test.values * t/Makefile.misc: ET: targets cloc.csv and cloc.total added * t/cloc-total.awk: EF: check calculated vs. reported values * t/cloc-total.awk: EF: print comments reported by cloc * o-saft.tcl: EF: read configuration from static files; new option --no-docs * o-saft.tcl: EF: --stdin (reading data from STDIN) implemented * o-saft.tcl: EF: options --test=FILE --layout=table implemented * o-saft.tcl: EF: degugging improved; default configuration for Android improved * o-saft.tcl: ET: option --test-tcl added * INSTALL.sh: EF: --check and --install check for installed wish * INSTALL.sh: EF: use unique error numbers * INSTALL.sh: EF: use --install as default if no option given * INSTALL.sh: EF: check for optional executables * INSTALL.sh: EF: functionality and documentation improved * Dockerfile: EF: build with debian supported * Dockerfile: EF: using alpine:3.10 * Dockerfile: EF: Workaround for docker/alpine (bug or race condition) added * contrib/o-saft.php: EF: moved to . * contrib.bunt.pl: EF: improved for ciphrs with OWASP rating * contrib.bunt.pl: ED: documentation improved * Makefile.cipher: EF: new targets for testing +cipher with options * Makefile.cmds: ET: renamed to Makefile.cmd * OSaft/Doc/tools.txt: ED: checkAllCiphers.pl and contrib/alertscript.pl added * OSaft/Doc/Data.pm: EF: fix for strange Perl behaviour on older Mac OSX * OSaft/Ciphers.pm: BF: list command returns sorted list of files * contrib/gen_standalone.sh: EF: check improved if source file exists * contrib/gen_standalone.sh: ET: less noisy "ls" if called by make (check OSAFT_MAKE variable) * contrib/gen_standalone.sh: ED: documentation for generated code improved * contrib/gen_standalone.sh: EF: handle comments with OSAFT_STANDALONE * contrib/o-saft.php: EF: improve: search for script to be called (no longer hardcoded) * contrib/INSTALL-template.sh: EF: options improved; --not-blind added, default is --blind * contrib/install_openssl.sh: EF: +VERSION and --version added * contrib/install_openssl.sh: EF: Install Perl modules using "perl -MCPAN" instead of building from .tgz * contrib/install_openssl.sh: EF: checking preconditions improved; building modules improved * contrib/install_openssl.sh: EF: option --m to install required Perl modules * contrib/install_openssl.sh: EF: adapting .o-saft.pl improved * o-saft-man.pm: EF: _man_squeeze() and _man_use_tty() implemented for --tty option * o-saft-man.pm: EF: output of man_help(), man_table() may have fixed width * o-saft-man.pm: EF: CSS improved for o-saft.cgi.html * o-saft: EF: option -line added * o-saft: EF: options -colour -blind and -prg=* added * o-saft*: EF: use print_pod() to print own help * o-saft-dbx.pl: EF: --test implemented * o-saft.pl: BF: allow $cfg{'ignore-out'} to set empty * o-saft.pl: BF: intended functionality of --enabled --disabled corrected * o-saft.pl: BF: initial time corrected if < 0: set $cfg{'time0'} * o-saft.pl: EF: use Encode::decode("UTF-8", ...) for all printed values * o-saft.pl: ED: formal changes in %ciphers (adaption to openssl 1.1.1k) * o-saft.pl: ED: useless debug output removed; avoid duplicate commands * o-saft.pl: EF: do not print same message (warning) multiple times; --warnings-dups added * o-saft.pl: EF: check for Extended master secret * o-saft.pl: EF: checking CA paths and files for Android improved * o-saft.pl: EF: options --format-* and --ty implemented * o-saft.pl: EF: TLS 1.3 cipher-suites added * o-saft.pl: EF: ciphers 0x00,0x7x added (ciphers for openpgp extension) * o-saft.pl: EF: warning and hint messages unified * o-saft.pl: EF: check for openssl executable only if openssl required * o-saft.pl: EF: --test implemented * o-saft.pl: EF: --test* options unified * o-saft.pl: EF: ECDHE-ECDSA-* ciphers are classified with "unknown" security * osaft.pm: EF: +http_body disabled by default * osaft.pm: EF: cfg{regex]{OWASP_AA} added; formal changes in %ciphers * osaft.pm: EF: cipher names adapted to openssl 1.1.1k * osaft.pm: EF: own _warn() and _dbx() if missing * osaft.pm: EF: export STR_MAKEVAL * osaft.pm: ED: formal changes; permanent hint texts defined here * osaft.pm: EF: cfg{warnings_no_dups} and cfg{warnings_printed} added * osaft.pm: EF: master_secret added to cmd-quick * osaft.pm: EF: ca_paths and ca_files improved for Android * osaft.pm: EF: new TLS_EXTENSIONS data structure * osaft.pm: EF: cipher suites from rfc6367 added * osaft.pm: EF: ca_paths[], openssl_cnfs[] improved * osaft.pm: EF: reserved ciphers removed from cipher ranges * osaft.pm: EF: ECDHE-ECDSA-* ciphers are classified with "unknown" security * osaft.pm: EF: primary and alias name of some RSA-PSK-AES* cipher changed * osaft.pm: ED: VERSION added for POD * o-saft: EF: cal o-saft.tcl if no STDOUT available * o-saft.cgi: EF: print all error for any invalid parameter * o-saft.cgi: ED: POD and internal documentation improved * o-saft.cgi: EF: pass parameter --format=html to o-saft.pl too * o-saft.cgi: EF: printing HTTP headers conditionally; --cgi-header and --cgi-no-header implemented * o-saft.cgi: EF: improved to check for invalid arguments without --*= prefix * o-saft.cgi: EF: disallow IPv4-mapped IPv6 addresses * o-saft.cgi: EF: disallow IPv4-mapped or incomplete IPv6 addresses; disallow integer addresses * o-saft-*.pm: ED: documentation improved * t/Makefile*: ED: ALL.tests and ALL.tests.log are set in Makefile * t/Makefile*: ED: documentation improved * t/Makefile*: ET: --trace-CLI option added to most o-saft.pl calls * t/Makefile*: ET: do not force setting of EXE.pl for testcmd-% * t/Makefile*: ET: qa.pod - check generated pod file * Makefile: EF: dependency on tags file improved * Makefile, t/Makefile*: ET: targets and documentation unified and improved * o-saft-dbx.pm: ED: description for ciphers_sorted and ciphers_overview improved * o-saft-dbx.pm: EF: avoid printing random value for cfg{time0} if OSAFT_MAKE ist set * o-saft-dbx.pm: EF: avoid printing random value for cfg{time0} if OSAFT_MAKE ist set * o-saft-dbx.pm: EF: $cfg{'trace*'} --> $cfg{'out'}->{'trace*'} * o-saft-dbx.pm: EF: $VERSION renamed to $mainsid to avoid conflicts withother modules * o-saft-dbx.pm: EF: output for --v improved (host:port/path) * o-saft-man.pm: EF: --h improved (remove internal markup) * o-saft-man.pm: EF: print own help if called without arguments * o-saft-man.pm: EF: mobile-friendly title= attributes in generated HTML * o-saft-man.pm: EF: help button to show o-saft.html for --help=cgi added * o-saft-man.pm: EF: setting document title in generated .html improved * o-saft.tcl: EF: docker_status_99x29_magenta.png added * o-saft.tcl: EF: filename for saving contains name of TAB * o-saft.tcl: EF: testing and debugging options --help-* renamed to --test-* * o-saft.tcl: EF: --help=opts option implemented * o-saft.tcl: EF: o-saft.pl initially called if +command arguments are given * o-saft.tcl: EF: --rc improved; contrib/.o-saft.tcl removed * o-saft.tcl: ED: searching for text starting with - in help text improved * o-saft.tcl: EF: debugging improved * o-saft.tcl: EF: avoid creating multiple option enty fields * o-saft.pl: EF: +traceSUB removed, is now --test-sub (see o-saft-dbx.pm 1.110) * o-saft.pl: EF: print ciphers for --no-enabled and --legacy=owasp also * o-saft.pl: EF: $VERSION renamed to $mainsid to avoid conflicts withother modules * o-saft.pl: EF: avoid duplicate settings in @INC; setting @INC simplified; set . but not ./ * o-saft.pl: EF: --exitcode does not count "no (<<..>>)" results * o-saft.pl: ED: typos * o-saft.pl: EF: use URL if any to connect to target * Net/SSLhello.pm: $main::cfg{'trace*'} --> $Net::SSLhello::trace* * Net/SSLhello.pm: version string corrected * Net/SSLhello.pm: EF: usinag IANA constant names for cipher suites instead of openssl constant names * Net/SSLinfo.pm: ED: formal change: use $STR{WARN} * Net/SSLinfo.pm: EF: check for Extended master secret * Net/SSLinfo.pm: ET: improved verbose and debug messages * Net/SSLinfo.pm: EF: prepared for improved extracting of PEM data * Net/SSLinfo.pm: EF: empty headers in Net::SSLeay::get_http() removed * Net/SSLinfo.pm: EF: use URL if any to connect to target * Net/SSLinfo.pm: EF: --test-* and +VERSION options added NEW * t/Makefile: ET: set O-SAFT_MAKE * t/cloc-total.awk: EF: added * contrib/symbol.pl: new * contrib/*_completion_o-saft: EF: completion for o-saft.tcl added * contrib/INSTALL-template.sh: various adaptions to previous changes * t/Makefile: ET: set O-SAFT_MAKE * t/Makefile.misc: ET: testing CLI with *pm * t/Makefile.doc: ET: testing internal documentation * OSaft/Ciphers.pm: EF: --usage implemented * OSaft/Doc/help.txt: ED: --test* options added * OSaft/Doc/Data.pm: EF: --usage implemented * Net/SSLinfo.pm: EF: _verbose() * Net/SSLinfo.pm: EF: Net::SSLinfo::use_https and ::target_url added * o-saft.tcl: EF: --help=opts option implemented * o-saft.pl: EF: --use-https implemented * o-saft.pl: EF: new functionality: +public_key_len +session_id_ctx * o-saft.pl: EF: +sstp implemented * o-saft.pl: EF: print warning if --port used after host argument * o-saft-man.pm: EF: generate nroff format implemented * o-saft-man.pm: EF: message box for "CGI Usage Note" added to gen-cgi * o-saft-dbx.pm: ET: --test* option implemented * o-saft-dbx.pm: ET: write real date and time only if O-SAFT_MAKE environment variable does not exist 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: 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-22.11.22/Dockerfile000066400000000000000000000403201433765727300150440ustar00rootroot00000000000000#!/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 #? (2019) alpine:3.10 debian:10.2-slim #? #? OSAFT_VM_USER #? Username to be added in the build image. #? #? 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 . #? #? Simple build with base image debian:10.2-slim #? docker build --force-rm --rm \ #? --build-arg "OSAFT_VM_FROM=debian:10.2-slim" \ #? -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. #? # HACKER's Info # Note that the base package alpine uses busybox as shell. This shell is # very picky, in particular for the expr command. ARG OSAFT_VM_FROM=alpine:3.10 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_USER=osaft ARG OSAFT_VM_SRC_OSAFT="https://github.com/OWASP/O-Saft/raw/master/o-saft.tgz" ARG OSAFT_VM_SHA_OSAFT="5f23bbed8d411d84faec29c0a5da07ca58a64702c98339c7e7739450f0f9161c" 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 (2020) 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.36 22/03/04 20:20:53" \ 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 \ #== Configure user if expr "X$OSAFT_VM_FROM" : Xdebian >/dev/null ; then \ adduser --quiet --home ${OSAFT_DIR} ${OSAFT_VM_USER} ; \ passwd --delete ${OSAFT_VM_USER} ; \ else \ adduser -D -h ${OSAFT_DIR} ${OSAFT_VM_USER} ; \ fi && \ mkdir -p ${OSAFT_DIR} && \ \ #== Configure apk (alpine) or apt (debian); default: apk apt_exe=apk && \ apt_add=add && \ apt_del=del && \ opt_add=--no-cache && \ opt_del=--purge \ packages_make="gcc make musl-dev linux-headers perl-dev" && \ packages="wget ncurses $OSAFT_VM_APT_INSTALL \ $packages_make \ krb5-dev zlib-dev perl perl-readonly \ ca-certificates" && \ packages_dev="gmp-dev lksctp-tools-dev" && \ packages_perl="perl-net-dns perl-net-libidn perl-mozilla-ca" && \ if expr "X$OSAFT_VM_FROM" : Xdebian >/dev/null ; then \ apt_exe=apt-get ; \ apt_add=install ; \ apt_del=purge ; \ opt_add=--yes ; \ opt_del=--yes ; \ # fehltnoch: perl-dev packages_make="gcc make linux-headers-amd64" ; \ # ncurses-base ncurses-bin already part of debian packages="wget $packages_make libkrb5-3 libkrb5-dev zlib1g-dev perl ca-certificates" ; \ packages_dev="libgmp-dev lksctp-tools libsctp-dev" ; \ packages_perl="libnet-dns-perl libnet-libidn-perl" ; \ fi && \ # perl-io-socket-ssl perl-net-ssleay build herein \ #== Install required packages, development tools and libs #apk update && \ # no update needed and not wanted if expr "X$OSAFT_VM_FROM" : Xdebian >/dev/null ; then \ $apt_exe update ; \ fi && \ $apt_exe $apt_add $opt_add $packages && \ \ #== Workaround for docker/alpine (bug or race condition) # in some alpine versions, resolving a hostname fails, see # https://forums.docker.com/t/resolved-service-name-resolution-broken-on-alpine-and-docker-1-11-1-cs1/19307/23 # as workaround we try to prefetch the name resolution; # however, it is not bullet proof either ... workaround_alpine_bug() { \ expr "X$OSAFT_VM_FROM" : Xdebian >/dev/null && return ; \ for host in github.com codeload.github.com cpan.metacpan.org search.cpan.org cpan.metacpan.org ; do \ echo -n "resolving $host ... " && ping -c 1 $host > /dev/null && echo SUCCESS || echo FAILDED ; \ done; } && \ \ #== Pull, build and install enhanced openssl workaround_alpine_bug && \ $apt_exe $apt_add $opt_add $packages_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 $apt_exe $apt_del $opt_del $packages_dev && \ cd $WORK_DIR && \ rm -rf $BUILD_DIR $OSAFT_VM_TAR_OPENSSL && \ \ #== Pull, build and install Net::SSLeay workaround_alpine_bug && \ 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 ... $apt_exe $apt_add $opt_add $packages_perl && \ 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 workaround_alpine_bug && \ 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 -i test && make install && \ # make test sometimes fails (see Workaround above), hence -i cd $WORK_DIR && \ rm -r $BUILD_DIR $OSAFT_VM_TAR_SOCKET && \ \ #== Pull and install O-Saft workaround_alpine_bug && \ cd $WORK_DIR && \ 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_VM_USER}:${OSAFT_VM_USER} ${OSAFT_DIR}/contrib && \ chown ${OSAFT_VM_USER}:${OSAFT_VM_USER} ${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 $apt_exe $apt_del $opt_del $packages_make # 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_VM_USER RUN o-saft-docker usage ENTRYPOINT ["/O-Saft/o-saft"] CMD ["--norc", "--help=docker"] # vim:set ft=dockerfile: O-Saft-22.11.22/INSTALL.sh000077500000000000000000001103541433765727300145240ustar00rootroot00000000000000#! /bin/sh #? #? File generated data by Makefile 2.19 from contrib/INSTALL-template.sh #? #? NAME #? $0 - install script for O-Saft #? #? SYNOPSIS #? $0 [options] [/path/to/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: #? #? /path/to/installation/directory #? - copy all necessary files into specified directory #? --install - copy all necessary files into default directory #? default if no other option given #? --check - check current installation #? --clean - move files not necessary to run O-Saft into subdir #? ./.files_to_be_removed # This is the behaviour of the old INSTALL-devel.sh script. #? --openssl - calls contrib/install_openssl.sh which builds and #? installs openssl and Net::SSLeay ; this doesn't #? support other options and arguments of #? contrib/install_openssl.sh #? --cgi - prepare directory to be used in CGI mode #? --expected - show sample output expected for --check # All lines starting with #= are the sample output. #? --checkdev - check system for development (make) requirements #= #=# check for O-Saft programs found via environment variable PATH #=#-------------------------------------------------------------- #=# wish /usr/bin #=# o-saft.pl not found in PATH, consider adding /opt/o-saft to PATH #=# o-saft.tcl not found in PATH, consider adding /opt/o-saft to PATH #=# o-saft not found in PATH, consider adding /opt/o-saft to PATH #=# Note: all found executables in PATH are listed #=#-------------------------------------------------------------- #= #=# check installation in /opt/o-saft #=#-------------------------------------------------------------- #=# (warnings are ok if »git clone« will be used for development) #=# Dockerfile found; did you run »INSTALL.sh --clean«? #=# Makefile found; did you run »INSTALL.sh --clean«? #=#-------------------------------------------------------------- #= #=# check for used O-Saft programs (according $PATH) #=#----------------------+--------------------------------------- #=# o-saft.pl 22.05.22 /opt/o-saft/o-saft.pl #=# o-saft.tcl 2.23 /opt/o-saft/o-saft.tcl #=# o-saft 1.26 /opt/o-saft/o-saft #=# contrib/o-saft-standalone.pl 22.05.22 contrib/o-saft-standalone.pl #=#----------------------+--------------------------------------- #= #=# check for installed O-Saft resource files #=#----------------------+--------------------------------------- #=# ./.o-saft.pl will be used when started in . only #=# /opt/o-saft/.o-saft.pl will be used when started in /opt/o-saft only #=# /home/usr/.o-saft.tcl missing, consider generating: »o-saft.tcl --rc > /home/user/.o-saft.tcl« #=#----------------------+--------------------------------------- #= #=# check for installed Perl modules (started in '$inst_directory') #=#----------------------+--------------------------------------- #=# Net::DNS 1.19 /usr/local/share/perl/5.24.1/Net/DNS.pm #=# Net::SSLeay 1.88 /usr/local/lib/x86_64-linux-gnu/perl/5.24.1/Net/SSLeay.pm #=# IO::Socket::SSL 2.069 /usr/share/perl5/IO/Socket/SSL.pm #=# Time::Local 1.28 /usr/share/perl/5.28/Time/Local.pm #=# osaft 22.05.22 osaft.pm #=# Net::SSLinfo 22.02.12 Net/SSLinfo.pm #=# Net::SSLhello 22.05.22 Net/SSLhello.pm #=# OSaft::Ciphers 22.05.22 OSaft/Ciphers.pm #=# OSaft::Data 22.05.22 OSaft/Data.pm #=# OSaft::Text 22.05.22 OSaft/Text.pm #=# OSaft::error_handler 19.11.19 OSaft/error_handler.pm #=# OSaft::Doc::Data 22.02.13 OSaft/Doc/Data.pm #=#----------------------+--------------------------------------- #= #=# check for important Perl modules used by installed O-Saft #=#----------------------+--------------------------------------- #=# testing /opt/o-saft/o-saft.pl ... #=# Net::DNS 1.29 /usr/local/share/perl/5.24.1/Net/DNS.pm #=# Net::SSLeay 1.88 /usr/local/lib/x86_64-linux-gnu/perl/5.24.1/Net/SSLeay.pm #=# IO::Socket::SSL 2.069 /usr/share/perl5/IO/Socket/SSL.pm #=# Time::Local 1.28 /usr/share/perl/5.28/Time/Local.pm #=# testing /opt/o-saft/o-saft.pl in /opt/o-saft ... #=# Net::DNS 1.29 /usr/local/share/perl/5.24.1/Net/DNS.pm #=# Net::SSLeay 1.85 /usr/local/lib/x86_64-linux-gnu/perl/5.24.1/Net/SSLeay.pm #=# IO::Socket::SSL 2.069 /usr/share/perl5/IO/Socket/SSL.pm #=# Time::Local 1.28 /usr/share/perl/5.28/Time/Local.pm #=#----------------------+--------------------------------------- #= #=# summary of warnings from installed O-Saft (should be empty) #=#----------------------+--------------------------------------- #=# testing /opt/o-saft/o-saft.pl in /opt/o-saft ... #=#----------------------+--------------------------------------- #= #=# check for openssl executable in PATH #=#----------------------+--------------------------------------- #=# openssl /usr/bin/openssl (OpenSSL 1.1.1n 15 Mar 2022) #=#----------------------+--------------------------------------- #= #=# check for openssl executable used by O-Saft #=#----------------------+--------------------------------------- #=# ./o-saft.pl /usr/local/openssl/bin/openssl (1.0.2k-dev) #=# /opt/o-saft/o-saft.pl /usr/local/openssl/bin/openssl (1.0.2k-dev) #=#----------------------+--------------------------------------- #= #=# check for optional tools to view documentation: #=#----------------------+--------------------------------------- #=# aha /usr/bin/aha #=# perldoc /usr/bin/perldoc #=# pod2html /usr/bin/pod2html #=# pod2man /usr/bin/pod2man #=# pod2text /usr/bin/pod2text #=# pod2usage /usr/bin/pod2usage #=# podman missing #=# podviewer /usr/bin/podviewer #=# stty /bin/stty #=# tkpod /usr/bin/tkpod #=# tput /usr/bin/tput #=# #=# Note: podman is a tool to view pod files, it's not the container engine #=#----------------------+--------------------------------------- #= #=# check for contributed files (in /opt/o-saft/contrib ) #=#----------------------+--------------------------------------- #=# Cert-beautify.awk /opt/o-saft/contrib/Cert-beautify.awk #=# Cert-beautify.pl /opt/o-saft/contrib/Cert-beautify.pl #=# HTML-simple.awk /opt/o-saft/contrib/HTML-simple.awk #=# HTML-table.awk /opt/o-saft/contrib/HTML-table.awk #=# JSON-array.awk /opt/o-saft/contrib/JSON-array.awk #=# JSON-struct.awk /opt/o-saft/contrib/JSON-struct.awk #=# XML-attribute.awk /opt/o-saft/contrib/XML-attribute.awk #=# XML-value.awk /opt/o-saft/contrib/XML-value.awk #=# alertscript.cfg /opt/o-saft/contrib/alertscript.cfg #=# alertscript.pl /opt/o-saft/contrib/alertscript.pl #=# bash_completion_o-saft /opt/o-saft/contrib/bash_completion_o-saft #=# bunt.pl /opt/o-saft/contrib/bunt.pl #=# bunt.sh /opt/o-saft/contrib/bunt.sh #=# cipher_check.sh /opt/o-saft/contrib/cipher_check.sh #=# dash_completion_o-saft /opt/o-saft/contrib/dash_completion_o-saft #=# filter_examples /opt/o-saft/contrib/filter_examples #=# fish_completion_o-saft /opt/o-saft/contrib/fish_completion_o-saft #=# lazy_checks.awk /opt/o-saft/contrib/lazy_checks.awk #=# symbol.pl /opt/o-saft/contrib/symbol.pl #=# tcsh_completion_o-saft /opt/o-saft/contrib/tcsh_completion_o-saft #=# usage_examples /opt/o-saft/contrib/usage_examples #=# zap_config.sh /opt/o-saft/contrib/zap_config.sh #=# zap_config.xml /opt/o-saft/contrib/zap_config.xml #=# o-saft-standalone.pl /opt/o-saft/contrib/o-saft-standalone.pl #=#----------------------+--------------------------------------- #= #=# checks passed #? #? OPTIONS #? --h got it # --help got it #? --n do not execute, just show (ignored for --check) #? -x debug using shell's "set -x" #? --force - install RC-FILEs .o-saft.pl and .o-saft.tcl in #? $HOME, overwrites existing ones #? --no-colour - do not use coloured texts; default #? --colour - use coloured texts (red, yellow, blue|green) #? --colour-blind - same as --colour #? --colour-not-blind - use green instead of blue coloured texts #? --other - check for other SSL-related tool with --checkdev #? --useenv - change #! (shebang) lines to #!/usr/bin/env #? Applies only to files with following extensions: #? .awk .cgi .pl .sh .tcl .txt #? also applies to all Makefile* . #? The shebang line will only be changed when there #? are no arguments given. #? Examples of changed lines: #? #!/bin/sh #? #! /bin/sh #? #!/bin/cat #? #!/usr/bin/make #? #!/usr/bin/perl #? Examples of lines not to be changed: #? #!/usr/bin/gawk -f #? #!/usr/bin/make -rRf #? #! /usr/bin/perl -w #? #!/usr/bin/perl -w #? #!/usr/bin/perl -w -I . #? #? Please see docs/concepts.txt for details about /usr/bin/env . #? It's up to user then, which solution fits better. #? #? EXAMPLES #? $0 #? $0 --clean #? $0 --check #? $0 --install #? $0 /opt/bin/ #? $0 /opt/bin/ --force #? $0 /opt/bin/ --useenv #? $0 --install /opt/bin/ #? $0 --check /opt/bin/ #? $0 --check /opt/bin/ --colour #? $0 --checkdev #? $0 --cgi /opt/bin/ #? $0 --cgi . #? # HACKER's INFO # This file is generated from INSTALL-template.sh . # The generator (make) inserts most values for internal variables. In # particular the list of source files to be installed. See the strings # and scopes containing "generated data from Makefile 2.19" . # # All output is pretty printed. Yes, this adds some complexity, but it # is assumed that mainly humans read the output. # # Environment variable inst can be set to installation directory: This # is useful for development only, hence not officially documented. # env inst=. $0 --check # # Silently accepts the options -n or -h or --x also. # # echo vs /bin/echo # echo is a pain, depending on the platform. The shell's built-in echo # does not have the -n option, usually. /bin/echo doesn't know about # ANSI escape sequences, usually. \-escaped characters, like \t , are # another problem, some shells support them, others do not. # I.g. we'd like to use traditional bourne shell, where all behaviours # are well defined. Unfortunately, some platforms seem to be a hostage # of their developers who believe that their favorite shell has to be # used by all users (linking to /bin/sh to whatever, without informing # the user). # Best effort to get this script working on most platforms was: # * mainly use /bin/echo (aliased to echo, to keep code readable) # * TABs (aka \t aka 0x09) are used verbatim (see $t variable) # * shell's built-in echo used when ANSI escape sequences are used # There's no guarantee that it works flawless on everywhere, currently # (8/2019) it works for BSD, debian (including Mac OSX). # Functionallity of this script is not harmed, if the output with echo # fails (prints ANSI escapes and/or \-escapes verbatim, and/or prints # -n verbatim, etc.). # #? DEPENDENCIES #? Following tools are required for proper functionality: #? awk, cat, perl, sed, tr, which, /bin/echo #? #? VERSION #? @(#) 1.99 22/11/19 14:50:00 #? #? AUTHOR #? 16-sep-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- # --------------------------------------------- internal variables; defaults try='' ich=${0##*/} dir=${0%/*} [ "$dir" = "$0" ] && dir="." # $0 found via $PATH in . _break=0 # 1 if screen width < 50; then use two lines as output colour="" # 32 green, 34 blue for colour-blind useenv=0 # 1 to change shebang lines to /usr/bin/env other=0 force=0 optx=0 optn="" mode=""; # "", cgi, check, clean, dest, openssl alias echo=/bin/echo # need special echo which has -n option; # TODO: check path for each platform tab=" " # need a real TAB (0x09) for /bin/echo text_miss=" missing, try installing with "; text_old="ancient module found, try installing newer version, at least " text_one="missing, consider generating with »make standalone«" text_path="Note: all found executables in PATH are listed" text_prof="note: Devel::DProf Devel::NYTProf and GraphViz2 may wrongly be missing" text_tool="Note: podman is a tool to view pod files, it's not the container engine" # must be redefined after reading arguments text_dev="did you run »$0 --clean«?" text_alt="file from previous installation, try running »$0 --clean« " # generated data from Makefile 2.19 { osaft_sh="o-saft" osaft_exe="o-saft.pl" osaft_gui="o-saft.tcl" osaft_one="contrib/o-saft-standalone.pl" osaft_dock="o-saft-docker" contrib_dir="contrib" inst_directory=${inst:="/usr/local/o-saft"} perl_modules="Net::DNS Net::SSLeay IO::Socket::INET IO::Socket::SSL Time::Local" osaft_modules=" osaft Net::SSLinfo Net::SSLhello OSaft::Ciphers OSaft::Data OSaft::Text OSaft::error_handler OSaft::Doc::Data " files_contrib=" 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/alertscript.cfg contrib/alertscript.pl 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/symbol.pl 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/Data.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/Text.pm 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 " files_install_cgi=" docs/o-saft.cgi.html o-saft.cgi o-saft.php " files_install_doc=" docs/o-saft.1 docs/o-saft.html docs/o-saft.pod " tools_intern=" contrib/gen_standalone.sh t/cloc-total.awk t/o-saft_bench.sh t/test-bunt.pl.txt " tools_extern=" cloc ctags diff docker dprofpp gpg mgdiff nytprofhtml perl-analyzer perl-analyzer-output perlcritic podchecker sccs sha256sum tkdiff xxdiff " tools_modules=" Data::Dumper Debug::Trace Devel::DProf Devel::NYTProf Devel::Size Devel::Trace File::Find GraphViz2 JSON Perl::Analyzer Pod::Perldoc Storable Text::MicroTemplate " tools_optional=" aha perldoc pod2html pod2man pod2pdf pod2text pod2usage podman podviewer stty tkpod tput " tools_other=" OSSL_CCS_InjectTest.py SSLAudit.exe SSLAudit.pl SSLCertScanner.exe SSLPressure.exe TLSSLed_v1.3.sh TestSSLServer.exe TestSSLServer.jar analyze-ssl.pl athena-ssl-cipher-check_v062.jar bash-heartbleed.sh beast.pl ccs-injection.sh check-ssl-heartbleed.pl chksslkey cnark.pl manyssl poet robot-detect smtp_tls_cert.pl ssl-cert-check ssl-check-heartbleed.pl ssl-cipher-check.pl ssl-dos ssl-renegotiation.sh sslcat ssldiagnos.exe sslmap.py sslscan sslscan.exe sslsniff sslstrip ssltest.pl ssltest_heartbeat.py sslthing.sh sslyze.py stunnel testssl.sh tls-check.pl tls-scan tlsenum vessl " # generated data from Makefile 2.19 } # HARDCODED { # because newer Makefiles may no longer know about them files_ancient=" generate_ciphers_hash openssl_h-to-perl_hash o-saft-README INSTALL-devel.sh .perlcriticrc o-saft_bench contrib/.o-saft.tcl contrib/o-saft.cgi contrib_dir/o-saft.php " # first, dirty hack to make tests in development mode possible # remember the inserted "" to avoid substitutions here [ "INSERTED_""BY_MAKE_OSAFT_SH" = "$osaft_sh" ] && osaft_sh=o-saft [ "INSERTED_""BY_MAKE_OSAFT_PL" = "$osaft_exe" ] && osaft_exe=o-saft.pl [ "INSERTED_""BY_MAKE_OSAFT_GUI" = "$osaft_gui" ] && osaft_gui=o-saft.tcl [ "INSERTED_""BY_MAKE_OSAFT_DOCKER" = "$osaft_dock" ] && osaft_dock=o-saft-docker [ "INSERTED_""BY_MAKE_CONTRIBDIR" = "$contrib_dir" ] && contrib_dir=contrib # some files "not to be installed" are ancient, they are kept here in # $files_not_installed to ensure that outdated content is also handled files_not_installed=" $contrib_dir/o-saft.cgi $contrib_dir/o-saft.php $contrib_dir/Dockerfile.alpine-3.6 $contrib_dir/Dockerfile.wolfssl $contrib_dir/distribution_install.sh $contrib_dir/gen_standalone.sh $contrib_dir/install_perl_modules.pl $contrib_dir/install_openssl.sh $contrib_dir/INSTALL-template.sh " files_develop="o-saft-docker-dev Dockerfile Makefile t/ $contrib_dir/critic.sh" files_info="CHANGES README o-saft.tgz" # HARDCODED } osaft_subdirs=" $contrib_dir Net OSaft/Doc docs " osaft_exerc=".$osaft_exe" osaft_guirc=".$osaft_gui" build_openssl="$contrib_dir/install_openssl.sh" all_exe="$osaft_exe $osaft_gui $osaft_sh $osaft_dock $osaft_one" # checking INSTALL.sh (myself) is pointless, somehow ... _line='----------------------+-----------------' _cols=0 \command -v \tput >/dev/null && _cols=`\tput cols` if [ 0 -lt $_cols ]; then # adapt _line to screen width [ -n "$OSAFT_MAKE" ] && _cols=78 # SEE Make:OSAFT_MAKE [ 51 -gt $_cols ] && _break=1 # see echo_label() while [ 42 -lt $_cols ]; do _line="$_line-" _cols=`expr $_cols - 1` done fi # --------------------------------------------- internal functions echo_head () { echo "" if [ -z "$colour" ]; then echo "$@" echo "#$_line" else \echo "\033[7;37m\033[1;30m$@" \echo "#$_line\033[0m" fi } echo_foot () { if [ -z "$colour" ]; then echo "#$_line" else \echo "\033[7;37m\033[1;30m#$_line\033[0m" fi } echo_label () { perl -le "printf'# %21s%c','$@',0x09" # use perl instead of echo for formatting [ 0 -eq $_break ] && return perl -le 'printf"\n\t"' # use additional line } # for escape sequences, shell's built-in echo must be used echo_yellow () { [ -z "$colour" ] && echo "$@" && return \echo "\033[1;33m$@\033[0m" } echo_green () { [ -z "$colour" ] && echo "$@" && return \echo "\033[1;$colour$@\033[0m" } echo_red () { [ -z "$colour" ] && echo "$@" && return \echo "\033[1;31m$@\033[0m" } check_commands () { for c in $* ; do echo_label "$c" is=`\command -v $c` [ -n "$is" ] && echo_green "$is" || echo_red "missing" done return } copy_file () { src=$1 dst=$2 convert=0 if [ 0 -lt $useenv ]; then ext=${src##*.} file=${src##*/} # ugly hardcode match of extensions and names case "$ext" in awk | cgi | pl | pm | sh | tcl | pod | txt) convert=1 ; ;; esac case "$file" in usage_examples) convert=1 ; ;; Dockerfile*) convert=1 ; ;; Makefile*) convert=1 ; ;; *_completion_o-saft) convert=1 ; ;; esac fi if [ 1 -eq $convert ]; then # only the very first line $. ist changed if [ "$try" = "echo" ]; then echo 'perl -lane "if(1==$.){s|^.*?/([a-zA-Z0-9_.-]+$)|#\! /usr/bin/env $1|;}print;" '"'$src' > '$dst'" return fi \perl -lane 'if(1==$.){s|^.*?/([a-zA-Z0-9_.-]+)\s*$|#\! /usr/bin/env $1|;}print;' \ "$src" > "$dst" || exit 4 # set proper modes \chmod 555 "$dst" # assuming that it is and should be executable else $try \cp --preserve=all "$src" "$dst" || exit 4 fi return } # --------------------------------------------- arguments and options new_dir= 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; ;; # # # # '-x' | '--x') optx=1; ;; '--cgi') mode=cgi; ;; '--check') mode=check; ;; '--clean') mode=clean; ;; '--install') mode=dest; ;; '--openssl') mode=openssl; ;; '--expect') mode=expected; ;; # alias '--expected') mode=expected; ;; '--checkdev') mode=checkdev; ;; '--check-dev') mode=checkdev; ;; '--force') force=1; ;; '--other') other=1; ;; '--no-colour') colour=""; ;; '--colour') colour="34m"; ;; '--colour-blind') colour="34m"; ;; '--colour-not-blind') colour="32m"; ;; '--no-color') colour=""; ;; # alias '--color') colour="34m"; ;; # alias '--color-blind') colour="34m"; ;; # alias '--color-not-blind') colour="32m"; ;; # alias '--bunt') colour="34m"; ;; # alias '--blind') colour="34m"; ;; # alias '--useenv') useenv=1; ;; '--use-env') useenv=1; ;; # alias '--version') \sed -ne '/^#? VERSION/{' -e n -e 's/#?//' -e p -e '}' $0 exit 0 ;; '+VERSION') echo 1.99 ; exit; ;; # for compatibility to $osaft_exe *) new_dir="$1" ; ;; # directory, last one wins esac shift done if [ -n "$new_dir" ]; then inst_directory="$new_dir" [ -z "$mode" ] && mode=dest # no mode given, set default fi clean_directory="$inst_directory/.files_to_be_removed" # set on command line text_dev="did you run »$0 --clean $inst_directory«?" text_alt="file from previous installation, try running »$0 --clean $inst_directory« " # --------------------------------------------- main # ------------------------- default mode --------- { if [ -z "$mode" ]; then cat << EoUsage # 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 # Optionally call: $0 /path/to/installation/directoy --clean # To check if O-Saft will work, you may use: $0 --check . $0 --check /path/to/installation/directoy # To get a sample of the expected output for --check , use: $0 --expected # To check development requirements, use: $0 --checkdev # In a Docker image, this script may only be called like: $0 --check EoUsage exit 0 fi; # default mode } if [ "$mode" != "check" ]; then if [ -n "$osaft_vm_build" ]; then echo "**ERROR: 001: found 'osaft_vm_build=$osaft_vm_build'" echo_red "**ERROR: 002: inside docker only --check possible; exit" exit 6 fi fi # ------------------------ cgi mode -------------- { if [ "$mode" = "cgi" ]; then echo "# prepare $inst_directory for use in CGI mode" if [ ! -d "$inst_directory" ]; then echo_red "**ERROR: 050: $inst_directory does not exist; exit" [ "$try" = "echo" ] || exit 2 # with --n continue, so we see what would be done fi if [ -d "$clean_directory" ]; then echo_red "**ERROR: 051: $clean_directory exist; CGI installation not yet supported" exit 2 fi for f in $files_install_cgi ; do file=${f##*/} [ -e "$inst_directory/$file" ] && echo -n "# " && echo_yellow "existing $file; ignored" && continue $try \mv $f "$inst_directory/" || echo_red "**ERROR: 052: moving $f failed" done lnk=cgi-bin [ -e "$inst_directory/$lnk" ] && echo -n "# " && echo_yellow "existing $lnk; ignored" && continue $try \ln -s "$inst_directory" $lnk || echo_red "**ERROR: 053: symlink $lnk failed" exit 0 fi; # cgi mode } # ------------------------ expected mode --------- { if [ "$mode" = "expected" ]; then echo "## Expected output (sample) when called like:" echo "## $0 --check /opt/o-saft" \sed -ne '/^#=/s/#=//p' $0 exit 0 fi; # expected mode } # ------------------------- openssl mode --------- { if [ "$mode" = "openssl" ]; then echo "# call $build_openssl" [ ! -x "$build_openssl" ] && echo_red "**ERROR: 020: $build_openssl does not exist; exit" && exit 2 [ 0 -lt "$optx" ] && set -x $build_openssl $optn $@ status=$? if [ $status -ne 0 ]; then cat << EoT # $build_openssl uses its default settings. To check the settings, use: # $0 --openssl --n # If other configurations should be used, please use directly: # $build_openssl --help # $build_openssl --n # $build_openssl /path/to/install # $build_openssl /path/to/install --debian --i --m EoT fi exit $status fi; # openssl mode } # ------------------------- clean mode ----------- { if [ "$mode" = "clean" ]; then echo "# cleanup installation in $inst_directory" [ -d "$clean_directory" ] || $try \mkdir "$clean_directory/$f" [ -d "$clean_directory" ] || $try echo_red "**ERROR: 030: $clean_directory does not exist; exit" [ -d "$clean_directory" ] || $try exit 2 # do not move $contrib_dir/ as all examples are right there [ 0 -lt "$optx" ] && set -x cnt=0 files="$files_info $files_ancient $files_develop $files_install_cgi $files_install_doc $files_not_installed" for f in $files ; do #dbx echo "$clean_directory/$f" [ -e "$clean_directory/$f" ] && $try \rm -f "$clean_directory/$f" f="$inst_directory/$f" [ -e "$f" ] && $try \mv "$f" "$clean_directory" && cnt=`expr $cnt + 1` done echo -n "# moved $cnt files to $clean_directory "; echo_green "completed." exit 0 fi; # clean mode } # ------------------------- install mode -------- { if [ "$mode" = "dest" ]; then if [ ! -d "$inst_directory" ]; then echo_red "**ERROR: 040: $inst_directory does not exist; exit" [ "$try" = "echo" ] || exit 2 # with --n continue, so we see what would be done fi files="$files_install $files_install_cgi $files_install_doc $files_contrib $osaft_one" [ 0 -lt "$optx" ] && set -x echo "# remove old files ..." for f in $files ; do f="$inst_directory/$f" if [ -e "$f" ]; then $try \rm -f "$f" || exit 3 fi done echo "# installing ..." for d in $osaft_subdirs ; do $try \mkdir -p "$inst_directory/$d" done for f in $files ; do [ -e "$f" ] || echo_red "**ERROR: 043: missing $f; file ignored" copy_file "$f" "$inst_directory/$f" done if [ -z "$try" ]; then w=$(\command -v wish) if [ -n "$osaft_gui" -a -n "$w" ]; then $try $inst_directory/$osaft_gui --rc > "$inst_directory/$osaft_guirc" \ || echo_red "**ERROR: 041: generating $osaft_guirc failed" else echo -n "# " && echo_yellow "missing wish; $osaft_guirc not installed" fi else echo "$inst_directory/$osaft_gui --rc > $inst_directory/$osaft_guirc" fi if [ $force -eq 1 ]; then echo '# installing RC-FILEs in $HOME ...' for f in $inst_directory/$osaft_exerc $inst_directory/$osaft_exerc ; do $try \cp $f "$HOME/" || echo_red "**ERROR: 042: copying $f failed" done fi echo "# consider calling: $0 --clean $inst_directory" echo -n "# installation in $inst_directory "; echo_green "completed." exit 0 fi; # install mode } # ------------------------- checkdev mode -------- { if [ "$mode" = "checkdev" ]; then echo "" echo "# check system for development usage" echo_head "# check for tools used with/in make targets" check_commands $tools_intern check_commands $tools_extern echo "#" echo "# $text_tool" echo_foot echo_head "# check for Perl modules used with/in make targets" for m in $tools_modules ; do echo_label "$m" # NOTE: -I . used to ensure that local ./Net is found v=`perl -I . -M$m -le 'printf"%8s",$'$m'::VERSION' 2>/dev/null` if [ -n "$v" ]; then echo_green "$v" else echo_red "missing; install with: »cpan $m«" err=`expr $err + 1` fi done echo "#" echo "# $text_prof" echo_foot echo "" [ $other -eq 0 ] && exit 0; # printed with --other only echo_head "# check for other SSL-related tools" check_commands $tools_other echo_foot exit 0 fi; # checkdev mode } # ------------------------- check mode ----------- { if [ "$mode" != "check" ]; then echo_red "**ERROR: 060: unknow mode $mode; exit" exit 5 fi # all following is mode "check" #[ 0 -lt "$optx" ] && set -x # - not used here cnt=0 gui=0 echo_head "# check for O-Saft programs found via environment variable PATH" for p in `echo $PATH|tr ':' ' '` ; do for o in $all_exe wish ; do exe="$p/$o" if [ -e "$exe" ]; then cnt=`expr $cnt + 1` echo_label "$exe" && echo_green "$p" #echo_label "$exe" && echo_yellow "missing" fi [ "$o" != "wish" ] && continue if [ -e "$exe" ]; then gui=`expr $gui + 1` echo_label "wish" && echo_green "$p" fi done done echo "#" echo "# $text_path" [ 0 -eq $cnt -o 0 -eq $gui ] && echo "#" [ 0 -eq $cnt ] && echo_label "$osaft_exe" \ && echo_yellow "not found in PATH, consider adding $inst_directory to PATH" [ 0 -eq $gui ] && echo_label "wish" \ && echo_yellow "not found in PATH, consider installing wish" \ && osaft_gui= [ -e "$osaft_one" ] || ( echo_label "$osaft_one" && echo_yellow "$text_one" ) echo_foot PATH=${inst_directory}:$PATH # ensure that given directory is in PATH [ -n "$optn" ] && echo cd "$inst_directory" cd "$inst_directory" err=0 echo_head "# check installation in $inst_directory" echo "# (warnings are ok if »git clone« will be used for development)" # err=`expr $err + 1` ; # errors not counted here for f in $files_ancient ; do [ -e "$f" ] && echo_label "$f" && echo_yellow "found; $text_alt" done for f in $files_develop $files_info ; do [ -e "$f" ] && echo_label "$f" && echo_yellow "found; $text_dev" done echo_foot echo_head '# check for used O-Saft programs (according $PATH)' for o in $all_exe ; do echo_label "$o" e=`\command -v $o` if [ -n "$e" ] ; then v=`$o +VERSION` txt=`echo "$v $e"|awk '{printf("%8s %s",$1,$2)}'` echo_green "$txt" else err=`expr $err + 1` echo_red "not found" fi done echo_foot echo_head "# check for installed O-Saft resource files" # currently no version check cnt=0 for p in `echo $HOME $PATH|tr ':' ' '` ; do rc="$p/$osaft_exerc" if [ -e "$rc" ]; then cnt=`expr $err + 1` echo_label "$rc" && echo_yellow "will be used when started in $p only" fi done [ 0 -eq $cnt ] && echo_yellow "$rc not found" rc="$HOME/$osaft_guirc" if [ -e "$rc" ]; then v=`awk '/RCSID/{print $3}' $rc | tr -d '{};'` echo_label "$rc" && echo_green "$v" txt="ancient" else txt="missing" fi echo_label "$rc" && echo_yellow "$txt, consider generating: »$osaft_gui --rc > $rc«" echo_foot # from here on, all **WARNINGS (from $osaft_exe) are unimportant and hence # redirected to /dev/null echo_head "# check for installed Perl modules (started in $inst_directory )" for m in $perl_modules $osaft_modules ; do echo_label "$m" # NOTE: -I . used to ensure that local ./Net is found v=`perl -I . -M$m -le 'printf"%8s",$'$m'::VERSION' 2>/dev/null` p=`perl -I . -M$m -le 'my $idx='$m';$idx=~s#::#/#g;printf"%s",$INC{"${idx}.pm"}' 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; ;; 'Time::Local') expect=1.90; ;; 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"; ;; 'Time::Local') # has strange version numbering, needs ugly hack :-(( if [ 1.25 = $v \ -o 1.26 = $v \ -o 1.27 = $v \ -o 1.28 = $v ]; then # 1.25 seems to be newer than 1.230 which is newer than 1.90 c="green"; else c=`echo $expect $v | perl -anle '($e=$F[0])=~s#(\d+)#sprintf"%05d",$1#ge;($v=$F[1])=~s#(\d+)#sprintf"%05d",$1#ge;print (($e > $v) ? "red" : "green")'`; fi ;; *) c=`echo $expect $v | perl -anle '($e=$F[0])=~s#(\d+)#sprintf"%05d",$1#ge;($v=$F[1])=~s#(\d+)#sprintf"%05d",$1#ge;print (($e > $v) ? "red" : "green")'`; ;; # NOTE: need to compare for example: 1.23 > 1.230 # Comparing version strings is tricky, best method would be # to use Perl's Version module. But this script should work # on limited systems too, hence above cumbersome code: # 1. get the version strings on stdin # 2. convert all number parts of the string to fixed 5-digit # format with leading zeros: 1.230 > 00001.000230 # 3. compare converted strings # Perl is clever enough to handle 00001.00023.42000 also esac [ "$c" = "green" ] && echo_green "$v $p" [ "$c" = "red" ] && echo_red "$v $p, $text_old $expect" [ "$c" = "red" ] && err=`expr $err + 1` else text_miss="$text_miss »cpan $m«" echo_red "$text_miss" err=`expr $err + 1` fi done echo_foot echo_head "# check for important Perl modules used by installed O-Saft" for p in `echo $inst_directory $PATH|tr ':' ' '` ; do o="$p/$osaft_exe" [ -e "$o" ] || continue # NOTE: output format is slightly different, 'cause **WARNINGs are printed too echo "# testing $o ...$tab" for m in $perl_modules ; do echo_label "$m" w=`$o --no-warn +version 2>&1 | awk '/(ERROR|WARNING).*'$m'/{print}'` v=`$o --no-warn +version 2>/dev/null | awk '($1=="'$m'"){printf"%8s %s",$2,$3}'` if [ -n "$w" ]; then # ERROR in $w most likely means that $m is not found by # perl, then $v is empty if [ -z "$v" ]; then echo_red "$w" else echo_red "$v" echo_yellow "$w" fi else if [ -z "$v" ]; then echo_yellow "missing?" # probaly due to ERROR else echo_green "$v" fi fi #err=`expr $err + 1` # already counted in previous check done done echo_foot echo_head "# summary of warnings from installed O-Saft (should be empty)" o="$inst_directory/$osaft_exe" if [ -e "$o" ]; then echo "# testing $o in $inst_directory ...$tab" cd "$inst_directory" w=`$o +version 2>&1 | awk '/WARNING:/{print}'` [ -n "$w" ] && echo_yellow "$w" fi echo_foot echo_head "# check for openssl executable in PATH" echo_label "openssl" && echo_green "`which openssl`" "(`openssl version`)" \ || echo_yellow "missing" # TODO: error when openssl older than 0x01000000 has no SNI echo_foot echo_head "# check for openssl executable used by O-Saft" for p in `echo $inst_directory $PATH|tr ':' ' '` ; do o="$p/$osaft_exe" r="$p/.$osaft_exe" if [ -x "$o" ]; then # first call program to check if it is starting properly # if it fails with a status, the corresponding error is printed # and the extraction of the openssl executable is not done ( cd "$p" # ensure that $r is used $o --no-warn +version >/dev/null && \ openssl=`$o --no-warn +version 2>/dev/null | awk '/external executable/{print $NF}' | tr '\012' ' '` && \ echo_label "$o" && echo_green "$openssl" || echo_red "missing" ) fi done echo_foot echo_head "# check for optional tools to view documentation:" check_commands $tools_optional echo_foot echo_head "# check for contributed files (in $inst_directory/$contrib_dir ):" for c in $files_contrib $osaft_one ; do skip=0 for f in $files_not_installed $files_develop ; do [ "$f" = "$c" ] && skip=1 done [ $skip -eq 1 ] && continue _c=${c##*/} echo_label "$_c" #&& echo_green "$openssl" c="$inst_directory/$c" [ -e "$c" ] && echo_green "$c" || echo_yellow "missing $c" #err=`expr $err + 1` # not counted as error done echo_foot echo "" echo -n "# checks$tab" if [ $err -eq 0 ]; then echo_green "passed" else echo_red "failed , $err error(s) detected" [ -z "$new_dir" ] && echo "# default installation directory »$inst_directory« used;" [ -z "$new_dir" ] && echo "# consider using »$0 path/to/directory« " fi # check mode } exit $err O-Saft-22.11.22/LICENSE.md000066400000000000000000000404121433765727300144600ustar00rootroot00000000000000 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-22.11.22/Makefile000066400000000000000000000662011433765727300145200ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for O-Saft project #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? For help about the targets herein, please see: #? #? make #? make help #? #? For detailled documentation how GNU Make, its syntax and conventions as #? well as some special syntax of macros and targets is used here, please #? refer to Makefile.pod , for example by using "perldoc Makefile.pod" . #? The term "SEE Make:some text" is used to reference to Makefile.pod . # # HACKER's INFO # For the public available targets see below of "well known targets" . #? #? VERSION #? @(#) Makefile 2.19 22/11/19 00:14:07 #? #? AUTHOR #? 21-dec-12 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID = 2.19 # define our own SID as variable, if needed ... # SEE O-Saft:Makefile Version String # Known variables herein (8/2019) to be changed are: # _SID # _INST.text # _INST.is_edit ALL.includes := Makefile # must be := to avoid overwrite after includes # each $(TEST.dir)/Makefile* will add itself to ALL.includes 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. MAKEFLAGS = --no-builtin-variables --no-builtin-rules .SUFFIXES: .DEFAULT: @echo "**ERROR: unknown target '$(MAKECMDGOALS)'" first-target-is-default: help #_____________________________________________________________________________ #________________________________________________________________ variables __| Project = o-saft ProjectName = O-Saft INSTALL.dir = /usr/local/$(Project) # tool 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 OSAFT.pm = Ciphers.pm Data.pm Text.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 SRC.gui = $(Project).tcl $(Project)-img.tcl SRC.cgi = $(Project).cgi SRC.php = $(Project).php SRC.docker = \ $(Project)-docker \ $(Project)-docker-dev \ Dockerfile SRC.rc = .$(SRC.pl) SRC.exe = $(SRC.pl) $(SRC.gui) $(CHK.pl) $(DEV.pl) $(SRC.sh) SRC.make = Makefile SRC.misc = README.md CHANGES SRC.inst = $(SRC.contrib.dir)/INSTALL-template.sh # contrib files SRC.contrib.dir = contrib SRC.contrib.examples= filter_examples usage_examples SRC.contrib.post.awk= \ Cert-beautify.awk \ HTML-simple.awk HTML-table.awk \ JSON-struct.awk JSON-array.awk \ XML-attribute.awk XML-value.awk \ lazy_checks.awk SRC.contrib.post = \ Cert-beautify.pl \ alertscript.pl \ alertscript.cfg \ bunt.pl \ bunt.sh \ symbol.pl SRC.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 SRC.contrib.zap = zap_config.sh zap_config.xml # some file should get the $(Project) suffix, which is appended later SRC.contrib.complete= \ bash_completion \ dash_completion \ fish_completion \ tcsh_completion SRC.contrib = \ $(SRC.contrib.complete:%=$(SRC.contrib.dir)/%_$(Project)) \ $(SRC.contrib.examples:%=$(SRC.contrib.dir)/%) \ $(SRC.contrib.post.awk:%=$(SRC.contrib.dir)/%) \ $(SRC.contrib.post:%=$(SRC.contrib.dir)/%) \ $(SRC.contrib.misc:%=$(SRC.contrib.dir)/%) \ $(SRC.contrib.zap:%=$(SRC.contrib.dir)/%) TEST.dir = t TEST.logdir = $(TEST.dir)/log TEST.do = SSLinfo.pl \ o-saft_bench.sh \ cloc-total.awk \ critic_345.sh \ test-bunt.pl.txt TEST.critic.rc = .perlcriticrc SRC.test = \ $(TEST.do:%=$(TEST.dir)/%) \ $(TEST.critic.rc:%=$(TEST.dir)/%) TEST.Makefiles = \ Makefile Makefile.inc Makefile.help Makefile.pod \ Makefile.gen \ Makefile.opt Makefile.cmd Makefile.ext Makefile.exit \ Makefile.cgi Makefile.tcl Makefile.misc Makefile.warnings \ Makefile.critic Makefile.dev Makefile.etc Makefile.template \ Makefile.docker Makefile.FQDN Makefile.examples SRC.Makefiles = $(TEST.Makefiles:%=$(TEST.dir)/%) # documentation files DOC.dir = docs DOC.src = o-saft_CLI_data_flow.odg \ o-saft_GUI_data_flow.odg \ o-saft_docker.de.odg \ o-saft_docker.en.odg SRC.doc = $(DOC.src:%=$(DOC.dir)/%) WEB.dir = docs/img WEB.src = \ img.css \ O-Saft_CLI-cipher.png \ O-Saft_CLI-altname.png \ O-Saft_GUI-altname.png \ O-Saft_GUI-check.png \ O-Saft_GUI-cmd--docker.png \ O-Saft_GUI-cmd.png \ O-Saft_GUI-cmd-0.png \ O-Saft_GUI-filter.png \ O-Saft_GUI-help-0.png \ O-Saft_GUI-help-1.png \ O-Saft_GUI-opt.png \ O-Saft_GUI-prot.png \ O-Saft_GUI-vulns.png \ O-Saft_CLI-vulns.png \ O-Saft_CLI__faked.txt SRC.web = $(WEB.src:%=$(WEB.dir)/%) # generated files TMP.dir = /tmp/$(Project) GEN.html = $(DOC.dir)/$(Project).html GEN.cgi.html = $(DOC.dir)/$(Project).cgi.html GEN.text = $(DOC.dir)/$(Project).txt GEN.wiki = $(DOC.dir)/$(Project).wiki GEN.man = $(DOC.dir)/$(Project).1 GEN.pod = $(DOC.dir)/$(Project).pod GEN.src = $(SRC.contrib.dir)/$(Project)-standalone.pl GEN.pdf = $(SRC.doc:%.odg=%.pdf) GEN.inst = INSTALL.sh GEN.tags = tags GEN.rel = $(Project).rel GEN.tgz = $(Project).tgz GEN.tmptgz = $(TMP.dir)/$(GEN.tgz) # generated files for internal use, i.e. $(SRC.tcl) # TODO: because make does not allow = in target names, the generated targets # should use - instead LIST.DOC_data = --help --help=opts --help=commands --help=glossar --help=alias \ --help=data --help=data --help=checks --help=regex --help=rfc \ --help=ciphers-html --help=ciphers-text # --help=warnings uses a different command to be generated GEN.DOC.data = $(LIST.DOC_data:%=$(DOC.dir)/$(SRC.pl).%) GEN.DOC.data += $(DOC.dir)/$(SRC.pl).--help=warnings # summary variables GEN.docs = $(GEN.pod) $(GEN.html) $(GEN.cgi.html) $(GEN.text) $(GEN.wiki) $(GEN.man) # NOTE: sequence in ALL.Makefiles is important, for example when used in target doc ALL.Makefiles = $(SRC.make) $(SRC.Makefiles) ALL.osaft = $(SRC.pl) $(SRC.gui) $(CHK.pl) $(SRC.pm) $(SRC.sh) $(SRC.txt) $(SRC.rc) $(SRC.docker) ALL.exe = $(SRC.exe) $(SRC.cgi) $(SRC.php) $(GEN.src) $(SRC.docker) ALL.tst = $(SRC.test) ALL.contrib = $(SRC.contrib) ALL.doc = $(SRC.doc) $(SRC.web) ALL.pm = $(SRC.pm) ALL.gen = $(GEN.src) $(GEN.docs) $(GEN.DOC.data) ALL.docs = $(SRC.doc) $(GEN.docs) # NOTE: ALL.docs are the files for user documentation, ALL.doc are SRC-files # $(GEN.wiki) is rarley used but part of ALL.gen for simplicity # # $(GEN.tags) added in t/Makefile.misc ALL.src = \ $(ALL.exe) \ $(ALL.pm) \ $(SRC.txt) \ $(SRC.rc) \ $(SRC.misc) \ $(SRC.doc) \ $(ALL.gen) \ $(ALL.Makefiles) \ $(ALL.tst) \ $(ALL.contrib) ALL.tgz = $(ALL.src:%=O-Saft/%) ALL.tgz += O-Saft/$(GEN.inst) # internal used make MAKE = $(MAKE_COMMAND) # some rules need to have a command, otherwise they are not evaluated EXE.dummy = /bin/echo -n "" # internal used tools (paths hardcoded!) 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 # other tools EXE.office = libreoffice # summary variables (mainly used for INSTALL.sh) _ALL.devtools.intern += $(EXE.single) _ALL.devtools.extern += sccs gpg sha256sum docker ALL.tools.optional = aha perldoc pod2html pod2man pod2pdf pod2text pod2usage podman podviewer tkpod stty tput ALL.perlmodules = Net::DNS Net::SSLeay IO::Socket::INET IO::Socket::SSL Time::Local ALL.devtools = $(_ALL.devtools.intern) $(_ALL.devtools.extern) ALL.devmodules = $(_ALL.devmodules.intern) $(_ALL.devmodules.extern) # defined in t/Makefile.misc ALL.osaftmodules= osaft $(NET.pm:%.pm=Net::%) $(OSAFT.pm:%.pm=OSaft::%) OSaft::Doc::Data # following for documentation, not yet used (2022) #_ALL.tools.dbian.pkg = aha libtk-pod-perl perl-doc perl-doc-html pod2pdf # INSTALL.sh must not contain duplicate files, hence the variable's content # is sorted using make's built-in sort which removes duplicates _INST.osaft_cgi = $(sort $(SRC.cgi) $(SRC.php) $(GEN.cgi.html)) _INST.osaft_doc = $(sort $(GEN.pod) $(GEN.man) $(GEN.html)) _INST.contrib = $(sort $(ALL.contrib)) _INST.osaft = $(sort $(ALL.osaft)) _INST.devtools = $(sort $(ALL.devtools)) _INST.tools_int = $(sort $(_ALL.devtools.intern)) _INST.tools_ext = $(sort $(_ALL.devtools.extern)) _INST.tools_opt = $(sort $(ALL.tools.optional)) _INST.tools_other = $(sort $(ALL.tools.ssl)) _INST.devmodules= $(sort $(ALL.devmodules)) _INST.genbytext = generated data by Makefile 2.19 from $(SRC.inst) _INST.gen_text = generated data from Makefile 2.19 EXE.install = sed -e 's@INSERTED_BY_MAKE_INSTALLDIR@$(INSTALL.dir)@' \ -e 's@INSERTED_BY_MAKE_CONTRIBDIR@$(SRC.contrib.dir)@' \ -e 's@INSERTED_BY_MAKE_CONTRIB@$(_INST.contrib)@' \ -e 's@INSERTED_BY_MAKE_TOOLS_OTHER@$(_INST.tools_other)@' \ -e 's@INSERTED_BY_MAKE_TOOLS_OPT@$(_INST.tools_opt)@' \ -e 's@INSERTED_BY_MAKE_DEVTOOLSINT@$(_INST.tools_int)@' \ -e 's@INSERTED_BY_MAKE_DEVTOOLSEXT@$(_INST.tools_ext)@' \ -e 's@INSERTED_BY_MAKE_DEVMODULES@$(_INST.devmodules)@' \ -e 's@INSERTED_BY_MAKE_PERL_MODULES@$(ALL.perlmodules)@' \ -e 's@INSERTED_BY_MAKE_OSAFT_SH@$(SRC.sh)@' \ -e 's@INSERTED_BY_MAKE_OSAFT_PL@$(SRC.pl)@' \ -e 's@INSERTED_BY_MAKE_OSAFT_GUI@$(SRC.tcl)@' \ -e 's@INSERTED_BY_MAKE_OSAFT_CGI@$(_INST.osaft_cgi)@' \ -e 's@INSERTED_BY_MAKE_OSAFT_STAND@$(GEN.src)@' \ -e 's@INSERTED_BY_MAKE_OSAFT_DOCKER@$(EXE.docker)@' \ -e 's@INSERTED_BY_MAKE_OSAFT_DOC@$(_INST.osaft_doc)@' \ -e 's@INSERTED_BY_MAKE_OSAFT_MODULES@$(ALL.osaftmodules)@' \ -e 's@INSERTED_BY_MAKE_OSAFT@$(_INST.osaft)@' \ -e 's@INSERTED_BY_MAKE_FROM@$(_INST.genbytext)@' \ -e 's@INSERTED_BY_MAKE@$(_INST.gen_text)@' # note that the sequence of the -e commands is important # last substitude is fallback to ensure everything is changed # generate f- targets to print HELP text for each target _HELP.my_targets= $(shell $(EXE.eval) $(MAKEFILE)) _HELP.alltargets= $(shell $(EXE.eval) $(ALL.includes)) _HELP.help = $(ALL.help:%=f-%) # quick&dirty because each target calls make (see below) #_____________________________________________________________________________ #___________________________________________________________ default target __| # define header part of default target help: HELP_HEAD = $(HELP_RULE) help.all: HELP_HEAD = $(HELP_RULE) help.log: HELP_HEAD = $(HELP_RULE) help.all.log: HELP_HEAD = $(HELP_RULE) doc: HELP_HEAD = $(HELP_RULE) doc.all: HELP_HEAD = $(HELP_RULE) # define body part of default target # TODO: adapt _help_* macros and targets according own naming convention _help_also_ = _help_also _help_body_ = _help_body_me _help_list_ = help.all: _help_body_ = _help_body_all help.all: _help_list_ = _help_list doc: _help_body_ = _eval_body_me doc.all: _help_body_ = _eval_body_all doc: _help_also_ = doc.all: _help_also_ = doc.all: _help_list_ = _help_list # for targets defined in Makefile.help help.all%: _help_body_ = _help_body_all help.all%: _help_list_ = _help_list %.all-v: _help_text-v = _help_text-v = \# to see Makefile, where targets are defined, use: $(MAKE_COMMAND) $(MAKECMDGOALS)-v #_____________________________________________________________________________ #_________________________________________________________ internal targets __| # SEE Make:.SECONDEXPANSION .SECONDEXPANSION: # If variables, like $(_HELP.*targets), contain duplicate target names (which # is intended), only one will be executed by $(MAKE), hence the 2nd occurance # is missing. _eval_body_me: @$(MAKE) -s $(_HELP.my_targets) @echo "$(HELP_LINE)" _eval_body_all: @$(MAKE) -s $(_HELP.alltargets) _help_body_me: @$(EXE.help) $(MAKEFILE) @echo "$(HELP_LINE)" _help_body_all: @$(EXE.help) $(ALL.includes) _help_list: @echo "" @echo " #___________ targets for information about test targets... _" @$(MAKE) $(_HELP.help) @echo "$(HELP_LINE)" @echo "$(_help_text-v)" _help_also: @echo "# to expand variables, use: $(MAKE_COMMAND) doc" # ensure that target help: from this file is used and not help% help help.all doc doc.all: _help.HEAD $$(_help_body_) $$(_help_list_) $$(_help_also_) @$(TRACE.target) help.all-v help.all-vv: help.all @$(EXE.dummy) #doc.all-v doc.all-vv: help.all # TODO: not implemented yet .PHONY: help help.all doc doc.all #_____________________________________________________________________________ #__________________________________________________________________ targets __| HELP-_known = _______________________________________ well known targets _ HELP-all = does nothing; alias for help HELP-clean = remove all generated files '$(ALL.gen) $(GEN.tags)' HELP-release = generate signed '$(GEN.tgz)' from sources HELP-install = install tool in '$(INSTALL.dir)' using '$(GEN.inst)', $(INSTALL.dir) must exist HELP-uninstall = remove installtion directory '$(INSTALL.dir)' completely $(INSTALL.dir): @$(TRACE.target) mkdir $(_INSTALL_FORCE_) $(INSTALL.dir) all: help clean: clean.tmp clean.tar clean.gen clear: clean # target calls installed $(SRC.pl) to test general functionality install: $(GEN.inst) $(INSTALL.dir) @$(TRACE.target) $(GEN.inst) $(INSTALL.dir) \ && $(INSTALL.dir)/$(SRC.pl) --no-warning --tracearg +quit > /dev/null install-f: _INSTALL_FORCE_ = -p install-f: install uninstall: @$(TRACE.target) -rm -r --interactive=never $(INSTALL.dir) _RELEASE = $(shell perl -nle '/^\s*sub _VERSION/ && do { s/.*?"([^"]*)".*/$$1/;print }' $(SRC.pl)) release.show: @echo "Release: $(_RELEASE)" release: $(GEN.tgz) @$(TRACE.target) 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.md; 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. # what may also return lines like: # @(#) filename 1.245 19/11/19 12:23:42', # @(#) filename generated by 1.227 19/11/19 10:12:13 # The perl script takes care of them and ignores or pretty prints the strings. # The "generated by" may occour i.e. in o-saft.tcl. # NOTE: only files available in the repository are used, therefore 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 '/ generated by /&&next;/^(.*):$$/&&do{$$f=$$m=$$1;$$m=~s#.*/##;next;};/.*?($$m|%[M]%)/&&do{$$f=~s/yeast/o-saft/;$$F[0]=~s/yeast/o-saft/;$$t=$$F[3];$$q=chr(0x27);$$t=~s#["$$q,]##g;printf("%s\t%s\t%s\t%s\t%s\n",$$F[1],$$F[2],$$t,$$F[0],$$f)};' rel :$(GEN.rel) $(_RELEASE).rel: Makefile @$(MAKE) -s $(GEN.rel) > $@ .PHONY: all clean install install-f uninstall release.show release rel variables = \$$(variables) # # define literal string $(variables) for "make doc" HELP-_project = ____________________________________ targets for $(Project) _ HELP-help = print common targets for O-Saft (this help) 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-man = generate MAN format help '$(GEN.man)' 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-docs = generate '$(GEN.docs)'; see also target doc.data HELP-tar = generate '$(GEN.tgz)' from all source prefixed with O-Saft/ HELP-tmptar = generate '$(GEN.tmptgz)' from all sources without prefix HELP-doc.data = generate '$(GEN.DOC.data)' for $(SRC.tcl) HELP-gen.all = generate most "generatable" file 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-clean.tmp = remove '$(TMP.dir)' HELP-clean.tar = remove '$(GEN.tgz)' HELP-clean.gen = remove '$(ALL.gen)' '$(GEN.inst)' '$(GEN.tags)' HELP-clean.all = remove '$(ALL.gen)' '$(GEN.inst)' '$(GEN.tags)' '$(GEN.tgz)' HELP-install-f = install tool in '$(INSTALL.dir)' using '$(GEN.inst)', '$(INSTALL.dir)' may exist HELP-o-saft.rel = generate '$(GEN.rel)' # # HELP-o-saft.rel hardcoded, grrr HELP-_vv1 = ___________ any target may be used with following suffixes _ HELP--v = verbose: print target and newer dependencies also HELP--vv = verbose: print target and all dependencies also HELP-_project2 = __________________ targets to get more help and information _ HELP-help.all = print all targets, including most test and development targets # # defined in t/Makefile.help also HELP-help.help = print targets to get information/documentation from Makefiles # alias targets pl: $(SRC.pl) cgi: $(GEN.cgi.html) man: $(GEN.man) pdf: $(GEN.pdf) pod: $(GEN.pod) html: $(GEN.html) text: $(GEN.text) wiki: $(GEN.wiki) docs: $(GEN.docs) standalone: $(GEN.src) tar: $(GEN.tgz) _INST.is_edit = 2.19 tar: _INST.is_edit = 2.19 tmptar: _INST.is_edit = something which hopefully does not exist in the file tmptar: $(GEN.tmptgz) tmptgz: $(GEN.tmptgz) cleangen: clean.gen 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 gen.all: $(ALL.gen) doc.data: $(GEN.DOC.data) docdata: $(GEN.DOC.data) tcl.data: @echo "**ERROR: ancient target; please use 'doc.data'" tcldata: tcl.data # docker target uses project's own script to build and remove the image docker.build: @$(TRACE.target) $(EXE.docker) -OSAFT_VERSION=$(_RELEASE) build $(EXE.docker) cp Dockerfile $(EXE.docker) cp README.md docker: docker.build docker.rm: @$(TRACE.target) $(EXE.docker) rmi docker.dev: @$(TRACE.target) 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: @$(TRACE.target) docker push owasp/o-saft:latest .PHONY: pl cgi man pod html wiki standalone tar tmptar tmptgz cleantar cleantmp help .PHONY: docker docker.rm docker.dev docker.push clean.gen: @$(TRACE.target) rm -rf $(ALL.gen) $(GEN.inst) clean.tmp: @$(TRACE.target) rm -rf $(TMP.dir) clean.tar: @$(TRACE.target) rm -rf $(GEN.tgz) clean.tgz: clean.tar clean.docker: docker.rm # avoid matching implicit rule help% in some of following targets $(OSD.dir)/help.txt: @$(TRACE.target) #_____________________________________________________________________________ #_______________________________________________ targets for generated files__| # targets for generation $(TMP.dir)/Net $(TMP.dir)/OSaft $(TMP.dir)/OSaft/Doc $(TMP.dir)/$(SRC.contrib.dir) $(TMP.dir)/$(TEST.dir): @$(TRACE.target) mkdir -p $@ # cp fails if SRC.pl is read-only, hence we remove it; it is generated anyway $(SRC.pl): $(DEV.pl) @$(TRACE.target) rm -f $@ cp $< $@ # generation fails if GEN.src is read-only, hence we remove it; it is generated anyway $(GEN.src): $(EXE.single) $(SRC.pl) $(ALL.pm) @$(TRACE.target) @rm -rf $@ $(EXE.single) --s > $@ @chmod 555 $@ $(GEN.man): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) $(GEN.pod) @$(TRACE.target) $(SRC.pl) --no-rc --no-warning --help=gen-man > $@ $(GEN.pod): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TRACE.target) $(SRC.pl) --no-rc --no-warning --help=gen-pod > $@ $(GEN.text): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TRACE.target) $(SRC.pl) --no-rc --no-warning --help > $@ $(GEN.wiki): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TRACE.target) $(SRC.pl) --no-rc --no-warning --help=gen-wiki > $@ $(GEN.html): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TRACE.target) $(SRC.pl) --no-rc --no-warning --help=gen-html > $@ $(GEN.cgi.html): $(SRC.pl) $(OSD.pm) $(USR.pm) $(SRC.txt) @$(TRACE.target) $(SRC.pl) --no-rc --no-warning --help=gen-cgi > $@ $(GEN.inst): $(SRC.inst) Makefile @$(TRACE.target) $(EXE.install) $(SRC.inst) > $@ chmod +x $@ $(GEN.tgz)--to-noisy: $(ALL.src) @$(TRACE.target) @grep -q '$(_INST.is_edit)' $? \ && echo "file(s) being edited or with invalid SID" \ || echo tar zcf $@ $^ # generating file containing our messages uses target from t/Makefile.warnings # hence make is called recursively for this special file # TODO: this is a dirty hack, because no Makefiles from t/ should be used here # most files could also be generated with: $(SRC.pl) --gen-docs # SEE GNU Make:Pattern Rule $(DOC.dir)/$(SRC.pl).%warnings: $(SRC.pl) @$(TRACE.target) $(MAKE_COMMAND) -s warnings-info > $@ $(DOC.dir)/$(SRC.pl).%: $(SRC.pl) @$(TRACE.target) $(SRC.pl) --no-rc $* > $@ # use libreoffice to generate PDF from .odg # unfortunately libreoffice has no option to specify the name of the output, # hence we need to use its --outdir option instead of make's $@ # ancient libreoffice (before 5.0) may also need following option: # -env:UserInstallation=file:///tmp/dummy${USER} # FIXME: (11/2021) libreoffice --headless generates a file slighly different # compared to the file generated interactively (reason yet unknown) # we keep the generation here, to avoid missing files $(DOC.dir)/%.pdf: %.odg @$(TRACE.target) $(EXE.office) --headless --nologo --nolockcheck --norestore --convert-to pdf:draw_pdf_Export --outdir $(DOC.dir)/ $^ # 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) @$(TRACE.target) @grep -q '$(_INST.is_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) $(GEN.tags) $(GEN.inst) @$(TRACE.target) cd .. && tar zcf $(PWD)/$@ $(ALL.tgz) $(GEN.tmptgz): $(ALL.src) $(GEN.tags) @$(TRACE.target) tar zcf $@ $^ #_____________________________________________________________________________ #__________________________________________________________ verbose targets __| # verbose/trace command # TRACE.target is the command to be used to print the target's name # it is epmty by default # TRACE.target 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: # TRACE.target = echo "\# --Target: $@--" # TRACE.target = echo "\# --Target: $@: newer dependencies: $? --" # TRACE.target = echo "\# --Target: $@: all dependencies: $^ --" # verbose targets # NOTE: need at least one command for target execution %-v: TRACE.target = echo "\# $@: $?" %-v: % @$(EXE.dummy) %-vv: TRACE.target = echo "\# $@: $^" %-vv: % @$(EXE.dummy) # the traditional way, when target-dependent variables do not work #%-v: # @$(MAKE) $(MFLAGS) $(MAKEOVERRIDES) $* 'TRACE.target=echo \# $$@: $$?' # #%-vv: # @$(MAKE) $(MFLAGS) $(MAKEOVERRIDES) $* 'TRACE.target=echo \# $$@: $$^' #_____________________________________________________________________________ #_____________________________________________ targets for testing and help __| include $(TEST.dir)/Makefile # Note that $(TEST.dir)/Makefile includes all other Makefile.* there O-Saft-22.11.22/Net/000077500000000000000000000000001433765727300136015ustar00rootroot00000000000000O-Saft-22.11.22/Net/SSLhello.pm000077500000000000000000015271601433765727300156430ustar00rootroot00000000000000#!/usr/bin/perl -w ## PACKAGE { # Filename : SSLhello.pm #!############################################################################# #!# Copyright (c) 2022, 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: TLSv13: Decrypt and parse also the encrypted extensions. ## 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) ## no critic qw(Subroutines::ProhibitExcessComplexity ControlStructures::ProhibitDeepNests Subroutines::ProhibitManyArgs) # yes, parts of this is is complex ## no critic qw(RegularExpressions::RequireExtendedFormatting) # because we use /x as needed for human readability package Net::SSLhello; use strict; use warnings; BEGIN { # section required only when called as: Net/SSLhello.pm or ./SSLhello.pm my $_me = $0; $_me =~ s#.*[/\\]##; if ("SSLhello.pm" eq $_me) { my $_path = $0; $_path =~ s#[/\\][^/\\]*$##; unshift(@INC, ".", "lib"); unshift(@INC, $ENV{PWD}, "$ENV{PWD}/lib") if (defined $ENV{'PWD'}); unshift(@INC, "bin"); if ($_path !~ m#^[.]/*$#) { # . already added unshift(@INC, "$_path", "$_path/lib") if ($_me ne $_path); } unshift(@INC, "../") if ($0 =~ m#^(?:[.]/)?SSLhello.pm#); # call in Net/ } } our $VERSION = "22.06.22"; my $SID_sslhelo= "@(#) SSLhello.pm 1.53 22/07/05 00:00:34", my $SSLHELLO = "O-Saft::Net::SSLhello"; use Socket; ## TBD will be deleted soon TBD ### use IO::Socket::INET; #require IO::Select if ($Net::SSLhello::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->) use OSaft::Text qw(%STR); use osaft; # main parameters, lists and functions that are used by o-saft and SSLhello ######################################################## public documentation # =pod =head1 NAME Net::SSLhello - Perl module 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 independently 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 analyses 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 obsolete, by their 2-octet-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 analyse SSL/TLS ciphers of servers that verify client certificates without any need to provide a certificate (which 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 %resultHash; # Hash that collects results our %extensions_params_hash; # hasgh that (temporarily) defines parameters for an extension our $my_error = ""; # global store for error message use Exporter qw(import); use base qw(Exporter); 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; 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: customised 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 $Net::SSLhello::extensions_by_prot = \%{$cfg{extensions_by_prot}}; # get the list of all extensions used by protocol, SSLv2 does not support any extensions by design $Net::SSLhello::check_extensions = [ qw(supported_groups) ]; # List of extensions to be checked for all supported params $Net::SSLhello::extensions_max_values = 50; # max retries to check for additional variables of extensions. Acts as watchdog protecting against endless loops while checking for extensions 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 standardised (udp) 'DTLSfamily' => 0xFE00, # DTLS1.FF, no defined PROTOCOL, for internal usea only (udp) 'DTLSv1' => 0xFEFF, # DTLS1.0 (udp) 'DTLSv11' => 0xFEFE, # DTLS1.1 (udp), has NEVER been used 'DTLSv12' => 0xFEFD, # DTLS1.2 (udp) 'DTLSv13' => 0xFEFC, # DTLS1.3 (udp), not YET specified '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 ); # reverse hash of PROTOCOL_VERSION my %PROTOCOL_NAME_BY_HEX = reverse %PROTOCOL_VERSION; # 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])], 109 => [qw(missing_extension Y [RFC8446])], 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])], 116 => [qw(certificate_required Y [RFC8446])], 120 => [qw(no_application_protocol Y [RFC7301][RFC8447])], ); 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 RECOMMENDED Reference #my %TLS_SUPPORTED_GROUPS = ( my %ECC_NAMED_CURVE = ( 0 => [qw(Reverved_0 0 N N [RFC8447])], 1 => [qw(sect163k1 163 Y N [RFC4492])], 2 => [qw(sect163r1 163 Y N [RFC4492])], 3 => [qw(sect163r2 163 Y N [RFC4492])], 4 => [qw(sect193r1 193 Y N [RFC4492])], 5 => [qw(sect193r2 193 Y N [RFC4492])], 6 => [qw(sect233k1 233 Y N [RFC4492])], 7 => [qw(sect233r1 233 Y N [RFC4492])], 8 => [qw(sect239k1 239 Y N [RFC4492])], 9 => [qw(sect283k1 283 Y N [RFC4492])], 10 => [qw(sect283r1 283 Y N [RFC4492])], 11 => [qw(sect409k1 409 Y N [RFC4492])], 12 => [qw(sect409r1 409 Y N [RFC4492])], 13 => [qw(sect571k1 571 Y N [RFC4492])], 14 => [qw(sect571r1 571 Y N [RFC4492])], 15 => [qw(secp160k1 160 Y N [RFC4492])], 16 => [qw(secp160r1 160 Y N [RFC4492])], 17 => [qw(secp160r2 160 Y N [RFC4492])], 18 => [qw(secp192k1 192 Y N [RFC4492])], 19 => [qw(secp192r1 192 Y N [RFC4492])], 20 => [qw(secp224k1 224 Y N [RFC4492])], 21 => [qw(secp224r1 224 Y N [RFC4492])], 22 => [qw(secp256k1 256 Y N [RFC4492])], 23 => [qw(secp256r1 256 Y Y [RFC4492])], 24 => [qw(secp384r1 384 Y Y [RFC4492])], 25 => [qw(secp521r1 521 Y N [RFC4492])], 26 => [qw(brainpoolP256r1 256 Y Y [RFC7027])], 27 => [qw(brainpoolP384r1 384 Y Y [RFC7027])], 28 => [qw(brainpoolP512r1 512 Y Y [RFC7027])], 29 => [qw(x25519 255 Y Y [RFC8446][RFC8422])], 30 => [qw(x448 448 Y Y [RFC8446][RFC8422])], 31 => [qw(brainpoolP256r1tls13 256 Y N [RFC8734])], 32 => [qw(brainpoolP384r1tls13 384 Y N [RFC8734])], 33 => [qw(brainpoolP512r1tls13 512 Y N [RFC8734])], 34 => [qw(GC256A 256 Y N [draft-smyshlyaev-tls12-gost-suites])], 35 => [qw(GC256B 256 Y N [draft-smyshlyaev-tls12-gost-suites])], 36 => [qw(GC256C 256 Y N [draft-smyshlyaev-tls12-gost-suites])], 37 => [qw(GC256D 256 Y N [draft-smyshlyaev-tls12-gost-suites])], 38 => [qw(GC512A 512 Y N [draft-smyshlyaev-tls12-gost-suites])], 39 => [qw(GC512B 512 Y N [draft-smyshlyaev-tls12-gost-suites])], 40 => [qw(GC512C 512 Y N [draft-smyshlyaev-tls12-gost-suites])], 41 => [qw(curveSM2 256 N N [draft-yang-tls-tls13-sm-suites])], # 42-255 Unassigned 256 => [qw(ffdhe2048 2048 Y N [RFC7919])], 257 => [qw(ffdhe3072 3072 Y N [RFC7919])], 258 => [qw(ffdhe4096 4096 Y N [RFC7919])], 259 => [qw(ffdhe6144 6144 Y N [RFC7919])], 260 => [qw(ffdhe8192 8192 Y N [RFC7919])], # 261-507 Unassigned, 508 => [qw(Private_508 NN Y N [RFC7919])], 509 => [qw(Private_509 NN Y N [RFC7919])], 510 => [qw(Private_510 NN Y N [RFC7919])], 511 => [qw(Private_511 NN Y N [RFC7919])], # 512-2569 Unassigned , 2570 => [qw(Reserved_2570 NN Y N [RFC8701])], # 2571-6681 Unassigned , 6682 => [qw(Reserved_6682 NN Y N [RFC8701])], # 6683-10793 Unassigned , 10794 => [qw(Reserved_10794 NN Y N [RFC8701])], #10795-14905 Unassigned , 14906 => [qw(Reserved_14906 NN Y N [RFC8701])], #14907-19017 Unassigned , 19018 => [qw(Reserved_19018 NN Y N [RFC8701])], #19019-23129 Unassigned , 23130 => [qw(Reserved_23130 NN Y N [RFC8701])], #23131-27241 Unassigned , 27242 => [qw(Reserved_27242 NN Y N [RFC8701])], #27243-31353 Unassigned , 31354 => [qw(Reserved_31354 NN Y N [RFC8701])], #31355-35465 Unassigned , 35466 => [qw(Reserved_35466 NN Y N [RFC8701])], #35467-39577 Unassigned , 39578 => [qw(Reserved_39578 NN Y N [RFC8701])], #39579-43689 Unassigned , 43690 => [qw(Reserved_43690 NN Y N [RFC8701])], #43691-47801 Unassigned , 47802 => [qw(Reserved_47802 NN Y N [RFC8701])], #47803-51913 Unassigned , 51914 => [qw(Reserved_51914 NN Y N [RFC8701])], #51915-56025 Unassigned , 56026 => [qw(Reserved_56026 NN Y N [RFC8701])], #56027-60137 Unassigned , 60138 => [qw(Reserved_60138 NN Y N [RFC8701])], #60139-64249 Unassigned , 64250 => [qw(Reserved_64250 NN Y N [RFC8701])], #64251-65023 Unassigned , #65024-65279 Reserved_for_Private_Use NN Y N [RFC8422], #65280 Unassigned 65281 => [qw(arbitrary_explicit_prime_curves -variable- Y N [RFC8422])], 65282 => [qw(arbitrary_explicit_char2_curves -variable- Y N [RFC8422])], #65283-65535 Unassigned , ); ################################################################################## # List of Functions ################################################################################## sub checkSSLciphers ($$$@); sub printCipherStringArray ($$$$$@); sub _timedOut; sub _error; sub _compileAllBytes ($$$$$$;$$); sub _decode_val ($$$;$$$$$$); sub _sprintf_hex_val ($$;$); # TODO: import/export of the trace-function from o-saft-dbx.pm; # this is a workaround to get trace running using parameter '$Net::SSLhello::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 ($Net::SSLhello::traceTIME <= 0) { return ""; } return sprintf("[%02s:%02s:%02s] ", (localtime)[2,1,0]) } sub _trace($) { my @messages = @_; local $\ = ""; print "#" . _y_ts() . $SSLHELLO . "::" . $messages[0] if ($Net::SSLhello::trace > 0); return } sub _trace0($) { my @messages = @_; local $\ = ""; print "#" . _y_ts() . $SSLHELLO . "::" if ($Net::SSLhello::trace > 0); return } sub _trace1($) { my @messages = @_; local $\ = ""; print "# " . _y_ts() . $SSLHELLO . "::" . join(" ", @messages) if ($Net::SSLhello::trace > 1); return } sub _trace2($) { my @messages = @_; local $\ = ""; print "# --> " . _y_ts() . $SSLHELLO . "::" . join(" ", @messages) if ($Net::SSLhello::trace > 2); return } sub _trace3($) { my @messages = @_; local $\ = ""; print "# --> " . _y_ts() . $SSLHELLO . "::" . join(" ", @messages) if ($Net::SSLhello::trace ==3); return } sub _trace4($) { my @messages = @_; local $\ = ""; print "# ---> " . _y_ts() . $SSLHELLO . "::" . join(" ", @messages) if ($Net::SSLhello::trace > 3); return } sub _trace5($) { my @messages = @_; local $\ = ""; print "# ---> " . _y_ts() . $SSLHELLO . "::" . join(" ", @messages) if ($Net::SSLhello::trace > 4); return } sub _trace_($) { my @messages = @_; local $\ = ""; print " " . join(" ", @messages) if ($Net::SSLhello::trace > 0); return } sub _trace1_($){ my @messages = @_; local $\ = ""; print " " . join(" ", @messages) if ($Net::SSLhello::trace > 1); return } sub _trace2_($){ my @messages = @_; local $\ = ""; print join(" ", @messages) if ($Net::SSLhello::trace > 2); return } sub _trace3_($){ my @messages = @_; local $\ = ""; print join(" ", @messages) if ($Net::SSLhello::trace ==3); return } sub _trace4_($){ my @messages = @_; local $\ = ""; print join(" ", @messages) if ($Net::SSLhello::trace > 3); return } sub _trace5_($){ my @messages = @_; local $\ = ""; print join(" ", @messages) if ($Net::SSLhello::trace > 4); 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"; #} # trace output for known and unknown formts sub _sprintf_hex_val ($$;$) { my $_format = shift(@_); my $_val_ref = shift(@_); my $_indent = shift(@_) || 0; my $_hex_str = ""; my $_format_string = $_format || "-- undef --"; _trace5_(" " x $_indent . "# ---> _sprintf_hex_val: \$_format: '$_format_string' -> "); if (! defined ($_format)) { # guess format, if not defined if (! defined ($_val_ref)) { _trace5 ("-- undefined value --\n"); return ("-- undefined value --"); } _trace5_ ("if (\$\$_val_ref =~ /\^\\d+\$/); defined (\$\$_val_ref) = " . defined ($$_val_ref) ." -> "); if (! defined ($$_val_ref)) { _trace5_ ("'' (empty value)\n"); return (""); } if ($$_val_ref =~ /^\d+$/) { # number _trace5_ ("number (auto) -> "); if ($$_val_ref <= 0xFF) { $_format = "%02X"; } elsif ($$_val_ref <= 0xFFFF) { $_format = "%04X"; } elsif ($$_val_ref <= 0xFFFFFFFF) { $_format = "%08X"; } else { # number is too big $_format = "%016X"; } } else { # no number $_format = ""; } } if ($_format ne "") { _trace5_ ("formated string: "); $_hex_str = sprintf($_format, $$_val_ref); $_hex_str =~ s/[0-9A-Fa-f]{2}/"$& "/eigx; # add a space after 2 Hex vals } else { # unformated string _trace5_ ("val: unformated string: "); $_hex_str = sprintf("%*v2.2x", ' ', $$_val_ref); } $_hex_str =~ s/\s*$//; # remove white spaces at line ends $_hex_str =~ s/((?:[0-9A-Fa-f]{2}\s){16})(?=[0-9A-Fa-f]{2})/"$&\n"." " x $_indent/eigx; # addd a colon and a space between value and descriptiond a new line each 16 HEX-octetts if last octett has not been reached _trace5_ ("$_hex_str\n"); return ($_hex_str); } sub _sprintf_val_description ($$;$$) { my $_def_hash_ref = shift(@_); my $_val_ref = shift(@_); my $_indent = shift(@_) || 0; my $_descr_sep = shift(@_) || " "; my $_descr_str = ""; my $_text_sep = ": "; # add a colon and a space between value and description if ($Net::SSLhello::trace >= 5) { # ? value if TRUE : value if FALSE my $_val_ref_print = (defined ($_val_ref)) ? ref ($_val_ref) . ": " . _sprintf_hex_val (undef, $_val_ref, $_indent) : "-- undef --"; my $_def_hash_ref_print = (defined ($_def_hash_ref)) ? ref ($_def_hash_ref) : "-- undef --"; if ( (defined ($_def_hash_ref)) && (ref ($_def_hash_ref) eq "HASH") ) { $_def_hash_ref_print .= ": ->{FORMAT}: "; $_def_hash_ref_print .= (defined ($_def_hash_ref->{FORMAT})) ? "defined" : "-- undef --"; if (defined($_val_ref)) { $_def_hash_ref_print .= ", ->{$$_val_ref}: "; $_def_hash_ref_print .= (defined ($_def_hash_ref->{$$_val_ref})) ? "defined" : "-- undef --"; } } print " " x $_indent . "# ---> _sprintf_val_description: (\$_val_ref = <<$_val_ref_print>>, \$_def_hash_ref = <<$_def_hash_ref_print>>)\n"; } return ("") if (! defined($_def_hash_ref)); return ("") if (! defined($_val_ref)); if (ref ($_def_hash_ref) eq "HASH") { # $_def_hash_ref is a REF to a HASH # _trace5_ (" " x ($_indent + 3) . "# ---> _sprintf_val_description: \$_def_hash_ref is a HASH\n"); if (defined ($_def_hash_ref->{FORMAT})) { # _trace5_ (" " x ($_indent + 3) . "# ---> _sprintf_val_description: \$_def_hash_ref->{FORMAT} is defined\n"); if (defined ($_def_hash_ref->{$$_val_ref})) { # _trace5_ (" " x ($_indent + 3) . "# ---> _sprintf_val_description: \$_def_hash_ref->{$$_val_ref} is defined\n"); if (ref ($_def_hash_ref->{FORMAT}) eq "ARRAY") { _trace5_ (" " x $_indent . "# ---> add ".(@{$_def_hash_ref->{FORMAT}})." description(s)\n"); $_descr_str .= $_text_sep; # add a colon and a space between value and description(s) for (my $_j = 0; $_j < (@{$_def_hash_ref->{FORMAT}}); $_j++) { # all elements of the description array for $$_val_ref $_descr_str .= $_descr_sep if ($_j >= 1); _trace5_ (" " x $_indent . "# ---> \$_descr_str .= sprintf \($_def_hash_ref->{FORMAT}[$_j], $_def_hash_ref->{$$_val_ref}[$_j]\)\n"); $_descr_str .= sprintf ($_def_hash_ref->{FORMAT}[$_j], $_def_hash_ref->{$$_val_ref}[$_j]) if (defined ($_def_hash_ref->{$$_val_ref}[$_j])); } } } } } elsif (ref ($_def_hash_ref) eq "SCALAR") { # $_def_hash_ref is a REF to a SCALAR, e.g. text $_descr_str .= $_text_sep.$$_def_hash_ref; } elsif (ref (\$_def_hash_ref) eq "SCALAR") { # $_def_hash_ref is not a REF but a SCALAR, e.g. text $_descr_str .= $_text_sep.$_def_hash_ref; } _trace5_(" " x ($_indent). "# ---> _sprintf_val_description: \$_descr_str = '$_descr_str'\n"); return ($_descr_str); } sub _decode_val ($$$;$$$$$$) { #? decodes and (s)sprints values and up to double nested arrays (= arrays of arrays of arrays) #? prints and adds warnings to the output if the variable is even more deeply nestested or in an unsupported format my $_format = shift(@_); # reference to a sprintf-format to print the value, or "" for unformatted strings or undef for autoformat for unknown formats (best effort) my $_val_ref = shift(@_); # reference to a scalar or an up to double nested array (= array of array of array) my $_def_hash_ref = shift(@_); # definition to decode the value: might be a ref to a hash, a ref to this ref or a simple scalara or undef my $_first_indent = shift(@_) || 0; # optional: ident in the first line my $_next_indent = shift(@_) || 0; # optional: ident from the second line onwards my $_text_sep = shift(@_) || ":\n". " " x $_next_indent; # optional: add a colon, a new line and an indent between section headline (e.g. 'sequence') and value my $_sub_sep = shift(@_) || ", "; # optional: sub seperators of elements or arrays my $_sub_sub_sep = shift(@_) || " | "; # optional: sub-sub seperators of array elements or nested arrays (arrays of arrays) my $_sub3_sep = shift(@_) || " / "; # optional: sub³ seperators of nested array elements (or error messages for more deeply nested attays my $_sub_lines = 0; my $_sub_sub_lines = 0; my $_sub3_lines = 0; my $_decode_str = ""; my $_format_print = $_format; $_format_print = "-- undef --" if (! defined ($_format)); _trace5_ (" " x $_next_indent . "# _decode_val (\$_format: '$_format_print', \$val_ref, \$_def_hash_ref, \$_first_indent: '$_first_indent', \$_next_indent: '$_next_indent', \$_text_sep: '$_text_sep', \$_sub_sep: '$_sub_sep', \$_sub_sub_sep: '$_sub_sub_sep', \$_sub3_sep: '$_sub3_sep ')\n"); $_decode_str = " " x $_first_indent; if (defined ($_def_hash_ref)) { _trace5_ (" " x ($_next_indent + 2) ."# --->> def_hash-ref-Type: ".ref($_def_hash_ref)."<<\n"); _trace5_ (" " x ($_next_indent + 2) ."# --->> def_hash-ref-ref-Type: ".ref($$_def_hash_ref)."<<\n") if (ref ($_def_hash_ref) eq 'REF'); _trace5_ (" " x ($_next_indent + 2) ."# --->> def_hash-val-Type: ".ref(\$_def_hash_ref)."<<\n"); $_def_hash_ref = $$_def_hash_ref if (ref ($_def_hash_ref) eq 'REF'); # reference to a reference => reference if (ref ($_def_hash_ref) eq "HASH") { # $_def_hash_ref is a REF to a HASH $_decode_str .= $_def_hash_ref->{TEXT}.$_text_sep if (defined ($_def_hash_ref->{TEXT})); } if (! defined($_val_ref)) { # check for (simple) SCALAR info if any value define (e.g. section headline, e.g. 'sequence' if (ref ($_def_hash_ref) eq "SCALAR") { # $_def_hash_ref is a REF to a SCALAR, e.g. text $_decode_str .= $$_def_hash_ref.$_text_sep; } elsif (ref (\$_def_hash_ref) eq "SCALAR") { # $_def_hash_ref is not a REF but a SCALAR, e.g. text $_decode_str .= $_def_hash_ref.$_text_sep; } } _trace5_ (" " x ($_next_indent + 2) . "# \$_decode_str: $_decode_str\n"); } return ($_decode_str) if (! defined($_val_ref)); _trace5_ (" " x ($_next_indent + 2) ."# ---> val-Type: ".ref($_val_ref)."<\n"); _trace5_ (" " x ($_next_indent + 2) ."# ---> val-ref-Type: ".ref($$_val_ref)."<\n") if (ref ($_val_ref) eq 'REF'); $_val_ref = $$_val_ref if (ref ($_val_ref) eq 'REF'); # reference to a reference => reference if (ref ($_val_ref) eq 'SCALAR') { # value $_decode_str .= _sprintf_hex_val ($_format, $_val_ref, $_next_indent + 2); $_decode_str .= _sprintf_val_description ($_def_hash_ref, $_val_ref, $_next_indent + 2); } elsif (ref ($_val_ref) eq 'ARRAY') { # array $_decode_str .= "[ "; $_next_indent += 2; if ( (@{$_val_ref}) >= 1) { foreach my $ele (@{$_val_ref}) { _trace5_ (" " x ($_next_indent + 2)."# ---|> val-ref-Type (\$ele): ".ref(\$ele)."<|\n"); $_decode_str .= $_sub_sep if ($_sub_lines++ > 0); # add a sup-sep an a new line with an indent für next nested array; if (ref (\$ele) eq 'SCALAR') { # values of the array $_decode_str .= _sprintf_hex_val ($_format, \$ele, $_next_indent + 2); $_decode_str .= _sprintf_val_description ($_def_hash_ref, \$ele, $_next_indent + 2); } elsif (ref ($ele) eq 'ARRAY') { # nested array, e.g. sequence $_decode_str .= "[ "; $_next_indent += 2; if ( (@{$ele}) >= 1) { $_sub_sub_lines = 0; # reset sub_sub_lines foreach my $ele_ele (@{$ele}) { _trace5_ (" " x ($_next_indent + 2)."# ---||> val-ref-Type (\$ele_ele): ".ref(\$ele_ele)."<||\n"); $_decode_str .= $_sub_sub_sep if ($_sub_sub_lines++ > 0); # add a sub-sub-separator if not the first element if (ref (\$ele_ele) eq 'SCALAR') { # values of the nested array (array of arrays) $_decode_str .= _sprintf_hex_val ($_format, \$ele_ele, $_next_indent + 2); $_decode_str .= _sprintf_val_description ($_def_hash_ref, \$ele_ele, $_next_indent + 2); } elsif (ref ($ele_ele) eq 'ARRAY') { # doulble nested array (array of array of arrays) $_decode_str .= "[ "; $_next_indent += 2; if ( (@{$ele_ele}) >= 1) { $_sub3_lines = 0; # reset sub_sub_lines foreach my $ele3 (@{$ele_ele}) { _trace5_ (" " x ($_next_indent + 2)."# --|||> val-ref-Type (\$ele3): ".ref(\$ele3)."<|||\n"); $_decode_str .= $_sub3_sep if ($_sub3_lines++ > 0); # add a sub3-separator if not the first element if (ref (\$ele3) eq 'SCALAR') { # values of the double nested array (array of array of arrays) $_decode_str .= _sprintf_hex_val ($_format, \$ele3, $_next_indent + 2); $_decode_str .= _sprintf_val_description ($_def_hash_ref, \$ele3, $_next_indent + 2); } else { # deeply nested array is not supported _trace2_ (" " x ($_next_indent + 2) ."# --|||> **WARNING: SSLhello::_decode_val: try to print unsupported or deeply nested val type (\$ele3): '" . ref(\$ele3) ."/". ref($ele3) ."' <|||\n"); carp ("**WARNING: SSLhello::_decode_val: try to print unsupported or deeply nested val type (\$ele3): '" . ref(\$ele3) ."/". ref($ele3) ."'\n"); $_decode_str .= "[ --- unsupported or deeply nested val type (\$ele3): '". ref(\$ele3) ."/". ref($ele3) ."' --- ]"; } # ref (\$ele3) } # foreach $ele3 } $_decode_str .= " ]"; $_next_indent -= 2; } else { # unsupported val type of $ele_ele _trace2_ (" " x ($_next_indent + 2) ."**WARNING: SSLhello::_decode_val: try to print unsupported val-refref-Type (\$ele_ele): ".ref($ele_ele)."<\n"); carp ("**WARNING: SSLhello::_decode_val: try to print unsupported val type (\$ele_ele): '" . ref(\$ele_ele) ."/". ref($ele_ele) ."'\n"); $_decode_str .= "[ --- unsupported val type (\$ele_ele): '". ref(\$ele_ele) ."/". ref($ele_ele) ."' --- ]"; } # ref (\$ele_ele) } # foreach $ele_ele } $_decode_str .= " ]"; $_next_indent -= 2; } else { # unsupported val type of $ele _trace2_ (" " x ($_next_indent + 2) ."**WARNING: SSLhello::_decode_val: try to print unsupported val-refref-Type (\$ele): ".ref($ele)."<\n"); carp ("**WARNING: SSLhello::_decode_val: try to print unsupported val type (\$ele): '" . ref(\$ele) ."/". ref($ele) . "'\n"); $_decode_str .= "[ --- unsupported val type (\$ele_ele): '". ref(\$ele) ."/". ref($ele) ."' --- ]"; } # ref (\$ele) } # foreach $ele } $_decode_str .= " ]"; $_next_indent -= 2; } else { # unsupported val type of $$_val_ref _trace2_ (" " x ($_next_indent + 2) ."**WARNING: SSLhello::_decode_val: try to print unsupported val-refref-Type: " . ref($_val_ref)."<\n"); carp ("**WARNING: SSLhello::_decode_val: try to print unsupported val type: '" . ref(\$_val_ref) ."/". ref($_val_ref) ."'\n"); $_decode_str .= "[ --- unsupported val type: '". ref(\$_val_ref) ."/". ref($_val_ref) ."' --- ]"; } # if ref ($_val_ref) # $_next_indent -= 3; _trace5_ (" " x $_next_indent . "# ---> _decode_val: \$_decode_str: '$_decode_str'\n"); return ($_decode_str); } # end of _decode_val (); ################################################################################### 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_CBC_WITH_MD5 DES-CBC-MD5)], '0x02060140'=> [qw(DES_CBC_WITH_SHA DES-CBC-SHA)], '0x02FF0800'=> [qw(DES_64_CFB64_WITH_MD5_1 DES-CFB-M1)], '0x02050080'=> [qw(IDEA_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(DH_anon_WITH_3DES_EDE_CBC_SHA ADH-DES-CBC3-SHA)], '0x03000019'=> [qw(DH_anon_EXPORT_WITH_DES40_CBC_SHA EXP-ADH-DES-CBC-SHA)], '0x0300001A'=> [qw(DH_anon_WITH_DES_CBC_SHA ADH-DES-CBC-SHA)], '0x03000018'=> [qw(DH_anon_WITH_RC4_128_MD5 ADH-RC4-MD5)], '0x03000017'=> [qw(DH_anon_EXPORT_WITH_RC4_40_MD5 EXP-ADH-RC4-MD5)], '0x0300000D'=> [qw(DH_DSS_WITH_3DES_EDE_CBC_SHA DH-DSS-DES-CBC3-SHA)], '0x0300000B'=> [qw(DH_DSS_EXPORT_WITH_DES40_CBC_SHA EXP-DH-DSS-DES-CBC-SHA)], '0x0300000C'=> [qw(DH_DSS_WITH_DES_CBC_SHA DH-DSS-DES-CBC-SHA)], '0x03000010'=> [qw(DH_RSA_WITH_3DES_EDE_CBC_SHA DH-RSA-DES-CBC3-SHA)], '0x0300000E'=> [qw(DH_RSA_EXPORT_WITH_DES40_CBC_SHA EXP-DH-RSA-DES-CBC-SHA)], '0x0300000F'=> [qw(DH_RSA_WITH_DES_CBC_SHA DH-RSA-DES-CBC-SHA)], '0x03000013'=> [qw(EDH_DSS_WITH_3DES_EDE_CBC_SHA EDH-DSS-DES-CBC3-SHA)], '0x03000011'=> [qw(EDH_DSS_EXPORT_WITH_DES40_CBC_SHA EXP-EDH-DSS-DES-CBC-SHA)], '0x03000012'=> [qw(EDH_DSS_WITH_DES_CBC_SHA EDH-DSS-DES-CBC-SHA)], '0x03000016'=> [qw(EDH_RSA_WITH_3DES_EDE_CBC_SHA EDH-RSA-DES-CBC3-SHA)], '0x03000014'=> [qw(EDH_RSA_EXPORT_WITH_DES40_CBC_SHA EXP-EDH-RSA-DES-CBC-SHA)], '0x03000015'=> [qw(EDH_RSA_WITH_DES_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/KRB5_WITH_DES_CBC_SHA FZA-RC4-SHA/KRB5-DES-SHA)], '0x03000023'=> [qw(KRB5_WITH_3DES_EDE_CBC_MD5 KRB5-DES-CBC3-MD5)], '0x0300001F'=> [qw(KRB5_WITH_3DES_EDE_CBC_SHA KRB5-DES-CBC3-SHA)], '0x03000029'=> [qw(KRB5_EXPORT_WITH_DES_CBC_40_MD5 EXP-KRB5-DES-CBC-MD5)], '0x03000026'=> [qw(KRB5_EXPORT_WITH_DES_CBC_40_SHA EXP-KRB5-DES-CBC-SHA)], '0x03000022'=> [qw(KRB5_WITH_DES_CBC_MD5 KRB5-DES-CBC-MD5)], '0x0300001E'=> [qw(KRB5_WITH_DES_CBC_SHA KRB5-DES-CBC-SHA)], '0x03000025'=> [qw(KRB5_WITH_IDEA_CBC_MD5 KRB5-IDEA-CBC-MD5)], '0x03000021'=> [qw(KRB5_WITH_IDEA_CBC_SHA KRB5-IDEA-CBC-SHA)], '0x0300002A'=> [qw(KRB5_WITH_RC2_CBC_40_MD5 EXP-KRB5-RC2-CBC-MD5)], '0x03000027'=> [qw(KRB5_EXPORT_WITH_RC2_CBC_40_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_EXPORT_WITH_RC4_40_MD5 EXP-KRB5-RC4-MD5)], '0x03000028'=> [qw(KRB5_EXPORT_WITH_RC4_40_SHA EXP-KRB5-RC4-SHA)], '0x0300000A'=> [qw(RSA_WITH_3DES_EDE_CBC_SHA DES-CBC3-SHA)], '0x03000008'=> [qw(RSA_EXPORT_WITH_DES40_CBC_SHA EXP-DES-CBC-SHA)], '0x03000009'=> [qw(RSA_WITH_DES_CBC_SHA DES-CBC-SHA)], '0x03000007'=> [qw(RSA_WITH_IDEA_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_EXPORT_WITH_RC2_CBC_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_EXPORT_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(DH_anon_WITH_AES_128_GCM_SHA256 ADH-AES128-GCM-SHA256)], '0x03000034'=> [qw(DH_anon_WITH_AES_128_CBC_SHA ADH-AES128-SHA)], '0x0300006C'=> [qw(DH_anon_WITH_AES_128_CBC_SHA256 ADH-AES128-SHA256)], '0x030000A7'=> [qw(DH_anon_WITH_AES_256_GCM_SHA384 ADH-AES256-GCM-SHA384)], '0x0300003A'=> [qw(DH_anon_WITH_AES_256_CBC_SHA ADH-AES256-SHA)], '0x0300006D'=> [qw(DH_anon_WITH_AES_256_CBC_SHA256 ADH-AES256-SHA256)], '0x03000046'=> [qw(DH_anon_WITH_CAMELLIA_128_CBC_SHA ADH-CAMELLIA128-SHA)], '0x03000089'=> [qw(DH_anon_WITH_CAMELLIA_256_CBC_SHA ADH-CAMELLIA256-SHA)], '0x0300009B'=> [qw(DH_anon_WITH_SEED_CBC_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_CBC_SHA DHE-DSS-AES128-SHA)], '0x03000040'=> [qw(DHE_DSS_WITH_AES_128_CBC_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_CBC_SHA DHE-DSS-AES256-SHA)], '0x0300006A'=> [qw(DHE_DSS_WITH_AES_256_CBC_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_CBC_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_CBC_SHA DHE-RSA-AES128-SHA)], '0x03000067'=> [qw(DHE_RSA_WITH_AES_128_CBC_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_CBC_SHA DHE-RSA-AES256-SHA)], '0x0300006B'=> [qw(DHE_RSA_WITH_AES_256_CBC_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_CBC_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_CBC_SHA DH-DSS-AES128-SHA)], '0x0300003E'=> [qw(DH_DSS_WITH_AES_128_CBC_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_CBC_SHA DH-DSS-AES256-SHA)], '0x03000068'=> [qw(DH_DSS_WITH_AES_256_CBC_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_CBC_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_CBC_SHA DH-RSA-AES128-SHA)], '0x0300003F'=> [qw(DH_RSA_WITH_AES_128_CBC_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_CBC_SHA DH-RSA-AES256-SHA)], '0x03000069'=> [qw(DH_RSA_WITH_AES_256_CBC_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_CBC_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_CBC_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_CBC_SHA384 ECDHE-ECDSA-AES256-SHA384)], '0x0300C008'=> [qw(ECDHE_ECDSA_WITH_3DES_EDE_CBC_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_CBC_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_CBC_SHA384 ECDHE-RSA-AES256-SHA384)], '0x0300C012'=> [qw(ECDHE_RSA_WITH_3DES_EDE_CBC_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_CBC_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_CBC_SHA384 ECDH-ECDSA-AES256-SHA384)], '0x0300C003'=> [qw(ECDH_ECDSA_WITH_3DES_EDE_CBC_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_CBC_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_CBC_SHA384 ECDH-RSA-AES256-SHA384)], '0x0300C00D'=> [qw(ECDH_RSA_WITH_3DES_EDE_CBC_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_3DES_EDE_CBC_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_CBC_SHA AES128-SHA)], '0x0300003C'=> [qw(RSA_WITH_AES_128_CBC_SHA256 AES128-SHA256)], '0x0300009D'=> [qw(RSA_WITH_AES_256_GCM_SHA384 AES256-GCM-SHA384)], '0x03000035'=> [qw(RSA_WITH_AES_256_CBC_SHA AES256-SHA)], '0x0300003D'=> [qw(RSA_WITH_AES_256_CBC_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_CBC_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(DH_anon_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(DH_anon_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(DH_anon_DSS_WITH_CAMELLIA_128_GCM_SHA256 ADH-DSS-CAMELLIA128-GCM-SHA256)], '0x0300C085'=> [qw(DH_anon_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)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: TLS 1.3 ciphers (prefix TLS13 added) #!# added manually 20201106 #!# RFC8446 #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x03001301'=>[qw(TLS13_AES_128_GCM_SHA256 TLS13-AES-128-GCM-SHA256)], '0x03001302'=>[qw(TLS13_AES_256_GCM_SHA384 TLS13-AES-256-GCM-SHA384)], '0x03001303'=>[qw(TLS13_CHACHA20_POLY1305_SHA256 TLS13-CHACHA20-POLY1305-SHA256)], '0x03001304'=>[qw(TLS13_AES_128_CCM_SHA256 TLS13-AES-128-CCM-SHA256)], '0x03001305'=>[qw(TLS13_AES_128_CCM_8_SHA256 TLS13-AES-128-CCM-8-SHA256)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: some further TLS 1.3 ciphers (prefix TLS13 added) #!# added manually 20201106 #!# DRAFT yang-tls-tls13-sm-suites; OpenSSL-Names are expected (TBD: verify names later) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x030000C6'=>[qw(TLS13_SM4_GCM_SM3 TLS13-SM4-CGM)], '0x030000C7'=>[qw(TLS13_SM4_CCM_SM3 TLS13-SM4-CCM)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: DRAFT for GOST cipher suites (TLS 1.2 and TLS 1.3 (prefix TLS13 added) #!# added manually 20201109 #!# DRAFT draft-smyshlyaev-tls12-gost-suites; OpenSSL-Names are expected (TBD: verify names later) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300C100'=>[qw(GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC GOSTR341112-256-KUZNYECHIK-CTR-OMAC)], '0x0300C101'=>[qw(GOSTR341112_256_WITH_MAGMA_CTR_OMAC GOSTR341112-256-MAGMA-CTR-OMAC)], '0x0300C102'=>[qw(GOSTR341112_256_WITH_28147_CNT_IMIT GOSTR341112-256-28147-CNT-IMIT)], '0x0300C103'=>[qw(TLS13_GOSTR341112_256_WITH_KUZNYECHIK_MGM_L GOSTR341112-256-KUZNYECHIK-MGM-L)], '0x0300C104'=>[qw(TLS13_GOSTR341112_256_WITH_MAGMA_MGM_L GOSTR341112-256-MAGMA-MGM-L)], '0x0300C105'=>[qw(TLS13_GOSTR341112_256_WITH_KUZNYECHIK_MGM_S GOSTR341112-256-KUZNYECHIK-MGM-S)], '0x0300C106'=>[qw(TLS13_GOSTR341112_256_WITH_MAGMA_MGM_S GOSTR341112-256-MAGMA-MGM-S)], #!# Protocol: some further TLS 1.3 ciphers (prefix TLS13 added) #!# added manually 20201106 #!# DRAFT draft-camwinget-tls-ts13-macciphersuites; OpenSSL-Names are expected (TBD: verify names later) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300C4B4'=>[qw(TLS13_SHA256_SHA256 TLS13-SHA256-SHA256)], '0x0300C4B5'=>[qw(TLS13_SHA384_SHA384 TLS13-SHA384-SHA384)], #!#----------------------------------------+-------------+--------------------+ #!# Protocol: RFC8442 PSK cipher suites (TLS 1.2) #!# added manually 20201109 #!# RFC8442 OpenSSL-Names are expected (TBD: verify names later) #!#----------------------------------------+-------------+--------------------+ #!# cipher suite hex value => [ cipher_name1 cipher_name2 ], #!#----------------------------------------+-------------+--------------------+ '0x0300D001'=>[qw(ECDHE_PSK_WITH_AES_128_GCM_SHA256 ECDHE_PSK_WITH_AES_128_GCM_SHA256)], '0x0300D002'=>[qw(ECDHE_PSK_WITH_AES_256_GCM_SHA384 ECDHE_PSK_WITH_AES_256_GCM_SHA384)], '0x0300D003'=>[qw(ECDHE_PSK_WITH_AES_128_CCM_8_SHA256 ECDHE_PSK_WITH_AES_128_CCM_8_SHA256)], '0x0300D005'=>[qw(ECDHE_PSK_WITH_AES_128_CCM_SHA256 ECDHE_PSK_WITH_AES_128_CCM_SHA256)], #!#----------------------------------------+-------------+--------------------+ #!# and more .... #!#----------------------------------------+-------------+--------------------+ ); # 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_CBC_WITH_MD5 DES-CBC-MD5 SSL_CK_DES_64_CBC_WITH_MD5)], '0x02060140'=> [qw(DES_CBC_WITH_SHA DES-CBC-SHA)], '0x02FF0800'=> [qw(DES_64_CFB64_WITH_MD5_1 DES-CFB-M1)], '0x02050080'=> [qw(IDEA_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(DH_anon_WITH_DES_192_CBC_SHA ADH-DES-CBC3-SHA)], '0x03000019'=> [qw(DH_anon_EXPORT_WITH_DES40_CBC_SHA EXP-ADH-DES-CBC-SHA)], '0x0300001A'=> [qw(DH_anon_WITH_DES_CBC_SHA ADH-DES-CBC-SHA)], '0x03000018'=> [qw(DH_anon_WITH_RC4_128_MD5 ADH-RC4-MD5)], '0x03000017'=> [qw(DH_anon_WITH_RC4_40_MD5 EXP-ADH-RC4-MD5)], '0x0300000D'=> [qw(DH_DSS_WITH_3DES_EDE_CBC_SHA DH-DSS-DES-CBC3-SHA)], '0x0300000B'=> [qw(DH_DSS_EXPORT_WITH_DES40_CBC_SHA EXP-DH-DSS-DES-CBC-SHA)], '0x0300000C'=> [qw(DH_DSS_WITH_DES_CBC_SHA DH-DSS-DES-CBC-SHA)], '0x03000010'=> [qw(DH_RSA_WITH_3DES_EDE_CBC_SHA DH-RSA-DES-CBC3-SHA)], '0x0300000E'=> [qw(DH_RSA_EXPORT_WITH_DES40_CBC_SHA EXP-DH-RSA-DES-CBC-SHA)], '0x0300000F'=> [qw(DH_RSA_WITH_DES_CBC_SHA DH-RSA-DES-CBC-SHA)], '0x03000013'=> [qw(EDH_DSS_WITH_3DES_EDE_CBC_SHA EDH-DSS-DES-CBC3-SHA)], '0x03000011'=> [qw(EDH_DSS_EXPORT_WITH_DES40_CBC_SHA EXP-EDH-DSS-DES-CBC-SHA)], '0x03000012'=> [qw(EDH_DSS_WITH_DES_CBC_SHA EDH-DSS-DES-CBC-SHA)], '0x03000016'=> [qw(EDH_RSA_WITH_3DES_EDE_CBC_SHA EDH-RSA-DES-CBC3-SHA)], '0x03000014'=> [qw(EDH_RSA_EXPORT_WITH_DES40_CBC_SHA EXP-EDH-RSA-DES-CBC-SHA)], '0x03000015'=> [qw(EDH_RSA_WITH_DES_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_3DES_EDE_CBC_MD5 KRB5-DES-CBC3-MD5)], '0x0300001F'=> [qw(KRB5_WITH_3DES_EDE_CBC_SHA KRB5-DES-CBC3-SHA)], '0x03000029'=> [qw(KRB5_EXPORT_WITH_DES40_CBC_MD5 EXP-KRB5-DES-CBC-MD5)], '0x03000026'=> [qw(KRB5_EXPORT_WITH_DES40_CBC_SHA EXP-KRB5-DES-CBC-SHA)], '0x03000022'=> [qw(KRB5_WITH_DES_CBC_MD5 KRB5-DES-CBC-MD5)], '0x0300001E'=> [qw(KRB5_WITH_DES_CBC_SHA KRB5-DES-CBC-SHA)], '0x03000025'=> [qw(KRB5_WITH_IDEA_CBC_MD5 KRB5-IDEA-CBC-MD5)], '0x03000021'=> [qw(KRB5_WITH_IDEA_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_3DES_EDE_CBC_SHA DES-CBC3-SHA)], '0x03000008'=> [qw(RSA_EXPORT_WITH_DES40_CBC_SHA EXP-DES-CBC-SHA)], '0x03000009'=> [qw(RSA_WITH_DES_CBC_SHA DES-CBC-SHA)], '0x03000007'=> [qw(RSA_WITH_IDEA_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)], ); #_____________________________________________________________________________ #__________________________________________________ help and test functions __| 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; } # version sub __print { return sprintf("%s%s\n", "#SSLHello: ", @_); } sub _yprint { return __print(sprintf("%21s=%s", $_[0], $_[1])); } sub printConstants { #? prints the global constants # local $\ = ""; # no auto '\n' at the end of the line my $line = "#--------------------+-------------------------------------------"; print ("#O-Saft::Net::SSLhello::Constants:\n"); print __print($line); print ("#O-Saft::osaft::TLS_EXTENSIONS:\n"); foreach my $key (sort {lc $a cmp lc $b} keys %osaft::TLS_EXTENSIONS) { print "TLS_EXTENSIONS\{$key\}:\n"; print " \{ID\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{ID})) { print "$osaft::TLS_EXTENSIONS{$key}{ID}\n"; } print " \{CH\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{CH})) { foreach my $val (@{$osaft::TLS_EXTENSIONS{$key}{CH}}) { print "$val, "; } } print "\n"; # print " \{CH_TEXT\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{CH_TEXT})) { foreach my $val (@{$osaft::TLS_EXTENSIONS{$key}{CH_TEXT}}) { print "$val, "; } } print "\n"; print " \{RX\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{RX})) { foreach my $val (@{$osaft::TLS_EXTENSIONS{$key}{RX}}) { print "$val, "; } } print "\n"; # print " \{RX_TEXT\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{RX_TEXT})) { foreach my $val (@{$osaft::TLS_EXTENSIONS{$key}{RX_TEXT}}) { print "$val, "; } } print "\n"; print " \{RECOMMENDED\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{RECOMMENDED})) { print "$osaft::TLS_EXTENSIONS{$key}{RECOMMENDED}\n"; } print " \{TLS13\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{TLS13})) { foreach my $val (@{$osaft::TLS_EXTENSIONS{$key}{TLS13}}) { print "$val, "; } } print "\n"; print " \{RFC\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{RFC})) { foreach my $val (@{$osaft::TLS_EXTENSIONS{$key}{RFC}}) { print "$val, "; } } print "\n"; print " \{DEFAULT\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{DEFAULT})) { foreach my $val (@{$osaft::TLS_EXTENSIONS{$key}{DEFAULT}}){ my $__first_indent = 0; _trace2_ (", \n" . " " x $__first_indent) if ($__first_indent > 0); # add a newline if not the first line my $__decode_str = _decode_val (undef, \$val, \%osaft::TLS_EXTENSIONS{$key}, $__first_indent, 20, ": ", ", ", " | ", " / "); _trace5_ (" " x 20) if ($__first_indent < 1); print $__decode_str; $__first_indent = 20; } } print "\n"; print " \{CHECK\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{CHECK})) { print "$osaft::TLS_EXTENSIONS{$key}{CHECK}\n"; } print " \{COMMENT\} \= "; if (defined ($osaft::TLS_EXTENSIONS{$key}{COMMENT})) { print "$osaft::TLS_EXTENSIONS{$key}{COMMENT}\n"; } print "\n"; } print __print($line); print "\n"; } # printConstants sub printParameters { #? prints the global parameters # local $\ = ""; # no auto '\n' at the end of the line my $line = "#--------------------+-------------------------------------------"; print ("#O-Saft::Net::SSLhello::Parameters:\n"); print __print($line); print _yprint("retry", $Net::SSLhello::retry) if (defined($Net::SSLhello::retry)); print _yprint("timeout", $Net::SSLhello::timeout) if (defined($Net::SSLhello::timeout)); print _yprint("timeout", $Net::SSLhello::timeout) if (defined($Net::SSLhello::timeout)); print _yprint("connect_delay", $Net::SSLhello::connect_delay) if (defined($Net::SSLhello::connect_delay)); print _yprint("trace", $Net::SSLhello::trace) if (defined($Net::SSLhello::trace)); print _yprint("traceTIME", $Net::SSLhello::traceTIME) if (defined($Net::SSLhello::traceTIME)); print _yprint("usereneg", $Net::SSLhello::usereneg) if (defined($Net::SSLhello::usereneg)); print _yprint("double_reneg", $Net::SSLhello::double_reneg) if (defined($Net::SSLhello::double_reneg)); print _yprint("usesni", $Net::SSLhello::usesni) if (defined($Net::SSLhello::usesni)); print _yprint("use_sni_name", $Net::SSLhello::use_sni_name) if (defined($Net::SSLhello::use_sni_name)); print _yprint("sni_name", $Net::SSLhello::sni_name) if (defined($Net::SSLhello::sni_name)); print _yprint("use_signature_alg", $Net::SSLhello::use_signature_alg) if (defined($Net::SSLhello::use_signature_alg)); print _yprint("useecc", $Net::SSLhello::useecc) if (defined($Net::SSLhello::useecc)); print _yprint("useecpoint", $Net::SSLhello::useecpoint) if (defined($Net::SSLhello::useecpoint)); if (%{$Net::SSLhello::extensions_by_prot}) { print "#SSLHello: extensions_by_prot:\n"; foreach my $_prot (sort keys %{$Net::SSLhello::extensions_by_prot}) { print _yprint("->{$_prot}", join(", ",@{$Net::SSLhello::extensions_by_prot->{$_prot}})) if defined($Net::SSLhello::extensions_by_prot->{$_prot}); } } print _yprint("check_extensions", join(", ",@{$Net::SSLhello::check_extensions})) if (defined($Net::SSLhello::check_extensions)); print _yprint("extensions_max_values", $Net::SSLhello::extensions_max_values) if (defined($Net::SSLhello::extensions_max_values)); print _yprint("starttls", $Net::SSLhello::starttls) if (defined($Net::SSLhello::starttls)); print _yprint("starttlsType", $Net::SSLhello::starttlsType) if (defined($Net::SSLhello::starttlsType)); for my $i (1..5) { print _yprint("starttlsPhaseArray[$i]", $Net::SSLhello::starttlsPhaseArray[$i]) if (defined($Net::SSLhello::starttlsPhaseArray[$i])); } for my $i (6..8) { print _yprint("starttlsErrorArray[".($i-5)."]", $Net::SSLhello::starttlsPhaseArray[$i] . " = starttlsPhaseArray[$i] (internally)") if (defined($Net::SSLhello::starttlsPhaseArray[$i])); } print _yprint("starttlsDelay", $Net::SSLhello::starttlsDelay) if (defined($Net::SSLhello::starttlsDelay)); print _yprint("slowServerDelay", $Net::SSLhello::slowServerDelay) if (defined($Net::SSLhello::slowServerDelay)); print _yprint("experimental", $Net::SSLhello::experimental) if (defined($Net::SSLhello::experimental)); print _yprint("proxyhost", $Net::SSLhello::proxyhost) if (defined($Net::SSLhello::proxyhost)); print _yprint("proxyport", $Net::SSLhello::proxyport) if (defined($Net::SSLhello::proxyport)); print _yprint("max_ciphers", $Net::SSLhello::max_ciphers) if (defined($Net::SSLhello::max_ciphers)); print _yprint("max_sslHelloLen", $Net::SSLhello::max_sslHelloLen) if (defined($Net::SSLhello::max_sslHelloLen)); print ("\n#O-Saft::Net::SSLhello: information about the OS and some socket constants and functions.\n"); print __print($line); print _yprint("OS", $^O) if (defined($^O)); my $_pf_inet = PF_INET; print _yprint("socket::PF"."_INET", $_pf_inet); my $_af_inet = AF_INET; print _yprint("socket::AF"."_INET", $_af_inet); my $_sock_stream = (defined(SOCK_STREAM)) ? SOCK_STREAM : "--undef --"; print _yprint("socket::SOCK_STREAM", $_sock_stream); my $_sol_socket = (defined(SOL_SOCKET)) ? SOL_SOCKET : "--undef --"; print _yprint("socket::SOL_SOCKET", $_sol_socket); my $_so_sndtimeo = (defined(SO_SNDTIMEO)) ? SO_SNDTIMEO : "--undef --"; print _yprint("socket::SO_SNDTIMEO", $_so_sndtimeo); my $_so_rcvtimeo = (defined(SO_RCVTIMEO)) ? SO_RCVTIMEO : "--undef --"; print _yprint("socket::SO_RCVTIMEO", $_so_rcvtimeo); my ($_dummy1, $_dummy2, $_protocol) = getprotobyname('tcp'); # is failsafer than '(getprotobyname('tcp'))[2]' if (! $_protocol) { $_protocol = Socket::IPPROTO_TCP; } print _yprint("socket::getprotobyname('tcp')", $_protocol); print __print($line); return; } # printParameters ### --------------------------------------------------------------------------------------------------------- ### ### 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 octets, e.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 $sep_sep = " | "; my $protocol = $PROTOCOL_VERSION{$ssl}; # 0x0002, 0x3000, 0x0301, 0x0302 my $cipher = ""; local $\ = ""; # no auto '\n' at the end of the line _trace4 ("printCipherStringArray: {\n"); $legacy = "csv" if ($legacy eq "compact"); # backward compatibility: old 'compact' style => new 'csv' style if ($usesni) { $sni = "SNI"; $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 'csv') { $cipherOrder = "Server Order"; } else { print "# cipher suites in server-preferred order:\n"; } $firstEle = 1; } else { if ($legacy eq 'csv') { $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 'csv') { # csv-style, protocol without cipher printf "%s%s%s%s%-6s%s%-8s%s%-12s%s%8s%s\n", $host, $sep, # %s%s $port, $sep, # %s%s $ssl, $sep, # %-6s%s $sni, $sep, # %-8s%s% "", $sep, # %-12s%s "", $sep; # %8s%s } } foreach my $protocolCipher (@cipherArray[$firstEle .. $#cipherArray]) { # array may have the first element twice to signal a server-preferred order if ($usesni) { if ($protocol != 0x0304) { # get results for SNI support from tls extension 'server_name' if (exists($_SSLhello{$protocolCipher}{param}{server_name}{RX}{values}) ) { # SNI is suppoted by the server $sni = "SNI: yes"; } else { # the server does not support sni $sni = "SNI: no"; } } else { ## workaround for TLS 1.3, sni extension is not decrypted, yet $sni = "SNI"; } $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"; } if ($protocol > 0x0002) { # SSLv3 and TLS $cipher = "0x".substr($protocolCipher,-4,4); # IANA HEX-value } else { # SSLv2 $cipher = "0x".substr($protocolCipher,-6,6); } if ($legacy eq 'csv') { # csv-style printf "%s%s%s%s%-6s%s%-8s%s%-12s%s%8s%s", $host, $sep, # %s%s $port, $sep, # %s%s $ssl, $sep, # %-6s%s $sni, $sep, # %-8s%s% $cipherOrder, $sep, # %-12s%s $cipher, $sep; # %8s%s if ( (defined ($cipherHexHash {$protocolCipher}) ) && ($#{$cipherHexHash {$protocolCipher}}>0) ) { # definiert, max index >0 printf "%-36s%s%-41s", $cipherHexHash {$protocolCipher}[1], $sep, # %-30s%s $cipherHexHash {$protocolCipher}[0]; # %-36s } else { # no RFC-Defined cipher printf "%-36s%s%-41s\n", "NO-RFC-".$cipher, $sep, # %-30s%s "NO-RFC-".$cipher; # %-36ss } print $sep; # Print parameters by the cipher if (exists ($_SSLhello{$protocolCipher}{param}{ServerKey}{values})) { #length of dh_param, supported_group print "param: $_SSLhello{$protocolCipher}{param}{ServerKey}{description} (". (@{$_SSLhello{$protocolCipher}{param}{ServerKey}{values}}) . "): "; for (my $_i = 0; $_i <= $#{$_SSLhello{$protocolCipher}{param}{ServerKey}{values}}; $_i++) { print $sep_sep if ($_i) > 0; print $_SSLhello{$protocolCipher}{param}{ServerKey}{values}[$_i]; } } print "\n"; } else { # human readable output if ( (defined ($cipherHexHash {$protocolCipher}) ) && ($#{$cipherHexHash {$protocolCipher}}>0) ) { # definiert, max index >0 printf "# Cipher-String: >%s<, %-36s, %s",$cipher, $cipherHexHash {$protocolCipher}[1], $cipherHexHash {$protocolCipher}[0]; # Print parameters by the cipher if (exists ($_SSLhello{$protocolCipher}{param}{ServerKey}{values})) { #length of dh_param print ", Paramters: $_SSLhello{$protocolCipher}{param}{ServerKey}{description}: "; for (my $_i = 0; $_i <= $#{$_SSLhello{$protocolCipher}{param}{ServerKey}{values}}; $_i++) { print $sep_sep if ($_i) > 0; print $_SSLhello{$protocolCipher}{param}{ServerKey}{values}[$_i]; } } print "\n"; } else { print "# Cipher-String: >".$cipher."<, NO-RFC-".$cipher; } print "\n"; } } # foreach my $protocolCipher ... if ($legacy eq 'csv') { # 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 octets, 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 %_SSLhello = (); # delete result hash '_SSLhello' printConstants () if ($Net::SSLhello::trace > 3); # additional trace information printParameters () if ($Net::SSLhello::trace > 3); # additional trace information OSaft::error_handler->reset_err( {module => ($SSLHELLO), sub => 'checkSSLciphers', print => ($Net::SSLhello::trace > 3), 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) { _trace5 ("checkSSLciphers: add cipher >$cipher_str< to cipher-string -> "); 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 _trace5_ (" >". hexCodedCipher($cipher_str)."<"); } else { _trace5_ (" SSL2-Cipher suppressed\n"); next; # nothing to do for this cipher } _trace5_ ("\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 > 3), 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 > 3), 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 Priority 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; } else { #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 (3.3): => Received no cipher while checking the priority of the ciphers \'$str\' -> Exit loop. Reason: ''\n"); carp ("**WARNING: checkSSLciphers (3.3): => Received no cipher 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 _doCheckAllExtensions ($host, $port, $protocol, $acceptedCipher, $dtlsEpoch, 1); # check Extension parameters for this cipher $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) > ". hexCodedString($cipher_str)."<\n"); _trace4_ ("# ---> backup parameters to values of the first check of cipher " . hexCodedTLSCipher($acceptedCipher) . "\n"); my %_param_tmp_hash = (); %_param_tmp_hash = %{$_SSLhello{'0x0300'.hexCodedCipher($acceptedCipher)}{param}} if (exists ($_SSLhello{'0x0300'.hexCodedCipher($acceptedCipher)}{param}));# save the param hash, just in case we will get the same cipher again $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 push (@acceptedCipherSortedArray, $acceptedCipher); if ($acceptedCipher eq $acceptedCipherSortedArray[0]) { # got 1st cipher again => order -> restore param hash _trace4_ ("# ---> restore stored parameters to values of first check of cipher ". hexCodedTLSCipher($acceptedCipher) . "\n"); $_SSLhello{'0x0300'.hexCodedCipher($acceptedCipher)}{param} = \%_param_tmp_hash; } else { # check Extensions for new cipher _trace4_ ("# ---> is a new cipher => noi preferred order by the server\n"); _doCheckAllExtensions ($host, $port, $protocol, $acceptedCipher, $dtlsEpoch, 1); # check Extension parameters for this cipher } } } 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; } else { #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.3): => Received no cipher while checking the priority of the ciphers \'$str\' -> Exit loop. Reason: ''\n"); carp ("**WARNING: checkSSLciphers (6.3): => Received no cipher 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?!! ### Ckeck all Extension Parameters for extensions that have been previously flagged to get more than one answer, eg. supported_groups # my $_first = 0; # $_first = 1 if ( ((@acceptedCipherSortedArray) > 1) && ($acceptedCipherSortedArray[0] eq $acceptedCipherSortedArray[1]) ); # jump over the first cipher if equal to the second (sorted list) # foreach my $_i ($_first .. (@acceptedCipherSortedArray)) { # _doCheckAllExtensions ($host, $port, $protocol, $acceptedCipherSortedArray[$_i], $dtlsEpoch, 1); # if server uses a priority List we get the same cipher again!$ # } _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", # CUSTOMise your own starttls sequence with 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 > 3), 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') { # customise the starttls_matrix for my $i (1..8) { if (defined($Net::SSLhello::starttlsPhaseArray[$i])) { _trace4 ("openTcpSSLconnection: Customise 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: Customise \$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 > 3), 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) && ($Net::SSLhello::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 ( ($Net::SSLhello::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) my ($_dummy1, $_dummy2, $_protocol) = getprotobyname('tcp'); # is failsafer than '(getprotobyname('tcp'))[2]' if (! $_protocol) { $_protocol = Socket::IPPROTO_TCP; } socket($socket, PF_INET, SOCK_STREAM, $_protocol) 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 analyse 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 $dummy=""; # if the return value is not used in this case 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 $lastRecordData = ""; my $ssl = $PROTOCOL_NAME_BY_HEX{$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 > 3), 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 ($recordType, $recordVersion, $recordLen, $recordData, $recordEpoch, $recordSeqNr, $my_error) = _readRecord ($socket, $isUdp, \$input, $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"); ($buffer, $lastMsgType, $dtlsNewCookieLen, $dtlsNewCookie, $acceptedCipher) = 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'}) ) { _trace4 ("_doCheckSSLciphers: Try to get and parse next records\n"); while ( (length($input) >0) && ($lastMsgType != $HANDSHAKE_TYPE {'server_hello_done'}) ) { ###### receive next record _trace4 ("_doCheckSSLciphers: receive next record\n"); $input = $buffer; $buffer = ""; ($recordType, $recordVersion, $recordLen, $recordData, $recordEpoch, $recordSeqNr, $my_error) = _readRecord ($socket, $isUdp, \$input, $host, $port, $protocol); last if ( (length($input)==0) || ($my_error) ); _trace4 ("_doCheckSSLciphers: record type '$recordType' is no handshake record -> stop receiving records\n") if ($recordType ne $RECORD_TYPE{'handshake'}); #TBD: wieder aktivieren last if ($recordType ne $RECORD_TYPE{'handshake'}); last if ($recordType eq $RECORD_TYPE{'application_data'}); ## replace the 'last' command above by this to test or to develop if ( ($lastMsgType == $HANDSHAKE_TYPE {'<>'}) && ($recordType == $lastRecordType) ) { # last message was fragmented $recordData = $lastRecordData.$recordData; $recordLen += length($lastRecordData); $lastRecordData = ""; _trace4 ("_doCheckSSLciphers: recompiled fragmented message -> compiled RecordLen: $recordLen\n"); } # parse the next record (no cipher expected...) ($buffer, $lastMsgType, $dtlsNewCookieLen, $dtlsNewCookie, $dummy) = 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 ($lastMsgType == $HANDSHAKE_TYPE {'<>'}) { # last message has been fragmented $lastRecordData = $buffer; $buffer = ""; } } } 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 $input_ref = shift; 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 octets for UDP (-> MAXLEN), # 7 octets 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 octets 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; return ($recordType, $recordVersion, $recordLen, $recordData, $recordEpoch, $recordSeqNr, $my_error) if (! defined ($input_ref) ); my $input2 = ""; my @socketsReady = (); my $len = length ($$input_ref); 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 > 3), 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_ref) < $pduLen) || ($pduLen == 0) ) && ($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); # opimised 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_ref)." 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_ref)." 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_ref)." bytes)\n") if (scalar (@socketsReady)); $success = sysread ($socket, $$input_ref, $readLen - length($$input_ref), length($$input_ref)); #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_ref)." 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_ref)." bytes)\n") if (scalar (@socketsReady)); if (! $success ) { # EOF or other error while reading Data if (length ($$input_ref) == 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_ref)." 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_ref)." 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_ref)." 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); my $_missing_readLen = $readLen - length($$input_ref); _trace4 ("_readRecord (tcp): try to recv (1): (Segement: $segmentCnt, retry: $retryCnt, position: ".length($$input_ref)." bytes, missing Bytes: $_missing_readLen)\n"); $success = ($_missing_readLen <= 0) || (recv ($socket, $input2, $readLen - length($$input_ref), 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_ref)." 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_ref .= $input2; # append new input $success = length ($input2); # same usage as sysread _trace4 ("_readRecord (tcp): recv: (Segement: $segmentCnt, retry: $retryCnt, position: ".length($$input_ref)." bytes)\n"); } # End TCP $len = length($$input_ref); 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_ref); # 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_ref); 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 implicitly 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_ref)." 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_ref); _trace2_ (sprintf ( "# --> => DTLS record type: Handshake (%02X):\n". ### only for handshake records that we analyse, 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 recognised $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_ref)." 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 octets (-> 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)) { my $client_ssl = $PROTOCOL_NAME_BY_HEX{$client_protocol}; if (! defined $client_ssl) { $client_ssl = "--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 $client_ssl (0x%04X) by $host:$port, answered with (0x%04X)", $client_protocol, $recordVersion), warn => 0, } ); last RETRY_TO_RECEIVE_A_RECORD; } } } } # end while if (!($my_error) && (length($$input_ref) < $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_ref)." 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_ref)." bytes >".hexCodedString (substr($$input_ref,0,48)," ")."< ...)\n"); } else { _trace4("_readRecord: Server '$host:$port': (any protocol, (record) type $recordType, -version: ".sprintf ("(0x%04X)",$recordVersion)." with ".length($$input_ref)." bytes\n Data=".hexCodedString ($$input_ref," ").")\n"); } ($recordData) = unpack ("x[$recordHeaderLen] a*", $$input_ref); # get recordData with up to $recordLen bytes 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 smaller than 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 smaller than the expected value ".sprintf ("%04X",$recordLen). "\n"); } return ($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); # Opimised 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); my $_missing_readLen = $MAXLEN - length($input); _trace4 ("_readText: try to recv (1): (retry: $retryCnt, position: ".length($input)." bytes, missing Bytes: $_missing_readLen)\n"); ## read only up to 5 bytes in the first round, then up to the expected pduLen my $success = ($_missing_readLen <= 0) || (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; } $len = length($input2); 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 $ssl = $PROTOCOL_NAME_BY_HEX{$version}; if (! defined $ssl) { $ssl = "--unknown protocol--"; } _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 $handshake_version = $version; if ( ($version > $PROTOCOL_VERSION{'TLSv12'}) && ($version < $PROTOCOL_VERSION{'DTLSv12'}) ) { $handshake_version = $PROTOCOL_VERSION{'TLSv12'}; $record_version = $PROTOCOL_VERSION{'TLSv12'}; } 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' => $handshake_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", #Comma!! $clientHello{'compression_method_len'}, # C (0x01) $clientHello{'compression_method'}, # C[1] (0x00) )); _trace5_ ( sprintf ( "# ---> extensions_total_len: >%04X<\n". #Point!! "# ---> extensions: >%s<\n", #Comma!! $clientHello{'extensions_total_len'}, hexCodedString ($clientHello_extensions), ) ); _parseExtensions ("CH", undef, \$clientHello_extensions, -1) if ($Net::SSLhello::trace > 2); # only for trace purposes; $clientHello_extensions includes the length -> length = '-1' as indicator _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", # Comma!! $clientHello{'compression_method_len'}, # C (0x01) $clientHello{'compression_method'}, # C[1] (0x00) )); _trace5_ ( sprintf ( "# ---> extensions_total_len: >%04X<\n". #Point!! "# ---> extensions: >%s<\n", #Comma!! $clientHello{'extensions_total_len'}, hexCodedString ($clientHello_extensions), ) ); _parseExtensions ("CH", undef, \$clientHello_extensions, -1) if ($Net::SSLhello::trace > 2); # only for trace purposes; $clientHello_extensions includes the length -> length = '-1' as indicator _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 ClientHellos > $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 $ssl = $PROTOCOL_NAME_BY_HEX{$record_version}; if (! defined $ssl) { $ssl = "--unknown protocol--"; } _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 subs that compile parts of records, e.g. bytes for extensions #################### #? sub __compile_bytes_* and _compileNextByte, _compileAllBytes #? the following subs use the same set of variables: #? $__pdu_name: for tracing and warnings: name of the PDU that is parsed, eg. extension #? $__format_ref: reference to an array including the format of the PDU, %__compile_bytes_subs maps the format names to the sub functions #? $__param_ref: reference to an array of the values to be compiled #? $__format_pos_ref: reference to the position in the array $__format_ref->[pos] #? $__param_pos_ref: reference to the position in the array $__param_ref->[pos] #? $__buffer_ref: reference to the buffer that stores the compiled PDU #? $__buffer_size: size of the buffer #? optional: #? $__format_text_ref: reference to an array describing the semantic of the parts of the PDU #? $__indent: indent for tracing #? #? return($_size): return the size of the buffer #? use this subs via '%__compile_bytes_subs' a self defined general description for the structure of for PDUs, e.g. tls extensions sub __compile_bytes_len1 ($$$$$$;$$) { #? compiles the len1 byte the following value fields my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; my $_next_data = ""; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_len1 for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); $$__format_pos_ref++; # Next format element $_size = _compileAllBytes ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, \$_next_data, $__format_text_ref, $__indent); my $__len = length ($_next_data); _trace4_ (_decode_val ("%02X", \$__len, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . " (len1)\n"); carp ("**WARNING: SSLhello::__compile_bytes_len1 for '$__pdu_name': Length $__len too big\n") if ($__len > 0xFF); ### TBD: add WARNING Nr $$__buffer_ref .= pack ("C a*", $__len, #C $_next_data, #a[$len] ); $_size += 1; return ($_size); } sub __compile_bytes_len2 ($$$$$$;$$) { #? compiles the len2 bytes the following value fields my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; my $_next_data = ""; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_len2 for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); $$__format_pos_ref++; # Next format element $_size = _compileAllBytes ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, \$_next_data, $__format_text_ref, $__indent); my $__len = length ($_next_data); _trace4_ (_decode_val ("%04X", \$__len, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . " (len2)\n"); carp ("**WARNING: SSLhello::__compile_bytes_len2 for '$__pdu_name': Length $__len too big\n") if ($__len > 0xFFFF); ### TBD: add WARNING Nr $$__buffer_ref .= pack ("n a*", $__len, #n $_next_data, #a[$len] ); $_size += 2; return ($_size); } sub __compile_bytes_len3 ($$$$$$;$$) { #? compiles the len3 bytes the following value fields my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; my $_next_data = ""; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_len3 for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); $$__format_pos_ref++; # Next format element $_size = _compileAllBytes ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, \$_next_data, $__format_text_ref, $__indent); my $__len = length ($_next_data); my $__len1 = $__len >> 16; my $__len2 = $__len & 0xFFFF; _trace4_ (_decode_val ("%06X", \$__len, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . " (len3)\n"); carp ("**WARNING: SSLhello::_compile_bytes_len3 for '$__pdu_name': Length $__len too big\n") if ($__len > 0xFFFFFF); ### TBD: add WARNING Nr $$__buffer_ref .= pack ("C n a*", $__len1, #C $__len2, #n $_next_data, #a* ); $_size += 3; return ($_size); } sub __compile_bytes_raw ($$$$$$;$$) { #? compiles a raw bytes value field my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_raw for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); return (0) if (! defined ($__param_ref->[$$__param_pos_ref]) ); # no value my $__val = $__param_ref->[$$__param_pos_ref++]; _trace4_ (_decode_val ("", \$__val, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n", " | ", " / ") . " (raw)\n"); $$__buffer_ref .= pack ("a*", $__val, #a* ); $_size = length ($__val); return ($_size); } sub __compile_bytes_sequence ($$$$$$;$$) { #? compiles a sequence of fields my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; my $_sequence_data = ""; my $_sequence_param_pos = 0; my $_sequence_param_list_ref; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_sequence for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); _trace4_ (_decode_val (undef, undef, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent + 3, ":\n" . " " x ($__indent + 3), ",\n" . " " x ($__indent + 3), " | ", " / ") ); _trace5_ ("\n"); $$__format_pos_ref++; # Next format element my $_sequence_format_pos = $$__format_pos_ref; # store start position of sequence $__indent += 3; while (defined ($__param_ref->[$$__param_pos_ref]) ) { $_sequence_param_list_ref = \@{$__param_ref->[$$__param_pos_ref]}; _trace5_ (" " x $__indent); _trace4_ ("sequence parameter for '$__pdu_name':\n" . _decode_val (undef, $_sequence_param_list_ref, undef, $__indent + 3, $__indent + 3, ":\n" . " " x ($__indent + 3), ",\n" . " " x ($__indent + 3), " | ", " / ") . "\n"); $$__format_pos_ref = $_sequence_format_pos; # reset format_pos to first element of sequence format $_sequence_param_pos = 0; # reset to first Element of $_sequence_param_list $_sequence_data = ""; # reset sequence_data $_size += _compileAllBytes ($__pdu_name, $__format_ref, $_sequence_param_list_ref, $__format_pos_ref, \$_sequence_param_pos, \$_sequence_data, $__format_text_ref, $__indent); $$__buffer_ref .= $_sequence_data; # add sequence data to _data _trace4_ (" " x $__indent); _trace4_ ("=> size of sequence(s) for '$__pdu_name': " . _sprintf_hex_val ("%04X", \$_size, $__indent) ."\n" ); $$__param_pos_ref++; } return ($_size); } sub __compile_bytes_size1 ($$$$$$;$$) { #? compiles the size1 byte the following value field my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; my $_next_data = ""; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_size1 for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); $$__format_pos_ref++; # Next format element $_size = _compileNextByte ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, \$_next_data, $__format_text_ref, $__indent); _trace4_ (_decode_val ("%02X", \$_size, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ",\n" . " " x $__indent, " | ", " / ") . " (size1)\n"); carp ("**WARNING: SSLhello::__compile_bytes_size1 for '$__pdu_name': Length $_size too big\n") if ($_size > 0xFF); ### TBD: add WARNING Nr $$__buffer_ref .= pack ("C a*", $_size, #C $_next_data, #a[$len] ); $_size += 1; return ($_size); } sub __compile_bytes_size2 ($$$$$$;$$) { #? compiles the size2 bytes the following value field my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; my $_next_data = ""; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_size2 for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); $$__format_pos_ref++; # Next format element $_size = _compileNextByte ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, \$_next_data, $__format_text_ref, $__indent); _trace4_ (_decode_val ("%04X", \$_size, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . " (size2)\n"); carp ("**WARNING: SSLhello::__compile_bytes_size2 for '$__pdu_name': Length $_size too big\n") if ($_size > 0xFFFF); ### TBD: add WARNING Nr $$__buffer_ref .= pack ("n a*", $_size, #n $_next_data, #a[$len] ); $_size += 2; return ($_size); } sub __compile_bytes_val1 ($$$$$$;$$) { #? compiles a val1 byte value field my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_val1 for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); return (0) if (! defined ($__param_ref->[$$__param_pos_ref]) ); # no value my $__val = $__param_ref->[$$__param_pos_ref++]; _trace4_ (_decode_val ("%02X", \$__val, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . " (val1)\n"); carp ("**WARNING: SSLhello::__compile_bytes_val1 for '$__pdu_name': value $__val too big\n") if ($__val > 0xFF); ### TBD: add WARNING Nr $$__buffer_ref .= pack ("C", $__val, #C ); $_size += 1; return ($_size); } sub __compile_bytes_val2 ($$$$$$;$$) { #? compiles a val2 bytes value field my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_val2 for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); return (0) if (! defined ($__param_ref->[$$__param_pos_ref]) ); # no value my $__val = $__param_ref->[$$__param_pos_ref++]; _trace4_ (_decode_val ("%04X", \$__val, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . " (val2)\n"); carp ("**WARNING: SSLhello::__compile_bytes_val2 for '$__pdu_name': value $__val too big\n") if ($__val > 0xFFFF); ### TBD: add WARNING Nr $$__buffer_ref .= pack ("n", $__val, #n ); $_size += 2; return ($_size); } sub __compile_bytes_val4 ($$$$$$;$$) { #? compiles a val4 bytes value field my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_val4 for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); return (0) if (! defined ($__param_ref->[$$__param_pos_ref]) ); # no value my $__val = $__param_ref->[$$__param_pos_ref++]; _trace4_ (_decode_val ("%04X", \$__val, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . " (val4)\n"); carp ("**WARNING: SSLhello::__compile_bytes_val4 for '$__pdu_name': value $__val too big\n") if ($__val > 0xFFFFFFFF); ### TBD: add WARNING Nr $$__buffer_ref .= pack ("N", $__val, #N ); $_size += 4; return ($_size); } sub __compile_bytes_val1List ($$$$$$;$$) { #? compiles a value list of val1 bytes my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_val1List for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); return (0) if (! defined ($__param_ref->[$$__param_pos_ref]) ); # no value my @__list = @{$__param_ref->[$$__param_pos_ref++]}; _trace4_ (_decode_val ("%02X", \@__list, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x ($__indent + 2), " | ", " / ") . " (val1List)\n"); $$__buffer_ref .= pack ("C" x (@__list), @__list, #C ); $_size += (@__list); return ($_size); } sub __compile_bytes_val2List ($$$$$$;$$) { #? compiles a value list of val2 bytes my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; _trace4_ (" " x $__indent . "# SSLhello: __compile_bytes_val2List for '$__pdu_name' ($$__format_pos_ref, $$__param_pos_ref)\n"); return (0) if (! defined ($__param_ref->[$$__param_pos_ref]) ); # no value my @__list = @{$__param_ref->[$$__param_pos_ref++]}; _trace4_ (_decode_val ("%04X", \@__list, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x ($__indent + 2), " | ", " / ") . " (val2List)\n"); $$__buffer_ref .= pack ("n" x (@__list), @__list, #n ); $_size += 2 * (@__list); return ($_size); } #? Hash with all subs __compile_bytes_* #? A self defined general description for the structure of for PDUs, e.g. tls extensions: #? len1: Len of the next bytes, coded in 1 byte (-> max 0xFF) #? len2: Len of the next bytes, coded in 2 bytes (-> max 0xFFFF) #? len3: Len of the next bytes, coded in 3 bytes (-> max 0xFFFFFF) #? size1: Size of the next value, coded in 1 byte (-> max 0xFF) #? size2: Size of the next value, coded in 2 bytes (-> max 0xFFFF) #? val1: value, coded in 1 byte (-> max 0xFF) #? val2: value, coded in 2 bytes (-> max 0xFFFF) #? val4: value, coded in 4 byters (-> max 0xFFFFFFFF) #? val1List: List of value, coded in 1 byte (-> max 0xFF, 0xFF, ...) #? val2List: List of value, coded in 2 bytes (-> max 0xFFFF, 0xFFFF, ...) #? raw: Raw bytes (number needs to be previously defined by a len or size element) #? sequence: Sequence of structured elements that form lists of compound values my %__compile_bytes_subs = ( len1 => \&__compile_bytes_len1, len2 => \&__compile_bytes_len2, len3 => \&__compile_bytes_len3, raw => \&__compile_bytes_raw, sequence => \&__compile_bytes_sequence, size1 => \&__compile_bytes_size1, size2 => \&__compile_bytes_size2, val1 => \&__compile_bytes_val1, val2 => \&__compile_bytes_val2, val4 => \&__compile_bytes_val4, val1List => \&__compile_bytes_val1List, val2List => \&__compile_bytes_val2List, ); sub _compileNextByte ($$$$$$;$$) { #? compiles the next byte(s) to a PDU, e.g. extension my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; return (0) if (! defined ($__format_ref->[$$__format_pos_ref]) ); if ($__compile_bytes_subs{$__format_ref->[$$__format_pos_ref]}) { $_size = $__compile_bytes_subs{$__format_ref->[$$__format_pos_ref]}->($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref, $__format_text_ref, $__indent); _trace5_ ("\n"); } else { carp ("**WARNING: SSLhello::Net::_compileNextByte for '$__pdu_name': \'No such format sub: $__format_ref->[$$__format_pos_ref]\', => Please verify hash 'CH'-format definition in osaft.pm e.g. in \%TLS_EXTENSIONS"); } _trace4_ (" " x ($__indent + 3). "# SSLhello: _CompileNextByte for '$__pdu_name' ->" . _sprintf_hex_val ("", $__buffer_ref, ($__indent + 31)) ."\n" ); $$__format_pos_ref++; # Next format element return ($_size); } sub _compileAllBytes ($$$$$$;$$) { #? compile all byte(s) according the $__format_ref and the $__param_ref to a PDU, e.g. extension my ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_size = 0; while (defined ($__format_ref->[$$__format_pos_ref]) ) { # $$__format_pos_ref is increased by _compileNextByte and subs '__compile_bytes_*' $_size += _compileNextByte ($__pdu_name, $__format_ref, $__param_ref, $__format_pos_ref, $__param_pos_ref, $__buffer_ref, $__format_text_ref, $__indent); } return ($_size); } #? END of: sub subs that compile parts of records, e.g. bytes for extensions #################### sub _compileClientHelloExtensions ($$$$@) { #? compile all ClientHello extensions according $Net::SSLhello::extensions_by_prot->{$ssl}, #? protocol version and some other global parameters: #? $Net::SSLhello::force_TLS_extensions #? $Net::SSLhello::usereneg #? $Net::SSLhello::double_reneg #? $Net::SSLhello::usesni #? $Net::SSLhello::sni_name #? $Net::SSLhello::use_sni_name #? %osaft::TLS_EXTENSIONS defines and describes the extensions (add there new extensions if needed) #? $Net::SSLhello::extensions_params_hash{$_extension}: temporary parameters defined for an extension if not empty #? #? return ($clientHello_extensions): returns all compiled extensions headed by the total length #? --------------------------------------------------------------------------- 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 $ssl = $PROTOCOL_NAME_BY_HEX{$version}; if (! defined $ssl) { $ssl = "--unknown protocol--"; } my $_ext_format_pos = 0; my $_ext_param_pos = 0; my $_extensions_data = ""; my $_extensions_params_ref; 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 (""); } 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} if (!grep {/^renegotiation_info$/x} @{$Net::SSLhello::extensions_by_prot->{$ssl}}) { # renegotiation_info not listed as extension, yet unshift @{$Net::SSLhello::extensions_by_prot->{$ssl}}, 'renegotiation_info'; # Add renegotiation_info extension as 1st extension } _trace2 ("compileClientHelloExtensions ($ssl): extension renegotiation_info will be added\n"); } else { _trace2 ("compileClientHelloExtensions ($ssl): Extension renegotiation_info will *NOT* be sent as the cipher_spec includes already the Signalling Cipher Suite Value (TLS_EMPTY_RENEGOTIATION_INFO_SCSV {0x00, 0xFF})\n"); @{$Net::SSLhello::extensions_by_prot->{$ssl}} = grep { $_ ne 'renegotiation_info' } @{$Net::SSLhello::extensions_by_prot->{$ssl}}; # delete all extension elements 'renegotiation_info' for this protocol } } # TBD: optional check if $host is a name and no IP 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 } _trace2 ("compileClientHelloExtensions ($ssl): extension server_name for '$clientHello{'extension_sni_name'}' will be added\n"); $osaft::TLS_EXTENSIONS{server_name}{DEFAULT}[0][1] = $clientHello{'extension_sni_name'}; # add servername as 2nd parameter of first sequence element; TBD: move to {$cfg}.... if (!grep {/^server_name$/x} @{$Net::SSLhello::extensions_by_prot->{$ssl}}) { # sni_name not listed as extension, yet unshift @{$Net::SSLhello::extensions_by_prot->{$ssl}}, 'server_name'; # Add sni_name extension as 1st extension } } else { _trace2 ("compileClientHelloExtensions ($ssl): NO server_name extension will be added\n"); @{$Net::SSLhello::extensions_by_prot->{$ssl}} = grep { $_ ne 'server_name' } @{$Net::SSLhello::extensions_by_prot->{$ssl}}; # delete all extension elements 'sni_name' for this protocol } my $_indent = 6; # for trace _trace4_ (" " x $_indent . "Compile extensions ($ssl):\n"); foreach my $_extension (@{$Net::SSLhello::extensions_by_prot->{$ssl}}) { $_indent = 6; # reset $_indent _trace4_ (" " x $_indent . "extension '$_extension':\n"); $_extensions_data = ""; if (defined $osaft::TLS_EXTENSIONS{$_extension}) { _trace4_(" " x $_indent . "ID = ($osaft::TLS_EXTENSIONS{$_extension}{ID}: CH:"); if (@{$osaft::TLS_EXTENSIONS{$_extension}{CH}}) { for (my $nr = 0; $nr < (@{$osaft::TLS_EXTENSIONS{$_extension}{CH}}); $nr++) { _trace4_ (", ") if $nr > 0; _trace4_ ("$osaft::TLS_EXTENSIONS{$_extension}{CH}[$nr]"); } _trace5_ ("\n" . " " x $_indent . "# ---> Use temporary defined parameters for extension '$_extension': ". exists ($Net::SSLhello::extensions_params_hash{$_extension})); $_extensions_params_ref = (exists ($Net::SSLhello::extensions_params_hash{$_extension})) ? \@{$Net::SSLhello::extensions_params_hash{$_extension}}: \@{$osaft::TLS_EXTENSIONS{$_extension}{DEFAULT}}; # use special params for this extension if defined _trace4_ (" ("); if (@$_extensions_params_ref) { # _trace5_ ("\n"); for (my $nr = 0; $nr < (@$_extensions_params_ref); $nr++) { my $val = $_extensions_params_ref->[$nr]; _trace5_ ("\n" . " " x ($_indent + 2)); _trace4_ (_decode_val (undef, \$val, undef, 0, ($_indent + 2) , ":\n" . " " x ($_indent + 2), ", ", " | ", " / ")); #TBD: Check } } _trace4_ (")):\n"); $_ext_format_pos = 0; $_ext_param_pos = 0; $_indent += 3; # for trace _trace5_(" " x $_indent . _sprintf_hex_val ("ID: 0x%04X", \$osaft::TLS_EXTENSIONS{$_extension}{ID}, $_indent + 3) . "\n"); $_extensions_data = pack ("n", $osaft::TLS_EXTENSIONS{$_extension}{ID}, #n ); _compileAllBytes ($_extension, \@{$osaft::TLS_EXTENSIONS{$_extension}{CH}}, $_extensions_params_ref, \$_ext_format_pos, \$_ext_param_pos, \$_extensions_data, \@{$osaft::TLS_EXTENSIONS{$_extension}{CH_TEXT}}, $_indent + 3); _trace5_ (" " x ($_indent + 3). _sprintf_hex_val ("", \$_extensions_data, ($_indent + 6)) . " " x ($_indent). ")\n" ); _trace5_ ("------------- show the compiled extension --------------\n"); _parseExtensions ("CH", undef, \$_extensions_data, length($_extensions_data)) if ($Net::SSLhello::trace > 4); # only for trace purposes $clientHello_extensions .= $_extensions_data; } _trace4_ ("\n"); } } ##### End Test $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 #? sub subs that parse parts of records, e.g. bytes for extensions ############################### #? sub __parse_bytes_* and _parseNextByte, _parseAllBytes #? the following subs use the same set of variables: #? $__pdu_name: for tracing and warnings: name of the PDU that is parsed, eg. extension #? $__format_ref: reference to an array including the format of the PDU, %__parse_bytes_subs maps the format names to the sub functions #? $__param_hash_ref: reference to an hash that stores the parsed values #? $__format_pos_ref: reference to the position in the array $__format_ref->[pos] #? $__buffer_ref: reference to the buffer that is going to be parsed #? $__buffer_size: size of the buffer #? optional: #? $__format_text_ref: reference to an array describing the semantic of the parts of the PDU #? $__indent: indent for tracing #? use this subs via '%__parse_bytes_subs' a self defined general description for the structure of for PDUs, e.g. tls extensions sub __parse_bytes_len1 ($$$$$$;$$) { #? parses a len1 bytes field my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $__next_data = ""; my $__len; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_len1 for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 1); ($__len, #C $$__buffer_ref) = unpack("C a*", $$__buffer_ref); _trace2_ (_decode_val ("%02X", \$__len, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); $$__format_pos_ref++; # Next format element ($__next_data, #a[$len] $$__buffer_ref) = unpack("a[$__len] a*", $$__buffer_ref); _parseAllBytes ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, \$__next_data, $__len, $__format_text_ref, $__indent + 3) if ($__len > 0); $__buffer_size -= (1 + $__len); return ($__buffer_size); } sub __parse_bytes_len2 ($$$$$$;$$) { #? parses a len2 bytes field my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $__next_data = ""; my $__len; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_len2 for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 2); ($__len, #n $$__buffer_ref) = unpack("n a*", $$__buffer_ref); _trace2_ (_decode_val ("%04X", \$__len, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); $$__format_pos_ref++; # Next format element ($__next_data, #a[$len] $$__buffer_ref) = unpack("a[$__len] a*", $$__buffer_ref); _parseAllBytes ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, \$__next_data, $__len, $__format_text_ref, $__indent + 3) if ($__len > 0); $__buffer_size -= (2 + $__len); return ($__buffer_size); } sub __parse_bytes_len3 ($$$$$$;$$) { #? parses a len3 bytes field my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $__next_data = ""; my $__len; my $__len1; my $__len2; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_len3 for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 3); ($__len1, #C $__len2, #n $$__buffer_ref) = unpack("C n a*", $$__buffer_ref); $__len = $__len1 << 16; $__len += $__len2; _trace2_ (_decode_val ("%06X", \$__len, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); $$__format_pos_ref++; # Next format element ($__next_data, #a[$len] $$__buffer_ref) = unpack("a[$__len] a*", $$__buffer_ref); _parseAllBytes ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, \$__next_data, $__len, $__format_text_ref, $__indent + 3) if ($__len >0); $__buffer_size -= (3 + $__len); return ($__buffer_size); } sub __parse_bytes_raw ($$$$$$;$$) { #? parses a raw bytes field my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_hex_str = ""; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_raw for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 1); # nothing to parse return (0) if ($__buffer_size > length ($$__buffer_ref)); #TBD: Warn (my $__val, #n $$__buffer_ref) = unpack("a[$__buffer_size] a*", $$__buffer_ref); _trace2_ (_decode_val ("", \$__val, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); if ( (defined ($__param_hash_ref)) && (ref($__param_hash_ref) eq "HASH") ) { push @{$__param_hash_ref->{values}}, $__val; # array of values push @{$__param_hash_ref->{format_positions}}, $$__format_pos_ref; # array of format positions } # $__buffer_size = length ($$__buffer_ref); return (0); } sub __parse_bytes_sequence ($$$$$$;$$) { #? parses a sequence of bytes fields my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $__sequence_pos = 0; my %__sequence_param_hash; my $__sequence_param_hash_ref = (defined ($__param_hash_ref))? \%__sequence_param_hash : undef; # (condition)? : _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_sequence for '$__pdu_name' ($$__format_pos_ref, $__buffer_size):\n"); _trace4_ (_decode_val (undef, undef, $__format_text_ref->[$$__format_pos_ref], ($__indent + 3), ($__indent + 3), ":\n" . " " x ($__indent + 3), ",\n" . " " x ($__indent + 3), " | ", " / ") . "\n"); $$__format_pos_ref++; # Next format element $__sequence_pos = $$__format_pos_ref; # store start position of sequence my $_counter = 0; while (defined ($$__buffer_ref) && ($__buffer_size > 0)) { # still data $$__format_pos_ref = $__sequence_pos; # reset format_pos to first element of sequence format _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_sequence: (next) sequence elements for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n"); $__buffer_size = _parseAllBytes ($__pdu_name, $__format_ref, $__sequence_param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size, $__format_text_ref, $__indent); if ( (defined ($__param_hash_ref)) && (ref($__param_hash_ref) eq "HASH") ) { push @{$__param_hash_ref->{values}}, [$__sequence_param_hash_ref->{values}]; # array of array of values push @{$__param_hash_ref->{format_positions}}, $__sequence_param_hash_ref->{format_positions} if ($_counter++ == 0); # store format positions ony once } } _trace4_ (" " x $__indent); _trace4_ ("__parse_bytes_sequence for '$__pdu_name': ------ End of sequence ------\n"); return ($__buffer_size); } sub __parse_bytes_size1 ($$$$$$;$$) { #? parses a size1 bytes field and the next value(s) my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $__next_data = ""; my $__len = 0; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_size1 for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 1); ($__len, #C $$__buffer_ref) = unpack("C a*", $$__buffer_ref); _trace2_ (_decode_val ("%02X", \$__len, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); $$__format_pos_ref++; # Next format element ($__next_data, #a[$len] $$__buffer_ref) = unpack("a[$__len] a*", $$__buffer_ref); _parseNextByte ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, \$__next_data, $__len, $__format_text_ref, $__indent + 3) if ($__len >0); $__buffer_size -= (1 + $__len); return ($__buffer_size); } sub __parse_bytes_size2 ($$$$$$;$$) { #? parses a size2 bytes field and the next value(s) my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $__next_data = ""; my $__len = 0; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_size2 for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 2); ($__len, #n $$__buffer_ref) = unpack("n a*", $$__buffer_ref); _trace2_ (_decode_val ("%04X", \$__len, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); $$__format_pos_ref++; # Next format element ($__next_data, #a[$len] $$__buffer_ref) = unpack("a[$__len] a*", $$__buffer_ref); _parseNextByte ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, \$__next_data, $__len, $__format_text_ref, $__indent + 3) if ($__len >0); $__buffer_size -= (2 + $__len); return ($__buffer_size); } sub __parse_bytes_val1 ($$$$$$;$$) { #? parses a val1 bytes value my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_val1 for '$__pdu_name': ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 1); (my $__val, #C $$__buffer_ref) = unpack("C a*", $$__buffer_ref); _trace2_ (_decode_val ("%02X", \$__val, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); if ( (defined ($__param_hash_ref)) && (ref($__param_hash_ref) eq "HASH") ) { push @{$__param_hash_ref->{values}}, $__val; # array of values push @{$__param_hash_ref->{format_positions}}, $$__format_pos_ref; # array of format positions } $__buffer_size -= 1; return ($__buffer_size); } sub __parse_bytes_val2 ($$$$$$;$$) { #? parses a val2 bytes value my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_val2 for '$__pdu_name': ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 2); (my $__val, #n $$__buffer_ref) = unpack("n a*", $$__buffer_ref); _trace2_ (_decode_val ("%04X", \$__val, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); if ( (defined ($__param_hash_ref)) && (ref($__param_hash_ref) eq "HASH") ) { push @{$__param_hash_ref->{values}}, $__val; # array of values push @{$__param_hash_ref->{format_positions}}, $$__format_pos_ref; # array of format positions } $__buffer_size -= 2; return ($__buffer_size); } sub __parse_bytes_val4 ($$$$$$;$$) { #? parses a val4 bytes value my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_val4 for '$__pdu_name': ($$__format_pos_ref, $__buffer_size)\n"); return (0) if ($__buffer_size < 4); (my $__val, #N $$__buffer_ref) = unpack("N a*", $$__buffer_ref); _trace2_ (_decode_val ("%08X", \$__val, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x $__indent, " | ", " / ") . "\n"); if ( (defined ($__param_hash_ref)) && (ref($__param_hash_ref) eq "HASH") ) { push @{$__param_hash_ref->{values}}, $__val; # array of values push @{$__param_hash_ref->{format_positions}}, $$__format_pos_ref; # array of format positions } $__buffer_size -= 4; return ($__buffer_size); } sub __parse_bytes_val1List ($$$$$$;$$) { #? parses a list of val1 byte values my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_val1List for '$__pdu_name': ($$__format_pos_ref, $__buffer_size):\n"); return (0) if ($__buffer_size < 1); (my $__data, #(a) $$__buffer_ref) = unpack("a[$__buffer_size] a*", $$__buffer_ref); (my @__list) = unpack("C*", $__data); #C _trace2_ (_decode_val ("%02X", \@__list, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x ($__indent + 2), " | ", " / ") . "\n"); if ( (defined ($__param_hash_ref)) && (ref($__param_hash_ref) eq "HASH") ) { push @{$__param_hash_ref->{values}}, [@__list]; # array of array of values push @{$__param_hash_ref->{format_positions}}, $$__format_pos_ref; # array of format positions } $__buffer_size -= (@__list); # 0 return ($__buffer_size); } sub __parse_bytes_val2List ($$$$$$;$$) { #? parses a list of val2 bytes values my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; _trace4_ (" " x $__indent); _trace4 ("__parse_bytes_val2List for '$__pdu_name': ($$__format_pos_ref, $__buffer_size):\n"); return (0) if ($__buffer_size < 2); (my $__data, #(a) $$__buffer_ref) = unpack("a[$__buffer_size] a*", $$__buffer_ref); (my @__list) = unpack("n*", $__data); #n _trace2_ (_decode_val ("%04X", \@__list, $__format_text_ref->[$$__format_pos_ref], $__indent, $__indent, ":\n" . " " x $__indent, ",\n" . " " x ($__indent + 2), " | ", " / ") . "\n"); if ( (defined ($__param_hash_ref)) && (ref($__param_hash_ref) eq "HASH") ) { push @{$__param_hash_ref->{values}}, [@__list]; # array of array of values push @{$__param_hash_ref->{format_positions}}, $$__format_pos_ref; # array of format positions } $__buffer_size -= 2 * (@__list); # 0 return ($__buffer_size); } # Hash with all subs __parse_bytes_*_ #? A self defined general description for the structure of for PDUs, e.g. tls extensions: #? len1: Len of the next bytes, coded in 1 byte (-> max 0xFF) #? len2: Len of the next bytes, coded in 2 bytes (-> max 0xFFFF) #? len3: Len of the next bytes, coded in 3 bytes (-> max 0xFFFFFF) #? size1: Size of the next value, coded in 1 byte (-> max 0xFF) #? size2: Size of the next value, coded in 2 bytes (-> max 0xFFFF) #? val1: value, coded in 1 byte (-> max 0xFF) #? val2: value, coded in 2 bytes (-> max 0xFFFF) #? val4: value, coded in 4 byters (-> max 0xFFFFFFFF) #? val1List: List of value, coded in 1 byte (-> max 0xFF, 0xFF, ...) #? val2List: List of value, coded in 2 bytes (-> max 0xFFFF, 0xFFFF, ...) #? raw: Raw bytes (number needs to be previously defined by a len or size element) #? sequence: Sequence of structured elements that form lists of compound values my %__parse_bytes_subs = ( len1 => \&__parse_bytes_len1, len2 => \&__parse_bytes_len2, len3 => \&__parse_bytes_len3, raw => \&__parse_bytes_raw, sequence => \&__parse_bytes_sequence, size1 => \&__parse_bytes_size1, size2 => \&__parse_bytes_size2, val1 => \&__parse_bytes_val1, val2 => \&__parse_bytes_val2, val4 => \&__parse_bytes_val4, val1List => \&__parse_bytes_val1List, val2List => \&__parse_bytes_val2List, ); sub _parseNextByte ($$$$$$;$$) { #? parse the next byte(s) my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; my $_hex_str = ""; _trace5_ (" " x ($__indent). "_parseNextByte for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n" ); return ($__buffer_size) if ($$__format_pos_ref >= (@$__format_ref)); return (0) if (! defined ($__format_ref->[$$__format_pos_ref]) ); return (0) if ($__buffer_size < 1); if ($__parse_bytes_subs{$__format_ref->[$$__format_pos_ref]}) { $__buffer_size = $__parse_bytes_subs{$__format_ref->[$$__format_pos_ref]}->($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size, $__format_text_ref, $__indent); } else { carp ("**WARNING: Net::SSLhello::_parseNextByte ($__pdu_name): \'No such format sub: $__format_ref->[$$__format_pos_ref]\', => Please verify hash format definition in osaft.pm e.g. in \%TLS_EXTENSIONS"); } $$__format_pos_ref++; # Next format element return ($__buffer_size); } sub _parseAllBytes ($$$$$$;$$) { #? parse all byte(s) according the $__buffer_size my ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_), shift(@_), shift(@_)); my $__format_text_ref = shift(@_); my $__indent = shift(@_) || 0; _trace5_ (" " x ($__indent). "_parseAllBytes for '$__pdu_name' ($$__format_pos_ref, $__buffer_size)\n"); while ( ($$__format_pos_ref < (@$__format_ref)) && (defined ($__format_ref->[$$__format_pos_ref])) && ($__buffer_size > 0) ) { $__buffer_size = _parseNextByte ($__pdu_name, $__format_ref, $__param_hash_ref, $__format_pos_ref, $__buffer_ref, $__buffer_size, $__format_text_ref, $__indent); } return ($__buffer_size); } #? END of: sub subs that parse parts of records, e.g. bytes for extensions #################### sub _parseExtensions ($$$$;$$) { #? Parse one or more TLS extensions according %osaft::TLS_EXTENSIONS and its reverse hash %osaft::TLS_ID_TO_EXTENSIONS #? and store the values in the hash $_param_hash_ref->{$_extension}{$_ext_ch_rx} if defined #? redundant values and value arrays are skipped #? $_ext_ch_rx: Clienthello 'CH' or received record 'RX' #? $_param_hash_ref: Reference to a hash where store the parsed results or undef if not needed #? $_buffer_ref: Reference to the data buffer that will be parsed #? $_buffer_size: size of the buffer: #? >=0: The extension data starts with the first extension or is empty #? < 0: The extension data starts with the length field for all extensions #? optional: #? $protocolCipher: internal Hex value of the cipher, for tracing #? $_indent: indent for tracing, default = 12 #? --------------------------------------------------------------------------- my ($_ext_ch_rx, $_param_hash_ref, $_buffer_ref, $_buffer_size) = (shift(@_), shift(@_), shift(@_), shift(@_)); my $protocolCipher = shift(@_) || ""; my $_indent = shift(@_) || 12; my $_format_pos = 0; my $_name = "_parseExtensions: "; my $_extensions_data = $$_buffer_ref; # do not chance referenced data my @__local_format_text = ( \%osaft::TLS_ID_TO_EXTENSIONS ); # array with a reference to the reverse TLS_EXTENSIONS hash my $__local_format_pos = 0; # use first element to decode extension type _trace4_ (" " x $_indent . "# SSLhello::_parseExtensions ():\n"); if (($_buffer_size < 0) && (length ($_extensions_data) > 2)) { # get the 2 bytes len from $_extension_data ($_buffer_size, #n $_extensions_data) = unpack("n a*", $_extensions_data); _trace2_ (_decode_val ("%04X", \$_buffer_size, "length of extensions", $_indent, $_indent, ":\n" . " " x $_indent, ",\n" . " " x $_indent, " | ", " / ") . "\n"); $_indent += 3; } PARSE_EXTENSION: while ($_buffer_size > 2) { $__local_format_pos = 0; # no extension type selected, yet $_format_pos = 0; # reset to first format element of an extension type my %_extension_type_hash; $_extension_type_hash{values} = (); # reset array to store values $_extension_type_hash{format_positions} = (); # reset array to store format positions $_buffer_size = __parse_bytes_val2 ($_name, undef, \%_extension_type_hash, \$__local_format_pos, \$_extensions_data, $_buffer_size, \@__local_format_text, $_indent); # get extensions type if (!defined ($_extension_type_hash{values}[0])) { # found no extension carp ("**WARNING: Net::sslHello::_parseExtensions: warn: no (more) defined extensionus found parsing the record\n"); next PARSE_EXTENSION; } my $_extension = $osaft::TLS_ID_TO_EXTENSIONS{$_extension_type_hash{values}[0]}[0]; # get Extension type from $extension{description}[0] $_extension = "-- unknown (" . $_extension_type_hash{values}[0] . ") --" if (!defined ($_extension)); _trace5_ (" " x ($_indent + 4) . "== Extension '$_extension' ($_extension_type_hash{values}[0]):\n"); my %_param_hash; $_param_hash{values} = (); # initialize array to store values $_param_hash{format_positions} = (); # initialize array to store format positions $_buffer_size = _parseAllBytes ($_extension, \@{$osaft::TLS_EXTENSIONS{$_extension}{$_ext_ch_rx}}, \%_param_hash, \$_format_pos, \$_extensions_data, $_buffer_size, \@{$osaft::TLS_EXTENSIONS{$_extension}{"$_ext_ch_rx"."_TEXT"}}, $_indent + 3); next PARSE_EXTENSION if (!defined ($_param_hash_ref));# do not store the results _trace5_ (" " x ($_indent + 4) . "# ---> _parseExtensions: ref (\$_param_hash_ref) = " . ref ($_param_hash_ref) ."\n" );# next PARSE_EXTENSION if (ref ($_param_hash_ref) ne "HASH"); # reference is no hash _trace5_ (" " x ($_indent + 4) . "# ---> format: \@{\$_param_hash{format_positions}} = " . _decode_val (undef, \@{$_param_hash{format_positions}}, undef, 0, $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n"); _trace5_ (" " x ($_indent + 4) . "# ---> raw value: \@{\$_param_hash{values}} = " . _decode_val (undef, \@{$_param_hash{values}}, undef, 0, $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n"); _trace5_ (" " x ($_indent + 4) . "# ---> Complex format: (\@{\$_param_hash{format_positions}}) = " . (@{$_param_hash{format_positions}}) . " > 1?\n"); if ( (@{$_param_hash{format_positions}}) > 1) { # complex format => array of arrays @{$_param_hash{values}} = [@{$_param_hash{values}}]; # store values of complex parameter formats as array of arrays } elsif (ref ($_param_hash{values}[0]) eq 'ARRAY') { # simple format for 1 format results @{$_param_hash{values}} = $_param_hash{values}[0]; # so one answer with val1/2List = multible anwers with val1 or val2 } _trace5_ (" " x ($_indent + 4) . "# ---> standardized value(s): \@{\$_param_hash{values}} = " . _decode_val (undef, \@{$_param_hash{values}}, undef, 0, $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n"); # ready to store value if (! exists($_param_hash_ref->{$_extension}{$_ext_ch_rx}) ) { # first %_param_hash _trace4_ (" " x ($_indent + 4) . "# ===> store first results in \%{\$_param_hash_ref->{$_extension}{$_ext_ch_rx}}\n"); $_param_hash_ref->{$_extension}{$_ext_ch_rx} = \%_param_hash; # add sub hash to $_param_hash_ref->{$_extension}{$_ext_ch_rx} _trace4_ (" " x ($_indent + 4) . "# ===> value(s): \@{\$_param_hash{values}} = " . _decode_val (undef, \@{$_param_hash{values}}, undef, 0, $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n"); _trace4_ (" " x ($_indent + 4) . "# ===> format(s): \@{\$_param_hash{format_positions}} = " . _decode_val (undef, \@{$_param_hash{format_positions}}, undef, 0, $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n"); } else { # check if formats are identical and if values have not been stored before _trace5_ (" " x ($_indent + 4) . "# ---> Check if format is a SCALAR: ref (\\\$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}[0]) = '" . ref (\$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}[0]) . "'\n"); _trace5_ (" " x ($_indent + 4) . "# ---> Check if format is a nested array: ref (\$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}[0]) = '" . ref ($_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}[0]) . "'\n"); if (ref (\$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}[0]) eq 'SCALAR') { # format is no nested array _trace5_ (" " x ($_indent + 4) . "# ---> merge new results and format_positions with hash '\$_param_hash_ref->{$_extension}{$_ext_ch_rx}}'\n"); my $found = 1; # 1: true _trace5_ (" " x ($_indent + 4) . "# ---> (\@{\$_param_hash{format_positions}}) (" . (@{$_param_hash{format_positions}}) . ") == (\@{\$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}}) ) (" . (@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}}) . ")?\n"); next PARSE_EXTENSION if ( (@{$_param_hash{format_positions}}) == 0); # format is empty = nothing to add => parse next extension if ( (@{$_param_hash{format_positions}}) == (@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}}) ) { # the number of format_positions is identical: necessary condition CHECK_FORMAT: for (my $__pos = 0; $__pos < (@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}}); $__pos++) { # check if all format positions are identical _trace5_ (" " x ($_indent + 4) . "# ---> \$_param_hash{format_positions}[$__pos] (" . $_param_hash{format_positions}[$__pos] . ") == \$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}[$__pos] (" . $_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}[$__pos] . ")?\n"); if ($_param_hash{format_positions}[$__pos] ne $_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}[$__pos]) { # format is not equal # TBD: different format: move stored format to 1st emement of a nested array, add new sequence of new formats to 2nd element; Do the same with the values _trace4_ (" " x ($_indent + 4) . "# ---> merging values and format_positions to the result hash with different format sequences is not yet implemented! New values are lost: " . _decode_val (undef, \@{$_param_hash{values}}, $osaft::TLS_EXTENSIONS{$_extension}{"$_ext_ch_rx"."_TEXT"}[$_format_pos], 0, $_indent + 17, ", ", " | ", " / ") . "\n"); carp ("**WARNING: SSLhello::_parseExtensions: merging values and format_positions to the result hash with different format sequences is not yet implemented! New values are lost: " . _decode_val (undef, \@{$_param_hash{values}}, $osaft::TLS_EXTENSIONS{$_extension}{"$_ext_ch_rx"."_TEXT"}[$_format_pos], 0, $_indent + 17, ", ", " | ", " / ") ."\n"); $found = 0; # false last CHECK_FORMAT; # exit the loop } } # CHECK_FORMAT: for ... if ($found > 0) { # format is identical _trace5_ (" " x ($_indent + 4) . "# ---> check for new results to be stored in '\$_param_hash_ref->{$_extension}{$_ext_ch_rx}}'\n"); _trace5_ (" " x ($_indent + 4) . "# ---> number of values to check: (\@{\$_param_hash{values}}) (" . (@{$_param_hash{values}}) . ") <=> (\@{\$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}}) ) (" . (@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}}) . ")?\n"); next PARSE_EXTENSION if ( (@{$_param_hash{values}}) == 0); # values are empty = nothing to add => parse next extension FOREACH_NEW_VALUE: foreach my $_new_ele (@{$_param_hash{values}}) { # all new values or arrys of values _trace5_ (" " x ($_indent + 4)."# ---|> new values-ref-type (\\\$new_ele): >".ref(\$_new_ele)."<|\n"); _trace5_ (" " x ($_indent + 4)."# --||> new values-ref-type (\$new_ele): >".ref($_new_ele)."<||\n"); FOREACH_STORED_VALUE: foreach my $_stored_ele (@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}}) { # all stored values or arrys of values _trace5_ (" " x ($_indent + 4)."# ---|> stored values-ref-type (\\\$stored_ele): >".ref(\$_stored_ele)."<|\n"); _trace5_ (" " x ($_indent + 4)."# --||> stored values-ref-type (\$stored_ele): >".ref($_stored_ele) ."<||\n"); if ( (ref (\$_new_ele) eq "SCALAR") && (ref (\$_stored_ele) eq "SCALAR") ) { # both arrays are an simple array _trace5_ (" " x ($_indent + 4)."# ---> check if value is new (\$new_ele): '" . _decode_val (undef, \$_new_ele, undef, 0, $_indent + 4, ", ", " | ", " / ") . "' == (\$_stored_ele): '" . _decode_val (undef, \$_new_ele, undef, 0, $_indent + 4, ", ", " | ", " / ") . "'?\n"); next FOREACH_STORED_VALUE if ($_new_ele ne $_stored_ele); # value is identical _trace5_ (" " x ($_indent + 4) . "# ---> \$_new_ele (" . _decode_val (undef, \$_new_ele, undef, 0, $_indent + 4, ", ", " | ", " / ") . ") has been alteady stored. Try next ele.\n"); next FOREACH_NEW_VALUE; } elsif ( (ref ($_new_ele) eq "ARRAY") && (ref ($_stored_ele) eq "ARRAY") ) { # both arrays are nested arrays (arrays of arrays) FOREACH_POSITION: foreach my $__pos (0..$#{$_param_hash{format_positions}}) { # all values = all format positions _trace5_ (" " x ($_indent + 4) . "# ---> \$_new_ele[$__pos] (" . _decode_val (undef, \@{$_new_ele}[$__pos], undef, 0, $_indent + 4, ", ", " | ", " / ") . ") == \$_stored_ele[$__pos] (" . _decode_val (undef, \@{$_stored_ele}[$__pos], undef, 0, $_indent + 4, ", ", " | ", " / ") . ")?\n"); next FOREACH_STORED_VALUE if (@{$_new_ele}[$__pos] ne @{$_stored_ele}[$__pos]); # value is not equal } # FOREACH_POSITION # all positions are identical next FOREACH_NEW_VALUE; # check next new value } else { _trace (" " x ($_indent + 4)."**WARNING: Net::sslHello::_parseExtensions: internal error in result hash: new values-ref-type (\$_new_ele): ".ref(\$_new_ele)."<| != (\$_stored_ele): ".ref(\$_stored_ele)."<| OR both neiter a SCALAR nor an ARRAY\n"); carp ("**WARNING: Net::sslHello::_parseExtensions: internal error in result hash: can't compare and store new values: " . _decode_val (undef, \$_new_ele, undef, 0, $_indent + 4, ", ", " | ", " / ") . "\n"); next FOREACH_NEW_VALUE; # check next new value # TBD check if 'next' should change to 'last'? } # if ref \$new_ele ... } # FOREACH_STORED_VALUE # new_ele is new => store a new value array _trace4_ (" " x ($_indent + 4) . "# ===> add new value (array) to the result hash: " . _decode_val (undef, \$_new_ele, undef, 0, $_indent + 4, ", ", " | ", " / ") . "\n"); push @{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}}, $_new_ele; # store new value array to nested result array } # FOREACH_NEW_VALUE } } # number of format positions is identical } else { # nested format arrays => not used and not implemented, yet! _trace4_ (" " x ($_indent + 4) . "# ---> merging values and format_positions to the result hash with various formats is not yet implemented! New values are lost: " . _decode_val (undef, \@{$_param_hash{values}}, undef, 0, $_indent + 17, ", ", " | ", " / ") ."\n"); carp ("**WARNING: SSLhello::_parseExtensions: merging values and format_positions to the result hash with various formats is not yet implemented! New values are lost: " . _decode_val (undef, \@{$_param_hash{values}}, undef, 0, $_indent + 17, ", ", " | ", " / ") ."\n"); } } # end of check if formats are identical and if values have not been stored before _trace5_ (" " x ($_indent + 4) . "# -> values = " . @{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}} . "\n"); _trace5_ (" " x ($_indent + 4) . "# -> format_positions = " . @{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}} . "\n"); _trace5_ (" " x ($_indent + 4) . "# ---> _parseExtensions: \@{\$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}} = " . _decode_val (undef, \@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}}, undef, 0 , $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n"); _trace5_ (" " x ($_indent + 4) . "# ---> _parseExtensions: \@{\$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions} = " . _decode_val (undef, \@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}}, undef, 0 , $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n\n"); _trace2_ (" " x ($_indent + 4) . "# ===> Cipher '$protocolCipher', Extension '$_extension': accumulated $_ext_ch_rx values (" . @{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}} . "): " . _decode_val (undef, \@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{values}}, undef, 0 , $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n"); _trace2_ (" " x ($_indent + 4) . "# ===> Cipher '$protocolCipher', Extension '$_extension': $_ext_ch_rx format positions (" . @{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}} . "): " . _decode_val (undef, \@{$_param_hash_ref->{$_extension}{$_ext_ch_rx}{format_positions}}, undef, 0 , $_indent + 4, ":\n" . " " x ($_indent + 4), ", ", " | ", " / ") . "\n\n"); } # end of PARSE_EXTENSION } # _parseExtensions sub _doCheckAllExtensions ($$$$;$) { #? simulate SSL handshake to check any extensions for a dedicated cipher #? called by checkSSLciphers to check some extensions by the call # my $host = shift || ""; # hostname my $port = shift || 443; my $protocol = shift || 0; # 0x0002, 0x3000, 0x0301, 0x0302, 0x0303, etc my $cipher = shift || ""; my $dtls_epoch = shift || 0; # optional, used in DTLS only my $parseAllRecords = 1; # read, parse and analyse all received records (-> 1) my $found_values = 0; my $acceptedCipher; my $_last_extension = ""; my $protocolCipher = '0x0300'.hexCodedCipher($cipher); _trace4_ ("_doCheckAllExtensions {(Cipher: " . hexCodedCipher($cipher) . "):\n"); return if (!$cipher); foreach my $_extension (@{$Net::SSLhello::check_extensions}) { _trace4_ ("# ---> _doCheckAllExtensions: extension '$_extension': "); next if ( (! exists ($_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values})) || ((@{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}}) < 1) ); $_last_extension = $_extension; for (my $_i = 0; $_i < (@{$osaft::TLS_EXTENSIONS{$_extension}{DEFAULT}} ); $_i++) { # copy all values of 2 dim array for (my $_j = 0; $_j < (@{$osaft::TLS_EXTENSIONS{$_extension}{DEFAULT}[$_i]} ); $_j++) { $Net::SSLhello::extensions_params_hash{$_extension}[$_i][$_j] = $osaft::TLS_EXTENSIONS{$_extension}{DEFAULT}[$_i][$_j]; # copy default value } _trace5_ (" (copied values = [$_i][" . (@{$Net::SSLhello::extensions_params_hash{$_extension}[$_i]}) . "], "); } _trace5_ (" parameter arrays = " . (@{$Net::SSLhello::extensions_params_hash{$_extension}}) . "/" . (@{$osaft::TLS_EXTENSIONS{$_extension}{DEFAULT}}) . ", "); _trace5_ (" format_positions = " . (@{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{format_positions}}) . ", ") if (exists ($_SSLhello{$protocolCipher}{param}{$_extension}{RX}{format_positions}) ); _trace5_ (" found values = " . (@{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}}) ) if (exists ($_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}) ); _trace5_ ("):\n"); if ((@{$osaft::TLS_EXTENSIONS{$_extension}{DEFAULT}}) == 1) { ## if ( ((@{$osaft::TLS_EXTENSIONS{$_extension}{DEFAULT}}) == 1) ## && (exists ($Net::SSLhello::{param}{$_extension}{RX}{format_positions}) ) ## && ((@{$Net::SSLhello::{param}{$_extension}{RX}{format_positions}}) == 1)) { # only one parameter array ([0][x]) as default and only one dimensional result array ### } _trace5_ ("# ---> extension '$_extension':\n"); $found_values = 0; while ( (exists ($_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values})) && ((@{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}}) > $found_values) ) { # received a new value _trace5_ ("# ---> parameter arrays[0] = " . (@{$Net::SSLhello::extensions_params_hash{$_extension}[0]}) . "/" . (@{$osaft::TLS_EXTENSIONS{$_extension}{DEFAULT}[0]}) . "\n"); _trace5_ ("# ---> parameter values type = " . (ref($_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values})) . "\n"); last if (!defined($_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}->[$#{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}}]) ); # found value is not defined => Exit Loop last if (!(grep { $_ eq $_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}->[$#{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}}] } @{$Net::SSLhello::extensions_params_hash{$_extension}[0]})); # found value has NOT been in the offered list => Exit Loop $found_values++; _trace5_ ("# ---> extension found $found_values value(s) " . _decode_val (undef, \@{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}}, \%osaft::TLS_EXTENSIONS{$_extension}, 12, 12, ": ", ", ", " | ", " / ") . "\n"); @{$Net::SSLhello::extensions_params_hash{$_extension}[0]} = grep { $_ ne $_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}->[$#{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}}] } @{$Net::SSLhello::extensions_params_hash{$_extension}[0]}; # delete accepted cipher from ToDo-Array '@cipherSpecArray' _trace5_ ("# ---> extensions_params_hash: " . _decode_val (undef, \@{$Net::SSLhello::extensions_params_hash{$_extension}[0]}, \%osaft::TLS_EXTENSIONS{$_extension}, 12, 12, ": ", ", ", " | ", " / ") . "\n"); last if ( (@{$Net::SSLhello::extensions_params_hash{$_extension}[0]}) < 1); # no more elements to check if ($found_values > $Net::SSLhello::extensions_max_values) { ## protect ftom staying in an endless loop _trace2_ ("**WARNING: SSLhello::_doCheckAllExtension ($_extension): To much checks for this extension. Watchdog aborted checks after getting $found_values values.\n**Hint: Please verify the hash '%osaft::TLS_EXTENSIONS' and the variable '\$Net::SSLhello::check_extensions', or '\$Net::SSLhello::extensions_max_values' if necessary.\n"); carp ("**WARNING: SSLhello::_doCheckAllExtension ($_extension): To much checks for this extension. Watchdog aborted checks after getting $found_values values.\n**Hint: Please verify the hash '%osaft::TLS_EXTENSIONS' and the variable '\$Net::SSLhello::check_extensions', or '\$Net::SSLhello::extensions_max_values' if necessary.\n"); last; ## protect ftom staying in an endless loop } _trace5_ ("# ---> check next extension '$_extension' parameter for cipher: " . hexCodedCipher($cipher) . ":\n"); $acceptedCipher = _doCheckSSLciphers($host, $port, $protocol, $cipher, $dtls_epoch, $parseAllRecords); _trace5_ ("# ---> received cipher: " . hexCodedCipher($acceptedCipher) . " == " . hexCodedCipher($cipher) . "?\n"); last if ($acceptedCipher ne $cipher); _trace5_ ("# ---> next while (" . (@{$_SSLhello{$protocolCipher}{param}{$_extension}{RX}{values}}) . " > $found_values)\n"); } _trace1_ ("# _doCheckAllExtensions (Cipher: " . hexCodedCipher($cipher) . ") ==> extension '$_extension': found $found_values values.\n"); } else { _trace_ ("SSLhello::_doCheckAllExtensions ($_extension): Detailled checks for extensions with multiple parameters are not supported, yet. Please check variable '\$Net::SSLhello::check_extensions')."); carp ("**WARNING: SSLhello::_doCheckAllExtensions ($_extension): Detailled checks for extensions with multiple parameters are not supported, yet. Please check variable '\$Net::SSLhello::check_extensions')."); } delete ($Net::SSLhello::extensions_params_hash{$_extension}); # delete temporary hash } delete ($Net::SSLhello::extensions_params_hash{$_last_extension}) if (defined ($Net::SSLhello::extensions_params_hash{$_last_extension})); # delete temporary hash } # _doCheckAllExtensions =pod =head2 parseServerKeyExchange( ) Manually parse a Server Kex Exchange packet and detect KeyExchange length, according https://tools.ietf.org/html/rfc5246#section-7.4.3 - DHE: 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: check for the most prioritized Curve (supported_group): ~ RFC 8422: Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS) Versions 1.2 and Earlier - RSA: RFC 6101: The Secure Sockets Layer (SSL) Protocol Version 3.0, e.g. EXPORT ciphers - PSK: Pre-Shared Keys can be used alone or in combination with all other 3 server key types: ~ RFC 4279: Pre-Shared Key Ciphersuites for Transport Layer Security (TLS), ~ RFC 4785: Pre-Shared Key (PSK) Ciphersuites with NULL Encryption for Transport Layer Security (TLS), ~ RFC 5487: Pre-Shared Key Cipher Suites for TLS with SHA-256/384 and AES Galois Counter Mode, ~ RFC 5489: ECDHE_PSK Cipher Suites for Transport Layer Security (TLS) =cut sub parseServerKeyExchange($$$) { #? parse a ServerKeyExchange packet to detect length of DHparam, ECDHE 'supprted_group', RSA Key length, optional usage of PSK #? Test PSK ciphers locally with: "openssl s_server -4 -psk 1a2b3c4d -psk_hint 01020304 -nocert -www -msg" #? Verfied size of DHparam etc manually with "openssl s_client -showcerts -msg -psk 1a2b3c4d -tls1_2 -cipher 'DHE-PSK-AES128-CBC-SHA' -connect localhost:4433" #? TBD: parsie independant from cipher name; could be needed for TLSv13 my ($keyExchange, $len, $d) = @_; my ($_tmpLen, $_null, $_handshake_type, $_bits) = 0; my %_mySSLinfo; my $psk = ""; # set to postfix '_psk' if PSK is additionally used. _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 ("-- Error in ServerKeyExchange --", "", undef) if ($len != $_tmpLen); if ($keyExchange =~ /PSK/) { # PSK-Cipher => 'Prefix': psk_identity_hint, rfc4279) ($_mySSLinfo{'psk_identity_hint_len'}, # n $d) = unpack("n a*", $d); ($_mySSLinfo{'psk_identity_hint'}, # a[$_mySSLinfo{'psk_identity_hint_len'}] $d) = unpack("a[$_mySSLinfo{'psk_identity_hint_len'}] a*", $d); $_mySSLinfo{'psk_identity_hint'} = unpack ("H*", $_mySSLinfo{'psk_identity_hint'}); # Convert to a readable HEX-String _trace2( sprintf ( " PSK Key Exchange (len=%d):\n". "# --> psk_identity_hint: (len=%4d) >%s<\n", $len, $_mySSLinfo{'psk_identity_hint_len'}, $_mySSLinfo{'psk_identity_hint'} )); if ($keyExchange =~ /^PSK/x) { # nothing more to do _trace4("parseServerKeyExchange: PSK_serverParam\n"); _trace2("parseServerKeyExchange() done.\n"); return ("psk", "" , undef); } $psk = "_psk"; # set '_psk' as postfix for the following ServerKeyExchanges $len -= ($_mySSLinfo{'psk_identity_hint_len'}+2); $keyExchange =~ s/^((?:EC)?DH)(?:_PSK)?.*/$1/x; # EDH_PSK -> DH, ADH_PSK -> DH, EECDH_PSK -> ECDH _trace2_ (" --> KeyExchange (DH, ECDH) = $keyExchange\n"); # => ECDH or DH, or ECDH_PSK o DH_PSK } # PSK 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'} = $_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 ("dh" . $psk, $_mySSLinfo{'DH_serverParam'}, undef); } elsif ($keyExchange eq "ECDH") { # check for the selected Curve (supported_group) # TBD verify if this is the default check for TLSv13? ($_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'} = "<>"; # set a default value $_mySSLinfo{'ECDH_serverParam'} = $osaft::TLS_SUPPORTED_GROUPS{$_mySSLinfo{'ECDH_namedCurve'}}[0] ." (". $osaft::TLS_SUPPORTED_GROUPS{$_mySSLinfo{'ECDH_namedCurve'}}[1] . " bits)" if ( defined ($osaft::TLS_SUPPORTED_GROUPS{$_mySSLinfo{'ECDH_namedCurve'}}[0]) ); _trace4("parseServerKeyExchange: ECDH_serverParam supported group: '" . $_mySSLinfo{'ECDH_serverParam'} . "'\n"); _trace2("parseServerKeyExchange() done.\n"); return ("ecdh" . $psk . " supported_group(s)", $_mySSLinfo{'ECDH_serverParam'}, $_mySSLinfo{'ECDH_namedCurve'}); # $_mySSLinfo{'ECDH_namedCurve'} will be returned to be deleted from extensions list supported_groups } 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'} = "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'} = "explicite_char2: <>"; } else { $_mySSLinfo{'ECDH_serverParam'} = "<>"; } _trace4("parseServerKeyExchange: ECDH_serverParam: '".$_mySSLinfo{'ECDH_serverParam'}."'\n"); _trace2("parseServerKeyExchange() done.\n"); return ("ecdh" . $psk, $_mySSLinfo{'ECDH_serverParam'}, undef); } 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'} = $_bits ." bits"; # manually generate the same message that is generated by openssl >= 1.0.2 but here with 'rsa' in small letters _trace4("parseServerKeyExchange: RSA_serverParam: ".$_mySSLinfo{'RSA_serverParam'}."\n"); _trace2("parseServerKeyExchange() done.\n"); return ("rsa" . $psk, $_mySSLinfo{'RSA_serverParam'}, undef); } 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 ("-- unsupported KeyExchange --" . $psk, "", undef); } } # 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 $buffer = ""; # temporarily store data of next record if alredy available my $rest = ""; my $tmp_len = 0; my $message = ""; my $nextMessages = ""; my %serverHello; my $cipher = ""; my $keyExchange = ""; my $description = ""; my $lastMsgType = $HANDSHAKE_TYPE {'<>'}; #undefined my $lastProtocolCipher = '0x0300'.hexCodedCipher($lastCipher); local $my_error = ""; # reset error message my $sni = ""; my $client_ssl = $PROTOCOL_NAME_BY_HEX{$client_protocol}; if (! defined $client_ssl) { $client_ssl = "--unknown protocol--"; } #reset error_handler and set basic information for this sub OSaft::error_handler->reset_err( {module => ($SSLHELLO), sub => 'parseHandshakeRecord', print => ($Net::SSLhello::trace > 3), 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 ("", $lastMsgType, 0, "", parseSSL2_ServerHello ($host, $port, $message, $client_protocol)); # 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, #a[$recordLen}] $buffer) = unpack("a[$recordLen] a*", $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 ($nextMessages, $lastMsgType, 0, "", ""); # maybe later, if fragmented dtls messages will be isupported 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.$buffer, $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 $lastProtocolCipher = '0x0300'.hexCodedCipher($lastCipher); # return ("", $lastMsgType, 0,"", parseTLS_ServerHello ($host, $port, $message, $serverHello{'msg_len'},$client_protocol) ); # moved bebind the 'while-loop' _trace2_ ("# ==> found cipher: >$lastProtocolCipher<\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 ($rest.$buffer, $lastMsgType, $serverHello{'cookie_length'}, $serverHello{'cookie'},""); # TBD: check if .$buffer is really needed } } 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 {$lastProtocolCipher}[0]; if (defined ($keyExchange)) { # found a cipher _trace5_ (" --> Cipher(1): $keyExchange\n"); $keyExchange =~ s/((?:EC)?DHE?)_anon((_PSK)?).*/A$1$2/x; # DHE_anon -> EDH, ECDHE_anon -> AECDH, DHE_anon -> ADHE _trace5_ (" --> Cipher(2): $keyExchange\n"); $keyExchange =~ s/((?:EC)?DH)E((_PSK)?).*/E$1$2/x; # DHE -> EDH, ECDHE -> EECDH _trace5_ (" --> Cipher(3): $keyExchange\n"); $keyExchange =~ s/^(?:EXP[_-])?(?:E|A|EA)((?:EC)?DH(?:_PSK)?).*/$1/x; # EDH -> DH, ADH -> DH, EECDH -> ECDH; EDH_PSK -> DH_PSK, ADH_PSK -> DH_PSK, EECDH_PSK -> ECDH_PSK _trace2_ (" --> KeyExchange (DH, ECDH, DH_PSK or ECDH_PSK) = $keyExchange\n"); # => ECDH or DH, or ECDH_PSK o DH_PSK my ($_description, $_param, $_supported_group) = parseServerKeyExchange ($keyExchange, length($message), $message); if (defined ($_param)) { _trace2_("\n parseHandshakeRecord: $host:$port, $client_ssl, Cipher: $lastProtocolCipher -> SeverKey Type: $_description: $_param\n"); } _trace5_ ("# ---> values of 'supported_groups': " . _decode_val (undef, \@{$_SSLhello{$lastProtocolCipher}{param}{supported_groups}{RX}{values}}, \%osaft::TLS_EXTENSIONS{supported_groups}, 0, 12, ": ", ", ", " | ", " / ") . "\n"); push (@{$_SSLhello{$lastProtocolCipher}{param}{supported_groups}{RX}{values}}, $_supported_group) if ( (defined ($_supported_group)) && (!grep {$_supported_group eq $_ } @{$_SSLhello{$lastProtocolCipher}{param}{supported_groups}{RX}{values}}) ); # add new supported_group to array in the result hash _trace4_ ("# ---> found 'supported_groups': " . _decode_val (undef, \@{$_SSLhello{$lastProtocolCipher}{param}{supported_groups}{RX}{values}}, \%osaft::TLS_EXTENSIONS{supported_groups}, 0, 12, ": ", ", ", " | ", " / ") . "\n"); if (! exists ($_SSLhello{$lastProtocolCipher}{param}{ServerKey}{description}) ) { $_SSLhello{$lastProtocolCipher}{param}{ServerKey}{description} = $_description; $_SSLhello{$lastProtocolCipher}{param}{supported_groups}{RX}{format_positions}[0] = 1; # -> supported_groups{RX}[1] @{$_SSLhello{$lastProtocolCipher}{param}{ServerKey}{values}} = (); # define the hash; it may stay empty, e.g for PSK (only) keys } elsif ($_SSLhello{$lastProtocolCipher}{param}{ServerKey}{description} ne $_description) { ## Error in parseServerKeyExchange: found different types of ServerKeys for the same Cipher carp ("**WARNING: SSLhello::parseHandshakeRecord: found different types of ServerKeys for the same Cipher '$lastProtocolCipher': '$_description' != '" . $_SSLhello{$lastProtocolCipher}{param}{ServerKey}{description} . "'\n"); $_SSLhello{$lastProtocolCipher}{param}{ServerKey}{description} .= " ## " . $_description; # segregate next parameter with '##' $_param = " ## " . $_param; # segregate next parameter with '##' } push (@{$_SSLhello{$lastProtocolCipher}{param}{ServerKey}{values}}, $_param) if ( (defined ($_param)) && ($_param ne "") && (!grep {$_param eq $_ } @{$_SSLhello{$lastProtocolCipher}{param}{ServerKey}{values}}) ); # add new ServerKey parameters to an array in the result hash } else { # no cipher found _trace2 ("parseHandshakeRecord: No name found for cipher: >$lastProtocolCipher< -> counld NOT check the ServerKeyExchange\n"); push (@{$_SSLhello{$lastProtocolCipher}{param}{ServerKey}{values}}, "---unknown---"); } } elsif ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'certificate'}) { _trace2("parseHandshakeRecord: MessageType \"Certificate\" = ".sprintf("0x%02X", $serverHello{'msg_type'}) . " not yet analysed\n"); } elsif ($serverHello{'msg_type'} == $HANDSHAKE_TYPE {'certificate_request'}) { _trace2("parseHandshakeRecord: MessageType \"Certificate request\" = ".sprintf("0x%02X", $serverHello{'msg_type'}) . " not yet analysed\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 analysed\n"); } _trace2_("\n"); # next message } # while (nextMessages ne ""() return ($nextMessages.$buffer, $lastMsgType, 0, "", $cipher); } 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"); # 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: unrecognised_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' ($client_ssl): 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' ($client_ssl): 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 , "", ""); } elsif ($serverHello{'description'} == 0) { # closure alert: close_notify is suppressed _trace2_ ("parseHandshakeRecord: Server '$host:$port' ($client_ssl): received SSL/TLS closure alert (1) has been ignored: Description: $description ($serverHello{'description'})\n"); } else { _trace4_ ("**WARNING: parseHandshakeRecord: Server '$host:$port' ($client_ssl): received SSL/TLS warning (1): Description: $description ($serverHello{'description'})\n"); carp ("**WARNING: parseHandshakeRecord: Server '$host:$port' ($client_ssl): received SSL/TLS warning (1): Description: $description ($serverHello{'description'})\n"); } } elsif ($serverHello{'level'} == 2) { # fatal if ($serverHello{'description'} == 70) { # protocol_version(70): (old) protocol recognised but not supported, is suppressed OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'parse alert record (2)', message => sprintf ("unsupported protocol $client_ssl (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' ($client_ssl): 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' ($client_ssl): 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' ($client_ssl): 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' ($client_ssl): received unknown SSL/TLS error level ($serverHello{'level'}): Description: $description ($serverHello{'description'})\n"); } } if ($recordVersion == 0x0000) { # some servers use this dummy version to indicate that the requested version is not supported OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'parse alert record (1)', message => sprintf ("unsupported protocol $client_ssl (0x%04X) by $host:$port, answered with (0x%04X)", $client_protocol, $recordVersion), warn => 0, } ); return ("", $lastMsgType, 0 , "", ""); } } elsif ($recordType == $RECORD_TYPE {'change_cipher_spec'}) { $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{'payload'}, # a[$record len] $rest) = unpack("a[$recordLen] a*", $recordData); _trace2_ (sprintf ( "# --> Record-Type 'change_cipher_spec' [Len = %d]:\n". "# --> payload: >%s<\n", $recordLen, _sprintf_hex_val ("", \$serverHello{'payload'}, 37), )); return ($rest, $lastMsgType, 0 , "", ""); } elsif ($recordType == $RECORD_TYPE {'application_data'}) { $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{'application_data'}, # a[$record len] $rest) = unpack("a[$recordLen] a*", $recordData); _trace2_ (sprintf ( "# --> Record-Type 'application_data' [Len = %d]:\n". "# --> application_data: >%s<\n", $recordLen, _sprintf_hex_val ("", \$serverHello{'application_data'}, 37), )); } else { ################################ to get information about record types that are not parsed, yet ############################# _trace_ ("\n"); _trace_ ("**WARNING: parseHandshakeRecord: Server '$host:$port': Unknown SSL/TLS record type received that is not (yet) defined in Net::SSLhello.pm:\n"); _trace_ ("# Record type: Unknown value (0x".hexCodedString($recordType)."), not (yet) defined in Net::SSLhello.pm\n"); _trace_ ("# Record version: $recordVersion (0x".hexCodedString ($recordVersion).")\n"); _trace_ ("# Record len: $recordLen (0x".hexCodedString ($recordLen).")\n\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"); #($serverHello{'--unknown record type--'}, # a[$record len] # $rest) = unpack("a[$recordLen] a*", $recordData); return ("", $lastMsgType, 0 , "", ""); } return ($buffer, $lastMsgType, 0 , "", ""); } #End SSL3/TLS or DTLS } else { carp ("**WARNING: parseHandshakeRecord: Server '$host:$port': (no SSL/TLS record) : ".hexCodedString ($recordData)."\n"); ($serverHello{'--unknown record type--'}, # a[$record len] $rest) = unpack("a[$recordLen] a*", $recordData); return ($rest, $lastMsgType, 0 , "", ""); } carp ("**WARNING: parseHandshakeRecord: Server '$host:$port': Internal error: ".hexCodedString ($recordData)."\n"); ($serverHello{'--unknown record type--'}, # a[$record len] $rest) = unpack("a[$recordLen] a*", $recordData); return ($rest, $lastMsgType, 0 , "", ""); } # parseHandshakeRecord sub parseSSL2_ServerHello ($$$;$) { #? <> <> # FIXME: # Variable: String/Octett, 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 =pod =head2 parseTLS_ServerHello( ) # FIXME: missing =cut 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) #? 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 || ""; my $server_protocol = ""; my $rest = ""; my $rest2 = ""; my %serverHello; my $protocolCipher = ""; $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 > 3), 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 ( "# --> (legacy) 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'} )); _trace5_ ( 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'})."<"); } $protocolCipher = '0x0300'.hexCodedCipher($serverHello{cipher_spec}); if ($Net::SSLhello::trace > 3) { printTLSCipherList ($serverHello{'cipher_spec'}); } _trace2_ ( sprintf ( "\n# --> compression_method: >%02X<\n", $serverHello{'compression_method'} )); # check the tls extensions: my %_param_tmp_hash = (); %_param_tmp_hash = %{$_SSLhello{$protocolCipher}{param}} if (exists ($_SSLhello{$protocolCipher}{param}));# save the param hash, just in case of a protocol mismatch 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) )); _parseExtensions ("RX", \%{$_SSLhello{$protocolCipher}{param}}, \$serverHello{'extensions'}, $serverHello{'extensions_len'}, $protocolCipher); 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")); } } # Check the protocol version (client vs server) # $client_protocol = 0x0303 if ($client_protocol == 0x0304); # Quick Patch for TLS 1.2; TBD: DTLS!check record_protocol, extension_protocol # get version from extension 'supported_versions' if it has been received : if not use legacy version from record $server_protocol = (defined ($_SSLhello{$protocolCipher}{param}{supported_versions}{RX}{values}[$#{$_SSLhello{$protocolCipher}{param}{supported_versions}{RX}{values}}])) ? $_SSLhello{$protocolCipher}{param}{supported_versions}{RX}{values}[$#{$_SSLhello{$protocolCipher}{param}{supported_versions}{RX}{values}}] : $serverHello{'version'}; _trace5_ ( sprintf ( # added to check the supported version "# --> => check server SSL/TLS-Version: legacy: %04X / effective %04X vs client: %04X\n", $serverHello{'version'}, $server_protocol, $client_protocol )); if (defined ($client_protocol)) { if ($client_protocol != $server_protocol) { my $client_ssl = $PROTOCOL_NAME_BY_HEX{$client_protocol}; my $server_ssl = $PROTOCOL_NAME_BY_HEX{$server_protocol}; if (! defined $client_ssl) { $client_ssl = "--unknown protocol--"; } if (! defined $server_ssl) { $server_ssl = "--unknown protocol--"; } _trace5_ (" " x 9 . "# --> parseTLSServerHello Server '$host:$port': protocol mismatch (expected $client_ssl != $server_ssl). Restoring hash \%{\$_SSLhello{$protocolCipher}{cipher_spec}{param}}.\n"); $_SSLhello{$protocolCipher}{param} = \%_param_tmp_hash; if ($server_protocol == 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 $client_ssl (0x%04X) by $host:$port, answered with $server_ssl (0x%04X)", $client_protocol, $server_protocol), warn => 0, } ); } else { # unknown protocol OSaft::error_handler->new( { type => (OERR_SSLHELLO_ABORT_PROTOCOL), id => 'check record protocol (2)', message => sprintf ("unsupported protocol $client_ssl (0x%04X) by $host:$port, answered with $server_ssl (0x%04X)", $client_protocol, $server_protocol), warn => 0, } ); } return (""); } } else { carp ("**WARNING: parseTLS_ServerHello: server '$host:$port': internal error: All server protocol versions are accepted, because there is no information provided which version the client has requested.\n"); } _trace2_ ( sprintf ( # added to check the supported version "# --> The server '$host:$port': accepts the following cipher(s) with SSL3/TLS-version: >%04X<:\n", $server_protocol )); return ($serverHello{'cipher_spec'}); } else { return (""); } } # parseTLS_ServerHello 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 separate them 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 separate 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 separate 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 them 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/Octett, 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 > 3) { 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 > 3) { 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 #_____________________________________________________________________________ #_____________________________________________________________________ main __| sub _main_help { #? print own help # if ($#argv < 0) { _main_help(); exit 0; } printf("# %s %s\n", __PACKAGE__, $VERSION); if (eval {require Pod::Perldoc;}) { # pod2usage( -verbose => 1 ); exit( 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. printf("# no Pod::Perldoc installed, please try:\n perldoc $0\n"); } return; } # _main_help sub _main { my @argv = @_; ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # SEE Perl:binmode() binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); local $\="\n"; if ($#argv < 0) { _main_help(); exit 0; } # got arguments, do something special; any -option or +command exits while (my $arg = shift @argv) { if ($arg =~ /^--?h(?:elp)?$/) { _main_help(); } if ($arg =~ /^[+-]?version/i) { print "$VERSION"; } if ($arg =~ /^--test.?init/) { printParameters(); } if ($arg =~ /^[+-]/) { exit 0; } # silently ignore unknown options } exit 0; } # _main =pod =head1 EXAMPLES See DESCRIPTION above. =head1 LIMITATIONS =head1 KNOWN PROBLEMS =head1 DEENDENCIES L L L =head1 SEE ALSO L =head1 AUTHOR 19-November-2014 Torsten Gigler =cut sub net_sslhello_done() {}; # dummy to check successful include ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main(@ARGV) if (not defined caller); 1; O-Saft-22.11.22/Net/SSLinfo.pm000077500000000000000000005311171433765727300154670ustar00rootroot00000000000000#! /usr/bin/perl -I . -I .. ## PACKAGE { #!############################################################################# #!# Copyright (c) 2022, Achim Hoffmann #!#---------------------------------------------------------------------------- #!# 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 utilising a GPL component, such as #!# this, is also licensed under the same GPL license. #!############################################################################# package Net::SSLinfo; use strict; use warnings; use constant { SSLINFO => 'Net::SSLinfo', SSLINFO_ERR => '#Net::SSLinfo::errors:', SSLINFO_HASH => '<>', SSLINFO_UNDEF => '<>', SSLINFO_PEM => '<>', }; my $SID_sslinfo = "@(#) SSLinfo.pm 1.283 22/11/23 21:12:47"; our $VERSION = "22.11.22"; # official verion number of tis file use OSaft::Text qw(print_pod %STR); 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: 081: ancient Net::SSLeay $Net::SSLeay::VERSION < 1.49; cannot use ::initialize"); } else { Net::SSLeay::initialize(); } } #_____________________________________________________________________________ #_____________________________________________________ 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 ## no critic qw(Subroutines::ProhibitSubroutinePrototypes) # NOTE: See t/.perlcriticrc ## no critic qw(RegularExpressions::RequireExtendedFormatting) # because we use /x as needed for human readability ##### critic qw(InputOutput::ProhibitBacktickOperators) # used at commands where we need backticks or qx() ## no critic qw(Variables::ProhibitPackageVars) # using package variables are considered ok in this package, check in future again =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 --help # print help Net::SSLinfo.pm +VERSION # print version string Net::SSLinfo.pm version # print internal version string Net::SSLinfo.pm --test-sclient # print available options for 'openssl s_client' Net::SSLinfo.pm --test-sslmap # print constants for SSL protocols Net::SSLinfo.pm --test-openssl # print information about openssl capabilities Net::SSLinfo.pm --test-ssleay # print information about Net::SSLeay capabilities Net::SSLinfo.pm --test-methods # print available methods in Net::SSLeay Net::SSLinfo.pm unknown-host # print empty data structure 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>. If set to 2 or greater, more data will be printed, for example the complete request and response data as well as data which covers more than one line. 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. Note that Net::SSLeay may print on STDERR with I<$Net::SSLeay::trace> set. In trace messages empty or undefined strings are written as "<>". I<$Net::SSLinfo::prefix_trace> contains the string used as prefix for each message printed with trace =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::target_url URL to be used when makeing HTTP/HTTPS connection (to get HTTP data). =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 information 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 information according the SSL connection and the certificate, can only be retrived using "openssl s_client ...". Unfortunately 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_https If set to "1", make a simple HTTPS request on the open SSL connection. =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. =item $Net::SSLinfo::verbose Print some verbose messages. =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_cert_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 #_____________________________________________________________________________ #________________________________________________ public (export) variables __| use Exporter qw(import); use base qw(Exporter); our @EXPORT = qw( net_sslinfo_done ssleay_methods test_methods test_sclient test_sslmap test_ssleay 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 extended_master_secret master_secret next_protocols alpn no_alpn next_protocol krb5 master_key psk_hint psk_identity public_key_len session_id session_id_ctx session_startdate session_starttime session_lifetime session_ticket session_ticket_hint session_timeout session_protocol srp 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; #_____________________________________________________________________________ #___________________________________________________________ initialisation __| 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_https = 1; # 1 make HTTPS request and retrive additional data $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::target_url = '/'; # URL to use when connecting with get_http(s) $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::prefix_trace= '#' . SSLINFO . '::'; # prefix string used in trace messages $Net::SSLinfo::verbose = 0; # 1: print some verbose messages $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($$$$); # define some shortcuts to avoid $Net::SSLinfo::* my $_echo = ''; # dangerous if aliased or wrong one found my $_timeout = undef; my $_openssl = undef; #_____________________________________________________________________________ #_________________________________________________________ internal methods __| # SEE Perl:Undefined subroutine *_warn = sub { print(join(" ", "**WARNING:", @_), "\n"); return; } if not defined &_warn; *_dbx = sub { print(join(" ", "#dbx#" , @_), "\n"); return; } if not defined &_dbx; # need our own _trace() methods sub _trace { my $txt=shift; local $\="\n"; print $Net::SSLinfo::prefix_trace . $txt if (0 < $trace); return; } sub _trace1 { my $txt=shift; local $\="\n"; print $Net::SSLinfo::prefix_trace . $txt if (1 == $trace); return; } sub _trace2 { my $txt=shift; local $\="\n"; print $Net::SSLinfo::prefix_trace . $txt if (1 < $trace); return; } sub _verbose { my $txt=shift; local $\="\n"; print $Net::SSLinfo::prefix_trace . $txt if (0 < $Net::SSLinfo::verbose); return; } 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 _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$/); _trace("_setcommand($command) $opt 2>&1"); $cmd = qx($command $opt 2>&1); ## no critic qw(InputOutput::ProhibitBacktickOperators) if (defined $cmd) { # chomp() and _trace() here only to avoid "Use of uninitialized value $cmd ..." chomp $cmd; _trace2("_setcommand: #{ $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/); ## no critic qw(InputOutput::ProhibitBacktickOperators) } } 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 !~ /\//)); } _trace("_setcommand cmd=$cmd"); return $cmd; } # _setcommand sub _setcmd { #? check for external commands and initialise 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: _openssl=$_openssl ; _timeout=$_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 _traceset(); ## no critic (TestingAndDebugging::ProhibitProlongedStrictureOverride) # NOTE: perlcritic is too pedantic foreach my $op (sort 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); ## my $_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 __| sub _ssleay_value_get { #? retrun value of $type (option, timeout, verify_mode, verify_depth, OP) for specified function as formated string # returns <> if specified function does not exist # $func is i.e.: Net::SSLeay::CTX_v3_new, Net::SSLeay::CTX_v23_new my $type= shift; my $func= shift; my $val = "<>"; $val = undef if ('OP_or_undef' eq $type); _traceset(); _trace("_ssleay_value_get('$type', '$func')"); if (defined &$func) { $val = sprintf('0x%08x', Net::SSLeay::CTX_get_options(&$func())) if ('options' eq $type); $val = Net::SSLeay::CTX_get_timeout(&$func()) if ('timeout' eq $type); $val = sprintf('0x%08x', Net::SSLeay::CTX_get_verify_mode( &$func())) if ('verify_mode' eq $type); $val = Net::SSLeay::CTX_get_verify_depth(&$func()) if ('verify_depth' eq $type); $val = sprintf('0x%08x', &$func()) if ('OP' eq $type); $val = sprintf('0x%08x', &$func()) if ('OP_or_undef' eq $type); } _trace("_ssleay_value_get ret=" . ($val || "undef")); return $val; } # _ssleay_value_get 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 useful, 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 initialised 'data' => '',# contains output from "openssl s_client -help" #--------------+------------ # key (=option) supported=1 #--------------+------------ '-CAfile' => 0, '-CApath' => 0, '-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, '-nbio_test' => 0, '-tlsextdebug' => 0, '-client_sigalgs' => 0, '-record_padding' => 0, '-no_renegotiation' => 0, '-legacyrenegotiation' => 0, '-legacy_renegotiation' => 0, '-legacy_server_connect' => 0, '-no_legacy_server_connect' => 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) # | bitmask used in Net::SSLeay::CTX_set_options() # key v v example bitmask #-------------+---------+--------------------------------------------- 'SSLv2' => [0x0002, undef], # 0x01000000 'SSLv3' => [0x0300, undef], # 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 values dynamically (to avoid perl errors) $_SSLmap{'SSLv2'} [1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_SSLv2); $_SSLmap{'SSLv3'} [1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_SSLv3); $_SSLmap{'TLSv1'} [1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_TLSv1); $_SSLmap{'TLSv11'} [1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_TLSv1_1); $_SSLmap{'TLSv12'} [1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_TLSv1_2); $_SSLmap{'TLSv13'} [1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_TLSv1_3); $_SSLmap{'DTLSv1'} [1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_DTLSv1); $_SSLmap{'DTLSv11'}[1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_DTLSv1_1); $_SSLmap{'DTLSv12'}[1] = _ssleay_value_get('OP_or_undef', *Net::SSLeay::OP_NO_DTLSv1_2); $_SSLmap{'DTLSv13'}[1] = _ssleay_value_get('OP_or_undef', *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 'PEM_text' => '', # temp. storage oF PEM to avoid multiple openssl calls #-------------+-------------+--------------------------------------------- ); # %_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'} = []; $_SSLtemp{'PEM_text'} = ''; 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 'master_secret' => "", # Extended master secret 'public_key_len' => "", # Server public key 'session_id' => "", # Session-ID 'session_id_ctx' => "", # Session-ID-ctx '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 # $_SSLinfo_random # SEE Make:OSAFT_MAKE (in Makefile.pod) my $_SSLinfo_random = qr/ctx|master_key|session_(?:startdate|starttime|ticket)|ssl|x509/; # handled special my $_SSLinfo_random_text = $STR{MAKEVAL}; 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 _SSLinfo_print { #? print some data in $_SSLinfo (for --verbose) foreach my $key (sort qw( subject_hash issuer_hash aux ocsp_response ocsp_response_data ocsp_response_status ocsp_cert_status ocsp_next_update ocsp_this_update pubkey pubkey_algorithm pubkey_value signame sigdump sigkey_len sigkey_value extensions tlsextdebug tlsextensions email heartbeat serial serial_hex serial_int modulus modulus_len modulus_exponent fingerprint_text fingerprint_type fingerprint_hash fingerprint_sha2 fingerprint_sha1 fingerprint_md5 selected verify chain chain_verify dh_parameter renegotiation resumption selfsigned compression expansion next_protocols alpn no_alpn next_protocol krb5 psk_hint psk_identity srp master_secret master_key public_key_len session_id session_id_ctx session_startdate session_starttime session_lifetime session_ticket session_timeout session_protocol )) # not yet: # cert_type # ciphers # s_client # ciphers_openssl # not HTTP(S) { next if (not defined $_SSLinfo{$key}); _verbose("$key=$_SSLinfo{$key}"); } return; } # _SSLinfo_print #_____________________________________________________________________________ #______________________________________________________ public test methods __| sub ssleay_methods { # not yet # cert_type # ciphers # s_client # ciphers_openssl #? 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 test_methods { #? return openssl s_client availabilities (options for s_client) return join(" ", sort(ssleay_methods())); } # test_methods sub test_sclient { #? return openssl s_client availabilities (options for s_client) return join(" ", sort(s_client_get_optionlist()) ); } # test_sclient sub test_sslmap { #? return internal data structure %_SSLmap my $line = "#---------------+--------+-------------"; my $data = "$line\n# _SSLmap{ key SSLeay bitmask\n$line\n"; foreach my $_ssl (sort keys %_SSLmap) { my $mask = "<>"; $mask = $_SSLmap{$_ssl}[1] if defined $_SSLmap{$_ssl}[1]; $data .= sprintf("#%14s\t= 0x%04X %s\n", $_ssl, $_SSLmap{$_ssl}[0], $mask); } $data .= "$line"; return $data; } # test_sslmap sub test_ssleay { #? return availability and information about Net::SSLeay ## no critic qw(ValuesAndExpressions::ProhibitImplicitNewlines) # a here document is not possible here, or at least more cumbersome, # because Perl code is used inside 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\n"; no warnings 'once'; ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) # TODO: perl's strict is picky for OP_NO_DTLS* below $data .= "# Net::SSLeay{ constant hex value $line # ::OP_NO_SSLv2 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_SSLv2) . " # ::OP_NO_SSLv3 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_SSLv3) . " # ::OP_NO_TLSv1 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_TLSv1) . " # ::OP_NO_TLSv1_1 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_TLSv1_1) . " # ::OP_NO_TLSv1_2 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_TLSv1_2) . " # ::OP_NO_TLSv1_3 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_TLSv1_3) . " # ::OP_NO_DTLSv09 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_DTLSv09) . " # ::OP_NO_DTLSv1 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_DTLSv1) . " # ::OP_NO_DTLSv1_1 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_DTLSv1_1) . " # ::OP_NO_DTLSv1_2 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_DTLSv1_2) . " # ::OP_NO_DTLSv1_3 = " . _ssleay_value_get('OP', *Net::SSLeay::OP_NO_DTLSv1_3) . " $line # Net::SSLeay} constant\n"; $data .= "# Net::SSLeay{ call # experimental ... # Net::SSLeay::CTX_new { # ::CTX_get_options(CTX)= " . _ssleay_value_get('options', *Net::SSLeay::CTX_new) . " # Net::SSLeay::CTX_new } # Net::SSLeay::CTX_v3_new { # ::CTX_get_options(CTX)= " . _ssleay_value_get('options', *Net::SSLeay::CTX_v3_new) . " # Net::SSLeay::CTX_v3_new } # Net::SSLeay::CTX_v23_new { # ::CTX_get_options(CTX)= " . _ssleay_value_get('options', *Net::SSLeay::CTX_v23_new) . " # ::CTX_get_timeout(CTX)= " . _ssleay_value_get('timeout', *Net::SSLeay::CTX_v23_new) . " # ::CTX_get_verify_mode(CTX) = " . _ssleay_value_get('verify_mode', *Net::SSLeay::CTX_v23_new) . " # ::CTX_get_verify_depth(CTX)= " . _ssleay_value_get('verify_depth', *Net::SSLeay::CTX_v23_new) . " # Net::SSLeay::CTX_v23_new } # Net::SSLeay::CTX_tlsv1_2_new { # ::CTX_get_options(CTX)= " . _ssleay_value_get('options', *Net::SSLeay::CTX_tlsv1_2_new) . " # ::CTX_get_timeout(CTX)= " . _ssleay_value_get('timeout', *Net::SSLeay::CTX_tlsv1_2_new) . " # ::CTX_get_verify_mode(CTX) = " . _ssleay_value_get('verify_mode', *Net::SSLeay::CTX_tlsv1_2_new) . " # ::CTX_get_verify_depth(CTX)= " . _ssleay_value_get('verify_depth', *Net::SSLeay::CTX_tlsv1_2_new) . " # Net::SSLeay::CTX_tlsv1_2_new } # Net::SSLeay} call\n"; return $data; } # test_ssleay 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 $prefix = shift; # get prefix as parameter my $data = $prefix; $data .= " datadump #{\n"; 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'}})); $data .= _dump('addr', " ", join('.', unpack('W4', $_SSLinfo{'addr'}||""))); # pretty print IP foreach my $key (sort keys %_SSLinfo) { # SEE Note:Testing, sort next if ($key =~ m/addr|ciphers|errors|PEM|text|fingerprint_|s_client/); # handled special if ($key =~ m/$_SSLinfo_random/) { # handled special if (defined $ENV{'OSAFT_MAKE'}) { # SEE Make:OSAFT_MAKE (in Makefile.pod) # ugly hack here, but simplifies testing with make; however, this code is for debugging only $data .= _dump($key, " ", $_SSLinfo_random_text); next; } } $data .= _dump($key, " ", $_SSLinfo{$key}); } foreach my $key (sort keys %_SSLinfo) { # SEE Note:Testing, sort next if ($key !~ m/fingerprint_/); $data .= _dump($key, " ", $_SSLinfo{$key}); } $data .= _dump('errors', "\n", join("\n ** ", @{$_SSLinfo{'errors'}})); $data .= "$Net::SSLinfo::prefix_trace$prefix datadump #}"; # quick&dirty global prefix_trace return $data; } # datadump #_____________________________________________________________________________ #______________________________________________ internal SSL helper methods __| ### _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}}); } if (not defined $_SSLinfo{'ssl'}) { # if-condition only to avoid multiple calls, improves performance and produces less trace output 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') { _trace("_SSLinfo_get 'dates'=" . $_SSLinfo{'before'} . " " . $_SSLinfo{'after'}); return ( $_SSLinfo{'before'}, $_SSLinfo{'after'}); } if (0 < $trace) { # prepare data to be printed by trace_() my $value = $_SSLinfo{$key} || ''; $value = "<>" if ($value =~ m/[\r\n]/); _trace("_SSLinfo_get '$key'=$value"); } 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'}"); #dbx# _trace("_check_host =" . ((defined $ip) ? 1 : undef)); 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); #dbx# _trace("_check_port =$port"); return (defined $port) ? 1 : undef; } # _check_port 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_crl { # TBD my $ssl = shift; _trace("_check_crl()"); return; } # _check_crl 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 _ssleay_cert_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_cert_get('$key', x509)"); if (0 != $Net::SSLinfo::no_cert) { _trace("_ssleay_cert_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) _trace2("_ssleay_cert_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_cert_get '$key'=$ret"); # or warn "$STR{WARN} wrong key '$key' given; ignored"; return $ret; } # _ssleay_cert_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 retu=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 ret=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 information, 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 ret=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 ret=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=$#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 _trace2("_openssl_MS $mode $host$port: cmd.exe /D /C /S $tmp"); 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; ## no critic qw(InputOutput::ProhibitBacktickOperators) $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 _trace2("_openssl_MS $mode $host$port : $data #"); } if ('' ne $err) { $text = "_openssl_MS() failed calling $src: $err"; _trace2($text); 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; } ######## 4/2021 # TODO: external openssl is called for every $mode to extract some data from # the given $pem. In practice openssl "simply extracts" the requested # information $mode from the textual representation of $pem. # idea: convert $pem once to text ($mode==-text), then all other data can be # extracted from that text; results in one external openssl call. # currently 4/2021 openssl is call ca. 13 times # see more comments labeled 14apr21 ######## #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"; } if (1 < $trace) { _trace("_openssl_x509: openssl $mode < '$pem'"); } else { _trace("_openssl_x509: openssl $mode"); } if ($^O !~ m/MSWin32/) { $data = `echo '$pem' | $_openssl $mode 2>&1`; ## no critic qw(InputOutput::ProhibitBacktickOperators) } 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"; _trace2("_openssl_x509 '$mode'=$data"); return $data; } # _openssl_x509 #_____________________________________________________________________________ #__________________________________________________________________ methods __| =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); ## no critic qw(InputOutput::ProhibitBacktickOperators) } #_trace("data{ $_OpenSSL_opt{'data'} }"; # store data very simple: set value to 1 if option appears in output foreach my $key (sort 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 ret=1"); 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'}) { # initialise %_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 "$STR{WARN} Net::SSLeay::free(): $!"; Net::SSLeay::CTX_free($ctx) if (defined $ctx); # or warn "$STR{WARN} 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 { ## no critic qw(Subroutines::ProhibitManyArgs) 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 innitilise SSL connection. # This nitialisation 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 (sort 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) { # avoid printing empty line, hence "if -1 < $#" _trace(join("\n" . SSLINFO_ERR . ' ', '', @{$_SSLtemp{'errors'}})) if (-1 < $#{$_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 "... uninitialised # 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_return 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() $Net::SSLinfo::target_url =~ s:^\s*$:/:;# set to / if empty _verbose("do_ssl_open " . ($host||'') . ":" . ($port||'') . $Net::SSLinfo::target_url ); #_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 # initialise %_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"); } } { no warnings; ## no critic (TestingAndDebugging::ProhibitNoWarnings) if (defined $Net::SSLinfo::next_protos) { # < 1.182 warn("$STR{WARN} 090: 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 information # 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_cert_get #5a. get internal data # Some values may be overwritten below (see %match_map below). $_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) $_SSLinfo{'session_protocol'} = $_SSLinfo{'SSLversion'}; $_SSLinfo{'session_starttime'} = Net::SSLeay::SESSION_get_time($ssl); $_SSLinfo{'session_timeout'} = Net::SSLeay::SESSION_get_timeout($ssl); #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 information $_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_cert_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_cert_get('subject', $x509); $_SSLinfo{'issuer'} = _ssleay_cert_get('issuer', $x509); $_SSLinfo{'before'} = _ssleay_cert_get('before', $x509); $_SSLinfo{'after'} = _ssleay_cert_get('after', $x509); $_SSLinfo{'policies'} = _ssleay_cert_get('policies',$x509); if (1.45 <= $Net::SSLeay::VERSION) { $_SSLinfo{'version'}= _ssleay_cert_get('version', $x509); } else { warn("$STR{WARN} 651: Net::SSLeay >= 1.45 required for getting version"); } if (1.33 <= $Net::SSLeay::VERSION) {# condition stolen from IO::Socket::SSL, $_SSLinfo{'altname'}= _ssleay_cert_get('altname', $x509); } else { warn("$STR{WARN} 652: Net::SSLeay >= 1.33 required for getting subjectAltNames"); } if (1.30 <= $Net::SSLeay::VERSION) {# condition stolen from IO::Socket::SSL $_SSLinfo{'cn'} = _ssleay_cert_get('cn', $x509); $_SSLinfo{'cn'} =~ s{\0$}{};# work around Bug in Net::SSLeay <1.33 (from IO::Socket::SSL) } else { warn("$STR{WARN} 653: Net::SSLeay >= 1.30 required for getting commonName"); } if (1.45 <= $Net::SSLeay::VERSION) { $_SSLinfo{'fingerprint_md5'} = _ssleay_cert_get('md5', $x509); $_SSLinfo{'fingerprint_sha1'}= _ssleay_cert_get('sha1', $x509); $_SSLinfo{'fingerprint_sha2'}= _ssleay_cert_get('sha2', $x509); } else { warn("$STR{WARN} 654: 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_cert_get('error_depth', $x509); $_SSLinfo{'serial_hex'} = _ssleay_cert_get('serial_hex', $x509); $_SSLinfo{'cert_type'} = sprintf("0x%x <>", _ssleay_cert_get('cert_type', $x509) || 0); $_SSLinfo{'subject_hash'} = sprintf("%x", _ssleay_cert_get('subject_hash', $x509) || 0); $_SSLinfo{'issuer_hash'} = sprintf("%x", _ssleay_cert_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("$STR{WARN} 655: 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_https) { _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 $Net::SSLinfo::target_url HTTP/1.1\r\n"; $request .= "Host: $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()'; #print "#dbx $request\n"; 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("do_ssl_open: request $host:$port"); if (1 == $trace) { _trace("do_ssl_open: request #{<>#}"); _trace("do_ssl_open: response #{\n$response #}") if ($response =~ m/<>#}"); } else { # matches $trace==0 too; that's ok as handled correctly in _trace() _trace2("do_ssl_open: request #{\n$request"); _trace("do_ssl_open request #}"); _trace2("do_ssl_open: response #{\n$response"); _trace("do_ssl_open 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 }"); } if (0 < $Net::SSLinfo::use_http) { _trace("do_ssl_open HTTP {"); # HTTP uses its own connection ... my %headers; my $response = ''; my $request = ''; _trace("do_ssl_open ::use_http: $Net::SSLinfo::use_http"); # TODO: add 'Authorization:'=>'Basic ZGVtbzpkZW1v', # NOTE: Net::SSLeay always sets Accept:*/* $src = 'Net::SSLeay::get_http()'; ($response, $_SSLinfo{'http_status'}, %headers) = Net::SSLeay::get_http($host, 80, $Net::SSLinfo::target_url, Net::SSLeay::make_headers( 'Host' => $host, 'Connection' => 'close', ) # 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 capitalised my $headers = ""; # for trace only foreach my $h (sort keys %headers) { $headers .= "$h: $headers{$h}\n"; } _trace("do_ssl_open: request $host:$port"); if (1 == $trace) { _trace("do_ssl_open: request #{<>#}"); _trace("do_ssl_open: response #{\n$response #}") if ($response =~ m/<>#}"); } else { # matches $trace==0 too; that's ok as handled correctly in _trace() _trace2("do_ssl_open: request #{\n$request"); _trace("do_ssl_open request #}"); _trace2("do_ssl_open: response #{\n$response"); _trace("do_ssl_open 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 uninitialised 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 "$STR{WARN} 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 uninitialised 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 # 14apr21 my $cert = Net::SSLeay::get_peer_certificate($ssl); # 14apr21 my $id = eval { Net::SSLeay::OCSP_cert2ids($ssl,$cert) }; # 14apr21 my $id = Net::SSLeay::OCSP_cert2ids($ssl,$cert) ; # 14apr21 print "#### ID $id "; # 14apr21 print "#### PEM=$_SSLinfo{'PEM'} "; 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 first 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 (openssl 1.1.x and newer): # Server public key is 2048 bit # from s_client: # SSL-Session: # 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 # Extended master secret: yes my %match_map = ( # %_SSLinfo key string to match in s_client output #-------------------+----------------------------------- 'session_id' => "Session-ID:", 'session_id_ctx' => "Session-ID-ctx:", 'master_key' => "Master-Key:", 'master_secret' => "Extended master secret:", '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 #'public_key_len' => "Server public key", # this line has no : hence 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 (sort keys %match_map) { my $regex = $match_map{$key}; $d = $data; $d =~ s/.*?$regex[ \t]*([^\n\r]*)\n.*/$1/si; _trace("do_ssl_open: match key: $key\t= $regex"); if ($data =~ m/$regex/) { $_SSLinfo{$key} = $d; $_SSLinfo{$key} = $regex if ($key eq 'no_alpn'); # no_alpn: single line, has no value: No ALPN negotiated _trace("do_ssl_open: match value: $key\t= $_SSLinfo{$key}"); } } # 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/.*?Server public key is *([^\n\r]*)[\n\r].*/$1/si; $_SSLinfo{'public_key_len'} = $d if ($data =~ m/Server public key is /); $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("do_ssl_open: -tlsextdebug $d") if ($d =~ m/session ticket/); _trace("do_ssl_open: -tlsextdebug $d") if ($d =~ m/renegotiation info/); } $_SSLinfo{'tlsextensions'} =~ s/\([^)]*\),?\s+//g; # remove additional information $_SSLinfo{'tlsextensions'} =~ s/\s+len=\d+//g; # ... _trace("do_ssl_open(with openssl done."); _trace1("do_ssl_open <>"); _trace2(Net::SSLinfo::datadump("do_ssl_open")); 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: _SSLinfo_print(); # --verbose only finished_return: _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) { _trace2("do_openssl($mode): WARNING: no openssl s_client"); 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("do_openssl($mode): echo '' | $_timeout $_openssl $mode $host:$port 2>&1"); _verbose("$_timeout $_openssl $mode $host:$port"); # TODO: both, _trace and _verbose, may produce useless trailing : if ($^O !~ m/MSWin32/) { $host .= ':' if ($port ne ''); $pipe = 'HEAD / HTTP/1.1' if ($pipe =~ m/^$/); # avoid in access.log: "\n" 400 750 "-" "-" #dbx# print "echo $pipe | $_timeout $_openssl $mode $host$port 2>&1"; $data = `echo $pipe | $_timeout $_openssl $mode $host$port 2>&1`; ## no critic qw(InputOutput::ProhibitBacktickOperators) 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`; ## no critic qw(InputOutput::ProhibitBacktickOperators) } } 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(); _trace2("cipher_openssl: openssl ciphers $pattern"); $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("$STR{WARN} 451: 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 test_ssleay( ) 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 master_secret Get target's support for Extended master secret. =head2 extended_master_secret Same as master_secret . =head2 public_key_len Get target's Server public key length. =head2 session_id Get target's TLS Session-ID. =head2 session_id_ctx Get target's TLS Session-ID-ctx. =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 master_secret { return _SSLinfo_get('master_secret', $_[0], $_[1]); } sub extended_master_secret { return _SSLinfo_get('master_secret', $_[0], $_[1]); } # alias sub public_key_len { return _SSLinfo_get('public_key_len', $_[0], $_[1]); } sub session_id { return _SSLinfo_get('session_id', $_[0], $_[1]); } sub session_id_ctx { return _SSLinfo_get('session_id_ctx', $_[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 # $alt may contain ( or { , see escape $rex below 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; # escape meta characters $rex =~ s/([({[])/\\$1/g; # escape meta characters 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 error { # TBD #return Net::SSLeay::ERR_get_error; } # error #_____________________________________________________________________________ #_____________________________________________________________________ main __| sub _main { #? print own documentation or special required one ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # see t/.perlcriticrc for detailed description of "no critic" my @argv = @_; push(@argv, "--help") if (0 > $#argv); binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); local $\="\n"; # got arguments, do something special; any -option or +command exits while (my $arg = shift @argv) { if ($arg =~ m/^--?h(?:elp)?$/) { local undef $\; print_pod($0, __PACKAGE__, $SID_sslinfo); } # ----------------------------- options if ($arg =~ m/^--(?:v|trace.?)/i) { $Net::SSLinfo::verbose++; next; } # ----------------------------- commands if ($arg =~ m/^version$/) { print "$SID_sslinfo"; next; } if ($arg =~ m/^[+-]?VERSION/i) { print "$VERSION"; next; } if ($arg =~ m/^(?:--test)?.?ssleay/) { print test_ssleay(); next; } if ($arg =~ m/^(?:--test)?.?sslmap/) { print test_sslmap(); next; } if ($arg =~ m/^(?:--test)?.?s_?client/) { print test_sclient(); next; } if ($arg =~ m/^(?:--test)?.?methods/) { print test_methods(); next; } if ($arg =~ m/^[+-]/) { next; } # silently ignore unknown options # treat remaining args as hostname to test do_ssl_open( $arg, 443, ''); print Net::SSLinfo::datadump("main"); } exit 0; } # _main #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =head1 DEPENDENCIES 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 } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main(@ARGV) if (not defined caller); 1; O-Saft-22.11.22/OSaft/000077500000000000000000000000001433765727300140675ustar00rootroot00000000000000O-Saft-22.11.22/OSaft/Ciphers.pm000077500000000000000000003705461433765727300160440ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) 2022, Achim Hoffmann #!# This software is licensed under GPLv2. Please see o-saft.pl for details. package OSaft::Ciphers; ## no critic qw(ControlStructures::ProhibitPostfixControls) # We believe it's better readable (severity 2 only). ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers) # We use perlish multiplication vor strings, like "'-' x 7", (severity 2 only). ## no critic qw(RegularExpressions::RequireExtendedFormatting) # We use /x as needed for human readability only. ## no critic qw(ValuesAndExpressions::ProhibitImplicitNewlines) # We use here documents as needed for human readability. ## no critic qw(BuiltinFunctions::RequireBlockGrep) # other people, other opinions # test resources with: # /usr/bin/time --quiet -a -f "%U %S %E %P %Kk %Mk" OSaft/Ciphers.pm alias # 0.02 0.00 0:00.02 100% 0k 9496k # 3/2022 # 0.02 0.00 0:00.03 100% 0k 9924k # 11/2022 use strict; use warnings; use Carp; our @CARP_NOT = qw(OSaft::Ciphers); # TODO: funktioniert nicht BEGIN { # SEE Perl:@INC # SEE Perl:BEGIN perlcritic my $_me = $0; $_me =~ s#.*[/\\]##x; my $_path = $0; $_path =~ s#[/\\][^/\\]*$##x; unshift(@INC, $_path) if (1 > (grep{/^$_path$/} @INC)); unshift(@INC, "..") if (1 > (grep{/^\.\.$/} @INC)); unshift(@INC, ".") if (1 > (grep{/^\.$/} @INC)); } my $SID_ciphers= "@(#) Ciphers.pm 2.80 22/11/17 17:47:35"; our $VERSION = "22.11.22"; # official verion number of this file use OSaft::Text qw(%STR print_pod); use osaft; # SEE Note:Stand-alone $::osaft_standalone = 0 if not defined $::osaft_standalone; ## no critic qw(Variables::ProhibitPackageVars) #_____________________________________________________________________________ #_____________________________________________________ public documentation __| # More public documentation, see start of methods section, and at end of file. =pod =encoding utf8 =head1 NAME OSaft::Ciphers - common Perl module to define cipher suites for O-Saft =head1 SYNOPSIS =over 2 =item use OSaft::Ciphers; # from within Perl code =item OSaft::Ciphers.pm # on command line will print help =back =head1 DESCRIPTION Utility package for O-Saft (o-saft.pl and related tools). This package contains the primary data structure for cipher suites. Common L and L are declares and defined to be used in the calling tool. The documentation 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 of this tool are only for this additional functionality, please read descriptions there. =head2 Used Functions Following functions (methods) must be defined in the calling program: None (03/2022). =head1 CONCEPT The main data structure is C<%ciphers>, which will be defined herein. Ciphers (more precisely: cipher suites) are defined statically as Perl __DATA__ herein. Each cipher is defined statically in one line with TAB-separated values for example: 0x0300003D HIGH HIGH TLSv12 RSA RSA AES 256 SHA256 .. AES256-SHA256 For a more detailed description, please use: OSaft/Ciphers.pm description OSaft/Ciphers.pm --test-ciphers-description or consult the source code directly, in particular C<%ciphers_desc>. The main key -aka ID- to identify a cipher suite is a 32-bit key where the last 16 bits are the numbers as defined by IANA and/or various RFCs. This key is also used in all other data structures related to ciphers. Each cipher suite is defined as a Perl array (see above) and will be converted to a Perl hash at initialisation like: '0x0300003D' => { ssl=>"TLSv12", keyx=>"RSA", enc=>"AES", ... }, Such a hash is simpler to use. Finally a getter method (see L) is provided for each value. =cut #This approach to specify the definition, which must be done by developers, is #based on the consideration that the data structure needs to be maintained very #carefully. Therefore the description of all (known) cipher suites is done in a #simple table, which just contains TAB-separated words. This table will then be #converted into the %ciphers hash automatically when this module is loaded. It's #the author's opinion, that tabular data is more easy to maintain by humans than #structured data. =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, mainly getter methods are provided. The only setter method is C which is used to redefine the security value of an cipher by the user with the option "--cfg-cipher=CIPHER=value" =head2 Testing The getter methods can be used directly, see: OSaft/Ciphers.pm --usage =head2 Documentaion This documentation 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_notes Notes and comments for a specific cipher, documentation only. Will be referenced in C<%ciphers>. =item $cipher_results Pointer to hash with all checked ciphers. =back =cut #_____________________________________________________________________________ #________________________________________________ public (export) variables __| # SEE Perl:perlcritic ## no critic qw(Variables::ProhibitPackageVars) use Exporter qw(import); use base qw(Exporter); our @EXPORT_OK = qw( %ciphers %ciphers_desc %ciphers_notes $cipher_results ciphers_done ); # methods not exported, see METHODS description above our %ciphers_desc = ( # description of %ciphers table 'head' => [qw( openssl sec ssl keyx auth enc bits mac rfc names const notes)], # array of all culumns used most tables (including # the definition below in DATA); # 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 # 'hex' => 'Hex Code', # hex key for cipher suite # 'openssl' => 'OpenSSL STRENGTH', # 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 known vulnerable # NOTE: weak includes NONE (no security at all) # high unqualified by openssl, but considerd secure 'sec' => 'Security', # weak, medium, high # weak unqualified by openssl or known vulnerable # high unqualified by openssl, but considerd secure 'ssl' => '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) 'keyx' => 'Key Exchange', # DH, ECDH, ECDH/ECDSA, RSA, KRB5, PSK, SRP, GOST, ECCPWD # last column is a : separated list (only export from openssl) # different versions of openssl report ECDH or ECDH/ECDSA 'auth' => 'Authentication', # None, DSS, RSA, ECDH, ECDSA, KRB5, PSK, GOST01, GOST94 'enc' => 'Encryption Type',# Algorithm: None, AES, AESCCM, AESGCM, ARIA, CAMELLIA, DES, 3DES, FZA, GOST89, IDEA, RC4, RC2, SEED 'bits' => 'Encryption Size',# Key size in bits 'enc_size' => 'Block Size', # encryption block size in bits 'mac' => 'MAC/Hash Type', # Algorithm: MD5, SHA1, SHA256, SHA384, AEAD, GOST89, GOST94 'mac_size' => 'MAC/Hash Size', # size of MAC in bits (usually coded in its name (type) # 'dtls' => 'DTLS OK', # Y if cipher is compatible for DTLS, N otherwise # # (information from IANA) 'rfc' => 'RFC(s)', # RFC number where cipher was defined 'pfs' => 'PFS', # )f cipher ha perfect forward secrecy 'suite' => 'Cipher Suite', # cipher suite name, mainly those used by OpenSSL 'name' => 'OpenSSL Name', # cipher suite name used by OpenSSL 'names' => '(Alias) Names', # Comma-separated list of cipher suite name and aliases 'const' => 'Constant Names', # Comma-separated list of cipher suite constants 'notes' => 'Notes/Comments', # Comma-separated list of notes and comments # for this cipher suite; for eaxmple: EXPORT, OSX # each value is used as key to %ciphers_notes # 'sample' => { # example '0x0300003D' => [split /\s+/, q(HIGH HIGH TLSv12 RSA RSA AES 256 SHA256 5246 AES256-SHA256,Alias RSA_WITH_AES_256_SHA256,RSA_WITH_AES_256_CBC_SHA256 L )], # qw// would result in Perl warning: # Possible attempt to separate words with commas # q// is one word, hence it must be splitted to become an array }, 'additional_notes' => ' Note about Constant names: Depending on the source of the constant, a different prefix in the name is used, such as TLS_ SSL_ SSL_CK_ SSL3_CK_ TLS1_CK_ Hence no prefix at all is used here. Note about TLS version: Usually the lowest/oldest protocol version is shown. But this cipher suite may also be used in a newer protocol version also. Following normalised strings are used for protocol versions: SSLv2, SSLv3, DTLS0.9, DTLS1.0, TLSv10, TLSv11, TLSv12, TLSv13, PCT SSL/TLS is used for pseudo cipher suites. ', ); # %ciphers_desc our %ciphers = ( # list of all ciphers # will be generated in _ciphers_init() from #--------------+-------+-------+----+----+----+----+----+----+----+-----------+-----------+-----+ # key => [qw( openssl sec ssl keyx auth enc bits mac rfc name;alias const notes )], #--------------+-------+-------+----+----+----+----+----+----+----+-----------+-----------+-----+ #--------------+-------+-------+----+----+----+----+----+----+----+-----------+-----------+-----+ # ... ); # %ciphers our @cipher_iana_recomended = #? list of all ciphers (hex keys) recommended by IANA, see # http://www.iana.org/assignments/tls-parameters/tls-parameters.txt August 2022 qw( 0x0300009E 0x0300009F 0x030000AA 0x030000AB 0x03001301 0x03001302 0x03001303 0x0300130$ 0x0300C02B 0x0300C02C 0x0300C02F 0x0300C030 0x0300C09E 0x0300C09F 0x0300C0A6 0x0300C0A7 0x0300C0A8 0x0300C0A9 0x0300CCAA 0x0300CCAC 0x0300CCAD 0x0300D001 0x0300D002 0x0300D005 ); # cipher_iana_recomended our $cipher_results = { # list of checked ciphers #--------------+--------+--------------+----------+ # key => [ ssl supported ], # cipher suite name #--------------+--------+--------------+----------+ # '0x02010080' => [ SSLv3, yes ], # RC4-MD5 # '0x03000004' => [ SSLv3, yes ], # RC4-MD5 # '0x0300003D' => [ TLSv12, yes ], # AES256-SHA256 # '0x02FF0810' => [ SSLv3, no ], # NULL #--------------+--------+--------------+----------+ }; # $cipher_results our %ciphers_notes = ( # list of notes and comments for ciphers # these texts are referenced in %ciphers #------------------+---------, # hex => 'text' , #------------------+---------, #------------------+---------, # ... ); # %ciphers_notes #_____________________________________________________________________________ #_________________________________________________________ internal methods __| # SEE Perl:Undefined subroutine *_warn = sub { print(join(" ", "**WARNING:", @_), "\n"); return; } if not defined &_warn; *_dbx = sub { print(join(" ", "#dbx#" , @_), "\n"); return; } if not defined &_dbx; *_trace = sub { print(join(" ", "#${0}::", @_), "\n") if (0 < $cfg{'trace'}); return; } if not defined &_trace; *_trace2 = sub { print(join(" ", "#${0}::", @_), "\n") if (2 < $cfg{'trace'}); return; } if not defined &_trace2; *_v_print = sub { print(join(" ", "#${0}: ", @_), "\n") if (0 < $cfg{'verbose'}); return; } if not defined &_v_print; *_v2print = sub { print(join(" ", "#${0}: ", @_), "\n") if (1 < $cfg{'verbose'}); return; } if not defined &_v2print; #_____________________________________________________________________________ #__________________________________________________________________ methods __| =pod =head1 METHODS No methods are exported. The full package name must be used, which improves the readability of the program code. Methods intended for external use are: =head2 text2key($text) Convert hex text to internal key: 0x00,0x3D --> 0x0300003D. =head2 key2text($key) Convert internal key to hex text: 0x0300003D --> 0x00,0x3D. =head2 set_sec( $cipher_key) Set value for 'security' in for specified cipher key. =cut sub text2key { #? return internal hex key for given hex, return as is if not hex my $txt = shift; my $key = uc($txt); # we use upper case only $key =~ s/(,|0X)//g; # 0x00,0x26 --> 0026 return $txt if ($key !~ m/^[0-9A-F]+$/); # unknown format, return as is return "0x$key" if (8 == length($key)); if (4 < length($key)) { # SSLv2: quick&dirty: expects 6 characers $key = "0x02$key"; # 010080 --> 0x02010080 } else { # SSLv3, TLSv1.x while (6 > length($key)) { $key = "0$key"; } $key = "0x03$key"; # 000026 --> 0x03000026 } return $key; } # text2key sub key2text { #? return internal hex key converted to openssl-style hex key # strips 0x03,0x00 # return as is if not hex my $key = shift; return $key if ($key !~ m/^0x[0-9A-F]+$/i); # unknown format, return as is # NOTE: invalid keys like 0x0300001E-bug should not be converted $key =~ s/0x//i; # 0x0026 --> 0026 (necessary in test-mode only) if (6 < length($key)) { # from --> to $key =~ s/^42//; # 0x42420001 --> 420001 ; internal use in future $key =~ s/^02//; # 0x02010080 --> 010080 $key =~ s/^0300//; # 0x03000004 --> 0004 } $key =~ s/(..)/,0x$1/g; # 0001 --> ,0x00,0x04 $key =~ s/^,//; # ,0x00,0x04 --> 0x00,0x04 $key = " $key" if (10 > length($key)); return "$key"; } # key2text sub set_sec { my ($key, $val) = @_; $ciphers{$key}->{'sec'} = $val; return; } #? set value in $ciphers{$key}->{'sec'} hash =pod =head2 get_param( $cipher_key, $key) =head2 get_openssl( $cipher_key) =head2 get_ssl( $cipher_key) =head2 get_sec( $cipher_key) =head2 get_keyx( $cipher_key) =head2 get_auth( $cipher_key) =head2 get_enc( $cipher_key) =head2 get_bits( $cipher_key) =head2 get_mac( $cipher_key) =head2 get_dtls( $cipher_key) =head2 get_rfc( $cipher_key) =head2 get_notes( $cipher_key) =head2 get_name( $cipher_key) =head2 get_names( $cipher_key) =head2 get_aliases( $cipher_key) Return all cipher suite names except the first cipher suite name. =head2 get_const( $cipher_key) =head2 get_consts($cipher_key) =head2 get_note( $cipher_key) =head2 get_notes( $cipher_key) =head2 get_encsize( $cipher_key) Return encryption block size of cipher suite. =cut # some people prefer to use a getter function to get data from objects # each function returns a spcific value (column) from the %ciphers table # see %ciphers_desc about description of the columns # returns $STR{UNDEF} if requested cipher (hex key) is missing sub get_param { #? internal method to return required value from %ciphers ($cipher is hex-key) #? returns array or string depending on calling context my ($hex, $key) = @_; #_trace("get_param($hex,$key)"); $hex = text2key($hex); # normalize cipher key # if (0 < (grep{/^$hex/i} %ciphers)) # TODO: brauchen wir das für defense programming? if ('ARRAY' eq ref($ciphers{$hex}->{$key})) { return wantarray ? @{$ciphers{$hex}->{$key}} : join(' ', @{$ciphers{$hex}->{$key}}); } else { return $ciphers{$hex}->{$key} || ""; } return $STR{UNDEF}; # never reached } # get_param sub get_openssl { return get_param(shift, 'openssl'); } sub get_sec { return get_param(shift, 'sec' ); } sub get_ssl { return get_param(shift, 'ssl' ); } sub get_keyx { return get_param(shift, 'keyx' ); } sub get_auth { return get_param(shift, 'auth' ); } sub get_enc { return get_param(shift, 'enc' ); } sub get_bits { return get_param(shift, 'bits' ); } sub get_mac { return get_param(shift, 'mac' ); } sub get_rfc { return get_param(shift, 'rfc' ); } sub get_name { return (get_param(shift, 'names'))[0];} #sub get_name { my @n = get_param(shift, 'names'); print "# get_name: $n[0]"; return $n[0];} sub get_names { return get_param(shift, 'names'); } sub get_aliases { my @a = get_names(shift); return @a[1 .. $#a]; } #or get_aliases { my @a = get_names(shift); shift @a; return @a; } sub get_const { return (get_param(shift, 'const'))[0];} sub get_consts { return get_param(shift, 'const'); } sub get_note { return (get_param(shift, 'notes'))[0];} sub get_notes { return get_param(shift, 'notes'); } sub _get_name { #? internal method to return cipher suite name when paramater is hex-key or cipher suite name # simple check: asumes a key, if it matches 0x my $txt = shift; return $txt if ($txt !~ m/0x/); return get_name($txt); } # _get_name sub get_encsize { #? return encryption block size, based on (OpenSSL's) cipher suite name #? $cipher is hex-key or cipher suite name my $name= _get_name(shift); return '128' if ($name =~ m/AES/); return '64' if ($name =~ m/Blowfish/i); return '128' if ($name =~ m/CAMELLIA/); return '-' if ($name =~ m/-CHACHA/); return '64' if ($name =~ m/-CBC3/); return '64' if ($name =~ m/-3DES/); return '-' if ($name =~ m/DES-CBC/); # 3DES and CBC3 matched before return '-?-' if ($name =~ m/DES-CFB/); return '-?-' if ($name =~ m/GOST/); return '64' if ($name =~ m/IDEA/); return '-' if ($name =~ m/NULL/); return '64' if ($name =~ m/RC2-/); return '-' if ($name =~ m/RC4/); return '128' if ($name =~ m/SEED/); return '-?-'; # shoud be $STR{UNDEF}, but that's nasty in HTML } # get_encsize # following not yet used, as this information is defined in %ciphers # # =pod # # =head2 get_encmode( $cipher_key) # # Return type of encryption mode of cipher suite. # # =head2 get_enctype( $cipher_key) # # Return type of encryption of cipher suite. # # =head2 get_mactype( $cipher_key) # # Return type of MAC of cipher suite. # # =cut # # sub get_encmode { # #? return encryption mode, based on (OpenSSL's) cipher suite name # #? $cipher is hex-key or cipher suite name # # NOTE: use get_enc() instead # my $name= _get_name(shift); # return 'GCM' if ($name =~ m/-GCM/); # return 'CBC' if ($name =~ m/-CBC/); # return 'CBC' if ($name =~ m/-CAMELLIA/); # return 'CBC' if ($name =~ m/-IDEA/); # return 'CBC' if ($name =~ m/-SEED/); # return 'CBC' if ($name =~ m/-RC2/); # return '-' if ($name =~ m/-RC4/); # return '-' if ($name =~ m/-CHACHA20/); # return '-' if ($name =~ m/-NULL/); # return 'CBC'; # anything else is CBC (i.e. if CBC is not part of the suite name) # } # get_encmode # # sub get_enctype { # #? return encryption type, based on (OpenSSL's) cipher suite name # #? $cipher is hex-key or cipher suite name # my $name= _get_name(shift); # return 'AES' if ($name =~ m/-AES/); # matches: -AES128 -AES256 -AES- # return 'AES' if ($name =~ m/AES/); # matches: AES128- AES256- # return 'ARIA' if ($name =~ m/-ARIA/); # return 'CCM8' if ($name =~ m/-CCM8/); # return 'CCM' if ($name =~ m/-CCM/); # return 'CAMELLIA' if ($name =~ m/-CAMELLIA/); # return 'CHACHA20' if ($name =~ m/-CHACHA20/); # return 'CAST' if ($name =~ m/-CAST/); # return 'GOST' if ($name =~ m/-GOST/); # TODO: GOST01 and GOST89 and GOST94? # return 'IDEA' if ($name =~ m/-IDEA/); # return 'SEED' if ($name =~ m/-SEED/); # return '3DES' if ($name =~ m/-CBC3/); # return '3DES' if ($name =~ m/-3DES/); # return 'DES' if ($name =~ m/-DES/); # return 'RC4' if ($name =~ m/-RC4/); # return 'RC2' if ($name =~ m/-RC2/); # return 'None' if ($name =~ m/-NULL/); # return '-?-'; # shoud be $STR{UNDEF}, but that's nasty in HTML # } # get_enctype # # sub get_mactype { # #? return encryption key, based on (OpenSSL's) cipher suite name # #? $cipher is hex-key or cipher suite name # my $name= _get_name(shift); # return 'SHA384' if ($name =~ m/-SHA384/); # return 'SHA256' if ($name =~ m/-SHA256/); # return 'SHA128' if ($name =~ m/-SHA128/); # return 'SHA' if ($name =~ m/-SHA1/); # matches: -SHA1$ # return 'SHA' if ($name =~ m/-SHA/); # matches: -SHA$ # return 'MD5' if ($name =~ m/-MD5/); # return 'MD4' if ($name =~ m/-MD4/); # return 'RMD' if ($name =~ m/-RMD/); # return 'POLY1305' if ($name =~ m/-POLY1305/); # return 'GOST' if ($name =~ m/-GOST/); # TODO: GOST01 and GOST89 and GOST94? # return 'AEAD' if ($name =~ m/-GCM/); # return '-?-'; # shoud be $STR{UNDEF}, but that's nasty in HTML # } # get_mactype =pod =head2 get_key( $cipher_name) Get hex key for given cipher name; searches in cipher suite names and in cipher suite constants. Given name must match exactly. =head2 get_data( $cipher_key) Get all data for given cipher key from internal C<%ciphers> data structure. =head2 get_iana( $cipher_key) Return "yes" if cipher suite is recommended by IANA, "no" otherwise. =head2 get_pfs( $cipher_key|$cipher_name) Return "yes" if cipher suite supports PFS, "no" otherwise. =head2 get_keys_list() Get list of all defined (internal) hex keys for cipher suites in C<%ciphers>. Returns space-separetd string or array depending on calling context. =head2 get_names_list() Get list of all defined cipher suite names in C<%ciphers>. Returns space-separetd string or array depending on calling context. =head2 find_names( $cipher_pattern) Find all matching cipher names for given cipher name (pattern). =head2 find_keys( $cipher_pattern) Find all matching hex keys for given cipher name (pattern). =head2 find_name( $cipher) Find cipher key(s) for given cipher name or cipher constant. =cut sub get_key { #? return hex key for given cipher name; searches in cipher suite names and constants my $txt = shift; my $key = uc($txt); $key =~ s/X/x/g; # 0X... -> 0x... return $key if defined $ciphers{$key}; # cipher's hex key itself foreach my $key (keys %ciphers) { my @names = get_names($key); return $key if (0 < (grep{/^$txt$/i} @names)); # TODO above grep my return "Use of uninitialized value $_" # if the passed key is not found in @names } # any other text, try to normalise ... # example: SSL_CK_NULL_WITH_MD5 $txt =~ s/^(?:SSL[23]?|TLS1?)_//; # strip any prefix: CK_NULL_WITH_MD5 $txt =~ s/^(?:CK|TXT)_//; # strip any prefix: NULL_WITH_MD5 foreach my $key (keys %ciphers) { my @names = get_const($key); return $key if (0 < (grep{/^$txt$/i} @names)); } _warn("521: no key found for '$txt'"); # most likely a programming error %cfg or herein return ''; } # get_key sub get_data { #? return all data for given cipher key from internal %ciphers data structure my $key = shift; return $STR{UNDEF} if (not defined $ciphers{$key}); # my @x = sort values %{$ciphers{$key}}; # lasy approach not used return join("\t", get_param($key, 'openssl'), get_param($key, 'sec' ), get_param($key, 'ssl' ), get_param($key, 'keyx' ), get_param($key, 'auth' ), get_param($key, 'enc' ), get_param($key, 'bits' ), get_param($key, 'mac' ), get_param($key, 'rfc' ), #get_param($key, 'dtls' ), # not yet implemented get_param($key, 'names'), get_param($key, 'const'), get_param($key, 'notes'), ); } # get_data sub get_iana { #? return "yes" if cipher suite is recommended by IANA, "no" otherwise my $key = shift; $key = text2key($key); # normalize cipher key return (grep{ /^$key/i} @cipher_iana_recomended) ? "yes" : "no"; } # get_iana sub get_pfs { #? return "yes" if cipher suite supports PFS, "no" otherwise my $key = shift; my $name = $key; if ($key =~ /^0x[0-9A-F]{8}$/i) { $name = get_name($key); } return (($name =~ m/^(?:EC)?DHE/) or ($name =~ m/^(?:EXP-)?EDH-/)) ? "yes" : "no"; # EDH- and EXP-EDH- for ancient names } # get_pfs sub get_keys_list { #? return list of all defined (internal) hex keys for cipher suites in %ciphers my @keys = grep{ /^0x[0-9a-fA-F]{8}$/} keys %ciphers; # only valid keys return wantarray ? (sort @keys) : join(' ', (sort @keys)); # SEE Note:Testing, sort } # get_keys_list sub get_names_list { #? return list of all defined cipher suite names in %ciphers my @list; foreach my $key (sort keys %ciphers) { next if ($key !~ m/^0x[0-9a-fA-F]{8}$/);# extract only valid keys push(@list, get_name($key)); } return wantarray ? (sort @list) : join(' ', (sort @list)); # SEE Note:Testing, sort } # get_names_list sub find_keys { #? TODO find all hex key for which given cipher pattern matches in %ciphers my $pattern = shift; _trace("find_keys($pattern)"); return map({get_key($_);} grep(/$pattern/, get_names_list())); } # find_keys sub find_names { #? TODO find all cipher suite names for which given cipher pattern matches in %ciphers my $pattern = shift; _trace("find_names($pattern)"); return grep(/$pattern/, get_names_list()); } # find_names sub find_name { #? TODO check if given cipher name is a known cipher # checks in %ciphers, if not found search in all aliases and constants # example: RC4_128_WITH_MD5 -> RC4-MD5 ; RSA_WITH_AES_128_SHA256 -> AES256-SHA256 # Note: duplicate name (like RC4_128_WITH_MD5) are no problem, because they # use the same cipher suite name (like RC4-MD5). # TODO: need $ssl parameter because of duplicate names (SSLv3, TLSv10) my $cipher = shift; my @list; _trace("find_name: search $cipher"); my $key = get_key($cipher); return $key if $key !~ m/^\s*$/; # try fuzzy search in names and const: foreach my $key (sort keys %ciphers) { my $name = get_name($key); next if not $name; next if $name =~ m/^\s*$/; if ($name !~ m/$cipher/i) { my @const = get_consts($key); #dbx print "C = @const\n"; # TODO } _warn("513: partial match for cipher name found '$cipher'"); push(@list, $key); } return @list; # TODO: # $rex_name = s/([_-])/.?/g; $rex_name = s/DHE/EDH/; #return $STR{UNDEF}; } # find_name =pod =head2 sort_names(@ciphers) Sort ciphers according their strength. Returns list with most strongest first. C<@ciphers> is a list of cipher suite names. These names should be those used by openssl(1) . =head2 sort_results(%unsorted) Sort ciphers according their strength. Returns list with most strongest first. C<%unsorted> is a reference to a hash) of cipher suite hex keys. =cut sub sort_names { #? sort array of cipher suite names according their strength # 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 _trace("sort_names(){ $cnt_in ciphers: @ciphers }"); # Algorithm: # 1. remove all known @insecure ciphers from given list # 2. start building new list with most @strength cipher first # 3. add previously removed @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((?:DSA|DSS)) , # all DSA, DSS qw((?:MD[2345])), # all MD qw(DH.?(?i:anon)), # Anon needs to be caseless qw((?:NULL)) , # all NULL qw((?:SCSV)) , # dummy ciphers (avoids **WARNING: 412: for INFO_SCSV) qw((?:GREASE-)) , # dummy ciphers (avoids **WARNING: 412: for GREASE*) ); my @strength = ( qw(CECPQ1[_-].*?CHACHA) , qw(CECPQ1[_-].*?AES256.GCM) , qw(^(TLS_|TLS13-)) , 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).*?PSK) , 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(ECCPWD[_-]) , # 6. unknown ecliptical curve qw(AES) , # 7. all AES and specials qw(KRB5) , qw(SRP) , qw(PSK) , qw(GOST) , qw((?:IANA|LEGACY)[_-]GOST2012),# qw(FZA) , qw((?:PSK|RSA).*?CHACHA), qw(CHACHA) , qw((?:EDH|DHE).*?CHACHA), # 8. 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) , # 9. unknown strength qw((?:SEED|IDEA|ARIA|SM4)), qw(^(?:SHA256-|SHA384-)), qw(RSA[_-]) , # 10. qw(DH[_-]) , qw(RC) , qw(EXP) , # 11. Export ... qw(AEC.*?256) , # insecure qw(AEC.*?128) , qw(AEC) , qw(ADH.*?256) , # no encryption qw(ADH.*?128) , qw(ADH) , qw(PCT_) , # not an SSL/TLS protocol, just to keep our checks quiet ); foreach my $rex (@insecure) { # remove all known insecure suites _trace2("sort_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_names(): regex\t= $rex }"); push(@sorted, grep{ /$rex/} @ciphers); # add matches to result @ciphers = grep{!/$rex/} @ciphers; # remove matches from original list } # TODO: @ciphers should now be empty, check ... 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 my @miss; for my $i (0..$#ciphers) { push(@miss, $ciphers[$i]) unless grep {$_ eq $ciphers[$i]} @sorted; } @miss = sort @miss; # SEE Note:Testing, sort warn $STR{WARN}, "412: missing ciphers in sorted list ($cnt_out < $cnt_in): @miss"; ## no critic qw(ErrorHandling::RequireCarping) } @sorted = grep{!/^\s*$/} @sorted; # remove empty names, if any ... _trace("sort_names(){ $cnt_out ciphers\t= @sorted }"); return @sorted; } # sort_names sub sort_results { ## no critic qw(Subroutines::ProhibitExcessComplexity) #? sort array of ciphers according their strength # returns array with sorted cipher keys # only used when ckecking for ciphers with openssl #TODO: should be same as sort_names() my $unsorted= shift; # hash with $key => yes-or-no my @sorted; # array to be returned my @tmp_arr; foreach my $key (sort keys %$unsorted) { next if ($key =~ m/^\s*$/); # defensive programming .. my $cipher = get_name($key); if (not defined $cipher) { # defensive programming .. _warn("862: unknown cipher key '$key'; key ignored"); next; } my $sec_osaft = lc(get_sec($key));# lower case my $sec_owasp = osaft::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 = 25 if ($cipher =~ /^ECDHE.ECDS/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 -= 10 if ($cipher =~ /^TLS_/); # some TLSv1.3 start with TLS_* $weight -= 10 if ($cipher =~ /^TLS13-/);# some TLSv1.3 start or TLS13_* $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 $weight $key"); # $cipher ${$line}[0] ${$line}[2]"); } foreach my $line (sort @tmp_arr) { # sorts according $sec_owasp my @arr = split(" ", $line); push(@sorted, $arr[2]); } return @sorted; } # sort_results #_____________________________________________________________________________ #____________________________________________________ internal test methods __| sub show_getter03 { #? show hardcoded example for all getter functions for key 0x03000003 (aka 0x00,0x03) _v_print((caller(0))[3]); # 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"; # 0x03000003 $cipher = text2key("0x00,0x03");# normalize cipher key printf("# testing example: $cipher (aka 0x00,0x03) ...\n"); printf("# %s(%s)\t%s\t%-14s\t# %s\n", "function", "cipher key", "key", "value", "(expected)"); printf("#----------------------+-------+----------------+---------------\n"); #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_notes", $cipher, "tags", get_notes($cipher), "export"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_name", $cipher, "name", get_name( $cipher), "EXP-RC4-MD5"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_iana", $cipher, "iana", get_iana( $cipher), "no"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_pfs", $cipher, "pfs", get_iana( $cipher), "no"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_encsize",$cipher,"encsize", get_encsize( $cipher), "-"); printf("%-8s %s\t%s\t%-14s\t# %s\n", "get_data", $cipher, "data", get_data( $cipher), "WEAK WEAK SSLv3 RSA(512) RSA RC4 40 MD5 4346,6347 EXP-RC4-MD5 RSA_WITH_RC4_40_MD5,RSA_RC4_40_MD5,RSA_EXPORT_WITH_RC4_40_MD5,RC4_128_EXPORT40_WITH_MD5 export"); printf("#----------------------+-------+----------------+---------------\n"); return; } # show_getter03 sub show_getter { #? show example for all getter functions for specified cipher key my $key = shift; _v_print((caller(0))[3]); if ($key !~ m/^[x0-9a-fA-F,]+$/) { # no cipher given, print hardcoded example printf("# unknown cipher key '$key'; using hardcoded default instead\n"); show_getter03; return; } print "= testing: $key ...\n"; $key = text2key($key); # normalize cipher key if (not defined $ciphers{$key}) { _warn("511: undefined cipher '$key'"); return; } printf("= %s(%s)\t%s\t%s\n", "function", "cipher key", "key", "value"); printf("=----------------------+-------+----------------\n"); #printf("%-8s %s\t%s\t%s\n", "get_dtls", $key, "dtls", get_dtls( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_bits", $key, "bits", get_bits( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_enc", $key, "enc", get_enc( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_keyx", $key, "keyx", get_keyx( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_auth", $key, "auth", get_auth( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_mac", $key, "mac", get_mac( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_rfc", $key, "rfc", get_rfc( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_sec", $key, "sec", get_sec( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_ssl", $key, "ssl", get_ssl( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_name", $key, "name", get_name( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_names", $key, "names", get_names($key) ); printf("%-10s(%s)\t%s\t%s\n", "get_const", $key, "const", get_const($key) ); printf("%-10s(%s)\t%s\t%s\n", "get_const", $key, "const", get_const($key) ); printf("%-10s(%s)\t%s\t%s\n", "get_note", $key, "note", get_note( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_notes", $key, "notes", get_notes($key) ); printf("%-10s(%s)\t%s\t%s\n", "get_iana", $key, "iana", get_iana( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_pfs", $key, "pfs", get_iana( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_encsize",$key, "encsize", get_encsize( $key) ); printf("%-10s(%s)\t%s\t%s\n", "get_data", $key, "data", get_data( $key) ); printf("=----------------------+-------+----------------\n"); return; } # show_getter sub show_description { #? print textual description for columns %ciphers hash _v_print((caller(0))[3]); local $\ = "\n"; print " === internal data structure: overview of %ciphers === "; my $hex = '0x0300003D'; # our sample my $idx = 0; print ("= %ciphers : example line:\n"); # we should get the example $ciphers_desc{sample} printf(" '$hex' -> ["); # TODO 0x00,0x3D foreach (@{$ciphers_desc{head}}) { printf("\t%s", $ciphers_desc{sample}->{$hex}[$idx]); $idx++; } print (" ]"); print ("\n= %ciphers : tabular description of above (example) line:\n"); print ("=-------+--------------+-----------------------+--------"); printf("= [%s]\t%15s\t%16s\t%s\n", "nr", "key", "description", "example"); print ("=-------+--------------+-----------------------+--------"); $idx = 0; foreach (@{$ciphers_desc{head}}) { my $txt = $ciphers_desc{$ciphers_desc{head}[$idx]}; # quick dirty printf(" [%s]\t%15s\t%-20s\t%s\n", $idx, $ciphers_desc{head}[$idx], $txt, $ciphers_desc{sample}->{$hex}[$idx]); $idx++; } printf("=-------+--------------+-----------------------+--------"); print ("\n\n= %ciphers : description of one line as Perl code:\n"); print ("=------+--------------------------------+---------------+---------------"); printf("= varname %-23s\t# example result# description\n", "%ciphers hash"); print ("=------+--------------------------------+---------------+---------------"); $idx = 0; foreach my $col (@{$ciphers_desc{head}}) { my $var = $ciphers_desc{head}[$idx]; # quick dirty my $txt = $ciphers_desc{$var}; printf("%6s = \$ciphers{'%s'}{%s};\t# %-7s\t# %s\n", '$' . $var, $hex, $col, $ciphers_desc{sample}->{$hex}[$idx], $txt); $idx++; } print ("= additional following methods are available:"); printf("%6s = \$ciphers{'%s'}{%s};\t# %-7s\t# %s\n", '$' . 'name', $hex, 'name', 'AES256-SHA256', $ciphers_desc{'name'}); printf("%6s = \$ciphers{'%s'}{%s};\t# %-7s\t# %s\n", '$' . 'alias', $hex, 'alias', 'Alias', $ciphers_desc{'names'}); print ("=------+--------------------------------+---------------+---------------"); print "\n= \%cipher_results : description of hash:\n"; # currently (12/2015) print ("=-------------------------------------------+-------"); print ("= %hash{ ssl }->{'cipher key'} = value;"); print ("=-------------------------------------------+-------"); print (" %cipher_results{'TLSv12'}->{'0x0300003D'} = 'yes';"); # AES256-SHA256 print (" %cipher_results{'SSLv3'} ->{'0x02FF0810'} = 'no'; "); # NULL-NULL print ("=-------------------------------------------+-------"); return; } # show_description sub show_sorted { #? print %ciphers sorted according strength _v_print((caller(0))[3]); local $\ = "\n"; my $head = "= OWASP openssl self IANA cipher suite"; my $line = "=------+-------+-------+-------+----------------------------------------------"; print << 'EoT'; === internal data structure: ciphers sorted according strength === = = Show overview of all available ciphers sorted according OWASP scoring. = = description of columns: = OWASP - OWASP scoring (A, B, C, D) = openssl - strength given bei OpenSSL = self - strength according own rules = IANA - "yes" if recommended by IANA = cipher suite- OpenSSL suite name EoT print ($line); print ($head); print ($line); my @sorted; my @unsorted; push(@unsorted, get_name($_)) foreach sort keys %ciphers; foreach my $c (sort_names(@unsorted)) { my $key = get_key($c); push(@sorted, sprintf("%4s\t%s\t%s\t%s\t%s", get_cipher_owasp($c), get_openssl($key), get_sec($key), get_iana($key), $c )); } print foreach sort @sorted; print ($line); print ($head); printf("=\n"); printf("= %4s sorted ciphers\n", scalar @sorted); printf("= %4s ignored ciphers\n", ((keys %ciphers) - (scalar @sorted))); return; } # show_sorted sub show_overview { #? print overview of internal checks about %ciphers _v_print((caller(0))[3]); local $\ = "\n"; print << 'EoT'; === internal data structure: information about ciphers === = = This function prints a simple overview of all available ciphers. The purpose = is to show if the internal data structure provides all necessary data. = = description of columns: = key - hex key for cipher suite = security - cipher suite security is known = name - cipher suite (OpenSSL) name exists = aliases - cipher suite has other kown cipher suite names = const - cipher suite constant name exists = cipher suite- cipher suite name (OpenSSL) = description of values: = * value present (also if None or for pseudo ciphers) = - value missing = -?- security unknown/undefined = miss security missing in data structure = = No Perl or other warnings should be printed. = Note: following columns should have a * in columns = security, name, const EoT my $line = sprintf("=%s+%s+%s+%s+%s+%s", "-" x 14, "-"x 7, "-" x 7, "-" x 7, "-" x 7, "-" x 21); my $head = sprintf("= %-13s%s\t%s\t%s\t%s\t%s", "key", "security", "name", "aliases", "const", "cipher suite"); print($line); print($head); print($line); my %err; # count incomplete settings my $cnt = 0; foreach my $key (sort keys %ciphers) { $cnt++; my $sec = $ciphers{$key}->{'sec'}; my $name = "-"; my $alias = "-"; my $const = "-"; my $cipher = $ciphers{$key}->{'names'}[0]; # TODO: compare direct access of %cipher* with results of method get_* $sec = "*" if ($sec =~ m/None|weak|low|medium|high/i); # TODO: $cfg{'regex'}->{'security'}/i); $sec = "-" if ($sec ne "*" and $sec ne "-?-"); # anything else is - $name = "*" if $ciphers{$key}->{'names'}[0] ne ""; $alias = "*" if $ciphers{$key}->{'names'} ne "-"; $const = "*" if $ciphers{$key}->{'const'}[0] ne ""; printf("%12s\t%s\t%s\t%s\t%s\t%s\n", $key, $sec, $name, $alias, $const, $cipher); $err{'security'}++ if ('*' ne $sec ); $err{'name'}++ if ('*' ne $name); $err{'const'}++ if ('*' ne $const); $err{'aliases'}++ if ('*' ne $alias); } print($line); print($head); printf("=\n= %s ciphers\n", $cnt); printf("= identified errors: "); printf("%6s=%-2s,", $_, $err{$_}) foreach sort keys %err; printf("\n"); return; } # show_overview sub show_all_names { #? show aliases, constants or RFCs for cipher suite names depending on $type # $type: name | const | rfc my $type = shift; _v_print((caller(0))[3]); my $text = $type; $text = "name" if $type =~ /names/; # lazy check $text = "constant" if $type =~ /const/; # lazy check $text = "RFC" if $type =~ /rfc/; # my $txt_cols = "= cipher name - (most common) cipher suite $text = alias names - known aliases for cipher suite $text"; $txt_cols = "= cipher name - cipher suite name as used in openssl = RFC - RFC numbers, where cipher suite is described" if ("rfc" eq $type); local $\ = "\n"; print " === internal data structure: overview of various cipher suite ${text}s === = = description of columns: = key - hex key for cipher suite $txt_cols "; my $line = sprintf("=%s+%s+%s\n", "-" x 14, "-" x 39, "-" x 31); printf("$line"); printf("= %-13s\t%-37s\t%s\n", "key", "cipher name", "$text names"); printf("$line"); foreach my $key (sort keys %ciphers) { my @names = []; my $name = ""; if ('rfc' eq $type) { $name = $ciphers{$key}->{'names'}[0]; my $rfc = $ciphers{$key}->{'rfc'}; next if "-" eq $rfc; @names = $rfc; } else { @names = @{$ciphers{$key}->{$type}}; $name = shift @names; next if 1 > scalar @names; } printf("%s\t%-37s\t@names\n", $key, $name); } printf("$line"); printf("= %-13s\t%-37s\t%s\n", "key", "cipher name", "alias names"); return; } # show_all_names sub show_ssltest { #? print internal list of ciphers in format like ssltest # %ciphers are sorted by protocol and name # SEE Note:Testing, sort _v_print((caller(0))[3]); my $last_k = ""; foreach my $key (sort { $ciphers{$a}->{ssl} cmp $ciphers{$b}->{ssl} || $ciphers{$a}->{names} cmp $ciphers{$b}->{names} } keys %ciphers) { if ($last_k ne $ciphers{$key}->{ssl}) { $last_k = $ciphers{$key}->{ssl}; printf("%s Ciphers Supported...\n", $ciphers{$key}->{ssl}); } my $name = $ciphers{$key}->{'names'}[0]; # special value my $auth = $ciphers{$key}->{auth}; $auth = "No" if ($auth =~ /none/i); my $keyx = $ciphers{$key}->{keyx}; $keyx =~ s/[()]//g; my $bits = $ciphers{$key}->{bits}; if ($bits =~ m/\d+/) { $bits = sprintf("%03d", $ciphers{$key}->{bits}); } else { $bits = "-?-"; $bits = "000" if ($ciphers{$key}->{enc} =~ m/None/i); } # NULL-MD5, None 000 bits, No Auth, MD5 MAC, RSA512 Kx printf(" %s, %s %s bits, %s Auth, %s MAC, %s Kx\n", $name, $ciphers{$key}->{enc}, $bits, $auth, $ciphers{$key}->{mac}, $keyx); } return; } # show_ssltest sub show_ciphers { ## no critic qw(Subroutines::ProhibitExcessComplexity) #? print internal list of ciphers in specified format my $format = shift; _v_print((caller(0))[3]); local $\ = "\n"; if ($format !~ m/(?:dump|full|osaft|openssl|simple|show)/) { _warn("520: unknown format '$format'"); return; } my $out_header = 1; my $txt_head = ""; if ($format eq "openssl") { # like 'openssl ciphers' print join(":", get_names_list()); return; } if ($format =~ m/openssl/) { print << "EoT"; = Output is similar (order of columns) but not identical to result of = 'openssl ciphers -[vV]' command. EoT $out_header = 0; $txt_head = ""; } else { my $idx = 0; foreach (@{$ciphers_desc{head}}) { # build description from %ciphers_desc my $txt = $ciphers_desc{$ciphers_desc{head}[$idx]}; # quick dirty $txt_head .= sprintf("= %-12s - %s\n", $ciphers_desc{head}[$idx], $txt); $idx++; } } my @columns = @{$ciphers_desc{head}}; # cannot be used because we want specific order @columns = qw(openssl sec ssl keyx auth enc bits mac rfc names const notes) if ($format =~ m/^(?:dump|full|osaft)/); @columns = qw(ssl keyx auth enc bits mac) if ($format =~ m/^(?:openssl)/); @columns = qw(ssl keyx auth enc bits mac sec) if ($format =~ m/^(?:show)/); @columns = qw(sec ssl keyx auth enc bits mac) if ($format =~ m/^(?:simple)/); # table head my $line = sprintf("=%s\n", "-" x 77 ); my $head = ""; if ($format =~ m/^(?:dump|full|osaft)/) { # 0x02000000 weak SSLv2 RSA(512) RSA None Mac -?- NULL-MD5 NULL_WITH_MD5 - $line = sprintf("=%9s%s%s\n", "-" x 14, "+-------" x 9, "+---------------" x 3 ); $head = sprintf("= %-13s\t%9s\n", "key", join("\t", @columns)); } if ($format =~ m/^(?:show)/) { # 0x02000000 SSLv2 RSA(512) RSA None 0 Mac weak NULL-MD5 $line = sprintf("=%s%s+%s\n", "-" x 14, "+-------" x 7, "-" x 15 ); $head = sprintf("= %-13s\t%s\t%s\n", "key", join("\t", @columns), "cipher name"); } if ($format =~ m/^(?:simple)/) { # 0x02000000 weak SSLv2 RSA(512) RSA None 0 Mac NULL-MD5 # no fomated header just a line $head = sprintf("= %-13s\t%s\t%s\n", "key", join(" ", @columns), "cipher name"); } if ($format =~ m/^openssl-V/) { # 0x00,0x3D - AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256 # 0x00,0x00,0x00 - NULL-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=None(0) Mac $line = sprintf("=%s+%s+%s+%s+%s+%s+%s\n", "-" x 19, "-" x 24, "-" x 5, "-" x 11, "-" x 7, "-" x 11, "-" x 7 ); $head = sprintf("=% 18s - %-23s %-5s %-11s %-7s %-11s %s\n", "key", "name", @columns[0..2], "enc(bit)", "mac"); } if (0 < $out_header) { printf("%s", << "EoT"); # printf to avoid trailing \n === internal %ciphers data === = = Show a full overview of all available ciphers. = = description of columns (if available): = key - internal hex key for cipher suite = hex - hex key for cipher suite (like openssl) = cipher name - OpenSSL suite name $txt_head EoT printf($line); printf($head); printf($line); } # table data (format should be same as for table head above) my $cnt = 0; foreach my $key (sort keys %ciphers) { $cnt++; my $hex = key2text($key); # 0x02010080 --> 0x01,0x00,0x80 my $name = $ciphers{$key}->{'names'}[0]; # special value my $const = $ciphers{$key}->{'const'}[0]; # special value my $note = $ciphers{$key}->{'notes'}[0]; # special value my @values; if ($format =~ m/^(?:dump|full|osaft)/) { push(@values, $key); push(@values, $ciphers{$key}->{$_}) foreach @columns[0..8]; #push(@values, join(",", @{$ciphers{$key}->{$_}})) foreach @columns[9..11]; push(@values, join(",", @{$ciphers{$key}->{names}})); push(@values, join(",", @{$ciphers{$key}->{const}})); push(@values, join(",", @{$ciphers{$key}->{notes}})); printf("%s\n", join("\t", @values)); } if ($format =~ m/^(?:show)/) { push(@values, $key); push(@values, $ciphers{$key}->{$_}) foreach @columns; push(@values, $name); printf("%s\n", join("\t", @values)); } if ($format =~ m/^(?:simple)/) { push(@values, $ciphers{$key}->{$_}) foreach @columns; push(@values, $name); printf("%s\t%s\n", $key, join(" ", @values)); } if ($format =~ m/^(?:openssl-v)/) { push(@values, $name); push(@values, $ciphers{$key}->{$_}) foreach @columns; printf("%-23s %-6s Kx=%-8s Au=%-4s Enc=%s(%s) Mac=%s\n", @values); } if ($format =~ m/^(?:openssl-V)/) { push(@values, $hex, $name); push(@values, $ciphers{$key}->{$_}) foreach @columns; printf("%19s - %-23s %-6s Kx=%-8s Au=%-4s Enc=%s(%s) Mac=%s\n", @values); } } # keys # table footer if (0 < $out_header) { printf($line); printf($head); printf("=\n= %s ciphers\n", $cnt); } return; } # show_ciphers sub show { ## no critic qw(Subroutines::ProhibitExcessComplexity) #? dispatcher for various --test-cipher-* options; show information my $arg = shift; # any --test-cipher-* $arg =~ s/^--test[._-]?ciphers?[._-]?//; # normalize _v_print((caller(0))[3]); #_dbx("arg=$arg"); local $\ = "\n"; return if ($arg =~ m/^version/i ); # done in main show_all_names('const') if ($arg eq 'constants' ); show_all_names('names') if ($arg eq 'aliases' ); show_all_names('rfc') if ($arg eq 'rfcs' ); show_description() if ($arg eq 'description' ); show_description() if ($arg =~ m/^ciphers.?description/); show_overview() if ($arg eq 'overview' ); show_ssltest() if ($arg eq 'ssltest' ); show_sorted() if ($arg =~ m/^(owasp|sort(?:ed)?)/ ); ## no critic qw(RegularExpressions::ProhibitCaptureWithoutTest) show_ciphers($1) if ($arg =~ m/^(dump|full|osaft|openssl(?:-[vV])?|show|simple)/); show_getter($1) if ($arg =~ m/^getter=?(.*)/ ); print text2key($1) if ($arg =~ m/^text2key=(.*)/ ); print key2text($1) if ($arg =~ m/^key2text=(.*)/ ); print get_key($1) if ($arg =~ m/^(?:get.)?key=(.*)/ ); print get_sec($1) if ($arg =~ m/^(?:get.)?sec=(.*)/ ); print get_ssl($1) if ($arg =~ m/^(?:get.)?ssl=(.*)/ ); print get_keyx($1) if ($arg =~ m/^(?:get.)?keyx=(.*)/ ); print get_auth($1) if ($arg =~ m/^(?:get.)?auth=(.*)/ ); print get_enc($1) if ($arg =~ m/^(?:get.)?enc=(.*)/ ); print get_bits($1) if ($arg =~ m/^(?:get.)?bits=(.*)/ ); print get_mac($1) if ($arg =~ m/^(?:get.)?mac=(.*)/ ); print get_rfc($1) if ($arg =~ m/^(?:get.)?rfc=(.*)/ ); print get_name($1) if ($arg =~ m/^(?:get.)?name=(.*)/ ); print get_const($1) if ($arg =~ m/^(?:get.)?const=(.*)/ ); print get_note($1) if ($arg =~ m/^(?:get.)?note=(.*)/ ); print get_openssl($1) if ($arg =~ m/^(?:get.)?openssl=(.*)/); print get_encsize($1) if ($arg =~ m/^(?:get.)?encsize=(.*)/); print get_iana($1) if ($arg =~ m/^(?:get.)?iana=(.*)/ ); print get_pfs($1) if ($arg =~ m/^(?:get.)?pfs=(.*)/ ); print find_name($1) if ($arg =~ m/^find.?name=(.*)/ ); # enforce string value for returned arrays print join(" ", find_names($1)) if ($arg =~ m/^find.?names=(.*)/ ); print join(" ", find_keys($1)) if ($arg =~ m/^find.?keys=(.*)/ ); print join(" ", get_names($1)) if ($arg =~ m/^(?:get.)?names=(.*)/ ); print join(" ", get_aliases($1)) if ($arg =~ m/^(?:get.)?aliases=(.*)/); print join(" ", get_consts($1)) if ($arg =~ m/^(?:get.)?consts=(.*)/ ); print join(" ", get_notes($1)) if ($arg =~ m/^(?:get.)?notes=(.*)/ ); print join(" ", get_keys_list()) if ($arg =~ m/^(?:get.)?keys.?list/ ); print join(" ", get_names_list()) if ($arg =~ m/^(?:get.)?names.?list/ ); if ($arg =~ m/^regex/) { printf("#$0: direct testing not yet possible here, please try:\n o-saft.pl --test-ciphers-regex\n"); } return; } # show #_____________________________________________________________________________ #___________________________________________________ initialisation methods __| sub _ciphers_init { #? initialisations of %cihers data structures from # example: #0 #1 #2 #3 #4 #5 #6 #7 ... # 0x02020080 WEAK WEAK SSLv2 RSA(512) RSA RC4 40 MD5 -?- EXP-RC4-MD5 RC4_128_EXPORT40_WITH_MD5 EXPORT my $du = *DATA; # avoid Perl warning "... used only once: possible typo ..." $du = *main::DATA; # ... my $fh = *DATA; $fh = *main::DATA if (0 < $::osaft_standalone); # SEE Note:Stand-alone while (my $line = <$fh>) { chomp $line; next if ($line =~ m/^\s*$/); next if ($line =~ m/^\s*#/); last if ($line =~ m/__END/); my @fields = split(/\t/, $line); my $len = $#fields; my $key = $fields[0]; if ($key !~ /^0x[0-9A-F]{8}/) { _warn(sprintf("504: DATA line%4d: wrong hex key '%s'", $., $key)); next; } if (13 != $len+1) { _warn(sprintf("505: DATA line%4d: wrong number of TAB-separated fields '%s' != 13\n", $., $len)); next; } # now loop over @fields, but assign each to the hash; keys see %ciphers_desc $ciphers{$key}->{'openssl'} = $fields[1] || ''; $ciphers{$key}->{'sec'} = $fields[2] || ''; $ciphers{$key}->{'ssl'} = $fields[3] || ''; $ciphers{$key}->{'keyx'} = $fields[4] || ''; $ciphers{$key}->{'auth'} = $fields[5] || ''; $ciphers{$key}->{'enc'} = $fields[6] || ''; $ciphers{$key}->{'bits'} = ($fields[7] || '0 '); # our values are strings, but perl cast to int, which renders 0 as ''; ugly, very ugly hack $ciphers{$key}->{'mac'} = $fields[8] || ''; $ciphers{$key}->{'rfc'} = $fields[9] || ''; @{$ciphers{$key}->{'names'}}= split(/,/, $fields[10]); @{$ciphers{$key}->{'const'}}= split(/,/, $fields[11]); @{$ciphers{$key}->{'notes'}}= split(/,/, $fields[12]); #$ciphers{$key}->{'suite'} = # is first in $fields[10], } return; } # _ciphers_init #_____________________________________________________________________________ #_____________________________________________________________________ main __| sub _main_ciphers_usage { #? print usage my $name = (caller(0))[1]; print "# commands to show internal cipher tables:\n"; foreach my $cmd (qw(alias const dump description openssl rfc simple sort overview )) { printf("\t%s %s\n", $name, $cmd); } print "# commands to show cipher data:\n"; foreach my $cmd (qw(key=CIPHER-NAME getter=KEY)) { printf("\t%s %s\n", $name, $cmd); } print "# various commands (examples):\n"; printf("\t$name version\n"); printf("\t$name getter=0x0300CCA9\n"); # avoid: Possible attempt to separate words with commas at ... foreach my $cmd (qw(key=ECDHE-ECDSA-CHACHA20-POLY1305-SHA256 )) { printf("\t%s %s\n", $name, $cmd); } print "#\n# all commands can also be used as '--test-ciphers-CMD\n"; return; } # _main_ciphers_usage sub _main_ciphers { #? print own documentation or special required one ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # see t/.perlcriticrc for detailed description of "no critic" my @argv = @_; # SEE Perl:binmode() binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); print_pod($0, __PACKAGE__, $SID_ciphers) if (0 > $#argv); # got arguments, do something special while (my $arg = shift @argv) { print_pod($0, __PACKAGE__, $SID_ciphers) if ($arg =~ m/^--?h(?:elp)?$/); # print own help _main_ciphers_usage() if ($arg eq '--usage'); # ----------------------------- options $cfg{'verbose'}++ if ($arg eq '--v'); # ----------------------------- commands print "$SID_ciphers\n" if ($arg =~ /^version$/); print "$VERSION\n" if ($arg =~ /^[-+]?V(ERSION)?$/); print "$VERSION\n" if ($arg =~ /^--test.?ciphers.?version/i); # allow short option without --test-ciphers- prefix $arg =~ s/^--test.?ciphers.?//; # remove if there show("--test-ciphers-$arg"); } exit 0; } # _main_ciphers sub ciphers_done {}; # dummy to check successful include _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 of various (internal) checks according cipher definitions =item aliases - print overview of known cipher suite names =item constants - print overview of known cipher suite constant names =item rfcs - print overview of cipher suites and corresponding RFCs =item dump - print internal lists of ciphers (all data, internal format) =item show - print internal lists of ciphers (simple human readable format) =item simple - print internal lists of ciphers (simple space-separated format) =item sorted - print internal lists of ciphers (sorted according OWASP scoring) =item openssl - print internal lists of ciphers (format like "openssl ciphers -V") =item ssltest - print internal lists of ciphers (format like "ssltest --list") =item getter - print example for all getter functions for specified cipher key =back All commands can be used with or without '+' prefix, for example 'dump' is same as '+dump'. They can also be used with '--test-ciphers-' perfix, for example: '--test-ciphers-show'. =over 4 =item get_METHOD=HEX - print cipher suite value for 'METHOD', for valid 'get_METHOD' see METHODS above =item find_keys=CIPHER-SUITE - print cipher suite internal key for matching cipher names 'CIPHER-SUITE' =item find_names=CIPHER-SUITE - print cipher suite names for matching cipher names 'CIPHER-SUITE' =back =head1 OPTIONS =over 4 =item --usage - print usage for L of CLI mode =item --v - print verbose messages (in CLI mode only), must precede all commands =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 VERSION 2.80 2022/11/17 =head1 AUTHOR 28-may-16 Achim Hoffmann =cut ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main_ciphers(@ARGV) if (not defined caller); 1; ## CIPHERS { __DATA__ # Format of following data lines: # - empty lines are ignored # comments - line beginning with a # (hash); lines are ignored # 0xhhhhhhhh - data line containing a cipher suite; used columns are: # hex - hex constant for the cipher suite # openssl - security value (STRENGTH) used by openssl # sec - security value used by o-saft.pl # ssl - protocol where the cipher is used (PCT just for information) # keyx - key exchange of the cipher suite (Kx= in openssl) # auth - authenticatione of the cipher suite (Au= in openssl) # enc - encryption of the cipher suite (Enc= in openssl) # bits - bits for encryption of the cipher suite (Enc= in openssl) # mac - Mac of the cipher suite (Mac= in openssl) # cipher - list of known cipher suite names, most common first # const - list of known cipher suite constants, most common first # notes - list of notes and comments # # All columns must be separated by TABs (0x9 aka \t), no spaces are allowed. # The left-most column must not preceded by white spaces. It must begin with # the cipher suite hex key, like: 0x followed by exactly 8 hex characters # [0-9A-F]. Only such lines are used for ciphers. # If additional characters [a-zA-Z-] are used in the hex key it then does # not match ^0x[0-9a-fA-F]{8} . The definition is stored in %ciphers , but # will not be used anywhere (except informational lists). These definitions # are mainly used for documentation, for example ancient cipher definitions. # # Values in left-most column (the cipher's hex key) must be unique. # # In all other columns, following special strings are used: # - - empty value/string, value not existent, value not applicable # -?- - value currently unknown # None - value not used (as in openssl) # # The fomat/syntax of the table is very strict, because some other tools may # use and/or ignore this data. In particular, the characters " [ ] = are # not used to avoid conflicts in other tools (for example Excel). # # This table will be read in _ciphers_init() and converted to %ciphers . # hex const openssl sec ssl keyx auth enc bits mac rfc cipher,aliases const comment #--------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+---------------+-------+---------------+ 0x03005600 - None SSL/TLS None None - 0 None 7507 SCSV,TLS_FALLBACK_SCSV TLS_FALLBACK_SCSV SCSV 0x030000FF - None SSL/TLS None None - 0 None 5746 INFO_SCSV EMPTY_RENEGOTIATION_INFO_SCSV DOC 0x03000A0A - - TLSv13 None None - 0 None 8701 GREASE-0A GREASE_0A - 0x03001A1A - - TLSv13 None None - 0 None 8701 GREASE-1A GREASE_1A - 0x03002A2A - - TLSv13 None None - 0 None 8701 GREASE-2A GREASE_2A - 0x03003A3A - - TLSv13 None None - 0 None 8701 GREASE-3A GREASE_3A - 0x03004A4A - - TLSv13 None None - 0 None 8701 GREASE-4A GREASE_4A - 0x03005A5A - - TLSv13 None None - 0 None 8701 GREASE-5A GREASE_5A - 0x03006A6A - - TLSv13 None None - 0 None 8701 GREASE-6A GREASE_6A - 0x03007A7A - - TLSv13 None None - 0 None 8701 GREASE-7A GREASE_7A - 0x03008A8A - - TLSv13 None None - 0 None 8701 GREASE-8A GREASE_8A - 0x03009A9A - - TLSv13 None None - 0 None 8701 GREASE-9A GREASE_9A - 0x0300AAAA - - TLSv13 None None - 0 None 8701 GREASE-AA GREASE_AA - 0x0300BABA - - TLSv13 None None - 0 None 8701 GREASE-BA GREASE_BA - 0x0300CACA - - TLSv13 None None - 0 None 8701 GREASE-CA GREASE_CA - 0x0300DADA - - TLSv13 None None - 0 None 8701 GREASE-DA GREASE_DA - 0x0300EAEA - - TLSv13 None None - 0 None 8701 GREASE-EA GREASE_EA - 0x0300FAFA - - TLSv13 None None - 0 None 8701 GREASE-FA GREASE_0A - #0x00800000 - nix PCT -?- -?- -?- -?- -?- - const - for testing only 0x00800001 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_CERT_TYPE PCT1_CERT_X509 PCT 0x00800003 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_CERT_TYPE PCT1_CERT_X509_CHAIN PCT 0x00810001 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_HASH_TYPE PCT1_HASH_MD5 PCT 0x00810003 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_HASH_TYPE PCT1_HASH_SHA PCT 0x00820003 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_EXCH_TYPE PCT1_EXCH_RSA_PKCS1 PCT 0x00823004 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_CIPHER_TYPE_1ST_HALF PCT1_CIPHER_RC4 PCT 0x00842840 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_CIPHER_TYPE_2ND_HALF PCT1_ENC_BITS_40|PCT1_MAC_BITS_128 PCT 0x00848040 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_CIPHER_TYPE_2ND_HALF PCT1_ENC_BITS_128|PCT1_MAC_BITS_128 PCT 0x008F8001 - -?- PCT -?- -?- -?- -?- -?- - PCT_SSL_COMPAT PCT_VERSION_1 PCT 0x02000000 - weak SSLv2 RSA(512) None None 0 MD5 -?- NULL-MD5 NULL_WITH_MD5 - 0x02010080 MEDIUM weak SSLv2 RSA RSA RC4 128 MD5 -?- RC4-MD5 RC4_128_WITH_MD5 - 0x02020080 WEAK WEAK SSLv2 RSA(512) RSA RC4 40 MD5 -?- EXP-RC4-MD5 RC4_128_EXPORT40_WITH_MD5 EXPORT 0x02030080 MEDIUM weak SSLv2 RSA RSA RC2 128 MD5 -?- RC2-CBC-MD5,RC2-MD5 RC2_128_CBC_WITH_MD5 - 0x02040080 -?- weak SSLv2 RSA(512) RSA RC2 40 MD5 -?- EXP-RC2-CBC-MD5,EXP-RC2-MD5 RC2_128_CBC_EXPORT40_WITH_MD5 EXPORT 0x02050080 MEDIUM weak SSLv2 RSA RSA IDEA 128 MD5 -?- IDEA-CBC-MD5 IDEA_128_CBC_WITH_MD5,IDEA_CBC_WITH_MD5 - 0x02060040 LOW weak SSLv2 RSA RSA DES 56 MD5 -?- DES-CBC-MD5 DES_64_CBC_WITH_MD5,DES_CBC_WITH_MD5 - 0x02060140 -?- weak SSLv2 RSA RSA DES 56 SHA1 -?- DES-CBC-SHA DES_64_CBC_WITH_SHA - 0x020700C0 MEDIUM weak SSLv2 RSA RSA 3DES 112 MD5 -?- DES-CBC3-MD5 DES_192_EDE3_CBC_WITH_MD5 - 0x020701C0 MEDIUM weak SSLv2 RSA RSA 3DES 112 SHA1 -?- DES-CBC3-SHA DES_192_EDE3_CBC_WITH_SHA - 0x02080080 LOW weak SSLv2 RSA RSA RC4 64 MD5 -?- RC4-64-MD5,EXP-RC4-64-MD5 RC4_64_WITH_MD5 BSAFE 0x02FF0800 -?- weak SSLv2 RSA RSA DES 64 MD5 -?- DES-CFB-M1 DES_64_CFB64_WITH_MD5_1 - 0x02FF0810 -?- weak SSLv2 RSA(512) None None 0 MD5 - NULL NULL SSLeay 0x03000000 -?- weak SSLv3 RSA None None 0 MD5 5246 NULL-NULL NULL_WITH_NULL_NULL SSLeay 0x03000001 -?- weak SSLv3 RSA RSA None 0 MD5 5246 NULL-MD5 RSA_WITH_NULL_MD5,RSA_NULL_MD5 EXPORT 0x03000002 -?- weak SSLv3 RSA RSA None 0 SHA1 5246 NULL-SHA RSA_WITH_NULL_SHA,RSA_NULL_SHA - 0x03000003 WEAK WEAK SSLv3 RSA(512) RSA RC4 40 MD5 4346,6347 EXP-RC4-MD5 RSA_WITH_RC4_40_MD5,RSA_RC4_40_MD5,RSA_EXPORT_WITH_RC4_40_MD5,RC4_128_EXPORT40_WITH_MD5 EXPORT 0x03000004 MEDIUM weak SSLv3 RSA RSA RC4 128 MD5 5246,6347 RC4-MD5 RSA_WITH_RC4_128_MD5,RSA_RC4_128_MD5,RC4_128_WITH_MD5 - 0x03000005 MEDIUM weak SSLv3 RSA RSA RC4 128 SHA1 5246,6347 RC4-SHA RSA_WITH_RC4_128_SHA,RSA_RC4_128_SHA,RC4_128_WITH_SHA - 0x03000006 -?- weak SSLv3 RSA(512) RSA RC2 40 MD5 4346 EXP-RC2-CBC-MD5 RSA_WITH_RC2_40_MD5,RSA_RC2_40_MD5,RSA_EXPORT_WITH_RC2_CBC_40_MD5,RC2_128_CBC_EXPORT40_WITH_MD5 EXPORT 0x03000007 MEDIUM weak SSLv3 RSA RSA IDEA 128 SHA1 5469 IDEA-CBC-SHA RSA_WITH_IDEA_CBC_SHA,RSA_WITH_IDEA_SHA,RSA_IDEA_128_SHA - 0x03000008 WEAK WEAK SSLv3 RSA(512) RSA DES 40 SHA1 4346 EXP-DES-CBC-SHA RSA_DES_40_CBC_SHA,RSA_EXPORT_WITH_DES40_CBC_SHA EXPORT 0x03000009 LOW weak SSLv3 RSA RSA DES 56 SHA1 5469 DES-CBC-SHA RSA_WITH_DES_CBC_SHA,RSA_DES_64_CBC_SHA - 0x0300000A MEDIUM weak SSLv3 RSA RSA 3DES 112 SHA1 5246 DES-CBC3-SHA RSA_WITH_3DES_EDE_CBC_SHA,RSA_DES_192_CBC3_SHA,DES_192_EDE3_CBC_WITH_SHA - 0x0300000B -?- weak SSLv3 DH/DSS DH DES 40 SHA1 4346 EXP-DH-DSS-DES-CBC-SHA DH_DSS_DES_40_CBC_SHA,DH_DSS_EXPORT_WITH_DES40_CBC_SHA EXPORT 0x0300000C LOW weak SSLv3 DH/DSS DH DES 56 SHA1 5469 DH-DSS-DES-CBC-SHA DH_DSS_DES_64_CBC_SHA,DH_DSS_WITH_DES_CBC_SHA - 0x0300000D MEDIUM weak SSLv3 DH/DSS DH 3DES 112 SHA1 5246 DH-DSS-DES-CBC3-SHA DH_DSS_DES_192_CBC3_SHA,DH_DSS_WITH_3DES_EDE_CBC_SHA - 0x0300000E -?- weak SSLv3 DH/RSA DH DES 40 SHA1 4346 EXP-DH-RSA-DES-CBC-SHA DH_RSA_DES_40_CBC_SHA,DH_RSA_EXPORT_WITH_DES40_CBC_SHA EXPORT 0x0300000F LOW weak SSLv3 DH/RSA DH DES 56 SHA1 5469 DH-RSA-DES-CBC-SHA DH_RSA_DES_64_CBC_SHA,DH_RSA_WITH_DES_CBC_SHA - 0x03000010 MEDIUM weak SSLv3 DH/RSA DH 3DES 112 SHA1 5246 DH-RSA-DES-CBC3-SHA DH_RSA_DES_192_CBC3_SHA,DH_RSA_WITH_3DES_EDE_CBC_SHA - 0x03000011 -?- weak SSLv3 DH(512) DSS DES 40 SHA1 4346 EXP-EDH-DSS-DES-CBC-SHA EDH_DSS_DES_40_CBC_SHA,DHE_DSS_DES_40_CBC_SHA,EDH_DSS_EXPORT_WITH_DES40_CBC_SHA EXPORT 0x03000012 LOW weak SSLv3 DH DSS DES 56 SHA1 5469 EDH-DSS-DES-CBC-SHA,EDH-DSS-CBC-SHA EDH_DSS_DES_64_CBC_SHA,DHE_DSS_DES_64_CBC_SHA,DHE_DSS_WITH_DES_CBC_SHA,EDH_DSS_WITH_DES_CBC_SHA - 0x03000013 MEDIUM weak SSLv3 DH DSS 3DES 112 SHA1 5246 EDH-DSS-DES-CBC3-SHA,DHE-DSS-DES-CBC3-SHA EDH_DSS_DES_192_CBC3_SHA,DHE_DSS_DES_192_CBC3_SHA,DHE_DSS_WITH_3DES_EDE_CBC_SHA,EDH_DSS_WITH_3DES_EDE_CBC_SHA - 0x03000014 LOW weak SSLv3 DH(512) RSA DES 40 SHA1 4346 EXP-EDH-RSA-DES-CBC-SHA EDH_RSA_DES_40_CBC_SHA,DHE_RSA_DES_40_CBC_SHA,DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,EDH_RSA_EXPORT_WITH_DES40_CBC_SHA EXPORT 0x03000015 LOW weak SSLv3 DH RSA DES 56 SHA1 5469 EDH-RSA-DES-CBC-SHA EDH_RSA_DES_64_CBC_SHA,DHE_RSA_DES_64_CBC_SHA,DHE_RSA_WITH_DES_CBC_SHA,EDH_RSA_WITH_DES_CBC_SHA - 0x03000016 MEDIUM weak SSLv3 DH RSA 3DES 112 SHA1 5246 EDH-RSA-DES-CBC3-SHA,DHE-RSA-DES-CBC3-SHA EDH_RSA_DES_192_CBC3_SHA,DHE_RSA_DES_192_CBC3_SHA,DHE_RSA_WITH_3DES_EDE_CBC_SHA,EDH_RSA_WITH_3DES_EDE_CBC_SHA - 0x03000017 WEAK WEAK SSLv3 DH(512) None RC4 40 MD5 4346,6347 EXP-ADH-RC4-MD5 ADH_RC4_40_MD5,DH_anon_EXPORT_WITH_RC4_40_MD5 EXPORT 0x03000018 MEDIUM weak SSLv3 DH None RC4 128 MD5 5246,6347 ADH-RC4-MD5,DHanon-RC4-MD5 ADH_RC4_128_MD5,DH_anon_WITH_RC4_MD5,DH_anon_WITH_RC4_128_MD5 - 0x03000019 -?- weak SSLv3 DH(512) None DES 40 SHA1 4346 EXP-ADH-DES-CBC-SHA ADH_DES_40_CBC_SHA,DH_anon_EXPORT_WITH_DES40_CBC_SHA EXPORT 0x0300001A LOW weak SSLv3 DH None DES 56 SHA1 5469 ADH-DES-CBC-SHA,DHanon-DES-CBC-SHA ADH_DES_64_CBC_SHA,DH_anon_WITH_DES_CBC_SHA - 0x0300001B MEDIUM weak SSLv3 DH None 3DES 112 SHA1 5246 ADH-DES-CBC3-SHA,DHanon-DES-CBC3-SHA ADH_DES_192_CBC_SHA,DH_anon_WITH_3DES_EDE_CBC_SHA - 0x0300001C -?- weak SSLv3 FZA FZA None 0 SHA1 5246 FZA-NULL-SHA FZA_DMS_NULL_SHA,FORTEZZA_KEA_WITH_NULL_SHA M 0x0300001D MEDIUM MEDIUM SSLv3 FZA FZA FZA 0 SHA1 5246 FZA-FZA-SHA,FZA-FZA-CBC-SHA FZA_DMS_FZA_SHA,FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA M 0x0300001E-bug WEAK WEAK SSLv3 FZA FZA RC4 128 SHA1 - FZA-RC4-SHA FZA_DMS_RC4_SHA M 0x0300001E LOW weak SSLv3 KRB5 KRB5 DES 56 SHA1 2712 KRB5-DES-CBC-SHA KRB5_DES_64_CBC_SHA,KRB5_WITH_DES_CBC_SHA P 0x0300001F MEDIUM weak SSLv3 KRB5 KRB5 3DES 112 SHA1 2712 KRB5-DES-CBC3-SHA KRB5_DES_192_CBC3_SHA,KRB5_WITH_3DES_EDE_CBC_SHA P 0x03000020 MEDIUM weak SSLv3 KRB5 KRB5 RC4 128 SHA1 2712,6347 KRB5-RC4-SHA KRB5_RC4_128_SHA,KRB5_WITH_RC4_128_SHA P 0x03000021 MEDIUM weak SSLv3 KRB5 KRB5 IDEA 128 SHA1 2712 KRB5-IDEA-CBC-SHA KRB5_IDEA_128_CBC_SHA,KRB5_WITH_IDEA_CBC_SHA P 0x03000022 LOW weak SSLv3 KRB5 KRB5 DES 56 MD5 2712 KRB5-DES-CBC-MD5 KRB5_DES_64_CBC_MD5,KRB5_WITH_DES_CBC_MD5 P 0x03000023 MEDIUM weak SSLv3 KRB5 KRB5 3DES 112 MD5 2712 KRB5-DES-CBC3-MD5 KRB5_DES_192_CBC3_MD5,KRB5_WITH_3DES_EDE_CBC_MD5 P 0x03000024 MEDIUM weak SSLv3 KRB5 KRB5 RC4 128 MD5 2712,6347 KRB5-RC4-MD5 KRB5_RC4_128_MD5,KRB5_WITH_RC4_128_MD5 P 0x03000025 MEDIUM weak SSLv3 KRB5 KRB5 IDEA 128 MD5 2712 KRB5-IDEA-CBC-MD5 KRB5_IDEA_128_CBC_MD5,KRB5_WITH_IDEA_CBC_MD5 P 0x03000026 -?- weak SSLv3 KRB5 KRB5 DES 40 SHA1 2712 EXP-KRB5-DES-CBC-SHA KRB5_DES_40_CBC_SHA,KRB5_EXPORT_WITH_DES_CBC_40_SHA EXPORT,P 0x03000027 -?- weak SSLv3 KRB5 KRB5 RC2 40 SHA1 2712 EXP-KRB5-RC2-CBC-SHA KRB5_RC2_40_CBC_SHA,KRB5_EXPORT_WITH_RC2_CBC_40_SHA EXPORT,P 0x03000028 -?- weak SSLv3 KRB5 KRB5 RC4 40 SHA1 2712,6347 EXP-KRB5-RC4-SHA KRB5_RC4_40_SHA,KRB5_EXPORT_WITH_RC4_40_SHA EXPORT,P 0x03000029 -?- weak SSLv3 KRB5 KRB5 DES 40 MD5 2712 EXP-KRB5-DES-CBC-MD5 KRB5_DES_40_CBC_MD5,KRB5_EXPORT_WITH_DES_CBC_40_MD5 EXPORT,P 0x0300002A -?- weak SSLv3 KRB5 KRB5 RC2 40 MD5 2712 EXP-KRB5-RC2-CBC-MD5 KRB5_RC2_40_CBC_MD5,KRB5_EXPORT_WITH_RC2_CBC_40_MD5,KRB5_WITH_RC2_CBC_40_MD5 EXPORT,P 0x0300002B -?- weak SSLv3 KRB5 KRB5 RC4 40 MD5 2712,6347 EXP-KRB5-RC4-MD5 KRB5_RC4_40_MD5,KRB5_EXPORT_WITH_RC4_40_MD5 EXPORT,P 0x0300002C -?- weak SSLv3 DH RSA None 0 SHA1 4785 PSK-SHA,PSK-NULL-SHA PSK_WITH_NULL_SHA - 0x0300002D -?- weak SSLv3 DHEPSK PSK None 0 SHA1 4785 DHE-PSK-NULL-SHA DHE_PSK_WITH_NULL_SHA FIXME 0x0300002E -?- weak SSLv3 RSAPSK PSK None 0 SHA1 4785 RSA-PSK-NULL-SHA RSA_PSK_WITH_NULL_SHA FIXME 0x0300002F HIGH HIGH SSLv3 RSA RSA AES 128 SHA1 5246 AES128-SHA RSA_WITH_AES_128_CBC_SHA,RSA_WITH_AES_128_SHA - 0x03000030 HIGH medium SSLv3 DH DSS AES 128 SHA1 5246 DH-DSS-AES128-SHA DH_DSS_WITH_AES_128_SHA,DH_DSS_WITH_AES_128_CBC_SHA - 0x03000031 HIGH medium SSLv3 DH RSA AES 128 SHA1 5246 DH-RSA-AES128-SHA DH_RSA_WITH_AES_128_SHA,DH_RSA_WITH_AES_128_CBC_SHA - 0x03000032 HIGH HIGH SSLv3 DH DSS AES 128 SHA1 5246 DHE-DSS-AES128-SHA,EDH-DSS-AES128-SHA DHE_DSS_WITH_AES_128_CBC_SHA,DHE_DSS_WITH_AES_128_SHA BSAFE 0x03000033 HIGH HIGH SSLv3 DH RSA AES 128 SHA1 5246 DHE-RSA-AES128-SHA,EDH-RSA-AES128-SHA DHE_RSA_WITH_AES_128_CBC_SHA,DHE_RSA_WITH_AES_128_SHA - 0x03000034 HIGH weak SSLv3 DH None AES 128 SHA1 5246 ADH-AES128-SHA ADH_WITH_AES_128_SHA,DH_anon_WITH_AES_128_CBC_SHA - 0x03000035 HIGH HIGH SSLv3 RSA RSA AES 256 SHA1 5246 AES256-SHA RSA_WITH_AES_256_SHA,RSA_WITH_AES_256_CBC_SHA - 0x03000036 HIGH medium SSLv3 DH DSS AES 256 SHA1 5246 DH-DSS-AES256-SHA DH_DSS_WITH_AES_256_SHA,DH_DSS_WITH_AES_256_CBC_SHA - 0x03000037 HIGH medium SSLv3 DH RSA AES 256 SHA1 5246 DH-RSA-AES256-SHA DH_RSA_WITH_AES_256_SHA,DH_RSA_WITH_AES_256_CBC_SHA - 0x03000038 HIGH HIGH SSLv3 DH DSS AES 256 SHA1 5246 DHE-DSS-AES256-SHA,EDH-DSS-AES256-SHA DHE_DSS_WITH_AES_256_SHA,DHE_DSS_WITH_AES_256_CBC_SHA - 0x03000039 HIGH HIGH SSLv3 DH RSA AES 256 SHA1 5246 DHE-RSA-AES256-SHA,EDH-RSA-AES256-SHA DHE_RSA_WITH_AES_256_SHA,DHE_RSA_WITH_AES_256_CBC_SHA - 0x0300003A HIGH weak SSLv3 DH None AES 256 SHA1 5246 ADH-AES256-SHA ADH_WITH_AES_256_SHA,DH_anon_WITH_AES_256_CBC_SHA - 0x0300003B -?- weak TLSv12 RSA RSA None 0 SHA256 5246 NULL-SHA256 RSA_WITH_NULL_SHA256 L 0x0300003C HIGH HIGH TLSv12 RSA RSA AES 128 SHA256 5246 AES128-SHA256 RSA_WITH_AES_128_SHA256,RSA_WITH_AES_128_CBC_SHA256 L 0x0300003D HIGH HIGH TLSv12 RSA RSA AES 256 SHA256 5246 AES256-SHA256 RSA_WITH_AES_256_SHA256,RSA_WITH_AES_256_CBC_SHA256 L 0x0300003E HIGH HIGH TLSv12 DH/DSS DH AES 128 SHA256 5246 DH-DSS-AES128-SHA256 DH_DSS_WITH_AES_128_SHA256,DH_DSS_WITH_AES_128_CBC_SHA256 L 0x0300003F HIGH HIGH TLSv12 DH/RSA DH AES 128 SHA256 5246 DH-RSA-AES128-SHA256 DH_RSA_WITH_AES_128_SHA256,DH_RSA_WITH_AES_128_CBC_SHA256 L 0x03000040 HIGH HIGH TLSv12 DH DSS AES 128 SHA256 5246 DHE-DSS-AES128-SHA256 DHE_DSS_WITH_AES_128_SHA256,DHE_DSS_WITH_AES_128_CBC_SHA256 L 0x03000041 HIGH HIGH TLSv1 RSA RSA CAMELLIA 128 SHA1 4132,5932 CAMELLIA128-SHA RSA_WITH_CAMELLIA_128_CBC_SHA - 0x03000042 HIGH HIGH TLSv1 DH DSS CAMELLIA 128 SHA1 4132,5932 DH-DSS-CAMELLIA128-SHA DH_DSS_WITH_CAMELLIA_128_CBC_SHA - 0x03000043 HIGH HIGH TLSv1 DH RSA CAMELLIA 128 SHA1 4132,5932 DH-RSA-CAMELLIA128-SHA DH_RSA_WITH_CAMELLIA_128_CBC_SHA - 0x03000044 HIGH HIGH TLSv1 DH DSS CAMELLIA 128 SHA1 4132,5932 DHE-DSS-CAMELLIA128-SHA DHE_DSS_WITH_CAMELLIA_128_CBC_SHA - 0x03000045 HIGH HIGH TLSv1 DH RSA CAMELLIA 128 SHA1 4132,5932 DHE-RSA-CAMELLIA128-SHA DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - 0x03000046 HIGH weak TLSv1 DH None CAMELLIA 128 SHA1 4132,5932 ADH-CAMELLIA128-SHA ADH_WITH_CAMELLIA_128_CBC_SHA,DH_anon_WITH_CAMELLIA_128_CBC_SHA - 0x03000060 WEAK WEAK SSLv3 RSA(1024) RSA RC4 56 MD5 -?- EXP1024-RC4-MD5 RSA_EXPORT1024_WITH_RC4_56_MD5 EXPORT 0x03000061 -?- weak SSLv3 RSA(1024) RSA RC2 56 MD5 -?- EXP1024-RC2-CBC-MD5 RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 EXPORT 0x03000062 -?- weak SSLv3 RSA(1024) RSA DES 56 SHA1 -?- EXP1024-DES-CBC-SHA,EXP-DES-56-SHA RSA_EXPORT1024_WITH_DES_CBC_SHA EXPORT 0x03000063 -?- weak SSLv3 DH(1024) DSS DES 56 SHA1 -?- EXP1024-DHE-DSS-DES-CBC-SHA,EXP-EDH-DSS-DES-56-SHA DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA EXPORT 0x03000064 WEAK WEAK SSLv3 RSA(1024) RSA RC4 56 SHA1 -?- EXP1024-RC4-SHA,EXP-RC4-56-SHA RSA_EXPORT1024_WITH_RC4_56_SHA EXPORT 0x03000065 WEAK WEAK SSLv3 DH(1024) DSS RC4 56 SHA1 -?- EXP1024-DHE-DSS-RC4-SHA,EXP-EDH-DSS-RC4-56-SHA DHE_DSS_EXPORT1024_WITH_RC4_56_SHA EXPORT,BSAFE 0x03000066 MEDIUM weak SSLv3 DH DSS RC4 128 SHA1 -?- DHE-DSS-RC4-SHA,EDH-DSS-RC4-SHA DHE_DSS_WITH_RC4_128_SHA BSAFE 0x03000067 HIGH HIGH TLSv12 DH RSA AES 128 SHA256 5246 DHE-RSA-AES128-SHA256 DHE_RSA_WITH_AES_128_SHA256,DHE_RSA_WITH_AES_128_CBC_SHA256 L 0x03000068 HIGH HIGH TLSv12 DH/DSS DH AES 256 SHA256 5246 DH-DSS-AES256-SHA256 DH_DSS_WITH_AES_256_SHA256,DH_DSS_WITH_AES_256_CBC_SHA256 - 0x03000069 HIGH HIGH TLSv12 DH/RSA DH AES 256 SHA256 5246 DH-RSA-AES256-SHA256 DH_RSA_WITH_AES_256_SHA256,DH_RSA_WITH_AES_256_CBC_SHA256 - 0x0300006A HIGH HIGH TLSv12 DH DSS AES 256 SHA256 5246 DHE-DSS-AES256-SHA256 DHE_DSS_WITH_AES_256_SHA256,DHE_DSS_WITH_AES_256_CBC_SHA256 L 0x0300006B HIGH HIGH TLSv12 DH RSA AES 256 SHA256 5246 DHE-RSA-AES256-SHA256 DHE_RSA_WITH_AES_256_SHA256,DHE_RSA_WITH_AES_256_CBC_SHA256 L 0x0300006C HIGH weak TLSv12 DH None AES 128 SHA256 5246 ADH-AES128-SHA256 ADH_WITH_AES_128_SHA256,DH_anon_WITH_AES_128_CBC_SHA256 L 0x0300006D HIGH weak TLSv12 DH None AES 256 SHA256 5246 ADH-AES256-SHA256 ADH_WITH_AES_256_SHA256,DH_anon_WITH_AES_256_CBC_SHA256 L 0x03000070 -?- weak SSLv3 DH DSS CAST 128 SHA1 - DHE-DSS-CAST128-CBC-SHA DHE_DSS_WITH_CAST_128_CBC_SHA PGP,H 0x03000071 -?- weak SSLv3 DH DSS CAST 128 RIPEMD - DHE-DSS-CAST128-CBC-RMD DHE_DSS_WITH_CAST_128_CBC_RMD PGP,H 0x03000072 -?- weak SSLv3 DH DSS 3DES 128 RIPEMD -?- DHE-DSS-3DES-EDE-CBC-RMD DHE_DSS_WITH_3DES_EDE_CBC_RMD PGP 0x03000073 -?- weak SSLv3 DH DSS AES 128 RIPEMD -?- DHE-DSS-AES128-CBC-RMD DHE_DSS_WITH_AES_128_CBC_RMD PGP 0x03000074 -?- weak SSLv3 DH DSS AES 128 RIPEMD -?- DHE-DSS-AES256-CBC-RMD DHE_DSS_WITH_AES_256_CBC_RMD PGP 0x03000075 -?- weak SSLv3 DH RSA CAST 128 SHA1 - DHE-RSA-CAST128-CBC-SHA DHE_RSA_WITH_CAST_128_CBC_SHA PGP,H 0x03000076 -?- weak SSLv3 DH RSA CAST 128 RIPEMD - DHE-RSA-CAST128-CBC-RMD DHE_RSA_WITH_CAST_128_CBC_RMD PGP,H 0x03000077 -?- weak SSLv3 DH RSA 3DES 128 RIPEMD -?- DHE-RSA-3DES-EDE-CBC-RMD DHE_RSA_WITH_3DES_EDE_CBC_RMD PGP 0x03000078 -?- weak SSLv3 DH RSA AES 128 RIPEMD -?- DHE-RSA-AES128-CBC-RMD DHE_RSA_WITH_AES_128_CBC_RMD PGP 0x03000079 -?- weak SSLv3 DH RSA AES 128 RIPEMD -?- DHE-RSA-AES256-CBC-RMD DHE_RSA_WITH_AES_256_CBC_RMD PGP 0x0300007A -?- weak SSLv3 RSA RSA CAST 128 SHA1 - RSA-CAST128-CBC-SHA RSA_WITH_CAST_128_CBC_SHA H 0x0300007B -?- weak SSLv3 RSA RSA CAST 128 RIPEMD - RSA-CAST128-CBC-RMD RSA_WITH_CAST_128_CBC_RMD H 0x0300007C -?- weak SSLv3 RSA RSA 3DES 128 RIPEMD -?- RSA-3DES-EDE-CBC-RMD RSA_WITH_3DES_EDE_CBC_RMD - 0x0300007D -?- weak SSLv3 RSA RSA AES 128 RIPEMD -?- RSA-AES128-CBC-RMD RSA_WITH_AES_128_CBC_RMD - 0x0300007E -?- weak SSLv3 RSA RSA AES 128 RIPEMD -?- RSA-AES256-CBC-RMD RSA_WITH_AES_256_CBC_RMD - 0x03000080 HIGH HIGH SSLv3 GOST GOST94 GOST89 256 GOST89 5830 GOST94-GOST89-GOST89 GOSTR341094_WITH_28147_CNT_IMIT G 0x03000081 HIGH HIGH SSLv3 GOST GOST01 GOST89 256 GOST89 5830 GOST2001-GOST89-GOST89 GOSTR341001_WITH_28147_CNT_IMIT G 0x03000082 -?- weak SSLv3 GOST GOST94 None 0 GOST94 -?- GOST94-NULL-GOST94 GOSTR341094_WITH_NULL_GOSTR3411 G 0x03000083 -?- weak SSLv3 GOST GOST01 None 0 GOST94 -?- GOST2001-NULL-GOST94 GOSTR341001_WITH_NULL_GOSTR3411 G 0x03000084 HIGH HIGH TLSv1 RSA RSA CAMELLIA 256 SHA1 4132,5932 CAMELLIA256-SHA RSA_WITH_CAMELLIA_256_CBC_SHA - 0x03000085 HIGH HIGH TLSv1 DSS DH CAMELLIA 256 SHA1 4132,5932 DH-DSS-CAMELLIA256-SHA DH_DSS_WITH_CAMELLIA_256_CBC_SHA - 0x03000085-c HIGH HIGH TLSv1 DH DH CAMELLIA 256 SHA1 -?- DH-DSS-CAMELLIA256-SHA -?- C 0x03000086 HIGH HIGH TLSv1 RSA DH CAMELLIA 256 SHA1 4132,5932 DH-RSA-CAMELLIA256-SHA DH_RSA_WITH_CAMELLIA_256_CBC_SHA - 0x03000086-c HIGH HIGH TLSv1 DH DH CAMELLIA 256 SHA1 -?- DH-RSA-CAMELLIA256-SHA -?- C 0x03000087 HIGH HIGH TLSv1 DH DSS CAMELLIA 256 SHA1 4132,5932 DHE-DSS-CAMELLIA256-SHA DHE_DSS_WITH_CAMELLIA_256_CBC_SHA - 0x03000088 HIGH HIGH TLSv1 DH RSA CAMELLIA 256 SHA1 4132,5932 DHE-RSA-CAMELLIA256-SHA DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - 0x03000089 HIGH weak TLSv1 DH None CAMELLIA 256 SHA1 4132,5932 ADH-CAMELLIA256-SHA ADH_WITH_CAMELLIA_256_CBC_SHA,DH_anon_WITH_CAMELLIA_256_CBC_SHA - 0x0300008A MEDIUM medium SSLv3 PSK PSK RC4 128 SHA1 4279,6347 PSK-RC4-SHA PSK_WITH_RC4_128_SHA - 0x0300008B MEDIUM medium SSLv3 PSK PSK 3DES 112 SHA1 4279 PSK-3DES-EDE-CBC-SHA,PSK-3DES-SHA PSK_WITH_3DES_EDE_CBC_SHA - 0x0300008C HIGH medium SSLv3 PSK PSK AES 128 SHA1 4279 PSK-AES128-CBC-SHA PSK_WITH_AES_128_CBC_SHA - 0x0300008D HIGH medium SSLv3 PSK PSK AES 256 SHA1 4279 PSK-AES256-CBC-SHA PSK_WITH_AES_256_CBC_SHA - 0x0300008E -?- medium TLSv12 DHE PSK RC4 128 SHA1 4279,6347 DHE-PSK-RC4-SHA DHE_PSK_WITH_RC4_128_SHA FIXME 0x0300008F -?- medium TLSv12 DHE PSK 3DES 112 SHA1 4279 DHE-PSK-3DES-SHA DHE_PSK_WITH_3DES_EDE_CBC_SHA FIXME 0x03000090 HIGH medium TLSv12 DHE PSK AES 128 SHA1 4279 DHE-PSK-AES128-CBC-SHA,DHE-PSK-AES128-SHA DHE_PSK_WITH_AES_128_CBC_SHA - 0x03000091 HIGH medium TLSv12 DHE PSK AES 256 SHA1 4279 DHE-PSK-AES256-CBC-SHA,DHE-PSK-AES256-SHA DHE_PSK_WITH_AES_256_CBC_SHA - 0x03000092 MEDIUM medium SSLv3 RSAPSK RSA RC4 128 SHA1 4279,6347 RSA-PSK-RC4-SHA RSA_PSK_WITH_RC4_128_SHA - 0x03000093 -?- medium SSLv3 RSAPSK RSA 3DES 112 SHA1 4279 RSA-PSK-3DES-EDE-CBC-SHA,RSA-PSK-3DES-SHA RSA_PSK_WITH_3DES_EDE_CBC_SHA - 0x03000094 HIGH medium SSLv3 RSAPSK AES AES 128 SHA1 4279 RSA-PSK-AES128-CBC-SHA,RSA-PSK-AES128-SHA RSA_PSK_WITH_AES_128_CBC_SHA - 0x03000095 HIGH medium SSLv3 RSAPSK AES RSA 256 SHA1 4279 RSA-PSK-AES256-CBC-SHA,RSA-PSK-AES256-SHA RSA_PSK_WITH_AES_256_CBC_SHA - 0x03000096 MEDIUM MEDIUM TLSv1 RSA RSA SEED 128 SHA1 4162 SEED-SHA RSA_WITH_SEED_SHA,RSA_WITH_SEED_CBC_SHA OSX 0x03000097 MEDIUM medium TLSv1 DH/DSS DH SEED 128 SHA1 4162 DH-DSS-SEED-SHA DH_DSS_WITH_SEED_SHA,DH_DSS_WITH_SEED_CBC_SHA - 0x03000098 MEDIUM medium TLSv1 DH/RSA DH SEED 128 SHA1 4162 DH-RSA-SEED-SHA DH_RSA_WITH_SEED_SHA,DH_RSA_WITH_SEED_CBC_SHA - 0x03000099 MEDIUM MEDIUM TLSv1 DH DSS SEED 128 SHA1 4162 DHE-DSS-SEED-SHA DHE_DSS_WITH_SEED_SHA,DHE_DSS_WITH_SEED_CBC_SHA OSX 0x0300009A MEDIUM MEDIUM TLSv1 DH RSA SEED 128 SHA1 4162 DHE-RSA-SEED-SHA DHE_RSA_WITH_SEED_SHA,DHE_RSA_WITH_SEED_CBC_SHA OSX 0x0300009B MEDIUM weak TLSv1 DH None SEED 128 SHA1 4162 ADH-SEED-SHA,DHanon-SEED-SHA ADH_WITH_SEED_SHA,ADH_WITH_SEED_SHA_SHA,DH_anon_WITH_SEED_CBC_SHA OSX 0x0300009C HIGH HIGH TLSv12 RSA RSA AESGCM 128 AEAD 5288 AES128-GCM-SHA256 RSA_WITH_AES_128_GCM_SHA256 L 0x0300009D HIGH HIGH TLSv12 RSA RSA AESGCM 256 AEAD 5288 AES256-GCM-SHA384 RSA_WITH_AES_256_GCM_SHA384 L 0x0300009E HIGH HIGH TLSv12 DH RSA AESGCM 128 AEAD 5288 DHE-RSA-AES128-GCM-SHA256 DHE_RSA_WITH_AES_128_GCM_SHA256 L 0x0300009F HIGH HIGH TLSv12 DH RSA AESGCM 256 AEAD 5288 DHE-RSA-AES256-GCM-SHA384 DHE_RSA_WITH_AES_256_GCM_SHA384 L 0x030000A0 HIGH HIGH TLSv12 DH/RSA DH AESGCM 128 AEAD 5288 DH-RSA-AES128-GCM-SHA256 DH_RSA_WITH_AES_128_GCM_SHA256 - 0x030000A1 HIGH HIGH TLSv12 DH/RSA DH AESGCM 256 AEAD 5288 DH-RSA-AES256-GCM-SHA384 DH_RSA_WITH_AES_256_GCM_SHA384 - 0x030000A2 HIGH HIGH TLSv12 DH DSS AESGCM 128 AEAD 5288 DHE-DSS-AES128-GCM-SHA256 DHE_DSS_WITH_AES_128_GCM_SHA256 L 0x030000A3 HIGH HIGH TLSv12 DH DSS AESGCM 256 AEAD 5288 DHE-DSS-AES256-GCM-SHA384 DHE_DSS_WITH_AES_256_GCM_SHA384 L 0x030000A4 HIGH HIGH TLSv12 DH/DSS DH AESGCM 128 AEAD 5288 DH-DSS-AES128-GCM-SHA256 DH_DSS_WITH_AES_128_GCM_SHA256 - 0x030000A5 HIGH HIGH TLSv12 DH/DSS DH AESGCM 256 AEAD 5288 DH-DSS-AES256-GCM-SHA384 DH_DSS_WITH_AES_256_GCM_SHA384 - 0x030000A6 HIGH weak TLSv12 DH None AESGCM 128 AEAD 5288 ADH-AES128-GCM-SHA256 ADH_WITH_AES_128_GCM_SHA256,DH_anon_WITH_AES_128_GCM_SHA256 L 0x030000A7 HIGH weak TLSv12 DH None AESGCM 256 AEAD 5288 ADH-AES256-GCM-SHA384 ADH_WITH_AES_256_GCM_SHA384,DH_anon_WITH_AES_256_GCM_SHA256 L 0x030000A8 HIGH high TLSv12 PSK PSK AESGCM 128 SHA256 5487 PSK-AES128-GCM-SHA256 PSK_WITH_AES_128_GCM_SHA256 - 0x030000A9 HIGH high TLSv12 PSK PSK AESGCM 256 SHA384 5487 PSK-AES256-GCM-SHA384 PSK_WITH_AES_256_GCM_SHA384 - 0x030000AA HIGH high TLSv12 DHE PSK AESGCM 128 SHA256 5487 DHE-PSK-AES128-GCM-SHA256 DHE_PSK_WITH_AES_128_GCM_SHA256 - 0x030000AB HIGH high TLSv12 DHE PSK AESGCM 256 SHA384 5487 DHE-PSK-AES256-GCM-SHA384 DHE_PSK_WITH_AES_256_GCM_SHA384 - 0x030000AC HIGH high TLSv12 RSA PSK AESGCM 128 SHA256 5487 RSA-PSK-AES128-GCM-SHA256 RSA_PSK_WITH_AES_128_GCM_SHA256 - 0x030000AD HIGH high TLSv12 RSA PSK AESGCM 256 SHA384 5487 RSA-PSK-AES256-GCM-SHA384,PSK-RSA-AES256-GCM-SHA384 RSA_PSK_WITH_AES_256_GCM_SHA384 - 0x030000AE HIGH medium TLSv1 PSK PSK AES 128 SHA256 5487 PSK-AES128-SHA256,PSK-AES128-CBC-SHA256 PSK_WITH_AES_128_CBC_SHA256 K 0x030000AF HIGH medium TLSv1 PSK PSK AES 256 SHA384 5487 PSK-AES256-SHA384,PSK-AES256-CBC-SHA384 PSK_WITH_AES_256_CBC_SHA384 K 0x030000B0 -?- weak TLSv1 PSK PSK None 0 SHA256 5487 PSK-NULL-SHA256 PSK_WITH_NULL_SHA256 - 0x030000B1 -?- weak TLSv1 PSK PSK None 0 SHA384 5487 PSK-NULL-SHA384 PSK_WITH_NULL_SHA384 - 0x030000B2 HIGH medium TLSv1 DHEPSK PSK AES 128 SHA256 5487 DHE-PSK-AES128-SHA256,DHE-PSK-AES128-CBC-SHA256 DHE_PSK_WITH_AES_128_CBC_SHA256 - 0x030000B3 HIGH medium TLSv1 DHE PSK AES 256 SHA384 5487 DHE-PSK-AES256-SHA384,DHE-PSK-AES256-CBC-SHA384 DHE_PSK_WITH_AES_256_CBC_SHA384 - 0x030000B4 -?- weak TLSv12 DHE PSK None 0 SHA256 5487 DHE-PSK-SHA256,DHE-PSK-NULL-SHA256 DHE_PSK_WITH_NULL_SHA256 - 0x030000B5 -?- weak TLSv12 DHE PSK None 0 SHA384 5487 DHE-PSK-SHA384,DHE-PSK-NULL-SHA384 DHE_PSK_WITH_NULL_SHA384 - 0x030000B6 HIGH medium TLSv1 RSAPSK PSK AES 128 SHA256 5487 RSA-PSK-AES128-CBC-SHA256,RSA-PSK-AES128-SHA256 RSA_PSK_WITH_AES_128_CBC_SHA256 - 0x030000B7 HIGH medium TLSv1 RSAPSK PSK AES 256 SHA384 5487 RSA-PSK-AES256-CBC-SHA384,RSA-PSK-AES256-SHA384 RSA_PSK_WITH_AES_256_CBC_SHA384 - 0x030000B8 -?- weak TLSv1 RSAPSK RSA None 0 SHA256 5487 RSA-PSK-SHA256,RSA-PSK-NULL-SHA256 RSA_PSK_WITH_NULL_SHA256 - 0x030000B9 -?- weak TLSv1 RSAPSK RSA None 0 SHA364 5487 RSA-PSK-SHA384,RSA-PSK-NULL-SHA384 RSA_PSK_WITH_NULL_SHA384 - 0x030000BA HIGH HIGH TLSv12 RSA RSA CAMELLIA 128 SHA256 5932 CAMELLIA128-SHA256 RSA_WITH_CAMELLIA_128_CBC_SHA256 Q 0x030000BB HIGH HIGH TLSv12 DH DSS CAMELLIA 128 SHA256 5932 DH-DSS-CAMELLIA128-SHA256 DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 Q 0x030000BC HIGH HIGH TLSv12 DH RSA CAMELLIA 128 SHA256 5932 DH-RSA-CAMELLIA128-SHA256 DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 Q 0x030000BD HIGH HIGH TLSv12 DH DSS CAMELLIA 128 SHA256 5932 DHE-DSS-CAMELLIA128-SHA256 DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 Q 0x030000BE HIGH HIGH TLSv12 DH RSA CAMELLIA 128 SHA256 5932 DHE-RSA-CAMELLIA128-SHA256 DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 Q 0x030000BF HIGH weak TLSv12 DH None CAMELLIA 128 SHA256 5932 ADH-CAMELLIA128-SHA256 ADH_WITH_CAMELLIA_128_CBC_SHA256,DH_anon_WITH_CAMELLIA_128_CBC_SHA256 Q 0x030000C0 HIGH HIGH TLSv12 RSA RSA CAMELLIA 256 SHA256 5932 CAMELLIA256-SHA256 RSA_WITH_CAMELLIA_256_CBC_SHA256 Q 0x030000C1 HIGH HIGH TLSv12 DSS DH CAMELLIA 256 SHA256 5932 DH-DSS-CAMELLIA256-SHA256 DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 Q 0x030000C1-c HIGH HIGH TLSv12 DH DH CAMELLIA 256 SHA256 - DH-DSS-CAMELLIA256-SHA256 DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 C 0x030000C2 HIGH HIGH TLSv12 RSA DH CAMELLIA 256 SHA256 5932 DH-RSA-CAMELLIA256-SHA256 DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 Q 0x030000C2-c HIGH HIGH TLSv12 DH DH CAMELLIA 256 SHA256 - DH-RSA-CAMELLIA256-SHA256 DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 C 0x030000C3 HIGH HIGH TLSv12 DH DSS CAMELLIA 256 SHA256 5932 DHE-DSS-CAMELLIA256-SHA256 DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 Q 0x030000C4 HIGH HIGH TLSv12 DH RSA CAMELLIA 256 SHA256 5932 DHE-RSA-CAMELLIA256-SHA256 DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 Q 0x030000C5 HIGH weak TLSv12 DH None CAMELLIA 256 SHA256 5932 ADH-CAMELLIA256-SHA256 ADH_WITH_CAMELLIA_256_CBC_SHA256,DH_anon_WITH_CAMELLIA_256_CBC_SHA256 Q 0x030000C6 -?- -?- TLSv13 SM2 SM2 SM4GCM 128 SM3 8998 SM4-GCM-SM3 TLS_SM4_GCM_SM3 - 0x030000C7 -?- -?- TLSv13 SM2 SM2 SM4CCM 128 SM3 8998 SM4-CCM-SM3 TLS_SM4_CCM_SM3 - 0x03001301 HIGH HIGH TLSv13 any any AESGCM 128 AEAD 8446 TLS13-AES128-GCM-SHA256,TLS13-AES-128-GCM-SHA256,TLS_AES_128_GCM_SHA256 AES_128_GCM_SHA256,DTLS_AES_128_GCM_SHA256 D,E,F 0x03001302 HIGH HIGH TLSv13 any any AESGCM 256 AEAD 8446 TLS13-AES256-GCM-SHA384,TLS13-AES-256-GCM-SHA384,TLS_AES_256_GCM_SHA384 AES_256_GCM_SHA384 D,E,F 0x03001303 HIGH HIGH TLSv13 any any ChaCha20-Poly1305 256 AEAD 8446 TLS13-CHACHA20-POLY1305-SHA256,TLS_CHACHA20_POLY1305_SHA256 CHACHA20_POLY1305_SHA256 F 0x03001304 -?- high TLSv13 any any AESCCM 128 AEAD 8446 TLS13-AES128-CCM-SHA256,TLS13-AES-128-CCM-SHA256 AES_128_CCM_SHA256 F 0x03001305 -?- high TLSv13 any any AESCCM 128 AEAD 8446 TLS13-AES128-CCM8-SHA256,TLS13-AES-128-CCM8-SHA256,TLS13-AES128-CCM-8-SHA256,TLS13-AES-128-CCM-8-SHA256 AES_128_CCM_8_SHA256 F 0x030016B7 HIGH HIGH TLSv12 CECPQ1 RSA ChaCha20-Poly1305 256 SHA256 -?- CECPQ1-RSA-CHACHA20-POLY1305-SHA256 CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 O 0x030016B8 HIGH HIGH TLSv12 CECPQ1 ECDSA ChaCha20-Poly1305 256 SHA256 -?- CECPQ1-ECDSA-CHACHA20-POLY1305-SHA256 CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 O 0x030016B9 HIGH HIGH TLSv12 CECPQ1 RSA AESGCM 256 SHA384 -?- CECPQ1-RSA-AES256-GCM-SHA384 CECPQ1_RSA_WITH_AES_256_GCM_SHA384 O 0x030016BA HIGH HIGH TLSv12 CECPQ1 ECDSA AESGCM 256 SHA384 -?- CECPQ1-ECDSA-AES256-GCM-SHA384 CECPQ1_ECDSA_WITH_AES_256_GCM_SHA384 O 0x0300C001 -?- weak SSLv3 ECDH/ECDSA ECDH None 0 SHA1 4492 ECDH-ECDSA-NULL-SHA ECDH_ECDSA_WITH_NULL_SHA,ECDH_ECDSA_WITH_RC4_128_SHA - 0x0300C002 MEDIUM weak SSLv3 ECDH/ECDSA ECDH RC4 128 SHA1 4492,6347 ECDH-ECDSA-RC4-SHA ECDH_ECDSA_WITH_RC4_128_SHA - 0x0300C003 MEDIUM weak SSLv3 ECDH/ECDSA ECDH 3DES 112 SHA1 4492 ECDH-ECDSA-DES-CBC3-SHA ECDH_ECDSA_WITH_DES_192_CBC3_SHA,ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - 0x0300C004 HIGH HIGH SSLv3 ECDH/ECDSA ECDH AES 128 SHA1 4492 ECDH-ECDSA-AES128-SHA ECDH_ECDSA_WITH_AES_128_CBC_SHA - 0x0300C005 HIGH HIGH SSLv3 ECDH/ECDSA ECDH AES 256 SHA1 4492 ECDH-ECDSA-AES256-SHA ECDH_ECDSA_WITH_AES_256_CBC_SHA - 0x0300C006 -?- weak SSLv3 ECDH ECDSA None 0 SHA1 8422 ECDHE-ECDSA-NULL-SHA ECDHE_ECDSA_WITH_NULL_SHA - 0x0300C007 MEDIUM weak SSLv3 ECDH ECDSA RC4 128 SHA1 4492,6347 ECDHE-ECDSA-RC4-SHA ECDHE_ECDSA_WITH_RC4_128_SHA - 0x0300C008 MEDIUM weak SSLv3 ECDH ECDSA 3DES 112 SHA1 8422 ECDHE-ECDSA-DES-CBC3-SHA ECDHE_ECDSA_WITH_DES_192_CBC3_SHA,ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - 0x0300C009 HIGH HIGH SSLv3 ECDH ECDSA AES 128 SHA1 8422 ECDHE-ECDSA-AES128-SHA ECDHE_ECDSA_WITH_AES_128_CBC_SHA - 0x0300C00A HIGH HIGH SSLv3 ECDH ECDSA AES 256 SHA1 8422 ECDHE-ECDSA-AES256-SHA ECDHE_ECDSA_WITH_AES_256_CBC_SHA - 0x0300C00B -?- weak SSLv3 ECDH/RSA ECDH None 0 SHA1 4492 ECDH-RSA-NULL-SHA ECDH_RSA_WITH_NULL_SHA - 0x0300C00C MEDIUM weak SSLv3 ECDH/RSA ECDH RC4 128 SHA1 4492,6347 ECDH-RSA-RC4-SHA ECDH_RSA_WITH_RC4_128_SHA - 0x0300C00D MEDIUM weak SSLv3 ECDH/RSA ECDH 3DES 112 SHA1 4492 ECDH-RSA-DES-CBC3-SHA ECDH_RSA_WITH_DES_192_CBC3_SHA,ECDH_RSA_WITH_3DES_EDE_CBC_SHA - 0x0300C00E HIGH HIGH SSLv3 ECDH/RSA ECDH AES 128 SHA1 4492 ECDH-RSA-AES128-SHA ECDH_RSA_WITH_AES_128_CBC_SHA - 0x0300C00F HIGH HIGH SSLv3 ECDH/RSA ECDH AES 256 SHA1 4492 ECDH-RSA-AES256-SHA ECDH_RSA_WITH_AES_256_CBC_SHA - 0x0300C010 -?- weak SSLv3 ECDH RSA None 0 SHA1 8422 ECDHE-RSA-NULL-SHA ECDHE_RSA_WITH_NULL_SHA - 0x0300C011 MEDIUM weak SSLv3 ECDH RSA RC4 128 SHA1 4492,6347 ECDHE-RSA-RC4-SHA ECDHE_RSA_WITH_RC4_128_SHA - 0x0300C012 MEDIUM weak SSLv3 ECDH RSA 3DES 112 SHA1 8422 ECDHE-RSA-DES-CBC3-SHA ECDHE_RSA_WITH_DES_192_CBC3_SHA,ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - 0x0300C013 HIGH HIGH SSLv3 ECDH RSA AES 128 SHA1 8422 ECDHE-RSA-AES128-SHA ECDHE_RSA_WITH_AES_128_CBC_SHA - 0x0300C014 HIGH HIGH SSLv3 ECDH RSA AES 256 SHA1 8422 ECDHE-RSA-AES256-SHA ECDHE_RSA_WITH_AES_256_CBC_SHA - 0x0300C015 -?- weak SSLv3 ECDH None None 0 SHA1 8422 AECDH-NULL-SHA ECDH_anon_WITH_NULL_SHA - 0x0300C016 MEDIUM weak SSLv3 ECDH None RC4 128 SHA1 4492,6347 AECDH-RC4-SHA ECDH_anon_WITH_RC4_128_SHA - 0x0300C017 MEDIUM weak SSLv3 ECDH None 3DES 112 SHA1 8422 AECDH-DES-CBC3-SHA ECDH_anon_WITH_DES_192_CBC3_SHA,ECDH_anon_WITH_3DES_EDE_CBC_SHA - 0x0300C018 HIGH weak SSLv3 ECDH None AES 128 SHA1 8422 AECDH-AES128-SHA ECDH_anon_WITH_AES_128_CBC_SHA - 0x0300C019 HIGH weak SSLv3 ECDH None AES 256 SHA1 8422 AECDH-AES256-SHA ECDH_anon_WITH_AES_256_CBC_SHA - 0x0300C01A MEDIUM weak SSLv3 SRP None 3DES 112 SHA1 5054 SRP-3DES-EDE-CBC-SHA SRP_SHA_WITH_3DES_EDE_CBC_SHA L 0x0300C01B MEDIUM weak SSLv3 SRP RSA 3DES 112 SHA1 5054 SRP-RSA-3DES-EDE-CBC-SHA SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA L 0x0300C01C MEDIUM weak SSLv3 SRP DSS 3DES 112 SHA1 5054 SRP-DSS-3DES-EDE-CBC-SHA SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA L 0x0300C01D HIGH weak SSLv3 SRP None AES 128 SHA1 5054 SRP-AES-128-CBC-SHA SRP_SHA_WITH_AES_128_CBC_SHA L 0x0300C01E HIGH weak SSLv3 SRP RSA AES 128 SHA1 5054 SRP-RSA-AES-128-CBC-SHA SRP_SHA_RSA_WITH_AES_128_CBC_SHA L 0x0300C01F HIGH weak SSLv3 SRP DSS AES 128 SHA1 5054 SRP-DSS-AES-128-CBC-SHA SRP_SHA_DSS_WITH_AES_128_CBC_SHA L 0x0300C020 HIGH weak SSLv3 SRP None AES 256 SHA1 5054 SRP-AES-256-CBC-SHA SRP_SHA_WITH_AES_256_CBC_SHA L 0x0300C021 HIGH weak SSLv3 SRP RSA AES 256 SHA1 5054 SRP-RSA-AES-256-CBC-SHA SRP_SHA_RSA_WITH_AES_256_CBC_SHA L 0x0300C022 HIGH weak SSLv3 SRP DSS AES 256 SHA1 5054 SRP-DSS-AES-256-CBC-SHA SRP_SHA_DSS_WITH_AES_256_CBC_SHA L 0x0300C023 HIGH HIGH TLSv12 ECDH ECDSA AES 128 SHA256 5289 ECDHE-ECDSA-AES128-SHA256 ECDHE_ECDSA_WITH_AES_128_SHA256,ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 L 0x0300C024 HIGH HIGH TLSv12 ECDH ECDSA AES 256 SHA384 5289 ECDHE-ECDSA-AES256-SHA384 ECDHE_ECDSA_WITH_AES_256_SHA384,ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 L 0x0300C025 HIGH HIGH TLSv12 ECDH/ECDSA ECDH AES 128 SHA256 5289 ECDH-ECDSA-AES128-SHA256 ECDH_ECDSA_WITH_AES_128_SHA256,ECDH_ECDSA_WITH_AES_128_CBC_SHA256 L 0x0300C026 HIGH HIGH TLSv12 ECDH/ECDSA ECDH AES 256 SHA384 5289 ECDH-ECDSA-AES256-SHA384 ECDH_ECDSA_WITH_AES_256_SHA384,ECDH_ECDSA_WITH_AES_256_CBC_SHA384 L 0x0300C027 HIGH HIGH TLSv12 ECDH RSA AES 128 SHA256 5289 ECDHE-RSA-AES128-SHA256 ECDHE_RSA_WITH_AES_128_SHA256,ECDHE_RSA_WITH_AES_128_CBC_SHA256 L 0x0300C028 HIGH HIGH TLSv12 ECDH RSA AES 256 SHA384 5289 ECDHE-RSA-AES256-SHA384 ECDHE_RSA_WITH_AES_256_SHA384,ECDHE_RSA_WITH_AES_256_CBC_SHA384 L 0x0300C029 HIGH HIGH TLSv12 ECDH/RSA ECDH AES 128 SHA256 5289 ECDH-RSA-AES128-SHA256 ECDH_RSA_WITH_AES_128_SHA256,ECDH_RSA_WITH_AES_128_CBC_SHA256 L 0x0300C02A HIGH HIGH TLSv12 ECDH/RSA ECDH AES 256 SHA384 5289 ECDH-RSA-AES256-SHA384 ECDH_RSA_WITH_AES_256_SHA384,ECDH_RSA_WITH_AES_256_CBC_SHA384 L 0x0300C02B HIGH HIGH TLSv12 ECDH ECDSA AESGCM 128 AEAD 5289 ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 L 0x0300C02C HIGH HIGH TLSv12 ECDH ECDSA AESGCM 256 AEAD 5289 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 L 0x0300C02D HIGH HIGH TLSv12 ECDH/ECDSA ECDH AESGCM 128 AEAD 5289 ECDH-ECDSA-AES128-GCM-SHA256 ECDH_ECDSA_WITH_AES_128_GCM_SHA256 L 0x0300C02E HIGH HIGH TLSv12 ECDH/ECDSA ECDH AESGCM 256 AEAD 5289 ECDH-ECDSA-AES256-GCM-SHA384 ECDH_ECDSA_WITH_AES_256_GCM_SHA384 L 0x0300C02F HIGH HIGH TLSv12 ECDH RSA AESGCM 128 AEAD 5289,8442 ECDHE-RSA-AES128-GCM-SHA256 ECDHE_RSA_WITH_AES_128_GCM_SHA256 L 0x0300C030 HIGH HIGH TLSv12 ECDH RSA AESGCM 256 AEAD 5289,8442 ECDHE-RSA-AES256-GCM-SHA384 ECDHE_RSA_WITH_AES_256_GCM_SHA384 L 0x0300C031 HIGH HIGH TLSv12 ECDH/RSA ECDH AESGCM 128 AEAD 5289 ECDH-RSA-AES128-GCM-SHA256 ECDH_RSA_WITH_AES_128_GCM_SHA256 L 0x0300C032 HIGH HIGH TLSv12 ECDH/RSA ECDH AESGCM 256 AEAD 5289 ECDH-RSA-AES256-GCM-SHA384 ECDH_RSA_WITH_AES_256_GCM_SHA384 L 0x0300C033 -?- medium TLSv12 ECDHEPSK PSK RC4 128 SHA1 5489,6347 ECDHE-PSK-RC4-SHA,ECDHE-PSK-RC4-128-SHA ECDHE_PSK_WITH_RC4_128_SHA - 0x0300C034 -?- medium TLSv12 ECDHEPSK PSK 3DES 192 SHA1 5489 ECDHE-PSK-3DES-EDE-CBC-SHA ECDHE_PSK_WITH_3DES_EDE_CBC_SHA - 0x0300C035 HIGH medium TLSv1 ECDHEPSK PSK AES 128 SHA1 5489 ECDHE-PSK-AES128-CBC-SHA ECDHE_PSK_WITH_AES_128_CBC_SHA - 0x0300C036 HIGH medium TLSv12 ECDHEPSK PSK AES 256 SHA1 5489 ECDHE-PSK-AES256-CBC-SHA ECDHE_PSK_WITH_AES_256_CBC_SHA - 0x0300C037 HIGH medium TLSv1 ECDHEPSK PSK AES 128 SHA256 5489 ECDHE-PSK-AES128-CBC-SHA256 ECDHE_PSK_WITH_AES_128_CBC_SHA256 - 0x0300C038 HIGH medium TLSv1 ECDHEPSK PSK AES 256 SHA384 5489 ECDHE-PSK-AES256-CBC-SHA384 ECDHE_PSK_WITH_AES_256_CBC_SHA384 - 0x0300C039 -?- weak TLSv1 ECDHEPSK PSK None 0 SHA1 5489 ECDHE-PSK-NULL-SHA ECDHE_PSK_WITH_NULL_SHA - 0x0300C03A -?- weak TLSv1 ECDHEPSK PSK None 0 SHA1 5489 ECDHE-PSK-NULL-SHA256 ECDHE_PSK_WITH_NULL_SHA256 - 0x0300C03B -?- weak TLSv1 ECDHEPSK PSK None 0 SHA1 5489 ECDHE-PSK-NULL-SHA384 ECDHE_PSK_WITH_NULL_SHA384 - 0x0300C03C -?- -?- TLSv12 RSA RSA ARIA 128 SHA256 6209 RSA-ARIA128-SHA256 RSA_WITH_ARIA_128_CBC_SHA256 - 0x0300C03D -?- -?- TLSv12 RSA RSA ARIA 256 SHA384 6209 RSA-ARIA256-SHA384 RSA_WITH_ARIA_256_CBC_SHA384 - 0x0300C03E -?- -?- TLSv12 DH DSS ARIA 128 SHA256 6209 DH-DSS-ARIA128-SHA256 DH_DSS_WITH_ARIA_128_CBC_SHA256 - 0x0300C03F -?- -?- TLSv12 DH DSS ARIA 256 SHA384 6209 DH-DSS-ARIA256-SHA384 DH_DSS_WITH_ARIA_256_CBC_SHA384 - 0x0300C040 -?- -?- TLSv12 DH RSA ARIA 128 SHA256 6209 DH-RSA-ARIA128-SHA256 DH_RSA_WITH_ARIA_128_CBC_SHA256 - 0x0300C041 -?- -?- TLSv12 DH RSA ARIA 256 SHA384 6209 DH-RSA-ARIA256-SHA384 DH_RSA_WITH_ARIA_256_CBC_SHA384 - 0x0300C042 -?- -?- TLSv12 DHE DSS ARIA 128 SHA256 6209 DHE-DSS-ARIA128-SHA256 DHE_DSS_WITH_ARIA_128_CBC_SHA256 - 0x0300C043 -?- -?- TLSv12 DHE DSS ARIA 256 SHA384 6209 DHE-DSS-ARIA256-SHA384 DHE_DSS_WITH_ARIA_256_CBC_SHA384 - 0x0300C044 -?- -?- TLSv12 DHE RSA ARIA 128 SHA256 6209 DHE-RSA-ARIA128-SHA256,DHE-RSA-ARIA256-SHA256 DHE_RSA_WITH_ARIA_256_CBC_SHA256 I 0x0300C045 -?- -?- TLSv12 DHE RSA ARIA 256 SHA384 6209 DHE-RSA-ARIA256-SHA384 DHE_RSA_WITH_ARIA_256_CBC_SHA384 - 0x0300C046 -?- -?- TLSv12 DH None ARIA 128 SHA256 6209 ADH-ARIA128-SHA256 DH_anon_WITH_ARIA_128_CBC_SHA256 - 0x0300C047 -?- -?- TLSv12 DH None ARIA 256 SHA384 6209 ADH-ARIA256-SHA384 DH_anon_WITH_ARIA_256_CBC_SHA384 - 0x0300C048 -?- -?- TLSv12 ECDHE ECDSA ARIA 128 SHA256 6209 ECDHE-ECDSA-ARIA128-SHA256 ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 - 0x0300C049 -?- -?- TLSv12 ECDHE ECDSA ARIA 256 SHA384 6209 ECDHE-ECDSA-ARIA256-SHA384 ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 - 0x0300C04A -?- -?- TLSv12 ECDH ECDSA ARIA 128 SHA256 6209 ECDH-ECDSA-ARIA128-SHA256 ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 - 0x0300C04B -?- -?- TLSv12 ECDH ECDSA ARIA 256 SHA384 6209 ECDH-ECDSA-ARIA256-SHA384 ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 - 0x0300C04C -?- -?- TLSv12 ECDHE RSA ARIA 128 SHA256 6209 ECDHE-RSA-ARIA128-SHA256 ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 - 0x0300C04D -?- -?- TLSv12 ECDHE RSA ARIA 256 SHA384 6209 ECDHE-RSA-ARIA256-SHA384 ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 - 0x0300C04E -?- -?- TLSv12 ECDH RSA ARIA 128 SHA256 6209 ECDH-RSA-ARIA128-SHA256 ECDH_RSA_WITH_ARIA_128_CBC_SHA256 - 0x0300C04F -?- -?- TLSv12 ECDH RSA ARIA 256 SHA384 6209 ECDH-RSA-ARIA256-SHA384 ECDH_RSA_WITH_ARIA_256_CBC_SHA384 - 0x0300C050 HIGH HIGH TLSv12 RSA RSA ARIAGCM 128 AEAD 6209 ARIA128-GCM-SHA256,RSA-ARIA128-GCM-SHA256 RSA_WITH_ARIA_128_GCM_SHA256 - 0x0300C051 HIGH HIGH TLSv12 RSA RSA ARIAGCM 256 AEAD 6209 ARIA256-GCM-SHA384,RSA-ARIA256-GCM-SHA384 RSA_WITH_ARIA_256_GCM_SHA384 - 0x0300C052 HIGH HIGH TLSv12 DH RSA ARIAGCM 128 AEAD 6209 DHE-RSA-ARIA128-GCM-SHA256 DHE_RSA_WITH_ARIA_128_GCM_SHA256 - 0x0300C053 HIGH HIGH TLSv12 DH RSA ARIAGCM 256 AEAD 6209 DHE-RSA-ARIA256-GCM-SHA384 DHE_RSA_WITH_ARIA_256_GCM_SHA384 - 0x0300C054 -?- -?- TLSv12 DH RSA ARIAGCM 128 AEAD 6209 DH-RSA-ARIA128-GCM-SHA256 DH_RSA_WITH_ARIA_128_GCM_SHA256 - 0x0300C055 -?- -?- TLSv12 DH RSA ARIAGCM 256 AEAD 6209 DH-RSA-ARIA256-GCM-SHA384 DH_RSA_WITH_ARIA_256_GCM_SHA384 - 0x0300C056 HIGH HIGH TLSv12 DH DSS ARIAGCM 128 AEAD 6209 DHE-DSS-ARIA128-GCM-SHA256 DHE_DSS_WITH_ARIA_128_GCM_SHA256 - 0x0300C057 HIGH HIGH TLSv12 DH DSS ARIAGCM 256 AEAD 6209 DHE-DSS-ARIA256-GCM-SHA384 DHE_DSS_WITH_ARIA_256_GCM_SHA384 - 0x0300C058 -?- -?- TLSv12 DH DSS ARIAGCM 128 AEAD 6209 DH-DSS-ARIA128-GCM-SHA256 DH_DSS_WITH_ARIA_128_GCM_SHA256 - 0x0300C059 -?- -?- TLSv12 DH DSS ARIAGCM 256 AEAD 6209 DH-DSS-ARIA256-GCM-SHA384 DH_DSS_WITH_ARIA_256_GCM_SHA384 - 0x0300C05A -?- -?- TLSv12 DH None ARIAGCM 128 AEAD 6209 ADH-ARIA128-GCM-SHA256 DH_anon_WITH_ARIA_128_GCM_SHA256 - 0x0300C05B -?- -?- TLSv12 DH None ARIAGCM 256 AEAD 6209 ADH-ARIA256-GCM-SHA384 DH_anon_WITH_ARIA_256_GCM_SHA384 - 0x0300C05C HIGH HIGH TLSv12 ECDH ECDSA ARIAGCM 128 AEAD 6209 ECDHE-ECDSA-ARIA128-GCM-SHA256 ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 - 0x0300C05D HIGH HIGH TLSv12 ECDH ECDSA ARIAGCM 256 AEAD 6209 ECDHE-ECDSA-ARIA256-GCM-SHA384 ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 - 0x0300C05E -?- -?- TLSv12 ECDH ECDSA ARIAGCM 128 AEAD 6209 ECDH-ECDSA-ARIA128-GCM-SHA256 ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 - 0x0300C05F -?- -?- TLSv12 ECDH ECDSA ARIAGCM 256 AEAD 6209 ECDH-ECDSA-ARIA256-GCM-SHA384 ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 - 0x0300C060 HIGH HIGH TLSv12 ECDH RSA ARIAGCM 128 AEAD 6209 ECDHE-ARIA128-GCM-SHA256,ECDHE-RSA-ARIA128-GCM-SHA256 ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 - 0x0300C061 HIGH HIGH TLSv12 ECDH RSA ARIAGCM 256 AEAD 6209 ECDHE-ARIA256-GCM-SHA384,ECDHE-RSA-ARIA256-GCM-SHA384 ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 - 0x0300C062 -?- high TLSv12 ECDH RSA ARIAGCM 128 AEAD 6209 ECDH-ARIA128-GCM-SHA256,ECDH-RSA-ARIA128-GCM-SHA256 ECDH_RSA_WITH_ARIA_128_GCM_SHA256 - 0x0300C063 -?- high TLSv12 ECDH RSA ARIAGCM 256 AEAD 6209 ECDH-ARIA256-GCM-SHA384,ECDH-RSA-ARIA256-GCM-SHA384 ECDH_RSA_WITH_ARIA_256_GCM_SHA384 - 0x0300C064 HIGH medium TLSv12 PSK PSK ARIA 128 SHA256 6209 PSK-ARIA128-SHA256 PSK_WITH_ARIA_128_CBC_SHA256 - 0x0300C065 HIGH medium TLSv12 PSK PSK ARIA 256 SHA384 6209 PSK-ARIA256-SHA384 PSK_WITH_ARIA_256_CBC_SHA384 - 0x0300C066 -?- medium TLSv12 DHE PSK ARIA 128 SHA256 6209 DHE-PSK-ARIA128-SHA256 DHE_PSK_WITH_ARIA_128_CBC_SHA256 - 0x0300C067 -?- medium TLSv12 DHE PSK ARIA 256 SHA384 6209 DHE-PSK-ARIA256-SHA384 DHE_PSK_WITH_ARIA_256_CBC_SHA384 - 0x0300C068 -?- medium TLSv12 RSA PSK ARIA 128 SHA256 6209 RSA-PSK-ARIA128-SHA256 RSA_PSK_WITH_ARIA_128_CBC_SHA256 - 0x0300C069 -?- medium TLSv12 RSA PSK ARIA 256 SHA384 6209 RSA-PSK-ARIA256-SHA384 RSA_PSK_WITH_ARIA_256_CBC_SHA384 - 0x0300C06A HIGH HIGH TLSv12 PSK PSK ARIAGCM 128 AEAD 6209 PSK-ARIA128-GCM-SHA256 PSK_WITH_ARIA_128_GCM_SHA256 - 0x0300C06B HIGH HIGH TLSv12 PSK PSK ARIAGCM 256 AEAD 6209 PSK-ARIA256-GCM-SHA384 PSK_WITH_ARIA_256_GCM_SHA384 - 0x0300C06C HIGH HIGH TLSv12 DHEPSK PSK ARIAGCM 128 AEAD 6209 DHE-PSK-ARIA128-GCM-SHA256 DHE_PSK_WITH_ARIA_128_GCM_SHA256 - 0x0300C06D HIGH HIGH TLSv12 DHEPSK PSK ARIAGCM 256 AEAD 6209 DHE-PSK-ARIA256-GCM-SHA384 DHE_PSK_WITH_ARIA_256_GCM_SHA384 - 0x0300C06E HIGH HIGH TLSv12 RSAPSK RSA ARIAGCM 128 AEAD 6209 RSA-PSK-ARIA128-GCM-SHA256 RSA_PSK_WITH_ARIA_128_GCM_SHA256 - 0x0300C06F HIGH HIGH TLSv12 RSAPSK PSK ARIAGCM 256 AEAD 6209 RSA-PSK-ARIA256-GCM-SHA384 RSA_PSK_WITH_ARIA_256_GCM_SHA384 - 0x0300C070 -?- medium TLSv12 ECDHE PSK ARIA 128 SHA256 6209 ECDHE-PSK-ARIA128-SHA256 ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 - 0x0300C071 -?- medium TLSv12 ECDHE PSK ARIA 256 SHA384 6209 ECDHE-PSK-ARIA256-SHA384 ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 - 0x0300C072 HIGH medium TLSv12 ECDH ECDSA CAMELLIA 128 SHA256 6367 ECDHE-ECDSA-CAMELLIA128-SHA256 ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - 0x0300C073 HIGH medium TLSv12 ECDH ECDSA CAMELLIA 256 SHA384 6367 ECDHE-ECDSA-CAMELLIA256-SHA384 ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - 0x0300C074 HIGH medium TLSv12 ECDH/ECDSA ECDH CAMELLIA 128 SHA256 6367 ECDH-ECDSA-CAMELLIA128-SHA256 ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - 0x0300C075 HIGH medium TLSv12 ECDH/ECDSA ECDH CAMELLIA 256 SHA384 6367 ECDH-ECDSA-CAMELLIA256-SHA384 ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - 0x0300C076 HIGH medium TLSv12 ECDH RSA CAMELLIA 128 SHA256 6367 ECDHE-RSA-CAMELLIA128-SHA256 ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - 0x0300C077 HIGH medium TLSv12 ECDH RSA CAMELLIA 256 SHA384 6367 ECDHE-RSA-CAMELLIA256-SHA384 ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 - 0x0300C078 HIGH medium TLSv12 ECDH/RSA ECDH CAMELLIA 128 SHA256 6367 ECDH-RSA-CAMELLIA128-SHA256 ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 - 0x0300C079 HIGH medium TLSv12 ECDH/RSA ECDH CAMELLIA 256 SHA384 6367 ECDH-RSA-CAMELLIA256-SHA384 ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 - 0x0300C07A HIGH HIGH TLSv12 RSA RSA CAMELLIAGCM 128 SHA256 6367 RSA-CAMELLIA128-GCM-SHA256 RSA_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C07B HIGH HIGH TLSv12 RSA RSA CAMELLIAGCM 256 SHA384 6367 RSA-CAMELLIA256-GCM-SHA384 RSA_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C07C HIGH HIGH TLSv12 RSA DHE CAMELLIAGCM 128 SHA256 6367 DHE-RSA-CAMELLIA128-GCM-SHA256 DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C07D HIGH HIGH TLSv12 RSA DHE CAMELLIAGCM 256 SHA384 6367 DHE-RSA-CAMELLIA256-GCM-SHA384 DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C07E HIGH HIGH TLSv12 RSA DH CAMELLIAGCM 128 SHA256 6367 DH-RSA-CAMELLIA128-GCM-SHA256 DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C07F HIGH HIGH TLSv12 RSA DH CAMELLIAGCM 256 SHA384 6367 DH-RSA-CAMELLIA256-GCM-SHA384 DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C080 HIGH HIGH TLSv12 DSS DHE CAMELLIAGCM 128 SHA256 6367 DHE-DSS-CAMELLIA128-GCM-SHA256 DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C081 HIGH HIGH TLSv12 DSS DHE CAMELLIAGCM 256 SHA384 6367 DHE-DSS-CAMELLIA256-GCM-SHA384 DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C082 HIGH HIGH TLSv12 DSS DH CAMELLIAGCM 128 SHA256 6367 DH-DSS-CAMELLIA128-GCM-SHA256 DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C083 HIGH HIGH TLSv12 DSS DH CAMELLIAGCM 256 SHA384 6367 DH-DSS-CAMELLIA256-GCM-SHA384 DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C084 HIGH HIGH TLSv12 DSS ADH CAMELLIAGCM 128 SHA256 6367 ADH-DSS-CAMELLIA128-GCM-SHA256 DH_anon_DSS_WITH_CAMELLIA_128_GCM_SHA256,DH_anon_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C085 HIGH HIGH TLSv12 DSS ADH CAMELLIAGCM 256 SHA384 6367 ADH-DSS-CAMELLIA256-GCM-SHA384 DH_anon_DSS_WITH_CAMELLIA_256_GCM_SHA384,DH_anon_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C086 HIGH HIGH TLSv12 ECDH ECDHE CAMELLIAGCM 128 SHA256 6367 ECDHE-ECDSA-CAMELLIA128-GCM-SHA256 ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C087 HIGH HIGH TLSv12 ECDH ECDHE CAMELLIAGCM 256 SHA384 6367 ECDHE-ECDSA-CAMELLIA256-GCM-SHA384 ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C088 HIGH HIGH TLSv12 ECDH ECDH CAMELLIAGCM 128 SHA256 6367 ECDH-ECDSA-CAMELLIA128-GCM-SHA256 ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C089 HIGH HIGH TLSv12 ECDH ECDH CAMELLIAGCM 256 SHA384 6367 ECDH-ECDSA-CAMELLIA256-GCM-SHA384 ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C08A HIGH HIGH TLSv12 RSA ECDHE CAMELLIAGCM 128 SHA256 6367 ECDHE-RSA-CAMELLIA128-GCM-SHA256 ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C08B HIGH HIGH TLSv12 RSA ECDHE CAMELLIAGCM 256 SHA384 6367 ECDHE-RSA-CAMELLIA256-GCM-SHA384 ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C08C HIGH HIGH TLSv12 RSA ECDH CAMELLIAGCM 128 SHA256 6367 ECDH-RSA-CAMELLIA128-GCM-SHA256 ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C08D HIGH HIGH TLSv12 RSA ECDH CAMELLIAGCM 256 SHA384 6367 ECDH-RSA-CAMELLIA256-GCM-SHA384 ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C08E HIGH HIGH TLSv12 PSK RSA CAMELLIAGCM 128 SHA256 6367 PSK-CAMELLIA128-GCM-SHA256 PSK_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C08F HIGH HIGH TLSv12 PSK RSA CAMELLIAGCM 256 SHA384 6367 PSK-CAMELLIA256-GCM-SHA384 PSK_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C090 HIGH HIGH TLSv12 PSK DHE CAMELLIAGCM 128 SHA256 6367 DHE-PSK-CAMELLIA128-GCM-SHA256 DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C091 HIGH HIGH TLSv12 PSK DHE CAMELLIAGCM 256 SHA384 6367 DHE-PSK-CAMELLIA256-GCM-SHA384 DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C092 HIGH HIGH TLSv12 PSK RSA CAMELLIAGCM 128 SHA256 6367 RSA-PSK-CAMELLIA128-GCM-SHA256 RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 - 0x0300C093 HIGH HIGH TLSv12 PSK RSA CAMELLIAGCM 256 SHA384 6367 RSA-PSK-CAMELLIA256-GCM-SHA384 RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 - 0x0300C094 HIGH medium TLSv12 PSK PSK CAMELLIA 128 SHA256 6367 PSK-CAMELLIA128-SHA256 PSK_WITH_CAMELLIA_128_CBC_SHA256 - 0x0300C095 HIGH medium TLSv12 PSK PSK CAMELLIA 256 SHA384 6367 PSK-CAMELLIA256-SHA384 PSK_WITH_CAMELLIA_256_CBC_SHA384 - 0x0300C096 HIGH medium TLSv12 PSK DHE CAMELLIA 128 SHA256 6367 DHE-PSK-CAMELLIA128-SHA256 DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 - 0x0300C097 HIGH medium TLSv12 PSK DHE CAMELLIA 256 SHA384 6367 DHE-PSK-CAMELLIA256-SHA384 DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 - 0x0300C098 HIGH medium TLSv12 PSK RSA CAMELLIA 128 SHA256 6367 RSA-PSK-CAMELLIA128-SHA256 RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 - 0x0300C099 HIGH medium TLSv12 PSK RSA CAMELLIA 256 SHA384 6367 RSA-PSK-CAMELLIA256-SHA384 RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 - 0x0300C09A HIGH medium TLSv12 PSK ECDHE CAMELLIA 128 SHA256 6367 ECDHE-PSK-CAMELLIA128-SHA256 ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 - 0x0300C09B HIGH medium TLSv12 PSK ECDHE CAMELLIA 256 SHA384 6367 ECDHE-PSK-CAMELLIA256-SHA384 ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 - 0x0300C09C HIGH HIGH TLSv12 RSA RSA AESCCM 128 AEAD 6655 AES128-CCM,RSA-AES128-CCM RSA_WITH_AES_128_CCM - 0x0300C09D HIGH HIGH TLSv12 RSA RSA AESCCM 256 AEAD 6655 AES256-CCM,RSA-AES256-CCM RSA_WITH_AES_256_CCM - 0x0300C09E HIGH HIGH TLSv12 DH RSA AESCCM 128 AEAD 6655 DHE-RSA-AES128-CCM DHE_RSA_WITH_AES_128_CCM - 0x0300C09F HIGH HIGH TLSv12 DH RSA AESCCM 256 AEAD 6655 DHE-RSA-AES256-CCM DHE_RSA_WITH_AES_256_CCM - 0x0300C0A0 HIGH HIGH TLSv12 RSA RSA AESCCM8 128 AEAD 6655 AES128-CCM8,RSA-AES128-CCM8,RSA-AES128-CCM-8 RSA_WITH_AES_128_CCM_8 - 0x0300C0A1 HIGH HIGH TLSv12 RSA RSA AESCCM8 256 AEAD 6655 AES256-CCM8,RSA-AES256-CCM8,RSA-AES256-CCM-8 RSA_WITH_AES_256_CCM_8 - 0x0300C0A2 HIGH HIGH TLSv12 DH RSA AESCCM8 128 AEAD 6655 DHE-RSA-AES128-CCM8,DHE-RSA-AES128-CCM-8 DHE_RSA_WITH_AES_128_CCM_8 - 0x0300C0A3 HIGH HIGH TLSv12 DH RSA AESCCM8 256 AEAD 6655 DHE-RSA-AES256-CCM8,DHE-RSA-AES256-CCM-8 DHE_RSA_WITH_AES_256_CCM_8 - 0x0300C0A4 HIGH HIGH TLSv12 PSK PSK AESCCM 128 AEAD 6655 PSK-AES128-CCM,PSK-RSA-AES128-CCM PSK_WITH_AES_128_CCM - 0x0300C0A5 HIGH HIGH TLSv12 PSK PSK AESCCM 256 AEAD 6655 PSK-AES256-CCM,PSK-RSA-AES256-CCM PSK_WITH_AES_256_CCM - 0x0300C0A6 HIGH high TLSv12 DHE RSA AESGCM 128 AEAD 6655 DHE-PSK-AES128-CCM,DHE-PSK-RSA-AES128-CCM DHE_PSK_WITH_AES_128_CCM - 0x0300C0A7 HIGH high TLSv12 DHE RSA AESGCM 256 AEAD 6655 DHE-PSK-AES256-CCM,DHE-PSK-RSA-AES256-CCM DHE_PSK_WITH_AES_256_CCM - 0x0300C0A8 HIGH HIGH TLSv12 PSK PSK AESCCM8 128 AEAD 6655 PSK-AES128-CCM8,PSK-AES128-CCM-8,PSK-RSA-AES128-CCM-8 PSK_WITH_AES_128_CCM_8 - 0x0300C0A9 HIGH HIGH TLSv12 PSK PSK AESCCM8 256 AEAD 6655 PSK-AES256-CCM8,PSK-AES256-CCM-8,PSK-RSA-AES256-CCM-8 PSK_WITH_AES_256_CCM_8 - 0x0300C0AA HIGH HIGH TLSv12 DHEPSK PSK AESGCM8 128 AEAD 6655 DHE-PSK-AES128-CCM8,DHE-PSK-AES128-CCM-8 DHE_PSK_WITH_AES_128_CCM_8,PSK_DHE_WITH_AES_128_CCM_8 FIXME 0x0300C0AB HIGH HIGH TLSv12 DHEPSK PSK AESGCM8 256 AEAD 6655 DHE-PSK-AES256-CCM8,DHE-PSK-AES256-CCM-8 DHE_PSK_WITH_AES_256_CCM_8,PSK_DHE_WITH_AES_256_CCM_8 FIXME 0x0300C0AC HIGH HIGH TLSv12 ECDH ECDSA AESCCM 128 AEAD 7251 ECDHE-ECDSA-AES128-CCM ECDHE_ECDSA_WITH_AES_128_CCM - 0x0300C0AD HIGH HIGH TLSv12 ECDH ECDSA AESCCM 256 AEAD 7251 ECDHE-ECDSA-AES256-CCM ECDHE_ECDSA_WITH_AES_256_CCM - 0x0300C0AE HIGH HIGH TLSv12 ECDH ECDSA AESCCM8 128 AEAD 7251 ECDHE-ECDSA-AES128-CCM8,ECDHE-RSA-AES128-CCM-8 ECDHE_ECDSA_WITH_AES_128_CCM_8 - 0x0300C0AF HIGH HIGH TLSv12 ECDH ECDSA AESCCM8 256 AEAD 7251 ECDHE-ECDSA-AES256-CCM8,ECDHE-RSA-AES256-CCM-8 ECDHE_ECDSA_WITH_AES_256_CCM_8 - 0x0300C0B0 -?- -?- TLSv12 ECCPWD RSA AESGCM 128 AEAD 8492 ECCPWD-AES128-GCM-SHA384 ECCPWD_WITH_AES_128_GCM_SHA384 R 0x0300C0B1 -?- -?- TLSv12 ECCPWD RSA AESGCM 256 AEAD 8492 ECCPWD-AES256-GCM-SHA384 ECCPWD_WITH_AES_256_GCM_SHA384 R 0x0300C0B2 -?- -?- TLSv12 ECCPWD RSA AESCCM 128 AEAD 8492 ECCPWD-AES128-CCM-SHA384 ECCPWD_WITH_AES_128_CCM_SHA384 R 0x0300C0B3 -?- -?- TLSv12 ECCPWD RSA AESCCM 256 AEAD 8492 ECCPWD-AES256-CCM-SHA384 ECCPWD_WITH_AES_256_CCM_SHA384 R 0x0300C0B4 -?- -?- TLSv13 -?- -?- -?- -?- SHA256 9150 SHA256-SHA256 SHA256_SHA256 - 0x0300C0B5 -?- -?- TLSv13 -?- -?- -?- -?- SHA384 9150 SHA384-SHA384 SHA384_SHA384 - 0x0300C100 HIGH HIGH TLSv12 DH GOST Kuznyechik 256 Kuznyechik 9189 GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC - 0x0300C101 HIGH HIGH TLSv12 DH GOST Magma 256 Magma 9189 GOSTR341112_256_WITH_MAGMA_CTR_OMAC,CTR-OMAC GOSTR341112_256_WITH_MAGMA_CTR_OMAC - 0x0300C102 HIGH HIGH TLSv12 DH GOST GOST89 256 GOST89 9189 GOSTR341112_256_WITH_28147_CNT_IMIT,CNT-IMIT,IANA-GOST2012-GOST8912-GOST8912,GOST2012-GOST8912-GOST8912 GOSTR341112_256_WITH_28147_CNT_IMIT - 0x0300CC12 -?- high TLSv12 RSA RSA ChaCha20-Poly1305 256 AEAD -?- RSA-CHACHA20-POLY1305 RSA_WITH_CHACHA20_POLY1305 C 0x0300CC13 HIGH HIGH TLSv12 ECDH RSA ChaCha20-Poly1305 256 AEAD -?- ECDHE-RSA-CHACHA20-POLY1305-SHA256-OLD,ECDHE-RSA-CHACHA20-POLY1305-OLD ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_CHACHA20_POLY1305 C 0x0300CC13-c HIGH HIGH TLSv12 ECDH RSA ChaCha20-Poly1305 256 AEAD - ECDHE-RSA-CHACHA20-POLY1305 ECDHE_RSA_WITH_CHACHA20_POLY1305 B 0x0300CC14 HIGH HIGH TLSv12 ECDH ECDSA ChaCha20-Poly1305 256 AEAD -?- ECDHE-ECDSA-CHACHA20-POLY1305-SHA256-OLD,ECDHE-ECDSA-CHACHA20-POLY1305-OLD ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_ECDSA_CHACHA20_POLY1305 C 0x0300CC14-c HIGH HIGH TLSv12 ECDH ECDSA ChaCha20-Poly1305 256 AEAD - ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE_ECDSA_WITH_CHACHA20_POLY1305 B 0x0300CC15 HIGH HIGH TLSv12 DH RSA ChaCha20-Poly1305 256 AEAD -?- DHE-RSA-CHACHA20-POLY1305-SHA256-OLD,DHE-RSA-CHACHA20-POLY1305-OLD DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,DHE_RSA_CHACHA20_POLY1305 C 0x0300CC15-c HIGH HIGH TLSv12 DH RSA ChaCha20-Poly1305 256 AEAD - DHE-RSA-CHACHA20-POLY1305 DHE_RSA_WITH_CHACHA20_POLY1305 B 0x0300CC16 HIGH HIGH TLSv12 DH PSK ChaCha20-Poly1305 256 AEAD - DHE-PSK-CHACHA20-POLY1305 DHE_PSK_WITH_CHACHA20_POLY1305 B 0x0300CC17 HIGH HIGH TLSv12 PSK PSK ChaCha20-Poly1305 256 AEAD - PSK-CHACHA20-POLY1305 PSK_WITH_CHACHA20_POLY1305 B 0x0300CC18 HIGH HIGH TLSv12 ECDHEPSK ECDHE ChaCha20-Poly1305 256 AEAD - ECDHE-PSK-CHACHA20-POLY1305 ECDHE_PSK_WITH_CHACHA20_POLY1305 B 0x0300CC19 HIGH HIGH TLSv12 DH RSA ChaCha20-Poly1305 256 AEAD - RSA-PSK-CHACHA20-POLY1305 RSA_PSK_WITH_CHACHA20_POLY1305 B 0x0300CC20 HIGH HIGH TLSv12 RSA RSA ChaCha20 256 SHA1 -?- RSA-CHACHA20-SHA RSA_WITH_CHACHA20_SHA C 0x0300CC21 HIGH HIGH TLSv12 ECDH RSA ChaCha20 256 SHA1 -?- ECDHE-RSA-CHACHA20-SHA ECDHE_RSA_WITH_CHACHA20_SHA C 0x0300CC22 HIGH HIGH TLSv12 ECDH RSA ChaCha20 256 SHA1 -?- ECDHE-ECDSA-CHACHA20-SHA ECDHE_ECDSA_WITH_CHACHA20_SHA C 0x0300CC23 HIGH HIGH TLSv12 DH RSA ChaCha20 256 SHA1 -?- DHE-RSA-CHACHA20-SHA DHE_RSA_WITH_CHACHA20_SHA C 0x0300CC24 HIGH HIGH TLSv12 DH PSK ChaCha20 256 SHA1 -?- DHE-PSK-CHACHA20-SHA DHE_PSK_WITH_CHACHA20_SHA C 0x0300CC25 HIGH HIGH TLSv12 PSK PSK ChaCha20 256 SHA1 -?- PSK-CHACHA20-SHA PSK_WITH_CHACHA20_SHA C 0x0300CC26 HIGH HIGH TLSv12 ECDH RSA ChaCha20 256 SHA1 -?- ECDHE-PSK-CHACHA20-SHA ECDHE_PSK_WITH_CHACHA20_SHA C 0x0300CC27 HIGH HIGH TLSv12 RSAPSK RSA ChaCha20 256 SHA1 -?- RSA-PSK-CHACHA20-SHA RSA_PSK_WITH_CHACHA20_SHA C 0x0300CCA0 -?- high TLSv12 RSA RSA ChaCha20-Poly1305 256 AEAD -?- RSA-CHACHA20-POLY1305 RSA_WITH_CHACHA20_POLY1305 C 0x0300CCA1 HIGH HIGH TLSv12 ECDH RSA ChaCha20-Poly1305 256 AEAD -?- ECDHE-RSA-CHACHA20-POLY1305 ECDHE_RSA_WITH_CHACHA20_POLY1305 C 0x0300CCA2 HIGH HIGH TLSv12 ECDH ECDSA ChaCha20-Poly1305 256 AEAD -?- ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE_ECDSA_WITH_CHACHA20_POLY1305 C 0x0300CCA3 HIGH HIGH TLSv12 DH RSA ChaCha20-Poly1305 256 AEAD -?- DHE-RSA-CHACHA20-POLY1305 DHE_RSA_WITH_CHACHA20_POLY1305 C 0x0300CCA4 HIGH HIGH TLSv12 DH PSK ChaCha20-Poly1305 256 AEAD -?- DHE-PSK-CHACHA20-POLY1305 DHE_PSK_WITH_CHACHA20_POLY1305 C 0x0300CCA5 HIGH HIGH TLSv12 PSK PSK ChaCha20-Poly1305 256 AEAD -?- PSK-CHACHA20-POLY1305 PSK_WITH_CHACHA20_POLY1305 C 0x0300CCA6 HIGH HIGH TLSv12 ECDHEPSK ECDHE ChaCha20-Poly1305 256 AEAD -?- ECDHE-PSK-CHACHA20-POLY1305 ECDHE_PSK_WITH_CHACHA20_POLY1305 C 0x0300CCA7 HIGH HIGH TLSv12 DH RSA ChaCha20-Poly1305 256 AEAD -?- RSA-PSK-CHACHA20-POLY1305 RSA_PSK_WITH_CHACHA20_POLY1305 C 0x0300CCA8 HIGH HIGH TLSv12 ECDH RSA ChaCha20-Poly1305 256 AEAD 7905 ECDHE-RSA-CHACHA20-POLY1305-SHA256 ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 C 0x0300CCA9 HIGH HIGH TLSv12 ECDH ECDSA ChaCha20-Poly1305 256 AEAD 7905 ECDHE-ECDSA-CHACHA20-POLY1305-SHA256 ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 C 0x0300CCAA HIGH HIGH TLSv12 DH RSA ChaCha20-Poly1305 256 AEAD 7905 DHE-RSA-CHACHA20-POLY1305-SHA256 DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 C 0x0300CCAB HIGH HIGH TLSv12 PSK PSK ChaCha20-Poly1305 256 AEAD 7905 PSK-CHACHA20-POLY1305-SHA256 PSK_WITH_CHACHA20_POLY1305_SHA256 C 0x0300CCAC HIGH HIGH TLSv12 ECDHEPSK ECDHE ChaCha20-Poly1305 256 AEAD 7905 ECDHE-PSK-CHACHA20-POLY1305-SHA256 ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 C 0x0300CCAD HIGH HIGH TLSv12 DHEPSK DHE ChaCha20-Poly1305 256 AEAD 7905 DHE-PSK-CHACHA20-POLY1305-SHA256 DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 C 0x0300CCAE HIGH HIGH TLSv12 RSAPSK RSA ChaCha20-Poly1305 256 AEAD 7905 RSA-PSK-CHACHA20-POLY1305-SHA256 RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 C 0x0300D001 -?- high TLSv12 ECDH PSK AESGCM 128 AEAD 8442 ECDHE-PSK-AES128-GCM-SHA256 ECDHE_PSK_WITH_AES_128_GCM_SHA256 R 0x0300D002 -?- high TLSv12 ECDH PSK AESGCM 256 AEAD 8442 ECDHE-PSK-AES256-GCM-SHA384 ECDHE_PSK_WITH_AES_256_GCM_SHA384 R 0x0300D003 -?- high TLSv12 ECDH PSK AESCCM8 128 AEAD 8442 ECDHE-PSK-AES256-CCM8-SHA256 ECDHE_PSK_WITH_AES_128_CCM_8_SHA256 R 0x0300D005 -?- high TLSv12 ECDH PSK AESCCM 128 AEAD 8442 ECDHE-PSK-AES256-CCM-SHA256 ECDHE_PSK_WITH_AES_128_CCM_SHA256 R 0x0300FEE0 -?- weak SSLv3 RSA_FIPS RSA_FIPS 3DES 112 SHA1 -?- RSA-FIPS-3DES-EDE-SHA-2 RSA_FIPS_WITH_3DES_EDE_CBC_SHA_2 M 0x0300FEE1 -?- weak SSLv3 RSA_FIPS RSA_FIPS DES 56 SHA1 -?- RSA-FIPS-DES-CBC-SHA-2 RSA_FIPS_WITH_DES_CBC_SHA_2 M 0x0300FEFE -?- weak SSLv3 RSA_FIPS RSA_FIPS DES 56 SHA1 -?- RSA-FIPS-DES-CBC-SHA RSA_FIPS_WITH_DES_CBC_SHA N 0x0300FEFF -?- weak SSLv3 RSA_FIPS RSA_FIPS 3DES 112 SHA1 -?- RSA-FIPS-3DES-EDE-SHA RSA_FIPS_WITH_3DES_EDE_CBC_SHA N 0x0300FF00 HIGH weak SSLv3 RSA RSA GOST89 256 MD5 5830 GOST-MD5 GOSTR341094_RSA_WITH_28147_CNT_MD5 G 0x0300FF01 HIGH HIGH SSLv3 RSA RSA GOST89 256 GOST94 5830 GOST-GOST94 RSA_WITH_28147_CNT_GOST94 G 0x0300FF02 HIGH HIGH SSLv3 RSA RSA GOST89 256 GOST89 -?- GOST-GOST89MAC GOST-GOST89MAC G 0x0300FF03 HIGH HIGH SSLv3 RSA RSA GOST89 256 GOST89 -?- GOST-GOST89STREAM GOST-GOST89STREAM G 0x0300FF85 HIGH HIGH TLSv13 GOST GOST GOST89 256 GOST89 -?- LEGACY-GOST2012-GOST8912-GOST8912,GOST2012-GOST8912-GOST891 GOSTR341112_256_WITH_28147_CNT_IMIT FIXME 0x0300FF87 -?- weak TLSv13 GOST GOST None 0 GOST89 -?- GOST2012-NULL-GOST12 GOSTR341112_256_WITH_NULL_GOSTR3411 FIXME #--------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+---------------+-------+---------------+ # hex const openssl sec ssl keyx auth enc bits mac rfc cipher,aliases const comment __END__ ## CIPHERS } O-Saft-22.11.22/OSaft/Data.pm000077500000000000000000001523251433765727300153110ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) 2022, Achim Hoffmann #!# This software is licensed under GPLv2. Please see o-saft.pl for details. package OSaft::Data; use strict; use warnings; my $SID_data = "@(#) Data.pm 1.9 22/11/06 12:21:32"; our $VERSION = "22.06.22"; BEGIN { # SEE Perl:@INC # SEE Perl:BEGIN perlcritic my $_me = $0; $_me =~ s#.*[/\\]##x; my $_path = $0; $_path =~ s#[/\\][^/\\]*$##x; unshift(@INC, $_path) if (1 > (grep{/^$_path$/} @INC)); unshift(@INC, "..") if (1 > (grep{/^\.\.$/} @INC)); unshift(@INC, ".") if (1 > (grep{/^\.$/} @INC)); } use OSaft::Text qw(print_pod); #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME OSaft::Data -- common SSL/TLS-connection data for O-Saft and related tools =head1 DESCRIPTION Utility package for O-Saft (o-saft.pl and related tools). It declares and defines common L to be used in the calling tool. All variables and methods are defined in the OSaft::Data namespace. =head1 SYNOPSIS =over 2 =item use OSaft::Data; # in perl code =item OSaft/Data.pm --help # on command-line will print help =item OSaft/Data.pm data # show content of %data =item OSaft/Data.pm checks # show content of %checks =item OSaft/Data.pm check_cert # show content of %check_cert =item OSaft/Data.pm check_conn # show content of %check_conn =item OSaft/Data.pm check_http # show content of %check_http =item OSaft/Data.pm check_dest # show content of %check_dest =item OSaft/Data.pm check_size # show content of %check_size =item OSaft/Data.pm shorttexts # show content of %shorttexts =back =head1 OPTIONS =over 4 =item --help =back =head1 VARIABLES =over 4 =item %checks Computed checks. =item %check_cert Collected and checked certificate data. =item %check_conn Collected and checked connection data. =item %check_dest Collected and checked target (connection) data. =item %check_http Collected HTTP and HTTPS data. =item %check_size Collected and checked length and count data. =item %data Data from connection and certificate details. =item %data0 Same as %data with 'val' only. Contains values from first connection only. =item %info Same as %data with values only. =item %shorttexts =back =cut #_____________________________________________________________________________ #________________________________________________ public (export) variables __| # SEE Perl:perlcritic ## no critic qw(Variables::ProhibitPackageVars) use Exporter qw(import); use base qw(Exporter); our @EXPORT_OK = qw( %checks %check_cert %check_conn %check_dest %check_http %check_size %data %data0 %info %shorttexts data_done ); # NOTE: do not change names of keys in %data and all %check_* as these keys # are used in output with --trace-key # SEE Note:Data Structures our %info = ( # 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 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"}, 'master_secret' => {'val' => sub { Net::SSLinfo::master_secret( $_[0], $_[1])}, 'txt' => "Target supports Extended Master Secret"}, # master_secret is alias for extended_master_secret, TLS 1.3 and later '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"}, 'public_key_len' => {'val' => sub { Net::SSLinfo::public_key_len( $_[0], $_[1])}, 'txt' => "Target's Server public key length"}, # value reported by openssl s_client -debug ... 'session_id' => {'val' => sub { Net::SSLinfo::session_id( $_[0], $_[1])}, 'txt' => "Target's Session-ID"}, 'session_id_ctx' => {'val' => sub { Net::SSLinfo::session_id_ctx( $_[0], $_[1])}, 'txt' => "Target's Session-ID-ctx"}, '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 header"}, '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' => "internal used SSL options bitmask"}, 'fallback_protocol' => {'val' => sub { print('$prot{fallback}->{val} in _data_init');},'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|master_secret|srp|master_key|public_key_len|session_id|session_id_ctx|session_protocol|session_ticket|session_lifetime|session_timeout|session_starttime|session_startdate 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 our %check_cert = ( # 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 RFC 5280"}, '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 RFC 6125"}, 'rfc_2818_names'=> {'txt' => "Certificate subjectAltNames compliant to RFC 2818"}, # 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 our %check_conn = ( # connection data #------------------+----------------------------------------------------- # 'ip' => {'txt' => "IP for given hostname "}, # 12/2019: no check implemented '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 our %check_dest = ( # 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"}, 'sstp' => {'txt' => "Target does not support method SSTP"}, '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"}, 'master_secret' => {'txt' => "Target supports Extended Master Secret"}, '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 our %check_size = ( # 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_noo'=> {'txt' => "Total number of check results 'no(<<)'"}, '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 our %check_http = ( # HTTP vs. HTTPS data # 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"}, # RFC 6797 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"}, 'https_pins' => {'txt' => "Target sends Public-Key-Pins header"}, #------------------+----------------------------------------------------- ); # %check_http 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", 'master_secret' => "Supports Extended Master Secret", # 'master_secret' => "Supports EMS", '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 RFC 6125", 'rfc_2818_names'=> "subjectAltNames according RFC 2818", '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", 'sstp' => "SSTP", # '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", 'https_pins' => "Public-Key-Pins", 'selfsigned' => "Validity (signature)", 'chain' => "Certificate chain", 'verify' => "Chain verified", 'chain_verify' => "CA Chain trace", '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", 'public_key_len' => "Server public key length", 'session_id' => "Session-ID", 'session_id_ctx' => "Session-ID-ctx", '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_noo'=> "Checks 'no(<<)'", '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 really a `key', but an 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 header", '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' => "internal SSL bitmask", #------------------+------------------------------------------------------ # more texts dynamically, see "adding more shorttexts" below ); # %shorttexts #_____________________________________________________________________________ #_________________________________________________________ internal methods __| # SEE Perl:Undefined subroutine *_warn = sub { print(join(" ", "**WARNING:", @_), "\n"); return; } if not defined &_warn; *_dbx = sub { print(join(" ", "#dbx#" , @_), "\n"); return; } if not defined &_dbx; #_____________________________________________________________________________ #__________________________________________________________________ methods __| =pod =head1 METHODS None. =cut #_____________________________________________________________________________ #____________________________________________________ internal test methods __| sub show { #? dispatcher for various --test-data-* options to show information # output similar (but not identical) to o-saft-man::man_table() my $arg = shift; printf("= %%$arg\n"); #if ('info' eq $arg) { # not yet used #printf("%21s -\t%s\n", $_, $info{$_}->{txt}) foreach (sort keys %info); #} if ('data' eq $arg) { printf("%21s -\t%s\n", $_, $data{$_}->{txt}) foreach (sort keys %data); } if ('checks' eq $arg) { printf("%21s -\t%s\n", $_, $checks{$_}->{txt}) foreach (sort keys %checks); } if ('check_cert' eq $arg) { printf("%21s -\t%s\n", $_, $check_cert{$_}->{txt}) foreach (sort keys %check_cert); } if ('check_conn' eq $arg) { printf("%21s -\t%s\n", $_, $check_conn{$_}->{txt}) foreach (sort keys %check_conn); } if ('check_dest' eq $arg) { printf("%21s -\t%s\n", $_, $check_dest{$_}->{txt}) foreach (sort keys %check_dest); } if ('check_size' eq $arg) { printf("%21s -\t%s\n", $_, $check_size{$_}->{txt}) foreach (sort keys %check_size); } if ('check_http' eq $arg) { printf("%21s -\t%s\n", $_, $check_http{$_}->{txt}) foreach (sort keys %check_http); } if ('shorttexts' eq $arg) { printf("%21s -\t%s\n", $_, $shorttexts{$_}) foreach (sort keys %shorttexts); } return if ($arg =~ /check_/); # cert conn dest size http print <<"EoHelp"; = Please use o-saft.pl --help=$arg for formated output. EoHelp return; } # show #_____________________________________________________________________________ #___________________________________________________ initialisation methods __| sub _data_init { #? initialise variables # 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 main # TODO: must be done in main: #$data{'fallback_protocol'}->{'val'} = sub { return $prot{'fallback'}->{val} }; ## 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"; #} return; } # _data_init #_____________________________________________________________________________ #_____________________________________________________________________ main __| sub _main_data { my @argv = @_; push(@argv, "--help") if (0 > $#argv); binmode(STDOUT, ":unix:utf8"); ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) binmode(STDERR, ":unix:utf8"); ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # got arguments, do something special while (my $arg = shift @argv) { print_pod($0, __PACKAGE__, $SID_data) if ($arg =~ m/^--?h(?:elp)?$/x); # ----------------------------- options # if ($arg =~ m/^--(?:v|trace.?CMD)/i) { $VERBOSE++; next; } # allow --v # ----------------------------- commands if ($arg =~ /^version$/) { print "$SID_data\n"; next; } if ($arg =~ /^[-+]?V(ERSION)?$/) { print "$VERSION\n"; next; } $arg =~ s/^(?:--test.?data)//; show($arg); $arg = "--test-data"; #?# printf("#$0: direct testing not yet possible, please try:\n o-saft.pl $arg\n"); } exit 0; } # _main_data sub data_done {}; # dummy to check successful include _data_init(); #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =head1 SEE ALSO # ... =head1 VERSION 1.9 2022/11/06 =head1 AUTHOR 22-jun-22 Achim Hoffmann =cut ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main_data(@ARGV) if (not defined caller); 1; O-Saft-22.11.22/OSaft/Doc/000077500000000000000000000000001433765727300145745ustar00rootroot00000000000000O-Saft-22.11.22/OSaft/Doc/Data.pm000077500000000000000000000537451433765727300160240ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) 2022, Achim Hoffmann #!# 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; BEGIN { # mainly required for testing ... # SEE Perl:@INC # SEE Perl:BEGIN perlcritic my $_me = $0; $_me =~ s#.*[/\\]##x; my $_path = $0; $_path =~ s#[/\\][^/\\]*$##x; unshift(@INC, $_path) if (1 > (grep{/^$_path$/} @INC)); unshift(@INC, "..") if (1 > (grep{/^\.\.$/} @INC)); unshift(@INC, ".") if (1 > (grep{/^\.$/} @INC)); } my $SID_data = "@(#) Data.pm 1.55 22/10/31 20:49:09"; our $VERSION = "22.06.22"; # official verion number of this file # binmode(...); # inherited from parent, SEE Perl:binmode() use OSaft::Text qw(print_pod); #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME OSaft::Doc::Data - common Perl module to read data for user documentation =head1 SYNOPSIS =over 2 =item use OSaft::Doc::Data; # from within perl code =item OSaft/Doc/Data --usage # on command line will print short usage =item OSaft/Doc/Data [COMMANDS] # on command line will print help =back =head1 METHODS =cut #_____________________________________________________________________________ #_________________________________________________________ internal methods __| # SEE Perl:Undefined subroutine *_warn = sub { print(join(" ", "**WARNING:", @_), "\n"); return; } if not defined &_warn; *_dbx = sub { print(join(" ", "#dbx#" , @_), "\n"); return; } if not defined &_dbx; # TODO: return if (grep{/(?:--no.?warn)/} @ARGV); # ugly hack 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($file,$name,$version) Return all data from file and replace $0 by $name. Returns data as string. =cut sub get { #? return data from file as string, replace $0 by $name 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 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_markup($file,$name,$version) Return all data converted to internal markup format. Returns array of lines. =cut sub get_markup { #? return data with internal markup, returns array of lines my $file = shift; my $parent = shift || "o-saft.pl"; my $version = shift || $VERSION; my @txt; my $fh = _get_filehandle($file); return "" if ("" eq $fh); # defensive programming # 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 # check for other markup in lines which are not code examples or # already injected other markup; # SEE Note:Markup for Tool Examples; SEE Note:Markup for Internal Links # quick&dirty: identifying code examples by # $0 o-saft o-saft.tcl o-saft-docker checkAllCiphers.pl perl perlapp perl2exe # quick&dirty: should also not match X& ... & as no other potential # markup should be substituted in there if (not m/^(?:=|S&|\s+(?:\$0|o-saft|o-saft.tcl|o-saft-docker|checkAllCiphers.pl|perl|perl2exe|perlapp)\s)/ and not m/X&[^&]*(?:\+|--)/ ) { # more markup, ... s#(\s)+(a-zA-Z[^ ]+)(\s+)#$1'$2'$3#g; # markup literal character class as code # our commands and options; SEE Note:Markup for Commands and Options s#(\s)((?:\+|--)[^,\s).]+)([,\s).])#$1I&$2&$3#g; # 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#([A-Z]L)&#$1 &#g; # SEE Note:Upercase Markup ################ --option=, extra behandeln # quick&dirty to avoid further inerpretation of L& , i.e. SSL # ugly hack as it adds a space s#(\s)((?:\+|--)[^,\s).]+)([,\s).])#$1I&$2&$3#g; } if (not m/^S/ and not m/^ {14,}/) { # special markup for tools, tool name ending with (1), ... (3pm) s/((?:Net::SSLeay|ldd|openssl|timeout|IO::Socket(?:::SSL|::INET)?)\(\d(?:pm)?\))/L&$1&/g; # special markup for own tools 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/ (SHELL TWEAKS)/ X&$1&/g; s/ (SEE ALSO)/ X&$1&/g; s/ (EXIT STATUS)/ 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/ (BUILD DOCKER IMAGE)/ X&$1&/g; s/ (TECHNICAL INFORMATION)/ X&$1&/g; s/ (NAME|CONCEPTS|ENVIRONMENT)/ X&$1&/g; s/ (COMMANDS|OPTIONS|RESULTS|CHECKS|OUTPUT|CUSTOMISATION) / X&$1& /g; s/ (LIMITATIONS|DEPENDENCIES|INSTALLATION|DOCKER|TESTING) / X&$1& /g; s/ (SCORING|EXAMPLES|ATTRIBUTION|DOCUMENTATION|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 # NOTE: NOT YET READY, not yet used (hence no POD also) #=pod # #=head2 get_text($file) # #Same as get() but with some variables substituted. # #=cut sub get_text { my $file = shift; my $label = shift || ""; # || to avoid "Use of uninitialised 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 _warn("192: 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 print_as_text($file) Same as get() but prints text directly. =cut sub print_as_text { my $fh = _get_filehandle(shift); print <$fh>; close($fh); return; } =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. These files may be used for following commands. =head2 get filename Call get(filename). =head2 get_as_text filename Call get_as_text(filename). =head2 get_markup filename Call get_markup(filename). =head2 get_text 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 { #? return sorted list of available .txt files # sorted list simplifies tests ... 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$/); push(@txt, $file); } closedir(DIR); return join("\n", sort @txt); } # list sub _main_doc_usage { #? print usage my $name = (caller(0))[1]; print "# various commands:\n"; foreach my $cmd (qw(version +VERSION)) { printf("\t%s %s\n", $name, $cmd); } printf("\t$name list\t# list available files\n"); print "# commands to get text from file in various formats(examples):\n"; foreach my $cmd (qw(get get-markup get-text get-as-text print)) { printf("\t%s %s help.txt\n", $name, $cmd); } printf("\t$name ciphers=dumptab > c.csv; libreoffice c.csv\n"); return; }; # _main_doc_usage sub _main_doc { #? print own documentation or that from specified file ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # see t/.perlcriticrc for detailed description of "no critic" my @argv = @_; # SEE Perl:binmode() binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); print_pod($0, __PACKAGE__, $SID_data) if (0 > $#argv); # got arguments, do something special while (my $cmd = shift @argv) { my $arg = shift @argv; # get 2nd argument, which is filename print_pod($0, __PACKAGE__, $SID_data) if ($cmd =~ /^--?h(?:elp)?$/); _main_doc_usage() if ($cmd eq '--usage'); # ----------------------------- commands print list() . "\n" if ($cmd =~ /^list$/); print get($arg) if ($cmd =~ /^get$/); print get_as_text($arg) if ($cmd =~ /^get.?as.?text/); print get_markup($arg) if ($cmd =~ /^get.?mark(up)?/); print get_text($arg) if ($cmd =~ /^get.?text/); print_as_text($arg) if ($cmd =~ /^print$/); print "$SID_data\n" if ($cmd =~ /^version$/); print "$VERSION\n" if ($cmd =~ /^[-+]?V(ERSION)?$/); } exit 0; } # _main_doc sub doc_data_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 elsewhere or constant string in description. It is difficult to markup character classes like a-zA-Z- this way (using quotes), because any character may be part of the class, including quotes or those used for markup. For Example will a-zA-Z- look like C in POD format. Hence character classes are defined literally without markup to avoid confusion. However, when generating documentation it is assumed that strings (words) beginning with a-zA-Z are character classes. =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 Referenses to titles are written in all upper case characters and prefixed and suffixed with 2 spaces or a . (dot) or , (comma). 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 preceded by 2 empty lines. All head lines for commands and options should contain just this command or option. Aliases for commands or options 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 - 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 1.55 2022/10/31 =head1 AUTHOR 17-oct-17 Achim Hoffmann =cut ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main_doc(@ARGV) if (not defined caller); 1; # __END__ # __end__ not possible, because we may get # readline() on unopened filehandle DATA at OSaft/Doc/Data.pm line 139. # 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. =head3 Documentation:General All public user documentation is written in plain text format. Hence it is possible to read it without a special tool. It is designed for human read- ability and simple editing. All other formats like HTML, POD, troff (man-page), etc. will be generated from this plain text with the methods (functions) herein. The general workflow is as follows: =over =item 1. read text file =item 2. inject simple, intermediate markup (i.g. dokuwiki style markup) =item 3. convert intermediate markup to required format =back For generating some formats, external tools are used. Such a tools mainly gets the data in POD format and then converts it to another format. The external tools are called using Perl's 'exec()' function, usually. =head2 Note:Upercase Markup There's a conflict in detecting TITLEs and options with uppercase letters, for example --SSL . To avoid incorrectly mixed markup, the sequence of some pattern matching is important. =head2 Note:Markup for Internal Links In some cases it is not possible to identify targets for internal links in the human readable text, because such targets are also human readable text but not written in all uppercase letters. Therefore the special markup X&some text here& can be used. No other pattern must be matched in this markup. =head2 Note:Markup for Commands and Options While commands are easy to detect, it may become complicated for options. The general pattern for options is: starting with -- and all charachters before next space, comma, or dot. Unfortunately options may contain such terminating characters too. Special handling for such options must be implemented, otherwise generated markup may not behave as intended. =head2 Note:Markup for Tool Examples The documentation contains example code to call tools. It is obvious that the examples also conatain texts looking like our own options. The options shouldn't be subject to special markup of option, like generating internal links (HTML). A list of tools (pattern) is used to detect such code examples. Such lines are identified if the first word in the line matches this paatern. =cut __DATA__ O-Saft-22.11.22/OSaft/Doc/Glossary.pm000077500000000000000000000507111433765727300167440ustar00rootroot00000000000000#!/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-22.11.22/OSaft/Doc/Links.pm000077500000000000000000000144251433765727300162230ustar00rootroot00000000000000#!/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-22.11.22/OSaft/Doc/Rfc.pm000077500000000000000000000222551433765727300156550ustar00rootroot00000000000000#!/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-22.11.22/OSaft/Doc/coding.txt000066400000000000000000000465611433765727300166140ustar00rootroot00000000000000 # SID @(#) coding.txt 1.10 22/10/26 12:02:31 # 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 standardised 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. For quoting see below. 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 is currenlty changed ... 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 most 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 . All tests can be done with make, see: * make help.test.critic Quoting Using single quotes ' and/or double quotes " is the nature of the processed data, the generated data or the program code. These quotes are written literally in data, whereas Perl provides various methods to handles different types of quotes. Coding gets complicated if both quotes are part of the data, in particular when printing data. 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. Perl's operators 'q()' and 'qq()' are used only to avoid escaping of character, because all types of quotes can smoothly mixed there. In general "double quoted text" is used for interpolated strings. In some cases, it is necessary to use Perl's 'sprintf()' function. For details, please see: perldoc -f q perldoc -f qq perldoc -f sprintf perldoc perlop # following sections: Comma Operator Quote and Quote-Like Operators Gory details of parsing quoted constructs 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! In fact it's a mix of tracing and debugging, to be technical correct. 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). # sub-name Name of sub behind the closing bracket of the 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. In general all names are in lower case. Using _ instead of camel case is prefered. However, there are some exceptions for wrapper functions for Net::SSLinfo and Net::SSLeay . Code information Examples to get an overview of perl functions (sub): egrep '^(sub|\s*#\?)' $0 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 '%' '$' Makefile.dev contains following targets for easy use: make testarg-dev-grep_subs make testarg-dev-grep_sub make testarg-dev-grep_desc 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 initialise internal data structure scan options and arguments perform commands without connection to target loop over all specified targets print DNS stuff open connection 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 Most information is collected using Net::SSLinfo and stored in %data. All information according ciphers is collected directly and stored in @cipher_results . Finally, when performing the checks, these informa- tions 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 Documentation for the project consist at least of these parts: u) documentation for the user SEE Public User Documentation (in o-saft.pl). d) documentation for development SEE Internal Code Documentation (in o-saft.pl). m) documentation for testing in development This dcumentation for testing the tools is done in t/Makefile*. There exists t/Makefile.pod, which contains the "Annotations" for the make system. The description of the Makefile's targets is done as target in each Makefile itself. Note that all documentation (user and development) is actively used by the program itself and by some additional tools, see for example: o-saft.pl --help=opt Initially all user documentation was written in Perl's POD format. After two years of development, it was observerd that POD was not the best decision, as it makes extracting information from documentation complicated, sometimes. Using POD is also a huge performance penulty on all platforms. Hence POD will now be genereated on request using the --help=pod option. For mor Details SEE Note:Documentation (in o-saft.pl). 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.10 22/10/26 12:02:31"; (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. VERSION @(#) $VERSION AUTHOR 18. Jan. 2018 Achim Hoffmann O-Saft-22.11.22/OSaft/Doc/glossary.txt000066400000000000000000000733201433765727300172050ustar00rootroot00000000000000 # SID @(#) glossary.txt 1.31 22/11/01 19:28:24 # acronym | description #------+----------------------------------------------------------------------+ 0-RTT zero Round-Trip Time 3Fish see Threefish 3SHAKE sometimes for: TLS Triple Handshake Attack 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, block cipher AESCCM AES with CCM AESCCM8 AES with CCM8 AESGCM AEAD algorithms AEAD_AES_128_GCM and AEAD_AES_256_GCM AES-CCM alias for AESCCM AES-GCM alias for AESGCM # AES-GCM AES-GCM is an authenticated encryption mode that uses the AES block cipher in counter mode with a polynomial MAC based on Galois field multiplication. AES-GCM-SIV Nonce Misuse-Resistant Authenticated Encryption (RFC8452) AES-CTR ? AES-XTS ? AIA Authority Information Access (certificate extension) AKC Agreement with Key Confirmation AKID Authority Key IDentifier ALPN Application Layer Protocol Negotiation ALPACA Application Layer and Content Confusion Attack (Exploit SSL/TLS) AMASTRID stream cipher algorithm ARC4 Alleged RC4 (see RC4) ARCFOUR alias for ARC4 Argon2 Password hashing function (J. Aumasson, 2014) Argon2d variant of Argon2 Argon2i variant of Argon2 Argon2id variant of Argon2 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 using the same prime as NIST P-224 BADA55-VR-256 curve using the same prime as NIST P-256 BADA55-VR-384 curve using the same prime as NIST P-384 Bar Mitzvah vulnerabilty of TLS sessions protected with RC4 BDH Bilinear Diffie-Hellman BEAR block cipher combining stream cipher and hash function BEAST Browser Exploit Against SSL/TLS (Exploit SSL/TLS) BEAST . fast block cipher for arbitrary blocksizes BER Basic Encoding Rules BGP Boorder Gateway Protocol 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 (64 bit) BLAKE2s-128 see BLAKE (32 bit) BLAKE3 fast secure hashing function (20??) BLAKE3 ?? 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) Blowfish symmetric block cipher boomerang attack attack on BLAKE BPA Branch Prediction Analysis Brainpool signature algorithm, from BSI BREACH Browser Reconnaissance & Exfiltration via Adaptive Compression of Hypertext; a variant of CRIME (Exploit SSL/TLS) Bullrun NSA program to break encrypted communication CAMELLIA symmetric key block cipher; encryption algorithm 128 bit (by Mitsubishi and NTT) CAST Carlisle Adams and Stafford Tavares, block cipher 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 CBC3 alias for Tripple DES (sometimes, used in cipher suite names) CCA chosen-ciphertext attack CCM Counter with CBC-MAC Mode (authenticated encryption block cipher mode) (with 16-octet authentication tag) CCM-8 Counter with CBC-MAC Mode (authenticated encryption block cipher mode) (with 8-octet authentication tag) 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 CGN Carrier- Grade NAT (RFC6598) 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 CLEFIA lightweight block cipher algorithm 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 CNT_IMIT cipher suite CTR_OMAC cipher suite (GOST R 34.12-2015 aka GOST3412-2015) 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 CRYPTON 128 bit block cipher (1998) CRYPTREC Cryptography Research and Evaluation Committees CRYSTALS post-quantum hash function, signature CRYSTALS-Dilithium post-quantum hash function, signature CRYSTALS-Kyber post-quantum hash function, signature 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) DEAL 128, 192, 256 bit block cipher (Lars Knudsen, 1998) 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) Dilithium digital signature scheme Dilithium2-AES alias for Dilithium Dilithium3-AES alias for Dilithium Dilithium5-AES alias for Dilithium 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 DSPR ? 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 (block cipher 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 ECDHE_ECDSA Ephemeral ECDH with ECDSA or EdDSA signatures ECDHE_RSA Ephemeral ECDH with RSA signatures ECDH_anon Anonymous ephemeral ECDH, no signatures 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 EMS Extended Master Secret (sometimes) EMS Encrypted Master Secret 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) eTLS Enterprise TLS (social attack on privacy by ETSI; renamed to ETS) ETS Enterprise Transport Security (renamed from eTLS) ETSI-TS European Telecommunications Standards Institute - Technical Specification EV Extended Validation EV-SSL Extended Validation Certificate FALCON Fast-Fourier Lattice-based Compact Signatures over NTRU; post-quantum signature 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 (Exploit SSL/TLS) 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) GOST28147-89 block cipher GOST3410-2012 signature algorithm GOST3411-2012 hash algorithm GOST3412-2015 block cipher GOST3413-2015 modes of operation for block ciphers GOST3431095 cryptographic algorithm? GOST3431004 cryptographic algorithm? GOST3431195 cryptographic algorithm? GOSTR341001 cryptographic algorithm? GOSTR341094 cryptographic algorithm? GOSTR341194 cryptographic algorithm? 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) Jolkit-BC tweakable block cipher JSSE Java Secure Socket Extension KATAN lightweight block cipher algorithm KLEIN lightweight block cipher algorithm Keccak hash function (Guido Bertoni, Joan Daemen, Michaël Peeters und Gilles Van Assche, 2012) KCI Key Compromise Impersonation KDC Key Distribution Center (mainly Kerberos) KDF Key Derivation Function KEA Key Exchange Algorithm (alias for FORTEZZA-KEA) KEK Key Encryption Key KEM Key Encapsulation Mechanisms KMS Key Management Service KPAK KMS Public Authentication Key KRB Key Exchange Kerberos KRB5 Key Exchange Kerberos 5 KSAK KMS Secret Authentication Key KSK Key Signing Key (DNSSEC) KU Key Usage Kuznyechik block cipher (used in GOST) Magma block cipher (used in GOST) LAKE hash function (Jean-Philippe Aumasson, Willi Meier, Raphael C.-W. Phan, 2008) LEA ? algorithm LEA-128 see LEA LEA-256 see LEA LED lightweight block cipher algorithm 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 (Exploit SSL/TLS) Logjam see LogJam LRA Local Registration Authority LRW Liskov, Rivest, and Wagner (block encryption) LSN large-scale NAT (same as CGN) Lucifer block cipher (developed at IBM in the 1970s) Lucky13 Break SSL/TLS Protocol with ciphers using CBC-mode (Exploit SSL/TLS) Lucky 13 Break SSL/TLS Protocol (Exploit SSL/TLS) Lucky Thirteen see Lucky 13 MANTIS block cipher, low-latency variant of SKINNY 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 MIDORI lightweight block cipher algorithm (64 or 128 bit) (2015) Midori64 see MIDORI Midori128 see MIDORI MISTY1 block cipher algorithm MPQS Multiple Polynomial Quadratic Sieve MQV Menezes-Qu-Vanstone (authentecated key agreement) MS-SSTP see SSTP 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) NOEKEON symmetric block cipher algorithm Neokeon see NOEKEON (probaly typo) 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 NTRUEncrypt alias for NTRU NOMORE Numerous Occurrence MOnitoring & Recovery Exploit, aka RC4 NOMORE 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 Picollo lightweight block cipher algorithm 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 (Exploit SSL/TLS) PQC Post-Quantum Crypto PRESENT block cipher algorithm (80 or 128 bit) (2007) PRF Pseudo-Random Function PRP Pseudo-Random Permutation PRINCE low-latency block cipher algorithm (64 bit) (2012) 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 RACCOON Timing vulnerability in TLS' DH key exchange (Exploit SSL/TLS) RADIUS Remote Authentication Dial-In User Service Radix-64 alias for Base-64 RAINBOW post-quantum signature (broken 2/2022) 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 RIPE-MD alias for RIPEMD RLWE Ring Learning-with-Errors RMAC Randomized MAC (block cipher authentication mode) RMD RNG Random Number Generator ROCA Return of the Coppersmith Attack (Exploit SSL/TLS) ROT-13 see XOR ROBOT Return Of Bleichenbacher's Oracle Threat (Exploit SSL/TLS) 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), see ChaCha20 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 SBPA Simple Branch Prediction Analysis SCA Selfsigned CA signature SCEP Simple Certificate Enrollment Protocol SCREAM tweakable word-based stream cipher (2002) 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 SEAL Software-Optimized Encryption Algorithm; 32-bit word stream cipher (1994) SEED 128-bit symmetric block cipher (1998) Serpent symmetric key block cipher (128 bit) SGC Server-Gated Cryptography SGCM Sophie Germain Counter Mode (authenticated encryption block cipher mode) SIV Synthetic Initialization Vector 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-128 Secure Hash Algorithm (128 bit) 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 (128, 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) SHAttered The first concrete collision attack against SHA1 (Exploit SSL/TLS) 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) SIDH Supersingular Isogeny Diffie-Hellman (key exchange) SIKE post-quantum hash function, signature (broken 7/2022) SIKEp434 post-quantum hash function, signature (broken 7/2022) SIKEp503 post-quantum hash function, signature (broken 7/2022) SIKEp610 post-quantum hash function, signature (broken 7/2022) SIKEp751 post-quantum hash function, signature (broken 7/2022) SIMON lightweight block cipher (NSA algorithm, questionable security) SipHash hash function (J. Aumasson, Daniel Bernstein, 2012) 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) SKINNY SPN tweakable block cipher SKINNY-128-256 see SLINNY SKIP Message Skipping Attacks on TLS (Exploit SSL/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 (Exploit SSL/TLS) SM2 ShangMi authentication function SM3 ShangMi hash function SM4 ShangMi block cipher algorithm (Chinese gouvernment algorithm, questionable but no objections yet) SM4CCM AEAD algorithms AEAD_SM4_CCM SM4GCM AEAD algorithms AEAD_SM4_GCM SMS4 see SM4 SMACK State Machine AttaCKs (Exploit SSL/TLS) 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 SPARX ? algorithm SPECK lightweight block cipher algorithm (NSA algorithm, questionable security) Speck64 see Speck Speck128 see Speck Speck256 see Speck Speck256-XTS see Speck SPD Security Policy Database SPDY Google's application-layer protocol on top of SSL SPECK block cipher combining SPHINCS Stateless hash-based signatures, post-quantum hash function, signature SPHINCS-256 alias for SPHINCS SPHINCS-SHAKE256 alias for SPHINCS SPHINCS-SHA-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 SSTP Secure Socket Tunneling Protocol 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 (Exploit SSL/TLS) 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 ? TGS Ticket Granting Service (mainly Kerberos) TGT Ticket Granting Ticket (mainly Kerberos) 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 XChaCha stream cipher algorithm (with 512-bit key) XChaCha12 see ChaCha (aka 12-round XChaCha) XChaCha20 see ChaCha (aka 20-round XChaCha) 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-22.11.22/OSaft/Doc/help.txt000066400000000000000000005612171433765727300163010ustar00rootroot00000000000000 # SID @(#) help.txt 1.110 22/11/19 14:14:26 NAME O-Saft - OWASP SSL advanced forensic tool OWASP SSL audit for testers 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 an 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. DESCRIPTION This tool 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'. 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 * 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): 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 * Show all --help=* commands $0 --help=HELP * Search for text in O-Saft's help and show with context o-saft --help=your-text * 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 sanitised 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 additional installed tools, for example by accident or because 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 SYSTEMS. 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. Developers may read more details on the concept in docs/concepts.txt This help text The sequence of the sections in the help text doesn't strictly follow the common guidlines for UNIX-style man pages. This is because it is important to understand the concepts of the tool and what options and commands are in context of the tool. In particular the DESCRIPTION section contains only a very brief description. The OPTIONS section follows the COMMANDS section. 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 "proper" recommendation. In practice it depends on the context what a recommendation or countermeasure should be. That's why results are marked 'yes' or 'no' if considered "questionable", or "not good" (for example according other checks). For more details please see RESULTS below. TECHNICAL INFORMATION It is important to understand, which provided information is based on data returned by underlaying (used) libraries and the information computed directly. Version 19.11.19 and later Starting with version 19.11.19 the +cipher command does not use any external library. Checking for ciphers is done using plain Perl code. Only other collected SSL/TLS related information requires an external library, in general libssl. The description about OpenSSL and libssl below applies only if any of the options --ciphermode=openssl or --ciphermode=ssleay are given with the +cipher command. Therefore following commands and options changed: * +cipher uses internal method * +cipherall command obsolete, !!Hint is printed * +cipherraw command obsolete, !!Hint is printed * --openssl-ciphers --force-openssl changed to --ciphermode=openssl * --openssl=TOOL TOOL only used for +cipher --ciphermode=openssl * --legacy=owasp option obsolete The historic commands +cipherall and +cipherraw should be replaced with the new syntax, as follows: VERSION < 19.11.19 VERSION > 19.11.19 #----------------------------+--------------------------------- * +cipher +cipher --ciphermode=ssleay * +cipher --force-openssl +cipher --ciphermode=openssl * +cipherall +cipher * +cipherraw +cipher --ciphermode=intern #----------------------------+--------------------------------- Version before 19.11.19 Up to version 19.11.19 the default behaviour for the +cipher command was to use libssl. The commands +cipherall and +cipherraw did not use any other library as described below. OpenSSL, libssl, libcrypto In general the tool uses Perl's Net::SSLeay(3pm) 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 * --openssl-ciphers --force-openssl * --exe-path=PATH --exe=PATH * --openssl-cnf=PATH * --openssl-s_client --s_client 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 information. Some functionality (checks) of O-Saft may be missing or fail, when openssl versions 1.1.x are used (because functionality was removed). LibreSSL is not recommended, because some functionality 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(3pm) 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 Please see ENVIRONMENT . Requirements 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 for example 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 customised. Requirements for openssl are described there. 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 information. External tools For building and/or viewing the documentation, any of following tools should be available: * aha 0.5-1 * perldoc v3.2801 * pod2man * pod2usage * podviewer v0.18 * tkpod * tput * stty 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 known ciphers in format like "openssl ciphers". It also accepts the -v and -V option. 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. Different output formats are used for the --legacy=* option: * --legacy=simple simple space-separated output * --legacy=full TAB-separated output with more data * --legacy=owasp simple output sorted according OWASP scoring * --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. Use --v option to see all ciphers being checked. +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). # next 4 lines will be replaced by o-saft-man.pl, see /Discrete commands/ there Discrete commands to test SSL connection and certificate details Discrete commands, please see: $0 --help=commands Notes about commands +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). 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. +tlsextdebug +tlsextensions +extensions vs. +tlsextensions "Certificate extensions" are shown with +extensions while the TLS protocol extensions are shown with +tlsextensions. Use +tlsextdebug to show more information about the TLS protocol extensions. +http2 +spdy +spdy3 +spdy31 +spdy4 +prots These commands are just an alias for the +protocols command. +wildcard +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 useful 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 Brief documentation of --help* options/commands. --help Complete user documentation. # next line to keep generated HTML links happy --help* --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 used 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 information. --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). # score will be removed, so don't anounce it # --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 HTML form to be used for CGI. --help=error --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=warnings Show warning messages defined in code. --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 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', except if 'no (<<...>>)' * insecure protocols are available * insecure ciphers are supported * ciphers without PFS are supported, disable with --exitcode-cipher # SEE HTML:Known Bugs in o-saft-man.pm In particular, the status code will be the total count of all these checks. The status code will also be printed at end, like: # EXIT 23 Parts of these checks can be diasabled, see --exitcode-* options below. Use --v or --exitcode-v to see details about the performed checks. Functionality implemented experimental, may change in future. --exitcode-v Print information about performed checks. --exitcode-quiet Do not print status code at end, like '# EXIT 23'. --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-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 information 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 information, 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(3pm) 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, for example: 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 --ciphermode=intern --ciphermode=openssl --ciphermode=ssleay --ciphermode=MODE Following 'MODE's are supported: * 'intern' scan for ciphers using internal method; (default) * 'openssl' scan for ciphers using external openssl executable * 'ssleay' scan for ciphers using IO::Socket and Net::SSLeay * 'dump' same as 'intern' but print all cipher information, useful when postprocessed by contrib/* tools --cipher=CIPHER 'CIPHER' can be any cipher suite name or (internal) hex constant. If 'CIPHER' does not match a hex key, for example 0x03000035, it is used as pattern (RegEx) to match cipher suite names. For example: 'AES256-SHA' matches 23 cipher suites, For example 'AES256-SHA' matches 23 ciphers, while 'AES256-SHA$' matches 2 ciphers, see: OSaft/Ciphers.pm find-names=AES256-SHA OSaft/Ciphers.pm find-names=AES256-SHA$ To be sure that exactly one cipher suite matches, use for example: --cipher=^AES256-SHA$ When --ciphermode=openssl or --ciphermode=ssleay is used, 'CIPHER' can be any string accepted by openssl or a hex constant. Examples: * --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(3pm) 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(3pm) 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 # --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. --force-sni Do not check if SNI seems to be supported by Net::SSLeay(3pm). 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 (for example --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 (for example --force-openssl). --range=RANGE --cipherrange=RANGE Specify range of cipher constants to be tested with +cipher . Following 'RANGE's are supported: * 'rfc' all ciphers defined in various RFCs; default * '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 * 'SSLv3' all ciphers according RFC for SSLv3 * 'SSLv3_SSLv2' all ciphers for SSLv3 with SSLv2 * 'TLSv12' all ciphers according RFC for TLSv12 * 'TLSv13' all ciphers according RFC for TLSv13 * 'c0xx' constants for ciphers using ECC 0x0300C000 .. 0x0300C0FF * 'ccxx' constants for ciphers using ECC 0x0300CC00 .. 0x0300CCFF * 'ecc' all constants for ciphers using ECC Note: 'SSLv2' is the internal list used for testing SSLv2 ciphers. It does not make sense to use it for other protocols; however ... For details about the ranges, please see: $0 --help=range If any --cipher=CIPHER is used, --cipherrange=RANGE is ignored. --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. --https_body Prints HTTP response body of the target also, if requested with +https_body , which is disabled by default (because it may be huge amount of data not related to SSL/TLS). --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. # next line to keep generated HTML links happy --legacy=* --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 'TOOL's 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. When using ths option, please do not expect identical output as the 'TOOL'. It is 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. --tty --format-tty Get the screen width and then adapt output of documentation to fit to that width. If the environment variable 'COLUMNS' is not set the command 'tput' or 'stty' of system is used to get the screen width. It's a very simple approach to make texts better readable on narrow devices like tablets. For more details, please see: perdoc $0 # the section Note:tty there --format-width=NN Set the screen width to 'NN' characters (see --format-tty also). Default will be calculated automatically. --format-ident=NN Set the amount of spaces used for identation (see --tty also). Default is 2. --format-arrow=CHR Set the additional chacacter when lines are split. Default: ↲ --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. --ignore-out=, sets empty list. --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. # next line to keep generated HTML links happy --std-format=* --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 customisation # next line is not a real option, just to keep generated HTML links happy --cfg-CFG Option for customisation have the general from: --cfg-CFG=KEY=TEXT For general descriptions please see CUSTOMISATION section below. --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. # score will be removed, so don't anounce it # --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-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 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 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 +CMD). --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=cli same as --trace-cli * --trace=key same as --trace-key * --trace=time same as --trace-time #--------------------+---------------------------- --trace=FILE Use FILE instead of the default RC-FILE, for example '.$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. --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:). --warnings-dups --no-warnings-no-dups Do not suppress duplicate 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 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* (a.k.a ADH a.k.a DHA) ciphers ** all *CBC* and *CBC3* (a.k.a 3DES, EDE-CBC) and DES ciphers * low: * medium: ** all *PSK* ciphers using CBC (assumes that the PSK is secure) * high: ** all *DHE*AES(128|256)* ciphers ** all *CHACHA* ciphers ** all *PSK* ciphers (except those using +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. 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. SSTP Check if target supports SSTP by accepting method SSTP_DUPLEX_POST. The check does not send other methods (like CONNECT) to verify if the protocol is fully supported. Supporting SSTP is considered insecure, because SSTP allows to tunnel other, probably insecure, protocols. 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. # TODO: test missing; check not yet implemented # Public Key Modulus size # # Some (historic) SSL implementations are subject to buffer overflow if # 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 ecliptic 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 checks, 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, preferred 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 '**', hints 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 information was found or provided. Replace 'N/A' by whatever you think is adequate: "No answer", "Not available", "Not applicable", ... Examples: === Title line === = this is a comment Label for information or check: TABresult !!Hint: above result depends on the target 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. Errors, Warnings, Hints Errors, warnings and hints may be part of the output as needed. While errors and warnings are printed immediately as they occour during the program flow, hints are printed right after the corresponding result. Errors and warnings start with a unique 3-digit number. Hints print an additional explanation of a specific result. They are are defined statically in the program code, or can be added on demand by using the option --cfg-hint=KEY=TEXT . 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 # #----------------------+-------+-------+---------------- EXIT STATUS Following exit codes are used: * 0 - normal usage and execution * 2 - command-line parsing failed, command or option missing * >0 - only if --exitcode was used ENVIRONMENT 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 CUSTOMISATION This tool can be customised 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. Customisation is done by redefining values in internal data structure which are: %cfg, %data, %checks, %text. 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. Texts (values) of keys in '%data' are those used in output of the "Information" section. The texts of keys in '%checks' are used for output in "Performed Checks" section. 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 existing 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 is recommended to use a non-existing key, for example --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 tool starts. It isn't a task for the tool itself, but it can simplify your life, somehow. There exist customisations 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 8) our internal hex numbers for ciphers are like '0x0300CCA9' [IANA] http://www.iana.org/assignments/tls-parameters/tls-parameters.txt August 2022 [openssl] ... openssl 1.0.1 If in any doubt, use any of the provided commands or options to list to show our known ciphers. For example: $0 --test-ciphers-show # or any other --test-ciphers-* $0 --list $0 --help=ciphers-text $0 ciphers -V Use --help=regex to see which regex are used to handle all variants of cipher suite names 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'. There 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 (a.k.a 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: 311: 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: 311: 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: 016: 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: 205: Can't make a connection to your.tld:443; no initial data **WARNING: 205: 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 . 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(3pm). 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 appear 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 recognised in some tools Some tools do not display all characters properly, for example 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) * 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 for example 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. Consequently, 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 command. The reason is most likely that the server does not respond to the TCP/IP request, hence the script closes the connection after the configured timeout (please 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(3pm) * IO::Socket::INET(3pm) * Net::SSLeay(3pm) * Net::SSLinfo * Net::SSLhello Perl modules loaded and used for some options only: * Net::DNS(3pm) * Time::Local(3pm) Additional files used if requested * .o-saft.pl * o-saft-dbx.pm * o-saft-man.pm * o-saft-usr.pm * o-saft-docker * o-saft-README 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. Quickstart The script INSTALL.sh provides a quick method to check, compile and install anything needed. Please see: INSTALL.sh --help For more details, read on ... Requirements for OpenSSL To build openssl following packages are requred (note that the names may differ depending on the used platform): * libidn11-dev * libidn2-0-dev * libgmp-dev * libzip-dev * libsctp-dev * libkrb5-dev Also, following Perl modules should be installed: * Module::Build * Net::LibIDN * Net::LibIDN2 * Mozilla::CA 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. Note that Net::SSLeay needs to be adapted properly then. 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. For a more complete build, plese see: contrib/install_openssl.sh . 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. ABOUT CGI This script can be used as CGI application. Output is the same as in common CLI mode. The output will be prefixed with the HTTP header 'Content-Type:text/plain'. The script o-saft.cgi should be used as wrapper for $0 . The HTML form o-saft.cgi.html which can be generated with: $0 --help=gen-cgi should be used as front-end for o-saft.cgi. CGI-form functionality This form provides following functionality: * top menu bar with following menus: * ☰ - general informations about CGI usage * Cmd - quick commands menu * Opt - quick options menu * Help - various help pages * input field for a target (hostname or URL) * GUI sections * Simple GUI - simple form with most common commands and options Each provided +command buttons submit the form with the selected options and the clicked command. * Full GUI Commands & Options - form with all commands and options, its content is The same as the COMMANDS and OPTIONS section of the complete help page (see --help ). In both GUI sections following buttons exist: * ^ - return to top of form * start - submit form with selected command and options In general, command buttons which submit the form are yellow. Buttons which show some help, mainly in a new browser tab, are gray. CGI-form limitations * The generated form provides commands and options which are rejected by o-saft.cgi (see below). * The generated form may contain references (links) to sections which are not part of the form. * Only one target can be provided, however, it is obvious how to use more targets ... * The --format=html option should be used together with --header , otherwise the generated HTML may be corrupted for some commands. CGI script limitations The script returns an empty page (HTML body) for following reasons: * Use of local or multicast IPs as target. * Use of dangerous commands or options. For deatils pleasesee perldoc o-saft.cgi 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(3pm), Net::SSLhello, Net::SSLinfo, timeout(1) * http://www.openssl.org/docs/apps/ciphers.html * IO::Socket::SSL(3pm), IO::Socket::INET(3pm) * 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: 303: SSL version 'SSLv2': not supported by openssl All such warnings look like: **WARNING: 303: 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(3pm) 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 (a.k.a 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 by --exe=PATH * prepend 'LD_LIBRARY_PATH' with all values given by --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, for example: 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, for example: $0 --lib=/tmp/dada +ciphers This works if openssl(1) uses the same shared libraries as Net::SSLeay(3pm), 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(3pm) 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(3pm) 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-cli * --trace-key * --trace-me * --trace-time * --trace=FILE Please see OPTIONS section above for detailed description. 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 '...'. In general, single-line values are always printed, multi-line values are printed with --trace=2 only. Hint: start with --trace-me, then --trace and finally --trace=2 . 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 This tool 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 ::SSLEAY_DIR OPENSSLDIR: "/usr/local/openssl/ssl" Net::SSLeay::SSLeay_version() OpenSSL 1.0.2-chacha (1.0.2f-dev) = openssl = external executable /opt/openssl-chacha/bin/openssl external executable (TLSv1.3) openssl version of external executable OpenSSL 1.0.2-chacha (1.0.2f-dev) 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 . existing path to CA PEM files /etc/ssl/certs common PEM filenames for CAs ca-certificates.crt certificates.crt certs.pem . existing PEM file for CA /etc/ssl/certs/ca-certificates.crt number of supported ciphers 201 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 = number of supported ciphers 1280 default list of ciphers 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300C0FF, . 0x0300CC00 .. 0x0300CCFF, 0x0300FE00 .. 0x0300FFFF, long list of ciphers 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300FFFF huge list of ciphers 0x03000000 .. 0x0300FFFF safe list of ciphers 0x03000000 .. 0x032FFFFF full list of ciphers 0x03000000 .. 0x03FFFFFF C0xx list, range C0xx..C0FF 0x0300C000 .. 0x0300C0FF CCxx list, range CCxx..CCFF 0x0300C000 .. 0x0300C0FF ECC list, ephermeral ciphers 0x0300C000 .. 0x0300C0FF, 0x0300CC00 .. 0x0300CCFF = 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.044 /usr/share/perl5/IO/Socket/SSL.pm Time::Local 1.2300 /usr/share/perl/5.24/Time/Local.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 19.12.21 Net/SSLinfo.pm Net::SSLhello 19.12.21 Net/SSLhello.pm Ciphers osaft 19.12.26 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: 121: ancient Net::SSLeay 1.35 < 1.49; cannot use ::initialise at /Net/SSLinfo.pm line 481. === reading: ./Net/SSLinfo.pm (O-Saft module done) === **WARNING: 120: ancient perl has no 'version' module; version checks may not be accurate; at o-saft.pl line 1662. **WARNING: 121: ancient Net::SSLeay 1.35 < 1.49 detected; at o-saft.pl line 1687. **WARNING: 121: ancient IO::Socket::SSL 1.22 < 1.37 detected; at o-saft.pl line 1687. **WARNING: 124: 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: 851: 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: 851: ancient version Net::SSLeay 1.35 < 1.49; cannot compare SSLeay with openssl version at o-saft.pl line 4778. ::SSLeay() 0x1.35 **WARNING: 851: 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: 851: ancient version Net::SSLeay 1.35 < 1.49; cannot compare SSLeay with openssl version at o-saft.pl line 4778. **WARNING: 841: 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 What is "testing"? This tool itself is for testing something (TLS etc.), so it needs to be explained what testing here is about. Following testing types are distinguished and then described: * User testing * Functional testing * Developer (internal) testing All descriptions below, except "User testing", are only intended for development. User testing During normal use of the tool, "testing" is only required for hunting problems with the connected target. Following options for tracing and verbosity can be used for that: --v Print more information about checks. --trace Print debugging messages. For more details, please see X&Options for tracing and debugging& . Functional testing This section describes "developer" rather than "user" testing. Functional testing mainly means testing the functionality of the tool itself, for example: do the commands and options work as described in the documentation: $0 --help Makefiles are used for testing functionality and code quality during development. These tests are implemented in the ./t/ directory, see all 'Makefile.*' there, start with 'Makefile.pod'. Developer (internal) testing Testing SSL/TLS 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 for $0 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: " The options which provide information about internal data structures and alike described below, behave like the command +quit and do not perform any checks on the target(s). See 't/Makefile.*' how to use these tests. --tests Print overview of following commands/options. --test-data Print overview of all available commands and checks. --test-maps Print internal data strucures '%cfg{openssl}', '%cfg{ssleay}'. --test-prot Print internal data according protocols. --test-regex Print results for applying various texts to defined regex. --test-ciphers-dump --test-ciphers-overview --test-ciphers-openssl --test-ciphers-show --test-ciphers-simple --test-ciphers-sorted --test-ciphers-ssltest Print ciphers in various formats, please see: OSaft/Ciphers.pm . These options are aliases for: +list --legacy=TYP . --test-ciphers-hex=* --test-ciphers-key=* --test-ciphers-list Print some special information, please see: OSaft/Ciphers.pm . --test-init Print parts of data structure '%cfg'. In contrast to the options described above, --test-init exits straight before performing the specified commands on the target. Therefore it prints the settings in '%cfg' containing all applied commands and options. --test-memory Print overview of variables' memory usage, used for debugging only. --test-methods Print available methods for 'openssl' in Net::SSLeay. --test-sclient Print available options for 'openssl s_client' from Net::SSLeay. --test-sslmap Print SSL protocols constants from Net::SSLeay. --test-ssleay Print information about Net::SSLeay capabilities. --test-sub Obsolete, please use: make test.dev.grep.sub make test.dev-grep.subs make test.dev-grep.desc Testing results Finally there should be tests, which prove that the results of $0 are really what they should be. A test target is necessary therefore, which produces reliable results. However, some of the implemented tests in 't/Makefile.*' (see section "Functional testing" above) already work properly. This test coverage needs to be improved ... 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 * 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 Testing with exit code * Test SSL/TLS connection and return exit code $0 +check --exitcode some.tld * Test ciphers and return exit code with details about exit code $0 +cipher --exitcode --exitcode-v some.tld * Test ciphers and return exit code for ciphers only $0 +cipher --exitcode --exitcode-no-prot some.tld * Test with exit code but avoid checks considered 'yes' even if 'no' $0 +check --exitcode --ignore-out=ev- --ignore-out=rfc_7525 some.tld 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 DOCUMENTATION User documentation Documentation is mainly intented for the user, which is provided with $0 --help But it may be difficult to find the proper information there. To get more selective documentations, the --help=* options can be used. To get an overview which --help=* options are available, use: $0 --help=HELP This only provides the complete user documentation, or the well known parts specified by the keyword, (HELP in example above). To find any text with some lines of context, following could be used: $0 --help | egrep -i -C 3 "some text" This is simply avaiable with: o-saft --help="some text" In the GUI a more sophisticate search is implemented, see the "Help" window there: o-saft.tcl Developer documentation Documentation for developers is provided in various ways. Information for developers can be found found in: * the files itself * with: $0 --help=test $0 --test * reading: docs/concepts.txt Makefile.pod perldoc Makefile.pod * using: make make help.doc Using make for development uses additional external tools and/or Perl modules: * perl-analyzer (also requires Perl modules, JSON, Text::MicroTemplate) * Debug::Trace Devel::Trace Devel::DProf Devel::NYTProf 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. * Basic cipher check 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 Project Home: https://owasp.org/www-project-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 ** Checking fallback from TLS 1.1 to TLS 1.0 (see ssl-cipher-check.pl) ** Minimal encryption strength: weak encryption (40-bit) (TestSSLServer.jar) * 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 really 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, because it misses IO/Socket/SSL.pm, however, checkAllCiphers.pl works. perl from older PortableApps/xampp (i.e. 1.7.x) does not work, because 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 command-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 information (a.k.a %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-22.11.22/OSaft/Doc/links.txt000066400000000000000000000155021433765727300164600ustar00rootroot00000000000000 # SID @(#) links.txt 1.8 22/10/10 20:00:20 # 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 Security Flaws by CBC Padding https://link.springer.com/content/pdf/10.1007/3-540-46035-7_35.pdf 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 Pseudo Constant Time Implementations of TLS https://eprint.iacr.org/2018/747.pdf 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 Attacker https://www.nds.ruhr-uni-bochum.de/media/nds/veroeffentlichungen/2016/10/19/tls-attacker-ccs16.pdf 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 Attacks https://tls-scanner.cs.uni-paderborn.de/wiki 3SHAKE https://mitls.org/pages/attacks/3SHAKE ALPACA ? Bar Mitzvah https://www.blackhat.com/docs/asia-15/materials/asia-15-Mantin-Bar-Mitzvah-Attack-Breaking-SSL-With-13-Year-Old-RC4-Weakness-wp.pdf BEAST https://vnhacker.blogspot.com/2011/09/beast.html https://nerdoholic.org/uploads/dergln/beast_part2/ssl_jun21.pdf 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 https://www.gracefulsecurity.com/crime-against-tls/ DROWN https://drownattack.com/ EFAIL https://efail.de/ https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-poddebniak.pdf FREAK https://freakattack.com/ FREAK https://mitls.org/pages/attacks/SMACK#freak Lucky 13 http://www.isg.rhul.ac.uk/tls/Lucky13.html Lucky 13 Microseconds http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.738.4741&rep=rep1&type=pdf Lucky 13 Strickes Back http://v.wpi.edu/wp-content/uploads/Papers/Publications/asiaccs2015_lucky.pdf LogJam https://weakdh.org/ NOMORE https://www.rc4nomore.com/ POODLE https://www.openssl.org/~bodo/ssl-poodle.pdf https://www.imperialviolet.org/2014/10/14/poodle.html https://www.imperialviolet.org/2014/12/08/poodleagain.html RACCOON ? ROCA https://crocs.fi.muni.cz/public/papers/rsa_ccs17 ROBOT https://robotattack.org/ SHAttered https://shattered.io SLOTH https://www.mitls.org/pages/attacks/SLOTH SKIP https://mitls.org/pages/attacks/SMACK SMACK https://mitls.org/pages/attacks/SMACK https://www.smacktls.com/ Sweet32 https://sweet32.info/ https://www.openssl.org/blog/blog/2016/08/24/sweet32/ 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-22.11.22/OSaft/Doc/misc.txt000066400000000000000000000125351433765727300162760ustar00rootroot00000000000000 # 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-22.11.22/OSaft/Doc/rfc.txt000066400000000000000000000237151433765727300161170ustar00rootroot00000000000000 # SID @(#) rfc.txt 1.18 22/11/05 11:37:10 # 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 2144 CAST-128 Encryption Algorithms 2612 CAST-256 Encryption Algorithms 2950 Telnet Encryption: CAST-128 64 bit Cipher Feedback 2984 Use of the CAST-128 Encryption Algorithm in CMS 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) 4303 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 4106 Use of Galois/Counter Mode (GCM) in IPsec Encapsulating Security Payload (ESP) 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 4490 Using the GOST 28147-89, GOST R 34.11-94, GOST R 34.10-94, and GOST R 34.10-2001 Algorithms with Cryptographic Message Syntax (CMS) 4491 Using the GOST Algorithms with X509 (GOST R 34.10-94, GOST R 34.10-2001, GOST R 34.11-94) 4634 US Secure Hash Algorithms (SHA, SHA-based HMAC and HKDF) 5869 HMAC-based Extract-and-Expand Key Derivation Function (HKDF) 5830 GOST 28147-89: Encryption, Decryption, and Message Authentication Code (MAC) Algorithms 5831 GOST R 34.11-94: Hash Function Algorithm 5832 GOST R 34.10-2001: Digital Signature Algorithm 6986 GOST R 34.11-2012: Hash Function 7091 GOST R 34.10-2012: Digital Signature Algorithm 7801 GOST R 34.12-2015: Block Cipher "Kuznyechik" 9189 GOST Cipher Suites for Transport Layer Security (TLS) Protocol Version 1.2 9150 TLS 1.3 Authentication and Integrity-Only Cipher Suites 7836 Guidelines on the Cryptographic Algorithms to Accompany the Usage of Standards GOST R 34.10-2012 and GOST R 34.11-2012 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 5297 Synthetic Initialization Vector (SIV) Authenticated Encryption Using the Advanced Encryption Standard (AES) 8452 AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption 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 6151 Updated Security for MD5 and HMAC-MD5 6234 US Secure Hash Algorithms (SHA, SHA-based HMAC and HKDF) 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 7905 ChaCha20-Poly1305 Cipher Suites for TLS 7627 TLS Session Hash and Extended Master Secret Extension 7693 The BLAKE2 Cryptographic Hash and Message Authentication Code 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 8492 Secure Password Ciphersuites for Transport Layer Security (TLS) 1918 Address Allocation for Private Internets 6598 IANA-Reserved IPv4 Prefix for Shared Address Space 8701 Applying Generate Random Extensions And Sustain Extensibility (GREASE) to TLS Extensibility 8998 ShangMi (SM) Cipher Suites for TLS 1.3 9102 Argon2 Memory-hard function for password hashing and proof-of-work applications (2021) 9155 Deprecating MD5 and SHA-1 Signature Hashes in TLS 1.2 and DTLS 1.2 8398 Internationalized Email Addresses in X.509 Certificates 8399 Internationalization Updates to RFC 5280 O-Saft-22.11.22/OSaft/Doc/tools.txt000066400000000000000000000171351433765727300165040ustar00rootroot00000000000000 # SID @(#) tools.txt 1.9 22/04/20 10:05:34 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&--cmd=CMD&--host=target" o-saft.cgi https://o-saft.pl/o-saft.cgi?--cgi&OPTIONS&--cmd=CMD&--host=target checkAllCiphers.pl 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 categorised 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 CLI checkAllCiphers.pl # simple quick cipher check 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 most 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 Simple check for ciphers checkAllCiphers.pl target GUI o-saft.tcl is the graphical user interface for o-saft.pl . o-saft.tcl o-saft.tcl --docker o-saft-docker gui -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/Cert-beautify.pl contrib/symbol.pl contrib/*.awk contrib/* TBD They are used in general like: o-saft.pl ... target | contrib/..... Formatting quick cipher check: checkAllCiphers.pl target > target-alerts.csv contrib/alertscript.pl --csv=target-alerts.csv Advanced Tools Check a target for ciphers with various methods: contrib/cipher_check.sh In legacy systems, or when resources are limited, a special version 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 can be used to install anything in its own directory. It can also be used to check and cleanup the installation. INSTALL.sh contrib/install_openssl.sh contrib/install_perl_modules.pl contrib/distribution_install.sh contrib/*_completion_o-saft contrib/zap_config.* 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/.perlcriticrc contrib/critic.sh CUSTOMISATION The tools can be customised 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.tld 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.tld o-saft-docker -post=bunt.pl +check --header some.tld 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-22.11.22/OSaft/Text.pm000077500000000000000000000106201433765727300153530ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) 2022, Achim Hoffmann #!# This software is licensed under GPLv2. Please see o-saft.pl for details. package OSaft::Text; use strict; use warnings; my $SID_text = "@(#) Text.pm 1.6 22/11/04 10:51:16"; our $VERSION = "22.11.22"; #_____________________________________________________________________________ #________________________________________________ public (export) variables __| our %STR = ( 'ERROR' => "**ERROR: ", 'WARN' => "**WARNING: ", 'HINT' => "!!Hint: ", 'USAGE' => "**USAGE: ", 'DBX' => "#dbx# ", 'UNDEF' => "<>", 'NOTXT' => "<<>>", 'MAKEVAL' => "<>", ); use Exporter qw(import); use base qw(Exporter); our @EXPORT_OK = qw( %STR print_pod text_done ); # SEE Perl:constant #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME OSaft::Text -- common texts for O-Saft and related tools =head1 SYNOPSIS =over 2 =item use OSaft::Text; # in perl code =item OSaft/Text.pm --help # on command-line will print help =back =head1 OPTIONS =over 4 =item --help =back =head1 DESCRIPTION Utility package for O-Saft (o-saft.pl and related tools). It declares and defines common L to be used in the calling tool. All variables and methods are defined in the OSaft::Text namespace. =head1 TEXTS Perlish spoken, all texts are variables: =over 4 =item %STR{ERROR} =item %STR{WARN} =item %STR{HINT} =item %STR{USAGE} =item %STR{DBX} =item %STR{UNDEF} =item %STR{NOTXT} =item %STR{MAKEVAL} =back =head1 METHODS =head2 OSaft::Text::print_pod($file) Print POD for specified file, exits program. =head1 SEE ALSO # ... =head1 VERSION 1.6 2022/11/04 =head1 AUTHOR 22-feb-22 Achim Hoffmann =cut #_____________________________________________________________________________ #_________________________________________________________ internal methods __| # SEE Perl:Undefined subroutine *_warn = sub { print(join(" ", "**WARNING:", @_), "\n"); return; } if not defined &_warn; *_dbx = sub { print(join(" ", "#dbx#" , @_), "\n"); return; } if not defined &_dbx; #_____________________________________________________________________________ #__________________________________________________________________ methods __| sub print_pod { #? print POD of specified file; exits program my $file = shift; # filename where to read POD from my $pack = shift; # package name my $vers = shift; # package version printf("# %s %s\n", $pack, $vers); if (eval {require Pod::Perldoc;}) { # pod2usage( -verbose => 1 ); exit( Pod::Perldoc->run(args=>[$file]) ); } 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 $file\n"); } exit 0; } # print_pod #_____________________________________________________________________________ #____________________________________________________ internal test methods __| #_____________________________________________________________________________ #_____________________________________________________________________ main __| sub _main_text { my @argv = @_; push(@argv, "--help") if (0 > $#argv); binmode(STDOUT, ":unix:utf8"); ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) binmode(STDERR, ":unix:utf8"); ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # got arguments, do something special while (my $arg = shift @argv) { print_pod($0, __PACKAGE__, $SID_text) if ($arg =~ m/^--?h(?:elp)?$/x);# print own help if ($arg =~ m/^--(?:test[_.-]?)text/x) { $arg = "--test-text"; printf("#$0: direct testing not yet possible, please try:\n o-saft.pl $arg\n"); } } exit 0; } # _main_text sub text_done {}; # dummy to check successful include ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main_text(@ARGV) if (not defined caller); 1; O-Saft-22.11.22/OSaft/error_handler.pm000077500000000000000000000541631433765727300172670ustar00rootroot00000000000000#!/usr/bin/perl -w # Filename: error_handler.pm #!############################################################################# #!# Copyright (c) 2022, 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 => '19.11.19', # 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 { ## no critic qw(Subroutines::ProhibitExcessComplexity) 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-22.11.22/README.md000066400000000000000000000103471433765727300143370ustar00rootroot00000000000000 ---- | | |:--| | Any use of this project's code by GitHub Copilot, past or present, is done without our permission. We do not consent to GitHub's use of this project's code in Copilot. | | | ---- # [ O-Saft - OWASP SSL advanced forensic tool](https://owasp.org/www-project-o-saft/) ## 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: | Module | Version | |:---------------------|:--------| | Net::SSLeay | (prefered >= 1.51, recommended 1.85) | | IO::Socket::SSL | (prefered >= 1.37, recommended 2.002) | | IO::Socket::INET | (prefered >= 2.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 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: | File / Tool | Description | |:---------------------|:------------| | `.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 checking all ciphers) | | `.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 --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 **22.11.22** 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](https://github.com/OWASP/O-Saft/raw/master/o-saft.tgz) ``` 8a1df29b32f6e8fe4bbcfd4b42a9924cb60434c54493cf0d27b2b881e0739c97 ``` 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-22.11.22/checkAllCiphers.pl000077500000000000000000001051011433765727300164350ustar00rootroot00000000000000#!/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 BEGIN { # SEE Perl:BEGIN perlcritic my $_path = $0; $_path =~ s#[/\\][^/\\]*$##; unshift(@INC, ".", $_path, "/bin" ); # /bin for special installation on portable media } use osaft; 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->)$ my $VERSION = "20.11.09"; 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'} ||= 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); ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) # 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-22.11.22/contrib/000077500000000000000000000000001433765727300145135ustar00rootroot00000000000000O-Saft-22.11.22/contrib/Cert-beautify.awk000077500000000000000000000133121433765727300177250ustar00rootroot00000000000000#!/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-22.11.22/contrib/Cert-beautify.pl000077500000000000000000000063071433765727300175640ustar00rootroot00000000000000#!/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-22.11.22/contrib/Dockerfile.alpine-3.6000066400000000000000000000075421433765727300202700ustar00rootroot00000000000000#!/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-22.11.22/contrib/Dockerfile.wolfssl000066400000000000000000000212731433765727300202020ustar00rootroot00000000000000#!/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-22.11.22/contrib/HTML-simple.awk000077500000000000000000000015361433765727300172620ustar00rootroot00000000000000#!/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-22.11.22/contrib/HTML-table.awk000077500000000000000000000061711433765727300170600ustar00rootroot00000000000000#!/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.4 22/10/27 11:07:38 #? #? AUTHOR #? 06. June 2016 Achim Hoffmann #? # ----------------------------------------------------------------------------- BEGIN { FS="\t"; print ""; print ""; class = ""; } (NF>0){ gsub(/&/,"\\&"); gsub(/"/,"\\""); gsub(//,"\\>"); } /^\s*$/{ next; } ($1~/ reading/) { next; } ($1~/^**ERROR/) { class = "red"; } ($1~/^**WARN/) { class = "pink"; } ($1~/^**HINT/) { class = "blue"; } ($1~/^!!Hint/) { class = "blue"; } (0 < length(class)) { sub(/ /,"\t");printf(" \n", $1, class, $2); class=""; next; } ($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%s
    \n

    %s

    \n\n", $0); next; } ($1~/^===/ && $NF~/===/) { gsub(/===/,""); printf("
    \n

    %s

    \n\n", $0); next; } ($1~/^== /) { printf(" \n", $0); next; } ($1~/^=/ && $0 ~/ipher/ && $0~/supported/) { # some header lines in cipher list are special split($0,a,/[ ]*/);printf(" \n", a[2], a[3], a[4]); next; } ($1~/^=/ && $0!~/----/) { gsub(/^ *=/,""); printf(" ", $1, $2); 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
    %s%s
    %s%s%s
    "; } O-Saft-22.11.22/contrib/INSTALL-template.sh000077500000000000000000001074331433765727300200010ustar00rootroot00000000000000#! /bin/sh #? #? File INSERTED_BY_MAKE_FROM #? #? NAME #? $0 - install script for O-Saft #? #? SYNOPSIS #? $0 [options] [/path/to/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: #? #? /path/to/installation/directory #? - copy all necessary files into specified directory #? --install - copy all necessary files into default directory #? default if no other option given #? --check - check current installation #? --clean - move files not necessary to run O-Saft into subdir #? ./.files_to_be_removed # This is the behaviour of the old INSTALL-devel.sh script. #? --openssl - calls contrib/install_openssl.sh which builds and #? installs openssl and Net::SSLeay ; this doesn't #? support other options and arguments of #? contrib/install_openssl.sh #? --cgi - prepare directory to be used in CGI mode #? --expected - show sample output expected for --check # All lines starting with #= are the sample output. #? --checkdev - check system for development (make) requirements #= #=# check for O-Saft programs found via environment variable PATH #=#-------------------------------------------------------------- #=# wish /usr/bin #=# o-saft.pl not found in PATH, consider adding /opt/o-saft to PATH #=# o-saft.tcl not found in PATH, consider adding /opt/o-saft to PATH #=# o-saft not found in PATH, consider adding /opt/o-saft to PATH #=# Note: all found executables in PATH are listed #=#-------------------------------------------------------------- #= #=# check installation in /opt/o-saft #=#-------------------------------------------------------------- #=# (warnings are ok if »git clone« will be used for development) #=# Dockerfile found; did you run »INSTALL.sh --clean«? #=# Makefile found; did you run »INSTALL.sh --clean«? #=# t/ found; did you run »INSTALL.sh --clean«? #=# contrib/critic.sh found; did you run »INSTALL.sh --clean«? #=# CHANGES found; did you run »INSTALL.sh --clean«? #=# README found; did you run »INSTALL.sh --clean«? #=#-------------------------------------------------------------- #= #=# check for used O-Saft programs (according $PATH) #=#----------------------+--------------------------------------- #=# o-saft.pl 22.11.22 /opt/o-saft/o-saft.pl #=# o-saft.tcl 2.35 /opt/o-saft/o-saft.tcl #=# o-saft 1.26 /opt/o-saft/o-saft #=# contrib/o-saft-standalone.pl 22.11.22 contrib/o-saft-standalone.pl #=#----------------------+--------------------------------------- #= #=# check for installed O-Saft resource files #=#----------------------+--------------------------------------- #=# ./.o-saft.pl will be used when started in . only #=# /opt/o-saft/.o-saft.pl will be used when started in /opt/o-saft only #=# /home/usr/.o-saft.tcl missing, consider generating: »o-saft.tcl --rc > /home/user/.o-saft.tcl« #=#----------------------+--------------------------------------- #= #=# check for installed Perl modules (started in '$inst_directory') #=#----------------------+--------------------------------------- #=# Net::DNS 1.29 /usr/local/share/perl/5.24.1/Net/DNS.pm #=# Net::SSLeay 1.88 /usr/local/lib/x86_64-linux-gnu/perl/5.24.1/Net/SSLeay.pm #=# IO::Socket::INET 1.41 /usr/local/lib/x86_64-linux-gnu/perl-base/IO/Socket/INET.pm #=# ancient module found, try installing newer version, at least 1.49 #=# IO::Socket::SSL 2.069 /usr/share/perl5/IO/Socket/SSL.pm #=# Time::Local 1.28 /usr/share/perl/5.28/Time/Local.pm #=# osaft 22.11.22 osaft.pm #=# Net::SSLinfo 22.11.12 Net/SSLinfo.pm #=# Net::SSLhello 22.06.22 Net/SSLhello.pm #=# OSaft::Ciphers 22.11.22 OSaft/Ciphers.pm #=# OSaft::Data 22.06.22 OSaft/Data.pm #=# OSaft::Text 22.11.22 OSaft/Text.pm #=# OSaft::error_handler 19.11.19 OSaft/error_handler.pm #=# OSaft::Doc::Data 22.11.13 OSaft/Doc/Data.pm #=#----------------------+--------------------------------------- #= #=# check for important Perl modules used by installed O-Saft #=#----------------------+--------------------------------------- #=# testing /opt/o-saft/o-saft.pl ... #=# Net::DNS 1.29 /usr/local/share/perl/5.24.1/Net/DNS.pm #=# Net::SSLeay 1.88 /usr/local/lib/x86_64-linux-gnu/perl/5.24.1/Net/SSLeay.pm #=# IO::Socket::INET 1.41 /usr/local/lib/x86_64-linux-gnu/perl-base/IO/Socket/INET.pm #=# IO::Socket::SSL 2.069 /usr/share/perl5/IO/Socket/SSL.pm #=# Time::Local 1.28 /usr/share/perl/5.28/Time/Local.pm #=# testing /opt/o-saft/o-saft.pl in /opt/o-saft ... #=# Net::DNS 1.29 /usr/local/share/perl/5.24.1/Net/DNS.pm #=# Net::SSLeay 1.88 /usr/local/lib/x86_64-linux-gnu/perl/5.24.1/Net/SSLeay.pm #=# IO::Socket::SSL 2.069 /usr/share/perl5/IO/Socket/SSL.pm #=# Time::Local 1.28 /usr/share/perl/5.28/Time/Local.pm #=#----------------------+--------------------------------------- #= #=# summary of warnings from installed O-Saft (should be empty) #=#----------------------+--------------------------------------- #=# testing /opt/o-saft/o-saft.pl in /opt/o-saft ... #=#----------------------+--------------------------------------- #= #=# check for openssl executable in PATH #=#----------------------+--------------------------------------- #=# openssl /usr/bin/openssl (OpenSSL 1.1.1n 15 Mar 2022) #=#----------------------+--------------------------------------- #= #=# check for openssl executable used by O-Saft #=#----------------------+--------------------------------------- #=# ./o-saft.pl /usr/local/openssl/bin/openssl (1.0.2k-dev) #=# /opt/o-saft/o-saft.pl /usr/local/openssl/bin/openssl (1.0.2k-dev) #=#----------------------+--------------------------------------- #= #=# check for optional tools to view documentation: #=#----------------------+--------------------------------------- #=# aha /usr/bin/aha #=# perldoc /usr/bin/perldoc #=# pod2html /usr/bin/pod2html #=# pod2man /usr/bin/pod2man #=# pod2text /usr/bin/pod2text #=# pod2usage /usr/bin/pod2usage #=# podman missing #=# podviewer /usr/bin/podviewer #=# stty /bin/stty #=# tkpod /usr/bin/tkpod #=# tput /usr/bin/tput #=# #=# Note: podman is a tool to view pod files, it's not the container engine #=#----------------------+--------------------------------------- #= #=# check for contributed files (in /opt/o-saft/contrib ) #=#----------------------+--------------------------------------- #=# Cert-beautify.awk /opt/o-saft/contrib/Cert-beautify.awk #=# Cert-beautify.pl /opt/o-saft/contrib/Cert-beautify.pl #=# HTML-simple.awk /opt/o-saft/contrib/HTML-simple.awk #=# HTML-table.awk /opt/o-saft/contrib/HTML-table.awk #=# JSON-array.awk /opt/o-saft/contrib/JSON-array.awk #=# JSON-struct.awk /opt/o-saft/contrib/JSON-struct.awk #=# XML-attribute.awk /opt/o-saft/contrib/XML-attribute.awk #=# XML-value.awk /opt/o-saft/contrib/XML-value.awk #=# alertscript.cfg /opt/o-saft/contrib/alertscript.cfg #=# alertscript.pl /opt/o-saft/contrib/alertscript.pl #=# bash_completion_o-saft /opt/o-saft/contrib/bash_completion_o-saft #=# bunt.pl /opt/o-saft/contrib/bunt.pl #=# bunt.sh /opt/o-saft/contrib/bunt.sh #=# cipher_check.sh /opt/o-saft/contrib/cipher_check.sh #=# dash_completion_o-saft /opt/o-saft/contrib/dash_completion_o-saft #=# filter_examples /opt/o-saft/contrib/filter_examples #=# fish_completion_o-saft /opt/o-saft/contrib/fish_completion_o-saft #=# lazy_checks.awk /opt/o-saft/contrib/lazy_checks.awk #=# symbol.pl /opt/o-saft/contrib/symbol.pl #=# tcsh_completion_o-saft /opt/o-saft/contrib/tcsh_completion_o-saft #=# usage_examples /opt/o-saft/contrib/usage_examples #=# zap_config.sh /opt/o-saft/contrib/zap_config.sh #=# zap_config.xml /opt/o-saft/contrib/zap_config.xml #=# o-saft-standalone.pl /opt/o-saft/contrib/o-saft-standalone.pl #=#----------------------+--------------------------------------- #= #=# checks passed #? #? OPTIONS #? --h got it # --help got it #? --n do not execute, just show (ignored for --check) #? -x debug using shell's "set -x" #? --force - install RC-FILEs .o-saft.pl and .o-saft.tcl in #? $HOME, overwrites existing ones #? --no-colour - do not use coloured texts; default #? --colour - use coloured texts (red, yellow, blue|green) #? --colour-blind - same as --colour #? --colour-not-blind - use green instead of blue coloured texts #? --other - check for other SSL-related tool with --checkdev #? --useenv - change #! (shebang) lines to #!/usr/bin/env #? Applies only to files with following extensions: #? .awk .cgi .pl .sh .tcl .txt #? also applies to all Makefile* . #? The shebang line will only be changed when there #? are no arguments given. #? Examples of changed lines: #? #!/bin/sh #? #! /bin/sh #? #!/bin/cat #? #!/usr/bin/make #? #!/usr/bin/perl #? Examples of lines not to be changed: #? #!/usr/bin/gawk -f #? #!/usr/bin/make -rRf #? #! /usr/bin/perl -w #? #!/usr/bin/perl -w #? #!/usr/bin/perl -w -I . #? --gnuenv - change #! (shebang) lines to #!/usr/bin/env -S #? Applies the change to shebang lines with arguments. #? Implies --useenv . #? #? Please see docs/concepts.txt for details about /usr/bin/env . #? It's up to user then, which solution fits better. #? #? EXAMPLES #? $0 #? $0 --clean #? $0 --check #? $0 --install #? $0 /opt/bin/ #? $0 /opt/bin/ --force #? $0 /opt/bin/ --useenv #? $0 /opt/bin/ --gnuenv #? $0 --install /opt/bin/ #? $0 --check /opt/bin/ #? $0 --check /opt/bin/ --colour #? $0 --checkdev #? $0 --cgi /opt/bin/ #? $0 --cgi . #? # HACKER's INFO # This file is generated from INSTALL-template.sh . # The generator (make) inserts most values for internal variables. In # particular the list of source files to be installed. See the strings # and scopes containing "INSERTED_BY_MAKE" . # # All output is pretty printed. Yes, this adds some complexity, but it # is assumed that mainly humans read the output. # # Environment variable inst can be set to installation directory: This # is useful for development only, hence not officially documented. # env inst=. $0 --check # # Silently accepts the options -n or -h or --x also. # # echo vs /bin/echo # echo is a pain, depending on the platform. The shell's built-in echo # does not have the -n option, usually. /bin/echo doesn't know about # ANSI escape sequences, usually. \-escaped characters, like \t , are # another problem, some shells support them, others do not. # I.g. we'd like to use traditional bourne shell, where all behaviours # are well defined. Unfortunately, some platforms seem to be a hostage # of their developers who believe that their favorite shell has to be # used by all users (linking to /bin/sh to whatever, without informing # the user). # Best effort to get this script working on most platforms was: # * mainly use /bin/echo (aliased to echo, to keep code readable) # * TABs (aka \t aka 0x09) are used verbatim (see $t variable) # * shell's built-in echo used when ANSI escape sequences are used # There's no guarantee that it works flawless on everywhere, currently # (8/2019) it works for BSD, debian (including Mac OSX). # Functionallity of this script is not harmed, if the output with echo # fails (prints ANSI escapes and/or \-escapes verbatim, and/or prints # -n verbatim, etc.). # #? DEPENDENCIES #? Following tools are required for proper functionality: #? awk, cat, perl, sed, tr, which, /bin/echo #? #? VERSION #? @(#) 1.104 22/11/23 20:50:45 #? #? AUTHOR #? 16-sep-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- # --------------------------------------------- internal variables; defaults try='' ich=${0##*/} dir=${0%/*} [ "$dir" = "$0" ] && dir="." # $0 found via $PATH in . _break=0 # 1 if screen width < 50; then use two lines as output colour="" # 32 green, 34 blue for colour-blind useenv=0 # 1 to change shebang lines to /usr/bin/env useenv=0 # 1 to change shebang lines to /usr/bin/env other=0 force=0 optx=0 optn="" mode=""; # "", cgi, check, clean, dest, openssl alias echo=/bin/echo # need special echo which has -n option; # TODO: check path for each platform tab=" " # need a real TAB (0x09) for /bin/echo text_miss=" missing, try installing with "; text_old="ancient module found, try installing newer version, at least " text_one="missing, consider generating with »make standalone«" text_path="Note: all found executables in PATH are listed" text_prof="note: Devel::DProf Devel::NYTProf and GraphViz2 may wrongly be missing" text_tool="Note: podman is a tool to view pod files, it's not the container engine" # must be redefined after reading arguments text_dev="did you run »$0 --clean«?" text_alt="file from previous installation, try running »$0 --clean« " # INSERTED_BY_MAKE { osaft_sh="INSERTED_BY_MAKE_OSAFT_SH" osaft_exe="INSERTED_BY_MAKE_OSAFT_PL" osaft_gui="INSERTED_BY_MAKE_OSAFT_GUI" osaft_one="INSERTED_BY_MAKE_OSAFT_STAND" osaft_dock="INSERTED_BY_MAKE_OSAFT_DOCKER" contrib_dir="INSERTED_BY_MAKE_CONTRIBDIR" inst_directory=${inst:="INSERTED_BY_MAKE_INSTALLDIR"} perl_modules="INSERTED_BY_MAKE_PERL_MODULES" osaft_modules=" INSERTED_BY_MAKE_OSAFT_MODULES " files_contrib=" INSERTED_BY_MAKE_CONTRIB " files_install=" INSERTED_BY_MAKE_OSAFT " files_install_cgi=" INSERTED_BY_MAKE_OSAFT_CGI " files_install_doc=" INSERTED_BY_MAKE_OSAFT_DOC " tools_intern=" INSERTED_BY_MAKE_DEVTOOLSINT " tools_extern=" INSERTED_BY_MAKE_DEVTOOLSEXT " tools_modules=" INSERTED_BY_MAKE_DEVMODULES " tools_optional=" INSERTED_BY_MAKE_TOOLS_OPT " tools_other=" INSERTED_BY_MAKE_TOOLS_OTHER " # INSERTED_BY_MAKE } # HARDCODED { # because newer Makefiles may no longer know about them files_ancient=" generate_ciphers_hash openssl_h-to-perl_hash o-saft-README INSTALL-devel.sh .perlcriticrc o-saft_bench contrib/.o-saft.tcl contrib/o-saft.cgi contrib_dir/o-saft.php " # first, dirty hack to make tests in development mode possible # remember the inserted "" to avoid substitutions here [ "INSERTED_""BY_MAKE_OSAFT_SH" = "$osaft_sh" ] && osaft_sh=o-saft [ "INSERTED_""BY_MAKE_OSAFT_PL" = "$osaft_exe" ] && osaft_exe=o-saft.pl [ "INSERTED_""BY_MAKE_OSAFT_GUI" = "$osaft_gui" ] && osaft_gui=o-saft.tcl [ "INSERTED_""BY_MAKE_OSAFT_DOCKER" = "$osaft_dock" ] && osaft_dock=o-saft-docker [ "INSERTED_""BY_MAKE_CONTRIBDIR" = "$contrib_dir" ] && contrib_dir=contrib # some files "not to be installed" are ancient, they are kept here in # $files_not_installed to ensure that outdated content is also handled files_not_installed=" $contrib_dir/o-saft.cgi $contrib_dir/o-saft.php $contrib_dir/Dockerfile.alpine-3.6 $contrib_dir/Dockerfile.wolfssl $contrib_dir/distribution_install.sh $contrib_dir/gen_standalone.sh $contrib_dir/install_perl_modules.pl $contrib_dir/install_openssl.sh $contrib_dir/INSTALL-template.sh " files_develop="o-saft-docker-dev Dockerfile Makefile t/ $contrib_dir/critic.sh" files_info="CHANGES README o-saft.tgz" # HARDCODED } osaft_subdirs=" $contrib_dir Net OSaft/Doc docs " osaft_exerc=".$osaft_exe" osaft_guirc=".$osaft_gui" build_openssl="$contrib_dir/install_openssl.sh" all_exe="$osaft_exe $osaft_gui $osaft_sh $osaft_dock $osaft_one" # checking INSTALL.sh (myself) is pointless, somehow ... _line='----------------------+-----------------' _cols=0 \command -v \tput >/dev/null && _cols=`\tput cols` if [ 0 -lt $_cols ]; then # adapt _line to screen width [ -n "$OSAFT_MAKE" ] && _cols=78 # SEE Make:OSAFT_MAKE [ 51 -gt $_cols ] && _break=1 # see echo_label() while [ 42 -lt $_cols ]; do _line="$_line-" _cols=`expr $_cols - 1` done fi # --------------------------------------------- internal functions echo_head () { echo "" if [ -z "$colour" ]; then echo "$@" echo "#$_line" else \echo "\033[7;37m\033[1;30m$@" \echo "#$_line\033[0m" fi } echo_foot () { if [ -z "$colour" ]; then echo "#$_line" else \echo "\033[7;37m\033[1;30m#$_line\033[0m" fi } echo_label () { perl -le "printf'# %21s%c','$@',0x09" # use perl instead of echo for formatting [ 0 -eq $_break ] && return perl -le 'printf"\n\t"' # use additional line } # for escape sequences, shell's built-in echo must be used echo_yellow () { [ -z "$colour" ] && echo "$@" && return \echo "\033[1;33m$@\033[0m" } echo_green () { [ -z "$colour" ] && echo "$@" && return \echo "\033[1;$colour$@\033[0m" } echo_red () { [ -z "$colour" ] && echo "$@" && return \echo "\033[1;31m$@\033[0m" } check_commands () { for c in $* ; do echo_label "$c" is=`\command -v $c` [ -n "$is" ] && echo_green "$is" || echo_red "missing" done return } copy_file () { src=$1 dst=$2 convert=0 if [ 0 -lt $useenv ]; then ext=${src##*.} file=${src##*/} # ugly hardcode match of extensions and names case "$ext" in awk | cgi | pl | pm | sh | tcl | pod | txt) convert=1 ; ;; esac case "$file" in o-saft) convert=1 ; ;; usage_examples) convert=1 ; ;; o-saft-docker*) convert=1 ; ;; Dockerfile*) convert=1 ; ;; Makefile*) convert=1 ; ;; *_completion_o-saft) convert=1 ; ;; esac fi #dbx# \perl -lane 'if(1==$.){exit 1 if m|^#\!\s*/usr/bin/env |}' "$src" || echo skip $src ... \perl -lane 'if(1==$.){exit 1 if m|^#\!\s*/usr/bin/env |}' "$src" || convert=0 if [ 1 -eq $convert ]; then # only the very first line $. ist changed if [ "$try" = "echo" ]; then echo 'perl -lane "if(1==$.){s|^.*?/([a-zA-Z0-9_.-]+$)|#\!/usr/bin/env $1|;}print;" '"'$src' > '$dst'" return fi # convert only "#! /some/path/tool" \perl -lane 'if(1==$.){s|^.*?/([a-zA-Z0-9_.-]+)\s*$|#\!/usr/bin/env $1|;}print;' \ "$src" > "$dst" || exit 4 if [ 0 -lt $gnuenv ]; then # convert only "#! /some/path/tool arg..." \perl -lane 'if(1==$.){exit 1 if m|^#.*?/([a-zA-Z0-9_.-]+)\s(.*)$|;}' "$src" || \ \perl -lane 'if(1==$.){s|^#.*?/([a-zA-Z0-9_.-]+)\s(.*)$|#\!/usr/bin/env -S $1 $2|;}print;' \ "$src" > "$dst" || exit 4 fi # set proper modes \chmod 555 "$dst" # assuming that it is and should be executable else $try \cp --preserve=all "$src" "$dst" || exit 4 fi return } # --------------------------------------------- arguments and options new_dir= 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; ;; # # # # '-x' | '--x') optx=1; ;; '--cgi') mode=cgi; ;; '--check') mode=check; ;; '--clean') mode=clean; ;; '--install') mode=dest; ;; '--openssl') mode=openssl; ;; '--expect') mode=expected; ;; # alias '--expected') mode=expected; ;; '--checkdev') mode=checkdev; ;; '--check-dev') mode=checkdev; ;; '--force') force=1; ;; '--other') other=1; ;; '--no-colour') colour=""; ;; '--colour') colour="34m"; ;; '--colour-blind') colour="34m"; ;; '--colour-not-blind') colour="32m"; ;; '--no-color') colour=""; ;; # alias '--color') colour="34m"; ;; # alias '--color-blind') colour="34m"; ;; # alias '--color-not-blind') colour="32m"; ;; # alias '--bunt') colour="34m"; ;; # alias '--blind') colour="34m"; ;; # alias '--useenv') useenv=1; ;; '--use-env') useenv=1; ;; # alias '--gnuenv') gnuenv=1; useenv=1; ;; '--gnu-env') gnuenv=1; useenv=1; ;; # alias '--version') \sed -ne '/^#? VERSION/{' -e n -e 's/#?//' -e p -e '}' $0 exit 0 ;; '+VERSION') echo 1.104 ; exit; ;; # for compatibility to $osaft_exe *) new_dir="$1" ; ;; # directory, last one wins esac shift done if [ -n "$new_dir" ]; then inst_directory="$new_dir" [ -z "$mode" ] && mode=dest # no mode given, set default fi clean_directory="$inst_directory/.files_to_be_removed" # set on command line text_dev="did you run »$0 --clean $inst_directory«?" text_alt="file from previous installation, try running »$0 --clean $inst_directory« " # --------------------------------------------- main # ------------------------ expected mode --------- { if [ "$mode" = "expected" ]; then echo "## Expected output (sample) when called like:" echo "## $0 --check /opt/o-saft" \sed -ne '/^#=/s/#=//p' $0 exit 0 fi; # expected mode } if [ '..' = "$dir" ]; then # avoid errors in $0 if called by own make [ "${OSAFT_MAKE:+1}" ] && cd .. && echo "cd .. # due to OSAFT_MAKE" fi # ------------------------- default mode --------- { if [ -z "$mode" ]; then cat << EoUsage # 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 # Optionally call: $0 /path/to/installation/directoy --clean # To check if O-Saft will work, you may use: $0 --check . $0 --check /path/to/installation/directoy # To get a sample of the expected output for --check , use: $0 --expected # To check development requirements, use: $0 --checkdev # In a Docker image, this script may only be called like: $0 --check EoUsage exit 0 fi; # default mode } if [ "$mode" != "check" ]; then if [ -n "$osaft_vm_build" ]; then echo "**ERROR: 001: found 'osaft_vm_build=$osaft_vm_build'" echo_red "**ERROR: 002: inside docker only --check possible; exit" exit 6 fi fi # ------------------------ cgi mode -------------- { if [ "$mode" = "cgi" ]; then echo "# prepare $inst_directory for use in CGI mode" if [ ! -d "$inst_directory" ]; then echo_red "**ERROR: 050: $inst_directory does not exist; exit" [ "$try" = "echo" ] || exit 2 # with --n continue, so we see what would be done fi if [ -d "$clean_directory" ]; then echo_red "**ERROR: 051: $clean_directory exist; CGI installation not yet supported" exit 2 fi for f in $files_install_cgi ; do file=${f##*/} [ -e "$inst_directory/$file" ] && echo -n "# " && echo_yellow "existing $file; ignored" && continue $try \mv $f "$inst_directory/" || echo_red "**ERROR: 052: moving $f failed" done lnk=cgi-bin [ -e "$inst_directory/$lnk" ] && echo -n "# " && echo_yellow "existing $lnk; ignored" && continue $try \ln -s "$inst_directory" $lnk || echo_red "**ERROR: 053: symlink $lnk failed" exit 0 fi; # cgi mode } # ------------------------- openssl mode --------- { if [ "$mode" = "openssl" ]; then echo "# call $build_openssl" [ ! -x "$build_openssl" ] && echo_red "**ERROR: 020: $build_openssl does not exist; exit" && exit 2 [ 0 -lt "$optx" ] && set -x $build_openssl $optn $@ status=$? if [ $status -ne 0 ]; then cat << EoT # $build_openssl uses its default settings. To check the settings, use: # $0 --openssl --n # If other configurations should be used, please use directly: # $build_openssl --help # $build_openssl --n # $build_openssl /path/to/install # $build_openssl /path/to/install --debian --i --m EoT fi exit $status fi; # openssl mode } # ------------------------- clean mode ----------- { if [ "$mode" = "clean" ]; then echo "# cleanup installation in $inst_directory" [ -d "$clean_directory" ] || $try \mkdir "$clean_directory/$f" [ -d "$clean_directory" ] || $try echo_red "**ERROR: 030: $clean_directory does not exist; exit" [ -d "$clean_directory" ] || $try exit 2 # do not move $contrib_dir/ as all examples are right there [ 0 -lt "$optx" ] && set -x cnt=0 files="$files_info $files_ancient $files_develop $files_install_cgi $files_install_doc $files_not_installed" for f in $files ; do #dbx echo "$clean_directory/$f" [ -e "$clean_directory/$f" ] && $try \rm -f "$clean_directory/$f" f="$inst_directory/$f" [ -e "$f" ] && $try \mv "$f" "$clean_directory" && cnt=`expr $cnt + 1` done echo -n "# moved $cnt files to $clean_directory "; echo_green "completed." exit 0 fi; # clean mode } # ------------------------- install mode -------- { if [ "$mode" = "dest" ]; then if [ ! -d "$inst_directory" ]; then echo_red "**ERROR: 040: $inst_directory does not exist; exit" [ "$try" = "echo" ] || exit 2 # with --n continue, so we see what would be done fi files="$files_install $files_install_cgi $files_install_doc $files_contrib $osaft_one" [ 0 -lt "$optx" ] && set -x echo "# remove old files ..." for f in $files ; do f="$inst_directory/$f" if [ -e "$f" ]; then $try \rm -f "$f" || exit 3 fi done echo "# installing ..." for d in $osaft_subdirs ; do $try \mkdir -p "$inst_directory/$d" done for f in $files ; do [ -e "$f" ] || echo_red "**ERROR: 043: missing $f; file ignored" copy_file "$f" "$inst_directory/$f" done if [ -z "$try" ]; then w=$(\command -v wish) if [ -n "$osaft_gui" -a -n "$w" ]; then $try $inst_directory/$osaft_gui --rc > "$inst_directory/$osaft_guirc" \ || echo_red "**ERROR: 041: generating $osaft_guirc failed" else echo -n "# " && echo_yellow "missing wish; $osaft_guirc not installed" fi else echo "$inst_directory/$osaft_gui --rc > $inst_directory/$osaft_guirc" fi if [ $force -eq 1 ]; then echo '# installing RC-FILEs in $HOME ...' for f in $inst_directory/$osaft_exerc $inst_directory/$osaft_exerc ; do $try \cp $f "$HOME/" || echo_red "**ERROR: 042: copying $f failed" done fi echo "# consider calling: $0 --clean $inst_directory" echo -n "# installation in $inst_directory "; echo_green "completed." exit 0 fi; # install mode } # ------------------------- checkdev mode -------- { if [ "$mode" = "checkdev" ]; then echo "" echo "# check system for development usage" echo_head "# check for tools used with/in make targets" check_commands $tools_intern check_commands $tools_extern echo "#" echo "# $text_tool" echo_foot echo_head "# check for Perl modules used with/in make targets" for m in $tools_modules ; do echo_label "$m" # NOTE: -I . used to ensure that local ./Net is found v=`perl -I . -M$m -le 'printf"%8s",$'$m'::VERSION' 2>/dev/null` if [ -n "$v" ]; then echo_green "$v" else echo_red "missing; install with: »cpan $m«" err=`expr $err + 1` fi done echo "#" echo "# $text_prof" echo_foot echo "" [ $other -eq 0 ] && exit 0; # printed with --other only echo_head "# check for other SSL-related tools" check_commands $tools_other echo_foot exit 0 fi; # checkdev mode } # ------------------------- check mode ----------- { if [ "$mode" != "check" ]; then echo_red "**ERROR: 060: unknow mode $mode; exit" exit 5 fi # all following is mode "check" #[ 0 -lt "$optx" ] && set -x # - not used here cnt=0 gui=0 echo_head "# check for O-Saft programs found via environment variable PATH" for p in `echo $PATH|tr ':' ' '` ; do for o in $all_exe wish ; do exe="$p/$o" if [ -e "$exe" ]; then cnt=`expr $cnt + 1` echo_label "$exe" && echo_green "$p" #echo_label "$exe" && echo_yellow "missing" fi [ "$o" != "wish" ] && continue if [ -e "$exe" ]; then gui=`expr $gui + 1` echo_label "wish" && echo_green "$p" fi done done echo "#" echo "# $text_path" [ 0 -eq $cnt -o 0 -eq $gui ] && echo "#" [ 0 -eq $cnt ] && echo_label "$osaft_exe" \ && echo_yellow "not found in PATH, consider adding $inst_directory to PATH" [ 0 -eq $gui ] && echo_label "wish" \ && echo_yellow "not found in PATH, consider installing wish" \ && osaft_gui= [ -e "$osaft_one" ] || ( echo_label "$osaft_one" && echo_yellow "$text_one" ) echo_foot PATH=${inst_directory}:$PATH # ensure that given directory is in PATH [ -n "$optn" ] && echo cd "$inst_directory" cd "$inst_directory" err=0 echo_head "# check installation in $inst_directory" echo "# (warnings are ok if »git clone« will be used for development)" # err=`expr $err + 1` ; # errors not counted here for f in $files_ancient ; do [ -e "$f" ] && echo_label "$f" && echo_yellow "found; $text_alt" done for f in $files_develop $files_info ; do [ -e "$f" ] && echo_label "$f" && echo_yellow "found; $text_dev" done echo_foot echo_head '# check for used O-Saft programs (according $PATH)' for o in $all_exe ; do echo_label "$o" e=`\command -v $o` if [ -n "$e" ] ; then v=`$o +VERSION` txt=`echo "$v $e"|awk '{printf("%8s %s",$1,$2)}'` echo_green "$txt" else err=`expr $err + 1` echo_red "not found" fi done echo_foot echo_head "# check for installed O-Saft resource files" # currently no version check cnt=0 for p in `echo $HOME $PATH|tr ':' ' '` ; do rc="$p/$osaft_exerc" if [ -e "$rc" ]; then cnt=`expr $err + 1` echo_label "$rc" && echo_yellow "will be used when started in $p only" fi done [ 0 -eq $cnt ] && echo_yellow "$rc not found" rc="$HOME/$osaft_guirc" if [ -e "$rc" ]; then v=`awk '/RCSID/{print $3}' $rc | tr -d '{};'` echo_label "$rc" && echo_green "$v" txt="ancient" else txt="missing" fi echo_label "$rc" && echo_yellow "$txt, consider generating: »$osaft_gui --rc > $rc«" echo_foot # from here on, all **WARNINGS (from $osaft_exe) are unimportant and hence # redirected to /dev/null echo_head "# check for installed Perl modules (started in $inst_directory )" for m in $perl_modules $osaft_modules ; do echo_label "$m" # NOTE: -I . used to ensure that local ./Net is found v=`perl -I . -M$m -le 'printf"%8s",$'$m'::VERSION' 2>/dev/null` p=`perl -I . -M$m -le 'my $idx='$m';$idx=~s#::#/#g;printf"%s",$INC{"${idx}.pm"}' 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; ;; 'Time::Local') expect=1.90; ;; 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"; ;; 'Time::Local') # has strange version numbering, needs ugly hack :-(( if [ 1.25 = $v \ -o 1.26 = $v \ -o 1.27 = $v \ -o 1.28 = $v ]; then # 1.25 seems to be newer than 1.230 which is newer than 1.90 c="green"; else c=`echo $expect $v | perl -anle '($e=$F[0])=~s#(\d+)#sprintf"%05d",$1#ge;($v=$F[1])=~s#(\d+)#sprintf"%05d",$1#ge;print (($e > $v) ? "red" : "green")'`; fi ;; *) c=`echo $expect $v | perl -anle '($e=$F[0])=~s#(\d+)#sprintf"%05d",$1#ge;($v=$F[1])=~s#(\d+)#sprintf"%05d",$1#ge;print (($e > $v) ? "red" : "green")'`; ;; # NOTE: need to compare for example: 1.23 > 1.230 # Comparing version strings is tricky, best method would be # to use Perl's Version module. But this script should work # on limited systems too, hence above cumbersome code: # 1. get the version strings on stdin # 2. convert all number parts of the string to fixed 5-digit # format with leading zeros: 1.230 > 00001.000230 # 3. compare converted strings # Perl is clever enough to handle 00001.00023.42000 also esac [ "$c" = "green" ] && echo_green "$v $p" [ "$c" = "red" ] && echo_red "$v $p, $text_old $expect" [ "$c" = "red" ] && err=`expr $err + 1` else text_miss="$text_miss »cpan $m«" echo_red "$text_miss" err=`expr $err + 1` fi done echo_foot echo_head "# check for important Perl modules used by installed O-Saft" for p in `echo $inst_directory $PATH|tr ':' ' '` ; do o="$p/$osaft_exe" [ -e "$o" ] || continue # NOTE: output format is slightly different, 'cause **WARNINGs are printed too echo "# testing $o ...$tab" for m in $perl_modules ; do echo_label "$m" w=`$o --no-warn +version 2>&1 | awk '/(ERROR|WARNING).*'$m'/{print}'` v=`$o --no-warn +version 2>/dev/null | awk '($1=="'$m'"){printf"%8s %s",$2,$3}'` if [ -n "$w" ]; then # ERROR in $w most likely means that $m is not found by # perl, then $v is empty if [ -z "$v" ]; then echo_red "$w" else echo_red "$v" echo_yellow "$w" fi else if [ -z "$v" ]; then echo_yellow "missing?" # probaly due to ERROR else echo_green "$v" fi fi #err=`expr $err + 1` # already counted in previous check done done echo_foot echo_head "# summary of warnings from installed O-Saft (should be empty)" o="$inst_directory/$osaft_exe" if [ -e "$o" ]; then echo "# testing $o in $inst_directory ...$tab" cd "$inst_directory" w=`$o +version 2>&1 | awk '/WARNING:/{print}'` [ -n "$w" ] && echo_yellow "$w" fi echo_foot echo_head "# check for openssl executable in PATH" echo_label "openssl" && echo_green "`which openssl`" "(`openssl version`)" \ || echo_yellow "missing" # TODO: error when openssl older than 0x01000000 has no SNI echo_foot echo_head "# check for openssl executable used by O-Saft" for p in `echo $inst_directory $PATH|tr ':' ' '` ; do o="$p/$osaft_exe" r="$p/.$osaft_exe" if [ -x "$o" ]; then # first call program to check if it is starting properly # if it fails with a status, the corresponding error is printed # and the extraction of the openssl executable is not done ( cd "$p" # ensure that $r is used $o --no-warn +version >/dev/null && \ openssl=`$o --no-warn +version 2>/dev/null | awk '/external executable/{print $NF}' | tr '\012' ' '` && \ echo_label "$o" && echo_green "$openssl" || echo_red "missing" ) fi done echo_foot echo_head "# check for optional tools to view documentation:" check_commands $tools_optional echo_foot echo_head "# check for contributed files (in $inst_directory/$contrib_dir ):" for c in $files_contrib $osaft_one ; do skip=0 for f in $files_not_installed $files_develop ; do [ "$f" = "$c" ] && skip=1 done [ $skip -eq 1 ] && continue _c=${c##*/} echo_label "$_c" #&& echo_green "$openssl" c="$inst_directory/$c" [ -e "$c" ] && echo_green "$c" || echo_yellow "missing $c" #err=`expr $err + 1` # not counted as error done echo_foot echo "" echo -n "# checks$tab" if [ $err -eq 0 ]; then echo_green "passed" else echo_red "failed , $err error(s) detected" [ -z "$new_dir" ] && echo "# default installation directory »$inst_directory« used;" [ -z "$new_dir" ] && echo "# consider using »$0 path/to/directory« " fi # check mode } exit $err O-Saft-22.11.22/contrib/JSON-array.awk000077500000000000000000000047621433765727300171200ustar00rootroot00000000000000#!/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-22.11.22/contrib/JSON-struct.awk000077500000000000000000000062231433765727300173200ustar00rootroot00000000000000#!/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-22.11.22/contrib/XML-attribute.awk000077500000000000000000000017261433765727300176710ustar00rootroot00000000000000#!/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-22.11.22/contrib/XML-value.awk000077500000000000000000000016611433765727300170000ustar00rootroot00000000000000#!/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-22.11.22/contrib/alertscript.cfg000066400000000000000000000104401433765727300175270ustar00rootroot00000000000000PROTOCOL,TLSv13,info,Sehr sicheres Protokoll PROTOCOL,TLSv12,low,Sicheres Protokoll PROTOCOL,TLSv11,medium,Veraltetes Protokoll PROTOCOL,TLSv1\s,high,Veraltetes Protokoll PROTOCOL,SSLv3,critical,Veraltetes Protokoll PROTOCOL,SSLv2,critical,Veraltetes Protokoll CIPHER,^TLS13_AES_256_GCM_SHA384,info,TLS1.3: Sehr sicherer Cipher CIPHER,^TLS13_CHACHA20_POLY1305_SHA256,info,TLS1.3: Sehr sicherer Cipher CIPHER,^TLS13_AES_128_GCM_SHA256,info,TLS1.3: Sehr sicherer Cipher CIPHER,^DHE_RSA_WITH_AES_256_GCM_SHA384,info,Sehr sicherer Cipher CIPHER,^DHE_RSA_WITH_AES_128_GCM_SHA256,info,Sehr sicherer Cipher CIPHER,^ECDHE_RSA_WITH_AES_256_GCM_SHA384,info,Sehr sicherer Cipher CIPHER,^ECDHE_RSA_WITH_AES_128_GCM_SHA256,info,Sehr sicherer Cipher CIPHER,^DHE_RSA_WITH_AES_256_CBC_SHA256,low,Sicherer Cipher TEST CIPHER,^DHE_RSA_WITH_AES_128_CBC_SHA256,low,Sicherer Cipher TEST CIPHER,CAMELLIA,low,Kaum verbreiteter Cipher (CAMELLIA) CIPHER,CBC,medium,Unsichere symmetrische Verschlüsselung (CBC) CIPHER,SEED,high,Altes/kaum verbreiteter Cipher (SEED) CIPHER,SHA$,high, Unsicheres Hashverfahren (SHA) CIPHER,unknown,critical,Bisher undefinierten Cipher gefunden CIPHER,^RSA,critical,Keine PFS (RSA: Kein DHE/ECDHE) CIPHER,^DH_,critical,Keine PFS (DH: Kein DHE/ECDHE) CIPHER,^ECDH_,critical,Keine PFS (ECDH: Kein DHE/ECDHE) CIPHER,RC2,critical,Unsichere symmetrische Verschlüsselung (RC2) CIPHER,RC4,critical,Unsichere symmetrische Verschlüsselung (RC4) CIPHER,_DES,critical,Unsichere symmetrische Verschlüsselung (DES) CIPHER,3DES,high,Unsichere symmetrische Verschlüsselung (3DES) CIPHER,MD5,critical,Unsicheres Hashverfahren (MD5) CIPHER,EXPORT,critical,Unsicherer Cipher (EXPORT) CIPHER,IDEA,critical,Unsicherer Cipher (IDEA) CIPHER,anon,critical,Unsicherer Cipher (anonym) CIPHER,NULL,critical,Unsicherer Cipher (NULL) CIPHER,^SRP,critical,Unsicherer Cipher (SRP) CIPHER,^KRB5,critical,Unsicherer Cipher (KRB5) ORDER,Server\sOrder,info,Server gibt Reihenfolge vor ORDER,No\s.*,critical,Server gibt keine Reihenfolge vor PARAM,(dh, \d\d\d bits),critical,DHPARAM zu klein PARAM,(dh, 1\d\d\d bits),critical,DHPARAM zu klein PARAM,sect163k1,critical,Unsichere Kurve (<256 Bits) PARAM,sect163r1,critical,Unsichere Kurve (<256 Bits) PARAM,sect163r2,critical,Unsichere Kurve (<256 Bits) PARAM,sect193r1,critical,Unsichere Kurve (<256 Bits) PARAM,sect193r2,critical,Unsichere Kurve (<256 Bits) PARAM,sect233k1,high,Unsichere Kurve (<256 Bits) PARAM,sect233r1,high,Unsichere Kurve (<256 Bits) PARAM,sect239k1,high,Unsichere Kurve (<256 Bits) PARAM,sect283k1,high,Unsichere Kurve PARAM,sect283r1,high,Unsichere Kurve PARAM,sect409k1,medium,Ungewöhnliche Kurve PARAM,sect409r1,medium,Ungewöhnliche Kurve PARAM,sect571k1,high,Unsichere Kurve PARAM,sect571r1,high,Unsichere Kurve PARAM,secp160k1,high,Unsichere Kurve (<256 Bits) PARAM,secp160r1,high,Unsichere Kurve (<256 Bits) PARAM,secp160r2,high,Unsichere Kurve (<256 Bits) PARAM,secp192k1,high,Unsichere Kurve (<256 Bits) PARAM,secp192r1,high,Unsichere Kurve (<256 Bits) PARAM,secp224k1,high,Unsichere Kurve (<256 Bits) PARAM,secp224r1,high,Unsichere Kurve (<256 Bits) PARAM,secp256k1,critical,Unsichere Kurve PARAM,secp256r1,info,BSI Empfehlung PARAM,secp384r1,info,BSI Empfehlung PARAM,secp521r1,info,Stärker als BSI Empfehlung aber langsamer PARAM,brainpoolP256r1,info,BSI Empfehlung PARAM,brainpoolP384r1,info,BSI Empfehlung PARAM,brainpoolP512r1,info,BSI Empfehlung PARAM,x25519,info,Sichere Kurve PARAM,x448,info,Sichere Kurve PARAM,eddsa_ed25519,info,Ungewöhnliche Kurve PARAM,eddsa_ed448,info,Ungewöhnliche Kurve PARAM,ffdhe2048,info,BSI Empfehlung (bis 2022) PARAM,ffdhe3072,info,BSI Empfehlung PARAM,ffdhe4096,info,BSI Empfehlung PARAM,ffdhe6144,info,Stärker als BSI Empfehlung aber langsamer PARAM,ffdhe8192,info,Stärker als BSI Empfehlung aber langsamer PARAM,arbitrary_explicit_prime_curves,info,Ungewöhnliche Kurve PARAM,arbitrary_explicit_char2_curves,info,Ungewöhnliche Kurve ALERT,non,info,Keine Aktion nötig ALERT,yes,low,Alert ALERT,yes,medium, Alert ALERT,yes,high,Alert ALERT,yes,critical, Alert LAYER,443,APP,Application LAYER,465,APP,Application LAYER,993,APP,Application LAYER,995,APP,Application LAYER,636,OS,Operating System LAYER,3269,OS,Operating System LAYER,3389,OS,Operating System LAYER,50000,OS,Operating System O-Saft-22.11.22/contrib/alertscript.pl000077500000000000000000000464611433765727300174220ustar00rootroot00000000000000#!/usr/bin/perl -w # Filename: alertscript.pl #!############################################################################# #!# This script is part of the OWASP-Project 'o-saft' #!# It reads output of ‘CheckAllCiphers.pl’ or ‘osaft.pl’ in csv-format and #!# rates all findings about TLS protocols, ciphers and TLS parameters #!# according the configuration in ‘alertscript.cfg’ #!# #!#---------------------------------------------------------------------------- #!# Developed as part of a bachelor thesis by Benedikt Gabler #!# “Identifikation und Adressierung schwacher TLS-Einstellungen #!# in lokalen Unternehmensnetzwerken“ #!# (Identification and Addressing of weak TLS Configurations #!# in Corporate Networks) #!# #!# Hochschule für angewandte Wissenschaften München #!# (University of Applied Sciences, Munich, Germany) #!# https://www.cs.hm.edu #!# Supervising Professor: Prof. Dr. Peter Trapp #!# In cooperation with Torsten Gigler and Florian Bockamp, BayernLB #!#---------------------------------------------------------------------------- #!# 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. #!############################################################################# use strict; use warnings; use Carp; #replaces warn and die my $cfgfile = "alertscript.cfg"; my $csvfile = "report.csv"; my $alertfile = "alertfile.txt"; my $line = ""; my $debug = 0; #0: kein debug - 1: debug - 2: big debug my $cfg_tokens = ["CIPHER","CRIT"]; my $scan_token; my @prio_array = ("CRITICAL", "HIGH", "MEDIUM", "LOW", "INFO"); my @token_array = ("PROTOCOL", "ORDER", "CIPHER", "PARAM"); my %cfg_hash = (); my %result_hash = (); my ($token, $regex, $order, $value, $ipadress, $port, $prot, $cipher2, $param, $descript) = ""; my $me = $0; $me =~ s#.*(?:/|\\)##; sub printhelp { print << "EoT"; NAME $me - simple rating of protocols, ciphers and parameters based on the output of checkAllCiphers.pl (is part of osaft) A configuation file defines the rating and the responsables by the port. This script generates an alert file that may be used to generate tickets in a workflow application. Consider to use different config files according the protection needs of your applications and how exposed these applications are. SYNOPSIS $me [OPTIONS] OPTIONS --help this help (also: --h, all options may use '-' or '--' as prefix) --cfg=CFGFILE change the name of the configfile (default is 'alertscript.cfg') --cfgfile=CFGFILE dito --csv=CSVFILE change the name of the inputfile (default is 'report.csv') --csvfile=CSVFILE dito (also: --in=..., --infile=..., --inputfile=...) --alert=ALERTFILE change the name of the outputfile (default is 'alertfile.txt') --alertfile=ALERTFILE dito (also: --out=..., --outfile=..., --outputfile=...) --debug=LEVEL set debug level (default is 0: off; 1: nomal, 2: huge) --d=LEVEL dito (also --d => --d=1, --d --d => --d=2) EoT return; } # printhelp #Subroutine für das Speichern der Alerts #Der Subroutine werden 8 Parameter übergebenen #Ip-Adresse, Port, Priorität, Protokoll, Cipher-Suite, Grund des Alerts, Wert und die Description sub store_alert ($$$$$$$$) { my ($ipadress, $port, $prio, $prot, $cipher, $reason, $value, $descript) = @_; my @layer_array = ("OS", "APP"); my $layer = $layer_array[1]; #Default = "APP" print "ALERT [$ipadress, $port, $prio, $prot, $cipher, $reason, $value, $descript]" if ($debug); SEARCHLAYER: foreach my $layer_key (@layer_array) { foreach (@{$cfg_hash{LAYER}{$layer_key}{regex}}) { my $regex = $_ ; print "$regex: " if ($debug); if ($port =~ /$regex/) { print "LAYER: $layer_key\n" if ($debug); $layer = $layer_key; last SEARCHLAYER; } } } push (@{$result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{value}},$value); push (@{$result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{descript}},$descript); print "STORE INTO:\$result_hash\[$ipadress\]\[$layer\]\[$port\]\[$prio\]\[$reason\]\[$prot\]\[$cipher\]\[value\]: $value\n" if ($debug); print "STORE INTO:\$result_hash\[$ipadress\]\[$layer\]\[$port\]\[$prio\]\[$reason\]\[$prot\]\[$cipher\]\[descript\]: $descript\n" if ($debug); } #Subroutine zur Ausgabe der im Hash gespeicherten Werte aus der store_alert Subroutine #Verbose Ausgabe sub print_all_alerts() { my $count = 0; print "PRINT ALL ALERTS/AUSGABE ALLER ALERTS:\n"; foreach my $ipadress (sort keys %result_hash) { print "IP: $ipadress\n"; foreach my $layer (sort {lc $a cmp lc $b} keys %{$result_hash{$ipadress}}) { print "LAYER: $layer\n"; foreach my $port (sort {$a <=> $b} keys %{$result_hash{$ipadress}{$layer}}) { print "PORT: $port\n"; foreach my $prio (@prio_array) { print "PRIO: $prio\n"; foreach my $reason (@token_array) { print "REASON: $reason\n"; foreach my $prot (sort {lc $a cmp lc $b} keys %{$result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}}) { print "PROTOKOLL: $prot\n"; foreach my $cipher (sort {lc $a cmp lc $b} keys %{$result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}}) { print "CIPHER: $cipher\n"; if (defined $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{value}) { $count = @{ $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{value}}; print "COUNT = $count\n"; for(my $j = 0; $j < $count; $j++) { print "\$result_hash\[$ipadress\]\[$layer\]\[$port\]\[$prio\]\[$reason\]\[$prot\]\[$cipher\]\[value\]: $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{value}[$j]\n"; print "\$result_hash\[$ipadress\]\[$layer\]\[$port\]\[$prio\]\[$reason\]\[$prot\]\[$cipher\]\[descript\]: $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{descript}[$j]\n"; } } } } } } } } print "\n"; } } #Subroutine mit sortierten Alerts sub print_sorted_alerts() { my $descript_sep = " | "; my $count = 0; my $sep_counter = 0; my $alert = 0; print "AUSGABE ALERTS:\n" if ($debug); foreach my $ipadress (sort keys %result_hash) { print "IP: $ipadress\n" if ($debug); foreach my $layer (sort {lc $a cmp lc $b} keys %{$result_hash{$ipadress}}) { #Sortierung nach Werten print "LAYER: $layer\n" if ($debug); foreach my $port (sort {$a <=> $b} keys %{$result_hash{$ipadress}{$layer}}) { #Sortierung nach Werten print "PORT: $port\n" if ($debug); foreach my $prio (@prio_array) { print "PRIO: $prio\n" if ($debug); $alert = ($cfg_hash{ALERT}{$prio}{regex}[0] eq "yes"); print "Alert: $alert (0: no - 1: yes)\n" if ($debug); foreach my $reason (@token_array) { print "REASON: $reason\n" if ($debug); PROTOCOL: foreach my $prot (sort {lc $a cmp lc $b} keys %{$result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}}) { print "PROTOKOLL: $prot\n" if ($debug); foreach my $cipher (sort {lc $a cmp lc $b} keys %{$result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}}) { print "CIPHER: $cipher\n" if ($debug); if (defined $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{descript}) { $count = @{ $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{descript}}; print "COUNT = $count\n" if ($debug); print ALERTFILE "$ipadress, $layer, $port, $prio, $reason, $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{value}[0], " if ($alert); if ($reason eq "PARAM") { #Parameter je Cipher melden print ALERTFILE "Cipher: $cipher: " if ($alert); } for(my $j = 0; $j < $count; $j++) { print "\$result_hash\[$ipadress\]\[$layer\]\[$port\]\[$prio\]\[$reason\]\[$prot\]\[$cipher\]\[value\]: $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{value}[$j]\n" if ($debug); print "\$result_hash\[$ipadress\]\[$layer\]\[$port\]\[$prio\]\[$reason\]\[$prot\]\[$cipher\]\[descript\]: $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{descript}[$j]\n" if ($debug); print ALERTFILE "$descript_sep" if (($j>0) and ($alert)); print ALERTFILE "$result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$prot}{$cipher}{descript}[$j]" if ($alert); } #Gibt alle Protokolle mit benutztem Cipher aus if (($reason eq "CIPHER") or ($reason eq "ORDER") or ($reason eq "PARAM")) { print ALERTFILE " [used with protocols: " if ($alert); $sep_counter = 0; for my $used_prot (sort {lc $a cmp lc $b} keys %{$result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}}) { if (defined $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$used_prot}{$cipher}{value}) { print ALERTFILE "$descript_sep" if (($sep_counter > 0) and ($alert)); print ALERTFILE "$used_prot" if ($alert); $sep_counter++; $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$used_prot}{$cipher}{value} = undef; $result_hash{$ipadress}{$layer}{$port}{$prio}{$reason}{$used_prot}{$cipher}{descript} = undef; } } print ALERTFILE "]" if ($alert); } print ALERTFILE "\n" if ($alert); last PROTOCOL if ($reason eq "ORDER"); #Letzter Cipher (Cipher überspringen wenn Ordnung nicht durch Server vorgegeben wird) last if ($reason eq "PROTOCOL"); } } } } } } } print "\n" if ($debug); } } ### main routine ####################################################################################################### # scan options and arguments my $arg = ""; while ($#ARGV >= 0) { $arg = shift @ARGV; if ($arg =~ /^-?-h(?:elp)?$/i) { printhelp(); exit 0; } # allow -h -help --h --help if ($arg =~ /^-?-cfg(?:file)?=(.*)$/i) { $cfgfile = $1; next; } # cfg=CFGFILE_NAME if ($arg =~ /^-?-csv(?:file)?=(.*)$/i) { $csvfile = $1; next; } # csv=CSVFILE_NAME if ($arg =~ /^-?-in(?:put)?(?:file)?=(.*)$/i) { $csvfile = $1; next; } # in=CSVFILE_NAME if ($arg =~ /^-?-alert(?:file)?=(.*)$/i) { $alertfile = $1; next; } # alert=ALERTFILE_NAME if ($arg =~ /^-?-out(?:put)?(?:file)?=(.*)$/i) { $alertfile = $1; next; } # out=ALERTFILE_NAME if ($arg =~ /^-?-d(?:ebug)?=(\d)$/i) { $debug = $1; next; } # d=DEBUGLEVEL if ($arg =~ /^-?-d(?:ebug)?$/i) { $debug += 1; next; } # d+=1 carp ("**WARNING: unknown command or option '$arg' ignored. Try '$me --help' to get more information!"); exit 0; } # while open (DATEI, $cfgfile) or die $!; open (ALERTFILE,'>', $alertfile) or die $!; print "$me:\nRead config file '$cfgfile'\n"; while ($line = ) { #Zeilenweises einlesen der Bewertungsdatei-Einträge chomp($line); #Newline am Ende löschen if ($line =~ /^\s*(?:#.*)?$/) { #Leerzeilen und Kommentarzeilen überspringen next; } elsif ($line =~ /^(.*?)\s*,\s*((?:dh,|.)*?)\s*,\s*(.*?)\s*,\s*(.*?)(?:\s*#.*)?\r?$/) { #zeile parsen mit regulären ausdrücken. Es werden nur Zeilen verarbeitet, die mit drei Kommas getrennt werden und in dieser Form vorkommen. $token = $1; #Token kann ALERT/CIPHER/PROTOCOL/PARAM/LAYER sein. $regex = $2; #regex kann entweder ein Cipherstring/DHParameter/Protokollbezeichnung/einzelnes Verfahren/Port/Alertinfo sein. $value = $3; #value kann Kritikalität (info/low/medium/high/critical) oder Layer (APP/OS) sein. $descript = $4; #Beschreibung der Zeile. print ">$1<, >$2<, >$3<, >$4<\n" if ($debug > 1); $token = uc($token); #Umwandeln der Zeichen des Strings in Großbuchstaben. $value = uc($value); #Umwandeln der Zeichen des Strings in Großbuchstaben. push (@{$cfg_hash{$token}{$value}{regex}}, $regex); #configwerte in 3-dim hash für token und value abspeichern push (@{$cfg_hash{$token}{$value}{descript}}, $descript); } else { warn(">>> Error in configfile: $line"); #Warnung wird ausgegeben, wenn die Zeile nicht dem definierten Muster entspricht. } } close (DATEI); if ($debug) { print "Config start\n\n"; foreach my $token_key (sort keys %cfg_hash) { foreach my $prio_key (keys %{ $cfg_hash{ $token_key} }) { print "$token_key, $prio_key: ["; for (my $_i=0; $_i < (@{$cfg_hash{$token_key}{$prio_key}{regex}}); $_i++) { print ", " if ($_i > 0); print $cfg_hash{$token_key}{$prio_key}{regex}[$_i] . ": " . $cfg_hash{$token_key}{$prio_key}{descript}[$_i]; } print "]\n"; } } print "Config end\n\n"; } print "Analyze '$csvfile'\n"; open (DATEI2, $csvfile) or die $!; while ($line = ) { chomp($line); #Newline am Ende löschen if ($line =~ /^(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*(?:,\s*(.*?)\s*)?\r?$/) { # =~ /.../=REGEX, ^=Zeilenanfang, ()=gefundener Wert in Variable $1-... speichern, .=beliebiges Zeichen, *=0...x mal, *?=0...x mal nicht gierig (nur bis zum komma inkl optionalen leerzeichen), \s=leerzeichen (space/tab), das komma vor $9 ist optional, \r=Wagenrücklauf=carriage return (Windows) $=Zeilenende $ipadress = $1; $port = $2; $prot = $3; $order = $5; $cipher2 = $8; if (defined $9) { $param = $9; } else { $param = ""; } $cipher2 = uc($cipher2); print ">$1<, >$2<, >$3<, >$4<, >$5<, >$6<, >$7<, >$cipher2<, >$param<\n" if ($debug > 1); #Auswertung der Testergebnisse foreach my $token_key (@token_array) { #Schleife prüft das Ergebnis nach PROTOCOL, CIPHER und PARAM vergleiche @token_array foreach my $prio_key (@prio_array) { print "$token_key, $prio_key: [" if ($debug); my $i = 0; foreach (@{ $cfg_hash{$token_key}{$prio_key}{regex}}) { my $regex = $_ ; my $descript = $cfg_hash{$token_key}{$prio_key}{descript}[$i]; $i++; print "$regex: " if ($debug); if ($token_key eq "PROTOCOL") { #Regex je nach Tokentyp mit der passenden Spalte vergleichen if ($prot =~ /$regex/) { print "ALERT $prot $prio_key $ipadress $port $descript\n" if ($debug); store_alert($ipadress, $port, $prio_key, $prot, $cipher2, $token_key, $prot, $descript); } } elsif ($token_key eq "ORDER") { if ($order =~ /$regex/) { print "ALERT $order $prio_key $ipadress $port $descript\n" if ($debug); store_alert($ipadress, $port, $prio_key, $prot, $cipher2, $token_key, $order, $descript); } } elsif ($token_key eq "CIPHER") { if ($cipher2 =~ /$regex/) { print "ALERT $cipher2 $prio_key $ipadress $port $descript\n" if ($debug); store_alert($ipadress, $port, $prio_key, $prot, $cipher2, $token_key, $cipher2, $descript); } } elsif ($token_key eq "PARAM") { if ($param =~ /$regex/) { print "ALERT $param $prio_key $ipadress $port $descript\n" if ($debug); store_alert($ipadress, $port, $prio_key, $prot, $cipher2, $token_key, $param, $descript); } } } print "]\n" if ($debug); } } print "\n" if ($debug); } } close (DATEI2); print "Analyze end\n" if ($debug); print_all_alerts() if ($debug >1); print_sorted_alerts(); close (ALERTFILE); print "Alerts written in '$alertfile'\n"; O-Saft-22.11.22/contrib/bash_completion_o-saft000077500000000000000000000036021433765727300210610ustar00rootroot00000000000000#!/bin/bash #? NAME #? bash_completion_o-saft - bash completion function for o-saft, o-saft.pl, o-saft.tcl #? #? 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 #? #? 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}'` _y_gui=`o-saft.tcl --help=opts |awk '/^[+-]/{print $1}'` _m_help=`make e-ALL.help |tr -s ' ' '\\012'` _m_test=`make e-ALL.tests |tr -s ' ' '\\012'` _m_warn=`make e-ALL.tests |tr -s ' ' '\\012'` _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 } _o-gui() { local curr_arg; curr_arg=${COMP_WORDS[COMP_CWORD]} COMPREPLY=( $(compgen -W "$_y_gui" -- $curr_arg ) ) } _o-make() { local curr_arg; curr_arg=${COMP_WORDS[COMP_CWORD]} case "$curr_arg" in help*) COMPREPLY=( $(compgen -W "$_m_help" -- $curr_arg ) ); ;; test*) COMPREPLY=( $(compgen -W "$_m_test" -- $curr_arg ) ); ;; warn*) COMPREPLY=( $(compgen -W "$_m_warn" -- $curr_arg ) ); ;; esac } complete -F _o-saft o-saft complete -F _o-saft o-saft.pl complete -F _o-gui o-saft.tcl complete -F _o-make make O-Saft-22.11.22/contrib/bunt.pl000077500000000000000000000307671433765727300160400ustar00rootroot00000000000000#!/usr/bin/perl #? #? NAME #? $0 - postprocess to colourise output of o-saft.pl #? #? SYNOPSIS #? o-saft.pl | $0 [OPTIONS] #? #? DESCRIPTION #? That's it. #? #? OPTIONS #? --h got it #? --test simple self-testing #? --line colourise complete line #? --word colourise special words #? --blind use blue instead of green #? --purple use purple instead of yellow #? purple may be better readable on light backgrounds #? --italic colourise 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 #? Uses tput or stty to detect current terminal with. If both fail, 80 is #? used as default. # # 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.17 21/04/23 11:12:32 #? #? AUTHOR #? 08-jan-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- use strict; use warnings; use charnames qw( :full ); our ($VERSION) = -1; # dummy assignment to keep `perlcritic -s ...' silent ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers) ## no critic qw(RegularExpressions::RequireExtendedFormatting) 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: colourise 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 # 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/) { # try with tput, if it fails try with stty $cols = qx(\\tput cols 2>/dev/null) || undef; # quick&dirty if (not defined $cols) { # tput failed or missing $cols = qx(\\stty size 2>/dev/null) || $_LEN; # default if stty fails $cols =~ s/^[^ ]* //; # stty returns: 23 42 ; extract 42 } } 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 ) { ## no critic qw(RegularExpressions::RequireExtendedFormatting) 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 author's 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 = <>) { ## no critic qw(RegularExpressions::RequireExtendedFormatting) $_ = $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.*MEDIUM/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; }; /\s+(?:C|D|WEAK)$/i && do { print red( "$line"); next; }; /\s+(?:C|D|LOW)$/i && do { print red( "$line"); next; }; /\s+(?:B|MEDIUM)$/i && do { print brown("$line"); next; }; /\s+(?:A|HIGH)$/i && do { print green("$line"); next; }; /\s+(?:-[?]-)$/i && do { print cyan( "$line"); next; }; print "$line"; next; } if ($mode eq "word") { /(?:A|B|C|D|-[?]-|LOW|WEAK|MEDIUM|HIGH)$/i && do { # match cipher line with risk (must be last word) s/(\sC|D|WEAK)$/ red( $1);/ie; s/(\sC|D|LOW)$/ red( $1);/ie; s/(\sB|MEDIUM)$/ brown($1);/ie; s/(\sA|HIGH)$/ green($1);/ie; s/(\s-[?]-)$/ cyan ($1);/ie; print "$_"; next; }; s/^([[a-zA-Z0-9.-]+:[0-9]{1,5})/cyan($1);/ie; # leading host:port s/(#\[(?:[^\]]*)])/ cyan( $1);/ie; # 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-22.11.22/contrib/bunt.sh000077500000000000000000000252111433765727300160230ustar00rootroot00000000000000#! /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.8 21/01/14 01:16:56 #? #? AUTHOR #? 08-jan-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- 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-22.11.22/contrib/cipher_check.sh000077500000000000000000000115731433765727300174700ustar00rootroot00000000000000#!/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-22.11.22/contrib/critic.sh000077500000000000000000000161141433765727300163320ustar00rootroot00000000000000#!/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.7 22/04/20 10:12:47 #? #? 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 \ OSaft/Ciphers.pm OSaft/Doc/Data.pm OSaft/error_handler.pm \ " _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-22.11.22/contrib/distribution_install.sh000077500000000000000000000016751433765727300213300ustar00rootroot00000000000000#!/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-22.11.22/contrib/filter_examples000066400000000000000000000142231433765727300176230ustar00rootroot00000000000000#!/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-22.11.22/contrib/fish_completion_o-saft000077500000000000000000000045101433765727300210740ustar00rootroot00000000000000#!/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-22.11.22/contrib/gen_standalone.sh000077500000000000000000000201011433765727300200250ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - generate o-saft_standalone.pl #? #? SYNOPSIS #? $0 #? $0 [OPTIONS] [output-file] #? #? 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. #? Prints on STDOUT if no [output-file] was specified. #? #? NOTE: this will not generate a bulletproof stand-alone script! #? #? VERSION #? @(#) 2.4 22/11/13 22:24:11 #? #? AUTHOR #? 02-apr-16 Achim Hoffmann #? # ----------------------------------------------------------------------------- dst=/dev/stdout # default STDOUT src=o-saft.pl ; [ -f $src ] || src=../$src 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 ; ;; *) dst="$1"; ;; esac shift done if [ ! -e "$src" ]; then \echo "**ERROR: '$src' does not exist; exit" [ "echo" = "$try" ] || exit 2 fi _o_saft=" osaft.pm OSaft/Text.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/Ciphers.pm OSaft/Data.pm " o_saft="" for f in $_o_saft ; do [ -f $f ] || f=../$f # quick&dirty if called in sub-directory o_saft="$o_saft $f" done _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 \ osaft_doc="" for f in $_osaft_doc ; do [ -f $f ] || f=../$f # quick&dirty if called in sub-directory osaft_doc="$osaft_doc $f" done 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 if [ "/dev/stdout" = "$dst" ]; then \echo "# generate file standalone.pl ..." else \echo "# generate $dst ..." fi \echo "" fi [ "/dev/stdout" != "$dst" ] && $try \rm -rf $dst [ "$try" = "echo" ] && dst=/dev/stdout # general workflow and hints how to include: # # 1. extract from o-saft.pl anything before line ## PACKAGES # # 2. add o-saft.pl POD # # 3. add $osaft_standalone # # 4. include osaft.pm and OSaft/Ciphers.pm without brackets and no "package" keyword # # .. include text from module file enclosed in ## PACKAGE scope from all modules # # 5. add rest of o-saft.pl # # 6. include cipher definitions from OSaft/Ciphers.pm # # 7. patch "standalone specials" # # 8. 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 'our $osaft_standalone = 1;' \echo '' \echo "" \echo "use Encode;" \echo "use IO::Socket::SSL;" \echo "use Net::DNS;" \echo "use Time::Local;" \echo "" # 4. # our modules without brackets f=osaft.pm ; [ -f $f ] || f=../$f \echo "# { # $f" #$try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE })) and not m(package osaft;)' $f $try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE })) and not m(our .VERSION); ' $f \ | sed -e 's/our %ciphers /my %ciphers /' \echo "# } # $f" \echo "" f=OSaft/Text.pm ; [ -f $f ] || f=../$f \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE }))' $f \echo "} # $f" \echo "" f=OSaft/Ciphers.pm ; [ -f $f ] || f=../$f \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE }))' $f \echo "} # $f" \echo "" f=OSaft/Data.pm ; [ -f $f ] || f=../$f \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE }))' $f \echo "} # $f" \echo "" # ... ## TODO: OSaft/Doc/Data.pm f=OSaft/Doc/Data.pm ; [ -f $f ] || f=../$f \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 ; [ -f $f ] || f=../$f \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE }))' $f #$try \cat $f \echo "} # $f" \echo "" ## TODO: o-saft-man fails to include properly f=o-saft-man.pm ; [ -f $f ] || f=../$f \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 "" ## TODO: o-saft-dbx.pm still with errors f=o-saft-dbx.pm ; [ -f $f ] || f=../$f \echo "{ # $f" $try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE }))' $f \echo "} # $f" \echo "" f=OSaft/error_handler.pm ; [ -f $f ] || f=../$f \echo "{ # $f" #$try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE }))' $f $try \cat $f \echo "} # $f" \echo "" \echo "package main;" f=Net/SSLinfo.pm ; [ -f $f ] || f=../$f \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" \echo "no strict 'subs';" $try \perl -ne 'print if (m(## PACKAGE [{])..m(## PACKAGE }))' $f \ | \egrep -v '^use (osaft|OSaft::error_handler)' \echo "} # $f" \echo "package main;" \echo "" # 5. $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)' # 6. f=OSaft/Ciphers.pm ; [ -f $f ] || f=../$f \echo "## $f DATA .. END" $try \perl -ne 'print if (m(## CIPHERS [{])..m(## CIPHERS }))' $f #$try \perl -ne 'print if (m(^__DATA__)..m(__END__))' $f \echo "" \echo "package main;" # 7. # to avoid duplicate definitions, "our @EXPORT" is replace by "my @EXPORT" # TODO: "use strict;" removed, as it complains about undef %STR ) \ | $try \perl -pe '/^=head1 (NAME|Annotation)/ && do{print "=head1 "."_"x77 ."\n\n";};' \ | $try \sed -e 's/#\s*OSAFT_STANDALONE\s*//' \ -e 's/^use strict;//' \ -e 's/$STR/$OSaft::Text::STR/' \ -e '/^use osaft/d' \ -e 's/^use OSaft::.*/#-# &/' \ -e 's/^\s*our\(\s*@EXPORT\s*=\)/my \1/g' \ -e '/^ sub .*{}\s*$/s/^ /#/' \ > $dst # -e 's/^\(use OSaft::Text\)/# &/' \ # -e 's/our %cipher/our %::cipher/g' # 8. ##TODO: lsopt= # tweak output if used from make [ -z "$OSAFT_MAKE" ] && lsopt="-la" [ "/dev/stdout" != "$dst" ] && $try \chmod 555 $dst [ $info -eq 0 ] && exit [ "/dev/stdout" != "$dst" ] && $try \ls $lsopt $dst # Writing on /dev/stdout is scary on some systems (i.e Linux). If code above # was written on /dev/stdout, the buffer may not yet flushed. Then following # echo and cat commands, which write on the tty's STDOUT, my overwrite what # is already there. Some kind of race condition ... # As the shell has no build-in posibility to flush STDOUT, following output # is written to /dev/stdout directly to avoid overwriting, ugly but seems to # work ... cat << EoDescription >> /dev/stdout # $dst generated The generated stand-alone script misses following functionality: * Commands +cipherall +cipher-dh * Options --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 ... Note that --help and --help=* will only work if following files exist or are located in the same directory as $dst : $osaft_doc "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-22.11.22/contrib/install_openssl.sh000077500000000000000000000531141433765727300202670ustar00rootroot00000000000000#!/bin/sh #? #? NAME #? $0 - build and install special openssl and Net::SSLeay #? #? SYNOPSIS #? $0 [OPTIONS] #? #? OPTIONS #? --h - nice option #? --i - ignore failed preconditions; continue always #? --m - install all required Perl modules also #? --n - do not execute, just show preconditions and where to install #? --debian - install required debian packages first #? --list - list required packages, modules, etc. #? #? DESCRIPTION #? Build special openssl based on Peter Mosman's openssl. Additionally #? build Perl module Net::SSLeay based on previous build openssl. #? Modifies ./.o-saft.pl (keeping existing one in .o-saft.pl-orig). #? #? This script is intended to be executed in the installation directory #? of O-Saft. #? #? 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. #? #? DETAILS #? #? openssl #? SSLv2, SSLv3 and all possible ciphers are enabled. All depricated and #? known insecure extensions are enabled. #? Installs build in specified directory; default: /usr/local/openssl . #? #? Net::SSLeay #? Building Net::SSLeay is based on previously configured and compiled #? special openssl. #? Installs build in specified directory; default: /usr/local/lib . #? #? Other Perl modules #? Additional Perl modules will be install with option --m . #? These Perl modules are installed using "perl -MCPAN -e "install ". #? Installs build in specified directory; default: /usr/local/share . #? #? 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 ... #? ::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 /etc/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 #? Net::SSLeay:: #? 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 #? number of supported ciphers 201 #? openssl supported SSL versions SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 #? o-saft.pl known SSL versions SSLv2 SSLv3 TLSv1 TLSv11 TLSv12 TLSv13 DTLSv09 DTLSv1 DTLSv11 DTLSv12 DTLSv13 #? IO::Socket::SSL 2.066 /usr/local/share/perl/5.28.1/IO/Socket/SSL.pm #? Net::SSLeay 1.85 /usr/local/lib/x86_64-linux-gnu/perl/5.28.1/Net/SSLeay.pm #? ------------------------------------------------------------------------- #? #? This script does no cleanup if any building of Perl modules, openssl #? or Net::SSLeay fails. Sucessfully build parts are not removed. There #? may be garbage in BUILD_DIR and/or the CPAN directory. #? Errors while building the additional modules are silently ignored. #? Failing to build openssl or Net::SSLeay will exit the script. #? #? PRECONDITIONS #? The 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 libsctp zlib #? Hints about missing packages and libraries are given if started with #? option --n . #? Assumes that ca-certificates are install in /etc/ssl/certs/ . #? #? 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. #? These variables can be used to: #? * adapt the sources and their checksums to be used #? * the directory where to find O-Saft #? #? 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 #? Full path to installation directory 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.30. Dockerfile's # syntax, which does not work in a shell, is deactivated with aliases. # This code is scopend with # # Dockerfile 1.30 { # ... # # Dockerfile 1.30 } # Please backport any changes in scope to Dockerfile. # # Each Perl modul to be installed may have its own prerequisites. These # are mainly described in the README file. This script does not (yet) # check or fullfil these prerequisites. # Known prerequisites (according tools used 7/2019): # * Net::DNS # Digest::HMAC, Digest::MD5, Digest::SHA, File::Spec, MIME::Base64, # Time::Local, Test::More, Digest::BubbleBabble, Net::DNS::SEC, # Net::LibIDN2, IO::Socket, IO::Socket::IP # * IO::Socket::SSL # Net::SSLeay 1.46 or newer #? #? EXAMPLES #? Simple build with defaults: #? $0 #? Build with installing packages and ignoring check errors: #? $0 --debian -i #? Build including required Perl modules: #? $0 --m #? VERSION #? @(#) 1.39 21/11/11 01:13:11 #? #? AUTHOR #? 18-jun-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- dir=`pwd` # TODO: on error or interrupt list remaining files and dirs # 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 # set variables used in the code copied from Dockerfile to build openssl 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 exe_mandatory=" gcc make " # packages required for building openssl debian_packages=" libidn11-dev libidn2-0-dev libgmp-dev libzip-dev libsctp-dev libkrb5-dev " lib_packages="$debian_packages" # following not yet used debian_packages_perl="libnet-dns-perl libnet-libidn-perl libmozilla-ca-perl" alpine_packages_perl="perl-net-dns perl-net-libidn perl-mozilla-ca" # Perl module names perl_io_socket="IO::Socket::SSL" perl_modules=" Module::Build Net::LibIDN Net::LibIDN2 Net::DNS Mozilla::CA " # dynamically compute list of Perl modules to be installed; see below # NOTE: Net::SSLeay must always be istalled after building special openssl install_modules=" " # TODO: list of installed files and dirs; not yet used uninstall_data=" /usr/local/lib/x86_64-linux-gnu/perl/Net/SSLeay /usr/local/share/man/man3/IO::Socket::SSL* /usr/local/share/man/man3/Net::SSLeay* $OPENSSL_DIR $BUILD_DIR " echo_head () { echo "" echo "$@" } # echo_head list_data () { echo '# mandatory packages:' echo "#\t$exe_mandatory" echo "\t$lib_packages" echo '# openssl:' echo "#\t$OSAFT_VM_SRC_OPENSSL" echo '# Perl modules:' echo "#\t$OSAFT_VM_SRC_SSLEAY" echo "\t$perl_modules" echo "\t$perl_io_socket" echo "" return } # list_data apt_install_debian () { err=0 echo_head '### install debian packages ...' for pkg in $exe_mandatory $debian_packages ; do apt install --no-install-recommends $pkg done echo "# installed packages: $exe_mandatory $lib_packages" return } # apt_install_debian mcpan_install () { #? install module with MCPAN _mod=$1 err=0 txt="" echo "### install perl modul $_mod ..." perl -MCPAN -e "install $_mod" || txt="**ERROR: installation failed for $_mod" [ -n "$txt" ] && return 1 # FIXME: perl -MCPAN does not return proper error codes; need # to parse output, grrr return 0 } # mcpan_modules mcpan_modules () { #? install modules (with --m only) err=0 echo_head '### install Perl modules ...' for mod in $install_modules ; do txt="" [ "Module::Build" = $mod ] && continue # cannot be installed, -MCPAN does it automatically if needed mcpan_install $mod err=$? done [ 0 -ne $err ] && echo "**ERROR: modules installation failed" return } # mcpan_modules check_mandatory () { err=0 echo_head "# required mandatory tools:" for exe in $exe_mandatory ; do txt="" echo -n " $exe " exe=$(\command -v $exe) if [ -n "$exe" ]; then echo "\tOK $exe" else echo "\tmissing" miss="$miss $exe" err=1 fi done [ 1 -eq $err ] && echo "**WARNING: development tools need to be installed" return } # check_mandatory check_modules () { err=0 echo_head "# required Perl modules (installed with --m option):" for mod in $perl_modules ; do txt="" echo -n " $mod " perl -M$mod -le "print ${mod}::Version" || txt="**ERROR: $mod missing" if [ -z "$txt" ]; then # found: print OK followed by directory of used module loc=`perl -M$mod -le 'my $idx='$mod'; $idx=~s#::#/#g; print $INC{"${idx}.pm"}'` txt="\tOK $loc" else # not found: add to modules to be installed install_modules="$install_modules $mod" err=1 fi echo "$txt" done [ 1 -eq $err ] && miss="$miss modules," return } # check_modules check_libraries () { lib=0 echo_head "# required libraries:" txt=`find /usr/lib -name libidn\.\*` [ -z "$txt" ] && txt="**ERROR: libidn.so missing, consider installing libidn11-dev" && miss="$miss libidn," echo " libidn.so $txt" for pack in $lib_packages ; do ok=1 txt=`find /usr -name $pack` [ -z "$txt" ] && txt="**ERROR: $pack missing, consider installing $pack" && ok=0 && lib=1 [ 1 -eq $ok ] && txt="\tOK $txt" echo " $pack $txt" done [ 1 -eq $lib ] && miss="$miss libraries," && err=1 return } # check_libraries check_directories () { echo "" echo -n "# requred directories:" txt="" [ ! -e "$OSAFT_DIR" ] && txt="$txt\n**ERROR: missing: OSAFT_DIR=$OSAFT_DIR" [ -e "$BUILD_DIR" ] && txt="$txt\n**ERROR: exists: BUILD_DIR=$BUILD_DIR" [ -e "$OPENSSL_DIR" ] && txt="$txt\n**ERROR: exists: OPENSSL_DIR=$OPENSSL_DIR" [ ! -e "$SSLEAY_DIR" ] && txt="$txt\n**ERROR: missing: SSLEAY_DIR=$SSLEAY_DIR" [ -n "$txt" ] && miss="$miss directories" && echo $txt. return } # check_directories test_osaft () { echo_head "### test o-saft.pl ..." o_saftrc=$OSAFT_DIR/.o-saft.pl [ -e $o_saftrc ] || \ echo "**WARNING: $o_saftrc not found; testing without" o_saft=$OSAFT_DIR/o-saft.pl if [ ! -e $o_saft ]; then echo "**WARNING: $o_saft missing; trying to find in PATH" o_saft=o-saft.pl fi # call in installation dir without --no-rc to ensure adapted .o-saft.pl is used cd $OSAFT_DIR echo "$o_saft +version |egrep -i '(SSL|supported)'" $o_saft +version |egrep -i '(SSL|supported|cert)' return } # test_osaft optd=0 opti=0 optm=0 optn=0 while [ $# -gt 0 ]; do ich=${0##*/} arg="$1" shift case "$arg" in '+VERSION') echo 1.39 ; exit; ;; # for compatibility '--version') \sed -ne '/^#? VERSION/{' -e n -e 's/#?//' -e p -e '}' $0 exit 0 ;; '-h' | '--h' | '--help' | '-?') sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 exit 0 ;; '-list' | '--list') list_data exit 0 ;; '-debian' | '--debian') optd=1 ;; '-i' | '--i') opti=1 ;; '-m' | '--m') optm=1 ;; '-n' | '--n') optn=1 try=echo move_rc="" [ -e $dir/.o-saft.pl ] && move_rc=" # move existing $dir/.o-saft.pl to $dir/.o-saft.pl-orig" 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 && \ [ -e $OSAFT_DIR/.o-saft.pl ] && \ mv $OSAFT_DIR/.o-saft.pl $OSAFT_DIR/.o-saft.pl-orig && \ cp $OSAFT_DIR/.o-saft.pl-orig $OSAFT_DIR/.o-saft.pl && \ 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.30 } # NOTE --ca-path and --ca-file are set to /etc/ because special openssl does # not provide its on CA files; expects that /etc/ssl/certs/ exists. ### install IO::Socket::SSL; uses previous openssl and Net::SSLeay mcpan_install $perl_io_socket ### test o-saft.pl test_osaft O-Saft-22.11.22/contrib/install_perl_modules.pl000077500000000000000000000116751433765727300213050ustar00rootroot00000000000000#!/usr/bin/perl #? #? NAME #? $0 - install perl modules #? #? SYNOPSIS #? $0 [OPTIONS] #? #? 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 = "@(#) 1.4 20/06/05 21:20:13"; 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 foreach my $arg (@ARGV) { if ($arg =~ /^--?h(?:elp)?/x) { my $_me = $0; $_me =~ s#.*[/\\]##; open(FID, '<:encoding(UTF-8)', $0) || die "**WARNING: cannot open $0.\n"; while() { s/\$0/$_me/g; /AUTH?OR$/ && print " VERSION\n $VERSION\n"; /^#\?(.*)$/ && print "$1"; } close(FID); exit(0); } if ($arg =~ /^--?n$/x) { $try = "echo"; } if ($arg =~ /^--?f$/x) { $force = 1; } if ($arg =~ /^--?l$/x) { 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 if (not defined $targz) { warn "**WARNING: '$tar' not found; not installed;"; return 0; } 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 1; }; # do_install if (-e $lib) { if ($force < 1) { my $txt = "**ERROR: '$lib' exists; please use --f to enforce using it"; if ($try eq "") { die "$txt; exit"; } else { print STDERR $txt; } } } else { mkdir($lib); } foreach my $module (@modules) { print "\n# $try $module -> $lib"; next if not 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-22.11.22/contrib/lazy_checks.awk000077500000000000000000000027161433765727300175270ustar00rootroot00000000000000#!/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 (< 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 ############################################################################### ### ### Beautify output ### # Replace values yes and no by character symbols. o-saft.pl some.tld +check | contrib/symbol.pl # Just print data from certificate o-saft.pl some.tld +info | contrib/Cert-beautify.pl ############################################################################### ### ### 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-22.11.22/docs/000077500000000000000000000000001433765727300140035ustar00rootroot00000000000000O-Saft-22.11.22/docs/Summit2017-todo.txt000066400000000000000000000136251433765727300173060ustar00rootroot00000000000000 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-22.11.22/docs/concepts.txt000066400000000000000000000532001433765727300163620ustar00rootroot00000000000000 ############################################################################### ## ## ## This file/text is not yet complete (November 2022). ## ## It describes the main concepts used for programming O-Saft. ## ## ## ############################################################################### PROLOG Some texts herein are literally or conceptual identical to texts in other files. These texts are followed herein with for example: "> See also: OSaft/Doc/help.txt CONCEPTS" It is recommended to cross-check changes of such texts and adapt them accordingly. PRINCIPLES Quick overview about principles and concepts: Program execution * program terminates immediately on errors * shebang #! is followed by full path of program to be executed Program arguments * --help* provides user help/usage * --test* provides information about internal data * '+' prefix for command arguments * '--' prefix for option arguments * the sequence of commands and options is not important Program output * each check produces one line of output * additional information (comments) are disabled by default * '=' prefix for documention/comments * '#' prefix for verbose (and debug) messages 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. It follows the Perl principle: "Perl is a language for getting your job done." Before the concepts can be described, we need to explained the words and terms. In particular: developer vs. user, commands vs. options, debug vs. trace vs. results/output, code. For the deatils please see GLOSSAR below. Following concepts are described first: * Developer vs. user * Commands vs. options * Verbose vs. trace (and debug) * Output and results * Errors, warnings, hints * Ancient systems Developer vs. user As said above, the main purpose of the tool(s) is/are to do the job. Therefore the user's view is the most important. This view covers the tools' usage with commands and options (arguments in general) and the results (output) shown by the tools. Developers also needs to understand the concept of the code. In code the user's view is used. It is explicitly noted if a developer's view is meant. Commands vs. options In general "commands" are used for somthing to be done. "options" are used to configure or modify the behaviour of the commands. The tool(s) have many features that ease the user's tasks. It results in expense of greater complexity in parts of the code (for example the parser for command line options and arguments). The design of the commands and options is very much influenced by linguistic principles. For examples, most options can be abrevated in various ways. Common things should be short and easy to remember, aka "concise and natural for humans". It's often a matter of opinion or taste how something should be done, for example command line arguments. Hence we try to allow all options and arguments a user might be used to (i.e. from other tools). Following general rules are used: * commands are prefixed with '+', for example +cipher * options are prefixed with '--', for example --cipher=AES * the sequence of commands and options is not important > See also: OSaft/Doc/help.txt SYNOPSIS Rare exceptions are necessary to handle ambiguity. For example --help is used in general to print the user's help for a specific tool. But if such a tool is a wrapper to passes its arguments to another tool, user's help for this tool itself cannot be printed. Example: o-saft.pl --help # print help for o-saft.pl o-saft --help # print help for o-saft.pl o-saft -help # print help for o-saft itself For some special tracing or debugging, the sequence of arguments and options may be important. This most likely is necessary for --v and --trace* options. Example: o-saft.pl +cn target --exit=ARGS --traceargs o-saft.pl +cn target --traceargs --exit=ARGS o-saft.pl --traceargs +cn target --exit=ARGS Verbose vs. trace (and debug) Verbose output is intended for the user. It's enabled with the option --v . All verbose messages are prefixed with '#'. Except for hunting special problems with a target, trace options are most likely for developers. These options are named --trace* . Their messages are also prefixed with '#'. Debugging is intended for developers. No special options are provided for debugging beside the --trace* options. For more details see the section "Debugging code" below. Output and results All output is designed to make it easily parsable by postprocessors. Following rules are used as default: * Lines for formatting or header lines start with '='. * Lines for verbosity or tracing start with '#'. * Errors and warnings start with '**', hints 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 information was found or provided. Replace 'N/A' by whatever you think is adequate: "No answer", "Not available", "Not applicable", ... Examples: === Title line === = this is a comment Label for information or check: TABresult !!Hint: above result depends on the target > See also: OSaft/Doc/help.txt OUTPUT It is also often a matter of opinion and taste how results should be presented. Most tools strictly follow the rule: one check result in one line of output For postprocess output (see above), think the UNIX pipe model. Results of checks are marked 'yes' or 'no'. This leaves the proper interpretation, if the result is "good" or "bad", to the user. > See also: OSaft/Doc/help.txt CONCEPTS For status codes see "STATUS CODE" below Errors, warnings, hints Errors, warnings and hints may be part of the output as needed. While errors and warnings are printed immediately as they occour during the program flow, hints are printed right after the corresponding result. Hints print an additional explanation of a specific result. Errors and warnings start with a unique 3-digit number. > See also: OSaft/Doc/help.txt OUTPUT Note that an error terminates the tool immediately, unless the option --exitcode was used. Ancient systems This tool should run on older systems too. Background: Most tools rely on the newest frameworks, libraries, modules or other gimmicks just to make work easy for programmers. It seems that 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 (developer) wants. Hence O-Saft tries hard to run on ancient systems too. It may miss some features then, but it should work. If "something" is missing or not working as expected, a **WARNING messages is printed. These warnings cannot be switched off the usual way with --no-warning. DEVELOPMENT This part describes concepts used for development. Following concepts are described first: * Documentation (user and development) * Progrmming (code) style * Handling erros and exceptions * Debugging code * Programming: arguments in general * Programming: +ciphers * Programming: +info +check * Testing * Make for development * Portability Documentation (user and development) Important information should come first in the documentation, details will follow. Cite: include Huffman coding (common constructions should be short), good end-weighting (the important information should come first), and a large collection of language primitives. Progrmming (code) style In general the code favours language constructs that are easy to read by humans, even they are unusual for other programming languages (for example postfix conditions). The code uses spaces for formating, mainly to make the code look like tabular data. It is the author's opinion that tabular data is better readable (aka understanable) than continous (code) prose. There's no strict rule about formatting of such "tables", their style depend on the context they are used in. Because of our goal to support running on old systems too (see above) 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. Handling erros and exceptions As said before, the purpose of the tools is to simplify users' life and not the developers' life. We try hard to fullfil this goal. Programming is often done in a defensive way, means that any kind of error (and exception if any) will be catched and shown to the user. Unfortnately not all errors can be foreseen. In the GUI (o-saft.tcl) a "silent" catch is used sometimes, which disacrds any error message. 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 shown. This may disturb or bore the user, but we don't hide what we detect, which might be suspiscious somehow. This tool checks security accurate, it dos not give a "good feeling". Debugging code Debugging is intended for development only. All additional code for debug, trace and verbose functionality is separated in its own file. As verbose functionality, and trace partly, makes sense for the user, debug does not. However, using the --trace* options provide a huge amount of information too. Hence, no special commands and options for debugging are implemented. Either use perl's -d option, or change the code. Further hints can be found in ... # TODO ... Programming: arguments in general A strong syntax for arguments is used to distinguish commands and options (as decribed above). As a lot of spelling variants and aliases are supported, this results currently (2018 ..) in an ugly parser. Known drawbacks, traps: O-Saft complains about unkwown commands (+cmd), but not about unknown options. This means that unknown options are silently ignored. And more worse, for unknown (or misspelled) options with parameters, like --legacy=compact the parameter (compact here) then is treated as hostname. Hopefully this may change in future. Programming: +ciphers There are three modes (technically spoken) are implemented to detect the ciphers supported by the server: +cipher --ciphermode=intern - private implementation without using other perl modules +cipher --ciphermode=ssleay - using perl's IO::Socket:SSL module (mainly based on openssl) +cipher --ciphermode=openssl - using external openssl Since VERSION 22.02.22 --ciphermode=intern is the default. # TODO: ... 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: +info +check # TODO: ... All other commands, beside +cipher 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(). Testing # TODO: ... Documentation about testing can be found in the section TESTING in OSaft/Doc/help.txt This should be moved to this document and then referenced in there. Make for development # TODO: ... explain make system and targets ... Portability As decribed above in "Ancient systems", the tools should work on many systems. So we use traditional interpreters fpr the core tools only, these are: perl sh awk sed . Further development most likely continues on modern systems. On these modern and more sophisticated tools can be expected, like GNU Make or GNU awk (gawk). It's assumed that further development continues on modern systems and The scripts use hardcoded path in their shebang line, for a detailled discussion see "Using env" below. Using env From the perspective of an end-user, using /usr/bin/env seems to be more convenient than hardcoded paths. The advantages are: it is most likely more portable and it respects the user's environment variable $PATH . The disadvantages are: /usr/bin/env doesn't allow arguments passed to the specified program (exception see below) and it may have a security impact, because it is not obvious which program is finally executed. Also, some scripts use the program with arguments. When /usr/bin/env is used instead, the user must call the scripts with these arguments, which violates our goal to provide a simple to use tool. Well, some env can be used to pass arguments, examples: /usr/bin/env sh -c '\prog -opt arg' /usr/bin/env sh -c 'exec "$@"' sh -opt arg This, a bit cumbersome approach, will not be implemented here. GNU's /usr/bin/env supports the -S/--split-string option to pass such arguments to the program, example: /usr/bin/env -S prog -opt arg Using the old-school hardcoded path is simple and is known to work on all platforms, while detecting the version of /usr/bin/env and how it behaves, is hard work and not guaranteed to do the expected job. However, in some scripts /usr/bin/env is used, but in the most simple way only. That's why the hardcoded path for the program is used by default. The installation script INSTALL.sh will provide options to replace it with /usr/bin/env . For more details on shebang and env, please read (last seen 11/2022): https://www.in-ulm.de/~mascheck/various/shebang/ STATUS CODE Why does O-Saft not support a --fail option? # TODO: Long answer: 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 described 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 environment, 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, useful, 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, the option --exitcode does the trick, there are also some more options --exitcode-* for fine tuning. Please see `o-saft.pl --help`. 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 < 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 DESCRIPTION This tool 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 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 * 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 checkAllCiphers.pl example.tld checkAllCiphers.pl example.tld --range=full --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 * Show all --help=* commands =back o-saft.pl --help=HELP =over =item * Search for text in O-Saft's help and show with context =back o-saft --help=your-text =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 --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 sanitised 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 additional installed tools, for example by accident or because 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 This help text The sequence of the sections in the help text doesn't strictly follow the common guidlines for UNIX-style man pages. This is because it is important to understand the concepts of the tool and what options and commands are in context of the tool. In particular the L
    section contains only a very brief description. The L section follows the L section. =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" recommendation. In practice it depends on the context what a recommendation or countermeasure should be. That's why results are marked C or C if considered "questionable" or "not good" (for example according other checks). For more details please see L below. =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 Version 19.11.19 and later Starting with version 19.11.19 the I<+cipher> command does not use any external library. Checking for ciphers is done using plain Perl code. Only other collected SSL/TLS related information requires an external library, in general libssl. The description about OpenSSL and libssl below applies only if any of the options I<--ciphermode=openssl> or I<--ciphermode=ssleay> are given with the I<+cipher> command. Therefore following commands and options changed: =over =item * +cipher uses internal method =back =over =item * +cipherall command obsolete, !!Hint is printed =back =over =item * +cipherraw command obsolete, !!Hint is printed =back =over =item * --openssl-ciphers --force-openssl changed to --ciphermode=openssl =back =over =item * --openssl=TOOL TOOL only used for +cipher --ciphermode=openssl =back =over =item * --legacy=owasp option obsolete =back The historic commands I<+cipherall> and I<+cipherraw> should be replaced with the new syntax, as follows: VERSION < 19.11.19 VERSION > 19.11.19 #----------------------------+--------------------------------- =over =item * +cipher +cipher --ciphermode=ssleay =back =over =item * +cipher --force-openssl +cipher --ciphermode=openssl =back =over =item * +cipherall +cipher =back =over =item * +cipherraw +cipher --ciphermode=intern =back #----------------------------+--------------------------------- =head2 Version before 19.11.19 Up to version 19.11.19 the default behaviour for the I<+cipher> command was to use libssl. The commands I<+cipherall> and I<+cipherraw> did not use any other library as described below. =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 * --openssl-ciphers --force-openssl =back =over =item * --exe-path=PATH --exe=PATH =back =over =item * --openssl-cnf=PATH =back =over =item * --openssl-s_client --s_client =back 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 information. Some functionality (checks) of O-Saft may be missing or fail, when openssl versions 1.1.x are used (because functionality was removed). LibreSSL is not recommended, because some functionality 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 Please see L . =head2 Requirements 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 for example 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 customised. Requirements for openssl are described there. 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 information. =head2 External tools For building and/or viewing the documentation, any of following tools should be available: =over =item * aha 0.5-1 =back =over =item * perldoc v3.2801 =back =over =item * pod2man =back =over =item * pod2usage =back =over =item * podviewer v0.18 =back =over =item * tkpod =back =over =item * tput =back =over =item * stty =back =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 known ciphers in format like "openssl ciphers". It also accepts the -v and -V option. 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. Different output formats are used for the I<--legacy=*> option: =over =item * --legacy=simple simple space-separated output =back =over =item * --legacy=full TAB-separated output with more data =back =over =item * --legacy=owasp simple output sorted according OWASP scoring =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. Use I<--v> option to see all ciphers being checked. =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. +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). 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 +tlsextdebug =head3 +tlsextensions =head3 +extensions vs. +tlsextensions "Certificate extensions" are shown with I<+extensions> while the TLS protocol extensions are shown with I<+tlsextensions>. Use I<+tlsextdebug> to show more information about the TLS protocol extensions. =head3 +http2 +spdy +spdy3 +spdy31 +spdy4 +prots These commands are just an alias for the I<+protocols> command. =head3 +wildcard =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 useful 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 Brief documentation of I<--help*> options/commands. =head3 --help Complete user documentation. =head3 --help* =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 used 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 information. =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=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=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=warnings Show warning messages defined in code. =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: =over =item * HOST:PORT arguments are used as is (connection to HOST on PORT) =back =over =item * only HOST is given, then previous specified PORT is used =back 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, except if 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. The status code will also be printed at end, like: # EXIT 23 Parts of these checks can be diasabled, see I<--exitcode-*> options below. Use I<--v> or I<--exitcode-v> to see details about the performed checks. Functionality implemented experimental, may change in future. =head3 --exitcode-v Print information about performed checks. =head3 --exitcode-quiet Do not print status code at end, like C<# EXIT 23>. =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-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 information 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 information, 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, for example: 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 --ciphermode=intern =head3 --ciphermode=openssl =head3 --ciphermode=ssleay =head3 --ciphermode=MODE Following Cs are supported: =over =item * C scan for ciphers using internal method; (default) =back =over =item * C scan for ciphers using external openssl executable =back =over =item * C scan for ciphers using IO::Socket and Net::SSLeay =back =over =item * C same as C but print all cipher information, =back useful when postprocessed by contrib/* tools =head3 --cipher=CIPHER C can be any string accepted by openssl or following: =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. =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 (for example 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 (for example I<--force-openssl>). =head3 --range=RANGE =head3 --cipherrange=RANGE Specify range of cipher constants to be tested with I<+cipher> . Following Cs 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 --https_body Prints HTTP response body of the target also, if requested with I<+https_body> , which is disabled by default (because it may be huge amount of data not related to SSL/TLS). =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=* =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 --tty =head3 --format-tty Get the screen width and then adapt output of documentation to fit to that width. If the environment variable C is not set the command C or C of system is used to get the screen width. It's a very simple approach to make texts better readable on narrow devices like tablets. For more details, please see: perdoc o-saft.pl # the section Note:tty there =head3 --format-width=NN Set the screen width to C characters (see I<--format-tty> also). Default will be calculated automatically. =head3 --format-ident=NN Set the amount of spaces used for identation (see I<--tty> also). Default is 2. =head3 --format-arrow=CHR Set the additional chacacter when lines are split. Default: ↲ =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. I<--ignore-out=>, sets empty list. =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=* =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<--no-SSL > above. =head2 Options for customisation =head3 --cfg-CFG Option for customisation have the general from: I<--cfg-CFG=KEY=TEXT> For general descriptions please see L section below. =head3 --cfg-cmd=CMD=LIST Redefine list of commands. Sets C<%cfg{cmd-CMD}> to C. 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-checks=KEY=TEXT =head3 --cfg-data=KEY=TEXT Redefine texts used for labels in output. Sets C<%data{KEY}{txt}> or C<%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 Redefine general texts used in output. Sets C<%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 C<%text{KEY}="my text"> from file C. =head3 --cfg-hint=KEY=TEXT Redefine texts used for hints. Sets C<%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 C<%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 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<+CMD>). =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=cli same as --trace-cli =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, for example 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 --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 --warnings-dups =head3 --no-warnings-no-dups Do not suppress duplicate 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 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* (a.k.a ADH a.k.a DHA) ciphers =back =over =item ** all *CBC* and *CBC3* (a.k.a 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 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. =head3 SSTP Check if target supports SSTP by accepting method SSTP_DUPLEX_POST. The check does not send other methods (like CONNECT) to verify if the protocol is fully supported. Supporting SSTP is considered insecure, because SSTP allows to tunnel other, probably insecure, protocols. =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 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 ecliptic 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 checks, 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, preferred 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<**>, hints 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 information 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 Errors, Warnings, Hints Errors, warnings and hints may be part of the output as needed. While errors and warnings are printed immediately as they occour during the program flow, hints are printed right after the corresponding result. Errors and warnings start with a unique 3-digit number. Hints print an additional explanation of a specific result. They are are defined statically in the program code, or can be added on demand by using the option I<--cfg-hint=KEY=TEXT> . =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 EXIT STATUS Following exit codes are used: =over =item * 0 - normal usage and execution =back =over =item * 2 - command-line parsing failed, command or option missing =back =over =item * >0 - only if --exitcode was used =back =head1 ENVIRONMENT 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 =head1 CUSTOMISATION This tool can be customised 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. Customisation is done by redefining values in internal data structure which are: %cfg, %data, %checks, %text. 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. Texts (values) of keys in C<%data> are those used in output of the "Information" section. The texts of keys in C<%checks> are used for output in "Performed Checks" section. Texts of keys in C<%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: C 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 is recommended to use a non-existing key, for example 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 tool starts. It isn't a task for the tool itself, but it can simplify your life, somehow. There exist customisations 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 (a.k.a 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: 311: 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: 311: 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: 016: 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: 205: Can't make a connection to your.tld:443; no initial data =head2 **WARNING: 205: 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> . =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 appear 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 recognised in some tools Some tools do not display all characters properly, for example 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 * 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 for example 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. Consequently, 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> command. The reason is most likely that the server does not respond to the TCP/IP request, hence the script closes the connection after the configured timeout (please 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 Perl modules loaded and used for some options only: =over =item * Net::DNS(3pm) =back =over =item * Time::Local(3pm) =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 * o-saft-docker =back =over =item * L =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 Quickstart The script INSTALL.sh provides a quick method to check, compile and install anything needed. Please see: INSTALL.sh I<--help> For more details, read on ... =head2 Requirements for OpenSSL To build openssl following packages are requred (note that the names may differ depending on the used platform): =over =item * libidn11-dev =back =over =item * libidn2-0-dev =back =over =item * libgmp-dev =back =over =item * libzip-dev =back =over =item * libsctp-dev =back =over =item * libkrb5-dev =back Also, following Perl modules should be installed: =over =item * Module::Build =back =over =item * Net::LibIDN =back =over =item * Net::LibIDN2 =back =over =item * Mozilla::CA =back =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. Note that Net::SSLeay needs to be adapted properly then. =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. For a more complete build, plese see: contrib/install_openssl.sh . 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: 303: SSL version 'SSLv2': not supported by openssl All such warnings look like: **WARNING: 303: 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 (a.k.a 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 L 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 by --exe=PATH =back =over =item * prepend C with all values given by --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, for example: =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, for example: =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-cli =back =over =item * --trace-key =back =over =item * --trace-me =back =over =item * --trace-time =back =over =item * --trace=FILE =back Please see L section above for detailed description. 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<...>. In general, single-line values are always printed, multi-line values are printed with I<--trace=2> only. Hint: start with I<--trace-me>, then I<--trace> and finally I<--trace=2> . =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&Net::SSLinfo&:: =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 This tool 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 ::SSLEAY_DIR OPENSSLDIR: "/usr/local/openssl/ssl" Net::SSLeay::SSLeay_version() OpenSSL 1.0.2-chacha (1.0.2f-dev) = openssl = external executable /opt/openssl-chacha/bin/openssl external executable (TLSv1.3) openssl version of external executable OpenSSL 1.0.2-chacha (1.0.2f-dev) 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 existing path to CA PEM files /etc/ssl/certs common PEM filenames for CAs ca-certificates.crt certificates.crt certs.pem existing PEM file for CA /etc/ssl/certs/ca-certificates.crt number of supported ciphers 201 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 = number of supported ciphers 1280 default list of ciphers 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300C0FF, . 0x0300CC00 .. 0x0300CCFF, 0x0300FE00 .. 0x0300FFFF, long list of ciphers 0x03000000 .. 0x030000FF, 0x0300C000 .. 0x0300FFFF huge list of ciphers 0x03000000 .. 0x0300FFFF safe list of ciphers 0x03000000 .. 0x032FFFFF full list of ciphers 0x03000000 .. 0x03FFFFFF C0xx list, range C0xx..C0FF 0x0300C000 .. 0x0300C0FF CCxx list, range CCxx..CCFF 0x0300C000 .. 0x0300C0FF ECC list, ephermeral ciphers 0x0300C000 .. 0x0300C0FF, 0x0300CC00 .. 0x0300CCFF = 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.044 /usr/share/perl5/IO/Socket/SSL.pm Time::Local 1.2300 /usr/share/perl/5.24/Time/Local.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 19.12.21 Net/SSLinfo.pm Net::SSLhello 19.12.21 Net/SSLhello.pm Ciphers osaft 19.12.26 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: 121: ancient Net::SSLeay 1.35 < 1.49; cannot use ::initialise at /Net/SSLinfo.pm line 481. === reading: ./Net/SSLinfo.pm (O-Saft module done) === **WARNING: 120: ancient perl has no 'version' module; version checks may not be accurate; at o-saft.pl line 1662. **WARNING: 121: ancient Net::SSLeay 1.35 < 1.49 detected; at o-saft.pl line 1687. **WARNING: 121: ancient IO::Socket::SSL 1.22 < 1.37 detected; at o-saft.pl line 1687. **WARNING: 124: 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: 851: 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: 851: ancient version Net::SSLeay 1.35 < 1.49; cannot compare SSLeay with openssl version at o-saft.pl line 4778. ::SSLeay() 0x1.35 **WARNING: 851: 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: 851: ancient version Net::SSLeay 1.35 < 1.49; cannot compare SSLeay with openssl version at o-saft.pl line 4778. **WARNING: 841: 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 What is "testing"? This tool itself is for testing something (TLS etc.), so it needs to be explained what testing here is about. Following testing types are distinguished and then described: =over =item * User testing =back =over =item * Functional testing =back =over =item * Developer (internal) testing =back All descriptions below, except "User testing", are only intended for development. =head2 User testing During normal use of the tool, "testing" is only required for hunting problems with the connected target. Following options for tracing and verbosity can be used for that: =head3 --v Print more information about checks. =head3 --trace Print debugging messages. For more details, please see L . =head2 Functional testing This section describes "developer" rather than "user" testing. Functional testing mainly means testing the functionality of the tool itself, for example: do the commands and options work as described in the documentation: o-saft.pl I<--help> Makefiles are used for testing functionality and code quality during development. These tests are implemented in the ./t/ directory, see all C there, start with C. =head2 Developer (internal) testing Testing SSL/TLS 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 for o-saft.pl 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 C<%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: " The options which provide information about internal data structures and alike described below, behave like the command I<+quit> and do not perform any checks on the target(s). See C how to use these tests. =head3 --tests Print overview of following commands/options. =head3 --test-data Print overview of all available commands and checks. =head3 --test-maps Print internal data strucures C<%cfg{openssl}>, C<%cfg{ssleay}>. =head3 --test-prot Print internal data according protocols. =head3 --test-regex Print results for applying various texts to defined regex. =head3 --test-ciphers-dump =head3 --test-ciphers-overview =head3 --test-ciphers-openssl =head3 --test-ciphers-show =head3 --test-ciphers-simple =head3 --test-ciphers-sorted =head3 --test-ciphers-ssltest Print ciphers in various formats, please see: OSaft/Ciphers.pm . These options are aliases for: I<+list> I<--legacy=TYP> . =head3 --test-ciphers-hex=* =head3 --test-ciphers-key=* =head3 --test-ciphers-list Print some special information, please see: OSaft/Ciphers.pm . =head3 --test-init Print parts of data structure C<%cfg>. In contrast to the options described above, I<--test-init> exits straight before performing the specified commands on the target. Therefore it prints the settings in C<%cfg> containing all applied commands and options. =head3 --test-memory Print overview of variables' memory usage, used for debugging only. =head3 --test-methods Print available methods for C in Net::SSLeay. =head3 --test-sclient Print available options for C from Net::SSLeay. =head3 --test-sslmap Print SSL protocols constants from Net::SSLeay. =head3 --test-ssleay Print information about Net::SSLeay capabilities. =head3 --test-sub Obsolete, please use: make test.dev.grep.sub make test.dev-grep.subs make test.dev-grep.desc =head2 Testing results Finally there should be tests, which prove that the results of o-saft.pl are really what they should be. A test target is necessary therefore, which produces reliable results. However, some of the implemented tests in C (see section "Functional testing" above) already work properly. This test coverage needs to be improved ... =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 * 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 Testing with exit code =over =item * Test SSL/TLS connection and return exit code =back o-saft.pl +check --exitcode some.tld =over =item * Test ciphers and return exit code with details about exit code =back o-saft.pl +cipher --exitcode --exitcode-v some.tld =over =item * Test ciphers and return exit code for ciphers only =back o-saft.pl +cipher --exitcode --exitcode-no-prot some.tld =over =item * Test with exit code but avoid checks considered C even if C =back o-saft.pl +check --exitcode --ignore-out=ev- --ignore-out=rfc_7525 some.tld =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 DOCUMENTATION =head2 User documentation Documentation is mainly intented for the user, which is provided with o-saft.pl --help But it may be difficult to find the proper information there. To get more selective documentations, the I<--help=*> options can be used. To get an overview which I<--help=*> options are available, use: o-saft.pl --help=HELP This only provides the complete user documentation, or the well known parts specified by the keyword, (HELP in example above). To find any text with some lines of context, following could be used: o-saft.pl --help | egrep -i -C 3 "some text" This is simply avaiable with: o-saft --help="some text" In the GUI a more sophisticate search is implemented, see the "Help" window there: o-saft.tcl =head2 Developer documentation Documentation for developers is provided in various ways. Information for developers can be found found in: =over =item * the files itself =back =over =item * with: o-saft.pl --help=test =back =over =item * with: o-saft.pl --test =back =over =item * reading: Makefile.pod =back =over =item * using: make =back =over =item * using: make help.doc =back Using make for development uses additional external tools and/or Perl modules: =over =item * perl-analyzer =back (also requires Perl modules, JSON, Text::MicroTemplate) =over =item * Debug::Trace Devel::Trace Devel::DProf Devel::NYTProf =back =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 * Basic cipher check 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 @(#) 22.06.22 =head1 AUTHOR 31. July 2012 Achim Hoffmann Project Home: https://owasp.org/www-project-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 * 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 really 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, because it misses IO/Socket/SSL.pm, however, checkAllCiphers.pl works. perl from older PortableApps/xampp (i.e. 1.7.x) does not work, because 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 command-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 information (a.k.a %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.29 22/10/10 21:19:33 # # # acronym | description # #------+----------------------------------------------------------------------+ # 0-RTT zero Round-Trip Time # 3Fish see Threefish # 3SHAKE sometimes for: TLS Triple Handshake Attack # 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, block cipher # AESCCM AES with CCM # AESCCM8 AES with CCM8 # AESGCM AEAD algorithms AEAD_AES_128_GCM and AEAD_AES_256_GCM # AES-CCM alias for AESCCM # AES-GCM alias for AESGCM # # AES-GCM AES-GCM is an authenticated encryption mode that uses the AES block cipher in counter mode with a polynomial MAC based on Galois field multiplication. # AES-GCM-SIV Nonce Misuse-Resistant Authenticated Encryption (RFC8452) # AES-CTR ? # AES-XTS ? # AIA Authority Information Access (certificate extension) # AKC Agreement with Key Confirmation # AKID Authority Key IDentifier # ALPN Application Layer Protocol Negotiation # ALPACA Application Layer and Content Confusion Attack (Exploit SSL/TLS) # AMASTRID stream cipher algorithm # ARC4 Alleged RC4 (see RC4) # ARCFOUR alias for ARC4 # Argon2 Password hashing function (J. Aumasson, 2014) # Argon2d variant of Argon2 # Argon2i variant of Argon2 # Argon2id variant of Argon2 # 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 using the same prime as NIST P-224 # BADA55-VR-256 curve using the same prime as NIST P-256 # BADA55-VR-384 curve using the same prime as NIST P-384 # Bar Mitzvah vulnerabilty of TLS sessions protected with RC4 # BDH Bilinear Diffie-Hellman # BEAR block cipher combining stream cipher and hash function # BEAST Browser Exploit Against SSL/TLS (Exploit SSL/TLS) # BEAST . fast block cipher for arbitrary blocksizes # BER Basic Encoding Rules # BGP Boorder Gateway Protocol # 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 (64 bit) # BLAKE2s-128 see BLAKE (32 bit) # BLAKE3 fast secure hashing function (20??) # BLAKE3 ?? # 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) # Blowfish symmetric block cipher # boomerang attack attack on BLAKE # BPA Branch Prediction Analysis # Brainpool signature algorithm, from BSI # BREACH Browser Reconnaissance & Exfiltration via Adaptive Compression of Hypertext; a variant of CRIME (Exploit SSL/TLS) # Bullrun NSA program to break encrypted communication # CAMELLIA symmetric key block cipher; encryption algorithm 128 bit (by Mitsubishi and NTT) # CAST Carlisle Adams and Stafford Tavares, block cipher # 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 # CBC3 alias for Tripple DES (sometimes, used in cipher suite names) # CCA chosen-ciphertext attack # CCM Counter with CBC-MAC Mode (authenticated encryption block cipher mode) (with 16-octet authentication tag) # CCM-8 Counter with CBC-MAC Mode (authenticated encryption block cipher mode) (with 8-octet authentication tag) # 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 # CGN Carrier- Grade NAT (RFC6598) # 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 # CLEFIA lightweight block cipher algorithm # 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 # CNT_IMIT cipher suite # CTR_OMAC cipher suite (GOST R 34.12-2015 aka GOST3412-2015) # 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 # CRYPTON 128 bit block cipher (1998) # CRYPTREC Cryptography Research and Evaluation Committees # CRYSTALS post-quantum hash function, signature # CRYSTALS-Dilithium post-quantum hash function, signature # CRYSTALS-Kyber post-quantum hash function, signature # 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) # DEAL 128, 192, 256 bit block cipher (Lars Knudsen, 1998) # 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) # Dilithium digital signature scheme # Dilithium2-AES alias for Dilithium # Dilithium3-AES alias for Dilithium # Dilithium5-AES alias for Dilithium # 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 # DSPR ? # 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 (block cipher 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 # EMS Extended Master Secret (sometimes) # EMS Encrypted Master Secret # 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) # eTLS Enterprise TLS (social attack on privacy by ETSI; renamed to ETS) # ETS Enterprise Transport Security (renamed from eTLS) # ETSI-TS European Telecommunications Standards Institute - Technical Specification # EV Extended Validation # EV-SSL Extended Validation Certificate # FALCON Fast-Fourier Lattice-based Compact Signatures over NTRU; post-quantum signature # 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 (Exploit SSL/TLS) # 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) # GOST28147-89 block cipher # GOST3410-2012 signature algorithm # GOST3411-2012 hash algorithm # GOST3412-2015 block cipher # GOST3413-2015 modes of operation for block ciphers # GOST3431095 cryptographic algorithm? # GOST3431004 cryptographic algorithm? # GOST3431195 cryptographic algorithm? # GOSTR341001 cryptographic algorithm? # GOSTR341094 cryptographic algorithm? # GOSTR341194 cryptographic algorithm? # 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) # Jolkit-BC tweakable block cipher # JSSE Java Secure Socket Extension # KATAN lightweight block cipher algorithm # KLEIN lightweight block cipher algorithm # Keccak hash function (Guido Bertoni, Joan Daemen, Michaël Peeters und Gilles Van Assche, 2012) # KCI Key Compromise Impersonation # KDC Key Distribution Center (mainly Kerberos) # KDF Key Derivation Function # KEA Key Exchange Algorithm (alias for FORTEZZA-KEA) # KEK Key Encryption Key # KEM Key Encapsulation Mechanisms # KMS Key Management Service # KPAK KMS Public Authentication Key # KRB Key Exchange Kerberos # KRB5 Key Exchange Kerberos 5 # KSAK KMS Secret Authentication Key # KSK Key Signing Key (DNSSEC) # KU Key Usage # Kuznyechik blockcipher (used in GOST) # LAKE hash function (Jean-Philippe Aumasson, Willi Meier, Raphael C.-W. Phan, 2008) # LEA ? algorithm # LEA-128 see LEA # LEA-256 see LEA # LED lightweight block cipher algorithm # 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 (Exploit SSL/TLS) # Logjam see LogJam # LRA Local Registration Authority # LRW Liskov, Rivest, and Wagner (block encryption) # LSN large-scale NAT (same as CGN) # Lucifer block cipher (developed at IBM in the 1970s) # Lucky13 Break SSL/TLS Protocol with ciphers using CBC-mode (Exploit SSL/TLS) # Lucky 13 Break SSL/TLS Protocol (Exploit SSL/TLS) # Lucky Thirteen see Lucky 13 # MANTIS block cipher, low-latency variant of SKINNY # 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 # MIDORI lightweight block cipher algorithm (64 or 128 bit) (2015) # Midori64 see MIDORI # Midori128 see MIDORI # MISTY1 block cipher algorithm # MPQS Multiple Polynomial Quadratic Sieve # MQV Menezes-Qu-Vanstone (authentecated key agreement) # MS-SSTP see SSTP # 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) # NOEKEON symmetric block cipher algorithm # Neokeon see NOEKEON (probaly typo) # 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 # NTRUEncrypt alias for NTRU # NOMORE Numerous Occurrence MOnitoring & Recovery Exploit, aka RC4 NOMORE # 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 # Picollo lightweight block cipher algorithm # 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 (Exploit SSL/TLS) # PQC Post-Quantum Crypto # PRESENT block cipher algorithm (80 or 128 bit) (2007) # PRF Pseudo-Random Function # PRP Pseudo-Random Permutation # PRINCE low-latency block cipher algorithm (64 bit) (2012) # 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 # RACCOON Timing vulnerability in TLS' DH key exchange (Exploit SSL/TLS) # RADIUS Remote Authentication Dial-In User Service # Radix-64 alias for Base-64 # RAINBOW post-quantum signature (broken 2/2022) # 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 # RIPE-MD alias for RIPEMD # RLWE Ring Learning-with-Errors # RMAC Randomized MAC (block cipher authentication mode) # RMD # RNG Random Number Generator # ROCA Return of the Coppersmith Attack (Exploit SSL/TLS) # ROT-13 see XOR # ROBOT Return Of Bleichenbacher's Oracle Threat (Exploit SSL/TLS) # 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), see ChaCha20 # 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 # SBPA Simple Branch Prediction Analysis # SCA Selfsigned CA signature # SCEP Simple Certificate Enrollment Protocol # SCREAM tweakable word-based stream cipher (2002) # 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 # SEAL Software-Optimized Encryption Algorithm; 32-bit word stream cipher (1994) # SEED 128-bit symmetric block cipher (1998) # Serpent symmetric key block cipher (128 bit) # SGC Server-Gated Cryptography # SGCM Sophie Germain Counter Mode (authenticated encryption block cipher mode) # SIV Synthetic Initialization Vector # 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-128 Secure Hash Algorithm (128 bit) # 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 (128, 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) # SHAttered The first concrete collision attack against SHA1 (Exploit SSL/TLS) # 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) # SIDH Supersingular Isogeny Diffie-Hellman (key exchange) # SIKE post-quantum hash function, signature (broken 7/2022) # SIKEp434 post-quantum hash function, signature (broken 7/2022) # SIKEp503 post-quantum hash function, signature (broken 7/2022) # SIKEp610 post-quantum hash function, signature (broken 7/2022) # SIKEp751 post-quantum hash function, signature (broken 7/2022) # SIMON lightweight block cipher (NSA algorithm, questionable security) # SipHash hash function (J. Aumasson, Daniel Bernstein, 2012) # 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) # SKINNY SPN tweakable block cipher # SKINNY-128-256 see SLINNY # SKIP Message Skipping Attacks on TLS (Exploit SSL/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 (Exploit SSL/TLS) # SM3 block cipher algorithm? # SM4 block cipher algorithm (Chinese gouvernment algorithm, questionable but no objections yet) # SMS4 see SM4 # SMACK State Machine AttaCKs (Exploit SSL/TLS) # 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 # SPARX ? algorithm # SPECK lightweight block cipher algorithm (NSA algorithm, questionable security) # Speck64 see Speck # Speck128 see Speck # Speck256 see Speck # Speck256-XTS see Speck # SPD Security Policy Database # SPDY Google's application-layer protocol on top of SSL # SPECK block cipher combining # SPHINCS Stateless hash-based signatures, post-quantum hash function, signature # SPHINCS-256 alias for SPHINCS # SPHINCS-SHAKE256 alias for SPHINCS # SPHINCS-SHA-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 # SSTP Secure Socket Tunneling Protocol # 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 (Exploit SSL/TLS) # 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 ? # TGS Ticket Granting Service (mainly Kerberos) # TGT Ticket Granting Ticket (mainly Kerberos) # 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 # XChaCha stream cipher algorithm (with 512-bit key) # XChaCha12 see ChaCha (aka 12-round XChaCha) # XChaCha20 see ChaCha (aka 20-round XChaCha) # 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.15 22/10/06 12:11:57 # # # 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 # 2144 CAST-128 Encryption Algorithms # 2612 CAST-256 Encryption Algorithms # 2950 Telnet Encryption: CAST-128 64 bit Cipher Feedback # 2984 Use of the CAST-128 Encryption Algorithm in CMS # 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) # 4303 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 # 4106 Use of Galois/Counter Mode (GCM) in IPsec Encapsulating Security Payload (ESP) # 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 # 4490 Using the GOST 28147-89, GOST R 34.11-94, GOST R 34.10-94, and GOST R 34.10-2001 Algorithms with Cryptographic Message Syntax (CMS) # 4491 Using the GOST Algorithms with X509 (GOST R 34.10-94, GOST R 34.10-2001, GOST R 34.11-94) # 4634 US Secure Hash Algorithms (SHA, SHA-based HMAC and HKDF) # 5869 HMAC-based Extract-and-Expand Key Derivation Function # 5830 GOST 28147-89: Encryption, Decryption, and Message Authentication Code (MAC) Algorithms # 5831 GOST R 34.11-94: Hash Function Algorithm # 5832 GOST R 34.10-2001: Digital Signature Algorithm # 6986 GOST R 34.11-2012: Hash Function # 7091 GOST R 34.10-2012: Digital Signature Algorithm # 7801 GOST R 34.12-2015: Block Cipher "Kuznyechik" # 7836 Guidelines on the Cryptographic Algorithms to Accompany the Usage of Standards GOST R 34.10-2012 and GOST R 34.11-2012 # 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 # 5297 Synthetic Initialization Vector (SIV) Authenticated Encryption Using the Advanced Encryption Standard (AES) # 8452 AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption # 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 # 6151 Updated Security for MD5 and HMAC-MD5 # 6234 US Secure Hash Algorithms (SHA, SHA-based HMAC and HKDF) # 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 # 7905 ChaCha20-Poly1305 Cipher Suites for TLS # 7627 TLS Session Hash and Extended Master Secret Extension # 7693 The BLAKE2 Cryptographic Hash and Message Authentication Code # 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 # 1918 Address Allocation for Private Internets # 6598 IANA-Reserved IPv4 Prefix for Shared Address Space # 9102 Argon2 Memory-hard function for password hashing and proof-of-work applications (2021) # # # end rfc # begin voodoo # 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. # These 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 voodoo O-Saft-22.11.22/docs/o-saft_CLI_data_flow.pdf000066400000000000000000015346041433765727300204130ustar00rootroot00000000000000%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-22.11.22/docs/o-saft_GUI_data_flow.pdf000066400000000000000000017120011433765727300204150ustar00rootroot00000000000000%PDF-1.4 %äüöß 2 0 obj <> 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-22.11.22/docs/o-saft_docker.de.pdf000066400000000000000000034602301433765727300176150ustar00rootroot00000000000000%PDF-1.5 %äüöß 2 0 obj <> stream xݎJ$ݯk]&L@ЅeAt!ˀ`A?jP~{3FYU}|6\939|l-ߩgmӯOgW8>GXW__?O/.> 9壜{]??(Mk{ -2ιm)]蹷 i%Tk:>_?~atH28OW'ߢ_L^Gw江#aiVGCMs>sZZKSnZu<q}lSשײ-q}nkTΐ절-niG~v|k۾k#o׀5PͿS/׷qݾkrRܯ-~zao;`׊W/Y/Ϟ~e^_¯qƲy!]iGfۈjsZ,G\t\^̴WZOsy|]׷g6:؂^ݣ|Zqv-'r6> ȵÆ(OG>3;/@U}׵9ƙl;u;kʦql1s8֕–o9D ]GԞ}=a[⮽|'@N `;sjQ W/atq'[KQ/RՋkg^< ^sjdKqԂt] Zٷэ-oÆ(NvX ǭ}|+c bg`kȌ8 ר 9 v Z9ƙȥosu Ry18bcfFW*[J=8 uٹfWׯu`y5;~2{0Gc]-rhM(jװJ #nNx;7o>F̉^üku۵ځSpι;L)݀kpo{r&_p)QRq`x=I1Ľ-imvFܶ%9p}Gc9Ցc\KVucqɠ%8ݮSg;h[s' X9"3r!Ez8 qS}^GK+?|4>.;rjDIiN" n/q#q&~(}+IDNhwOn#ɵ0Z$&*.$71/3J:9c~mJsdl.쾭whi;7' _K#\:#rI.;r96! c};/a5ܤ~|8L=s8hvcoőc|>\#r<#ȇ]=(DїBZvGq~@]#qpz-3^;FRO_/Y\|'qOܺ6c'r]l81>)<##W|=\SxN>8+Z2#~%"[ kL~ zuGm(1Lg"3v:plx/`w9ѕ-LdO~\swcC $ c}\"=8pí)Вy301LMGyBdUqP&\sX%~m^;c˶fj@܉$^;p]cv&{`Zuԛx0`-ks_LjI~7%e/<gk/;9/ԀnH(\-MȊ-=1.HT\:,\/4zrqc#_^wv.džg 'ҳG񡠥!r,eꉻ W^7]-O!?{w\䱿½P2O@ꕸicg/.QſH3-Nƣ| ;d^ yNegKDvq_ ɘ7y}eD JY뮮`ߠ1DNMGQGq2ߣ}WnZuQx/G_N5DZ^nշҭD.vb8`@M-@ފc 8<0;|ԃv8LENit FǍa^qy^{ ۺm##R+llw a,_+}k5e[ZWC`OF?Qe 2QՎml_V_GB<{̫AUpk,zvXpݩ5p2ت [K9@v[lEV~~lQFDΧlkz|X:)*/h+ +> nc%t+^voS2}2bdԬbgY6\;O@d2ΧvX˩L`)qVY- \!DQ:6o*Q}nXL2q~6`n0H8qc/`]wWo=W7a.3z>]S4{6);9XT,0S,_+DbsiY Zybr4GqryG(>lU~dte SV-JTYM/}^xTVÎd-4Wyc7ҭĭx`d/lEș;|v7Ūݛ[ ܬ)%A ЕD`Yf+`}k;#jɸZf 5(ôV/ۜk%kµ(k?O&> jwq_MW%a(-V2/3!f=W'VR"{4?[$d4CRyiTL:µ> p42#R˯ W"?{lRRͮI+/&#-6h-51g5Z~no=gdG*,\.O0ta2ƣ-ݏEߢHd*ƒ[M8Y0`Moz 348?h%sDj8sgԷfgS1;ewۃGKoUIՅ:iY0R6Z[ṗt$ߢ 5 Hu'Ӯ1gJBqPhޯ!c"ܪ:-IsKGZZOaL+wLykGZRMrE4"ZO|>C13-ɯtWy|*!m5fdWV 2yv=z6ѳc'Zg7v%5L]مL_5Cb5 <:9+&_*dreL_U-3;-2 x?${F덬JKg,Z8w}Pó?$E%!W~EkgA-Li%⼑mW,]Il96hC'Z8XSMH q7pC' v=Ր8IZ4RX+I݉;k'f%F9O!yˏ\rkɅV<6۰8+JviPwxpDeHyI`bY&Xî8Xdv?~fwze JA͏EVah3 ux;Ǡ۝.^8Ɖy¢=TgI]MTt1[(aY'%-zg9N-D}p)@$z<ȻE1-TfH!M­qM!R!X|IRjlJ\!hgc̖A6Qn0B>_<#тjL-0y%b̲'Ai3{`#},vve>`/]c <3 )nvumT4MJkYԘ):EQ2 dæ%$:[Z={Vʌ9MIaU6U,⼧ϊS B!`f(nGuW\")kGYcT_ &ڮ17\tc$i#-akYS)4 mttCV)>Md ."V9|x@@N+,]Dmw2AAagY^DKIM~3Gr>5]F~!1{,۳P @\v=}vK딅[A3͉֏B͉kgYAtl)E~&]IFqgqc*>xb+ܷ0I7_!UW9gEP,nVtl38(Ú`NX-y2BbI)s[yZ/qgc|lsb;E4qtp,:Q13,dQ; 1H;w6yWXgVJOG~L; /a0h+{g'`&ݨt 9`O ɤy@VvQm{5ϥbһ@8[ }arm&ՓF*ool]3,|-Ut^=nJu؝qm=R7yF7. x" l By 9y@$*{ئ9|ҔDq 0\0e=8=K1o,e~B!ؕ^~yBu9E7 NRcuSGaKUag!٦pBxd,O%[m`gJGF9%ٌEE"Iy< qAqW%1#(f,+,5l|H'⒒X7=l^Bqޓg=!%d Aj_ΎdA,̿~ݙ_p9\ϕ8ِy'P+SÅ.*gւY:Ed3\ҽ--]W/3@ *]M#ck-)L3W5x;>zqQcm(2П3D)~5)/n|;kO7 } 65QƄc;C,oL~6ZYȢfQ#ࠦ*7[8y;Y}L=) 5Vq-c}Bܼeγn@oFxo[XmPїb'$1[\0g3:9cl_{ lik@Ͽq-k0^=;Oeң_as{;U+DQU=#kM@\9zwG}pDL8+=vۄ =`:ITw^tY8;'z4z=ZS%d>F'[4f/ i|wɮpau79Rᰄӝ o\(2詬r׵>FƇ9&, :unDԅm &'k mƲ~Z5r6S1D~Co8]*{Tjm7:/azQBř9lo}\k-hc/}Y\m ly7=pdLw69"EL5!_H- ?;LkW.qyȂO_3.ma^Vh$xXO/A&+z%Y>dalw%Ɋ-'mY(Y0Xf(P<܉-ɥ< osр}5U97HM?oЕ.Qf1 5 alkp7G˱H,(Nو'MnvS}-xxPW`D_-'11t\m[/teřqFIB!}GOGK+ь^q^3f*?އm1ٶ7^|K, pdfheqp3j;`sҙ&L5{Ktu0{.`ìa+z9ܲmt v"}57+zV" Շ8J\cΊ8'Y܋-% i 1SP!' 1i4G,r*j^99ƙoJH?x24xƕibk2QBKvg!I: 3Lٍ'Mݖ 9F00~@M--I 3z{oY.JK}ѽ#v#Q%$.3NX'ZjS%/ڳ7f8#'Q! PAf< 3zึѣb8=p;cO!76ȍ!g"s7GcT: s]Nϧ-{po^,Vw~IGi/MHH C" odҡb,`txsE5D~F3 Z܍;d'%pl!f8a/̖BC6T.7f9!wْmw64GKowq&;3zQX(=p^bo_"cF,] ,Sk?u9\fNUJ 1Nٍ5`SJrD[F\Gt 3ayKW޼cь^Q nj˵oa^rňvV.V:^Eŏa+zI VK8{"ȄUS5'u*ęo&[Qc e(BPhZnaNt9%g1ZdA^L7^V3˶OzVۆ4 Rlei8g3zzI9.4,X, [f"\ 'V؟J۩-K%i({=Qݎq^󢷚x/2=ɘ.f7GCа,!cjU.{7N;=y2r< [*J@ 3vT\Izv~xW@@v'AK:0Ͷsq12ƒvtMDGFo(]||bf#vOQ/%Lَ^lG©F2e,ѕ[ufq7.H7PA2G/߽'[8.AYv7Fo,:akzfK< j5HRƓ^DjU/8+wnM?mR? idE|3iZUH=lm$E!ѓu7nv!22La Y&f}K\jVdGoN\7n\CZ&2zׯD-?ez7z n_| |獆T=&GVQ-=1=Lwncْa6=Ųw7' qM{BհL$*"g"s# ua/;4FO1/!8g7z{NZQ%nraEk;z|!,$,3TaZ~7I.rt@67;,kfilwS =svYP=+<7nJ8LXpwqX Ti0=t-RuyrE8^6X䖽/Kof>f&6Nr]8^A'R4gxyKC ęсaFWXbzV%EoS 6%~pKƌ/E]Q4}UwbcKO⦇x[D("Y[;loת1Jىjaŝi"Wx5٢:p8ѳI`c)'zhd-Bq&;'zzz'I+]|~H2]' 79eCU/,}iW?H_"ƙo%0̆fzT{؛Y \H~]?gYT'񢧿`%b eãd˩kƊDdѯZi{!LONkWw'jVeebnQ@qNFۤx;j>c0fNVf(( N8i֩`aE}}t2 o[T@'c]Sc&G_NQcΌg cx:J,9"ѣ%0=HΚUQNK7ZC/q&;7z8RlJ&/%^ ?﫿ckscv,3\d =|S6.RR #6J]Vp8`;ѣnE`gx Z oqFa;ч79nE_:p[KGw3%Y Lh >hՍ҆Z>?F"W(AB h0WM0⒜I4Z Mu v4Ӎ7Ė!)G-s-~' N4~j~Ƨ<ۜ|~K-VOK[ҫEVZS~:ғkk fU+tWp縿-dKtZnEu Mi3❷JE?_ B-̵ݒHg\0&Kzt5τZzo!BQwƂanI 0v pVmՄ:yr P b8(pݓިE6%%:ܖp?1 qE7GK6(8HbSE:1R-qF]i<ܙO%O̩삋LoOE5FŨy<Cc+џ_<:/Cb Q>Lo.d+.<w,Ig,јcqD<1,&`ƃv(,Eğ 7yƨ5Z:izp-HrqP7DyB|ZҘ>P-ݘ^ۃhn Md@/=64yTWT=tOl@kڣ;&/cnqj KMdMe1dSlgT} i7D/XtyF%߹mdM#`]5iɑ~R+s5UM8X>FZ38O(7Sua7=ؤgh 40GqPjYG3"dRKH̅ڞ--tfGyKoD&d !B)x%7{&pI 8m+FlzNk|p{)`GL{v-Ƀn͆lPkTQ#ϓ~Ș ü'ԊN֮lq>ُI?VIY;0=E@,aTȪ[ZLOQLbQ[WSf?yƩ݋;@06sOoU(OH4'[J6(=V< ՚^ AS*^KUyPKcy{u]>H7+ CK33j(O贴pm;|ȞjrOK[y2Sim,T VĆqia+Ov X5b8V`G! [YӞ~8O7.B<驸 fnt!?!qjZ^[6Xn +3RC'Z!X} n QoDz/'xR+1ئ<6JQi qQ9gOYjpgM Vu7u $G"%iTaK 8yB<_; A5K/50I1.-]!4Ijh8F_lA' y<Lut Z}?%N-;Qg]q z_}DywkJc{Q/qpjYG"L{A[Qji,oh6nBldxPKcy;DA='GqhSeP/ϗ8t,`Gkf!`/A=kmďqPji-oC4qqHxt]vzEzPKgy&M?}`.?\aj+/O,`r?KQcwZ:ˋ?PoUee~ԏ}Q+<#B ͇,xw*Yxa' Vx{\^Aa Xsh}%F%J~2鲨7r"# V xt\xN ~M  64NV8O>5=yBe>Z>y\VC= N| Nm5zIe=Pɷd} OrBB9iɷLLeK'Zgzkh2.9%i8OX*G-ӜhG_*[S4 i娇nB_t6ٟ OH)Hm0,EuTB?=C ֬" &qEP<ȟFVۯZKZ^ȩ$~%iYQy5F-_:P)5,'iIcZ7Yě[*d#:iiR釮qj].]Fw?QonO-a޳j]ު5YDm3} PV DM0<%mgCF΂ aj)m(]t?8d;}9QP?yucyf NjԗޤoƙNq>be;ޅy~>o22#ovp4_xw aB},JN΄Zd7oMVDc[T-*#&*Y{⟧EZ8+G9*oޢ k~2x}Hڃ_w1Szm240%}B )exie ?5_V*{QJ7 -'K/qC7E&j'ϹdOo8}qŹׯ/3j+2$me ?ZQ|8Y`5=ut e 7NZ0:VY04BTWOjIk;VG060n Z&8i {C6=2Ik[։^ŝ 7 -C{ZfeÇnLvU>6ZFxo [HWu9@yM@I3QZ~͖q-E}8k^-pu|"%Ajg"MH5|H_:_ ϻywy-2ι?э}Ɖ:ѧM#/YѫA.>|Gg8ϧ,0 50Ӽ~ afjdsg^GC3@KӅk#|;fk+[%G&W%+G78}:%KH {ѣ8Wf 2ξQ&={+zm-BD-3*܊-qwVSp+JV >[R|%_[tj4ђ=`]ם+2e¾s%!fxcNC^ Gkƍglm*lɐ)#7qY0Ir:S7vUѣ rhg"YR0K]f 6Lװ9a7zt v BenFT.! oqB*@g݊>YzN[LwV8# QnWSvO]).q ?;8CYS΢K]o6CR$Lw>9D )=F@88Fh2;H9l!vGq'z㦾 nau#݁Cpo>9NI @"-yȿ /:L!H~}Lw>8ß݇>JŅ - 7F o\qV4ծB I&n SMy3߸9;.hII,С ԡA8gzY#y A0gz,-q)ÆC9{hF7>߅k,>|e@c=D2 JlqF2(9uH&hXFuskƆ8gR6!Æ> ]Ÿqz "eh -`)х-> B ΅gCUr/C ;xYj G,8? |#c&~ђ7  d)Q -R8Z7Fsttd{7gCyu3 ݣ=) %D 4eygz aHA bst^@ߘLSG H礯Є([Rˑg"3W\-e@#TN$yƃ'T5pYx;-ݲh9\m p iflԝ+l/43b ΄8p#-yu ^}&@ު+b =N(Mz 6@hC4lm+^ olqLЧ+nTC>@λ1ȫ`Æ S!P;mң GoL_Et_E`i#z&lB$  Q=dn`BP;i`Sl2axU7rCz!c ?{)pHU$X稼qɡ< ?{}#]yYI!xA/q^s+Bmh*f6h񷺷8 =HT e$Te`/N5X7>9`Cͺ 롮TnֱD?P̀:Z]]0\sG_A.8awKGЧmfB|HEI!wz`|Bj4S{lt^A`v yH:r@}ؖGGhA8LeN`ɺ}BqK]|{ϗ8=@2cC@="m5Dut uѕuz`liu0+w2U  U,ЈL;zPAGև ) Ɩp}Pϳ%!n6ѿc ~ "-y҅-u,o%H ]}u]-uagqq8W).`ƺ}p]<,5ηwzY@'c݁@Lw8#;1 \8.q  m?9\ܑȀ޺PLwiYȾEQT@rQT qh@o(([=A+OcWܯUBXEeJ4JmV<8za8yVWhЌmё–K ΂gUsebĒrw),Y7ta zQ?eciA:Tpl@X8WUv#K5í6zBƀ'l֥=pHXR>}0cn@~(n#hq bnm|K}gatLygFW kӐc}8}HW~-RUwGQ_wЕ.a&?&=Ѣ0 QԈ}*}=0.WtТD, 4u[< ?[*ea;Dn mdg,QyaOIܤ4IoW Da51~g?o0]k-wryWɣ؞mayQN|3!0x=A}Y$u 3ߘX_iXwG ;(t =~`\y!b[ Ҿóܶҽy\ ?b= q[/5L~?>?Z&ZAsƿ'xtCIɀ[V<>}(Gsac$X']6a3ds=~vB}1,d¾r y]f_HlR>cLcƒaGgc~١. Z\d' 7~82y9ұ?. Z%N@~c@(7q܀>AJ!vpǑ`6X =jdߌhZ…&PO-bZYvg  wN:DSHC-#s#QӀ#J -(ųGujߦekb-(S7a/j|~ |8(o}oSjN  穮xh|9>6'R˫<&h/_@"3y+E5%l 'u4\kx?ϏsM~I5,E9 ~_}=c9fk~~:[|Au^W \S'pڕB]t 3tG,|Lɺ#Mc2GKF3񈏫(Y1wpH{C[[(賰ߖ%wS=nm)i^١((^_c H״e:Z6|vneĈQԞN}e?KxQpmi/??<'$tnqg3\6Kc>ԗO`e8Ot7^DVވ,ڪ+J|ʸ]1-=qFvwaZσKń3z9ؓX13 EA܄k/pycЊ` t(ɨ#j]u-~W@K@<"Вw4<ΟSŞ4mtşD8hbW3Jrtqe1iǿ:@s!X'=(1ʟ0Ox4 K A tG+`X]FC!`Y!8Γa)4cw!d%0hF5Ti։I_w%Ak%3-9?\顫.I$#%3-9ɞk#U:l`uWҝĿNK',Zq9%EXw灼Bqhi36u[GOڋc'Z7iML\G<:pi [FWaPii4R$բWA9n_յA VrHo{<0x7{Npn]7o.);ء en",$n'iCF=Xqhs1w"ECK(qh|;G{6qrP [N jlU<4m4oQqi3e7ϯ<`K,~`v ҅kx"ne ;'{8f/u06aX,9 5ysxMI5ވ7"Ł`,&Zx LKt xpl<}8 ¼6Msy]g$ b?yOz+@]e5]4XI֪_lwU|$|~!0O7k -D2D^.=c'lZ36WK{^6=X`B6n3Վq0j.΋IxV]v=8(dw.ijgl̼X6:y¨;[C$W᭏dk8y©5xPpmeS& UzpSlbmyN# ]"nC3Vqjo]Z8У0荾<؀0Ot!8X .hٗI_vz/'0Ht7 @ </=)q SKx1h l>x@җc'ZZNjA -!d?܁~/0(t۠\=0؟±/qޑjR]6rQPI,& 9z5C{i'rN8OX"W6цV 9B'ZRfr!ӆ'3C%RX#;}R[Etp`-N1R-#UInu%؇؀FE. 9y@|2\̈́M?#^m_Aaj.i!ϩ%Vp2uܓB'Z˯[zIQ/Q=Ǝ^35*Er-f8Ya5;G5Nd2{g"@:ױzK! (og"!.l ( Z8}X^-pu<~;Sl.l2G˯٢ְcJ"wsfwei4B{'aed7NhrQ˯2ϺE~Ui=U(%n ( @YLiV0ZY'{[z iKlS3^R 4Jk-2O;?Śߨ_ӟ7{)dJ;\b ץQtk᳽w=dTғaKW˱UyO T9ͬ3>Nr5 =@>_UWx+9'-\?zf*ևhA2wL_8ڡ(?w vi"ʖ]v93 y)LL0 ߦc?o(iG-65 qҤ /%6`NWR@?~3D!%|npFݐ+?eL Zu 9ƙ?l&gMB\^c og_D5N@Ag)px2+rmB+6 o ?Cg,t-eWe3hiR%a&O6´ `n`{f;p`r7# rN7Y`b:}]z3_\@g*A̲ j{乞R]r 3׀`p)} $wRmomՇc}iDޏ(8{ htJ|i*USC" ?lΘ( ӔpL)B.Pƙ?#ls4net|yҦZ8RAZB9N-)ha &Ry d5)OS"L+TV/by(w9]Z)Z8 ?%H@^]8PTي 9@B@AKf1Lɤ~Kv6m7h-ErC3GNN3u4a9 +oq^} [< JnʋBK]*-^ xK8pzsP)+!ffxC( K}@(8C ׀ZHIj_.խl>l  8:]?MDǶ5\_0?͇.eklq]%{"Q%ɤ>8c/R|3A.g29ץ#bp$@ p+ JcKNlZlrLIg"RpP?*qf? -NA]8cw 9 u*& i%g|ZTiM.C]+غ x3E %'FL&6Z a&'z&>!bi5,d#^e|wۀ&.5bܜ%* :\5L>;_}FA0mM-:-E!ʄѤ~7JP9;$0{VF#6|CPo rJiV>4\Zc 8}Ͷ%@+yHM0'e <CzXkC~ۺy𨷻-h>@JAOj-m0z<mCJ3߯@~iV!~'&Pq4T]oN!y|-C/MTksjü~SiÅ-"be⇀+>/?a(òkAO^['춍l-U!ʄɤ~/]{['a.EiYxd=N1L>Y:lɌ x)Jlz1h9v(G C{EHCk|%~oN_`K‚R쪔-} ~aPBNpC(vCf׼cw e&`RZ!C! 챋1@1}3Ex"2XhI-Φ@3c b&`S.[|" ,4JvoC~w?+Hl-+9c(MlwVߣ|U|j.g%n9."&oQOHZY( G%pu,`PA]s|mJ>?;?l YϙP&i\ϓ~hC49^㟏z.Ru43L8l -f"4?Wu+)Z$LW\@e|Mm,sϽk,nKLH ~&$ k̃nn/qe ֝2AgG› 0E5ϜYo]C ~gOnCC h|t [IɔF^1X$!Nlds-3,J5{-gSx;Re-3,^yL0 C@ Lsp$DyF-f@uz2lnLa7>#Q6gf Oز eg[ؒ3z>H%Hv['tYmJ)(n/ 5:W+9|/Kk.2wvI¨Oɧ0Xo3 ئ1w/0["#Uc]mv?x^-6m,޾c͞ƗZi1#lXP 'Ynp*i<AԙḐR׏^y#(OHPR7m])ƧDə]<̒ ꦾ_|%4o+ПoQf| "(w;܏m{*ن|/U}:ė x> ֮ONw[2[rBetᅳ9#Q.nr 8b$E'r*'ф6$<͂},i3NxnލyBp80A'< vhTiE_<#nvaϦ,pc(vKؙjg?RT (U [*w[.#]v;H01."x9ْʰ K'Y=T;#?f>8gKM A= 8y˜E _,M#Zϝ/y a0f?VD}1PFnt܈\!|2w ?xL#R&'V̋tysa EkpG4.wGF»61c'f":e/Bx&/{qc'fD\Qd\70n֑zjQ#99yGmV,s [JtF#7fųQ#%;֬Q\j6N2a}xfyII1ڬ3ۍ9s$e=Yh^c'(9E=af hф\=e<ҚXv0OxNpMr'nAu7x<+y@ux`6b&2KUB՗0س"֌̶f% ?__<`6*ǚwPDw-M;ڞH[<'\ID2d"aD._~DY35?r޹+q!)@y'XȒ"RAzeN߷Ȉ~(W~eќ+e2=g MA}_?1:$j$zKê{clo!kH" ̂>{k 2*]ǿtyP#K sD7?0hVj5f.!dƀwicH<Fi& #N}`>o?Mx]n|LO"|>YZ-W %]i:69bnrR'#:&<w9e>nmfmH DuUq- jRS˄CΩlg"66[ jP-pu<~to &_Znb'2mﮓ^jg"{cfFxo[w=&|VlgW8   =h5[YkD[&4-5Msz!zyKJͅm X-N׬ A~뺈_eu7cK#0$Jyѥ4 BRڗVx]nIk6ݮ͜}y=OxW'~6?>e a\/Bm0f쮆f 7>Ccg uɹhXXJjPkIj3{"6x>N\ㆥX~Ha4SOϵCw{! րeoafkh~ا::Ր2UV쎔S?l `1GM׾?ſm|Ⓘ |ƫ}[>P4=}cA϶`~,(Xnq1nmƂ+_hc;#2u~vZ?C / 3"N {k7/JEkۮhc^ט9 +?s:.9i5?so/ch)Zc,eQ|;.俊>|؎ϯabs٪]^x&3'fJ9yyhy߬>x*vtؼܰŬW雕gaNu4d_{y ØP<WğL;Y'(0!n ~tl犈?kN<wDov W%!A'] AZ !@o!*  Ho~&AZC3]&VD FD ϸ~Ed_CB#W@wz+\x' Y h ϸ~mBVY\ag?Y, E؂h '>ⱘre,训Dg^*ݒ09[T?#QϦN2flѭ Q{] ȜF[w$a|DQk;pinzHM6f!z׮tFG{c~&mٰh0B Yeۀ#S[Å~MVi[W6E,3ș4dj֝Nؾw*tYGPwORt!UymRm~XkjbZZƥث?cê*y wI~3[HN -vثd/A`x2n=qP옣c?眊b3go,a-9~b52{? zE|1Uŗl+~05\/uK/{aO3?so5[+wr{ /~O+=K__K(9t%l̿_/%/Wѱev,]% R9* J߉[gXcGoK/ ~Wqz=ߋ,NTn{̝ogl}[g?t68qLue> TWt;2WNm$YpƦ5[E.BOѯspxQ /򯗖׿ 7gUF^uXns~Wn˼>,^@:nX2~XQRK~Buzeո6w|>|X1è$J|xy/Z~] <//ug\ An} Z5F+23>&3L Cg{S:GY]!y߬CGmLՀ#Á`Հ*q2 O3:?s @n>?q|?/|hVyҏ»lc7>Oӯn29ndrlZߣc+xLkc~حJGxI&d?(ILA'u({ I~!%a9s"XLʽ\uoqxW;4>GHSƍ1J՛ݟFgjQMdm} U>;}U^iĿ,VUVJ-RXFe +uhJz_%1CH ^u|⦬^znd}??:gML@,nU3oYigi_뽎y-t +xVޫc6V Ec-z.V[cye듷<0>w {#|̶cs /1&qs&FڵXs/DCcvαD f+N ћͥiM(W"qʡ/D[-t± i0lI3Fjqbʬl9 TtTTI2)k\._ ʙ7o}I 0E %q.ypk9:P`渕}-p9\{r8%Ȅr@v=MR/)<3I-dJȀ Ah-G k`jwq>b*y6O}uCpN` x߃LZ;@֓={A49:'vhpFMCQ.G j4+m00vo6F ],s-(V-BOgG4O `]8t9 s Voki =9[ђQ.%<ף:+'Vʠp{WlƗU|Fk aϝT{Sajax"J/1*;ףPH2&C55wDэJk(;ף2+YYMqIJ5l/F tt ||pCҢ 7LgGKc a977qU< Wų1Ȅuzzl\{rw, -P׬g1F@%ar=DrzmCasK il])Y.|sL!vHώQqco -&SL߰PW^Uj 5_K%`킜Wφo^=DrcjHjlw橍w#rtPK6M 8[<ɵ{eo9 svcyf_OG;vp\7[[9&,B-4A?2 2sP`o9fa;gt_QI햫%ɔwߵb+(Ik!5g2MYKzq햯Pf8g@=mVcUFӚ1&˾NMG1Ots~kD-X! -ÒR6i \+.O90ܤ\7[_UtDh^Â*ŗԙ9M ?}czj~= s~%ոhaINi:1F@ef~=:ev* ?JW7Hr|]۵b踖YK]|9e:BbKqpf잠|0B27R0 a|1Hd^~=:euҵ G+zkT2qeh{pvMۧ[< >!ϗ-Zb5g3 [%U?QA<;/9ܱrJ'BmL5ϗ .<`)g祇wM#1rL5Ht谖<9ĝٗ-yW.yr~2qe8;A\B@:7A5Juǚ踖A=LP pTYbLPY,Gr$ZuuKt_GͯA,G\"rwܢ\9Gģp\2p'!%X7RXk'kWPTf?2}-ĕrz]vYfq`;gx P`9:u*kjW\1- 1AŮV}=S4l.)^pCVࠖDOEŗS+`/a~ZO1Je>~=:nq}zO(oÞ\#>M'_m-kyYU,9 A,3a-$9wβ69VdzJ~= 1(b\;_O)ptMiLǯGǴNHZPg0BЍޓvOp_(: ɤb~֑L\ǯGu=vjAY֧4־j/LMڕ}Xe rmmvrejNEM&;ezN~= q~b:"q+g+X.\LO}1HztNG1|5is)|@_=8;7C-Jc/a9b l2q=! wgZgxߙ*LvyT8Ǎ[˄z.S勴⣣lR RQe+OLPăCZR˩ؓkRJ5t#@2Ւ:8crJZmyJgy9el `T~n;%~$" Z9^"Do{<U)JjqdQ.QvqkWnz(TRQB])F ǯG-~B֊{^,{! =k Q'(<[%u5TWCeܣ\fףVi;,3,;;q7_TdzB~=:tn?.xBfix^Ԣt40e,^œ](;1Je6~=:et\q]3<3+L0^2͛XL\ƯGᲣej:]} *Ȼ;TfףZV*D$7vs_MK8Ę_=99i1u&Jih}!Dh88b <)\ڵ#O X=H/zjR,P['ez&~=nb^*4wW=rX? LįGݩNÙ w[c^A-8Qq11=٦Q-㲑ý 7<$2ֲ:8#kAYgWB-?ׯegqK4z,'Ѝ[0 qwo Uk9YgWFWxo(iB8|EĦ볽XdV-)dY!^ٛRKW[/N@_;P4Ŗj$P΍S+ZO$2 ;?] PkW.̃k)/!&'ף e}iwغx]uj9(Yrϐ9-r6%RSߧz$iIr JaNK JY/X9j1!H@e~= U E{Ʋ=iF!yGmGy 2a= vZGz +W7vNUG:(NVαNpVQp_Pi+i Vg٫VXGw{2q= w]}oH箢 4o~7 ¯G:lЬ&p}p7^LXïGgqHCōzI놧 SBӂL*U V.] -Fd~=:8N5q9^DM)F_u,3*a }=& %(Y%kXGRfo\Hk Y(Xh-3+ewx 9KLïG]{Dz=49.{פ%Xfף6wd%`Uf尗֍LXO¯G jXGJW(YAM<8ZQ1Je~=:@ZQeZq^4tez~= Q HI]΍gիV{{drc=2=CCbTsXף`ҺZGz7T $9[Q&ף ;)>OJX&gA/G ͯ9E T޽#_L\7~ )Z)|l /^Pף e"W=ie)5HzxJ03d+;9^xNƗtLztЁA-VtvC²5b2f|kFShʑj7LJJWk؋cTA:ݝ*k>TW.# n=:56~5i-(QB|Eˎ[3NஉlU)/A,`'HMB=|19•ntCg SQǏ|0ݭ`S$W:ܢ\ףZ#_FxՏI~!^Tף2!J`6ΰWtZ'h1_o>\6|@'ثVe5Je~=:OVrC'gثVX~WFQ$e? 9^'xpZL!Hd~=:"T} ά@hj8VrP_BrR::Q9^wߵbyV@wZcHWv$|0ME+[ΰ܃TfףP;' X{rj X{lm*Z X8,<ѷU:>B9? GI9&R _ҸWġl.J(7m{ !SN8*^~U^(*fqG>NƟJ{0uB?0*Zw$^M/lEjԹܽP_lN*g*9<>RJ%A7R׃ <6Į_Z~}7S,?WlWCZaLsc G{6qߙ/{ok~r]_Xrv VIhٺ]sʼna| C瘻}|%y/@`G;jME xK,;ps!8j凖W I, M^BO%#I+2mNt23]K nsBIcf!1&\_KȞk/n(ˌ/WB(76\q`ݻ0W ^:}-_zTm2Alu *lHO*v4/C^)>ihF3Bř`;ӗشFy斜?s\.9sjk%=jXnqx}_iD'!r|ִǼK3?=Xkk_™NDz}m_iq7I)yø]wf.:{>zxװ_0[؅{xŸA}u40C4ngʯ{&(߽)g[Qoa7|4g&ܸKQrwn_?&OoH-+'AOAWa^oX]JGMڹ'$zVOn+ꖥEH)_oT4GNA>Abۧ6ljuYNLr%d$PL6z9a7yʦwF=+X9 -.vfW]ƶQ:5tf1_yn4|{pîq9vG û%t 5k~z ?7OaZϗ2.ɷesmϝz ĕbYkP?Fx%~:]b賅lݽ^ACq :l*5qu.rfb0W٭Gaj8ѻ~˽랽D [kCCEfJ6ե15+/F|K֣Lr j꧑>߮(XؙAfzV\]TqÔ/F [+fRR]~XK*N@aC2qn= &фQ^}ZKv ɕxbPVحG&+5w(p A&WحG6~+g.E ]E 8z]\Nm88FգtTӰ6K"(Xl82^߄':E^?1bEvqjt+%2bRbTحGjlpsJC{I9(k֣jldN?4Uok(P}v娍1jqO]Hb% [;vRH?H-^c :E;4˱%JeznK!9JpϏ!Ndzzt1CKCrlfеbʷQpEyG,2IzA֣6\a_3YzpY`Z[it/q?Bt*& MXZ+_gA}MW1D(T (3VN/7^F%ಾn=:[ ͧ2sz**#q T2qn= ׬!̧E1YX'jM(ת;Al{#?/$@n=:&[p95PLHCy*^b{16uh5\Qz#X"(Evq56f۵rJezznZQUrm > `p~"f^NL; 4:0=(܃H֭G-+9HRJ@u^b va95]E~&[!Jeznw"jH 7Kh4h&pe5Zct]+.Rꯀ)X %n= z2$/U|&+D [{6kYiK xclKE( ܭGjtU4SzocTܭGʋɪhs7jE5NV?ѧM*uǤGW2Ytlw>y-Kʊhad1RP_BЊ% TzZUv퓤Kʬzt1,+ꂱն=ВQ&gףpmz\Tl嫵.#2+t -k=5cܞ|6/Κ)WAx 2a=+C-K)`9T؇TP9V gl^In>%JeR~= B(`[}Q6cLPȯG|gڰ'΂^_k `_kgѤd`n-(8`s2q=%W! ނd\fףpM5a yqY jLȯG!٥"YvhirR{rdztH*or1?Q?zwQL8u\aSKLzt1C>hת>.[}|LX&&A_HZL4A$0,[Y@_;F6CP^-:/\A*֣P5&'1^s1|' D?jd7},&PV}L ėCc`M3,8 I؝wnZM1J*Sq5*69D׀s;3c 0Gi(D7M&TRξa%ףp5(5WܰqMػS2q= wMy(q/]`-dtW'+y:Qz_9FU%>ueA&ף`۬sXzK[vR30Sp_;W)\Fm5r ё=^_L\Gjtofx"0N1HxpLMi}F+ 6k 1[հ U@m-Z`iЂQ&ףᎡaJs.+9qd  }_w^媯Dz:tZLXOG}5{mDŞ<|k{_s&o8eUlv,6ˋ^,kz_ SlmJa{ѿy_cyU̻l[z 1(AȆ!Lul?Ӌ=سT 2ay̳n4mjX cdR ̻Gj`v0|:8F ̻GǍs^i՝7²3 %-uy(CuSz*b]E_LG;'~R92,$cT# PYl/QVzt\:`K;/ Xtd#s3 %2ZDdIpM 0 zzt\'wN _tbPv_Bؼr.Tm`]`׮㯫,Q}N9Cy[ҰY_yc踴d_AeX%^4K(Sb˄zt\NDLjư.)N@_2qQ6E {Ϩ] Jr88C@fף0,"gއ'^-]'gzA,֣jd]4WϦmIhzl{dOƯGhaUUߴv ZiKˌzt1)Iċ%p7K!Ɵ((\ԊG,Y&`ldzZ~=:ۣ;G&^X/6~xφ)(L 씛 س_lJ1&'ף.#(-,K↌Z1><AY:ׅ[$^"K:X`V~0؊Q(sqȆ"=,U^5dpWy#&ezR~= W,,G[,bʔztԴ)RUba,p;]x1zMx4'xg}_3݇f@ڍD<SD,[|vmqnt [KK"a:xD+]0aL\OȯG+򺥈ꫠ5qN-%2+oQ~' 3X:o'œQ[ VW$+=6Eof'ףCqe`uL# qTʌzENL YG%Ȅzt1DNW̫&Qh1JeR~= c˪VY$ k=S 2ayI{OO&*099(Y(\~a$J:.>%coZP!FeJ~=:hQi+HqG xF~= )Gmsl@}ڄ IZHPUX]0.,SW-e~?ai@iؒZkhenƜuQVzneSݥ"$uh>0ECPףΡB'5zoȯA&ף}Xv/j>i.>[qϞ_BtAY3ȒTEU=8 3z}F|zƪI|fg{b2q=6|VvU> (ة 訝!*8Ƴ]bbz*~=:(rJmǡ|P9 6KේMiH\k-@_;&sE* 7c緺ZL!D4zֆj㷺 Պq}ߴb4ztغ)6,R^ ?_c 9(Pi1㋋r`Klu~A,SaȈzlSP3 k9-3@_-bARSUxs^LTOGG# (&.[z6fϲV?c(> ۷)dʑ%Hzt1i#I֭mYnd~Ӕ: ̾Gcӯyh=Jmjѷ:LTϽGJ[vذn._urz&^1qXף`5,KBЈyz&ZR1eJ" *rL K* ^^?+cz1+\_(qe04Q.֣jp&MK}#&i?iU1ȀM_xa9}VJ_\ףKWO2rbOtĮ%2{1ǭKUp >1Ȅztؼ)Ie_ /]߆lp_­q˥m p2q= 7qRqU5s8y8.s4p-5RldgUr݆/.*ȚLïGjd]KldgUr^ e2dz~=:w-Vzm)8ѮJ&.Q,r\{VWLxrKez~=:Mab{p3]WE v_Mf^rsb]r%7o=:z%qͽv[U^/ej4}2q=90YoU~=X+lp_;F׵zzj9 В1&gףP*#5Ps]kˌzt1&-^eDEoQ.3QU }nͫ\LD/GuG`/"|<ڪ9=J+r}p_,T[Uo˪sy 7p > XjUy1ȧWΡOc#@2!uF[X2p ٽ˸3F ɯG csؾZUʷO0c8 ףP"{vyU@bgR ˜zVcYgUy>WhLPO"+٨܅\ QǬrؾVU^eU\ף xqU>WQwIW\LTOɯGjlÉQnC,&-1z ˯Gu#;TWt o( Y(cN9,K< ԽecƘ_:;Y* ^0 ᪸/F%2)F\^ZxycmYBi %UbOt#Z[ p,%, 09P/%FdV~=:-{Q͔xV=:O‡ez^~= ֵc͔xW5ea=ʯGr lWBqUU 7†{`2q=1Y;^7UInd%23 wr 0, eNрen~= d5/Y^xիa=_Ę_a*hjJW1"21t kAU,&;iM(QԂ(jZ1dX>9G;osaBu]'/ eWǍ̻cz6L3B1ԓ Q^ JQcx=ۮ5\fףp}lM4b%V\\beXrxp1C&ՙR"஽ %FdV~= )Gm*7`X U1F@zt1KQ^ lzף`5,]j{)*%JeN~= ),71Y LKx!iOkQy:~=:Xnϲ_ AZN1ףj`UKqXb1# H=unRdu%!-TL%'ף`-2ʬ`tAzƱ7uz|AOKQYc †, y(TV P;#tڥ`'0هl[z~=:?q\?i:̢>#AH=fR m"0L\OGÝsLPcuy#;؍( AZfJA`8<= u[oݯ^95zEzd܆>g/-,[zt4+-˃fYE1&'ף@ˬrԶYBqE)F ̾GcW0` /:x=-Je}= GwxXg-P6 ֓Q}QnK$p7_Svϗ al+,~={ŧs}~۴xp1TϥU0r]Pףp".GɫdN^`\ }zQ.sQat=6,xRag|#z}=:9{ZkZ}t^;hcz1d5YVIJO:Yߴbs?-l |0-=ڶofWtOPě+ʑ;ڧ xA"}cj$ܽ4@ R.(I{6ސm8Y"6I7ޮAK#A ;4Pnx. w} J[O:xŵgP4NnlT?0*w>*dܮ?* +È9[ OϞA̿i'0=ޣLfgp.&!me j1)eVfҘտMƸ9&񭘪i<^o_1Zgg923*Wotצmk\|qgΎo(  ;з-?>:?nWeUOþcpRݘ]!n{1np ƴ -3gpgnY:QSfv34\~zGI,{q-\% E&.blYʄm\&  p6>&|DT4+=l'n2GU<ƍǽ{qj1{xs~/oe_r}+D^8iAUwW /%{S? Hc1 |S\247zgwZΏ5^Dpf6.#t1K~k]{$Ǭ kV&;Y7Ĥή^K5@?,].Im^6g ~(~I}Nr߱ẗ3G+qg 4nFw[n^  fӯ0K BKŷoҮqÿh3VcUT/Zf~ס_??LBeW2 C]ã3llɟ<k:{E%5jW t κ{zYol0ZȊ85)f5;=q-vbd*W=\d$%Ǵ|jLT粸F_PC%QSduF3IJʉ>nN_5(%%qqvȸ9rq4IuӴБacHh̳-`kBA$ *чT }^ Cq9Os$_Mʀ{؞B_UԞhbAKAU=֫N S/,Zs1% 2J);:ҶLPV]Jn7fN==Z 9vT&}m}cNz_ SpMm'rԦh%pT A6ă2(7ovfJ"+J(ъPb o|up|aZˑm݇J7+E ,%[$΅텗qg\i'4$dU`,% mRנ~,_V!7"e`Y.eyZ;aW^R7rjm0C=Kj;LTb,ߩXVB|A oO"Qd[:ŠdT7#K.`YR'p !?u+Ȣ2j-: tC,U^W ,ݝ=Sdh7ܬW1SC:j[$xcT/J6BKHB/$" Ͻ(n[tՐ'aeqKr}AdmЏIHq˪q~E 6ptR5A[U α[7#J, YXy]+7!ZOtF7dڄX\Mآ9}S\>6RZG($?3@bqM2.V~j&zŰK.TwFBW,!V&߉m]Yj i];Z mB _.&_M^y]mhR՛IPOX8wࡶ>^?pf (XFq|$֗C .yqڱk7^64]J{1Scv%lئj"E&EI%+c YXJ?fDЕ׮,.Cs)n)U*+9Vt%w,q+ \:b)bߠbRk$zfiSf#V7K}٘M5f+M_Ж˗(AE7|GZj %y?jÓLg9q#)=,vks)M:65d]ܞRNE0]fz꿫Eׅ;츪,s/b|:ܬ&q+8l/BuK2<i܎uC"Fc6 Υ8v<=&2iSknm.UAZ Ie XѢ[ UmzZvoNjW߄bʊGxBUkFp.IUAoikX)fL&,.ks܆UQٮ &®a:x17ab7iDžM*';kl#d5ȗ)F=:LlcA KB'6dQmfW69O)f+}ccݯtW3;jS}\QBe/(K|')&AtfPlRІxw1y$L'EtYTnT_džJxr OT/l%? {u/HIr@qGL ]7=%W KͰX!XT:aR7ۜ3E`=JSKqEx'IaSt Oiԛp|cn_cnX?ѓMa7lAf|Iu:gćp.-`$vB["B#=\poS{ :;S!nE;V"ex*ןKfrGllcae.XxcZt W(vdJ.owC1DP1x0OJW<+__T\o6N\Jlq3MbPyv꒹ӮccYE+5\6+6Ff*~s MM:=uХzդh%pKrOƑ#5ֱF1AMe%S6 TRT!*9v,RĔt%)]h$@_+5(a~FdNfWt=lq7l|<~櫓"ha r6 TlRTBMs(v`$fJ7YXXA.u-:.th7=Y=GUh%?_SmjgF;l/B 5ycH%*3ݣdva$0Kb} bY;]إ #PSN2Sf%t46bČpLi*D+Q%Lnw E)uaVc%|TlRAݏ ;rs.RzYr7 BŮlHV*8ld` gyq7ΞsEpˋHӒ>f$4`{|c5Gvt)X,%]:>|V\CWQ[e:Pcp.Q+b/SN âYF;yv`Yb%._E]&lmNAc,٩36I, _؟d1?wC93>&vsI,kعF4hZLSHb6$@N~u,IfTz۷oXIw He҇(n璍}$ܩ3t^!SHb8 ]l-F Vr2_O.ًb%a ªYp|b(1Svښ$=6cacp8l/CٰR1*]7%!˼ \cjS^W'dMgEZ,.wisI4M S~9)p -umMNm&( o. _ d8_$:T"՝Y/fWFvyk4W?~1zX k%oXXmѪTJ- lanOiCa')LǦD+Kq+:C7,O살tJu.MddQKRI ?PݰP)l; ]l?s+L6B{pBALZ_ [(&>(~sI$?[Dd! -o."_wOJjC?6ĖJf&$YoF1\Fbg6^Lը7cYR̅æ6&9Kh$6q7lSCm9KRQCeŠ̓{P_F)v$C sG=5l.蝝;(ݨ>E][b}n4uHuԖZig NUad{6́w ;2tIE"Ǡ2JMPIxF{'vYb9i]{bT4!heq ?ߤ}0Ul,tEwQJjqJ:ZgZt ]u(R/`E FBKɗ"Djœ/F8*r!V>\{2Ti>z %CFh$_^3SoG౫Ijwsrľqhz76v*gFBN&&~X \\_0Ob)ibTKr#8⎕)sxI͸z?AtÞJ`.屒r:n C;Z rx,"!^7 #ʢ-awI]n$ KQުuwv巚hkxCwVr6=.B0P][8vQ8S5RJ;הz FC%%펎7mQZK"8 -.p."_0ObQ)C&&p.I9U$>e.%$7Z \_|BP&;TjL mQj1J}/: }]VKkh? l>a]K6jRg/~ Im|Ƣr86ܭ^0.ѳ FEXyإ%(b0P]mW!4)J,VR6kQ^ c[]wE%[k՗+l mI_,G#\ ;V0bsIcCaWzX \lƄLTs}VSelpi} u=lkf遞,R;v؄]jwsM:qId!=K>Z \\_1Eq9VKfjh;L [̞273@ߤ5|j~[CQnї)PFBR]bzX P\_ ?RVP9)oM0讖\I=eeN1MK"Z u8`#7_h0%LZĒeI M]^zXY-o."_07N6^t)F+\;)UwZ-$?TǦ~?.沲d\`$i[s央0 Guls=lv1ג%i&WG 4V>Ŝي[d|`D9:T2uV&E#\K&#٬gznjfD,ͥTzaubԒ8ˤ ͮp|_k%ZzD]bRzX mo.&_}0/hvMY=PĢgro.IОʞjDj$T~Ƃr6}3*-U"5muY56Z 7W:LE7)L|Ƽ,gӞDvVBKo䍙 X_X֪zRFv6mQɧϻo.+)35.յΦ]1 0a"|X \ܷP3ӘڲʖVADvA |ng`D#Q噼 uAV2+lkK9/8,\e~ pN'?k;ֿϫ7tCxVUOj qej9nԶ;L=cx{9.}ߑΙj79ٴ?7̒vwxTOb =CmܩSz쵟zhA?eA@ݘk=<.LľKl<nVC:ű.T=ݱϺ ),=tIdxz<:g@/ -|<)e;S0:7hjg臄7)svA7u?1GQgM'C u;b~hYUe/~Hgz2em Sd]=UmXLq ̫ݘw+!e;]YJؔcű=&cuƎ5P{YUQ? -G'yz܌臼eJ_VG_!)0HL&8|#cTϏOX@=7-CZ}2L~J~IJޫݣpϪN2LLl2}w,"a?VQ~> c]=UDP U5&tzd\g=']Dz^6,MoP VucbSUFqj]="ϺN K칟wl26@F)ǥD~~4ndm&絿dz!{xBDN5Ƴ!|m=ܠN7C^ 80STYQQ?IPj蔁yr]=Uo`It¶]zWg]%OcK,7c! m)W?UYWaߦɾ!ķKwl'eUYω:@(,h{:3dr̽^Yz1_Z0IJo~H3 ?+!m{&^H]E=$,7 ݰ"ϺND7 &Q4|nXUdaS]:~;@`މ'I:<924'#!=2kZL וmڝM⇔7yc\ⷳųҳKRTjI-pFTՉC,nL9ļά]V/\ZXQQXgKz.`)v:i UY׉k=JƖ~|Wg]w=4O_\ R횞]5L8sIf`u ijbꙛ9s?C/Ҙ&uam/лYOQ.$_md]%Ls z. Ǻ`ԋtȁ2jyWg]o=F 5Q-8c¹_S/~?aNïE ةy|#go=d|/] Yg='\_Jz. JMJ{5Txs jJ5Ev }YՉg=J^G,l`kFgyWg]'\+ T_'jȢҹKPP)G2|WGM'L=1o!] n&\&e2u}~v2Ƚ:~?wxVtRVZu LoXF^\TIb^XgM,6Ru]| ȳ z.3{m5cG̊ӯKbC=ogM*<$uA*1%*ny񨨘23k1G1~ggf;.@)Nq;gRT%rwxTTsIj;HMߙTsAh+9.p:Ă@pِv뺅l`ȫij z.?f.U϶\~¢ԍ~\ PϩVQ]5LxsIC}iw# z.oԳߨީI-5nkm55TsI z5TncAP =1j~S'D1$O:S%LxsI(XEW=7j3ߡWCh̭ѱK@Ȃ/E2jqtIJg$sdoLUb"UC, L*"cD❖j"5ϚJz.AINʍj*$5@2uw( xTTzsyҍr oKb-Q agE&6ubQ%–ċ`˻jϖŕ{]).jW^/ѽnָ|7R|$a M_^7߮a?_sqaye7ZUF{72.g7b϶p DgִkS)#W97lNgl̟ pŖ.ˤ|}~u{T=݋CCaQk!lގs*7leϖ>~nd=u9AkzMPj^lm+jFpo:1 kݗI]nMnncMg&'^7_횙RÛgE}40? X^<7O(/;sf*f_c=lչ{Vݫ_~A5L~C59ļ}fnkX>$3Q>s vֻŇ̯pͯgL(sœshJMM>֤;-5~= k^6ͤ+^4˄׬O6`}CzyïT! cT УX7H?5:0 8;jzh(ꭤ֛M֔QSFoOM*_1o}ּ;5s-Aw8'%?;לl>xzz;zmeG9\Q7}>O%o??2ha~GR} |ZZ ^Z­?^I,Xg!WB5_vЕ_=`͢/cWѬ3݉wxOK+QϽAWaH6Ί ѩjI3֯,.gT}}yՕ/En RI7eT2Ҥެ|JFp {*啈/ElWLkQoܖǔ,.ʓ[=DJĖ흽C[mZyeQVpdʖ⵴=4py%rKn\2ެ<"{FM3hu%b둩ݼI~_nnмh}?%9-YBB$fxO,䮂ߨ~%rKsf?~OE.,.3TR)t'߸a˕H6ԙӈG̤;u;v_?f+}˗' \^\RF+oJ4ܱ7G_Zl*]l\\.ry%rvdn2N]o+/-ns~u[_G-n̵+/-n Uy{ǙFl+[ҏ_`yþ1z7_q_AJ'?3F*,*/'.s;_+*p W|?cïn *goְKχ +KNf؞88]La_۫V?}?+lƍvXؿw"2=s1Qcqc7A-kv kqp|tl s Ay}6s=}?Q0 b8>3T1hϖ6~C)'ء܋ko1Q3!7"wn>a%<&VܿP{}]k8Vk7W)o>G|<5'^dMׅ(kN>S#qglQoohq߱|M^;Lv̊qޯU*">glmWz\k-<4 Aw]|}sp _}a> }50GFU;Yql/ţYmnRy}69i07aBW|ʤf?V@SN=SDMCMC>BgI>n(Ď">.\Wya(/5>~pCY/wz~9/k9w}{^=# /]};c;)87n]ܲ5}61iת G5Ϻw> hqb CsSW?56%p8_wϊu~Z {D=YՏo늝'C[8}|M?cc]ZɘWX Y~4/Vro n%|^ו{wz,}iD5/Pea~^Ղf-s;~<|5t*s||l KFmc.׃˃?]Fqy\;e5nc|k"aGaΗm3W /ƨEGH)r̮LmCc񃩯@ S1gEke>O_Ud~=*@ah./bWiX-aX{GwqAsaMQŪr2궢ܮմ%lcz\RhSbwm[_.߂uchzYh5'x ׉y^6b9mG>m4{r9_m+6z݅?˦E kRO{ kVOω>f~ZY5ZՃ*i->!c9~5_֟s8Ѧ#x㝻t\qWokfʜ9s|`>+x[\n1b~'^=;Vnż3j늵kYc+T_WJ[b̫}d/TKZI#ՙ_ם^^:=|ttRo+<KqE9EN?1xJ٪B!=7;\<9.W=]ٱ;m\Kۦȅv ltݔ=vtT8EBPcsAȪlp7(˥TDqiqknr;C+Y``ae!! fˉ";M\,N;4̫dr22Vec^z+]s" S)|)jq.'RU3* dq(o"KW]1Wx"SZ=,27\gf@FK2LKs;Phl]z㗯ՄG4}MڽoN #\.I-6;z?5#,q;,*RԂګR<:! 8+!H)KroYfl?:ru"3\.En8E. ‚ǩtt ?҈,ƕʶ+h&޻ƕyE Ev\S5nC\*(x#,0`s7˅5w.R܁.jkUxF`}mP|Ydͥb v zKH}h}K?K9bAlEeh.Ձ.ƖsG[<*^ʥerjݠ -wY].ͥhgyD2$[s9T4<"[ ӭktE;ÊΡerpGՓ;xf ,l0<8Kb.:wM&s8Z6{uzR]+ridE3xeC=}InRN _.uvlSƟ.0'WGM+Y`%l:i߫}!sו}Qc5zC_,.]$UŢ6Ը3<4-K2pRG6~hl63q f\ OFuaǼ)M\ f BO OO,Kfgǜs mk*E; .Efn>Ʋcs\i~>,21?n!=2XѼyoY Txs)l"9 {dhiGe1z?Ssd.zh&];Cv ,^_7; .IfS\f>(Gcwvv\CG+ .EebR4t4ʁnMC:uҹv.\*_Mdcu^AVF 0'W@?"׮u1͹dNS /3K.u_at 옏kR4/\nG`mEi}qIdfN\{\r]4:]uJOdfqϥC3Zaۮ%{{UC`'%ɕuݮJ;PF8#p#z4E#:1pNuBwl^1bO+ .ED ͶEHR\-\I_p\efd$YV.\nᇧshh5kVE:Kq+:_ A0׉)fUq%bd lܩ5)&ԃd&@ϥ st +<y U"KCeW<КUrhdE; .Exru£q$rp4`0r3xxF;95:7bAja14I?RȚP5v/\̐ޱk.ecT*OWf]. hg%2Niv u)ON Kz5M(wXryj9kV]$ZY\s(<_v-wXfjHG<0\x.lE;L.IFs7~փl&Pϥ =t3U/yuUy `xsl?GݙbBXx4*g;L.ER8u4P6<2$W0ҁo3R'CVR]r E;DmӘr/V(E3V%Hp݋b;gyaZUXV^\*WшϓмKk >[UM* dsI;2L=53V@?"wRJEK Rzu]"%K:K J/Y`i嘡5*c+ \xs)@CëQ@kU:,.$ujt! F!mGZR5@Fcg){~0V%UkhE; .E8Dv =/WeN?:FքC#+Y`zsI02y c4 v TIU?r PR7{r\hjbMV4Rx\o/yB̹yUIU@6pR`fE9^. u& dsIg '8RbLR&YdsI)i T<,wm^vt)^4R}\HN>5wv\|j]6j]_8+ؐϪR4\Gugbyd*<'ml%p%4;\#=#gKȥ]TN Bkʬy=;}itș@@.IFk\yfj(cWrhf,BB䘹]:ե PRcכRCmC"A6zjdE+$A \.aEm;:a+^\.Mher/s)nCU3tg+:A6FL04@@.IR4>y,GӨi.E;\ `(sTQ67q@.ugVqli',:_2yG8 `lRj|j5?n:%b[W6it3-\:Sd_V@ s R΂N]9*spI0BA*Wh`I163ӎh;=\\Pr/QcҶu?[q2­lf%}JQdn}y ,dec59ㄿȳU*EǢCs44+D;,RI Ý3FRe򔪞f.JB)94F6̢S7ts>@6eJ%!r}&˄9 U?4EHR*IF#hd!~,e}9|J\fjE [[(  ,RI,rV[pUۦ4vǙpR2t8 `JR$33,Pk4i4,[LK'CpA}2RZ7ƭxM.t4N*t% G:l Bπ?ic5!;J%6tQ'}TFPjhTv9 $X9;]9ujs1[>,g.- { uѿX+`q [3$=IDJyw=B2fJyw+K9T!T 'd;U2NaX[A{q%p5F~AbI{:=Hi;:!+^هfPH S.LrH=NrGgUc+Yded(xS݃dӪ&P?̿ͪ`L{JR"v Hd܆m]؁>[%Y j83{4Ɖފ+9[]f')K a:%4(q\#a>*$1sYJW׎ 15FE14E?$CNj6 K+-Cc+ d8s)rE/5}1$6(Ӹ{^,0$]DȬn\f_kFXMNu[LKq;e#ed`a:tG<.t.(a2B\ȞuE%U)ʓ,0x\H8I@O_] 7; .IBu!:,xN^#+[}we1v^\|0+F`vXUNnKa+:^\w" 튭1lCO3LKOf]Ki6=t@O{"KzJ 1?-W0܋;NVD7ptB؁ju7m3ƮlmhhE; .I.ֶihɒfNѡ涊~6M`%`0ĺh"\N A>Hx\XR܊*U j܂~fq33 . nHm AE{& PȪoWLKqz:4:3@8OAEyYd:sIdw#)Qw 1r%@?"#C|#ʓ +oedA% b6ڨ_,9p=;/FV4LQsvJ< ʽ mJa-}pRdC-'1CcN**f)pg3K.ݙqnmX/kXDЙ@?"7\$d_cAkᛙ?K5?\ . MBOHᕭ,DgC!fGO^Bv ?~댭~J`,^$]C h% =pɇZ|E?$STrGskVgdIZV\ZCiX'ie i4ͤhg%)bPpmX %'YN KQrgjV` 5Y*JKbOD/I :2t'zNn4z:Oj``WsY@\LLKg$JR~/KiXz\"ca b'rWJj؁VTvDxNKũMJRvN;i+u.$Tax.G<,0=Kj$%[c)-ǥ2# `sI <)JcGW_t ha| )'Wp?G2'2N̕Lt"2\L?;q'MgO>9a Ⱦ_/xQ7]|jr; "9K}Zٰ;Ťv?ݯ|MJN~ '?}iL)z(S.8L M"~ߔUV Z㱲uEr<nIOիq5­?W~>o/?Eoueyd !UZ?4xixnCa\02\`s@CT9aH̹yDnӄӀ)ǟ)5 և̘ƘxߍYfp%ĵzѧ@}|Llfxig">w<c/2,Yu_?9_sp Y< k! ?W~~O!%娲a矿Iɮʡ\WSVܥh՛G)%};u ݄j}n\,*e$@PKA65l]8q(AT_We@a.}=FOiΜ.'|H%;eI4(%jߵKSTNat3AXF8Z,. sIL7"Y(Oހ-C v(oV*In[Xʢ207KʹJ9*2V AٴE*w3YQ GT>,B sIlܔr5/0)S,0# s)0`+f_%7sVN`TN #0$z:SBPS2&ꁛda.TۚL!ˮMZEa./0DS} =S(Ra'JKg檰,NFS\/Ydª5({3S腾I+ dR7Nڂ7WȺӝQn7+H\U͘]QB ;˕+;vϥWvjWꡎlQ}06,s)lfyQˮ0qmC됙f$x6o*(:]-)gW倍vY 4업]aq#הc(vBd"#x"kܕ]96!}$KS}-X LRX2u%Sܔ'6_>Jb9䚬n (os<2hwn/R./ jLj t;F.3f'JKgO ,mE}{ t;V%̥ȞEobdCk E+Y`FSMي2<#z dRd6_Jא.8%TV,{mDw3.IUE;q* V+ghEw*SOw\L"0qR͍r2W@Wf)F,0C s)@bdDl }0屢@F(a.EfM# ^wҢM27;X\<[8ЉM%^9G7?u3ˠI~} anΦTaVR\rcJxٶI[7q˩,. s)ZOq/d,uh2 sd-%ti-ekd0;p\v(AS#c/ ;LzMN #0"iK}mItW)8 TQv$[3hI|e=D#3rg D;̐\<[4 &i㸦JzaS}- dR gBlTaH04"/Rd~k\P6OЕ:cGʌ@EDa. P( .j$ ;ɱVȈ(̥oeKNrNa{klE;̘\<[X5Cԣ3=k؊vAY-]<&>:+*Y/GVx95av7hg]Y*SB] Ε wvSN Kg Ϭ7dwf& Mc*Ydzs)r-9T_V \d3 . )I 8贄\; .EFmWlY3m@ꄪ,.]$"uշ!nxz$EґLKپ~ht d 7BsAMhed5PzRXn2s N(^N C!,)1cI1Sʤ4ǩy(tj\%'#&UΜS?I q#5^g3 .1>6ؐ-'PDvr yEh@8}dTȥ 7L2G{jT V[$[B[³ҳ۟:ȥl؂f 5.# .Iһ`~mx,sr,0XZЫ'Zgr<2~,7>w3 \qt A֏⢎=t=o V\;[5(Hŋ-a8b0RX5NY11=g耱M-`fҸN&u0:hE3 .VVH&!\qc,La.ɝ͛A_uGT428i+=<1q; .If䅒T.¤sqUHKAոKs|SsGpN8v@׸vn\L2Gԛt0U9 \8sIlT04 \vct-u?3JsX3aDM]4uGR,*q%IZ-jV>\ :P;2$O,2$y:1": j"h&ϥjੁ%E@uFXK88d5pITJ9qg;ruf3XJY%Q9e`Q`\;{/\S3 dxs)"H.) N9f/p#Yd:s)0eH/jãԒetLzl'%ɳChۙ\vs; _G,NL$6-c`u낢fN\:8nL)RQ`رAK)h'0")- a8ۜcsE;|KcxZS8 x ; .EV F- ORK34)ic\p©d;6S;?zaM`fϥux  3.SvqhxE+ .ɝk^.BŽ Ҿ1`իLf}j"KW}6ӕ'auR,ENDzqKg3tSThT: @.EV,'X`3XU[,.$wi`-wsK3 `s)0% Xc3tSDOs f\;'d)F5eG, *B^  m0J5F3`.+ άBRsqqE뀩5,0$xf E)r&qh&ϥmEy_07@V\;'쐚 ew<9`Oi=Ц2pR$:#)C /73$lJu Lm(E?"uG}]Q`Fnh~}1UY5@?F-(7!: ƪ^(RPv+XQf[3+uR[V\]D߶K=igWcT{ F~\ GlI`׽]I"KIEBKb[W0 EN K "!A`27?.hgih d1%[ghjj!`dN:s)굢-H4SҒ?{}i@E3 . f놆Z$wpByMȂKAٶi,!q{nst}; .E+䑂:v-RRN V4P )m Z:?LY7 Ts)7O;cfm*\0q,2}$y6h{y}0j0ف[3zf; ,0}$X+SM x~.uӚ働?ZRQz.`xs)Xq]Cw~}NS=Ydzs+*KitM{Na0Jpa&%Kxo (,2\] 3Z!`klJv.U!ztms {2$YHɡM{&=VH tXLs)N-_*ˠwu+bTOa%p%j9NQ⸺w vnX[^UO 2a+n.xc\S8 XsI2#$yuxv]w Kaۊl#w0Wޟйt=%:FhP8LԷx dxs)r]]$gf'qIh:N<%dP/ŃDt),*Z]V$g;S 9w@Ȋf\1숑QN$?zagN%ɐ>q/XҠn{!)qᇝ@?$Nw$_`%{Ac Qj)9$V{LQh&PϥjܥUwM(ST S!2$963GAL,ʽN\D?"S0h\\}^`R<ͽ@'DpSl( Kl6Y/'E15uafRl4LX03a;$+ ~""F_A4iLE; .E3~n,S:f3K.ɝ;&ΔhD9>.&v0RfѐpE L).;)Z \sIDŽSgz~]&jBP)f3 L.FCҶ6s4n)n&pϥs،w?rׅzb_TBmť?yC{c&NFVB3 j\ߥ }M ;p{9R<,d:ǩpfMwܟ$uť?!W\Wofn\ |{堯 Oϑ6{ԸZV>\:VDA_/l,"*of~\G𙣾;yC0㣛&\VP9Bg ~h`E+K.ɝk.b(e\SɟK< ds)2ۧG/ 9'`ȂKB][A]*ߊ*x*}F]#+ `Υj]rU|qv FVtH'hgn)0,2=T -_϶145v±I; \xsIl_*mLlxsBPjd>Tmỷ?,$e/5NvWs5@\I<a'8E˟ M#+\<HPfr< 6woRkv9ÿ S|2t2Z5kW V>\{.p;"EV1;Mt5d+ .]vlP 4R'\,UӺ8sW8g/Ш V\ 9Y;SkCMoh'%ɱ}FtЯԚ}04r?L~.Et5XU`xqĻz5@{?NM/vЯGgmO E#:Ѡ ybԼ_^$l}P6ݯCEo˵kdV:rݣbwŸHý3u[TW|#oI.UхIrlJ;\[SϦ3W4[ WP|s_ac(xxZo&N v.CooԲY?|ib/ +i͕M1S f;zUfg:f;!|c+MuzCKul [d{~xc~wk6:.* Oǒm^_sc[vq 9'W.zA͓^lZY恃OqYu󫜳]l7^Ğ}_6H޳O߾pXo9XDǼ٠Z{l'8Nl w}TcHdozf^h{\?1m9w{2p^Ϝ73f֏o˦ϼ=k̬Z a-a)et?Q1ۺj1{H'§)]t羞i8nk,u|D뱯1okVʜ5s|x\?^xކ cʅ j!OctoDM9f]V2}0>%^{iv_(trT;L]/&O||ޘHukqLh_rvo>|캻31Te6WUhjuY`R@4] -ZZa'K ]: K%0 慺49 r+jX%=8HtNhlrɆ5W>ɭB%@ ĭ;>mythꛝEfM.Iy ]Pg L9_U)f6$wl#+}  97&z wV#n DwkWN's џ2YbO.]H^* ]9ԟ@nڅ?f/6tLeg үwRH" qjm*xrIojw>s..ܔ(Vay-f']\AQWŇ;7;] %eaJ0d6-6T ԡv]Lv75, dDt/\ĩL#MAfABW|Cwj_zVCu뗬iK}7ԧtJ;ը;*is{Z\U@?0- ћJmSiӃjPEQ.aSoƮAKBo^3(ۺśI`kojTj.Eh'iTnW.p̈́v!)ls]ۮ(Ӷ9foqzD+\kK(0JA5/;J3^;e;\\G禡kKxipF1 LjV0g+N5/͌v\ bHhrFْ!̙vƮ( [&i]r ʥ_8l˚m37@.E˛ɾFf_,qKC;.sSI0è3̈́6!0+l0t#OqsܴR4Z鄪TJV[ұ ӖM䭝[0`ʥ7gPu/~herrG?Mv]nuLe;>jŌUW4ò]JGo|oCo8XqXU'*sQ~rf -jT Ng2X\_X<16HF ˥tj/iiz@ Єv}tAˑN㾢I[_0շ8F!/lԤp||t#텀cmW603/wܵMVM1MA:_Z\tw3\4ރS^\l5r6n"A؞iE[Cw2PĬʭCփ, q<8i{ڔhsW7tWf`. }Ь% z^6СvBbcTq0/OCDž=ڵt4ۣ.%uab:8/iFwO8α{]xv6bA4_c;nۮ#>*s)p] 鴭Nܑs:q״; #n7G!Fɪl_;rj2ڄ\MX1ȥ6Bu*v͝9 Fgny3x%V1 :3q*73ˁзAl'K%h8@ƜG,Jp/n%o ~jR=Z烧^hEvVkuh:[hjVY1E +8ӚFq7:lT7~] V]4}21I]̗yZm\ULFzR3с4 Te.jW܇%ɝ + Y*+q;53.E}c׳bx>Xܱ3\ ? pGgT7wjv_4_ 6пuwfܔ57&J4/SV$c HXvh7n 3lKVt.._76=|=3kiF ,穆E;\eW}Ac)ܸ1doU6G;\<9Us2HM"CqFFCπh&K_&)m]pyֵ7%ea' ҹd|d:5-ȏlb.$UAu2N cC:NX7NXy*BSkONm3G%fkTs6s;6fVK,UЎ]yl 3s>26sIL][}N^)O4\x6܌ΥC^ưUf-SwV~l%iˁגTqS.ca'4 w/l//;fNʓ+T} XFRTSu9Rr.)Z~܌%ȉe8=K/?v}P|b/sb43U vBðK6W+!9}QJ)F[ѹuήfNz[[/I"N c8$RžA/fp.\cfMN5xY 7QK,MHSjcZ؁73M؈%Hڋl.Z?v|-̕ZL6|܅%v2JȻK֏d@" +6mMɆME'5vt9`s"܃dJJ˛+KD9&'Rlc{ mt.,_X+fDev}jvkmv\KT=65J]U_Kȱ~FBbzUFhv]ff.nA璍FܮSRMd ㇝@.t.I6(Ai^`vD}6؄%ce`#w IPbhֹ'Ċp#}9,kf}ǒeeFuIbag5йfX7<^eH^ "+}W%~ dlCRddvtwf]**,PIbnfqKrwf#-Z 31Ts7Nb[m;VX07tB:7{73]q%ƵId֣KxunI>,6sI/| ylj.t 4,ΥS-v!k6Ԡ X''iĂ̕3.`-l:X;̎.#\f]3ϛGsQ!QχEVt.,pOF@GoMF;O*;"ϻyj03%TVs9w(DfSқJhs6A$Ӯ{Pۂ$ιjҥa,sILXTϹGA0Ȑj4&ΥRS.bՅqEvέJl;62SS`[6ق(9w>e =Ԭ`% [йdN4g2R=UAj'[V fй$ȸa,IةC[qಪе2_(EJ2ň}aVtV)lXlx$`C}Ntqx4ڃ\I4a5;zF9BU裝Et.Eg] @{[Nn[S@&q.Iu3L 1i5s#RT?VӪxg". hs+RFjwsf@L4Ucn5*i{ dB&1寐 ͨ;;qͽ^L(s)(sCXs\hm5WBqg@3ㅕ Ӫf,(Aoj; *IhfйvQd)F ͸PSRJb:rI?.55I{M1Л2b^5XwYюdU8ݽk;40*C璭:45. < ث?ϩ2\{$,zF+SzO5XU(>t.kjArz Ԇ~R1{U7p'|aToFrݺq;:lXY9нIn>w:x0؍ΥqLi_X'A=}nȅQv^X+>%O|ῦ\1Ӄp}qĴj> LSu _|mڦ@z4\U)SD]ADtq}nƙ}v=&Y,<Нڌ}p9L\ V5+5y/k;uBNI(SDَ:vt6LJ.F% СՆ\'oSj7 dlGf6}YaqD#rҧ,2wsI _veW^ @fg˂uzCbP]wN[rLfBK6˗IIRGdosG С[WEt.I RџT*2pw׭JEJ3<b֕ P_[T܌l%B_0mW@Wj36^դh' ѹd|k$#f\JSnt. .yk,]pl[458Z \\QƦǀ-oWW}fԘ&\*g;NVf껚՘tmjָp߮Z`!͜Mb _K" ='W/B9}Wٶ!L`:_x=~FLXUWf7/?r/,Z5Ƿ%W6:"P6{9)`yՕCbj/L;na~3c i~*{2Ycͥs<&yXrQ@LL5sϯ*e`_67;s~ԼqHf.B&S")tʛN'? n~Q𠅀TFѣ"o:/3Xf,X @(`m~Rsq_Q?*Q Ğ1Ki1PrWoj:(3-ddk^g](%NaT[K |M5{=ub? E8$_ L)j=Tr? f CR5Yu3X_enʻWY׉$xܸ{ްIiF!IOK0=*~ZbB,׻<:t3حD7dqce ̄$B.x O:7ȭ;Y*a9񔹬ʊQ0~*7.~\E.<>xX Oju[oTg ^M ۔j~ O>Qnn>ݚGn-7.Nk,1\.iUyvr?07powp9nЃ#Ww?i'oNf"Q߯#D]{ɛN'ELau|ȳ~{K- +A忕V,F ږbME'\ ]$ZMѽ"o*+G5OZvB*e]((Aɣ~QȥJz~{Mvߪ[ڟ~қqHޒWK|^7 IƢ&o*;~ɥFʟ~Qȥ6=ΑjI!BL\1qp$Q7՝Om7΍pE2܃[$N̝ZwUyvr?E~n΍5Yj7FEǻz~TqH>1-8fN{q"f.+0en`}Y*N_$rETur?oNpv^N_Q$ubt iUnLKshT껪%߸:;X(dY^Oa7 C70]pQ7՝Oa1ywr=䘍곶׍CP=28v›N'm3L/^xyo(cwpL8A|0*cf3NI}!`bTm`yLOiʛ Q}+c~ՉGM_OXo&E>{36 ͨ*ǜ ]UTw?WE"N үFy=u?cg 3}F"xM}'T~`ouyY"St-NO-,2u졵]'I,ҁ.-wp\Fp>@09=uG{a{UTW:M~2Q"'[nd.xMIqbce˛YQ!̠y'.;ɟDnLq'.o;ɟDnz'3;<"T>q@]q9\;8Uw? e ctq_׻b<*;V!d$䦑TagE6Uvb? 8$o<r uyS_?Ji2??i8 #jQ=1M}E!t|!vgqNˡ4b˛N[?)OZ?7Dq.xnr [lsq{MTv8?IFgޒ~Za>@hzTWB 7H7[PZraRZa;$G1,Tv> C0~^mDA{Mv?!dq&/ Q-vgԪG5 v'C`u sɛ ^I 2םnd&ލ19N,&p|`RESAQ7c`OgCMVS[n~޹WCp o S sQNSC>g_kr2ݰض?¢~Lc"Uw(GA*iqjAѝuz~JN9W9 Oo%k"} ,h N~L1!Lsb/~( K_qɭﰟRel?hl[o"a? Qȥ^N^6R5yS XE}ReM8V7ʝ|n&pf1H Ң֎I#Y[=ub?%߾qH 䨥ȳ.+cwYn]<7 T <"o*,$6@HrzN1bq{w#W_.E "Re [qoF\zs)n!_|Yطc$UMe'^\ 07okSUN\~B.q{{.|$7b4YvE}$éKdzcw5yS[qLN- ~.]PhQdzb "#̊ɒ CP3hoj񦢓 ~.ϥC A;L)]MV`:s)”&N,#4hKLBSBM'u?T\9$)HMm'\!?˥G?. ԗW4isEUTs)j+}߀QF{S7u`xsIp++2Ou <f&doUyS 7? qj&0R!rtMpUYEFS/яwx X8s)rh/itX7$0tpKk|pT"ϺN*Q+;PSLsܰMF.\F,7nț`xs)p,92%qj{W7՝dxsy#S>;xz'G?LM?M0<xa=1Nr 0o򬭸-Z~\7;ٹ94dbN't$ëK17nX&oj+.$7R~E33`bk ys.|4 =0)ꔧt ]5Tubϥȁ,覺$w`.?hF~.]R+D;>8#ݛ<:pRTQD=ǍjqN=[ڍg5ѩKSMˆN9Mm'>\+~޹~<,,=c{a~ޱm7z7bAhDZ0T(uaBۻj£KYɵȩ.;L~.븓|?T]xa6*׻\8$ȜOyxqT OuySI?>>Ϳo/Wگ_߻Lu~;d/۵W˹j|s0=ZU,**9k`Wf/,Zo mwR4׫Oz*O3ZMuy߸Y|˽Ⱥyo_?|qvL7_ӷy?o_׈Ow+ӿoU\cG=/۹n0BU^vw>V۵o?wK`nԋ$|t?Y^b\/{ Jޢoaֻ1ּxz}s۽\}en n$nnW}~?>0EÏ9ݷT ulg F|=͚ [Ɠ1>~}Nᣥ/ط}~nF{ꅩ5r;V=o~ze#m?N5tu7V#|M' /^](.P" ^tadçዶ{^ͥOf]-xlliy̞x8KK=eSpّ,~~]B>nEnrq =IEF~s>1hzU-{k>nFd|ȉU?.;pz϶WG;a߻^/I֧9;ĽƲ+:y:k95|*g5sΠe{ /f'GϘ?ƧhxzEGoЖ:Lk>|BOcO7u z| LMOtܦ#Cz%p c?N~|a|6m8z2~nXjMƩf9f^;}yh[fcl^9g_]jC+;|먻:?Qbcn1ۼi>Y~YY7~;ݚsZ+n]+qzQ72 w-r _In/Wt&@q!@M6~{&3}mS^i@GFLJhg}s;;Ծ(2L7E|2HBf?"s% i_I`HHgG|4x!@M6P%YВR# YsމϺ—.li&S,k5UZ#.@q!A+ ld9 /OI|%AGՄCPIP.B'r&$4_ d ".$}%A lDX`B`+l<"؎l((![hGک j_I`й;aى9#3Ǟ.sAD6D;d̙H[1L4A‚+ m<G2% L^ L\H[Iy5ZmJh^lܝ *| ą,K zisǃADeS^k~5 q! d Z ?ABW4xys-k~#r_+J@&8myv5u-.$}%! "EAdZ/ kŏ"/N+a?qiznQtS* ճ{:~}cs?m;s_w+ƾ.ԆW-#69^3_sԶjuN| sl[ŎEך+G?܁kG۱Ah2=ׯ $up[? I.̽nLK?V TԜ:fs})k}؛G RgqdimɼYӍxzvj~1BwwSd֏Θjs: ooc>ڹr dBx񨻤R>sε?f:^[a mcL(d,k=XSnu5/.Jnv^fwruNu2_Sa>FϻFhʂvZ:opK*?Ej{|b˧c M L_OAǪ8b?lh-?|h}O/YziLJ#ozxr(oxH|4#.zvQvS=9f19]mx=/뱕gGz0-kUeܴ}#eB3e4W;E%Yc}f>>~ъ;ќp"j1G_K/5L~l> EG,Ȣ=-u-#c?}2ѧ@ÿ0|7ĢWQ,"cq!ǩKp*ې='8Pźν٘?w`W R*+m' oxÒ:;W0o]6b\P)VIU1ۤ!~qYY~S?|zPzWvs]-}'AWHӺ.on?y`Ni^U2q5.ۯ w ?)Ӣ?>ޘ z?sag;â\ 3>L7j l (ݵrt >DQfx0Bu=!< a-yͨ?wǮ=fd83>_;[W+.C}YcnaX14-,untxnqHlbN,w awX:Xx;zu_1bdKbK֫WsՕ<g]}_QXXG?5X)ϑg(Gx=XS@Oi e<#5 ֧ǤZ*X&ya-ɽCdxuո~>ưI{~&#c翳nv{c}{u׮}VKغ'֮^mM^ ~Y1~mL>Y.cP E t>/Z\C?>Y. 6A7[Sb*"yYrufnܴʥdt[.֔xg Z{w"'\jc}HlPNC/ݨl(rr)(ߚ"ӨBmVD8Z&9$RBfXBcr> 'L &{*$SG}@OH;+b\ |Aw.$h$7Lݺ휷ӎOZ V2Y.|vqBL$v؋l{UlcrIaG)kzn޷j\vTݑ;XP&>˥"v⮼m~DD`z},#חF_|$^Q4]!_wKAwK-+W-MCBo+߯Z`cAy$1CZ.j5vڂ5ly40"k V sM7\stX1\*ڷx\E^޵祩bNh;k[\2un95lkt?FZFTE4+bVs217_9uF'新 8VɅ=ɽo]#(X䱮\ :cSÿqr}{@:Š<5W \*Lݎ}\0uL4[d];W~=nh0pqHhb6-9g~i\yNvk }-t38Yl :.l48LvVvMO |ЪC$$ $U{Y@FXDrq_G8. uVWmZ`g|6t6?\8f"-CNEL-bYu4{41xvL H̅"fc7a>~UJ#qq}gKa:&I欑MFiGZ;[@Oc5ׅiOusH|L7u[K >BƋsZ][d)$kL$zk=[`"-NIr,n,+\N"-ixԕ=WոLI@m|RE;[B-jH0Kaj*#Fq6JP-;V Xc/֑:#--V=cY_[+~8P*(Ngb= ,{wDp\%Pۓvڟ=>qth~fK,'!$S128G{41 >"-SP!f ,)C#6gqqygK䍋H LeA4೏wk%hBHuVHipq/Xou?8@j𦦪?A;[ALǂvIEo$=4AqzhR; ݁)gyx# o}8t -+)?f*Df6bpi!l nx]vBKY5l0&fG/<'x8lznsߜ@$ v%utllVx>''ci(P]DDw0Y q?0h]:t\ Hg .O@+p<}(B*@ٲ~sƬ'qZQj1l :4aT.NVL΢@Ζq[EڦضL87yY 1,8@;P zgKhס)XvJQiވna+Րxo^̀r(R x(x8[%q\}d{wP7Mx]w,YR,vsmNjK@ΖP; V@kǘ[P 0EGwv ihǁ~?\,ѱ9Oݑ{g 11%!R26mXHxL {g ,⧾v܃'?;r+>l  R!acZv"o"bqjlP06gΰz=RZwOjl ]7Jbc݅}ȜhEA"@-+ œƜrF;NgQpΖ̭R6InaUۣ(8LDs vP/$ fxV4N#@mLq١sm'ޛiLUiB >b:5b7$Z;U.Π0L-m.eg:~i܉Њz%|%ԤD1 K <,s8He+;W&wcWK;e O:}gKsdQpTswv2B?--kT/.VkSB bH>l-VbT-988ڭC7E`Z;[2L@?xzt]Ц\XFx@V;)/>+ұm %B<["KkC aigCSMg fcuQ_"J19Ʌ Ń%٥" PqgK2iSpEZk yBJ\|XxjpjrQrT A4I W烲 ‘-[i`=!l& $BW &{s踶3H-_4IZEO+ER> lFU%e*CG~3Oφx.zYG BDR U(?Ful%P gK^֎N ӊ ك .lH|z 0ThMݩ\%s pz2u, sű-Vl/ .1l95"me"7Zp=OQl hY E`Z`(k,lA pArjj\ #--C5ç-th19N“ä.M`JEQ.H2sv?- 98o$Ka7O:ҧmȎ1Kj$ ZQhg1=ѵx溜4ݔ`:*dSvu>#fȰ: "!,cRF8[T<3CdnΟ@)a,ZeiC@ej1*3jtIL~!{ N L_SْäG`JE3hJTط8V"0!,-|RG8Ա6 )zx8klD D[8yTӲ!Bth%8ݤEdnc >+RvHpd(#>OJhڧS:JŘ!i@ ѼE:38L(Ofd'as_,&=zKġcmC:zO9x<dTbBuH*b௷ץZ6ʑ raL3bH̩R c/L,kOպʎS|'emZ^PEޓ5I$i nLUj;V),]TN-'y%l yrR8>+GKh*dh Ͱ_i\& G DW9m$"5gɼMY)#@Q>YB^ZW$&\8Bma@xq,g,5ժjrX*w W\&*'Kґ\ 9Y$+BRjqJgqqˍ/hQ &A#)$[8B |pPC1-8_LIPTZEEsZE69P븎 &q<}(:kUyH+9wʛMb`-[5+',#{87QlA ' hϛRth!M:}m\^"- "53`'t6%%YV38>*t{EU *ޜD:9 wBrqzgK)_5#l},̭[Ptt5#@--Z2k5:JF*MR% 9TjOwڻ8dRKi#eGubÙ|gK䰂s+'J;VfyrGH-kǍL x0L%(&q<]&ْig岵U+pSH zg d ףp>qhE$iA4$n^HF*"wNir _'hql:;@a|L!C&c?3a<&gDB0mEH,= -CVR"0l0,R=jf) >Ԣ: kSY^W@E4`9.b9u` $SP&M{L8>Al JT"0,۔v!hA"L zgK%/f9% tlx WTӶ -jfI]a@EyM'Cqih(RĵBB!BpFI]!"#--) TD5y/PbA"-:eOa<[fjQl  + Vyrt[wq{g ( NzǢiZoiBMWoάb0ĭɂt`'Zz2O͕-]^h_N*̋H޹rYE;[@ 4ae|ZGpl :,qH0+: :qzwJ>"=OK .Bْm,gbNBA^:ݢZDqXC" r=;H4C'Pq7l18$s ThΔF >)E`Z;[2|R$B_R:tozqjkh@`f: ud!uۚ]ż%ibJH;i& ΟL ļ $SP7zqygK&۞[#1hL<728>b*0,nĜz"_)Ե&i]nmˤay/<h%m<}8b Jh`NBȩ:JbK/AP0=w((-fu@BFp1ΖD:'ևgBh:Ll<]^"-D`%{k1.ZuH7ھ9qwܜD}95 2 SǶc-\&bق T 4_X PRM_5(CGZ;[@pՠJ!/z:]$ ", | b`wF0aSPKY]u eG%VUqTU}1.OP{,q@P2o_N¢3i$gJW%ϋO_XPͯ=knF?}^"-d4NsJBmOC紐w1;iRk_[D%"߭T+N1 "#ȋlf~6A-;n0J+,}E% N(~9 yI*0L" s h̭˼IX&j?k%pЊ`N2N0+'U}}_Ig_.q,$`9[4 xcVt`%gA;ɒ V 9t`1T^La~3NP26 :Ek܎eZ8u0 P9$r ,n۞ar҂$@ xgK&ωD_XP"Զ'yH.~ye &H"0>0_:t Al44f1m e[14F溜w`9$skyӖgyHwV`a|E%geW[D`iRcok+6gQqzg (, ̩W(L/fy0o>*E`Z;[0b`J s2CR(8P%iM EȲ2Cnp@_r|f);فl/%Q ۪SPD\+Al%cpHHT+,~ S&ޓ}E%t!B”_c;It\R=sh.bᭃQaqD;[0%܃r`9ul#CE`Z;[2IjrIsN254Ц'xL.m|V%W4LC%B|g@.Wfwȡ(?G Z;[BJ; <:LA|RwZЛmv ցeRɎ'c=k1l[ ZU'( ~+,`溜GSb=(F(LKe@e[rUu_͎/1 D款)xjkS `DyP8C~7⡴t}+gѓOjI׏DžqyÏv=={"g^_ڑ0v)-E-ֿ~o旟 8҉!-!cƒ:U`ɉe67 ̇}C{Ni9EfweX1| y[mp*eꜪ?6B~||Kui|YXp=e>ݯsb";_4t:>mKm翰N٭˂c.Ѡ;~?~?E`Bo n۟6 }z|:  m=biے IVct%M%SP7ubGk^B ɡ"ݶe5mzX!׏kMS"*a?ϊ'xJCܷ䁞mֆU\obp9^6ذޡ|jf[||nxeB>o#f_g~k잦hυ%e'檔-e ڡ}kw=>4 y,׹p-tGdri%ƛWV_?#7^xJh 2˲ry)<UZPZu8DbYdڌi.2{4 _'9.R˲rTkf({3eV-SQlQ5cbW1*˖ݩnL՚IR[ofonTX-K، RIl5C1' ?}(2˲R}Sm&|rieْY'/?(/JOAeg!,["ѫFq^DjSy8D^Y eFt+&bu:1!tʲ%qvDj,GMe ($*p5_7/y 0jejP6c^%t}h@,%dC;Y/캬 p3s3W-֣E5XG8jwΞ mo3[U(:Gߢvua+[BG 6&NJ!<̚>ʲp4jJ{͐Fi#@-,[BEi_@MVG=g:x8J*HtJǪy. DS+tYeْ9\,̦7 Jժ9T~NpqH*˖̵2d|j{! uK.t΃]BHDagXGђ@le4RָW8^0W-唍8ʣ~zt"0-,[2ѭo1ơح{ jwZdlelʺ|޹JAGv. !ti ڦ!ܝ: #ɺw=dh\ق> }(k(q,˖PSBy,k]P-V:P9jv~5/uq-˖PtzL*SYƓ*^ !EQ̲l; Bȥc!.P\e j0y ( EiyWx8Pe (\C ^ t}V.X\-(.&:/~dfEqĭU;BX *,48.ϒ˲}ijUol^$D[ZrYJ 鈹B*.CPq0PvrT9;=*$<]eeKKj#8z>8u7J:2PYm >4ΖPL);B?--j`aIFc]8HDRUn-hLU;:jS_稷0sOjl ~˕TÜ&ЛB=d'.ldu$G]OÙC`Q|DNuq؀V⺹:.B-"O6;rUD cS>8Lľ%vJmL|) ^7:wd]QqGOx_G\T 6?|z>\*L gKT::819sݑ5<9w@WUQI*|2m*s8D;["S3H}Po _dGHEy?y>}~ԺU9TZnBh2]e_EΖѾO#.b`H;ΜE;[ѩCYaɱg.?$"ْ=Ș*E,eE0wŲuo} mƴY8S,yg (52&m}Fcdj1l ZdP(/ 1Ityϝgg!-$bSj\G.]qw[.10fm}^Kv<w2餭! ؁-;E]wy>CY;[ ٟ0mU$z1F|AE;[B[`Δra YEPw@[DBG[߁r ۷r㩷,ْ8]@ }nj-;}!1zx<"jGjJNg/dŇN>Ql@1h{/Vκ]V_d2*GcgbC"rgKdD"0}O%6^@h3bقN5J 3{1.V)dpzi!lD\INV>:~ߎD$6[29{q,s>O;ʂw_;fm}FeV=8H*7UYF[>-1S)L`w8!H8Wb՛Ʉ맏@(w.O!2$>֨P9l$_Bǁ"̝-% FEcPΖ4"0W3YّʎD;[ ѭ =1Ϩ\zFkí76N"0-ʝ-[`Θg$qǓ̧㕳( C-Ν-*giDU9O4*>rz덳(8PD%suH՟;2$NWjjl ݛ3 y %w}, >lUź#ii76ho;zD >~f (;\mT.U#uW .ӂْ<Z(iPJ.lɴökQG: ^s?a=>b~M9V0&uA4$(B5;'d#-蝭BO&n;g\Y&Т7P.L-s\1H[K?lzg ]<Ș*G a QjMǟ>Ԃ<ݢJb=zwSPv PcQX}:[pq}gKd"0W6 A żw SsH5<\2xerqlNi ϸt #ۓS(#M<ԇOS[߃G9..UN:#L[U~a"-VW861|jl 'sČBރAל죋D;[ -'2ĭu .SW* ˕S)?w<\ْ=ȐˊH v "A"-)&|#) oWO=V%tz>IqiWQzg $nΞmbH8@UgK򂣨'(`xn qˊB7--hD/$ YE紐M%ԺEhz‘@ B Ԃ 4tP* G/0uCx m yD͘n$<:ܧuIHrŽ]ڮX*-o }gg -W@m$9\:Jϑ!qlRGF?JIV&~ tGfYΖl"0tҍP+M 0iB[ЧB<{8ڻ|gKd" ̕;G/<Ӈ"--UoEԂZ-oN"-yQqFeW.ZM=tl ]DiF]+J7^;GZ;[@ٱNJ8wo1] @Ζ4"0^0 }ȃ< E;[U8:l{_Q.n;A"-˓;d> n/Ρ,4U?ԢlqiqV޻tΖLteLUlӌXVz/r@PRrE% D;["pho\R)'n/W<alD Bˍ} _- E --%{2 ϝeCw$nO!2ovLm^y pwdVO$2e/ Hͥ`ª g~"؝-֫Ez͐g$=] ֘&M"bi3H4%2w(^["98}D;[4pJY#Aaຒ~?]N"Ν-Ԧ^hJ$Rt:Þ~WΟ@-L 1iF(:ROmPK#ט_T\ki~ϟwMϙp'HxG4x^GXlH 2XJQ#S򠛚;ZΖDr:LګߨRPvlW2z1D6z׏ZkqpgKhcyF.;PDr"=+>]^"-W`R:T׼ߨ2gy0.&2bw >тN ;Y 5էE;[@1)G/<|L=_=.bivQ$LYƔ#aBk *z|(<Ƞu#;N t!ekhxzz")77Myt"+[2'bʑ0pHOPw_b~y^ Y?ʪ﹤|%DeZRx1`ws ZWgv_-_ilɜMj!Hߟ+ilܞTdLYHXϘ;q|& h"бcQagGZ;[@1 &EJ+L]wQ@m 3(!s»?EZ;[2S6'S ]6P&׻3w`nYSQH.<G14"-&19"L>K|@xw@[(6aғpmfbrq_Jwfh51ɨGW{!lS IFM߀AtQ:P ygK,"@wyFM_Gewc/All&:O,pDΖID@dd%AZ㓇w@SuSIFMSeZa:wK>"-D`UA9a.E03" -杭"ew3yc&iP18PD%KIFRS1 DjQRv$ߦ O~D {gKhg #%NHmTfyߔ<.Ald(jJML3j*c7 -3Ȗ>mxΧw{ߜ@&=Ƞw򌚾@j#(P|g h5%](1\6C--MFRP:>lq=;w@[rL $6j%"K1ۨtݶ Fp:w /2 e'רކg|n/Πt?o%ݪA"[GfB_=j沏wc3H%fS G=t}P78PĿ%t0̙ [9㖌<w W(5g2!H B פVh -r yQ]ɀAȲ׺'}>?]QE;[0ESiD٫hdJf#Q#@WvO?#)ZGnDábʎ|ɁuO|v; #-S˓l5: |^Z;[6fPPcOQWYaN[{m?}wbw:~ˬ+1Ȅ^ןݵU}ΖD@pnNyIZ|qql 2h=&uUo%BǑy0$NfRQǼ5O<Ə",-Lo$r%^9j>WKļ%ަ#ID!ۨƶ\岋KޅDl%%xG>a"-"̝G^~:ȫMs\]W5} '1+w岇s+ΖޘGHFCty;]8#ق^ ʩbePCC% owYY y%ڼvy ږO ZCkQ:An=*եкjOQ JZvkHC._~Y2RQʕ[H_u7jyd[?vZԽ_dZrZ/Tÿ4]_4\HY;mՄIo}o?9fRqq?~p%,Z Qg{c7]$e.I[PW-Kwpv="8)Z;-YVɽ[ն`_f`rVGKJ[W>-Ō[!pKeNRFL}9f D ixk}$JJy^o. 51>Q6hqˍy[{RT ݺ:MX<ʜߟW\3rǭ.}׬pma{g\7$_;CQލUd沩!J6jK$ZM5Gˮpik G,{7>F'ǵpeT]GebA' W=W?%mnBm]rqdzfi 쌤^;۵"E(h>$Bі=ֻ>v$8T_/kooolV^$[^LM3\ݏ9\ΩzA7L~U>4nM}/}{jm `gG) (w%_ks81ŇXau 9J_ o):RXKn}ɯrEf&|SITo8as7NR'NNT\Tx>'fٟ9 >Ń1F_R}7%hT/ &^$h닦k )/1kـ!U%ߢjxܔɈe=l?||_ _ OK/rLdTɯ,(D%G(<%68`P_p Qr> J.֫z_9-I_M+B'KHKɇBWR)jatfh bYaWUWF´$0?˪k?eXփ0< :Ezݙ(.StdpA+%蕱 N+{|G; /`Ք ee[(||Tm[ 9DiQg~٣8{٘d/΋WhuhL%rnu (1t뵡=/FxkRr ӵĆsrq:Y ^hozaU'tМKJ)r^ X&{ywUv߼;VIXMbwqk:q[91hiV/"0?K} E^?nU7m\=mIV(=kdk=:%R z†Qo;a9t\g[h$.HoB_Q+7MV7Mtmh.oi!rnE_d1!Zrcv/Bvο=][lYt1!,U.7fF+XA 5e3B[O7Γ-zcQE|OyzjlLzDu[4dE#]By(9ϲ *}lezGdK2f*(b:]=};Vuov !<^FRyPq6EWd9!DZU,m|-$ eKоכݔ@/vsҺhh+y\ e k=!~zcv+kݏd}D˾_]1gWS9Zke.rvzbG٢'D,>tdW8鸺tYuqHCiOur;zwl]O2GZ"R8|+NB%MX!ܵe +ˊ) *$W(bg >Ng-:# aLvFV@- %#o5q`@Մk륜PEg݆>ѧSr/lXu%!,S5fáEdVӇmS[ѱ(o ܲ,U?dѣ3tȜ!²j/pIDoO9km^V"0-s*[08$.bm&ոrTpҦ% M=f҄*'=\& SYjL 8p (k6Z\{qѠ+Uq/vYgƓUԬ4q{5G@JBU]kΔ?ztgEJV.fGe!BJֻ6@>֜|pFcaXSNrT&^0ŧl"8SRqf.JЄ{"XÙʖĥ9^ OdK`ei^)֨U7@ϩ+{|rz >ń8BTߩÇ$JˆDgK$ :;# n :(Yz(g ,[@e)!8eP]ZYI{G=#6iحP]3NH}XfF0x8#l3M@ЯbcJ܄xԴm@/8hh~ΊT|dG宧@4l zXv:cKCQ婾_iJ\CPi&mז+@}Qt]8]9.BO,-[DVr.YjxޒIͳA"-[ e%!;DV5^Ò45Pr`Oioْ)?$Ȝ:eq4L=%5]2ȢB.\t$مE\W؝t T9e1 O‰~tΙ.͖L \$dL*6 cOiق)+A sVv6r~Cx!žHpJc>[@(8}fi,!X6]dTe.L+"0m4[0e!ʗ,3fa=od.z,*||GڎfNQYi̢ڇƸ-EJ-Л3ϗ,.'YuKΖlU;-ݑ|kyKKaF`9L,V@]jDq[Y@-i[ ˕mrchUE!uf* n,tϢ}Ñ =e=uƼy0Gbф .َidnr;\:zEE B:&l0zc G1ߏ]f3ؐL +gՋ} .B_l4[žjC.\Q>:7Ft@g-d`uܸG{0mEQK1s^.!.rTvGڽ0i6 !ylfȲE]5RxTQ)#mf +mYyN}vj3J=}(M%T7) A^.#{ԅ4jCK¤xAPb>*]%H$O3zlYVLsjF2LR1xbB"98Plf ( m$RR%$1 "0-V22[~U\5 ]L}S'.},Axb#t6MEgdQ!1-:Ø읾QfT{8Pf *ӢIubMS]p^(̖H˗oU\8RuF?;]8U@YYكGumiGg,t z" i1OY:rh,8RJFdJS d)ϯ`;;|(6KqVSV 0J^|bA,>KdxC8ݜ|GmfĥRX.3Gҡ7ǁb4[@fGe!a"b#&" m4[ |e1 n r2pgRjz Jw}PW.vbg0V{t"Er} .:ʣ*ZYab4[2vXU.aJòJ_A蔎\mkf ,'1Vy,3(%ңK>-]4ȗ*&9Ģƹٛ~5D# ѥ p!t"+2 dhE*i_. %j{ FeOkyH8%I76ldeGizGݑ|L]0e=&q MEoda#[ONSreʨPM#@m4[Bv\|;rLSrĨ*q_ YKHgxd!mؙf+Q&y|t%!n[=O;meE/Yv|l o~Ǧi芬&1Dru -dVHjeސ Jlfl%1o1[+3Vn+ T%(C\K.%[o!fUKCW|Z|r8E0ŧE\*rc3@Gi 5 9U!9 džQ~AZᲨ7ǫZLQbw;p٢/e!G eEkj>\mf di~!@_kc4[ؔƐO>V$ejrs "o]q 7ê%bOB_>ȂEܻhqaj_.|w*eB%)>Ži&l+T0rCN'_-Zg!hH.uRcMH:?oް"0Y+UW7Մ8ve ^-3~0e *4] ==viDn<@y~^ėkQ"{,w=if JHd'Uw1nA@͔*RŗWn:*aU꽻 (nOa4[tgY]Z;t(v{Ma4[eM#F%ay]F }^bW3[51G}Y1]MobC:sr A&iPbeM!e6oTTpC Zr,_^i芊w0bAŸ]Q=S9br^q:イ*.' 9鵪BCOZaK#@mS3[@{'.%\bJ>ZP,S.~K$ w 16)jIuQsðM-V Ȯ_\OE]*jq*at`u4nul]%uq^ĥryu[JMExT9V%2$B\kb{٢7*ߵV6f2\n,USht"0--/'dO-@VX0ˤ vpFPE%L+C5]4Gdijtͅwa4[tרW]f:ƜjE`ڎi`.+j4o*KbӢ x1D‚|re-۫B5nċ&m|OEJVIB2E}s4ٗj_TĠTBf o-U:e>WE}$|\$vMf?Qԑ]d\҈~61Mʢ.`:Mu#tGCѠ/nb`_TM">vNT 2h+^P¬ROl܅%ZUE_dR`jxO̱,,z%iHsD})~lћ~y](@t溣PQN0u-,1e!\PU\:T]2z|Q( eDYur'9Wтw|6pШ|7i+E芭lEoͲ;T &Hǁb4[@iu/uQVBmLx]7>9%t6[q͎ަ])p(~<,-`/W:ۦ$ OE_d]LN@ȶPth)-%!#@m5[2CTVRۈhaÃhHYW8F_G>Y32Ū Bɍf"a:I 6PEwVg5Jn-& #@m5[Bfy(@W (},l" aP\;. nV $4%v\/ZJX< lI B?l4[tE(UaJJûyhDqpq3͖LCܮ)_,gda=#rL҈Ǝj{*Kԃ2 PiJ(7I!ܵuy']Vh2jTԭ8i,PʠވR@*ܓlբVJ-TkVIqn,Ml2fZ9٢nT4rth$:>M /Zr>cYmHԫE1uU >a4[}"3kRԅO.ӶM6|) xI)QeRSу~te *?cQƓbI1ݞ&n"MР"`pq}lїblmc":u/ >_ZBSRu.=\Quu" m4["dM(09CF4 ɪ̳+XHOTq}u&8iNP`ZI9U#of]fKmlP r~^: ypqX;JdOYJ-lKKN 60 m]/(S]Z&$:Ո2f":VU$Ƀ?k;ق(k TroQWw8p4 efzwiTV,w I#ܰfx5Q˅]u.!!җ\mlYP8=Vn*=7N#:;\&MW/dLYrHeg[fɒjr-D`;Y smIXZC fpnڰ<}3Ǵ7o:3zUэ;PTo <4]$M)璪H@1DO/Ғrj: Okw A{=sO=/ȠFU/ՈIˢ?tsA @򗈤[+X@3 ?̿7/XZXvJT"e8 ه?N2Pzf( }9xo3?CL }b~TuKCģ,8@iCnk2|tKZ]|ͺ&'ѵ;ۅ?Je5&r -[= GD6c#x} @-zv8F7̏sd~HCj)t qQM#ZIGՎ![B#xoCLj%Ffz묇@8Exo'62à}o-}{Ji=ZN~RǠkFf:tϋ>ոxoC?iadUk6m|ӈf:bE@W0q0X@^-Dܣot'0Y)l{3 ^W"Ѳh1OW:V$䦢x~ҕ @* >ZNB??dA9l(P@c;I!|` Ky@O_Fy;}|gN޼LkD`f:NC@ ~0[Q!#ƃ,4⽙$sn~Ux@ъt'1 3I]8ЏcWOh9gٷ<}k{3| 1"z W8}7bȼz?xoOh簼XaцVQ !2N`Zg#ZO"!kk@FyQ";IŗS0шf:@fT ¸Cg+O[B?V @) 'GcM#ޛORqڏFȏp׿,FSb nt觲eW$cvDOE3:C}*iplǣ$"fMO3#CCc;}ftXopsMzGd/9{`F<\䧒<{}ӈf:SIor xo'kCBKY xO3a4}Tz⽝~>vUXPW ZŝCs> #CT7JM#ޛImdlfݙxOS :IY<0^cLҪ!/QByὑ (W=2p \Iccj^GfXzfPEOG+O3ofh)|P+c_ h_@?U5 @wxo3?5ODkۆ >l%3z SEԩDo+VXq;@ n*=*=hGjeЄ,클64>Źkc^e:6vf)6,{nߴ⽝T:0t e+8ЏE3#AGVӡV%>huw>k?֚>fBr\YXc:S[N-Ft+\@gVz\K~&d{# tFS ^!JwiԷF7ӡJAX֞}NJ͙h?h{;dsfZc%}6⽙d~,1GK UN~ECy6Fr&eT>|ۄFG~,~ ]{bK&g߼q[m9i{HaWAq@T83 tl9, 3Ve3VktjqCL^8 S-ԫܼ}-V[ҸxUڏ3HH&6j`HP]fDh$^#~?]MLJщׇ)2d=lŁv0o3E:7]Oy3à&%*Һ7xo&wg Ai>pњn6bKh2mDGf_\xqef3#ΖCҔLM&7ҙΖ̃HUꃹ{#[I&~bB)0=sZ;[@PӢLWtE%0ՅwHthCnO"`"_"-Ν-$hr޻uMMt,xDΨ5zo-ĝkE% :S܊mxo%pgKAiu]j{+il?U`PT>uoMF|;[@ОeM#ޛLpg7A~=| oĸ%e;E!V~߄ówU2e>Lل6:قy_#I(f(I s˅wg߆J[%##}D Bxx('{e}ׂƒ T}~Ӏs#Ζ'}f x2VƖPs^߄FVM@p9<)گvy4w&!9DngK!JRn^|ӆV:Ԣ>HtthW:l7قI33t}hil<0M˹TGC#[I&b>>8s`"2P -_HwcPogKaܕѷ}!ҟķ>8@ og uڷ5@'Zp {L>5fI7щΖhpsl庤5Bh;[0̡3_.p3~o{+il4D`֝Rt>3C#>Ԃfh&U=Ζ։9lų ?ilR'!`6$vxz {D D\p^I?\O݋D'Zp;[BeU]t40:ByMt%05#$5腱i{3D;\wfqQBWfXB;[2˜e?MR>3O[I-0p?MR^^6ཌྷN8w, l = @[o;[Ĺ%o呥\ц w(ށ~wuj^:w&_b{҃$z?_tRK~韮]s^?]Ck?Ï?[ E(37Aܗ:뿿mH)-Q}w^6.z?6 [35qEqW&.PڐOm<ԏm>|{_/y=?_wu`l<7/)ѸޙrٝtmmO}ݗ9+wjNz҄WïvxHjy?qF>6I4fBd|9|Q5)f2U'֞MD˟/`/G]R$^ire˛V^l>(.RwJvEeem>o93W'沿o[JD[kE?J{9jZ^F-![JגRʔ˕הoQZHCȉZ߲XԌ +\hz~W$p\JaPYViu̔NS6I~re&4~FR%w)P~?$8c"թ% ~V{3U^+NUju㡏K(?OU$Wf[#YŸvetEMS ͯ;uѬO9UxN5Sr C+ҴkyǤ.*T}dc+>vzeۇI8oSVL' 4Dgy(yK!}"׮8_iawwO/0xڪ5_φ 5غ?ok}+/k]P{VͶtT:6M;C$oW(G/?5t[_銾9UI/_?8}L4|pQ=Xl*n_z24xK>~i4kח?o?3ۥS;tf }fT˓w?w }>^;+Sei^M9QSDx#a鿐rV2>WҵPZa߿~X+Jl%<qllUxEQǧd1@m+L2&";!{ن\7TGI؆#=UX6OeKw]MQ^=xkz}&S% tN]dq>~$(:a'3_2|ʿnqGJV0ǦZClXvb]AurA 6 N! ]]®ҵL_>8a){Z;+ 1&E TV:_+s"'1eh_;ݺv۾e{"la \*U~{|'z{nQۑCJCZĞquCߝg#k+mtiHS 0vkO7sY\o._i{u]on;~:W8̨ŸFՒf2iUxyA=I_],n%ZR&vg 87KR)k{lwùb3}rɉٷ}OgwtﯜeF7kٮԥEw_W~ b a_uNǷ͕i>*t'h2~u[RFGW~EΖ[jy~}P=+h{`+s?~]^SjHJMJW;*U5_@=ߧV[﷾t&n?NN^L թ\MNm'. XFZ|۳ۮedB5xmyhWԺo(^ iΛk MB<-eUo d?.&^A_x7e oDNMSׅhQ\fdHiTK(^\[?TG)lmn&55V4 ?`d|[%4'Wڪbqu[;QSkwZE=SAsP-EE |ٓY뭕y&&,ptj'] ]ėb/~EJ/9߿l*ǧ$)?-em{ڀkAЪ2#.: :>H]E[o HWg :[붪|RbY.0%T?}6o<;oy~8>9՞?C)nw ov ĸ*E 5c8w+%x3h}'_>LY|Wo;ӍfNH{wYޱ=WrKŞxžTF~oV鿧z]BЉzc9bMj+]r/Jxx9vWnnK*q*ʕj5_7_Wƶ o`fK28 򭒭~ȋ= ïbl'm3[3^bhGmKb1[rLrŎƼ(IeV^MÆZU7me` Xq[U,=+}Aj}ȶ-b+26(k ya:8CƖZ ;g.kfhvYyƯ'K[*Ssle sPΤU\aL^pW8z9\lidK.)&!WU|aJm 6*d8tY _:nf7rceQ!SUY g 7/2i%uCP}cS*?l'%+ =*+~]KϯH[~yق 1gVߏsQ/xif 1 `K`bjgt'"K^JnR|%f:PTpl9MÛۊᙇFg;fpz\)a| |ll &fyNroήS+cP+9de 29pvoPʫ)qz?n '-*[i|DRW\kYk5'b- ^{en)k^8><~NTiY~rH7\l>N\ܜ\{HД-!'D?lIْLN۾9@ْmzRW

  • FT|Ml~0כ6b6r81-yꁼ}0M8c[9hآVbs?O [?[ڋ\8H/tsF7kl+'P\mgZвq~?,n0"/7mĩAFnЛ-86&2"ْ c`CHx]Nq6*a4Ά*Rƹ%vùi4d@6-"-W -'kWntrϖ܅^0z`Wa,el+!#-7 _Q@L2$5dދJOO [?[Q%ioR3K[jo.j$PG'j!l Eᕅ*b}j|Nlpsg˃8]>MF ^Y;'[C58@$[Sj('ҨVlmN6&oSnlm7z̲cmi|@ 4m|4z-+0 E,Ϧ,Npϖ\k Ӿ,>M ip|&ʒɵ/oH܊n"趝Y,gGiOZٌ'xNm_Wt-fz_=k=/Ϋ'` /KoNȗ)py[`snlISxōԾM/kl0Po9y]YXIK~uφL>HM[?[Yk<Ϻo ל+9duGKI,;Xo kBSLu6 \ g &ۆz $;U<&4?ZCF?[Z% :Gޒd)̮ mC?hXBYDn[Ԛ xN84pһ7+^`P fYIz0^zdsbE7ll vD]Y<95);d+!0i󌣥$ոg[:gVȺX R dG<u?2(E?k߄ْ@Ӗr8M@kH>..BRkv&GK:6@VQ{O_;j% u>@vϖact-.8!8Rv&Uq.Ȯ)GõG4jKE1킢ذd-W9qH-N$-0*_ +c/N'a [Q+vedР}[E!V/PP8a [rQ|VF*Wt- VurfۆvKmHG) `Ȗ`/FŁn"Bl=c [5X$ " 밃&? -OSȶ -P05/We*66r琱 EE1 L`j/MD0xW%z% La]&bAdKFnU3 @vITjz܃WpϋsåVjH( ?F:YZeԋQժq~PJ\ݏ6Kp |Y`B!S*Y5R$,|u8FE>wsbE7lBPm`)d])cN2^Kg\Vmc' T@% ƹm"Z̴ ^åSZգ[oi2-©m KB)YrP|pv5ïi*S(YKO C(Y R|Ԍ\9F KZon@lblr" \IR'Yb70ϒ˖S.hٸjž `*D UDU&'˚l-wE,E7 `@Ͳn+ +TEㆸlĊ~b5ђ<&h Bbu!yE(\:'fLqm5R5Fz.zH_~=怩,~a=/vkKVNlold?[˲p*嶱s+%\i Y39ܯ(?Z6. oE8'V􊱱8&,B5D՛RQVrLqYÿ2tLfOVzt o]KXvCv=hI6J ;H]5pd7l 0DXcDjIMyXWF1|FNzB.](I첁+z9\j$ -XSj IU>@t͍ج77 qd ^6BRi#}Zŋm܊~6ܲk󴫍uW i!_|@1n"vY]9F~ '%m%@--ښrh\+(QZS0Ta㬹3onl6_[CXCSs26/N&p-- ™E} U *eYnqlJ UTC+CiJ'Vϖec4-$E-MZs _E;'-򟭒EP<D+7g2ղ!b*#-xxSo"I!H(m=;W.b&--xNXHRpp2i]^KrMu onl.(tY7ƐdUG~4ņ@SgΖҎXJ[ G.̰F뇟@ [n50I#l=)cqX(l`k̛CF?[|ZK`T`Gm{UcDsˊo-i-+XԺ̙77lahH6:Wᣤ1$)8QFn\lk̊~قܭm!$(f<},7k w@t`Is,b`ٸ007?N.gK2>V8)*nc4!OY~ق[VV: 5l)[MZ?[rX] bF*`l"Fh` ,7jJv0V %U(h ` gK 퍓KHpp4l 5p\ & ,[(r_oZ(,K_U@.dFa-.k嶁hϖdTEewotC6̱ Xwrg b외Imm A%p--:smiE1wH s!#-(g!Ekmb#I6Κ>tZ Hʁ:U|̯i}7?k߂ق\QtΖY/R*yCazM:9.bق +$/T#3 2sk$3د$@--jYS,T03F0k̛CF?[5LR Ca N+]k[4WL۲8@$[SH)*`mZCfi3O7kl0*XCIЩanW6Kys|3' s:'DTT aY4O,E7l1l &C$WfbPfWe$V QfVTDo>IKZ?[rI)|sh95]+>kS:Ut`LN T ˆ5oìI3o~lI&Ғ*7r{`3+ d gk, -r@)L.ЖT{@Vgns6̥P3i"t '`--T>L :̌д-2bقƏN}bә4fd"%ͧHCG)ކy留r/U+ju)4C)Qdt>H:bMN#[M#U6lĊnآLEmPT ȈȍUKysgÑҟ O8z:X8LzXvp+bG:hJ5 j2o^lu.kXKUwEH _+O lIgbU,xtꃖJ.oUCeGr*G#ObXϖ`b&gNPlH`!E9OXϩk,9drDC gNPOw8z P gK.)OFXS1'u!ypp0[,łHF3kn)q$SLFL*dTk}s&-暾sؕ^9;qji Uƚ5oLE'-- >NJbN#Wִcvsg Tuqzi$ 8_!6Ԛ;%p--H-Pp!@6̯44qvE?$386Q2T$ 5l䧨 &ϼ d )EC&'v2UqJj,&(ԊnBl W,+lxRە/C*dл<^ %YTw􆡼ݯ+MJN쬇䞣ܸ'ZgG5gM_JZPmOW5S\n)B, 0:mlNVf kR)&¸[bnyu4}~<~7g DL+T^)׃#ۅۓn_\6(ˑ> |*Qݗb~2xKuM8/v8׏#g]h xB:IӬ98yhC%+WC^ CWBj}Μ +rYpN}k mS98NӬhi9+j x!P)qH>zX~}wįe!N~+7Es tlo7)srz߱dj񃡝'۳/bllc1鳅lsm70v_kz>; M̝vEW4rp8ƭ/?\i\?U'Hټ Tn<|L-E!{SDj j-\JIZaoj35. 0,V O琑H-ޔm*7dԸ\oۖEBFr3O ["a {e+_(ԇL0f4lɵ!E LrM7 @pO74lU)鞋ɏqY/ 'F=GO>fK.BU㲚^Vf474lV%VVaCKO1؜YMC*;7Jw^&K giB囟4lA޹0$WIѵ͉0%<]^ʾCL VAPtK-kdRF1)9a҆x8PfK(8L k[5wZgޟ_YfKIS%;ۓ^ȖG-\|ԛS|JQ^s#daiNmޡ(&G7ly\w_~ԶE&R~#`F-])Nm/ޡ`w J 'm3?[%{,̵ʸR:s:f l v_JZv.ewIWB((02ۮd\RϬZr`M[as`-Xs\#cLDj\- {u\6bUׂlELM}b'U-&u4@i\[P^½ֳ.~8xaS1[Pȴdk3{+^{z dKd6kEQ{1" |RtH-gyF.Fi .eܐ`d$f wqbVGkO ["a$7=PB\`BiEC^4Bc6.4;ޣj`z Lg5W?- wN,\psgKpE"kqC/9žԋ"BMZ?[r7x|dN{y#]77{\˔4s>}Q. dgKS] *wԚ61ؔ.^bقYYNKWȃo~lIFfBu+܍~ :Nj2|G*u:pΞ~qvsgK0{7\oYnЬYݳsJ7gV#<[3<^cqVϖEI[9p1pl>2s"-?=D uoK_>CO'jlIe*IZ&w#q&VsX4N,s{*MZ?[ٻyehB*aI8 -'a G4jkj&j`pZE/CFTIT\yGn\É7?llA gE渪*U8 P gK(:o>C@V8" F?[!: g%ۓg_;77llfz$ LՍc9CF?[yQ@҅ճ+gPTά&p5B0#8![xr9iYimyw4Uϖ\]TTeZBnl!E1)xRxrovϖX\VTd&زwTp2قsaJ(&2lL#P\0 `]kDCjit)8,ֵ0n DF7j_7A9Xiucǁ"-r!{?nΪ%p-ޟ-W.ZVɱߊ<9j!#ޟ-2YޔRTrsV}'8\ߠv e pJACp_WM[?[I20:Zgun{-r޼.bْ N-42l櫔Yk77llf\tOضS*#Yi0!.j'lkS;+gɞnԢق]桧mO3l>權nآ)`^ R̟,嚔iHF?[w4S9`ޜrɼ'Yi%kVdVYs\t49/)HF= ,2kۛ@ " n `F?NgK8i] C`pt)»e(w&-C+OIQ_[fkAO%JMs2ْNv[1lD-=5  {+eT2m{gxe&%@($Cj˩cH&m+z  {Ζu \q|,:񽟃Ш<oR;t ~alAfEȺrضUn 4JE7lc gj[< XgK: ^FVA̐)E/F~lAn>*2ye̿F@`$ϓJy`Bvj}#oI7`{7'jL4rR} n;*'Wtϖ?gJ0T隉yllAVQx8= \x^Lꕶ\vbqTίϖdpQ8 eB^\3 d gKC#ƥgYn󍒾g4g!#-&yr`B6.ri>ΰ'x {'g\z&XL4W*C(g?l1lIn' 2<, tF"-qnqR6[Oߜ]KZ?[pwg&y*G\-yZ![#bNeOʼlA׃G`qUrvY9`(J-\`(>̖dS^) L8(P.qpC?[McR lGߍGtJ];<.W~bق$V.{Fe<"-wl&aE}`srE7ll5N.tr;T.v89`D%aA(sC 1\iheҨ1k⎞mO+|(_XOZ?[;OK@&kqbQ`qsg qb+ wme=S8 ` gK7EWG+@e~eZ"-yXG6mb]Vކs^E7KhH A6mrT ?D8 X"̖9^^!9)ᆋe(#઺"-_\T0 )i'VtϖyF.*e27@.قIq7T &Ten"YKR4ά'--' i+_MYs \;řy.J]){|7o~lIfvzd0!O`8(cP9@ l{(g Vn{Fen?GS.9`[EC%L5T|gkEa@zזk2$;eyEE+k-w &`>ݫ^F4@ VDakmQu(!%yt7ґ6vMXjjF7ll '&|cz81xss|M' J_,'{4V{GRSO [?[A}k&NU<-!/ZOZ?[;wm>JuU#/.\8vBa*V(ϖeʼ=4fo A[O [?[äMEj7d^m_7'5&;T BY}(plduxUˈaWf; v'-ޟ-Z|0kS77'T):>2ق΋Jե%Eql gE%yxb恩_N g Jq%`--=v@_~5S즵{Lϖ`toS<j: XC:'>&p-蟭r_du.9{^PU0TPMEϖdvpP^7/0NgG7?lC =W%pXyycnْk6 l %s3K_½(.قjS/d.%ZSHזS x+9`%x.&jx^O=Jmˉ9v䚓z˫hillI' P1؜\"-?LVQڦy=xpϖ`tsrxHcFYKNlAUaudvOW7Cٞ`qjE?l?%ݫZ<򿺽?Fz(C08@ {JzK Ҧ.>e{osȖdKY2򿺽D_sx{L;u}&TߎNjtr爆Lrb湤 !(,ۓxdt.`_H:cYHOU{w>Ml' `aݜC,+b!hUэ/D94 KgEeo>"ْN^R_+ˡ`WWe  FѠ}Ҿ1?SV[!րfs{' /wCfHnْNn;u{e ס#ޟ-.IHd 89YCHkg | ^ @! P g n) q,ӿ/DB6D(EV#S"؟-S1/2.hpL^قZo)uqVrp*ڸL- ; "̟-j|0 hI.0;84~c& f|x@l 6GJxqz9CF?[(aoMLƓ5l6'UpϖL a"SdLF?[I2'kkS?g{?llAa.5Y&Scv\oxn6xcϖz򻌼LAw}-,έ%p--ݗ`JF GjLή>T_}>-'{BY|λ>x9|}ȋ`ZI_hwSֆZW!󪷆鴨poe/ ]֬do+r/^I&2=wx;YU?hVTZԖ$&DUZb"m|_bz@Թ1Nl \XfkKuȥD~?;w$ݿ6 j;4jX‰sʞ61:xZ:OF?#LLs:HK sr}Q3~paO{xl:樽n Y)+WKsڪg}C腆P_Ƚ?'ֆF e6N,Y%ާMX?^Z"+t` ^DYVc'_>ke)0?R+ x%kb}|Mr|ѾH{k>c@RD.譁bu95jZ0%y6ͽ7WV{uvb Urkm#+UgWAmj?l70b Cm0YGZ~EɿuJ%38 LKػ$d6R-X(^W Io#!4%(+Xc3t A٢[rc[\)(bs9^nزi{rm#%G8 r~vsʖect$|Xca.a傰-`ԡ_nf}W^~M ߇1K>kۆ*Xן bF!.![ݜrM[QE0.l^WVj#JB9B]_!#([u"w.ll=v O[oetn%}oUާ8(BŧnE7[۔-'n-b^n[rSk7mm0қXO|mCѫ\oDx:fK1o]C¹ pkMNWXS0 wR- %[-m p_?]٭,OFeS٢[lO`\liӷϫ[7J݃/琑:-[cHEe)1(5K~-:gݐE3Mfe~SP7{֭*;m,hՓ}nˏyv4;ۊAVMZfVnc8%`c]^$k)SJFy6 PKƛ+ ٔ웳[!g/WK-z@ʦKhbWAꈪ e7^ʖ` \l`]ǻdGȮIږG?l_ق8'e6*Ղ|Wpua"t]Cu惆})+rc}lY_hخ@5v6x9X$eK+rnc|w ԕG% PL=hu!R+na[|+Kr @r'@ʼnnfEV_.g8'a77φH5C!7?lY}ق &W=N䋂m]lv qfյLRʊ_FY"]dێ΃-Ke`:K1 ɆS S"e0[pu"B2}Xuv.qSi6~pڦY7fNM=񽻍8{ ݲl[͖) -e|[l !ۏhuHewS첻]ޛlIv׆ *R؄샚]2=QG4~b:B7\?mNʉƃ gWpe)٢[VO얮g\D1Dm؀+sHyd]9J6@*dźl ޖ}Tl<fD'Ɇ}/]ȕfl=n)/QC_t"yuL贳8?c؋Ŋ|Kf !_ԂPWֶ !&m7:[u"-iz*Z^a.G?lْ!cK:[1Ȯn*v!mT~ˆHqmG faֲ]M*8 lѩS)уT}3NonضX.*ڦ7==rGYw!/琱-ɆX%w[X!Rbdž{qmp ue" 4_߷&(^6ۛ'ۋ}Ep&&˷߾wR.>!c3:[氅dG^fH\ >y[򃼱&$sÖHɱOyruiJ|?jzOEg^E8R|˦_ܐۺzO/lP&;\%(†ݖý.v7z \(Ζ\^8 G78s7@qbű ]4, s܍Be[monN,X ka 9~K8LawB3{Cg .)M&u/߈P7y X d ,)!FooQ!8cp ui$}@SbCv7KΛ;ql͏k`:[kze&S;A•g N%u$%W+*U%t!jki@9?A[ˌf TV Y< {t҃NmuMp"b8eA~Ǭ8qjpV_f{n"Ϡ]:eN 5/ڏ _EkJq9Y7|^)] 2(g/l ގ#c9$]dFSlmF̃K&sC:$s_VYf4 lZ7(DW͓YqXFǒX}Ȝ@jgHp5!LInCގf+T˕U rN N7XJH åuȕfj*Url27c䎖HF$55Gƞq,IYp}s`fSSx<6!Jlٱ{905YƪVL/5b&7μ|-=^̮f|Jɔe18-!>ܮov;ұ$Y-IyO}4ޜwoSb8%&Zc_tj2컽qQfI˘zㆨ rgΔ9kXV2ZNb6Cul8q`lGRpq<$>cC+ Y/׭*lGT_%&rCq2g]ǛwdlU8~ v݋39a&}cu܏%%:eFS/|mi]uaf}ؐIhӗl[Ry3 Xl3_/ En//MG3LJWQ՚knoz ss!Ja3:L)1{w{q\lERS$Y16EQݎ}7+֜ӑU0.͙/m ƃvnnڛ]-naƒՒJMe:#tNb{CZ꾙q`lDǒ[PfV S,!OadcK6Pxb*S%+!L;LW\ٌf}T[)e-Air'S쳽qs$SU[T$dBhkkZ\Ke&73}X*!l`a: gzV~X\Bǒ\$Z8iLYBQ-9`Zl&iA,KS$3uŞ&Gg¤ {lov\KVJ(YkՑ`D&; ʒ2t,;@1eBk sj٭LjbG6q,I)4LcV1>fKގjliA*t'Τ@r͎cɊ &) T ";/Pr4܂%2oZX_&r he hFkRm0'd0UY S\ΔuDG{[q&ǹR q]?iLZVm_dn|Y͝])nAǒFRm[>^Z)M,ªɄovpTrG3\VX&4eO@q:Z%Yʏ7;}X|#/Ф-UM~28JThܙql1 ЩԑJ[Vݍ3OfL~+]XR2oZ߸V"ʾ&$ uKMe&2͎#c:$fEEef,Vݒ3 of Pk`uk1mˆ 9Ul{3UuL;i"ߏ7;R؊%UǪ& VBFڦ\v 7$Y,Qu.ԫjm1NJ7+AeblL]41זl, vZѱdӴZuS,1ϲ'2GƆt,I ƥQ\_ @9ؾ'nhǑ)KF]L:ŶT<`4nLimYOhXl_Ne" 6jq[:RIJsb:Tf ;s&>8.6c\& 3K}hET%쿶haifs%Krӏ:RZr4++;n &>h&7aJ7n7j%`a҂U%ckRkoa#K3SWUq/hbu wzW!XfesgKNb׊tAئ*$|nKg e2#:vT`͎cɊk`# n{@.ۮ츽dIR MqhlV0S]m9[t\x3,SU_*3`Uf5zmʩ"aƆۛw#enTkޘ-i&dFkZ%gXR)Z,Vxlr[t7ܐ%Ia1uitUٻETڜmov{ƱTLkʔalqT[d}x+.μ-7f5$QoSsg^ۛ]-nHǒ՚bMb֥V4,:mQcnqؓoX d(Ư*_$3l[r[`{V{Ʊ$W&,F@[n2kmmwRmofNޘ0LUn Yf֓T$t,Y/D /Sv[59!;vZqXlGR7-7ܒjxۖ$֖#Sלy$k0v-&,j?N3Vxw$X#u)=R >yu@vѱT2z֗)96&7680vcILY| `h[R%[VmQl]Zeo:v3oŴ dx˖y̮cz5汚ɄofڐmsιRt{; Xqk/uF-&WLl՛*JVUwZQ7l.m[o91vJM*u;iٱdEǒ\UW@L`_m&لםNt,ɕi -.6dݍPv6[ѱ2%ęt䉶EE wۆ/&UحN8S|…&H⪅XZ2Ma5pe*ӡ*"rrΩ،%F1`MSd{r[4%{;X*QEu ZcQZIUPIYoTg4/fj tɶA.L*XR2Ga3ruiLӾhNݕ g܎%2Ka5e"ȗtɶõ| 82+4He[:Xߋ%)z :e<-AuOCgjR:3X*w ;uhXdg6#.vez~-念e.Z%og׉ѱd^#BXMq8:(GVt,$e>,zFD#of RaЇc0Lyl#˺z;&kgWhZY*j5&n땵VގcɊhqj<\HZ*R5JrEŪM,ɕ  ,񴭸! gюonR}'^#Y4L8AI;3NʔΖq.|!hNŵ֤LQ4mXN2Sa5be#j%6n YPOi:;mX jf4_`D8:e+\ f6ı$0MCV 7m7n+e3v+G̲F9^imN{.iF;^؇%%#&`9F$+TVD4W܉%2_a6ZRE n y+0ވB/v50 Sxe-u'nA;Iwek0_9Uj[q+kf\KK*LFp 9ulE)Z+oesKrkڪ(X {qiD3Xlΐ+~O ڏEAu/mioG13ZoukefI<4imm ԮT9lnX4a;cJ|ys>C=8}EwVj^-QU2lwHB4UoDPd.rWܚRI!Y8}n}˺X{:m#T/0ł}6]YKlzwN$*Y|<+)VJёTrH ukkS׷ag)̓CrB0&,[9_#d:~$T<8 _Ȥ*PwW5'ˈ!W~tWbȻF$G2~Ԣ< 搢qmN3 zWёWI{|_OOUG?NGCv w.ÔƓ^!0fRjK @3Ѷ*yF'x}ϲGfCʁ+DgݿC2s@5ٶ<˃Fwpr-<5'mg0eQ[yaUcQ?)3w/o"]ʃ0 7xff?JeP˔Õo IgI KH$v}#<4?iFm"஁?Io:Nr>>ׁ!0aj5uPMÖRaHɃ (1`>rEeWQyÅ pըD"܊A1lb*{܏\w~r[FL1*]3UWL0sq2zR~[~ GjuڪDٖ?r}TgMBn:;40r͓oIys69\s SG =aOATĀ)iH΅aZ❮{kOPczON3Q™AApʛ~+:f X6#Q?/~|p[T`&R:8 #$ 6/*!``dZu0]\yp?s'џ!ЇG8'W޽UGɟ0b 17#mʃF)*!a`:<,0=஁?3E:Ky>ୁ? x_+vf6n΁!ШQ O}5;G"3 !a$ [.KWȧ}8ૂ?le Fb7W5'g2Om?QwfM?]yp$J"\=>J>+aG C0lrlйɃ!1257;؏*?r`?I|p5cs,L OO5'C0O80ޟ\ypWe8~B:Iҧ3:F֜x௑?)%v{'G? <Cow?~w1vKoi:0yza?D`u?9%~T#x&7ڏJgb?pot#gɃ ~ MYN͎~ 8jwg9u>G~V 88$L`s ௒?wM葜IqO9zgj vϼ4YVۘ/f=988觜jڮ~Ps~LPeߖ"`¦'SJ|1&uໜzdgǑ?%?*x[9|jRǤdfpnSiH3v˃Fs6yY^<|dgg?f?8=஁G@ ߌ)&,\$0 !qs25gS^<8jO70 ÖZphw)Y[#n4/Sw (0LoOFj&~pHfA1˜$VxȟҲqTdn;*pஂ?&N`h}ʛ1R 2Y~J~PU9Ʉ/LQ!Ƀ s?Jo~`.Q8fַs]%?7? &~m>9a?% 7_M+86\a×ILw+˻+Spܜ~W=q?e ;ChGJ-O7b?& ?(^ <8kOY %ڪVS`ueJ}#~K;5Fxȏ60rTpY~J}pHNkWjdeJliS+qOٶeʃ b, vr߲vvb_*s_ȜNdrfGO#X*Ջ؜l ޟZG\䏥r #ɃF",8S;#=௒ˏdUsT?G9$sH`.zOQ×X*qHbcʃ s( pyX*xcUr-UÓwg/B֨*/ƅ)xԨX0c`!8cTw3wpƝ\ypW\菥dJr:rQ!×X>y?Ll&:E5dvxpĵX1׃{yO5.cܒ(TKqY4~qz#TV8[}Yc?{3X9d.$O}h~p௒˃0:)5HɃ,vr>B uX~W Lm|E`,tBAa15 |'?|5,cd]rvS_ed#Miڃ!_\%ɞCr(Rғ/Tr69σ,}yXI-WC9>YŵX*aNH|%W%O5.c\|rt'of6+<5Npi .(T B0na,V~,8 T)~_%s?$g)8ꋑG/ y ?<])T&F<8\nR8.%"\OXrtpIOU2cyLSG1vZOW8kP222WUWǺ׌|^ tW],UftM\c|> ?|;z{+UkuᏑ2S,mwzo\Y>VMCwJ-ɖO ,luW{2zXUzhwMx=W<ϜD,ry>v|絡CG /}^9 Io/d<ӳV%Ͼ?n\ޕ+]w.=;yH}]oJO9gľw ݘuL*3f#? |bԶBdԫ2C$,G$c92$_p)__M$H$z=ay}M?zHuAЍ7ʺ=7[I_ӋzIu%~!q~{\_yӿ4' <>8H8Q}6nz1awi8+K?oS;ʣw:q_z汗yɩ?ɖ'{zOoߛjwd!KވF|vٹ?oɍ)Rܥ~&}v= *t-l^_/d-! ^x~-R®\.>?Kz`G.GZ_s$ZgvK?yZkJfrtᯥk'~ie=^LWJ2m=52,jz|s]oĻs>k 2^yMgn?.| %~q.T=^M0܌'f?aWxߺay-l&^ep\Vlz_2,zCxNkk) i䆦1 {߿}9W?Wiw_5+^Vjv&Z}罚4]~&зOj}Lyۿ7-:nt3˺+JX3ĕw&+kϩ_Vʡr~[g/9s/%&70F$2SJɷ\*׆Ly_ol2}Qn3>գ/ W!l蕥_,2}]IߥumH u}}.ׯօl4l:>_ܖ\;7ܯy,}Kۺȕ:>?W odܒ|ۼe:-{nޯ׭ynUb]QW#_I9m.9[orhDiM]bG>~5pEDK5䞣'F"kuE|%+v4ES:V`4+YO'\״1fdL|Iʵ*2cfQU"x_Y㤩arD\%&4 ~t&]cl{5'jre/ X-dF&k\_oXmw?}Ywp|W=>úwb uX_R% ʼfs#+rm,_Rl nCyiP<~|W0|K9\b:yeG5<~xu7m{}Gx"y`/џ؏u4aGoQnV- c=]~KNJfr4o:w#R!{*uHzux0b6 R۶iu+ D?PS~ƫT]oKdZ`|wW {3pgT6: G-檈!SndgO]VI~FtPkQ^+[v9;C鯟U=G^y{ '[k\ss#~q\'G;֟9H^ߊdo灌+zJN䎒v>s-_8¨JvRT ?cOƷ<9y'kwOߒ$ǃq%k=X;Np;\`Cx.)qH큜%^ѓq%׷"y;z`-#[}pg:鉩TMlo%[vi?\X|sR*yIu%׷"y 3?ɰB#y ;<[$;şeX'<z<W"y}+d(qG>#h坫 =-,S$+oyr@NX<DŽrAp#{L=rוH '{;d*xu\΃Dy0x0R^#yu%u>d;}ƹvƷ<8y;t!H.uRA^ߊdo'd;!Ie"xKcUcW ǥ:JoE@V=;<<#)~ˑ;o 7(y0d=W"=c^ {F^Ix^eF;ĭ_x\_+#*2H|וH^ߊdo'd]VU~xœ-OvWXeZ/cZp-w}'rwehQY_9OoM'G;?!ka>c[ӧq%y Pׁy:2{%[欵v^ 뱵q%u~=)br`my\ +f|˓d˜,{Zt+ܮyVqMF,t$T'G;YYTnNjK+$.Jt Xvy}vx3JXڮߜڭOG;?!k7F +[} ʌoNF;3,̠,q%r׷"!/:iJ,<}kѷuE6 IlV^~Ye!t= ֕yO/ߴ%F?v?r RXe9$ %{[[qq/KvU®/^WZf[ּ_u͛{˲òvxӒB_Y%?]<\u7]Evְ[8纞ln|}nAz:e&5}tgl_3Ы],e2Sn=|}^3&%Waw;N@M3ưn5dOoz,[RڗOwۿs|NsOsky)QR5]5m;: V5>ax==vss>1g?x=a=Mߵ3ޗVofaaן6&/:sv*};~]~5%}jِH =!f׏)_ U 2mHߥl51i]؛9;{T3K& b?uO2:fQ {{K_ʷm0G?c'I$}K"D:7U 's\G쟵#B] uY|gve֚}[W۰H/ef Ωgm.[~ʞd0^2L]~Wm2*=|c5чMw|r@= ~|%W7&LnZu KA0Ez|ɰ+ 0$ |.}ER1 0 e+?ֿdWdgv+Whl M2jm>R-m>B-߮x{e}ei,l˜( )_+<3ʄVLO3KOZ2[Z+{_S߮L.F-><ʕTo8OLHX#x3|5C_k QL0/mb wFXpiIxL[|^̉ps}n oM+p%>_nWFMΆ~v7V3$h/y 4%KxME X 77AiMivWm+ J]]QsP'̛/o-PwZr۞%D߯ϯ+d#nqz|Vtb+ D"~Y(j*ahZMּ%k_eqR-_isv1c='o)KOљ_ŌZ }mzw.*7\yv_}^m#Ϡ24s~aps|[8Зd& asW M'o>@i5ixiWo]Cպ=!{s^~aWt#_oJо|^y섘fz W|9+'MĂ}!':DW/ Xe}c3"P/i+@zYRNӴ Pb갰7ey)e,L* u27xdŒdd[u|xZ:#CuKm:{;@X*Y9U{W+J82cINsr=iF+&AJz,h̋c[F2ՑWl,cIl)Vu bXX܄:~wҾ82c/qSsuk2fb^&s?J) ʊ C4/ce蚂E?3yJngʋ:",̄@9H=IM0߮ LX?l2cS3;+(x6+-دÎ#c?$3EּL ץ}Kw GŪ,+_W(sRo44Ւ'--Bov6ԓ  r`,,)M ڿŪ,؊1cZFmI.i.!zZX.ǒXYJ8| oWzWԕvݱT@ =KOD1mTKގ#c?$W淦CIPЮ%^W‘OWv-gfsKNQ.ԡ4";vx2%gqKr=viY=Y`ҽD3_md+M;`aGnm6Xrg=֨{j3JOگG`,IN&qڹM,y.B^|i)X;Y3z7sB4#yъb?2& Na W YMr,\Փ3iMf`\}/=8$B3/vF,,jnUjw+b?h ddD8wYh`fsKreja4֍hdz7fƁKOMnI{,[}7;X\fK5syHKӞ87|AQ-bγE>:`,D@e}Q._כ`ǒ`YZڹ}k_$Wƒ,Fq+:aYPbW̓}˙\R}ڵde=֞5)5Γɛq`,R+YG`v G4sy;Xg\ W'Ue%iAiWԕtif6k$H@mOK+(3'@}pfT0R.~[:zX.8:IӾl0Wcxhrpʯ4Kp<閶™q`,RmT /ArE^|lE; X,E|{imoNshgKoQ`0z4-k' mݴG,BԾ% '$b+D#XE ]9f6;$X7.MBC[;\@v9^5vTrG12V<҅ьc &&'dR\Aڷ:E_cRc%dnRɃt893-X+kFIa ͍5e'|尲X\ļ%2I:YmG95M78,bJI;׏!ۦvY"SҮ82cI22"T{NRHHf[ǒbX*Zѱ4*ںb+`iȃ,oǑKЮ5ښ n,_nt80cF-WZԜpHu(y#EX;o}a5!-7Z6˓,oǑK%&%u䎖N\_q3hiyX,idӍuhk)$`.G3EX*|$ sWDٴo m}3X%*њE|e6v-;Z4Ƅ\ of6$L.E^z!!8k/lk80޾c܎KOYDpܢ!6 ܑ;eX48NKhlM ؝{<&s?J&fx*!%|6 ,O_C{3X%K3I Y0ۭϼd,uB dwvxv> YW.smڷŲ,ɭhW)H7S[y2l%x)%B wH34 ,BWю% ;w"WmIZ|):Gƪ,I!ΑL,W2ڱŚ,ۑOZ"Fz$`9?sXT.ǒԑoew2$V 43l#%hfT02=kSEج+YgN3%X; a rAJu .vh苯.ю#˂/vA.4Pdz]ziC* zEBVŚ,̌N,='.t4\%)A`Q.jElu3[|M ӇGƲ,ܩb1\ ҮB^G;V,U=+'2^ΨQUcșӊBh P>yR~Uʧ5IM%ɹфrޥ qQȗvJO y\%ɔ%)q5H%zS,i `K{\ *&)3yOTފb?E~yi)tqZYjT$'#b4X%72=QJ$kvB0#Snl>CIqv s[P '+MG7X3t$m]N}7!kT͊G[_f6:_l}_.Kʖ15<8*Vc`yfx^rdWuq`,ǒ` Z:7zW*pUB|dogK%+d!sͮ-oǑK!;VK$*^a5U+XZ:lGMa ]*w4Ҩ607;FSX*Y9X]oxK+5f l\gqKr2t~ڥd`Uŏ7+X*W)U;d#,AM9GiE\aǑK,D1 -4둂Η(oǑK%3.Qt BEjGcߜAG3Xlc^PE;WwjH|i{3%XlRF)BMI5iHz%\s? V^ڽ^W80Z#kj#Ik77Y8M/dNގb?JVN$f, {;%Xl}x Ɛ,R*!X͆b?J%\:F8kx*#UY;7\%)ڱDgg5%d15&(؛q`,ǒ`4JU2Y Fˑ=[q\,RX/7w,GR XB̛Mz,9+'_\GѠ@_qdR+-KH.G轎FcjT:!^s?f(w ܘڕD[kH $w`qK39eiLmeYHy3X%T5$)yMHU򉢥3X*X1C;WpIBXvF/YAhShǑK3u@[j$l29|AAϙ"T/AWqXrVTRz؞\box2gy3XlKuPnXͬ6 jԱ,LNXeɒt~ze5,=˛q`,ǒ`TYmy ][kV?UMގ#c?JVNԩ!Ůnv/ogKs'_b~K&/TPk2[!`f$0zGZkV?]ڽ,I5e 4hi YGhiy3 R1t41OreiR|ufT01QgYGrB6vA3kt Ԏhf6@?l]Jv蚵uvNPG;EX*Y9` ]܆8sZXǒXR:W3S |S#k T.#* _i.gYBryBtmiq5ˍ2IvTrZ&Y@TYFjl7+\f6+$zi3Q !+݀N3Xr):*Y,?`ZASkXJjx4\%iگjXd{@SWmҭ)؛q`,RH?zkת}3MZKgQ]i .Zۊb?䣷vFr ]ʬ 15:nH&s?$ Hָ 4Uk֘%.MX5kufCcлKhLMSqe`rf6;_eS9@Aj유4Ԭh74tcy;UX*YvU,\ǃI4%_{3UX<Ѱ!:hgVrGl,c؁S;hi !A&\@L@X%ɳW "(S8ÂjvZ*ڳ뒎< |F!D\M]vbL]. i ]J !.+9Uճə'G[vLەoOHL=(U7>gobRePe9." ;x v+<ns{g5˄=Z+Tydf*.`:U9ŃӮv`ly -5Z,-[] Qbwݾeq0f}Ǹ[zooc:gWU$s8LCKoϮoY`[^eC<1߶.ktŬrT _p0-a'Mg<Su#,h.}0FsVchAHG˒}mװ MTc퀋mە-a/ٵec )ԚYRM`@,u$%'asozG$O Uy\YP^oh4 {4ͧ< )uTI^3o[Am# A QG;[FYK:; loz6erwG,YM{c7xY{r61w/l%FoQMj vuxlcӶ21)E#cmh}iO=')Sp|fם,D=3ƾ=shmpɌII‰{?gmfO` h[Щ2)@0Ԃ}6]fAv[]Qʷ"+we3=୬xVJڼ]n |'TBkB G]]?f'qQ_'/$YCbgK{,rًtzPW<v+S%GFta,In䠺$*FI\MpTRZ YYށEuskg(3X*XEw0Dֆ6<WǧX,S4Svq$٪7ou B3UoL 9l2# c伵Aν 6>x3X*X+8T_6.`͒5Gy3 -%V ;[a Q6mqdtB/C;פ;S'/, n `98,~ cIUX..ڹ @ė[|q!dRZæ;Sm!3?Kh]VJmmtZ!8Qż`RZJ+H p&@82 c䉽& VnQx &8.B cI.,بF-܊2?\\&})=ČaK~UTzqDqmwތ#0 .nY2uK%MOڠ7BԜU{ζutgHov$jg5"Q Ea,KwVA83 v -| 4X20Zv,m)ek6Fa,ջMn@pt^*C/Ӳ5FhڳMH\Hm!玧`V1Zz,R?HedYXRZZi;35XSi3MA:&0NofKUM0Lz3HJlBlތc?kTYT,xq䩹R\zfX󏥒Qzi炘[FQfzkstf6$bu\hmvDnUpfT./W!W P܇w}+4X&s?JftfRMAU3(K YqXYF0Rsy:٠B&pHRXK*GҀ6 |U*ogKUPjjacuM@]_oAKr%€5д㙂MR,ImJi t I/JqȭSiMu0ʴyUqXŒdnvl]G<7KE{3\句RvfzMt:nUΊb?; \#MM_'n~`.ǒ(c4+b\: `.vGEXl*'61:U 9ivTr^ L}Y(މ*,3D 7j؄u1@USI%`l`oƁKEa_ ̼ldM",I -&-$[R^ 7*ڳ,GpQ_ˤz25'f20VcI0dGp nrIW҅3&l0c`E(sni,< |#XvTVAuiq_7^n'3n}\%TU.ŭgX Y;׶x%V} Ru_"+y!Qьc? .;h7AN:M2,<)5TJrQ5a82VcCH!knNs6E֯H6ov$jrHs/"-z=0o93UX*1t`䗶t*lZ`X%H\.p;Z 8OXr?ڙB5j-y8M=6Ю82BwkTRҠV"5th735X*XkBeno3%XkڟgNE뼻گƒ,̄wՎ5[ZdY?`\%Zl7%mJyU\G*\/8*cTW;bkZXTвhڳb# T܁]']dS]] ֻ\񏥐wWlL*/&יִb>82VcIpOc8=Y+T ,w7jť~n7m:ވ;e QHOh[{W*82cIVޗSBe:&@a\b7/z-lq e"n+YQqdRZæ@KmBefLz\ǒ;(/j ؍e Oѹ:,w [N-lqd,RsGy\REmG qd,ǒd!s:+TX"&[uM -; Zc$XҰ^&8,cdV r +|Rj䁛|7vvK$אcl9WEU}cC)KT)7f+x>ilqd,ǒd S:RGGgףq؛q`ǒ``՞Ujǻbn\ѕG S m0s93XkSVۍ kxt$Kq5axjG+dRyx{3X xEi`)#lBcȒ`he0BJt˨ e L̻d~" cI)2Xr̴Kdx`F/o_HdC-t9DD_TT d IEc*&Z%VN,b'߾+qWnI6M޲&٘N--9v.\6D^6&]5֮ÚWv!^Y^/.A^9*kXV(3}7IC jҼCdW+Yr@_EjQ]z#^Իynoh޳^"c~5JwMk'V- Zj_ طgo ΟYg} %?7؏̦_ #S:ѓb_gu4mǗ(.\@cT&?6jy1g/Goߎgŏ+^H˓"IMILɄ,k^7(gmLd+T%K̔d|)Vп .{RVQYYP 9vŔ72bR«h'%+F55oj 4c7S+Amh_knLk&0.v9te?|[C&u WVy΄y$jP7z%>%-17jIέ#o.z2X)h5 רnlciI6d Fʊv/ֳA#GaoO+,tKb1 Vdfoʓ d5\Fs26W^f=SHkq%: Esʒ-n>؂7hLk_pwasߥ5}\KŇ~J_%=jX{:IR`Ҿ{_Õ58#ǎFo$ǟA1Bsaps[I 󆍬O_63ɞiE/sAYѧ+r_8{OԛGFM,IZGoy>b־v!4Qofܭ s%:FSYV^֩~hJag׋:[U&2Sj}Er}={bP,YUWܐZ0SjFrfB$7߸m)$ܓݴ]Lfhes+KPau -͉74U/q7kUhZR$2x1U4'w3^D%U&ZZ:ОEf.y-2LfH$X. 3t`FdFEva-֛Mf4R,I@7K8S΄mBKևn% vّLUbގbɊ4JbCdY^F5 se }x3pX,Ө1v%@>Jd҇3r[0ZT?l.^0qwR.1YƩz_AccpUBU,Y%,7f6K0+)5J0`FQR7&-"8,Zݜ(׵D X[ޘ,c]wS[F3^Ҋ%ELIzW}/mRq׮5Ul*6}A̜nysElV+[6V܀^Mގ"L+Je<k*A;[͸{pLvs1K~jXj, 9la0Uwsc>IڲZʅA5hȃ_TrC#\ze>#ZݞєYEU\ZagqKrdeQVX3Ke\kUzM%Wbc0nLGc\,K:q+s4f\\K0SG4LZ+ofeKeҴqi4=c5/ע`oƁdKwܴL먉\&NY~&?U2ZqQ"Va.וRU>]>nf\qoeWkdd(C+%6fRGƼi8GT?8[&5^(w͊"|-͘, im޿ +ffBJ͔)+<%vvK8ȟ+nVW+%H&9sJю##>.$!x$ygӍ'wUEEfH G9a< ZZ}Ek̸Z!1LXVnLjRѳT}1,HydF?ƒdȪl'Y&54$,aߛGFc,,o4֤“Bnhlݘ[ehl,vܭ,K.S+&u%~S hoY+}LT_ڣӺHs;:ULq(?k[h-u3n}Y73X,!U+4jdNUA fܽ 0KCk64k5&0'_G])EǒlVre2 _jRhƁKe0Lg$_ojykfq,,;KkMk,m߉A]k͸(8zŌEU|xG;^܊%%3C$w4(ϟʖbOqFt,(Yk,?ڙڲ5iF3̝X,SV3J5aHe݋[9bFel[RL=;Z3sU3qsk$SחH1)ֵ!&hȊYk8,vc6(T$#-uEhKv6ı$Y&*CL4RM%CKX.kF+D 6Lhq4܅AWLj7{EKF܊>2+YVJf.} O ͩpP\Zy;V؂%k%s$E|ROogK͆y ,'_O^%qd,RțSN~ᔂV=S[{߸حl$JPl'ӘiqTΌ6cZɜeaz"q 3ܔnKOfgKeҲ8C|#RЌ߉;ў@FűT,O_ܗVX53ՇrKELlYΌgߧ. "!C)vq3‚/X),9M&5)eU(!缘Z%o1Kbҵ2I _['|~9ҿb&*er$ۙpM2T+}`͎2CZ8ns]=Aar ?f*ָKV h7xbbTZ-gaK:$:hծ P)[Z8qdlǒ^k0n4u&Mx6S5Y{ގz2Mmf11nNhdW[ѱdϿtn2q&*[,f[ѱ$0]G%5E%M~q,.mv9%c 84۹ތ.#̩Y3 6sqՒv_HU޳bZpG.Sдb6qXGRɍi٥/c0j31fmoIh5}$Z1YZ&LAinк7X^u=ɤy4naqm tqdGǒyUgyFӎWўlt3ܑ%ZsͰ果wdh}w]9yp0*%__F55΁_0cUNZ#\ߌVӚX*j뭵m7CuI/}7܎%lR=JgGOih_pf=<ߖ>ќw]w\sZy3V؎%k%'jWTݓ-Tlkf73X̱{'p/e=n`5O gqKr Ӕ`*&Ln @dj;h9Vn-n&~Jy;V؊ G^3 Nv2!(UjCwۂFt,+aw/ I԰R6GH>SSK̜~4㪅XZsuikc7Ɩķofѱ𔉊|gɌM23ul mof=GI[/3@BEbK̮1cjEug 䨌NgkˬfǑKoMDQDf,!_aesK6Qx|f]M j/S5G͸2gS~jL 9SNn{ V\iwJL19UT&}؏%gȞ.H85r7:"ABPmzօpұmov} q]Z&]}nUolg2֞^ތcz<^H22.j29nt,;9f4}eBbtpyo806cIp/HUջVxdt3UCeyE_j*{;FN3UAHE1Ǚ0(q~t,Y\Y[U sRɇO+X; n[e Iɗ*WJ CpKE}zlhiݍSɌ736ւd}h 󪪤;k_Go ѱd*Yu Jo@[*}X%Zч@G[P15o͂c^ۛך=*.L4f)*` Z+gjUK0]k5LtVweQdJ73X<3$} ̌a4mGN}ȗEǒ乳1%X:A9%(.fRkg!KR3U-h6We"ˏ[l0cl֡'8$._{;&J"HfXќ՞(PmC| <юvcɊk'_#i=S yێeҊy;̽X*)駷„f (˷ZvY %4Q)/4uN7ԗ2rDw#pc3WeAm&ےsuf\0s%eՂeESE-\W&s;: m tOR3a͌c8 mI|ie3ٖu'Eތ3k-ebksݭ MzqC:diz. `bg}9-=qdlIRȷY4FU(CܾnT180vcIpv5 ;jZw]yر{yˬEs\]-klcUgݛt,Y/4LcUA1֖+S%|Gƶt,z3}X*isчAh۞,"6/ۣPH~{3ؖ%Fͤіʖl\]EGuejwihAjd /ۇټfgW[ӱdZFS[G|Ѣe؆e{tΗ#qdlMǒdd`*=hvlldY\=$ kAFk ړvN3֍Y3a|KFaU rTK[tɝJt,Y,V[N/ 7;Ђ6ؒ%¤WFk6S 9*v-O*{3X rzU wٖt k0p$d 9*z27j XVF;~ESyٞv7ؐ%1{FMj% 7;=X*Qs-V2Y6.lq72#MpiטmY_gu̾/lF\KV*w4)64gL kmGi[r5fg!KKF3$551uKN5&N+ eA}8q=* ʗ]ꬸWj-3!?n5(-뷎soU {ѱdE|dtň^ɘ\f6ѱT01Ô{~iEmLn ֪Uvű$ܷ >\lf"O<ﭸ;9b5U1m7AoqZq3:ըhi1D-)En١շjzkGnt,I&`[d",O5͸.˗)g{X*9^LM .hgƭ h4Lz[Xd `<%]VyDaqkmyDkŝXJk37T(-=';m6t,%e;òEEVVZ$n _y3X RYNhy[2%Z;!n,AD+:حҿ5wdd_is/7DCO\֌v\Ű#KV.H4Y%?LѢ-BѢi t, Z]-20+7Vx+:8Bm'b0Uڬ-uWn AC˖ۛw SZK,S+&SV`5L ӑg I1̴B$*a˃J98'UǃC'sC4NWUGYLjw%bɻxP"NFW Is1BHeT6Z9b? .rjZVDC[#RD<8$34* ΗM*$F' ֞ó8'QărgJqG%N_5'ƒCKeO8څTOuz` zmfƁ? n何.x mLbo^<8jOڂB6p{9\~}#I( k*϶iOW5's[=9q#kL3' | N{ =]ypt"&psGY~T{tpcu7E՛ k >xpԠt"2NBڴOOޝUGO*w@ (7WUGCrY%ɹw௑~c?N[_%T;8 N2\ʃ$s(`܁!n/GLO5'H!.V ț#[2wV tj8_&|AwIos6d}yzk$b==9a?)3-Q϶Powୁ?iotk'8h#~yͲNrD<|چϪeZa*@8<௑?ɖopܓK?ܼQr%-vkIRF$.vpHnT[ g6|yȟ7z}r'Y?xy]ڟ7ƒ$v`NPl,U !% Go1(/*YAJ'6l㰟ԝR2#N&xh&#x:8 #,PɗItpH.T~q'Y}1rȟDN$+֞|yC2C2_UGr?deF$tpH襥<˃J(俁61~fǑG+kllpְɌէ 1\ypW0xIn蠀b0z5yyT}n>ā%Q of6́!j'4MoOɃ (r`)OW5'Egp(ir`xӮq\+ycŴ+oL":NU$mXC+!9 HɓoQH>NnW<98'P9P,`B p@G_ (J3$C,p@P1klpPE8v8A~'A]n''F? $<CШW?ɾ ~F$ppHjyKǠaJӓoI!P~FU7?޾̏OL&dŨ<'ق}l]njWG|U𳮀gl*sonjz?8'av cl? ڳgyӕo18qs?ޕ7;)QANw}r/MR-sQ6ܑ{98n:8#.խ|@eQt5ȟQ?>0S*#<ୂ?3pmfƁ?>0Sq;Ƀ B~, vr)66X:W'GbOU?m8"~bPW-RSf??bKn+S`VyոXr&O\ypW\G 9r9K$sH:N\ ZᡥuX*q@/oӎ <`ǒ`='$~XۏgpEtzL'XR8 x'7\5*c=nu3O޿dX M dcI0&4.jzwX*G C"/ovKu.ؿ_XIAj0YHaiɍWuX*nWl0cyS]p\,RpU.ɕwuXlML#_$/FvY&PDl1^nU<ȅAU0*(qZ/̜O<`.R` C:pMƚ,0xVnp]%s?'xT=ug˃Fƚ,I+F2ꋑFƢ,8$S2w&N˃J,rMw$wuX*q@'G5pboy/b;Lbӓ#<ɽ>͓\IQcd!:T3]@௒K%; ٯ21^x~WRN>{~i7Yoڕ^|a-u*|z|H?N=~}#d ud0c!>0m-ZsaS򺰲 +<dG^ysn}zԶī~;VVn~j6$U|J6 6̲8Wr+srֶɕZzsF_Ηa7Uו;uyN+;n}ZG.nzk[GƱbZp-n\)z_UuPGnsMVmXx`<~|Wa&p1(?->qGy+I6.؏\|ƞ(?aO$Uڽ~W6bO'!}1&7zf^W蝎{l٠W~cOm3 Znh-}e) C}_wx& Fe/:O# ww%Kma4Y[/K7m@}K#~/{Z}X+++t@ ]yGjYש@^H^W<h'dFo>y=R J$>y%eZ'uœ-Ov>u#l}Ԏmy2DV${;ddڪR<[|r+l}kOt\ߐ́,IDV${;d&Me5t(:2x2[ܤuQ&%dP u%; tϱY;oypfF/O>FTֈJ*Xfgs%ʹ]W<h-@Db\ߐu"GnHȸ[*Ipo-|sw&0X`b+YqU^S?ȲgȭŦƷ<9yiUb[oઋ'oENyqA\{ёDAc+o%O[EQWxw<3Zy>:CNwF#ȣ82ȇyԫJJ𳴄P[DroM3r 'G;AJSfUOhć&^ZAvLdj{[MƷ<9L֓fm\en.'&+VyLV38棕w&nZܵZ[3n=8K\…vR=kS뫗:r>[|Ѻ-4&ў+Kaܿ(sHY@-#K_W?kU\(\ib}d,}}Na;c`g|.=ïQԺPZj,ܰ>wj+vV|-s+Wx%ы,OB`M,Ķ]YuKWRۺ U7-xԚ-Sc}E7r|1R@0׷}CMT<|˷;$0wݒگ]Ho;lC˼aXOkvh=٦yRu=nʤB~n:x&4x%fV=˶ ^G1ӯϽ޺.\aCg 5Buh-/| P73.}oȫTlaa]񢾯X궒LXԥ>~zuk" =%viӰڠ+:,Anw}}})|n~K/kKU"e1WT_!l69čo3V}G Gwk}\}~HnwIk6s=W_`b>u_cJ0\mko֯<9׋F%؀'zkS;<1VWx"i_r*vaslg׸7+CLJH^/LK. ;b+k'֒w&aJ^Kl^,o2So4k]'DέWv'?`Tu\TfI۹⡻&x_VHa_Aoεm.z~.b=bS`^ݍB8琛vv{ֻ]@v:_ F k<:wn=/PdMՖ%lq0"a} Ӿ%"?o Ro " |F )/V2oA?o^Q/Ԃzʏ,Pjɮy'E^yM1Z ]&u! ,+tB ߮x{e뉍p34j4J(FjvLI.i!D!-[xmJG׼W?\chZ s6Iyc%otИ bw>?sD_Q%S "#!'Qd')sZS[ɾVgLZhVefgY F9n[tv[m_˸|JgNa[okay ߸'2[ztMzZ0H<{0jMF<dqïOE;>᮲G_}~}^uَ+#|n' %bLQc;ƭYvfCcVZJKѕvyAtC"]x d [`Wܹ,:#G֮9Tٗ֜Z{֜(߹ܭbjuk䁸J1 Wg&9 s s#ܪ'LiKΗ=h4_.Êwf+A|J_>ThOߊ{*wn@ṍ>ڹ`\|hs&33JV_l7QwYy5|ʛq`"ƒ`w!) --rel\,}KImK;[m8ձEwq`PRC)2{sI6*{^tFCf=TbZkFhVuQn[r~q&gec enߗNYD^Q̅ktь";f, 6LӞ%kLա$oA/=m82cdL.拳^p%'Yތ3dƒ![W+jS{7rM&8]hTu[GȐK%Kw$2zWJU:;u[ގ#_!3ZJ}TF^8^g0Vr%a3Af,tz]h؉n=xae5`S'SV1cԆj|}yz?sFQ:RpsXgf3#by=uv.y:'k o/ю#ˁ_(zi,S4sO/u+uqPdnj%X|snU/(K\Ihn!&m,<@)h7p k,5xzwGWve8 aX[.4Н_N֙(0kݒ$oǑe 64O:d1e"-ڱzF3b-MXfa;Kem8 }OXBCnifsy2ʕwf&BdF-]+sj X,VD{[;zͱ nSE3̃TŰ ݛRfEC_vb8KRejQ,+X9$}qfɛq`@+vnwVr" B.M晼X*=KRVx]*ۋ`+&fbI.qQ&v^h'R"]d|؎|gXIYf#.Ա|f!譼qTN%|Ɣ++)`*|3_ hΩt8!K4!Y7174sL:d%ɲf8IOXk:ڳJN]7ZZ82jRoXYݴ~blVY?`IBZ X7Z7W=ؚHu.ǒ`YZ)4:zؒhZ|Xr>³3iojm8QzTO3X[x6{LJ$`ni]tqdR<6ʓk锯uFo82cI2&KVc&6' ]ItʤKǏ3\r'ڨ'@DZ־5wܲ=)ڹƊ, ntU]zMΔt%sOOy3Xy82VcIU-N%+(<#Nˢk/]SLx;EX*c#X/ ٮ̤˙q\zL5krGh7ꦁ5΍\f$XV`=eBBk/]\󏥒MezQC qLOގ#c?Aw鋉UgP8_sdRLky=iTPck+V$V$Ore9e;kKOcjVT.K;WG9rxqrxR.Js?#:u LBk/UX%ɲr8M97&c5Ηd|V ą޽.Fx?n}L{+UXx]K&KSq v+@pE68p:(t<*k-Q{Gdl$~򩪩DEeka ~he!.:ww-yqg+0gR \~;*)Ms+dU "n|~j/ԺmwԚGS^0 2^2-*Zevn9-ͮ&1JšO$\ӚLSNͭ'`ϖd -έ qЋ蜒jBKl.ي۩+577<`JjK~lI@5/@FZD39cStg+ݚZS۪ 9+d[F}I"JQre^X O M[O c ['u#}wmB֮WЖ)dd˚x p%euh.]QB5*0%X-ȓZx[1ʁ-еinTi\ Hn6Kي۰[j_=>5ajO\ ^ْ UN4Jؼv.;+?Y@围*'vܹ܏@a4E~6 ْ|KinAJ0pP~o0Y"Aptg+9t9][ZMٴ"iO SB#Y cT Շ+lˍz~6Y*Ɋ L=5P "8&i3O7K)d-,帆zaﭳxlJXwID7Q`b&Wht9m`) `ʕlCjŠ^CWi5#f(f%HgZyO76]nM,m=ַ:7 s)X0[̋Mf?[,^0GEց25 [XZr* \g7vP勴Vqy5=1W7`% ߣEv酩,H)rg+.CSKȯՁf^ee4&# wACk\j7I5!,.M'`ϖ[X t!afveNhHхNيY)2Puբd1fjHqňWe?g 3kV[. μ dDM]e@FU{BE5 <0wѴ nlmͪթYJZ(X3f5X_URɌg+@Yu%uFCg B1Ued9J^lɝwn$NE:-m`[Gq~$7x6NtW]QffS7u2O #ޟTHbْLYM:\tv g+0P|v{w 5BLY\6GG/ e`Vg+~{TaU2Qa6"wE7`%1>24ewI0Ν)M#Ο-X񗋈0ix`-U?{󰘑4Z#i)ȁxQ($E`KyȈg+8E'\aEa*lp gK 'ÂFN Ot9nql_MhB3f-p!EO #Ο-'ʀd.jra"jʅPfV`aF'yh*Նf"" ujrE?@$;*bEPKIrcO?g?H$;2uy]=ixb08Q\BYtI*4[>? T%XUKh+:b'd^l0# ,Lj7ϊ`P}ZRt5E7@;jj,ؒ<<0LYM0ԝ_*&3ԟCSWEA]lT."w ɼ d%Y[]{e0 SiVKnuӔNlIuH܂ƎJ.j@lce?[qE麘慦 gҬs=4@F?[9/ *'Ty>&fV`bn\LBG^0WP3fnYM;[wk^kw7F4%'FB&pV\aXai<*9}733ic/~d/8iѣPtIDgfҬgKy \%1|=R_[P& gFXA}yxIPW ?ECL;—&Pϖ`bVOr;^/ͫj_jȖy \|f+0UT,Z83fme@̋'gKs45*eC4%'FOM%`VX˴W]Ԋaf2͢v <*ْKFuTnִ~alIv>W .)4>"cSvQŀ:X9R/1=JG E49#_.5uct7?*{, >ցLZsgֻ|CC^6l%abگ]ZH`άD iE%`ϖX!.{j>r6 ܙbuf (&3Ksn,y#ܙ兑`{ d%p}򱸉W4L;0ʝY놏&pV܉14e$%.sgV*?2DN6lI-<.*%C_1̊nl (znebV]܎)sfc˭+)\E#h*jriVv16ьI*blte4br,ìębԅ2يꢧXҴԙƏql,m zpF+<=]_UQg+Qbwq;1_9ng-ivP ~|eo(>F*a eG0Ҿ/- 8_iÓ*iZ ƣB8sИN*}+v C-տPO!ˑ/{)ҳBCo<&ۭW6|M<N~c0zxGyi0FQz .% d/ +7Sj{:b>U[Jjl?TNjTKGR96nZN׷B{M_1'ū̗ T{ws+ ի* ~sRb3] 9n8lo`͚fwB܏_/G~7OCjڈD&T8vѳrR~<2?#Pi .$pR?Vq{z X$fKwV-.?j}g?7z4~@j*_Hot'&?` ġϮqw!h^كْ{E 4\tۮF+2y0[q0q4P[U>R؋F`{nAj4q&?b1. l2sa%R۩F4T D/Pܝɿobc57lfnzIrVM:&3w0[!`5 &/Bm0ES+ \f+.wn%,xZo)6өǏG2q0[rѽy!a2F/lŵ5n \rkы~ْS \>C 75l2=Y/\VSK"q0[QGށ YVnS3nf8-ʡ"‡_P[!q5ԋ@ƚ~${&:ʉǮP GaU~Ƀي|܇TNս{hatQ/~6يJ# \kfIyq3b3\- \fkп.u~C(%@^#"QMYQRMϪ6g[v{\#H^% XfKK@zV\MC'䜭Ȧm,@r)VaQ(v8yp1[/w7u_m_:t V\ϕ{/h :a C+ ddf+)ſNeW[ b ~6Yْ=֔p][t-R&E-AKv҄6}>/ߒa?  g~6يޚ\.}~"]E*et sԾ5njCE?b"w. -@~s}Q> pecW-؝A=TX n ,a[3 a[ tvsqkL,̖du JK18 \f+.@fo.){DnK"0[JES$&Ei* rhbٽQF^l03 ݓD֊!E:D7lw Iԫ7N|nו ~6ox yUZT[l.xz LdfKmj^]IbXGw%pW7΋%V.Y#?lEf\*o[Ӌ1c_K"0[b{C i=}j qr?z.6(9\4}*~t{~ϖd|RKO`c~qg+:5 ( .]! B=5Mf?[!i1^qlUfn/Zp\5\an 'ϖdUPiQN0v]z8S+xXWvFۖ .k[pk7 dD%4%\ 63Pz/~6lEVu!f'%\no/0.8BHdv^paʥvs?" UWσ4hi׳3e?[qr pli@vp'ϖdޭ6K p[/}QxɌg+zxr)VDФo5F?[K [VdZwAPQg+`laZm$wn*~6alIf%+9}wyK"mz%Rv-)-q$Mf?[ qn-pCVdP[O WGjzE?$S5 'Ѕ{mN n𲱌g+,'qWI:԰8άVͬ#PϖTm.w M2[qES+d7RԼVС.b*b޵C Bx[l"}^')˜Hl387xqF.EN!V. w/n!l VfVif]L[+x X%{ߓf=a0NMfsV-=)(7U9Wj&V`?d 5Ͻe7A@G7`;U5A=$Ő$/B)RDjͽgvAY.i2F7@{ߤx9 Bte:д n6qlm;ύ`nN_ #K"̟qCk2_y`NߚiM9?0"UgRGT&XoL0QjDCI#4GZs\* X<YݓK#)[wⓍ9$/8z7a\/0\1x \WzMj.7xhX$t)E?0$2JnTw'Ū2426Y=(]v~s2 E1f6yxe^`8=Ax\%w $u zLW8g~lIVP pV r_xFky+C5BC9 wǃ;^* m@(dFԃ٪Fn4@F?[cA$Nkԗ=hrlE;ы䑓6"{gKz8O.BdFك9il6a-'5N82-yV`y&Erg+2;H9 Q`j;P2Q g+|IRI` 眾Wi¹7@F?[rHaM*Jkv\d6ד&)'G%55c%esV{w G v OOC0N~E?"ǝiCcP۴Mf?[]bvPfc<RXncc'w:vk\!i^,Bْ[P `nsw+v7\7|塲kv.ᗗu_0B|_.%wX@fe?[qٽaIjaaG g<4E?[bcWNvk[Hb%'# ͝8Jmv{4ʟ&3-ê$+2Qp'V$n)T?5L2-\Դ nPbQ'Nq[K#<[qջ"IhhZ nW2ي8{WyqgKp;)a.\GCpK/ c-ugzJeuwJv_M'`ϖdpBt烩Pc`="&Yf?lEf&$ ѝְ//¼$2%|) ztaEQ6NܚXɆ2м;l}~w%p}#AN"1pvq?zWotxfK0$d$Vw"ذ{\*Nr8Ҭn6lVDt[NS $>ƀu~lI(h+,0yC0Cۦ0_ĂhNv\j mNF?$Mh|ab <@S+P?ŵtDTisQ{{7{f֤6;uSMa@F?[A@/u' Bc04[]4N$. ԝE ~hV7o5eD+64 Vtgk;`!(] x>4O # \w-gR(w؍`K?${&O0Gմg n6K>Uװ'Q~iNu3ܟM&h:} û0]e6NB1C7Sǁ4e?[bwťs'bиj~lE= `ܯaKS5eYIo7HΝ0@sR!n6l .W߼!< nl;z?)cNm8åjjE78eFӿPӅͭ'1<Ԏ{7U>NRx<&Uׂ~6ѐ,W3ʟԕݦ{[+ d%; qi72ϣP4Mf?[é5:5F .[F> `%8v`(.i ,I89lf`A.l2يl.cْީ!:꺽hvw~^<V4!Vwl]+] : T< %x^;k!}28W ў-dT}G\F|7F&pָy1idE*cpzygVd^q)dEnPE֪)ӹE@F?[}C̅`a We{<AE?[qt{).~uxzXݞ%:vTil疶=/naln;ٍr.+i nxFع-ίy!pM'`ϖd[\0:x*7}J5 \%7 vVb?J!Pi0 ; ZR*"Sia 3b{&#; `iI*4?-LecQޥ$Y:~]]Rͽf-a' q>ΦU)k{V?ݦO #- 'ui.O:)Mr&s [N"3 'Lm瘏M#-.NMɬ[꾒iE?[qN"wSHR525AU1d.dKW5Cj,כ1xz X.rŕ(h!,*&s [ >ͩ+e< +AMcUCЁBז45vo TdR^rRhEjWo.6l~A;$~-$Yhrpg+)]Δg黱4l2ْ\ 7΅=ܚX$0V̶Zn{z+4WN6AhTI틧R?a/~qlE;W=I_uiF.8Ҭ~ْ=~V .pc?qzYي9f)]Wh}K"ʟ'R=_13ո<5>,ʟ-^ ]nZ+r f%Ք?4e?[bw]SkΔ%onɦ!Vg+򽓼ynDs4&Z[֍q ql2يzy@ᜉ`N$ 1lI\W5(Tͮ'VdorI`aVs^l2#يޥkeU ^/G.7^/[y\Vݮ|-?lt~}zzok$/!/Bc:Id6?yxT+l,U# l/:r͌bA!kmQӮuB7n~'7ca}p~Rl[USʩ3NѪo?i >GC}OL?[ ^Sڄ1y\_>8p~iN4qp~ uq4~RK_ 7Î ϼluZj>2Ywe쭦9 }/8һ]:7UhO][7l\$6z Y/Tn"R-^ESҩ ]$'DpVtSUUՉqWr{Jo3Y+4tW+nQr^j/]V wh Tla~R+x\7.v>Ķ}֑wa1:IT`/Nש5SVֿ_Lb~|ZitѬ>!m;˰}K_v sp^6Zƿon*[/Ja|ަ._v-څB*]=1Dom(>rOֵp2Izu+ gyH`iG,QWqiw^>ը}~ -cUOLG+L{]U "+а'r^3^w!EÃ^<ɻ>!֝O? ~I{΢nvP_SET kɨҌ޷B]Q<BGtĿf=to?o_^=YYP,T5+Md=l2aΪجM^oH04nYt_MgUk\GO"?\k~ BS엽?-RבiS(_nM>qf{} z\f>e+w;]ü7zct~kْl,St#.[8h}\}ONBF-d) wU..KPFpD}*!7Ƀ`ْl)a{Y:\FSEVV: n` A걽ʬ#,B,e؆qΡH&WbwOrͲe ݯĮ@fO?pb+d/\lG`;Ϧ3 mNk8%0RͲ%^/,P0@3a5@3&G{YtLR5V2dٲeEeqn^fFq ?:GD#8pb㏎o9:x_ښ\dec&-ƴ(C>-\̸#okBPُN}U-{YGX5Vtjo yC:fѰWB|fLNcW&6upCrxV\͒}+.v6J܋Mf^$ρW%7t5)KgRQtΣT3:RrێInH`|,݄5,&zbĢ> Bb엽,Tƴկh˸Աg Tۅ-s}a/k_7ʎiynv~9T9nkrV*ΣDF?'ޓ&秭K HZ+&f-Mя /F߃l}QVqkYʷ$ /҅W`u 1[Kw`dŋL@RtK[]xYߤSra,WBQԋ~6ْl):sۗ+6{bOQO> f|ꓽƜHzC uAkRtel%Lj7J>*%^~fs-a uZ<:{np5$M@7ʛimfWԩ%t ٲSBpS@D-o~?lEH*YK,FQ(:t k;x\CgKn=^fV}urN7x '^F> :rꚘ ?FhS4 "t씽j$^ej%`ْ.pt\Ζ`›Z$).(<{)Cw'Vdq<1jgC딢YPp&hfu5'Λo@g?_XΖ \IN@=ݪAukp\7W'9]КR0ÛMc8[ueq|\[A~ A]rr7Ept+:L-k9}s+ n<0/kaeeugu+vxg;^ْ+ʭ3˴nφP7y XmVL~]E4\B外>'D{;I@b{wyl_,ۋXtNCf[rDՍu hկ&p -S;۲ڭt/I| g?ElE枪Ƹm5,'q5?TrjW#} "knO7[\ΖVի>1m@?%|Nnkي+ _o{YG)~˛7gj-xruK:+`֔vz܄8l{"Z۪ǥ" h{4l*aGi1CrA_,5rwÚk嘡bOu_}g&q%z}5lٯq|񓮶Vʣ/~kيlKItܹ9ՀmgVMt$3N1ܔ.G7\/, (6QΜ޶tA/{N[h3"-5&]Ln7ْu BIRjF7El _;0ԝfm%=n]֑[3ۋt3Mel/U[:"GjWnTt\Vaz+tٱtsKMKrvXΖ`aSvU%"<%)ptNu)@ kAn%&O֣eFy;,v'~ @U+JkE墻r5:[r\!îb2[9Zɻg:X,VXYQU\?YY`\ܢXn?՞g։  ͗\-yٽL4֥j/+@J#uJ̪/n"%+6^4Hu2q/H: dgKs|_rm*/ n/nIj ~QF2͗$/Nv-;uWȍSroaZ2޵/~Kْ\fp^U=0=|lrwVzYq I8qB/Vl _O]'_~I*tUyvFp[epP틛*t#qTu` _ą 8`gK0SȰLg' c6Pu/q.3ߧ[V֑Rcy\V\ޕN4Ŭ#[B:jc ^X. ԭz}V#zTJ ^a):[v q貰~uH|mέ.R ~q\ΖZP3f"ص3ǩzCqRzrX.V\˨V˅qٔG?LK7j~Sf8i1FgˎDu-U)O۟[Ee ⧗btNvc)!2(.ox`<Þ2V%yT^dݱrK(]`& gҒ !xJHړEq.O7[\Ζݚ qI*"iOd?[FbF5ؑ-Ɋ\s TG?lEƵWV¼$[ҥ>i yYHHZ\_>q-:[JZ,ru BRx$'?.ߔ-Zs+m/^61ho|I^ v`,oĹU7ޓΊT:ҕCK!KX2ۋ'Dgn}$cٜ QIMWnql *yU,뭵8w' hmv_`@~AVU-[7|@fի-KK_0֢%8o6Nw^? r/nln^ QBͰ/WזRN8YPt}(^ZfTt;Ņl٩1 K)ʒ/n+<]mX0;]D V^l0x`.⣣+Io]G ڷ^Vgp^%PlR\VAG?ckz w#:Qg\I)o^ZZjd䣗JtۨQ}.TV:&l\)ΖܫkK V༴'EAh Ybs[AqU|aKeh._ SVҷZRխg -ܵHf!7v^ZL"3. d{GFX*CBSnmzi-: ^{Zo'SZЃun) }S0 CˢInZ&j &s!:[˯U]PVI.u?ʣjq $g.InAp(C} %|:t)OKinv-4nq题UMlzVKMc!:[Yj&x[;'[7w`8[] z \,gK%_[\{/W[Cj,P~K0_CKs9[ opNb1 e8<&!Ԏnv-{1S:E>)s*\DgKc:P4NvVRKݍN6KnU ~Ft1> Zw]O8um.Ϭ B8Km/~37עeǺ-y`A(lqTڍAl.%wզwh9Nr]-EB\V1s75ȧfk.Ik zN<1_^ը8-VW%,Dg.MVUGѤ .ægul8b\H,,6FmC rR[ml2%.a!:[8g)q ݘL-+d-)D?M"wicz< ppp5_\*Ζv[C}Kq[C}-nAK7DHd 2z\R~B-5ʮkZ.F5W5adƭ} 7rnXVdʅ.=F8%8T)ms\/ΖdP<'U *&i-ȭ>N.en\^k~T/UEO~]k$P ՒZMˆ6Le?lI>YjK]].jAn)`@)UQh{Nlт r!Σ*XU0y_4T),Gg~,dUU`vj=n>իes@mrhIz%p^-NA\:e ΚV&q·p녳vWu8%׭nFuĀC~ޗ)myYf-@s}L52GT5j{74Qÿh_5F4Am0!^n9޻[;%WRSy+7BGVG&/P7˲b׍;Пqpֻ2߿ZqQ(} nz58OAf2*j%k_^~W {~*E!E\.o[X~ԻLbYl:ij׻ձ(E,˟(3wi\A!ђ7uG-ʌ!Œ_.WMy\?Ed)q}$Wb/\'Vr_|}4McQ02s@|D50H)o+gIǍMTtLr{zڦ GK^+gED!77K=V~T\̔O1V~\rYbr̺|/-yX?K.f Jy4MsQ1sHfAi OA dɹ"Eܿ$As^GY!eY k˛:ra_.jƦ Y0b$w: ԏڂk`VV x3Ȃˁu%%їFiS? _ n ivr>\fH 4:Rť:-oџFnO}ou< ؖ!VS`|!ђ7uGH>R5䥩~V{='Ǡ2̻inΡέxP~ nY X+RhʛYv'}%)/my^?J=8 _c<#Wі7u[ _~R{pHlɛ֊Q.QH.Ƃq];^ZOp,_~{@=xÆܐ7mu'i'Hlyiʛ:xۃws{E(\u딚-oOjxkS[^l{ymGC4ֱD%)gi?) ~bcCN6Bb:'j-5MSI,bpyg(L2_Q#dq{f^>˓=84;!2S_rk˛:>Y%E \'9.{dngr7#ObX;Z=(Ʉ9nlnWyӒ7u'ᩈV`-86&TztAI޿%x <|S9my^'҆ @>Ɠ\ڃg?jC=z c#NzFš){{w]'i՛cCEoěr2Vڻ޿c?7=(^X[K%oKgq2~i~ՔMNu'yAAV-oー҃C2s3-o+GSEÖdeS{I!`Y)o+G \@LMyqoU PVM6O(Q[qaPd໽iɛ QD_4/\uRs'[}ה7Ѓ2ҷa%3wmy^'Uױ{'䆫UJuk˛Q!ƥц.>ݣ)oOj<2-σBcN)>4M[[?h<(bbտiɛ:XNydM(\qeh+%wŲi?)<8$_K8uNEŗiUm"ı/X'`?<)n\<<ߵ09̓CrO5Ms(=\pmh*!O3<~px3/^6+ <5іf .QM{I!BQ&7bՌxM{IRvGU{q շMy\y`Fł>s)ܔ7߂T? .VK}iʛ:ǃCٞJRߵM{E?sd (J"-"\>*khkk}/`Z&~\񦭎k}ה7c23 Myqe8<GX0f=M \?`E>ؔT?wșs?bcf , <=nvY4Mcp~ w9n)nSG`9xwcfDX8!EQpW}ה7u`Ur?lJ7}<4sp-Z-m`Kۯ\85MS|Ɛ{AB`PXlp}X~U907uw-yZ>Q?Ol  2L cT !F Ni]S4ɟ*ć_Pɳ>ɭ?gCBzAx\*16ȌHcQpT>-ym OU3Jyԩ_^%u . W@jɛ  TA[cf`qݴciɛ AjR18Xg񦭎T ~[UHzXxV~LMR4џdes{EX};\Orn^Cnq݌V5䵭2ƟXkz;6 F46r^xe+l, zCKތ gKpLEZ5KfscK޴g+p<~|Ӕ7l?)J~d9p@2W%.=NF?[#dזi3'w+wH43lu ~lM@K0>TA@&KK5i:/xP"_g+p| \ҝ㲏%|kʛ~$GTӾk{>NFh?&/h7i]=>v6\-?MI;V1zb9{{׎7mu*b-u2lbNי⴯؍85\&YFzӊ7 u0 0^~dSsEfpQHMO*rjV*j'9Ut|ז7lN.%9rHư->Msƻ]4n. AԌז:lX 1jOlz31qUHMOb ܞXϖ!E/0{Ӕ7u2\g?_W_D~Y9׻ϕM_Gߏs?WxZZ-Z5~ |xZL׏u?~/mo YEzב/V\ڪQ14K32;Ÿ_kS\Ȃe뗵+i"!UsupdmL^~=EjZϲ2Z믿?gǁ/(#6GV.}`)j6u{7_6mnНsw=t:ݪ a8WV,ڐvYc̴ꃧ][I>m%kz6/3*9L6ЧZIڠ9K&}>i JikiIt}8> |*\o~*k}Gw}ŭ9;jLEu~~YV.rЯn)+aYaܾ-ؿȚ>cIz3qVHgȘ>=ߜ@H/\j)Z$Y}iŰ:{ud\$ԕˎ~bUt1~πQm/ױhm_vKxr{fv㮅ZtWSuOwN /ƫssnuu E|YG&=,3חc=8[?/BcWR,/F>U/W5^׾!}_׏a׊Sv'8m (b)%Lh{d Gp$^ -_oaM^c={ j9X y񲸧\Gձ|^6~:kG o _Z";z"H"ۯ9yY[Te W+kk&ۑ@9LVtq<ٙGG~2J:u< 5r[ \*p\FJCy`I`UG?/+2R!xrA>D~^ɪ%"<,S'y$@~ŸWv$0kX(i/y׎.ˢ&)p{O+<~^i2x#_p7`U/Vi@?O^IdU"G?o,ݡz 6W܇z#"G~g"qye d*WjDryW<\MF/eDwbdBv$W!X"Xcq$H W$8Y ;GrlG~+R]N& WyHWRJ$B~\$H"ۯ9Lf4y9=ǃij2׎.~KYM^?@lsiF.$*!3.L|H WU&k~No.# \˃[=%0 dw|r[iI\UG?/U׳$Mo<ԫOj d*W wq>IDU"F?o^fyg8"G 5uYǢ x\\MF/erzۑ@9y͙S%%̯_3? #G~+ً0w~y=_y p^vҰm#lJ YUD+3==6&W(/ P$xzz,H"ۯ9yCf"%[ 09frґD3YI늎EY@9y%Q$r=v$|pۡf* 9^Tvڑ70w _KcDN%IdU"G?d\v<xyM^HsBG~K-'4c>_n󉫭 ߷3=FTmK_uV9~Ǻ["zn2V*h#@BLRvن~0,ܾ~q]IJ}*,_bmX풵1,/uǪ`Cm?v-7ť~/ķzZH=t_isbqäbV/AYE?;W}#zsVx] PDw2v?bo>te\@jnzV1 ҹԵ5 '׭po4}z]ӵsÈyj?VH+g9n+ðd RԞmo?vGZ\53kh(*?u u_\ ?YE%lukznwWт; _.Q,{#b4vk9{l\D#/VսOXٔO/pfIfѸyUn3_\ɼ]xhFuwXu5o WtaKnox_\Ҵz;Я=:K٩vC7_f7,;;&oއk#A# 'g?Y8aJv_閟^_z-`U6\oBL?VӘw}3 ŨE?%xk#ur1w$|V|_zz}4L:`ʤ%6/?\|{^s껨]9jz0]mβn9uT}}WNN9*\OW뷩( vdO,ys(g&ǡ]{Ւ#uBY>T?Gx9Rxdχ>C9~o&ZBבiW]׿ȿY0%ȌG,iϾ [ t'Rhjw+_xE8+U, f^~ke~k:b/Tz7Fs7G܁!o\lHҿXX3x߁#lxs/~g-w18-Ki'~Jkdyt37nj/m97u+Oqa×&O=gVė kEۍ` "J~5e%2պө}\k $$K=u3gwq!pӷ,)2V9V%,sJ@$SFªQubޭ':VV>WnS6z6u7>3^[z׿}>ke{j+52qMd[O2j )PFC+ho2ےJ>Hʒ^bgcBB7U~/]1b&Z;=z+ 4ۛ) [cg&s"[i&zD#(j$w<'1+j/쉻)*#X;n~Vͬ&PQT,۴^:v(Qm܎n|>t9X%fsYS,[q;7P|A.Ɵj7Kb@Lq5h:y')hT5y`fg+0Vԍ3iScI~ْcn֐ wȘ\(Vdrao*?N.vw1pL̖`ͮ{-r֔2rO?lIvN;%e`ƛPC+\&e+.1ЖIJ :(v(kx5`Q%p,Htx`Q؎ M'ⴓ%@qqM|6rPH&3$[u|Hsqgf[gL5^يKJKC  xyoH7LGܺvI>{4EqluJ׼!IjP00A&L]HcmT&H>t)MO!bْi)kJ`!n(-2Z/%>).r'LOh n6Ųx`c 1N[>^!|[nM'Q_,[&vԛs]-k1VWWӁP|n6Ʋx"/LkkhvYn'GO hM럟'_SS0PIiK>,eKnK{Wybϥk;6>έ)?l0wf+pe+lUu5U0lM 2hl}a(rE4D>/ي;0D* #]O]ME;fVh?sDCj1>JxF$@a~WCfVxf+$5:# #Cg8d̖dK_8t5Y@eOMSS1]g8z \lx̖\]-J̲x0csk 䆮f0[hH)+5捡.](>O ca$[jn 3-M>5| vgؾrWlsbi6 vKr܅[irY@e%7NZX.תޅxVX +v5,$~."K:b|^g 9w82:1'ߧqc/?flWrq'ƹ#Z|8v`Ozg7]a 0.ͫeSVTnd]^7rC7wWgݕZ:=Y)tX[qH/P~lEzh? s[,#jWCq\"?̐Ɋd·NyƔcη&pV\&B'ͣҘKu'9yX%,-j"aNcؐvΖ`VRNMCWR׽ˣ)M"ܟyl5WfVcEgSfV gKra[d]MWSSJ켞m麚@F?[3)pC"<4:s?r" ꨤ(XG87wz+nm̎nlLuoc{f(gQK&VpV[1}j^YĞsxУ!SRhZjЅa%= HʛΛrkVE?h"7PV7YkrXY9HgfMlKռ~lI`m,lbJؔ̚l.ي1F,a21'gY2tnl % ~lIn6lLw ?K\ք4]MO [)W( @SS>ѽGԐO"ڟ-Z@ ȧySkv[,o&3ܟ C!EPUpkB[0l1\98:x?2*z\ֽ+lɥO +G4Zj7˝J )7OI;Gdamc+ź϶ gϖdQYZsKL'zԚݖ2"٪XɁQꧮ't">ք/Vl2Cي\1JjzY *z0Z<& 0"lA++")kfh [e)J-Wtg+07V|X:ƺ)f72g^l2CْY۠*{:f+Yg[g+(] t,,衲kB[Nsx͋XZSR2t=E7sukri3SwkɋF?[1cᔵ7~6krE?̠c+P! #8\=Tͣ-/~alEn9]+e"ë϶ _eϑbK~]Vf^iٔ0l1iQfЌj"z{^ͣ-/~lUA`OYL]D2h<5eD:[q64K@ EjBCG/ JqVفޕ@xiK~6lE/;u#ַ`AXOͮ'1۸s4:vu]+]-̊nl^JS\;քtMgϖd!B?vrWoAٖsgpFI87jBC.MdCVІ:&>>o*vjgCצnl hEE^͓J<'V jb}O[5vSCa f?[;T+җ7uGy5;-Xx d,d+ b}jI샞eLWfs-'6D\jT*Poa ϖ\ZMk`Y–Uyܚ\~!mO c [+b)%w ͮZ(4lu|~6KْlJMU׳Ex-l5%pctee᳊ΡMޗ4߈fT N 8_fRRK[ۅ7%l˹,DA3lotM%`M-jV6n>4P1bҊbԥ8p [l3XTJj$<0I}*'Ʒ6M18N(Q$ecX=5}\CՒbMS$Y-:ԑ- 0YtY͟rat˥9ٕf]*$ZsA#?`=Ȓ d-NӄU`_CTf? df$+D9\;/X&9TҾOͮf,R@aS-dcZ`E6XO S"YQq/VV<0ʯ>,~0X?h* wl!$++nC95x>P%p)O (EP3\ ưrӓk# O"蟭Ȭ܊fKhX|#D̋Mf?[!TI [ cs8_c֔0b <1H]C'xN u?5U۟HyxT%C,`ukŭf2kVb1ƹM&ϖ`(斅Vb&fJGS.&VZE*2kVV4F +d%e{s+BH|h]21ؕO #蟭f 4{cu. NJt gk܊0_)||ZI`֗(f5O ;[Yw1u&Ԛi3 rgK.{N,Ěi{!w!6xXF%DRT^oV%FE4jVR@ '7v PӄҪ~kbiv{ X| fK:SkA$V4HԴ^{1䟭(ZM+ȇ{f%׬HCQpgKX `Զgί(-Tͪ'ϖd -Nj*bP~Q[̋Mf?[kBJtfR0L5+tE?[b!rWX,td) ę7̈w*JpHn"EH!v ̚gQW,+lI3O7ܜ,zS#~ibE?̈$[p[D#7 CxЎ-ܚjZ̋@F?[#jm tWhg^M7`cDĆѮ )Ri5Vl({ \HCgtbۥ9UL3^Jvxe+08EB)5 l"2O7PZ?Y ͟RkWJ: dy`Yeq]#*|@Žl7Pߨ.ZIe9ZʨY+/K"ҟ#twM-(zŝ骹f+!0"l!bH |i8NMfu[N`ܚ[ŜY"0f\2"ي,r0LaikgV ZXtr/Pͬqc-WM"ҟ-aOMuwv 43j:J܊nlhn ܰ@zh&c}98`F%1MWT`ܧ_sjfE/X2, !*`SQȇgi~FzM[)Fʏ_5I<[gJGhW]f`,Frd^08`:R9NnS)2ڟ-T1סl2يL85,~KRnqoMQ1ؖ(&ϖ`$[H85\uXU+ \WCqGAWtپxri,J=ђ)`F%1CT[KcJC`~d7` skrYh5) 5si$ڂ-?p$;r rƹ. 6ilYݻfWȁ3nh<+.ЁЎU:y XDc zFotՁb2ܟ-Na +.@3f90Ж-'Vdq 9"H*U 55)g7HG4qX0+WeH1saQ'`Vru8H* rH3Ɩ1Vn옦e]f¢U]oͼxq:E3I*f'ZrYM"⟭ČKILJ_1̬} yb~lIvέ.WlUsoQb:b7̀34,ZH70jNzAM"-,ڜ$ZWc6K+dYO[b ]f^[,:KZH)BheaNofԬ.g+բe]%C'raQӡh-)Mk]4V64]KHQ]NtՐ ,bْXM, 0LY܁q K^lEBI9 2/2ilFi:/pZjQfPDr A^lE;);&(*UlF4%\M:b[gQPW(mOJcwK0$ĊAg_x{uڑ||,rǻ=e̿+:o߫hڟ8,^!Ύn5Ե#WɆ{+<߄1ՄJ߹f[ lSer>C}j%0)O|]Wj-Τ4 1ZOڻBb#?N0ԍN DA[\z"o/i/^BF8fݯ#_M=cٺS +hCO_j!hoY8ǚ~:Fn5<^ϺW~7X^&Ks/5͑1Dl[ *hg~=j Lryg|>ܛ;\Y :´Fqsp%tt[y9ˑou ? _?/7y}rx~7z.^87z *E/FL_{peWJmo8?Uc`)K^4p'6XbnzKѵsK>rQi1iw =4Or|\>?#Pڗ _1GZ+ŷ?p% {z,xOQ{ h{;wp*TÑf.n9!:,v=/Y|~>=6*-2F-`;`$VIFl®Tޣb{<j_jgV-hp~^l٣Un}eA>;~t$RL&fkX: Dp#"un$ToK"w0[qջ*Zb)W~e?lI6++_CCb<F/qVXu:w)dv0w0rsr1h]$ JItL̖XSZs1S[Zմum*oed%M>2%Y+emHC04Me`41ؚT.zh^Lp'1$He5зE*ًE`${\t3$MyAԊ~6ي<Mm2O2$vi0Uk{ T fKnaa. ?tmh/N69 ΕK M~0JEdyz@MZXH̖dZúUnުx=*zM#k0[rRjO,(:M'&3m0[š~RZ4!(..[_jůbuAdd~3g5-*֗ZqCЪJ$Z;Li^ M-Sᲊ[TU4,0%T*\'%v,g6K% zK"2'6:pUbTޮ%GAY^&#["a NNq"ӵ}Vz94x Pd fKwnHBt\~a|vh0֕ƙ9]4ʳ'uC0\,qbc Ul.ss'8-A)b'wm=PRHVeRA+2I-h7rYW< ^6yْ]&5I\{^.Wk\&G^ ?( yzJx fKUb {XUTEn6ɃݻY8x^M,G2@ڹNȴ$/%ͬg8dff+z((M5 "Hnكْ 9w5⾸<q^F`S%)F&i#bxQUF^l25 e]amxދ^#Bu'@ g<Ăj wE/P\U.dEC)n4˶:X8E`sysy{8ߵFa_8. c{+R~6IيR[IC[%MT \)R4Fa{])?^\ŐjQ_OzzH$FoyjJE?NgKjjNA,m~ג[.`A8nO #K11J\o`y݆0Sl.ي;qFΩ)Q9xDx 80" "{M7U!O7z&T:J:b8%Mf?[;[VҶo;wAWxȈg+zuPF<v}ċ f?[Uȃ^d=+ 1]McHbv;F/z\jv]SYz&3 g.zς>*֬Md1C+z \D%wK!~;do…cM@"EZET Id`/ƕL`:BEOZc;ƀ[@F?[?V.9ʲ{M#⟭ ~B~o'y͹q .ͬgVdY Oi+DV^1ĊNHѐ ()B7Vvh7J{F? $K3Uk' (Bub0<'c.Xe?[qN"x̯{zjd~>g{ d+b]sn{jn-q-ݼeSϖTݐvvyW"V3@G7 FԺHL*m3G_,bْYPY_,NYvC\%~61lEV0$wW"9 ̊~QlE0$w4 sew5.l.cْcZ$=Bv- ܊nAl #x˭[ގƠ2b''#ȟegu ͝p uaMl2#ي|.7wW.Fr'ϖdHu$9`stMf?[U*iAr'5FwE8ǡ2%{X5 gqWJ{ڛO #֟ laP` /K2`%H6;IBYy-(^wA[~!lEV&xhPf9 tMg숆q.`޹u-b7|!hR~qlEVbp'e%+α D/l]W;pF&Gpa?[N"a54v#]W7/~ql:xKBr;Fj[4v\rO #mF!p||D f?[N;>vW9nl >& )JkaoUecϖ;rgNC@.#P$ߗGTFۅ@E]Xl^w[|Hnlŝ; `+TTdqn)W3-4(n kQcpK30 dD,/s"Xbyӯ-;1(R ^6lMX:tٯ-[3+ d{F ^v೪ҡNy8$ ̖TS Z:W`εse?[q9WlSQXP*0gɤF?[M5PtkgW{ +8dVW:o3Uř^qlu]:>~&0 \v9`pxBc^l2ْI5$u>yߧfWg+z,9 yRs&WpxFЁSS Q Xfʻ~.b\"k%[C`g]uힸ:?5@F?[#Α:rWǕY'S ʅld-qB)ِruz o=qQ ~lEV^oH4/G ;R9F~v3䟭d*Wy;\f!y X%ֻwk.,tj(g0]io_l.يUM'SuEWï%暹O #-ɦ۶kCWǝrI{3 QOO #䟭"y0+, Rs&W g+i] * (}fo3ϖ `ץU|(knDߤk2-&AҾXySU*L l0Y}㣫nRyE?[j;մ%٭US*d%Y=dU{F?[O$/%}aTMdSϖTuNR K+&} qnua K"Οs]C`SxKZy8$ks ܝ5pܪa\=`XYw}RYvSF?[տD } \..F`G/6Eni_Njy!` d|egk? ao_Q<: PTۄgS+N.iWg7~*zϜ5pB Cm0 5'/lMJa XfψFԐ}0STa$dEp?[ӹnpB,@7N体ŗ_z\pϟir|#05_g+.8*8p[ӏ!xqg+ ]Ny.{'ϖd`E\o$(kB?|@ApgV)]5qk r.Bْ+\}J-vOG/~s%_8 Ad EC,D,Dwsk",ي.qD#wkrA:K(* kJyF?[)EdRe nInF70C:)^LNG>&6gG&[v;qugKK! lB]ipnxϋF؆s19lLG}F: T%{74ʍoJKs+z \7tܖ&o=0*&ϖdV# d:{J8qhoȈg+z5ED!w-Xr~?OSJsZ|c 8f?N;VHnЙbWG;l{.-'ϖd >:'++gVdP:RrS a t NAlE; qĤ/i%=p&ϖ`nm7J0k9IPSe?[r{MSkLf;V,g=ߍ@F?[o蝨GXI9_RST NMgVdHX8rjh;h `q0zDsb}J޻pO X|.ST6khjE/ "֞$WPvg+n]w_f}-.%!En6l >ϝ0T<֋]ƠI: d9td^M lc*T >|\H>d.d+q11kqI0=dzˌW`WG;qw\#pkvE?`G4ĢkmCU :g+浓@5%AE=,t@`"w#̯E)5i/Ӌ8f?N>ϖdt} y2vp?""ӂh!k;N55.LziZ/znN_k_Wvg\CBtg+:75Rۊ-W_ZM#-ĉa ǹS&Zfy33S)G[\MgVA|0l-sca('[0)aDS&>cvSr' V1Xqa|F`Rm}>l.ْ!԰̔!& ~dd}(B zM)LPn~GgVd|]߳[DXon3!;לz3 JQ`n?7>*~ 3ȝTaX?yG8Il,C\Bs\qx3.[m|8 XVUJąYwgϖryN9`kwk$8]*x Xci-<lQLu 4M%pϖ\]Ѽj2 lmas^l0 pfXq{28Õц 75Ms+ d%9t~3 UƠjfasшbyoVM"ğ-&.M>NuvG\GvM#Ɵw`"7pX1A$2cي&+A ?j=ҹ2 J7 0la;c$Nm6/XfOeG,6ٮÏXFJξek/oʃ;wYuk|_.=c>,b\H;Jۃ] ~0[>+OqZOlm0XVG~V (otp9'BlgJk&=VA6i1pW8^zeYQ?r?GU/e5Q9|uRVƗ;'g BaiUVfa7KYJ.rW~fu>ʎ4Q-wrfCy$lL4H;'ƺM5#uLv\0 ZUL} 0wDKˡ&ɮv e~u~Yͣ[ >ktB9څ 'qE(vme쉰\Y~Rq22i\O֪F[Sg8>+*iGmZ߷ g ./~/?6o~Z_Fy<72Gp81ui`S>KVby\Ϻi|.aw邧tcfyr*=WaY>B៸e'/̿vxޭխ^WyX !x]FП؝'Hw2B@A% 5 xkOS7]N6)_{:OY{?f= Gɯe=no?ίyMy{Ջ*7X\:Kto듹*ْ{w5aAr:j=wY7/So^SYUY e^~!&[6^\W1UVPՖG~60ْ\LM? #8V%=pӋ@F6L"1fOՒBS.G7\~Ȫٸqn8(Ndlٯv5~K7TK۪Hn66يqjEi qQ'ktuxIJP/n6o QH# ( YKbUp0d.y7_ӎ[urpewi<ٲS`nLP yqZXd"W] 0^0cvO_V> Tdd+pqOdZK}jQlTw?׉ >EK' k7V)2pegYBZ Y/K[ȇuMկ ՎsEP䮌ɗ7&H>^l0%xE $Pr,0\nV+=30IwpnՂ,C蛝N!)[vj}uj-DVot;NFR#FVY6P;FF MfR$K߻0E^Rah nit_]'@|tQk/WpʖEZ #Qqގs;YuAF?lI vZui) aQ^0xb.XY`8oxz` >|ho+SSfʸu%x?fAi't SٲS~q>`4KI;NyQ>Ex_ fTA(w{1DקJl¨bU%,_X7]r&4]U>6WM^ 6M#>:o*+򹵢8 ?hm8g SKv幭8Po߫p?lI^oN=:pU"<1LXG//$gqdECW*_y`a݄Na0[vW7+Z|b8Kc26^ y#Ƀ_ي<걽,gn= 'R5 ^Y2 f`|yTQ֊&^aNLELzw՛O&[meqߜxWzWԦ}{̾˖d{ y경ьZ S)J|ud7,ʰ]n4kziOnt#]OM^1ҍ/M8Y1fY9$E V7+f^iE_ꕽҬTfx Yl2%X:W rĹѪۚ~U* ‚t약2U;()_+V < dHgKrqwQ聆@\ΖX{kPl!wbϮc-ɭZO8j!b #5Ymk߼խ& ٲ_-\{Y~[tKr)C{p\Ζ\4 RiB]14d>.pي+JWgAp-YSkko'G{K)\0.M5I)ƒۋ1Hgˎ[]dJ媕ʔ/^6 ;ܩ'7zHfBJrhM0k@Ƣq"sEk걽׬-0ַPC|M?L,/8/ _-IƒѰGOy o4eA%݌E7lk4+:{1-ordKc|}w' K#]+rH&Al"d.9!$cԸ-do+T(3;+fQ@zt$WW]J6jܗ/I|k g?lEFS{Ҭ\~ ъ/=݄ظkuif4We/ܗ^q9:[ mHa85x[S24jt:.`/4fa$z}\hIm d.gKsZ䤄"'7Lu8x g^lz5NHum.ro(l$苛)Gٛv۫Q]8T[zYw~kي<1 gݮվ0W^#WQepib,hmq~d7W\zuMea|svu񐭠ux2id#Mզu)Ees-\:l/3{џ oNb={ّJ^N_tf?W d/ErXg.IPKV+(=$i%콭V{A-JJbR_2t2 M| ϸZ+K1sho#Yuno,}I?Byf01,DgˎUM^gzqՓ-N%\uveɕ.?p~b{ 5P@A?FAo PfkiF8}oxI'=F-ogKu>.h:|(ਂʺRlVx;Xl) _pL+^q[(hedwDpd6 r,o5 ѱdtq$j͚7%/VokSuafKu"icܓ40@_ΨNw:q`},XCZ;r&0ndDlыYptfmmI7fۅ_h +:`Ir-aXS޵-?<vѱ$YJfYW5=Ck ᮜ.&n826cI28rڬ]C^ WOi؝55ތFȠYb򒄡䯜>iKh2q4 XYzp3Qo(9>82vci׹ :5krcХ Q-l#LW*۴$7ia3QW^mx;RE.g8Mg"Z;r3-[ұdt"b] /S :|Ӱfy3X 4k.jh:?^?YVi-f6Ʊ401岙awd ֯`^ݻqw3kRN6GM1li.եj?<6Ͻ0lJǒ œp5lL1UK Yf}pTlHҨ ƂLȥjԱ!gmי[\ WY$7ڶN=fq3l'Uk*V3hgZ"˫{qPlERi\ZFKT5dir[R<`D=;/ ̌e)Z]Wκ?]"Pi0/Ǚr^Ìkn+بĄ?~M Xo(w2Êb':Ɲg:UwJ]cm/Τczy܋%ɺLK?fMr\q&;n.F:iILgJ>ÈkvcV"Eq۬ЅLGt=8ܚSʤ;̭XG.d: o.\.iaWKvtQ*K=s0јHz3.a3ŃX[qeӊkcFHqYgvf|5,ss]T&~`nD캭*]/t :d& 5hǑUKu''œ)F1Q(L$.A8XqwQ#bߊ5ktu3iYnWYfvK6JW*ؔu5#I&8aǑᄋz~JF[/m+G-Xe&TW2;mùZ SvV tq!"H\g:̗[ XUH; KNt~wkM2_iqKr k4UeVwMۆ3Ɂ- "E ٚ Ҏ x@n4{;6*EUkd$%hVAGq@^[l;U؂%KM=jSB8V $چrފeKt}@3 оhر:TW#Ҋdj5okd;Ѻ7U Kka3ըKq4K@fб40r J4hk6;{@;8Ozb:ꚉzH¾`8SOg{qϝe֙=s+AA*8h{.t,ٮk&dҥZLz;1W&}q\lCǒ\]0YXeLMkvl=l2ciӯ 3ʋD-Žu+.I o&bSy,uBK\ղ xͶB`ͶG>t, PԬŚ y-ذ+%ɺlb5UѺ#ɺo%dV>ۨ+X2V*Ym-E0lEǒ U \ziڭ]װ0܋tbM֕ԥKK*{3XlzY{79þ]m5(ny e96qrij[qK:q7n]k;w\g-*6VVK2cVAiE WWnȝ6t, nL}q&%56 6t, 8Ү<,ۊ3.HﭸpMF{L]rTp'7ڄXM G5ᚘeC3M(F],&ތc: ޘTi-Ry,g`RbZ&s8FFDiՉDp]^jRMYYwˑY -1lj%'LJpZVa#:l䱑mi_ug^b4h{dDȨj]ĐӠdی D>Gs),ޕ5}%U/r*VoD#Wte.6[AWr'N7t=L,q>t,ٮ/fPPEndnŹܗ܄%$q7nͅ[֖^ւ=6q,w5r! Ɩm#NȺWUaGh?#w \K tٶ;bl;a܅%g$]#YT`7h[tf{q`Cǒ` :+yj͌K6qdll%z$3FϣIؙqrPKndYmͺ3:{r+к{3Y܊%]#xCM"np)tNt, lak/6#J1oܕӘ,[q{ر5qcWգ֮ps& bz;a܍4LkЛ\BthZΌK6tDA'YN,面K:d/*d)Gƞt,INi^JCDzvU9rۤ8w+/%LСwvUݔJRz%k3MXYjam]=kf3T}9 J3IdoǑ-K#s/Y]ٺlO6Ɯ0QUgfsKr)kGZrzLkbe2x}i*Dd'~[$lIǒU|!٬P[=lj܆=ZjoƁ᳉%lam`9C3;mS JZn"'ǒ~kJ@W5&,voF"c|HN$h^?^GUtq¦t,.]0ڿjC"Y±9Zi]=Gƶt,|]uigO*FVҬs8/ ųoK>9;gsrwrEu/on w%u4qlcNkv\ð1Km؍b#`J7v^T}eMq;ll&cIw6P!kXX7^[rrF=Wtq`¨}C"2E =99B6Pv- j$/uokGV_&oŵ [ұdtlnJ&޴UUsG:f%IsS54ېsU}2%ɋ[/)5߸o%W*u{3Fih} R+֮qtBQ+Cqm?GZ7.=ΘM4fo4#`!ct.5yS(w~ǏjCr}-uS)zVYu1f\̭uQ7]j5Gg=!f(9v5UMee̦EA?EC(>akEFCul/.mc5tQ?jEF #RI=k,18G5ǀ!8q?9F 8Q.ʛ.G9|{K+%#dτjҧ*߳&ojkςBlO:Qֿc:A 5g1DOl, cVb{Փkɛ.GY__k񦪋QO} .L(lEF/2Hm'Koj"trg?W Q-8lgE!K[dQ7]|sp8ʳ^ep^1/2HŖu4j>񦪋Q0/`MT(v3_wyըR?E.0}TMUY.RȥR~\|GMv+{_c?*E9RY75g!2=؟5yVva? [?~MeT]wɛ.GA!BLlWƻ<뺨"$b)oÆ\[KTl\&o꺸eq/l9n'ag?Eȁ"o*"dꧭ^48ɛ.'3Gq\JW#aes?j +;vQE$x>|d)YNn=dG0HK'7MY\1Ƽ뛚~R$+ϢaGMUds}v`ְ2*TMuf~O^.w#sU ^NxS$1fL V~<npTY[~_3`:8[խB썉AB@=:M]ցX÷ I;juPX7_ZOX"m:0' a gg򦺋Iq6CWvtƒ\ [H];p9,^165. *.'q)YrV6Ѻ;mlgqCaqr/bUv??9#'5Yhu.Σ.okRGb_&.'2?->>|W75G# '3Euyq䷒D؊p\;! ۉeE66Vva?IZ[˥ʛj?{'Ѡ!1dJ*hЁԍ䊺C.*oo}1\O>䂀߫#2=F(spHHAk 뎺":Ksp@FD>M=򦾋I\qDۜ&OۻRخ83r"܌a'nDGU]O9`Fdh*Kʛlb:;IhAߘ x!ěz.+8;*U?UN$NM~p@VfB@Qg]w?%Moɼގ#J~ 7Uu>˛2|50Q7]Oɽ#XX7ԏx&aSGu7?8LDrƤb-TtQ?e>0SjT{vO0ɱF~'yRÌʾ1Rjs+L]M5,=4kcZOds}eWW8ԎiqXƒd:'*o:tC.ufQI*K:ȁǛ>X~RaK`ci`IpW ׮lnzs?Al]=U]TxcIAbKIxXciX!yvy}Euѹ8L$kT詿ΫK#֑LnG.5%#ӫK#;&MI(S뻪í<nY:H 7$5z`U#b}EҰB,K1+=6"G6һ<뺰vb{=堎;TzӥKf>>ĆZ\8cIPTN75ySYӟ\|~82^cid@s;Ȫɾt"ßK#;&EZ/L]UTwZL_ZXc [y,}{XdL bN{ 8GzWgE>XQ~˕o+ X~&̇UϽΏq2պ=6TCgMeX0 8Uyqdxcy{>J'9'4㐜1>WUC0ʛ.04a6o,/0[S{ix|aP5 H񦪋 ~, ^ F$b?_v?їU@QDL/__wnHO]o~W*pKZ0}_ߥ#DTx|߻Z5hg\lGk"&M.ȶŔ\'߲y5%ǭh/MsʅZϢ |% 3> +$;/kP^kIџz!t۟d{}n̉ _Rm$2H4O|V&rztǾYC'$/'}YK*6^1_K~x]ګIw_[ǟ;|| _],8$3kL۱h1U 撷j+_?ּ.ȋUk4v:uι:5Я~i?5Vy>n%?mGq=6x":~|O6N@ס)چ,t_Pq!A͋ l޼K=mZ]y%󪥦ҭkꟿ}[]vGH}rKrZsKU!TW|]:1EY?z̾:DnԸWݗ]=^Z^ۺ#Y행ɡLvW"[meQ?T~!5pJƣ,2qxR}+U?|u(V.H.̧kK kHWׯ|leEkr9Ñc DH]Z?\5a[?{6_5ׯ5[x=1=۞`ڋ߯_j/ Ma5Q}y֒Ne3?^- Cϋ߫`U&HZzh~j^HAM«yAh؅cOт,Wy! _*N)VggWV;=LЙk#T/x~CPscL1=4AyaC 6@9/Ȳ(9"z#+m|F(ԧggn1͌6/ϬՎ WǭĬ9jQ_͌6\PJ__CZ4W?o$D'9RֆeA+~[lwP^P :2yzWE\`W63xd n<[YLlXJ6+ GOZI[`oMۃy%}{kXz 5rkzp[<ɖ,f%IUo+o9rlbt%>J%ag5bSV1;S;38yF_ی8q!yXy[j=)/WrhvN#^j֕@n2#5A.8.3~rX|8"WYΓ0t^1g=z%[yZ ds282%ry\k9z%)Ū8L=Yʼn+o9rtDkdu2;v5cƇj92߿V9{ϩx}[!VZ+<(-st ]#g!ٳ |бȇ1Xck?{ lN y"yϸb{lQ9[(C^!zEzs3|;˪_mA:Ja&m׆mW1vO٥h1h&v%cwM_q7]] ^LLYSwpT\+Ͽq9I'idM\훥Ӿ򨽊{hNva~g+QGJVMj]\k^X{BlWֱXܔ[ }ߢP %7hg18|kQ6א7\+E) ZE ( (/m!낼 8ol_aVV]l}l*qc?#!Vz^MRX+"הZ]W@K۱ 3ۆ}ŒP@5RlI&ri-vv{tڮEv,1xskp/ාL_2 _J?ΜM۫՜Xgj ws?A a-3`_{1k1#:`&FOaY!{J͘0|:.넨HqA~4N'~B\s߳ yha~_ {UvulP]/_9ouWgN2R5kyEwfy]#!2[YmXknWm|gƒ {#Xq\lҸFQEϨ{5 SvmElWTn1, OԼoߋW?ք>wXG=uUQV}EvXVß$V8: ʃ|xVbi5ܡGf.xaD% yI_Sl.3sŒܡ/J+aH vncqX劥a:TV]"յԣUaes+" F^7:!#Sb5R m1/ 85o!tTVepA6b[uR-ج~Rcz+4DT.-8X oPŁXZ(sEnn 7s8yX%Bfԉ^Ntr QZGń/ 7W ftp7[+*tF?t$6'Mm@DgNqŽK'`,KH٣nLR4v :bz4OΈ,_,IU_@XuTl>B/ݦ<[KգdI_gmtq^Zoaq.Ī?3)aPW/9 8ƍN$=R QX}AK]|م>wl*Ҩ ӧ (44x6}XK=qQ'P٣6MłVm,u=`PQhKfVLފ8V,Yu XĎi[q\q' JV=?Vtq5`;2 {;Q$TLҴdIl/I7:C;Ն78K;rwrTI{xyqw8V6 K\8=2ШelL 䵱sYN|,IUϒ|`o6(tl)Eirk,ٙoqᐏq;.q+zF. I*RcaG>&|62OPhRiƗkF%ԙpLciL9 u )/e"}T2g{i:;|A? DŽ3>dqp\mpTV) l.f[ޱs]lHy+uAQVm<5Sgdˌ+r8)l8"$1L@Mc" Al,}4,ϠTp<։!Aw0VMoqጏ%vZ1'b iZܙ }l*]4DniLmjLw55]dÈKbig?27ӂUpetr8,\NF}ֻm0f3Ҙ<-qJS+EI=WI촱:<9p̨\6ͅ[ml8 e4=+5`EuV~Xg<S&SH9b=mqTҨS'xP*+舏%W:G~sj;l@9# ?|,:LQH"2L*1Q>9ZU\9&32eW%R Krխ$(6;hX\Eoqᇏqz6rx*2lPy+K?|,Uǒ|Tx=򻐫XlÆcك'ܦ$BPlx y c}ԂhAsKrյ$i؉>O6FzL䃑M+>F< mHYY3چ_\8,| K>I03C&qa+Ҹ̇DAyaɸΊKrͤs0I8:O!W$9MoqᏏqyP3XV/-H9E1cQ ;>Iͨ"4bX|% )oQፏ%fo\6"!5: WrV6 7_δ!kcdE8($WLBi6/4'چ "+ |,;E!QW|4!"#KK#Y nЮ+# |, ;˂ r뉐_f#/G2W8L!W.7_WŪtǒIwD =[o6 9h*A\Ef;ފ%K6t?x"T#d\90tǒX}XuR?Q GS>FL<#ɕ4+ |,-SFbC*}Aʐ_ |D#Kq, ;=ڈ]|w d _飜DžW>"CJ؈*9,t<ĄˆǒƒKmCIThW|=)oaѻ0e6/>Tkь8&$V}; )!vX|وF6nX03GʠWD|4ǒXDl^8~D+,SҸԻ snq͊S vwDžc>ڴ 4F҃CGcMoQᗏ%ߑodSc%er6{Mg>FeFZl͂Bj&H͸ 'FG18.\$ׄ9 ]>$ JP3cOQWciL,ˌGCO ]q_O oeX2R?4t%YH?6:Gc>F|VX'^d '-DBI_vboesa~ @/D5Mlc)# |,U΍j|:aV"a&|ۀVv4nilD␯p#FDG>YB|,U@Vd't2bY4:n6 c>Qk@[rq!"Bhaᘏ%B,Msg1_>VlD5:gLJUD@FnXT?kzg+dưl.$W=; Nq|, DD ٳM8$t\a).`Ӛ%@~d\ |,IU@ywCET$w[l%Ҹ]Mп`dSZi3r"ÈR(ĪWGűx@)37^?ioK!lI Ұ.-Ϝ8`) 2Y MDž+:] #[b m\G#IiP>L˩oq@A'3E(`dSMi'Fw&BOS2a*>&zM(U@號L*Pf6fIÀF6քhBi؎|zXS!"I|Ԣ %Ȗ(\dLAM(YVRyXq\ӆqzH.\3&iPL%DsGYoKB9'oc7t Tͭ*H@Ɇ!CPb\-koes VMI6wZA̶!]b$@^m0y#i%$V:i6Ns|"Rnk6y""Acµ#abh"܁>nXS %ۑo$K#>n9[|B Ӛlxe<DŽkGǣ/~RXNtri6d;G,G3!;DŢTEkpz壕AJ#HjLs2mhqph2 7Ƒ7Գ%Αo)_L(l]ZD )+4%|)\@7992S23ъ SwV%|i܆e#Q6,^C7#8DxVu& $T]:R'*¶1W}|Kl*Ұ,ܰ,lCiStcf`puވPyXq\\u'rsVL* [Ç~F6cr{=gilHGGPeąȅ 9mǥv.E"O] qLcIlamDl>]_[oąH5tNyTzciԆI&z}Jg-vۀVX.Fը|lݸɈ dts,ɝH `*aU6G?>F蟆-_'b)G揷R7\;B!񋒙,q׏hQᏏQӱ&}$ׅMCWdW5:崱pODubI$ѿr4*,7+XqPxcI:u2l8%&LM+Td$쿣ȇś],ij )J.l |4X M2 z~V"KQD#X&qTxciԎ޹$IGH(sÆ7ǒ\ӦN}Y5boF!qR9l*4@rXfvS!,U][ǒ\F:~V"Y5`RطVV6XdlG*Ջ\FԶ+2ЍF}V KY6A4:XSVX^$M4&Xsl*4*u0+D52EnԢq6XN&U>:kV|V6Xwwj4I!,Mah=r0Ⱀu3(L) _iSy!Fr4D.糲W u"6m8#J_|,afJ`äʏALx O|, 3!2\)i/t0cW$)M#>Fm[XuXHp W CpǒD9񔙳 +%K~ )F~X0OG/#I%B&:;Ɔ8.F _txr664_l0gM3w)3Җ':ފKr%[Sc"#"N,X\cIn dUny\E 6׳U&WQV6r8qLcIpI)+Rn *tҨ(6߳RVROhFB=M oqሏ%lrEJSB'3rO+7hqሏ%F) F}9$6qLrNW#X:ciXBV]>,Rr3z+^n6 #>.FKY]\B66~Xݦ{,YH\PFt]s+8,^cIAd]RbHTL܆^f<͹وV6X(XJmN\){4+CsæԝBقt׎Y*oB;+j$D#KwW\윕.fDEuVX(\"K,R,e֡փkhajKB|QNZ9!؛rK%r0$ NyMN*a«#8.\4Q ( b*·Nf]`GmuFXkB=<8ڍ>fP/Vcڈ66Xi—B9u7-t0WL!:aQᆏQ9Q5b{F3~ehL֣pF6^Xknév+==^stGU/ iawLR=\BzXV~X(v[+%pZFll(4(ŦM/H@gYѽ ]6 >.ư4.$CJaƮ@Y/ 7 Kr")uI# ]m0y# _{jtZJu E0nejXV9oO\,I]KɕjCLEWL"z6ͥ#>%!/*Z_;s, ,++ ^6s G'>J] T 7jQ+S4t{I?|,i 㫺>VJC2u^kÈ KbzJ^J`SB<9W&laERhqᇏ%lU};qu25V`c3醏1+z'CBBMr4Մ>f@ _<Dž>3ӭ"q`1+Â./]Xˆ=m֔Nb ݚl,9'|, -z{Rн Y;to6oDž>HI.Og`ːY*l.$Wc lKHNfȊ5 4ҨM|U h*X}k"ڭ6H! o( ߦ4D/\X-!]?~23KvYגsN,}$IUP1T8ÍY,OqYln8- ٩-h~gTCN .OT)FΩC}וu,ò<ޛV현|^>P\\ 6VwA_h|ޣČ ygW.uDb fX)0uɓ&M? 5Rl~K6KσKNU;wVsWX˾1~i{֙uw~>eǒVH;˳r*c]GpQO ucE}py9wYzNs_ fr|(0gk̹e _[;s|z XۃbݘwneǑv>lXqNġs'}I-(K︰N>ag{c]4߿f A(};hoW{{u]@ UMҳ^A5G؟ْ_畟߸+T. C (/X3煟Džg^/yyς*lhjۭ?%<_v7~hWG`Wg~f#vۂe{O[JJ.X(b9~xlyٔ "5)ںv exx:G캮o}ٿtYz>oJ+֬xO{6HE=#0X;׵2]zkN F⑖o|#i}2;kdN|#(_õKάq?8 :97~e=l^.|Iyci7`,,m",1>PEf؟ kx6(i_?}}7ş_K"i[2t-0w$z?UmK~=3=8.bI5m T*YlS &6v4!U/PS *Ln4eAMlۊqie $?ƺrK[q\R&4T1B_"u@\l.#bi܁MOA1oYj2XXW&bIjX7A?L3UT gabv40MOh}-υZZVWգRQa%n9=d=8(bbi\kePNؽj8lh}`V6v$FŖS&Tt-{oxHXԚ%:l\7'(dH?l,CbIxB /Q{K?@l8(biЂ[r-#eJqm6GE],I]-6uy-`'nl]Rj2.Ƶ- yMLgވ".j2aK~K#=l,#bIj[19(hjɣWb>-KÈbg<Į-$ժ-osFqv4j])ņD;D-َ4>^մe], km6TkCޒE],ɵƙIs@7?ـ6 "XEhMfd̻+ |,ˆ=3lǿ] p66XtpކDD KTGG>Bl/ AA$z|Qu7aes钏%qci鋌IIA;._oOފ+KFJI`!f@klD9# |,jm3)Hڶ ϟ_xXL d<6&Lkxl4y#Ұ=;04Pq8=Z?m4y#K|,FG)IѤu>Xq^K[q\3Ҹָ%sF!DXKu<+:8(F7ǒն%Og wL{uaR˻OOy+U/ W&pǔWG> i!xQaK']5/(cʶMm@y+ {,# > tk͟6bX)blǝOk# {,]m&OfvC>T6y1w󗢤7_Pu}LL\kr_"bUzcI.pezzKKR2/O7m y+ {,k+6 8hqU w==BMqi]&8Dn:=saUӐ-8.\$w5.ۨ2IdSR ;ۿͥ{8-8*~pU;pҸֺe~7U*U53ǒXkDM[|``+(5ͯF c1EDfec+ |,5;nٴᒜ԰}k{ƝKTciTm+]AGaUƤ{/KqX8cIv\O7zYz#K|, ˶d-J{j(dUYXgaႏ%m䃪G>gtb-.4nZТT :a[qsbCT:cIj۴!EDԺ/}:oaሏak^m#*V6Ƭǒr)p!`haUrF ފ:Ƶ T,I{ <:+ // w=q6gDŽ#>uMT%ܹs;pcۆx%ָfaIW2Ǔ+3ӷxrFK3EdTUbR#+ g|,]k6+lrsDP(oqጏquvsgqU1oyKl*=$")&cZY5>GC>F۰BP@@PƦKƦ 1˥0)};hq =EhG ]de ⾦%8(|$w5'!Sqnj)KZI<2jom8*\$"dJ ^r&l.]4.ږ (D.}YI3eᠺǎyLC14/],Ʌ<[1 %@,7/3PlEI2x\Aml(4(率C~\IF7ǒPk鏘pRȐ ah{8.4.am# ҝ9RƵMӖdY Vsn}/X~* Uӂ&l]{bpHxciT6kp ET[>#P3#hr6.X +IfdMPgX)RzRf0` ivSDžG>䮶Q3+QaX_.Ytl35~ puSpi&k:# 鐏aDBC2blɯh' 7> u- ZYzS#Jg|,I%:TeЁMo,hLG|, T@mPb3vVƴT&KZ˪"K۩D]mf\ges鈏%*gʐ)r}BsɎXފK㮴N0*ɸddz>.*&6NXUitU1o%%C˗WW)";j̔=ǒհ%B;8SZ+r㮦a[\zci\k][+#);!nD%Dž>kENZ+_}Rb&6>XZm8y*tH Dž>亦ۯQ))Nf#*tςKZ6vJ;srSwOKb;^)H*jUf8>$ÊKZ(!tRѮK[\ciܹçW*\zLEF˱$׷lb oK݊Z G>ZZ1 z̥Vh|^R K>%X*\Iͯ6Dž>;z \XVEsV:elc[\8%|ЬK=EhƝeQLZ¾8&4lSĎ_UaD> js4x%mK44hD}]k0>X)B; h'& Xq\cI 2| \$\VEʽk2QIoq჏qusVEn5F6NX/$amӆTCUg ^F^Xڶ;Kl?tKV Kb}ۈ!تTYQ||76 SdwU'MsqH8ciTkXR+Ъs҉}.ᇑ>Į%[BU9_Cخbm.4QT{ T Vj KrW몍^@%܌ʹ%/ jM[]ۀr6?u$TyA*خ%-V}XzciXkw(`ì `;M֪(?8.$w5ڴqV[@ȘXz[\:ci܆¤!Ҫrɒ* 8.|$w.aVUT$L[q\ci܊;!s t[jGXv@*`MVU[R0z#eb{J2j'cUՉ$C:#t%K0SuÊw]aPkڰD.$fUǒT/g3xF Fp)܉;{ol.}4.w"+ĪJQ/E͇D\6nciȱj,3(|6P:cI,;xԊXW5}LY=~XVX*7X}%\Z&:hQᙏQu2Q!>€JA0tҨִjը6TլfRPj:,D|,\ k6So9νhd7>XiՆVpUӇ@-b/Foα$vͨ^UMEE[9ш'KZӪ DFa25}U;J|, 4"" j,mp6>U3jcᐏaٲ =Z )jSIe66 _Ul@d7d{4a1ፏa늙"UW0+ j}E#qxgmqTŒTkS .j΀ Sl# {KZ۲ ہMZ34aqᎏq玝#nU@橾Tm0y _|, 1Ӡ&-`Og&u$yJ 3 V6X˦ge0@z_҈7%A1V]D $16PciX0`煰YDygM{W}> t$܏d!P}hVXLk30OH^xTeӴw66~XjMt^RQ Ak< FnX*b;n,ìx)gP K1!f1YHƽe'G#_ZF7$L7fn;3 F?r$v6$f@t-TciTk jN `$jaL4xXq\cInQT A:!l66>X*R[,z9s!qXcIjZ9[n,0 RB)|wι-aa၏amT)!Ъ cb?l.=4qT+DZu}RMQ:$?# |,#v%EBnO32ࣃ՚/\j6aVC`XnpҨyGP=nY }HMZ${pFX5 ~cx[O:ȸǒv*b3n+$>Ou6 =;>9&F7Bh@K ) .iC}#73kREۋ:ŲF&٧ zRey]HW,W`piff 5PDuiyRrWYǤBzr෼I"т|]k;_а JDk'*:Uvu%8G53(./Zkeⵤk|+OTV]{8_v7gB}c+& ^vC/+PcΥї?'ڂ{N|߫΢'\4,Pn}!]^+'M8'?5q)5M}Ѵν;[ ᳬrzq|Z9~q N(Y.^Lz9n"'͜k 1ׯs>("߂`%̼Ď*c~e_ʽҞ&9LЁܶVKKGH륭F R)lmVϲg'cMWNthP" o;y@S0&`*UJ7D|6Bhҵp|v2 I>lG9%ݽ?J4M?^* 7]b4nӅ̫ժÓ)ǎ+uXV^Pݏ#Wg/oyoEc@6dLs$6eHÆl&(%~NCK8/8/S?#Wd Õ1?'nfc랽'mM_jQsQ/˵)?>YCIm`gYO)op-bdp/ා:5(Se8 USgSך0k*g8;]Dh_a}ɇ˟;)>l)n?(5 }JzL1*XsT+VUAe =dG,+? *W $4eiFUK[E%XTa*6|V\PKVM/k'0Q92$Ħ^+Е82$]x 3ezF$$6_ `/1E\=5[qpJ֦O8FYpXQe*P,G֓Y69LlXz#xX[/ܰDʄTyELR3/6F+XxDvxUDǐ'!~T0zXqP҄bӡMeO%UoBVaMb,L,٤ WUUb:(+`si[q\9W*AԡGi)3kƝE4L,Nh0y'6Mwl/*6ŧX6vhK6i&ܭN 9Pu땆Hqut3EO$oqmKܰFMa9Vt%^\)ɦr3 ֐^.ot3v|"Q-YwP*9`\lS {@_rڄXXMwE/lmJ}c@/LIK"5[q\DĒ\]ev+qE#(׽.|Nd,O,;BcrT\%g𾥦ZQy?+Sp6q-BP,"]IL܉ rd'fF6B4J;#r!hX+/I< w|ͽX+phy]bH.]ltш} KƣY=AFEj1ZjXk6 &!Œm|ش׵S٥!/ )4zvƦ2)F$R#zٳe6t%T++u!5I%)k~ *lm2E#Mr%dvT_m^e/ܰ)? [\ V` mDL>$VdS,Ip8I:~w.޻[3u b(K$Zـ)wQtCniV\b3.ڨq0Jj%+l'hb1çbI.DeU*< 2ⓦ/Z[ET,;<$܊> m>{$܆V Lzqm[IIjfBZ&nyZجXEm_$Yٞ:j7Soml*#biT}PbT}I<´B_X 71⸈ϊ%Ϳ )/ Jq%on5P[ѠV٠\'5ё܅?1+l.Cb@* 8" j3"gQS CNǴ9Љ+mbb6EW,UPc{LJTRܰƸFӥ&]$Pj`?H6Mnb6-ʴy)pM9~Fae$VWC&SVCv|/7b[\Œ\]swZ+x5 {`Gs[ȧup7P!bȊeJnEOr7N㼬# ]B[S"mœ~9Ɩ2ZqP,Wbiݐt֋yfg4f eZ, e|JEZntpmWʺ{1EJ5tƩX8h\F+Q%(\VX^Z kQTi+ˀX+" )S\xڍ;\R[Z5qXҰlt܏ˋͩrWa ÊSBVV$e:F<]Fވkb6am#b qh` ;ї6y+hXeA,+iFF_"T/M1Zq}imS\%bb M}LxUފkbbFD(וpBmoدӪF&y_Ś?Ѷ!ioӤm.x+hX"L;t/=m'ފ˗o FNQmSOk7ڄPXM" ٰhlsbV>nI`!aes*Knr۰hI)/Sveaq-K6,I2EKx|nȢk%jdT6:дDRl nЗc#l!d ҭEi5\F+չ!Krb ?ײ%W"8GMLbŞm, ;qJ;Mi ԛT.L2qwM=b>F --HӬY"5̲wS:Zmp,&]7R7DW&{t4=ylolpJxq'5J/NRl\oagKbu)"jJtlUfcS}ʽmvx+zC.iɚt*۔&v{KGW!I Յ@/B&ӇqkբX{fp,]~Oreg:ܸ``;jciD*Ize/+;5]6wt#=n%5NofP+ ݋i`Ce ~%ÎYL+aa KBu!Jc"4-_Zr6EBXܒ=[7NtpJ7ZYwc!ƅl2>c}$p-p,"CLkNr˹+fr7d.7ȕ;!n:q7Mb4Zq1esAo&_]Vz;Z "lƒ-0N@˅N8*^fj(xpLlҘPE1V.=ЙPaesKru"Mc"\{t`oh= jI"+ä!z^f] "lƒ-0M]ÎvVFmV{+X(&.Q$"sEEһ8,\e4,!nGqL1 t0a?]HO^$h}Wlv=la7l?nDʃ<2kbKꜙF64lE 3mPz2\oqCKru"zD'-[UN|-p٢; Sa{`-":7+VvDf`":(rE/1ZqPlǒEqBu=pas=8,|,4, 7n2]^ǁDLyS(^+JDZp[trlOQ .zXٍp,( p=蕎ՃBb8F5r&EEWƞ3clzPܧ%2ڲɠmZ+/O\oB]'I$56f͵m.p_ED%@EB3x%}z]#b8JD ͨgpjvtu!n+u!7AW$rd7! 4FvK6I"$V֣.9ŖpY-6;4#ӨMRʃdUhesK:JjnULAMns4lV\tM HW><(:5\SlW:%AўY_iX^4k%8*d}j#x!_Xo@]thJۺ.&Wms hŵ dpx Ru"1L NlxS&m=X ʽh*r=Ztވb8.W+Mb"ņ flv=۷,(5܊7^o36F\K6I>֤^q/|]R&;[\nǒ\]h$ Lo:MdKaaIKtťĊEMtjPtN})#C3HݴɠU$SXm&tK6In^K|JDSDŊ&(#3x.uٖm{# XrQZЋݴ̔V%Myg1AKMwٔ\]%bN#qڲ=pB5qWl2Sid7{dtIY3)V؀d*Ue҇ Go,Iե|d'tUr_X ]RG%+ۈ}*Mwt!Zq]HjGͿ4堜*bv*w~cCSl{ Vk\rΕb䭬Ϋ%ʴEthy޶*F6$vAw[&s7RnXoݾJCL+lY6 m3¡Lzp ¶o, ] YzbDLPڢj*s>8.}ci\v*I\=,5zXq=o#لUfOgƇyZ=X&R"-a,"]}Xt"峮\jԓPKy+XZES^eH JN' l,cId"&￱<SKΙLuU#ۼwFۖmZLeUL-aqGP#~7ڃ m̍5DXk ǵ\Lx0%QY MOC2 +Nr7NTuy":/&Ve'tzov=l{+ Un&"DlߴU;bb6V\K6IWB)&z P2 R2r 8DՀ`=NdJJ/mm8*icIja.٭BQ)[B=mF4K?b4-Bu`=a8lQe foH\'=qWY^t+MXx}A״̶";څ&N$22lgIK#VtMk~UM0ZAyf~Fܽӵ\lbjDUMIr(AfrVvK65٤ו4 Rv%-TeӆGKBu"lՕR:yťmʒlx+MXw{+Ɂd LlKlWDwV\v!BMǴ mU 2 ncJLUi\}wKYyxF;4ɛ 2HM3e=ͅ:DUxLLj5+ Qi[b*8uY/a!Z֞<71ݼWה'vF\sKH#7`0fj$IU| Md&쭸6a8lD# \UV[l SMU&6ۿ$Tuޙ! Pd\lX|)&8:}aLfbj\Z:cٰ0ӞzXqwO UrWmկ0Kq j(lӂTkJ]&5l+F6{4l3h8Ey6l+iR/$Zq\ƒܚv0pU]\ӴT^ɏ t=["F }IE& m-{zmo,&0g^.`U[SZ na&3p,;w0rujBcvLgÈb6Ī;Zߖj?_]Ym-Rs%S^ݶ6/qgdۿdWqGMabbTJވb7Īt7s jKMu3 Օf*0gƠCO&fsyM/=f0 5lTT1S:8(cIʗ3Cɨ@KX'VdXcp,K>M:]ڕaQ֪cnJa31L焞\ZUnfU[+E%[ZHFlg⬋-)9/QjΈb 8.Ri/ &eU-\,cd&5srŜh=O:ѹ!fQ ]yFLdWPHj!fX ]#{dT:Wjg1zk%ڹeF̞&]&ɍhTnҨL4ґfnn+j%fRM ^+B `jsKkA٦Q5y=Fa8l\ pTbiԹSڙ bSbJnu=8.6cDž@~GACwvyҝƺy _4=hlQǶlOdq7l4a ļ9ϐvԧrh8.cInBR L1IMp;lף&l* rbp.2d_.boݿL-~[Ohta --F+E%Un-PTU[HMӊ07Ұ}'#٦Jes{E_rCLcЗZB&ƒj"qPs {t3wĦ*jz#ց^ A͞+T#&Y@5/ya7lQ+;#ɦRfMʶ'&oɫ/TgqKr! `$\ y Ui f64aQI}1'46UwG-o (scLq0㚅XY)69ۚuw'Ɣ<ѡYM^p,Kzv6I1KA%8}خF }n }ۅ =ݸ f}K2o u)5*t'|CwV>ڢ( ǒp}/ ]Pjrf6±4@GPF?ܳ4YJrG3X0|鮚k}FLd4ndNmeZʍ[_0!!r8} {uUizrS tjıWYE03$TP!,jcg;L%1_dgV]e@6&j6>w~_ݙ+~&xx^GRF0㲇 I҃@:gFw=鋟}}}+e4Ϫ E/FkYTSm+_+1Jh6Vvo5EO3;Yzȣ QAK a[v·lxSv(2av#M˧]]M]܏x"a܆ UMu&a\]%-uyS_#v^<0BnR]=uQ? Y&eqSYge YQ!יqpٯ*MMTָ%Xf](ȳ Q/P"yNsו]܏*|C0ӝBoܔn{VMuY/r@.oȦwuySE9$-[#o* kϪyYNpaƁ?  >N=j~Զr/ S.ݠ'7T7LKӁEl+Q.65yKANkBT|YDitK9~7rq$$"(#9 e^T mɳ Q'z|~vbspzTMU[Dn`G{W75g `jw߫w|[aˏz<U"BXk:F?Q.-rHKr]?0^>>QgeSGQH!EwYz?k,l1zM\UySE>[1X|-4E}M}Y0Xƣ*otL.q5',:l.jԘYE hac3ߪxG[u*<+$B&?YtVYE !J.GI8l',E.(_=*~_<K.׻a"rBXGښCĤ6?:XE%E~r_涣#Gj(T(u6'a7=A`0T|ϊ.*^ALRoTgUAalq\'5pTYW~R_a[*'v3o|:`fTmNoA{QnSL9*a?I>Î]E_ZLu`"F~R?)3P+A.v#T|SgMz,j*K WN+A@h[v{RbMXIEeb&nd˘,8ȳ AQ6˅V6ѸMr7r'lf(a;Y;f yua?y54tEhK 9TRLښl|"VԠo`k9ehU07tfEjg˟}dԆ(g=U%AQlt6rJn'* AD'wyua?`< <*a?` #瓍Z=5TuQ?PoVJM55'>B+']M-NN (!v,ADBZ.1j`bf7U:Q?cj~9(Nb#"Ϻ^AQ,"퐋B8v\UYׅ}(󏙹AP1ۘyհd `$T"Ϻ.ɗﰟT_ 7&XbϪ.ї8`t7xtQ?xȿjWl'Uj1|[\Idz AC+s9o@ȳ}ɓ'ef:+A9hY.֕1Qr*쟅 rPkL7*a? `yhҥTZE 뺰NT+ca`hw?l79 T1=pd?kGGTCTcQCMB-G-]O+I[Lz}Wg]PA6MV* A'}g=6V68`tb}b}E]<bqΤ &KNQg] ID'XE}YځHW?m @o8Jv{DcƳFq@"qdz AO؆IC4AG=U]hעvWKxQY?I Sp9D- dZ.aȈ>P_p@@<({\-zGO*ecvbK9" pP"6;UY p0:&@mv >A?ixƂy@'W  ̯5+F,I=Q?i/;P[:,}/?$$:z<_#3s!3Dg:'5YS~J@@e=$HƳ!y x|ǘc&Q>韙G&3ucL髑UQV B_z`Rh3.fxYOmKRTjJ 4C(65tQuYb'2w-?8"~bInBMA5uhj<ƠtP2amڨ5uhXֳϪ.,$Qzb"ϺX~擪to-X!R/?Սx]5]LxcIcmI2}xӠ zKwP/zcI0ePA"Zƣ 'z,$cA'TsqqT8cImoG_TRT52M=U]XxcIQ6+rZXzcy`[:>-Gl_L0U2a)Z<+ǒXR~PqR}=N#Jwz,#3RK?G>Ez,Au@+5Gp]55&$ mAj,3⨺|m.Ҳ-Vs!Hm5;~WU@ ]=YUҧK`ea[;W=Vz+ z,umw?-T+aSme'7V% [˻<뺰pǒXGg,U u]XcI90rb M=U5*뱌ԎPp#GjjZ1^A&O=kjT|A#X* ~ibϥȧN~=#~}?zy[u}K.\9 "7> ׯ֠ $P^kV|yO"X>KfU9$2v%+UDD&m؟_<_IT~kb)ͻ~U"7ih|~=f8廚 ]Ҹ֫~#|,t]hG gQ3k ) 4@X](}^R'O7M֎b_˷^G.oS >&L79\pttK$CԌCOҡ)n==cCe?~gٟan׵Yn S]c5 ^جr rJ?1Ц$AdyB>J")GK֧oB/vjcWJNˠ~uEQB |]j).m5XJf{aB'u_zAf|%qX>n:pskH:d~+Hm 8eF-mgyv٘\Xc^>&|͘o$m}k5%W6&|Z6g&t]caScAXqcgO%Z3mu zP\_V3<}>sW5We T|_5%=ߵ5Yg L/sMEkM.l]iOw~?/ӄ_<>̑_K @rn;oix_$]1cx"V"V,v!/ikn.'}`隵ȭo$[MƉ$OFOG9yC4" 8~^ ><ҙOELrhIbKꉪ⁸xݿ<4&"&zQ-Gv\gd{{2r 5ߐnn]p\~qgeo(pF-q$AJ yWF7~J  bx282qy\k9z%EjANʼn+o9r5kdl y^ q̓gj䎔^q\|aPkV4Umsy%p[*}'2xz~{Y82o on$;+\}#Frly^ \Vz;k]ucqaS;zX!Uv/=8&^Qno8Y׃VwEJf삾Hz R *`]XdD_9mS_#t␠|w;FOGys_JIr6'x,C>gne~}ZW8&A9űՎ`<~v!ZΧ;|Ɠ׺K|ȇ^8YƁ=lm!y;M>^zZ?k}`A3xc$EpX?ׅ׭?7ϭ]2kMPQYU>[ 8-?lk:U.7s]0%F9M} +9VTz^ R;Cc{ch,%|72?t'La}}W3w4\@JZ } oj2G%9tskh/`诏://k^]%N͟]iN(jN}[tJޏջ|u|Zw0Pn`PV‡J|Ƈ|cs{s#O?.I?!pT/~3Q/k93ڕMBñU ^Xu&|mfun'Jrf K'WeTQ'/zsX-YͿX R&M#؉.\-aqKEX<2I JI,؆ r~F6o{T Δ+ .ӸmYq\ҸFbV p[^+7p;rz؇%FtXcɆCR^o 66[P$t1) 07'GOaF;A4A .WKţR1l.wbIQ Utx;݋|ۧE˜$ }d&Y~1&א5C<E"X]za>䁈.F.MG|(̓biT =v&WpNkrpPm YGA0#SP@&GF#iesKrEEJCݡF!Γ9K/eފ"\85>idN#T$v !F])PD'lcqXda6 qk{gt2D!oes*jP`%|82| b0<}۠kq )Xa6\Ho1* U,5b>#*_c K=^ag,;;! "ȕSNmP1ZnXgaq3\Ambu?xGzs];?#$4]蝖l<Z7OKC^H8.(|aІ\ gAƭ`ʨJ-@V?v$7't;W!+sT}"= |]vgXrQG`o'YnSۭu6GbIQl8u%eΞ~mT/'ulx#u4Di}b;~wǥs>ÊP],ɭtYAƭP}\n)":qTq_+sNΙӧr;HB13Sm\gqq+OEvBȘSs.]9l*m0ɊAձD|5۳qLĊ%hHn! 7F5nt)<8,CҰ8Ɠ:BDR+[C9l*BŒT4 dA |Qҍʼn%N&NފHR,˅i| aו۱9t!*܁$I!󰲹_X\5>rϨa тsXN|,T /{ Mg@c*ɝ2;8,<4lG. MDW]@<%Kr "u| umlhi=j&qT8ciԁI{p 阆sZ4ʴ18.$W}KXu|Hi}PuF6XZвdX}l Ʌӥ$Am!ፏ!+# ';5+N؃aonӨK;eƣsd>}V2Oފg]aPed1ĸ9v7 S8$$1( O"Z[]|U](ĪSI Fd4]O ףVW>0hGa3M}Eۊ]Zۆp2dtOC!ܛmDbqͥ#>9cGnG'_꺔hi@:# G|,@JC3_J7ZZ ;Xml*=$f9Q>YjÙj$Zq\]R ~:<א1LG-J6%U  u2rLJrGE@V6X{e#ʎT3 W+hqጏeH84oA. Ҽ _i8+Ko|,,ڠRf j;Y+ 8,$VL6f@b8ıjF7Ұ,RO>̶LF;y،ݨgkP_ivO>m81:v WzĪ[@IJ7ؕ_hW$$Z\ci\Kq홉3].6Džs>$Wz+ݐnEH!/ VJ|,әzqP'S]ĮuƓ7J|,l2D19p<#?q{4K l,=$6,g4fo )+ |,3opc4.ǐ*,)yAF6n _3#AJ@bDmc ) |,IUߎF %FH5,{K8*^biTu R$Ƈ>XB|,I-nwbH=5j6} +9mP'ssp"YVzrE# |,E֢N =\86fA2rd[\J q;z>Ke"$SZ.8pTTI *3Y:P:ĆP( :ɠsrIGSb،p8.}\ NG/9/+`o/ mmG#IEPAbTB9zTG;WfflIҸ 蛟єPJ$"\z\G+K͛Po~2*aS,R`-_4&AJvtUmHY8{*["PD:aM(ED/郤)j |s-7Ⱖ K^p֌$6D47DO|JRչ#l @Y<1AP brMnaqM-ŗ"g.8:"Nd7,?vsͥ`+ Z=mi].(K-;uL6҄K|IvSŕ-߅@DBڙmxCQl@Qp8M}{2hztPxH(Ep9bj㌍,‚:f7^#HyLv͞nyyF"؉nal# sr4ځ5!®hb6eEAD#iLtvcMxX"CaaQ)dJRգq_H1UЯdTѯ qei}]bPntύ5\+sYZlRf.5) _.%鼾+ ݌9?8,5BIzu2, :~$iQnηUV6Bi\xnC~qsڔnFtp9]5JaqlJrկ#,cK>/R |iƆ~Lk/_,uN$Cl\I|:#Kъ]mZm#)ϖf"6Dž;>_GAj3;;nt2C}"B就tҘ@H:ƪLfG3h?Dl8($\~Ɍ[8sfF#*DQҸ#w=8|@3E< aes鍏%]nOj˂^FP`z.mogQዏ%pg={x.fg=nri6ͥG>eիۘy;/܊^fDs8.^cID4K &n:-E"Hm8&4fG. K^E+kZd?Kp bxB>]0_MS+aqᎏq' x,\7DUT/T6ȦA "խ#~52#S(D*?>BCXrBvk)Td XTgAJKuA߲6|4X Xȳ^22ϯb8>8.4nGHJr+z8gΤ"1^m0y+ o|,-Ll<籜N65@4tҨMĎxbKՅҒd98,$o ᱳXNIN.Zs0ǒX&(VG*+j[f#jpL€=s LR9ؔ/>vG&O/J&֏v5+PNIծPfc }R#=}DzF4mJ\{rz-K)Z\s+.͢-%=`'z0L`y=;H"[R=zG#6Xl FN2[qƧI=4.(`Q" L(FCCd,i:Wڪ1~ͦ`# [A'qY|!ڳW֞+{N tV6:B\)=Y IGWJ؋c*F{gEygկ4l 3Ŏc=;ees?h R5XZٔB?cWMhd$-[b8.{VJզˊБg&Z \Ds+(xjEBHLZ`a#TsK D"[AjFG"Z1MΎ4͢h%pϭsx^+'ʨy+q8[\FsK.neʓSꆻL[2`|6VXA PR )kr1ʞ4A)s)$1fڊ1ƅl$`1SY*MyJbo=&%$v ڼ8}3o21w|V6Q܊+J|xϪX9?79%5B.%wQV+ڝN9]ЄF6 K85:ݚRƦ2[Ry쪕Fa F,Si ]?"sU报ų#g+KJQUrGWP&Ѡ\PP\j7?^rX~TR@܊JWUr>9w{Ƃ l G.yZbq2VTBƥeUҕ0_} 9 XDsK -ԓkөM)TFsK &H|a}W(}E2)/+P|ne#tMZ2<K*XsK |D~VʉeQC6PFD2MIt؂n^1?D(>.tb5PT4L=l,#1O=:24+ƷV4@E$>.HdϪ_9m1f S^V6ܒ(]e#1L^'dMh"@}a<5&u)Q҄ kaʄF9~.-qϒҕo-\.ݨL2[qEoUr/T /W#ztE$>LODgHN1Wj9ddSϭ0"_X+'"%Fa BE(>z)("T][+&2Q>Vܒ cяUҨ1y+qe_nH|nM -דy+49l$`-_r)YMUWQҰ#̼ 6+ZlE/Kӣ4D1LZX'ƷWG2T.5lY뱏Ur"h؋mE > -o+uOW0V,JnƆ2[B+үծp0u1D>bN W :045fbJ&~Dj4sUߖ\"뇾aW]\-wpXAm%6vRSJuce/?/_m7YgL(s{}XF^\,YS|hw:|4bd6GK58P9^ Po#`t|JSxjZ~߰WeZ8(›s~ʐ(d~0wv.L_?W~M5SASX]as^9ouz=+CߺKx]&ΒleUK[4\|U':RJKͩ_qD?O xf j\:͓6UyRBvD%Zj57!wHtXʖ9_ò~1AD PR5nP(*,쪃n=+Hk>&/;I>{;Y H^6-9kڳcϙXA~Pήİ5>4:k?(Б$U)TgXu[xb"3)+ȤC+إʜ+ ?'kb®,0u̧K/~$s[MV4|SKPέx]Yٯ7'.ߢ zG_.< k/u]_/Iǒ]B0?Ѕe=|׿on]mV]`bUL&ϥhi`}+?W~M(p}fxGyaysd0UzG:T`&Eߐʦr.x^ dlcrZGsr*g݋e3ږwzB/Ο+;rɉ"#%8G赯_?:^c}]֬^i}t׾(5^io̽Vmi7MCw3tѯ*릓ek|mvf+}&zs_kXx<Oz^|;^Q8} vO|e14n:nEWЅe|!gV ~H gܨb/wZU+1b[B]g m(D]Ye%pb[rRsqVWV0L˭.{QRиY~骛?.,wHe+P$VPUEuϕSb|E#:BZZ *JRE"F̯˭U)S׸PZ}ʯKeA.VM6u%tV$) EBau)we籧0L˭.Kbma4=GsٯrIL&r+<ۺH&4} j@Fe2L-\5*Q6uKȅL~PLjV$h>/OJ".ʷ|re$j*׏@2.һs)PҲouFu s.a*[ `#ܺ+߬8 jC ƍnxn]MM*c2I2խ/eh%p][qm=;pt\_EwƎޗ4e~]nŕwS;T@Ƹ}J"..f- sBF=l,b#f/Ḱq>IS!6Cm4H-˱!mW9ZB&_ru'=l*vks+jKFT K:rVfVwp.Υuum'E3rB+܊Z S0GH-e5)6~JL˭kNVgBK޿,rrKriR^ShH:P2.Rx?i"|ngCu{C Fi|Tէr/|nI]uͨ^:oK/Z\Fs+nvЌL`P(ןj .%wyחM}Byn惺HBe`>ʹ*:gQOMh"@1!9e[{V*fJ:myo_VQ܊K d$6j|l66! :a_$i0l$%]M<Mh$`-=3QǥbVa}:%n\ѣ/+˰|n]&IqaA/Ѷh$`ϭǭ9hIӨw<QH",[Q~n N#g߀rZg<>.nL&ɑ1gqu95'_5b}U82oz3E#x|n|52p.r ~#JWsnťsR `2 ;~ F 5:$zmRu>7/ݜ`cCϭ@HSbm4dDC?,I8|n[) &i4BtJ*ٞ"*1+yIkJh(7P|卮RVܒ 4PoLf(0u$f.~V\z'-D2qM,ߜ x\2qn}ĐOk:5FsK뇦$Yh9l(1ͧh%(|nɕcz7Awm+xSJJ﷟V7J\t%YMi)T;21[qCP[p^2%ָc2 \YTCt2?HT[ļE=.ߖ(Xc*>WF6k؈y)0%jg_TNue# }ϭkiI V$*O.%7F,Ua5]N!3z_Ԧ w#W SbנN.%Wݗ+@ s_JƦ"QjiK@OUFjܮeXR,m -Vk W/+{nť:#Ġr AAgt<%cUe=B=qi-Axx[ag~ *F#{n;cH2,L5n]"H"[boSt[Z8X=E%ll.cùR;v< (TEg]_V܊;0hSFՄSON)Զ ِD0ʠ^fxȆF̱sȜ89J= 6(`(b !1.ov3Ӹ7V6܊+TS5O]/K/"[qNҶIeETe*a?5e>.& mU8 T颕E >{yGnUƭ8H9E`H1-Z\FsKn9v-Tj.ϖ" *)ʊ! 38J?O+|n- (Ǎ@;`dSϭmh.!!UE-?dz3PsKiu-qCƶL %.!u䪛_ne8>.z\UKzOͨh%pϭrN:7 )VFuɑdԄ 66+ؐϝ=K`y e (%J SUC eoS)PsKht T]UVP$zFfSaϭuN˂S`:k\P/ԥ.%w9'4&Uzռ!/,IU# F6I,6T[n<[=%,x|nŝ;m S%T3_%IM(uhp@Knn7|AC>[\sK\cK3DPD,>bެvKS1jx3nsD{VܹsEAPȷSY&Ahes-.cʼ)ro|2߂a6 +:aU7^[nޟ66*%$;  %|QHbdC#fۉSdvtUVG E0>ʳ}!rXYޑVͧhesϭnά (̯*Qa6 XsKl=v =gUwmnFs+&S- W'6 leP|n  Qӕ^UΝ>ʷ&=)楚gEX"6D;%Ny㾢\Ks6 Ls+l_ySYU*/ Ԝ*~R& LvotlcQ/s+jݙSv&W|`;1MRe%p-P*8\WzU{u_PJ"[q]]S~UV te>@43˙ҫ RM%;*"U-aqE)m[-(l,c%6FLV].2[n-~b#F(cWUŋrKǒ VQ܊+n(HȮ\+kۂ$_V6aܒ[ؒR*J&Ts+yTNgU^pF+0|nɕs,;xVnHx]Jxչ|XUva%p}AAڽ}=ux$kp,a`$0m[b!ɋD*`![rP[{ .:Hݗe4>9\ʵ+ݪBz+⍟egE4>ʻqiN͋VO $Gw_VI4HVK :nl0ܔ qӭ: [* Xs+l}K7kL}zֹUwp|(Em% V\yǍ; Х`KF+[l; HVSὄQDL>.φ \+`C/vF|nI:SUE۹g˨|nŽwbUŻ@K2H"([a\ׄ*T]n͊wa F6#JL")19tdtE:ϭ}'N;SnU rKXnؙ.%w9Dk W5!MQO$ V\y'i__58zE\>V(7XVv%v}DF"([AOJj).IERQ"Ʀ2$[RgM-:OI; _V1܊vL`nU7hxLͧhes-˻vܰ*+I >#Ae$`1SUͧT4$<=(%_6Aܒ S*ʭ2\ONkhFE+ˠ|nťoaU Z/bgi|D@>B9eϢZ 6Z/hes-)r5d)J.un\~*t8Uҳyq܊;y2d )^"P  F6Q܊:0m 3$XAά^Lr=\v]NFsKքP2 l[L 'Rʰjx|0}Rt4[b .a:A}eEP>ҹvi>ݘŷFZ/hdc-PFa^IV oz"3_y,MECyX5)?T{s Et"6$ʭtBZ&"Sa/|nE;wT+Z}=oe%pk..FҨ)V =#:UoaeqFs+KL4n斲fET>ΝCVUPd|tK)PsKreB;ǪC4AƧy_0ɊeD>ʳ!U>S5,ɌX~Cx8[X_ aϕQSU[L!?5*7x<`VL2.>Sy|#?!t\#w\rНk"bIƧE<>" ;a9= nL`aWsKrϨ+ZuWzG.χ^v܊v(Le= ]fS ֹJIsYu$,ozH:"6Bʱ ("sa(60-籓ef 8=F(|ngL3 `LOrvH"[bYd̐oǣXRaO|n-+ЖR:^e235@E>3V<#LoK_}zd6܊*׊&S)) 鴆iz/+{nŝ; z,7d4M) XsKltXt]iVl|J%ܯPyB-6d.n!Gʰx|ri:#{nEwo2)od|Z7.„l$`}ϭ7`lK60Hͧsטզަ$$GJJ浭/;9sx$-b~{A䁪JG7M?7̟dEUi{؁)-~ۯ~nCp/WhZ?|,ѭb[ʂn쯟 z^qV3ϧ_T.S\^50ˬ9W%鵌]ɑCuk/ۺuX%w[?s{CW8?~ZV9\N/>X~qz/9ڣGuJ ;Aܡu.>|< ^)5a/WX3tL[v"a_=HqACκ^:Ü7_?=_0琤 5bxlb_='~6ً wTq5KЪ?nTC? 1nS#{B}AO*vg1Jc7qn˞ӗ~*|#lgmp{F%'S=lentB1'y)DAJO?w.G۷ǂZjVgI`5&QњJSYbaնd-Imu RNug|ř?3vpeN(.5ŏ0g,_#.FYM+ײX ^fGʽOOjkܽ\nEc5n֝Ssÿɛmڷ9ZYʓṮs]+|l60G<'c` '/Y>r<1ϱ>V|h,su'ҝL^q|fߒLkT߲ךg| |kMq}+_O?G'KYO_epZdT/G+׀,4ՓվGѱ úþPvǨ?/#ĺ%WEl[ƙaY#ԏ1ؼM[t*/2uZd F*ވ~ adcL[b/W Ya}mKbIn'- :e [|0ߦLV=\*Zs,#l%8|ҩRpǚnap?š,N겳 gtZܯZ yŨ*OlՋ^V*bxƸdrP=+ʕi)paR0THaenqm "OljQD;A V™}ƒD"Lng1l] L'K' ;N5`,ƸradҥyfͰu{ХXMNF#< k;'Ԉ qY-'g(Xg)F6i6uUAPU@_sSy ;֏PSed@+o`i@N,D]l#8ҡb!8Gʅa񽄓Gދ[E#΁v'[;X.K ?W9MeNnEmzǍʸpeXϠR:AŸl#ܼe!8EZp;W\BzPn钯2R8V4p+JV6AD8s7_3mٹ@ 塑&y%"@UU Nu?ȉ鲍p|bʰ|FG ɵm\BQn/D/=b:y^iX>C0.T\fʴ :1<9dP_a .S1(RV3琛K|nJ% :/[B}b!_}2N2@R"Ѭu,ҥr+lǞBCԆJ_6n߅7UV #TBB1y65#'̔V⺶dػ>k=puO^O1JOZ\ɰf4yOlC>E+ jq(cO -ٸV^%W"u3PJP6"* f#<nŰ`U.##f-Hӣ_3R3Ҥ=G#T+"t=<]5,$Vhԓl.SrK/4_xX N! .tjQ 'O dyFJ ўF6yp%՗DN]D$ݲ^\mh#P[Q'!\ot5q=9V DpzŌR0ȽYYh#$%mK.6O5vy#M.E+$܊0YKmqc(Q:R1vVPC* }Yҧ`^rsݦh$ '_tȱ0O|5 Cf !RrSچesnbTpvw5 #,顏FulJ A6,Vq9^=Ʀ(HװSmO|ٜ wH6)_#kVO?>`O8ͮ+(YM+O Z[*fq+#Jb6Nܤ~۷-M{K:IoEm3TR)n*FkfsK|ѡ4M@Q;b'[^V[axҔ*<&2h$`I[b} b1ذJ1)%)w;`3T3KϕKmy衎VS-EQw_Kh[La&pn])ܮPlfo U{ZXǗ:7js+:p3Ce5gJ1SUO$OMk2X|G޶С?]6)jxR/zDlP__ѱD1Umo lesO[v@Bvebdjo` >f#u,ARO'.4IKS,c<pnUs'6Qml(7sK܎Q~Q'E01"z 6zJp S]g7xᦘtYLi#@[A;ƀ?=#yy't|Y\n\_t7p};T.!%*];@qic$O{b4pn鐯E Q bwe؍G;Z\nEiz}bBr| z죑E, n:#nC%/Yԇp|c/= 6\^ \cGl \zX qAkpNiCR"|HwՄFۿ%!F5e&OJUKGWɔ} T䒯E,KYic+A_zsK|bi=#.|ll/xzV~џ%K"׳Db[2q0[H%Gon38<:.>m\%p|aPs#x1I?wbVO-}QZbl%.,zȩhes[q; kǸ;R$D+ܒ+Jb##nPe$p*zQ$| ד;bAr)Z .a8tɗ=FrW܎'נ_ 7^F6%"zƉqIJ @?l*hs+܌AN,W*y:N=8%|Q-c.IY{bAYv69l$6"vb ,*w.YyhJF#  g L׬JSnPa$`M[/r"HyxN9mkwXK_7Bj(s.Q2}&pn/ sH+} ʠTUҗ&pnHG"<C-#jAV6aPڔ8 m b+".߅}ojvh;&XU<}X^T:=*RNjΕEb!pnQJ)9M֑=¸:2oܪ-CφwcTLۡ=R6^Vt_zjrC1NmA3T5U6G-=1ny/\*d3UsJb8NCXtZ'˒:4Ʊc<rVgBbGzp 1 z}/H4(QO@E#܊[= R7LU@BF6;%v|`k 8XՏƊȺyҐ6KXIZnD,4̉4]ޮHYfMnI 5N_V%A,w_R/9//ɱݬ*les[q;R%J\TѥD/?L2_x)5ғ/2<pn鑯>/NI^-J|Ef_V6{%FT-^FlxT ՇQC["}a"W}uQADveEH{Ѓ_vä/+a[T9lqt~1I0I]r7buqtB{LNeuKeG-܊)t\z5 y^,nٸV󅆙RG Z` T})AVq_FO-}L*R*L+]E} TDrKA/9J壤D%e%pE[qƧeJJAopK,td#ܾeI/ؿRG0#ᆲl[b;{p2wt"aKLw6;' .ivI7Ĥ%s7_V6kCr՗)+׵&!An߅u/1*H-oӕZ"d~ a7W"F-Ŋ\e67*DL~x4X__iYwj.j_~JJ_o|*(73Oe΍t\*-]ȣZAvUW"y,-2Ɛ d{m5>S-ڥɣpnmJ.]V[1sSLy;^/#5:pʥR*\מt;vFG-=H"ai>[+9Ue%p[r})"aj*[UInI.*G+=܊;w0r{ߵDںv$Oױn9X }Yҏ-:Z]bxG+)dž-R>XЖ)2έ,nu5ں6[mM&meldcU[XFGlŭ$515M|YYfEBT\rFhjK^VS- 䌠AFM>pnI;ʄr }1i5e%p}AYiPSBSU1%@ִ)&=p vb`0 մ-hEE+#,rKD關jxIiWLjo {^/#˽ qZX9ǧEϚp;2,.ksKnV0`!nq`eI|ai$AHm7$($%0ְ2=NpnQ X|O-1)Eh%p[q.F.O1 5l{,vksK,DQ+ gނWîH&aM0ڞCR'۰g!.q'8tIң U1&yd.sK.Q-̸g1U3&y-ԻR( F, ի*,&$6 Я,@D*$V0x-.G0@/}P~Vax/Vɞ^,=^&T1UDkFu.X=`S*^F;-݁6ѽvvGKJb 8R׬o,".6z؟šVHϸ väU8%TM{VX6n?0ؒWF*(Vnpn$Q \3-z5=*֍;t0-`q0bY_)DujG 0: $ ucWn`x6dӂP]CS"}]O#AHE!hIɠf~-dC9q~/EZ#-(Fcll(7hsK#%n. KW2ub$O|5MW~T.pw`vVJ0P}L=Jb8maq0`}b5MKb(u) `=1gKo ]o2Cy\K5X.q8t# /Y bą˝1Dl#m +ܒyt@}buyD{pg,tcHsL9cC,{V KbSF+ݔ{R6vMؾx7k F?-]OLisIP'b'nT)F#Kn8,/ܒ_;cq_Sy4vpn閯^T<:}bg̱yrjPVЊA{xɝ1ҷy `UƩK #ub@:v:[c~ɟzYw/AȎuղ F{cn3z >a?8tv03V2N90}v6[¹y 5nPgxZ׳/\g;}ܒ8\w|[ɫ[>ׂ;=2'e~d+NJ`"%3 [`/3Kr:M^ݿ,qw˄oozaje-bL1¿t?sY kl?Ԡo?`cc?S,%IkZ Y[u ?㲾X?xgWmb~my߶G"D U_s꙯ݢU;d+H:_E/yVaa~/rPS/9W?=]o53\=n/[̧__.B6ڿ#F9 :)|V0SȭZ%,6=~osu3Xܩ:XPՏ/*& kAjIokԯ:ߋmȿ V[uD;!=yU2Rܬ]oe2A[ɩ_jP[Z'n{w _k d2m] d^ڶ,UO͝{ɼEk^f[ټ!>`P-ɻ ]{b'6U_Vw_ J~?eZaƎHo2T'ZjP|㋾."t/J{{},l&U|'scO&rF,.SVaRA}]o%c뉝mZa.췒n_a>Stbo[4%DG?~+ Ol-_uWq]{'jܯe2ԓw//5}]o2d²4UW_ V!-cFPǥ=~(|rc#.2fÄV,Sm)]9~c(Rfa%8^PȻ awke G(K_^GW"79] ؓ/z߈=( {?`_];IT ׵c.+=W7]o4c1Lx/L\A1Eޝ\o s-'xpىw7EV3؋ NP+11o(RB~# E(`` 5V6gлz1{PVAq,/ʍ~ՍwO&>q[A|@|2믱Yo0/RtGQΣыw?)G]3;#VTOš:ϥAwO J^e0<"xSA~ImAO_9=`ޘޞӃ܇Zu{CﮊO2oť2qAS\z0xکlOg~# z+O+(÷ճټX߱Dzc3X g_xtA-AxBY6$@c7F6;͢g:ڮj=(x ǵ?:~+({Ol}PS?F6;UoZKR{NSqF7JrdzO$,d-dN7?vOjo_EF'C0ƫd~+ΓaG e764vtAQy@2'ǻ 4σlO1BWG};؂G`L"UXEF@tWyP zN g(rH~p 8:`~"ىL\on`+X.~*w"4.~A!,MR{ T$<묊38sq}ՏwW+WÑ,OM/똡׫# L̃oC59PfՑw_%ryP=z@YPՑw_œqH秜q,پǻJPyldSSZ@+ҍ:f _xtAZy@@eRYG߫ J@l&+7R(2vUG㳰H<(ᡄ=P}Ցw_NA#[EUG}]oJGs2u| b%@퉪%T }#[Eű8e2ĸړ~,j~'~BT#}y0߉< s?яwWŏf : G3W?lw='Ol{aű8;8gs_yU9m;)ׅJ?KfifɌ7 '2u{ųSꯎ*wJs>|Ցw_8X~p ԢwExVyՑw_Bcr~Ցw_! Q<(h[;t'[2#.7Zcq>aXՑw_N.o^ălКdu9CUuׅF.AO,=O Ͽ _1Xѡ|@C)xMz~ՏwW?aWxUXrsΣQoz rI=xT/KGB,LxZ o?Zػ#6f[AqEZq`L_UQ+ ZD5 Ix o*gb|+@O?Ca.L!-ÓX~woG^4=cƎ<7e,CZ[Zc調? 6VSfDAp>ǻM{>~7ej9~\PE!OGWxwuQ) ,p^Oj?:/z~UE7OE޽\o? ^xʥi[yPW?6uU?(Em\w G`>~S,hMUj+,Wxo+Z?Q ơ,g7]oNGR>[*llԜ~M7x~ё ]X e?/~S5}jܭgƢ]EHqO_x4_~|o<$7]xr)֜Ѩz?xh;1ً] /N~Xoj3g1ZkɸE^@RTjY˃z ꋅd"$"n}\_9.-1J*`ƎGXFs lKģVe.*%5@2uOj_SQOw e/u-ܒ!{ɛ8Wxut1M-RVj|YE'S5pCJϭÂ" X|QHՍWGb,6$'*+ZuT<__uD$="[bű#r _uSAH-hKLdC9sEC/\Lsv{̟m Sj|ԥtG}\.*"%Eenņ^ꆠF"n[B##n9؍g?d<Gv/"j[b#KQ aՑM}]XsKl|V XGTWxTPFsA4?>9ϭA3Њ >A^짠XņʱTЭ[n.&"}`Qo [P8[ XDsKl8vLTݮI**C5@m({@kc0~zPT? ˏ_/gvݧFI#w]~٧ϟMv^ 5OxGm ;g?_e~eϿVp^?zoЃ6kǭ>zt[&@7Yy|8cVnX~.TE6>/*J>/4[oۓ?.nP0хM/}ThZǿ, §4u6ln v[, vZƁ\ ?ȗsx<( <))A5guҿ~ ~COwOp>Z4~OqG&yO5<矇Ov g\(>?NqUhco?Xo ;l[mfj%~S/P`̪늟He?׺|QVS]'wVrIf_#bM\Cv1+kH VLcnn}^Lϟm5??C ?EG֤sƸ֬хp}>Xvu=Vvzb~9rH]_?hz(3?__W|2bzŷ7_Kp_ZN󝶆/0p|)[kZ]7oo}ejdMKn8~sű&"W4SZZs[62|Ŷ~q"Ћ5oտ~mے/za^'0?5TN, xQt|o֮/.v ~iO?/]7o\~K)o||ծ1g=F?y(XP>&m$}\_(%9^Dn)}0]9^bvga2@ .|KDh<=:yeѼ?_}oebSGz.n軁"B g;F矷}?k 6#u["ɶ%`oWmÎ1hR%L?G UBA@dFdD Td" YaD8D O"wؕUZBѶ6ѳR7yׅ⅐eEÊ@ U"d_&U Dׅ$`[n"m"?G·DVy%(%^^D$I,b{EB&sWwDV=M'-?x]ȂhzGB   bLKLKHLoa商r r7PN -&cJLjVPD VXX XTX^XM&+_`Uڃ[OүL DYNDet^-CPM&+oOQրs@ƗUNDJ hR;YD] }兄m'`z-܄E;kKSzmPK&a7vNa5c-6aB$l7X&_Rf6Kb]w'ȶظbpl_ `{m E{>gx&?-~6>O 9>vn{,Li'aw_ykh;>gWG˶k }^|{~;Ƌ~vp_+Qf5XsM%8|5mtM&coݩ<> M7cb"MO?r˗kW8C}E]Q_YTEe!ė#i*+!_8+Cwztg>[<~+|.||ko|S{_|,/!|JuNk#1 <^-fzͮy֯7Ǒ]೑k`e~SίL{ozeng_<3w*A&+Ԏ_ÿ'6k* ?1Dz)qi!𽺄-r!a hWuyp.|G"ɪjBWBç%7 . 6v~YFks;da \?Lb^տ3Cm)%{L<O\(׋d.|O~)Ep$jBK~Auzmʯv|QX] -99~[?4©{A8Nc bY}]Xç ^N~'>/8w.PzV,)Op2!4\W`zo*Wn'3q.t-/~Nt?[.oB6*6=d.RqQ'xrp#-'ϗ'.xn,9K ּj8>di5l[{ [_F13ӍE:3[fEK4M>;giSq)fI}9ho-7?}shI\'<6Ͼa5v#Ο%D%Ͼ|>* u SuXx&:udG^g#=uK3u5+Љ>rY|ɾ/Fa׼J79q=3^>z_O|4^]^^~džo,|X˟{Zu0ocӄ{"ޯk"듕oh2uc|^Ӳ?/_?D5VJącl9H3~1¿]F睜+~\`kuEqM,~fSaVGї`{Uj}Rx%wQ\X1D4*م# V[yWva\?&g#=j]Ey3 ~;ެBj`Z  *,ZWrsD[׺ ΅~ X1XAU_^RYqcr).HՌBJަwePڸ_Jb' }?goo's\T \Q8_1~u՟6c 8/bH>Hɯ5H;8Dܦ;i=]ˎ.cgD1찎=l.K9V\QjyvW% w!7cXF]e$`Q[2Wj/Ύ=V0*2:.J Do˓+2׮.vs+(GCę0x5D#\2_GvrNy]p\;4򰱙S̭bF+o/J!+^FYu%vAJsEiėMeWnE%WAS*]`wi|Y \d Vy_S>|ha. "/+<ܒ(M؊_BLڨN66 TAߖH}t$QHb? rQV"qTzV6{T[OOpBuv%D} ]7x݅@ ;1|#2OUf5  Dg/c`dcY)Ď==9aX$Xq6/>1ƾ%fЁ!\gSپ @Q-c-n~Yx|nIВA/{ܖ2$&fTV܎19ugŁ-ˬف520l.%g%d=[g$*'Kԓm#0ϭ̇mQysDċG>0E(S( XsKͪЌ*"_z` 5B]Ux4D0>bz@kN:U+]=NH*e5X\sc:H4 VT4 3w0QlCG㢑E0>zîLi]NȦ2[Q'ͦS"sGC_M3$E,"%vYL?LB?n rPJ"[{DRq݈ۙv q9,@|nEA8txd$P{9zLqVy yqh%pϭӹyXGQKur8[\sKM鴐2GH"[R=d) ׃S\r7)l*ah& BW/ч[vD>: Jã\q:5eѴGt Fr+jQ𰌤·ܜ,nc>zLh: ~bgvcKqd+@|nŝȧ4=q[E3Nsf~,Ps?;n+ TԄ66aܒ1%C3@vݏrىVq܊0<ǥuV} Б)l.%wlR8<@߁`KH}b#hG1x>pgo_ 2Fܪ#S>"=Ob'\;J'l,v`p=e˦*|Or %iJE+@|nY]`EqCȃs̡ёE2[rOV\7D=x ܆?c]`G&#J"6heD>^Cqŋej\+ܒa%& ߝs U;3XbGV6܊yojR5!%tDCm*U 'SO@BX(Q2[aYdQjOP I,u.b%׃L^R9 | Ρ#lHc &UV\ʡANp`Q1}ُeD>z`qyR`in al>[ \Ds+n]²Gv❃Z Cʳ/#|nU]&Ս8TRPَƼЏ!2d[a'4Qުј;R5E`>t;IUŹp!#M*Z\sKGx24 a;C K}jRE# *piFUVj\p !ץ)("%Ri׆AovGa'O/Ъ勪D#?rrڲB(e$`)Zb=c.??\verݬJ1F6V=vµj5 _"SP C'":W<;/Dnq,gu׋l$0)Zb=cש+sBA]0('3J&6NwRSmCqY^5TϤT_08?YB1QX&ololcS%ZQ;FUͧaRHL1`N法,LjEDȁ)ͭ;](U6Zb+Sstr98Pf]\g*Ԓcz^\!㼙вTPhe$`h[b+_IwהrE8\9Iz~IhĬki|P(|w3Š<5Hlŭy5`(b`zV7j~$؎Qʪ]1GfNqƸ[lD?RKw25g[~Bƒ3jBLzIE#8Dx3:/شcbԉQoͨhdc?wDF6bS4v|jc,]^J"[r ;Aυ}/zz e4>6YxJV JX>Ў.c #p|nA֟O81 cQyY\s+.nd>cR<آ*%Ճ:Q긅hedX? Fz|E4>>0j1}΁Q>օ|S2"[rY xSP@N22C 0Fܒ:Xz!6_w-M%iКRȦ2$[QF-,@oO`']P4[b'j>Zl_`*=b #x|nE*ycN'(>򰲹 ֹ'b;F)3U7`nVf1+㇕E@>⢴#U꼷${*R1m.aec3 ֱ}T"=cHUEF@"[R=sd',Yy|t2Ŗ^SyY \˭U#? iZ1d AE-Py(*YjA5'T^V܊1>*󙵊2iAS,.(H" [b e6ͨzBӖd=­`=IicCϭ멲cP}`]hC|PH"[R+9.M(B~aR;V6ܒ G:5 [zD)e|H=,1K)Z\s+.:Z׋x+,Bf %S}G5PDsKtXTzdԺF [wF6 ;0:t$@K E6F!s;?p!.JU]8,܊S0˭cs!&P 0 Xvbb?)/+X|n{!zG#]:+_uh68ODdʃONbM #)OH|nm[TnlɅ*Z3#[ \DsKh?<.D~VK9+E92VXT#RU>!T(NF6UԒ ~V(0p(}6D0'J"[rЏ G:by3)l,jS aUr6ЃzH`"[bڔNO34,V (ꕆL_Ċn==2[bFԝ>=Ǧw;E >RM(e&XE glO'-r=I 1g~ &Gѹ%s!f{TҘÊ]gl m*UGc=!2kQ_Yl.%W{g`sV,# )/ |nE#s#ԣRNdtyyGPֹ2X*Ydt_x?P1TFsKꂠN],Py _b)0?7@E>XϪY)KKbw{R2 [r ⛲!,\[wz /;q*ԄH*Yi\̓8̔!f0XA%y4#>?~hBE+8|njFyg7X  ybV7X \sKh=rjw:i+ÈQS3*PFs+(;n{XRJzJؓR^6QܒQHi0[龙RJ" [rkJ5JˡjqS=Z2[aQHǽ1EF0S3*Z \sKzg4(3o"֏[P0 VTAAE&-sZ^tMh#P9.Д*Y9-acˊ{^J"[qI>*܆Afꊥc[s*Z\sKGAgU4@x̕d>,Si ]owuC'w#\g+KJDgH VJ;ڠeEq6XAxG"j\|.OLRů JaVkKЋV6`>.FNLj$Zlg:J"[qI)f@TK3ex]#8|n֣S()wUNvb2|!Ȧ2[RDcqUҨcJ[7F"[AŘzt*껞O1E p4Me>qUF` ߗnzt@OlAćE#]&`xb-1\Vqܒ(S"WXf jhhdcϭ,yF:b2 B>z81D#0|n]LlS}eܔb1ԓ/$b#&lDJ)߮Mi+*ƄT6~-hRҕCЅV^@)Z\s+( ?8Z]9-e#̬+Џg' Xs MԁdfL?XF䓑Me$> ˆ|EcUPAfW5 XsKGXX~pQ(Uݸ0maE >³<*|AY+ϳ&0|nŬ R~F6Γӧ^a&L;kl%p-_r1YM5WQҸC̤wb V6K^M>T2_P+F_uF " [B=dqh2ycU4_`Iy XDs+g .%T=7S`XE U4e>zہ*_9NƘi+ 1@E>za_Ui+ kROT&rPړLZYj}W`efIH lcy"Q͏SKuc%0?/_ Y:g;#'s?PuuQu׉@<@8J1*Vi׏G:S4lX &ϕjyQ~tOf]̼åxsͥAܳK~Ra/V+zϟYê,tM6{umc$J"Y5_0)va!̙] ׿ֶAcRj<!\U_*=#n_ϧ2o/}ۢ0~lcV]J jUKZnW\c%d%s)t9+mSכeUn0u4S=: #*E~WPC𮄅l] -P̄]AGd-nRa[V,`?_}nYa\j\5ր\uSˬ6]iv?Y7#@5{P'Bq3kfd]߂6-5z_ڨcIA>q%*:JجcXj=pҪ;:K:u;Nub")]S(XO+r.pXj ->?3.Ͽ jsy5=k\ߥd׿h# t׿W\Pg Q^Xnnz^@JѹHU+jh3>ŧZyuXjyqrTo4W'g~R:Z\k??W.xfp/6F3~'h8G趯Nh! *~ -G~~]8,PmB!Xg,wc N/C}9p"vp"5v?<Ҡ+v׮7Zetw2`h%tl|u.qfK1a_khx>_O=H^zE=.7j5_o*K]%=+=-u)u%>ulqP^,qb$)u%U~UIMAmURj>0Ll&r+K5?0nPIUV_JꖇDalsH˭rJ@䠤"T%.r\ UOKT_R*Bf#ˌ ;[8w*o!yY2*Kp5<+Rހ$QE)$oX@2.6ܔw>$$b|# ˯Ո*ʪ/vUeZ2Ȧ˭rli/A&so~/e6]nɅQZJB?Υ]Hm*rr+|BHc%*UǸl_V6t%c!I~׫Oj6m\ O 0¾㛟̮ͧh$`J[bٸE~oxU 2ĝ-K1-Z\V\:ח4䅢t}yWqfTȥ˭\ށ y!UǸ*C2L-r΃M61 oAU!z X~ԤSAjoR_JbJ".޸/Y zU1=NE/#d +&;Y.ƨ,rKk$rӫ虒LzX$FLlB4QٙwE[ mKZ+Z P$ِ4$nz70gFHbs6ºd㉕t$]`%T@uE4su$ ,T$mr'& z XV؇xh*4EB]nɅLM`8?qV6)uWa$HFB2H-˹I 3@Y$5T&VTZz} ֻry?T01WRSKMJ{ty_KJ"..Ϫ2(&lغÒMeR]nEeF, F~I E#|KB~UĸMrk>E#˴ +ߖ"^'J^ԇk/ X_QĆL(wAFK\93yY P|V\yXnJO])TTf{ C!=oKQ+TdVԆ["j Fm恷ɍQ%l.rK> F|X"@[VJ".V)FSTk(n<+ @]b^J".cZK"x +a'no]m0̭˭M͐ԒBAUz:AȬ˭\> sPuګ:HN/ V6z\6dcSWxE*9Er]n]MnPXxPN{% .r+"Acz-\rxZ_F6uIϘ7KwPPU ;s\Ev]noS30|TՀĶMDC4[9wyIqgP2HܒܙE.eⱍ A=~F%."W "[BƝ@K,X\FsKv0d\Ǡˡ`$PϭmI[y$K"F3E.xPsKI%LMP<|Mhdcϭ ,0ZЗSOj\׌j_o܋98K/Z\s+zpJW |tb*FbpCCYi)#vLf&ꀷA}Y PDs+.P,a[8\Of2"[1틞XȀ'DOtY'Mڴ|nɅgr+lԩpuy2 \Ylr!3,jD 4ng]* TDs+\c㋚igM.Lڇ -")mtLj,qtk:E+Us+ns 74nGj'NHml*uj^l6 \ ]FWsnEg]lH3gq2hg4>ByBMjc5ø}Dg+p|nD"ga{L5,fXm 6*Ʃ3[rLoFDlH&$iȺE,>ʱvJL g:k/+sBNFe2fӶsrFjw[pVo?vo 1[}h"UƁ<1'Eq$)%W~ Iec``{{nEq/CHkC'!܊+ZkPfKD F6ܒC%/);$X:9xOlDzQ\]Ӌ8y( \IF "[B[]3InH+WZ oSohdc}ϭm'KY7K;_圼x;֏3o}TFs+|[‚ҽCv< .ye%p}B'eA)N# ]p}m$r+k/ѻoH;fY]tx|F6:vV.Nc V6ܒۓ yxIɞepa{nŕwE:۫'L h$`{ϭ!} Xց79 kԱTsKr,?!jiLJ45hMh$`|-˵%?' KCyvf{FTXF{N*;:𞴴r=OᩗE=ʵ';WvhY \sKr҄r䒫uM* XDs+YcYeXFg.`es-AJY5/.~Ӝ FQ܊wHBQ@An]5MeT>Nͮ ʥrᩌaKP+z((6?EhG"ʷ\xSZmM0 KN+Z PDsK\l4+cJH(-Z\s+.[Z$+Y$zFQ,YX{LQy; L@2j^xQ<=y^~mlGϭkj2Ari\Џ5pN*YP_LFı,T)j!'nH{Jk.BsH"s)\xGFTV6QܒK(++t,0qFq (iIO.Sm VPy6Hϝ^eLF 7$mED>.)9 Z:gv<4@E@>RNP椞ĪH/ʀ|nI]uM&s*jxAJUR.WV\V%"Ȱ2ٞl,j!;w L^*jxCn|?5E@>3} ftUWVjlMD@"["cBUVHdyFϗiQϭugNʢSPыy-dVܒ|$$A\5oK<}sEͦhes?Q[Zn.ϦK*=i܉;R+|nťwcʎӫ %2[aΞv)=y(x[Rk[ƭT|F"[RgSSS-&)޲V\ՕL*xUny-?*U5J*P\{|XD$b% 8E*4ak+'R F w#V&bq;01g#r%v4H&Wגּ%{S2^VغHL:9f6jL6ZU@:{Tk~ Xs+\+nkJ*P|Wl.%>pWj3[Δ[UmeE=ʻ%Y:l0ժM)[V6ܒ#wTrm-~b#`CDֵ Ώk&VݚS.*ޔ[׶=(-ᗕe=.-)ӪⱔkdE>⎝HE[VK?ue>;0{ ZU/EVTݚSRky?cOVz ޗ(rK 2 \W݉V/Lg/+H|nťw,9(ڝmU!rTW+ކIa6 XDsK+$|Q-dRlֳl.ưqGʷxaJ{ԹXkݔq#gV.>z<_V܊;s.CWȵg_[1/+7rjK_&S+[U4$i Q"/#|nsC:gMVo)hessgRz)٪}`uEL-jrn *^Rtn/)uF+|nɍޑ;SUE -չu_c$.CTRVUF]e$`ϭr'!nUܺ/ĤlOGI!cUţ(Q08')BgLxE.9@E`>.ǚ&Q-HU`UҪur5 V\5\ R@mxzd,`%p-|M P^Vzh#|nEoU i\Lj".ERq 4|n ]5M~2褈?V|~H".[aΝ"CUU G+ĕV6ܒ[r7L0Yɱ~D˧@؆FH9V5E7d:暈O=-V.*4Wfu3dz>suOs+,{h%Ԫ+I7ͥ`#@ϭcgMJjxxp~h*E+˨|nɝe%N[Ԫ/Յ֦1FA:5FG\9Ag[ZXs+,c% \0Ʌv8W4[U ӄ$t|*XapB+i7zgMh$`ϭt$|# ;@alpF61 idO `4Us>Q3ksϭt |[^V /ʣ0ӰamioDlH_X'Pe$0ϭuNې;* |W~k>E+s%w97Bz%X}~U :Qhdas+O̓^ /7Sa,v*`;ǘd| &Aʵgʰt3jq/ͧ`"0ϭ7n k z&Zu&MmFK]hdcϭ3`f[(|Nyx֣>!s\H]s +ժ5pʅݾS)Z Ps+.XiF0Twq3ӰF 66\ct೨bUwEfgu6܊vVT4RZND@|n_NQ,^Yͥam<+b}@'ytZW[Hqꑋ5tشWPKmOװ&rl\Z1.efv/{ܸ_?QwY?o{FCW8;~YV9\N/Ou׏'O_{|@(J=C`!=Big׾|D[{ W0(c2 "q,r1PS 9w{KGc> .WPUb>~'>W̕g=&R}s7JLZ!P:~GB,s핆&U٘ sW9p|~zm!7?{ZhYk/xbh]U/o=NͼI%v\@;پm/?9ܷx!s@ 1B Y^oMl 'Q*9lG`?1Ѱ!ayME Vז }b 2't Ǔg`2* }m๺lџQGS+Kߵ,?Še,0j;1?q@qLp[C]cn֝3r1Sϝmg]˾:˚|Uy۱Js_{#l6xyRIhOǾZ8<~?|>3c,_#|%ŗo?p-{wane;5 ^Gxj!ҿj5ikz 5a_y1g6ջwU+ׁ֓9pNoϡӯTİg |(kf6,s`+)N+8UXejټR[:u C12Ϧx$F?0(-W(VaWp&eX׫%N ~X \dt:w㙋Q]i%~ F\\*ւ6fyie##duzꅻqB"sMV9Kۍ #QeJnn/FU -0z XV؊BHǰ/26L#J˧Gn`InNq`(;0}b.LnSsav.j|̂> iM~s!8qb qfX5a $߬v9(2br+kVm1n7zXrq,:" l%@iL^-eqˍk߳J̴-ݙTv}ׁLމ"w=Lɭ7 p'p ŰHIcl*Smrkuta #|V'֍PWec:+q!a ȫӣ1T1mՇxrKΊ1tI0':YG :n9.yrK/H7,w >~Ć2'6 I} ˰ϠV:Aݸl$e!,Vh,A=ۇrK|Qd)m/2`5"N:q?;U_ePnuբc> 893VK jc gmܒKꋕQ'L~b%KKԖql4*<*'ogw  !)ȗ"{_3Z[J8>TVԉ!!v dջe6 $u,!%VHrLrW$xT:h]NE+)$7N-Г׷e$yn mYs=b76Nq3p ʘ<d*v4Hn-$ܸ83,%~ܦuE~F#,5\Fv9Dnf?[䲶`r[= p߬4 |w&s0k*d:CRyʠHy@ GV)_ETnŵQ]@*d܆1V_nū[)XVWoBI6 .!)+tiA(R}ЉTt2Z66)YvuJOvQw6BJ"-+X־/lM}+-ZOeO(}ܙq84G.rrK/`onp+hԣl.rK/=ܵdoR?Kc=Rz "vȊپ(~QIIZ#Jp״q*"dRx͘X;Nn2 $-uaq~k nȫО9=l*3rK/F 2H}C śyZldݻ]Mjls eR,e##$-cţsc1/URiN2.(Udi շn d6ȇ˭'t܍+_a>ON*FxX W#vAȊmҹvtݓ[eƣrKKs~x4ϸeP̸y49l.r+n0,/Y տ2nҡb,%򘌄5Yz}Yr_]vЙh%l%__ڰ5=piCFgClȃFxqVӗҤcz D"_nA^d;CzV0puGf+L1hW:OO/Ql\6K-]1lXؕCyL,C# ;0<]186g؆\HJ"I0mXކ}ܰ䟻$(s!mװ0C 56,Hn+xwt/VjFG?Іs=UlIg+չ[rE)i-m؃jY7nēd#@O[A'n}{\G׵ƤcJe6/v̒L?~ڐxeqGQsK|b$!R&]a2Tl$`[aƀg-["G<]&*IF#m풷D1-u I6)iCFn/2Tۖ:*iM#ml[c =@\]bKJb8.ʔmW~u٬'ngU&`4:hs+\Z2Z+M|L+8_0n/snWyVTi@'˯ujB*cee#Zh`umrhynb"d;^6%WKY9crUm olesK[v>9}Z?[ӐKW7N 5n_L9u%yE`1m[$FG>{\Oܒ)["K] [`4[ ?v}Hvzc,H O8H-1uTZ aRBg9onHOϹE1T.!UOJ&- 1  \JK0UB[4[ σ"|9b% 07lu=m[zc@ a$yUۍaCv-°cZ21$0V z꣕E,o:#v Ka%A_e4hz nÁS_Knza7tW!ಶ{RX%1 r"/+܊[1 ;IKY|`!o@mnIAxğKHnnLu~/wQ]{`5rqz3aK^beeilܙ5u1ǁeA)ctݰ on][Ȭ@YB?0VXBPs+T3SuNzҍfhd#܊*׻ϕU `1X8% t7rMy0m/{TO}yT|pe<z 秦SP ^%/ܒz'uJrPJ^+a}aXXyFeFHnz-=?l[:+;aR:ŐW/Pi"0[1VA;JEϨԫn5Z\nֹoa%0-]".Ԓu%hYyGbVqpJH;1E׷Q JKR.>f+UKn:}VRnT/l,7sK,NZDLrŰTz@^h#ܽ tL`$oI/Ol%%Y.nGi }aIFʽ܊1אX:!T~G}Hb7 rq;X1ݰ;F \nqHL^:zIvt[xrщԋۇ|V6;%"Fzn:M_ME)%0؝ͭ~&1~btx"Iceon8̃K>Č 7Âlmz~ĆJ]/VE*xRZeD_F%E5,0&v_\ KT*C7n_آͭ:ٌB˯折zceDwW)VAh6suF Efzt ;*[hܛk#Ls܉$fMnIN_V{%חA8%bx2)7$ MpnE>) p岃As]'^6½UY82j< 0%w$@ybi$8!_~Ҽa m+'UgecS[R}!u J2Zg=ܒZXDkB:e^]F-CCwϿ" *lhGH;G=.:R? aU=j*b-N9F=31D!?mnzWEH(0e$=_fW"VoMh*侬l[Vg=Hi,JRYQr&Q+C"ŠRcKQSzln5Ux%_ё$Z ojoi+% mm"i0H{u.+.0쉊/SJ(/®TݗonvI+HHͤl.✱! %|}ո,tEQJz!1hdݾ KTЅ6֡X*R+W&`7tȗ ƠÅU]e6w*ULxܛ!Q5$(!yp;}֏"uh$ ͂Ktvz%6[*Ron c#(1)y`TTSdS{bҟzY 7,.Q-5)h1$l*!rZ=w)+G+Y%!{h$ܽJ`H^״YcsK P;$gJ;1;R%n.,`}^1̳/%`eq/\#d(+[fgnQ 1kn"4Om.0|chWCSGV[ʪ /[?}_h_ *z TT)BKW-m<(gub:Rn4ܭͭ)EIƘr ;+ v"=hT-R!VO -}ǮF.Sg`bcnyl27s+2/  ;u:umsNy_ Ƴ.h'=\vKX*؉nv:c~HY/(djYU9u '|p!sKk :c)/Élf+[F6 %7ώ"ط-¨$"X^ꖿapd`2 C  jG8b 8s"(.>3jY8 b j]L1¿}+ױ??• . ?zglLrp󂍍|'JĂM,}@<[1Å?{=Dw!ӏ?ѕgV6.(_6_m)ث#HnI]wBnDKXoifcsFdjA6fNGIt.x6+ӑͮ|1/ؗg2#O4Pa?QQ cvY5f%ݟG=:AE~7 PKHdǛ:aJ>]Mu,Y0SFLj&o*Rp \PUyS]? Y2>Kfv+KwxSU~ PRRRWϊQMg~Pӊ 2[ݙǽ3c-6# IKk?D${YU~ _W߰p-jfdQ#c'L$H[G T̲ Zj<+bW е!27jܼ(H[fPH-*hlwAjcTsb;_ 9z:UB.i;B~ҊE6F33QO~ FmrLqaDVgU$0/ܱڰ1{= aLhg3?:mBE󬼋aVg]Q~-]E_rͥw ]spL?LAZm\mDƳ  z_AӕH~F-Лc5&͟U1*Q:2n(XS=UuHql; ٭,'墭q;m/->(> m6 7v)ȳ /( {;nTȢ~ږ~_Q$I\h(Uj˦J/M5%P8L,މH@~Jr̝˻?ơ6QSu8wxV؏=ÉScQMuu|Wg]Agai{4GEu%F1lYP&NMUu bӆd:j<+J'6U,{n$PߩlEZh&}x&uXTMG~PV^RXG=5% ͟3 b jC0bYUb?lZ3(!vQg]N*1q'J1Ű&@kY¯GEu%RF1lI&o9ìwyձ\4V~~s(=m=5 =S?daRdgyWGMAo%B(,' bjF;i3,z<b+ŰMLQVd(&hv,+TW~P _ܰpe-썭$*Q [Ӧ]wyձ?6aqp›ui86ձ?zXO6ߵ:vl9wlȳAc(rcgpȳ~( [c'}'񖩡vGٙ?a~(=1x{RjyWg]$Q<<Rv8ax~Һ(m6i;٦Kȳ vQ {D8;d6h=UYW~P$HQ CngE+6]4³"Ϻ:(FQO3fwTYWb?F{A;b\*d6]UUYW~Ў(=玭H_wy֕O?Ŏ6b-S("ϺVaC];ҏϊ:FRlc?H0l89iK=UYW`?$DccKٰ"Qm]EuuXMar\9*+ "űen{+[ RŰȥUy#j֒F=* 4>PG۩ܨZH3+'~ Fm6 }<]55%@%lroT2#SC¶lM3]7N t6Qd뼋WI2Ϫ: @~μLoZ3:֕O7aMfSw#u`gs)0(]W=) aLuSx]%tysߟj\ JU䋊  ^XgMI=F=Tr[UYS=='_e@7d870#0'r! BTQKGT@ţ5y.7zSǵSk٨1E y. mS)a'Ywlȳk^\6R [,?QxU{)z2 9l=!0\26˘ޘǵC]Ps0&DOR/[ƣ_K@Wzm_%ǚ< T aS?cͿ 0Bw*aij4y.!,z\flXHK.  O2Ƭ|5@zd3D*N5y.A e{yϊ y.7Eb -s@\ 5CZm<{E^SRm1 #*p5͚j:<ܨWл$(LP6;T Cc%n\4Bl7wR0\~9YUǚx}bGYģog>)q GI|)!%$x"0D抍NϏLbd#lff89-dm9}wظ' n. _wX7./I /ߐ|1ָ)|ă5TQ?de«enrB_Q-~5U[ZkWqxA~]# - (߶sN,}qa'bˌQX yh@+"}nuD _x\Hx%hgogy¯xpɟhʣ.)ڗ/<.<ɈFOy'!E|'"Db/S-sҞ~I_O,^'\#O>Ǐ,$"?OWevY4D]Ă'eh@z9ط/<.|2AJβ h}/EI2"Q>}q#Y8l'V8>& ;[ȫN /<.HwX{+yDžODfsD2l^q<&Š{GƎ@DžDd[Rاhs>/<D$uM7f"JzH`_x\DD #%Zɾ|q#9*ђ\GbO>}qWD?kx9y!Xd{=yD^5Zo_x\%^O{_ĪgR>'|q7"q zMK@UNn*~/p | "Πi> /<.|"~!χE3u'|{{҅'@MoO}JVJ"/<.|$2OpbxE/<.DHk1g"~Q>'|q#IYe~*v |^|qWDFXWuFDT(`כdIdE|2pƕ7>a}L{~dd'@sųDLDDžODfa4} S6]@_-^_-zcDž I ȫ񵢕8Bc2^7~NclGG|N 'nj6FzUz7?&2װPk.o~$ %?|8ʋ"!€Ym2S#,˩O[۞'e{d}O ZnSSP ; (.rԮC /;UV:,n6]>P|$clnׅ!~r8¥p"  ܡ:v;UĬbKZ#?l*S'C7dؽlKTؕw&K:t,g܌\2r.Gh#!Da$6U70dQ|9uA*.j~}|;ǸL =) B*!i!>rtXdD Ż=\mQpX -~eBu_ydiSVGʎLgֿ] f"a> ȶuwچQ({8ҷY.);2jD:dj5 Iz k}GSD*c۪^mK?Z§Zw <^V>xr>eÃ-gnx26''K|86FoC }w7NY)ߜ }c,{|d['Qozd'SVy@sV vwwثBURy?k?>0{3g1| kw\€{(K{#xXKhcTA'NpTKPd¿ x[)?0wǪ;h .mD~[nIg逾wk>]p#Go|r6}?0L?m iC U2ص:miA8cx|jkHD\~N] :IXwIsocEΎodrQSⷺ#S%.^"(л%y-&j[i<թL \ D׵Q9&SӉk%l#@m+nx_cUsi("OMm9Ƃb)c`JRvajA:Pd mт'rmT@/Ls+ \GZ UkM\-\ YvK6`-doa?v ]\  ؁c¸u :.~xQati;%;bΞ*k-7G,XPxsI(d^0 :JO2D@Z|5fʤ# ͕B2, 2t_W[kYQvk-?Wr|z}"P.Fa(7h)\Uvn6"sI(7ٻ]̮[l#XLL ΃E~\=ۋqq 6bOs (Hm2?)sq{Δ`#@-T2ueœEֵA,0\ , vyCJQ`b1a$N]QV2 cN*6Al,(r ($th-f-,nدԎW"&~͔s! zzwuvs:@FhEn䒱Sh)"̣)[¼++!Ng 1%$ܜ'"ۛV6;O7l6sI"}иn*u͈I6cm:"`z\:[u%V˫ĩjB6hrI(wT^^p԰ JJTZ6LD%DKbt 9k-ӗ^8kM8s oP.1'k1Ȩ ŏ(5f"0-oP.'q "$'[ 4¨]ri0/YoٱLs ??/iʣ8-^\8W4-k Ymz%dDǏj&޹t9xt( Lm%$ӴmsiGi?d!M[%&Q. o}И}I6V ћ^ #VNj5Oh6|޹$TkN%"_rkĢHShիvVqsS-@r |1?vpvLcLdV;'HiƂ۝K@q)Q,t`'ĸ2*h3%S;nZ`Qpi\Y,C\~:*/Ү$@C|9I;<§W, k$iG,A Ow.IcF,oypCV7P1j%ݹav4(@z@Blh@Fګl. y7! E`5tm(D@;@ϗy)7[5=M+qbٝK2'680.^9Y:ܕe"0ݝK0?勯Ͻ-_`:na ZsĂN>9z [cq̍? &V %M']M!]9zW\a͂{ABsnO(Gc&C;B%#$˄#<ݹ$klj  A%ב/5a_łڱjd"0՝K2R%W0v}s׉؎Pxń;`_GH~^JFXJvJ`1lys 8vE6:sQ:e]8<Ƃ՝KBvuqϐqWE#zF%<~j?*P*v*LsIfn9ǐ !'Uق?|ݹR:B*| 'd[N6V;%vs?/A2ƨ\Vrl,(|ݹYQ9Yg';B-h4ؑ>8Y*3o lЪOEx wZ>p;LipjQCdՏ;jg4ow.ɴs7BRp]4.OW &\9Tq1>-'<V;WB7vj\:c27׆1cբ,Psw p(խ)k^$b܇6!ZpxP;}v#ͫ0_gL2`!CpĂ?E\֮=`bN\Y[1TT`qkFnlcA%Վ֛Ŏqڹ†kj-vе[sIxrdaGm;'Ki^\*iaL>B.3#'=>0ńATK=rvaɎ!.4YP8p>wv ޽a),F=8K@.I*,qsBIYh% M,&uBR fmVحĩR]K*aIJ&$SqhJqL2ݲAbRO#`E?Pq0;USh%y)D`BQ#dJ$]d6/x &s;m(E.b x[e;5M92wnt6$th4,k-\88D2O—g֣U bқJnQ{[Ӣ=<'BB"iULvki?xGnM6V*C, +.p n;'(S(T[O&3*%D=RڱŞ>EbP<XB* 3xCuNfk>Ų5xQ@j\rjߞɦb!k% )]&M%:BYO6mw7v9!zsȢV$B֕ʁl(ri"Gs5DtAS, d!a<9peX*.ő,89CLC29Ջ3$PdO%M. QHaN& >ZofO%aAvDCFr>Yʞ亨=|,c3ZL$sh9lڵU` OXЏ=rYq 54CK+¡gd &WAn3E0iFOvm_$kح9~6޹tZVy6E>ZX~\*Xn9*ȩzV-q w.!r9,Y G9* &V#%ͲH!jyH95w.cܘTu[T1faBaBK"v )3cqa"Z&P{fG-כ#F3^%ʜ^2A,DuvkaNj^'@;wEppEraU;-(ST8s 8XUg`(Р:@앣'pw. JލG<0+[axOS\XL\Ls 8PV#MWe45Dd0%]CUU(LuCDjjnb1Υ2=3DJm9ݾ-4w./ִU0+Y069.Ӻ--ypzӲeM,j:`'P%+OM)#P8UGL,@ި!QL6m=}ypKkgBCPM!#Dxs W194)\SwdD֛x Z,vK";3Qyޓ1k"Kŷ"S-|eI7:H6VB1$Z;MhDi9!@%UדG|/+Kazگ xoU'g2pxٙqyz@cNض.F2%*ywqì[IRg kߝK 0h9/[>-vc3Z ww.l-4LGӞex(Nol6ݹtXӲr} &d}2C*qkbJ0B9!Ma=,o6޹$U&!hS7(ݢDνo>iŴW,r Q!Yۚ֠;D a@E,Ad~L2h\ Ā߻fe)%?!8c5|cwPcHB9 jJLsxL"ttDULZ 6Dvy^/Wz?A1لclK" Q/qxnBQ1qTeC@fai$ݝK I9=¬ڝm]B6vwP0Ǎ܄bhKաx68C5w.%cri-;"]žڹYX ow.S~WfB!V[Du4DmdpwH"*^P l׉1%j`"0ݝK0*r8!5!$uԮըb۝K2dAcyU(DѾ P֧PڵԮ*gJ%ݕ 26 H$ |TZ M,&<޹qre&)Zv@IZ~ lsI(v;r01"dR˖=chXHxsȅX9WrBS E,_˚j-ݹ$1 rԵz!(NxP2 eyi"C[Ska9,;Qmz^@/}T d"0K2@f&v.: >o'nb!%@HA0ʹڵ?ڳ |H ǐԄa MfB=`8Ùv-B;vmBƂR_<<8vB~B}ν[-'KN%ʰ' S~AVj7Jw,l; 3sI`BC98}NQJ4e" K =Y wz~ɤxu$PszP0&ɬ#ИgnN]d!L,&޹\ |C0+Oh"R\6>\JF? 'PЎE|TԎl2\޹$R=Y UV{Vwr:-,"\޹sD/)PԎ\PRl5A,@$/ C/+W*B;tO{"DV.DK5mSbJ0Oeb!%D嬠L_y߿7|ZUmeUaz(V fr!ɂ4yJu$* i1:l<͓1Mpʲ(.s "M ̑P8fAЇ n͓秉lBG|'Wįwsb"eYiij[T\-+3:ned@DW8,)?o9:젹 TQU:֋bu1Dy_W])}?neV \/ =mP%<"i@3W#ɬ8`>02j~)0\=So71.vvv_%$[\0>W|(THe)r9:tHRQ15ѩ!ޗǴ~cI7C6$21s4Af*<񗟿D4Ĺf}c/6㾯 hS_ ~>-h*k}kŏV$/XBLw~d5nzvm|Dm~.ۚ֏۩u ? +j=bMhBCku_t蚣*ᦳl]sȊBgT `?ie ܖҪ`Eq2+uW ] ,`QCIܦg>8=J]kltmKpUsig3m^8!ʿ?=R=TIXZcmSu0qZFCGt|zZޟ.Tz[B_ˤrYxT\c!lQ: =N]٩߿m>+r[ln)P\)f62u;bׅQ*B~ {Vb}Z3MV+Ui:_lZ)]oKT385=?*X2!%5\"FVˁfc )'Tg4s פb6'2=KBEI-MmEP4:Z+|BPU^ VӡMlŏ֣Dp;TW:p EX.Tm7TLP2̼pXDY. Q-.(w!lQ;jV3>KUF])*gȂ].eb5 EH.ATcOFNDZX.d\FSydckϲEX. QE)NCv{%#,H %l֤ƁI7'b=WZWfg k t,DUIR .0J&V+:K"E-I$-ݶvåsȱ\*s5k,deUzηȠI%lKXK>fL'-o%б\z6oK.)_.qm,(rI(֨b-ճ$C[^\]|xD`q.d* T 7ĆOic$hv0R%I sf7%lk͒vC` MŎL4pFL _OVÇ, jQuo6b83|z\Fj"J D$كr F^f.UI ωBͧ)rۻpvK"ߖtN 5o&c9T&&J 9\*R;ήUM9_ĆWNeb!>K ,(A&9WJD`ZY.ɴfՋTb^\Ӝ(bL,&rIhQEj=Q]X=ejxq2&e ѦJR=KZbL "HMD !%֨w=+WL,$r JXpnA:4v@D`ZY.:FՁLP)I@=06 \j"?w!^5kn KXh"~%f]|ut{0d#+Uםpa.94pG Y. D#M fskdb5!dS\{AqgB]qz:Ƃ",]H%wnK:+.I.90\:[m#Z"P_9EH8\:KIi#kM.3B6"%lKwQ_9ݖHa3HK2Eȴo*o*x<dž(XP[ułDӔCH*W>Ssln#-,UjHKAkS]*jd$t1s\BO燖eb!MK ٬!k2x;N^=R!&ӂrI&U9Tdzcb5@䅩% zI sp|LRFkqqZVU$N%lWșW^V 8bK2MT0{[ٱbhF;].K_ZD!g᳅ w.IDN=Ӳ~Q,'c}C+XXHsH4ѐ*h./}O6VKBѬۥz6M m,(߹ ʦŹJ`#@WCAbiQbSB)Z- w.D#H\^Qu86R$Xm;dPuPG$Ds|3pRO&߹$s8ٳC/}Cǂ4;YX= w.AF-IZjʫǡхB@;DvEH/Au65ճPk MZ*$ɀw. DkE O\޹TjR@R-d,ehHN\:.:BXZU-hvj^\ʆf,Ւ}M62pzH t$Ⱦf#,YXjOEȖʜu!v ' g8(4w.  ,#aڑliha.\%),6_hw 6V3%5-,6urpzP4lɯQ'lR[x-6Q.P]ĂĚר6<^#J-fS mYXw\&+K1HOQig%F`0pyDk}r@|GjFزz>\:=ȠE%,N?~sj w.|꒙C>e[kwiwd .\JUY&cQѹr24w.ɼ=Ș&vV'W  ;DN-2$t|ډ`GꁦR8Lxs &[59;#ٮL,bAr_ <*8QF ;Q./Ԡ5NyiD`;dvSQ /1B<]C&޹T]sSBcsU>qIsU4w.rvTT.QqRgX/ Ӗ yQ.A}Zhfa)۝K"ٯiT'!>ѦhY0MpvLqԨ 6**=XoGR\C43%#)֨A-l9s (۩k+ԨOSV^vt>8l4ow.D\kIu<֨hFpƉdb1%#s)\|aUɂ5ww.e*$tlT''Y=O`cA%Ӄ)ܨ1Åfrj(@T%;~D;D$sjTW;)DُBhbݝK0٬SVQW;c;P%̓ 70c?>Kl,(\޹ sapTUgQdow|jN\mgQI4W95w.U<'2̭<N9;Z(tTUrMMoHF;ƆMUr[aGU' گ奓L,&߹S閂 VQ:_pQ~49\*%aE8z1jf;9x][ˋ -j\zZSQՙϔ&hl,(߹$tzXAGU/Oy:sL}L˕T>nU}᷋-iރX8 m(s^Ξ}_a[&|߹MjG]cQ ZKusioa$sz0=U}"14t`á\z_Tdb-= Rrw7Mm9sIh"@㎪>JdC/<@Y^1ԣ2}lkg2 x.lTfOaGM"xO6DXHMrwиB[ 6>\ʆߑwOorJ^. fKGB|-9< w.d*Gأyj^ "K]z JVzVw`"+d*&WQC~l ƂK@ٮBŧ㎱GME.ºE@ 5n>mFa`c\*ԛU\='G<Ec84䓅LxsI"Z W\jl%ETBdgz> n?X w.D\1L WQg  f.lys (UN*g=j:$7ŵ7R2,XP[qłYbG&%W;O&߹mر*>wG7%( k 2!ْN0|߹$qz4!Í$ZЅXf`%hS=9lTIiI^>ٯW8sIP"0g 6[R]kA:L|L6kPtr䄫]Z5w l,(\߹$yD#nfdaO8s TGOdyqd>(RX;0Ҋ+ !D_V+џM"Wx(+&6Qf*9in"м޹$y,}h#dԅA$XPs.pp-^- 6޹$ԓÃJ 8:)[~: w.d?#I}EkKW,)ڨ뼃mj4׶nqsIP"c 6 Jl6ń;`YqٮnTE8jHsvHjjqul$ gw.ɼ=ȘA~yUMDƬGGX ~m֨;@U#HV3S3dFe].tPd uHFCKV+LHstH4 9$FClhvn ϲӺJf:ٗ>jhtPy[F,A}h#L "*}ҳl0•K2P9z7JC+P \FS+5aYBL,,dsIb`" =q4bM4?w.DsN^3 U]⥡ݮl,(ݹ$x45 W`#@ѝK@ѰRYbѰ'!T< :Ϭl,(|ݹ$t5 raszq陇E |4Ad=C Q0Υ2W&> @%Tw _w. v݇k}4tQ26=k2>iAݝK@O.NC}k]6.\:<Pٶ\GC4h7EӓF  U.'*Sؕ2j7rehb$yh򵂏>)h:.XLs &ը*4!hO`D`;dYx]L=7tS15|R 2XPs Ƞ">)h8,zlsI(V9E8c jlMf 6<߹$tzxAETp౜:6ƂaJ@EENCk^ (L|L%LGSl)TZdcAm "#Nz f>D}EGST 4 D`;`vyࣩ{K0s !\:YLGS'=URGkepB;@Y7fGSKIPbb2_41=MpKmha KчP"AFS.Z d! K"6n4 o!\yKfiZ3Lt=D`;d6&x#1Yz͵h5w.=]˘*a#Sd*aRw, w.IV͋CHTHck>[bw~ &2}pO?L>XPxsIhC`3tC'ha,:4EU X.m>bw%l1Huvt7՛|wAqDj bAQxseij#߹$qz(!E kAL 4 ySm\*t5 l"zËj5byK0.K}8:ؕ2@ӛ&߹$0Ȑ2 Vȑ γr4|b>YXB~aT1D>—Ec'm:g2p}DpɣgAOaUձp}E{$sPQ+O9=G2|.cz#zuW2S8DCA`"G=^G9zu3%X-JGɨz{3jOeb5^\9Wd GB @ʹjdV%BPÎyj*ppxQE`By(kj""RB`3uE Ѧ~qpDx\rU`ƬVߜF ڏV. )rKs[!q,[ gw.d&G:2lɰrp,6vk.DsuDkS2Ug$[X Ww. Rd)t$Pytm &<ݹ]!H(^?d59馹85Ow.E8bEIȡ#*;ZX^\x{P Bԑo娭ӭZA?vr*cG QG ]31\M:L[gBM/; [b/F ;d9M9fZBۢز5/w. 3d_QGyr.4RC(ܹ$ +#LE\-?-g|6%QEƼ3ظ4,<餷-e|6Cll^[_y.zw{vxzX.$ -CM ۑICe&%z*tO}m9̘yzA~T< uzGq/Cj,I_MՑ6(ނf6k(9/MSeT%V^{$ίTeXniH/N&  srǛn=tl-Ew_7=З=ɅSOofw>s.cfm?/OQnZ50V\OCZ$[3QN8EDjRkaYqB0[<*^4,q7Y_߿Ln띰(N`AwAeEW1}L)wڡ4rJG~V7=-~qit j.a}[v#D?XQxjXz~92|*s2:ޔjtTvz|pΪCgVSZn;!q6gmӸ@:l V䗫Ima}XK¡*o'$O6A4,adUk]1E`K1M^~G߽7ʞNf]#^x>PpQ 2|y4vj%:EN2YntoɠJk3[;gϞ%n CWb ѡׅAXUޒ9%ZBCw /KS**5XPD|#@p7x%kK@eQ# Ki*I8֭PeX6) &6Lb~+.Fh[s^98}%˥fڮǭʊC]ZW+hKe&p\)K Mܖu)2'V^lEJw.Uw19Ud#rzB LYp[# pb%|@2xHo>Y@Z.lz{.IOWrfR6|ObH6\^=؅^2zςrrBl5W 7yLV@HYMԩ~q/ \ Anco$t)τ~἖BM݅pӚm|E]۲~Ѭx쵟+:0XXPY@Ɓ.K&`={/\vg$ F]òh%Cd`9c_32FBYp/J/l#%YUDY;it9ci:l0Dkd!{Ch1)Zsp>j;xCWWL}k܅ʢ7366sIhӮ[*~;1n ћ.}iCR\&x4HA4FUaםlqd 13%#A@eF8}}6%"aL6f̨9[KrFFڶi.x]X'%"Ϙ'.Xw {$kHtu]X^Y RVccԕjl-5 ݖ%KNoXm\js +2dP*LBb4@:yoVp1LSL"nSrhh9۩j`r%lv!F}pרzҡm&Bcl4h(0M5=]F=Ls ,( 'C9T̬iʜLVbk3DZ|j,Z|Wura~&eiz/e⩏e5ch|@Cd1!,FO]nA+WJ^dCy1%DLKyf)콯-֢qj.\JFĖ璜g6Y`o}Fe]krVQYmm&1 Dcd9ؘeSM )/0öiۦ$',8XkֹFL667s AKrd3/;P2pþQ2 SWz Yvm6VKcKm .]oiuKH6vMs (`ʊCb75Z,JԪ&[$dC/=6T]bWMl d; g.]4oszlӺ^Hl֨9h&D 6OX(_Lm̦mPojl$OX(_ۙL%\=YT奬:Mgmp%55%Z# MBB&ϤQQV3#R& kְiKe9JlZ壺i\U:5XĞi.^ENwo,c fjng? hS#6핳7M%h,YfK䘧&rQ䮒 ιl- ~Ert-fptQ%llfb46~qfRCRKFi4T87Wd!1,q"wxn#4nV(ЖfKje[6)TiK[M$=i.lz8$Tdjڤra4) ,Ms ,!I'P$xo9m%+%am E2d] WF%nle)eK4EB$CU.A<{HX{$s K[ 7JGP|p)y\*+U 29eXz:/]3̪{u!]d*wL4 ; \jC h_Dy騦GRoK\~4XM\*at6S߫Q|݅-]>3+ \tZ \%*!/ȜyT0]%[ E9Oa,A\5NTּ|W *zLe!mO3 "BO{حn*J$LtC%+W 16Kc*쨻u˰_K4G*tTޓo+6vLs ,ft$)OLJo+0OG_&< phKui۪k䮒)InpT0Ve4ITc(iPD O*Y&͋ &BNK4\~Zz2Τv5`4h ƪu^(ʁI٤˜tgKfx<-Lcxƒ)1mf" m4@ls^Y2R&fk ,_P1m,X>ؚ`c5ۦDs.Iråfӄ*6Y}i.Iɡljv@;}kɔ(ռXĦi.C1 UUѪ}&MfHDw@n#F̱@S׶nj QAxڤ}D5%r5',(JUlP,@ \:&D*N%EzswIEavᦵIpC~wvaU;lhZcDkӻ[@)hZ&w \Z=AAea!^GgڨL.c,*,Ad!^ՠ ܣ*PylXp]YTn-dK[! A&h!Q.WL,$6NsH_j9]/>z.@Mۛ$LeHY)n,AIz4[F(|CKKrE5Ձ8%Z# $gi'& =]D%v0qK0eQ QƔe$4Di;G \:=C 9 4*HӶvIg#Y*ٕ]RG.Ppec5[Ds)H0:\P&vNsIlH(-kwni K`RHefET8`E%v&7-jAhcYdȎ녛 g 둁-\C#o M.2g`"ѶLs 'ʘXtF~&6aL0l (a]$zD[d5PFQ%,AYYEEPlN<ϰ͢FhmAXyjxR˓\J ZҳT=epWr97# klbO3D6&2H "T4fpWj^s;-{VOdve/tj iԖ&Va4h, ̪W.ׅ)sɑSfɠ'\nf2,- )!RK4[FºaO nx.(,U$Q䌮zlct@&, 9+e{SޝA]Uwl4h`.( GHOTsD WKA(lȈ'5ADI`b5SV0H%Ie0]FlpdtO0lb1-xU#.]Xvi.5&=TPE1%;+-' a4@j!UnQi0DP-ʹ}\iDBʘj.S-vtN 6M]M Y5NlL=ΠGZyځť傉l2Bz֤۴Rj;B}BQ֣/bM-4ZoFry',@;Hw 6VsmK4 }՘H^zk\Lyr ,(ʘj!|u߭JmhuKB'.R lH-XM6m;iWB!uUy_QT۶i.YQ !Cfr!%(&I>X݇]\ BSk .(jQ85b,@`ک2zF#q l.[L5 }%[XK6BSl4h*mNjP|qjx1DԆRVgG5G.'BmRNM.,UorSR0p\=+ߖ"2)&Vx'{W\6x8 BC9.1#uiB$ͱ\9*qy _$dk>B$Y}a4 ^]lmfV#%W<`b*OOx*{xX`c%=ݙ vLJުZ<}Dh- D&Q ǮʢD&SH01!/.f^XU7p,H١,<ص֮徒DAkv.aɂ`xjvq)Ԯ$^}p0Zb{DcdAPƔ%$1E *105ǰcK ŬLFyQtC)ԋzYD% Z~5)I]jR:lX;6-} 2C$ hZb<~AF)J6D jtʻC[! C{G']GXVB72sZGY;Zo~/H_V[B C\UVm3PH`|6| G= oVU~[|˸~۷^wBM:oŮ'.](!IH$ Knf\$hiϐS 9@VG%Q Y-!yiij(ZAd3TYMg~_3#("GD_֮ߛ*:k}!c{`}T!qɕ}THF|/mJA\heD:\vo$e D@~T1K0+M%$YbT(TuȵYm,2q!cX"<5!dUU\\"܈=_%w|sbyzUs!zuܪxũyJ^KMgO].NQNFXJ*TOR`DqXT3eB?<~TyJ۽vԧޭ :Y)!kfBޯ\g5^''՘"#;Սy*%˜ALS3j:l'ej|_\K)E"D7 UHU\F {,k,sL|QAzó(?4<*XD tXgQ("4!H@Qxґe‘&<v(k!c6 Y&(!yF"n83?/ܮ\̽پi,|-L-M]u>*$tt h,' B7d6߾(VS\y33Hook}Qog}9p jWϊ8>p6Sre`nr~R MLlÔZQ'|_Akfژ1ٚl߀*'^ntwGњLQˤؽɄ#~y J 葳Q\&3 *]oy7xVәD`b1m+'pa74`R2ry Iš3Γ*0#b}*K1j:VbynК(֒ەU2[3>A?jd -2I`븐Ua!kc2aJnV6)I䣪Jfjw>5$Pves*&O}j4Pm~ڔX"~G8IF<4J< g6LTb1c5I$#ûLuȕJ2ސ\D:<+IG-0:-PY OZ"hQYYOB?/tX.&Z6GxYGh-YutA#! .,{<8{%$0ǟA^G2GFu܏2,u_o*&92Т&$2,mxӡoE4?%~ @OhWzQD#3 P6e㹆\g=IOA Q"3m,%sr[IJt @-kN}V.{ų~K2ق"Ԃs8C?^ 3(#7hhsz=3ZwOJ<̷_ρU6l0*|̐@ZQ9bIbV?jI aLbbtYAfT_Cjk&4Wu-iԭJ:S:6lwfucPI3jI&9 Vӡ6gW9js-$cj?O+g@B/s:M}v\o*3?V0̀C'UICs )$V%[8S$n)uHVO̓wU uoDYdA6phr#sdL{K"t-(Kt/YKB%`hkT Z84P] Ă{.ghXܘ[`4uģDŸK"p17,#uH7% .K'xVPsAf5ٿak.\@VNZ+#c<ڹ$rtS0rϷCuxVLs1+g:Aڹ$t1 Z{5Y -֓P[mv:-.Oz+U&ڹs,jp%qܭP>SS v. \ Ojg5NVdE#*DڳHn~} w] kWS\Gab0K?~*zI^fCKIKiھjdžmz.J|xBq__(G?]9Kyz>ӾOCcοro_9U4㏵9)E_V x}VOmM{^z_t_?5"*_nb־kzrvYm{mwy]78Tb}y*@}ϼJ__µY.Wip?wM_} ֬'s_l|נל=mI9@ܰצݥzɝBCy_mPPqf7#ERriX^g޵?i<~%'dv!wɈZ4vQ]_Ӿsꈖn)k\\A?-TT$7'Udzu Z7yr^E7?L~SҟotO:`R~섈kMh'?ػOzwV=wo^g{GT*x/0zͯK# -)VeVCU_360q[Ugj}.Ti3qw_y\Tu$vKL])u Omzի>=Q'%J̯ޥ_w5WcVc_dncc94MҔ )a_w5|IWV/( AfS!X^uA^B{+؇!DV./cu|]>۳ة!bҰ.btѐh}4gQ=rrյޛ)bIR._ Z楝'%|Y0bR|~='ĕ\ڥ¼c"/~Y E~nSwIhMU !M>n/VMec]miM[Z5кfnhދzM{ rx@r8r5 {)vk6bwHG1CG|N7OZ>J0IFґiKm>r%ݡv$*qþ~-getY#"bqV5;2̪v5 Stq[uL"'sNM~^_nUl|nyϣVtؓ;<$v; NY2ocbrh3o4s-~.E[2SƸ|LJvqg\2s>%䣸9g+Ҧ٤: 2|Mv"YmVl؃MP%ɀ5,]%e97~1}*'o>YDk2t| ^&_5wY:/G^23V[l֮fߢ+Q?u߽UoMVcxֽ~k$.ة«#qA¯nxȳOn;ALH~q;"_OD&.D~۹x:Uλf8xT/D~%BPRLcFd7=#_Yl RaOV2KFꅈԯDdhkԧbdϜ36ƬLQJW4P iw(VduXo7Ņw6Pd1gfJ]bW3xDJ[Y&J"6ZE7Wrnq||o qyYl;BoiB¢;Y VkJ ch u 2 JٮӻoI+4E|+﹗{zvJ-u?`w)lA5ÖP)4ۡ$ٜ~/k=}q6 {ӝ{ȯfiq -QlԽz6MpQei`Cڒqо>6ː8<v xȮm=Cy6xnE]} 쎽Ny90\A7A~6Qnf3]gXwlK,:[ĤvYV\NK}Bws?^á$OP`eM*(zoCݚCY"Ytm/7$Zʼn؋jj }*M83R19d|sª, Zl{~\Pn:U>{^_ By~W_ #c}#mF6uuQ+aS~m7ƮcX5^r}v<uEߏ'6?"/Wn7l n A$-p Zy[F<pŏfVxǏ|~_߼VyV=$#ϓԇCo֥ږɯCH0L9'U=cGsB^)z[DC̸6Z+kJKB<~a@!5nGWN.)EY=5&jE]|cY ղ]/x-3ÂzZ׍ Xw[˟pACClrh5 Ye߾E~dYWCtluc^M?Ƈ7,`ppFw߰aw\@'qvׯ/WJ1 d۲p6 1mb>䰜x z~*qlg`_g[@ &|4oR5éCvADŚvϹ>zy6x~[~3 5& ϫb5ooG~<&ZI}44A,D̗?tFhn3z[$vfG*FgC.e{Ftiwy~,v@6B] ċ+$돱U T\C/-b>Z SKƛ]t(C͖N{zO8|-^wh[upھ.`[~5߮>N7iKV35&Ji磷y|/+}NnDv XPQ686^C(/Nq&@v0N%kA,]OUD۪g\Ɋa2S)\uȲPC;ܴ>6m;>D9?d|f,0XU*fcR[Gi݋'7O(xEo2q6 ?X#k,9c Yx '5UZ*Or y}&~l[ upQ`i5~^ ټs* EqE^[\^Vb4߽*[mf__'-md_c*F7<_vBMyΉh{~HzEwt!Z G~VrI.){VwKT{ZD. g# m\rמM'WU*0xkr|Bh%pm+R4C.2b ݾn3nnra%pm):wVut PqR9S.uFwjtȔ!%AZ^@F6rI,!S]VsSxat^PbjKprsL\1u&r_F#k 2It7BMAX;SeP`5"Ib.kf7ZHE\ <8{l@pJNC0מKQ8QMn Eq['ZY\D_\4]i j h%p(].֟b[ɇ22o4ג2'O0v-?$Bi}\+e C̝>=S8fKrOdܚ2B)Ni<=Hڑ\˽[8XqX̔9 x I6Vl [ϔI] CQ[8v*ډ[#>!i\ CYESv*NL'u[C [ cy Ȣv*Iq^8=^zx&h%pR.yj9k%wX/74*TzS+~?rGIΨaۄ8D4b9Tn txs : x09W MmsIj8rKԬT |/L)֫5i!Kpqpzt%,ռ`'"8FU9_#j\V}8Kg/,/'P%7r2tڂCj&1$(Ter؍,*MR fְ 0]'Z&|$ pa-SyA:Ɓdd S'ZY\sɣe8i6z'MH\qrleOJZφPeSz![`zN2s jC^Sz8zkAڂŵctYƏŅ3>}p6,Bs ,&^|NC8I65 jqYl,&\$sNh8>{,0L3C=l9s scPuLĉOhH=nrp_ֲַ:TFQfk%5*|t u FrI*':^WΉKEp0q݊sWJҸG-O0 ^ysI@Qn|T4o !,"'Z \\;jRC4;VUKpխ$߸81d hvkbXBEx{5G|.mvg!uyC#GCۣݱK`x}%.Bc='QݒP"Zۑ)v6`95G|.X 7zCO-%V4V\;{ZcI9kG"FD>8凜 qjhK`Od$vcemvYb=VW YO r`Lu]y(T%8ySSY,%Vf{Ņ;>IҤsPĆAe3:YbEU%jj830$Ycr E# kX 8/ +wd$ !KP$5kڧ)( q,{=V$wNYWz^!:$VdrDE+{K>LR_p/8e!eJK>pDQϼ`Cb=*GT4_(u1BS'X,xegFT%r쨏 `u,n%i gj>\ǍWɣZؕ# |.U'(aʏaXd+kN\ۭ{ɐRL)ּ "+kN\2um=t7؟hh Հo>XPsI9 G h^RH_>Z^ g =t;q+28Ņ_>ઃGq8: ^9 ׏4WM˚f!!)Z Ps\u1%&o\X,.$[CYs\բB"S6U][ \i'dLN[`LBE\8=J4梈Ab c"Qպ Y 4|.AUNؠ,p? E-xVrIns*՚['!VN':E#-XHZBZ0eYf/Xb:#k\ 9j^.zBD;4?Jk>V&/YʁA5ne glFx5`g>NrqP5 3& @{m9s zvR8LN0RKR~c>duͱ1K`ձ#LԢDNh$`M d6 y2L+̵az LsXup8z0r6;D[糕ť@R*;GߴU+J;x[Oa#P!WJPկ#߀wt)tL/6tNJ% y&/ 5-eg,Ï5)P(tK[. Z;95q39%R*|6I%|SJRS"@bo R['6֚fR>Z`[o> THݤTuħ5HEgjXB٘7XT ϤnS;ݬK#[[`rt2a4I%2ɰ/:I)>P pHE+K)X;!UuͤlF\jܞ1XTʲTurDi4ǒBL!FH6!JR$%Vp[U@i9g#UC4@g7͌7bZ;,.W;jh|Ç?br j}rD#;44r/KuŴvZ7_)ZY/t2QSJNdaWk9e'I;#ihLdphqnJ†(PWP7CKHڶK^ ˷<,KHRB9w DRk(b:gİZJڱY \ HĒf=TJj\4]rw!6Dx F# %T^?=qwcjm٭97+KT;QUoeDV~UƂ~Lf/_Lb1.NcPy XHULK(>xj:, |բp@E+j\[l3PQ0^ X5@ada%z輱|çy>.S%בop0<0|il!Rzfk?>qsXb K[I٧e>GS0%DxRm:؂B:XSV׼$wZqɾ nG>iaX2G^heq%ANLZDزXJ l^>\; TT4HVQ`r5| 94;qZM[:mF\۬{2n6O=O My X{s%r=(a;(iz2E^2'oF$[{r ۭRu[Q9ŅC>=ͫ#6=SbF. W^n߬9sIevOx~k[W$="1YTsOHuHî}Y0~ ^jJG>SG(#Bʣbi]HYXp4RKbxPoVaVӫ=Mf7 \iE nd)ڼu1Yk-l%2cёAri du95w|.-H983YNY[#E F\:,dՇ2Yp5H;>VT(uxY(,ը0pX謜RD)zb0 ">,>a%@Kp՟"Kx 1y\oKrq4 c;">Hﴓe$PKPթUGFE t,.$wX'Ԅ Qt"T o72?#w.Oli=sK^RX uZ"E⾬sD+ W|.{k)T}jX[*7=ԩXsoF|l>.sxK"cį:YSv# _|.ImpdT0qK!,K-vF'>cGI}?L_) /c^=~bYmsI*2bbY|y#RyȢJPR9+g3m:4֣F+k~\٣TT,Wd˩Z=&S4T 9|sWΦ>&e^LRəs *!i.W$yX5ޑsI,!A2W ؔ>:d߇Y#UNV/ Wz{rYTybE Ģzq - ?|.tF0RwV.īH8u]8e5'|. %’y9{&R:+]hE𶑭ysEX|*z`]{Y=l͔,.mT5kX7Xg#kN\KHeeY#ddQ%n5\BT@mIum(Pd"Uyc<y5f$0 K`bJreXKxzA+YES\RΪU0 E Ȥ"ys Sh|"U4.F 7|.I%Rw竤^Z*oո+H'>:T0W3]Dž$VsL#j~\! +w`Do`̊ m,*$ S7z{)RUqobĬH@q95?|.uJRwNF y"C*ZY\8sI.)h@i^"•OZ!5XB&^=nx)\xh$`KbWV>Lfl+b:TK`|1'@i[gAFF2Tl`a\|.^8u|{@4x䋹|rNɈ_`Νh%pKrAƭ1mkXGᐊF\KH吪P_z&A@ 6T? ΩcH2:^) LsXB&^@|<ֿ^Z܉F~\ %9}9R+Ch=s C:}FTGbHFn\JHUrN=K)L=0l$PKPտܔUF D~eq6%h|Rzq+SݕJ5dc1%Ěi#Uyl%p Kpտ*O[j}1)+k+XڿҘ`HAz1+ o=|MH@>sIqq4sW vZ#letԉV$W#43%=WaD8E>j|IU=^9V2hEbᭋKm9sI΁Pu V[+V$ިS4Ƞ_jT$OSOR/b=3.+i8@6pU[Ū}(Qc·wQ)?<'JE|Ǘ fzy?D~揟<~<}]j-wzJy6m;ț!g^ ""U\>qrgu jd2 )_~dWǕo~нLԂgNܜ_+ۺlCPObCctm7>S>^Swf4e_]ԌEa=)+"7W6$^C FDHj!_y~?SpdCQȝ# 4.YJe+6}e SXt(yp|]YJ'2NW&{%jxH>Oҳkxw7%uܤ [P#6usqk+p뙛ae&WUj 7: cd8o<#y3ұ!<~?;E2v!7rF7 'cX- ~ ')=tw+w>*άv<,Hx^q\G'rZya?\%HGYW7X<$+VMhԏ//}/X U&/# hʷʏ+t K峎 (.x3[3~<.=ﺆ=AjSs\Ĩ(ܮƥMNf2ơn <Ѳf)%5ܿmUp=WMv/zCNŢeprYZvSIv rvEme_kd'22}QBd ^ZL8#]K|8y{euޞ ]z[;`\,^Y̱h.Va)O5sywڽOM]7

    &>78ϤcfƏ}T`|,nk}I80o"p_k+~W>m㳍87RuEkz[͑; 5ſ}s=fi),\.qpD].5NE6}yok#JZ].e:uL/Z6%SzNf\JHR&ł*RڻzWAKZ HZ].Ie:51L- %Y,/4&_4cKR_Sn%wey& U".k[wmi&4g%"%נIaK@iH&ST-KK|jύG\fdabKbݕR)b*EU⃤;3 WG V׺6zZ(ȴȍdKr4d2$P&.{'T%kTqU 92)sw|yrE].R&8Dvё78!B&z X%l}ReVE&Y|VbrIm)S4 *`D;~"".uAeLAEFtWVעr nSB"boX /FbbA8[r5\9];Ty¢L%p2N@$.vm\ϖX QaP][lN9B|b20"ljC R,j#P2-3r]Z]BuJH^+يKkf c46t*ܷ߰v=Ibm>[bgpCR}PϾs.Bxs\VX&Zso.= "$hfL>Kn0K_IrԨ5^}fM 5lܲzZfG9i(E'UlRk(AL}P]Pō{|$ԤQyZ<Nu$`.V9TIӨg< ßONpXVTF %iD.Ξ>?%pFUQ2AEFqωKtz|¶cFl@C6xV=Ik,E' lb+SB89 hmC9KWs*K*uZDja{<DN+MjD"KRgtcU=ɢr5>[Q':(XxG*ҠaWmE`b%>[2g`А.a:E ŲD4bͨtФ)i̲rE AKb1>[rgdФ)ӔuS\߼.~e+.⤛h\u=MS28T#!eI8{ rΜ齈`+%Rt]hylL*RG{x^BXϖ\okmx ̳KE+P.g+jZ#89p>jFeUle\KQkAq9 _Kr>[ruҤ =Ҧc+يZW{c) :bߧ`gXϖ\vmSo,9ZCpr>[q y0t|>PiItp!N' gcG@K.[QXëPV tА^K:wD 3wqDU9{N#@֒oZ!$⢏E{If/ڙiP&_U*߳VUIzIRҶ?33Dr#8{ \,g+nHW:|,Eiz4վs\}ϖ\C\ij6} /BnQIb=[bglSNvzᡬy1|IOE' Z4b+ LIm`MZZ9@zXzVT5% lAoM.t!E%p-!6bOjژoN{>EjVFmȊ^:%p-3K Slthm +cQ?ʘbN*<#3\a2YKْ )6u؎cm̅l8yL-%pnbK̫2sL׬4ԫI{BEqj}~LO]$`Djq{e2q]z7/lUpTj~SZkNiL0pRp?uw'(^pq^ي;fAOUc;Vf{Up\~ϖT66 NZ3Z9H/ $`ѷWYgVcX֫&-1hNof#/@~E/UlUtS ʭ;Z;`ʵE/elݏ8.$ӎe-Lqs,.W )*ʸgi܆*4.%7FyܪuNEl1а:{̭2li+Cݾߜ,,%vuJSiL,!oS.z \g+n9gp֘_e܂$,.%KIʯ;f:~?4OlUtM/f&GzaY`S/ FlE+wg$t0؄da -PDC)tY/Ƃ;T ^ْ;NIJD*F/h=W=$Z w=G@bM>[QXx, *U܎#S2T˖TEv髠I=Y/d{o1)R6>|Q.=L)7/5lɝeYɩdsUiǯ+F{ТSr9 Tg+b;ȎCѷf,,% )ϑTƁ>'1˛zElUdd=;, Yq[yTt\֡90@d9][q1,wd>ui9!3D3>F>Ӧ@]9#SkFg59 H|eK*TAʊ3%;YXgKbkی"*"m1ÿ4ł|&JDS S48YT.g+*c+FWԾMyB~sXϖِ#: 1z03h@E/lť"̹Ie)_r9>[bgplƉ^%p7/lUpQ,0$+v@o$`<-!) !qCD,z|2>BSU:ߑK7NGb1>[BchB'T VVP$zM)\Vزe)jDDX^j|ئ,*jg}i4E' x%YCTCCoeN.g+XiS*"v_S|;\\Eb->[Ш !ͩ"S^ě/g/lUhm&VR0E`b)>[1YkP T%YUěq霟xI%p y{%|UV^KْZ̛"djG՟%::@F'l]EIpQا28~O"wulɜM)a]U[IzӀNueMp[U_BXϖٔuѕXT츭[p^ي,mD',^PR^2ܡkpXϖز)`+Ӌv@)j\8{{'!F.&j.e%l]ڶU!e͑4bL$߳R̭+oɩKbI^V{*4˜NWrJn4N ԛWʭDNÎ^ي;VcKU^IVZr9 XbΖX{;*<uK}[yZ#N%M\$޳%Rq]vV1.nI"r=[aϕ7eX Ԫ %|hџһ^Kيິwf0N^7/UhzQMz% K9; Lg+lYSWu5/Vsr1-3%<{Em|C,8x1߳)RSNvi#߼.߳%ץj9.*m /JӷO{**ҳ bKwu3^ْ{n3½\u] O$Pm*v^ .iuU)[^&+,.%7GHVШ]4{ ITʳ*xWN|4"|*"PW]V%y{=(7/elɝU KԮr يWn&Z/M}jr!>[rgtT+DW{z+G'3hTdSrk-hc395`Cu 'lui^P+ͪm)T}Kzr1>[qܩ/ׯ]VKUgb|. q֢(xH4u@p\V܊;ò)Ӫ})URR{F'lUp:h'he))-"ltXV؂MCWεK8YRITJiV/%SZ68Ib9>[Q!#4miu8jtE#X T`[ʱ*xRVnKB3: LgKcAV(0ŪUIL^%ltXϖ#eXp_ҝ!sKي{)`,SWR4fւbA>[Ap,GSo:,G9v "H͜gP1bN&ir|/EH)U/%cB7z \gK k !̫x;(Ԙd|2,b|ҠQxhX)|gFlɤCSOYUTY+KGb9>[AXwEKQѡue\ϖYpj;ӊN 3hmj|֕3En`ZUEq)lNrE>[rgtu*;;i֐m%pѽЖf3 2Ă|BmR)K<( Ӹ3!,.BxfVUHv_. WڔA_/6_URbK:xY\.gKV>[U,IFSXֹ9:r;n-s^ yhS9bU>[qq'k ,gnUśen^NkيΩҫ gV.x Jrٹ -3"]E rI .^%yX ]QPݛUoi)&y$`9[b N^U,3=}tKbU>[qܥu" A)zrU>[b0)`!<3*ޕBg IbQ>[a`<*ޕ/ = 1Rǂbm"gXT4,=L17lE-+qԊ1VQ\L4z%ps.[r+ N_A\Ok/y]5x2ѕ]éZSɰxXVܱmcU P{n4ޣŊ|І֡<_\{Z腍N ȎMC_E r2v`~l\V_%Y5$)r_:]ˊيv̴j^(&ZޙT_~ ͟ :T*lM^kي4#V4,be,'< f̧5XLgK挌+&+տ[ϡGb>[QJ"ᮞ,J]Nr>[.r0ڱP%NgRPerʡ4:S7\JfU7@9"\(>Kيи`"HY`4O:Th%p-i8̵Ii|QÿXPg+5ӧ) Yf|SpX~ϖ%EN|OY9 X,g+bJ 8aF-7/l+ ܲ,d9i܎TtXϖ>g_;3>%m3eCb 3)Ū5bv=L3t$'lE=W>)V/ɲ39؛TXVmcϠ$>Agj@.ْ̡"4si+&zgsвi_p9wwz{,H׹^?2mR#tojʮi?ۺX杲e;i+Dwھ0Eob'&|z#~;:~6Cӭ&)|yʊ/;gǠ,+ٳ{)=Uc/ q?P!wY?pֿzCсV3>|T;@j'<0 P輇|8DUǏK} r2_.wl5[é[Gz4:fZ{l[@E`, o÷;v\㑅 `V;ըQevsJGFGDRۉh'M2iܥQ% \yb$ش5%.\B02?N?pa0}IWmd^n.W.-i A6c4UC?XՒ[fP7;=Jbk-*Ggڳ]/~u[gwyy} cN#(O ǒU:Q軂չxdYG|Ł96\;X`0#uMv]j'c~5U"beݑs滗svRzwM/Pm{?|ID h6mء6ضe_yM67esZ[^{yg#\6yÓ%?>߳|x mʇ垝O#Qg lt+ҭ+<||1_s=׬?p$MqWƱ/#03}AzXIϪzMM2EL}{NT*/ɜN{d+ T0k=YBfȚ68;wA;rElp}Ww0t\e5o^BH$ɖ!}p] h҂qh T~-Q X}d' Dl=.u=S(Q/7Z;N},rI%?<MƮ5#Tzs2}Njq12t>"'+GG?r$ԝl^ 9#?'Xcv()z \dKE7đ ^u|,*Sw6rZl›9T[R\vn4]wKbDz񎖋N-cI}bWL l^]vnDSW@>Yl^yncl(D/!&$e˘|6b8An09zeQ #qǨ;wlzg("tKGNkחӤ Д-ķvCa7ܰ b|Űxh1\u [ǒKN;N} n' ᨜p*L#ăiXيpP9y0Y4}]|KX?{ \$ceKω:6-;zӶOk}Q0{ ϧhl0dL*O满/~sbbW'#F+\ өa|ۉ<6.t .=>W'=ibv~N^ْ3 ]*FSѰTTNFEQETm/ k(8Y1,[F4!^'UZZ.6; XeKO IUCl G^U!5f/)jĦ`}bԝ'gN4ܜ̻W0 1OT)d2G-7-ܼ-cJUz53zyPcA->2FSCPw+TڲFǦP@E[@]p/΍=Z+xSC$稉^ydT[=jC΅FI u2& N3nG(T:3@S̭V܊^9-վ O(С5%cҧMg$aԙ5(eL>ni n((XTb 8YGٺ Eܭo!FxE^l(5;M ͢\1rxp|c~a{Ўan ?CD'!dfx|bdLŰE֘[ЏWc,l!Z\8(܊ޘUBW]} ֹp bw3{$ppolxRԡN-o|Jw?5 }K`!e10G|bu& B'ո-¹{| ѵg7kljq1{ \lf+M:=;.UysQ.–Gk>1GM!]qU5xʅ'7'+"gˈ| b/az ѓy*Oum4 J<{K۱ަ sImt j7璯 2('8*b{XhȩFpCG=fY#vPz=#i{يqjc+nF$"pkCO~nx(8p3. ?; B"aH޷`Qgb5yb |ْJ,m 2R_ҟr6[6LCvM,ʅm1Ƶe޾iv>Q9řXv"6pH|7wjA.p6U?Ψ4EЍ>1W\`ݳ؆Ī akʟWky Aa8[y&©.:l* M1ɟGb8[AxӓmtS|9yY\ngKF;>_i*TI+MNuVD>%1גFIjb"lOE Qd cv~Xh mΖI\ab)p逫'Ib,[aڣ%+ީ!J7/|A=e/%{Ww!a 8[=xNVRׅ{bSۜ߼,.wxh$]PfE=kDž6,i%"\ ߧ@N6vĦva.ptqL)o7Uu"j4J \y오9 pG,+Kb8[r' 3!]AYB3(ۚ}(Y{33 :S*uiZt}Ǯccb vw-}p7nM7/3lOBr*SiW:WCG^U1E/l=;t.>*;4UpHK6Plf+( Nv;).Qc';tfכp}bSȕ%Re8NVLΖ1||bГbFl'E@b7[!$uh,bd7{Y\fKi~*?l(,(Md֚|s͖XYJk>XA:S%t3UUL>C,]2ŮT~-c9}bǓ=|g[BE Y9 Xf+*lAC vI$ͫTao K$AWRC;:d rg;O56 n_di%{K0 ,_(Xo%LߓˏI`bʒ-:ZvzD-mT=.,.w%gOm=Ld5?aDwNvpN:94KX&sJ-c9>XrSVj,eq pl+ťg}ؐ!z \lgK\z}l)KzŮ9GQ-0$Ib[,(ܶveH>1JSH=ThMD)],qeq ->#OzƮЛEﳁ9 Xlf+ŶS=>ki0L*OcW,͖[[t)$KSXДb^VL]  ! %:KwRPCߜ&v%4l]L>mi8=MU26҃,6k' RXD~7a$pzrCjzoBw܋S'blײ@雗weP>72J'8q;)-JƐ+'PlgKHs&;(Ī$IX~>2 bep|bX2vD$c\æB,k1gx|bl%D!Zo^{ْ݆JѼXGSjjNm2=%n\RP1Ж ek(e/zDWqSfrB)eV)"@!"gˈ|6dZ+RAHzeTS}V܁>Ԇ.R#bn.B'6tY04oIЦPlh}`{-14}l(-Р>=X '8 Tlf+jEץX}~b%(ISs@g' lpv)mY&#uyh?lc?'-O&9mYj&=&¤y`E,fھ+7Iŵ6&L7}s͖XJ$p6IEʭ0 .eqv+*}Ksosh("~_6..VlNB@͖>qJ'&VKJTq7/lyQ@mzjY*Y:af_nfKŢYNfGWi!6܊9TpTiۿ%ZIC. G/-c*zwq!Y1\eq-T.0.LuG+*M.#0=sXR ʢQw="K>0WCCƚԒk/RdĭlSCc]P%ij zST]ܻ@2YB;OQ + G$c!6z \lf+nGXţB!hnI*M7'NO]"]N PnpyY1q7[`ٻeQeHEUU*$`99.)@v%zĨ!h i ^KCZJ;Tгr- Z+tyLEUjATաJ*KD)$ lOFTu80_1T 'V^ãKĞ)UO,;U$ MbvTqЕ'.K1]%?峂60 uG3{2$1"l+aoʜzjw'lII}bs^VLU<^%^ي[W0p]^խ\о!EF/VFp*& ^Snh[L^w'+$gː|Bb&5F[eAo.T-7/l ˄s+n(⺔_tQea>6E⩽F7mlI˄j^cC{bR_K3AYZڥ ܇aJzlhCLs]o^9OKTj}umZUDKӢlԤ\ ʿg /}uIcr8[an(ĮUb"9w*KO:z \fKϋRk׆NǾc">=\АWG8TXVכe8>ay.`}b5$V q 1ɊE%pc #uodź6Ĥֱ$`M-5ZW>_Qu-ֹ4E:vޜ;V7W׆؂)4-C%pHd! BS>: XgKOX&̰Wy%,յ#&I7/+j`t>XL+GuA;~DP@7J@`Q00;#uubOنۦNpt2oTQ;ze] }-3sIr`7[sHk2)0ԌzH2zY\fK(}JBfŬ [rrfSF/mle6j/cU6:$Ǭ!]:KPE/8gr NYbv ݼWiG'V*-]y iThWYu -#j%uTavmi6c($`-HZBM1;x;%Г~xy'4Og1V| -#0-*Uڭ,[ecGOV|3 hԍ^pي;Vu0r+ZII wKb#8[V8;5`@/sW̎K)Id?i}tegGWb|tekB>p Z A͸z]}1{ЕWJKb#8[r9N'+NŽ+ [=2g4N >GiȎ{1{In^;&א$Tݮa_wU.sjN!gˀ K%h3Im D@r;l`oEitXdVضJˢS`]/W6tk2i%F15VFYti7Im'AKf*Oe-Kav0IHG!"lgˈ`|f{hInY1ՊfTqpJr >_Qq}*^["aeqOLbAq\7y Ч>,@16v:ubN;qS; Qa8[F5Y(\m jow3KQTr8[aYxq(] mcD_b[r7)nssVS#,F@/aC/_гMq5ȆIUBWbc̽WU&Ąl~Ja{ekCobk,R\"s;8[;z7FTW]Xj Wg?MlIJ6|[o!s2BމNY@u53`=ʩ3OMI~T"dj"?fȵҁΡnu|jʇN a\B+0MZ2&bYrP~jLJN$0j)JRJBJW-yoM?Je ip-mДY/cfΊjoMI~˜yG"N_̂z'o{oʇ ȗ1_t|h?e 5rlƊ,>QwU?~KrY:[țzk{c'Q.SejTN͠ nwnj w Hͺw~T|y30cS>:tB,o~MQ(M7Cc'Q.|;y;qx̂,AϷ>D/42\.)iUH(7C['Q3.Q27fl׫#ub>a~ީgi !<5qzkLJN죲[d*nVq>qrRw~V_ P}IR%鿦(Y~kLJN[|qfBxJЭ)+PhTZiHV+ޒY*-QE̍o yo~4g)ִ}M1r>K% gXT{C:c¶WcC65[S>4w2? <*jȇN> sԷ $vcjsEy%-o{3'A+ &zCF|,G ☈}h{#'Aphxv#DVsBĵcAkA͸;Y'i BQz({k[K'AW+{D*zݣvܽ,W({(}u8uǍ>5㽥{>W~ M؏T900~k`f"Tn03q׉{+9TuSj)zPE}RA9Be_S>Cc-ͨ "SduGDvT'Ѩ*N&j?#UON7T.OftKYͭ&  3?nxoON7ȟQЎL'jPil?}^1(~.ց3ZޚI}FI/w/t-c5kS_Qc2أ6R8I)קvtB"DPN46dAn%걷;J%$_t{2O], Jxo>( EȤZ24b1ԅnef;os4 heGA+:קf5GpA!pe346tB$znLN-ǧv7ubDzn`}9n$#$sz1~9PbBSC'AHt`3C6[L1DtY ފ@ss#8:f#ՈL“ DFz-RAh"_BdhșzT<}\qoO47C*ჷftb?U؆_OxoO17I}Pq6~}qQԹv{qi{k{['AFaT)g:vOxo>ȬD?B_@NId%C-8*T6Pg }XA@=~Ud[;ޛ*GXms2K`>"ع~lFC`o3"(7Sq~(QYvƇvT'ԋjvxmU 5tRdJ<4P;;4P[~gzG6}D=(.$QTcQSS'AJ$~Al)}A@-FOQOxo>}(|a)cgC&6ub>F-}Rvܱ~Ɔw>r(Q4~gUsVad9n{:3>2yt1[؊_03n`w]lv7U' sܨ(֎N胾('('qԊr[Muԉ}Q塽my ub4(c$(n`ym?t#'*7佭Bq8vVa"~-_>(E(^xhKxXU?㽩!-(1^o Icp84T+oǧv7U؏"737<%Pxk{C'AgFZlj>,(3tO yo+Z2[cM { 1%ac{ԐNXRR񤴽~j{SE}+IFݩw' V!TV]< lOxkOB߷vܡuX@ g؈!zlnxFv7U')Ӊ{ro{h"a(n,7t# OI/SC:=?ezgz^K`>Qf_!{SE}*ǟ!=;{k[C'f :oLog|y B>˿AN j O 㤦U?㽩P,F3!a IJGKiv;o`YPE`IԐ |DL&K9nԊ|(;,cĖX :cgxTQ/Ȃ#Qw|vܜCeYrAkAhW{+ s  {6.bT#x{E3֕66%`߂KuO1|,v.d^{)X5佭Pa=R&bS3`Ր ^- {S]$SX]7_x@r}j{S'z*zܡjƄO5o{A7[ T5 }ІVNCToM׍v,ljOeoǪhyO yo>T)hןbkcqæbOo`)gmzIݱ1NCkU7FmxLQ?㽩PE<~zם:zwShr:eo zOUxoO*>A@-Сw 2\}ԎNC؃ncaleVajeUl/oǺqȉ'SC*j7.*kԈvNCI˄Ȯz֙& eB⭝d>ֲ1ݣC zI}7!ɟQ ^-ׁgSC{Hاj7 ݰ32\S;ޛ:ՠoP<WY[fLjjOŠ y 3-Oo I;&r4'#%?t6 s3Պ@|ϼyo1nZ>ŝ]C]L-}VSTgKjJAx9uvLlj!̄XdzccK`-[bCd$U厍 ya-,®7>MT,gKj$j;xo\bzޡ,v/Xcϖ:oe.cc{d Z[XC+)^ۡ@=/X]֨*\|"QHMӲh 0WVj{C'l ǺlrjC|_~+Mق!ݼ:C Pg')U~-(v z$6rv.gKf`JoC3:XYϨ\*S-Tɂ)0|^%֎N,ֳ6R(vh7佭l ;2ra=v ~wrIz2\} УߠwɅl  ۧ$?⭙N &yy\ճ%2&œӵ2u]\RϖJcs1-X,gc7T;1ctzĆ+]E%l`q=<>5佭5loZoQzǍ#\SϖZzgB-̋2"۔ih[3z),{F^{#{̛L_قwvܩg澙T,gKjzt^S3[**Wӳ%uA; "}f2s`ѾWASP7DCb 8l(ϧõ ^JzFʟaOx̤ZOT>5\n\LϖߧO^?⭙lBcwO4$P:L=NMmulAP+zk)Q-TgK zLu5L;YTg{;:o+s!10%JFLԈvN&ҳ%ߨ{Sc;NfL=ˍyэق@թ#9-x.Aߛ**Wѳ5@x\rYc̥ԎN(Vѳٚˏ??}/X_ePIߡٿ_O_~{ UM_;㟷㟷W#}ϯo~oˏ~/ m{[P*٠[M -y5o?>n /W7Z|8JzEF^dygkm*N{vnwqe;.?>kF޿uԻlzV5_W6߾/O) 3~^}] ]9ګ{Ŵyw8]YI(zJokOwrFtIqۿU.^Wו #;H e^.LbU}dîm!um?_W崮,}^ngx_akDOUqUb5d+~Z [mF^beޥ_{(_\VX;xwP nNM_ aSڃA(ի2yS}բpZ*e/}j{]Ξ1;89ꗟG> ]=O]]C+.?`C;!_~YP&t}v~Q߿PlW^~LhScUï{s뺠TxcMZv8  $V yĈGXrP31r>P?alG] 4>ݫxҋ d|tɖ;>񭀾F7BH]/ueJP7x/ϻֳ̗&|ys55/ Q~khKzC9z_W}]G_uУ76_:փ9z͘./州z^@WKm33|Sﺶo㰺u&/s뒾?Xc~5/2(v˟Z gs-̭FgmnG-tk{RZ^ǪsYȫ=^;iZ;lq 8\Go<*-2,m)l!3:S\x| z x^<9^;w&5DOiZl͚p^8^8*sɰhgߋG:B;LU&̾ D$Z/=yZϴ7-.^<\GrdYK^L}&6f+7"Ww̙,d}$|$ #L?(> pE%!1{<νJY%8jF#>|$|<9PAP~%:}'QH8Ltssy3Cm-AhUm{J+Hж >U:gǑOܯ^ o@ۿGFyjHzo=JQʻZv ?(>/Lx{DHr|erEWFֳf!!# |N]c?˪ 9ƗOo[*oڮbO:mu`\1X]V,yu-Uf^G8=! ` h-7bɖŅMW>-x+CRDKM\f+ .Yn|V9{wFn6 S/{]&L/rQeו=#?5j_%+5no+#@?h0F3Y(UՅVI1#Kj3̟}{BilW}h6g >w׸;+ww?狜pe G^^)|庎8jFr6T͑w?@v!W? GLƧl _|Z[t3>/'XK|̗6W _wm/Qno?58|/az4qylFlVDlk6WOOc0&C^#Q5,c%*M<wbeoÜqszX|_*ZǤ2a~[ zΣzQ|T,K`fiÏ}]xZE?α\^fz>|sT>\kD9b?UpN'%? J-V Ouٗ„Wmy^cw[wqC0ǔ&Lr?c:^ }~Fo͓uNC7q8^fe|^g!u~vڥR'%P} =Az]/%=AWlד \"ʫ ~va(y ,~=}00f@|Z[*RDZ|a>oPoM6dgZ%cv|bWS1yțiHl,澐xR]WAi߇gg;\aZS<Y;2pҾO:{TX>zjç)zuu쭰P\oDpݓ |m]fowuj 7;ܦv0=[mHe >[VsΟ<4x-Wpai5_S}S;6@ю]+]]*rlxNB H`jgKtkHj1UWȽ~n=Իu=R ~+nEY;+VT D4HkSLlrSx Tt΁w|%.wÀ9JPCoJI|rh1}p]W^@r'[ߵ|[XY6 {xC@b%[!IK*CStI@6խ,XȖHnY.PiVЂ(E`-ܿɑd y-f`_ϩ]<,$e+$ E^%߲Ozجp>8V?4ln5~,"d%k*/qZ옜OI! ܙ$3浼&]~/|E~y.apI̖YԙIc&)ơc 6wAdb[B0HS~ª,ؽأ=$R%~T!7i\}`ke// s m٬U;'S&18Ddd\!ԫ$ldpX-U#xnS;)|>-_BeŁs&BipܢVD.=;+QC3@זbMHREΖH'}~'~y~/I]шצg`Q9nlcPԦ>hG-ihT~Y">Gĵ}uj|4t a";+eKf8(v!GؔR 9nZ6ukp(D{ew'v?һ'k3ɧY^UU^u_;sXi7O@BQDXhz:l]1Y:Fǒewu 18DV{cyg'Z!1[xשc,"KeK\>w^Svֆ}t}]nޫ{ ˣrkU_W*sx(nu$rp(9-s"LJA->͹vK"<,$e+$*0%&4P%qKKղUin)"&g3]~U#%nΏ/ύeKiyz'qmDkC[A ~4USU.pGM9C/ll<%m^Ÿ`y)[w~hڂXOϋυʷp""eKb.ܪg7,b Ղd q<([`o^wbSDKY[Lj;uG{M<ի6X1 mM;8['O<$dKd;p0S)Xґ3:6c l`kAYhDk5llIa,kxnǍ^E!p%[";+ah ed|;i`ڽ lzir%L^3pOoK`Ieo Co/±Xä1|Ÿw%Cv*KȎ B2d۱҈AgC_0ެ˗^}axa%e:l \l>QRۀ{4^{VX+ ؼj5;rฮ=$?vdYK`$-b4\NNk>- 7?E" VVxbFUg~XΖH[1B}p#)GUjBrE:["=+x]@؄j{ql|7?hXV4 @|ݸ ΛZ#yXfr\VtpO \BE ;:j6A[׆Lӱ]m1-mCO|a1:[**^m{YD>f\oޡ۩<,$)hȴxef|dQ4frtD,WSaKcf~&*t>@Q, Wp "FzfĄZtvmP}wߋ߾zI'8DEgdrV  ~$? z5c屲`8 zpNZ|`&u.9uװ  ن34/ZF廙^8RÑ<,$_.s[9ubZ0󁇟ْ@uHqmHVx潦 blidN0p\>_ 8HzXHDgK[63L,=ժ:tZX8 ol-躍B}4Ui%K{9)M+D'd0ɤ6̥X-4pďll#hغrɰ I-.X-}G׈Fo!ujM&8DCg+1ёFdقiS#^xtLXM:3<,$ס%c4vl^ece 9ܓt+BtB]/K mYZː[MMz>EBt$ڊ%i tEHLSG|I45IZe\_)ilu~t-D~-Ca!aքDuqSQ!"4  dLg#68x`ñ}hV栱1FF 0-4 ;*3u}7BEh©Q<,$''y/g( .-:fz2l8jD04ltBv?r46q$A|x!0*lU*HۻH짎1mW tg&jؾ*c)"=:Y-z6tBHAz>lѐ p< dr ]YiМ?)t\ kNTw9%x"@d 4[V|h9ɷRjf@,Mg+`ǩu.Q{.79;N<,kx Xp\Ζĝ1\^xr>Vy?U{NA! 68rx5;8C!f$zB4K w*(s*S598,MgK-tu%0ƫ"LF4rlhXY.D T'tڈѳask[iKlfy6|>4fUSZ=$OY@)Cz8tDTlCx*PZPUy%8XDLg+(:SGb9BۉY>lIхpZ[ ^OV/18XD.LgKD6.ΥwǩG#|;-N>AeK&8XDOD[1@Ѩwq+Q3\v=A Ʋ<4=yX jTUqX%.yX/t,cGX s];ߍsfv#+\N&LS+"F88XY`lMUT Y)>Y]Ӫ7x9ڎQk/#Sa!gh ibᷰ]Cob\w+3)t0ʵG+` V~CٳF`Nݱ.m9Ґ[@0O@[1 BۢUɫ9-ZpzXR˓uDޫPyV n=$k'K-Jr@&7+}T`KK0 ؽ[ɑR#l(<ǒ5N/;YsDoտ&z40al Pl5^9uh7="r9:[D[2(-Y)fޡhl#T J1GޭEg;_=Oa!]v>˚ZQӛw+(."lɳ%g:psa)mwH|"q*Ib6oѽSEa՗S<,$%taG4ܣWN=G}X BrXΖ*Oc%&eӵ  Yvָ4r\ pAU w+(^I_7ߥ9]/x:v_3bX^۔Gaޭ VUU&zVy2xF[_@.HgWEEu0TO7L@zt"jT<kQZF Q, ~GC-vgk&V=s\PdE{ar=%EF́yQrAD ݋]%̓ϧl& D[7U>"&wp5:[Өf%=X *Шl@rt"SH,}U[̧( ]&xH,GgKjآɬ7w*),O;%jtJy$cձ3"ROQnYmhԣRzx~Cn9 J'k' l*G`/FVN=O@h*MYDϴo~> 4 ηdp|a:[M]J 󋧗hЃqѐXU 7aS.RϒyHCgKP6V:C(^yi T4{Ѡ%Y/ W:tDlǪWg ~o ћGUƖJf<ӳ̻ͫxu +(6ڡjuޣۼ޽GMf9X@.Dg+ ШŒY/EP95M )© md֫3WCUīV5jE:t"5jldṾTJÛllaٰYΔQgaUD!! -"zBiAE ٍZ>\V@/\2K֙tZ٫x6@Rt$ 04t,g G54㲇RtBpz@:PPnLh *ɒ(@бY4oX7VfPXrgH|<$eVMf:CVW&QرBWt5Mf<NE|z^HdC@pdEr(,3-?yXH#s,'Ҫ btDЛ}U3*)/s *[&nް#ާ̥hӝS`7.FgK^p2KQ.RعiՍC@b5:[!I8gYE\jwqc+v=\@EgK [<.3/T|7ǥlɓKyUCπ-ȔyH,Eg+$ UG9V;;ODmSZr\ΖDM㦴J{2e#B%9@_@F4x?k^ޣ̢ pޣUt}>-y_5fPp'fB0FBt UAQ  X7F}ˆFrXΖ@C=jYCoʻ(((#Z%u\ΖHN==3bNe^=FLpup s:3/yXA1|s]O|`[)[EQZi<8O يHg Kd~OH@BtNN/uF(1X 8= H#y/-q絭5gC@b!:["mNx@ڴtV2 &؎ZtD"$.I_F XW?1<P* ǥl+;!nuwx2{b %F'"#ਹw'G|>p2g? /NX*L<&λ}XK*߽w(!]Kw(~\ cRIzjk/tkik/(ı~DU]GKtԻOR].-9uɳdy42oCTςQ}܇LA?>,+_K~ަ>1TwVQИe$~_ |`.A]t8 >8?nO~ЊEtzCU@V?$JQ*&es&qa9 Wĩݟ_*׮C?T{uҏV}VU:q^W~bwLuNMU ifEO `kJLYmddPPﻩ5ltu ?g̳ܝzeMSzY }o5Z}n/OTC؆^<˪!r]1FuW;}/[ '6 []C`4;C}y&pCG/fApQIGԙ:kZPpx?-:_xy\G'x?gɶa@30>G?c8RNJs2;XOۣw|5ûηz Eh0jV5d5wL*2kMU^9/6 nq'_OKlҭ?!|EK]Dm=?K|u|iC #_=^c=N1W~aT`g]9BHW?QxAwӄ9Wzf X}U6_'TI 8?Trϖd| ߻ PϰLU⎣i~ʝ J̣%𽯦Bj2peSOOG.]/ͳoV,Z$fYBWgTWm&ڗ@{iese{a76=z&ԝR5>t?WtΥV +V+FKH}{(;,6 -yACپI{c|K ێC'Dú֧ٮ[e7X:&MaUtrU^?m-iҩ31ĩ"/D)'C@"*["uHAe@T|YfE\>p̴VsDr*oUouo! m8$v.9!)H<$u$:8-ȶ BNzio,tlER*'p\SNz RVْǀ IK f e"2*[kQ]*CD_Cj{6=)=7tldDSĴ4tGa,"%AܵkiHiY:ɪBfU|"*[ѵEZSA禎%S!,"%u a׵DJ2K>xHVkHݚ@DY6q5nDUD*qc"^ًBQb'e|JdLVH57I*ɵz'+OI! mcWP@v403{HM1||j-yir5Y~FKAぇ-lS8UL`ceV9wDUB~J #F* ")h\yXHZe+$b/Da8b IA%DUD*cr!ͥ,WUb7;Ua0zQH❒4A!*[Nv)HVbг\Ɗw"v ["RV.tԈY&s([B* z de:X@Ze+ DHU) !A Bt:Z4,U@j׳~C!*["h"%T?B !2ZdUBKA %ST٤ܵ ĨHȹʖHjmSL&gJ|xWv̸V@4ǭHH!- {?L; ,C@mRy<|Ae+$`+a)u^*.B2*["TjP<ի.c1SxC@"*[!k`Yꢐٶs1ޱz"dUD*c,Z{~"1C@"*[!M!K>!z=WC"%o3DDDo9XD^e+"Cvغ -y=ϯ1Ui@DU"RIw&R[Cuj U4乞0!36OS||xH֑+q&dN J8$]D_e+Y&q(6.!<dU2& ζRKX|yHd`eK$C7tb »,RǘR[i]aΝN]i nfGp0)ْ0K 8\5j i}4-yHITEbU]14h( 2_a׹megxXΖH5h\HriaGϯT! )[!TU^kWvSLJ m80E$d,TǤ#4DgKzٸ\uS~qӠ +ْpC"JbT~u2x`P;h.CDŬ)spS"L2"^|'VS&xXH.BgK$TJ:C>2h\Z cJ]HhM#^bfB2W{֩sue%O\2T>B6-hz +يXgzP>b&ϓl+d"%Q!]S G}xᐗ4=}~&E1(HbǶbM&xH<[IakjA ~[ 7-(dxDy8re'i lCrZbA +L1Kb}5p)ΙuXpgw]e6O<֝R 9-dr\K*|y_7 5lGwqq L1?GVtLlS8g-V`eJ>YHhM#^y:䵲dT둄ٗx}`}vA+`;؅dOosC)["]n@ nU?}g5}ttD*(D/d;[ xFu?K{z0. EldDejtArxA5z>xXΖ<tAUOx5lB-7>,DoA,"%Q1QnfVH*ǎNيgm:g!W`1tLm1i6#4pâtB6됈" n$62Ul hw3ǎ=K18D\4jbL"tQ;Ypc!eIJtD2K*ǎe @ @Rrd։'lH'e9ي8fx6sUK̷֤u G!#ʗ=["BrQ:["O٧(b7?h;>$Y>pXV84St(`B>c7ؒ N 9f^^-TlBmۙC`-4QJOYA bA:[g%2xPd۞lS@Qo%xy╜n|#Қ'Ch"aAa):[T Ã*SyKap\VDTz4e=ܤ"%l3Oz<˞쩂">>\V@Fx.-V ZAb:[W@!+QcpL!_uKu,a!-D ȃʎ&ZY^eS}!  j#+&\-c K 9b"/ۉzS 6>K4[-,cvzժQ 5& hi-nTMEܦj\Vs&+Ɩo4k%l3; H+Ҿry.W]B+ꦷjN/ɎLN,aܦeL tⵙC`<ﳠ<$~5eK$C:q]!z=#ג\1#!,;ăkيXf &_b9DBgK+?VAgҏ'﫽ҦC@b:[!LP"|s? zJl el<]:@^{ r!:BtBCdCr寽hȫ%`-!&GL)șc><ĢtD*=YyLROca!( JˠbL\Q=C@ba:["ˡd]rf@brXVlGH汯%f8I-~|&-qiD`fb{A bM:[!SEW/3$5ۊM\ΖH*hay!!P̚Unx5P9թi o4,LgK+*&̙ѕz sp\VĪ$y+3(B>5lيgm.}\Ov=:"4jtDk&Yz3䦘-C K:2ElOFgnYH,Og+l]sfT_O#<:X@.Ng+ Cʊt|z?au9$`>xXΖ<7.<{g+[tIt"C:$Soz6ߥKtz,5`gC@bm:[!R׸9_Oۋ5 KْjHAgFOw ` ,ﯛtB6%ϐSW3b^n~zS?Lʥ. 8>hXV23uL停U=X̐q^9C@SD*)]z^}2ѡBhn\V@T'і8"B9DJg+: =dߜ`~OÊt))u 3$q=P|Zv\ΖD3ۈwW&]huW !-6uDc z`!`N_@Ag+ Bb4"C9=P:ÈEв"tD2i,ۤAnʙ!/ן:Ր=W7 ^3A b9[|.}/$!-7dS! i4l+4,p3܅gKwydz~/`C+5g$wѺCT-82:.0jT_;ZB:8N"E/>| ܶ;}ѡgs  Nd.'U A5<d !du ʅqB~ՇeP Cכ=NX{4u)\l[1$!-GS`áG@k3暚FA`?\8[SO6fO6BΞZ9}hql߫l>ƪ5lۓr)Vv#_]q3߶DHm88_0'+oU=7 O\u6S̡vzH̍1-ɌEUaqj,E7Ǖl?su{lD1QcaƔii}ޮ!ie1kӈ}^c(i+rIPxBlKv>x؇'xIy G%YŲi]QnQ8& Wܥ+cnTEb)=֠c~Q^Db>CQZE pi;(vσڗaA>ڶ]Nux1K<䣸UhQ$" Z|*rs} ~yCZ=vyq,}zm_NJ J(]D֘<gs߂jQ}Cm@=~xzV'峷āBnTnTݩo^_2zHu_4ʆ/DɎ"uW$C@>*~MOtU_JKE17~O$iv¹%*c=O_"%5^׫ /~d.vd+0ҖSO)}>*9}R0o]PJ)!Z~tE\R0AX67 ,\~|װ"K>u8rmQقWiVoV|JkplXM'M{!Zg+ !~t![Tk0}R9/!թ,yXrnBٔ ^X:ñfɣ\(}l_V~Rؾ ]mBvEbĵRaU5GWzTY?}BrKBq,u'kVy.xAC~Jpm즣2CmAB(vU6`m>'7 # ߑ>?yPob ^-v8Nb+! /,*FMxIG_hkv]Q*ywwzW¤t9 (awχesW=@'&{ ˵kmӜA'xpЉ :LRܶ >K'< ١qX 2(>KQD}Nʟ_<0eKm" AD}JrQ9ވ;Qŧ.mPOT:$MLT"AjTf/TWa$M`$W]nQْhQѝ \./֭,ltlM;) ־#n-3yw& '[DDrlt>@U & |"Ϟ(=-Q7W mr*DFv$Sў"bGfC9 W-}0x{!TlM\cMLbxM dm*a MIz4{WJmou*NϞn\iӓlcc`IOu2g/u +Qt%-2Jd)  lM\TGD7&pSn)b ٱG3 s=gy(#S"RIJub ^$TU$J/qKu-9w| & LzU;=TyX|l=wDg_:&;UQN;[8L&q2["El{ͅk&ԔdU! oIٽ/)hdԨTܒpl6U$׵]U$c\PЭV ܱ̖ؗo C(]3\h~ѺyHlYf+d@<$i_3S*usY̖D(p@h -X$lC]6POMCti$ Su ,e$6U0f@"&tE<$,%R ׾r-8@: l;tK2ET pn½;l/o}Z)|xբG6x8:e8F[¼ on4lYfKM|Fe^Ix)E ȝl|s"81GZRrüSͧ >٧۽ QFp=.~e"ex8ZrN/MUD! -6Mٱ"ٱ/>iZ%&RO;esӤTo=IzN?.+ (F!t>N܎c7e"h#4!$#&MA }l\>Yi^c(=ܜT{+`g)T6TB(>q|ψS;KxM̖<:?yak :H)ppMV7(Onz Fw+ /A쯗V(C2TءP*bew.'׍IJ6pn+ѐgSܦַFumP)ca+HY[7HT2ԬI ͛*e$6]0BgC(%}XkC@bq"["OTmoLNMXSu|<;Q3O!j;Ҡ= z(`Frq2[F@:O`bEG,II(hHi$Y\I³ڷAb2[`i JԘ 1E5a![c0" C'ޡSCW6+`!iUۑ@kYSkBuh[#A i Дo ه*(#I>-` F &)9S\0üYmf"E)abw VKm0x`2[b/bM'fHqCRQ(ӴCmpl>*EkUڑMӶ\BdHľUgy!HWFP9XDTf+b;SN q}>;c!{T)-l,Ǭ_[S0+u(~ۥe3):V H: 6_ϯ8Q-㰉h3 +H$X:Q8xHlTf+P"ܮkP#XzB7_lɳQEx(S2n*mn­ѫT[Sv~~-l=.`;~U*u RK88DlQfKx)` <\Df*lnfQ5EOJ.KHCx{Ey"\uU3s }|a2[]u0 ZЧ ؟̖H};åp#j4' sιkģ>>(@#eT*6mnwBc鿸vHѶa mnfOnRf@\劀tPU֑Z䖭 зMMl;z9%^bH䅏/(*W^CxmP`!-EM"u;e\ho,*A۔2E"*($ 8@RfK 7=ٽ?vT)Ry?xN̖zEf[j!(rD7_7V)o髠7\#aS`!}l=hi\6{:'5A\G:P% ]l^s^ x$MQkXIRWN%*^]It\Bki^9m5mwhH;~eD =Po- [7_Ab?1[GW"QD;=sigCpG7>d$J- t \ugww( IB`]lKF^S:F-ww( -A OuV,"&A~yqg xMcSaElIC固+~BcieDMJح̖H@ V v^׻?ߺy;Kk.> 8Si0yϯ0S-pD&2 Tg}1U?fX6T;~o;~TN:2kxt]R˭ߑjfpv\ˤiK+KWתHkޮ/w(Eb+2bVǃdd(4q=?> kK0:~/v+VYCRsCu{@0_ p O!MM\GM?ϼgM J.6H*"5ὍdT }KPO\>kp%vho's8jЊvN WbZREkʚ un{;}VKP? $͹nEUq~h{'Q8+"Dk=Pې9gE!.V W figFN؆U"yLrC67r2ը"3?,fld>Q%XFM(7⽙>kR%6PGG &T2L1HzsG oeڐ9gD r;c k-R{ojOޘ1ǰ,S ȳyi e"d{pcڮB6p,0=3)E"f~RE)EoPܼxB!#ξ$!{#ޛ9ZJߐ!Ϲrce>~CހϲG @y5K"TϹną|>J,WFLJ&7RgO̭ܘGEmݮ ӗ47%Z |T)J2. pj!%7⽙>+ > %0Dςgn{3| m53C6FAW_=J%5-_=ކF,d%3)~z9ὕ(j,ٓdni]VlS#[9= HHCgކVNNF$\m%9jv2E. QKւ[Ag)X3/5 }~>d 6B` 8ٿ:n([n \@H t0 {X'L*B逘۾|Щ ޫ-6'pX30iN}9 & H üu b2@5E|8@,P=$s|I߼oȳxk@n=(ן{P"D j߷? LZ;OB$DKkH=97{P 'ϟ^'MFRy1Q,$+ܗ.⃪G L߈%S |!E`=2?%m'EqEۖ$%I}Qz#8\uY:[Aw#ހ)[w,F&xd& (&M5ـ -\ HGЂ[ A"#,ނ['I"@|gт M\) pQFk=X?he_U\@5|;3%H7`J`/=JJ1ނ['IG"D&HHt> |҃zr%8#C n-\O ϸՆL؁bL{7I|m/Ccf ւ[A[/'ic.[[x  .oCpS nM\1"">dEyq;4Qgܚ `B>K ROrED[A \)_ۧ:dT 2~,$}ջ{k­$& ^ E|(?T<>@ik1{ nM\ X={7O+N-CLĺfbh">KOACpA%c֭& X<&px]ZCMH:nc r y8*h5āz-5q$^#OblB3Ds Zpk>_%˕mcOvT!!Z>h2cȷ>B SxoAn}*9v|p3ԫFȱ1|k$>g~ci|(qRX=;V8y)'CA ,5~KF&.CIL5񪟚p$>UDD9޷|(^mVt[(p}jAn}1-jA=$\!ڎ_o+LgnzoT z&h [C%Pqg5/2) Azk(aT&׍=CS" dg?kN*ʣpKPU9;Gu0yA=UE౵"u$>UYG>[pk>?^th7x;qxʼc|ڷx g瀕+8^ֺE{(R(<4 f(}U=e#*ܚ5y3D%YAHOMq%<>fYټkMq?ϖK!^~~ڷhUn}=MV޸O> fK<ȉ8.C)@ XL\m)W1&:e fFaGԄ[\l&݈Z5L22"6NS랉}܈tjf`%7y P5we?ڮ:GĽÞʸ_eU`|kvC?}%l \!ҚI@`Cѿߣɸv%\ߎOgolI\9/x16%ElA O }ͽ 6."V%qLG V%pJR>߳pXVΖūCs͇7yzq&oG`ĢrLs5暏Iݩܚ82ECrD\ي?o \8,,g?lI\'488kԄ['qr 57?Q>r/?BS0}.Yj5Asع-q?xy]>Y46ĺrW\WΖpIc>ZXXh_Zpkbe9[  ?L`hra9 D3Y9ܚXYΖĽ'"o؂`- !)# `-Z[x`l; PXXΖ pP]8+uel[1.lYjjul3L" "hr\YΖ{Ѐ[,V/> pw 5pmB6=VoI;%qq)[, %pGesJTcmVMM 8.-gpud7+ wy~;qf \<$v܀gX@+gKkX%sS nMD+gK"؏pX@,+g|_EO0?!mywufˍ6'2kޢaU9[x3[p"Q 0prNxH/E~Z۱ lvxX Ѐ m#k'`L-ܸ- uLU+7@?EIJr$0D "rY9L5O$UhH[A|/Kx[ HgU/6 ;X@.-gL#U˱n\^'7|j@nqq9[ʞyyY6hGChS}Jpo[4|e'@4kK5 xZpk$ri9[EZoD+#lC bi9[!G? r5 ZXYΖpIX)T  -\@-gK}/u[p<Cn-@..g Abq9[&e|yo 抏7S3s &xn C ba9[}sjgbIr 5iO-5q_O_????}o_\{r!ۿÇ%|_]? kK׭k m^qę~pK_4D [ӎRjhZݘQv2#?\Z)R_lLr/oLW3?,rrM~ [Xo]q^(j_"Օ}L Z0@?P׭P?6VZh ϵ_fG*o6&YQ=~MM H ׯD endstream endobj 3 0 obj 497579 endobj 28 0 obj <> stream xOQ/ƃ'/^聋/^8y@.zP KPHp bc#@ (,RRZeڙn?_L72}$}}ߛ  *EH=yay}$h$t+[u띦=y!g,[o/ 1gӰ٠7[}Z*7LU5=:a<҅]wR*k5|qwv)Ac#iD<†,c891NA]a{ HWHsbK%Ú@ע7$< +x+,a⡆bYl98'wQXd x)K حSb\pLl^nOS}$@F8\NZ|TYR;1S 0 F(HUS5<dtՈK(7հ2ŃA#|ANV<|]b4\نE\F4],cE{Inc2~ 3\Wse5XV]xΐGijӏ#5Vw7(WFvnm!5ZfwƇ}9R#Kwh/_9T0H2R[ak!3x/sؖ3! W{wPXqD} cэaMJ.dǑ +H4.HOqyzұJawǂs8p*LdKF10x,H1KGA4)SLy pm9 endstream endobj 125 0 obj 822 endobj 126 0 obj <> stream xiHqKa (%TJIK025,+NʳC˴>J+,c=Xϸ9z`> <03PȫMLդQMCKG iR:7oVRQ^ssKJIB@& pCT*Ȏ[⩦T7nD~qs+"7O-* Jm6#]Ft'asDeUumd.I\PiU}WR ' kifCcߤQjk 5b"KDi)> eH#'zzx c. | :bȅETsB8ni#R^e_(dA>A7"D ؔE`!*u1 ĔWhFxx"ϢѩbXe~t^W':'Q2AB z3Nx rol6XB QA yߥ!#'sf!@")T2ZHJ@N^A}#2(TO D!`&r1$ s ѰAB0'nE0df/=LM6Brv+4_ endstream endobj 127 0 obj 808 endobj 17 0 obj <> stream xOQē/j6O׫ #Hqgr(w&Hҡ(1$2,G3P_fXJ3f'ʭ҇W.@}\jJA+}䝜AjVK imٻmU/>ل ̳ B4{cS.YCތ;"bѕm\x)qBPw~+*$+^|7C}l5@Y!e\mxLÃBzI8v7; RAL휬S~qD;4`wUҴ-n`xQ95-wR@w矬΅竽K>Lgx\/jUbEvd9)^nI/4VbւB톐uT4ob]%ueu΀*>- !Z@ȳQ U*Klpm)&)² ֖b׼GY#OչbIyo+7)«GaP";LY\˲# ?#0<m'[TBZ:CCb8-`X.nxu>Pp*(9XZ)R?m endstream endobj 128 0 obj 818 endobj 129 0 obj <> stream xiPMapid2 } ׌5 %-Ddi,IRlYZTB,TiQ."tM<=8u}9Μw9 ' 0LG6]./ )24$>g̬9zy (hqN7Z|5'7lM5we+VYmbߩK\)z33\dbfvA %N((ӝHģv;) $(6!%=*$746YnG]Eڎed PŢ#[wR3r* Yϣ38/ID)Ƣ\IQ Rd (EaYE7 7  Vdj:<rfy?zRZ+J=(R@o>r|5ECD%[1D#'#aQs`5A}[@q򨽓_l(:w9=Ր>i>!RDL\ҽ/ jbw`CQ-EܕѓrAsQx8鮀|YWC(OSQ ʼnjTXD~w"eơ< 6~C**y"&eC[O?#\J!7FV휄²*D["fIe[?AahSK#*ix[ڻ47|HsAkBީmBPF+4*m 7 endstream endobj 130 0 obj 823 endobj 12 0 obj <> stream x7KlQ1@KkRĄ  1`kai9眳OGq7^1]p 8k5͒%K,Yl̃-R-ՍHAAAccc<ĸL'&&NNN秧gggWVVrssNsȍ]xkii40y嵵5^aL0a|9@IW?vF5L%ýMfff ޞ6KKKxp8gggȭ-<$Z[[GFF,nnn1 E-̸v[LQ.,,}.X co]Ϙ$$ɇtAEc 9-7pQ3%6>>ί1vA`r է.cctɧHT$0@"9P9zRt; sՑJPPR-9==="]J0Xss3`pAI1ʟ 9bgr$+˞c+ zUU566BUSSr*jvvd%i0F aaaqվ 9u]VRqh&$$h]űLq *0*I5J T2Gvuu%0v%lqqqR)T$]Q5E>ʥȼ\rH9]R>[aafMU#""LҾ?] TR=**L$MeaSbHoɒ%K~ endstream endobj 131 0 obj 1000 endobj 132 0 obj <> stream xKO@A4&E!x5 DB#J@£E{w[]|\l׫a=|vvcYX_$ 2ٲ!-ftb[ 6,&Ϧb`9>u㩊YfZIMX峹ZGd@`Bϸx"C=SdX |a/_Oiquw .-%r/c V[^A y(e>Ң7"6A ٖ Ԃ\7)"7GnX֓\gc Hޗ{O~#;P=щϑq|3/PWP.>) *lH G_"sg,u@0 EIL/ Y0C`Hw@:L370P S"s|6LH endstream endobj 133 0 obj 426 endobj 7 0 obj <> stream xoPwnF.f7hK+ӱG@Z j4g#x \-0`hp rs6s9NL2eʔ)Sqt4 ?!3E1g\Urѓlc9#~x뫰sI}?^9|_foprֹL/*$A K*ޥ +ٜ>^>O-oo!+ `J`LzW&|w gw*VGRl{1; q9xKw,,Wۿ|33G6w.v^x cJe8=#zb] +ķAj*6!-/h_F 9fZSL2e$ endstream endobj 134 0 obj 747 endobj 135 0 obj <> stream xt@L@/h$BX -@~Di9޽"4;w8-}z~#?o߼l}'(ۋKg7v~oyI53kgǯO-. [oalV2u_igjHIZL ߸}qաY."*P-psԄyZr{PchϏ/(W(Ͽtտ?_YQj ' *شݷ ۫+[2wo<%_~~*%P]@ 'XrAQB*QE/ŗm[\!/: endstream endobj 136 0 obj 605 endobj 8 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)뙛(Y)$r{++r] endstream endobj 9 0 obj <> endobj 10 0 obj <> /Length 43 /Filter/FlateDecode >> stream x3P0 w.C,J*TwuTH/V)PpW endstream endobj 11 0 obj <> endobj 13 0 obj <> /Length 69 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)Y(+$r{)+r< endstream endobj 14 0 obj <> endobj 15 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu64QH/V)24VpW / endstream endobj 16 0 obj <> endobj 20 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)뙛(YZZ*$r{++r endstream endobj 21 0 obj <> endobj 22 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu62TH/V)22PpW{ + endstream endobj 23 0 obj <> endobj 24 0 obj <> /Length 67 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)Yi=3S\.}\C#|@.ȍ 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 31 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)뙛(*$r{++r7 endstream endobj 32 0 obj <> endobj 33 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu66RH/V)26TpW / endstream endobj 34 0 obj <> endobj 35 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)Y(Z($r{)+r endstream endobj 36 0 obj <> endobj 37 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu66SH/V)26UpW 7 endstream endobj 38 0 obj <> endobj 41 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)뙙[*[뙘+$r{++rO endstream endobj 42 0 obj <> endobj 43 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu61RH/V)21TpW 1 endstream endobj 44 0 obj <> endobj 45 0 obj <> /Length 69 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)虙+[XY+$r{)+r endstream endobj 46 0 obj <> endobj 47 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu61SH/V)21UpW 9 endstream endobj 48 0 obj <> endobj 139 0 obj <> stream x[-_.@Y%H@-UzhJJJ@!Ŀo7cfkEdiU&0ǚt'h?܎QFy\_^O?c~?|ί4k67?Ϳ_o?c}<˛|G9Vo~/?s Ўlէ֟W~oyܶ稛5^~~Ow}?]W?p~riu]JJ+RuWW7uǏ}(lg~lxh?ͷ ~mo?G;>Fy>z|q_[ q2sۅk8m{5sܝ|ڄ/ ]cv} {3j?GG}f>km?vUTfk}~?Q^gz-qwYޟcm볤^nnupsuͺAu[|ml~a_o?6FvP/^,w7e?w\0n3|n}[?w Q9z {0*>Z8}4дsVźCP1}O@>4qnwj^n6Qa{GS~}ݙ ~C1R&r.̪v_8Ϊ-^u6-@k/uߢ}v$w\1>R筰Ͻ^~m}~?ppGzjϿ+G?ƻ}neN8}Ζ_9iN~?$?슭"8&khWaYb1yAY.GEORH/ί94;lp:ڹ_mɜrzgs:ߟϿ@=Lh#^ZOaz?#=?3nG<3#:><8rct;ɧkfGIJ9u/?lwΕ>h-t'~5Fr`]g}@,^tE"/~4dY,YzH?E޿#mbϵG$/L=1U4t^@?n;~x"~D7IJ 'nFy>ދD^8;-q>W_Zl .MgskW"6,6Kҡf8:f+o1k^`E.|“/-nz>m?>^ܶ̍V\Ƶ5n{Rq<~eQM6y Zs [HǕʛ}z=_Y\~iq?ܒq5y%r˹gnpQ:ֳ>~%RK|GuQw{IB3MA]L}e26ȴ?Ќz\f5_o]{%\}?|~ xv4Ee;Gyؚ*m;#P /6ͱ`.l6g&6fo:fMawqУ{sܕ͏`XՖCɌ57`+يm G{$k ߵ'wA>l/f}aʜ'h#}5+|oO{7ܬZa|sն혍-ZvtL\|X\ϱz~ _ v|K~/p #~c9N6 ?N+ G>7vkۚ|}|گ6'Pl3׏u#^YlbO(&9RQ/<>C l82VAzO'ݯu0IJRxXU"ṡ'/]>o+w9Xo1f~n{2o^W>_j۝߂záUtڲaW? 'qVϝ󽾏. wS g?eWLWӢ`ۅxaX\=Jc]ѯҿ C侰 }Nuࣇ,%u7fw?9"Æqu,O!:'OZ7>xI65Y_?O*=7Yծ?0؁S,}Œai78ۺA D2 ^ |_kkY_pa-}<ǟ}2=w [{,ڬ"@E>Zț m!<>גCa> "+²>ը[Fn=`K MZgu^@gw}}\QgVeeB4DXZlRWL؆O'x|yo5{ E=v~ܳm _sim :^5N>j=ܩ桷C{m?kõy?PR,y ;_m,lgyfw^Vu$= j1N?{R`gޱy׳:Ѐs켟-V[{޲foZ޶kV[e~孴x([H0gr_؋?P7Y<ݘ;}Qqh?soEnk'¿vs0) _v6cWIH=v&G}f n[Vf/^f5@=fc]t[Xyۆvl7αjz c m>_9:F_|9!z95G:~\sk0~U ]^һO2ϘV!4Q!c>0 | FJy %5a `|RsDxsAۚ>_?/q ąr/qNүp>?c 9zqz` +SW;\6_ |* mfVoxwcQ>$,]'}`&cdJ CX$t=LT-.vr).)#'^վ>&[.#O";Pz+Ő_l9[+iʥ{TFl=؆A;Hb)NH/{PF;8F:vhbAߔKB'WE@b..:9Jb'ru? Go;T j\5v,.$wRmm8nyC7FF 1I87xIqO[S }i^N4@w {lrL +{t`eq}_Y+w-B,gϠQF"=!} uY={Zh%pגKr'Ԁ: ~?ln+O-&x0 ȥMNI %H6 XD QbNO:ɕlda% 1I]C0ˁzP8.GX-asfŒ )Pu_O6WՅ=\DVW T=ݏ]^SZś\|Yn˵gInuUԈB98|d8n#* X;,t@'NIFC*Z \{N?Ksר ܳ`sX hda,۳${T5v~6J@34P;\,4_R6^Clc}zZD+'̞%ȵy2ukMu xkSJX=#ow`nW^躱H`nϳdԬ\N~t7tqDmj@E#q$ֽڨ!py{m;xRȬrWi##jTd!֏qOlCOЈVr)C랐Vvv(E~6%̸r6h%p%'3)1u,Zo4uG/U9;++Kruq9*e3(ρeazѤY7)p0UnN4Ig|.ug5[p܎8y#[ \j(e䦡T œ'"fα w1/>V&NZDkv ¤ƥ,.}'N<uۅ\2RWM`$P%:4mq_9ǿ1[5@⪾i8 JW|.%ƥA5(̓}RI-_Ɗ\:}b!hClE3}౶a96DZth%@ϥ融 8/1:ycKȹiE+KO|.8:v%:ؘ< > (XK*Z \sɄsrv+~T5(T+j,,=$A] v%g& \g+ |.mt2Jט:qh5A|6R؁ҽ=:93~%VАZ6n\c\^'XwhbBb-.hda%.E#s Xd# i4 '=Gʁ!$$G\XӸ6fR NmǼ\N/KqN hm8zܻ3$$V+d#@%'OhbWB5M)YX:s)lAk<5uk'(hBBBE]'Z \xsk>؊7/$Wb=T4pXrHg~P,.]< _?+JSq+΍57 XsI2 }u0ñpc(Kyۖ~\  Xxs)lSz虀S2yb鷩ڄ F\KԊN) sðHb)B}pR\zݫR[琂Bc]FH򴲸QĂPw0C4gNR"Db̘;F@3KROm| ؓ!.E* XR؊Σj@]bc;Xa5:F&k>ĺg ]ӧ 3DO@ot7vxF\ K~hNSLG+|2TJ%1 ŜNTXW_hcQJQ!3\z؎N>ycM) X™sx|=>@K/泑N*uAQ9b8|Sb`z/ J'z{9..Jeqk>[ \ դ\wk );yׅ؃hcQ%JQ=4Ί^â0Q|uN|TI%ȘhNMMA ZfR|Y \)R܎CcjR8cf{ 6U +$};M'`'Có0e .1JJ$"eş TAa"vag ,*eOB!dA\UzOv'RF mC)HIĒTw76 By=8A.JF9$1ݱU)Z \8sIu4+GP͈ 4{ťG>2DȍoQrySwe#0%Ա/R丼D#(jq=:e$`ϥcxmH6*Gb6t4ť7>2Ǿc6,-Qaɑ~Ot0'?L&k3;~uqc􊝶CoNtҹ;:ִ$wOGu9b !0X \s).:*%WKT#jGq6NĂHdǒj Ȍ\63w"7>ĺKǾ„ΩsQT^;:!H.¢Tw(Q UIJg+ȤtTH3)Ri)7>6>4}!# ZExV\{ {}faG b(yui#Jo|.E蟭hvCQA,ŏ),QC>HC?3(pA(*{m,*$ :wMw(}3EȣKe"  t)蔗/>;)eOza Kl4ť/>⢢m`tؓiPr5u@+>K *uRG.AC1,ࣣhdaϥSӠ*RX{-&N )-7{7ljeJeq =$~r)@\|8+ ;п _Ll,.=tStFT?G6p8.x~fJ&bdMyYT:s)j]GY#p[9")O# O|.=*_R+-WHym* Q;ϼKNX!=|m,$jζi8gW,D>b)mȌOg1W,k(Ob 1E]9%2cW-൨;JKr' ;P:8zoK _ub#e# ?|.E%O"(z 򲱨85uvﭻW{ݼ"U)Z \sIt'wmdƯXtMheq?X<4g٣LD)(/#%\;! +ѳXiqi# 7|.EhҸi"]%Bc"Ѩ)/# K7|.IޞƠi Yi LpRT2,QO8{'ҩ}̐gE.h%pϥsx,8WJ<@/3nWKleq%% wrE:=l$`ϥI0?9+殰 G78tIurE:w顝|#*6BtwU*Xbt>NFvԺmOeb1KqE953U9jBU2y.$wRj|L.l;a+&SP,,VA|f))jŢ\>HKR)f|(҅͝bR^6~\:T)(9 XRXBq3sVKxw5bb6&t/>N@Kqkep<+> 24 Q+]ou%'>RvMreFi`Ǝ4E'>NHxrL_i؆>f e/}.<WSP&Oh{k L,($sxr]iЎ.փBƽN8QHWн ^dR4+>N ?L&X{BZGԉF\ K4 n%tlA3z{QHKR'XrL`90D'3zz{?_V\;)N# ^ti*N 'w{̕òb6t ql$PϥI}հ9 ijX{iV,L} i_@/ &Z"δZϔt k|LIm?(wmTNbY=uPq>v9S!=񜑟9YZKXYz,V&2.- <CSEc4:sLϏjrg̟83a#[ P 3Δ];1,i}KeYE[Ҫ[t -V'̔fٙ3pJ]72Ӽq3̼J~2>F̱Ds0#$}فvA8[ρ:Û9 mM1LbsΫ@ o@DGq`yvl]S;3/(J1N.@'Nr˧C˷gѻoieI"=|v.͏G.2_F_?N ,º*, ^|prn w>'AFXٔ+W\W=ه* >_=n)8 >pqX_6 6_)ၲ?%$Lo>']W8̔9E g| d}lsaBGn6mׅIY'E=Tסal;euumsA]e<׬=}p5cj^L*v%ke/[e[8] DqЕ}4:oZN|^ djXEXWPe5|6׫QP>QCV)+?\1H#XPFRPO<Ԇ;{GTE F 2ծzdm S]9=b(r).[VDl%j_M2.BΨi9%ٟlWSF".mREjv* ȸZYY\\mh@aq%Qc\@gEEh].pS)OY$kt! =Aj}SG#غ\;64d ~<35/# غ\ M ( E B1ŘEl].lR{ע_qwl=,,CrIl\אԐMC49D/#\;@SE^jrZ),br)r!a1ywH3ep].Uۚ;<Ƹm|Dh%qUc GR/7z`'?,,"b!fMA?*gcV2[H`".ΆUB@H&\vh"@UKA] JC\Z t*vLlv].+m+ 'ynTHEp].RU q3Kl~G0%Ћ*X*QXd7:Ch}K4 ˥j[O 6 #aT_Vu$w6ԘTA"atz4zy?# \ lK\SS͗঱<_5ЎXMߧ.wsr0fǻy*LH@".a+O;,dnySƢ2.k6TF7 :.M.rIlqtxR!e<,.r).[קS $}RZ捣>:` E+ X /RvI.miGFt Ldݹw<Fm2.ĪmFC(b󯩮.br)n=d䣦sǣQH_~fvhF+(\֝F.$~5y)u.r)nG{*AbkJ*w* v1E]. [ ˹ig܁6Ue].UƕOBIVY,sJl#h\ K.hXȇXf(9ƣqȢb "!u,2)]4s C 1}e%@mK熖u@k w sjD+x\{H"_5,7e!$,,r)79S9iOviD#\!*U!f;3sƂ~Z!Ȑ58Xh4Q2Y.\;4 u Ua 9 XE?tce%pϥjݔ؂To;AL札,.$߻!% ,Ť;h}l8 F~\ iT0٧l/ |.IM4 ANt{l}WTRR Z5 %X2˦i@@x XsIl5NRx5y:bedaϥj)Ŋt-L|l|Ӏ6] "жg%c0>#jJ1Kqٰs5֨ak<f۲RЎ;P}ԁZzD# |. h2?RčzW>ĪmbvI<&?c>"g4pgc/ e#0ϥlQѽHhD~ܟmH5L#S i]cFVKϥm#Τi؆PϡL!KǮ]l`cLG;nV.ޜs).7M3hgcO!- o|.HZy274F\ IsiAҰ-A픒Xpٲ$ V١Gdȍԁg"bRml.6$YV\jJ~Y PsIl\mJIUgy1i$P.KQն&'WXQ &Z_F&P.XB!T yEGN (_i`>+$ri,ρbŲ1FLJh*<$W 7<Wx0#X->"zkS8plx8ÛǢf˟FV;ϥjTsmj\LW,.}$WM,T3FX OLzG+X(9:WpsSd4>df I VcY;sÇtᢑ >9F,Eޘ?mB<|4 >ƕGG7O(V=x}YY\s)Z7Q"R c9/ bA$58E`egv' ly`4}˥jCQ+R jPK箦gry^Oi`#@~ϥͻF'e9hEZKr{S[-i\~#W}ϥۥ%my>_&6 X8s)lV{̰A1ָ}eda{%j[SK{Vcrxϱ1h, 6\-5:)wSrcgl,,i\S`J͎Y6<$`85}%&< [pRCpؠi%?_F\F,]5vpS)wtR6#H1ʨlk0vlx HKRgӆ]C-ԨPT\Ƣ~ʘ!p*CU桎zL=`e $S&mJMݰ2kpLh%pxϥj]0bۀAg \:sI.W6׎_VܘhTA[QUm85h04ť>֝RAڡ̪S. Xs)l9g㈭1ʰ'*_,.$V,TtϐyLКUxΥw;4xUeND{WE# g|.+r男$t6E7ZY\zsIn)+rR*xhޘCfa.$W2gF+;Li`eq᪈犛2 F 36>I>d u)P;@qOLEC*Z \ܶUYi=h$zFE|.Em+pتyRlJ+Kr8HNrJx^!]?p O1h%pϥjݐ h1ʸ<썘,,]$v s$છORiD |.TÆ6!ʠ` Ӡl2/J|.(D,ˁ)SƨהJ3uEOBAOR k̂{zN}h%@%e]*qPT̆SiD⢑c>ªqCbeTS=7i&^\ KDO eHXL@XdgR\6MM.;9 )[ mWD< ~T*Ăo#Y{$r#VY DzƖS) -C>RTI:BSJ(g_F\;veNWݔz05O>qf-S ʰ8r136I,,Vj 3x H(`*FTݮJ}ju.# |.EeΩʀ\*?M)P8sIhlUpaU)wtRزbe)JC0ɸ X_e$`%j[jxP UՍqiaτq,K xۜN%|LI|.+j ]cxQM(tj!9%Vo x- lda%luH`Ԏ}Omw|tRH.HUu3O<{ |.+b \" |ŧJ /ZY\sI.L7E.mS8_Z.w%$v "U'Kjݟ&\9[6E-: :۱7& 늚"TT5R_V\;5|,:^w<$,.Wk,ThO:ŷWF\[<letRnzq4tRPi4|)V!9Uru)~g# /|. -r3dth{gBϥ׌" OɥG.ddQ%e5K*ZM1;?%2pRXm+W]K:4`G+K|.+v ܱ I#+_F˹$v6niV(y{jK: XsIl-U}Lj͝ug5=*`b.<'^`OHKaմKSUD^rh}׈V.X8Nz"ͨ`264N`$0|ϥmENSpՅR0 J].MUB,0 F&=–=Elc`6b hJKr]Szauaib? R6Lj-)  ȢKR X۩Au)³@ʶmJ+ |.-+0a)e[^KL8ZY\sInl#[Lǣ.GΟX/ldWUr)݆שt(wX*p]Av[<.G_FN\t؛E *zMZ\s)n_T *xbMASd7ZY\sIlИj19 *|bRwչڔxa%p}Y Aٴ1]~4-SuYVy$5yJ ׮h‡!5w_V\ur *^ROè;.$W8puq^TCS7YXs)lōaApUc n$`O>5n'l0:{ J)Kq n1%ʈSPjxYY\=S\ 3 \y0$J }Y \xs)ZW%ݹqU-S8XTb!XT@[ *x\f-_F@)KRgPWaURrνpc&h%p%mĎjU}v;HTs)⨀j# Ү?$f`[>ªmEI*5*xZ.͂Ga FCT "1`R82tRж¦H)+C8V^\;6/`pUT Ѡ$ f#J|.EUۊK[tTXdTlh|D6~\Z `qS0 Β F)KAհC*U%L:J2XTsIl%#G4Aţ~K>4ElC ê*xQo`dQ%j 4@yXOFT| Xm(TN&jp!Ѡ1Ml$$U4**D]a[xVN\1͠WhUi4 |.3jʠŷkB\U3j Ȣ'KRǵ⦈-UG)Jk,|tln.3#8s5\s).N&[A^UO)6ނddQϥjTE^YIhmgb6pPmu]U!~5i­3)Kq74 7*WUj)ih$`ڜKbgFKE誊Uiqkwr4pRXmhDQH1hTWGߔbacQ%,)P]yEXU<)PqJ-Kq6 xR^M#*XP8&bAlWhr}r1Ӡexit&|)b}!3wUy¨S; XٶW|=VwPJ]3К?4ϥj[jа ]/+ |.+ ܆1X"Ӡ PsIl%u(-+A/* _bL40tXj@⫨eyEê(:]`J/)̪yMr `j(=6 ر? S5fӛSuO,>g jx†w`$ ϥRcA2*ǫ0ӠDmHb K2ge\*MOh$`ϥuEP +J^^EaM+heqϥsWeK|Oy%/@<"b!vY٥8"%B@eIpl>?,GbAc2vAV]rx1j+$W-zĶ4u) 67icAzϥ׊"u13h(E+ {.Uۘfp7QD,0Ȫ y] 4= XV\[Cۮu]1ʪa:^bYXzs)XAT-Y5<&sL~M5=ĆZaqVp">%}]4ALjV4JOAVRDlh(<\TB|Yu<#Q!C)Z \xs)nhm YuWЭɠL6#q{%c*rOZYu\"bCO h$`{ϥmPaQVdԧaAx4B@#17oF˘pA~ݓ_+4)n#y[cNQWqg)=݁rJRdKi1'>J7ӏ?/m;6TP%[M,;N}k|j4/~vxLw/rfm6AUm-:gwrHrwZk;JAIe׃/WlS<>9oн4.?L x0 |x葾{6Q f\Gӭ&'|Գ?̊nsEcvoE"{;mέq׍Ӷ9 gbx>V ~̆qtϦszgB9Ŭ3x |R(s{9keN9|Nľ$\pbP;wH|ڙ nVC.o/BQgɎ,]E1g!O@.j$$== mP~; ;&PT:Tqb>Ln?9. }TنQA(rM3?.Z>㠆-YP?*{hjٛ1pDLLnvmoxt?᳗w\b U9l'F81ƉiÑd;8cn5}?𢲺tpdE{a3pe ;W`0$rϙͨk~ϥqܾI]|>GsA~pAg1A s77~5q?>TXL1"?;N4]ؠT)\E`G.u~<- fbQ?frݔ00~/aDZn9cÅeRؼ6!$l 9 H <&0:/Vd=,,IrIq*ʥYuthޮ8a+:N56 +E(1Eڷ[~&R&D6m5 7hwUleq A\̆{PƬ]o_4 @DhS. 1V%v|=YjPKy.,82Q.INB}w?Fa+.ި''IE f?(\ImD@*lb2;rID QV_#VȌCy@'eJ"j*6:._\ [T_nZ"10Ll$4 1Yd&Z+^7;A怃ڪM,(#r)?+#_n O'ݘzvQ}ЖF DJ".+(Ųa߮.m[LekF+.olSlS!nZ_jS4Ġ\MjW{r.tANUԦh%p!T A ё8dІI^0EW.ňQ: 砺\AŒL6Yjkgv,MءE+E *%[$uj*qioNOӠm*%&2JѼ~SpGeeo6 *%0Z;.c?sH_|ۦ#Z,Y\iS゠\Nqi"D+Ip!:@}bНJ@? :vvg+eK.Q 1ik#\7g=s%1{YTT_^iXkGWhus,8,*wsI/E RJyRZK5RA4[ @+kX4pmW},AimQi,,wsI서TxC"np.eWs8ldG:U.H{1KCӠ3tjn~ݱZ-\E ox`Vם{bS_Vx|uC.J bʪgЕGU{Fm.Q|ϩ=`T߾.]rCX?tؔzYY 5dl?'r穰]oU1lLzh oi=Lp0l@ _x>:A4HQA-.6s)nEF1d tt.Ehc1K2\yFXg%|6 꺤DٵKstW!}h#,H{95{_9;נ93JyN_V{$W@Ye=6܆S'G%¤:5o.> 'a*n/% x_X*F&쒗"-A I ԘUړL3%UT_VLE%/K:TlT_vTOlFT 5թuj55n3]+d$sxjL2`2m\A֛滋 s83J)l_V$iPc]j֟ <]r@"IeG\ Y9mSSS^Ճ=ʫ>-H{0Ken8$OmIOq_VVK6j2AQpf}L8rI/> V_TK?J!:&-?_F;s..tw,O St~6B=nJ)idJlcܚ6q7ަ ɷK3NA&} XlR؎mvTޡ0Beeq?gjX( y ?Ԣm(CMW2v^FBKɗ!FÁ\d)h fTV\{2TÁJ3~0f| ]y2RԦ \?5&T٢ۿdhT(7helSJܧ@o.IՐAd[f+ZB*hɣo.+Ggf'UgMVhդƴRT$ٖnKZ)YMo.$_7Ni78wnRDG%a0p}bNj@rמyΥc#]h3~ ]ce%B#7C,!$sܵ)h\f+Q[$. @ s4FnmSxLl5%LͼFUK6m.{bUaBǨbpe>v>5䗑yi^Yh$e]b_+Xza8lޑ X_({T [:P_\r 8r €E?tҧգKHX ,Qeƥ('ڹEJhEd&eQ=wQKSedaKanץ4`Ϲܙ$KMvz Tr`Ȯ%7mQvѧFyG+:*LPZ3۔]_6VKW#L/X n XҘ6ۿu`v&R0n Zٰأ%a0p}¼V3aw`ApNF{a0ݠ2GS̫l EA%$4LIdz F%^.sI/̸Wb.%e6=I9nm R& 627Xxk(` :2WUʇ@^pӞe 6>_V{$"HDOS\;ZyGl(v~s)(eʝ6uq|@nӎd T?&}r/F,o ViӋbU VVK6ȗ! FnCam RcF$vBJiē,AZ]Saeeq?Yb&. m8\0ihLzQ\/]gYhL+" Ikhdo."_z0:Q% 5~JB䭫EFb7ʃHe+i6.gn|XTnRT^ycf6t zNh$>_]0lDɪ V6^VBKɗF.d]S hh7lգlHb7 5ٓSb@CaBƂrk6}3*+tl>fX:ۅϗp}ä_4^p3g.$wä<4}\z k4\IJU]8 è4~N`b1K1JF(Kmuk;LK]/+ B}d`D9 mBQI<77υ;peK;wnu(]P|mo._w04qv\][aMr7Nn%2nwt10h%p;KqyiLڋn]]ac=%EwQgjdʥqbյ֡fg0d|\`e&6:4"UmVۿt`VA/'fЗeJ:G+]\k$|d؝cHx4navX\Qm}=G(vMjws65*ٺƀյ)QԦ`$P KR'j6 _ԁ-Ž;Oh$d9& FZJ۶ibip"id[d|_|+U N}oE# \.+% KN=D_"m*+m\:͕ X_X"}j5FᖘGb02ar&]& ;^/+I%`' ]ټ"%n%7Of;{pW,ԣH3YT9cA$h#rd⎘,M- F;)֊㲄5ȹwӴBHhsҧnDu#fyЋ׶JӒKq F.M :aEy^ی6&6m.I-LU̧Y0Bhٛzjm:o~Sk drۘoh|`ױO&E#M\ MF#+!oTƻ*vb=NfG+˝\K1uܸ!9b]1$Q̈́{dq~lWqsp"Hhvs6 ˆuW?sWЗsK y"s8"3jv69Nt&6Ƽ*z6Lົ:mX0Aag%N_˾2`Òi`|:l;դB_bgWe2 m^p.٬X9@>8׆XPâEvp.E *8)rMX%p0ص%T%qL\.99->f­@l 7PF3Em3/_{;|Y*PmUOJy}~e/Nύg W%X͸R|va{ſsѝ`#6r u9;]?ǯϲﮰˁV'jZ⩣hI05c5gJ|nͬA%[#xHzUVob?@~/r^!LQ/)g5~+r)2u%SUM$+E7y;jr1ss$Wu$a\B)*0w_u"/%-k !w묺SkG=~+02k9tC%eEu{}۰J~)vµz䋺_ ^5_ϿX坍kJ̟SU$+99C{@LQyxUN7`L!UWQ@ަy)ƫlIYdD6_Jv=g͕\w'á\tmg8DŻVdL(ut;PNRg;aԩʞxWtR _]D/R ўT?IAP<)ԣ^![ɫűT!۫;&E9WxtB_IWruA"UjT[>gL7bTiQE-oT,h?2!jE=a<.WOwE'TJyMτa(: ]SQӊ_hRk{RZ_9=`禁Z}2co`7ji0Gǻ~'! mU5^ߙo`z r_Nn`]eyU]IF)B&<7H%kԊ9RcطHS=q_:,N7E2?\j~[h[ƶ=۟bNwE 'ki(~, ZTNU(+`Ϙ~'@8+Z80GYw=ER'&\5'h%0y4,c{ybWMΤ~#z';=4UwMIVqApIU=DM5oyLDUjW=Uoy`xb7Đmg" ~΃Y0WG jLh~#`u^_UM!ω?̂lH~i$PҷyqU +T%&3s2yP-ֶ_]UQSCQy0z@Tz: >x]ՉJ#ofo$b`f@׼4q<v_YMul uj<9P$e;DK"C<U2u}~tt߫nN*<|PkyPͤĞjeH%iN(vIxw‘K`#XJ\=`޾Ȼ Oz.3[Ժ'L=bn䝮\ƿgBL%H SjHOz.3<@㉼Ό)w ,@)MfRF%*%ϩ7}UwE=ƟArL(\aUƥ 4{(\ 1x6sfdƒK`#ϰYKyib%!t=NuMꄾ_YI=$ A1'. xLxs`^m Mm_Bc\!VtU:.b`U55TsI*!zե5TicA=e<'3-opĂ@rؗ  nzN&$VauOjȢ҅:RB7s bY0%B#Z<)"}$yOdLUb"B, Lҧ T~r"sƚKJy.AII{F# y.I DX.ePwME<6M"z:p@vg(HYMuXxsIlrḾn寪񮩠tœrbGy0X=L @2'#2X }z\S7]Ʉ<GcG//۹][٪o_?o=-/ۿܬ m?=<_WU>_bӿm;W_ԊVW0;۫;:O1+p ~jÆ?_\rGGPՇ_ݩzјؽ?o߃^B}]x}{7owoۻW MwkFӉ v6%Ѭw 5[q'k{_;۩ˇ}>Zc҇Ofu'{/?wo}worl sګ'üs0}/tZAX?8ݴ9Ϗy*8ӹ>ʏye~a5H-ȁ_^s&P./VW_67`_WUzZvݚ,= r߯N>MUh[Zٱu>xWN7^ M>blyN_V} fcXdB<6,ɾlޖS*覩4B^==#ph>"׏y6u?(suxw WwUZ*>[o]C͹wW{c*vAxlٓ%qs~OYzٽ{뉡?t- w-C>8,S4x,$6CՋC>|h k蚔ŵ['ph29}>E>ίwW9T]}s/KWY}10'YW1)s)OeVd٢UFb/?H۷jRBirl tG쳽薙~>蝹 m~瘈|>mljܽo~pۀϭ`oV.̧}GBoMJټq3gms^Y &ʧJ;|.6l9ko _>8_wOy#^x!g5`w1"V4Rce.~_9]ç_nݜӑ?߰5iR_z(|f(%uϬ?E%7Ϙx M^qxp #6N Ͽfxa &a(|JSKi煻yxWvWti@ =3D Əo6^ _|xE@ _h{ܫP{‚+ m|EN w y+#BDW"2~UO/d+mbtDb:~bqDBdƹ-q+M?3~a!l (/-B/;624lLo,o$K=]je Kɼi{ZGfW3#=mRbo1@y!B+m|ejX _h~3'W؍H^^ [vb;1BdWV;w;I*":zPKY~aA6iEDhɫN> ו~aA6^T2|) P^P h2aVP6eĴbW3|Yjڈ Meb^XRF+cЌ+;5O;c&+""Wzr/,^u"sK-no%p&+G"`q$#W$J [|AV0n2N_xJ%+Jx'SG}pQ lM`2{DJ@\H_h^V,e=L PVf;(g~4iFuDDi<?B;#M'#Dv䙝v+N&Do%rd25&y%@v +5\ xM/0ԌʌgVAP6H.P>6[O,Wkӏ0]Ёs<em7Wu`'b8r*6(Q_~&-V y/@[~<σ{$Wzn`.nأ2 f%?VY$svV1a;w=Q׸1.~Y#?\JC8X}MWnؙcw9[k|.5{]Gxٙ.3>vboF^Y"<r:y hm8|3>sDŖS ׽;Cb wX|۾$Nn 4&'T>4[\떩rqfW$8 xB@>9jguB|?VnL. z7܉ׂ"`7w;}_W=ql:.[0ч|@a/1mpGj[Oan&9~+eiSXPN_^| kDŽƇl82V1zϩx̡3A9o!kɈz$gyp؇"s`dṈ~\3?FsF{]yUוʷ?,׳i7:)3ל_W>$W/G{Ҫ ouB-rp!_ve{)GshHC1@;fbY4-tE?M+4|?:!p':eW :Ttrvaal[4G\oz-x:SnEY3 VgyoAw^F5Ԩd~?U7dbƠy-n1hsB8T?Uܹ_p]ũ~?AGvS-{dYOZ6O&o[@T) j ߳^M|MxŲ1& ;~,wu0.cjw<˯h~dYS[\i[)ۈ1REG[ƟE{vO5Ǿ- lǏϯ1`be.|`~ZJ;_dzVZ/ӂ۽49T[̏SΑ9O#!V{Tq.^[[^)~TTKk I}e"ʾ]ϾlNAs)y\G7Cz/@0. r͟(PEQ恤f~><+ sJͷG |s0' cc)66cg/$ {t,ZXAZis٫a!PXRyWyۆ`\Y*92Dvc̓=9cgĂ%9p9-^??bZ6mںmm+8~_U\uԝm̞:̧Ou|||Ӽ|8>qGI|ΑG|cpS.%< +/cQq_%qb(>[?e`*{ ˡӧyƎH}{/E_ Gϟb r(q>ꚶI')D` g9(w.#:KR'a}B@7–ó@_.Eó+]vr Qm؊ P}YXR\ 8~z^xRu6?.vr)(]ە;ƭ\۸󷠧.T.t- 8wjx}mdאF[P$vB.)DgTo2W娲"ȌTV[AWJl=PqP@5Π5E@.Id4L>[}צm*6B6tͶkMr#OߴaxVtLL{qOW<a35r#t`eqL2tg'2~9Ǧ,BsBf🱛~q{UD/jl%qjRæڱ'2;_SΥbšq}WMS' XĴ撡>2f4UC/g ̥D/3B{Q`M`%pKr'vR|[G5v˓H"( #hv!d+)u96.^rI)'[{U~::hdaKaA|_:T= dRJ"& 䊲R <8剠AEHM9C~i,LR؁i_A ;. NϗE\*고jא:x&n/8N5nnL6KrPh2vF"d.EriH^\kPzg={2d.E )aێN>Jyv掳 :qps-nqƬ)^F 'sZXF~+i8uF+]j@\$+(WL܊>toF@ V1sڹHp<יc.D7{ї\{l}א:yغظH"bVtv^wiKi ʉ.>Y_F?v$c^nшr_}WΞi†햃 leqyj024bW6(Z6 T*zs?*T67"r-md.X=/+Cuw6TVVoC}l(ЂC ΐdCJ8)>N8Ko蛺iĨSeF#v]"eeqy,VN)PvغqNezWzY \%޳ѫ㎐ncjt`qxԹch@#E[,lKbwt{H1W;z~,aW>{ H%8;rzPTou܄|Fr)j8S[п4lCȢn8 KRdc$w} =Xǁ>.FS8K_?#f܎^@VCmA;?:Rϸe?lT6*'}$5sIΠAG|6= q+H.!|Ä}0.+g;b،J|tLs,p ];3\FKAyҪ.*Uaq4fS3R( 9?>6J;B,VtF+K|.Ez5a.Y.'SӅ}>l&y J%TǶ)ʆ??F\v^MSb:si:$14pqG mhځ0r'l,(2By<{S?Cs}vepl%pϥ|<xP7X \sI.J;<\31,"]77ZY\sIƔ{<9FCò*rn?JKq+]S=]6!i^WKȥq,.=$3!q/W8hx߆Ŧ=X͏F=?!ekA϶ {Bx!&T&Q0 P2򲲸tR܎ީ!.sw[4s %Vw/Z \8s,~+cC-Q.].IuRC0ͤa,tg+KG|.m<84too0 ?*]l%pϥ2j8:hɟu'qy^&|3FtR\Aߋݼ@uc(HKRIsx q,C* Xxs),gn;A B@PRyYY\zsI{qv+Odsl;c"f<6nC+ҕk'Z \s)nqeyc0B:ؕg-&\>&2)g;OWƃZ5,|ov0'{o^چؕgE^V>\*Ӊ7(̃wTz\|F>\ ;AۮuRdPR+F+ |.E*R)g gf麣u RȢ-KRݿc1uQ MCJűiHE Jk<&o'6UFZS\wԜE^ sp@5DJHՀV~\=V4TN / {> XsIwNlᱲq^ jm4tR؎)T)kQ d# |.tB\v@OmXjyԢiH |. uAFT3M : j ͞hdaϥJi =q źpVQJ7Krn0d['b RfB|.l蝝zC'j܊>Fq;Oj+=dR;d %9+ k| Xxs)lSz QO|5o,R ę'XT:sI.,z;1,D! B|pU.\wlXxttrTW(:_+=JpRĂPw0LFv6t1CfДg>ĺ_06<\ r] e(H.Vt]*h.N9]Ą^tPbhd(;S;k,i_;g>R\Ngʸ Cq$[ \xsIni ENtеiDULsA!]mXTTXMOlԓ# B'YzӍRbInQ.n֪f; &iE+KPZ={xPH|w2Š5nI,u}Ѐjx9{\ϰGTgV7$5Qtk]DZن87ؓ-jH#J|.IuAwMuj@KW>(<;ƠW~*_+Уb؁>>heq?Yѱ4?꬝#b6L2YgHb>O9nrsڃa,R=;]e$`dJbݩc0嗺бE}Ƀq!3ŜJ41vtN[ޮP+n*3X.߮Z-0Sa zrq+z!EHRO!ĺS M'&F=NF++5Tۙo׽uq7v 1@7{JR S(X[|L b,ICY4ӊivb6oJ.5+VA(r4Z' GTŌ_nṽ>F\z1y~jDӧY8/ _[ƅX5S'XTzs)jEl},kue<boi6$4Ix?ukKG# o|.-hD=&.fK^҉ F\=X&vQa,ŏ,]7>ִQy,GsO^h@KrqG:5J[#@2x=SSc>`$4me6S^F\f$)/;v̙ϻFSR\T:5:Rx"Sпa1?%xN͝`$P%aJ`ܑQWHzWmKq;NrHbi\PR} 0P ߹.>#pPN+)Ʃ˥]'oԎFJt0X, M&5YXsvgF8tPat FKRw$ ѐrS+E#,*.#`Sn`YOyZ \xsIv—ޟRNaTQ6D,<y4ԠԳ5 4m,$Svh8G+GAOr=6e$`%rjGY#;g{IzThdaR"t&wԕ)1c0tk5w>Nq2Fw9y=#{h8E+ 7|.EwR+ 2x6tq4w>NFqSF->PJuWkwMh#Pϥbޞp(QC :+z`$PϥS tt1Vo"y5fM6 ]ԉ2j;7>  LY)bAdIyYY\sI\U܆!d{eJ}YJwC!Lwt&uevd#%b$;+خ2zR{90m,*UK=3Wh0 [+ 7|.ɝtI)ZqpF^\ Kȹi8g櫔qvsiD+ ?|.ŲQ%t̸;nF臑'>NH՘CJbNE'>!՘k q]}|mRHKRQ+ ; [T V\+ʩv1B }ʨ^^,^sIt(̌ \t5/>24tέfFXt~hPE+Kg|.ɝ}\p̼&hk\͍6ztj`KԊPݹ׏lda) 1Eg&1w0H (|$W5Ntޔ6/۰tg#7\ K]?3g"gFXdNHۅ9\ckG' m*\sp7Det]>tWCWnf O|.I̹&_OuG3{Wh<#JO|.I\maFP 4w'>JAmi',ݗuk#> rj<"a;:+Ox=N͞`$P !E4u )ɼ{w]h=|4h%@%5*)"oaƯP. RE+>2%榩(vQϽS)PxsId\L,4. _XU܉V\;)UđqUή_AD,nM^i"Z2 RjLhLe#\*HQC3t%{Cb !l,(T :OvDžޭC-V'3PsЅhC̎jC_F 49ddQϥ>f1cO >)uF~ ^.tg+ G|.Ep>vDJV1Vky-L,"o6Kt̨Yl$`%]oO+ [>.XB`C # QO $$=KK+ ; [~/ Mh%pϥ1RNb[t~i8E+KG|.H뮏r/rQ؊Eã*u:To-ZXxbh8 }Gv_ f\"̸Zt0m|J?)wmm=:ھQEnjuc/?//.mOY}u`>Rϳ=Ob\H8O گ ϿXxV<R7$~THk uSuUwDCESPg]y☊ӕдjuWÌ?dek-Pfޢ_+ʗwǺ-홎D!%3 2uas,jJ. y#8|+~|~,McҰʌ3e[ԿCטyb#Yw %9 Nqc#n'c:wjj{VW-Ǔsk|?;^z={\cru`I`|r}f \~lk޹3b1$PΙk>{3/ыAFm's VoW6Wfs3J^SCasͺ׏|͕=8ݵwlQrĝs3"&}a43xjV@ Xi{6׫ILC>zgӏ)S^5E8&Cc0.B\Qb$徒DE/# ˀ\]S.!i<|S7LT%i]c LrUJ-}Lh#PmKQOܔcӐ zWkMeeqmKqն!q ){1.])m~E+x\;[4%AEPh>6!圖ȼNnvfÍ=T  ZOݭh%@nKrgÚV x$]qӲ?5x+=,6ps) ^ASX KݟdEI?V2xt\VXHBI۴w [.{˥uI-IASn& E].BiIbۦfRxV!wWSQ|g6&ҨCʟꀗE].ɝ+SP:^0 dTe].uN.5)[0bMbL`$`=#be%+QII9֖&brIl%E;Iڸe$sT VQw_jT8bg#\:vM,Bw<,g2 MVawWy2Sg%Ƹ;J"eui64xXe%@{KqմS寖tS5FӐVw$W;U!;3GEl[H".V YSUj;w<+-Kw$KP2.ĢmPULFxpDGl_V˥lJSxk -wnF+!v5E]. וpx^;c ˥l5 ǣt!d\Jm2E6jS{T2o&Ms+[,u.]B35)>ܩD^.Z6q˄ÝRxڭJ3J"/➸+R=ה5,wf?D# !/ªq!0,gw*q;1K%j\׈)q;] StlY#w=D *^G;|85y `E#%=}}]Q+0Fn\ 5 #Z AhOy`eq%Ԏ]eƦk&q|nF$# |.EUۦ{$jTl>M"22F/KRgӪFw )-M9":Zm,*gӀr kTwA 6FDF\;V5* ,HS//ZY\s)'- j"˥QVND`gCA5Z 1l,!ǹ2s),U4k&Qx <|-I|.سf+,:&)h$`%B Hxc 4c=j'Krg&"&J xl~` F^\hi$At9y3ѱU)Ls)FOzI КBP!l3>$F):H %ǖWhe\ێ6rOm,,tlhNfGy[!mV mU:H9v yiRq(slC%P>)oZd|BnlV\ t<&HökXk*2 O|. UڦQ4 e2.Ohdaᓈ#!&uIC)[~H/ H8sIU6 mA}0LYG{1e$`Kaն8'!GÎ?55['dx Ltٰ$8hZqΓT ?|.UúۤƄu6R``\Hu14$֤ tMYY->aSQlLAq>]m/O$X%:kԊ;ck-F#뾞X%(y:W#΀n?pi#~%YMCIo[Z !kGgj{J{.]SJI6<(kc8albK2gΩH5m*$U [tҸc 36zƶWOE+Z,=Wcګ H)deEW8Rp4 G)^&Z!/# {.Uۦ$R5v< P;~C*ZY\sIl\F(ʸy(6Z \n(+XЁ#ݳx3v =$4-KNѩZiȢKQնuATxTx V\+^ \NZkqk,.W ATց{1jxc4^Ʌ>VܙJ1ʸ uP=zqť+>+-Nab3@쀩T.\uWe܂{j# KW|.FRd玤ZК?,ޟs)viT9⪌dTHKa -)x"d6U7ZY\:sI.T,4O!˔ :ЬaCޝ?>MTH(LbQ"wP4SBsLmGaP/DzƦ 6\vPiSeرq7h%pKr%"UWǓOIq>[?g1)RbPǎ?*oam X8sI&KN=J;z}sZh$`ϥcŋbHay8Ϳ&6YX:sI,uR$#FETJ;y4[?%@K>:E*[eP i̊{\MbKg EK)1KlTʽ3uM00(r yC?&<$v6hd|cCRqJC-ZY\s).'D*ʰh,;C!h#P%Ǧ)0qYOu R;l,&KЈuqlD`"-Eyr"3Z_Vn$ڠKjES{㱞 }5^Rt:jKRUii%pϥER%+xԃACbK1ղ63?fX!9!DxZ=$sjBsqP5vŦ[k uLP?xAld`|ncS`Ԏ{`0VLHIgF8j\j'{A=[ \s+XbࢤbۨE}S)[Y\sK˙2gܓ^s(钭.bw$vӪN>iM,&%SIR+e+)| HbdC#fSD6CU)`tn#-r뚺.3:STދt4e>ʵTTU]R^JSs)Z \sKnVLSɯk|nEoCBz[rIbV!ܒ|mS#s_5ix&܊y)BkL:up|6ܒ:Iu%VOY~Y \s+|JU)_2[qJwl)[RjɪA+yO;[J6U-<'F;}SjE'[pR2[qUZ%-ؕ[um/ kVE+{nŕwۙܪ KB9?4EE\"6N߆4 L*S:vw7+|n-/?t ]Kw2Xr7FVo:LV ̵*x_.҂!EbFA +ߚ4P UYY*UȠdgjUuuqi+:61ܒ:]ӷMۙZQɟBSW7ߍ*")bf<i<9/KF eP>NN= fVٱݹDˇ؆FPyvi:u8  W{a# -]T_p*B$Oڋ|ozG+˸|nd})P<*^Jagph:|n+qʨ CnU[eS q)r l0E S~|Va:7{Gne~f?nc& ;YByfXUJQ&lpddQϭt)ʳЌlLPS/܎Va܊(rLxKI 6sKmL  Cq4/KoFQ K]D^j L|[2([b5*`!<Ӭ*ޕV\:%l EeU,= )BƂ"4Wߦp"&"sao?&)b+ǘaE>zᶞfS5[RkM,gS s2Ӻ!KUoV&wcL>ʷT=uʠq=r*6VԱR@mHٞF츯w 3Egc<>dNW- ٞ溽m7ͧhex|nɕgMө`E ND`"[1OV܋ Lwd9P7fSVÃ*3٪a׻)z'6d)}JCUV avM/h# ϭ4bA21V E/Ρ&XPFsKt#eZ5A}GE>֕EEl]e.ˡdlVa:78:+;'%Y{ZGv[ eDlĔg EXT4eCɰyTY P|}[iTLjxA]g XTs+|ІZQL4ϰC@E>ʳK0F ކDZʅ;M,&ZYT֔h,> d+|nɕk3l0ժY}wβJ"[qݩ[{])ժ,bo𰲸V13-[JjxQphB{n Za@ܙ)hҌ#*Vj!Rn] vCJx L ͧh%@~ϭʢ3Ѫ%Yv}ZG<7.7xnۘS9yqp#q-.`<*rLb d#|nm+؎fZu*hA{?5rMzt_d⌎dVR-_'Ja׶ >PDѶ{'Wܡhl`,E6_TҡH1%z3cCa{ "ܰv6C&?nq~YA ڭ.xNv%7i|=^VB@ݱmuӘLA֎2]۪x-b? Tvi{ .~c ,y,ZͬͶo75,c>}@A:.~6u՚y>zl—| 9,(ͬ7W$8Ōk ގy_q~|H~v?pv\V}~5 r9g8?qߦgw>C ዥJ)ϧF!QSzǺ|Lo7^")(Rn&Ԯ2ܭmaRqz߯9 _UJmAa`ox6uʓZ"{bKEW*o,j B 5ĸOfJd:m`rp؏ N%/ |ŷ`[דn_nus sB5,+7NC~i-Yos|[[¾7_,g{L~Ai]~GL%|T./\\\V\©:a\<a,CY3ۂcf+)y]-騳L.jLX[wOh8fc_K B|+-OgC)&UPp]k}F+ܒ{n*WxQ*L)~HyROW?7eA̍7T>Y|BJnu~r~l4!f MU#HFi+%la*|/UJwk(a0[ɭb):~ɳӯL,SSطXa$A_@MBuyǮ`Krp #ɛsbrKKZ V0M/qa /΢86w-4$ZN9w "aM 8WJ"%&vM؊-Xv'CkHwГ_' Kki *w>o6C̵-Tt8=:6<|~XfA1߳yrK1؇<:N$N da Vg#DKX|aYYabAǓ[A+Fg؉JxŖ (C Je#MKUut4 77+' >(]>]ypq;K2M(S>BO+)Ww,-1ȥ+9xKێQ.]n/FTK^闗:q[s=me`$'_'6=lxn[f3}7#yzEe RnE 2jH^z^ȘJS=Y:/I^W΋[XUrK&QnȾo |;5ƴlXw~4 2fE-`K%6M%C LHΉ;>2BP֍)Oy.8J\Xq7 cp?f%8͸ܺSw>EQ.,Xw,5gڙ:[B}1b&g}O2HR$ТѬh%p<[qm1b!o}bW 5bؗ;x*W$^,LY1,IQk^ި4(eػh%pX[r}Id 8O[u;nK}Y?Fie% N7];J]|0mHn`b=E VIA|Tcslw|9` b.j ).ic`J_#XF j`ֵY*fw#lܒ49+n3>7σd-le޺e]MJŌoKgѦ`$\ҧ aૺ<@׻GBYOW Vp%CFa"~|[֏zo6pujDkoE㎣F}?b̮zu41g[zKo3lG(>3@QQR0̲˭cW= VlOѡu&c6FfH=qF[3-zrK|%b!|ҭ,(.U}'KƢCl`lrտ yP_{;q5H`"/b سٕ&mnqcuaVEzmGBvw 0oTPsK|bF +) 9(A|ܩNNjklda7$V؎!>6 $b 7f0gk,Z \dֹ=VN;uȬ'XƼ}+ 3T/F00DhVK_nhD5bywR4Q{ֻvXSI:[ܒ+ Zy Ou}. E+}܊;pC7a¼+Kdҹ$l$7_K>]V8tԚ˅Ԟ(7+'>(?i64nX6 ena4έӈTEViRjyL6۴%W .g};ҁEض3EV*z}-.+[~ ={O1H딾Too[(|V%wR/qkeN츝[Gwis+fݪ\ZE>zp U~xc͸﬿V) =5oG WG|xzr&6r=ܒk=l ˔FLWɷ)@Vmn۰1aF\3o\AWvK֯al#8=!1EJxqʓj{Goonq+R *sh6;vE;vlua)3yM! 6sK<7zv :xnYMn#@[Arxӓm18X9g?)r8J(]O/Vʩ>5S%Kp=n. "]lȝWnIwbn#x#_'t|҆δJ{r3,F%uB>_X% C?h%p)˭h[Wܭ]_JH{䱫\ؾX4mv(s]65+7w*~sKw| b.j"bGfɇĦonIGq6P}b]j<4Ut5Q!:_~kSr 8(CCQ;j"%oFcW:bJnc2tJ0t }ib7ՓbAb*)Y.wIl/H12v@V,ˈ>l$vsK*iXXLjirST)C7U|3ئͭW9 ֒lC ew5u^Ol{=?vy7rRR|pn/t.W)2•*aU)} XlX_U, ݅aCVKU1({8\0%.zp?, BŌ:`6cYacQ[ch"Jo, X= TlT_W_4K}lFr6N6|7+/сj>W`)n:Kr3z0C?2!b+D,LzfTT}X ܊;09UJ3 v45Slv=ql;Xs[/eb޺`I` väy`a#x{we/܅}#dMnIeNF%W?Sdž񾝬Jʭ0Ɂ.lda[a97j8i)5YbtzΗf#_Xa&FVN'KJp KOl8iN*JI}YXnX_ys"ĨFz'u؞-kgHK8oovIFRfv)Z}u2onNᘕsRRlV%slz]l]PQ2VUڡP]ZF`bk6b E+]{a[(+a%<_cy|bU,8}uYV}XYNq7t7G3kvI,-5Un$P%-1ȐH+C٨Ma~TRln#kvϩgUW~GC;8MT_7mQwFOͭt*3(%,*!A}TlVT]R۰=1 Z?.G+0gl%!),av Iэ;bNT)PG#XK(DmjbTJ4V?HۿK1ʔ[e6w Lxܓ&Uզ. PBsӖE#䭣0'+.]N]pmɕ(&ȧhdtq8IS.խ(Y*y{7-$2HcBVJTV2yID4Ю6G-=1.=ލ66B 7 s Jb8z%SJw|iEhda [a*FlLЦ4vV u s/M̸D 6)hEwxlDyX+ImJK+܊˪VHUj n6IoIg# ˽:ˆu=bk%Pv`+&I+XvmX4r-FKoCy^R FK-]KկZ*dS-"lYXnX_>(l~HImxw#kɚr'}Ȇ$?70/:X }YUKk?,N,-}e]R[^r86ܬ9p]+lWK,ySJ]NAl%pS[r}a a֮UM}_ulv={ q R.Rߛ`\&pn钯GP P_TP`tJ/`#@[AǪF*+N5 -B^kGLj]+]ܒX% tյcPScn#<_ McIz^]a uN`c1޿*Zk6/h%p[r}Q`ƥ8Z-y0ikuu=̑.7` !յ-+q~ƽ$7 +[ըH M1iuy=(sK/DX ܃vTr누@on㘪RUL2&I/hC'| &+r/FpԴ%m~sK|`&PZEߥEL&6~sKD *hW[VKuR^%.Դ&Mp.VX_4@S HMajzXn-]ˁZPL֑Wz-`=0rYjp:8nI]iGʝ܊K Ҭ T$6":S~J; wЗ۾Q%DԴ& ݮvsK|z`%z@M{bǞgQon$!P&%s A)GlM"L.T%!fksX uEY^ƹ'&顊 vsNAژ*TUya,=+`$2 a;8tj?f0=2̵a(?rr+Y\V܎q+F܆wl{WJ8 dl9[q-=2'l&I_ ,_; $\VE'5nBOl=м+37M{ߛ)k<zVQ] Xp׃;%{_O}N8?n٣X V&ޭ|< d db@ihňUן>YM@[CXS1ǣQOAO,B?@?KfW(5+Kё7}چCLcNNzʛNG?MO"rfs4w}yIC9$P%k hѕ7ZS#``Fu;MG't$(IJZ)JQJBVώ<*gYE`&?e ipM=7]y[? e ,}YGѕ7ݝ|s#<,r$Ut&Ѷg_WB|ƁL2uMw'Z^\xLn'qy"o>+Q//Qe4!p[șzt׉(i)\5)TP;7uVϪv})[y33Q{.*]y3N"PbykjAIeّ7؏tgkFeuⲇ$| .r˛"bq2I \S+ɛNGDIX\IZ;L!Ğg \SI~t˔߱Wyב7[Vn`+PGʏ~<:2 "euMwE_Q!-sH)GOVi37;ꤾ2ryD~T2bkzSs;3rKvE]yI(9KrϚc Cw6)4+NGձ7me.$ƣ'oz;nm3fGGgvj3b梼ЕywfM؅Y{nxhG[]7#o32ѽnN]ZSc?V֍쉙1I)T=ϔ=~P fʵ̢3>^8YЯ{hwE ts1$}A'sOq^ǻn<{:$ZMTjC[5g`qŌ?g"?Q`1nN9#9]t5|AI9e_S>SϮNXy!ƆGD~<*'ŨG~ޡܠQ歠SHm׬i<(G/' *4K/v QǭϮ IF#LͥwB}ԭid tcJ5}],fpƳA)0+w+AZƞ;Q/).ҍ؋2&S=lϮNoT5ndQ?ie2;\Hsp ꉧuKÃRB-Չ 0( wlQS?FͷLJo# |1iRmsRƳUI,׍xNTFͭD=N @7 Gc+Gswy؏B=7cHUu;UIӓ!Zڎ]?=2=7LK O xvUOJ:7 k1AIuDŽr7xSO2:ȑ,xN6wB77n8Da"S/' jn1PxvUOR4{_b?H(΄MB+ky׍gOCDҳά8ݸs"I޸~sc0K;6V;;wxTO 17 }{gϮN?K-~Rp1yzjFExvtR? ! := ܶϮNH~RXQ-8)4F@,~X@᫭"UxTз( 1QW&q  (7Ƣ898AFq,N%,K΀Kdz~(A@4̬y{:$J\"R kndQ@0H{X"g("r8'89Ll~P 0J^7w#ID$C-#Cqod~ 0OLΨWnLh~P#u;[YOZ7߀ݎ;ؑM-ű:1:߭#Ͼ IFrݰ>Xubifeb~ݙ`~͸Qu^]G}hƍOdzA#%f'Y v6ցŸxtB?Z VukÄ]?]'n`ymzO Uwyub?O(Łc GG}Bįqi ^t'KR#ϾN}ܱ#Ͼ IT2ġR=YQT]ySAJ8@x׉g?'gAeFת'jTn8wy؏B2[cM[ J7JƎ-]G}B7cD,OJ]G}ZA,5nس;6vn%`?(RY0k^uSA?IlԻqS8>sc3yDn @+֎wxTO"qbۑ/ ߜ,7Ѯ;6"a?QXh><:ľuYy3{|*8,@UOo`z;T{t P?1~SB_2?"&j7fJ`~7,cgD Xi~78BQ t~<*ꧢ2H~~܌自ٳm h ~&Pf$la gX=RT ;rߜXF{Jʶ(lgkRKёg_'Ce@YX]NˀUG&6X oe,X˭!SqXU7_x@dzy꿁zܡƂo Z7xsBU>@dEl~ó> *6]/VucbSWTFq*jKTwyub?T'bqzGVSXMsm펍?: (#*o𘜵dz|>0 :Z{(!(=ܠGG'Cqá^~28rכn<;* z/*p  Pt'sr]?]o`Inco}בg_T&OcK*7c]a8ēR#Ͼ L &?*~NB@ueB;"֙&dţd~a}cG<$tώN*"UW&6X UoelM<#8u9B~1}[ {<#:~(}{!8Y ;;2~?kƞuǾun$PUO<&mo~(ΜNt!piޜNThN*d*Hj߀g}u6\TEyp}jyӋg?Eeh=T: GnُM]X_6#3ߙ|J`-+)=;aZ-,%®<u׉Ep=J-쪨CY -d"Ğ[2H껕q{o:D"["ŬS­co:즠zݦ_ݏTȾ}"[f+3~2~ޣϮ EYl 0)Wfj+x@F=Dl= @q%OHxF <*,6RyuK=u Ep=-ן~?]pN pv (k@A~t`t/1ųznORV-T)0|^ dzzn`)źώ<:@?b畉M}aް/  ^wyubW-[NYTFs jJ>H&uƣq M˼nd 7ΠznI .It ]?EPsKh`Ju\ W}׍gO'!ް}15m&;7l,3[bs"v厍y"[`#X[S^s;u׉EL=7oZa#w+ ˠzn {ܩߨM*%uA*1ՙ*n~ ɘzn3B.Mߙ5#cΟĹ2zf=C#3DmJnq]7=( {!E8=6+$jr3AN<j nN"4BZ7[n?a1R|.]_AQ- GuSzţpznBcw#tun"0KYˍ9;3 ƔV 15]ƳHzn%eazú@Ǝܭ,,#orֽ7tbC"aKnN"B%TBswfb2 YƈznA @ )9vM7FsKYdj(X^b §8+.N r{cV>۠Hң(]/q;)[;V6Z XsKl$uܩK4UQGmo MN}?uD=d.[V:6A ;:yQ1ڱ؍gOEe(=7*5Emwuܠ1Ysc$= @ 2#e.MG)(c!1@<0ˌVm GӇg/'aި+2Ll%`F->0ˌVAF}a)V<E"0aNxvuRGT>~Kw?Ͽ?泹aqկ3Z@}u?߫{&uO׎jտz_ݫ+~um_?|w?_/z}mJ֭1\Z{}뷿_Oa(2=8jGnmO9_^vm/xoߺȄRpWtl.d/bϯmˊ_nUi^X7{[8eE^R?M,uc^ֺkQ_x]*?FkAdowLvJ$R_9lݯ]mG~6f,{LBo.XLV1h/__z`b^ w!oab׬.W삗^߾?xu5Q M >67zHn^>n)}_ovuoڟ힯j+!ܾw򃱱WYn$_kFլȼjн.ؘα훟}Vcs.Xy>h௣zd/N{]Ss X>0 Ӽ 6Ώf|UY2m=yl~Ǖj]*ϭ&Df[FE}^yrP3ɭwE~?~5?n3Atx 3պybj`ޛyOweE;ru*csk1ag?2g6/_4os"9߶3v*Xܽ|unW|R ϿM]i1m2x~4{o\;_{թy9w/xM}h+ǚFL2-ti練Md}qbԣ`߅e=)K|ͧm~yw;J-|ycx☟eL %,_ |Mtݟ o}`A;G`x7 |[пP'e!yaa`; O%p̢2nW l3o2#W:f5HM"&JSM U7TOHDO%r$N$~2Jޙj:1gMOV۞t%pvtǽ}F긑:ndT"G;O ƶ߈8oDuEHvg=#ܼ sJQg⽒Zy-?/<`g?"W\ϷH1qr#~%@vYLj'%j*+\򯦛_y>1q#뺑J"9yCVI~ ~+OrHY'.}F+Jh t%}5YHsK_M"|&}oF~J"}h|"Vwȿ$t%MV{m#ZO<Ҽm?oܶ;?^ۍq#@9yUJ@5=lyy%qwC fsk׍ݚW lm͉%l=h\HԒ6ݬ|{KT;~%qS/ʼ\ QzL5TEWc\W|{QX+a\]Cv$MiYֶ0Ze\i;׫Y*[Ulbwcc¿8 lxtCЭm? vakLrDnݰs?Ս{t+wS!-mSѾX [Ix+:Q4òGL?BTr5kwײ"sx*oqG.6sv0ﭯya ټ"Ҝi͢ùTM9t~EF㉦z^_vr)LM8'~8DyMOԑg6Vm×,#>~0''\bXY~7a9xjv^rpҰI^=ۭ&~ WWWPfYbo8QM]5Xߋ+,ُ+?fQ pv{˚DjbS{#:5%`A/^f?~<|~y_56p_3&741w1s]ٱdmoLb7N _U|ri_#tbv2]o&H?"|qqx W+}(zOTBq!s2 ~4IOIHc / [p=1-xe{\"^^Щ;_ m+~UכwtRdG[^صƷ{tluCcD9,tdO[lljV(϶߯ÚVsu fur7;=^] 8rrcpcNUݯs 맓_Kb sYsS_} - J [Y7yeF,-th[>}N%cN&zzY2]i;!Ng⡭fEk0|n`6ML8uGq]t~Z]0*|X_17ٚ{4??m]x;ˠcIb/G' Ɂw~*vfG'G+Vɪ9ij ibghfƂ7)s+0W%[QO+6i4^:>;Mܒ<9.W:z`'34_0 m,0w s+01צ {5 G̰+[ \V)p^_^Ʈ@8V=90ի2r+8`vV{; tk9Yd|q JסvU&9D3ͫ,.sOM%: v0}rEn*09vr3~\NlhD65ו>4.Q έ**6l'ep'\17q,2Vy;M޷yUw­jbE;CYNuQu%a7e+ ˬ;)(AʎL=64+AqL#[:O̩eyXvK3^[s22xs+8ERjvuۼ`!s3L-34jCϮ;ʆ_m聊vk(ͮHS/^0vp%yrWq!ܶ94Ms)]0ET܊*7va8l\0W4 ͭ`&p[%sxjlNcc#Fze*InɝConW%p@_E+ `8V`aڑu'8@>J{"# 6Lބm.gW>h'`QM."siC'~;XO[O8wqErtn{Ʌ׋Is`v2hf; Vj  WqӣtxmZgElqC`'QW.J+|'6 5/dM\cÄVPVi0(.[KvP$V%[юk; s%,$3Y^nS=ke5pzχ@Fܒ|%+bMN2poze܊[1F^`Q0XڭԂnfW0~#6lcT,:0ʥif \h&PQk.w0ՊQF}>tzZŕ:SY\OƱ3N>5q.h'q5" DڡNhj"~>,2OV i: N-9X]H#6Dv?Y֯Q΢lczϽĊf_u${Om(EWa_Њqn|cH뒔 &^g!#'+NɩE`IƵs6АdɰGIro ]9ƷvR@E?Řy<)/ub˼,G,.%`9Ԅ:I,3 OSG;`nE9NUU~KC}1,2% `3T7&ZһE?ѶS5L,0cVfW=Ki v6p{JeF>4E?V?]3ˣ&ۤyOfpa,E3 @n waȉ/,9 |J̊v?s+22HV&=JBnޓGiY TsK*NB[PFOM3N[51vMheqϭ 2v'YIz@F?$w u{%D:1;+ӡ+,.bq tv^xrw&W.B?<,"bN.<:>=lٗS+ d -cot1%IrpI5+\D'3[ϭ cWq+LlM3뼘7gOOfܒ*#QGit15'#+L#ҟ[^n83NM.Գaו*BHLމ("atj(~};T,E;PnIq&ؕM3T jB_ơqv܊ OŁ q˩)YdsKreij:T fW!S[i5=1 L0 й =#_&eTޕS+YdFsB!;F(\:踟:uxxsѳ/ETȈVd߫(X`./׊Wf_,Q,2%y\c8c8CY5/|qE;nEe̳XUR4â@F?,㬗=2L;snP5/:D,0Cx wU:W)1#ǮJ"[r=bend+'tXņXWB,%բ5v\v!܊\1DkncNގw}y ds?59 {Du[Fw櫤 3[y\[PC U`{ۓF?{ a*+]+Y/'K_b4|5ZSJf&0[Q3 =r@^Kt'[nvQܒ+TM)< ^J"3[k%2W=)T\Z'vM)ԡIR0V!ڪfWWUER+U+YdFs]TMkxQ:V>jVWax7VCKC]v&W0\]t֌0)&jrE3 넡lTVpzoG?J+nѰhaaMAǼP}ag-ɐ @ ..\N{|)@F?"7R6YXG3p\UY5+] f?*Ar:Yz۾m@F?"2ֵ xd**&t?]@npa,Ws e?^U8]GջR(_/C+ dV!:vMB ^Ԋ.hg[ (4SƗYOV[q)wMlAYP +yq f[%FzP$uqg knE+-܊qwGgzv֕CR4--2XE0)*O#̫)佪d;Glu{gQ@vZ6<,rKNcx]3i|I;.JG1΅߼8DueHa'OZFVM)&Pܛn- g"!%#DW*^CSJۼ*U7ͩh'%[=Bd5*}^0Ԝ.Ӿw7^Fj>/ͯPs\1oU+ZY\e\H()DBi(]|ycVfON umz@nEjEc(p)*NPC+Y9U 쁤a`iʩ* `*Fԁ'c7O;VzT%})ېBH@qaO`4Fzf? Op%}14|~g 60L#[=@d,O<+8{0GQ]hg- bQuQwR4`g;nEVV?zͭsM37+nIk#Q$~zVgj-0[Q}hfϭlUs˃H0JϾly3;nI2 k>N֙Z#V,.%DCS˃H5چVnM8) dϭȕe/=NE2-9:k ƺ5Mh'-eI\YhzVvc=snfqϭ c[\SiDzRk{hn-+nI|\^׊ͬr50tFTI &cUcY㋿WE?z>iVuVA-?<#({2~d$$@'}+;4I>ϭ( Bi l0ʯۀ>e%P-"bPGqί%*]gv;nWL#[ u HN+Z5ëzEf?N.YQЪP襹uR(L5`7E?vQ *j`IJM⃞:Ȍd(ȇ*oJWqD_(>q4M :X5BIuߦn;d$ϭszR欂 yE፱dfq-2Ь:YФUjT2.rF?GٕYc+ s=5e?zl0EsGHeK62kl#]&UС o?uM+ʿ*f;uf߀%L+U!B}wX阭,,v`x6 đT܁aoy0%ܨXFZBcTc?Ipzf?7&Qga =̩c׼ f܊[QүYDZA \1J䊍') dDsKXd",'lIy)ƺBMheq^N-5< wmBJ"ܟ[qEx*bH*7E/eXO|wB"cQU԰̨ ع-0V`a&s ̤#W䱲@F?$s1_DZAFKY5֗#ݸv܊LΉs"œ e&a+L#ޟ['hryi-f߅C_*?¦v VkJ=< ,yn&fϔѪ j]䞚Q^wf<1P+ ƥS;4S;B"3ܟ[iQuAMCL)~d}iN #ܟ['g)葪qB-w1ևh$`ϭ\;UAZ0қqk,.%wR.=AkTFulM+ dsK MF,Nꩄdf?S7=N:R9N#Pc]2;1 RDm9˂cNcTAx"Wn&@ϭT!Z|H0,.%WkѪ j`:u!t"[a'ϭ\F7T9Ge^=p"[agϭQѪ *S 5֕]Pf&ϭm'̈́#w va? dsK8;Z;6{lfX_N g<,2#%yrt=a>qod%`ϭ7KCi-f:Tx>.0]bs}\*#͔aC+ dέ\]@ZA%9I5敝l&-SfJ!UbP Itv33jʆq>% Ps+0\!&{}aT#)c.+ ˈn:UY57DwX7v Ƹ6VX4<ʨefܒ+gY2aWFuk;evW!vBf?Fmffwd<*s+* ~aN:'2ޟ[bE#*c;<0XH?0@3@{R5f? 5uKl'-^n0c.ݔNc];+b}A6X[ $Y*A꛾WQb-WmFXbχtݹ3P\/,R֚#_癖A>/FlwV<҆oW?(E-V~߄!|<4ܬi[lǺ_gJRCEΥ66BeR)N~A|穘NK/TOlʷ:n*vYW<輢)L8r^Rhy?ݯ|0ku2-YB8|7,>?Oqſ}_֬lO?C%e CeaIˁp)=XW嗲 hUU BAZH윫wEYs)u`Vc,7Y8(Ԯ4Yh@ڿW$V3?4C 6L~|JK]?5PHr$x%<>m s'+4\5UW\{ʷs}J?e2f =3LP9mkiu8QPBVSmuQw_57xkAPQTpNoCsO[Ylq>urϥktpWi%ͻ 2|eaR7g yeiWg~߾x'=}ο(Yx#U֟銇}: Ǘ׿>Ͽ}^ _V?W~>|3ǹ57D+7%8¿素ݔەo$]*jc~D?W~>߬~"` 2+M/![H<F:p^kH}%z7j夰r܉po;hpsУs)^v- k"X;Ra]?|1ЯF0Q_\lvOJ5eC‹b ?1)zp>_,2cKk؏5 , QU Q .B8zptۯ}aE$Gx+" 2)eOߖæ 0bZ/ws^v㊹G \m_i$@Jj 9ST?L#̭X/z=FJSlZDancVJB3wc& J_[f̭#zLg_ϮH`N,܎y dd97SL])]b;S |%h'B[kSlr[QJV)%ג 3%p@CM'xhE`ns#SٕC7nVl,(ssKk]RMMeW",Tqjo$]274ʵJoԹ[ձ6.N"{0$OlaН%!)!,2s+2eה{tFUj E`nɝQrO*[X(j>WP<,.ss+kRBl;u2s+S R{Vy VulpM5 ץUi~>,23sKojDAgj̊5Vͦ0C2/N #y0"Agj9'k'M/(JlYdfVdyX535fiu&RP3<]@eq!R Vur=g~FCzYdL-=S 4uE;܊,O.\Yj|a ЦYț ^A⪣ 3o^^h&P?[)&(\I  #4@>snIYX%3V`6S, \pkʥ)> ox";;_nf %X]䵢 ";a N #0"_;'6ڝlY?& Bv9%yzxL9K[ߢV?f>B@FanET]c{2FW(L9hgF[;΄Q`&=K%6ʻk%-j*Ħ(7hYvTIf>an]3 bbzAnsi T{ f x`O=&νs#y YcPvR4'-A)GSsMwh:T鑇Ef>anIqZ{8rk mj-3܊{2q?'T} fk؈J5ifAlUx;ލENanI=P}[jTqU$&>*̭tS ѷ:x5qV0)-ӿ$4@g], s+&AQkUt\E3 0| iKK "P[&4IkVd9ui>A8*\q[2%yzxjByh 'x*W8S3Y`s++$5T!?=֜5 [2\G˕Y_K*r4E?ҽ|FQ}h\=?ILhfϭJWh+l["ޛ%h&ϭ8u"!|@쟺HbQE@nIR/5ˍx%q. D;1vt1VRKwY<(6rKyp!l'ZR<8@hfϭ'xtޠw'\>CpjfE+nlԵېԠڛ^밽[_C-O:T['Y8S/ `lV5e 'V'x<~&G;=ܒL+E%3{2do`dQϭkjAn'oC3+ XsK,뉷:wS?0Yds+YDK4'ލ:[MS J~Sr#΀AfV4V`f՘tjdx9A,.%w7^'1Q4̧@F?"ӿ*a;^ k187M`ea䈍xK|s&%vzV56GOcІ3%x7EO(QMOEcN3 F;OMr|1[ Xs++Rz84<\5.lCs* Xs%E;I;a hfϭT 6,5w<`*Ax dsKt $yBs׍C Vdu\~̡FգH!RR\N7yY>,"S*t0HW+ pnRÄJ;RXgWͫh'ϭJ;2\¡ᇝEf?$éJ9<| B fח\S+L2%)`%0[bRT"#8ɦgwo-V2ҟ[q4?|' {w܇Ҽv܊؅Wg?g҅ԕ}X-ӿ!@4*#O18:% Vse{,FI^x&^x9rf ,dvAXb4/C]q[f ؈JQ}hjAp]x{Z|3PN"؟[wS<+삐j?}vhnE;`nEr:؅C?G!RD\ a^xADJ"ܟ[q^"W>~0m5K-Y/G䟥ŕvЏyxe=$LXa?E0uv{h]rN #ܟ[U3JzJ wfA[Vk%x[r؅B߿z)0%xW5$G ;Ϥ /E#oQN #[堔\1];U,!efqέ}w<&>z4=L#ޟ[Es˕C XUu̅V6 V`wJVXCGARLcCC} co;|<,YM) ^}g1!e??Q_r<}cj..ryZ_/о|ނ f<ݛ:ɝՔU T7&zWvU3+ ds+rpJ97C8hr做dsK " `W _oо͌ނc8e?RĹ }W8,0BxeH+|5lSMcpK1YdsKYIqIreBg #_,P4@:yyhVy 1  v1܊|b׬R _2P),.cw.Q9gE:FOm_4J+f]S4Yd;b#,%1@y& Ehfϭ*;|!ʻR:ޢK^hχ@F?$]# Mޕ!T'9Y\6b#( nekCb t:^ ROh&P-u_]Zտ7֥lS;Z \ ̭meۙ5G8CpMp03#%BRǬfXԷ!x `s+p]6PWjx;Jn&p-ӽGxlÇ$_q&v4 Vkv\rWNjA y &8 `sKo*n;l()d=xEf?"IJxFM-x c&H+NjБ:^K.9$ujpK3 չ ڐ~Y`s+0Ti9 RpJ33qܒ{ )^ WNx`ooTEf?")R"3[ 6i.ޑW"{t*Z?()leqX҄r=5XJj4{]LθnI2rZ1kչdOU* ds+r[]$$(li(Hʒ7;nWnWL*_ LIhdaϭ}%v uҙe܁iMg:x2&ͥJaT6Hnm+܎䯲PRyV d4\V{IîZW &`%`ϭrk]~|ew8c6 `Wgf.ȷʆË40cԊvs+L+ W fܒ;k[mOiB_kN9,,0 -gT.0g;#04E?NA~ʆ)fM.9tMhgꈍta*[ӦQ%[ Ls+i]rFu}1]`&p[0 ޝI|%/ztf\*LƸnI5t,O=_ N #[/w|\a 90Z\W"[ao׿Qg:_}4 s;BL8$l2L/G3rFhP5Ef?$GA ӒָaQ8 Aq? l_'3 LsK,h2%|鿅4hMhgϭt*5Âal,%l-e׼GJ}U VRHnt0#Sfߍ6/6bC;s0 &C!bڬ嘭.6ͫ~1Lnf vM`&pϭ? &ɵX#hnٛц~ʣ$.u1h )x-X:Üi߾nz3Vj)yoE38n |\H`؋c[cDf?"WܚMh) 79a bL"П[r}x|Ri`e0 oVurP_]YfLU} ocu{Ngx\tn&P{Kbş߿*>n:ê=:J#7?R odo%bՉ׳Ҽ4_!?~7V)uRIԫ_nJ̲^OvG^~_ch&V3eo59H b>[h1 9 ۥ`4]ҝ:|ƒا\PMN{]ev.Swi>xW w~ 3_ύ@'k0v ڕm Ϻ7J'* :zuolcќv|v*WPmx0ņk>@TV/&)ԀʻfPYETSOJu\"Q1X4lpϲtEWx +: ۦaPۨY]7٦ҕç.q>?^ .<)ރcR6f/OY<:j$а#h1ZmE=ۺKS1Nۿk*;h8[l盿8|ô}f{ i7E ѴnX`̉pxތ'J)'-߯q^%X< N~eWs'߂g\w|-3?0~U b&}~ioW&v@l" eNt8Nj>ݮʒMklXkMk+ i[υc'olzC OoywQ8:xĥMۺ-һL7o;@.}y7ksͦl#_ܘб?gxz}T|j +ƾvt{d_BImWx~3tڎ-nIlg.WrKr88RL*+8dJb#-ս뮻-۱ݯ]P^C͠rcrKLP9M~#z'ZpԆO9,2scr+rPHU1rÈt+k) 22HL#7& S2h`#yZ"W(;Rp4w]٪[[wBMn閥;)#7'" P7U i7;ܛ:sR}`d9-o C.dL#& &Ocɨy/N1ʷWOT+h\\]]s0OY1't/pZr30&.*HV/4b6 B,L.z1 QYx:m-ɖ{ r9Xo}l&i veMj%e76kofW-QzgYVX-fC%m'Ry4-9 oxYdʺ?Yag<[;<"c}N70& n>_+EeP'Ɂ,W4BjRnkQL_cDy6)Wge>WN-ɶtO닛1x\I_5#,>OebRn ;M+rQ_Q0tқ qe SGm| FSH{-Qb?]u8p31Z7fSnܰz2 ? 'rr,YPf'[]%vNw\(W5f'^goUsxr٘S[: ۢaQ3<wu&{Yd&Ud_K拚1fmoq,15vb0&1SC^Ůleve5oVOH-}SOxUZJJZ*nE>ulUAD-;΋S狮 DVnԉm*Z\vCs6X w#vyk=,SHR~1vW0-Ŋ9q1뤷j'=ڙt܊\9岯gFT>b[m8X XX_a_Όr uXcPsf'I_,r_1z( Ʈ5L f_´]/.V[ZBX#b]W7-ɾj 22>_Xhgw]XlSJF",6ܵXwVJp9<ۦfmX-}]5˰#b-􁛝3r~uV3'NYn ttc8p3'R}bJzft 3ŝ1A}bl;d܊<0B51%jW|;(DynIKe˘)qJ~7nf_L-"fPCqd캐,Rr+m9T4\cmL-ɾn2%O2k2{ W/SUnf؛R:<7ٶa8" ^76tɗ*7|93<ީ;ONbi[}bz ț nW-Ef.^nEo=/jFF`F@>93.lAبtj qf_[❻h'TҭzWh;#sv$W˭ 7\qSC{ۊ=2rK/-AѤ Ip'}b40{WGF̺IvWH%̭{55 : tskLb&@0L$-h ߮ M6 1d>aQff#گrZ: Ƴq=[ au)0u;]a3Y` QC:{3L ?QA?*;kܝEtFov}Ey(n~Upr{ήlpr, !2t-ƹ/llKӐ9W\6=320]_،y=%rH̭ȝ6 p]i #Md$km_mEfm󋫟GK _7dF%mGc~Y ?G3ָ[JKi1ՓEU;<>>0sK 85yR;(Ny0˛7bܞi&Eb:ѹ_P1 UnX̌2NO jrU~v0vsI)͍ueXJ+J05I~qn :RfOd&7 +Oe3;Vqq_)}*ui<,[:4䆕 N?q婧{RU؋-ɓ#) \pcOV;Mf[Ź%La57ʜ>e܊~0U乣l$D_ek_9wWXl'x+sK1&Uc,UHWNb':"YL8܈uFs5XTT_~va]h'E_!|3yAkk536sKwaCK~A i,.sK(}\ryߟVzJL_ )|׮yN6̈́lfS؃-aLlwygLJ@tnIy<1cEc]З:{x܅έ CXkNJf\<"#Tvm3o%+r˗-S{q߱NtnݱW+ma<% !5}nƅK2܈-H),BOVܒ;)>wNʚаZKN7 9Y*"1Ŧ Ƶ#'m;/D~r8}|, Jos?R=Jr:j>c_15kJ<ؗSG;܊#. ]ޖ֖mHLnK%ȉK+G!' m+-jcC|b Xњ* VՑ˧h'`['g]_ؕm*ke~s/Rvܒ<9\%jWl6$aa'dž4')JosGN vnVSѹS;>57R7v9S4؎έ3E^OkHܒLvƹ%g XXrֆt7lݭk3Œ$5vX`K{뺱c߰ftnݫk?p? ѓNV_v* e; ܒ<9v`ac&zE!S_(a,2s+29.]. n'nyl̼I!wEWv.6 ї$f+_ /w=,K&6W*Ϲ>1m|,m(Nb+:" C*Ċf/Z ];s+qf3<1E.;} wu8 їGfʭvH"FR}nIuev_܉-}b׋d)_Q xiyƕp؉-ɨD)ĈNoLi啮v6_0_Kn8ҿu(bh'?_G÷)<#67:b3ӗ/_'ܼ4W%?Z+܊B H6fO&6YXֱBɟ "U6m5(s[?y/CC}I4O[!N- mf;/lF~tuTɞYtpV[ѹ%* /,f;%# K7݆ 01cgbS'vޤ۰Ffn؉ѻxEj9R]j,sK:MZjU j*ܺ^x܍έC4o/e*XDUr+\'3>N[\_*/ : jWNj[n;-ܾ'_dRfTeŘF[ѹmC/ƂTC3tlSt%i,0wsKpmz B[vj;rҒm{ 7"!:ܒOw=c+:˔"6sK|bg2VЫL-杒܎έucZC $34CS,;=ܒ0YNpx9EgWN;9mՋ܌OLdֹ#GP  .a3:R xh؆lץ:撁H*k?,2sKtM> $B++'s3ܒ .}9cWmdmI*H{~#v/YER,s+N:,o\Ntn/UUprƊe-%2/-N8~ `r+0zy쫙nC̽8iZqRV[܇-:_?Yk )AAQŽJu؄έjg;EW]T_K>"s:$b@FUYmJ]s3N2vv}<*zFզ4uvcj  W|[A. w8i^j{ XC"hmÕEʐ̻d/=,2ws+rgC>ȵ]?GG&Z ^7V뢸<0H߅sKX]]o_֨*ג憜Dd4܋έeU_ؗ5ޥYKrT黼χejl kvNa<_ڌ"6vm K| %\;yCNE3)rK&I, < xbag['7,\(KݾyUcg<qba&][nƅrt)24+OmIR%[ٰja5?Pl5#4 X~tn阯ZXdV^jMQL/Hn{ `G`_3R3-9Y_N G;-܊* sf3 G;>6=z14k\eo/8vntnֽ%/Z~,sKn,ԧDN&"?_O*V2кt 0xh?NZbF9ۙ欰;ђI/`'6#'7sNQHe%9[Nk :G;ܒ ^hC)SZ plU(rum@nfRy&tn-jA,@vy{q.<.i;F+-ܒ\#QJ<'qveÀ]zN c8",I|t1.ߤڴg䂱޷[9Xae5gAʯ[Qv㌷cD,[k]#bDy i;._N c':$OΥGÿ١jӆWƆͶ08be5wQ+vɱ꧅6ٕM`fү uF[z[`@^pa< VK\ח3ve=q%h'[*FrH]+F.Uoh&G^D1-Snyo~a<&wsK|škRizGxuH> dlGVbgS5VM+1f_NG;PjlL jW0w#'nQpVi5,jhfqGڽʫh'x-1_%$wۡN ryR0WAȈmúe$TXχkmٕ Ca|3ws+r[edgU79&idn6~nsYK^bCm9ZTƀ=rr ҹcza.^62<1g`dL `%p+[rMիܣzv9,0sK 9_ve9Tp[κrRf'ɓ嬬ͳS;4|qc7hAhf'81_-ȅcoĈ^]~E3 ̍b#cD)Ydg|وv٣wA?1ڙ+ ̈́ZvdsWreWR4\®tn镯\P \_۬h[O V[ҹ%%[^ȎLc8O̐[/n Nvܕj}9$[QpKv-cEe?@U4Bېf&ہ@R](~tc"f;?a SCLGK=2.X?di?\vFʕ6ʓA'(lo]oJd%vc\R|yY8e{=s"{= c{+\,>vtgigjBHk*K=ޓ7zGg (5RʛNG˄!CV`ԤM[W܏{bY2cƽbFָɛNG9ʄ!w $oyUZ }@U8/Me)}Q,wM7'NdJ) ={"r ?Kvc搼Kw=y[q?K9F KOjʻ(7?SueRcO'bu/T0yY?,& a#ϾNG !ESpq*g^n\$6E3Ÿ-w,'oz; 3d Kh [.2""V* @ ;,a&? f f .N]y3NPL @;5 7MZϞNG5\s9+8\*f3Q/G.KO!2!mJ+LЏBqP^#Pۄ^NGP*7(5vu*|BM}c򦿓Q/sn+o+ggQPkJ(|[7=̏:yG"CܰIZ![G}]GL!≠t;g'o:+g!,704W+o;~-ן~T2LME49 ~B&s 7Z}ח7bp"O?k% 4muP}7!ى((c=yȳQ-Snn2k๨Cq1mؕ7ZjyǮ<,1 Xl:QM-sH>fTtG]'{pzM'Y,d \ԗEw9 E1vɛNGvݹWs+IEH* u;)~!G!x &y; o:Q,|lwp-wgwp^X`OI$v\N0tG c>򦿓I1,~b\LN.N>z8$sC@𦿓I!js[(֕7~(ȝ?=z&9[s]hΌ?;:Tnr)m+$Mg(uw]yI$L[_ _I(u〼Qr9\xח7O VL<%9^y O V7otR~IIgEn)g<#;{* `7aeq?Len2#r1uٴ!ONQ]ɛN'Yr8ؕE(us0119 }qH>d:f[؎/o+{X$n%YXudatsF3;z74ɟn븓7<>w}y_?)8$_x8(A]+ ;n >=[`瞼~SQ;iB=yY?0ъWoJ\;9uw?8$Г@w}y_?Oʫ(֗@~Ht{0qTް# :;4n;sb25_"TM$tp\Uo̘<껾n/<:c%X>\򦿓Vck'}OFiOO绾~nz]_w?ii_?8$2fs˛N'G0׊h/o;ɟro$";Q)!y73껾$Rʹq@]jݑ$׻l"da%K߰N~w#wFn-绾Igs㐼;Eu֗7̍2NBïWdeS'LD|]7w_Qrf2n˗^}qH>@Wϋ<ȩI&~7TrFag?*8$oǝ| C$nq@Jv~"N'cɥ:|Ergؗ7#5ɟ$Vnxg~ /o+r$rdد;1E/ ~+򖪓z5tWO2(7 <bvf%׾Mg(rm+o;ɟJޓy /Yo'T*qH1 9.<<~˛N'd__%EY˛N'A䏂"7 lEwuxcח7O"7Kʛ Q׃? 08&X]y $q\;MVuMwE(k 'u'S[xVmn}y_s n]E<:IBƹg`_DNO7^GΎ ڶ)3~$V@F"?_x#Ǿ<'FflmYrʛN'`LЃ5*(鬸(ebQ(q΍= OJ7 5V+~,9Hܻ"T0΍̰"7V VodwJE#,7lo;f&TčCxUw_xvy˛Q*"~;y;wy5>nc;9›ÍC2:zN'oz;o?g_Aq2؃%QU؏Z 7 (J\X'Mo'VK/)?!'X(9u'QCjimxrT֗7Or7]_|J䏒Uh_KYp|:=y[qk b悖ߠw#IQ ;*6~Qe9Z  =y[?I9a'?Uyx#;* .gd9!1g\?`7ڝ{r7ܻz`tWUoUHޓ7OuebU7pVXSۍ:7?Hԏ%obYzhAnoo:}0 9pnٕEvcaF.7*ߺ}f* $Ƴ|bܽi[sՓMc`ܧq4Lޣz| |ޱas3T[Z='jr TUGOyG?ttb?ՅcKa~~,~rc蝱#𦻓pC!W:8ԕ7ce? O3ƸԠR5SWOoia O2n=y[??5S!2uWQ=ܣ>3 Kś~N觲queT, T<0~uMwI\! +5Rʻ1 |_ÕfS_ ًMa֕0j C{ⱑvЭ#o:;z' ,ZZWVXeG cAzr^̷o"ϋR'tsB?۾Q(&O/׍;{2,>a< N } ADr]_WdsKrLSsv+ ;Ȉ͝Zrŗ_n]{ޱuܰ#q (RI5neǻ<:V@q}ӏ7]~J.`-!ZtjK/wM_' 0Sl\ۻz1o!\ۯɈVYzeFXņ  9VuD |luws+pp-M=y3LX~nŝP%܁y_#N("AGQǔuw,,%6F.v獛hϭCgbPk_ɝz3;;x&7NJ;ZV[r1x3L8~nz-*&o3i]WtWdskVd~|jg2nzd]#s8Fl"Om3(f#hm/Ds+h6o>3ɗۏ>Py8WW7sKp\1f q+o;ɈVdrً-2u(29a'퍼^w$OUK{Kc܊8$ox()[F/o;Vdq&={cWfcs[cnֽ!hBH MURjIDD?.u|dĹw+_C_#}߽=/ _I6+xVfꚞ6dž0z|7jx}?_Wx^[ǚAb982g(wӜm= o>EF 2瓈z9ןWփο|ӻ~w/MB{k}~s|@\ e{z -ƛlo7q4y,\󂺇Ox-b;5h,;u;98ex6y5|K[хRyg˩0"^/ &TЛ_@wda#2y!2[v,Wp$zedkFD7*R2iz&N‚# m c0h{F;5!BDG"2d|LLLLbf,F6k=B|d<.<*{2ˬ%d7f ʏ,?ʘ%BO6@YfEx[o#C3/,(?#cA zD<Ѕ,hTU1\:zfG3vBG"4xeE{ [P634zwȖٖO‚# m|*?L"3~d_^? "X$Jޙo,ɖ.>|:q+lC.zz*$f TZkfcS!v5}#ͭWv7w7 Co˰r2_ (hm L?{lZSGž~[ltm၈fJb*x^#3K/|M H[H{ִ ]G"ſ;|QU<# O?,k}Ã/"ȍ^ 0fnOpO+7Y6t"H@9C\7oXQL6L#Jw=Y˃_ j=q{:D_(%Vdm1d F22dVVierp'q*y>,y@~dU؊d{܊d+@x$[ӐUbku3xw{_`Mžj]m"= H7!J›Kv%u1>0MSG[ R]m񾺿gM3rȶ?meEvt)Lw1MVKvm˅:GŲLQ.r d 3Xi b9cլ5b-*rg(dn>g Cu->%uַ*_Tpȫ jΉBQV8?`"]PH[TЩ:#P,҉_k"#w8NxބOS{5 O=Q$ISDͳ_kB׃Ep^KS?rC87,@56Ȯ 5QV4>[zpnCҏ*9(W#(_@Yg>u_G;e-̍٦]knaK9lFkr 0wu5p߹x.ٮ/.?FK\K+hwyX=]duw_?6Ɠuppus~h}thyۃ4w{`fN jc*V=~~~~W~a/6^ho}2kxIٳqo>KXC\/j˫ 3=ˠ>uV$贜W|2LWea?eGǤ'ύ W횼ڼӵ#}'؞?Wq-`cjۉg~Z tc uJN\DmuROԃ Qɇugϩ2]tG&mTekT~IkmvY$kh:s KŤS8'dN_Sk?x~~qݿ< vldEOŇR[7VK2y:`8}e}-{|ƜG"#h>թ߯]._V&]]k>:p{v_Xy`]4a{@ ]߄W/[`8|N0]^ٖwgg>eR3׉)LiaQզ>9|@ftǧX;.V{|WvOw >Y 3}P8 WcZnf>]AmM?ҵW 8@+hbq=~lg:2wgG9Vw&+/'㽧ij${j96G>g{m{RYb{xXN=Wo:ٚ&'d 57hkyJ)|/ Λg #iI|ZgcO`_3}r#Y""cwow;v㯺,KU!׸oxO:/M\ GaT*Yּ@<#Bi5<>[ښrLͥ/YrzkV"~cjCq=4 p\/o^z׭o2m;8Ǟޙֹ ?[7'ѹnkf!o>Sy沫p _?q=u@W~xt}B>)>NPLxOi?ym}{^:pzab|~y~nGov8y*xzk^bC o^T𱢮WO8 ;9Tfu2|Ǽhh7 90s-N6 rي*`#BQʿ0ubďw$`&- u6(Vmy58H7Iba*[ai^2Ư-G9r+ix}46>YͧdS(- R5Yު*w(rZ3j#5: X, e+ b_00hK3RܧS\ ȖP2ʩ?t*hč."01hB/"1Z1f߱60*ЪfRt(mZ.,tˍ-Sk_+v:YemlC91; ~uT Nي*Np(Y 3ob?hŭ&PfdgKb]5W|bVEry5 k容,V1RS$q+6ngk躉^٭2Gy(FKpbO嵲(?W dc- ~q5,EG㌺,5^i{ي+ 'ؑD!k=΃7t4^< ^6dْ+J?m q_&]9FhtH4VP"E}ݐ-wݾthe|La@EKJ]iF-/NpP(Ul,S1V ߖ?G*'/ vv+].8 X$dK ҄B{'ݜP_}4.ĭV4M@vBSg^W e}6ߟGDpD*qd.ԕ<;4\񭗦St5cp[}Ebc,4C|W0oǭ'z \TVi\삷7[Χ dch:E'o kW_ىa`cOΨ0\[r._0.fÜxV;hjF'o O1]>6e߲%)կM$zUۢNO9͸1sycToӅz҆~:1y35z PT~V܆iYܾyԹ37cWh>ϕ\lwQratj?EjpmZNq<r؏TFaU b_^6$U >yѕV8 }?PD#ܥ_6*[P62HeK]14AnD?>G΋zp>yAn=-ȂO'._T ~G|Kb/_R4*7O1wZ/'˭u1&4]?oEw`u0g/; XlV؎9)[n7 }N;ݲ&~SE'Qaa3~{TtÃrEgQ V tNv57N,V4?ځWJ?OAALgu, ~\#[<ŕ//Vu F뇗;k)}''ܒ:v'h|"J8&;v Ͱ ''h|V Y5[r B7T1ABe~Y8m Ҕ^l-Q>^1j?8cCV;θ&văvq`>g0 }*F6!2hvMeY8%@ϖƚ3]M|HPʋy~Blt gKl.kO[ J(tg+,,CWՓ%vC)dkGEqk>E/˰|z(EGi؉QFk;p0Nal  .멽OOQTݨ Д >1l ,r7C\u0Ĩetg+,ICֱ l؆!ڄa^fTtg]vvrۮHX;n1N6l=s8([>v>g'wlV.^>c=8 ֻVkpgK&vZuJG>,Ӄ ; gx|v&t&{VuYr368 X%cKv ZN&m7_hyiEp"1' _=^9 y,q7: LD&iU|jd'eZ|*%գJƘL4%JVJltlmzL%/rq Pqk:E'p|zh UɃTq f3eNlm%?9YrSS*z\%CKSS#' `^=7qcG 4s`t, ̎!>=&M毨՟ rp[y#^؄R Np$IG==L_`+;Xvbp62xTOL_ܔE >[Ԩzvb=aXjz؎]k2-K|WiK؎v, wtMΩ~wU؎~hNE' |j}jNyð{ك ,MdcVXnn]Akb(o^MS*T%CKRmK.<7䯄ft]@a-1g[288Pu0'$4\OK"-XoCu-+f|*b٪1 tbgѐzѷ op g+&1;rykV."ْ%RXw*6.!'$6Vwb1/ϗ5XyN2-+ z6[x *8xݙ4؎ͺK"c;pGw  +v|0Uf2?=14@E=[RXNq>OR+:2Q>6lUSW +ހݠHV16Y4E=[rQvC/`^ucs/@!Gl.٢<x0'N@5{Fca~*ٲL y /k)\*?@6 /oG$"cI%Lrp4?޿BMe=[Qʋ5 Dm]~v`t+CI"-dm6"K'6+K(!1KCl."5n8.^5FʊT|9 L޳%FU)p'jI^ךQ1|N>oq :}yNM2Pii ^5^椀}>F޳%8 k 8qӱԤFB),"[Q2jTͦ:1mT@0gյ*ي-M O*aKePesxϖ\7N('&8f @VLE=[aQ]zz A\òTݬRɦ2-1Hӌ vtG'916Qx Tbj9oE "-Y.Myȍ GP_c]axDpEJTҙ{UEE(%p)Q s1og YB5BNkt JֱӃ8UM~89nV@uS& `D1]@ v1t&\RN=0?]'\T@E5`|o೓NR+d {TVC`aG/KqdhuArlS_$b/sd/+dpQ&=0̽p`#Úq:'cGRm&YQ={b8=Tm-SY5JQ^KJ%Zr=c85̍qT0radcŒn]B^-WqNA*9TFTȵȄk]4.`b((;.esS1|Bu\NfTR*\7a3QI ֎1.$`^HRdQjn"feX;mpҌV؉ÆUHl(1jȁ1>x \'$Kq2V{*) U0'N6V $vbT}fb9n<?.5 aB@灈 [:yy+[!?lr4fUaay y=9 ֎G#6: XJTl#`!DFPc"@Ԅ>!l,[J<"ZQ0rg+uYV΢xK 8 X%9CIHyp1Fqy^6!lo-T6M0'M%pV܆g#s ތk'PD%#:, }ϠJsLN=4e >[a;F85[Ǟ㌂ĢdCشBDR][qǦ2 =SbЁA$Pϖԓu딶VkF2aYHN6hz 1rq6 )3Y?&bATͦU(}dJ_ԉȍ^uي;Xz5q;Ob[L]2mjBE/{1-v$naɋ 3SW,܇a 9T%#;,AI(7' OnBQPI"s6ͩޢJ)ގ'z\%C;,B niA!KuQ~|*ي1>ǥ)屟UҸ ܕKP gKnc{mS3yC(gIz (1͍ UԨ4[ `OKyD%ԃ:@ }T*ZcJPy+H g+4J_i_RnqEH>[r=RNP>bj :2$-رoORV9׈O$.Ff؏D:bO%4,ď]16QP*ecbˣ⎧cSVԁR658U~&#6pgKGx| Z*D<Ƙ+jޟdcVعŕpi]LĔEL>[b=caU 2Wr2A%pϖܛZ/T%rkџ[Qg|lɊ*ƭ)UBJc6i\v8PD%T#@*ik9,&TpxbELYu*1L`>O]:I`"XJ`;n/3Xodw쭹,+H&(RiT_lIKy=|uй$7zܟ'=K׊|TYʴIHJyyY,IIgK4M"?1[urNl]Kƃ> ؎eڊԡ$l.يK͸M4 ĕT.%pֹReyӳr&]ĕE`"BFG)]&Xb3S^N6l]H ؑJ''=1L^^ǹ|"^lA!Ur_^m2- R;QQHW:1̧ ܋A%p1* S_eؖ'<| يI՜J(ivaxb+hDl>6lI]!UҰit @2S^^lJBx=uR߃/2-SC>6D{s:vbE,>[auxG%!]xbb;w:4E8>[rkRAF)M03{CauD/x|⊢+c> ؆Qf(zjR`|.ƭ91U01f y.dcϖ)<䣊c&7qSK9[qEKǍ*M9tAȃ$`ϖXAΣ ;QyK00xd/p|⊂\Y)M`2얎v,TO֡u 3gŘ|vyFD|V]JIF>4(E0>[rE9p=ࣂqu0Km g/wl] b>2q2N{CZ'7zY܃lezG!J_3㳓E4>[bi|R-*IV{ _$`VXAxC.< u23YbM*z\F%wQf}VJS<0d5rR/x|2uU 'gUcYl.ْ(EQ*M831έ*^#@U9Yҡ1lE@~Ψ")7,cdd/|z(Ssꦲ4Uwbbi'@XesV|N aHe&FߚSG",-r<BYa:h7Ddc,ck(sF|,\&TtgKG.dnV9-#t{{I".-mb1Jb'F9:(f.kN24 7TCTrZl˓({K"8-:M ~*ԉAf2m$ 4gsc?C/MJ+oCwFvXAo(B Z'7Tܰ|jPտ8㫿@Rzf][cKr~뀊˯Lr iB1ƵE~xmmN;4|gZB];wYykDs- r_.O@ne~OQ4KU S=ëoȏU8ʫ O.9amD#ZRNeo~<~M5S5?XfQ%r^\b1f޿XƪݻbQ1gɏi-vFfjspC:%bNeמ]ObCI@A*'UcūZWi'&@J1rv !ZEG≾v]j7UWvYaդ\T5CgʀS'mY'vHљg51X`MV<>pjkfNցzWζ*0bΆ5={e]_~UoGclm^!V&g)6ʡdҬ{δr"h-g8Xs[y} ˡf"*;lW Kk8m:f~9fט[F]wu^v UBg"wީ4/x+C3gxR|'/I~x29x@XOmZk@PF^?tϿ~,}Y}MXg~:7{͵ ?P!,n.%mt?+?G~&AsS,ہϿ~߯ϑ ҵNJ]\VCҭmOp*8פ񠲞S:S;~sʩ 7)ϳ̚vNPvjn]F͢*K^-7]#&F q:5ܸO _9 /נ08xU!p;~' k{^ V*ΏcӘ`}G/r>jpigsD~lU[]TnˊjLe+L.PcWy޳FI"/[RWߐ˴d:nhKo]bY ;X&e+$R#v-6@E*^N ]RȀjPAn]5b{E:^VHr<ܼX8D'tlАio A[m^u:qn*U]+ C yKKD\lEzK 1A]EbY*7{ \ m0c%5Va_*${zD$eKf8!wĊe6^hhƊK^%bfSV\un$A;8иW!k2/[rջ҄ȽjhPK"/[q;̹4 T= ztDdlIEߚ@RRbA\^K(-Aes\A *ЗWE:^B\ Dq7y 'u|f2/[q9Ir2{Ԑ{!,̳%vunjNAߠ/$` 神Ti PWaGr˖XSi リ3֌I"/[aշ')H Iܰ%V g"/!B!TPA'z?N]K"%/[qյ!Cb3uV{&3=.ss@#*W1mKb/;s%yr+|4i sU1ͪ;GlI]}[/_0y*zM/'luUe m8(zeF^s] KK"viItI漼.2%wIT5 3PC}0V ^6yيqf$S.%q;XTLah\=kYJ7K &\jMG@"/[QկU(拊Ć;@>%&l.%rV7`t0 ri}LVTj>UJwi,| VWfa/YEi3mtPrU 봒i6f5>h5s@^wْz;压֐K*x\e+zɆJX%ŵ*uHZjSwSZ 0 2/[bWnM(M!ש[/bPK"/[qND%ǵd.%p-PSV䒖[;kil.wb.]rIKذځ*um'|lIT!NY" E*:X[rW熦$:&n3^~*g+zu׉ڗm(r:cE'|Rava)7Im7(;?u|duͨF)BKmQ*MxT%uul $z:B5lO줏}+,x \ l08!Ꙓh?i*nDx>[aճgKԸ3nץ}l*ْ*iT%7bg~o}_rE"4rMɕĖ8Q;RG.$//|kqTD˜!\CW2vg+]^kЎ*!_c׻&StgKY']/iFCX~k6E'˨|ªov\lrGET>[~fKsLjuzCNuFowJ>'>_'ˆ,' 6`)=tvG%S(ݘ"7&9vI;)TD\\KNn4na]D<6݇5f2-gKP zȲ={>_># Tyȱ2]Gǧ~O\c%W86i/4p<2e=[1/(ݜNE7w%.ي+ٽ.SV'3w'>c΢e=[b0Oy &7kg+lH##}]~E#K)ma|ϖX ;W9X޳V}+K1}c욟~hJE'{Į--;@ցLS-AW&X5F۪^Nl]=[nRC<]KvsiZ Nl }#+d#3v_"dye=[b%xO"~<c|*BيZ>(uBo/ esX\⩐S^|`grY"U޳%Kgmi-s0!ְ7Ng]K"-ꜥM;bf[qٹY/p<aF25@EL>[RWߖ'Wa .rtTD#f b`6٣[aչ[SP\7 K28 X%}1JQU%iUG﫨dž2.egMbbQ+Nm[Y!Sֹo>WZ񼛽lʜ"#Ӈ!7~+ɥ# |&up|d~ M&Vv򛣕W=ـ_R3NlUR u;nZQrS)z \%)/uh6AS(W>6lTϺ&SdW\Z,8穹}*bْz֖Uhzt~j:E/Ǵh-8!Wl+$3ZeL;>OM# VTui2A0sIXܸ?Kd򻟍.bْF,]L~1J=!)3 # :v3&YҤ7` q^R^lUߪ4lzbɢq|lOHiKtĴ*+63(vE֩E a( U:<%.يK4uY^N6l]|>Nj$xBng+nS" VEU$೏@E>[Rշ {K4TucS[ob^6lŭ;y܆<Ž~o*$`ϖ؛,w r!_U7nKO/'H|¶;F,0JU,Нz_5#D Gk#N)$0ϖXv/_ȑ*rVSNdž2 -Y;t֙bbwRÍNalw쪂S﫦S g+ܩS]Up٪³E>[rcȽSzU%)4!ZXD)bg̰*~\*֡%+>j gKL;JhO{Z3SURʻX/U_^يmUoKƥBrE >[bW4]R /TT>W]u>flp g+ .VcV-\fh~-$`ֱoK[jyw EX"Yk<+DCSyI`"-3N`rUrKsxV\unI^I ̯p9U)eq/Fw)p]rN+nK1//|亶-ҧHaU`ҧao:5@E>[RWŽaUՀCqtg+ӧ-oN* ņOM%pV\un| L*WR׹'wG/(|ށ;ߪʴЗNnP4IEHVwʭ:?$h$ْ:vkFεUn܊_^6lU窦Tk)ת⢔LlU:"- JnRU G4op g+lT-0ߪ~)VVTgh]=[wky?C /l/^֝IEdS[}y\%WcA | Zq3jI""\4fŹEAúHd^leP>[aΦ2lgݐpUqsGKڱK"*-1sP+e kVE/|⎝MEdUV6]Si^^6WdK)afS+M&\U2ij/'|ªsC:aUT7T=c緒jtxxډT ^wʵضFͰ%("ي~Mͧk"#VJIk:KI".-oʴ>wYy5@22ԓiS}wUŭ@*RNl]}Ix'ZU+fō0IF'SRʘ\UqJa2v^dp>[r˱Rsn[R=޲G"2Z,.Q)ˆORN6lU׆&[v ֛ NqlE-;sؖ($'w!$`ϖշ*9N &W5(Ksѹe g+:S ӋN_V?}( GLj9Z ƾ\!j1ϖկ"L3]JW|Tj0D^maܢ;BC&//|;i \.yUjsso{%l.ي-_W.޹U /Vԯ<`IG/|NY!}\ nV9%P)Bdj^p3.:7v TKU^ހ 3.]0: |B֝9EhGnVU;#2&- J+ygXQJ*%pV\|r=aՠnU gKN:|+V`%5VR^>oيɞ wUۤ=zMp|c咬k4nxiԏ; >l.ي[0< ";ŪNi+wh>E'x|ªsKEwUǍDl."n4fbJ}9 Lv*bgʱ~qy-=~kFE'lU߆#̲<`${Z3=VPlNm0 )E,>[Bx}Π=ʱK[ɧ\LK"Z5 dա)oN2~ 1?5e8>[rW&Ըp.IT44.يvJHaU凊OV܃9Ǧ2-o>seEgnPy|Ճ>Yw2-[uLS)DD%t85hJlq< > {l^6lU"h8l03~): X/)5e[QdSg94,ϙlq< s> όa&PJ1蔠連>ͅ# N*)ϪpLg {\W}ʴ>q3Ӱg5@E>[RWߪ&}3 ?P>:򱩌g+j߉TΔki˜yu5T߳%usfZu x*9g+hAbx!Ӫj`r gKl9WNyVI/<~7rpg+j)??mgs|ţZ4dݚNLiVSEbl{)z P߳cU*4{"_=zUͧ$`ϖ9` Lbg~|#$, [pR5kJ|̋ OI"-)T.*R?:ksPv4m׼zOz-;memwrz<]E2*/{.(„U;:?4}m(b=Ӥ/jǶ,I@y۬&M˷E:L;>ڮXN5/Xjs]_s_ Vc,܍&S-VgN,/'DkעbuR^Wϟ?40|8?U\Y ss遱εb{^G ̌}.g]>y- lDp3[M]xo+~&bߪ.fvpd@ġ;=[y`;O?Tg⪅ ~25J u9Bh(GhiiG?~mXT-傾5&fF:8P]z:<1/]Vt?_?[̏ąQX@ڶ=4vc-ٻ[' 5~[cˎVS}w?]ѷɱ_<{bO<#(ݚe_ o~~|,gu&`1֑݀aWAɹq:6>܏l=G(,:mmrjqn%Q"ruWz(aVbbIKec/>03*k]X˩ivL,V؎1h,l $6 [twwXòjP>jv,ɖpw?` ǸV3S>[kuWŎ@pc)e/KZɖ]*] l*DHMm,sRb${\fdK..~_oE^Ny+ ;0@b؎aƞòLdo{arN!톨kFL*kjܜFu.R>>1/&[M©IF89pc$3"0qւ!W(p 4y VtnkhȊɖr+Z 45"-X [rΝBw۔-.[9R;%'ƏRo瞺Ŋo4!ljW8 eЉSW*wrmV؎3MIEWgX*]Hɨ F0GuaUlK!Fmm}V`GʸCLCE!.%T/ɟGn-[yUd/0-XU%e.-jX`ٰ|cP8q:Ox8 Xe+k1NvY2_1#ɦ2,[Ry |iGN_'3+zy F)߸N(~\w,pyE|M>Ba6Nc=fy7F`o&'lE;UY؎ayF(Q[#$\aPfT0ya$,#y^'de>}PYs䤀u'b;n):X4D#& שo1o*#TUl2HeK? wb8 \ (%%>1W|mKgG.q>xW]Ǧ270[6<7(bK/㲘U4H6db>.ca+ƸK.!X:} ɵ?|4Nr`܊YpFf??}G+J7<w( (DBufK *h&>OqYNf1{ \fK?Vw%3'NT.pa\Uu4[OkX^؉pl'0׃P; -5fŚ0atXV؉AVD2 <ѓiJHEN ַK^!^:$@0O|mx P6Vm&<4~e <6<'7WJݨG.~%wQz?vFaMHF/lG!Fe2KÝ)Xё.=sSuq[rR> kaR7e!`0(K(oCɔKb7[q(dX9Q ~饯jofry6[gv<~-WNX*6HZc.sU#B\I,@>a7[iAO(=R(ߥv;.l ]A8GjG K5; 3ѿ_ yuRXz9 =o[u炘DYcC#}FBM|A;b1; XfKf'o!c=lIowd;7"3QZ\l◦=xv38b@)-CVq,e W~%wQ:O)g[ Y/K—/)v䐊8)%^^)SƐqn,Rb]o?ܾCSL%zA:&:Yظ웭;rM( l5eU\bK%p4-#R,]e%&ݰΝ?.3ʅm0`Kc(.E/K\͖]mV$#7v)F!|^+ْ(|pC@X FʵlE%V}.Krٝ;T|:樫?¹%鶗F?HIn] KǾaw\nt[>8|VÂ@Ģo}뒟n{]詍O=L1$ ?bzb FO\ ǩk 8o?}07KyL+܏:/]Ib7[N :T>=6什dhCɦr7[R/b[$Oc_p3+]Ici_\K 9ŏP"JUQ%@񼒭ڧz{2ǐ`C6 3;XfK?7NuS {IV¿,҅N ćىGϑ*%R -f'KX͖]nu{kH c.Uaއl.|%D2]V |' bC.|rgJ^ҷ\//.WEwpB.s/<–m2I~e U}|j.bΩ>E/˥lŭ0QXx*ޫMi%p- aqN}a,K* .e rv?OA)S]G;rҨيŰ%jE%7ì{psC WÖ\,T.gNÈQvb%Z:Pq9c&C= .˿ي0WԟU>GNS S=>6 ْ*u˖-xS魕Je %>\ĩX,г`(멾>a7[ uPP'˘fTVS}T,fK?dB'VSʺ-˥Xzy #j5 )V~zcMew ٲSb8)kI4*Z Ub/lEUKJ`LE@DV^6ْO!Ff2=Ukr^RT;ʡ ?8Y'0x[ւ1ov.9qZD^ WUjaiB AF(RLnIAREVNv'-aJxB"cTuѥzc% O!ViH|^ FK\OGX͖=Ʃ'F6ld'Q`dc𛭰Cp~ǓAd+/t钞܂Kbu6[r pPjӉYѼ,6f}c|MznqYMRZXzx|egqǾpsB@e+dڗ=\͖\ܹԸauC%kljANvrXVԁzYCq*d-#Ο3Se=XMJªV¤¸//K\͖]gL]rUjPNpW"+㾜,e!Cݝ(iXQ(%i5T,fK?jdG['(4V;.%IkRezjAڍ(ąlKf]G T(JCPUw_N {uIڕ*yHȉZ5J|:8T:al[zr! 6{bd O橪?rP#oѥFO:l٧ m&e.z 簝Pjk-i{yau*zٝZp?&bX)BbkjabQe>P,gK?2bU\]ljYLjk^//l6u*ƸG J_k^O' \C]';'&PeiC\ΖZKr )`룏@pTuKdYjJM-IVkbd#Y ]1*We%0ig?%D7䣦$6XΖTae0PaŰ{ ݬkIb8[b/VҪ:*haT'jF']mWoV>ZT`4%#fsjO*VC.g܊jpX͖L!C=-,uv$4J-5?OcrfcI`SaXzy ̬|kWDZ 2ͅl!`90BYhI]AjpyɨG1E/lg!;4Eޫ~\V\ԑf-x:YDCKaftN^gy"Uj  -I{j`%tkٲCb`RurnHJ*)XV\RK$-ZN6O@,fXdo7. Y+:}3HijU @f[ O)^^BwƬ?XF )W 3t4\͖\`A0pk.@f\Τ48ow=0"Y` y7 񑥑WUuуuܟNyU ئ)bgFet:%l'`=0bY3r\I"L͘$0p $k[u[+uǬ:{Gb6[B!@zs-HY+$ Kv-˫w@c [f%l'SUW?\Q\~̵d،X|(zPԁD.v $ņWu !z \,fKncK+yaol7Jv8z g_=1dHrQ Z*kSpUl%aE0`e"Q\LC]^ْ(Sׂ[1+LWrI_<;V^^PcɒU:N A'u3^v-;?eX跪dA. X4Y ! Qե#@֡eU0PŊYURielz7cJf0: X,g+lUm㣑{{sO*F/R ſB $e!㵤]%.g.JݸyqJPralz7/%%p-ͥ q WBCt1E3BbC.Ml:PgpygѪI_.ho^us)/GX Ζ>픖)8fbE~1dK?2cY/vuooFfk`6֝˜.c؃W 5k`c%,Mp>1\";%t kٲSEq0r+x/Mbɼ >fl ,)u/ch4xϓes\-݊[!FT.'j6?3ˁ}e1~is?Q+Q+ zp?V-uhP1oʅɎn6 <0:Uem0X sݛ)]EƱ&(Su솏q^1̾Nbs KXvyXb̽O8g02 =šp?\*yJ,ŖK n6kْ{N,Bt U.0Δ0nXF';~ܭխ׎u2'؛O87K1զ~;<8`8nE/t,>dvͅVҿOl(;# 78!y1Rq+[+@50|tƼq˹mL\=aخh! Dzk n s@ql}Z!i/.BNWR@Kb? ػ V0v S>޵QL9?8`?W9vJ{of]d1EVij]oU5nwe#wٷ*U/5w;^-]o5P܇Ķ_҅V_r7e33Vtnk|EV0s@n#T dj{|5k bfS% Uf`3KB2W|Z[{V/Q=P$5U;M{a&)g;-]oA{,nj~1n=tHm|\Y4UKh~)kx-[юMm{>~rׯbV+/Sm:|V.aȽIJ)%j/K/m׃:W: or߈=\Onh#$7s u7%%mw3-]ox{{K~[Ay6ٵ29勁"/42s0@YG)_4w˘9dV+5\&nl_sKrۙ=变jȻ[<3Sk}v ڗPI/~-D V.跂kCt,cE~M":[i!\ʵ~5 :Z|=TV/.fV,QsǑEjȻ~a)m#pȅ_- _ۿ^h,Q*%غmZn~+41 <6aEs[Q̉d^˜YsRX.K9wKh~#) [TMЌR+OY{~тWٮ] ؆DFjƂ*u(jhɦ~'J 6Rk[٫.7Z a^%;ПA* J D ~ A^= Rd싢FWx7ua_=c26MN7h{|Yb_ |؟{_f.7Tw }lwQ5m\>Qc ]o$PJpQZ ^Thƻ R`l( <}7bHehiׇoŐP/ .qׯn~V!Ի>O'^QZqWp kO|q{ԅFT(P6l㉍ yzdZLI;UԓYCkŀdz O\D'fbH7.{5Va+yPO,lj~VY [Wz؟AR҈pmNwVOAH%l-  HQ2>(Hɦ~')! z|ՌWCɏǾ3c'T45tAQg^GRU^6;MG߀'65=B (ǃwc .}5VaxP2',3ں_f|􍧙yOfl_0QxP- G,jȻ~$U;M]o.AE8ws_^D VGaW;^-]o-P.m3~ԅFew2 7Ky:R ۺP<(-TPՐw[N+/whE<(* CX-Րw[:pھjȻ~'yo`O\ ԙ;JQՐw[Rp̋* U+ ]oD-.7  B:2UCm%[]HYػ<_OllK~#$l;W yuaExP=p!S[yUCm;HKdٞؐFApG|әyBԫ! rAB;1Z yz د=z"| S#óH d߳*R?uD_RAlZb :1:Xz\Oj{|,]xu!.W_m<|0w`YlG\= ]uű*V6n&l_5օ:U{DUI 73P^}cŷΆ+E_xtA#8jK~W(\aPeb\k>W yU/ Gbf=O/M%G2vE~[A`:JT{5Va+(rЁz'5$P)[עTQ.>;p.Q+u}[=B*Ojюo˰Vb_acvǢ欩An\[Cn~Su=@6'h!jt\t-S]S:Jn_ԅ,z,v,jpEϐeH+@RhƫUI p @'"&kWMx5r)Y`Z1KPQXza&^U7v_ԅfyBm[Toɦ~WUq*JuC޿[ߔ@@V}4Hv[_@Q=}d޿-stM{n~S;C=Et6tf*wUE]MQá(/g\JzhƻMMԊK\:Z}_Ta/cof?(^QoıR&`>n_~zRK6 7X'؈w3򿈪#F'MMT4:U2zmQ D=cG.75#cA)|P#@9X6By_4=:~WqqSJܳ_ԅ ,ukԹ)j~W:~amWybW: ԯJA?@R' YQوw3ZX5qnOL/fji_wb,?}75Ñ2 ^jų"2-&ե)s|۹MFB,"@EǟN?iْ*ũ"5=:2-Xis|nֻ!.,);e;MlRvlSٿ"-(NX᫳9v.(B`Rmx5TPs&e"-񁶥5rE+d1\AdmxrQu( sŬ>ngKl8V:{XOf.*# qRH1H(?DA?7>t2-&=ѿjū`zż>95&#ْݻD3feQLlŻ @zn3'.RZjb"-}|ASCe=W[ē&Jjǻ (zĒԐe=[bű}.9Q735t11'Imx gKd@ycS7W!0FVg3Cb?1Gd<[2C$fLx΢"~-P[_EgЕ.jǫ yhjoOjy# g lX<-,(v`U3-l3-_~BxR{&ze~2C_cg dDI{ nѯE+lI D5S,*~Gq,E/W81DC&x`S' 0j""v-#o/-,^Ѳ{w\{0z-,F6pU3-]Pϳ%>LVl3L f6"_#$μ&~]1xsQ7YV~Rc;^6qlz`ۃ:1G@&"7S_d00x5s6ϖPA=S'ʸyB*J,P1r0r-X>KIv~ՌwKe<[@'o։sd%!/{*V ~qsyfDǨX`TngK*!z| ,){?[4TQ7AU_)2޽x5t16ϖLU 2E<[B# Q. y}Ԙ~0t-E`G#4vPA@3Ċ?VU>6g"%/w I"v-EѶr]DM7UXγ%6P;&kb0f[gC%߻3y/^?Cr?~L{Y?:;?\vG9꿗;ߎ?l/1 =C:??pc2ӫ^Vgs|ݵ}+5!mXUb ߡy5ѥu+w>Q?sfMOTuoj[}e@ fjQEL)ka,||)*ϻ >yO>Dwe%\9i{Ko{joEڞ6AҚvzEZmtz7m>[%f|#Ύ}>{Eg쯱}jǟ8_mG皪a>/Fir/J(TvgYF~D;l}>^'|R*b9g}j4>["ϑIѽh5g?/Ǝ|^p} gk}T)V&̏o?m] }_\߰m\ܠyyM2tI'|v?ѱ j/f e5|ϖ+,y⟯O;wgf9ffb7>?{F_`~U#կ\5t]gKf lEO?3!vmXc>mǯ#εF~,evd_$,~|˷MLjGFsY 5S'Τ}}{=s-kik:e{5?#,{a_}|>yk\^wm]uquY| ;|K\n#~Y>yw*ޣVq39xNoK9}u?Y}bZsH*`Y~8O3ڿm&y5G\-ד~aqMW?t+V>[ ]kt=wpw>ϣݣ֛L#%+?,z1'|$WW`7"ӯwP}yR£ZUr*b?gi+{#&'#~g!72ő}R)& vd~Dŷ"7y-p+;7sת3q$[|OVlܾa A#l 2Jp0Dc>˙őŷ"7 }a?fV1𝌍^^K^5]9:xxGy;|eAv\N#l畾ɅKg>Gj|+7XeO`:*g bed|+/Ȭ%irE<5y$[eJ7f}q=Y9~bl`>ˑ"s6rq$p~yU%G]}lG2y G?A沅y6d`R&/_`YlF SEő<+%jva^ɶɣ塾ϛR7Z/XFH۷28r7RlzslG"ߊ{2O ߧ2ˑ2F/ k9=x@ d|+ sžQFuYa#lMVH|<d;L~ p̫dі~x$H~^I׳Ɛ}cק8A&oeI䟬5d Ķe$f?_W!^y?L8jN|9 QǃlG"ߊ/ܔahy<dp{rۗX&se\{\;Vg?o<&dV&G?A z\pzjR&/_`U)`KO?Kdn~9"k{}cfa1̝_7-.KKiG]j'6d@~-"_,֚_x$G~qzyUjmx D.;cYt?_%Mf9#l/ܨb^.f(yH~d~F+ǩV#q$[Vo!vaL56H~^)\[k5#_87 38ඖGߊ*aj (%” #x8>/y__58Xퟶx՞=v(nMK?+ j^k|G.)_JҹZ_g_܁6;'罱_=#cg+΂ȣc _+\YE*lر`kBNma1R|-M.\WeE?GlU-䃵1Ǔ)ng<+zQqcۅj5VxOauFw=ޥϺ_r~;$骿.ywaΒA8tCsQ?l?6#O>+ WE˿^G~~)Z4|}KuxgXou_Thuwܡ¯N#ַhѯSp)@p?2ڦ;&lu=w59kp4?3«G?>c{7ס#chz%_9;zx^Gs4~GbFaK$o_Xn峷o^k'(+Z6N&^U$|;Ο˻B]˹ίiaK-;aӸd zay*p?ŷ{|D=5jmv>/rz/k3>quy8:"~Ofr|˂wb yod+|[N/vM~$m Z–5,2T^ Z.>-d~QJwy`zuXo^ s}F19/ھa/\!s7_.[$9j3|3ϗWMA>m{)n@!eRdrp]X}5~8%8~Guu$𩿬tROzd#<{!tëUÄoR}N,g=[]9{DUl~#ԹxϸOesQg?۵ɫoQq}= v^k OՓx/y ǘ?IX7+u3i펯|0"n_EkB/۾1W'1ݝ˻S~!\WsM=eTșՑi=Eݤvά}bm?[Um~ [9N7s|jJL=!뤇:ϟ?q/_:,wU1=? co^sa|=ܬ`d S.PĹJx]^k(^[O?dazaboǍz F\VLeŎ;ӧ 8xbk(` \,e+0Cͯ mGU/XR7 `eˀ.(\^}9: XSS`A|g!4BĺTd R΅hFO?BjDROv`܎Anu 06R7 V5F=w `( &@Q.۴3 eUG!k } ev"d6_tj-\WkJƹ^&ܓ:ŤS.]5-xVV'#2/E55U dVdOn 2 4j2u#حj]'Q.[vYn^>ZSE fl Մ5-{j}t]MhM_O ]$AS^6tE}_&bdreŻlŝ~ꂪC.M/N;Q4۬ Q5<.q!>FT|r3 X˖d_"O sGsah򐣟MlEnzjj!98@[GSStثR/ Ru1ay;'#Zr0ctwM0-clj?rDC1@ЅjPOP|m`OM&PStݚZ(N$mS tz[rRn6{'%0pټ8}Xu[m1e'1[f{8|Q17\(Dg0[=%Ȟ7geHo5^XK tI-2Lb_@e!'֑c} 0ve+GX0Խkz>4>Rf.[ퟸ1[6zK>0e+cۭU+nuS-U+d0m90VNO cU"w=4z|5uWo|!J3W]L?m10PN!mr4D.Mg:ي<00z0b|KՌn֔ ( \D%rUl \DTctks"24e?[r`)rgneԄrO]BO #ޟCt7ɓ'_X.l >WR0wь~lIhqށ ^H|[Wʰ򱩌g+*W >FDQ,q_La8֑sUdԊ~1lާV'({̢Mf?[qOe !ϸ*&`{wڂ^,Q(>7}a~|M"蟭܅c!Ijb\_~6QlIXޚZVj>)0n!nQl ^3KuyTiMSLuX3쟭ܽϟY(Xbv3yVBM"-/R<ڔׁpkjE'²dU4u%Żn8b/z_n6Al=¡dG0:S\S@F?[<4%4kwGebn6Al n\6{#cޚIwٔJnxΖ\Tijy?1VCK"򟭸BwZ;olWtYMecϖXUyrfO "JGKKRtg+pAT ׾)M+`8!T`;o V{UU&_ٟ@E?['9 1Tō4|MUtxV =>sHdFMhJeqْ*"~'?&V!_04*%s0BK_\x(&4hg{t g+p]Usˣ'RTrT}uO #-2NRp0UZRI>6lE*LVS3jtEF ty伴ϊEsjb+UgK2|^AvQu!u`Vu!E7pW44+Ch\$wnujVE7p{ʾqkVy䄛 kbSn]I&3ޟԋ693g>ׁՔ?lDCjg64&>Rg߻0S;&K70[qƧ< ?wɼؐ[3+`%.rOl.cZMlIѵ0 ROMfsV\UEmj0)&jn7E ;^SԿLI@&PV`nq;ȡuWMy4)7Se?[rQ5#+(~Sj&ܪr2٪ہy)D$wtP4-?l2ي0ԭWLLI-gKM~B*,ȱ:gU t^vܚYK"ΟG*W1ΪhUgxfMAgϖdnMR=1Хkj (Dc;Vpg+.UꡙU"|S.>_FUqb~6qlIlkA6^T5ƍVMe]GWm&ҝ-4HDD!K$w&vg+(w_X(uxxy@fFudpu;4e?[r;ko\&4Oc+u&xS.ֈt-E?8"Z8 K׫LrmDCDŽXj*bڼCQg+ԅ4w@35Tq/ͫ&&-s9<"8+*P1/ [VXڟ܁MCz0:a*~7ۋ+;L% `%X[Nƽ4ʁjsmu_Fe?[q!.}rZ (U) dD%0F~+z`ܪĤ\KF%Ilt g+,꩙u7 t9t%UkXo{,4!u q2*.URkH k=,يKEI9ͺXMvTn6X2X\0&vȖ)f%4YEŬO7KAduY'ƭYU'<5Ɓ.EzB~6YPɊ0Fgѕ%K$:-~0ԙ!sBe[`Lȼͬ1.%0)͔s@$hYtyl%,HZ )\J^V'd̫Jn2E ö1ҽ1XՖO%Ld?,dICkKNT@\P$&姇2 [ JQYXd#@% }UΎ0 ma͕lNEVu%?G̺ODU4X'_CT!igd>F"ou;n65唍hyt8U Jl~tg? XID+ݪ0~u  tX@7J.QW0t1Cӎځѥ,h:J%Yrt}̺F4VǪV)x[y~9DUΩK _ :RdYgi.0hfTtC:}@0,؝$M}c`SW7X3QO S[$YE)(u猋:] u+Rc^~6y)|D+@ nCsjQLۖdjJ/+hmf_Tn9[qi>>O]CKR"Yq'_KmtzEg?h$}XlNMz`ou‡&VEr C}#coe?[bQފchr(@]s 7`wT]Si>5V ҩ 6\&3؟-Ʌ#;.Mo hAt9E7wlxrUsKZJO—'ϖdvk4ק\+uE >q%/ˀĶCT.KKGVg+.[UIri&MJ*fxқrj~6qh)U807̈aV"0,ي1D'j@+UbԵ0^ %x 8u-͓(Un_ g+]|e)u@ <0eq 3/7ς1*oYh%XJ uYRtg1"ǑB-P#SRi5 9KZ g+r |GZ%8sSZG$t~AlI>UϻP ԤOjn e?[qR`>ɭs:4JK*cFUXe ISWSHj/zCt@E?[FȪ}U"/n gK]0>.[ jWͬf^~lE-1V)Ο[dZ5|knE?$QEsBEASLi5_4r 2J*q`:z Tf+0CS-A_J~`]H2-XOp;j^fּ0ʫʕV4F?[jYaYk,#Y3/?$wJ}XODž>ѮYcYM#tǬz,=cbVm.<,B;( b}w\n[, 5\p&_q=w[.4ES+z \DWkOV-N`)Kw#g@_fVtxƩѤP7i5֎93O7.LnhxkW/ʬ10nl-6 փzj%x"ifϖ`bxnOZ8`|p*ي*JլUS 3j z?Pᓬ2i{*f7"mϢIU<[)fS)h1Vߖ#ct;@F?[Ź/]@@믢O 0i$v"QfϖY܆hZ1a.qƺv]@M"蟭 ]?tu dkHA .ْ(|OiPf@<0lɥ'z\WroUi 4i[17S@F?[gwJa :=QS 2NrɌg+294 * ϖdq'ɾ2?ʰ1!-U+ dY5/%AM\h3bk vtgK@̎P F ˷esV\R IBIPW~P3 C/A@F?['oꁡՀw1dYǑBYP#W5l1ڕg9 d(EC V@SsjXCn 5enal ^BIPwXq%oIG7̸ S'IeqF0ƚR07O #-\F2(0ƚi66~6qlE&gB'a U{Sy6F0O G4.H*CͲj&ؑC}B'`񃘭t]M[5l\~C}^&3-Sӫ>C7:rE~0b0.Rhv {]#a@oIn6lkr Zn$ƚy6[t]PO #-d ҩ *w`fc\ M^l—ၕPVo 5l-c)4/?$ =\yb/XH 5lȉn%`V؁!Dymn~db^6y::zzPet7uco6 XDyb|NL( jaf_'W 2X1f5H\n6l >O UBuP$N g<, ۠K6=N)796֐yp^/( YS(=iC1b>B',%Hm:$/*s~'2_G~|72vM{=>Tï^#To\G/.E{j<7{nRvkh"v3~XsՄuב.x_[vZc/ZD* E r,*&q<7{w h]8 JWVdn'/UhH,cKn1y[ʢu_Kcﴗ.r NTIr\j<爿,1KuLV1:.rpD[vpYҨYZx֛j*[ΡbUtWڐP#v.] /Tˆ]4ԐIW M hдQ- V)sn=mȏj]aE<-!J@DUH9mkκZ%3 ֬][V֎]y5/XژDuI;k/ZIlqVyw ,{3RF8{X$e2H6C"*oTFi[ݯZ^_cG^bܟm~Σ#z럿g{T#Wyu,5׳/p9 }F.b<㯟;_:NxxAE?nݯ?}=kiCTϊYQp׸K3f/@L=dɧ4' Z9Ǝ^#KiV:I]#6ޟ/vPs9 Ղ6T(koww/{\#/*:W~[w 7}hr ŻQջK"bu\#OG[c 7y7o^g|~/Mj݁\lyAQ@f?׏5u醫~{+/Ao%]EZ~#ՃCs1= p;{c& jcïG8_RM@h@hg'v{RPj!ْ  JFcI ~%g0Vd>ɧ+j⠆W;k>&3U0[gɧSvgD`bot3GɂVK{H+z \ f+Z=bWrl}4e`B߂R*hrkԏF`ͥn5qv",Uxk=?,lEvBSvx>|4#:7T_Hօ2XtT'`$-qચX.YgEN6 qVȵtJjQir~9ْ |oВwp^~69ي6.Aડ:;ڟ@F`NW  Ws[U`,U'%-k^oA[*tс;El2Y=\*Hײʚ_.ַ(wy ` fKཤeU?pE 芊n6шZpjΥFɪB?Mi*Лa*%xu܂b wO2S eb'nh_ĉ\2VUU[=49qTF`R!%]&0T c &#U ,I;3r=Ǡ,ppL̖`^Kܫ@|+=JP8WHVdvbef0n\s WpL̖\mz-wP^& 'D#*;wYRl+})X&P!-sK頜>@C0kNG?lEv2td 8uWg{ B4@F`{(&tI(~ VNU9eSݐtIi9eNE7ш@g?؉4 UA>q ONU'`;-ɫwC3 Zf[NB ynM̖î0ie;y`Au(Ԯ@Fz`"Q|imeO./72;0[qտ.a@h?ŝ䘢Fr`RR'w=c"E?lE;[d)l_hO UWg-ɫM bj{A1أИ22AupnTu5v=a,f a}T{l PQ#HVdjr5 KtaX#0 ْ vUaUC5 f`Kzn[]t]pr EA^~9ْ:X45S#*knE?SDS5 I/_sZՃ{>;=gKSь3>5ƹK4^%pV\u҄xApU q&Tt g+$`V_'ϖ[9V1 M+D*' O #w;cPBQJA͉n6l!ږDٶ.[.``p4_E:AO c [zJQ l[ģmPWAMuRmlIUʒfʢ@"'1qb`QDJmwD?[b7T .d;k\{SUtg+0F瘺!g,zF` 7BrpUaMo @GesV\uo.> 6M+:O #- k#?jV{w ͝VFj`VI 4MgVdvp }AvsU  M'ϖdHu$ȍQX;W5XSn­gVSHHPX[iLad֐ 0óup -!˝V]1fpg+p9^3 j`[O f?[kxq8 ( 8Vm2BيO; nA/ 7G4BtOI@Ӕ4dQpR ~lEVJ~E%r+NyifE/l]*PT3O<ݳ~,ra?[kjf8n (W4O'uͫ Y'?Ьϥ.Bي5]_?K4dy.%iQhVgKa[2Q6XqZi=v M@$_%3iq=NeV.X!pCS+z Pwgy uӝ A9f$s𲱌gK\ӼZk~W0s7@F?[;]5 =\Fyl2ْzX4/,(MG4bΪyIRgqh ZФ}(~%wRqG9TY`?UW"o;~hbE/{ [sXsf|@[RM"sUlP*Mbu^ki摽l.ي>Nk~4ιʾԂ|7@F?$Rkylz A0ag+nY^R Neo>gϖ,t\wXaǭ!hsT DD?[!ٵ(dQWXc}]WE*z\~"a Cf?[aN"׃2;K|ᥚ/-%bT_ݯΠ$G-gV([ܯΥsWEMM;[rտ5zo  Fyg+W4 {xX]x@|kt gKp=vf_oA\l\O # 9.ݝ5 jP5 FT#QJ884,M&@ϖVpfX5e~ ykݪM=0[?Vs4JnĞ | 9/ƙ9NMQ4,(2يamrSs6!&3ԟ-ɫS򞗿 \WNW&#ԟuyr.Xټ{spgK/$ )lF U^(!]&#Qչ%*zWA]V\K8\O0[UY^ 3g D;x8&3ڟ-ɫUqidzAFPx)G?x$v|dSc;90 C+dFމ^ ׊d(5jpDptg+n> Su F?$ky|4a>fuNVaV5..XM#-.~TbK5yE?Ghm;NjX$") l0 #: T%xn׏>6ql*r 2ي;Hp԰#)AЯS&aϖq /p畒&n .У\DcUG9${Q5rұ&?VnJ^N_WCsǩҖ,"y%Aϣį0oKc{ \u935q4KCP(-:l.يbςt s,h%2يT5~~6lEmHM:,Yht:8>,72շzhVY_EwW/?"wu*#g}Qp O7%iU]ٹm]XrnlSbⵧ/7^%!4e?[r+5Tqtf~35u~S*z \D7tܚ_a0*EF?[ہğu!3}F܁S =1ecVXuifL,5n.VgK܂~U "qf_a▝En-lv4&!#0޽%ݫKks4&:wb&vg+t˚ 2}7vn6l;R lwјF`jbE?$2!}T'۽FA7fFT<иa?okYdg}ݮk^x5J:PC:pRWϢ1H3<23B"e4HOfQSC]]JT+G8.>c*w{r5 + lbleFrv&LIVоVnaSam+8ݔќW>0y0GҤm㨂*3)*8v*mOﯡjqGNNprf{1XյM۲|x}Tu.oǑS7k:]h-gtNVm,&c*+pSEeG_^+hbm'b&ؠv,ϵ,{ՙqTlǔs2t'͖kS⨀$7)*_ԧr r =լ͈v{1^y@RrF1UUU=ٯj܆VhƁmRYr[՛OYmwW1XqLb*l&gK5c2ܣխE.LIcǡHt3ndxZ^.8F;]j*F[fG uYYTǔԆ #ȗw'̖/`aSaUvۚ`܌zbN~cy3<:PȾ^ov1,.w rA E-O,oǑAJypg&Q VS"cIaU1wFh G~LE^#}xx [q]dc%aSar>yrUGLIq9tS5m1wYɦ >-v1 2`l9:;6`hjr>:Sfg93CHS}ZY58hScc8l*vWcr,ޤr7u/{rd\~ebn o{f`šNp'8isn5eHƩj>g\ڵW6_]Z}k'М׺t`QyD/(ɷF`.4!qic}֞ {}U7}1'&2Iηp/ l^6:EӞifkX!C—LQY?fq[(? vL|%Vu#ulkhfOQwS5cƥ} ey]# f#<$d/1eؼT ?]β4ѩg| ib@*cb* Nh6װ51aNWl95ba4%+hsvM)MpkjfƯ\t@+94DCg_*^37fG#J^DMg痁0Aݍ KYz3W>+1%y,Sjx'd`:c#1v3-kf}xì?63T)KU ꡨ:[Bufx#',.=bbJn;Q )cr:'2/L c1ݸgYq\T܊[41a${;1*a/cC8B@#<\wez2p]9+vEuTrtE\F+Lt)t%poV &UHC GFDءE: ]T;Q4 ÀO8CRiDŽ3OL-Tu'\ujׂ.ϥ ުʈ6Xd<fgB1eRGբI ˸+,pe`Z(u˛q` ŔjF Qjdq[Y\ Ŕr B'U P<O E ov\Kp4kF}K BL$3O=K͸r),WP)\@}"2q*O;7 ?&^H1xi0 bЕZd uymJKGlkCg^ONmG ;.+I_ތkDٺ(\_:O{Ԫ̟ó͎+ܜbrqp`cո88T׌˵[YXz9԰˦AE/U*Գu7hƕ n1el20I%͙,893\{^,23|B^'GUw);c@7; Ęl硞xػBE 2뭸f(w/ ㇊U/&OFm֬by;Xz)e˕U,[ҌЬQAupt|vtcXҼԢݨOajm8(|cJ-Vk"Ii*n>=9PT*v,<<ܿD3?gP|oLIvV cka;k0:g |YM~v&:$ONQ{|g 4STqns180Έc*pEk"|2_dfǵ_+ ߾15ǛU.Aǔ岅Q?<)&r<Uߛq`B,T75,f{ܶ%"YVKa80Nc*pGU%9٫boe65y(QCDԸ:d֧7n8^fVxS*C˙~B-'EV'1W[e 0|<`",U%v1%M(õٓZ5:(,ne.oxH6 YxE+Xh?LTl-3TjSpcDm2y;s蘒lK)y=Ɍ=^:MUF;̣☊LLD`2c`ZF=0FCV*TWl53|JO9]]R:,8Ppk9|uͬ ofySI5^2yF |%Amݾƻ}1?+hv̿ߌR:,TI$Ey#O%97;蘒l˖ ^=C2-ev,2cjaDӖ6ۧF0{vԵmَ'&VVlrhRgoTN`oOqYtLY,[ cX &u滣Bu ."8:$ûc.]% r b#.MRy;I u*~QIދ+.6N;AOTmDž6pfǕ g1ej f:nAjmȍ1,:nM%\ZV:naqXSaO7Wq츆̺5˅椢:N;B}YvOX*tj(.wFv1ҠwYTkaRזr0*Ϯ2O|2$"^nf1e{ԷʤǜP ]y\h͎#(:"Ñ5 *ryn*;ϼ4YdEǔ)*smnpt̷"h5Sv^ QWR.IcqOXjoT=o(3'\!G3<1\&#vxrMM]I #7;%1h<9%a>VoR8.qñtLY+C/ʹ#/kIC[f1%>P'GhV_:9 hƁqlS36m{D*qQe*Jr3qM̟͛ɸrQWsKr33YOXdFFf+&[)m!d'~M5ikڦoBpƅpJC防TׁpM{#)CLe[-.#ྙq`JT`sq *7QCrҘM8q{fFYFO%h:{nڛU,fƔź+*f+ԧq%4ͫov1%9JU3ْEl]KX<YXIT؎**&\Q2|VN͸;KK " GnW(4KXrRRƘRtCC›qTHT`DJ~$hlM@K]!@z4GyqLINtw䮦=\Vuג4u¿t.y&'ONͬB,:,E#eT$5$8of1%0'C'ǔsjBnۛnOH}ž1mz" լ9IM^8l͸6({WٲU( T,og+<:V,i ?(SC3ܲD͌D:W[\}I>TkQDQ!82cJW9IO3.Vy,Gn'oVfK[(W'#I2pX_2 yvYtLY+" j3ˍ =oqdIǔX!Hf,kJBGs0yɒ?vg1[eVp\FGz_? G^L'b>|J)=%~Σ짤ƽW0t K5!]Anfի)nof1l䂆}M~k &$YdǔPWR+/[sQ4qINq i h3ey?{ь+Φcr{Fa%msQoO˙Y\LT\Ƴ*]nT$sQK͌b')&~tԱ G>Vf\#ϲ{o̩Srǝh +T2ُ &jG8ȇ,2ϥcjjk()bذ=dbxԩˍ=GqLEh(ש2CбU:̖pQ5Xjtr!0ɳC)YtLYd &諣Fv硓9 9eGtLE. ߌԛjҝϕqpLǔBJ쨊þ\?x6E7;o귬3&SK&y^޸3#防XSΙZB !mofG1%83UN'5g0Cr[5pފ4P]w]~NjXpڦb',SQ a[l[#$+72"moQq S* )y]~dn`**8)5~RUۍzfxu<_[P}<~^ڼ׊`!4|GmJ"^9+߻U(Fǔj u錆v]*Iy toƁqS鷋洴M5'{s3_@peW3:Z`A=$n*u sEW31fALVQܔJ8f{3r :,c,WBNX=}*8 `obԥU{Ъ:]/:^7巩{ZjցA8e{B%.{WX$UI,og 1eb(m`h?簘٨^v|En\AǔIrҰ,TYܔ8i{<&ȍS>8W4HSNcSCEf\+FKM*0ΘhCPeY8g{J#蘲T5>UE}S R\Gmov19"i&TdkMqS͎#]Bl=QEW_3Pj@뫛z9ۛ׊pg4Q' 6_S&J͎+cb8<8\)iMq>/{3 ̣<1v*]Sofg1>t.h.h!񽛙 hWD|ZUyP7SDub,:V,uV5 rF}<$P8)ɌVuB'*-yߨ$h8.c*.`PyJ`q7ݥ7ur L{ uz;`<) v#T*Q64[N`x r]Sxq\GT\an &TP*qдT#f\}ƙM[2ɥVu6x&BpYqtLY|(kw qshOl'cIWG^LE.SJJUDndT5Daޭ8,΢cJlPC甇Uy 7viۛ׌0k^3/gTg/VPu {;\<)UǪgAOQz>|w YO oƁqS;9SUhaUN+#N8B\^쵼~}Y8MD˂%G )Y__o0fWL?1+`[Ryw:զڌl9~#!rb8;_A[F:-.ՏC"}Me!Q2bhjP33f!Q v??kPF9Diz ՞NG !6J[<ز]? E]pͿ?DpjO }Ql{N'Nd{2Z,J}Deo9yȬ1m =!r؁ZޖNGň`}NGň`5yU޳:db/`y=q]Fެ,1XLn~{N'ZL4j*I{fzCv'ڙ,25$#"V;)SwTgNۖNG37~vpP> dLo,W쇚!7zdB,Fi)#y؏jdcK8Q{ݨ7ZalRpa˹q}jhr?IE WAtnܻ|{f'RAk iSż6Nut+!Ik~"6˾[V+G5/|\}R>FI$a>}=oީ.)'ֆ+p9y~zf ~Êb/ `nWz{f'`Lj+Gr݌~ڊuc)`dYj\0,(h#8C e!IPamYY܏rR[6n7n;_'RΈs{6rr 1_㳁s'YO["8ؒt>j>s{8 ag-> 2yWّ%oșIi+Ɲ;cCt+CM'Arm'2]?k&m Cr6r21I5iDp{d\CVr;T6 FkyCnka>ݹ{2!Ih\:h;r+GY#k3Ӟ݊> E]݇bu*r:d6  Ee!"T~Ih\%X:Ydgg? l/ 7G0~tkC~'!fzV>S^+FLn'8'x&=1|TPMIfOƏ nyyȯed6'YY "3a{ T2ip .Y$!9n\%.YyI1WyN.S-YJ/d^w训?!Ie|INV^9w?ɱ_^'k#V ovbVBq2{'<$RL8$'Swc,T]?jDL^G5ऩ#vreMgݡlА@?lqyv(&dbeYyȮM6F.y'S^;ɟGWJGCg]zUDI$?qH>00! oN'*!dD+`a=SV;DB"T#l@=~T-a>ngnCv'SD s_? m_OqH.iFlyyȯR;mأR#06H>ٳ]?U8#eqOzqn e=Ib0027Ӳ`0p]? Jx"_;8޲fƁ?ID 1t*17jmYyϭ$ ]{iKKǭgAa+%ک>u467cq#- _&ij-/ڃEvr?wr.̼qOz [ If1GNe#Zx)?*2l,jvB\h)/GIwlK6D2,qHFդ飶} *j6%!D_%8'th5"\I;F߲[q?.Yyȟo559@|`m_uh~پ)X!}?9\N>Nyyȟ"o%{ +ǘ!L5yy$ 9|7Ό0[~zc`D0ũO9y~\(ƽڸ \a6pJX(Mz2NKcCvE{dEqYSV+s 4y98 ^N/:+)F!R@/LKCf |ܚW1̅SNr;{Sw`=`oƁ? yFjc C0q`H)hCv'SC2]2E˜8nȭx_3r}w~7+; {[P[.9lob)=NvsƼ 1ʶEoXiχx3lo`aPrS`CnLv/Voتʃs!l Ԝvjw3+͌S}<W{C%̭8$~T퓠B;=+ٝ`TܻoO9yϬG,7}G-1Q _&S/!M1S슬9rGr9OƦLEv).M%c)+:JQ:i\0u|1TzCv'1kr)9$TH ~Cv'1a>fޭ=d! 0,]`=["AMFTZqX|iTU8bazX_u4܏C!qݱ3aԔz=e!"ss?";_έ8o&[1}W{˝g\_bK'!E}sh3jxdbg?._Qz&_~10)g/֏nI凌<7TCnƪ'.cPHF)YPtvv}p[?${ByȾ+2c*LZ A cp)+ٝ`*??O_Ww+B?W }U3aOJq^>Ɠ!U(u2_?^ONӿOFLU {}m1qq׏d'mf!o^=yի=IC6 m="/2lq 6zq / ׻`XOx R0w,c{_ur^*jwyu?~ؿ8N{ b* e'Cl|<,@5c<>Em˳g̤\ AiՍC^g eR(' 6BB5qǬ-Ԯד2UKf[}E~'W%#k:ڜ=~{>.n=x9:Fq/hH/c[f WӿWFkG Ieà`BOlʘ9iSί%I3ӘyMƬJk֚M+g?̚܋v3,.ʛ.l;ˆkO<~;VQE&v| ;Mړ6Z cq\WO<~L~a{<'!V~9|"u3T2;W!q\z+\n9UFnƵ'-n:vx/ǽBssG뭼s>ۆ#Ξx\)G،3;z5&>YDh!w=mϟ%=>6+^z6=YXfQwG@įT>7l}w9y"qGKzWOL«GO<~WFn;Ƶ'MfR\8# ><~QtʹQqؘ\hq\]8gx=z#V޹ =~qvÖ+R{l*l!x=\O?Zh7XvhEGO<;Wtaؼq{;7=Y\hqpyaO,޷ YyfZ[^6jkmړE5ZD~<bG9 u9|m7uZ-nv&i=c;{M\ ft~ɕu3Pg:*8m\Ӹ q@y(cl!Z߿gq;,#cu !C]p~֌#1]-;(V`zؕر8* m8PaINMEQzAwY_C\[c#޲0p2@u0 U @"fEZq6t"Gō3ţ̯YCJu֣O@]MWP/>W8>$!g/'5(~9{~Փ-~}|5poHy (/m_so#ٲOĿlѦ@lلlcn+m^ثhVْ%UAn͢*CrXjs[}_ EsbkIsi}ipr=ɣ]ԥ:.fc`[iNge,x>'6tMI23>f0}~ jSs7QF)W+j.KJε qz#_ _@govs~2!5k]o[6OroFJqЎ!;rz<D?q{byM**10C貀^N B8ܛ8ڷ$+z2.w_, &/ b<#5/wDZ Ʒ,a!9sv;V<$l.ƢՆ #_k/ڵ{#ʀMٙ2ji8|ZV.k*牽<ԫ\r_,v3,4rE]Cam8|xAN'/dU#/:ef^ 1X7ק_hA olnV>!T6dԑɗ:[?PVvb*8Y]˾'ЋV/5GSsLIA5/xyɁJH]]˛g1S][*nE]9oy3h1ghF\CZVvB:ȈSj0ɶ>4Lu},rǦUy,0CT`sO\IηxPz}g $5]DE{j%^j*_EMI}>P'Ef\QE c.YD_߸}> j:qdbUTݻ|ͼU(8 臞$[`޶~3㨈S;j5Omvj4+]M,0oƔ;rRςsh]gNn.X73[1:JYcvFuRQեj(冪6of=c*pA%~T2OT/T5BpY^oqd[v|ʡ@E_zRm|k,U$goa2UtI788dL ~gv]_U2pDM[<7;1S˶SP {Fe߷zWY,0/Ɣ`ۺ[ɜ+e;r /Y7+ˁ1%$;vmԻp!`mHT5#82nTdremTl߂<Um,2ŔdۺXb~-PшnT8뗷ᨸSQ+jfɨ¯gh\b_p/[YX|[i5=j)/(f?c?ȧs58*nT)\P7LKn/ g& fƁq+۶G^nIU@/\`&ovb*rG%%n6XTPمt,/82nVŔd۹8 jZ|ci,2wcJr!"ɠ\rfNx[#gaSauKݓד[w.p<"gcWr?G=ysp*<v;M|}"ԷnLiVBCUnG;M tWUY4otϵ ,0c~`>YNPxJt*7w]7?zSfo5;\OffSo:ĵ^}Ϳg>3ꎩ ~kQ*tMѓΈb?v-Xp~UyҞ[Ydǔdۧ2Gu,<[%t-uXތc?gTR-Jw2Աpj \[V:7 G59TtizD8jAhB!/I7T$pF=9Mwg$gy+OfE=6Nl;5.'Eɛ PEi$پɘÒymYiz)ɶK5~qg։nOxJѳe^Kތc?wTҝ4ld{\qak:+k[TKo&E籼i$y+mQ JvT}bq7ffS Zz }DŽZn[V"x3l[H>Q t`!]ȑgVқvLEn\p5u#[dӷfe>tЛY`nǔ`ۢP@֬`3[Vײ^#=+E`gfSoFUcNx?e<ԳǵOM ,[Ͳ]#V)?5G[0O1xyY*tg5.+h,27cJQ NUҝTԏjǍ39ָT쏩t%EBFo:(+McYYXnT!O>Xbۑ+yǭ8.c*nG kr+~Ϋ}ygV:)ɼzu-DܼO,.7cJ.B،M#&]k\Vnu-oǑS 6db_Jhrfk;ʠG js^Rv\tu,g1Sa+jJzb>o(5qdlTa|{r@]q2wy3쏩ȸ4ݰ?W:֝Q@ylY8.cJWpI7cpl|U,#vt[= ft[0Xצ'͆33a1mGF4ݱ^V[1%i&71z#1rfgS=9$g^I7zKqdlǔ$2wV*#͖݌b?6iZQ ')!+M}YdnCT1WqPש *mzҸ\[ˊb?+^iRy6o+(Z}FRZF1άneW (BErhǑQ.!*¡NUmЦNCnIJv[1SɛY`)`"յʉ+ Xyk,y+KPE5i,!L{]Mw9\ތKǧtuzsah3=T,+ ]YdTJ*Ku <=j5CnvY 5>%!G M O 9Le 'gea)Q2mh ʄv3 1/G5׮8b|*pAC=gTŻ umBF>$8m2*sn8AQ<7d,ofR* \PgV2qELFR4G *^IepnTMqS}tuFe˥Qfgh5srL ;>uFNz3v=k20sa-8}R)~E#Ul߻ǥHHɵݡKB2"2գ;GO \ӯq?x02bˍٍ;s8D>|J_$u(AA.ur'FUIGEHEF2}KUIn죩wy;,鋐Xf{γ ͌$Tqh-#J QAX:jOn4Zٯ$u-of? LbطeH')i0zU}fyLގ#Sad%ЀT %[o~D#dW 8*6c*0)Sk[H|{FM[UԴɼYdnǔdD` m#$-4]ipu-oǑS+j\:ڌ1Q٩sUCɛY`nǔ`%BtpTnW |:}8.6c*nCzm$ė 5}siy3)#F矌k׹?Qrye%,0cj<;X2FDꋛ"8G;m̈Ҋm$ 5^~&gfgSmhp2zՓ҉>z}OQ wLIez2m׃G+m{9p!eP28|v\GG;mPEEFrz9]4/0>{Vf1%fd\ԳhԳrEe̛ELI"v)]Y!VV1ΤeJ+.hơ{Ի173r &OR6#/ YiK?9ӽ Vĩj\@ӭf;y3i$mi\7n5#+Ŭ f1%wbxpWv.jver?= td4ji͎#c?$3HyUMǚ Uv1Ye{H+ T6}k!+\GG3 ]<1Ucv0Be_IQPv[1%/NuD,Z|kSYdTdqʶ(7ꚮ5#+xpeu/gaQ.!s"6svT3jƓ|V&oQSiMi LךA.+"s?$OέeH+k FVq`T`a(]!Ϛ#jܶ~)ɓ }tJ*Yj\8.6cJ0Xm$Fm̛žL%sA`g^7j5#+ 5mn3ov1%yrƓm#)' UMך@U826c*297?YV8JlLn3ov15P$wսMߚhݛ7xL醝t3*V_um3of1%xbßNT57:q1,.cJ.0#V-pa C})U4koGLEVm3I8!x,2;|B4utHG;,Np$E4NC6Q82 cJåaCiEqHSbXoOR\ίś:=mw,GN80cJtu.OZ!BSmJG;,N>5 âKkR:L#'/ogS_**6#/ mn4ov1%yrƔ()2' g;Z62 r^bu=@˪Ԁfv|Bd\MȜv3]mƓ8a?iE ZLw T'ogyS'aIgPP~\mȧqdTdqxбBrAmF 1,2Objdc[I:3BO}< qd[| y@ǞҊ:`fP;j5ъ}SqIitQrBNl;OD3 S<1< ]ZBx&oD'͛G)@LE\$sg4^jr'1  Su-ZYB_Rc? 82b*rgQ8T5mwߓ ލ8*bJmb JQ߲}&tȰ^(rkYXĔ̠#(zTCgAzgy;3\PCz må,}WVi,0Vx>!նTWQpN`1h3\ԫG @L UYaBmf 95 $gqqSrm!@PGi32r] @LX2KO$80bJ_1 (s'gyiXu|A44ZZ3o|J$a_{x&rF=6"^h[A$C:\ }jFyq;qחE%_8겋q5~ ݯJ[ o}y]pks6Ҹ] 5O:rmsoMTkP0WP oT1XuzNV O~,Ɂ7)ӏs݉Q`y;`ƬSBQa蕃&OT'ŌPbݖy?L1-ύ53+#bvVxRbuww5ȈmbيУfd1{4np ~̮5nssoOW.|c~L 0w;2V6hި[WWԌ˼u dn$uUBoƛWR'ðkv>a7~ĐeyI#?, %ޜKe6+55I&5܊롶BfC{&<\YnތÓE*'Z 6<|>c;4AOYPC~eʍupmb0M__S}zO{Dn,}(ۃRܪ7t O 6.w.<)@Gb፻k93nS mA3_Z4Rc<)GIX?bkCkw{d++<,> ~ ߋŵ3g 8fYȫZ8>6?.o)iŵPkxMXoSsu/~GLngH*pJx|^pjEX{xRYD.;0g|m-gRpd~2`׏}|97tij}'6.oJqN߯ڭ8I}eac:xM 2,BX_oO7l_lK@NͪNAcD3*;u3J:cJ2ŴPZ'd]WM=˙q\8T rO-&N0#ʄ*[Ӈ0vR?f͎#Ç0"zWŝ Z}*aJy3 L'˜ 8Է"d^]ԊD*wy;l)>!vN} d^drM qPƔ\S+޸ P L 2geqASq2&%IJ{ LY,oƁ@SUKPDz e0=*̛EaLIfTknY#UJALkkj[&(u>E bh 3fo)_ݳ@~TU!?,'bhf>SY`L_UjŒ M5gǑ>S~JbbbK9~XgZǔ>ufރ1廏M_deYS[q\ԸҔSsmq_TAUv{19}I 7U65W^FΊb?v:3pqKjofcQSIWzKk_826c*y;DsSڬ0oH0rF;1%UTM7OOl^7;-St_o50ņLɅߒTz1+[(,27c*2ʗΩalZ6wF_;z)*[uۗVZF;1]SJb~d6s̜̾7)*^_ye7;6u,U&Ow1cBԱEO`?>_ M6qϮ:FLU$fyN~4{`ﹻq\|Ɣ\nʞ5JndR?_&FbP=qߪ+ku:4zG.LIūVwj2ݸː0/Kէ珩*a6e>'ș0/qH9YdnT;l|Sn;YBlv+];7@%'gd*Jvsy3 ] ̋5}y4TAWv6|Bɹ 0{Ϋ#t,z7揩*] (zVSDYdnKPҘKP` 󖪯*(oƁSU,9),QbT70\ 7;̍< 8E*%(_DQ (oqmA"F?Dֱ}HқqTcJ,[U (:V,z-Εꏩ*୮5SIoPԷGVLIbi RuctY %,27c*h ?)i]^RQ~`3hӱ7sv73-%AI ,CT5fÊfƁS]R2DvLI楉 J ,c7}nLUz"XmC,# KUO+c:}^dY.1I8Փrʘ6ss(v[1%y)WktS(NIILEŠҔ+c>ȝ^ƹ8*cjTW&.)WƤ͘G_f1Xś:sP}\_RGW1EFtLE˯ d>*fܦ3.FoǑSg ܛ1uFU#.Yov1%yg\_47:Z|va ])eLMOޭ8*c*JWԻ \2fj6.S-YdǔdP-@_C47:hҙ[V[1..r{ʘBs~NFogSgz'WjmnQ\h㫩gy;mJHr_úka'ƚdlǔ )O;̢/\y Ȍز߻LUn6ґR`ń~g_SqXǔXhytBryL E5@KYdT䲼H< biVu.oǑSQBwx^.`ڹFV tv19-/@N`fA@V1%˿70G>`s 3|QQv1YNT6 X0s:StYYXlwD̶<TCCQc&\'+"427cJʖ_)}U02,ձGgaL  eSU6DG30IN<Ⱥ,Qu1k3h.ӗw݌  Vl̅^FަΜ7)t`sD9f1e$mV0k MUgaSbg:=3X9Ǭ8=ov1ycG5NPIkI>!!p(-W3[0+j^oaSO' eR%;#}:Kթ '*Ucmf18// V1wpzet$)^] rk9}ì8jAڛY`nT`pRb 8.j%BuwPHv܅QtoM.[8*6c*6KX 4}M`ggSgۉdkފb?En_ ScNL ūSFbtʬX^Vޛq`lT`W>]Mm"O&1%3)@h.﯆t靻:Xr?|%JN0JU}fGͿq`l|KGAT}L}HogSm ] 9z5̠ZafǑSU©"|!fۓSvVy)ɳjeڊ[ͼJ鏩;|;&%=m|r!q`lǔY$IL.y%wy;M[g sԨc]8,6cJ}-.&ѥ=bBKjK h_dwtC%dh%#8.b*Wz#Ia v: @L5iizk֘mT,*xȚC*rY^$SE`sҵdjbSzގ# $)#:uK5ԂV*'E(ԉDY~iz: VFHk&OѼPv1y<^@SU$(c*h[.^r~.mP4*)ɳxY}J"D҅;0y:RfK6 Uԗ$BG߯v`@RW4̄T)~ .7p5-;3M)/5Դ80JZv)lYD!7e72J_2mKINitՀ8.cJ,ݥeW;R/M䄊,27c*ʗPa nЉw73}5C{C%ԵTOg];3mKSRG5W@k@YGEĐdDsMzxUUMw/ŮLE˧dK_/ {d)z;]*#eW; ܓ*]SC-)82c*24v@e=kpǼw}dI#/+Mڗc+'ׯ6 B>5[ۤ8Jm8*vcJ/37荾Tu4myu܃ 75 _y+;7M>{yInpYȉ>ю#c?"|6r{Pzkv`Ub8F3 lt8R[qd|mTdw1{J@w;UΈb?uu-Yi31ZY\nTܲȭ$t1}BT_RG~LIc8GJw/vbL15?ԷEƾOU:ɛpI*x)&N.D03BTvtIqX|TX/y6O̍73cJJW%rl'Fg*j`菩iv[f4Qg he826cJ,rRbc&er.`s?`<$c"ӓU珩}yz{lpϪ>n_g~鋻tk0eYv⽒&ض|"jEڂ؀V4/x}ma3)罜'&,9_ԭlV7݈s?|Yl;8hl82cJu.//o[YNO0ʟ,7^_ ᰛY`nTຜnAGHR=17J(Zގ#j'%RӉf06'53xTԼl@ǔSC:+!x/ؠiv#9lZկG~LEVl+m 3%fgSƹQ6UC-du,oǑSrt#w`<ϔj17Z0?ݎ#c?$p"{Ova$޽,0c*]8<9o=\ G%$u0oǑSWn'L셹`Q)1[=OU꡾R-|6+ oy;mܖv;n<\G \[ގ#c?$3lIk( jakJdT|Hnhc -^_ :)N^ OG.LǪeeLKx߻rM7o{Ǎ3adSb^Ax ԎXM ;>;l5 5!病ePKׅ!epXnP|LOvk` p/ȯ/yHO?'oNYVO{|V~p#zc~@1fYqJZ*h|jg'Q{Nuqh Jc/~v[}/دcW*Ƌhv4s/7rVGAigke͛#s {mڜxzM[~JVLWmk0wP+71y,t VodL7NXpƆ^xbH;z4e;6@EUhv#`n/̉1&Oҩj40l]L-!#7›Gx2t*C o1)ԯOtN]OsYE;,d*a4<qGU8Ϻ*yO6X3TV+6َB +c98iFe094Pѽ)hxyī433aO'WA[;{Pnz%ln_=iW繲>$w*X^x5[h7<"*"+bd 4h dQg ݸp.F 𺻯{ve^J]]md5;#^Cяq.] NGxbbakPd#oB14tvYE0 )b@XAF acgTŜXmJmLkf1\Lse_2{#_?f5~c >(17-Ĺ{9B#~P'p$0x'X1қtc)O4]giŶ.\>pGY۩![7\G6mbֹ=fAf ^21eRBEʟ `?atV Ch%mlv21" \WByKg+*<Ȍt3ip)9x]f4[XupQ祫ގki`?sƁG㇊學b',VhtjhԆFabMdYdĔpd+ ,nv+ OT/4zː@<׌fõ!֔#EϨ˃ýKF1"z V7;Pt) / M1iqY~`)5rk&fmQ^n6\4Q 5ܣ:+ 7v|Pn7OEhecdnff#:[n>#-G3'Vܴͬbч(,Ybwx|,%DUS)_*!)׍f<6F-ILBME3feqESq;[Q\6jREyqN< U..p7j›W*x)ŔJ!iTi7O5wTuPΈC)/&5w4ѿjx6O,2}bJVVmEc44yKGr*G8[k ʘ?i<AZ/i.׎LT,[͌ox=#b=uXC錸2*,-TDlEm&c$.jEULIRUxcɫ܌vu̬Mة2,7TeTsCww Wxm>ݚ-Rg vՉ= .YOHH.`%Dk]eoͅqpڊ5ċZާ WKvVb=b]OM?s*+#Ynƕ G1el28=tu UE;O03^a1>M]V3#bsRKB "ܣ*p )ɶV"۲ a3XgAt̸x|jۢb~jzW.Ŕ嚜[-:1-adfm-*7t;)p+Q-#w4 Ui;56GYLEntM>92}grьkI[Tlº[L Alj M/n'YŢ_[LY,[R\*-i {zCry;l>!x3&qz^MC"YhASrm20z`0q)m*)!z(e4Z$&SRu!\`Li]*EZ'!x뉽M'sKk!,v=vns1%VNDRC45r4t wJh3ak?ոwFeSr3۲cbM7fWqZ1Tպ706;` Kl-N IJGȍюbSmbr`ɶG l.S"7/"q@($ՍiS tˡ ?63!m2Ӷm_SUo,6\SHvj"wY["ֽYdT6>:\dw.Bsd5DB Q3ׄbٱ1QWT'=F/ uo 1el2~qX1EWvc]bYU.ofNSm2 ȵrǪDlι($?T(W*X a$Ii`̃h 1el28 p`Uc*E~吗Y7p hUF58і Wьc . È`y ԱNQ7Xqh+afc/ 6.ִy.'37;T8’N.O<ϛeEytLIӓW}%?! y<'*-q\T܂:JI%U83]r 0u.'Q1 ̦,LtEs9)7YNOX n!9[%61%RTImIcd@38 G3}<1\"__+Ds42 f.jj.hy'73\1elRј`^*Kx1rby3 ,[C4Ë$:O$STGƉqLI.0ոP1)TΫ8:PyH4Z,v!e C{w M]fVxSꡡx4OP/d[8)i57]%b,,ϋcJ*pUt?4A ;*7Gujo oL F:[ש̸RnOHo {Cd!Kuz)3Kyf48whycAc*QKYGff]XTLl)|ܤ1>|3{;\<)e˕)E䪛=Sٺ03YtLɵŊ9ӟڂfx9ti ,0ϢcJt4vBBt r뭸vU]TWtd˲̸R',-I"5VpJ%KQYqKS:s3qXkb*2o֢f:SdTrPy9tL QmU3n0u -OY[Yډ+hǵ-KKݖ.vjWyq:8qqtLY0\-kƍk*HSxVKȹ\4:ےe`l˚ד{ ||k)'7oqqSrEI&[Ԕs*97Չ+fǵݧ{hP39i'Ǵ̸r8:,-[F6S ZH7aatLma҈eO2# ]wO82΋cjp3aMSm>c31nvfC&KC{6i*v+2U,|e(AڒfPx,Tzt ŨqtLIFq6kRA07ϳ9qF;3㘊,NUmzRJ 31U3v4qSJzrhC89J#3ne1el4~p-$OHK 2fǑq"S ! 3*pe ޥ]Xbl3Ȳ ;#ƇX)㚨P8f߻nJ o\ oSmFyIzQk̂dEǔ(å_9^+1U,oƁqS;(JlKדsC68j3☒;1McΎ")q|FފkG[ []ûIB6 2#T܃,qitLY,[0_*Vn )*꒝eT7;蘒l˔QBl+,$TboǵdcT,[h؞ H^* Ƴ蘲`n춶NAtu> ofG1&nlVmF[E94"4:FX0ȊhRS novf[VNjt)R!C9 َOX*ANbP{ԙ$G6TqtL{ }M|k(YdT>0h`>u$' /݌kěF5XO4 m/,ȌV\pSʖ-FnGu9@y2|,2c*rY@FdQ9i4 oǑmb3\iՓE"Ip@{+mi8k4^PRҢ80?uO[q%),Ԥt2BY=u'Kov1%OjDSmɦ@Sq|牣݌8⒒5My Kǁ|8ԍ4MΊkE[ lۚFa ۰=əYeAtLY&[0̠XhYFFTAtLesڂf#;2ŗV15,N~܎?];Pv5AIS7;s蘒l&F_#їےAFNF\u^eUofM`,?VD:q=*>d|"@̈V4&NyPNsA8,Nc*rE5pe.lʸTT|p_*8)1EkNj?8.NcJ(:- Ȕv4TGVr&q i#FX&I2Ea>Yu|gp>O,`E;a$"=.\(iB'9Y׬~?_?l; ׸n;_p>?Pe|/Q?c? Oy2gxuy4|ɬl^_T|(N {1S!RZqD+%V~vqKم[AaU3 ff hS9hCn'r?k\F&?!r (q13Ԡh)薕NGʿMfO*C4=A!žNG!!/VJmK[V+gȿ GXd`q侸ݲ()2Z,J}foyȫq)^9,'ڒl'LCf,1Wv(g!Qp1r62>dc~'b8i֬{Cv0䦈"|uR? "zMꇋ:Yq|QcQ~#+U!#y܏BnƀE=h[{F&8fVz%ə͌#; PO"P`uEٖTD3ى,~@ '+ Hpݸt v\j"7Bj†A".ieuB?EHccsT{"Y/b--%ԖSF2;5"e{^='yh#dqsp%"P]*jOox~͋nb%2Ya?~Ts0m7znSJsz}cϨ"toTɏk/!5[j-Qj.b>1'ަUr[?+E vz{Cn' ow"=lYy$T\0np)-+ٝm_JN[V8!ƀЍq!XedaCf'!dV{f;lo^Bgm;YyYI$FEhGn,GACydTm>SV;$W6 fR:wr!Iq"_;T~EيGnN{{<Dr/]uX[q?l <.ǵr-\ـˎr!0$&; ]_?l!9at(ш#@^nyyȯr3،eq`gǑ?9 KDR@B9?e!>c.^8CNԵ-XO&ؙqm&-C)+$;dj82u%!! Eéq++ +ovp͌?*F掱#-Yaw ԟ*:R.YY]y0hbp6rN\r_b73!X:Vl C=d!X { +M)WB++N;|S۽Q稵/$2Ob*㐌/zkHP!N0b*D\CO}?=D ?bqSb=\J11`N0Nb*Lɿvܟr[5;_.(Je5mu.ƜHo GwpN8TC5M2c*\=T)'1%S{~3gnFku {>!e2Lbr}CN'1xaEܔM,bK %DUԃ1uA@&Rx'FL;gubSb'ebSް&?>#~Lwnj;>F8$yVԧ>!m0Nmc yTTT!ƘoASxQSa[dW.v ̣EҿgU\,|"czV Q|b0tC^'1ȍ~#o nnf~L Fzr+07c*h&z1S!3Oǿ}O%>}1no"e_lUy+]|{5ь'z}dz}^_ړ5'{o*{Dz:n:.|&<r+Uac=9`a,aCBx_#i|b2psKW69arkk 5jŃW]!sڟ#?ƓqoO vm5+ g1܃e4݋~$WEEG_UqqkU;h\^OJvbjr=^Kdț+<1o7Qf/tA{Sy:{y<q#6 ^Jk,uòJmr/Ȑw!ImmA}vhyOɘ2yߌX,v0*QL nk^3磬uxsg+g7k#H5O{2λg BڨioRdMWD*xR]/ͿֶzNigO6qi~΍FӰxo"#k@:vvَsH|i?c"&f)LM36uŹZM*럫5]4;Ͽ8{ϿmvWkW7||cQo1r]1umXބm (9z"uki9.s {D=o;4{M7J͸6Tӓd!-Dvο9bg˂{jdQZBBX_5_;Tz]k?\-'c*~'ovގ츢|q6=q`q`ASW('k `oQNZٞ82gT qOd> dU {;dЗXqk*מ8.g_?)v3v-;@mʫt@-9mܒS Ws“S΁Z5$W=/7d{@vȌv15ڵX|#G;o̭Y6p*mۓ_V ~KD=q`ʁ߀EnOI ۯy 3T”?,~ț7gy&Zb |޸;;L"מ8.;YaE<9Ĩ'l do7d=LD3d{@v h⃸P -){xCWL'缁s޸\oH*>8Xh z.80TTNMaV\| ڮ݃$osSNκrh睬1<}y2x2*blTzlOrhͣzZpe'l do5#X#О6w+8 L4ywX{HIOϦoG$#kƏ7XyS!~^դ'[_M"=EY$7=qdʑߐ|oGԏZғ@_@Vt a܎"WyKy:=# >~Qs ,ƵM6"W|&O>6{i쳖^ғ@_NV<$Oө[\ʻ!&1 K*pā+v~>=FIO;Ya~ۦt$H'_9r.<9YoO@irε]6nkm7ĝ9ءE;5֩Bi<S^' q6EOvB2AOrpr.0!F+b'#FnU->>3RqAauZ};=qRx>:6/}X7/N_/n:w^jp:s Ѕݚq`4LXEl_@1e9*7VOZd;Gn}k/<_y{vYϿ3Sv- pz/ΰZeF?zYjna>X͞Ygݿ_~9b,Bx">M~6|<練S|f>8y/t|1[7t-0N\Q*ԫU_dI}U_ְи\u;_?W#C\ǹ=[{ן'oG̞SՖuz<ڵkp> O^3›YчsO:~?,y[eK_np՗PCZ* R :5f1YvwqX|=1#moeO;?q<}?wyeZUcs%Fk7voVmr;Y1l%f*b:^si ^,0#%xa(kv8nv`#qC¸7ҳM`"3*Z߰7&6cOjd?l@Ngy.v26-8A&D- ~ߚ]`Ӧl.ȲWVFUUG;Ŭj&%ԉn U0,2~,<0B̊>6ي*F̚-/uO/j~Gu)!&c /aGkC* X 6-̼$n-0Vv,rsauj]?L܌ug7dl ^jg@\ǎ]kd>?^EJugt?s*]Pmp7l F`_ESL vaѿ'e`_rn.'ضu77nm̖_e`{tQNUn ,$V^XcE n6nْ0ENZ`gjF(FJT SuA7~7.S0hg4FNJA ڑu= /꾵udꂊ~6#ْ,ͲeTݯ5"E?|lEGtdUi  l*r !rb4{"xdK:p`Լ^Uòrh^KZiO#aۡ+) d$BgK8ץKi&SmܚWVA:/rm 1ֵRnòU1:XG‽ 7r.F.<_[[ ƺ60ʇeLN,5/IoCCslk'R"gt|{Hf)C}ޚnh-tv-1Bu`{T*C}LM7magY?,[=0$R##aO~pDCU0DjnХB@Ԫ'F`&PQ@,['FQ[֭0BT;vΕ%l2wfKr{jr!Xɧf]_܊^XUF1O]Mn}{b;u_o^6HaꭙuWtn*F*m *}%kh"a&[N?4Oa"w Q95{G_//@nf2[{RLy9fc__m*,G?vْq+߷75@~lEd9Hrc{jʍ>Vtx{*ڑ3\dd^כMf?['74L*/uDh6K) `DX[6CM3=OЖqkf/˰*tqO- \tgK͋%T'(v*,?#m% d;JQm[cU!ߨ(l0j*_<@ 4*3o>Ag?"ss9HjF07\A:eo7˰V:]MՄ9]g3VxVTV9O,ZjJZ a.kgK.v?_. O%)s%S3+d%CUC3(>9єе0" |#fP g"~bunGS:z\D8!ԃThUMmzolE5 Tc|O,eij^M&XKU0[90<ҼIARrg_C%҅,pc?[F.NE; S>^Քy2Bْq* +ȱڮ=J1&6eJn!l2u%yĎJ̚ݔ~inE7̐{ʾזy t:r(n,chNrtg2 $IO+p  [WNn6l .,S>.]I:^;pvC*&Ċn7!lm*wޖ5MG0[vh*X5jD̛Mf?[=Fe(XxF}b2kB['Vdb.%XYOj0#)]s+\U%VCSˣ(^Xtx)SPF?['KUƣ(XT_w0W%5Cy; Dcp6CYRƧv `UeR`O!uGS ?`"c4C1pѴ*7:GSnlh1;= DL=ѿcϦ _Gl`x䩾_Tfn- 6#Jt d<,Bjr=h­{ф2iMyɌg+r/C򍑮MDy̔Ԗ2ْ\:5n6&:DGSnl*JpBԔԒl.C٪$[ZnͭvaSJ -[M#؟-ԥ2㣡wY-Z˦2П܂u=;w9U;фTM'1U_ִROKgs_φܚVO"ԟhucF%9i=z<ݔzh^7@B$)||VĔؔr2"ي{e׾hvSNd?@,1q!FYʮNvXk MkJv gKji5?v/L=X94܏-&pV\ʮ@HӶNqm<)T|vNn6alɽVnl\9wb=Eڸ9B.E0wwE?[r=*d+M׼j;ʻ.%84WgVdY.}b[r ݗ2d0\1ݸY4V :^U"Eh#2=&#,q2Ҹ{7kE4 TNU~[eռbk\M%`-NqiV9[V1.fq+يQb5Ф\zvԬ~QlIԜCjTR':֔M#ʟ<ߧ#yza~1ʥJz&3̟-oݣ]Cʁv w$G70{P0|c(#880`,ed'(6h[WHUb J%ȐjƱTٲ?c-#c륙%xE%2ܟ,ي1DBqj$kf]n6XYQ!0oi khfy(UxDS*˖.uo ŗ1{ZHTMf%,2 *7\ IK#IK\zsl T z [e3Wa0WjS"K*8rh"5vX4|G?,dI}hjI{uHgXV]LMS(Y=e2u1 mR7YG`_]+d %K34 CHc*bm),5Jx7Ld}K16š_:( ޼|%CDF]PV&xKn Qu9E?,QdEtEy}:]YP#.y}Ȓd0:^.owq'U8T#8`jC*J-w{%"tbkQ=T+Ƣڡ)eaxjĚ7ycF_/j KFb SPl+[%S:}>4 KPThPiU'pۥk) (WS0HȈ>oͫR0ʨybYUgOdzej:˕1eJ;'F1,,oGNRj*Fv/._WH{hȾQ4P6FkF5P"A&/hEn7 ]=|t`nrHOMK#Z=6d #+64}ډ>O StTHVRd\ /MXI>WRHʱ׍ϭꡨ6R1ǭk( `*R$+ 5M-{i%:|J$8Mfs$0LUշB L(>O]OKRqdB=8dKwhl <0ʢTd-}* 2ʵkby鲐Ѽ1mha47?̈$ƿŌt=dGD%]βRiPɧfVȈg+r(_| ]5X{2-#btpQIj2{oYy4}%]3+ `x08e"f#]'Fڳd2Bْ-$2u$UtʠںOKø_X_g+[Fm0 ʬXJnl ~zʫ{h^E795< 5(AY3o~6lI~4 f?[fRxq쯿Rl <0ǥ2ي,]tؙkKESl9,zRGI58_,e93o~Mي,W:Hr 0j-793o~lIE@˥ T&Ɨi5;2g+(|"j&scTc؆nTmnql ^>DwĐTFy5֖ #}!: d.j䆡fj|n6al *}A$UtL0̬ v5@F?[g)łKPf'fn6qlfrtH/h&XCp[Ib|!sAڕ@:1̪#FSf,ي,N-$CJ83*XLaOd?̸$/ Ү:N_w;m܇F?[釮%"'zL%cl2#ْ8USH k^X[.'ϖi-plϪTbš24E?[qM/(iz 5j%raCSt gK0q$y`YcG u^O #e ӳI8[[gɁӛ?rښqYcm91ڍOO <[a@(i5fv;ѳE?[b$VtH=1ҋZ r {\F%wQ0K5A 1̮1@nD~lEbI*|肪#]. uɈvDCͬR *c*FE>,Bي,έCI*gfPM0[fjny4i5H,77 |0tܔ|lkC6FhrE?$/έ]" Ef߭-.'ϖi֡eDu^2-S+dYWO/'" f|ꂊ~+ْ,%j>YʿqkcfX\Vdqfؠ:2˄oh3rc; `,ECb*@O. F(VܚdPS1̶-$d.dKT]OQRqNM8e9/s[O c [RDLi 5rX3FZvdG?5l, `VtN0̷6'hH] .L[*Fb~ߑ(~Wn'eBC6Hq>l2%YҮjqfkrr tXVdr:DpI9cgʵ1=[Sl0%xaGVvQ!̵a?UlEr6'pt%؞ |h~E7Ul 0}ʮj:E*\F/5lɽYVʀ+ߪ;-H0aJ HK2"1ҭzn6Oyѐ,C+* е4 s4@"@w ʮ:6FnhOyXȖda(Nqf8W sp\VIԼ,Ƈ-[8<\%p-bPp=>=+ƚR0Υmi]{O?'iOd u%ޅĿ˞(PĊZ&|էڵ}^;^VۑΘ7ZU~N&@@bɵзvAu ޭv?)ϸ|!w9蔪- I4 {Kn\J:b#?>MH$r-8MbGV::[+'fWJ-y߄A3<ֱ*^YEu-QNWşoW#fآ׫ ^˂1?(N.*Kj>_K[.^ *=ȚQ@y`#DbTsoQʵS`c 1Q5_)_]hŮ.k5Y5[+^Wj.;u&~?;mH+ڛ9 }:%Vn7Q~c)=?/&舚@ ?} {qX鸢d\ϯ%*^xp1 j>bV@O=ߥvCneN~5~&#vB5EumT< cR#şjXm-zEAJG$/ȡ%w{z"az/mG+nUkq17k;^ ňgb9[5I]Ϻl_UͲFjm%tc\{$O;4=4ŧom햓aQ9].P\(ZR1<_`~=un{_ݲeٮΡ 8>6lJ3} Q+m=#}Ď:tLB-q*gI&S%jNĎD8l2o Q *tΞhN:% zRTlw,I%p?'XzcYjK!j[ l2%:Rt;eV+o˅iɇ@Fa"}`+uC|'keɦQ`&30[\AyF㜿ڹ5S+ `q0w=QU0](u@OU,%yn)pAɶHvTyC+`f+SSu!V7P*X\M"0[rW!kJLޔ!xL!VduԂVC!w;+G9#aO #0[!ռ>߃a=Ԫ"շQX2zO #0[%=,ۻPMFaE?,lI^=,RԽJw0]+ `$f+p- S7j\YNhץKl2YRԽ꬟bEk=R2%Y=l\M0RWѠ4 K`. df+ԩu'щJdff TK4 j\/ץVoK9w4O #0[C{O#y:%HFaSդ}2<`E?4lE8;EkȐEwQƀnsS!tu j'g.w=ЛEa$ M-zU(E*fFIuU,q @;0 ) 'x"-=!%pϖ=cyx- tJ]~_e?[qջyEӺG!%pϖ\ ʶ Bw<~6lEffԙîvS;S<$,޷%vu웠Z zv~YM#؟ v-%%܆vhb/HĮJoJ ;9d>_pg+W%p'q*7y7Fl2"+y/9?nH~Bhsm4K"Ο\ռ@VLd_۟3u2^%Y[1#a ~7RI>|ޚJIV@F?[Wftpi$g(뉤7?0"UC aY6A5e?[q'Yi>M:'GK"ȟ-0*T>צ8Vtg+,QN*R UMTM'= gܢ[P`ϵ34E?[ٽyHLC_T=hE7(ޒܚ7Mq (0 wTBX-T;07?0$.JI'*!RdT;0 %a?rD#Hp⽶`4XWF$,~ %yn)'vM%V]GpwR~6lEV&R#5;QfWgKciLn4< C"s3֟ﲍT#k:u3Q1ޟ-ɫ]omTJ؍L[ά̹ۨEF?[+ζzt%&xFjۚ֔F&3anRnH٫N8[gK1Rn\dj%l.tT/B;do^l]][bAT2 as0m՛R0CS+ dy`E*L[Mc0Le&qϖ\a^M`iE*]6qR2Bي>#w* s0s5 ~ ?$+)q= //lv1~K3Y!lnHǑtw׍9VR{F?$J;놌9ƠgJ-.ي{SHo AR_7n`j%.:7tJy ;M+ ц@oM#柭Қ!v{vfAز&3sgv|q394~G8J pK1 d%yp)wγ3Q[g`7˰);X_7ѳ3M5 -ͷ&1ZvVz1 qQpg @׼ʃITT$/@Q n58{%6C* P7+ItTDzP_§*cْ:wkNALtgu4MO #蟭N"!Mi`wγކۢAp gKzh)^ CNtu)i&VtD!% 8Ե*So'l; ؎At>:t e?[B'*2-5֤~lE; *y*wAѵl.CْSS ;yVf6Tg+)n$3kZY`)F7H S3 2Ye4ϲygVdtPB/zY`N]\K"̟-{RnQl}y*u^6Osшv~3D9`ͳDTmE?['%.[=ۦݰh#pI3 d9%u\gaj0R"3ҟ-(7%O.XDގANcg+C_vguUYY\u~YԄFN"Je [wRYoV۱ʂ6ܧSgK_Bug^ wmg g+z84e+a'Z0ng+ܹ] Cvu4MF~:g~ `%xu|MߨZn6ql8;¾ӿ!A0nal NUdM(k6S2&3Пn='n( M'1 -D!aZ[ìwJ}@E?[ջ% iڝڔUtMf?[W|ڼ&+so0E?[qEnO_jK7x\F%w,݋UD*~壟@F?[wU6 UK:8"П-= qܝ5p ݂q { g+򽳻Hfye,U'{ɺ7Xܒ3' \Kw<n6l'`V{'u̴6&~IhKur>OF?̐$JUw8 s4fAKu{ \:Wĺnaq54,rp g+ܙ]{Ln% gSn7F?T$Nl#h+˸78G`,4J"EL_F8eM6A;4e?[rWt]:{'Ih25peVerg+zA̛p 3ܟ-.RƉ;є`hrE?7lEf+ 0T%,wkfj%!MIryߍ#$l0 vv`[#5F?[?slN'/N~܉{ B~6эhUfK[°kxsgKK3 `%1j/S ޼.^S1Gi07pʥ3F+YlIV%nby}K"؟u'wRqoZCPp˭2ْc9Jp0=9wG f?[ )LGmnͭ%pVܹs=f\YNl0cپ`rq|}cHшqb.48u\0ڍJࡆE?[ϲ@*( 6N>|hfц@fV |YWO`M#ԟ-׹.prx\ZCq f?[տ! fc"*:>?oDCH=q~\}s|z Pf+) v[8 STc/rt gK'ڑ恹thyO78xp$(1_>_`f>&3Ο-sJjg31i{ q pg+w/pG\\y(w[C`wF0B5Ly`y%>&3ԟ;Yю;%$.mWg+r!fYe%"n04Hǻh]Ө) ̨\m nl;ŋ`Rqq~kvM#֟->6iK5tͭW}vY}~ş%ˇD.Gh{RYNqV, c ωTO\?+LX˿$X{$[>똧тwD"SsbqB:*Z>l{JbV[kLN}acۚ#Huk>W4F)L GƵ[Ƈ m7ٝvx>?^# Yǽ~ѷQ[X{7: C=ǎ0\E B0b8v9a>n1([vt;Hb/Veśԯ¢Hn9D|a@:7X6 a4o`>l,Svb:jcPn܆*uc_A'R1M}W ՒW0\^B-{U]+{6,u6\ t.hRtHOV؆A֤0SXYBky&3A)[Q8S7)KqsB]pS,2o]}0TU/$@e~5 u[hW^iZQnmeS3Qx=na0[v˟Sм#z^rz5!+D"fe+޾ d1."D vzT۲M#',[Q0E]Gu< cyCNQ%G1_]׹?My?xX BY ǼT׿gTD)oN:l23β%ٟ  )Θݺ7]O #,[0|O]lGF`ޱ ;rM8Hb8R,#iĀ֡n 1s$<͔}bΥD0/d b?,9gVN-e97ԫfwrzfVuO#)l벽_ۛF\c}숿UnDs5lхu~6rيpʥ._t+ԖCMˇu"'XWQOOczcO?GN#Aa؆Tx DqWax2,q%ٟZðēM) Pk*&gCt?59s{)pN?uIȨwoOu<܄n!/[vka4^*2_/@6ի~ZuO7dl8mg`(-lIE3w}K"/[rɾ vHt tb?M8b@<\:rkvΎdyfvTl-d1̭ncTbzY1TMf*a$#}u5#eH%AR& ?X/NOv1O<֏=&t yٲ[b 8XS, n]ْ&ptx 3M94Tty؃[REb"74(8]7ƳbsQgKɉΡypN_*_ 9R[qF(T:$l)d>S0HZ3pzfs-bnD6pg?lI'ơۀ?ՔQ.hQn8d.Fg+(rGc o>ZK8XbX ģK wu/W\[PXq{s:l)f1Lו5XrkYn⣟Mbt$/`bR}UKڥ{AeK.)N[aSkko)&GD*~w_9<;N$߱'t z.<uOnZbʪ2&s=:[_?`IOH8^5ȁ-,`.aTƎlZZiMu*/] /<؎.aB[KrC] nKْ0J)$\x[ rjVNnlS%l,yZ`zZۛp\Ip2%AY ߰guqA:[v˟Yo'[溣@}K߾̛կ& ʉ:Xc{!֚ʗpvX2ΖƭR]j,,r¹Rx>*g?T3T/{p[N.oG7_\Ζg?W F| .^9ڎH$)kl%(*lسxߌ`O:K䡧[ݍn6+O+)?\U YCyj D?^q9:[B5)=v^"5x7yY`O cA:[ơYzYw+{7vY&i_ǶvO2ZmZ8o_'Syj\V jTY͵l%P1Lוy_6ݨ>X<ի'Yj-k9NMيr8[r"ځc@5ҏ^y"wlڃ, rt?1[ͭ~(,'-bez%iANmO'k8o rO7l1Z5nʮ[j<;X.Dg+, 5>xlw'+j9.O8r{gBZjRۛ-`'2ĥ>Q 2Z*+Ծ XEg+2Y)ziqBҹ~hYKqݚr%:[r 0ixeIFv$F7$S>-R1KѺ.C`M֢enb. ^Kdx8R+e৛JtNZxnZ祕8n%`R- =O0V:Y,doN#5*{57ĩmGkXl5K1,DgˎÑq%GVHe 7/el''T5:_[ҖVس@Zq$qz-Hoy)q@F .[;.?\vJv]kAb֖) 'Z-bA0^ڒ,Y܎lAn!I .8HWeɾfT( VkJSg l',# ?֨4a$g[}~v --,~F2[x.9HMIȇ裟@Ɗt$ڹhƪi4E7&'=嶧@zqNxda6b' ̱Fץpmo~։xda5sISoSKrإqE:[vlqn /URԢ`Xp{XΖd|b6YV]ljIn)M,y zUVa*RZIJ~lSJ +(?XU3:skoO/lVEmkݕ,+g۞^B$-{I-yꤠ̊,k4 / `Dn%_ZtؖD0Z2MN_n{W(ы lʳ0z|ܣp!;ReZm-UH;eޙe.Ign EX$w +y[ ~ْ ac2WO42B[l2urPPįU[۫ǭE9[f^֩<Ēkt>pRC\ך\S-,Jgn|I(T?Z8-iV\ΖXna=6rYiՁԊG'5: XG#fC akw k=0Ⱦ'C(&W =1Z}yEnB-U@U[6lR+r)l.%ZjEvjpX]i=.Mc8['~zXSiӊ\OpԮnZK77oO'cPHw9jZJ?AQ}_"=.U +#$yP? cʨo[=w~W34w[̜Lf]dYEVq1sHn[I޲|-Zq[rސM]oJc.j{1VP75z o36ʓ{QVnɇ.zC+iv>}ZWA#sn[Y=r2qsSKGIoT3T-5%v|h~*ۃ܏IOp''9aѿ!^)F0KMG;[*eΌ=N6r[[M<ؔ?/ɗ1{k:VV%Z*%L@){ɼO\ΒͽSjY0/3HeQuߐ`ҦօV4/sHNız4Cc^_췒vWlR +َ]fZ˃*qr;>4u?)\0[!ĥ05%5OgK>V\_MH\J˗~j{c[-?ÎrׂAް{є]o27\4Ԓ]o%cכ |~/Ֆ Ruz Nf-C;[*žT zrCClg%#SjjLJ.wJjN[׈ޚ Yl056Ԕ77Yƀ{PupEє.wrg xG`_Q):al^,cȥ E(3o!m]Ꝩ+&FcvdjZ^-5blN-A1.S=ƛQNnC-SK>vS ߠ$$+ΗFCk;=D!QVH9fԒW{._דS?Qpv 1Xq'5C[;!(} !J[Ÿ2[ N3*PU|-[5/ Zq ƉEN*r 4=|ĕ?ǜ%2ʴ4º oMyo~"1{=x`SC^6[ G;&qo52\O Yk)EN)B6'ݎ7'ӣo(O,dt4wzP- کNLZ"` sY] '`aztA \WBc>”1"+rYm([XbWIbIxbՐMm]42%cgb!m]2|rQ!m[\#q%.wF w}s~jʇQ]'u_Ԗ7?Qg!V?jƦ.w:C&uBo;{Ԕ[)۟Sp%dQ?佱~+)޸,>}Ūdua?*r);\2}-Xy`x>/Zphˣ) 1΃Cr%Ma&щ˦S[>wypHTY)}jʇ.wZ7/#lj7C=|gj,|wє.wb7 '3ʪ>Ck,G?^h߉<6>+CK> E|'ўGS>4Wob}Sر}lrj"1|^דH.Ʌouj>`6%Ss;U fycS>"'|ث[[>WoQyŏO2Nw?J|ٌ-퉍 3w&ɍ%գ|hjd̃f[S[߉|3q[EåeaGK>4vSy`UYGS>4wߝȃCr+ 5nqΜ򡽋ȃC5j?"d!wZ^r"1Ydkˇ.wZ|Q?C{EVSO9qwׇu-+gMس>7.YO ؅Ny{S{;ًd/f{~dz-KwlOrl˛@Ny$-ڻIS<8$_8ZYm !]֖[|)ȱ-o~;d%dGj;]m^UAV@IWo7j{{}|-o~; GAVŰ@ړGHÃC2낍C:qA^-ڻ5Ÿpcg{bx`SYnM惜C{EV(!)Mj j >򡽋Pƒ<ץ{H|$Գw4xp\-%,{x[i<8 `캞˅k-+gYXk'66O~ ^$_cRɅj.ҫ;m^9|''9O Wr_xEACQ]vqѨ}_f?r6Imy0ϳ>#ֽCɲX+vIє]*G ,k>l7]AG\[>qۂ Ĺk灋n|h"W>r6דlrߖp2ZES[>w?֬@=[qԐ]?8 ʶDj2g{ٖ@NۺSbdvX'ߟ ]YQǓ|?1?%`f!{J7pJ佱]z5K ~[!QwA8ߔerH.ԑ:ڑV£-+w7 o*?9$24*.>OmEr) y|hʇ ]i}r)l1̫[ϨCC>U܏2(R}j{K/?M'diH vpHі%O-8:߳OmE4w? f?[7 ř1;FV´vqV܀1A.Vj>5Csl9|`l g Sَ .SC>4vaV@MHVl 2Osļ[#>rQ1<,+HF TD8 |'86H$G۾$5|h#ҟTDn+~nl#z>Z>J@ _[ !WLק|h"П[~r['6&g+Ğj-&"ْV\e)xQxoLJ~On)O.ccۯ*'_8t~!0L~"m(i|K25Csfx?[毸<K ~boz.ٟ8sȈF V3\g+~jwo}~KL]P5@;|;qŌ6򡩋~~p]}"scK2>Qr=Y#E9pH>qAܚX.|qSS>4wV`a_ Mysg'w' h R!%;*_b Jf|h"-ԒeL?یmnqŽي  aG _АMleqK\H\dhHL|]num]Xe CnZu SS>4W`X >ӹ)0 1=s)V\}ro]|rE^ꇖ|h#-CnU!{mՌ7'H~ Q"ac?U`:`v`f͆WGG#8}3ђ_N~hXQ?z#H±]"|4?k N4'5h巫﷧-e֯bl>ZR9^x|xt%KB8 Sl?خ_ Q3AY6QꬺMfnD7i8Ju(vKjm_ w] #}̟۳twOϐ.6͠n'ǚ_5/^]fTq Lfx^]LWF{bOs;ρof2O\BBӿ[,-e>q%kb;-;󋅥nZ>>V9)w3l+s}g>KXr+o$'L]1gxi=5ρofêYڶ!N焼ϛP#>7B'N.&w&D)o$񁩺\9˙(y>Ծi%7 ρof2`co5#΄A?AOxn8kIY{/Ur,2g3-fF91}[:Цq'>܀cz;o?'#t2xi<~#0?ar׍}ߓV6Sӿ[;"Fb &||G¸3Fs"7q *:vf+y83 (&8|]D^f! Nׁzc U?dR/Yޗϡ+"0 bnj]ǟ+ ^L;y{зw|`? U[toZd kƷW|}l\r?գͶ fw[-Zï3ƨk{bq, |EڹpTdB;h5|_?Ae`ZChߞ~2zaw~zъ].XS͏?TE8ՐWD5K{tb[˜X")UOe:`~ .!~Gk?U?f}H.{Fh}6vvךu]Ǚ eF͟z'~}௯xĮPv=n9oc&m( (SEuxxg7X3%RkzX3?&?U"gi-ʟ ˕On_hAgc@?ȻՖOSe!}ڄSgݭٯ ~W=gt6OOnmL)jwfIWȏ36uf #c mkώ>WXw tnsp)ޱOgoZ5Ӭd~Xl^TZOan5z'}{8uz~5\4+)fɡnjgZsiq<{={{Ae&)x~-+i_k@ցkۯ>lM'BZ"#h>S&u.O@WG1u_m͟Vp`]4ay` ]֩_o޸l_Uxd.n$5ܯ-'~Cf>ldɊډqZ(3;<*.OeOyyMD'ҞN:n1#Ű2{Y;GDoOmr$qz]Gcr+Sja x[ 8=Wsz8_i֑f R5^9(rMړ}}}8<QcawH/TVu Q#mw鳬`:KLt~ X9i`]JĞkM!(eM1˖\ i~1w_#+u>ڟyYsj[?xFQgws>v<`~ݫH;$-e|ײw<L;:+93)ţmYYg]-=NL_3c)'' pruc;\pu?s|T\y΋W㥽zk_e ݃˛{yѹi<ܻ@{:8N?uMB|1q}̵NlMv0],cAq~;,UwB$iamS?j_Wݑy'K;= +]Fj/|='릇_Tȼcv.3_YߩSsD@$y:Y5ldzI%_5>A VagE9 X,emB=|ZXfA^װg cp\GVTABÛo 9;Ɛ#@-btGXzhÁ|+Gb)[Q7~9:Nɦr)[Rdh6!W)N|4X~9 X,d+ S׎SX}B&_j04Z@ jv\t<_/mތ!U`!1#w D}$e>LL[GMʥ`tSi3wdcY.[erz+3= m\JGNي*ȭ4 Z~uEb8a~뺉N6 ]?Z̛\S:p\:{y \df+=8sLpKvrY%p-Sq{LpNokG=}l( %t16 r'ft Ψk`^IN9r +^'ZNpOj.zg7x\seK`O1M;N^AurV) |#P bx%0=n@VXƨqUC7/lH&vU'SadS_܇m^!f ](%t!&2P) .p{l.V!t!.y^uynS)z PV\Rʡ/[&k_zq}]v :0:ǥ574 [gr9e@O]CSNM'}}ԝ]&6:X˖X[G>,^900\O%p'-[q;^wD|UN2?%p[,[/z8ӻ2|uͪdc+[a%-UU~Na.l0}5AdY5l>Q0gѤN6mѐ1&#T(?T"EPs`': LlV؆ -`=Y|\ ͆pu${ \Kʖ\3M\6؁[ÛO&hF/˽Iي1B%,zL/ ԕGfԘfh}Br߇*9bYB'W8}l40CRǨ-{1e:#j7MŐKz{zA &ZiE$>[b=[mYfdYC^6lŽ1@Ў"ET]&gQ2Θ'`|b[TV|\^d_<E,>[Ay?fTeV[a_7}cK/h|V"9Mn\Ȝ@K"1*xcϓΩ (:X0nzø80Ƞ\jJE/ FPY&T)(efc|ܺ|EP>[rK4 v'Ψy1}A.S3*P%s{  c% y.lծKwХPIWϼQjܚN2$-]2Jt,vb<&$`V؁*CgvrO=rY^ > ,;Y+sԞEh2Zɥ|xz5-oGѵl*#يʝWJn=ɸ6n9~wͨ#PV[:d`j[v"s}dbtޜl,{rKyhOn(?N(ߢb2xDkGvxqVX:yzQx[aR4d'3ff HMysx˖X*7.%{PM߰4)o^1 t]:zW7'+|Nl4 P=x &3e7c\l2uxÎ@!7~ӭX&TtgK|w!i*N{ 6;ֶ8|bupp_R`1.1d>[2=d4}b2ߗb#e/b>hK9O]60 2Wb#tJD >[Qo XLPllŭk&T~%yݻ X leq>%pV\n|$F~9 ;+dcϖؓaDu`(>; XF=m ]lZk'bl/\z4X;Tk3wec 12 .(mO^=gFw&vF|*qcxǣ'Χva}N61l ^3y4l%CJl,B ǥ#|TNΠ^;䮄vͨ$`ϖX,U3vm L^l.CيW)d1E >lIؒ}Д9+SS|l*բr r`鄊! U)z PD%J5鵍}oL^yI"jsAa4<o؎!%dN2jGߐlƛE>[aMMg w4Ć0l.ْ=֜FjS(Ҙ۱1'{v55jcARnCHlԔ^6lɭܡtS#.'qwHX SKbp5nMALy fTpgKq FA s>CJl| N6lIE%C e9yP21$0}*ي=a|`0WNuLUb;nͦdS~V̸9mtMq`30D ;9v#{ \߳c[^:E& P*! .ْ;ybYrݓB3.c3~VLzF]dBbЉ͸kBE'{ĢӠ0EHu?wNdf'z\E85𦇁Ҷ1'y*]ˣPeyXlYElE]𲢂)a|ă g/gKs V|zpuB{lNes{V\4*xQ䜜=v#שXOG"-E-p%l\ZoMEH"!yMs!dj@ygKjAu뢩&' Wfzh2'lEe\װ;p g/[zϖ\uT s2ul?5P>I"-7j٭=1ƨ*5vM~aAvg+$Ո "7z1l,#aOT_]7rEk: &R=Qכ O6 O=cBJ,c9S`XNmTԒ{Q+gSa}`|: T#d؜ w͞n< T>g/J5doLi^'F88*x.(gX᳓LR`~܅CRC`eDz'KdA,vjΧ]͸1ȪlY%9ì EÚ}2'GR%YQ=( TAi1>N1'Eq_o^W)ђߵ)nl`TD5(g/+idt yqdߣɓQLdo>U#ђ&~)"^W}E yN6#906up-O(qW2QQ5*Hz0(M3_Rypa': بӑ3&9[OkrH*7Oq?4͕VG%~bjR1jTH !ZcbQ2䝁\kŅ1VcSO9Ѽ1Ga\q0kE' UExz¸4^Ɋ;0("m(e=Dl)Nn֛C$]b u&"H14*,<(_?w阪~$nD/.V$؁|"CH\7Nb=a8BjPx>6Tz$ubOːS@|O%+qߕ$`P \|X%됗U*_ s~[(iNUVeSȫI_vG'KщmcVΧ1U养~y P%RoV˧ 1r@C(O'|N NzX=JT?4<5E>[B=c V{b^s y\%:P؂/>3[ޣ17^>^1lm,eTz|l(Bш16w̅V֤.?\"bQctͦRsS㑹+}.w$ic|tS1+[۵_eq/F%@TEJ/QfT0{fʛE4>[b=  8{ސAltg+9HģcQSSޜl,#֠64ȠsWc\Tg+jVJ61Wn u E/ː|6B*v=K8Ksۂ,FSKz(A~P*^c{{ZʛDL>[b="zG"A9f[3*z\wbtzӌ^*UN&ΔAiCC,v܍wbCϖP D UZuH_ |l, ;08V؆!.'SW,!F$`ϖXR^*Y͏cSVԹHupvN'hJ^̔7'|zǾw AUV1Xr0C%pϖBE {"w"[ز :dcuNVXAT*g68 X%Vǣ@*iԁV0М N6m)<5<Tcb Ebg+ENC ^9Fd$G" -bt%2FG6bHޣ N6lEd D̝3t:{\KI"-  1U˴_e KSގK'z/K򰏊B:2q~ָ $l ]9A|AKk%TD%UzzjB:cXFq:l.ي+ **N9to`r뚉^l(aGXF03wu`P>T dy!U @aJwǞɦ2-XIbZ~L!f 4|Nl!URʗ/ W,hSdcϖX(k_dfX|"^ BK *MiPy1hWy>g/h|Ru@^%! .1X,P2- 24<*Sv`B1;0tD/|⒢AB=xLziFmh|d.F|򘏊SJ: %X:<QuDX|qR=䣚.d/ W,{|^l>4 ┦O{`ҡ3e"7z\zzG5!0Mf 5I"- H*M9-Z3dSϖ|<ÊNc&X1ƸSI9[a N)ʔ-T<>uD'X|.HQUt 3(bkӔ^6lQUҔ+ ,'a7/K=d(wIœg;>6)+B>2D` E 38 L%vADBUP&m ''7lI]F+>MiԎe"%Y*oN`0>[a :QՇ\+6`F峗E4>[rt*Ti\[|qbg*rkBE/p|tT9e L!S*z\%Wo"UrRθgK$6: X ="1̍gfUtgK4ͪF[Ԫ4i\K(k(z \ECB ]AdHv qՁ>0Ԕ^l%4<*UL1f2 i.esϖE<dfX< , +ДBG*1% 'TF%u1(uLS'4qb _EhjFyg4I#\ ARkd^wْ(|LY}a2R7dF/˘|ݔHЪV9ܹ'|19{ \E rS*ekJfDy| gK0<ZQe)ez'oF#4PҫD:Fט̂Nel>; X%M Puի43Ot^6Al,Dg㢷r7,VD.,V ʢ`Di0eBuv[45ux4Du"0ƷctD'|zɾQ4<*%c+gq+ډ.al hkQ:1G|0uM]):X15vM]-`bY2uD/|z) t 3tN5 ťo_g_Vpw0* xDV:+ܰr~| -O,:VFf\7:+ҽ :Z;Pqmak?Ͽ>vg4-rqS:,؞>HO&yZu䇫Q"T%A*tZfn^Zů,c$쪑$[UǒpkW:+p%]?Pm[b, @?VɵidKT.*|]$ I_ Qy A-#[DR@b{V`* y܃ QZ `ku~SgUjfUE%@A5uP;s=p М:Co{37ӖS V*+}zʕdz*(QL#ݿUiՏU,TXuoy^?1 ojI̿_Ϲ:= Q~!&QyaCWi"q?1= ں5иb<36ϝ]Nod?hNZdX5QT z;O,|k?QW\T_0o?mv$:ggr6hؑbS&0&Lףm.Pё@Kvj~YJj^"jlv|Y.7_xC+1:^5?Dup_2ўRFLݗ_P?r[ͻYe1Tנ̞XCjǍ;?@',䓉qFycI+ksO:W}<5z^n r /[ĽX4*<@__;?c(@Y}-Xg~oSj>%pjowUZY'+1y.\ YgP,P G".[RWFj𗲺O%T>l.3o?VLJeN#PwSC߆1 t 5hdU`%py7ѥ%흛U旴jV.;XeK,t,w kk˫,@UK".[qչIu@[}&>l,s֕LT}c QwHݟY Nc WD7/Awr=Kg=] %sj0MR8&r~==0Qp̺V؂֥`͟ϗ)M%puEML)U.$]{޼l.3%wNH_?,; Tde+jy9:T'my!RI".[bWn)"UO 22䕷X.iɧE/ĻlUT䆂=Ue(kNE'Ļl:,$prQEk&=l.SWcrIݸ~. (}P޼.dz%Wkf* V|m,i%p| g殚VPe JаWIR7ԻlIUI],Ybq>wيʞI_^GR17jpboͩes PrR;*b,oJ/[]K".[qٵ! i(Mtmci@*|/,lpKw:VbWВ'$mϩ8A ,>wْ%A!"Jץ.r%Egl'D:e]w>Ԓ;VdpNJ9 XeKܒ\UAa P$B'ܻl8/$h>+ռ9 XOձ@wǭrF\LK".[q3 U*خ\ܖdSx-B߀%xMRo8G}_"II".[aշ %]Hĸ7 d+8XfeK˃UKrx{E'OшI>$YI23~yբů]䮞v S=zpR*|g,dSv۽7Nl[r7IRil(F_5Meh>[Q+qiy̒y5Y5V$.ْI}yeK5c.]HfD7'|ªsSS%*mr=_4el>[aOM)ZҰF8ح2d_DG"0-Y;4eO;5O8{-cSϖճ勢K԰t y \l0Rl˚S8#S7/|kC%Ζ`%K)T%%(=K*2nflWHΏS٢G"4䘚N >rI,Me`>[Rճ4XɄؠᄋSs)LLו$#✃kt}h6E/|䮮ui Z?NnֵTZ^Oqg+zפ_2%aʡ.:w LIU[-ձLC#1x|NRe@9qG`zL2gK9k8;O'69!g+nɸܤiʝߥl, ݚIrl]^SIaE8>[rWҐC89U!v_>6qhۼ5$J};-I,/z P%WR ɜoJs}Pe+οoWNp.?O#i-l)8skF^v79Ymg+U4'=C2;IglU^QlU)-7-Ec^ܚM2 ƴ=4*Sf}*ْ-G鲱9ǽ4l*cي-&$\7׋2tjFEh _^jaXt^!leĬ2$Z9}M2ԺBc73H0z \%wvb)jBаu}P%tum)J1iVNyE): XF̲ce-殟$0|O~!uEܢe>[dž o-{]y-ż%pV\iM&ʵTL tƢe>[b?Qտ'`꧵ aoCيȥR_W_}0sILh|B0)QE+m{;A2Z_Ca;0x2w9.Bْ:$zX(d~%l.آ~w׌aSZq-UoN1l]=["rRC OkƁ]( zF ZOۣC)gKDclbhN}lo^lU$!}tvB]w&/dSO$RTm1#;Fgq_B gK,D[*c'n3#ָ'M8: XD߳%vhAPU߳!lvP"\r_(Vh{/%p~V\una'Uưw&{ri*ْQhliQ{넌ioLǦ26}gM}2ymLug^l]}[_CbED8iNE/|⎝6FnUb 3T%:$ȍ[ qIQ?dgNlEm;gAM({cQ}W%ޜl,m, *V/`_%3.Bي{)r6汌jɰƭ8u E/ |w.[e+'0LRUd"z \7\$`Y< Rcg+ܩS#$Wvb?"b ;pzϺ4'e>[bW禦tX UC E/8|S#v*llf<%l*ْ ƭ$yC%Xy˹Kx;X!aIF/WlU疌) `e &UgK.-=En VWt"3 @;tF/˘|s#+@. RqV|(S!*"`u%RE"1w%)BPѴ9~+?>uF/|䮞uM"HXWq 4ĉM%prݭvJEgVS^24-SNh@4f"cİH}I"4ܭ)ɥosvi۱ZTtgKV%ZWJlXT N6qlE;u<Z_K"2sC+-GZYBMHYeޜl,C :GlVeU6fp!Z\E#NuЖ˅;eL5&>$6l ]bʲR9lOkDiբMe`>[RWt+v%@g커DET>[ANԐbe*@{T>6alE; TG.AHDgY2{ \fEv >,rB{zp]VԾӧHUEɋoVnZߛfSgKne)XTVQ( 3tikn|b;΄ΚK~”9l.ْskRxIVeT[)z \SoU(Q y S>cfgK&^ک9OPԷF2어A(+ߦYqRϥ}*ْ:6rU2\/Hu}xPFЊQ$Hd*ʠ^4zWM$0VXLw&d.Ŋ/%*ْF,*Wc=`|AEIV\X\I.ͧ%pϖ\ZU[ϒ]b{;sVe[#o=XiHl*Q_Z%x0YH|gmIN*D[w3l.Cْ:7$h Rvd*T#3J0z \)r*e {A=PD%tu2 JR.tl2ຄVT-e,>[q;Enczթ27N.w),B[XR_S~{r^2o^6lU0^ Nݗb`HG-HE*N`Cߜ&"~-_ݹULYlsNdž2-gE=SvU}oMI" eNjʮ H:~,qesV\u,ԃTo[([UW(xvgKl%eWU\ԊNݿ#g+lSΔ_1 Yz5e>[bշSc;JUhf{zŸN!lEUז-J!*\ѻK);T%u;y YR~U}P:BIe9[aٵb|ܪ{[;(R}+VG'|ĪovG+~Y2,6ۤꪫ;^5+Wgе)DW]]U^ *S"T$ev)ff-MeòA9{ P߳% 3m fVU'q]08g/lUrՙssL;aXweq/߳w(w TzAV~t#0|ϖLװe7QTo{;R󛓀E=[bW)B'zoes~VkN[+3 SmziJE/{wKͳN`UŭRڷ!8l.ْ{\ץ)Z0nO4GE舙V7n[ ww<5D>[bWϚKL-@esV\u/ޖR`d^ecm.ْۨkp6ͩ~lKfEJ l.يݚS} gV7fu"U|x \յTx-UbC.%@񓗭Σ"W\WՍTR[} gK]0tK0F'h|ªss҃^ lde4>[qN2nu]֐ou)R玖dbE4>[r;4n[ݖ(%pVܱȝ8(?h\Jv4y\ݑu.5L.[aN&#y?KL_©-2k'Rykuv`Vߗjjg+.z⃆HIaՍۥ4KgpgKjs=CZ|RLPsn i'ccm."ْޱ|w胸a^6Kbnn\L}^cN%;{ Tj9(ݪI](B %p V G;'&^6le׮%_iu%w*يZw-WQtg L%pϖչ )Dq,:j-)+ 4aVXunjFJm'Muq|Eh>[awHU 7)^ʖ e\>[BWՁ̭2qG e.. SKBa~sg+l9SBxUQ&\8esV\uR`d8S)z \D%wz SbȘ].nS)T)BjN&dOWZSpg3P*_ 2=CQi98|b;qЎLVaˢQ xA gKZ|6JYi 9pf%W<V\i>A>z%X50f.esϖܕ=(DVzUÝʄ g D7g+U4 TeĦaxt>!lI]5 \Xep6\*6} VG/ː|V O)Od^U 7VЫf"(sO Mbq|a' Z%<ճ3Qopb!DT>[aΟ"v+dO=:4\s7$W롻\Ok>*X̃ldƥ+ 8o.!l b&+Ǫ&*S='Nl5EL>[qN#w2s@]AAq;_4eL>[rջ{̎ 'LZQ:l[*z \*rÜwJuA e@>[Bc?cZ/`{;  Ϣz'!KEdKVwV {^5D8>[brB:n=uZ/iG/p|6LڃV\{޳G"L~'81;[QeĆae,>[Qw~sH. 2> ,7]?HDC#d"M "N?q [VWMiV:~1Pl*يu^δ}iԁszB$`ϖշT .^~9]+u2}R;S2J~T%u{ZL ̵E y]*9g+s[=R:.v);6b3~ϖz4*@b5&Ttg+l>ie\hPy|œZ4k)j>b016~j>E/{zPAi5pl>^C): X%6v^V^l'>c!aV؊R~3Tbl=I"-iT>i5pl'?;ksP̶Ãyc)S[LR'﻾epZ1N\G9nSy],Vj>t`ir'ZvzC{LT/ʾ`6 V-7b|xby_|(?ցõ~/XkTj_ gɉd5kI:.]t,0oѰГ/>Z~CmaׯDr*u,g}yPyiQh3 7=y.k7ntk `*_(uw1ps)k\lPɮQJe/|u~::I}_Cgw8sWZéřΩzƩι\Jc]q7_Ā+}[L~ݗs 9l^5l= }!pPe}r K\x\Xc~܏>c|Lß]Pm,vG/ 9էGJtd | sؠT{sϺ1CX+p3c}f`L6bfͱfJ^W[WSתr M˽Z4\~M`{y 7~_+/wGB4w ޟtprۛ3[5Sp 4Uߟ?4yy{1oy g~:b|y5("15;M#^ƍwPu=/z2#[rm,mum&#fHXEޜ]ƴ:}_ ӸJN5,/Բyl٧([}*ƲAR0¿^"-esSXڪ`,)Jb ˒A[NI%[ ebZ(cӅ],*D݌}CbyI`~y$T![%[vvt-cRtMyX 5{\dK.j_{{@7Ճ|ћ@EJcðNSEo^g ;\u)ti4'^qTq \|xٝb6LT֥mdv^EA1uG' ]}.b{s3@np~yI_oN 1;\־;Rv,XJp+H@{cY~ Sme޾ze=\m,swu(: XddX{Rb& ŨHYƷS]z:Tfd+jt8l;& yzc%ta %: ]_pUՇ#ddCpjH2ꍁDɸy5u)z \ddK?e@by1aGAC:9X&d+[JaUTERc GET,IeeqPcm2"PW\ILӆr7ZqwV Kѐ l!/q|uXPV,٨I P*UN8F囩.5[Y\eŒ܄ɼ/7O( j*NjL] D@V,ŴKdfBEW,mrkRelEܿaN]=gRl=biب1}$:Z&9#E %%[4!]/7Ϝ<)l~t_ވ",6.؂V 8"2d\c+`Xk+:z!3t3VCvfyTZ+b4wf_ۭQlHԻ&7dY_X2"шڤXm'sq{8$-$V"5ob6ԛ;i-geZ,-g[XVN%n\ 6Xtx`V+#$1_kX\F#A%4!@f-2!MJa<$oeqKq n㓽ە9ʍ["eI{Xq\DŒ]!֟l[Nts[0-El?HSV+M]y6Ɲ"Ίkb&Ru VVTbځD+@Xk/DɻZAOllep ׏de#- xn4DŒȠhDbclK޸Q"gdQ !EHj58CspHDŒT[ }8~^idtd-{C aT^?:vۭ6y#M %d+ +{S FЗ=l,*#ciԂ`p[X1 /_=ɍ15aqKqqZ:#r3:JNenu rȼaM 1",oRբ/Vc+ABL wrDUnǒ ^ѦeU }bB`ACKBm4NO)1]'n$.wl3Li짂;AsE?^8mq7l>T[ gzeNCjiNo,C\]z@XZ9V{$V^[${+ǩ፸hK SK|UХl:Ua !mq7l->/Nt[d㙤aIMV$SG\>gVʠ0ܡ%2e.}3O 3|  =~|7ϖ9 "9JЍ B{]+=k`clahLԇhlxzXqPR\@*N; }H ҕM:K4XPnҠndHKKsJJ-En2^꣛,WT0IYf^519McXQBce\9q ukU$,,wcI RF}R9#a_^6\ORLWt%lJ7m_ÈkvcJg@Zn܌Sbƅyް!6ЙMaqKrm-2~ 8O)!OB%sZC7:_¥ъOq[W*Vv^T5[qp,([FsNtgvᆘF=5Ep,Ikz=Pri; 7Y, jj;tFZ+)Yq2Qm  /C^ؔ.8iopWXC <ݍ k(u!1YmX;!EUo>z]Y޺Yq\Wb).)m>q$ġL%oй+acNJ7b✹65adp7l-B%M31vMUmV{`uUvp JOm͊=KrOidWWCbҙ\\7@ȕc ?\aNuE7x+9%ygx_W F`ԋ]E*Yq\ƒIAq2dAƢro6slIRmCE댸g˝qP35QcC״ъk}`w8$oh1Kb:RG;NS NEWTF\7"ö"[=.Yrǭy୬&q7l-@>D6F5x(#AMA?N&V(cWړLyg-z F$uB&Y".Ҧՠ1wYbxX$ho0FH~q-E/[XC#h* {{-tDSi93]+¦EXΊo E8\$:"ЛaS) OVfC2cFJUq; ꦖ3yIކb7tZ[ /ii"ga)jD&m,Jxl;$L/mݐQa hA[ Sv͠ 0J#dc`5 dڑʱFTR}pTƒT[4V*vSRJZZ בht$Jp0j 6FVK" bڇ_L Agbej}pTRTQjT; )@@RVۿ$ז!v[dI]LyOLUV\)v{Y9|iS21/x=FιZtڊgTRN΄"̾J=Lf9m8"6cI-CƝ_9HZKx:YTǒT[X,lC^ZN1 {]+]m!2,_dQy>W0=[dkl1IL[R!'^adu"~c)lEOf<@i:'Szqf.ړK:Zq\lƒ܄UH;UhJThZl;CÇDM`Tydڇ ƒͱ%Odg!;3RRkV;$VC… 2uG^TIBwv eG#X p*e N[dqtrcEKpVYݘT+K8ѓ^IvqVVK6V!]mHJPSp椥R6βXj  ;Ԏ$G%f؛%9o˔wÏ)72+b]+MS]n7qAԎuad[6]L}L_XXDBUT\#+X{" %nRm$bs!*zhC:MȢ ! :,RQ5JKbǔ\%v7i{]X~ CMͱ|X*.Uͮǒ-$X~3AP<)ÝG%d@ni*e}$;nQoTJqy3[TjRb"$Si6aMMVfc6MJQe=V5吥xJ%Y_ЕYTZeroaKa;(Ҭ7zeJqx"?V=SxeF Qn$ի4Qj7cFU&;2ԭG)gLeN$#~qXRXޱthۊedjҦї6>V$ז#"qg8ݨވ\]KjCӹ3P]3p-2?/؜ Rx=(A mK+]X 4ADo*x^T[Y\nRkZă{J,cRȚ02oߍE3KF*%*gA}caŵ ;dNf\j\ R^ؔV{$$LYF^Ne!#Z؏#kO_i$#Sc]cRڍw JM$h}u9XQ{b&Mczڍ,*wc)jǭJ]$vGZtֵ-VLvq@m8*vkcI- Tɥt1~zXq7+jkMq{uly=6q+8l-H X[4D{X[Mc:ވb+8ڂ5KCΏ%.ִ/&q]~m,m+=z wWþÊ a050.zs:ǝ(nǒ,΃ 4NЕY5ކb+86$wj%59YZRMbRjڍ̎(7ӀI+0m0igZL% r3=ҏK>isLa ;_]Xj+#G#*F=Z8,vcIlZ9\:P{;zS`Yq7*+33Ԧ20iU5lo=l&q8l-E T[ &zкkކb8N=崙:x8Ih =J9ƄBܡjNXfgI(:w$հAzHaê o,[{0%L 4ŮU4Ñ2*q9캛$H leF~ NT&aCiU/#XD2hٹKj+L\ w*,l+ZCUaRzXq o, [z0>@T*sЈY&ۿW*RRKvq?L2PjF;$֖@L6P#ynmnSM64~tcFYORߤma7 32idLF?Wh.Uw=,,~cI; X:TS+UbR\zpT4WYW:0"_Rf+|,o]пGUSwl<\0n+P*0~Ml?ZXQ`B0r3Q Jі-KodaKb 9\-vjPLun4 }twF$Ֆ@i-ѱQ 쌸cilUgchKAzm>$魬6q 8l3*Ii[Xi h `6t$ruu$MЏh&x#}X[X!le"~oZBiﭸXW/ȜؤБ jZXEEF0P!%\]C_dPZR5C-V[$WEvG~iBE[brXEȽדXih: !>ܷhv{+Q%]Z\2]ՠ\RF} їGS .p/R ב'k6ƺMFˆb'8Vf1S<(7zAMV$wR4n>[,}G$ٕ6ьb60Zϸ'-R̶mP%z=Fa+8l-*lpqUi&Y].TQs/87tAd] [c$]͎#X0W'sOzrilYEn4㟣y+&L F 9}jSY͸6aK8l-M. `[T^n&BUf{±$:g.rBJ=PuV۶V%+#Uф7 dnhǛv8Z-=.3KrVh$|Irư}Wx::+w`r\:ݕrlaߦ4Xr] ~/1Bf`?LV\X^3W=#ox\u-aM ~4^]+G0G)ڙ=>Xwd}0cQyuR?*5*֤u=Z]޷/%ͳNG!/֍O}S75؏Z [ ,D>}Aܪ񦢓Q0R- sQ7^_&s{!63=FԄj]=uR? WiJKl<++geEk _z\au_gU,)f&u\/WM]'^D.NG!81q뭻UyS[?+E nɻ껪$ʋmַi-2ȡ"s(N;8w0P;Tԣ"ϺNGU;!gT)ZϒvK=QSTEc=Z[q؏smMv5yEP Ps~tM(K>񦪓Q{ \NN;'D\lW l_HJ\|HS"Q$T\69X&;'5wo\;Od~TsHQśzYo-7dvkA)HG-tR?JE st4ŌUyS[?+{?jE )8CUyS]?E$x[UTwKzuG3O6 w'#QGU`!ayȴyS 4S87?KE :ɛNG!?L9yثQ,b6-P[?KE٩tLJRY7]3yÚnFvW$xJ~[&n'GszmB'بi m`OLѡwxTз"@0ܑy#:A(*2J 73AgcMvFXϚQg{aajagE&6ub?ly;*~(E(]̊<*'la ᓎcUac]'F6aL|m*򬫰tt {ʻzFFxTY׉}'SbXDS܋A8`UYWa?l`+&At/&ZZ}Wg]'_ƶ3'Ml<1YYI !Bn3c'Q !L2W6EC㘃L YՉ QeX1YGg|Wg]}1ue1 ,b7ˢ*쟉 Q={cUYWa?ɖl⤐NJroknea?Ilxh*~(ffcUac]'NK{vlڿ[YO[〽[ yv~(x9N`nyUO%bcsٰ8ľxr* ra C"ϺNlDHd>"ϺN=g'9$bUY׉ GQ=ҎM.H_ȳ~)A4b ȳA5b ӥ]EuϰAa{b.;33绊<*[a aL̋j wWgE'Fؚvl~_(Lrhs Zz j،8 e2!N6 L|ūb@Qg]'s&YJd|o`]:W*64YWa?(Uֲuiyub?(sZE?S*XvW9[ߩ?~Ȥ!r: ftj<*:o_@!WQ?RLOاwC *3 :L.񬪰o{d2bL_݊c~F,bkbK%B~{0Gu<*짌x,B;wnQ?d%jΟRc.-a|4 PFnOQ9r>fu -Z6CJazҥ \RoZqoxVub?$^-ueDz"8쇼["-?HOy7 7Fu#PsUY׉S&ܩoYIuFSr*;dKdБ͇:Nއ̌ pe= jߡWdj )m8^-%7xVtR?-?h/6lH )F1) r~-Q^}Q̐zwyub??/a}o`qSjߩϪNIMXذrƣb~CjaPK?qazN臼L;ϊ)w_ڕ`?(^^rİіʻ<*˜&(5Cp3ejd~n(:8X;ߺ4Ϫ1u.`$dNӞ1T@ T&pEh=LjA?RϊNTהK ƚ)+Dj>5C݊þK !.cR>SQgE'C,T_޶Lb2CEyd=zkf!?dj#J1O{-Ec= zek=#3sRm y Yߴ{xŒP,@P堶rP_gJz, u J5ɸ05TYIK=zHܩdzҥOX*-'l?§KbXܤz̐©KB'HJ麚t^O! ߊL X/f*~}:3כZ<)*bHz|}:[GwUxrJ;X}zq_Yg==:A%Ɲj?Iy,AM:4jZI<:HLOe&;^UYSQ:FH-^yA}XzEdޙΙHxc CI{ njIy,t_A۵A3QͤmO?6&qp/LOIw ^vij y,Iu_Qͤ -wOST ԃNX!\l@ϚN*$5oܩejl6^Xf"2  _ǒȅ01L+ţ y, 1Kޙǽ3}-6# Jy,7hn՝_R}ύ/t0o} Q`M|6zN$$E=N-T_Ƃa-gޠq_Pϯ|gKRĨ\K}zwxTTc CQNo\u-Jg'XF&yaKsrӛZX(GO;V:LpHψ\7H}55XnجR_am>]=UTxcIzc֩kjLj]KR#Q(`@jSgME~O??4 a빏i ǿ@j?}WM?cuݧ.W#G?pqtH?hpO????QOsqE3}2xOhpև}9vp jF7O͙q??eV> yg1r>@YN;:Bؕs[*%#p}-_߿2H\K96Ӯy-'gv}<WMWؕ=\xn'̃ ]X~) qcz~}])fwQ_s$0?QP.&4NrW-^Q,IJwGi_qeX+Gq%b$ZWKԕiGrt>uuZ~UmE,YjmIݼƸM}𸿯yƕ{ݴןW ^k9=GRJocו[1;5Z/ϣws0?2y}}|ѼK ̉/+c{-]v~}{ppͿW"jJ17yd#s63$#I>\^gX?JaѶ㓳Fzglv{ߘc}Ӯ(xmݣrHwedH=Js(<(OH1o)G39L@0 r@C-\xy~\qif~}_0êdS d#G;oL/"g,r#qu%WnZWtd$1vl|l17_?H":M cuFe*1,tW]6Ao$n|[v&}ܿ/ v~?m @<" CdƗⰹ{T%mۆZrԱ~'ܪ7)̍rei16n w3Atׅ[֖ݤOmjl^z O4U=Kڪ锶;gY];cW}o[}v{R Yd` qav7l}@ TldXu.>r>ֶ="o_.Sל)]xBg5)y!9f k kvtWj4iuUK;g ;p̋wkE纇c#.wq!7Gola}Wi#`\95^_5{}6g^ mͩ7&vq7&bcp1͇l-j6>WR/|=|FbUg7POѹSVC`=5H/Z4mD ~:_uDz'XSf8[- ?ލ?DP­*42 geAX%%1^zތ] iv5+Ɉ{s25\8=ە5͏kf ͡<>*Bv#nCׯ|[_S**#da6.7Rk<^0vNo]ofc{Au mào*. c.rb:ûw;˳/ٙ?cz;dFUޯﶾ<~+slʷeccsj;߾tEKON3r忛143e.M W,lR#*LQz{[('F[^L~^/4|[c#̬&+Ers[0¾'5A[ EUATЄ{~}Yu/ibNaij˄/lRa::axכk h(Z` kZL\k_=Oգgi͑y%ݻc& ljre^ò+5Z6l;,{pLVfpN"]('߷Kz~9um\P` rnslj,?|T1p:@yj[z5M7'{LߖMNIUfWqN0>t>$ჄG5b>X7AO+$=tp-|"~͑Gkc'{k3$|>e-|Cf`4w|`>+tijsڂ^-B\sYȍ~ɿVl}_CvwZ߷VvunLX_mׂ=TtlpXCf33ݾWZn6u3~!aƁKɖ6Op¾z9WSV&K[Y\ Ra܊UMܸ+մ)6+X +Jf8.Tg/f|hǚBM\gƁAK'_7\84.΋lyiʁ~.Ɉof?Ksi<>07?RP MF3mX;1QcO -aECHuF[Uh[V0hYB+zYXgqѹ 6]~wΠ$ c=ѻo5֙qPie؏p` [aci,0R`affV&B'42&ή180"cI01He\:NKc I,*#c)*)#!P7j>)T͊":NJBUe½n8gUN|Iv!Y|HBӜHcZof,28cI8#!@tpήIW\f!$xb&S-<.Ԫ,2b)8Më=][#_=cZxqdBRqn&#q:`^ea{͉"$1ZY7B)wU"s\fVS.K'ƒ(M7 o~Iy;XLy\!P\apn'! yY`}`TB͌0Wu{>oa-$ON u_ \O9\"9 S3M(tGMppE~ތj=t\3SNzwHjYC[qPc)}eKAn -r`NOp2M$ofy2#Z}R⯇kn^9otujhy;Ìdy/YVAS-*~";/{;Cb۳<ą5JBg8.ƒ\sU Lӱ N6k4{z+}rt>5RB8B B#_ vb7('.˖ˡ`[\eKQ83sn~2h(}2 7uiXXU~hd1?h =]N]A~t8,ΚŒdJFr*N80|RR^WΤdqjpE`gfy+j`fx6Llh^8fb)pExyl†HU3:of<ٓHAc;_ISP3iXjDUhEg1u VW՝vXd!<~E >Nt"mN 搷ǒƸvc_<.gƅܕ VXs85i u[/pv$Ȏ%gU%:G?$jp3?I/[kNAzq5?6XʃVcRG_i\Y_"LYގ#K6;xx)gu`-@ ѵhYtܨJ>y̙Y\:c).2h~3z;eaEBx'q@](1\4 \C}ΎKyt f8 sWyZ;L,I*Z[xY3 , 4%R?u uSG_S#˛Y`c)_ZS;ipY쳂vXlMΈYba\*ht9+ ,m!b]񭠡U \- ,.}IaH;e63N:<5*Kcqd8c)ȈFR+Lu§ mxY`cIfQ^W|#v]yaVihy3Xl a;z:[+qlqh.-# ,-rj&5\ȊԵSپj$ ,oeq%欲xX1 Xǧa*}*Yɛq`c)pEA|#VgcU?Vjs.y%TeuʪF=uۛqTc)p'KJ)edUhXy3X9O^wOFXT9ɹOT2U hf $a.;(>.5@F$M&oǑ%srA~ Wx73 o,.8Ysi< ϐYenFXl6#0_YfYKcwx# 80\!a=]g&VPIn;3 U/H5?35z4 #dRqfQ菥TO+_>}?9͠*; O,'ߓ9PƩeTBUN:+KG,M<*FO,FV_SPMÊKqKql]ivj R5iF_4sO|&Hx@3iX0+>RucKr;50]ɜ&< 2%GUag菥+jI~Kyɭ8.$_ϤSI L :05٭8,T:tt -;p2N1q(IclJIvX\Eǡթ[/Fڔ6ci\]n-oǑ%gI{VgV}'&YCkYYTc)#-n8W;80%u'zsmǕT8,lg}]QUfnX $}%QGڗ([ڽW͎#K%x;Gm4R9HEҬt87;LG,E橻KC1tj* ?k:kfXfnX{Sp#\zfŝ5Ld~^8.2 >V8Ƞ7gISof% ?2 '::5ń=F[Iril93 7,m+ihY[k ՆC)ϤIYdcIrf]ϬT.tQ548B< ]J${;OX6iaD>fJ2Nl8"1ydIUwT [ӨD4?WfYRqAʑ9j\{E|Î#KѠUMϕ~cBz&Jf _jn!&@?eWmiJI8,y =' hXy3OXWj-+qsQ.3!#@E&c)nG!kpz:X=z"f ,gq揥q!d?BOJefI mL}{T͊KruJ~.Y@?+F'Cwd]f^X[A7?X.^))oѡ%ҕqdxcIl[ @äP2BK4>oLNh;8(\AlHtn]TފKq9C RcO-SK5t4R % =z\DF,P+k&TΌR*K~5moMvϦAU伊R 4#gV -VƁ$qDžF+-lۥ8l|)pE]\E}$0ڛ7t?Y`ظT YEuaNU]8F;CYE2@ㅗ}ot RM(oǑ)2 b34 xR^Sf28H2ޏ݊cKa9$heq%\_y,fS9\F6͎#Kw| I.|i,oZ؏E?$'vm]SP7:[4\V80c)pG'dN$ˀ ]{F4;%kCqd8cI2lCdH jaKlӼȔPE?$hptKH+="d$]4#}]pRXf(~| A3i yY`;|AjlMOG$Y4#a%9 v>X\A筡՘@YGYa5#a%Bff$\El$4tp I-Z4wJ: }}}uM&gq%*bο1]S }+fDۡ[qX8ci ?ѠKZ@Vm֪0E?"gH 87eX-ITyqdcIT/d I+WlV^X[>|k$%f2f8y|A2Td@5OJj1IҮEToQ 4G֍]+S+SrVXkn"KqY1WW3"˕KhǑL;}WȒںk%W,og%'e|3#jڪ4+HLv#s$) A|jU6KCqXc)2x$vtǒ\s1'aN |ۍn8.|z2J :ljF|?zbfvX\O&s)) lԣF7pR4~-kpQ? A8Q5SBÌK]lKIY8!`;o)\oeqx%ScXGU*GJjь\󁈙?NՈ5Ro\hFX.t5Gww,Iet+z5'G?"tͅƩ7:W穱,0$xbt͇ZW_xV=5q\xc)0I|H̽5\DdT.of4rJMDB4ߚf7pR`bFƠp`3cnJYގ#{0$OW*\H+ xac =3=$yr f5kfB6h.]cqdc)29e^2c+lf^X,̥G]NʁI˙Y\c)07fFPŠfct*MތK;LmSLwwyTWR]Ntu?Yd:c)rgQ:H++ g5Cll䡯oc8|A܅X!)A҉>غotha%ɓ6/J j14ClOlsIJ'p%Yc|g~_Z 7+mXZdS^Z6_XGARnK᪆ 2Ŕһp]9VZۍ]$w<chKo_y[_i~ H3Zh)k8'Dߌy9.YExQtX֚'u\aH^;ևՇ ]/sYs )W?=v%\\gKK]l|^h*ufX=8}xL%=9-I[yv_wYS;#{87+}xd {af^˾_W|o-46YfSӢam&(z+HX{֤SL =29fP]W]QΌd\~S%%l5w5LfW:`:+ @X [q_Nef?@pI\S{qdDƒdZߝXc91Y]agIK~H2X9Ag{!E,qdD*թFe*X#Y=kOΑ Q?[qTRTS}\^㼸ƖEs$NNfa, ͛P*3 8.Ȉ# K45 .{6*5"30$v .HK^P =aǑK)Upet ϩ8. cI.Ɗyw\yf:?uV}5E8a,-~µ"M/ =F]VHeyYdRd60_jIIl #ȼ˳$68-=|!*-8V̚|Rx<*ÌuK8 -;aE"7"30$ &&Um[}$8. c);C"5)~96),{6*=30wJnY&N貅>`gƁJKoIwAsm)q_B\'L%oǑLKۊ+"YbY]kPcx$;`Xj:e+ G=UצGE a,E-¹M. E1 ;ZY\,|A(n{%M}g\x2;HX5BrIS_PDt{,8.cI.D&v=^x.a,2 c)(5h- ϙ8.cIl_tԨ<(73)s.F7_Oc)d ,f%[r}pR܆p~v4.g<,2$Y[Z&W$-mQlÎ#K©k yѣeppk`y; /5bd$޿12]/upRPOn/ahKuf߁$XM,pf{^~>V$IJ4O)!XP<C67ꂇG?Fvk{`52HK2Uގ#KB:H.8o<` u*y;Lo,I`a[S=VY]qTxc)ZW5%U k>,.i.]( ~f׼G TŒKSʅ<96yaa%ɳuEdTM%T8{O!Agg菥r !-:O>hWފKqվ2 P$]4rsvXC9q%&eAm +RhWG.JqXbIl[EO]xh\y;L/,EV o)Fx(;=zjdy; ?,Ib!ÆMd{:HϙY\c)SQZFօ8sb|O}ٷ^X;/=+%٨Py0N5tAv^X\V5&gHK1+08LZ?"T4=h vX<[5$NWֹ^؛Y`zc)p]]DA:ufX<5NGEiZcq182Y *WW퐥J}Ж,2Bǒ\I[]z~85ek[XÌKվ47 .{.WO{3 L, +z7 ʘCخm} z3vyuJqe9?w)Inr~esLjLM,-ܻoUȯǥrUqd8cIwwEr.0Y,.W5B͸yH]0|?ר!9U;9d &gQ돥eES,WQo3clҸVXW`2SCmv={G?$H.=X)3ѩ8Cz3 Lg, P]_L)1 cW{Ю4АSR^# W,Uۺ LU7㞲"K#5bwv %9[gaꏥ<{x*Hɽ4kP^Bܮ ƖplB̶"DǂĨc7pǒtcWs cNooƁ)Kgnv†¿PK:A_tRQ)5k`"@Y{0,yvnXfh& 좿#Pmw3 7,Uq/ՠ.d}Liloeq句uEvbWÃA:ɱ ^oƁ%ySN2bAC^Yd:c)k 55LRK}WN\&ٜH0, RM=Pj2pRܺ"nU<C)݋Lqd[rBX6MxLԢI:}\S%zqP c)nǭɇfMxŀ5SЉVKgf0M%; /boǑ%j}L8YkO؆^`V"KrΈP$X3TB Ss{; ,EV |ˁ E QpR^`^͎#KM[Q^$Q^ǎR{agmEyL%bҥn;3 , fGskF3 E/D-+ƋT^a`O!ʠ~)F3 , S) u*{D E)gԙ1ZY\c)nZA]f ~.@12x}$ -oǑKپ)}"OY@{r./28: w,dCGȓ.R㕽1ZY\c)n[!]5 7MMKqdcIls9R{}پf4 Yd88|!Go5H,tÎK#SQ]o}Q.IMWC0j] +&3&UQhg:cIצȯKjSΊݺ`RXݳl2n 2nqLIwgǑ%ɳ}Tឱ_c>8}Ft{;L,EV gMB엄K_^hFpǒd)c.,x|0M Ɩ3tRT:b(0787QCM|!f_]`BxF hGBg.hQ%). l0̂K0άaeMYdzcIl`ְw1`( 8N`aR{y&3ZwRť?}$00 F^l}y84|AFgC/ D¥zob:#`,E+׭qU{0L W"KռS&f*0K9Dž?}t5bZD6=_]0tǒ`)!`# {?FgfT&Yq\xcIZWjCe#XsΫ;L,E.3`_;(Ug+id93 ,wk$5`V&GI.@ᣛƪq iP /6΁6?Ί¿KrM&] =G@.bRd>+#u| 8>`G7 L,n >BJ9f8*$Ja͈j=:_hnAhf`D{Q(Չ/9z_O?D:RS NS9MMx8)=\3vZ05 xP 6M r?Pfgfd25bAf\Fj!$ݮ a\9>mRcvrAuxNfg?i h^0+oVv_'(^:h|έJQ`v򀽬CwaT-.㲭hEն9 uy GdvIM#A}4k]M)Xk[AZ C?ߴz>4Wz0L״Ȱ꼏߿;==<«;7Q*QiҨu縆5M#_suϸ-Bad MRޥ9ym9'şgǏdv>#LYfu0C[`Ond|ցawYOC>/\cT: sqO]Tpc#F,xCؘ~zXW漙fuoϷBEOۙ;ˠU~d+7E_ \%c/88b.#!ә"F]%FHfd3fYi3[,'qB`L,ٮZPZBb&:5aʬЛfdL, n':FʘW:r, )P: 2Tv1xBMSof&PUj7E2f> ̸f!&֬_v95nq.+ӂ* ީ"3&"Wܸ0l)U'F8d5v7$4!S8#ݟ=?[%{5E=[Y|٢f8rwڕ49!e|YY+z{.Ē[},z:]+1D[J98.n+zwCgdѠ2?Yl1ZoQK|<9kBRǮ"ȍV=_z)'S"LqjbF;[3]h܍U⎝UuYގ##l($猻N5ܸ%|޴[jT%?ϪI,0#bIp9Iwst57! (#7;Vz5GP&If>G!q ChR,ٰz+Φ=sQՙO6zȤX .N4ibs=e\R,%KgHHդ18aQFcrE;r FY t5˙qBS,٬N ^, v+U+eqg_3CndQKV,f#4]CDَY3<|];XA)WEwѾGΧ+WC?Sp33b劝^UwoJ14lӶ3ڄXMV.+3vL ۘu7;̨X\  (4Xs]= VԾ]99f茘"Jd҃`!KRmd)"rV(Q FZ#$ӕv ňP ug SpլZ p}⚅XYN,#䶖L+~0%UUam$7ƂRdSzvʍd-|ʰFCmv`$*`HmnשNUk.oG[XFm K 5Z4.Œ"&_z2KpN.^UIWVe_,ɵjp'w)]&ë>82b)r}zr-/&v[ S\ whLiA:N1^Rp;z5(Dձ\8-0sW)s/nANS3Y\ƒ\[G"4q(XTIfJL˺mI ç,Mͺ\5.(ƒE$fH?sVz]kNFشw)h7MF<؂Eb,E/Q Y#U f}E)UZUt۾.l =ѝ]ގkb cv٢epe 2mѡּf18'xҴѡP%_3oÌ# 2ۢe`4pm]ckjp. ]8Ӕ-V},DNIPӳ't1[7ϪFy3Q_ Ei2B|ܰ}̗LZ>t,I*ǕĚ{8nqk{+}X[qS-q,ӡ ZfLn rCW vt'-j,Xu[ڰ4+4u'(nAǒe) OlGoJ`M>D3X ,L#&c-Jf>> .3S vf;ı$VL&Z n܏|AP]8;HŨ[:v]Ů]㖤X) ]q8,V\p\6%6:զЙڀЙgSt,IeikNRujћچ7tb.q,> f!mnÍ6T$!ସ{hkфKu0~Q/pƽ(l@ǒVS~=\5zӛY`n@R`a8 2yfՙiOюP[ c=BL$Wx\zUވkvcVْhT:#@Yy)٣?KՍv[б$,#'57?/=oag K#X rYMf&ʥ{vnyOJ->rW}CGP07;Y؅%e $5#N:34܍suahgK'rO[Ԍ[MVNXKJQIj0ԩ[5䗄n-edAS`jܑ`|vÎkvcVي~E MH9-qy0L܉%<̥3'V5cH6B1^Y&E vF[ű1990~_S3q72Zl=y: 9ɴWl=쬆W 8=(&Es7U#MˊCb/:'4j :W1_[&vX<9\$N,yPȄ׹' wm4e5~J =9IWff cfيNbYqej<#1ŌL8.vcIXlIy(+_y&wr%_ю#c8"4Uf U%ɭM9 Wl=xabN<pOY{n,+fVKkօ%G.kJJ||i%Ϻ{؋%LvaYc_Q]9W&׋vƱ$yr|yP/+<8ԫ{ծHc (mIoAw3YrdL̴Sb6ӂnFѱ`b 뙁=D)<t!Ԑב&;2и-Z?+MIgIkMzŎجFq/:lUk6zv)mmeK:3>80c)p p$Ǭj '/K vѱ$Yzɶ1&TښufoiוSLǑ27ݖ4ьk}Fh0DK%R'Yڍ[ юbiK;zr?pK)ē7܌=tw5}dDϬǀ7ncٶ`n,\ƶֵDk?5voǵ ѱdpvMpEJd/yj)6,,ci ;5c_tj:eXU EG+X+74'>e%l{m;>X0YxI3%&g>R-}0o5 ѱdld1jm' "_Nx)`K T˛Y`nGǒ`[ ݟbWj<w'D826c)rƝrXX\x>[;rKь&O-Kv76g 3vVV1 6ɖ*4̀NʔK_jL؍%ɶbN-j,lLk̕|*ҹfű$xbl/zV0n6Rw{qHXWj-.$ܛ2S>̬vq7:l/8 %w?]JهGvt,En+Q zL:TQZ/--^iG;HE^^rba" *)oMo>[X48)6#4w4\3)ұdl20tm&,hF0>82ciŊ";߷)x3v\]0q,?%gѯړ6y#FThDJ6_ziLo5qŽt,,[7ٙ5h3tޛ.>82c)ES7.)NVrMs{Xqjk;nQi-vDݗZWoM[{Yvf,,[15˖4NU &q ke}qdJǒKڜàܭKuiG+]XG\',hSe>|Uz8w":eSR1'n;U}`la4 ~GJg%ޘL'M gA%KqT:/=j8oC|Y5dy0܏%ȋ5^;zZN`F{nIC~ÎƲZe+;*iiI|oufe-`F;aؓ%fKb :ZF%NR ޭ,,wcI-S/N RƎJOyҮCR:aǑkK+ҵj143oKaեμΘݎ yM92 n5 [ұfep}&ݙC/.yT ~XY\nHR Τfܐe܂\"ˊb8be4;)69դ:͸{hkˤdB4(' N8~Yft,,[XzgI''N&9~q`b)pGGM-NM+'!.uyoƁaKm2~q9N85\MތŅpƻ|dܓ'R(VVK6VM Ncgޑ[]Fޥ< 3X\!>- ݙ{ ʓvT_[RƲ0MƔP.նq7V)cJ 5ŕ ;3"K\b o5ѱdlby4#l53rfiILkWNtG&"#SzzƒkQNkସɸLeE9~;/UlUft,U,x=Ei&]?82c)r})R>eVϹ#G-E'|8.6cI- \VY=Gj73d9h?Mvn 5gin3Y܌%ek񋩻n뙑MyFVf{ѱ$V+LF0x) EsnQN4JYdERdfEMFZܙM}vU7'6vܭu ]FJ>/Ӧ&{;aq[%H,jU#GtfOl=8*vc)pY.ɥ yv׭5Qz;mX\d52R SC`/\{3>ڲ h=3)|G97(gg5,lJǒͪʽjk*Y5 osO:7tDb[֌aI5P<-G>Kcy8-S}AW{ T[ӌlaSͼT$PhY+f] SzCg.,hdړvÌkOd[}EeQ Cv[ұ4r jpBY,IY h;cvƱSdG°6CО,Qy++-̱붶Q^f0]jwcv]LլڡܳPXxhSNkK:ގ#cK:$gʗ&M̴atj0)=EvAob#g:xiZx;Ud Y5#/X j;[/g4ٽŖt,E?0qG@umywqފbG:ڒ9eʍfy@n}wm]g4ѡ.WT3^{Y t,0[ yzVNJsoդΊb?:Ċ$)z.w,3Ι,f]j յ7:vv正9s ێ`Q-k3nJul=̶܍%u2YVl)`N1swˮ*gaKaêTb$ժ)m"s/:$*@ SA@Ws3nJw&؛qB|K+J䩺6Pֱ϶[qNt,([0YIѤյ*rҸfѱ$xb$%M܎:amFq,me6=בk>_մ7Zގ"B5Xb^2܌T m(Aǒ*L72ۘlbKGQ&t,腣!PtM)S \ ;m; bm}k"?|`ηW7Y=wk]hyG5:3ϗ ̸a:lTcz NJ wVJ#YdDǒ)jrg¥dgd.( 2ފb82TA.ȳݍ{q66qgS^2o#Š\ Mu?%aBuw^{ iz;U܇j̻Frq@s3*GoƁ K-Me[h.Awr+2??)8.c).݃-k~*{q-To+j03OծlUq"BSY Ft,0<]e뙕^܍U)vf[ѱW0+ßsWm꧀{9eeM[i#Wu/=ULzf?,S 3KŭXY6bz5pCѝVs/3U?br\jĴl>&UoƁKmkے>ձnit= w#mQ k^П]=?|w͇vq7:lWeԮj_3#{MYÛq`FRNԠu9n= E'NTJs̸mܒ؂;{55q7S.i՚ʊ6>6nه?n*oǵ [ұd:SQH $'ׁo[~bWEr4)-{3VR`=qS͎ܲkvcv%&Ms#3S)jWMQ W4z4jܕ%ɶva66p%Wd@mˍT%krx3lNq_ژN7nm]ۼVG3ns|LݕOtvn:jjڄ=XYrA.6Il}yΗrj3ܑ%pa4mq3{[8k#URŎq,K睹.~2&ipy%h͹qpJÑsg  I3xUfhr42)=D?'I63Z7Ͽ Θ<nOQ5:&4l@Z[_ԷhU2 9*19R]߷="[WgшlmVARgS#w^/\4,8'Cqe4.c }?a.~C!) % 3ڗͻ}6Uf`m̉ ՞M3/o:u-*^ƏϺC2}M=)=kQ2`\uzd~Vgm'_3gɈ!8̌vW{UTw?NFxI7TZj~Vk\}/ Dr~T=5u7xVs"?*BF's2ߧF$Vț Yqa"؛qCp~Ж:[jm rlxq0^ge'bl>syq}e'b|0t;޳*o+ga!l`).ؔNG@!ɣm:Y-o3tG*eFad+ʻțNGiˆ`~( v`UeCuE,M~AEwnaq?˴⚤W%q?zLΔڹM!ӻj<*:ݿhqo-v_lȭ`_7DO\f?&_$DfҫkJFnl~{ STw_?~݋ R5yS 0뿆`? 7.Ms=G<:eqm/ry.́]MfvZdlԜ6Yz~N *JĞǘuySIn8|lבȟ"mUyS (o~PAϽk>@@mGV?;ȏ 3_7"ϺNGRwl;66Xlti:.O.7}46 ݑܘ*8qʛN'u0 +|u'I,qH.=k(#d o;ɟ46*kᮘ: (تhִsSٹي2JMm?k:$6 'P[7ajŋl5yS[?Jlm_MMfr?`RVaVRbU6 %ôIʛN'*ϙdE<8'jap.;>R!fO>˻Ғ{`_(%۷qk)G) CqM_ى~U$V7OjO#Ν0Şm+W(aΌ%Ga*o+{A&Yثؒ7GDm鷚unOLd bZyW7%n!0{U ՝OIqL`oUyvr?&m '&rwr/zag?ls'̛J򦾓Ie|INf]9w?_侓[~ ;QBek!:罓}]$P8$l?5|W7)m;;oNcyasٰ"?~:8 س> etYN6'+C .o;ɟHޓ˹䏒$䛇.ՋY-}˛N'IC2-*wH@Q7O!䏺!d$1Pn㜘C)򦾓I;d㐜F>PjT)<_R0L3kgR08y^ցy4]UTW?'O_ 8$LsHk586wڰBQ7OJ'\ȡI)c|`n\ӹv$o\绺/ɟ,wn;+Ί~J5/pq[{o:I܏y#XtnYWҰc*~d)˴͋{ڸda6p۹)ɛNDA(Sv/hϚNTRocrsUc C0S[>0vzW7՝O/k!l`,EWwNdB,."ϪNT%՝ۆ~~LԾQES㺮wnԾa%gǴpV7c. Ng9S.!t*NTf>e6'եUMuEsld^`wySYaߧ:" Yg-'SrPuAPgQ? Q heaH%MU |lq?F0crj)I8p{3)Ixlƥ,iai2򅨋(ƀodKbN /?<׍Z_RX (^RMMTV`:c)01 \zUEvv C6TNEo*;xr'gR0bGAN]]Wdzc)8|lR,pRdlj)=S6TMuG?ƅo܄ӦZ|ɳ ~,]`sü0"qX_׉K?z BZvԥzS7XR ^תÌáKb}S08ꊌE/u`Sǜ=h§ˍ[3u'sx1ѫK=iR:ґ}/tRd!S0x óC|????4 y=ٯN5_{?OUK g:h, O߯T-%u;DAmJ)v>RlC$s\9mjӹjmyH6_6߯E 8;P?Gg}-fp۸bbڐҦ\c]GL[,]ےg_xmyS/L28 8@z@&{M6֕l[_F0|]q\Y%+P5o/3c;{{Γs%bRvW2m_~WL%C C dww2io"|7n:m[`4y2҈M@h|x̞%ue@;9'niW՝7ն_ y5^!q9Rh)%7aßVMXf4sՎæH3;gKGbNi{]ApsJ{Lz5pMx=WC ? ;ؾl:L4gmޣΨU2-?h8*ȿ?JOu?=w'PevHqeDivCd!n\Cp}9H"`7+$t>Ϛga7J}dHZ2kgsA+ɖJŗXj _˂㻻rY~e5c,v|-›;YKƻ]꯱2o4{VY27+;N~δ%n+9n,]N[ \^ \U{;MVE:r6MHS<#W|&:~QFZCGY@@_󆌬HOw$$\F;tW--;@m1@ng]_9r$+?'[Gf.\G@_82M"#W<ͮ=3%wdj92*'yӱm@_@۳#Xyiy=Muz8&3oOd~٤+gf'dVB+9n #T"0Kjj΂y.n;jy!ɁauEr}#G9 /^K}$: %] dU {;oJ$r΂Q6]Ydj7;ϠMupnGY k \o ɗtnܸؿ`rh3Yg/KZ{IW~ΓOӋt!p{pڬbMKIWrh'`hߖ!snүnY9tzbX{;7]qdʑyzbO,דy%kt<9wZ۸vq+Ǎv>qujcmLV)j^ mP+M3/| ȗZZWlS~ث`4k`Q9bl!Xij+cgm^#ǃ0];lb\zb$qgu9/m. ҍvs㶍-bSK͍{c;dm$ v5c( Qy lؕy̵zrF5Yݧ>#|IFA[h7-[Lh΋H ~[-:L\zٶ`^ \;2{na&l[ώZVߧi ޟ4Oy19K_c57ƀ/ǐ9o+lZ9e0=91/:2*j[s*]&5g5g&;LR ﶴ5jev5IլWW]mђayX\_'w3 66g0qgFFʐvey^ caf_'Jz~btXﶨg 3DWW-"Zu;,j=^OlEu?'^6U4|[8 ?Ҽe#[:oQLW~&~Z͈w%kg~}eؓ?dzVzb^mެ>}޺2Ư|[%"G1}7]ړs<\EΨel[yŢ0֟. 97}GIWq. ~cNwWwwZS(MS] :Ȁ}oԏ_/8Tl1G v<2:OR"z/ 'm}5 bgm1l{6ㅊӫ ^>e^?qr55 e髍g_EĜV]AnDG~g@]8$٩d!|b)fQq;%%Qer j5bAGwZ>.[c~$M!cmlwAcoqټ n}5 jX`ʠԓ6Hx[y @Gx9_ﰖטOoK+cY.w_I@`KTM&BwYq<*yаfj:W+Ձc Pbڞ›0쵮dQiF,>.[FFrs$0n :A?ZmCmxN5,[Lgz8Nv ?dݕw&WqN0N,awWcF=I{'"u}p^ͧkc=9۷t=عp[<9jc \f$p}}V=;?U2PM /lk:DFL15sbhy\ׇ=cuguW #}.}t˵=Mu%cBםm|X>Vr_Sg2={gׄHJ +-aq)Kr'%Uq<Ӽjv[Yz]-33z:Ff$?v; X*dmյsǺohƁOKbS[#KhkRvT,$-C|8xR2V uV{U$wR = ~]ZzEE,E%&8\-``=nǑѽ &2\< o]_jڻEBX?RvT{Sse{t|j9+ ljT(=kxI=_rq{f$xb.pF|spd ;"3 ="OU qiuEG80bcI°) nrrw:ͰIqdRdrʩ0,Kˢu,fS{\6;PX<9Yn}JPko80 c)0PixzJ|}]3x%¤@GKc\zj>y+X+ʥHΨ&s|$kly3PX*NUNTIBOVot휝EfH,I{lʡ*:;+eI]5GFLC,EGQo4.[YYX̉HIv^ߙ"WȚW4nF7ȫKiYVN>O#4GF8t,InG}|?ua'Y7&W;D`8 TvfbҌ>`+E u⃫c=“GvbɀN's?EA}p9,0R` g.u+ e,`]ea\-Ğz(@OmZ5g9[Iz3 jRmt5,2$ >yQEvvqFK#vJ@?[+z]z3j\W!dTeF {;ӳ$NK0\*'::u|ӷuVgXc]tv$ Ӯ"Vf֜9X[A愎>. z+%1Gѭ8-9|Al>?GD2?Jy14jcBӱ\_;a,Eׅ4ZbڸSf%{Y`%5̕2ȗFEdge+'zzboƁq1[cWuCg&m\z,a, 6Np E,/k5vt%oƁq0:g`n>չw/7$aއGQXIe>>̛2\P_ʑui vbIybxq=]g GőXZC%t\.%#ہqYd|soJREN /& ÌY,nVF0{e ,; rS,8Krk50jipUsSǪrM5agy+"wuYvΩd䆮\OG;CX$ 'MF^ٙ<80$sg)cր* yr3 L,V!0hNP(J.b3 , YZ5 ASaתrCqd8c)rG'UIʡ Gl܊6Kb'YEp+sgP#n,̳gފKzc\5t~- +< -of<:%<ؘ~ot4GMfJ9 -oƁ DO5:3v\BՌ1 j7R`u 5 V0ÌKO`syjhy/X?*וrCA )Ś05Zq\cI.N@ߖ\qdgVr{M,2]$\U3opf|Gv\{UZ%؛q`xc)pf͡d>u#뼢X RM5I Go,6sGDvNX\CtuOFReIrVs2,󞼮Fuy]AE,laer S3ɼ'K^82<$4I-RU)JތK;:騺=)%!YUI7tǒ`sT_舿NYqwPMn5YqX8c,IY(qǼWnKak?s\cBiSJ[Mpt3D(\W]MyNƕCQ`ͪ fa =Tn aZָjnf%|*iqyE5*\oq]ƕyNx܂uA,0$f<'WZAqUY"KE5~qjdT5jA3լSqdc)20ץdNǣCV㪒5ť?Jtg2e1\w笊ڛq`c)pG- \qw3}V/͊Kryj4̉2<ϰWKOgfq%nsf։z$3Ujhy; w,E<2@ո4cog d9x*ΊcKa+?O2N'w HOs [Pe_iN6 cRm}/~VV-s2_$y4)?kI?JsHgK%_ZPݯ[ 䑼Y`&ߎ!"g-&Ճ)i(M * dd%ήS `~*ن \w F ?,N#)VpLBg\_*!?(2&d nl ƫOj|su! ;_G0/' LV5+{u*&w'ui]E?CTƭU%p>BcҔ4[Ӎ~lE8{ղfvUdxT4a(C*Y\f%!檿sP=@F?[+pgś* C/fqV}"?ۨͽGׁO%`V*=} ul]ф{G̋F?[ ~I'ʂXF*f96%Y\d7!Bl9BC5[-^8q>'`VfQמ[hbonG,~fK~/"47KЍ80͟inN֪z:kd d%SzpV!Х5zײz 4HM#͟|uVWDUL#9f_^,2ْliLHh9 Env?:E?[b--4)%>?]`nU<ٱ5-cQVԆ\LcWE C麓@ZC0ք0[>9$J6RXE?[;Bt2S1R1߻jY]lgRnXYlIaH֕RG aE7Ldʅam>НTb}郛ڄףK0*Y-+4 K+kB6~yqm TK MFBYT:''|r,"B^*V41ﴴTˣ,%C/N-h >Nr8&3ǩ) `%+pGڥ hgk-F4?".jqE?,1dI 4-v"إv?d!WB2?y}(O G(290?9 {ZZX{,U̶ED{Lnp=V^~nv<}@|d?q؝dOX|lm⧶%UxdɇڼG?LdISk ))ӃS$:eŮV%f]$ZZ5)Գ}$;֒7x \IDKe&kEYikډPG+HiA̋@ F"wh# IhA>.-g%,Ʌ-R,4<_z͡Je^0)A#֗K&XfP{wyY؏RMk˲Hud dZm) ` ,C~Vjx:s ?bdfh TdϪe):kvOEsEf?[;GdiQs/ heE?"wDГ#'#ץ ev/ ˔Z E;ٔ~y,-i#Ꮦ&V.ziqY"iv#faVO ҇x铝쳟@F?[-KĮǓ\%n2kWfo/E%yjqE7 ̤.ޙH$M2=v`⟜tHg+2["$͞Uk5$(4$}~lI\۩ifP'.~g+nǩ\N-.^Pةqy*ْz9p!i02f7pXZ3VLgK8eyԵ̱ͼ dd%9ʖFR#N;bҚ <āM"WKŽZNAfeIAp3-(̭:BɁPK+ dYH'踬`rX\B g^,29pjAѵ>D/d?_يLCeVWɭ5k&#V;y Td%Ug V)'9>y,03j&<ޏk&y V:'Vdq dԌG5s,>%Yd;!VvjeȮ[+˔1g XY[w%Ԋ8nrXh3s>Ҵ@OlIvN겄j :BBܿϱtMяYNPRc/`WmVWpgKcn-.K(yЩx"Ԭ#9[StgKcƦggΓBIuZ^"3'@>i5 5M8ĺW(Ѽ d%Ya, {A d?lEGzP]Bt`f"؋e!͡=ؚ߰heE/l%9,:N(Fœ|^~'ْ,J[3'6s,|V'q$ABi yJzUH{n~G9pIIhi<\mmG4Ѹ}NZMB'u+<הF/l٤ L1{ƴhO gy-Aji qfq"a@@"mԒzsg^ f{^3%,0%1EK*MprXg3r!؍٦'q4[ZskLpGnl9y,ڄN Skf`b@V6M@5w7r hmE73lnQo:$g!}C#esECeTK5'1N|ZWM [u*h]YVeu 3C8f}@@$[-@A|z&phV̡46/l}ZYH't; m&#VD%pq-bPp-Ɲ9 s]'O_P;'Ș'5oL&N_ū1Dlx:9i$:DO Ƌh|X7r^/tzoO$j5T_aEZc䗗&@/WQبV'r0NJ~kwkoU˺&,[S{L^)P pT |=alE`P'bf8‹1v6O_yeq.FƵ_^c?K "T(*~}<]'c{?Sv`>䢾cɡB=p)r+uw說BB 6)1!zl|u]ȨU+MX"d,{T,-XŏR{AlIa/F7`uU.Ra\}Jiʻ.fqV]VFלm8|MkvW2Í.º*"'?f+ X<%$QW-fUy*7TxNEczime쏻^RԥZzkg~'aUJ'\?-}d9m[]M W([m(-Z/52zp)ï?Gt£֛+ßf\;|ח7 O}Yd`hG2'C^ _å?ෑ;пAh)qںj=Q7ϟ\|ŏ_"|$@'V3ߧ{P¯RkVS>xWMj+6{ ]~yCZ54 ~.v<hh6q>ѕJLj{t~j/8v۔_q~IObd d_(7SR^Obѩw{+ ~s`|w>Ub;^&>o׀^l W]ہ*8Mr58ω+6qv4/7Ke=ɰ__ -xN<#RO 0[}.%pBb04YQ8/-'QRR֖ۍ\q[ Q*IndpImE KyV ^0 XZ_O.u-ÕEfAa"?:wM(_IzwO [J4zV$';UT;?lI5-.|o}6 aV^5ي{7z1x=.* WkZZҲhrv3/~ْIpP[Ry=~6m<㲔 KʅGz T|fKϭjUAm_E4Va e˓Z@E?[R}rfr5rEf?[-9jMlNFs ,nl .z9PP"^2rي uUEKocpZZ3- %#|㱹ẕ<8tF?"sCkP[27 k}dQϖT]!N>ziBk‹F|HX*w f^7lk/~ylIui AN:c}@;Ef?[˗ ZXh <_7>cuPVOXD|~RG_xqLgk0*a?-i2} #ը&V+3| ߧj<`_gKOժfo_&2d?̜"k~ŕ*܇-@K"-[*Ҭ[7 ~IlEMҔ/V#.t,~qgKOe'ȯvcVtHg+0  E}YgK2a?Ɋj%{z2ћ|K"ן]L,oP2 [pW3B ?F4Ěܭe0rI{tW%@V\N^R"-,hw'9 d̖doIlZ9KXgb8EKL >j㫮W7esk=G?<$kz) E) >C ftc8CP@F?[9CW2D9 [kkyYT&~TZF7_} vI/z \%W[S-XڧpK/Y`̢oG.+Eի1Ҋ~RH+Fis.%⁆&$;rmu,RيIL‪+E_{K +Y\5?DtTYyJ.z \W{$mU V471›/~)lIZ%4W)XԨ AxzjvوFԺJH P0qH- X| fKNuŪI>j(^:Ђe?[q5嚄:nvhmE?4$p%C>?֫ pLg+z#E 'zU#Z\oْ3}z*҃) .!Gc?[OD%(QA4BnU>!?t"kU+L/U50<"5O #ݟ->C3$*l5EAbwccyJ9DU@().0xov,JU<9ފ⌁T7s~KtBڵ`c7 tt? `h@JZqcpK, dd%Y".UU,6FH:{2->Gbwh_hSM!*0"l%EV,ëy TXcu2WWSs]r{$jdLgK&8t~ү;t X&pVܮ.b\U,+y+3߸,*ْZVН¯YjpKM#럭az\\X<.d%Gjwjx| K++Y\fW Hj&/tW2^Ylm.z\W͹xcg+r[]$\9ظbٕZ\M7x *jН!|XA(+t?"UE2>PX'ceqϖ\(ۏU-xC"R~lEV6W X0r W]^ɎhkB%9'U{0|CUuG?$둲O_ OPvZ"+ʊ~ 5r!=$Hjn~u E7.g+0_|fArR2 *-E?[q5"=tR X|#jYq梓E?[b5qICr X9{/hR؋~lE Bs5<@{W݂ %pϖ\ߥU ,CGY`&8L$3;x+(9Iѐ7ֺBgU , y3MK+ X9 IuPezja/ nɾBYtՂu<Jej AVeHg+r]^$74=P1XTmx6T-gϖd^ C[tuRXf?l[hǣ@7~КcTV8ӝ"YU^vRs'8'^e?[B}fЇfՁu8O2%_@F?[Ǫ"aXU*{$u u1,.sْ{\x‡:-`8cpF?"k~C%F.Ū+s_"ngKhaAU"UƻY`&YuՁu<:Ka1qI9x Xd%gJEuu7Kaj?ņ.1۪"O5/x6NZK"՟D/ C,T|3Ҍ[,7kS㤇m'Lg+jYE]Ķ'=/gǒz I?YV)NF?[}zE }jTC)Yd&Y3lZMh_%#߸Gng+]CvUu<2R/E?[b}z1Z>aBSM=]+Y`gpY:(z ۇJtgK2U VC_ m?LQpgVH8%잣д@F!KB"+5]^ĻEM"՟}w.Y U`j߮bF#Q۪"~ np6u E?[˫.w.x.9\rMaj~s[% P>lǬgKz@F?[޳C ؃gj֔(7vۑK/Ef?[+.Oq1+<$bpZ]M"->*pLJ^utLg+p5W=I C (89ْJ:/`M8Ԃ=x. Gk+ Xd%٧W\~W5'k(OQ"3->C}5'=GośY0Hg+*~0Hzx=on^Il\8C`y'm ,GzTܞ.'#P]1z P|f+n_U^?SR7\߳k,2yMP/Y9 xG?"kOώKގ RQ(.U,2ْlw{-BΥ'.يW,IZ]"I$`ϖXf7a xz@'+r[^$SE`Kv_2ْ3|t'#=ukKF?-^4–UE,>P=cφtwI`"->O4g58*.ukiE7ّ[R1RS==jHXv2/pMyM.(Y#p'yl-2ْRA<@ꁇc~K#M)C ƁR2i8@"c%C T6,4q&7lVjTX6d7pRT]e?[b}vn:ӳVXo qJxtEE?[q7KIAy#PΤíE?[r}vM_ Pq@^ ?1YdYZYEI.ݹvWNNR ^0k)yJƁ7e6Wg+2'X.{ `ϚJEPw'c05&m=NݭP; yٿ Td.I,P5|?I[%bNf?[}*{.&pV.r+>a\]B.2ي-2$E?￱ϟG2-.p!5`sn!pI';[1?r* T cHgKO6!Y%5o xcypLg+p.r;cX6y7dsV-.ْ驧#ulxv~SnZ'3EK+Y`$7M|!5EλwE?[M̝] 0%`fN<gk/߀ي=M|UMp8<kM-'LgKX^?<+j8NܞwUK"ןewR ΧZYd!@F?[}~VnxlZ$/Ѫ3ן \RTL1u1%h0 z/#Mk2U#_>fϏ`xMؘ æ!h&[)Q-Z/RGԎ |bS ܹ X%WWփϻNr[3՟ S=?1F?[sU{|߸¬]TBpYawLg+״, KUpqȶ㈆X]*')3K-z:^_ي[W=ՂMp{ neqϖ\t 3(GŠnlVDSJ!xgKr=PcvZ).}c0E?[q5[pp{z~S.^x4t&ϖ`_jO*nлwEf?[- vT 6pk|YawHg+p ւ}sn4gVWECNkzT6UеE?[qǪ"؎{Y6sfaqNieE/TT"1%;'NCPrDf?[۪"i^61 MK+ dd%V$v ƅg7\ZZQZZɦ>.Kr E+/MMVߏ⫀3+d?fqC-GM;Mx$BJۗugP̦ Ɩ2{}|8[KO2Cګj7Ti_WoI&3Ӛ洞iwJ.+o(u6q0p+2yk桧O~"}o4l>ʩjqGx޿g ̤ί2ۺ3˯t5ThO~1a7͞Wyq |.au[3I\u_L۫f {\(c?ukYm+k=߇nWw<):W]p.ץV#OM+_{p0@~ _ïߣ~:.y]ip-I㗗|Ln-o/ n'G3ǖkCkszYTtwa5|B9ݻTMxI{eͣcA n\ēWꢺJ[ WT>g)nQ|GjA7MlzJ)y5ߍ]XT {D/Zߍoϵܨq^eQMoa`7|S)7Zs՛ KwXP|!.]+/U.<;u nׅ¬Iˤ0WeG<` #R -y΍U.?:b6vBYWɚZtKov.Qwv7Om9ͯMG #WKybb۾g`7_'v[mskB䓷Cqs- z+ lDٞ4 0E]@O+]"=t.Z|fm->WYɟ\ndzfx?u_m? #lm~On.z=T~>8_ze,ْ|,c`z'x=dr۰4^l%J޾K_1ޚWЋ0/dyH["zq:HHNΡ։R"R&[DF$DLr-I@'[Ο_+\Y?'XO!/܄8i뚕eL3t~Z)BR4oKl2B6L,'SEԎXUπeaYZ-KW5v2ߟ̖ =ݮx0=nss3nG8Gn~l;n~\̑L u= pm2'q~=Tl|5ݣ0-TfiپebnM˶6,qS𯯧fȬ$̖d۷LЍa{Vd;}ԉnnB@ms2}=mn. q놏~¼P-eTf:iUs4~M,YdX'(z4tlF'`Q C'*wecM^t  5*OZ׬Rg6QnUfBl9+۹̿!f:܎h^EْjIv6UΗ{(Vlt`_nbh8K>S(bhkZyiv!<@N:4gMKdt]N]Ipm/2}uv:[v^֬x-geytN& GR/M*z \?gK(z?ķ^\Mq\R4gyLO&=O^TWٖO'q Tl,/i[skR\Vn滏p.G.^0ɂ24!˅7B|@td{\L)UILC?SlEPo>iW+{= GWplw2=UMv0إ.dqﴡIE?aR8ΖrNӬl1Tga _]~GيL߃e#1n*+ f?!'Ӹt95vr:l+Vh8v~^´p -e[)VA+8Pc~6{tq{C@;# dDgKV&g)Y^bb?:[ǡgAnj?kX0X(w݄ i{9SӲ}tBlje(Ml21Umit: #ytG7 ̃l vL'_s]zQW#= F.[a/f& Mu~-e%܄h1w Kr;ި~.'S?aZ8֦ua29{Ym&p%V{ANRЃ-eEit$ӓ, >9kűq6욱mk&KHeN>E@%cM˶.R+:h{ǩfM h8'>/h 5WV+~(4&@q&-׶5퀨ג ~&F"-&pɖ\ǰyt׆jiw?>|yۋWtZ,.͋oN[/ǂ#0ΤuS4Ur)_BO 8[_C7mlfӜsdͷhN=p-m2=mmh>.1ӿqgMrbRނt=št:ꦴM; HD˅ = Eq$;G~Y5c>tQ84%\G$MWl&nӥWn- n }dhlB76,?>yfEp5tg6 XIg+r3)'oGqfo/cycW2]UMv..Ҙ֩tݬYH:[kCSE765J{\}{hB'q$-ɶa:ɶCSg@:[rrkƶ5zv}s 论kunK[P0 Ӳ=p4m&!Z*q àfd+,ߡf[.TJ6M寠*}ݚlt<Ζ`ۯږfroURֶsM)nt۸R%=^4MNc/l[0^:N*Y`EgKmW&ьmK3?qo&q-a;:;1JJy(MY{D%`->4' gr^;f8 }2\ݕ>O/d&},*ϡ y)Rj'"_Q7*tAq.ةq\SӽZN|q&9X!n.M=.u$ S˚~D9Ne2(\%_K7 nC__,N%}Jfm e r˅0Ǚ2NzjE_g~(KV-C?:Z)Li^HF娊治5)DgIٶiB)KrFw}Bo?lEn5fQt&eb֬?a|KuIg' sle  ;>諱죟psu J_mRu'Ղ7a^zpR#I.BMRu'U}8VdS*:du'٥j,.%(Ôf>6 $To?썃?2Fd:mVf+G:0Nr7N^8:[NKwc&uǙ^)nيOкLmPZjIt'7lmicfǚ C3s7}(C~…tgW|&1!Ƽ4NB'L rbEp5e ]T ~q<ΖX=Mʥ }mZڠ7l,Ǟ2N%,S4aԙtUҁP0N"ˋp%mo2e6.YQI]_i,:[VæeӚ $W*Kj^Rls'V@\flIvBtHNjD^*O 8[m29Ҹ؏”7(}ye\lR M>8~fMrJyX6z\]}/?$[(nْ{5C:D@8iO^8h{qHF#G* {Z9x]!N^hiR'_Ȓ؜ry:[v,$m J⦫yW~q8VHCٶš6^OYdDgk= [|^%}ŅӶ?~-;6&wF l:.'LrpVRu(WNItkt\ױpr`6kpoɡ[9t&Օ탟51Igˉ9疞}φdWR~+6]> dIgK؂d(] 7Msft,>D@ŏ/g k.Y __O\ ™t]{-hN2S3LnVo8ΖdɆҖ/;Ǥ9)cs<6ȁC-wwNr4Mvf}Un43{x#ONM\m(E ngْ{U4}.d?8>ģ!:*fvkAu$7Oe;p{.DH[XB3b6Sn¤p"-+V!nKT*f6M5ӑ\ U޳Ƒq;1`_}?n 4TX'\H%7\j^~EUM˵ C{8sO.[.m?Pج@r}Vd1 <J'~OA^q}@)cdeQ! 6O\׿5|R~zOYy6Ca/{k'-i, 7OC?YȆ90kh/{t[χSeg$h} CNH܇>.Cݠ}$oF|#Y2a&w@z_./ סֹ-3`]6/QW0΍TT9.jKD*V6gmxI=uo؏/jɣ亁%dGv<;6M޹}9\؆`V|WyP ɟ_&q@Y䏢^ ?Qwp ›:WƐ{TQqMUe u~{r\;oQm~v|fN1RPb+ؽ ub~ ee_p'ADjݪ⪛1Q kcJY[j_N*;4&ڷq?U"w &9~'?Um3U7ʡ~ >Ue .V u$(1νvl6 d夶%uۯ('1Zl(ɜoH^OrO޹ǵH^,Gmz|= NE6 7nmCy3\+2Emǖa} 'Mmz|G{7Qr'Q~w#y,52X :c6;Y4V~RLʔ}HrXI.)Se\E绁U؏bF\{o"wrMu'5 Cp]vʛQ(]>6*/'jmboza; 4X~8$)C?]^f"~Ih|QbN=cwCy3\? e ^ݠ7#ֱo{ 9d~(^%j׵,f$o+G 7]r[{ pI\珓:䆛p9pvƲiN$>wr}6uwQx%_6繓ګf$ʲab^8;s'FO,/F'<71xqUS\>{ǡ?l2= y77tȞ=s=6}N~+n7kn;6䷰M6ɍ<{v}n67Ȟ>sSߍxI=<{5+H6 '^ ~xț:"ȵKiNq@p[_.E+"fki8K~(\Ǜ?Vl/wm 7O?ڻe%"gs'Ncyȟt%6h4tZ5%9'Vkmcy3^?JĿhN~NnNN[ʆޱq oOFtIkds˛Q!Er-84-umX_m6 TQiv+hV!}jo;w?O~P8$߸-꩕TڳSތW #7T{tp˛:]}o$EޒP/s;9FȟD6F}tUA v˛:]n(oHBlS+t6 jت}q7Cy3Z+DƢ^ϳS8^'mvy;'6]ѫNf"8|l?9O jp#c#ls_7hjfS͙kw#iG"Oq,/~Sm;mJ7 <b |kk( ,ֹo[o R٫;P nލXY}gK !;oP ǿhwSG7 ` o6{7`|:0ʍ;A6:S#x2&ޑ;z&ajԾanHx8vn:C CMQ9:i'lCyqn!,sʛ:C2d*.&ĝSߍhroS?49"`?ۦ^uo*+hF:P~@02>Y'? 9 W62t{FJ/P 7 -j=P^G-ƹw}.? &p?4ߧiz77aSCwCy3\c.P{WR;,n:xǿA޹x/ >m ub{|ᖸ]XC 4\?5NΝZMha޸mߍu2-B,ʩETs5:lP EjiUf_,9̎dJ-r}'DZLg+rkHތֹHg+$l=۞7yLgzq'*_ E?[b#\Jqf7#y3X#ٟC0j۸Uߍhփ9`*~#ٟ Ѓ%V\l!42HdtBg]'ng\fE?g+rkՊe?On$oF+.3ي(R3p+:T"˟RǨ_H1P&^%k@D ;ϖ! |/Y\ pO0 l^r).=;v6DVP^G\7`&pyCy3\'#3g#{b YWd&| y9h~K ŵ },(s Ryxzx^fEhٙ, Lόń(^*2 Ĺ*;8MDff?[#dJmK'&i$oF\$ݸNu#>e1zYTfF*D!"B.]duixǛ:9lwn;έLg+ڱF 3ϖ  W2ɋI8ތT\fM\P6n6n9Okl#; B&LNF:?[6!ya*~P W`%8`~wkȱHg[x\;7F3yh RqUn0 թHg+^7Nŏl?R)s`/\~pwL-@ չgKSԍkG'v'{#_絓{r=V! zxQunz37u0 ,;83.;=;~09EBrRӼ$fNE>?[ν7neav>}Jnaw5T~ QaϛLg+0{罃9@~!euQc ֱv'ݾ7V4ɋP W`f| >nl^{?xmheB?۝{{n$oF`%8`m- B86թg+j{㞐zU(&y3Tqv>K;yK"B{_$nъ=]4gQ}+g뛁cv'ɥm;96>ϖ!pcS7 l^r5v/&ťH^XdG?o?\?aK||էٯQN[P=??J(hkJe]x 94I*۸,`?fٲߺ8|wן(G_swc<_O?>~"w.T1[?ǥG^ыgp>]}XM<-rq(VF;Oǿ;8Qa_s|?#Y~vpuÚa?=k)u{<x_'_/V endstream endobj 140 0 obj 357429 endobj 170 0 obj <> stream x}|u"QvT۱c;8q$KeI$P* A hDޮWzݡ~g8DI o޼yҿ_ظv6}}ݮw7{6}yһoo9&sƃGQv7}l{gk~{[~Iuauёb2bj$)&>>*l"Qp*Xӊ)E‰䣧Órc2=WYqeueQiy2EbUCb|zUpnaeaqbXVyrr".5>-6(eޓ>ΡS;%?sbc2J?r: 2ҏEŷ{?Y5X#f֬k-kh5vpjlS&dqKBy?i̖~88n;:;;;::{]Hoo{ӷ_p8 ł1[m.Fk6qlNf7؝v݊nK̫kw&pd-@bQz"`4u hj\.J>Њ?LojjjɤlO!kUHRaL־l6iuZZ#&jd2FKKSRR[$ ƭ&<<|޽o/>===""O>)//8eYs HE\\\__9*1/Qv\@bas6si;~yk?ifiۺBBC׿~{>gݵk~arr'?(z-qܹs'dH{+6O^"n)WVQMO8y$tEHHHFFT-[rrr!f8ͅ:ذaCYYD_+@0z}]]]EE4ZZZiiiuu5NMFSbF>ZvCB?Sxun/pRpzC G!y"OuB]]]puRZt% XXڅXXEEf9#7O&655?*rqbͺ=Z^%D@Q zjHj 9e\UK *k PURiT C |ߤT,JMҤTjf^8$0Ⱥں,MV" 5 JeWH I>ER*Iyڤ@T޼OvڎFW \BM UWYVQFVنa]6 ?r[jŗ1oC;"7M@p4dLg7/h4ztՄ>iGeƮ>M6 4w! tw9@BnoGuJ t?;?q/NV~'{jǏq;J!^\bɣؑjnzT!iSLFP9;7&Uv,?|G떽 wF.+N<HhL&mw_r`ETʀM6vxɡw< o=+l&uo^!ͼ$΃뗥zM~뗅}kl~K+Ml"¶~{Jv_U6tɍ5j^)rM~^Jn-{^?=}COSw{j%y2dqs{|O![?u37^sn=hDps9wVM|^w~{oA/^kUA737ee~ivʪqKK˗',-(ZݻFF-mjYZQdi-K&,MK_ZXaLڢ4X2EC""Ͽ%GLa墤D܏D?wD96% 1r>=i+}??ݣ'd|UmDLY]CCvZp;olS/כLeVfYdՁ5D uF  EEMZxPM].746467jZTbs{{G{zr}}}ȃT*AiOOOWWbj NR0#h/**ɓ$%%߿O)\Y:h]V :uĉѻw A@ _PώXӬ,MLLLHH'''ر#(((&&&..-Nkiضlxk+tƍQuՂ#474 ^ՠRI3QQ[snܢ{I~hD''GG Dx@@rbbdD`/斖m2XmKsc4RKK sN3F/;;c^]]]T\| +Z[ڜrbG555 aFLEz!(}t ۵kCzرP@jb^8GFJȠ j]ikl%_tϦ7LMMNNb1b)`BWcicpaǑ8v b}Qsz_"X3hgUKLJf;n8 v@軬.\Lյ fT1}ll,QQVGr`KJJPLa`Pdh@FV \Xj.|,+ @^ 8  °yf4p)Q!OKK!#B aA |*Bp8qϣG³U$H[ !U?HiUtn N1ZFoiZ0mo Ip)\*9+VB"- Ʉ?$ËÇ18o`` }ڵ Jc0P - 6к%; "L1& D % !' 8?q`ZQFrЇb3/@S fĂ&؃hJ U5`Ga ]]*_MM+(aaf8jxjo 3 d[ á|ڈ+nvp@K12Ghu:1 -ǪbǼ@$z:ҠKTݷ j[x %k?$ AB݂ 9–0}T=L "a!vvL&.: ^A*364j;:t&^\ݶeAÁ To .14THi$SZK/xW}kXJEe3?7HwԛF ^E9(#8\O 0w53B0繺秃eW_lSMӻPEEMM0-Ng|>/Ri\"Xk 4 2"^% xC3ޣ\mȷEԢ-*f|˯ŏf<@J|9yD$|$Osk/4a!"Qq.|A$`;QdƆzb8- Q仺RNMMMLL #A((7OrەezD"A9w CHӻR1s 酧Tzh@ CK4564Zc/ł>y$;!a@@5{=vXPPN1#H|PHII>:t(>>>$$`PA"##ӁRTH % QXf~Z%#L(FkYu.4͈dؖJM>ɦf/b?zT*ʹt,M8GـMP6h';͋c[HE8P&Bra>a4L] slSX22f0UIYkceu4bի4(m,*Y5k94=us=~c#|0Ш5]=qN CÈ̜Ng =}/gETp-LugN'%CXfbBװlI dz"EulA4auJ6Q&YQl^*B4gCjy&iJ5EbeJm<MNOb٦rd6Wlqd*pZ9xlQ UpuEl)65esA՗qH6E|)ck5]^)`riݑ!fl0FLr\@'hx2MVYs)փ0} 4<Jzv8D'0mYH5K xP&jĖe&VRICbն&n'.jkjgmǶcBj(_"dE{M$p-bX×rbبCla6'"ڃwٹb6猿'lgt&)t, õ ɬ% r*F..+7<@lLgzR$# 7@J p@! AS1B-g {ai_fsy'Q(p,A,EMἘ_YEqXpVȝs-9gixιu1ls13ϸx}frsΩo!meAp|qcZA/13չ#up Z'5}_R[7jf{y?N :\O'g7r=]\C$n-@\{Ǔ|M9ɞ.s˳3GM;ltҝ NOPNp_bztā9xoH[IRXb^j^9 oz|(9Dix4vZCXsN(1h\Nsj]}`!"1Vgu}&GoxxdMl BϮ^|dೄ&7n<2X#pf #u hӍid<)umYx ޶@=r/|jm $ƁSx#`N[Hbђ1Pggi:P@daH"#=<"AKX"?nlQ2PXİd&x!;ٚ|6;-H cf$A@pJd*ypzRvXF!)L&{fo]`"m;F.t'>t ƆQSS,DQ')Գ<]:y8qIC *pSFf ?1lQrjaxeDCe{:Iu >aqo/O\#S_D蒨]FhX}7?ˏ }|_gl{K=ΒAneEz;;yPĉӝc{;١>~w9؞K%!aoKyyq a@9(yf|߼tީaR^CCCiii|||NNzn8Q䱱1 geeb5^^PPPWWWRRBߑr];pDBƂ<`mG T$'%''>} ד%t7ٙDg*j롡ᢢ"??cII6)+>s?]V C@@8ܽ{7[nāPFFǑ72\)CCCֆ 0;tvvr>oX)0.ghv@qoⴵUWWl64 Jp.;Xz 8 όB ~ *VD-'ЄRһ V5.,,,**رcIIIAAA111@@C`C03zY^B(&$$GFF=zDY׫RUBA_؎.XP2%sz.><^´4Pipp0F&daGXX }o m:M@`^{5a}^{B20 / baMT*j*+%NLL@=z kMCׅHf?W5*r` J`rBꂦ'‘L$)8Pkȣ! `WW.(xQollҺ0|ArNU Ѡ;`sեXb!g'yAcXxaMVʵ%~Z(dY\lw~m!M£7ƻry r t&;)pn{ A D lT?=-AP hBhuАv/euOj )0r}%wx53UŘ2#he ͉<>>;/}b(`a( k4Gap4c9_a]RGvV*jGγHi# ʼ[8?3ǹ{Hr/,:y 1O;ϨYhscKQP%  1ھN$s<\J$Kk4#R%fv%:]ƹNXk iڏo%;''ȓͪlV%&{ۚzrBR_B~'eJ_mmPyE3M!oCG$~ ;`[taC\Y&icO&4U2.6d($DsF 7;ٳ ` C|o«lf~k}Ns_^sk7C7ϋv}=w{{'o4*vN?F=CSkQ|u}Wy٭\]4Y^}Nx(F?Eҫ^;50fRHHHHN+dYJe[qIQnnffVZEE9y<`--+lk v"8Z >>6))zAA`ӕ8]^|L*Eu@!334f+3ƳbC @ MdREtl6n?777114D>G=Hpoo$SPtvvl^xT*j5=1n/—M=11q%ZKd- ~V?ݞaZ }x FD7T OQȗAttj(:h2WأZ:j4Hpǡ D,]m\f+u<"p!`=i&h NX_PeJ60~I #uCo޼f9lgz6oB0 sֳ0oWt}9ը/̗wGM*慇f^ì=u4;|#hA"x]+ob^V\<^Y}#k.^FG!WeGQ̋> 'Uэ4/<*<(α1/"/j1).XX@O`vaA "[<:sLd`m\x7?zn4ލPQ EE.} 1) K)&V( Bٝ'־$G$F;L_Dh pT@@V:jL%ǂLGFF}z2e<D!'|T:===??G(\^Aʅgp#3lv|.,jyYsK2s9*Q&]8рʅ"F~C ;)RlP2  @Ho`LY|Buug5]2ЮtZC 7`F`yvp3TjlpQwqx5k%_ї /y.󾘈ty\4"}s ܜ;y燹w(W k a65DKx_F_# 3N_ϼ;wzsOЗw/N5^hc|;<ƲVPvs9WIWʎ 5Cf yVN!ipL+h!Dc:9yms9n,"C>|͖yL%Ts3~1aȊm~a;lzT}m'/9ogmFQ~x;@Jѫ-S( 7U d˳<1'I'=ĆLeadf?K:\ݲss k Nc'fnApm! ~oaQXn͏PpxmNRfkё ?>Bx&ɋ|ٛbq%L%#gNT+$ZbllmFQoT HOoPaZcccvl| 礯A~98}Z st:q ZSzy˗5fT_tѩxA RtAY*0H借y廹wy/3ox%l.5_i}lt!|q,.%>g力7,?OXk"`Q$a,"̂EXY(0 EbfH,,XE"`'?ޤEk"^ZldsAgtv\}!y>".."\B]n7Ð=*0gEby l2(ZQjJF9&%àPɘJeT Tkj-= %I(!Wj`*U*RI?D3GB aT JsR$W2{R}H\Vi ba6Ɔ&i+֨4:٣'xAƞx`#O>ӿSi2>>4~$!TlC4ճdUaQ VG===n)aaQ4|?_Ub|/GGX25p6b4RkoBK0&]g{EwE?oI%yPdHMO";"[&Ǧ~,"-Stz뢢CwEE0QaWEQlSj=yÛf۵k``֭[+** aьF^O4\Z9K[uIkʠa7io쎼IsF.}~%s7}a9?i(][QVYQV__-]Ǝ?y+O+=vnܳ߳o_ʯ^o+[~_3+;oD?}C3_Wcg ~'+zw|Em |;vK?裏>>lmmX,El^՚EX }֯/sæ]xG+7]]?߹~ wkUjyi :aJ|:8吝x9l&ܦgMcACG{#'G&L{_|g;<⁍noKanjv#[?NlҫPP999 ??#cPPPeeeQQpwK@_ft'<#JxvI.YQoDj?\55'Eq;~ȜNVqmQA_&4J-atV~F,3_u%_K){j3hیQ2ch^ M7 32322q/o+ژ*HBnnnqqq^^dD"$2L\2ˉӶ VYїxd<쑡G~4G&NLO#C'Af62-%6>6"!. tCH' h)1IgbV\tRBLbh&ƑrXAp 8Iq 3}Z8.<?"f:EƝHJx6fm,Zx<'ƬÙa[7gW%SJNo;az覔 LEH;I$؇Pi~@wՕ)Jv%8)牢l?Q顛֗'M&կ"i_ƩE1;eŁFlCMYAA^hmʋ֐y"q8(ڪLއ깑RNl@>Xf=-0'ޒt.\_|&_ےu(;UQk^Uʡa?h: MuQ=LFn ; c0Ua9;OlJ<2 Y8G)'T=!.HVĎg}|ؽI!O}"6tD198EXv, U{p :<4ajVpRy<^ x{!*|{;e"֜r5#YBGk„9w˜Y Y$鳺Z2ޖϷbNrxw !b/2{IA1}&,U$w&HE$G1-1#~U*! u kejȴ: <\Kn"yIڌ]&Gl4 &j*钓)gIIIH9Ck cv)g 2Te'Ua۳#wO'@b*ðr զۛC3)K(O눬Drfe?҂ Ei#Є<B5nȂX.KNzmjjR3opK3L9cL[KlcQ|ԑuyѻSF=~߆}l0Gw}ِ.l p0;@X7`/DG3Q!>hkI}Zi¡k Q\{a]?D͉2 rBؑcJ ,"#K3"-xW!:cH)XPCtdԩ( 5qKX`&`kh U &-O0QHEe ǀ:N(͠O*QV'^@ D#KgEbsRo7@yX0/,)!aQ#<Κ4TGri+"G)0IuOWOMW̥hҤD(AVH٠FVG]_@AK{(p)&3M3%9ʁE:SkVƇ`,8i:̬>Ue%sޘ6j%cIץ-/QJХL蒅<)ߐ>K=;bNde)ΊYL_ٌ+N ;=?gi*ʊc33֬czb2$[:e2]ۮs 9Ne\'CJp*V,_]jF^L_V(ޚ7Od >f̛7gL|uQƨV+uZMD-6iw1}i@RlOq7Lů }o<6/K|mOp;> stream x} xTוgIfcڀI'mgI:ˤc;^}XbG $I @ @! v{i)jz}7{WUIts=sUM oɝ:rj=HZYoНYi/`cNX0p@7M{NnϴzǁmwЙnc]xܼ/`wCgO7 [v*uzMtjYlzELZ9\G".{#.h@hTRN%8!wލˬN.hH]z|d| FY,IK+,&eFT%礋d +I"T{/"41>_z7Ip796>?>h߾1("7(_I}ӟi˶˱ASB"R4`pZҿ忿Ws.b6x:xo?߼t4z-I5M83ԥ۷o7RSޞ՗ZQgUUio:n};TVOTo2M]gCoZSUHbA]A[,-=y%G([RKWc&q OKȋ7 P\^a$jK$tVTgd*ubYTv[VY9TgjTMLuTF`nQFh6(d[,4M&Lz\4&~1}fQ֮f\Z,ֶήD!]Vkf]$ X*tШd`0 fd54Z&dXKڰFh4*JVS,(J(r|^jIJ Rt:B.J|B I!/e2H$ R@%&b?a Pt }.-1:p$2L.S/U*#*K]ۨ7S/qlAQqlLLRRR}}}CCCmm]uuuddd```TT8>>>Ľfeeɔ>%hooZCCC---6pvpi#gfmv0)xQZ^Ք4Ϯ߻wZmرcջw^jU@@͛>|ݘ7|ݺuk׮ݴiӍ7m_YYyڵ/޺u`"VD10@DF{1 x?{A0z`ܹ+ɭ)z?EzDaqqjJJrr+W 411#ѣG 00á |0]\.WȂT*nv }ttBUUUiiiEE:2VݨC>., ^h[H(I793|DϚBV Ĩl2,tuuಣ&\kfȝonnJ`OOOD8??%LĻonֆd+d2PRR e v&@%\$H,UEaw}D֐ncI˲⋊ ҒuZ l{z)0 v|  |\d∆0kP3AؙGHI;֦&*%U'y:!66V `RѨ- QDSSS^zq8h0ˀt]gb( qhLXe@Grz1۲e 8矯Y|88Ο?#sppY E'cuPX+W $OҥK p%ggg!#F!Sƨ($0T{qqqGȺ%f8f8JJJ"D!TP 9T, k$xpϬ|iдI1! HwlQ\\p" M4)((ǡT!cą%.B!e9 bƌD&dEsT?)M+p˜t:,LA.O8#qQX"ɤ hX[bJQ0rSJfU,Lja8R&\ʈY*ÊJ2D2pQ VBVs\>,E*LYX'!Q]blډ!"k>)g4md2&tivv5 wSJ׫+12AR?BHaGqr9/;35#3]f*!tssPcs=ll:rM ~SKJAtc32?7^ob%[54ސy0(&CR+Tfֳ|{Xe]ːjmHr[rnet"6Yʥ;=m^[>ֱZA/R=o]N3DO0;n{HV'\6;xN՗Gvڷwѥˎ_‰K–\.~utu؞03'/ueYt>K<7/v^ߢE- ?/ц=uFBlKGZ4S^ /[}vS.j Ʉgo]zxqЃX(%w-|t3K_o] ,zţu?XڑE;ğ^zsMOtEgw.O/JdR̰JT$$7c??U,+A NPCۗ9F^^ry ï,=rh󢣞MI^g?c?iE57rb=bA|K lGzfgO$]{xK]6,{KKXyj?=~x듗}\]'=0?jپ/kz /тeβK/*p|ЫG;ϟ-e/ zDA~tgaOmpϻ,]TwG J3'9 6'W?}y_'z=CEiyIt}..|{{!8񫛞+?NLmyP*"I$$vv햋B45J(l(OC/_n5dltF^8~w=SWVp~B~^~Ge/~'Ŷƴ?HS[e ˀp%-y!ak)ڋս޲l/W0TU SZV9VЕ .qP2t`]Le/##cl)YbKy'ni%#?C'?Zu\nKN|Rh<"ۭ}7Žp֢GEas O8Ÿv=5p~3O?z~~'ͧCÞ1gUzm3Nrx^)/V4L%mZjD)J zbX)FXH@QJ! ղ"QUuTVQdP G+/+4RL4 JM%qFRdTdbH'-DX'-b²BVjDjaN\ REqyDPi(P +r2@/b&Uuy@[Ա _Son@l!O#SjRjksԵ<=/O[gu<]]3B.A1)Fj^D7.F=A%%@RP )ℎ+r0RE81TБKy®( FFF0A6b\ɟ("V1 2Q_V0| !ReJIJPGU:F@u'^rJL:F@fܺiBZ%\T.*yܚZLOAD`#j42T0^F&LZ5KOZyIh\IP*x<d%ppaa!f3IY,ɤg~&z9#*Ód^ZZZYY (y ! &% #+W*P# I( jzX% IIIϟcΝ;׮]w^DD۷ t߸q#>>>77799#J_;??[n9s]yyyeee \x1333<<} 3JGԭE\~=66644"H& $ʊNLLDYhjuҰLwlI*Rn޼9x#G;Çn:PC8pٳHG7ʕ+'OD:u*00ܹsOF8qʀQЁݻw=zt޽P-t%kDt.ųW,{yyJ(A̫l |28P9*$$BJ0LTqCaJ"KHHصk38;m RSS Qm why1RPh50p[q*"fK!wp25%Ů;lS@$:&! %ܹеpb2HKHGh&d t=CF]zQ~6t8.I,ɜ) )Q~h&%|W%|!n n-4P &şwMt Lx'WO˻/IU22|R)} Mxhm:xiWWCR K'x$ܹyא2q;7n erbHV i+ Dd r\dyN!Pક]E`Mċ!c+PSsdI|2[=om3#jT aXL& W k8l6&fd.9j@dsΈ`w.w@d'LC<HM(%,LԁBtFQ+={dI:FJ6Z@5!M0ApW<>ڸD/sd=d_Dy95iT $,@P걱5EBD}'h;*KTM@у2d#7D.'erH/blق&cN\*HPo?OJ@O8m۶ 6\}/pѧ11n|嗡9{7HEbw>غu;^ jꇛyUV%8 S.>a. D0ɷw8DO=IttYwM@5YՓPF ⷢ®!)c}d0Lh E,Y'24!IAHBAa<8.yrsdRC?QJ7 E"m*Ax;GrIRbMUK$IZWYdV9bWN51(>NLHf9JjHKWKٓw`͙?pbgyIM7jQ|De/`_T_qk`C;?Njm*8Ħmo$)R 2ZVUUq8YYӀ xhrWΟSʣj`vv1A>a%w5e*L48_iF[R5S$PR6 X.Q@@ @dc4q 513rR ƪ񢧲u@gVߍTXXD4m#)%4))q#znq8iiJ-]ѡgihvbgB t; ڔrhul̢qpt8u&a6.K(1dZgYP„fzv% al62՚;r0f캩COӆ.kTQ$ / ;:d߾7oz{Kv 'nE:?)9jxMW%yJe .3n] ߸q&4DJ5?}ǀrQ 6@1@%M6ygAT"yTc%>[rf@D\\ Xz =|dFߓ^lO6ED>spڱ}AG!vǖ-bغm5bC/9FaTNnn@ ͽx"ϯx La`V~S$pL;}hHk5Z;2L–1nr8VypHА|aq8Tm,dQOCئޢ$DIIINNN|||LLL~~>҉T yɫOHD$wJE@# @. x9ʾL%Whue$7V vJelر犊1YWTTTVV  gJE;wKzw҉ 0.nxHBQJRR2Y!wmUgyU}>co8H gpz{=]oQPmWMF殺jLAz[JEzC:HawlCвQͬ`y04̦uHb2ŷ<SZfz̠3tǍ=vlWq=IWܽ@qn,dg^Jmc9<:X2vpɮ3J| 0:豝!}߿U$g?3׬` e .fJ u" z;jLZg ::jPTPUbXsD<meK _(b(6uu1̆;o` "pBw`?=-18,Ǥ<8qD5RMkg h6~l adT:6UϒjiTJ$R(@VVFljkkgJ8jGT]1&&՞%w֤}[#N0uU`PSu:N(eRzS0{$e% bσQSFWQ:8@[B';4tN#s}+\2Z0&-v3p<&ͬ 8(Q-,5ˌ ,IBOa G7ԊE-{ gkk+9q@=^c`=4`l6L"gX_a1'\i`nд066QmmAR;896fhj2yQA(M+o54ιm2vvIlz09#j\v )iQJHZuдk&Ff5Jʞ^zFDk#IӍЍs"V7lر_SpȱN?ڻ%_xymqOпGzF 45vX}׿~mM)8Ïڻo38hјM;N(9i&8`55W&iQ #9xlH WĒ;KKKK32n&%Ć2n9ѥe霛i7**qέͨIs" хEw/]>᢯_s|ٷ**STP CЊ躺R.KؕX:a2$ȍ0*h]6 {7 d6EI+K MrPROӝ,_S@rMz}H$.,,p85 3 _%XC&WTrE!T"Jg)J$ eR3PR35Őxz3[U)mfCC=^D( 0)^ M$6$9M"%Rş ,%+!|֛wKXpZȗ'qٿ׹z)VVVN8vgf.cc&CAxe,6!g‡"I54$1MlPF{\ +*rZl]:R iA-gvó1Z*kR?v;hY`+C*kHXQ-d2555ÉFVء=oBG0>Cq;:豝O`+]299>&; >ZMu;xx\|rՁgݻrI#>mz5.C=v]!--mݺu\Z `77eeߊn݇n};UצcJUi)?x3pWO[V6x'N91UVB®=*YsrBB9J[]vyzٞͬi RЍn=^DQ+Z\VƘ8fvnv!A,&4YUoJeeeB1ΉQk7[-V”e2蔲3+e(}xq5 /VWWcdz(:njP\ ӆ|> ೗VPW+Ƀ`il5{ОZ-좺U]JiC.e_I;$( $|BQU;J̄IsQ(W RkqԜ%f 5ut ::Dmn!b:n; 5wv Y:gpd52em6HO CP 'g{{;qBoB v?;綇ZP/#5H {tNFdcotL{/>ljB)KnF 9 i|BXDeYAGyoɹ.M{țP)4",` v7=]P#G=Nwr狵fD5CJe7 ͟:ƏyO?{"9I:d6}W~̙HEӝsBn _qBJYYY;v ?J1*Anc_<>!L)+*Tގ9r˼ʪԡaF[i6ו''%f / <4>!L^\[!5fP%1ap:RSSWVVRsE%73cQkP)efbvh0N+3T^:=ɑ"1ZA~2P F,~$ U"W("("&EUA%8,h[@ UO!B\%J (3IPBPH]rS7 I&qfj-_?m`m1fktqtP6p6 a9lWvZ\y1PQ5UHCH P3DŽ^/z"I͑3n^:2RYZMak3N,яULJ]-a?r ۣY)h,zb[FGu^1>VK݄r,whEoqݻ > 7رp@xms}W~o/'z{V_=/E=%>ʎ:SxLX&$LKK[v-dRsgY nFC%Ν;v/唔Yc v*졻qpQcb/]={p䭠9m63m%;+++""(5wTb_?NDxOm`Jk!JN5$1l|b׷gz=O( MHH{.\y9VI Z w ^_K :':%5Cz&Ub`P jWf2 ʙ3ôHk4ZB~@Ԭ%y6ٕ=44vxT;%62;vvv6;ft[{6IgD]]X1Vhf~9&Xlߡ1Lmmm--C[[[Yxh6<Y *o${A*+_S15+QQuЋm+y1/AsmYYBgdApL&)+O Wnȳ.Vގ>Ͼ1o}c0ltL*1 Wr/3^}#G9IfdD;6څAf3SlnrhH=UµC[ (j$g)A>\N8002{9m ! 犋Ce[f'tBƿq-p?1Y߲'YOՀ UU )Zr&-(HsU* 􄢈ŒRv\O2Rq1BIRaEWsGsonx}h4%%ii 8`nnj^^Zn^:'#)'757'5++XP_NcsrRYɠHdA =#yJq,V"#֥U ¦:MfȨX%sedFGwt ZZ[M=ЎNX_}i/0+a{#CJr@``*p.訟߾>9wڏ֮h۷ܵvz\ig?۷i*?xOVv谇Cm6~MlX[VYdhKSӮ5xm81$]_UYXtW $\fddD(d/P7buanEEWV%F˨HιVYJh c RbcgeepJK3rr))ᔕgYQ]R)*.N̮ʎ+@PH%#\P\XqX RPw IqDL6 !NR D.eȼ')\zKU\(L;7UxJ)¨u(1*a`TB+Wd5E"d˵VuW,a&a`JJ,SהhJRmU[bP"R HS)djs|.u)t#&Rжm:l?}w?߱~acW_['_ђ1b%VUҩmowm}~1;>1?Vc? EguzB-IFΝ;W^qƍ7ozL"L%ڵۺ<2ڒyV-XɼMX?B?U/Vqb5kw}O>O{_}ڵֺοtp-SmK?N_<[4aW +Bl{t풸&?JWRK';;1&_tʕ+/^''''###??=P~x 5SJmkOo0 2vN:,tmҶW)V"WTT3?q P@~=P28G;0pJ'TR, ([%e,Jv~YpÜF \.S!AtJ>7sPcv{A nnp$p&[%0 *IV 7LJaLR +K7( ^5qhH$?1Er&/? +*n5pR`"xƿ%6"'0TUWUp+kj+UZUTpU\_ͭtE 8WJtneqEժǥ99{Ę3h$uSƌ9f^U!gD=Q j2[ʼn@)oԔ;e{>e:i\ٶzI8'4/_ZxU{YVw*ޜ *S1R)EN(SmQ-gL9DQ+EmaT"b˓Ņ ؑq`ڌ tS~3ni[^‘A^1}氆3pFt]Ϩ&%?n+v˓: ~ fcֈ>BlƬvib*mD0bZpFuȓntQbqP_ѐT^pᇹkܰԐ^E͐FUj,J,nv~| Ғ՜ A W_u~+xgiY1nkgv^=yL(I+SᰖÍsуvGŎT}m iRMՑ[u3ni\KCL ?zPdӥjS ܛэ={ݒ&ѝ>y<IӦqv`&i 2*rJRkjj5%+ȩ{1I8P.29/y#s>dg ߷> stream x{y|Ts2[2,I;,` KHB4! dؒ!h2-DjhU&wU JZPhnoൊ: Ñe·!2`<1zcSG/:h7'XRbp&&M=iީYٗ?/xl;Ȟ]Lb#.<ե {B &''I22!jirmXI*y<-pFېv~[t+pl_F`ew߀k6S)1̧܋~ w<_Q9 PMQrCFz;&bDsIwaT|X}Z2RH/i&d/: ])`1>;6縑۰s+YN ~%y@ ] ېa1ىXVPUi&XĢ'f1d-bNP}Q݌r=F>C)|-M 뮺r+ίW9W3|̲gL/VX>՛q'$%g2:Q9 rڪ|,^m^\U[i~9/![[ˆ&G30UH%CU.'唄Wðlq wTy}rS־ 1c+ʭ\Y5X݆~0T&-bxh; f4,&-^k.?os#4ApPaNt`qK/ծD)E6:sxlLgfƗyQ [Bo5J|?:j5LrT@!᪉ nA+$|{}BR\E4OM]ߕdtmNZJ6\oCuW1eF [9]Vuwc [-EI[*ZPJl@qyjv(S.f>f+M-  /k\c$6A ՗bht¹xZq@Q}o+ Rí,[EƠh\h""5yctxպ<>OpZ j)0}ΫeCTovQIYzb"PaFkr\KM˃Aܫ!$(&\.X,+[ѥC) u殙wAǠAc<于J$ aaSe^.!/ܴxH<)W ܼJTkyB&Da#Ԁw=2f6@ؘal H0e0B pF(cbcl]CL1A1*s :#Ob4y$U lx+1JÛ/n^HrB֮%9$"gr~yGe /2( V\T[-.h]uJ$Opˉdni3@qҒ|dzqéons8[䧙c_3gi[z?:;:\ #J\)m/Xeʹ3Sg,ڀz*ǽ2H1U*ffK.[|i._BwMp'pF!!11n/њR@ |S=\)ԕJTfQQDBIqle9mnTLUOvةfx*.I(m?s+Z`Tq}?eSR\0vnș?wwrŒoH_}R]ZwΤopFN֖_v|o/xryTst,}&<9B/I9' 86+Ƕ6T$%p[E@ oi1SN6pBkή7?[j|ULN7 fAp8͢NtB:q\@bLPqRfۋ^M:w%zXygvWmwUgG~W04' LC?q*&n a+qoWvKb$R$qGi:_ݚ`1xΧCg D7욿sLݨ~Tb^"Xc_\$+ڝN?g&Jen2ZxhSStf4 Jlm6ld4]2iРJcHcd3CLฆ/PZ _>w^Vr3Zsvu0a>:&SMRhX z鐈Uo|\u.'uB 63ԅ$sq`ѢGb&odþ7<8MꇐbW_zH &6xTk,I *&䈋yĻRq >*Z :DK8g% }`ıA`x+XRW9'>&Da'rΓ`:#W#auo5<3Я(jY}Y}Ӱg[0C{c^#3h4yA0ǃ`rXQ 5ĘL1.y@#ɍTp7]&jauHO,7 W MEvII4o"G[un:;1A({WM$k"LP'ov/đ8~m߻,~(,,Z䎛8g=zVdXŜ@N RbIv}Ud؜ Ǔ@2&CA2ܚ\_ceh7Nx$d+-=U%r߆CSWY>2m*g!n{UobLm|Lmx@짳,1 `VOec݂,Y@Tςhɂ,hcs+WjuLԟPp7jwM9/6kFPs=_fdԏ5t\+L~xpivi07ׇ>n[YL';IƊ7bK,<+p2(Іps2 `m5>cmM 8yrĻR7U/Oq^Gt`9 u?\)Xc=3qAZOFU|!~ ģu*Iz3II5Y[}&c[}B3TPR H,hb]? sHo[Zßko>[ܑ?`+4A#\CWGWs,U^Fx2yRC9&!7'>OI[}'gB=_W.*o;y䩙xKK!3_(-Vwv3Soaz4&Orh5DT>C}߱깲/^>9~;_(.$==o^LgLKYJF{+rlJ|ON=ԃ^o$Po f YK|XQ\F#ENLX~Oubden͔Nu)G㆙)VbMٴ$qŎNv&h!83<:rΟ|O!e[K߇_B28N3jGCUcgtL_2=Qr}鹽;vQ۷V CI@~Ms :xd q [+ JO]0 Ac9K;XvG2$IS\ؒ_J1~b(F%R?aa 1sWkkK\`[ ͉hMUc̍~B`bУ>hz7|I= 4LvsK~+;PKܡ^%,úCr_f2>K&7|NՒ]狷؉~o)4HD.pqhW2vD0r!>`:6f\88K%zU[\K)u=rodhS[6w2A7{^떲k$0YE~{mR-_'~zX}@8ևFRdr:=3q&/`&X@O>bWxqxR =Qsyrp_ȊcT4ZY|M¼mvYuguv١vpAQ7RԆ'EXEOtz{{QG@v^}ʮ7שG:cXzs$r`K I^2Y'bIgIB楸) Ozw/MEgү* x~=KuԻ^T@V٭ܧ7kJ^ V 6\gԯ W %@5'Bhxbl$O%  `o&411'ZQ&)a_XMo%kxx2d>fį?|׻qh9Tٷ:I⩱YWX`S\;ׅpmI}w̦"}#I$%dh""%Py$&ؠwRס/9 ъn/#y To}Ϋ=Ž-]gXXեBTFLI)11d$%`Y.~ڝX; ENtN p t£N\p"&|2\pšsNx w¯؂{pntz't: U@/^boD>:ARv#" 2E.f /3Wfi6~x™Yl Yط:+_ _H%׷diV2KٷIr8+  L Ț2w/dMKPmh T֏a26I^Cs_/ʸ/jn7VYR,*2oEWZ1R=@0Ż^S2{ Ysa don6㽙qlՕ&q % itQ:/Ҁ0Fa =FrX's}n|2NLX%+fWt. O7 军 O>1LsL>wKܛ%UL*9ʘIJ bWMD`So\vKĂ=V $yJ@l{Z[$ Z[꿵\GؠHkIhmtC֎#g:0;ͤkʗ#'  Dk"pZ#A<)@Z[$d{^%>d6qUG.7dѠjcN %Uut_; m^ڳi`pMO@`_iޥ`ErGr}Wbr/\nu .n3a 䐿/z]0@&_tي 2Y3@#Lс[EH'n3؏uD&Ҡ=zP‘1A #7flذ!߯i \dc(bYZ[TK7Ѹ`\B s+Yi cw(w,"U:TDۏ}?IFϠpT&Y8"RH-\/cV "|= o|<؊ՠqQVbkoG pjW&#aR\9Շm +<?+^`EU!o1!o7SfT#lrދ~r I翕p0XaAճT2FA5}:؉ۙF nj1Alwi2cz #$]70RW|423WqJ쇵}d6bm?g[MmO[Otdm_K6%]ɻ=ÌnҐ=f/an\Lb~&{q6`q6j~׋Q]y]{GxOYĬSSdI/i`\іj\b6g h0nǤԡrb#yY&ɥ%}#Ƙ&Zdz& l,8.Y գQEkƵɬ,&-[dѨGs̢vZ̋b6|ںPZ1^zWt1 XU w'YD_i<%_z+$8+yEi>7k&x&1,bQ"O&9 W.Ӑ޴KvnG?a&|58_F@Lkn372(#0G{WuۍYfy氶 pf,w!;(˰OwBO98oR/` (p|+|{?q]pvY i=<3_N?~TS'g|3y]] 2 adL#?&r뿟~WwzU88R')G~쇧 I`W[_}wx߃pgM{ϏQMrv]ޚt ܼsN3u;r3(7Yj,۸|n>Ln=^w0!pK /ãgM!gWSNf}1߬Cqm[k߫պWd/ֽf;(YD E|s _A~3/6Ҙ[4NIGRr5 i/;.uqÐդԤkk % G([>YRDB q sKJ endstream endobj 195 0 obj 9182 endobj 196 0 obj <> endobj 197 0 obj <> stream x]n0E /E8I"$ EbчJ!14Rq"}}禭ѱsgrl jnL_Cܨo;8w'ڨki%TIkwN[*If{w/uGu2 _dP;>O\\*Uw6], _5Uun\%U-T,a|!FufYUf<.g`ˌ\0c%ksW%3K&G7EOq/ _2/_ӿLL-M?Y40-Υ'ACOC{6/J0%9J9eo?-п`L j.!ıAyäu~@p͞ endstream endobj 198 0 obj <> endobj 199 0 obj <> stream xz{|T^1$̐ I& Irx$eBd@ CfBIf@JT "؋Tj+ܪ_%Zm}@MگZ/+g䮳IHz朵kk3$&fAX"5[Cӄ@Z㦄V[p?!̮躶sBfBZ4-ql&$3^/&$uLoFD{v={pܖy`[[# Xj d?c=K|h$8@& RTX8zH+A;q2#S :hJ1 --=#;7i]~;->f Oѕ{rM^$Q]6;E~NЃdϷ}#cvvr;xZ^o J굚I*dy܂p_@F=H ـ|5n323!X7~# MWqJ*4 VqL3 ݚ?s}uu XbUTI6] ӐJ P ?}NpB N; 眠aVF:6کK Ϗ_G}w3%?1% |O/7ж1I BFNO,3e8edX.u:Huwv3#p'gM`r `燐X3N|a1?Ri&#))z[(F8LjU5aWsAsD %Qπ,<:T p}b^li>_͗6<lI{;;Ʌ+-?UpNAFaTnۨYoc]Y:a@ܘ1F%Xncf z]p\Ⴈ \wA 6l:uHȰ09jTD}<2~1]|os}w8&Y`q/9;ѱ4.w\S:HV]z:'nљEu7"}}v:4m0phS^~ެ&vN'wQK̓[RkudL.Y9b$߰pg7X4fݚ9]W9KlV:ΓLRNI[q+&WM0¼躧|'y)9|oxg]fm EҬ4DLYLVb"l9.`6g0p6DBX,FKՈt4vL8Aien ~[0,yxG7mz=l틓²U]fE1$THyBFFbL{*o@S,F0F`a&#s0 :֧X1 7M2Xui645>)x 3)߾sͯ+[`p~v P ʾ<+-'N"س)c5"'z)OKj$IaSSmR8\ JP R(UW҆{XKQIY[0mrPtav\mxO*/A`冇~/yK{ E&]J^ݶrMƑukwƖA]">jm޺? pLIAݘ`6*pT Fف kaؐa#3bJHlR]S>U<֧,n^:dpˈ)og>]OOjv[~dl,2Uvtٷmz!7I匵XM.Q=v5 RVƶ>d7ɏOs΀3߫'GVI8f0 Kr z Cz)>Uoh/9=^}SQ_Sa;uG㹒o-޹xÏ^ܔЪ?|yũл,̡&=s@"<㡗C=^QlH)2_O =ς;AeZR!)( (]$DxygW>{^UCҔ ۭtR$9ue9nYƠߌ}j<ͼ#57z!s͖6PkQ B"'~˰=y/!̯';IMG>x[c(hbFgbSFƢfi3,53f0g~3 Q֩d6pU+)5)> ф7CyPl3~_ W5iDC1;b(/=Q>&nrs /O*Mxu&e)t[.ָq|j$m]q1ٙZ<C40Лqj5K{_?ԸsTqGoݻڢ@{id`n}'J߇:UOl'g뉍㉁7RJyޑoUK<`{>޹n; \%ߛˬ/I+\/Ea$o GbF]n!g8YF,o'˙'. /I3حn=|e2|yyn{ ;Qa38WpȫKvtxa9\dp\6=g]#0CGLc')R7)+)&7a838h^HMb٦ܥ< 4X#'l PF n͜" 4vrRI;-Έ_c̐T.[Y2ǭ`dsj4XO>5@&id}lb?23 6 _j@hp*j|aA˺D- &bc$%ֲ9!Nh(L)DֵX4 &Z"Ei|QL  bm=$nck067ncd*±bmA1 mMbib,%.`"ܞ!q⦦0E6c 2GhxQ-^4l_&›D" q.ln-R(nnnil7b(oY׎ĵ[2"R&T)\v7ubW,ñ&Mh&`kZ[Eb6$كOV[НbK[4D͛o8O0\ڒ@XkiSgh}rX$F#_ #:2iSp8W%Nܤ,)CB#m'P4"C!\3:*ҸM z81d\1AZ5@-mD":xEA-*"\mĖhX ELֺ#߮Dm# څQO%'j PRN)Mnl&E֢Hl]Edi!-$LBDoAID\͈Ng))XuAz+ʋxD?JA7BIRLJZQE ZQ"[ԑERvrF#sӈvԥHd2~]÷SQJ|_ৈQ۵ E^NPbe&E6O#%LG!U]O%/$lk7̸glBF!F[Usf͟1jA -3ߜԺMt)^)mںTͥHfDAV]\&~<&ҎV*2=Nm9DRźǂjېomYji3ݛkG\+PINbGCޛL#V)P(JQh9 kNPkVXɤfÚ'ceXUoH%E=pj3+n4,S& 6Q$Y#Ԣ~8Aٍ4j.Rs85#\֡fK4d&h)7r4j;H?-+bö=>6صCʳV?ī4({J9r*llq,kX8"/kpZþA~,OrąlOfdWcǘOO1O=)?zz{YǙ#z|qB:*Ǻp[oۿw~>>> {2YsOA;`)DDžDg+Y7:.ik{cUL/M=\)[ʂ.b[[YB͠ai3* oaaBX%PtTBf:k?RnYcf,bbKIJr2hї#XL#x}]KkjY_).9VK5+d.ԭXYpo={ȼrim06P-خL2/O*@^o<@*B#P$' ݒ@|V#Z8~^M&`5*[B"G8k9W, endstream endobj 200 0 obj 8014 endobj 201 0 obj <> endobj 202 0 obj <> stream x]Mn0Ft !%$H,=ːgRgq\֧vS}I55+:I%LeEo7.Ce'kyoao,V3\!_ٛX}ܝ$(6yjsCLUڄnס/>;֒U``tDy""k=\[!$+ y|D1SL!g*A~$Rg_G.K=kϜ>˄Bf "U"/_"fJyW&ʳF<_NǀgB߽D3iv~V : endstream endobj 203 0 obj <> endobj 204 0 obj <> endobj 137 0 obj <> /ExtGState<> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 138 0 obj <>/Contents 139 0 R>> endobj 205 0 obj <> endobj 206 0 obj < /Dest[1 0 R/XYZ 0 841.889 0]/Parent 205 0 R/Next 207 0 R>> endobj 207 0 obj < /Dest[138 0 R/XYZ 0 841.889 0]/Parent 205 0 R/Prev 206 0 R>> endobj 4 0 obj <> endobj 5 0 obj <> endobj 6 0 obj <> endobj 18 0 obj <> endobj 19 0 obj <> endobj 29 0 obj <> endobj 30 0 obj <> endobj 39 0 obj <> endobj 40 0 obj <> endobj 49 0 obj <> endobj 50 0 obj <> endobj 51 0 obj <> endobj 52 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <> endobj 55 0 obj <> endobj 56 0 obj <> endobj 57 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <> endobj 60 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <> endobj 64 0 obj <> endobj 65 0 obj <> endobj 66 0 obj <> endobj 67 0 obj <> endobj 68 0 obj <> endobj 69 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 77 0 obj <> endobj 78 0 obj <> endobj 79 0 obj <> endobj 80 0 obj <> endobj 81 0 obj <> endobj 82 0 obj <> endobj 83 0 obj <> endobj 84 0 obj <> endobj 85 0 obj <> endobj 86 0 obj <> endobj 87 0 obj <> endobj 88 0 obj <> endobj 89 0 obj <> endobj 90 0 obj <> endobj 91 0 obj <> endobj 92 0 obj <> endobj 93 0 obj <> endobj 94 0 obj <> endobj 95 0 obj <> endobj 96 0 obj <> endobj 97 0 obj <> endobj 98 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 102 0 obj <> endobj 103 0 obj <> endobj 104 0 obj <> endobj 105 0 obj <> endobj 106 0 obj <> endobj 107 0 obj <> endobj 108 0 obj <> endobj 109 0 obj <> endobj 110 0 obj <> endobj 111 0 obj <> endobj 112 0 obj <> endobj 113 0 obj <> endobj 114 0 obj <> endobj 115 0 obj <> endobj 116 0 obj <> endobj 117 0 obj <> endobj 118 0 obj <> endobj 119 0 obj <> endobj 120 0 obj <> endobj 121 0 obj <> endobj 122 0 obj <> endobj 123 0 obj <> endobj 124 0 obj <> endobj 141 0 obj <> endobj 142 0 obj <> endobj 143 0 obj <> endobj 144 0 obj <> endobj 145 0 obj <> endobj 146 0 obj <> endobj 147 0 obj <> endobj 148 0 obj <> endobj 149 0 obj <> endobj 150 0 obj <> endobj 151 0 obj <> endobj 152 0 obj <> endobj 153 0 obj <> endobj 154 0 obj <> endobj 155 0 obj <> endobj 157 0 obj <> endobj 158 0 obj <> endobj 159 0 obj <> endobj 160 0 obj <> endobj 161 0 obj <> endobj 162 0 obj <> endobj 163 0 obj <> endobj 164 0 obj <> endobj 165 0 obj <> endobj 166 0 obj <> endobj 167 0 obj <> endobj 168 0 obj <> endobj 169 0 obj <> endobj 171 0 obj <> endobj 172 0 obj <> endobj 173 0 obj <> endobj 174 0 obj <> endobj 175 0 obj <> endobj 176 0 obj <> endobj 177 0 obj <> endobj 178 0 obj <> endobj 179 0 obj <> endobj 180 0 obj <> endobj 181 0 obj <> endobj 182 0 obj <> endobj 183 0 obj <> endobj 184 0 obj <> endobj 185 0 obj <> endobj 186 0 obj <> endobj 187 0 obj <> endobj 188 0 obj <> endobj 189 0 obj <> endobj 190 0 obj <> endobj 208 0 obj <> endobj 209 0 obj <> endobj 193 0 obj <> endobj 210 0 obj <> /Outlines 205 0 R /StructTreeRoot 208 0 R /MarkInfo<> >> endobj 211 0 obj < /Subject /Keywords /Creator /Producer /CreationDate(D:20211113100347+01'00')>> endobj xref 0 212 0000000000 65535 f 0000923820 00000 n 0000000019 00000 n 0000497669 00000 n 0000924519 00000 n 0000924595 00000 n 0000924671 00000 n 0000503593 00000 n 0000505345 00000 n 0000505616 00000 n 0000505658 00000 n 0000505905 00000 n 0000501765 00000 n 0000505948 00000 n 0000506221 00000 n 0000506262 00000 n 0000506511 00000 n 0000499723 00000 n 0000924747 00000 n 0000924824 00000 n 0000506552 00000 n 0000506825 00000 n 0000506868 00000 n 0000507118 00000 n 0000507161 00000 n 0000507433 00000 n 0000507474 00000 n 0000507724 00000 n 0000497692 00000 n 0000924901 00000 n 0000924978 00000 n 0000507765 00000 n 0000508038 00000 n 0000508081 00000 n 0000508331 00000 n 0000508374 00000 n 0000508647 00000 n 0000508688 00000 n 0000508938 00000 n 0000925055 00000 n 0000925132 00000 n 0000508979 00000 n 0000509251 00000 n 0000509294 00000 n 0000509543 00000 n 0000509586 00000 n 0000509860 00000 n 0000509901 00000 n 0000510151 00000 n 0000925209 00000 n 0000925286 00000 n 0000925364 00000 n 0000925442 00000 n 0000925515 00000 n 0000925593 00000 n 0000925671 00000 n 0000925749 00000 n 0000925822 00000 n 0000925900 00000 n 0000925973 00000 n 0000926046 00000 n 0000926124 00000 n 0000926202 00000 n 0000926275 00000 n 0000926353 00000 n 0000926431 00000 n 0000926504 00000 n 0000926582 00000 n 0000926660 00000 n 0000926738 00000 n 0000926816 00000 n 0000926889 00000 n 0000926962 00000 n 0000927040 00000 n 0000927118 00000 n 0000927191 00000 n 0000927269 00000 n 0000927347 00000 n 0000927420 00000 n 0000927493 00000 n 0000927566 00000 n 0000927644 00000 n 0000927722 00000 n 0000927800 00000 n 0000927878 00000 n 0000927956 00000 n 0000928034 00000 n 0000928112 00000 n 0000928185 00000 n 0000928263 00000 n 0000928336 00000 n 0000928414 00000 n 0000928492 00000 n 0000928570 00000 n 0000928648 00000 n 0000928726 00000 n 0000928799 00000 n 0000928872 00000 n 0000928950 00000 n 0000929028 00000 n 0000929106 00000 n 0000929185 00000 n 0000929264 00000 n 0000929343 00000 n 0000929422 00000 n 0000929501 00000 n 0000929580 00000 n 0000929659 00000 n 0000929733 00000 n 0000929807 00000 n 0000929881 00000 n 0000929955 00000 n 0000930029 00000 n 0000930103 00000 n 0000930177 00000 n 0000930256 00000 n 0000930335 00000 n 0000930409 00000 n 0000930483 00000 n 0000930562 00000 n 0000930636 00000 n 0000930710 00000 n 0000930789 00000 n 0000930868 00000 n 0000930947 00000 n 0000498691 00000 n 0000498713 00000 n 0000499701 00000 n 0000500718 00000 n 0000500740 00000 n 0000501743 00000 n 0000502942 00000 n 0000502965 00000 n 0000503571 00000 n 0000504516 00000 n 0000504538 00000 n 0000505323 00000 n 0000923240 00000 n 0000924009 00000 n 0000510192 00000 n 0000867696 00000 n 0000931026 00000 n 0000931106 00000 n 0000931186 00000 n 0000931266 00000 n 0000931341 00000 n 0000931416 00000 n 0000931496 00000 n 0000931571 00000 n 0000931646 00000 n 0000931726 00000 n 0000931806 00000 n 0000931882 00000 n 0000931958 00000 n 0000932039 00000 n 0000932115 00000 n 0000887895 00000 n 0000932196 00000 n 0000932272 00000 n 0000932353 00000 n 0000932434 00000 n 0000932515 00000 n 0000932596 00000 n 0000932677 00000 n 0000932758 00000 n 0000932834 00000 n 0000932910 00000 n 0000932991 00000 n 0000933072 00000 n 0000933153 00000 n 0000867721 00000 n 0000933234 00000 n 0000933315 00000 n 0000933396 00000 n 0000933477 00000 n 0000933553 00000 n 0000933629 00000 n 0000933710 00000 n 0000933791 00000 n 0000933872 00000 n 0000933948 00000 n 0000934024 00000 n 0000934105 00000 n 0000934186 00000 n 0000934267 00000 n 0000934348 00000 n 0000934429 00000 n 0000934510 00000 n 0000934586 00000 n 0000934667 00000 n 0000934743 00000 n 0000887871 00000 n 0000903825 00000 n 0000936933 00000 n 0000903849 00000 n 0000913120 00000 n 0000913143 00000 n 0000913348 00000 n 0000913830 00000 n 0000914168 00000 n 0000922271 00000 n 0000922294 00000 n 0000922492 00000 n 0000922913 00000 n 0000923194 00000 n 0000924202 00000 n 0000924261 00000 n 0000924389 00000 n 0000934819 00000 n 0000935889 00000 n 0000937043 00000 n 0000937243 00000 n trailer < <87B56BB34C394ADF4C30D0F7588553C5> ] /DocChecksum /CC9593EB690A77C8172C2338C6C0B2EF >> startxref 937783 %%EOF O-Saft-22.11.22/docs/o-saft_docker.en.pdf000066400000000000000000034573711433765727300176430ustar00rootroot00000000000000%PDF-1.5 %äüöß 2 0 obj <> stream xݎJ$ݯk]&L@ЅeAt!ˀ`A?jP~{3FYU}|6\939|l-ߩgmӯOgW8>GXW__?O/.> 9壜{]??(Mk{ -2ιm)]蹷 i%Tk:>_?~atH28OW'ߢ_L^Gw江#aiVGCMs>sZZKSnZu<q}lSשײ-q}nkTΐ절-niG~v|k۾k#o׀5PͿS/׷qݾkrRܯ-~zao;`׊W/Y/Ϟ~e^_¯qƲy!]iGfۈjsZ,G\t\^̴WZOsy|]׷g6:؂^ݣ|Zqv-'r6> ȵÆ(OG>3;/@U}׵9ƙl;u;kʦql1s8֕–o9D ]GԞ}=a[⮽|'@N `;sjQ W/atq'[KQ/RՋkg^< ^sjdKqԂt] Zٷэ-oÆ(NvX ǭ}|+c bg`kȌ8 ר 9 v Z9ƙȥosu Ry18bcfFW*[J=8 uٹfWׯu`y5;~2{0Gc]-rhM(jװJ #nNx;7o>F̉^üku۵ځSpι;L)݀kpo{r&_p)QRq`x=I1Ľ-imvFܶ%9p}Gc9Ցc\KVucqɠ%8ݮSg;h[s' X9"3r!Ez8 qS}^GK+?|4>.;rjDIiN" n/q#q&~(}+IDNhwOn#ɵ0Z$&*.$71/3J:9c~mJsdl.쾭whi;7' _K#\:#rI.;r96! c};/a5ܤ~|8L=s8hvcoőc|>\#r<#ȇ]=(DїBZvGq~@]#qpz-3^;FRO_/Y\|'qOܺ6c'r]l81>)<##W|=\SxN>8+Z2#~%"[ kL~ zuGm(1Lg"3v:plx/`w9ѕ-LdO~\swcC $ c}\"=8pí)Вy301LMGyBdUqP&\sX%~m^;c˶fj@܉$^;p]cv&{`Zuԛx0`-ks_LjI~7%e/<gk/;9/ԀnH(\-MȊ-=1.HT\:,\/4zrqc#_^wv.džg 'ҳG񡠥!r,eꉻ W^7]-O!?{w\䱿½P2O@ꕸicg/.QſH3-Nƣ| ;d^ yNegKDvq_ ɘ7y}eD JY뮮`ߠ1DNMGQGq2ߣ}WnZuQx/G_N5DZ^nշҭD.vb8`@M-@ފc 8<0;|ԃv8LENit FǍa^qy^{ ۺm##R+llw a,_+}k5e[ZWC`OF?Qe 2QՎml_V_GB<{̫AUpk,zvXpݩ5p2ت [K9@v[lEV~~lQFDΧlkz|X:)*/h+ +> nc%t+^voS2}2bdԬbgY6\;O@d2ΧvX˩L`)qVY- \!DQ:6o*Q}nXL2q~6`n0H8qc/`]wWo=W7a.3z>]S4{6);9XT,0S,_+DbsiY Zybr4GqryG(>lU~dte SV-JTYM/}^xTVÎd-4Wyc7ҭĭx`d/lEș;|v7Ūݛ[ ܬ)%A ЕD`Yf+`}k;#jɸZf 5(ôV/ۜk%kµ(k?O&> jwq_MW%a(-V2/3!f=W'VR"{4?[$d4CRyiTL:µ> p42#R˯ W"?{lRRͮI+/&#-6h-51g5Z~no=gdG*,\.O0ta2ƣ-ݏEߢHd*ƒ[M8Y0`Moz 348?h%sDj8sgԷfgS1;ewۃGKoUIՅ:iY0R6Z[ṗt$ߢ 5 Hu'Ӯ1gJBqPhޯ!c"ܪ:-IsKGZZOaL+wLykGZRMrE4"ZO|>C13-ɯtWy|*!m5fdWV 2yv=z6ѳc'Zg7v%5L]مL_5Cb5 <:9+&_*dreL_U-3;-2 x?${F덬JKg,Z8w}Pó?$E%!W~EkgA-Li%⼑mW,]Il96hC'Z8XSMH q7pC' v=Ր8IZ4RX+I݉;k'f%F9O!yˏ\rkɅV<6۰8+JviPwxpDeHyI`bY&Xî8Xdv?~fwze JA͏EVah3 ux;Ǡ۝.^8Ɖy¢=TgI]MTt1[(aY'%-zg9N-D}p)@$z<ȻE1-TfH!M­qM!R!X|IRjlJ\!hgc̖A6Qn0B>_<#тjL-0y%b̲'Ai3{`#},vve>`/]c <3 )nvumT4MJkYԘ):EQ2 dæ%$:[Z={Vʌ9MIaU6U,⼧ϊS B!`f(nGuW\")kGYcT_ &ڮ17\tc$i#-akYS)4 mttCV)>Md ."V9|x@@N+,]Dmw2AAagY^DKIM~3Gr>5]F~!1{,۳P @\v=}vK딅[A3͉֏B͉kgYAtl)E~&]IFqgqc*>xb+ܷ0I7_!UW9gEP,nVtl38(Ú`NX-y2BbI)s[yZ/qgc|lsb;E4qtp,:Q13,dQ; 1H;w6yWXgVJOG~L; /a0h+{g'`&ݨt 9`O ɤy@VvQm{5ϥbһ@8[ }arm&ՓF*ool]3,|-Ut^=nJu؝qm=R7yF7. x" l By 9y@$*{ئ9|ҔDq 0\0e=8=K1o,e~B!ؕ^~yBu9E7 NRcuSGaKUag!٦pBxd,O%[m`gJGF9%ٌEE"Iy< qAqW%1#(f,+,5l|H'⒒X7=l^Bqޓg=!%d Aj_ΎdA,̿~ݙ_p9\ϕ8ِy'P+SÅ.*gւY:Ed3\ҽ--]W/3@ *]M#ck-)L3W5x;>zqQcm(2П3D)~5)/n|;kO7 } 65QƄc;C,oL~6ZYȢfQ#ࠦ*7[8y;Y}L=) 5Vq-c}Bܼeγn@oFxo[XmPїb'$1[\0g3:9cl_{ lik@Ͽq-k0^=;Oeң_as{;U+DQU=#kM@\9zwG}pDL8+=vۄ =`:ITw^tY8;'z4z=ZS%d>F'[4f/ i|wɮpau79Rᰄӝ o\(2詬r׵>FƇ9&, :unDԅm &'k mƲ~Z5r6S1D~Co8]*{Tjm7:/azQBř9lo}\k-hc/}Y\m ly7=pdLw69"EL5!_H- ?;LkW.qyȂO_3.ma^Vh$xXO/A&+z%Y>dalw%Ɋ-'mY(Y0Xf(P<܉-ɥ< osр}5U97HM?oЕ.Qf1 5 alkp7G˱H,(Nو'MnvS}-xxPW`D_-'11t\m[/teřqFIB!}GOGK+ь^q^3f*?އm1ٶ7^|K, pdfheqp3j;`sҙ&L5{Ktu0{.`ìa+z9ܲmt v"}57+zV" Շ8J\cΊ8'Y܋-% i 1SP!' 1i4G,r*j^99ƙoJH?x24xƕibk2QBKvg!I: 3Lٍ'Mݖ 9F00~@M--I 3z{oY.JK}ѽ#v#Q%$.3NX'ZjS%/ڳ7f8#'Q! PAf< 3zึѣb8=p;cO!76ȍ!g"s7GcT: s]Nϧ-{po^,Vw~IGi/MHH C" odҡb,`txsE5D~F3 Z܍;d'%pl!f8a/̖BC6T.7f9!wْmw64GKowq&;3zQX(=p^bo_"cF,] ,Sk?u9\fNUJ 1Nٍ5`SJrD[F\Gt 3ayKW޼cь^Q nj˵oa^rňvV.V:^Eŏa+zI VK8{"ȄUS5'u*ęo&[Qc e(BPhZnaNt9%g1ZdA^L7^V3˶OzVۆ4 Rlei8g3zzI9.4,X, [f"\ 'V؟J۩-K%i({=Qݎq^󢷚x/2=ɘ.f7GCа,!cjU.{7N;=y2r< [*J@ 3vT\Izv~xW@@v'AK:0Ͷsq12ƒvtMDGFo(]||bf#vOQ/%Lَ^lG©F2e,ѕ[ufq7.H7PA2G/߽'[8.AYv7Fo,:akzfK< j5HRƓ^DjU/8+wnM?mR? idE|3iZUH=lm$E!ѓu7nv!22La Y&f}K\jVdGoN\7n\CZ&2zׯD-?ez7z n_| |獆T=&GVQ-=1=Lwncْa6=Ųw7' qM{BհL$*"g"s# ua/;4FO1/!8g7z{NZQ%nraEk;z|!,$,3TaZ~7I.rt@67;,kfilwS =svYP=+<7nJ8LXpwqX Ti0=t-RuyrE8^6X䖽/Kof>f&6Nr]8^A'R4gxyKC ęсaFWXbzV%EoS 6%~pKƌ/E]Q4}UwbcKO⦇x[D("Y[;loת1Jىjaŝi"Wx5٢:p8ѳI`c)'zhd-Bq&;'zzz'I+]|~H2]' 79eCU/,}iW?H_"ƙo%0̆fzT{؛Y \H~]?gYT'񢧿`%b eãd˩kƊDdѯZi{!LONkWw'jVeebnQ@qNFۤx;j>c0fNVf(( N8i֩`aE}}t2 o[T@'c]Sc&G_NQcΌg cx:J,9"ѣ%0=HΚUQNK7ZC/q&;7z8RlJ&/%^ ?﫿ckscv,3\d =|S6.RR #6J]Vp8`;ѣnE`gx Z oqFa;ч79nE_:p[KGw3%Y Lh >hՍ҆Z>?F"W(AB h0WM0⒜I4Z Mu v4Ӎ7Ė!)G-s-~' N4~j~Ƨ<ۜ|~K-VOK[ҫEVZS~:ғkk fU+tWp縿-dKtZnEu Mi3❷JE?_ B-̵ݒHg\0&Kzt5τZzo!BQwƂanI 0v pVmՄ:yr P b8(pݓިE6%%:ܖp?1 qE7GK6(8HbSE:1R-qF]i<ܙO%O̩삋LoOE5FŨy<Cc+џ_<:/Cb Q>Lo.d+.<w,Ig,јcqD<1,&`ƃv(,Eğ 7yƨ5Z:izp-HrqP7DyB|ZҘ>P-ݘ^ۃhn Md@/=64yTWT=tOl@kڣ;&/cnqj KMdMe1dSlgT} i7D/XtyF%߹mdM#`]5iɑ~R+s5UM8X>FZ38O(7Sua7=ؤgh 40GqPjYG3"dRKH̅ڞ--tfGyKoD&d !B)x%7{&pI 8m+FlzNk|p{)`GL{v-Ƀn͆lPkTQ#ϓ~Ș ü'ԊN֮lq>ُI?VIY;0=E@,aTȪ[ZLOQLbQ[WSf?yƩ݋;@06sOoU(OH4'[J6(=V< ՚^ AS*^KUyPKcy{u]>H7+ CK33j(O贴pm;|ȞjrOK[y2Sim,T VĆqia+Ov X5b8V`G! [YӞ~8O7.B<驸 fnt!?!qjZ^[6Xn +3RC'Z!X} n QoDz/'xR+1ئ<6JQi qQ9gOYjpgM Vu7u $G"%iTaK 8yB<_; A5K/50I1.-]!4Ijh8F_lA' y<Lut Z}?%N-;Qg]q z_}DywkJc{Q/qpjYG"L{A[Qji,oh6nBldxPKcy;DA='GqhSeP/ϗ8t,`Gkf!`/A=kmďqPji-oC4qqHxt]vzEzPKgy&M?}`.?\aj+/O,`r?KQcwZ:ˋ?PoUee~ԏ}Q+<#B ͇,xw*Yxa' Vx{\^Aa Xsh}%F%J~2鲨7r"# V xt\xN ~M  64NV8O>5=yBe>Z>y\VC= N| Nm5zIe=Pɷd} OrBB9iɷLLeK'Zgzkh2.9%i8OX*G-ӜhG_*[S4 i娇nB_t6ٟ OH)Hm0,EuTB?=C ֬" &qEP<ȟFVۯZKZ^ȩ$~%iYQy5F-_:P)5,'iIcZ7Yě[*d#:iiR釮qj].]Fw?QonO-a޳j]ު5YDm3} PV DM0<%mgCF΂ aj)m(]t?8d;}9QP?yucyf NjԗޤoƙNq>be;ޅy~>o22#ovp4_xw aB},JN΄Zd7oMVDc[T-*#&*Y{⟧EZ8+G9*oޢ k~2x}Hڃ_w1Szm240%}B )exie ?5_V*{QJ7 -'K/qC7E&j'ϹdOo8}qŹׯ/3j+2$me ?ZQ|8Y`5=ut e 7NZ0:VY04BTWOjIk;VG060n Z&8i {C6=2Ik[։^ŝ 7 -C{ZfeÇnLvU>6ZFxo [HWu9@yM@I3QZ~͖q-E}8k^-pu|"%Ajg"MH5|H_:_ ϻywy-2ι?э}Ɖ:ѧM#/YѫA.>|Gg8ϧ,0 50Ӽ~ afjdsg^GC3@KӅk#|;fk+[%G&W%+G78}:%KH {ѣ8Wf 2ξQ&={+zm-BD-3*܊-qwVSp+JV >[R|%_[tj4ђ=`]ם+2e¾s%!fxcNC^ Gkƍglm*lɐ)#7qY0Ir:S7vUѣ rhg"YR0K]f 6Lװ9a7zt v BenFT.! oqB*@g݊>YzN[LwV8# QnWSvO]).q ?;8CYS΢K]o6CR$Lw>9D )=F@88Fh2;H9l!vGq'z㦾 nau#݁Cpo>9NI @"-yȿ /:L!H~}Lw>8ß݇>JŅ - 7F o\qV4ծB I&n SMy3߸9;.hII,С ԡA8gzY#y A0gz,-q)ÆC9{hF7>߅k,>|e@c=D2 JlqF2(9uH&hXFuskƆ8gR6!Æ> ]Ÿqz "eh -`)х-> B ΅gCUr/C ;xYj G,8? |#c&~ђ7  d)Q -R8Z7Fsttd{7gCyu3 ݣ=) %D 4eygz aHA bst^@ߘLSG H礯Є([Rˑg"3W\-e@#TN$yƃ'T5pYx;-ݲh9\m p iflԝ+l/43b ΄8p#-yu ^}&@ު+b =N(Mz 6@hC4lm+^ olqLЧ+nTC>@λ1ȫ`Æ S!P;mң GoL_Et_E`i#z&lB$  Q=dn`BP;i`Sl2axU7rCz!c ?{)pHU$X稼qɡ< ?{}#]yYI!xA/q^s+Bmh*f6h񷺷8 =HT e$Te`/N5X7>9`Cͺ 롮TnֱD?P̀:Z]]0\sG_A.8awKGЧmfB|HEI!wz`|Bj4S{lt^A`v yH:r@}ؖGGhA8LeN`ɺ}BqK]|{ϗ8=@2cC@="m5Dut uѕuz`liu0+w2U  U,ЈL;zPAGև ) Ɩp}Pϳ%!n6ѿc ~ "-y҅-u,o%H ]}u]-uagqq8W).`ƺ}p]<,5ηwzY@'c݁@Lw8#;1 \8.q  m?9\ܑȀ޺PLwiYȾEQT@rQT qh@o(([=A+OcWܯUBXEeJ4JmV<8za8yVWhЌmё–K ΂gUsebĒrw),Y7ta zQ?eciA:Tpl@X8WUv#K5í6zBƀ'l֥=pHXR>}0cn@~(n#hq bnm|K}gatLygFW kӐc}8}HW~-RUwGQ_wЕ.a&?&=Ѣ0 QԈ}*}=0.WtТD, 4u[< ?[*ea;Dn mdg,QyaOIܤ4IoW Da51~g?o0]k-wryWɣ؞mayQN|3!0x=A}Y$u 3ߘX_iXwG ;(t =~`\y!b[ Ҿóܶҽy\ ?b= q[/5L~?>?Z&ZAsƿ'xtCIɀ[V<>}(Gsac$X']6a3ds=~vB}1,d¾r y]f_HlR>cLcƒaGgc~١. Z\d' 7~82y9ұ?. Z%N@~c@(7q܀>AJ!vpǑ`6X =jdߌhZ…&PO-bZYvg  wN:DSHC-#s#QӀ#J -(ųGujߦekb-(S7a/j|~ |8(o}oSjN  穮xh|9>6'R˫<&h/_@"3y+E5%l 'u4\kx?ϏsM~I5,E9 ~_}=c9fk~~:[|Au^W \S'pڕB]t 3tG,|Lɺ#Mc2GKF3񈏫(Y1wpH{C[[(賰ߖ%wS=nm)i^١((^_c H״e:Z6|vneĈQԞN}e?KxQpmi/??<'$tnqg3\6Kc>ԗO`e8Ot7^DVވ,ڪ+J|ʸ]1-=qFvwaZσKń3z9ؓX13 EA܄k/pycЊ` t(ɨ#j]u-~W@K@<"Вw4<ΟSŞ4mtşD8hbW3Jrtqe1iǿ:@s!X'=(1ʟ0Ox4 K A tG+`X]FC!`Y!8Γa)4cw!d%0hF5Ti։I_w%Ak%3-9?\顫.I$#%3-9ɞk#U:l`uWҝĿNK',Zq9%EXw灼Bqhi36u[GOڋc'Z7iML\G<:pi [FWaPii4R$բWA9n_յA VrHo{<0x7{Npn]7o.);ء en",$n'iCF=Xqhs1w"ECK(qh|;G{6qrP [N jlU<4m4oQqi3e7ϯ<`K,~`v ҅kx"ne ;'{8f/u06aX,9 5ysxMI5ވ7"Ł`,&Zx LKt xpl<}8 ¼6Msy]g$ b?yOz+@]e5]4XI֪_lwU|$|~!0O7k -D2D^.=c'lZ36WK{^6=X`B6n3Վq0j.΋IxV]v=8(dw.ijgl̼X6:y¨;[C$W᭏dk8y©5xPpmeS& UzpSlbmyN# ]"nC3Vqjo]Z8У0荾<؀0Ot!8X .hٗI_vz/'0Ht7 @ </=)q SKx1h l>x@җc'ZZNjA -!d?܁~/0(t۠\=0؟±/qޑjR]6rQPI,& 9z5C{i'rN8OX"W6цV 9B'ZRfr!ӆ'3C%RX#;}R[Etp`-N1R-#UInu%؇؀FE. 9y@|2\̈́M?#^m_Aaj.i!ϩ%Vp2uܓB'Z˯[zIQ/Q=Ǝ^35*Er-f8Ya5;G5Nd2{g"@:ױzK! (og"!.l ( Z8}X^-pu<~;Sl.l2G˯٢ְcJ"wsfwei4B{'aed7NhrQ˯2ϺE~Ui=U(%n ( @YLiV0ZY'{[z iKlS3^R 4Jk-2O;?Śߨ_ӟ7{)dJ;\b ץQtk᳽w=dTғaKW˱UyO T9ͬ3>Nr5 =@>_UWx+9'-\?zf*ևhA2wL_8ڡ(?w vi"ʖ]v93 y)LL0 ߦc?o(iG-65 qҤ /%6`NWR@?~3D!%|npFݐ+?eL Zu 9ƙ?l&gMB\^c og_D5N@Ag)px2+rmB+6 o ?Cg,t-eWe3hiR%a&O6´ `n`{f;p`r7# rN7Y`b:}]z3_\@g*A̲ j{乞R]r 3׀`p)} $wRmomՇc}iDޏ(8{ htJ|i*USC" ?lΘ( ӔpL)B.Pƙ?#ls4net|yҦZ8RAZB9N-)ha &Ry d5)OS"L+TV/by(w9]Z)Z8 ?%H@^]8PTي 9@B@AKf1Lɤ~Kv6m7h-ErC3GNN3u4a9 +oq^} [< JnʋBK]*-^ xK8pzsP)+!ffxC( K}@(8C ׀ZHIj_.խl>l  8:]?MDǶ5\_0?͇.eklq]%{"Q%ɤ>8c/R|3A.g29ץ#bp$@ p+ JcKNlZlrLIg"RpP?*qf? -NA]8cw 9 u*& i%g|ZTiM.C]+غ x3E %'FL&6Z a&'z&>!bi5,d#^e|wۀ&.5bܜ%* :\5L>;_}FA0mM-:-E!ʄѤ~7JP9;$0{VF#6|CPo rJiV>4\Zc 8}Ͷ%@+yHM0'e <CzXkC~ۺy𨷻-h>@JAOj-m0z<mCJ3߯@~iV!~'&Pq4T]oN!y|-C/MTksjü~SiÅ-"be⇀+>/?a(òkAO^['춍l-U!ʄɤ~/]{['a.EiYxd=N1L>Y:lɌ x)Jlz1h9v(G C{EHCk|%~oN_`K‚R쪔-} ~aPBNpC(vCf׼cw e&`RZ!C! 챋1@1}3Ex"2XhI-Φ@3c b&`S.[|" ,4JvoC~w?+Hl-+9c(MlwVߣ|U|j.g%n9."&oQOHZY( G%pu,`PA]s|mJ>?;?l YϙP&i\ϓ~hC49^㟏z.Ru43L8l -f"4?Wu+)Z$LW\@e|Mm,sϽk,nKLH ~&$ k̃nn/qe ֝2AgG› 0E5ϜYo]C ~gOnCC h|t [IɔF^1X$!Nlds-3,J5{-gSx;Re-3,^yL0 C@ Lsp$DyF-f@uz2lnLa7>#Q6gf Oز eg[ؒ3z>H%Hv['tYmJ)(n/ 5:W+9|/Kk.2wvI¨Oɧ0Xo3 ئ1w/0["#Uc]mv?x^-6m,޾c͞ƗZi1#lXP 'Ynp*i<AԙḐR׏^y#(OHPR7m])ƧDə]<̒ ꦾ_|%4o+ПoQf| "(w;܏m{*ن|/U}:ė x> ֮ONw[2[rBetᅳ9#Q.nr 8b$E'r*'ф6$<͂},i3NxnލyBp80A'< vhTiE_<#nvaϦ,pc(vKؙjg?RT (U [*w[.#]v;H01."x9ْʰ K'Y=T;#?f>8gKM A= 8y˜E _,M#Zϝ/y a0f?VD}1PFnt܈\!|2w ?xL#R&'V̋tysa EkpG4.wGF»61c'f":e/Bx&/{qc'fD\Qd\70n֑zjQ#99yGmV,s [JtF#7fųQ#%;֬Q\j6N2a}xfyII1ڬ3ۍ9s$e=Yh^c'(9E=af hф\=e<ҚXv0OxNpMr'nAu7x<+y@ux`6b&2KUB՗0س"֌̶f% ?__<`6*ǚwPDw-M;ڞH[<'\ID2d"aD._~DY35?r޹+q!)@y'XȒ"RAzeN߷Ȉ~(W~eќ+e2=g MA}_?1:$j$zKê{clo!kH" ̂>{k 2*]ǿtyP#K sD7?0hVj5f.!dƀwicH<Fi& #N}`>o?Mx]n|LO"|>YZ-W %]i:69bnrR'#:&<w9e>nmfmH DuUq- jRS˄CΩlg"66[ jP-pu<~to &_Znb'2mﮓ^jg"{cfFxo[w=&|VlgW8   =h5[YkD[&4-5Msz!zyKJͅm X-N׬ A~뺈_eu7cK#0$Jyѥ4 BRڗVx]nIk6ݮ͜}y=OxW'~6?>e a\/Bm0f쮆f 7>Ccg uɹhXXJjPkIj3{"6x>N\ㆥX~Ha4SOϵCw{! րeoafkh~ا::Ր2UV쎔S?l `1GM׾?ſm|Ⓘ |ƫ}[>P4=}cA϶`~,(Xnq1nmƂ+_hc;#2u~vZ?C / 3"N {k7/JEkۮhc^ט9 +?s:.9i5?so/ch)Zc,eQ|;.俊>|؎ϯabs٪]^x&3'fJ9yyhy߬>x*vtؼܰŬW雕gaNu4d_{y ØP<WğL;Y'(0!n ~tl犈?kN<wDov W%!A'] AZ !@o!*  Ho~&AZC3]&VD FD ϸ~Ed_CB#W@wz+\x' Y h ϸ~mBVY\ag?Y, E؂h '>ⱘre,训Dg^*ݒ09[T?#QϦN2flѭ Q{] ȜF[w$a|DQk;pinzHM6f!z׮tFG{c~&mٰh0B Yeۀ#S[Å~MVi[W6E,3ș4dj֝Nؾw*tYGPwORt!UymRm~XkjbZZƥث?cê*y wI~3[HN -vثd/A`x2n=qP옣c?眊b3go,a-9~b52{? zE|1Uŗl+~05\/uK/{aO3?so5[+wr{ /~O+=K__K(9t%l̿_/%/Wѱev,]% R9* J߉[gXcGoK/ ~Wqz=ߋ,NTn{̝ogl}[g?t68qLue> TWt;2WNm$YpƦ5[E.BOѯspxQ /򯗖׿ 7gUF^uXns~Wn˼>,^@:nX2~XQRK~Buzeո6w|>|X1è$J|xy/Z~] <//ug\ An} Z5F+23>&3L Cg{S:GY]!y߬CGmLՀ#Á`Հ*q2 O3:?s @n>?q|?/|hVyҏ»lc7>Oӯn29ndrlZߣc+xLkc~حJGxI&d?(ILA'u({ I~!%a9s"XLʽ\uoqxW;4>GHSƍ1J՛ݟFgjQMdm} U>;}U^iĿ,VUVJ-RXFe +uhJz_%1CH ^u|⦬^znd}??:gML@,nU3oYigi_뽎y-t +xVޫc6V Ec-z.V[cye듷<0>w {#|̶cs /1&qs&FڵXs/DCcvαD f+N ћͥiM(W"qʡ/D[-t± i0lI3Fjqbʬl9 TtTTI2)k\._ ʙ7o}I 0E %q.ypk9:P`渕}-p9\{r8%Ȅr@v=MR/)<3I-dJȀ Ah-G k`jwq>b*y6O}uCpN` x߃LZ;@֓={A49:'vhpFMCQ.G j4+m00vo6F ],s-(V-BOgG4O `]8t9 s Voki =9[ђQ.%<ף:+'Vʠp{WlƗU|Fk aϝT{Sajax"J/1*;ףPH2&C55wDэJk(;ף2+YYMqIJ5l/F tt ||pCҢ 7LgGKc a977qU< Wų1Ȅuzzl\{rw, -P׬g1F@%ar=DrzmCasK il])Y.|sL!vHώQqco -&SL߰PW^Uj 5_K%`킜Wφo^=DrcjHjlw橍w#rtPK6M 8[<ɵ{eo9 svcyf_OG;vp\7[[9&,B-4A?2 2sP`o9fa;gt_QI햫%ɔwߵb+(Ik!5g2MYKzq햯Pf8g@=mVcUFӚ1&˾NMG1Ots~kD-X! -ÒR6i \+.O90ܤ\7[_UtDh^Â*ŗԙ9M ?}czj~= s~%ոhaINi:1F@ef~=:ev* ?JW7Hr|]۵b踖YK]|9e:BbKqpf잠|0B27R0 a|1Hd^~=:euҵ G+zkT2qeh{pvMۧ[< >!ϗ-Zb5g3 [%U?QA<;/9ܱrJ'BmL5ϗ .<`)g祇wM#1rL5Ht谖<9ĝٗ-yW.yr~2qe8;A\B@:7A5Juǚ踖A=LP pTYbLPY,Gr$ZuuKt_GͯA,G\"rwܢ\9Gģp\2p'!%X7RXk'kWPTf?2}-ĕrz]vYfq`;gx P`9:u*kjW\1- 1AŮV}=S4l.)^pCVࠖDOEŗS+`/a~ZO1Je>~=:nq}zO(oÞ\#>M'_m-kyYU,9 A,3a-$9wβ69VdzJ~= 1(b\;_O)ptMiLǯGǴNHZPg0BЍޓvOp_(: ɤb~֑L\ǯGu=vjAY֧4־j/LMڕ}Xe rmmvrejNEM&;ezN~= q~b:"q+g+X.\LO}1HztNG1|5is)|@_=8;7C-Jc/a9b l2q=! wgZgxߙ*LvyT8Ǎ[˄z.S勴⣣lR RQe+OLPăCZR˩ؓkRJ5t#@2Ւ:8crJZmyJgy9el `T~n;%~$" Z9^"Do{<U)JjqdQ.QvqkWnz(TRQB])F ǯG-~B֊{^,{! =k Q'(<[%u5TWCeܣ\fףVi;,3,;;q7_TdzB~=:tn?.xBfix^Ԣt40e,^œ](;1Je6~=:et\q]3<3+L0^2͛XL\ƯGᲣej:]} *Ȼ;TfףZV*D$7vs_MK8Ę_=99i1u&Jih}!Dh88b <)\ڵ#O X=H/zjR,P['ez&~=nb^*4wW=rX? LįGݩNÙ w[c^A-8Qq11=٦Q-㲑ý 7<$2ֲ:8#kAYgWB-?ׯegqK4z,'Ѝ[0 qwo Uk9YgWFWxo(iB8|EĦ볽XdV-)dY!^ٛRKW[/N@_;P4Ŗj$P΍S+ZO$2 ;?] PkW.̃k)/!&'ף e}iwغx]uj9(Yrϐ9-r6%RSߧz$iIr JaNK JY/X9j1!H@e~= U E{Ʋ=iF!yGmGy 2a= vZGz +W7vNUG:(NVαNpVQp_Pi+i Vg٫VXGw{2q= w]}oH箢 4o~7 ¯G:lЬ&p}p7^LXïGgqHCōzI놧 SBӂL*U V.] -Fd~=:8N5q9^DM)F_u,3*a }=& %(Y%kXGRfo\Hk Y(Xh-3+ewx 9KLïG]{Dz=49.{פ%Xfף6wd%`Uf尗֍LXO¯G jXGJW(YAM<8ZQ1Je~=:@ZQeZq^4tez~= Q HI]΍gիV{{drc=2=CCbTsXף`ҺZGz7T $9[Q&ף ;)>OJX&gA/G ͯ9E T޽#_L\7~ )Z)|l /^Pף e"W=ie)5HzxJ03d+;9^xNƗtLztЁA-VtvC²5b2f|kFShʑj7LJJWk؋cTA:ݝ*k>TW.# n=:56~5i-(QB|Eˎ[3NஉlU)/A,`'HMB=|19•ntCg SQǏ|0ݭ`S$W:ܢ\ףZ#_FxՏI~!^Tף2!J`6ΰWtZ'h1_o>\6|@'ثVe5Je~=:OVrC'gثVX~WFQ$e? 9^'xpZL!Hd~=:"T} ά@hj8VrP_BrR::Q9^wߵbyV@wZcHWv$|0ME+[ΰ܃TfףP;' X{rj X{lm*Z X8,<ѷU:>B9? GI9&R _ҸWġl.J(7m{ !SN8*^~U^(*fqG>NƟJ{0uB?0*Zw$^M/lEjԹܽP_lN*g*9<>RJ%A7R׃ <6Į_Z~}7S,?WlWCZaLsc G{6qߙ/{ok~r]_Xrv VIhٺ]sʼna| C瘻}|%y/@`G;jME xK,;ps!8j凖W I, M^BO%#I+2mNt23]K nsBIcf!1&\_KȞk/n(ˌ/WB(76\q`ݻ0W ^:}-_zTm2Alu *lHO*v4/C^)>ihF3Bř`;ӗشFy斜?s\.9sjk%=jXnqx}_iD'!r|ִǼK3?=Xkk_™NDz}m_iq7I)yø]wf.:{>zxװ_0[؅{xŸA}u40C4ngʯ{&(߽)g[Qoa7|4g&ܸKQrwn_?&OoH-+'AOAWa^oX]JGMڹ'$zVOn+ꖥEH)_oT4GNA>Abۧ6ljuYNLr%d$PL6z9a7yʦwF=+X9 -.vfW]ƶQ:5tf1_yn4|{pîq9vG û%t 5k~z ?7OaZϗ2.ɷesmϝz ĕbYkP?Fx%~:]b賅lݽ^ACq :l*5qu.rfb0W٭Gaj8ѻ~˽랽D [kCCEfJ6ե15+/F|K֣Lr j꧑>߮(XؙAfzV\]TqÔ/F [+fRR]~XK*N@aC2qn= &фQ^}ZKv ɕxbPVحG&+5w(p A&WحG6~+g.E ]E 8z]\Nm88FգtTӰ6K"(Xl82^߄':E^?1bEvqjt+%2bRbTحGjlpsJC{I9(k֣jldN?4Uok(P}v娍1jqO]Hb% [;vRH?H-^c :E;4˱%JeznK!9JpϏ!Ndzzt1CKCrlfеbʷQpEyG,2IzA֣6\a_3YzpY`Z[it/q?Bt*& MXZ+_gA}MW1D(T (3VN/7^F%ಾn=:[ ͧ2sz**#q T2qn= ׬!̧E1YX'jM(ת;Al{#?/$@n=:&[p95PLHCy*^b{16uh5\Qz#X"(Evq56f۵rJezznZQUrm > `p~"f^NL; 4:0=(܃H֭G-+9HRJ@u^b va95]E~&[!Jeznw"jH 7Kh4h&pe5Zct]+.Rꯀ)X %n= z2$/U|&+D [{6kYiK xclKE( ܭGjtU4SzocTܭGʋɪhs7jE5NV?ѧM*uǤGW2Ytlw>y-Kʊhad1RP_BЊ% TzZUv퓤Kʬzt1,+ꂱն=ВQ&gףpmz\Tl嫵.#2+t -k=5cܞ|6/Κ)WAx 2a=+C-K)`9T؇TP9V gl^In>%JeR~= B(`[}Q6cLPȯG|gڰ'΂^_k `_kgѤd`n-(8`s2q=%W! ނd\fףpM5a yqY jLȯG!٥"YvhirR{rdztH*or1?Q?zwQL8u\aSKLzt1C>hת>.[}|LX&&A_HZL4A$0,[Y@_;F6CP^-:/\A*֣P5&'1^s1|' D?jd7},&PV}L ėCc`M3,8 I؝wnZM1J*Sq5*69D׀s;3c 0Gi(D7M&TRξa%ףp5(5WܰqMػS2q= wMy(q/]`-dtW'+y:Qz_9FU%>ueA&ף`۬sXzK[vR30Sp_;W)\Fm5r ё=^_L\Gjtofx"0N1HxpLMi}F+ 6k 1[հ U@m-Z`iЂQ&ףᎡaJs.+9qd  }_w^媯Dz:tZLXOG}5{mDŞ<|k{_s&o8eUlv,6ˋ^,kz_ SlmJa{ѿy_cyU̻l[z 1(AȆ!Lul?Ӌ=سT 2ay̳n4mjX cdR ̻Gj`v0|:8F ̻GǍs^i՝7²3 %-uy(CuSz*b]E_LG;'~R92,$cT# PYl/QVzt\:`K;/ Xtd#s3 %2ZDdIpM 0 zzt\'wN _tbPv_Bؼr.Tm`]`׮㯫,Q}N9Cy[ҰY_yc踴d_AeX%^4K(Sb˄zt\NDLjư.)N@_2qQ6E {Ϩ] Jr88C@fף0,"gއ'^-]'gzA,֣jd]4WϦmIhzl{dOƯGhaUUߴv ZiKˌzt1)Iċ%p7K!Ɵ((\ԊG,Y&`ldzZ~=:ۣ;G&^X/6~xφ)(L 씛 س_lJ1&'ף.#(-,K↌Z1><AY:ׅ[$^"K:X`V~0؊Q(sqȆ"=,U^5dpWy#&ezR~= W,,G[,bʔztԴ)RUba,p;]x1zMx4'xg}_3݇f@ڍD<SD,[|vmqnt [KK"a:xD+]0aL\OȯG+򺥈ꫠ5qN-%2+oQ~' 3X:o'œQ[ VW$+=6Eof'ףCqe`uL# qTʌzENL YG%Ȅzt1DNW̫&Qh1JeR~= c˪VY$ k=S 2ayI{OO&*099(Y(\~a$J:.>%coZP!FeJ~=:hQi+HqG xF~= )Gmsl@}ڄ IZHPUX]0.,SW-e~?ai@iؒZkhenƜuQVzneSݥ"$uh>0ECPףΡB'5zoȯA&ף}Xv/j>i.>[qϞ_BtAY3ȒTEU=8 3z}F|zƪI|fg{b2q=6|VvU> (ة 訝!*8Ƴ]bbz*~=:(rJmǡ|P9 6KේMiH\k-@_;&sE* 7c緺ZL!D4zֆj㷺 Պq}ߴb4ztغ)6,R^ ?_c 9(Pi1㋋r`Klu~A,SaȈzlSP3 k9-3@_-bARSUxs^LTOGG# (&.[z6fϲV?c(> ۷)dʑ%Hzt1i#I֭mYnd~Ӕ: ̾Gcӯyh=Jmjѷ:LTϽGJ[vذn._urz&^1qXף`5,KBЈyz&ZR1eJ" *rL K* ^^?+cz1+\_(qe04Q.֣jp&MK}#&i?iU1ȀM_xa9}VJ_\ףKWO2rbOtĮ%2{1ǭKUp >1Ȅztؼ)Ie_ /]߆lp_­q˥m p2q= 7qRqU5s8y8.s4p-5RldgUr݆/.*ȚLïGjd]KldgUr^ e2dz~=:w-Vzm)8ѮJ&.Q,r\{VWLxrKez~=:Mab{p3]WE v_Mf^rsb]r%7o=:z%qͽv[U^/ej4}2q=90YoU~=X+lp_;F׵zzj9 В1&gףP*#5Ps]kˌzt1&-^eDEoQ.3QU }nͫ\LD/GuG`/"|<ڪ9=J+r}p_,T[Uo˪sy 7p > XjUy1ȧWΡOc#@2!uF[X2p ٽ˸3F ɯG csؾZUʷO0c8 ףP"{vyU@bgR ˜zVcYgUy>WhLPO"+٨܅\ QǬrؾVU^eU\ף xqU>WQwIW\LTOɯGjlÉQnC,&-1z ˯Gu#;TWt o( Y(cN9,K< ԽecƘ_:;Y* ^0 ᪸/F%2)F\^ZxycmYBi %UbOt#Z[ p,%, 09P/%FdV~=:-{Q͔xV=:O‡ez^~= ֵc͔xW5ea=ʯGr lWBqUU 7†{`2q=1Y;^7UInd%23 wr 0, eNрen~= d5/Y^xիa=_Ę_a*hjJW1"21t kAU,&;iM(QԂ(jZ1dX>9G;osaBu]'/ eWǍ̻cz6L3B1ԓ Q^ JQcx=ۮ5\fףp}lM4b%V\\beXrxp1C&ՙR"஽ %FdV~= )Gm*7`X U1F@zt1KQ^ lzף`5,]j{)*%JeN~= ),71Y LKx!iOkQy:~=:Xnϲ_ AZN1ףj`UKqXb1# H=unRdu%!-TL%'ף`-2ʬ`tAzƱ7uz|AOKQYc †, y(TV P;#tڥ`'0هl[z~=:?q\?i:̢>#AH=fR m"0L\OGÝsLPcuy#;؍( AZfJA`8<= u[oݯ^95zEzd܆>g/-,[zt4+-˃fYE1&'ף@ˬrԶYBqE)F ̾GcW0` /:x=-Je}= GwxXg-P6 ֓Q}QnK$p7_Svϗ al+,~={ŧs}~۴xp1TϥU0r]Pףp".GɫdN^`\ }zQ.sQat=6,xRag|#z}=:9{ZkZ}t^;hcz1d5YVIJO:Yߴbs?-l |0-=ڶofWtOPě+ʑ;ڧ xA"}cj$ܽ4@ R.(I{6ސm8Y"6I7ޮAK#A ;4Pnx. w} J[O:xŵgP4NnlT?0*w>*dܮ?* +È9[ OϞA̿i'0=ޣLfgp.&!me j1)eVfҘտMƸ9&񭘪i<^o_1Zgg923*Wotצmk\|qgΎo(  ;з-?>:?nWeUOþcpRݘ]!n{1np ƴ -3gpgnY:QSfv34\~zGI,{q-\% E&.blYʄm\&  p6>&|DT4+=l'n2GU<ƍǽ{qj1{xs~/oe_r}+D^8iAUwW /%{S? Hc1 |S\247zgwZΏ5^Dpf6.#t1K~k]{$Ǭ kV&;Y7Ĥή^K5@?,].Im^6g ~(~I}Nr߱ẗ3G+qg 4nFw[n^  fӯ0K BKŷoҮqÿh3VcUT/Zf~ס_??LBeW2 C]ã3llɟ<k:{E%5jW t κ{zYol0ZȊ85)f5;=q-vbd*W=\d$%Ǵ|jLT粸F_PC%QSduF3IJʉ>nN_5(%%qqvȸ9rq4IuӴБacHh̳-`kBA$ *чT }^ Cq9Os$_Mʀ{؞B_UԞhbAKAU=֫N S/,Zs1% 2J);:ҶLPV]Jn7fN==Z 9vT&}m}cNz_ SpMm'rԦh%pT A6ă2(7ovfJ"+J(ъPb o|up|aZˑm݇J7+E ,%[$΅텗qg\i'4$dU`,% mRנ~,_V!7"e`Y.eyZ;aW^R7rjm0C=Kj;LTb,ߩXVB|A oO"Qd[:ŠdT7#K.`YR'p !?u+Ȣ2j-: tC,U^W ,ݝ=Sdh7ܬW1SC:j[$xcT/J6BKHB/$" Ͻ(n[tՐ'aeqKr}AdmЏIHq˪q~E 6ptR5A[U α[7#J, YXy]+7!ZOtF7dڄX\Mآ9}S\>6RZG($?3@bqM2.V~j&zŰK.TwFBW,!V&߉m]Yj i];Z mB _.&_M^y]mhR՛IPOX8wࡶ>^?pf (XFq|$֗C .yqڱk7^64]J{1Scv%lئj"E&EI%+c YXJ?fDЕ׮,.Cs)n)U*+9Vt%w,q+ \:b)bߠbRk$zfiSf#V7K}٘M5f+M_Ж˗(AE7|GZj %y?jÓLg9q#)=,vks)M:65d]ܞRNE0]fz꿫Eׅ;츪,s/b|:ܬ&q+8l/BuK2<i܎uC"Fc6 Υ8v<=&2iSknm.UAZ Ie XѢ[ UmzZvoNjW߄bʊGxBUkFp.IUAoikX)fL&,.ks܆UQٮ &®a:x17ab7iDžM*';kl#d5ȗ)F=:LlcA KB'6dQmfW69O)f+}ccݯtW3;jS}\QBe/(K|')&AtfPlRІxw1y$L'EtYTnT_džJxr OT/l%? {u/HIr@qGL ]7=%W KͰX!XT:aR7ۜ3E`=JSKqEx'IaSt Oiԛp|cn_cnX?ѓMa7lAf|Iu:gćp.-`$vB["B#=\poS{ :;S!nE;V"ex*ןKfrGllcae.XxcZt W(vdJ.owC1DP1x0OJW<+__T\o6N\Jlq3MbPyv꒹ӮccYE+5\6+6Ff*~s MM:=uХzդh%pKrOƑ#5ֱF1AMe%S6 TRT!*9v,RĔt%)]h$@_+5(a~FdNfWt=lq7l|<~櫓"ha r6 TlRTBMs(v`$fJ7YXXA.u-:.th7=Y=GUh%?_SmjgF;l/B 5ycH%*3ݣdva$0Kb} bY;]إ #PSN2Sf%t46bČpLi*D+Q%Lnw E)uaVc%|TlRAݏ ;rs.RzYr7 BŮlHV*8ld` gyq7ΞsEpˋHӒ>f$4`{|c5Gvt)X,%]:>|V\CWQ[e:Pcp.Q+b/SN âYF;yv`Yb%._E]&lmNAc,٩36I, _؟d1?wC93>&vsI,kعF4hZLSHb6$@N~u,IfTz۷oXIw He҇(n璍}$ܩ3t^!SHb8 ]l-F Vr2_O.ًb%a ªYp|b(1Svښ$=6cacp8l/CٰR1*]7%!˼ \cjS^W'dMgEZ,.wisI4M S~9)p -umMNm&( o. _ d8_$:T"՝Y/fWFvyk4W?~1zX k%oXXmѪTJ- lanOiCa')LǦD+Kq+:C7,O살tJu.MddQKRI ?PݰP)l; ]l?s+L6B{pBALZ_ [(&>(~sI$?[Dd! -o."_wOJjC?6ĖJf&$YoF1\Fbg6^Lը7cYR̅æ6&9Kh$6q7lSCm9KRQCeŠ̓{P_F)v$C sG=5l.蝝;(ݨ>E][b}n4uHuԖZig NUad{6́w ;2tIE"Ǡ2JMPIxF{'vYb9i]{bT4!heq ?ߤ}0Ul,tEwQJjqJ:ZgZt ]u(R/`E FBKɗ"Djœ/F8*r!V>\{2Ti>z %CFh$_^3SoG౫Ijwsrľqhz76v*gFBN&&~X \\_0Ob)ibTKr#8⎕)sxI͸z?AtÞJ`.屒r:n C;Z rx,"!^7 #ʢ-awI]n$ KQުuwv巚hkxCwVr6=.B0P][8vQ8S5RJ;הz FC%%펎7mQZK"8 -.p."_0ObQ)C&&p.I9U$>e.%$7Z \_|BP&;TjL mQj1J}/: }]VKkh? l>a]K6jRg/~ Im|Ƣr86ܭ^0.ѳ FEXyإ%(b0P]mW!4)J,VR6kQ^ c[]wE%[k՗+l mI_,G#\ ;V0bsIcCaWzX \lƄLTs}VSelpi} u=lkf遞,R;v؄]jwsM:qId!=K>Z \\_1Eq9VKfjh;L [̞273@ߤ5|j~[CQnї)PFBR]bzX P\_ ?RVP9)oM0讖\I=eeN1MK"Z u8`#7_h0%LZĒeI M]^zXY-o."_07N6^t)F+\;)UwZ-$?TǦ~?.沲d\`$i[s央0 Guls=lv1ג%i&WG 4V>Ŝي[d|`D9:T2uV&E#\K&#٬gznjfD,ͥTzaubԒ8ˤ ͮp|_k%ZzD]bRzX mo.&_}0/hvMY=PĢgro.IОʞjDj$T~Ƃr6}3*-U"5muY56Z 7W:LE7)L|Ƽ,gӞDvVBKo䍙 X_X֪zRFv6mQɧϻo.+)35.յΦ]1 0a"|X \ܷP3ӘڲʖVADvA |ng`D#Q噼 uAV2+lkK9/8,\e~ pN'?k;ֿϫ7tCxVUOj qej9nԶ;L=cx{9.}ߑΙj79ٴ?7̒vwxTOb =CmܩSz쵟zhA?eA@ݘk=<.LľKl<nVC:ű.T=ݱϺ ),=tIdxz<:g@/ -|<)e;S0:7hjg臄7)svA7u?1GQgM'C u;b~hYUe/~Hgz2em Sd]=UmXLq ̫ݘw+!e;]YJؔcű=&cuƎ5P{YUQ? -G'yz܌臼eJ_VG_!)0HL&8|#cTϏOX@=7-CZ}2L~J~IJޫݣpϪN2LLl2}w,"a?VQ~> c]=UDP U5&tzd\g=']Dz^6,MoP VucbSUFqj]="ϺN K칟wl26@F)ǥD~~4ndm&絿dz!{xBDN5Ƴ!|m=ܠN7C^ 80STYQQ?IPj蔁yr]=Uo`It¶]zWg]%OcK,7c! m)W?UYWaߦɾ!ķKwl'eUYω:@(,h{:3dr̽^Yz1_Z0IJo~H3 ?+!m{&^H]E=$,7 ݰ"ϺND7 &Q4|nXUdaS]:~;@`މ'I:<924'#!=2kZL וmڝM⇔7yc\ⷳųҳKRTjI-pFTՉC,nL9ļά]V/\ZXQQXgKz.`)v:i UY׉k=JƖ~|Wg]w=4O_\ R횞]5L8sIf`u ijbꙛ9s?C/Ҙ&uam/лYOQ.$_md]%Ls z. Ǻ`ԋtȁ2jyWg]o=F 5Q-8c¹_S/~?aNïE ةy|#go=d|/] Yg='\_Jz. JMJ{5Txs jJ5Ev }YՉg=J^G,l`kFgyWg]'\+ T_'jȢҹKPP)G2|WGM'L=1o!] n&\&e2u}~v2Ƚ:~?wxVtRVZu LoXF^\TIb^XgM,6Ru]| ȳ z.3{m5cG̊ӯKbC=ogM*<$uA*1%*ny񨨘23k1G1~ggf;.@)Nq;gRT%rwxTTsIj;HMߙTsAh+9.p:Ă@pِv뺅l`ȫij z.?f.U϶\~¢ԍ~\ PϩVQ]5LxsIC}iw# z.oԳߨީI-5nkm55TsI z5TncAP =1j~S'D1$O:S%LxsI(XEW=7j3ߡWCh̭ѱK@Ȃ/E2jqtIJg$sdoLUb"UC, L*"cD❖j"5ϚJz.AINʍj*$5@2uw( xTTzsyҍr oKb-Q agE&6ubQ%–ċ`˻jϖŕ{]).jW^/ѽnָ|7R|$a M_^7߮a?_sqaye7ZUF{72.g7b϶p DgִkS)#W97lNgl̟ pŖ.ˤ|}~u{T=݋CCaQk!lގs*7leϖ>~nd=u9AkzMPj^lm+jFpo:1 kݗI]nMnncMg&'^7_횙RÛgE}40? X^<7O(/;sf*f_c=lչ{Vݫ_~A5L~C59ļ}fnkX>$3Q>s vֻŇ̯pͯgL(sœshJMM>֤;-5~= k^6ͤ+^4˄׬O6`}CzyïT! cT УX7H?5:0 8;jzh(ꭤ֛M֔QSFoOM*_1o}ּ;5s-Aw8'%?;לl>xzz;zmeG9\Q7}>O%o??2ha~GR} |ZZ ^Z­?^I,Xg!WB5_vЕ_=`͢/cWѬ3݉wxOK+QϽAWaH6Ί ѩjI3֯,.gT}}yՕ/En RI7eT2Ҥެ|JFp {*啈/ElWLkQoܖǔ,.ʓ[=DJĖ흽C[mZyeQVpdʖ⵴=4py%rKn\2ެ<"{FM3hu%b둩ݼI~_nnмh}?%9-YBB$fxO,䮂ߨ~%rKsf?~OE.,.3TR)t'߸a˕H6ԙӈG̤;u;v_?f+}˗' \^\RF+oJ4ܱ7G_Zl*]l\\.ry%rvdn2N]o+/-ns~u[_G-n̵+/-n Uy{ǙFl+[ҏ_`yþ1z7_q_AJ'?3F*,*/'.s;_+*p W|?cïn *goְKχ +KNf؞88]La_۫V?}?+lƍvXؿw"2=s1Qcqc7A-kv kqp|tl s Ay}6s=}?Q0 b8>3T1hϖ6~C)'ء܋ko1Q3!7"wn>a%<&VܿP{}]k8Vk7W)o>G|<5'^dMׅ(kN>S#qglQoohq߱|M^;Lv̊qޯU*">glmWz\k-<4 Aw]|}sp _}a> }50GFU;Yql/ţYmnRy}69i07aBW|ʤf?V@SN=SDMCMC>BgI>n(Ď">.\Wya(/5>~pCY/wz~9/k9w}{^=# /]};c;)87n]ܲ5}61iת G5Ϻw> hqb CsSW?56%p8_wϊu~Z {D=YՏo늝'C[8}|M?cc]ZɘWX Y~4/Vro n%|^ו{wz,}iD5/Pea~^Ղf-s;~<|5t*s||l KFmc.׃˃?]Fqy\;e5nc|k"aGaΗm3W /ƨEGH)r̮LmCc񃩯@ S1gEke>O_Ud~=*@ah./bWiX-aX{GwqAsaMQŪr2궢ܮմ%lcz\RhSbwm[_.߂uchzYh5'x ׉y^6b9mG>m4{r9_m+6z݅?˦E kRO{ kVOω>f~ZY5ZՃ*i->!c9~5_֟s8Ѧ#x㝻t\qWokfʜ9s|`>+x[\n1b~'^=;Vnż3j늵kYc+T_WJ[b̫}d/TKZI#ՙ_ם^^:=|ttRo+<KqE9EN?1xJ٪B!=7;\<9.W=]ٱ;m\Kۦȅv ltݔ=vtT8EBPcsAȪlp7(˥TDqiqknr;C+Y``ae!! fˉ";M\,N;4̫dr22Vec^z+]s" S)|)jq.'RU3* dq(o"KW]1Wx"SZ=,27\gf@FK2LKs;Phl]z㗯ՄG4}MڽoN #\.I-6;z?5#,q;,*RԂګR<:! 8+!H)KroYfl?:ru"3\.En8E. ‚ǩtt ?҈,ƕʶ+h&޻ƕyE Ev\S5nC\*(x#,0`s7˅5w.R܁.jkUxF`}mP|Ydͥb v zKH}h}K?K9bAlEeh.Ձ.ƖsG[<*^ʥerjݠ -wY].ͥhgyD2$[s9T4<"[ ӭktE;ÊΡerpGՓ;xf ,l0<8Kb.:wM&s8Z6{uzR]+ridE3xeC=}InRN _.uvlSƟ.0'WGM+Y`%l:i߫}!sו}Qc5zC_,.]$UŢ6Ը3<4-K2pRG6~hl63q f\ OFuaǼ)M\ f BO OO,Kfgǜs mk*E; .Efn>Ʋcs\i~>,21?n!=2XѼyoY Txs)l"9 {dhiGe1z?Ssd.zh&];Cv ,^_7; .IfS\f>(Gcwvv\CG+ .EebR4t4ʁnMC:uҹv.\*_Mdcu^AVF 0'W@?"׮u1͹dNS /3K.u_at 옏kR4/\nG`mEi}qIdfN\{\r]4:]uJOdfqϥC3Zaۮ%{{UC`'%ɕuݮJ;PF8#p#z4E#:1pNuBwl^1bO+ .ED ͶEHR\-\I_p\efd$YV.\nᇧshh5kVE:Kq+:_ A0׉)fUq%bd lܩ5)&ԃd&@ϥ st +<y U"KCeW<КUrhdE; .Exru£q$rp4`0r3xxF;95:7bAja14I?RȚP5v/\̐ޱk.ecT*OWf]. hg%2Niv u)ON Kz5M(wXryj9kV]$ZY\s(<_v-wXfjHG<0\x.lE;L.IFs7~փl&Pϥ =t3U/yuUy `xsl?GݙbBXx4*g;L.ER8u4P6<2$W0ҁo3R'CVR]r E;DmӘr/V(E3V%Hp݋b;gyaZUXV^\*WшϓмKk >[UM* dsI;2L=53V@?"wRJEK Rzu]"%K:K J/Y`i嘡5*c+ \xs)@CëQ@kU:,.$ujt! F!mGZR5@Fcg){~0V%UkhE; .E8Dv =/WeN?:FքC#+Y`zsI02y c4 v TIU?r PR7{r\hjbMV4Rx\o/yB̹yUIU@6pR`fE9^. u& dsIg '8RbLR&YdsI)i T<,wm^vt)^4R}\HN>5wv\|j]6j]_8+ؐϪR4\Gugbyd*<'ml%p%4;\#=#gKȥ]TN Bkʬy=;}itș@@.IFk\yfj(cWrhf,BB䘹]:ե PRcכRCmC"A6zjdE+$A \.aEm;:a+^\.Mher/s)nCU3tg+:A6FL04@@.IR4>y,GӨi.E;\ `(sTQ67q@.ugVqli',:_2yG8 `lRj|j5?n:%b[W6it3-\:Sd_V@ s R΂N]9*spI0BA*Wh`I163ӎh;=\\Pr/QcҶu?[q2­lf%}JQdn}y ,dec59ㄿȳU*EǢCs44+D;,RI Ý3FRe򔪞f.JB)94F6̢S7ts>@6eJ%!r}&˄9 U?4EHR*IF#hd!~,e}9|J\fjE [[(  ,RI,rV[pUۦ4vǙpR2t8 `JR$33,Pk4i4,[LK'CpA}2RZ7ƭxM.t4N*t% G:l Bπ?ic5!;J%6tQ'}TFPjhTv9 $X9;]9ujs1[>,g.- { uѿX+`q [3$=IDJyw=B2fJyw+K9T!T 'd;U2NaX[A{q%p5F~AbI{:=Hi;:!+^هfPH S.LrH=NrGgUc+Yded(xS݃dӪ&P?̿ͪ`L{JR"v Hd܆m]؁>[%Y j83{4Ɖފ+9[]f')K a:%4(q\#a>*$1sYJW׎ 15FE14E?$CNj6 K+-Cc+ d8s)rE/5}1$6(Ӹ{^,0$]DȬn\f_kFXMNu[LKq;e#ed`a:tG<.t.(a2B\ȞuE%U)ʓ,0x\H8I@O_] 7; .IBu!:,xN^#+[}we1v^\|0+F`vXUNnKa+:^\w" 튭1lCO3LKOf]Ki6=t@O{"KzJ 1?-W0܋;NVD7ptB؁ju7m3ƮlmhhE; .I.ֶihɒfNѡ涊~6M`%`0ĺh"\N A>Hx\XR܊*U j܂~fq33 . nHm AE{& PȪoWLKqz:4:3@8OAEyYd:sIdw#)Qw 1r%@?"#C|#ʓ +oedA% b6ڨ_,9p=;/FV4LQsvJ< ʽ mJa-}pRdC-'1CcN**f)pg3K.ݙqnmX/kXDЙ@?"7\$d_cAkᛙ?K5?\ . MBOHᕭ,DgC!fGO^Bv ?~댭~J`,^$]C h% =pɇZ|E?$STrGskVgdIZV\ZCiX'ie i4ͤhg%)bPpmX %'YN KQrgjV` 5Y*JKbOD/I :2t'zNn4z:Oj``WsY@\LLKg$JR~/KiXz\"ca b'rWJj؁VTvDxNKũMJRvN;i+u.$Tax.G<,0=Kj$%[c)-ǥ2# `sI <)JcGW_t ha| )'Wp?G2'2N̕Lt"2\L?;q'MgO>9a Ⱦ_/xQ7]|jr; "9K}Zٰ;Ťv?ݯ|MJN~ '?}iL)z(S.8L M"~ߔUV Z㱲uEr<nIOիq5­?W~>o/?Eoueyd !UZ?4xixnCa\02\`s@CT9aH̹yDnӄӀ)ǟ)5 և̘ƘxߍYfp%ĵzѧ@}|Llfxig">w<c/2,Yu_?9_sp Y< k! ?W~~O!%娲a矿Iɮʡ\WSVܥh՛G)%};u ݄j}n\,*e$@PKA65l]8q(AT_We@a.}=FOiΜ.'|H%;eI4(%jߵKSTNat3AXF8Z,. sIL7"Y(Oހ-C v(oV*In[Xʢ207KʹJ9*2V AٴE*w3YQ GT>,B sIlܔr5/0)S,0# s)0`+f_%7sVN`TN #0$z:SBPS2&ꁛda.TۚL!ˮMZEa./0DS} =S(Ra'JKg檰,NFS\/Ydª5({3S腾I+ dR7Nڂ7WȺӝQn7+H\U͘]QB ;˕+;vϥWvjWꡎlQ}06,s)lfyQˮ0qmC됙f$x6o*(:]-)gW倍vY 4업]aq#הc(vBd"#x"kܕ]96!}$KS}-X LRX2u%Sܔ'6_>Jb9䚬n (os<2hwn/R./ jLj t;F.3f'JKgO ,mE}{ t;V%̥ȞEobdCk E+Y`FSMي2<#z dRd6_Jא.8%TV,{mDw3.IUE;q* V+ghEw*SOw\L"0qR͍r2W@Wf)F,0C s)@bdDl }0屢@F(a.EfM# ^wҢM27;X\<[8ЉM%^9G7?u3ˠI~} anΦTaVR\rcJxٶI[7q˩,. s)ZOq/d,uh2 sd-%ti-ekd0;p\v(AS#c/ ;LzMN #0"iK}mItW)8 TQv$[3hI|e=D#3rg D;̐\<[4 &i㸦JzaS}- dR gBlTaH04"/Rd~k\P6OЕ:cGʌ@EDa. P( .j$ ;ɱVȈ(̥oeKNrNa{klE;̘\<[X5Cԣ3=k؊vAY-]<&>:+*Y/GVx95av7hg]Y*SB] Ε wvSN Kg Ϭ7dwf& Mc*Ydzs)r-9T_V \d3 . )I 8贄\; .EFmWlY3m@ꄪ,.]$"uշ!nxz$EґLKپ~ht d 7BsAMhed5PzRXn2s N(^N C!,)1cI1Sʤ4ǩy(tj\%'#&UΜS?I q#5^g3 .1>6ؐ-'PDvr yEh@8}dTȥ 7L2G{jT V[$[B[³ҳ۟:ȥl؂f 5.# .Iһ`~mx,sr,0XZЫ'Zgr<2~,7>w3 \qt A֏⢎=t=o V\;[5(Hŋ-a8b0RX5NY11=g耱M-`fҸN&u0:hE3 .VVH&!\qc,La.ɝ͛A_uGT428i+=<1q; .If䅒T.¤sqUHKAոKs|SsGpN8v@׸vn\L2Gԛt0U9 \8sIlT04 \vct-u?3JsX3aDM]4uGR,*q%IZ-jV>\ :P;2$O,2$y:1": j"h&ϥjੁ%E@uFXK88d5pITJ9qg;ruf3XJY%Q9e`Q`\;{/\S3 dxs)"H.) N9f/p#Yd:s)0eH/jãԒetLzl'%ɳChۙ\vs; _G,NL$6-c`u낢fN\:8nL)RQ`رAK)h'0")- a8ۜcsE;|KcxZS8 x ; .EV F- ORK34)ic\p©d;6S;?zaM`fϥux  3.SvqhxE+ .ɝk^.BŽ Ҿ1`իLf}j"KW}6ӕ'auR,ENDzqKg3tSThT: @.EV,'X`3XU[,.$wi`-wsK3 `s)0% Xc3tSDOs f\;'d)F5eG, *B^  m0J5F3`.+ άBRsqqE뀩5,0$xf E)r&qh&ϥmEy_07@V\;'쐚 ew<9`Oi=Ц2pR$:#)C /73$lJu Lm(E?"uG}]Q`Fnh~}1UY5@?F-(7!: ƪ^(RPv+XQf[3+uR[V\]D߶K=igWcT{ F~\ GlI`׽]I"KIEBKb[W0 EN K "!A`27?.hgih d1%[ghjj!`dN:s)굢-H4SҒ?{}i@E3 . f놆Z$wpByMȂKAٶi,!q{nst}; .E+䑂:v-RRN V4P )m Z:?LY7 Ts)7O;cfm*\0q,2}$y6h{y}0j0ف[3zf; ,0}$X+SM x~.uӚ働?ZRQz.`xs)Xq]Cw~}NS=Ydzs+*KitM{Na0Jpa&%Kxo (,2\] 3Z!`klJv.U!ztms {2$YHɡM{&=VH tXLs)N-_*ˠwu+bTOa%p%j9NQ⸺w vnX[^UO 2a+n.xc\S8 XsI2#$yuxv]w Kaۊl#w0Wޟйt=%:FhP8LԷx dxs)r]]$gf'qIh:N<%dP/ŃDt),*Z]V$g;S 9w@Ȋf\1숑QN$?zagN%ɐ>q/XҠn{!)qᇝ@?$Nw$_`%{Ac Qj)9$V{LQh&PϥjܥUwM(ST S!2$963GAL,ʽN\D?"S0h\\}^`R<ͽ@'DpSl( Kl6Y/'E15uafRl4LX03a;$+ ~""F_A4iLE; .E3~n,S:f3K.ɝ;&ΔhD9>.&v0RfѐpE L).;)Z \sIDŽSgz~]&jBP)f3 L.FCҶ6s4n)n&pϥs،w?rׅzb_TBmť?yC{c&NFVB3 j\ߥ }M ;p{9R<,d:ǩpfMwܟ$uť?!W\Wofn\ |{堯 Oϑ6{ԸZV>\:VDA_/l,"*of~\G𙣾;yC0㣛&\VP9Bg ~h`E+K.ɝk.b(e\SɟK< ds)2ۧG/ 9'`ȂKB][A]*ߊ*x*}F]#+ `Υj]rU|qv FVtH'hgn)0,2=T -_϶145v±I; \xsIl_*mLlxsBPjd>Tmỷ?,$e/5NvWs5@\I<a'8E˟ M#+\<HPfr< 6woRkv9ÿ S|2t2Z5kW V>\{.p;"EV1;Mt5d+ .]vlP 4R'\,UӺ8sW8g/Ш V\ 9Y;SkCMoh'%ɱ}FtЯԚ}04r?L~.Et5XU`xqĻz5@{?NM/vЯGgmO E#:Ѡ ybԼ_^$l}P6ݯCEo˵kdV:rݣbwŸHý3u[TW|#oI.UхIrlJ;\[SϦ3W4[ WP|s_ac(xxZo&N v.CooԲY?|ib/ +i͕M1S f;zUfg:f;!|c+MuzCKul [d{~xc~wk6:.* Oǒm^_sc[vq 9'W.zA͓^lZY恃OqYu󫜳]l7^Ğ}_6H޳O߾pXo9XDǼ٠Z{l'8Nl w}TcHdozf^h{\?1m9w{2p^Ϝ73f֏o˦ϼ=k̬Z a-a)et?Q1ۺj1{H'§)]t羞i8nk,u|D뱯1okVʜ5s|x\?^xކ cʅ j!OctoDM9f]V2}0>%^{iv_(trT;L]/&O||ޘHukqLh_rvo>|캻31Te6WUhjuY`R@4] -ZZa'K ]: K%0 慺49 r+jX%=8HtNhlrɆ5W>ɭB%@ ĭ;>mythꛝEfM.Iy ]Pg L9_U)f6$wl#+}  97&z wV#n DwkWN's џ2YbO.]H^* ]9ԟ@nڅ?f/6tLeg үwRH" qjm*xrIojw>s..ܔ(Vay-f']\AQWŇ;7;] %eaJ0d6-6T ԡv]Lv75, dDt/\ĩL#MAfABW|Cwj_zVCu뗬iK}7ԧtJ;ը;*is{Z\U@?0- ћJmSiӃjPEQ.aSoƮAKBo^3(ۺśI`kojTj.Eh'iTnW.p̈́v!)ls]ۮ(Ӷ9foqzD+\kK(0JA5/;J3^;e;\\G禡kKxipF1 LjV0g+N5/͌v\ bHhrFْ!̙vƮ( [&i]r ʥ_8l˚m37@.E˛ɾFf_,qKC;.sSI0è3̈́6!0+l0t#OqsܴR4Z鄪TJV[ұ ӖM䭝[0`ʥ7gPu/~herrG?Mv]nuLe;>jŌUW4ò]JGo|oCo8XqXU'*sQ~rf -jT Ng2X\_X<16HF ˥tj/iiz@ Єv}tAˑN㾢I[_0շ8F!/lԤp||t#텀cmW603/wܵMVM1MA:_Z\tw3\4ރS^\l5r6n"A؞iE[Cw2PĬʭCփ, q<8i{ڔhsW7tWf`. }Ь% z^6СvBbcTq0/OCDž=ڵt4ۣ.%uab:8/iFwO8α{]xv6bA4_c;nۮ#>*s)p] 鴭Nܑs:q״; #n7G!Fɪl_;rj2ڄ\MX1ȥ6Bu*v͝9 Fgny3x%V1 :3q*73ˁзAl'K%h8@ƜG,Jp/n%o ~jR=Z烧^hEvVkuh:[hjVY1E +8ӚFq7:lT7~] V]4}21I]̗yZm\ULFzR3с4 Te.jW܇%ɝ + Y*+q;53.E}c׳bx>Xܱ3\ ? pGgT7wjv_4_ 6пuwfܔ57&J4/SV$c HXvh7n 3lKVt.._76=|=3kiF ,穆E;\eW}Ac)ܸ1doU6G;\<9Us2HM"CqFFCπh&K_&)m]pyֵ7%ea' ҹd|d:5-ȏlb.$UAu2N cC:NX7NXy*BSkONm3G%fkTs6s;6fVK,UЎ]yl 3s>26sIL][}N^)O4\x6܌ΥC^ưUf-SwV~l%iˁגTqS.ca'4 w/l//;fNʓ+T} XFRTSu9Rr.)Z~܌%ȉe8=K/?v}P|b/sb43U vBðK6W+!9}QJ)F[ѹuήfNz[[/I"N c8$RžA/fp.\cfMN5xY 7QK,MHSjcZ؁73M؈%Hڋl.Z?v|-̕ZL6|܅%v2JȻK֏d@" +6mMɆME'5vt9`s"܃dJJ˛+KD9&'Rlc{ mt.,_X+fDev}jvkmv\KT=65J]U_Kȱ~FBbzUFhv]ff.nA璍FܮSRMd ㇝@.t.I6(Ai^`vD}6؄%ce`#w IPbhֹ'Ċp#}9,kf}ǒeeFuIbag5йfX7<^eH^ "+}W%~ dlCRddvtwf]**,PIbnfqKrwf#-Z 31Ts7Nb[m;VX07tB:7{73]q%ƵId֣KxunI>,6sI/| ylj.t 4,ΥS-v!k6Ԡ X''iĂ̕3.`-l:X;̎.#\f]3ϛGsQ!QχEVt.,pOF@GoMF;O*;"ϻyj03%TVs9w(DfSқJhs6A$Ӯ{Pۂ$ιjҥa,sILXTϹGA0Ȑj4&ΥRS.bՅqEvέJl;62SS`[6ق(9w>e =Ԭ`% [йdN4g2R=UAj'[V fй$ȸa,IةC[qಪе2_(EJ2ň}aVtV)lXlx$`C}Ntqx4ڃ\I4a5;zF9BU裝Et.Eg] @{[Nn[S@&q.Iu3L 1i5s#RT?VӪxg". hs+RFjwsf@L4Ucn5*i{ dB&1寐 ͨ;;qͽ^L(s)(sCXs\hm5WBqg@3ㅕ Ӫf,(Aoj; *IhfйvQd)F ͸PSRJb:rI?.55I{M1Л2b^5XwYюdU8ݽk;40*C璭:45. < ث?ϩ2\{$,zF+SzO5XU(>t.kjArz Ԇ~R1{U7p'|aToFrݺq;:lXY9нIn>w:x0؍ΥqLi_X'A=}nȅQv^X+>%O|ῦ\1Ӄp}qĴj> LSu _|mڦ@z4\U)SD]ADtq}nƙ}v=&Y,<Нڌ}p9L\ V5+5y/k;uBNI(SDَ:vt6LJ.F% СՆ\'oSj7 dlGf6}YaqD#rҧ,2wsI _veW^ @fg˂uzCbP]wN[rLfBK6˗IIRGdosG С[WEt.I RџT*2pw׭JEJ3<b֕ P_[T܌l%B_0mW@Wj36^դh' ѹd|k$#f\JSnt. .yk,]pl[458Z \\QƦǀ-oWW}fԘ&\*g;NVf껚՘tmjָp߮Z`!͜Mb _K" ='W/B9}Wٶ!L`:_x=~FLXUWf7/?r/,Z5Ƿ%W6:"P6{9)`yՕCbj/L;na~3c i~*{2Ycͥs<&yXrQ@LL5sϯ*e`_67;s~ԼqHf.B&S")tʛN'? n~Q𠅀TFѣ"o:/3Xf,X @(`m~Rsq_Q?*Q Ğ1Ki1PrWoj:(3-ddk^g](%NaT[K |M5{=ub? E8$_ L)j=Tr? f CR5Yu3X_enʻWY׉$xܸ{ްIiF!IOK0=*~ZbB,׻<:t3حD7dqce ̄$B.x O:7ȭ;Y*a9񔹬ʊQ0~*7.~\E.<>xX Oju[oTg ^M ۔j~ O>Qnn>ݚGn-7.Nk,1\.iUyvr?07powp9nЃ#Ww?i'oNf"Q߯#D]{ɛN'ELau|ȳ~{K- +A忕V,F ږbME'\ ]$ZMѽ"o*+G5OZvB*e]((Aɣ~QȥJz~{Mvߪ[ڟ~қqHޒWK|^7 IƢ&o*;~ɥFʟ~Qȥ6=ΑjI!BL\1qp$Q7՝Om7΍pE2܃[$N̝ZwUyvr?E~n΍5Yj7FEǻz~TqH>1-8fN{q"f.+0en`}Y*N_$rETur?oNpv^N_Q$ubt iUnLKshT껪%߸:;X(dY^Oa7 C70]pQ7՝Oa1ywr=䘍곶׍CP=28v›N'm3L/^xyo(cwpL8A|0*cf3NI}!`bTm`yLOiʛ Q}+c~ՉGM_OXo&E>{36 ͨ*ǜ ]UTw?WE"N үFy=u?cg 3}F"xM}'T~`ouyY"St-NO-,2u졵]'I,ҁ.-wp\Fp>@09=uG{a{UTW:M~2Q"'[nd.xMIqbce˛YQ!̠y'.;ɟDnLq'.o;ɟDnz'3;<"T>q@]q9\;8Uw? e ctq_׻b<*;V!d$䦑TagE6Uvb? 8$o<r uyS_?Ji2??i8 #jQ=1M}E!t|!vgqNˡ4b˛N[?)OZ?7Dq.xnr [lsq{MTv8?IFgޒ~Za>@hzTWB 7H7[PZraRZa;$G1,Tv> C0~^mDA{Mv?!dq&/ Q-vgԪG5 v'C`u sɛ ^I 2םnd&ލ19N,&p|`RESAQ7c`OgCMVS[n~޹WCp o S sQNSC>g_kr2ݰض?¢~Lc"Uw(GA*iqjAѝuz~JN9W9 Oo%k"} ,h N~L1!Lsb/~( K_qɭﰟRel?hl[o"a? Qȥ^N^6R5yS XE}ReM8V7ʝ|n&pf1H Ң֎I#Y[=ub?%߾qH 䨥ȳ.+cwYn]<7 T <"o*,$6@HrzN1bq{w#W_.E "Re [qoF\zs)n!_|Yطc$UMe'^\ 07okSUN\~B.q{{.|$7b4YvE}$éKdzcw5yS[qLN- ~.]PhQdzb "#̊ɒ CP3hoj񦢓 ~.ϥC A;L)]MV`:s)”&N,#4hKLBSBM'u?T\9$)HMm'\!?˥G?. ԗW4isEUTs)j+}߀QF{S7u`xsIp++2Ou <f&doUyS 7? qj&0R!rtMpUYEFS/яwx X8s)rh/itX7$0tpKk|pT"ϺN*Q+;PSLsܰMF.\F,7nț`xs)p,92%qj{W7՝dxsy#S>;xz'G?LM?M0<xa=1Nr 0o򬭸-Z~\7;ٹ94dbN't$ëK17nX&oj+.$7R~E33`bk ys.|4 =0)ꔧt ]5Tubϥȁ,覺$w`.?hF~.]R+D;>8#ݛ<:pRTQD=ǍjqN=[ڍg5ѩKSMˆN9Mm'>\+~޹~<,,=c{a~ޱm7z7bAhDZ0T(uaBۻj£KYɵȩ.;L~.븓|?T]xa6*׻\8$ȜOyxqT OuySI?>>Ϳo/Wگ_߻Lu~;d/۵W˹j|s0=ZU,**9k`Wf/,Zo mwR4׫Oz*O3ZMuy߸Y|˽Ⱥyo_?|qvL7_ӷy?o_׈Ow+ӿoU\cG=/۹n0BU^vw>V۵o?wK`nԋ$|t?Y^b\/{ Jޢoaֻ1ּxz}s۽\}en n$nnW}~?>0EÏ9ݷT ulg F|=͚ [Ɠ1>~}Nᣥ/ط}~nF{ꅩ5r;V=o~ze#m?N5tu7V#|M' /^](.P" ^tadçዶ{^ͥOf]-xlliy̞x8KK=eSpّ,~~]B>nEnrq =IEF~s>1hzU-{k>nFd|ȉU?.;pz϶WG;a߻^/I֧9;ĽƲ+:y:k95|*g5sΠe{ /f'GϘ?ƧhxzEGoЖ:Lk>|BOcO7u z| LMOtܦ#Cz%p c?N~|a|6m8z2~nXjMƩf9f^;}yh[fcl^9g_]jC+;|먻:?Qbcn1ۼi>Y~YY7~;ݚsZ+n]+qzQ72 w-r _In/Wt&@q!@M6~{&3}mS^i@GFLJhg}s;;Ծ(2L7E|2HBf?"s% i_I`HHgG|4x!@M6P%YВR# YsމϺ—.li&S,k5UZ#.@q!A+ ld9 /OI|%AGՄCPIP.B'r&$4_ d ".$}%A lDX`B`+l<"؎l((![hGک j_I`й;aى9#3Ǟ.sAD6D;d̙H[1L4A‚+ m<G2% L^ L\H[Iy5ZmJh^lܝ *| ą,K zisǃADeS^k~5 q! d Z ?ABW4xys-k~#r_+J@&8myv5u-.$}%! "EAdZ/ kŏ"/N+a?qiznQtS* ճ{:~}cs?m;s_w+ƾ.ԆW-#69^3_sԶjuN| sl[ŎEך+G?܁kG۱Ah2=ׯ $up[? I.̽nLK?V TԜ:fs})k}؛G RgqdimɼYӍxzvj~1BwwSd֏Θjs: ooc>ڹr dBx񨻤R>sε?f:^[a mcL(d,k=XSnu5/.Jnv^fwruNu2_Sa>FϻFhʂvZ:opK*?Ej{|b˧c M L_OAǪ8b?lh-?|h}O/YziLJ#ozxr(oxH|4#.zvQvS=9f19]mx=/뱕gGz0-kUeܴ}#eB3e4W;E%Yc}f>>~ъ;ќp"j1G_K/5L~l> EG,Ȣ=-u-#c?}2ѧ@ÿ0|7ĢWQ,"cq!ǩKp*ې='8Pźν٘?w`W R*+m' oxÒ:;W0o]6b\P)VIU1ۤ!~qYY~S?|zPzWvs]-}'AWHӺ.on?y`Ni^U2q5.ۯ w ?)Ӣ?>ޘ z?sag;â\ 3>L7j l (ݵrt >DQfx0Bu=!< a-yͨ?wǮ=fd83>_;[W+.C}YcnaX14-,untxnqHlbN,w awX:Xx;zu_1bdKbK֫WsՕ<g]}_QXXG?5X)ϑg(Gx=XS@Oi e<#5 ֧ǤZ*X&ya-ɽCdxuո~>ưI{~&#c翳nv{c}{u׮}VKغ'֮^mM^ ~Y1~mL>Y.cP E t>/Z\C?>Y. 6A7[Sb*"yYrufnܴʥdt[.֔xg Z{w"'\jc}HlPNC/ݨl(rr)(ߚ"ӨBmVD8Z&9$RBfXBcr> 'L &{*$SG}@OH;+b\ |Aw.$h$7Lݺ휷ӎOZ V2Y.|vqBL$v؋l{UlcrIaG)kzn޷j\vTݑ;XP&>˥"v⮼m~DD`z},#חF_|$^Q4]!_wKAwK-+W-MCBo+߯Z`cAy$1CZ.j5vڂ5ly40"k V sM7\stX1\*ڷx\E^޵祩bNh;k[\2un95lkt?FZFTE4+bVs217_9uF'新 8VɅ=ɽo]#(X䱮\ :cSÿqr}{@:Š<5W \*Lݎ}\0uL4[d];W~=nh0pqHhb6-9g~i\yNvk }-t38Yl :.l48LvVvMO |ЪC$$ $U{Y@FXDrq_G8. uVWmZ`g|6t6?\8f"-CNEL-bYu4{41xvL H̅"fc7a>~UJ#qq}gKa:&I欑MFiGZ;[@Oc5ׅiOusH|L7u[K >BƋsZ][d)$kL$zk=[`"-NIr,n,+\N"-ixԕ=WոLI@m|RE;[B-jH0Kaj*#Fq6JP-;V Xc/֑:#--V=cY_[+~8P*(Ngb= ,{wDp\%Pۓvڟ=>qth~fK,'!$S128G{41 >"-SP!f ,)C#6gqqygK䍋H LeA4೏wk%hBHuVHipq/Xou?8@j𦦪?A;[ALǂvIEo$=4AqzhR; ݁)gyx# o}8t -+)?f*Df6bpi!l nx]vBKY5l0&fG/<'x8lznsߜ@$ v%utllVx>''ci(P]DDw0Y q?0h]:t\ Hg .O@+p<}(B*@ٲ~sƬ'qZQj1l :4aT.NVL΢@Ζq[EڦضL87yY 1,8@;P zgKhס)XvJQiވna+Րxo^̀r(R x(x8[%q\}d{wP7Mx]w,YR,vsmNjK@ΖP; V@kǘ[P 0EGwv ihǁ~?\,ѱ9Oݑ{g 11%!R26mXHxL {g ,⧾v܃'?;r+>l  R!acZv"o"bqjlP06gΰz=RZwOjl ]7Jbc݅}ȜhEA"@-+ œƜrF;NgQpΖ̭R6InaUۣ(8LDs vP/$ fxV4N#@mLq١sm'ޛiLUiB >b:5b7$Z;U.Π0L-m.eg:~i܉Њz%|%ԤD1 K <,s8He+;W&wcWK;e O:}gKsdQpTswv2B?--kT/.VkSB bH>l-VbT-988ڭC7E`Z;[2L@?xzt]Ц\XFx@V;)/>+ұm %B<["KkC aigCSMg fcuQ_"J19Ʌ Ń%٥" PqgK2iSpEZk yBJ\|XxjpjrQrT A4I W烲 ‘-[i`=!l& $BW &{s踶3H-_4IZEO+ER> lFU%e*CG~3Oφx.zYG BDR U(?Ful%P gK^֎N ӊ ك .lH|z 0ThMݩ\%s pz2u, sű-Vl/ .1l95"me"7Zp=OQl hY E`Z`(k,lA pArjj\ #--C5ç-th19N“ä.M`JEQ.H2sv?- 98o$Ka7O:ҧmȎ1Kj$ ZQhg1=ѵx溜4ݔ`:*dSvu>#fȰ: "!,cRF8[T<3CdnΟ@)a,ZeiC@ej1*3jtIL~!{ N L_SْäG`JE3hJTط8V"0!,-|RG8Ա6 )zx8klD D[8yTӲ!Bth%8ݤEdnc >+RvHpd(#>OJhڧS:JŘ!i@ ѼE:38L(Ofd'as_,&=zKġcmC:zO9x<dTbBuH*b௷ץZ6ʑ raL3bH̩R c/L,kOպʎS|'emZ^PEޓ5I$i nLUj;V),]TN-'y%l yrR8>+GKh*dh Ͱ_i\& G DW9m$"5gɼMY)#@Q>YB^ZW$&\8Bma@xq,g,5ժjrX*w W\&*'Kґ\ 9Y$+BRjqJgqqˍ/hQ &A#)$[8B |pPC1-8_LIPTZEEsZE69P븎 &q<}(:kUyH+9wʛMb`-[5+',#{87QlA ' hϛRth!M:}m\^"- "53`'t6%%YV38>*t{EU *ޜD:9 wBrqzgK)_5#l},̭[Ptt5#@--Z2k5:JF*MR% 9TjOwڻ8dRKi#eGubÙ|gK䰂s+'J;VfyrGH-kǍL x0L%(&q<]&ْig岵U+pSH zg d ףp>qhE$iA4$n^HF*"wNir _'hql:;@a|L!C&c?3a<&gDB0mEH,= -CVR"0l0,R=jf) >Ԣ: kSY^W@E4`9.b9u` $SP&M{L8>Al JT"0,۔v!hA"L zgK%/f9% tlx WTӶ -jfI]a@EyM'Cqih(RĵBB!BpFI]!"#--) TD5y/PbA"-:eOa<[fjQl  + Vyrt[wq{g ( NzǢiZoiBMWoάb0ĭɂt`'Zz2O͕-]^h_N*̋H޹rYE;[@ 4ae|ZGpl :,qH0+: :qzwJ>"=OK .Bْm,gbNBA^:ݢZDqXC" r=;H4C'Pq7l18$s ThΔF >)E`Z;[2|R$B_R:tozqjkh@`f: ud!uۚ]ż%ibJH;i& ΟL ļ $SP7zqygK&۞[#1hL<728>b*0,nĜz"_)Ե&i]nmˤay/<h%m<}8b Jh`NBȩ:JbK/AP0=w((-fu@BFp1ΖD:'ևgBh:Ll<]^"-D`%{k1.ZuH7ھ9qwܜD}95 2 SǶc-\&bق T 4_X PRM_5(CGZ;[@pՠJ!/z:]$ ", | b`wF0aSPKY]u eG%VUqTU}1.OP{,q@P2o_N¢3i$gJW%ϋO_XPͯ=knF?}^"-d4NsJBmOC紐w1;iRk_[D%"߭T+N1 "#ȋlf~6A-;n0J+,}E% N(~9 yI*0L" s h̭˼IX&j?k%pЊ`N2N0+'U}}_Ig_.q,$`9[4 xcVt`%gA;ɒ V 9t`1T^La~3NP26 :Ek܎eZ8u0 P9$r ,n۞ar҂$@ xgK&ωD_XP"Զ'yH.~ye &H"0>0_:t Al44f1m e[14F溜w`9$skyӖgyHwV`a|E%geW[D`iRcok+6gQqzg (, ̩W(L/fy0o>*E`Z;[0b`J s2CR(8P%iM EȲ2Cnp@_r|f);فl/%Q ۪SPD\+Al%cpHHT+,~ S&ޓ}E%t!B”_c;It\R=sh.bᭃQaqD;[0%܃r`9ul#CE`Z;[2IjrIsN254Ц'xL.m|V%W4LC%B|g@.Wfwȡ(?G Z;[BJ; <:LA|RwZЛmv ցeRɎ'c=k1l[ ZU'( ~+,`溜GSb=(F(LKe@e[rUu_͎/1 D款)xjkS `DyP8C~7⡴t}+gѓOjI׏DžqyÏv=={"g^_ڑ0v)-E-ֿ~o旟 8҉!-!cƒ:U`ɉe67 ̇}C{Ni9EfweX1| y[mp*eꜪ?6B~||Kui|YXp=e>ݯsb";_4t:>mKm翰N٭˂c.Ѡ;~?~?E`Bo n۟6 }z|:  m=biے IVct%M%SP7ubGk^B ɡ"ݶe5mzX!׏kMS"*a?ϊ'xJCܷ䁞mֆU\obp9^6ذޡ|jf[||nxeB>o#f_g~k잦hυ%e'檔-e ڡ}kw=>4 y,׹p-tGdri%ƛWV_?#7^xJh 2˲ry)<UZPZu8DbYdڌi.2{4 _'9.R˲rTkf({3eV-SQlQ5cbW1*˖ݩnL՚IR[ofonTX-K، RIl5C1' ?}(2˲R}Sm&|rieْY'/?(/JOAeg!,["ѫFq^DjSy8D^Y eFt+&bu:1!tʲ%qvDj,GMe ($*p5_7/y 0jejP6c^%t}h@,%dC;Y/캬 p3s3W-֣E5XG8jwΞ mo3[U(:Gߢvua+[BG 6&NJ!<̚>ʲp4jJ{͐Fi#@-,[BEi_@MVG=g:x8J*HtJǪy. DS+tYeْ9\,̦7 Jժ9T~NpqH*˖̵2d|j{! uK.t΃]BHDagXGђ@le4RָW8^0W-唍8ʣ~zt"0-,[2ѭo1ơح{ jwZdlelʺ|޹JAGv. !ti ڦ!ܝ: #ɺw=dh\ق> }(k(q,˖PSBy,k]P-V:P9jv~5/uq-˖PtzL*SYƓ*^ !EQ̲l; Bȥc!.P\e j0y ( EiyWx8Pe (\C ^ t}V.X\-(.&:/~dfEqĭU;BX *,48.ϒ˲}ijUol^$D[ZrYJ 鈹B*.CPq0PvrT9;=*$<]eeKKj#8z>8u7J:2PYm >4ΖPL);B?--j`aIFc]8HDRUn-hLU;:jS_稷0sOjl ~˕TÜ&ЛB=d'.ldu$G]OÙC`Q|DNuq؀V⺹:.B-"O6;rUD cS>8Lľ%vJmL|) ^7:wd]QqGOx_G\T 6?|z>\*L gKT::819sݑ5<9w@WUQI*|2m*s8D;["S3H}Po _dGHEy?y>}~ԺU9TZnBh2]e_EΖѾO#.b`H;ΜE;[ѩCYaɱg.?$"ْ=Ș*E,eE0wŲuo} mƴY8S,yg (52&m}Fcdj1l ZdP(/ 1Ityϝgg!-$bSj\G.]qw[.10fm}^Kv<w2餭! ؁-;E]wy>CY;[ ٟ0mU$z1F|AE;[B[`Δra YEPw@[DBG[߁r ۷r㩷,ْ8]@ }nj-;}!1zx<"jGjJNg/dŇN>Ql@1h{/Vκ]V_d2*GcgbC"rgKdD"0}O%6^@h3bقN5J 3{1.V)dpzi!lD\INV>:~ߎD$6[29{q,s>O;ʂw_;fm}FeV=8H*7UYF[>-1S)L`w8!H8Wb՛Ʉ맏@(w.O!2$>֨P9l$_Bǁ"̝-% FEcPΖ4"0W3YّʎD;[ ѭ =1Ϩ\zFkí76N"0-ʝ-[`Θg$qǓ̧㕳( C-Ν-*giDU9O4*>rz덳(8PD%suH՟;2$NWjjl ݛ3 y %w}, >lUź#ii76ho;zD >~f (;\mT.U#uW .ӂْ<Z(iPJ.lɴökQG: ^s?a=>b~M9V0&uA4$(B5;'d#-蝭BO&n;g\Y&Т7P.L-s\1H[K?lzg ]<Ș*G a QjMǟ>Ԃ<ݢJb=zwSPv PcQX}:[pq}gKd"0W6 A żw SsH5<\2xerqlNi ϸt #ۓS(#M<ԇOS[߃G9..UN:#L[U~a"-VW861|jl 'sČBރAל죋D;[ -'2ĭu .SW* ˕S)?w<\ْ=ȐˊH v "A"-)&|#) oWO=V%tz>IqiWQzg $nΞmbH8@UgK򂣨'(`xn qˊB7--hD/$ YE紐M%ԺEhz‘@ B Ԃ 4tP* G/0uCx m yD͘n$<:ܧuIHrŽ]ڮX*-o }gg -W@m$9\:Jϑ!qlRGF?JIV&~ tGfYΖl"0tҍP+M 0iB[ЧB<{8ڻ|gKd" ̕;G/<Ӈ"--UoEԂZ-oN"-yQqFeW.ZM=tl ]DiF]+J7^;GZ;[@ٱNJ8wo1] @Ζ4"0^0 }ȃ< E;[U8:l{_Q.n;A"-˓;d> n/Ρ,4U?ԢlqiqV޻tΖLteLUlӌXVz/r@PRrE% D;["pho\R)'n/W<alD Bˍ} _- E --%{2 ϝeCw$nO!2ovLm^y pwdVO$2e/ Hͥ`ª g~"؝-֫Ez͐g$=] ֘&M"bi3H4%2w(^["98}D;[4pJY#Aaຒ~?]N"Ν-Ԧ^hJ$Rt:Þ~WΟ@-L 1iF(:ROmPK#ט_T\ki~ϟwMϙp'HxG4x^GXlH 2XJQ#S򠛚;ZΖDr:LګߨRPvlW2z1D6z׏ZkqpgKhcyF.;PDr"=+>]^"-W`R:T׼ߨ2gy0.&2bw >тN ;Y 5էE;[@1)G/<|L=_=.bivQ$LYƔ#aBk *z|(<Ƞu#;N t!ekhxzz")77Myt"+[2'bʑ0pHOPw_b~y^ Y?ʪ﹤|%DeZRx1`ws ZWgv_-_ilɜMj!Hߟ+ilܞTdLYHXϘ;q|& h"бcQagGZ;[@1 &EJ+L]wQ@m 3(!s»?EZ;[2S6'S ]6P&׻3w`nYSQH.<G14"-&19"L>K|@xw@[(6aғpmfbrq_Jwfh51ɨGW{!lS IFM߀AtQ:P ygK,"@wyFM_Gewc/All&:O,pDΖID@dd%AZ㓇w@SuSIFMSeZa:wK>"-D`UA9a.E03" -杭"ew3yc&iP18PD%KIFRS1 DjQRv$ߦ O~D {gKhg #%NHmTfyߔ<.Ald(jJML3j*c7 -3Ȗ>mxΧw{ߜ@&=Ƞw򌚾@j#(P|g h5%](1\6C--MFRP:>lq=;w@[rL $6j%"K1ۨtݶ Fp:w /2 e'רކg|n/Πt?o%ݪA"[GfB_=j沏wc3H%fS G=t}P78PĿ%t0̙ [9㖌<w W(5g2!H B פVh -r yQ]ɀAȲ׺'}>?]QE;[0ESiD٫hdJf#Q#@WvO?#)ZGnDábʎ|ɁuO|v; #-S˓l5: |^Z;[6fPPcOQWYaN[{m?}wbw:~ˬ+1Ȅ^ןݵU}ΖD@pnNyIZ|qql 2h=&uUo%BǑy0$NfRQǼ5O<Ə",-Lo$r%^9j>WKļ%ަ#ID!ۨƶ\岋KޅDl%%xG>a"-"̝G^~:ȫMs\]W5} '1+w岇s+ΖޘGHFCty;]8#ق^ ʩbePCC% owYY y%ڼvy ږO ZCkQ:An=*եкjOQ JZvkHC._~Y2RQʕ[H_u7jyd[?vZԽ_dZrZ/Tÿ4]_4\HY;mՄIo}o?9fRqq?~p%,Z Qg{c7]$e.I[PW-Kwpv="8)Z;-YVɽ[ն`_f`rVGKJ[W>-Ō[!pKeNRFL}9f D ixk}$JJy^o. 51>Q6hqˍy[{RT ݺ:MX<ʜߟW\3rǭ.}׬pma{g\7$_;CQލUd沩!J6jK$ZM5Gˮpik G,{7>F'ǵpeT]GebA' W=W?%mnBm]rqdzfi 쌤^;۵"E(h>$Bі=ֻ>v$8T_/kooolV^$[^LM3\ݏ9\ΩzA7L~U>4nM}/}{jm `gG) (w%_ks81ŇXau 9J_ o):RXKn}ɯrEf&|SITo8as7NR'NNT\Tx>'fٟ9 >Ń1F_R}7%hT/ &^$h닦k )/1kـ!U%ߢjxܔɈe=l?||_ _ OK/rLdTɯ,(D%G(<%68`P_p Qr> J.֫z_9-I_M+B'KHKɇBWR)jatfh bYaWUWF´$0?˪k?eXփ0< :Ezݙ(.StdpA+%蕱 N+{|G; /`Ք ee[(||Tm[ 9DiQg~٣8{٘d/΋WhuhL%rnu (1t뵡=/FxkRr ӵĆsrq:Y ^hozaU'tМKJ)r^ X&{ywUv߼;VIXMbwqk:q[91hiV/"0?K} E^?nU7m\=mIV(=kdk=:%R z†Qo;a9t\g[h$.HoB_Q+7MV7Mtmh.oi!rnE_d1!Zrcv/Bvο=][lYt1!,U.7fF+XA 5e3B[O7Γ-zcQE|OyzjlLzDu[4dE#]By(9ϲ *}lezGdK2f*(b:]=};Vuov !<^FRyPq6EWd9!DZU,m|-$ eKоכݔ@/vsҺhh+y\ e k=!~zcv+kݏd}D˾_]1gWS9Zke.rvzbG٢'D,>tdW8鸺tYuqHCiOur;zwl]O2GZ"R8|+NB%MX!ܵe +ˊ) *$W(bg >Ng-:# aLvFV@- %#o5q`@Մk륜PEg݆>ѧSr/lXu%!,S5fáEdVӇmS[ѱ(o ܲ,U?dѣ3tȜ!²j/pIDoO9km^V"0-s*[08$.bm&ոrTpҦ% M=f҄*'=\& SYjL 8p (k6Z\{qѠ+Uq/vYgƓUԬ4q{5G@JBU]kΔ?ztgEJV.fGe!BJֻ6@>֜|pFcaXSNrT&^0ŧl"8SRqf.JЄ{"XÙʖĥ9^ OdK`ei^)֨U7@ϩ+{|rz >ń8BTߩÇ$JˆDgK$ :;# n :(Yz(g ,[@e)!8eP]ZYI{G=#6iحP]3NH}XfF0x8#l3M@ЯbcJ܄xԴm@/8hh~ΊT|dG宧@4l zXv:cKCQ婾_iJ\CPi&mז+@}Qt]8]9.BO,-[DVr.YjxޒIͳA"-[ e%!;DV5^Ò45Pr`Oioْ)?$Ȝ:eq4L=%5]2ȢB.\t$مE\W؝t T9e1 O‰~tΙ.͖L \$dL*6 cOiق)+A sVv6r~Cx!žHpJc>[@(8}fi,!X6]dTe.L+"0m4[0e!ʗ,3fa=od.z,*||GڎfNQYi̢ڇƸ-EJ-Л3ϗ,.'YuKΖlU;-ݑ|kyKKaF`9L,V@]jDq[Y@-i[ ˕mrchUE!uf* n,tϢ}Ñ =e=uƼy0Gbф .َidnr;\:zEE B:&l0zc G1ߏ]f3ؐL +gՋ} .B_l4[žjC.\Q>:7Ft@g-d`uܸG{0mEQK1s^.!.rTvGڽ0i6 !ylfȲE]5RxTQ)#mf +mYyN}vj3J=}(M%T7) A^.#{ԅ4jCK¤xAPb>*]%H$O3zlYVLsjF2LR1xbB"98Plf ( m$RR%$1 "0-V22[~U\5 ]L}S'.},Axb#t6MEgdQ!1-:Ø읾QfT{8Pf *ӢIubMS]p^(̖H˗oU\8RuF?;]8U@YYكGumiGg,t z" i1OY:rh,8RJFdJS d)ϯ`;;|(6KqVSV 0J^|bA,>KdxC8ݜ|GmfĥRX.3Gҡ7ǁb4[@fGe!a"b#&" m4[ |e1 n r2pgRjz Jw}PW.vbg0V{t"Er} .:ʣ*ZYab4[2vXU.aJòJ_A蔎\mkf ,'1Vy,3(%ңK>-]4ȗ*&9Ģƹٛ~5D# ѥ p!t"+2 dhE*i_. %j{ FeOkyH8%I76ldeGizGݑ|L]0e=&q MEoda#[ONSreʨPM#@m4[Bv\|;rLSrĨ*q_ YKHgxd!mؙf+Q&y|t%!n[=O;meE/Yv|l o~Ǧi芬&1Dru -dVHjeސ Jlfl%1o1[+3Vn+ T%(C\K.%[o!fUKCW|Z|r8E0ŧE\*rc3@Gi 5 9U!9 džQ~AZᲨ7ǫZLQbw;p٢/e!G eEkj>\mf di~!@_kc4[ؔƐO>V$ejrs "o]q 7ê%bOB_>ȂEܻhqaj_.|w*eB%)>Ži&l+T0rCN'_-Zg!hH.uRcMH:?oް"0Y+UW7Մ8ve ^-3~0e *4] ==viDn<@y~^ėkQ"{,w=if JHd'Uw1nA@͔*RŗWn:*aU꽻 (nOa4[tgY]Z;t(v{Ma4[eM#F%ay]F }^bW3[51G}Y1]MobC:sr A&iPbeM!e6oTTpC Zr,_^i芊w0bAŸ]Q=S9br^q:イ*.' 9鵪BCOZaK#@mS3[@{'.%\bJ>ZP,S.~K$ w 16)jIuQsðM-V Ȯ_\OE]*jq*at`u4nul]%uq^ĥryu[JMExT9V%2$B\kb{٢7*ߵV6f2\n,USht"0--/'dO-@VX0ˤ vpFPE%L+C5]4Gdijtͅwa4[tרW]f:ƜjE`ڎi`.+j4o*KbӢ x1D‚|re-۫B5nċ&m|OEJVIB2E}s4ٗj_TĠTBf o-U:e>WE}$|\$vMf?Qԑ]d\҈~61Mʢ.`:Mu#tGCѠ/nb`_TM">vNT 2h+^P¬ROl܅%ZUE_dR`jxO̱,,z%iHsD})~lћ~y](@t溣PQN0u-,1e!\PU\:T]2z|Q( eDYur'9Wтw|6pШ|7i+E芭lEoͲ;T &Hǁb4[@iu/uQVBmLx]7>9%t6[q͎ަ])p(~<,-`/W:ۦ$ OE_d]LN@ȶPth)-%!#@m5[2CTVRۈhaÃhHYW8F_G>Y32Ū Bɍf"a:I 6PEwVg5Jn-& #@m5[Bfy(@W (},l" aP\;. nV $4%v\/ZJX< lI B?l4[tE(UaJJûyhDqpq3͖LCܮ)_,gda=#rL҈Ǝj{*Kԃ2 PiJ(7I!ܵuy']Vh2jTԭ8i,PʠވR@*ܓlբVJ-TkVIqn,Ml2fZ9٢nT4rth$:>M /Zr>cYmHԫE1uU >a4[}"3kRԅO.ӶM6|) xI)QeRSу~te *?cQƓbI1ݞ&n"MР"`pq}lїblmc":u/ >_ZBSRu.=\Quu" m4["dM(09CF4 ɪ̳+XHOTq}u&8iNP`ZI9U#of]fKmlP r~^: ypqX;JdOYJ-lKKN 60 m]/(S]Z&$:Ո2f":VU$Ƀ?k;ق(k TroQWw8p4 efzwiTV,w I#ܰfx5Q˅]u.!!җ\mlYP8=Vn*=7N#:;\&MW/dLYrHeg[fɒjr-D`;Y smIXZC fpnڰ<}3Ǵ7o:3zUэ;PTo <4]$M)璪H@1DO/Ғrj: Okw A{=sO=/ȠFU/ՈIˢ?tsA @򗈤[+X@3 ?̿7/XZXvJT"e8 ه?N2Pzf( }9xo3?CL }b~TuKCģ,8@iCnk2|tKZ]|ͺ&'ѵ;ۅ?Je5&r -[= GD6c#x} @-zv8F7̏sd~HCj)t qQM#ZIGՎ![B#xoCLj%Ffz묇@8Exo'62à}o-}{Ji=ZN~RǠkFf:tϋ>ոxoC?iadUk6m|ӈf:bE@W0q0X@^-Dܣot'0Y)l{3 ^W"Ѳh1OW:V$䦢x~ҕ @* >ZNB??dA9l(P@c;I!|` Ky@O_Fy;}|gN޼LkD`f:NC@ ~0[Q!#ƃ,4⽙$sn~Ux@ъt'1 3I]8ЏcWOh9gٷ<}k{3| 1"z W8}7bȼz?xoOh簼XaцVQ !2N`Zg#ZO"!kk@FyQ";IŗS0шf:@fT ¸Cg+O[B?V @) 'GcM#ޛORqڏFȏp׿,FSb nt觲eW$cvDOE3:C}*iplǣ$"fMO3#CCc;}ftXopsMzGd/9{`F<\䧒<{}ӈf:SIor xo'kCBKY xO3a4}Tz⽝~>vUXPW ZŝCs> #CT7JM#ޛImdlfݙxOS :IY<0^cLҪ!/QByὑ (W=2p \Iccj^GfXzfPEOG+O3ofh)|P+c_ h_@?U5 @wxo3?5ODkۆ >l%3z SEԩDo+VXq;@ n*=*=hGjeЄ,클64>Źkc^e:6vf)6,{nߴ⽝T:0t e+8ЏE3#AGVӡV%>huw>k?֚>fBr\YXc:S[N-Ft+\@gVz\K~&d{# tFS ^!JwiԷF7ӡJAX֞}NJ͙h?h{;dsfZc%}6⽙d~,1GK UN~ECy6Fr&eT>|ۄFG~,~ ]{bK&g߼q[m9i{HaWAq@T83 tl9, 3Ve3VktjqCL^8 S-ԫܼ}-V[ҸxUڏ3HH&6j`HP]fDh$^#~?]MLJщׇ)2d=lŁv0o3E:7]Oy3à&%*Һ7xo&wg Ai>pњn6bKh2mDGf_\xqef3#ΖCҔLM&7ҙΖ̃HUꃹ{#[I&~bB)0=sZ;[@PӢLWtE%0ՅwHthCnO"`"_"-Ν-$hr޻uMMt,xDΨ5zo-ĝkE% :S܊mxo%pgKAiu]j{+il?U`PT>uoMF|;[@ОeM#ޛLpg7A~=| oĸ%e;E!V~߄ówU2e>Lل6:قy_#I(f(I s˅wg߆J[%##}D Bxx('{e}ׂƒ T}~Ӏs#Ζ'}f x2VƖPs^߄FVM@p9<)گvy4w&!9DngK!JRn^|ӆV:Ԣ>HtthW:l7قI33t}hil<0M˹TGC#[I&b>>8s`"2P -_HwcPogKaܕѷ}!ҟķ>8@ og uڷ5@'Zp {L>5fI7щΖhpsl庤5Bh;[0̡3_.p3~o{+il4D`֝Rt>3C#>Ԃfh&U=Ζ։9lų ?ilR'!`6$vxz {D D\p^I?\O݋D'Zp;[BeU]t40:ByMt%05#$5腱i{3D;\wfqQBWfXB;[2˜e?MR>3O[I-0p?MR^^6ཌྷN8w, l = @[o;[Ĺ%o呥\ц w(ށ~wuj^:w&_b{҃$z?_tRK~韮]s^?]Ck?Ï?[ E(37Aܗ:뿿mH)-Q}w^6.z?6 [35qEqW&.PڐOm<ԏm>|{_/y=?_wu`l<7/)ѸޙrٝtmmO}ݗ9+wjNz҄WïvxHjy?qF>6I4fBd|9|Q5)f2U'֞MD˟/`/G]R$^ire˛V^l>(.RwJvEeem>o93W'沿o[JD[kE?J{9jZ^F-![JגRʔ˕הoQZHCȉZ߲XԌ +\hz~W$p\JaPYViu̔NS6I~re&4~FR%w)P~?$8c"թ% ~V{3U^+NUju㡏K(?OU$Wf[#YŸvetEMS ͯ;uѬO9UxN5Sr C+ҴkyǤ.*T}dc+>vzeۇI8oSVL' 4Dgy(yK!}"׮8_iawwO/0xڪ5_φ 5غ?ok}+/k]P{VͶtT:6M;C$oW(G/?5t[_銾9UI/_?8}L4|pQ=Xl*n_z24xK>~i4kח?o?3ۥS;tf }fT˓w?w }>^;+Sei^M9QSDx#a鿐rV2>WҵPZa߿~X+Jl%<qllUxEQǧd1@m+L2&";!{ن\7TGI؆#=UX6OeKw]MQ^=xkz}&S% tN]dq>~$(:a'3_2|ʿnqGJV0ǦZClXvb]AurA 6 N! ]]®ҵL_>8a){Z;+ 1&E TV:_+s"'1eh_;ݺv۾e{"la \*U~{|'z{nQۑCJCZĞquCߝg#k+mtiHS 0vkO7sY\o._i{u]on;~:W8̨ŸFՒf2iUxyA=I_],n%ZR&vg 87KR)k{lwùb3}rɉٷ}OgwtﯜeF7kٮԥEw_W~ b a_uNǷ͕i>*t'h2~u[RFGW~EΖ[jy~}P=+h{`+s?~]^SjHJMJW;*U5_@=ߧV[﷾t&n?NN^L թ\MNm'. XFZ|۳ۮedB5xmyhWԺo(^ iΛk MB<-eUo d?.&^A_x7e oDNMSׅhQ\fdHiTK(^\[?TG)lmn&55V4 ?`d|[%4'Wڪbqu[;QSkwZE=SAsP-EE |ٓY뭕y&&,ptj'] ]ėb/~EJ/9߿l*ǧ$)?-em{ڀkAЪ2#.: :>H]E[o HWg :[붪|RbY.0%T?}6o<;oy~8>9՞?C)nw ov ĸ*E 5c8w+%x3h}'_>LY|Wo;ӍfNH{wYޱ=WrKŞxžTF~oV鿧z]BЉzc9bMj+]r/Jxx9vWnnK*q*ʕj5_7_Wƶ o`fK28 򭒭~ȋ= ïbl'm3[3^bhGmKb1[rLrŎƼ(IeV^MÆZU7me` Xq[U,=+}Aj}ȶ-b+26(k ya:8CƖZ ;g.kfhvYyƯ'K[*Ssle sPΤU\aL^pW8z9\lidK.)&!WU|aJm 6*d8tY _:nf7rceQ!SUY g 7/2i%uCP}cS*?l'%+ =*+~]KϯH[~yق 1gVߏsQ/xif 1 `K`bjgt'"K^JnR|%f:PTpl9MÛۊᙇFg;fpz\)a| |ll &fyNroήS+cP+9de 29pvoPʫ)qz?n '-*[i|DRW\kYk5'b- ^{en)k^8><~NTiY~rH7\l>N\ܜ\{HД-!'D?lIْLN۾9@ْmzRW

  • FT|Ml~0כ6b6r81-yꁼ}0M8c[9hآVbs?O [?[ڋ\8H/tsF7kl+'P\mgZвq~?,n0"/7mĩAFnЛ-86&2"ْ c`CHx]Nq6*a4Ά*Rƹ%vùi4d@6-"-W -'kWntrϖ܅^0z`Wa,el+!#-7 _Q@L2$5dދJOO [?[Q%ioR3K[jo.j$PG'j!l Eᕅ*b}j|Nlpsg˃8]>MF ^Y;'[C58@$[Sj('ҨVlmN6&oSnlm7z̲cmi|@ 4m|4z-+0 E,Ϧ,Npϖ\k Ӿ,>M ip|&ʒɵ/oH܊n"趝Y,gGiOZٌ'xNm_Wt-fz_=k=/Ϋ'` /KoNȗ)py[`snlISxōԾM/kl0Po9y]YXIK~uφL>HM[?[Yk<Ϻo ל+9duGKI,;Xo kBSLu6 \ g &ۆz $;U<&4?ZCF?[Z% :Gޒd)̮ mC?hXBYDn[Ԛ xN84pһ7+^`P fYIz0^zdsbE7ll vD]Y<95);d+!0i󌣥$ոg[:gVȺX R dG<u?2(E?k߄ْ@Ӗr8M@kH>..BRkv&GK:6@VQ{O_;j% u>@vϖact-.8!8Rv&Uq.Ȯ)GõG4jKE1킢ذd-W9qH-N$-0*_ +c/N'a [Q+vedР}[E!V/PP8a [rQ|VF*Wt- VurfۆvKmHG) `Ȗ`/FŁn"Bl=c [5X$ " 밃&? -OSȶ -P05/We*66r琱 EE1 L`j/MD0xW%z% La]&bAdKFnU3 @vITjz܃WpϋsåVjH( ?F:YZeԋQժq~PJ\ݏ6Kp |Y`B!S*Y5R$,|u8FE>wsbE7lBPm`)d])cN2^Kg\Vmc' T@% ƹm"Z̴ ^åSZգ[oi2-©m KB)YrP|pv5ïi*S(YKO C(Y R|Ԍ\9F KZon@lblr" \IR'Yb70ϒ˖S.hٸjž `*D UDU&'˚l-wE,E7 `@Ͳn+ +TEㆸlĊ~b5ђ<&h Bbu!yE(\:'fLqm5R5Fz.zH_~=怩,~a=/vkKVNlold?[˲p*嶱s+%\i Y39ܯ(?Z6. oE8'V􊱱8&,B5D՛RQVrLqYÿ2tLfOVzt o]KXvCv=hI6J ;H]5pd7l 0DXcDjIMyXWF1|FNzB.](I첁+z9\j$ -XSj IU>@t͍ج77 qd ^6BRi#}Zŋm܊~6ܲk󴫍uW i!_|@1n"vY]9F~ '%m%@--ښrh\+(QZS0Ta㬹3onl6_[CXCSs26/N&p-- ™E} U *eYnqlJ UTC+CiJ'Vϖec4-$E-MZs _E;'-򟭒EP<D+7g2ղ!b*#-xxSo"I!H(m=;W.b&--xNXHRpp2i]^KrMu onl.(tY7ƐdUG~4ņ@SgΖҎXJ[ G.̰F뇟@ [n50I#l=)cqX(l`k̛CF?[|ZK`T`Gm{UcDsˊo-i-+XԺ̙77lahH6:Wᣤ1$)8QFn\lk̊~قܭm!$(f<},7k w@t`Is,b`ٸ007?N.gK2>V8)*nc4!OY~ق[VV: 5l)[MZ?[rX] bF*`l"Fh` ,7jJv0V %U(h ` gK 퍓KHpp4l 5p\ & ,[(r_oZ(,K_U@.dFa-.k嶁hϖdTEewotC6̱ Xwrg b외Imm A%p--:smiE1wH s!#-(g!Ekmb#I6Κ>tZ Hʁ:U|̯i}7?k߂ق\QtΖY/R*yCazM:9.bق +$/T#3 2sk$3د$@--jYS,T03F0k̛CF?[5LR Ca N+]k[4WL۲8@$[SH)*`mZCfi3O7kl0*XCIЩanW6Kys|3' s:'DTT aY4O,E7l1l &C$WfbPfWe$V QfVTDo>IKZ?[rI)|sh95]+>kS:Ut`LN T ˆ5oìI3o~lI&Ғ*7r{`3+ d gk, -r@)L.ЖT{@Vgns6̥P3i"t '`--T>L :̌д-2bقƏN}bә4fd"%ͧHCG)ކy留r/U+ju)4C)Qdt>H:bMN#[M#U6lĊnآLEmPT ȈȍUKysgÑҟ O8z:X8LzXvp+bG:hJ5 j2o^lu.kXKUwEH _+O lIgbU,xtꃖJ.oUCeGr*G#ObXϖ`b&gNPlH`!E9OXϩk,9drDC gNPOw8z P gK.)OFXS1'u!ypp0[,łHF3kn)q$SLFL*dTk}s&-暾sؕ^9;qji Uƚ5oLE'-- >NJbN#Wִcvsg Tuqzi$ 8_!6Ԛ;%p--H-Pp!@6̯44qvE?$386Q2T$ 5l䧨 &ϼ d )EC&'v2UqJj,&(ԊnBl W,+lxRە/C*dл<^ %YTw􆡼ݯ+MJN쬇䞣ܸ'ZgG5gM_JZPmOW5S\n)B, 0:mlNVf kR)&¸[bnyu4}~<~7g DL+T^)׃#ۅۓn_\6(ˑ> |*Qݗb~2xKuM8/v8׏#g]h xB:IӬ98yhC%+WC^ CWBj}Μ +rYpN}k mS98NӬhi9+j x!P)qH>zX~}wįe!N~+7Es tlo7)srz߱dj񃡝'۳/bllc1鳅lsm70v_kz>; M̝vEW4rp8ƭ/?\i\?U'Hټ Tn<|L-E!{SDj j-\JIZaoj35. 0,V O琑H-ޔm*7dԸ\oۖEBFr3O ["a {e+_(ԇL0f4lɵ!E LrM7 @pO74lU)鞋ɏqY/ 'F=GO>fK.BU㲚^Vf474lV%VVaCKO1؜YMC*;7Jw^&K giB囟4lA޹0$WIѵ͉0%<]^ʾCL VAPtK-kdRF1)9a҆x8PfK(8L k[5wZgޟ_YfKIS%;ۓ^ȖG-\|ԛS|JQ^s#daiNmޡ(&G7ly\w_~ԶE&R~#`F-])Nm/ޡ`w J 'm3?[%{,̵ʸR:s:f l v_JZv.ewIWB((02ۮd\RϬZr`M[as`-Xs\#cLDj\- {u\6bUׂlELM}b'U-&u4@i\[P^½ֳ.~8xaS1[Pȴdk3{+^{z dKd6kEQ{1" |RtH-gyF.Fi .eܐ`d$f wqbVGkO ["a$7=PB\`BiEC^4Bc6.4;ޣj`z Lg5W?- wN,\psgKpE"kqC/9žԋ"BMZ?[r7x|dN{y#]77{\˔4s>}Q. dgKS] *wԚ61ؔ.^bقYYNKWȃo~lIFfBu+܍~ :Nj2|G*u:pΞ~qvsgK0{7\oYnЬYݳsJ7gV#<[3<^cqVϖEI[9p1pl>2s"-?=D uoK_>CO'jlIe*IZ&w#q&VsX4N,s{*MZ?[ٻyehB*aI8 -'a G4jkj&j`pZE/CFTIT\yGn\É7?llA gE渪*U8 P gK(:o>C@V8" F?[!: g%ۓg_;77llfz$ LՍc9CF?[yQ@҅ճ+gPTά&p5B0#8![xr9iYimyw4Uϖ\]TTeZBnl!E1)xRxrovϖX\VTd&زwTp2قsaJ(&2lL#P\0 `]kDCjit)8,ֵ0n DF7j_7A9Xiucǁ"-r!{?nΪ%p-ޟ-W.ZVɱߊ<9j!#ޟ-2YޔRTrsV}'8\ߠv e pJACp_WM[?[I20:Zgun{-r޼.bْ N-42l櫔Yk77llf\tOضS*#Yi0!.j'lkS;+gɞnԢق]桧mO3l>權nآ)`^ R̟,嚔iHF?[w4S9`ޜrɼ'Yi%kVdVYs\t49/)HF= ,2kۛ@ " n `F?NgK8i] C`pt)»e(w&-C+OIQ_[fkAO%JMs2ْNv[1lD-=5  {+eT2m{gxe&%@($Cj˩cH&m+z  {Ζu \q|,:񽟃Ш<oR;t ~alAfEȺrضUn 4JE7lc gj[< XgK: ^FVA̐)E/F~lAn>*2ye̿F@`$ϓJy`Bvj}#oI7`{7'jL4rR} n;*'Wtϖ?gJ0T隉yllAVQx8= \x^Lꕶ\vbqTίϖdpQ8 eB^\3 d gKC#ƥgYn󍒾g4g!#-&yr`B6.ri>ΰ'x {'g\z&XL4W*C(g?l1lIn' 2<, tF"-qnqR6[Oߜ]KZ?[pwg&y*G\-yZ![#bNeOʼlA׃G`qUrvY9`(J-\`(>̖dS^) L8(P.qpC?[McR lGߍGtJ];<.W~bق$V.{Fe<"-wl&aE}`srE7ll5N.tr;T.v89`D%aA(sC 1\iheҨ1k⎞mO+|(_XOZ?[;OK@&kqbQ`qsg qb+ wme=S8 ` gK7EWG+@e~eZ"-yXG6mb]Vކs^E7KhH A6mrT ?D8 X"̖9^^!9)ᆋe(#઺"-_\T0 )i'VtϖyF.*e27@.قIq7T &Ten"YKR4ά'--' i+_MYs \;řy.J]){|7o~lIfvzd0!O`8(cP9@ l{(g Vn{Fen?GS.9`[EC%L5T|gkEa@zזk2$;eyEE+k-w &`>ݫ^F4@ VDakmQu(!%yt7ґ6vMXjjF7ll '&|cz81xss|M' J_,'{4V{GRSO [?[A}k&NU<-!/ZOZ?[;wm>JuU#/.\8vBa*V(ϖeʼ=4fo A[O [?[äMEj7d^m_7'5&;T BY}(plduxUˈaWf; v'-ޟ-Z|0kS77'T):>2ق΋Jե%Eql gE%yxb恩_N g Jq%`--=v@_~5S즵{Lϖ`toS<j: XC:'>&p-蟭r_du.9{^PU0TPMEϖdvpP^7/0NgG7?lC =W%pXyycnْk6 l %s3K_½(.قjS/d.%ZSHזS x+9`%x.&jx^O=Jmˉ9v䚓z˫hillI' P1؜\"-?LVQڦy=xpϖ`tsrxHcFYKNlAUaudvOW7Cٞ`qjE?l?%ݫZ<򿺽?Fz(C08@ {JzK Ҧ.>e{osȖdKY2򿺽D_sx{L;u}&TߎNjtr爆Lrb湤 !(,ۓxdt.`_H:cYHOU{w>Ml' `aݜC,+b!hUэ/D94 KgEeo>"ْN^R_+ˡ`WWe  FѠ}Ҿ1?SV[!րfs{' /wCfHnْNn;u{e ס#ޟ-.IHd 89YCHkg | ^ @! P g n) q,ӿ/DB6D(EV#S"؟-S1/2.hpL^قZo)uqVrp*ڸL- ; "̟-j|0 hI.0;84~c& f|x@l 6GJxqz9CF?[(aoMLƓ5l6'UpϖL a"SdLF?[I2'kkS?g{?llAa.5Y&Scv\oxn6xcϖz򻌼LAw}-,έ%p--ݗ`JF GjLή>T_}>-'{BY|λ>x9|}ȋ`ZI_hwSֆZW!󪷆鴨poe/ ]֬do+r/^I&2=wx;YU?hVTZԖ$&DUZb"m|_bz@Թ1Nl \XfkKuȥD~?;w$ݿ6 j;4jX‰sʞ61:xZ:OF?#LLs:HK sr}Q3~paO{xl:樽n Y)+WKsڪg}C腆P_Ƚ?'ֆF e6N,Y%ާMX?^Z"+t` ^DYVc'_>ke)0?R+ x%kb}|Mr|ѾH{k>c@RD.譁bu95jZ0%y6ͽ7WV{uvb Urkm#+UgWAmj?l70b Cm0YGZ~EɿuJ%38 LKػ$d6R-X(^W Io#!4%(+Xc3t A٢[rc[\)(bs9^nزi{rm#%G8 r~vsʖect$|Xca.a傰-`ԡ_nf}W^~M ߇1K>kۆ*Xן bF!.![ݜrM[QE0.l^WVj#JB9B]_!#([u"w.ll=v O[oetn%}oUާ8(BŧnE7[۔-'n-b^n[rSk7mm0қXO|mCѫ\oDx:fK1o]C¹ pkMNWXS0 wR- %[-m p_?]٭,OFeS٢[lO`\liӷϫ[7J݃/琑:-[cHEe)1(5K~-:gݐE3Mfe~SP7{֭*;m,hՓ}nˏyv4;ۊAVMZfVnc8%`c]^$k)SJFy6 PKƛ+ ٔ웳[!g/WK-z@ʦKhbWAꈪ e7^ʖ` \l`]ǻdGȮIږG?l_ق8'e6*Ղ|Wpua"t]Cu惆})+rc}lY_hخ@5v6x9X$eK+rnc|w ԕG% PL=hu!R+na[|+Kr @r'@ʼnnfEV_.g8'a77φH5C!7?lY}ق &W=N䋂m]lv qfյLRʊ_FY"]dێ΃-Ke`:K1 ɆS S"e0[pu"B2}Xuv.qSi6~pڦY7fNM=񽻍8{ ݲl[͖) -e|[l !ۏhuHewS첻]ޛlIv׆ *R؄샚]2=QG4~b:B7\?mNʉƃ gWpe)٢[VO얮g\D1Dm؀+sHyd]9J6@*dźl ޖ}Tl<fD'Ɇ}/]ȕfl=n)/QC_t"yuL贳8?c؋Ŋ|Kf !_ԂPWֶ !&m7:[u"-iz*Z^a.G?lْ!cK:[1Ȯn*v!mT~ˆHqmG faֲ]M*8 lѩS)уT}3NonضX.*ڦ7==rGYw!/琱-ɆX%w[X!Rbdž{qmp ue" 4_߷&(^6ۛ'ۋ}Ep&&˷߾wR.>!c3:[氅dG^fH\ >y[򃼱&$sÖHɱOyruiJ|?jzOEg^E8R|˦_ܐۺzO/lP&;\%(†ݖý.v7z \(Ζ\^8 G78s7@qbű ]4, s܍Be[monN,X ka 9~K8LawB3{Cg .)M&u/߈P7y X d ,)!FooQ!8cp ui$}@SbCv7KΛ;ql͏k`:[kze&S;A•g N%u$%W+*U%t!jki@9?A[ˌf TV Y< {t҃NmuMp"b8eA~Ǭ8qjpV_f{n"Ϡ]:eN 5/ڏ _EkJq9Y7|^)] 2(g/l ގ#c9$]dFSlmF̃K&sC:$s_VYf4 lZ7(DW͓YqXFǒX}Ȝ@jgHp5!LInCގf+T˕U rN N7XJH åuȕfj*Url27c䎖HF$55Gƞq,IYp}s`fSSx<6!Jlٱ{905YƪVL/5b&7μ|-=^̮f|Jɔe18-!>ܮov;ұ$Y-IyO}4ޜwoSb8%&Zc_tj2컽qQfI˘zㆨ rgΔ9kXV2ZNb6Cul8q`lGRpq<$>cC+ Y/׭*lGT_%&rCq2g]ǛwdlU8~ v݋39a&}cu܏%%:eFS/|mi]uaf}ؐIhӗl[Ry3 Xl3_/ En//MG3LJWQ՚knoz ss!Ja3:L)1{w{q\lERS$Y16EQݎ}7+֜ӑU0.͙/m ƃvnnڛ]-naƒՒJMe:#tNb{CZ꾙q`lDǒ[PfV S,!OadcK6Pxb*S%+!L;LW\ٌf}T[)e-Air'S쳽qs$SU[T$dBhkkZ\Ke&73}X*!l`a: gzV~X\Bǒ\$Z8iLYBQ-9`Zl&iA,KS$3uŞ&Gg¤ {lov\KVJ(YkՑ`D&; ʒ2t,;@1eBk sj٭LjbG6q,I)4LcV1>fKގjliA*t'Τ@r͎cɊ &) T ";/Pr4܂%2oZX_&r he hFkRm0'd0UY S\ΔuDG{[q&ǹR q]?iLZVm_dn|Y͝])nAǒFRm[>^Z)M,ªɄovpTrG3\VX&4eO@q:Z%Yʏ7;}X|#/Ф-UM~28JThܙql1 ЩԑJ[Vݍ3OfL~+]XR2oZ߸V"ʾ&$ uKMe&2͎#c:$fEEef,Vݒ3 of Pk`uk1mˆ 9Ul{3UuL;i"ߏ7;R؊%UǪ& VBFڦ\v 7$Y,Qu.ԫjm1NJ7+AeblL]41זl, vZѱdӴZuS,1ϲ'2GƆt,I ƥQ\_ @9ؾ'nhǑ)KF]L:ŶT<`4nLimYOhXl_Ne" 6jq[:RIJsb:Tf ;s&>8.6c\& 3K}hET%쿶haifs%Krӏ:RZr4++;n &>h&7aJ7n7j%`a҂U%ckRkoa#K3SWUq/hbu wzW!XfesgKNb׊tAئ*$|nKg e2#:vT`͎cɊk`# n{@.ۮ츽dIR MqhlV0S]m9[t\x3,SU_*3`Uf5zmʩ"aƆۛw#enTkޘ-i&dFkZ%gXR)Z,Vxlr[t7ܐ%Ia1uitUٻETڜmov{ƱTLkʔalqT[d}x+.μ-7f5$QoSsg^ۛ]-nHǒ՚bMb֥V4,:mQcnqؓoX d(Ư*_$3l[r[`{V{Ʊ$W&,F@[n2kmmwRmofNޘ0LUn Yf֓T$t,Y/D /Sv[59!;vZqXlGR7-7ܒjxۖ$֖#Sלy$k0v-&,j?N3Vxw$X#u)=R >yu@vѱT2z֗)96&7680vcILY| `h[R%[VmQl]Zeo:v3oŴ dx˖y̮cz5汚ɄofڐmsιRt{; Xqk/uF-&WLl՛*JVUwZQ7l.m[o91vJM*u;iٱdEǒ\UW@L`_m&لםNt,ɕi -.6dݍPv6[ѱ2%ęt䉶EE wۆ/&UحN8S|…&H⪅XZ2Ma5pe*ӡ*"rrΩ،%F1`MSd{r[4%{;X*QEu ZcQZIUPIYoTg4/fj tɶA.L*XR2Ga3ruiLӾhNݕ g܎%2Ka5e"ȗtɶõ| 82+4He[:Xߋ%)z :e<-AuOCgjR:3X*w ;uhXdg6#.vez~-念e.Z%og׉ѱd^#BXMq8:(GVt,$e>,zFD#of RaЇc0Lyl#˺z;&kgWhZY*j5&n땵VގcɊhqj<\HZ*R5JrEŪM,ɕ  ,񴭸! gюonR}'^#Y4L8AI;3NʔΖq.|!hNŵ֤LQ4mXN2Sa5be#j%6n YPOi:;mX jf4_`D8:e+\ f6ı$0MCV 7m7n+e3v+G̲F9^imN{.iF;^؇%%#&`9F$+TVD4W܉%2_a6ZRE n y+0ވB/v50 Sxe-u'nA;Iwek0_9Uj[q+kf\KK*LFp 9ulE)Z+oesKrkڪ(X {qiD3Xlΐ+~O ڏEAu/mioG13ZoukefI<4imm ԮT9lnX4a;cJ|ys>C=8}EwVj^-QU2lwHB4UoDPd.rWܚRI!Y8}n}˺X{:m#T/0ł}6]YKlzwN$*Y|<+)VJёTrH ukkS׷ag)̓CrB0&,[9_#d:~$T<8 _Ȥ*PwW5'ˈ!W~tWbȻF$G2~Ԣ< 搢qmN3 zWёWI{|_OOUG?NGCv w.ÔƓ^!0fRjK @3Ѷ*yF'x}ϲGfCʁ+DgݿC2s@5ٶ<˃Fwpr-<5'mg0eQ[yaUcQ?)3w/o"]ʃ0 7xff?JeP˔Õo IgI KH$v}#<4?iFm"஁?Io:Nr>>ׁ!0aj5uPMÖRaHɃ (1`>rEeWQyÅ pըD"܊A1lb*{܏\w~r[FL1*]3UWL0sq2zR~[~ GjuڪDٖ?r}TgMBn:;40r͓oIys69\s SG =aOATĀ)iH΅aZ❮{kOPczON3Q™AApʛ~+:f X6#Q?/~|p[T`&R:8 #$ 6/*!``dZu0]\yp?s'џ!ЇG8'W޽UGɟ0b 17#mʃF)*!a`:<,0=஁?3E:Ky>ୁ? x_+vf6n΁!ШQ O}5;G"3 !a$ [.KWȧ}8ૂ?le Fb7W5'g2Om?QwfM?]yp$J"\=>J>+aG C0lrlйɃ!1257;؏*?r`?I|p5cs,L OO5'C0O80ޟ\ypWe8~B:Iҧ3:F֜x௑?)%v{'G? <Cow?~w1vKoi:0yza?D`u?9%~T#x&7ڏJgb?pot#gɃ ~ MYN͎~ 8jwg9u>G~V 88$L`s ௒?wM葜IqO9zgj vϼ4YVۘ/f=988觜jڮ~Ps~LPeߖ"`¦'SJ|1&uໜzdgǑ?%?*x[9|jRǤdfpnSiH3v˃Fs6yY^<|dgg?f?8=஁G@ ߌ)&,\$0 !qs25gS^<8jO70 ÖZphw)Y[#n4/Sw (0LoOFj&~pHfA1˜$VxȟҲqTdn;*pஂ?&N`h}ʛ1R 2Y~J~PU9Ʉ/LQ!Ƀ s?Jo~`.Q8fַs]%?7? &~m>9a?% 7_M+86\a×ILw+˻+Spܜ~W=q?e ;ChGJ-O7b?& ?(^ <8kOY %ڪVS`ueJ}#~K;5Fxȏ60rTpY~J}pHNkWjdeJliS+qOٶeʃ b, vr߲vvb_*s_ȜNdrfGO#X*Ջ؜l ޟZG\䏥r #ɃF",8S;#=௒ˏdUsT?G9$sH`.zOQ×X*qHbcʃ s( pyX*xcUr-UÓwg/B֨*/ƅ)xԨX0c`!8cTw3wpƝ\ypW\菥dJr:rQ!×X>y?Ll&:E5dvxpĵX1׃{yO5.cܒ(TKqY4~qz#TV8[}Yc?{3X9d.$O}h~p௒˃0:)5HɃ,vr>B uX~W Lm|E`,tBAa15 |'?|5,cd]rvS_ed#Miڃ!_\%ɞCr(Rғ/Tr69σ,}yXI-WC9>YŵX*aNH|%W%O5.c\|rt'of6+<5Npi .(T B0na,V~,8 T)~_%s?$g)8ꋑG/ y ?<])T&F<8\nR8.%"\OXrtpIOU2cyLSG1vZOW8kP222WUWǺ׌|^ tW],UftM\c|> ?|;z{+UkuᏑ2S,mwzo\Y>VMCwJ-ɖO ,luW{2zXUzhwMx=W<ϜD,ry>v|絡CG /}^9 Io/d<ӳV%Ͼ?n\ޕ+]w.=;yH}]oJO9gľw ݘuL*3f#? |bԶBdԫ2C$,G$c92$_p)__M$H$z=ay}M?zHuAЍ7ʺ=7[I_ӋzIu%~!q~{\_yӿ4' <>8H8Q}6nz1awi8+K?oS;ʣw:q_z汗yɩ?ɖ'{zOoߛjwd!KވF|vٹ?oɍ)Rܥ~&}v= *t-l^_/d-! ^x~-R®\.>?Kz`G.GZ_s$ZgvK?yZkJfrtᯥk'~ie=^LWJ2m=52,jz|s]oĻs>k 2^yMgn?.| %~q.T=^M0܌'f?aWxߺay-l&^ep\Vlz_2,zCxNkk) i䆦1 {߿}9W?Wiw_5+^Vjv&Z}罚4]~&зOj}Lyۿ7-:nt3˺+JX3ĕw&+kϩ_Vʡr~[g/9s/%&70F$2SJɷ\*׆Ly_ol2}Qn3>գ/ W!l蕥_,2}]IߥumH u}}.ׯօl4l:>_ܖ\;7ܯy,}Kۺȕ:>?W odܒ|ۼe:-{nޯ׭ynUb]QW#_I9m.9[orhDiM]bG>~5pEDK5䞣'F"kuE|%+v4ES:V`4+YO'\״1fdL|Iʵ*2cfQU"x_Y㤩arD\%&4 ~t&]cl{5'jre/ X-dF&k\_oXmw?}Ywp|W=>úwb uX_R% ʼfs#+rm,_Rl nCyiP<~|W0|K9\b:yeG5<~xu7m{}Gx"y`/џ؏u4aGoQnV- c=]~KNJfr4o:w#R!{*uHzux0b6 R۶iu+ D?PS~ƫT]oKdZ`|wW {3pgT6: G-檈!SndgO]VI~FtPkQ^+[v9;C鯟U=G^y{ '[k\ss#~q\'G;֟9H^ߊdo灌+zJN䎒v>s-_8¨JvRT ?cOƷ<9y'kwOߒ$ǃq%k=X;Np;\`Cx.)qH큜%^ѓq%׷"y;z`-#[}pg:鉩TMlo%[vi?\X|sR*yIu%׷"y 3?ɰB#y ;<[$;şeX'<z<W"y}+d(qG>#h坫 =-,S$+oyr@NX<DŽrAp#{L=rוH '{;d*xu\΃Dy0x0R^#yu%u>d;}ƹvƷ<8y;t!H.uRA^ߊdo'd;!Ie"xKcUcW ǥ:JoE@V=;<<#)~ˑ;o 7(y0d=W"=c^ {F^Ix^eF;ĭ_x\_+#*2H|וH^ߊdo'd]VU~xœ-OvWXeZ/cZp-w}'rwehQY_9OoM'G;?!ka>c[ӧq%y Pׁy:2{%[欵v^ 뱵q%u~=)br`my\ +f|˓d˜,{Zt+ܮyVqMF,t$T'G;YYTnNjK+$.Jt Xvy}vx3JXڮߜڭOG;?!k7F +[} ʌoNF;3,̠,q%r׷"!/:iJ,<}kѷuE6 IlV^~Ye!t= ֕yO/ߴ%F?v?r RXe9$ %{[[qq/KvU®/^WZf[ּ_u͛{˲òvxӒB_Y%?]<\u7]Evְ[8纞ln|}nAz:e&5}tgl_3Ы],e2Sn=|}^3&%Waw;N@M3ưn5dOoz,[RڗOwۿs|NsOsky)QR5]5m;: V5>ax==vss>1g?x=a=Mߵ3ޗVofaaן6&/:sv*};~]~5%}jِH =!f׏)_ U 2mHߥl51i]؛9;{T3K& b?uO2:fQ {{K_ʷm0G?c'I$}K"D:7U 's\G쟵#B] uY|gve֚}[W۰H/ef Ωgm.[~ʞd0^2L]~Wm2*=|c5чMw|r@= ~|%W7&LnZu KA0Ez|ɰ+ 0$ |.}ER1 0 e+?ֿdWdgv+Whl M2jm>R-m>B-߮x{e}ei,l˜( )_+<3ʄVLO3KOZ2[Z+{_S߮L.F-><ʕTo8OLHX#x3|5C_k QL0/mb wFXpiIxL[|^̉ps}n oM+p%>_nWFMΆ~v7V3$h/y 4%KxME X 77AiMivWm+ J]]QsP'̛/o-PwZr۞%D߯ϯ+d#nqz|Vtb+ D"~Y(j*ahZMּ%k_eqR-_isv1c='o)KOљ_ŌZ }mzw.*7\yv_}^m#Ϡ24s~aps|[8Зd& asW M'o>@i5ixiWo]Cպ=!{s^~aWt#_oJо|^y섘fz W|9+'MĂ}!':DW/ Xe}c3"P/i+@zYRNӴ Pb갰7ey)e,L* u27xdŒdd[u|xZ:#CuKm:{;@X*Y9U{W+J82cINsr=iF+&AJz,h̋c[F2ՑWl,cIl)Vu bXX܄:~wҾ82c/qSsuk2fb^&s?J) ʊ C4/ce蚂E?3yJngʋ:",̄@9H=IM0߮ LX?l2cS3;+(x6+-دÎ#c?$3EּL ץ}Kw GŪ,+_W(sRo44Ւ'--Bov6ԓ  r`,,)M ڿŪ,؊1cZFmI.i.!zZX.ǒXYJ8| oWzWԕvݱT@ =KOD1mTKގ#c?$W淦CIPЮ%^W‘OWv-gfsKNQ.ԡ4";vx2%gqKr=viY=Y`ҽD3_md+M;`aGnm6Xrg=֨{j3JOگG`,IN&qڹM,y.B^|i)X;Y3z7sB4#yъb?2& Na W YMr,\Փ3iMf`\}/=8$B3/vF,,jnUjw+b?h ddD8wYh`fsKreja4֍hdz7fƁKOMnI{,[}7;X\fK5syHKӞ87|AQ-bγE>:`,D@e}Q._כ`ǒ`YZڹ}k_$Wƒ,Fq+:aYPbW̓}˙\R}ڵde=֞5)5Γɛq`,R+YG`v G4sy;Xg\ W'Ue%iAiWԕtif6k$H@mOK+(3'@}pfT0R.~[:zX.8:IӾl0Wcxhrpʯ4Kp<閶™q`,RmT /ArE^|lE; X,E|{imoNshgKoQ`0z4-k' mݴG,BԾ% '$b+D#XE ]9f6;$X7.MBC[;\@v9^5vTrG12V<҅ьc &&'dR\Aڷ:E_cRc%dnRɃt893-X+kFIa ͍5e'|尲X\ļ%2I:YmG95M78,bJI;׏!ۦvY"SҮ82cI22"T{NRHHf[ǒbX*Zѱ4*ںb+`iȃ,oǑKЮ5ښ n,_nt80cF-WZԜpHu(y#EX;o}a5!-7Z6˓,oǑK%&%u䎖N\_q3hiyX,idӍuhk)$`.G3EX*|$ sWDٴo m}3X%*њE|e6v-;Z4Ƅ\ of6$L.E^z!!8k/lk80޾c܎KOYDpܢ!6 ܑ;eX48NKhlM ؝{<&s?J&fx*!%|6 ,O_C{3X%K3I Y0ۭϼd,uB dwvxv> YW.smڷŲ,ɭhW)H7S[y2l%x)%B wH34 ,BWю% ;w"WmIZ|):Gƪ,I!ΑL,W2ڱŚ,ۑOZ"Fz$`9?sXT.ǒԑoew2$V 43l#%hfT02=kSEج+YgN3%X; a rAJu .vh苯.ю#˂/vA.4Pdz]ziC* zEBVŚ,̌N,='.t4\%)A`Q.jElu3[|M ӇGƲ,ܩb1\ ҮB^G;V,U=+'2^ΨQUcșӊBh P>yR~Uʧ5IM%ɹфrޥ qQȗvJO y\%ɔ%)q5H%zS,i `K{\ *&)3yOTފb?E~yi)tqZYjT$'#b4X%72=QJ$kvB0#Snl>CIqv s[P '+MG7X3t$m]N}7!kT͊G[_f6:_l}_.Kʖ15<8*Vc`yfx^rdWuq`,ǒ` Z:7zW*pUB|dogK%+d!sͮ-oǑK!;VK$*^a5U+XZ:lGMa ]*w4Ҩ607;FSX*Y9X]oxK+5f l\gqKr2t~ڥd`Uŏ7+X*W)U;d#,AM9GiE\aǑK,D1 -4둂Η(oǑK%3.Qt BEjGcߜAG3Xlc^PE;WwjH|i{3%XlRF)BMI5iHz%\s? V^ڽ^W80Z#kj#Ik77Y8M/dNގb?JVN$f, {;%Xl}x Ɛ,R*!X͆b?J%\:F8kx*#UY;7\%)ڱDgg5%d15&(؛q`,ǒ`4JU2Y Fˑ=[q\,RX/7w,GR XB̛Mz,9+'_\GѠ@_qdR+-KH.G轎FcjT:!^s?f(w ܘڕD[kH $w`qK39eiLmeYHy3X%T5$)yMHU򉢥3X*X1C;WpIBXvF/YAhShǑK3u@[j$l29|AAϙ"T/AWqXrVTRz؞\box2gy3XlKuPnXͬ6 jԱ,LNXeɒt~ze5,=˛q`,ǒ`TYmy ][kV?UMގ#c?JVNԩ!Ůnv/ogKs'_b~K&/TPk2[!`f$0zGZkV?]ڽ,I5e 4hi YGhiy3 R1t41OreiR|ufT01QgYGrB6vA3kt Ԏhf6@?l]Jv蚵uvNPG;EX*Y9` ]܆8sZXǒXR:W3S |S#k T.#* _i.gYBryBtmiq5ˍ2IvTrZ&Y@TYFjl7+\f6+$zi3Q !+݀N3Xr):*Y,?`ZASkXJjx4\%iگjXd{@SWmҭ)؛q`,RH?zkת}3MZKgQ]i .Zۊb?䣷vFr ]ʬ 15:nH&s?$ Hָ 4Uk֘%.MX5kufCcлKhLMSqe`rf6;_eS9@Aj유4Ԭh74tcy;UX*YvU,\ǃI4%_{3UX<Ѱ!:hgVrGl,c؁S;hi !A&\@L@X%ɳW "(S8ÂjvZ*ڳ뒎< |F!D\M]vbL]. i ]J !.+9Uճə'G[vLەoOHL=(U7>gobRePe9." ;x v+<ns{g5˄=Z+Tydf*.`:U9ŃӮv`ly -5Z,-[] Qbwݾeq0f}Ǹ[zooc:gWU$s8LCKoϮoY`[^eC<1߶.ktŬrT _p0-a'Mg<Su#,h.}0FsVchAHG˒}mװ MTc퀋mە-a/ٵec )ԚYRM`@,u$%'asozG$O Uy\YP^oh4 {4ͧ< )uTI^3o[Am# A QG;[FYK:; loz6erwG,YM{c7xY{r61w/l%FoQMj vuxlcӶ21)E#cmh}iO=')Sp|fם,D=3ƾ=shmpɌII‰{?gmfO` h[Щ2)@0Ԃ}6]fAv[]Qʷ"+we3=୬xVJڼ]n |'TBkB G]]?f'qQ_'/$YCbgK{,rًtzPW<v+S%GFta,In䠺$*FI\MpTRZ YYށEuskg(3X*XEw0Dֆ6<WǧX,S4Svq$٪7ou B3UoL 9l2# c伵Aν 6>x3X*X+8T_6.`͒5Gy3 -%V ;[a Q6mqdtB/C;פ;S'/, n `98,~ cIUX..ڹ @ė[|q!dRZæ;Sm!3?Kh]VJmmtZ!8Qż`RZJ+H p&@82 c䉽& VnQx &8.B cI.,بF-܊2?\\&})=ČaK~UTzqDqmwތ#0 .nY2uK%MOڠ7BԜU{ζutgHov$jg5"Q Ea,KwVA83 v -| 4X20Zv,m)ek6Fa,ջMn@pt^*C/Ӳ5FhڳMH\Hm!玧`V1Zz,R?HedYXRZZi;35XSi3MA:&0NofKUM0Lz3HJlBlތc?kTYT,xq䩹R\zfX󏥒Qzi炘[FQfzkstf6$bu\hmvDnUpfT./W!W P܇w}+4X&s?JftfRMAU3(K YqXYF0Rsy:٠B&pHRXK*GҀ6 |U*ogKUPjjacuM@]_oAKr%€5д㙂MR,ImJi t I/JqȭSiMu0ʴyUqXŒdnvl]G<7KE{3\句RvfzMt:nUΊb?; \#MM_'n~`.ǒ(c4+b\: `.vGEXl*'61:U 9ivTr^ L}Y(މ*,3D 7j؄u1@USI%`l`oƁKEa_ ̼ldM",I -&-$[R^ 7*ڳ,GpQ_ˤz25'f20VcI0dGp nrIW҅3&l0c`E(sni,< |#XvTVAuiq_7^n'3n}\%TU.ŭgX Y;׶x%V} Ru_"+y!Qьc? .;h7AN:M2,<)5TJrQ5a82VcCH!knNs6E֯H6ov$jrHs/"-z=0o93UX*1t`䗶t*lZ`X%H\.p;Z 8OXr?ڙB5j-y8M=6Ю82BwkTRҠV"5th735X*XkBeno3%XkڟgNE뼻گƒ,̄wՎ5[ZdY?`\%Zl7%mJyU\G*\/8*cTW;bkZXTвhڳb# T܁]']dS]] ֻ\񏥐wWlL*/&יִb>82VcIpOc8=Y+T ,w7jť~n7m:ވ;e QHOh[{W*82cIVޗSBe:&@a\b7/z-lq e"n+YQqdRZæ@KmBefLz\ǒ;(/j ؍e Oѹ:,w [N-lqd,RsGy\REmG qd,ǒd!s:+TX"&[uM -; Zc$XҰ^&8,cdV r +|Rj䁛|7vvK$אcl9WEU}cC)KT)7f+x>ilqd,ǒd S:RGGgףq؛q`ǒ``՞Ujǻbn\ѕG S m0s93XkSVۍ kxt$Kq5axjG+dRyx{3X xEi`)#lBcȒ`he0BJt˨ e L̻d~" cI)2Xr̴Kdx`F/o_HdC-t9DD_TT d IEc*&Z%VN,b'߾+qWnI6M޲&٘N--9v.\6D^6&]5֮ÚWv!^Y^/.A^9*kXV(3}7IC jҼCdW+Yr@_EjQ]z#^Իynoh޳^"c~5JwMk'V- Zj_ طgo ΟYg} %?7؏̦_ #S:ѓb_gu4mǗ(.\@cT&?6jy1g/Goߎgŏ+^H˓"IMILɄ,k^7(gmLd+T%K̔d|)Vп .{RVQYYP 9vŔ72bR«h'%+F55oj 4c7S+Amh_knLk&0.v9te?|[C&u WVy΄y$jP7z%>%-17jIέ#o.z2X)h5 רnlciI6d Fʊv/ֳA#GaoO+,tKb1 Vdfoʓ d5\Fs26W^f=SHkq%: Esʒ-n>؂7hLk_pwasߥ5}\KŇ~J_%=jX{:IR`Ҿ{_Õ58#ǎFo$ǟA1Bsaps[I 󆍬O_63ɞiE/sAYѧ+r_8{OԛGFM,IZGoy>b־v!4Qofܭ s%:FSYV^֩~hJag׋:[U&2Sj}Er}={bP,YUWܐZ0SjFrfB$7߸m)$ܓݴ]Lfhes+KPau -͉74U/q7kUhZR$2x1U4'w3^D%U&ZZ:ОEf.y-2LfH$X. 3t`FdFEva-֛Mf4R,I@7K8S΄mBKևn% vّLUbގbɊ4JbCdY^F5 se }x3pX,Ө1v%@>Jd҇3r[0ZT?l.^0qwR.1YƩz_AccpUBU,Y%,7f6K0+)5J0`FQR7&-"8,Zݜ(׵D X[ޘ,c]wS[F3^Ҋ%ELIzW}/mRq׮5Ul*6}A̜nysElV+[6V܀^Mގ"L+Je<k*A;[͸{pLvs1K~jXj, 9la0Uwsc>IڲZʅA5hȃ_TrC#\ze>#ZݞєYEU\ZagqKrdeQVX3Ke\kUzM%Wbc0nLGc\,K:q+s4f\\K0SG4LZ+ofeKeҴqi4=c5/ע`oƁdKwܴL먉\&NY~&?U2ZqQ"Va.וRU>]>nf\qoeWkdd(C+%6fRGƼi8GT?8[&5^(w͊"|-͘, im޿ +ffBJ͔)+<%vvK8ȟ+nVW+%H&9sJю##>.$!x$ygӍ'wUEEfH G9a< ZZ}Ek̸Z!1LXVnLjRѳT}1,HydF?ƒdȪl'Y&54$,aߛGFc,,o4֤“Bnhlݘ[ehl,vܭ,K.S+&u%~S hoY+}LT_ڣӺHs;:ULq(?k[h-u3n}Y73X,!U+4jdNUA fܽ 0KCk64k5&0'_G])EǒlVre2 _jRhƁKe0Lg$_ojykfq,,;KkMk,m߉A]k͸(8zŌEU|xG;^܊%%3C$w4(ϟʖbOqFt,(Yk,?ڙڲ5iF3̝X,SV3J5aHe݋[9bFel[RL=;Z3sU3qsk$SחH1)ֵ!&hȊYk8,vc6(T$#-uEhKv6ı$Y&*CL4RM%CKX.kF+D 6Lhq4܅AWLj7{EKF܊>2+YVJf.} O ͩpP\Zy;V؂%k%s$E|ROogK͆y ,'_O^%qd,RțSN~ᔂV=S[{߸حl$JPl'ӘiqTΌ6cZɜeaz"q 3ܔnKOfgKeҲ8C|#RЌ߉;ў@FűT,O_ܗVX53ՇrKELlYΌgߧ. "!C)vq3‚/X),9M&5)eU(!缘Z%o1Kbҵ2I _['|~9ҿb&*er$ۙpM2T+}`͎2CZ8ns]=Aar ?f*ָKV h7xbbTZ-gaK:$:hծ P)[Z8qdlǒ^k0n4u&Mx6S5Y{ގz2Mmf11nNhdW[ѱdϿtn2q&*[,f[ѱ$0]G%5E%M~q,.mv9%c 84۹ތ.#̩Y3 6sqՒv_HU޳bZpG.Sдb6qXGRɍi٥/c0j31fmoIh5}$Z1YZ&LAinк7X^u=ɤy4naqm tqdGǒyUgyFӎWўlt3ܑ%ZsͰ果wdh}w]9yp0*%__F55΁_0cUNZ#\ߌVӚX*j뭵m7CuI/}7܎%lR=JgGOih_pf=<ߖ>ќw]w\sZy3V؎%k%'jWTݓ-Tlkf73X̱{'p/e=n`5O gqKr Ӕ`*&Ln @dj;h9Vn-n&~Jy;V؊ G^3 Nv2!(UjCwۂFt,+aw/ I԰R6GH>SSK̜~4㪅XZsuikc7Ɩķofѱ𔉊|gɌM23ul mof=GI[/3@BEbK̮1cjEug 䨌NgkˬfǑKoMDQDf,!_aesK6Qx|f]M j/S5G͸2gS~jL 9SNn{ V\iwJL19UT&}؏%gȞ.H85r7:"ABPmzօpұmov} q]Z&]}nUolg2֞^ތcz<^H22.j29nt,;9f4}eBbtpyo806cIp/HUջVxdt3UCeyE_j*{;FN3UAHE1Ǚ0(q~t,Y\Y[U sRɇO+X; n[e Iɗ*WJ CpKE}zlhiݍSɌ736ւd}h 󪪤;k_Go ѱd*Yu Jo@[*}X%Zч@G[P15o͂c^ۛך=*.L4f)*` Z+gjUK0]k5LtVweQdJ73X<3$} ̌a4mGN}ȗEǒ乳1%X:A9%(.fRkg!KR3U-h6We"ˏ[l0cl֡'8$._{;&J"HfXќ՞(PmC| <юvcɊk'_#i=S yێeҊy;̽X*)駷„f (˷ZvY %4Q)/4uN7ԗ2rDw#pc3WeAm&ےsuf\0s%eՂeESE-\W&s;: m tOR3a͌c8 mI|ie3ٖu'Eތ3k-ebksݭ MzqC:diz. `bg}9-=qdlIRȷY4FU(CܾnT180vcIpv5 ;jZw]yر{yˬEs\]-klcUgݛt,Y/4LcUA1֖+S%|Gƶt,z3}X*isчAh۞,"6/ۣPH~{3ؖ%Fͤіʖl\]EGuejwihAjd /ۇټfgW[ӱdZFS[G|Ѣe؆e{tΗ#qdlMǒdd`*=hvlldY\=$ kAFk ړvN3֍Y3a|KFaU rTK[tɝJt,Y,V[N/ 7;Ђ6ؒ%¤WFk6S 9*v-O*{3X rzU wٖt k0p$d 9*z27j XVF;~ESyٞv7ؐ%1{FMj% 7;=X*Qs-V2Y6.lq72#MpiטmY_gu̾/lF\KV*w4)64gL kmGi[r5fg!KKF3$551uKN5&N+ eA}8q=* ʗ]ꬸWj-3!?n5(-뷎soU {ѱdE|dtň^ɘ\f6ѱT01Ô{~iEmLn ֪Uvű$ܷ >\lf"O<ﭸ;9b5U1m7AoqZq3:ըhi1D-)En١շjzkGnt,I&`[d",O5͸.˗)g{X*9^LM .hgƭ h4Lz[Xd `<%]VyDaqkmyDkŝXJk37T(-=';m6t,%e;òEEVVZ$n _y3X RYNhy[2%Z;!n,AD+:حҿ5wdd_is/7DCO\֌v\Ű#KV.H4Y%?LѢ-BѢi t, Z]-20+7Vx+:8Bm'b0Uڬ-uWn AC˖ۛw SZK,S+&SV`5L ӑg I1̴B$*a˃J98'UǃC'sC4NWUGYLjw%bɻxP"NFW Is1BHeT6Z9b? .rjZVDC[#RD<8$34* ΗM*$F' ֞ó8'QărgJqG%N_5'ƒCKeO8څTOuz` zmfƁ? n何.x mLbo^<8jOڂB6p{9\~}#I( k*϶iOW5's[=9q#kL3' | N{ =]ypt"&psGY~T{tpcu7E՛ k >xpԠt"2NBڴOOޝUGO*w@ (7WUGCrY%ɹw௑~c?N[_%T;8 N2\ʃ$s(`܁!n/GLO5'H!.V ț#[2wV tj8_&|AwIos6d}yzk$b==9a?)3-Q϶Powୁ?iotk'8h#~yͲNrD<|چϪeZa*@8<௑?ɖopܓK?ܼQr%-vkIRF$.vpHnT[ g6|yȟ7z}r'Y?xy]ڟ7ƒ$v`NPl,U !% Go1(/*YAJ'6l㰟ԝR2#N&xh&#x:8 #,PɗItpH.T~q'Y}1rȟDN$+֞|yC2C2_UGr?deF$tpH襥<˃J(俁61~fǑG+kllpְɌէ 1\ypW0xIn蠀b0z5yyT}n>ā%Q of6́!j'4MoOɃ (r`)OW5'Egp(ir`xӮq\+ycŴ+oL":NU$mXC+!9 HɓoQH>NnW<98'P9P,`B p@G_ (J3$C,p@P1klpPE8v8A~'A]n''F? $<CШW?ɾ ~F$ppHjyKǠaJӓoI!P~FU7?޾̏OL&dŨ<'ق}l]njWG|U𳮀gl*sonjz?8'av cl? ڳgyӕo18qs?ޕ7;)QANw}r/MR-sQ6ܑ{98n:8#.խ|@eQt5ȟQ?>0S*#<ୂ?3pmfƁ?>0Sq;Ƀ B~, vr)66X:W'GbOU?m8"~bPW-RSf??bKn+S`VyոXr&O\ypW\G 9r9K$sH:N\ ZᡥuX*q@/oӎ <`ǒ`='$~XۏgpEtzL'XR8 x'7\5*c=nu3O޿dX M dcI0&4.jzwX*G C"/ovKu.ؿ_XIAj0YHaiɍWuX*nWl0cyS]p\,RpU.ɕwuXlML#_$/FvY&PDl1^nU<ȅAU0*(qZ/̜O<`.R` C:pMƚ,0xVnp]%s?'xT=ug˃Fƚ,I+F2ꋑFƢ,8$S2w&N˃J,rMw$wuX*q@'G5pboy/b;Lbӓ#<ɽ>͓\IQcd!:T3]@௒K%; ٯ21^x~WRN>{~i7Yoڕ^|a-u*|z|H?N=~}#d ud0c!>0m-ZsaS򺰲 +<dG^ysn}zԶī~;VVn~j6$U|J6 6̲8Wr+srֶɕZzsF_Ηa7Uו;uyN+;n}ZG.nzk[GƱbZp-n\)z_UuPGnsMVmXx`<~|Wa&p1(?->qGy+I6.؏\|ƞ(?aO$Uڽ~W6bO'!}1&7zf^W蝎{l٠W~cOm3 Znh-}e) C}_wx& Fe/:O# ww%Kma4Y[/K7m@}K#~/{Z}X+++t@ ]yGjYש@^H^W<h'dFo>y=R J$>y%eZ'uœ-Ov>u#l}Ԏmy2DV${;ddڪR<[|r+l}kOt\ߐ́,IDV${;d&Me5t(:2x2[ܤuQ&%dP u%; tϱY;oypfF/O>FTֈJ*Xfgs%ʹ]W<h-@Db\ߐu"GnHȸ[*Ipo-|sw&0X`b+YqU^S?ȲgȭŦƷ<9yiUb[oઋ'oENyqA\{ёDAc+o%O[EQWxw<3Zy>:CNwF#ȣ82ȇyԫJJ𳴄P[DroM3r 'G;AJSfUOhć&^ZAvLdj{[MƷ<9L֓fm\en.'&+VyLV38棕w&nZܵZ[3n=8K\…vR=kS뫗:r>[|Ѻ-4&ў+Kaܿ(sHY@-#K_W?kU\(\ib}d,}}Na;c`g|.=ïQԺPZj,ܰ>wj+vV|-s+Wx%ы,OB`M,Ķ]YuKWRۺ U7-xԚ-Sc}E7r|1R@0׷}CMT<|˷;$0wݒگ]Ho;lC˼aXOkvh=٦yRu=nʤB~n:x&4x%fV=˶ ^G1ӯϽ޺.\aCg 5Buh-/| P73.}oȫTlaa]񢾯X궒LXԥ>~zuk" =%viӰڠ+:,Anw}}})|n~K/kKU"e1WT_!l69čo3V}G Gwk}\}~HnwIk6s=W_`b>u_cJ0\mko֯<9׋F%؀'zkS;<1VWx"i_r*vaslg׸7+CLJH^/LK. ;b+k'֒w&aJ^Kl^,o2So4k]'DέWv'?`Tu\TfI۹⡻&x_VHa_Aoεm.z~.b=bS`^ݍB8琛vv{ֻ]@v:_ F k<:wn=/PdMՖ%lq0"a} Ӿ%"?o Ro " |F )/V2oA?o^Q/Ԃzʏ,Pjɮy'E^yM1Z ]&u! ,+tB ߮x{e뉍p34j4J(FjvLI.i!D!-[xmJG׼W?\chZ s6Iyc%otИ bw>?sD_Q%S "#!'Qd')sZS[ɾVgLZhVefgY F9n[tv[m_˸|JgNa[okay ߸'2[ztMzZ0H<{0jMF<dqïOE;>᮲G_}~}^uَ+#|n' %bLQc;ƭYvfCcVZJKѕvyAtC"]x d [`Wܹ,:#G֮9Tٗ֜Z{֜(߹ܭbjuk䁸J1 Wg&9 s s#ܪ'LiKΗ=h4_.Êwf+A|J_>ThOߊ{*wn@ṍ>ڹ`\|hs&33JV_l7QwYy5|ʛq`"ƒ`w!) --rel\,}KImK;[m8ձEwq`PRC)2{sI6*{^tFCf=TbZkFhVuQn[r~q&gec enߗNYD^Q̅ktь";f, 6LӞ%kLա$oA/=m82cdL.拳^p%'Yތ3dƒ![W+jS{7rM&8]hTu[GȐK%Kw$2zWJU:;u[ގ#_!3ZJ}TF^8^g0Vr%a3Af,tz]h؉n=xae5`S'SV1cԆj|}yz?sFQ:RpsXgf3#by=uv.y:'k o/ю#ˁ_(zi,S4sO/u+uqPdnj%X|snU/(K\Ihn!&m,<@)h7p k,5xzwGWve8 aX[.4Н_N֙(0kݒ$oǑe 64O:d1e"-ڱzF3b-MXfa;Kem8 }OXBCnifsy2ʕwf&BdF-]+sj X,VD{[;zͱ nSE3̃TŰ ݛRfEC_vb8KRejQ,+X9$}qfɛq`@+vnwVr" B.M晼X*=KRVx]*ۋ`+&fbI.qQ&v^h'R"]d|؎|gXIYf#.Ա|f!譼qTN%|Ɣ++)`*|3_ hΩt8!K4!Y7174sL:d%ɲf8IOXk:ڳJN]7ZZ82jRoXYݴ~blVY?`IBZ X7Z7W=ؚHu.ǒ`YZ)4:zؒhZ|Xr>³3iojm8QzTO3X[x6{LJ$`ni]tqdR<6ʓk锯uFo82cI2&KVc&6' ]ItʤKǏ3\r'ڨ'@DZ־5wܲ=)ڹƊ, ntU]zMΔt%sOOy3Xy82VcIU-N%+(<#Nˢk/]SLx;EX*c#X/ ٮ̤˙q\zL5krGh7ꦁ5΍\f$XV`=eBBk/]\󏥒MezQC qLOގ#c?Aw鋉UgP8_sdRLky=iTPck+V$V$Ore9e;kKOcjVT.K;WG9rxqrxR.Js?#:u LBk/UX%ɲr8M97&c5Ηd|V ą޽.Fx?n}L{+UXx]K&KSq v+@pE68p:(t<*k-Q{Gdl$~򩪩DEeka ~he!.:ww-yqg+0gR \~;*)Ms+dU "n|~j/ԺmwԚGS^0 2^2-*Zevn9-ͮ&1JšO$\ӚLSNͭ'`ϖd -έ qЋ蜒jBKl.ي۩+577<`JjK~lI@5/@FZD39cStg+ݚZS۪ 9+d[F}I"JQre^X O M[O c ['u#}wmB֮WЖ)dd˚x p%euh.]QB5*0%X-ȓZx[1ʁ-еinTi\ Hn6Kي۰[j_=>5ajO\ ^ْ UN4Jؼv.;+?Y@围*'vܹ܏@a4E~6 ْ|KinAJ0pP~o0Y"Aptg+9t9][ZMٴ"iO SB#Y cT Շ+lˍz~6Y*Ɋ L=5P "8&i3O7K)d-,帆zaﭳxlJXwID7Q`b&Wht9m`) `ʕlCjŠ^CWi5#f(f%HgZyO76]nM,m=ַ:7 s)X0[̋Mf?[,^0GEց25 [XZr* \g7vP勴Vqy5=1W7`% ߣEv酩,H)rg+.CSKȯՁf^ee4&# wACk\j7I5!,.M'`ϖ[X t!afveNhHхNيY)2Puբd1fjHqňWe?g 3kV[. μ dDM]e@FU{BE5 <0wѴ nlmͪթYJZ(X3f5X_URɌg+@Yu%uFCg B1Ued9J^lɝwn$NE:-m`[Gq~$7x6NtW]QffS7u2O #ޟTHbْLYM:\tv g+0P|v{w 5BLY\6GG/ e`Vg+~{TaU2Qa6"wE7`%1>24ewI0Ν)M#Ο-X񗋈0ix`-U?{󰘑4Z#i)ȁxQ($E`KyȈg+8E'\aEa*lp gK 'ÂFN Ot9nql_MhB3f-p!EO #Ο-'ʀd.jra"jʅPfV`aF'yh*Նf"" ujrE?@$;*bEPKIrcO?g?H$;2uy]=ixb08Q\BYtI*4[>? T%XUKh+:b'd^l0# ,Lj7ϊ`P}ZRt5E7@;jj,ؒ<<0LYM0ԝ_*&3ԟCSWEA]lT."w ɼ d%Y[]{e0 SiVKnuӔNlIuH܂ƎJ.j@lce?[qE麘慦 gҬs=4@F?[9/ *'Ty>&fV`bn\LBG^0WP3fnYM;[wk^kw7F4%'FB&pV\aXai<*9}733ic/~d/8iѣPtIDgfҬgKy \%1|=R_[P& gFXA}yxIPW ?ECL;—&Pϖ`bVOr;^/ͫj_jȖy \|f+0UT,Z83fme@̋'gKs45*eC4%'FOM%`VX˴W]Ԋaf2͢v <*ْKFuTnִ~alIv>W .)4>"cSvQŀ:X9R/1=JG E49#_.5uct7?*{, >ցLZsgֻ|CC^6l%abگ]ZH`άD iE%`ϖX!.{j>r6 ܙbuf (&3Ksn,y#ܙ兑`{ d%p}򱸉W4L;0ʝY놏&pV܉14e$%.sgV*?2DN6lI-<.*%C_1̊nl (znebV]܎)sfc˭+)\E#h*jriVv16ьI*blte4br,ìębԅ2يꢧXҴԙƏql,m zpF+<=]_UQg+Qbwq;1_9ng-ivP ~|eo(>F*a eG0Ҿ/- 8_iÓ*iZ ƣB8sИN*}+v C-տPO!ˑ/{)ҳBCo<&ۭW6|M<N~c0zxGyi0FQz .% d/ +7Sj{:b>U[Jjl?TNjTKGR96nZN׷B{M_1'ū̗ T{ws+ ի* ~sRb3] 9n8lo`͚fwB܏_/G~7OCjڈD&T8vѳrR~<2?#Pi .$pR?Vq{z X$fKwV-.?j}g?7z4~@j*_Hot'&?` ġϮqw!h^كْ{E 4\tۮF+2y0[q0q4P[U>R؋F`{nAj4q&?b1. l2sa%R۩F4T D/Pܝɿobc57lfnzIrVM:&3w0[!`5 &/Bm0ES+ \f+.wn%,xZo)6өǏG2q0[rѽy!a2F/lŵ5n \rkы~ْS \>C 75l2=Y/\VSK"q0[QGށ YVnS3nf8-ʡ"‡_P[!q5ԋ@ƚ~${&:ʉǮP GaU~Ƀي|܇TNս{hatQ/~6يJ# \kfIyq3b3\- \fkп.u~C(%@^#"QMYQRMϪ6g[v{\#H^% XfKK@zV\MC'䜭Ȧm,@r)VaQ(v8yp1[/w7u_m_:t V\ϕ{/h :a C+ ddf+)ſNeW[ b ~6Yْ=֔p][t-R&E-AKv҄6}>/ߒa?  g~6يޚ\.}~"]E*et sԾ5njCE?b"w. -@~s}Q> pecW-؝A=TX n ,a[3 a[ tvsqkL,̖du JK18 \f+.@fo.){DnK"0[JES$&Ei* rhbٽQF^l03 ݓD֊!E:D7lw Iԫ7N|nו ~6ox yUZT[l.xz LdfKmj^]IbXGw%pW7΋%V.Y#?lEf\*o[Ӌ1c_K"0[b{C i=}j qr?z.6(9\4}*~t{~ϖd|RKO`c~qg+:5 ( .]! B=5Mf?[!i1^qlUfn/Zp\5\an 'ϖdUPiQN0v]z8S+xXWvFۖ .k[pk7 dD%4%\ 63Pz/~6lEVu!f'%\no/0.8BHdv^paʥvs?" UWσ4hi׳3e?[qr pli@vp'ϖdޭ6K p[/}QxɌg+zxr)VDФo5F?[K [VdZwAPQg+`laZm$wn*~6alIf%+9}wyK"mz%Rv-)-q$Mf?[ qn-pCVdP[O WGjzE?$S5 'Ѕ{mN n𲱌g+,'qWI:԰8άVͬ#PϖTm.w M2[qES+d7RԼVС.b*b޵C Bx[l"}^')˜Hl387xqF.EN!V. w/n!l VfVif]L[+x X%{ߓf=a0NMfsV-=)(7U9Wj&V`?d 5Ͻe7A@G7`;U5A=$Ő$/B)RDjͽgvAY.i2F7@{ߤx9 Bte:д n6qlm;ύ`nN_ #K"̟qCk2_y`NߚiM9?0"UgRGT&XoL0QjDCI#4GZs\* X<YݓK#)[wⓍ9$/8z7a\/0\1x \WzMj.7xhX$t)E?0$2JnTw'Ū2426Y=(]v~s2 E1f6yxe^`8=Ax\%w $u zLW8g~lIVP pV r_xFky+C5BC9 wǃ;^* m@(dFԃ٪Fn4@F?[cA$Nkԗ=hrlE;ы䑓6"{gKz8O.BdFك9il6a-'5N82-yV`y&Erg+2;H9 Q`j;P2Q g+|IRI` 眾Wi¹7@F?[rHaM*Jkv\d6ד&)'G%55c%esV{w G v OOC0N~E?"ǝiCcP۴Mf?[]bvPfc<RXncc'w:vk\!i^,Bْ[P `nsw+v7\7|塲kv.ᗗu_0B|_.%wX@fe?[qٽaIjaaG g<4E?[bcWNvk[Hb%'# ͝8Jmv{4ʟ&3-ê$+2Qp'V$n)T?5L2-\Դ nPbQ'Nq[K#<[qջ"IhhZ nW2ي8{WyqgKp;)a.\GCpK/ c-ugzJeuwJv_M'`ϖdpBt烩Pc`="&Yf?lEf&$ ѝְ//¼$2%|) ztaEQ6NܚXɆ2м;l}~w%p}#AN"1pvq?zWotxfK0$d$Vw"ذ{\*Nr8Ҭn6lVDt[NS $>ƀu~lI(h+,0yC0Cۦ0_ĂhNv\j mNF?$Mh|ab <@S+P?ŵtDTisQ{{7{f֤6;uSMa@F?[A@/u' Bc04[]4N$. ԝE ~hV7o5eD+64 Vtgk;`!(] x>4O # \w-gR(w؍`K?${&O0Gմg n6K>Uװ'Q~iNu3ܟM&h:} û0]e6NB1C7Sǁ4e?[bwťs'bиj~lE= `ܯaKS5eYIo7HΝ0@sR!n6l .W߼!< nl;z?)cNm8åjjE78eFӿPӅͭ'1<Ԏ{7U>NRx<&Uׂ~6ѐ,W3ʟԕݦ{[+ d%; qi72ϣP4Mf?[é5:5F .[F> `%8v`(.i ,I89lf`A.l2يl.cْީ!:꺽hvw~^<V4!Vwl]+] : T< %x^;k!}28W ў-dT}G\F|7F&pָy1idE*cpzygVd^q)dEnPE֪)ӹE@F?[}C̅`a We{<AE?[qt{).~uxzXݞ%:vTil疶=/naln;ٍr.+i nxFع-ίy!pM'`ϖd[\0:x*7}J5 \%7 vVb?J!Pi0 ; ZR*"Sia 3b{&#; `iI*4?-LecQޥ$Y:~]]Rͽf-a' q>ΦU)k{V?ݦO #- 'ui.O:)Mr&s [N"3 'Lm瘏M#-.NMɬ[꾒iE?[qN"wSHR525AU1d.dKW5Cj,כ1xz X.rŕ(h!,*&s [ >ͩ+e< +AMcUCЁBז45vo TdR^rRhEjWo.6l~A;$~-$Yhrpg+)]Δg黱4l2ْ\ 7΅=ܚX$0V̶Zn{z+4WN6AhTI틧R?a/~qlE;W=I_uiF.8Ҭ~ْ=~V .pc?qzYي9f)]Wh}K"ʟ'R=_13ո<5>,ʟ-^ ]nZ+r f%Ք?4e?[bw]SkΔ%onɦ!Vg+򽓼ynDs4&Z[֍q ql2يzy@ᜉ`N$ 1lI\W5(Tͮ'VdorI`aVs^l2#يޥkeU ^/G.7^/[y\Vݮ|-?lt~}zzok$/!/Bc:Id6?yxT+l,U# l/:r͌bA!kmQӮuB7n~'7ca}p~Rl[USʩ3NѪo?i >GC}OL?[ ^Sڄ1y\_>8p~iN4qp~ uq4~RK_ 7Î ϼluZj>2Ywe쭦9 }/8һ]:7UhO][7l\$6z Y/Tn"R-^ESҩ ]$'DpVtSUUՉqWr{Jo3Y+4tW+nQr^j/]V wh Tla~R+x\7.v>Ķ}֑wa1:IT`/Nש5SVֿ_Lb~|ZitѬ>!m;˰}K_v sp^6Zƿon*[/Ja|ަ._v-څB*]=1Dom(>rOֵp2Izu+ gyH`iG,QWqiw^>ը}~ -cUOLG+L{]U "+а'r^3^w!EÃ^<ɻ>!֝O? ~I{΢nvP_SET kɨҌ޷B]Q<BGtĿf=to?o_^=YYP,T5+Md=l2aΪجM^oH04nYt_MgUk\GO"?\k~ BS엽?-RבiS(_nM>qf{} z\f>e+w;]ü7zct~kْl,St#.[8h}\}ONBF-d) wU..KPFpD}*!7Ƀ`ْl)a{Y:\FSEVV: n` A걽ʬ#,B,e؆qΡH&WbwOrͲe ݯĮ@fO?pb+d/\lG`;Ϧ3 mNk8%0RͲ%^/,P0@3a5@3&G{YtLR5V2dٲeEeqn^fFq ?:GD#8pb㏎o9:x_ښ\dec&-ƴ(C>-\̸#okBPُN}U-{YGX5Vtjo yC:fѰWB|fLNcW&6upCrxV\͒}+.v6J܋Mf^$ρW%7t5)KgRQtΣT3:RrێInH`|,݄5,&zbĢ> Bb엽,Tƴկh˸Աg Tۅ-s}a/k_7ʎiynv~9T9nkrV*ΣDF?'ޓ&秭K HZ+&f-Mя /F߃l}QVqkYʷ$ /҅W`u 1[Kw`dŋL@RtK[]xYߤSra,WBQԋ~6ْl):sۗ+6{bOQO> f|ꓽƜHzC uAkRtel%Lj7J>*%^~fs-a uZ<:{np5$M@7ʛimfWԩ%t ٲSBpS@D-o~?lEH*YK,FQ(:t k;x\CgKn=^fV}urN7x '^F> :rꚘ ?FhS4 "t씽j$^ej%`ْ.pt\Ζ`›Z$).(<{)Cw'Vdq<1jgC딢YPp&hfu5'Λo@g?_XΖ \IN@=ݪAukp\7W'9]КR0ÛMc8[ueq|\[A~ A]rr7Ept+:L-k9}s+ n<0/kaeeugu+vxg;^ْ+ʭ3˴nφP7y XmVL~]E4\B外>'D{;I@b{wyl_,ۋXtNCf[rDՍu hկ&p -S;۲ڭt/I| g?ElE枪Ƹm5,'q5?TrjW#} "knO7[\ΖVի>1m@?%|Nnkي+ _o{YG)~˛7gj-xruK:+`֔vz܄8l{"Z۪ǥ" h{4l*aGi1CrA_,5rwÚk嘡bOu_}g&q%z}5lٯq|񓮶Vʣ/~kيlKItܹ9ՀmgVMt$3N1ܔ.G7\/, (6QΜ޶tA/{N[h3"-5&]Ln7ْu BIRjF7El _;0ԝfm%=n]֑[3ۋt3Mel/U[:"GjWnTt\Vaz+tٱtsKMKrvXΖ`aSvU%"<%)ptNu)@ kAn%&O֣eFy;,v'~ @U+JkE墻r5:[r\!îb2[9Zɻg:X,VXYQU\?YY`\ܢXn?՞g։  ͗\-yٽL4֥j/+@J#uJ̪/n"%+6^4Hu2q/H: dgKs|_rm*/ n/nIj ~QF2͗$/Nv-;uWȍSroaZ2޵/~Kْ\fp^U=0=|lrwVzYq I8qB/Vl _O]'_~I*tUyvFp[epP틛*t#qTu` _ą 8`gK0SȰLg' c6Pu/q.3ߧ[V֑Rcy\V\ޕN4Ŭ#[B:jc ^X. ԭz}V#zTJ ^a):[v q貰~uH|mέ.R ~q\ΖZP3f"ص3ǩzCqRzrX.V\˨V˅qٔG?LK7j~Sf8i1FgˎDu-U)O۟[Ee ⧗btNvc)!2(.ox`<Þ2V%yT^dݱrK(]`& gҒ !xJHړEq.O7[\Ζݚ qI*"iOd?[FbF5ؑ-Ɋ\s TG?lEƵWV¼$[ҥ>i yYHHZ\_>q-:[JZ,ru BRx$'?.ߔ-Zs+m/^61ho|I^ v`,oĹU7ޓΊT:ҕCK!KX2ۋ'Dgn}$cٜ QIMWnql *yU,뭵8w' hmv_`@~AVU-[7|@fի-KK_0֢%8o6Nw^? r/nln^ QBͰ/WזRN8YPt}(^ZfTt;Ņl٩1 K)ʒ/n+<]mX0;]D V^l0x`.⣣+Io]G ڷ^Vgp^%PlR\VAG?ckz w#:Qg\I)o^ZZjd䣗JtۨQ}.TV:&l\)ΖܫkK V༴'EAh Ybs[AqU|aKeh._ SVҷZRխg -ܵHf!7v^ZL"3. d{GFX*CBSnmzi-: ^{Zo'SZЃun) }S0 CˢInZ&j &s!:[˯U]PVI.u?ʣjq $g.InAp(C} %|:t)OKinv-4nq题UMlzVKMc!:[Yj&x[;'[7w`8[] z \,gK%_[\{/W[Cj,P~K0_CKs9[ opNb1 e8<&!Ԏnv-{1S:E>)s*\DgKc:P4NvVRKݍN6KnU ~Ft1> Zw]O8um.Ϭ B8Km/~37עeǺ-y`A(lqTڍAl.%wզwh9Nr]-EB\V1s75ȧfk.Ik zN<1_^ը8-VW%,Dg.MVUGѤ .ægul8b\H,,6FmC rR[ml2%.a!:[8g)q ݘL-+d-)D?M"wicz< ppp5_\*Ζv[C}Kq[C}-nAK7DHd 2z\R~B-5ʮkZ.F5W5adƭ} 7rnXVdʅ.=F8%8T)ms\/ΖdP<'U *&i-ȭ>N.en\^k~T/UEO~]k$P ՒZMˆ6Le?lI>YjK]].jAn)`@)UQh{Nlт r!Σ*XU0y_4T),Gg~,dUU`vj=n>իes@mrhIz%p^-NA\:e ΚV&q·p녳vWu8%׭nFuĀC~ޗ)myYf-@s}L52GT5j{74Qÿh_5F4Am0!^n9޻[;%WRSy+7BGVG&/P7˲b׍;Пqpֻ2߿ZqQ(} nz58OAf2*j%k_^~W {~*E!E\.o[X~ԻLbYl:ij׻ձ(E,˟(3wi\A!ђ7uG-ʌ!Œ_.WMy\?Ed)q}$Wb/\'Vr_|}4McQ02s@|D50H)o+gIǍMTtLr{zڦ GK^+gED!77K=V~T\̔O1V~\rYbr̺|/-yX?K.f Jy4MsQ1sHfAi OA dɹ"Eܿ$As^GY!eY k˛:ra_.jƦ Y0b$w: ԏڂk`VV x3Ȃˁu%%їFiS? _ n ivr>\fH 4:Rť:-oџFnO}ou< ؖ!VS`|!ђ7uGH>R5䥩~V{='Ǡ2̻inΡέxP~ nY X+RhʛYv'}%)/my^?J=8 _c<#Wі7u[ _~R{pHlɛ֊Q.QH.Ƃq];^ZOp,_~{@=xÆܐ7mu'i'Hlyiʛ:xۃws{E(\u딚-oOjxkS[^l{ymGC4ֱD%)gi?) ~bcCN6Bb:'j-5MSI,bpyg(L2_Q#dq{f^>˓=84;!2S_rk˛:>Y%E \'9.{dngr7#ObX;Z=(Ʉ9nlnWyӒ7u'ᩈV`-86&TztAI޿%x <|S9my^'҆ @>Ɠ\ڃg?jC=z c#NzFš){{w]'i՛cCEoěr2Vڻ޿c?7=(^X[K%oKgq2~i~ՔMNu'yAAV-oー҃C2s3-o+GSEÖdeS{I!`Y)o+G \@LMyqoU PVM6O(Q[qaPd໽iɛ QD_4/\uRs'[}ה7Ѓ2ҷa%3wmy^'Uױ{'䆫UJuk˛Q!ƥц.>ݣ)oOj<2-σBcN)>4M[[?h<(bbտiɛ:XNydM(\qeh+%wŲi?)<8$_K8uNEŗiUm"ı/X'`?<)n\<<ߵ09̓CrO5Ms(=\pmh*!O3<~px3/^6+ <5іf .QM{I!BQ&7bՌxM{IRvGU{q շMy\y`Fł>s)ܔ7߂T? .VK}iʛ:ǃCٞJRߵM{E?sd (J"-"\>*khkk}/`Z&~\񦭎k}ה7c23 Myqe8<GX0f=M \?`E>ؔT?wșs?bcf , <=nvY4Mcp~ w9n)nSG`9xwcfDX8!EQpW}ה7u`Ur?lJ7}<4sp-Z-m`Kۯ\85MS|Ɛ{AB`PXlp}X~U907uw-yZ>Q?Ol  2L cT !F Ni]S4ɟ*ć_Pɳ>ɭ?gCBzAx\*16ȌHcQpT>-ym OU3Jyԩ_^%u . W@jɛ  TA[cf`qݴciɛ AjR18Xg񦭎T ~[UHzXxV~LMR4џdes{EX};\Orn^Cnq݌V5䵭2ƟXkz;6 F46r^xe+l, zCKތ gKpLEZ5KfscK޴g+p<~|Ӕ7l?)J~d9p@2W%.=NF?[#dזi3'w+wH43lu ~lM@K0>TA@&KK5i:/xP"_g+p| \ҝ㲏%|kʛ~$GTӾk{>NFh?&/h7i]=>v6\-?MI;V1zb9{{׎7mu*b-u2lbNי⴯؍85\&YFzӊ7 u0 0^~dSsEfpQHMO*rjV*j'9Ut|ז7lN.%9rHư->Msƻ]4n. AԌז:lX 1jOlz31qUHMOb ܞXϖ!E/0{Ӕ7u2\g?_W_D~Y9׻ϕM_Gߏs?WxZZ-Z5~ |xZL׏u?~/mo YEzב/V\ڪQ14K32;Ÿ_kS\Ȃe뗵+i"!UsupdmL^~=EjZϲ2Z믿?gǁ/(#6GV.}`)j6u{7_6mnНsw=t:ݪ a8WV,ڐvYc̴ꃧ][I>m%kz6/3*9L6ЧZIڠ9K&}>i JikiIt}8> |*\o~*k}Gw}ŭ9;jLEu~~YV.rЯn)+aYaܾ-ؿȚ>cIz3qVHgȘ>=ߜ@H/\j)Z$Y}iŰ:{ud\$ԕˎ~bUt1~πQm/ױhm_vKxr{fv㮅ZtWSuOwN /ƫssnuu E|YG&=,3חc=8[?/BcWR,/F>U/W5^׾!}_׏a׊Sv'8m (b)%Lh{d Gp$^ -_oaM^c={ j9X y񲸧\Gձ|^6~:kG o _Z";z"H"ۯ9yY[Te W+kk&ۑ@9LVtq<ٙGG~2J:u< 5r[ \*p\FJCy`I`UG?/+2R!xrA>D~^ɪ%"<,S'y$@~ŸWv$0kX(i/y׎.ˢ&)p{O+<~^i2x#_p7`U/Vi@?O^IdU"G?o,ݡz 6W܇z#"G~g"qye d*WjDryW<\MF/eDwbdBv$W!X"Xcq$H W$8Y ;GrlG~+R]N& WyHWRJ$B~\$H"ۯ9Lf4y9=ǃij2׎.~KYM^?@lsiF.$*!3.L|H WU&k~No.# \˃[=%0 dw|r[iI\UG?/U׳$Mo<ԫOj d*W wq>IDU"F?o^fyg8"G 5uYǢ x\\MF/erzۑ@9y͙S%%̯_3? #G~+ً0w~y=_y p^vҰm#lJ YUD+3==6&W(/ P$xzz,H"ۯ9yCf"%[ 09frґD3YI늎EY@9y%Q$r=v$|pۡf* 9^Tvڑ70w _KcDN%IdU"G?d\v<xyM^HsBG~K-'4c>_n󉫭 ߷3=FTmK_uV9~Ǻ["zn2V*h#@BLRvن~0,ܾ~q]IJ}*,_bmX풵1,/uǪ`Cm?v-7ť~/ķzZH=t_isbqäbV/AYE?;W}#zsVx] PDw2v?bo>te\@jnzV1 ҹԵ5 '׭po4}z]ӵsÈyj?VH+g9n+ðd RԞmo?vGZ\53kh(*?u u_\ ?YE%lukznwWт; _.Q,{#b4vk9{l\D#/VսOXٔO/pfIfѸyUn3_\ɼ]xhFuwXu5o WtaKnox_\Ҵz;Я=:K٩vC7_f7,;;&oއk#A# 'g?Y8aJv_閟^_z-`U6\oBL?VӘw}3 ŨE?%xk#ur1w$|V|_zz}4L:`ʤ%6/?\|{^s껨]9jz0]mβn9uT}}WNN9*\OW뷩( vdO,ys(g&ǡ]{Ւ#uBY>T?Gx9Rxdχ>C9~o&ZBבiW]׿ȿY0%ȌG,iϾ [ t'Rhjw+_xE8+U, f^~ke~k:b/Tz7Fs7G܁!o\lHҿXX3x߁#lxs/~g-w18-Ki'~Jkdyt37nj/m97u+Oqa×&O=gVė kEۍ` "J~5e%2պө}\k $$K=u3gwq!pӷ,)2V9V%,sJ@$SFªQubޭ':VV>WnS6z6u7>3^[z׿}>ke{j+52qMd[O2j )PFC+ho2ےJ>Hʒ^bgcBB7U~/]1b&Z;=z+ 4ۛ) [cg&s"[i&zD#(j$w<'1+j/쉻)*#X;n~Vͬ&PQT,۴^:v(Qm܎n|>t9X%fsYS,[q;7P|A.Ɵj7Kb@Lq5h:y')hT5y`fg+0Vԍ3iScI~ْcn֐ wȘ\(Vdrao*?N.vw1pL̖`ͮ{-r֔2rO?lIvN;%e`ƛPC+\&e+.1ЖIJ :(v(kx5`Q%p,Htx`Q؎ M'ⴓ%@qqM|6rPH&3$[u|Hsqgf[gL5^يKJKC  xyoH7LGܺvI>{4EqluJ׼!IjP00A&L]HcmT&H>t)MO!bْi)kJ`!n(-2Z/%>).r'LOh n6Ųx`c 1N[>^!|[nM'Q_,[&vԛs]-k1VWWӁP|n6Ʋx"/LkkhvYn'GO hM럟'_SS0PIiK>,eKnK{Wybϥk;6>έ)?l0wf+pe+lUu5U0lM 2hl}a(rE4D>/ي;0D* #]O]ME;fVh?sDCj1>JxF$@a~WCfVxf+$5:# #Cg8d̖dK_8t5Y@eOMSS1]g8z \lx̖\]-J̲x0csk 䆮f0[hH)+5捡.](>O ca$[jn 3-M>5| vgؾrWlsbi6 vKr܅[irY@e%7NZX.תޅxVX +v5,$~."K:b|^g 9w82:1'ߧqc/?flWrq'ƹ#Z|8v`Ozg7]a 0.ͫeSVTnd]^7rC7wWgݕZ:=Y)tX[qH/P~lEzh? s[,#jWCq\"?̐Ɋd·NyƔcη&pV\&B'ͣҘKu'9yX%,-j"aNcؐvΖ`VRNMCWR׽ˣ)M"ܟyl5WfVcEgSfV gKra[d]MWSSJ켞m麚@F?[3)pC"<4:s?r" ꨤ(XG87wz+nm̎nlLuoc{f(gQK&VpV[1}j^YĞsxУ!SRhZjЅa%= HʛΛrkVE?h"7PV7YkrXY9HgfMlKռ~lI`m,lbJؔ̚l.ي1F,a21'gY2tnl % ~lIn6lLw ?K\ք4]MO [)W( @SS>ѽGԐO"ڟ-Z@ ȧySkv[,o&3ܟ C!EPUpkB[0l1\98:x?2*z\ֽ+lɥO +G4Zj7˝J )7OI;Gdamc+ź϶ gϖdQYZsKL'zԚݖ2"٪XɁQꧮ't">ք/Vl2Cي\1JjzY *z0Z<& 0"lA++")kfh [e)J-Wtg+07V|X:ƺ)f72g^l2CْY۠*{:f+Yg[g+(] t,,衲kB[Nsx͋XZSR2t=E7sukri3SwkɋF?[1cᔵ7~6krE?̠c+P! #8\=Tͣ-/~alEn9]+e"ë϶ _eϑbK~]Vf^iٔ0l1iQfЌj"z{^ͣ-/~lUA`OYL]D2h<5eD:[q64K@ EjBCG/ JqVفޕ@xiK~6lE/;u#ַ`AXOͮ'1۸s4:vu]+]-̊nl^JS\;քtMgϖd!B?vrWoAٖsgpFI87jBC.MdCVІ:&>>o*vjgCצnl hEE^͓J<'V jb}O[5vSCa f?[;T+җ7uGy5;-Xx d,d+ b}jI샞eLWfs-'6D\jT*Poa ϖ\ZMk`Y–Uyܚ\~!mO c [+b)%w ͮZ(4lu|~6KْlJMU׳Ex-l5%pctee᳊ΡMޗ4߈fT N 8_fRRK[ۅ7%l˹,DA3lotM%`M-jV6n>4P1bҊbԥ8p [l3XTJj$<0I}*'Ʒ6M18N(Q$ecX=5}\CՒbMS$Y-:ԑ- 0YtY͟rat˥9ٕf]*$ZsA#?`=Ȓ d-NӄU`_CTf? df$+D9\;/X&9TҾOͮf,R@aS-dcZ`E6XO S"YQq/VV<0ʯ>,~0X?h* wl!$++nC95x>P%p)O (EP3\ ưrӓk# O"蟭Ȭ܊fKhX|#D̋Mf?[!TI [ cs8_c֔0b <1H]C'xN u?5U۟HyxT%C,`ukŭf2kVb1ƹM&ϖ`(斅Vb&fJGS.&VZE*2kVV4F +d%e{s+BH|h]21ؕO #蟭f 4{cu. NJt gk܊0_)||ZI`֗(f5O ;[Yw1u&Ԛi3 rgK.{N,Ěi{!w!6xXF%DRT^oV%FE4jVR@ '7v PӄҪ~kbiv{ X| fK:SkA$V4HԴ^{1䟭(ZM+ȇ{f%׬HCQpgKX `Զgί(-Tͪ'ϖd -Nj*bP~Q[̋Mf?[kBJtfR0L5+tE?[b!rWX,td) ę7̈w*JpHn"EH!v ̚gQW,+lI3O7ܜ,zS#~ibE?̈$[p[D#7 CxЎ-ܚjZ̋@F?[#jm tWhg^M7`cDĆѮ )Ri5Vl({ \HCgtbۥ9UL3^Jvxe+08EB)5 l"2O7PZ?Y ͟RkWJ: dy`Yeq]#*|@Žl7Pߨ.ZIe9ZʨY+/K"ҟ#twM-(zŝ骹f+!0"l!bH |i8NMfu[N`ܚ[ŜY"0f\2"ي,r0LaikgV ZXtr/Pͬqc-WM"ҟ-aOMuwv 43j:J܊nlhn ܰ@zh&c}98`F%1MWT`ܧ_sjfE/X2, !*`SQȇgi~FzM[)Fʏ_5I<[gJGhW]f`,Frd^08`:R9NnS)2ڟ-T1סl2يL85,~KRnqoMQ1ؖ(&ϖ`$[H85\uXU+ \WCqGAWtپxri,J=ђ)`F%1CT[KcJC`~d7` skrYh5) 5si$ڂ-?p$;r rƹ. 6ilYݻfWȁ3nh<+.ЁЎU:y XDc zFotՁb2ܟ-Na +.@3f90Ж-'Vdq 9"H*U 55)g7HG4qX0+WeH1saQ'`Vru8H* rH3Ɩ1Vn옦e]f¢U]oͼxq:E3I*f'ZrYM"⟭ČKILJ_1̬} yb~lIvέ.WlUsoQb:b7̀34,ZH70jNzAM"-,ڜ$ZWc6K+dYO[b ]f^[,:KZH)BheaNofԬ.g+բe]%C'raQӡh-)Mk]4V64]KHQ]NtՐ ,bْXM, 0LY܁q K^lEBI9 2/2ilFi:/pZjQfPDr A^lE;);&(*UlF4%\M:b[gQPW(mOJcwK0$ĊAg_x{uڑ||,rǻ=e̿+:o߫hڟ8,^!Ύn5Ե#WɆ{+<߄1ՄJ߹f[ lSer>C}j%0)O|]Wj-Τ4 1ZOڻBb#?N0ԍN DA[\z"o/i/^BF8fݯ#_M=cٺS +hCO_j!hoY8ǚ~:Fn5<^ϺW~7X^&Ks/5͑1Dl[ *hg~=j Lryg|>ܛ;\Y :´Fqsp%tt[y9ˑou ? _?/7y}rx~7z.^87z *E/FL_{peWJmo8?Uc`)K^4p'6XbnzKѵsK>rQi1iw =4Or|\>?#Pڗ _1GZ+ŷ?p% {z,xOQ{ h{;wp*TÑf.n9!:,v=/Y|~>=6*-2F-`;`$VIFl®Tޣb{<j_jgV-hp~^l٣Un}eA>;~t$RL&fkX: Dp#"un$ToK"w0[qջ*Zb)W~e?lI6++_CCb<F/qVXu:w)dv0w0rsr1h]$ JItL̖XSZs1S[Zմum*oed%M>2%Y+emHC04Me`41ؚT.zh^Lp'1$He5зE*ًE`${\t3$MyAԊ~6ي<Mm2O2$vi0Uk{ T fKnaa. ?tmh/N69 ΕK M~0JEdyz@MZXH̖dZúUnުx=*zM#k0[rRjO,(:M'&3m0[š~RZ4!(..[_jůbuAdd~3g5-*֗ZqCЪJ$Z;Li^ M-Sᲊ[TU4,0%T*\'%v,g6K% zK"2'6:pUbTޮ%GAY^&#["a NNq"ӵ}Vz94x Pd fKwnHBt\~a|vh0֕ƙ9]4ʳ'uC0\,qbc Ul.ss'8-A)b'wm=PRHVeRA+2I-h7rYW< ^6yْ]&5I\{^.Wk\&G^ ?( yzJx fKUb {XUTEn6ɃݻY8x^M,G2@ڹNȴ$/%ͬg8dff+z((M5 "Hnكْ 9w5⾸<q^F`S%)F&i#bxQUF^l25 e]amxދ^#Bu'@ g<Ăj wE/P\U.dEC)n4˶:X8E`sysy{8ߵFa_8. c{+R~6IيR[IC[%MT \)R4Fa{])?^\ŐjQ_OzzH$FoyjJE?NgKjjNA,m~ג[.`A8nO #K11J\o`y݆0Sl.ي;qFΩ)Q9xDx 80" "{M7U!O7z&T:J:b8%Mf?[;[VҶo;wAWxȈg+zuPF<v}ċ f?[Uȃ^d=+ 1]McHbv;F/z\jv]SYz&3 g.zς>*֬Md1C+z \D%wK!~;do…cM@"EZET Id`/ƕL`:BEOZc;ƀ[@F?[?V.9ʲ{M#⟭ ~B~o'y͹q .ͬgVdY Oi+DV^1ĊNHѐ ()B7Vvh7J{F? $K3Uk' (Bub0<'c.Xe?[qN"x̯{zjd~>g{ d+b]sn{jn-q-ݼeSϖTݐvvyW"V3@G7 FԺHL*m3G_,bْYPY_,NYvC\%~61lEV0$wW"9 ̊~QlE0$w4 sew5.l.cْcZ$=Bv- ܊nAl #x˭[ގƠ2b''#ȟegu ͝p uaMl2#ي|.7wW.Fr'ϖdHu$9`stMf?[U*iAr'5FwE8ǡ2%{X5 gqWJ{ڛO #֟ laP` /K2`%H6;IBYy-(^wA[~!lEV&xhPf9 tMg숆q.`޹u-b7|!hR~qlEVbp'e%+α D/l]W;pF&Gpa?[N"a54v#]W7/~ql:xKBr;Fj[4v\rO #mF!p||D f?[N;>vW9nl >& )JkaoUecϖ;rgNC@.#P$ߗGTFۅ@E]Xl^w[|Hnlŝ; `+TTdqn)W3-4(n kQcpK30 dD,/s"Xbyӯ-;1(R ^6lMX:tٯ-[3+ d{F ^v೪ҡNy8$ ̖TS Z:W`εse?[q9WlSQXP*0gɤF?[M5PtkgW{ +8dVW:o3Uř^qlu]:>~&0 \v9`pxBc^l2ْI5$u>yߧfWg+z,9 yRs&WpxFЁSS Q Xfʻ~.b\"k%[C`g]uힸ:?5@F?[#Α:rWǕY'S ʅld-qB)ِruz o=qQ ~lEV^oH4/G ;R9F~v3䟭d*Wy;\f!y X%ֻwk.,tj(g0]io_l.يUM'SuEWï%暹O #-ɦ۶kCWǝrI{3 QOO #䟭"y0+, Rs&W g+i] * (}fo3ϖ `ץU|(knDߤk2-&AҾXySU*L l0Y}㣫nRyE?[j;մ%٭US*d%Y=dU{F?[O$/%}aTMdSϖTuNR K+&} qnua K"Οs]C`SxKZy8$ks ܝ5pܪa\=`XYw}RYvSF?[տD } \..F`G/6Eni_Njy!` d|egk? ao_Q<: PTۄgS+N.iWg7~*zϜ5pB Cm0 5'/lMJa XfψFԐ}0STa$dEp?[ӹnpB,@7N体ŗ_z\pϟir|#05_g+.8*8p[ӏ!xqg+ ]Ny.{'ϖd`E\o$(kB?|@ApgV)]5qk r.Bْ+\}J-vOG/~s%_8 Ad EC,D,Dwsk",ي.qD#wkrA:K(* kJyF?[)EdRe nInF70C:)^LNG>&6gG&[v;qugKK! lB]ipnxϋF؆s19lLG}F: T%{74ʍoJKs+z \7tܖ&o=0*&ϖdV# d:{J8qhoȈg+z5ED!w-Xr~?OSJsZ|c 8f?N;VHnЙbWG;l{.-'ϖd >:'++gVdP:RrS a t NAlE; qĤ/i%=p&ϖ`nm7J0k9IPSe?[r{MSkLf;V,g=ߍ@F?[o蝨GXI9_RST NMgVdHX8rjh;h `q0zDsb}J޻pO X|.ST6khjE/ "֞$WPvg+n]w_f}-.%!En6l >ϝ0T<֋]ƠI: d9td^M lc*T >|\H>d.d+q11kqI0=dzˌW`WG;qw\#pkvE?`G4ĢkmCU :g+浓@5%AE=,t@`"w#̯E)5i/Ӌ8f?N>ϖdt} y2vp?""ӂh!k;N55.LziZ/znN_k_Wvg\CBtg+:75Rۊ-W_ZM#-ĉa ǹS&Zfy33S)G[\MgVA|0l-sca('[0)aDS&>cvSr' V1Xqa|F`Rm}>l.ْ!԰̔!& ~dd}(B zM)LPn~GgVd|]߳[DXon3!;לz3 JQ`n?7>*~ 3ȝTaX?yG8Il,C\Bs\qx3.[m|8 XVUJąYwgϖryN9`kwk$8]*x Xci-<lQLu 4M%pϖ\]Ѽj2 lmas^l0 pfXq{28Õц 75Ms+ d%9t~3 UƠjfasшbyoVM"ğ-&.M>NuvG\GvM#Ɵw`"7pX1A$2cي&+A ?j=ҹ2 J7 0la;c$Nm6/XfOeG,6ٮÏXFJξek/oʃ;wYuk|_.=c>,b\H;Jۃ] ~0[>+OqZOlm0XVG~V (otp9'BlgJk&=VA6i1pW8^zeYQ?r?GU/e5Q9|uRVƗ;'g BaiUVfa7KYJ.rW~fu>ʎ4Q-wrfCy$lL4H;'ƺM5#uLv\0 ZUL} 0wDKˡ&ɮv e~u~Yͣ[ >ktB9څ 'qE(vme쉰\Y~Rq22i\O֪F[Sg8>+*iGmZ߷ g ./~/?6o~Z_Fy<72Gp81ui`S>KVby\Ϻi|.aw邧tcfyr*=WaY>B៸e'/̿vxޭխ^WyX !x]FП؝'Hw2B@A% 5 xkOS7]N6)_{:OY{?f= Gɯe=no?ίyMy{Ջ*7X\:Kto듹*ْ{w5aAr:j=wY7/So^SYUY e^~!&[6^\W1UVPՖG~60ْ\LM? #8V%=pӋ@F6L"1fOՒBS.G7\~Ȫٸqn8(Ndlٯv5~K7TK۪Hn66يqjEi qQ'ktuxIJP/n6o QH# ( YKbUp0d.y7_ӎ[urpewi<ٲS`nLP yqZXd"W] 0^0cvO_V> Tdd+pqOdZK}jQlTw?׉ >EK' k7V)2pegYBZ Y/K[ȇuMկ ՎsEP䮌ɗ7&H>^l0%xE $Pr,0\nV+=30IwpnՂ,C蛝N!)[vj}uj-DVot;NFR#FVY6P;FF MfR$K߻0E^Rah nit_]'@|tQk/WpʖEZ #Qqގs;YuAF?lI vZui) aQ^0xb.XY`8oxz` >|ho+SSfʸu%x?fAi't SٲS~q>`4KI;NyQ>Ex_ fTA(w{1DקJl¨bU%,_X7]r&4]U>6WM^ 6M#>:o*+򹵢8 ?hm8g SKv幭8Po߫p?lI^oN=:pU"<1LXG//$gqdECW*_y`a݄Na0[vW7+Z|b8Kc26^ y#Ƀ_ي<걽,gn= 'R5 ^Y2 f`|yTQ֊&^aNLELzw՛O&[meqߜxWzWԦ}{̾˖d{ y경ьZ S)J|ud7,ʰ]n4kziOnt#]OM^1ҍ/M8Y1fY9$E V7+f^iE_ꕽҬTfx Yl2%X:W rĹѪۚ~U* ‚t약2U;()_+V < dHgKrqwQ聆@\ΖX{kPl!wbϮc-ɭZO8j!b #5Ymk߼խ& ٲ_-\{Y~[tKr)C{p\Ζ\4 RiB]14d>.pي+JWgAp-YSkko'G{K)\0.M5I)ƒۋ1Hgˎ[]dJ媕ʔ/^6 ;ܩ'7zHfBJrhM0k@Ƣq"sEk걽׬-0ַPC|M?L,/8/ _-IƒѰGOy o4eA%݌E7lk4+:{1-ordKc|}w' K#]+rH&Al"d.9!$cԸ-do+T(3;+fQ@zt$WW]J6jܗ/I|k g?lEFS{Ҭ\~ ъ/=݄ظkuif4We/ܗ^q9:[ mHa85x[S24jt:.`/4fa$z}\hIm d.gKsZ䤄"'7Lu8x g^lz5NHum.ro(l$苛)Gٛv۫Q]8T[zYw~kي<1 gݮվ0W^#WQepib,hmq~d7W\zuMea|svu񐭠ux2id#Mզu)Ees-\:l/3{џ oNb={ّJ^N_tf?W d/ErXg.IPKV+(=$i%콭V{A-JJbR_2t2 M| ϸZ+K1sho#Yuno,}I?Byf01,DgˎUM^gzqՓ-N%\uveɕ.?p~b{ 5P@A?FAo PfkiF8}oxI'=F-ogKu>.h:|(ਂʺRlVx;Xl) _pL+^q[(hedwDpd6 r,o5 ѱdtq$j͚7%/VokSuafKu"icܓ40@_ΨNw:q`},XCZ;r&0ndDlыYptfmmI7fۅ_h +:`Ir-aXS޵-?<vѱ$YJfYW5=Ck ᮜ.&n826cI28rڬ]C^ WOi؝55ތFȠYb򒄡䯜>iKh2q4 XYzp3Qo(9>82vci׹ :5krcХ Q-l#LW*۴$7ia3QW^mx;RE.g8Mg"Z;r3-[ұdt"b] /S :|Ӱfy3X 4k.jh:?^?YVi-f6Ʊ401岙awd ֯`^ݻqw3kRN6GM1li.եj?<6Ͻ0lJǒ œp5lL1UK Yf}pTlHҨ ƂLȥjԱ!gmי[\ WY$7ڶN=fq3l'Uk*V3hgZ"˫{qPlERi\ZFKT5dir[R<`D=;/ ̌e)Z]Wκ?]"Pi0/Ǚr^Ìkn+بĄ?~M Xo(w2Êb':Ɲg:UwJ]cm/Τczy܋%ɺLK?fMr\q&;n.F:iILgJ>ÈkvcV"Eq۬ЅLGt=8ܚSʤ;̭XG.d: o.\.iaWKvtQ*K=s0јHz3.a3ŃX[qeӊkcFHqYgvf|5,ss]T&~`nD캭*]/t :d& 5hǑUKu''œ)F1Q(L$.A8XqwQ#bߊ5ktu3iYnWYfvK6JW*ؔu5#I&8aǑᄋz~JF[/m+G-Xe&TW2;mùZ SvV tq!"H\g:̗[ XUH; KNt~wkM2_iqKr k4UeVwMۆ3Ɂ- "E ٚ Ҏ x@n4{;6*EUkd$%hVAGq@^[l;U؂%KM=jSB8V $چrފeKt}@3 оhر:TW#Ҋdj5okd;Ѻ7U Kka3ըKq4K@fб40r J4hk6;{@;8Ozb:ꚉzH¾`8SOg{qϝe֙=s+AA*8h{.t,ٮk&dҥZLz;1W&}q\lCǒ\]0YXeLMkvl=l2ciӯ 3ʋD-Žu+.I o&bSy,uBK\ղ xͶB`ͶG>t, PԬŚ y-ذ+%ɺlb5UѺ#ɺo%dV>ۨ+X2V*Ym-E0lEǒ U \ziڭ]װ0܋tbM֕ԥKK*{3XlzY{79þ]m5(ny e96qrij[qK:q7n]k;w\g-*6VVK2cVAiE WWnȝ6t, nL}q&%56 6t, 8Ү<,ۊ3.HﭸpMF{L]rTp'7ڄXM G5ᚘeC3M(F],&ތc: ޘTi-Ry,g`RbZ&s8FFDiՉDp]^jRMYYwˑY -1lj%'LJpZVa#:l䱑mi_ug^b4h{dDȨj]ĐӠdی D>Gs),ޕ5}%U/r*VoD#Wte.6[AWr'N7t=L,q>t,ٮ/fPPEndnŹܗ܄%$q7nͅ[֖^ւ=6q,w5r! Ɩm#NȺWUaGh?#w \K tٶ;bl;a܅%g$]#YT`7h[tf{q`Cǒ` :+yj͌K6qdll%z$3FϣIؙqrPKndYmͺ3:{r+к{3Y܊%]#xCM"np)tNt, lak/6#J1oܕӘ,[q{ر5qcWգ֮ps& bz;a܍4LkЛ\BthZΌK6tDA'YN,面K:d/*d)Gƞt,INi^JCDzvU9rۤ8w+/%LСwvUݔJRz%k3MXYjam]=kf3T}9 J3IdoǑ-K#s/Y]ٺlO6Ɯ0QUgfsKr)kGZrzLkbe2x}i*Dd'~[$lIǒU|!٬P[=lj܆=ZjoƁ᳉%lam`9C3;mS JZn"'ǒ~kJ@W5&,voF"c|HN$h^?^GUtq¦t,.]0ڿjC"Y±9Zi]=Gƶt,|]uigO*FVҬs8/ ųoK>9;gsrwrEu/on w%u4qlcNkv\ð1Km؍b#`J7v^T}eMq;ll&cIw6P!kXX7^[rrF=Wtq`¨}C"2E =99B6Pv- j$/uokGV_&oŵ [ұdtlnJ&޴UUsG:f%IsS54ېsU}2%ɋ[/)5߸o%W*u{3Fih} R+֮qtBQ+Cqm?GZ7.=ΘM4fo4#`!ct.5yS(w~ǏjCr}-uS)zVYu1f\̭uQ7]j5Gg=!f(9v5UMee̦EA?EC(>akEFCul/.mc5tQ?jEF #RI=k,18G5ǀ!8q?9F 8Q.ʛ.G9|{K+%#dτjҧ*߳&ojkςBlO:Qֿc:A 5g1DOl, cVb{Փkɛ.GY__k񦪋QO} .L(lEF/2Hm'Koj"trg?W Q-8lgE!K[dQ7]|sp8ʳ^ep^1/2HŖu4j>񦪋Q0/`MT(v3_wyըR?E.0}TMUY.RȥR~\|GMv+{_c?*E9RY75g!2=؟5yVva? [?~MeT]wɛ.GA!BLlWƻ<뺨"$b)oÆ\[KTl\&o꺸eq/l9n'ag?Eȁ"o*"dꧭ^48ɛ.'3Gq\JW#aes?j +;vQE$x>|d)YNn=dG0HK'7MY\1Ƽ뛚~R$+ϢaGMUds}v`ְ2*TMuf~O^.w#sU ^NxS$1fL V~<npTY[~_3`:8[խB썉AB@=:M]ցX÷ I;juPX7_ZOX"m:0' a gg򦺋Iq6CWvtƒ\ [H];p9,^165. *.'q)YrV6Ѻ;mlgqCaqr/bUv??9#'5Yhu.Σ.okRGb_&.'2?->>|W75G# '3Euyq䷒D؊p\;! ۉeE66Vva?IZ[˥ʛj?{'Ѡ!1dJ*hЁԍ䊺C.*oo}1\O>䂀߫#2=F(spHHAk 뎺":Ksp@FD>M=򦾋I\qDۜ&OۻRخ83r"܌a'nDGU]O9`Fdh*Kʛlb:;IhAߘ x!ěz.+8;*U?UN$NM~p@VfB@Qg]w?%Moɼގ#J~ 7Uu>˛2|50Q7]Oɽ#XX7ԏx&aSGu7?8LDrƤb-TtQ?e>0SjT{vO0ɱF~'yRÌʾ1Rjs+L]M5,=4kcZOds}eWW8ԎiqXƒd:'*o:tC.ufQI*K:ȁǛ>X~RaK`ci`IpW ׮lnzs?Al]=U]TxcIAbKIxXciX!yvy}Euѹ8L$kT詿ΫK#֑LnG.5%#ӫK#;&MI(S뻪í<nY:H 7$5z`U#b}EҰB,K1+=6"G6һ<뺰vb{=堎;TzӥKf>>ĆZ\8cIPTN75ySYӟ\|~82^cid@s;Ȫɾt"ßK#;&EZ/L]UTwZL_ZXc [y,}{XdL bN{ 8GzWgE>XQ~˕o+ X~&̇UϽΏq2պ=6TCgMeX0 8Uyqdxcy{>J'9'4㐜1>WUC0ʛ.04a6o,/0[S{ix|aP5 H񦪋 ~, ^ F$b?_v?їU@QDL/__wnHO]o~W*pKZ0}_ߥ#DTx|߻Z5hg\lGk"&M.ȶŔ\'߲y5%ǭh/MsʅZϢ |% 3> +$;/kP^kIџz!t۟d{}n̉ _Rm$2H4O|V&rztǾYC'$/'}YK*6^1_K~x]ګIw_[ǟ;|| _],8$3kL۱h1U 撷j+_?ּ.ȋUk4v:uι:5Я~i?5Vy>n%?mGq=6x":~|O6N@ס)چ,t_Pq!A͋ l޼K=mZ]y%󪥦ҭkꟿ}[]vGH}rKrZsKU!TW|]:1EY?z̾:DnԸWݗ]=^Z^ۺ#Y행ɡLvW"[meQ?T~!5pJƣ,2qxR}+U?|u(V.H.̧kK kHWׯ|leEkr9Ñc DH]Z?\5a[?{6_5ׯ5[x=1=۞`ڋ߯_j/ Ma5Q}y֒Ne3?^- Cϋ߫`U&HZzh~j^HAM«yAh؅cOт,Wy! _*N)VggWV;=LЙk#T/x~CPscL1=4AyaC 6@9/Ȳ(9"z#+m|F(ԧggn1͌6/ϬՎ WǭĬ9jQ_͌6\PJ__CZ4W?o$D'9RֆeA+~[lwP^P :2yzWE\`W63xd n<[YLlXJ6+ GOZI[`oMۃy%}{kXz 5rkzp[<ɖ,f%IUo+o9rlbt%>J%ag5bSV1;S;38yF_ی8q!yXy[j=)/WrhvN#^j֕@n2#5A.8.3~rX|8"WYΓ0t^1g=z%[yZ ds282%ry\k9z%)Ū8L=Yʼn+o9rtDkdu2;v5cƇj92߿V9{ϩx}[!VZ+<(-st ]#g!ٳ |бȇ1Xck?{ lN y"yϸb{lQ9[(C^!zEzs3|;˪_mA:Ja&m׆mW1vO٥h1h&v%cwM_q7]] ^LLYSwpT\+Ͽq9I'idM\훥Ӿ򨽊{hNva~g+QGJVMj]\k^X{BlWֱXܔ[ }ߢP %7hg18|kQ6א7\+E) ZE ( (/m!낼 8ol_aVV]l}l*qc?#!Vz^MRX+"הZ]W@K۱ 3ۆ}ŒP@5RlI&ri-vv{tڮEv,1xskp/ාL_2 _J?ΜM۫՜Xgj ws?A a-3`_{1k1#:`&FOaY!{J͘0|:.넨HqA~4N'~B\s߳ yha~_ {UvulP]/_9ouWgN2R5kyEwfy]#!2[YmXknWm|gƒ {#Xq\lҸFQEϨ{5 SvmElWTn1, OԼoߋW?ք>wXG=uUQV}EvXVß$V8: ʃ|xVbi5ܡGf.xaD% yI_Sl.3sŒܡ/J+aH vncqX劥a:TV]"յԣUaes+" F^7:!#Sb5R m1/ 85o!tTVepA6b[uR-ج~Rcz+4DT.-8X oPŁXZ(sEnn 7s8yX%Bfԉ^Ntr QZGń/ 7W ftp7[+*tF?t$6'Mm@DgNqŽK'`,KH٣nLR4v :bz4OΈ,_,IU_@XuTl>B/ݦ<[KգdI_gmtq^Zoaq.Ī?3)aPW/9 8ƍN$=R QX}AK]|م>wl*Ҩ ӧ (44x6}XK=qQ'P٣6MłVm,u=`PQhKfVLފ8V,Yu XĎi[q\q' JV=?Vtq5`;2 {;Q$TLҴdIl/I7:C;Ն78K;rwrTI{xyqw8V6 K\8=2ШelL 䵱sYN|,IUϒ|`o6(tl)Eirk,ٙoqᐏq;.q+zF. I*RcaG>&|62OPhRiƗkF%ԙpLciL9 u )/e"}T2g{i:;|A? DŽ3>dqp\mpTV) l.f[ޱs]lHy+uAQVm<5Sgdˌ+r8)l8"$1L@Mc" Al,}4,ϠTp<։!Aw0VMoqጏ%vZ1'b iZܙ }l*]4DniLmjLw55]dÈKbig?27ӂUpetr8,\NF}ֻm0f3Ҙ<-qJS+EI=WI촱:<9p̨\6ͅ[ml8 e4=+5`EuV~Xg<S&SH9b=mqTҨS'xP*+舏%W:G~sj;l@9# ?|,:LQH"2L*1Q>9ZU\9&32eW%R Krխ$(6;hX\Eoqᇏqz6rx*2lPy+K?|,Uǒ|Tx=򻐫XlÆcك'ܦ$BPlx y c}ԂhAsKrյ$i؉>O6FzL䃑M+>F< mHYY3چ_\8,| K>I03C&qa+Ҹ̇DAyaɸΊKrͤs0I8:O!W$9MoqᏏqyP3XV/-H9E1cQ ;>Iͨ"4bX|% )oQፏ%fo\6"!5: WrV6 7_δ!kcdE8($WLBi6/4'چ "+ |,;E!QW|4!"#KK#Y nЮ+# |, ;˂ r뉐_f#/G2W8L!W.7_WŪtǒIwD =[o6 9h*A\Ef;ފ%K6t?x"T#d\90tǒX}XuR?Q GS>FL<#ɕ4+ |,-SFbC*}Aʐ_ |D#Kq, ;=ڈ]|w d _飜DžW>"CJ؈*9,t<ĄˆǒƒKmCIThW|=)oaѻ0e6/>Tkь8&$V}; )!vX|وF6nX03GʠWD|4ǒXDl^8~D+,SҸԻ snq͊S vwDžc>ڴ 4F҃CGcMoQᗏ%ߑodSc%er6{Mg>FeFZl͂Bj&H͸ 'FG18.\$ׄ9 ]>$ JP3cOQWciL,ˌGCO ]q_O oeX2R?4t%YH?6:Gc>F|VX'^d '-DBI_vboesa~ @/D5Mlc)# |,U΍j|:aV"a&|ۀVv4nilD␯p#FDG>YB|,U@Vd't2bY4:n6 c>Qk@[rq!"Bhaᘏ%B,Msg1_>VlD5:gLJUD@FnXT?kzg+dưl.$W=; Nq|, DD ٳM8$t\a).`Ӛ%@~d\ |,IU@ywCET$w[l%Ҹ]Mп`dSZi3r"ÈR(ĪWGűx@)37^?ioK!lI Ұ.-Ϝ8`) 2Y MDž+:] #[b m\G#IiP>L˩oq@A'3E(`dSMi'Fw&BOS2a*>&zM(U@號L*Pf6fIÀF6քhBi؎|zXS!"I|Ԣ %Ȗ(\dLAM(YVRyXq\ӆqzH.\3&iPL%DsGYoKB9'oc7t Tͭ*H@Ɇ!CPb\-koes VMI6wZA̶!]b$@^m0y#i%$V:i6Ns|"Rnk6y""Acµ#abh"܁>nXS %ۑo$K#>n9[|B Ӛlxe<DŽkGǣ/~RXNtri6d;G,G3!;DŢTEkpz壕AJ#HjLs2mhqph2 7Ƒ7Գ%Αo)_L(l]ZD )+4%|)\@7992S23ъ SwV%|i܆e#Q6,^C7#8DxVu& $T]:R'*¶1W}|Kl*Ұ,ܰ,lCiStcf`puވPyXq\\u'rsVL* [Ç~F6cr{=gilHGGPeąȅ 9mǥv.E"O] qLcIlamDl>]_[oąH5tNyTzciԆI&z}Jg-vۀVX.Fը|lݸɈ dts,ɝH `*aU6G?>F蟆-_'b)G揷R7\;B!񋒙,q׏hQᏏQӱ&}$ׅMCWdW5:崱pODubI$ѿr4*,7+XqPxcI:u2l8%&LM+Td$쿣ȇś],ij )J.l |4X M2 z~V"KQD#X&qTxciԎ޹$IGH(sÆ7ǒ\ӦN}Y5boF!qR9l*4@rXfvS!,U][ǒ\F:~V"Y5`RطVV6XdlG*Ջ\FԶ+2ЍF}V KY6A4:XSVX^$M4&Xsl*4*u0+D52EnԢq6XN&U>:kV|V6Xwwj4I!,Mah=r0Ⱀu3(L) _iSy!Fr4D.糲W u"6m8#J_|,afJ`äʏALx O|, 3!2\)i/t0cW$)M#>Fm[XuXHp W CpǒD9񔙳 +%K~ )F~X0OG/#I%B&:;Ɔ8.F _txr664_l0gM3w)3Җ':ފKr%[Sc"#"N,X\cIn dUny\E 6׳U&WQV6r8qLcIpI)+Rn *tҨ(6߳RVROhFB=M oqሏ%lrEJSB'3rO+7hqሏ%F) F}9$6qLrNW#X:ciXBV]>,Rr3z+^n6 #>.FKY]\B66~Xݦ{,YH\PFt]s+8,^cIAd]RbHTL܆^f<͹وV6X(XJmN\){4+CsæԝBقt׎Y*oB;+j$D#KwW\윕.fDEuVX(\"K,R,e֡փkhajKB|QNZ9!؛rK%r0$ NyMN*a«#8.\4Q ( b*·Nf]`GmuFXkB=<8ڍ>fP/Vcڈ66Xi—B9u7-t0WL!:aQᆏQ9Q5b{F3~ehL֣pF6^Xknév+==^stGU/ iawLR=\BzXV~X(v[+%pZFll(4(ŦM/H@gYѽ ]6 >.ư4.$CJaƮ@Y/ 7 Kr")uI# ]m0y# _{jtZJu E0nejXV9oO\,I]KɕjCLEWL"z6ͥ#>%!/*Z_;s, ,++ ^6s G'>J] T 7jQ+S4t{I?|,i 㫺>VJC2u^kÈ KbzJ^J`SB<9W&laERhqᇏ%lU};qu25V`c3醏1+z'CBBMr4Մ>f@ _<Dž>3ӭ"q`1+Â./]Xˆ=m֔Nb ݚl,9'|, -z{Rн Y;to6oDž>HI.Og`ːY*l.$Wc lKHNfȊ5 4ҨM|U h*X}k"ڭ6H! o( ߦ4D/\X-!]?~23KvYגsN,}$IUP1T8ÍY,OqYln8- ٩-h~gTCN .OT)FΩC}וu,ò<ޛV현|^>P\\ 6VwA_h|ޣČ ygW.uDb fX)0uɓ&M? 5Rl~K6KσKNU;wVsWX˾1~i{֙uw~>eǒVH;˳r*c]GpQO ucE}py9wYzNs_ fr|(0gk̹e _[;s|z XۃbݘwneǑv>lXqNġs'}I-(K︰N>ag{c]4߿f A(};hoW{{u]@ UMҳ^A5G؟ْ_畟߸+T. C (/X3煟Džg^/yyς*lhjۭ?%<_v7~hWG`Wg~f#vۂe{O[JJ.X(b9~xlyٔ "5)ںv exx:G캮o}ٿtYz>oJ+֬xO{6HE=#0X;׵2]zkN F⑖o|#i}2;kdN|#(_õKάq?8 :97~e=l^.|Iyci7`,,m",1>PEf؟ kx6(i_?}}7ş_K"i[2t-0w$z?UmK~=3=8.bI5m T*YlS &6v4!U/PS *Ln4eAMlۊqie $?ƺrK[q\R&4T1B_"u@\l.#bi܁MOA1oYj2XXW&bIjX7A?L3UT gabv40MOh}-υZZVWգRQa%n9=d=8(bbi\kePNؽj8lh}`V6v$FŖS&Tt-{oxHXԚ%:l\7'(dH?l,CbIxB /Q{K?@l8(biЂ[r-#eJqm6GE],I]-6uy-`'nl]Rj2.Ƶ- yMLgވ".j2aK~K#=l,#bIj[19(hjɣWb>-KÈbg<Į-$ժ-osFqv4j])ņD;D-َ4>^մe], km6TkCޒE],ɵƙIs@7?ـ6 "XEhMfd̻+ |,ˆ=3lǿ] p66XtpކDD KTGG>Bl/ AA$z|Qu7aes钏%qci鋌IIA;._oOފ+KFJI`!f@klD9# |,jm3)Hڶ ϟ_xXL d<6&Lkxl4y#Ұ=;04Pq8=Z?m4y#K|,FG)IѤu>Xq^K[q\3Ҹָ%sF!DXKu<+:8(F7ǒն%Og wL{uaR˻OOy+U/ W&pǔWG> i!xQaK']5/(cʶMm@y+ {,# > tk͟6bX)blǝOk# {,]m&OfvC>T6y1w󗢤7_Pu}LL\kr_"bUzcI.pezzKKR2/O7m y+ {,k+6 8hqU w==BMqi]&8Dn:=saUӐ-8.\$w5.ۨ2IdSR ;ۿͥ{8-8*~pU;pҸֺe~7U*U53ǒXkDM[|``+(5ͯF c1EDfec+ |,5;nٴᒜ԰}k{ƝKTciTm+]AGaUƤ{/KqX8cIv\O7zYz#K|, ˶d-J{j(dUYXgaႏ%m䃪G>gtb-.4nZТT :a[qsbCT:cIj۴!EDԺ/}:oaሏak^m#*V6Ƭǒr)p!`haUrF ފ:Ƶ T,I{ <:+ // w=q6gDŽ#>uMT%ܹs;pcۆx%ָfaIW2Ǔ+3ӷxrFK3EdTUbR#+ g|,]k6+lrsDP(oqጏquvsgqU1oyKl*=$")&cZY5>GC>F۰BP@@PƦKƦ 1˥0)};hq =EhG ]de ⾦%8(|$w5'!Sqnj)KZI<2jom8*\$"dJ ^r&l.]4.ږ (D.}YI3eᠺǎyLC14/],Ʌ<[1 %@,7/3PlEI2x\Aml(4(率C~\IF7ǒPk鏘pRȐ ah{8.4.am# ҝ9RƵMӖdY Vsn}/X~* Uӂ&l]{bpHxciT6kp ET[>#P3#hr6.X +IfdMPgX)RzRf0` ivSDžG>䮶Q3+QaX_.Ytl35~ puSpi&k:# 鐏aDBC2blɯh' 7> u- ZYzS#Jg|,I%:TeЁMo,hLG|, T@mPb3vVƴT&KZ˪"K۩D]mf\ges鈏%*gʐ)r}BsɎXފK㮴N0*ɸddz>.*&6NXUitU1o%%C˗WW)";j̔=ǒհ%B;8SZ+r㮦a[\zci\k][+#);!nD%Dž>kENZ+_}Rb&6>XZm8y*tH Dž>亦ۯQ))Nf#*tςKZ6vJ;srSwOKb;^)H*jUf8>$ÊKZ(!tRѮK[\ciܹçW*\zLEF˱$׷lb oK݊Z G>ZZ1 z̥Vh|^R K>%X*\Iͯ6Dž>;z \XVEsV:elc[\8%|ЬK=EhƝeQLZ¾8&4lSĎ_UaD> js4x%mK44hD}]k0>X)B; h'& Xq\cI 2| \$\VEʽk2QIoq჏qusVEn5F6NX/$amӆTCUg ^F^Xڶ;Kl?tKV Kb}ۈ!تTYQ||76 SdwU'MsqH8ciTkXR+Ъs҉}.ᇑ>Į%[BU9_Cخbm.4QT{ T Vj KrW몍^@%܌ʹ%/ jM[]ۀr6?u$TyA*خ%-V}XzciXkw(`ì `;M֪(?8.$w5ڴqV[@ȘXz[\:ci܆¤!Ҫrɒ* 8.|$w.aVUT$L[q\ci܊;!s t[jGXv@*`MVU[R0z#eb{J2j'cUՉ$C:#t%K0SuÊw]aPkڰD.$fUǒT/g3xF Fp)܉;{ol.}4.w"+ĪJQ/E͇D\6nciȱj,3(|6P:cI,;xԊXW5}LY=~XVX*7X}%\Z&:hQᙏQu2Q!>€JA0tҨִjը6TլfRPj:,D|,\ k6So9νhd7>XiՆVpUӇ@-b/Foα$vͨ^UMEE[9ш'KZӪ DFa25}U;J|, 4"" j,mp6>U3jcᐏaٲ =Z )jSIe66 _Ul@d7d{4a1ፏa늙"UW0+ j}E#qxgmqTŒTkS .j΀ Sl# {KZ۲ ہMZ34aqᎏq玝#nU@橾Tm0y _|, 1Ӡ&-`Og&u$yJ 3 V6X˦ge0@z_҈7%A1V]D $16PciX0`煰YDygM{W}> t$܏d!P}hVXLk30OH^xTeӴw66~XjMt^RQ Ak< FnX*b;n,ìx)gP K1!f1YHƽe'G#_ZF7$L7fn;3 F?r$v6$f@t-TciTk jN `$jaL4xXq\cInQT A:!l66>X*R[,z9s!qXcIjZ9[n,0 RB)|wι-aa၏amT)!Ъ cb?l.=4qT+DZu}RMQ:$?# |,#v%EBnO32ࣃ՚/\j6aVC`XnpҨyGP=nY }HMZ${pFX5 ~cx[O:ȸǒv*b3n+$>Ou6 =;>9&F7Bh@K ) .iC}#73kREۋ:ŲF&٧ zRey]HW,W`piff 5PDuiyRrWYǤBzr෼I"т|]k;_а JDk'*:Uvu%8G53(./Zkeⵤk|+OTV]{8_v7gB}c+& ^vC/+PcΥї?'ڂ{N|߫΢'\4,Pn}!]^+'M8'?5q)5M}Ѵν;[ ᳬrzq|Z9~q N(Y.^Lz9n"'͜k 1ׯs>("߂`%̼Ď*c~e_ʽҞ&9LЁܶVKKGH륭F R)lmVϲg'cMWNthP" o;y@S0&`*UJ7D|6Bhҵp|v2 I>lG9%ݽ?J4M?^* 7]b4nӅ̫ժÓ)ǎ+uXV^Pݏ#Wg/oyoEc@6dLs$6eHÆl&(%~NCK8/8/S?#Wd Õ1?'nfc랽'mM_jQsQ/˵)?>YCIm`gYO)op-bdp/ා:5(Se8 USgSך0k*g8;]Dh_a}ɇ˟;)>l)n?(5 }JzL1*XsT+VUAe =dG,+? *W $4eiFUK[E%XTa*6|V\PKVM/k'0Q92$Ħ^+Е82$]x 3ezF$$6_ `/1E\=5[qpJ֦O8FYpXQe*P,G֓Y69LlXz#xX[/ܰDʄTyELR3/6F+XxDvxUDǐ'!~T0zXqP҄bӡMeO%UoBVaMb,L,٤ WUUb:(+`si[q\9W*AԡGi)3kƝE4L,Nh0y'6Mwl/*6ŧX6vhK6i&ܭN 9Pu땆Hqut3EO$oqmKܰFMa9Vt%^\)ɦr3 ֐^.ot3v|"Q-YwP*9`\lS {@_rڄXXMwE/lmJ}c@/LIK"5[q\DĒ\]ev+qE#(׽.|Nd,O,;BcrT\%g𾥦ZQy?+Sp6q-BP,"]IL܉ rd'fF6B4J;#r!hX+/I< w|ͽX+phy]bH.]ltш} KƣY=AFEj1ZjXk6 &!Œm|ش׵S٥!/ )4zvƦ2)F$R#zٳe6t%T++u!5I%)k~ *lm2E#Mr%dvT_m^e/ܰ)? [\ V` mDL>$VdS,Ip8I:~w.޻[3u b(K$Zـ)wQtCniV\b3.ڨq0Jj%+l'hb1çbI.DeU*< 2ⓦ/Z[ET,;<$܊> m>{$܆V Lzqm[IIjfBZ&nyZجXEm_$Yٞ:j7Soml*#biT}PbT}I<´B_X 71⸈ϊ%Ϳ )/ Jq%on5P[ѠV٠\'5ё܅?1+l.Cb@* 8" j3"gQS CNǴ9Љ+mbb6EW,UPc{LJTRܰƸFӥ&]$Pj`?H6Mnb6-ʴy)pM9~Fae$VWC&SVCv|/7b[\Œ\]swZ+x5 {`Gs[ȧup7P!bȊeJnEOr7N㼬# ]B[S"mœ~9Ɩ2ZqP,Wbiݐt֋yfg4f eZ, e|JEZntpmWʺ{1EJ5tƩX8h\F+Q%(\VX^Z kQTi+ˀX+" )S\xڍ;\R[Z5qXҰlt܏ˋͩrWa ÊSBVV$e:F<]Fވkb6am#b qh` ;ї6y+hXeA,+iFF_"T/M1Zq}imS\%bb M}LxUފkbbFD(וpBmoدӪF&y_Ś?Ѷ!ioӤm.x+hX"L;t/=m'ފ˗o FNQmSOk7ڄPXM" ٰhlsbV>nI`!aes*Knr۰hI)/Sveaq-K6,I2EKx|nȢk%jdT6:дDRl nЗc#l!d ҭEi5\F+չ!Krb ?ײ%W"8GMLbŞm, ;qJ;Mi ԛT.L2qwM=b>F --HӬY"5̲wS:Zmp,&]7R7DW&{t4=ylolpJxq'5J/NRl\oagKbu)"jJtlUfcS}ʽmvx+zC.iɚt*۔&v{KGW!I Յ@/B&ӇqkբX{fp,]~Oreg:ܸ``;jciD*Ize/+;5]6wt#=n%5NofP+ ݋i`Ce ~%ÎYL+aa KBu!Jc"4-_Zr6EBXܒ=[7NtpJ7ZYwc!ƅl2>c}$p-p,"CLkNr˹+fr7d.7ȕ;!n:q7Mb4Zq1esAo&_]Vz;Z "lƒ-0N@˅N8*^fj(xpLlҘPE1V.=ЙPaesKru"Mc"\{t`oh= jI"+ä!z^f] "lƒ-0M]ÎvVFmV{+X(&.Q$"sEEһ8,\e4,!nGqL1 t0a?]HO^$h}Wlv=la7l?nDʃ<2kbKꜙF64lE 3mPz2\oqCKru"zD'-[UN|-p٢; Sa{`-":7+VvDf`":(rE/1ZqPlǒEqBu=pas=8,|,4, 7n2]^ǁDLyS(^+JDZp[trlOQ .zXٍp,( p=蕎ՃBb8F5r&EEWƞ3clzPܧ%2ڲɠmZ+/O\oB]'I$56f͵m.p_ED%@EB3x%}z]#b8JD ͨgpjvtu!n+u!7AW$rd7! 4FvK6I"$V֣.9ŖpY-6;4#ӨMRʃdUhesK:JjnULAMns4lV\tM HW><(:5\SlW:%AўY_iX^4k%8*d}j#x!_Xo@]thJۺ.&Wms hŵ dpx Ru"1L NlxS&m=X ʽh*r=Ztވb8.W+Mb"ņ flv=۷,(5܊7^o36F\K6I>֤^q/|]R&;[\nǒ\]h$ Lo:MdKaaIKtťĊEMtjPtN})#C3HݴɠU$SXm&tK6In^K|JDSDŊ&(#3x.uٖm{# XrQZЋݴ̔V%Myg1AKMwٔ\]%bN#qڲ=pB5qWl2Sid7{dtIY3)V؀d*Ue҇ Go,Iե|d'tUr_X ]RG%+ۈ}*Mwt!Zq]HjGͿ4堜*bv*w~cCSl{ Vk\rΕb䭬Ϋ%ʴEthy޶*F6$vAw[&s7RnXoݾJCL+lY6 m3¡Lzp ¶o, ] YzbDLPڢj*s>8.}ci\v*I\=,5zXq=o#لUfOgƇyZ=X&R"-a,"]}Xt"峮\jԓPKy+XZES^eH JN' l,cId"&￱<SKΙLuU#ۼwFۖmZLeUL-aqGP#~7ڃ m̍5DXk ǵ\Lx0%QY MOC2 +Nr7NTuy":/&Ve'tzov=l{+ Un&"DlߴU;bb6V\K6IWB)&z P2 R2r 8DՀ`=NdJJ/mm8*icIja.٭BQ)[B=mF4K?b4-Bu`=a8lQe foH\'=qWY^t+MXx}A״̶";څ&N$22lgIK#VtMk~UM0ZAyf~Fܽӵ\lbjDUMIr(AfrVvK65٤ו4 Rv%-TeӆGKBu"lՕR:yťmʒlx+MXw{+Ɂd LlKlWDwV\v!BMǴ mU 2 ncJLUi\}wKYyxF;4ɛ 2HM3e=ͅ:DUxLLj5+ Qi[b*8uY/a!Z֞<71ݼWה'vF\sKH#7`0fj$IU| Md&쭸6a8lD# \UV[l SMU&6ۿ$Tuޙ! Pd\lX|)&8:}aLfbj\Z:cٰ0ӞzXqwO UrWmկ0Kq j(lӂTkJ]&5l+F6{4l3h8Ey6l+iR/$Zq\ƒܚv0pU]\ӴT^ɏ t=["F }IE& m-{zmo,&0g^.`U[SZ na&3p,;w0rujBcvLgÈb6Ī;Zߖj?_]Ym-Rs%S^ݶ6/qgdۿdWqGMabbTJވb7Īt7s jKMu3 Օf*0gƠCO&fsyM/=f0 5lTT1S:8(cIʗ3Cɨ@KX'VdXcp,K>M:]ڕaQ֪cnJa31L焞\ZUnfU[+E%[ZHFlg⬋-)9/QjΈb 8.Ri/ &eU-\,cd&5srŜh=O:ѹ!fQ ]yFLdWPHj!fX ]#{dT:Wjg1zk%ڹeF̞&]&ɍhTnҨL4ґfnn+j%fRM ^+B `jsKkA٦Q5y=Fa8l\ pTbiԹSڙ bSbJnu=8.6cDž@~GACwvyҝƺy _4=hlQǶlOdq7l4a ļ9ϐvԧrh8.cInBR L1IMp;lף&l* rbp.2d_.boݿL-~[Ohta --F+E%Un-PTU[HMӊ07Ұ}'#٦Jes{E_rCLcЗZB&ƒj"qPs {t3wĦ*jz#ց^ A͞+T#&Y@5/ya7lQ+;#ɦRfMʶ'&oɫ/TgqKr! `$\ y Ui f64aQI}1'46UwG-o (scLq0㚅XY)69ۚuw'Ɣ<ѡYM^p,Kzv6I1KA%8}خF }n }ۅ =ݸ f}K2o u)5*t'|CwV>ڢ( ǒp}/ ]Pjrf6±4@GPF?ܳ4YJrG3X0|鮚k}FLd4ndNmeZʍ[_0!!r8} {uUizrS tjıWYE03$TP!,jcg;L%1_dgV]e@6&j6>w~_ݙ+~&xx^GRF0㲇 I҃@:gFw=鋟}}}+e4Ϫ E/FkYTSm+_+1Jh6Vvo5EO3;Yzȣ QAK a[v·lxSv(2av#M˧]]M]܏x"a܆ UMu&a\]%-uyS_#v^<0BnR]=uQ? Y&eqSYge YQ!יqpٯ*MMTָ%Xf](ȳ Q/P"yNsו]܏*|C0ӝBoܔn{VMuY/r@.oȦwuySE9$-[#o* kϪyYNpaƁ?  >N=j~Զr/ S.ݠ'7T7LKӁEl+Q.65yKANkBT|YDitK9~7rq$$"(#9 e^T mɳ Q'z|~vbspzTMU[Dn`G{W75g `jw߫w|[aˏz<U"BXk:F?Q.-rHKr]?0^>>QgeSGQH!EwYz?k,l1zM\UySE>[1X|-4E}M}Y0Xƣ*otL.q5',:l.jԘYE hac3ߪxG[u*<+$B&?YtVYE !J.GI8l',E.(_=*~_<K.׻a"rBXGښCĤ6?:XE%E~r_涣#Gj(T(u6'a7=A`0T|ϊ.*^ALRoTgUAalq\'5pTYW~R_a[*'v3o|:`fTmNoA{QnSL9*a?I>Î]E_ZLu`"F~R?)3P+A.v#T|SgMz,j*K WN+A@h[v{RbMXIEeb&nd˘,8ȳ AQ6˅V6ѸMr7r'lf(a;Y;f yua?y54tEhK 9TRLښl|"VԠo`k9ehU07tfEjg˟}dԆ(g=U%AQlt6rJn'* AD'wyua?`< <*a?` #瓍Z=5TuQ?PoVJM55'>B+']M-NN (!v,ADBZ.1j`bf7U:Q?cj~9(Nb#"Ϻ^AQ,"퐋B8v\UYׅ}(󏙹AP1ۘyհd `$T"Ϻ.ɗﰟT_ 7&XbϪ.ї8`t7xtQ?xȿjWl'Uj1|[\Idz AC+s9o@ȳ}ɓ'ef:+A9hY.֕1Qr*쟅 rPkL7*a? `yhҥTZE 뺰NT+ca`hw?l79 T1=pd?kGGTCTcQCMB-G-]O+I[Lz}Wg]PA6MV* A'}g=6V68`tb}b}E]<bqΤ &KNQg] ID'XE}YځHW?m @o8Jv{DcƳFq@"qdz AO؆IC4AG=U]hעvWKxQY?I Sp9D- dZ.aȈ>P_p@@<({\-zGO*ecvbK9" pP"6;UY p0:&@mv >A?ixƂy@'W  ̯5+F,I=Q?i/;P[:,}/?$$:z<_#3s!3Dg:'5YS~J@@e=$HƳ!y x|ǘc&Q>韙G&3ucL髑UQV B_z`Rh3.fxYOmKRTjJ 4C(65tQuYb'2w-?8"~bInBMA5uhj<ƠtP2amڨ5uhXֳϪ.,$Qzb"ϺX~擪to-X!R/?Սx]5]LxcIcmI2}xӠ zKwP/zcI0ePA"Zƣ 'z,$cA'TsqqT8cImoG_TRT52M=U]XxcIQ6+rZXzcy`[:>-Gl_L0U2a)Z<+ǒXR~PqR}=N#Jwz,#3RK?G>Ez,Au@+5Gp]55&$ mAj,3⨺|m.Ҳ-Vs!Hm5;~WU@ ]=YUҧK`ea[;W=Vz+ z,umw?-T+aSme'7V% [˻<뺰pǒXGg,U u]XcI90rb M=U5*뱌ԎPp#GjjZ1^A&O=kjT|A#X* ~ibϥȧN~=#~}?zy[u}K.\9 "7> ׯ֠ $P^kV|yO"X>KfU9$2v%+UDD&m؟_<_IT~kb)ͻ~U"7ih|~=f8廚 ]Ҹ֫~#|,t]hG gQ3k ) 4@X](}^R'O7M֎b_˷^G.oS >&L79\pttK$CԌCOҡ)n==cCe?~gٟan׵Yn S]c5 ^جr rJ?1Ц$AdyB>J")GK֧oB/vjcWJNˠ~uEQB |]j).m5XJf{aB'u_zAf|%qX>n:pskH:d~+Hm 8eF-mgyv٘\Xc^>&|͘o$m}k5%W6&|Z6g&t]caScAXqcgO%Z3mu zP\_V3<}>sW5We T|_5%=ߵ5Yg L/sMEkM.l]iOw~?/ӄ_<>̑_K @rn;oix_$]1cx"V"V,v!/ikn.'}`隵ȭo$[MƉ$OFOG9yC4" 8~^ ><ҙOELrhIbKꉪ⁸xݿ<4&"&zQ-Gv\gd{{2r 5ߐnn]p\~qgeo(pF-q$AJ yWF7~J  bx282qy\k9z%EjANʼn+o9r5kdl y^ q̓gj䎔^q\|aPkV4Umsy%p[*}'2xz~{Y82o on$;+\}#Frly^ \Vz;k]ucqaS;zX!Uv/=8&^Qno8Y׃VwEJf삾Hz R *`]XdD_9mS_#t␠|w;FOGys_JIr6'x,C>gne~}ZW8&A9űՎ`<~v!ZΧ;|Ɠ׺K|ȇ^8YƁ=lm!y;M>^zZ?k}`A3xc$EpX?ׅ׭?7ϭ]2kMPQYU>[ 8-?lk:U.7s]0%F9M} +9VTz^ R;Cc{ch,%|72?t'La}}W3w4\@JZ } oj2G%9tskh/`诏://k^]%N͟]iN(jN}[tJޏջ|u|Zw0Pn`PV‡J|Ƈ|cs{s#O?.I?!pT/~3Q/k93ڕMBñU ^Xu&|mfun'Jrf K'WeTQ'/zsX-YͿX R&M#؉.\-aqKEX<2I JI,؆ r~F6o{T Δ+ .ӸmYq\ҸFbV p[^+7p;rz؇%FtXcɆCR^o 66[P$t1) 07'GOaF;A4A .WKţR1l.wbIQ Utx;݋|ۧE˜$ }d&Y~1&א5C<E"X]za>䁈.F.MG|(̓biT =v&WpNkrpPm YGA0#SP@&GF#iesKrEEJCݡF!Γ9K/eފ"\85>idN#T$v !F])PD'lcqXda6 qk{gt2D!oes*jP`%|82| b0<}۠kq )Xa6\Ho1* U,5b>#*_c K=^ag,;;! "ȕSNmP1ZnXgaq3\Ambu?xGzs];?#$4]蝖l<Z7OKC^H8.(|aІ\ gAƭ`ʨJ-@V?v$7't;W!+sT}"= |]vgXrQG`o'YnSۭu6GbIQl8u%eΞ~mT/'ulx#u4Di}b;~wǥs>ÊP],ɭtYAƭP}\n)":qTq_+sNΙӧr;HB13Sm\gqq+OEvBȘSs.]9l*m0ɊAձD|5۳qLĊ%hHn! 7F5nt)<8,CҰ8Ɠ:BDR+[C9l*BŒT4 dA |Qҍʼn%N&NފHR,˅i| aו۱9t!*܁$I!󰲹_X\5>rϨa тsXN|,T /{ Mg@c*ɝ2;8,<4lG. MDW]@<%Kr "u| umlhi=j&qT8ciԁI{p 阆sZ4ʴ18.$W}KXu|Hi}PuF6XZвdX}l Ʌӥ$Am!ፏ!+# ';5+N؃aonӨK;eƣsd>}V2Oފg]aPed1ĸ9v7 S8$$1( O"Z[]|U](ĪSI Fd4]O ףVW>0hGa3M}Eۊ]Zۆp2dtOC!ܛmDbqͥ#>9cGnG'_꺔hi@:# G|,@JC3_J7ZZ ;Xml*=$f9Q>YjÙj$Zq\]R ~:<א1LG-J6%U  u2rLJrGE@V6X{e#ʎT3 W+hqጏeH84oA. Ҽ _i8+Ko|,,ڠRf j;Y+ 8,$VL6f@b8ıjF7Ұ,RO>̶LF;y،ݨgkP_ivO>m81:v WzĪ[@IJ7ؕ_hW$$Z\ci\Kq홉3].6Džs>$Wz+ݐnEH!/ VJ|,әzqP'S]ĮuƓ7J|,l2D19p<#?q{4K l,=$6,g4fo )+ |,3opc4.ǐ*,)yAF6n _3#AJ@bDmc ) |,IUߎF %FH5,{K8*^biTu R$Ƈ>XB|,I-nwbH=5j6} +9mP'ssp"YVzrE# |,E֢N =\86fA2rd[\J q;z>Ke"$SZ.8pTTI *3Y:P:ĆP( :ɠsrIGSb،p8.}\ NG/9/+`o/ mmG#IEPAbTB9zTG;WfflIҸ 蛟єPJ$"\z\G+K͛Po~2*aS,R`-_4&AJvtUmHY8{*["PD:aM(ED/郤)j |s-7Ⱖ K^p֌$6D47DO|JRչ#l @Y<1AP brMnaqM-ŗ"g.8:"Nd7,?vsͥ`+ Z=mi].(K-;uL6҄K|IvSŕ-߅@DBڙmxCQl@Qp8M}{2hztPxH(Ep9bj㌍,‚:f7^#HyLv͞nyyF"؉nal# sr4ځ5!®hb6eEAD#iLtvcMxX"CaaQ)dJRգq_H1UЯdTѯ qei}]bPntύ5\+sYZlRf.5) _.%鼾+ ݌9?8,5BIzu2, :~$iQnηUV6Bi\xnC~qsڔnFtp9]5JaqlJrկ#,cK>/R |iƆ~Lk/_,uN$Cl\I|:#Kъ]mZm#)ϖf"6Dž;>_GAj3;;nt2C}"B就tҘ@H:ƪLfG3h?Dl8($\~Ɍ[8sfF#*DQҸ#w=8|@3E< aes鍏%]nOj˂^FP`z.mogQዏ%pg={x.fg=nri6ͥG>eիۘy;/܊^fDs8.^cID4K &n:-E"Hm8&4fG. K^E+kZd?Kp bxB>]0_MS+aqᎏq' x,\7DUT/T6ȦA "խ#~52#S(D*?>BCXrBvk)Td XTgAJKuA߲6|4X Xȳ^22ϯb8>8.4nGHJr+z8gΤ"1^m0y+ o|,-Ll<籜N65@4tҨMĎxbKՅҒd98,$o ᱳXNIN.Zs0ǒX&(VG*+j[f#jpL€=s LR9ؔ/>vG&O/J&֏v5+PNIծPfc }R#=}DzF4mJ\{rz-K)Z\s+.͢-%=`'z0L`y=;H"[R=zG#6Xl FN2[qƧI=4.(`Q" L(FCCd,i:Wڪ1~ͦ`# [A'qY|!ڳW֞+{N tV6:B\)=Y IGWJ؋c*F{gEygկ4l 3Ŏc=;ees?h R5XZٔB?cWMhd$-[b8.{VJզˊБg&Z \Ds+(xjEBHLZ`a#TsK D"[AjFG"Z1MΎ4͢h%pϭsx^+'ʨy+q8[\FsK.neʓSꆻL[2`|6VXA PR )kr1ʞ4A)s)$1fڊ1ƅl$`1SY*MyJbo=&%$v ڼ8}3o21w|V6Q܊+J|xϪX9?79%5B.%wQV+ڝN9]ЄF6 K85:ݚRƦ2[Ry쪕Fa F,Si ]?"sU报ų#g+KJQUrGWP&Ѡ\PP\j7?^rX~TR@܊JWUr>9w{Ƃ l G.yZbq2VTBƥeUҕ0_} 9 XDsK -ԓkөM)TFsK &H|a}W(}E2)/+P|ne#tMZ2<K*XsK |D~VʉeQC6PFD2MIt؂n^1?D(>.tb5PT4L=l,#1O=:24+ƷV4@E$>.HdϪ_9m1f S^V6ܒ(]e#1L^'dMh"@}a<5&u)Q҄ kaʄF9~.-qϒҕo-\.ݨL2[qEoUr/T /W#ztE$>LODgHN1Wj9ddSϭ0"_X+'"%Fa BE(>z)("T][+&2Q>Vܒ cяUҨ1y+qe_nH|nM -דy+49l$`-_r)YMUWQҰ#̼ 6+ZlE/Kӣ4D1LZX'ƷWG2T.5lY뱏Ur"h؋mE > -o+uOW0V,JnƆ2[B+үծp0u1D>bN W :045fbJ&~Dj4sUߖ\"뇾aW]\-wpXAm%6vRSJuce/?/_m7YgL(s{}XF^\,YS|hw:|4bd6GK58P9^ Po#`t|JSxjZ~߰WeZ8(›s~ʐ(d~0wv.L_?W~M5SASX]as^9ouz=+CߺKx]&ΒleUK[4\|U':RJKͩ_qD?O xf j\:͓6UyRBvD%Zj57!wHtXʖ9_ò~1AD PR5nP(*,쪃n=+Hk>&/;I>{;Y H^6-9kڳcϙXA~Pήİ5>4:k?(Б$U)TgXu[xb"3)+ȤC+إʜ+ ?'kb®,0u̧K/~$s[MV4|SKPέx]Yٯ7'.ߢ zG_.< k/u]_/Iǒ]B0?Ѕe=|׿on]mV]`bUL&ϥhi`}+?W~M(p}fxGyaysd0UzG:T`&Eߐʦr.x^ dlcrZGsr*g݋e3ږwzB/Ο+;rɉ"#%8G赯_?:^c}]֬^i}t׾(5^io̽Vmi7MCw3tѯ*릓ek|mvf+}&zs_kXx<Oz^|;^Q8} vO|e14n:nEWЅe|!gV ~H gܨb/wZU+1b[B]g m(D]Ye%pb[rRsqVWV0L˭.{QRиY~骛?.,wHe+P$VPUEuϕSb|E#:BZZ *JRE"F̯˭U)S׸PZ}ʯKeA.VM6u%tV$) EBau)we籧0L˭.Kbma4=GsٯrIL&r+<ۺH&4} j@Fe2L-\5*Q6uKȅL~PLjV$h>/OJ".ʷ|re$j*׏@2.һs)PҲouFu s.a*[ `#ܺ+߬8 jC ƍnxn]MM*c2I2խ/eh%p][qm=;pt\_EwƎޗ4e~]nŕwS;T@Ƹ}J"..f- sBF=l,b#f/Ḱq>IS!6Cm4H-˱!mW9ZB&_ru'=l*vks+jKFT K:rVfVwp.Υuum'E3rB+܊Z S0GH-e5)6~JL˭kNVgBK޿,rrKriR^ShH:P2.Rx?i"|ngCu{C Fi|Tէr/|nI]uͨ^:oK/Z\Fs+nvЌL`P(ןj .%wyחM}Byn惺HBe`>ʹ*:gQOMh"@1!9e[{V*fJ:myo_VQ܊K d$6j|l66! :a_$i0l$%]M<Mh$`-=3QǥbVa}:%n\ѣ/+˰|n]&IqaA/Ѷh$`ϭǭ9hIӨw<QH",[Q~n N#g߀rZg<>.nL&ɑ1gqu95'_5b}U82oz3E#x|n|52p.r ~#JWsnťsR `2 ;~ F 5:$zmRu>7/ݜ`cCϭ@HSbm4dDC?,I8|n[) &i4BtJ*ٞ"*1+yIkJh(7P|卮RVܒ 4PoLf(0u$f.~V\z'-D2qM,ߜ x\2qn}ĐOk:5FsK뇦$Yh9l(1ͧh%(|nɕcz7Awm+xSJJ﷟V7J\t%YMi)T;21[qCP[p^2%ָc2 \YTCt2?HT[ļE=.ߖ(Xc*>WF6k؈y)0%jg_TNue# }ϭkiI V$*O.%7F,Ua5]N!3z_Ԧ w#W SbנN.%Wݗ+@ s_JƦ"QjiK@OUFjܮeXR,m -Vk W/+{nť:#Ġr AAgt<%cUe=B=qi-Axx[ag~ *F#{n;cH2,L5n]"H"[boSt[Z8X=E%ll.cùR;v< (TEg]_V܊;0hSFՄSON)Զ ِD0ʠ^fxȆF̱sȜ89J= 6(`(b !1.ov3Ӹ7V6܊+TS5O]/K/"[qNҶIeETe*a?5e>.& mU8 T颕E >{yGnUƭ8H9E`H1-Z\FsKn9v-Tj.ϖ" *)ʊ! 38J?O+|n- (Ǎ@;`dSϭmh.!!UE-?dz3PsKiu-qCƶL %.!u䪛_ne8>.z\UKzOͨh%pϭrN:7 )VFuɑdԄ 66+ؐϝ=K`y e (%J SUC eoS)PsKht T]UVP$zFfSaϭuN˂S`:k\P/ԥ.%w9'4&Uzռ!/,IU# F6I,6T[n<[=%,x|nŝ;m S%T3_%IM(uhp@Knn7|AC>[\sK\cK3DPD,>bެvKS1jx3nsD{VܹsEAPȷSY&Ahes-.cʼ)ro|2߂a6 +:aU7^[nޟ66*%$;  %|QHbdC#fۉSdvtUVG E0>ʳ}!rXYޑVͧhesϭnά (̯*Qa6 XsKl=v =gUwmnFs+&S- W'6 leP|n  Qӕ^UΝ>ʷ&=)楚gEX"6D;%Ny㾢\Ks6 Ls+l_ySYU*/ Ԝ*~R& LvotlcQ/s+jݙSv&W|`;1MRe%p-P*8\WzU{u_PJ"[q]]S~UV te>@43˙ҫ RM%;*"U-aqE)m[-(l,c%6FLV].2[n-~b#F(cWUŋrKǒ VQ܊+n(HȮ\+kۂ$_V6aܒ[ؒR*J&Ts+yTNgU^pF+0|nɕs,;xVnHx]Jxչ|XUva%p}AAڽ}=ux$kp,a`$0m[b!ɋD*`![rP[{ .:Hݗe4>9\ʵ+ݪBz+⍟egE4>ʻqiN͋VO $Gw_VI4HVK :nl0ܔ qӭ: [* Xs+l}K7kL}zֹUwp|(Em% V\yǍ; Х`KF+[l; HVSὄQDL>.φ \+`C/vF|nI:SUE۹g˨|nŽwbUŻ@K2H"([a\ׄ*T]n͊wa F6#JL")19tdtE:ϭ}'N;SnU rKXnؙ.%w9Dk W5!MQO$ V\y'i__58zE\>V(7XVv%v}DF"([AOJj).IERQ"Ʀ2$[RgM-:OI; _V1܊vL`nU7hxLͧhes-˻vܰ*+I >#Ae$`1SUͧT4$<=(%_6Aܒ S*ʭ2\ONkhFE+ˠ|nťoaU Z/bgi|D@>B9eϢZ 6Z/hes-)r5d)J.un\~*t8Uҳyq܊;y2d )^"P  F6Q܊:0m 3$XAά^Lr=\v]NFsKքP2 l[L 'Rʰjx|0}Rt4[b .a:A}eEP>ҹvi>ݘŷFZ/hdc-PFa^IV oz"3_y,MECyX5)?T{s Et"6$ʭtBZ&"Sa/|nE;wT+Z}=oe%pk..FҨ)V =#:UoaeqFs+KL4n斲fET>ΝCVUPd|tK)PsKreB;ǪC4AƧy_0ɊeD>ʳ!U>S5,ɌX~Cx8[X_ aϕQSU[L!?5*7x<`VL2.>Sy|#?!t\#w\rНk"bIƧE<>" ;a9= nL`aWsKrϨ+ZuWzG.χ^v܊v(Le= ]fS ֹJIsYu$,ozH:"6Bʱ ("sa(60-籓ef 8=F(|ngL3 `LOrvH"[bYd̐oǣXRaO|n-+ЖR:^e235@E>3V<#LoK_}zd6܊*׊&S)) 鴆iz/+{nŝ; z,7d4M) XsKltXt]iVl|J%ܯPyB-6d.n!Gʰx|ri:#{nEwo2)od|Z7.„l$`}ϭ7`lK60Hͧsטզަ$$GJJ浭/;9sx$-b~{A䁪JG7M?7̟dEUi{؁)-~ۯ~nCp/WhZ?|,ѭb[ʂn쯟 z^qV3ϧ_T.S\^50ˬ9W%鵌]ɑCuk/ۺuX%w[?s{CW8?~ZV9\N/>X~qz/9ڣGuJ ;Aܡu.>|< ^)5a/WX3tL[v"a_=HqACκ^:Ü7_?=_0琤 5bxlb_='~6ً wTq5KЪ?nTC? 1nS#{B}AO*vg1Jc7qn˞ӗ~*|#lgmp{F%'S=lentB1'y)DAJO?w.G۷ǂZjVgI`5&QњJSYbaնd-Imu RNug|ř?3vpeN(.5ŏ0g,_#.FYM+ײX ^fGʽOOjkܽ\nEc5n֝Ssÿɛmڷ9ZYʓṮs]+|l60G<'c` '/Y>r<1ϱ>V|h,su'ҝL^q|fߒLkT߲ךg| |kMq}+_O?G'KYO_epZdT/G+׀,4ՓվGѱ úþPvǨ?/#ĺ%WEl[ƙaY#ԏ1ؼM[t*/2uZd F*ވ~ adcL[b/W Ya}mKbIn'- :e [|0ߦLV=\*Zs,#l%8|ҩRpǚnap?š,N겳 gtZܯZ yŨ*OlՋ^V*bxƸdrP=+ʕi)paR0THaenqm "OljQD;A V™}ƒD"Lng1l] L'K' ;N5`,ƸradҥyfͰu{ХXMNF#< k;'Ԉ qY-'g(Xg)F6i6uUAPU@_sSy ;֏PSed@+o`i@N,D]l#8ҡb!8Gʅa񽄓Gދ[E#΁v'[;X.K ?W9MeNnEmzǍʸpeXϠR:AŸl#ܼe!8EZp;W\BzPn钯2R8V4p+JV6AD8s7_3mٹ@ 塑&y%"@UU Nu?ȉ鲍p|bʰ|FG ɵm\BQn/D/=b:y^iX>C0.T\fʴ :1<9dP_a .S1(RV3琛K|nJ% :/[B}b!_}2N2@R"Ѭu,ҥr+lǞBCԆJ_6n߅7UV #TBB1y65#'̔V⺶dػ>k=puO^O1JOZ\ɰf4yOlC>E+ jq(cO -ٸV^%W"u3PJP6"* f#<nŰ`U.##f-Hӣ_3R3Ҥ=G#T+"t=<]5,$Vhԓl.SrK/4_xX N! .tjQ 'O dyFJ ўF6yp%՗DN]D$ݲ^\mh#P[Q'!\ot5q=9V DpzŌR0ȽYYh#$%mK.6O5vy#M.E+$܊0YKmqc(Q:R1vVPC* }Yҧ`^rsݦh$ '_tȱ0O|5 Cf !RrSچesnbTpvw5 #,顏FulJ A6,Vq9^=Ʀ(HװSmO|ٜ wH6)_#kVO?>`O8ͮ+(YM+O Z[*fq+#Jb6Nܤ~۷-M{K:IoEm3TR)n*FkfsK|ѡ4M@Q;b'[^V[axҔ*<&2h$`I[b} b1ذJ1)%)w;`3T3KϕKmy衎VS-EQw_Kh[La&pn])ܮPlfo U{ZXǗ:7js+:p3Ce5gJ1SUO$OMk2X|G޶С?]6)jxR/zDlP__ѱD1Umo lesO[v@Bvebdjo` >f#u,ARO'.4IKS,c<pnUs'6Qml(7sK܎Q~Q'E01"z 6zJp S]g7xᦘtYLi#@[A;ƀ?=#yy't|Y\n\_t7p};T.!%*];@qic$O{b4pn鐯E Q bwe؍G;Z\nEiz}bBr| z죑E, n:#nC%/Yԇp|c/= 6\^ \cGl \zX qAkpNiCR"|HwՄFۿ%!F5e&OJUKGWɔ} T䒯E,KYic+A_zsK|bi=#.|ll/xzV~џ%K"׳Db[2q0[H%Gon38<:.>m\%p|aPs#x1I?wbVO-}QZbl%.,zȩhes[q; kǸ;R$D+ܒ+Jb##nPe$p*zQ$| ד;bAr)Z .a8tɗ=FrW܎'נ_ 7^F6%"zƉqIJ @?l*hs+܌AN,W*y:N=8%|Q-c.IY{bAYv69l$6"vb ,*w.YyhJF#  g L׬JSnPa$`M[/r"HyxN9mkwXK_7Bj(s.Q2}&pn/ sH+} ʠTUҗ&pnHG"<C-#jAV6aPڔ8 m b+".߅}ojvh;&XU<}X^T:=*RNjΕEb!pnQJ)9M֑=¸:2oܪ-CφwcTLۡ=R6^Vt_zjrC1NmA3T5U6G-=1ny/\*d3UsJb8NCXtZ'˒:4Ʊc<rVgBbGzp 1 z}/H4(QO@E#܊[= R7LU@BF6;%v|`k 8XՏƊȺyҐ6KXIZnD,4̉4]ޮHYfMnI 5N_V%A,w_R/9//ɱݬ*les[q;R%J\TѥD/?L2_x)5ғ/2<pn鑯>/NI^-J|Ef_V6{%FT-^FlxT ՇQC["}a"W}uQADveEH{Ѓ_vä/+a[T9lqt~1I0I]r7buqtB{LNeuKeG-܊)t\z5 y^,nٸV󅆙RG Z` T})AVq_FO-}L*R*L+]E} TDrKA/9J壤D%e%pE[qƧeJJAopK,td#ܾeI/ؿRG0#ᆲl[b;{p2wt"aKLw6;' .ivI7Ĥ%s7_V6kCr՗)+׵&!An߅u/1*H-oӕZ"d~ a7W"F-Ŋ\e67*DL~x4X__iYwj.j_~JJ_o|*(73Oe΍t\*-]ȣZAvUW"y,-2Ɛ d{m5>S-ڥɣpnmJ.]V[1sSLy;^/#5:pʥR*\מt;vFG-=H"ai>[+9Ue%p[r})"aj*[UInI.*G+=܊;w0r{ߵDںv$Oױn9X }Yҏ-:Z]bxG+)dž-R>XЖ)2έ,nu5ں6[mM&meldcU[XFGlŭ$515M|YYfEBT\rFhjK^VS- 䌠AFM>pnI;ʄr }1i5e%p}AYiPSBSU1%@ִ)&=p vb`0 մ-hEE+#,rKD關jxIiWLjo {^/#˽ qZX9ǧEϚp;2,.ksKnV0`!nq`eI|ai$AHm7$($%0ְ2=NpnQ X|O-1)Eh%p[q.F.O1 5l{,vksK,DQ+ gނWîH&aM0ڞCR'۰g!.q'8tIң U1&yd.sK.Q-̸g1U3&y-ԻR( F, ի*,&$6 Я,@D*$V0x-.G0@/}P~Vax/Vɞ^,=^&T1UDkFu.X=`S*^F;-݁6ѽvvGKJb 8R׬o,".6z؟šVHϸ väU8%TM{VX6n?0ؒWF*(Vnpn$Q \3-z5=*֍;t0-`q0bY_)DujG 0: $ ucWn`x6dӂP]CS"}]O#AHE!hIɠf~-dC9q~/EZ#-(Fcll(7hsK#%n. KW2ub$O|5MW~T.pw`vVJ0P}L=Jb8maq0`}b5MKb(u) `=1gKo ]o2Cy\K5X.q8t# /Y bą˝1Dl#m +ܒyt@}buyD{pg,tcHsL9cC,{V KbSF+ݔ{R6vMؾx7k F?-]OLisIP'b'nT)F#Kn8,/ܒ_;cq_Sy4vpn閯^T<:}bg̱yrjPVЊA{xɝ1ҷy `UƩK #ub@:v:[c~ɟzYw/AȎuղ F{cn3z >a?8tv03V2N90}v6[¹y 5nPgxZ׳/\g;}ܒ8\w|[ɫ[>ׂ;=2'e~d+NJ`"%3 [`/3Kr:M^ݿ,qw˄oozaje-bL1¿t?sY kl?Ԡo?`cc?S,%IkZ Y[u ?㲾X?xgWmb~my߶G"D U_s꙯ݢU;d+H:_E/yVaa~/rPS/9W?=]o53\=n/[̧__.B6ڿ#F9 :)|V0SȭZ%,6=~osu3Xܩ:XPՏ/*& kAjIokԯ:ߋmȿ V[uD;!=yU2Rܬ]oe2A[ɩ_jP[Z'n{w _k d2m] d^ڶ,UO͝{ɼEk^f[ټ!>`P-ɻ ]{b'6U_Vw_ J~?eZaƎHo2T'ZjP|㋾."t/J{{},l&U|'scO&rF,.SVaRA}]o%c뉝mZa.췒n_a>Stbo[4%DG?~+ Ol-_uWq]{'jܯe2ԓw//5}]o2d²4UW_ V!-cFPǥ=~(|rc#.2fÄV,Sm)]9~c(Rfa%8^PȻ awke G(K_^GW"79] ؓ/z߈=( {?`_];IT ׵c.+=W7]o4c1Lx/L\A1Eޝ\o s-'xpىw7EV3؋ NP+11o(RB~# E(`` 5V6gлz1{PVAq,/ʍ~ՍwO&>q[A|@|2믱Yo0/RtGQΣыw?)G]3;#VTOš:ϥAwO J^e0<"xSA~ImAO_9=`ޘޞӃ܇Zu{CﮊO2oť2qAS\z0xکlOg~# z+O+(÷ճټX߱Dzc3X g_xtA-AxBY6$@c7F6;͢g:ڮj=(x ǵ?:~+({Ol}PS?F6;UoZKR{NSqF7JrdzO$,d-dN7?vOjo_EF'C0ƫd~+ΓaG e764vtAQy@2'ǻ 4σlO1BWG};؂G`L"UXEF@tWyP zN g(rH~p 8:`~"ىL\on`+X.~*w"4.~A!,MR{ T$<묊38sq}ՏwW+WÑ,OM/똡׫# L̃oC59PfՑw_%ryP=z@YPՑw_œqH秜q,پǻJPyldSSZ@+ҍ:f _xtAZy@@eRYG߫ J@l&+7R(2vUG㳰H<(ᡄ=P}Ցw_NA#[EUG}]oJGs2u| b%@퉪%T }#[Eű8e2ĸړ~,j~'~BT#}y0߉< s?яwWŏf : G3W?lw='Ol{aű8;8gs_yU9m;)ׅJ?KfifɌ7 '2u{ųSꯎ*wJs>|Ցw_8X~p ԢwExVyՑw_Bcr~Ցw_! Q<(h[;t'[2#.7Zcq>aXՑw_N.o^ălКdu9CUuׅF.AO,=O Ͽ _1Xѡ|@C)xMz~ՏwW?aWxUXrsΣQoz rI=xT/KGB,LxZ o?Zػ#6f[AqEZq`L_UQ+ ZD5 Ix o*gb|+@O?Ca.L!-ÓX~woG^4=cƎ<7e,CZ[Zc調? 6VSfDAp>ǻM{>~7ej9~\PE!OGWxwuQ) ,p^Oj?:/z~UE7OE޽\o? ^xʥi[yPW?6uU?(Em\w G`>~S,hMUj+,Wxo+Z?Q ơ,g7]oNGR>[*llԜ~M7x~ё ]X e?/~S5}jܭgƢ]EHqO_x4_~|o<$7]xr)֜Ѩz?xh;1ً] /N~Xoj3g1ZkɸE^@RTjY˃z ꋅd"$"n}\_9.-1J*`ƎGXFs lKģVe.*%5@2uOj_SQOw e/u-ܒ!{ɛ8Wxut1M-RVj|YE'S5pCJϭÂ" X|QHՍWGb,6$'*+ZuT<__uD$="[bű#r _uSAH-hKLdC9sEC/\Lsv{̟m Sj|ԥtG}\.*"%Eenņ^ꆠF"n[B##n9؍g?d<Gv/"j[b#KQ aՑM}]XsKl|V XGTWxTPFsA4?>9ϭA3Њ >A^짠XņʱTЭ[n.&"}`Qo [P8[ XDsKl8vLTݮI**C5@m({@kc0~zPT? ˏ_/gvݧFI#w]~٧ϟMv^ 5OxGm ;g?_e~eϿVp^?zoЃ6kǭ>zt[&@7Yy|8cVnX~.TE6>/*J>/4[oۓ?.nP0хM/}ThZǿ, §4u6ln v[, vZƁ\ ?ȗsx<( <))A5guҿ~ ~COwOp>Z4~OqG&yO5<矇Ov g\(>?NqUhco?Xo ;l[mfj%~S/P`̪늟He?׺|QVS]'wVrIf_#bM\Cv1+kH VLcnn}^Lϟm5??C ?EG֤sƸ֬хp}>Xvu=Vvzb~9rH]_?hz(3?__W|2bzŷ7_Kp_ZN󝶆/0p|)[kZ]7oo}ejdMKn8~sű&"W4SZZs[62|Ŷ~q"Ћ5oտ~mے/za^'0?5TN, xQt|o֮/.v ~iO?/]7o\~K)o||ծ1g=F?y(XP>&m$}\_(%9^Dn)}0]9^bvga2@ .|KDh<=:yeѼ?_}oebSGz.n軁"B g;F矷}?k 6#u["ɶ%`oWmÎ1hR%L?G UBA@dFdD Td" YaD8D O"wؕUZBѶ6ѳR7yׅ⅐eEÊ@ U"d_&U Dׅ$`[n"m"?G·DVy%(%^^D$I,b{EB&sWwDV=M'-?x]ȂhzGB   bLKLKHLoa商r r7PN -&cJLjVPD VXX XTX^XM&+_`Uڃ[OүL DYNDet^-CPM&+oOQրs@ƗUNDJ hR;YD] }兄m'`z-܄E;kKSzmPK&a7vNa5c-6aB$l7X&_Rf6Kb]w'ȶظbpl_ `{m E{>gx&?-~6>O 9>vn{,Li'aw_ykh;>gWG˶k }^|{~;Ƌ~vp_+Qf5XsM%8|5mtM&coݩ<> M7cb"MO?r˗kW8C}E]Q_YTEe!ė#i*+!_8+Cwztg>[<~+|.||ko|S{_|,/!|JuNk#1 <^-fzͮy֯7Ǒ]೑k`e~SίL{ozeng_<3w*A&+Ԏ_ÿ'6k* ?1Dz)qi!𽺄-r!a hWuyp.|G"ɪjBWBç%7 . 6v~YFks;da \?Lb^տ3Cm)%{L<O\(׋d.|O~)Ep$jBK~Auzmʯv|QX] -99~[?4©{A8Nc bY}]Xç ^N~'>/8w.PzV,)Op2!4\W`zo*Wn'3q.t-/~Nt?[.oB6*6=d.RqQ'xrp#-'ϗ'.xn,9K ּj8>di5l[{ [_F13ӍE:3[fEK4M>;giSq)fI}9ho-7?}shI\'<6Ͼa5v#Ο%D%Ͼ|>* u SuXx&:udG^g#=uK3u5+Љ>rY|ɾ/Fa׼J79q=3^>z_O|4^]^^~džo,|X˟{Zu0ocӄ{"ޯk"듕oh2uc|^Ӳ?/_?D5VJącl9H3~1¿]F睜+~\`kuEqM,~fSaVGї`{Uj}Rx%wQ\X1D4*م# V[yWva\?&g#=j]Ey3 ~;ެBj`Z  *,ZWrsD[׺ ΅~ X1XAU_^RYqcr).HՌBJަwePڸ_Jb' }?goo's\T \Q8_1~u՟6c 8/bH>Hɯ5H;8Dܦ;i=]ˎ.cgD1찎=l.K9V\QjyvW% w!7cXF]e$`Q[2Wj/Ύ=V0*2:.J Do˓+2׮.vs+(GCę0x5D#\2_GvrNy]p\;4򰱙S̭bF+o/J!+^FYu%vAJsEiėMeWnE%WAS*]`wi|Y \d Vy_S>|ha. "/+<ܒ(M؊_BLڨN66 TAߖH}t$QHb? rQV"qTzV6{T[OOpBuv%D} ]7x݅@ ;1|#2OUf5  Dg/c`dcY)Ď==9aX$Xq6/>1ƾ%fЁ!\gSپ @Q-c-n~Yx|nIВA/{ܖ2$&fTV܎19ugŁ-ˬف520l.%g%d=[g$*'Kԓm#0ϭ̇mQysDċG>0E(S( XsKͪЌ*"_z` 5B]Ux4D0>bz@kN:U+]=NH*e5X\sc:H4 VT4 3w0QlCG㢑E0>zîLi]NȦ2[Q'ͦS"sGC_M3$E,"%vYL?LB?n rPJ"[{DRq݈ۙv q9,@|nEA8txd$P{9zLqVy yqh%pϭӹyXGQKur8[\sKM鴐2GH"[R=d) ׃S\r7)l*ah& BW/ч[vD>: Jã\q:5eѴGt Fr+jQ𰌤·ܜ,nc>zLh: ~bgvcKqd+@|nŝȧ4=q[E3Nsf~,Ps?;n+ TԄ66aܒ1%C3@vݏrىVq܊0<ǥuV} Б)l.%wlR8<@߁`KH}b#hG1x>pgo_ 2Fܪ#S>"=Ob'\;J'l,v`p=e˦*|Or %iJE+@|nY]`EqCȃs̡ёE2[rOV\7D=x ܆?c]`G&#J"6heD>^Cqŋej\+ܒa%& ߝs U;3XbGV6܊yojR5!%tDCm*U 'SO@BX(Q2[aYdQjOP I,u.b%׃L^R9 | Ρ#lHc &UV\ʡANp`Q1}ُeD>z`qyR`in al>[ \Ds+n]²Gv❃Z Cʳ/#|nU]&Ս8TRPَƼЏ!2d[a'4Qުј;R5E`>t;IUŹp!#M*Z\sKGx24 a;C K}jRE# *piFUVj\p !ץ)("%Ri׆AovGa'O/Ъ勪D#?rrڲB(e$`)Zb=c.??\verݬJ1F6V=vµj5 _"SP C'":W<;/Dnq,gu׋l$0)Zb=cש+sBA]0('3J&6NwRSmCqY^5TϤT_08?YB1QX&ololcS%ZQ;FUͧaRHL1`N法,LjEDȁ)ͭ;](U6Zb+Sstr98Pf]\g*Ԓcz^\!㼙вTPhe$`h[b+_IwהrE8\9Iz~IhĬki|P(|w3Š<5Hlŭy5`(b`zV7j~$؎Qʪ]1GfNqƸ[lD?RKw25g[~Bƒ3jBLzIE#8Dx3:/شcbԉQoͨhdc?wDF6bS4v|jc,]^J"[r ;Aυ}/zz e4>6YxJV JX>Ў.c #p|nA֟O81 cQyY\s+.nd>cR<آ*%Ճ:Q긅hedX? Fz|E4>>0j1}΁Q>օ|S2"[rY xSP@N22C 0Fܒ:Xz!6_w-M%iКRȦ2$[QF-,@oO`']P4[b'j>Zl_`*=b #x|nE*ycN'(>򰲹 ֹ'b;F)3U7`nVf1+㇕E@>⢴#U꼷${*R1m.aec3 ֱ}T"=cHUEF@"[R=sd',Yy|t2Ŗ^SyY \˭U#? iZ1d AE-Py(*YjA5'T^V܊1>*󙵊2iAS,.(H" [b e6ͨzBӖd=­`=IicCϭ멲cP}`]hC|PH"[R+9.M(B~aR;V6ܒ G:5 [zD)e|H=,1K)Z\s+.:Z׋x+,Bf %S}G5PDsKtXTzdԺF [wF6 ;0:t$@K E6F!s;?p!.JU]8,܊S0˭cs!&P 0 Xvbb?)/+X|n{!zG#]:+_uh68ODdʃONbM #)OH|nm[TnlɅ*Z3#[ \DsKh?<.D~VK9+E92VXT#RU>!T(NF6UԒ ~V(0p(}6D0'J"[rЏ G:by3)l,jS aUr6ЃzH`"[bڔNO34,V (ꕆL_Ċn==2[bFԝ>=Ǧw;E >RM(e&XE glO'-r=I 1g~ &Gѹ%s!f{TҘÊ]gl m*UGc=!2kQ_Yl.%W{g`sV,# )/ |nE#s#ԣRNdtyyGPֹ2X*Ydt_x?P1TFsKꂠN],Py _b)0?7@E>XϪY)KKbw{R2 [r ⛲!,\[wz /;q*ԄH*Yi\̓8̔!f0XA%y4#>?~hBE+8|njFyg7X  ybV7X \sKh=rjw:i+ÈQS3*PFs+(;n{XRJzJؓR^6QܒQHi0[龙RJ" [rkJ5JˡjqS=Z2[aQHǽ1EF0S3*Z \sKzg4(3o"֏[P0 VTAAE&-sZ^tMh#P9.Д*Y9-acˊ{^J"[qI>*܆Afꊥc[s*Z\sKGAgU4@x̕d>,Si ]owuC'w#\g+KJDgH VJ;ڠeEq6XAxG"j\|.OLRů JaVkKЋV6`>.FNLj$Zlg:J"[qI)f@TK3ex]#8|n֣S()wUNvb2|!Ȧ2[RDcqUҨcJ[7F"[AŘzt*껞O1E p4Me>qUF` ߗnzt@OlAćE#]&`xb-1\Vqܒ(S"WXf jhhdcϭ,yF:b2 B>z81D#0|n]LlS}eܔb1ԓ/$b#&lDJ)߮Mi+*ƄT6~-hRҕCЅV^@)Z\s+( ?8Z]9-e#̬+Џg' Xs MԁdfL?XF䓑Me$> ˆ|EcUPAfW5 XsKGXX~pQ(Uݸ0maE >³<*|AY+ϳ&0|nŬ R~F6Γӧ^a&L;kl%p-_r1YM5WQҸC̤wb V6K^M>T2_P+F_uF " [B=dqh2ycU4_`Iy XDs+g .%T=7S`XE U4e>zہ*_9NƘi+ 1@E>za_Ui+ kROT&rPړLZYj}W`efIH lcy"Q͏SKuc%0?/_ Y:g;#'s?PuuQu׉@<@8J1*Vi׏G:S4lX &ϕjyQ~tOf]̼åxsͥAܳK~Ra/V+zϟYê,tM6{umc$J"Y5_0)va!̙] ׿ֶAcRj<!\U_*=#n_ϧ2o/}ۢ0~lcV]J jUKZnW\c%d%s)t9+mSכeUn0u4S=: #*E~WPC𮄅l] -P̄]AGd-nRa[V,`?_}nYa\j\5ր\uSˬ6]iv?Y7#@5{P'Bq3kfd]߂6-5z_ڨcIA>q%*:JجcXj=pҪ;:K:u;Nub")]S(XO+r.pXj ->?3.Ͽ jsy5=k\ߥd׿h# t׿W\Pg Q^Xnnz^@JѹHU+jh3>ŧZyuXjyqrTo4W'g~R:Z\k??W.xfp/6F3~'h8G趯Nh! *~ -G~~]8,PmB!Xg,wc N/C}9p"vp"5v?<Ҡ+v׮7Zetw2`h%tl|u.qfK1a_khx>_O=H^zE=.7j5_o*K]%=+=-u)u%>ulqP^,qb$)u%U~UIMAmURj>0Ll&r+K5?0nPIUV_JꖇDalsH˭rJ@䠤"T%.r\ UOKT_R*Bf#ˌ ;[8w*o!yY2*Kp5<+Rހ$QE)$oX@2.6ܔw>$$b|# ˯Ո*ʪ/vUeZ2Ȧ˭rli/A&so~/e6]nɅQZJB?Υ]Hm*rr+|BHc%*UǸl_V6t%c!I~׫Oj6m\ O 0¾㛟̮ͧh$`J[bٸE~oxU 2ĝ-K1-Z\V\:ח4䅢t}yWqfTȥ˭\ށ y!UǸ*C2L-r΃M61 oAU!z X~ԤSAjoR_JbJ".޸/Y zU1=NE/#d +&;Y.ƨ,rKk$rӫ虒LzX$FLlB4QٙwE[ mKZ+Z P$ِ4$nz70gFHbs6ºd㉕t$]`%T@uE4su$ ,T$mr'& z XV؇xh*4EB]nɅLM`8?qV6)uWa$HFB2H-˹I 3@Y$5T&VTZz} ֻry?T01WRSKMJ{ty_KJ"..Ϫ2(&lغÒMeR]nEeF, F~I E#|KB~UĸMrk>E#˴ +ߖ"^'J^ԇk/ X_QĆL(wAFK\93yY P|V\yXnJO])TTf{ C!=oKQ+TdVԆ["j Fm恷ɍQ%l.rK> F|X"@[VJ".V)FSTk(n<+ @]b^J".cZK"x +a'no]m0̭˭M͐ԒBAUz:AȬ˭\> sPuګ:HN/ V6z\6dcSWxE*9Er]n]MnPXxPN{% .r+"Acz-\rxZ_F6uIϘ7KwPPU ;s\Ev]noS30|TՀĶMDC4[9wyIqgP2HܒܙE.eⱍ A=~F%."W "[BƝ@K,X\FsKv0d\Ǡˡ`$PϭmI[y$K"F3E.xPsKI%LMP<|Mhdcϭ ,0ZЗSOj\׌j_o܋98K/Z\s+zpJW |tb*FbpCCYi)#vLf&ꀷA}Y PDs+.P,a[8\Of2"[1틞XȀ'DOtY'Mڴ|nɅgr+lԩpuy2 \Ylr!3,jD 4ng]* TDs+\c㋚igM.Lڇ -")mtLj,qtk:E+Us+ns 74nGj'NHml*uj^l6 \ ]FWsnEg]lH3gq2hg4>ByBMjc5ø}Dg+p|nD"ga{L5,fXm 6*Ʃ3[rLoFDlH&$iȺE,>ʱvJL g:k/+sBNFe2fӶsrFjw[pVo?vo 1[}h"UƁ<1'Eq$)%W~ Iec``{{nEq/CHkC'!܊+ZkPfKD F6ܒC%/);$X:9xOlDzQ\]Ӌ8y( \IF "[B[]3InH+WZ oSohdc}ϭm'KY7K;_圼x;֏3o}TFs+|[‚ҽCv< .ye%p}B'eA)N# ]p}m$r+k/ѻoH;fY]tx|F6:vV.Nc V6ܒۓ yxIɞepa{nŕwE:۫'L h$`{ϭ!} Xց79 kԱTsKr,?!jiLJ45hMh$`|-˵%?' KCyvf{FTXF{N*;:𞴴r=OᩗE=ʵ';WvhY \sKr҄r䒫uM* XDs+YcYeXFg.`es-AJY5/.~Ӝ FQ܊wHBQ@An]5MeT>Nͮ ʥrᩌaKP+z((6?EhG"ʷ\xSZmM0 KN+Z PDsK\l4+cJH(-Z\s+.[Z$+Y$zFQ,YX{LQy; L@2j^xQ<=y^~mlGϭkj2Ari\Џ5pN*YP_LFı,T)j!'nH{Jk.BsH"s)\xGFTV6QܒK(++t,0qFq (iIO.Sm VPy6Hϝ^eLF 7$mED>.)9 Z:gv<4@E@>RNP椞ĪH/ʀ|nI]uM&s*jxAJUR.WV\V%"Ȱ2ٞl,j!;w L^*jxCn|?5E@>3} ftUWVjlMD@"["cBUVHdyFϗiQϭugNʢSPыy-dVܒ|$$A\5oK<}sEͦhes?Q[Zn.ϦK*=i܉;R+|nťwcʎӫ %2[aΞv)=y(x[Rk[ƭT|F"[RgSSS-&)޲V\ՕL*xUny-?*U5J*P\{|XD$b% 8E*4ak+'R F w#V&bq;01g#r%v4H&Wגּ%{S2^VغHL:9f6jL6ZU@:{Tk~ Xs+\+nkJ*P|Wl.%>pWj3[Δ[UmeE=ʻ%Y:l0ժM)[V6ܒ#wTrm-~b#`CDֵ Ώk&VݚS.*ޔ[׶=(-ᗕe=.-)ӪⱔkdE>⎝HE[VK?ue>;0{ ZU/EVTݚSRky?cOVz ޗ(rK 2 \W݉V/Lg/+H|nťw,9(ڝmU!rTW+ކIa6 XDsK+$|Q-dRlֳl.ưqGʷxaJ{ԹXkݔq#gV.>z<_V܊;s.CWȵg_[1/+7rjK_&S+[U4$i Q"/#|nsC:gMVo)hessgRz)٪}`uEL-jrn *^Rtn/)uF+|nɍޑ;SUE -չu_c$.CTRVUF]e$`ϭr'!nUܺ/ĤlOGI!cUţ(Q08')BgLxE.9@E`>.ǚ&Q-HU`UҪur5 V\5\ R@mxzd,`%p-|M P^Vzh#|nEoU i\Lj".ERq 4|n ]5M~2褈?V|~H".[aΝ"CUU G+ĕV6ܒ[r7L0Yɱ~D˧@؆FH9V5E7d:暈O=-V.*4Wfu3dz>suOs+,{h%Ԫ+I7ͥ`#@ϭcgMJjxxp~h*E+˨|nɝe%N[Ԫ/Յ֦1FA:5FG\9Ag[ZXs+,c% \0Ʌv8W4[U ӄ$t|*XapB+i7zgMh$`ϭt$|# ;@alpF61 idO `4Us>Q3ksϭt |[^V /ʣ0ӰamioDlH_X'Pe$0ϭuNې;* |W~k>E+s%w97Bz%X}~U :Qhdas+O̓^ /7Sa,v*`;ǘd| &Aʵgʰt3jq/ͧ`"0ϭ7n k z&Zu&MmFK]hdcϭ3`f[(|Nyx֣>!s\H]s +ժ5pʅݾS)Z Ps+.XiF0Twq3ӰF 66\ct೨bUwEfgu6܊vVT4RZND@|n_NQ,^Yͥam<+b}@'ytZW[Hqꑋ5tشWPKmOװ&rl\Z1.efv/{ܸ_?QwY?o{FCW8;~YV9\N/Ou׏'O_{|@(J=C`!=Big׾|D[{ W0(c2 "q,r1PS 9w{KGc> .WPUb>~'>W̕g=&R}s7JLZ!P:~GB,s핆&U٘ sW9p|~zm!7?{ZhYk/xbh]U/o=NͼI%v\@;پm/?9ܷx!s@ 1B Y^oMl 'Q*9lG`?1Ѱ!ayME Vז }b 2't Ǔg`2* }m๺lџQGS+Kߵ,?Še,0j;1?q@qLp[C]cn֝3r1Sϝmg]˾:˚|Uy۱Js_{#l6xyRIhOǾZ8<~?|>3c,_#|%ŗo?p-{wane;5 ^Gxj!ҿj5ikz 5a_y1g6ջwU+ׁ֓9pNoϡӯTİg |(kf6,s`+)N+8UXejټR[:u C12Ϧx$F?0(-W(VaWp&eX׫%N ~X \dt:w㙋Q]i%~ F\\*ւ6fyie##duzꅻqB"sMV9Kۍ #QeJnn/FU -0z XV؊BHǰ/26L#J˧Gn`InNq`(;0}b.LnSsav.j|̂> iM~s!8qb qfX5a $߬v9(2br+kVm1n7zXrq,:" l%@iL^-eqˍk߳J̴-ݙTv}ׁLމ"w=Lɭ7 p'p ŰHIcl*Smrkuta #|V'֍PWec:+q!a ȫӣ1T1mՇxrKΊ1tI0':YG :n9.yrK/H7,w >~Ć2'6 I} ˰ϠV:Aݸl$e!,Vh,A=ۇrK|Qd)m/2`5"N:q?;U_ePnuբc> 893VK jc gmܒKꋕQ'L~b%KKԖql4*<*'ogw  !)ȗ"{_3Z[J8>TVԉ!!v dջe6 $u,!%VHrLrW$xT:h]NE+)$7N-Г׷e$yn mYs=b76Nq3p ʘ<d*v4Hn-$ܸ83,%~ܦuE~F#,5\Fv9Dnf?[䲶`r[= p߬4 |w&s0k*d:CRyʠHy@ GV)_ETnŵQ]@*d܆1V_nū[)XVWoBI6 .!)+tiA(R}ЉTt2Z66)YvuJOvQw6BJ"-+X־/lM}+-ZOeO(}ܙq84G.rrK/`onp+hԣl.rK/=ܵdoR?Kc=Rz "vȊپ(~QIIZ#Jp״q*"dRx͘X;Nn2 $-uaq~k nȫО9=l*3rK/F 2H}C śyZldݻ]Mjls eR,e##$-cţsc1/URiN2.(Udi շn d6ȇ˭'t܍+_a>ON*FxX W#vAȊmҹvtݓ[eƣrKKs~x4ϸeP̸y49l.r+n0,/Y տ2nҡb,%򘌄5Yz}Yr_]vЙh%l%__ڰ5=piCFgClȃFxqVӗҤcz D"_nA^d;CzV0puGf+L1hW:OO/Ql\6K-]1lXؕCyL,C# ;0<]186g؆\HJ"I0mXކ}ܰ䟻$(s!mװ0C 56,Hn+xwt/VjFG?Іs=UlIg+չ[rE)i-m؃jY7nēd#@O[A'n}{\G׵ƤcJe6/v̒L?~ڐxeqGQsK|b$!R&]a2Tl$`[aƀg-["G<]&*IF#m풷D1-u I6)iCFn/2Tۖ:*iM#ml[c =@\]bKJb8.ʔmW~u٬'ngU&`4:hs+\Z2Z+M|L+8_0n/snWyVTi@'˯ujB*cee#Zh`umrhynb"d;^6%WKY9crUm olesK[v>9}Z?[ӐKW7N 5n_L9u%yE`1m[$FG>{\Oܒ)["K] [`4[ ?v}Hvzc,H O8H-1uTZ aRBg9onHOϹE1T.!UOJ&- 1  \JK0UB[4[ σ"|9b% 07lu=m[zc@ a$yUۍaCv-°cZ21$0V z꣕E,o:#v Ka%A_e4hz nÁS_Knza7tW!ಶ{RX%1 r"/+܊[1 ;IKY|`!o@mnIAxğKHnnLu~/wQ]{`5rqz3aK^beeilܙ5u1ǁeA)ctݰ on][Ȭ@YB?0VXBPs+T3SuNzҍfhd#܊*׻ϕU `1X8% t7rMy0m/{TO}yT|pe<z 秦SP ^%/ܒz'uJrPJ^+a}aXXyFeFHnz-=?l[:+;aR:ŐW/Pi"0[1VA;JEϨԫn5Z\nֹoa%0-]".Ԓu%hYyGbVqpJH;1E׷Q JKR.>f+UKn:}VRnT/l,7sK,NZDLrŰTz@^h#ܽ tL`$oI/Ol%%Y.nGi }aIFʽ܊1אX:!T~G}Hb7 rq;X1ݰ;F \nqHL^:zIvt[xrщԋۇ|V6;%"Fzn:M_ME)%0؝ͭ~&1~btx"Iceon8̃K>Č 7Âlmz~ĆJ]/VE*xRZeD_F%E5,0&v_\ KT*C7n_آͭ:ٌB˯折zceDwW)VAh6suF Efzt ;*[hܛk#Ls܉$fMnIN_V{%חA8%bx2)7$ MpnE>) p岃As]'^6½UY82j< 0%w$@ybi$8!_~Ҽa m+'UgecS[R}!u J2Zg=ܒZXDkB:e^]F-CCwϿ" *lhGH;G=.:R? aU=j*b-N9F=31D!?mnzWEH(0e$=_fW"VoMh*侬l[Vg=Hi,JRYQr&Q+C"ŠRcKQSzln5Ux%_ё$Z ojoi+% mm"i0H{u.+.0쉊/SJ(/®TݗonvI+HHͤl.✱! %|}ո,tEQJz!1hdݾ KTЅ6֡X*R+W&`7tȗ ƠÅU]e6w*ULxܛ!Q5$(!yp;}֏"uh$ ͂Ktvz%6[*Ron c#(1)y`TTSdS{bҟzY 7,.Q-5)h1$l*!rZ=w)+G+Y%!{h$ܽJ`H^״YcsK P;$gJ;1;R%n.,`}^1̳/%`eq/\#d(+[fgnQ 1kn"4Om.0|chWCSGV[ʪ /[?}_h_ *z TT)BKW-m<(gub:Rn4ܭͭ)EIƘr ;+ v"=hT-R!VO -}ǮF.Sg`bcnyl27s+2/  ;u:umsNy_ Ƴ.h'=\vKX*؉nv:c~HY/(djYU9u '|p!sKk :c)/Élf+[F6 %7ώ"ط-¨$"X^ꖿapd`2 C  jG8b 8s"(.>3jY8 b j]L1¿}+ױ??• . ?zglLrp󂍍|'JĂM,}@<[1Å?{=Dw!ӏ?ѕgV6.(_6_ng]I*_nah@R@G r40KXw05#2 U=$2n2_}y&s1A%1fǏ[cVryc#?jdJ[g}do_J6z? f H{xMmQςO3Ÿmԁfoj(E1א*| Q7%`%S#d`k7 j}W7UuGHK-%%+qȣ~[?I]V_;-KzzS7%_ 5yS[˘ '_XT[TT\儢m-U2 Ryiʛ:X^ⶸ8^*%\^}mq-^+Q0/R@E5K=3?J%Vm.}ƚY.|a7כ?Gݹ<H@罃cUt2X){r(K>N(?QFFl&?j|*o (eE@T!|TMuQ*.a2ޱFS?sXbn}']mbM8 6.2TYQ~_w }QGA2B*oQq5@cjTàsl8y7xӡʯwLQ&VTF(Ah4?z:P1jؐc&#zΌ F1iث͕R˻wdģsAh`$'adwx֔O: -R˽Q-XŽL ~"5ͨwݨW/;5?~ F=.^&ɼۻztR5uzej6CBe gV+j.}g'|Y/a3]=Uu쇬끲"ʘˊ86X Y׷e,|Y {wfkx}޴g}&}S?FB 8Pj8|}cdlojCߥFFD6E J:Ca˲ Z85UO7R5߶]WmjoS?._/mTnea?(18pwll^||hH]=Uu gz;L=cbr7O45QQg~H1i]AMz_o(sY}!;1j6ЩI}[gM!71esx+6ƛzZ6ñB,2t"skn#,v)Tz {(4d$baq̜Pg-jn\:Zj}շ|wqKC dGBn!n\|40jyWG=j^\n1"w9kֲQc^\ڦXSNسXg9ּ4lX~ܣ. RwxVթ5F-u{sکldQ5%iFvh46=5y.] e(.QO24eb4|drzB&a/4dl1۽1kޙơ0%aL̟."/F_TGE <ȯڨlK5y.?aéA¦ƚ!`2nr!/U6xWg=i\5B~AmYz x~ǩOTETp0e3֌ywxә4%dz{r:QC5v#j>\n~e3T[f?1ϥ1ˆzvuA1,jWӑ.%dy Z+m,$|ܐؠo~]Ɲü73 yȿ]3wTg=i\Jz jXLs1GMkwИ]< cVJGWG=Ʉ<`ޡܨƂ#XwUƆ?kD):&fF+(Ҡ!zjs h$*u)zGTj5MtysQ˯wIPTc7%1m7wRAƶ?*J(4hoR5ardz5y.o?嫕UtB ZWؗu?4c,YzS$hrԠ~}INMW-]мrR>M?ʢK TcFcM 䂬Zkx>B8|‰?jNIkQކk޺& Hִe~() G>o|z+`U[#h[OHR\_SI+p>| qujGɫ-zAkrhlVTCۡ0oeNNS߿Gu6=57v\8߀*Nx^ʸ>V["'`ã89|jьu\Q+gcO8Z5#ccHG`dתEj/0U4woNUNjUWwz'EL Ř ?' ^:VMթz 4׳El3oСX_4515reջ[դ-zk%&P{,:G.݇|*M4C7G#lܯOȗ gX;5''Ǘ5Wri'Sj>'Gb  D7ÅR5{ e_^~ ?|үo]q겡 B ӪZoG]xx9/<.WHF<"P}hh>w"JR$/<.|"2A@$;B>'@/yDxr5s0/}B"tUXKYfEɼ|qAE,xY(}' ,[@99ٗ/<.ߡX()s>eC{vbUc2/5xPO_!/¯tŻjrh_x\Dd6HXH,#~ɃkR Jwa`_x\HD%}j9>'@ƒh NORtc&DDžOD䩠;R\-%_@>b-u$4ns~ESƛhꨋgZwE.OGZeDž_Ez&us>z#癀״~Z1Q긪BnG~EduUgdKDIe9FzIDfYך+g\ys~/gK.}N{zI~D6,]?5dE;)X{¿_G/IV1~655uo "Gl<ٰ(SqYe5>mӵc w[Mb;&~],?#\j ' r0cC]}_:K .5ֽ=ur;TzCVD]){gCWyvlx-),-rw[9?NOFnSu M5ȗQ"&Ws˴C?2/˜b#wL'/EFZ#ߦ-9Q,ھޒhw]&tq*[WJ6euh~*`{nKИ[m/R9lPwmػ#}*?n[x@.SOs@V dخh`?g4I26vt%|:xx|eu?c'S6<8rQ|q'#nzrb߹ķ1X > nc69~7~|$"͉P߷?ϲ7)ךIu}['Jv2e%?켞o9Q;ToI>wlj)`}w:߬,{X. 3V#Yߺ^ !=q7&=! Pɓ ڹ5 w]6Ha 5nφirOWޠ_]-qSzE=a 0/o`6mAWGAvۛE&G lB hz}^'/hԩ +ǵ>^H}]8U ˿-N˭GKo":.on"5P]hkpg("%6H*cl^(#~i `>Z5^5ſ:.on }=@%)ZwCЀ?lvZgrFS7OwAkх*!;m쎆m>WFp ìB)ۅN_%.fe{aVFoA4ͮ6oG4ԷƠQ2lYK@y͕CY"~ϷNӥ9>gofJ#Z_:UYUW OiSݛ"+s"u w;K֎ޕ=W!d~h.ꊺ}.1c@'˃YՔˇv ,lʅR"rb`fkL^-1EDXi'av{ulrϢ$ bgA۱ +yU.]/e ܆ MC0715v.0F$q1oM!* E!Ώ͎h s0[ىp۶HtK<=~7({4}'n3lpä6P1)][0CݖVxlA^yS?g'h}Ff^DIW!\>گD?6>XaϾM,Wa;u;5,~1>_ѱ+YWoonES̈́%@ !~]% l85V_x6r (V/5V5B-zЦl,(6rI1 $e&HĩPE6p-Oxb (A :u4PK%Jے%@yU+mjSh BFcؕ%`08([נgI7A0SK0#zi2n/rsx̒'=Aui D$Mui(Q ZcL:\Y,t,k"P.Au}EAhS{x%Jϧ'2 咑`{SH!ʙRͥ^5if#@-2:1x3Kjڻ0Do.<8Q$g# _ǟ@o`#@-4Q84Ц!B9QڻwL 6B%sI( LYw>[/A+9Qd]% X/ Q))qhמ_8t &V+K2 auk-0]줨Bms,DƂ")NBV2ar֎j NX;},arI wL;w\Wh7lVZF.;eƙ"*<5!̻ٸDy\Hy"/Yh%j#d#If mS<$G IkH-RXٌa:vc-u]Wn:Jڭ)d:(q7@uG 񛽐Y$Dծl3H\ID=$ֻABS2}S֜ل3̡sbYA0YY_m&咁7 B/p5ޠO#uo-f"0-kP.ɜ1GrBHM:*thX& A~=8WtgBJ":b~AOݖeq8(JQ$+^!P\VS{Run&rIMUy Ҫe`lD9*1$^TT v &в̡b"lڳ)77%>iƠV c#/h\K囍L%SN?UhӮ~atwm,(Uկqkߚzu-rCм &Sp-:v dKԮ5%6E &~rIf^19q qڳmS]\/D:XSWL,&NL*foax]`Nu),NÔJ `#@W. UąWnׅ;yF d6zsĉ\"Y\>Ҭ)~ a@}kwZS;!P;TKBv́e-b%ڴs;*K1OBsNd\yUV] cr1qٲ D@GsXH<%/Df{D ,L;K2%ㅸ #m/DT9PkMmt3!^ YCE;9=L*7<;K"vD ٴ_#.xa(v3MyvX&Gw~.i8S>eӃZdZڛy\:Ȯ}?I}TEx86LNfq͞tD;ft@f8dysu\sLVѝK0=o?iG$LVlP}wS8Q$ VNVΉLs |' x3(_Թ7L,&ݹ$s"`CH !u]\&ݹshO] 8rVA֠5A,x.铣Gϐ^51dc\j1gc$cj1ul(7ƂםK@%_~zF|2#bKX(C(M?p)F oX. /LY1`pGE7XPsɔKE8DVx!ᾃ~6qLvL;\;'x#$'Et0`b1%NW{i~caaʺs%4xc%XjыP;&s]^{m;V-΂5ww.o[jeA"/}hjΩ w. 3ܗ-oi0Ҽ c<&޹S=s|!riJ`lb1m N٣q ^}{y@4w. m-¡ojPsyiGBA;%cNmUϭ7PpyP;~jgr+HzHq.=J`9arȱȱ~q-9օM8K0591)E04HGDE 6޹T=h8b@OЎ\ƂKB[%à!#d"Tb8D`;`Gpq ˊQxf1#Wb7%}XriەU5CTal,(d>AńԳ4݃;( &߹$sjGڮZ\vq x.v2G8Fpj߱j9N Rv4o\XVK8k`~l"K2 fWYKU[G R%F򲳛~X(wM*'8/޴oz@qB*+GC͒5pəc]`b5n\,\\$oBx{hϞC(Ps{9ƍLUuNc!6oL,$޹$kK*)=0-2C<&e5w.mϺq"q9b4!JXI ea !sĂ8MZk4Veyz }I s xW _$gVr_a2yAlN;EZuq  jC pq^9z ^pzP8z4zU(D@;@Y-m5~QyLScL@iN\ٵ_.1T\4Y7yHvq&N\*S3!O*D&(K"Hyȡr`M[ hc21Ғg w.=-[ĢyQԔ2;PuċZ d#!aߦch\޹$v&!4x_!P :XM;EH{B5uGyHdj'|޹$3!.=!!ڱ-,"<޹Q|+Bڑ]Dh&$S &SE\0 ~h"C*qiז!l,(SI1΃CZn''WY{urp MT K?hPq05jůvs[{9C:|M\uX7j#޹$ q03"D}IѼ0up-i/_qq r!iL8;d!48a#D.DY&|޹#NP|wL ~[88O5w. cr9zE뉨8BbK0vJT`[x@Y70M%|޹T"p\0i ׮m.>g;^JsI&X؎L }k"C]ڳt{TgL,&4 WKdv]8[5tc3x%@=꞉+;)ecA%dyQXwH%NX{&kK-#Phgoou׎-#"KI8GTN˥ )u=X[D0r k"CW)LlLODhHq1Q6 v Y&.\I#Pwc!̩{ޜ%F;Q8Mi1^Bc^o5nc7pzL 8$VB<8$ۨa. kKGg*B  ?HsADhs zQ8i"YD2ڵX('ƂK@3i7<5=AY HVߝKk7LFTri.aY Anc[Q=9dW-!}S j*qmNϧ%[Y V&_'PbJ@j&,LӚTAv믳Ȗ΃<݄ '~,:<),ٴIcV}&zJ".'K*hMLj4 e.[SIA} qL7֟4z1dC)3Ad6£.>=dqjVE92n:˶5(t Mn&Ym) Vz 1|^w[0p/i ͜n5=nmZ}cú~ܣDYho%Fݶ8X~>v6Fr#aC5n?kQ^=Ye=4HzDɧk삱*Ie/YL-wGlʅ9¶IîX3/O4ѕ6 ~ž)&*b&a#S?^#}]("n>g!ڧe>ldR퐦%/ʦҵDE:ӈS/A%c\(?]seI R/jJnOoh=KМrRAuVOhA3PlpM:+f}"c$t\RZqxAߔ*FZX.EîJ"' U5蕐h5dFZX. m=Jԛ C{#Z `aQďHf}K _.;. GNBrha5cQUkTKE},8Z&V#ѡ Zԏ$oK5vQmDMŎL%lT:%*K6v,[}Q(XPUԡ<4dWo9bȒб\fMjys"sqqovBrI$Z$eH pdbc$r^L뒔IB;+m{j8\:gL˥2WNNFPYծW:|K  ȱ\vԊ$ct2vP P %waZ.BH睁NƂ"x,aZ*R=K2ŇgMmLrMe`h}3IlxN0=K2fw#ձY^9W 1nYmv\f,Ijl7P`nD`ZX.D jT d5|^ϲ Uf`C Z/3Ç7ݾ@%hT&9OJD=(leP2.(|ڛb)wn ' Ki{[$NJ^uIϫ mo Ql›9?K0٪#HEinj{ ݝ#(P%"S~Zդ>3Elx\&c͂4ijk,/sDMLkVN)5͙"6?+b",dUՅUNSfg.iRm$ճ!&Τ.$@\jxW ۓBO|X.@B",@5\FTj3MClL̡c8]tp B+c3"˥f!cK{BUӾ斻K4&B;NGQbW^HWsH6~r (ZśyIL^C#ZXwĐ@4j8Bo۱9V_KN&V#BK0UJȵww(-%AKm,(brI(58TrT_r(P #%-9% >]$P#%Ę9"Jx<(d (\ft] m6id$SL̪b}lx;8UW,H4M9Tg B<~89v6br ([JOT65BYOKBGPmmC<%t~hZ&djBF-S#n"0-,dYCHE<>]iX/*&Yc 4L^ZЪ[k;N0w.D[*eiau[@rj\vyEiOa΁L,&߹$TI%`j<[(ls (@tzEK"[Xz}D 3:- qR:7;Hө FK':-Ync,|߹$ͺ](xymzƂK@0lZX:HM6z5$%6U)zB=+nºH>9DU-X'c+OFsI ^UzDBI;w9C|n )d"0K2ވ=+?A':t,HJcճpDmԒTix:p],sIdWġ9RTh_kS=/X= w.fQ ҤHm:)PkaV3%hդZW\ :}s}L & o jŞ &\fM l4*s\V IH MŲ<ڻ4w. xkRu%p3{ V;%lԬ+}݊$G=.`c\کIE®TFφ@piXgWsp@% nӑӢѓzzj#߹m@sbƵb@Cn#@+a=Q-)Zl9F|ȣQ"~Ϛv-ND>3Z lz@Q<]MmQT[l K%& ,MRV_%b?3)ԎuPfHO%loR-ٷۄ`chK- w. @G^l6"ϒu?f Tl̹Zb^agpPjpHy"0[ =j&V%ZobmOv7`c5>\<PbmAmSh]g+w w.EÖu&U-b킍UA,HY}aC%8rBn6Жu7%hRD$pvVhw.I6'ķzT쬖1[k-W% [TR^7f0py̧.o1CPi/ovF|'L%T;(a2F{~o-'3Lxc a2jg}Jp}la "xsI"CBGvTh*c(Ẍ́;`Uz_ >/ ٛbj+Y;8 OA <#8m9s (YbQQI@ ZgLsIj=>-5dKe57%4Izj=WGt\hn@,ZDUaA -qO?9p[7LsIH"0FU~#QrH(L,&ݹͺ9=UJmEU|#16sj\<P;p=NdƂK@0~vȈGUu@VzG'n%avU@jz0JPszPϳx"܊8<@>)XPsI59К[AGU)Ɓl9sIllT%vTuҿZ^:bK0Un)@mU} sG(P{ͥB]VsfS׵ܲ%`X5ULiVƂKB@xT(| 34w.d\MVQKQ~2=#ʻ@9Nކ؏2PEe"K Ѥvp5Umu^^7P0K2SSQW+"COW{ 6Z%AE-ҳ/q(pG}FnD= A~6$yl#dN^5ͼ`cA%l)|vo-岰n&$xt-DKגoop~@6rHފ=j0(FO_m] o+ԥDkegnu &~rI"aBYẌ́;$UIpEWP_FF h\xYdHU+DFѻկp~LTp5}Rq۠MoRF;]夲}أOrS\{+%ÂW,HE z$o"Q{s nK ѦR+C0p7}Q|3h\BԱՐNm;N*2bD ;B#@>wZ w.EẌG]9(4rI GO_ 4:N G{S1p w. -%2f 6,-da) KG1H]讏5 `m\6ՓF] L~;d%s`O%4w.dE'GNUUs|yƂKBG:Bva_K;@Ku$DwG]~A6룍"ջN8sI !Oe` T,r%lbeÛ&&B K2g6BF](,>O; ]B HGrP-=I`#@KB=9<Āӝº骓!dֹ}飆Fl Ow.eg6ȴ Ҫ'=i/\${ x#QpA4r%`41ERU d/ԽM;$V&_!hcG#ڴJsL 9$8cPu%^ƂѝKBGZSѰ~xjz 6ݹ .Ux%F {BӠ̊ƂםKBW-w ?6=~gy(H[GCK34ph\*s5jRN!hpz \BuuPk}HGC-cӳ(ݹ J?8޷/-ecA%ãm4yHIvS4=)Xl.b"[z)Q8])o]v#\+KB*/_+hҏꢻń;`]M⏆*,LsI&7z sCg C;PB%E`{4uS/|V'-s $uly4qUk8)&&ASS GV{0\߹Q}%k4B~(H|߹${0aFSfreޛ'߹Tj+ў53ؑDڣ.LsIfh"0{72%Z\vPU6+h>2E&uzºp~Dkռ8$JD8fv%6{7Z w.`"cg 7S?$ ^铍;6Qk 69C78zVϢCCZN\)6y7Zh\Y<#TgGwSɷhw.det+_h36{¹dc\z{$%U(r GO0p~H"C R)'@D@;@V! (WY ju\=HqAyQgǗ㔭xO6V;%hV2AAJ^7"f w.ID&p#AN!>lfK&V+%"kDT26RדND}f.LHq6 qCHq7LJP%lǍD\K{ZO`cA%U;3"i'BCpH6r..sGtAlv $Zepj7'Qf_Z,6KRİV@\1F{ʥBWfʻ+Hʸ70[C ߹+dڷ])sO4in"0K2 # )` <+OϷ-擅% w.IFeH Cđ#|Q4Yqfs&w.Ad ru;%/D ֻiQjq:ݪc7 /w.\2yu11@5ՄpAcȴuV,d/c̑/\.m9sI8N&Ӕ1HIo8*ͼ--Pr0J&u$ )B-e9˝KBɰ"@{;Trgin\)Ud>CܑKrɓNzRg`<$Ee*e*~jWwᨇ咚_NIZ iZ24_zIN44_jmR'廒MWf *MόW\NɣP~G©9~/f2>Xyjӫmq!-hlx?ȋo841A^Oʩ[riuG:Lu]vxt^Rd 10'wYIKih9R4uxS@ʳ!EY;[ؕ7,[V9pNި\7RQ~ D8 *4XQ;͇ÁbF4G1[;:/}7k\>6af~32f߶cT/ US1 c5*94E;5SI)&{]M؞'%̣E2wx6,A ;"6zT6^y\TpUYδ!X1롚rnI#tgE{SrFp֧m>BxATnhu9'{ꗣ,2'XYMIMhljAx謊P1tf5߽ߨjs7H60nJO&'b!ME肍,lVa(vTat?VoLƻّ)3vz-``fV]}5+>k$N=о߆ؗu$T9! .mԃw~yζl^Z.#O ƿcE~T,Fٗh*Ed@,Fpr1IrMdDL&I6Xu)S-! 컩gzD/O>~pd>ی>GE|p sF CljqOd-,O(lcA?cJ-A}Y{ txD`~[D\3vAW*++!K`G3QWf#Lq%XHRH,wKB~\-漖7~kc԰*~3pڭoWia34Ϻr(ʒ %(i/I@1}hd0v4rX.L&ЏMcSVU~J#(7s&}% M<-xAkUrvD.6ԬsPp\,,X 2D[dU#SYPo<d e \*FvD.LǠ,mC P>hBdrI'_rU~nD?|N6SR_iuKkK ;.9_뼇9b;g1zK4F°h_4J 6GRX01ncAzK@eM! ;" T|%&&GTDBʲAL6Frᤡ:kZm &B[,'h ^XUER ѪޤqL֦1lcAm_4 ʚFi#ONQ!$pJeBʣDZTO.ɜJldǸD1Gw %kzr˪Bq]Aԫr obWDSdA!WV]FW sjM8s V(djvʊW?sBHc$t ^5"r 'PJYqjw 9#&̲ alXv]XtE'l9haHDs8 +ЃRM!iRl,("r aAUEg` NXYMCR. } | .F0ՙȠZy6~ӆ.ĐYKYE͹GQ&X\js( sjk\e6Gs: 4YX=P' oB$ޘI6t/\:WÜi^ۋ9f_&-UlkwXp}lb5SDc Q/ xjޡ?5rN1H%S% s/. N2ncA>K@e 2zsӡIi`ȂKe>L aADh.CcZBZ +H=sf"lّK MoG'8l?Ilv Ȭ\S$F d6CJCY|2t5!fx]Ux-->-\%D`:w~n 4"1:REW. }= ':_zYg^2h[ivj!_T5°Ck UeBp_`hb0d=!=akT]f5핃7X\jkz18dšU}%fQf2'%/Dmɘ\"sBm|O]4KTRUzP;K6B[,L-h'G5*` 'V$ i+XG~泪A J+[XĨȦ,.DH{ti,g/*/lG;.njsɥEܳAQ]H%,-h,'QYpF^sp4lE-D[.ՄL {uYH 6V;KBoLk)Q ]/7YTۥ-͊^Ձ_Xmx]`n S̕ml7}ֱkK2А_[0nԥ=,{pZ0K35s ,c0Hq.}6]Ŋ\;OӋ+y6O36ƫsaKFVt! |;޷]x,~3n#@mo36k藾ܗ6(eMÎDc4]vY9)J&p0=\1T`]fS.Oϭ 6ԶMs ( ~26H TƑ%m7%%5Q!־s)D5fH6B[^ %.6D&r h$tj;H؎|nnZW2ykO/YXGlnHYFt]hH4h מ؋Fg#+..Fl87͉lľi.0戻;+tj=,ľi.qjoCQiJZ-!/19{}p{V0 97X݇m\-^dcf3!gmmPy:ᩋׅ,qQ"y⒁uǰgKvˉ@9^ۅ"Uzi5&>O]9ƶڢ_mYnF6ͥ6͞r(̮LKTM,$Ms $k0 DFhzcjBXJހqjCtBoDڦi.l Uf衶FBtBD>Y2ՃEX^ʪӄ1}6AWZ]\5$$dLe랞v%HYSJL 8e{\Ԏqg`Fɂ?`fv|fB6U=ri^9{]EnDyjB)5}O*i뜻F #JЈ TBkdϯ lZl,(Ls 'RYqh^2AڔJK3L kWVmRr_iN`"4ƶMsġ¼u]N h#sXLR'4Ee!Y*{z0{K^ &iľu(]Z9Hpn6-Cpރk5*fYd";Gži.YhJ6FtJв\r]ZwX=M\ڵuݪ/)HY'wj}d#@mw3ʒBӜ^ʢCVA|]b5wM b[W$w\:s\lMZc@Sd=p9e!DJ@>rB9Svh[$TBG$[TQo5ZpiƆ.Qѱ`u,$&=ՋlHkmvUkD'K6VkwKF6[Ov!r($9_rwK@5rW)FYՎ\z|?`d)!V & MOrmr{ ڑ/Il[% MsyGl9@+0rV{K4G򅃒ѲP5 6G%(czl{b4Dm}Q^t2.tVCe&`a!əKE.Jpp^K]eaL'Vt٢J0,ޢa\s ȃX DcN#LEj1lK|= Czd!tDYJnnZC.GV-d˺76dj: Ѱe&o"M>\.њ[kx TRӕk& oK Wt!GbG%\¶j&6NsIh~g,5TOn)jѨlFCX~sE'r J6BsfmiVinJ=zDla3ȦLIEfoM*Aa4Bt( /L-A𶝣F]RPQB֖P$CօeTrƶQ6b[DSd!N,1T8t5[ zX\Z.Xi.YM #lMM l,ZlMcK@('e=-a x$Bl.,}22XTZz/zIM`c5ۦDs`'0[Y䥧1vuD@+@ʂ )K&B'P*!vj[$tzB(@ }](ʆd#6밓v!RI\jwEźm(YXlMBi9d&ǛbY`4퓉}5%0!1UJ<0;XP*D(g4+i@沵D_O0<ϐI,AWR9`d#4Ms֨&7CDm(UoqPwRzq2)_*Zv>,7% ^%ݳBu !"Ñ2jbwjڽwqee7* ;sx23P!A9%Kr0IO#I6Ns eمfޖlf5]rΓ &V+K04k7Nn)Z/6F |[ғٝi`k~ͤѱ᭪e>ӗMخi.Y A1im1p*,Jnb1iK0eQQ`b[(aڊ5Puǂڙʈ̓];nZ+Ivmw2,( fw'"KJ %gK4FHeLYrM#^ؠ/XXs ;_daE7;rA8@]\B?87YҞDAU*(u9pˆic Q;M1mHj%-˳dRiCPF;< =|4qz_e}dhu.}#ok<\u|Eٿ%vji/$kE 9z tluxTґu qU˜X J<Џn尻OV;C%tG?ü1"ri}T_K NeB  +2 GR\G?Agiɼn).ڦ4\ ZfI$eJYl! MGW~QTYMB?%AeAEY\K!#i2q!?j%͓N~QAY\ťQi,ύc8ɣX"yqib٣6VI2? /33۵!G}d!h}2ggzT!q?jvEy/ʦdy;QI"?+vG.mcwmGi.@ϱA-oAc-}Ci0!n; *<>*k!ؘ=# Q+6 v&'KU2}WN1G*֝7h_%87GQǭzQ神g! nUx֑"O ]3 ~JA],T.:ZL, I@B~5JLJ UtgYD0dKgB {tG!GqoPƂ~ JL7 F< D A­<ģ(4ᡀCY 밙X2A a{6q9\g-Q%h}avbM`ᓘOl (0efJni%Q'@Ac9uwUU|ʽ!!&Dq'ʘޘϞq'ŝ5WELu}{S\Kۏz; ρlV30j}Vĉw_s(sc N&ibLdb#ux֒Џr8 Z3_ƌY?d蠥UU1=rs c?d]&uuhM&9ϯ8[Ub@M-Џ2aP T~g/̻ij$i[?a ILϘq|T0oSYgxVӡZ#@šM,Gܮt1" Q%i!ON`V\Dž YKFސյ5UrOM UU2P!+Vg5|~;P"n L'ԦtV?őO267yGUYM@?kdE>QEXegO%%gbmCP @'YI2?jd1EiɄzoznXM~ @΂zQL$|a\r118bo5?28bFk,` aH tIdAc+%9 :ϐ92̮~4aɼzSg5 (͑<0!mΐaių}+)Ffzꠇ@뽒7x֓Џ"aPr1,#5Z0*>32~(@ɵxӡgn(ѰK`ijd~,ig3Tb3gd UUbNlxVЏ7hizwGۜU ZElPg8=39IX0z1{B/Ld R z z=7̠Hgߠ!cTk=n>R?+3ߦ^}?^Wـm1CzBiF刑c&[%3g1D r;[%t 87h#!}ЏBgl@?2 @-,rlI(mxӡrg/xSWq-1ãS0h qSko*&ﳃ~+il&SvԤsr*+2[P+&xCVeZ6Sܰ mWФJygV=pY5p>^gf33!YY?%έrgd=0Cnj:;X)3muxҙ2c/#51hb^u8kُiS2qLl}S:+v&YgVL$UuxVҙW/D`^ucĂ. 1ufdhm¹z:m 0i9񮔙|YG~3`6>zfL$cؚx m}Cn)rxF2Bv> ̏ e[S%: i\׵Q:<+Oݙy׍C%?'m0%0,34YM~Jڜ^=ЯתgHϵx֓Џt?~J= 4qij[9#4r:W%΁XlO9ȒĻ!U[>r6TWu^̣>+?)itOi3à"l:.hȵxi3t9$4^Xg=)p`,Q| l|¹a r S,o*2?07ΛyUuF BِڀOǔp̸78~uLdĭVЁLJIdȢ<2Y$cZ~ z =Mw)3ofJ2*aZ\ 2#~1-rCͩˏP,r៙n<O/N^k+>M% sbIl~O1uW^IyK ȦTݍ$1:$pircWLx u *8sIbLkZ'ڊb3$?tZ\6W`M8sY6 ~?̡Kh[;,}&:\@:)Ԥy䠽TYIgC;y[߷_?O_OϪxzb"ٿF9'76?yYr.q<</p_/9 /0J9_GC?M_N;\?:MN*v w/gъZ/4U[?t4*VyɎ&?~/\?|YN ٥*fCɿa9s_PYu?.*yך Zf_4ʫvU?wɩ~~Կof=1A]^h귥:^/$7Eq&nmB]V#Yr`o_ǿ>'gE>vM~ZOj_5]lȿNk躓9R?^8fwuN?3IY5^ GdrXddm.W|I祿}z4_jh{]ؿ~7Ӹ VqV~үOy7X]k`QYr:%C!):?/ ?Nƹ|+R/yCKzu~~KOPnJ򐭯e*mf~?V9uW7F6x)Ԃ6E:5ƴ>4%Kl;$[߿.{\h/cE-?hʅeΖOGyֿ~};UQDYnׅ^.Q]O{,R(a]NݽP^ե3EXL?IuA^K׼dz2/kF]*+ϯ1 ]T|lZ%/k~A_m $׍ʴJm||ݚ߿-m:iK~z{Z״߿ME{QO?i/zAN4Hb.|ƺA5yo5{MqTPfy$p#RCG^3_:2`G@n6u7P .0kDYU=Ϊf(Yծdo{Xt"韾⏸_WD W^#ܠ~Չ߿ɕO+­-ϭ4oy={Gwzy$){\>Kz}Wɇ:~c0擥,'&~T/OE'됐sM!Avך| \<.?YqW&~sj=Ҕ\4>8vP*"0W *){@ Dy׏x/;_xu$.cTX^m<y Ms'h)/<.>"0GąЯx;7Hy UկDh芗{g‚+ mZ3JYfH6>#bx͖TLs&#ՙ`^d|+'B#ihHƕDgϟ1]jpڸz%pKzAl#+ۮw"Fz%@v~BơcFMFp?ˑ_Iz}??ȝlvWW'.;r_-MH^XT~gQ7+MßժvM\v6uuA^ A)uz-[w}唦_u=}ozNWS.%!8r2B%ޜf;$W'/fáp^u,`#>;%|g5R&­k}ht¶r^ݱW)/G&k[Z7(V:9Ƽ>J&.6VѬ!g K kΔmIٝEg˜79]rˉyO7`XnKz8 l"Ƭ8E$Mt[Sq(K6veހB`48{XVM{XX|{|b 6tUq#/}NXsA!WmbʵT^M>ubXvkA_h=a7ޞqd6pmȲӦNrE"lpOblඝ྆?K~?cv}[%ӭ#ۍ'7xSj}?r=ƒV˲Z4sG?h}pY+Or |ш1ь 1Sb0 7*ϊS|y>pͺT\2wbwYy褪'6×`VuhW+eSQoKh׆PveMiP(Y6,u?dʩU6MW`5H~#5Z"2ֳYaq,Z q7ѳ%zSqXPOQ3ם nK`=t;?|HM79F߿o!۷h/?lR=+jՑmӾnk N"È> $Ύ}VU:=[6$Ẏo!~A~ۯ&nm z 1Hv%Ȟ76 mF{zhPlż =|>0zo@_á܈:-v]_.6~ÏȆVȿ?uxuسb1 āJxhCW8Egv[sasj~xK%`I~^oҚ+}3n{<:.ZlKï7ں&ǩ< uij&T6|%נ2I{[L9Y;ƪv2(5S4H @[e#}V_C?m%]X7b\{U[V툽Gc*kQY}}Ǧ-stGW>ȩGL\EfJ?V1yQlL~[Yj`(<<@{}< 0M3Άk1c%+O4 8N9b@M-Bĸú$5TK{V~rHb4PV*X`da8Ӻ]=/1ko`hПTrHE#k)sIlx4\)u.D!),.\ ٕSi\=[ĥpmU S'Tz!yYߺb\֥B j%nNh$0-Ep.P`|>\F}XW^ZF+)~cZ\c;ώ~ru5*$6 X;KF.W(^`O b+]acQq2^uY8i|ܘ?[' Jʵe)bAh9pu7In z[_`_kHkKp˺882n=Em\}"z\.ݢ{+ӂ$ UOPo UVuaL%lDhR7J:u62E9\o=jԛbɶwhV׎j/ߚX),Fs-i(.s#jrɈG"tǵb8 ]F0ܳq8E+cf$YzAƭ)#2o>1Kv@#_U{:q+)sp;?l,bAb)7G@LA<㷣Xeq=Oa%@U.#FbW} C9Ӹ݇` h%pT.ɝNZlE=T.AU?|pzD xrM-NJ9\asJ^>nh2%UprVdY:>%Qö q2rGLu.a*D7KXyNDp r"MM F$'q^=#X^(E9Oh%pKpod輵LcHP zY'YTs AaaTO LsI$Z&tB^NGptm Nđpǹ8 V˂ {+&B 3ԫp/e$ uԆ2&pւ;k貐+ g|.ʼnxѐ|lX&S' XsXMP@m-iXLsI4p| Y`1fzTsԁyGQǠ똈 zxV.';Hbvk /vZ[ȢKR’#h!8dSzy`$`KTҀl8=M)]Th#'"'>C`)\!WucB9\Kd#@]9?iP^CB/.r `nga57|.ɝ;v0怖ZKp/:9nDS5jtys z'OCTEXI:zF# kX٬o 7x:|?v[ZPy7 LsG]rԨ Ӂ2fԭs' T{%8.wNx]9'FO/9#Ww+mp\u(I.Nux`< /xE*S%GջuQѼstNh%pKp@K‡DB֛'XrrTE+ G|.U|Rǐ]/L٭ya F$iY81 ojt# ?|.B<XDJ'vKB9j]lGڦY,%搊Vdۺc1=8g\?(XҘ XY\8sIi$r ^/ Xslp7s{༗RӂǕQ*# O|.=رى dG>[ \]VĂPd=-kBp[-MhKpճ$ɝDZɎ(Pleq%ݺfsyt:0m(P;- Ts璉4.;/xXHvYȊhl bhE#YXxsI,#J} Vq+9s 4W.@ʁ1qt֣\SJ;>TqsLOMgf@XV\k&IAGdTJC>ફI(X fŞV),bAf$N0,_kGxHE4|.AUW@*G@ k4ıxX \sq:f=\)pyX,a.\2 #J}!½nԗنH"+k.\;S5E=m:Q~?$;S ֳsL9` qRO>ȱ>&@ֱp!"$Ԣ7msIj7^Ao'~k9bWz<,,\VL6)?BbE9sIn:&Cv8K1X /<9sM8bq!$$VdcA2%Ӻ(Q7J& !x%VsHE#k~\kOxA,YLHV~\N.v[,x%搊F:7d2W^?z\7E\.kZh%@1Kpս#T`b蛼qq6WbE>pnfͭ#rW j4LyTTu񘞁A;NjL;A8Q8Eg>8:@f.Xs\kźtNa^6.y,,z#* XX7.1VzZO\&9f^!"X۬[cbh%p9KpÁ=ِ:oa+r{ |. 5'>MEm ֿpFV;%RYq!$W^E+=q Jk>:޲JpNW76Zg# |.UߎP&!a%q T .l%p7Kr'3^:m1e !,rn (š"`g5DVf=|Vf(6\U:ݎbm`XP#[ \{%9Tkn@FX;}87K`ճ#j !jxe` ?sI,jxzT4we sD+k\[q f%*ո-EՀF\;Al*'fϘ0+S:m%H2i;q`H.I|5F# |.Uǎ@2Of;SzXb:85!P٬s.Exʐ'RsP00׆*~a$0-K`թ#4d o]\VI$[gjx|V5ӏ@\Q*AU|[ӥ1ѶNx;ƢR:(NL8XN,Nװ>?Vפ|Bi.n$ j44朗HU|H`B'KG O +mKMF@QNd+KmT۬w:[kM|cVKha"End$P!uJP#'G W,Ea mfcZhcQ).n}l"܇HBz&ZvĦ$Z$B-!.`bI*7T7Y"rq{`cQ)˒JPս#y{K 1!-.ۄ<+KX[D&u$A7"EɴI@B'%V랋9[>/K{w#E8DʕPrsݍ骭e߬,.uRI@? Y77ZWuņwZ7w[oVzW;BiK$FURLXU sg 1|a2ǔz~`:_85Ba$`!U 0-Ix8#`DP/Us nA޳Q@>+Gz!0D*b;>6띣ƪGUO  bX OJC>_GEH=n园 6\ ͹c%,n='ejMD`3>`KGI>2o` j`NyX \ii%.x9b{Ņ7>"p:}$3jab*-&DzpA`$PKP YE5ii4mYXxsIl#DMH۰?yχ<-4a$`9N(쯦?rX{yxYJP˜ TnS/f3l>FK}nGV\*4PL_+/\zc~%>mY\DdX/kpndQ= թ# f)z2xE^y7+j\N4 Y+Su1"Ydc]\HK].EQ@kNZq[M41݄3/xs <ݗ2}vD7 gGGɥ |2EWpV ]gd9eo}8Y|[/6YTxsI\tXv'Tdz Xv#k\[Q^8y,gHLVZkK`rׇ#%DZ6S? Z4,NsxKU|4t5g|.UT,>.&Tqg}d+ g|.ɵ4FL Nb@5g|.AURTV>+/SpasPRFAKӥ6h#PMf4@N$m\ܑB V@:Wb՜CHruPM% o|6ֵ vr@ǓUW1T@ns4'|.u)ȕa.NaHHeiO KrI;OW4Q+#Nn%Nm&T1ӰO;[m,*$J=zu jV#k\R\*tY^{Z1s C&T܁1+&&'OT0$LݨaHUŽ"怊V)J=R:Q+畊Theq%4N)axW V5O|.d\X0abEHErPE# G|.uŜ>Rdm+C( X̧Rq1E;xB=/Thºj$JNh%N)'pT (y !,CZR@׺\ ż>rJ6a2hOM8#>`:T\DIUkgtxV$o`|`0H>R9w ΎNbį z F~\Jup8X ['#~=8w5G|.ESZƀu2WaC*YX8s ,!CBX vX'#|eG5PĂD: J"q{h$0K` x)"S|X"zjs'YXsI, p,aHV_ =Z H2%L SNEK7@Yy_Ņ>:er9R:n ^>u@եD,hho +J7gM0 K0Q8k:+pZ5:Sp\R,}唐y^DQf&N4ϥbR,\VB_+SaC"YTsI*!Tux9,@2VÔ糑@5?|.AUrSVH)aV+H#>eXW}xJ6aĭLuW*ń>dVkjTzr[㳕57|.Ur,f%:B&j*X}o [Px^L"~|Y־qRkSlfJ?M=IDKo̸\ oHK?*Wmm{nGy EAd +'Ok_.l#ui@?~0˳v8ܝ_+l'N8"oa{-d{@7:a`ʓ]yW$A2Q :9Eps_ܿo 6= CI< _FeCʏ߄NnfbzNrL$OiӔu.RR3f^8؊&\R8Tz i'\I` 63p|۶I~L•Sk8 Gm wē~.$zʦfQ+-Mb-Laӡ@:]ue)[>,t 8_~HB}Hi#UOz?yBKϮHq.dLhWogB$>8vp&ϙQ臯}Xg f^Ʒu`gnN^qTv9+в)+?)X.:2Ͱo_LXRMysrN69%~0~kD˚,WsUqN\6%ڽ:sY 85eiMG&ٝ?W,e)5OIG ͒%xh93AHt. `4ٗCԭ z{~7tYDlj)sxmd{3Ǫ*_=GZAc<%k>7uqLqxҟ~/Ս]*wjmkva$`mC[q)8}mSҬapƆܟNۮ'5: XgK nh(19qNV\VvЈ(yh܆Ϫ'IwdacCleʶ]H' u0SmH8'z \jV\wIRH3lGc]HIb=>[bIwSmHd|In J'8YTg+*CD+HW#SmLgK x2z8CAvXF̂`4%YV\H!(z P,gK`4%`ZCb뛗/letҲTt˜iv@p^&j$,gDÙC2̷bR|D*pN -I8Cj`OKKْMzmR_c /yuy4|~El[QJ#ro,_0W^+ْخm Q6#9CkyY\g+S 9o^ק*?N=[ؘd.s=g)|(߳TzCZRCQ:$D\\}ϖw>B%Y;S> $k _{**I/]J'v}Ong/l ITJ6(XWoN;SB|ȳxƼϱEhM#*: XgKmJIގU6<13/da1WFseP)iIK+gsTo>KيDb56b偮6(.޳%7FI4=Ps>cM)\yVжҧH1ʨ YcKP޼.޳%wvi8AoJY!|},'R3Z̩2RgzƐ6 ^&p=[r!8EӦTz֐ G8.޳WMlyUcɞ1z5\yϖT(N 4Oٯ1,߳VSߐBH2wL5+0U/%p- JbSoJk)ɞa\V\.e wٞ.=Kb=[q̛¡4)jxGlOúѠ Nْ&)T`fQ A,61ʙ"sT"xC\{o^ zUYۤ%)7 zhOeq n\A@PUccY+3=cL%p -T~񾬅ɰ;n>2|*1AVR>pS&:|=[5vICݜhb7fVgUm8^t}er|غNBiq*"i%Bm*E/l- [pw⯛Ӣ|BqI1IPUvsGـC_FU H2,z%#PcN򖤂fУ,,%ȝ{23ŜXpgʒKbQ>[rgpS҉XOeqRʜQXY &r|5E`bG_/ʥ)%p&-3,+9l*ue(Z}Y.'lEUlBbQyٞ16,|R!E9jTb8_3$fySϹ(vgE6!+n4.+:4(,ˁ1։O=@Zg ゲ.ސd"1 6EĚ|*0HUOkņNcQ& XbyWV=G3"#P"-Ƕr@<ҫƁ7d=k܁JJ/zY\g+.ƟNۘ٧.- 3_~h&'шgK aāzjp&'olI*RYtG_Dg' lUlmvVdWYE ]>fSXV\DIHrjxԓ!c 'lEeleh“*ڷ?T~8~ë.%p N#Fder=Cml𱠘EC"$>?$d0b5N#}eXV\֧P(SbJ;rٟ|]])P,gKh T*JDi4 [V9E#=k uvqtXϖ۔CV%XTVu7da?O5֝x{yLl+m ]ETkr{|Pg!$9Toʫx1eq- M1Ī]ꏾC 4L,g+&k J3jx3. 鞽.W!oOo 5[r]˔ySLDC($`( . R&OIb1-3)%+u+BoPIc)2nʔ0So^ْ;#2TސukNr>[q[脅 JK;t~ N[=lez(E͑+bw3y|b203HT`rՅV%X-+2P۶;:䠬9r&{7Ejcj.m0{T-3E͙\uEi_r~X~V\EW%Pz]uA zXbr=[r wRמ. $q=*UMΫ3.*pثd|)Ӫ4zU&ח~! Pב]yVʩxFTtXVXEVJ+ѪU$o/3eq -3TRUc)U.b!>[qʢ"DSm7zY\.gKҘj>hU”sOSo$`}FlJ|emR&lN$0u-.*`]vY-%uIyY\.g+;e+Ӫ@z lXϖݥ!5Z(R^ي[qgXvи=eZ/J\j/v$` - UMD,%C_N [p_{ʹ`ɔz'\# Xw0ͪdJ ކ; T,g+j]9dĖfU -GNh+ cK9V/S-vIhF'lU`;h EX*) N+c#v K3NCrI>[qϙ?,`U"eJZP,g+BNt RG=TCb8ǮAISU J>2F:$\VԶ)d,CsF/lɝur!9yUoGSUE5x\V\FE/V4*U +/#0"-yh} 1 ;KPr~q P,g+kHbRUuUq)*:R>ْ:#NmgZI9!McXVܺrmLx9H4.-])zY\gKN>Wev"-߼.7Al}BAc"TbXϖT-_18eg^^x|4|26X̪ RE@b1>[!J2^3P2`WuS/lJ"s*ޒ0S•}h^ :7GGnǭen띻<m6>\g+.d-̭x,ɢrM>[Q95BzʅOC6ٽAi0{[.;%sV ^U^.)ث$o+1K# {3M6 1$,~7gKc})=ӫ*ޓbÿ.y \g+4N$a;(EBO3|9YXgK,>,gUŻ\Hs ; X,g+,58ug~UŻEAa1Xj0XPMDC pJ2⡇)# e%NZ8*jp[Ϣ.~eKbc)S=^?hv`i %Ko^&w|2k8U_:Xkиr*o^ي;V cLjtOv{tXϖڐ:gUptOރrA>[bٱiHaYNС=̯يx~/<17EAK\|yYr1>[qW`_SVӤYk;>d_gU[J Kb->[qfJeZ ސdaьulɜqSUsc9tVTg+j] T6SCi+)zY\gݥs~CYzZ;vI,"!W BZ^N9Bg _v˖}[ TLj([QwL) L}9i\_ ޼.%W5 ӗ6i6׀N#orgƧd-|,{HXԢ!s6=Xu^̮iε$ ʟ3Ū%Yvf|Z;<5{Ӏ^يmLd0HW Er=[r]9Tofct~7#Pm%Qڑ<7eٙi\αITB?sK׾=sAY|H?bj֥FmS%mwpZc@{⨋" tz'KMpQndžzcC,aM;֡db?eǑogD/\ZCt0xN9Z6;wY 5X_2b:GbMW1{~nM~PM5w_{[w—˼SQ'ԕ6uH5`$/OpRPP[YQ"we?{v1{w/e|]Jve}7*;nsWo/>: ~ƇϹr|Yj`2szǟHf];O`*Ou( q{)|OAUKE1XVfk8u(zZXg,Y u-v u(h%dQmvߎk<j'5nNhA~;Q_ !I1T:dḞ+TąWF釳1. ݱ/w[` T@ֵmå%A\VS5:T>g{#clZ3B%7'w #CG,rrt#QoNBHHɖ!pPþё8ciq5&kkEN\(8}cJi1.PYǢ2u'[Q+g(Jx&Cu )e'NOCu.FT8hXTLK A2&'vtEarJVyY\e+^:س:ezxىt%y^^TMϽV^qKcie'LXPe+@̐A:pZё{GOMF/'}a"IIo,v}9MPPK M2(Q.NnO|kw;4N}  c96+b7A"תf1+j ߵ0& Gس@DJS~ya tAYl[3NUF/]r+j\t;B}qlPg~uM웗߲$oA0a֣ ,\`Lv9M>&3Y*[B}2bWUFI**4WON.#nW wUɰ},$ܿW0)v GQ>B<ʖLU.utpIj0ֲ+cQ zoE'T΋uE2Vcܲ>m[Աp|acNjd[7'+&&ze˘|2b| ΅0ǾcSLKB>A3s~Г1/fG?$ ->Pe|bԝ?1 oIEe$=ot_^NEJRȲeD™o~Q!BlEY ^^5ĶpݏX]Io#˖\w^X[c6,]\'ov)"=BT"bn.iơ z |6`bmӔ~PAz ыkKbƒ.AT[s ^ºvQcA-> Ol g*F |r|vDɼ{DUJ?o!c4{O>uǽB-kāyl 5Te+\ أ75Hrq%?+.ALU܃F=\k[-cžiЙML 9]2: 1!q/[3PL>Y1ƘB֊E/hSuyP*Vm7{ PdeKφQ3פо ,o#7ΧODObɸLa 7: XfKOC r)\S-~$+;kmK>0WVLGIvxs.z*Nܼ-y}ڊJxr*7팅 *z \lgK( IaG@n-> O0O1,#HMq%,,jul4{q_az\3@o\{^kva3Pe!"lgˈh )}q)I>f@$XPgKH ܊mcA]zKS4{ sF;=mHvyž֛ePg"æ9}(6!>=I8O9g>ɟ6pl>6xr OT/$?_P7 aESs-nĎ+v.B8ΖTUOV9VmWf\f/lɝuf+) 7qr,˲V=ZHἲ梅z{ϗNSflRw~כeH>1HSyd%u]'6Yr8[q :V_L% uoVԳv\mSIb6[b}.b}|dcGlm9=pn.wLGǔf|^\+,Ft@ ǎI#9 wb(6%wR8dU/4Gb%[A(83Ȁ3RuN|:;|.v`wxsf.z2#͖$(B:}%C{5tUS͖ܓMRCCYE`mPdcb)%:v3XHHlvy w'!M!<Ŏ\Iz\2{-PvSd lyͧg)=),hiDFpB]$~R*ORZ6*V NvlNl!|qq+$<Y>t}!A&߼|;S&aHDf7'l)Qy% sH ᛓFmYl[1ﳖf ä1vłlI>0OBI4UOnM٫+eń%0 bQ9KбXt'eY?I`b8[bQLŤӖSSTu)c3.=Ib6[/p E7|vK'7ݯ7/ *{ǽ8%[x.6Ȧ~- yYAq'8[s#tbҢn Byһ6p>gR@ɽ3XiRxYjK9{Y/O.A(sQ(S- :X(9 g!%c7LTZM2`;l*IJ雋Cpǧ!̆J+XAru%p-> 1 m4;(͋u46HO9{Y\fK(Ѓ_+mPPR`KOt7Ej&'\fB+B*Mt"pgC("WIe97/MlImhyR(e=,z`"tbC]OC$1mzQ 2~C'(^rY ӃOp@oV]'Vbd{9e9 tv͖؁ gҶNe2R V;C|p2otnWf3mr/L6\xpς`vqq{CT\;Ym;aRDq7'lُADҏ adZ ^[يˡQ `Iҷ$0giѩ6כp|na"e"[Jbv($l:D}bb$ [j*JI}͖\wE ԦGSofElD^,dvpbS)̭C5: wOL[]D=I뒐};2nx7coʵo^;ْA_NE킀TwфȎ>۳يY;WQŮ.ꮭ0,u# s5` 1%+Z~O=+ڢbHw:z7T\5IxDUBTI4ߛNB@Ζ1d>AUJŭP:{bA9<: XdKɚR:ɲSEܴ+F>kG7z ]yRӅ?\RsQ>++i Pw1C-C*"ζVYx{wΖT'6=.eoPTZ%Y%p uU UUj Q Rnn`ebɬ55ᆶŤ8uwBp '$iRoU$fYN"~Ζ\L>gV*K)MEϣFpU'KxM1 l{y g>7*VXu '!$_LX16%G57/le}1o7$ՓVm=1/b0P]"Y{JJxWߜ{wbR`͒ASM|J t$ -c SVZcS$kԪΖTL|x-%>6'&?8߼O>]}dž6$<7%?sDUWזXUE0-ʖAMʥ+{W׎t:ޜ,,v]KZ+i 6*sGBzѸ^m+Vijm ;vn.k3 {uCU{ulu9Yp 8[+VJbXT^[ي;V0rYwfAVkCLj]oN۴XuUbOScI>a50*}(yum-XB ;2 Y>NvҀ($?룓pe KqZR];bz2ܬFŴ|T}X!WI4Q Dqtģ:wƤֱu͖PD=M9j=.J֌Ho2Ev)KeS6n.}rG|T\iKBU ZoNV8͖4 LpW,4䒔j͖\PP \Ve<{F5lzyY/լ X% {ҵ$~CAf/:f})uA0a5lvyA͖܃UJV-9m&kȉ+Ib7[b}`ĢBP=wհ$Ąl>XX]SiSl5㸒B,.6͖XBC?{zA iSP ^w -l * fT[-CK.T'֡fh 6z ':E7LnVY&%Wzp4Y XXժN) +Ub\XPf+h_EHmmc.?VvŤTuwo`3RWg+Vm8ѿmG'AC{WvЇ93כt/ e<KHYI0POj.sJLͨ/oҧT-dvY0U*7!'nf9mئV\VajSb9[jSCrҥC^s_*cU{bk֌NVLΖ1Au,UǪv:*޼.`VƋ]/-fvЗt^{ْ QpYuQ+f{Fxtnarr]ѕɐOՋvźqXWHɊ2ZRGl1f3"N+ȱaԮ*K)SB9z =px}Mĭ}c=NJ2"ӢQʲUF9vd7 ގ&M%pcU#Y؀ڋq).6unNP ƞ 2wzT N, @WAyvt%6@Wk*/+$gː`Ԍ{:ѕ ]yd.6%㤊zT)rm XL,sFCLsVW$+%ܽ `r IBu[ by:fp ]6SԦ@t!ÆV4əF'Elm4,:u\ Nѥ0rE?ncJ/{p6[r ktS*meEvxۦzkpnTNm`_vfG!t"p:( WlƁ䆘ShF7z \lgKT p7╋;M%V^ي+ʔ8,Q^qLQp }R`p>kcs_7)7zveTcȕߦμ.q:E,,7Nu 6F9N%ż!z677k8a:2arY 6=y+\lX+:/t%6{E_\nBL ΖaǪ^ƹ6&R[.,2'(pc=O|u5쎥wuش͖d׺*2'#$H*|_; 4\SD'Tn?@/쀽wcn}agUL@ _>jأk^7 p а9vyT> `}c?1Gsrܮuv vиU@7n-?{^7͓qcKVv)~tg?]?qB`Cwkn,PxBA1R@m {PiM[Cޚ: Jѿg ! ޾fzIټ5C['Q0cfЭJ>cԔ͝G%¿L'a\{,]ǧ|h? f % sޔY8/kg !(w) v|hnO C.$D,tޒ ,(_\ڙ :MZU2`]ନ֔͝G1̹G}$Ͽ,rj$?e,x IwB|hϊ|J,ټhʇNl^\,Z*y˖Lnnϲyq~^S G鼄!7vb2\VH v p>!A> Ԭ{ G'ˑ0S 86C?C!fG{C>4vb'jG|wp/g ,8| MB3.S咒V){C>ur5%c~úZiv:R['QwL}vb3.\Syv|h>*%Hb&a!mY}w+w.uwqg՗$Uk͜v|h>*eȪn&wݚ? ?Je dr-XqX_dܘ֐NgA_0!,zfBnMk#G:!*Y{Ku7佭:+l,<1oykZZ5Cs'Q|,sC@̣b|h> :W~M}kO`76W\WV7s2Ļb"ά7djb~2q.Xڇ&7rtn kngH/} 6'PbxJ< mTjrH2VcV<%_5&=j#eC/]Ok=r}j[K'A(BD,@c3nNIY{S_OE7 '/oԎNPLߩ%Cc+.I]Xf<ǟA0ΓЍPOr+l P ,dnkw!f@2SG{LPz3q}j[C|T g>^YP6cAcC'Ar|j{S'AFiioїFM2O2:7Sw U+&45tBtn @w :3oID'~:ﭸ; O:77#c8;R|йQ-<@1P`-I/Bk%A&1ɚGv $Asc8Y:>xk{K'J_e_~|PQmϛYԎsza]Pɽ-LmW'@kWWQub4\nOArcngԎNJ#TdQDV2ЂBu._m q6o-AW[EV8㽩~TA ?g/ -W˦oT?= r8lk|h{KE}R)A@xؑfֹQRsK'A$~OCO߽,WP)yjwkGԣȍX2ObNe;55uRDVz^9Y'2n>tԎNǍ,v[2v6dbS['A#~`\ X{Y'U[pn{wll{M,ǍXExVP5!mIF~ܱWaqI=#gOΌA=Fv!V𨜭~j{SE}Ȑ =Ǎ"oxk>[|Pq? }A@8.U:\MXۆ0^j{['A3IFC7^xR{C:*7cq>aX!mI(reRčG{\S;ޛ::>nЂ]P1t~h!(*u* OJv7U'kd۝qwb(Ke5ų`̶Ԍ$T} zmmz]7h?j p}!xI|A@Ƕngϩjj{S}=zݱǸa!w/Pgavݱ1.b{C7?5佭Sfw߼C=ű(jfbN7Uԧr(Z].ý9A-f5t2JgƟ0V}F̧zG,кߠ)gC딠2NjZS;ޛ:o?Î!G,xԹo׿PF\< O yoGdc`^L{ ̇2vhMl5O( 3vVM8,h9u7jlI>Tϑe(t?z7 g"_K<G^$=c]*acC^x-\ :˷(lB[C:#ebY,va;U0V %`*߂غ߰Q?E>XQŏu#(קv7uRfLTHб{OoYymxoD>)A@eqiشzݨj¦ TFq k[N͞ԐNCv);7l*THFrۦDo>QVu|cԆS;ޛ:UOqݩިg|^*}g; FO-7h PpW 8\ЌTRKC!})Oxo>Q=*q6V!mV_ŖmP*Fq!LxR?5佭~}CObXOxoD>^Lh|g`Pq^,[+Ic-=*8! ԇz" Y%`MbخxxFj?5佇}6}[ {<#5㽩P 3pzEelƤT :| z7jް=SIT F<񐴳~j{+'Nsb8RCgӰ9;Sħ럷FFSE >e!zb߷q~h{;Ez\7lĦNOLEf7f?O߽&Ѳ%6DXIRQؐ)R)z3H/I{HS[Ў%lb5lI]@V2֎8o L,gKf`uj%Y>⽝ꕛԳl!R'Ta1-̀:|u._mV7t2XgKl8eT#\!Hxo\]&թzxobu=?N+K#hDYKd I䷶si=[2PV'}+IzFRٿʅlI JMSB-ѷv7ub-,EYܽ@;!mX,gKld쨏Mm ް/ICh/ԎN*ֳ%I[ XL.g f@I>%I<o͜Ltj0XU?5"𰨞-!&0)_zTBnOxobI=ی۸avޱd;Գ%6Xb^ؐ.X,g lKQu] !mXg{zÎr;mԈvN&Vҳ6R {~jg&ֲ}8tbz.>|Bo͜HgKb3}Bw'loqfqwjmHE7g jZ[SLu ^Oxob=[RԳf djlɢr=ܠߩx[ /Q2`Fs2-LFqw\L6SϭfYng3n\ǸPN?4"r)=[EHV Ⱥߘj.V.DC`Suelo'tg4`\|j{KE*z ި[SQ@*z.HNyRQ'xk\DnԚ\T)0[}?oXx*z [V;FAΆLljb!=[b-g5ՖRAm?tNjo\G֠hCP:+dv Y4$UZh*z7,25-GacUl Ghu 25TQ-hPrc.uvtBO?ӿ/?ǯ6x7 [j_=W(n/{?ˏ}£J{kGQiO[O۱OO[ۿrۿ/fcw>ӭ}CsjI:7?ޠM7 4׭!_gk՗V7o|Ѯ6_Yڦ>z%޿z}}ŝ&[ܫ ڎP?z{}'[3z ו i/nru{m_kkWG1yyߝ);bWֺb89^CC.Q?]d~xU{}ueN3 vU_k[~]ۯוIu|C+a׭AW~>Sb8vU\hͿ 0ּʀEgV.Wl?-6xpi~~w޶SW?ץUWc]Sv?Ga3W|T`P0JL^Ԁ_{1\ Cku^g$ḊnWm?|E͟}z|?.cx¥=/w{厏p|+/9|i|P:RWmK]w?~&ԍk2^K4.Aw, _FMv 29KCRw~!/}W?׏`+a3˟|y|#URz { mۭ8_KCoúo2V~˟ *VCl ۦY9avt!]~ֿR4\T0jO}s4[!ѿʍ<]<[͌<߯7W_/w<;H3ĝv+:zSVk&"ή{;[\28Zpバ>S) /3z)Kts5N ѿ3e撦:NVj-j:z~ĩ]t•="?|7>9_V> O 9V./C/mc |k}.ᕦ;ם|jnc} qn{[oi N5vz97_{K؆ ~uܾi~ۄĩۺUIӟlh;L7P1W I'KۣC)K?8O9nٶk0g6zƜ{e?1.W q1́C?z$$9ǴAT;R$^ÿ;iޭtu߸sJW՞7ղO*7UQ:Oe3#JhRK8Ck~ݡ};t0glymޅz+~Pp7a<[yl ٙVsߢg9T|L^'f> g秿/?`)_sP2t<|mj>;jd;輸zƦt[W]ڠiltC_nyϖUI&9}4 {wc5ֽ1`XZTwŽM?bcJEx ~/.kjb7!0-@̺c߳|Oɧ3 og~u$ ~{Cw/%s"_I˝/?0{4.c!_ܭ+E/Z a_WGwW)Ϯ-Զwth#?3ú Cnt2VC쟷0,0_{ݽ]_F`Ջ Dݑ7kh\'r|>F,<̅ͥl}{!#/~~el`l''혳v^^կ)5>V{wm4n~VzާjDjVHjP(!y{u <$<%Ri`K58TڡU,J18XDnxdK"f2/į~r$< O=ks۶˿nTXߙ_@.BgK7 忳8_c߿A 'އ _!G/`R|;ԣCࡊQq kИ LؼOKs , F IBѣa?n|Wķl16 2U +'avw|_bv9KF,lI$`F%DV8!;&S!xH$wf+$ y-I8_Qy_ޫ,N"reևuf؆qXB͝vea!ؖ }'|߁! v/(%ETl$Un-~ߢZً& \l:s[6kqm6:ΉJ Y&*W*?;+VPՈާP @$AdK C#ĺPx ~q\f>P,"KOJ#ǐ еX$=$v%RI_. _KvRĆn4(X8w[;.eK_6~|2>ո`րkJ.lE$0m_]c {]'xrDiY}庝k6C~xM"e+^]ljݏn'yi=5D)lWv]׎>Vo<h>z𰐬C-m%ЖippջT /QSNЪ m&/l<h\X=NdXȸ|נ\=Y>:@V)؛םђv1bNQީq<,$Od+d VQH[S0΁2NuIcC4ak Vp䌎͘ -Z4rd*jyt ;+?ާqe2W ny<jɖJڂ}q7Nv`Cf~>p$[<}^4`b'q71\s>x SڽO Gl OR(ީ祘pՙ<$%et/Ј;68pQd\ΖH c'6!c@^$͏֣ 'ǩa0P t7VH,"){#}fQ!r`Dֵ!Sq2rtlmGmKS>`XΖmǞpFڏ~כwvj lD-2-x!F@"y! --g"p$3_E ^ k gU "m@K;^طpyl:X@Dg+ _5I}Cn FN|5l@Btjh;*Vfǃdo8Ca!:[>w|<]m6ǁ_ˆЄ#xXH.Dg+do5!QoԣxTHM85pBt; 3o3klg>@ O6"׃< S>pXV?bK+r*Da,"UIEƖ|߄~*SܛpXVq@dL'zPZpG@r_)8'89>lN؛)\ΖE?lu"ljJm]HPM:<$V"wsz>\Ζ@?~mԫ`R#WjttXV\F-sp$ӏƇ<$UŘs<ĉGK\P-tr\DVıL3mJ|(V"֥%k84j\}̓*%7`.-8ֱn.׼&i2plz59hDѶC&88,LgK-xŽ FF Dpj ɅllEG6 gދ E&8DKgKx >|3><($Q& a!2ݏMo#IP (nȣ&̺JA bi:[n .#8l{LەEC'|>2-:♉:ﻊXHNV a!6(RP[4d©#,v2)5vtD}"uW7rZ%q_FIV6pfWƨޣ./rG A R#YvdZ]'i^EIg#Yuw>48x¬2 րQ"/q%לZ8w襊W6/%іD,NQ0Qc2VM'C\\NR YK6Mi2;jM~T8"NDD6=PЖ38pʎqW=`ݐp"V}*XP θ4<$%K^?˾pU+|8 ܫrRTV8ޫzcp`O ɒg#~^A?(.\3"&`H/i5pl2C98P `x I݁`+'ٰs߳μ ^5AI Zmu>@^ۼKOrY 8j 'c~>b9T!ųO`=y GEmPҨ Q%VG P4j]z\,gq ݫEEp,~*?|uMEoީ;֥-;iF-VKK#Ʀ6"V\w܅پ ץ9S}T~N=Vؤ0)v!DՅ}U%8DVODM>^fiGe@q ȔyXY=ZCaX-lL fF,L'r X,´UPXSwK[4d /̓%DжhbU*GN@ީ;֥TdDц!jm|&6TH<ydZi"i&:PJF)٪\X y9_7lEJrؼ[!btTfQX%ԫj ll(]5r: Sd'ւ %z:litmF<4ptBV5.W=\P,yzC@wiD@ LX4!6QXw+'llUըIޭgFlޭL(QlD :pU~b>kL0  Z$r_ZVxB8f@ ѐfK"ٚU$T͔pûpzzJox26Hq,"uQVqG^3YB|kV@Jt$^Ă]*YY}Z9? XLp2Qeƈ;Uf\x#O! -:Gg0(>xXVxA0byRû‚t%,y?`\@4$`UÍsؔ˻Գ$n#Uΐ.,}z^6"bp^4hld/Ԯ_`ulɰEY7M :ʎdl8t2҃dŋؼSYQ<;XDEgKr2י“5%QP#K+;@,EgKXY>ovmʢ4 hz6EDӮKf:j{7eN@('"lIhŒY2ψ{}xP!{HDg+$ W%ҖKf:+y̝5i ɕlAN\2+f6^jz  Vx/Xi=;5V:pz U Uޥ̞h^ZpyH)B=,c3 ʴ7F|"k%*G!7CBa!-F`E<"۱{2²_"9Df0{ոY.l.G*ޥG@JtʿvZ6wcӰY @?4jld{*Bd|,dNMBtDp*H[,LPe*%v 2%nK IBQU΄N*k԰p,"W%kӸ)zFީLCو{IP OZk*`g((h ]0,EgKW ܉P-L'.||xCkPC;MQt_0 %P;a=4 ʈdI|<,$%RSEؼSEa߼WϪG#w\NL~eP ߜ5z1?XVʖ8GQC;g:Vo6?EBt"٩cyR?@a߼?S/ ' 'xy NOBt|ދ`FymkviXΖH>6-놥L`ū y!?! -Kŗf<VUO ?Jq):[JcqOn_(*V<)ǒw7+Y.饻JsT Eɱg$=]d:T鵴uN?n"ڪ.#p%oA'x. ~OsY< ]o7t!ig(ǾTC&E EK/A%r?o]^ ~?`h2C?/VspO>zatui.:On_'} Sh"{d:gO!* R+Tus( 2|i+/k!*=:\MG>*8/ ?f;:m&4Yye"V\ge5KH%o&kWά62g hTL}6jt:Bb3YN2fξ TQ- ݾYBuyJ['!@lR/ le\_Y+~Lqc-m}u!H0>< 8@ #DvLN-b(/<<Xo#zkʟ3qRd[0|P1I'A9e'];Ix_][h"45Qzk2;S[ⵦ*wXC^'%PY6ݥ?^"G6ٞ%:4ߡeM'ߘ N+0\*|03_~.t@D+ş( iB٫C={IvS{A/uY$ *gK2> gqgq˂*q4 ?Άo%jyQђiWS^5C8X'{§#H.ٷ|mxP-gy,O!P뫳s}ٶR@K齴ѿ2޹Pղ=~0U=gc|xY )ݚCLȟ+al j+N_+yr% C}m߇=|ބ%mǡe"a]N@l׭?qXh{S,JTꦌI:*I/}z̶ʖ4WXRԙRTUi! m-:2 `W*x".Qy_8fZe+9r977m@ȶVHDtmp ;FL]TU V:ZKIAdۅY!'7EdU"v)8)'=eYFZEedlc@؇䤥[\\3IJ`k. Muh!BC@/!=j}D鎂WWJVCUB2)hbZQ|v԰ Vْh Aڵ4,dUsY!3*>mZ"If)͐oVْȈ0ZS%KVLJ%2xXH&[e+$$ZVuݧȶVȱ+( MCS=$F}>xLʖCy<$`eQK8S 2s{|%A ."Q~8T}zNgF2*[QZQ SBg[g%,>O<$2%!U:]GcC-~0HdN4ezK#8ulITU%fKQT|!Vƃ9 Ȉ.WݑN#5u:<%"Et$Bt+.CQByqip9@,Kg+ #;T$wh:r%N4wU:m4"J~>Y!A6/bQyV 7> xb<4f\58!:iӋlE]vfS|xB] $A! +.$%o 'r@byXHGgK))$=lh%l<[ DW9EĂt"$))|g0O/=C_.%ѴM7֣d#NitZ3;2C@b):[!#:884hK:oFTZ=F1<;9uf! s4[!ҔJ6w!rXΖDd`D 4(y1=v_ llQn OnC<0?xXΖpK >\Vvעry$1c[1A<GC孤5Rw?Sv-z K xΛ2y| y< 4lsTH! j-цIy%}>pX{Vk&W){4=C3|Mr\zΖ7) -+nOEOSK YD2yf_+cSΕl\: R|*D@$vnfķ/ %}]A{ <">6^ ֝%PMa&J;Z!8BbxLN,R߮2'Zn t tsث>5h"RW;7ǵCy_@.:g+`I:cDX.Lq%ElTH]Ƶw MpݧBZp_(Ģcn?mTZ&p9["]KB:Za.y:eʖIJs2$fQT;l8zK!=j1g-.6|$5nv[Ar`aC@b9[!L!+{ǐl>n5^sD*USBr`B^Br4[!9 Vx?L cիĞv!AY7~'M'xXH.>gKb*gw Y\"[C'xHf0CAew]1y W8XI츢TfU.$"OhU\VH4`\/Kt@B{tO!ݔ-o *F>[:BrM:["nQ2~Aw-Ul<V=Bnzt22V: ]9dDoБVgi͓!4D{0y - g*NA֩%O08XDDg+"CzKB岞Su|nI  ْXb=BeOTA]T\_@.Cg+ #CQ[ Y<+  -+ Mraf\M]Ш pXVkWc寺%:k\ΖHETJAeG Vi>{XVH5y.ؖRz %lql1Dʩ?x%-yh}e\1e;jUҨl T@U}hh"nSpyXH.@g+9u QɃjcK7E5rtBi_<+.!u[5xXHydGqE0 nS2\L|a:[!D_xK^Y M%!Sb︮skML5lE,3WĆD·Q1"V%ѕʠIp\3Ǔ^iSR! m&(Yb>K}r=%62tDۮ| =\O9ubC@b!:[!!!c4Ւep\Ζ#&Lq1S1t"Bl:2wsÙSWej3.l3sHW>=yKWyXHDgK$:)yԞO*\Q XV>3w=r(W"r):[Sȱ_+;]пmtefkD ,ZxʖHD.8z%y\VHZhZTfOq%#X@bt$*q3dG{ вrtB֮"{)ғKʅA bA:[SvSȝbhC@bA:[!ɼ+zvcs*siΣ^rhwTZO`M!Û@rt"֙Dbi=N Sh3ec9=pS+{ ylTDEƴWNOWޔ3$dʐ]XΖ#/伔Vۋ2\Vs&u{*GdbA:[L sz8\Z K#a=TaO'lj@zr9 f#&-ugbC@bQ:["Ԟ,W<_tWv)h觱 Z\VHu%q̓e E1&Q! 0-P`9ynTVMe9@,Kg+`S#$3$?p\Ζ8sjs" V 3} &uJHmE&xXH.KgK$cb4ӰB.O'J\_5Bra:["5u,=dTrS!@l"֌f6'K f[,$T9y?/'W, !Qee:g>R0 X-;XD.HgK"RmDȷ] x]>pXVs0a^bBO]Ypi, ȵl\h۱iWw V `Hǥ|Θ&W /88Dg+bWH`>OW\ỲoUf}~ -y ?m%&&P-\يXC`!ouW䊸O"t^=3z4ͽ( f  Zv5pd.4E+gr MxNʖ}:@ڄ@=0u/ נ!Ĝ(׍ a"hC@b:["eh4mR ڃV7Lيv|jiˁx/ - h>>BFO]X̐ZXVHĴo6SzMٓoK 9f&zwK{"%1DbCZeUhZ7Au$b qghSz:M +S#'x<@g+93v4֕X̚pm}"qM:WJOȯ2~P⳹GGцmDmP*zAIEq h2m]J֎dr?TDy(_셡ye`oy= .@)v#tHsMMiiq{ x.lww'd!gOcs>R?Oj{wtmc_ I9AI+;Ǒڸƙo[UjrCa6|gcW/}_ו'{F.qp:)P;m=_ b`dA~"KGǪ85R~PTs{y߇n=ZY{ѨKcʿ4Q~oאi>1yű+< M%t{Nc[mC ep|]W|7޻^8~W.绅7%Nf½{jؾ5 b;ſۥw_|#kp9?PirdEo>v#P5g9KZ-UdBXw~VN ȏD\Ks'灬B^i;\(2BJ;CQK} $\(r^%yXL_g  <$^Lx]9w˾q^b!ؼ߸A>x붍]kwyFE"Jz VkL^oAsp5(󾡶EhGtwyGn yEuve[@ ]7*x7Jne/TS߯UV|=i V$:/Qu[e×ԏ?PSldGe+! mzݧ\ʪ/%?gE|V?}V'hw ;$`-\qܺmun۱ԅmc (1nbN`W ٧ $Ho[~ Ʊ'/ǒawbNUw|?}`Q`;}2biKiᩧ>n\ þZY)TO\(HyT-?}b@qNuw)@r ,PBM|.?}kXLqw^AD96\~l+4+7h+V>MC]6[j, Ħ^HJוqzByTD?}t-{jD5SQVYԍM S/V+RClzք6xXu;"{ZA0ҪߚShyNx`=>]}kj%!85lüQ !X%6vpr!6f!Gv;h*uDN6Nm`H[N__X{ChV;pA'V^bOP&#ǿBK45[K_>WZA}該 ނ, SpyYIRTUVrMlۆ*ƌÖkaT YhU ֫^OQ"Uy,šp)! ?+_>O`b |OvY/(rD74LlKBlT|J½f𞻚w닄yȳ~*Neo کxzQy[cl4M|ɅA~V:yXgzKG{GA~wMfÍ9 =JCڵiNO Dh<W8eK&)n[gQnSl8ER(>K'/s%R6p >%oĝ`ިSO H*f&q*y 5*[FB|+0Ѧr0L7lIYK(N.җKUDvTC:Fk_Z_pΙgOўŖnCa Ɍl6R9M#\;hO1 !M\LϫLMo>Re=@lBA*W & Pl&1&x6}HE$=+BN6g'gBR7TlykI߱J0դ:ճ:ZrMG\P(C:ߒ%HpAX Ħ @#\ T"Λ] T7 lDQJĹ<[_n)b:LU/m*ኪ Cꥺ̻U}>`^bT}O檝SWl|j#s^i`2d$Dbl>Idq#G-bI}`aީ^q@(#C?ne ˡ(`<'Ý%&Ve=ES(G]W2u- %lbn8c?hƶw nB$ث̖Xrb׀RصD[;TUaNeⵊ%CcEjUd7 ɽlW=/HG%𰠔x)N-~OV IvvjeN\WZ5eiz/}셍C ئ̖sYEʮ;骈"r2[K2BHdpJϗ*vP̖H& XؗF4_RçÝyiRoIKΎ]=nVO|k'nDZYŝWFxxا̖HxЏF`R},ٿT`KيظYQ A b}yOC ~`Q} ǞضyQTnRf(<8hDf)-وX[x"e9()%AIN1 81NhOfڞRmplIf!R<}O6_7+nSfPpP@\j|a2[zm ЀKqO̖HMU%n C_2Ykf\I[&U:pa罣d'@|7FasӺC)3Wb9ْh#p)$³$J J=RҋA7 xlTYR[V$ܥ̖4$$X;A b2[^I~DAnDƦ >e\. Gx,O4 uZnN =\~*vd!TF8l>fgDQ)ֈݝ%OU 0ȖD?viI0i5.y2aܮ̖H?؇w"PN<dpM z <T(d!>OB$خ̖!E/'?A"T! ەي̓nu͔8RY~Ңmlk_^@oDRآ,xsئVqo{M w;&9)QϚE\B5?=? =jz _2 0\D@= [يh[ѥO巃<4 irܥ̖ā#Tu߼t;T=SKԊ%issH%קC =xT]?]9,No'S6CbAa2[]tݖ~JTiܡVH J)5%nRs {6_χrWf?pFUS. a!=l.O@dۥbXjY`a!O-.vnFS݉j/TOM<&fKK^z<PĿ`|W^Լ^|Pp_e[y6e f!Fa]Ku#)֦•7]lIZ+D $[6m{e 8&f+\F'?|ZUIԻĆ pyKOM!f mP(L1oV(ܥ̖4oG-SxQ恢Y%T3;@,%eKM @P`G̒઴цg8<$6{] ,CnqݝՄI\ݒ$m`$\C;$S͛ 7*H.nil璖IJXl6ev9G2;FIUbY8_7 hȳY)nӈnیEwձ{u0So$*SPjVϤXA[2.N[Ò>5JVG! 8-'6Q&KKB:onB睨ӧUViPuL=Ip0#_-#O'P0#$jfl mVGm$Y BE _uV04g%)%IwVP;8_7^ՃeൡΥ!umPc+}~lMz^h(ӬY\UnV9DVfKMXDLXyCjL~՘nܭV1kB!umPc!+ڴHË5m,Ω5xo4kuq4L hJSI7 lCDMK$PdPorX։sf#MJ ީURZ.Xa,6L0]1;Ŏw^ۥ6Zqϱ Hא=LĖbDc/ҭ )E:iRi ݲmfLmMWܨ̖qDՃf$,mS<$6*r~{n{µu,=vbDՋ("<ةNr76_7VLER Hf-`;?e CdINc*o)%}"(%`QȈUiHzX"3{6_7(E'Y[jǥd!} h< 꽢<h:XIX*SÙ9P}>аC-ENSDR23zC@b2[! 8(+dJ';e 4Q.D=Xu .#hq.eY@T9/<(5`H,xHܤ`s)M+u'UvgtW.$ɊGU.!굂{AƜԶ;4~?">e @ɛ㔪mvx:U:Br2["EUugt\7F˅ Xs"מ!#yp\2%c^3;$!~s.e %#QD)`u#;vrاV:+Xd T︳cP1<$v%҅4EUPF8@7_7nUԡ%R҂8xEN~"NeMI?BI1|O޴e&\ %xHVfKEC}m{;o|<띥zF)bc4\nzdWܩ̖aN" 1%G_75l,ZD`~;$p@ט;;5U}lg'Txا̖H m*T363LQk~&SѺX)s <[uB!_s-V qtKi[Wyr&ef# I5=8nۈZ󁇵lkX(She_RFs9<-UEVJq; ?Kpl:JAtۼP\%~|2zRE69+9ǭg C@b2["] e-ށ !=&쇢 ۉ 95 א%cC2=;plFD;T,ܝs)(wa52pRͿpƹAǾՓ}ܨVTȐ NF8N6pA޿3n.VXƁg [D|lD<D@kUwC؄HzS"Dl~E`{,dykDW4ǂr2[AAV_6lqX̖P2隿2PRH(qn.m) +Bɝ͏,[97쪟O3F}ykҝa??I*t'[Ssx5]<.V_GD;~?X.erkz祫kU$5gs?o;"{R_1 bzjQm 8thce~نyKUHuLq]|I+l_⬊w!V)BuAs y_h eP冧Ç&&.ޣ׿g޳WxJSt$|TJ2QOl*M}vxo>o%'?B5P;7˓9B~h{;'Q+1-"5eMx:⽝>f%|~J\E*8?ཌྷ(D5(QSmH"ېw+g3~_SlCn Y*JF&[9jT 3r2LTH,SjLA5P^f(jЊvN~TbZt*FLfjRc$f=9]棆TDy7fXomHʳS"5տs7RgRo~ݘc Y)E LM2L=y1m`XDR[8LQמ" ~"t7(nނV RJ @g_߽͜G-Hozސ\X1Gu!o܂g٣ <%}\7bhB> %BF+#C)F'VnLHE"E?nVKL-xo>%W k8LA{BeP\gA37⽙b> E!CR#/%Ț/iuo{#|J2ϒ]|ybj5|I2IX+ﭜG՞zd$3|o{+'Ab'#r6ukO ;b"%e|k 3>pEp Lik!o[yz7\[u.RML o[=,PM&!t@LumZpk>ԄP 8BD4L$a޺AG1 p cSb^*ZR2ߗ=wCI%\.ƛc^{Ўs 8?7o^?ǎ/xb ;ciGA p g`E|csVݱyb&N"K X!nJٗZĴ3-{kޢ=dۈPP͞NZpk$> d/}/p">h| ZFsDN9smo7Y5 oHOpA=(x"P f̟y&'!Lp5IIǜpk=(WxO/ړXH&yoϼ_(wvgK?JԀ[ A#&qoĒ>z"˟6œG8ˢmKВ$Uހܾ(U̺ab{-IVo;Aw#@<ꍈR2[Ԃ[|ZsΚl.DF$yހh qn}xod ^>[3ށh&.Ek#Jod,¿*.w|x}ҚH~K [[ %N|oW#A"@\i$V$]Zpk>Ad=9Vr.'ՆDSg܃jC&|Sw@Y1ߛpk$>6d1}Մzk GB1{rΊR--\] ROR?!8&.a2Ңx[ nM\ Y\jZpk~T)' Ͽ- RÉ}S n*D?ݽ5I|kųg|@@|<.L`N)`񾂐@v ^orbo[Dy, N9kpME|}oxpg?Ɯ,S 4?+}܂[ >x'ud [0 P?v܀grOsH nǍx7bl­S~&8]YtNS?ю~ƫ|WSwU3yj?x{[Wր[ '}&$b/7Z,b(L`}o:ƪ{o P>G|* 45_P&.Cpd=m~k@n=xƍx3t XXނ[{&&NS_KK:@/4$8PZpk~žVm''[Zz&Dbݏ51qg' !qgւ[|i L-y$^7P<hK^g=ܚ8Oa'T16!{ćv?Xjo-5qjߎ@ֶ '`;J~q?B;L>{rۙDbU#ۍqmgh34XZpk>N_T),|`jb xuϼ vxsg?%ւ[$v&xOM}bW"so>N6Ur> p>֘ v K JLhp.xmǯj3}x} 7 |*W4-Ht (xes SKRPԠF5Kz͋0v?FM\s)K3p5'xQեւ{#: *" ؎Oߺd*g,Y #UK-5q/x^:4 XT8Oze1>o[OsʕamS/~kݢ=)Djj$&NSLpEUe?])&.C_~x&^*TI8KãmƋ.C u}mcJZ7|"}k l |*>įMK.Cy^ZqLѷ8O%y Pzy3@˾2`{ nM\ć"_C ^&8OsQZs3l^vݵrsb&8fg˥/c??o[* >&]A_^zo\'~npn%DYր[L ~,G&.P6XSn2Oh3DT#\D0m~j­P.6@nD&gmxBvC'Zlu>nr} :{Ob{n0גּ{(;mS#aOe\2 F{P5! wtŸ־ r.miM~$Z0d\o W7Q$H͗@<ʍpIr P駆>|Sބ[ْXF& 6N"} 7`#+8A%EQO \8,+gKU!C^?o<8#bQ9[&йs^`[ nMDL!nUclO.Kr$.MSj ~j­ae9[(Zpkbi9__!)>q,QB\XΖ.׬zpkb]9_{+@+gK8EwLjo-\@,,g `x /en-p- &0pm"vfyS nM\D,gK7`lAv\[O--\įjG` ѐ;W F5oѰ-k`R-}b(bAWqi9['<s"Us?V؀rѿxT;ė%wyel $@γ*, r&X7./g W|K˓V>5 7p⸸-qeϼ,4ـ[п!myOH>b-eȗ-^ N @TK}NAGт 2euT<CķN&M6usNJ󩏙u lol<Dq!->|c31|k$ra9[Ě|Py܈ܚXX/'/?Տ?v͇l*}^W??ZL~V?m_BkVx?FsV+G~͟M;vK h˪ٍ6ǫ__?$RXAm2 azg)w / \sǭ8+[WX? Ql/j_WW.2)rKjXhA^"zC4V5V6+g+_kr@j'΃}$ \ endstream endobj 3 0 obj 497574 endobj 28 0 obj <> stream xOQ/ƃ^x=xœ51&rhT(*A!AFb h@EBPR(}_:󛶔.S2}חޛ=9Gk6v?4Q Ye~jJf0y2c 4"CaȭoƜ퓞wףÎA~ۣ>k^K]RiQW%3NPnm= 6l\6-J C>@F(C2(a9B6 6 a:;9Y#y#JԁN7ӓr0S)+/4 kYFvW#h$%((W?!=pcÄ{?i2.X?!έmeﴱ4 s%hvyõ |h0JƴhEY*ѺSQn*Lz՗ih`dxC!NhO4.Ie̖ff0xykNjc*"34ߕ~ (7Bٗ w\V 4޿_ NVqiB8d1N`paW6Xm8{-}& #VcӀmFn </[F*KJ6{ZV#TC뮝3>QC8ncɅ^Y Y FTكXzpMj\HU>4h! tX(ZaN Hư'D*!Щ.$Nc *Tnm endstream endobj 125 0 obj 820 endobj 126 0 obj <> stream xiHqKa (%TJIK025,+NʳC˴>J+,c=Xϸ9z`> <03PȫMLդQMCKG iR:7oVRQ^ssKJIB@& pCT*Ȏ[⩦T7nD~qs+"7O-* Jm6#]Ft'asDeUumd.I\PiU}WR ' kifCcߤQjk 5b"KDi)> eH#'zzx c. | :bȅETsB8ni#R^e_(dA>A7"D ؔE`!*u1 ĔWhFxx"ϢѩbXe~t^W':'Q2AB z3Nx rol6XB QA yߥ!#'sf!@")T2ZHJ@N^A}#2(TO D!`&r1$ s ѰAB0'nE0df/=LM6Brv+4_ endstream endobj 127 0 obj 808 endobj 17 0 obj <> stream xOQē`{ (&'}hѦ~9\m,(Oh(oJLE7f0C)^i.%DJD!X6j C1O;p͆wVR|똱bUSE!Etbð[QJA4dpm5AEg!bֿMyvAGC !GT3ART[#0HO$˙x9(? *.bA*˜<>F2Nhr-^c@@<0s,*֋\ŋ ߨBIJ+RJm endstream endobj 128 0 obj 823 endobj 129 0 obj <> stream xiPMapid2 } ׌5 %-Ddi,IRlYZTB,TiQ."tM<=8u}9Μw9 ' 0LG6]./ )24$>g̬9zy (hqN7Z|5'7lM5we+VYmbߩK\)z33\dbfvA %N((ӝHģv;) $(6!%=*$746YnG]Eڎed PŢ#[wR3r* Yϣ38/ID)Ƣ\IQ Rd (EaYE7 7  Vdj:<rfy?zRZ+J=(R@o>r|5ECD%[1D#'#aQs`5A}[@q򨽓_l(:w9=Ր>i>!RDL\ҽ/ jbw`CQ-EܕѓrAsQx8鮀|YWC(OSQ ʼnjTXD~w"eơ< 6~C**y"&eC[O?#\J!7FV휄²*D["fIe[?AahSK#*ix[ڻ47|HsAkBީmBPF+4*m 7 endstream endobj 130 0 obj 823 endobj 12 0 obj <> stream x7KlQ1@KkRĄ  1`kai9眳OGq7^1]p 8k5͒%K,Yl̃-R-ՍHAAAccc<ĸL'&&NNN秧gggWVVrssNsȍ]xkii40y嵵5^aL0a|9@IW?vF5L%ýMfff ޞ6KKKxp8gggȭ-<$Z[[GFF,nnn1 E-̸v[LQ.,,}.X co]Ϙ$$ɇtAEc 9-7pQ3%6>>ί1vA`r է.cctɧHT$0@"9P9zRt; sՑJPPR-9==="]J0Xss3`pAI1ʟ 9bgr$+˞c+ zUU566BUSSr*jvvd%i0F aaaqվ 9u]VRqh&$$h]űLq *0*I5J T2Gvuu%0v%lqqqR)T$]Q5E>ʥȼ\rH9]R>[aafMU#""LҾ?] TR=**L$MeaSbHoɒ%K~ endstream endobj 131 0 obj 1000 endobj 132 0 obj <> stream xKO@A4&E!x5 DB#J@£E{w[]|\l׫a=|vvcYX_$ 2ٲ!-ftb[ 6,&Ϧb`9>u㩊YfZIMX峹ZGd@`Bϸx"C=SdX |a/_Oiquw .-%r/c V[^A y(e>Ң7"6A ٖ Ԃ\7)"7GnX֓\gc Hޗ{O~#;P=щϑq|3/PWP.>) *lH G_"sg,u@0 EIL/ Y0C`Hw@:L370P S"s|6LH endstream endobj 133 0 obj 426 endobj 7 0 obj <> stream xoPwnF.f7hK+ӱG@Z j4g#x \-0`hp rs6s9NL2eʔ)Sqt4 ?!3E1g\Urѓlc9#~x뫰sI}?^9|_foprֹL/*$A K*ޥ +ٜ>^>O-oo!+ `J`LzW&|w gw*VGRl{1; q9xKw,,Wۿ|33G6w.v^x cJe8=#zb] +ķAj*6!-/h_F 9fZSL2e$ endstream endobj 134 0 obj 747 endobj 135 0 obj <> stream xt@L@/h$BX -@~Di9޽"4;w8-}z~#?o߼l}'(ۋKg7v~oyI53kgǯO-. [oalV2u_igjHIZL ߸}qաY."*P-psԄyZr{PchϏ/(W(Ͽtտ?_YQj ' *شݷ ۫+[2wo<%_~~*%P]@ 'XrAQB*QE/ŗm[\!/: endstream endobj 136 0 obj 605 endobj 8 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)뙛(Y)$r{++r] endstream endobj 9 0 obj <> endobj 10 0 obj <> /Length 43 /Filter/FlateDecode >> stream x3P0 w.C,J*TwuTH/V)PpW endstream endobj 11 0 obj <> endobj 13 0 obj <> /Length 69 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)Y(+$r{)+r< endstream endobj 14 0 obj <> endobj 15 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu64QH/V)24VpW / endstream endobj 16 0 obj <> endobj 20 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)뙛(YZZ*$r{++r endstream endobj 21 0 obj <> endobj 22 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu62TH/V)22PpW{ + endstream endobj 23 0 obj <> endobj 24 0 obj <> /Length 67 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)Yi=3S\.}\C#|@.ȍ 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 31 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)뙛(*$r{++r7 endstream endobj 32 0 obj <> endobj 33 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu66RH/V)26TpW / endstream endobj 34 0 obj <> endobj 35 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)Y(Z($r{)+r endstream endobj 36 0 obj <> endobj 37 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu66SH/V)26UpW 7 endstream endobj 38 0 obj <> endobj 41 0 obj <> /Length 68 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)뙙[*[뙘+$r{++rO endstream endobj 42 0 obj <> endobj 43 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu61RH/V)21TpW 1 endstream endobj 44 0 obj <> endobj 45 0 obj <> /Length 69 /Filter/FlateDecode >> stream x3P0 w.C,J*T0321K)虙+[XY+$r{)+r endstream endobj 46 0 obj <> endobj 47 0 obj <> /Length 45 /Filter/FlateDecode >> stream x3P0 w.C,J*Twu61SH/V)21UpW 9 endstream endobj 48 0 obj <> endobj 139 0 obj <> stream x].ޯ_1 R~ 88@Wd؀%F_- ocΈ19U:mIXo<$̗ ~c~nG(<ѯg??c~?|ί4kkՏo~?c_vS,oy_~[1/|~B;ϲVZ#\+KO^q:n֤z?]￿Zo?<;ogYw6Y[/o>(1/n- WRKVo:@G Qs]Q}af㷏~on~v|}㾰z+㺿e掟U?~ m.\qێa}jչ; u_hG#=§>o'f:~VSxw:}~T-> 1[TGZ.Z> )?s^?_gIa:/Vp86Tur8V]ۏٖ ~^mvC^/kXnw~x/`0܂S)gtsݠ9q?{<䣣OksralU|qٟhi -6u}b?691=~}hռ*wwݴm^գ:l8f>73M>B.}+cϥLگvR]CUpU[sl=[f_EI|Wc}n[a{;2>o5dW!~#^䟏:31G}>9aW~wʜ q-rX8~Iη[Ep>OM&p3]²b=Jyo]x`fl w~̞p-u>ogHW|15#͟9̑__s('ivftsM[󉿉>89g#S1}t?_W[ϟq zG׽V^~F]ׅ{L+"gxYg~F\u~{}y㨑/-lSJ"/ips;Z~_YL~i1s[=qkz7#+[p߹Yn9ʢfz?jz/4OQ˕G92W"׿ʛ<޿oQzׯD)r?&sE5^m{K|v>c;RׯD؎W|?mqνt%+-O\^Y\~iq/N[ܾ8 xmdn߾'⽴ _']k/?Zm9Xc|R}~ΡhzG]qr#>h&yR^?rW&_}>t.^}!wZȇ?'Pm܎(2kտnGą z "`7η$}_708G:#[dbxOop/sxc n ϧjs6~XW0 ??&&bc+s30̆)kuD7 [?xZC, -Z%Y:G|qer9\`eV_kFo')sJuh8-?ZEwߡ-v~B=.gܹQ=2o[@7>U@ݍm\q){_ve{p5- ]vϊCi|T˚?*~?.N Їԫ^>zx?{ RؾXZXWm6{wy!N(r:lG_wBpsqbI5 y~s'h#QUcsU s=g[,vltmݾAO? #> 5*5gc^~.sgٹey*O[飅p&aob/x-9,º*, ^|Mn l$ $дZq6]uA_ { D|F˯^zWn]~{V׫A oUV]_(DMtQ:<&u˄m8x͗[CG[ow= ~)-=ޫUÉ֓ ̝jz[1TGaI;\W k9NL%Œp)3uv"v,Ǟov'e_N2?"~cZ*_ vw=c[ 8Y>oޚ/UщWJ׊j~){Ӎ9,UӁ;aZ,\a|Xto v"k^> 5l`o;\}U:jl{GmlevReoXcvj?z=C¢*>`una;FfL^.:Or-LDKJbw/9y_MA`~*.s:YXnR;X(2UX ݼF+ͮ\+WAKis.m}<*rI 5/`c[Poc׈&M$t"[t !2∪~c.~r)(In=Pp漽CΠUskKr'ֆ#f7tsnh$`ѻs쁗g ]azj*JGV՞(~ [+q l(s(2R3'Q+O4%M5|aX_^"ҀVW`{wu`i>H""5 㙐6czE;c9G^V~zA{u1v.j%qQ;*^ɸ֎*pkz;ft`0X.u2 .ZF? 1heCT<($Pw;bu8._f风Vq-$wRN tQQےir# p\ +H7Y9DTRtaE$@.X? )K\F[5qp5rpՂ6H`Z,^i=|U]ÅKl%p KqE@=uUyϗ\xV[YE(+ޯȗMv@k>cR؁OM_Aqqᔤk4T:gu瀲qnh%p}M A+zǢ]TNtq99{.Td+\{螣jD'Bca7^Vr).!M=!͜Q|SN](}\6 `$Pq.ɾkD#İ6yrHUhday.t'O-GTCԆ>>T48KbݫiRfN!*w5O08KE[ZHbW4 6q>>heqyh,z9D i;8fpH AJW.5_cVͬ!V 2XBCɽ <2chD#3U$BdNbc.l܏mϗ\;)Mi:ojCB^4wE\&йy l[( ݎ/C)Z \4ʥlkшm;w*l]>FCDB,$w|4O v=`a;Tw$%\2Ͳb;1ЭR܆qr u4ׅ~elGq9heq%phð;Ž҅|qI*gF(C0)gŨiE+ |.=Iatgz㤩;z8^ɍV^\tǎU/1EY|D}, ϥx4/&jMrKw4wL:sCd5~ð C4wE#>>vtnj)ljN8?y*FKxkJ,q'uOj2tRX< x.Z%m&ޖsI{A|Â/8qxb\F# ?|.u}^ QP:䳕ť#>LprG,Rhmzp@%# ?|.IuAN '-Q,.\s7ttΨ:[47t3 L8slq`qeM(OFM.6tMN밈BJ` ը;VzsI{5{NO蘾1MTkg˪H;4}>M41531,"F# K7|.uA;Żs ƠG-fORԊه&{;Įn b G\)7. @iې:Nj4Vh%p Ag+Ah !!%֢F+ G|.pDltWFKHӽV\*wƁSr]ᡡIyRg# K_|.eԐrekkAjyԂkl#P%e򜶚?$[w֣iPE+ g|.chP侲7NdAKr~~9c0%VԠV\~&aySQ %֣h#[,}l<3ءȮ:04?>ĺɾiDu\@| eBJKq>)VAR2B+R4ťG>Jy3jD3ĎtD`(˳"/+ |.פ =hCB=]#*Y#}LW7x@u:W엑*tu!9s߼a=LgPH_B@K>V;HS!נPRtƮ<2XwXwؕ3$$Tsu.|H;}ʂ{x\gE^V>\*c<+]caq {GgXH]kKa:HlcBXCCjLsI;xqzbٺe 4[>^< a$70 Wb=,:6b*kT.]2+PJ/KrݻcMژI){r8*ri8E+K|.m8Q6vArΐX [>6 k>}i] 86hdaϥxԭmOLl9kߦj6YX:sI.Q+z;, "[cPU =J5KqyuJQxpnC :,va!G Bݱ29JAQ1cDF |.I=[ò7`O [\Rr h$`VKa+;ubĸ͟h%p%E/OS 1O@,.zm,*ujא8w^'OG:D/KBݭc97;。He(qn $[Y\sIuFTK6Z@UH"(Ĭ蝫ht\83H׬*:th$0%ұolMcC^7'WhD++T;3*8O3'}"HRY(ĺ[ tΛ;/s:'SSa]qjTREO*E7rux`;:I7h$`! g8tRm:T-F;$:k~xPFOe4ՃQNd++MTPRs*Q"eǃl%p)TJrݽc3v:].bREtL*Ew ,Ӏ:+zY¤G;=FR=&"c9Y4y69/ hKke%pKq;KKyP D>1XT)T76M Olԃ ˆ)\/++͓X*lG'_''R؅&P0= sU1>ٝH}WbH4 h# %AKRݵc4چ>G tg+@<ǀwvhʢqZb܎E*ZY\Ɂ\j@cy"N*%R5{Iccy[|QAHaP~YԱ:4-tכu쑈 1xACs&Z3Id$QtG=۸y/oYDHFR"Kx4S[wQЯ BT^Fv FҰّ-oW(gڥv23X.r.++X/fv ם> n˽$ĸ K٣~B*uAJ#VkmR1o5q J?!2Vtrͽ|gbdQ9Y7%IT^kd-ف..Df9\P?+Ƣ~޾1ɬh@ߧIΞ2È !nX1DqO5 O_ϗ;>^L{1>nz1.*hdaϥs<3]|.)K!,+{=Sp\wiDUI!Wb9ͥiD+K|.%dZo8zC'3QF`K2ݩc_85cqy#lj.FPB{tHKa:2ې(mT `/liHE+Ko|.e}yLj 1lEC( T8sI*'"v OZclX&K2ϗťG>VdŰ6t>F9|lX[ UÒ#`$O~Lxs)fC4xgv3P);m6͝heqϥsw8uiIr*zABa-pR\du,U2/Jp}70 GՎldQᝈ1Bt%LmzgDF# o|.u}v +ϝS碨d卽vtpCf;].E=-y!QHl1e V,I=%x}fKS֥S!*/+ o|.m}h C:GFEK ʡ.$. )<ÎأbQ F\?[)8TXSX,O+ |.-̑6;~fQ!ܝQTN6XTsI*t>QHg&qGD@'$Ec>3"S,7)/+ _|.uwSd/՟& ؼi0E+K_|.EEۮ5)>`+'Ӡk# W|.IuT^\؇bX,GG=*Ka;4 AU4, 1VQZ4Mh#P!# "R[nJ#p(o!L@z HRԁq3WvbS'ZY\zs~&]?")^~7l$`%;Rq\M~C'3x"4tRԺ4uFNr(~ESF\{PU`43WZ) `25Ts)*F`wy#4Bz?>XP=SII՜mprL_9*5ůX-t42+ 7|.rSېPbX0tQ4b-b rT?Kd Ʈ@[kQ5w'>NJvuptߖbŔGF~\JH;4*EP ]+7=4ecQ%qjGI#][wETyESpIO+Ɍ_ >~X<4g٣LD)(/#%\;! +ѳXiqi# 7|.EhҸi"]%Bc"Ѩ)/# K7|.IޞƠi Yi LpRT2,QO8{'ҩ}̐gE.h%pϥsx,8WJ<@/3nWKleq%% wrE:=l$`ϥI0?9+殰 G78tIurE:w顝|#*6BtwU*Xbt>NFvԺmOeb1KqE953U9jBU2y.$wRj|L.l;a+&SP,,VA|f))jŢ\>HKR)f|(҅͝bR^6~\:T)(9 XRXBq3sVKxw5bb6&t/>N@Kqkep<+> 24 Q+]ou%'>RvMreFi`Ǝ4E'>NHxrL_i؆>f e/}.<WSP&Oh{k L,($sxr]iЎ.փBƽN8QHWн ^dR4+>N ?L&X{BZGԉF\ K4 n%tlA3z{QHKR'XrL`90D'3zz{?_V\;)N# ^ti*N 'w{̕òb6t ql$PϥI}հ9 ijX{iV,L} i_@/ &Z"δZϔt k|LIm?(wmTNbY=uPq>v9S!=񜑟9YZKXYz,V&2.- <CSEc4:sLϏjrg̟83a#[ P 3Δ];1,i}KeYE[Ҫ[t -V'̔fٙ3pJ]72Ӽq3̼J~2>F̱Ds0#$}فvA8[ρ:Û9 mM1LbsΫ@ o@DGq`yvl]S;3/(J1N.@'Nr˧C˷gѻoieI"=|v.͏G.2_F_?N ,º*, ^|prn w>'AFXٔ+W\W=ه* >_=n)8 >pqX_6 6_)ၲ?%$Lo>']W8̔9E g| d}lsaBGn6mׅIY'E=Tסal;euumsA]e<׬=}p5cj^L*v%ke/[e[8] DqЕ}4:oZN|^ djXEXWPe5|6׫QP>QCV)+?\1H#XPFRPO<Ԇ;{GTE F 2ծzdm S]9=b(r).[VDl%j_M2.BΨi9%ٟlWSF".mREjv* ȸZYY\\mh@aq%Qc\@gEEh].pS)OY$kt! =Aj}SG#غ\;64d ~<35/# غ\ M ( E B1ŘEl].lR{ע_qwl=,,CrIl\אԐMC49D/#\;@SE^jrZ),br)r!a1ywH3ep].Uۚ;<Ƹm|Dh%qUc GR/7z`'?,,"b!fMA?*gcV2[H`".ΆUB@H&\vh"@UKA] JC\Z t*vLlv].+m+ 'ynTHEp].RU q3Kl~G0%Ћ*X*QXd7:Ch}K4 ˥j[O 6 #aT_Vu$w6ԘTA"atz4zy?# \ lK\SS͗঱<_5ЎXMߧ.wsr0fǻy*LH@".a+O;,dnySƢ2.k6TF7 :.M.rIlqtxR!e<,.r).[קS $}RZ捣>:` E+ X /RvI.miGFt Ldݹw<Fm2.ĪmFC(b󯩮.br)n=d䣦sǣQH_~fvhF+(\֝F.$~5y)u.r)nG{*AbkJ*w* v1E]. [ ˹ig܁6Ue].UƕOBIVY,sJl#h\ K.hXȇXf(9ƣqȢb "!u,2)]4s C 1}e%@mK熖u@k w sjD+x\{H"_5,7e!$,,r)79S9iOviD#\!*U!f;3sƂ~@֐DMdHw,b{4xH(ZF|.ɝiF:0"pR\nJlAOL @&sV\ݐbRuy>k# |.EUۊх}T4*S6@W>Φ]SeOy=+*)ZY\zs)nfS qe4 s ,$v6Jf'U)<vҼPSL2RXbōB:KÖu&>6i@E Ph[ҳ1Sl Tԑose%@ϥl9L@k԰5mo3mXPzs)hMY( }-h~p[>B̎i4AL}ISF=j+Kb6iJ;M}@Xp͟xJ1KqNٳrd8z3бԲRLL^Y4"O?oyi`6zsIUw &).΃ȱzFD#tRv̶ag4lCTRO hdaϥcWۮ} ]w&D#Vu+VoιT&dz˱Đ7>DBjJM G<IE# Ko|.E$ڹ iz ȠvJI,PsIlYhZ#cC@3 1)66T@Z,+d.5O%(|$wLZ.6$o*ϳV4x˥j[+I,Ѩ MI/#gi~,g<#'d/Z40~\94 @b[sw h%4\UMWW][+l< KO܎C u)86<́cQO#tRT5k9JoY6H5c}PV>\&*M#Ɔ'S=uO,EU⫌w8) nIDK2g$ArCpKa#"o̟Q!r oNJKrgԣmBN,.]WRC(F S "x3 uaJh0DRP5zj!ʨ) R heqϥsWNMm ťW8^8tv )A-ʸ~޵33v\V\M/!tFy%TC*ZY\zsIl]UeLќ04EBо84=;3 = $4J= Saj# Ӹ'nnKq:[*,A]aHKRcEM qY:`;n5ť=qEC 2nmGW~h%p~%uG ;y耩hrϥ7*UVT`qw) Z heq%u 8ev(*@lԤF~\ [8bk2lJD{WiE+KG|.ɽ:.$ ]eG=3d^0.S$a.^s)n +(GpaўUtHKaNJ9- x"(MjV\[ʊ A7PnnjXE+ |.UL$ę(,J(S1XY\*b!mhLB8jYB|.E+l 3Їr\{ѐVx$-%"b|C}VZn<%5Iz!KQ "v0rTF>\5Nr=6v{WS8Z \xs)Z7$;Z 2.{#3v# K|.'"42fӲT_QD`1K1հ!} k2(4h+Ƣ-K )r`JƔ1j5%RL;b!d]Sd6ġPSTS_+Z P8sIlYJT,a5zZE6!hdaϥj`b&XzύgڬW>BSBRV70ָu;$,.MSS 9NHʖ8i0-+XWDRDxv)&~rI,AD3ȁc) 5M'Krg"r(ʒ#mK_pR\HDZS#|Om`dQϥj*c"b= HE|.&U.DFBKϥԁ)Uꔾ:JC>ζ]YSU7@3=u h%pϥjܩY˔#2+\ozG# Z,l  'Ul{ZH@%KQٮs*2 f(k?!?kyp 6\[*B\ei~Egl{h#,)b{LFj2a| XxsI֧TB`uc\ZXz3aj4E+bASz3}݉YC/=:ϥcEM+}L=Z\5C>]M 6D-a%!,,$-!TڑyXO\ ɔen?^rVBSϥcET!o4BD0qIbK2g˦0EgtABg;\D_C!b]QS$6բ껆WjJKrg/Eg`27S+㮞:ť#>uM⶞JiQj1HKb˶.RҝRЭ&n\ 5ژ/0Ū?$ R.l$`%eBtV]RwL(\QSWu)Wۥ,*$uf VW1] 27fgD_F\ M~ 3r)COheqϥcN;]u!)udeHu9- E9o/VvIRG# {.mӽ/Im3lFTtRPSUlՅK,i| Xs)vIr3KQ% !)BOWLF†ש6&)b{ \ A9[ \ٸJz\[`|%>U2Rزm F aY \xsI 2| \ϳ".<,MLG4_V\f%EX]^S8YT:sI!k;5=X]xH65M`%pϥeS`?,l ww G+K|.ɍ#wxiҶxtQhr A T *xZ.:n>K+ȮpԺ( Kbո{HWRZYcW1Y ?|.+\WO̲)(6F+K?|.ɝS &WOL:^>/+b!(6ֺZr3J7/&/CumU[0KqպW]WKiug7>uuӠ.݋CJphF# Kw|.1;h؞ #ullٸ& F\_Bg/Ң}Y \8s)n9VqurU/+'r*KA`S+9F\<3DiQ°/+ |.U몤;" T%;`\,+ cVOˬK5H8sIlV**xZJ.ӹnl$.$7ؑB />}cJ|.E=WTbU@ڕČpRXh4IVO%Y(~QjO .c &!#SlLN|.m+lԑ" K24l%p%mSJ WU<Műp K2`6tRTh4EJEFņWMh#P% 7 *,9)al(T ;NXU]O\rΤ$,EK>Ζ]Rn;BPipTAT<Y \s)nAS6D0hUvZ>FN\1٠I a jDU˗E߆BL5h  hF@)KR]eAS񊫢Bi܁heqϥh JxVU(\QFSpR> Z|&UU<09,*}$u\+n؂XD^Q_LH'K230?\sɅ[>"dlRuZUaC-HFn\M[ԛU5J+v)f |. U&[׈^UW&j,.qC# {3IpUF͹$v6kDT􊮪xL^VvW/G# |.UۆFԉF)y՟ztM)6^\ WUœ Z.mCAI0'Ui؊>4c"$vu&ק.3 XFWjH`'Kaˊ"23}Weq/:Uś\.m+IzWcuԥ?C)؍.\ )P ۀ%pRܱmcU (b= qkz?>Φ]YҲPOk!D# K|.U˪T)ZWQ4فKO¬W$ 6|KaCl0Ъ0Usi6i0ޙ\wĂ~~y g` lh{X F~\ 5&4*b:Mx < JԦL,&$s6 =OQVdF>\ [W ( UZߴrV>\:w5Y+dWY*J*"iN]Z; /B.\o+ TVw^͆zDK1.4&cdE5*S >Kr2z Gl{Ock}.^`s6\ z)Rk jx@^=c닆Rp\iw{EŀOϚπl%pzϥ=Pu) =ŽDlRUcҸ;ǔ/TC* X8sIlh&ge SbץL˴XfMd.EĆ_OJKqA.gU3Ҹh?4=ց6`Uwz d>\:ƌ"ĭeUgu*"6ԀF\ f &eNF}o O# <8}ftYZ7(aTo=BSb;8r'N5uywi('$O&H~⣭T~3cC \Ru4Y_~ʲԷY. yFlݽp"gfsT֢svz?!Ga$w7Cq~aot Tvq{=rnv;u/̣x^֯K]}Jô[ Bɇ+i7 P(mVy4ݪlr—K=M[mi+Hɬ6W$8fY]đ)co>wX?mߝ1`p|*ooUlGl:w|@q)S: 52輇ÿ]$O< =A[PkMW.k; V{ sħ)@ofu:~*B/QEz6ȒUs0xYFB9 5-OȰcO#JX'FqQ ̴p:GmU(-^4c=jK?ޒ-N5)UcһFm ;WJĴ٘*fgHg0c>{y/YU/vgdc6ISI8]#/*kK'Kx.X4p?#xWƀx} C.ٌ&w\C56OԜE%뿳;Rg;WX fIu8Cs0yn Ǽ㿻A?UY6gq *ѼɝUe26o "|isۗ9UY-l l+mG/!Pol>}t+pҝs$9 D|jG!џ|k!0@~~=~#Wo>I,QUc+r H/oOӅ H¥\T|RX:aXݢ0jhV,cfyY!M  v{39\([f}!HhIr6PXa\cbENփ2$:"V'QE+Z=)褴J'%ɐ4Z‚.SšČԺ?q+ԜqGJhr鍺~r"TDZizr̕T&N&&3j*dJUmJ Ie+J + SHa+FBK6iBruCd8ja{ ==Ă2"+1Btҍnmi`L.rI/\,JkҶDPV]Jn/9662>F6E#M %k6zŸ'BlD_^EmVBt xHˠOmHNQA [ P}\_0Zq ],d#=_naF{^aj҄jQZĠ\E\`&D4 \f+\k"7n~_V o\f# ˠ\KscnR;3 mjm0E}˕VЎ')EӴg;-|+ոKr'-hN›Jg9q#DFv&]=;)yCdҩ}euZt]]=m|arQVVK6W FrbN47?%,_7t侩'>p.EX?,+yq̴Hb6 Ce]٥N1.3Lkl%B_jKW#buo)Ҥd?i\f+Q%Mx_,%!QFE+\;)@⼦]\>VZ6Ď-yq6b]Ӥ=9륔\ëH1Kfp_Cm̜1lVV?򶅂 ꌱn4*^S.ou4&$ԗ @ar_)-*τoRBr6mX7ٮ %iL ߌ;'ʼ} k®FpI ,$MT|}BʶlcAKB'I6$+G.'V"9Pf+}caC]Յ̰%5tk6E+Q%!TA/_i{We $c<FB Ǘ F Xo=S"|.½)ZoX)E{GR\ 7Ǧ-ӔFq8l/LBj ~LQ&,ldUe$` Kb}MbIdk_NUե,T%W*Jpa65Ue$4_ef̉]C 7æV,lVn-u՟7,U*҂$bR`P "zv$"qϗŅ3 I,Rfcwh/L v^VxPUV6]$z o.&_V*sV=W/QAq76Z WWJQpf[i.hm<Ԧ`d5d|-b8ih9J9r2Jb7Z)%:U]{bԦKr 8⎕#wI͸ytp !v\0I$qצXquF<l7&662SΝbpҔ HlRԎMm(3ՔD35U-F۴tU avBډnԐ_FCyem wmQ|`2Z=\EPxG0`}USlC}Mr/# -\&9/dIkV.!h%p} AV# g(>wɯUMm`%?_s0 DޗhE+EX咍F/LE/ OWϗp.m]ZҬ=rg`w,5}i$PKKR˱"޴F1GJA0ڮH0A]kIS\LoSv}X-o."_01`1*Hػi3bIc>TlRԱяJ!¸i7je^Jb6j  ZI^̄ ;]/bihwNM1i3lšmq7lcӬ_kK0%2E2Pux}%(b~0Rh\d㧮UDhd$帙+(+H4<ۈZjHb᭡7\U)yM{b +,|Y P\_ 9=]Nq,j}xjjͥ@)wz0!M;b*S|WL˾UҦXݦM/UK+0`}udUKj4[W@Ŷo.IӁ,Vpsm]0I3 ͥ̽46@mH#D bp H}`/U-0O lt6a7l/=\4 ɺnتG4Ůo.k'Ā6(ϧl. fTJW|.)Ͱu /+:Ihf U)\IIyh`e%4 FA֘iՉeqAv mQwijbr7b P: dWvd6^V-rX.2':xxn42o ;3-wᾳ.v P:H0ڂm\9`&0@}iJ2+B-/o.ɝ)VJ`eW2ƛcvaJbw62Ҙj3M1ݺ:Tnj{J2Z إɔK}vk?C}`% άaj7s6˶M.?vumuh YE.s)n]l/2u Ӄ@_rOr/˔tV$#FQYI:DZ;p!h$J:%}b4 {bݏP8T&mjL!Ut ukS,ԣMHb8NHl̿4[bwt*HɎ)r6MptUm[̹5 rDjsʇ KVf2C-F.\ ;VJ0b:rHAz XET Vt+%^DV'k-1Q.U`d? 2m"M:;[Mf۵v^VV K6W#L 9ObOyEK`%p Kr6nj4w\9@XG0f0psƂIX=GeȎ1#YZwR5e k si)>ecl-O$g#RW9@/rG/m%ⶕ\"t$,:$mLm\ZLO_(aL07?Qh%A_u07t'Hw ަ0{- *j6s6k14c7]MF$HFlGWBeߨwU4z͎V;cqC\s\UbI"M3% З?خJ.7^+0D6ϧ&m~/-`@ϗE>p.Ef%%Um sLlyU.&umuwu,ڰ"a0R=J :}1}ee% ӀNuvI煾ΘB?dڄ\Yr|1{q TE;\Tql[S䎛TK`&kKK☺75\s!s0Z|5̈́[+!&kM~٪#nofhe9/`g^ʿv~+bT۪r6,7N­=L__K,`q1٥+lQG=/Xs;Fmgis1NK{>ڡ_rB+w3~൏__e]9<\]aag| N-.SGђajJ92jΔ`38YJ2)F lMyɵ ǫ^0#B^R6j|QV0Seã6Jȧ^|QIVo&Tw3c@H6E}'[I!TST`&E}E^8o%K[ځB,YuG,װz|QIV<0aesJrˊ*~aV/S-L˅k){u{}L!p7멽jEm'[!y-YW9wR&wU% /.%vɻd^[2yLlK/=냋؝Wy C?󫊼: e)ZP'6UU7jyrFց{kE/][)%wE~BH. @H`.pD% H.kj"Uwe'[DIXvG㋚ڗܭQUwUN$⏰f7: ;[:J*~'0G1Ȼ~'zo"r8`ҿȻ~@Y'sTN7b J– 5UuRZ@O|tFB'TF ֞T>~#8 RYfc*򮫰 ^={{bcEVX:uς!;慠ZAyej=U':ƃz$_ vx!}mΙoP+ shVWxWUƞmOlRmGe=HR?(2U8|}/WEuد2ǿڟ2DN&'X6kMPEw̔~?C:ZH_1ѡu@Sۿ~4d%J>קgk?1KUwU'ʟaUE__bȣOھ]o?(2a" eXLt ̫=O+MG2v:EV?ĦPcfVg)z*wIdBˑ'~Pc=Fezx?A](vR8~WoG,=c뉍yZ o?tf-u\=cҸ?(V 3kw5եbȻMHs}.\ >_)N7DPdN e5t]2#C27MŻU&r=mPuxr"IXz`M׃:1~Aq,2l+ӺCNf>*~<~"0[Y2?(R(;mkOllMBXܥFֆiRU=Uo҉/gW8]`GD-D~p&KIj ]>M:B1qS&I;WxWub{PZbh*򮫰e!c! 'm_U]Wa̘@o_EwlWy_U]ω&uk+73L*]\]:WxUoY?`QƙsŻMPi!TWD Ftӏe;x c_?~mA)B8WyubIKŚR8|"*w٠x`GbUVdO"ؿûMpDꡑC'w`>WrEb9= &5$𥼥Jk)(}$40T."tVCTI5C,~fd'կZ9%a(U">acE#,]6RVX;`}ߠȻ z. ݉=ϯ*򮫰t;2Ky!\ RM֎۸j*:put|Qw57r~| Ȅ[=0)קjE|޳zY,  קj+ UĻ z.+`U%XWMtȁrUEun\)Dv~UwU'~\ +CHZ:)Y 95HU9rvzsIf`ʧJ^WxsBSA!\.hcfS[&V]IC=FW}P{ĸU=UX8sIldlٿ¦ Kz.CWxWuRP%4 z'4VicAQ%d>j<9P$e;DK"C<U2u}~tt߫nN*<|PkyPͤĞjeH%iN(vIxw‘K`#XJ\=`޾Ȼ Oz.3[Ժ'L=bn䝮\ƿgBL%H SjHOz.3<@㉼Ό)w ,@)MfRF%*%ϩ7}UwE=ƟArL(\aUƥ 4{(\ 1x6sfdƒK`#ϰYKyib%!t=NuMꄾ_YI=$ A1'. xLxs`^m Mm_Bc\!VtU:.b`U55TsI*!zե5TicA=e<'3-opĂ@rؗ  nzN&$VauOjȢ҅:RB7s bY0%B#Z<)"}$yOdLUb"B, Lҧ T~r"sƚKJy.AII{F# y.I DX.ePwME<6M"z:p@vg(HYMuXxsIlrḾn寪񮩠tœrbGy0X=L @2'#2X }z\S7]Ʉ<GVu ǿֿvUMh"n}zߩ;id T%jKןoݭԸ*ɟ/{ Bǹ1|~+PXlϽXW~+[ï=QA:BNz;oCE웿hZ]~Aߞ}]Wi_]uk^s 5;n0>v7WYsߒ~_7_\ϾySayU6%*pсa;X9tnGzxHۂ [s#~# wg>ڻ}}|3y / ^1.?:nۅ;CVj{m67{Yi۹S.>ݫ_)ا_u&oˤ֊?Y~VL} eѴʆ>ٗ-ے$`T1]hޫ_5GDL1/ƶ.'%e.TKgu~9bjolOŮ] Wm>{Ғ(޷;.yi"KHyo=n%wf|hU|zqׇٟMs ]vmӲ:縯PҼPy:Uoej=O n_Z;w?^} ~hNk@W xʜ <=.h|wׄݯi ;?sF650m1|z3koi|n͖6Ͻ{|.udwٞ?{lg"|ZÈ? &X}Js gE#?;>PǜeӅ?|Oa99aXXeNy~?g/B{__|^?[JIm~T#Oo6y?+2y!2+6P;q~!B+m|{j}P^XP~eA/"$;!qe_HJDF#w/53L~e1WUT5nETʢIDgFR2/,m9KEe%#"ԿPIۉx~~-ۉ%{I _Y6^l:12"moYLbffMZF(/D%B/L570}~!B+mtJ  P?k=abx'_ jgnrOsGG/jI/,(@ױ#;462UPǑ2/,(+sB/eS 6P Zզ%OLbf_0a+@MMqAL+_h{,7j[O~eb&iz^ܫeXVJ_Ofedn-<vde[dEdd^ d~+/J-ƭb_I~XyόfJN8j[Lmj ʗLJIiW l̨&Hȼ5<\T9"]\~'pw̸}\y$2WٿΛ<}NedDv#`fF"WD22d%  g_Iؾm独gf,N+ortsxݹpGrƃܷzIA4zAvgb"V g;oEr%s?LmormH'"Jo{5xpJKuk]zߥ{ $n=~N$PYZ{1dV g;@8FIFrѼOplE׃[o%nWGu_ݔUYԇR%1iQj"58}j%ńݲ :>Ǧl;J8L\L2_NU}|;kzۊ0O}w+:܏ypJ^ {41@^FQ~VLF] ˫d}6&l?ynȕ.|^ڈU}6/kuy䇋og+BiPP ;Vsln;gkm`ٻe{Ϻ2;ӅۇN;ͨ7˒ʜr`Z6o5?Caw Gf Z|~΁h;2ajwgh[ztɍ&ʇ?r+k2uq6$ dQBr_WVЇ?'PmNhǵ_8ȵTA&;1бcZPn;+jC5C>cc }t>? ]%ޱ _Hmk)dۜ>3ׯp堰9:mr )kՋOt{P C>Bo9>169t!>?-r-c@svY8=nPēsȖ߉9C5kh(V=~~>_c<ኝFve=Q'&V=Uʇ%\O* sV oCLEٕ55m6'# AZ[bfZҴ4=\鬗_%XPمmqa+ O}ξ_bCTOʺYg( [罩Zya~s+ը#Sc$sW- sߐ]g[vi[ۺ?| S8TE_szvs~CG#=GjӦ LEgYw? k]?>+i-m~|AX[i gC7O$nO[P"~l2?ZO;GڴAh붵9}USsՙSw3{S_2X?y1;ϗV4oOb<0| k$:Gs(ÕOin2Ԗd|&hG׏hƉlT<}kkt/,N; "]x**__e>6ˡǍ[ڇ誫~~{$/eL_.I^- !ܐ> [~6[U ׯv-xa+.@ idaKm r)l)zItC!˥t[KToWwsn:߂VP$W庤@ܝcVٷ=B_C*YXnA 4Q]X\ދ"3R!Z \lR\Q*@շA[8WWר F$U}Ӡ2;88omyC_fPP5ۮ7ɍ<9ӎG5K)Z sO2y=_Pۺ;؆ Qҁe\+Jӝ3˸ S4qϥ"n=nu=VƂ2 ;NƩK "dhǞ|mNF"V8z k*>sj\]5Mh$`ӚKLȘT U/Ǿ7KvD22rVruh mFa܂]~6qE^.ɝQrH]m.h4 ˥BBqG ,l\O#\*psuKٱcׁ>PXx%R4LOkBlUR.beE.j}eR.xUdhHE+\+ʾkH!.|$ypPnvMheq3 Ag;4{/`4 }| h$02NHՐ׮ v!xPG#\ + ٕX;4Wx8y1X3;>_V)sς]C_c\nS;躹2=e.;zn?Ca\DzSɰfoiFʥ!5 zrun"ZE|K/# $7 n;:D(ECeۙm.ldO~!vŷڻŵ0t(r'{ L%kb-.>NsC#@V,wasp^15r+ҽ=u7X \̥B zh"hкS9G_F"sI챡]Cmc뮆nFcTdnF#닊XY9y)BM-(' ⾊A~ LӏyE#}!^9{?w&b [.ಕ\Kq_]8F:^q8TKB : ([ :CZ *q;F[.oꦩ^OݗQ vQy\[;h@bƉ.U]e%pq+zF;BMѵQV,*ms.= !S\aH]+i$ q +AYS=ֿmTjjp$ XʥNnOBlABӰ ҍO#$T.IuOAk[J1dMJ@R.u|eCG7On܆^Ǝq;z9[Y ۮ(w~tqبim UN擑IjԝA nlb;zrYל~Y \xs)nCP at]Wvİhc1%U+]Th̸g̥Psd+ |.=mOOSwXm;ȍV\k\<\NZ % |L8s)&Jm]OSAD V>,*3켚Nç}9u,xF 1Qk`L-qn7;`jv͛`$ 729O. ;b7<;Kqyh-7„ebi;JKruFqĺîl ǙagY\`cAϥGuN ΃ x[E{=BDFKR;mx .Zi@# _|.uH;ch<дKaN C3'XP:s)hey23':x?x胧2S) XsÑQ2ގnTl1<򃱴?x42ZY\s)nVa+v'Hatp2pTw)눱;;y]8 #z]#*ZY\$b!hE\ ) 6hZ\FxRٲKGq>Gx )QQś\.k8Â'OжDԉ6& KRݟds8 an a FpR\>JkYo 6Q:ķ7NrapR5ĸGEΙO#XY\s).ӠE؊nNNZ:z]e$P%ebyi<Ɔ8XA,3Mʝ vjp !yvc KG,.$=MָCShS<9G1%VhPE+ o|.uOQU婘9,a+R5->6ԩC [CB-]C*Z PxsITg=0g dye$`ϥ}Ԋ..JUƇzT `dQ7xs48<\R' me2YG>kRȅF [8zC*Y#]LW7x@qܦ-B2Y.\2ێH!w/$ĊtډV.\[qCمx92vYG>D @qtǕ tg# |.m蛝/ ̉dׅ!vYO>t{M#9(!!?8tжk@T.'TĊQJ-Kr TeșYhBBb=T0tTiL]8s8jCjqlRFkC!O ɃM!($ם;F95g\1Pg#+R5ť_>6tOm-) CBb=Fn\?<xxl?}!WBEZ,,ʩx:8FAZyT/ H3K%]?ooE{:ZhRF1KBݽcLSCC'YXs)Ryl@Bkk.gC.>\չFT\${2(|?c_X%(/K1zg2P 7b܎>SJ|.mB+yccBEx ?>_F\ y씯Hgԓ<_vq& 6\K:i >QA2¨GA'\g+ |.8#ۻ2N6tJ,. ;L(M+]e 4e$0%i8M,eCY""l4x˥'k׀ F43zthdaϥtmQ?}Plj&O4XXvhZ# $YuҠV~\ 6˻mza"Vh+J1m*B!dEM֙Ciz:#ЅL\/ |.Iu}/ =?M'Smq>J')6tF]EXYTv[f <ٞ>_FE$ֽ:~g:BoqI r j4hda!Ja)\+\InG/T=HB'p؟7DxxOԀ+l")JBݡc] >'Y̊5,vR)nET4Пd~Dqr 法M*u}f/f_ADUSqM*mRD)Ll0v'#J T4!)cij̤H2RsmSWCCPOP6U,$ս;ִC'䈂Pxt/++X[@:FY2D®IAR.%t5}.ߝg1(Gwh$0[Kbݻc84چ>v3ՙw:4}!IccZql!5 dDa;RȢKRݽcmS +A!DR=65 x$!1W bcvC)ZY#=:WgX3u$BC ^ҜV&L"ILcc9)M.usn]{0Eg~,,RI;uR:~/y0.d`>򰱘SI"4ƎΩpjM%vfە^ FV2s :,|A_2nE#2ĸr X)Xw)Aسsըlj<}SrheqJq;S1n!fPyY \\wbKbvwrA`^wb6}c(;~Z4t3CtM f*EF $ӽ>va㈪+ <ry,c*$:(vǏ%=9ƉNFXUB' w|.V'=<|{rg5 hcQ%L6'4t *b؊6M`$P%k&;} 7RhcGQ4ť?>VOO<#"sc^HVoι$w ٣v2onyI _gRv=7>6tυ#6t21z hdaϥcw8u rbxh^%qŢa%pϥHxti(^9CvW=4idQឈ1wؕ]+c5 JKrݣc߸4&6b]|]RPV/upD.dIt1X$\CidRsIЀrLdi";zq,CKhpRԆDtԂQHFir@qkH&ҽ?gJ`jL}xCxH`Kbݝ2E|qn9SyhV\^FSg6V Xd 1,懠ϩ*\$:P |;2ji^oTM5ZY\s)nGCiPI, CX7Fj s0;3?#qʩ1|28U6rtkv_i؁f[פ# KW|.{=*L=T8sIDva 9XZy3||ydE>֥s~6r M,K3)O+ O|.u׎Qq3WZ) `*ʆ蔗'>" z6up&}A;_>#8d '({娐0U.Ǧ,$vBNMw(kscl/ V,,VjSNrT?%f Twx-NpI3cAbasפ6\* E:bQ!G8 F\:5@QJ<@3j&Wad# K?|.ޅ-LOqHh,V,. }}# Xs) \̔,]Q+Nť>NUm{Bk\ƭ4ߗpI.z7 1twLWir\?_z`N6n\*FAQ*'ENƢ KQŸ43sU ðjY=!npI=QH۝¨ hdaϥ{fJ)`7׎nO\Q,%QHh:͌[sf~ XxsITJa9$4,ʩNdIyXTzs)R'Ѕ^צ!*<$ Ұ]̰JZ͠heqϥjnS/ЧZiQH9NH׈rX9,LG/]3(Z \s)(C3>J܊nfm@7UtI[iBֺȕ{^h#P7JFDy՝K)i}|FS/8}fJ HssD0JKrE)\#_QHګMi- K|6x˥%3sV*rFaEƣ=>idR7sIꄴ]؁5VoJѝvtFKQ8w 'CTJCq5plT1͜jrTw0#XG{5S0 ;L`i؆f ЭMs'Z \xs)(dx6v}Y]6YX:sI S-W4 F=@RKS:zxׅVGxV\;)]""W^f j 5XTs)*Sbn:"mpw?5'>NƥnrIc5[5.͝heq%R5yzHX_WEz$ X_KBL4(K&RU+"ƄT6%5}>SIW7+pƂKAŠCdWy\*9Ԃmu2>]618epOcOF~\JI|cfÏ0:dkX \sI\~(ma0\1B|p\ GcGL$4hE3neׂq*" K f^`H0DP LH@ KRݳd䮏Ұ]̰'ԉV^\HKI.O a+ESt\t;+Y/X4fbЦdE ݷYOclK?(<ۨ<4 &<ͅ$t Ҭ\펧/panΣQ,U@G$&PK\7UW\uyNdϞ:T:>U{V ZЕG*8],Mf_W~|7NVe-|y+ҞHR2S`,CA+Qد+ =0rʪG̰0;I7i*η_9 ?ǗYz4V) 8SUM~LKY9t\~'"+´>ը72뼀h@yM_Szui`}fS~<|&^rR]j}dxEya64³gB1EG U>4JZ?az^(-I7$dNzaGcgϕq6-\)\C  !c̟ Bz8MUNx{Wl5~r.&C2~圹fo7}P;kbPitv2`fpjcx.l6<?5?WѬ[xΌ\ۃ]>yye,lj>L9w;#rnҗA:?c8n yXg~d|<䃪w?9i\S)ab:4rI(%&ןẼ4%j5T0ֺ2N`a& ˥T\1T~ [L!4j*r)ZvI"A氢xa8Oyh%prKJn %',Oy娊вh,.cr)nG&u'[_:dTf*Y&v$r6* 2Oy),,r)l=@,3"Oňh%pѱ t̂Eiק;6Mm{fz LRXLݫkWheqrKr!qT RWK)TRԊ1-$(!ȸZYY\F\mPPJPWYL&r)k@]۝ Qo&h9噂E].UڮWKR^9;pkϩ,.r).Wrԇ}YT˥cCnZ+iqLT2 %j<v':uADE/\:5 t!WoHr6vM96 N){ܱƻߔɍ^VvWmRg WJҕҦW%uMCjPRIT3PacQ !]iKDfg6CǠ݊Vv$w6ImG7-]ӉgHb7º4剕$I`IV4sj`E+۹KJe偅$TM~+ jrx\ ^Ԓ4f2xaz XXHH`,$mj !heqrKqո:Uwic"Z8IxY \ٺ15 @K*XY\R\WZRm#$v F=b!ZV3!;nmLH`".Ά]R[O2O%`equKqK5iϸXz#vq0%m/{r 1,0aeqvKqո)W(<}VZb)bAk{QPxNfO#~H^VwWM;uo]j Jw`*?q\c4 heq|Krպc `QEɽI0sT*r)jM5UsdzҲTHx~NR,,rI,l`]UdGye `+\[Ζ4rfb\S+X \ܾp]yk* ܱ3ݽNi0F+ \I[SHذJmq)4.r)"cHMi]r׸jF㐮N4br)Gr pZ 3cD+(\u(ʘS/PB1EǖE?,!jPa8ǩS+F|.S낍Z9 4V (Q4pRXi5iB}ʛ+K|.ɥvtF.36^{4s3" Txs)65ܛ%WbyhAI^6~\:V5\oHii)z hcQϥ>wMmX' Z6&j4ٴU) m>g1Ej^zy5Kq8)oQPY.|l|p &= =P,J،a}0`Q 9-Ka٬]3c3mXLs)fǞ}?5[f9 4h7IF# |.q@A7YV_V>\;771 }PjPcS0RTFK# *Ԡi3mMD`%K10z лHhH%??f$q6HDeu,9j,E+tRv̶K}2?4nC'P hdaϥcC$u2; iCjn Fo̹cK;m3hGcmFg|.I2IA|"RucX]tR\@)6EŘ^b]S)PxsI6'Y(9 pp!6~j|E# D,,U I4KHCxH@KRծIh hTa:kՈ!/#\ M(I=Ѹ 9BvlLRhe->1${<` gb>DΆ % AТTvDTsI%&6&XG^RDˍ$&uqslj)=W `c j{yj%J|.YVV#ƆGW_Sl1 XBL-E!ʐgqtìO{. jJ}C\~lz2E# K{.+tX1چ:Z?.$w6M:cF y*C/# K{.U `56FalpF Sx ,=Z3m$~r)U_x'Ǔ?"ԅfuh,.}tj%7SK/8Tzs) Vr|LAYa g&^\9[vN @|%-ld^tR̶HAi;}e$`%j{.9l<*[Ak~?>Ž/Fl!U x4`da%I$Q5<(书lF.\fBlA@1+nqi4I|.(-r`:,1Sm+ĺ(b4Efˁ' m\Of0ٰfV I ) heqϥlf(*â 㢍@C>JªƁGd=jԁJ:޲RLk,A#R'eo9r+]&kXWKaȁ[nk}Y P\h. hNz2ո'zJKrgA.]JVY> Dv@C>6I-r Py.Ig|.TaUND|Lx=ian^ٮ )qBnKq) s4'vJmbv/# Kg|.NTd8񈔂ópR\5*vP5*-dBS`B SU#rگx[%;_./8hBV).ZbjJP,bε.dY7>mMh%@ϭhFu&TU?hO`#@-5P!*+^n7M<<2[Qʜ"妨`{C)Z \sKR Ur84,Y%oO~?Q5N⮂`ZՉ?'d>d3Pjt%Vl%eS1 XlhĬ3cȆz*Lt{;m"b%Tn]SeFgJ7S{nR4 VX6ʴ ZK;xj.E+ |n-J"7Uw#5M`cQϭmHȲ6VWOK.IlZ]J"[romUvtAus$x.8 d"[12EhIUߒROƢ2[Rc=)*՝ݘi܁;7+{nŕoSu_)#9K;ZY\Fs+XS-V]xKJ-Y5h%0ɜ[bsK ơJԹEu]H"[bo]sU-c.5S 6XY\Fs+J˶r.-wqwͪh%p}ϭNx;A[uAyI(&U0KƑ)s5,bN)?l$)R{J\^A9[ \-ӷSz\*koK6؃ [VUGk%Vܒ낵H%6grՅVZ|t Ts+|;5ϒҫ.hB/4Vܒ{n/WѤ^uU "J"[qݔl0RZu1(.,.%7zGHVO꩚PmPlmȤdWUrI۔ V܊;V&( ^K›P+@|nɝ]SrJVϥ_$]c-,"L*bL*xc~sjF# `|no9h6mU” sO]Y \_VFPyvhJe4?K 68N`%@[r]yTຎJ*x_Jս}XY\s+.cAخl%Z6"H"[bg=rT]i=Kl,*#ⶰQ{J*x[JԹT`lېv"]V~P'#}f%pϭe.kV_KmZRTJV˥WZ2HH"([a[^RU75;K%5YXb#X9T`[J*xvHVAܒ;=Q,w3{4<@ET>F߈1˪v\޳ceX>ž+ XJw1˪U -=tS6A܊*j^IV)YLڡ~?NJ5fZUC(LΈ|nEm3eԑ ގKr9,d$P-ӵ2/d`hAIYXs+| Xdи[<MgE\>R*3;K]2?4@ET>7LL..mERQƢ2&[Rki;S6*9Sh@ED>֕6El쐞!"pɨA6 ۩*;v;֑(q*.M=*`o?l$%˗ NuZE]Ri\{Moheqϭ/8grUK)L M`#@ϭ}%Naȭx ,}|Vaܒ;:En fWU(_yJܯOJ",[f̯_y| "2[aq'!]" A)ʄ 3\,*# g–>ElE3(g\R/l6rKt鑅\LpaN&|Z7 FlV܊\wxPe&[55 2>z7XĆ~ #Ou*Ӫ".m$F,2hP&0Ѫ Ӱ9 (|n 1@=qL/2=(1x3VغmLe9 M2 [Pgue$|OȎ{pA6Jƴ r(68J7+ܒo+ \V_/r=d|nEoڐT+jҗv`6Tyvi:(8Cd>b^+К^@g򝡂l%p-ruwS Z5"OYY \s+;uk+Z5m_QyxDJ-6DʭnHV/i(\YTB|&Zu$δO漼4E>m3~*x 3c$.#%GEV;cZll$`ϭmQۑLWq-xTB @,נ]jӾ^qCãkD)L(v; 吺(߽^:)ƱR^ol(L`o ;AĒv<Φu(D-;~o?+(zO5S׉خ2 ڟ7QJ;\zI;ڱ]Fk[s@gaO.mo|s̛6o^K_^qԗ<:3c6Q'Ϧ.Z3ϧ[MP ]Ͽ9c߼u:1v>n܏/]wΎ3>ӪϯA.':|'5>|H!|T=Eh1=*|JuX |fyUK>E Ěڕ1zUV&ߝu-sx@ ڜ;NP7g /\M6(6#O۽ 1ܦNyRK8oOpJeZ-O(tt=_ `^G Lp Yot{ dn.[5K?6S'dg3,j,OUזxTcX} 9v~^kt+tsu,z/`Ńcbk ئibxN,GL48ٮœuTWC&sBW,8+N#WƀsQ+u0H sH]]Wcv@ -.۲9s1 委s/p[5ʼg/Vϛyw̶lަ}XckV#Q͙U39s--^?<<$i˾O̟|r?e'e/#|`lt+zҭNx}!yWf߰e|iȗ/R5mr^A{}+}K}^b/4˯ qρ@zX܊Z8U81g#Lx%|(kf[ptCl\7>4}ػW0uم:B-KrK mGlLV1ڠkIARo6y%%2 bq(Ť<| k/h%pW[r !Z#/J)z 7oZjơ5Ȃ*#'VOZ-}.ܯԓP܏ &ČXᴩ*`2m%Ė 7lXo^xŰRSn %Fy+_,EO6;yvej*+=; Y.Zlc)UҾa$;y3\bNLnRui^ 2. 9Y=F⮅D˒u)GAY# CWX4Z PV܎[1rc~Hy- nZzzaibm3Ar6C*ΰUGdžo?ԏˌGJ"&vܮv$,CU~heqn[X56&(zR{ ;֑Y\ab?{c Jsر2^'c;Fr{oi1ҥV-ň*r+R'n8un[Ħ'ߗM-uˌqơ~`$S}LAʭcDFmKQ1TګSi00K<%yQ~+0v4\BvSn҄4=  oƘmVt؏[QƬ(3l 1_F ")z>I9q'pڧ[F`sݺq8i2ޅ9@I 3֗al@g߬[wy(ʅK~rΓ%:}blcB;SrK/F䬯WɳVFIZ4v9.r+-F2䭯W W&V p^šۋ)GLm2\BnVn҄z?e 8u6Sg &yYf:pf֋1T΋EjVn}+^,m#;V%ypKƲOA-gm,[krɗ+<>uvb(wje+ :0E+'>= um܋r {S.rK/inǭc/67=Ȣ2,~YF+]{ Wr6 7З"v-,U24rhy*)jz/gcA Em2% ~ U˱c cH`b[a;\,T#\s#^ú6YndQ[R}b&g}-|&yVvq[W Թ)XCyIl7ڴ [4!@|UzHW(+骡P2.z( AZ$/OZqPqTF".B\ 7㐨|㍽(`qt"!vGٕ]F5qСzb7 rK7cI|̀y(g(4\ FYvb '*-@ 9:nvFHb,5=ܾ'HV}+u]w|B_n铯D2/Ve$ur)XT` MW!ko'nV7Ҡc3 LX_ {a9Ҥ־ -n.lp^ґJ}1SUוZ}N r0q8!iz}7MbeOJb8NJ%nW}l։^w (^.mn[]Cý(҇XЗ`AVb챾zT*^߰-43OOoR.}ēP|~F@n[R} ba7Ԉ_*6hܪͭs!!Ҟ>X bፋdd޽5HjV.yUuC1m[:$HO>NyYmobm2-:Nve WV PeW9czF b.3hG.,e=)^|pnWԎS : m(s+hCz-+'%tV|XY\\_)Jw{׬\K 0 66?۾?lrdwuУ:O4-9D5eUjS6 TlVT* 8l'3'b{\# ,5䋔 ?`~)bvO:䅓va`$q:6F cG*}s+ ⫔֡TdUs0C#,,fsKyxm9d5&ovm3TQ< W4Yva%_?ǐB$UQȬ9-h8/Q K .JG_eS.B* 3J ]Sc?VS-UQPtN-<]3 ~Hb763'^u䔻r7]]_W$>T9;c2a0ʔp?] ܪ"JSRFO 5x,ti? %Tb/,( =f+EKnձЫ8%qtp0ld# SjŰ;GT"R76;y넮6$y]9$>~+O]6sKpN.V)N);Tͭ ð7K 09(D+ܒ+uŸ,vĖ v={8-qq;lb1$WlVS|pn铯rɧ? *D'1or*ZY\n\_eq~Bw"}G ZHb6aCGl0Wm#%. IC12;R TeчpnIE9 IW-Bb*>eoF۴*'ZЛmr.6mݻ}.O9FR=Y\;cSʖUJVO-}QX1EFQA%"#-+ 1{2V]r~?*er甫EaGJo Gq_]væ`,>lL7 sK|b MD_%D˲w# ܒ f4V6r6YX zކ/f% :pvBMχp ,ut<%mPgiRnQ5T5Uofp7BF8O;XlEI,ʚ+a[qF6=Ji!N&=fͮ0 Vg_X* 2bMy7sK|a/QM,i@΁eԃeonkB1tT tt.Qleq[rkHe'VA"pr~#L[4ixSrn41lu=lopBXA"oD,ɭ0aH@b7>pJ1p6޷UI&9Х:,,}s+,'FM'?9KN1\,Uy++$* ]r)Z .a7tWM'`\^=2# +sUw_Uˆ5V/dP6۳%b6<_X #69{GMC-.P,.E/ְN&;-)2x 2uWX\r7bΗM **S J;ʳK+;LlV̂bcbTWk/bee~>k 35/Cʚ^.+)N5z}. PRpލ*d%W )vEs(i?֏Jj4؟ͭó_z}.9johz裕p"vJRX-17{u;]e_D"QW%]%$܊ʢcKjV"Pݴ'F!A%heq 1!%%N_!)qG:։*hd޽tɡeCULJj' `7t"F2ӾVr,XiVܒ{Tݤ}%JHxnhu䔼udť˩ >2لL.n> r%U 9R%O5qF{%՗Diz](ۊZ遃PJJ&/ G+]܊[Wu0p]^jоujd+Vz'_pה{G1ƥǻƦWf!uN$~X \\_@dV6quJ/(},,ws+XˆmvהiFJ`a.dц6VS =S2k#iMIwIQUa%@[qYժںQ^ c{6K-]*s+J*[N %4l(vs+XHeũ&EȋuI^ca%pK[r1VSbsj}ulwmq,Iϫk?lΩ7l,[#F׵Q%sSK|F1`.sK/X̸gU%/յ&m9f0,5e%r6oظ7f/}bei!յ)&=onK{.C2S5`h4ͭ`SW*j9Y@$mDDs`E.Xň>v$Xհon鐯BPXڠJ˽軴onɜ!_ZtRj?pTÖ~?.:\`Vҫ$հn KVYh]Ai#LX ]+ӍK`90p}yRUKq:rb\V[%F.X ]ǭ03Y+MhcQ[QY~SAC_DPgjOitG#5`W *W$Aհ|on/=X\b]SiOlؓT,*6-P^2DjT~br6d}3( IŐ:٬|Vu~x@.(8$=Ton)H>rUGBVĨTuͭ}#FAfԍBxba%pqBCX vf"FPv,4:=MݯczsKP뵿* W֬2ȱc+ FA܊:VY0bY]V #^]JHb8aU0Pwj sWJ`&]`d=m &1j2Xvi'F##AU=(W ~0wN1`%p[r9IT >Yj2Q+Ѥ,*✱!rZ9B9+gv,Y%!ch%ܾ `WCP%TŮa_0];)ئrl06pnilJiw`Ƒ{bz?.)F+XKnm09un-1[e`$:E\ =O[B sSZ,leEvĉn).5 ZF ]}dԞl>Aum85[b89%S&pn6}ŢV_FYrq)hfW[3Vl\qϊ673&`}I=-u͢vsKƶK0sxCnE;܊KQF Fe'cޗ zMh'=h6IP'ԁq.gu80 8M2mԇ<:/%zXDf;#lNǬ^6 %bW]n3܊11phmyJi;mܒ<9\v+oC9Gdx1<̈́;k!k=٪ƍWMwes a{Y<"X**kyx Uzvd/{ﲯё?-{tf5{'hkރk*F>w~xtB?j)Egi ! E޾fez <:Q0cQi ɩSw]yI@Y<]+oIsB,o~{M-(L>;Q.|wrwyRvN\ddEN}y3R$B,.s@f4Ikj=y(( 29:Q~ޡ2Lk "֑7]܏nr;*:^{ LZbHb|3_яgW'Z|qP>c@ȟ?*eX"9sɛފY#-Qs|{G]RfB.ȏJfBlAoz\{GUbfCYn`ɎH+o;%~I.Ys,a5u:1Ma1xMo'8 m謰n`1^mF\^<;:Իb"ά ??kϴ O{AFpdmFƶ3"wI!Z˝wj~պQ=1;&)癲G?]Z^,BYc'kg# t7mHn?W7Su)8nx׍gO'U@@mwuܠq &U ̲ߠ<L=s~8F G?p=~ԕQ7S=)RkgjtՉuK=1(5֏gWE?0;4ټt)51:$~sA@v.LdD~A@-W <jTңϮ IOcK)ؙIheZb-쩠thÑHz֙Gp~N;?/xbn @~)yjgϞ I!F/]o\VI gWO .7;OO^xH۽ώN3qBAՉ )"6[YO +7 'h(P]?]+t3|UVߣ V%D?&$.#AVX4uǻ~<gb?((ɡe)pIxvUO%7ƐU@&<؏P>{ۏ$#J z1,;Q˶G^=c]*acGVCs(V^bXiSX֕ c^ {)W>:~(  ۩~+͹e+`5x9D~*~ڽF qwxvuR?T?AU7P;X S#CA~N7,m7}xr"?'A@e%u~Llꪰʓ(UEq#ϾNWC9nX~ ~˚ܣiݱg_'CXsDEQwxvuR?f_RGSk\3%S49d~(}c8+OQgxRzӍgGETOR%CBDxNrdz5}m,:쫰dilP%Fq LqxR6uWaߖɾ!䧛ײRuωP:@Lh{P:3dcXwx̏5o @(Ђp.wIPe:BDu?+ͷ-ׁg绎n<{:/Gв I.h<>ȏ3["LVӗ7fxsRWP۾I*%5@*16/ DxvubV-,X½@2ّg_'a([G22 6t#{#ϾN,%Va| ԣߩw#znA @ۧɤwxtt21I~\7`wЭ{ׁlaT-% ).ʐzn @ܻn";Ķr^wsKlpαRؽܱ#!Xs lKqq> rn绎<:= [{7wneaT-9`;5IEX=.C[>:Sm:5V;~}쩨 FE毨4&kn֠h#Pf̥ {?b,6$fѪ!oD"~ES&xR,%6P*W#2[`#؊'(ZF:̩ϮN*o?/_G|62,NӾ{FP__|7{u_ӷ}Q ܤQ _տ^َ_Ǿ__/v???}ϯm~d_v:Kko}, EYQܓ_W7ݟs_ ucy '_^Og+]6hSUO7U1u6eݯ?4-&yLִ2JڶGKyͫן1^ ^/aُןVL* %fZ+Yuh`ues}WKЮآsolaMh&!b,+ow{=01;jE2 W~ovkylo(ëߦe$ho ^y}CQd97~ugO vͫW Jn_[yثs-fMJ~¯5 ]kd^L}k^lL͏m]Yw1WPm|4_Q^s^2W(sQ9}Ij[jiކ~[B^GIc>GʃcǬYƶӼ^6J.oS#-j͢ >|]|(/V֢QTO Gǚ\~m c :jebz+Vf>Dzxͦ4ZW˜6BTqbN=[7v=_az;\&4EcM#~ioMB:4˂&8Mz1Q²Ugߥ?6l<^ |q2m:M4_{ׅ&:ϊU7_F[ ¾EF#\-t`r?N_0ǰP?eJpXͯKgtao,YĿ}G0$*_5QnzsW liDHdq{"J"9LV>1F.J"9yCF =|aE&ry%pv>stsxF_I`TG;-ze)xlzW lIVHnWld^IdT"G; 3mVg_ \LFo,з/`˕(čv|'ʸJS<*/ + Jh`F_7ML+Or& 'L&(?#D׳t}!sK;o?g"fl 35yeEyU\%oWq3}3jG.2 $d_ d~*7dufD=X@X$J"#h!K>n~7_ d~*'Ue)`^EJ8yfeEF Ln+Or] @7ő+[ [b&s %&e[y%pv~A΄}*'_$J"9yUP'~~~%~w̉UIͳomOOTg;4^>v#_uW7*'U}Wcoq7_ ĺ"e$f;ovn^9Ry%Qqݨ3Q^NC { l\wO3s +\Fqfv*̃G]zndT g;O,fc5`VD.W/<`㸑u~%S!$ֆWS|H֕@9yc>ƍ\~#DO%r2N:yq,&]Yd}jov>u>ѷz#~~%VojUCj_;x_P&+$`=~~'ki^Iض7nߎC fuFJ S<ɪa ZO<ҼqImn+OpHĊܒ6g4.$j?nV>QuedbXčvg_|.c(="J+1s+=(1.X!yry&~}lpTk~q˲wD.Ë֬H*AUq˻1h_GO6Yڜk?w;5__v}o_ǜ?=Pċ~ؼu=UݏuOuG{c g7_!/b8^A؎ƞ~[lͷ-c(;W\]U9^ƚ%s%L f|6"~:38w g;t0?*33Lomo{؃pF+K/ T Cf}_u 4%P_/<59yֲ֕~hUgA\Urb^n>@zz:+*Kϻ"*^Ш>{nJ47^P߄7]ɜ>ܝ"~4TA9cy[ӥ-xeM&Q"ͮiOXMO _}צ}KOfk/7[?`uG+ߦa_?pvt1,,_yOm~xo| /^8ůAMx X7u[?X Ϊ_\}sԴO􎿯S :1g}Jb;7S%8<󍫕>q'q*!89?Ɖ$`~'$1sUd헆-[pci' [Ӳ| Wk/{/6M;@)-/Z=h~BCo纇̡rC"Ĝby-?|65gaGOݹAuwUU`9i{zouoyc1c1dW/d%GlL׹,ev)ݯЖeOέ`KxO{M2o#}:o->1 [YV= g|㴝 '5VY"N5o?o>7o{~|&M&C{_5-2Ꮴ^3a~[@*#t/a:\+''SK\m9)W;no|0ʼ2w:.:BJ.hpv,寘Pl|֟Hu.ePDZ$1}#t@BG?^qI@Eo8pd.~z#y"řyp;M ,U V*ar,W0N c2$O+9C> @4?W6BG3 ̝ L̵)m{,x03lŅEVuU(ח׿+P87αչcO uRxw;=܊,N=]N3vy'7Ev{fe8_c!ĮlCc{uh'lILc* c+&SSɳ j e_`eam[aEc9LS`\ <.743 AM*uM k}usF32q 5ClI*c {";ZqUގ8gyh^ݮgpbXN @nE|]|zj?Gm G2+=N(JsvEG(gt0Ȗ-sjrY])LV;i$G; ܊,NѳTw]6/Xd,0;sK Mk*n~z@FanE&皯-; Ck0T  v4Ef"\nI:z\m(Mk\J=LF"U*ō];+[A 4.Cs+ \Vw^c(ȁQ.heqJ[r'~ە:Eu 1WĊf)Xv}`Ͻ2/ X˭gЉk߆;8<]e%`[b'*~rbj"7ΪrcZ{FU(]oY[9 d˭J=MC" YS'0յ?U0*VAR]AM.:B"\nI>  EM־`TZ-g7a'Qi.$_;F r`b; heqYj.VѥG)j2'v++`ۥ ~"U3#+DŽriYm(ת) T˭s4=LbQ8fVqΔhfy6~+yΤqLOM~`ˡ) diͭZk?{+,Z;̓Ux(m*SKN9n81gWv2 5tְ+~3so<4@`no=w;ex?1{YWN=G"enIFgmnf@wkz2;VdbKy]<=Ob)Y\9-=jew=bC?F-ʎ.G3x`jѹ!qpN܆dԼ `˭<`\)*'@60^١fϖdfqy.z>kny uDnvh,bxw;Cpb.)F4UP˅FûE.6zS. ZߩԎ. ]11܊0@Rsp@C0~֡v=\wMh'q ,${>qhny,uiE/;G3 `X/:amou645߬,NeXZ?\ii܈zE:1aXW:Ǯ7}wMԄv&1[>.Mƒ6 j\IKû  .%Zz:V8:wWez]IV,c/h'-z]'5qNdt $3Flt{]-\ Џ>c;HnE13.O!yeĊvsd lbIR<:dRM Vs+nU [:/&dE?z>@Ċk]̺gFMJ6VwS GOľ\:,2#%#T&02&$G;HnIqN^W\1ԄfWȌVdVzPӏA;,8X X"F5vO;,yuP;GwjfE+Hnm44JJ ]Ol&p[r=\d2;oqpUBGfeq-jnU=NWQTW(xE#v;`]mh.ס+bˮ*Ydn*-/ͭ1zx֓.~V\ʝm[PEe)Jwoz@na&I|]!dټ4mTL[Jb =es6;Ρ35wbBVJb D=BM:SR씘F;-ܒ"A!aW&/:+:3 <0HG-hH3QYzs {>q{}D*:5ٮr8X X:LiPMVg3tU5D?V 4|{YFbYUENNl,TRKLj3hN *AZ_sTJȾmM;%'5 ^4^@ KR*{0ERE[մ,$, {s|X \;FAмB=BZS;yXOf&LR){x>Mוvb롉u>slwunfV4VJ-(id+, =0EfҕU3kmVȔ9JȼaBZ[S":l^2v}hjE;,Ԓն&*%ͮ(w=LLSm(7 uaz2@AZeeQN K'$C`m4#r\3{r窱fX;c٨maͯc]j>lobԓww T(z;/pK(v7!%w7b;Fy+X(gd(_\Ig;+ ؊\0D70BG6 v;5]h&Z+:%K+'E[VWj% (g PJ_vٓC]h'[Z;z<4\yJʲ<0vxqN+${ ivA~b/nX?rꁊf$u` `^#UI{_ &%v6#/r\?X=Q>hfϭ/\I_ " mpf%6V`Y&A) ^ 4QTW:YdsKXTdԝ&Mk`+ƾ{1;N #[黸aCsxS{J"[R=Bzɸ^ՙZc< VT?Y`s+0k R|@=Lh/jzN #[a5x嚏S߾uH~in3ˠn} wMa[=cpqvs+reKGLKhrAnM+ dsKrYWoE3g<,0"En),ȿIceX?d&@- OlUUksy6G;%٣D'I* @ʎ>/Mhgs+2JBGZB/? k6`hY TsKXԸ%QkJי]3<αU4V~(Ҫj䊁Vzj>hgϭwV**zin Sz=0鍱d&pϭcT XCS<,2c%D, eyGbC*};5`fPcRݷN@* Ds+h\9 Bu^dxc?Y\sKG 34N=4*5wZ3<ůh&ϭ1*s~Emve\OM`fq-2Lќ*zْ #HI2thC#,[Ob+n]ӊʪ,Nݫ@7`n .(ӼJAhUP&V~'j:f+ ˀnBq$Uw`Gh^E3xn 37&VP/%O\9hf- AjYhXCO52sjG#5E?VfVyPWj(bcpIvܒ"كH* [R^JP~7ZY\SKt-!e]u,0V\Qr:MKY5ߝ1XƱ%tEi5p3jv.d<*X.+G83#-yl'-\ WV}вQgRVeH7Ef?"s\k#0'pI5nʸ6)\FZ5B't9Y5wЗJp4_i]UtxRa|Ϭx!Oaf$K[3"rꂚ`fT0ݳF?O JCyqiԎe*' Vdqf$"f]PӐ3iYD_lz'D.0:R0mhfE+`n4%Y Xs+(@AiaN3O<,0%xbF\5H3Ʈlv?s+8fVqbIfaRyeb: `sK=OERMN(8衤ʁ޺&W Vdr8Ҫj\=Sc܆@E?Rw=LGbAί ~( d<,.!t"ǐV])?~(F2֑') XDs+8MT9.0{fv sK8׮P3A ?~DHy L̩'H*yebk f!ܒ;1M3IJ.njfXWv uiz@F?"3Ks[1̫1nH]+XYXsK( wđfPׄ83:rb=gn%`ϭcRjn oqfZ;d?Yds+8ҿSȗ5BM@3ƺraRlHX0BCi~ȟapIf!܊+L!cHD^_f&Hz22[b'N.jUVq ѝ)5֍C1,G7M* *_2jte? c%@(Y zؕQc]ڎl@FlYϳFQ4F23o )<_Ӹ .n(":XQ.`# Ψ23xnRa+|"L0̦)@Tͫhf-t+k>I}@(e3xn}I *s:f5.VȈdV'.ͭNir 5clˁ.=J"3[I)z<ʜV 5i1gZV܊ꛪʪZN/\O?6\Qł.6ʼZOB 2!xw6Df nv."(@h9]m0̦ l&pϭsT, PT`M)Ʈl+lgϭc"ŲwO]9*z: dsK?%[(*D7XW|wzd~m_+V:Vjuv}nVx-6McPKJ3t"Rv2'`HT̎V'~VYF7CYx+J\wt^~_YNQ9f)4̼W~>M5c:VìH!u>NSMo8_\_/kMRס2W!jβ0$@” u,ÃKmy~*̪ DB$vջ`,9:0+1zcr㬉||jW,Mtbue+!ix&\?VP%~u%rAOjҟU$Rc hudw ]XƉyVeU@Fw6`q9XDh險+o{=y>z˲BgA|SQNĜ5N4:co(V(Kd+6:}A_F`W_gOl~Zt>RK_KI_>/{ف+?W\][ gs_PsZqnJ7. ~1?S y" +?o?X0畦-v|C # 8w5?g~mx ~rrRXQt9Y[MA 4ُeѹ|@ zׅk } :~谮>WH]?(/ .6f;'܉yPz~yz!E?Cv|[T|1}=JBYJa1~ cc̨*NW(Sq`SbrƎasy|v^sz:þư"Q|1^OQůn#Ty.["@["ᘕƌI$ye֢+s+kr+R)/K8#cpv%YMT&eWJ|TpI) dVT {=vAzV50gԧe anɵ$.Lz.E*qS+ 8`%`?[a܈Tv 2jb jiZTiSٕ ;UZ[#;{؞ѕ1 S,YdV#{mDw?3a&8 `R nZtAlx3O2帢EanťoWwqo?^H&̭nSjg*,?J,;ޑ**L'̭gp "y)B/=b#*M6{vjKPv Ua&Pu[sCX>[Z;Uû)-hgP[\([/|4}kL"0B-mO1) jE7fUafO[_̂XE^8k:ނFBangSﺉsHEB0 sK0vf\qw!UzagO[zVg:\skL"0➸9L0Eɽ)UC04/6RjY2[bޟhƎwa'`S[wEO1TߖZUİ`d7O2 s+2Cβ^ xE,.s sK/I-/Y;r0adhb+ +mPg>gU4])W? nk>ҴԖ ~7ͧhgYN]ON+ ra#W֫k>E;nIP+ZU!f z.IM.UOf5g4<.%WQAreW=Ҵ \7ͨ`&pϭt:$Q{WOR4S1Y`s`/ 04ۖ,l`qI?( `Ds+0;)nGHin:RXTag[ԋ%nwr^ @KB>N cC#,%]Le| Rz5+ ܒ+,G\I89Χ8Y`s+I!7h].'F YJ"[q;t4>u6$5:lo<,2wrK/u>TfsM0HI-"N c $A)JQo̞,6Y9=;F:YTs+ZP ̊F %m+z⭰Νv܊,f$,!Mb*w?2~{aԂߔ\=3aꮙ0ك}hj5&3#mCP6}=D+nɝMW(IL8 )'ya'ϭJxWC s M+XYX9b#}),=\硣zc+nU*Mѓ4acL`n MSJTSјŌ8C$>j$yĥz*s|k Va +Ը8+O&WMg%МF1:68wINj|RIb\u 0,2CYl&x/!_>s@(Rl T8b!u^ֺ;nEoJ)<0U"o2ܟ[b%t0N8E* ds+;u{!N=L'phag-pRN1OF(g=P4FlE/*Jb2ӴjIJ/X L|XT/p%Ȉ/N;h<[UV\z76+*IB!4@F?">|)djS ~3֟[4rvthc0ue4VsKoH:P:|)i λNc+\^ KQҁ^vi^f?%Fe]}5A8pn;%0%xKP)a?`j1V.6RqZ=\`ޞ$uߌ:TJ z_x[N #؟[$vQz%0u/0"WB؅$C^:V\פȕvArL[CpRzvK3g)Agq]x!c^Y~E3VϭewLE]xq}^x+y\`Ռ.٪q$,.Z ^䖜vއ` pF3pn U(Q*{3KțfTVd9(e9z 9`md4KsY\s+n_]怉/Ϥ0Mo4_rǐV;sU|&s,0X鰕VQcЦg0Аz0X[36;xnEw`C9`jvu58@F?"5Ĭ a3˘n+ `TΙ)`oQi0B%x74 R DY6T v $O%QMC;<'F`R faܒ;S|rMUPV\bO ,J6.?m0K5Av$_ d" >K#/Q;>_fiv܊, EP̘Pq; `sKtp*RII`O!6MheqϭuexrX;QBN #[_삢JxLU6Ve?9C !`}&أJ!U5pY`V2X[r4YL"[\ĂJc]ֿVm> fLɘnEp%~5/cg+E?=ڪnj便 _W 6*M ETJ_Z܇F?Eș_ JӎvT vܒ<l &mʮ,2.D}si m+pn6I탢/̠d2߳.;e?һ)H Yڕ:p#pl[JbtCC&4w*TimCsټ2wo?,bYUiBve~6A.ۦy,2urHsrW&wv0$2yP\5쯆Wt mF9 q-ӿ25tsWgXW%).7GOI!g F?Jjx.5S2ZY\sKt2+sMhjQ:;`nI-s :ƠJ3Yds+@׬,@/܊,p`C9`{6+ȝg+Pnɝ]y&HMA8Y`s+ N!_R6./a'-rpHCweuH{/8If¼)uڐ=WS; TsKpWnDVu+nTV?s+n[mv u р9\LHn 1r1:v4mf \fj &5=h:ގ \sKtoɅŗ@t,0Z]bBr fq< x}J `EehgϭA=~R:QS 6,I0Rl"t,Kpjf-+8n\xu.dú6$fq L6U{x>LEF?$BǕ:ޟ&(`gϭp 6`/ 7ovW!v'Qﳲc󹄃(s+n]^wLcr˨DގWTf<҅R_*֗wxIG;HnEMs몸ê^m.1hg-׾@.GxJ}qΨ2YJGr^U(tͯh'ϭc%z mvx?,e(<,ѩ%қ;N/%mkdQTa'-SOs9l@ǝڮy&X4XFB5H` 6~0US: XDs+4xJd{2%9zHs*/8 񸏔 Vd:xirAy x,"%vw$y6ʫrJi6[Y/'<4\.d <^}9D;3[DZ2Vxu.xՄv܊Vv1xu|. "3['yȴ 5 m$1_sj4Vһn9JS4A L#[9Rh:$ K=R? f܊KLW{Lp7cÍQ9G+蚲ޚ&:k,0cX ̞ 6Q٘#PvbݱiZ~=fhL N"[E2Rt0nzWyqe?N&+\AmPcP5L#[ϕEӿ}4S>YXs+l_]Bt&w`Ckٺ?2%9G0_es!cUr "[aJ"3lx/ԡT0ǡ,2%Y5,^_ҰC"֕CI`h04E?N斫z[Fڟ嚓m9f3 n.HUk 30nَ Mh%p-ӽkjiE_6]+Yd:b#,c؁iTtfVa ;fZܷ2hr_~"+ \̭swg=_ `ŋ^0٩>J:f;1[E;G5ˆfWoVK]Wf`{}kt.ו%VرoԙfΨ_%l,,%v:`܎&5S94 G;nE+Ӌ䑲qd{3(Tͭhg-C´5.pX1B!8{()6֕E*2fP Fa{o: :L l0xuo!M--ES+Yds+2;4JM`c&&+n-nK5ꑒ$|걅~y,2T/l04w3싍ؐ*NLxPž%Y9f+o܊^UH`*a`ݿ4e?Nz3!OuO6k9f+nŭxM_Lwtzlf?37+hnɝ5=SLغ`"z YL#؟[{CSk Vv<984;`nE>g |}\0Ӷat18p]+ \s+n}cr-[f4(e]l }CgJ+;^ 0g[*ᾰ{39-sD[wL#Ο[(9:>'ϭf=Z3p fNoC6c_9^TXis6Ûr]'Tk-7W&rV%)aUs_F~C^S!/ee:]ۣ(TjAXbg/ʠưj'2͏[ gXu4/׽t+;M0U~Dm]T>syzo{&G蹧[58MW~tg$i7נ.Td.Cޭ6[Mr)kئ`Mg4A`i+p V*Y}̻ }ë́p+-?g8U̸ȭkN~ >{Y sM^}_ËOױFݧ !]O/n?ޕB㝥LWs#4Љ7}nbve@[³nMa~R^=/X4g/J%Tso=% i!8.U( >Iw 5 wV-铒v->o~  ų쇯%]5^§GE ;ȶ lX*36=bVׄGMt)kǿ… Ov+إqk5O;cf 4,ڦ(k;[wvQ϶sh/ /7N'0m_s^ikB;MѤmCgh4s7^7IR ek_?W h_/.'3ɷW_˃-G}:7I_w[,Ƽ%o`<«{8ξ}eOd&$(5VZJs/s?ج?2ɛD<^Pu>@a^#0qig4|nu.Mzj+|\iv9|70t㬞zm=2wB?_.vBw,K6 Ϝf#N۱ŭ<)̥`JnIXIe]~BZIsdW0C_~uE1p;0[ jkBnLn ;ɯcD>_+@Y)ǢEfnLnE*FnQ1re-%]>,WamUTOHp iOS|2 T^ǢkNxf2pS@4L{ʭVO'ADN@a4 J2 s+I Egm= 7#&6Ẋ]^ƌīa{O.rrK|b~[4,jƘgc.N?B`;̤ܒ+p|Q3Ƭm9N_%FNl4$fj+_ؕMӳ ڮLJ [Or@JqZK)BɟQ4]Kōݐا j2ey1Wvs|!5rHʭ: wCU7Z[EN}h+z.oz |2aI\ /=N WX1'=澠1|6[VG;ܙ[+0\ YjGVlM+\K9˙Q܁.kljn;36eX+F5&P3 ~!,K%cKK~?YUvY+vf%WMAF +~VI{TVԆVB#؊P .Wg4̼ҹ+fvdB~[,弝5ؐ>pb&[nݯՊqD :MnnAQnf$bCU[XόΓa3"hϣYa'`̖[F@;FzPJ/rǾ(ov5C|ls#=N֏cr_; |xWw(NS]rE\nm<0g\ߞj<ܖkvr%Mƹqs 4C]zBf3>e-_ {SjZ;6 g=X3+_Ɔ.R/gFgw;CqǸ) X,mrKW̻]o_y}`0U%˭᭧\Eh(c~uG<`&E_-UͰ7kKs[59CJm1C#a)bX|K̲m~qc_(ZY}?z\F̨#1b/+ᇞhfs+08[iI3 6zVJ|gQ~qn 5a<&YB}{WE 7Fvy_FlS"-ӤH }CR8Y~q7:*a Qb)!^Mʯ"ntn=|:0<1LKiŀV TƳ&i6/έAX\'`_ʌ W䆜pɠlF7s*.43>/V;sK|bܰy]"'<{Ov{ѹ%yr/QP1]v njr80f][qj3܊"_Q6Y !3Zݛoڕ>U7ωݵf0mSLp {йS2LW ђm>.؃-3'fwh KQgwVйasXьP]`^1Rvܱ$1cEne\sxj/Nr;vvc؉έ;j>7!͸zIfѹ%Wݱ16v\艰J"[r'IYS_KU~f3>:@=3KE9ta¸v$ca'/_/%;A m]^gV|XY\C\_'6y+;1fMޡrh'[[ybqґ?1ڒ陉v­ud9ci(6ؾaae@ml蓯V B+;ZSʷ:v,vsK Mwo.EJN #p['SRJ" 斜7=П&`=%T qmI!~ntr3:t3Vq٧F\ێ<|fѹxq/:,FjyCJ"K\[qŋ3+? Yz߾,|]7Y`nF`a5Ͱ)MkƭH{9 7Qꮹ˦UVr~mIPkl&xk%_Sw,)e-= ,7i/7 Ĕ4Kjd3 ̽0y`I3O|zCqAR; q۹Ie8|;?ԛO=Lp {ѹ[\1'p#OhM3,]ͣȭ`fq[X+kq|5\]}VL=lt6؈-Â'4cw!!ݸ;m;Fcb~ӮtْP6Xr;VNtn閯:}/fW ^jؒ܊v{ѹ/x;DFZ6*܃,u--ɾ^1'4~ICڎF#>,uy˖c]1q⎽~ĆJ9'V3F eb}} XlEVa(\%Xь%_K!kg.t1l&U['e}'úoS]G36lUIH ύ9 !;ѹ_vOzC +/-o5ٸv;ѹ%7v(}-)fK3}M]SLTcӃ 3t6g$?憜TQafR[k3cʗwBYa%p[qYZh0ya53<I\ֆ# :6@(s;~X] ܦenǐ}43ubhBuO"Ii+q:Zl'ү.ʒ6SQb13Jb+:B>Ōqdda)&۰W#fV,v VΛuvvc-;1zW_H-GʲK}W-!^tnTa_X@M[vѹb@#`jS.td&i _VgTIMba'k"L*l|tU깬3v=H@b+:Vܱm%Xjhm{$ͳntn n||M/_tˮPQsGNZm;&Zļ8W[gl_W`ZVftn/R SLB z)YڼSUvѹnLz(|!cd^UthPa'g[}b5w22:()y'zѶ) :w(7#%lF]*X P4tP\2Ie ⇝E~tnIuq4idtDhw`.=`&p][r/g슠 8tZi/z.%KSHJenIvK܉-]q .XXŹD3[nFO"}5-^`P'-Rlj,vsKT,M]R}R);{qn$ @uCi I̽8~;ѹ_h Y˵{j9@h3N,0؈-A{SP,7 ܋d>#Q;n+2,ez2L ' vV=U]䑯d"W,Q,xͭ8)^f{ؙwbA2k0Um^s3Nʑ!rй[}'x!1((]Q߹_RVйV^q˚Jk^g{YdnBd_Ȩ; M knINNXEhvf5wNpCWB/t+' [m;}ܒ\XrRry7lⅽEnqnE,4{g65G5(x}?D+>kUXj]t_^黰^tnVcMUZuܐHНf{ѹk4kQwiC*}ױL ^a5@}Mc)KSqSFN2a5/$ؒk'7"oȩh&8Sn4IB~EDO=,27s} e7/Jp 7삇#Nl=0s+pÍ۸Pnn2e\f8)Y_y+V--fuēvc܏-U kKI4~) m3_bv&TjFP<%'>)h'e[,F0ymJ59u!ybn&ɓ)y_Xa;V`;r7sK&IWK٧BX%al&[n56=-1SiJSp3ήlнK2 dVd2=:T\06՝y++,WU|+jnv6u:sK|¢kW>$6mž+ dDɹh ;4~Bmڐ3ذFG.7j.9VЦ7)],[uhrR/r h 6g:J"[b}škrƮLc8'W ={2s+XEHnk\{H_1Хm̈́kה(fzʭq`8/V0ntn/WXs`V^*Ms~wG;܊\YlJPƊu1i9)hgJ A]㎜uč=v}*FP w6ș[Wy%[:$Tn;IqU.SU_ s*vqmXߖ$ kpMm9aH7,ov&qnEnߖ9$9m9#[o9͔x.+m˚yZl`H-g@'^UN[aS:tW/k&U6 ̞.vsKZ]z{[O.qn !k߮lX;jnYW[;yU[y`jV7n̙-mǰ3[:%bP1r̺b_Msѫ˯hf1[}Blw(% 0ژ;=N {T<6²Uջ5.'Z;s}]p}Rk>0.lJ].\fKؕ- ʰkU~qISrK:Ķc>^~ޱKٱ^ `l|ߍVnZrT/ףp}rk0? nNSq(hFhR߬d;(R cS6~n,}B~xg",a7o z)ǿSK,풑?\\⧓?.@^6ֆUy;𭿫Pm]i\,noRⴠCWo8/ cobqxζBd/?casӼuroÕ+]NU 5mBM3SQuTE~{򦷓QOyHw9 CT]y w0zu zʳQOrO,?q?Qf WhwR=y (G0n4 V#ϾY+Q/"3Ƚ 祩,/*N~ԉrY)?<"gOVZgN s}I'oz+g)HucIZy~ˍ˂đsVb"ΕMo'Ra̘qiMaEf_DWJv <G9 +oIjh篦Iku&>{.gǝK%l&? %e Cc7#D/2PWxM \}%ޙQ/#nPkj JƮnY/s@Uot[_w?*e΍|7wMw,| 2?T^bM Ő/}ƳQ'/QHd6U+$tȳ~(c)V<TnMgb1JuMw'/؏JsCTfȟ2dOdF򦿓Q Wig-!3$<;;csqg;wyub?*eʍ[MT[| <u!3Vۮ;wn\%IIeq'EB/25$0oMGu?ʑO> >{߿ i |wp74ɟn+ YaG_w?)OɽeɱgYdNqh6<qw?z8$Smn~+eܺO^'^$'Vx+#t> qܙgG'֍B.QMa%䞼n?_+o>5ɟޓ)|+;A{ űn7 R8'򦿓I*r$+;I<4P/1쳈ՍC2gdgoxPѕ7ݝO"S^r㦞<,G ;CfC4n26iکv<=ʱ=y $1 \xenf1#f?&'ᢏ2P7Lgl1ME~!ĭ=,ln3r&rGoCf&RӍCrwǧ/oKg9 %K>`ueSw' 'g ܓ7ObJ7 y<=['o:+G`?ZMI~'N'z2v/o+GV?@yonb>nJvvdaSg'&э2{RqNL[_WA<ɟnj2G}ח7vЍCCpdˇ]_wyl~s㐼(!|ח7ύ2rO`sܾ˛N' ?MKG3:Yf,xw}yI$s|ᨛZM'RNd]Y`g?*8$ox>tsF}ח7OJ97ӳk];ķzח7M,,6 Or67n-|ח74ɟlnz'"Tq@IuꝬ,r$R h{F޷nv+JlVƍvrvkϢ07'Xyg_9w?OF֑@(<,Ge/aH֗7O-78_s;Y}YI$?q;YǞoUn|םf&ʍC!3~ME$VnLu'?呻;oEPRu7P~n IF!ǡU άڷePnwYuMw'R{22J%7<>^!DžU}yITr「뫤?}yI$(_QP!BAOu򦿓IR!ywr]y]? ckԪͭ/o+{yحޱ< GGtvb?Ih87 ȩIC1Xv;CQ},v'Qx3R"sqHFC/֩4Mo'C笀+h:nTB{bY= OP򦿓ICy˛OQ=yá V464{]Ov?U`_;7l.:|rRK0DM?;:Js9ǛN짺cli7܏oYN 3qqtw?nqH> 1JzTS1`ʳ C0-8پɑXƭ'oz+|}1^YYuPڻ<*7{ԇqfaџx TLp00'cF/.ɟ8$ dSSJyו7ݝOU#fkpL*܃A2{) ߺ&q?V acO<6uMg'SQDEK ߱H~,UVn7 @uސyTěnNb7 ;sqgO&8uV' s<ڻ!x Oo!h\N˛̰~nI)6vj.`vesw'SZwp7˭7r;6u9B2[aX*]fQílxבg_'A (7U2o2ۏXI~2_#!R PC u厼#[`Jk{ו7Y/=R>k5܊8 Ḵ>Hw֕7ؐBQb5NJu׻n<{: (zOrd]G} (R3pMGurrB/~?e\g}*Ⱥi[ 23[#`ޠlo೽ʛN2cr;4܊8$S^VnQjyד7\s+J e!N$"%r"2蟙2B2LO [/Ts+ Ku ^?,.#7Pȥs4 ͝ˍw=.za6a&Pϭ9{cW Ȍ!ےUئB/o;N;gN@~n|ܸ߸'oirϭd;p?>u E$?77RNe?FϚݎ;qM08`>L s틱}?SOV`s{rP_F>X1{O #xwUn8oiϭ_SCm\0ʛ@~n|ꝌُOM2"LF9Mk`dn_pLjAmlyţ@~n ?&6g&?r4o3 0~n +l10uMw'q܊LN {ѢEE&Ǿ<2w)*ro{׽1[ >e+]SR7M'܊,$xwp3;|wn̍պ7bCB)ẩJjYq׻^<9VХGqީuac?Vޱsksp~nfu) ]WtWdsK,rwVde@Fl ].8o:; |zz);*a //o+2YEƝ|Y} `'ϭȁs#;x᦮j..]:"[RԂB:zM]Xs+l{ࡐu)oz"3;lLb"ca܊8 _υqWdbCl[PHԎ)]Gtvb`HQGMEf?";)j]ߘ'oz;g_?/+Co>WѾwP_|zE~}(+?˧ׯ}S2s;wߎ۵~S?}a_HGq5lai_VjZp囮܌>vqtf^fC{?|_>oݨG Χ5O)؍du痮>ի֕o>uwӞ}}=+/UDnX}ۋlOkX=[\8|-_}ucRǷF; <.OGz _ V!m]"]}Peua[aϗoS?_]9'͚es9\0Ӻb[fJ]xDN3W gY/s'څ#OQ]𺹖[۸ v^}_ݼoߦ;`b|i^ʠsVohK66 lן [qSd()``GΏ/Mн8Ux/^N5ۻmsvRec$nv5pnV-_8lX1_%珯}۽+ vXK~NovpX6f{]9]H>ߵ-S)S}C6 ~1Gnm/3ؿ>調]?[s"s&]9}G6_RhVB37R {\c>2pLƯݯ^^_lyϯx^ $^J^9{Q^.2^}o~Ec6m`G^إԭcZTOj L/]{;20e|m+o8G25#BDGc~B)\=|'@yaA6@Q1[Z=#흚~!"#m|F2L>&Ic&_XL~d1GRgm[VH>2wDsH=eG eL~XV'N]PHFo,p7ϑmYlⱠ="BqJBdqdfdvff=3b#mHk;oipy!B#mֽg֭d_PHFej=;dKl'ByaA6>C&re?2/DfϿ[-K_1NDx 6EHp@==MT3*Ђf5w1Vm>wTfM%dl5#F+ǻ Յi!eX9Dhq`oWf~eL|=ZD)#aO-E:@Dou3x%_1kx<}dd%^J-l=kZ冮#_^*a\>C)c®o-+Z5~aK {iƁE&rr¾a/[\JMVMF5HF|=y$@~ MV2M"H"9y]ϪG׃< ϚG MGW["B`9y$Wj/y:M@5y'M>K.}+HDo%rd0gz#=ݬ#orT'G|FH'wVaW'n0Gzͱ#-#opdҰoXŨHF%HDo%rYuyA<5o%G)"ky`$C1y$@~ ʕ7L,$n=W[EOG]Do%r&hrA55_MžQk:)u$[r9zl?q;niO[HO:č~3r]C}k̹LT}ߖ;l%mXޮUX~m'O[YpQd:]}b9jcLf_+^\Dt}raQ,pz-SxFԴ\nn5k`a ځu!ӛ|>6a[j[#0=آ"\lZaŧ;~|I}ʗ;$-~iG|b絺sP;{z_k0<5v6XHXwKBS:U'tdVE:kMzg ϛIvj/&B#'$i ykMr[z0tbRG<{Gh8o5!&4*>=Ͷϖ*^*ۿac F<6e֙g]gWNE s#~_hך[X"?kہQǚ ]|]}M_~ĺ2\}w>'~ 8KxĮWf,څr&VxY]]׏5: }jml0g]Fq]@7k3w_{6!Xk󇄫U__߻߯U_K 0(ZDiR {V; g bhԓ^myWag*O #LCv=蘔DRCܘpծ˫͒ ?qmXWN?#ZOesGtckOSrbO:e'j+zLov O>T>{NՐS=257٨_?o*˯\uX {NZ_l|s`G]'闯_#u@8 SXt(&9&sZZ3y/_?}yggcLV{[|uyՒ>>~N{:XN_zYFa1F/Ѭ-=.zuorױKW( ){WGךOXZ߾=|gtE^9؟wuMg~:7XxRq{ 43"91]Sw[Sɞ|r%KNZs?^ߟqUva >q]m(KWⅽ+_/e&c[˟{yѩi;޺[:}Os&k3wh.z 5yXt'׏ǁH'-Isg{gGLM;ξ{y酉}Fzsjy Q׮?xuV ){NNǓoPNJNfKbj_>q^''܌Gb-0[;@CQְL?΁a'sO/hp\VTA/u~ S*FzGNkb ^gÏ ?bFz^Áts,%c -h9ʑ[.^O| N6Rْ U 5_az猲(56RP !EN 6 qt:#}j>Հl %>bNb(~ .!-Nckj&E'p٦Տ"@7J=8RlSEXֆV0 S# ް[8POM$P랭΂CaJ0Y=NjEWMΖŸuL_iZ4'ߗRtVXAHINƭ @x\ڸ!&z \df˴QDte/~‰A>ʢ\e:d.Cհ3VQHV\Q\8\'^Vq!\:)n$˖\QQh;T;2bq4BEQ.2KA!/n[-*the|n'̗l&Hӌ*-E9Q,VZpLVXA. [)3UO^@8V\pHȖXAK )맟V8ntE/%h]V4M@vBSg^W e}6#"uG?yE`"8[2biЁ񭗦St5cp΢"ycf(xEl =.x{| 2]GO;St(vUXIP 8䌚 |͕l.eKO|+E@lʝ{mU$`Q-[a=#v`;&Qw+uV]>Ǧ["dWQ,t闗5|L]AK>h;Oezl.$Ð6Љ>,%@Q-[qfQ|soΨoxǮ|+6:j8~j۴>xjM#'%p3[qM܆aΨ0w<"wTrdJ.!ۀ n0TDW9u:GE4BN No!rBBe n. >?uْZ*;HAsxډF/ْ݃,ON yrxeAuΰwWJ.e+~(&TŁpQ. k!Jl,eKǘtxܾ܁aց̟$`.[a;84Wo ػqc/uaˡ': XtV|;z݇Z8r^< _TtyvD؎A7/Y1Gr6]CKb+X"=< 91i=!O@7Il.ݢ!cL꫇?H sd|C|\'G b[V6M+T|xCu Φ,6GeK V) #(Pg܁SXdc3*[a;΢r[:pV,tK): XlNʖI[qCd,,z eW18ή'PՎ3cbY+. yjBE FHnj| xAYlޜO}`|KNgKnc.&>Lc$q(b{Ń1l ,RHD!:p^b2:XzX\ 6lCm°UfTtg]vvrۮHX;  O'ˈ|Ğ9b-zkdjv;n>g'wlV.^>c=8 Rs+\&"ْݾVݱ Ehņ2(]ŪNS0:܌> NlؒA-'A/44"8}GWNC dc#6F'h||cpZՅ8|s;68lI1&G=, iiү,lc<>[aS{o}q PQ4E8>[b=dAb+U>L`xE8>[a;Ƨ4]<(V3 %15e8>[r=d85<9rs#7vdKc,>[1FDz`c~dQf2-S2BlL>?Fhx=DF{FE-ґ]" Z14=o`|ЊK7dcϖzð.+vE/ |~7'|x[Nd^h'I"\}G:vCs*: X%V;4˩9a*f&v4+e>[a*.śsj]hRG"-Z2FהG-R@ߐuE'hĜmtBЈ|^Al}ڮk~?}/^y6#PVh);fh|d>[1%xL%yؑe΂:ZgKGHa͟#ظؐF/SĢc;"_.>/kԙd?,Re=[VA #@Pm@Up3i SuE>[q'ƄwPw} Vx:T%H@]XPFeۍ! $6kB'{ܙt(ߥqgV &T`dqX1)~ՈK)8 HD߳%Ճ8E=%2NRqd/{"Zr<(ޙ2T,z \߳];^J̰'*E)8TF߳U3J8 vnt9 %p~V܎ჩ`7#,ۣCs*8 T߳%uU^Wn=/dm!#cC}VPU8u̎!xŰ dNlÝ&TgK..}(,|`Qk 6"Rx4]@2-*ˁapŇ9v$*3,+SxϖPfZXd6|N"-1YϔOȸngwcSzVTb~@ ö6QF|rgK**x۪RʴvH G/D4:;fRa UjIʗD=[b U}Qq2Vu#̧#@ۗd*-՜P:]#;Y؛l8}3N{qtl?5Qz/'{VUN 1s[7jlD%C8ủ*ˢx]o'J:~y \J%+n\ [C|vPbE  l$u }1xUNNTYb3n#@Cs2KWJl'7cI`R'Yb=cݗ=)r:ݠ"IŚqc| cJN'Ya)vc΅=lN +!c94KR&Yr=cc~ܩ=[sT*ƭJl&Yr=c Uߜ?Hf|TIVTn**tO_[o橬(%p-бoT^ƸG|z3radcŒԊ.!|٫8'UGoTMS*TIDK* ZdBSʵ. Hf(;.essO]?c nt߸4RIz@ǾwːDa>$X;*Ƹ]>IF11Ȣ x&#[>6TR! Z1:tBj^*uN6u$Վ}3&ģe;gb EBu Y5fŸx]$\#Xz߹eJHQ 8h\R8KR"YqFm(f=Pp^373P>6tFDkPc(7?DzWXy)*Nq[s<4#vaU;aJr`O^ ɒaUJmr B6 ⇓xBz$1vrU_,v\,Ǎ⇗A6 PC<aK'!UPP~[(JiV,~w^B^O0QX=|4bD6bBau0U$h?PG"-7޷J^0HV^ODy9XFvbdJ²@u`,JUYoci'|z<Ǿqh65 )Nqcb\'e>[r= g<0̷\oM%pV܆g# 4F 5MNgKGtXRTX?A΢LUzhJE'|vqjJyǰ^Ÿc '.bْ KJ/}zV/ciJE'|Nԙ]֣>V˱w`R=u E/lQ&~O}=dZV F'`|=YE-Ɇiy1]LǦ2 =SbЁA$Pϖԓu딶VkFTdJ&5:XD(cl1DO馐2U,>1I`"-1Jl*BY Z)?̕2{.^w|kv 58*ŶejԄ^b<>[r!PIܛe'/vcb> 3oG"-a JRF,@RyrjՄNliNUU*?NyD&TOv4]>2-aJpCuH A]:Я#PVԎ9.M)2mdT_e@>[rKoG圚QB9녍Nc@ш9Pmn MF!J{ZE " -aJ@=VPW3_AeH>[q'ƦߚNP PJީ!w7x \%;,E Dک,%S+Ўl,Cơ4)5jӊ+pO8}DrKB`4AnV>^JC-TJzR?z9 Le  :o9QrZ<+6AlE+EIj_tt51EL>[b=cKȅ *V%1^W+F'ː|έoD,쁐֩ɤHLy9 X%cbM;4f_ƕJaOE""-Bܺx<FFbi:kB''h\џUҘԥ& K^8`||#cRtgK UP HQ}P%Za|=Ac3VL1byH ^SS)T%Uvh.uLx櫃=&?^V<棚ΪWH@RbIJ:[riygeފMKtgK ]2QMHv -Vu )esV\R *Niz#+kx/]4K" sMʙt 2W> r$`|b 7*S L\f 'l, @#(ON21L^^ǹ|"^lAϪN/eX6dcϖX(^S ܋A%p1* S_eؖ'<| يI՜J(ivaxb+hĭ}l*cْUC>(a:g4d.ي+J!t:{괥_8e0>[rEi|VmJp:vbE,>[a)x<䣒.T1];hRK"-5 ڔ&Q{`ҡ0e ze<>[qE1Մtl(3yr@=5E0>[BhNyG)%cB}^kE%l, .!"s;Ƙ+ c\TxkV\QQY)ژ=y,+y4a~ *oq? esV\Q0o}VuJ1_vKG;uP*'h:Qmp]3bL>P#"Oo|V]JIF>4(E0>[rE9p=ࣂqu0Km g/wl]o|VeJkeN'{wNnي+8C.9U땾}c,+HꍨϪRiX[4,npUNl7QtLoGӬ^6l]YqU23Y(n K"L]Ectus4e<>[r֬jEJe=1LexsuE/h]KڜЎAf'YoФ^1lejRyg4 lJWcSϖT1 %-?.N)3Hᙵ?oŭ, +HՌϪU9 t 4[; 𲹌gKJA>yrhFE/J<5[aؓ*)UlҰxl,y| gKeVQeޜPf̀ G"&VY$0w 3ezW%pϖ\7ejN*KZq'F,&^6Ql,tϊQf2`{ќ>alIhԑE9=PjLfzCN6oш2V́>;gݿo%r`ԄNqlhlbM*cbyaUy9 X%֣M,FIlVގl,C PzHe8D%+,0fFBM;~V?}zgeIi%~v8(Z6s>X[ʃOJ~|AYZϬk+#s ~yIC.BoPq^.q!_(Ƹ6گiXKk綖T=:/v홨zNeA-S~^ߓ{R tgk*:㫿a “K,AX:rb,.jۯ#_FaMThM/(,$Wk0^}^W,ёC?,KX{B,*,Vr6Y4ޫ3~˙?>wKؿCa,չ>P~Z+G入zw3\3^kL-@:/Lܪ}3{;T &,l ^Z]l璶^A]G:؟ٕ#_ )x_?VCq`utׁȄyxccS..kgCҭmOp*8פ񠲞S:S;~sʩ 7)ϳ̚vNPvjn]^›ŭf,zw5ƅT;>p:Uq:owZS/+13mN@%_ziO'llI]}C.Ӓ 긡-uգgdc~KP^r#JؼZ>x:5tJ!A7~uհݟ^xي[qV['i,+j.U4)rC:vg*K]$qbZOdl ]L}Gy?{ޗXQpV؂ޗT^ X}iܫR}l^xي-$c dqxy\feKzw]Px’`W 8M*z \e+nǙ9fGA|^/#P-[{PJ_,˫5b %l.}K;CA*</$`-WB瀅DM^Eek_0V\vvF;(8?8\'5^zF/'%l]SPhb5,S "MA*c\4^N6x݇t/&5;rVXmI HR67+3es wڂ?QA'z?N]K"%/[qյ!Cb3uV{&3=.ss@#*W%\ֹ<>*G"#/[RWߖ ė$L!,Ƅ{vI"#/[a]U2^Tvq N.ʢ3es\פҒ]Z}]R9//l]kR>ՍĆ >Is+E/ˌl83)@Z*qIzG4dN%ʄXXc.# WՌ)拊Ć;@>%&l.%rV7`TPdvJv>ZTe+V5*EW@>a++O^6xْ:wk>a/YEi3mtPrU 봒i6f5>h5s@^wْz;o)HcS%,!N5,-esYՠ!Co ޹S#},Rgp>[Q՟uE>2Y(SEt>[b5H}Lʸc:\e B'|ȸSc~5lq޷C JK"<-sCc7Hyw?Axy \WCDK6 9uincE'|Rava-~6TDp>[2WǺfTMKmQ*MxT%uul $z:B5lO줏}+,x \ l0 RLI4lF\I`"6lIu4ђěyj/Y"@VNզJbKԨ#.$//|kqTD˜!\CW2vg+]^kЎ*!_c׻&StgKY']/iFCX^4eT>[aշ"1[dǦ$`ֱ_@dސFFnl۝ω! ; x]:;#Cْ^IPnLzݤ}*"يz\\KNn4úyly8XFV][ZFRw䘔TaG>gKw"2/qpP! *dcFLm!t9v[R< NqlIeƩ٤.=0MbϯACE`.[11I]JRŠ?s`~Hb֥;l$.'g5`u ۝_^V_#ي˞C3r4bl-5ni=oM%pϖջ)i7-9ƃklK)z\̔Cn ȣO2j^@E>[RW#6;(񸶣ݟe>[qФ&rw >c=ѐ(-(;Y̓ȵ%XɐHf-z PWO)CaWz=5e=[a~ǒkko4}y \D%WK̎ q,v>݇5f2-gKP zȲ={>_>#*CnhRI"-oKNzx,u<'?cTxfFP*[Jrx,uFiamU/'{Į-y7!jiniZ Nl }#+ȦGgD {J *O"~<c|*BيZ>(uBoЕge?O, .TH)Pac03v^"U޳%Kgmi-s0!ְ.%p{ϖ\uҦ1jP<=cL`p g+쵳:;qC[wBcg+YSN@bq}{gBq!窚HK"-N. iS[qLF)Rd?;S=WR]_NlU׶ A?U7Hjes~V\unHh1ʸ${גe ^ʏؼ>Չٙ K"ZG\T'n}~gw1O'{-U,H2+L DחE>[aΙ"aS^]܊3\X8^6l]QT^KjI"Z_XnGw}95E<>[rRf=J*uc3VLk2u@vAϥu<5@E,>[RWR21j\&ѯG秦SxLF'md&SzgId>lEUǚ&3Eє^:'lM%pϖ7bYdQIѬq3cgP:c*MZk؎ږhgKVxaS%%#OͦcC@N[#UYA>},Ra >[Jx)SB3T4W<[g+Vhd9K--^N6l]|>Nj$x%pVܶӧE >Wc [Ig0|oR|iǦXob^6lŭ;y܆<Ž~o*$`ϖ‚V;}!_U7ȥP^p.2mLRK*tWM$`19"a#zz}9 L%Kr+JT|.U)P%T=k:SvةpE>[aN)}@թU)z\w)pbp̮q٪³E>[rc-)%)4!ZXD)bg̰NTC_ϖճ[wJўLfxT臗E>[q'dSP2+EWzvtgK8w wJi*bT~y \2g+:Uc|Tտ;04.ו,b:7ZbtBEsU˱4ce>[aUpv鷺ΰqR˷ mԯ%,b:6Mu)֝`uzZޝgcCFD-C"gevr(6t|J:/: LD%[r]SVd0`ҧa NoQI"-oŽauC=z/dcVkO{,_8p'8?5E >[qչ%yO`{%eqqr qgKn.>*LcMcFо2)תN5rCMD >[RWNJf\[ȭJesV\ujJr*.JĦgm^cm.bْۨp`T+e[U0-ozK'`|¶LE@*kuk%NU|x \ճ%z38~Mn[mVܺ35וlUqxs{l.ْޱowUfVqF$`VXv]Rܢa]p2/6t,%dcVع {nH[JԹ%%pϖ\uۘ92/UK"*cgS;p8MT8YRJTJӃ W̭jZq?I"4ܐ'FoU! U]l(ޢ!v"WIV֨zdTEd>[qٯtMd0ժ^)iM6zI38 T%5 X]V=+HXFz2mj6δH2u_BI"0-o=ID{۬&idcP4R*.B)L.b gK})`2ܪTgg+4jCT0"ӨTded>[bյI:–]ie&Ct@E\>[Q9ElKUYPltgK[|ȥ\?J2{\Wө7ӋN_Vw>al݉S#V5TcOv}.u{gK-L3]JW|Tj0D^maܢ;BC&//|▝4 *JEYʹ=F^6alU+ܪ+w?`IG/|NY!}\ nV9%P)Bdj^p7g]3*z \un.>, 3.]0: |B֝9EhGnVU;#2&- J+ygXQJ*%pV\h>ΰjP[*| gKN:|+V`%5VR^>oيɞ wUۤ=zMp|c%Ygh' w|x\SEwUÝ_W, -ci9V7J8 ZbwLDCzvNj(5h ĭ)$0Vر)NJ}@{ьNos ]Ge=y(Hf3+ f z084`SB/X|BΠ=ʱK[ɧ\LK"Z5 dա)oN2~ 1?5e8>[rW&Ըp.IT44.يvJHaU凊OV܃9Ǧ2-o̹ ~"3t_7<>Ah;ӭ:Rǩ]"":W LG7> {l^6lU"h8lfgStg+,s_Smkʶ#N2swPoаT?gU}iX|f 3L- LVF-Oo.[RWߪ&S)L6/鰏ο|l*#يw"3ZuA0f}v^]>lI]=㲃\ eV7ȣ0Ӛ/{o4/2:ٱ/'{ʢg5p4i'QNlE ]#v0gA⧔L[|xTձΔf5p0uP$Ɔ7ݜE=[q=Vuq{JG*ޣW|Nl`(>coͧE'Ě"T0 v5odj'%$^NC2;9q y{R"l=ߟ(„U;:?4}m(b=Ӥ/jǶ,I@y۬&M˷E:JJmW',./q1Vvz3'_kQ|1:)t@n{>N*u,ԹX]~1޴(_Y?o^uf6CӭŦ.la#(.'jݝkT \5?`-&?~9rܽNvYg+:mqb>XGnFhwnl\{ɷŹ@8W9.5l0 7\'ȯkB^¿Iko+~&bߪ.fvpd@wzw:|y34z`Hl'Z_zsH^޺` o|U Dej.u9Bh(GhiiG?~mXT-傾5&fƍ]up"CEwP ļXw[?|~ylik3? 6ԉ fi"0 kdK=WNj^zQ<*}kt7=Nxٳ}z=Ͽ~G \4E',ܶ硇2NO-GyPcfQ@H=ssbOxc0@ [@ m3Xy>M=VSU]8.=盅,>f5\'(k\N(8u>/{qe;}^L#LmmC(ۋff.6%e}ĥ>ڵ/wWw{?FWys(x{? 5ԼDۗ跷3_3ky[~h&6f*ɼf::ïO|_7???>WOֳ: 0?nˏ`Ȱ+K;/z2#[rOQ7 N[uG1¸anAoܨkg'aT6H\sZ=0~yD1$%ٲG׉1zTZFk9,dl,Kc K<[8M)ݝrְtS5; XddKl) 1n+DՌrG8}u.XBN׹`#%t Y+ٲKwo] l|~"Tq69)1l.V%iTSps[^Fgv"F/'l ?1l0cOaYf=0z9 OvCԵ]#~5P5 g(Eʇ'd>Q85)H'nvduqFu\&Z0::\¶q3h^Z:(b%wJ;$ z {H cC;$–s'O 5;KOgu5kpd6ٲGߞo_٥؃]\Q;XV(: XdX*)ie&+K//ˌlmF%0QQh^W1n0S-;Yg{PG};rw Hrm#<ٲGC=F[Z1:c$Y6; XdK?+qRO 0dacC̓SڢeHYZA$=yeV؟Z#r6AP?b;y8u'ʹ](e37es#[|Cn^󭀫pKb]/[r+FYTPRH/钏p95UJR-p=X|#u! ec}O*rh5/xߥQѥv뚏^69Hْ:Uۇl@bOa'b{Se.8!)Cuu'AnSbPsvJ'GsO]b7BAT6+2ĩnbrz9 L6e+lǙ$â3,.dԆ׭Fx0OD0R,솯r`N0r%%t pzn<O7TeMr;uu GeqS%ןCB۟TJ6a.?JY.Ro@ETS}PoAŰ(.JMƝlup Q\QoH[N ř"mwpl٧ʍbS;j}O)z\eeK FWgoܤdԎ8?j]lKu_} Fhxfb)f/ӆ*s>ف5'f|e>1VY ƽRpPH1e*="v__5^^I_ي;08E*#e܊!Ρ[}N_d#Ec|^YK?L VէdwdٲK §?lr>N1k~8'j<,ɲv|Z̆]V̗a|dr&˖T2y?sڑS׉) Ŵ^^;|7.  ܣ|E&k#ƻSbdYh(l|i3KA}xV)˥{, .2Y-[qxh Ƥ}c[,#ܱdG;Ls~Ri^UQ({ }B*\Ӣ0Xs] wwݍX:l.q'ev{AunôS[֐ .%fY\ЉA l'䁂~u*^1Wm Xz^Bod-{!Fф[?ٟq`Qqa/Me]ڪ,l00eTH1; ׁ?l'ٵ=F:n^C?K`$Kv l'o?|>rSlGQKC4bpVPЯd#G@"/[RaMTRl?/rU 3H#p\񩶺.]U>!90[ɟC cã9(F|QDQ^uDlbߠ_ã-}^^XbV#ِV\_\.Arco0ĒL>kx0GMqsqjv7KݜOc O'EC!\O4I<,To ­oR{mJ Kb}6[r9(EݽOO-}=qr;檪Sw9(:m }:6_;N'.f>AR.KJkXIb7[a'[ L4DO)rh#ymtX͖X]?>@ҹ7Bе ! e ofbC}q7[@c3J9R F=jn8ե%p-2[#'5 kE,֋l.g%. Vt]Lr<Јta=5<혛ےkH yc &x#Y6{ y C0RNmܤ^GxJ^ي HG% ͉K/}U{TM.6˳:lɶJvWE Fuu<~[='K˕oaa5&ڐ$ kٲO 'B)'.B,ي+ _ؑC*PxtꖸnXzygO8|VÂ@ĢoX)'^;zjDt#S6; iód+qNv-;O}+ R50kKutXֱӟ>| ՟Ol0. cr\͖T@?H[)W;y^ {f+i,݂eX ʿu䏰Ѱ?cnx V[J1꘽(WBTW's VsT%$WTUl*}$vDpU wnQ~ҏ^kي1QXx*UxP({ \fK.jCXܫ[.ݤK~lOjbP.9xiTlbV|[%7ì{psCo-X=}yY\Ζ,]KtLsL-U|Zq]h3)p)-Jy5WXv NAlI.,COWl $]N\ΖZ[k+YU%LWS^Kb 8[r++-˾a, TZ EY#Pv貇p=Y-8/}񽚰I8yWU2+M-IjbmcٲG`K6⼤\&~%Sr7K3& R{FMzlOX%.\XXDbV^^)c=3+߮FjŪ(5t:Q-;,F(-+A ./(=ա%p-r`v?$t` ~{܏^6˿ي:2ڬ7Nv16R/s=]Y^i0HdDC aҞXzy o?x<@%4RJ-.V~Rg/`/ U$>qB{D'l' 3,䈍zt٬U>4k~`JQW -C ^//KXֻDecןOZU+W:^]Xzy\.fK?~ h5[ .g]XzT`,0uNvlP, C|diUUl?`.8s~sتYlSu3I2: p?U9lV`$fCr 8[bY:VFq-c{#@J-r`J=j鎹m $UǬMWHtN K֕ZWy@.qeKٲO4zBQ*kɰX|(zPԁD.v $ņWulх.j%LƕѼ0E?[& ^}Od=٧90\Ú.q8[vɟFX X`Y愾m/jP:p.Ե?V $U{RfώU0e|dd΁0{lj;nfWe V2ea+_&+!<|(p:ڽ ?X1J4M_fL F'l* c|4r?7-M.9bN `Y /@bXB>^K5]Bp?*ԍGnJ.MOWd.V%b:=ZXhȐ.fvFCB,`H1ځuMl_w2K96x =bpilH4+y᷂eE%[rzM|{347\m4\tKf/SX Ζ ,[Y oZO`1P,gKhgIV?σxVM?OjHSgrm.:_t+nUQ0GT'g力_ZYwSڳ.{ =VG7uqUYii$ŶwShKe,nR%_vqp5<[юMm{RVF%prk!_4vմKr ޛ I)]-{Iy>zPGO'\Gy` bFy.!Ƶ$-nƻ \=ޞ;\f?B\ &DkHF_5EF(BDg{PK}Rc;N6;ܵ Im? ^j%PW>)юwSQ@2 =:>Z&wB':׊E]g3 KRxOd#y*Ay=,7?~PoϹnǻ~+{1Z͊WvDjj~ϓ!Zlǫ 8ԋՁZX]_TayPm乏Ī!.79 7ܯrѐw[N@'|_b H~$PyQՎWKuԆt]mۯvPNAǡ:./nȻ Ńq?7.Tx5VaӊKle7Zc ê3V5օF,AlZFm_5VatK;p.q_+u}[=Bv%O/MEG2aeŚo ?(EYS)ӏeh)=KST.7`[SNz! ]92];I~U A8@Fj~@@ǪSI>1澘b~W9~yzhN GJ(@Ozfz FTꇦ zffncC4 m,yƾK)u"~-,[uwcn gE|AKyBxR{&ze<믱YHϳ2"|Y[sAъw;Ee<[RQkTo;yQ ;=!hL tqU#^\Dγ%4@ud-+Z`K0+7`Fϳ6Rh}) \#.(Z|B[fFdyk&֣yaKtXOeʸyǼTOTcaE<[`#%c˓5Ic;MqlT"k|ьWCal 0 f$ΨRlƆƆ.( YhrFWx7UXγ}`GWlI ~.z\cE< h VBU!\|ED<) -=C/g'yEVu 5uTa;ϖ@q옸4I`œn"tEޗww請~xO/_3$W>Ǵm5ϟΟ'jߎ˿׿ߎrGߎ?{c?9uK Ðx<0 Cj_w?xnu͚6 Vl` O}wV]+G yrr9OT:ŷ>}Zn߶uY;·ZTѢ5Sno||=T?K}m|Je%|7+r9߽OliՄ=mσ5Jnڊ}J|#Ύ}>{Eg쯱G))Wۑi0?ݏ}/^ȉv}Nl飥T:r/g}j4>["ϑI^4ߚu|^upcG>{ S.Gٚ[۽~9ʄb]/h]\v؀n|϶W8rqNKf lEO?we1ųks9{vd_$,~|˷MLjGFsY 5S'Τ}}{=sd5UtnjFY¾">??G|絮)syzݵuյ~ර.Z}avKxo 'o0[{j7b>g{){)Wwۿ8?v>~[{__kW̲w8 ~>>|&_s]~$e~z/쯟o0IJZ;bŪuUg+^{.g~6yt{m&&HuJx>'?]>ߛ>` r{c,> -W ܇_'%<گE^%Ǯb*xލce/v?uз֑22dW=Fߕ8O?dxX#8Vf?s$/6j<&+@yɫ?G^;{ygoEr&G$[P$cN$H&۷29 23yx\QdǕ(8L~^|~,GCoEpI1z#\|sZL6AL#oEr5Wd`0-@2d}+WWiƬp;<;:O }Ȝ\ \~+~d|QlW_&ۑL?_la^[݆ #_ ,h_S[y(_8pJZd]W<6G-ghy/znr&ԍ/ V38 ~&T~&\&ۑHƷ"9Br}<+ZvbNǬ= md2_b߸GuYa#lMVHe>udV&G?_Uk8EhKP<V$g?YcȾ1SE oeI䟬5d Ķe$f?_W!^y?L85yU>yhA#oErdnʰo

    +0.*x ~~\ʝ= HI QgkdsԪ<[Ր6٬Z:#2m6Cgf(4 >7ßN!Jʉ>"_3 )ʷ I:RrHST.bCC3GM"pf&j:5sjeک1џtDR+mfQf 5z]1c01Ӊr71ڱQsrX50N 4L`6[ffw𭳅/:uFUhų"3plr 쪁qas\¹?1Z%F2Rf4^ uKM:XJ:~Z/I3OӴֻm{(3t0 o&x&A :eo]Үh,iͷ'fn&njKߧ,/^x'bf%xUg}V>0&YZ?L)Y [Rfl'-/X.Y.[T׭EIX=xŻؑX^-_hwqa0aLsy8R}85B2 ۃ[hh'xx}$ JK0H lX%p<Dhܰ)I"͒D#bQ o 7p"ڱ0@[قx=Z"li4 [ !NDw qVa #Un-p5ұ^H`D8iU`Ry{84ڶbc(Ӵ%l+M{aip X<75;N0\i$QGk0l`a"   vL\cDҁLD6#%Dm(ۢ[D^(:u-ю$F`(}@E7K)' 6ǣH=QښL攕mٲ4(gR˾ ˩KZۖ`;m:QxP9Af(rZ41K&Jh|}Yo $$HwAIV\$Nw9qBz"  %)ZJn}-%-F ͨc ʭCHVIPdDiFL$2唒ƗG.J~R$H^SoA\׋|aR´Z% QOTRBZ\˾b-ZlAf!f[(­r<7`ԃ[-3^Ի/ _-ڱ%b z"mp3D%a iGer^:E޴LLPhC@8cz*y2 F,Hy;Rm*vO:y4mcuȟ_@3{-jiSQPҌHWc}JQ;i?ZiMiFrۡ(^I(f* 83,VhH)mE#+qɖ=n3-YiU^jBcFG!󜮨(nYKt ' oTy()NGE+{2N9VR*\ߖa_%kFڡL̳1~|r12vE#NR4^r1wr-'٤3!vXo;#nYF:J͖>} ^*?oد_fk/ˊ?}8|vggR~Y~2hq>*' _4 ߟw 6ߵЇuKpoE'o*xԞ~gT֧ v)?I? ji˧NqȈbxAdNzN2G`Svs98=v1ؾcLٱ BAAxX;0x@{?y?uc}17z/{o~Nصs=ؑh\{o= mPbכ}VVW;o]$ߛ~XըzOﲏ`}\柀ݮ9L_/*.(Z"}^߽U .UU"ꥧn- ܹw/Y8F,oj^ D0LDrS әHHH-gF!p&l(&p&HhI">kN\ XXLH$P.z9_]T+ endstream endobj 200 0 obj 7836 endobj 201 0 obj <> endobj 202 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 203 0 obj <> endobj 204 0 obj <> endobj 137 0 obj <> /ExtGState<> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 138 0 obj <>/Contents 139 0 R>> endobj 205 0 obj <> endobj 206 0 obj < /Dest[1 0 R/XYZ 0 841.889 0]/Parent 205 0 R/Next 207 0 R>> endobj 207 0 obj < /Dest[138 0 R/XYZ 0 841.889 0]/Parent 205 0 R/Prev 206 0 R>> endobj 4 0 obj <> endobj 5 0 obj <> endobj 6 0 obj <> endobj 18 0 obj <> endobj 19 0 obj <> endobj 29 0 obj <> endobj 30 0 obj <> endobj 39 0 obj <> endobj 40 0 obj <> endobj 49 0 obj <> endobj 50 0 obj <> endobj 51 0 obj <> endobj 52 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <> endobj 55 0 obj <> endobj 56 0 obj <> endobj 57 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <> endobj 60 0 obj <> endobj 61 0 obj <> endobj 62 0 obj <> endobj 63 0 obj <> endobj 64 0 obj <> endobj 65 0 obj <> endobj 66 0 obj <> endobj 67 0 obj <> endobj 68 0 obj <> endobj 69 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 77 0 obj <> endobj 78 0 obj <> endobj 79 0 obj <> endobj 80 0 obj <> endobj 81 0 obj <> endobj 82 0 obj <> endobj 83 0 obj <> endobj 84 0 obj <> endobj 85 0 obj <> endobj 86 0 obj <> endobj 87 0 obj <> endobj 88 0 obj <> endobj 89 0 obj <> endobj 90 0 obj <> endobj 91 0 obj <> endobj 92 0 obj <> endobj 93 0 obj <> endobj 94 0 obj <> endobj 95 0 obj <> endobj 96 0 obj <> endobj 97 0 obj <> endobj 98 0 obj <> endobj 99 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <> endobj 102 0 obj <> endobj 103 0 obj <> endobj 104 0 obj <> endobj 105 0 obj <> endobj 106 0 obj <> endobj 107 0 obj <> endobj 108 0 obj <> endobj 109 0 obj <> endobj 110 0 obj <> endobj 111 0 obj <> endobj 112 0 obj <> endobj 113 0 obj <> endobj 114 0 obj <> endobj 115 0 obj <> endobj 116 0 obj <> endobj 117 0 obj <> endobj 118 0 obj <> endobj 119 0 obj <> endobj 120 0 obj <> endobj 121 0 obj <> endobj 122 0 obj <> endobj 123 0 obj <> endobj 124 0 obj <> endobj 141 0 obj <> endobj 142 0 obj <> endobj 143 0 obj <> endobj 144 0 obj <> endobj 145 0 obj <> endobj 146 0 obj <> endobj 147 0 obj <> endobj 148 0 obj <> endobj 149 0 obj <> endobj 150 0 obj <> endobj 151 0 obj <> endobj 152 0 obj <> endobj 153 0 obj <> endobj 154 0 obj <> endobj 155 0 obj <> endobj 157 0 obj <> endobj 158 0 obj <> endobj 159 0 obj <> endobj 160 0 obj <> endobj 161 0 obj <> endobj 162 0 obj <> endobj 163 0 obj <> endobj 164 0 obj <> endobj 165 0 obj <> endobj 166 0 obj <> endobj 167 0 obj <> endobj 168 0 obj <> endobj 169 0 obj <> endobj 171 0 obj <> endobj 172 0 obj <> endobj 173 0 obj <> endobj 174 0 obj <> endobj 175 0 obj <> endobj 176 0 obj <> endobj 177 0 obj <> endobj 178 0 obj <> endobj 179 0 obj <> endobj 180 0 obj <> endobj 181 0 obj <> endobj 182 0 obj <> endobj 183 0 obj <> endobj 184 0 obj <> endobj 185 0 obj <> endobj 186 0 obj <> endobj 187 0 obj <> endobj 188 0 obj <> endobj 189 0 obj <> endobj 190 0 obj <> endobj 208 0 obj <> endobj 209 0 obj <> endobj 193 0 obj <> endobj 210 0 obj <> /Outlines 205 0 R /StructTreeRoot 208 0 R /MarkInfo<> >> endobj 211 0 obj < /Subject /Keywords /Creator /Producer /CreationDate(D:20211113100828+01'00')>> endobj xref 0 212 0000000000 65535 f 0000923405 00000 n 0000000019 00000 n 0000497664 00000 n 0000924104 00000 n 0000924180 00000 n 0000924256 00000 n 0000503591 00000 n 0000505343 00000 n 0000505614 00000 n 0000505656 00000 n 0000505903 00000 n 0000501763 00000 n 0000505946 00000 n 0000506219 00000 n 0000506260 00000 n 0000506509 00000 n 0000499716 00000 n 0000924332 00000 n 0000924409 00000 n 0000506550 00000 n 0000506823 00000 n 0000506866 00000 n 0000507116 00000 n 0000507159 00000 n 0000507431 00000 n 0000507472 00000 n 0000507722 00000 n 0000497687 00000 n 0000924486 00000 n 0000924563 00000 n 0000507763 00000 n 0000508036 00000 n 0000508079 00000 n 0000508329 00000 n 0000508372 00000 n 0000508645 00000 n 0000508686 00000 n 0000508936 00000 n 0000924640 00000 n 0000924717 00000 n 0000508977 00000 n 0000509249 00000 n 0000509292 00000 n 0000509541 00000 n 0000509584 00000 n 0000509858 00000 n 0000509899 00000 n 0000510149 00000 n 0000924794 00000 n 0000924871 00000 n 0000924949 00000 n 0000925027 00000 n 0000925100 00000 n 0000925178 00000 n 0000925256 00000 n 0000925334 00000 n 0000925407 00000 n 0000925485 00000 n 0000925558 00000 n 0000925631 00000 n 0000925709 00000 n 0000925787 00000 n 0000925860 00000 n 0000925938 00000 n 0000926016 00000 n 0000926089 00000 n 0000926167 00000 n 0000926245 00000 n 0000926323 00000 n 0000926401 00000 n 0000926474 00000 n 0000926547 00000 n 0000926625 00000 n 0000926703 00000 n 0000926776 00000 n 0000926854 00000 n 0000926932 00000 n 0000927005 00000 n 0000927078 00000 n 0000927151 00000 n 0000927229 00000 n 0000927307 00000 n 0000927385 00000 n 0000927463 00000 n 0000927541 00000 n 0000927619 00000 n 0000927697 00000 n 0000927770 00000 n 0000927848 00000 n 0000927921 00000 n 0000927999 00000 n 0000928077 00000 n 0000928155 00000 n 0000928233 00000 n 0000928311 00000 n 0000928384 00000 n 0000928457 00000 n 0000928535 00000 n 0000928613 00000 n 0000928691 00000 n 0000928770 00000 n 0000928849 00000 n 0000928928 00000 n 0000929007 00000 n 0000929086 00000 n 0000929165 00000 n 0000929244 00000 n 0000929318 00000 n 0000929392 00000 n 0000929466 00000 n 0000929540 00000 n 0000929614 00000 n 0000929688 00000 n 0000929762 00000 n 0000929841 00000 n 0000929920 00000 n 0000929994 00000 n 0000930068 00000 n 0000930147 00000 n 0000930221 00000 n 0000930295 00000 n 0000930374 00000 n 0000930453 00000 n 0000930532 00000 n 0000498684 00000 n 0000498706 00000 n 0000499694 00000 n 0000500716 00000 n 0000500738 00000 n 0000501741 00000 n 0000502940 00000 n 0000502963 00000 n 0000503569 00000 n 0000504514 00000 n 0000504536 00000 n 0000505321 00000 n 0000922825 00000 n 0000923594 00000 n 0000510190 00000 n 0000867689 00000 n 0000930611 00000 n 0000930691 00000 n 0000930771 00000 n 0000930851 00000 n 0000930926 00000 n 0000931001 00000 n 0000931081 00000 n 0000931156 00000 n 0000931231 00000 n 0000931311 00000 n 0000931391 00000 n 0000931467 00000 n 0000931543 00000 n 0000931624 00000 n 0000931700 00000 n 0000887888 00000 n 0000931781 00000 n 0000931857 00000 n 0000931938 00000 n 0000932019 00000 n 0000932100 00000 n 0000932181 00000 n 0000932262 00000 n 0000932343 00000 n 0000932419 00000 n 0000932495 00000 n 0000932576 00000 n 0000932657 00000 n 0000932738 00000 n 0000867714 00000 n 0000932819 00000 n 0000932900 00000 n 0000932981 00000 n 0000933062 00000 n 0000933138 00000 n 0000933214 00000 n 0000933295 00000 n 0000933376 00000 n 0000933457 00000 n 0000933533 00000 n 0000933609 00000 n 0000933690 00000 n 0000933771 00000 n 0000933852 00000 n 0000933933 00000 n 0000934014 00000 n 0000934095 00000 n 0000934171 00000 n 0000934252 00000 n 0000934328 00000 n 0000887864 00000 n 0000903818 00000 n 0000936518 00000 n 0000903842 00000 n 0000912929 00000 n 0000912952 00000 n 0000913157 00000 n 0000913625 00000 n 0000913955 00000 n 0000921880 00000 n 0000921903 00000 n 0000922101 00000 n 0000922510 00000 n 0000922779 00000 n 0000923787 00000 n 0000923846 00000 n 0000923974 00000 n 0000934404 00000 n 0000935474 00000 n 0000936628 00000 n 0000936828 00000 n trailer < <79C41BCC8724F80543CC0978EA541980> ] /DocChecksum /579E040215F59D12D29EFEB0644ABB45 >> startxref 937368 %%EOF O-Saft-22.11.22/o-saft000077500000000000000000000167771433765727300142140ustar00rootroot00000000000000#!/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 # -help got it #? -n just show command to be executed #? -help=* grep for * in 'o-saft.pl --help' # TODO: should also grep in --help=commads and some other programs #? -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 # -prg="program" # use program instead of o-saft.pl; intended for debugging only #? -post="program [options]" #? program in ./contrib to pipe output of o-saft.pl to #? -colour alias for -post=bunt.pl #? -blind alias for -post='bunt.pl --blind' #? -line alias for -post='bunt.pl --line' #? -less pipe output of o-saft.pl to less #? -more pipe output of o-saft.pl to more #? -- 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 #? #? Option +VERSION prints version of this program and not the version #? of o-saft.pl . #? #? Automatic detection of GUI mode fails, if the starter in the desktop's #? panel (or whatever functionality is used) uses a terminal. #? #? EXAMPLES #? $0 +cmd --option target #? $0 -post='bunt.pl' ' +cmd --option target #? $0 -post='bunt.pl -blind' +cmd --option target #? $0 -colour +cmd --option target # same as above #? $0 -gui target # $0 -prd=yeast.pl +cmd 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.26 21/04/16 13:26:57 #? #? 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 # then check (below) if tools exists, if not, remove path and rely on $PATH [ ! -x "$prg" ] && prg=$ich.pl [ ! -x "$gui" ] && gui=$ich.tcl [ ! -x "$cgi" ] && cgi=$ich.cgi [ ! -x "$dok" ] && dok=$ich-docker contrib=$dir/contrib try= post="cat" # default, avoids special handling if -post= missing post_args= # aguments passed to post command, mainly used for -help= such= # text to be searched for passed to post command, mainly used for -help= 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= #dbx# echo "#################" >> /tmp/t.o-saft.log #dbx# [ -t 0 ] &&echo 0 STDIN >> /tmp/t.o-saft.log #dbx# [ -t 1 ] &&echo 1 STDOUT >> /tmp/t.o-saft.log #dbx# [ -t 2 ] &&echo 2 STDERR >> /tmp/t.o-saft.log [ -t 0 ] || mode=gui # no STDIN, assuming start from desktop, hence GUI while [ $# -gt 0 ]; do case "$1" in -help | -h | '-?') \sed -ne "s/\$0/$ich/g" -e '/^#?/s/#?//p' $0 \cat < (grep{/^$_path$/} @INC)); unshift(@INC, "..") if (1 > (grep{/^\.\.$/} @INC)); unshift(@INC, ".") if (1 > (grep{/^\.$/} @INC)); } use OSaft::Text qw(%STR print_pod); use osaft; my $SID_dbx= "@(#) o-saft-dbx.pm 2.24 22/11/05 13:11:14"; #_____________________________________________________________________________ #__________________________________________________________________ methods __| # debug methods sub _yTIME { return "" if (not _is_cfg_out('traceTIME')); my $now = time() - ($time0 || 0); $now = time() if (_is_cfg_out('time_absolut'));# $time0 defined in main $now +=1 if (0 > $now); # fix runtime error: $now == -1 return sprintf(" %02s:%02s:%02s", (localtime($now))[2,1,0]); } sub __yeast { return $cfg{'prefix_verbose'} . $_[0]; } sub ___ARG { return $cfg{'prefix_verbose'} . " ARG: " . join(" ", @_); } sub ___CMD { return $cfg{'prefix_verbose'} . _yTIME() . " CMD: " . join(" ", @_); } sub __line { return "#----------------------------------------------------" . $_[0]; } sub ___ARR { return join(" ", "[", sort(@_), "]"); } sub __INIT { return sprintf("%s%21s= %s", $cfg{'prefix_verbose'}, $_[0], $_[1]); } sub __TRAC { return sprintf("%s%14s= %s", $cfg{'prefix_verbose'}, $_[0], $_[1]); } sub _y_ARG { local $\ = "\n"; print ___ARG(@_) if (_is_cfg_out('traceARG')); return; } sub _y_CMD { local $\ = "\n"; print ___CMD(@_) if (_is_cfg_out('traceCMD')); return; } sub _yeast { local $\ = "\n"; print __yeast($_[0]);return; } sub _yINIT { local $\ = "\n"; print __INIT(@_); return; } sub _yTRAC { local $\ = "\n"; print __TRAC(@_); return; } sub _yline { _yeast(__line($_[0])); return; } sub _ynull { _yeast("value <> means that internal variable is not defined @_"); return; } sub __trac {} # forward declaration sub __trac { #? print variable according its type, understands: CODE, SCALAR, ARRAY, HASH my $ref = shift; # must be a hash reference my $key = shift; my $data = ""; if (not defined $ref->{$key}) { # undef is special, avoid perl warnings return __TRAC($key, "<>"); } SWITCH: for (ref($ref->{$key})) { # ugly but save use of $_ here /^$/ && do { $data .= __TRAC($key, $ref->{$key}); last SWITCH; }; /CODE/ && do { $data .= __TRAC($key, "<>"); last SWITCH; }; /SCALAR/&& do { $data .= __TRAC($key, $ref->{$key}); last SWITCH; }; /ARRAY/ && do { $data .= __TRAC($key, ___ARR(@{$ref->{$key}})); last SWITCH; }; /HASH/ && do { last SWITCH if (2 >= $ref->{'trace'}); # print hashes for full trace only $data .= __yeast("# - - - - HASH: $key = {"); foreach my $k (sort keys %{$ref->{$key}}) { $data .= __TRAC(" ".$key."->".$k, join("-", ${$ref->{$key}}{$k})); # TODO: output needs to be improved }; $data .= __yeast("# - - - - HASH: $key }"); last SWITCH; }; # DEFAULT $data .= __yeast($STR{WARN} . " user defined type '$_' skipped"); } # SWITCH return $data; } # __trac sub _yeast_trac { local $\ = "\n"; my $d = __trac(@_); print $d if ($d !~ m/^\s*$/); return; } #? print variable according its type, understands: CODE, SCALAR, ARRAY, HASH # avoids printing of empty lines sub _yeast_ciphers_list { #? print ciphers fromc %cfg (output optimised for +cipher) return if (0 >= ($cfg{'trace'} + $cfg{'verbose'})); _yline(" ciphers {"); my $_cnt = scalar @{$cfg{'ciphers'}}; my $need = _need_cipher(); my $ciphers = "@{$cfg{'ciphers'}}"; # not yet used _yeast(" _need_cipher= $need"); if (0 < $need) { # avoid printing huge lists my @range; if ($cfg{'cipherrange'} =~ m/(full|huge|long|safe|rfc|intern)/i) { # avoid huge (useless output) $_cnt = 0xffffff; $_cnt = 0x2fffff if ($cfg{'cipherrange'} =~ m/safe/i); $_cnt = 0xffff if ($cfg{'cipherrange'} =~ m/long/i); $_cnt = 0xffff if ($cfg{'cipherrange'} =~ m/huge/i); $_cnt = 2051 if ($cfg{'cipherrange'} =~ m/rfc/i); # estimated count $_cnt = 2640 if ($cfg{'cipherrange'} =~ m/intern/i);# estimated count @range = "<>"; } else { # expand smaller list @range = osaft::get_ciphers_range('TLSv13', $cfg{'cipherrange'}); # NOTE: osaft::get_ciphers_range() first arg is the SSL version, # which is usually unknown here, hence TLSv13 is passed $_cnt = scalar @range; } $_cnt = sprintf("%5s", $_cnt); # format count _yeast("use cipher from openssl= " . $cmd{'extciphers'}); _yeast(" starttls= " . $cfg{'starttls'}); _yeast(" cipherpattern= " . $cfg{'cipherpattern'}); _yeast(" cipherrange= " . $cfg{'cipherrange'}); # format range text foreach my $txt (split(/\n/, $cfg{'cipherranges'}->{$cfg{'cipherrange'}})) { next if $txt =~ m/^\s*$/; $txt =~ s/^\s*/ /; _yeast($txt); } _yeast(" $_cnt ciphers= @range"); } _yline(" ciphers }"); return; } # _yeast_ciphers_list sub _yeast_targets { #? print information about targets to be processed my $trace = shift; my $prefix = shift; my @targets = @_; #print " === print internal data structures for a targets === "; if (0 == $trace) { # simple list printf("%s%14s= [ ", $prefix, "targets"); foreach my $target (@targets) { next if (0 == @{$target}[0]); # first entry conatins default settings printf("%s:%s%s ", @{$target}[2..3,6]); # the perlish way instead of get_target_{host,port,path} } printf("]\n"); } else { printf("%s%14s targets = [\n", $prefix, "# - - - -ARRAY"); printf("%s# Index %6s %24s : %5s %10s %5s %-16s %s\n", $prefix, "Prot.", "Hostname or IP", "Port", "Auth", "Proxy", "Path", "Orig. Parameter"); foreach my $target (@targets) { #next if (0 == @{$target}[0]); # first entry conatins default settings printf("%s [%3s] %6s %24s : %5s %10s %5s %-16s %s\n", $prefix, @{$target}[0,1..7]); } printf("%s%14s ]\n", $prefix, "# - - - -ARRAY"); } return; } # _yeast_targets sub _yeast_init { ## no critic qw(Subroutines::ProhibitExcessComplexity) #? print important content of %cfg and %cmd hashes #? more output if 1= ($cfg{'trace'} + $cfg{'verbose'})); local $\ = "\n"; my $arg = " (does not exist)"; ## no critic qw(Variables::ProhibitPackageVars); they are intended here 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'}); _ynull(); _yeast("#") if (3 > $cfg{'trace'}); _yline(""); _yTRAC("_yeast_init::SID", $SID_dbx) if (2 > $cfg{'trace'}); _yTRAC("$0", _VERSION()); # $0 is same as $ARG0 # official VERSIONs, not those of the current files ! _yTRAC("::osaft", $osaft::VERSION); _yTRAC("Net::SSLhello", $Net::SSLhello::VERSION) if defined($Net::SSLhello::VERSION); _yTRAC("Net::SSLinfo", $Net::SSLinfo::VERSION); # quick info first _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{'out'}->{'traceARG'}, traceCMD=$cfg{'out'}->{'traceCMD'}, traceKEY=$cfg{'out'}->{'traceKEY'}, traceTIME=$cfg{'out'}->{'traceTIME'}"); _yTRAC("time_absolut", $cfg{'out'}->{'time_absolut'}); _yTRAC("dbx{file}", "[ " . join(", ", @{$dbx{'file'}}) . " ]"); 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 }"); } _yline(" %cmd {"); if (2 > $cfg{'trace'}) { # user friendly information _yeast(" path= " . ___ARR(@{$cmd{'path'}})); _yeast(" libs= " . ___ARR(@{$cmd{'libs'}})); _yeast(" envlibvar= $cmd{'envlibvar'}"); _yeast(" timeout= $cmd{'timeout'}"); _yeast(" openssl= $cmd{'openssl'}"); } else { # full information foreach my $key (sort keys %cmd) { _yeast_trac(\%cmd, $key); } } _yeast(" extopenssl= $cmd{'extopenssl'}"); # user friendly always _yeast("use cipher from openssl= $cmd{'extciphers'}"); # dito. _yline(" %cmd }"); if (1 < $cfg{'trace'}) { # full information _yline(" complete %cfg {"); foreach my $key (sort keys %cfg) { if ($key =~ m/(hints|openssl|ssleay|sslerror|sslhello|regex|^out|^use)$/) { # |data # TODO: ugly data structures ... should be done by _yTRAC() _yeast("# - - - - HASH: $key = {"); foreach my $k (sort keys %{$cfg{$key}}) { if ($key =~ m/openssl/) { _yTRAC($k, ___ARR(@{$cfg{$key}{$k}})); } else { #_yTRAC($k, $cfg{$key}{$k}); _yeast_trac($cfg{$key}, $k); }; }; _yeast("# - - - - HASH: $key }"); } else { if ($key =~ m/targets/) { # TODO: quick&dirty to get full data _yeast_targets($cfg{'trace'}, $cfg{'prefix_verbose'}, @{$cfg{'targets'}}); } else { if ("time0" eq $key and defined $ENV{'OSAFT_MAKE'}) { # SEE Make:OSAFT_MAKE (in Makefile.pod) my $t0 = $cfg{'time0'}; $cfg{'time0'} = $STR{MAKEVAL}; _yeast_trac(\%cfg, $key); $cfg{'time0'} = $t0; } else { _yeast_trac(\%cfg, $key); } } } } _yline(" %cfg }"); return; } # else user friendly information my $sni_name = $cfg{'sni_name'} || "<>"; # default is Perl's undef my $port = $cfg{'port'} || "<>"; # default is Perl's undef _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{'use'}->{'forcesni'}, sni_name=$sni_name"); _yeast(" default port= $port (last specified)"); _yeast_targets($cfg{'trace'}, $cfg{'prefix_verbose'}, @{$cfg{'targets'}}); _yeast(" use->http= $cfg{'use'}->{'http'}"); _yeast(" use->https= $cfg{'use'}->{'https'}"); _yeast(" out->hostname= $cfg{'out'}->{'hostname'}"); _yeast(" out->header= $cfg{'out'}->{'header'}"); foreach my $key (qw(format legacy starttls starttls_delay slow_server_delay cipherrange)) { _yTRAC($key, $cfg{$key}); } _yeast(" cipher= " . ___ARR(@{$cfg{'cipher'}})); foreach my $key (qw(starttls_phase starttls_error)) { _yeast( "$key= " . ___ARR(@{$cfg{$key}})); } _yeast(" SSL version= " . ___ARR(@{$cfg{'version'}})); printf("%s",__TRAC("SSL versions", "[ ")); # no \n ! printf("%s=%s ", $_, $cfg{$_}) foreach (@{$cfg{'versions'}}); printf("]\n"); _yeast(" special SSLv2= null-sslv2=$cfg{'use'}->{'nullssl2'}, ssl-lazy=$cfg{'use'}->{'ssl_lazy'}"); _yeast(" ignore output= " . ___ARR(@{$cfg{'ignore-out'}})); _yeast(" user commands= " . ___ARR(@{$cfg{'commands_usr'}})); _yeast("given commands= " . ___ARR(@{$cfg{'done'}->{'arg_cmds'}})); _yeast(" commands= " . ___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_list() return; } # _yeast_init sub _yeast_exit { #? print collected just be program exit if (0 < $cfg{'trace'}) { _yTRAC("cfg'exitcode'", $cfg{'use'}->{'exitcode'}); _yTRAC("exit status", (($cfg{'use'}->{'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 my $label = sprintf(" %-10s=", $key); if ('arg_cmds' eq $key) { _y_CMD("$label\t[" . join(" ", @{$cfg{'done'}->{$key}}) . "]"); } else { _y_CMD("$label\t" . $cfg{'done'}->{$key}); } } _y_CMD('@cfg{done} }'); return; } # _yeast_exit sub _yeast_args { #? print information about command line arguments return if (not _is_cfg_out('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= " . ___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= " . ___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= ". ___ARR(@{$dbx{file}})); _y_ARG("processed exec arguments= ". ___ARR(@{$dbx{exe}})); _y_ARG("processed normal arguments= ". ___ARR(@{$dbx{argv}})); _y_ARG("processed config arguments= ". ___ARR(map{"`".$_."'"} @{$dbx{cfg}})); _y_ARG(" #--v }"); } _yline(" ARGV }"); return; } # _yeast_args sub _yeast_rcfile { #? print content read from RC-FILE ## NOT YET USED ## return if (0 >= ($cfg{'trace'} + $cfg{'verbose'})); _yline(" RC-FILE {"); _yline(" RC-FILE }"); return; } # _yeast_rcfile { 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 (_is_cfg_out('traceCMD')); return; } sub _vprintme { #? write own version, command-line arguments and date and time 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'}})); if (defined $ENV{'OSAFT_MAKE'}) { # SEE Make:OSAFT_MAKE (in Makefile.pod) _yeast("$0 dd.mm.yyyy HH:MM:SS (OSAFT_MAKE exists)"); } else { _yeast("$0 " . sprintf("%02s.%02s.%s %02s:%02s:%02s", $mday, ($mon +1), ($year +1900), $h, $m, $s)); } return; } # _vprintme #_____________________________________________________________________________ #_________________________________________________________ internal methods __| # subs for formatted table sub __data { return (_is_member(shift, \@{$cfg{'commands'}}) > 0) ? "*" : "?"; } sub __data_title{ return sprintf("=%19s %s %s %s %s %s %s %s", @_); } sub __data_head { return __data_title("key", "command", " %data ", "%checks", "cmd-ch.", "short ", "intern ", " score"); } sub __data_line { return sprintf("=%19s+%s+%s+%s+%s+%s+%s+%s", "-"x19, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7, "-"x7); } sub __data_data { return sprintf("%20s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", @_); } # subs for fomated maps sub __prot_option { my $data; foreach my $key (sort keys %{$cfg{'openssl_option_map'}}) { $data .= __trac(\%{$cfg{'openssl_option_map'}}, $key) . "\n"; } chomp $data; # remove last \n return $data; } # __prot_option sub __prot_version { my $data; foreach my $key (sort keys %{$cfg{'openssl_version_map'}}) { $data .= __yeast(sprintf("%14s= ", $key) . sprintf("0x%04X 0x%08x", ${$cfg{'openssl_version_map'}}{$key}, ${$cfg{'openssl_version_map'}}{$key}) ) . "\n"; } chomp $data; # remove last \n return $data; } # __prot_version #_____________________________________________________________________________ #____________________________________________________ internal test methods __| sub _yeast_test_help { local $\ = "\n"; printf("#%s:\n", (caller(0))[3]); print " === commands for internal testing === = = Print list of commands for internal testing/information. = = command/option prints this information = ----------------+---------------------------------------------- = --tests this text = --test-init data structure %cfg after initialisation = --test-data overview of all available commands and checks = --test-maps internal data strucures '%cfg{openssl}', '%cfg{ssleay}' = --test-prot internal data according protocols = --test-regex results for applying various texts to regex = --test-memory overview of variables' memory usage = --test-methods available methods for openssl in Net::SSLeay = --test-sclient available options for 'openssl s_client' from Net::SSLeay = --test-sslmap constants for SSL protocols from Net::SSLeay = --test-ssleay information about Net::SSLeay capabilities = --test-ciphers-* various ciphers listings; available with o-saft.pl only = ----------------+---------------------------------------------- ="; # o-saft.tcl --test-o-saft # just for completeness, not used here # NOTE: description above should be similar to those in # OSaft/Doc/help.txt return $data; } # _yeast_test_help sub _yeast_test_data { local $\ = "\n"; printf("#%s:\n", (caller(0))[3]); print " === internal data structure: overview of commands, %data and %checks === = = Print a simple overview of all available commands for +info and +check . = The purpose is to show if a proper key is defined in %data and %checks for = each command from %cfg{'commands'} and vice versa. = = column description = ------------+-------------------------------------------------- = key key in %cfg{'commands'} = command key (see above) available as command: +key = data command returns %data (part of +info) = checks command returns %check (part of +check) = cmd-ch. command listed in ... = short desciption of command available as short text = intern internal command only, not avaialable as +key = ------------+-------------------------------------------------- ="; my $old; my @yeast = (); # list of potential internal, private commands my $cmd = " "; print __data_head(); print __data_line(); $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); # probably internal command next; } $cmd = "+" if (0 < _is_member($key, \@{$cfg{'commands'}})); # command available as is $cmd = "-" if ($key =~ /$cfg{'regex'}->{'SSLprot'}/i); # all SSL/TLS commands are for checks only print __data_data( #__/--- check value -------\ true : false # column $key, $cmd, (defined $data{$key}) ? __data( $key) : " ", # data (defined $checks{$key}) ? "*" : " ", # checks ((_is_member($key, \@{$dbx{'cmd-check'}}) > 0) || ($key =~ /$cfg{'regex'}->{'SSLprot'}/i)) ? "*" : "!", # cmd-ch. (defined $shorttexts{$key}) ? "*" : " ", # short (_is_cfg_intern($key)) ? "I" : " ", # intern (defined $checks{$key}->{score}) ? $checks{$key}->{score} : ".", ); } # FIXME: @{$dbx{'cmd-check'}} is incomplete when o-saft-dbx.pm is require'd in # main; some checks above then fail (mainly those matching # $cfg{'regex'}->{'SSLprot'}, hence the dirty additional # || ($key =~ /$cfg{'regex'}->{'SSLprot'}/) # print __data_line(); print __data_head(); print "= = + command (key) present = I command is an internal command or alias (ok in column 'intern') = - command (key) used internal for checks only (ok in column 'command') = * 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_* = = Internal or summary commands: = " . join(" ", @yeast) . "\n"; return; } # _yeast_test_data sub _yeast_test_init { local $\ = "\n"; local $Data::Dumper::Deparse=1; # parse code, see man Data::Dumper my $line = "#--------------------+-------------------------------------------"; printf("#%s:\n", (caller(0))[3]); print " === internal data structure: initialisation of %cfg, %data and %checks === = = Print initialised data structure %data and %checks after all command-line = options have been applied. = "; #ah not ok: use Sub::Identify ':all'; _yline(" %cfg {"); # only data which influences initialisations print __yeast("# key | value"); print __yeast($line); print __INIT("ARGV", ___ARR(@{$cfg{'ARGV'}})); _yline(" %cfg{use} {"); foreach my $key (sort keys %{$cfg{'use'}}) { print __INIT($key, $cfg{'use'}{$key}); } _yline(" %cfg{use} }"); print __yeast($line); _yline(" %cfg }"); _yline(" %data {"); print __yeast("# key | value (function code)"); print __yeast($line); foreach my $key (sort keys %data) { # ugly and slow code # use Dumper() to get code, returns something like: # $VAR1 = sub { # package OSaft::Data; # use warnings; # use strict; # Net::SSLinfo::version($_[0], $_[1]); # }; # the line with "package" occours only if the data is in another namespace # we only want the code line, hence remove the others my $code = Dumper($data{$key}->{val}); $code =~ s/^\$VAR.*//; $code =~ s/(?:};)?\s*$//g; $code =~ s/package\s*.*;//g; $code =~ s/use\s*(?:strict|warnings);//g; $code =~ s/\n//g; $code =~ s/^\s*//g; print __INIT($key, $code); } print __yeast($line); _yline(" %data }"); _yline(" %checks {"); print __yeast("# key | value"); print __yeast($line); foreach my $key (sort keys %checks) { print __INIT($key, $checks{$key}->{val}); } print __yeast($line); _yline(" %checks }"); return; } # _yeast_test_init sub _yeast_test_maps { printf("#%s:\n", (caller(0))[3]); print " === internal data structure %cfg{openssl}, %cfg{ssleay} === = = Print internal mappings for openssl functionality (mainly options). = "; local $\ = "\n"; my $data = Net::SSLinfo::test_sslmap(); $data =~ s/^#/#$cfg{'me'}/smg; print $data; _yline(" %cfg{openssl_option_map} {"); print __prot_option(); _yline(" %cfg{openssl_version_map} {"); print __prot_version(); return; } # _yeast_test_maps sub _yeast_test_prot { printf("#%s:\n", (caller(0))[3]); print " === internal data structure according protocols === = = Print information about SSL/TLS protocols in various internal variables. = "; local $\ = "\n"; my $ssl = $cfg{'regex'}->{'SSLprot'}; _ynull("\n"); _yline(" %cfg {"); foreach my $key (sort keys %cfg) { # targets= is array of arrays, prints ARRAY ref here only _yeast_trac(\%cfg, $key) if ($key =~ m/$ssl/); } _yline(" }"); _yline(" %cfg{openssl_option_map} {"); print __prot_option(); _yline(" }"); _yline(" %cfg{openssl_version_map} {"); print __prot_version(); _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_test_prot sub _yeast_test_methods { printf("#%s:\n", (caller(0))[3]); print " === internal list of methods to call openssl === = = Print available methods in Net::SSLeay. = "; my $list = Net::SSLinfo::test_methods(); $list =~ s/ /\n# /g; print "# $list"; return; } # _yeast_test_methods sub _yeast_test_sclient { printf("#%s:\n", (caller(0))[3]); print " === internal list of openssl s_client options === = = Print available options for 'openssl s_client' from Net::SSLeay. = "; my $list = Net::SSLinfo::test_sclient(); $list =~ s/ /\n# /g; print "# $list"; return; } # _yeast_test_sclient sub _yeast_test_sslmap { printf("#%s:\n", (caller(0))[3]); print " === internal list of constants for SSL protocols === = = Print available constants for SSL protocols in Net::SSLeay. = "; print Net::SSLinfo::test_sslmap(); return; } # _yeast_test_sslmap sub _yeast_test_ssleay { printf("#%s:\n", (caller(0))[3]); print " === internal data of from Net::SSLeay === = = Print information about Net::SSLeay capabilities. = "; print Net::SSLinfo::test_ssleay(); return; } # _yeast_test_ssleay sub _yeast_test_memory { #? print overview of memory usage of variables # This is not part of the functionality of O-Saft itself, but more like # a quality or performance check. # I.g. it should be implemented in makefiles or alike, but is done here # in the source because the variables are avaiable in the source only. printf("#%s:\n", (caller(0))[3]); require Devel::Size; # require instead of use to avoid dependencies (i.e. in checkAllCiphers.pl) my %types = ( # TODO: not yet used 'ARRAY' => '@', 'CODE' => '{', 'FORMAT' => '#', 'GLOB' => '*', 'HASH' => '%', 'IO' => '&', 'LVALUE' => '=', 'REF' => '\\', 'REGEXP' => '/', 'SCALAR' => '$', 'VSTRING' => '"', ); print " === memory usage of internal variables === = = Use --v to get more details. = "; if (0 < ($cfg{'trace'} + $cfg{'verbose'})){ foreach my $k (keys %cfg) { printf("%6s\t%s\n", Devel::Size::total_size(\$cfg{$k}), "%cfg{$k}"); } foreach my $k (keys %checks) { printf("%6s\t%s\n", Devel::Size::total_size(\$checks{$k}), "%checks{$k}"); } #foreach my $k (keys %ciphers) { # useless, as each entry is about 2k # printf("%6s\t%s\n", Devel::Size::total_size(\$ciphers{$k}), "%ciphers{$k}"); #} foreach my $k (keys %dbx) { printf("%6s\t%s\n", Devel::Size::total_size(\$dbx{$k}), "%dbx{$k}"); } #foreach my $k (keys %data) { # most entries report 42k, which is wrong # printf("%6s\t%s\n", Devel::Size::total_size(\$data{$k}), "%data{$k}"); #} } my $bytes = 0; my $line = "=------+----------------"; # get all global variables and grep for our ones # ugly code, but generic print "= Bytes variable\n$line"; foreach my $v (sort keys %main::) { #print Dumper $v; # liefert den gesamten Hash next if ("*{$main::{$v}}" !~ m/\*main::/); next if ($main::{$v} =~ m/::$/); # avoid "Segmentation fault" next if (not grep {/^(cfg|check|cipher|cmd|data|dbx|info|osaft|short|text)/} $v) ; next if ( grep {/^check(cipher|http)/} $v) ; # avoid "Segmentation fault" # TODO: my $typ = ref($main::{$v}); # not yet working #dbx print "K $v $main::{$v} => $t"; my $size = Devel::Size::total_size(\$main::{$v}); $bytes += $size; printf("%7s\t%s\n", $size, $v);#if (exists $main::{$v}); } print "$line"; printf("%7s\t(%2.2f MB) total\n", $bytes, $bytes/1024/1024); # the traditional way ... #print "%cfg : ", Devel::Size::total_size(\%cfg); #print "%data : ", Devel::Size::total_size(\%data); #print "%checks : ", Devel::Size::total_size(\%checks); #print "%ciphers: ", Devel::Size::total_size(\%ciphers); #print "\@results: ", Devel::Size::total_size(\@cipher_results); #print "%text : ", Devel::Size::total_size(\%text); #print "%_SSLinfo : ", Devel::Size::total_size(\%Net::SSLinfo::_SSLinfo); return; } # _yeast_test_memory sub _yeast_test { #? dispatcher for internal tests, initiated with option --test-* my $arg = shift; # normalised option, like --testinit, --testcipherlist _yeast($arg); OSaft::Ciphers::show($arg) if ($arg =~ /^--test[._-]?cipher/); _yeast_test_help() if ('--test' eq $arg); _yeast_test_help() if ('--tests' eq $arg); _yeast_test_sclient() if ('--testsclient' eq $arg); # Net::SSLinfo _yeast_test_ssleay() if ('--testssleay' eq $arg); # Net::SSLinfo _yeast_test_sslmap() if ('--testsslmap' eq $arg); # Net::SSLinfo _yeast_test_methods() if ('--testmethods' eq $arg); # Net::SSLinfo _yeast_test_memory() if ('--testmemory' eq $arg); $arg =~ s/^[+-]-?tests?[._-]?//; # remove --test osaft::test_cipher_regex() if ('regex' eq $arg); _yeast_test_data() if ('data' eq $arg); _yeast_test_init() if ('init' eq $arg); _yeast_test_maps() if ('maps' eq $arg); _yeast_test_prot() if ('prot' eq $arg); $arg =~ s/^ciphers?[._-]?//; # allow --test-cipher* and --test-cipher-* OSaft::Ciphers::show($arg) if ($arg =~ /^cipher/); # allow --test-cipher* and cipher-* if ('list' eq $arg) { # _yeast_ciphers_list() relies on some special $cfg{} settings # enforce printing cipher information by adding +cipher, this # should not harm other functionality, as _yeast_test() is for # debugging only and will exit then $cfg{'verbose'} = 1; push(@{$cfg{'do'}}, 'cipher'); # enforce printing cipher informations push(@{$cfg{'version'}}, 'TLSv1') if (0 > $#{$cfg{'version'}}); _yeast_ciphers_list(); } return; } # _yeast_test #_____________________________________________________________________________ #_____________________________________________________________________ main __| sub _main_dbx { my $arg = shift || "--help"; # without argument print own help ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # see t/.perlcriticrc for detailed description of "no critic" # SEE Perl:binmode() binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); print_pod($0, __FILE__, $SID_dbx) if ($arg =~ m/--?h(elp)?$/x); # print own help # else # ----------------------------- commands if ($arg eq 'version') { print "$SID_dbx\n"; exit 0; } if ($arg =~ m/^[-+]?V(ERSION)?$/) { print "$VERSION\n"; exit 0; } if ($arg =~ m/--tests?$/) { _yeast_test_help(); exit 0; } if ($arg =~ m/--(yeast|test)[_.-]?(.*)/) { $arg = "--test-$2"; printf("#$0: direct testing not yet possible, please try:\n o-saft.pl $arg\n"); } exit 0; } # _main_dbx sub dbx_done {}; # dummy to check successful include #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME o-saft-dbx.pm - module for tracing o-saft.pl =head1 SYNOPSIS =over 2 =item require "o-saft-dbx.pm"; =item o-saft-dbx.pm > =back =head1 OPTIONS =over 2 =item --help =item --tests List available commands or options for internal testing. =item --test-ciphers-list =item --test-ciphers-show =item --test-ciphers-sort =item --test-ciphers-overview =item --test-regex =item --test-data =item --test-init =item --test-maps =item --test-prot See I<--tests> for description of these options. =back =head1 DESCRIPTION Defines all functions needed for trace and debug output in L. =head1 METHODS =head2 Functions defined herein =over 4 =item _yeast_ciphers_list( ) =item _yeast_trac( ) =item _yeast_init( ) =item _yeast_exit( ) =item _yeast_args( ) =item _yeast( ) =item _y_ARG( ), _y_CMD( ), _yline( ) =item _vprintme( ) =item _v_print( ), _v2print( ), _v3print( ), _v4print( ) =item _trace( ), _trace1( ), _trace2( ), _trace_cmd( ) =back =head2 Functions for internal testing; initiated with option C<--test-*> =over 4 =item _yeast_test_help( ) =item _yeast_test_data( ) =item _yeast_test_init( ) =item _yeast_test_maps( ) =item _yeast_test_prot( ) =item _yeast_test_methods( ) =item _yeast_test_sclient( ) =item _yeast_test_sslmap( ) =item _yeast_test_ssleay( ) =item _yeast_test( ) =back =head2 Variables which may be used herein They must be defined as `our' in L: =over 4 =item $SID_main =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 should 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. =head1 VERSION 2.24 2022/11/05 =head1 AUTHOR 13-nov-13 Achim Hoffmann =cut ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main_dbx(@ARGV) if (not defined caller); 1; O-Saft-22.11.22/o-saft-docker000077500000000000000000000565061433765727300154530ustar00rootroot00000000000000#!/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 #? -h got it # -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 -h 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. #? The option +VERSION is not supported for this tool, it's passed to #? the Docker image. #? 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.44 22/04/22 22:22:10 #? #? AUTHOR #? 17-jul-17 Achim Hoffmann #? # ----------------------------------------------------------------------------- VERSION="${OSAFT_VERSION:-19.01.19}" 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 '-h' | '-?' | '-help') my_help; exit 0; ;; '-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=\(.*\)'`"; ;; *) 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-22.11.22/o-saft-docker-dev000077500000000000000000000556321433765727300162260ustar00rootroot00000000000000#!/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 #? @(#) 1.7 19/08/01 16:34:26 #? #? AUTHOR #? 17-jul-17 Achim Hoffmann #? # ----------------------------------------------------------------------------- try= cmd=unknown VERSION="${OSAFT_VERSION:-19.01.19}" 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%d%"H%"M%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="29d4faa2ed3025ed18d31175e868d6be9312b36ba486c6e5f305afeb34947f68" 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-22.11.22/o-saft-img.tcl000066400000000000000000001246611433765727300155340ustar00rootroot00000000000000#!/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.9 21/01/14 01:15:39 #? AUTHOR #? Copyright (c) 2021, Achim Hoffmann #? 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 }]; # docker_status_99x29_magenta.png set IMG(docker_status) [image create photo -data { iVBORw0KGgoAAAANSUhEUgAAAGMAAAAUCAYAAACZHIPsAAAHkUlEQVRYhe2Za2xU1RbHf/vMmUfb GWlpKSAzoaVPaG1rpCnlIvXRmBSURJT6oWqM1kdAcoOE+gANml5uboLGRIPGoMZEEhNBI7ZKq40p l5sKfSDwgbY01oIaCk1J23nP2efcD2dm2iGlcBO4vbnwT07OmbPXf+3/7LXWXmfmCMMwABCwFtgM lAHzuYUbjWHgONBowL8AhGEYWDTt78Arsyrt5sYrUlX/IdRgcC3QNNtqbnJIYIWqaNqm2VZyC1iA rcIxNjYMZE5nIZuaiNTVISoqsLe2XpdZg7m5cPEito4OlGXLrovP/xOcUxVNmzYQALqUAAjDQNG0 6zqzIuV19/mfwAgGCTc0oG7YgOXuu2847xrgUWdaECWu4PoFQwAGIDRtVoMROXgQuW8fakkJSmXl DeddCxRFSmKH0d9PYO1avG43/tWrMQYGAHMBYzZibIzQtm34iorwejz477sP+fXXTPUTtykuxut2 41u+HO2jj1CkhOijtKLrKFIim5vxLliAb+lSGBiY5G/dim/pUrzZ2QRqatDb2+P+fUVFBGpqME6c wF9djdfjQQQCCRoUKdH27sVfWYnX48FXXEzwqadgaAi5fz+hhgYAQi+/jHf+fMJvvGHq+eEHAg8/ bM6dlYW/uhr5/ffm2Aw8b1YW3vnz499BkRLvwoXmvXPnZtQTs0+oDN+mTciTJxEZGQiXi9CuXebA lMrwbdlCpLkZkZmJetddaF1dBF54AaHr2B58MNEmLQ21ogLZ14ewWhMqQZESvbOTwMaNYLOR8vHH qB4PaFqcr65ahaWoiPAXX+Cvq8N16BCWvDwA5KlT+J94AmN4GJGWhkVRYIp/raeH4Pbt4HRiq61F P38e2dODJTUVGQigpKWhT0ygrlyJUliItbwcRdNQgkH0gQHUqiqEqhI+cIDAc8+htrXBDLwYxDTb ryIl+rFjV9QjovaqEu0L2unTyJMnwWZjzrffoixYQOC99wi8847ZM6RE/vYbkeZmsNuZ8913KOnp BPftw79jB6H338dRU4McGjJtrFZua2rCcvvtGLoOUiKicwEwMoJv0yYIhXDu2YOtrAykjPNFRgau Tz9FqCqWxYvxv/Yakf37sUYzk0gES04OzqYmlIwMmOob4MIFc3FSUnDU1qLecQeGlAiLhaRHHkFr aUE/exbbmjU46upMjpTY778fW0cHQjE36YkLF4i0t6N3d8/Im7rwymVaFCnRZ9AT48crwxgcNG8U FqJmZICmYVuxgsCUyoj09Zk2eXmoc+aApmFfsQI/IHt7EeEwem8vAJa8PKyZmZPZKoR5Hd2m/K+/ jjE6iq2mBkd1ddxOi85hjIxwKVoFMehDQ2bWRX2kbNyImpqaUBEx2MrLsWRnIwcHGV+3DmtFBckN DVhLSkw5um6eL8vk8JEjBD75BHnmDProKITD5sDYGIqmXZGXEIzL7gtNu6oeADVWIrEzihK/FkKY 9wwDoWmIUCjhcwLPakVIiYiKF0JMjk0DefYsJCcTbm1F6+7GWlpquvZ6TRmLFpH8/PMJHIvbneBT cbmuOIfF4SD1yy8JfP45gc8+I3L0KGOPP87cb77B4vHEAyp0Pe5D+/VXxp99FgyDlM2bUUtK8H/w AZHOzkm7aXgJiEQQmobh88GUwF1VD1MauLpokSmorw9GR81t6fhx0xlmxK35+abNmTMYw8MoUhL5 +WcA1JwcLLqO6nabNv39GH/+aTbkSATj99/N66jm1HffxdXQAFIysW0bTEygSIktN9cMyugoSffc Q8r69aSsX0/yunXYS0oSfMQeAqY7hM+H6nDgqq9nXksLalERBAJonZ3muKqaTsbH4xx54gRoGmpB Ac76euzl5eiXLsUX/0o8RUqUlBRTd7QhR44cmUyaa9CT0MDtubmo+flo/f2MPvoo6pIlhHt6TG/R bcq2cCGOBx4g2NrK6IYNqDk5hLu7AXDV16NoGvYlS7CWlRH55RfTT0EB2uAgyQ89hOvFF+OZpWZm krRyJaGWFsIdHXgbG0l96y1sixdjr6oi1N7O6GOPYV+1Cn1ignBnJ2m7d2O7887J7Jzht4r/0CG8 H36IrawM4XIhz50DwJadjaJpWLOyCAG+vXuJHDuGWliIY/VqM5F6exnfvh35xx9mBceCcQXebZs3 YystJdjWxvirr2ItKiLc1QXRfqBISegqehIqQ5GSuY2NWJctQ168iD4yQvqePQiHI97AFSmZ++ab OJ98EoBwVxeq203qzp0kV1XFbdJ37yZpzRqwWAh3dqIkJWEvLU1obDHbtB07EE4ngYMHCbW0mPxd u8w5dB3/gQOEDh/Gmp+Pmpk5rY/pDpvbjZKcTLCtDf9XX2GZN4/UnTuxFxSgSImzthZ7ZSVEIoRP ncKSlISjuBjXM88gnE6Cra1Y0tNJf/vthMqYjqdIyZyXXsJeWYkRDBI5fRrn00+THH26vBY9ipQI z9Gj57n1l/n/AvpURdO6MN9l3MLsolNkHz68EjgC8b54C/99hIESYRgGuT/91AD8DVBnWdTNiDDw 14F77/1QxF675v/443JgC/AXYPEsirtZMAT8E2jsr67uA/g3Hn5bxP6TF9AAAAAASUVORK5CYII= }]; O-Saft-22.11.22/o-saft-man.pm000077500000000000000000003626101433765727300153660ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) 2022, Achim Hoffmann #!# This software is licensed under GPLv2. Please see o-saft.pl for details. package main; # ensure that main:: variables are used ## 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(Documentation::RequirePodSections) # Perl::Critic is uses a strange list of required sections in POD. # See t/.perlcriticrc . ## no critic qw(Variables::ProhibitPunctuationVar) # We want to use $\ $0 etc. ## no critic qw(Variables::ProhibitPackageVars) ## no critic qw(ControlStructures::ProhibitPostfixControls Modules::RequireVersionVar) ## no critic qw(RegularExpressions::RequireDotMatchAnything RegularExpressions::RequireLineBoundaryMatching) ## no critic qw(ValuesAndExpressions::ProhibitEmptyQuotes RegularExpressions::ProhibitFixedStringMatches) ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers ValuesAndExpressions::RequireUpperCaseHeredocTerminator) ## no critic qw(ValuesAndExpressions::ProhibitNoisyQuotes ) ## no critic qw(BuiltinFunctions::ProhibitBooleanGrep BuiltinFunctions::ProhibitStringySplit) # Keep severity 2 silent. # NOTE: Modules::RequireVersionVar fails because the "no critic" pragma is to late here. use strict; use warnings; use vars qw(%checks %data %text); ## no critic qw(Variables::ProhibitPackageVars) use utf8; # binmode(...); # inherited from parent BEGIN { # SEE Perl:BEGIN perlcritic # SEE Perl:@INC my $_me = $0; $_me =~ s#.*[/\\]##; my $_path = $0; $_path =~ s#[/\\][^/\\]*$##; unshift(@INC, $_path) if (1 > (grep{/^$_path$/} @INC)); unshift(@INC, "..") if (1 > (grep{/^\.\.$/} @INC)); unshift(@INC, ".") if (1 > (grep{/^\.$/} @INC)); } use OSaft::Text qw(%STR print_pod); use osaft; use OSaft::Doc::Data; use OSaft::Ciphers; # required if called standalone only my $SID_man= "@(#) o-saft-man.pm 2.84 22/11/21 18:46:50"; 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=~ s:^.{5}::; # remove leading @(#) as already part of the *.txt files $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|o-saft|checkAllCiphers.pl)/;# regex for our tool names my @help = OSaft::Doc::Data::get_markup("help.txt", $parent, $version); our $VERBOSE = 0; # >1: option --v $VERBOSE++ if (0 < $cfg{'verbose'});# if called via o-saft.pl # VERBOSE instead of verbose because of perlcritic local $\ = ""; # SEE Note:Stand-alone $::osaft_standalone = 0 if not defined $::osaft_standalone; ## no critic qw(Variables::ProhibitPackageVars) #_____________________________________________________________________________ #_____________________________________________ texts for user documentation __| # Following texts are excerpts or abstracts of the user documentation defined # in OSAFT/Doc/help.txt . # Currently (2021) it is difficult to extract them programmatically from that # file. For better maintenance, they are defined here as internal variables. # TODO needs to be computed from OSAFT/Doc/help.txt, somehow ... my $_cmd_brief = <<'EoBrief'; +info Overview of most important details of the SSL connection. +cipher Check target for ciphers (using libssl). +check Check the SSL connection for security issues. +protocols Check for protocols supported by target. +vulns Check for various vulnerabilities. EoBrief my $_commands = <<'EoCmds'; 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. +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. EoCmds my $_voodoo = <<'EoHelp'; # begin voodoo # 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. # These 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 voodoo EoHelp #_____________________________________________________________________________ #____________________________________________________________ HTML snippets __| my %html = ( 'title' => 'O - S a f t -- OWASP - SSL advanced forensic tool', 'nonce' => '4f2d53616674', 'script_nonce' => ' EoFUNC 'script_endcgi' => << 'EoFUNC', EoFUNC 'style_root' => << 'EoROOT', /* variable definitions */ :root { /* color and background */ --bg-osaft: #fff; --bg-black: #000; --bg-blue: #226; /* darkblue */ --bg-head: linear-gradient(#000,#fff); /* black,white */ --bg-menu: linear-gradient(#000,#aaa); /* black,grey */ --bg-mbox: rgba(0,0,0,0.9); --bg-mdiv: linear-gradient(#fff,#226); --bg-button: linear-gradient(#d3d3d3,#fff); /* lightgray */ --bg-start: linear-gradient(#ffd700,#ff0); /* gold */ --bg-start-h: linear-gradient(#ff0,#ffd700); /* gold */ --bg-hover: #d3d3d3; /* lightgray */ --bg-literal: #d3d3d3; /* lightgray */ --border-0: 0px solid #fff; --border-1: 1px solid #000; /* black */ --border-w: 1px solid #fff; /* white */ --radius-10: 0px 10px 10px 10px; --radius-20: 0px 0px 20px 20px; --shadow: 1px 4px 4px #666; } EoROOT 'style_button' => << 'EoButton', [type=submit] { /* submit/start buttons */ text-align: left; font-size: 80%; font-weight: bold; min-width: 10em; background: var(--bg-start); box-shadow: var(--shadow); border: var(--border-1); border-radius: 4px; } [type="submit"]:hover { background:var(--bg-start-h); } .navdiv div a, .b { /* help buttons */ display: block; margin: 0.2em; padding: 0px 0.2em 0px 0.2em; text-decoration:none; font-size: 90%; font-weight: bold; color: #000; background: var(--bg-button); box-shadow: var(--shadow); border: var(--border-1); border-radius: 4px; } .b { display: inline-block; } /* ^top and start button */ EoButton 'style' => << 'EoSTYLE', body { margin:0px 0.5em 0px 0.5em; background:#f2eff2; font: 16pt Arial, Helvetica, sans-serif; } /* { page header */ body > h2 { margin: 0px -0.3em 0px -0.3em; padding:1em; background:var(--bg-head);color:white;border-radius:var(--radius-20); } body > h2 > span { margin-bottom:2em;font-size:120%;border:var(--border-0);} /* } page header */ /* { help page only */ h3, h4, h5 { margin-bottom: 0.2em; } body > h3 { margin-top: 1.2em; } body h4 { margin-left: 1em; } /* mainly +cmd and --opt */ /* } help page only */ /* { cgi page only */ body h4 [class="i"] {margin-left: -1em; } /* mainly +cmd and --opt */ fieldset { margin: 0px; } fieldset > details:nth-child(2) > div { z-index:2; } /* "Simple GUI" on top */ fieldset > details > div { margin:0.1em 0.55em 0px -0.85em; background:white; overflow-y:scroll; } /* fieldset > details > div:focus { display:block; } // geht nicht */ /* for menu bar left vertical instead top horizontal: * .navdiv { float:left; } * .navdiv > details { min-width:4em; } */ .navdiv { background:black; color:white; padding:0.3em; min-height:1.5em; font-weight:bold; position:sticky; top: 0px; z-index:5 } .navdiv > details:first-child >summary { list-style:none; font-size:120%; max-width:2em !important; } .navdiv > details:first-child { margin-left:0.1em; } .navdiv > details { margin-left: 0.8em; float:left; } .navdiv > details div { margin-left:-0.3em; background:var(--bg-menu); z-index:3; } .navdiv > details > div > input[type="submit"] { display:block; } .navdiv > details > div > label { font-weight:normal; display:block; } .navdiv > details > div > details > div { margin-left:0.8em; } /* submenu */ details > div { padding:0.5em; border:var(--border-1); border-radius:var(--radius-10); position:absolute; } details > div > li { margin-left: 2.2em; } /* lists in texts */ details > div > table { font-size: 100%; } /* Simple GUI (unsure why necessary)*/ details[open] > summary { text-decoration:underline; } /* } cgi page only */ li { margin-left: 1.2em; } /* lists in texts */ li[class="n"] { margin-left: 2.2em; list-style-type:none; } /* "comments" in text */ p { margin: 0px 0px 0.5em 1em; } /* all texts */ p > a[class="b"] { margin-left:-1em; } /* ^top button only */ label[class="i"] { margin-right:1em; min-width:8em; border:var(--border-w); display:inline-block; } label[class="i"]:hover { background:var(--bg-hover);border-bottom:var(--border-1);} b { margin-left: 1em; } /* for discrete commands #FIXME: wrong in cgi page */ .r { float:right; } /* help buttons */ .l { margin-left: 2em; } /* label for options */ .c { margin-left: 3em; padding:0.1em; font-size:12pt !important; font-family:monospace; background:var(--bg-literal);} /* literal text block; #TODO: white-space:pro */ span[class="c"] { margin-left:0.1em;} /* literal text (inline) */ /* dirty hack for mobile-friendly A tag's title= attribute; * placed left bound below tag; browser's title still visible * does not work for BUTTON and INPUT tags */ [title] { position:relative; } a[class="b"][title]:hover:after, a[class="b r"][title]:hover:after { content: attr(title); position:absolute; z-index:99; top:100%; left:-1em; padding:0.3em; border-radius:2px; background:var(--bg-mbox); color:white; font-weight:normal; } EoSTYLE 'style_ciphers' => << 'EoSTYLE_C', body {padding: 1em; } body > h1 {padding-top:1em; margin-top:1em; } body > h2 {padding: 1em; margin-top:-0.3em; height:1.5em;width:94%;color:white;background:linear-gradient(#000,#fff);border-radius:0px 0px 20px 20px;box-shadow:0 5px 5px #c0c0c0;position:fixed;top:0px; } body > h2 > span {font-size:120%; } h2 > a[class="b"] {float:right; margin-top:1em; font-size:70%; border-radius:5px;} /* table { border-collapse: collapse; } * nicht verwenden */ /* table { table-layout: fixed; } * geht nicht */ table th {background:#aaa; } tbody tr:nth-child(even) {background:#fff; } tbody tr:nth-child(odd) {background:#eee; } tbody td:first-child {text-align:right; } tbody td {width: 5em; } thead {position: sticky; top:3em; } details {padding: 0.2em; font-weight:bold; } details:nth-child(even){background:#fff; } details:nth-child(odd) {background:#eee; } details summary:hover {background:#ffd700;} details span:first-child {text-align:right; min-width:15em; } details span {padding: 0.2em; display:inline-block; min-width:6em; border-radius:4px 4px 4px 4px; } details div {margin-top:0.5ex; font-size:90%; border:1px solid #000; border-top:0px solid #000; border-radius:0px 0px 10px 10px; } details dl {padding: 0.2em; display:block; } details dt,dd {padding: 0.5ex; display:inline-block; } details dt {min-width: 12em; text-align:left;font-weight:bold;} /* automatically generate colour of tag based on the sec attribute */ [sec="-"] {background-color:#f00; } [sec^="weak"] {background-color:#f00; } [sec^="WEAK"] {background-color:#f00; } [sec="-?-"] {background-color:#ff0; } [sec^="LOW"] {background-color:#fd8; } [sec^="medium"] {background-color:#ff4; } [sec^="MEDIUM"] {background-color:#ff4; } [sec^="high"] {background-color:#4f4; } [sec^="HIGH"] {background-color:#3f3; } [typ="PFS"] {background-color:#4f4; } /* automatically generate content if tag from attribute typ= */ [typ]::before {content:attr(typ); } dd[typ] {border:1px solid #ffd700;} td[typ] {border:1px solid #fff; } [typ]:hover {border:1px solid #aaa; } [typ]:hover ::after {border:1px solid #000; border-radius:3px; position:absolute; margin-left:0.5em; background:#fd8; min-width:19em; } /* following definitons should be generated from OSaft/Doc/glossar.txt */ /* sequence of following definitions important: more lacy pattern first */ [typ="-"]:hover ::after {content:"\2014 none / null / nothing";} [typ="-?-"]:hover ::after {content:"\2014 unknown";} [typ^="ADH"]:hover ::after {content:"\2014 Anonymous Diffie-Hellman";} [typ="AEAD"]:hover ::after {content:"\2014 Authenticated Encryption with Additional Data";} [typ^="AES"]:hover ::after {content:"\2014 Advanced Encryption Standard";} [typ="AESGCM"]:hover ::after {content:"\2014 AEAD algorithms AEAD_AES_128_GCM and AEAD_AES_256_GCM";} [typ^="ARIA"]:hover ::after {content:"\2014 128-bit symmetric block cipher";} [typ="ARIAGCM"]:hover ::after {content:"\2014 symmetric key block cipher encryption algorithm with GCM";} [typ="CAMELLIA"]:hover ::after {content:"\2014 symmetric key block cipher encryption algorithm";} [typ="CAMELLIAGCM"]:hover ::after {content:"\2014 CAMELLIA with GCM";} [typ="CAST"]:hover ::after {content:"\2014 Carlisle Adams and Stafford Tavares, block cipher";} [typ="CBC"]:hover ::after {content:"\2014 Cyclic Block Chaining (aka Cypher Block Chaining)";} [typ^="CECPQ"]:hover ::after {content:"\2014 Combined elliptic Curve and Post-Quantum Cryptography Key Exchange";} [typ^="ChaCha"]:hover ::after {content:"\2014 stream cipher algorithm (with 256-bit key)";} [typ="DES"]:hover ::after {content:"\2014 Data Encryption Standard";} [typ="3DES"]:hover ::after {content:"\2014 Tripple Data Encryption Standard";} [typ="DSS"]:hover ::after {content:"\2014 Digital Signature Standard";} [typ="DH"]:hover ::after {content:"\2014 Diffie-Hellman";} [typ^="DHE"]:hover ::after {content:"\2014 Diffie-Hellman ephemeral (same as EDH)";} [typ="DHEPSK"]:hover ::after {content:"\2014 Diffie-Hellman ephemeral with pre-shared key";} [typ="DH/DSS"]:hover ::after {content:"\2014 Diffie-Hellman with DSS";} [typ="DH/RSA"]:hover ::after {content:"\2014 Diffie-Hellman with RSA";} [typ="DH(512)"]:hover ::after {content:"\2014 Diffie-Hellman (512 bit)";} [typ="ECCPWD"]:hover ::after {content:"\2014 Elliptic Curve Cryptography (with password?)";} [typ^="ECDH"]:hover ::after {content:"\2014 Elliptic Curve Diffie-Hellman";} [typ^="ECDHE"]:hover ::after {content:"\2014 Ephemeral Elliptic Curve Diffie-Hellman";} [typ="ECDH/ECDSA"]:hover ::after {content:"\2014 Elliptic Curve Diffie-Hellman with ECDSA";} [typ="ECDH/RSA"]:hover ::after {content:"\2014 Elliptic Curve Diffie-Hellman with RSA";} [typ="ECDHEPSK"]:hover ::after {content:"\2014 Elliptic Curve Diffie-Hellman with pre-shared key";} [typ="ECDSA"]:hover ::after {content:"\2014 Elliptic Curve Digital Signature Algorithm";} [typ^="EDH"]:hover ::after {content:"\2014 Ephemeral Diffie-Hellman";} [typ="FZA"]:hover ::after {content:"\2014 Fortezza encryption";} [typ^="GOST"]:hover ::after {content:"\2014 Gossudarstwenny Standard, block cipher";} [typ="IDEA"]:hover ::after {content:"\2014 International Data Encryption Algorithm";} [typ="KRB"]:hover ::after {content:"\2014 Key Exchange Kerberos";} [typ="KRB5"]:hover ::after {content:"\2014 Key Exchange Kerberos 5";} [typ="MD2"]:hover ::after {content:"\2014 Message Digest 2";} [typ="MD4"]:hover ::after {content:"\2014 Message Digest 4";} [typ="MD5"]:hover ::after {content:"\2014 Message Digest 5";} [typ="None"]:hover ::after {content:"\2014 no encryption / plain text";} [typ="RC2"]:hover ::after {content:"\2014 Rivest Cipher 2, block cipher";} [typ="RC4"]:hover ::after {content:"\2014 Rivest Cipher 4, stream cipher (aka Ron's Code)";} # dumm ' [typ="RC5"]:hover ::after {content:"\2014 Rivest Cipher 5, block cipher";} [typ="RIPEMD"]:hover ::after {content:"\2014 RACE Integrity Primitives Evaluation Message Digest";} [typ="RSA"]:hover ::after {content:"\2014 Rivest Sharmir Adelman (public key cryptographic algorithm)";} [typ="RSAPSK"]:hover ::after {content:"\2014 Rivest Sharmir Adelman with pre-shared key";} [typ="RSA(512)"]:hover ::after {content:"\2014 Rivest Sharmir Adelman (512 bit)";} [typ="PCT"]:hover ::after {content:"\2014 Private Communications Transport";} [typ="PSK"]:hover ::after {content:"\2014 Pre-shared Key";} [typ="SEED"]:hover ::after {content:"\2014 128-bit symmetric block cipher";} [typ="SHA"]:hover ::after {content:"\2014 Secure Hash Algorithm";} [typ="SHA1"]:hover ::after {content:"\2014 Secure Hash Algorithm";} [typ="SHA256"]:hover ::after {content:"\2014 Secure Hash Algorithm (256 bit)";} [typ="SHA384"]:hover ::after {content:"\2014 Secure Hash Algorithm (384 bit)";} [typ="SHA512"]:hover ::after {content:"\2014 Secure Hash Algorithm (512 bit)";} [typ="SRP"]:hover ::after {content:"\2014 Secure Remote Password protocol";} [typ="SSLv2"]:hover ::after {content:"\2014 Secure Socket Layer 2";} [typ="SSLv3"]:hover ::after {content:"\2014 Secure Socket Layer 3";} [typ="TLSv10"]:hover ::after {content:"\2014 Transport Level Secure 1.0";} [typ="TLSv11"]:hover ::after {content:"\2014 Transport Level Secure 1.1";} [typ="TLSv12"]:hover ::after {content:"\2014 Transport Level Secure 1.2";} [typ="TLSv13"]:hover ::after {content:"\2014 Transport Level Secure 1.3";} /* not yet working: setting CSS variables and then use them dd[val] {--data: attr(val); --index: var(--data);} */ EoSTYLE_C 'body_anf' => << 'EoBODY',

    __HTML_title__

    EoBODY 'form_anf' => << 'EoFORM',
    EoFORM 'fieldset' => << 'EoFIELDSET',

    Host[:Port]::

    EoFIELDSET 'form_end' => << 'EoFORM',

    EoFORM 'warning_box' => << 'EoWARN',
    X

    O-Saft as CGI

    This is a sample implementation to show O-Saft's functionality.

    It is not intended to be used for regular tests of foreign servers.

    The server may be slow and is short on memory, so please don't expect miracles.

    EoWARN ); #_____________________________________________________________________________ #_________________________________________________________ internal methods __| # SEE Perl:Undefined subroutine *_warn = sub { print($STR{WARN}, join(" ", @_), "\n"); } if not defined &_warn; *_hint = sub { print($STR{HINT}, join(" ", @_), "\n"); } if not defined &_hint; *_dbx = sub { print($STR{DBX}, join(" ", @_), "\n"); } if not defined &_dbx; sub _get_filename { # TODO: move to osaft.pm or alike my $src = shift || "o-saft.pl"; foreach my $dir (@INC) { # find the proper file if (-e "$dir/$src") { $src = "$dir/$src"; last; } } return $src; } # _get_filename sub _man_dbx { # 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. my @txt = @_; my $anf = ""; my $end = ""; if (0 < (grep{/^--help=gen.cgi/i} @ARGV)) { # debug messages should be HTML comments when generating HTML $anf = ""; # TODO: need to sanitise @txt : remove } if (0 < $VERBOSE) { print $anf . "#" . $ich . ": " . join(' ', @txt) . "$end\n"; } return; } # _man_dbx sub _man_use_tty { # break long lines of text; SEE Note:tty # set screen width in $cfg{'tty'}->{'width'} _man_dbx("_man_use_tty() ..."); return if not defined $cfg{'tty'}->{'width'}; my $_len = 80; my $cols = $cfg{'tty'}->{'width'}; if (10 > $cols) { # size smaller 10 doesn't make sense $cols = $ENV{COLUMNS} || 0; # ||0 avoids perl's "Use of uninitialized value" if ($cols =~ m/^[1-9][0-9]+$/) { # ensure that we get numbers $cfg{'tty'}->{'width'} = $cols; return; } # try with tput, if it fails try with stty; errors silently ignored $cols = qx(\\tput cols 2>/dev/null) || undef; ## no critic qw(InputOutput::ProhibitBacktickOperators) if (not defined $cols) { # tput failed or missing $cols = qx(\\stty size 2>/dev/null) ## no critic qw(InputOutput::ProhibitBacktickOperators) || $_len; # default if stty fails $cols =~ s/^[^ ]* //; # stty returns: 23 42 ; extract 42 } $cfg{'tty'}->{'width'} = $cols; } $cfg{'tty'}->{'width'} = 80 if (10 > $cfg{'tty'}->{'width'}); # safe fallback _man_dbx("_man_use_tty: " . $cfg{'tty'}->{'width'}); return; } # _man_use_tty sub _man_squeeze { # break long lines of text; SEE Note:tty # if len is undef, default from %cfg is used my $len = shift; my $txt = shift; return $txt if not defined $cfg{'tty'}->{'width'}; # if a width is defined, --tty was used # Keep in mind that help.txt is formatted to fit in 80 columns, hence a # width > 80 does not change the total length of the line (which is always # < 80), but changes the number of left most spaces. $txt =~ s/[\t]/ /g; # replace all TABs my $max = $cfg{'tty'}->{'width'} - 2; # let's have one space right my $ident = ' ' x $cfg{'tty'}->{'ident'}; # default ident spaces if (defined $len) { # break long lines at max size and ident remaining with len $ident = "$cfg{'tty'}->{'arrow'}\n" . ' ' x $len; $txt =~ s/(.{$max})/$1$ident/g; } else { # change left most 8 spaces to specified number of spaces # break long lines at max size # break long lines at max size and ident with specified number of spaces $txt =~ s/\n {8}/$ident/g; # reduced existing identation $ident = "$cfg{'tty'}->{'arrow'}\n" . $ident; $max--; } #$max--; $txt =~ s/(.{$max})/$1$ident/g; # squeeze line length return $txt; } # _man_squeeze 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: 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_get_version { # ugly, but avoids global variable elsewhere or passing as argument no strict; ## no critic qw(TestingAndDebugging::ProhibitNoStrict) my $v = '2.84'; $v = _VERSION() if (defined &_VERSION); return $v; } # _man_get_version sub _man_html_init { #? initialise %html hash my $tipp = _man_get_version(); # get official version 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) # this function is called once, usually, hence it's save to modify %html directly $html{'action'} =~ s/__HTML_cgi_bin__/$cgi_bin/g; $html{'form_anf'} =~ s/__HTML_cgi_bin__/$cgi_bin/g; $html{'script_endcgi'} =~ s/__HTML_cgi_bin__/$cgi_bin/g; $html{'body_anf'} =~ s/__HTML_version__/$tipp/g; $html{'body_anf'} =~ s/__HTML_title__/$html{'title'}/g; $html{'meta'} =~ s/__HTML_title__/$html{'title'}/g; return; } # _man_html_init 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. return "X-Cite: Perl is a mess. But that's okay, because the problem space is also a mess. Larry Wall\r\n" . "Content-type: text/html; charset=utf-8\r\n" . "\r\n" . _man_dbx("_man_http_head() ...") # note that it must be after all HTTP headers ; } # _man_http_head sub _man_html_head { #? print header of HTML page # SEE HTML:JavaScript _man_dbx("_man_html_head() ..."); return $html{'doctype'} . '' . $html{'meta'} . $html{'script_nonce'} . $html{'script_func1'} . $html{'script_func2'} . '' . "\n" . '' . "\n" . '' . "\n" . $html{'body_anf'} ; } # _man_html_head sub _man_html_details { #? print details scope with summary text and div content my $sum = shift; my $open= shift; my $txt = shift; return << "EoDetails";
    $sum
    $txt
    EoDetails } # _man_html_details sub _man_help_button { #? return href tag for a help button 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 $href = $html{'action'}; my $txt = $cmd; # $txt =~ s/.*--.*help=//; # button text without --help and other options $txt =~ s/&.*$//; # button text without --help and other options $class = qq(class="$class") if ($class !~ m/^\s*$/); return qq( $txt\n); } # _man_help_button sub _man_cmd_button { #? return input tag for a cmd button my $cmd = shift; return qq( \n); } # _man_cmd_button sub _man_opt_button { #? return input tag for a opt button my $opt = shift; my $val = shift; return qq( \n); } # _man_cmd_button sub _man_menu_bar { #? print menu bar my $menu = _man_help_button("--help=ciphers-html&--content-type=html", '', "open window with list of cipher suites (html format)") . qq( ! Help (this CGI form)) . qq( ? Help (complete help)); my $cmds; $cmds .= _man_cmd_button($_) foreach qw(+check +cipher +info +quick +vulns +protocols); my $opts = _man_opt_button('--format', 'html'); $opts .= _man_opt_button($_, '') foreach qw(--header --enabled --no-dns --no-http --no-sni --no-sslv2 --no-sslv3); my $help = _man_help_button("--help", '', "open window with complete help (plain text)") . _man_help_button("--help=command", '', "open window with help for commands") . _man_help_button("--help=checks", '', "open window with help for checks") . _man_help_button("--help=example", '', "open window with examples") . _man_help_button("--help=opt", '', "open window with help for options") . _man_help_button("--help=FAQ", '', "open window with FAQs") . _man_help_button("--help=abbr", '', "open window with the glossar") . _man_help_button("--help=todo", '', "open window with help for ToDO") . _man_help_button("--help=ciphers-text", '', "open window with list of cipher suites (text format)") . _man_help_button("--help=ciphers-html&--content-type=html", '', "open window with list of cipher suites (html format)"); return qq( \n); } # _man_menu_bar sub _man_cgi_simple { #? generate list of options for "Simple GUI" my $txt = qq( \n
    \n); # Above contains the quick buttons for some commands. These # quick buttons should get their description from the later generated # help text in this page. Hence the buttons are generated later using # JavaScript function osaft_buttons() so that the corresponding help # text can be derived from the HTML page itself. SEE HTML:JavaScript $txt .= qq(
    \n); $txt .= qq(
    \n); # show most common used options; layout by lines using BR #
    contains checkboxes for some options.These checkboxes # are added in following foreach loop. 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 format=html BR enabled disabled legacy=owasp BR traceKEY traceCMD trace v cgi-no-header BR )) { if ('BR' eq $key) { $txt .= "
    \n"; next; } my $tag_nam = "--$key"; $txt .= _man_html_cbox('cgi', " ", "q$tag_nam", $tag_nam, "", $tag_nam) . "\n"; } $txt .= "
    "; $txt .= _man_html_go("cgi"); return $txt; } # _man_cgi_simple sub _man_html_form { #? print HTML form for CGI my $cgi_bin = $html{'action'}; my $txt; _man_dbx("_man_html_form() ..."); return $html{'form_anf'} . _man_menu_bar() . $html{'fieldset'} . _man_html_details("Simple GUI", '', _man_cgi_simple()) . _man_html_details("Full GUI Commands & Options", 'open', _man_html('cgi', 'COMMANDS', 'LAZY') . '' # print help starting at COMMANDS and a reset button ) . $html{'form_end'} . $html{'script_endcgi'} ; } # _man_html_form sub _man_html_foot { #? print footer of HTML page _man_dbx("_man_html_foot() ..."); return $html{'links'} . $html{'copyright'} . $html{'script_endall'} . '' ; } # _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) = @_; my $title = ''; $title = 'experimental option' if ("--format=html" eq $cmd_txt); # TODO: experimental hack return $cmd_txt if ($mode ne 'cgi'); # for "html" nothing special return sprintf(qq(%s  ), $prefix, $tag_id, $tag_id, $tag_nam, $tag_val, $title, $cmd_txt); } # _man_html_cbox sub _man_html_chck { #? return checkbox, or input field with clickable label (to reset input) # to be used 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 = qq(); my $input = qq(); 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 { #? return name for an ankor tag without commas 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 qq() 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 = qq( ^\n); my $run = qq( \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 _man_dbx("_man_html_cmds($key) ..."); 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 { ## no critic qw(Subroutines::ProhibitExcessComplexity) #? print text in HTML format my $key = shift; # cgi or html my $anf = shift; # pattern where to start extraction my $end = shift; # pattern where to stop extraction my $txt; 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!<<\s*undef! or s!<%s %s

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

    %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) if ('cgi' eq $key) { $txt .= _man_help_button($a, "b r", "open window with special help") if ($a =~ m/--help/); } $txt .= _man_html_ankor($a) . "\n"; $txt .= sprintf("

    %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) if ('cgi' eq $key) { $txt .= _man_help_button($1, "b r", "open window with special help"); } }; m/^\s*S&([^&]*)&/ && do { # code or example line my $v=$1; $v=~s!<$v

    \n); next }; s!"([^"]*)"!$1!g; # markup examples s!'([^']*)'!$1!g; # markup examples #dbx# m/-SSL/ && do { print STDERR "##1 $_ ###"; }; m![IX]&(?:[^&]*)&! && do { # avoid spaces in internal links to anchors # FIXME: dirty hack, probably bug in get_markup() s/\s+&/&/g; # trim trailing spaces }; s!I&([^&]*)&!$1!g; # markup commands and options s!X&([^&]*)&!$1!g; # markup references inside help s!L&([^&]*)&!$1!g; # markup other references # L& must be done after I& ad/or X& to avoid mismatch to i.e. I&-SSL& s!^\s+($mytool .*)!
    $1
    !; # example line # detect lists, very lazy ... # SEE HTML:Known Bugs m/^=item +\* (.*)/ && do { $txt .= "
  • $1
  • \n";next;}; m/^=item +\*\* (.*)/ && do { $txt .= "
  • $1
  • \n";next;}; s/^(?:=[^ ]+ )//; # remove remaining markup s!<"; $p = "

    "; $a = ''; }; # SEE Perlcritic:LocalVars s!(^ {12}.*)!
  • $1
  • !; # 12 spaces are used in lists, mainly $txt .= $_; } $txt .= "$p"; # if not empty, otherwise harmless return $txt; } # _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(..) ..."); my $len0 = $len1 - 1; return "" if (1 > $cfg_header); return sprintf("=%${len0}s | %s\n", @args) . sprintf("=%s+%s\n", '-' x $len1, '-'x60); } # _man_head sub _man_foot { #? print table footer line (dashes) my $len1 = shift; # expected length of first (left) string return "" if (1 > $cfg_header); return sprintf("=%s+%s\n", '-'x $len1, '-'x60); } # _man_foot sub _man_opt { ## no critic qw(Subroutines::RequireArgUnpacking) #? print line in "KEY - VALUE" format my @args = @_; # key, sep, value my $len = 16; $len = 1 if ($args[1] eq "="); # allign left for copy&paste my $txt = sprintf("%${len}s%s%s\n", @args); return _man_squeeze((16+length($_[1])), $txt); } # _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/); return _man_opt($key, $sep, $txt); } # _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; return _man_cfg($typ, $key, $sep, $txt); } # _man_txt sub _man_pod_item { #? print line as POD =item my $line = shift; return "=over\n\n$line\n=back\n"; } # _man_pod_item 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); my $opt; # 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"; } $opt .= _man_opt($key, $sep, $val) if ('opt' eq $format); $opt .= _man_pod_item("$key $sep $val\n") if ('POD' eq $format); } return $opt; } # _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; #_man_doc_opt($typ, $sep, "POD"); # if real POD should be printed return << "EoHelp"; # begin $typ # =head1 $typ $help # end $typ EoHelp } # _man_doc_pod sub _man_pod_head { #? print start of POD format my $txt = <<'EoHelp'; #!/usr/bin/perldoc #? # Generated by o-saft.pl . # Unfortunately the format in @help is incomplete, for example proper =over # and corresponding =back paragraph is missing. It is mandatory around =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 $txt .= "=pod\n\n"; # must be variable to not confuse perldoc $txt .= "=encoding utf8\n\n"; # for utf8 SEE POD:Syntax return $txt; } # _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 my $pod; 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) { $pod .= $_; $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 $pod .= "\n" if (0 == ($empty + $code)); $pod .= $_; $empty = 0; $code++; next; # no more changes }; $code = 0; s:['`]([^']*)':C<$1>:g; # markup literal text; # dumm ' s:(^|\s)X&([^&]*)&:$1L:g; # markup references inside help s:(^|\s)L&([^&]*)&:$1L<$2|$2>:g;# markup other references #s:L<[^(]*(\([^\)]*\)\>).*:>:g; # POD does not like section in link s:(^|\s)I&([^&]*)&:$1I<$2>: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 $pod .= "\n" if (0 == $empty); $pod .= "$line" if $line =~ m/^=[hovbefpc].*/; # any POD keyword $pod .= _man_pod_item "$line" if $line =~ m/^=item/;# POD =item keyword $pod .= "\n"; $empty = 1; next; }; $pod .= "$line"; $empty = 0; } return $pod; } # _man_pod_text sub _man_pod_foot { #? print end of POD format my $pod = <<'EoHelp'; Generated with: o-saft.pl --no-warnings --no-header --help=gen-pod > o-saft.pod EoHelp $pod .= "=cut\n\n"; $pod .= _man_doc_pod('abbr', "-"); # this is for voodoo, see below $pod .= _man_doc_pod('rfc', "-"); # this is for voodoo, see below $pod .= $_voodoo; return $pod; } # _man_pod_foot sub _man_wiki_head { #? print start of mediawiki format return <<'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 } # _man_wiki_head sub _man_wiki_text { #? print text of mediawiki format # convert POD syntax to mediawiki syntax my $pod; 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 m/^=/ && do { $pod .= $_; next; }; # no more changes in header lines s:['`]([^']*)':$1:g; # markup examples # dumm ' s/^S&([^&]*)&/ $1/ && do { $pod .= $_; 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 $pod .= $_; } return $pod; } # _man_wiki_text sub _man_wiki_foot { #? print end of mediawiki format return <<'EoHelp'; ---- Content of this wiki page generated with: o-saft.pl --no-warning --no-header --help=gen-wiki EoHelp } # _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)', _get_filename("OSaft/Data.pm"))) { # need full path for $parent file here # TODO: o-saft.pl hardcoded, need a better method to identify the proper file 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; } if (m/^\s*\)\s*;/) { $skip = 1; next; } # 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); ## no critic qw(InputOutput::RequireCheckedClose) } else { $txt .= sprintf("%s cannot read '%s'; %s\n", $STR{ERROR}, _get_filename("o-saft.pl"), $!); } 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'})) { # TODO: need a better method to identify the proper file, RC-FILE is # wrong when this file was called directly 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); ## no critic qw(InputOutput::RequireCheckedClose) } else { $txt .= sprintf("%s cannot read '%s'; %s\n", $STR{ERROR}, $cfg{'RC-FILE'}, $!); } return $txt; } # _man_cmd_from_rcfile sub _man_ciphers_get { #? helper function for man_ciphers(): return %ciphers as simple line-oriented text # SEE Cipher:text for detaiiled description and generated data format _man_dbx("_man_ciphers_get() .."); my $ciphers = ""; foreach my $key (sort keys %ciphers) { my $name = OSaft::Ciphers::get_name ($key); next if not $name; # defensive programming next if $name =~ m/^\s*$/; # defensive programming my $sec = OSaft::Ciphers::get_sec ($key); my $hex = OSaft::Ciphers::key2text ($key); my $mac = OSaft::Ciphers::get_mac ($key); my @alias = OSaft::Ciphers::get_names($key); my @_keep = grep { $alias[$_] ne $name } 0..$#alias; @alias = @alias[@_keep]; # remove names, which equal $name my $pfs = OSaft::Ciphers::get_pfs ($key); my $rfc = OSaft::Ciphers::get_rfc ($key); my $rfcs = ""; foreach my $key (split(/,/, $rfc)) { # replace RFC-number, if any, with URL my $num = $key; $num =~ s/[^0-9]//g; if ("" eq $num) { $rfcs .= $key; } else { # TODO: also make URL for something like: 6655? $rfcs .= "https://www.rfc-editor.org/rfc/rfc$num"; # old style URL ('til 2020): # https://tools.ietf.org/html/rfcXXXX # https://tools.ietf.org/rfc/rfcXXXX.txt # modern style URL (2022 ...): # https://www.rfc-editor.org/rfc/rfcXXXX # https://www.rfc-editor.org/rfc/rfcXXXX.txt } $rfcs .= " , "; } # keep in mind that the code marked with following comment: # take care for sequence! # relies on the sequence of line in following $ciphers $rfcs =~ s/ , $//; # remove trailing , # . "\n\tIANA name:\t" . OSaft::Ciphers::get_iana ($key) # . "\n\tGnuTLS name:\t" . OSaft::Ciphers::get_gnutls($key) $ciphers .= "\n$hex\t$sec\t$name" . "\nname\t" . $name . "\nnames\t" . join(', ', @alias) . "\nconst\t" . join(', ', OSaft::Ciphers::get_consts($key)) . "\nopenssl\t" . OSaft::Ciphers::get_openssl($key) . "\nssl\t" . OSaft::Ciphers::get_ssl ($key) . "\nkeyx\t" . OSaft::Ciphers::get_keyx ($key) . "\nauth\t" . OSaft::Ciphers::get_auth ($key) . "\nenc\t" . OSaft::Ciphers::get_enc ($key) . "\nbits\t" . OSaft::Ciphers::get_bits ($key) . "\nenc_size\t" . OSaft::Ciphers::get_encsize($key) . "\nmac\t" . $mac . "\nmac_size\t" . '' . "\npfs\t" . $pfs . "\nrfc\t" . $rfcs . "\nnotes\t" . OSaft::Ciphers::get_notes($key) . "\n" ; } return $ciphers; } # _man_ciphers_get sub _man_ciphers_html_dl { #? helper function for man_ciphers_html(): return DL tag with content my $dl = shift; $dl =~ s/\n$//; # remove trailing \n return << "EoHTML";
    $dl
    EoHTML } # _man_ciphers_html_dl sub _man_ciphers_html_li { #? helper function for man_ciphers_html(): return LI tag with content my ($hex, $sec, $name, $dl) = @_; $name = "" if not defined $name; # defensive programming $dl =~ s/\n$//; return << "EoHTML";
    $hex $sec $name $dl
    EoHTML } # _man_ciphers_html_li sub _man_ciphers_html_ul { #? helper function for man_ciphers_html(): return UL tag with content # generate simple list with UL and LI tags from given text my $ciphers = shift; my $ul = ''; # #
  • # weak # cipher #
    #
    name:
    RC4-MD5
    #
    #
  • my ($hex, $sec, $name, $dl); $dl = ""; foreach my $line (split(/\n/, $ciphers)) { chomp($line); next if $line =~ m/^\s*$/; $line =~ s/^\s*//; # remove leading whitespace ($hex, $sec, $name) = split(/\t/, $line); if ($line =~ m/^0x/) { if ("" ne $dl) { # new cipher, print previous one $ul .= _man_ciphers_html_li($hex, $sec, $name, _man_ciphers_html_dl($dl)); $dl = ""; } ($hex, $sec, $name) = split(/\t/, $line); next; } my ($key, $val) = split(/\t/, $line); my $txt = $key; $txt =~ s/$key/$OSaft::Ciphers::ciphers_desc{$key}/; # convert internal key to human readable text $sec = ""; $sec = "sec='$val'" if ("openssl" eq $key);# OpenSSL STRENGTH should also be marked $sec = "sec='$val'" if ("sec" eq $key); $dl .= "
    ${txt}:

    \n"; # tag necessary, otherwise dd::after will not work } # print last cipher $ul .= _man_ciphers_html_li($hex, $sec, $name, _man_ciphers_html_dl($dl)) if ("" ne $dl); return "$ul\n"; #return "$ul\n

    \n"; } # _man_ciphers_html_ul sub _man_ciphers_html_tb { #? helper function for man_ciphers_html(): return TABLE tag with content # generate html table with all columns # SEE Cipher:text and Cipher:HTML my $ciphers = shift; my $tab = '
    '; $tab .= "\n \n"; # following not yet working # # # # # ... # # # build table header; cannot use "keys %ciphers_desc" because it's random # and we also want mixed rowspan and colspan # take care for sequence! $tab .= " \n"; $tab .= " \n"; $tab .= " \n"; $tab .= " \n"; $tab .= " \n"; $tab .= " \n"; $tab .= " \n"; # $OSaft::Ciphers::ciphers_desc{'auth'}; $tab .= " \n"; # $OSaft::Ciphers::ciphers_desc{'enc'} $tab .= " \n"; $tab .= " \n"; $tab .= " \n"; # $OSaft::Ciphers::ciphers_desc{'rfc'}; $tab .= " \n"; $tab .= " \n"; $tab .= "\n \n"; # second header line (for those with colpan= above foreach my $key (qw(suite names const enc bits enc_size mac)) { my $txt = $OSaft::Ciphers::ciphers_desc{$key}; $txt =~ s|^Encryption ||; $txt =~ s|MAC\s*/\s*HASH||i; $tab .= " \n"; } $tab .= " \n"; # build table lines my ($hex, $sec, $name, $td); $td = ""; foreach my $line (split(/\n/, $ciphers)) { chomp($line); next if $line =~ m/^\s*$/; next if $line =~ m/^mac_/; next if $line =~ m/^name\s/; $line =~ s/^\s*//; # remove leading whitespace if ($line =~ m/^0x/) { if ("" ne $td) { # new cipher, print previous one $tab .= " \n$td \n"; $td = ""; } ($hex, $sec, $name) = split(/\t/, $line); $td .= " \n"; $td .= " \n"; $td .= " \n"; next; } my ($key, $val) = split(/\t/, $line); $sec = ""; $sec = "sec='$val'" if ("openssl" eq $key); # OpenSSL STRENGTH should also be marked $sec = "sec='$val'" if ("sec" eq $key); # OpenSSL STRENGTH should also be marked $td .= " \n"; # tag necessary, otherwise td::after will not work } # print last cipher $tab .= " \n$td \n" if ("" ne $td); return "$tab\n
    $OSaft::Ciphers::ciphers_desc{'hex'}$OSaft::Ciphers::ciphers_desc{'sec'}Names$OSaft::Ciphers::ciphers_desc{'openssl'}$OSaft::Ciphers::ciphers_desc{'ssl'}$OSaft::Ciphers::ciphers_desc{'keyx'}Authen-ticationEncryptionMAC$OSaft::Ciphers::ciphers_desc{'pfs'}RFC(s) URL$OSaft::Ciphers::ciphers_desc{'notes'}
    $txt
    $hex$sec$name
    \n"; } # _man_ciphers_html_tb # TODO: instead of
    .. and .. try to use
    , see: # https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details #_____________________________________________________________________________ #__________________________________________________________________ methods __| sub man_docs_write { #? generate all static help files # this function writes to files, not to STDOUT # TODO: anything hardcoded here, at least directory should be a parameter # NOTE: $cfg{'files'} should be same as $cfg(docs-help-all) in o-saft.tcl _man_dbx("man_docs_write() ..."); if ($ich eq $cfg{me}) { _warn("094:", "'$parent' used as program name in generated files"); _hint("documentation files should be generated using '$cfg{files}{SELF} --help=gen-docs'"); } my $fh = undef; foreach my $mode (keys %{$cfg{'files'}}) { next if $mode !~ m/^--help/; next if $mode =~ m/^--help=warnings/; # TODO: my $doc = "$cfg{'files'}{$mode}"; #_dbx# print("doc=$doc\n"); open($fh, '>:encoding(UTF-8)', $doc) or do { _warn("093:", "help file '$doc' cannot be opened: $! ; ignored"); next; }; print $fh man_alias() if ($mode =~ /alias$/); print $fh man_commands() if ($mode =~ /commands?$/); print $fh man_options() if ($mode =~ /opts$/); print $fh man_ciphers('text') if ($mode =~ /ciphers.?text$/); print $fh man_help('NAME') if ($mode =~ /help$/); print $fh man_help('CHECKS') if ($mode =~ /checks$/); print $fh man_table('rfc') if ($mode =~ /rfc$/); print $fh man_table('regex') if ($mode =~ /regex$/); print $fh man_table('abbr') if ($mode =~ /glossary?$/); print $fh man_table('data') if ($mode =~ /data$/); close($fh); } exit(0); return; ##no critic qw(ControlStructures::ProhibitUnreachableCode) } # man_docs_write sub man_help_brief { #? print overview of help commands (invoked with --h) # TODO: get this data from internal data structure when it is ready ... # extract all --help= options with their description from @help # using a foreach loop instead of regex to avoid memory polution _man_dbx("man_help_brief() ..."); my %opts; my $skip = 1; my $idx = 0; # perl hashes are sorted randomly, we want to keep the sequence in @help my $key = ""; foreach my $line (@help) { # note: @help is in POD format # we expect somthing like: # =head2 Options for help and documentation # =head3 --help=cmds # # Show available commands; short form. # # ... # $skip = 1 if ($line =~ m/^=head2\s+Options for /); $skip = 0 if ($line =~ m/^=head2\s+Options for help/); next if ($line =~ m/^=head2\s+Options for help/); next if (1 == $skip); next if ($line =~ m/^\s*$/); chomp $line; #_dbx "$line" if $skip == 0; if ($line =~ m/^=head3\s+--h/) { # --h and --help and --help=* $idx++; $key = $line; $key =~ s/^=head3\s+//; $opts{$idx}->{'opt'} = $key; next; } $line =~ s/^\s*//; # normalise $line =~ s![IX]&([^&]*)&!$1!g; # remove markup $line = sprintf("\n%17s %s", " ", $line) if (defined $opts{$idx}->{'txt'}); $opts{$idx}->{'txt'} .= $line; } my $pod = "\n" . _man_head(15, "Option", "Description"); foreach my $key (sort {$a <=> $b} keys %opts) { $pod .= sprintf("%-17s %s\n", $opts{$key}->{'opt'}, $opts{$key}->{'txt'}||""); } $pod .= _man_foot(15); $pod .= "\n" . _man_head(15, "Command", "Description"); $pod .= _man_squeeze(18, $_cmd_brief); # first most important commands, manually crafted here $pod .= _man_foot(15); my $opt = ""; $opt = " --header" if (0 < $cfg_header); # be nice to the user $pod .= qq(\nFor more options see: $cfg{me}$opt --help=opt); $pod .= qq(\nFor more commands see: $cfg{me}$opt --help=commands\n\n); return $pod; } # man_help_brief sub man_commands { #? print commands and short description # data is mainly extracted from $parents internal data structure _man_dbx("man_commands($parent) ..."); # SEE Help:Syntax my $txt = "\n" . _man_head(15, "Command", "Description"); $txt .= _man_squeeze(18, $_commands); # first print general commands, manually crafted here $txt .= _man_squeeze(18, _man_cmd_from_source()); $txt .= _man_squeeze(18, _man_cmd_from_rcfile()); $txt .= _man_foot(15) . "\n"; return $txt; } # man_commands sub man_warnings { #? print warning messages defined in code #? recommended usage: $0 --header --help=warnings # data is extracted from separate file, which could be created by make _man_dbx("man_warnings($parent) ..."); my $pod = ""; my $txt = ""; my $rex = '.STR\{(?:ERROR|WARN|HINT)},|' . join('|', $STR{ERROR}, $STR{WARN}, $STR{HINT}); $rex =~ s/([*!])/\\$1/g;# escape meta chars in text $rex = qr($rex); # match our own messages only my $fh = undef; my $doc = 'docs/o-saft.pl.--help=warnings'; # file generated by: "make doc.data", which calls "make warnings-info" # TODO: need some kind of configuration for the filename _man_dbx("man_warnings: rex=$rex"); if (not open($fh, '<:encoding(UTF-8)', $doc)) { _warn("091:", "help file '$doc' cannot be opened: $! ; ignored"); _hint($cfg{'hints'}->{'help=warnings'}); return $pod; } # else # parse file and collect messages from there, print warnings while parsing # first, otherwise it is difficult (for human readers) to distinguish the # collected messages from the warning messages printed while parsing; also # note that Perl's warn() and not our own _warn() is used, because it # prints the line number from the read file, which contains the line with # unknown/unexpected syntax # following formats of a line are expected: # **WARNING: 042: text ..." -- _warn() called with only one parameter # **WARNING: 091:", "text ..." -- _warn() called with two parameters # print $STR{WARN}, "text ..." -- print used to print message #dbx# _dbx("rex $rex\n"); while(<$fh>) { next if (m/^\s*#/); next if (m/^\s*$/); if (not m/$rex/) { warn($STR{WARN}, "092:", " help file '$doc' unknown syntax: '$_' ; ignored"); ## no critic qw(ErrorHandling::RequireCarping) next; } my ($err, $nr, $msg) = m/($rex\s*)"?([0-9]{3}:?)(.*)/; my $bad = 0; $bad = 1 if (not defined $err or $err =~ m/^$/); $bad = 1 if (not defined $nr or $nr =~ m/^$/); $bad = 1 if (not defined $msg or $msg =~ m/^$/); if ($bad == 1) { # unexpected format, silently print and continue #dbx# _dbx("bad $_"); $txt .= $_; next; } $err =~ s/\$STR\{ERROR}/$STR{ERROR}/; $err =~ s/\$STR\{WARN}/$STR{WARN}/; $err =~ s/, *//; $msg =~ s/^[", ]*//; $txt .= sprintf("%s%s\t- %s\n", $err, $nr, $msg); } close($fh); ## no critic qw(InputOutput::RequireCheckedClose) # print collected messages $pod .= <<"EoHelp"; === Warning and error messages === = Messages numbers and texts used in $cfg{'me'} and its own modules. = Note that message texts may contain variables, like '\$key', which are = replaced with propper texts at runtime. # TODO: some missing, i.e. 002: 003: 004: EoHelp $pod .= _man_head(15, "Error/Warning", "Message text"); $pod .= $txt; $pod .= _man_foot(15); # TODO: return if (($cfg{'out'}->{'warning'} + $cfg{'out'}->{'hint'}) < 2); return $pod; } # man_warnings sub man_opt_help { #? print program's --help* options _man_dbx("man_opt_help() .."); 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; $txt = _man_squeeze(undef, $txt); return $txt; } # man_opt_help sub man_ciphers_html{ #? print ciphers in HTML format my $txt = shift; _man_dbx("man_ciphers_html() .."); my $cnt = scalar(keys %ciphers); my $htm = $html{'doctype'} . '' . $html{'meta'} . '' . << "EoHTML";

    $html{'title'} table <> list

    $cnt Cipher Suites

    EoHTML $htm .= _man_ciphers_html_tb($txt); $htm .= ''; return $htm; } # man_ciphers_html sub man_ciphers_list{ #? print ciphers in HTML format my $txt = shift; _man_dbx("man_ciphers_html() .."); my $cnt = scalar(keys %ciphers); my $head= $html{'meta'}; my $htm = $html{'doctype'} . '' . $html{'meta'} . '' . << "EoHTML";

    $html{'title'} table <> list

    $cnt Cipher Suites

    EoHTML $htm .= _man_ciphers_html_ul($txt); $htm .= ''; return $htm; } # man_ciphers_list sub man_ciphers_text{ #? print ciphers in simple line-based text format my $txt = shift; my $keys= ""; _man_dbx("man_ciphers_text() .."); if (0 < $VERBOSE) { foreach my $key (keys %OSaft::Ciphers::ciphers_desc) { next if "additional_notes" eq $key; $keys .= "#\t$key\t$OSaft::Ciphers::ciphers_desc{$key}\n"; } } # _man_head() and _man_food() doesn't make sense here foreach my $key (keys %OSaft::Ciphers::ciphers_desc) { # convert internal keys to human readable text # $key must be followed by white space $txt =~ s/\n$key\s/\n\t$OSaft::Ciphers::ciphers_desc{$key}\t/g; } my $note= $OSaft::Ciphers::ciphers_desc{'additional_notes'}; $note=~ s/\n/\n= /g; # add text for note with usual = prefix # see also %ciphers_desc in OSaft::Ciphers.pm; return "$keys$txt$note\n"; } # man_ciphers_text sub man_ciphers { #? print ciphers, $typ denotes type of output: text or html # see also https://ciphersuite.info/cs/ my $typ = shift;# text or html _man_dbx("man_ciphers($typ) .."); my $txt = _man_ciphers_get(); return man_ciphers_html($txt) if ('html' eq $typ); return man_ciphers_list($txt) if ('list' eq $typ); return man_ciphers_text($txt) if ('text' eq $typ); return ""; } # man_ciphers 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/;# normalise: cipherrange and range are possible my $pod = ""; _man_dbx("man_table($typ) .."); my %types = ( # typ header left separator header right #-----------+---------------+-------+------------------------------- '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 { 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) $sep = "=" if ($typ =~ m/(?:^cfg[_-]|[_-]cfg$)/); } else { # this is a programming error, hence always printed on STDERR print STDERR "**WARNING: 510: unknown table type '$typ'; using 'text' instead.\n"; return $pod; # avoid uninitialised value; return as no data for $typ is available } } _man_dbx("man_table($typ) ..."); if ($typ !~ m/^cfg/) { $pod .= _man_head(16, $types{$typ}->[0], $types{$typ}->[2]); } # first only lists, which cannot be redefined with --cfg-*= (doesn't make sense) TABLE: { if ($typ =~ m/(abbr|links?|rfc)/) { $pod .= _man_doc_opt($typ, $sep, 'opt'); # abbr, rfc, links, ... last; } if ($typ eq 'compl') { $pod .= _man_opt($_, $sep, $cfg{'compliance'}->{$_}) foreach (sort keys %{$cfg{'compliance'}}); last; } if ($typ eq 'intern') { # first list command with all internal commands_* foreach my $key (sort keys %cfg) { next if ($key !~ m/^commands_(?:.*)/); $pod .= _man_opt($key, $sep, "+" . join(' +', @{$cfg{$key}})); } foreach my $key (sort keys %cfg) { next if ($key !~ m/^cmd-(.*)/); $pod .= _man_opt("cmd-" . $1, $sep, "+" . join(' +', @{$cfg{$key}})); } last; } # 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} || ""; # "" to avoid "Use of uninitialized value ..." if ('ARRAY' eq ref($cfg{$list}->{$key})) { $txt = join("\t", @{$cfg{$list}->{$key}}); } if ('range' eq $typ) { $txt =~ s/ */ /g; # adjust leading spaces } $pod .= _man_cfg($typ, $key, $sep, $txt); } last; } if ($typ =~ m/cmd/) { foreach my $key (sort keys %cfg) { next if ($key !~ m/^cmd-/); $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 configuring the # key in RC-FILE it looks like --cfg_cmd=sni= ... $pod .= _man_cfg($typ, $key, $sep, $txt); } last; } if ($typ =~ m/check/) { foreach my $key (sort keys %checks) { $pod .= _man_cfg($typ, $key, $sep, $checks{$key}->{txt}); } last; } if ($typ =~ m/(?:data|info)/) { foreach my $key (sort keys %data) { $pod .= _man_cfg($typ, $key, $sep, $data{$key}->{txt}); } last; } if ($typ =~ m/text/) { foreach my $key (sort keys %text) { #_dbx "$key : " . ref($text{$key}); if ('' eq ref($text{$key})) { # string $pod .= _man_txt($typ, $key, $sep, $text{$key}); } 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}; # $pod .= _man_txt($typ, "$key($k)", $sep, $txt); #} } } last; } } # TABLE if ($typ !~ m/cfg/) { $pod .= _man_foot(16); } else { # additional message here is like a WARNING or Hint, # do not print it if any of them is disabled $pod .= <<"EoHelp" if (($cfg{'out'}->{'warning'} + $cfg{'out'}->{'hint'}) > 1); = 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 $pod; } # 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 # _man_dbx("man_alias() .."); my $pod = "\n" . _man_head(27, "Alias (regex) ", "command or option # used by ..."); my $txt = ""; my $fh = undef; my $p = '[._-]'; # regex for separators as used in o-saft.pl if (open($fh, '<:encoding(UTF-8)', _get_filename("o-saft.pl"))) { # need full path for $parent file here # TODO: o-saft.pl hardcoded, need a better method to identify the proper file 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 # check if alias is command or option if ($alias !~ m/^[+-]/) { # look not like command or option, use comment $alias = $commt if ($commt =~ m/^[+-]/); } if (29 > length($regex)) { $txt = sprintf("%-29s%-21s# %s\n", $regex, $alias, $commt); } else { # pretty print if regex is to large for first column $txt = sprintf("%s\n", $regex); $txt .= sprintf("%-29s%-21s# %s\n", "", $alias, $commt); } $pod .= _man_squeeze(29, $txt); } close($fh); ## no critic qw(InputOutput::RequireCheckedClose) } $pod .= _man_foot(27); $pod .= <<'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 $pod } # man_alias sub man_options { #? 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 # no need for _man_squeeze() return join('', "OPTIONS\n", splice(@txt, 0, $end)); # print anything before end } # man_options sub man_toc { #? print help table of contents my $typ = lc(shift) || ""; # || to avoid uninitialised value my $toc; _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 *(.*)/{ $toc .= "--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]) *(.*)/{ $toc .= " " x $1 . $2 . "\n"}/e; # use number from =head as ident } # TODO: $toc = _man_squeeze(6, $txt); # not really necessary } return $toc; } # man_toc sub man_pod { #? print complete POD page for o-saft.pl --help=gen-pod _man_dbx("man_pod() ..."); return _man_pod_head() . _man_pod_text() . _man_pod_foot(); } # man_pod sub man_man { #? print complete MAN page for o-saft.pl --help=gen-man # executable pod2man is used instead of Pod::Man, mainly because Pod::Man # can only read from STDIN or a file, but input here for Pod::Man may come # from variables; _man_dbx("man_man() ..."); my $pod = "o-saft.pod"; # TODO: dirty hack to find proper .pod file $pod = "docs/o-saft.pod" if (! -e $pod); $pod = "../docs/o-saft.pod" if (! -e $pod); exec("pod2man --name=o-saft.pl --center='OWASP - SSL advanced forensic tool' --utf8 $pod" ); # return; } # man_man 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() ..."); return _man_http_head() . _man_html_head() . _man_html('html', 'NAME', 'TODO') . # print complete help _man_html_foot(); } # 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"; _man_dbx("man_cgi() ..."); return _man_http_head() . _man_html_head() . _man_html_form() . $html{'warning_box'} . # not exactly the place in HTML for this
    , but syntactically ok _man_html_foot(); # TODO: osaft_action_http, osaft_action_file should be set dynamically } # man_cgi sub man_wiki { #? print documentation for o-saft.pl in mediawiki format (to be used at owasp.org until 2019) #? 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) ..."); return _man_wiki_head() . _man_wiki_text($mode) . _man_wiki_foot(); } # man_wiki sub man_help { #? print complete user documentation for o-saft.pl as plain text (man-style) # called when no special help, prints full help text or parts of it my $label = lc(shift) || ""; # || to avoid uninitialised value my $anf = uc($label); my $end = "[A-Z]"; my $hlp; _man_dbx("man_help($anf, $end) ..."); if (0 < $::osaft_standalone) { ## no critic qw(Variables::ProhibitPackageVars) # in standalone mode use $0 instead of $parent (which is "O-Saft") @help = OSaft::Doc::Data::get_markup("help.txt", $0, $version); } my $txt = join ('', @help); # = OSaft::Doc::Data::get("help.txt", $parent, $version); if (1 < (grep{/^--v/} @ARGV)) { # with --v --v return OSaft::Doc::Data::get_egg("help.txt"); } 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 $txt = _man_squeeze(undef, $txt); 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"; $hlp .= $_ foreach split(//, $txt); # print character by character :-(( } else { $hlp .= $txt; } if ($label =~ m/^todo/i) { $hlp .= "\n NOT YET IMPLEMENTED\n"; foreach my $label (sort keys %checks) { next if (0 >= _is_member($label, \@{$cfg{'commands_notyet'}})); $hlp .= " $label\t- " . $checks{$label}->{txt} . "\n"; } } return $hlp; } # man_help sub man_src_grep { #? search for given text in source file, then pretty print my $hlp = shift; my $pod = "\n"; $pod .= _man_head(14, "Option ", "Description where program terminates"); my $fh = undef; if (open($fh, '<:encoding(UTF-8)', _get_filename("o-saft.pl"))) { # need full path for $parent file here # TODO: o-saft.pl hardcoded, need a better method to identify the proper file 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; } $pod .= sprintf("%-15s%s\n", $opt, $comment); } close($fh); ## no critic qw(InputOutput::RequireCheckedClose) } $pod .= _man_foot(14); return $pod; } # man_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; my $txt; _man_dbx("printhelp($hlp) ..."); _man_use_tty(); _man_html_init(); # must be called here, because function may be call anywhere # NOTE: some lower case strings are special $txt = man_help('NAME') if ($hlp =~ /^$/); ## no critic qw(RegularExpressions::ProhibitFixedStringMatches) $txt = man_help('TODO') if ($hlp =~ /^todo$/i); ## no critic qw(RegularExpressions::ProhibitFixedStringMatches) $txt = man_help('KNOWN PROBLEMS') if ($hlp =~ /^(err(?:or)?|problem)s?$/i); $txt = man_help('KNOWN PROBLEMS') if ($hlp =~ /^faq/i); $txt .= man_help('LIMITATIONS') if ($hlp =~ /^faq/i); print man_help($hlp) if ($hlp =~ /^(?:CHECKS?|CUSTOM)$/); # case-sensitive! return if ($hlp =~ /^(?:CHECKS?|CUSTOM)$/); # ugly, but there is 'check' below # 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 all performed # checks. Workaround is to treat all-uppercase words as head- # line of a section (see matches above), and anything else as # special meaning (see matches below). # all following matches against $hlp are exact matches, see ^ and $ # hence exactly one match is expected $hlp = lc($hlp); # avoid i in regex $txt = man_toc($1) if ($hlp =~ /^((?:toc|contents?)(?:.cfg)?)$/); $txt = man_html() if ($hlp =~ /^(gen-)?html$/); $txt = man_wiki('colon') if ($hlp =~ /^(gen-)?wiki$/); $txt = man_pod() if ($hlp =~ /^(gen-)?pod$/); $txt = man_man() if ($hlp =~ /^(gen-)?man$/); $txt = man_man() if ($hlp =~ /^(gen-)?[nt]roff$/); $txt = man_cgi() if ($hlp =~ /^(gen-)?cgi$/); $txt = man_ciphers('text') if ($hlp =~ /^(gen-)?-?ciphers$/); $txt = man_ciphers('text') if ($hlp =~ /^(gen-)?-?ciphers.?text$/); $txt = man_ciphers('list') if ($hlp =~ /^(gen-)?-?ciphers.?list$/); $txt = man_ciphers('html') if ($hlp =~ /^(gen-)?-?ciphers.?html$/); $txt = man_alias() if ($hlp =~ /^alias(es)?$/); $txt = man_commands() if ($hlp =~ /^commands?$/); $txt = man_options() if ($hlp =~ /^opts?$/); $txt = man_warnings() if ($hlp =~ /^warnings?$/); $txt = man_opt_help() if ($hlp =~ /^help$/); $txt = man_help_brief() if ($hlp =~ /^help[_.-]brief$/); # --h $txt = man_table('rfc') if ($hlp =~ /^(gen-)?rfcs?$/); $txt = man_table('links') if ($hlp =~ /^(gen-)?links?$/); $txt = man_table('abbr') if ($hlp =~ /^(gen-)?(abbr|abk|glossary?)$/); $txt = man_table('compl') if ($hlp =~ /^compliance$/);# alias $txt = man_table($1) if ($hlp =~ /^(compl|hint|intern|pattern|range|regex)s?$/); $txt = man_table($1) if ($hlp =~ /^(cipher[_.-]?(?:pattern|range|regex|ourstr)?)s?$/); # anything below requires data defined in parent $txt = man_table($1) if ($hlp =~ /^(cmd|check|data|info|ourstr|text)s?$/); $txt = man_table('cfg_'.$1) if ($hlp =~ /^cfg[_.-]?(cmd|check|data|info|hint|text|range|regex|ourstr)s?$/); $txt = man_src_grep("exit=")if ($hlp =~ /^exit$/); if ($hlp =~ /^cmds$/) { # print program's commands $txt = "# $parent commands:\t+" . join(' +', @{$cfg{'commands'}}); # no need for _man_squeeze() } if ($hlp =~ /^legacys?$/) { # print program's legacy options $txt = "# $parent legacy values:\t" . join(' ', @{$cfg{'legacys'}}); # no need for _man_squeeze() } if ($hlp =~ m/^tools$/) { # description for O-Saft tools my @txt = OSaft::Doc::Data::get("tools.txt", $parent, $version); #$txt = _man_squeeze(undef, "@txt"); # TODO: does not work well here $txt = join("", @txt); } if ($hlp =~ m/^Program.?Code$/i) { # print Program Code description my @txt = OSaft::Doc::Data::get("coding.txt", $parent, $version); #$txt = _man_squeeze(undef, "@txt"); # TODO: does not work well here $txt = join("", @txt); } if (not $txt) { # nothing matched so far, print special section from help _man_dbx("printhelp: " . uc($hlp)); $txt = man_help(uc($hlp)) if ($hlp !~ m/^[+-]-?/); # bare words only } print $txt || ""; return; } # printhelp #_____________________________________________________________________________ #_____________________________________________________________________ main __| sub _main_man { #? print own documentation or special required one push(@ARGV, "--help") if 0 > $#ARGV; # SEE Perl:binmode() binmode(STDOUT, ":unix:utf8"); ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) binmode(STDERR, ":unix:utf8"); ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) while (my $arg = shift @ARGV) { # --help and --gen-docs is special, anything els handled in printhelp() #TODO: __FILE__ must be __PACKAGE__ if this file is a perl module print_pod($0, __FILE__, $SID_man) if ($arg =~ m/--?h(?:elp)?$/x); # ----------------------------- options if ($arg =~ m/^--(?:v|trace.?CMD)/i) { $VERBOSE++; next; } # allow --v # ----------------------------- commands if ($arg =~ /^version$/) { print "$SID_man\n"; next; } #if ($arg =~ /^[-+]?V(ERSION)?$/) { print "$VERSION\n"; next; } man_docs_write() if ($arg =~ m/--(?:help=)?gen[_.=-]?docs/x); # testing this module is technically the same as getting the text $arg =~ s/--help[_.=-]?//; # allow --help=* and simply * $arg =~ s/--test[_.=-]?//; # allow --test-* also, next if ($arg =~ m/^[+-]-?/); # ignore other options printhelp($arg); } exit 0; } # _main_man sub 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 * *roff (man page) =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($format); # in Perl code =item * o-saft-man.pm --help # on command-line will print help =item * o-saft-man.pm [<$format>] # on command-line =back For compatibility with other programs and modules it also supports: =over 2 =item * o-saft-man.pm --help=<$format> =item * o-saft-man.pm --test-<$format> =back =head1 METHODS =over 2 =item * printhelp($format) Public method for all functionality. The generated output format depends on the $format parameter, which is a literal string, as follows: =over 2 =item * pod -> all documentation in POD format =item * man -> all documentation in MAN (nroff) 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 * ciphers-text -> list all ciphers with all information in text format =item * ciphers-list -> list all ciphers with all information in HTML list format =item * ciphers-html -> list all ciphers with all information in HTML table 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 * hint -> list texts used in !!Hint messages =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 * error -> show known problems about warning and error messages =item * warnings -> show used message texts for warnings and errors =item * intern -> show internal grouped commands =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. The I<--header> option can be used for simple formatting. 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 VERSION 2.84 2022/11/21 =head1 AUTHOR 14-nov-14 Achim Hoffmann =cut ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main_man(@ARGV) if (not defined caller); 1; # SEE Note:Documentation (in o-saft.pl) __END__ =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 variables (like $a) should be localised in 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 derived 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 need to be completed. These special sections are mainly identified by lines starting as follows: Commands for ... Commands to ... Discrete commands to test ... Options for ... Options 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 separate statement. =head3 POD:Dragons POD's =head2 cannot contain () literally, it needs at least one space between ( and ) , otherwise formatting will be wrong. POD's CE$somethingE does not print "$something" but simply $something unless $somthing contains = or * character, i.e. $some=thing. Hence we use IE$somethingE instead. POD does not support nested formatting, at least no prober syntax could be found. =head2 Cipher:text The list of available ciphers is defined in %ciphers . In that hash texts and values may have some special syntax optimised for programmatic use. For human readability the ciphers and their descriptions can be printed in a simple line-based format as text or HTML, and can be printed as table in HTML format. Before printing the required format, the %ciphers hash will be converted to a simple (intermediate) format. The result is plain text which contains the data for each cipher and looks like for example: 0x00,0x3D HIGH AES256-SHA256 name AES256-SHA256 names const RSA_WITH_AES_256_SHA256, RSA_WITH_AES_256_CBC_SHA256 openssl HIGH ssl TLSv12 keyx RSA auth RSA enc AES bits 256 enc_size 128 mac SHA256 mac_size PFS - rfcs https://www.rfc-editor.org/rfc/rfc5246 notes L Here the first line contains the hex code, security and cipher suite name, while all following consist of a tab-seperated key-value pair. This intermediate data then can be converted to the final output data. For example as plain text: 0x00,0x3D HIGH AES256-SHA256 OpenSSL Name: AES256-SHA256 Name Aliases: Constant Names: RSA_WITH_AES_256_SHA256, RSA_WITH_AES_256_CBC_SHA256 OpenSSL STRENGTH: HIGH TLS Version: TLSv12 Key Exchange: RSA Authentication: RSA Encryption Type: AES Encryption Size: 256 MAC / Hash Type: SHA256 MAC / Hash Size: 256 RFC(s) URL: https://www.rfc-editor.org/rfc/rfc5246 Comments/Notes: L =head2 Cipher:HTML As explained in L above, the intermediate data of ciphers can also be used to convert to HTML format. The generated output contains the ciphers as simple list and as table with one cipher suite per row. It is possible to toggle between these formats. =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 that 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 |+--------------------------------------------------------------------+ | || Hostname: [_________________________________] [+check] 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 | | ||| [^] [start] 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 interface (form in the web page) consist of following sections, marked with a single character: T title H line with buttons opening a 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 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 should only be send on the form's submit if the value is not empty. The setting 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 formatting 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 a paragraph like:

    ...

    . These paragraphs are generated in '_man_html()'. This allows to extract the description text stored in the paragraph, using JavaScript after generating the page. 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). =head2 HTML:Known Bugs Our options and commands (like +cipher --help) are not detected in lists. =cut O-Saft-22.11.22/o-saft-usr.pm000077500000000000000000000143461433765727300154240ustar00rootroot00000000000000#!/usr/bin/perl ## PACKAGE { #!# Copyright (c) 2022, Achim Hoffmann #!# This software is licensed under GPLv2. Please see o-saft.pl for details. package main; # ensure that main:: variables are used ## no critic qw(Documentation::RequirePodSections) # SEE Perl:perlcritic use strict; use warnings; 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! BEGIN { # mainly required for testing ... # SEE Perl:BEGIN perlcritic my $_path = $0; $_path =~ s#[/\\][^/\\]*$##x; unshift(@INC, $_path) if (1 > (grep{/^$_path$/} @INC)); unshift(@INC, "..") if (1 > (grep{/^\.\.$/} @INC)); unshift(@INC, ".") if (1 > (grep{/^\.$/} @INC)); } use OSaft::Text qw(%STR print_pod); use osaft; my $SID_usr = "@(#) o-saft-usr.pm 2.6 22/10/31 20:24:01"; #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =encoding utf8 =head1 NAME o-saft-usr.pm - module for o-saft.pl's user definable functions =head1 SYNOPSIS =over 2 =item require q{o-saft-usr.pm}; # in perl code =item o-saft-usr.pm --help # on command-line will print help =back =head1 DESCRIPTION Defines all functions for user customisation. 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 initialising internal data. =item usr_pre_file( ) At beginning, right after initialising internal data. =item usr_pre_args( ) Right before reading command-line arguments. All internal structures and variables are initialised, 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. =item usr_version() Return version of this interface. =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() {} =cut #_____________________________________________________________________________ #__________________________________________________________________ methods __| 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"; } # changed only if fucntionality changed! 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 _main_usr { my $arg = shift || "--help"; # without argument print own help ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # see t/.perlcriticrc for detailed description of "no critic" # SEE Perl:binmode() binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); print_pod($0, __FILE__, $SID_usr) if ($arg =~ m/--?h(elp)?$/x); # no other options implemented yet print "$SID_usr\n" if ($arg =~ /^version$/); #print "$VERSION\n" if ($arg =~ /^[-+]?V(ERSION)?$/); exit 0; } # _main sub usr_done {}; # dummy to check successful include =pod =head1 VERSION 2.6 2022/10/31 =head1 AUTHOR 13-nov-13 Achim Hoffmann =cut ## PACKAGE } # local functions { # ------------------------------------- # local functions } #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main_usr(@ARGV) if (not defined caller); 1; O-Saft-22.11.22/o-saft.cgi000077500000000000000000000473141433765727300147440ustar00rootroot00000000000000#!/usr/bin/perl #!# Copyright (c) 2022 Achim Hoffmann #!# This software is licensed under GPLv2. Please see o-saft.pl for details. ## no critic qw(RegularExpressions::ProhibitComplexRegexes) ## no critic qw(RegularExpressions::RequireExtendedFormatting) # because we use /x as needed for human readability (may change in future) ## no critic qw(RegularExpressions::RequireLineBoundaryMatching) # hmm, we're matching only on line here (Severity: 2) ## no critic qw(RegularExpressions::RequireDotMatchAnything) # hmm, we're matching only on line here (Severity: 2) ## no critic qw(Variables::ProhibitPunctuationVars) # we make regular use of these variables as we know them;-) (Severity: 2) ## no critic qw(ControlStructures::ProhibitPostfixControls) # we believe that postfix control make some code more readable (Severity: 2) =pod =head1 NAME o-saft.cgi - wrapper script to start o-saft.pl as CGI script =head1 DESCRIPTION Calls o-saft.pl if first parameter is I<--cgi> and prints its result as plain text. The result is prefixed with proper HTTP headers. Some parameters are silently ignored (removed from argument list), i.e: --dump --exec --list --libversion --version --trace* --v --ca* Some lazy checks according parameters are done, exits silently if any of following will be found: =over 4 =item * not allowed characters in parameters, allowed are: a-zA-Z0-9,.:_&\!\/=\+- =item * not allowed options: --env* --exe* --lib* --call* --openssl* =item * illegal hostnames or IPs: localhost, *.local, (0|10|127|169|172|192|224|240|255).X.X.X =item * any IP notation other than "dotted decimal" are illegal: * https://0127.00.000.01/ - octal IP address * https://0x7f000001/ - hexadecimal IP address * https://2130706433/ - integer or DWORD IP address * https://0x0b.026.8492/ - any mixed notation =item * any IPv6 addresses in URLs =item * any octal (prefix 0) or hex (prefix 0x) notation in IP addresses: 0x0b.026.8492 =back To get a list of RegEx for invalid parameters, please use: grep qr/ o-saft.cgi where $key is --(host|url)= =head1 OPTIONS, PARAMETERS =over 4 =item --cgi Must be used as first parameter, otherwise dies. =item --format=html Sends HTTP header: Content-type: text/html;charset=utf-8 and convert output to HTML format using contrib/HTML-table.awk . =item --content-type=html Forces to sends HTTP header: Content-type: text/html;charset=utf-8 =item --cgi-no-header Omit all HTTP headers (useful if headers are added by web server). =back =head1 DEBUG If the environment variable I is set, detailed error messages are printed. In particular, it prints the RegEx matching any of the dangerous parameters (i.e. hostname or IP). This is only useful for testing on command line. It's not intended to be used when run as a CGI script in a web server. As it is not possible to set environment variables for the CGI script by the client (browser), the code should be safe. =head1 EXAMPLES 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 For debugging only, call from command line: env OSAFT_CGI_TEST=1 --cgi --host=localhost --cmd=cn o-saft.cgi =head1 SEE ALSO =head2 L =head1 AUTHOR 12-sep-12 Achim Hoffmann =cut use strict; use warnings; my $SID_cgi = "@(#) o-saft.cgi 1.67 22/10/27 22:39:21"; my $VERSION = '22.06.22'; my $me = $0; $me =~ s#.*/##; my $mepath = $0; $mepath =~ s#/[^/\\]*$##; $mepath = './' if ($mepath eq $me); my $header = 1; 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 _print_if_test { #? print text if environment variable OSAFT_CGI_TEST is set local $\ = "\n"; print @_ if (defined $ENV{'OSAFT_CGI_TEST'}); return; } # _print_if_test sub _warn_and_exit { #? print error and exit my $txt = shift; _print_if_test "**ERROR: $txt"; # #################################################################### # # This function should print an empty string and exit with status 0 in # production environments. # Printing above detailed error message is safe, see POD above. # # #################################################################### print ""; exit 0; } # _warn_and_exit if (not $ENV{'QUERY_STRING'}) { print "**WARNING: test mode: restart using args as value in QUERY_STRING\n"; _warn_and_exit "call without parameters" if (1 > $#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, which results in a # Server 500 error in the web server; that's ok here for testing ## 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: # * URL-decode once: QUERY_STRING and POST data # * 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 by calling $osaft # NOTE: in true CGI-mode, QUERY_STRING just contains the form fields, # when used with our own osaft: schema, the QUERY_STRING also # contains 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() as it may break the HTTP response my $cgi = 0; my $typ = 'plain'; my $qs = ''; $qs = $ENV{'QUERY_STRING'} if (defined $ENV{'QUERY_STRING'}); #dbx# system "echo 'QS=$qs #' >> /tmp/osaft.cgi.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=@argv' >> /tmp/osaft.cgi.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=?$/); # TODO: check if following RegEx need $ at end $typ = 'html' if ($qs =~ m/--format=html/); # --format=html already in @argv $header = 1 if (0 < (grep{/--cgi.?header/} $qs)); $header = 0 if (0 < (grep{/--cgi.?no.?header/} $qs)); $header = 0 if (0 < (grep{/--no.?cgi.?header/} $qs)); if (0 < $header) { my $_typ = $typ; # check if force using text/html $_typ = 'html' if ($qs =~ m/--content-type=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.67\r\n"; print "Content-type: text/$_typ; charset=utf-8\r\n";# for --usr* only print "\r\n"; } _print_if_test "**WARNING: test mode: die with detailed messages on errors"; if (defined $ENV{'REQUEST_METHOD'}) { # ToDo: NOT WORKING $qs .= <> if ($ENV{'REQUEST_METHOD'} eq 'POST');# add to GET data } # check for potential dangerous commands and options, simply ignore # (just remove) them; examples: # --cgi&--cmd=dump # ignore # --cgi&--cmd=+dump # ignore # --cgi&--url=+dump # ignore # --cgi&--trace= # ignore # --cgi&--opt=--trace= # ignore # --cgi&--unknown=--v= # ignore # also fix trailing = my $ignore = qr/ ^--(?: # illegal commands and options (?:cmd|url)=[+]?(?:dump|exec|list|libversion|version) |(?:cmd|url)=--(?:trace|--v) # illegal options given as URL # illegal options |trace|v # options to verbose output |ca[._-]?(?:file|path)|rc= # may be used to enumerate paths )|=(?: # illegal commands as parameter value [+]?(?:dump|exec|list|libversion|version) # illegal options as parameter value |--(?:trace|--v) |--ca[._-]?(?:file|path)|rc= )/xi; # o-saft.pl splits key=value arguments at = , if 'key' is an # unknown option then 'value' turns into a valid command or # option argument; see o-saft.pl's argument parser #dbx# system "echo 'argv=@argv' >> /tmp/osaft.cgi.log"; my @save_argv; foreach my $arg (@argv) { #dbx# print "#dbx: $arg # silently ignored\n" if ($arg =~ m#$ignore#); next if ($arg =~ m#$ignore#); # quick&dirty fix generated parameters also: # in o-saft.cgi.html there may be parameter names like: # --lagacy=owasp # as these are input tags with type checkbox, the value is # empty, hence the parameter passed in is like: # --lagacy=owasp= # because the input tag's value is empty; this would result # in passing the value owasp= instead of owasp for the # the paramter name legacy ; the trailing = is removed $arg =~ s#=$##; # remove trailing = in key=value push(@save_argv, $arg); } _print_if_test "**ARGS_in: @argv"; _print_if_test "**ARGSuse: @save_argv"; @argv = @save_argv; #dbx# system "echo 'argv=@argv' >> /tmp/osaft.cgi.log"; # check for suspicious characters and targets, die if any # Matches against QUERY_STRING (in $qs), which still contains the # usual separator & . The first parameter in $qs must be --cgi, all # others must be prefixed with & . Hence most pattern start with & # to avoid matches inside a valid parameter, for example: # --cgi&--host=a42&--cmd=cn # ok # --cgi&--host=42&--cmd=cn # bad # --cgi&--cmd=cn&--host=42 # bad # --cgi&--cmd=cn&=42 # bad # --cgi&--cmd=cn&--other-opt=42 # ok # FIXME: last example will be detected as malicious and dies, this is # a false positive, bug here # NOTE: Technically & may be a ? too, it is not really RFC compliant, # but possible. Someone may sends malicious data. my $err = 0; my $key = '&--(?:host|url)='; foreach my $dangerous ( 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/&--(?:env|exe|lib|call|openssl)/i, qr/=--(?:env|exe|lib|call|openssl)/i, # see comment for $ignore above # 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 # 10.0.0.0 .. 10.255.255.255 # 100.64.0.0/10 CGN - Carrier- Grade NAT # 100.64.0.0 .. 100.127.255.255 # 127.0.0.0/8 Loopback # 127.0.0.0 .. 127.255.255.255 # 169.254.0.0/16 Link local # 169.254.0.0 .. 169.254.255.255 # 172.16.0.0/12 Private-Use Networks # 172.16.0.0 .. 172.31.255.255 # 192.0.0.0/24 IETF Protocol Assignments # 192.0.0.0 .. 192.0.0.255 # 192.0.2.0/24 TEST-NET-1 # 192.0.2.0 .. 192.0.2.255 # 192.88.99.0/24 6to4 Relay Anycast # 192.88.99.0 .. 192.88.99.255 # 192.168.0.0/16 Private-Use Networks # 192.168.0.0 .. 192.168.255.255 # 198.18.0.0/15 Network Interconnect, # Device Benchmark Testing # 198.18.0.0 .. 198.19.255.255 # 198.51.100.0/24 TEST-NET-2 # 198.51.100.0 .. 198.51.100.255 # 203.0.13.0/24 TEST-NET-3 # 203.0.13.0 .. 203.0.13.255 # 224.0.0.0/4 Multicast # 224.0.0.0 .. 239.255.255.255 # # https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml # 240.0.0.0/4 Reserved for future use # 240.0.0.0 .. 255.255.255.255 # 255.255.255.255/32 Limited Broadcast # fe80: IPv6 link local # fe[c-f][0-9a-f]: IPv6 site local # ff0[0-9a-f]|f[c-d][0-9a-f][0-9a-f]: IPv6 multicast or unique local unicast (RFC6762) # 64:::IP IPv4-mapped IPv6 addresses as NAT64 (RFC6052): 64:ff9b::192.0.2.128 # ::::IP IPv4-mapped IPv6 addresses: ::ffff:192.0.2.128 # 127.1 127.0.1 IPv4 abbreviated # TODO: better, more accuarte checks # ::1/128 localhost # fe80::/64 link local # ff00::/8 ULA - Unique Local Address # ff00::0/8 Multicast # fd00::/8 Unique Local Address, not routable # fc00::/7 ? Global Unique Address # ::ffff:0:0/96 IPv4 mapped addresses # ::ffff:0:0:0/96 IPv4 translated addresses (SIIT protocol) # 64:ff9b::/96 6to4 addressing # 2000::/3 # 2001::/16 GUA - Global Unique Address, routable! # 2001::/32 Teredo tunneling (RFC 4380) # 2001:2:::/48 Reserved for Benchmarking Methodology Working Group # 2001:20::/28 ORCHIDv2 crypto hash identifiers, not routable # 2001:db8::/32 ? Documentation # ff02::2 Neighbor Discovery Protocol # match IPv4: ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4} # match IPv6: ([0-9a-f]{0,4}:){1,8} # match 1234567890: IP as integer not yet allowed # match IPv4: less than 4 parts for dotted IP # TODO: build a map of integer ranges for IPs to be denied: # 10.x.x.x = 167772161 .. 184549375 # 127.x.x.x = 2130706433 .. 2147483647 # ... # then check given host againts this map if conversion to # an integer is succesful. # It will also work for mixed IPv6-IPv4 IPs like: # ::ffff:127.0.0.1 which is an alias for ::ffff:7f00:1. # This should eliminate some of the restriction (missing) # of RegEx (see NOTEs below). # Unfortunately Math::BigInt is required (breaks usage on # ancient systems). # hex IP addresses may look like: # 127.0xb.0.1 127.0x00000b.0.1 # octal IP addresses may look like: # 0127.000000002.0.1 # i.g. each octet is prefixed with 0, followed by any amount of # 0, followed by [1-4] (may be missing), followed by [0-7][0-7] # NOTE: octal addresses are not bad in general, but the checks # below expect only CIDR numbers in decimal notation, hence # any occourance of octal numbers are rejected # NOTE: according following RegExs # - grouping with back reference is used insted of (?: ... ) # sometimes, this is because : is used literally in RegExs # - RegExs are not case sensitive to match FQDN and (hex) IP, # but this also allows --URL= --HOST= (which is ok) # - sequence of following RegExs is important, more specific # ones first # - the leeading option like --host= is optional as the word to # be checked may be passed without key, something like: # --cgi&--host=good.FQDN&localhost&--enabled= # - IPv4 matching is lazy with [0-9]+ qr/(?:&(localhost|10|127|224(.[0-9]){1,3}|(ffff)?::1|(ffff:)?7f00:1)(&|$))/i, # first match bare hostname argument without --host= # this avoids false positive matches in more lazy RegEx # FIXME: probably necessary for all following RegEx # NOTE: also bad 127.666 (= 127.0.2.154) qr/(?:(?:$key)?((?:0?127|0x0?7f).[0-9afx.]+))/i, # any 127.* qr/(?:(?:$key)?[0-9.]*(?:(0+[1-4]?[0-7]{1,2}[.])|([.]0+[1-4]?[0-7]{1,2})))/, # octal addresses are always ignored qr/(?:(?:$key)?[0-9x.]*(?:(0x0*[0-9af]{1,2}[.])|([.]0x0*[0-9af]{1,2})))/i, # hex addresses are always ignored qr/(?:(?:$key)?((10|224).[0-9]+(.[0-9]{1,3})?))/i, # abbreviated IPv4: 10.1 10.41.1 10.0.1 224.1 qr/(?:(?:$key)(localhost|::1|ffff::1|(ffff:)?7f00:1)(&|$))/i, # localhost # TODO: IPv6 localhost: [7f00:1] .. [7fff:ffff] qr/(?:(?:$key)?((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: to pedantic: 100.64.0.0/10 CGN is not really class B qr/(?:(?:$key)?((ffff:)?(192\.0\.[02]|192.88\.99|198\.51\.100|203\.0\.13)\.[\d]+))/i, # common class C RFC networks for private use qr/(?:(?:$key)?((ffff:)?(0|10|22[4-9]|23[0-9]|24[0-9]|25[0-5])\.[\d]+.[\d]+.[\d]+))/i, # loopback, mulicast qr/(?:(?:$key)?((fe80|fe[c-f][0-9a-f]:)))/i, # IPv6 link local or site local qr/(?:(?:$key)?((ff0[0-9a-f]|f[c-d][0-9a-f][0-9a-f]:)))/i, # IPv6 multicast or unique local unicast (RFC6762) qr/(?:(?:$key)?64:([0-9a-f]{1,4}:){1,2}:(&|$))/i, # any IPv4-mapped IPv6 addresses as NAT64 (RFC6052): 64:ff9b:: qr/(?:(?:$key)?64:([0-9a-f]{1,4}:){1,2}:((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})/i, # any IPv4-mapped IPv6 addresses as NAT64 (RFC6052): 64:ff9b::192.0.2.128 # NOTE: would also be matched by next more general RegEx qr/(?:(?:$key)?([0-9a-f]{0,4}:){1,3}((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})/i, # any IPv4-mapped IPv6 addresses: ::ffff:192.0.2.128 # NOTE: ([0-9a-f]{0,4}:){1,3} is lazy, matches also ffff:IP or :IP qr/(?:&[0-9]+(&|$))/i, # just 11111; does not match +11111 or -11111 or --host=11111 qr/(?:(?:$key)[0-9]+(&|$))/i, # just --host=11111 # NOTE: in general not bad, but needs to be mapped to # allowed IPv4 or IPv6 which is not that simple # FIXME: i.e. valid 3221225473 = 192.0.0.1 is denied qr/(?:(?:$key)?.*?\.local(&|$))/i, # multicast domain .local (RFC6762) qr{(?:(?:$key)?([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 ) { if ($qs =~ m#$dangerous#) { _print_if_test "**ERROR: $qs"; _print_if_test "**ERROR: $dangerous"; $err++; } } _warn_and_exit "dangerous parameters; aborted" if 0 < $err; # prepare execution environment local $ENV{LD_LIBRARY_PATH} = "$openssl/lib/"; local $ENV{PATH} = "$openssl/bin/"; $ENV{PATH} .= ':' . $ENV{PATH} if (defined $ENV{PATH}); # defensive programming local $| = 1; # don't buffer, synchronize STDERR and STDOUT # start $osaft #dbx# system "$osaft @argv >> /tmp/osaft.cgi.log"; _print_if_test "$osaft @argv"; if ('html' eq $typ) { # 11/2021 ah: experimental: generate HTML output # need to use system, as exec can't pipe my $cmd = join(" ", $osaft, @argv); #dbx# print "# mepath=$mepath\n"; #dbx# print "# system($cmd | /usr/bin/gawk -f $mepath/contrib/HTML-simple.awk)\n"; system("$cmd | /usr/bin/gawk -f $mepath/contrib/HTML-table.awk"); exit; } exec $osaft, @argv; # exec is ok, as we call ourself only # TODO: Win32 not tested: exec 'perl.exe', $osaft, @argv; } exit 0; # never reached O-Saft-22.11.22/o-saft.php000066400000000000000000000062721433765727300147640ustar00rootroot00000000000000!|$<]/', '', $qs, -1);# remove just a few dangerous characters $exe = get_exe($path['dirname'], 'o-saft.pl', $dirs); $call = join(' ', ['cd', $path['dirname'], ';', $path['basename'], '--cgi', $qs]); #dbx# echo("call=$call\n"); passthru( "$call", $err); # pass QUERY_STRING on command line #dbx# echo "# ERROR=$err\n"; exit(0); ?> O-Saft-22.11.22/o-saft.pl000077500000000000000000016113421433765727300146140ustar00rootroot00000000000000#!/usr/bin/perl #!############################################################################# #!# Copyright (c) 2022, Achim Hoffmann #!#---------------------------------------------------------------------------- #!# 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 Perl:binmode() ## 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; our $SID_main = "@(#) yeast.pl 2.51 22/11/16 10:06:25"; # version of this file my $VERSION = _VERSION(); ## no critic qw(ValuesAndExpressions::RequireConstantVersion) # SEE Perl:constant # see _VERSION() below for our official version number use autouse 'Data::Dumper' => qw(Dumper); #use Encode; # see _load_modules() sub _set_binmode { # set discipline for I/O operations (STDOUT, STDERR) # 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 # return 1 if value in command-line arguments @ARGV sub _is_v_trace { my $rex = shift; return (grep{/--(?:v|trace(?:=\d*)?$)/} @ARGV); } # case-sensitive! SEE Note:ARGV # need to check @ARGV directly as this is called before any options are parsed # SEE Make:OSAFT_MAKE (in Makefile.pod) our $time0 = time(); # must be set very early, cannot be done in osaft.pm $time0 += ($time0 % 2) if (defined $ENV{'OSAFT_MAKE'}); # normalise to even seconds, allows small time diffs sub _yeast_TIME(@) { # print timestamp if --trace-time was given; similar to _y_CMD my @txt = @_; return if (_is_argv('(?:--trace.?(?:time|cmd))') <= 0); my $me = $0; $me =~ s{.*?([^/\\]+)$}{$1}; my $now = time(); $now = time() - ($time0 || 0) if not _is_argv('(?:--time.*absolut)'); $now +=1 if (0 > $now); # fix runtime error: $now == -1 $now += ($now % 2) if (defined $ENV{'OSAFT_MAKE'}); $now = sprintf("%02s:%02s:%02s", (localtime($now))[2,1,0]); if (defined $ENV{'OSAFT_MAKE'}) { # SEE Make:OSAFT_MAKE (in Makefile.pod) $now = "HH:MM:SS (OSAFT_MAKE exists)" if (not $time0);# time0 unset or 0 } printf("#$me %s CMD: %s\n", $now, @txt); return; } # _yeast_TIME sub _yeast_EXIT($) { # exit if parameter matches given argument in @ARGV my $txt = shift; # example: INIT0 - initialisation 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 - initialisation 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 _VERSION() . "\n"; exit 0; } # print VERSION and exit #$DB::single=1; # for debugging; start with: PERL5OPT='-dt' $0 BEGIN { # SEE Perl:BEGIN # SEE Perl:BEGIN perlcritic _yeast_TIME("BEGIN{"); _yeast_EXIT("exit=BEGIN0 - BEGIN start"); sub _VERSION { return "22.11.22"; } # <== our official version number # get official version (used for --help=* and in private modules) my $_me = $0; $_me =~ s#.*[/\\]##; my $_path = $0; $_path =~ s#[/\\][^/\\]*$##; my $_pwd = $ENV{PWD} || "."; # . as fallback if $ENV{PWD} not defined # SEE Perl:@INC #unshift(@INC, "..") if (1 > (grep{/^\.\.$/} @INC)); unshift(@INC, "bin") if (1 > (grep{/^bin$/} @INC)); unshift(@INC, "lib") if (1 > (grep{/^lib$/} @INC)); unshift(@INC, $_path) if (1 > (grep{/^$_path$/} @INC)); unshift(@INC, $_pwd) if (1 > (grep{/^$_pwd$/} @INC)); unshift(@INC, ".") if (1 > (grep{/^\.$/} @INC)); # 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 - initialisation start"); $::osaft_standalone = 0; # SEE Note:Stand-alone ## PACKAGES # dummy comment used by some generators, do not remove #| definitions: include configuration; it's ok to die if missing #| ------------------------------------- use OSaft::Text qw(%STR); use OSaft::Ciphers qw(%ciphers %ciphers_desc %ciphers_notes $cipher_results); # not loaded with _load_modules() because always needed use osaft; use OSaft::Data; # simplify use of variables (because importing fails in o-saft-standalone.pl) #our %cfg = %OSaft::Cfg::cfg; our %checks = %OSaft::Data::checks; our %data = %OSaft::Data::data; our %data0 = %OSaft::Data::data0; our %info = %OSaft::Data::info; our %shorttexts = %OSaft::Data::shorttexts; our %check_cert = %OSaft::Data::check_cert; our %check_conn = %OSaft::Data::check_conn; our %check_dest = %OSaft::Data::check_dest; our %check_http = %OSaft::Data::check_http; our %check_size = %OSaft::Data::check_size; $cfg{'time0'} = $time0; #_____________________________________________________________________________ #________________________________________________________________ variables __| my $arg = ""; my @argv = (); # all options, including those from RC-FILE # will be used when ever possible instead of @ARGV #dbx# print STDERR "#$cfg{'me'} INC=@INC\n"; printf("#$cfg{'me'} %s\n", join(" ", @ARGV)) if _is_argv('(?:--trace[_.-]?(?:CLI$)?)'); # print complete command-line if any --trace-* was given, it's intended # that it works if unknown --trace-* was given, for example --trace-CLI #| definitions: forward declarations #| ------------------------------------- sub _is_cfg_intern($); # forward ... #| 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 ($cfg{'me'} =~/\.cgi$/) { SEE Since VERSION 18.12.18 #die $STR{ERROR}, "020: CGI mode requires strict settings" if (_is_argv('--cgi=?') <= 0); #} # CGI #_____________________________________________________________________________ #________________________________________________________________ functions __| #| definitions: debug and tracing functions #| ------------------------------------- # functions and variables used very early in main sub _dprint { my @txt = @_; local $\ = "\n"; print STDERR $STR{DBX}, join(" ", @txt); return; } #? print line for debugging sub _dbx { my @txt = @_; _dprint(@txt); return; } #? print line for debugging (alias for _dprint) sub _hint { #? print hint message if wanted # don't print if --no-hint given # check must be done on ARGV, because $cfg{'out'}->{'hint_info'} may not yet set my @txt = @_; return if _is_argv('(?:--no.?hint)'); printf($STR{HINT} . "%s\n", join(" ", @txt)); return; } # _hint sub _warn { #? print warning if wanted; SEE Note:Message Numbers # don't print if (not _is_cfg_out('warning')); my @txt = @_; my ($_no) = "@txt" =~ m/^([0-9(]{3})/; # message number, usually return if _is_argv('(?:--no.?warn(?:ings?)$)'); # ugly hack 'cause we won't pass $cfg{use}{warning} # other configuration values can be retrieved from %cfg if (0 < (grep{/^$_no$/} @{$cfg{out}->{'warnings_no_dups'}})) { # SEE Note:warning-no-duplicates return if (0 < (grep{/^$_no$/} @{$cfg{out}->{'warnings_printed'}})); push(@{$cfg{out}->{'warnings_printed'}}, $_no); } 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 = @_; 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 _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) = @_; # TODO: quick&ugly check when to write "reading" depending on given --trace* options return if (0 < (grep{/(?:--no.?header|--cgi)/i} @ARGV));# --cgi-exec or --cgi-trace return if (0 >= (grep{/(?:--warn|--v$|--trace)/i} @ARGV)); if (0 >= (grep{/(?:--trace[_.-]?(?:ARG|CMD|TIME|ME)$)/i} @ARGV)) { return if (0 < (grep{/(?:--trace[_.-]?CLI$)/i} @ARGV));# --trace-CLI } 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 = ""; # need eval to catch "Can't locate ... in @INC ..." eval {require $fil;} or _warn("101: 'require $fil' failed"); $err = $@; chomp $err; if ("" eq $err) { $fil = $INC{$fil}; $txt = "$txt done"; } else { $txt = "$txt failed"; } push(@{$dbx{file}}, $fil); _print_read($fil, $txt); return $err; } # _load_file 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) # TODO: 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 #| 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 with full path $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); # _yeast_rcfile(); # function from o-saft-dbx.pm cannot used here if (_is_v_trace()) { my @cfgs; print "#$cfg{'me'} $cfg{'RC-FILE'}\n"; print "#$cfg{'me'}: !!Hint: use --trace to see complete settings\n"; print "#$cfg{'me'}: #------------------------------------------------- RC-FILE {\n"; foreach my $val (@rc_argv) { #print join("\n ", "", @rc_argv); $val =~ s/(--cfg[^=]*=[^=]*).*/$1/ if (0 >=_is_argv('(?:--trace)')); print "#$cfg{'me'}: $val\n"; if ($val =~ m/--cfg[^=]*=[^=]*/) { $val =~ s/--cfg[^=]*=([^=]*).*/+$1/; push(@cfgs, $val); } } print "#$cfg{'me'}: added/modified= @cfgs\n"; print "#$cfg{'me'}: #------------------------------------------------- RC-FILE }\n"; } } 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 'checkpreferred' => 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, 'checksstp' => 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$|exitcode.?v$|tests?|yeast)/} @argv; # may have --trace=./file push(@dbx, grep{/^[+,](?:tests?)/} @argv); # may have +test* 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 { sub _yeast_init {} sub _yeast_exit {} sub _yeast_args {} sub _yeast_data {} sub _yeast_ciphers_list {} 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 {} # debug functions are defined in o-saft-dbx.pm and loaded on demand # they must be defined always as they are used whether requested or not # NOTE: these comment lines at end of else scope so that some make targets # can produce better human readable results } #| 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 # OSAFT_STANDALONE no warnings 'redefine'; # avoid: "Subroutine ... redefined" 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 {}; # " # user functions are defined in o-saft-user.pm and loaded on demand } } usr_pre_init(); #| initialise defaults #| ------------------------------------- # 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; option --v # above host, port, legacy and verbose are just shortcuts for corresponding # values in $cfg{}, used for better human readability my $test = ""; # set to argument if --test* or +test* was used 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 # SEE Note:Data Structures # our %info = (); # our %data0 = (); # our %data = (); # our %checks = (); # our %check_cert = (); # our %check_conn = (); # our %check_dest = (); # our %check_size = (); # our %check_http = (); # our %shorttexts = (); # more initialisation for %data # add keys from %prot to %data, $data{'fallback_protocol'}->{'val'} = sub { return $prot{'fallback'}->{val} }; 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"; } 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 'openssl3' => "openssl", # OpenSSL which supports TLSv1.3 '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 'envlibvar3' => "LD_LIBRARY_PATH", # for OpenSSL which supports TLSv1.3 'call' => [], # list of special (internal) function calls # see --call=METHOD option in description below ); #| construct list for special commands: 'cmd-*' #| ------------------------------------- # SEE Note:Testing, sort 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_cfg_intern($key)); # 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'); # SEE Note:Testing, sort foreach my $key (qw(commands commands_cmd commands_usr commands_int cmd-info--v)) { # TODO: need to test if sorting of cmd-info--v should not be done for --no-rc @{$cfg{$key}} = sort(@{$cfg{$key}}); # only internal use } if (0 < _is_argv('(?:--no.?rc)')) { foreach my $key (qw(do cmd-check cmd-info cmd-quick cmd-vulns)) { @{$cfg{$key}} = sort(@{$cfg{$key}});# may be redefined } } _yeast_TIME("cfg}"); # following defined in OSaft/Ciphers.pm # %ciphers_desc(); # %ciphers(); # %ciphers_notes(); # %cipher_results(); our %text = ( 'separator' => ":",# separator character between label and value # texts may be redefined 'undef' => "<>", 'response' => "<>", 'protocol' => "<>", 'need_cipher' => "<>", 'na' => "<>", 'na_STS' => "<>", 'na_sni' => "<>", '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_protocol' => "<>", 'miss_RSA' => " <>", 'miss_ECDSA' => " <>", 'missing' => " <>", 'enabled_extension' => " <<@@ extension enabled>>", 'unexpected' => " <>", '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=== Information ===", '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)", 'anon_text' => "<>", # SEE Note:anon-out # 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: # print_title, print_cipherhead, print_footer, print_cipherpreferred, print_ciphertotals # NOTE: all other legacy texts are hardcoded, as there is no need to change them! }, # SEE Note:hints 'hints' => { # define hints here only if not feasable in osaft.pm # will be added to $cfg{hints} in _init_all() }, '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' => '??', # list of hosts '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 information 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 - initialisation end"); usr_pre_file(); #| definitions: functions to "convert" values #| ------------------------------------- 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 _get_yes_no { my $val=shift; return ($val eq "") ? 'yes' : 'no (' . $val . ')'; } # return 'yes' if given value is empty, return 'no' otherwise sub _get_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) # unfortunately 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)); } # _get_base2 sub _hex_like_openssl { # return full hex constant formatted as 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 #| definitions: %cfg functions #| ------------------------------------- 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_openssl() { return __need_this('need-openssl'); } 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}); } # returns list of matching entries in specified array @cfg{*} sub _is_cfg_do($) { my $is=shift; return _is_member($is, \@{$cfg{'do'}}); } sub _is_cfg_intern($) { my $is=shift; return _is_member($is, \@{$cfg{'commands_int'}}); } sub _is_cfg_hexdata($) { my $is=shift; return _is_member($is, \@{$cfg{'data_hex'}}); } sub _is_cfg_call($) { my $is=shift; return _is_member($is, \@{$cmd{'call'}}); } # returns >0 if the given string is listed in $cfg{*} sub _is_cfg($) { my $is=shift; return $cfg{$is}; } sub _is_cfg_ssl($) { my $is=shift; return $cfg{$is}; } # returns >0 if specified key (protocol like SSLv3) is set $cfg{*} sub _is_cfg_out($) { my $is=shift; return $cfg{'out'}->{$is}; } sub _is_cfg_tty($) { my $is=shift; return $cfg{'tty'}->{$is}; } sub _is_cfg_use($) { my $is=shift; return $cfg{'use'}->{$is}; } # returns value for given key in $cfg{*}->{key}; which is 0 or 1 (usually) sub _is_cfg_verbose() { return $cfg{'verbose'}; } sub _set_cfg_out($$) { my ($is,$val)=@_; $cfg{'out'}->{$is} = $val; return; } sub _set_cfg_tty($$) { my ($is,$val)=@_; $cfg{'tty'}->{$is} = $val; return; } sub _set_cfg_use($$) { my ($is,$val)=@_; $cfg{'use'}->{$is} = $val; return; } # set value for given key in $cfg{*}->{key} #| definitions: internal wrapper functions for OSaft/Ciphers.pm #| ------------------------------------- # following wrappers are called with cipher suite name, while OSaft::Ciphers # methods need to be called with cipher hex key sub _cipher_get_bits { return OSaft::Ciphers::get_bits( OSaft::Ciphers::get_key(shift)); } sub _cipher_get_sec { return OSaft::Ciphers::get_sec( OSaft::Ciphers::get_key(shift)); } sub _cipher_set_sec { # set cipher's security value in %ciphers; can be called with key or name # parameter looks like: 0x030000BA=sec or CAMELLIA128-SHA=sec my ($typ, $arg) = @_; my ($key, $val) = split(/=/, $arg, 2); # left of first = is key $key = OSaft::Ciphers::get_key($key) if ($key !~ m/^0x[0-9a-fA-F]{8}$/); # if is is not a key, try to get the key from a cipher name return if not $key; # warning already printed OSaft::Ciphers::set_sec($key, $val); return; } # _cipher_set_sec #| definitions: internal functions #| ------------------------------------- sub _eval_cipherranges { #? return array of cipher suite hex key, securely evaluated from given range # invalid; avoid injection attempts my $key = shift; return [] if $cfg{'cipherranges'}->{$key} !~ m/^[x0-9A-Fa-f,.\s]+$/; # see osaft.pm return (eval($cfg{'cipherranges'}->{$key})); ## no critic qw(BuiltinFunctions::ProhibitStringyEval) } # _eval_cipherranges sub __is_number { # 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 } # __is_number use IO::Socket::INET; sub _load_modules { # load required modules # SEE Perl:import include my $_err = ""; if (1 > 0) { # TODO: experimental code $_err = _load_file("IO/Socket/SSL.pm", "IO SSL module"); warn $STR{ERROR}, "005: $_err" if ("" ne $_err); # 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 ... #$_err = _load_file("IO/Socket/INET.pm", "IO INET module"); #warn $STR{ERROR}, "006: $_err" if ("" ne $_err); } if (0 < $cfg{'need_netdns'}) { $_err = _load_file("Net/DNS.pm", "Net module'"); if ("" ne $_err) { warn $STR{ERROR}, "007: $_err"; _warn("111: option '--mx disabled"); $cfg{'use'}->{'mx'} = 0; } } if (0 < $cfg{'need_timelocal'}) { $_err = _load_file("Time/Local.pm", "Time module"); if ("" ne $_err) { warn $STR{ERROR}, "008: $_err"; _warn("112: value for '+sts_expired' not applicable"); # TODO: need to remove +sts_expired from cfg{do} } } $_err = _load_file("Encode.pm", "Encode module"); # must be found with @INC if ("" ne $_err) { warn $STR{ERROR}, "008: $_err"; } return if (0 < $::osaft_standalone); # SEE Note:Stand-alone $_err = _load_file("Net/SSLhello.pm", "O-Saft module"); # must be found with @INC if ("" ne $_err) { die $STR{ERROR}, "010: $_err" if (not _is_cfg_do('version')); warn $STR{ERROR}, "010: $_err"; # no reason to die for +version } if ($cfg{'starttls'}) { $cfg{'use'}->{'http'} = 0; # makes no sense for starttls # TODO: not (yet) supported for proxy } return if (1 > $cfg{'need_netinfo'}); $_err = _load_file("Net/SSLinfo.pm", "O-Saft module");# must be found if ("" ne $_err) { die $STR{ERROR}, "011: $_err" if (not _is_cfg_do('version')); warn $STR{ERROR}, "011: $_err"; # 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", # 1.46 may also work '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 (__is_number($version::VERSION)) { $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((_is_cfg_use('sni')) and ($cmd{'extciphers'} == 0)) { $cfg{'use'}->{'sni'} = 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("use '--force-openssl' to disable this check"); } } _trace("cfg{use}->{sni} = $cfg{'use'}->{'sni'}"); 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 (_is_cfg_use('alpn')) { $cfg{'use'}->{'alpn'} = 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("use '--no-alpn' to disable this check"); } } _trace("cfg{use}->{alpn}= $cfg{'use'}->{'alpn'}"); if ($cfg{'ssleay'}->{'set_npn'} == 0) { # warnings only if NPN functionality required if (_is_cfg_use('npn')) { $cfg{'use'}->{'npn'} = 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("use '--no-npn' to disable this check"); } } _trace("cfg{use}->{npn} = $cfg{'use'}->{'npn'}"); if ($cfg{'ssleay'}->{'can_ocsp'} == 0) { # Net::SSLeay < 1.59 and openssl 1.0.0 warn $STR{WARN}, "133: $txt tests for OCSP disabled"; #_hint("use '--no-ocsp' to disable this check"); } if ($cfg{'ssleay'}->{'can_ecdh'} == 0) { # Net::SSLeay < 1.56 warn $STR{WARN}, "134: $txt setting curves disabled"; #_hint("use '--no-cipher-ecdh' 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'} set to 1 by default _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: Net::SSLeay $version_ssleay < 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 ciphermode=intern can be removed when Net::SSLhello # supports DTLSv1 my $typ; my @list; _y_CMD(" check supported SSL versions ..."); if (_is_cfg_do('cipher_openssl') or _is_cfg_do('cipher_ssleay')) { @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_cfg_do('cipher_intern') or _is_cfg_do('cipher_dump')) { # internal method does not depend on other libraries, but DTLS* not yet supported if ($ssl =~ m/^DTLS/) { _warn("140: SSL version '$ssl': not supported by '$cfg{'me'} +cipher'; 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 # 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 an 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 (_is_cfg_use('ssl_lazy')) { push(@{$cfg{'version'}}, $ssl); $cfg{$ssl} = 1; next; } next if (not _is_cfg_do('cipher')); # 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 '--ciphermode=intern' instead") if ('intern' ne $cfg{'ciphermode'}); } } # $ssl if (not _is_cfg_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}; # may 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; results for following commands 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{'use'}->{'alpn'} = $val if ($opt eq '-alpn'); $cfg{'use'}->{'npn'} = $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 { # check cpapbilities of 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 ... # SEE Note:OpenSSL s_client foreach my $opt (sort(Net::SSLinfo::s_client_get_optionlist())) { # SEE Note:Testing, sort # Perl warning "Use of uninitialized value in ..." here indicates # that cfg{openssl} is not properly initialised 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: 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" # until 4/2021: path was only returned if $dir/certs exists # since 4/2021: path is always returned (because Android does not have certs/ : my $openssldir = $dir; $dir =~ s#[^"]*"([^"]*)"#$1#; $capath = $dir; unshift(@{$cfg{'ca_paths'}}, $dir); # dosn't harm if (-e "$dir/certs") { $capath = "$dir/certs"; } else { _warn("148: 'openssl version -d' returned: '$openssldir' which does not contain certs/ ; ignored."); } } 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_paths=@{$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 file for CA; using '--ca-path=$p'"); return "$p/$f"; # ugly return from inner loop; but exactly what we want } } } return; # same as: return undef } # _init_openssl_ca sub _init_openssl { # initialisation for openssl executable # TODO: Checking for openssl executable and configuration files may print # **WARNINGs, even if openssl is not used at all. # Unfortunately there is no simple rule "openssl needed if ...", so # A userfriendly solution would be to define %cfg{need-openssl} to # contain all commands which require openssl, following settings # should then check %cfg{need-openssl}. # As long as there is no %cfg{need-openssl}, warnings are printed. # TODO: if (_is_needed_openssl()) { # openssl executable only requrired for +cipher with --ciphermode=openssl # or for advanced check commands $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_file'} = _init_openssl_ca($cfg{'ca_path'}); if (not defined $cfg{'ca_file'} or $cfg{'ca_path'} eq "") { $cfg{'ca_file'} = "$cfg{'ca_paths'}[0]/$cfg{'ca_files'}[0]"; # use default _warn("060: no PEM file for CA found; using '--ca-file=$cfg{'ca_file'}'"); _warn(" if default file does not exist, some certificate checks may fail"); _hint("use '--ca-file=/full/path/$cfg{'ca_files'}[0]'"); } _v_print("_init_openssl: ca_file=$cfg{'ca_file'}"); return; } # _init_openssl 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 my $notxt = ""; #my $notxt = $text{'undef'}; # TODO: default should be 'undef' $checks{$_}->{val} = $notxt foreach (keys %checks); #### temporär, bis alle so gesetzt sind { $checks{'heartbeat'}->{val} = $text{'undef'}; foreach my $key (qw(krb5 psk_hint psk_identity srp session_ticket session_lifetime)) { $checks{$key}->{val} = $text{'undef'}; } #### temporär } foreach my $key (keys %checks) { $checks{$key}->{val} = 0 if ($key =~ m/$cfg{'regex'}->{'cmd-sizes'}/); $checks{$key}->{val} = 0 if ($key =~ m/$cfg{'regex'}->{'SSLprot'}/); } # 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 # if $data{'https_sts'}->{val}($host) is empty { foreach my $key (qw(sts_maxage sts_expired sts_preload sts_subdom hsts_location hsts_refresh hsts_fqdn hsts_samehost hsts_sts)) { $checks{$key} ->{val} = $text{'na_STS'}; } # following can not be set here, because they contain integers, see above #foreach my $key (qw(sts_maxage00 sts_maxagexy sts_maxage18 sts_maxage0d)) { # $checks{$key} ->{val} = $text{'na_STS'}; #} #foreach my $key (qw(sts_maxage1y sts_maxage1m sts_maxage1d)) { # $checks{$key} ->{val} = $text{'na_STS'}; #} # } foreach my $key (@{$cfg{'cmd-vulns'}}) { $checks{$key} ->{val} = $text{'undef'}; # may be refined below } if (not _is_cfg_use('dns')) { $checks{'reversehost'} ->{val} = $text{'na_dns'}; } if (not _is_cfg_use('http')) { $checks{'crl_valid'} ->{val} = _get_text('disabled', "--no-http"); $checks{'ocsp_valid'} ->{val} = _get_text('disabled', "--no-http"); foreach my $key (keys %checks) { $checks{$key} ->{val} = $text{'na_http'} if (_is_member($key, \@{$cfg{'cmd-http'}})); } } if (not _is_cfg_use('cert')) { $cfg{'no_cert_txt'} = $notxt if ("" eq $cfg{'no_cert_txt'}); foreach my $key (keys %check_cert) { # anything related to certs $checks{$key} ->{val} = $text{'na_cert'} if (_is_hashkey($key, \%check_cert)); } foreach my $key (qw(hostname certfqdn tr_02102+ tr_02102- tr_03116+ tr_03116- rfc_6125_names rfc_2818_names)) { $checks{$key} ->{val} = $text{'na_cert'}; } } if (not _is_cfg_ssl('SSLv2')) { $notxt = _get_text('disabled', "--no-SSLv2"); $checks{'hassslv2'} ->{val} = $notxt; $checks{'drown'} ->{val} = $notxt; } if (not _is_cfg_ssl('SSLv3')) { $notxt = _get_text('disabled', "--no-SSLv3"); $checks{'hassslv3'} ->{val} = $notxt; $checks{'poodle'} ->{val} = $notxt; } $checks{'hastls10'} ->{val} = _get_text('disabled', "--no-TLSv1") if (1 > $cfg{'TLSv1'}) ; $checks{'hastls11'} ->{val} = _get_text('disabled', "--no-TLSv11") if (1 > $cfg{'TLSv11'}); $checks{'hastls12'} ->{val} = _get_text('disabled', "--no-TLSv12") if (1 > $cfg{'TLSv12'}); $checks{'hastls13'} ->{val} = _get_text('disabled', "--no-TLSv13") if (1 > $cfg{'TLSv13'}); $checks{'hasalpn'} ->{val} = _get_text('disabled', "--no-alpn") if (not _is_cfg_use('alpn')); $checks{'hasnpn'} ->{val} = _get_text('disabled', "--no-npn") if (not _is_cfg_use('npn')); $checks{'sni'} ->{val} = $text{'na_sni'} if (not _is_cfg_use('sni')); $checks{'certfqdn'} ->{val} = $text{'na_sni'} if (not _is_cfg_use('sni')); $checks{'heartbeat'}->{val} = $text{'na_tlsextdebug'} if (not _is_cfg_use('extdebug')); if (1 > $cmd{'extopenssl'}) { foreach my $key (qw(sernumber len_sigdump len_publickey modulus_exp_1 modulus_exp_65537 modulus_exp_oldssl modulus_size_oldssl)) { $checks{$key} ->{val} = $text{'na_openssl'}; } } 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(); # initialise defaults in %checks (score, val); parts be done again later 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 sub _prot_cipher_or_empty { # return string consisting of given parameters separated by : and prefixed with a space # returns "" if any parameter is empty my $p1 = shift; my $p2 = shift; return "" if (("" eq $p1) or ("" eq $p2)); return _prot_cipher($p1, $p2); } # _prot_cipher_or_empty 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 ... # forward ... 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)) { ## no critic qw(InputOutput::RequireBriefOpen) push(@{$dbx{file}}, $fil); _print_read("$fil", "USER-FILE configuration file") if (_is_cfg_out('header')); 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_from_file: 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 # should never occour, defensive programming _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 sanitise 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)); next if (_is_hashkey($key, \%data)); next if (_is_member( $key, \@{$cfg{'cmd-NL'}})); next if (_is_cfg_intern( $key)); 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 (not _is_member("cmd-$key", \@{$cfg{'commands_cmd'}})) { # 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("046: 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 #| definitions: check SSL functions #| ------------------------------------- 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 _is_ssl_bleed { #? 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: _is_ssl_bleed: failed to connect: '$!'"); _trace("_is_ssl_bleed: fatal exit in IO::Socket::INET->new\n"); return "failed to connect"; }; } else { # proxy or starttls _trace("_is_ssl_bleed: 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: _is_ssl_bleed (with openTcpSSLconnection): $@\n"); _trace("_is_ssl_bleed: 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("_is_ssl_bleed= $ret\n"); return $ret; } # _is_ssl_bleed sub _is_ssl_beast { # 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 ""; } # _is_ssl_beast ### _is_ssl_breach($) { return "NOT YET IMPLEMEMNTED"; } sub _is_ssl_breach { # 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 } # _is_ssl_breach sub _is_ssl_ccs { #? 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: _is_ssl_ccs: failed to connect: '$!'"); return "failed to connect"; }; ################# # $ccs = _is_ssl_ccs($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: _is_ssl_ccs: 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; } # _is_ssl_ccs sub _is_ssl_crime { # 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; } # _is_ssl_crime sub _is_ssl_fips { # 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 ""; } # _is_ssl_fips sub _is_ssl_freak { # return given cipher if vulnerable to FREAK attack, empty string otherwise my ($ssl, $cipher) = @_; return "" if ($ssl !~ /(?:SSLv3)/); # TODO: probably only SSLv3 is vulnerable return $cipher if ($cipher =~ /$cfg{'regex'}->{'FREAK'}/); return ""; } # _is_ssl_freak sub _is_ssl_logjam { # return given cipher if vulnerable to logjam attack, empty string otherwise my ($ssl, $cipher) = @_; return $cipher if ($cipher =~ /$cfg{'regex'}->{'Logjam'}/); return ""; } # _is_ssl_logjam sub _is_ssl_lucky { my $val=shift; return ($val =~ /$cfg{'regex'}->{'Lucky13'}/) ? $val : ""; } # return given cipher if vulnerable to Lucky 13 attack, empty string otherwise sub _is_ssl_nsab { # return given cipher if it is not NSA Suite B compliant, empty string otherwise # TODO: } # _is_ssl_nsab sub _is_ssl_pci { # 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 ""; } # _is_ssl_pci sub _is_ssl_pfs { my ($ssl,$c)=@_; return ("$ssl-$c" =~ /$cfg{'regex'}->{'PFS'}/) ? $c : ""; } # return given cipher if it supports forward secret connections (PFS) sub _is_ssl_rc4 { my $val=shift; return ($val =~ /$cfg{'regex'}->{'RC4'}/) ? $val . " " : ""; } # return given cipher if it is RC4 sub _is_ssl_robot { # 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 ""; } # _is_ssl_robot sub _is_ssl_sloth { # return given cipher if vulnerable to SLOTH attack, empty string otherwise my ($ssl, $cipher) = @_; return $cipher if ($cipher =~ /$cfg{'regex'}->{'SLOTH'}/); return ""; } # _is_ssl_sloth sub _is_ssl_sweet { # 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 ""; } # _is_ssl_sweet sub _is_ssl_time { return 0; } # TODO: checks; good: AES-GCM or AES-CCM # return given cipher if vulnerable to TIME attack, empty string otherwise sub _is_tls12only { # 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); } # _is_tls12only sub _is_tr02102 { # 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 ""; } # _is_tr02102 sub _is_tr02102_strict { # return given cipher if it is not TR-02102 compliant, empty string otherwise my ($ssl, $cipher) = @_; my $val = _is_tr02102($ssl, $cipher); if ($val eq "") { # strict 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; } # _is_tr02102_strict sub _is_tr02102_lazy { # return given cipher if it is not TR-02102 compliant, empty string otherwise my ($ssl, $cipher) = @_; my $val = _is_tr02102($ssl, $cipher); return $val; } # _is_tr02102_lazy sub _is_tr03116_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 ""; } # _is_tr03116_strict sub _is_tr03116_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 ""; } # _is_tr03116_lazy sub _is_rfc7525 { # return given cipher if it is not RFC 7525 compliant, empty string otherwise my ($ssl, $cipher) = @_; my $bit = _cipher_get_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 ""; } # _is_rfc7525 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 _is_ssl_error($$$) { # returns 1 if probably 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 (not _is_cfg_use('ssl_error'));# 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 _usesocket($$$$) { # return protocol and cipher accepted by SSL connection # should return the target's preferred 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 = (not _is_cfg_use('sni')) ? "" : $host; my $npns = (not _is_cfg_use('npn')) ? [] : $cfg{'cipher_npns'}; my $alpns = (not _is_cfg_use('alpn')) ? [] : $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() # NOTE: eval necessary to avoid Perl error like: # invalid SSL_version specified at /usr/share/perl5/IO/Socket/SSL.pm line 492. # NOTE: 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)], #SSL_ecdh_curve => undef, # TODO: cannot be selected by options SSL_alpn_protocols => $alpns, SSL_npn_protocols => $npns, #TODO: SSL_honor_cipher_order => 1, # useful 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 preferred 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 = (not _is_cfg_use('sni')) ? "" : "-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 ; dumm } $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 = osaft::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 '--v' or '--trace'"); # print always } else { _v_print("_useopenssl: Net::SSLinfo::do_openssl() #{\n$data\n#}"); } return "", "", ""; } # _useopenssl sub _can_connect { # return 1 if host:port can be connected; 0 otherwise my ($host, $port, $sni, $timeout, $ssl) = @_; if (not defined $sni) { $sni = $STR{UNDEF}; } # defensive programming local $? = 0; local $! = undef; my $socket; _trace("_can_connect($host, $port', $sni, $timeout, $ssl)"); if ($ssl == 1) { # need different method for connecting with SSL if ($cfg{'trace'} > 2) { $IO::Socket::SSL::debug3 = 1; my $keep_perl_quiet = $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: $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 _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, analyse ... 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 = $arg; $path =~ s#^.*?/#/#; # get /path/and?more 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(" target 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 sub _get_cipherlist_openssl { #? return space-separated list of cipher suites according command-line options # this is usefull for display only or for use with openssl _trace("_get_cipherlist_openssl(){"); my @ciphers = (); my $range = $cfg{'cipherrange'}; # default _trace("cipherpattern = $cfg{'cipherpattern'}, cipherrange= $range"); my $pattern = $cfg{'cipherpattern'};# default pattern (colon-separated) $pattern = join(":", @{$cfg{'cipher'}}) if (0 < scalar(@{$cfg{'cipher'}})); # @{$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 "intern") { # default cipher range is 'intern' (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_cipherranges($range)) { my $key = sprintf("0x%08X",$c); push(@ciphers, OSaft::Ciphers::get_name($key)||""); # "" avoids some undef } } _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 = OSaft::Ciphers::get_names_list(); } 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 = sort grep{!/^\s*$/} @ciphers; # remove empty names _trace("_get_cipherlist_openssl\t= @ciphers }"); # TODO: trace a bit late return @ciphers; } # _get_cipherlist_openssl sub _get_cipherlist_hex { #? return space-separated list of cipher hex keys according command-line options _trace("_get_cipherlist_hex(){"); my $ssl = shift; my @ciphers = (); if (0 < scalar(@{$cfg{'cipher'}})) { foreach my $name (@{$cfg{'cipher'}}) { if ($name =~ m/^(?:0x)?[0-9A-F]+$/i) { #_dbx "key = " . OSaft::Ciphers::get_key($name); push(@ciphers, OSaft::Ciphers::get_key($name)); # hex key } else { push(@ciphers, OSaft::Ciphers::find_keys($name)); # name or pattern } } } else { _trace("cipherrange= $cfg{'cipherrange'}"); # default @ciphers = osaft::get_ciphers_range($ssl, $cfg{'cipherrange'}); } _trace("_get_cipherlist_hex\t= @ciphers }"); return @ciphers; } # _get_cipherlist_hex sub _get_default($$$$) { # return list of offered (default) cipher from target # mode defines how to retrieve the preferred 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 preferred 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. +cipher --ciphermode=intern 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 = OSaft::Ciphers::sort_names(@{$cfg{'ciphers'}}) ;#if ($mode eq 'strong'); @list = reverse OSaft::Ciphers::sort_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 preferred cipher; ignored"; # SSLv2 is special, see _usesocket "dirty hack"; don't print _v_print($txt) if ($ssl !~ m/SSLv[2]/); } else { _v2print("preferred 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) { # 'sort' is used to make tests comparable foreach my $key (sort 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)"); } if (0 < (length Net::SSLinfo::errors())) { _warn("203: connection without SNI succeded with errors; errors ignored"); # fails often with: Error in cipher list; SSL_CTX_set_cipher_list:no cipher match # TODO: don't show warning 203 if only this in Net::SSLinfo::errors if (0 < ($cfg{'verbose'} + $cfg{'trace'})) { _warn("206: $_") foreach Net::SSLinfo::errors(); # following OK, i.e. if SSLv2 or SSLv3 is not supported: # **WARNING: 206: do_openssl(ciphers localhost) failed: Error in cipher list # ....SSL routines:SSL_CTX_set_cipher_list:no cipher match:ssl_lib.c:1383: } else { _hint("use '--v' to show more information about Net::SSLinfo::do_ssl_open() errors"); } } _yeast_TIME("no SNI}"); # should be before if {}, but also ok here # 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) Net::SSLinfo::do_ssl_close($host, $port); $Net::SSLinfo::use_SNI = $cfg{'use'}->{'sni'}; _trace(" cn_nosni: $data{'cn_nosni'}->{val} }"); return; } # _get_data0 sub ciphers_scan_prot { #? test target if given ciphers are accepted, returns array with 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("use '--no-cipher-md5' 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 the 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_raw { #? scan target for ciphers for all protocols # returns array with accepted ciphers my ($host, $port) = @_; my $total = 0; my $enabled = 0; my $_printtitle = 0; # count title lines; 0 = no ciphers checked my $results = {}; # hash with cipher list to be returned my $usesni = $Net::SSLhello::usesni; # store SNI for recovery later my $typ = "raw"; # used for --trace only $typ = "all" if (_is_cfg_do('cipher_intern')); _y_CMD(" use SSLhello +cipher$typ ..."); foreach my $ssl (@{$cfg{'version'}}) { $_printtitle++; next if ($cfg{$ssl} == 0); if ($usesni >= 1) { # Do not use SNI with SSLv2 and SSLv3 # SSLv2 has no SNI; SSLv3 has originally no SNI # using $Net::SSLhello::usesni instead of $cfg{'usesni'} (even they # should be the same) because Net::SSLhello functions are called $Net::SSLhello::usesni = $usesni; if ($ssl =~ m/^SSLv/) { _warn_nosni("409:", $ssl, $usesni); $Net::SSLhello::usesni = 0; } } my @accepted = []; # accepted ciphers (cipher keys) my @all = _get_cipherlist_hex($ssl); _y_CMD(" checking " . scalar(@all) . " ciphers for $ssl ... (SSLhello)"); $total += scalar @all; if ("@all" =~ /^\s*$/) { _warn("407: no valid ciphers specified; no check done for '$ssl'"); next; # ensure warning for all protocols #return $results;# only one warning } if (_is_cfg_do('cipher_intern')) { # may be called for cipher_dump too _v_print("cipher range: $cfg{'cipherrange'}, checking " . scalar(@all) . " ciphers ..."); } @accepted = Net::SSLhello::checkSSLciphers($host, $port, $ssl, @all); if (_is_cfg_do('cipher_dump')) { _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 first one } # prepare for printing, list, needed for summary checks my $last_a = ""; # avoid duplicates foreach my $key (@accepted) { next if ($last_a eq $key); $results->{$ssl}{$key} = "yes"; $last_a = $key; } if (0 < scalar @accepted) { my $cipher = OSaft::Ciphers::get_name($accepted[0]) || $STR{UNDEF}; # may return undef # SEE Note:+cipherall $prot{$ssl}->{'cipher_strong'} = $cipher; $prot{$ssl}->{'default'} = $cipher; } # print ciphers # NOTE: rest of code (print*()) should be moved to calling place, # but as the variables @all, @accepted are only available here # (or must be computed again), printing is done here 11/2020 if (_is_cfg_do('cipher') or _is_cfg_do('check')) { print_title($legacy, $ssl, $host, $port, $cfg{'out'}->{'header'}); if (_is_cfg_do('cipher_intern')) { $enabled += printcipherall($legacy, $ssl, $host, $port, ($legacy eq "sslscan")?($_printtitle):0, @accepted); if ($cfg{'legacy'} =~ m/simple|openssl/) { printf("%-36s\t%s\n", "= $checks{'cnt_totals'}->{txt}", scalar(@all)); # FIXME: should use print_line() instead of hardcoded printf } next if (scalar @accepted < 1); # defensive programming .. #push(@{$prot{$ssl}->{'ciphers_pfs'}}, $c) if ("" ne _is_ssl_pfs($ssl, $c)); # add PFS cipher } else { Net::SSLhello::printCipherStringArray('compact', $host, $port, $ssl, $Net::SSLhello::usesni, @accepted); } } } # $ssl return $results; } # ciphers_scan_raw sub ciphers_scan { #? scan target for ciphers for all protocols # returns hash with accepted ciphers 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'}}); my $results = {}; # hash of cipher list to be returned foreach my $ssl (@{$cfg{'version'}}) { my $__openssl = ($cmd{'extciphers'} == 0) ? 'socket' : 'openssl'; my $usesni = $cfg{'use'}->{'sni'}; if (($cfg{'verbose'} + $cfg{'trace'} > 0) or _is_cfg_out('traceCMD')) { # optimise output: instead using 3 lines with _y_CMD(), _trace() and _v_print() my $_me = ""; $_me = $cfg{'me'} . " CMD:" if (_is_cfg_out('traceCMD')); # TODO: _yTIME() missing $_me = $cfg{'me'} . "::" 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_cfg_do('cipher') or $cfg{'verbose'} > 0) { _warn_nosni("410:", $ssl, $cfg{'use'}->{'sni'}); # 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 # NOTE: applies to --ciphermode=openssl|ssleay only } $cfg{'use'}->{'sni'} = 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 we 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 for loop # now build line in %results foreach my $cipher (@{$cfg{'ciphers'}}) { # might be done more perlish ;-) my $key = OSaft::Ciphers::get_key($cipher); $results->{$ssl}{$key} = ((grep{/^$cipher$/} @supported)>0) ? "yes" : "no"; } $cfg{'use'}->{'sni'} = $usesni; } # $ssl return $results; } # 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 (1 < $cfg{'done'}->{'check_certchars'}); 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 explicitly: 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 (1 < $cfg{'done'}->{'check_dh'}); # 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 for 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 # # example (?/2019): http://sr.symcb.com/sr.crl # HTTP/1.1 200 OK # Content-Type: application/pkix-crl # Transfer-Encoding: chunked # Connection: Transfer-Encoding # # example (12/2020): http://sr.symcb.com/sr.crl # HTTP/1.1 200 OK # Content-Type: application/x-pkcs7-crl # Content-Length: 540 # # example (12/2020): http://ocsp.msocsp.com # HTTP/1.1 200 OK # Content-Type: application/ocsp-response # Content-Length: 5 # # example (3/2021): http://r3.i.lencr.org # HTTP/1.1 200 OK # Content-Type: application/pkix-cert # Content-Length: 1129 # # bad example (12/2020): http://clients1.google.com/ocsp # HTTP/1.1 404 Not Found # Date: Sun, 17 Apr 2016 10:24:46 GMT # Server: ocsp_responder # Content-Type: text/html; charset=UTF-8 # Content-Length: 1565 # # bad example (12/2020): http://ocsp.entrust.net # HTTP/1.1 200 OK # Content-Length: 0 # # bad example (??/2019): 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"> # # bad example (12/2020): http://ocsp.pki.goog/gts1o1core # bad example (12/2020): http://ocsp.pki.goog/ # HTTP/1.1 404 Not Found # Server: ocsp_responder # Content-Type: text/html; charset=UTF-8 # Content-Length: 1561 # # 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) # TODO: add 'Authorization:'=>'Basic ZGVtbzpkZW1v', # NOTE: Net::SSLeay always sets Accept:*/* _trace2("check_url: use_http " . _is_cfg_use('http')); _trace2("check_url: get_http($host, $port, $url)"); my ($response, $status, %headers) = Net::SSLeay::get_http($host, $port, $url, Net::SSLeay::make_headers( 'Host' => $host, 'Connection' => 'close', ) ); _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] || ""} || "-1"; $binary = $headers{(grep{/^Content-transfer-encoding$/i} keys %headers)[0] || ""}; $chunk = $headers{(grep{/^Transfer-Encoding$/i} keys %headers)[0] || ""} || " "; _trace2("check_url: length=$length, accept=$accept, ctype=$ctype"); } else { return _get_text('unexpected', "response from '$host:$port$url': $status"); # 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: $length") 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-cert|pkcs7-mime)#i) # for CA Issuers; see rfc5280#section-4.2.1.13 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 (1 < $cfg{'done'}->{'checkalpn'}); # _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 checkpreferred { #? test if target prefers strong ciphers, aka SSLHonorCipherOrder my ($host, $port) = @_; # not yet used _y_CMD("checkpreferred() " . $cfg{'done'}->{'checkpreferred'}); $cfg{'done'}->{'checkpreferred'}++; return if (1 < $cfg{'done'}->{'checkpreferred'}); _trace("checkpreferred($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 = ($weak ne $strong) ? _prot_cipher($ssl, "$strong,$weak") : ""; $checks{'cipher_strong'}->{val} .= $txt; # assumtion wrong if only one cipher accepted $checks{'cipher_order'}->{val} .= $txt; # NOT YET USED $checks{'cipher_weak'}->{val} .= $txt; # remember: eq ! if ($weak eq $strong) { # FIXME: assumtion wrong if target returns always strongest cipher; # meanwhile print hint (set hint here, printed later) _cfg_set('CFG-hint', 'cipher_weak=check if "weak" cipher was returned may be misleading if the strongest cipher is returned always'); } } _trace("checkpreferred() }"); return; } # checkpreferred sub checkcipher { #? test given cipher and add result to %checks and %prot my ($ssl, $key) = @_; my $c = OSaft::Ciphers::get_name($key); # $cipher = $c; my $risk = OSaft::Ciphers::get_sec($key); # 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_or_empty($ssl, _is_ssl_pci( $ssl, $c)); $checks{'fips'} ->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_fips( $ssl, $c)); $checks{'rfc_7525'} ->{val} .= _prot_cipher_or_empty($ssl, _is_rfc7525( $ssl, $c)); $checks{'tr_02102+'}->{val} .= _prot_cipher_or_empty($ssl, _is_tr02102_strict($ssl, $c)); $checks{'tr_02102-'}->{val} .= _prot_cipher_or_empty($ssl, _is_tr02102_lazy( $ssl, $c)); $checks{'tr_03116+'}->{val} .= _prot_cipher_or_empty($ssl, _is_tr03116_strict($ssl, $c)); $checks{'tr_03116-'}->{val} .= _prot_cipher_or_empty($ssl, _is_tr03116_lazy( $ssl, $c)); # check attacks $checks{'rc4'} ->{val} = $checks{'cipher_rc4'}->{val}; # these are the same checks $checks{'beast'} ->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_beast($ssl, $c)); $checks{'breach'} ->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_breach($c)); $checks{'freak'} ->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_freak($ssl, $c)); $checks{'lucky13'} ->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_lucky($c)); $checks{'robot'} ->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_robot($ssl, $c)); $checks{'sloth'} ->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_sloth($ssl, $c)); $checks{'sweet32'} ->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_sweet($ssl, $c)); push(@{$prot{$ssl}->{'ciphers_pfs'}}, $c) if ("" ne _is_ssl_pfs($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 = osaft::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 _checkcipher_init { # initialise $check{...}-{val} with empty string, because they will be # extended per $ssl (protocol) foreach my $key (qw( cipher_null cipher_adh cipher_exp cipher_cbc cipher_des cipher_rc4 cipher_edh ciphers_pfs cipher_pfsall beast breach freak logjam lucky13 rc4 robot sloth sweet32 ism pci fips rfc_7525 tr_02102+ tr_02102- tr_03116+ tr_03116- )) { $checks{$key}->{val} = ""; } return; } # _checkcipher_init sub checkciphers { #? test target if given ciphers are accepted, results stored in global %checks my ($host, $port, $results) = @_; _y_CMD("checkciphers() " . $cfg{'done'}->{'checkciphers'}); $cfg{'done'}->{'checkciphers'}++; return if (1 < $cfg{'done'}->{'checkciphers'}); _trace("checkciphers($host, $port){"); _checkcipher_init(); # values are set to <>, initialise with "" if (1 > scalar %$results) { # no ciphers found; avoid misleading values foreach my $key (@{$cfg{'need-cipher'}}) { if ($key =~ m/(drown|poodle|has(?:ssl|tls))/) { # keep "disabled ..." message if corresponding -no-SSL option was used next if ($checks{$key}->{val} !~ m/$text{'undef'}/); } $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 %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 $ssl (sort keys %$results) { # check all accepted ciphers next if not $results->{$ssl}; # defensive programming .. (unknown how this can happen) foreach my $key (sort keys %{$results->{$ssl}}) { # SEE Note:Testing, sort next if ($key =~ m/^\s*$/); # defensive programming (key missing in %ciphers) next if not $results->{$ssl}{$key}; # defensive programming .. my $yesno = $results->{$ssl}{$key}; my $cipher = OSaft::Ciphers::get_name($key); if (($cipher =~ m/^\s*$/) || ($yesno =~ m/^\s*$/)) { # defensive programming .. probably programming error _warn("420: empty value for $key => '$cipher: [$yesno]'; check ignored"); next; } if ($yesno =~ m/yes/i) { # cipher accepted $prot{$ssl}->{'cnt'}++; checkcipher($ssl, $key); $checks{'logjam'}->{val} .= _prot_cipher_or_empty($ssl, _is_ssl_logjam($ssl, $cipher)); } $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} = "<>"; my $cnt_pfs = 0; foreach my $ssl (@{$cfg{'version'}}) { # check all SSL versions $cnt_pfs += scalar @{$prot{$ssl}->{'ciphers_pfs'}}; $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 # TODO: $checks{'cipher_pfs'}->{val} = (1 > $cnt_pfs) ? " " : ""; $checks{'cipher_pfsall'}->{val} = ($checks{'cnt_ciphers'}->{val} > $cnt_pfs) ? " " : ""; $checks{'cipher_pfsall'}->{val} = $text{'na'} if (1 > $checks{'cnt_ciphers'}); _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 (1 < $cfg{'done'}->{'checkbleed'}); my $bleed = _is_ssl_bleed($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 (1 < $cfg{'done'}->{'checkdates'}); # 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() function 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 (see _warn 112:). # 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 (not _is_cfg_do('sts_expired')); $txt = ""; $now = time(); # we need epoch timestamp here my $maxage = $data{'hsts_maxage'}->{val}($host); my $ts = "@until"; if (exists &Time::Local::timelocal) { # compute epoch timestamp from 'after', example: Feb 16 10:23:42 2012 GMT $ts = Time::Local::timelocal(reverse(split(/:/, $until[2])), $until[1], $u_mon - 1, $until[3]); $txt = "$now + $maxage > $ts" if ($now + $maxage > $ts); } else { $txt = "$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 (1 < $cfg{'done'}->{'checkcert'}); # 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 (_is_cfg_use('http')) { # 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') || ""; } } } else { $checks{'crl_valid'}->{val} = _get_text('disabled', "--no-http"); } # NOTE: checking OCSP is most likely with http: ; done even if --no-http in use if ($checks{'ocsp_uri'}->{val} eq '') { $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{'ocsp_valid'}->{val}= " "; # _get_text('missing', "OCSP URL"); } # FIXME: more OCSP checks missing, see ../Net/SSLinfo.pm "probably complete OCSP Response Data:" # https://raymii.org/s/articles/OpenSSL_Manually_Verify_a_certificate_against_an_OCSP.html $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_cfg_do('verify')) { # print ""; # print "Hostname validity: " . $data{'verify_hostname'}->{val}($host); # print "Alternate name validity: " . $data{'verify_altname'}->{val}( $host); # } # # if (_is_cfg_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 (1 < $cfg{'done'}->{'checksni'}); 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 (_is_cfg_use('sni')) { # useless check for --no-sni if ($lc_host eq $lc_nosni) { $checks{'sni'}->{val} = ""; } else { $checks{'sni'}->{val} = $data{'cn_nosni'}->{val}; } } if (not _is_cfg_use('cert')) { $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 checksizes($$) { #? compute some lengths and counts from certificate values # sets %checks my ($host, $port) = @_; my $value; _y_CMD("checksizes() " . $cfg{'done'}->{'checksizes'}); $cfg{'done'}->{'checksizes'}++; return if (1 < $cfg{'done'}->{'checksizes'}); checkcert($host, $port) if (_is_cfg_use('cert')); # 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: RFC 5280 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 consist of hex digits if ($value eq '<>') { $checks{'modulus_size_oldssl'}->{val} = $text{'na_openssl'}; } else { $value = length($value) * 4; $checks{'modulus_size_oldssl'}->{val} = $value if ($value > 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 = _get_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 (1 < $cfg{'done'}->{'check02102'}); 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 (1 < $cfg{'done'}->{'check2818'}); 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 (1 < $cfg{'done'}->{'check03116'}); 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 (1 < $cfg{'done'}->{'check6125'}); 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 (1 < $cfg{'done'}->{'check7525'}); 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 _is_rfc7525 # 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 osaft::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 _is_rfc7525() 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 (1 < $cfg{'done'}->{'checkdv'}); # 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 (1 < $cfg{'done'}->{'checkev'}); # 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 (1 < $cfg{'done'}->{'checkroot'}); # SEE Note:root-CA return; } # checkroot sub checkprot($$) { #? check anything related to SSL protocol versions and ALPN, NPN my ($host, $port) = @_; my $ssl; _y_CMD("checkprot() " . $cfg{'done'}->{'checkprot'}); $cfg{'done'}->{'checkprot'}++; return if (1 < $cfg{'done'}->{'checkprot'}); # remember: check is 'yes' for empty value "" # SSLv2 and SSLv3 are special: # The protocol may supported by the target, but no ciphers offered. Only # if at least one ciphers is supported, vulnerabilities may there, hence # check if amount of ciphers > 0. if (_is_cfg_ssl('SSLv2')) { my $notxt = (0 < $prot{'SSLv2'}->{'cnt'}) ? " " : ""; $checks{'hassslv2'} ->{val} = (_is_cfg_use('nullssl2')) ? $notxt : ""; # SSLv2 enabled, but no ciphers is ok (aka 'yes') for --nullssl2 $checks{'drown'} ->{val} = $notxt; # SSLv2 there, then potentially vulnerable to DROWN } if (_is_cfg_ssl('SSLv3')) { my $notxt = (0 < $prot{'SSLv3'}->{'cnt'}) ? " " : ""; $checks{'hassslv3'} ->{val} = $notxt; $checks{'poodle'} ->{val} = (0 < $prot{'SSLv3'}->{'cnt'}) ? "SSLv3" : ""; # POODLE if SSLv3 and 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 now, but needs to be fixed too } if (_is_cfg_ssl('TLSv1')) { $checks{'hastls10'}->{val} = " " if ($prot{'TLSv1'}->{'cnt'} <= 0); } if (_is_cfg_ssl('TLSv11')) { $checks{'hastls11'}->{val} = " " if ($prot{'TLSv11'}->{'cnt'} <= 0); } if (_is_cfg_ssl('TLSv12')) { $checks{'hastls12'}->{val} = " " if ($prot{'TLSv12'}->{'cnt'} <= 0); } if (_is_cfg_ssl('TLSv13')) { $checks{'hastls13'}->{val} = " " if ($prot{'TLSv13'}->{'cnt'} <= 0); } # 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 ""); $key = 'npns'; $value = $data{$key}->{val}($host, $port); $checks{'hasnpn'}->{val} = " " if ($value eq ""); return; } # checkprot sub checkdest($$) { #? check anything related to target and connection my ($host, $port) = @_; my $ciphers = shift; my ($key, $value, $ssl, $cipher, $cnt); _y_CMD("checkdest() " . $cfg{'done'}->{'checkdest'}); $cfg{'done'}->{'checkdest'}++; return if (1 < $cfg{'done'}->{'checkdest'}); # remember: check is 'yes' for empty value "" 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 (not _is_cfg_use('dns')); #$checks{'ip'}->{val} = $cfg{'IP'}; # 12/2019: disabled # 12/2019: only relevant when target was IP, then $cfg{'ip'} must be identical to $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 $cnt = 0; $cnt += $prot{$_}->{'cnt'} foreach (@{$cfg{'version'}}); # count ciphers my @prot = grep{/(^$ssl$)/i} @{$cfg{'versions'}}; if (1 > $cnt) { # no protocol with ciphers found $checks{'cipher_pfs'}->{val}= $text{'miss_protocol'}; } else { if (1 > $#prot) { # found exactly one matching protocol $checks{'cipher_pfs'}->{val}= ("" eq _is_ssl_pfs($ssl, $cipher)) ? $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); # TODO: $checks{'ccs'}->{val} = "<>"; $key = 'compression'; $value = $data{$key}->{val}($host); $checks{$key}->{val} = ($value =~ m/$cfg{'regex'}->{'nocompression'}/) ? "" : $value; $checks{'crime'}->{val} = _is_ssl_crime($value, $data{'next_protocols'}->{val}($host)); foreach my $key (qw(resumption renegotiation)) { next if ($checks{$key}->{val} !~ m/$text{'undef'}/); $value = $data{$key}->{val}($host); $checks{$key}->{val} = ($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 master_secret srp session_ticket session_lifetime)) { # master_key session_id: see %check_dest above also next if ($checks{$key}->{val} !~ m/$text{'undef'}/); $value = $data{$key}->{val}($host); $checks{$key}->{val} = ($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 than +/- 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 next if ($checks{$key}->{val} !~ m/$text{'undef'}/); $checks{$key}->{val} = $data{$key}->{val}($host); $checks{$key}->{val} = "" if ($checks{$key}->{val} =~ m/^\s*$/); } $value = $data{'ocsp_response'}->{val}($host); $checks{'ocsp_stapling'}->{val} = ($value =~ /.*no\s*response.*/i) ? $value : ""; # for valid ocsp_stapling, ocsp_response should be something like: # Response Status: successful (0x0); Cert Status: good; This Update: Jan 01 00:23:42 2021 GMT; Next Update: return; } # checkdest sub checkhttp($$) { #? HTTP(S) checks my ($host, $port) = @_; my $key = ""; _y_CMD("checkhttp() " . $cfg{'done'}->{'checkhttp'}); $cfg{'done'}->{'checkhttp'}++; return if (1 < $cfg{'done'}->{'checkhttp'}); # remember: check is 'yes' for empty value "" # collect information 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_equiv = $data{'hsts_httpequiv'}->{val}($host) || ""; # my $hsts_maxage = $data{'hsts_maxage'} ->{val}($host); # 0 is valid here, hence || does not work $hsts_maxage = -1 if ($hsts_maxage =~ 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/); # RFC 6797 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 !~ m/^\s*https:/) ? $http_location : ""; $checks{'http_https'} ->{val} = $notxt if ($http_location =~ m/^\s*$/); # if missing $checks{'hsts_redirect'}->{val} = $http_sts; # 'yes' if empty if ($data{'https_sts'}->{val}($host) ne "") { my $fqdn = $hsts_fqdn; $checks{'hsts_location'}->{val} = $data{'https_location'}->{val}($host);# 'yes' if empty $checks{'hsts_refresh'} ->{val} = $data{'https_refresh'} ->{val}($host);# 'yes' if empty $checks{'hsts_ip'} ->{val} = ($host =~ m/\d+\.\d+\.\d+\.\d+/) ? $host : ""; # RFC 6797 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} = ($data{'https_sts'} ->{val}($host) ne "") ? "" : $notxt; $checks{'sts_subdom'} ->{val} = ($data{'hsts_subdom'} ->{val}($host) ne "") ? "" : $notxt; $checks{'sts_preload'} ->{val} = ($data{'hsts_preload'}->{val}($host) ne "") ? "" : $notxt; $checks{'sts_maxage'} ->{val} = (($hsts_maxage < $checks{'sts_maxage1m'}->{val}) or ($hsts_maxage > 1)) ? "" : $hsts_maxage; $checks{'sts_maxage'} ->{val}.= ($checks{'sts_maxage'}->{val} eq "" ) ? "" : " = " . int($hsts_maxage / $checks{'sts_maxage1d'}->{val}) . " days" ; # 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" : ""; $checks{'hsts_httpequiv'}->{val} = $hsts_equiv; # RFC 6797 requirement; 'yes' if empty # other sts_maxage* are done below as they change {val} checkdates($host,$port); # computes check{'sts_expired'} } else { # sts_maxage* are integers, must be set here to N/A foreach my $key (qw(sts_maxage00 sts_maxage0d sts_maxagexy sts_maxage18 sts_maxage1d sts_maxage1m sts_maxage1y )) { $checks{$key} ->{val} = $text{'na_STS'}; } } $checks{'hsts_fqdn'} ->{val} = $text{'na'} if ($http_location eq ""); # useless without redirect # TODO: invalid certs are not allowed for HSTS $checks{'https_pins'} ->{val} = $notxt if ($data{'https_pins'}->{val}($host) eq ""); # TODO: pins= ==> fingerprint des Zertifikats $notxt = $text{'na_STS'}; $notxt = $text{'na_http'} if (not _is_cfg_use('http')); # 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 _get_sstp_https { #? get result for SSTP request to host:port; returns '' for success, error otherwise my ($host, $port) = @_; my $ulonglong_max = '18446744073709551615'; my $url = '/sra_{BA195980-CD49-458b-9E23-C84EE0ADCD75}/'; my $length = ""; my $server = ""; my ($status, %headers); my $request = << "EoREQ"; SSTP_DUPLEX_POST $url HTTP/1.1 SSTPCORRELATIONID:{deadbeef-cafe-affe-caba-0000000000} Content-Length: $ulonglong_max Connection: close Host: $host EoREQ #_dbx "_get_sstp_https: request {\n$request#}"; $Net::SSLeay::slowly = 1; # otherwise some server respond with "400 Bad Request" my $dum = $Net::SSLeay::slowly; # keeps Perl happy my $response = Net::SSLeay::sslcat($host, $port, $request); _trace2("_get_sstp_https: response {\n$response#}"); # if SSTP supported, we expect something like:: # HTTP/1.1 200 # Content-Length: 18446744073709551615 # Server: Microsoft-HTTPAPI/2.0 # Date: Mon, 19 May 2019 23:42:42 GMT # Connection: close # convert response to hash; only HTTP header lines are expected, so each # line is a key:value pair, except the very first status line $response =~ s#HTTP/1.. #STATUS: #; # first line is status line, add : $response =~ s#(?:\r\n\r\n|\n\n|\r\r).*$##ms; # remove HTTP body _trace2("_get_sstp_https: response= #{\n$response\n#}"); return "<>" if ($response =~ m/^\s*-1/); # something wrong %headers = map { split(/:/, $_, 2) } split(/[\r\n]+/, $response); # FIXME: map() fails if any header contains [\r\n] (split over more than one line) # use elaborated trace with --trace=3 because some servers return strange results _trace2("_get_sstp_https: headers= " . keys %headers); foreach my $key (keys %headers) { _trace2("_get_sstp_https: headers: $key=$headers{$key}"); } return '401' if ($headers{'STATUS'} =~ m#^\s*401*#); # Microsoft: no SSTP supported return '400' if ($headers{'STATUS'} =~ m#^\s*400*#); # other: no SSTP supported # lazy checks, may also match 4000 etc. if ($headers{'STATUS'} !~ m#^\s*(?:[1234][0-9][0-9]|500)\s*$#) { return "<>"; } if ($headers{'STATUS'} =~ m#^\s*200\s*$#) { $server = $headers{'Server'}; $length = $headers{'Content-Length'}; return _get_text('invalid', "Content-Length: $length") if ($length != $ulonglong_max); return _get_text('invalid', "Server: $server") if ($server !~ /Microsoft-HTTPAPI/); } else { return "<>"; } return ''; } # _get_sstp_https sub checksstp { #? check if host:port supports SSTP my ($host, $port) = @_; _y_CMD("checksstp() " . $cfg{'done'}->{'checksstp'}); $cfg{'done'}->{'checksstp'}++; return if (1 < $cfg{'done'}->{'checksstp'}); return if not defined $host; my $value = _get_sstp_https($host, $port); $checks{'sstp'}->{val} = (0 < length($value)) ? "" : " "; _v_print("checksstp: $value") if length($value); # reason why not supported return; } # checksstp sub checkssl($$) { #? SSL checks my ($host, $port) = @_; my $ciphers = shift; _y_CMD("checkssl() " . $cfg{'done'}->{'checkssl'}); $cfg{'done'}->{'checkssl'}++; return if (1 < $cfg{'done'}->{'checkssl'}); $cfg{'no_cert_txt'} = $text{'na_cert'} if ($cfg{'no_cert_txt'} eq ""); # avoid "yes" results if (_is_cfg_use('cert')) { # 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 (_is_cfg_use('http')) { 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: to be implemented foreach my $key (qw(verify_hostname verify_altname verify dates fingerprint)) { # TODO: only if( not _is_cfg_use('cert')) } return; } # checkssl sub check_exitcode { #? compute exitcode; returns number of failed checks or insecure settings # SEE Note:--exitcode _y_CMD("check_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; # total number of insecure ciphers my $cnt_pfs = 0; # number ciphers without PFS per protocol my $cnt_nopfs = 0; # total number ciphers without PFS my $old_verbose= $cfg{'verbose'}; # save global verbose $cfg{'verbose'} += $cfg{'out'}->{'exitcode'}; # --v and/or --exitcode-v if (_is_cfg_out('exitcode_checks')) { $exitcode = $checks{'cnt_checks_no'} ->{val}; $exitcode -= $checks{'cnt_checks_noo'}->{val}; } # TODO: $cfg{'exitcode_sizes'} my $__tableline = "-------------+---+---+---+---+------+------------"; my $__exitline = "---------------------------------------------------- exitcode"; _v_print("$__exitline {"); _v_print(sprintf("%s\t%3s %3s %3s %3s %7s %s", qw(protocol H M L W no-PFS insecure))); _v_print($__tableline); foreach my $ssl (@{$cfg{'versions'}}) { # SEE Note:%prot next if (0 == $cfg{$ssl}); # not requested, don't count # TODO: counts protocol even if no cipher was supported, is this insecure? $cnt_prot++ if (0 < $cfg{$ssl}); $cnt_pfs = $prot{$ssl}->{'cnt'} - $#{$prot{$ssl}->{'ciphers_pfs'}}; $cnt_pfs = 0 if (0 >= $prot{$ssl}->{'cnt'}); # useless if there're no ciphers $exitcode += $cnt_pfs if (_is_cfg_out('exitcode_pfs')); $cnt_ciph = 0; $cnt_ciph += $prot{$ssl}->{'MEDIUM'} if (_is_cfg_out('exitcode_medium')); $cnt_ciph += $prot{$ssl}->{'WEAK'} if (_is_cfg_out('exitcode_weak')); $cnt_ciph += $prot{$ssl}->{'LOW'} if (_is_cfg_out('exitcode_low')); $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; } # print overview of calculated exitcodes; # for better human readability, counts disabled by --exitcode-no-* options # are marked as "ignored" #my $ign_ciphs = (0 < ($cfg{'out'}->{'exitcode_low'} + $cfg{'out'}->{'exitcode_weak'} + $cfg{'out'}->{'exitcode_medium'})) ? "" : " (count ignored)"; my $ign_ciphs = (_is_cfg_out('exitcode_low') or _is_cfg_out('exitcode_weak') or _is_cfg_out('exitcode_medium')) ? "" : " (count ignored)"; my $ign_checks = (_is_cfg_out('exitcode_checks')) ? "" : " (count ignored)"; my $ign_prot = (_is_cfg_out('exitcode_prot')) ? "" : " (count ignored)"; my $ign_pfs = (_is_cfg_out('exitcode_pfs')) ? "" : " (count ignored)"; _v_print($__tableline); $cnt_prot-- if (0 < $cfg{'TLSv12'}); $cnt_prot-- if (0 < $cfg{'TLSv13'}); $exitcode += $cnt_prot if (_is_cfg_out('exitcode_prot')); $checks{'cnt_exitcode'}->{val} = $exitcode; _v_print(sprintf("%s\t%5s%s", "Total number of insecure protocols", $cnt_prot, $ign_prot)); _v_print(sprintf("%s\t%5s%s", "Total number of insecure ciphers", $cnt_ciphs, $ign_ciphs)); _v_print(sprintf("%s\t%5s%s", "Total number of ciphers without PFS", $cnt_nopfs, $ign_pfs)); _v_print(sprintf("%s\t%5s%s", $checks{'cnt_checks_no'} ->{txt}, $checks{'cnt_checks_no'} ->{val}, $ign_checks)); _v_print(sprintf("%s %3s%s", $checks{'cnt_checks_noo'}->{txt}, "-".$checks{'cnt_checks_noo'}->{val}, $ign_checks)); _v_print(sprintf("%s\t%5s", $checks{'cnt_exitcode'} ->{txt}, $checks{'cnt_exitcode'} ->{val})); _v_print("$__exitline }"); $cfg{'verbose'} = $old_verbose; # restore 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|https_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_cfg_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 print_ruler { printf("=%s+%s\n", '-'x38, '-'x35) if (_is_cfg_out('header')); return; } #? print header ruler line sub print_header { #? print title line and table haeder line if second argument given my ($txt, $desc, $rest, $header) = @_; return if (0 >= $header); printf("$txt\n"); return if ($desc =~ m/^ *$/); # title only if no more arguments printf("= %-37s %s\n", $text{'desc'}, $desc); print_ruler(); return; } # print_header sub print_footer { #? print footer line according given legacy format my $legacy = shift; if ($legacy eq 'sslyze') { print "\n\n SCAN COMPLETED IN ...\n\n"; } # all others are empty, no need to do anything return; } # print_footer sub print_title { #? 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 =~ /(compact|full|owasp|quick|simple)/) { print_header($txt, "", "", 1); # SEE Note:Cipher and Protocol } return; } # print_title 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 $value = Encode::decode("UTF-8", $value); # 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 (_is_cfg_out('hostname')); if ($legacy eq '_cipher') { printf("%s", $label) if (_is_cfg_out('hostname')); printf("#[%s]%s", $key, $text{'separator'}) if (_is_cfg_out('traceKEY')); return; } $label .= sprintf("#[%-18s", $key . ']' . $text{'separator'}) if (_is_cfg_out('traceKEY')); 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_cfg_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'}})); # 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); osaft::printhint($key) if (_is_cfg_out('hint_info')); # SEE Note:hints 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); osaft::printhint($key) if (_is_cfg_out('hint_check')); # SEE Note:hints 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 {printf("= %s+%s\n", "-"x35, "-"x25) if (_is_cfg_out('header')); return; } #? print header ruler line for ciphers with DH parameters sub print_cipherruler { printf("= %s+%s+%s\n", "-"x35, "-"x7, "-"x8) if (_is_cfg_out('header')); return; } #? print header ruler line for ciphers sub print_cipherhead($) { #? print header line according given legacy format my $legacy = shift; return if (not _is_cfg_out('header')); 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'); } # old version if ($legacy eq 'ssltest-g') { printf("Status(Compliant,Non-compliant,Disabled);Hostname:Port;SSL-Protocol;Cipher-Name;Cipher-Description\n"); } 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') { # my @heads = @{$ciphers_desc{'head'}};# not used because not all parts wanted printf("= host:port\tsupport\tprot.\tsec\tkeyx\tauth\tenc bits\tmac\tcipher key\tcipher name\tcomment\n"); } # 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, $key, $support) = @_; my $cipher= OSaft::Ciphers::get_name($key); my $bits = OSaft::Ciphers::get_bits($key); my $sec = OSaft::Ciphers::get_sec($key); # will be changed for --legacy=owasp $sec = osaft::get_cipher_owasp($cipher) if ('owasp' eq $legacy); $sec = "-" if (('no' eq $support) and ('owasp' eq $legacy)); #my $desc = OSaft::Ciphers::get_data($key);# not yet used my $yesno = $text{'legacy'}->{$legacy}->{$support}; # first our own formats if ($legacy =~ m/compact|full|owasp|quick|simple|key/) { my $k = sprintf("%s", OSaft::Ciphers::get_key($cipher)); print_line('_cipher', $host, $port, $key, $cipher, ""); # just host:port:#[key]: if ('key' eq $cfg{'label'}) { # TODO: $cfg{'label'} should be a parameter $k = "[$key]\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, $bits, $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%s:%s\t%s\t%s\t%s\t%s\t%s\t%s%7s\t%s\t%s\t%s\t%s\n", $k, $host, $port, $yesno, $ssl, $sec, OSaft::Ciphers::get_keyx($key), OSaft::Ciphers::get_auth($key), OSaft::Ciphers::get_enc( $key), $bits, OSaft::Ciphers::get_mac( $key), $key, $cipher, OSaft::Ciphers::get_const($key), ) if ($legacy eq 'full'); # TODO: check if OSaft::Ciphers::get_ssl($key) matches $ssl return; } # now legacy formats # TODO: should be moved to postprocessor if ($legacy eq 'sslyze') { if ($support eq 'yes') { $support = sprintf("%4s bits", $bits) 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, $bits); } 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, $bits, $yesno); } if ($legacy eq 'sslscan') { # Rejected SSLv3 256 bits ADH-AES256-SHA # Accepted TLSv1.2 256 bits AES256-SHA256 $bits = sprintf("%3s bits", $bits); # printf(" %s %s %s\n", $ssl, $bit, $cipher); # TODO: new format 1.11.0 printf("Accepted %s %s bits %s\n", $ssl, $bits, $cipher); } if ($legacy eq 'thcsslcheck') { # AES256-SHA - 256 Bits - supported printf("%30s - %3s Bits - %11s\n", $cipher, $bits, $yesno); } # compliant;host:port;protocol;cipher;description if ($legacy eq 'ssltest') { # cipher, description, (supported) return if ("" eq $cipher); # defensive programming .. # TODO: analyse when $cipher could be "", should not happen printf(" %s, %s %s bits, %s Auth, %s MAC, %s Kx (%s)\n", $cipher, OSaft::Ciphers::get_enc( $key), $bits, OSaft::Ciphers::get_auth($key), OSaft::Ciphers::get_mac( $key), OSaft::Ciphers::get_keyx($key), $yesno ); } if ($legacy eq 'ssltest-g') { return if ("" eq $cipher); # defensive programming .. printf("%s;%s;%s;%s;%s %s bits, %s Auth, %s MAC, %s Kx\n", 'C', $host . ":" . $port, $ssl, $cipher, OSaft::Ciphers::get_enc( $key), $bits, OSaft::Ciphers::get_auth($key), OSaft::Ciphers::get_mac( $key), OSaft::Ciphers::get_keyx($key), ); } if ($legacy eq 'testsslserver') { printf(" %s\n", $cipher); } return; } # print_cipherline sub print_cipherpreferred($$$$) { #? print preferred 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 my $key = OSaft::Ciphers::get_key($data{'cipher_selected'}->{val}($host)); # TODO use key print_cipherline($legacy, $ssl, $host, $port, $key, $yesno); return; } # print_cipherpreferred 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 =~ /(compact|full|owasp|quick|simple)/) { print_header(_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_cipher { #? 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_cipher # NOTE: Perl::Critic's violation for next 2 subs are false positives sub _print_cipher_results { #? print all ciphers from %results of $ssl if match $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, print all if empty my $results = shift; # reference to hash with cipher keys for $ssl my $total = 0; # list of ciphers in $results->{'sorted'} is sorted according strength # most strong ciphers should be printed first, hence loop over list of # keys in 'sorted' instead of (keys %$results). foreach my $key (@{$results->{'sorted'}}) { if (not $results->{$key}) { # defensive programming .. _warn("863: unknown cipher key '$key'; key ignored"); next; } my $r_yesno = $results->{$key}; # [0]; $total++; next if (($r_yesno ne $yesno) and ("" ne $yesno)); next if not _is_print_cipher($r_yesno, $cfg{'out'}->{'disabled'}, $cfg{'out'}->{'enabled'}); print_cipherline($legacy, $ssl, $host, $port, $key, $r_yesno); } return $total; } # _print_cipher_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 cipher keys my $unique = 0; # count unique ciphers my $last_r = ""; # avoid duplicates (may be added by checkSSLciphers()) print_cipherhead( $legacy) if ($outtitle == 0); foreach my $key (@results) { next if ($last_r eq $key); print_cipherline($legacy, $ssl, $host, $port, $key, "yes"); $last_r = $key; $unique++; } print_cipherruler() if ($legacy =~ /(?:owasp|simple)/); print_footer($legacy); return $unique; } # printcipherall sub printciphercheck { #? 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 = shift; # reference to hash with cipher keys for all $ssl my $total = 0; print_cipherhead( $legacy) if ($count == 0); print_cipherpreferred($legacy, $ssl, $host, $port) if ($legacy eq 'sslaudit'); my @sorted = OSaft::Ciphers::sort_results($results->{$ssl}); # sorting has no impact on severity _trace2("printciphercheck: sorted $#sorted : @sorted"); $results->{$ssl}{'sorted'} = \@sorted; # pass sorted list to subroutines if ($legacy ne 'sslyze') { $total = _print_cipher_results($legacy, $ssl, $host, $port, "", $results->{$ssl}); # 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_cipherpreferred($legacy, $ssl, $host, $port); if (_is_cfg_out('enabled') or (_is_cfg_out('disabled') == _is_cfg_out('enabled'))) { print "\n Accepted Cipher Suites:"; $total = _print_cipher_results($legacy, $ssl, $host, $port, "yes", $results->{$ssl}); } if (_is_cfg_out('disabled') or (_is_cfg_out('disabled') == _is_cfg_out('enabled'))) { print "\n Rejected Cipher Suites:"; $total = _print_cipher_results($legacy, $ssl, $host, $port, "no", $results->{$ssl}); } } #print_ciphertotals($legacy, $ssl, $host, $port); # up to version 15.10.15 print_footer($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 = osaft::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'}}) { print_title($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 # ------- # RFC 4492 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 RFC 4492 Table 3 # ------- # cipherPcurve ...P256 # TODO: } print_cipherruler_dh(); } return; } # printciphers_dh sub printcipherpreferred { #? print table with preferred/selected (default) cipher per protocol my ($legacy, $host, $port) = @_; local $\ = "\n"; if (_is_cfg_out('header')) { printf("= prot.\t%-31s%s\n", "preferred cipher (strong first)", "preferred 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 (_is_cfg_out('header')) { printf("=------+------------------------------+-------------------------------\n"); } print_data($legacy, $host, $port, 'cipher_selected'); # SEE Note:Selected Cipher return; } # printcipherpreferred sub printprotocols { #? print table with cipher information 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 (_is_cfg_out('header')) { 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 preferred-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 preferred-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'}; # FIXME: fails for --ciphermode=intern 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 (_is_cfg_out('header')) { printf("=------%s%s\n", ('+---' x 6), '+-------------------------------+---------------'); } return; } # printprotocols sub printciphersummary { #? print summary of cipher check +cipher my ($legacy, $host, $port, $total) = @_; if ($legacy =~ /(compact|full|owasp|quick|simple)/) { # but only our formats print_header("\n" . _get_text('out_summary' , ""), "", "", $cfg{'out'}->{'header'}); print_check( $legacy, $host, $port, 'cnt_totals', $total) if ($cfg{'verbose'} > 0); printprotocols($legacy, $host, $port); } _y_CMD("printciphersummary() "); if (0 < $cfg{'need_netinfo'}) { my $key; my $_verbose = $Net::SSLinfo::verbose; # save if (2 > $_verbose) { # avoid huge verbosity in simple cases $Net::SSLinfo::verbose = 0 if 2 > $_verbose; if (0 < $_verbose) { _hint("use --v --v for verbose output of 'cipher_selected' or use '+cipher_selected'"); } } my $cipher = $data{'cipher_selected'}->{val}($host, $port); print_line($legacy, $host, $port, 'cipher_selected', $data{'cipher_selected'}->{txt}, "$cipher " . _cipher_get_sec($cipher) ); $Net::SSLinfo::verbose = $_verbose; # restore } else { _hint("'cipher_selected' temporarily disabled"); # TODO: adapte to new SSLhello (2/2021) } _hint("consider using '--cipheralpn=, --ciphernpn=,' also") if ($cfg{'verbose'} > 0); return; } # printciphersummary sub printdata($$$) { #? print information stored in %data my ($legacy, $host, $port) = @_; local $\ = "\n"; print_header($text{'out_infos'}, $text{'desc_info'}, "", $cfg{'out'}->{'header'}); _trace_cmd('%data'); if (_is_cfg_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 " . _cipher_get_sec($key)); } foreach my $key (@{$cfg{'do'}}) { next if (_is_member( $key, \@{$cfg{'commands_notyet'}})); next if (_is_member( $key, \@{$cfg{'ignore-out'}})); next if (not _is_hashkey($key, \%data)); next if ($key eq 'cipher_selected');# value is special, done above if (not _is_cfg_use('experimental')) { next if (_is_member( $key, \@{$cfg{'commands_exp'}})); } # special handling vor +info--v if (_is_cfg_do('info--v')) { next if ($key eq 'info--v'); next if ($key =~ m/$cfg{'regex'}->{'commands_int'}/i); } else { next if (_is_cfg_intern($key)); } _y_CMD("(%data) +" . $key); my $value = $data{$key}->{val}($host); if (_is_member( $key, \@{$cfg{'cmd-NL'}})) { # for +info print multiline data only if --v given # if command given explicitly, i.e. +text, print if (_is_cfg_do('info') and (0 >= $cfg{'verbose'})) { _hint("use '--v' to print multiline data of '+$key' for '+info'"); 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"; print_header($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 (not _is_cfg_use('cert')); foreach my $key (@{$cfg{'do'}}) { _trace("printchecks: (%checks) ?" . $key); next if (_is_member( $key, \@{$cfg{'commands_notyet'}})); next if (_is_member( $key, \@{$cfg{'ignore-out'}})); next if (not _is_hashkey($key, \%checks)); next if (_is_cfg_intern( $key));# ignore aliases next if ($key =~ m/$cfg{'regex'}->{'SSLprot'}/); # these counters are already printed if (not _is_cfg_use('experimental')) { next if (_is_member( $key, \@{$cfg{'commands_exp'}})); } $value = _get_yes_no($checks{$key}->{val}); _y_CMD("(%checks) +" . $key); if ($key =~ /$cfg{'regex'}->{'cmd-sizes'}/) { # sizes are special print_size($legacy, $host, $port, $key) if (_is_cfg_use('cert')); } 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/); $checks{'cnt_checks_noo'}->{val}++ if ($value =~ /^no\s*\(< $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_version sub printversionmismatch { #? check if openssl and compiled SSLeay are of same version my $o = Net::SSLeay::OPENSSL_VERSION_NUMBER(); my $s = __SSLeay_version(); 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"; } if (defined $ENV{PWD}) { print( "=== started in: $ENV{PWD} ==="); # avoid "use Cwd;" or `pwd` } # quick&dirty check, should rarely occour (i.e. when used as CGI) # SEE Note:OpenSSL Version my $version_openssl = Net::SSLeay::OPENSSL_VERSION_NUMBER() || $STR{UNDEF}; my $me = $cfg{'me'}; 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_version(), __SSLeay_version()); 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','','',''); } $Net::SSLinfo::verbose = 0; # do not set here; will not be used later print "= openssl ="; print " external executable " . (($cmd{'openssl'} eq "") ? "<>" : $cmd{'openssl'}); print " external executable (TLSv1.3) " . (($cmd{'openssl3'} eq "") ? "<>" : $cmd{'openssl3'}); print " version of external executable " . Net::SSLinfo::do_openssl('version', '', '', ''); print " used environment variable (name) " . $cmd{'envlibvar'}; #print " used environment variable 3(name)" . $cmd{'envlibvar3'}; 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"; } } } print "= $me ="; 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 +cipher --ciphermode=openssl or --ciphermode=ssleay ="; 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 (0 < $cfg{'verbose'}); _hint("use '--v' to get list of ciphers") if (0 == $cfg{'verbose'}); print " openssl supported SSL versions " . join(" ", @{$cfg{'version'}}); print " $me known SSL versions " . join(" ", @{$cfg{'versions'}}); printversionmismatch(); print "= $me +cipher --ciphermode=intern ="; my @cnt = (_eval_cipherranges($cfg{'cipherrange'})); my $list= $cfg{'cipherranges'}->{$cfg{'cipherrange'}}; $list=~ s/ */ /g; # squeeze leading spaces print " used cipherrange " . $cfg{'cipherrange'}; print " number of supported ciphers " . scalar @cnt; print " default list of ciphers " . $list; 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 OSaft::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) { $d = $INC{$m} || $STR{UNDEF}; # defensive progamming; sometimes undefined, reason unknown printf(" %-22s %6s\n", $m, $d); $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 printciphers { #? print cipher descriptions from internal database # uses settings from --legacy= and option -v or -V to select output format if (_is_cfg_do('ciphers')) { # output looks like: openssl ciphers _y_CMD("simulate 'openssl ciphers'"); $cfg{'out'}->{'header'} = 0; $cfg{'legacy'} = 'openssl'; $cfg{'legacy'} = 'openssl-v' if (0 < $cfg{'opt-v'}); $cfg{'legacy'} = 'openssl-V' if (0 < $cfg{'opt-V'}); } # anything else prints user-specified formats _trace("printciphers: +list"); # late, to not disturb output of plain "ciphers" _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{'opt-v'} , -V=$cfg{'opt-V'}"); OSaft::Ciphers::show($cfg{'legacy'}); 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); print_header($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}); print_ruler(); if (_is_cfg_out('traceKEY') and (0 < $verbose)) { _y_CMD("verbose score table"); print "\n"; printtable('score'); print_ruler(); } return; } # printscores sub printopenssl { #? print openssl version print Net::SSLinfo::do_openssl('version', '', '', ''); printversionmismatch(); return; } # printopenssl sub printusage_exit { #? print simple usage, first line with passed text my @txt = @_; local $\ = "\n"; print $STR{USAGE}, @txt; print "# most common usage: $cfg{'me'} +info your.tld $cfg{'me'} +check your.tld $cfg{'me'} +cipher your.tld # for more help use: $cfg{'me'} --h $cfg{'me'} --help "; exit 2; } # printusage_exit usr_pre_args(); #_____________________________________________________________________________ #_____________________________________________________________________ main __| #| 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 # +---------+--------------+------------------------------------------ if ($typ eq 'CFG_INIT') { _cfg_set_init( $typ, $arg); } if ($typ eq 'CFG_CIPHER') { _cipher_set_sec($typ, $arg); $typ = 'HOST'; } # $typ set to avoid next match if ($typ =~ m/^CFG/) { _cfg_set( $typ, $arg); } # 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 'LD_ENV') { $cmd{'envlibvar'} = $arg; } if ($typ eq 'LD_ENV3') { $cmd{'envlibvar3'} = $arg; } if ($typ eq 'OPENSSL') { $cmd{'openssl'} = $arg; } if ($typ eq 'OPENSSL3') { $cmd{'openssl3'} = $arg; } if ($typ eq 'OPENSSL_CNF') { $cfg{'openssl_cnf'} = $arg; } if ($typ eq 'OPENSSL_FIPS') { $cfg{'openssl_fips'}= $arg; } if ($typ eq 'VERBOSE') { $cfg{'verbose'} = $arg; } if ($typ eq 'DO') { push(@{$cfg{'do'}}, $arg); } # treat as command, if ($typ eq 'EXE') { push(@{$cmd{'path'}}, $arg); } if ($typ eq 'LIB') { push(@{$cmd{'libs'}}, $arg); } if ($typ eq 'CALL') { push(@{$cmd{'call'}}, $arg); } if ($typ eq 'SEP') { $text{'separator'} = $arg; } if ($typ eq 'OPT') { $cfg{'sclient_opt'}.= " $arg";} if ($typ eq 'TIMEOUT') { $cfg{'timeout'} = $arg; } if ($typ eq 'CERT_TEXT') { $cfg{'no_cert_txt'} = $arg; } if ($typ eq 'CA_FILE') { $cfg{'ca_file'} = $arg; } if ($typ eq 'CA_PATH') { $cfg{'ca_path'} = $arg; } if ($typ eq 'CA_DEPTH') { $cfg{'ca_depth'} = $arg; } # TODO: use cfg{'targets'} for proxy* if ($typ eq 'PROXY_PORT') { $cfg{'proxyport'} = $arg; } if ($typ eq 'PROXY_USER') { $cfg{'proxyuser'} = $arg; } if ($typ eq 'PROXY_PASS') { $cfg{'proxypass'} = $arg; } if ($typ eq 'PROXY_AUTH') { $cfg{'proxyauth'} = $arg; } if ($typ eq 'SNINAME') { $cfg{'sni_name'} = $arg; } if ($typ eq 'TTY_ARROW') { _set_cfg_tty('arrow', $arg); } if ($typ eq 'TTY_IDENT') { _set_cfg_tty('ident', $arg); } if ($typ eq 'TTY_WIDTH') { _set_cfg_tty('width', $arg); } if ($typ eq 'ANON_OUT') { $cfg{'regex'}->{'anon_output'} = qr($arg); } if ($typ eq 'FILE_SCLIENT') { $cfg{'data'}->{'file_sclient'} = $arg; } if ($typ eq 'FILE_CIPHERS') { $cfg{'data'}->{'file_ciphers'} = $arg; } if ($typ eq 'FILE_PCAP') { $cfg{'data'}->{'file_pcap'} = $arg; } if ($typ eq 'FILE_PEM') { $cfg{'data'}->{'file_pem'} = $arg; } if ($typ eq 'SSLHELLO_RETRY'){$cfg{'sslhello'}->{'retry'} = $arg; } if ($typ eq 'SSLHELLO_TOUT'){ $cfg{'sslhello'}->{'timeout'} = $arg; } if ($typ eq 'SSLHELLO_MAXC'){ $cfg{'sslhello'}->{'maxciphers'}= $arg; } if ($typ eq 'SSLERROR_MAX') { $cfg{'sslerror'}->{'max'} = $arg; } if ($typ eq 'SSLERROR_TOT') { $cfg{'sslerror'}->{'total'} = $arg; } if ($typ eq 'SSLERROR_DLY') { $cfg{'sslerror'}->{'delay'} = $arg; } if ($typ eq 'SSLERROR_TOUT'){ $cfg{'sslerror'}->{'timeout'} = $arg; } if ($typ eq 'SSLERROR_PROT'){ $cfg{'sslerror'}->{'per_prot'} = $arg; } if ($typ eq 'CONNECT_DELAY'){ $cfg{'connect_delay'} = $arg; } if ($typ eq 'STARTTLS') { $cfg{'starttls'} = $arg; } if ($typ eq 'TLS_DELAY') { $cfg{'starttls_delay'} = $arg; } if ($typ eq 'SLOW_DELAY') { $cfg{'slow_server_delay'} = $arg; } if ($typ eq 'STARTTLSE1') { $cfg{'starttls_error'}[1] = $arg; } if ($typ eq 'STARTTLSE2') { $cfg{'starttls_error'}[2] = $arg; } if ($typ eq 'STARTTLSE3') { $cfg{'starttls_error'}[3] = $arg; } if ($typ eq 'STARTTLSP1') { $cfg{'starttls_phase'}[1] = $arg; } if ($typ eq 'STARTTLSP2') { $cfg{'starttls_phase'}[2] = $arg; } if ($typ eq 'STARTTLSP3') { $cfg{'starttls_phase'}[3] = $arg; } if ($typ eq 'STARTTLSP4') { $cfg{'starttls_phase'}[4] = $arg; } if ($typ eq 'STARTTLSP5') { $cfg{'starttls_phase'}[5] = $arg; } if ($typ eq 'PORT') { $cfg{'port'} = $arg; } #if ($typ eq 'HOST') # not done here, but at end of loop # +---------+--------------+------------------------------------------ if ($typ eq 'NO_OUT') { if ($arg =~ /^[,:]*$/) { # special to set empty string $cfg{'ignore-out'} = []; } else { push(@{$cfg{'ignore-out'}}, $arg); } } if ($typ eq 'CIPHER_ITEM') { # $arg = lc($arg); # case-sensitive #TODO: cipherpatterns nur bei cipher_openssl benutzen if (defined $cfg{'cipherpatterns'}->{$arg}) { # our own aliases ... $arg = $cfg{'cipherpatterns'}->{$arg}[1]; } else { # anything else, #TODO: Prüfung weg, damit auch SSLv2_long möglich if ($arg !~ m/^[XxA-Z0-9-]+$/) { # must be upper case # x in RegEx to allow hex keys of ciphers like 0x0300C014 _warn("062: given pattern '$arg' for cipher unknown; setting ignored"); $arg = ""; } } push(@{$cfg{'cipher'}}, $arg) if ($arg !~ m/^\s*$/); } if ($typ eq 'STD_FORMAT') { $arg = lc($arg); 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; } } if ($typ eq 'PROXY_HOST') { # 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 } } # following ($arg !~ /^\s*$/) check avoids warnings in CGI mode if ($typ eq 'LABEL') { $arg = lc($arg); 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 = lc($arg); $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 = lc($arg); $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 'CIPHER_RANGE') { if (1 == (grep{/^$arg$/i} keys %{$cfg{'cipherranges'}})) { $cfg{'cipherrange'} = $arg; # case-sensitive } else { _warn("056: option with unknown cipher range '$arg'; setting ignored") if ($arg !~ /^\s*$/); } } if ($typ eq 'CIPHER_MODE') { $arg = lc($arg); if (1 == (grep{/^$arg$/i} @{$cfg{'ciphermodes'}})) { $cfg{'ciphermode'} = $arg; } else { _warn("057: option with unknown cipher mode '$arg'; setting ignored") if ($arg !~ /^\s*$/); } } if ($typ eq 'CIPHER_CURVES') { $arg = lc($arg); $cfg{'ciphercurves'} = [""] if ($arg =~ /^[,:][,:]$/);# special to set empty string if ($arg =~ /^[,:]$/) { $cfg{'ciphercurves'} = []; } else { push(@{$cfg{'ciphercurves'}}, split(/,/, lc($arg))); } } # 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'){ $arg = lc($arg); $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'){ $arg = lc($arg); $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'){ $arg = lc($arg); $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 _set_cfg_out('traceARG', 1) if ($arg =~ m#^ARG$#i); _set_cfg_out('traceCMD', 1) if ($arg =~ m#^CMD$#i); _set_cfg_out('traceKEY', 1) if ($arg =~ m#^KEY$#i); _set_cfg_out('traceTIME', 1) 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 _y_ARG("arg_val? $arg"); # 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 _y_ARG("opt_old? $arg"); 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 _y_ARG("opt_usr? $arg"); 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 _y_ARG("opt_--h? $arg"); if ($arg =~ /^--h$/) { $arg = "--help=help_brief"; } # --h is special if ($arg =~ /^(?:--|\+)help$/) { $arg = "--help=NAME"; } # --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*$/); # pass bare word, if it was --help=* } # 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 if ($arg =~ /^gen[._=-]?docs$/) { # --help=gen-docs man_docs_write($arg); } else { printhelp($arg); } exit 0; } #{ handle some specials _y_ARG("optmisc? $arg"); #!#--------+------------------------+--------------------------+------------ #!# argument to check what to do what to do next #!#--------+------------------------+--------------------------+------------ if ($arg eq '--trace--') { _set_cfg_out('traceARG',1); next; } # for backward compatibility if ($arg =~ /^--trace.?CLI$/) { next; } # ignore, already handled 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 eq '+VERSION') { _version_exit(); exit 0; } # used with --cgi-exec if ($arg eq '--yeast') { $arg = '--test-data'; } # TODO: should become a more general check if ($arg =~ /^--yeast[_.-]?(.*)/) { $arg = "--test-$1"; } # -"- # 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 # normalise 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 # normalise option strings: # --opt-name --> --optname # --opt_name --> --optname # --opt.name --> --optname $arg =~ s/([a-zA-Z0-9])(?:[_.-])/$1/g if ($arg =~ /^-/); #_dbx("normalised= $arg"); # Following checks use exact matches with 'eq' or RegEx matches with '=~' _y_ARG("option? $arg"); #{ OPTIONS # NOTE: that strings miss - and _ characters (see normalisation 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 = '+cipher'; } # alias: testssl.sh if ($arg =~ /^-(f|-ciphers)$/) { $arg = '+ciphercheck'; } # alias: testssl.sh (+ciphercheck defined in .o-saft.pl) if ($arg =~ /^-(x|-single-cipher)$/){ $typ = 'CIPHER_ITEM'; } # alias: testssl.sh (must be used together with +cipher) 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 =~ /^-(Z|-tls-fallback)$/) { $arg = '+fallback_protocol'; } # alias: testssl.sh if ($arg =~ /^-(s|4)$/) { $arg = '+pfs'; } # 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 eq '--version') { $arg = '+version'; } # alias: various programs 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?$/) { _set_cfg_out('warning', 1); } if ($arg =~ /^--nowarnings?$/) { _set_cfg_out('warning', 0); } if ($arg =~ /^--warningsdups?$/) { _set_cfg_out('warnings_no_dups', []); } if ($arg =~ /^--nowarningsnodups?$/){ _set_cfg_out('warnings_no_dups', []); } if ($arg eq '--n') { $cfg{'try'} = 1; } if ($arg eq '--dryrun') { $cfg{'try'} = 1; } # alias: --n if ($arg =~ /^--tracearg/i) { _set_cfg_out('traceARG', 1); } # special internal tracing if ($arg =~ /^--tracecmd/i) { _set_cfg_out('traceCMD', 1); } # .. if ($arg =~ /^--trace(?:@|key)/i) { _set_cfg_out('traceKEY', 1); } # .. if ($arg =~ /^--tracetime/i) { _set_cfg_out('traceTIME', 1); } # .. if ($arg =~ /^--traceme/i) { $cfg{'traceME'}++; } # .. if ($arg =~ /^--tracenotme/i) { $cfg{'traceME'}--; } # .. if ($arg eq '--trace') { $typ = 'TRACE'; } if ($arg =~ /^--timeabsolute?/i) { _set_cfg_out('time_absolut', 1); } if ($arg eq '--timerelative') { _set_cfg_out('time_absolut', 0); } if ($arg eq '--linuxdebug') { $cfg{'linux_debug'}++; } if ($arg eq '--slowly') { $cfg{'slowly'} = 1; } if ($arg =~ /^--exp(?:erimental)?$/){ _set_cfg_use('experimental', 1); } if ($arg =~ /^--noexp(erimental)?$/){ _set_cfg_use('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'; } if ($arg eq '--anonoutput') { $typ = 'ANON_OUT'; } # SEE Note:anon-out if ($arg =~ /^--tests?/) { $test = $arg; } # SEE Note:--test-* if ($arg =~ /^[+,]tests?/) { $test = $arg; next; } # SEE Note:--test-* # handles also --test-* and --tests-*; no further check if +test* # proxy options if ($arg =~ /^--proxy(?:host)?$/) { $typ = 'PROXY_HOST'; } if ($arg eq '--proxyport') { $typ = 'PROXY_PORT'; } if ($arg eq '--proxyuser') { $typ = 'PROXY_USER'; } if ($arg eq '--proxypass') { $typ = 'PROXY_PASS'; } if ($arg eq '--proxyauth') { $typ = 'PROXY_AUTH'; } if ($arg =~ /^--?starttls$/i) { $typ = 'STARTTLS'; } if ($arg =~ /^--starttlsdelay$/i) { $typ = 'TLS_DELAY'; } if ($arg =~ /^--slowserverdelay$/i) { $typ = 'SLOW_DELAY'; } 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') { $typ = 'PROTOCOL'; } # ssl-cert-check # NOTE: not supported # if ($arg eq '-V') { $cfg{'opt-V'} = 1; } # ssl-cert-check; will be out->header, # TODO not supported if ($arg eq '-v') { $cfg{'opt-v'} = 1; } # openssl, ssl-cert-check if ($arg eq '-V') { $cfg{'opt-V'} = 1; } # openssl, ssl-cert-check if ($arg eq '--V') { $cfg{'opt-V'} = 1; } # alias: 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 eq '--openssl3') { $typ = 'OPENSSL3'; } if ($arg =~ '--opensslco?nf') { $typ = 'OPENSSL_CNF'; } if ($arg eq '--opensslfips') { $typ = 'OPENSSL_FIPS'; } 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') { _set_cfg_use('alpn', 1);} if ($arg eq '--noalpn') { _set_cfg_use('alpn', 0);} if ($arg eq '--npn') { _set_cfg_use('npn', 1);} if ($arg eq '--nonpn') { _set_cfg_use('npn', 0);} if ($arg =~ /^--?nextprotoneg$/) { _set_cfg_use('npn', 1);} # openssl if ($arg =~ /^--nonextprotoneg/) { _set_cfg_use('npn', 0);} if ($arg =~ /^--?comp(?:ression)?$/){ $arg = '--sslcompression'; } # alias: if ($arg =~ /^--?nocomp(ression)?$/){ $arg = '--nosslcompression'; } # alias: if ($arg =~ /^--sslcompression$/) { _set_cfg_use('no_comp', 0); } # openssl s_client -comp if ($arg =~ /^--nosslcompression$/) { _set_cfg_use('no_comp', 1); } # openssl s_client -no_comp if ($arg =~ /^--?tlsextdebug$/) { _set_cfg_use('extdebug', 1); } if ($arg =~ /^--notlsextdebug/) { _set_cfg_use('extdebug', 0); } if ($arg =~ /^--?reconnect$/) { _set_cfg_use('reconnect', 1); } if ($arg =~ /^--noreconnect$/) { _set_cfg_use('reconnect', 0); } if ($arg eq '--sclientopt') { $typ = 'OPT'; } # various options if ($arg eq '--forcesni') { _set_cfg_use('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') { _set_cfg_use('lwp', 1);} if ($arg eq '--sni') { _set_cfg_use('sni', 1);} if ($arg eq '--nosni') { _set_cfg_use('sni', 0);} if ($arg eq '--snitoggle') { _set_cfg_use('sni', 3);} if ($arg eq '--togglesni') { _set_cfg_use('sni', 3);} if ($arg eq '--nocert') { _set_cfg_use('cert', 0);} 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') { _set_cfg_use('exitcode', 0); } if ($arg eq '--exitcode') { _set_cfg_use('exitcode', 1); } # SEE Note:--exitcode if ($arg =~ /^--exitcodev/) { _set_cfg_out('exitcode', 1); } # if ($arg =~ /^--traceexit/) { _set_cfg_out('exitcode', 1); } # alias: --exitcode if ($arg =~ /^--exitcodequiet/) { _set_cfg_out('exitcode_quiet', 1); } # if ($arg =~ /^--exitcodesilent/) { _set_cfg_out('exitcode_quiet', 1); } # alias: --exitcode-quiet if ($arg =~ /^--exitcodenochecks?/) { _set_cfg_out('exitcode_checks', 0); } # -"- if ($arg =~ /^--exitcodenomedium/) { _set_cfg_out('exitcode_medium', 0); } # -"- if ($arg =~ /^--exitcodenoweak/) { _set_cfg_out('exitcode_weak', 0); } # -"- if ($arg =~ /^--exitcodenolow/) { _set_cfg_out('exitcode_low', 0); } # -"- if ($arg =~ /^--exitcodenopfs/) { _set_cfg_out('exitcode_pfs', 0); } # -"- if ($arg =~ /^--exitcodenoprot/) { _set_cfg_out('exitcode_prot', 0); } # -"- if ($arg =~ /^--exitcodenosizes/) { _set_cfg_out('exitcode_sizes', 0); } # -"- if ($arg =~ /^--exitcodenociphers?/){ # shortcut options for following _set_cfg_out('exitcode_cipher', 0); _set_cfg_out('exitcode_medium', 0); _set_cfg_out('exitcode_weak', 0); _set_cfg_out('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_ITEM'; } # openssl if ($arg eq '--cipher') { $typ = 'CIPHER_ITEM'; } if ($arg eq '--ciphermode') { $typ = 'CIPHER_MODE'; } if ($arg eq '--cipherrange') { $typ = 'CIPHER_RANGE'; } if ($arg =~ /^--ciphercurves?/) { $typ = 'CIPHER_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 '--nodns') { _set_cfg_use('dns', 0);} if ($arg eq '--dns') { _set_cfg_use('dns', 1);} if ($arg eq '--http') { _set_cfg_use('http', 1);} if ($arg eq '--httpanon') { _set_cfg_use('http', 2);} # NOT YET USED if ($arg eq '--nohttp') { _set_cfg_use('http', 0);} if ($arg eq '--https') { _set_cfg_use('https', 1);} if ($arg eq '--httspanon') { _set_cfg_use('https', 2);} # NOT YET USED if ($arg eq '--nohttps') { _set_cfg_use('https', 0); } if ($arg =~ /^\--https?body$/i) { _set_cfg_out('http_body', 1); } # SEE Note:--https_body if ($arg eq '--nosniname') { _set_cfg_use('sni', 0); } # 0: don't use SNI, different than empty string if ($arg eq '--norc') { } # simply ignore if ($arg eq '--sslerror') { _set_cfg_use('ssl_error', 1); } if ($arg eq '--nosslerror') { _set_cfg_use('ssl_error', 0); } if ($arg eq '--ssllazy') { _set_cfg_use('ssl_lazy', 1); } if ($arg eq '--nossllazy') { _set_cfg_use('ssl_lazy', 0); } if ($arg =~ /^--nullsslv?2$/i) { _set_cfg_use('nullssl2', 1); } if ($arg =~ /^--sslv?2null$/i) { _set_cfg_use('nullssl2', 1); } # SEE Note:--enabled --disabled if ($arg eq '--noenabled') { _set_cfg_out('enabled', 0); } if ($arg eq '--enabled') { _set_cfg_out('enabled', 1); _set_cfg_out('disabled', 0); } if ($arg eq '--disabled') { _set_cfg_out('disabled', 1); _set_cfg_out('enabled', 0); } if ($arg eq '--nodisabled') { _set_cfg_out('disabled', 0); } if ($arg =~ /^--headers?$/) { _set_cfg_out('header', 1); } # some people type --headers if ($arg =~ /^--noheaders?$/) { _set_cfg_out('header', 0); } if ($arg =~ /^--hints?$/) { _set_cfg_out('hint_info', 1); _set_cfg_out('hint_check', 1); } if ($arg =~ /^--nohints?$/) { _set_cfg_out('hint_info', 0); _set_cfg_out('hint_check', 0); } if ($arg =~ /^--hints?infos?/) { _set_cfg_out('hint_info', 1); } if ($arg =~ /^--nohints?infos?/) { _set_cfg_out('hint_info', 0); } if ($arg =~ /^--hints?checks?/) { _set_cfg_out('hint_check', 1); } if ($arg =~ /^--nohints?checks?/) { _set_cfg_out('hint_check', 0); } if ($arg =~ /^--hints?cipher/) { _set_cfg_out('hint_cipher', 1); } if ($arg =~ /^--nohints?cipher/) { _set_cfg_out('hint_cipher', 0); } if ($arg =~ /^--showhosts?/i) { _set_cfg_out('hostname', 1); } if ($arg eq '--score') { _set_cfg_out('score', 1); } if ($arg eq '--noscore') { _set_cfg_out('score', 0); } if ($arg eq '--tab') { $text{'separator'}= "\t"; } # TAB character 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 = 'LD_ENV'; } if ($arg eq '--envlibvar3') { $typ = 'LD_ENV3'; } if ($arg =~ /^--(?:no|ignore)out(?:put)?$/) { $typ = 'NO_OUT'; } if ($arg =~ /^--cfg(cmd|check|data|hint|info|text)$/) { $typ = 'CFG-' . $1; } if ($arg =~ /^--cfgcipher$/) { $typ = 'CFG_CIPHER'; } if ($arg =~ /^--cfginit$/) { $typ = 'CFG_INIT'; } if ($arg eq '--call') { $typ = 'CALL'; } if ($arg eq '--legacy') { $typ = 'LEGACY'; } if ($arg eq '--label') { $typ = 'LABEL'; } if ($arg eq '--format') { $typ = 'FORMAT'; } if ($arg eq '--formatident') { $typ = 'TTY_IDENT'; } if ($arg eq '--formatwidth') { $typ = 'TTY_WIDTH'; } if ($arg eq '--formatarrow') { $typ = 'TTY_ARROW'; } if ($arg =~ /^--(?:format)?tty$/) { _set_cfg_tty('width', 0) if not defined $cfg{'tty'}->{'width'}; } # SEE Note:tty 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 = 'CERT_TEXT'; } 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_DELAY'; } 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{'use'}->{'mx'} = 0;} if ($arg =~ /^--(?:dns)?mx/) { $cfg{'use'}->{'mx'} = 1;} if ($arg eq '--sslretry') { $typ = 'SSLHELLO_RETRY'; } if ($arg eq '--ssltimeout') { $typ = 'SSLHELLO_TOUT'; } if ($arg eq '--sslmaxciphers') { $typ = 'SSLHELLO_MAXC'; } 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 = 'CA_DEPTH'; } # some tools use CAdepth if ($arg =~ /^--cafile$/i) { $typ = 'CA_FILE'; } if ($arg =~ /^--capath$/i) { $typ = 'CA_PATH'; } 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"); $arg =~ s/^,/+/; # allow +command and ,command # 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 # check 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: # check 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 =~ /^\+ciphers?$p?preferr?ed/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 =~ /^\+master$p?secret$/) { $arg = '+master_secret'; } if ($arg =~ /^\+extended$p?master$p?secret$/) { $arg = '+master_secret'; } # 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: if ($arg =~ /^\+hpkp$/i) { $arg = '+https_pins'; } # alias: if ($arg =~ /^\+pkp$p?pins$/i) { $arg = '+https_pins'; } # alias: +pkp_pins before 19.12.19 if ($arg =~ /^\+https?${p}body$/i) { _set_cfg_out('http_body', 1); } # SEE Note:--https_body #!#+---------+----------------------+---------------------------+------------- # +---------+----------------------+-----------------------+---------------- # 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 =~ /^\+(.*)/) { # 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; } $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) { _y_ARG("cmdsusr= $val"); 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) { _y_ARG("command= $val"); 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"); _hint($cfg{'hints'}->{'cipher'}) if ($val =~ m/^cipher(?:all|raw)/); } 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; } _y_ARG("host? $arg"); if ($typ eq 'HOST') { # host argument is the only one parsed here if ($arg !~ m/^[a-zA-Z0-9.-]+/){ # TODO: lazy check for valid hostname, needs to be improved _warn("042: invalid host argument '$arg'; ignored"); next; # can safely reloop here, as we are at end of while } # use previously defined port || default port my $default_port = ($cfg{'port'} || $target_defaults[0]->[3]); my ($prot, $host, $port, $auth, $path) = _get_target($default_port, $arg); if (($host =~ m/^\s*$/) or ($port =~ m/^\s*$/)){ _warn("043: invalid port 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, auth=$auth, path=$path"); _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 osaft::set_target_orig( $idx, $arg); osaft::set_target_nr( $idx, $idx); osaft::set_target_prot( $idx, $prot); osaft::set_target_host( $idx, $host); osaft::set_target_port( $idx, $port); osaft::set_target_auth( $idx, $auth); osaft::set_target_proxy($idx, $proxy); osaft::set_target_path( $idx, $path); osaft::set_target_start($idx, 0); osaft::set_target_open( $idx, 0); osaft::set_target_stop( $idx, 0); osaft::set_target_error($idx, 0); # endif } } else { _y_ARG("ignore= $typ $arg"); # should never happen } } # while options and arguments # exit if ($#{$cfg{'do'}} < 0); # no exit here, as we want some --v output #| prepare %cfg according options #| ------------------------------------- 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'}; $legacy = $cfg{'legacy'}; if (_is_cfg_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{'use'}->{'https'} = 0; $cfg{'use'}->{'http'} = 0; $cfg{'use'}->{'dns'} = 0; _hint($cfg{'hints'}->{'cipher'}); } if (_is_cfg_do('list')) { # our own command to list ciphers: uses header and TAB as separator _set_cfg_out('header', 1) if ((grep{/--no.?header/} @argv) <= 0); $text{'separator'} = "\t" if ((grep{/--(?:tab|sep(?:arator)?)/} @argv) <= 0); # tab if not set } if (_is_cfg_do('pfs')) { push(@{$cfg{'do'}}, 'cipher_pfsall') if (not _is_cfg_do('cipher_pfsall')); } if (_is_cfg_do('version') or (_is_cfg_use('mx'))) { $cfg{'need_netdns'} = 1; } if (_is_cfg_do('version') or (_is_cfg_do('sts_expired')) > 0) { $cfg{'need_timelocal'} = 1; } $cfg{'connect_delay'} =~ s/[^0-9]//g; # simple check for valid values if (_is_cfg_out('http_body')) { # SEE Note:ignore-out, SEE Note:--https_body @{$cfg{'ignore-out'}} = grep{not /https_body/} @{$cfg{'ignore-out'}}; @{$cfg{'out'}->{'ignore'}} = grep{not /https_body/} @{$cfg{'out'}->{'ignore'}}; } # SEE Note:Testing, sort # _dbx "unsorted: @{$cfg{'do'}}"; @{$cfg{'do'}} = sort(@{$cfg{'do'}}) if (0 < _is_argv('(?:--no.?rc)')); # _dbx " sorted: @{$cfg{'do'}}"; # $cfg{'do'}} should not contain duplicate commands; SEE Note:Duplicate Commands if (2 == @{$cfg{'targets'}}) { # Exactly one host defined, check if --port was also given after --host . # Assuming that "--port 123 host" was meant instead "host --port 123". # Latest given port can be found in $cfg{'port'}. If it differs from the # port stored in the list @{$cfg{'targets'}}, redefine port for the host. # NOTE: the documentation always recommends to use --port first. my $host = osaft::get_target_host(1); my $port = osaft::get_target_port(1); if (defined $cfg{'port'}) { _warn("045: '--port' used with single host argument; using '$host:$cfg{'port'}'"); osaft::set_target_port(1, $cfg{'port'}); } } # 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 independent 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 (0 == $cfg{'exec'}) { # As all shared libraries used by Perl modules are already loaded when this # program executes, PATH and LD_LIBRARY_PATH need to be set before the tool # is called. Hence call myself 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, therefore the directoy given # with --lib will be added to the PATH environment variable too, it 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 (_is_cfg_out('traceARG') or _is_cfg_out('traceCMD')); exec $0, '+exec', @ARGV; } } #| 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/); } #| set openssl-specific path for executable and CAs #| ------------------------------------- _init_openssl(); # if (0 < _need_openssl()); if (0 < $info) { # +info does not do anything with ciphers # main purpose is to avoid missing "*PN" warnings in following _checks_*() $cmd{'extciphers'} = 0; $cfg{'use'}->{'alpn'} = 0; $cfg{'use'}->{'npn'} = 0; } #| set proper cipher command depending on --ciphermode option (default: intern) #| ------------------------------------- # SEE Note:+cipher if ((0 < _need_cipher()) or (0 < _need_default())) { foreach my $mode (@{$cfg{'ciphermodes'}}) { if ($mode eq $cfg{'ciphermode'}) { # add: cipher_intern, cipher_openssl, cipher_ssleay, cipher_dump my $do = 'cipher_' . $mode; push(@{$cfg{'do'}}, $do) if (not _is_cfg_do($do)); # only if not yet set # TODO: funktioniert nicht sauber #$cfg{'legacy'} = 'owasp' if ($do eq 'cipher_intern'); # new default #$legacy = $cfg{'legacy'}; } } # $cfg{'need_netinfo'} = 0 if ("intern" eq $cfg{'ciphermode'}); # TODO: need_netinfo disabled until all functionaluty provided by NET::SSLhello } _yeast_TIME("inc{"); #| import common and private modules #| ------------------------------------- _load_modules() if (0 == $::osaft_standalone); _yeast_TIME("inc}"); _yeast_TIME("mod{"); _y_CMD("check $cfg{'me'} internals ..."); my $do_checks = _is_cfg_do('cipher_openssl') + _is_cfg_do('cipher_ssleay'); #| check for required module versions #| ------------------------------------- _check_modules() if (0 < $do_checks); # --ciphermode=intern does not need these checks # check done after loading our own modules because they may require # other common Perl modules too; we may have detailed warnings before #| check for required functionality #| ------------------------------------- _check_functions() if (0 < $do_checks + _is_cfg_do('cipher') + _need_checkprot()); # more detailed checks on version numbers with proper warning messages #| check for proper openssl support #| ------------------------------------- _check_openssl() if (0 < $do_checks); #_dbx "do: @{$cfg{'do'}}"; #_dbx "need-default: @{$cfg{'need-default'}}"; #_dbx "_check_ssl_methods(): " . _need_cipher() . " : " . _need_default() . " : ver? "._is_cfg_do('version'); #| check for supported SSL versions #| ------------------------------------- _check_ssl_methods() if (0 < _need_cipher() + _need_default() + _is_cfg_do('version')); # initialise $cfg{'version'} and all $cfg{ssl} # function is oversized for --ciphermode=intern but does the work _yeast_TIME("mod}"); _yeast_TIME("ini{"); #| set additional defaults if missing #| ------------------------------------- _set_cfg_out('header', 1) if(0 => $verbose);# verbose uses headers _set_cfg_out('header', 1) if(0 => grep{/\+(check|info|quick|cipher)$/} @argv); # see --header _set_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 (not _is_cfg_use('http')) { # was explicitly 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 (1 == $quick) { _set_cfg_out('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); ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) # avoid: Name "Net::SSLinfo::trace" used only once: possible typo at ... if (1 > $cfg{'traceME'}) { $Net::SSLinfo::trace = $cfg{'trace'} if (0 < $cfg{'trace'}); } $Net::SSLinfo::verbose = $cfg{'verbose'}; $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::use_SNI = $cfg{'use'}->{'sni'}; $Net::SSLinfo::use_alpn = $cfg{'use'}->{'alpn'}; $Net::SSLinfo::use_npn = $cfg{'use'}->{'npn'}; $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{'use'}->{'no_comp'}; $Net::SSLinfo::no_cert = ((_is_cfg_use('cert')) ? 0 : 1); $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 = ""; # following are just defaults, will be redefined for each target below $Net::SSLinfo::sni_name = $cfg{'sni_name'}; # NOTE: may be undef $Net::SSLinfo::use_http = $cfg{'use'}->{'http'}; $Net::SSLinfo::use_https = $cfg{'use'}->{'https'}; $Net::SSLinfo::target_url = "/"; } 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); ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) # avoid: Name "Net::SSLinfo::trace" used only once: possible typo at ... if (1 > $cfg{'traceME'}) { $Net::SSLhello::trace = $cfg{'trace'}; } $Net::SSLhello::traceTIME = $cfg{'out'}->{'traceTIME'}; $Net::SSLhello::experimental = $cfg{'use'}->{'experimental'}; $Net::SSLhello::usemx = $cfg{'use'}->{'mx'}; $Net::SSLhello::usesni = $cfg{'use'}->{'sni'}; $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'} = 1 if (0 < $cfg{'traceME'}); $cfg{'trace'} = 0 if (0 > $cfg{'traceME'}); 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}; } } _initchecks_val(); # initialise default values in %checks again depending on given options _yeast_TIME("ini}"); #| first all commands which do not make a connection #| ------------------------------------- _y_CMD("no connection commands ..."); _trace(" --test= $test"); # all --test-cipher* are special (need other data like %cfg or alike) $test =~ s/^(?:[+]|--)(test.*)/--$1/; # SEE Note:--test-* if ($test =~ m/testciphers?list/) { _yeast_test($test); exit 0; } if ($test =~ m/testciphers?regex/) { test_cipher_regex(); exit 0; } if ($test =~ m/^--testcipher/) { OSaft::Ciphers::show($test); exit 0; } if ($test !~ m/^\s*$/) { _yeast_test($test); exit 0; } # interanl information commands if (_is_cfg_do('list')) { printciphers(); exit 0; } if (_is_cfg_do('ciphers')) { printciphers(); exit 0; } if (_is_cfg_do('version')) { printversion(); exit 0; } if (_is_cfg_do('libversion')) { printopenssl(); exit 0; } if (_is_cfg_do('quit')) { printquit(); exit 0; } 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'}}); } _y_CMD("dbx init ..."); _yeast_init(); # call in printquit() also! if (0 > $#{$cfg{'do'}}) { _yeast_exit(); printusage_exit("no command given"); } _y_ARG("commands=@{$cfg{'do'}}"); usr_pre_cipher(); #| get list of ciphers available for tests #| ------------------------------------- if (_is_cfg_do('cipher_openssl') or _is_cfg_do('cipher_ssleay')) { if ((_need_cipher() > 0) or (_need_default() > 0)) { _yeast_TIME("get{"); _y_CMD("get cipher list ..."); @{$cfg{'ciphers'}} = _get_cipherlist_openssl(); _yeast_TIME("get}"); } # _need_cipher or _need_default } #| SEE Note:Duplicate Commands #| ------------------------------------- # my %unique = map{$_, 42} @{$cfg{'do'}}; # perlish way cannot be used, # @{$cfg{'do'}} = keys %unique; # because sequence is user-defined @{$cfg{'do'}} = do { my %seen; grep { !$seen{$_}++ } @{$cfg{'do'}} }; _yeast_EXIT("exit=MAIN - start"); _yeast_ciphers_list(); usr_pre_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_cfg_do('cipher_openssl') or _is_cfg_do('cipher_ssleay')) { if ($#{$cfg{'done'}->{'arg_cmds'}} > 0) { printusage_exit("additional commands in conjunction with '+cipher' are not supported; '+" . join(" +", @{$cfg{'done'}->{'arg_cmds'}}) ."'"); } } if ((0 < $info) 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 ((0 < $check) 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'}})) { _warn("048: additional commands in conjunction with '+check' are not supported; +'$key' ignored"); } } } #| 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_cfg_do($cmd)); } if ($fail > 0) { _warn("066: $fail data and check outputs are disbaled due to use of '--no-out':"); if (0 < $cfg{'verbose'}) { _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=*'"); # 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'}})) { _hint("+$cmd : please see '$cfg{'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! my $idx = 0; foreach my $target (@{$cfg{'targets'}}) { # loop targets (hosts) next if (0 == @{$target}[0]); # first entry contains default settings $idx++; $host = osaft::get_target_host($idx); $port = osaft::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 (_is_cfg_use('sni')) { 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_https = $cfg{'use'}->{'https'}; # reset $Net::SSLinfo::use_http = $cfg{'use'}->{'http'}; # reset $Net::SSLinfo::target_url = osaft::get_target_path($idx); $Net::SSLinfo::target_url =~ s:^\s*$:/:; # set to / if empty _resetchecks(); print_header(_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 = ""; # reusing variable if ("" ne $cfg{'proxyhost'}) { # 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 (_is_cfg_use('dns')) { # 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; } if ($cfg{'rhost'} =~ m/gethostbyaddr/) { _warn("202: Can't do DNS reverse lookup: for '$host': $fail; ignored"); _hint("use '--no-dns' to disable this check"); } _yeast_TIME("test DNS}"); } } # print DNS stuff if (_is_cfg_do('host') or (($info + $check + $cmdsni) > 0)) { _y_CMD("+info || +check || +sni*"); if ($legacy =~ /(compact|full|owasp|simple)/) { print_ruler(); print_line($legacy, $host, $port, 'host_name', $text{'host_name'}, $host); print_line($legacy, $host, $port, 'host_IP', $text{'host_IP'}, $cfg{'IP'}); if (_is_cfg_use('dns')) { print_line($legacy, $host, $port, 'host_rhost', $text{'host_rhost'}, $cfg{'rhost'}); print_line($legacy, $host, $port, 'host_DNS', $text{'host_DNS'}, $cfg{'DNS'}); } print_ruler(); } } _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_cfg_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_cfg_do('cipher_intern') or _is_cfg_do('cipher_dump')) { # implies _need_cipher() _y_CMD("+cipher"); _yeast_TIME("ciphermode=intern{"); Net::SSLhello::printParameters() if ($cfg{'trace'} > 1); _warn("209: No SSL versions for '+cipher' available") if ($#{$cfg{'version'}} < 0); # above warning is most likely a programming error herein $cipher_results = {}; # new list for every host (array of arrays) $cipher_results = ciphers_scan_raw($host, $port); # print ciphers also $checks{'cnt_totals'}->{val} = scalar %$cipher_results; # FIXME: this is the number of enabled ciphers! foreach my $ssl (@{$cfg{'version'}}) { # all requested protocol versions $checks{'cnt_totals'}->{val} += osaft::get_ciphers_range($ssl, $cfg{'cipherrange'}); } # SEE Note:+cipherall my $total = $checks{'cnt_totals'}->{val}; checkciphers($host, $port, $cipher_results);# necessary to compute 'out_summary' printciphersummary($legacy, $host, $port, $total) if (_is_cfg_do('cipher')); _yeast_TIME("ciphermode=intern}"); next if (_is_cfg_do('cipher') and (0 == $quick)); } # ciphermode=intern next if _yeast_NEXT("exit=HOST2 - host ciphermode=intern"); if (_is_cfg_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 preferred cipher") > 0); my $cipher = $prot{$ssl}->{'cipher_strong'}; $prot{$ssl}->{'cipher_pfs'} = $cipher if ("" ne _is_ssl_pfs($ssl, $cipher)); ##if (_is_cfg_do('cipher_selected') and ($#{$cfg{'do'}} == 0)) { ## # +cipher_selected command given, but no other commands; ready ## print_cipherpreferred($legacy, $ssl, $host, $port); # need to check if $ssl available first ## next HOSTS; # TODO: foreach-loop for targets misses label ##} } checkpreferred($host, $port); _yeast_TIME("need_default}"); } next if _yeast_NEXT("exit=HOST3 - host ciphers start"); if (_is_cfg_do('cipher_default') and (0 < $#{$cfg{'do'}})) { # don't print if not a single command, because +check or +cipher do it # in printptotocols() anyway printcipherpreferred($legacy, $host, $port); goto CLOSE_SSL; # next HOSTS } if (_is_cfg_do('cipher_openssl') or _is_cfg_do('cipher_ssleay')) { # implies _need_cipher() _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 $cipher_results = ciphers_scan($host, $port); $checks{'cnt_totals'}->{val} = scalar %$cipher_results; 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 ((0 < $check or _is_cfg_do('cipher')) and (_is_cfg_do('cipher_openssl') or _is_cfg_do('cipher_ssleay'))) { _y_CMD("+cipher"); _yeast_TIME("ciphermode=ssleay{"); _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 (_is_cfg_out('header') or (scalar @{$cfg{'version'}}) > 1) { # need a header when more than one protocol is checked $header = 1; } print_title($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_cipherpreferred($legacy, $ssl, $host, $port); # TODO: there is only one $data{'cipher_selected'} #foreach my $ssl (@{$cfg{'version'}}) { # print_cipherpreferred($legacy, $ssl, $host, $port); #} } if ($_printtitle > 0) { # if we checked for ciphers # SEE Note:+cipherall printciphersummary($legacy, $host, $port, scalar %$cipher_results); } _yeast_TIME("ciphermode=ssleay}"); } # cipher next if _yeast_NEXT("exit=HOST5 - host ciphers end"); goto CLOSE_SSL if (_is_cfg_do('cipher') 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_cfg_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 (0 >= $cfg{'sslerror'}->{'ignore_no_conn'}) { # use Net::SSLinfo::do_ssl_open() instead of IO::Socket::INET->new() # to check the connection (hostname and port) # this is the first call to Net::SSLinfo::do_ssl_open() # 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 (0 < $#errtxt) { _v_print(join("\n".$STR{ERROR}, @errtxt)); _warn("205: Can't make a connection to '$host:$port'; target ignored"); _hint("use '--v' to show more information"); _hint("use '--socket-reuse' it may help in some cases"); _hint("use '--ignore-no-conn' 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 (0 < (grep{/\*\*ERROR/} @errtxt)) { _warn("207: Errors occoured when using '$cmd{'openssl'}', some results may be wrong; errors ignored"); _hint("use '--v' to 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_cfg_do('dump')) { _y_CMD("+dump"); if (1 < $cfg{'trace'}) { # 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 # Net::SSLinfo::do_ssl_open() will be call here if --ignore_no_conn was given _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."); } if (_is_cfg_do('sstp')) { # only check if needed checksstp( $host, $port); _yeast_TIME(" checksstp."); } _yeast_TIME("prepare}"); next if _yeast_NEXT("exit=HOST6 - host prepare"); usr_pre_print(); if (0 < $check) { _y_CMD("+check"); _warn("208: No openssl, some checks are missing") if (($^O =~ m/MSWin32/) and ($cmd{'extopenssl'} == 0)); } # for debugging only if (_is_cfg_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 for both _yeast_TIME("info{"); printdata( $legacy, $host, $port) if (1 > $check); # not for +check _yeast_TIME("info}"); _yeast_TIME("checks{"); printchecks($legacy, $host, $port) if (1 > $info); # not for +info _yeast_TIME("checks}"); if (_is_cfg_out('score')) { # 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); ## no critic qw(TestingAndDebugging::ProhibitNoWarnings) 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 $cfg{'use'}->{'exitcode'} += $cfg{'out'}->{'exitcode'}; # --exitcode-v exit 0 if (not _is_cfg_use('exitcode')); my $status = check_exitcode(); if (0 < $status) { # print EXIT message unless switched off with --exitcode-quiet print "# EXIT $status" if (not _isc_fg_out('exitcode_quiet')); } exit $status; # no __END__ here, because it causes problems in generated gen_standalone.sh # no __DATA__ here, because ... # public user documentation, please see OSaft/Doc/*.txt and OSaft/Doc/Data.pm # following annotations are avalable by using: perldoc o-saft.pl =pod =encoding utf8 =head1 Documentation This is the documentation for development! For user documentation please use: o-sat.pl --help =head3 Documentation General Documentation distinguishes between the L and L and L. =head3 Public User Documentation All public user documentation is available in plain text format. It can be accessed programmatically with the --help option and various variants of it. All plain texts are designed for human readability and simple editing, see: ./OSaft/Doc/*.txt For details on documentation texts (format, syntax, etc.) from files, see: ./OSaft/Doc/Data.pm ./o-saft-man.pm =head3 Internal Code Documentation All comments/documentation/explanation of code details is written close to the corresponding code lines. Note that these 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). Some special syntax for comment lines are used, see "Comments" section in OSaft/Doc/coding.txt . Additional documentation is avaialble in POD format at end of the files. Examples: perldoc o-saft.pl perldoc o-saft-man.pm These comments are called "Annotations" and referred to using a special syntax, see following chapter L . These Annotations are used for descriptions needed at multiple places in the code or even multiple files. =head3 Internal Makefile Documentation Documentation of the make system is mainly done in POD format in: perldoc t/Makefile.pod It contains the general documentation as well as the Annotations used from within the other Makefile*. =head3 Terminology General notes about terms and words used in all documentations, no matter if user or development documentation. =over =item Perl Is used when the programming language in general is meant. =item perl Is used when the program perl (or perl.exe) is meant. =item Perl::Critic Is used when the functionality of the Perl::Critic module, or any program using it (such as perlcritic), is meant. =item perlcritic Is used when the program perlcritic is meant. =item Makefile Is used when a particular file is meant (usually the file itself in which the term is used). The term Makefile* is used when any of our Makefile.* is means. =item makefile(s) Is used when files to be used as input for make in general are meant. =item variable, macro In documentations for makefiles, for example GNU Make, the terms macro and variable are used interchangeable. In our documentation the term variable is preferred. =item target Is used in O-Saft's documentation for the host target to be tested. And it is also used in makefiles where it means the recipe to be executed. =item arguments Is used for arguments to the tools, like o-saft.pl, and is meant as option or command for this tool, please see also COMMANDS and OPTIONS in o-saft.pl --help =back =head1 Testing (Development) See L above and L below and o-saft.pl --help=testing =head1 Annotations, Internal Notes The annotations from here on 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 --2022-- this is an internal documentation only. It is available for the developer also with: perldoc o-saft.pl It is written in POD format, because some tools analysing the code want to "see" comments and documentation. We feed them. For more information about that, please see "voodoo" in o-saft-man.pm . =head3 Annotation Syntax Each single annotation is headed using POD's =head2 syntax. All following text is supposed to be read by humans! It then will be referenced in the code with the "SEE " syntax, where "" is the text right of the =head2 keyword. I.g. no other markup is used, except POD'S =head3 and L <..> markup. All following texts from here on are Annotations. =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 . The functionality was 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 L 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 The documentation was initially written in Perl's doc format: perldoc POD. The advantage of POD is the well formatted output on various platforms, but results in more difficult efforts for extracting information from it. 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 - programmatically extracting data requires additional substitutes - POD is slow See following table how changing POD to plain ASCII (VERSION 14.11.14 vs. 14.12.14) results (for equal number of source code lines or kBytes): 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, nor is perlcritic. Hence perlcritic's pragmas are used to disable some checks as needed. This is done in general in perlcritic's config file t/.perlcriticrc and selectively in the code using the pragma: ## no critic ... All disabled checks are documented, in t/.perlcriticrc or as pragma. Following pragmas are used in various files: * InputOutput::ProhibitBacktickOperators) This check seems to be a 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. * Variables::ProhibitPackageVars perlcritic complains to not declare (global) package variables. The purpose of some modules is to do that. =head2 Perl:BEGIN perlcritic perlcritic cannot handle BEGIN{} sections semantically correct. If this section is defined before the `use strict;' statement, it complains with the error 'TestingAndDebugging::ProhibitNoStrict'. Therefore any BEGIN{} section is defined after `use strict;', ugly but avoids clumsy `## no critic' pragmas. =head2 Perl:import include Perl recommends to import modules using 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 if 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 that some functionality is disabled selectively, if loading of the 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:EXPORT Perl modules may export their sombols using `EXPORT' or `EXPORT_OK'. TODO =head2 Perl:Undefined subroutine Perl requires that subroutines are defined before first use, obviously. As we have some subroutines which should be used in the main script, and also in our modules, another separate module would be necessary to achieve this. This module then needs to be imported ('use' or 'require') in all scripts. In practice, only a small number of these subroutines are required in our modules. Hence we avoid building a special purpose module. Unfortunately this may result in Perl errors like: Undefined subroutine &main::_warn called at ... when the module is called as standalone script. Following approach is used: - subroutines are defined where (mainly) needed - modules use Perl's named subroutines like following, example: _warn(): *_warn = sub { print($STR{WARN}, @_); } if not defined &_warn; This ensures, that the definition is used only, if it doesn't exists. This also avoids use of Perl's eval(). The disadvantage is, that the subroutine does not have exacly the same functionality as the original definition. TODO: in each named subroutin: return if (grep{/(?:--no.?warn)/} @ARGV); Also SEE L. =head2 Perl:@INC Perl includes modules with the `use' or `require' statement. Therefore the @INC array is used which contains a predefined list of directories where to search for the files to be included. Following disadvantages are known: - the list of directories depends on the system (OS and distribution) - this list must be known before any Perl command is executed - it's tricky to use private directories - using "-I . lib/" in hashbang line will pre- and append to @INC Therefore @INC needs to be adapted properly in Perl's BEGIN scope (see next annotation also). The added directories are: - $_path # user-friendly: add path of the called script also - lib $_path/lib # we support some local lib directories - $ENV{PWD} # calling directory, some kind of fallback - /bin" # special installation on portable media Note that $ENV{PWD} may be undefined, it will obviously not used then. Note that / works here even for Windoze. Some logic is used to prepend these directories to @INC, avoiding useless paths. Keep in mind that any script may be called in following context: - /path/to/OSaft/Doc/Data.pm # full path - OSaft/Doc/Data.pm # local path - ./Data.pm # local path - ../OSaft/Doc/Data.pm # relative path - Data.pm # by $PATH Two of the above exmples need special settings: - Data.pm # the path matches the script name - /path/to/OSaft/Doc/Data.pm # the path matches ^/ =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, the limitations force us to use some dirty code hacks and split the flow of processing into different parts of the source. Also SEE L. Also SEE L. Also SEE L. =head2 Perl:constant Perl has no "real" concept and implementation of constants. Using Perl's pragma constant declares in fact subroutines. Beside others, this has the disadvantage, that such constants cannot be use in strings, they are not interpolated there. Our texts are rather variables than real constants, because it is possible to overwrite them (beside some exceptions). Therefore it's more consequent to use variables anywhere. Perl's constants have the advantage that they are replaced at compile time and therefore the code may result in better performance. That's not really relevant for the tool's intended purpose. Unfortunately using Perl's Readonly instead of constant is not possible, because constants are used in the BEGIN section also. Constants can be used there but not Readonly variables. A hash is used for our texts. This has the advantage, that many values can be defined without the need to care about every value everywhere. This has the disadvantage, that runtime errors like "Undefined variable ..." may occour. Instead of using constant , the corrsponding sub are defined verbatim. Also SEE L. =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 globally 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. writing texts to the user using STDOUT and STDERR channels, note that it never reads, except from command-line, hence no STDIN; 2. writing and reading 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 like: binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); As most --nearly all-- data on STDOUT and STDERR is supposed to be read by humans, only these channels are handled explicitly. The idea is, that all texts consist of printable characters only, probably in various languages. Hence UTF-8 is used as default character 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. However, modules need to use the proper binmode() call itself, if they are called from command-line. Unfortunately Perl::Critic complains that ':encoding(UTF-8)' should be used, InputOutput::RequireEncodingWithUTF8Layer must be disabled 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. Unfortunately 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 keeps 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 the option --no-warning _warn() can suppress messages. However, some warnings should never be suppressed, hence warn() is used in rare cases. Each warning should have a unique number, SEE L. See also CONCEPTS (if it exists in our help texts). =head2 Note: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 A proper test for the message should be done in t/Makefile.warnings, where we have: make warnings-info =head2 Note:Data Structures To make (programmer's) life simple, complex data structures are avoided. Global variables are used (mostly defined in osaft.pm). This should be ok, as there are no plans to run this tool in threaded mode. Please see OSaft/Doc/coding.txt also. Here's an overview of the used global variables: Data structures with (mainly) static data: %cmd - configuration for external commands (like openssl) %text - configuration for message texts %ciphers - definition of our cipher suites %shorttexts - short texts (labels) for %data and %checks %prot_txt - labels for %prot Data structures with runtime data: %cfg - configuration for commands and options herein %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 %info - like %data, but for data which could not be retrieved from Net::SSLinfo like HTTP vs. HTTPS checks %prot - collected data per protocol (from Net::SSLinfo) @cipher_results - collected results as: [SSL, cipher, "yes|no"] NOTE: all keys in %data and %checks must be unique 'cause of %shorttexts. NOTE: all keys in %checks must be in lower case letters, because generic conversion of +commands to keys. The keys related to protocol, i.e. SSLv3, TLSv11, etc. are mixed case. Note according perlish programming style: references to $arr->{'val') are most often simplified as $arr->{val) , same applies to 'txt' and 'typ'. =head3 Initialisation Most data structures are statically initalised. Some, mainly %checks, will be initilised programmatically. The values in %checks must be initilised also before the check result will be assigned. This default initialisation could be: yes - (empty string) no - (any string) undef - fixed string Each method has its pros and cons. This has been changed, see below. =head3 Initialisation since VERSION 19.12.26 All values in %check are set to "<", which means neither 'yes' nor 'no'. The advantage is that missing checks are reported as: no (<>) and hence are easily identified. This also allows to use different default strings, for example disabled or missing checks, for example: no (<>) The disadvantage is that all checks must assign the value 'yes' or 'no'. The default initialisation is done after processing all arguments from the command-line and the RC-FILE. =head3 Initialisation before VERSION 19.12.26 All values in %check were set to "" which means 'yes'. The advantage was a very simple default assignment and only failed checks are assigned. The disadvantage was that missing checks, due to programming errors, were re- ported as 'yes'. =head3 Shortened variable names Some varaible names are abrevated, instead of using full blown "speaking" names. The main reason is to avoid overlong coding lines. Some examples: cn - common_name ext_authorityid - ext_authorityid_key_id ext_certtype - ext_netscape_certtyp ext_cps_notice - ext_cps_user_notice ext_crl - ext_crl_distribution_point master_secret - extended_master_secret psk_hint - psk_identity_hint =head2 Note:Testing, sort When values are assigned to arrays, or values are pushed on arrays, Perl's final order in the array is random. This results in different orders of the values when the array values are printed, means that the order changes for each program call. Such random orders in output makes internal testing difficult. Hence, arrays are sorted (after defining them) when they are used. It is a small perfomance penulty in production because the 'sort' is only required while testing. Using a pragma like in C would be nice ... Unfortunately there are arrays preset with a special order, these must not be sorted. These are most likely the settings read from RC-FILE. For that, sorting is not done for data read from RC-FILE. The --no-rc option is used to check if the RC-FILE was read. The data to be sorted is for example: @cfg{do} @cfg{commands} @cfg{commands_*} =head2 Note:ARGV Command-line arguments are read after some other internal initialisations. Unfortunately sometimes options need to be checked before argument parsing is completed. Therfore following is needed: '(grep{/--trace)/} @ARGV)'. These check are implemented as simple functions and 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 naming 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 array also simplifies to pass the value to functions. Note that openssl uses a comma-separated list for ALPN and NPN, but uses a colon-separated list for ecliptic curves and also for ciphers. Confusing. 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:anon-out Some texts in output, mainly in warning or verbose messages, may disclose internal information. This may happen if the tool is executed in CGI mode. To avoid such information disclosure, a pattern is used to match texts to be anonymised in output. The use, hence definition, of this pattern is intended in CGI mode and can there be done in the RC-FILE. Therefore it is also necessary that the tool has an corresponding command-line option: --anon-output . The pattern is stored in %cfg. The correspondig string for anonymisation (replacement) is defined in %text. Note that the corresponding variable names (in %cfg and %text) should also be part of the pattern to avoid its disclosure with --v or --trace option. Known (9/2020) variables and texts with potential information disclosure: ENV{PWD} $me cfg{me} cfg{RC-ARGV} cfg{RC-FILE} cfg{regex}->{anon_output} cmd{openssl} =head2 Note:ignore-out The option --ignore-out (same as --no-cmd) adds commands to the list of commands @cfg{out}->{ignore}. The purpose is that values of the listed commands should not be printed in output. This is used mainly for commands where theoutput will be 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:--https_body +https_body prints the HTTP response body of the target. This may be very noisy and is disabled by default. The option --https_body can be used to force printing the HTTP data. The option removes 'https_body' from array cfg{out}->{ignore}. For convenience and lacy users, some variants of this options are allowed. =head2 Note:warning-no-duplicates Due to the program logic, for example nested looping (targets, protocols, ciphers), the same message may be printed multiple times (in each loop). As the duplicate warning doesn't give additional information to the user, the duplicates are ignored by default. The option --warnings_dups can be used to enable printing of all messages. As the tool traditionally supports complementary options for enabling and disabling a functionality, there is --no-warnings_no_dups respectively --warnings_dups too. Note that using both options --no-warnings --no-warnings_no_dups is not supported, means that no messages are printed. This behaviour may change in future. Technically the list (array) "cfg{'warnings_no_dups'}" contains message numbers not to be printed multiple times. This list is set empty when the option --warnings_dups is given. Some messages contain variable values, therefore the printed text of the message sligtly differs for several messages. Such messages should not be subject to the "don't print duplicates" mechanism, in practice: don't add their message number to "cfg{'warnings_no_dups'}". The array "cfg{'warnings_printed'}" is used internally and contains the numbers of messages already printed. SEE L also. To get a list of message numbers, use: make warnings-info =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. The existence of the returned directory will be checked, this produces a **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 certs/ sub-directory. This 'certs/' is hardcoded herein. =head2 Note:OpenSSL s_client Net::SSLinfo::s_client_check() is used to check for openssl capabilities. Each capability can be queried with Net::SSLinfo::s_client_opt_get(). Even Net::SSLinfo::s_client_*() will check capabilities, no proper error messages could be printed there. Hence checks are done herein first, which disables unavailable functionality and avoids warnings. Results (supported or not capability) are stored in $cfg{'openssl'} . Some options for s_client are implemented, see Net::SSLinfo.pm , or use: Net/SSLinfo.pm --test-sclient Example of (1.0.2d) 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) -jpake arg - JPAKE secret to use -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) Example of (1.l.0l) openssl s_client --help Usage: s_client [options] Valid options are: -help Display this summary -host val Use -connect instead -port +int Use -connect instead -connect val TCP/IP where to connect (default is :4433) -proxy val Connect to via specified proxy to the real server -unix val Connect over the specified Unix-domain socket -4 Use IPv4 only -6 Use IPv6 only -verify +int Turn on peer certificate verification -cert infile Certificate file to use, PEM format assumed -certform PEM|DER Certificate format (PEM or DER) PEM default -key val Private key file to use, if not in -cert file -keyform PEM|DER|ENGINE Key format (PEM, DER or engine) PEM default -pass val Private key file pass phrase source -CApath dir PEM format directory of CA's -CAfile infile PEM format file of CA's -no-CAfile Do not load the default certificates file -no-CApath Do not load certificates from the default certificates directory -dane_tlsa_domain val DANE TLSA base domain -dane_tlsa_rrdata val DANE TLSA rrdata presentation form -dane_ee_no_namechecks Disable name checks when matching DANE-EE(3) TLSA records -reconnect Drop and re-make the connection with the same Session-ID -showcerts Show all certificates sent by the server -debug Extra output -msg Show protocol messages -msgfile outfile File to send output of -msg or -trace, instead of stdout -nbio_test More ssl protocol testing -state Print the ssl states -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 -starttls val Use the appropriate STARTTLS command before starting TLS -xmpphost val Host to use with "-starttls xmpp[-server]" -rand val Load the file(s) into the random number generator -sess_out outfile File to write SSL session to -sess_in infile File to read SSL session from -use_srtp val Offer SRTP key management with a colon-separated profile list -keymatexport val Export keying material using label -keymatexportlen +int Export len bytes of keying material (default 20) -fallback_scsv Send the fallback SCSV -name val Hostname to use for "-starttls smtp" -CRL infile CRL file to use -crl_download Download CRL from distribution points -CRLform PEM|DER CRL format (PEM or DER) PEM is default -verify_return_error Close connection on verification error -verify_quiet Restrict verify output to errors -brief Restrict output to brief summary of connection parameters -prexit Print session information when the program exits -security_debug Enable security debug messages -security_debug_verbose Output more security debug output -cert_chain infile Certificate chain file (in PEM format) -chainCApath dir Use dir as certificate store path to build CA certificate chain -verifyCApath dir Use dir as certificate store path to verify CA certificate -build_chain Build certificate chain -chainCAfile infile CA file for certificate chain (PEM format) -verifyCAfile infile CA file for certificate verification (PEM format) -nocommands Do not use interactive command letters -servername val Set TLS extension servername in ClientHello -tlsextdebug Hex dump of all TLS extensions received -status Request certificate status from server -serverinfo val types Send empty ClientHello extensions (comma-separated numbers) -alpn val Enable ALPN extension, considering named protocols supported (comma-separated list) -async Support asynchronous operation -ssl_config val Use specified configuration file -split_send_frag int Size used to split data for encrypt pipelines -max_pipelines int Maximum number of encrypt/decrypt pipelines to be used -read_buf int Default read buffer size to be used for connections -no_ssl3 Just disable SSLv3 -no_tls1 Just disable TLSv1 -no_tls1_1 Just disable TLSv1.1 -no_tls1_2 Just disable TLSv1.2 -bugs Turn on SSL bug compatibility -no_comp Disable SSL/TLS compression (default) -comp Use SSL/TLS-level compression -no_ticket Disable use of TLS session tickets -serverpref Use server's cipher preferences -legacy_renegotiation Enable use of legacy renegotiation (dangerous) -no_renegotiation Disable all renegotiation. -legacy_server_connect Allow initial connection to servers that don't support RI -no_resumption_on_reneg Disallow session resumption on renegotiation -no_legacy_server_connect Disallow initial connection to servers that don't support RI -strict Enforce strict certificate checks as per TLS standard -sigalgs val Signature algorithms to support (colon-separated list) -client_sigalgs val Signature algorithms to support for client certificate authentication (colon-separated list) -curves val Elliptic curves to advertise (colon-separated list) -named_curve val Elliptic curve used for ECDHE (server-side only) -cipher val Specify cipher list to be used -min_protocol val Specify the minimum protocol version to be used -max_protocol val Specify the maximum protocol version to be used -debug_broken_protocol Perform all sorts of protocol violations for testing purposes -policy val adds policy to the acceptable policy set -purpose val certificate chain purpose -verify_name val verification policy name -verify_depth int chain depth limit -auth_level int chain authentication security level -attime intmax verification epoch time -verify_hostname val expected peer hostname -verify_email val expected peer email -verify_ip val expected peer IP address -ignore_critical permit unhandled critical extensions -issuer_checks (deprecated) -crl_check check leaf certificate revocation -crl_check_all check full chain revocation -policy_check perform rfc5280 policy checks -explicit_policy set policy variable require-explicit-policy -inhibit_any set policy variable inhibit-any-policy -inhibit_map set policy variable inhibit-policy-mapping -x509_strict disable certificate compatibility work-arounds -extended_crl enable extended CRL features -use_deltas use delta CRLs -policy_print print policy processing diagnostics -check_ss_sig check root CA self-signatures -trusted_first search trust store first (default) -suiteB_128_only Suite B 128-bit-only mode -suiteB_128 Suite B 128-bit mode allowing 192-bit algorithms -suiteB_192 Suite B 192-bit-only mode -partial_chain accept chains anchored by intermediate trust-store CAs -no_alt_chains (deprecated) -no_check_time ignore certificate validity time -allow_proxy_certs allow the use of proxy certificates -xkey infile key for Extended certificates -xcert infile cert for Extended certificates -xchain infile chain for Extended certificates -xchain_build build certificate chain for the extended certificates -xcertform PEM|DER format of Extended certificate (PEM or DER) PEM default -xkeyform PEM|DER format of Extended certificate's key (PEM or DER) PEM default -tls1 Just use TLSv1 -tls1_1 Just use TLSv1.1 -tls1_2 Just use TLSv1.2 -dtls Use any version of DTLS -timeout Enable send/receive timeout on DTLS connections -mtu +int Set the link layer MTU -dtls1 Just use DTLSv1 -dtls1_2 Just use DTLSv1.2 -nbio Use non-blocking IO -psk_identity val PSK identity -psk val PSK in hex (without 0x) -srpuser val SRP authentication for 'user' -srppass val 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 -nextprotoneg val Enable NPN extension, considering named protocols supported (comma-separated list) -engine val Use engine, possibly a hardware device -ssl_client_engine val Specify engine to be used for client certificate operations -ct Request and parse SCTs (also enables OCSP stapling) -noct Do not request or parse SCTs (default) -ctlogfile infile CT log list CONF file =head2 Note:Selected Protocol 'sslversion' returns protocol as used in our data structure (like TLSv12) example (output from openssl): New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256 example Net::SSLeay: Net::SSLeay::version(..) example (output from openssl): 'session_protocol' retruns string used by openssl (like TLSv1.2) Protocol : TLSv1.2 'fallback_protocol' Note: output from openssl: TLSv1.2 Note: output from Net::SSLeay: TLSv1_2 =head2 Note:Selected Cipher SEE L. '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 (output from openssl): example Net::SSLeay: Net::SSLeay::get_cipher(..) =head2 Note:Cipher and Protocol Cipher suites names are not unique per SSL/TLS protocol and can be used in multiple protocols, for example SSLv3 and TLSv11. When ciphers are checked with +cipher or +check , its not possible to map the reported cipher to the propper SSL/TLS protocol, unless the --header option was used. As the the checks for cipher suites are done per protocol, the result will be pretended with a header line indicating the current SSL/TLS protocol. This additional header line is only printed for our own formats. If output format for other tools is requested by using --legacy=* , these tools are responsible themself to print proper results. =head2 Note:Connection Test To avoid long timeouts, 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 L. 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 experience) 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. Measuring 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. The reasons and calculations of the returned status are printed withh --v or the special --trace-exit option. By default, the "EXIT status" messages is printed, which can be suppressed with --exitcode-quiet . NOTE: option named --trace-exit and not --exitcode-v so that it matches all checks according --trace* . =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 TBD =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 available 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 containing 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, a "preferred selected cipher" is provided. 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 "preferred" 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:Duplicate Commands If a command is given multiple times, in any order, it should be executed only once. The normalisation is done right before commands are executed, because multiple commands may occour in many places. The normalisation must preserve the sequence of the commands, which can be defined by the user. The first occourance of a command is used, all others are ignored. =head2 Note:+cipherall SEE L. 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 structure for the results. Then the program flow should be like: ciphers_scan() checkciphers() printciphers() printciphersummary() =head2 Note:+cipher Starting with VERSION 19.11.19, only the command +cipher is supported. When using any of the old commands, a hint will be written. With this version the output format for cipher results was also changed. It now prints the "Security" A, B, C (and -?- if unknown) as specified by OWASP. The column "supported" will not be printed, because only supported ciphers are listed now. This makes the options --enabled and --disabled also obsolete. Note that the description in L uses the commands names as used in VESRIONs before 19.11.19. More information, which is also important for users, can be found in user documentation OSaft/Doc/help.txt section "Version 19.11.19 and later". Internally, the commands cipher_intern, cipher_openssl, cipher_ssleay and cipher_dump are used; the command cipher still remains in $cfg{do}. SEE L. =head2 Note:--enabled --disabled The options --enabled and --disabled are traditionally implemented as toggle for the functionality to print enabled or disabled ciphers only. Therefore the default is to print both types. When either option is given, the opposite one is deactivated. The options --noenabled and --nodisabled are just for convenience, but do not toggle the opposite one. =head2 Note:--test-* The options --test-* are used for testing, showing internal information. Actually these are commands, hence the form +test-* is also supported. All these commands do not perform any checks on the specified targets, but exit right before the checks start. It is the same behaviour as the +quit command. Until VERSION 19.12.21, only the options --test-* where supported. Using these options exited the program. This behaviour resulted in incomplete or misleading information. =head2 Note:hints The output may contain !!Hint messages, see --help=output for details. The texts used for hint messages can be hardcoded in %cfg, set dynamically in %cfg in the code, or set using command-line options at startup. The hash %{$cfg{'hints'}} contains all these texts. There're at least following types (places of definition) of hints: * permanent hints -- defined in %{$cfg{'hints'}} directly * dynamic hints -- defined at command line with option --cfg_hint= * hints for new or experimental code -- defined in the code itself A definition for a hint may look like: $cfg{hints}->{KEY} = 'new text'; KEY can be any string. If KEY (without leading +) is a known valid command the message is printed automatically with the commands output (see below). The text may contain formatting characters like \t and \n. To set new hints dynamicly, following option can be used: $0 --cfg_hint=KEY="some text\nin 2 lines" All predefined (hardcoded) hints can be listed with: $0 --help=hint Note that dynamicly defined hints with --cfg_hint=KEY= are also shown if the option was given before --help=hint , example: $0 --cfg_hint=my-hint="given on command-line" --help=hint Automatic printing works as follows: print_check() and print_data() will automatically print hint texts if defined for the corresponding command. They can be printed immediately (without being specified in $cfg{hints} : printhint('your-key'), It is not recommended to use: print $STR[HINT}, "my text"; =head2 Note:tty The general concept is to use postprocessors for any output processing and formatting. This concept becomes clumsy when the tool is used on devices with limited capabilities (like tablets or smartphones). The format of the output is described in the RESULT section of the docu- mentation. Beside the results we also have the documentation itself, which is intended to be read by humans. I.g. all output may be passed to well known formatting tools like nroff, troff, etc. but this may clutter some texts which are well formatted for human readability. The documentation is also preformatted for a screen width of 80 characters (when troff or alike is not in use). This means that following situations have to be handled: * output of results * output of documentation * output of preformatted documentation To get a better human readable documentation on small devices, options can be used to force formatting of some output depending on the screen width. These options are mainly (for details please see OPTIONS section): --format-tty --tty --format-width=NN --format-ident=NN --format-arrow=CHR By default, the format settings are not used. The settings are grouped in the %cfg{tty} structure. All special formatting according the tty is done in o-saft-man.pl (because only documentation is effected). The function _man_squeeze() is used for that. It tries to optimize the ouput for the device. Text preformatted for better readability will be respected. As the approach is genereric, the final result may not be perfect. Following restrictions, oddities exist: * splitting is done on length of the text not on word bounderies, some words may be split in the middle * additional empty lines may occour * dashed lines (used for headings) are mainly not adapted (split) To clearly mark the special formatting, an additional "return" character is inserted where text was split. If the (human) user decided to use --tty , the output is most likely not subject to further postprocessing, hence each leading TAB can be replaced by 8 spaces too. Hopefully this generated result is more comfortable to read than the text provided by the default behaviour. Simply use the --tty option. =cut O-Saft-22.11.22/o-saft.tcl000077500000000000000000006267221433765727300147720ustar00rootroot00000000000000#!/bin/sh #| restarts using wish \ exec wish "$0" ${1+"$@"} #!############################################################################# #!# Copyright (c) 2022, Achim Hoffmann #!#---------------------------------------------------------------------------- #!# 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 [OPTIONS] [host:port] [host:port] ... #? $0 [OPTIONS] --load=result-from-o-saft.pl-file #? $0 [OPTIONS] [+commands] [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. #? #? It can be used to read saved results from other calls of o-saft.pl. #? #? Any argument starting with + are considered a command for o-saft.pl #? and o-saft.pl will be started with all other options, commands and #? targets and show the results in the GUI. #? #? Result TAB #? The results 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 functionality 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 customised 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 or can be created with --rc . #? #? 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 #? #? 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 in this window #? 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 pattern must have at least 4 characters, except for mode "exact". #? #? The GUI contains various [?] buttons. Clicking such a button will show #? the corresponding section in the help window (context sensitive). #? #? 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 ). #? This behaviour is disabled with the --test-tcl option. #? #? Key Bindings #? Following key bindings are defined: #? ! show window with About text #? ? show window with Help text #? c show window ciphers #? d show window tool settings (with --debug only) #? h show window with Help text #? q (quit) terminate Window or program #? start browser with selected link #? copy text to clipboard (see above) #? copy text to clipboard (see above) #? copy text from clipboard #? copy selected text to clipboard #? #? OPTIONS #? Options for information and help: #? --h print this text #? --help=opts print options (for compatibility with o-saft.pl) #? --version print version number #? +VERSION print version number (for compatibility with o-saft.pl) #? #? Options for configuration and startup behaviour: #? --rc print template for .o-saft.tcl #? --no-docs use configuration texts returned from o-saft.pl instead of #? reading prepared static files #? --gen-docs generate static files for configuration texts #? --pod use podviewer to show help text #? --tkpod use tkpod to show help text #? --stdin read data from STDIN and show in result TAB #? --load=FILE read data from FILE and show in result TAB #? #? Options for use with docker: #? --docker use o-saft-docker instead of o-saft.pl #? --docker-id=ID #? use Docker image ID (registry:tag); default: owasp/o-saft #? --docker-tag=ID use Docker image ID with tag; default: (empty) #? #? Options for GUI behaviour: #? --gui dummy for compatibility with other tools #? --gui-tip use own tooltip #? --gui-button=text use simple texts as labels for buttons #? --gui-button=image use images for buttons (see o-saft-img.tcl) #? (not recommended on Mac OS X, because Aqua has nice buttons) #? --gui-layout=classic tool layout for view on desktop #? --gui-layout=tablet tool layout for tablet, smartphone; default #? --gui-result=text print result of o-saft.pl as simple plain text #? --gui-result=table print result of o-saft.pl formated in a table #? #? Options for debugging: #? --v print verbose messages (startup and calling external tools) #? --d print more verbose messages (for debugging) #? --d=D print debug messages according level #? D=1 - print verbose messages (main) #? D=2 - print proc calls (those not triggerd by events) #? D=4 - print debugging in proc #? D=8 - print verbose debugging for "help" window #? values can be combined, like --d=6 to print procs and data, #? all --d=* imply --v #? --trace use Tcl's trace to trace proc calls #? #? Options for testing: #? +quit exit without GUI (for compatibility with o-saft.pl) #? --test=FILE read FILE and print on STDOUT; used for testing only #? --test-docs just print used external o-saft.pl.--help=* files #? --test-tcl just print debug information; similar to: --d +quit #? --test-osaft just print text used for help window (help button) #? #? Option aliases for compatibility with other programs or legacy: #? # Alias Option #? #----------+-------------------- #? --image --gui-button=image #? --text --gui-button=text #? --tip --gui-tip #? --id=ID --docker-id=ID #? --tag=TAG --docker-tag=TAG #? #? Options passed through to o-saft.pl: #? +* any option starting with + #? --* any other option starting with -- # TODO: --post=PRG --post= parameter passed to o-saft #? #? 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 be 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, in particular when texts are changed with this option. #? #? Some --legacy=* options are not handled properly. In particular the #? result looks corrupted in table view when the option --legacy=compact #? or --legacy=full is used; , use the text view for that. #? #? 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) #? #? To pipe data in on STDIN, the option --stdin must be used, otherwise #? it will not be read. #? #? STDIN and _LOAD as filenames can not be used to load data. #? #? Not really a problem, but worth to mention: #? It's not possible to map cipher suites to the proper SSL/TLS protocol #? in the results TAB in table view. Therefore the cipher suite names are #? prepended by the protocol. #? Due technical reasons, the protocol and the cipher suite name will be #? separated by the non-breaking space character U+2007. #? Take care when processing saved results, [Save] and [STDOUT] button. #? #? ARGUMENTS #? All arguments, except the options described above, are treated as a #? hostname to be checked. #? #? ADDITIONAL SYNOPSIS #? On some systems (i.e. Android) it could be difficult to pass arguments #? and/or options to this script. To simulate passing options, following #? alias names are provided: #? o-saft--testtcl.tcl #? o-saft--test-docs.tcl #? o-saft--trace.tcl #? o-saft--d.tcl #? osaft--testtcl.tcl #? osaft--test-docs.tcl #? osaft--trace.tcl #? osaft--d.tcl #? #? SEE ALSO #? o-saft #? o-saft.pl #? o-saft-docker #? #. LAYOUT #. --gui-layout=tablet #. +---------------------------------------------------------------+ #. (M) | ☰ Cmd Opt Config | #. |---------------------------------------------------------------| #. (H) | Host:Port [________________________________________] [+] [-] | #. | | #. | +----------++----------+ | #. (R) | | (n) +cmd || (m) +cmd | | #. | + +------------------------------------------------+ | #. | | | | #. | | | | #. | +-----------------------------------------------------------+ | #. |---------------------------------------------------------------| #. |---------------------------------------------------------------| #. (S) | | | | #. +---------------------------------------------------------------+ #. #. --gui-layout=classic #. +---------------------------------------------------------------+ #. (H) | Host:Port [________________________________________] [+] [-] | #. | [!] [?] | #. (C) | [Start] [+info] [+check] [+cipher] [+quick] [+vulns] [Load] | #. (O) | [ ] --header [ ] --enabled [ ] --no-dns [ ] -no-http ... | #. |---------------------------------------------------------------| #. | +----------++---------++--------++----------++----------+ | #. (T) | | Commands || Options || Filter || (n) +cmd || (m) +cmd | | #. | + +------------------------------------------------+ | #. | | | | #. | | | | #. | +-----------------------------------------------------------+ | #. |---------------------------------------------------------------| #. (S) | | | | #. +---------------------------------------------------------------+ #. #. Description #. (H) - Frame containing hostnames to be checked #. (M) - Frame containing menus for all commands, commands, options #. ☰ - menubutton for all commands and options #. Cmd - menubutton for quick commands (most often used) #. Opt - menubutton for quick options (most often used) #. Cfg - menubutton for configuration settings #. (C) - Buttons for most commonly used commands #. (O) - CheckButtons for most commonly used options #. (R) - Frame containing panes for results #. (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 #. #. For the main workflow use the --trace option, for example: #. $0 --trace +quit #. $0 --trace --gui-layout=classic #. #. LIMITATIONS #. All help texts reference to the default hardcoded texts, even if they #. are changed in .o-saft.tcl . #. #. HACKER's INFO #. 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 #. #. 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 application logic #. - some widget names are hardcoded #. #. 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 Naming Conventions #. - procedures: #. create_* - create widget or window #. osaft_* - run external o-saft.pl (and process output) #. search_* - searching texts in help (widget in help window) #. - variables (GUI): #. 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) #. exe() - global variable containing commands and options for #. o-saft.pl from command-line #. cfg() - global variable containing most configurations #. cfg_colors()- global variable containing colours for widgets #. cfg_texts() - global variable containing texts for widgets #. cfg_tipps() - global variable containing texts for tooltips #. search() - global variable containing texts used for searching #. myX() - global variable for windows and window manager #. - variables (O-Saft execution): #. hosts() - global variable with list of hosts to be checked #. results() - global variable containing results of executions #. - comments #. lines starting with #. #. - these lines are intended for internal documentation #. lines starting with #? #. - these lines are intended for public documentation #. lines starting with #? (inside proc definition) #. - lines are used for internal developer documentation #. lines starting with #| #. - lines are used for internal developer documentation #. lines with ;# #. - Tcl requires a ; after the statement before any #. comment; the ; is usually right before the # #. #. Coding (general) #. Sequence of function definitions done to avoid forward declarations. #. See Debugging Options below also. #. #. Coding (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. #. #. Starting 11/2021 the default tool layout was changed from "classic" to #. "tablet". This only affects building the GUI itself. The difference in #. building the GUI is mainly controlled by the variable cfg(gui-layout). #. This effects the procs: create_host() create_buttons() and gui_main(). #. #. STDIN #. Tcl's file handle (channel) for STDIN is named stdin, which is open by #. default. Data piped to $0 can be read from this file handle. #. But it is difficult to detect if data is available from stdin, if not, #. Tcl's get() function simply hangs. To avoid this, the option --stdin #. must be used if data should be read from STDIN, example: #. cat some-file | $0 --stdin #. o-saft.pl +check localhost | $0 --stdin #. Reading from STDIN can simply be tested like #. echo "label: no any comment" | $0 --stdin #. #. Note that STDIN is used as filename to indicate that Tcl's stdin file #. handle should be used (which needs to be treated special). #. #. Tracing (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. #. Tracing is invoked with the --trace option. #. #. Tracing (program flow) #. --d=X - see description above #. #. Tracing and Debugging #. All output for --trace and/or --dbx is printed on STDERR. #. Trace messages are prefixed with: #[$0]: #. Debug messages are prefixed with: #dbx# [$0]: #. #. --test=FILE #. --test=FILE --gui-result=text #. --test=FILE --gui-result=table #. loads FILE into the GUI's tablelist widget and then calls the save #. function, which prints the content of tablelist on STDOUT. #. This is used in Makefile* for testing functionality, does not make #. any sense otherwise. #. The --gui-result=* option enforces to display and store the file #. content in Tk's tablelist or text widget. The displayed output may #. be slightly different, as the tablelist doesn't always contain all #. data of the file. #. #. Tracing and Debugging with Alias Names #. If arguments (options) can not be passed to the script, alias names of #. the script can be used to simulate passed options: #. # alias name # behaves as called like #. #-----------------------#------------------------------- #. o-saft--testtcl.tcl $0 --test-tcl #. o-saft--d.tcl $0 --d #. o-saft--trace.tcl $0 --trace #. #. Notes About Tcl/Tk #. We try to avoid platform-specific code. The only exceptions since 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 gui_set_readonly() for details. #. #? VERSION #? @(#) 2.35 Summer Edition 2022 #? #? AUTHOR #? 04. April 2015 Achim Hoffmann #? #? Project Home: https://www.owasp.org/index.php/O-Saft #? Help Online: https://www.owasp.org/index.php/O-Saft/Documentation #? https://wiki.owasp.org/index.php/O-Saft/Documentation #? Repository: https://github.com/OWASP/O-Saft #? # ----------------------------------------------------------------------------- set cfg(testtcl) 0 #package require Tcl 8.5 ;# for documentation only #package require Tk 8.5 ;# modern Tcl/Tk doesn't need it anymore if {![regexp -- {--test-?tcl} $argv]} { # keep some systems quiet package require Tk set cfg(testtcl) 1 } #_____________________________________________________________________________ #___________________________________________________________ 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. if {0<$cfg(testtcl)} { # do not bind in debug-only mode to avoid errors, see "Key Bindings" 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 {1==$shift} { set txt "$w $klasse: " } # TODO: Menu, 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 - Menubutton - 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" } } if {1==$shift} { set cmd "" catch {lindex [$w config -command] 4} cmd ;# show error or command append txt "\n -command $cmd" } putv "copy2clipboard($w, $shift): {\n $txt\n#}" clipboard clear clipboard append -type STRING -format STRING -- $txt }; # copy2clipboard #_____________________________________________________________________________ #____________________________________________________________ configuration __| # this section mainly contains variable initialisations, it also defines some # functions for easy acces to configurations proc config_docker {mode} { #? initilise configuration for use with Docker image # may be called with $mode=opt for --docker option or with $mode=prg to # check if program name matches *-docker # must be early definition, because called right after program start global cfg prg env argv0 switch $mode { prg { if {[regexp {\-docker$} $argv0]} { set mode 1 } } opt { set mode 1 } } if {1==$mode} { set cfg(docker) 1 set prg(SAFT) "o-saft-docker" } # independent of mode, can always be set if {1==[info exists env(o_saft_docker_tag)] } { set prg(docker-tag) $env(o_saft_docker_tag) } if {1==[info exists env(o_saft_docker_name)]} { set prg(docker-id) $env(o_saft_docker_name) } return }; # config_docker if {![info exists argv0]} { set argv0 "o-saft.tcl" } ;# if it is a tclet set cfg(SID) "@(#) o-saft.tcl 2.35 22/11/18 12:41:50" set cfg(mySID) "$cfg(SID) Summer Edition 2022" # contribution to SCCS's "what" to avoid additional characters set cfg(VERSION) {2.35} 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(O-Saft) {o-saft.pl} ;# common name of O-Saft executable # constant also used for filenames set cfg(POD) {o-saft.pod} ;# complete help text in POD format 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 set cfg(stdout) 0 ;# 1: call osaft_save TTY set cfg(docker) 0 ;# 1: for --docker option or o-saft-docker #et cfg(HELP-key) "" ;# contains linenumber of result table set cfg(docs-dir) $cfg(DIR)/docs ;# directory where to find documentation # may be redifined in RC-file #-----------------------------------------------------------------------------{ # Definitions outside RC-ANF - RC-END scope, because they're not intended to # be changed in .o-saft.tcl . #et exe() ... # will contain commands and options from command-line # define 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(post) {} ;# --post= parameter, if passed on command-line set prg(option) 0 ;# set to 1 to avoid internal "option add ..." commands #-----------------------------------------------------------------------------} # 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 # Will be set to o-saft-docker when --docker is given # prg(SAFT) must be found with the system's PATH environment variable, # otherwise a full path must be used here. #-----------------------------------------------------------------------------} set prg(DESC) {-- CONFIGURATION external programs --------------------------} set prg(PERL) {} ;# full path to perl; empty on *nix set prg(BROWSER) "" ;# external browser program, set below # o-saft.tcl tries to find the browser automatically, a list of well known # browser names is used for that. Another browser can be set here, must be # a full path or found with PATH environment variable. set prg(TKPOD) {O-Saft} ;# name of external viewer executable # 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 a full # 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(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} } # List of quick access commands, for which a button will be created in the # GUI. This must be commands of o-saft.pl, which start with + character. # +quit and +version will be added for --v or --d only. set prg(Oopt) {{--header} {--enabled} {--no-dns} {--no-http} {--no-sni} {--no-sslv2} {--no-tlsv13} } # List of quick access options, a checkbox will be created in the GUI. # This must be options of o-saft.pl, which start with -- character. 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-) "400x80" ;# geometry and position of no match window set myX(geoS) "700x720" ;# geometry and position of O-Saft window set myX(geoA) "660x610" ;# geometry and position of About window set myX(geoC) "" ;# geometry and position of Config window (computed dynamically) set myX(geoD) "700x700" ;# geometry and position of Cipher window set myX(geoF) "700x700" ;# geometry and position of Filter window (computed dynamically) set myX(geoT) "" ;# set myX(minx) 700 ;# O-Saft window min. width set myX(miny) 850 ;# 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 set myX(maxS) 3 ;# height of status line set cfg(DESC) {-- CONFIGURATION GUI style and layout -----------------------} set cfg(gui-button) {image} ;# button style: image or text # used with --gui-layout=classic only set cfg(gui-layout) {tablet} ;# tablet: tool layout for tablet, smartphone # classic: tool layout for view on desktop set cfg(gui-result) {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) 4050 ;# 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 cfg(docs-exe) 0 ;# 0: read configuration of commands and options # from static files in ./docs/ # 1: read configuration using o-saft.pl set cfg(nbsp) \u2007 ;# character used for non-breaking spaces set cfg(DESC) {-- CONFIGURATION misc settings ------------------------------} set cfg(no-match) {_NO_} ;# text pattern used to avoid matching some text # RC-END } set cfg(docs-help) {--help=alias --help=checks --help=data --help=glossar --help=regex --help=rfc --help} # file extensions for files from ./docs/ used in osaft_read_data() and osaft_help() # missing: --help=text --help=ourstr --help=compliance # missing because too much data: --help=range set cfg(docs-help-all) "--help=commands --help=opts $cfg(docs-help) --help=ciphers-text" # this list should be same as $cfg{'files'}, # see also man_docs_write() in in o-saft.pl set cfg(docs-files) {} ;# contains the read files from ./docs/ set cfg(guiwidgets) {} ;# contains the widgets of the GUI set cfg(guimenus) {} ;# contains the widgets of the GUI's menus # debugging only for --gui-layout=tablet config_docker prg ;# may initialise some docker-specific settings catch { set fid [open $prg(INIT) r] ;# read .o-saft.pl set cfg(.CFG) [read $fid] close $fid } #| configure GUI set cfg(gui-tip) [catch { package require tooltip} tip_msg]; # 0 on success, 1 otherwise! set IMG(help) ::tk::icons::question #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 #d9d9d9 ;# default background color (lightgray) # this colour is used for buttons too # default background of Tk widget (if available) catch { set my_bg "[lindex [.i config -bg] 4]" } # 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 guitheme_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 . # Note: should be used after calling gui_init #----------+---------------+-------+-------+------------------------------- # object button text colour image help text (aka tooltip) # name -text -bg -image guitip_set() #----------+-----------+-------+-----------+------------------------------- array set cfg_buttons " about {{!} $my_bg {!} {About $cfg(ICH) $cfg(VERSION)}} 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}} helpreset {{Reset} $my_bg reset {Reset/clear list of search texts}} 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 docker_status {Execute $prg(SAFT) status }} img_txt {{image/text} $my_bg {img_txt} {toggle buttons: text or image}} DESC_menu {-- for following rows, colour is the forground colour of the objekt --} menu_menu {{☰} orange {} {Main menu}} menu_cmd {{Cmd} white {} {Quick commands menu}} menu_opt {{Opt} white {} {Quick options menu}} menu_cfg {{Config} white {} {GUI configurations menu}} menu_cmds {{ + All Commands} {} {} {Commands submenu}} menu_opts {{ - All Options} {} {} {Options submenu}} menu_load {{ Load Results} {} {} {Load results from file}} menu_filt {{ Config Filter} {} {} {Show configuration for filtering results}} menu_conf {{ Config GUI} {} {} {Show configuration for GUI settings}} menu_prog {{ Config Tool} {} {} {Show configuration for tool itself}} menu_mode {{Change Layout} {} {} {Toogle layout between classic and tablet}} menu_help {{ ? Help} {} help {Open window with complete help}} menu_list {{ Cipher Suites} {} {&} {Open window with list of cipher suites}} menu_uber {{❗ About} {} {!} {About $cfg(ICH) $cfg(VERSION)}} menu_exit {{⏻ Quit} orange quit {Close program}} menu_rsave {{Save} {} save {Save results to file}} menu_reset {{Reset} {} reset {Reset configuration to defaults}} "; #----------+-----------+-------+-----------+------------------------------- # name -text -bg -image guitip_set() #----------+-----------+-------+-----------+------------------------------- # 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 configuring 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_tipps. The settings here are defaults, # and may be redefined 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 initialised here for all # other values, and then the values from cfg_buttons are added. # # array in cfg(RC) array herein (see also update_cfg() ) # cfg_color cfg_colors # cfg_label cfg_texts # cfg_tipp cfg_tipps # functions to get above texts proc _get_btn_txt {key} { global cfg_buttons; return [lindex $cfg_buttons($key) 0] } proc _get_btn_bg {key} { global cfg_buttons; return [lindex $cfg_buttons($key) 1] } proc _get_btn_img {key} { global cfg_buttons; return [lindex $cfg_buttons($key) 2] } proc _get_btn_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 " # above texts are used with _get_color() array set cfg_texts " DESC_search {-- CONFIGURATION texts used in GUI's Help window ------------} h_min4chars {Pattern should have more than 3 characters.} h_nomatch {No matches found for} h_badregex {Invalid RegEx pattern} DESC_texts {-- CONFIGURATION texts used in GUI for buttons or labels ----} host {Host\[:Port\]} hideline {Hide complete line} c_toggle {toggle visibility\nof various texts} DESC_table {-- CONFIGURATION texts used for table headers ---------------} t_nr Nr t_label Label t_value Value t_comment Comment t_key Key t_moder r t_modee e t_chars {#} t_regex RegEx t_fg Foreground t_bg Background t_font Font t_u u DESC_other {-- CONFIGURATION texts used at various places ---------------} cfg_progs {Used programs:} cfg_regex {Used RegEx:} cfg_docker {Docker setting:} gui_layout {Layout format of results:} gui_button {Style of buttons:} win_about {About} win_cipher {Cipher Suites} win_colour {Colour} win_cmds {Commands} win_opts {Options} win_font {Font} win_help {Help} win_tool {Tool Settings} win_config {Config} win_filter {Filter} win_search {Search ...} win_search_results {Search Results for:} no_browser {no browser found} gen_docs { GUI may be incomplete !!Hint: use »$prg(SAFT) --help=gen-docs« to generate static files } " # above texts are used with _get_text() array set cfg_tipps " DESC {-- CONFIGURATION texts used for tool tips on buttons --------} settings {Open window with more settings} open_browser {Open in browser:} 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} possible_values {possible values:} show_hide {show/hide:} tabMENU {Select commands and options in ☰ menu.} 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_filter {-- CONFIGURATION texts used in Filter tab -------------------} t_key {Unique key for regex} t_moder {Modifier: use regex with regex pattern (-regexp)} t_modee {Modifier: use regex with exact pattern (-exact)} t_chars {Length to be matched (0: all text; -1: complete line to right end)} t_regex {RegEx to match text} t_bg {Background color used for matching text (empty: don't change)} t_fg {Foreground color used for matching text (empty: don't change)} t_font {Font used for matching text (empty: don't change)} t_u {Underline matching text (0 or 1)} t_cmt {Description of regex} 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_tipps; # Note: text for tab* contain new lines. # above texts are used with _get_tipp() # now add default to cfg_* as described before foreach key [array names cfg_buttons] { set cfg_colors($key) [_get_btn_bg $key] set cfg_texts($key) [_get_btn_txt $key] set cfg_tipps($key) [_get_btn_tip $key] set cfg_images($key) [_get_btn_img $key] } # functions to get above texts 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_tipps; return $cfg_tipps($key) } #? return text string for key from global cfg_tipps 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 _message {icon title txt} { # print message, either with GUI or on STDERR if {""==[info commands tk_messageBox]} { puts stderr "# $icon: $title #\n$txt" } else { tk_messageBox -icon $icon -title "$title" -message "$txt" } return };# _message 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" ] } } if {1==[info exists env(ANDROID_DATA)]} { # dirty hack to detect Android and adapt configuration set cfg(gui-button) "text" ;# text by default, because icons are too small set prg(PERL) /data/data/com.termux/files/usr/bin/perl # FIXME: not working for all perl installations on Android } # 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 3 " $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]} { _message warning "**WARNING: (main)" \ "$prg(SAFT) not found most parts of the GUI are missing! ---- $usage ---- !!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 # # counter also used for number of TABs in $cfg(objN), hence # # TABs with executions start at 3, see create_main_tabs() 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(winO) "" ;# object name of Help window set cfg(win-) "" ;# (reserved for future use) set cfg(winS) ".";# object name of main window (usually not used as just .) set cfg(winA) "" ;# object name of About window set cfg(winD) "" ;# object name of Cipher window set cfg(winF) "" ;# object name of Filter window set cfg(winT) "" ;# (reserved for future use) set cfg(objN) "" ;# object name of notebook; needed to add more note TABS set cfg(objS) "" ;# object name of status line set cfg(objT) "" ;# widget name of button ttyresult 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(winO) # 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) ""; # array containing host:port set results(0) ""; # contains raw results of prg(SAFT); results(0) is empty #_____________________________________________________________________________ #_______________________________________________________ filter definitions __| # arrays created dynamically: f_key f_mod f_len f_bg f_fg f_rex f_un f_fn f_cmt 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 _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 4 " no = »$str«" return 0 }; # _notTOC proc _count_tuples {str} { return [expr [expr [llength $str] +1] / 2] } #? return number of touples in given list proc pwarn {txt} { puts stderr "**WARNING: $txt"; return } #? output WARNING message proc perr {txt} { puts stderr "**ERROR: $txt"; return } #? output ERROR message proc putv {txt} { #? verbose output global cfg if {$cfg(VERB) <= 0} { return } puts stderr "#\[$cfg(ICH)\]:$txt" return }; # putv proc _ident {cnt} { #? return ident string set txt "" for {set i 1} {$i <= $cnt} {incr i} { set chr " "; # . #if {0==[expr $i % 3]} { set chr "|" } append txt $chr } return $txt }; # _ident proc _dbx {level txt} { #? debug output (if $level matches $cfg(DEBUG)) global cfg if {! [expr $cfg(DEBUG) & $level]} { return } 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" return }; # _dbx proc _trace {args} { #? trace output global cfg if {0>=$cfg(TRACE)} { 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 {^\{} $txt ""] set txt [regsub {^(.[^\s]*)\s*(.*)\}? enter\s*$} $txt "\\1 \{\\2\} \{"] 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 _trace_add {cmd} { #? initialise Tcl's tracing for given command or widget trace add execution $cmd enter _trace trace add execution $cmd leave _trace return }; # _trace_add proc trace_commands {} { #? initialise Tcl's tracing for most of our procs append _trace_cmds "[info procs config*] " 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 " append _trace_cmds "gui_init gui_main guitheme_init update_cfg" # procs not found by info command before foreach _cmd $_trace_cmds { if {[regexp "\(create_\(tip\)\)" $_cmd]} { continue } _trace_add $_cmd } return }; # trace_commands proc trace_buttons {} { #? initialise Tcl's tracing for all buttons foreach obj [info commands] { if {![regexp {^\.} $obj]} { continue } switch [winfo class $obj] { {Button} { _trace_add $obj } } } return }; # trace_buttons proc read_images {theme} { #? read $cfg(IMG) if exists and not already done _dbx 2 "{$theme}" global cfg IMG # 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 {"image" eq $theme} { set rcfile [regsub "$cfg(ICH)$" $cfg(ME) "$cfg(IMG)"]; # must be same path _dbx 4 " IMG $rcfile" if {[file isfile $rcfile]} { catch { source $rcfile } error_txt } else { pwarn "$cfg(IMG) not found; using traditional buttons" } } _dbx 4 " IMG = [array names IMG]" return }; # read_images proc update_cfg {} { #? 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_tipps # 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 2 "{}" global cfg if {1==[info exists cfg(RCSID)]} { # cfg(RCSID) is defined in .o-saft.tcl, warn if old one _dbx 4 " RCmin$cfg(RCmin) > RCSID$cfg(RCSID) ?" if {$cfg(RCmin) > $cfg(RCSID)} { _message warning "$cfg(RC) version $cfg(RCSID)" \ "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_tipps cfg_tipp foreach key [array names cfg_tipp] { set value $cfg_tipp($key) switch -exact $key { {start} { set cfg_tipps(cmdstart) $value } {closew} { set cfg_tipps(closewin) $value } {showfilterconfig} { set cfg_tipps(filter) $value } {resetfilterconfig} { set cfg_tipps(reset) $value } {goback} { set cfg_tipps(help_prev) $value } {goforward} { set cfg_tipps(help_next) $value } {search} { set cfg_tipps(helpsearch) $value } {choosecolor} { set cfg_tipps(tkcolor) $value } {choosefont} { set cfg_tipps(tkfont) $value } {plus} { set cfg_tipps(host_add) $value } {minus} { set cfg_tipps(host_del) $value } default { set cfg_tipps($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 }; # update_cfg # if {1==$cfg(gui-tip)} { # use own tooltip from: http://wiki.tcl.tk/3060?redir=1954 proc guitip_set {w txt} { #? add tooltip message to given widget global cfg if {1==$cfg(gui-tip)} { # package tooltip not available, use own one bind $w "after 1000 [list _show_tooltip %W [list $txt]]" bind $w "destroy %W.balloon" } else { set txt [regsub {^-} $txt " -"];# texts starting with - cause problems in tooltip::tooltip tooltip::tooltip $w "$txt" } return }; # guitip_set proc _show_tooltip {w txt} { 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 $txt] 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 return }; # _show_tooltip proc gui_set_disabled {w} { #? set widget to disabled state (mode) $w config -state disabled return }; # gui_set_disabled proc gui_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 }; # gui_set_readonly proc guitheme_set {w theme} { #? set attributes for specified object # last part of the Tcl-widgets is key for array cfg_buttons _dbx 2 "{$w, $theme}" global cfg cfg_buttons IMG # text and tip are always configured set key [regsub {.*\.([^.]*)$} $w {\1}];# get trailer of widget name set val [_get_tipp $key]; if {"" ne $val} { guitip_set $w $val } set val [_get_text $key]; if {"" ne $val} { $w config -text $val } set val [_get_image $key]; if {![info exists IMG($val)]} { set theme "text" } _dbx 4 " $w\t-> $key\t$theme\t-> $val" if {"text" eq $theme} { set val [_get_color $key] if {"" ne $val} { $w config -bg $val } $w config -image {} -height 1 -relief raised } if {"image" eq $theme} { if {"" ne $val} { 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 }; # guitheme_set proc guitheme_init {theme} { #? configure buttons with simple text or graphics _dbx 2 "{$theme}" global cfg_buttons # 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 4 ": regex = $rex" foreach obj [info commands] { if {![regexp {^\.} $obj]} { continue } if {![regexp $rex $obj]} { continue } if { [regexp {^\.$} $obj]} { continue } guitheme_set $obj $theme } return }; # guitheme_init proc guicursor_set {cursor} { #? set cursor for toplevel and tab widgets and all other windows global cfg foreach w [list . objN objS winA winD winF winO] { if {"." ne $w} { set w $cfg($w) } if {"" eq $w} { continue } # now get all children too foreach c "$w [info commands $w.*]" { if {"" eq $c} { continue } if {2<[regexp -all {\.} $c]} { continue } ;# only first level catch { $c config -cursor $cursor } ;# silently discard errors } } return }; # guicursor_set proc guistatus_set {val} { #? add text to status line global cfg if {1==$cfg(quit)} { return } ;# no GUI update $cfg(objS) config -state normal $cfg(objS) insert end "$val\n" $cfg(objS) see "end - 2 line" gui_set_readonly $cfg(objS) update idletasks ;# enforce display update return }; # guistatus_set 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) _dbx 4 " $w tag config $tag -elide [expr ! $val]" global cfg #if {0==$line} { #$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 _dbx 4 " $w rowcget $tag $val" global cfg # 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 2 "{$w $tag $val $line}" global cfg switch $cfg(gui-result) { 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 _dbx 2 "{$w}" 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 {0 eq $k} { continue } ;# TODO: == or eq ? # 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 {"" eq $key} { continue } ;# invalid or disabled filter rules if {"" eq $rex} { continue } ;# -"- _dbx 4 " $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 4 " $key: $rex F=$fg B=$bg U=$nr fn=$fn" if {"" ne $fg} { $w tag config HELP-$key -foreground $fg } if {"" ne $bg} { $w tag config HELP-$key -background $bg } if {"0" ne $nr} { $w tag config HELP-$key -underline $nr } if {"" ne $fn} { $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 optimised for # use in Tcls's text widget, the RegEx must be changed to match the values # in Tcl's tablelist columns _dbx 2 "{$w}" 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 {0 eq $k} { 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 {"" eq $key} { continue } ;# invalid or disabled filter rules if {"" eq $rex} { continue } ;# -"- _dbx 4 " $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 {1==$col} { # if the match is against the first column, colourise the whole line if {"" ne $fg} { $w rowconfig $nr -foreground $fg } if {"" ne $bg} { $w rowconfig $nr -background $bg } if {"" ne $fn} { $w rowconfig $nr -font $fn } #if {$un ne "0"} { $w rowconfig $nr -underline 1 } } else { if {"" ne $fg} { $w cellconfig $nr,$col -foreground $fg } if {"" ne $bg} { $w cellconfig $nr,$col -background $bg } if {"" ne $fn} { $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 layout cmd} { #? apply filters for markup in output tab, data is in text or table widget $w _dbx 2 "{$w, $layout, $cmd}" global cfg 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 return }; # show_window proc www_browser {url} { #? open URL in browser, uses system's native browser global cfg prg if {[string length $prg(BROWSER)] < 1} { pwarn [_get_text no_browser]; 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# } putv " exec {*}$prg(BROWSER) $url & " catch { exec {*}$prg(BROWSER) $url & } return }; # 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 {0==$cfg(gui-tip)} { tooltip::tooltip $w -tag $tagname-$i "[_get_tipp open_browser] $t" } # cannot use guitip_set as we want to bind to $tagname 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) guitheme_set $w.closewin $cfg(gui-button) guitip_set $w.choosen "[_get_tipp choosen] $title" set __var "$val" return 1 }; # create_selected proc destroy_window {w win} { #? wrapper to destroy toplevel window # avoids destroying the window if key was pressed i.e. in an entry widget if {$win eq $w} { destroy $win } return }; # destroy_window proc create_window {title size} { #? create new toplevel window with given title and size; returns widget # special handling for windows with title "Help" or "About" 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 bind $this "destroy_window %W $this";# see "Key Bindings" # TODO: bind should not apply to entry fields guitheme_set $this.f1.closewin $cfg(gui-button) if {"Help" eq $title || "About" eq $title} { return $this };# FIXME: use configurable texts if {[regexp {^Filter} $title]} { return $this } if {[regexp {^Config} $title]} { return $this } if {[regexp {^Settin} $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 # FIXME: widget paremeter $tbl missing for osaft_save guitheme_set $this.f1.saveconfig $cfg(gui-button) guitheme_set $this.f0.help_me $cfg(gui-button) return $this }; # create_window # poor man's OO for created windows proc create_window:title {w txt} { #? destroy "Save" button in created window global cfg wm title $w "$cfg(TITLE): $txt" wm iconname $w "o-saft: $txt" return } proc create_window:helpcmd {w cmd} { $w.f0.help_me config -command $cmd; return } #? configure new command for "?" button in created window proc create_window:savecmd {w cmd} { $w.f1.saveconfig config -command $cmd; return } #? configure new command for "Save" button in created window proc create_window:noclose {w} { destroy $w.f1.closewin; return } #? destroy "Close" button in created window proc create_window:nohelp {w} { destroy $w.f0.help_me; return } #? destroy "?" button in created window proc create_window:nosave {w} { destroy $w.f1.saveconfig; return } #? destroy "Save" button in created window proc create_host {parent host_nr} { #? frame with label and entry for host:port; $host_nr is index to hosts() # must use index to hosts() instead of host itself because the entry widget # needs a variable _dbx 2 "{$parent, $host_nr}" global cfg hosts myX if {$host_nr >= [array size hosts]} { set host "" } else { set host $hosts($host_nr) } _dbx 4 " host=$host, gui-layout=$cfg(gui-layout)" # the frame with the entry and button widgets will be created and deleted # dynamically, it's difficult to find a unique widget name, hence it will # be searched for set nr 0 set this ${parent}$nr while {[winfo exists $this]} { incr nr; set this ${parent}$nr } # got new valid widget name frame $this grid [label $this.lh -text [_get_text host]] \ [entry $this.eh -textvariable hosts($host_nr)] \ [button $this.host_del -command "remove_host $this; set hosts($host_nr) {}"] \ [button $this.host_add -command "create_host {$parent} [array size hosts];"] \ guitheme_set $this.host_add $cfg(gui-button) guitheme_set $this.host_del $cfg(gui-button) if {0==$nr} { # first line has no {-} but {About} grid forget $this.host_del if {"classic" eq $cfg(gui-layout)} { grid [button $this.about -command "create_about"] -row 0 grid config $this.about -column 4 -sticky e -padx "1 $myX(padx)" guitheme_set $this.about $cfg(gui-button) } } grid config $this.eh -column 1 -sticky ew grid columnconfigure $this 1 -weight 1 pack $this -fill x -before ${parent}_1 return $this }; # 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} return }; # remove_host proc create_text {parent content} { #? create scrollable text widget and insert given text; returns widget _dbx 2 "{$parent, ...}" 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 gui_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 header} { #? create scrollable table widget with given header lines; returns table widget _dbx 2 "{$parent, ...}" set this $parent global cfg 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 false \ -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 foreach f $header { # silently use given keyas text if not defined properly if {[catch { set txt [_get_text $f]}]} { set txt $f } lappend titles 0 $txt } $this.t config -columns $titles return $this.t }; # create_table proc create_resulttext {parent content} { #? create scrollable text widget and insert given text; returns widget return [create_text $parent $content] }; # create_resulttext proc create_resulttable {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 _dbx 2 "{$parent, ...}" _dbx 16 " content=»$content«" global cfg prg set this $parent.ft frame $this set table [create_table $this [list t_nr t_label t_value t_comment]] # configure columns $table columnconfigure 0 -width 3 ;# -hide true ;# line nr $table columnconfigure 1 -width 50 ;# label $table columnconfigure 2 -width 25 ;# value # insert content set i 0 ;# count line numbers; for debuging and warning message set n 1 ;# add unique number to each line, for initial sorting set ssl "" ;# TODO: ungly hack: need to detect header line with protocol set tsize 0 ;# count size of text, for debugging only foreach line [split $content "\n"] { incr i # 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 #_dbx 16 " line = $i, len=[string length $line]" if {0>=[string length $line]} { continue } ;# defensive programming if {[regexp {^\s*$} $line]} { continue } ;# skip empty lines #_dbx 16 " 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]} { $table insert end [list $nr $line] $table togglerowhide end $table cellconfigure end,0 -stretch 1 ;# FIXME: does not work if {[regexp {Ciphers:\sChecking} $line]} { # +cipher header line containing protocol, like: # === Ciphers: Checking TLSv12 === set ssl [lindex [split $line " "] 3];# remember current protocol #dbx# puts "#dbx# C $ssl" set line [regsub -all {=} $line {}]; set line [regsub -all {^:} $line {}]; set line [regsub -all {^ *} $line {}]; } # tablelist does not support "colspan", hence lines are ignored continue } if {[regexp $prg(SAFT).* $line]} { $table insert end [list $nr $line] $table togglerowhide end $table cellconfigure end,0 -stretch 1 ;# FIXME: does not work # tablelist does not support "colspan", hence lines are ignored continue } if {[regexp {:} $line]} { # line not from +cipher set col2 "" set col0 [regsub {^([^:]+):.*} $line {\1}];# get label set col1 [regsub {^[^:]+:\s*} $line {}] ;# get value # NOTE: there my be values like "No other text ..." # these literal text should not match our yes|no condition, hence if {[regexp -nocase {^no\s+(alternate name|response sent)} $col1]} { set col1 "$cfg(no-match)$col1" ;# add marker } 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 "^$cfg(no-match)" $col1]} { # replace marker; space avoids later colouring set col1 [regsub "^$cfg(no-match)" $col1 { }] } 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 "line $i: 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 (not in table) } set line [list $nr $col0 $col1 $col2] } else { # lines containing cipher, like: # AES128-SHA256 yes HIGH set line [regsub {^[ \t]+} $line {}] ;# remove trailing spaces set line [regsub -all {([ \t])+} $line { }] set cols [split $line " "] set line "$nr $ssl$cfg(nbsp)$cols" ;# add nr and protocol # quick&dirty hack to uniquely show the protocol where a cipher # was used: using the non-breaking space (aka FIGURE SPACE, aka # numeric non-breaking space) U+2007 avoids that tcl's tabletab # breaks the line into columns at spaces. # FIXME: see KNOWN PROBLEMS } set line [regsub -all \t $line {}] ;# remove tabs in line $table insert end $line set tsize [expr $tsize + [string length $line]] } #_dbx 16 " tsize = $tsize" pack $this -side top return $this }; # create_resulttable proc create_filterhead {parent key col} { #? create a cell for header line in the filter grid # note: key must be the index to cfg_texts and cfg_tipps array _dbx 2 "{$parent, ...}" set this $parent.$key grid [label $this -text [_get_text $key] -relief raised -borderwidth 1 ] -sticky ew -row 0 -column $col guitip_set $this [_get_tipp $key] return }; # create_filterhead proc create_filtertext {parent cmd} { #? create table with filter data # TODO: should be replaced by create_filtertable() _dbx 2 "{$parent, $cmd}" 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_filterhead $this t_key 0 create_filterhead $this t_moder 1 create_filterhead $this t_modee 2 create_filterhead $this t_chars 3 create_filterhead $this t_regex 4 create_filterhead $this t_fg 5 create_filterhead $this t_bg 6 create_filterhead $this t_font 7 create_filterhead $this t_u 8 # } foreach {k key} [array get f_key] { # set all filter lines if {0 eq $k} { 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 {"" eq $key} { continue } ;# invalid or disabled filter rules _dbx 4 " .$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 guitip_set $this.k$k $f_cmt($k) guitip_set $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 {0 eq $k} { 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_filtertext proc create_filtertable {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 # _dbx 2 "{$parent, $cmd}" 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 table [create_table $this [list t_key t_moder t_modee t_chars t_regex t_fg t_bg t_font t_u ]] # configure columns # TODO: -tooltipaddcommand, $table config -columns $titles $table columnconfigure 0 -width 10;# $table columnconfigure 7 -width 10;# # insert lines set row -1 foreach {k key} [array get f_key] { # set all filter lines if {0 eq $k} { 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_filtertable proc create_filtertab {parent cmd} { #? create tab with filter data _dbx 2 "{$parent, $cmd}" 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_filtertext $this $cmd].t catch { # silently ignore if systems has no fontchooser (i.e. Mac OS X) tk fontchooser config -command {create_selected [_get_text win_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 guitheme_set $parent.tkfont $cfg(gui-button) } pack [button $parent.tkcolor -command {create_selected [_get_text win_colour] [tk_chooseColor]} ] -side right guitheme_set $parent.tkcolor $cfg(gui-button) return }; # create_filtertab proc create_filterwin {} { #? create window with filter data # used for --gui-layout=tablet only _dbx 2 "{}" global myX set win [create_window [_get_text win_filter] $myX(geoF)] if {"" eq $win} { return } create_filtertab $win {FIL} return }; # create_filterwin proc create_filter {parent cmd} { #? create new window with filter commands for exec results; store widget in cfg(winF) _dbx 2 "{$parent, $cmd}" global cfg f_key f_bg f_fg f_cmt filter_bool myX 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 "[_get_text win_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 2 " 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 guitip_set $this.f.c [_get_tipp hideline] gui_set_readonly $this.f.c foreach {k key} [array get f_key] { if {0 eq $k} { 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 {"" ne $fg} { $this.x$key config -fg $fg } ;# Tk is picky .. if {"" ne $bg} { $this.x$key config -bg $bg } ;# empty colour not allowd guitip_set $this.x$key "[_get_tipp show_hide] $f_cmt($k)" } return }; # create_filter proc create_configtab {parent cmd} { #? create tab with config data _dbx 2 "{$parent, $cmd}" global cfg set this $parent.or pack [frame $this] -fill x -padx 5 -anchor w pack [label $this.l -text [_get_text gui_layout] -width 20] \ [radiobutton $this.s$cmd -variable cfg(gui-result) -value "text" -text "text" ] \ [radiobutton $this.t$cmd -variable cfg(gui-result) -value "table" -text "table"] \ -padx 5 -anchor w -side left guitip_set $this [_get_tipp "layout"] set this $parent.ob pack [frame $this] -fill x -padx 5 -anchor w pack [label $this.b -text [_get_text gui_button] -width 20] \ [radiobutton $this.j$cmd -variable cfg(gui-button) -value "text" -text "text" ] \ [radiobutton $this.i$cmd -variable cfg(gui-button) -value "image" -text "image"] \ -padx 5 -anchor w -side left guitip_set $this [_get_tipp "img_txt"] set this $parent.oc pack [frame $this] -fill x -padx 5 -anchor w pack [button $this.v$cmd -command "create_main tablet" -text [_get_text menu_mode]] \ -side left guitip_set $this [_get_btn_tip menu_mode] return }; # create_configtab proc create_configwin {} { #? create window with gui config data # used for --gui-layout=tablet only _dbx 2 "{}" global myX set win [create_window [_get_text win_config] $myX(geoC)] if {"" eq $win} { return } create_configtab $win {CFG} return }; # create_configwin proc create_tooltab {parent cmd} { #? create tab with tool config data _dbx 2 "{$parent, $cmd}" global cfg prg set this $parent.c pack [frame $this -relief sunken -borderwidth 1] -fill x -anchor w pack [label $this.t -relief flat -text "Self:"] -fill x -anchor w foreach var [list ME DIR O-Saft RC IMG] { set this $parent.cfg_$var pack [frame $this] -fill x -padx 5 -anchor w pack [label $this.l -text "cfg($var)" -width 15] \ [entry $this.e -textvariable cfg($var) -width 33] \ -padx 5 -anchor w -side left } set this $parent.r pack [frame $this -relief sunken -borderwidth 1] -fill x -anchor w pack [label $this.t -relief flat -text [_get_text cfg_regex]] -fill x -anchor w foreach var [list rexOPT-cfg rexOPT-help rexOUT-head rexOUT-int rexOUT-cmd rexOUT-hide rexOUT-show] { set this $parent.regex_$var pack [frame $this] -fill x -padx 5 -anchor w pack [label $this.l -text "prg($var)" -width 15] \ [entry $this.e -textvariable prg($var) -width 33] \ -padx 5 -anchor w -side left } # prg(Ocmd) prg(Oopt) set this $parent.p pack [frame $this -relief sunken -borderwidth 1] -fill x -anchor w pack [label $this.t -relief flat -text [_get_text cfg_progs]] -fill x -anchor w foreach var [list SAFT INIT PERL BROWSER TKPOD post] { set this $parent.progs_$var pack [frame $this] -fill x -padx 5 -anchor w pack [label $this.l -text "prg($var)" -width 15] \ [entry $this.e -textvariable prg($var) -width 33] \ -padx 5 -anchor w -side left } set this $parent.d pack [frame $this -relief sunken -borderwidth 1] -fill x -anchor w pack [label $this.t -relief flat -text [_get_text cfg_docker]] -fill x -anchor w foreach var [list docker-id docker-tag] { set this $parent.docker_$var pack [frame $this] -fill x -padx 5 -anchor w pack [label $this.l -text "prg($var)" -width 15] \ [entry $this.e -textvariable prg($var) -width 33] \ -padx 5 -anchor w -side left } guitip_set $this.e [_get_tipp docker-id] return }; # create_tooltab proc create_toolwin {} { #? create window with tool config data # used for --gui-layout=tablet only _dbx 2 "{}" global myX set win [create_window [_get_text win_tool] $myX(geoT)] if {"" eq $win} { return } create_tooltab $win {CFG} return }; # create_toolwin proc create_ciphers {} { #? create new window with Cipher Suites; store widget in cfg(winD) # SEE Cipher:text (in o-saft-man.pm) for expected data _dbx 2 "{}" global cfg myX if {[winfo exists $cfg(winD)]} { show_window $cfg(winD); return } set cfg(winD) [create_window [_get_text win_cipher] $myX(geoD)] set data [osaft_ciphers]] # extract column headers from data and convert data to array set head 1 set row "" set header "" set content "" foreach l [split $data "\r\n"] { if { [regexp {^\s*$} $l]} { continue } if { [regexp {^[=#]} $l]} { continue } set l [string trim $l] set l [regsub {\t\t} $l "\t"] ;# squeeze TABs set key [lindex [split $l "\t"] 0] set val [lindex [split $l "\t"] 1] if { [regexp {^0x} $key]} { if {0 < [llength $row]} { append content "$row\n" } if {0 >= [llength $header]} { set header [list "Hex Code" "Security" "Cipher Suite"] } else { set head 0 } set name [lindex [split $l "\t"] 2] set row [list $key $val $name] continue } if {0 < $head} { lappend header [regsub {\s*:\s*$} $key ""];# remove trailing spaces } lappend row $val } set table [create_table $cfg(winD) $header] $table columnconfigure 0 -width 14 ;# hex $table columnconfigure 1 -width 7 ;# sec $table columnconfigure 2 -width 30 ;# suite name $table columnconfigure 3 -width 30 ;# OpenSSL name $table columnconfigure 6 -width 7 ;# openssl $table columnconfigure 7 -width 7 ;# ssl $table columnconfigure 8 -width 8 ;# keyx $table columnconfigure 9 -width 7 ;# auth $table columnconfigure 10 -width 15 ;# enc foreach row [split $content "\n"] { $table insert end $row } return }; # create_ciphers proc create_about {} { #? create new window with About text; store widget in cfg(winA) # Show the text starting with #? from this file. _dbx 2 "{}" global cfg myX if {[winfo exists $cfg(winA)]} { show_window $cfg(winA); return } set cfg(winA) [create_window [_get_text win_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 {viewer sect} { #? create new window with complete help using external viewer # for advantages and disadvantages please see contrib/.o-saft.tcl _dbx 2 "{$viewer, $sect}" global cfg myX set pod $cfg(POD) if ![info exists $pod] { set pod "docs/$pod" } # TODO: does probably not working on Windows putv " exec {*}$viewer $pod -geo $myX(geoO) & " catch { exec {*}$viewer $pod -geo $myX(geoO) & } return }; # create_pod proc create_help {sect} { #? create new window with complete help text; store widget in cfg(winO) #? if sect is given, jump to this section _dbx 2 "{$sect}" global cfg myX prg search if {1==[info exists prg(TKPOD)]} { if {$prg(TKPOD) ne "O-Saft"} { # external viewer specified, use it ... create_pod $prg(TKPOD) $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 references 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 4 " 1. build help window" if {[winfo exists $cfg(winO)]} { # if there is a window, just jump to text wm deiconify $cfg(winO) set name [_str2obj [string trim $sect]] search_show $cfg(winO).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 4 " 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] \ -command {global search; set search(last) ""} ] \ [button $this.f1.helpreset -command "search_rset" ] \ [button $this.f1.help_help -command {global cfg; create_about; $cfg(winA).t see 84.0} ] \ -side left # TODO: remove hardcoded text position 84.0 in About # changing the search(mode) resets search(last) to ensure search execution $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) guitheme_set $this.f1.help_home $cfg(gui-button) guitheme_set $this.f1.help_prev $cfg(gui-button) guitheme_set $this.f1.help_next $cfg(gui-button) guitheme_set $this.f1.help_help $cfg(gui-button) guitheme_set $this.f1.helpreset $cfg(gui-button) guitip_set $this.f1.m [_get_tipp help_mode] guitip_set $this.f1.s [_get_tipp helpsearch] #guitip_set $this.f1.help.rset [_get_tipp helpreset] bind $this.f1.s " global search if {\$search(last) != \$search(text)} { lappend search(list) \$search(text); incr search(curr) }; search_text $txt \$search(text); " # FIXME (2020): all following code for markup needs to be redisigned, as # there are to many missing matches (mainly +CMD and --OPTION) and some # matches, which result in wrong markup (i.e. --OPTION in a header line) _dbx 4 " 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_0-9? '()=+,:.-]+$} 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 4 " 3. HEAD: $i\t$t" if {[regexp { - } $t]} { continue } ;# skip glossar lines 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 ;# gui_set_readonly $txt #_dbx 4 "TOC:[$txt get 1.0 end]" set nam [$txt search -regexp -nolinestop {^NAME$} 1.0]; # only new insert TOC if {"" eq $nam} { _dbx 4 " 3. no text available" ;# avoid Tcl errors return } _dbx 4 " 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 " 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 4 " 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-$i $a "$a + $e c" $txt tag bind HELP-REF-$i "search_show $txt {HELP-HEAD-$name}" } _dbx 4 " 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] # NOTE: above RegEx does not match +CMD or --OPTION if they are not # prefixed with at least two spaces (reason unknown). #dbx# puts "4. $anf\n$end" # 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 following 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 # allow spaces. # FIXME: # _dbx "############### {\n[$txt get 0.0 end]\n############### }\n" set i 0 foreach a $anf { set line_nr [regsub {[.][0-9]*} $a ""] ;# get line number from $a set line_txt [$txt get $line_nr.1 $line_nr.end];# get full text in the line 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 r [regsub {[)]} $r {\\)}]; # need to escape ) set name [_str2obj [string trim $t]] _dbx 4 " 5. LNK: $i\tHELP-LNK-$name\t$t" if {[regexp {^\s*[+|-]} $line_txt] && [regexp -lineanchor "\\s\\s+$r$" $l]} { # 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 4 " 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 4 " 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 4 " 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 4 " 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 4 " 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 4 " 9. MARK: [$txt mark names]" #_dbx 8 " 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 8 " $tag [llength [$txt tag ranges $tag]]:\t[$txt tag ranges $tag]" _dbx 8 " TAG\t\t(start, end)\ttagged text" _dbx 8 " #---------------+---------------+------------------------" foreach {k l} [$txt tag ranges $tag] { set t [$txt get $k $l] # TODO: set rex "cipher"; if {[regexp $rex $t]} { _dbx 4 " $tag:\t($k, $l)\t»$t«" } _dbx 8 " $tag:\t($k, $l)\t»$t«" } _dbx 8 " #---------------+---------------+------------------------" } bind $txt "search_view $txt %K" #bind $txt "search_view $txt %D" ;# done automatically set cfg(winO) $this if {$sect ne ""} { set name [_str2obj [string trim $sect]] search_show $cfg(winO).t "HELP-HEAD-$name" } return }; # create_help proc create_note {parent title} { #? create notebook TAB; returns widget _dbx 2 "{$parent, »$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 layout cmd content} { #? create new TAB in .note and set focus for it; returns text widget in TAB _dbx 2 "{$parent, $layout, $cmd, ...}" _dbx 4 " content=»$content«" global cfg set tab [create_note $parent "($cfg(EXEC)) $cmd"] switch $layout { text { set w [create_resulttext $tab $content].t } table { set w [create_resulttable $tab $content].t } } # ugly hardcoded .t from .note pack [button $tab.saveresult -command "osaft_save $w {TAB} $cfg(EXEC)"] \ [button $tab.ttyresult -command "osaft_save $w {TTY} $cfg(EXEC)" ] \ [button $tab.filter -command "create_filter $w $cmd" ] \ -side left pack [button $tab.closetab -command "destroy $tab"] -side right set cfg(objT) $tab.ttyresult guitheme_set $tab.closetab $cfg(gui-button) guitheme_set $tab.saveresult $cfg(gui-button) guitheme_set $tab.ttyresult $cfg(gui-button) guitheme_set $tab.filter $cfg(gui-button) $cfg(objN) select $tab return $w }; # create_tab proc create_cmd {parent title} { #? create button to run O-Saft command; returns widget _dbx 2 "{$parent, »$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 guitheme_set $this $cfg(gui-button) return $this }; # create_cmd proc create_opt {parent title} { #? create checkbutton for O-Saft options; returns widget _dbx 2 "{$parent, »$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 guitip_set $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 2 "{$parent, »$title« $cmd}" global cfg myX prg set this $parent set win $this set max 2 ;# OPT: 3 columns 0..2; CMD: 4 columns switch $cmd { "CMD" { set data $cfg(CMDS); incr max } "OPT" { set data $cfg(OPTS) } default { pwarn "create_win called with wrong command »$cmd«"; return } } # 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 last_key "";# remember last option set last_obj "";# remember last entry widget set values {};# collected values of last option 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 4 " create window: $win »$dat«" set dat [string toupper [string trim $dat ] 0 0] set win [create_window $dat ""] if {"" eq $win} { return } ;# do nothing, even no: show_window $this set this $win.g frame $this ;# frame for grid continue } if {1==$skip} { continue } #dbx# puts "DATA $dat" # skipped general if {"" eq $dat} { 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 4 " verify: »$dat«\t$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 {0==[regexp {=} $dat]} { #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 ;# --idx=val --> --idx val if {$last_key eq $idx} { lappend values $val; continue };# ignore repeated options, but keep value if {[winfo exists $last_obj]} { set txt "" if {[llength $values] > 0} { set txt [join $values { | }] } guitip_set $last_obj "[_get_tipp possible_values] $txt";# $tip may containing collected values } _dbx 4 " create: »$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 set last_obj $this.$name.e set last_key $idx set values {} 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 guitip_set $this.$name "$tip" ;# $tip may be empty, i.e. for options # TODO: create tooltip with $values for very last $this.$name.e } 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 rows [expr $cnt / [expr $max + 1]] _dbx 2 " 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 } return }; # 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" _dbx 2 "{$parent, $cmd}" global cfg prg set data $cfg(OPTS) _dbx 4 " gui-layout=$cfg(gui-layout)" 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 } default { pwarn "create_buttons called with wrong command »$cmd«"; return } } if {"tablet" ne $cfg(gui-layout)} { set txt [_get_tipp "tab$cmd"] ;# tabCMD and tabOPT pack [label $parent.o$cmd -text $txt ] -fill x -padx 5 -anchor w -side top } #_dbx 4 "$data" foreach l [split $data "\r\n"] { set txt [string trim $l] if {0==[regexp $prg(rexOUT-cmd) $txt]} { continue } ;# buttons for Commands and Options only if {0!=[regexp $prg(rexOUT-hide) $txt]} { continue } ;# we do not support these options in the GUI # skipped general if {"" eq $txt} { 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 4 " $name {$txt}" if {"tablet" eq $cfg(gui-layout)} { $parent add command -label $dat -command "create_win .$name {$txt} $cmd" } else { 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 guitheme_set $this.help_me $cfg(gui-button) guitip_set $this.b [_get_tipp settings] # argh, some command sections are missing in HELP, then disable help button if {1==[regexp $prg(rexOUT-show) $txt]} { $this.help_me config -state disable } } } return $parent }; # create_buttons proc create_main_menu {parent w} { #? create frame with main menu, quick commands and quick options menu # used for --gui-layout=tablet only #. +---------------------------------------------------------------+ #. | ☰ Cmd Opt | #. +---------------------------------------------------------------+ # ☰ Cmd Opt are Tcl menus # _dbx 2 "{$parent, $w}" global cfg prg myX set menu_type menubar ;# FIXME: not yet implemented due to improper widget names set menu_type normal # on Mac OS X not yet used: .menubar.apple .menubar.window .menubar.help switch $menu_type { menubar { set w "" ; set packman pack } normal { set w $parent.$w ; set packman grid; pack [frame $w -bg black ] -fill x -expand yes lappend cfg(guiwidgets) $w ;# important! needs to be removed too } } # create menu line with button for: Menu, Commands and Options set w_menu $w.main.m set w_cmds $w.cmds.m set w_opts $w.opts.m set w_conf $w.conf.m lappend cfg(guimenus) $w_menu $w_cmds $w_opts $packman \ [menubutton $w.main -text [_get_text menu_menu] -menu $w_menu -bg black -fg [_get_color menu_menu] -borderwidth 0] \ [menubutton $w.cmds -text [_get_text menu_cmd ] -menu $w_cmds -bg black -fg [_get_color menu_cmd ] -borderwidth 0 -width 5] \ [menubutton $w.opts -text [_get_text menu_opt ] -menu $w_opts -bg black -fg [_get_color menu_opt ] -borderwidth 0 -width 5] \ [menubutton $w.conf -text [_get_text menu_cfg ] -menu $w_conf -bg black -fg [_get_color menu_cfg ] -borderwidth 0 -width 5] guitip_set $w.main [_get_tipp menu_menu] guitip_set $w.cmds [_get_tipp menu_cmd ] guitip_set $w.opts [_get_tipp menu_opt ] guitip_set $w.conf [_get_tipp menu_cfg ] # create ☰ menu menu $w_menu -type $menu_type ;# complete menu $w_menu add cascade -label [_get_text menu_cmds] -menu $w_menu.commands $w_menu add cascade -label [_get_text menu_opts] -menu $w_menu.options $w_menu add cascade -label [_get_text menu_conf] -menu $w_menu.configs $w_menu add command -label [_get_text menu_load] -command "osaft_load {_LOAD}" $w_menu add separator $w_menu add command -label [_get_text menu_uber] -command "create_about" $w_menu add command -label [_get_text menu_list] -command "create_ciphers" $w_menu add command -label [_get_text menu_help] -command "create_help {}" $w_menu add command -label [_get_text menu_exit] -command "exit" # create Opt menu menu $w_opts -type $menu_type foreach opt $prg(Oopt) { $w_opts add checkbutton -label $opt -variable cfg($opt) -indicatoron yes } # create Cmd menu menu $w_cmds -type $menu_type foreach cmd "Start $prg(Ocmd)" { $w_cmds add command -label $cmd -command "osaft_exec $w.fc $cmd" } # create Config menu menu $w_conf -type $menu_type $w_conf add command -label [_get_text menu_filt] -command "create_filterwin" $w_conf add command -label [_get_text menu_conf] -command "create_configwin" if {0<$cfg(DEBUG)} { $w_conf add command -label [_get_text menu_prog] -command "create_toolwin" } $w_conf add command -label [_get_text menu_mode] -command "create_main classic" $w_conf clone $w_menu.configs # create submenus for ☰ , Cmd and Opt menu menu $w_menu.commands ;# All Commands menu create_buttons $w_menu.commands {CMD} $w_menu.commands clone $w_cmds.cmds $w_cmds add cascade -label [_get_text menu_cmds] -menu $w_cmds.cmds menu $w_menu.options ;# All Options menu create_buttons $w_menu.options {OPT} $w_menu.options add separator $w_menu.options add command -label [_get_text menu_rsave] -command {osaft_save "CFG" 0} $w_menu.options add command -label [_get_text menu_reset] -command {osaft_reset; osaft_init;} $w_menu.options clone $w_opts.opts $w_opts add cascade -label [_get_text menu_opts] -menu $w_opts.opts # {1==$cfg(docker)} if {[regexp {\-docker$} $prg(SAFT)]} { # TODO: add to options tab, see create_main_quick_options() set cmd "docker_status" # TODO: pack [entry $w.dockerid -textvariable prg(docker-id) -width 12] -anchor w # TODO: guitip_set $w.dockerid [_get_tipp docker-id] } # FIXME: menus are shown "tearoff" at position 0+0 # FIXME: binding must not be at entry widget # hence disabled # bind . "$w_menu invoke 0" # bind . "$w_cmds invoke 0" # bind . "$w_opts invoke 0" # bind . "$w_conf invoke 0" return $w.main }; # create_main_menu proc create_main_host_entries {parent w} { #? create host entries in main window # add hosts from command-line; line with + and - or ! button _dbx 2 "{$parent, $w}" global cfg hosts set w $parent.$w pack [frame ${w}_1] ;# create dummy frame to keep create_host() happy lappend cfg(guiwidgets) ${w}_1 ;# required in remove_main() foreach {i host} [array get hosts] { # display hosts if {5 < $i} { pwarn "only 6 hosts possible; »$host« ignored"; continue } lappend cfg(guiwidgets) [create_host $w $i] } return $w }; # create_main_host_entries proc create_main_quick_buttons {parent w} { #? create command buttons for simple commands and help _dbx 2 "{$parent, $w}" global prg myX set w $parent.$w pack [frame $w] -fill x pack [button $w.cmdstart -command "osaft_exec $w.fc {Start}"] -side left -padx 11 foreach b $prg(Ocmd) { create_cmd $w $b } pack [button $w.loadresult -command "osaft_load {_LOAD}"] -side left -padx 11 pack [button $w.help -command "create_help {}"] -side right -padx $myX(padx) return $w }; # create_main_quick_buttons proc create_main_quick_options {parent w} { #? create option checkboxes for simple access _dbx 2 "{$parent, $w}" global prg set w $parent.$w pack [frame $w] -fill x pack [label $w.ol -text " "] -side left -padx 11 foreach b $prg(Oopt) { create_opt $w $b } if {[regexp {\-docker$} $prg(SAFT)]} { pack [entry $w.dockerid -textvariable prg(docker-id) -width 12] -anchor w guitip_set $w.dockerid [_get_tipp docker-id] } return $w }; # create_main_quick_options proc create_main_note {parent w} { #? create notebook object and set up Ctrl+Tab traversal # used for --gui-layout=classic (and version < 1.254 ) _dbx 2 "{$parent, $w}" global cfg set w $parent.$w set cfg(objN) $w ttk::notebook $w -padding 5 ttk::notebook::enableTraversal $w pack $w -fill both -expand 1 return $w }; # create_main_note proc create_main_tabs {parent w} { #? create notebook object and set up Ctrl+Tab traversal # used for --gui-layout=classic (and version < 1.254 ) _dbx 2 "{$parent, $w}" global cfg set w $parent.$w # create TABs: Command and Options set tab_cmds [create_note $w [_get_text win_cmds ]] set tab_opts [create_note $w [_get_text win_opts ]] set tab_filt [create_note $w [_get_text win_filter]] set tab_conf [create_note $w [_get_text win_config]] create_buttons $tab_cmds {CMD} ;# fill Commands pane create_buttons $tab_opts {OPT} ;# fill Options pane create_filtertab $tab_filt {FIL} ;# fill Filter pane create_configtab $tab_conf {CFG} ;# fill Config pane if {0<$cfg(DEBUG)} { set tab_tool [create_note $w [_get_text win_tool]] create_tooltab $tab_tool {PRG} ;# fill Settings 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 return $w }; # create_main_tabs proc create_main_status_line {parent w} { #? create status line _dbx 2 "{$parent, $w}" global cfg myX set w $parent.$w set cfg(objS) $w.t pack [frame $w -relief sunken -borderwidth 1] -fill x pack [text $w.t -relief flat -height $myX(maxS) -background [_get_color status] ] -fill x gui_set_readonly $cfg(objS) return $w }; # create_main_status_line proc create_main_exit_button {parent w} { #? create exit button _dbx 2 "{$parent, $w}" global cfg myX set w $parent.$w pack [frame $w] -fill x -side bottom pack [button $w.closeme -command {exit}] -side right -padx $myX(rpad) return $w }; # create_main_exit_button proc remove_main {} { #? destroy toplevel GUI, leave toplevel itself _dbx 2 "{}" global cfg foreach w $cfg(guiwidgets) { #if {[regexp {ft_} $w]} { } # frame for host #dbx# puts "catch {destroy $w}" catch {destroy $w} } set cfg(guiwidgets) {} return }; # remove_main proc create_main {layout} { #? create toplevel GUI, layout as classic or tablet; sets $cfg(gui-layout) _dbx 2 "{$layout}" putv " set layout = $layout" global cfg set cfg(gui-layout) $layout remove_main ;# does not harm set w "" switch $layout { tablet { lappend cfg(guiwidgets) [create_main_menu $w "menu" ] lappend cfg(guiwidgets) [create_main_host_entries $w ft ] lappend cfg(guiwidgets) [create_main_note $w note ] pack [label $w.lm -text [_get_tipp tabMENU]] lappend cfg(guiwidgets) $w.lm } classic { lappend cfg(guiwidgets) [create_main_host_entries $w ft ] lappend cfg(guiwidgets) [create_main_quick_buttons $w fc ] lappend cfg(guiwidgets) [create_main_quick_options $w fo ] lappend cfg(guiwidgets) [create_main_note $w note ] lappend cfg(guiwidgets) [create_main_tabs $w note ] lappend cfg(guiwidgets) [create_main_exit_button $w fq ] guitheme_init $cfg(gui-button) ;# apply themes } } lappend cfg(guiwidgets) [create_main_status_line $w fl ] return $w }; # create_main proc search_view {w key} { #? scroll given text widget according key _dbx 2 "{$w, $key}" #dbx puts "search_view: {$w, $key} [$w yview]" # Up and Down are handled automatically, usually, but not always, grrrr switch $key { Home { $w see [$w index HELP-LNK-T.first] } Prior { $w yview scroll -1 pages } Up { $w yview scroll -1 units } Down { $w yview scroll 1 units } Next { $w yview scroll 1 pages } End { $w see [$w index HELP-HEAD-oAUTHOR.first] } } # FIXME: Home and End not working (reason Tk's default binding) # tested: "$w yview end", "$w yview scroll 1.0", "$w yview moveto 1.0", "$w see 1.0" # Home { $w yview scroll -99 pages } # End { $w yview scroll 99 pages } return }; # search_view proc search_show {w mark} { #? jump to mark in given text widget _dbx 2 "{$w, $mark}" catch { $w see [$w index $mark.first] } err if {"" eq $err} { # "see" sometimes places text to far on top, so we scroll up one line $w yview scroll -1 units } else { _dbx 4 " err = $err" } return }; # search_show proc search_mark {w see} { #? remove previous highlight, highlight at position see _dbx 2 "{$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 4 " 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) _dbx 2 "{$w, »$search_text«, $regex}" global search myX 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_resulttext $this ""].t #{ adjust window, quick&dirty create_window:title $this "[_get_text win_search_results] »$search_text«" create_window:nosave $this ;# no "Save" button needed here create_window:helpcmd $this {create_about; global cfg; $cfg(winA).t see 84.0} # redefine help button to show About and scroll to Help description #} $txt config -state normal #_dbx 4 " 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\"" guitip_set $txt "[_get_tipp helpclick]" # TAG-$i are never used again; new searches overwrite existing tags } gui_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 2 "{$w, $direction}" _dbx 4 " 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 {"" eq $see} { # 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's $w widget _dbx 2 "{$w, »$search_text«}" global search if {[regexp ^\\s*$ $search_text]} { return } ;# do not search for spaces if {"exact" ne $search(mode)} { if {[string length $search_text] < 4} { _message warning "Search pattern" [_get_text h_min4chars] return } } if {$search_text eq $search(last)} { search_next $w {+}; return } # new text to be searched, initialise ... set search(last) $search_text $w tag delete HELP-search-pos ;# tag which contains all matches _dbx 4 " 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} { set regex [regsub -all {([(|*)])} $regex {[\1]}] ;# some characters need to be escaped before building RegEx # 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 {([(|*)])} $regex {[\1]}] 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 } } {regex} { # RegEx fails, when some meta characters are uses as first or last # character, sanitised RegEx to avoid compiling RegEx # Note: Tcl is picky about character classes, need \\ inside [] set regex [regsub {^(\\)} $regex {\\\1}] ;# leading \ is bad set regex [regsub {^([|*+-])} $regex {[\1]}] ;# leading *|+ is bad set regex [regsub {([|])$} $regex {[\1]}] ;# trailing | is bad set regex [regsub {(\\)$} $regex {\\\1}] ;# trailing \ is bad } } if {"exact" ne $search(mode)} { # 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 4 " regex ($search(mode)) = $regex" # now handle common mistakes and set mode (switch) for Tcl's "text search" switch $search(mode) { {exact} { set rmode "-exact" } {smart} - {fuzzy} - {regex} { # simply catch compile errors using a similar call as for matching _dbx 4 " regex #$search(mode)# = $regex" set rmode "-regexp" set err "" catch { $w search -regexp -all -nocase -- $regex 1.0 } err if {[regexp {compile} $err]} { _message warning [_get_text h_badregex] $err return } # else { RegEx OK } } } _dbx 4 " regex sanitised= $regex" _dbx 4 " regex mode = $rmode" # ready to fire ... set anf [$w search $rmode -all -nocase -count end -- $regex 1.0] if {"" eq $anf} { # Show warning if no matches found. This could simply be accomplished # using Tcl/Tk's tk_messageBox like: # tk_messageBox -icon warning -title "Serach" -message "no matches" # but we don't want to bother the user to click a button to make this # message box disappear. Instead we use our own toplevel window with # following adaptions: # no "Save" button; "Help" button to show description for "Search" # finally, the window will be destroyed after a few seconds. global myX set warn [create_window "[_get_text h_nomatch] »$search_text«" $myX(geo-)] create_window:title $warn [_get_text win_search] create_window:nosave $warn ;# no "Save" button needed here create_window:helpcmd $warn {create_about; global cfg; $cfg(winA).t see 84.0} set auto_destroy_timeout wait after 6000 set auto_destroy_timeout killme vwait auto_destroy_timeout destroy $warn return } # 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 4 " HELP-search-pos tag: $a … $a + $e c" } set tags [$w tag ranges HELP-search-pos] _dbx 4 " 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 4 " 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_rset {} { #? reset/clear search list (history) _dbx 2 "{}" global search set search(curr) 0 set search(list) "" set search(last) "" set search(see) "" set search(text) "";# resets entry field return }; # search_rset proc search_list {direction} { #? get next or previous search text from search list (history) _dbx 2 "{$direction}" global search 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 4 " 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 _dbx 2 "{}" global cfg argv0 set qq {"} ;# dumm " if [catch { set fid [open $argv0 r]} err] { puts "**ERROR: $err"; exit 2 } # $rc_doc is used to define help text with the same syntax as used for this # file to avoid that it will be extracted with --help option, the text is # defined with a leading space in each line. # Note that the VERSION of the generated file is the same as the VERSION of # this file itself. set rc_doc "#? #? 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 must reside in the user's HOME directory or the directory #? where o-saft.tcl will be started. #? #? SYNTAX #? Content of this file must be valid Tcl syntax. Values may contain Tcl #? variables. #? #? VERSION #? @(#) .o-saft.tcl generated by 2.35 22/11/18 12:41:50 #? #? AUTHOR #? dooh, who is author of this file? cultural, ethical, discussion ... #? # -----------------------------------------------------------------------------" puts "#!/bin/cat [regsub -all -line {^ } $rc_doc ""] set cfg(RCSID) {1.7}; # initial SID, do not remove package require Tcl 8.5 set cfg(TITLE) {$cfg(TITLE)}" global cfg_colors cfg_texts cfg_tipps puts "\narray set cfg_color $qq" puts " DESC\t{$cfg_colors(DESC)}" foreach key [lsort [array names cfg_colors]] { if {[regexp ^DESC $key]} { continue } puts " $key\t{$cfg_colors($key)}" } puts "$qq;" puts "\narray set cfg_label $qq" puts " DESC\t{-- CONFIGURATION texts used at various places ---------------}" foreach key [lsort [array names cfg_texts]] { if {[regexp ^DESC $key]} { continue } puts " $key\t{$cfg_texts($key)}" } puts "$qq;" puts "\narray set cfg_tipp $qq" puts " DESC\t{$cfg_tipps(DESC)}" foreach key [lsort [array names cfg_tipps]] { if {[regexp ^DESC $key]} { continue } puts " $key\t{$cfg_tipps($key)}" } puts "$qq;" 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 {1==$skip} { continue } set l [regsub -all {\$0} $l $cfg(ICH)] puts $l } close $fid puts " #-----------------------------------------------------------------------------{ # Tcl's option command can be used here too, for example: # option add *Button.font Bold # option add *Label.font Bold # option add *Text.font mono # NOTE that setting other fonts may change the layout of the GUI, it may # only be necessary to adapt some sizes (see myX) too. # # set prg(option) 1 ;# set to 1 to avoid internal 'option add ...' commands # To avoid o-saft.tcl using its private settings, this variable must be # set to 1 #-----------------------------------------------------------------------------} "; return }; # osaft_write_rc proc osaft_write_opts {} { #? extract and print options from myself _dbx 2 "{}" global argv0 set fid [open $argv0 r] set txt [read $fid] # The goal here is to extract all known options of this tool. They are # found in __ main __ where there is a switch statement. All cases # there look like: # --opt1 - # --opt2 { # --opt3 { some tcl code # +opt { # --d=* { # If a line matches ^\s*[+-] it will be trimmed to remove leading and # trailing spaces, also all other saces are sqeezed to one space. Then # it can be split at spaces, which results in an array with the option # as first and - or { as second element. # The options --* and +* are ignored. # dummy line with }}}}} to keep Tcl parser happy foreach l [split $txt "\r\n"] { if {![regexp {^\s*[+-]} $l]} { continue } if { [regexp {^\s*[+-]-?[*]} $l]} { continue } set cols [split [regsub -all {\s+} [string trim $l] " "] " "] set col2 [lindex $cols 1] if { "\{" eq $col2 || "-" eq $col2 } { puts [lindex $cols 0] } } close $fid return }; # osaft_write_opts proc _get_data_filename {mode} { _dbx 2 "{$mode}" global cfg return "$cfg(docs-dir)/$cfg(O-Saft).$mode" ;# TODO: directory hardcoded }; # _get_data_filename proc osaft_write_docs {} { #? get documentation and help texts from o-saft.pl and store in file # see also "make doc.data" and "make static.docs" _dbx 2 "{}" global prg putv " exec {*}$prg(PERL) $prg(SAFT) [docker_args] --no-rc --help=gen-docs" catch { exec {*}$prg(PERL) $prg(SAFT) [docker_args] --no-rc --help=gen-docs } txt return }; # osaft_write_docs proc osaft_read_data {norc mode} { #? return configuration from prg(SAFT) or corresponding file # $mode denotes the type of configuration; it is also the file suffix, # example: mode = "--help=data" # reads: o-saft.pl.--help=data # or calls: o-saft.pl --help=data _dbx 2 "{$norc,$mode}" global cfg prg env set txt "" if {0==$cfg(docs-exe)} { set file [_get_data_filename $mode] if {![catch {open $file r} fid]} { set txt [read $fid] putv " read $file" close $fid lappend cfg(docs-files) $file return $txt } _dbx 4 " error=$fid; ignored" if {"" ne $fid} { # open failed, file may not exist if {1==[info exists env(ANDROID_DATA)]} { _message warning "**WARNING: (osaft_read_data)" \ "no data available for »$mode« [_get_text gen_docs] " # AndroidWish cannot yet execute other programs :-(03/2022):- } } # else } putv " exec {*}$prg(PERL) $prg(SAFT) [docker_args] $norc $mode" catch { exec {*}$prg(PERL) $prg(SAFT) [docker_args] $norc $mode } txt return $txt }; # osaft_read_data proc osaft_about {mode} { #? extract description from myself; returns text _dbx 2 "{$mode}" global arrv argv0 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_ciphers {} { #? get description of cipher suites from o-saft.pl; returns text _dbx 2 "{}" set help [osaft_read_data "" "--help=ciphers-text"] # convert to tabular data return $help }; # osaft_ciphers proc osaft_help {} { #? get help from o-saft.pl --help (for use in own help window) _dbx 2 "{}" global cfg prg # get information from O-Saft; it's a performance penulty, but simple ;-) set help [osaft_read_data "" "--help"] if {5 > [llength [split $help "\n"]]} { _dbx 2 " help = »$help«" # 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 # FIXME: workaround does not work with --docker set prg(SAFT) [file join "." $prg(SAFT)];# try current directory also set help [osaft_read_data --no-rc "--help"] } _dbx 4 " 1. collect more documentations with --help=*" set info "" foreach mode $cfg(docs-help) { if {{--help} eq $mode} { continue } ;# already read set txt "" set txt [osaft_read_data --no-rc $mode] if {2 < [llength [split $txt "\n"]]} { set txt [regsub -all {[&]} $txt {\\&}] ;# avoid interpretation by regexp set txt [regsub -all {^= [^\n]*} $txt {}] ;# remove header line, the very first one set txt [regsub -all {\n= [^\n]*} $txt {}] ;# remove header lines set txt [regsub -all {\n=---[^\n]*} $txt {}] ;# remove header lines # add section header, hardcoded (stolen from o-saft-man.pm) # these sections have special formatting, which will be more pretty # printed here: # - remove empty lines # - ident lines # - add + prefx for commands set key [regsub {[-]-help=} $mode {}] ;# simplify match switch $key { {alias} { set head "Aliases for commands and options" # expected lines like: # -t --starttls # testssl.sh set txt [regsub -all -line {\n} $txt "\n "] } {data} { set head "Available commands for informations" # expected line like: # before - Certificate valid since set txt [regsub -all -line {^\s*\n} $txt {}] ;# remove empty lines set txt [regsub {^(\s*)} $txt {\1 +}] ;# pretty print first line set txt [regsub -all -line {(\n)(\s*)} $txt {\1 \2+}] # each key (left) is a command, hence add + } {checks} { set head "Available commands for checks" # expected line like: # breach - Connection is safe against BREACH attack set txt [regsub {^(\s*)} $txt {\1 +}] ;# pretty print first line set txt [regsub -all -line {(\n)(\s*)} $txt {\1 \2+}] # each key (left) is a command, hence add + } {regex} { set head "Regular expressions used internally" # expected line like: # 3DESorCBC3 - (?:3DES(?:[_-]EDE)[_-]CBC|DES[_-]CBC3) set txt [regsub -all -line {(\n)(\s*)([^ ]+)} $txt {\1\2'\3'}] } {rfc} { set head "List of RFCs 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" } default { pwarn "unknown parameter »$mode«; ignored"; continue; } } append info "\n\nINFO $head\n$txt" ;# initial TAB for $txt important } } _dbx 4 " 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 exe() _dbx 2 "{}" global exe guistatus_set "reset" foreach {idx val} [array get exe] { if {[regexp {^[^-]} $idx]} { continue };# want options only if {[string trim $val] eq "0"} { continue };# already ok if {[string trim $val] eq "1"} { set exe($idx]) 0 } else { set exe($idx]) "" } } return }; # osaft_reset proc osaft_init {} { #? set values from .o-saft.pl in cfg() _dbx 2 "{}" global cfg exe prg if {1==$cfg(docker)} { return };# skip in docker mode foreach l [split $cfg(.CFG) "\r\n"] { # data from .o-saft.pl, 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 4 " exe($idx) = »$val«" set exe($idx) $val } # now copy commands and options from command-line to $cfg foreach {idx val} [array get exe] { set cfg($idx) $val } return }; # osaft_init proc _get_table {tbl} { #? return all line from the text widget (table) $tbl, 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 from text widget $tbl to file; $nr used if $type == TAB # $type denotes type of data (TAB = results() or CFG = cfg()); $nr denotes entry _dbx 2 "{$tbl, $type, $nr}" global cfg exe prg results if {"TTY" eq $type} { # FIXME: following type of TAB needs to be identified individually, not globally switch $cfg(gui-result) { text { puts $results($nr) } table { puts [_get_table $tbl] } } return ;# ready } set title [$cfg(objN) tab $nr -text];# get TAB's title set suffix [regsub -all {\s*\([0-9]*\)\s*} $title {}] ;# remove (index) set suffix [regsub -all {[^a-zA-Z0-9_+-]} $suffix {_}];# sanitise for filename if {$type eq "TAB"} { set name [tk_getSaveFile {*}$cfg(confirm) -title "$cfg(TITLE): [_get_tipp saveresult]" -initialfile "$prg(SAFT)--$suffix.log"] if {$name eq ""} { return } set fid [open $name w] switch $cfg(gui-result) { text { puts $fid $results($nr) } table { puts $fid [_get_table $tbl] } } } if {"CFG" eq $type} { 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 exe] { # 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 {"" ne $val} { puts $fid "$idx=$val" } } } } _dbx 4 " file = $name" close $fid guistatus_set "TAB »$title« saved to $name" putv " saved $name " return }; # osaft_save proc osaft_load {cmd} { #? load results from file and create a new TAB for it _dbx 2 "{$cmd}" global cfg results set name $cmd switch $cmd { _LOAD { set name [tk_getOpenFile -title "$cfg(TITLE): [_get_tipp loadresult]"] } STDIN { set fid stdin } } if {"" eq $name} { return } guicursor_set watch incr cfg(EXEC) if {"STDIN" ne $name} { set fid [open $name r] } set results($cfg(EXEC)) [read $fid] if {"STDIN" ne $name} { close $fid } set w [create_tab $cfg(objN) $cfg(gui-result) [file tail $name] $results($cfg(EXEC))] apply_filter $w $cfg(gui-result) $name ;# text placed in pane, now do some markup # TODO: filter may fail (return Tcl error) as data is not known to be table or text #puts $fid $results($nr) guistatus_set "loaded file: $name" putv " loaded $name " guicursor_set {} return }; # osaft_load proc osaft_exec {parent cmd} { #? run $prg(SAFT) with given command; write result to global $osaft # $parent is a dummy here _dbx 2 "{$cmd}" global cfg hosts prg results guicursor_set watch guistatus_set "#{ $cmd" set do {} ;# must be set to avoid tcl error set opt {} ;# .. set targets {} ;# .. if {1==$cfg(docker)} { # pass image ID to Docker; # note that this option must be before o-saft.pl commands or options # TODO: docker_args() benutzen lappend do "-id=$prg(docker-id)" lappend do "-tag=$prg(docker-tag)" } if {"Start" eq $cmd} { 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 {"0" eq $val} { continue } ;# unset # FIXME: cannot use 0 as value --x=0 if {"1" eq $val} { lappend opt $idx; continue } if {"" ne $val} { lappend opt "$idx=$val" } } foreach {i host} [array get hosts] { # collect hosts if {[string trim $host] eq ""} { continue };# skip empty entries lappend targets $host } # check for some special docker commands;# TODO: quick&dirty if {"docker_status" eq $cmd} { # 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]]} { set execcmd [list exec {*}$prg(PERL) $prg(SAFT) {*}$opt {*}$do {*}$targets]; # Tcl >= 8.5 # Microsoft 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 # synchronised, 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 } # sanitise $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 {} incr cfg(EXEC) set result "" set status 0 guistatus_set "$exectxt" putv " $execcmd " if {[catch { {*}$execcmd } result errors]} { # exited abnormaly, get status and sanitise 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 4 " 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 results($cfg(EXEC)) "\n$exectxt\n\n$result\n" ;# store result for later use set _layout $cfg(gui-result) if {[regexp {[+]version$} $cmd]} { set _layout "text" };# no table data (only 2 columns) if {"docker_status" eq $cmd} { set _layout "text" };# don't need table here set txt [create_tab $cfg(objN) $_layout $cmd $results($cfg(EXEC))] apply_filter $txt $_layout $cmd ;# text placed in pane, now do some markup destroy $cfg(winF) ;# workaround, see FIXME in create_filtertab guistatus_set "#} $do done (status=$status)." ;# status not yet used ... guicursor_set {} return }; # osaft_exec proc config_read {} { #? read configuration RC-file and IMG-file _dbx 2 "{}" global cfg prg env # 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)] putv " source $rcfile" if {[file isfile $rcfile]} { catch { source $rcfile } error_txt } update_cfg ;# update configuration as needed # read $cfg(IMG) ;# must be read before any widget is created read_images $cfg(gui-button) ;# more precisely: before first use of guitheme_set return }; # config_read proc config_data {} { #? get data for commands, options and help from $prg(SAFT) _dbx 2 "{}" global cfg prg # read (get) data from prg(SAFT) # 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 norc "" ;# may be --no-rc if necessary set cfg(HELP) [osaft_help] ;# calls also: $prg(SAFT) +help set cfg(OPTS) [osaft_read_data $norc "--help=opts"] set cfg(CMDS) [osaft_read_data $norc "--help=commands"] 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 _message error "**ERROR: $prg(SAFT) failed" \ "$prg(SAFT) did not return list of commands ---- $cfg(CMDS) ---- " if {0==$cfg(testtcl)} { exit 2 } } return }; # config_data proc config_print {} { #? print debug information _dbx 2 "{}" global argv0 argv env cfg prg myX hosts # some platforms are picky (i.e. Android's AndroWish)-: global tcl_patchLevel global tcl_platform global tcl_library global tcl_rcFileName global tk_library global tk_patchLevel global tk_strictMotif if {"console" eq [info commands console]} { console show } ;# windows hack # cfg(RCSID) set in RC-file set rc "not found"; if {1 == [info exists cfg(RCSID)]} { set rc "found" } set ini "not found"; if {"" ne $cfg(.CFG)} { set ini "found" } set tip "not used"; if {0 == $cfg(gui-tip) } { set tip "used" } set geo ""; if {1 == [info exists geometry]} { set geo "$geometry" } set wmf "<>" set max "<>" set tab "<>" set osv $tcl_platform(osVersion) set sid $cfg(SID) set str_make "<>" # SEE Make:OSAFT_MAKE (in Makefile.pod) # TODO: string should be STR_MAKEVAL from osaft.pm if {1==[info exists env(OSAFT_MAKE)]} { # avoid diff set osv $str_make set sid $str_make } if {1==$cfg(DEBUG)} { # use with --d only to avoid noisy output with "make test" set max [wm maxsize .] set wmf [wm frame .] ;# returns a pointer if {1==[info exists env(OSAFT_MAKE)]} { # avoid diff set wmf $str_make } } if {0<[string length $cfg(objN)]} { set tab [$cfg(objN) tabs] } #.CFG: $cfg(.CFG) # don't print, too much data # collect important environment set sys "env(...)" foreach var [list HOME SHELL USER DISPLAY LANG PATH ANDROID_DATA OSAFT_MAKE \ osaft_vm_build o_saft_docker_tag o_saft_docker_name] { set spaces "" set i [string length $var] while {$i < 10} { append spaces " "; incr i; } set val "" if {1==[info exists env($var)]} { set val $env($var) } append sys "\n | $var$spaces= $val" } set targets "" foreach {i host} [array get hosts] { set targets "$targets $host" } set tk_wm "" if {1==[info exists env(ANDROID_DATA)]} { # some platforms are picky (i.e. Android's AndroWish)-: set tk_wm "'Tk version' and 'WM frame' not shown on Android'" } else { set tk_wm "\ | rcFileName= $tcl_rcFileName Tk version = $tk_patchLevel | library = $tk_library | strictMotif= $tk_strictMotif WM frame = $wmf | maxsize = $max | geometry = [wm geometry .] | focusmodel= [wm focusmodel .] | system = [tk windowingsystem] | clipboard = $myX(buffer) | geometry = $geo " };# not Android #dbx# puts "CFG: [array names cfg]" #dbx# puts "EXE: [array names exe]" puts [regsub -all -lineanchor {^} " ICH self = $cfg(ICH) | SID = $sid | DIR = $cfg(DIR) | ME = $cfg(ME) | IMG = $cfg(IMG) | POD = $cfg(POD) | RC = $cfg(RC)\t$rc | CDIR, pwd = $cfg(CDIR) | O-Saft = $cfg(O-Saft) PRG $argv0 | INIT = $prg(INIT)\t$ini | post = $prg(post) | BROWSER = $prg(BROWSER) | PERL = $prg(PERL) | SAFT = $prg(SAFT) | TKPOD = $prg(TKPOD) | Ocmd = $prg(Ocmd) | Oopt = $prg(Oopt) ARG argv = $argv | targets = $targets | files = $cfg(files) CFG TITLE = $cfg(TITLE) | debug = $cfg(DEBUG) | trace = $cfg(TRACE) GUI tooltip = tooltip package\t$tip | gui-tip = $cfg(gui-tip) | gui-button= $cfg(gui-button) | gui-result= $cfg(gui-result) | gui-layout= $cfg(gui-layout) | docs-files= $cfg(docs-files) | menus = $cfg(guimenus) | tabs = $tab | tab count = $cfg(EXEC) SYS $sys TCL version = $tcl_patchLevel | library = $tcl_library | platform = $tcl_platform(platform) | os = $tcl_platform(os) | osVersion = $osv | byteOrder = $tcl_platform(byteOrder) | wordSize = $tcl_platform(wordSize) $tk_wm _/" "#\[$cfg(ICH)\]:"] ;# same prefix as in putv; dumm " # [tk windowingsystem] # we believe this is a window manager property return }; # config_print proc gui_init:prg {start} { # search browser, first matching will be used _dbx 2 "{}" global prg foreach bin " $start \ 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 4 " browser= $bin $binary" if {[string length $binary]} { set prg(BROWSER) $binary break } } # search PODviewer, first matching will be used foreach bin " $start $prg(TKPOD)" { if {"O-Saft" eq $bin} { continue } set binary [lindex [auto_execok $bin] 0] ;# search in $PATH _dbx 4 " viewer= $bin $binary" if {[string length $binary]} { set prg(TKPOD) $binary break } } return }; # gui_init:prg proc gui_init:cfg {} { # configure GUI according available packages _dbx 2 "{}" global cfg IMG if {[catch { package require tablelist } err]} { pwarn "'package tablelist' not found, probably 'tklib' missing; using text layout" set cfg(gui-result) {text} # cfg(gui-result) 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(gui-result) in the GUI later only affects creating # tables in the result tab after osaft_exec(), and will not harm # widgets or functionality created by create_filtertab(). } if {0==[regexp {::tk::icons::question} [image names]]} { unset IMG(help) } # reset if no icons there, forces text (see cfg_buttons) return }; # gui_init:cfg proc gui_init:geo {} { # configure according real size _dbx 2 "{}" global myX 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" } switch [tk windowingsystem] { {aqua} - {Aqua} { set myX(miny) 770 ;# because fonts are bigger by default } } set myX(geoS) "$myX(minx)x$myX(miny)" return }; # gui_init:geo proc gui_init:fonts {} { # configure fonts _dbx 2 "{}" global cfg prg font create osaftBold {*}[font config TkDefaultFont] -weight bold font create osaftHead {*}[font config TkFixedFont ] -weight bold font create osaftSlant {*}[font config TkFixedFont ] -slant italic font create osaftBig {*}[font config TkFixedFont] -size 9 if {0==$prg(option)} { # only if not done in RC-file option add *Button.font osaftBold ;# if we want buttons more exposed option add *Label.font osaftBold ;# .. option add *Text.font TkFixedFont; } # 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 4 " table font = $cfg(tfont)" return }; # gui_init:fonts proc gui_init:keys {} { #? initialise key bindings, see "Key Bindings" _dbx 2 "{}" bind . {clipboard get } bind . {clipboard clear ; clipboard append [selection get]} bind . {create_about } bind . {create_help {} } bind . {create_ciphers } bind . {create_toolwin } bind . {create_filterwin } bind . {create_configwin } bind . {create_help {} } bind . {exit} # exclude above bindings from entry widgets return }; # gui_init:keys proc gui_init {} { #? initialise GUI _dbx 2 "{}" gui_init:cfg global cfg argv 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]} { _message warning "(gui_init)" \ "using images for buttons is not recomended on Aqua systems" } else { set cfg(gui-button) "text";# text by default, because Aqua looks nice } } } gui_init:prg $__native gui_init:fonts gui_init:geo gui_init:keys return }; # gui_init proc gui_main {} { global argv0 argv env cfg prg myX hosts gui_init #| create toplevel window wm title . $cfg(TITLE) wm iconname . [string tolower $cfg(TITLE)] #wm geometry . $myX(geoS) ;# use only for small screens #| create toplevel GUI set w [create_main $cfg(gui-layout)] osaft_init ;# initialise options from .-osaft.pl (values shown in Options tab) #| load files, if any foreach f $cfg(files) { if {"STDIN"!=$f && ![file exists $f]} { continue } osaft_load $f } #| special test output if {0<$cfg(stdout)} { $cfg(objT) invoke ;# call button to save on STDOUT } #| some verbose output putv " hosts=[array size hosts]" set vm "" ;# check if inside docker if {1==[info exist env(osaft_vm_build)]} { set vm "($env(osaft_vm_build))" } if {1==$cfg(docker)} { set vm "(using $prg(SAFT))" } guistatus_set "$argv0 $vm $argv" # full path and all passed arguments; useful if started from .desktop file if {0 < ($cfg(VERB) + $cfg(DEBUG))} { config_print } # must be at end when window was created, otherwise wm data is missing or mis-leading #| GUI ready, initialise tracing if required if {0 < $cfg(TRACE)} { trace_buttons } return }; # gui_main #_____________________________________________________________________________ #_____________________________________________________________________ main __| set doit 0 # see ADDITIONAL SYNOPSIS above switch $cfg(ICH) { osaft--testtcl.tcl - o-saft--testtcl.tcl { set cfg(DEBUG) 97; set cfg(quit) 1; set cfg(testtcl) 1 } osaft--test-docs - o-saft--test-docs { set cfg(DEBUG) 98; } osaft--d.tcl - o-saft--d.tcl { set cfg(DEBUG) 1; } osaft--trace.tcl - o-saft--trace.tcl { set cfg(TRACE) 1; } };# switch cfg(ICH) #| main: arguments and options # for some options following variants are allowed: {^--?(PREFIX-?)?OPT=} # which is: -OPT=val -PREFIXOPT=val -PREFIX-OPT=val # --OPT=val --PREFIXOPT=val --PREFIX-OPT=val foreach arg $argv { switch -glob $arg { +VERSION { puts $cfg(VERSION); exit; } --version { puts $cfg(mySID); exit; } --h - --help { puts [osaft_about "HELP"]; exit; } --help=opts { osaft_write_opts; exit; } --rc { osaft_write_rc; exit; } --gen-docs { osaft_write_docs; exit; } --nodoc - --nodocs - --no-docs { set cfg(docs-exe) 1; } --post=* { set prg(post) $arg; } --pod* { set prg(TKPOD) "podviewer"; } --tkpod { set prg(TKPOD) "tkpod"; } --load=* { lappend cfg(files) [regsub {^--load=} $arg {}]; } --stdin { lappend cfg(files) "STDIN"; } options__for_runtime_behavior { set dumm "-----------"; } options__for_use_with_docker { set dumm "-----------"; } -docker - --docker { config_docker opt; } -id=* - -dockerid=* - -docker-id=* - --id=* - --dockerid=* - --docker-id=* { set prg(docker-id) [regsub {^--?(docker-?)?id=} $arg {}]; } -tag=* - -dockertag=* - -docker-tag=* - --tag=* - --dockertag=* - --docker-tag=* { set prg(docker-id) [regsub {^--?(docker-?)?tag=} $arg {}]; } options__for_GUI_behaviour { set dumm "-----------"; } --gui { } --tip - --gui-tip { set cfg(gui-tip) 1; } --img - --image - --gui-button=image { set cfg(gui-button) "image"; } --text - --gui-button=text { set cfg(gui-button) "text"; } --gui-result=text { set cfg(gui-result) "text" ; } --gui-result=table { set cfg(gui-result) "table"; } --gui-layout=note - --gui-layout=classic { set cfg(gui-layout) "classic"; } --gui-layout=tablet { set cfg(gui-layout) "tablet" ; } --gui-layout=window { set cfg(gui-layout) "window"; } options__for_debugging__only { set dumm "-----------"; } --dbx - --d { set cfg(DEBUG) 1; } --d=* { set cfg(DEBUG) [regsub {^--d=} $arg {}]; } --trace { set cfg(TRACE) 1; } --v { set cfg(VERB) 1; } options__for_testing__only { set dumm "-----------"; } +quit { set cfg(quit) 1; } --test=* { lappend cfg(files) [regsub {^--test=} $arg {}]; set cfg(stdout) 1; set cfg(quit) 1; } --test-tcl - --testtcl { set cfg(DEBUG) 97; set cfg(quit) 1; set cfg(testtcl) 1; } --test-docs { set cfg(DEBUG) 98; } --test-o-saft - --test-osaft - --testosaft { set cfg(DEBUG) 99; } options__passed_to_o-saft { set dumm "-----------"; } --* { set exe($arg) 1; } +* { set exe($arg) 1; set doit 1; } * { set hosts([array size hosts]) $arg; } default { pwarn "unknown parameter »$arg«; ignored" } } } if {0<$cfg(DEBUG)} { set cfg(VERB) 1; set myX(maxS) 10; } if {0<$cfg(TRACE)} { trace_commands; } if {0<$cfg(VERB)} { lappend prg(Ocmd) {+quit} {+version}; } if {0<$cfg(docker)} { lappend prg(Ocmd) {docker_status}; } if {98==$cfg(DEBUG)} { foreach mode $cfg(docs-help-all) { puts [_get_data_filename $mode]; }; exit; } #| read $cfg(RC) and $cfg(IMG), data from $prg(SAFT) config_read config_data #| special debug output if {99==$cfg(DEBUG)} { puts "$cfg(HELP)"; exit; } if {97==$cfg(DEBUG)} { config_print if {0<$cfg(testtcl)} { _message info "$cfg(ICH) --test-tcl" "click \[OK\] to exit" } exit } gui_main #| start main (event loop) if {1==$doit} { osaft_exec . "Start" };# call o-saft.pl if commands are given if {1==$cfg(quit)} { putv " exit"; exit } ;# special for testing with Makefile* O-Saft-22.11.22/o-saft.tgz000066400000000000000000112430101433765727300147740ustar00rootroot00000000000000[isƲg I?2wǮl+b,l$@"t;3^r}xE鞞iܙO{|7|<}n>Ns{Y7XB,=^Ӧ>D0U"a-?uH" |ՕLύ<3=K-?2F/΄`A/sf%_9)ќ魯y"8v1_@@!QP&$Ѧ}<0;9:y=( /xrpUU2&66,c?M% y P 3^Y` 9t?X|k/r9Q3YMcgɪք A:?a^-pQ^m[^Ȇ0[?ce#{ 4P,0ZLbA t{SBؐ 0d )D](5=~y%,ҞhS8]@@j!p;?:=LpYw)ޡJ))3"h _Ԋv)~x pa#+kc moI vbq~J0aiA09]l,F@F\zs x; T'ӟ/߽9D= ć? 2^'%|#Vfy:BzP6¤e҉xzŢ`cy4u;j_@$JLPe0eJAq-/L)Qr^Fi?Ke\h|/vg;Y+A n喜1GM)+] %Cr"!٢8Y{pzx‚<<[ye\(wDޙ%)W*/cF@ilsވ&xWX#n96 wڸ>(UZJ]УNePɜO>U3$Q:cX]ZTbEqjZLa h((ĺh+ͫQx?jT_;Ѿum7l|WtȘ*ջCoܴw^Z|]H T4FTl$}{5R&wqId)Z'x@6@kUYT^zWz}reHXMO?զ3y̕5AD>؀]a79R,$M*/LRV5T/.ӻjGu C-rM6m[u;%;̀XěqI$ںs#o}cٗ2nnC򡓣.ZTB44jFXvMwj5d X@2A4<'קVXqmeES>̴K]+ErjE)@eہv KUKJݢ'[oz*G/Ptx \}龜YR)K)O'#9%$*2Ƕb MўF ~ ^)ݭqI:w>߽}zzvhyi1RInNy[Eq>r#2T]'KR73%evzcDZ۽^߯RSCdr]aJ9+GL*tmQE;#,۴n nG( ./t6\5pN}}5(zpGڮ*?lS6A29Fզ^6rjZ ۮ¸X:2M!h19jfxlt|ve!='87B"5욘QCRH26^a J)0XV;H|m QLg`p* ԭOJjcu$N:Ea಺c*Ԣa YOy>E8:BٕkFM.IrL ?_Ii!CЃpA}0k86<֒kY nMyVO]d>_ a>fD 蠳+ÂwN#Z6 ÇƢkm,L!Ե6SK]kcOX"On|6kܩĀ6+?{r%n+bJ9]啮 5T%fA:u*~:z{g[Omn9|Et$\J+5o|]ۈ15%鹄Xw)R\b>+C*MB.l+[n s-^c vz.ӝ`Xf!/9fJb>s}{ht'6_Φ& &fƿ|h!CnS47EipTTcЋpؘv,4,>]({>k1AwsVuFfZhok¬mo?j%{wC3οop^mmڑ~lIs՘T7ʆˢHX܈̭M#zZs5 K*4_7:~S6y^\;|Z_,ݭLid/J&?4ns}͗DQϾ4 [-4 y5PV؀ sHSj Wè u` \G:L31,Q6Z/nDcDgORl-o|_u` 9:zAbV3%ZJ^ty_^հ揵OyEKNl oQ!j;N(Fo:գCK(,!STAr~zQ؀]3zG^Hww_J!RҊK:8[lVv]Vxݢ\Ȓ)T2EM)LYY2M/NNWDc/҅L \\2I!{N Zq;AuQ_B&ΝZ-yϯ򪂟%55N!=CbipX̝SA>Y7PI_:I<]ݩLn8_Mg+fU`v /eFCᇁ%2解GI#wgUl1ɚΘ^iDP]#d z&ː\zkqϺr,7T23f;?9R.~Um^jL`Kc7;eDDzWO>vrߦ>PRv-Oż VSy1yfCEFUW3%~tKۼƘ\[˟e<3ߝHSnarq%aW~~ SnbN\ ) @T`:~@Ƌ1"j9'HtKcG( <v"qV<1<W%Z#IgzPBRYFL[[5Ga&ŋܧbw6T귚-M.e3׏~|pKC3 ɟg"W Jxʼn@*SZtSʾ*|I;W8¹xR:357Ig\,ؔY rohpҤ,ڠ:C  9ռtK$rA }2JʀR~Zh8Unh^7rwK3R?Y4_pcaSժp[DV`熾Jo 9䵁r3Y#N7$rN܌6i.Eeje٪깦v5t޻d:K6w^aZ^#:z‡ٴ7gm`j4 |` ߀Yna( %iX#%Y*ts})}Cכh%ɑI&2eRo8>kz_B@Vxx\64QsB7:6By[jzxaNbᅄ!U$Z1/fdh [#m׸GG#d^0'J4b0^~@orVIIf_{&TVh0NA~O2F A8*Dx6GyEf3[uQx>4(p =m 偎׍P?v hZN'QZVÁ( QAe^v zN@anbۤɄ:,˸:g&πRu vZ:=yN%0~rswquQG|w_K*q-Z6zQY_W(OχZT3J3]C[\k0D>|*iW{9wM.Zg :n>B !ֹcsxd._y%ƢlMZCE/*vٴ'yJ|P[{,Z ^5Q*w@$ YJ0[Mwc{:ſuf»W9"c3ɕRL,|uW%/'J\V/Kw'G_쏏by%*JY&=RHr{-򇑫 X˼CT|ơqXYow,Dk`bpkHpݮar8-4^oPA cs's .=hVyv$IS11C1H`שrx{"A0jF?}d5GhQΦ֨K^-hB%~y*BDzYZB={Z) u:QFȵgy q+7FK :,h-藑 XGF[[m>]xNjpɶD3Z6CQxAK% KP!;TђdŜy/B|-!0T0+*|GA~ρSVɔT21䆃6{;~Q)~Y*V9~:??]V}2aݙ][$ 9Qsy2[R,ɗX8#q'&h5eB)/F~"}XjM&[ed &8 $& w Z^q @Đ CSZL!(f.;&~F> }L _XIo )kbGMI329+/®EJnu#9Ǘ/<5+JF )G&P#%?%*!$ڈsI ^H4~236UU9!8$'[LxGOy FΙ7ak/GDo%bȄj= ʪ[ @;#)ЈѿXX:9kP]dJM\ hk5VT_E5$Fj`)۷GտHmN10*J*e AC2o%)noFuG |ѣ'Q ל7L]ELm<]̖x^@A3Жy IAE RJ/A~R2wL6<f.MHU$]i ~ ؔ@;Ҕb#|v"F y\@3 df.sSo3bQXi 0XUVE<hѺdjY l#F> Hi[]Ӧ8iSlhew)NUiZ}<^8鬓UE էe>%M+Se43RnX$LZA& u^? 4bQF +jCx [)T<1^϶GJaA&qL7glL` ~gp\'bs\ڸ;V/ *vRT,+.Dxzog_ij2;k.g6@aM @* &f~l-Yg @|JޅC>qSYxAU[3za!  `+yw,.{+Z U偏7bk!;)GsJ0qciLUSvb6[mfuk櫌N$$ĈlVHWx{OM~/oWE`(U*4N/jh$k_R1߾DRtTM bRhp "C>3mR`W%8U nU}K |{V.A VU]T%%%EE!6Q8tu< Y't:CU n.A$;yPh%T'fL'2=]1t߂A, E?ݯ`xJ_,,4 } ΃- [ ~>V4~`gI.RS%7pW!焘(fAhaUx:KuE>Q=pI,EjUQe20 0Mg@1|Q #)!"nnSgJX seI8ۚK_LcLP߳0?yH<$O{G^ O vRraQcbPŘyAǘ؉Tzǜc=ɢ]qD=3gNBdoG峯F`2ͦQ l|k*@S;D|7=0BjQؑΧZv2#zPjj~b03JŘ|<BtkSG4-&%LJ/J܀ 0~MU.ָpbAmjɎY[ܣ`S51 -(gV -O4|/A&I$ ft@qonU^f@2[-`G ]'y2t[>?Fʼn3ΑZST}Nl:3Luk a bxcPZ FcQ1,`8V [GTy=F1 8@ڢ<\VF$5JbWQa@g("G&NB?[&-H{:{%@'ŋ֞=uyqnX`O V S`G,.h3@H:E!">MVK0<(CuTQa>*r@K h?:tTCC'T-+Lr`XN6l![#<3MuYFw,{+}U\gi|5kvE7Q%"ͱ>Ox2|!)Zy{INv\-u[nRux}2Ɗ'Fd;1}AΙ7 &4Rn-oqɮ`S)Q;-fI l 11g}Ѡ.O^1Є”0Q"Ń=;[N1]_8'iL=Pw{ b `~p&Nqƴav)e*ݿ'x `$nb][G'C^D_4z0 63 z~o70&>2M<~7_η,ixx ^3fSLks|>Go_^>*^ =8yyKWc=:aXjnmm{uz+DvO}>s67$:SD+_)YyT3t?ˀSNP)|UDk6x6䑀+Q\RZ(K!@f YvӁdT>y@Q841i"9Iğ"eJgN Zrɞ\O#Rr\Jb-ɯhe&]=W)pZwVݛ]^ES# ^w^p{ӗ]RYC>Yd[bR6aVAiW[TqJ$lpg ֪U,}|#v,FFhޝqWpP/y c[95 ޝIxVƬ}}_P-z%z~[鬘dg\!MwջP' >ϻɯg;tfηu Y)r!OVcdIjh@ea>63vuD2; xtO,g.hd>Xd@>\@}R{* نܴW)UGS\gLfPq<]jxbaX͇{gޢۅi>~$0I (<_dvҏ/,T\xZ=^ӑQF7w=yð:LR?)JOݒ?غ*eN4y& ]2GȤ&J[*TӁf(~|4N^IAdJòXq G,y'tC,m |0JK)TLoY #1}sbÃ6(}]Ne;0q' =g5Qg4vvst$,NxlЊ.¶(wZxb a$.C[X͒V i }πǀtt[F,*SO==C$chhG]D)^(yE3P6ڻIWUꍒz$TX+i1 "@-7q6T7-(کPi,1a6T5%#GbL+&>d4E%p;Q1+ٙvC.K'm:~ !dvٽ֘`ؿ̮~;ە?YZ9CՎOvWϞIAu TM( u5uN]( ے'+06İ#Q}5uk$ݮ_{cOގmR÷j%Q" ?Q=DZ8832Ϧ} 6qng d1[ؔ[;'08r{RwI)rR,[[* -{I6^n4n$b0hj={MR?#B*6@c9>j K{/w~:VtT ty2vvB0ip#&uj>Z/Q8:g< ,V8ۘcnѸbBc4W.1c?RpxQ2)v5,Kt<)/ˑ%JiF9ť3)"LI;@%vxu/e`sG1Zwi1vCt|t ]Qp $S5Q;IګDκt71͚5/ Mt&H+6ǘ{o51vpI0Z8pLGu4C ^l_.10Dތ&K+a>#,KC$A'@Q2Qb~=Q9HK N:/:''_O_v6Nս:'/w nHJˠ2Z搲 8Kyro{z31ݷ4lyR`|e\ls;LQ H  pq&0h ] l&cSt q/_RC!'ڈACsPU@<14I7:VOqjWB[%$em;t]kPʎXU3m)*5-䵁&7?H yx2eAalk:?DWQ@Cځ)ʢF <E*Ҷ.o>FhDmt<;i͠7i("G[C,uDٙwo:y]'5eHW5ga-nCNoY:| oZה#u3ݬIv$h` ֿ۫>j591بKfAb0Kܒ{wE&L6{^a4B-rx| GqQ q>!:[LU=S Hn}= t໇ؚt"̅=q=1,04:9Ji \Q3qg@iڀ78@F%^pG?.:mŠ4m σ뎊Q5yZ5g;9125jJ* b9OubQGjc& j0 a2 &pѕߒtZ&3cfHl7n챶t zR8'*delPOf2g4I(fV$￯ O(XH2BΥH S.Ť lW,ZM . v $hlg$ǬȀ/DiJEUX.f&2;m#M*M&-7sV̔?MgȣL"l Ay4bhJU1CcdrLT'XQ Z,V3=/24ӯVYјt?}ܝsh Ʌ*qVP1 ]Hf,UymQb0D MH+KG@Q{tֶ)լK9Xfӭfɓ'OBWBW*]5 x)"/LC@2x&xwtO-VdSd[\a/J24l7}*% X|f#&RVvG ?@NH7Fcz H6i=@Juz)?i$P s}^*|j!Փ,E\KK.Ѽ$T<&zAYEt"L3Y, KTn7&e%;{Xk1j5`s%9ML 1{TKn<&ʔƵw̬|FDeJ3GC6ID 咞|e*B}Aײ} bQtl|K P }:fS(YX 3Fãx_+F]ڍ2? Ǖ P0rp{>*` i|bK1&lA~k8| wv|#b`p|@L})z2QjԻ76G{)§#/%?v >2P|(\p Mw-J, fWkqpya;*HD=\ BȠ.eI30pA+wmVHI!=!fClnUHP؇OV>I ޶ Jds[:&>4NS Snx">Ԣƀrr fi43 M2D'&)ƥz 㛜2>k m'!uܧ+{J95v[@h皓*%t?ywjݠօJ* I eK _  aֳ{O\r XzQ(6vHM0 ͺO V;T8 )`} J=)&Tߩsj5,gkIDH$yS'lH??[[!|(F?"EM>CDf%!hffO[n1QAPd}yrevo|dXVaiea5ЃdN\ȦWH[ -Ԉ ‰=[3 *]yOSr:͔<34>$aY+HEp)wV*S`L6Q q6yS :Y״4X ?pԇz"9zv"ZY,fIW/l[5E7|:|n><:8aSbm԰+Þ2x:h$ =;܎%24u}>Ww^nژ7u~;s.kn*eX6֥BPˍ%Ysi937gq7I&[6c_v5 1Q瓔p$_=U0xtSB"< |IA.^0x4KvւhɴݙFOL \P/G'=%]+}KNcsؑ fdp.V뙔:|>8˭F& lD`<J^|.Nhxd:Zm->Lf BSM ] [vAQs'.4#J3S?d{N毾?<3+3G7)ݦswQ=1fX'Jo1<3Ὡ"c f26>"FGK&;tL3`ܲ15P`vMA"8邿8eI\nGr fe,+MЭ+gmtikr0_l?iٚ_l 4c4d\q0̑CӡnJW;-DCEF:B<:G}yK>M*7 U ?$jŲ2`4`=x<=OeM1?4!XF5tiB(-v$JbO="h1ߧTe+7j6Djhm\cxA= Fڸv=*<<ȫ~2Fch@Sh8KaI- Y@04sѭ(i$=zanЉMg6dT>Udx4.ڊKiM,o()[*5sYST:%2s$j#DzISV5 8 Kd66d!>IEtmc  z㮮]s6ʿ6I$qf 4iwTW 8Yd p[QTݯv7GFMqFkUo5=בh/B?z:ٵ4и wf3Ld h~r`t%QԹ4vטvʉxO2*% }Ǐ3"3eF ER[G!7ol_8] t86l3a,G8i&z-0Dz>V2ۅ̾CyL"~}!I!tŮݨ<ж#91aLvlNpbd+ɢL__<`+l9jz "|q'ŬK"8zͼh|µѹDž ᴏ(l" ܂BJf&*ю(R'{v@:O$p<?OL2Kgn+~Eֲ85UƟpS#u{A'E1yӐb`n-ye|@?W|\Y)d-Muթi*$*Ͳ㕣w& ĦKjt)L.U}D69j*0K-̯wxPLRi,hAs(h8lٰDi0 3ZBDbܶ= pN9$."j } +}g&gw}x2 ?`a@9bp(8:, UɆ2N fy=@:0EI4h֒#~UoR,ə+*^Bʮ*{gRZe I-Rt8N2Kmȇ;bVh%lݖ+8דVh o()ཾ8!8]i #pqE[<kG`ف~59b;`M+iG?p11eYmhPQ&T5oւ(-1%jgDo|w$թ OuVƮ(iZ,0SŻJ&im!5JAX g޲‚AivO 3ZD r^Rث +8L#N`UGàP^K%Wc`L]7Q$3綯\Azp7/!SH% U٦&}`Ҧ!zH7o79Oiǖ]~W Ax&}V0Y>4jꄸ]Vwʚվ+ˁffy:L1+ ;ㅷ&dq!P"U̝5{|jWoR;ȸL4zCN~z~bc%;F$eBk6:Fh( s l="i2WBm>'N=hp+x{Ub4P2W}ɱalh~3:Z?0~} zn>Zq72n5\7Z26$d@y*"1&.E)@7N iȰ¬efxZ2GqwtXaSw+`nV&UŲ_OzMK+._G5op…+n ''a tt֓qsRs$jU:=*m, Ԣzee8&`=jYS:݋pH@3e&:s[Z(cLI[(:ݴ7E곿l\ZOq)Y&6E$)`KR #x@Dm}ԻMA6KR!CW37NNsGvEO}|Go^#w޽8kT#B>ZRCtΆm;.XQY^ :2;@t:&L'ʼneB0PJF5QewVH IfZnOTfFše~P5}e|}6F'Y;@glAjPZhL8;<|gogDVU,ԝXc!N6ۇvO<䒉 Uco9vTv+himk+m~6f#z:W ٟ t>nڃ(CI"xD^d t1? 6=a,$U[o&C TH7koggzU/!:-!T4*p<:":\6jK «vW+ Oӿwdr3jN!;# ~Գ60{b '܎A8gs'[Jd+iwbWeam¸S6MYcow$ϧ!g:}FH>+okP`1IW)o'F;=Qem׾_NMx<eTu onsI=%G]%r aPZ0 5aNER!,b(LS#K :jHa#np-p/r9TKB31 E`AŢY^*bl] Χip{s_ڋaDF0l,܈LlS&`U!l-WŶ#gȓ>D$+nsj\HۓX ^1B֝vPdX6'=̃)>`"fdn )W8/fbews^8)-Ȑ.xfPmKѕ%J"kJ$b}%_p'3͚:4ZQ_$.<ۜ[ ?]&Z|6( > zxf[TT"6zp]0yz߭Hmܦﲫ &F]Fl:B(7F]cL`28Scjlr $0 `Bic9d!NM->3 x xs H$ 9F!|o?" IC$.C'ry},_ BJ)qկ5W)DTD)tH*WAR9 &Wm ~gPȞ]%ʍ,FPFtH&9\p'MrFTY[}=n㝅7;E?b6甹P\\^@ԉfuݢWJtx͞k}v=F5C.a|4 1tI~ױnP鄛Qc~"wVMIq%esaYRaj}ţ$\Q&1^lS&XGws wO0aEocqJ() 9rO16uΧ\  d P#>B'ȝ1FjL\.U{&?TV.Sa*1"tP'1qTu](ȍ pF<0+Sc\3!>UwdFblTI1mD98.:r緢6rpY&{,wyG*;Y,sxifn2`4Y학D/ عmϓijiK8 %턮Ce! b> `Ƒ̢ٜL_XMsonDlA5 ٦Nv^%i8 IOߊ˻m^ris{-!pNÙ_1yaùbnqԽ{KV^%j;!f|#X"a|vc6!HrQp 1K0t?&X)/Pce`E#T gqs' ÄohsJ'hpMCWRH#m-5G+nϽ6ǞL(R>)s-4WsgcCt0Ag$X=d_Fqn }27Dq*vWw'e X,gv:]46.&, R;~T3+\s1Ɗ̄D. {kD `Jw maո[A4]2ctx 7Ƽx(?JR$l9κrw5W#C_`Ti Kt{kkfvFzB3#G,5H,:k@Bso\Lz N3ȓx{("ҶcU[;b85F.is8ل ⛨;#_)h g щN[BWI-'RFq9/ZKEF.;[EAMp,<Ե =< Jf8.j^wl֠:c58 TPA%z>ٵFj, f! 볛NlIBM'n-oӴt4iAJE:=.TO|T2jiC [#  U==ʖq  g C睤?'#= ^R@:ޡX $\28Đa*e0RF7Ex5j^F#8W4uVL5-jݦj=a^>̫xlhޓ‹>勹aݿ W6tWo~Y|S}0`HnjgJQFida{Ѷ܇H| gv1&2C-kQ{t<,'CN \C 6m,o/S߮Kg[j|"E_x4Ûd:QJf̘tqGRC  -EX):JيG"դ;zEiOϥ|KSɣyt$|>3Z[O1 O}nzͭGRr ՞'PO3 '0E<h,1UKdVFARo ۼr384&%6~2A5ϧqr?cа#k:(vE )8;HY5K#:)a.YgP*w锋)ݪ}kz?2s5d\C65m -} DT  m/kVNJVAa;C)b  J]H*A[ -Sh$k1g\qBuON-E3?BNb>Gd5PgjYWoSXTMu*L"U1_(FWLa;N1N4}]vXFf.=~b4 754:U]sP0$xPӑ$=[;Z kP-dKh4Lߦk e7E6v3v\m_հ ;X-,1jISe2MZA; 1ղƤahV[lj!lug\L2DM/]vp-K|ZߝW<|usqH9jR8tIA=A>FDR}nUs7Tb8m?{ K|),3 bw p.Qre2"ko4 mDy8QO#BҽC;6[f9JYG$ERnxu{[{ZJk -E*Ũ88z^W&V+i^Kk~Vs빨mCvꘌ]|(0|-cLsMflrE*03qXBA5`w0iVTR<1 yh6&}OɊ׿U\D0dk8+\KhU| -_*ZiG6n|68Ro"cWT6?Y(UL2!tdgþ1\ Coyջق+&rڽ w *Jp==$jg/󆿥, `3UE^6RH TZ;6|tJ< п/VQ}ZuՏH*X .V>WsxtׂsB\ M,617+^/^;u8CbD)D xXZ>{}>QxD!E.jBO Q vh$'`Yڡi,u7FDh}w Z-2ω]`SD,6tH5yA~! L%:"/"gK.`iWCCXؓ_?XNvTtH~M>2ʆOdc(I(%;>ocs"}cC $sDOƨ@ lQR*\kI4qmTFz@I~\X2@譖7W}.Y<)zm*wlJ*fXL+RrT>4a3BSy=H]}L+P_Tjh5qsP||Cϝw7_4؃ Cz/͏x6s?s{C=gĞnhK`B h3[˜حNZb6"%hQ#R%cY͝Ձ `MSvg n 5C,Mn)wR9#4Y%:tBϱ8'4xatNIǴ[`{IYiٍRDx)0R~C`eʱ/23zgRpN7 &LSkh';Dw?>a>$J^EMfmq|1'-;܇9+p /‡G ;Ow{aV π#NyLU٢O{T_gX 7T^Nȋ^EjS[TvE->/uuVlwߴΩ#$ ǣMc_PM~t'A֠1ϕ]M8c"O@SKT2A->Zd`]zDzgt?yy?옘v3֐.7CXb9V2EaҾ"FqaSRqقCݓSgP U$Suj$}80ǻ?T/䝼^vC@{D؁wɘRM1058g,>!cPlT4߾:x}`m*VzqR Lk)Y3M&Aʼn釘1!I] DrX' ȫ崟4kbxzJ>9?Olcy*D|R"f7 "Je;}݄Bx>:mGLgM8jBK`@;QRKCѾ*c Dp.d=O}ҏZц~dAmVt,Ԅ|in~fD~7&Ť B~QD\ 8 , cDYuC F )hj0js%˻QFQ4D'LᾰnGOCتڣ Z{6ῖ:Z=~@X9Rцz68RlSEgj\6P"j zj&TRhmӧAV9`0a5 'MVsrfJ r,Dm bKWk6X: Sl*cs4=h+D1%rU.OJE+^Yp'M C [)ZXߨZ+ }`a¥# 8yEщpl`pc:pM)^=dIs݈,,r^zA*6!a*3-'Q&Ҳc9ݓV}YP0IU*%A?A&mbUgA_=yB20xlp~ӈ=%^~EjFmH.џW8I>-W_,`o5 " r4Uk@Y>w8U|hxɓJSHןEQ'PrkZ:AL1ͼ{l gL)D,qk&6tl{Txџ?pTpuW^̅YYt$_: [83.o=, 6Hb?cI*{ UkyߩO,CK%KY1r ӟb cpy3~ ?LXL%脳5*-JmyVk'{jI;O9V$T$)7>iYSu1i}:z?@OwE%/HԹLLGQLx:6>zKXj㒠ȼ/ԟL MZ%Dn4$Ɗ\%ZO!*MdĔ0 MV`zteu41bATN7nf³g{G5,gY{S:D#-ݛl%@1j㕥ĉd2ASN>75G{F]G5D\ |uVLd G̫ n=g1Z'C )%ӹl +{Y'3: ݙ:iTum,]:Md!!ZLYFi^tA(A\%deHLOΤ0U'G)hVP4z1l1x2E.ec@K@bMf6v㉨x}CJ ań60͸B#r5!.IA)SVE^?pG<O.1R&IF0Z rhROä=udd0i!.P2N_m$4O |'7b'M&$&'4Ě?bMt&Ӊ(H %PV&h~wn$I*Q|Nɣ>.o)Dlv0 d N[C_|S.D˸Dl9RN]B |l;أ $>;<q}`oet)MeQK'J X&-Kbxv{cABo(&FMAZ YYLjX׻%>>,qWDmT!޼+rBvM/.yy,\h}Vm&s*}?e[Dչ6nB #>ûoM˭3cQ)NwUX2m"ȗe4RHs~?7VF~?7~M!]vS{ڌ/F  di8{YUw{|z3M輵Y7x4o+*yv̖H֖ƌ&ИBS 1mtShSSqW+Hc̞LN1|=;3M'~9 #4KqxSSeGsլ=΄U >M]- +2[ 6f@%H"DxPv*(P~O'L^W?gIȿh5GV',~1vA`pe ¡VK;ky2P/3l :˘_#,ye\Ÿ#,#,KXGX%xn,g Vp<"ŗuFnJ|D"9y[XM怐=FUϜu&$fhnvB>w%N7G XGQaKVt{n?N35 NXkR6wuf^c@ۑc*IɩHP[m@@x|cl|Z}*.)1A(/;25ŗ'x(48Ee NAd!b;MKL8t9HbrubkbMR&]7%Xìh왠s c{e+U0 tdz.XpID]ߧf6Խe{.9 n1c ~] 'Z t8b*>G_g`|\j l&l|8=A{fGp%A̦/9 &G1p'<4zA։e3޺f beց]b RUHGyEϳt\րW* l2[#gnX(ֻ!|E]9+lV'zEg]~ۨ՛SOIGk_E! d$]3/;R^@*|#_C>2X۵ϲii͘jsP{y5kRN^Z{CPC Jok֛kI.[37)[߭;'*Uh centeM7)>f]It\09oi41qB;]%s6"K2{ZX \LSQ}<"5v:(d]/20ċIоoIK{Ym]mznn6?ml" hmt~9><=hg9|8۵CZ|8KewSJLj;fÄ'fOc`;/^zfW<4v;͠lWGA6Q]6 2%_NֆfKeDUhL gRLaxu6լ5jX6L ^kmxF-g~ "BIZ'S۬:-+S؉O6l'OӒQDt\l}Fsv[=(hg%_,PP`M ,iv]:/hzpC$6YGc7h'n*R[2_ ]?7gj5TEQňKb+ Qci0C UM8:{N[]HŻtdߖJRE/9fV4n1-`>Qg?FO+ m}:ZfOJ"#y Jwb*uBf\5U۔48P+ {rzw0\=I W䄅7\x(Cv1xJΤ{Y4_}.EsQP 1}I-:tqWgUh`ⱞ#}rli!cRZh{8vP#;~UQoNVظ lg`n)flH( 65D]ߑ!9Jr(I"kt>h=)Н9l2[-GG!XaҰ9j 1'4zn$@K?|ű`}Vw *]egt nW'坍E^dӵKCp ƻC%5Խ uܓe7k "oشseKC.s' %b;g3K[/:~tٔc3` ȹˡ=,ÓCE)l4(>F F)-*+>^mV^?b~6ߟ~j#Q|<9FTQ 0v=T2̼qނrI2$8G0!lUmOoր*u'`yztK}h{gOǍv9'Ǐ6O>.X! '?Vcsj|[~r?ttJLQvvtvZ%zSO+m36J̉p[tX,ӭB\r>'c!A ::S3r]p%9I?)}/>wC8. -=|hM0;蓛Q4MGwИ!|1iIUʿFzu|}4(4Qrb鎌ɕ9Gр>牮)|>f.%e&vlsBXHXi}m-5B` R7_>~|X^ |V%)'6?QR cvphVtdR$r?D.B{J@(;:ti&0A$}7>CՎI`Hh7wTC<8TOzZvlL&f%ԖŻrHcN5'%Kt-ngeoq-Pϐ/DRC|db^k;pD J*&BI{x/fξ4g䫧Ec ~=K*tQЖn\{*j'r݃q ֻc#e6L閆f&ŋwZkINHm欯eˬz4Z͟9D8|a&hC~Ș,P\2ˡ.D 0RۡvjuR :Mi2;ݻ:/75A}[+Ϣ- ՛䋵/`%ĴY:t 0ccfٟq$=|y`.n0˳Gm1'\c!v^v0gW|l#Vq3oFҌ<:_|a\v"BEaFtSrtYp@o6=/Ldt1Δ` 1z4'xInZ+8fEBSY݀Qnܔ_{LJ~ M GkbaxW G `,i({[HlkFR=70[e7Ft}g";Tˀ \`0VXPT{m{hLw\=RmbUĊ5I=m.xi?%&oiDctVtK#Ja1 $0mBETuqUĖQ6CZd\3 AFKd#,mp$x`?QEN"5sJ)?|!jGF=4ul<"oGRTMG$;@v- LCY#:~И'jh1DDaVۘRq-f@ȟGɗ*CpŽ [b͎˭iNt41`&xÏ a_ڬ _@eS?O0uгď'Mq2KV"HYmS4,Lpx ~O>tE.7]YhM>wHc~`Y1W ̛;Ҩ{)r"ƞ.#Y*wԊnk@tWvZ\SLQ" /5DIo}AKl\5j棈bhi*XBOg%/ۜ.pCs-1ӫ8Jy {͛j>(&D=:34`h6k -XyB풡13Z~!c`Ϙi '}mxS7#dtL< `C}Fqm#G82647x+A[&^%zgt90{8\^+E FdИ?Zi"} G:Wm ׮%!άO:a=CvbEc.G$h 5̾wż$hb7|vdm֓$qUe(wr hB@ % I:}lSZye@f5܇y+{k,`f xExtD)ZtZB1=,$ E9%$#TUq6std- >x3wlk Ȇ3ٶmu]z[h.jG`NcO@HӐ^kqƄ,mPyFGct e42?fKmg3YG=ԃV|\$q-E4?Ld99mY'˟PJEgGY9ۻ1[9_,;`E>߱Q1.O6~1؝#V\(j_.#Q%!]@;rEGve`998]Rl"A^P` #-& z oyc+D( N7] b~5A3G 6N5uN;WxfBz;iPT\.cASlV 8jUcGDZ\!.%y Y8};iHGJf{tp1FىDN]14r&v!Lb sZBrǙ#]j:Lb3y|Oϼs)zxV3nnG@2'?^*ALPy&tx8m2㻍^..0ᇛ4؁+ fθ=\[ PcK>vMK\@"b)HH#B@%E/}KU- lʆUD{E}_NulQ+g7=x4&hyҋϪ<߼=3 GF&+-\t%88O-ez~:WzApʢY-&LuD ˩w/WjrWkr2W LQѼAOiB7R)|(.Aʼ4]ʻUz~y/^z׮ 1Gչ0=Cfpw4'}s|1zFQg'(VuxÎ1u<(=pMY8i"@Qv?{励R@K;bf3څc0C\*A#/Vvr䰆\f-ژΜPÌ۔1k .`SЛma?z'0;^9Cg4(:P9%.ۥfےE~a.җFrcB.LʬLZjC9IJa"h`7ⱑuYNf YEGg̘AC2024ƺFfZfpy|5!d KRs+Sć4C^Yǥ s6~L;YZhv-}%< "'ouj=JD2CD) W*S;*K KSёrYm˩u` XqI3Hb[6xkLHumO@@LtVeO~zfg'U*̠v/wIQ~{I!X%|2/䢃_yexQLF'3dKqgU,tDaFTq0H%ԎF[~pCMQlt©i܄hI!HTgYlP]E^6+ f+Q@]ӧ٬U$H9,9:^Q8s6(^+,?87v(Ht [1,4Eז g 20#ƞ_DǓ±]uQa]ah>ꥦ$lnfww g /BL{mצLDL )Hyns.\U>G㽖nM9}qM`(hnrՃ,gryp;a+2?jM v8^qnExQO]&?^hBx)K#'vmC6Y(("ɬC7ޔexzRE<&&G)u@X-مuBh v:ORR5#znlom|̜D% ].U4b%z͓.qyY*|r-;BIѕ+J+@&XЦos`cpv4woMV LWRVg*na0M@>c%8%FyD I~bOgZm}~pP g{9hR쀺sǃ{2v ; %U)\cd7ɐ6q\1Lgb`<8F9X kD+5,f!4Cs}mEuOD JuD:!V 2y.Dఢtv-،`aX#<7qǜT@ -m9XwU2zM 'cD捍qC=t1rԸJջSu.]$)X;[o۸xiGtX ^G3 '`ӈoCm~=25!`;:bYFhϒF^m'ޓ^,dAAUx5,B6;*Hm L^4AEt6mzSQTIXh4^&@S)m )l`LU:3# jg4Y$)^45wLKp|0Γ[άf$ 8n0J1,p|%]f"SajYҾ]!ݤfڙ}X^[&YƱA6_ܖ2VŘ@+H6Ob4L|0z^/ 7BaxIe0V?z咳 BJd@2D|1kM`^} LQfSd a|l^+ERԍ۷[<"t"] BY#e gϴ)_K `?KL*sЬ:-R 9E=qI'}3Qdu3!Rv97hɕl%…mbQm4FgW"ҢVѣ>@Vc[:0%mm=rJ/)w$SXs/BAƒ{˃P֪=xJzlެK@X55ӊLFk3,`_@'Ɠ͊?׌XH#\ k`1ae9=ϥ=$ .)8=3ټc<X"d$ Nsb֣\#sKD D[(Vf}m:.J^[0^"phN:()߭A3'd|x,m#w9lG7Ӂ oT 1G a]i$"If`_l&: ^ְ*ֵ-oGO)DGn(l+p6?Q*Cy}FƸKX*ycm`]-hFvVr@Lx+)Zy / 2ek uO?#mPoO(]=u 1#mKlг;@ ߒ!tl8X8و/Xkt1f]l6 ?L~w:N3_quicJu: דi-v{+X0r$^ λi܌ nG&yUz"OQd'iMEwpV[{k]&9{kM7j0iZO/DEzG)Γ{BzDXtd>!ڝLaLG [GקNn+$ s6o.g;N>Y4[18qEm6|aң'^T86;N^4)4;U8gܞw^5P$7c>%x=cŐ(uYHoO(M^ljY%$QP› E=lF"9 uj$<3\(]T̑j 'D#`Qd#0km& zѤI?>,kZ93rwCfå&e %TZ׬΢(5ŠM6`gDSj& OY ppF2rB OҎLVE|0v @˔VQܱuB pƋ MaƍDE!`FNnKAsMvw5Jo^8i_;d1N̛< y$&\qݿwk퓵AVd(4gZlʤ\zk^(bGϸFpU@tgGr8fEm&T`]\YO1h(No aE8] aa\^뗕$S**4=n4>fV o68|q?`vNNx. DO1˷򝙽!s[pbLrWo*#msXqw-m#I%k"m.HҬBkی~S [ȓ67Kh;2&g Gk: Cf⇝\$ ƣ.okI'_4AnJ [*Q9ILU*H,I ;0W|jf7Ww+#25yd+I'&lcDKmIHxPOMIb')}Îhw9g |02Bv2,QgbWes" 9h.KƛU*2ៃ~`@LW K (10+^w?]Lu6oi+^g}XJ{YWG'LFήeh &!!&N0-HĔ#3Ib*KL-yC3FSmlL2??wQãLhk|W^so$ڃf(L&]=4h;Pܳnaz~BqH(ל:סÙMD|N:#>6~FO^a%)|B\gğҤR~Uqh|Ⱦ Vkz8#Gw16Ű?)PKDeʸOf_RxQ"߽b @9ҽ%dYc>FǝӖs[2тxurйUC'NѲN)8L)m8SI)+ U~9fڳIC;r3"d7Pcj -6ug'g{?.'ˠ!S$ٶW r+QT-qUd2JOyd/`A^W<0mT2F2ḞSF!/:fP.| زޜw'xF<'`c4o#eBRVZ"v`LTd4ɛCQt 75yqȮ7MJ8l/M"/~u>;c^(í؎S(ؒYjHMaqA0ɍ_!p: 87 ɸx+FaMxw 5f1c*(uW~ˏHAIYhB&wmi?S?%'棦z~}hDFq8CݫWuCU}xz[d9tuN7Lx3iH{F~׋{?87n)8Ow3Vtxz, NgXu1Z/>zq,Yү^F`VM̪Ѩ1KE5N|tQmn4fl;IV8z}݈9\*O+`SRhM -?|+ۼt*>wks2t Y`po~=yܐm8G~E\EͰz k[X뇜Z?,SkWHK$*u' 3.cR޷k]w+g:vۘg0'Zх( t,;KZ (DsqFQD0W!WJMu 1|u!PD޵sQQEN Y*dS~)d)oUex JPxIB>SI )69Ѱ}yLdr1E-@Ձ'NY5 x4aM(Ӑ=D( +lzm~V6zT%:e>^qmBhj[u7Tp']L3K&/їx_.Z r9~M}*H,ݿԗx'kZ8yۃvs:T.58B˕8 dy/$ikf9nۂN*tO3+v#M!/=Ƙ(LM9=4;YVJ`s>6%UO/_2՜Y@SN8<*sWĀ {%Z0I<njŶz}X&%#TPx`ɩ$w  r\ | 0[ I+IXG%v ⎮xH&rqg뷯^c͈&uףr->+utJHzMba((uRؔ)AjU-T Ιزb',fx`Fƀm*b8hwu'S[[͙C157=ݚvuSWY t.[`GzWW0{x (߁ 28b« ۼRc_q+\pm Nc#iGjGM-s"FJq1n@~OCeT-w ^j)9S]Xzٹ&N2 Ю bO\*VSx A_ QT3hE{MrA< "UwՉ2UsK.h 6/fNPMk?]ˏ^G%}>T |Sedps#; UO~ybI2ir&Ɔ(bZ+d&|2]eSg1-T'ykl!o*tdD?󨕩sfjO{S{q䪫Sj>RԂ/ 抽wLdN[ƢDj씢5mk${"ϕOmͤ?p}jWwUUc<(ϛ*<f ˏ|*ֈvbV93t烈rlȞ~R6k!Q87A)u14VVmFI5\I;&ZlI 0٘*R5}̰4lŮh~z}J@Q8Wְ^~e{8l' ekd"Cej&Q !0@@BF~ph]_Q2_i~F# HDT=4neȮ*L'\ ,f;tIs-?*N#IG$ 5CrclGC?9`c1>SANİha|Bl;$RqסCwoamc~ƴ2g5AZa!v1rr}ʾo||= $p 2iIFTƽbXUf7{5Z?[66k~׍- %@JfccEf5](M-S@PyPY9hk*EK7r1!#g3U8dimM)mj5fPP 3A-gU:QW~q{:DVK5E46rZ@ݛ*ުy~^ 4]$7FF% 5 ܩiՕD&dێyPs:/'ֆ#mBgє:g-(r)Cgbw?a%"u9B:@s&DI1clo )Bڋ5Gxԡ,I,M &JDTph$e8$ 4bߠ"^ |ρNe= Yě-No_}˃9X +܁5sam ϒS\/ۙfNN?;?qi(pI]].y0CLζK F5ܗF4fa8H) &8]z'ߜn4AXbDJ"n7[oeY{PƨK"2n}VЬC>exh9v`OԛeAU/^d)T%\e)X=ua!]ޤ:ώ:\2U:H5v)Npg0vyiNAOX:UdazQLPP?웻̓E+r<ى7"̳IN"16%h XEJ#ӻ IJwɄj&e50P'y[>Q 6s{m<·/pyYJwEK7 vm@{tz]LYDNf:h*[ju uP.$'x&Տu`}@vAZ$ϤA0wqR ;D~ۉ:ءɬ:;:QVNsJs*%D^}'mxi$-}Gxc^$~o`N#/6I5tvr?3GNxBwm:*]J'l2Dˁܿ]h><ĽkprKEMZjC/c~ќ4lEFa56m'Osz\^U8R&AGӐ[ MO!0gmy_PRfE CWĖ R0 F v5vzَ"Ad;3׊`#kS9q ӛ_K/ 8kO2>Ig4u @9K h>eԢQ=.c|rxP;L떜tIW3M4C6_s@gxeQѸx_:oMj2?pb 0/KV *ϚW\]5|V1K2-/& Лhp4`No t]Nˢp>ěVųuwS[+ "v *`|3[kJ}ttozv*j?9?ow;tgNȎzqHSl Lld;k9A`*G3YLFAsɛyԣLv gT57nkRY5{@ ؓMʏs.hDtd>9:ԷҤQpg5R|تPe(ph?Xa֒RאfHYKu?׻N Q6fԹ6٦ rAd͂A`q0]ݑzߘp[L)>ÇZE0.VE#ѵ+Q&.d6ILU2C=k* wJiQ\UV$|啾<=P+4&3xC ߽o֘7,3p/=`zܽrT=~Ao_U8%e00+8(qKSkѝWc pwNDeL^<Q[ f@df:N)s%X?B閌4Eᕍ Gܢ 逇T;tQ\R%qdZ] ߛzcPa!JlD'5EDkL̃}26M;%qS§~pȰ`4E9ܦy$Zi zGxo$W76~b R9ۂt%Z 3ud#b8}"uM\pNspx׷8*jóM.JAipyW#t <*k XT""`a)*$t.Ebtf:h PL1oSK CLDҝoNY";vCVS3a3p9dtf)/Q'p^#d{QnI+w͢HD=LcuzcWfd7O:f>i OGZJ%K 0 d\N L(c$A7/Z\S6Rh4`>;6[[K>1(5_`JZaU}\5H:lNv Ps!=B?EpsH42.@~&7Ū> G@bPAa;xkCaެg{^Ba2S$%3$@Md} YuͮHsE`=f&FU`1&/S&SCL"fC/c˥|ߥjs"ߡ5m>V)v+>ÓsǶ(!v+zIx˳:[zėVaVSuiZAOj͗gA&s)GYޜ `dCZ64Kj`:O!*89tgǣj)Z#p䮋u.&Ȝ=NВ\'8B.7 TJT`JIGC9rT`Df۝9d%H7H:Fɰ]֡ʠ?vT}+"ou͡W7ExJ3MVgƍ@UQaADV_b::9JEs&3v10*ˀhd;#pe(ߺQka 髓\C FW&SV`9p:gZGRq}.i( ubb? . IBgгFauSzZ#sF:g0aɾ䭺9Ciyŧ9-yzw;O.3W(h;(ߺ s.'0d [j6xNbb0LGJ 6 DJ0GdQ{p9xD6y4b٣Lom {04;>|}J~?sSyUs ^aHwܨ.swI< ْ4shS{.͚c,{[(JMJaiuR}mU hSLc BL#K ,GL+.uKtdޗ]@'Px%?DzaԮf%}Z "QxAє/M&cY&E5@0b4qH?Ngă92ELa?PR Fu8Z'EvI4+Id\bUĕmȆP܏/ >ֲgC2sS‘ToBF3*O)XB>NkWp^t1+:Cxߡ!yޑnEʼnf3uO{@:T?NW`3'R@BGx=rr6J+Y.Jw3^4=Wqګ v/cUxR^NQ崏KZ<"PyQWOfHZ̟=>."%7&M3%H:l 4J'U&"yy$_nh>\;RGSÛPk*4̫W}N(PUh"}( #!nFx0߱q,깬 F6[d8n۽Hnu< ftGhpq.j9Τݝ+CۧpĄ@&U< 1z'qIM4?Xԧ?]p.@Am5䠁 D0~1x" ^j4)Bęp)V+?Uo_=t{{6zDb(Eeq 7ca'|wѾJ^FT%ҮɄCMU{6 \ pacăsbTw,cze7URS[6;q'UlD˂V1Wo^xHSA7Ch h i_>[sG!3iM6=9q%0Ωple7 0),+&0'hdXjKy)Hml |ا疥]np$pGrD5/b/ZT:ETlh3;2Pȴ{9?EҘ4bzwHSMv SfwP y>,{@O Yky_ ! b|tjPp9xye9-gl6ٶ'ddySN^V(w{{>`r\q_A<:<9U{Uo#ԓG'3d\ȝn!oh;HY`i.G]mܣfk+W]zXk_bѰ ~65iHY׵y{0R,#F;JקӘ `%nN4WMr^S@T5t& M{;핺@uؑ `|M7LRvZjB[{ xN ĴtSXDgd!Ȫ@J|~Y" ; [X=9Jq/R;puP*3l- P5hMj2~Ø0zv8 44C$"!+Aqx':UP$ލHC ]28n|yBȢJm8ZMf#0ZP{.`ޔ5A9哗o޽GÖa|3 hCo 3,!ˆcY''ոgu$EeC&%,ųy^WH;>syӴ!ꆄ EdRyx$pXl>3t.aWxPuy^2L `oy? Y$gX͢OMp@0c>^ љ %H^!wVܚהbَg1e Asc`Fj*8U'a!N7O܃=~s棥z[DV <Żh:>HIԈޟr}sR S,J}AG5#3v."dWBq,QK6>tyb*EfϹ _~ )ĎZI>~OW_МWIA͛4J B2s W40hLM :쪟P^cPJ'lSX9.| U?mhsdl=oED:5؞cwy{[BIgψ3nwGTyokMޔ5O@(}F>̝ xcG!#E%dXE^8aC3+@o=;m&?1 ;;Ž PB=3P"E{J|({_pOc% `_PJna] KAA5ؙP<4VMB07a& !3|doI/L~Uoa<-(ph#,]d*O**O6EWy*O.q3pp6)E\7isC'ޣfOڵ:L $iJH\mB2om>Hc" YPՕc8B!$@Z~_S&msf@WaXF#y/$^E{FZq|yJf#YJ7Yj>1¨r 4 1Tw#Twcy]6Tv!r_}*E}%R|*b]D=7dpw 9qw2IMܾ^w-6I׳1jI[ϵUJt=Vt?y c3i_Q6A,WtrvtVX'#^I)7l9#f6NNwOLYY)d3FR, [|2$Qb= Em*rvI8X•OS#%פvtuMz/Hu xb;g[̠6>̼e?^&Z{swbzPI× /D(Qax2aHF4BA|JL/W|a57)jTp78_tq lč )͌q0Wy9l͸m8N,0w 05~{??d_εEvKN@!Ift ta4!E+]%dn"=aӂsN֧61 w/*јc`@=-PSŻU?kUsӼ;/://;'O{;N mUޒbK`B ]]s`.U;;CR7&KȎ`{E g%-C7:a7!ޛׯk>2إ>⠘0^`, ¡ˎ11:Nmq-u[k;]h 4RH>r^`ߋt%\ˡuMD ,?Q n`+QNW$Ilj=Td~EL#XVcR,LHx UY=.ףLhfhe)BlB ~&a"VioxeވbfvvBS(;"ÛGK\pMiC ؐ6>GNRsufZ:7&HBq@ػ(%mV*%&Yzm3G-N)([##q<!hdNwĖ)SvTv=BdIE$\oSc_,y6o(vS|0!6#D=Z(05< }"\XvqU 9\5ρXC=Qi<\$6_)68|W KM,޹:Ö$SrLI)0%=cJȏýW&G^αl>ءwD"'+{z]߷OI; ZO Mܧ:5FxH]Xҿ~VgOb5EFg0 M";p @ّo0~w<",Fk(9W@4J;ۨ#݃^.3yy04}6;E[y21 Frcvg4Yi@j7HI/>a @rlywc`tbe[&[YŮn@K/@Dk(Я!>+4xI#1R<˙X mֈ(J}e 7ϓT(CЍՑ샙مRS̆ժ[o:eRS۶=e Mܚ?~QLSq)0'qoӨYֺ]SHrn2,څ9̰ x'3ڂٳ'".c&V|sn2L0&h|-U㸧cov-4/oafw^DO VO֚ "baݔFFp#fi~䷾ kk'`a$r hėL+1-@;l;fbn*4~)߰ |J΅/9;ƳlaMuPv$N;6x nn^:Jz[N8Tu8 Qr>Ipwg]13}vKU[QNB|Y6fjm#qx>h<|eNbJMٺՌL DO;cad/wG N(af$&U?TRjzBobL<Hr_|ghhF3Oc}pG8siJ<:8j=֧+b\ߩF'mO$"e&qv3 ]i:y AYɹUK'gsLְnP.Pg ȷZJFae#,vX1)KGͶb9JbWtlEBcئzH`:TH) I] "$)'!9գ㩔P\IЯA{Yd,hQ:棥3 aak#ȬǎJ(xUYcH^(];Q0mj"nNCyN+4khOpUֱ_S^&3jwTq.mk\m~7m?`5h6ڛ-jק_5cH9'cctB䵆sZXX\>J,WIN8 V߭#"0;_38*I qpEػOaQ|u8IM 'Ratob{"(U\i'NŞմ7WT{qZb۳`0%\^eB„ "΀q A<ǝOlhwrj>(Yo~okU/JqE`+!c0e84NBw*C޿B9Qvt/}34M;hl iS\Ex0eKi2Ә U)@<5p1NL2"'X^QtIidzȞ09x>ǼLBc^($"d,uR.F~$ҷ=pgtExCKC#8%rbl{8p˯ӑ :.B-T 0WZg-BmH#n+LzExœ׈)d lg4B\:*Ul;Y7ШSDw4R ԃ9 ^t6 j2 ]ٛ[߀+5Q:%CM8ܷ'v)ނN) 6ȷ sˆv s<#2?sKg44बcuT5uCg]"rk*7)Ac@{:RjFJ= C2S 33l0'+L刀G9}2 O`mc EMV өg#OL[V*1$ü\˼~#qzY/{3tTL3UOEF})\>q;_!σݚ/P^PiH," ik$Z49[.89}KT//Pk#l DY'%* [_.Zcܞln>zxtkUtO9%!'ӨӭOսͧͭ'gէޓ̓㭻p2|W?-XQqnQQϞBMy{jz֤{o^9:o8>vßntUs ret2' vaư:.Qo?nT!m?`4bkHݶ PTÈe- g@VM8~z ̼C%KjEBc@^R]Fɭ,Q~dڞq6q ʓ?`6$YÖq14-H+حF j4j)̩u;'Ya=j>_cS:Uh(H#J^\b,2jf63d!J.ގ$I#C14#r%86ks'QZsdCQX;1څ_25vr{֐人-F!P# ڃa.:F1jVĞχch*~]d`p:*iԨ?f jiMga:*+'zN!E``\mt'Ϛѭ^l1oMC^"3_MD<&iCJ?v67f*$z0 |f%K@&%FJΓ"/KiuǶT*c(n6Ea`pȷkP&oeOoRpm\"y0e(Pd,QP?5{ouglml~|ߨ>?_2=c'a;Ҝ"EQ#E1ʹ>MMzJ6qpK--}_i4&NDH́Xl^>{l՘4Q7dZEfKSǹŇf:oP R^ӻŷ\>L[ C} 6*HB_n%Ӧ] `џ𫎸Cj>6G Sח~ʠ0%踇fA*8a*-k<\b46銾{.~Q8)xF?A5@+&ݍFř uMJcgW<XM%b كG;N* n80 S-dQ WN*)Cz!ZZTFh-VPWtl>Zn (x,~ebe,J6cDBB@jZOOVE1<VXTH%}ݎЀ<(kdO)ʭNhTaISصbZ1hŲ&+Z^cղ𫖕hK>?Af}kmrd2ccTPz0x$h*F_zA.1we&ݖD-l2p3vmRSuUU~#?;8WGG;kR;!]-W8t{* vy ګmƸܱWMӱ\I+@ -IA2a/zQrxi}i%'4P[bh g7əse3.t,N!& :> sN, u$+ ~⤜غ hAuK9%a y)c!0ߐ'չ8<-l{t.Y`E`C飦\;WL n؂Yʎs̤.,IHhW4[6! gl]f͸g r!|UMMBšd@5`KTmQi$8 ԓ2n#?B6=)M^|_'/2r?QEUͦfAvw|A8gSA hQ 5P+*qC^m! ,졿~_E_r{#עц[~}:8:RJoYq.iZ|>겾ޯw FINef%Ƹ$Dxd l3@8P^|4Ui8('2 Iʸk%s`=0g:wAJywk%himFE5^!P>ju4UQ!h`męͰ,L!M%rMaБg]KE3k;kfgYuIFЛdřAtBXCm[#}jdST7xKUi&1w&:(Bg+7Q#$Aͯ}&v ?:%tp#( z)Iz@):Хl;6I9OM"!'FLZJ~5 x;)y|OcQXg:S ;%EzAfU*?&-}B&N\h!NEq5MC42x6ŜU%./n%U3_Jm@ +;|ޕ"Ý%u3 (*]C/`%#ʄS|>ςS,/xMDBqx'㒧Es` ߂YvpJL7HeĨ#UM W'q+n~ؘ-L˝^\,[i `⾛e(5UQ./Ct \ty;>8yD$yPD&2OVZsVFc'Vq-`օ.ΡAnM~|,57Q20=\=e:=3"5fwgqPWp1Zd{ۃ^c6ncrviL%͋Mq['ǯy'/ {^kW31ŘL ?\ϗPŷ4y5gmmmit9H -^(qV uZjI76?\L c?^I ܮ|6KPfXLbck1I`(bXwL."_e34W\$[&jkjF *~z<օVJ> ,B&lYN0r[ӼQV^Aljd !>m6]I\`>`zoքέ76nrmhJP4s*Cn} iN^g;'?ȲJUfc4WX6//F!E?/l0 ë֟OdSg+Xd^bO+ّZ`>.x>t6׫'To=rQxwENANr*J@3CDgfvssvmMv=cWzkĵ~"ͽחec?!UY5G4"RtpNnhG'߾<:N޾>|N,ApD Nwvǧy9tQ[z?;54^QDZv.#/`K~]aΐ=8.J%M2J Kfa*][_אi%_Kϟ6Fw*6ɊT~c2׾+*g(B>EC{ 皏Y]O)\,r .adsKͿ.-gV4C 2)Z!i>;RM7J)^6j $湺y)/!t<69x[31K(AC b+[[W~-?$T l%7w\YϤGq&1!Hh!lmKi,pTD~Pm%=+ao)=E#?K(M/yЁs<ؕskwkg: XW^|/6^jKz[S7IE[\8qK;Ϻ;ݝg<ch\-ҏ`{颚u( yO1+g  ` 99++ +%tL1Ϋ@+C n(\}WN/*fDsCtuZ Jt`¨sؼAi u[InFg]6$Bǽ v+`]YP%^c뾹UEQZ܃l$" ,9}tҊf@% \O I FwZ;*܀)}1 .h14yꅵN4J%G}AN(uI$q$Rc]@rO47>ka?a A~+ǘyI;193Qg\ PuuL"1) sU LA*^j> <{7 :o}:38%Qm.OCes,9a MPN,ϔ[FvHK=O=t ;h7ȯ7r={_9q-]6!`'k=|ނ3 7ƛ:Xu;|ho W$hB .mly [܅.W:mW3Bb-L"tRԏ4 P[<<zITU`T%"ع K.`9ZL o\/ۿ b4הې,<-Qgi8 O'MprGf G׾T++ ~9H W~ o-+s^ a%d^d['n#жu/?c\afsAbs-)omO0 Xƿg؂0ϭEOa[xYV-1{孫&ӹ!b9Ug" h\o"} q\+r 6f}xt@ZDYvYm|D F|;g FwǃV @fs22S#㡀{%~ئUO[T`SHQ2 KU_T01ֆ>~&ʢE禪qiiFmMC]E95RQ2H#@ҍ1M"# ѕqe>( q& s[(0')hܠ9լIEYtS}]qH6O#y:VC_Gl<٬(^ޅ ~5+х{D<'3EPC+V1?0+;$p=BLuxT‘7ma%T(cϣFneau?(R#z@QKFû WtN*sKHѣ roJTqD+6[<42ng*ˮ1g53~\dḿjŵ\Ǽ>Hs!&U@&ppM)Ěy?r iHȻѻ&*KkeFYzam| X@~Ĝ 6є.yOWhǻ~_$sofQ+ίȕ8uDDR߹?nޛVaʑ0bx#VHvO>yLMazRJkP7d`o9ti얪x6b&9 hrsS0a„<@1&a"h6Y& ѳ:M&ߐWp>xoW ֕_ 0z\WL!aRhFdţGB)j`'6D4GXainR&\'t^w4 CEQ{ЭWhp SY?{"[Z|3É!zGx{WZtI^OAJPw{m9 <cRLC - BC46_O0d,֬a 3ϕN~C+ 35=#rJ&=lf#yU> o|9ghX жʜL$ c ²c11O!KEfÂU=wv\} f#8F] 6ieq;oE2¼Aq^4Z(oRH@6%|~ϙh2'>"*{Ѳu/] kɃ:I6Ig{)mę#?߸|l6aj;ma!oyS*.p6ÔN٨ze_S((12,{Λcoc ;GԒr Hya_}Js0o *HO׽bR>-JӰ+vB ERQ F9uc-0ON '=-k^:OZtuF `R=Aba=Lv뮯 eXs ׃oQGhHVndYS%Ktؔ"؊B59Gvs9ʥ"m&DR_L'VEˡwE"[vܮ宍 >Vb1r8|6TH2lQb6Db\0U tx\B/>&~X3.> &~XxOIal̶aw-9vU00@@t12`P+sHp~_UkC{_ {eT*53(ʌ5ߪ+ZЬU@gaofC 2pCKu51a2_' x&cJ?+C2_M ^Hi[kJy@iM_ɹiΆww1+G m(Gj߅_9+H2۪NvwV?toV"қDљXTۚL4P3yƘ7ǯK;>9:3dΒq$!1')4tl @`>KI-\O}6$= Cnůf0cĞ3SLs6 82?ᘠUy4̷WCgAg[T~Vq ^ockit㆘@ӂHDO?Զ7)c˜*9G™rx/CBRgcs܆Y@?%& ^rБA3BNĆĠ ɜ9y=dϼL#7IE =@P z-q 4p   ܨq;+jC5-0CFs93;eUˢpyú_S ?x;.Tr֘*.2UL1X #,\D,n ge:)A 9aqέ=x=(5{ҿ:9E)Bt2Y:j>ʛ̖yEǒIٔ}=[Z6 +Gcw+hLSS|OOt".>z]U(5jse.Xy 9X,Q˜h:KoRb # U`KUO/%\ռ֓0cGY<y[0UڠB VSr>>@'FHgS\x5Jij-a*hKLJnzXHԞx}`⋹K_28ѐa׻YWgB*Fm䧏G?[ѳcrϑz^D  J0aONZu+˃xၰQ)ԇ,AY("L!)~x ] '.;r.OʾXO2̖%Ooa0:[9|r >Ҩ`J`^C98~[&4!%)MǴ8^Otˆ7IiEϣhơ<TR^Bd13Nn'*JL<)FfNɎ )D T#I_b1-a(OL "<Йu"PX$+=J;!W#aֆSDB(4kܯo_qך3agAw%90ezg!1A{q9Z~rD&/_z`rP0:PNބc)XY rPh3hSW@9;~udz g "Z\Xg |>T~Y0ri(rXŋZ ƃ2Q%5y)/PQyo޾?o^=Fv!Sd(? ̃fއ@yzZ2(eGYJe\ dU/IG-ǚ4 FGmو)i< eXLJ^y(7f%'}wxu]3^%iﳦz򘧨0)19;Q 2xOVóeu׃`MHirh;Kʭa^Ggoh192Y<ݭ7> 6~ϧ{*xjxGp"PP:2x?{-ޓ<ޛN"<7Ux*rxO rxքg?"hRNL@9y-\KKm$/ޯ荫u\>Hs'4)&'%Wh 6pYV-$Ϙ;PK*^ 5kWml!%#?N2*lx4Y+$o"ǽ%ٺͶ,3梫$|y[j[gf * y6hʢ ?(k;[/W_3bm,(i " svѭS]ŷlȹbvRpmݞԐ2MʷKsg, Wc!X |ş٥ehV2'_Ilx^M 2M69w^RcWz/ (A3è*e*L!Osݨ^~lbws+)^"j E ̓J0OWR0UA`~*s[f`y!f0_`Wuh_zk3\ćvf <)fʱA{w.~0.߻t7$rNمnNZ9F_G %{PELMic{A7/Z=o"XSqT{#YvV@c!ylK]ԯ!q2ؗr |gߙN~ox2ջT=> 0, #o"u49oٽE(+&斍ВR} m|2 'THyJuV!S2q6hhol{ Q}wK.B[d= 2u/$n^h2 zSAҷ'= I+)Hbdu9ayŹh3ãd/bjņ_,]H?a2cY@T뿖(8IEg8>Iz؆юysնːO/{6-ؘy=Ҋh\4/ є@Rgѝh,)9O=JRWi~+h_P[XXuKvQ{6MH5_%.]HI  ?)LUɻ *LdpUn{:HGE`,^f ((YBp?*ed(KKNJ_!:m/e O=A* v* {^v>op2../`+(g*:hȕdjciz{^=U<7UwK[>e_yOaQρISLMxt'C0{qfWPy`mQZ\iKrn(.LoQ]| $h!&Ou/\vL󄗎%jӷ<$#f2yons#} W0Z00C x t%0]2~5pWG= iX}S=8^ڵ2}n!z\&*ڋ] v#WGqA>Ɨz@+-aƼ`7!JRZQaD.(9M7ǤdM3U1EDL,2-&.ٹ^Ut4"*E㹬u$Ԩb@ZtOUr >‹ $|CVp=v]ԋMr*mszt dzGG%x%} $No_~^ EȖ78tNgd hj]P{i\B]i/}j_b.PUHgp #HǛ[[^Fcpn:n2n94)@01|"X)G hu=4k';Ŭ{HUL%Kۣ)6)Iwg3n@;;]a]b’{Y1$P|؜bQ7۳冉^k8^09QidR 'ZWzd&il]+kᔋyT͉PZE:s=lqG,?z h56K^Hx&D!P120 Nrܣ]N;;N0X~a\/f17`:4|jk1`> /ja[gx(~Yӿt!e?+a?%E#UqpVҋ]EB/CY)rb|1:rfY48OiK 7w,ҝ)R!&nĻd4˽xH^or+WGg?|F:\j7w=/CG ŶsJ΀a9 re.ѐ-/ Ѵ:&pV;K^O c!sn,Yr&1R,sc*3N(J9e<߃h2uVۃ|t XDfFy϶C!`bec3lt^Rl"/Tf3~?wDS#("% ;pLA̓P}qѶ<:;mSq1/($o|AF,qP,gS 8\-Kbuꧯ%ˮ|i=lY9_&8xx,G^Yq(4)_`];#=~ &{X=sσ 7z*|% ,CXS±вh͖P$ꌲ7H%ؤ[鹻{t-8w(2_{{*#$y@henA'jCOokqBaDx$[ZhZ0[ JػeWJ^*,âIϵ?߻kG#b˴^XEMOQRNɬ6QPGĬ/ "^?_9- lX}QKC$-p3QV_~'%Q[_ve 2ܶ^lD|՘$Eb?e1?emVs?hB?iA ˕[s?T &SLН%?˱$Y>T|\N7f|pP'ȩ;[AŗQ4r>m^P5h'5HIPNVI9a$3zқ "nNkD 's~d'k*d~A.$@d![+|)*6xٴ9^xFQq0oZ_*q]PV(RbdJOX6I(/P  eϞa*=9OV:r#n;YGxqymv sucZkx^yTkwmcdH}޷@>>m->]AEqE8/@~ћ ~0X2sXoKƏg$L [ ֋` ^CCSO ެ+ dRs>ץx] NJIZjh ǃA E./ +@NS% 2C$]{%ۣ }>0]qP k%j'H|n_?UNP4@3yxN $R~LCD. 6wEwiw~B TbTrsAuCkDM /n09}yq]^:ŹBAiypת7^c&sDsԤB/A/6 q&i hp1*eIv_T~Ot+f~av%*29PK8RCb${uvc z% ĆrY`<\ّDU_?R uA)!c7F|2PwWt$> xJEѰv E1 ZQY|d!,Xyn%~R׾ ݕ9ywuot$xEV=l`6X'Kރ-Y' 1K Xr9- _ϊ7T\V>xY(S _HV-6J[3kԠJVjťQ d(.\W@Ɵ )^Σ=1¨G–B_j'=sk%TѽBn:B)WCtP@cDKƂrVCZ7P@N9i:^ TaK3,g$f 2, <n%@yR zP(ެ9#R97kΈTCf@yV Yew;6gBg6)qSb)uSEg.7Z`qagϹyl|sGxLqUӵ#.u[>~il0ygq:m)u1 pY<c iw:LVJTj=D3$uyqgHW>v*f˃,t$N W2{=$ :+A"Tw A&xzTEXKA*4bU r瞧T4$ p}`oDɤ oܲO1h ePoȮPmSUS> 9f9F)ݍeJ-( (O0p<:w@oCyꞯkNa,RXSQPʱ0A e0E{iB\KV:2ڨB/J1tTAOakEϋ7VGٻb:KFpS)+!Gݡ&K{Ȃd=q1,˂ࠎaeTn 7q~Ū`uެڽ~E *z>*+V>lqCC28kAU(=0lf kPBBvBhY@Um}YGj<2FjcCYr.;wC :.I&ar ૐf*~ %@Y +Pv+>ʓJ(Oց"**eGJ@Yk]KV[޵kA)]CoyC!!9wBH(R:,R<'`(;%;uVA}'UPxO:P3P~ւS1{ւ[e!PTAy`K P6$MF4PPa'?ϓVnY?I>`vNOw%;[:vzJEQh,&yoakp o qN4Ag(\jn e^|z"aW@2E/< )Qe)B9@*  70^?9ha-d#X9ZrЖênMQ^n)n帜)` ջɸ,FUiɝD-+-ڦbT5] =|oS.-G۬EJ Rݕe Kv T8bG'Hl, F :s~MEXЦL.RKJsRn]m/jլ*aV{ٸ NqqЖZ9.b󖮗U 1.rXq? =+.:R,nW m9j4I6)>vhѮgu&gߺP+ Kb;'B \.R37Ȫi;XU2a~jXIJLl78n%$ hr|r|Vzh4*6˗KqP|SXT2G,U`bcC^}z, %|hV@I^xRCJRMo_"^wKxlH_Kp-VC2nxu@ sLiQՠf6d@Y2ؒac|/#NެE_H\H]WGA(c%[4۳+FgĪ|<@*ѭo$Q(/k_}Xy K.}-cj!Yi95|r( 2#˔;OǗ''Gg^_/Y{һ>,Ru\tN5 3'׃cEНI ?d| e|kw,cb Q~N_pۣ(a͸]r[(UKi=X.oL聶'RL UQ>bNrt+0m-xK&Zh錋քrY#oJq\9ddYUPsIV@Y5AhOWy74+ 5UT=O9'1fS1LRTc 7+C F6d Pnۂqu$zo0]/]UZ: ~ŃE7U K[+$ ͦqv}0Q:G4 Ar9D?:ܔZj">1CG>U#tS/cqq1}\||S3 t0t'F3we{kqZ6ZΣRU _1ܛ? ՞V/*+{eT2RddB1\[w3 \i'Hy̏X>[نpe<<ɗ<_-iS m \75+:<ᡏP1G^zrչwfﳭ_ί[ϩ6+ȵ$cAo a:޸́\pڂhte@ܜ?GM9z;mzcִKgW~,}A^`a;#Lƨ&GFZ<ؕ& na Tc]gVUڇRkDnVϸZᬍuVɖ-T0Lfq%(уNӒqodhbx@;eO?mwY%k}x<,)b E ~/Mͦ]K-Z'3Fnp> ngUՃՓ?a T~ 8`Cg\eN/rp7:n1d~9pjutղEp[n΃EaIW~ep'8ܣltY|$dM4-PiO+u_ij ^ erJ=C:CM3->r6CA㵖&otXr|zjaj䯞z'vwnOn\ݙ!ߗVur"ܢ B’aFa\U|t"~>I'.}&pŔ_[pi>տ( >#:\%JlOCৣ2ǿ/<{,GʖTw\ ng=%Uxn׽pOp_~]uv_l|tjpOT] ɳ?ρ[Rw9g8薔]s%UgWv~+](ŵ ~VvTd+/º#[c-Kat[M-)ZAz .Vc|lg߯wmeE]dhfRp8".[<Cj<5w,'sd~uUsL~38@s˝/,*\ n }rt)L z^C| EkUUv/tk|gK_O8И1(rfМ@nh)FCq2W <; ۾oS%\fCUzU;vx1OAxi8.FLޓ&SaN#w3ٳ'_ $Ji)x̊XR19.ΙƓf1;}h'>JO_g}zrtqeWs iV;NyTC۷% _Tbx?h 2灯׈S޼W}Acxfq9p.qV>.4~^D΍7/߷nQ _!& NZg:t}X|0&w p`> ۧԦew#1c]hs@$v*D3,4('jc|OW_>qGu]JH.gqW-thWj,4eTr~o0{Pn7lҬo?}ji|8bԟCǵz9ar-^JP7I -%dtgF +``'G?LF >lww9x+V+b: i%D 0OYO) /PVIi48nZ[ Jp"aLXS)|>jYΏg=Zӊy.N:$:)+ 6sj \ư4iŃqH.a+[G  alтP+(0D\ِᗨ|`[wM%Y,6 S24MA{T2OX_|>/nI3"5B41Yt0uS^&s871dzQ\$FNg5`_~h1#yѧ V+=~!Yk_47Qve{Ĕ ^3踀TMLvC*=ͺۣx߻t iŜ.yC#.x25˹!JbtIlǷR#`}{X;Ndƚ`W 5Q=>۷'hph+ $_AhN&Vw&( ldWZgmWF-r6વrTdl0 0%[> % @'%|W0E'^/8އO.FF"xY7?,ƛ/pu>0 XgwM7ۻ՟D^'DaV}A5<l ulNoM)*F>9ѣ$ *WҍaA՘|F+&!%SMDk_kJB]Ds+u:&]̧9Άt$mX6b;y'8RxQB7aeLn62{F;vبN{".>.A;eef{aQJfmgس&y бߍMNUk;I] T@0m*ܢ-mԂ-l6l0Uz1RA vdLUGHNn2tD,Nо"]Ṕb.nLU)@~h\aNilz+_CZ6qN^0i$,K,$$]ZgS#ԗ.-;a񐕠+Ag=b"QRi!9PT;p0 NfZIꩋ;Z~dY^pV.Ō3Dm*FSGQa8kY g*6À. ?FqJ!o@Ug %f%clSJ:akQ`ك 8RlG_'[F*VӢ'0O 3j XJL~/=7)g<$BN^cF,Q\-M ܄2Ϯ"mR7ld( V; Q Er/6`G miK^_v?(=0 gFR!8L(`!]%Eez60K`x›MW*ݼB*ixX@zVqHߞ…8 "`xδ Z:F w2OEc7(4[f;Xtn8pe<퉆C*րmk#C 5vq|ɽyl#6fge^^W^t4y_l ixdM1qǫt20; fdm@@2/LyLW'Q * 7Dk@q "LZ[)Cf-$i$,̂I_ y_oD$kUJoY:?mT+c2* \g,\WU,xOg|?zE*xO8KzsXPԶhܾ?4Bx؊0)Bmn)m/|=d+-,P<^h49Q  $;QC EdTb|RSX B'k X+* n~8& ~D]:R8R_hX3GANϿKa9¹e&2p-22:WTcUb1XF]trbzw3]̦)_V@'GoNNPT68A-QF#M8<*m5V\Ξ{n6A0iaAl)'݅QbfGK8ܚN@[m޴XK͖Esd߷IA7u*ud<۶iYC?1Bhg5K(59ș'|<̈́MZ{:O4Rն B8&ʦ ^@` ϲS9bl*ښKB+i:y&AԹz&>3a- P뜲/wx$!]'Gg^{+;c<C]No#&hOQw+RHt}h{=šy2F c1<X!suCO`9(Ø%t)`}\CCrkPƈ5! ġ+nXH=i42 &xI`8n QD0~0O ~6"AL{*1\y#XZ?z_WtOyHc+iم.L[vL螚MYnJ+7zd_* +ywŧAsvx~a{< Ծ[j.ej} E@W8.ܳh1=P4E*DOgh&a:¨,'PD\V 7Fe m7&3Ub`EڴvzV{TUAC/u$P5m8!r lP H$pTƧgoU xM)I8x4"Vsu_L`$q\'jhb-^è11bdu?FѴo+N_2OS^{ULN9a2<{f^%$Y 8yǞ\OףQ. .샸gx4En?yQ(ll9Zo 4%kJ>r,{Q),MZSe2㠊—ˠ?Y-߲RmIߝy}&kڞkA,5Y '0!}dEпZ ~U`aoƒ\~Q$`<{QhTE.ś?U,n{T;xlyo S ?M{Q1!SPZ)_dEW- _TFвS՜-^,_ˮuq$}<׬ /#~>ʊ,/) ;7󼞫?$Kه쟴(?>Ěϥ⋊qσKF?RǼ~eP9(Kw6*94ڲF9F;Kc!W3¨#9 K!&N<,]ItU/np K`Y%mV~ zJPSzv̮T@"9J|KhVnHI^泥ǯOe s r)'*ܧֿ6(@10GRT瀌o|5?-cW/9~w9Ns7$z%Ǒtv7W]is+sg ,/ \f#j!W Y<2jUb݊0[ZYg%mC..+ !j3h%\>3mJ<Zn9A PU9UIz'I9I,$0rXyn5cqv;%4 >#!q$pUAA3Kp3+|oT&)!:y(NR nuޤ6 mo@hڇ5@BTQ4 3󘓟d^0gg#J6Q@ zcmG*/;."/U4`/~?ߴMm1[nMh (2Xn>=&?pɄ_RсDnʀOh2KһUa/ +±-YPE^@JQj]Us⠰XHCm1Af~TDžMdVM 䳥kAi(QzS_|ZhUdZ.W:4 Ը53D Ov"&f0]R!uHׂP#}@nsBAdW ?id#q\f!K1"Q!~xN}[hLOŸ(m?π}q4o9s22熴H)m?M'00ubxfpuD}TÆKs>?aܐͽsB^`(vŦapajGl8z!Rdvyg8eA n# Ha3T ^M.>#SН:'@akeEt(eJUŒ-.e~t`Meb$dIZ|DajW'.FtmزěQ* z/8ǁZdL-ӭH{LeK7ܽG voG7gW`6̭X# BDd+cnźo{,ג9OP%qw=л kmhԼw(kh@o_~<^zFr b=t4;ow:GMf!7lkf =KEe1QK" 1̈́õzWh%W(yDȕ)dhQ4il5%c7eW+o P{vjg\x˳xyWd[JзKIrgn0S퓣++xY<% C1Ǐh[+Yd;41ڽu79'2 c#qbIuD gњ .$.g1MNW=9Co_7Gϕ0**{lỜ=wwjyOkvI~2ǐJRk2'* B^Rzn1In}L#hogSڡl!R>[4$X qY̸3:!]!DX-7s6wrH_7hY"H+X~%QC?'{O{{t#GrX5EͿxHHވDs8I&&ζK@ѝ_ƳOQR8M`̿iB$m lp.5ĤȚ)qF ͒$=Q-8A{3*Č II$<-#_ ɢ-Qpiէ8U+P .7ET%.\ 4o~j\:„-8SޘmKt)$ oZy5l>/WS ErEдY{ឺh'Gg!@ܺh*/_ ) SB k1uO.1_i֪"ryKBa1gb$.@h ": Űd " 8?`xD"q'v>o K>%F[g!2|7v:YGt>7Eϲ_yUIw3nЗŢ2Z"nM 3xfHKin>DuWYz- *4RmT*% 4C!k7H%W4q6^@pR?>&E7eN&wl&QU|𨞣6+ȝh0x>R}kvłb+ V47ݗX,\=XsQۻr+;FpnR 庝 ϔ=tTb:b]K4˵>;O<Q\5xJy!:Qc'<{VSr ݴEKUʫ-?}gb>&}A' ,@DW: HU~9gW:wnI&Mr >'`G];DE/xґDf|*8lƩc(vN/WOYn.Yt ,YȾ\ tu4j \G3Y_Tw|wWYqd>h3xm6D?S%ҸsoY<Ԫ^hnRJp||v0HG)k-M3uK%<ȶ"3K݋1\8ߩU1Jz-(1V({\NrJU+UNx"_N&W,x&{{AH4-POz9hZzH}Rd> {;N(向}]ݐ]VKD1`y_\ 8cuagvJM$2#r?ek7‚\8FbIPn#^:X+D_CcfBf IqsU3)YZeL[.|S Y7@yAQq&`sX,zP]BKK"|G^#oz m _ˬlKWE$s'%(0ʹMnO%XQh_ čl N+Tr7s)f, T).Xx2k(ifbH,NO 8 MemJ)ux è}6Y,\fCg@1M c9:} ky]r,^>;eIwL`ɕ$U8-+fB9ȀȉXYV=CQ eؠZSCNӬsNwMO?peyJ!U!q|7~fSuC3HNHutp{a0TeTjxKfCVmN rv*eP}=tx^keB:%di Sh"uavy'z>Z\:L 0() zKR;OWE [9)g D3}Kʻ*H t/q׫QKi~INd 8/:pZ 2t !,^IÔHMRO/#,=Je~q ^j Z''sZkT#tUȣ.yF݌ҙ4&T$͵HJEcm[~-5E Q+I+&Լ4~N 䮘fwx>3tdEt@E]j/$F✅νēߝ@-v@$ṚTSm\64&8gь C:-h7uȃ(g٢9wa}]9W/\tϓ!dr7`+}@|[JE{`1֬m?:L[T_ )&N+i2#'EK߱g(&k:wZmo ?{a1zcAjg9(ÿjߥVcn0SIcTH+lصCVr3a0M#FN`h,Kc@.$6_h5T fA=e$`E-42۟º\-!<:NRŨ\\kݭ2.pQf*NmDmݖcQ=.0sl̒}AoCфI)ۆ#c7ܦ56Lu ٖAaiVW\oe|tsu2Ї^Ɣ9I&. 1 cq(hoؼ'[rqC9uZ)Yy3ظ̃"b !U?o)TPN[;3A"+>rnN ;Zgj`݅)"/z ZqqAY\ESLy ăv(H}+CϑqJG)ᔾbv&,Yd<'Mv1!P!7,6eu9|sR|%"L4F !KQx6N&)ZM<*191fq& L>Azx _(,5QXDs|@}.FkMצn|J``z;J`i .A# '澑"{IB 8@g3keJ` `xd4oBߚ"cGL,0f/pdҩBZ-ʸ#,[W"=IQMz܈ \8h:7 TNМamh;>wgܴT|# 8C)lG( 2Fǒ(ulF$svlu+}pFo51)80~P`yrϸz^g@ۧ3X̽A/4 Rc )M1M kiM472)B $WOOUDxsvvf{ii:x ]`/Q㠲 ބ}/r/jbiT.NGi.YO ̀Z‹4hGr )i| tQj[=JDN◻IւqD3w/E*ئkިcbZvǓ,&2FU&LP^lx1DT9٭S(q~a"ǣ\5!jʘ:e 9H" L` H i1W\csP=D%W`FO˯ӥf=W_t|[cQpalACJHL!DLFNWK T/=Gn0QV.iVFwbDfղ9c]ØiL$JiS4Lk ܢm=H@A_mmuOXXĎduuvx%e;:i2x'8yRh2w>UNQC͐f9\\j`iL<&AF20~z|#3<5pw G0LKy6]=6fgg~—wOd/@a?;vxݧMw8= n cۻHS2fX_SXYem׋h0f̧A]GQ k~ OPjt9|9n(zZa mf@}~VL+aLtDečE`SB"[V_kwod|&\%5GvٙJړr/dwPmlAZP,zS8{M66Na& oA{܉TNFtp"gAOTe=-B*>$>0Qpz=rzWn4gq:YZ"piJb}RZ.0\ k}PĽYyʞgj&֢k.[}>g3/d@U{V RLAt0Cdd.Fk5vwS}J݅$[|;YЙj}H5[d:rgEf/pyZЁugWi_O u);aRh8m Ǻ"֝2@XOH=2۠! %N1+Fɋa<%J|}Fs*8Iƀ!FZPm#ŠAw*1F %S.xEī(:i&j՚&X[Y9wƧ]bDbU11sd^Q9{fHJg$)&Us*B;U`6DLބN-}JI.` /O|xoǀ0p;-zם&ϷΓIS{=RڔXOxk5/gmi}ACa<@[رg<{FS^ tZY̨AW, 1$hvjGǩpQƘE{7OKpr@<(zSw64n\fg1n& kjl?NM#-9k2kL,r0“10r -Rlժ@U&j/EX$1"Y+wPF RAT+PfgҒ:KYIrYO)X$"+WHGIx)io*1g)J7lɬ~1sSQMw+/OU|Xb\ɫ2EἍЭiB2Ď YrClvNMs}oTHq Yk|(^)] Q@IY w5+#U.CSD\ _ږthE%,fgFǏZ>'|5A67L,#ouqEL޺DD:z8>q:IE!^~梞ds0-ӍsY&څ8ƠMs!ơXg樦;7Xx$ & R ,s73Jt`JD'k<ĥ ##{ךGPh"05r)`UzTT ;`SЁ;_c#9)M4l$cfyb$g %4)zEwxo8cK QҶCK\i?y-|rol17,R dn*}K*Qy "] ]]3U&A 𦅳n8ڜ];1w #Nn9pX54U~zv3ףoɗ`2mb#^ShYwKr p X^u*m֙͡/,f7e-Ǝ2.H&"y+X"Oބ NGGmJcA2an )1䶇ax5Ѕ&} Mt`3v`ta݀ tୱD%N. %dcƑSkaTF+!&h zh¥ko|e*sZ:e.ۦEvHaPLW# ZaMj0I +^V*Pa0-~x舴\+Ei)Guˣo\BWdr&eAP3T ^]T \яQE|^jmq^ dAS%,5~$_ T>q"ZÔ/t)8^ s9P.E$O& XFR|fCx6O.(R&,Mոp ^;'"Ak,(]|S\l, {1EgTox,:!RV[ZjS CgQ3-ǥmwqqr0>Tcae6 wغe<#C'W y'`q^#a3g@T ̼XG5*=Y$e-XY,1Ja n7Fl5E|zO^ \YE9֎#zݴƎ9 J}}aLENAk|[3Ȏ_ԲCī,Zft/N}<iUDQٮT5Lp ];10OR==M^wwvK\'aaJO'cx9I0BRXy?+z*B~&%faA{^iUə1&qBvBPjIP&f7cHyeXMFXy$@CDF`_5U~s6H c2?U% 0hdkO)Hah%pVmh|ZňFȗ, yw R`vl؍K9o:>X-3DXl׍-(y\@;M24F oWNw(N OҰBDɗHtH/8hP*A!鍅8#5[x޻?.yt;]ך44a12O3+z6'MUo)ǤXDz!NRƹ74 ĬWD6颈؈L"ĒVl:yӫ6J4ዌ>pOk.F=l(o I=b EmG$姱Iۜ9"MXlFf$ۆ++}tM#& huˮ F|gx|tr7VԱ ^N0&mMb QhJOr~Oze܁2YHp9~C:r6UCºh(F+:L!g02H?id5M'ͨbJgBթTHXR~2EB4r*c]/YBsŢ@AL U76 aKZp8Um!L]hU=H H4 "&hiՐ57!ߨ]bB(f=C#fkl# s6mO(/8EH1jr*bu >ǯ6kSF50R<i#ڇC@ʾ#100Zk5?܆-#r8ۻqiP^9Kw t덓g%FWAGevU@%9xRH1=_F.q#v76Yc˷9!l5bMdSd(Ur3>̧.WY9HS0ɓ2 @Mx-qH5yU`X#v+ VӔҰ"GUcǸj5v{;l5r{`_ƷX#׹[&oB҈dsz5Ƙ&+3kad_f|sAHb8VEH1a/jAnHRf)kPYUlNlDzg#]˩{P< %ܞRKeԄjZ4kӷx&bSl@I)x,vԲtknqU4VmUcD0C U,/yϧY<bTSd ײl4,6jMk?٤m"߳e -q Gh@^L@Ɇ"7RT0hrOE;rī+GBdf/j(X\@ .Cf' JB3ZgNmׄi1[HGXd/Y'34kH$5+|r9k^/d[_fa :%`_U70m 0V -}{c8ϔPmæ\jI8`Vg VڲK3H҃ s%drxEE$ )S&q#?$9lv龦S䗛V:cGoR*4TPcՍ2|Z+kլ($%a3PC=V4~ v?ЩMG}HIB̝:|d6yN3\/:2ɔB Ġ$[ɬET!;-ubwv[/R=GȊ`\Nll3%^wLeyow};ݯnZ^wmv'1ݱowK';Avb^루@dyX2'mSc QjR IX*2aBn7dXѡh!yH+P!]r[`:"FY_ #R_`СZb&[Xs~e)m m5p{űQwXD38B'vkplLZ]]Zu+;r .GQiM\bݹ;3_ijDW/yNW# jI#4KweIC{] 1A<^u4O59P0IIk׼Ք–J +8p)i13V$y{ˇ8GoR%SIUrۭa{0%a^bf摢6P)45 QlXJ*צ8 5ɓv5Ko@֘Tƨh&ui 5\S;dj)-5cZM"')_ҷ}2)sЎ^~[A"I2ysJqP> 1mw0ã-awwcL.=$EYB19HkÄ#U[i~|Ͱb筚A72jE1kl4B*O|h}!(G$ؔ5[ `U>`!]1CwlWڦK#1}IօL|o(͝HFv˚J<H*2Si_VԸ@.dC3` 7tX0^hVUH:|n 3 >투7oFq( 𷦩(oRln1ߎx1M%aF}C%uB'0cG *N}tA?QGϫihdu1b2pZڰ0 _ڗD|gHfMМ'RmWO[!zDj\ +F~x?e;{AI[Tؑe}P <~6vl]#@ !g{6H:љ'eݱ/.ˮ/.fQ2\NKw gSN#i„ 6R,0@ H\3 ~4jc"-ZB/YngeV6׭Z ^+~Go6Ţ =01#uwYPO3DcS sDSo!6BˆA[b6 b"Zz6OAƮO}oim}&\܇FCE-o;^ɍ:g[lM!a ?Fh\ p$p|[n#@-+Бq3&\65Er\T[c&8´5.">QR?E!Waj5B+LXww".SU o'E"6&KѵcPNȣwOmqN:^Y"x8BX$ЛyO("0D&QY|2]W)\a=/clV r542o[89B{^nʡNt21ד]6d|Ǝ"C[ <.qhr=:F&ldEg{p耸ʘL!WY,dSFH~oqblfoA.:2C0< nEHD\+4!ʑ9ЩGpځ[y̨=Z1}ETGOdzP+Jl +k~C7HUX% ǹeb'go߸W;e#=p $(a5.%J)ʧ0>'wu)g)\irz~*ΔW\[dTn <_}"~<ƒ θrV?Q\ ;@{ܧe3F;軧FY3 +/utM*ϛJ :VKJc舥Hm`w˄5`EI9&*~o)/ސlAѸEDeH/KZvZP,`Ɋ4eׂ-8'=1)є EYfx%Uk3*©I|a>9>lDΡ>/GEՀ@Ok0rJO-EdP TtjN0֤͂ V5c Y?_"]&t%IH^bc`w!e`]H_P-O[%?GE{ЁWΆH(cy}'F}s#d5,[b|%dSKQM5tAv"cpH !E(E6S:Y 8I3]GCUx2x~AU+|3M]:VO9a4@ nj6:ڠs) "|'.Mƺ+9\&l1`'ZAöq&ȲR0+= n%<;(.̘ש3^}הs/cwofg_n+FiԎ CQH䚲_IǸ@sG;aSGZwuX?3W+L`uͿvcmz8|٬XƣyT`(#O⠫#&qD@&t2 n b+V{xb9-0~zSY^j :7JJ mg>yS|c5[D1AU~er_Iv.=uWng0 0E%F|#4.s*2.^3#ӆmD(΍h)ԕO~hTanO L+x2P[o0>翬re+O^mOy F&R+-)]hYxosY&L|pݗ@`KhZhjKK$bc\ٴ|?f\ %}DXJQpKJF[Cc}]TK.HU:\YpV.F--F^X[z0,%^n]"Uy._Yϯ;_q?ƫ%޵[[h3ĵd_[m[dޙo5e!9h*I(6[~Rh 4)=y}p|x)J VWQIP}-|^za Y^| \bXQWmj@d+F&<SK*:V2M1B>[pHHI|/89`Y;Xd=">w_ =T5DdfZ#9zy⌉Xig/ZS-l,n)OONRҶTmjyaȟ9_zJ/O" oP3GoZRX crPģRTc`e & "X(A<<8\Ďs-=;U&,yI&5 rӇ\>Zq*hq}5w"$6es⵩x5 a51Nfц)bTH^&/W̕Ui,v6/"Җaْ p ?~)Yr 80tM$.NE@k`:kP{duVaILpG{fzJ>\c19?}2Ѣ*4gT&bm1"8y$y ;NjҜRVg (1\R8EɯE HaVEm ڮ_{45%& Wo$ugiŐ`Yi+J)yj;TiqIR) 6LBdI4Kl|1q>}Ayh^:AjeAs9S <"JX0Dx?(>K_[KRKALIDq1pݣ\BkzD+C 5Z}K" ^iWSCl:^w T'Ѩ@Ӟ,f.}d)$FkP |;$0+7L+.,:"B1lqPc)Ir)\XTИ뤐ob*GK땬F7]VsF(v2QYQzNJ7HTg9 il}ӹ(^ bN*#˂d)Q{:LI%gt7]ʎ !ߚFs'aՍmJ?;~}rj@`e)̺wqku%oWH59NkU9Ѥ|q0g1kL泈guEa ֔LXʎq$Jvw ;@Ü808$]d I>➡K OlPCcd[vkd{HFljZA`dc!FXzq) ͵Ɋ~#ico6vfrttWIIjTDIw:F} (Y08 ^Ր?]9}@cr`d~z1Bn6&m6bdWξ=3ĒY"%C T'Sm r^a,Ht4;-ʠ6k=Ot&>W:F̣'x),ӱPyd *HlS^kx<2Bp+qHYJHUT%C?:w%j2 ˴idN"ؙdQҕ@xlOq M K.;])4XKhp(kfvfn\N#A%NݺB@~[Z FPNf`zubJ7SG;G ΎbXW`ԋ m\oIvIye&'8R)ȵi 8ys^`ZrD\CMȑr"3 IIJ:r짔&/: OB9n͞aFsM05<4\|*5I?ڑ;m7Ԅĵ Ww$p?amo2*v09`xM3Ǜhŧ+h櫗 Ёc9mNU)/G&ږBhsڢO&w4d.#Đ/N8Y- ۦ4T)ӑӜ[[r`i>)R "\ML%cHdT1D NkRV ᔟS51-Bk(:TS3fNV˧l 7 l!7#zjL$E(7Ҽ ї/Ui,ի(K gHv^z7|Gzv76r^,גoL4j3@eݝm(2 b4XVю w 0d=7h)DWe4ݠZ:Nz9z 5TŘ f+fsa`]c2k P[z&!%/OOk{Wa4{Ϙ{!o'%Xkb\@*0Dpn'tc}q)Di I& ;.û & CEZELJfc-> @sɼ}$0ltbi6?I}O5}ѵ/ޚvj- 2r/Mγ/zcEXD5떅D-6 =~Zl xqT]*FM!1MbW 1B ƉcAv[! Dk ԔobM;!?u̵<.F_G"_)ԥsH@q(5<]+Z$AI%OzIg5] %<>!xvm-U;ʌ\ʧ F,F569Wl߁,%WsMTRH횪8l;OO`UČvJ b &(P_S~]%X9#NȈSAy">0 z Ǧy=it2,Uw )㚤gARBj7%LgэV igN]KUx9kOΌyeTiMgsVᨂ+*&FH t49 .D!kI9R oKxDV,q H U-BuX-]a`I(% |zjRFWD_`6[5Gd욳ԩعE,H #0f@$^S8zxUJϳ+B7Hq#ݩ]\7<%4@<.(R,2ּY?]lH$֫|YIyzu,_Yc#2?wDG"sL\C 4X?[i]^!IzRQed`09TO%n۶9yAUhQxWF-EuuCX.h\ӐH(mA or$b!k'oq P#'g7[K\/] Ndz*2󄗞&M)Gy! Hm1zc2y8GNĿ kqil.? S,%%K3 d0kx~SP!mgYFTn~ˑ#EӚ״4)p[ܠ4E\lšE TqNGqq)c2G\-7I_I"^1銯,CvPG!ccnSe  j4+2Gq[ʣXufih-.D,dQ5[|>zeN.g9ѫǿ/y2EAnwwǻFJκIrOShΔޜ|H%k9U !-9?uy%Vtg3\])pd|!FW2b ݀FWfLFI5rmMI TQsTE{2{ьbdS ߩө9?R]Ay1qcp{4AE=G3w'(5L]aG+&;cKh>~'n$ܴ0JшtՅF.{QXoG7{:7jL0Ő7vǏ[l4 *jS|֓X?8KH}<-nu-GOМQԕwΊpMDN$lCG^H.ٶq{L-a&0]^#nV,Ѕ©Ɔ>;ekqJ_̈nHrQsԎTV^;5mN||ס L{u]aL"@~Uz齭Jh+td7!OCf&t}l3TNjcۣk8[!ݵ;@Ɵ>j6cFn,繲^V_~8>9ofUW8ߘAnRK"'/WNwx̱<Fvg\Gr‘D136Sռʍ>G9 d ΧWd-\8'k2Ĺ#z/?. ߩYk)KSA9cjMHRG;sۈH._&L}2QB(f2K/.ħ 5As 동M턣K=hF*ΖL7sSfnJ< wo!Y5p"8 S-ܜFw!˼ )s`^.l]y0`ZaSWIRHFu(1n`yتDdyMU=yP!1 -3^΢,dc̔Ocũ=i :@*O$ r$|JlV kmd!wΎmt7NCS'tDWDLhl x_\%jjqOJLI$#FGܫ1ef$z%!FW<*VUAEEcs;b|` %!AH*T@zި3(Lq{(&;ҦM D/̄p" eJ9Ǧq2bsfCΕ,kGdM'0CshJI#pH6eF^w,QrC ;K"IЙ\rܨw5a&5ui@ »y,S%MU@ "ݗ0DqNc̚%n.X&8+0:2_bR}ѵ|Ԩ'+`N,,H%qFBٳSwÿ?v>yϿxٓ'l c),P}`˒܋#Oy2ʮjG3$2jO7f__6gtzevwwfp-)'?@ԖKЁY(&F>`GƗOFfȘ >cp7Pgi\c `z~NaiQ4+[̢KVLl(MxSVx)`T/sJ9zFzۺCY4ߩ'‘o)U|B'v'Geiȇ̂@LXa7gh; _&x|Y:|%c(y1By0B!rX cqtգ(CƤ SkfkO8A nW7.qH#F+׻=U'?E fqiۚ-w gd3#dMg[2lr:v< \`7Qz5SlQw<$xo((:QUiׄWK>RH*!$y‹2ΓeNC\Y"F+"Y9,Q Cō3v27AiQ"wA%XWᅽrGF}g@Kn;9 nc+B.*ZKWAm9u(1TѠh Oq/"j~Aa1Nc=wjwlJUcU9?<:=x{LZpP UU0( K4Fg(`Нr@Vߋm V)Tw4YQjC$_/Ƃs!5ߡEIbr,kG4Z6 YT"R#̧k8Ȝ)8S$zQfJPq-8@{qv6j0J^0y;܊l{t-: *RLyJ'B%PȬW9&?H1ah:LÝwIQ 2O)>i0]h3 *B+\D7 (p,fcm{_6m_S[Os: `C:TM SU@&n_ 7LjbK["e\ƻ-O {’Q??,\bL2dnpKl73x^~jZ9=eKMeī¾9bF"Vf[$#꒴q̝mWeOWjPעJ?LΒ!3З0+4mqdKj|]f_F*嵀aLfww<IA|pH44y`XnT鳡3Pnu17mo,] DF1_K>HrR^@E@sכ?R,f ̥VǙ2 0p.l^?4ʁ[\Ta{Rb8Ne r!T[=lB>=؂pAT 2TFA?Bn^3` YLHFڴWߒq(ٰ=; `E g NTL^G h:|$* ۽ޚw{/^>jQDAp!c冲ߒĒ鯜.fH 9r?y+8膜7 geNz `a7K7ݙk.)3F ;)ɿH2KX6$Hl|1hB p͂ 84rN_bC:4 NM]CsB@sfg)сN{O!t =Un<8$dx%v>?VB| _7K lHP<*qv$\e~Oi*NS1sOn<7[yΥu 4gCs-S6M`/ϞԂc4R=:]ʭ0j@%\L…pQI{ۜ#Ȥ\Wb%@7 EMbfgGf:_z? pҗesWl(QcAK4N'LyHQKvk)=\b>`6ȥ$-GN{wwk÷39|}OP/|˘] ?%:c ?ʏ|=ꛚlWc.ۨys}gо!(i4hiBбtVOǢ`r}gSbNgR?n~}=;A >]qP)Mf<E}DF=U[к#oPc7&f$-Κ@ﵕECr{H4} 尡OpdaH BܚƮ3!-s~nW>|0'?&?}K0h/VPez(;B[XRXWEIuK@@}M(wFl N\ɦW꜕TD]2Ϻy6RTPZ2ɺقyna@+Acʼn Ljft.uA)1{zƙs8Ͷv'*Vb-=PC)],O.HvAԈ/|J1Py8 F cL~QV _KpDVaw5f٘ʎaL]0.\3[GP,͟&#Ʌ%q†be˛?u3XӌI :_qmZaSyov7ko",X|PQ ©O!27 a ܌7cQfv߾ܣb_?^]^]G@\3G٣5'=Xj3?<}Əc 'lÌIȁq(5sx 2IH=dF#GVwT+r=FƑ'`P&'N&dm,mȻTca½>FZ'H#-҈ "+rqE)Ɨ_9r:مqvbX>1~|U Qv+qfFr{Of 7!N2.ok^ZY wu5 a []rxgΉ"44FQMKGYΊyE.?VrU,rr˨_*4#@U.puLi<Av;:9X6+eWn͙dd8^,+4FVC˛36yX`g S-t77rj*BĢ4F̡P8Yh܌PHUYrlĺ6tE8qFK|ܒ=^ZmE3^ޝgrg$ݖ2&ɲ|W%JI8fޝ[}M81,~!O+V7fP0H\HbFPFEp: 6HX*#yȮJXRtg N[«vB@ @O|OItI~t@p*)[rfkGN;ZhA.UbuCIw("m1ǔg 1Itp H2BEu7jP VDW0R8$2`uk5A?H@.rs8qx@`EZ8O%$_φ')R9EO}orHx!BЀV8ǧu`*Gvc?-:GʮHl@ (ENTu(>kQS~M-@N ja(Gy98*Fߊ(EZ6vcI ewz&1L&~ :y 2r]p~xHoBl%A|rA*%9 g0I"8DB79`(𑮢%Jˤ!3]D48 @KzɐO=L>sl{ ap[0TyL5ȁ"yGkںKA 219_$!%A~+F} nx[$дiwTi1'+3@J]9KD%Aݔq1{m?Z7FZ`Bѭp5()>coVWW;vé~:1,/e9u鑡½әaG% G#sĺޥ\3)n|^O 0Q>6`'눑cK 5.d:Q_,kER*V*qr sPu.@?WkfC)L-)\ OfC]\ͅ>ݰ:Zs ba;Xn UFhz8mݕoBևG*HNk?AJȇa~XMq*ǚYoCfp_7?rYPj{$'"Zm3S;#D@ 綉bOO[33U7A}{2§υnAF?J}VON>9tV 8%'/G# Hiki0!uAN í=D bVܼ6=]1 J6j'.D@bk68UHԫ>:/%x{Z@F"'fVZ\(.K& kN+@W̨d>x''E# `\< g&Z_p-mE/R}R@*dD _n"!!h_ ,1G(8ќݔ̠fϼ3eʸ#~#xH!$7Io<֠]lGuƴ@vgulbixu$t̿d4Z3vh0[Y\X@t]8Eeʳͮ=,e\a&\5s\OYrW66*<\ILĝ,%V}_։;PvtSƫD$`D rn g$˯~K_in* =ԯ_5a^ɪj_J#3d9. z=4ӦfCh{hE; mwhNzfllMWLa9‚.z`UL 'r _np6Q~jؤdXgG+ؼ KBK2:9 bG}/LnjjPkkfbW,- [of`W}g)ݮIv:FD 쌦/.k#D,.N@4yZj3g$-(£ImﲎC{R>c),` G7NXc/`P9tF$-VsH!cP}N?rQqMp5ar̍ a)Vg 04᳒O3Vk34G|z]ZBo<!JXlr.zTBNO ̶|{@5S)ePkU^.|Cm9wS9P+[>mleviPP3xefeuڳUQő)cx>qL}su`eR"/+W]ꔚ@Kow )-򟚨22m<)4B-OTIEݭeG1]f*N<P%857CI}9̷+7 }Ln=9ǀ/V[gg5.a޻C@)źգͅF u)d a7_iPc^=|ƿnM}tXbzwŚn"]i?4ORiTu3{ZB"CfB2lD~ B)$pOȑ=dƟ![ij94>I]dOH6>5uÓG{m K1I/ĝ23Uy`V7}͛ͷWWicW 3sxv(9>gfؖlY3U|yan x0W~<"e$ Wfh~!>_~| #>' vWh|'ՁyF*T=$s䈟H\DAGUb@V#1K!3g}Q{9$B%1I#/> %G/\ȑNA /K'S@dNj}~Jz\7AT%bi[n{w~D#Ĥk`33z4%*{w;enJDu]?!2u`/kGO;t,GHS/%){[G'e/G}H@Vbd/39ATBni#ط Zb!|4u]z\2!& n8^a[Q“J9WZ9R!C(7=9&'m׌6:ZɖEdW+,VN!9\B:A>(=ϓ6»7O^/|kJ?^ pU?a&V >uI%Oͥ+{ys_>=#Jr %sc&S&0RU7Pg{U&.T^y, i7kg%97A.D޴:lI;VxKGAIĹ`5՛1!1OJX09}nCʊ^K@0 GDqcw_8 =yAkT K I̤Mt0 ¥ua."^ .Mw|e=1'[(IK/のnG2꯮>QC ʂ+pK}tBCDb {WϰmU^xk~h0яqx%r*a8"80 Snx^:Z:]^` \|H9H /\>R4Nx t|'^*&s\Y˫~R(!͓{'r`m)TxSm8d,τ FS(#U59LG_o1Yz^e|Pビ'>+ˍCo.Ikf` ЂLCb[}?n ⃓!d$x199.1OJ{կW#`"uII _Dl7x`1p/VtxTMx\M#u gB1&swBsQ;<3^$![(/?Q3޹1?0=(T/`_rCarR 倗((9A樒Ә,NwGlc40lqZwS5aG×3K+:RюdV:rgPqs4$N /Wa֩~2LWW~EMi[DE5G૭(@QT?P1X"ǴQJsjghb1ZhoHftM*,q v0> s ڌD 40`vl| -^y[S$9JߍOᡣ*3<܇N`j07 !2m@;@=$2}V9>.OlYJgdɸU$Q2 1XF\$mo"/Pp& Ty\d*Ax.{Nq).f#\/2.9T56EO&""3}cFKc)Cr_[?T/vVċ9Bi1#1_c0L>;-{FrtX FרD/6׾ Q-4] -!E9a)bh bėZ-ى0G^F)? U暋{kbrRkߌE0k$t!K_!*pKǪtwNO}j%3>@F/9dxgiY^X ٿvtO )k%RL4E $K0aǦZA(Nrk"=:LzzMt]tl N!A!'uF=|R"rBh>/%_ڔ\/^HgBZlK /}c_>;N;L1h p""](#([:ʽ!fSz A+ u&e*p g$$A)4a rEvL "TΏd"%'ʓw 3 ,VHﶿJm'"Q;d Sllw2n$2MHYKb Grtߦ  $Hu.ɩ=[ x4%Vϸ {l@Py?'A(JVF(N8'i)?;3b`Ξ(НLY!NA Cf۳"m36> + Q^Z4?&?' 9+Nƒf{—@=+A\&HuϷ]qN_pcUI;{؏2JG9IBH) ]bZj ]T{::b)K͏*R9۱x2g}mQEPOE(&}?gK C݉?lg5rTm#Ëh k iUYh4O" ˍ?O$Lz}W%!7l!Ӟ/w9~ߔ:J*g]ae97Aɱ̽<;9`xn';-CYAl ^F+ݳ Bӵ9Ac @RK[S3Nz z}^К0_HAhU[!K5O0yK R04\:FqEWj0IkDr ((au;#4čdu*0hpveIzigBsBAę{\Iۂ(kh0e^xqsr /٥`,W$?#V1y>C-홼mk1yӒ2P ]0E|#AN+now. H"]6cowVׂr_처x}Pl<şT8|} xV`LN\7ksI^.YwLZi͂Wpg$˹SA7nܥƅPOJ%\˶Ht"h*z G~k)9UAYTR Yh(wX) 1in1`܂R :Qm$|KcOk -J%|s-ѳZzIKĽ% r,|Kش6p7"h\͇u#A|+ M@p8P |}J(1V&KQG>kzv xz}v릆0C͛ 4dT)=grtu:cSD.}9?sn@܁0ƭmR{"=a<#~ kh+|ϑD%ԗ2q0M~4ͷ{'ۛzA&kar^{(1Վ9{>5]0NQ(2cJ,c!i{ cq޼fg <97ܫ۰ tuzں A+ OPv$hl`-epk%DjT^,\pBD÷50' Z2-Wr%xv-Ev J+^i?7y|H٘PZs٧LB`@fS &? sM>5-r񂞺EEcw*!9%`XdVj;7{u`w_hao_*cVEj`Qqq:scA~Es}ZFڎ3u`.D 48\$AʈOIagq 0VzW#szõ3HA57_5i齭-۹ayH,'Aa5.S.;ovٹ#F!"'&:̇J{{>Dz0UJ5Gc4 pFT|U N"cZF|ۜd+6y{j6YZ*\x^aG 9/6 偦u0ƙRTc9dV*H7/|!g){Sڞx @nBƧڙQUW({}Y6Ǧ**.(H @󘲎81r>Zrf_!.l-H8)(HC *mHu9Q= jG MxHnx7aaȓ4dpJgmC; @Ѻˁ]r5h8I(cMӁא(3yWmm8``wd=w B(!R~L+S@V4`gBZC41P]s89!6Ppobae # uƿzڡC6K?=F8nHTvQhn ks̄YI2_ b4p5Xx,$F0`;#54C&׮S58.TBwDzx@a2ǫ-S$B)L<i{E&nlkPpo }.jDъP:$rbelnl+[mc'[ZE!;G@HogZ聃ɏJäc9 흙Л (S..;(lER+0*T!) +n뺒ä>~[ԧ-@ utorX:` y9ÏOr$hdamgٽ3k,[F^I<p{ \2.0ˁ h(V:x-T"SZ9:uUIGd1 ']imexr|{K1Pt<^khȺH^Hg@C1ЬիVjQ;+vU+\~fq=Xn6sU$SUj%_ȮB|3,z/))PW,,_h\R|!X *_ȮBo(!3!JÂzGlLi$.X>-sYW]#H02liJVqPK;_>Asd}C$F vgkIՖtNgVW\ ,ÆH nIO>DulAUD 1#){X0ONjR N& Z 0]1zV t zlS֊CiQʯ_+7ܜco&YN!|ů N8}0J >үt~}%q ''nCK~}slԝsd Uvcu v!Ks~ {J1 |I nAa2aB}+f~̈́EMb`bSxDw F !WuW=wYqrX*QW&W(!`Ke{ }#.0`hVm=Aܭ=`? FN ^Ox ???KܽM{دO+CF{||~ڟ,G#^dm`KmcK-d-ƨl%i,rӢp^k.sh#:.(Z‰PabbCSaO{r'[ >CIؚ-mUȟOOjנU_'T Z4_Xo+eNǗbMy'fÞ <|ny~ 4Ou~L􇩊i 5d-_wNCV&C9d*"fS-B_>nV  A.򅪛̏/\%Uk`Ru\ݭ۪n>nz%EJZ?~^b{3lwqcp,-?Uy ~=7Ib76֛CW:@'mǍURN1o_|pD)/?}?x,gώ=O!R Q?a禣*-=㣣k5_pd9> Zr.?p4{tA9YZaͲfQs ϡLcw^'F(RnpٮWukϏ66ųI|1i@AM`gLVLBhyK3oVɔgVCU|0*16U^I]v/׿9>6JQD(e=!Y]*Fsds67\yB<`U FwN',TO?T!Gcp")rJV3.i@HBy9^~Ol=5S{@D#HO2Ol#ɐȶu(v)aW1S=F} v /0<7t*tubƹ }GL{˓>K5w(cumuRxfY ;G縹潆0F6ɴoZQqQ(=]ǬڕY!R5M^sRרB_76hY*b"v5>G=gQi3'2@: {v|`>H2t $M/xLY;7\[rL̢6]SA6rР2S .)+_Ps x57w_;G*;-3!|"gex|[p 5" zQ?o-boX(>3 xx5Cf6*#0am;DlE<-"oi V?W3g_3D<ٙC/V7l Ǔ[p'46>gͅXJIs<9>^=2`EtS ȿXFMAo"I ~|LO/3c׿3~G̖6 ˓ [B=rаڽhp FlY֒}; ) 5V29QoK߳8y̤i8>lh'suuPSo.|yns;ڒN(,6j>wO1OWK:JǵZddԊrAXu&Xg /&O^{7jVJi2+XGWDp4B.hB@<ۙ#ыͰ& J6A8V En H=UM*D-א8JLNM~V V[Z-[-HLo9i8NinJ^M r;Uh7'̙i}[^Y \TVz%L~к{c+Vo\q9_YTΥIZyQNVC&7ۯ̇,MUVCfGSYKӯ.L D\PjD?f]"ͽegry -'AW&ձu)MwVdV*(!U GUk?N9*oۏ߸}߰5(SygG.~އЌmh>pqPUz}1xdä7Vyu> *g5[ ġ>^)o\%DBuqyuGߩNS{\o7{7~g"ʏǎ0uB_~Ԍʉ%NѰck5N!ߛ%$oK ԣ&vņhtx/;~ /ܜ o m}$hr}\ߘFFŞz7HB4fJF feaO6O~6+}եB% 6 K DG.8ibn, ^}6@4b^[{~Š]ܓt$ 5`1p-c_T n-^[(%¥FZ|p7.@E6 5p02[8X>%E{bzw]pEM/ARDf_+#)EQ"WM@YnǮ kޣ\ sְ;Bt[jy5Q=1;RÓ[SJ$ä&:ﴝ.3i%@]GOsvT*Y] %\/:L$zb誉d\&/ G3 tpyydwR/ K\*I[^0o|phuzR,A͞~!jG 0*)BdhRGwCeH-r,ݪ!W9Qog.#26J,3)|:NKth*bx,A  PBG'wv1*1 Uaka :_JPu F n-L2?iYH'+}#Ku˛]FKR,`_5`&gpw% Zn$#WS|A!B.a7dWDڲWҀ{B3ʱ]~15m֤2 aWTs"P!غU_Q;ATYIR)9܇ua"g"WFKV@bu& QIQEw6dz͗ FFpzE -&3||mLqvo…+t0:Go2p2n4v6(3QBHIaOs˧Ig*rb47$Y \[ Ȍ;^w\7sD=5-7Q,( ?93a>Ձ2t0]# T}'5'DI- 5bH8gp+XF 7x*>&BhޤQbF׺db nYØ{FE1iPLyH0XVEKQSit9.$7A!u+Vj}#,u֑@+>(jJƎw09>y_Őv~P?`߿ Ʃ չǛ)]/T5`==#2[A66dhFH:H) f]cWa yܳ}Dr! xVGEo_9d0 JɰYHFژ[Jsck|qߕoHD2? 7Ѱ^D9e轨sHi@<6 6ؖŵJh.! ΜE!9p(pEA<7g`7hbmci ҂LL%CQVS#pg^*O'D=qO K>. ZQl/6ND,3Jr<sLk~]%]ɏ􈹔M\=j8H*eUF074s1O`P;L8o',mx=,d tPkכAo_{RdLL:q^F7?O30U g_N.Uu'T6w"i j&00 &xaR?FC1 b奨q?mbCNvc9> [^o͢Y>OKZ[1!3vKe肪LKKŞlLxw!㾞}}X3kI} ۼmnoT,qQsƷc%>;>K-P-l>s.)GcLcNiGwG_p-:U,) _;~h9Bلee.3>HEdc>/u*1gL9/Y(Jd\ LH=ʨxa 6?ZNvcD2)#1-`" տ'oqmV nX*?ԍ'"cXǼZ04M=4DSvN '$cxAON0]OqC !T5a9@k.+,kPgΦMq 8iA4 wvʦ"Yc^L鄌sqlpΒyK ]醬ߥ?VBv2"ixu 7`Mwy &cY ëqAWvwpCKN Dtȑ5>Sw]2htҞST6$QYJL CrO$#Z#9ZW7S0GC0K.gC [PsS<>Q/0,`\^|Jє6)N{JӞ"i^Ɔ:*{|emV`%JvOZy'(_Qocp9+4b%&-X¤t%uzx7 : 9I΅|(b![<\CdXZ"Cgv$(_ӜFnCGR ke$!YTgO1J K,b,_Sog[BXMgm ^⦵wGJbAD=:-={MAN]WL~g|PUow j)>SZ[݃Za+{BU p]ݕuF?J+B}ɤhbKK4q f[lme2L•=t+p )ݕtcadҬƬ>qE EUk)cm047 HS /`gQJR潾ѵ]z:_k,'^w7P jOxbZP Oc hv]ReˤvL%M¦̏i{mg67:2c:x b]@;R!=׷?\lhe;spҰC'9fNG VKhO?tg1aPՒ>:r&Uj*v?3~`i|"#R{w#DŽۑ =ԡi\anC-4XkGvqLǀv)햪LS /{nGLoJۨڧM:^XrˮҦƮU!GqFUC9I -\(HMi -rUyxe?Kˢ|à!X=+ 0U1DqοmC䃪Av{ (uv +SYRSɧ'nА>Jej%S#g(JA=CU.15V4UuHh\L]z*j:Dl>vD48Á"̗Vaezo`DH3}ZŚ[MQ2rL^([3TҰetuт` IqzMFE&O{%!N[R',kT#Fmu$peɹ-1̃P5<0k(,aj w#(xʘݤ3#QŒUc")*狽cQ#Գ=lxjGT /27:Zv5 yuQ~pM_iϡQv3@b $p0]`/ PoSc8r, a|FKڄ_lS,~wfȪL/#r+a =ŸպNB~zod>x1f,0愨`3wid)kjCƺpmuoYU,VC9Hʾ&vh;ϨرNΩWKeE |QV^|PA Q p{ EJTB.6: &/?9~PC/+FL^ Ppv$_eqˊ!L%mƣ|K;u<%{C $P "`HY'ii9+n2qu(STS#{Fo<^ Ж ʼn9JE ljiwg:yœ[a@0p>%e#Xhݭ.EL@MJEʆ-YHwWpp=*27M*hI'[ݚdp `2@ea6N˛ia#kÉ?8ך"gj `L.n/X ݱZS2Dt\=a91l%+%W8<(~ 3^GNpnaOVf 0i.r`%0t^]WHQ \3Z5w( SSR%J$l4Q~a1i1&^꠺BSVT#|BE0Z;o֟,[SO{|R4ip"!>,Yh~J7K5Uۯ:kӻZuJz K Tef⦸ʹWE @ya?,O 6pBN,N>Oʎn/Zˌ>ZZVsU! OҹRg爀e(a=}>Ȗem{ȐR)-V>O ʪZ%7[t G OPPSYb=}:1\w^PmԋvqPffJGP8Y)KVJuȔ-D.Tj2n~"TRLn1lK&="C_Bs)r&f_Y+\CPQ첐 &U: h_ *,S.bxr[z2$%jj£JyO?E+nۑXrrC3ho_i^.ј`&gkР߻]!JN\R?}%aL RxY`iP&¾6Ǹ[$u 蠉6HcQ Baz_@Ƒ%vRPsVV~Y7xT]M5@& Eb.9i uXhcn1Sˮ/tFb!)s9 egk0DȾr^0c@(,֑A^GR)Xʗ&&h'L-$tR/ATR? [i%Ҭ0e)llwњ"/ bEYW=`:R~Uc˖^ E èD+.I-94ޫT`h 9q@t͚s(eYL BܿTKFR--GrKab|/X} ח^|_\m|ޥZg8jſ BLeș_$*>o̞ 0B5`mǘQg@q|0xszLKL4]GhȾ+/!dV#\0#%WJ+H&XS37-95 ȝycICCZ]Ȱ;ץuⴛIph|¯ب%LyPAQ. p,.ҢZNWn$h^*N~6&6曋~2N1OS:1eCBa+ _˷@98 sumA7D6@wī.Vvi~~D>'Kĩ$2W|^?x?`&k7"?GU~_ZsXM%?ObEcE@',+E3i ۽C'5#0>Z}NJoJlwv2G9Q$.$g_tS3I c-V.fLg+ yulT ke! 6ŬnfBK¢Ä7]һ`gE;fXG1B_3XL4&2*s4afUtW]YP%{o1hA׊<$C3CUnۿ@Lo/l̀{'>،|&Uغ}i^l|iǔSLZXĖ\Ϟ̷xEi).BWI ߟnq*g jI\u-M!_l=GBi٦ab_ds݈cC{h9ڿLV*@"C~C ҟ}eqº(ڣJ͝կo>)vˬ5sRb$Ub͓o^Ӭ(pI499U!l邬şC ARU3D2< ૹhJy)A8o<{uL<册Ҳ}~Y2ze2L[%4jWW|w?%Ft%@3ژ#`v立ދ;oJEpMDA=\.RM+[yi;Zy5S\4%B\GIp3* %z'(I>OQg B,߄BSe%ݘ[g'co O3|}ԀC!%n .3Ir1"3k}aA̗|^kũ7(Oh4ѫKQkt[_KĬ^6n8!YS nN|ƕtޑEKָC6xB"i9$pH1ju?o"Eۏm"u pj$:6o9:A-h_坞J+J~U,鼋(*#ԥvy!oFF~]r^N2bmM`T6:z!(|r=mK, I!Hl [Sl씆g˲] B/95 VQL `Ȱ]Rݮ 7Ȗ7),鿬y ,օ!$D(M^͏J`깋A(๔x\Lp2BeFг3n{%i_,dԮuZ ߐ,=Է)UnC kؓz~뙱~HF5 dV`]ӿ,7e4W8Њ- 5s]Q̍{`))Bfg;>(ih5;S8?ȵQVi4OF[$( Ίw=@_kHF5yn! Qn1E=ɖ`_`hLVg끲곺!v~͒ZeKlt:!5STQ9iJP;]XMFB@͖{J(!Ǒea}oBF Gaw*to'ز5;dD,^$ 7MHϧjM !<&Wf->Eߘ_VsɢO~#O  qz,34 6Wlc%5gf#xXyTM` ]U]fvOY}3y\;â w+w3*;bJ Gb@lώWڴ3~ ;{Gvмm896pF$ bʴ#L{ߺHwPOm͞j*UMsNXn) 3$-0 v9"(,ةK`ga A>\ؚA %dQv=]fpձ+~k YyXs6gG\ȈI)?*EbE ((f&oNuahxwk|'!TӒŬGSv $Zx]B>Eqa6{(ApeiZٕ-_c;gx)e GA|;%ˈФN 89c'd^#Ҵem7-ٹ!jP-{6T²w`%0Fd`*x4jYCA6ED,?̻<%~\,WۚYe=Ax ւN$^]˰q<. |?w@q;뛐|f M=^94#uCd!`))0)1J_tb!̬azA3$)Y`;g~O|qT[P<719u T1OCK٬B!/+5umWwv\eTGԇLWZvLq0#? ӳs~GNы?g%޹aic<|0w~88??yAcrև"ֆ=tȊpqqY0@3jzK%t dp,$59&ceb ̆.ømmդq5#Jġd:k%Ru! l#pwVZ)_ ܈}G Shz׺stado5n&#?muvDݸx[c =aۦ9.Cf߫ =)hf7;եm$L;7` `t*&k; G 3igk8Ut%y;l؇3UsHd=ЅqrQ8t߼z?Zr='}`5Z3QOvk<۬FAˆfS48RZQ*R?26~ [gvDOeD (L94W$IgpItE,j߾@ {FzΛC*["MY"}+9@gl!꜕aqYhփE3|F r:井. 2໎,y%B1&Ekys8(zb鬑a i=NZ _{Hjw΃J~pFpsr"SX?Y?ʭG zͣFr&d uSK*œ|*q"CX_L3rNPPpǁU^<7 ${$L`%{N+鴟&Se L-N"80I֊YZUP^^>jUW}PY8OYqp% ig]_9%:>+JĎTҕzNeKGĂY5qy)x lwNaRrTavN,VhuQg0@d]Τ"ݸ9(O /  CI"cp &[{ol>jn(NG}'\<#0Q8*.@)폤kOS'RBe*\29 _m7 GsB֓mWR ^ƥ l|`](GDϾa~ uTJ >gͼ%V1mĔ>n6׎GO"A݅Nrr^6Y;gSRi~}<-Fؽґ\8/8Uڡ쭙yDzI١V.,a;o?5nZ;nȺ73BnU7qt$JlUރoĴ|B8O1#. !Dөa'ĝzGV%'i *<ǿVe*1)@ݑ$]BGLPvE]x~URh32B<` qT=n nY2jM>0[I vyJ8km|A2D 5T^NpX: cܤ ;Ut.Bf@FU\;vj5|Y <~|ird9'IvGxCSs:{|=sri#?%xY)ʕ 5~Dy$[j ANQ!~{@([|Zޞx^{,ZpXuY[>ޘܳ{P[Z½|[3q/N~1'8p<lub.mb3d=N[ aڲ=Pwb8Af ӡ2n%"`th``<5lMMObtn~B?'D0ĄAa%1L;0ܦD6er "j2 j1L>`tR,$V$G՘Yc %GNGBe| 8V޻5._n4V֛5+04drʒ=">wN x}U0-5횈ă.rrqmE>dj.hF 2Cl7ssCzlEMYThǡx6ŭ9b˔m7oUOl=`Vo:"do̩ƾRfepTҩA oxIt?PqX8HN=qeM+ҎFH=}l|F$vxgs] ȵ.ldBT/YZ8o |tgI/Zh_?{^]\KzvIoTJ {{g5@ :s5r0x fm;PC3 |] 6SȌbt'C>%Q$hTүu:zo 怸"|g}aQ%G%0>pcSdg++q~m1W ;!(h5Dc:Q "V1HO :迳d\8`Я&c k"ā%j9D[-=ܣ=\mtT2he'K@+xCQ)K ࠵nʉ?$."0O>!kc_H%`!nP4 ND"d,țR %!\!.$p80i[>ï3D{'i }ys `.3BةHzcRn4th =.`M8Z'"l.HyYs8[uoMH?qL+8dvT1t =4zXr q9022 [ɂRw}L@ / N/e,5ytVa>1N+ZXisWkZM@YӽYgՎ˳uJ6r >뢩PG#u|伝.@sָL(OeEE"nl8ƭc74ŏ g FJ Kc`Yj@䱽U:2Ol ׀?[IׄƋSWۿ7z;|R ap`R%]?ad@^ dH-.E v[B$0~MYvѵ>=+ٲi>:(ޠ= xb\7rPl}x-^Wb)2;; Wbkei/+z.(5-L@A]:Ɓ(v5_K@W|늙SvURwݔo(/EFp**T8b–3t9mGmKcËm4/tqf^٣ᣆ ׳&UȂG7n[AôSewwt=n\5._toƆjBkVrTnGk6U]8{U_~30@WŕkXq~LwY/9basè$=eg$Q;j#dF1!7B& :gDk~ɵշ;f6=XSȁ!k ҟ|Q] <\lB!;k)KlB3ز|1)` V}Y~<8UgĥPe>6Ƣ nҪ5I?%REl\}Wm+ٿdQV*>$b/1ͻi뒣 F L.R%R%]/wٴ}bK9][<<M{.FF;`y\h/՘-p(?)k,3‚c!s yU*F&0wfx [X᤼ı叱 Og-NSBUA¼цi_3 ~{#ɂZYD\#&96,wk/X#펒|E*6Mc00.5V,4v(0׀.Ar{/rX; D5pvwܽe+ ƥz` 0 7 kX>5 7 a $5*27DiI u]}!އozv*9T%zwjNCy;mWJnU-Y2Mz<U`pzPG8-8qqʩC' ԡWsEN"Ց(Y^*Dz-YYn_4 hii Ce,JHyTyLN^mn!If=QЗO!+iA Fkjy I 8IʃZBDA\rR?+9U&,$ձ}|*w3V!37?\ L}FcADVPq9ԣ\T6ҧ4i{dt;(6nI=fb{J X-z(AхŌpQ-p]&^&κ@ߟ( V -sw3OQk%,Jǡs29)G &[oo\P҃)vI.SzL=r(X{P⎕0:&*81z*2~mLDP?IKGop5|EL؝5ζ}\g`~xAځj(>]LᄋTfѾt#c{ SrP*sn2׾̮6#E9MRIsV ߴiq"VQNv`Keyq9Qp%F K` ښU0}@mEzry?$yoT\AAq2leC&#$`nϜjlrK0Zw? _څdš+2C^ +NBO)+5sn7e7mo7mC3'52:Ցbox3 )tKa CxzMv%D~ǿ:/2ƴ.1TvcԊL/FHMv, kԩ^6yhf,0wEeD QIJ8ND_ qUp)$ׂ *i)33:]K(X#Sאy3HV+ɦEÖ,߿lFMC>t]ty~QSRY/Q! PXwHlة䧘]Bnj NYgOMK/s <]}Xbm2Jnj^RP?[I4?L8pE&R\˂( ]ruI=ڌp[:㵘"R}+U;7P_YnuO^Vu_J*WO3h3\թCАc X8蚋4$4y[sfwQg~gX緕G cW8eKq.紻 KFCcs3/!Ӟc~;Iŷo7iFofE+ "®~4ze|m[0 =:4K\_ 5%hmƬx0pfrm 9Ɨ}{蝥bQ?VJpUr|@ȣ3cWo[39m_ڼ'mPރQB *ɖ~~{}O  ! r tq)袩XFД}+/=KBƾ6%:Ҳ |jw㷿rk`  P/`HVËG a{Ji މk2 / +g8F}3t~8PM0/WZ jaι8cv{x6*8H:ƲNqΰ's7N?i<$BOQjYA-CI\Ռ˓LChc?l`I1 GF$Qo1&ҾKa6 gJȆY.|z e~>\|#|C? }[FPjsuR oeolW2k`Q?ƃ%? 4MKw졬N'퀋UۮALs=@9\YaCTX%~M":DQZQ-nэVr2 ZoӍjF=*zé#ba:HT=JS%$`%HL麺t NN6XA++Ԯb0,lM1EcAjtETOItcƹd=@Gm}/f:OrЙbPd5U [%KrO>Kv'8:iY>q-˺6pWarg3t!u20}$cmZUJB] yjr S)!H9!b!\>+H-'t\2]k(̠(1\_|r V` ޺nPs70D9<,"!ƓUWL"^6ω)Ɗ4 tuqqdA]ӅI P3kqZI{\nuk> t%7>7nFvG#^Pޥwȋf2#Jg! rj#: b%iJ.NjdD^2$@Dq[.,& #V%Ym@bQ=1#o7h+P3|(/]-ܢ{c+ T†UZQxrmkm񁐍_O^kǧy K3P1"aC{ 'JFoP ު5S< -l dՠ2pPCsW_ *-˽mK?TpvUGr^Ը/driWvN.Zb$_t~B QBYCp\*09:^i6$%siax`Nm˛4v VT_ XnD)umgsĸLᴰ*ҙ!xn# oI~&8E0_ڛ^ws18sC݊9.p|U?wjoKps/C1~3׫prWl}Ya<IP$%^BɑsU") Nvʕ^vV2r8-y, @qx| #bVy :>>^tr.1w{Kbx}-|^'AKYj.ҳLﰣWpya< $==-i,F^쪊z.̧]{VrBh`tq&79Ra~Y1lQ~(#DhnM(̬:ĩB HCےQ|\LgGyq.9gL"74*j 5dt>37A_V4|ЯX ' HGy mV B> p~\4O!RΒj"B܅/B?v ps}JiG: 9Uˍ1Qc ferPy{׆)( ! S 4;OtZv=Fх֋uIy=|ĵN 'y4oVEN!Uܣ?9Ǔwy@m!g^eI㘘a.'FJ(0";+eEͳ߸e8y溉-ʠL.z:p^2։>AC! 6TqokC Q[Ĕw-^ 2̀<3cUs?Sq3#n.;@F8M—˴*\ةSx@iIWD\gD7vi*ձ4xbJ>bZ&JA,%g%䁓M^VEKF3ՒnI7*Oݥ5+|AΑ1&O^ç)6yANm(ag폡xPO+/ H+/lTy/7/U!9wuig(c,tPY/1 Ƃ! sq C sTZ%j*łj 騰He][wXMsb w҄= 쥙[ ٮA-hӺh aCW3VKۃ1V,hYR+ߖL3apo}wͯoZ%K-+u~WJ ^FX=]ȋWɪA% EG!paveZx݄9 ?s; f%nwns\>/VLEdrkGr ky+&ר`m O,,:=C2l@JP!Z] eQV8NZ(0soz롄$$ASQc|nhW%opV I0F[q9JcE`|_PY2&\8,P +v•%ww1Հ/#0t4ܽ9ǾzktB`N2G+HN ^eUlcG):"A#~nq9nٳdԠYk(i6̏Jem3̿/`RR:1'㕕+_յ+kϖ59f><svֺK|aZZ ':7?./ǖ̅!|4wV{NJv ?Yi|e.$"Ӷ/_X&lE} 3Opn̳N,3J- t#P,&h_tlIWm8m!jQ` *M˶[r5/Ѭ.sT.fkW7<эD+q@A >8ZxrEՀb[]0{bm}bfIΡ0)< 6AVDJ^ WRB+6wCj\cdƕexFvWjNzO{8P  iB Q1Drڒ6 ^=,1SsEt;7N~wCQ>@QG)ڟ%+6QϖbrAiP:#%!]j5C zޘiL0jx SW2˞HuўPjR 1p E PKc\Q7^TJn/ ^X+]S\7^HJ.^9upr."\4JD &jijuA<\-( 0@b32̙B̊(:ٖ-#'Oe+ZJ3l`t1y 'H>{UZM|\t 'f޳`nGYe lp$C\I}тҒ0uL#ovO77kM~՚vT-*O( mvom@klC+f WH9%K ƗYW<^]^]jygH f{_hvV(,<#'9&Bsqex3|di~l.^Fөo?ي*{oGn͌w'2CH]ϬԺRQ@u6pI>BC 8=R8Bc:Q(6(\ ]$=;QQ|:Aw,n&a?PSFYϤ]9iMHUIc; iI),\w[$I8s 8b?ڽ2q*bDX?=0x <'BM9hZ V cem~ohZec:G6)O>jlL$&=l FP8{/͖ ed~ }<"~?O[CXPs\sE .qڇl8!k~W^xx;}el I jdy]((_4(dZ4T\蘮[O9 !qL3n])~sW8}3A"vcj揟';֋'voISW<&>G\Tɣ3QNl/2˄f냨H7}yE?'ȗk/oBY .ݓ? &BDW2%_P2 tWpv߾[3$9!l_D6OGX.0PҚB(VlC`1Ba'rƅzEX8 C<@g5zYad<,iz)szVE爄K{NB5IAWgt/lofQzeL^\ק% 00˗秨w&{}!x䮱"02?Ə?h8|[${!-#xJ{[38&^z"( Ҙ 50^0^8x3]sytY r)9Erd#: pY1e}\Nop[0ؓ3TqO{+mPA=XA" 3uGP.cCѬ N%;Á!5Ř2ϮDJ l!+&<ʕ8JYfKp1݆ncuU@Rve5kuX8QeYhjIo `J)7ȅ@s =+xRv0$OΫ\X%oPbˮB'pC-ݯtA`^=/h?)kLNT(̱)C^/Zm%@v5M6J.C:V}@Q3bxp^Yߑ8h1asOh$%(GMPphѶ[ D\P\O&4 8)xϩB|'gw[vnk+{P]5ix?^A~Y3.\P@yPlJvZ}r̩҃ [kD pKJl(dSE+U$tPp'nBNuUsdߪ{v|x^ ` ?pp#/3Zt* |5;bCB@,`4ȏ4,/40R<<lxІSP[*Mq1vaWR1a9V@lDsT e_wqG˞ݛ5!ILjħe˼Ւ9򱲨I^*%p@{,z=~UI 8=Ax _`s_׭7B?Y/vi9hK$+X[E0G]vLOұ5R{g&I/MmAr-I Ɂ@c9 n$ &)o,ox轨ic(L]yEyq,X=b<ۼ N/3*\j:VE&XIeIJJ-k9 rk<Nm'(Kیw6I!`q@ѨխmWTN o`t|f ŽqgV]+*TQN(R.0H "j5";'8&^Ce-0 ? yrQZb{/NΜg}{Hn#҂JK)3E;.\B]E\Q3u*-Zfpm D<1'#cmdR)@>_@s&HwDV:ӝXhbmg mw[ހ7MĀ+@coiT*\(-eYg2RU`JcxP6al%`;<5y91ol5UjWK1%3mO!)ޏ9,ZnW\C-32ÀOnkqw^3L7iv#.XK@,M#Tʁǝ!Ǥb3cU3Tä_ZZЍâeMEo?yWNl[0.%(´y l–_7`(EJXy=~`ξ=xzgz+¹ЀIF-r#÷O'>򞄿C8xHM~m7:G߱Jj5+BX>GhtX%*Uϊg P36'FPae-7/ r\ح{\^jG(>鍡]ҡ`B;SfasvhAGUK &o&: 0h>z|l}n F??G94QjF@kAKJme;,ꦃ~TS+91*F2ssU6ȷH((a'W|!5x14ֶbw{0w Rc9nܓ ۻ&(n]!xfy>e>y>?Г2l-%3j- sjs+ȢF=t/+R!.?;^\=S;hl=xz ~?pXgH6i;y`gǍGFA=A8茨w"֣k^(ˆ`7l=H8 -3 ,ؿh됨)힒krHKQVcP8=<6w87K!<ӏPr |`7M6w:@swHX|v"j]A3)>.xz3JRPm`{\9_P*x̝OsI]IG9Uj#Oycx 'Ӎ{-HG7]+R#,7K0X[]AblmrRLq /h`Y֫7H&&&Dpu#tCun hvWfYI'nxg 4`JUzś*P[]'l_:_\|gV 1Uoi)̨TQ:_ƀQ'K|24Eu`g 5)Kͺ^_1+Fr%_%U^vg|- 9 3|xM]{ilU۳m>LK`t:]-I'br֔xA:o4 TFfl`jI>r>Q^Gג]YLi)Bj+lZ(@뤘j},ڲO^{L; kvBY%L|E_o-Fj~s|a+h >5.= #ޏIb]ܥ4;>-;&I;722yXİy2X>L=]at:'M^k dXpOŌhq'3Hn\?[;M1uD?؟^OVio!߭2jJq>˷)[Rt"`'Z͐mj=nu I4G(/wv18n;ogWC^0@ xɾ{<xCD*U+2 E ~>|U.C&>"H/HTsa\h[BW0fRgJȕ0]SLR15 }"N}H0M"<0iWT6,qOy.X QVm)?6. 6}}eӥo]Vb'hG|_,jD-R7B~G$fMX>iV¯:Jg܅͟?L}Dsqs{{o7_;= pNCXw-.zx)0 #E<򠈴7__ۻՊA܃ /:,y<*}!6>!-mi]y"SiKSguC럣0lS(%r#O'ꥼMOo I;qV,!crʓ)MA -BO).lH٭)P{}g?>dk^m.r,.Tɉݰ'ñ/)ǟRp #| P9#݈'N Lͽ(?U'N k&qj녷3Z}*z^5*,rft ,Fz KƏt;QOVQ{hߠZ˗dQq1gYYV7NM3 s:EA|/H/ jBC7̽kFXxAFt HBA,po0OQN*=D2+$?nu(m_Wyuu$B=*ݜBo=)Ph}:FKpc89A=(dg,vaFtR`=Eht=5L( BC|=3Aע݀qg|pAj\g(UÊۜ{W=]%ߣ1DWC]dv^|QING{S>-}7$irNF՘u v^%PpOjjQWcS* Y :ӽ)D<1 eh*$OrHx&,)Ss7d_^ `nĆ|1u"Dj!=NSڦu׮9L%4FDTz_7P LšDaX~P],Xm:_7wY]yxY^Y[y} ڪՕ%:O/N:W1u%g܃xW^Zmw]P(/a g wQefGAUgFx_c=7ɠRTBrir{?msMmD|X6>{(sK;66LϛpDN'd8tλȀK(^#ue7`8Nɓ3+59q^7ѷ*3SOv;q7=}cs᫯ۏ>ؚχ{y}n/?|b|qpdˋWo~9߳r_/>ڒO]|毧7[+?/+_}ם\'ӏ_}j}/? :tV׿_vI;Ϋލg?>:?H?䲯_my׏[oAwofvlaut*=}]?⇽߮rO;ٻwo}OO?|W/.ozyzzpʎض;Orvqyxxwے;ln~zgo}×iu}=~wӕ/oO7ϿyۗOW0//gggsp78m5uk,ӛÝk_-ы^_}w7y:=.ߟzh/?n}.v>˛ꯝ/z_. ׃xͧOW[W/ts,Ewg_Z-͏O_]?o.>[Y'D)kcjc<æyħdufduEvݲHBpÓq{1|Ag%cЕF[3_aLS9i KZ͆y~]es.Iٵ1q8>$ Õ(m zV+]@mN[r$GD4VVLQ]Nr%-xUjJS|~l$뿌E=Nf"$ؓobٶt,v_.ܺRK^I G_;V%AWGގ~RwEhnx;dz"&[?ZiLʬ`،FLF$F+ۑ$0rtV$wzhjN@3J$si,W>kIdlOCk Y}ont0QlVfs8mig?nIh'ҵƢ}lG=#`fk({׫%E_{1}3n^l`GU2 tH:qJ )A 5qS$ȖSภ)I=s! !}&uC1%`b&x_ǙԸF֘ԫJ^8:YĴ f"kS놨I+5Mc1e[r{0TN)/s$_ ŐϑXSS Zo!sh*oBxTAxٮTŏ MdtwO|قRccR'hJ2V:!i[3_Js{1z^@f8nXC7oEw^тA%j/z:o׻V,YD2KUdU"NY'[VX*"H)x/!LJNw cl0<M ]Gtg]s3j>80KT>oÎWt*pǜby-ڤ6 Siկ_2tW#,""d|ZMUgg1j803 4Q?6o#GGF I_s? Uiw,ReX.k5nV0,/wjj0Cx.˼oudYjX| QBzԩY{^izܩ:jĭ²ΐgh^s).3B+I`?gUgJd✗IH0] iJӘ J/{;"D֣(Rùwsud=7` o [vaׇ CfJKeк"VtE X2?Ǝ? Rx5Cr=g{g2=5lzچcRI^T=C/7 [p~*Ia"-PW jAnˀcd-S'"$ŰD !V13a ا> fg=/ѕ$.:SJoXT"+yAevh9K>t92lɠiVa[{^?"jdn[)r64ɂ>ꐌFr];Es0ekA!`kY?hT䴳{+iXb~PE[>bvB\c dޯrk,bNFYfe3KU^GkcW\73LAY YhJ-sĭڋ7ֹD:m%/ޣ\N@kn 5$-7V*Rn`9 g _]+%P`s(P5}IUZA\&L*l[?_2|}-+ NZ3i' z:s+ʈQ-%ibHb1ƞd[+ҟaIr[d2r^#Fhw  CyHmeIj'(O}5nU[},kNń;{Ge1[mmd2ËGൊd i:H3su;!{ql,({M/s/%?=%J^t41tyA7 '-\|ks!jx&eooAX4ޜGQҿnJ%Gc/a9;zx r c5~-]S"2Dl$,})4I4hƒ ٸ ]vVQ> PP(KuA1I'U$1-aGњ{q4wfNgg?/z>bA+ SIZ] p[W޽XDgq ʢ'ǀCM~AN.:K7[Ur+Zth!H wZ?ڧ|!?&$h*T@}j3%Ƣ<'•>i[}d9. ʚi^s4^ysK{+( `r60w! ;s,u?i,w(`bba(\wbm׍Sr֛x6|\eiTjA fS/d„, F?b1: X W 5GXT-Tŀ4.Z"1_L|=TLtkGUk2_a5D{.n-~ ?[pGgqIQA;u]4@hEGJ& b \Wjgy ~Wf|~~l6/Iۀ?v,Cιo}q7Q# [uU דr_ g"RRod=@-A5؂݃`o3$~ZU豌MђEpKsDGMoԾQiCqbٍD(D=t?i:碜c(Wq>|g ;0~<[VV? И fKQvDET%VMy$v<6b7 e~8jȒ/Ox|*})u&UϦf%wO2ىw||ލ DA{N?9+ʱ-ZIX:_2ǂGoo̞MK0M7>R5m \Ө4+ s^r!5W Qq/*ikv9yF ߼5#y8=eaKn@ؒbFt=*3v*¨R cv(f@*(yk)(]nQ'?<{)BcR^B>~1Rn$uUdf(UW/,ֺS83Gk??K7!rm:4||=\UPAC2٤&~ ^w´`k9xrR"ir =r".)2X˞s]{KĽ@bR*dDd  4\%,ܝt&^b@)n`t[8̐0!K~9[bpv- )?)h![o~lEVN;,DJ˯zk  x wN>۫!I?LҕιS:8wPYdI 萅3ml 8x!U&_S{5 U_ym^k|F)R_0Jܨ3<WU/GߵMt6wi:)Oх>&hbM^ٷ)i'npbTyY>кXܐavS8qҲꌘM{7u XѶ,7oR#vy__RO ܛ=}vU /M\~- ڋKh zZB2[#mz{S 85 X p6ԻH3< 1W>)U] nG}VN }a6F3\g8"M{ !T/Fg_{r5+}2]nTf+Tdr,][K,"pg岣`1lOQ2tonT/yleo/GVy.LE@ RhiI|XWU &:}<M2_!~Q^_8; mGE.H g! stү'h!>EޮFߣxM~_nb1 H0ExvN:Ϟ޼ &tH%1j|+&| a_Dj2 .B9o mNqSC+8:+i(ϫ5G<_ v(kh)XT=հXJ$Vcg:2:iѐX@WA rmc)gAۼ_'G-% @P1;rC;P:U u2qW4 nԾT #SI#9oeex_g2% {ƺD]%Mrk(ީd?G+vu0U. G^5;=`4iL~[5pA.=5icVo@yô((l? ݈w fG<|Y;=ذLyϫ0JƏJ"u@c9 {pg4 =M5V%߄ ~)kb6rҸ+81` Ss Vn D_G8q(ׯτطfv4teݺ7Q)9hbuFyzIʹNЃNA>wީ8Ox8, u·,!KM!5I޷4eR +e0@qƬY(:E)J u"YaO%*_>hY nDK/C7M~mJEwx.ݟ67Wp$pcmwA3eȴhkހ}" /nx/=q2aPz-ߦT%.-쫸eKg{ft2̗!ШRc`yC|.Dn)%8k.-䥑- #|\ PCE%ww(_:]<*#`BBQ٪}U|>`o2K HRs[F<&pȒh mFM.C:'[ZU%|Co=%haћT݉>uq]nPI b^vH6x̞O,<_?u?Ku|u &k|QnپEsU[ŭH/=#̏3μx.-f xQ_t冥l 4|:oH{|Bh'wL7`]OؐO맯3iN/DRMr>w-7|{wjtc*?B!*Vgp@(o%,O2LK#ffl0SrJHA]醻<ۓ{ko7@X^1 4U-!܄-2aZ(UOu|-4ÅאuFxJyvG0M!7U3vV55l'/@vOz32f6}_:Q+-/?'^W:(?mPh4sp1kLb֗(A68ՈdO 4X_l!L u,h~ ¥h@".BU,б\h{bm+j44u%وvxƎiO>=Ѯ=WM#F\.IOm[ ~+ay਼BCn%T;  {aD-\n<+q%T(cuctm)PJwZ>+U>M,㛛b X1ߔ[[ >FMl 䕅 ¬x(Vgm@8xAML'\< /v7$6֖߷-gf3HWUz=UnVt'[ Ԧu[-._K>Gl}.4> K*"<<;6S4jz+@% ^-w?S{ͯ$ؚǮN"mdMmcPIh\'39ӟ48gKTWe1HĘDY@̴ L!՗ykS/_\yzL({I6xoKR6moV7+oj Zk~~ ]D J r6=1kى`}YZ*jf0.)*G/JHQuB\~36+D|G(U+W0'iͪ M8HG)*GZ玢{oEX82WVKGWՃpzյZJ`QU TVT$}4!Gg2_5he*4#OY8؃r"6J8H/-m&@/AbBt4̹x;&1f f&Cm۱5B˭3sXxQBV™%eg0唔' pV&?۝X@``ȉT- )Jj$=%^ Wг.!F  ֮ o~/,,N|3HbО|<ʼ\ai)ys]^/zWPg}G[‹Pl#*`( 1e\S9n[$򗈍m_}d. ^ =e.\ `<ż"ѨrC1g+?4>\b虹r1\M=kdK3dQHo4Qs=+M5IKoyxa~PQ]J!WJ2С5TI/sQ_D9(e1@f}v|bSe3(ߺ.Y,._5"޿< E?ݭ^;4fS_=&>ُ$뜁gX z~26ĴIUуexceF!ҏG=Ԯ}S!)QNb.)]9 ߵ쫏5 #MDK 2xcL6ʭٜzdӣfޛi36I#P0v%,lv BFwҷLemGU EB;_ <$MrGn 1H%>ߗ SN8E5yy$FqfV֝JJQ+ćDen+O $_թѭ|Raי~k6!c6.2s(s'-qi2Rv#o"ϴZcK؂U##}Du%lE@<}?۟2]=}UnTCdMB|*1fq#P>RD㍪O`oaC[oHZw+067s }vX; ƥqa' [LPɤ7r.zA.G.@4CҺ:D5>zd+o"U4H])AGC%}kpw1:(#a!Dq9c*‘YX)qa` %3 %!Aq-sc`_7yܲ.$i;9&}bEmKqE%85?AD$hnahLwq )Tڸ^8G$'ƩJ5C~U+\Xap@a?_YZPc?6:*PVvy +th>tjй(f^UxټtUڷIQzqo |LB-rRˀ]yd'~deC6=Mk fk'izm"}@2Dght`j0 {ĉ]HW1ܒɸV .&ipB 3Sҏ7"[x?)Gya-_ߞUSqe6TIlD*BGOk~}倅Ϙ+,!=`wjx譴d:CQfR\1ʡevjVV3yѺA[[eb6,VeСwҸG&s`o?1<#9gdLYiDPetW0,gN)Ɇ A!l\oy&& R~kH&͹5<@ IMƜ9D!SyK)=->NMwifFſ0d~*Lo*~g EY~E  imtZ=γ ȂJo tEHud%فK فTjqhR}$uNPSNrI_ &ŌP(oӲ˱9E jBy3Ķ׺?2أ?ƂK}9jA~'WL~!fԇ EPy'֨&S)Y4RY~䅆 >\}Z97лˈEOWkCnO̯:iW>'Nar~*8Эp-$)$"mVp'Rw+0RdO;v2h:Ljkl(S7N*&K}Lwvƭ!>X:dF\ȳԀUKk(6D|áT;Ou+Dm H2]i`’Iezоmo2 jbDJ`{ =t=Ƕ$3,Qd@jZạ^3IK`V!bX//WA볇UbO H95[?c+?Z"vĝNneVgH9_+e?7a^_]k,cϱ$. dU" tN,(Uz(@8tϡe6K& g:T\}Z:Ed'3sRST5`PWP)pU’™ZWdb( :J4ӋB%nO毼Lr=V ;/?.D"$~05Wݸ}p rF$ mn͡ h}) KA"05;x%Y.doHgjfP#@= uOYo1TZ IUү >I"ox]V6q+$l}$dO{À?Շ~4JVxhCHBiwA.+UcŅx)!H&3ew1$Յ% U)޿<9:P>y4y>m=%;9LfHQMxhrskE2O5*ݞ3-#0(b. `^w$2I_ шqRfܜ-v=TL ` ;Ak%4l /K<}g΍dt_g4;1tySW*ygo(r)o蟶kZX'GDVMoM+gȣ2(~#DYp"IN4:I?E/@Ʒșrڞ>:0~2T\:*JF3r䊘hpX_˖ \ʜXʕߎ|=FX #*9Sc^~Go;ĵx+Bcn J`^oYtߕ}306t4k$^!*ZSbO%+twBg U<afdn[@ٟg+ g QGx5|*V>EH}vORnH~?_o[ͯ VҾpffPo^:B?/xd*ރ¸_y}Gbs'`5lmC3CFf p`eb;ree{_f5tމ()/3􄁼W L=d #Q7J@ԕ%BǙ[st$&t\ HK&A]xd]H{Ɇ~]ʴ9CbѮJ0# pto8bu}֟``jI(# ;cg$ay "+"bo{ 1Oೡ&e-BP{ sRùJ A (" F725c)ܔTv("v2Fyϯ wǪ6 .K֛<^#S+ll}k1Oa9H{S;& * Сx;xvwu^GA&&_<* ]%*V A]W`gKA&D *}k8k,L:2O :7'7v~?3 XBW`6MoGqx*B[-;VsA44ߙۭs_OlAB@ YE8b'>kXw`BY|b?~rn[y0_RrD|,;ث P1pITX&1ꐯh?$V_\^B.A)CI!i 7N[tߑWSg@tF*9Q~`[!-;};+>9incܱFThi :z\VUz^)-q,G`C_Cdɜ+jw;l#2ϴ~#.‰o!-#sDdmz:y< Ju.:̡=G&L}˧ ҬհJaXYfHyepaҪ sU(68Z~1.gMB?Kw<8Hh/zu <0|9_(۠ǂ?M6J24rqܙк%t MLeEM +u x 02Š|=ĺ1Y{у 2oŽێ3 "| %:Ly>hLC~Y@y=m3T4O1KКiQdw8;PwԞ ~Akyٝ^E !JȨ-c#91 ugU]&LkvԦ!nCӌbj U Rml0Msǁ5U:P J)mÕ>TS,?_+$8IAEkE\7'yTb?K^8k2= ɍSoRmvL: oI\wF+/{##>tQNΠ"mSFw8:(4B45qP؇EWE'/Vhȫ66<:G oް%Tq @aS[':gk?xQ Kg-  &kKR*LvvBA{>(q 0'%-3zO=p?K ~v5y͠;pz;# JDH&XL ʂ.F߁9BVݎbm'Mc:DROOicpYP K"uM򕮕B")LW׫?wpg.M`@J[UU*Pf_)Β+ d'=uꄗږ E,Ue1:WҲsE`ǭkv3$w>]|eU_ΜcpVn̽1:OJ1?&+nTXi QEhb$F}/ 2st/d_C/c'S{rWW@/B]Ŕf袾Tx_;>bv'D_Uv||5xa:5 䠖@1+fvͬA ٳZ@NPBоFRP{ % l5MJ1:^uyTW6H__7ݢPoTZѫe'ʓg[2Ca7C$Q[<]%(r~䊜YH&>AȺj֩|lGi*)A\{üf_wX+14VI bY]THW*xq*S){v" 4~MT$V {W6#93V=CɜWC/4W B7/z~( ~[fHUMZtXUI ;Mt ׉Gm?Euy3d D'}2T?4#9ax|1*;z,0=~$ 6ҙ>Y({L MP$tNËr#m`L2\TÈ.+y(=VNҐ{ &JU?!NkF7fӬ& =]ݐpԋ@tD/vK p|$-d xd9o3"N|?EhBP&_ˡ{+w-3Υ\:,[3o} i7CSðߦ%8sD*z0h@H 6$8D5, OLՎRѿrH$i2Jmv\ՁV35´seQG@[ Um"iȥBzHZ{!Ar;(FlDIBy;[6hS+Dél!]y;YTl`>7#NIqR85e,ɱBoRLz0SePb+Klmh*mE&Od ՗5cMwΞǪS'4b(0Se)1&/#F\R67Ȗ-Nx{~>H"R{|F.#Oa#<2CÒ݁ vVo"즄 0 x`7܎QvnlOmɉBÃx Wׅ=A/e%)^Y5Py J?4F9wlL9ĘL6!ҜX{Ѣ8{{A2P;&QgU(ō ZuzM꟭T^BrL }^~b$@N$K kwAב%>Clؠ:~yDdR9gnn`=nxK8N=```PH4#OVI6AbiT[eY0*`דvJJnnVձF'058RaR.N,bU7ROXhϾ( UdI4خ. /Ah>$5oeCf“dŸIh}mG-/No w#.F =ċuS JHK}bPŏ8^E^%wѽ~QO Aϣ?|/&Z`~^8wQXaX;@~v 4Ӥ *i2h,*Qp >^#E82jΔҴ9hjѯp=wTPĹ ~$n`Q5L3ؽͬT:3ݗx~K[ ]bt=yžA 1ޔB@LCsnAFuUV w IZ|-`ɡT +iSZI%qlsri̴l S74}o)]adFAqKy,B'h- <*|Q}DI+VهP^rQ(BrZf*b1k=UCt!_e.WFf‰d0(/#NKU!4ݧG׸d`d(h"nq:Euӛ|`\"C03USi& /[a>TauSK<_`4vįM}Cz ;92G(>Z 坮w&:k΋mŧX=Aч ģ ɝxVF;v۩R"˅U R#⣦sAiܧкNsJxJoD7`pw5TͶPT}xu$b [[&?uD3U\w./rp[؞"g~t%VpO[ =7 ϲ h> VWU+oӾ$}wd[U:`L L[+:}d?bg>2?`{ r ё !&v)6S7Fo#d]x 0SJI4&Nyy1$~YUg%%m$) ]tSԬ/| "= +t1=7|Gn,Q/Li 10 -Gw{or%9 n`79pG $oH;B|lcB)һmPgSDhuM["tސ uĜWҘ*7ȔW:5:G{^&i "DU5֍ٞ}gvA1Py|7#;obN `5={;NzVY:[DSfgB77Ż |+kyC?6Y01Πx%1m)ENsQ>#c_z]ϒPk}?}ܪޯMR{v|'gXOk pS6i&[XX6m4DΗxU/r۵GAxEF:~~m\Qj> KvI397Hv+shIQqNPz2o "bKeyU NNf8֋ n> k8 ד$ګ 6|1 o3M#$gI[|6XM`W`TPx`NouJhg8zRoOyNm\}P˿Cz@umFv`.Fn6G g:'D/'  bH-1[}GlX>C_)#jgq> e-iq8| =nf$Vl7B2M_(w#ZS $TlS?>d0*84<9_"LFmb1"Ы,osm)et7U U+seVr<+fco՟I륒kcܹ tEu; P,P~YɨFK홆 nhYzs[/_`㋅@`)@N"'sF=ϚH[Ywz} Q"«F?SXO~e!Q}('.F|-PZɆ=9F[ơKWPZ(ˊO;xGF&6 a R4r;Ý譨 驪[}!C| ~sp%z``w;qlI 0Ss凉8!W >  S"2WVaZokУw}t_ _}S6 ?#8 ǛhP1sѣa&*A# T.2OtF@e-~Jz 1@ϔ3m$Af޻Rn _Gbp\uCN٩?PFQ2w3/;EEW{(}ME9Dܔ"O S^a}-GQG揯$ƫ꩑Y&T@ Z>o\p?ES&{jO[GGrcyL@h2~K(M9$?q)]FK?k9T).v[mw;[vpGFm(Ͷգ}$w|owAWD yC?궝 2 \6Y<+_DϦo.V4'vʼ A/JE->ъ`mEĿ=/O!DI[=zzTTW$=>?v.y;xDldpǁ㫲t91(I,Q+@e3n|-0Kl?tHP 5sok1$suK(G|#2+/¡$X66mI4Te?([|y -#]/;Tp$ SlXqH=[e> BO+ m_¦6DBGG=vƥ{Qf`ƺ_:8 >ԋ[F!{$?7dx*vd!7mb}٤yD`{ajD򭍽mz>B^-Ur 5\K~9z{tZJLPt <98r$ӋCHh&k|..hq8Rx1[ڷtR͙;z;;NU^ߟF3h1 PI* t<<k;(]; !]WF$E!8Uo~8EtͿ'hW?wLҖFXL H뛶cO?  )5~bw.6`IuĦyhԹ#9[lFo ?T B=A[Ͼ˕d@Zmqj[$KV}=vYprfl9jNMHx=gKt!Ip~7)w} rzƤ(ȡ16];`˞.+Ԛf3ӷ䛌KpǫzM4\D`J$e08Fw]Y@ab@"boc<"4/mj޻DuܿJ_4Ǐ +4MN*k$?Ởoι~u'+׫JcDRI= `c9Òf}#67"}6i;tfsy^T*{P"6aeYxI<H#9^^'޷ XJ E !;qZXy9C6*aE+yb~=N9z*$_ӠYwL$wO)ۢ(⿺Ma(Ϩ;~z ^{Z/lsþoߔ(Z4zjf{秳 qIfXgi2acx`4-aB%D޾}p甍b/?֎APf0ٝl;/l>-p:MxvOvM}e}ھq M|𐑪FfDHCC ^4AbT.1s#)MmaS p#| nn)^SR ۜ ^?˸"ٰQ\VbiYi~旺&EY]{<`r _CV*P^4.k'oM W^$'?3J` L직׬e&7![2/UR$um\跆w7U48Wf}ؐ667%D]{k^9̈0Pҷ(A#Ɋިw}ݤO*'gT@on`oIqzZr)(ߊVª/^u.^i"UBt.RY[c9,TN{ʼTV{5oT.ޞ{p][q=Ը#0&߈橪}&"Bձ|^ #w}mMG͆id+C,jCRhT Zp/Q<e-Ciۧo%}BeX\ШS}ȧ ~c_ A ϳ<9؀\sk+%<P>@-,Dk'pϻ0Վ?J`[̠7t ӣ6~N\ńN2fGQx(&][ۚQD*?/`X^CT$k-7GsDkzjwv":SeӮ/1#L?5}?]`8 xg"}C4tVQP> zϲ~,{vXe;/Yn؟GP"@qjlL [Qjjx[բlٽCtaP"g8K=ǖ8iXߴR\,) =GO\PU8F#z Ϧv8<ϔ~Qb\kPjC!>l? B} 66!͵= ljp9҄1k*k D0~: gt{^}#|}T9^-PFJC*?9 ]5 åY"zmv}SEqǵX1}CZK_0,9jEfAM|.pxZླ>h r8 2]l~CViKhlka"?LM%_Ά!z"?a +G3zKK @[%Fƅ~H1 eATOO$.;ye^Kh C+M'+'aBs*|k rxU6#GK@{AMT"jtcO5d!S`y^B%75uΒ-xBr,`z;AMv|HԱ ~$ߑhJN!~s<*= e\6ΐ 4ii`zE7~gF|R ;?¨2evIC ȜlxTԿ KuA  ϩEW|"V3 Utl9BQYu=V*UZ\ `9㊢(Sjg ?[61m&ŗNa}~ l5/~fB^ZDi]#"$03u[(T:#||i UYalZEc`&zLrDeQΪvnOQa_2򹜯GC]^GJ6*j"+pST@6cW^tH2&)z/5C[~r9hXUP|H`tewikjuj5C*I ;8!7WGCj̸ywHg$H$9!0;WIN6ﵭrQ>D%rfrZ%fRj$ivO>k_\eԷբe= L|=^@U M XD;ey7",jI v\c~mJy\ 爼}"4~U$=O4* =\3fPQ pe׎>ߕLV"_%T]~?5O<5 f!dɁC k푘DqˠFr4e~u3&(nFhv,oYmV},h (1_Fux{)eVN~[4ٸ\'(uo[*Ӡ%0S~px|}UFG5uCNeࡆUeO9 + G:`V~u=Kո2#o"J5r\Ce;tSE?9GPPȌ}M𧘚cΔzQ_,[½?+vl k؆{<+ i!t14hߢ}nqltTz§U} YH~Ks @2ytF >O/(ZJN؍L R R$jk.>$|2YJu+'N`>OX+( ZA|LЎWF7$ K51֞rGGm_^tI̿z,A0$~4ڳi'K!'݆g胦=!DiWV"}9xRDHS8)7+`?=RrCIE&W#I8Eg04 b<PlR\ҋ‹5Dv$g1VZՊ r1Wx%$] ɕ2tRb%e$N6?N_4)m eIܯ2CC[ kseNjӼ 7яF6@_0uavL%n~[ńO9yБC)%1\ jdZKTEg/j*%w MНzx|wb3 Lѯ5 #f-eINVZ!0 i p\AahQBL!(Y Wwm{-qb_X(WmBiޣּԟ.F|]yU]|GD~v, `+ViV;U~}H4HFGo0  9&. ,ʼneH.SJw*YRڠpЙTI]B 5eph N$k A$>QG &;p}~ޕ ^wbb1"_N肘l"oɽhxqRhh#nҾX@Ga$GLGwRg"Y}9#ztvR\0mCq@Vp0S!t#GC)}dݾNod? m]!jK!u΂ rzJSW>GAy;5%a^C{`Vt6Xy}SoQouHuŒ^ eM42,Z=n9KۤK|+u3h2mCH8 g 3':hQ՟4+k 2:0+=mSfdp ͊DZҘ芛Tu@fZ0@m}1x{x*FӮouy r3 #2M`<;+F,{NV.EϮ,3kz-U,e{B|2#0cN*"jV@).J7]O%^yV/8XBd GFQLg1cZ&N7k\cj†bHkq&)޷v%4 9 nƍm3xB% &A`FVUwBBwÚ@]U]]~Վݖ 7NN\f wxj5G'Y}w lteݧǍިRom*iZVMI9,a]}\ˢ8o(Q>]IO.jnzs0|x>V{UW7V{yw<5QgIj_n~70sщ>nv::|9R7@oOMAլf6rۣ|~](G*3w'8P?::1 Pz{͙mV&W㛧SFz׭n)}щvf '}9߸.NJY9WT?<|اjZZEam884o7:W}5vp_P3iih]Jzv,lhܕO6芆#\]kbbg6orʵfȫRewϵ4DU:Rʑqirݞ~2sZ*}uM}i;l=>S7x?Qz{suu:q(;q՚{E 9n \d-uܾ7 5{~=|sճjWяrz;w~~gtf)N ׵bfot$北drt=<:IqM띧^8oj;2\Z y3I5\Nt^s1ɝ^چW|~zZ=mWޮ͍3+L po˷kGWէ㋬;l;jwoNw[W|'o 7FN>|V륡WϵCѼIOOrxl^_nO 9 ww[;9O-p}mzh ^ڸw&ʱw_-Cf z)](䏺yRMܨ-sm}XIwz5>_koVk?gɆԱrO*:)! |ol.Y+s<oB>_\3X, i0d7ʖ"e[(f%G6E4XP0?,c!]c01nf19Κiيn_1YRZ̒Mu`36LfvvUi'!WdE G[jF4F㸧F +&CH` KT*c]%(RXW}RbEi$?'U 6gNU˶RH)5IkNUc9K~4iD tG$hIj͠)M'A bY0 vsU j6*SOHM:&;*`Cs`XJ dBLyRtY='Lvg۠ =Z $@8HK`m ',IP&#RH}UVt u ?'KB-^EWL·-ƎyW<ͅ5Pd%. (Շ$+Tf : t$ 2ldCKVj5X3}\ۭ6)MBBBmm3w.$lh0`hYH:SP\5uFPT8Ń)+O6 S<Uz;t le;1:Q}iihϏ#bB#Q#.T+#-cV~c(x踪Ok`?ˈ$KmESePI h0ad6:r$ݲ B܎iMXob1,[?+pMpjPÙI 4FF/ަkJ8aI@y\,S; Iq@ji _;f_9ؚaeS% TUeiizP; S(**NcdL#&ln =Vf+~-3ԭڱcNw,>",+K lôɦjs 珁3 Baށoc8beɃn[-j,Ru01z UlXTKBg Neq}mJ> 31<Sr$Iefd ߰#w!SǶK_zQY/,iH*A9G|waRf"Ĉ )m4sa4]CW6"!T&>Tf5SDkVbcGr|KKӳFrvn7ol$K {f86 lғKKH&j*@M&یhM-R%1Fiz=^?a }$٥/ؾ-Mcm# 3kxLOYoXriքh҃ sRony@['{rm4MQF $~v<+ab@EE_ɲD*1`%cdbAjmcNuE6ia8 9B3€> 3q,LѬԛFq<Ru]}$GEDT @KJ S.A[OYN%)@;rΗ|yJE-&4]4hPb`0!};P9*,F2}c-hˤ6Sx"Pl ja$cxT(&N/ O8g-fbz cE=O]NRKn~+=+W<)b{5Pc߆`z 4[z3ă餺 &KWJ@m(&)˚FFkQ M)PqT(c<*RۙrCɶҗ&Fu7 A ہ0V$1#O@:C>Vg#ٮcnZZ{*I0"7H1rj9b+`R,++#ӣ zrz'M6'ӠԇZ Z28-qT|Npx3xQH/LgwrrzPMCϠeŧS_̎qzs]PB UL  ʩ kA(xt ֜,4:K "{Icnr^H֔ˢ4UĜ1/[+x(XB%LpG:PY ~TH܄ 0 XP;p!Slh[$`O@U ~;N$Y <|LBۛbXLx(D,wT⎛}+ ^XؓMEWd*@ 0hȵ S@įdS"o Մ7o= d$lʌV@շ$t⏩C+L|Bi`%Vx<" i`PKGccc5cpebNYH`, "> #) İ,]Η#jC W-$ Q J+LwVKrOՉ c*#1 ^vFPȈ2T%˽DEMEVP)6Vx9ڎm2_Zב8rI@otHgN!r|j7ˇ~ iSm* C0Et؛Qf}1Ӽ"¸(@W|ԩX4P\ShF 6OdGaX~rDs舖'8?Rſ ͗zifhm$կY i|(ZPkEQ0Dcs*Z=4im)N&Z j3lFf|=99Z!gI'܋yn`Ÿd2>Z ]h E%<., Rx qV:> rW|Ⴛ!kEˑy bBAxwy͡CʥS|YԞjk?t׿Fn^:UVDe}8z yQ>3_2bΓ̍K'=Mv:Mg JUJktj,,A9! r[+GPZo1C>osi;$,-U-v"ghw?ęWsġW4=+΢,h霪H /5mL/09'iyev By|\q)Q(I3\I3hnAN|)-M̲|6h_ԎΈIL~ƗN8b'3T`&*B?ON~=Ϯ ؏Rmx~aV[( 8V AU#NBI@20kaDQEX0t68@5D(_2y(,`ZiޖЈC<EpV'ƱH lQ)'PR`xd|T l^/o fbLʫ -*=V!$7C '_3Zj=EDN,m\k`}P"w?ܬbT<%!R߉`21NŨ?)~DY#@˖ҡmZG9H4UkDΌV;\e^ʲ["їzE,GBux8֠iJYNWk=bbQCYss&Xi` i `£!BBk E}\P͎dC=O2j#ǧƓQ`N&uw8b1/ox<#)8_5->q&x|:Qedy:tJ}i_V='83*3Գ2Vjw3_{,֍f?^N{Օtz̙F&X'4DHh{2k Yoj-f`c}ޔ  9}w\!`p*TTy%2yUO8˴QE>hΠh-3e HPh5tqu}tO?o%YW!w ~p{їU..x? jZ Ŧ_߶" `ch2[fZ`ΐc!U,Σ=6DwR!6Ͼ7c$ho(d)eH5O]Z{C./1Gb_۫~n9EY})8ASP SAc3Q==TYb '!.M>'{!8S zP&a}zH..;+)B7k'Un?gB[ΌC$ft$I]3K &;Dkzk|B>Na7 p& czbőӖGV$vf;4n[t\lȇHqh];,m&y]ֆHUsUdGYώe/]>y bku 3YM. mgJ\9F.;^}۔o!p-yE( oTOp] EH;X- qvn!'zi˃)RqCjO0ߌ1ql7emg_wog6V.9hݜ>˅7ŖA14.B(ړ ! ,?lxs=/szn14=\3A}Uhiy~gޖZ.~7waz/@&="׌a=͙c,==b$/Xg,~zk4YkzDjt{eQor;y3_p̿`Wso;'7}ԡg  x!ą6m}okc?.`m$^Lʟ4yeYl34 D&ͭaB>LigdL]Gt4ASji$<-䧨l1/aoTӸW@&i/Wz7!?('a86^΋lEG:ac|9Wqπ }ss)x#7K9=U-q޵,16n{t;'dK/l! qf&܍ 3kx)"<ꬹ^sZ@|:϶yYH¼ML;^FyoA٢q踟eY6&?v)ҹiԖjWt6ѓN(,o%60,K}o8*V'K<_ߓPX2W6A"4Zz޺{ͤA7MF\\l-y瘨G3gN`N͢cUWiӇ3j)PRҚR*2^߄(ikPqϥbxV|fjA,yWb+$IE)9ABkz |Y({BdSd4n]hmqs!ߌ kiln(<֗l~vsZoݍp:9~:ga8Gt7|@ 5z&/1̅k8* `0A8o?݇0*سy^wV{st.7^w8?j {VO y~fc]:m_,r!Se1Lg 3x_ ?^dҴT/yϹ_sW=u'c.?OřaVŌf, C쿓N遧-ɂ0OOܷPғ "z!NU*s)$)#$LcXu@ zʊCk1 ν.c78ۃy/ |k ޢgD0wd: Rp Uay8;Pβ8ʏ/u¦-d2@#nq{LY$h0 O˩+qWXQH;b,Tt\o y#s a\qUi4νgkτu8:*yi\_񘮙)E!1]KQLz!/@<z]1t2Qpx,nSk߁QVq%u@*{:|W FH903WfeJİ~, _͒px9\<պ*t 3zHXGYήiz{1}=?%50uƟ'ݵK>{qF`'oOG̢8v3w>Q;t|V2BDpr '%Xj~ܸ{W67wxs; \gt,h\Y!JM*Q$g$n6S`?~yCR'/:kR_2]%`4218Βa?YC<vg][E9F4ͯ<IJ*fwOwd~7愐 W]ԇKu\aDOǗ9"YpUYO1gejf>Ca7-E'(G?CLT==P_?$]c0 YL\&KS5vht:KӡŇHu\m+hNB\Nb 4|Ls/P[ >[b(^YDu '}J2X)OE$)X.A^Hbi~*=| c8W6kNQR e?2:mnG+rY"%Yo'(*8q\%3ZYc^gg Mm͇sMMlhFh Jl>/-pɂ!n/,4x!z{)bPeSQ8Y(dӻ v%Yl9M#d—9-hG ̒ #+ 6IȘw .mo $$2ΆEސu9TL$&4 l^D̝gaӟdX$ojQe6GD?m8i8R7 @՘y6:(ݘqrD0ߟ _TPhzYR4ޜ ?0| . @bzNrokfid,G=c2 ˜|8OqxH?8"BL?BYLXH}2L+iïsE71RsK^ae1h5P CkE~c ./ғ1]i3؜膛yX 'ʯMm>)]gnPm)F!&c͡`gѯ@72=-(V0EDϡsq0(hZ3Peněd$  (ܘXߐ]0 ņ)|`I4^o{ЇE.x5?ht[&,!2Ψ c]rx*VOˉ`|6+})BT6d\cC?Ldh%S{ӻæ͜@%dtѐ 7)ܵg`K"0mB8=ֽu;/`k\F# h_sÊx> ^4\ 4rY`8.|Zq%GN:x{&.F鳨^ I stV%pYh-L *9)GOF c3|><;w22i{D62#{w`N$i?'!÷3T-+eىDM|Rp96i<lFOSw?9#ϳwVN0˹ ȭL[y:ㇽp 2S* 9doSfU̽ևDsFϨn9K}GdG{5v>?iw93 <:zSS,|WYߛ2T`!aaTicƐ0} _VeG}1a A9b-_m\_ğqi,2-LmlpqA* eWP`N0 nM[0Sk7ޝ7;/.%3Ɯ2qŔ/2c( ]<^9x8 NF U^Cf?0bp-^tNĂƼ "3VK]\ͼI +V (û#`=0(ݻՂ _u R٧7@O% gmIrӯxv? >Vg\ c[O/&V[uOnUc1\\׌cv|=v*$iL*FY8!XN0_HmԿ'Cp$?c!ۤac<"˨I3}@ɞQ_Mh`k=%@J8&)m|6C:g +c% 4?fOZIj3Wabac|k֯C QcYl-w'yVA0Nk8+ңc!Y>tNk0X2x@r4[bV.(Aqj4o DLg[H|޿9|wvq0XӚ ^5d>~Z)S\^sV.)CMfNkżŔ.yAK.:.߬ϑ$8~Lew-*:vAVXiR,Iv\1QXgd+ٯm9nZ"+Dhb -7kP/h V|>%i]0VS>.Zv9d?i(o;!J]@WoP1;;ٯHI;ȱKg uG8ʧ翆R[xF 'J# k]}K%#ais9zzydzNFcuk t=Fŭ9Jpv5_s嘴6XuX{?9b: 3zUJpv<'1a4eȝA8)B!*1|MV[4Q?B?aH>or[cIbTotӻӎvn KU5O]-q:MJLEb[FC h){Oh=_Y 2j&\}n4ўa*k܀;`JKN +U*"elV*~ewWɲd[Yz(;@ x(-e*Q6 {,^a&}Tj5ٱ!A}),rGWO&7.yFr:'oOt`iJqDƝZX%xPL 1`[c7/7'KЭbI^(zqx{g1LtWYn#&{.SMo>QoOו3LRkrmZpag?'+J)Gg *ӑew @yD^%V^>y|y.?[wz_ފup@ )a_H:l T3섛Z^{IװЦiu'1- a\I>jR+nCnISN\)U-z\ H uS^81Ozk5'(Oޭ'_۷b7vh id~]}VڕQNFҩ⡢]K$~ `8*6*MN) {?XBr'sX$!htaksB u(4RW 'o/߲b|%y:)gؚ̪?Ul|h33ڽL+ѿ1(I*KG-[`I}ؽ> ee6 nܗq;(QU R0$rq(Gr#Ka 6euv}2孾&~fz,gI.뇌* ٥#p"qNM 4SqUĢ,-1+Ż;lUD˩kř#x:l..ϸ-nxj»xuIk_ĶS2_*q)H݃Aq8y*ZӨ4}*+a*\bNltn<3cdCi:]])YXZL6Z[@z<[xl|Thpq jqxsE;kS.Q*v5f`"@ĘwJyp`TFҎ+=a,S~g9I:9S[DA.{V#r6}2˄RUQ]a 2С3tZe;񩓍:ƳLڃحP_n8sI #P4ozii;*Vaƴ /G|F Pg4 㜫]; u9vJSMRN-z^VUuPI~l2NVkb9(zuR<,:bϯUrRMEF Er Ջ=tq8 X 3?"R1C1y)zp'@9%1cwkdxýr?]`gvߟ7X6xBySl[;g\{]{2狻-hZv I潹ğslVm9'@)E|Mi}oQ_,V(`f:vioa_&.uY)!SފA orz#ل&߲67,Ilq{9~ t"qyS\ud E׫dQG:9;8Rjɰ9@lJ_~?ݣA 'd!~4jg[nB _bB[ { An5@6Z |+M m:O|rW<&H-`"Fܰ<@j>~ Qkq#`k|ZsZuA]:&B[ܝ0g-Ykj?"nb~Nn-U5=E4vw'mj_Ϊ Φd:S{/GF[Ge׋9ZwGɂ{.C1iUe %vW\ p7~6ti?L°9xr.xR>74neD'>/ }t 7 e.#:GrIW>uA-۶+m/{aKyiyM!,S.5~LyWz,-*byyp1GGAA 䙀%[ 2,ٶѬgv9N+.H8Kh=|']< )4$F"vX4)Wr~7[%' Gia@ϪXS3F)QybYT^iuH-v]:/HtYhkCfö)Cfcpi4e!H|HqŁ0lNÃ00z]d$X9[658R5c 27%~R,wtM,)DndžxuaX,`Iź [s!Ed&G Ms/^6\^tʺ9y)-D=Z4CKӸZp=`2 qht0e7)GOoś|=踲`k58m1`pp{Q,Y LqY07>R r;`PVJe# #Ci\1\BL.{zVv;Љ!~VtIe@8Ԯ3Гr)'7Gl$&hZ>,cDyP(VTv,SJ?>*cTԸ GjЯigB42{˓Bl:Φ.9y'^1 i 99rj1IA/6T s g # em e螎i0I=Aw비!RX}؅$1guQO^X|謱V?N0,nuqSI;E8H1?:'0qB;])qdF $ 6:{43;6Y9M8 [N[}Kxئ 7 #l Ii@/Y-a0H\Aqj{kJPrZf tWtOwL@mQ *"f.;':#_0>s'3"{ ,8P .qk:5m A{w;T3xKEa "Pפ[7@o$@r`N43oda"1=pL]fL3ʄ#) ƳAw@M?V4$HӇ}v:G E\Df,.P1Bt::Fؽ9D [8,{V7P:/Uۜئ D DRM#Q${lj6Zfs'( myQ̂`A1==qtng2ػ7x~$oF:Kodӷ<stzW9tAQЊ#rK0c$mR\c*hFLKF?b Ҫdz^YͲ =)&pK¿&)f9{cu 10Aub߯ǃULgP~<!=n9'p.{:@ &R<$l1`1l&¯DxX){FtRx <3MZ-II&zVȇm%dTXhѐPsj. R .hK՘I fdpGHد6tUFcS @R/P&T ` l+F`,U[x)r7a{Mr/'Y]Ny_H }mu$#a5sy/^ay!Yhh{ b-L_E" Ȉ :0p!7 FK'rঈ߸<QHuBƤ)ӓ1GLb{ ɶQK_>td ӣwᣀv0ڤHqxfljіJNAN|KqC4HfhaWWxk^鈈rRDI\W?[ȩNO_99B20~#L\t"2=>C0&fRBxE$Tƛ ,~5E=UA,-,$nq!D\\Hr..B:QB]qI>4ua$bY29 LRjCT*|j09a1W YXm:лl^fb5P`79x#L 4R)Vj:3 ˨{)o(Hs0өtAiήV Wt&NJnai=Ĕt3O7dLm%]EjJoi>g'uxbrRBUc w?7_lO u*[lc'xѥCfһa.+ .ޙ+>B);in}(T~ w{}RwqG~ޏ1V@5')*cE]8HR*gOt>~oũ%R{ע+|[Ѩ"*Ѽ wR@:[)ApLjPXik&rR{ ԱAXt 1cx ?_b$ZCږ9ҁ4$f@0t%]N8rz:=-R/YZtgv &՞ᛍ\0 bෑY[ٍ:hĚk)."i]hV,3 5j5@o+f.ڣw 5.SSZR}т'sO? C~o0v]S0v8 C`!mH`lK?q)8Z(%xq/0 dV Do572Dʑ.Ce_k 3C9 ^uSUkl,>4igN+|7NU|l ,l0} w.ͯx _ 1@t_{ЮJvUz ͯ\.=3-T-+L9`ZNAYUK!?)PG>˯mqe/7LߋQ@zHcV8Dc7x4bݔFˎ |gF3\ivj6^UE)>ov{5OQs\`OPY;ږl哼T.kþ$н) rm6Z[F?ZA R\Um5f,#ծKr٭U},~d}6{9Vh6Efʴv]g4翆y$ Nc5ħ `;t§Hi=J$.]FZ+l#K2VZ'J*cTXt98pV3M2{Z#{cx"--)}Tt3?K~(m1TTo>EJ|UK]{߿`VR SR5xL&s8vV'tU wSJ@ !!#w&R}nC*9 bCn,nK&CØ &36xQch?a83{=_pXHqSINJ}iUe1OGKX_f'L .Ѻ3)#|6 Mۍ!I l 11g}Ѡ.O^1Є”0Q"ţ;[N1]_8'iL=Pw{ Çb#wG\85 ş ߟ5)!um ~`z~%+nQ445F;֢K~` _xcxPo>:aoY4E&@f`֦ͦ !}N޼{{@{)Zzțvx/u_<aj;㫳w*xw$_"ZbOʣ츟]\*pJY+"Z'T^B\ y 5s$X]¡IqM",sEPOv?sf*wCFMB}RsoI~?G-7R|OIKzXpUU0:Yw?{Ypl%5TE(&nj銟FpuH%W~l^IGH`Z{^94G1"nbdwg0aQ\18敬L:*5fo'QbGywΊIvVx.btW uR`˼[Zʪ;(z^Kgi|h[@;z d5FVTs1cQG$SހLTlrҳ6ώI&CUJfaCg*~.H'HmM{UR%8p4Z{`yd&?e;*&Ɗ|8)J11w-zk]ƹ7:@B$hLf'({Bu(C?5XqetI}'z!qo>': ;A$,ȯ-Yr_f~)DCig2?pۥAi8 3{L a-N5iBqAGedDvQ=,^pK<|B;4 bzM_ض]s_DbK6 i=B7Ŭ.6٧^#ZOE{Syf/LLIdQo{)}2 {[`|o+٪?-XcoPV'>8)+JJު=h
    ؆F-kʑ: nV$;m4||_jSl% I Y%n"h&}݋/~0!S9]94^B8+(UֿC.L^Gvyx4KUq^:@zD,Qh?Ε% # ݨjlo?~kJ5Ryj`w./JZ-ֻzӓk}I8!$QO:(?.<@Wי``S3!e{ -dlv3dgx&Pl1)!fϝjҍD׸n:oh跬@IvhsȆ?H}c!0\AL\/:ZA,ꃎ 204~Ol % @ pVnBj(`xkQP`(:}@@g>  fUN_y J?頢P/;cDvcpg 1 Wp $ї)M{cC@{ g;"|k;WOc!j: OŊ{G1܄q$b`vwv3Dȕ zo \&/^4CrGf#lv:$(iV}H$1i3$P]^A4O;ecK4(P0v)⃙XL-j (,`vH3 ;҄/Nt O{b{.,/j\n x1/v lfqRb\}Sma qp9PAsgq7 F| m]𜤝Ppf=',ux_RjD!Z`N Ь`< k`hdµrO=U̳Zxֱβ8iUvR Wg醣>YԳfUϔJb1OR~e۪){vt.oc\qA'ff0vl.1| Eܿ{MWwsI7t1]sS)Ojl0. ^n,ɚKOϙ8N ٲ| 2H0 F-OR'HO{ ` L 覄Dx=\` j!\;i4쬭mgɴݙFOL \P/O'=%]+}KNCsؑ fdp.V3)uN|`q.$yD(y8WXVkђh % O6 #';t) VjnkGIo|t( OA֋9D2?wߤ ^vέGG1Ęa*&w`'L0Xɟ2j[}Tn~HrՊee i,zy$zt ʚ>b,8q1=~iCLͦk:&P[DǑŶ-|!h1ߧTe+7j;nx"tFm6 .C#S^m\MEUӿ`O#14uR%j$xCqL9V407Bئ3M2*ra@*2g<TmEͥ&7-Za)Ql.Ag¤c莇ф5Ig X),)b*ZiFJsa w9"Ov@C_Sv T%Bau$Ghl61C{qW.9__$S܂8f 4iTW 8Ed pWQTݯvwoN/@657>N)jzo"^~=4uki΃'D qVA tM ,.+K4\"csib19(쎕K"dUKD5jf8D('fЍrץ7Cnn`7lCپp#%p(>l8VwjPᤙ][a#r4w{1Ht V}4wCfaOUʋ?e M A+vF偶ủۄf*$M,gsP'[LUdHZ[qĸ`+ U #W")fXi;&heX'S;=.(G,#EGg3%~J?TF݉C?Fm>gQw(GH9ĪCkUn$-=Kr=t{ʩ"m+DVahi4$lR{!wi ۥ~ Nk$Z )WL_53S"7>ISe*"2ܽp]+PXpkia %wMBjֱfμefȽNZWWpGFh1'wA_J&̻jo.Hgm_=+-Ko1 Ho'^ӓcz_`KK/-LvMCoosҬ6!7-չM: a=}h qsXҍ5}VRt*b W! @wƷ oPM(Y*`Ce;ck>ޞ(wq5f3h0⭕xmcKvIz˄|6:Fh( s lAMHt+!6 cp\a4 Z *|Uw]1Wie~@(wX0rB4?Y܁q?O=vV\͆[ 26WG͖? G.mE"@1x! D"gsC2lEy50kY.-Q]-!l`R|z JCӤJX6IiIջ|u嫱\ nZpō$$ l.Tz6>_>ɬDpզaMt(4;h?3v|~Y)N>,m,8aN*-\/L梉ܖSV~%:0N7Mh>WE4S\vJqM> f iؒnȈ#"PbQ[!ggS _̍S=D]S#7Q [ё;'?~~.kT#B>ZRCtΆm;.XQY^ :2;@t:&L'ʼneB0PJF5QewVH IfZnOTfFše~P5}e|s6F'Y;@glk#LY D(k-C_TCxm@>73f"NrqsZQg'FPewVF@rDIOz;]*b`K)6^ε6HRi3=LOHSPqvZi7Y!$<^yn/2]]M7u0ḒRz *s$ǵ73cǪQ@*|~q8B}GFm-XsUXׅ';z29wEr_ fty'rBeYD El{zl~͒u2__Q)OKgSsu:vέj8xN~- I{/(?R1n ³-dh%}TV w{Xg;1O6a܏)_n&򬱷c`Nx@3>Eve5(g0HuՊ(2Ҷk/~&<r~:a7tThV.] 0(-hcN"lād{eťc@PV5r0B{7xB[CւPܥC"u dbQ,/} 16.L4m̽/Űdf"AD6KnĿ =+A3XbzH=mor)Q-m/dz-)ýf?cAku砝 Iϩ#eO3XYg0[|Jk }/iAw97\akZ(IHߙL;(B\6`|hڭsXd HݡN %6h=I[8XGM-ԇ辘r]9^ m '#VЅvulK䘿%sjJn)J1!סr6)04:` eZhyx ưEqAv_ F\ A7%clexzsV6<,/bQ*`u3]+Ր#`b9ȆEac>ݣȝ9ޑ:&E_^U0*O+6TK8 [O輯iR*#U0Wof١.EkGcI[;$:}$_C+d+ &IJN =_ӈ&F $UXPflZ " ·+F1PIf׀#Q ~58V\+mmܡ<avJpap`Wl~e<_ LҿP>}biXPq| -qd/1LBC^b QE|cic D*ŻARc=`a/hHP-=k#m5ʾxFe`K$K7DV[mULSQeL׋8"`%u@]"sˮ *p0=t-ۚ# EPZQoHq9=V>LǘUMgq\|ǘ</H` xM%Ҩ)r%]\C,[=2}0f@ <\' HA9r Bf~UEB7=Hp)},UOXʫ􅔸S*_k?RFRT^rM6".=3J.': YU';61M=x<%헮s t"ACV2'S꥟)RPRϷ{`tѢ1-ϚU-n$=%M$d0KKY:~ o[m>+tu,>sʺ:Nzq" ɦ 0]Oƅ]L86ͅ1FBbFkD]s7_Bgc c1O$"q\x7ea!|r:(&K<2B|i/%HYwaҧjNi Es-Ɩe zy("Qޱ i@]-|#_i v qM\ӇP7(6vnۀdZZ8Au je;jYfj/dq$h6'gV[8[z;=Ehæ4BWIb%Csӷ(i[r\^K\(pfgStF:ZV\knل 9pRn2:ƴ 0MIwUp @m[ tFdmbYQ%{\1 j4?MFi#v]Ỷ"r ǍB)֛kxuO Gtb.Da-sNmb` vR iĵV&|hW4&ؓ EJ'eNwjyll&Śh9Y7Vp8NVT"n>}NkuuƾFфdQ }g[Y/c@ }Fvk.FPX=pU(easz{Ui4nVt#w+qOfOӑfҘO^e]GPRj$4-GYW@P&J6vpk,s[ }B}8Bab.wO}؆}m{RnHOhfșE"\\AgMHHxKVIo8Y`yo^EDul*vko}R z(0å9xN'ypYCt">֭URvK l)qvq~RQΖeQl1+%b$Dn=uX騄h&1Qg'*6jY=hD@/ Ј|"\1)YVS~5Nfedxa$ư+7#~LcRbw C=;Q._b'WמAE?lisYirO AP@PKР)&(metС۬om="&Eb}Ϝ2&IvjxsV1JN.xW^- !鹥Lc S$.a4fD@'jhh"K tV[Zԙh?6om5^pdz`JQz_}+}2Q-IᵰW(<uyxF~m4ŷ%F۲6Zknnc3 ZX#L)%!A!,ZC#i'(dz$D Ҏ'A$\S8I un~"cBB,JrTrbQ'_b!>P0堰sb;MCx#s y <*Jo] dǽAU)19VVB ݃!C,xU*1ÌZxmj XZ8S?N8n0v8rEػֺ.le(*bw~@cM|bc+Z.f~|jX7Բޚ[T% .&TDhbZDQ])vbi  \zb4 754:U]sP0$xPӑ$=[;Z kP-dKh4Lߦk e.ymdg<ڈav"[XF-bԢd^vbPeI꟭xtȚ&G 0D_\dϚ v1.vY%F\a+ܰ QAHfx'i1aF6̆RaAn;]ɛ7(3=k㕙"SЧFD)2Wf{.mCetmMz;`w46Eک s 1v("vW@n){SupEJΫCfó(1G#&xa%'m9ً2p8l:J0~|eC+_p1a:7tI,fh]񫣀CMAVyK i&p 0"B?UsiÜ4EomY*{LfY#VYs*3,Y#|Y0n#u~=5T=ڱz4Q\b>"-Jvuϫ+3K?TRl6u[r*Ũ88z^W&V+i^Kk~Vs빨mCꘌ]|(0|-cLsMflrE*03qXBA5`w0iVTR<1 yh6&}OɊ׿U\D0dk8+\KhU| -_*ZiG6n|68Ro"cWT6oH,*|& t:aY.Ʌ#ق+&rڽ w *Jp==$j/󆿥, `3UE^5RHKTZ;:I壻WI~ǕZZ^w Vs Ŋxo"nZpN 2IF8aft_Kp@xp](0];BVKgﲏg6x1*tҴ^(WYחYV\IY#J[ X$,K;4̓Yf݈#q3^!VTE lGEцI/:T?n뗲P>T(>"za/> 6͞vE04ā=dlXNN&D\PJRR,(|{O Ԫ=aHw[= S7EUe6 ߣ/ /~pVĠ8((Xr%IeQ*8\8H]$z_ ~^$ zcg 9ժeɫUm25Z.< dI1PiJ[Mee1齞BhnoXkn)=Y$NPou=bW˫1۴]uL2gҬ)Xz=5?c΃j0GH&zA'w.S}Z^Dk1@_O1U6|"CIR\G.锬})Cw/P -4<h~W&0p:2ݮ8#3x֪i`WQUM aMF+9R΍0fZf>DtVN=~nYuW蟱d B'SEŸ%Ѥ#IiʹpN=*=.G-xt'Yx U/e ~.>$XS/q xːywaIL8(Jzz~o6kQ `=Lw24XO{M@j?!64_~nˣ>|FfL4fof͢I?=1^??zMz3Ľb@Jb搫ܔ/&M+\E8R7<$ 'D&]aL4sa/ 0 GVo.\' gm_\S_] RE9v`9=4vz ;%{_;F2+jviɾnQbQIHch i~D21muvtzv|6d$Ey21\;i|!*q6 *|_^Jے' UwZיN_w}@w5KuHdmW˺Ru2aCd?~^D/,V]A9E[BoYM$(ֻe|x#^{tqЮ/y 8hs>ٮr~>ׇH4:(H6p>8uuOnA+ʕM$.)ryY*?!.&0QG+d.%jC"-M :R*Tm(|4Jϛ+MH|v%XRB<ц50je[-oB3toK]4H %xBS&,TٔUJWfP)|h4g1 {5'WEPЖkw>{}QZS}y_m~|0Odz#Aw{.O8#%,vCXz-JAgnuҺ)EQ|* rEnȨmžho;ctNu`)mrN )Um%Ϛ(ѡz hw[]9:6Ύ6Ts BE L+C]E}ȭ!UTj_f^<]Sc)'ݤR=z;!/{fLmQ8-֖[-|Ӻ;TqIouG՛<&NN&Aca]\([TqpmEnd I [|B~ȝ*r':C1y4RٗHN!4Ixs殙  o pu,{:NBY9߶1ş'tkVrT7 S!lf k!ˑ&2{|[Q V?;MU4a,^t,,U ]fdܫ&ᗒS|we1;ެ![Um-6T͡dX6.hi XUU9SnfK,Ǫ=C([S^H}2.;lJ*.[¶{=??=qyPUAb>L\gXFº)чsoCKP|.xH3tϛ;73Qi#f %'d`Ur M]WG^У[6JB6Nwiĩ~tFkz\Eɠ/qqPqdz">hCzyvV˔P0M{j;Pzr8Ùja]$|d90O7]ԆR~ /t,l }HuTP:n)~pP C Vod7talq7Y-F;0a|D#0eӌ^jF̬!:VK6%7qa=#462& m} ni3許sj͇ 9KAHrTyֽFaןMZZOI!'\Cm@T{OUXoBJD_,ATZILwQ7sPVZϐG IBMh Lhz'=J*R x(Wo $hn5`ޅl'IS?ZQ<ԏ,[ć Ä cG1n1;%zP_=KQVB%CJ b6bL\YQ4DLnG[lUzU-=W[_K]R; az@+iu[7)a!!V}PmU %^ q2tGYzaߙ޷<o+B$~ zP+ VOM7I`!7Iޜ/!Ҁ!+m~ &H_ y2S弩`oV^l9i(>׃߳G&t#烫h|}$4OW8Yk/R!妳C` 76㈍ʔ9x`:8DHա%Ȅd_{[|`X 'C<_[(2:Lnmjꔯ͢x>liJ>U a PRy(F9a==vբ7w>D3Wq8Ͷ̦fLc^<#-N^EƞBcMh1U6Na-2+`g\s5Ѧekƛ/;9pog.jW#wY8™]t)U|aNA $5N_W]}V?ӟȞ3J/,Mfȁ/OҊ-:TĚU*$2ccd2,bd諐kkpz+Mۭ݇^('>XPINثN theMQWvѽx/*|A΍eld: bC]OT(m E}ɧd(Hh*6'&r %1Vz Pi"#1H(h.O)?u$QMQGXVQUl0}ӘC9wQB ?0F1$c>,)oHQЯ*PVO>6V ! =t%1zIWs}[ z^otNO6\~F 6ڒlJe*Ӽ'\*<{ECG`2`tyݼ<43ҡS]mW5Hn^726,x9(N GĝU`#Χ Ɵ͆@nŹ;%%٩IS ~>K]z1zJAht$ⱥ{M(UmM1^YJH&?|SsXQ89Rw7j6$>Apk! '8(;c_\LfHs]ۓ3y++qYB¼q0wg"1*3Ұ?OW} yzW{QFeu0zb8~OpSFK §W uGNfu,3uҨV11X tTHɒ=BB4Ҽ PLJ@ɑIaNOSvєh_b"cd"\%DƀX_)0dͬmQԕj m` qFjC ]*x7PSbS!16Y+^Q$ɽlGx5\aB.eM` /k_"IC{vȄaB\ke:JI4hbe=U^nr?&N/oMFI^MNh5ĚLQ A8TKLNGE8"2HjUb G#|b]bn'P?S:` @;@, 7])d^qёrӏ 1[ܳQ`b(,LPdZOz ݮsѥ6r흖NdL[N{'f PM ϱw#K|}XjD )ڨ8Cxy7Vp:_^0Y*4k۴!L\=:;1<,U>0'Rʼnsɱmpݶ F|w&䛖[g`9 %b:ySYvVPd7D5:|/38h;~n~n\S/M!]vS{ڌ/F  di8{yUT֣1["%ZNT3@c. IOܷѕzOY槦?VWƘ=b:{"wg[NrxAF~i*> ^6jčY!<*z18l | >N{)G3QZ:Vd(6!l̂L/KGE|pUgQ>,:CO??(% |p( BktNHY=~s=4 [ʧ+8p|ӈ4\S4&!m3|w^g56 $9&& #dTqI! :Eya9}9mo(?ySG)*c eu 'C+iZg[93ttFTXS^Hso6)-fEc^-߫,[*Yc=ujSN:l'=:0> 6C-spQp{LԞ1c8mlBV'yX=A]S S=:,T[4Qg5TpeWá 3{چCO./9 Hd6}io09!'c?ᡙxt ]w N,E6 PH{`5삟c얪bFz8/k/ǰΡ$pRI`)?s{_%G޽1.I|Sa[:+:<`zr_oF N='I nt~CZ_,|8vBϜHZ{}#|-p`m׾") Ƈ7cAmxkP?p9Gw쥜-*Y@CцK7zs- ݥrkF ~焂Z ͘aLS3E+8.]f"0&"7Txg" \dF~_;c\K)|*[&npXG |%PQx? m?~i/m+=MͭǍmbC~5ώYv<@Am7>LmbvĔ1#^0 3=|lzY0ÝG^i+GvfߝF+w>σqLZB#&掙N.c_HI+$h=nno.?nle[FTōPxxv5.% 0fWg p^Z֌msͤոV;77o=l9"4 q&iu&pnZm^pLa'7[nn=jlN4ӒQDt\l}fsv[m3c=[lyߩ7r,IJt}M]|9Dӣ:$Onagd<ljBfh Uhd1D&撆 CfL(PqsӾ2NΞn{n.>ٷ@K n$gvLD*C /F;+ d@[F哒h]J|(+j0Efz6& G pžы;vrJi.꤅I rڌv.sF{<}d%g҈=N,z/]Kn>hޢȨu(e&YИ>񤃖_}ȫTG@ o0X/>9D4ǐB)Ne 4=?T{UQoNVظ lg`n)flH( 65D]ߑ!9Jr(I"Wt>h=)Н9l2[-GG!XaҰ9j 1'4zn$@K?|ű`}Vw *]egt nW'坍EeӵKCp ƻC%5Խ uܓe7k "oشseKC.s' %b;g+K[/:~tٔc3` ȹˡ=,ÓCE)l4(>F F)-*wH<~{U;^?b~6_~j#Qq1Gvkn SiUO{kVOC_f^ASѸzkoA$D#SIVڮ:ou|k@λu} `0<=Hph4۽GF{ÝG#K dd EL`SO`pWg!tރ.N)Ξ]+YSSvri }6F9n+eUȷ+ۧd,$(7`AT~j^. $'9{aoCG@(o f}r20?H03O?& ioQר>.?YQ^MÈ"I*W(Ș\xvFpfXx Ig5gY!ylY;kvdKԃ dΌER! h.j9AmUBrov^udwOB"vP*(}=O #,svo{Cxذ rL%'JXJXYaLNp P2ЊLʜdrqտQt⇨ۅ#^h^VȵcGb#Mf|2$/g1 lm᎗_b>]^ѕsIOw"Ĭ$xWQ=iӺS9d]""-_\Ż;>P %hZʖp޵{L,kmo 'LBĬn"da+`KQLט̞|BH9{LڡgVqi@".ҍxOUEdX{0nrzw` uՆ)ҰIZyR9u2ep8%G_g.D7gF A/̐qD|*kRf9EHFjt;Nm7]UR٢ Mw{t`SBwG/`b֊h C9b- e/~>`%ĴY:t 0cgfٟp$=|y`.n0˳ͶUHQܓDonn;Ddpkr>őt87c #iFOd/T}ju0Y.ixܦ0fw#_K ǫh)s Yk87&xc/~gJ0G|D ^=UB$7-3"ў@ִl,0瀙5`+ yܲ`(/s,("!D,n(7>{z?]&51A x˰v+#[]†bxr}4-$5#ʞZvL歲#˾y[3Aje@.0hqo,l*6L =4;6xY*bE皤6kUfj*7zԹHeKv#Ԥ!?}o6H~棈bhi*XBOg%/ۜ.pCs-1ӫwq@ xe7|PLz%C t gi2lքZ ֱt%CcgB,{t1⋇OUnFD'x5UGpeli nV,߷LHeUKt/f)r f%aq๼V45M<ۡ1 ~xA>DMt2]KBfYur(j{Ŗ 2\/Hj}Sa;xrZ(}(4` ] :pDbDC}sztBr7g'ȩӊ4tQEdF(wыŸGlȥWp|9ҬB[sf:hlL)*a:8@6ymЋg"!>dL ٱ%eP.(9Q{IN lVr]g.gl!*Wcq{>'C ]K6qv84b,/LÉ|ϝb\ۋh*L*?C洄3GSpuFS7f&hyœ@ER*"`gܨݎ6e fOjU,Vc_MX&1qd ww=]]aJA07iW0策;sm(B:/$5jƃ/qI #mw-UM(x+V/ !ՊC[9EOFߴp{i;L'iUy(dy{gX Џ,LV [:Jpq[t%V E (3[Mdԉ<7@S_f;V室 XjqsceZEL뙢-ym+'8)ӄo,RP&]:yiwzUsc\#2~W #5>:Ӱ0QI# dEHXRx;Ff ;(h`5:du $^* 9Fm:N+J-EHz h q8}Zβz*ˑrzhc:sB 3nSƬq&nd(΂OAo4myl ј@!甴lY:6cnKZe^4sJ_) ߻lT2)v2i2 Y:4Fםf9IRSZ5d!1cYX jׄГq*8,I]YN#lyfV3T)23 ofiA@صU\0\cxqԩT(U~ kq2N ^L GIPxHvXX}ŀ %jJ0 75qu\Fj8D`lvNo>Ĝcbγv4em"a 2~f9e,f5zfKonH`>%3R@V[,gOn~,wҁL]JLBSαc/`8BOAb1eo1b6tG R?b(}!prxG;v"Œig. ٩L<2 ђCϲW٠lllW+ /A(W ֣*OYo5Z%īHޑs%YrF-u/m%GCqFlPV ,Y~D p,So n-P$bXh g%-z$e`G6=UU33 w͝|KMIT7ٜ}*91H\ ).#JPxf9ݫhCI2@2O K 3 j/At&lAeDj k1)G?F=i`xJ}KEbRh(봱F\plYDȬ̯!a 퐙i<TI/A<ƃÈţx7o!6kS&N`Ou$qw$zS»H"=;` o韾m|aa4ѡc-Tkx ._O#QfLG M x q&g'G?Iq{a>{OziU:hm觪 -0zѬ3*m[TԛQUH#e4Bض29Ɣ]>30vA5NE\Sh N^^yr}KpљՌ V F |?f<Lr?H9_-+_Wuڷ+X>׾4t׬\;kk2+8>;xXƊ1saiFIWX]恩FXի?!ZF(A; 'YjֻZrva{ZQH H/vmٻ ̫p]= 8lL0̙kW1yZcGN^AA(uĴ̡Ab1kO~i\_e2߾yw14;|TB-QDceljsx}YF})4J6LR`I.16hoV{#3+mhiUgQ~p-_˶wK :Ɯ}`3jq6`%z.a)~2:O+ z26c| Z _ßכ* ^3bc!exsiDƄk E5ќuQR[fOҶ=l(U[2[  'kMݝZ8ƿc fsa uNbFC|nl>^i~NG}z2%noeUqċyוw3Ȥt;JTq9=sZ:R`78 5£iju{bqkÄ/ǜt6sM۹f_&Mk埂th6[y`8ytO(PO[h^<-\0AGO#9jo^9OR_0N\KZ$xhllc q^l7,M!P0إG^T86G ^;:}YoUIWq{Zxzy՜ClMT6㉷g7wyC2e!Mx\FiVSD >(Q%LPu.A0g3QTk&YL@!d7bTWSA9vv儓ƈ4+wgk~Mz&kʔ!c?-D3NmG ~6?7OTwyN}(ІF}Í rm)Юcm]KE|jsU͆K]M˲JY+5EyRQ߉x8 7$jă,PENJ,\bE/yُ{zF7BTK7[[ ۍFYy{$?!NSQܾa:vM+az.J^{RfX{F gKmLc>_s|J DV)0= @ @A/]m\;#R3ymxj83 Hxd*⃱gZ=^j<⎭UЄ3^dn: wl6>+ATtb ]d䶈̎Dxl=dY|'\èF L.C4ϼ3`Gbg{>YKdEI0 Bs5˦Lʥg& Łl vkXe Dwv+k[fbaIE{_eڙ/dZ \t(~g5̰?k2z}u$s@Q֣ZLu֪5 CF$|gfo+2)9m:v܁=@]K}R wAiq 4kfm6ߔV&MtF{̥ə‘xȐa'<<ɨ3C{GRq8fMn*JhTNvS#4xJ?+ d#&#g+;wBct~<2^oUIPX" ۥ$$s(⧦$Ҕ{`>aG3z>glq!;mTΨ3d+9sfE4y%k*'Tci _A?0 uui4EJL>LE%zOtimE[J3Y3^щQka/ZIoȨᇵS8-+jjt 1寠k뛈b,k`ʤu;}K✢Tts#S/.]T($e03|ں+F@A OD '2\C@ hc60ZY/Óy1Mێ6 9n C 640D%Nb줒E  DUA߈a34ې, /B!/5W P,QthyG|rN1ޠɽv؂da.[D-$RUDvUPϜgĹ krE筶Qӌޤߣ``{ԭX=LO IS:~8Ix$DzҦPW2+$/\bKl˝@ sy[T !VЏ=ٗas S/G`d.ƻ1@yԙȐ72R7,K C|bUᲔ(V7PbԽ,ksr{K>Z0>67jjljɝ$l H+͈PtnL_VLn}Ї}џ<K6l{64ZZ gSC;+-m 3۲l6;_3׌/=uH Fl PFC61 p|vN<6 TbSra.OM~T9|ՓL{ ƳMff*g`a_%saϪ(h*:8CUbl5/FO: }]`>,|kjz^ۼ|mm^]L:]|kk ;Nϵ9:c,0OV7?`H n6w|Qœ}?".ڢzfX~Årj,@uMtrRACApl3&I(  4a'>VƋJ]45& MFⰝO諵o_>:9;:$&{+2LG x[|Vt1,锐PP?ps)S Z:>3=eBOX829Fs1=9Up*N跘3b|Uko`{5w/k-˭- j 6tu1]~7V$$Ab@P)%d숉 tnRH}=ps0dQ+SԢ7 vcUW|4ҥ' R_|Q{ BY0lg)E ))Ek( .HhE+ ϓ_ T]V6+?ovp<]%^/CC,?S8Z#ډYН"J"9ZkJPn8;sD%⨇|@vbYۯX[:'$r:'Qw_֠[1Ұ~C5E\Yöz:c@%Ρt8!$ $ A= 8{`E|^a^:MwH~C- P4i%e2kJ>B c:}zqHd5Hedj)l/.{:N"nkti?>h>n4][ AJNJRE?jP0Z ?ݳrnTL;./1Tojc.?CG8fpښ0(Rj̠0yPOHzf`Y̑-J?oȣzcU3G_4 xia/7fL@P*ШF}+sk?Q;&Ş@;ҤCM" 'D)VPsot29LJR%c@BSk846mtEJ\`6 ;Qu} 9l Rl'+6~&2Uavx-f/܃4F^\]7u#Ebτfi-3O{, z,M1*@*Kl?OyR9o*Ȝ UBH&9'D:Aa䟰Kt>)M+l9 t:xPǹ’1c *VPk kPL˓;:S|,lt_b}E%eza꫃EU#R1K`k+](Zs4Y`XK*2L]NܧW^>Eʜ;$YCGBiބs{a20L9hc62)${@V@4n(ک^d@6 #Lh@c4"?R'3 SRk/=j^V* )iQBy'"|5O0Me(ND nΆ˦$TD$#Se_o2bKcMCU .q 1Vo0^Eg ݙglFA)Ämu2S:.(CZe 6EF- uQoft(™,'U͍b,AE+PlMḩ'3X4SfQ[.R57+,UzZR]ҬR)k}tz׉!Jڌ:&TtB@:LU~Y:L:K\;r^O=w;2SJ'6>|/oQkU4b]5QjBNAfdtKZ(+1KгpgN%|[5oEW^S0уҡGc:30dKfyS i9た^ 'O݋̎)g:K5I#JY<˻^F@\u#\RFr^4y5Qw|ATvtc BOhDfs8^#ʞn8[@S^^ۨr-ېxHC'um!Xrq{Gյ7 &LtRPDKè\F})Y6e#JoX#v޺Inl4@rsJf%FpS僳Ey̝*opT,n- ğ'0ݼkqMloo>Tfрh0nm\7C|*b!P5j9#L9C;HmU}\5H:lNv Ps!=B?EpsH42.@~.7Ū> G@bPAa;xKCAQ_oֳ=Io_0Zjr)yuBGIB~x&\s }fW$";s ~l||| ˔IgDh0PHz,Xrwi~|Cm@;@棭օ[eԈ9NlF>xF(_C )wlRhb迢7 x]X҇>Q{TG NB tޟi}BKe4L6ԉ7,/$ mANջӒK74 l=y w$L&oՅJ +>?1l yr@?F#܀hAMs9a&f@&?RYse:BUZ!Rt>"+0^ /;w deev3ۣ6sic{ҜmFQhR Ks:CߏhF8U@BhzdGNWv+/)X2=p6/z_bwC#@u4ˏMVbi1|m<GOZ{FS4`>g è?0A#8^ I_SWR0{P7@Iavi?k5ٍ'*Ӭ&q2ks V9W2k!B97r?2DX˞ @M GzR @V5JKH$?b9 75@+b4ͧ?t>x𶵽3mVִJחz㏄aTW/ 7w'~%NYrazߡ!yޑnEʼnfo3uO{@:T?NW`3'R@BGx=rr6J+Y.Jw3^4Pqګv/cUxRg9^MQ崏KZ<"P&yQWOgHZ̟=>."%7M3%H:l 4J'U&"yy$_nh>8ݫD6qK(`Q*4>BiёzEr_#x]<FoظfBVM#-2Qv\^{U`:U3P#4\T8nRQgPR8bB@X@wI4z,`BnoLIgR/5%3i~FKE,{P[ 9h:{`>Mp8ׁA.FJq&bJՊO&2~7iQ#k vQYXz!]ᲗU}2PSA՞Mrz\eU]zD1zb^oMu6N0}.[=ѲULտ*T!|M>>Z* 3C\Qoi EZi qfON@G#s*[Myupx Y{k0Rkp d[*8#uܲkc} `zH3ܣ1pԂFe ſBk[P"Q}< {Q7qG`3Bc1Vv<8h4BfRYts{J2χeȻgt~11oZC:2n5y5T9n^mCYs;[-?U;?=ݯ==uԫӗUϭ5@+3֐>O`:X:@zl爛ԓVs!w韣\ eereu)sq;vU)0:3MM:6|X%a306$mk6nnnjӋn5`H10@dq&u=Eŕ4qW+n#D+ ͲG`R\d)k>rʧ/Y| [9t.RV ?%p^`t,*epVʟA֑q1\اhZ01ge;4㋼)v}:iC ; g/LI=o9|淭gB®8 ӳ^2L `oy? y$gl M+VpffXiWqt&H -@sqǝ eXmyLYC%گ NՏ~GXSM+`o߽9{Rmz?;x1w\ug#}$e͑' ?R6I7X #kFf.]* E*nX9l$9ə5|t%yh< 3( 3TB]iuzHӺDOcl28NDׇ訋U:2\`.ES{baͶHĨ%x=hitYTQ牦6Ǝ] -84%CΒQ;ݙ=b eA +un( m! HuxŒ|[U5͞s  )jS1ŵ|:yW}uRWBs^&]7i4 O2ehBax%-&tu?p⡔O٠ 8s](&~5qtWX9{Roujܱ=7J9 "dgOg:{֚)6kQv|{A&'CF>JȰg;püfV&R88]&?1 ;;Ž PB=3P"E{J|({_pOc% `_PJna] Km YLLf(H+_&!0WG?pMҐMYMR&hbk8JP.2ID'J'"بȄ460Cv#kFuX3QrPGǔI}ڄY.UX))oH$xh>_EҺ0EGn֨MuOiAL*0\M2H \^"]ȳ|Wn`bl_D'Qiqx .h]mFNpܝp;; a5=zֳu3F61)oZʐ>+ 2#86a~&#M+&.RoJ Wy+64)M 8Gy3(Sv|V&:9F Y4ꌋ%Q˂zyvV+_-"CXBcF]1jyzvZ0pԈa ]]0R1(Y3zm03oOEi)G#Te $&> e~= Ʒ|F0n:Po_e羮'=5an`&MiTkH:INnmن܈<h$6Svcbd, OhC)'gimXB&8q&4OnBALr;ȸxԓTK08NNdsgwkx `3򑟝3sh6>`AhAYS] -Փv(b`ʧ^L10@NzWMDLa;aޯߝ1ZEV@h[#c%)o.t>V>,tTwG^,H0Z##5di6hMS-BXpq.$yto3]w \FN~<@;?v`;?`:5UBGK- %tav́ӻT= Ke@,Ajvc#;i VE(O×:xdRLFGo^>:9<: `:8XvbzY6(T^0 :ƈ:d8AN:ǵmXw)XH!wd G0Ƚ{M`l~/ 8pX8.!VC6p{ Nf׀tDaj0XbK2#DD9]"'E^\R]2=/C-&4vVcR,LHx X^ qh\QMc&M43b̈`J42q`A!6LLl?m+7<زNoD1DDN;Js뿣%黟\pMiC ؐ6>GNRsufZ:7ǰ]ϾФ=YR TEA;8)LH5͈?сhoh`l(,& L 0qC_ĸz\.B,C2Wx K,POTrOIMw N?$C}uwΰ%k)}S/aJ%LI|O$psŕ 8+gs5`v ^GAcñBnN~C?At<,r?.f,_iv}cx' K UF1df"vs|H&l8crx7̵KH*f 6H \^wm :N ,#VޤL6\X;9MV&M3xҋb[~<{Q}9]qVş`*`@vt^F+[.b?3{PۋQ|fWuLLډk;0]5yEmw+?vO" 4M`#F `u#foW@LPԺӁƒEEߚNFQNK3 ЕaõWh**K[l-`m'4(u6r'VPiSy{u^o*o 5! 7ZZdք[z\^Ӽf0\02Ý3Cq?.{u?YG#z 4!^$v ذ{6[Ro囉0ޓ?4(wIz \a=!^`:e|4Y9PQvCE3=`?!Lq3.۸YE&ͤ7n>J :x?.Q do$oմ~LyBȶm4yǵ|j46 8H}8c ƾrI2pՀ|VU`p7\uR9^;+xj:CE4z (xސNOx.'@@|hH MygMSWNlm*xB IOIV?r%WsݚL1{觶 jXUf5 V̮Y'-T&=4}.(%H(ylP43GuoUPڻkgd#"hHB Ị]l3LQƚ\D/%p]t< 2QX$Ǡ&+Ow58k*#<<| ]k41զ b 8/D_='KOB2h_/ \b+,z09ƬUNT0>^EA`Piȥ#qoN:#8@jn箎d.*E"^f6V5lz(ʝߵ,dh֬<7?o>śM?!;#[z21Ye5Lo:"(#R]xXc ʐw~B7cj-؟=yx"x2h"l7Ŭ~8֯c" 7R5{:&E3f 1,l8܋I^Ο'{WuQKm.mkuF[m-mn.ntsi e,ăPBM%LF!#{j~o9<'@vIZAd`X,l3`w Ur9͏7`pMq-,D!3i%Ehտ׬BME/#=zXQ{0Y%zx bYZl>pY6ztYA16_ҕ>qM|Y=m u()q&b- :~W:kЫt:$}Fni.Bx_xݲqt_}u= eU5uv^92^!D3mK);uš%\15œhz}5qFP1xB\j) Z/4ۺAɀ9={)A М ~NٽϋסOqφOtmq< *̄e4x^u0$~a&Hde⭺S4(,iJxMt~Mn AMҺ3rq 0# :!KӍ5(zb8#[._?gN?ZŦ&]g )xPp9hh^ LV6\vkRF~x}NpXX3Qq|B_11K:Jz/D^k8)J,|X%`~Սs]-`J-8.i__ O;` S˫9: K9n W$=cENRS'ĉT@ݛޅAWډSg5 U=՞~V,c"~1¢W0a0stgcv8}٠K'6cl;9\T}nFz sgmI0z &yMi9-QD,SdX<ֹ:wr*l̜3mUY[dd`kqK:duujU/Jd~*@ Kb%e XFI^.R߾@!O_+q{& x9Uk+"!T/J,RtA #8-zrcbp7H]'[2AG(3A`n]R3!xUYe"4NOd:+BOY';)r؉ |d*d)ղpެ<hiIJ e:WrjP6:G0jnx\5V wͿ өvpq!&g_>v[_:e 6CWh[+-@hn\\v,ψۢh!j8dVԫEN[4|T/0ķStc~Vgh3:pQTloCg6#E&nlkqJS Ŀ SrxXNJr+bf6LbLE>dS9 |R@B#LJ8")p(>GqF{5Rm".N/;YgD޲ WAcit Y/==gX2{4CWz=Fi(_Z: nt+3eV e[+(p+XFYEHCqrٍӳwDuxB l\fWg:)Q Y4&ɌR?\o sŋϿxb/6zr KBˍl?}˯睯w:_8:?<8Æp l+6Y~lϸ6K(F쩯V/q?{}g}8 ]y4?Nd/6?>.QWg6ӇFu^/2B֮20+BdmYKU\_FCJuf]-")?1 /)lmڟq>v3հ6I#+`jZߑW0 j{sG=T5+|3@јKN~<5[ݗMއه >Zgkk\t4cԾ={jş KUu2Ҩx,~e jiM'imRN6,7v1 !!jc>ELf{ktL8N~xiCCo>URa&ʖl,KT'G ȹv#{'_~P̡bs! 4n06ڸ S}z MK WSڞmf/t-omW-T3zLXv9 Sl7NRU9-/>͗ȕl4)Zٿay/MV}/{k!db9zQgwc1Dݐ*.zng4j6-ʋ\ ްI3B٥g-c`48v`jJUƢp/6rN[L[mFڄ@_XOL\%x-PG+]q]-cxd$6}{!~S8{F?A5@+GSK Dܦ:&a1ru.մqX"Q=(qr6Qt[r+˰<!ӈJVuS 7ū}vls{kszٷ}Zws v>_APUÊcSմ#2r֗+æX?Z+l_r$c[iZh@uTd~NhT}IW8b1hŶ*Zcն񫶕iK>?Cf}^k d2ccTϵA(=4g/ C؁=}9JTe{|'eF{̧}^=Sǵʞ=#G!eCh y%qe_ C6 ;0:hprQ&Kf4vMT0~V|'(|Ξ$MJ?:55catS3Gaį⮯u~S8ǀD{#[rT#0.8ÐcSWbcүYaz`Lu*!ev:^c7hꎦݎ,drՅ9&GVvfT\?ֻ?k3zFDYc4&^6]Ynpi_߹#S ,|P8t4J4'j0rGڑLgz ښtoPJs] }|ge˰8OmaA5SYjqnfXәdM=U?cA"HP+S_?cj^gEYa\0e hNz~*֡^AV+]c޽|F6Mt[oЃM>Kl%B#\ /31g&ݎcJ -2W΅.Tsިr ܛPzlb;j}S e (i hZc B#{`p[Z]g+?k&>^8JqlxGWSo 늰oy|:;$%(܆pd~O3mi)FJùDcoEVI|C9`^L[Ő=4\^ 5II0'sc{&YE5DQ#',b7xYmܖ-pݦU @`&ReMο!ck9Nnp8"GBUbneuF+DYMnmnHuL7k\^0aYL9dzHk3Ȱcyk8INvAx .P @h~01!>@?.l{=fɸʨJf?F9ς2d f< >ivtd޻Yz's*p߾D2qf-9[.² #,gK j2e.._%Sr' V\BXu^uݜ0ݍ4+wA~$hb9IBIF6mЮ߬<d|AaL<Ĭ'A.=tvL&mėA3<&ЪfS@5 Ii#c%@K\t~"IpqwSԓ2v֍|DtΦsW)؟ګq:3y"d^7ο[;Ūp4>ϧ:ѢxUХ8n% T\_0D_~#ja!`?> 5J ZݳCյzXL/+i%e0bGSYca1nJ9^&c!LP2}/,MLQ5!?9WXL3I7 6"=@h08 ?eG=*K ~-,L!r]aґ=gCʛ[`>;_U?"`'3<&8+ $ FnU󋗪]3鍱V8PL )8F=&RGEw5Tc3nV ѝ: 61F Ms\`_8C񻞳MO-VQ)>/ K0p J?Llcw*((ic71ȫKRQk@WIK]Sm°l?\gGȸ<4t`a'LH(zã:'A>kU#5i NPQDC`I@LD 0>d>#wΖ'bܤ:o9.nt`KxBJ&.u N?fI3/K>Ct79ϐxBɮ+%X6fF)aCq'=lDk_1d1͋q܏'Gسv6 0p|Gz ]S?}^}.c0xnDŽ0~GS&;\{rP`)>H7HˑNJ yꈗDo%s[ ^QKo/-QFtbT=~,ZD\6ÃϦ=u.;[_.>ku2sOCL#I $#TDlbdGf yQ-ь1L-Tģl؛ p0;i vΗiFT`/zSn d !#YD131!nH[qiMeɈRkbnp_nn& Nta|R æuD Pk)WyEK>yPM ye%J&P6\ӹ HjXXJ6!vrls =5-oʴZ-WBSJy,)W@bI$%q>.ΡAnLn|,5wQ2P=\=e:=5"5fwgqP[ob67[[置a; {0*4/ lB$:88~4=A`gsZ)L/d2Lo8&xW @}^*E˛ڸ,xFPLY ~>K. K~܎c4_qf٬Ziψ-8pzu vyYa1͢yT'΢h}`2x|֜g\sl認)D*KKyN;Z d( }@Y3 2&`NVӼQV^Al*jd !>mV]I\`<`oք΍66rmєIhQBϮ}iN^Oҧ;۝dYs*ugc ?az+Ndo`"1zy87X?{@[ІgYvA5RզV k+JHMM:+.aJ=c+304U.{cF¾b$thڇr5wuG[ vy:cI~hGM!sg"V/+`UJw|O6KGKlhğFU>_2OH F8:ax^=uX*tEv%vXfJz@,jrJ~ H6ɛ#a.a' ǃsn?#H> 43a?1X?’r]+E gXSoO%{pTMG͏qq* wPSIsk%b:*a P.rOh,䁊34Oϐr,hlLRnmV $EU2Q@J2].31{˵tEʈ5_0<60-1}O.2 R)=}4؅`NNw|բ.?.1¬SnhVHF?<?s;(_]O[_:>bGxW,aWe,lk+OKw5][PL+vȮ*[taۘR\c} gβRooj4Fwp`qu-+=BGَ#”,՗ i0߿Zx S{ g0ܖ0ϖ v2] AƽqeXt7o0m{^py0+jg)a303֖cB ?6ڋ~ޙQJ)EGTD!Pґ 5vH!CQFOV`ΰBtFJ4wi|~(cRbktT+h@۪  J%gaL'rHs-I|Ξ:͛P{6 ʥ?nKJJ`ҏ1>39R=:(Wvl; &Ct㹳Qv hlB|t ג }-i/qkȥYw'm/ _rS-KbU Ք$q$_`h9_*iɔ1jM G3)sIŚRp"̓K^)P - ̕:?LSxA])B/,/\WqfjX'nu{)lKKKݵ+{Xf`|%9)k6wo'8C$X;M߱)v L nT<xBQ憈7/:4[I4p&x|}*~l.7M!_z"o Gkw*7&Gr_ic*Tmy8ѷJ,ޟ]8^[et3 娯()g/0-&X5u7)u:sCp#)y!,%7$M6loj'oLa"֛9dt*ǵMA[޹ɮټO8*hT#l<ruaK[\zY1,+G"xVF ?)NjJMjyG|<&+>PEnUYl\D)ҥ3\8|Uw?pQEHOP熑5ET]%f4AM[4H h&M/k^qӄcS  \\]HcPQf+b`2{V7%'Jj/|UU ,9 M`&cV`p2#8EK 6%y4 |,rw-ϊ@sf FuGQ"Ckuv͹J;܈\Ng?WzSZ%z?Oߙd$]e )7R?Nbi%fwjz>+l=E1w9]T3{; 50qx!T,2Q[81#;e%v&De^I3Ⱦ^9y5hx?5rP[ kS 鋊PF[vea8Bª֧"ffi[%u^N0asqhyk m'EqvِdD-ueT@x fWEUjI+,p=1]~vTSb2\$7bSi k;ÇhJuI$q$Tc]@z`'Xي5L̰߰cLɤV[^Ҩ3d<7Tb`'Eh*\%m11rP0jׅ6zK5|,Gak5(0xxV(0Le:Q<O95XI Y xuPԙ6tUOhD5&#ET@qͱtRj5(81O oX%ŋn20`hz9Tڥ0\` p3 :s$& .C$: z*|İfgtv\4@&;C&z ©2X_89c̫\{[!"8Y/J"D+R$b)r_ˣۼׂ5*}(j8>Rqʰ/y>j(PRsDefujP.|+r1zw_yDGN%l@tӾHckSty}c![uSEe%gBM$,$&bAV߶Ձz;*'p|~k L_C8C^vxa7AYg`X)oQR[!-rt'^F LBfO>zgvȿoxDucwߞuwԘ[!YdIA Go*ޒ9&_q^u.-!M&f ^Bu)](,A5ZLQ7MjW毂 ~56$8&OKe@2YykOjщ[o%\>ѡ,xB%ߕ/ҊEfiPR8pK &":tކ]`z9+0Ye_l7/6^L+lU?E0E=XDܹj!-k/D%C#MpS&>|W5V֥3!fgJw[w79l)b`ã)C!]6tylU:?Ll"( 33ߚ&\-.caYTߴjRW:%3gg zҧuuw:?Q jMy!YyM^dy˵!ErW A^CђOM2]sOT3nM%';XTzhv:N$pM\ўFr _kVG;4M'{mDO𯆂֗20`0^&CK$~]')HBH P*}_fQe($66BQjF/SKkoiZay%ɲgYN&ì0Y vCy@74%',5 Z-=jLEkxo.u1Mˌ@ k %e *׌HSG(k}W7jiʢsSdy4B#L⦦!^ܢ^ɚK)($ ]&ʸ2Oi99-'s Z)7h&Dr֤${,.}8Hf$] {{o<CW5C(_+#6U"O.y4E6K2 k\BVRCyuJta$hIT.rQloe+V1?0+;y$p=BLu5X>)h GF4e_+P^֟ComQ$G86::<n ζ-\];U5F%.^pz1W*mɫ[<4 \CYLeט⊳A ńj5\>Hs!&e@&ppUybMҼVHZ2!{J]p4=gOP#d@ذt;~Dk?έ";3+zNt~EǩGDD)eSjlt:M=W!6>~7Wmh}Zڃ{FPi_;pӱ߇ͭa,rOY^Q#< awkFϙd1<+$GA0\`)5Y{RowiOmU<_m1AsT9ЩwC0GfaRV<@1&a"h6Y& ѳ:M&_W)p>xo[tW/q]"W1HIW \O Tvkc@Dq+u2K'u;OU_ST$z +<ѝw)73"9|aa u^ޟ=k`9H ^6 +7B?~L ÂiHaXEZ Wţ旛=%yTґkəQEbCqy&H> >C,R'$\fMX=s]4A$Y\%[bB`}wteR|{^p͍U BV VnTc=mHT b7LYc7ؠɭpAU!fUȑn1*@sײyIlKZJGlnUK=]%L5XvB m8N&L9v6ڕ<< ̣U0$QgH hKW`)A5(P}=IJ:3(ʔ1jWR-$Ykׇ߾%L>igw \"l1/ 3a:o(1E5SYIFzhBJRoXS+@O^5uLuVMs6.mA_t?bhC9]$zNT}wۦ,}Bm_Qzht&mM&:Pgv1o>"w|rt%{MCb ON=S)iroi0| `fZlU!߹۟ %l#IzW Cnof0cĞSSTl,p~?S1A!.iqkѯ>֖>φtfk&W=N 15sxm_SƄ1U3s=F'd66mt{ cO0OQ<r"&$%Mɫt&{u)O*}ɛ&4!ʫEv9z)<Q(K'ﬨ sakkj}J뽧BeˢiuC4w]z=U 1cQ\^Ud?#?fF@Y@,n] ge: Ч񧆜0ԸCp^ 3|j~{˞oNN&;:vqg&8d[%G|N&ePMDzΡӂb mRBL'0P:ۺY3I1e+jOaUwXylT8Xyq腝9iN{$qQ)'TQ8w #b3uM8Jӏw˫tc#%iU#װʛ/p#!gڠÇ(BU誆A)'"~&tSϑ r\6E s'atΨubQV{%(*j4DNQ޳ؗ[G ZP\+^(z]*92,Q,&cU x ~i_̏?wb֝T{23F=`r-Xx-i2;Zmg jlcWj'ș~"ڴFóhVg\Spv, 9崝rUXcr'M[qc@y568$W؄r'd 切r)u E&w`T(f%WmhӪd).1P kJv5MT]eH#% S_֑vDŽ^A(:pMa sKRJ\N(7)D6-H8G[}ߢ ҋ@?#F7]fb|H&G2XPDN7(̜(da d֡cխ(FnoO@֘._5\(1AILe O3UyVWy|69K.LZŜwvR EqЁB6S+0'Myu21z- w" X䘪fFfu"s? w.X@5ӄ[Sm&~t "З]n|+i.e }wv 6r7oO߯+>y[0 Fq׭NQc #-fV slbrkJc`VnAfVnTF׺tLQtBtSKW%^BO-C v;z;{u&jF G'?)`MGώ)#byqZp?ّsyUvw2Qf/1xz O鿬s'x" $ B7O&!eRP|‰|L.N7LȩxS V<|fAE 5j(DS}$>L4R[w7;[j4h2|1ʃ^Pb>yj}*FU)%b %[Pv4 @[ExSE$+=J;)W#aVSD|(4k<,oߞqWۆ3akAw%90el!1vA;q9Zar^E"ʖׯ09(e(G Cg9(H@N4( I޻%PΎ,BvYGCQ-.}ճ>*.` t9 @q"Vrx΀q A*?nIM^J* %4{GgrȎ;dV Ss9P(OOc1PuD YƥPNOO"$}rHs`$߿Y"5507gPՠ||+&,o^'c4dg)@K`>)j(ȸt SLY;S Nz%75Ë:s <8zm4Zr}L sgw;6s 85;_ 530>wW^?w(Z}?rQ])KxrtpXxRaߝjqi|6e>Z74?>cnpM[R⅝P]1vR8B$XޏG\9/y9q+ @ j$[7veƑ\te﹥Lł C^0'hsr85o-wfίִE-(i r"5uvѭU]ŷlwȹbvsgs`sEdx|'%5dTc}t4+ak,x ^!JKia3z AAþv AY<`x|>ɀ43z+OO.cTxCk2Ah?i;ûQ.J=xz |'FRD$U)!@N)xj+= /~W Ŝcll?NJ`f|9D8_5V#|Ep<0Ͱb?vT,wr0 z;Nz/}"g]FlU35>k}Zs ] ^):ʄo=wH-KyIk%CVSPGRuV@s"y!AI Tc>^JsT{|pd(` X4#o"u 49oكE( UFmh½_`~[qz B =3[J^}ǮDpHv,ERQS~ll SwEpI[gFVƇޮ"qKLƳx+SU Q2_"?([1{. rVŹh;ãdObjņOF/*A::}Jʞz׀b []T>$S.aF;J͍F,C>EaKbci̩*K+yY(NI$uݹ^Ϝԣ$9 ~Uoq6cm j KkozqgԞiUJĥkR'R1 !yD NJM`O(H㑥+ܬ%h \JNO%VG'mwbcc'ʾNkgK?SaOWwɷ}[A.SAA#e~$U8H^1zW\>ǡo)bf'<e<8X0pb(-l 97Ta_(.ɄkZKhxpRSE%|_ń¥uxv{*g:Q:"*E\V:~T|ꨴb@Z-F֧Zrt>+/$|MVp=]ԉMr*mszt dzGK%x%] $No_~ٞ xEk:gd hj]P{i\|]j/}j0Ϧ(}IN3LVZ[e ^Fcpn:n2n9.!GYo{`sNv7o ;N[8ۘ5u1hId鷷{4&Vt[z hg}  9˼ۣwQ]Xr/3 9ƃ9^3BCBLP%9R_ې' CgI|QHU#z1+:%@"*'6?oڌgQe~Ӗ8 o X6[9RHLoB%M0'wbm+<$7PLj훣Ol#l. 5d[=/CG ŶsJ΀a9 re6ѐ-}, i;~$'uM>;K^O c!sn,Yr&1R,.1' %vO~*L kۃ|u P"3Xhm~g>i11rIJ1r_֖:ZWx`{4@g6o)7XߝxS#t("%[pLyP I(:x}lin68{ #_~ Q #{8(lbٿ3)8p\-:{7geWl>DHt=l/+m<%WjF<|L"ڲ `:7h~b6j+VWD@?p W-1Q_6涺ɹmP؏)cmX̧Ͳ~.F qH ZXm8 @Lϧ0;/J֟-Ի?X_ed d K]#WӍ2',I:rjjPgbJ+sݤf)D@i)8@&1;־Jo:Њ:yWN$g'k*,d~cBYl Nuob@a>v=[$]̻ң髋~E%8O@~՛ ^c}b,w?9ՒYE7Csd{caiѽTW6(uC\ȿAp]"R#cݕM< xY,$er-N'ƅ5] pŦ\M0̮Da(lU Œ B'+3l+Yl'6.Ҏ$ǵ_zl_K{ MLY*Hi&B#@Q]Q ֫I%\!}JEѰǚ.,K#b,d=&h9GfiY0dqK ^0> 9y:ŷSjQ+GPo60N7(Y'CޣUr ^IuB(ƴ 9,BB % %e1BRUbgxͺZ85z)|lZ?dqi|qEaZ2OTeūz~eE6B|EܩiNGq[J] !\߇I.<wվ>A]Q"Z(|eGIJP` u L -f{өIdETUڇ4 /sґX5t^!)W8VY 9jt{4[*ªo$ŪU rj;qP4v$GM>7d҄I7Nf ~L&HTcer)S)]f LRZlSMisw^B);<Pe x(YsG e1{jFe;]Q7K¨R>`iBй+V*eh u7bK{)7'Oha+Eϋ7GdԺu)K!Gݡ&=idA Xx,gY< M}\*IJ+A7voDuz-޸ <2[,#|g%ڣJ&31(!!;!,+ֲ.,k<t2FkcEYr.[-mk%U ];o=Lj)a ːf*~ AZ +PKl?N)UHBPlՠlIeX%%VC!!9wB$$⟃j(#>@ V]e1Pvʠx'`(lŜlA~ 2(;+AdeO dMFQWvZbg&b :)^>G-VtWrv\8ІYL4L8WeMsPr(~ {իO_$lw *SP9<(HʉRjnyj+uwGFj ^*^=&o,.2(X|($ʖWi`jZFRe?Yb`6&ldUJe1'o?ԏG%T\)eT5K۴'gX qW T 2t.HlV(WS֑ԯvfO a:=9narq>s̨6)V"*=+ fX9 mܨxUêd#E |\9hհʭ[h[ =n]:.k8|.DR6QzZr'UeE[VM -cߛKը`Q*Е7,[! tU); qq>0"2JbWU :s~MEXЦL.RC9qPҸ[쬺ꮖ ḬYUۅ|U6RXz+˅V k鸈ͫ\/^a\jXq?w =K.:R,n V9 G$p;i4hWS:om ԒpYV\Ҭ+\v2] *fD9i:r8<&X/ajO&#i{袷_|YR1+2@zwIF,Tm`\ߒX %i6dF h@̧rt;?:ܔZj"|ѿ!ýVtrc!0g~1/oj*:BR I-LqxުRy1 T*;#FWU kdcULkc(Pi [jf&])uC(WR#'Ta \)1reJ gmulBô C#,dtU>zIzc$.OM/CK%^Z tf\\CHq K5[T r2=WzӌxbU佦Džق 4Fhd& qy.d%g-XG#-O}M9ONjI)ai!*qg2\"Q3{,MjA}v9.N!9f&6|PBCk"}/<8Pz^EC2p PVILʗ%8ZuYLE8? !z -p M.\,P"c~ۧĹ;纳U41<߭⟙V.76˗ޯ\07ˁӴ#*$W&5J\j*1[ NM.j sPvv1ְs=.tXE:7P:pwD rz: "On: 3O0^iIC7S;aryzj~_=7'vwC7;0jw;rnէv(wVn'wȉr/P w-,aʕuMy!i H:q1^I >Wr_S~=7|Q >#:\)FOG!ͯv^|#e+mm/ʁ(Z nWyp\ vp_~]yjp/6>́(]dAy9pymGWQ͝KGbs3q"vqfO _>V#:U^X|2|ds{IS#,\z˹ip@KHo1ࢋm)9&AVpjVVEf l6k%݊rOo*G'Wc͓ip״Ά"~1GVg^6>4\g(~nEŜA_q٣M_7= [/KG/-@LaRplԳ:H,Z˺-EIU,VFy/+_zO8Y1]c PRn-L9*znc>7cR@ǩ6U 0T}XU.7x_/sʫ~H1j<͋7꣗8fGx0sΡsIܴ,suC3JW\rŦAh\Ɖvk+PQoʻ@? 3x[<lp1E% S=^OMV>l&SDi=E0஢mv\˗3pu RNFw nkd vr#0;drfwkI#h^b_YLHk։@`&R@2_f[y_`&~ݴ6 oJt0 T:'{]B,1°RY4"eo3˺գNQ_\cl?w"}q1,Mayy;%lc\$őJk R6BтPWQ'a(0:r#d}҇k†_9@t5g؀LP m ڣxF,%%HDeEe74Qve{Ĕ ^븀TM L vCuJЎfx߻t jŜ.yC<*\_c%1$[ Xc=,'Xdʘ`$jh{} oO6Q&VHr 9xXph/7ƳQ]:kc7h]WQWCP(`h lc`,tu_6 zx>l*&&n])X3_/}`D&~]7]=^LS>@*:ɒAb ,=S汞wqL)5KoR?ʨz]ۿMd|ia;E9,:gXpvI,FY*bjO)LCEn<9U2$u-"ZiSs-&O–ؚ004*T1I.4f@"؆8aw&r`Nߟ3d\ER350iB ` l1, U$(J L=!\@fSwP@cƧ L}o7_[=CyܕL>ՈԲ*H0Mx=[ :grd߅19dɫi)2))&f(7:~ظ :qAƀ._Q52}@v]WmfB ܘ C6++~CG͙Y!OI@YS/&=:6ov>22m½ hl Zx#:ZSnGꄙJ&5\LG{̴m=F[dY-9soI/D总U.K&u~--b.nmp>Bcs-C+a50x[Au.(@b.nLU)@~h\aNiLz+b -8Nޞ0i$,K,$$]ZgS3h9.yK/I],[wh7>+AWN_DIIv=nkCd+)ݷ`&4:쪦huD@5\ORO]#†r\.f!j P6bb>L:dŹX>W$]vqL173V 9C:K(1mcR$ ) N(G6qSQ4|W1-TiϨju >p&Rjf̑!0qgPZKˈqt@FIhlF0ʫOؗf]>or5$BiD\"jG:[W36 D\Vn+U߭$JZ 6C- w-(n\Ic*2q $Y6ypBr>"ɟ|MVJըɟ>vFdP=F.~).2 <]=e`*g{x:߫zE*xO8=Y,*)~9ZO._=GlEVD0)Bpo)m+ܛK 鞮d+-,P<^hN59Q  $;Q;V!QhNOKa,*Na 2 1|a?k&6VUpLY#lu0qZa M9=.< 򓆙4R™0Wqȍ{9viEg+,wWlhq]nLUjrsԬe4(D]Uꐕ쉼vk*dɖ21y]X#JSh [sZ} h ߛWs2h 6Cv5c51ƾN7,PgPgpFp͟p`h43nƎZA8>'JM-r6s3ab71ΓdpMŹj5}9ifAn4؂T&Е|Kרt+#>׿ɥ慹 ,ݠ2C :=q?/3H ț%p\/5y`e!bz[@)T)5Q?5F M:X+"uQ2N*)q {ZZ $(-vהll53+Jֺӳ#, fzБ@ia Ѯg2iOHe|zVŀW[2.K9 ]`I->CQ9?߸($hHE$%+.=`=jH |R?>ѣ1R{ nŵ\U\Gh ~zǞr% ;a@RѠo5+I&JNݻGҠ[Vq}(1p% ѷ?~_)WZi kjSI'|qy zfUrOҟXp)̕t{=E>{MStvc`bz堻}jLhqC |dq 7 ,SX2OE,kU%_z_.丸8Fn0oQ/OoOJ{O5YsvN+GeGRjR 'd0!bEпZAm *7\t[,_}8 >}e_|*51UQKg!ߣgwxAg 67qE؇OAiާ|*HQ _Fgl)jΆ>իc.g%zGYE9eaws }IFY^T}5⋒qϽKFy&UP9(+ ;u-Y4ڲFs`mct,V"l?9Isz}62c`QAxtHEyeۥT5_9  Ҷ[ۉ8@W\,ukqŽ@A]3<Ea<AW UJ@y̔DK9{ĭ:bW50ҝ|zN(ނA+z4g4i1ʼn(p2#jL7b8.7*cuqXXLWH,I Ƹʒ)j|NO1aNXuqN?t4 `䑵ŷܚL=!Ks(co5&.d䖤b{^(AĆWc-Z3X[kZ : ߣl]sbOCm1Ad~2 =ùdVM ҵi(QzS_78zmucP U!`bgO#k|^ٞЀRhc>SOTPdzAԎbR$ +rpCz-5r&M9'|EFw𓗶J6g.ZOg2F$;O鴴o2 BMU,#\.Z XGOz3'SܐIF}J O ߺf\^FfQDc{K/' szpN(ڛ E#94>輫05#&Q{!Rd vyg8eA n# Ha35x69HzlV2OaW@w W<pQ(4U3ؘj15AI!ó%xOSѵajoF,O.t{jZ[7v9ʲ99(23An$+ښ/z!0%kD៲BpDCn=iU6TqF,d o>wq:\DiV/ >>9~2)9bZ0Ii=_-#w_GR /p5U]]S]Iz 0NJf'0NYVPNr-Uqd^mMGke g,=y @_u(49So G;54H,0g[5[ppt4E/Y-z-aʤ6n..GXa)$n&sBCd#^jE_jnM WKɑѮjXij4lJnF^Nq|_Ǔ2y\em bJ+Aߺ/%ɝ~LeOYqƻ 8 )a(I_&VFj3 61'0ԧ-: hֻI) ^<=UzmLvJ; DQ*g%Gg&ZDNsÓSx:'拋 yJ*y3*pzp@6?6M9RRyV[ =7Q0C!u{S{y'ɒ5M'WU I)mE:;`D BiE#FD X|WClMd)*p lls /k:8hyTDt.U3s1|X%!% `dlPK<1\<.]P874H) Qhf`.eVyb)Sg%2VOD l taWYm.䐰9 nrG1E'ˑVFJ~N -06FP@y※""y#'Gt8ےf,qFw.;|Q?EI4=Pi: zPg>y ]Ź8"L3, NJ":sт٧?#bfL5HJz YǸh9Om1 L@>ũхRpht!{ [NU?|>X•Lf~ ΥC/LVy7f??1@ vp6d9]M+?r$+Ք\5m鞿v9jgA?,;<+BJp*ppԱ(&ZǁF ~œKqdʈ\zbPC 4,U_bX2Rd <"wۿs Z͊OYH˶n4ߍݕNh%Xw~,i.[mong00} JN/^F\o:xg3CZ~\L{tɥ'rk1%hPWnJ*H) tT3+|6o*Jhl~|N"oBN&wl&תp >xVY aN4_,F{JqڷVaWX,-Fl=.€` =_>_[Gkκ`6j;7Sr}SUMPSR L,CK%*%5(Įli|v⒍1aV щұy=]%iJJ[N8[62vxtڼ3o>m HU9kt&`2HM4&i |Vb5vadHG%4{SPg3NSFatzn*LၞE7:>̂//0Oшk\G#u4SEuw#K=NO+ڻL>%ch! Qs,4nܸU9ZU&-.gYg4o|r^,lj}?Wxƒl+2p90۽sJ]cnF13gx`sy-+,GW؏m~>..`AkjykwvbL2K;Xh:"o5n`\(hk46>/6's|نsMKnjZLܲuI31$U+U"Lz/,x+&{{^H4-PQOz95h5 CzI}Rd>5g1@&)wP!#H0&>],G&Zx=44X/Qg_X r]BWU%KrSb-0 l \&̢xnfUC 4UL[í|S Y7@yAqQX8 0X9g P [(ykM@FאQ\cpUYH2+@pR۔'ݧr>I+n)KN}7Fmn5;* AJn fT_^?/֗y8 3Kt|:31B@HkY[p|6CmJ훜)ux èy6Y,\fCk@c@Tmst|uɱhx|],&ݡ.`e,..õR.W/N`Is'R+@0)Z> oVY,: -򴊁v/7KB׬L(ӫztH&aR o?uo5k}= p!u-hZfq&@䤮қʘ,w8OchߠϘ7[G0~"6mݵE/ˑaxHz8CT\OΖNqX㯔+3BKYѲ:"*7mu}r?zC}kŇݠxYSuMgb^#c IZFTi6o g2i[,&I̧Rq(r *O F&u[Q m+XCLѡ|AX܂#Hs}un*M$D+CD<c[ZbTteX0~p#쥷A'ܰ՜06{C4I E£v})L jZ6t+NžZmشl$i@agJM;0 Prڐꒊkz ]mtsʾ eWMbp?j`N~#KQ6 >YiDԴzH\lCBqn,¤1 P@\panz ]e+:Jp[M1LV$BS9S-u„ElޜLv7cj4"ΊX u^tڂN`@nׯaBre>QTG.ZBkuVR{ Ddܧ.!KRE+bYfGwEt̠oIPTs_8a#2SRaIO8R]z௯ a+׽]/RGi~40 8-;*BãH+'y3si4*L]1|8=f8fV,#V+^H*?9 }'wkPڙgDJ&2 2SNf.5nc19ń&Pf~^xX34ӂv`y7>},[4Gr1S>}q=K2%N0y6ĘaT@fW>ah2]`Kh0,:kẍ́)7Ƴ.՗yI1Bt`JzuRw)ʫ VۛC/ȏ)^X/^nCwڙE/,uTBXp='XIJ v W6_.LŘsM(wⶭRtp3B~Θ݁gd07 ,Mxmya92xmZcʄ>!m\Wm :ͪ 7>nQC1%jhIKBA8e$-?7lޓ-:n{Yy3ظ̃"b !U?o)<ὲ;(}q0D#9 jP.Evt!.fE"W|j%@}U߷ SE_@⵪idypM1-^ۢ$"E e?G)WD.? /Uqvۛ6dœ&nyz+ Ov.cB$CoX2m|CwԥxnQJE90- ӈkDT/aɺgBųq2IjrQ$X1s7l(1o(7&Ba =D[GeR H':Wr!hw i% zX~Ʒq+kGtx9.0k|N4/0XZ͠lzNN+>#|@?Bwj.2vԔ .=L:U:V23l-+^PӤ&fvcyQ4YFOa aPZN9v0K| iݗG9gApҰ-6z_K" g2%0cg](,RUh̋6H"tBAg=zm`1wF2;@J]LHii(l\K|O@n I! R:o&r<Q6DM3RBg,^>gI!8! ̝ 9!s0-5K4x,q0\=o?>ђ+0B'Ro+/_tϱ(0!a%PπP&SB"&#ի%pGdJ&wtff3&.FavLUQfҎD" \Iɕpd#pՊ#)_5^ÕCe$A6]&HWФB"0>c;5 uӂ&0 .V\L䖐&j Ǹ4&0*fp @wleSrr3)ҩNSf6/7> prI2C%z0k-+965~D) tFZhcrOD6@rWsuu]ē#c&'j9e݆/^ n~َ4|A<)4psjNQC̐vsds拹|5#,8\ MdNaF"9dy?9y2ӤmD6iPk:U.d:9hx3w+-h=$`<.mPTj˗~—wO/e/+ 8 0-g [_<‹ a{'Ag#~fwscU6_ !લr +,zB/<`Fb$0 @)BP@;enԀ>i ]#GlkV+ wZTF8Asi`Ū6\F6VDv5\qiaDN&,J;ǫ;9us+EʒܚvcyQu6|NPa>3~u.K3l"汼U+(OOZ#a%(1 s#(QJ2$M2Q gǨ~|$KJI(tSXGڍw Q:|;;18f3Xgr.J6gSҟ"v b Px0đP?in;Mf!ƅT F7/G9@-fK` 3nt?Ѽ;,L})gBbӃa`1MKx/ޚY5-7>8b4i,Q).!M^Y"Cc_!|GîPm L@iv%9sFI{.aVDI2) ,<ĊSȢϙB=΅: jmJ8,?XX sa{[ ޗ)s3{ ܎j aI?yLG}NL#@]?Ma-%FE^=;GM"!,ۋA'i34MhނDւ"#xzZ.Q|H|gka#pz=rzh1[R[dxd<֏jE!tJKiِsØr-vAfնPė_ x{TߤZtŸ~kW=s}+y$gl5 _̈́߈D99xLfkJVѨb`XcG|{M>:0שԝOŷ#%~q FчTENO3(~6_0j Xqvn@hP+ eY%ԕ"@i$?Y]&t 5RG3L6zph# ЂEmOc4ߞ0AN1 ]zFZPmF:}OW;2t3,jʗLsY#`wMaeשU ک&MXHר+2χf c آ {鄶y2+w ^@kvmFA'qutC364>ACa@رg<{F)/KZY̨AW, 1$hvjGǩpQƘA{7Of8 9X G=){;mẁ,xaݾ4?S~vj f55~RFK8)d#\ 2[mZ ģ3&[$+Jpt<)u" TD HQ؈3WiI`^bt1Gt^` Ml,' =n:9JƉy+Ar;Ej3zdX[[ۚʻQcQ:9J6FVdk}21ӝ[ߥ# C<2 y!)v(",QH7 >xTsא2we;RYǝzlYʚ@Mzj.2aũJ/2}J8h1/C6> B%,EU=/fNv* 1In ʀ7x ^}:5MW$Kr]S\WZHq Lw*VuT J-e0)d&f DevB4L$cfyb$g%4)Z8ǵ?xq3qSLj:D_JI,qE$S;5p=ȝYDGaJx\'Cvҷ!pm7ѡQr_ }}׌&FIPil{6ozmŮx☻zy'lXP8MQY߇l}?=;|K0G61Fu4̌%9i^[m@O8xێY,f/:PAEJEI VgcK$xz<|K,#rQoB6finGXt4yD[{IrðRx4Ѕ&} Mt`3v`ta݀ +uୱD%N^ K5>#”-UW;7j@ 4ZIk 6#gD95LVs"NjđJdbn TS _# ^dB oTqƧ s:%Ľɹ5vۮ~@_;2U 'HGÍI|qXF*bFΣak 2?H63Ώēgo1#M,!TeJ rx}4w4N|+"k|;;F"gV-r3$z~ܲC.Z :90@&;ǿf`Fi,'db^C!Iީmp|tI5$E&8f).Zj+41n $wγh4g [;d"{V#-)0="Iku-uEj% ǖQ.QѠÆ7 rH~!y.j՘ :͗8y(yT2m%qJ% 7KcdPo9Y"N&,CW@'?2dG29i>ÔpK^+5$ ^\.[Ap8Xn%a CClK43v&;;37͓ I%iIYoGC$hmov0Bx9Q _ >X-3DXl-\[Qt/ƹ^ "Yl71ȾE^tJCvj|rXGH"_"!lޮVv"IXY3\# ܢńY)DZ̵\EHcɱ#4 ֠qױ9iANIۯF9|wp1)Ư.NX='uTc: ČWD6i؈L E^͉%ئMf{i}$$altv07X&a%$m'hw'mu>t(Ǹ?`32͌&%6\Yk20t I61A]vMn0B$>5v.; UP\O75)cyto?_l2!SSoISP!w & .qR0\|'N2 cG逹!a]Ob5:L!kP2H?id5OQ Ĕ΄gWlcPy[#aIp)᠍5GE{ 1KtX4" DްF'j wK̓~K8B6Vhe=H H4 "&rHl󚛛oԮv1בB(f=E#fkl#glhێPfN_pb䠑UJYjt/4)pN{yL>T "0@ kh:ٕDxQQblo!h9&'>w9Jt$l"lZl8nV^M cqVƦ.Ԅ]͌=%͕-obJn$%Lӟ &&g極B1zx5 2DB5.)BJylYK>r4gLE]}(.jR'n [G{S|J&yL%PSi7^F5yU`X#f VӔҰ"GUǎqQk wj䮽,oF sLގ)Jk:RMVg%,ȾLë, |4pw"댡 xQJvSlF,=m&R!/f<܉mH,yfku9ub2Qq2vɡ:څZ:m(^Ń&?[+%Gx?|+bc2ز[\ͭj&+7PCt< *@i?O@?t1*)ɄIkCX:5^qyL6hY8􇆣h@^L@Ɇ"7 ~G4'Ilڢ^gU#!^3L J5-\{x !Qn{ h!{-3m+k-#d/!2Nf9hjE""(͍#ﱲ%wzՑUe-]fE0_5=z枸-ZAGnK'^cDe6g&3\4T .ptn0+ى3գڲM3H҃ s%dxEE$)S&q#?$9Lv龦=/7-GEЏ!KvJU 6:f\ʪGD5Ljk\U(W+M;t&ǣ>$ifOH>ǍHqE(j0c@IX&Gq2t}8q6)%*. ߈:]g1w%9$ }O7l׵U2Ml7:)] uTelu4Γzc:DNr3](#o%2Rq.a98&t-1~V O,jCSe)m m5{űQwD38g@'vkpl%40`]S>є%Ɲ<|xU/) lއf=Cwr;x4(Mxa\Yb3wD^{DAzdLa]0fMΥ.B='LҤ†J 0+8p)i1+eC .L?p^JLlzfXG̍sV pN6^6!'>þɣ$ؔ5[ `U>`!]1CwLWڤK#1}IօL|z߲QO[-Ǒps53xTd(N)Ҿʮ.q?A:]_6FGltdzRDK`՞o^CKnê Z a&qA=_;[B3ޝMG# v7jdN)67#%eL9pgSIQQnvI 9kG-SasOszu@+C<@@̡X #VmXq/Ku"{W>3R@`RdiP'RnW/Z!m;Dj\ +F~S~GV|AP[e-Ejm? tz~6Ȯ ^ON³=_g\`يQBߜ0n_\˶/.fԸQ2\NK@>F҄ %m X/a0Afa %h@DZXڣk }w;#+2QnşEwDfsX,Z a3C=R7xW4N4&0'L:5WbkӹQh@C1h+_fTA]@Y)i:v<֋h}h4oXtвEM}a+ UM0)$9:l+(X?r/}Mq{%p%=:R"nfZބksM*<խ1sa5.F|,CiVdKe@CE2\ZmC/AP\]ڋ٘1YҌ]ЏroEթyw%/쉧/Ό#$5M w1M<^$xD *4C'(K.ѥw55ϯ8_RX!pA.FM{ 'G9[t( D,dyd1Y9HBC`v܀Fe4@9񞴝 r#7j 2âZ|s̎zZ8`t@HeL&ːo,X^S)#$?8gl1CG6 Qܷ |S!]}7[w"A$"NHC!8mTEclRfU)e~i_~ѯ5eq=`jaMae-o89?B<sQ~R;[}Wt<9NhVAtDe>ƥĴB1EUx0,E /L|YuKVlE):9} t:Ppn|XQ8*'Go2Ī8!FT&+vSџ:bY:)@ \3=ƢI3 1k{Ts,&_{_fSBPS~?c4"u OEܟ<')TcNK18;˫5zfFy?AU3$SOy?Gbo!|;9tYG.v0qx0ͪJ1я]c9x9Y ~~cF+E22(ZQdieAaE~k0HH_kD;]t}4!Wr,w Ey0I,I\04ֱADZgpgA _VL>c 7̈́ P? ʇ3-̪%k#[bW8m b _# n,,;ğw˛KȦ\z4>rHA:JA,E6kܣH#~\0LikeGqg aWUB4=ws>\{2}&KwWZHS3 j9Ro)OAu"ͯ"d%lϦ|+h6DY@ xgMDg?х: uq5\c< u,brMQ:SjG CQ 8)5eq&羏vB'GZwuX?3W2`uɿƺYebmQ̎?Dr[GdNa:5%& !, V r>[`id@un2}?F}U^c*侒:W^ \ƟyC$T LG Tϩ+tx]O< /OFݷT@;7PWZ>vQ='[3@UnP+)hOa|YjUee!'{c/'<2lqDRђڅFSefՊ0Au\"*2]$bc\4<3>d ",(Ud!J%[Cc]]T^ zK ȵ QtKܻ=%]&P}R]]j~^O{yo*k96,n"۶y" ~ᢆהO,iIJgEV_D!lUVK9D*2դBd;2(K [J+ RGeC `z;VCƒv5a0Ц D6adK`?廤ݪJ\)F(g"~ߴ XN2;O;G|s-p'׀Oz2f|@ Q!`HlNDs?3x΄8c"F 0T[۠ T4֝o1/T3CViCeErb Zj 7sAKjKa1tu19Rm(I Q12~- a{b.^bǹ.=;LLj&E5!>D}uA5ֹ<$)#[GMūQ ۨvE8%S!yF(ZB~o\1WFi3qn ˔dcm߄K9ְ,-Βh1Snb 'u<(ZBxm2v/9Ya+?äPh& RH#JgJgzJ>\c19?}2EUu|HQ?R K8RT54;IsJZ`JX-@7svK%- Y/7)3kV~9ذ,90B|#{5C> d]s^Q*OɃV#$չ9O..U\43cQ!4SwBdI4Kl|1q>yAy꼽tʼsby:E*`ƥgG"R Du{JU7fLx~ L}d@0:;|y\ؤIe 7ggoONM>20Yw.`mS&i*?:*z\; &YLLS,bYjdQsC5+b,f8 E ⻅\zaNZxGvs.2v$qOQ^%kqt6v!1۵oM=$I+t-#G02R&NQhIV$l=)f/I5`wLS䯣>Z ^K{ v̷Տ~|&6wR#Rgk ̍= u6X}.L~} H%3u6!FBG欻 b6KIIp }iltt1 2њu}y]%!$QU'i4<[DfќhHU+gS%t;׋s1i#)#ra!tϚ^!R{810d@~25Aۆ ҉@G I Т aDosk<:"r2; I2ϴ0pIs-g stWHn$U9Ҙ])4KɷnI{ߏ^ɶ g/!g3en33vfq8y>Yo4KiK L O9a 9Jlbf05[b%W2KoYQtp^TD+8y_d ̜B8DssK >:Rz "tOMCD5z;֩z=4 VI'\Q'g_F!VNj^w}9F.:l[ ސ8G0Φ{V[]S_$$?m,K4UdK% pDf#DjID:/>Ͼ;;6s82ʰ~1Tg0Vq>6UوҕtXDg#HB':Q9:\ FlX&0hTmIJS$e6p MSa&@1O@ Xnc~p %݇/-.U}YWIV$ ՕmA[BV>:xlGח.(p(yi^Ko(@dgeN䠍@-h6@dȐ#z2]YS.iN&jXf*&:}4 4/c.$kTHL!Cq8=a2ڵ;-?l|m ]Cإ=m1ϐ= }u7Vln]}poG[?lVƟ>:xjֱ"buBe ÆГ.E0?ƀ+Mλ7$j'y NȇV<'WH -sHPjᛘ~849]2Ԓ aA0"u5͟$2gsœȖ;St+Dǧ>OӱXefL>7f%3ԚĤ* րRkYt?;LGjj$ppz>@nWQP3z(SLN%֧NC`uw-!)ADFD - D}`}Ǧaם^Z~~:8\/Z4铯5p~,%$1La:ή,)τ?\/05YH޲ m)l"*S0'tjh7 Ty9O|᫵ٳ3GRb;3GطbR@4{C.[UOBt'>0$x]:}2 `>vĈdXOt;JSѸ_Ei䉔Ѣ&G )U<:te] NbAh [ֳ;9ը^5}i8(yO FڭrpTLAJDignV9I BCg9Aު>xO'X 슃]߾eէdǵ]tX4n i ii4kt5\k""&Nlx,"cvRxXxϠݖ!ߙӫ&B|PP7۳!yffd+5xWlQyX gvƥТzQlM*iaȹ3ݳYW6X?\'Kf0} y9doZcLzfGXbX;Ǐb4 `j*#|ѓ8?8GHt INK\o 9AqF1Wo>a( 491Ho][5l!6eK$-f 0ny"IҶX5wڲ֮6/jEgZAϱ S;SEy6l4m}rMwA*ӝ>0@دJ܎# ǚ[x]l~\Ȇ#u%\ 5X!4\LzX$/peZe(~~{[#]Q-,+'Bo'fbeHS9 O[ $lש~d9K9j8f!wXdn9lO8P )pryNNQ{ɇa!N CH| ( ,F豕x A לS:I뉫4 %VP¥xœ(9HfS:$R_A2ɵ)?=e=_]׋-|2;&BVJUC*bP`U',mPE}󱖌Ri>1]]РJ SEoԱcwfO;t):(e ̀Ɉu]l0z(J/ iq>Lo0^;ccZ‹pE=<0<.|yNQd6}q#_P"QIbbK1eK:5/~=7vQnIb. 01/],;g4~h6 vϩ, D|;́n.XlOqNpQ0; SB'.[@q0\{wz:.tJBIm,ߓ'OeiKKO={/ˏVKIIPd7Wt/W޷'bq?xSCƌCpyeh=?> rITQnnvpowbnRmP陛iU|EA(㚯NKzDj0dE¦b:@Vt->ǣ!%4i!&:,r Go[J-w\Msƛ'ǒ zi{ ]|ז_e]5Q|jVC+Tůq[=q%Xn2Y7>&h{5gɗ8uvM"q 2 J \Ww6[ͫΗ<ΖQ_֏ Pu{G۳{ъUߛdgxq{ڂ΂{l _^&cmxް?ߘ&l" Ƙ ؘf^>^:}= p蹱^ K53)2̭Zo2M;vuVhgݟBuW 2e';9g#8Ws[/6jare -j4~Cӿ~(ab#3?@ca΅u}2†TIku%w_e_7VE8~\g)mȢmRN2mj:-h=\nsMkC6C.ns[vH EB˚4KA듀mDG]&^QN7tÍ{u}+]nťNjO't7;p喟5{y,/ҷS܆2 _SvoK=\-!/}zч@xZ 39eQ@~=veJh %@NO[}O9rl`\WBIߦ ٗZ@jbdMr_q$$QZvogAC3̀sa~yflR4;D`=g2y%HRYHuΗpj3VٳԎEUR\1bV Q)Sa;!))leA կWꚊ R1}i` Dhm)4_+|C]_L}G+$v{L}$z'y|.+-rqR2iOOxmSn+,yk/F2֗/<_k* ݃_5! Yl b1F 'cH$p >ѹ3%BQh//`%t /Q Mn,!lſ~X,^> Bz5:JR jH6+a񆗞dƷP ;*˗u{wZeY[X*ݿZXJ _.ǿ09ȡy|lѩN.?AQ9m6R94zsL"?^a+/_$ JeU8| ~]]Hn->ß6vwp(zF=;@NY|PqM_DGiSܦ&٫羽k=?'=.[$cDRIE;K*mxZWM|Aǵu1=4ూrkIq;L!dyx?_#V! gsCj2OX> ;k<]*Юri20MalѷX"dP0\0ŔZ{iy]RYe#t!`4.C'ؘo?~_>ytm o諾DԺnh -v$zr:$*}8v!-p?|j}c8 0U ?gK[GZ IRENe 0-8:΍i[$g@2؏2Y+=Wue(k(6;Zg/.yCaф^Om^ JJ$kM] / jc%وKbnn#ȇviq4O q)p,8޸'娧>?M:6 dm*D1&mYdW̞>`(K_1 xqz#q'",th@L?oyf:"4-#T|kDLS8\DŁ,?lmt餵~zE{ c.$Ԫ H=#cigsO1;c)QHD![N $_NjS9%ְLǃRFH7mΜHh NW,VƊK#>&9#}cD*Eg'kiy(G Gv,ME_܂$S7hP{1c0i@d d/^}!Afu\q^O=8ht{y!Í7GtAm 2F].YN"p`X Bvc;'1إf,9H2Gȋcd JHU7 sTE䅩Z5=!kb` *t>֢KkC0N"~LJGۻ?==]zte&w>H#r&O \ݖhMJm֖T{olwr܆\#ptgs"w^9&\~Ywԥ"Yn#esyFBD )?We\\7t!Zn=}ۋKm|X]y^^x̅l-}n%:^K/t_gZk=\wb_h->ٳ.u*;R؍K6೻A57 0VX  őx a-/4|KK+Z[ /2JC@XԧR|kFTE)`؝%kiaIƽ~WE ތJꛪGJ=h"TJwϏ~Yoxkb}Kن\yDD3FZ%|9PVd\="@"rHm2C)eۏ4 b.5WsEk3 $AYf2C_6  X-}YqA};YkR66xʌyS|r1h%p ?C>h~ؔ[M?/2aK+6g:jJ iɹee:~D P Vg.@#K*0 uD ^J&5+DI>([O[r^_)b>k34{i(6$;qzokpd2_~__ŗF!v#@ {$f=_Fuq;3գ:ȚK햑[5yF)kBܳZy"kv[xu?޶b~gWxҡXNt5ҐS\[Yl`sָ؃ G=|_`;GMFymDGMz=ۢ(Φ"cEĹ!Ӝf呲(×i,Yѝl$! Ic(۪Ar+U* l}Ci6~c wInl( ;9e:R?D)%" % n7$$~܃wyP鼔P#C,6{eߠWe*)fwyE,8t@'91۷.`~xCA!p$mg> 5[֥ڭ2p!aӡ<ѕvU~ ~XjYzҮ鋓U#ո^wO/&Qeғ1@ȶXĂ3FN/_ˋh^O xW\-w6Z{/6tC"vgɿ+UZQ]C8t"nVEY*u;DyT'qRo#vH\%#hR6iNn-ƞ8V2=Y~#=frt 7/ߖM=BvQ:gpW/2mھy-":> ĉ#bӟF`טdtno~jd$Y.jz'm(ߧQ&`QOo/- yEWZʓ_Lc~/Gڇ֗jpVۥV[n<Zn<~K[P,Uwo٧PT"OB2XsKK}h!Y/T#1eeOXy^g L}g<},xj,.|7 +0M3g\B!qԐ ٯ͋ ld[#Y6b $X&hLJYξ1A^a!ZfuUn9r <SKibiMA .(Af.\%{s-)oe3D7.Lv ^4X?">&) x>e_9tIUPyi<~#I TQ^6d$Nh:_F_[ze:azZR/D!]O2j)]м5;Oy'fWdyL<.jY GTd2oWrL5%"'gŝe`k߯ⴧ5A5Z"]9:YCc: _܄v%y( &4!oms 5ںun [K#VxZ6v蟷{Gki͝Ǻ. tIk]mɑDmb&xps/EAp9G|'m`\RKZxpqt"hkaƾsw.+W# N|$Zj q$ɨpZY8QZ^gnV/U ݅9cW#dK(VC cY* /eRMuJ21qPM\yH19BpA>}֔s'㺟''4usGTTU@뗇xLhۿFNkUD+\eׅYP:^nC=lV]E;JGxcտ'̋HB-n<^Rl3&.Mzn %)njl@ZYJ>Sʱj{4 Z域Am}YZG~s/A_w%+5+[Tb_6"4g#JﮖtlƊT~aK_"C P|i/K+6ّHcGrSO8"1Otte}S̶H $<% Aܪ'ik&mD녝evڿFf.W5?]W>Ɖ9?_(SF"ނDn/?[WZ)%Y&}z( ӟɩU>7Yl~懧o!gNrC͋nv \~bɖjiKnB@Yql.ôAş#E 2Mwx',JnֈV=]}Tjj*J<h|_YKI:W?[bV}ɯ7DQ`?pɋ0?zN)\ %>c1N/N+ 1S2y`t-Xx?YD--Y~4c\ V iNė]EJz-NMsi{ CSzO/b{fy^u.z\SI0fX~k4vơW9GSÁ )dkAa 15 EW;ŕIXH^I]+Zz)'6~<<tO&5 J*1_؟ÕS9T6Rw4"`ȱ<$)Ӛ?^_`Ǐ?.!, ˼ o,;!䂀q*n "0_"h/^K\C_ xqlF[\h!j)di&SM 8~<ۉ_^V"7j8I{9co_>0=VhE^}{g_./,paѣZ vflFl D&)bQ N"Fc]a}po:|,'?<n:,elpMR$ 1 JF moJsmE(/=E&:}e`k:z!.|W2\x[8B2 ˁ m%H9]STL0/V5$2"˱%aU9uK?Ʊ4,`!~~@++_.1EźdK]b$jjv}&>K'S\~ @Cb\Z*|Mh_1*\1!\R {~ݱЁ{w 17/ثhp5 sݻͭ8It>#]."|Y@GB0?e>m)q~v,[İVc`rqNT_U=5d@ @}P,aS)cv9'@`3|MN!gnDw!`IV6h>C5Sށ!W0. !'3V|}jU񫠲ӉHh$z,\0U5V5mjXޟPtG6\Ya^Ք4hl8!Lxv9h[K>^ L0{O\mInEFRgd0:Y bxw;[[׷6B,`e^5Zv6Y+yOeىhdt1lHU$n~?cCo3RY\kk^+=0.Y` JT|l^"6Ui(˥S%_ciɶhZ_ 7xЈ*?*~Tج"2%Bn>w|vz1ѥEY{Frٿ?&*d#b0q& r} $Rh[N | y'Y38Ĺ3|֯}PL6I³/ ({~T" }.74)Bá#p`ad+ cl<ӈI1?@ugGZd?%z]6;E)<}4Kh#74Dj^iOauS@!cK5h7w|dX%v cl_>*JW;R &]+ҦJ: 5LU^nNl-pxqW=קv1 بpw2*#q,3m0*~]PXd s%gyr*GKoc䂏`pw6ӚW^)XU|[MXV/-::D+ӷP][&AV C}+G{zڗp֖ 58 [,MmO^D!m_p:|khSh` Lo}v:v1|~GoWgnuNls3F6LpEOGcn7;1!޾ RᚮVص[O92&V,@gHPT\~tQa*[gz8hezts&Ub;k8u}b<1+lnNa} #D64ȷT'sdp_.0Ž 0wiM܍43dO N@=2?KVS(% _j atr|ղUl<ǖ5oqu* lIr:bduN:zUI.qo\_>3}aOH>ֿ__, /8M.*' 3ٕ?w}lEfdh ث p"[^]9Ŗp$񡦆BΚ!J9FwGkiM?kڮMIn1N82dMD:, ,/$1o!kdhVu4f^(>fk %|A"λM;?8vm-!ҽ髵tIg l|`dyT/_GH.f(l3 Qװ@T٣5C+^1}8 ^¿.UF*B*(En1)ȹ5xa%q^l/fa=,)Uj}?m]K/BShObMt{wh w!\yLU0m==FF<$XRP p[O%Q/f[=էm$iR'޲K 8s<+~Q+ euSNtz.́p_p6KŒSPQg 8ǖ\]}c\Kܻzu _[D),^h$6o\{ȓ.*PTsǜNnX@2[V3_R8-tsy< 7BkAas ;\ja{# Im-S;bH/ZZ94ϥRiȥx4 o*=Tn--SY(-K_*_znV1k=64`l6zxp2J  VA~˗H2Ep#*/@xSYyTLx&]m.zeA`i*eq}?PxN>E &%C!7,L?ȇ=P!X跅zDEI#Fz>BdD=r\=b"+qln * 5SK}ǜw7 }7:a0DozAT:e\W#sFjqIJިjH(MsxKCtF:;'7NJx,؂&\%` !,|W6Fq~{TJ:gNFu*4ͲI?'d$ݬG 3I~Wb<8 Iy`Rmit #6Ք Huxf` G$k\)&zgﲻZ9"Q_Ҧf@OxҔʥUa|wpo<$:K/-gW!r%ٺ l/0M7=H ]*t a( C IF_l·^E0EϲLv9; T\W ` k[Ǥ|z݀cfFs!sH 50?}d s<^0$ˆZd`ݴpgJ'R`4!>*݌`#I"V,.hf-t(xJ hkc6'@霸))#V_2*zU!dQzG;q-ê߽l}oՕXy}p)fƆ;i)sH:tyU/t7= 8 5.}]FÆܑyГ3`dEq5^x_AE3 O]ZHiciZ#Hq4miJD\fntwѩf`d*80ݾ\cg xIăF+vZ P`2T5p3jԔX4]4W'V]xJTcBV\:P %9Ep F,zꖧuUe_uhay| &.]yjs#gnGo;Lv?m;l;l!vZLD C:\\#scqNp!S:bX.]) Gt3RX.#Y:Ff^6 e=h6%2"v\b[pp-Ţ>(vD0:bYuGZʧ%> g>|5s?5 g .NӏႳ}L&,c} .Kfwn,#w|K9'Q.+3&_qj%c _!TYBIr`sYfE6yyumVi~ "DZ (PXG i$-4L.n%=;c @"O0|31k&7 &s_@.h/*uB$D.xҔBe'3;):Ytz)XixLL8(*@M\l 1:EgGT /$˅'{^![wge7{6D/t~.24gsh#=P¦qwj u^rȡ9Cn 8,!U2.§|_.z馼SD]''$HhVMvx!9dž?V8sHX)0DvsMvva;5/eAPsZt%&*R#vg mҽ4`vKJ+^5YcV:pӾ KֳV_2"DQ%C}k|'N죖nUnnkp-&7D:{ҥd}9iP2Q^RA"™ɮBԂ"'s |yx3o90kov\*mub~v>}{D 5Oގ/Z09T!σcFk a"mݱKD(T{\'E/ݡvrVFV͞f{%&)Q幖=:uDeV}E&˭K\fen>U|dv7 \˸S:ca1vy+|8C9(9 d!>5: " B%dy bqm̋#bvIo60Xpq@덪 %eKc|{ CQ LZfK׮ u+:"A;-vW#d$ [  o)^5|{# BfSXW m* UDǀnP61DE& 4e)2{?#yIKyږ巘9\cCcu3vSc>"ˑOe?2pvh,!mb- .j*~eYLݖZOhF ?ϗ?io"oxA-yo[,DX3byOFsvUxٿC/mg>]!:/;o kp 0Ez2rRX4N(Rй:"I4 yC)mN. _fVlpy䓾$WX_M<+(T@8?þ{kӼN3"l[%3u{'Բ\+6-WU @Y^NZo%%v._BBE)&?yUpLv{5rb, /gPs_LOFfZ: f,荘˘@*KCmqe6A~ a4B )VJ=W!<[eNB;0[óقT\*#V19BƘDmRdD"#g4su͊oiNy;-PҌC hJ"ޔf#h% Ѹ pk8 ݞZQ^;!SU,\_ ~DYs6ݘq&YEn墽sQt@%m$f}I@jQ,ӳof8GgJ %jq}Z gHBXW'ofԏUFc|Tق=,ČĊ0N"0>?馳#jpv* 03!L 7wʎ,isz@On0B dY8惷ҵ6us#qCβhh{ -^LGnZuYނh>Ɠ4K; D98J#":$P%=+TÒD6,`t 3T0ӣR{ylsXn//֏qGt:b0n#4/QFaO%\M0_slrN 6->̌ak^9&`ImQ*jRM+u/_+45UxS 'fُOm?FT8ޚ?CKoW`@Ʒ)nb n *Є35wMcWH'hFy'"!hE*O%㨽:گ$ 8bTAAmck,Zۚ9s fT"-w\n)X ФKⷤV@F?OXS~xAq=z[zm!pN ^LMMfZgσΡ*j_`@*S>B5:K֕v]Wem!t@%w 䒻ꘒzl܋S ɳDeiN_Q⤅7%e/GϠjz: ! :o;Yĥ*7z\6c"u3|J:j AM8A.Gر.Zv<(b=‘-=$!kOOX1mT?%tH\w| I6'E+DzXr/Fo 0?R*: /ќ&`7It$RCq6*=5;P*Wbd$wuB_bZdrM,:^\CFQ8S0겡.\̎dDqxl,)%$JWKmuc}y{`{J\V320Gd=axe=leݖ8@qz׉.;(nEp (<w8Tl+~lK;yЧ.PW7ڻU)Nou2ׂSф!vk/mIԹlǻk?czeUrm՟(ݪfӜlU3E/ITAr FœJ6vتNЇK(~RH(MJ 뢶v2VGjFc`]PJnCd*lVנg)Ic8?c2 0Y364 |f= 3a|r1p^fC=zǥ0k)ySѫܲ$3qS 3Wg9bLY 2s\3Զ Q?rwޅp" Ԣ|# QpiכZ30wG%\Nk''S_FAO'q`p4ъM4-OPp2U4 !zv%ZL Y~gϣ3ըvd)UjZqy)-fFmG_8+9'IKK%eans*!.a?#WS=u$DC,@ȌQ R} N8ɳג880GEL3|[eDm;D#7s&L eסJӪ]QX*HU$ Ue-y׫~u]OB9Ɋa]^K#|؃3_8z[z!hNy:C$o"9Pp3b0+57(_ڻSM1bK@nE.bZ8>ợq\H5aA駪4ȣAo'B=.ÝWGa݆O{+zj9ؔwv6e0ӻ}ӛ9=w͋`iլO#i i fxkD8{P#u0+&"( =/pn\yp( 52&RN>-Oh|sXA!1(S#ikXw[ׯ;VG0!ث3syK3y!t (0,*p΁+`k~QSnJּΠE/N|Gj}[phta5Pl($&}U!b+^pkD*H.F#.!q O1:N>7v^ۧUa*AHGڈyAZgYCn/)]Q0X% #@C@E۠H z#j^gݮpWw݀kЃrTҺzQ`%xHQbۢu< !_bqT-ofUtokݜ(FD:Zcn2e [_yP IYݳo蚂܅季kRPbZ6XWM@KדH6OXslbDIA '$p4W(mA06Q)Jw@ @UHT $!^J?G$IgQMc<ow4Ḧ(bᄮ.q뀶(ky*3Nf6fwJ@WW c%4ּ@BOs H0 )-svI@V<~}qcU**<̓SpJ.H|8kKt:ն"N&AS0>vAwXm>U;pb ­<0&Ć3ͯ)!Z9t(% h="9sp$졄uKq80^- b2~|-ni樮aTdFn4~K~IH)nm0" Yr(|/r̥L!5BR%nWƎ*1rCAÜz}*M(4{>&F$!{ GG(k'CeDr:-O(?j:@r70lp 1eZF T-Pɹą`'0ϜW7Q\AƸFL9@K ;;x;Bk?BN]{uvo|R>CĔ] -%`pTU:L`ҘqnRAI~'Ӹi>1Bx/xZiZkZT0s #T¼9Z)&@̯$qnaۻOV1i#U*ُg1Қ$634zTSscOq4XC#Q^m,qJucOv~G^':$EqU.m8 }dŌ܏L5-q9Mui)_=p9D]=8Z̘g \Oa6TMn+8|.& iLOQPJ>0I+uyHxd!bʢf =K0TpftvE>7 mSU,=/IԔĬֵaO΅nй7Ǿqc#n*|"{0cL{ #..,$;3luMt,S`~=qs6KqĞ8ģܙS*J6)\AI "e?6}mQ(B~rU6 ~t*~{9EOK[a2P Yu)e{阾^HS j]ù"3Jq0b?))̬bl "w%00/Gń.R$,>4hҢ8xg<2M[i @73Fb%y#~̯KVofH/͹g[zO T`W['Oo7]`{%*I2PJo)֥'M‹!Ni+75_]߻O15;uN<,}j8<eY oI`3'7xđ$]hH:vxǘiOo}5xŬ,i 5( :ѤN4}-A>ؙT-oX  Ԧ՜w~Zj9apM:&YW %"3ءx\q$e%]ɞj^" Avoh16|} '-OF᧥Y[6 !jF<4;@`E , !Bi;Q(ŹCpiuW r[\$ZPWhцG oK.NVBZ„6Fɉ5vB;%V_3@^-'w(0@?l|yO<Ňvǧ/%(jzN)N/KlRV٧QR!N6461+[u EK,n-J-R@Uxe:+{ZtآAͯ"ó7}dq`R5~|LF (NHN3a=7jj9ˍ{_?-ۿ-\duDְU(Ca-afbhx6ꫜ!DL- 2aL o%G>9?rAE]V7i] =gtIk1h.h+l(le jwڛ72ꮇx8xzfmKÖf6*jd҄2AtT%A,WX&t -ڳ& ؞qQ_c+Lo;5vlkŽQz[[ىQ,1kz_&Y8ρH(_]yhu@uU~#$cIQW:ҧ0/Xt]ڝ;_R dC~'G%=ZoNFggDqDH3L*gVK®9n4}Q /rKV=IrIb{ҸѶ&nc]J_{F"3fG/؁&o|M@렎_e=W2x}y9^BU7MtbJ`5aB5*{]z b48̷s1`FT!7(3.ʁ(G*>OB/)P眗nO8rzq((ȥȔn` aNiπH b8Ql{~̳f:+hZՒGL9Oi|NeA-@_`5tyX&iB%P R"q:BW˻,D_Q孕ϩݪwS'6ZQ#㮬mȹ+_ )5 X<(֨9nDZ[gӱ3B%B8D`a(GHPXRTҋR>kMKΪ63U^ @37_7#jw(Q $\WSW6* G.؁j7.AXt1~PL+@p@37d@ĽCÃ!V [6iUԃ6K6;i<A\{\#^Y52KV,Z,X2&[pP#ls8WyPӹ"%"g*ßnN(o>i*Q[h]J[7M'M9x3F|* Qw1 %P M8v]DžUfg*f5 uũeNtc5MF=nQ٪6{~FVO!SMzkǍ6 KpzECuUBTS?cȾ 6<4t<׷yPmVQ;[@ثw{m].1ףd2 a}p< qq P^Nfj[s҅1F8w } Kw5;UEQKnvzvMKөh8o㷊թwYoW{"3w]L&Nrq;6"G 'a,o:>pZ#՟>}LN1P)"Jհwԣ,"ί|zU|DR~{C7L@vu\'7J:Ma8x9-G+uÚ6[t.w? aΝT0ϥ/CTnDtnvo#MjusC>Shɪt-HR Q@XnY|k~,lllZtETGrO;<&k%ㅔ!dzӭ 5UX[Ĭ)1|(cK@Re @2\x}%w ą9*fE>T;I^0[i,FS&wP\ .(qI"aqn[[?m31b;?Gb#;ѽ#: ]l6, jLM~ #B CC騃X}a3JNsw _ŲXcC$b cr<4.Ppr/lD#F^նgnㄣ<`]CGIOt~hw+ug%Fk{:V+ \l5:MOt/ca8N;bPU0⨣V]DVKBQљL'؃gS\r[^h8zf*ȍ2S~ fꋬS\D;@o煭R97ueJ H |u0;|C>|~qk|5 F}%۞^Cˋ@82ׂG;^1캀pGYlp$~*)mZ<{N]8RArNF$wRʝj7;cjLc4lBӆA0(ߓh\xv'뙃'qȢ~ON8ЈoҌձ$aCSaU}|n}s6)4IA}\gU`ᬢPt>`^'9@28υ$1Ӿ`'d3&|L=՞1 P]Ϭ ujww`aIY.!tEt#f|/^<#]Q#~x:o/hhyyݙGQ\%_rOO`[rB@=푞JрGYYHWeɈRK]wc5hfύ,Ȥg_i/̤WV6pNzJv:{[>nҍA @n40ۍ 9|rP)S H*k]M&/߲ {dٻĐ\$z^%4H?T&шaM9-!P$7!sɁ[ 8zgs3+~FO+ᘱt 7I% uKK2v} dF{l5rIA2j>E Ȃ$RŅOՓn3U*}rl?lvGY7puC"N?0& Xw1f{ZoUbr:OMIɼNEj{(}Y1A3zGŀ6Uw$9 if ɠ~4]:^d%`AJ R A1qVaj)H-_rMH2b'1Vξwq?RX꟩DXk X8 BphD ,V6􆣉̡ϻsi[@͊^4Ja34 w!/T)hh+ey密uO|qy-׬{tw7C.%=u9l֞{FHDjPOR,-u_$s껤.%c I;>i.Լ||n!vդl:Z\nP?U}6l"w諸Rhthܡ+0+*ݏ-oWU1}_0k^eǷ6YGGUƜ[W\^uGaָҵBw_X:uzgߕP], <{1vj޻Cvщ\g)H2cmg $~aOXW*7*դR8}x85';P:^C! w+<(jCNQ%tYiJwb_[8Yt!!t.4Y d(4c9]m63f Vrx1$;Z@4Rf o\SuXWWono٩@W  ’n)oTo|lw ĭF?&m^5m}JAϗٜKW~? HYH`Ģʖ {ox[7/RGUɤ!@7s 1 u`P#TQ`5*L$s71^ }> Ϊ~Ɲ& fXy͆ppO5>5da]*Ij`/a29gbWE&0ӁڳubV.?Ƕ lMaO,4$̨tWr&~ZA‚XޝWQʎ/ѷr]͇X'1"f*~+Y[ʪ@, vؽ;!J}n w iYZj)3'ۅšSl~պdseuDJJVVs:H+SBSKzTE#*ҍ)Ot[fP*3XadH^7Xr"9,#o`%@guOMPOOKS9 g_)ek̓Ί*A ~OS%G53uYȷ擌Hub1$7ވ5/պh2+/œ҅eHNrnOVUdz9rUN ZAt|?jwa߇r_4sIt`5ىmv}=(㲪}LvޛZy W^|}ģg^X2v`(_Z9 ~gAw,#%*g#1DE'J "K}Ewr!]nA [ +z4lA_#!G|.tG Q]')fH4U⮳d(شgahל= oӝszݽC3hQ{M$_`mv;܂Se@~/O;%FI}ntg-։|(.$e;mIַSOJ(v&T}C=nP̪,yfz@[aRiW%1>L7kP"牙"BnRu[ 2yu΂[; 5+CIhnޗJ$.5ʯ @l9::6J2׮9OA|RNR{l i,q|P Ou٣ʜ\^.B'*s>[Aj4!3+ =p#o x CM XĴT8| L$%a{4<@8չH4pk2oRK܎]\9SŊk0!)obsg!qpe[8t ~7tBԋcU'mgH8LWϺ`s9X՚1.ZtgFnksOO[ofԼh{y,6˟; u-~!rbYagF*Pܸr61KsCCl8 }~ȳA߱֟p>Lv6 4iFnt^wiUuH6/Г(ZyG<~?enI ) ҋ|/s[Z||m Wv/G1rdV oAG%`  C!~b0Z /¥p,lf}\G_Q,Jz:t _ir9\A&Wךfa.}$$N=y ԙ#]tK%Bdkp7WjMDk2zи9hY2-sn3F<1է~~ _XU5ŴjQ‒UC)^J?۹GbeuMn*Q̹G '%?m8<2fߩG k1:%>E=`sU[rf'tKǠ8NA 9$y6ua9Q9P =Lpq|>bz?zuQdx%޷_K[  ,L20vh{΋s=V9EII^$2o`#jfNKr&/ĘQԹԪyt+0Ȭ+DUtt9yPp2#d͝- 8/zd4Cu{\m f>K˹;twٕΦ|ö|ҾKk朑q(?+GRoˏ)>֨X~&D&ogmAލq*QFf'•.xo[M4:F\˄ &uʄ cK*WMR?mb"q5/* 1 hC/~C("7P1[Q95y!Fwxq-A9nIJ!PmD&C.ü;λimMzkb|00352&96w'j;M Ʀ/}띃mDK6zAb_⊇5-(TJuDr{qbr@vlC &d!Ue 7 -PZdh\Bn[ΜxpR7qEL1NɅ,,R{?~ 0 ,Kw&߈+ˌgB7q$JyZ St9\&J2m`ǭ&^z%8BxeS?[Gw6@ ?n.-?]Jaj׿?,'ȱȞ%Ǹ%.dCP=^>/s3DEdȭc\|fwUehYLL9B O.ȉͤ hi/^BGaKq;|֨n-Vҝf:VZᶪ4>$!nM1qhSO{9Nƶv,oO#u49ޅ%)S`\Nsw|^֨PJA{-j)pªvaz+;LnѡA?2V}WBL }2}jh}ThXm8gqt*T´Յ^5WF50tOD~.Z.JN ˡ Ns&}:r菩хw#ҿDť6>{pKC`C;K,=z1^8f?e0\QAUڬN+l_)U8K5<2Pfj. `F:\t+{mW8 ӆ#Qa̔$9ɝIF#F|I-]\Tv̦dr4>[t 蔔nur\PXhUmW޳! dC/ֆ<  ԆF~1a:ӣBSxsH9L(HGIX=!Wya~x󷰟 0C^V"=3h?3*KIz{ҟb&#G#S)WhVVz䗾`_7: Y2UQqK:8b+aLvD:)LuH5M^U{KuARk8^gL_i9 ۗX̛@d~4O[48FhSXo k仃Yի (!-x#0z5v/ֈHG "AL/5-8 5揌mL7GG'uk{*υ%U捡@ 쮭ՙST|p#yK:"&\Wb.Smj>kqr}Jo 6wjl,&~z:vnvr,isby#,͜(Vmo-^[g70-!ٲWk@~rvgYAJ%L]GDСp,٩MȞ鱟? ҿGagm݂k{ffΨRׂ=(Q_jn!̦)s4~}aPJ絑ˮvX r?}YF, r7>vF7w-$ OX_0G|5 bhhJ8D@aܩK :|3lƒ7X<\~ؓ))wW'beII]S.~Ѷ:IϠO..;vp^e6X\ž20҃y Qn-{id ]PwS.e`/aR}U] ]M{8=FpŇa]&:g K47E9!6W$vg'YzCMAɚ6zrĮs:Z]^X4C`s^~N#)ey󧏗,k|N1X. ?[Lμ 9*P(6 5{~s6y)٣fi&1wbp|_ gkʊ u_GXB ?eCTch\.7#EΫGE5t?~%Y,+iD1+ZnV9clqMs]~L_=esz.nFt}[MTeaEoȑ'ҹ,[{8&1x*IUj}N;7sKVZ~  \eQ yX14ibWYnjWrQS!hLi<'cF¿flBY_cI4iZen5y=yzs5;jIkFxlGVq'LuC ?;]L„8ۻvӮx!1,7j}lG}4Kf{ OTw.umJpNWA pS΋+UhQ:\ށd _`bCǏrhD˅BDI%6Qѩ]:[SH8+ {A/(¸ x+uR{Cg-1yzOp霣<84^F2x>M'ag/2@ٓHKy4˗GLZ hdB#]onLs9D!ѧE"O"xwχ}hɠ?ţni`t&fD |'.NhX̒y_i-V,~iRrvI T֘ Ok(9pHO8.Ϯg˿'ipk_d2friᥖz-:3('Ɯn]\l9kԳ#w.fO \#1u?r0{@?ES c _BQ<ll6k[6p_l~f;_b^$.oqA"ItF[J Q=DQ6)O܉;ԽKxr?>n\~)ɳO-փNscZe'Xhv7 σhSh0zw۰GX'#\scx6KW=;3!(ZtV8>~yn[ ԹX^:ߺܮX4g+4>U {ʽxkqjq[ @= {VtwYA&X0X3MR͓tc9 f#ջ"57a>]*u`ϰ$v_ T N1CPo}ŏAf}DCz 0 " j|‰CHwL1DS >Qr#H/eSze4p &I9*.aY 쁢eBb T0N_ĥĊnYH]j:WRw_3\_]CIJ|Q&CiϤǤH7J_6"L`/Ihny㋔kqZWwBadtHM(B&z~nW_a}um#8RlD`ޝPia_]GfihnEʻmA @ []#lguW^64GHA4glQGzB'|4-ap.i~Hl@WKh?p](," a2ΦF6Ȟs|_Xc, [γ`6q20g*G6'3.ls5}DyO n8]oOG]Db[(ћX XY[6&NW}bE縎v^l'zuRAy7d( mȠ-Ar#>1~uN3y9:0qrrƒ1bdǸSıw~ `Bu +N(Xɥ ʣ76jHZ GyufĿ_S|ٗ.(V7Nxߕڻ5}S]M@QƬGsa\?TRznjPڤѰnUQ-txiEfͼf(Ԯb 7wLfDWˆݹY:%iy~γx*L6bRA=$e᤬-%]2Em5<*ږqxpEH!$yhL>8[?-I;#S*x@<ޜ3ME5T5ֵȿLñ8D.QzB =V"̟uENP{iH<㣍#`]s e~1xUvoc( )p(&vCa}6 ts~\10Q+\u*TEB1o3#W=8Z1MTȠqۮpX!abkjY|xԐ~& y3,h>1o.QtV[;yYÈ@>:-ž6Ljyz1T%"QU N0)/0;BGe#Z1 E]NZCdN2S! ޥ9I~!f6wO~*ҪfhCO{7tA8isٹkeB:`T,J=ᰍ6aX`"GU'iQJ2Г x+,pt 82Nͻ\.-N 2ná#dռ\_B X0=9q`olj4x4 (S;< jg.D jAtb% ˻?<{}ȡec]: wKOFtF" b,VHB81I D7%7$ zVq y%P>Ag&=Ðи,?O蒠IT}'9؁mS[$fRz=<:QɧaUK!i2DGԭ#O-4u|Mu2oB+0 KBv?#atn=5IlqpǶfT8A}+s,MWN gMܼDpq}J\hQ8zj;wrrɋ\FJâHXʔ?E 'pִM48ZW#6Z$,([LXYͅ/DHK(8b3PG)@L(69T ?ͥdPҖگe=@ Y):g@b.K'?C-\Vո?CIXxނIb'9*ua XK,n(s͜dGPiEzM_âo}Q=l9:#q:Pv]Hq-3,k0޽<+l@ E E86XĜ >mPnai3<0 T +_XiJ&ɀE`j2< dkC#un&l44wPv:bAe~~w\Z$p^zbՍ1MvNK&fZ˴bͩSn0+6ĉ=?IQ4$lr\йz<ߺK*/*1IP:>4lSvIIa w6|Rkg^u~"{Xaձ)q9S8mqaWk~R'ƱU#09a^ӺH$3GY=:UzaEaGK+KKƋuWT~wf쥟xd`Ydk+|ӍRMfO$Q7Н«Ɯgĝ$t*`D=rqʀXl"F[E˧RBHK _6+f9iG W*>;KyZ~1JؘlB_3ڤ'ɻ"9M٥8;s^| paNP4FQm5ds?Pf7ސ_6V㟶$1Ji#p$A"bz2|}ZpCD'4ídF^ t,tJ0TY8$ȬXg@d]u oxq?:2* -9KkpxeFabClC.^Qq }꘎1p4hO㿀ȫ12䲧X;Jv_[o!cΑT+]p%V1/mpHW[ו$Hf,^#.`(R VΉe!3oeQ'ݩq^ D ;NFT[Mt^{B)O9ps_ zn)7}G֝# ZHo7%&Ȅ6vv.xvٜGӳq2'L#3>ۇIYp4_tJZ91 0h jt6e&e5:'?s[: e#7\MU/'Qs~{to7\d&& " ^AgOf>΀9bҜq(tIRARPNWkb ZGe)'б&qH[,Ip||v A͊t3mXoogbih9\TA@G, J)MLh)p_s'EckE'1<̨%1 .B92FZr.4z-{`N'_$ X'od `Gh&_{xO5[Y (@#. 2"v i4sϬ兌 N(xT&(MIu!v! ;3rÕBlڱV vjwe&׽+1F}3>G³ Tȝ $: &:3`Z~R,U"Apbލ/vtpȻ~q3)utU)e¹Ee凪xi]F!ck@ 40td6VpCʌP2gΌgf[CpIc lba:D4eg'#El}O?϶_`Mr9 M%1IZi7OAw4fr,lqQۭnyEtjݲy}`2+.nfKX+#7tNyc=ae%De.{eיbztO,8QS?B& `fut9@`$ 0ZKo?,X?NdRT2Gbk xb4*9ήlkQM* !mvjҎ)oZQ2^U3LRlοDP-}o1ca)p{#bjZӸhu`O.qF5RI9!az[ ~7Dj?ù`ߥ?3n>}|O kHYB~ ha_ExI^N$<̃[|F$!iWi&/ V6!Bd؊Z`db{7S}$WnyG$PjynΠ2gm\ᆲhbƢ(ªqׁ6{bn>L[B׈!ÚZC FMrCzY錻9,*k|gi;Yk(oɐ1o$㲆"*#ssKgɪEH/0x=05Y:6'7&] 3*7X̧rTCz*>xMdNjy=ҽ(^ ž^gc04wpdt8Ōv98?lN +!ZX[ :5呢knp!R0Z1vrN{+ml m}كO3Tz~'u^0L5ITo,=UsÍW FrLnp#_՚/9 ƺhg3i ])+0Lu#Mwx?rV3ͷ] xn_}cT视ǯ,_.kRL TUaj> ux1XD`873#T@練4 Ѷ]7ۧfax)\s3d5D$hWl{t^-:}q!*TQD yw<Ȯ Dʝ{n!r4G}D5!1 pJP]<٧- 5IιeOBAk-F#a3q'Y7ъw(,֏:`] ԰t'q 3^˭u:g=hfSf1γє{_sC"`*@MsKN5@6QܲyWhB_1vPs48F!cXϽ &VSFPl:Ä 8Q"wF=0W|r$)30W *Υъi:q2ê'Z )šԜ%EhEé/28~O*{򯔂W-D> OɁFxQV a2d)'.ALX1 A<5~}GنL;eb2tmS2h<8cժ`$7:[\,6_O%PCB9?VfZ7}Gl`]ftѱoBeHpwhOC]>fI2;}"ue$q5ܺ\+_O>`e6#$- إI4 4k1ZNW%zkOd- )&Q()5"=-hI:-3Z K'>Lq8.vC|҂_A.9qތ5>evm>QWˊbz}^ŶzL[7}cy=٭bſWR]z̲_ɯωKe@i60d^2y;1m@2 yskkwsk =h S|D;*v0u x3HI3d`3xf؟0% 2p3̕9{ޏۻG;;.Du9@ T` /< d:g*ju*1 \͌dU)EɪϛݭJj=Ҿ_Pͯ. +F7wysDpuugd7'B `? 7io-EwtPJ^RQ>h|k[ﶾD\Q0w͆-9O84X+& dHF]N& Cꮼ}b޼?y޴}&Ϋ7,*DB֘$WaɥUo?>##0{ בz!5+vi'`Tk [HIHIUΎrpnx2A ;XZ|,K1yUmUj )~gtQM~vCG2F&?q #۟gᕯr$vb^uH>=9`Ϧ1 Z5yC;]qojM(]Msí#114QܝAXb^h/:W,< }SY ^sQmp7z`oZ~c&?pCOWdsKsLm1⬺KDH*x:C߀tPA6\Wq~{f/4o;-/]\Ư(^8>y1'q)[awk,ƍe{Wy7xluQf4ܾxIY~ZzڂN?NJbsj:c̊sgsq} f[X*r#RݨdI3SiLoJ< L 44ZW0+#_*y9ttr+-o2|EF[vV6i﮳1)_DHl=[tgAL=药P>5>!vƧa?7jCm\+^T5snz5N{퍮eL|l%'f#pw|`]^B Y Tj랏&x?ol#1α9|}u(Gui.ǿ+a4]Z\UizTB8SG/KJ/WgC'#`[i-ůoJ% o 1SGjEs8NpWWG{?ֿ Vhn gmJ?ݧ|vB>>ve2*BCWo%?Q%`H߄++%dnRsìQVF\F)VI*I?5f$$CoMUyŀDh8©= +S_N(jby+O~)JvP~ÅgSYMa]ӒƗztO.7 iiyW lv֚ALI7ݭ56ƛ۱|.N..^b̅³!@$y6%74vsw2{#^oҥK#W۽a E^!cy-ܩ--rY@r7ۨҁy7?rq]98E%Qc-Ɇ=-l!;w=Ѭ0[Gc~`Z̈́SJh˿!Ϲw$(ͅB r9/zOZ]hLTA P>uY|n\2c;_"NI S2#!pEUh؄2fXY+ٕi,(M ^*2 s]sYXyW;{w콹UbWlWT.@_G|3K/Wf"|L<0Vxäl THΫ}rD.GJtAkfG+YG +<航q${E#֩fݝ\ytۂ{58V>왶OPqDSpH?%Nɹgé1?iZ7U%ha„~4w:K#`yxX>0K+An difğ0@wDQ]2d3iKJ5lɡ0HRb&p8ܭ?fأV2X('14taIQҾes4vA: ̖ć? ۑёC)O<ꙛETH~;=py6;iOP3񜯘z:6ߥ迳Pqo3ngf]D6Іe⼡&aO(5X9%ST^7ڀc XagãlL; Ut I{LE>-aZxh[Qph],X(7cbyMĊV29E:M94,1it!Tk9.{A6./[瓋ގa[^ W `/yS|iM18o[庡 (9hlÀh_"2su?`D[+ mn1Tdk GzQa۲Nii ~I@dw8iJTAbt{)Dz?XH!@dGUTdbkwucv71Ř,f1v;%㏈ ԭ{@fK,vE#)2s{ +ghu-c`v Y0~.wpXHGz{4lCOd$#elIQva qΌ6PS1eN/""Q0j[ڋ`F:ṵ q-H$.'hiͺGކί*237T,+V62P7O uV!/|)ܞiYiUmUF'FHļPҜ!wd3 qc~>e.RSʙN#4vR& 5Ga(# bc& YCulQ^ũF ?eiҨ)0vlڭ(rQp0Fհ2:J<"DÞդ 1gk1 ]) 7"2\ &9}IS"`!c(t飜MP@ِV@Ez=8;=5{60a$*$?,?e< JeDZJ1ƩEPB;__41JDh&*x oBh@&nrN'LY4B*8PtxNG^qͦWx;?^z+nm-?RWBVl[.2L9 bK-ԯ?iG)'%Ɖ"ҏQ&:}G^8UYB-e+aׇDHKR) p |<Q[kaV(#OV"ocbA2;c`7:)dOGoIxΈބW ccRDc#ӫ"BhBd#DnVtW [ .1 Zœ+C@t vDUWd ?ש`[ʆDWCBp☠ 3(7n̮IP~zR̊.tF7n]up1y =NvXj+ZlA^wFC8YRa2n.V"0G1,U7a(QX}c)Q$b h#Q~jlCŋ"ы {iO:(>B t"$/6!ܡˏ; ; *HjٙTw( @ECcF9ArE ffބxH/:RS&ޘ|y8 6bG+퍑'C̑cvD뛦 D (\h1Oi6<(/L8.MrQ9kR<2+r:9ư2٦QwKȱ9;ȶ)?FT钥hR򄤲vKؑ@?L{gHmPLD)d'x@nx7+#p${vȥ@Eڷlc\ G 9)210b1ݬ*)7¼ VaH4{#ʍ*Hpz#G%)rlz/ЦEC@aP3IQB4jt=Dh8.-J$%@dJà4K58['*ͫFc#LN$CR$7,K:xPkr%JF,7n )*?"VT DƃWi N׀U<4cȲMh/YQa7/mjByCͨ =d7BQ&yAC+<ޥYf4ꍦ me[RHc؍Š/XOX/.{vqfFB$ڐґ:Ei0ѿjwz="_~bEDw%3z= Z}CjH͍qOarOR*-=GQ޳*Ir') KL-{80Q%Yt'Aա! 9m4pBj#(狦g= `/$NJ\C4)L8ǥLx7Tޔqk:)oR٣Lr1m Ra ːa*B8=I#<-rr8s0 YN~Z MbEnSU(B|uq4qp*/. ]C9g0_\+ۡNG Ghie,_0u#_4`١9GlթgVEX)x?+i:H4y~j_w^' a+SC3{@E3D'!I-yEԿ,hU)S] -]e7d]P8\< b2%iEfUik{#/ez,{"aIfTaxU*eZ+p\X;qKe"*(C̦*Fp1$z9“nT*#e{xӟT7ofjʙ9beZ8b|٥MܥZ+S<-`ӞQ5MyAr@ >vJq/n40줘2^lC^UUpNg4,+NJ)yq 3%9% 4ߗzN{es0'BxnD= m-x Bb R35 ,[?3 i= ʓ 1%Z4)U8lt*H!6lf„.zmMtW8&cwe2޸\KZ6f綈 ϱI<f[`Oap?ft܂tE(~K6\)푯 );$Eэ1g(#?XByw2;u +O.InyuhsЬ9ܢS$80^/3Jּ"hC,. 9 D$fcḕ0$~|izFFF,R~/<Ƀ gqG}HDyTZXOKLiͼ~'2{a&cGH\$%P0VZ0`e9bVTõZ]vl+~@ GG鱻vv|ZuVB 5?ҝi/tEMŒvLoq̲AlqRzkOKdл=k^\LĺcK8] Y5êY֑y_, &W_*ãAču#5v uSA:Lsu0U*No6GINUB -ߍk(_Jayl7ibWo"Xe(k 9հCcr+;*botWc>B3Rem9= 5[s.fV3`2;t9 Uc]vb.#ϝB/gd\&egp"Z653Tha1׈Yʕa,Փ5 Zu}N̲D'uk{Xi 6"6{<8X` ~, 9XVLzJC+/ KMjcx[5kءʩ_&  /Еk˵e6rjb+ L(d Ŵ4ځYj|{{D8\-"ۢ+e/-` FV{e0RhXgDYIyd|*!`k!X9Ld`) =$z6kiVС)БRBH`Vw~{7ݔץKHքazHaty&zp'~k곗OQr0V?(a6_Kew09ѳ8RbN/ɨ'5ꐫy.m3org~ɒ(Ͼʼ7+ j՜/˓˯J[k8Qxmql [-T%h}{Jǧ^'A=9魵T)eʎ ,}P{fh>cVK؞DuFH #`KligpuTk5 8fc_%֫v>};+֕T15'$\B%CR)7/_|Zjie3(XZo$5Qb셪aw?c6_*o-[" C1X&o2]U1K"pF-NHaO8G9Eڳnj䡙,Յɚ-UTwB܍T(/Nɾ#؜s>o53^ӹF ˻EcsL.hN,lX $/Ԩn؄gA-C4(5@j!2]U kw\a1Z5#tƦާM+qډ9{al7%<>}>@6v,C"ɰJp )6ei~^?/g."{&ҭ0](V kd#H]JJJ7gj╵ikr*-gW>6Ni?G36G!6 &gs އ:fMQ&= BT֖tCgC8`n˹3JDH1ฟST %:lXG٩p_gY>BP\GpaSegnZV hgM˷L="0mne!_VF068pKu9L "5.܄c/P58ճSOՅgKM&ِxJ.O3pL!pb ӛƎhFqTj"솄 M~aSc؁8&{x3xmnlrimG绰:O.FblD⣣"op"7ـC3=a?s߽u|zAy۩? W |j97@*:wM ՇZdͭ^]i&yX1\Vr b8_SB^p"B =m;8\6 R,o`(4irID$J9<ˑzpGNK84D)LB3ՙygixN~y@ھs|ƔuB$G^N^nT5PhJ<*Tk2)to1!uT́kY/Tى!&[BGP:]ܝ^;O/%9& k;~bHMn12H<6&j1o71^Vސ74pm^a&oN:%|q2W~xP8:tMuD4B*m\wC7:x)J >d7(Pqp2/I'\by Q.~Hz=e$5ׁ\wv{ RPW~o9q#(=պLmM%icmDñ}[*fҕKZpxy"O&StEِכ'ky'L/IQ#4#pF`-Hdvٳ_pzs(}d$ࣴŖGtz0Q*ր<|uNIaUi wuz"t 84С`\d0{lL];i,òZWKv#V`݊yVpSDhkG=B\ÅEXZ+cziKzЀUҠ':P|11Ө #>ҙę"НӅЊ@i-|'+VF6~/ -(Ƀ.mU.0Tx:p>]=<9t_ zor.KFy% 0G7~ݪ]‚F"A@"!_<"'R")Li80-nrcQ`"4V#lusƵ+nn.(͑jo!>IGsY#Ep6+xxՀLƄz9]xN4 -eVaK(nRI?46=d,ُl *F2iBOлs~EzJe%i[űCDѫM9`wH}AM8M@֬|߲}bZ3~|0">-r<"cc?zF}?]׾l}8\\51:H)b`O0$_e)IUKA1ŸK/4sj!by񇮨&+?PN 3C!fë^Fԯ15-$n( ]+,D.@^ "1EC3 |/ˈkl ?*;~E令O$^AOzhGסh.DSOKHp;eTM)>T٢J!e`r"5OSyy)YHP|bO nnl-+&Uc;$쨰(˙=Uakré2Ql.`H]T|gOEtB=]cd\~wQ/gl(1Ps k~Խ^sNWm t"P.P)f_1Cuo>;b܍K]@'Y6 d#yw< [(/ƨT #{6՟;77㱏Nl4g;F-u7X!]뽉 Q/xǞ322g+R66}gkWXqջF,^!cΝ;x%;X#ծh=>>eJLT WĐpx86V/xy̢#lճ>g%<2_5{~J-DIm2hI ,S"1([px79hc綝Con¾*%ZwTf^+l?K@;8w}@ sTug_ͲE"kPpwvV e>EF-4%m~;i&Y@ăWęnhL æLZ"ɨ.iL ] GWTMQ[B$̾NZꟾ(j¬:aSdϥ0: 0@@<dILHէAJ'V<I\56hK;D AsKo[Wp;ì,z mpc87Žsˢ6Y.!Wte)]w`:;$qٿi{-8*_I\"9$V^Q?ޠYaH.sVV.e>]n.~Ko6^ nB7;IywoZmq$\`5IDQ-]/8_iPb+]pʁ|@++5;{T2Mn1J O8 D+hPzw\ޫ;߁=NA5A*C;;!qh6 w 7킖HeZB'ѾCr)W)vmT"f=}ÛkOIugIkcO~Cy'Z9L S\ ZzU@NRϩ:J5Doq2ssiutPlHA{ sq isȮ@"rV Z:HA?KmZweu0UoC^uNnHzŵ—/>̘£B(@ S:>)gNSo֛͖q-/#c#&c[=<}pAY/%$#s}wz'Zڕt+|+fAmE~gG'58}м@;rKi]FEfq7'K7[͔";`A&&=̲ߣޟ7W=[t+"V\''hUc˓= oUAw\C4v\5{UmT #z.{Q [F4A0S{ "Ie/=zѿ xԅ.Y_BեCܧyaDp)"ykI +O,Irqm.`{uw.F̡vu7zQkubh[ qaйh}¸>v{%˪[ldg1|9;M/0fVSؓMnvet`bbX="ĊB*x -spȖ1xi 5-7M , Kᝡؾ[Grk! 7i}X* Ư'`R7(Y+z-{|~R ?Bao\5؃~pGkpzu6 H`^z dqv8V.!N*XWP#SM+'> /?—ǭBis!S*b/ɐ(H%n%3 D5&+aR9ΐR][pn P$q,idtC樸TdPj Y5 ;bRE!hءf1ܾl+2q]t0vd*lη Uz-`Nv=2gV/f(YV25^fghoÍy/ RP-EAF (MRD㌮zW?6> ' ^pC`[[̰ >l .qlRĉQQR Vk 5Ӎli[AygJ oMw("Z!<.}Se'Vq(n8)lreƲBfK TR/)ըQ湆@f0Ɵ;H܀ИRa!RiȂ#S* <2=&zw./ *a^U[EȚ d ?C&T_5AEюEC ZR-vd?~&>1b4s"2]RؑioJdTxo2,ừ8\6 | ].,vIS·U`teH W n6=F3w*(bzQ PW) S a;@ V;H~yKLz;N9UT8xט lCv$xB]LTWD9REۿK& rO艢/x l(×NopޒBhbR34Я E֍ d"~j snn o˅F x G˖qM\D ЍPAΨSb޺sn`BF ҦT U/+tvû1μ[)[?)U7Ϻi1T>_ə{`O@x`jOf&| LA-Rd6h~z{a_GK^~wDw^ɼHƦ1dI'Z-(<_m5QpiL #G'Q:bm;7n%Szd~Q>Pu{5{i6p Xij:@c[BP5$BjԭO :ĽnkA)#o(wޓ={jq9vH¶~w эxvud s|>s Ǣ=b VŬp_uuAR *͈(S]Z 9vWO3zԝc9E#7eP<ݡK# E^Xb-KQp6ДC?hvZn)ɍgnP8i(Vgw5\1.4ȘtĒv5z_%R4p7'ynaZl>C{q.]v G8A)E0٨$?&p>oz-  L~J-ζVQ7K^ĥpwN-)maLV%:HA=:@j0C]Ͻ1+θjuKw w.u.1N0Oa߽o/)GN8`P$ABOŹ8)%P2w0O#̨y0Mm؏vUMRC/tpuu[/_Qѫ]i-Fם +whZ(Z~ iY'i?b^ Do)}#h ^z/C$q,uu#"ʜ6֓#cTfhP#."2iK4堪3"U@S8IM_;{Sv֜2+@7ߥ;fݟ/su^ Da4{/+:!?ӷ0o>ι~s6wVUI^K졂rdA`B nO,ζ63?Њ6nI벎]ZW4vT&(XX/2nR{XɹM,ݤ#T(>JŸ%7bj| In~ NI)Wj^Iw|$W_y{w^:nD!cϟ\` W͋|v:y:á}2\=dJ8G3Ci܅-_u(? "F 8shɪ}΃n5AzzSvxnQj9Dv}{ǿv|fO=7},$R+Aqyϵ;TiHQߟ 1dר b)e|}wF_|qإu~rO0@>Ұ};WZ*T'ʃ 'r/'| Nl^3vS;ޭV,uzy|O™C!k߼?1kŐ0.YB !KxfOᙼ8n/ɜ ERz[2؆g⚄̛T43k'!D1zVoHxBó %,,?{Y Ǐ.Ȏ 4<ק22y_ D{X $kw T} J{>)Ȅ՝ '3 `p6/Na1V /"X?*xFGRgIp[('tv^mJWneE 4PT,4lk?ktAefd&ٞEtsDBK%Vp/BDi{ ? ЈĎe45#J8%'9e9+/z*)i$B&<C_?!c=SNtXI/W]~GsmʈE[f7sϑ0`ʺ=-ǻd (h_.-\ fa!ÜW}ìXFFe}mR/#yxǛ]T#kӷ><<5ysBA͝f桮|]UDS$2+v;Wh9ճu!0 ;ʍ{WFXp8 5@H݋.$sJ窄 i׆^[iwquv^B\g٠' 6 %_3Ĝ8+r@>1/b "OvuhӋO /{b"0.M \w"Fh%N A}cE]ǝzs^ X7v`;UylvK52D/[Dž˛F[k*It_s晴w=]^:Bre({>SAE X8>{VhO*`^)Dpy85Ktȋ=:] mU$Q,z-cpYnR˘E+<G#z E\hv@ !Ks!b52xQ CǘfE.O$A^MsE<{p뚝%I$o 1^{ɂ 7/I^0H/_yH'w- ? ,"vY_(vP7dàPYH׋~GװK^պ(\QZXV% IF]8KfC -`۵ǥ)B o?z!B @ެDzӋ ֠}֞Uѕ.yr +%eE 8ր\HZ(q8ު Ԋ1-=7f8UժݩZNȊJ{aFF?zM I-bsP Bd`CTR)) ZCEjZE᫳:0j@37P^"/*G"٘F4.>e w#eUC97ë EuɎ@ڻ*U?]啄uyr MA*^:S y:L{l2CMJ,uIEi|UҍRyoCaGK&2Џ`F<{O mߤ_zނ9vF7F{;߯R!@gkR"_1ac04= @TM7;{dZ T++|4V$sa p}O&6˳YK{5Ќ H{駱}7{7s K$q0,v2`fsKcB0KmK[E9Lǜ@uAt@;x[ wFȲktQޕ*o1K%+ ̌Lz+YX EEŢUEMIf>.eRaZVI-072Km0жX2JjAn-hb,icSM(jZF_g5Vh5,i))簣Q2^c`>Q^1yZ4^<{"f eٓ"p^L7$6䐫#֔~ӦJ=?Ew+2č;h rEuOMUAMJʳZ2Jefe _.3pZt269Lqg? A=B۞8 j?ô8킪ch A.$Mа-n(5Zށ$t h<'O±j[L{̗=G8SDHғ51YBҼX-Yj^ 0aܕcN$SB{ad.s<A 3xUP{Bj#+?V,K?ho(nG0,5vx-pfs)ƅ]^ 3mK$ҕE Ͳ#McN$0n\ EUU*!0Ի,K JnNh> ShcJbe&RoEl"^6unIq=&db]1 2#/.+Ȍ7E>2 9[NS#,}7611!{~XسLc܄ƽֺ50a|'Qg|_x]W^@)>*/e1[m$LPֿtR p:/rw&6IP <"4zq&/L+%H./Vbp2sq'x^!s6 ԚcNDW!M˹#x\{I,^ǽxS i%7h##ϽA'yS)緎Ȓr"lՙꏎ3ZcןG'$D u,3gZ);1Ξ,<O4oákO.;ň]=EjIK,. 7:^5 hy6WxG|֓a ƿ­c.+Z5V #|N\umĭasE# ^LE4!u*Q^N-WLQ/o> :F,?xˏ? C BV0Ds& kOJI gq̬JOf GD*Wx3vizeyuٺ3䔼Np^4@-#~+U,1 kr:CS UldUw amIU=&=.~Fwy0An{:izP1iWWWJ 1">zQKպZFÔE=cQ?7QC@f~AfV?)U[XƧxEÉx%^"8,/ 3eafY:"#CziYt%h>IuTknk Di PD\ HI{w;^^%hwhs,y%4B!~x/O- mL.ř\;#W7| 8#I{DqڮO7OF)B' SvBOO ]Z?ٍ*F"q"'4u>I3KE=?QQ>J`Z-SFNW|*||Sl ?=>[VWAN|[aoof}$_kTm?|g@ %OȖhXa DIJCw&Rea҅O'T!y{'0ރc級9qvz\@ CGCf?Hh|HSpzezol?0e*9'8oZ~sIoDfs@f6yT?2+"9t'psWoe,qN6:i"*糣獃o <'=',)%d) n4,lȮ)yN1Y[&ʚYeIVVكZluI mpōshaNMid| n'D6"n%V 3گ*Y][JA9c5}T*{/dRUT\HuEd3kJJve sLf:WQsYH%48B5A- ڭsQ;D#?mmr=fsھ {~6fNXw\7R*&ֶY8UcX#%D; ġ:Ң[R]l7֪Utw1b$f`sNw!^F>Ӯ$%pycWk-e uC^2XSzhaF[pXIpXgBj WBԪ/&a_DR(8LY EdDGiDS<~ k7ܾHή:mP}hg׌ɮFVlE~$uXC0Q4԰HQ5h|\6&?]i1Xœ3qaԀ%#&w&(\UQqN+A()ý^E9;U%Sf (q~xN/ܱR(^+@3a-0|>RB| iIj/CM)Շ,&{j1m.΋߬T1xk"OfC}5 l@)وV@~AG}GX / -vtX=iM(8j /| y-_uw*Dz 5G3G|!w\։- 9pv䙺Xיթ i;vE2g7h|;!j#+a'ۥA?,Ć~#U}P*$fhEι Vд8(oĠcAkq#:fru AuR$MRQJYg 5'(mJxCiQ) x#3RmSM$%Br%f2I)bp,_i]1U=W=AP!6^ɬ; ƥ]1t!Fg,7` HvBUM'1GMA-FNļ;!+)bUC;E fz=aH[ @yD8k˵Zg΁ K=:64_SXA4W%u@Q ԑEz0بdd s;IiX(Xo1Ěy0aj?-.)Ij@ F(3-ʮ;t7U I&fAA~Ŋ_>~1kqzz/bD%w@vĆ `*Lᏻ%ɕVH;),sc8ͳ}gBUN7em5׼}09*f 83åkY\J5{ͬ!0Lv ,l$gs.s8$侌]kXXz5 Qm'*z] ƽoeg9)"*8zԗ8 bE"*f u}-/wl#k*a!H,#Bɸ ]6^Gêzi +f vx({e衦 c1׮y469$̺>1<?eW[rKLsDȨdb|'BFɢ~ c&@4F2d.cN9H9#;4;Zy+mI&@# :T5bS|I~/Q?7tAr$ -{L*zHJSfef/ɡ<`Υm-ÃB/w["` #|CqPaŘ, C j% 豛zKPTsͥT/Q'a"o* sYDQͩ@cIN݉'NH]C)FR㼉Jm,#kuiPYܳwX$ ִ+z}~0\*x#؎.!R'G7&h\Rwjxݸ SI(WWΠdL-x>ŃCtDgO BD֛Z*a!82{ Pv;bcU,2:4o,${*Ba\#tYf5\0^]e6MP。Z J6|>fyD@(vlEv>4ͫapd%(û"@JN1e&Rlȧn`_@p 7BI{QCZiY7@&_` %[X9O.ΖA l k} c1ٙuPVU@{bpľuQYFr)k2O;X|)eĝ!@{޽Io0 Nw>ts '.7c̗KH _8Aїf'Sa>,F2@'N=0]1qIK5Ѝϟ a q'ߌGchQF QŜ8b0ʞo\Lt:}"' &{|`ߡ#:rv%JBK- -{,S-s!Bvz@녔'et 7a8Φx 7؈y<'2dX2t\b!$p+VkZnC&IS~yxm666}?<:b? _SGGe kKc /q|rq_h4wPGOŮpOׅcr=Xe;v"=#X @lIzO2~EWˣ07<ɀJczMAƦo?nri#D2T}xe@QI"#;p=g "ǝSL#F"~Cѵ;E]`7 vs\@G)N?Ȇ}`8"nl:[N6Q6u7Aa ڟңo;MiP@ ͅYO8@)pyd9@Z |f=K~csJ,Gx:aH:l ZB,:pcp 8#@/!Rހ+;$wѴPsQvTm-m:_~tt'7.|3I#z cZpvCeWH 5¸; ZɥZh{}ep_y+*3:Rn0`vl϶q]o]pmD\8xs8$Xq-C|=F#h !`p -^4;7.a6S'1Oggih"37-gpF!$PYX:}īr2yDlչyBl5%1KGO!?֌sdקa6"Gr5el|~rX8= _ᰕ#H9`xtuN(CLB_6_&2شU#c(2p;VEixJ VˊFh ( .we9/߹u> s%a;Vnl|>BcFѨf|F$9G(9>(xr޹zwن߰JaC&lruDTm)q[ ){Z;¹U%"[ Њ1v+OuqyՁu?Eoy<^13Jd5"@&klOJ98|)J40P&J <7R &ȾNh~ռJ5F XNw%wŒH ie/ڝ%a]?-kyK!^JL7Q|"?F+N樇_:O>w0 G|qut>]u.\cg80<|4sGa*<G|ٍzbq%Lc,9PdiJHQ/IB-e{ٻ\7P7"ؠi>c{錈SS AE%RY$y.Ԏ#cه/d!x5y2d5WDܧamzB tG:yx)u z֠{ fpr;o^ޞ7? Nzͷ(qֹx{.ZYNqwyuٺ<|Чֻ?}{Ѽ w]\N{w4Wrfi[>LnUZц 9B |Jr|3`y|eA)nt7@USEwO#8=z093̀)^۴$V)IҞP/ 2&(Ș c &(Ș c 2&(Ș k}f&S!>0|H" mYoX<fqO\Q#QS c: }̓K-N|wO@TG6]YΏn{̽ٶj7jGQR:`; iD :~bke\ҡw´8l9qinG??nm qN],%Q"-T488p) vR䵱#4=qO+cp,)rGE+ Hb( 2AA? 828*Ɉ氂P?@ ҅p7|3!8=1 67wJ# W&~G)^6OmN&FcRXJ0kR AV@VS@V+j$5Li (H;f$Li 4i ) k) H4exn'@C|iƗg0\#{O&VPTbO:''IX %K%KleitL$Vj0T7ONRT-&R G":xyt){⎟s>D#ݎ -NDS18i7[h gDrAi47&hl MckA<`msoB$*ɲS8Dҷ]F8O?woIKff7XHC-)/Yw&##&|ggc S1@E]<,6vS `ZG 3|Tpxī|pS$X 2١]mzw LΣgSR< w7|G4v)HYt()urg-TDvXJ+WZa98q 2\iY.UEVE2THٽH+WC' N|[lݓ]%ULcr3`UI#Оy2$M<#H (Cm MbjQ!dL-GA5(8_aoᇨ~qQSV5"' J{@=Zo$eG곽B ^vB(LׁUP#*iU0k% ĸvH@b dX|xԝ`%DYɺcϳ`JNp:^ a?mRx/ JlvT}[m /̉f8v/,zyQ`SGKYLǁZ3S"ٗ Qx\ɗX܏5'ؠTKhEzdqS?4Vux_׋ΫYKL)z6Ϥx%ٸˉw3#,Sq+0+eX: -D5#%T 1UvqIqFSP)ӟƳ͛dS8Ko~ v'EEy/dG`/-'jBS;Bgw2=%C]ZEڿVqVjiׯd+,ˋNo -!~+_V%P0W|,-~,`Hwy5;p`@;A,=̳0[2HmKQ\I DZ:gˣ{8 I=1gjT QYY;h ')GՊ޶FaytZZ9qO?:NcVdԮ9]jH9Jv-',YZsnUmw@B}ۂ~7S'7:TJ7[_~~K?j|ׂ6/9|͜Czϓ*S1QKՎfn|pO'ۼ9)Jf8V}? Zُ\>Z $I>Z0 a(B@}l\f $b]F9|K/v^9\ 0 }[ \ \d n6Ytt <|(n3 ZI47|(]-}#a- %vX'F |z>/s?ǹCÒU58|xXM[^z>6K־U3atS֗煏%H/>LY_~>/UŇ)ˏsÇ҇ZqX_xx8/|,mjÔǹCj m30e}q^X^7*Vb}a~Q1Ň)ˏ҇Fͪ%S֗<+Vl1lŪ+ x@$`v|aC t9/N(j"E) H,bM٘lZXK6V]l/X}Ec_bh2V=Jݹo׆+a`%ţp",k,rK} w ԥ^W'J@g[*-QJtN.;[xn%Y,E_$r|E|F`|aWĩcC`,ǚrŐ,t1A &nS-cЩk*`cgjт9SkWTsԤ';7Lu.CAIS !O"hBA'kCguFpT@YGv#3BVQ[. LlsEWGѳEbr3 DIm'|cFp8#/aɲgkp ʼn(LddH hcx7s :$vmxa6GOTn'WaezmQ\B5<d 04(a@,-Y2wiPp]hd. 0Bti)F#¨:Z%gh p73 {tܾґ>}>!в8w ۈ nQڹ}(2g};Iek;\p2OƖ7(\) 9wNYba;$WH**SDZQT;;,X~¨.І-vZ@Ne 3AĤ~l}Pms^\a{8]9 %!,Dq`ș'Ix\`f@!RԊ%e/s.gc+$@ӶYj?|bw|&}Pd5v$dE9|etgK`Ĵ^Tr03#g[@mS_#jGC ȣɾh LEƳHiĺ}Ϟ=ӄ (Pc;n=53n&}h)я ,c_- zk"Qi#y[ PK,z񃋔jos 1 c(>"_~s&:0#s-ZOl=)KWVY':b8%(jf#TQ,@ .PF%Dp:'܅$-r$;=ڗME79li_{kOqPT2r"&t;qۯ,|e%XoEX`%k!= 1m]f̼UgDLAgZZe?I9x1ȆbDFp |bo5,6 Du-&"}eY9m`gG; HW凋֪AZT9(_q~ŊYX?lγLfʩcs\dg[ Cx̔S+ӨTx2Tfd@2#woVu41 koqN,þdj+tŪ^ 4`^]k~0d- mS]QpkڶrBuC"%^׷3Wkگ~C'ks?T[_û~V9d}]N7>]߬hѾiRAwUs/?_N Uqׯ@bo2>xICw_o$QWڨi5fL9ဒS 8RU"m2<*,#b$DOs5b]9+TnY /ӧ5*?ֺd_G̤")>akA .3 `[K``֨v_ϖ0)ɋ`6S`t1S`/80!ñ$ nlcZ[qZ|'/jD"#?_k:CwzvZ*u5B ѻv}o|qǧfoZy5@࠲& 5u=-iXuƐ{7ck^ euz {tn֔Vrƾnl?9` @ *?ͪW+=mEֲua㷽0ly =Yʥ=zXT)VSyȜU^nb5%Rh봕'Zί$kG[$1 Ci6`y m'kTh'Ko)ٯآxحJFL`d5pLZrчS>?6̽{ tUb|56Oj`oْѢ,38Z[Np\n=%+ >ҔZ-o\&/ohY(ɩqonw:^;.2$P`UF*e GV\o"2ȣzI7ӍNoFdMFEiuu-k[4k2;dEnAHT/'_Gx[ӫ෽8[ dP;_*YWkIVƮQ5#.d/w :2DAז3\1$h\R2ER^\^ȭss|{:V"ܑ̳k. [V=.g0)%R%7Y<ĔshbU*%~w3dz8d}˷nq]~~ڛ޻۽C4*G*&:'c^c@@+01"2l@.jIx0zq_8aǧdP"3oC+b!{b@WnTCKl..[g ɉ]l]ԋ|Wn%%W_ rKsk\SZ&:ydg#E=w:EqߥK=;Ξ:7r Oe_aw:/(荁P|,/cג|!ֈnc~#A8&CΌ3=*wt>5/v5fu*s8u1alS_cj0svI,5RKźmI˺Z- )rHuV9״zhpe^%ug[67p(Je-boo:+.֗c=v񷱎iȯ3O cB f \_1ِ*VGs0JNug+3cUMEodyjcb0;&1w l54ܨkpⓖK%VuxF qlς_ w5cwf&5?oB} `&0 0La 99k"T>8Co:b P*ʂ`-k ڂ`-g قy`-g قy`VU[ժW~֪ 0 0 0 0 0jgtݮA5h֠4[fkl A5h֠4[fkl^u_u_u_u_u_u_u_ 04OoO8*zoQn[CԔ t6aKejQnf7`:\%n=Qmd_˰3I*$ERzm;T@"XX8Ahߎ8a 3OR%ջWGɨ ٩3f3bZ4U?_ `3^ƞĦ<[Tҩ5~'¯+뵓! ,A\d@+#!Bz0o+-F:Yy!IRg3T'" dv)`U42 ̙{S1c|ݖ !ZġG##@q 7GY9-^C.{jᔬcBUtaOC(?/O(떱3}>`*Rc/?ZzvCbX+TJ|s:&{DT,MWr0L9#O~p|^f)]Yگ/ 3T|[$uAFCkp^#2kF0![ ׫hF'B -cվU?"~&1ԗ*/Y_czֳ&/Y,ֳ./YϬ(ZOs0y4U=~&3 k3ͽxa,#Ni{puzmP[%|SR)P?4c_ J9|6;dfTwLXec~:Θ<G{'On9.!%qvB \6,e~ƞi_~FsÝ2ܸŲ԰}~#Y{v7}=8 oFu/094j<`0oqپ<bN3y8Q&gQ8mt]t#66T܌yԛP`@o0,: 30Al@2K8 ŚkXfCJSkQHڈ:h68(ZBR]ab\޽|nndoI8%\%Pަޗ2>6.^ZJH!,& aTc8Hچex%9RMfs_,8$hH HyQK>[%ҲiR=g9q-2+nB~Yo҃9tPO-R=EEꦕ.1L3}M=%N4E0)H [@vRӦ,(A^*2J#Z+0J_ʾ/ݣ7{ j_a’aё{~٩bsvZh-*7r.kk%=8 Q}|P}V<"{fYÆqCi}b98|#Bqp+ s^o SjxΞkP\Ed۳9OU4JVtۓ:p(4ŊДlڷݬIۯob-  1KO59qrZbM/h[/ʥ",3.< 8bQՇ(h{:sƱ |ǽ^LoEȸ1sߝҠCJZ!,k7rYܯb#URiJaU1U0O_TKvVbŅ%,(m(ݢmYKh}y'젊37d 8gBU^rnj49Fٳf8Qe(sU/CoM ~WhEu o^\TEuQ?EuNY 9H2=mz/ijjBʻb}}=Ŗq#zsNA UK»u t]mhX-|Xm&V, "!(3ffCBۗx5<{ ,Xŀ/o6^OnϵCWZerVuG exLֲ MX5;6FLhMeݷ]jJrt\@5 xxUϒr+UEr0,1 N=#"6Io/WHKs'aSFVQ6-b1iҷBQ{pk㵁[e[kF^8-^wMj115HЈa\F4+J!Y*+neO^ WӀ[ÇUeC,Ϟ^/КOCRz^/i=/im /(7u ?{Z=Y=-%jiLˁ~AG9knkw4rB5?iT_0?$ ^N6/?{C:Hb>o<>{ZB:Hb>*nV$#} xxR{p$#KP`bz?575Cxl'CK7ӽ~aFֱڝ3l ԳZWSk0hz l0~Ohor7Xo@Uԝ/oўے;;*=zY&wO")`ui .i{)M7tmX.I!k=XӶ3?Ĵ5WFQ(F 0 ʒl>RA"5mYSӲ.J>It뢽n11حZd(oyIү8XՁA_'Ɏ&S=1PWb]YLvWJ%E8fVe/>%i)w{z./#w "=UfBuӪˌ\j$؀i;} V;ՃCвW1lKt-pО}z%njv۩tvALZ";w,ö́UO%o2:zH;0@H;{ {8%Q Jr[Ĝaw`d",WvIGFsQe"i,;O_6kၵhSXj^* r(W1.9FF _.J%wˉ~6`gϼ@N %uMk&71yd3Ds<&I3myJA4 =X`=PNÕRw6 X`ދK1kh:NC z [ j12%۩1Hi#"<2Y(ʆ"SPQwlp=.}Hۋ"i?x(::~f\b;rr7yȔ-<x(bgwm25I1GZط舧ss20,!U<io};_s#d)7񅫭4ꭦŸM%8^wSo4楖pUqҦ0. veD5S7e'f&mc5|?[(K+wXrBFLv0CeQ 1 ]pʖqo_EE b0mP HV3c$vR@F;! u5)2JӕEE7ЗBe 2pZ= .W3i!=KhsC~.pb que"NnLCm`DNU\3G_ڴP6L X+]PG7NAsh*~jRg7?s}+#UDghL1og:ӓVGl4!m)VlqR]!J_vu\ݼ,v6(sw(ҭ#NH5:4Cȓo45Tt|}1Aq2F_ ;o YŘL0 u+0%qHZ%J߁1)T89=;Ci`ƎH_%4DQCG2KL}vDhÿ́n`@ɦS==Hηߓ=%,q?:Kq٭T "^l$ʆ60o23[0]mh+iMʷ\mjT ,7<`- ^ƽ12YiRdx-?9vb柺w*kǘMʨ87Z\*Eu" \hS%kÅ!+d6`\/n$SЄ50QtTzCwl{U;t0\CNҾ@i{TTt b fȺ Hkю\FfLj9SC$f0K$Y!i@}13jleN*lw`<@Bb0Am -5M0ed*¶[bP"pҘV<|(+#fDXt͸"YN5L7Q[&k0v;y{JFuh;uȃ7`ZШΞ>=!u{'JZbNl{s<^d{=/w+b0=lZVQS}ٖR+a<P  \+@ӜnNYO7QsgM0ufu0a)Nd~)9И66ty4.Pil',ujg_>#4r=25 5JqT^(H9Pfb7jrU"a:jzdD"0߿Bڃ8=#FR `wy_%%s@Ӥ`Hfto&΄ 7c%B"` v ??x(ԡ,d\J;00Іj&"bO<4),J(C#C  7p|c;rs2cvxBV3PUgL*&C\L][pHPQq;"p==EFJщgh CXAy0̲ޱi18u c=]Sm0G `E?՝|8*D"6=g>#w,-o^Gҋ>pu62H֬P =5bcӛ`;9 ñ$^t`|#E97 rہV3}HQf3|[.(*ˊBqgb5H<և~-> nq$E8 %ƶsxn{I8 T5E@6wHs\F`I75|,!E, T#'oiXUP!SFюંf^Vނyrb2a͂n`rB7b]jp-,q% ~ׇcLǡmΧ.$jQ êmSQ0ںΗ'q('V<;R lapDCحw2CR xpE8P1#]~"'!v;u@lx}ވ ly><Ȫe#w6_zׄ[$m~1Lz.3]%~:ۣ;':=q|b uZiD[Joĉ#F`КwcqXNv%C ͌m bpnwd'iE-n :gV1]]X$où~ٻ%] "lV.},#pFfxv\ mMQS4#;8MlgDxu; GcGgCdQDfl^Y x&2d5lp "t_AGv^L@aB#[98Nrp#~JRZ9eъ;rȌ;Yd _=o(3ZWB=6dT%ynC}kYYU;o%:a+d/gxP?gY>YtUHGX"!Ϙ%lJ5Z3 +s[1SZI4i%g!JXXEf׏y^7 U%;i F}s;}yZͿ"V&kWԖTau,^H:X cgLѣcG;x`ȉۨ!Vvp}D(@T{Q8Ӂ25CY@&rKԊ-LDa|[Io'$I,m (zKoZQ[ cgw|9 $AD-zו,ׁwpc@:ؚ8QlZrV\I]-NCGTf#3N.vQ5jF#QΚ$&/1HcsgQC%a@WD\*۸[${!ę @ `W0 y|g@\xǹϛ_21*m8xg`SlpjHT=xK,%CTwOe?9v Z 6mm| rjz'̻gtďQ.IQ|7 o2U֟*ٮR>aUdH|ᓥDCƈ}6y οt x>MBZxhCN,鼅R}e4ЪԹը@nqw UP)jI݊Au`X$aKѺeT}?)ꍰ=ֆ@:caaC9\} 7&-3pu[ti[*† +3M6^D/RyOhÕˬ:q$V;NFNhc.12o:w:9VyCqF!98^7.;X1p9ZUm{fojUlqh^aDW,Q[!`O,T`Dho7VC#IZW)~gm̪$:G9HAsMنD ./*RmUi#7,3!PVjvcnDNF{F:l5!U_V([ÕZe% ]YٯL3]ZIlCVS*u$WUQ{\Ӿgȗp u.MS}^mgGYkz7 }4JMclf[}4;I$ϡd~^I2Kp^%g)64 e֚P:$t|HvM;嗣 I5"i솃Q tI9+~JU`E-$Ηf[ in)ix Mc -`h+\/0#ì3>y;< -?d?hx$pn6!!~ ?̪r:P$Z^}lT~o;[˪5n5Wy޸ &]7'rq/Oh/{d{Բy0vDr;0tgi!Da<2ת@fj_9KlKXqh" i0E'E x0$ۖ7/+02SŸNoV i"Č%e |֝R qU4&6l];izwέ2ä.La]] 1Důڂd*8D.Hi5BUkhGn N' 0`bg\0GgYp?wҐh5(?rKn1 \IDml( ErM2ցg3~FE+ʋ+Y7-2F{m'̸óoxp;<ֲ΂|B@ l*%&61hUSkBܽgunA?,pې•nxL\.EFگ;mU|&_ %f0`)Z3FV8R"gz>@g0pJEoNvs'jw(-𑷻{ o`p`18Mw:M#G{F?rO#6iR'qg8+@;e~ Of#I~nQbAGh9F97 BAգN"TN'gFzl`nՍ?XfF}+ѷi6QJ ͡dW&Fu! G ѓ<`i{$z !5C<'y Qx1IV(k/:$O`)xtyUēսCXH2+:O@y`, "o* X(ӧJ*!-M 'Fڱ'T,+%aR;^ƪRl(Ϋ;; G_\b!sg,}4krأ%Tqɯax+XSes`f O$ raV(ۿٓlhbG3ANh%m0ⷎO';2!w!:)-1[\Bl܀c";aPp&By>A O}VtPnaX]X lD #򯘰tv. ܮ~9JTsG=o]n#Gp*G'q.9:ځ,v,.ù0?2Z1M+ :\W 'c> ԛym1-*C&#sF `b!㗡"sOTNүJo_cw.NXJ]v8 m<5t¡!I-'k,\bE~1I)P[ſT^%J XcJ8Y ;:x K8Д g̥Z03R)>'-HvAd!$| #CRw Eof3 \6qOZ]ƢCG3`¤lbyDamSJ,kXQDŽʓ(o&9L*{$1aB *灔 IJ6$~'{ҧo/JU,$[ /O/0p։}ħ93J?6+LAW!OJ/YLN)FzMӐ>&_ z$l #1ߊk+R68:Fg@J[Hg&n@ƆcLIDe%!}Liʿ4`P ,jyI%7 HJKd%Tr5i 髦ЈK1#ʩ`n?37+w ܗ0R_Up0 i3YKk휘c6 Z0߫¾x pޓY_eB^0jſR10N# 0"Ԛ?2t4s2ZJͨVΈB6;NoOEIl-3p$kVn9Z`\5: EQo40N{8T9h_/Bʭ+Y+ĘʚQhze$nN.g1}#'wg˰2A6b>0>|]j:DFFs2X[:na i9gx1 ~J*g9 g7' ﺬ`֘SHyh[ƘX2XdeܞFd$s HSXTBVEeH@] ՟+ 8aC!mҼiw%WSg:pa˽cmZ^ᇆO64j`(>0>I+9?A&.u&{aYDDxqG̽]aPDuK c\Q69tNn~9#T| q*e㜃(o\ҏބ-.JfL $mDt;u']Rv1mYP$zJt$P4nPma׷nL-Cw&>-e8k΋k~ph#(ea/&`WadXPșMf|(@(\<$TC Ac·ooUG0<<"=E coj@uxkD?QʪGppϖyk_~Xmh]V-;F)G{b19 9oCslKx uiXcRLW:kʘ86 )fޡ&Ve@:NtEk<&G|6`䰿*49#ރg{OhT&9LC(9/F I;ǻk6J]-z;XַE#=SI=s QyCim8S f`Q4M|]A_6{Y,=bCzZiY]GU^75UAM۰9;s3_*''\'vح }B{iUw\ TkL`^@-L+Nχ|G 玄GǜԢ~ id.?r A EtD@kuL촗(+@YNyKQ=D9Ckw p! ^Q|P!iU88CH?.'PH&bs W|! v_*<2u'஽|LػF6D'[\˚,KBs4u+G ;R&W*tD`ph GT#/+H$A'^Ntu z@/@ȳ(:`&m17PBMLQ)ȸ]{8׮F: 7|`{B\M/JT\ ^&poqfzC7/b|p3 eLێ[Sڂ=7>; fhF=#J3vnS RNsQ8d@Z̗THҤП&L  QƳB{abze;,Goa׋"(ܳhÓޡ\v#_\2?[;Oޟ6$ï]ۍ,1¶n˒{)AIb@_?bɵLwi 2"XmJ!50*|\KgZ9TFBvԁPhK :G޿nڙP k] =6>iahfC/E9o1a:U3ӽta<B({U<ܘ.A^ks#D¶EmWs\> _ Q0.M1,PzG ^ C[qdX Rd"fl;H$ Yı+1=JeODtWA0"Ddo/E"`9Um>+ =P*c[A, Z7 /֡|b:y-J-Z"G' bGBCDx*uG`}`4MnQF9ÇEahj %{L:"MFk3V |:Ag4bʧ8Д% _oȪo}$׫ԋ`~6M&>,"gIxvG@$amD2P&(tFAVy&w#ž*$rnu&N~vY\0J%d%"/QPl,H:, 9 IOAfpvt ie=8lv,YBj*3uZO~ZogU9&dZ|fyh:1c8N1|}Pa|(1jp8L`"/{4ڗro98-H.>keߞQKGDˡd3Z$Xؿ1$8e 8'Ґ#덳KQIqƒ%3:Fȏ4-S?:Ȩ?jպ_JLHCe؀*u#إPN6i`ݚ"\d7d >F $BX8#Xr NH-/t{ye}YDyӛjobL}\tN^> .'1){,ܑ-eΉ. ØS" aN/p&25fǧb^v S92lsIs>S%\n9Bcvo2y+qρMh#] 4tt/͍cۅ;zhM4߆ױYՌ̆Ļw'9ZឹUP߈["`!cR7{;377Q(rveDޔ)#ga<("vG;)~[d9pgc'ޫΠJZ xyxmY*#X0oВ /k #Ø)k̼2xme&M|D\Z$3]%iio/އ:ȉNo M0԰9ad]âGhD~o|>]Nv{~hg>um+ZC7:=>z;p:j~r_:ԤN*8lMI8_NHsQy8$zs8kqWlM2F1?px8<ܠ"l&<y8'A [ }}V}m?4sȿUW漙͜GCާ3H~ntHZ;]>KbhPmڳdLD)G{\T DJoE,9;Ñ@ 7NZUV7>W|?:b[\6;0fhI̛lһ6Stws4?ɑn<2T7eњw"Wgۄc&tP즌&+1 $ž3/y'#%O>Y:O,w>H7bz7RB KC8IOj-E҃sxi$rp !<,!',!\Kۛ:z<#Ř`؈) 1G~G*$L9.2!o pqzd&:5eQ7/$I]C"B}UjH˾n5gry%Żxa4eޝ=K8A*HJ}JVR݂HU[`S7s|dZ,G\p!!&äX‚GlrHky>Ee6@vlM(fXˡ~9P=-DfB$Eլ<'R4dwIʡ=$uMԖ@,ЖjnȪ)Ki:΅e$9qZoT"(Yi!  Pr|Kzx|ѧe Lgx~)%̑/pX6gJ 2[sF̒AU- % ]p•{@eO޴7da79;-R6SRø>~"NyH\y:4b.w̻Ϡ"*^,ܬX# tcDaěn[Rm+xqMQ%&g 2}}=!P>ZxY8 w VFe8>-dZe>»<9#TW#G?Z^ktjb}l0Ed*pIZlYd&h1kAb̈ N7ML¦{^~Uyi_չ7;~i> m+ hsZFupy==Pӂ8:[puڌsdZ>(MKeb]wfkKUkkaWɕ7>Gp;@W`oa؟2q8x6@ 2Mo_&1[Ah+<{l+y9yN~F]r&qp/2xr }2ob-P6ܑj/8? / zxyK3lf?yI!n7M8밋ZWYM;/9VjhbGP]ȷk@CAdoui:qg7 y JGmy&Onz|y0&;sZrzk[[To;W~kU4D@vȑ>Y>@{J ,y$rrIUѺºd8=_ѠO~2kܒG'ѪjsiJϷcE؎jV0Y=֡l Ȋ7[ Pl,(,dмO뾉 a|4>-k҂ag_h^`ˊPų)9rb7lk3;NnD,M)jKq',MvDgJg>>hIi.3? $ GguðYѻ+Si$t١0,4h@aX} *LqТݠ, =rCd M5I ɗ;, d {*,D[X2\d41A cJa0[dn q,W%foũ`FVouIZT]$ -蘰h$ $GٓU*"':e"A}R;^+cO(^71{dD3{ ݊ ^cT'G%PiO(|Nebwv&Lci@1V8 9ʀ`/t$[b#y0aX99hs,0 }@ 2F…0 r1?D=d5-B=pVåVgҿ*~G}w^5Vx217~{l ͸`*i32$]`:ˈAZ$>kVJʎaWOȚ FfyC!mlaaw/3>pqΉ?? .&9<7b(urCQch8-F(Xygu4W/e%qr(4ϥKn_JBu/)>9Gc\ʺA5lK]}7-.-Eɂb l,U)~ /% DQ u`K7u 0vp>z"E=aDMiD;ĦZ~AbKǬ^rNRR" `_WC{cn/[yr оopiLM1f>$nIy{=`YQu]/SeF+<9 O]>-]mh _-n]贻yx- ^u mUHF2{KӁGt.(} IzI2 . 4*t_K_ * 4Gjc#c+ #OtD(牜0ƶl%@Z9gu4჎0r8XKl FbYAH"T3a \TX @8^FV-ܜtMa sc yk="=W]}klq3PLcDnk{G@%iu }9/mOxr̦Tz5bQ(f5EL#`Mnܧ&X3ۛnB}0bdTWdzٲDL&˘RRw7|7B*yk¡$?uq ajR~/3Cπc3ʏ+'>Crװ1LH uE' {O9"ii~3_lT3;3jdAO`Y|8y▫ b8ul ^@ Xo-)2sY "ǬL_֛'DrR,RJ1Xm6셙-e{0vlԱ&j"n223TbMXCf|X,!k̙{_D*&+:ajd3L$FQ;uA-{f85Ҡٌ(g,F 'ZJG%/_ i+ީ#_nDerly.ܽ\nUlW D -/?ê9܋-jBT <Y%$zJ7IM㻍 $u/nɹYZV30NHG:tmz6,Y0 goҺWQ,&IS<8|*l7uzsOO޹+JGx(V~̟:/E@'*|x>4+Ǘ>=-Hwe٨=ޫ!5[]dP$Ư^i8·GĆF|<s߹.1jI a?TVP~ƯygyBM  ;P1L^(O]_=]M~}5Ci5h[G-_GD]ȚAS{ysH 9~MUbL*'?1}>!gc@(m뇩y .&HD6ہyO H&k RHuAt [qYO((GD0䛓L1DZ QqzD NoaTՒUAMEUqH1o5zÔF2jY54⼈!ZV!ąEmɘqOr_dݥEz(F; EӮնaPfhVqZ̊dI^'c{ f-*2 Up׆۵-$Mz`lQH)@",|=߻ǽCh1v4Y|{൷ &ߒ`,ߒ}zVa{E+PM*@>> 񬋶)FD &0)R,=(a:'8T"N[H(Ef*)[yPŗV ekl=PYS F@Fh5ɛ6!"~!!~aDG=Oѧw];e4 OUL|ܿ4 6S sF#iө]ȽuX5&&PiXR?4@xϟ|AȂ]jz:>_{\c^Ǻp2Nֆ@1)`uύ5q"HoI#*92V P7Ѩ_ghsaM!G"|%E_/Aސ9.}v] CC)2%a\٦6 Rol;54prU/2HE -@ q2G-ѯe"\ qnxi':Ѵ0΋=Cu~!:G$-?G>c撴8t2 Ұ͉=/H$O_ge 6+LlYc]vb0tZudCb!'7ʛhJ$e;^:,0]ƜiV FCDPPiX ZJl^ т,8t`uERvsv_*#S"'"lU Y! !:+ǎ MVK(:R;*அX*QR^3 j`_KrE Hu{ |iQX[. v˜a)c4VE10$m¯)\: ~ԅ/[?PSN.+>~ZRFxDj1mqd8NF+8|b&!^zc&+t?dlx)c M)Oar>" *sVGxc$tqx(;4P)Rh8>1#Fng)BZAYDQZn[lTL ;L|,STʍ.߻Hc4h1jI.tU+m~,dIO1^v0D pY@2z6P[qӥr ^ӷ}éo}?)U:2 Kg6z:Jhd#K h -6  :S$T6#Ut-g"8Hck`Rej&B;@Eȥ`> < ˗,#We)ۦ9]3*+fFU#M[].qqdr{06҉_0Tw0E2,zcT %#€eo)tѢ5U%_hTyQj^oĻ%,!;CP>;Ղ~bC4Ԛ'pw* %RS?J<վJ=R$0Xe AS.+Zz.jrZljZ>!V+UZ-7ZN|Jd7"!}vgZjYJXgon҃J`VtvP@ 3wμІaW@׿)BF٭~ɉ0'?:>~o^oqկXCcvYK A7W g]|r^By^?~;9>=xkKl+`_ERre;Ʈ%}$*m֣V*ej!Dhg%"qdDQSOAԿ!jh84UwH ʣ E2#KW>2eu|rDi[X#[RdȤ00 H$ ;"@ 8|Y>kv~%(2%!s8VJ5`mJW 8 #!UJN>"FzdX8G\~2'DG))GDG=F&}~[&fx֖'!Ca|] f!Pv "]iƐcz!T:Lhi*U/b>߂L`ןm9$^p9.Cy]ZCM,_B)yM2H$."%pI i,0Cȫ8u\p<> #"DQ%*JR|5 sh#ϧp؊?sc./9W`8M)fqsx >E%˴. b5NӡY`{fط(cOjF#]oҸ3}EoeV/G\W.rmߡ}%?Vlg"?]ْ+fpšYCc@-琋X"2d,y%rι_"O4>q 6EaR$u[AF#K<"ٺꑳt2f'`zٿ%p> ѱL\ch8h)Z/dby# d, R" QŬ?Jk}nio(b?HODz3)kXp)ɻJg Rw`Y1UG}e__c8LՍNƸ%hJ!Ql{< &e eRD"'"\ēxr"Y"d_Άq$T^yz{pC}OG3.kۊ'A`(ͦz'M1v,O?nnhِΙ6 ˫ 'q V×f(BKt^!6y鼄b!fXhuIZVzQC}ֳXѮ%٥'Rs!yFv@1%*qFG)*66>gh-K~C `3(!`Wgh*J$R.De𚳁N8NDr[^|l\ ##Azmyf3L8'Q`2:HѽrGӣG${PFeAa*'R *"J#՛l3uv퇖m?0.wt=|$mD4lޣpKm %zҌ_^Qr9IP-CѤqdײǔ}̘PhF/fѾ^)~%4$8H|5u᧡V;tlf\R7kR! "/T6TZMKS):0$f.̺NR*Ⅺ{R*n5;yG0z;YH+Z-&ŀb95^eU(),Z U}_^ s?^`6zTgM%4uleRa L#Te˧8kf67HK+F@* 8j]ؓK_VE'$aK'7E<ުT&)4臝>}mg&hA{e腎 ="#MP:|{r΢e/"pLxʋsP WR*#Ȝ-EMzpjΩi`*\h2P-;m={d~#7Dc^%)ΡSbLLh@̆BF+& =ANV QKjTؒ˖u:e^C΁֌e֌c{Mj3ݭac¦|u_`Isⵀ Vnu-ANFAPT $Sm;@ #T ϧA?àkueNԅ42G >qYj-|.@GlZ~uFNx 6p6'¬r؄FR?r,ekI Ƅ7$Te=Vi6߷Xh6޷>ڢUw©jn?r[-, ٸBk,$ɒNXBȱNN`52]/x4c~FQ-H!zc7=*+Pp`I+4IG|?>:UX )7aFjOZt^7x `#4&QI([vg$ CLU#{u&sew[7?H\@VAI#@ı2`_3y/`X bidXFQK4 kd6chbo}BL)(U[gu%Ǿ,5DXdw _uxp9pYhu[G~ irFw~0-=,N϶OaIv}dgM|п.:,6F9c{:!r2ޅPj o2<0scGu7 ɢ,ĐЖhr@R;*-hP!u(L%%^1v?}b­qH5UyVQ$?|(?ԝ{- ^?Iy^z #2U&1C 0RJ">9MM^.ݕhrU^Qĵ Lad,M梨1BIS2ձc|}6kךenXki_*nGi<7_0__?Mp4_-Z3_(OwH| 4EB"Ek3 EU PͧBյfUʋJk-"f.uEF*klqjқ7p03}8%"7gP(RΆz-?e$j3Ev\R߮mװWNqMEYTK_AfNk:R)_Q% $3I$h5X!Ӟj%Y-I;KNI:B%p Ζ ∿~B);ܙ>~Dh4< rvW8sy&:΅= sz܂R}{-ďE7bxT-\.ق\bQ^*%N% fJ/in,eLeJN%$C\zN.$d&t2^RK|΍^$6_ xd%]Th邼92*eRޙ9fddm2d4Z d 2Ket}I9M\a8\ dyhR' =-iuUR&-@UΠHs(TNUKM drrp$7\P5*H̭~uX oQQV 1ڱbͺwpG߁@\?wb{6NOg1- ,ƜP ePAzd5p <{<Q9[Vd ɥTjr?8|.h*;8iAPdԳ S)?t[#`,qBM{s&C/ 幋!ɒ, I%l]t!) I:%ld$H Ci $!IE-Y$!sQH6?V><2QP .4B g4d]l azG/!Kѻl'>Aj)XE֍ VDYvV(-ᢑes5d2<&_6dS6C:9ؔV8>QFxS!gK# YT W'W',HU ]~BLZpl#0e bXv aNOe|RDH"/5TVZ{}hhN(T Bq~=]kZ2 WS\2B [G5Zr 4)ɰZ~V#"h6-y9 $wpғs\LOFGu-ꨎ#ڶ=*.09!M2x-Lz&%3 4]n&c4|Y)֑/)%KJIRRϽi/)%KJI][*)A"26a =i=ɘW!UK"լKJI(ʛ]CAA _a8&bHi<*Y0IQ7ШRG@us[0U#+M C^BXo#eEby9׿) _Cl- |1:*}eV5AW[Z7D-@ie.Dlz}>t8\ѷVX{RdBSYƬmm%I\j1fĿ ʹ|2Iڨ^f쒞dԄRm\zu `:|JBܧMtc"?p͗ +_rԦ>nv-|y!JnodDܓ0 O4z#APpGzXŒ%4SGu8_BG$pYQJXP^M*BFsR nZe՜'XfWU#`!GAU9^7eH?̴ad" :) *;p7ߜV0̱̎ݥfUSy8q#`>ysN%YϨpt0d39VxXvʦ(y5rHSØ ɸLN8)/NKr2pJ$pݴ -Sj fe8&~R}Or/^KZIS4C.w"mabf Ӌid%~!BSuϩ8P."ѝ+W@LV btBaCQ@wIgq{`HdzO` @8x\oD{{*Imn bc,E}af.G8fR2-D,H|;@KV->Ɵxj|VqeDgX  Z׋ ,eŶIJ%ྗPnJ'&dq eJaU9>ʼ0M2ccď ZdU[I %4:m ͊¢{\3JGKL]"e8h"܂] f[ܩ7Й7ЉSfu!#-k%Wr3/ڏ*G⟗tDE-=$w~2Dp0V=IΎhouBFoλcJ $W,ٴ*MU䪕]w@xNwo'sk %͌lzc x.`8Lp1!y։T-WRV `X`L)s6kf$'p5d_"Er#X͵n -|U>^]Pj;,V܀E* 䱋G_Pxv>)Tcҿܟ0ZjSō"ŮsBJW6Bƕ(c~Z+yбv5yѠeVZ]#@DmGr!m){WуwI"%P,F-M|K4ξEqX@ ,>Ljـ?J]#cρM(m3y: sU[f(xkÖǤ/rRi#0smq$6ě0}`;f%CU@P6*kcA*>N7K%yME HC B[h8+ۭO9LNӛwZJ kg8 UnZIۈ6j/beCU=xS[ڏ0HoXV=FkPyߟH@qbv7| %#aPԆg āf Rv01jy1HPHdd+]MQH%cwR h͸[mf%mX@2fdHX| Ԓ tFP f xT1qfkƣcv(~gQN 9Nڟd(1By^'}(ћ Y~Q9FA\yxgL΅{2. a.0쮲 8>H[B%&W± _IG ^DӁL(_]OMjXmQr/(ݰKmK-|B K~BgqCeY4y.v sA+,Ԓs2H5G">64pg6Di~kbkd>PcRpf EiCK}EZ@٘F/5 ɬ8!jM lIP6uLQvH*;Ls,s@$*Õ8S f2QAa4H`I@]V`YVM$g/ld(-"OCsoᱷRrrOr|'0 Q0G덌Xs$NGV|k"|.J(VQ,nW:ȨYKkNQƮVQ#3U_QCʚBcvKghI,h#E9hBOܓ >}'6PNnZ#/9N~H,Dv&I/4:P>)58*6fnO[]Q+@/ *خ_p{ ]®U Dt:[|^Y/ю>p)my,H.y!.(~ LvLxEx1b \^l%,.ifV" _zJĂ|s]d[Jhxk͋,Hbh̘pi&0]gK\-y[t:}ɝ{][ 5WR-3#rŖ|Лj%{'O[fi]k"l#T?-&kMbMPsOPx5j^&B1BE P؟5j6{25d鬁 > B3?yB{ O+Pqa\iqgk" #T?4D9IOC'IodqFvJ#񉎧8YHW)L Jh@v;3CjwwHܠ>uR;ԟZ"1R#N&dgFy(U"sɯ5WHj)\ԜdQŜЀ~]B'm̢{Ǵiқ:ٜ (zb\b~saNO>qO'O·LZ^aUNH> {2>W)d턶m!Gwo@Vev64rv Oz) $c %υ~05tSJFl31Hp.T`70 &1%auYOisJ _y:Vrť)+us44YّhxF䆲Nw4ǝ]dnue2+1֠@6ٙpT;<0go9:m jFKjhe uUlo|,Zx*taG^Nr`,LMrUDh[f^4Nҳ䂬\%dӧVFP.Nz"eϸ]^DKvyz!W!!!̓P lCe>)ւK'#Yix%Q&&x#9N7hrd٠XL GbrtԭaC0>>VOzZCejjO޿>]`zƈ+v$czpT:` ";Q.3'g(X(/2aM7$Q j#d9лH8@dI(2lF1!& Z[o1C\9cG63E-`،|Qa"c ,]䩬işjy݄19 G+>ZŵTZGQcJ9>;+r'>@ =ŕK996TvC)P/ꩋMJ mWZ*fbvl}K̢L'>l!r0(nh qr<T)x_~cН<_ႀ"׽[o.|,1Y1y_,;8[ ٵ/.n^ESNXsmLa ƭ~,9jh|@Mł W"W},n|e1\S|BXT%0ެ{OˡYӨ,Ջ{B_L56KĿT*iT #ё Yş1hA,yjM| 'Wq'cQ֮ZIb-$|Dd`)scۤu+Xb`axɣ2քp}C0|{$f=0'\ ۱6N?Z-[ ̏ >VRQ5y%TMT% ע bhLي H讷5xAbF&2\ YTb؍$._d?Gw콄pdOw ְ p9 ΋+2vTwZ裖"WmWƅiF!bm=˲QZ/'N4?j@k|äB *lJO쫒"OK'ȴch) }Ho()N>Ðٱ3Ecm*nMYݠe ނK*.s3XAgkY(#ZJC90bavհmpX W7(;8F2{KqĦ!IJ ܍q9 DD6&/\sg `TV?-jB,{/B 4 Mn #X F-aCXKiqP~veZCY]ڧ^k_S|oOO =W=],({{[rQ>//u^FS),X]=W5H*V-B诋P{`LPP)E&p?eGZ+XMx+м!Xbce2`:n l`Zho!޸7@7*SIN#o0P c, fxB(UP (Pm(a>s }+P**ZQKBuF!|h8Ykcw$Gs,e*ަS[mA~OR7o"G,Q'5%A"aw~sKfsy;˕6X?Aan (TdqDw%]<>,c|V$|΢߾.>h4ŬswTB(GV/ҏ/!aP&͔%# nTMBKF?p.,^|Lx}P?GzTD4׀ȹІ:|[6XEb~+ve*# 2Y"%* 5`e[Ӓɿ[ПTd&jH+dooD b E\H5T#'P_{3mb_4 kҴ4RaE/x]L{%# YЪ1 k]gu;x_y{6(Bww݇f,闀#qr`2C1ji]Å:Ѿ]%ӗ} t O鎼+62 1cѬÞqTJFͧ//#r%6ҪgF=dLC$E!SR)lSuBמV6Y|3IYu1ބr`uXIu=JoVf(`4s$9_2p`_ 9tD^Fd5' E`jE6;6pk@0^4agiUj)>`Ed*B'›F9c _qXX;ⰇH{Y{5x(XVi܉"zJ c0F4vΨVŁKe]xu%,LRE].{2O[h x3[03.-fv7 sP5nbO:ea@q`:I߃:Bnz"]2X-D@󡵞@kmoO-(T#-n9 'Zţ 5s*Z0tFy<;#D-OfG**V'͘:hғ =YS,Xq7̕(rZxr|{uL:Rg3\]#E44r{GJ&ш&wCug7pw jvĄ"+QCRx6eChֶ5Б޼8I^ L%=j?g8<xc-MXƁ].m'BM.a~&Ǝϛ\:n2C.ZsE%}!_Ȏvۃ¸ 0`19[2b<Qti)2M_TWE~;:ħX"W+] ,]J VNΰO)b' e_nCS _Q'p*Ud_5[C8q  y%`s1[:bw0P-񨝔$v<& u+;Q4fǣr.ЌGCDQ`qۯ,` AD^b $z=ISZ_0-!VA0ƨ*vzNGܱ~If*u*gb *yRxN5b%9D٧Yy$8Y:.K^mh4SzD<*!sYqSb,ABeٻw8;賲\6[&C~Od ,^J]Z UVvٔ٢G웕QeXBUi:x)#JfTʗj:L^Bn 䭁~W>j A|!̾DZٓ@fqM};p/+O<+g< 8){Ut\/'4]?JUEXIzz3ȼzœ ɜJF@đZg)Xe[JeU,)mq>օd SZEE*ZZ-W0%`BX}.:nĻ% .w2B^ C,HR_},/⻌hApXLޡ<`x{rx[+~48s `(KZVcӀK7I{qeBvETK? sQkV (TܷZTש׭Gl?5ϸj)TGEYpXLicS&scʏ= y`,O?nnhِ9lVAWW k/?FQ`I%wӥR\]my aBu)t@?š*fP{*?r6;K1@Q٠߶B6Ia !Шv|v.ev"b# 1:.RpMhș / q0[j$/_ׇ-8`+k]11k3z&26}Ě:֬HH2}wI@*?#Hλ>tLĢL`Y!x( _/t}8ABpXnG"p<E=m#6=xpg n^כ%g@rye À(!!XX΄AyA3V |,} !/Xj2 >ݶ1()${4bVRpJ,%`MjXYQYbKn阅'o{ N9fUb,V*gE>MgPпv2Pyd"GbN߼pT4-г@93Z/+Bf\=$PME: սWb,̀#W.tVm⚃ƍ>:n%ǿ5 JxHa$Ѧj 9uRs`G1cۯcHKyB(˱$DQ+iyd'3F`w l MdXXM r*%/,v-G>0:0Ah#2/Ny .^f$14) ^tcޅ?ܨ 7t; G/x.[̇%A7<2AQv@rZ:/))XHhI뽮 Zvj1竪+ w'wnW# =]z [6A0'NV0VWt`JQשY|eh H ώ(^$ >ٕf@-oL[9Z~}m7)hv5P4!B4|QrпP1CC,+O\33 ΟCirťVMVl_Pgu+.|ZoS0ڛA5.-@ S=܍S~#`8qF7ʬ9L4z=h`0ZM`W _~BwCx*Xɭ[;G n[Qz#ۑsa _1 3gfCeұ`r_5Fu^Iu+Cd(Z= ʲì,Zp,>\ Y{o LCJi^& 9χNn p J[7,t`0kq+`0Nb@cQ!a֛݌*1r#Je֢TpO|+f}6Z'aV`fu!0h=hA#`֨ڀx/fW 6[ SX\a۪WʇjwbVWq0U+HmAM']4 `Zt@e8 #ӖחxVj 5 {p7 EelNLj|ž1Gd7k&f}&Ei_]E"MФiIoִ𠜣o]q`U0a>8^̈L"k_`XUWO@$7[1Xfj6;즬kU I`|ŤP %zc8|Wƨ=h;/ܪtTϮV SXj_cCfv\bf0juE [8gd %1^\(A - p m CoIݶ uRXuN,Fk ƅ(_%-9Bͯm~Kȸ9zclLnFX0HCmC.Ql֑{)-FI(I^Wm$ašo XF*UJഄ.6ګ|R+_ъ׶ۊ޳x0< N׊o6La cw,&yaNs7c /l hAHB ̑Ra'2;3ݸ!Vn`V'`!jп;gB ,Ux-YwÂY2hP~4*X |!R'ֵ4B- @.5ܹuEt% װp'ퟥ8Nw69@}fU>ƆY4Ё84+pۧ'kߛL/|opȰZv7WNALʨ;+f="& hl :zqx#vdЎSDE $mW9$q1&%I&R'l)R#fvIsÓ#<h+Pl? bFʜ/ #?k72xz c冈ܑݐ#$6%!* Xe _Z8;65Z(S-b%J|1m]KJk a:N鲙`:~\?׺~*Ǭ0Ń}t̅YuTETv*0*`!?0N$[ q#B\ ?߬tì2&C 37vXc8f%ɡ!r4UF8jh77Ev5}EcdLOﺃhn|cV56J.f8Q0uKН a7dm"[qnre߆Y&lp}h Iȑ?9ܝWlUk`0h00_5 Ԅ?.` l]&c;_8!|„$9ZH\ף@7`"R' tfei!Eu1rd2රC,|ۮ[)֩[VG.\1kVL0U7F'XYйCY4~'WJ+0/\)οtfƼEԅ[2vRkfe6^c'LQo۔Y hdsoin#=pr-+.pf EqMҊ3̲CT޻oX?F70+#""ۈ{̂YA#dyg+hsaNC=V:V> sU6Gز0Y^YVc=EV:Eսq:Qvrސ08o8J+XHm{Fs<1  ,E`(d,(`r6X*X1: bLdKo6r;کJlu.#P YL9Ÿ8,' uFXM)@P1so6: (, Te) 8+5I\TFbR ةgؕR(_r&^Tyܪ O1ߌXx5 0#Ha1,UC (ER[r"R9[׳Lsstvy-LR2bC[>]e\ٜ̍Ys̍9ܱzy|]h0W ;y0ύvfjKF0wu~a<$?Gd@UwENW;,'-4)} o1a}MƼu"MeMRRfZ*9 O n9JV$,D0;F6{`HB<)tI@5I|Jg<$1z-kCtCƺaP]1\~'"w뗗<Srf8Z#ED%ϯۛY1+]uĸQAa 2X7v&z9F&emk /ۆ/$O?V6OM' $*;{Uk_o}W{a2KKMz7}<'\LHFDU d4bW2bHO^ `&6űO6Tj_Ŀ}QAםaAX\ rt!dtn{Oh"du7v8/dK5_ors74F.v8['Z?tW#HX@'1ц%q2 ͯb%͓b2XL"+4XAO4ųڋeuE'pmW:l`'ٷQ'y'BTDQW74z]װ"Nre ^µ n!f%fC+Hl2/ѨlAh?S_6W/~ PIQ;T^<~#r*FPX0#:y l=XahX^aC/-zM?U;"\b5^ynXOFFŮXhHφr< (D9_+H"%`2#{R S)k #K1Q}yCsRBd笞`:>3R( ) '$r`;j\T:E%M-Bn..R uLN1snn[E7y,89miOF6=KgZz -2[fmFSexLW9Ii|'Qbl?UI&MӃ0ބصzF6u:]D|9]~P&; 8]ӻY\۬ [ Du+o<;9>?LŤUA5}==~}|F FƮu dV ਘn֞6E9# (_|A9+0M` (egQ~a!JPG嵕*Rrr;bv5xHrvsR\\K\MWIw[§5vt5"~4' 0{*=Ihq[ ZrZYPwnGU-Z]^8!Zx(l`r10ِbHt3 ?(Hv up($Iz4@ dWfV(u&>[Nw]\.pBCa%<,gMz1u$Y:׎bT0u#&p*n&ؠ uX3mJ dev]nӔ]k^P7R;lCn錔TlAF#| EXnܐgb-D$wy6 𶣶x+UlZeB%\,~<{E<{NHDwq=[|gKV׿G|- 6\s}im . dKK\{(/"&4w!hߠLBUzqnL*z/NFx&~1t2vݿŊ/2vrQ"4F2!gnt`k ?c;+fCh e3VԄ58m#+b PTD*PW@()ٜPrUjJ@y&\xAg۪8,$Ƣ ѓ*%z91tԄ-X29x 2`5dI>a< APweuY^wi/ t^(S98qq,+BbַWr,űq=~l<˃d:淪s鷪SrfjUP?eMlC4zUZO%_h~/.dGoak!Pmoi0 W L*B ,_DjhqtO"&7?p3NO"om 5(D/Jt" h–&&ȖU$d:fDa&GGZs$sێF)G\(86Sj_(vS.uU(c99QbSՅۺ)n,u,FuxݔeK2`q|C0!Kk▷Rҿ$ .]$ѾK$$X0d"h!emD,hy$x`Aۊ#ш#JeH4HG.͋ͥo&M$6R.y&!k S's^p9e_Eݩ-%)|[:TVoR* OLxN6zυ7jnȖ]`Ć]l6fFڝ롎؛rdREMu3 ]J\#Cp}D u9c GuaepFMQz F-uA6!ÃזM p͚Gb*ۓh٨q_1"bvt#FyDc4h%M,C5/g#94fw pKپ%9E-1VrmK[lP؀-ڧ^yP4(Fl[-)V GF*uC!RW Z&4+ʓ>R>J.+_Mb("O[q;Q#&N-K@Z˅1QʛVذ,7QN&l 05"[uVAtD= H¶n+gMF.eYjiO8p* wf]<[ܜރ DChNASi*M6 %D˒|#0jn0|j?mHu:٣,5#N0?(Hj8 ʺNYG]]\$ {͙WVLOǤ6Pѳ02 ANNnE2|ptjƦLc(-dIҖacR3i,m٧F ì+TM6JǘhDZ1:)Rё&q٭Bn>Oq:1V,Rb7qIOX8ckGJ{M"FϞ+_ȱkQ6.lVnXF  n w SF8&6-$)X&#ؐ}?\\$if/A4 }{/ #*:f؅à8+GX)]VbcA#ܟ]o,LmvMxXrర zodq.jJA&;\֘_e.ZWsUF?K0`Y1Ũ.BFrv9Jqqe.rUXZJPa׾ w Ϊᡣ{> Ene;jU+Kr$zufUِ(b թ6|咖]k\ɬpKƕF٤rooAB2>1ko [ 6YW17`/YDjXD8pE!Vɬ1&gߌHAR\ E|TmQ.Hl늌/ "e#%6 ́Iba,>f\eK+0̻e6:t)BQId,C("<&P}݇}mwLZȺ˄/N*=dh>"HhlGĎAB:MF/w+ ~qHY.j!­.PA,ѭPD},PP^L9O˜FloRηtB! D3v%Nɠn@1kb|Omv u%s母ӣ@O<<:a(8#x$kU  ]܋3P"ÙVF ;wwǣK*޷S#K;=` .b =cb[o)OM #"©p<ø 7޿ayoatHk7bÛ\_Nw!-\zWwa'*t|$8G(lt}vz?}0(O]kzOէ/*W1[ʪyz,Rs\\4{|MtMïm({ -I-@ӯl,r5 -{Pl~-0E,&ZGeb.(!꧘Qu˗?'x(K2Y _C]3] LbVvRs7 N&%p7L&osdҀ>Jd`QBuIƵrlr%8(yfʞ\ s.z|FtV+7oF=?>?pa>^a&Cb&@ϻNc:SlvGx?pšOao=#0j5y[LƇw-•tJۨ`O͟o[J4y(Gw۫06rh e%R"lhK{}N_[O4r tew1o=.`N*}9(q߃NE8{V_tAEbAF\Q3+?vnj_a*/)m~,dwL7v,O?nnhِ86 ˫ Sj⏿7G%8tІ>/V,1 k)S.։js!붨T[z,V+UZ c_EHpc"Iݑrz^kt]z0׸Kp b +y8-YVq3$YD 2`inΗ@7oxJQT)?q9߾pSinAP^/07ž&sV)ᩖx,)`Δ H#}*$T>Bh>wR9 #l ӹ&+!|SґN&XPQPM&CAI>: rCʾ!7[fkozsUWFf0DIw6AYZ Տ" }`rʦK>X##'ga5+]KR:0@Ԃ3/APDY{`@D%ڝ/4 @|vU6y*T)V𘦳D^F+|207#d00ۆ"m(=KXpc GJ+T t(j.V u5Q`{鑜}we 0B{x6B=jlCE=W'bNb鉻7KŵUAċE5*w2o#I&dÃ`rTt:r XR wj^ J9) Icm*qdgņSڟ øQ.m3Ntcݒ (ʆ{f^Pm.(#) bMth0JT8c"3\9\n4dnt4|QKf$.q m i87p8Ƞ)^$bqx _#Ü%>UׅFhz{\lrMHlVgHt)r9PohRp-rtx|l5a ~-VF3LcqI߿8yk{*8;?gd"i.^De]go/قlaxKWAeu]::Vꣽɢ$9)7,I?Blyk.JeKx?5, :3Yonth&sg`Ĉ>wt^|;+o,4f<%w;DC@lmJ^ i4XZx տ"?"/튍-oR Z6RYgrThy>,Sp_GCCy%b*R`[p?g\IpI0H j>9zyp5 A!61YzALZ܋X5bg]H5r8i9 Ҍu^VpPZ(e)D;pM>ƫ#@PI1%@1&8AffA!/ɢ/AuFYFc_sL-P-LV$Kl?Xc m kiAYQ.T<U)yj"|TUp:7`[W)m0Ma0">pFE0Ç0\'=j1oPwlt- ms遽SVM7AFb/eS^B#,fõ,l'x4e$Xj&pm|;w48%Bs?X}u qmE L#J?07~4$5 JI IBǏrE##5؉ِh.3"2ٝOFeΝΣ]c檋sy/;$C=b}?mbOŢ[2i^(K֋8Os@(:~'OQFݨe72W; `[M`M;L]%!7ÉRe,E͖[; i<6^tw?Q%lG> 5R]x#)ް1v+^X ^{QRlKI%pE0Q61n־ϊc9,(H- umqi׉&4[el,%=eeA0zcxc ^?8j<{|WagLQM^ L`4'71IКwq?GoyqLVc}+P–5:52>_Ƴ;!ʰ9(+t2+sN7fYW&QJlK@/3w&{k/؄$R"Ga%Pw%6>jQY}2՗;#9z6WpUzE?1!)5"p^x;?m?[")`2[<>zsi /lk_[ I[EeZYBT̓wS2YXߵǢ?z$NN_/,?n 8xxpT+}j;:h6ћ4p0sY{:}lL=iZ͟񇳓g67BHN|['Q՞\ҫ9>;8zcy| OSvJb|v;Wa?@gv96ύGi%{#LQqЮSY3 MdXW[g !mH.u>!Ybi- 7m%6stԟKKX~b>4'Bq$m.!к5*tơ_^ n,PApx<@Dqձ Rt96dwvm.h,+)|#[l%"0:6p9GL-V41pMqo$q@UdG<ߠ5T6&TM2*c PjNrfڴ(ы5fLkW ¥xo ,X e  $ ck#/=G*x'SJs!g6C$QM4$7!m(]mKq㘈^[S;:I$4%jݩ{+rեn4MDc`Y[K#1sr-̀Q/8elD/7YS1MQohAi\:>8kcoar1!lhqCnwAGCnʂ8 'Wr"4 Z}|TVڭ~2iQNVTc͖FdT|25!Vg6 @KpW2`͞ғ-5 xn@y Y ̱"8B7+^4wY7sԻ^t,uQp;lEOO[`۪EG5szGZۿE/;^-Gu;B.L'IrwEm"s|c  -;um]mܟw9e\T "`LH%@l S[|*՞1nV[RmdEN;࿢< +/^ߩz}CO `npcr1Gf@tPpFhtyן\<9ty'm 6G\2.dXiZҺ>B1/2"ε,q. !i㫢ULVYaYrHWxiԯ]iE zaG?EV:e׈U1֌' "j'wi#3UPĀx(s Ti J{X"\Ip,[u5:PT*N8"$ i"{čp4(Ȓ KrѾj ibzDDYʅXԢ%fay)_xRڔ̛3 «KW%ϋ4FXR(^ \grԨUUŃTejYDC7Za0raivts6~7Z? KJ R԰YB+ h_ɗȨa}ֻ)T( w$ W#v<'j݀x7C9?vd;a J)en4ykrAvMHP"ٴl`oOy r`_6P˜5xlňzEb EV'-+q5 -o {hIK%=(>;e6[af7*Y@:*$?J-,7;N0Sϓh )]\blD{WSx\Cאkk|3/d/JByj1R|]'&M8\%E) x2Bv J 8( GɌpc0 ILĨ|&j+H]{YAC SƑJ"ft ξehiF 2iͭ&It^4IKNH,g]Zj;ڵ kC QhpN#'BnBRi/ uJuSPl&+p1!3t6Lj̈NcSt#Me4B4Ҷ|Kp񹦽EurmaLDϢNDkAȰEXiМEtĴY.Vv:BSc HcX <}C\љl,´0<0/]\MF8BQ1tGR5V&<IdJ:Ֆ⨮!jL2J#MX~ۦ W8N gE~}Lz0lkxбV[Bj2ԟwY"%0ZeW8D[cǤ^/ѯI2 xs7$ d_8:wLHtƣ'g0dTBl8rąK}vj~P~B*DQ**lzm^b[d+lUchdžu2NZMG%.[Q#ZKBiŅT,Tj{ :T7R dS%]/ YtV&+EXߔo#pW .'o4{&v;φ?g~LOn & n55FwS5U  r _ 6orS9`, ЀK޻4@]{{Y̌h5 du"wR Sj6ͅj ?X^^u6w_ uo ̿Okoxx p0R| J\yolcUICWCS_{Iuʇd$zK!mhD10xQ` 'ʏcy|KEUV#d=:ﲏ*PJc*$(MAT"e4G*!?%h+!pK}~y$˶HW"<~<,/~<Ċ,Cɨ;:S Ay_EB0ea8 {`_ ܉O}%A _Ƥd4[sNAiw˥F^CLNOO1Zs.Q[%+Fޯ0*KRzi韈߯h8EbrNa[)3 e(FE@-kei3@k[Тhv( ʘ-W8m ,Q$i"䙅W R2]ge-Zʱi\4+JUlbukU wꁅϼ1 ]~b@WP$죃8 b{_bH^2~[h(- Mhi9u,ԑ6T&܅>*d kzM AIp`-JީpCY ^MLkp=҆9 bZVj'vͨ67Z1?/ bR>j <מ_scW_)%jHiXP8@5z`a/vPOV0Zu#4ŗ]&EM 0{On0(f4Wz4Q׳ף[twOrY6z%[ghRh?-❼jd.*߷"K (R8s@ B)0dQpIعl FvVe&-[9Or:mp c$d=O 2(TD̍ZŶFV \ e6 ѥ丈MJd '*F jEь*0f^߉>??W8}jpkCA ڋZoUvs~~PjvYɶg8-yn!팣ICĽXvyor ܲ X5ȻĮt@5dl=q*XG˳G4T2Z^ El{͐iȋDoLJ)合Ce`zdwSTʰa+d1V'F7#ϓ 2:V/M97oW9)rFCq̗)r dj0~aI*w#uS)EЋ1)o2bBb^ Z[-C!'J$Fr,a9MȊ-:gT25 FUJ벳kAg‰b2g*2y|@mdsRLwxw9tnTrRda-oȒOgCɾp= M华*tɤv {"3nm`Nvd\+$n4PH莯_toz |2ѥ.zs ucCEJpR꩒OS 3euf t)41ʗ(he?#.3c wrcÓS~e_9jx"Do+ѠµƱ[gE eZFϭjyq?}F`|']xZ@H!y0:Djz géNaAA ۄKUkfgmufo/٪F6˚v.ҋbzMЂ :FBwxY1(M Ҝ|?ōJ4Rj$z1JQywIpd GÇICHV'?^Y!݋fG~t6`~hIB pn027m hx LpA ,X`;+ Kz#&̒z|G$xhW,]Є+s3ė䩉{] ”,8UkmbT/`A:Pɧn n:C(6< F@FpI灘k-ф Ҍ%c71 UD^Oy0'{=uIf0~<xS ?}qEvGWZ.,H2uq4ѸI>O\kkL (F@@ f ̃O2nr $h\ 8Rhz)93y|2 kLK=-:BX\_{HSk!FSiPX؟JCU O0ɒfV3&DXEFV,[Fn@7)̰ץG ۾m=>vseقJcLгݴ ~n>u ~qe{d2Ȫ/_ -yy=yre0= ^?BPGN*L5^U1J)03\T''no)A\=2(I*@8( .#^@e{%^jeE͖_i]!Pn8 ,:ר OxiECE/ѝKUv?eSɼ#zs!ˣ\^N߹;0Y3[g .lgTiԹQ0FsYR u_t} t/E֠/hFKl7]A[,vozi즹ie+"x+g%cLQ]˞RuޢNnwAكg%,[{,up}BB/ ;Pu3+XrA" 1׼znrAZ7@u~.KSp9?Eb|wslVLnM2k - lW#( E"ndId{/pco.pM_GXB7l p\?xLg(S[O(wIbMgNÙwB\vҍneG_h%SMA~_$bǟ`yXDL=J2(G"N|KϤAupJ#fzf  Npj#}\LyT;9d=dYZ}")I{4 E (XMoR㓳+U7rR5wLXqHd(/k:PP :^ǣjesx4;n)aupCvKC(?zb ؛PFz[eGYj SXQ oELCc0b)i Fi>s<Ҍ+SGt)@yl`MMwW7 #k{a-s(إKp^KfC :A>CbZւ8zHy:PcpT*)X+2ձZ#+#jB* @ʸu,G&#@d#.#l6Bt)k@#O:,سYcVnJ<yDz|3 (~LW`%C`ØHGFqd [P0UI(d{7KveAR6֫~WR]5X(!L3yH[Sl' iX&h BQܪ8҃lo[ME?~OΧH5Oc8q/Oёp$ٺ papOdmh-K09cg:OrַIv foUuA+ƚW[e&Mpn*g+Uy:Bg `eyUbdeM&q2T`Qe~i;_ј@C"MȉJP5PDA!1um* aVdҍ<'NeMJ)KM^Sr結R"bU܏)tVm"6KH8 !+ނXWdnjҗ9?C"!tp"2qjvkr>զ亹:].`G\ĝ` 0PufMD;P@~n>CԞF|go)3M;'z&CzjBFP(EZ5_֘a!/..6sm>57_if9In[R/eIruֶ-T<\] ޳@(Jw>ѭ\G*}ۻk:Zšy??3 Bc>fmQN!~Ȣ2|cmTX/.7i[-;peܿ^hԒxһ@Ԃ_JQVWv`vm!௛{NUCM^n"psACØշ=Vdh{ 9h!ZZkɂ{뼆A0ڇhih pQUWOo2Mvt#;e5@B_Z@i$r:PiY j5`d!@H ߱5HWznt-]7{CɔZ! > mkԖUᄘiۃ"-o0n՛oX]z0RvZ}&+ym.FYaHHW$\MWxE DhyBǝ"1kouhc <^AiNJTOptIoI veSlmIyiK݉+2ųM?m*zm!ҚxrB1JdXh&7*aoexd}e7=Bp^\Y%TЭgb"Tm&e˛y0ywP]!zUvxDDFD̽ț7@Zsht V66S|qI =4řXI`*^2m^S/Sزv!qTބI&L_`ZKvD,YқI r^o[ꆼS>@KL7iD0O8C*IcZL\ .IEg]k0(^܋vQ_0Kt,Rk<Iߑ=֘}:s6SfMwlY=ة^<[۫mMI$*18փ9GF?$5$`^ңXHmv: |{zz8O2 ;_4C'q(5xwK5A-l%$XFѢa=\ 1wau䜂<ȿ_rnVKO#ĥuԦptxZ9*NwDfJZ_ВSUsO;|aN?@4G۰_4+O{7X[T"u2A Lϟ:t4 =LP?'oH, ­M`h5 y\uJn"MF)MtȄu܂?k<c¹mC8%;fX|#o$mR3m̳ݍ+vJ}ݒ'Թ0Sa}֠S1U% hFl y PE@trb̧=ž:HC?BrD1x@2pu ZD ;^6oflU/a*uJP 0yaӠ*mkV>2uact+10e\{JtdggoI`3txR쮮v&wlAF;pp0q[,ق)ѤuW08/G mnlD->~|=%X;GuX;}>H [TlnjVaw7/`K{|r\owIӍrԸN#]1D"۽`$ x_U\}hpN!`a{bFhz3PUKޝVi_y^Ee0l:^cIeZҀ g<<ҁ[ycoYp:Qgн{ػMba >՟.HdG p+' 1JKo9^9y$M=Ĩtpb^ oBnbUª.7h ;o~[c6$q$7@{`ã)TJ/A7rk5*/J5_l8|HMҧ&=;yYV.rϝ% #矑s; i2;C]s惽%qBbV;,{*drK=X<72I}zd^%a\<< O= |w81\RS3\e k;]vv{:s1xw٩!>%GR[7Fb/yU6}7:wvi\R7ޠwTA/WmdYZ!=?8M(Jt! O Y[io>ana7KL50Xl(iaB15`O闖ZO^.-V/*HRs- DeP&IvzIwOL `Pͧq<va^/u L۬(ow!φ@:=d.b7hx!ֳh>j]<;$h1]a=L2) +|[Xº%{B4EOf4? ԖzNi͍M'D*8Da{W{N7Q{3/1L-V :HN ?U#P}b m:+@e yDRޠG;ܻʯ^rߒd@5 UvkyO`1@œǤF&%] Qk ´ ,ýJn̙"L.`T<.$,hd#o̠br[c4z&5E0`BjONn-6Dr[Ewx¦rzjh즠yH#&ItjiK{La!쎄YSI]KIGK/ڠ%URs|}APMAD-aEsfTD0޴rBPP۾/E_.m+$Glt P8mo@߭G qknMP x2 ^tR_w߾z}MƱ~J {Q͆4U@5hY5daHMS1R gs8}?M 90%ttr'QZAц׼JMO&#L43(ׁ2m )z RlF(ܒMd#h~4~\/hߝM7QrAyOw~L [ZM}cn|׍oXݦAKX/L5x42 '_$f4fexrm"Qdc7c!սM`27|F-nl{h$q;C;e5 F:''L;r#L\J[t-XT75ѣǛ1Mq)=&qҖh鼾.?ƻ%EׅS{&?>OJ2Qa Q2 Hդ& ||eZPR zJayVxBG"!$m)a xUm>& v#o)5. dMˍF檪+c9k j$*$(L--sW^_h/z#>|bmsj`7k>l7,'h}HATn!df́-Dpl }N>GC%=kH9w +ȽQA 7Uf$]wȭH­_'%?pS RvV NCqr DxאA3z=4L>*{!  j4?G!0nM)(;%/Hs$}"'J a|Yz@&&rtt.RxXh#dByZPKתQ1}`ʕaoהn_P9XW?6@%L]܉ti zp I]x;+tlʤf C*/k^IJ 6He8MC~&)-J.uKw܉".x#0h=RbY)\A|ֲCRT eٜy(=<ϰv}Ѿ /vAttv%u il [ n/ؗO @Y4uKO! ZB s1ĜP(%cAIxLG{ܾ0?tw366s&dB 7 i]S3&IcY֌EVadbn *,0҂7h\<RK @i(-&];eQJQ..˘nypLE4_|/#ñkyGͩ?iP+5fʐ%QS0mϢNg[Fv/.<{K c[1kױ`hrA( 8>+T{0O/lawt#^2Tz,L!++H=5{Dx0_a*l'VEK L9k{FT}+6ᏛXpJ*pEy' W[ٔ0Ř[ P.j<ߘP GP~Qzj0I/MI(G:D_oɰ'_tHڲK4oT:9V8$cz\*=R[Xr<Me˅m'E5v]GF.*XKv-* '*硊%#<`? se.{턃,;j3 0^o!zS=qCrp" *=#*Ol|bUh`)&0v 7Q%dt&xͦF3jy-džb3p泊jz~;Չ(k׻j)i4"8_su""ԽżU  qYǸel,LLF:[Ӧ☙oEiԏθm )4uBTqL-$G1\kN*` (;|ͷ wDGxvt^QI?50'@T~gm^A4yNK2Y;1YeԹDI~㤝ye՞~rs"ӖH+vJsG Ð?<\˵P;P,M+yݵd;4GLS '#v RʴH=bY<L>UW Hx_n.ɣoטc 6}6ZW2;ZLzoqK!WXX 4f^+mVʳmhF$&G}XBHwQ&QZ3eP #vsikQ7U3~آUvmVD&g]rr*yl~:#"!YX*jL6|'&ɯe4ؤT΅Ck2tUbm(m}EX^bS$_А7wcոmnE.}a:Z}דF]f Z2-MzaSc 1Kh 9Km=2dE2Ŭ Sr9TI'Ù_kIj^[{_+¨K'whE y_‚!݇72T ituax,IC,Qc_Ii7/7Lψ""j}q\_-w SϵvYgJowgITW Mַ PMGI*TRFYW9Ƃ]b.ɥbt4.pqy@lAC詙6d^!G=GcO=WU&R9f0P!\\ k03Dv:-^@~A}y˃m^Qo۳\IX]4b4QL=b/Ϻ!2Ud4t2d I0v#zQ$4IMn> x<4\5:7d쎛 7uX3t矱g)zh7o;N:Ukĵ5UǒsȎ dB4Ԕ9JhC6U% %[ѝ%d s]=smt qV)w_1y'bªX )C]SHȟU(N1u,Exa8=?l{*5:GY8!@) I-pw'_? S b{Y؞"4iu-٥ghΨ SèYO-SVk:ZQfpqtا}A]8ZU*,>[V(7:"z`%Ţz}t&.O*DrDn&3؂mD7cu]CͷLViNm+#;қq/%fOuGCfC'fpAky#:z 71RT7'4VᯡRX iT#JxD̙(:2ߛta7h\QH GsTڜ%W1YT!CM"Nꈷ5>iqrQ)J4z<6;JN@ u64nM}Qf1/ڟk' + *Q[s+F5ƨe߿p̞|]~Wn,ܿ]r&3EZS:ԁW>*FZ3r?v:oWv]Y7W%`}PJ=vؔ` 0J8"ҁC,x`G~_dZ,HeFohѭ/(fئ/P;POxy`gQ6 f!BOe@2&n۩%_:0{7&{X+~ïQs@0o_[۹'z\WP qk@WwѨT*b*@ *o!'~2[Cޡ*W|e⒤-؃*I-yKбrN@>bR{&aV.L #eVIwh&Ksat-QuJWQujԁD\j)\`c[q?ĎUp'o?Ж_9Wus<; ]p1Wp[69Ĕq2ɸĿ<7H|MVygrv`#P >A#FUX~uxDJj@n]]='`6 -X-(FN˜.#P^m(SFbdЕ&*nMѥ}At.I$Wo+CT[kP5ߣP*"cqWb㻯Qx'tzH%2y속*>5, RP0ť|uFË匣f4JԸ4Q)8S3m4On#_~e] 19 [8(L k?|qLfA QgóTU>yb(H:3y37Л)dwvQMlU" G{8/ M| ,aNTl%ϼdݠy{>kWa3+9aMkUjrEd4\1WNܱ)T5i^OWUI_X{83e' U4VwE/csSN("Ϳ1 \t#tGΜ8$czfMjylP)co' BEPWlfDSHGh_RIc Q7l\նbظ .[q-}34ȌTMLߔC k',n(LJا4Csexn7à-#p^LR41瘂NloK? uڡi?~qo95/ 0'4TbO1 ²J ]b0G$ٕ'\_Xԙ!"EjmHargJeůdnZ)>d6Y:z; C=S ߡv?*& E ҉I _(@(;hk%u+4Ru =F/z&=,*}QV\>dܒc~Jfba%}ǩ 0P|t.a 4]]q}1F7 7tl6Ӱ%F{0f2Uoԅs.)N yaE@C;I}Q}dì.vgu-K䵵bzg[ dbԜ6S !oJiJOVg6e{I Q5BuU}6\")MC/0Ոۋ2F6˲iVt@8iȇW[9"(PJk*[ug nےj6qJvPx5ѐD7`@/!^| ڥ%NP(MN*i6YGMI% 9=#ޥM\ׂ#ܒT) H{ {Dѯ;'ox JߵЩ- CGܷ ^\=tVhAH "($Ɠ(BQMĊ'o| KKeSˉo?& YePԆSJKSL|7\ K Z wo{OSYpVceR%\:,ϖ>CƕmQj S<S.a孓wWWKކwgjfrI`98Ud =ZY~jƧ S}=bu+֜X%Ict"A`7:aZ"ǡ&(CsǍ;ą!8HhI?p_E \6H;3:MV[scBN ?ɶz2r Nvr:]ņbNSQO 8B6Y[xq8͆q뢝h#Gs$yelL*pǽ秇'͏WY6*FŘKh6 2zb,돍 wpuf݆_]唵G?ՠ)(VOjVo;}ңx}j3;;܈4+Gh2!Cnvʶef$ \2Rb5oz$;.(Uz6\61Cs*j.NLv{b愜K#g`2z19uSx;y?ᨬ8=}?7IiTI!/U?oZG0Bjsu*x|A9^"Di$ٵImCrm[FzHɷXmMx_F3F'dx;f O=Ib>$ Kr8t$wsdqc:ʕn\#ROzӀ'jr)"n=̟_5QM*hG,wcRj/{%iQBii{dcI-]!mD/V3HCc1ĄJ햪+6=yC$b ^44ȁp- r8ځ蓓5 x2MPh_8 g\ z2 q*WLB2 8R#ER30'|vbc0j ,2 @c9M"Nz2K r(9ܦJP!8=X;T W @GS\jٻ`yK >J{NTvn*7|[3ȳA䧯MrOW KqTȠ8<ȝ2R2T>bL89aQb͝'KD$<+4\G ' ތopHm_@\H6f6S5əb r!qFL AA #,eчm#ˑ*pFeQmϺmb+`)}j~f-ʃ~o{ўLRO3a崏Ӯa~ebz^@=e{v\ni# <4ZeӑQD?$BM EV-OEuNNN_j,ϵpp$T}'{,:I3Hl趙"$?(xcT iKt&h8)sCNNbS"moƩ+XvⓍr*wJ@̎:Z<7f.sals:LgSBn1(cﰟM'=| ##G3d4o[IM;jڣ/7 #s4lj]?:oxЙ| pbv#y⥘o&xUvfF䅇V:Zc{5-2UBurw$Í8Pz"6KJ3\5Zzp'z_Q@ FTRvX9ovI3 ~pO6z+ k?ma8%tF✗kC"к S4-|'K* 4%z??|:KJ.K[JzOte ケFnh*ω${ g=ЖvKiBY#zpO\֦Dh"^e (TkW&Y Z]!`֡NI15w7RV$WQ.N,*'(`{ڏ˂/> x? bWBM?sKw^*nw_|R@yCݹae|j^,ON@R`b;FQ5FT$=&vpӼys>ٵ'⋌C:Wc`%j1!;LQ?[?Tt|HL&[;Q1n@ؑ=KpCIDajmm18\5/;CpQ?h1c5`0ٍg8N֋B`7>Ih;#NV 8ǔU'P߫=󣤣2V^"k?gx爑Kɨ9͜@;ar!0TXz싁2as 4gȗI`< u=.!I&9yJaE|yrX/y-3/W8qF|/Xɝu&U1tq4 ɻ$CI 轺fJ)JR~e"{tT͢sCt+A;0A7-Uݗ;ǯ?FwIV(Ia 0ӏYE:읪8x-zjc"+ .x-U Qǥ.ݓK ( 8ŕ+|豯|&?w9v [8E $\qQT5UkJ¯Ij].#tƊ#&<ۥPDbS!m$+U`4%8@HuP&j̆&w-5aaOH`Wru-$?#9xSK=]o47|Yq6:PnFo)(m怜ތ,' -F\Ҁ6KPw3:ܿVマ Q IOA\<luZ_̿Ff_keFg~5`46[fLuӸe;VLr0bVDQw۷̬ v/e{2n(M 7\$ o+m+sG'3-7X<-h`JrTI;rahcfaiʱjx8bI)r+:xS"-Gt6Y/M j/qAzd9@`m)5֌$Y2c 3g|=,~A\''bdӘٌnx3V9k`7rх`('䴷꽶HHent˜Vp1 .}9`Zf(srY4mjHj{jDqjdV.]1&YYYߢQ.%MRiFtIňަ0J6^8AVQeLHR u-F__W)'Z$IjV6GЅJ"vQIJRu<9ӌlRQudxC|?NOp*ZY-W#65.Ol@G0jC١Mh)JƒH]f?OjIKF=G U$+ڃN9&]Ὅ]& '>*fᛷP*2YN*|#1q!7nm.^x~AS`.cA-ehWa'f(?c*8d%+'Rh$(x ?44 Jp:ɋ*oaNaפճ]u5LJ JP-CR^XZ4W 1H*ʤ-[X΅3bQLΠk9Z* w8˭U~|U~:f׮j&D}/&c"ő^\sr&}n9F.@H>#H.nQۆ]e77ѝL"vr|\~\k;1-aKՅKӞvyq {C@254A)kxckđBccgo >hyb ?a$V C"+ V*EhIwSȃG?blavdEJHkB]ht/j:mSm؝n5:ˍyC'}k2k4Nx@mFS>[= 6>EO2F-g[R0W " E{>t%vYWdo$l,W nm킖<11G[k?Xh!叞Xs?E2͆,aPyb)5犃>m 1 JM;I җ <ۜH!L:WRR*]^Eg"[epi :83nğM|nbB#>{S9ߴW^j7 b0|Lxa ]>~D;W(X[>7cx矤@KNh"iW!%,5,mQd~N Ep}\3η:% Ph`NL5NFX(A(cC`FRkGDb}\Z[)Zڹ;Ҩu<]fĞ;Q>%̖U#lL֯,2ޓDbLf7xwaQ;jĐʹ\6NX x А pdT)BUٙJ :WsP~\_Ɏtn?;u -agG2dA&dNo@68 8 $4jQn"twGGrZ݉P3c2Xwe[ iSz6ϾӪbG]0BcEzz&ȇBCg*ͨjUG \ '{L$h]=e$|_lڳHV7v#l5bm[v&+&"'R@0:G&1:o5E"v r Q /݆b)]*3)ǝEτ۶1v&1&+1O"GPM-KxS&pJ2f CNao߹۸v+Dln1ƣ@a}Ǒ>e[SJ'r`&!dUFc^Q⌴yhlU) @uHv_eω`HB"{^D<b91P[37| *mS>T\*f `!mT>"VűhժXc1e3\7a4$?F uiWK-UTcm\fa™nQ%1>:0g]%N<ʠM=u.^%޳{ OI~^h4GȷNn|u~ e@$'  jjK {œVi9zmO_BTcK:epUළw;|\{\!HqEh "j1B>F}1)/}~xo} oEw6h|[I榀,ިiIYaSyutpaRDM&RZaK!rZgόbVFOTtB6L"G_^:{bNB?=J-aY@\i#?/*~VΆT?~_m> " /p f=&(j|%퓸Ox=(`1#R ]hR0f-@}";n[B.RBiǕx[mHt9[~W(rXUWRh&aQMNLkiЋݠ6|rLЧRC ,X0$p$mWaAM!!+%0c1dԀ` ~:s^G0V$gkopIןyeLMFVj+ZK&Ԕ^ Ѫu64 vЊ;Ҵ"S2>:U?U} ӼŦFA8%Az?[U`=Sا.|hq'=&^Lc;=:S7eNIMTF9IG_$tk0Yw%ւ>UOMx,Um8O3 MàLV -VVqUtxxd#3j㆘bޤH31V6hYKjab6\?t&E_X>D$`| 0{ytr0~.(w{BVc5IQPu8jP5 ŗͧb jD:@=,D1Œ@G556ԄZ(DnK=&a%f?q)q q3X˴\aEtDqHg}Fk_s"qhjG3I~@ 5F: gs<._c-/|hw$jۥWV@8h'ԓW;g?7nѯ՛y8L' 4aM*?aPtm=7%'AkNw2M-+DF9S #l?=9=zU.fZGA$%Bx-u|+`gqһ3 uLd(qJBb?ƤDGF>Q!O0{4),;TP`Xr@b ~ 9J:r):I_-TSLk3Kt.bkX4"ˮDdB0]*;$Kk֐dʅm|L@!D2G3uyM9cߋaQx&ŦS~v'XW~:>VFKmP䣶Fy+&>K6r.+ϱT6)EKukcPm_6 UEW~7..B&e(Ί\{.T k ,7.(2iO}@^s)O\~]g߄ԯԱCuz W{׮S9k 1I5 w^s9LȜ6i>?|4yNL 0XY 0HX90os`Ơe{D;X">)wZ(p~8uHrᓻ5~qՑ'uҢtSh!4<4p{Z@PÇZ+.RXQ+Z\KϐU4 ]u6}ºP,4x}t_F;ns Ϯ8y)v0'd t^Z}'o&9r_tν s~;$k690%jAI:$90VW^sLLtvWKMk!-sY.9O<~/!1r?hJ~'k5{c*L@u'O69Óz"׎`Qw:j$_r'ot'4]翔0KBh2 Y)<Lnk -20A#暥u'Mܹ N){I1n:i0KiWls8{ojIV]?"KMkQC}B!6Ԑ#R 14t$ޛɬ 3g߄9>!7Q-җ <`/y VV^%なsx[ﶇ{' r 4p׽.f6%vs+4 $ud]m_G7-Z/hJdkG3t_ƖсCz<|XY11`whj%f+GIBgO_l+&vnOI`r?e]/d7Z_hlP81k*i㇗3ix}I^ȓT}E͡94 -}hH[Gƹ帓z)d f{e ow1 xvwgAԵr7x(jA`|:$&1w ݠf=8EyFiNvs[WݲCiL]|WMd*i{Jin[ۼa g`*r*8o< 5ζ-O*^U*SUr~t͗[;5cTC''L~nx#5ifvCZ"b ]İ6\zf +K-So74KܑcP }LA _u0^d2:UJ<++FXo;o?^Yi> G׵Sh^g (YODH_++Q95WE;Q(UT7ư*]Lo"k9#d=Q?9^PI1bx LØ]H̚8{7qLG|ʕCz!C  x2VU;˷C#蹅hgd]eQ*Q}|mr˼pNcb0l_vxM_7#M@KP`ASo C4JFwZ#etX)l[JN\G:]>qF^EgJΐ!Fi"m G>y^z0_9G̃cyF֢TNY }؋gݬ$FKΔ w%R6Bf[K{Eg xs8 %XD\Y󵤓q6^yU`5Ɛn1+w~' "r9`4Rߺ|1Hѿ6B^\n5ìJ#2WxG(HST| Ѣ|K+%qO=9#|D{q5Wx?M?c`vsw BxXqvXmq,OZ!][U)/}j۸Utد]@{j7]~V_jjK@U k?q'G0ãc{5EW`^N-U\ZA7j6[ͧn2 `dT5&][.AuJza8 Ҵ7#kxJ!t2BqpΧlۑ; M8hW{4+5^j:D7-5<U |/+ͧ>Vϴ;\0;"ݢMe,l aC9myTF_LCpW,*k LCp%ʅ\:P!E}NYmoDQLhVLglv!;m\ iE' :t\ELi4jH)'I5=ۯݝÝ㪢EUM $WN^ fظ#%GZ0U9&A*1ɯF3l\AR0k8teX2qq;ɠKUB9`ƩV۾Uz_evă1 ФX F4(6LE zý "9#vqlthLJP_m6 bCG-IC~Qj>9|u\/Զ[UB>tSqPV)t;7@?I $ĩz7Qzpͭ_=<]Oj5(HD]CP#$MDwW ql"vTO'~!VWgϒyb/MЋiF8@辜xÒk6ӑJU!WC6ʙMC!Ɇ6I K>aCf݈AH`ࢥGxAѾQ@)ˤ֛W\nqSX?(ӫq5dݼoO{vgp&= 9}D@Ghc;,N8lm) j CI"Kmz>9o~btECE8\k4O8̭wdR9! o-ʫCe@}`MXw?pSc|Ƿc2JkB Pl7$*NO%:QH*F-U{" Mq5 ?mOGg)sW8JR93$y)hDoH6Ǣ`/4!|y*iKb %8 qВPi?qp5/![{פٺ6YAgbKܪa#F ϶͸ tv 4o3mS5"L,ܖ /wd?D0S:(*dKϮ ׂ-6Vsd_!%QQ֖Ī%ɬ#6=2 ڒ.˗\i{)yȍ ґvQ5frs"A_rMD*N'&|,Ѭ?SO6{݂'W_7߾LK"od΍~!1R=x_I(I{bZA+( -V'ݴQ=akCɾYc^P nN>NEZ@S1J'b )]dWDT(o hS[k|zÀeF()Le5Tژݶb*:ՓgNU̎h=#QP׹ՓN'έg@u:>k8~[H qg;[߼p ounUL`ᨍ 9&F^ն/:iG0Ty=PjTT0QƝƸ{yĝPuW=Dy, ߽wY^ÚbC<'*۸GJԱ7x~l~< jk(L_RJ5?cVP<ͣr_r_::yq~~i.>-[]Ii2K4pk1*ͳIpa?v90RR[}K%Dy=$<[]:"%^ze(؋(>{ c|koGCHyp)-w,A'kl,o<5FmcʔfƩ^3m(/(n@ (3rď*8K( #+e?;zipd]dc2BVZ_ycԶQ^128^{ȽB3>p(6ow>t~eիɉ*;@j9zj8[[O'E9eQO߿_[pPK|wi7b*ܨ/+(ޝ4"VKJ pQvG e:qhj [p޴ggl=j~{;săo;t2?\[U=!wO%Z\+T7IՒt۴sFQVm~cM0QGג΂&NI>RFbf&K V pUE!cCϛs5 nx@+BlO=;|!_dˌ?8|&Zv1K`Glެ>Z{ d>s#_Lm_4i߃Z"Q|Jz˶fht k]|)lR^Tmhgq[A8BzC5inŬSes)д:p=Ke=0PkH Q;jȃ?ǟ ez tO6fO7FyE .1H7 ByJؑ{5<` :q sjݰUY_"#Gq%4y:`MRs`xJJs`|#3W@Fٴ)  F.-XS;,#Z҇ ,a>%:E ~ZPhQ&^-NBϺ-1XX{K9aO;}G~N0NB[V9*lLzSM#h|>":dx EgqTdBNH{ /AT(kN2@Οp+ 8f4agcQyN\̭MROUҌhph9*ܢ`F ^=4^R,oiusoT\:w`HMx;#򗗭 ]s+GR6xj4F% :.yڕʕ RD B.ů{*4ڍ)y%kDvcwZ):qa\X>\y}A`m8ᠹq19 xx>0DK"8a-~x; 1:z%q-?-`͆?fNZs, B!q*m\=odp8I)`]fxu)c z-`܂zj;U{IzY7qcl2* $9Mb8I̫ɋZSFv98`q$JgXXEDE!icAˡESsOYY&Kf:Ŭ{9KBj\V.@PC~U|{@-ehTˇʚ@2xCjK, a8%^ +"MclC^sTSqsQuOu! !m]NIi/(N?{ϞX.L; 3YK/K2 0 sVfJ\,M-݆ *MҠzKŏ8}rĥ;2mg4@2LT{st0s+]~[N{-(ɞ8Q+Nq Uv'3lGɰ/U$n1wWŖ!uC积 lWV Z9b<܃l #o5ƯJFI}-nxAҵoDKjIY,#zq7JpB,n 9ޡ꧇IeV`6A9Z]d/T0K);xy]c^1I=qK}pG~d"q3 ;zC dv;9?XC%Td/>8.\4^|4wUYs*2oKӇSa:'M\hEZzzJ9q˩_vh t>\W˷gg 7I69|)(qs{٪s(FP-<(sb9J:@X'\POŐ][z ^KYVh_6+)b2XDE7 @KQh%0 Est;w/iYHl忶uᅴg^~2yvF˞ʻ*&s8k 8K){{gׂΠ+.v*7d7H%Fn/)KZlA?F2t\M'P&!|5x9xn}hB` K/~-[w5ꛝLҎdGٚ#lꩧsם/͛-~@G)p2ر$U}K1K]<TU !BK`YEjm nL1Z1D鋘"#I{w1Hŝ].{C<S8$ tz;}kl] Ֆxf:nէ}zx]'!rN8&D$iw8K;U{=70'pJIuxL)ඊNPT :B[ | K1:o>0a驔}3/6-fs^\^,drgJ'> ƅ|FuɒcjK]MxƩȵ[p< 9)q+7(T\2<xSM`CV0-ަր @,~Rq<[6Gth |/IH E,< s9k~;m;P ӲO6mQ-KX?+7c;k-./ YRO)Õ2gi$HLO?Tmϙ.\z0ݔ֚>aFN`r|#2dӹI&`۬əCs&xL\x"-z OӢkOAPl P|0+&ڿ $L(2N*_~x(pF̫ٱY j({^OQMŽg}2]?>t)PGˏȧ| I4Y㮨@WMPzWy n C9;dTm}?z +?;|Wo?g ˎuA%$KOJK7*@}pYp"ACJ0bΨ' 9;~kH{R{_{NcyhhlZ5D$5 5je|[ł9 Nin9qd%MM>>\>v2#3Bx Wb;o="< 0~^lҟF# ԐuFSUUs6N:n05A* ֐, G: %ҸCM8 [9dU*`Q'ah6D',%b6Up\*E|SF^R!ڬk:˄՞KYi=4. "9BZTL5>bʻvNrqQ ^]/dZ ͷxEkozsrpRC×4}{Nmo᳣7'm(yu>ضM)퇕C? xlL}@3_! ]I¯%P5F{Ħ]#6 P|uLff[ <g~od`eeRj&Q8labI]lI [vݶjމ^W/LzCOCLޒqM)1H~O1n`JUǾdӑgkH=x49םf&9%6s j4l-=kadX)Z"j?-ݹ/Q ̶1+d@>4m̍_٤;)Z:H_#S?x3NB槴Y( YU"uX`le:7lRw1ǾN9r<٩)[ve]n#n#X*2HZf`Ĝ{ Vh(}!,NoRIGSs t0V:u݋ei5ș$q}4lme6 3 c= W_E /ٺ7ް.މ|@ĥ*H=({ޔ0I5O`ÔM7p9hיaR<"$F=IrI!pF.z0D4QMNOQWoPUh]Q~残)z0V؅+8"P`@yDzݭ@,Ø5?~~Kt8ް$yȕ:|*HG`d zbLD_gzҸk5[畬q/KfuDl8LO냮{OpߡX]' LG$h%"?³+L.52 9;-ᬰ@$%ZVtJ4k╥S@Y8!SX;foY۶1ٚ I16Ei"0H !I&C 1>xSEjUb҉D.ް+xfVe@)ͤ!uܗ9N:v2lW՗EI L(t[:ٝQALmD9!G=tИVYݒ0GɃ#`S,MR 4z?Fz}K$M(۟8xn\ހӝק'ON_"q>B>cJ*`י͕?B ڍ&M~Ϭ%"o uȝaw53(Z \{]f]"mBX*p٬ <ѧ.Zi~_o6Kmr} [sa4k}__Of>a0!.z,n\ 筒)zGqz}܎H-%?y, A w%d ~2crH]LrM KBΚ?<4@:vncX)NOBtOTOYUѥEsC(4644UtBC'';O&TLp iC{~3Wed=3(H9Y9r; {oT#dN'ܓdIv/(Tl F,Koƹk-*+AGΧ;?Bԟw韄+j'w,r}5:1<Ȇ|pp;7OFr2[l6ñ9-ʂBmh~XhsbȜWllm8M;}qc,(PNI*i s#Boi9҈#Ѣ q}2`h/`ӞoOrʻ^yiQl9p '-2 p9q:-8[~xiA/AR6ҫ"try^9}Tm9\h|hhF*?LQ.&\s@i>h,$|pȲ\Uퟹyb>2,̖0V=ɪ.;YS-pukj gnM 3TΪ3u5Z)>Je4 G*W~jAۭٳ+bԪhRJgR.[;V˅4*&?m4cô7WiJ ʓ}5w)** g*3~J:VPwJ=,2My-;EB-#ysJ@Z-CA.*eHea9YTgqBAJ71З^LD#MaM,}6ծcotيХKYх6^JROS=Y`% :BA6G 3Vl4VӤve_P+QԦs9?PJPxf fBRR"q 385tʂ3Qb\" #X(9R2&?2ii[8ЌGlݦw3kR9o!MϺGW]&@I8udj7@e{ݽ3JV~;# h)nM5ϱ*_&8{X_JsOxDx&gަ '_3x`6JЌ'iL߂ƾuM-rF=y]dr "& &+~O+{PT#큄5F}33_1#V3ntWU&wy-#x崮J@IN'O%m0c 9VRWh^Ҵ7mI0;Fv[tɱr16.p9tܑq`@&1Ut/+KD bq?5Jg|}_:`)% 6G;2 #~qdŏmUrHy)71XOJcJU3YWx a$T)RBRNT7C7BE65r@3VbE٣Y5m(\_z? 8zV:Z_lrEE,K"Á_cQМ䏛ɿ9a56W~,l mfJQN+)pz5$hl~\h֟~2a.xW.<~cX-e"=~UʼnrХBvfYʊjO?gc1 ꟑ)hL0đTTnE&gb >3AXf$;lXvP.{4tj:IᰀJP3w@[Is*b8 }|Y΂71 e:0*,M/!6:OᗤWdUC1)7Y#&[ Q*3zdQp<ưn4DPN]D\/:"3/bdE3Ndr;Tw{H5EA( ia6V2&48"Z+t4Up\V\>GcApC2SS ̅)8 H< t۩] e*=)H*B^ 1P2{ a%"`sp 0閊;\G ~ܶNϷ5u=L&d<&G Jħ2ݴ`X5gScO(>/^ X 8fxܸEI[G (p(| pePkS̉~(T>V")r%;B'6)x!ʺR9e @* +KePXI&DYrB͉%:BK^tfJE| N&4ە<&l ORe2? UEUr OrY6O$ Jڒ~.PJt̆ы(&F LuN4ڋ}jH[NTF 9LkE]WoG/`EAl]*M#UEҔЛJ: g%+\&%5sk>: ߔ {(OnTl. );OGyٺ`JI牰(sZ g*uYXn {Ϝ)om|,.IV"Leq;EQʒ lNF ~.6B9o5QeNPqZ'(f1}(+;ieM6^Ѥi8 {/LFꗝ÷@Lָ-jsS.WMrF~9`ڤpI&' Ðs!q(bOcoYH/"rR'TZY9t:H"F`q}m5)bXscK`i&NISn` Ә$Saw1Kr9$uв@B3GxHsNI s^nlF 3. Q(f~L=vgm삉1pr#Zc`Cn@fx!MBBORMm'{}R^եZR2+495=[뜣̈vX.ϰlxޡb-MLLZTRT!RԹZ\dG=5iWle^qO1Z:-WI{r|!R>@,+Jqp:Q3鯬=>fo#EA#v "NGJ|(,_Cb_i :+y]OH(O`w-ȺdW)#PZICLgvE>V[uWlDGhӪEq_O)EU'^F37) dpۓxdv# [*D2,7L6%+( fDE.?DCW>g[^óU8g0,*I;O鶁n"ipy/s]۫xM`8+yC n;7gY^Uq (sHmܙMI\ S30M+O55pp۴j4#B!c=+Qk)"Jf-U͈7;cJzBk.cgTtN_9Q*Ι |dCRD.0x i8yNgCem L Q@/PnNZ=I`Wx EuTji )Ba;K\ SE.UqWIHpqmF\D-':$]Pk"Q1:4M_ GjzR}f]Cf}%œE̒!Y2Ͳ2&h᜸qKM4:Xvδv: v;Q<,z2ʰk%/vbk>5 NzW:xe尗L8:w\qxQȌFN /ӯnrj9܋޵ᤪ]S/e)Rv¢u܋|*N!t^HKk@۶@&ZXXYK\``x{hҋ#n"8Z1jĔmSnr]ֹvu6r\xvd%:"i1h:BFF 'xUfw.xApfoq$zzvGx9hJwV9W\xS;pqls"Gf]0=rN"؞yPٳ-e:17/sd8 gCb;SR|V~utq[q˹,ʤA}|Sduv VIDh1ιK)RTKaSa#m N-PJѮϮ0&x>BI 閉gFg\OAyԠh祉:фy6`H4m\S՛_9xP_.ɮWZAٹB=+Kdy1CUw7#[dFgp==(-,]^,mQ"1+MpGO/ W;9+*=PQEߘLq;hD_drH%ĭ'mI|aqxI>Rysr%^`#"cna=e8Uh%9:FrGW0lS6`*5&Z.{ R٫Jٮf/dF 3Qʿ;\m^։mI?%]TUi T:UK$Y=:I!rP5;Jaq6@`y^R .]Y-N8XE|K Iw{2`]kze%QվT4Gm4+͒sn]$::U.)OPܑb!\10CF@ئ9aܠ7MC5t9%_0 !)+-;`=vӞ~e+89a^)s\oq ŴxDѹI UU2p쎜rɲhj~5CrC3N0)C˳E1kڅk8]LSsBx(K5π+)^o 3vf ھϘ}\wROGݻt!!Fhӗ.I dЯLC 7l;u?HCk tGx]E*h(_%s(/y`_HyZ^0ֆ*%1Y]TsUgS_1.G+/NsmfHK~]X;oOa<=~;9fϹrr*Ў:t25(ѽaj|4&I4]MsIތ\5U SKRG.8oQq!mn4z5VqѬ}]l?P<oz?K_9]%cUŚ 4AzGe ]$昒.&lA=VƆj ;Fu/%pK紳9ɋr2Ԡ&Se B"ځdf͕]f% 5tOW6>\Y~RE"Z34Rn@$d9ʻ0HUs?Cgp%A/I)-beݖ8MglZStRAL&/]\c6U!;Bu)F)&657Izp%ucW6pHyf}~)ndi^1Tk~F2~JpǑLz Ύau sŗdN̴00Q=hs_ʆ>t)[4nq8ohiЃ.e֝@w0 W@*MQEl_>'7kZni0bsM38j%WUS{@ M\teeģ7m՛ duK֏-%&j8 C x !*kT>IUέJvN 0(8K S-v/&AGԿU S;M1/ۢ$&BgX"t)!h7T[[]; [uΗa~gYT Eo/+rDk]G王Cj!<5vfV,HopC0㼠 D̆$YvAEG߿ t?p]fグA0.F>?O忔%!ض 82ep NkZ1{DN/ఠi?LɊMtְK-/jTEG r6P3~S ׷nH4E`ML6lgњb;n"H@]ICj 2r=fA m^I:Ͻ'L%)Y椥\PpZ|l8 6y³&ḵ#X!`ܒXG n?5y/&zѨ9S$QS98`e$Qb [r&ӂ.BՆekx M6jyͩLGւ׋]jt5f U1x+VIo׎-;Mkm'k߄"88IOY<t]6 J>$3/0 -R8993gF%/>L%E7ߌ9KJ&"OzfmgWE|'Xtg5{f͊NIS`6]6onX<9z9kt';oۻ/C'9e{i.'K,r'o7;{{i:?Cl/%Ov^w^ߓPkaڻO{/sz&͏G?. 0SWoN~q+h$3_GxӷwGG?h~ T==y?'G[#BװJ'o_Q6zEr4;5þƔN`i^Sr^_ V &B!_fbB3qrx|#4'ͼ76Mhj{=w/:Zvމ]S4b5%g }uJЩW;X(ϻ'M>Yf:ݗeCoy}fоh#ἵO_u  Ʌ{*1!H#>se8Z>O#`ѡ}ʣ6Ԣ\JThɿAs܄<:I8 dfSȄ,+\y]IDB(S­L'l$GCGm2tX ?0zLj10SS0IbF㚻 +sOxڽ|'vT$=ZfQWT@tXQUm@r10Đl)XO24DQ.Vs9I7hYz%w|}agKJ=z]yT`R `s1VD;$% @ J7iߐsA {~gR A[͒L;IBk@zfx%:f\FahCN__1`a^n{HZ&XY/$˨o{3Ec`r 6xȬRJ){{]@Ftc&^b1R2܅ fKJ12v(+-uӴ) 2lK:;o Am`X73UDWzϸݹ= UQVH{4EaRd@o96)s1Iȹ/ y5æ*]ۺdDnHk/*ط#UzIQk> ZH!nr`|~ry|>kԈݢ͒[t^u޼Fn(YdQ5\c(^W@cF :kecȑ*ΡM:ʪP{Jk~T걷ӝu @5# U/w= wKgwOO_^2v%o,Efx"i PF1 ZfFM.z.j&(}GlD0Za(k9=;jY^Ȧ b eysqyx jC qv'22/[T+3wk2MyS^(OLX!҉ ,?gNvj}p ,0hӊVJJ}9@ Rs=UD4cS_ۈDM,Ny\q݌Q2+*Qh7;'<\s6Lnf~BӪIt(+^FMԕ| 7 (uԙ U/Yaѷ2'l_*ZTqk$USJʰUɫc(EJvädmу [Ҁ8wF)ûQ4ڮ,ºM=x0N.ַ>0Bg,.}Yw-͇%2cVw?nhSHIX@͝CwϤX]їzGHH .ЊJ/VUԲ~<-6PijWN0%oLՆBih@Q{K>HfJxAlK~ ։_s{Ft{:n)'d~meJ`6P teথtTޒ;T]5{k#q~B;ya.Wݑc{ґKKT~:0К,ZsA)!%ltJ E]ʂADxsEVO [m]Ȱwejq!w=`)ԹO^,Xd;^rXݥ@=Қ2S'PZW%#j!WmŅaPe% aƪR@gBLoi':|gR8=$P:T?~SF/{HSKS(`n6ea2*Yj{U%$7>j> `(_Saq.~=؇.yyčQ`Jw9C֍~ ӜR19VsCG*a L9k+ %e<ҁjo3qKN,qCZ4QCdܼL򃘗ZoyBԽ~&0%,,v$"zq^|X7yr0?3lFIPփJO)Tͩ#1zҦ7&& |^pӧg_bK`yD/!S>_҅ZO*\aKo% e_V @r@$L!SFJspŏz,t%&NR:X~)w[>x) 8qHߝ>)qMWυ\wBD@\wڋ1w0#:m嗧x}p +GP E+A$l9HNz 0Z?I)TP^JsHސ4`0r1ponRo:=r^|4 X +S2I²k/IʒK_&k`RЙMT ( RAIh?^ԢcFhE6y|JNAFSlJZ`'8MOf{y,%p2&B[@)dJIۆ*_*Nv^_B̐A}<5&T-ǤG˘|GMyqϲG`?bNƦL!_HlŀWG'Ŵ:=CLxmO⥘_yŋu/%WAS2[$)>v"g`vMLC)&SP{>,(DWӧ"nr]Ѽej:Wr4ܸ?̹ȓB(-B91^%*mR(PE O0I09 ~B & O8G^损'/:o3/C9P<2GK?3!M]*ˡ<2ʳtB,qn !~BP ?$~9'~JJAqB; bxp:tmoR1 NHCt^d&EF.OK210eMK!B1L6X㋠Q&}^X|;^¹dp7cZ vI[5S%r:Ol7$:Nfo M27SgUS{me+~~alS޼F?uH槀k. /\{ +mcٮs)^q rxF%YFH3Y-|$Sn3F&mIp@OWplO^S5[xk΃&/S8j1?Wm]Q *́k8]wC,]bCt$3uQnIs91opS%3W2(!#`B9}Y|s*qDgЙiGV޲~h=YǴ*qtu}e;vN/隔q'㒹.LdW*ޝaT{_|ll?qِG1%PJ W'CfFtn GwA0 .|{DQaĆ#m>MΦ[ =M@m 1ܺ_+M/4d`仓(<"IcP Q3j}Xbû {ybD";ߵ!'MJ2|[E/tx##}l%!y<9` O\y`]< n|*ml#Fǿ-WRZ7%NZħ;rto֖,iTrbOStR$*'}U$ TUTxVjJ6}=XVe|{XMk<K95*mOy6~DC׀l-rFiz"wFB<ˆaHi@1y1}#U3rHKa+H+i$(@)j+NSg,Ԩd} V pB8r.-!ςloJ/b ~|Q9~+WHcER?L㟃x~:RAeпө/'`JiםqQf_s.lAV؃0k؉4AGfHmDϿ=6gm=E}[sb*EFR5L9/yh'GvO]"T\xGsi[.iszIqwDN>7EUףHjH" ? cRD!Σ03 @e*P6-S72G胉 >\B*%YEtMLY0j/"o< %jt=3ye - ^M1z]}0RLh9e>1a]*AX6.fcIm|O+'qNC#cqxF$>: O{ {oTʏ̈́tTu' hG  !hZ h<rIɕRE gǠ@Xb.4+kqnỹF`İDLXd,O+u?Ftͮ~ym0mSҡVD(V@a5.:\ J{JQ FK* ƷzaTu:i؉PG "55(*_xД/\xB8Ɨb0d/^(Ed(!9 /oޣWP$n11g C O%Ifbms0`"yD9!$̟X0`yj[-qGW_H|-݃j [L|/"mև DyER;6*BQ٨HXawpz;;7&ΒMX$l+)mS;fM(g7yt|?%@x1 njs )c' `X"Vώq:bl!+_g<8;9)5OF[ 5v% N( d̹lYg/)Ce--("pEJfY:_KqXGrX EL8}'/l"@ %0ut͜vؤlGEǟ&=.*WJIN9/3>F.7pb2jvb>&Ӑou2Hpl7HC1 &jZ筒)[=6\.F>7R2d:8iQh5zz䯶[^/Nq'(:Gog]նՠAYm[O]o5+WYFv1fx)KIVIof;fu_>3'qnق`[J:Sz0Knj<M0'苑Mh"_ մc*-߻ -Xt҈`Kų{i9ɍ+s%>fc3+=VӦ9E Sv (;aʨ"[/Q0&{BMXaNZtdG#k`Z %5%{xezEL{Ҹkmm:H=N#*zhS;Qg!ξJS7tGvd=& yv{G$ɸd%KZw'k ]Mgv,FPC$s=I%ksBi4w2U@Jf~#i,p_*Qd6Y22=1s|rۊj5K5[eV?.ޜ F9*sS[f7/AQZL[ >׫g]²c5*G{s1iQn@{b&SZrz6=b[ip~u/ڜ}V PΦ56.lDܒP)qX·S∏O<}gQlɓ+*NYe.ʘDOVX?VBNކwbӪTvg-Y'vsE0}pn~Hb]g'g}~'(!gj Eݠev,ireJ/73otג)/i0|r2Wl,GpbS,./t31~᳤(?}ax&?N~="P:` v~Xuql}{}> ݒ$AbqsY*+]BNxxg6PpKBA1qnjz|#` GJU$<ԫ|:fnq*[ S(THա?A[nS@tR c2Y%aj~)[-|!kP`[FoK'Jdi%Vz|$"#|d86%L4+K7\ @R֥I-1"2WDu Y;)9<\ɷm&vnH1FCڴ;l2Tq!67fQSlE:!O&S'5u1k]f.⩦;|rvPq#znJ2A ,j)iA4o<7 QN9p\Q$3+D)ywCRov'dlI07ɟ8EJxTG5 ) 6[?1ߏ1 c61cQmf*>jL&ico|77oǾ3W귌w?c[>~ː3] L|P~6W|3?(bU=n<`IMZ^zK(qń jh2!"SulXdجNBsb &8 ME.R,+"6E2èapUxp\QXH;EGT`shȏ)ڶmy&eEă7߳Ot5c UVjVyV w17%Ykq=<0\@~zer3*,sr:sDɆGW/k`ql0]vL:ljlTq`W`ptrlwDV1 Pd ,#yÞ+C%E7 :պRDd4 kI}g3D"o섖,e 7J dogC&UӨ&aHǾVͦ24;z:O-} ǃa}_/NΎgI+t|tDhJ⇴RGeQUxLFqm,18F ʲͶ.'| 3H&-d-%:cpH6zќ9IGLP39aТe\t1dĨ"Qؽ-Vh{`necb$#2UFuZ=dԹ9(.fD Wovt|x>8q؅]3FپҞI < RZ|j80 A["_~Pth(<.8qP%` ٻr5fؑ㚐"~PeQ G?t`,Eg<AX%S]!w:kBkmA(tX XloSnóǖ(i51ݡN")]VKp}YN 9-s+bֆ]aAEfѫ!JnXz럞UfR@QoMxg7bԼteG<OJw7G>X8W uտw^ +w6Kld136n.E7IAƲ$%׌~wSjW TQ#.9)OZ@+ +vN.bG" $Qe,~Z&֝ CBmb49ԈZXD&Fی) ool:lWqV#[eiF%7\NH)+8=ʦWwE\/;WT: gvj]Y0VYv;x1 .#8>%wzFr`n\ITt5! 8~Iʕ <;#_):(n7DSӭN;@r^^uRFtĢeK K 4if_.˯q0YPvl ӆ9 %7HM~i'UeGF/W~݇&k<HHё'/R@U'Q|d%mPYLs,өep}Mqљ*>;sb W 0#H@X51)Ub鑸H( %>l\qJ͊3+ J5CH~.[(5l֕'0U4I9oͻ?|Oxtk2 F.bm\7dtӧ^kr*i;:uڲț<ʑVT7^b)̬:#/;-e.RBw0?۫v֮_[^'O$~#I7ޙ!o45hs+DŽf㷍{X׶ fcb[@W c(DR;uqyv0ܒ#11h8d]B&?4jHƺjJ1T(rp LnH+ S3vjJK;!e,Fqh Ak0W66R @b<Έsrz`E8 G7+|)l<Y1*#ϛQ#΍x3ԣ/FAz#$F<!1 W88WV|JaQ LŎ@eb&2ΣйS# i 'POC@|צvk4&Jnf4 RExG#ף1u&9itP>'6]5c}J~Tf0)눖\YW&؜,֗4vh6C]ؙ$G)'k%*s 7^;ה~Fw:d{tV)ljEx `jch'wʘ$oV(d4A X}Rsw`>NkN.?B_gGGY+ -?(:/O7fC9$[x]&J6bV%k'85Ǝ7*L\9Jiv'aEsCHSU0h8 :J07hCs.rWiiLVF]㛺Gx+X\ЉjHODjtD[Ms-S\4ZFP 4 CF;X,qu|!@D(x3di-d=rl;X?ig"ZX 3 Fw5Zg%\{qs!;td_/HkM3ƺ"Ff1[allr* X:)4y>FkHM}a=RoHgF{] v{SɉILb`Ebܸ7PIz"()Lѣ`(C?Q !QFd—EK.6cf5 כ rJeIB ^!FBٺ,Q:E 7MpY7iVꓱ2B~uDxo6+hK?] ؗ+*4pir3fO@R]OIJRDLz,-w\&^Ff3= 8k_nܩh:,"CwsqS5gU|_jܳJLcAB<)ntq)-͒~GM_P7Fʦ-Jh䒂AFH̀N8$$IևFhhleiZע0>c/:uZz̬Ƶ2swRym'bKC0NpysGAN09b G_cca\Z%1=kE{ #+|ETɕ%ThA7F(F& y1\Mc@9ʙ$׏_)єEBVdGpQ?g#Ћ|.yJ"E5aﴡUD,{qܜ+G-`_)c4ĶO&I)ATVbׂ8J࿁HuҹK`1-% ]2>M@.;iL%[=ZjP" %oUɟXHy*!^4a% JT߰NL`)<%UAUO2UbQ~e)UqF*9yÒTcEרxjf)+)M + ]'Q !OPcn1o!*~-*&<)U=:KkSe4 FQnGqf?$ qKu@@ǰHMX:R%j)ҳ|H6&!݉> AUi + 9:aVRn6 &F# Cb ^=b|/8!; sK#nqJ($\yx SL91#%`gD_Q83-o!a1ܢE1FtX%yVD9=쵷;c/ETDv1&8C֙xY~ t7PGL|Ã1b@\Hg+^&5UӀ1,|)8#㒬0 /pBsX-+ B(d G]';7]*K^eɒ1@6( VRZVGkP G[BlCM(Bv?{/<H %:tW'5˃n.aVxYE7\Kn\"ٯ> ȏq{SE k4&p"!Da_6O$'QuVl1A8,+R8_,J7 r/S6R)9R6,-5<8@mqf4"n^T\;RdJOMbb~XB7,D\zSIAlvRv"Wda98y.&lzx-kљ)l7]u71M@$#xECy/!_!jyam#yls,^=\ߞR SVFT4W 8 byz_ R뒹 -:QdqfRq~/??@Zi%$3Jb砢}lOF%zX{ ަ V 9+qtmEA~lTU6f7{`~FItnIi*dQ-h>tSIFZވ㕫'Ds@HP*|]u,#wh cΈ`Q"bʄ幀)mڝO<3| `4owA.dzGs@Hݓq8Y]>yMs h@޻]r\ 9 U%kS`?\ԟBxRc2l'"ɄZiQDߒxv!*2Dz[\? Ҿ6P-T3hRn 0z"yM&ʗ&IR8ѩ]xeT=btIQ#0m:X;8?q/~|5PLp [9.&kG1LD7$HQGdaŹ FHvTDx''_q*m8ʀ6MM_|Ǎ>#C+%j QAKܽ.V%waDE1 Kq-<;+'<VeݿO2#cUy )"8pj?: h*#*pmwk5'gj< {ZD>T.*p$Cq1<(xz"U,R[M.nŠ| ;҉zz5CaNF!ݱJoM2C餬ȩRА$#JБ0@߭e鍌&)u~G V1Ud,/ ϨnihEm8q ޷CuNZqV-cmk58xEыox_Tּu֥SLaLp\#2;2gie'=w-(͘)Lo|WnVBA zj&;?tZ Ffꚮ|T-R">^Xɬ~:]Sғ}V/D$O`*NF;ӲZ4;3J{eJ g%@9tɌYMVQ&1t+,]ĭɜnnX*kˍÉ75!2D̗s<&pFqWblg0&#'Gw%[ap3 &ΈT-% )Q&bV*gRa##-EM/ 2'*?!ù4s\df?!N-E%mN7|I2P)snl s~EߪLџ32RGD.)D sxΊc O<7 (z ֎Ub8@;Oj_;4mSU`/ FDGOq. `@#9c|Gg<-T^ O5NDl`Κ}m/i" 8Β*X1ʰ8Htqw7$B~&ƧZgmxV}KpM J%j(ߞu.`ЋO:?mƣM4xqW^q"0,Ã WC(n6;~LTCDëe"zCMr%{@ȓS'vþRMw~m,ʌ B` gQd. ,KpC[)ԡsLgz&2\{,5%wV\UDw W=P)$;{dԅ%CjԠw|c=Ya&=}#&ҕ=}6cM8lIʌv!ʯ5Uo\vz)&c_E=$}UF<֨5vc9P慨)!fgį52_L$F )i. .ǹHו@[q 7nYthlnh9;<,G`' 4M<3b]ib8J8Lo;]]+5V8kJ~)٦A˷o<A$,_ǷxqRQY߁=%JJE2UJeʥR"Wn\$G QPhH{Lqm6q#If-u+5 n2N/B8=Ai?ˤ}t{ܡ" %jX4h:F5d"Ha167EUqQ RqG]?`[ eIyVWnh¯֜xh>'?Q8T[u"|~vga^S@MG`2g#i 㳱}[ȕNBv>=*lUiqph]磛x$9*HfcH1Z/Vmt%-$HC+^{ǖrwSƽGܳkr+5GYʼx X]}unnKf4 Q´mr B=Fm>HH-zŃ$(_R *hd^Ӣ¢ZlO T5i|t1ǖ㒳H" \4&}f7*Wp7Jl^D[5^[R(6OB<AJYlB3[+=yނd3!Ml)苎N}qC=тRqQxlè.ĭhFjb~o?ͥz$`FuX|ʐܣ# 9݀ a~W@HK~ BgM߶lm^KG\-CEg2=xs 7+ va64eOmD1}xT0y'nmq' !L(RR}0 0e(|͌tܣd Zx*7x%îVEgs'6_^nCxg6jۻ9jx]Ӏ͉!PpxV}OÏ"C0 l"Z?6t-y̭l'&Hm-2Ky3'R1e>Yed/Cliዓ_N~E~= !4™x5'c:]\ҙOa3M:]GgJe7F\*n_)'"` 1HP9 /OW*M9<|}K` Y_d oN^FjRMM{Is24*6lUƴfk<8P  "A:䃧7uqmC*z8* ʏ'!+`8LCJ6z(I\69DMn*`9n蟠;4zdIevOeN BA10^ + bҤxD~*s>.G哻-0tԉP ɠ >UxN9~r _jXب|y q{=d: 6juVMzcgY 9z;b~-wz=̣"/g)NHFi7W rN^BH,,Sf?Ǘ ɪ-j0%đpV-%o}U| )6qǰU{^f]v_CI;<1㩓\(Gea5z)IaQb&igIcv!-;|e7 t|>%y(p O 4$\.1l,{୯ĥ\'O(x7) #O߻jy ~7Ƀ\i]uZNɇ48 t ~f\S٣M Y`ъ~[CNd &-hv11P%WEaq%9%O(-4;G xGo, oVx󠞝c8:@`h9+IU:Y Tqu\Al"EOEq֯{*'I~쏼Xy hY(Û+%uf-Z #ڣ2楖i0B;&U_O#DJ~#k/'F,!%O"8  օ /7QZHɔ$1[ʕJ-H 0H4* 98p7?Nŧ-&ǁݛsPw7X &+"s'$w;n=q9!?BY0q0h*_HDŋd**$5үʊ;o+MŤ=~(c$?V$i&+.>8[dңճdE z+#n1H4.n\uԋWh4翇I_]VBݜ$IYEd ӶuWU:,^};ɬTi4(\9}w ݬZ=+q1|\ʺP eVk$(,!B/!47}Ğ}냣W5?QÈ%p(А-Zgs~ߙ?_: dj"2]) ˔xӘXs>CY`.#,hZxS$~ kzkt ȞsF?" r=VzVyD#`w{ϻ@<CF"F8%VtیkȜz9/^&=npOAgl߿W__ tQp`q8\ (fbo&7vc&S-W66'<ϩBjF3|9/j6fofr+l[<1S7m~{IE.0Jf7xN pSNx͞2ogR6:5 5]3"c @DCr,b`sиgh:wx +EܹO|kVV)"'VM2+6R-+e!e.m-L<' ᄢWWxbhCFzעt& ,4YE2J@ݺ"UZ!ty>[w%eah|-Gqpy :KXW+'lq=KKVuefjмm2fNƸDO5-cSE(9{ئt-+ W3~I 6m-g,hU`,V2:ca籥5texս.4/:=Z]E=F'0 &~%7A Qw Dƴ*+`ۤ&lqHzzCL !&Z+!KwsnUp'㯠qsGG 3@(LG6^jۻݸlW@ul!RZ db^i3݃KI-撴Ny<ő;({\))`Ղ.d ãԿ]?[}!z>! CQ*Q$lY'-(G kdoon+0QQj~LÙ.6{B0$BwԀo5Yn}^t2,DUn )IsRk!AG0m67/ZJK:]B$?XINDŚqGc5E kmY? x b1t ŕ;S6L& Ȫ#> P{l/Dw#X=zzzrZTp "7Zw풂k{eZtC[q^#)eQB5X,sߒyqEAktxuA!Gak^-Q[wLD~f;hWOZCTS(D)k굆 tA'2ěݭF3Yu`g!L_B^V3&=چ[ۼ^Z'>@wk"Upkdkڮ SHbNꀇ|зxT|D"=a$Hz:VO{*EDj k5V~l^}y=hvުo?mmom6w:K^nzMA|^kt;fk[nw`pn׷[[~n[zk}pvn[JwyI:옉XbyT9O*)BjڤAGs;@-رQ]\`h[f{˵Pƕ1{a -Jv:7XhdQ9?h/8[)(%~m&_OE/* <@[]Im EYCy6lmvEa(wȢd쭮*v[m˅'UͰWwXF(ӢH:}h0]%oU:sgTj  GjQ[ "&1c׉$Gf >ց{Uxu=Q#r8`\nH2 7m):E|&we>&]qYIla0Jlni&kJ6/6 1=GO`dfܼw $鶨Bʓ ":[qvN3nuڻy߶@ad,+-to)s!G9ҳѴމ$l8aw)f76;zv/PRCeOMz\ND P1"΀ιٌfFt, Pt"Cn2Fo>\~|Esyt suSb8vi<{qa\P`8aJ<`Z9bLuHBtOᒞIE-YWL"%P'kW@~_׾|uoByPT}C:BBP&9! ݠ@oS .PQqC17 ɥ Lу1P?.[]40}6YuّУJ)4&PasXv18ȮZx3C0X?VJM=ɌA\:NBeb{ 6q.xCvo=a ~F~5n7O;Ҫ"nl *[*ᄈ?D6:Z5fcFRJ0Q:=h 8>9Ġ`4[#i{vt`;)@%$. z  : fE099/ Z?tytV CLT/تH/_ֹ<{݃vqx~[[{n?nAoFlVܫۇ躅ܩO(b\ -a1ĀNWНl%&[QJJ^[PQ] X"STfwļ{=UKVgs+pE[4ECVbI<4$nz~GMTY~VTKõ2{e8)h|:+{8CTD%5ÑHE*O <o. Fi +Mr]빪'Vs! Go>DtKz2W!h(a j7@R"{d_aZҴ}-t/r.k1P{$[LL9hr`%ه lX? E8j /&̷i>}Oj?`cډ6Ɔ/_f4ɬiFcR%Ehy/#ཛmYyTU`\?6iT+1fzco%5yh7"Vt*?Vp''S46IfYXFk &W3ӘoӚ[+W~<;O> Ʊ}1?'?vgr1GKD~o[^aM: ZYO&6Kc,BY爼{35q}Ձu~Q?S=qdWGLJ'N4qۍg<jX* I9.!IC£$UHca5eKն>B9*\ž)M1.n1֘lPk8ZCkk9H)P+'6Oxe\,C:H$񨶶?Ydn(31cg7:T1*NIO>vQN¼(l:UTJc Xj)PIuTofYɫX%L"Qrd Pa*Z+\Y[/fr Q~f/nJ$/Q sA /- WU㵣 vDvL#{"*_6:#TEUOE5v"5E),pM7f,׵5ChjKi/:ḌgQrl} SOkL"Utaj$/҈hpxf0hw:2UgÆڙéA*<5L3Y9کKzh{O]҆*",c4D1J:.gL|ūGL9QD%Gzn RG((^cz}]M.V|Zj8c[܄" xp9~ P@hGUN"b`jrIN@rHFC\/`_rZqm}TÀ kj%m{.y^G:rG"MZĎ&7K}7&19UIf0I$0֖8!_U; D5au\L:p}1lc$g%%spNx?Mkb/r9\,#2:Rzk5y"-?D2@ 9&(tjB V 3(5 cy $lerYE*ޡ{Ê.NLȯES V A7+}xuN2芜 Rf\b81}pTq[ܤ .2nLL덴$5iD=ÒBQ?kZKPTpS y!vw4̪.m Բ92D=nQ6Q~6J0qאַə zЍ.d);i]jUDi,z48-'RUj߰_R`1 ZHmbZV7}FKʯF+RҒUh$Pj,h,R% D8b脖5[3rB5/rU7+zVKƂ_QNPnBVN׃Nf9 DG uˡHۤUSV"1Ⱦ!2$S~,LtCנje[/:٪B'Dw6 (ul+@lq:kqlZ.O@ Vs-De"sͪ%aj&Y!*n!"OLHvz/qAH9 6foM5.6s-q5aA36p)rwICi4fym`ҏmucH-QT }X)Ϩɏ[%L"^*l @Rt0Ta **< ̈EϾ&8an's/ ,v/ \ V"2Ӻ$(RSq9[K~SWNdhYq5T o%Y1gQuKo`]hѬ2处qLZ2*Oti>k{e'L d/m~[ M0QEdZB&1Fzu:q PkѓD .)?uMw@^0HtI^/xE \Uܰ?&B Hcy:$NX2;%}!Q}.y-hRy ֓T|"8ߠ޵ DFt op-˞gM羜DyM{ Z$N'-?,ZN-'w8l=qj1ˬZF6AZ)?e{mƑYLүAbpBMֽU2Uyv@f7*2v`HZ`#"Pu]&ϣ'j 谱aFF$6Ozp,W‰p`P:n-!D,ltɥ M:pJV%XQah\ʦpq6šs,%҄\4^᝷Νyx^_&&:Z` 'L`tI/@)I|ѻuҟ''Ǫ;L^J=rW2Υ!2Ȑ@Ȥ$/9ĵ0":c9z3&4߮4"]hb, %!DGɺMߪex1;΂ecnܻ*"e @HaUC+S :H]YN[gxh*hWWE^a+[u+Ln%) ~!>SP^6ʰdfn栦P(<`*8r2=^j:*.-5IpʡD88Ƨsr[7"?l%.6o1cv}":jw\8t8(fn^'pxFPSl𔑷 W,pXHsLpTD fb9 . /Wa8QLN"YYC _Ky?'Ѯ5F[x+son lS ΘJU~<(:|7739=cY,nĽ9|hQe`,GPFP*)gNp,?88'epK8zUu Xjf39Xo%1^f0eNKTDKReNIonum.$=>qiڈ@ NH]U"}}R24/uwb8Y,]!]RҸX,O/&7~c^pfWάyc E5uSR$X\Y~3^Y̻T0`}O2U,c6) GŲ ?,pX68ÒNPvX)X9XY,(9[Xzg5Kg]8vtKl*8c`S Fh1Ԡe-Q,QbOTb#>eŲI pXƾMCY>=Dz`^WQeM\7Ӫ#n}o8_p|?"yYXjqoFA =y0=MT""J$A!;E-ψЅZ Y>.@tP1_Ql:Sh zZbXQnuX1/9,"qTxarGGczG) `VBE~km6TW$(n՘P9`B?"gBt׹7.m:ˮ['6yԍuGh9!J 6Gse]e n1b:VF+GgY@FmYYa*XO FTSʯx 'U;J@(&Bzg澌BML_:u*܆ ސ Gy+3FŪvؐ"}Lǣ`9̑_-f+3BEYapܕY `0rq.'fD,%}vgѝQ&|[{]Me&D#netT.-}~69D'>NoO${T|GMW/8$=L/N_X G-#bX"ĥ`>?%}iwþ6[wNI~Dɩ*řfќ6q)@6N0a zbς[vf?UR&ichYci qQ'kyfOOQ*Re{>  l8»a@3(޹Mn;7B n~c*T-! f]vIz>U:NV|I*X^pԽD2*W]ug-9=>ݩQ~0[G(VD&^RiO"A;Z\j(D~zLRCp"!\} $wE ۟ WL,@jP՞8Te PU0&|:gq ]EO;F0eв|0qc.jsE0fK`̠]-t~//# Y!7@ j tu-+[+Y*:0.#ZE#yTh; 6 v?>5#7p.?wU|ryD/AMQ,0V>؀姪L׳'kkjpsYm4Yķkr~q L47 Wra(>kr3 5}9,!FA,J"1)BN&]{8 bQ>:@HF .2-Xo lSz [lD;:!Ы3M@0Axizrry:̚f@]Ckۋ% kR :┫W99kw "Wh!ot3M2 80p ʥj*BMf;ՅnȢ%2/U?^nV y|4^ `~"}e.3ǁan"vѷ}Ɂ"9(3hjOA͗hD79јGZTF@CVw Q%ѭࡥa3,ƥ^WN'+ ]@T`Xa]LV3#KbC-aǎf(^)D p5%{! !f{4kBqZ$Xpi6Dv28([<eF@b@$ JKͫ͸<ʪ P8Y,ZQ@$Ό>}D">DiYDtPr%y MZ16OYy|:?tzAv=&x@S`x;"v|ԀI(5Z\gE,ɕS<4M(_ cjb 1O:L(r_2 Jm2 ﮺E_ZL,_" #%|/?H38a #XA5F|!JR *K'WB _Kɀž w%^j|b'M4@-"a79$bR2; *7Tpr%ѩ1)ޅjK2Yfu>Z[BI^SJ'KJݫh\kju=]7_V+K_l"CC"] ;( jk;㖂`-tRBfE11`x ڡJuY+L;H(qnPBS¨3g2bϗ\%R FLp(su6"`oDh~[]s{y4HLwZ㹱M.HXad($MjY%#"&j9\l?Y e88B8aI9?eqêBf$|60V* w-4Gԥ,4 Fw suh#M*1v/$@Bng/OҒB׏xX/뱝3$as#pȌ:U6{ 7KHrzIҡ$ON=`Xy pم> ZuIyİAU# ΉzrDcvCBI$iIbh\?<: ч-c2eד؄\c{>e+Ip-n9i`WPq+f A?$&$c|aXH4@d tdX >.#Τ ;4KZG#2sqt",ѸNȀqSPR%(e%JV<;C&NA1ak?{*.:3T~*;l()ˁܨnqKI'[9H0e܈=K{n44Y(Ǖ%98G4#I.6z=igJ>ߜOá1;䪋{XKN,nE@%28Bُa W0e:/4DeD/&4%b*:q1'EV^dkKy.ӧELU*HLdPB ^v)MbS3Cn2tUY[ƠDKF2W⫬R9 )w($mX+ PoAM砦P{ [XBPeDrshvAyJ7d1 Th ~Jx[ShpVjJJNɨz! x5uRyo[XĂkvnc{8#r{UƟPU]UeGwYe2œYa7&O=Y2;sq8P2xdjwY_ o+!WcB ;ԃ*󐳼 ? HL謴[+'7qiΗ(&+)k,Ճ%,fѮַBCxb(/Ƞ6 WR1:JQME`V#X7 ( uQ$ dOX# Lw+(NXф X~xuܭ45?tCKVܮoqs`^&]YD?-ы~W7UX]u˞fwQ*93YW5 ߋ;T]^Wn Q<@[ rb1GjTƵi%DD󴥖I}J ]K#l&eeVzL.Hie2-L_[mL;Yf.GjOlI~xt! }-oe&3Vׯ^%u) ~}Kӓ_ HTLFR!ԉ433?7 voohqUy-rFD{iT+7[6MJ!w{R*wh領SvjeumxRiU^>a[; exRmU^>av=1)ʉYVyǮlϪʻF彦^3U91%S*7u[4m= ͞Fm-ݲa֮6IlpV3l*;_ȸϧotmwxh$+hw1)žc/$qc+mă/s@ixH; iM EeIBw喇$=@$6WjzQj4LVa2>np wǀ7j1\}y=n_ 7n}n2xmBDc]0$EaMv3:2;#$*lIMag4֎QU1w lw=v+ʱ1*ު=^*cFu`nUo C|?^bG\{/wXTڍ\׉Á ט$Z]lDSS6So&\Hm 4MM@;DmfXlh/ lf7v:Ȱ)Md6 (Wmͽ&{16 ,֨6wFZ=9mvPUv҆'lmUvppM@jkok'm{r&^Mnn6 ,֨wviÍߓf7ZUwiÍߓf6Ŷ[fppM@vJnn6 ,Wn7i ߷f7`1ߪ7SbTsQm\̗CC!ct ܍%`y>ECӰ̭cU)Vh? f <2CG[-7a ?kzg4s1wSs;o%S%ܬį"7,v7 CQ~=xUǼ,)¨[x &?LU܁:>-1uP$`Iבĝ!~fy3X<G|[t)bx&2hz: 2n' -ah/Z:{C׽yV"QVEqBq+5a>}j iX|2+X~Rk !}(%7{St|oi[FY^C$OJn˶9 W*$]ze->^יz3꨿#%9iJR_V${W.xב2ԋR~XmCy['-ZQ$taXG#W`x(,I<66aLðư~ˍa2 HЃֿm7bh"ݧ򐶅}3a~5j&y/ hb!KA;U1T_:Ə*DYVUY,S91fs&+].R֮==t" uO_g6MȬziC1]>;q+:35+~>}HߩWv>Զ/| 2(n~ ~W£kȐ }V] gqPyCFT1=wLha<23"QU'u7dyH AULǛ^hB!]ؗ/jFDl2.Y(<1V" ` ժHQTD4fvcRNj6Z2,gyɣ$"Z*$NbF3e;-+)RP Y3j3S c+I wb&xxn;㬗4(Y> :]>bV,RxXΔS%fnQ¿aQ|ȉlw8*˷vwQ$ 3~|0w0Ü3F{T, )9eFӍD%k 6ݫD^) /i</b"–gJYuAfaXa3\)c E-p!exor&nfV]T:Q28}l֚ YA"#$tQ 'zEx=m k^؎\͔0 1}lPƑfnobh(f|:炀p oߑSXl~Xb6{]EȵAv!B ?6RJ,W`rKQѳ9\R`g Ra.%a0eLcI4x}%_{󱘜xq+Fl+{3<mܳ_:trW( >!Rr >i3C]ҥ "kb{NO!L4UTQUtl1Y~H%1 (d=~&¿%l̮є>|xr{vaC0+fz/Q$a= n%րb׿Kג?,@:R={Zu>gl*XOU{cK+JoIjpc]3Vu{!>MD.)*Z圤H-bCY$)*NxIX^"Xĉ#3QQjD/0zOeĆÂU/R(ߕ:):ebSp1=hQ :YM^YkҜ0UL"Sw*S@JU˅ v. QH*cO2jkQ\6;L[:Od"fI*B_xuU＀U? /g*ҿr,j"1Rj5;[2牒tĚx奧LP;PVj'OLYڊmyKA,~;>[q ҆-gcn,;8{K;0Ú O3{2 Y@+ Gչb 菚/g`Mmn?h.R5 9M&&PNR,5bQ!}Mv)661 >Es.ٞ4y(I>|DpIu 's!7ӤacV :, f| 0ߢa6Y| d>ɽ|&P1}5i$ZbʱEe(ںECX=yr F.*[QraouF ҜmK-zbҮlyULeãGxE>#q~X q0W* m^AӛF(5|^]71%lU2v?Esl0纵j&WE$uY+`? "}2﵂uct`(7Lo`if AȜo}dWdN/.<,!c^0ɋHd!-oO/+gLYgf|% ,Hߝo3SX6Ydcutaɤ?;!L6g<_TY.NǏ!!tǸ㹳)1 Lfj0Zنdz@aQLeԞ}*KNb͸"ot sRqV{U;&5USh T5 LC'u0{'!EֳZ "Nq Kw^*txt|4x?ZF!Ag9:=.*d7m:~Q{B;.č2Phxͽ`1|P3o}pnϻɢd(qFI!tQmN-Ӳ&|(zEH4WT>U xGB ۪%J78۬{-V"Yك0̪qD:t{9eGwXWO=P)?䚃NHߴ=M;:>?:پ-(>?hK듃__:Hi6aD`=kJsg{'B˪n8Yw)2EFG}FE]Cܚxjh3)dK ?'V^v&R He+4 O)]9-2|' B.yTj<~%Dj?Ws>?&_"<ˑGAPSb6]h<1[r=6_ 7gd+ow^(bLv>l5~k{KUo<ŃȂ6xȸ76l4lh6j0nayuCGl$~7W7YCA;+o 8ѣC&b6oN ]LikTb6 X&vm@_?ld#Ήs5_|ksĈz=xYup  -TЮMV N]́uaBMn `=( {; L4s\K nυlаLE\[@s@{B60- ,hPs~x5 mh..gsAmCM!rE j%8`Ix T`HPDFZ߆ W=Y:T d|rVВtu-~#O/2C= [rV?4dݻ͖o.hPv xn>gB5m"HIڴy`ܴ̃i -ki}<)nY kOzM4$L }$O j4ȱlL n4=͜gq,RA4K=p=se :;A:@ מr)ӎ=N}':h@O3)' :dYP}եt^NiMYa3&7T$ɇrp'F;{7'H,>z&wT͇rp'`?4Lӛgbh0&LtO y}dML$Xʉtt 95LȞ617`sc;'i;G;;4iG;=4}P0G.:@0SwV#C{^.`gơG)zf:Pcϊn.`ān6#+sL*!؅sv w*4R JAtTc?@bfӷo{sw VLxv{ FU ת&`fy L7) wH3H*o{ٮmM.v¦t;z:lqym.ַb=9ʀ89p8t3\/*kxo-?z)ޒnV7x2,nIgTs rNToϞfE㯽ݽBN{.y1NŹ{"GtjS@?#=99C^o,[>);mzI<͸*OO6̙\=]VxH#9cNiSԚnPhkZQg=+I^ gog{,,VgR}ekjR+@Ͻr e\n%H:?lt@}o/'" ͼ<5'm7H``` غ8Kc&ipߩ}G暽.G z,P7P!׆j=dj?dڲfoaH8=$Lu`Dpm^|n^ #ɿXowNQ6YIi:?$[Bʃ0HϹi+wD6 iAnHH݇@JzkUWI1{13tZ_Scj{`{*ڭ.xo4р>3JQ2;NC>MݓFs' $xZO]ta@=gc=Pڴ1@B-su˞H ˅l 9l=;vc9'R.2UrD߃D\> 7G?r-2+訣JQ J {e-= &sjSu?A_hT.Dͥvd]R^t_/GQ,Fr`~x.nN5 ĩe.o6P0__vkgfgvo|CО_X̃-*'0r n@Niyǒ w\xtsi&sHo+Lq$gE>[pnVkݚd$ ۶ w-gs Qb Ȳ+ӧvnsxcڻO*ޮ){'{'pwMw7S=kqI5sh[ٸk\?dzn%"IIY43q|T wC0k`8e ⾘L]7j.q/—jVCVkJGG/{"x{_~;1LZ8kwwfKS0j\,꽶=%dJDzƌ9tI#Z`4L.0_44,( , $Up4|dIIn^ qa0:87s\`ܻk[.0iԑ#rPx/2 qK.\v)^8> %ئ>}T ǰv=d: hZ,Vf$ m.>L6gET|[T 8֨7ͥpEaGo]ސLEɫY$.h"u8#Be</@l!`*rx]'Oh~Delb b9fj\ji͂p͓SF,SNt:wkzEf/ި(*n`(N#cjN8REsq1 5XnXΩ aZ3;54,5wMCllm70'$m%Ȧf$uT 35uR<}p Ӥ5UUK'E\)jjQ4~riF4܅cuieӁL"\¦k!prV.NN$ i tP4x)ε8\snhPN]2(V:QR8Oimn4ha|saO\8:@ 5$c@lɺ eҎOӺc=цOk׿&ɷej:^ew8e忾%k@7wdr HڥtRo.h@vYci@Ҽҷ- Hs1熥ynL5t k9/qzɈ1@d) lit=L K/Cda|~bS{:8w7 ,Wg3g+yYXN={0|x>p< :o-%? Dž0j}|$x s߇'EӏgAL*O3:qċgh ԅ4Ӷ4JK`kd2p2ٱgr{K-`Ia2e ЅKW8ug' 'ƔL񄘲GP4\p\ʋ4L?Cp<Nt8y+82 Y}/ 8eRv5E~)÷g"k5\:)`L`MS!sQP2=Cu,|/6 ;P' l{gPp.VbU,f ?9y}k4\P1ʹ&ΰw|6S7RH*1[6D- >z4iI`621;>֭d2 7=R t-"GD [-dSgPO/5x{ Le]A/2ӟN^ _wr]߱ {ueի>k){kBҖ2;5TϱAC]gC弬S;@ wPuu37O6/@w~ֵ|b[;”پsakw. % s҈aT{14.tjy'|kYѰ!1l:΢G:Fۆ zd <V^oxLО |J¢ q1u"p[],"h7\1ܫ3ñfu$rsf$o:hH' ;pn&I!y8E47$u+ Uj~d `)`ؚ`v`Q75fcCI]zl.邕$[j8C|&w녚P2D2nuc$&y.E9f,$ҌRfA?Nh2&\2A{CktWU5Hi{vtr<<:><z*CXkk| 8З 'h.nfd>pem-93ްl]<@Nh@g@&V[]b2SU|FZtwWe!ɦTxYٜ79+Y"! @dREjg._Y|2\,gngQEEcc+ : ~yX~y;V4T@PP~ ?;z9F/mC:sZ 'AptU<8eZHJeyDogcb uCxJ| C3 :g-b?:53 wciEws1\8΍9M{}_.g =bd-an {/:??~⾬՗=Dn ûA|M78ޗn8{q۷ o<; o2 m~?>$~p/ڼ'^-ĞKc!9t $|-{?·=뿂[D_ًaW_q_ԃ8eNfȲx W`6 )Tح]F)C0O$AٜNT:80Z-7b3;D9bSšu`tg g@O-Gf=bOX2>#o„>O7;mnvyc^͖}4_- CQ1}.MGTI55M : U꿫 p4~6,TB`4) ZMJk̮-Js5% 46fh4Ĵ%= (uܨDqS:;zW9kcrަ(\2 A(*nm<9CE^՚Qۿh6ч΁2І.X3wz-Z4Zj15Bhr9 V7pLqHe9:iF%#Nik1e{T-^Xl oW ^7:ƈFd%Y>qPĪ>zY"(Q|LIIFW0) cҿX=:g"!`: *c,WixY8gqKd.FO|>aF'ysDaw nL;3w,S۵nd|ɡjIu\+GM^*G<8 mFmti.?KhY"}jم}{.A|lnv엾W'CǑI95PPޣ1*pxt?se+߇Zц)[ j7G] *E_\cˊ&/x}15ajl2D$P*֮t(頡j g ёCё9evMl@VWbdTNO,lb* v-t.tN{q#?YQ#ۍ)m 7w ,A?5+BT2e2\ѯwѢHG]i\KX+oJ9gf'h} zsizol'*wY c*{Vz1l`/xCuo.7zYPq?_\5\讈=?Vȇɐ [ džs39*s&vOr8Fɂ6IAOaH~{rQDT X?+e۠5`*,]X)3է k!&xF2؄Hc ϲap lKaؓhiSrvySbtCAFk<~5Xd&NhhDV(plEqR#xzxM-~j^x7>Wʞ!K 4T4j e^fob3+6Pf2on`m2uTkμgn\4 (|\6[C^UѽI=(t8-&} /mh A%7gqڧ IG'QPp5" 5vMrPfaocfƺ=]bv NC=59)Hس#O~ic*|kSXǀ$\,l53VhкXLP[ o'*%K.-Z&(|̍r)CT`6iF:.MP \xKzI*A.\7_a>͗QsXic7x h}I"\BQ'YÖ00S!Cs1:^ؒMͦo 5P@AC,YRmWڦΎ][&t9 +ۉ#K||{o>tUM] җ5; çZgFc=y럳?OB$upе='W\mm7\C:("ZurA"gHD==UUrN9Iaj:N97ͣT[R-=fV}C_bI)p8 :,__T8ppvi|5)V% h5YYPK _>̯+;!ՠR"^>éUm~䀒wB.oLAoc6nH88}ԻMB(ZT.PpZaOT$`QW\ a-Ѓf$2{S M:I!Go)?z]{*}}ƤF˜T%y\l6Z=K=t=֤4Fb9lFksڻbwH0QaK w<V:&7eyv:Gt| +-N Z!,x? >i=+p5w1[S6)N>עܪ& @rhƋuu8Jt3qϫ) @>jۭp>%_Z#bD~&c>l|b`ei92R:\U '֑@|c}D8*:;KᲊQf=)N dF: oWl8LW-;NtW 9'ZGxX'Pv?:{m@ aŃ+VTӼbn.Np%JinhqeR6Amp]0Oa{j/K||Ï#K ѿ˨㻢+b^L+(,t״u om؊Gf&xs.~Ѻ^cxH`ܻ$SēAT|GOѴSɱ ~}LD OqCuRTV-T&Jcl^xmq-.E$`e rk3,$BS _,,=h!EJoEzXܼ/ëղF^ޢAMx–7˽@dWN"Yݵ}XF2NJB),u]z߱sڳUB@N>uj|h=­ gJeZ'+` V[w|۪U}=NĊ9Vc \n'KF8ɽj(>%&V'-dڒUtQYd.ID1Zϙ 排jn$&ס2q,ɰȝ-H9A! jRLk28o &j4ANW21 |WyTiIB+C2M./x+PN#x}km|6목{zE'e.zX"Pwebcuk=ǻJ=?O[Χ?PꖡL\4(D%q'LvOd'oc\H(ld$eIkAv>ޱlO⍫Ӓ?ӊ? '>h2)tm`s^\xʵB:^.O#it~ "i㤕`:cqXcDfaDrn6Fx6?W9]=H ٣} գG0  ֱ2̄!)WRX9mDv,F+%Y0-:< ,^83%*i^wr/2B u+6(qT;A,8/kAr2`l y uOF~f_ro\za 6'@ϓP p×'rR.O\4Ԫ`LYv]O&b28r-}}ff (@AD-d .A >#Q5)EjLJU +\@"|A_(ikv@Z:+\KhIB> gdLKd4n9HP"֧iR f'r4MGEtC P0P?85o}kT/*| 3 ^l LߐL,|q6j\Y|N1mF5)d-\.7r#mFeۼ!?R ;v`":%b0Zg"<":r{H7 Mfɘ{I2EPosvKrh"΁H$°.ygxf˫?X߷AXDK iᜌY, Wgڲר 4 =vxy]ZWAH+n8Krb53UYIkUj<lk!?nu-\>9At$⋦Txaēқ#gs5$U[Ow)-^y"76{<uS#G}~n;ӹ':m-@'uY;Exig["f3JW1 :0S)yJ={kV(qŒJWHT;y1zN95'~z3o<z !Ӽ2zg]'u,s_s(N@g:bEj|k{ݿ7+5I'vqywH:%$er=^M:rsC:?Ln>%'?R?գGY>s珌&R?rv:[lyV'+NUR4a%rb8ȍa{|AB>fZ0=27n'c>VI],=iwȲW9M;=`2`21 .^&%V$LKꥪk몣-ahL$J α^fGz<vD[:H4ۈة4yXnv4w#R]%`RxqOF:wV0F*t4Q=-(&A [6Ls;<[Kl /`q@{W @>W^ҘơV qo42 1ṯK4#12ֈ]&gƩ-59,RӺDMHnq֐-5ؾĵS夶Q%۝%ωbEhGKW#lHbA ko3ՋT/1d|bio^Źϋv^p_ާߖXmcje[ c)J<Ȳp6#I{hP:=qk*ՊL0Qh s]ÛBS *9@ Y wUWcS niZ͠'hL[+EɏBd{Aç%[Їq}|CCN+rFB:"SƠ߷Y8B @PLJ ӏ2\2H `CwC1`7@QWD"2̉5.Zeod{6}S`tr ?4@utR NqF)cvMx!:)q Ctƹn&,6>'I|1H'6pl"(sVBXzCK8PP/ n~~s![6łṲJ8n;ا g-u s;b*FKOTgyN0߁_?}a89E0@(ܤqvO⩣P!h#{3AF2Eԓ ?˿>d{aQxه]vv#$G߳O6&:GZJA[z$^w2!pS^ >68֩ԷZ;zmwtvahPm1<WJy+̈́!ǽ"l{xk U:v"RA"&F2kبG ZIu%^] 7-ߥV׊xjF tGk=2[]]}GQn_KN EsaGE 8Tݺ%J:û}^}w9VoÝUԶkso@ap5[*uxcսM[7Rf +"YoHq"~ GbLDNVfWA{ӂItaBkWjĸb.˰E@EY3Til\j9Hj3`8*EeGp \f Xks_3:wmqFyK7zM!H*'p)o+ ]KUkrl:ЬClEvR_RMښzSY+e]" S8Ɯ#SC}} 2jnm 9TQ+1aWўͱW/ W^TbGA %v" iIlpC;++ôެKՓoD^uigTbGצ]qE|4{JKYM"⦣nj{[ jdf?;.dSP")"S84-kp^<NC 8U 'ORJw}7EJP:sG)=$l S Dxevm нͅd9 ;tNU~$R~!!?, C{"\|s,mѿYGk zo[xw.N^ *>JWAAEȷA i3*\2M3qx~jBT{%!՛MQ`UR SnxuE8 Cn'k[XS*_!is[V:Q Q@wgFj1sÝ uWj}U*?]>XG^P V Ri5mi @Qʀ!>^ov`R%k8va?]|9Ea=yY I$ONjG|@UB/z^{C|ϠoqhNF֨otf~j)bO-WJkRAWx `4Jc,2Ae]Bg v:RMv|luNFɼ_wKRNzK Zc뼴oQ$b+,XN<ϡsfjoufh 2ATUn~Υ7m2(9*YA> vymʾ78 4ZƟ;G8:i@JDX|/n_4[7 \䤕 G*|Û  r#?x6I\z$]#,ϰʿp`ZS؄(E6Au<}UE YłZdh3LUy`xq{SQ %e+A Ӱ 0cX3G<{:zeČpOST"-Sy*`?9Gl]бMe_aat {vWWsw%E1 r`vF&CSLuTXe+v!~pˆĹ"g%:U{BSZU잉_q)-I=1a<uuXs5p'<{V_H[L¾=).0-uկāJ+I^xWD~M5)xN>m 4N'zIS$ q%nj]mdzy؟`eyq")8stx`nM5f\);FHabF/mPszN3 @Kz3Ղ!x0dgҰuUuR{mt-Z~ʤJ1^3VMuՕv0bF3x$&fWAQ}ta!_@E_6%x0斗0 3>Vu}ど7&au }qy*cyRV rY?j`P/~2?HYLʐoqHKuZ$q;0W[A`ıʰ B*ia-k]jt`y> )4OP2fz!/IdQX /mX:MA6\̈́Ҿkl ɺ+K!Qw|4<)2qM3Ϊ?󑅇 %ٸD K?Zxn꠨MI PL: I~Jc e8Ma6Xfc}oa)DH/#a4RņsQpYF#݁ 9x rpIYD;^N0urL% ,iu1p_&w,L}J쨙qHOUVaFZ+a N(vl<|݅؍i7vLk6Gn:<ڬ5{U( Y^.jr+(jCYQr8{cp1~(f2 =1p|F/O 0*e%TXWޟ({@ -t7؝LB>:^$v: S[_XEl԰R1 &uG]m'RLX˳Dn@{Ny-9Uа)찈섾q;9s/2&2LfkѐN _{R`ޔh*s/|XV .k݆" #^tU־;GW:M9K/Qv P.KnSLY"HC}EQd'爻I;%ٓU(Yo5aNqpPvUXn إ%Y%ZUeeŖe dVSTDH}߄/I4O$ KPB B^/wg__Wᦙ)Čnͧ v\7{'~<Ԣ ,sZ= g8y&[җo<%ȮJ7"::/X,O%<\P`A)mS0+ ^ @*Ux]n|t>v6qhi#t`~CLfd`IgTBФ$`E™7eFj5#ǚp"P/Eڮ Ү(S}4SZ.RƒtGd6ɥ|4%EK:G~R8~O*8^s+HS;Bh"jeGUmM)ny%;QȖjr7l/6A^NFc()= ,=.>P_[_X$*{E#]{HG:at僒irCgʱFQYw;ibMHϘpg6)}Qʔ S5xA9:i ë--,+9 NGvy'VѦ"!@5@@2Jg.Oѷf{8B=gqs"Ϻ]-H֯_f[42J HvXh)y XsP r`<{m$I8W-W- -01m>@ۣ!P0*ecsƀϭ)O֐sQã|!iLKjZzS{LmMX2@-6Q&ـQT$x1LQ$13nsf`|:*lmI$K,ʂ$ml;) ;> LVsA7n0є8&dnE^s#ی/=KVJKD?GB1?,!^y>饄:)W n$\RYߟRƟ%".^cxx{ɱdXqCKn70k?iUD-#1\bKs'/|+ٜ6DCsraAc t#ovgrZ Bh)ZtaEZ*)7`WvROq 7#3uW I%NyMs|'KI -RJ$ܛ7F-!Ui1'xwfulmHeNTE66:rS#hzm"FHM̀N9?j$c`9k}^{8u\Ot_v{@Ww1no][p<ЭTx6-x?-s, z4PZͧO{J&t:=CShR>gwbW 'Z@I0;5a̵p!-#Z +ĠVDdP5z*wPٓ>$s遣}h-zh=pw:qe{pzѦF:7Ydsϩi5]c+xxޝҕze}}7JL,;[N R p룣+Z[XQ3!HaWR7AK/nzN NsDLy՜;MV8rF0*͈2ɰVdJ[`1kO0֧ɋO?寍Myл ЁhǒyB%E8t/&{?晽&MX~s 7~,Lx^<"F5kqwQhڤQ2L.\E'cFS2Mσ=/F=u1aRTcU']knj;9CMɝ~Č}#|m@Q 4 ~$j.j/pwC}ȼq؃NiSC"X7lW0짒{&9іTN2֒0 '8rpcG 5<>1ΏI1rv+LTL@,> } d8S 8o#u}[wgw`K h_+H])=ŜX@^,iԅ9g0JS@$fOmL\gyI twy9K!Ҳ=U;+^6ч3C.stZ!,hRlƹeO%sYH qJBDt#i# 4Vp fS؂\4Nʭm J 0L$Ehyx1,4EF;qPfMI3OC k/V$&#*>JTi[.,li}Fϧt0>&i`^sgVOmhB%{|la:=IVsDr{&>"Kz.uKC2=%3d7DՓ:RGQ2BqPC[^sV_5HN[v/ʆ<&I Dy|C̣ft:A6Ig$ 9r#}6#9>D Hnp4DdjrNd_o'C>C>~1?&o$a2O,sr`ɼ޹;f30|-661l7kO^5L6L@𲍤0[/[sXo"-ytz{s+W3`' /a@$*li#q`В2&m5,9cDet=TU&sd** -x62JXn3^3OI6j)_fhJѐ.;2*'ċ`\e1r}Qs|V\%7^T3je93 /-:w Fh9}j?v`#eee[F`k^͋8I ki%ǮHV2[>eǓȎtM9"sO,7JceyϢ\W8y>1_Ђ.*Frm0~۶-mҶ-A~0ncq[1nw68K1Z힍 jK>kv), ZҳBUCF 6 Csކ^-FRPt^}M87Beatƭ7P{0uKCnpou+ۊײmb澆]Fnx}hx>[oefs.mմzyI|[.HWn 6.U_݄1o[ؖڮ%[zlK9Ic=Dm%s!-cj`N1PF~)#,Ѵ1w72Wmt+-`y vŒ}bj{Y^}~ղ1c 2 < K ř.M|=O+[$ 2 8D1 ӛJѤ.yH &ND4yBUBU0uc7r`f ;J񞣩q{ĈzbE8Gycd+jDuGvEnG:.x= gǬ/-8?'; ;^0ΐaP 0,JDeu ~H`K=o0{jP[Y V νI ~o<[[6kM[!4a235OwgQwSl?_!&2;dQ/#-&=d=zG0b}Vi0U@Au0 #{]aݽH;|zpvJgP<0v#?hh3 NO;+O !;UW2wsf;gcX) *h]^'[ `'S$b@8'⫫ͨTX$mԯz?[ )~*̟Dmpv/U>vFfעťf =3x7 4bov~父(+P ݎ|Okr<\╖^ϖo60/Hm` Sњ3H1*R4/c_wA$9zaKԚ$]TZ׃"5C$>hokY9 =IKkuc_;ݷo:G]=mϥ7Nni0x|fo<.: ۾?iV;Iת֥ J4|yGRETRB驘wpj]~\GǬ~&MX5R6͸?OW(eNڵH ijӰsz0-i]23^Y݈B.k 6>| Zlx֊]u: ^A֦a7c`^Pl ;WFbNy Y`\>,]㌴ ^z矟*ЇV&Jp% Bl~f;9@t`n2ԌkNpaS?+&d7QH ) a(#$L =4E3MJ1!_3Q>lwD~nw36oHqZ9;k6$)76 NϦt]h"F_kA%Zw,TZ[H3xϡ-.3XPe?,QAj$8?^mH$_xrވ> & jrEx[.E)!X9-hSd$*Q%nfefix]ki}jSx^H/bR6> yƴ eQl|RnBKRq);f/Τ䲸Kد.JB$/6O!p>@y8KY<}()W!ӥR1I v9;Dy\ZHCN)X%o:>T)ra5ݬkQl|De,0$_П#0T>7_|N]@J bA&ݩP~cn;N _#kjBֽz{!@&"e[Ӿ&;F %&RdݖInՔrm)DCN_4rG^›ɿ:'&TU$P92_F:^ FuS5Wt qH5DL7ۮG]'qױv3YDnc; vرrmxT%s//i΀04!ДJKIE87|̛DT."]~Ԕ=d O^n8`Lv-RT7tI/y`OcxQ砻ajxot[xcX:}9c'g6g4oiюNN |wIscn p{k" !E%͌no0·j"$d&MJ7 o=}K1zOIz>2^5W?ڒJ#tåmͺO4̊1t+rV&sLx{̊67bhZ5Ďf1sR+jXlYt~ s%i.zǛ>u#w1dQ]ȉ#7[\,͸9gF1suyتd!YSs0s$V;{Л37%xxG#xCFM&qP`Jʕ/evKEYe4dV_:D;S肭Tu$+*)]mGΏ ` H(M*\t k{NX5< H{%׉E cY0Bp4 ^}4OS2`"z8  '%v%jy*[uD]gώ `qJFc5t[Pʨn`^\;C]\2,rLӯk{qB7/ҜSq \GC>ْ(9DR>pLƧoueMq fU˗Q y`Do{x6핕S4;2_]+k0T \9W^\ M}>k2ŸY DF%)2ob^%ԲiY\wֆۅs;[ vo$aJsD0dYBFl\aRtd:pkImY2|4M] PivY&TXUk',Z.\ JEr*5^}ueӷO*6kAyдIhOJK 7M90&A,.|$E?!vms;֓=/)Ufυ-mݷzqTZ=E%~*Ɵ# GEᓗ:M"V$!*T1EvKZ<;)6J! l6H=b~[+2 /TF)_Va狕))'ٹjuFT"_9Qq)g6lhm$FL.Mѥ'H̄X\Bo2رbo3'1Ov_ 21,/>Y9iEr+8soUJLCl '$ׅ33iaFr]U޾13q9Ǎ.E ӅT> {=IK'bY#Kܘ1 sGޏzr<iǜ)HrkR$F"FQ Z#HǴ[ ;2䄐ϒ^zmF쥀r}Lję#SΩ`/t'0YGLh!?.buTv [$nYIF!t̥gg|W׳;PױуaF723KW9i] {RU{ؘєp<QhZyyNjNmUjUX(ũ-ߑbo.-ۏr;r45rLyVے6%束,Gvvy+5>"FC̬))0`g}K_t!N~+&ҸP01!v"v빧-1%##RfR^4m"=zW!Lx<Ĵ#A+ K^-0wD%4yM->Z4$uhG##fɢ]I y-j0cő(hz]2wFuazh:@F S2؉{9 gCUd*ť9 ك7װK6|fկ6D%;@hV.;QD&nn`+Sh"W(U *r1n22gQtݲs`]-UbĪp2$*ꑄlzeO@XFFZt5n)CC\6E aY0溌cL*I  fwE)"oFRNVf,G+=`Kϙ) 뫑۵ ZչNH;24pwwA5A'ΘT TJVKB }yqҡJg9l{k4WV"Qo$ ,A=lf6'JKKvlkb)a$}tpSDIWʥ6-QA[|dVHPZrjM'U,"w#ęA\,{,i߻5K<,^"@ y<$f@KQZZ1|#U~LjZ#e.E4o?.-8eV f3(v'"3zWtסc.[|-ao!( WFsz&K7e.)7JyC!B |KɯAu[$nK` fm$ ~ G{YpwEQnJjXcÔL7>GĆ'[;gKJ·8\3O-<8K!*hF .Q"qƑVr1<4)co<M!%}'9/smFbۈ_K-bʔho.e; 7(aH4rM H9`<>7W%ı"{9h0οt_WMl]tc[Vm^ZupqTwd\P^2bNT{]k4x<O;#%Kyf<'MJ`Q5 ? PLvGx(5 j (+ >92Y(ʼnm^>ÎofD7 4xu."6dY?O/P I9n23fc(f͊ з 5XH b- '*JA[5G9̜r c19=,u0k4 2} +2oܷ۔xRNTmmND SLysReV|>Ч@=G)#hM8f"D@xytHBqWV\KgԻh9Ś[.r(3cFPyt}1j`;`iڤ$q10MNɿEL:Z[F6Q ͛_#{yDk'q@̩S.ǣ t)r$٬EMA 0[HRV@W!oVӄU_VDHF2- UJyN)4,D:.3bi[ED7s6Zؐ}}C"yIMr>Py}{Zb}JmГB vL7gƖG#E Lkҩ" &i5KS& " g']$YDgt%OGrź*26:α: qcRՎ (Y9U@2eyڢZ'ɫUATjwq?|;f}Ua(n6Afi38zqNΰ._؄٭:#7<| 8ofQBLqE$vh͞zWSyy(E2}900Y,(<ҋ;?nE~OB)q-+T,.E#(y {VL8jK}Hӝ--0ᒄv3Ԗb71o˻wk4KVSzN %\a>AX68S*R00h9FOOP"vEpnfFi^͈te&-͍ %*C`<0iw6 Hج PnfтYIց&'=Z}-:볨N*mRV#FI)ZR%cAkb:֖f@|FCwx5iL߭XǑ!X`njF"fp1(bs%2IǝY>+i>11ɘBVktpD1jRKt(M`eH+nh$Ky;#CiKWTkGOZ¯꼽aY\VJAId%Pn'jUzx*ǫm`C& , Ci1ld :Y Qb a)ݴ;rDq8wݞZ.v18lҫƷ|jؖOnxp\BL~ 1t:F(Lñ\Q^(l'<;vioLi2+LE(ђH*Z31ϒc"=I֓6JSD,HYvL(yθdh "dEXCS֍DJ$PP*$fQx Uݣ^>LEߣkV3C&Aخ]͊BY{>n8%ۙ?ЀP Ǟ@5kaٲv? r%ƨcZ4 KW`bQT8@t Cߔ5T8a/iɩILei|̈́ʚv 'A~VڷŘ]Sӏ]})XT̴ԐiJxZyTe'Eؔ峐I?aj":kK+,D+jeb-(HY^`c\2D|ufLY5X)" :kP#z*|tQɪ杀`$H_O?ѱ|e5J2&yܒfRKTYMgsKs Z:%/Ys x@ o%AznF=ǎ$0϶B1ή?-2'Pk3hЎs[0h'3hNL2YӭR4G]"-.|a`WX-\U ?|699+9!t0 PY9JTm>27O,\P[pkS?T3Zιf6 ~]1{$oص(wx̳mRxI]$en%uC\w5Q K̽Tv6:{׹hmv U[Lp_խ<>(BLJӥ3f4DwYRQV:zRnSco=YeO6Nܰ,"w2EunRQ',SQeZѿ )ֲS)"bzTYbݴeMgWּ:jsL6zVFQpr}Fsh4CELR}7(۫ő+Ip.ڮ,CSla)ҫ*|,^d2R2igtTlb`~w4!l?@Omk\82=́*sMOe^*{0W\bBn+Di>i}jT~xɾI wqpp.䇹 ?cUӽv y\(Ab}]6Oݡw^ܽa_Z0,NSwvxͷڲ["62},CeZ+j21ܥkZVp!j)8'~_7 a)&C ފFk=y˸m;="6k6ZODM-ݗԱNє(֏=o10<:;"LgXd@J;lkv+x̆+ApO`"o5W@h d|0Z$@ -C/Of#% ϖ8U薬xѧ@",Pqz`Dnb!1 :-!蟴x2ӹNkwi1n1F<} $SL늎;4i05??ЧMԩ56+ o6ހP}& ,M6a{ߏ6+ri/E?D^U%N$c12m3+(ynj!TKKE3'SJJqJ1K }#q /M)98M$5^9w6QD,5sy՞t0F(>'בHToy[h \U}M[L6mJ=[1$meMcIn7δ$Oh0:y{*tOhtxJy*حc Z0^\7]'ڪ0CrRZPSHj,^Ƙhfc/z%}u qx+P+3|!ݳm\ bTI93Kf*قM%YJ/Z )[ )[V~Z.M.-ti4Nk |b~gAc)3,}XH4ֽo]m$W:^gi0g=1"|Z@[y&G踳J !3}Q@qGa=_<{'F{_ AZ;U'3Lfڶh3 ]bL3pLpϘnׇVf>iƜNZx擲ԩ&&01XeQE8L>ߛ? 2n9pr?r[2@~20gl^te h *so2 q8 fOɜ6+]T(|0ZE ^*/hAưHXՔzzMx++.wYw' vқw@ ,&n}.]$ը&N0#.Jђb2񮅵L&+iUHȣ'IoMu#duj|qdzNaň  񏲴is>W3;B荦AOeqQ @h3碴IDiTn3lPۉ#b^+:q<̪zSO, 67z8/axLFg=rܒ)I'sʢ&EgX4R7͹)m+m=PҶ(PTR5[PmX>7G,ZCV^Z!$շauRbcZL[wA=e8uwRq"eBd0c@>ce][Ne]T[4ɓN9ɜ4[uy'y ¶g^DUAs>pgbZ|LfMN gD 4*&$ /0BmiZ8ݘf$WC݆eOX޴%kP⟍-mC'k.iX&^OeO T 5tu_%ii.z&a"t/_3i:ڜH3r$VJ?q0|]q5u,GbCSl%pYâ$T8#(@PlM:Q{vDfj@! fv^)1?tkeG&aJ%mӄ’xDwֶNKa%цr3*[uܷ 7Do<$?'M1*DE3&4phs*{bys\[zw9R/̚AYєõڷ"*wfc,mr .YrҲWe?/$/Vף KU'0t ƙ}i 4&@$~3*c6]\.uc4K@(*jloD56ؖo>l{U{ꏼy~|_{ g |t,"۹6BFk4o7*e4  #T0w5CL3UDZ PtI5uE=Hǟ66CKi>OmЪQ'NHTkfo(s:VqCt^EP'ޥpK؟}|_Y8V[tME[]\q,6<&2U/ X*H2Ц dzQ_x)4?DBo6\YUxQ2O+ x(JBIY@'T **+FPZY,PEWF DN:UɋSH}!7YFf0I2q%e-4 5zoqp{]NX`4 rSq WLZtYT!.Iprΐ+.V4 hz'S \H ^|v8cHC5Xb>"ˮ5ܸRN0)-lQlKϼ%QN'8%uTE$|R/V!9L!I B8,';F\XlGTIOE4>S dCl@g,-wP7/ [LO5xlO#Q_1ơ cci1Hvꄝ@Jڏ"C"բU?M-ώײ pYp΂?ӡn`GB<HNp~:a*|7A~R E2gRx>ܴ!gM5S7p$ ϧעm z(~| N=љag2H-l) jl(bt9XrیJ("ZN+Bo>zJ5̌w S^H5.>: -Gr=+- R/ CSچ*`əŐWFPr}%Ud<+EٵT,$J—?yLasdHG=QrG9('C!#A+ЗULߎ7L\Roo E\CE{8+ҚD? g69Ҽ&9 K@] @1W>]럮NNVn 3z&TPg Z%?z S ǫvA)j4Lx~ _tQaʱYt V:=l]#݇t:_95 +&:1_4L_ShN f4zWZ`Xf4Y; 8zm5c]>Z R6 P]{ݙ`fζ;ms=F{ Q dk&fY6Ǎ\Dl؜I *u~Y%9N zg~ I΍ ᡹3͇4*|&iNN=ybV/LeU!%LlHi(ތAOїI%pST{ ??M^|XYn^9I,kDA,pg}8>ץFB :1(Woh͂ޗ 4ap:dqk(>Q@rlMz,qjeUEr-eKL g>E)-̻k)""7\wt<vfv,;eZ37_:v~{{i>6>bf)h @Pt )A10փ9tS! Mh]M1/iyEyE|O}y0'7p-j7nwD3qgB΄FS [G/D"+q}aG |wf׬4/kG'HrGvv!R-]ADK젣oȆMn۬) #7Uf%\ф_-k^2GT1Ӵ_70E]6ݤLP.ݫ~LC%׷.iYxcqF8կCRӣ–usx6c0PU9GG\q4.8'ȟ fwۍ=ZaM$Oܖ$o\Kf) k(b^"jmù1Kytk$2\vUxmz%6 MgXNa"pYm+qtDOH/B &HaKy_&72VJ*G1d] MPZ&zAR1)8glhɵj0?ǹۑ9a&R3$/)Sȑ csVx3c%U*mJESdžeIJ2i5? dBNH39#\r>H*rd{ S-@mpsϨ+ҞJ /;dC9Εf9h }XL:xK>ͿBoҰ">F%b4Ӗ8b2Gq̼M h@q^.ujl} qt| ߑ<&ʺcؼ+8ڋ6ͥ&Tw6M1u',dt8Kn27 ߘ/Vxs`&Y;gz,Y(NG" - ] L )y;4DolbI)+VjdsΠstSaf%k7pW5& G^Onج7 oJO5 5P2zs B4?% f.qX"xfKxal˕R+%io<zr"'L6fX43iD8G^do2Q;d$<h9t{9uGG5>K y&'p)!xR&|lC^c*1Ayu@w2N:hT98GQ/t!&HQҐt0} oƤ3F%'s~7ņVp<hJ ^5&So&}8*B;kw׷yG&3.R41$ ?N~Sb+0akkk[1RnFkLM-Ke2221X$5">a0VB^!M)-/y(O~#;TSl6wwH3ښIh{`0$d p Kl +N.L5,i3b>U=8R )s]S/.w^8 pYb6Eiplɇ4[[ b\]Zv{Qe\<Ȩ*ݙ k㆛Pnm#>4}S.2o䖻ʔ_ 0,u\a=? 1 ,Dםݿu_?xsԎrwFYicommy&!|-c},yʦ6kݖ'vR9gmQ.!5Kz'Κ*5p|K>I=Katd_" xoɡHYoq:VU8Һ8CFYMNm<9 vȞ5PӍ:)؍1z(l7',?z/s˓cuV#㧖xSW7vIo0vjDJy43+˺N39OB~bou. R^#P:Gv%&psޠ'<΢>,G9b5qKnX>߻C[zgº̿hĒ9<ED '0!|UEPWI!ZzB ?QfS9gbb1{;r=*Z9W. #ig-i40h=teM)m],7H v)(_wf ,d\ v2FȭBnGR!7FvHwd_STqf#'$Զq51w/j) "֮}.8IIRzR">#1]0e亹L麌EMʼn7k λ:Zuckl[wm|"ўoY] YIT_7Gdj&*kl!-(\LJ@$J+(@l9p S| AIȆ\ec^NZ521y=Ԗ]loGJz8B'*o2Axh']tr-?+S9] WA,?.`1=oT s]4G+u(w4⻊³l'Sr)"/!<Ӗ+hNW\)e3Y%H0ӲCfd# VDMef$TbE:-^}Ȭl+DWE]*A4CQ *9p-tۆ;ϫub*oDϙh/y;9W%6 ̈u ua5X& 덍]ԈmJ=YwL LZLskd"ȋWyVPlaS-6s /:1WmvDZWbMZ/1| 7E|_ y_|u J3XÙT@& C_e)|P_TCW#+F=X8Oj([M9ق_gUoMUab YB2 I3 aܝhp @8;@E'Z#e )fC݈+2"i!aVעeۚ)*[HSX/] ?4$KƷ,5D CV7fԈu{IK"XRȤtނDv57_ݘu)J c AӁZ\dHK@adupKtf;@/ |ԁ;,z?ԋcc2LrJOPlUܔ!C ŵ.?ǖf]mG× |vt^Cvd.W$yj;.lɱD nC bl,g̭F[v$%_P~kg--pat&/ձIB6+'~_+Ycǫeܕ9U(0o*UNLh$tp&HsQl|Tʻ9A NKŢy)pl鲩&0%h, NU٭=4Ļ;9nHtK4n3]PDg'ȸf>@[}o4?ZeHal>eWc6$D3dl'O"hDxWL#` +RϐmMb}_T-׳䐀@ژ G:;t<)΋F_ҵ_ 0< E2rxiлRg8K QM5zx ? ]24 ZѡK0㑵BT(в߽i?>exB‚>)Aڧǯ ikFWn(oȽ&aPT+ X9HQhc~qnf+iif? ‚hHPLCҁb9.D WIW"hE+&攕6&.tQ3O\b=#:PF/U+c^fjwǣ mH&xz8LOd!0^H?xV(5[?:HD6kmQwo9KoʜScOD+*@)g;DD:)g<ڒe&249ryE-wz @ >aAP?oOc߷|Ӵ |{zg@w|%k'`5V@+L9F myqB +DyIk.΂殡o[35مg/{6wy^]+ZDrtrQQL\VoAĖ%yEjAɎgSF9yIKRc*[?W51%Rf.*.Fv!S=و㣐*H_I"2Ny ”4ɕmPZ/xƽjv`Acgؚ,E65i n#= 0дYsXꞫ>uVKURrM*q+FW}nz#{ۿ:`Vnw4? 'siVо,R2[BzphE i~dQ+XkfבҘy,Ca!5wb{Qx:5+ѝ)$8 p=#{nʶ+<{.,Ov8vҔ8$p ͖y/;Y|M6{ "pk<ҍR9 f;>̉gC67E hbwkq\S**LrMwPo?>G* ||1y?ˆNە?4]Jjvh3=ȡKv!ޭT632W&K92xyT9b]|92hb2hw<E |sB-E%NdzQXݭZzpRv"]IQPw]y% HCZdUޏZam:3PɩVa~UѴEbj#`4EӪf;G8βct*Q4lQh]Ǫy|Vζa,qJu5&~y^0@AzDeE#)l 6*d3>7*G2!"zHAw)w_˦kE8<. 8?)a~%Y]wy-8EKk(Q𨂑|8x~λN?}&I5@BׄQʶPDI8 OtktQjS4W (NT}%GÈ2םoߗ+ \4XaJ?<۬@[qGo(ϳڐ>S b*dThmYF449q: |\E%p|HONizD6"n!бHGEkS+# ?}(z5@o>جF !}Hg`EyJnpM({+Kr!J@kEgC50{8 ir%d%qTF\3I9qu3~Q앮% /~ a$\EgAE"yC?QzVLX푮ab fm܁9TALª$K /`}7Y^! M/Z+ ByHe1I8D6k&*laFsgH4_j&ئ-j*-N#4ARaGq-SB_%Zr4mD.tb6VBuc;8Iܸ@L3" 7ccC.FI)y=MH!+ sn- 1Ta6ۮ_9Gˆp/bvs+U:Ph@W$(-X@D#m˝+ ~wf(&pO`<\[LYh_GL)HOU5}7!lDi7:Jj]]|xyKxh(0dǚ24gj 9Z~=i1{r}'bHBt Nzߨ5,vMmG05L(*$s411v7s*.usSKs;k?@C^)t+[ְ^)qhk1&t[~qsf-ȧ>2=tP%a>FG:FӈgW> ZxaAG'JJ'P;U蜀 H?p$Or?3g-O '-@Rыܲr#,-;47 `X 0{DY耠O$-`jYq@4vHso(j#"'.Hs9x;>9AŶM}Y 9ϔ\b|nE]ː1GݜaQWbPd3#aٔL.!ZNz.Il@MP u40xGiߑf諒DJ%s|( $){yoYZM2*tz -S4})|8qK_[3OW6r+/pmsns LycݱLOR2\Wڪ"ٌxÌ7Yl2ݍCǓuEzO9x("E)8p`ס/94YBX0 ' Jd[fi~}d|y},5*4@/3+'9FzMe&bVt[Jyo:\kA (aJKBG^Y(=OiVPߎ545!s0Ž蜔KL ܬQH"kcL1q'QߒY#]M@ڒ! A2Oo^0Ѡ)2G;GH=ymo4  ˛Bk6Nٮ?*bx5)E +7#/bO5FaDZ'B3Pr)B紭4c}{'_sh&L{GCfb[Wwy>ēf, -@Q9# ݍ>ʼJn€9Jə%9ѷN:$O%R'K}a*rn,ac8syLХcXF]2M ,tLMDj/ Z|l-edԓ4If{/e3$StbKeA0NfWzY7n9a$^)f(~y!ǁHR*'_r & rг혱s|?m.}u'T.j+-&Tt/4tmX=*PRϩ^&O*ydi)J@roG Ag Iџ+bYqk5f`P1]2<3w3 DhT\p!74x$t,Nx=l4~ `"-wcAW"rislcޓr3VNm@.wȣK) u#3֖3;˥gzOYLOˬte7Yx]/0\gpq,%a s>cd.OTE]Y]ڑN)%W!U"H1,?] UN)hQ(*zU#'7܄)k)oE^n2\7=60[G] |lw'7h \9vD.{Sci҂Em'tQ̎ :>Z[&K֗eW)ƒ73paf3%M^' 7 Jј"b4vzn_:hp]+Q[ZJG E[6y;v`9%Ib6cNd2^nn1{`T+z^kFF CyJ[Vvc)y! #a(:G@9BUE7\Pԋ2t*h6Z H"dRC4)RBGRV\Iw3rg@^q3[At1"|O*x~,M<mC| Gs}`lp*/f,XZ?Rg1$BiyVFUcGFLw 8SXV*)7>*f2D%|%޻1]#ܭĉuzm0kCPۼbN(n􍕀P)[.鈔))Dce&0٦P@F Bn÷>H2{]a^zAi<藣x7KeuSǝjc_r0p$vƒ5w2GwTfAT;VKr1TEpzJ3~ຈ< 6d q_LN=Mڅ[^z.@Ar>?'~+iO>nAẒD|R[d,R/][?SNȿ,‘QwEe./BWtk-#"*]qVAIVC܁N`=F()j?ah{>L5:zh"p#'aՓ^e%]>0)>77WC Ac&G鐄*F B tbPڜ^H:,KkIcw*UDFvQ^ U2/[J&4.V]-_ЃIރm-Mν'UtsdnqDݘ3oKX?\}r#>8s[2g&17!H t߄ǵ(P$Xd<2j;Ɛ|-̲ ӍV8xB]Zwmm= 4 "#x #f.kTIIx?cJ.ۣ ʒ],ּEN=|[]o? >$t~!Ƅ%RPVvji3ʆq<:$5|kE,EBAeQd\7Wno55t{3tL"m$ 74eמkv>z|ѓɁR0G ^Q͐esZ B0y`vW|ή;ct6 K=&ޏm/2MgҠ+?z$ZR5zBS )͙,B~xe`t =E@4-ƍp%(FV7Ֆ&ެf؟x'jOOkDVY*zAؖj!G ~<^ Ku\2ϗJU3ꚨ/Kgؔ :ȀH[j%=2 H#T=RL/ElLj94uf4^*v18%j5e(o0>67>Lj7Z M=zewpKκ|<%,'qiEUdaGbC3_cR|*7ssP yq`qnq33xܬSeۢ6o\+jnNIPCǦlL$ ,$cdf^k5$j BMhrsa9m7ʣ4Jn2hN.(Σqجʫ"GQ״w2H[dkup<LriΒϳ F效Mt}en2(Ay Ug#J3B +C<|(L챹 YȰIxe/APX,ae+.UIyoY(&5֢8frYimNym !iԾcseOx;8Kd? oeʱ0&xG^8@S371.Z] =e<(HܭDP\D wiIZF}dɳk%q_JJԡtv4f/}FAM4ᮢ\Hg`p.GIZ):ZqDϫ5 Hd8֨57yPin]9Ū%Uﴡy/N}%"4ptjݲg}.|&YH57#[# r)/؏<3;]b%f1H L KXK]si3U^ti }  ڭ@OAf0bJl4Uի#fZVZn+~pJI1|6IȀg9 r@p<.>p=BMYM%ߏ^a5|>`0e@F{/PaSsz_:'OkK \hVYbp64*/ A_(1Ȃ?.6eqJ`J*щҋzNW=y),]ݸ)^l+Ƨ`A sz=,}.luz* nޠƨ[aY6- W N e"M~l pHU*kMd#hnG7"37wSsUꇶIU7m2_n374EE◦H- QcMZmXjX<͹7K;{Uc1k#*<;G6Ҝ,xzl,ԭsc\?zC KMBH$#?:N_^O}fYzM:T%oo Uhԭ, kِHhlZb*8Ήk4F$-a/~>_OMM{ۊ7fs7r7Ĵ!WϺ6t_-.egtQc`c; }ե_s%XKZ+xlbeYb{dRKmieC2BP) rGds&k Ʃ?}_U˜IU b(=Γ )>;zDJ(̰}He MY2Jl:! |zW;bI&c~[R8-\uzYgsBt5av/V%$w}7BS:K1 E^=r.IKe|utj f!l_@~Z˭ksش3MiSΏ{t`HfwWD~3ߓk~.F6I"r90hu˒xg;W(_Wop{V9lYt26l]>w nOava3-p@J _<,y ظĆDuAgU0ōF%?uvvk锵|EC`~ ަMf{o>xdC0 (lT[똱؅]yaV̳;/38ft>M_=%=TIXֺ"9xF>7 FM;ڭbH^( 8J}:gZ47}&* >/N'm 3"G\OhU5 ~U'_Ψ7ƀMgx]"v0B8 ߎڶg=l!hE:"܊v|Nǘnt ژ:,蔡}b1S"U'=O@}.@@Sͧ=*lꋳҋ6tby,WrxP>>~~!L4Wb)wda3J:i+S :ShCt(/QvOQYp:E|C Eλo;>pB~M|ݛrmه/vE:8{_iQ6^o;G"}[m,5UcRm~j=<>n<žl *p80< ^t[{y$i=YSSc+at6!ML!("jRuȤ#ŋX%v0.J_1d`? )KoY}XW0\z!}owC,Aه䚾aua%&qtk,l|P~4M`'r_mONm2%(DD9rar}*UO.U8>~33>bF0Yv<%OF>vsS tzP?e~BYhVkW|-?s!,1@QǤVp;!Dd zE /y:r>حz& C^9ONc#(^#;d/;3? ;<+,M/ :U82t,7"!&/Tb?aTK/d?p‰>++^ær<- y@)[5UXy@A9q|CMwݓ}Ãg-bZ}X&i/NN'x_ELޟ*Jp#0%lk+jPYïoZG[“vY;.8: 36!S̈́4Ho6nxy2{lҏGNf#S*>nG鸕IQG"T@MwJ#WWS.b?$K&/?n Ʌ'e)D4Sdxg8SnvFt4/PV |)`yCgX!!0ũ(ߪѸJBb,8!e N6Ϧś"" v0(དྷ}Tq?^ 8EQ_onm<~BA|5y\&х}`hĜPv3Z‘K S* EٟT Ѣf:To+,fMy(岎 3`'; zQ^ƩEsSGg-Exaȗ^|C2]6MDJ eGJ{Pgϙ Q/J|6PgaljpQPQ:hRjSj /KU*SWل(kZ#n { F"ܱŘggi0`>PXIk oJ<ǷaVg:;T MQ@TEVq&<ɢ88k#oH<g-"v[V^ z?> ?ybӖ;IcRﹲs㥂5cr h #agm E0rҴsXTS >pmhd]$v21a&Ѩ9YF>'D1hUctQ $.}.#gkVdb Q`(}|e NBl>o)[lf< 7@/>-Md@&oz&Og<*cp5Ln-;A11au~z\)|bUYލG0 gQ.P'\ҁM@dKPT71\uH0E{^0@o&Q$)1]cY0 +|2+kd*kOht3_)Dr<g^$KGX>ibcNKKXĖѐ& !o.iK Fⰷ ظbO-\x'ͻΟ:D2NƩA$ʎ-&&xDy%csE{Il.Rno.&wdsϽ;Q/#PQY'2{! &FUT>I?-rJs%~uG7(TSGEVɞ9˼7okmV?I%XݓeS;EP;_w-fp~",$FA/$_qʉu_D5`F1 00_\r❟caKieǥ&󵋗OK Q1) '#y qbH0. `D7Wx OR6ŨeJ")nokJ>_)J~'k lk}DVXʱP)X)'T*tx5ssnV;X8%,e-^8lN dz{R0ȳtt Q+-ž񻚒*{{hn}t œҸUb)|rTii.$a}0d4T܅ͺa|6cB|{bW{6w6k6ꭗg{֟ll|Y}P0>̎A`^zz\4vכkWOONcw@pљH ?#AcsÖ4VRX^^0R^| jY/0-S8sbG%J[xB@$.Oڄk5ZOU%*|nH?L=\m]1wxwE#t DjUFK 7D Uy?d')Z\SIlV?@v_ 5Ab&Bp=0(\4مT*1K4=gxut}wpH0MdZV DJX/1Qe$P@ 0 }G |p_xk+z/ءm: h,4;W;o;$7T$7HSp08 M 팸f(iEzܨ5w#xpqa}*.h~Nl}WÞc ;4]͚zmc^kV ~yZkjz0 j=iu^vZ{9[Dkgح;r nrVŒ~[Y}YjccmFkish:5^zi=}Wnv{b7`Oa`{;W/wv:뭜^e60mOyIrՄu}̫Wf;`@:]_oww:FM{moSX7yвMtp)i_y^h~pݛw{D>ܪgoguV`MmWW7_vAquX/ d@֛uE*a3VP@6<Q_aW1 R@@6HޏzI 뚏}LZMOYMHYo&Lr@>%kyl|rW'HM`k?k͗f}o 5^ŔSNn oYm={ Nyzg{ggYgF̻A O游;kgaZF:f \HУnb~=\u)gE} mF[ퟛuۯg[GpdN箏7Hux/4ԁ1HƏ/0{4L^Y8̏;چ.!f^*,p]B;2ox,l)'[6mpt(c)}XFK :|  xX>^<+vƗ¨S96ښ)"6#.k[@ɃI yrhe5sʾ)|LJ/O4;?c*GFt>2wwQ.t16tP0 ݰϩ~"xť| ޼ֈO1qA"\(1_&FƭuGiU23晔fEڇ/c P^o[q@( 6`Sܦ,8pD$!?'sdtԧѧwEl1Y911D3Zi qXձc 27_tF?9^t\; q~aX, s[Ϲw=tI%!C;kS;rpG7Rݭ_}lLfãzҋmΗ&~~furx0W9Ao4zta 1:)5\ :`Ld*%S^^i9wJ g)Nu Bx*CS!GQ}KK,y IWy Qr 1ɻ0"4w骝^ΧQAƬe zˤ2/1Sĝ= FnTA4Mʇ(*⪨)"gQ.,vQưJָ GЬ'@<Y24&vQp:(BM=$44N|69cg";c|dM/{V,$>q[ěRt|#'L|䉼qwok!R\}X7&sW{!Yη|[-VܽlH DSE8Hg9!ɲXuAA&=DO $": j|^&mf⹟&+' A0O?mp1@:9q2*W.KFQ$kdgVų wxјj[oѿ #J+zWrю4+%Ȯ W재k^RRݏE=$Fy0V̌c~줟\5? GFGT)g?ʎ3I`ȡ^<#% ~|ggN?)BqArkN"R%I ƦzA1% ]_/@?v>\pa5BVנͤm)l$x4%_"0s}2T\@d3 $N?bM΃'[&r29jZx8|`xQZ|z0v6 @Da}.Ltrq4Pibi:]JGy2_ѓ4 "]I"z%#KB7$LE<1x:9 (e;ΎL14De QFӽPmZ(1 I|$_P% !R ^"f* TKP,$slBeovA,$4H$pɘ&$aTڇG::Q s&  i^M}M2<2ryG9<UKoeGXVuN_걆׻v_(VsZ"6VgS*U}Xl䱏ٞƤzRNӛMy]<=*5ps2Z<&YweLv)9㕒dFU$aEc5MJ?l zt*[b'K%82X&}{;c@+ˌhdoTjP G;v sソ#^.ȟ't1PIP2"ͮf$1OdEПAqjɨ?螤v>"bD>`JYWXf*Xh 7T&  TY4cZ'l̀" $3`a )\!El!`nY*^jܚx_kU%B $x7,{pK"%j$3VN/>')` wigKovP6b+!9aHwAO mpS&0 1JWyl'b%=4^Ox@-{ =Y!.@ʴ,Lf0v4ł`Uo:z_q,d -K~Pw{:MF"#4x"QL1 ͼx# CL0L )P"E W aob2zN O s HW ϛoC[8Qf ſsc@7!Lѐ Xv&(7W(zڨ޾nbk)`x&8/<[WM<}*o<#|ugw~{NQߛ7;ѐ3\m_=gw~? V_ZSOz^1Z;arXk`G|m'd6w=W/"bO d Ftpc06Te ~UDknWҭbFiAt y52C Db1; ¡_D<5마69A~20A9ܺ}iQFIE%2XVֻ{*EH?Fñ02ⱇf) JEʹa ~q1f`q+thB ڗ')zz~|dg\!MvոP' ʾzezso3iƨu (B e,(L@#"{X6o #wG{8pAaHeșO<)p[]_43?J[ALkY2UL a-Z5i?qBG;؋qiE,x GN~oYTn[]p_DB2ՌzɫgEM8 d?K5@0_l׉~kە"?EHF;GvU;8&=.bN>WvP@u֤ u/G|BUH, 3Ţz.zk4"uk$(ݮY{зz.%itaJ"zG=݌LۓXyn.QAutVQ26F eeWBG =v&D se< ]y2p Y"S A^2{ޤŇ+Sbkߟʌ jg.T4BgBnF4¿?*.JU׵a"C=+"G WU[A!8:|[fOEc)|MJ0 `D24?99cr]j8XRHYJ qƎmR7~D XGݎh䪳y: O%pӇ} ٔدpVeĭ֝CJ1g]8{}wI*rR,E >5g.X}ݲQa(I @ޕب<4ZF?&)#FcSqEi>l=Kw$tTY$Q?DE4lX7깳^@_ l`Z.^ rĽ}03H2mgO,搿g6~&* Qn][7̀#T! ?$<<>`Ys1R1R"t­fp. S5D]crJܹ1hxv|3`=S6Q8&)$W=?B6 jv=%͒5/B? v%W|ocx*Ou#(!&$8XxȲѫdRz"{E)9\.'f4Y>0zߣB$xH(D<5'7LvQeoÑbou{3HJ Go{;ݽ:^r{zԢ9,r  n)9׾HWl~{P`83mz>5ZG ΃6N|$-@œ@wB3%I) 8vv P AC<*2~⏯?ky<_bht/]R^]ta q$;Y(`@`]MkPV]aUYq(L@RARhr!ӝԀ'#W(,^mM+cwM/VVPc)xQVEҶ%,@](-Pu+]t2Kt{S ]X/Hqp0RWh^SXwgdHNֿw>j5qiHn-(Df 2H͓'ؒd"̂=(qa8Cg<>i Q18m@._p*JHJtZ|%ڄiPRAw_wTEXUe|%Pk򎟧U6xLX q5%* P&rx9nubQ4Gjc&`1 arLDfDW:yK#G7o0ZFhXkkA' C6kpZZ^.z|ErVW/Mmo/+neS M&#!w\H2/EERN:pOI-&ꀀſBBQ/"&j v $h F ςVOV*HɊblxY@fm)SEBI%|u 3&`Rm9lx,bkA0$uC?_OL- &"Gr#ŸNᐂj94U e(cz^- Ƨbh7B5ˢ IPތ*\gcfʅw~M .hCFBȜü]C\Y=BkZէڳgkTcEe6ןW֣B1}B +]5ux*&RG^'(JE(g Kۂ8QV%L3E+s MJ!|6U3ƴRVW V A_[n l]O"rQ(OQ\SL ?S~< h$P s}R*l"ܓhOZ gnD%dh^TZmeVtA"Ι,w7jQx.mY(^Ȝv1Y,L(ٓO_rqYU?6 ORa(SM.Sh+P:Z9䆰?H< pF$':r*C}A}9>Ȩ"9 P|:f-&AdAʛ1IQ@A(0WQP`0(|}>X>=@6/o{>] .*` bbK_1&lA~׮r,nq<pz~рS U*݈F,3M9()Wmh+ʻG`"꣏>YO25&piG^^폱iC5BD OINJ9F^@ܸq7Y>E-~8[$F}`dЭ .eI1.pA;6+=2!M!AdH3L36!H>IVٽ%'8+ut0rOT0/-9ZP6Yނq t@}҄g'O{zfLyU. Uȯ݊nlpʞM |&21/rBIi 5] ݖJ I kC><|gsur ~3Ba/6)5Q@xrh`< k ^Cݝwo4Z yu$썾@"`ZZZ+eBg9$($i+"y׍HHQEBug>X ,$O_@6ky\=vp&6ea!F?23QF3:Om873Y?n7"24dy+]z7WxWib޼a5=2ԤX6oR[ F #+HK3aO8{%W](t2H00[(/|O 8YsR\- f@O f¥9\Ϙy==Eݱ}+%Y;jmeS9 t)J\VWubqxEw`XؤY#4{b[,+_8s17Ͷ'βfv%u o蚛ΈyD3C"ݍr7jY&lɺydq(|m:<|`:2:s#dlB 6!=$R IlbnK:AKDY.G!oGҨ@12L˚=VKkWڪg?/SF&.KX\kioX" j:"856xɲpK|I@p͞=yq'7 1a?PjM3Or_W+dzѴX^[5qo%\+/rT<d D._X @'`aJkZ[ 'YA̧+94+h9 rD^/が1`hAXIA] ayw^ʍ@\VЄef dԨ5 &_訡r@C\DI. Xwjj-b*i1 5cga*o3 Mkq,PAnh Ŋm$xZkYcd킰oSqJkAjJzKRq5*Ⱦ Hd7֪Rץesp>ЦD ("ړ| YG?}QxhQ;mY1 &r h~ `tǐ2%Qcib]PH8-&WabOsV=}c1\0Ք6%̳7?dnD %X01b橪ؿha4I8v ly?[n#E7Hq V(O U>?kZf#4GU52_c8,8 ږbǧ>lhV< e"#H8 +ي&!:[NIP ʼnj4Cjg*hh4iC^;`L>/G`aK4xʧ8=,N YJoRb$S/\mq{# -ҵ$#@kU#k2iw]&jRtIS#34,m@ Cygʁ!:g)Zt~'1$ZK.e7-nFCX 7!er->N7ҠD 8"т(KTE0p(A(}G6a͒rsD#8*Eğ ;%u$يvUh<+FTc椲|ŭRXhKLt,,q%SS"_|TY*}[.蕱kz-)AqKB0R\ͳ7"eQGL):yurb+"3zRgv D1 ] NJ% 3lcOJ3KIԏ零Wkt}= 9낛PM(\Pgub5Z jαWy{@$[эhҨӳPv^G b NW\̝xEuqd>E\ 9gbHV d-Q*ORtJ7-*d~gP4fM+x`32`I RS:Iv -N~Ni:hAWʦQep42Ɩi꛹yF*-୷ Bm'&nkRw~f(,h/q4pqG8;  J?ʁȭ{y[u3^1itZ-g^-Ŧ>Geq=xVx`S\lrUSJ]kHֶm\벵XdmG Dd~ub=P5@pՆ 7 K:dh7Gh[E%LM(iL`Q{dACOSS23&E7E}e-0rL "wi8l9nF[쫹t\jhb-^,}v?P()b^nZ=ROb7vihiY+r1>o^vC  bƒYؠcQJu?Kl8H-4c?-2G2LUb-WaΠZt ]5,)YE[„HIGGx" l63꒼M{xJI<^C6,Nz%EDg6^) lf 's! =hL1rLRijyv’C$ۂd|]bqS* Dm $cfx .mnY#rc /ytaNEp=jfyX|菮L$vfwV(OmtYD>q^h6Yz7e <(^.Q)oR3*oIȒߺtkXbSpâ("(/Q?]R>8nG!I Ackbb8l(f`@'AWfD 7|)aȇ*|2D@)ONe&.ůO3wA?5?%?*ss#Ql:ubr wU!<R(I$ɡKFK/iH'/ I$6+a=&\S6 VknYţ}L0MPv ~LHͬ&BE1 #%W\#Unxr*ATQ1TǦIImmRt/^}Xr2c tĿ*Yt8Mh 8HScna&)Ml|7rw&σ)EV3 ] Q-ЄBp)=8H?q4%< C9;:S*uxQsXJƩ_A2Y0X:xHxu-c;)־;# "O&mJ) wM;F'Foz QәxadDOgEnNId6bBt.3"Qfh=I!"\ rVMt/kDNO@2f^pz=hL uhGV[iF{ጚ%T+Tt4uZGFݚt 3bZhy "FwB  !ɃnWӐcThçgsX 8Xx癬j#0֜ 7zsv7;uۮ2E; NϪ&ҤVP\M)UɆLOT2bRt^4Y'p ZJ# (hD.-a4K_0?xgL+ <|ScM(g[yJk@%Ʀ"{d--qኡChEvE&u">ۓ1[Lrk-D8z08g\ \k~p{jtp{ɛs\\ 57]Z`wE8'̤Oz*F\?ϦW#a؎QӾࣘVN!H#<1"Ҿk ŕ*śRh9ɑ STO[;f![d).>VaS^&"y, ane"P\ K;ԝ[džz޹6)8}+1nbc3Oo{WV䒍 0ysG3U 2>>ФΡZz ?G7*/br攌,w+Qv#q'6+ڋVd1"M"ahx$=kwM|UW l-Hb!]\׺hSSHSB<9cp̂'$=B Hi2@G~ޟq$" R @LR(HIj&){I26I0p$ysr@Y^|ݦ)22"2D,[=?}0ft <ܝ' HgA92 B~UFB#Y R ;X՟tfc)ZНSri+~%ȾJ "Jvʿ|bin|ٴItAXrrIXwDx@C5FwTa~tuEnBYIeF"K?9V⥥o(E}3*5WZH\OhKs&$Im ˲f1&t\9 {WR}X&yguoxZ@Luw OnąmźM861 FBF;Eu7_LhcW׾OfdzIoN^ͼjnʎBLXpyl6Qsp4ۜTgC!3Y|Ѫ͚EQq=#\W N zk\cil];bx>È;Y4: tgfw8c ViI"x`)Xޱ |Ӧ 7bǩ ԭˊ+ 6j$-$cs4" IgJ}T,O_Lf|h;V9yKŏnKvr'&x36Y)m|O$L^Q@-l'tZ- aЌ@ͅ,Y3x֙hU7=>vW-HƝ~1.S! mG/h[}^<럏VKl [3K1cn:RF>UQ[R-(zsLܺǁ2`_ٍ YOo>Ī7G6X4]X|HhxH#rD߽Z˻P%ڶ:gg+(&w3m ?gg̚jqnuZ" ٪`<2fԗte@ӐQ5ID(yE "k4,%.-Z}Ժ˛hb&\k-*^VKa銮k5Q^:5Z{.9*ǻb$cTQF0 g뺀Hh3PF cB;lsJj Cy0(r kzSQWsN]UdAs0t}]Nkx?W+0nnc%c%ENEg:\mnU;s{]sу芸τt.ۛhmX%ul#X`8b:t 7ȼL(sJbl$EBr8g#C`Tn gi~ LD{ olrkfzwF\GRC?  qJ3mC'89 k[ BkUێCjO!cq3|87GI4s4; wf~}4tϧ[RYo)!8;"D}.#7c[J&Hz*Jc@EIc.*^](ٳ$HM1gYJXR06rLC")$cU^T1T0!1D/ڬ!JW ^OUC.xcOPiS>DMR'_A;;\fRq :.2Op%jVó&MH1Ze|JW1H%9-)22P8lpP/J<%ݓ*yYw>и|F*@9{ގ~"9%'Qsm e*fNb ,CG fbRFasz8jפA2|ʪ[O֭ ~CnQ?fUNTLEljvlp]eް_. «7R˿;xT =$q7dH4ӽ@^kCre'>3; HNFŨf5(;/#msT`C 6m,/S߮ [j"E_h4ۓx:QJWf̘&vqGnC -EX) JK#;jE% 3§R>%)f\B{S?֙Z'ClnYͦ>7^CwHjO=^zT1Iؙu8 ЊYl/ /1LyiDod~'M2kM֓(aG,DLuPQ4괏O]# HB &TfZ\R1FB\g$-PlI&*m0 nn0v8rEH".le(0,bwz@cM|b-ʝZ8~ 9*ta4&a9S˺zkZoA@RhKPaA9bt:[IvDHEpL_ x]vn FӠ/}=^(V#Vع/;ӮPЊg 0mLҳEmemM%`nR)@䵁vKj\LUc4!>M朠Xvz1lt'iFY c1^2jU*ܤ#\-kLVl&KTF4492o!"x_pz<~ n42[\e F2s?D}ͼ@7v7Isu52c6{7oֹfy&d+3"SЧZD)2Wf-4ѡN@DY=֝UI2<l"E툅=Rmv3|/- lW){`͵qENO4.&'Τg a|xuQ@6xT(ׄx7.nrڇ hsvJl:wD;M7m6؆`]G_E2>렡dKG/YS|! cq HsoCq/(xov[lu^ bMpgcD3$x x\ޝ(?.玓$ۡqڏpl \wz.sKm\BabwGv."i6y<aX^".20g`/:j[M3Q>{@R!CgL:* T\gMqQts|9cU9HthǦ,#G s=(?,mpۖWW|8g!V^@S?.Fm)H&2ZaOZX3[oG'h:ժbBzy2oTJuddͫ$~b4L2 L` ՀM"["RI9ĀQؘp?y'3|FL4fof͢I?v~Mr?^1%rsUVnʗV_WcU妕v.MPej YYҏc &0Iח]#7㻓΢֯.l )qgtA>0HO aIQ佯^c۴d_rN(1E(uH߱r4_4?Y"bИ:?>98n2a>$J_E8Mfmq|1' ;!.9=FcEoit \GB7 IȎ Fӝ^oz#jbœz8D#>$m`/o4% `ئS[lCsɘ(8)whi7v2lrTD"3(!ԿyL9Iw,ۗ!"4?Eᘸ]?3poΡnUP7A\T/haqa$Z}T ~V|-*/VA/NnP ѝOV=FZ|ҡM[M|8f */yu~A-EݝMX:;Sv7bڊ<u. kcSPk4kuc靅";UN>rcy "aX;ɩt jg:YQsk"yC)=,WMrkyX{st fM.p^qTQX"*RpT N=dٽiO#J};X't`}<_sH3vt-:2+k"i^oQ]ܲJ88Itp5`"z85yH2rgi^8A8JZ5ޔ[[o]BR-/uT%0rAMy᜹dp;#'vtSX:joۘ g󚳕 T)Zrɰ^=^\Z ǟdR*d 0Qw/:DQ|(sC.52 VbsR=ײu|t\ dJ޻%~24Sʟ޼ٓ,F-,–`kR*cbJMYClr3d:9}E'æ+lߏ;' .*Ḩ HX7%pHawj9 C_;y+r9@)x}26babq0X}BVǠk^}z^=ڼU`*o8O#N=XK ]E3 '^#>Z:Pi^2T. to^{YXOWc8P-la^:hN{|F +T|Hs:06>@*`WpO(Vtn($pP C1 Fox79ta њ)&u7htp6 W͈<=Vڊb~҆Զ&=i7tDƤV¿u۠OM͐p5pNM?&U)a@.J W~\=I8}r~Olcj=Sa" )}A@Pi%2}-G>anLQZMk!R; a<zrbrͅ~☰zVCþcy6ժbUES8mMQ{_X)wf|:mћۊ_J'axՓESMR<cȠM7'/唜Z]:D?ī(3cƟr/iq! @j7U3Tm*ˢm-ǽ?..{rz䚮Qtd|pϰ#! G+ eZ* $tVx,{S}FT|r[0=8L֪c0yHTXLHѸLUͰq2 B{1)/̄.vƯڬ3G;M#Mgf{C8=QJD(A'4Ztևh4Ni]tS\l)iۋfϢؓ\(9x5 - Xۦ=lS"te5WmZ*`@`AZ@۟{0\կ<3!DVV#:mLKFKEu@ X @^NEuj`;}E\w(QrdiR+F~F+ph8w`7PkKU0}#2ccd2,b諐kkpz+MgG[G/vF;O9V$T$.7>iYSU1iu:|?@OwD%-HԹLLGQLx:6>zKX⩪7g㒠ȼ/ԟL MZŖDn4$Ɗ\ZO!*MĔ0U MV`gpb~t:QOIbU~ܼ**-ƸOQwq(.JW(G^ޝ,w. !Mke- +Ӗ!އƊ!$?ǔDPc6Fo9jf=r_[q:n=wS,&Qb8?՛4hdAm n*;42G <3u+/vhh .5x=&3X:t 48l]WGAJu)no\" ]rD)Z f~r;SS`ݝDU)ƒDJŔeEdUJVtHL Su|xlyc'̏X(!Z6O-${mfm;n4{H] 8! 8QhDY:|0ڥw#)u<%6sjjHKvZ&TR$@ Aaz;az^.-i4nL:)%JR髴D)X_2)6qyh2jrBC#H,`b=Pd` ¡z^eer:*yA☔ J\LUw}@DO!bD1'qBПtz]%rDGfˑr:Nbb#gPX  ޡTU=xS.KQe2L/[:QM2n9]SLCs b.xC61jz jȂb\QD:ލ,aC 2] 4h HÕ+~`z!ҬEto҆0ql@V8 ?(øH'9uR0)}oZn~$JO:ڗ6b1@o4kt#<_fzqАwJ.X^~Bz8X#'_ ph6cC)٠C@"pEqh:,tE8~WOTxmƪ`aq1޴n2HO5;^S~^m3IHGʠ&Ry&uIku MP_GxGD(!wlhDς%*:%K"mv~۬;ɥKj8 㡘ԡYj&`|즍Q{|l#yۇoGbwLkFIؑ80\U*Y&h TI:AQ efYa~:`lHΛsU֔1!YifCp}XK~1OFiK+T C]e6Azxx1[$%[[NT3@c. IOܵѕzOYÍOu=,~\ 1{29t p:V95N} SeWH ~RQ zNQ)!VSxxM'_q ̗^3X-?BL᳁,c>|Kq ߄GX%܉GX%1aKYX)X.:/xfag E/0 yH_ӟ~n#f o^( 9 k)lݔrvbXsmYc6BUm#>u֙ǚy+1Z8 _8%rzT*`)*OntFE-YR K8>F4;`,6: bImbr :۝יyMroGοH'%"Am=}i}>ʜW_㩣1:!Bs4-AT3d2#Y*sՉnM$n7I\nJv Y3A& r2VaXf]6±T;ۉ8t O9>Ёm{@+\rS9}-32c ~]( 'Z5st8b*>G_`|\j0'l&l|8=A{m8S ʌDfSr 8VGGUq[ IJo]\DZnQ.11n2aܼi{:j.k@+6pN@X3E[rc}.^FW%uϳ.N?n_͈'8ߕ/uH닢O2.BJ{/ Ou!NgY$崁fL/5\9n^y\Q5{)'`~aaz!߄ 7k8tʭǂ V+24c2ANESO=.ps\09oi41qB;m%u6" 2{ZX OSR}<:juQȺWea+} ۶Y߬=zR"6DWchrtpLsp06+J nQb.'[z̈́'LfO'#`/_zdW<4v;͠kجW'A6Q]6 2%_NƓֆΓfKmeDUhL fRLaxu6U*H6L ^kMUxFG g^f!čfmVkNwÕ)ēzɣ^'iC"].rf\|-U7Sc^/[+g0 X\CXqR*EAgC&iKcGhn*R[2_ ]?gj5TEQňKb# QcI0C ǕL8:}N[])HddߖRRy/9fVgpչ3fD:ZaD0Z\=@&mg2|SP P2vE Ȭ@ڦܤ\!>N7tX qr[JWlk (I$rbvb3 -K239E;cJͷـ=%4oĤtbdvuf*# ;gH[BdhZ֭:  Tw^ԛ%r@ w"{8NRDNq3%x(/̐h<z"Y[EDܙf$R̲woXͶa5lBw݂kYڜM6r xnի&:5#ۡ@?|߱`Vw *Yit oWg蝍DHKPp QͻC—R5T$ 4DE7k )mش뮥K /uA &b/Hg3X[ǖ;a~ل3`aӏqҡ=9ÓCuShFUR|2OЙ'痆(wGHӃ GXr|Z;}ܬ=5۹=n>z0zqiKt~,"0w'Udp[[+5XjQ B7}L<r$sJ|0sgԃzZdmQbNۢ;Œfnm>s Jթ˗@+I.lNG?|P}Qk)wAh[}ac [|F :؟y$|§|QX+?xY|^¯@ +MX#ceN }.yk"KCdJx].ڄ(W墆w VS m:xü{2sS![LA",sng6{48v>4 VӴG/E #?'\\ohm3/o t'±h&l3>t$/g1lc $mb >]_sIOێ"%<[R4i]CȨR@wv.XJ.-(5AgZHp޵{,څu(L8BĬ>#da+y(ЦkLsfOz !^Z$J&3+4bKU e**z2,W7`;VA0Ҍ:ĄnigR<V䠫6]Fw<NAK,NijqS{ʷgȸh6?tY5)LB #5j&~\*ъlX&ڽ:\Bv}o9H^qmnDʷl1~(,~ce5P}NJiK(to` efٟrX=|`nq0˳M+"'Y\!]ܴw_F0gl#Vq3kbFҔ<}]%kյ̹i7'5[9ludRIxљ`0B֖jiM1Hrߚ̞2&hSMK9꩎8P mZCt]wd! 쎕 qpnYJ`!頙KUH O:,3r5׮S~zBq!: e h.d1(&D=:349bh6+ -YQyC13Mۄ!c <¶U|+IC;C5`A7#)jCl l/`si=_Y34`irYIex.ՙuj5M1?i!IÝI:ӏ( #2#;wd#\6RP8ciV޾ 4m4C0{*Gm ۿQt6E5ĐMRƇXyKxU%A6\I+9Q:{F36+Oc63lJ$?v\Ӊȟ( T9474(k.e8.z, uʄ@w'䯇@y4FPDӁǼhb)9|w~Bp֓б2PP -3A ф4%5@J <REO jV"KY*FI hǥۈa'Q,q.%H\5L 'k`c|; e[hn R@6<ɶm}jEtqb#>y B|g{'4gIʳM=+<_1[_%;`dGe𧦢8Z%insuh)R:bͬ:J:Baze [Wcyd`+4XS7 kഛzɊh(X{JkE2FMLLm4#aU)mFY5vQz9IRB]]7Ft`Hca<~aNL|K^4@WaRa8t9w<;3dL5~663Gt,T4.$XÖ{;v$,S{Ru24 Hn*[LDӮ&P>0mz^|/0p4؁K#zθ=\[ PcK>M]@"b HWHB@%&L/}KT- lUD{E}_NtQ8g74nyҋϪ<߼=4+ GF*_-w&88O-a~ڗzApՊYC-&Lu$ U/WjrWLm22W &LPѼAMiB;}(.[ʼ4]Ux|y/;^.'>FѴY0qCjpw4}s'$2b؍kP$ )psNC#3H5`\5Gdu $^* 9Fdm2"O +J-EWIzʮh$a q)9}[β&0ˑrz7o=s 3nSƬq*d(ΏONo$Mr6hLusJZ]K,1P%-2I3:sJ_) ?lT2ɴf2 R Y:4Fם9IRS˜5d!1eYXH 52>2k] '\UpXh[9">Fb38.fSdfbtnfIAZ Z~_0\cxq$I TC #Y{BA̘b.2' NJy6/8`Hn\J|΄W=w}AmG1+9 jR7k>pғ;Ys|#WZI&ᦸ&^##!H 'ڐα͇bOLzn&,m]$L3AƠ #7l6p&]3R\aT6{tS0 5zd~G1IsI)d!4=v #$-SFHza+; 1ahiD7Jq4ɀ(%#7bp '~mZq\|@mԅ3S;)ǙGD+>LeR0ݷVslܲ<ġAn\wU2 Ja=`OcCS@ws@.%^q'%d.k={ңGuc[" |蚅3d]v}xc",%:ue˚g^c*2!`)(T>X2[tн9}j֨-dyI6jM ytޔ2T@t ?`)fNg4靮A2,F)W|^pbW[ \*z؇譂̙Q8#7f#tkG[R/%fsv=͕C1#R9c S7\Fβi'JM=14/I(v{((>Bܞ9zu(7"ho_vfY ^1rvP.ɤKACFArþ5 OVXNAds}3wҋbMѠ7chtlm+i ̊ !]Iϑ9.`ۥ~`oQ0M^~Y~>4i  kzpvFYF\$6v"[4cYeY; Hc<9P{US(y_(e2/#z/w<2}򬑝884dU "):#)3Y1k[(c^bM_!mߐHQ^f3gӟ;o(E[#`1gXQ q5iGBXR-KhY8]  }oHLP m6)?IcG~Ƥyxt?u%L[llи9P,/ k8oZ"V@xzZ;Sԏc',2嵨po F2+d5)%@.{%;!]'k-!0uH#-[Zb1y) jo>d}8kE}?~z7RHn$¼?{FÛpnc?;w)O6?oV6s>S[5V Ӳfs6'`ؙ>;n鳌]+ CImlU (Mk$EL#='΢"'&FV08A6ȱ:F,DŦv9}hy)(AWO3bHAwq.t\f2n…p4κN9,l~  t&6⥓hHYM2rJF{aUdѹ弶x>.|t.F:G#5.SŔd߮ x<IcJ fɫ7 hF:\w > -$et4_ۄ_Mz RxNϲAtm~&u?KvI$ flP1i5Ф{. iCm,Q+ݟ njޔ;UV3@I1`Ɔ 60f*~o5 q./N=%8|>z^OVEgVSr7%drp8.3( ት|N{IG`LcӐn]Bjr>( L k0linJc)Ɣb" OJ['q^auz>ESo=V ䷃Ǹ`~.a%gӡ%Ȁd౸b&>PͦH Ü V}㑷oiGGX;$XG$FOjS"~ᗘƅoU;(#훣O1YuQ \"t9H4Y&qH<MGDHܠ&W `: K 綉AG/;W9_I@K.[Gn”)ߑTa#lI!;Kzl.?CYr_?>/|=(z*b)2GOK z2kc]|  _ß7K $^3bc!exlD,>ͣd4̀yU>NѽLf!sć'n`u:=Ff9h7ʠD4a5ZAjזRdYY0(RלGsցGIiq ?xi`;z.1N~Cbŏ5\J;"kI~H&(`e b]Cs ojyLt'=O E8G% :gd`8x1F՜`tg%Iő'蠔r ӏa\&#\Nͣe;"Cgm1{Zu0ea;b8(faF 0dI8EFSaoFpC w(UvPTR?/ONV:н!~C׿#LI1jgX:Qs~uy?* ȹZ}#.1ɧ~|<>DxX`ɴ3nG1FvB׌H/#P÷d[  'kMݝ8?c z}a1uNlFC|T?>qJtS&1 dpq4k;yQ~h na qN۬e7p(w?rG/_4kj XږtgwW9TDnK`CO;x8Gs̻E. iVII7F A*I_zi|m//IJg1|MqW2V&mi%wvh3zOK2_DuW ي_ mhޯw55Fu kX[BZ_@UW*k m g<.{:(:no.N ɼZ- ӱ5/T^~R1;X~A^r|sjtCl!J8߯Dɼy}|٪Պ 7ӧq{\%fgY)kF@h+x}j aaa@ T ژ;֫}`'"4-/_V" a{w-QR_ \wavJ4fp g$%.*$dJ2lO)Oc`9|I4!)oN4k%Cl<,q" ρ-"k(؞2bwb7=yHLl4'k#6x69=&A]#}PhδٔI䌑ׄ58jʎrLΎxprvp L,ho ,׹4Z;`P,59YKÚp%V è/*QqYjv$ fF^[wr0ha䤁S&pHm&a+ex;/ 1_4Cuahц!藸I T^`qBQ*H1lfОFsq$E(4jA%  2O#4N[l1evQȮ1,*8x#|?@UWo5#@a*7wA#9=u뿵q=wH,lg奬Lq՜-oS[BX.K~Ym_RhNшҁqVW:mR.;{/ӽ;:Lt=Ͱ]v#q7 \/ no8 ܴǧhws<݁ [t%7YAG#ϰ|<^TEWqu09 6Ygڋ˧q|щr^GgVQSV,GFVF1Z_3~<=G10ǯ:7Um5{/(Da':acB6Yh*bEM۵﻾ٔ! K(m̶lï[iXkF@ d䃞8$Ƥp #6`]VF6O1 pw|vJ<6 TbSra.O7 ~wT9tՓL{ƳMFf*`a_%a(h*:8Cbl%2vt̻|X$M|Y_{mmV]@]|kk ;ϵ c,0iV7mcH n6w|Q?".ڢz{fX~v3j.cFɨk%hΓ6UFT1Z)ϕJ̻;^^mL3?:J9ǎ8(b +ː+{~%AE:QR|\("]Њ"zYA{Vrm\hNpNg&:Cכm heaG\^. Lizd< /\ b1~M}I6ꔣݿ<xljkZ8Iۃvs:T.58Wk߾xGMVd4#;_͵#bY)!6qJ`S8T9Wv(|9g6z`ˊ Xۛqdr*; cx4zrfUԝLl1Qgֈtk>^ZB[i- j16ty1]~7V$ĮAb@P)edѿvąWA:yaa) ƾV8PD t_EGjԎ=l[FXl6t9bn#:6CV[+@,ն R< r0仰,%sMe]Ğ"T FȂpwNH ̋55 8t[/.+V^ݓWV-U:S8׌7A-|1vjLAZv:zX-!EgO%k 4C`瘯& I8.xΣK!d,8O][ǿG716`6@Z!3Iw-XR.i`mT?!=4}X#d Y}S3tX&'-EL-3S~ߌZ?|؍#WU=tRѬ?HI=~E5W5 ee"p2%JTci\3 Ux|z0h'+UMEW~Dx4]X~[pZFBɝ;t(g(fk*eC{ٍR'alCc%lDΨ?)&+9sD-y6SRyzoݲvmOO( 6ׯޞh8VlEUGPCCH= *3PЭԣ> ^&+~4H!8 oFb@UvndȮ*L'\ ,f;tIs-?*N#G$ Crca[?`/SD ?#ovd7 ڋ{6Cms`7(?|)  Zu*"z3[ j6 .ȤR$^%R]ubET]gݫ5?ti>>?&][ AǒRI?P0Z ?ݳrnTD;.1Tojc.?CG8fpښ0(RT*̠0y$ePOHzf`Yԑr_@G* "0hB6jXguh[$Ft@]#WϬT=6)t Z-M:I pBDiOux)[x)t x8h/TpQVW1hn2m;A鼜Z`B. 4fsw\י ݕwUX&PL6)!t;ܲn|Йi[fUdNf,n"AE!4"'F"0-v ,$tQQ%JU6T@B+R9cjHL({͜1Ifcrj\Dq `(os4ݴ;mklS@x{:QZNrJs*%DV}'iyuo܎Y4yvݼ#k~42 o?E70O*rAwm=׻;z9Ι#W'G+<67}_.%ۻde@߮ hrX^wz 8N ǥRj->]QhR6"#I0`~ڋ&H6>./*ACkH v ƩxD)Gmu!e"tgq,QbK 0 F wv5fr Ad;5׊`#S1q ӛ_ ϛ58+O">I{4@єKh>EA%1߅z]N#1 y$3 h~ 綁Sˢqv{qD"t\_!HH.d~ ' `^ SU5&҈='9ml٬egڣ@o:9Gvz; r_5I!^4j,ŕ$c\_okqj W)?Yk򱦡HGXL7UkUR yk;!-sgc7␦J&l qF: w$wt,T]Jî*p\YZoFQb)YrRU })вT5`\*/!]Ĉ||x1}I>ENk1\08PF1N[@_ZPs} MR5%ե!*y EW!~wdzm3 MA(䪃nTɛQ)`#46ﹻݑ\_+1B9;1b\tF ;XJMW=_()l|Ie|%5r z2U)Т/2fH+yyJ&5zл=W:hL"S{_V){iU1kjYB= 6g3 ^R{x{1Tg&){U)'vyw둁(ٜqKJaasPΫ㖦ֺ[9 @"!.x `U3A MHtƝ R\Ta|W7S5HXGY}!DJ/; dLeEv3ۣױ68=j*=fڒNeU,xU}3:ܥKg5xA;dKquM4k=niN=(4) rי{|KlUF#2M?2ѕԕe,R=p6/zWbw#}Mu'Fqǚ v6+bx88#ES "$Ld2Zajlb]$Z$;@ #4ҏ`ǜv}ꊢ^Z z~() Q-:g<$fÌN2[fm.0*pL6dC(gFǗ^oлؤ{/[dQL S51 b%1(|] Ngc26N%MV1z# zTkRcφL*X CI?#.Y!d]Σ)SDj|<C\1Y3p{ l<8Gwv0|_ 7yj:P ,7b Tl3v^9@hVJ4\7л.[t$17~m7{gj' oጲoBG#%R;ewԉ0љ&:q:tvw"mbFM:W&DIKG}&5 ƺx> /se*! TX> ,' V;#Q:P;%H"΄[LȷZTل/{[?#س#jsI.J [=1䓨:v2*awO*6j"3AnZO # K(fQvQKm.ڢڱ;e+'Zi_VM2tr , 239lePfP՛6AW`yt08'±W,.zV c- ''M630b[vml:OSoás{4ZuQ|>V'Hi-bCxTU !%p*،XJ i3!I2)wat9Tag=ejvt`â4M (w b!'[Mv UWwPrFcS؟m+Q|̿wwo8N*9"{gVߊN %kHL`uÃz];RJFV{/q p D&n&zrRQj8oRE~luu#ǎOP+RaƔR>P3uxU8MƦ?32:= y@Xjx@cLбaxx˻;U!W|_*|S8tnsPz9\!tMi]MSo0~>FU']&w(3$"~%h4/D% ?ûiyK:gҍ?O]cYT\ 45v0Ir,z&QQjAL6Ȧ;#|ͻW{c2ap-7xz`-b&uxX 'j5DhI'9xIl}:L+ ~Y g,+}v miuCŽĩ RS)<<`gz:m:+Bu<(:wwl/{'Iw ,2L7ә w^}낷<؟K$g܇g4Y>H:5S`}H߽%3AJp nxxC>5(j O#J!(NY0p{;a!N7O܃=zs棥z[D <Żh:׾#e͑' ?R6I7X #JrFf.]5suT! ^ ]ED%rz/I8r3k ZӹK汵ТigP# gҪT5u90FXCephU$Q0Eu1 + *. dVǥm(#]5"Ϧ:D@ϧsL:O4ްd6vl2]h/rGƖ+ p4]!sC)\PnCAg ~06hf? v>ߪRtiP5']PLPbA(L$QKy^ yɛtM@WyLLOxڭĐ)-3gpEc 6+iID33.15x |2=9S<\7\Ӷ?Rٓ_~KS㎍1V)_@%d>{8fwDޛքMX `ndlash7/}aQNwx9؇yͬrۺM`Avv){-P"E;J|({WpOc% `SRfa] K~A5ؙiP<4VMB07a&pMMiM&hbk8JP.2ID'J'"g91¨2 4 1Tw#Twcy]6Tv!r_}*fE}%B|*b]D7dpw 9qw2ILܞ^w-6Iӳ2j[ϵUJt=Vt/@< c3i_R6[,trztVX#^I)7l9sGLm@#ೲ4q54RŦ1Tg1X˓ZjI -z۴31S'E ` W=yQO\5a?#]≙휅o1V^z|4BkaAA%A_ /LbPJܣ`|gㆭ#e4{*1YvxRþXRIQ߀5jE_Lc``ndHѠnˀN*^N/akݬmVGQ<Nf%Seq$kr-Վ(rc\v 9H7sNȥ ,\JN!J&:-8_a}nbp3BX q }*y`V kQ5dz)}F97%.܂9ގ54N3F3dY&i, U2evQz[kMޅ%{p>IɈTkH:IFn-نGn s4p^);612 񅧃A6,hW AL'DN7RI & \ds0ɉXEJE'93:u5<} ]0`Ι: 4RAhQ lנ)qeK k؀')tyQ̫%/-Cc=|ꕲ >̣Mݪu:]d%z b1qd$-ҥʇ<8Ջ2FkL3F|t**#.E Ir^/,,30+1F] Ѷ>Ӽ{//'/;mOۘN mUbK`B ]]3`.UֳzP Df76o9_a^Q{IPNM&ńhdý vOd8(& e3Bep(mCLS3\K֚x51|Gqcܹ&q:"Y@ypWrhb5lS'@d&} H7 O%68$3JA?,r[䅾Zj%_{,"*>bXDp?e {q7f^>~U/hGpw4Ge(1&]1fD0%dD80dP&ٶ`}`@AlY7Y`"xT9ʎВg@z,)0\SRBm"%6iܟi]ٰV Y ɷ,[#6ԃЕ̏sk(+*)ɺ}>2` ~bb?l5K.ؐG)89pjRamYҟ p̼CJ2\Bӻ֍;ӬGYX2e]ei_F`"fC@&>)2su@x4R껆̔՜ÚhJbշ )sBU봯>jF3敿rg Nsf%;z.J@&ι&_ BK:9\\꣙Qb ώF ma?̨MTT%5KsT~.R+|Ju߻\|r/dA~LXENÖQѡ]|,lVT7zNU䅅oZ:2AgI/rd>&+orx0*c+z2=dss.52z6V[إĂiM:ݨ,ᰣ.mv=PZ*'=IF;& T^!W'؞-d%Q{=k_Y? ż2ߋ.xpi560+!jptv-IQB"%S!gl '{YD;DZsA<tY|} /[K\QڐQ%g vhtftd.zn[V?>/uu?R &cPvar{Z7٬26eJJcخg_hҞ,Km` y Cn&fDaWZYk406bgwSb\ n=.J!qx+X9g-U8F_ARjRbjo߼ndbﭻSlIaJ;0%_DKh Sݑ)<8\}qe|,Ruf}#9Ya99{mp}S_O]_Ō%>=gcLD!{)(̌\Sn6!"Idx1V :&W%`F^>xGu͙Oױ6`)b|+kWtZ:n}BSTTWYbmqWOo8A ݐ;r`5MCoۋ@zS%x;i P8 &ңL؞fM4y삑wZ\ [ũQםp>d)-#8FxS[&TM(l`XoH  o&;OvtH£|N[8:h+O.XpY]0^sj;Ҏz@<hG)pF%T`7(䢙ƣ'VA|Džt~0J᷃䭚(o>WpBHTлɞ9cOF\ I–QDa@2Ϫ NN*A z|R]>*<8T+yEV8%{?iжO1~Vڪ7s|JX x<[-d,HK5AM VkXqeGxx քhbMA$Г:[y.>  },p\.DtBV9Vy<3x*wtB9 Ra:~d1:"{ԗ(zFz3Xۗc.Z|ߧxݹ p;CQh<$a |_\јTSL,D6kDԉ}e 7㨐(C?׍Ց샩مRΧ/3B|ojJNodI24mpcVoj/C/5OƝxOHǽADvdYvM= %ӛ7{ɹ7Hshb2Ŷ2MZkk gO7B޺5G{=]qlVw`1F+E=Msh9|C K5.ii.jsIzhcq6эōn,mt#QxjYUtQȞNi9I'z*]zlp- &4:0b 1Cu}GߦS wZ߁5D|ƣ_2ĴCg)e^/`v 8*q'8W0; PAl<5[BBŒ8 Y3l027!{NLrƉg|#)fS)#+h$E?}ٞXZlڂ$n{ Ec'6ҟ3ͨ70`œFDdd.p2 5Vl7G֭dp5m&~LhA2\^j QœʹIX1ZM^UŘyTK刿mͺ7,QьfܟڶAK8siJ<:-8j֧+bXߪF'mO$"e&qv3 ]i:y AYəUK'g3LְnP.Pg ȷZ Fae#,vX1) |1 |WtlyBcئzH`:TH) I] "$ '!9գ㉔P\IЯF{Yd,hQ:%3 aak#ȬGK%Cx<Ȫ,⌱azU/tt_(QZc65NeZ>PS McZu>hU2u9ԫ?:CMvϓ\3X?)e}D~jz@&V7˪|kv (rdBhG۔Aw9"C/ cj9Oj>U㌠ Ecd#xS@v_hu,ܓsr[ A М ~ٽϋסqφOtmq<*̄e4xVVR,C(8>cEt%"5X%_wQby0Nr¹fn%i /mO;`Sˋ9: K>n $XQ"q"U&A@&w!bPɕvTYM{qUO'+= Xȥm|U*$L̰s9R`{;eH%q16xꝜj\g*>OS7ѳz#Lބm-r/7ZE__ZUa?dy\aX_dJLN0]>}n /_+q͚W& xl֛D}!hڊHs|">˳_ qP2-I/<U/w9taU7f@J^Z=qG$)v} $SFGO3ztE=z_kll=|# 7 t7jBZ'W=^b9LA{4YÃi^* J8 'ox_~,/g(J$w״_2=dOvq[-R G񾑈܊Z5YD̀J9QQzFrXKuGS3pRֱ:!5守rIpՇ a`n1 g )b5XnZL̆ !Ȇl 6o&YHsD@S >)'61PEQSA.&t?Sg&NpFDNj-+ vVHFape^Ty葅8ٝ*]몧ur"%>Mt.Љgn(/gw ZU$w^JK4c- XE-n%(5az`-LQ-1Mnn77>ܬ=xT{UX;姜JViǝ'kݽ'ͭǧ'ޣ۪pR|W?-XR87K(Fܴӧ*?>_P߾9>ZW;'o{4YTnSw&!ܟ8, څ;`RND!7;Vb40҃]ӈ5#Qٌ PZVF`E-kI8mcGNrko>TġV$(%5Eg2qEt1-׎pxX2gN7jBs!Py2̆$+p2IuЈy\Ж09@Swx|6+#̝Fł#UkZ^wn)ȣR'n d YloGY$!VwZNZsdCQX;1څ_2v|s֐人-Fۛ!P# a.:F1jVĞZsÈ1Rl4a.c20}dL4j_t3J54Lga%(*'jN!E``\mt'Ϛэ^l1oC^"3_MD4蜎9"Mӆr~67f*z0 |fK@&%FJΓ )/Kiֺcw*17k00R85\h(tof72է7 U.,_MB\(j{<(pFƟ=Y3766?/[ZՌְiNԼ(ۍ͘Φч?J&=r%8|J햖{a/[k hU_Z8S33A+㟽yOYFzv5#M j'VFfqny񡴙p6T#iL(nyE~-/-VPb- 3[IisXtg-ЦڰMō2(, Lo:YbtŽ%~y%~ʃe<3)Md8Ǟ˅_T>n&sa纅O=a|"ţɥyw;̆:&nrx1 AGÃgjl[ |T ^g2+&_uyS-Z~ZQ5x|NTHبK7}}yus2f|X2U1"&! +âՍ?Z+,_^l$cKϾn\h@5deV'4fk*)ڊe V-bY^-/ȱjY\UJ|^%ep#3>ϵd 9[v1*gBv(d=<4g/q]؀ۢ~lIU6Mۄ6hwZ_*QWm#ޡ? )BcU[.+JX^ pW<նQ]xc\ثDL\A+@ '^f h5@#ط<\ C*u䨙zwT_{*fQ?f_Md0īiex†1+\j^cMޏGqKRi˃^b)^ZFZJ= )!Bٍ39D}oDo.Ō s|V CyɐxIc9'UTGЙ~⤜غ hAu %a Y)c!0ߐ'ѹ8<-l;t.Y`E`fCw飦\;WL n؂iʎs$.,IHhW$[6!r%gl]f͸c r!|MM\ɡd%@5`KດmQR^X΃Yk}wfE&/Ao>ghjD|S'P/ VG[M3鍹31p 9G:XazLL!n~3k(Ffi(G-Χu APm`N <0NJс.f۹N2ybʭ19NGw0SWʤ뾳TRvq`%nn`N;;*>Bo,<ʍMN3D;/eQh7Y`!$O{bnh݋cwV~ML EzW: w^WP 9؃R(*]C/`#ʄS|6ςS,/xMDBqx'㒧Es` ߀YtpJL7HeĨCUTM W'qKn~ؘ-fL˝^L,[i `⾛e(5UQ./Ct \ty;?~XxsrsPv<("rT+W9d|_uɗ/1s==L$:s\hצ2d0 L]Pa>fI3/GK>SCۜb5dz$.畁[r,,fF)aC p5'<>9 ۔Ђ5HaK=eT2]ýi,GENoM(Fw'/ʏs)5f!RH PG[nMK/k33Ţ_E8nE*Q%\ɕSu2?ڗ&:w+`U]Wكٸqx q`\W԰tqo>ǭZ[6+OЩGK ;_T}2i&aƱ0O43唶9;0FS1`/Qo|:jeZTq _?zUe#"{6jcYn~%R/w me؏GR4%q֭)>Y?`n:Fޥ(Tk{oݡ(.nÇR%@}}k Kw;lB=_" p>57#^|֕ȯk2I0,d*IyaRtxG>hQc̪|[ZF}!d ukWіC1ߗ̵u*ĖzU p&.a.XP`Wz6\y4%l092d%gח|܆cnE)DA*߂z5x[p e7Q*ZMfO `e[a3 mBe) Jgl `xnޣ9Lbkelk,ǣ.P-+8 SYcv7%8՝ N7{=ҾE_ʥ 2r2Bӈ ?90qS;pJtݏ)d=@ޏϜ6$C?nm',A؉z0q ϜΏ8xw/6HwxhIHD ȤY7;" jjƯY ŤH5?p<$_4*&J_FCC_H6AͤB'MAJn0NNJ(z@NӳF3ic' Rr^X._f! l9.d,9y%-M%64lbo7# yZ{:n "hԲTqet)4Bʯ$ j=.QAŃ;(o;D|_hhmݬ0&xHEKbr7:4"D鑼I]ޑ_CVy܈2 owSTz&O Q]̢[U1" &G EsI|m>.&rYS{v5g.$287 %ϿTO0:IM=uL2b"7sȞiT&80sMgY[7U+7 U=ڸc_ԒS" #> cPJT'"Vz k%tE<}ܦ+6PinyYl\DWiaNkނjwܥpPEHL(adMr cp p tfH h&/k^p> IssߓԼ|ifV>HaP'0W IhoK/U+|-$&*(yY6sBuS9LrZeOGGq*>>Hh'!,mnLqA*yW_dCNTIVI?3gRꎢEiٺ) v͹J;]\ZX'#J*BJP[޷w \uyW(uCECA!'HU*y1٠y,t}:q BP:0,> }x CZN9BA*s=⩓phWd"K,8ib3&^@FP8WMJ5*fD]+J#Dz0l!a>qTSz3a]u^N0acqh^NjneIv)QGa|0E[-ueT@aMe~[Q.^g4Brh8(^x}hϧp)K2W~TG; b0w[:WZxQTFLMF}q# uG&t|`!Śpz;.ʡm<*r 9F|;7 |>h͐Gk b -j$#]Ux VRyAz$nrw9^1n.,!Nd~:y]h(So@)Ep z]~pX@Lΰ_ pWKͽF]/ʥn &mo1\ taWAygrқۥ-ĝ,Nu]y1%5֥ ukWX%WjUhAq谟X&VˣR]߻^o":;QR"XB62m3rR{NudLZ 0a!~Ww׮n *yGMtdWb Ts!1n|dJRq<c![ űk2LNep mOԏ%sVakNǟXBÏkx?wB:-ҕ= r-κ~TƎ5T7RY{VДe W-4EP9pe+E LBw>exX= $=ʪۣ7'eL ,Rqu%lJVP/'Tp[O.jޒqZZ9).XW2fեao;6&Y.3էc|!UHO9; nH&4[-JfScIp֘WD"5wT~qamZx_((rӧ.E2 ћmkdM.%&S-.D{Wݕ̴ V `*͏\pv3efivđ1-Z3&i0*Ϙ6Ps|+Lnդp)ai5;\s>/ %w^a䕭pi0|) b7Om+q"3t+e-+]!6~>ݬL.kz E*mwoɻMEvp-) ד"Ĕ,^3pyO?Y9V EJ2с.g/vgѻI;TW*!C >*P!Luc>T۴#/ozGC4~ԝFWV).1A .֟u Ԯ65\ꍼߡ*Oi4Q_ A1Y_\~YX.Q.g` (_h!ԘNJ N:N"a]j\" qG6RI4v vNd[ |մ?E:]JGM J{j 9ƴ-R^%&mX-h}sЮSҩVak9:<8IQn1)ԙɥJî|g$,WRqOy `jy[Ou^V3M}CdZT|#S2A7W29?ѵzWbT~}|nFݓv2 A'3`ʿ/5MTHpn6p%OQ)90 svљōI[8Bg%VT{,a-g~ykh+ 9釧kꇃ]t>Ӷr w|XĈq&ϟgb&*jT<됅XԴcH{\l5Η>hSvev uHhOylĀV?'vLvRnLec7ҐSh: #m<0kv)0~'}:0m]RB޸saL= p luq9ςک9"3~vmCSVmiXCV= 5r|6U)͈4?mV&d-;b)9[Hf;oxӱsE|*s=BFx wQzpNPN[4k ro_휼xsNp7<4 \r/X\:iu@lLaLf LX cLA7 8j9w >҂֠ l 9F1b;g? nҬӧNU  Ϟ1y.iQ7oF}@L3؂Ty_ZG\b- R#W(5{9_Vp`6sZ< OzMuv"JQ7N`$Q)WY۳,CDYy (#JG Sv؄Oܾ) \?ӧTXQ3<7i"[Hknmy_k1nHoׅՀ`~J˓Ci$4^tGgԍ\;"7*t$X܉$w;z%}`{{jvZSATo_KQɲ'v 4j h4#q - ,AmʐF"(^+ Gwwr`s2B0 _GI`2g^ zd̗ ܳLZl!ܖHMG:n ɐG{5ewyΫ%uЎedQaٖ6BMHhiG#jhQ2e z!1~X|l)kM־;^5;o";(r֝>홫}<>W>ϞUoM!;8s9Nbâa XKW¢ݚR5Bx $4V&+U=g%чc&@)C[Lۄ-V+eg^R\p= 0㙞M'L׵N\T\y)@uxFqrJIqPbY 5Bm򞌬߮L'V8@`d>@4mpݍnY] `~Lu`WĊ0Ċ00 sv}M0KT*/B,Ism^0sffd\*.ҥ@ /(~g+l:27JfOֺ˯گ~<9{KEa2`%bNf5YGW\lHAh`ދC_TϐkD)3'_R9|a:F,{%'8o4?1$v(GO}[ _9I M\9wh<}zƃhumquVZ2w(֡C{Q*Y)$9y*D Jr^M0jW^X%IE`we ukq_ Ky9Z) <08^N<ijğv{ ]1ֶ&! 9\}ܙԳ)^R}f//j5*xJcf^{?:DEőJ@3]8^DM;Q>?e7ɗ0#mc[7lhCS7zƎ{R1_j9>*yI+աle拾1 .g[IJKfz6I*HU"ʖ)tx}USs|jMERot߬Uӆg 8ab|v0F΂l"' r ?U9Ujv'A6 jtxI.}1p*(M1AiʠWT/BU9o5<=:!ۑкƊIL?s?wnyid:N](`2@לh1Pc+ Zx5iiuTX7-%%0Zox[2vl%"du[ޚi㫂%~ގs۝AvAOQA>JB>k:z D>:=u8ug1T\:w]4)GJ d6y3i^hŢ=ZыlbQt omI0:STSE@@NTjl%Cv{l7(Вc}؎S+ݳ_EVeE!22"2h#z I4@x,V&lOu\]nmD.wC 91M8X@d"U2Zqyv L Qh|ruI xj1R&"/m=~O! 4$ajx~hP`~Ǫ/O1< m Gh/QlX1Dtݶ//..RGZ*{xGg_}vH_bd#f샋;Go(JiIڇH1߾ mKYfAM ]U#Y[&ͮ%-N}^^͙75Ŝطt fS G~D%GVa"Ӿ`;d}-h\ 3i1R c&]%XYg:\JUE8Uس"?u#ɑ}0j9@#xc_:tY6SSߜQJtw>t1C ԭ̨j]&/V[^ҺaҳW &5Wv![s<C2_=KP)Atdž&rc!2vE\Z_JH! KBN$F1Z^s2ӧZ6c#%_Ixۓvt|vp|ryRng6{G>tT@W807#a*!/R)*/.7ls 3/r|t̅UBA8E-:#D͢"F´, F|"ݟld 574 Mdίˎk|61^cF*F,)wz(1!@J9OȽq-dh &`&5֨(2. cFE8F"(Ɇ7.iX?1)r9j=(\HKl+0(۶lp ϋV@DV;ɫq5+Cywp|J "_Bwgϋ{҈pO+td4 o\0d`6h 2N {x &eCgws؊}a26i9<]w5x{cxxJx ]zOzg'?7\a,V럆wF i߁gsU}m 8+^6 ³C`C4<5}+£0ūꟷv Kb ʕ(38w6е¾={rvdMr*[^' O y Woo˅'oש׹/jxw\2UJ{\2^=.wT۹/OK%&%~:)]*P9rұjDjqs\mo蚫~BsA wO1#:L/npvkq4X'\8o.k&)p҆IUBsMK+n!c?Nr5 &?N^8+LXeUW]u{ܕxT#=?ߋUlFx7?29omߞ0a=T/т2b+Ly=Irٻ5&䖯魈=rؼ q:RC+ZDI~}tjr3cvp&^!v^[3;͗>&MO匠a_yn.uN0<t;&efk Aŭ0=LQю)5 F*}vw~ |;MFZ#|"]M|#VPX-TPIWc!Iq z*z B_c~) x LPޭl(f+?\u,;\Cfoo}j'M'2pU$1갚a5>l~-oi"Ư`\(Ii2Le{&rA9iMӝҕݝU⚹(N"g 3OӴP N/L;JEda-Cm=JJ\AV HP\^inΗ֙чUx㄄?t5P.̊E*M=; 6=NaH  ;i_ǯ]I)>L6`ȡsjDˀĆK:2rܧrmt-?i4l>M"2*=7^?yrȺp S=WF([ ;9#\sI3VV/ߜR;lݷW=|)Sݑ%-1 J٥!)jՁ5ԈשG[GXa]kz7%ۅ!:`meHˤ>#<ı9!mͣ4'iO5fᆉJk8-{\09ϳQ9dR%U;->&wn۝}1p[;vg}{+jrjٚfX@8 E9fG(9JVBSx4Cz6\ϸRF:K:M'NCPcera Nrj %0tq{:.`P_of6լ Z}Ҁ0e]n|Jj"wÿzdBFC?+w5>K5TZYE6#u>k:E6?iVg/GYdzl5YіtG)+Iuȹ &$o\k чwr'Cpq2G[=O@[ նsJ@a= r&e },*×9>$w -@Nh8%av5l+^Eu _8h7t^ M(B,ֿQMwr !aOdå.+Ml|nVo~#07{ rýOצN!l7x\|A+b6b׿1(FXNkΎ)˯| ֯eXƽLopL3M!X`G߹Yӊq7) *Zk{<> 0K|_X5v6(]u啔SfK6AB6I7#2ʳ U`Zn}w'`Ml$(ў/\ЕBb sd6i$Y!&tNjIC8t!E<+8*~,&rêJ -Z\ ˿1ǎ1JKxItM**oh(bJ1eA5X@4D2(24mkv`q{SkZWjծhehkE&Hiݍ<{T xm*}eK^/̽\SF^\۵PvC7 8v@ʣX[?w1J("vˤn#G86_}CZbn>/07-12l3W! '\¡dsMfV`e1% م>Lc `Xe<`15#TґW?pXo:tܦ&"]Z_37\,;r,Kb㕷8d,5q>Bgt6.ʱ?T_d4d x TG7`J>lՠΒ(J9_7ou&dXXFŦYʏb<^ Ogcd'`3__*2.@Q٥ (XwX>I)O[ );GP'OmV_x='[HY7<҆K8ߚᕉCLc%!_(yCTH9톺jmҷFWk9d̬EuME2`$BJ觟Fݛ``]cА]^[İ; gg u",P[]^rN,3Dn2,B6M@p QX=3̪MhȦ2ȫjS=es\Y *s$ˆ(mB ϭ bw_Gr] 49@w_I@ͳc{b,g?%j,$<%{˽EC|x 20L86#_9D35((r2DfA޾JQp~cdˁ.lުo%VMzfĻ)+I_en'AeF9Ɋ@2M`“d0pDB}Q_r)FLH:ˣ@='r-`j/j'( $L~ׯʳ?$ l H^-;>Ĵ,Dd(rm=ool[6{?sU D?\Kq \`Y&9OX>5b&RUn0;}zsu{p.1PjpܵoޱQ_3D1?oE6e҄&Yhb@/<_ QT TJ2J(U@ʽo7^y^Ȅҍ VĆ2h0.E$q6>. fAk(pUA#CGϭ h/s*P!WtԳ*AnE WXT:xC0S1, m҈ Y ZΒQvK؂->7Y_SR} f݅l<%S:jRInSd?aP-DQ*(ݽnʜlupWY#G7ӥTsZo5PjT"R(ggđJlAan(u@է<_ZoZEUP T?3 E/6*(}&S]M*ku*B[:L,jTbA"~)Kk 박z"MѧF)j#8)—nQJLYt7 ,81Y@&z 61JPGͲQ{A^ˠ7}df OB&ZY (@ < /ʈNHkY[`ɀ*Y Cr-BqDl.[-=1n 秧;%UJ.^Nܺ&aJˈfz{.PƁ5@Bv)UH!(jP^J2}kzW}kzW}kz \(Jq w*P+Utʠte jP{ VbX VI_X J J>Pˠle>zʣ>i+xQ7uTx;"_l7Jm Ed?$[ 1:!OQv tEd/:sU,Jf1#l¹7 (cO5P)Pp. WAv7^׫%PkօB_#rLl E(H酇qTWK.<0ʠT_pUѬ"P՗2ņQT~lI[TԊ0*(ɒ &jSy-ЗHt:,wp/bJNY2ܦY=a) \)H!q9φv"W&}la 𮉌`PrS0eYj 86w!bN0X9fTkq >E~D R3lV 6}nTryaxЪaU#EZyQZI(1q_ynqꉫu2vkcquKg2)C ` _K,+l| (nk1a 0;h(B^гƇ2J+?x[ EK%:tTCJvӬIdB" -d #TbSĵ?cg䖟tS~(U0> /|/q`n%hrpxpV hTm44R}םJ1\yY2˼qF|- CIᐿ:o th'P~:7IPbnJtON~ZVπo%;}]I瀈`ہ\C)'6u ='/@]:ޘ'o)W eQ:J`1'U,6wsA[ ^ŰVUoEKe CF+Іoql=ZW?YVT/i [ ?:T,t~廡iUcKV5Z̪'TLKu?>&w/f2t}=Z A~y9<>/>VEèGhӡX]|koRiN'TEII[J%sJȊӕmWƳ|u]w 83i៫&ƔTrGh£{G>t:.z\/~뷍WTEZh1U0knLǨ=-G7]k-G7(qS UOՊon.Oxhd婯)3ssic/16~4-Z:MasL5n=6R'"P'n+eɓX6$<>P*Ib`lsa`Gyv;1@Z'1+PkժBe*rWxUACZ\2gXF= ,*xۯŹc==ycǺUbޭŻόwƋp T +}x2 }x8ŻX9(٢QuxxS)TR VɌ{&y8xuopI`,h:n_FWSWթ(6 FWGZ[$^-Ϟ};\_U/Èݒ5us.G.OFa#@lbV^ٵWJpGwy bV XK& x՘XN,Hf7<=]>CMs:2wr>e'NBmDE[pHU#?W8#J# xVm{>XaJp0t|%d) D_v \R q+YaDJtzW;3!0t~-B9<+l_y/@( Cre b8/D|/NR*% v/n)J2??8Y}beZTWFlmOCp^Hofӧ+X nk mx遫(Z ~㺷_n߻2vo6mz*J/] ngʼb6U =UT]ڻM)*.%Nqf[ ]{Sf$4'] 'pG8ZخD97 7M(Zz@T_hK1 [[y^k`F\z1MRx|)D@85+LW6%2:Q}d 8@b녓EEA_qM7}g[×p WaRpgu26Y4-E *p_>bew=Z1)҉|C5ȮGx@nxS\]86AjCN۟:/ ?>Ehq_e_ŮX9xhW*N˶snTK_b=Ih[%eJv gOn?/HtS x̊(FCLtL|}иJG_<雏 OoV0 r4iWq~凞kظMذ,Pv*JS oK)]EVi<׈ S^.H|ë>zjAcPx fZؗԸMBenHrF JKD8u~ 19n8x`.J-7 ׂCE"rO끣.("s)jӯ[/5G4F1R7L' 8~Vم( ,zGG _nP`nnHK57w(Vfnb}T׋1Pw$olXv_|C~R-RiTTG:}X8. DS+![p)AգO/&IUU>Q İeUqcAU#]E_xOP99's=6ɣ&d5]W~aK3Z£4E>TsT CRධ p ǃ =G]q,r "nG#Xo*Bv W|i9\npr6n|F6\hH*ƍ/}}\>,CLH9gp Zۏ/QxrG0S/ Y2ɛGcDkM || +T$)a@Q2M$FGd8r^m *T: ۤU{eRc-++E7-,ky0x5)Elrm1J=zW-JH`xrU؊`*`oEx6ƅsvg+/7^M̷;V5-dsTb7;[C`g}j$RW+zV [0X l?d|C3UVN"hp1'^򟊉Fp-T%W:w A f:&͝H7v y~-Nnĩ[1ԇ7%dtiVN~3F@Oiom͘dKf쥙1ń,<SVS H l×fR>Fp`#Y |J r*EgU5Ya $*ߩUJ_nӺKy-R3 c' ''x Ҥ'"!Zƞff) >P#LX*& ոҜ?BA@T!>?5mfe`mk* fa26)hJfn0wva%)!rfWdF'Q_$# weٔ5IxΣV2@K( 6i`YreGJF/?1v#yѧR+*Z5"SN#,Wg}Q 0EZGUq moV]E'`-0-AǭyG9ϫ#Nx:0CVKj;Ř5+ !W0DNW 'dk4廲|.kY5-eeߡPvm*';M}mVd6J+UgmlWF/2֌~YkF$![`J10}@F7lq_ vwsM}I\0qY_ΎX ju8f*㸽q-$Y$> Ney|MWoM)Jz}z;Q[Y&ASUHJ7b Qc Q4_41)Xj5m*VPcenbW71fJu-`}ƃigٟPW igI hbŞE~0dy .g0\fM/03ZW¶O?%|#J{"/>NA}. gXpvI,Fy&CϾ:g0 {˫#NUw^)oY]I Z:Y†Ca6̠kxTCc oZ#R2i|F  5q\uOs/!kԌe tZP,أD.LfLX*L(J B=\q-̦nᮄ)b"%lO,n| |݈Zb(L.Ո?e>H/)Gz2,UIbbG`EBm(u}D,ک7Td| |$HI2֞حsr=9qoCܘ骳ՔNI3w:~ظ :IAǀ.ܝIоeނV͊{]>5_alB_9nn7լќ%9TQx~-&9ɦ[Z ۹ȴ N(y}l@ӈ FNnX=}rO]AwEVez`.-i;5pq^c5tCnRN)ɧ[mG(ul}hE L5=0>z+9.(Ve;:@[.Ss4aS8 zhCOշã.=fZ8d%xxaŜ\]"\/Eu AFШC Edt{Wia*Nar 1lQ[c\_d5\25`) RhX=GAI>Ka:lyR ژCF8F2W4c6b1X*lt1f|>\3 *չĹj\o1,*;Ufꐕ쉼fDjsF]DCwaE(ufǛp85'2=-<{`y.8 MΠoe2I7vm* uyM U|{^  @Fbr_+0hĩɡE<'so$|u|EL1$\Axq.ZukBt'FAn ϲR@l*59ɗ:(JU #R%!1xSu:dwfUug}|ZsH ^h, u|VWhwwWΓa<I}y>C Q134$&UKdScI5ou; Drr 3CNk"kw5: &qI`8. qDSy"4>uCH,-ԴWho> PWgegSw4 )/53ilE~" =Va G掽@DW߹7Xi+7`_J*|38 jd?u j4ۍU6%9=> L( CV\뷖iOz~RK3@P6K\ah_j򅍅9W"S2j$l>G[-$7cz8rO)9sYzK^ C&R:_H@Ik2S%f V*QG gA@e7}AGe-^zCZ|R %R݈VH"$ <b| W}~1|8ʒƅF ŋT$ 1O2%W7,2-ڏth-oQ/.WIgϔ5ↁQa֥飊QWxmYޒZC a@VHРo(I2!-UC.eQŋ>&QTҳ5BooIMFvYUwXTm_i),>A'`v$qNN~=eWy:?~Fy~Ȋn25{ԋ5AxEivÇ< `:;7M[nhπ,nd s?^| S׷SQZeA/yɗ>Ov ,o(P[-ܯ:[jeàLO@M ` VwU+@-`Wv z&WEɧRSy]7?lU 8{ ( o[/Jz>d} Js>K6ֈ_EW32>;Ϩl3zQ=+9_b(I xY]G|Y^svn?$KCO0C_|k2C,u̳l72Mƅ`0j^[Sz1L]6( o;kcd!S' ԋHH`ȱIyNޥ잜M+?.[}q[hvJEY>͊"~-cTc=;OAqfW*[!g>A9+ Ҏwcwѡ,%dO@Jghr>ͺAFa<nPoV|5? [?o}˗ N"74εRÃtv7Miw^%FzJ9o}Vܫ8WdZ}dgAB@[1 ,te $T ZU$#S*$V0ȉm) jUg-pVe&>=Z0I"$SaPaXd\?$傝bԟu>!qH$pTCk]!+s+|ZG(!:ר.*NW0A7wImZڎ@iœR Bt/ Q<F-k g '?ɭ`Nzo*,AeTjC<_f|eݦT_jKS=  m7mQpJ9XۢR ;҃V9Qv?FDQ=@RRtYkj)H)qkǹRs^CA'> K*pEz43i4^O8]j48*U>nczLeSYRp3EU_ϭVO1ahk>BiN}?T4 `⑹ŷܚz(*{SEC@%-Pr1@)s'LB$:vhFw*OvZg2s'#$IXb^x;ܵȫUHuP~_e󂯜\Ŀ+@t5z:p기%Km 9ϖ YLbHIg>YIy~ѫ[7E%&f 9_ *U܌g .w#q:"_L; *=,܀됚 " ܤ)sBNd}V?9id!qb\ T\.gBCNKqkhLa&mbr A}q<ߌv:u2*e YTi4XN`nև5*O%^sȬ%B6ҟ }O^<#ɓr8YhF1uiX/\' yWmaGt8BX=CouA_`.hZİ g*RYMrv( I? dA$@8y2[ 1R+fl11&ck.<#&i},-xO[ѱjlF,O+xi)5"aٜ,k9'r`pX&"?҉dT[8|7d0Cf(Z[ٓD]n|$)eDmh[u%Cp}˭<Ӓ"J2p:<*pEjH"/$ʅ9xhrOp '㉍l^JWDq /ڸYve!! x 8qEBUfRiLP[L v lW%'OӂqvOJ2-Zt'V?|i:~=KM:]Iz 0JJf7`(l%6­X;:;˵dS4I\&m ;V3iUԼBڡQ~P "p:B OU;~ITߋ\ptP&I>48ŵ_z>z{:( µq*s(-|V}V7WzZ]tہfU!N!dWvUNe>)Qǽ$o1IoQKݍ]e(E]RetS-^ׂtg9^{b@ >Od䞘62/..9.m Dg4qo y#w #UOJfesuou9ښUy'ɒ5IWM 1i)͈uw:R8/f83%e`o2ۅ&x5f4e%G DPJrϒ o$졤 6Hȅŧ g*.QJd ET?ؔKYUl9X qDglnF{1:Pv"UV: 9$LNyY"{I̟I}W7_o҉fU>lH, &OslJEk< 5 /7 ~bq.5Ĥ*%S2@*KvGmuO+D9%/$%=Ȭc\w9 !r= .0UJezȅۀl~~rmME[et7 w.tɡ'rױk1'X:#(6ZUS f6U"\NtN'd(&t쎯 >Vp >xY aN<XF)g5 jl1+ V46V*<.!*X8z Ou2yKϛ&owlBMSrU$[KTJQkPMӄ]mRVRe%cbsҖԞ0@~ʇC7uRe`2Jf b$Ig0|pN 3:|OU'%tӡJS,Rt3a%i|[ǽo]bHC4C`2$\?ʎ7bUccUE#&,&Ntq.H9G3xiƃ2,Js9H!T=L]}n0bβZVesX~s+"%>.=.`A+Z ښT{E:Nq*ۓj)"ABhLxI^O鋱Ax:BԣܹnSQi`ӽ^)e CIfF E"ֻ̩#BhBzrH>}znf#g?kCN a1 fB$l:F>SGkThMN!gO/bQw9[E-P9@Dr)>!Ps`K!Sj:ݜz \Qa9Lۖ=Y2w񥹮Fl1 b-G4"!,rS .хNg4Z#PѓT6v&ׄU\e]_ZOZi)S3DΓL"+0k00^' ѿ)b\;r0\[~`$`鬈\ `#f&+lE2J 3W/[d`xRrnmWjȍ?y&6bRV*8.4Vs̟u 6Ι_tG~wcY_Sz ࢽG>R0- =\UtL}I0#H¹Q>ܦZ*l ¤ԫՊj_.J^Ib -K$o%a-( n26V7xhtL AF<'~lruͼ#f_;i#ƜN XeElC?:9!w,swt4>qy:%J``1;:ҪXj+.X0E5Z8D=VTqL}:;`!Te('B>(7nKwḁ`P(,j!-.3zD[ž)t!"HYQpR|6Cmʦ^9 3RQl0DL@RcZ@RZns|Tvhxy=I{jh/6$zǫOkB wY^-#7ؔ З ahֺ[~Z(WQ*_ Dz']yZ߀ ^=hbyյ>C82XEǬMbA,ۚS w|r5Ti X\\.}SJ]]'HGnM2;)x˕޻4|AeS}?bBhT(_hcU QeJ%0O5F2_'k?BKSu%fI*ߪBNU%]?\?fŪ2,1k-Π2\b;3͗rxEO/ `Ɉf_L/˞kd8E~".~ 5&kq:[ Z2񯏉,"2QGT*u*IץH _|^Pb #ed IJaHTi6UpD]Z.a$SR{x|3BI}Uh;lX[,d_lrx ȉ8^W7ބ#HK U* O$P u:-TMړbʛ -tL*3b,Dۧ|&DBV^ ʒԖ b"">N;$Rp8kFȄ UtZJ@lWa@rd=D^赴s鹉%~Ys}p%9^zBT&t&[QXQNcipyj7(3S<_ V 𐏢X`'yes]zF׵𕜃^"R}q>K:&N1.z2$bbFnW~]xXL#XR*3'޴s$q2lMxbt:@36^|1v#ʸ x^V{=͆_3ʰ_܊NjgI鿈(?jY`jf73":>i~E7 Glp>f/=|O6F7LĖ۰\VHPN<U0Fۉͦ EN`x-'Kac@$:_2RuRq$Sm[ӃeS4>C5-DtZC~y $KKи0lրpeA2-pf*y fFt1NzN(fL-1mYuAl8]¬I܆`'5'dkGtф sU|É"㛫ǔ>p(3&ˍ$h*a22E들.^QvN7D S`Ȟ#5~)3vVV}$MsWə[%!s<`6Ƭdnj#Ox { V?)N%?$*r!)j5i% zձ=NnFvfww,U=@pYq<`>Ix| hePcZEj=+:o"gLY k_ˤ]k5(<Ħ2F&5eT9Ӵe%=)N)=EdqfCekB,k@rҒ/s!J6݀M.|st S_Mu&8Co͌@Zx &|5Ȉf$|/D}÷O "19)`|ꛨ"z1˛F#4Ԋs|GU"S%'W1 D3c 9 R#t+\"L8W  y'0+tt @VTڵnsju6;VK]h%y6VɌ R)@,F%!:kyK$f]7'`"{ѻ@n`>k(O;;c:ˆY=tDSjv$zU3k'9:gqAƔO4s0_2Ժ5Vo֔Tc҉ܷJW( :ehFI}6^xq15$A2O#E_o})#rl2<)-юqOAuT}^:zDhBeaR)LXB h/'ƗMsɳ[fyf 5;G${ޅpL#̟9 iL$S: ]>-Rk2 ώ 'gw4+?6=żoo=]@8ҟPTkIL~NWK ԒCżLCMh+Ptࠦ=f. +t$&#EFÇx̎+W2u ^2b GtQOحҠ(e, 0A#! :*U#;p-QGULbuNQl\0NoxNƢ&="2-hJꥬOľ(3ڨOz}US)Y T$C:s y@79X)ft&&56u dV䀗1 xUtx̶Lԥ$Z]-7>M#v烡H$Y9!E](:I+-96ț5 VއB SFxFؖm%zf+7!wXDĖd56-&x$l[jtN{l]gF >U>}!m\h׷ps1{Y߱Qi"!D\/{IJ]مpSe&/Qs:H,1A2Qol~N?ޥҮ@<`^۴@j{kk3:Ϟ>ϋ|5a c:[VN{ioZ}l $(lov?fXh8bh @ BY@mGGY$ 41"u<SF5v'(Ɨ2R㏤"] ChN\\8bN|m`tE|5^_BELcǒ(3{(GdT-29& 8:@qw6|xŜ >(u!0rl"Y+H(lQ0LP |;ub3F錓,AcGN>;@#^RORS`ĉ88Tۑ$V,6Iؽ=av~ O%U,5DdE٥i90@E` pd0Ğdhx{h$7E&y#뗣SM{#HJ34 !0ND6Dx6=+e[_g`1 Kxژޚ3yrȰ(Ws*$? =x^%KpM֌ѡ{[\8m2 Fqڠh1C4DG&j PcP6!fy$4ۚ9m}%m>yj^lQ ]b+,IBw6ȤEmX* 'a{0ˌ/s4 aJ>yC:kr8_%Quz7XKW@5}3i(c,)Hf43c/I%=xzzt9H꼰N-Qk  `w. I7!' g&7#Bt01^n:9h̔%B<'cńIOllbk$°+s5aEL#QmMԅV)u^l) вN]6(޴T]P ck6z1v1tx}s+/JI\ l!|N#SLs3ϭYYUT\ǣzMa͖ h3< [GY ޔ3 EZ";7I+7] mi`iG+x}׃=aH"w]-"#7FA@^=l#Q+jSaVxl O(CSoS ײ Q-mLI(`9(j4g@"aQGPu}+w=(5~S kdV)8k 7:*ίcI"fI99bW,N+c3x^aCQbVՂbIx d 5m$)Ex=02돨|=tS爚u"OJE  !stq|OᏟHb坄/}LٱO%Х7ZdAx-%7e 9ZZ}+hx}I*=; zUS T;MIJ{X@!fH_v}PVΩ=F-n呿3%lͳF5,c Pj̝֍ہFCw,Đdվ4?wϾv) fAY֮RK8Ypgc NdlV Rk9hn#r VBT+pA#F#m &!<@$$c؏@EټT*N_\ fGB܁ߴhsSqQxJ <w_ hg$eiM娱6D*J>le%'_y*]\%v aJ/ruL8l1OC>9 t%C,CU/{B'9]ZQM2K/nrDQ\UH(Hr{Y"$I~ӄgHAd9@Lqj1E\GqmGoAM3Is NCZ/˅fF ,0K^;E5r2f#2*aMĩ 8hڦ xJT9;!!U5l׾џ6ׄL?05X6r2xjbpiW?z1v+ bB7ѭ=b(0.,‰"`'e1d$WڌTS+a&þXM\*2IIM=g C8QLѐXv#piA(H`ZX*M| G˘>ߙ4oU[ED-BΠTW7dAK 0lss`cd9+p6/?^tt`mFWLA:E5 Qj[d=-f F!#MTDhOko8]GP8^^aP _b,(p&,)oƑYb\lxO~8S~흜c$:/D+)fc0׾a{MT =8 X,^UU2ӚsyZ& o&_ #dZu"yED"KD G[mR dh1fb&Ф֕V ;coVG'йRo{}TdiiXt|N$6f-LăBl%$oAwM8qu s͝}ŬDz;5sSI865xBC8[Dd:h3K+. ATbB,Ҫ\ri 5-h.wvDz;!+etr,*ѴQY:PX9 WZO;;0 e_W#溢ގ\䫟Ç/GFPWcJ.4v^V:Tf"OÌW:χdDhF_npyn`'3B$S<2%iO:o(KM]'Ԕf-qcN EVѧG}Lod$ٸ|=aBf;"a<泠k`C)e jkoOym^$K(G}[o`(o|o6t6S&Ycٟ[Sc4*rez5+7y-{!y%_b0 Ӄ?Sl3N15/eB/aڻ4^ Ԧ(8{ zdIxU$)NZ+h0v%vgh:}+nnw$C(BR*22htkT7v$ :Ü$أK>fG5%veK}f1)(7p7bsRP)"5Ş|$* ;FQoL(ʷ@xÏhܾM;Ǘ Ng;b}~Ո 4A#DߣrhST6_9ZA›r&^12&-ʩGeXM[): /h%ML]^[Rl{2ԑ=*c2qC1g5݅GNg":pVf\&/6ng:=:Mn{d P}7jqvd<퓱akCi{9?s K% E7؁ʺdhrY"UEYʯBerҁ%U%2b-.FzY Ϥ83xqlaGcٕ6 e3iV.ŪS'M& v_FRN'Cd6O/(R"&?Iܸ?++%KEŸ)3H4|Szl/Y 3LCpN&S5k<'34ԀYu)EW̆n5e4$<~<1lк:Ӷ!HxFm$Z8jRd>ԀTXDo`%Bꂙ'KbUF8dEsFh)|$ߍɤC+@Ĕr$㠬A85:Es@ :p&C@P#t1b:O;o*9Hnk"ZxʌT/-ͲUdwsB-9.&uG8CT.Q;adj#zE V߉,Ix CWtb1cT'/>] ^bTX7k7&IJH0 R[dxɵ;DQ ⱯcdeMHX yH@C KF`_5f UL.3hNvN7kNA@ D] iad*&4"D>e'P` P[޺{E4&ol+>k;x+%++MbZ ͧ8l`e5ZD"pa٫ 8HphHkEhU)7x$ezQT?NT=/ȡ|4k4Z>"&{?;8"I)Nձx Duy_\d"e:V>gt?@9 oY X|: tO4}+ SWlYmw4Kz8qN#pS-;ziv,'fJllW-hr ~/ < A6q+bqa) K0jOieQ$@*\qLd< Eݪ TYIM'dޣ)Sx3OcE VƝvu{U@w\8.δ):ZGdrNLf yYH>Z-#DXCM\Sn\@s5nҹĠ-SJSC86B:4gTv5u|EHBr9#6)Wy<̾?xۅ]9ǚ>XUY,9PCS{(ԔsZwNJS~nWyavK+8W*'h]ԥqO_Wy&$$́LRė@͜XQm./jF6MEN>nL]GC'`#RiFrD?ftx|]*J  ]MK8mxS6Mפc@p1bfQu0"$W>5v.;e L5kCAc,v0fÁmMNRD)}jYSw&.qR\6|'0Of%FB2xo?IPVC0C-""BDXT@iF6RZKQAm%O)H6VR1N˻cR=kh"$H0ڰFem"w莫ĆaSq8Um.L]bA 2 RBn$CHTyI'j;zH! Ð5#-glhRw^cdѭ5T=%~ugzP 5ZX25Ww T2 B8p_ZCd0„h]G;uԪ]̮( cꦨ8LՐGt,B/njxpNr@&VzZٔTnjE]NԔ`t%6T7% NB^IFn0ݡO`0{"+|Elm4Է&O:#R\691z͒t!1PMRb,%9FJ~v"@WJ狖ԉnC^8U8^+&% 'bʷ>֍eqM, U NI',@뫖u#9KL͉M1˾7vB&sĖȺP6X;f(?.\hw:s.!ɧ%a'%~ ]-fUk$JUg= hf UӌrjabǸ05w/wXj,Ln sLގڈ|}zf5-&lP#ְ^#Ⱦ<$~1/@&%Q4|>a,Ajʝ|evCT؋} XӞBtgnX<}k9reCUv s[4Kjsz &r05R}$ɧ""TkvFS4ٸƈ`z{ϧy<bPhw& ^ŠajZYOgpm-ơ?%DpdIhrHM-H&$Mt@[<#\'kpAyɕc7p!I"g1ʎpO?|-;Ci4fM#DɌ-u嵈Q>U=3rTo0<;R¸bJ@tC@zOQ%X=hKii^kL,&;LI"9 m *KΎf#;I7.2,l-öIȼ=WK 0VT*\,d.bn_ӈDD: kcrrRT]TVZ`sbȕ QkoYUȿZM;`KW"6 -cC_BNm=ֆ1=Yq!|d6ϹRv#n{3IBWYe "YBI[ɨEU-{\]ME$״5B杕lRy\<-Vi^K ZYƷ[m'#o;[1Ajw(^k}T5h@0 Ku,#A;>JY]j-5*w ]mmb"KrH*Cngȯ~MJLph Fe! p1BVXq2PgvSЉ]PBu!F*rRԄǔs7rM:8gEJ :T71&KXՔ"` u쓆v{p󂶥ny2j#LNSanfC4(y_fRD B}x4{+I(RS7jwnNə/Yf0lyvWؗ{vpoP~udɥ>$+ ڻ$xs>ML e/uڡ8abDTR?$KUP]Y`ĿbO {0mgR$efmU-Fj}%ݼ4-#ue,M%T6SO.5oeD ~k_PewDF:25*a Z-ޯP5i5S;tS[f+| Ǹ41#)_89ghKv[A&x; ?> t:/>uz;i 1ӈ1wpj|` 9m^}fɫ =0:B kXX g͚9A`usj2il@ZO h>>>ᾛ.<޿?B*Hv ,s|C7pj^^.T6UHa<|3 i>mnyl 8>>RNۨQl"R2mnڊ}/28$ Z^ГcJ.:;gqo,ThGq:6z}aLF&!r(-'gو b;,‡et({[>3R@jaRtWatJъC|\4B>XDf\ +F~]~GVS|O q["Z~XUޮkxC/߿}?;|amr[ď"&g؆uKJ༨_:$)0ƎZJqY&gȷ+`d GQV(AZ?&UnW^CVi]VqcثGo6ɢ uO`e4 q̢]!+YnhtaNEk0-]J$J^wٌʉ5h:| :4n㿰 ~|;N׊͓߮$h߰tv} a+jhL6BKB⦐谅#4. p$p|kiۣ@3A*٥#%f͛r%q)[@g5fc)L&?1VO>c|UZpYf,:[t 2; oE";B4c"#.[GUjޓw{;O7W0;834'b">b)4^$(D )C'(O/ѥs41ϯ8_RXb!A.Fכvp'kq9/|iWl':\ד&&t Gқ yU rxz=i rmT- hg)bp 耺jL@!,RX^RS)$?8fl1CGf޷ ᠔c}S!H>͆>HbPHj>Dk[ 8F<8[`7ʌڛ*1V~L=.Ze05Bg?ͧ ˰7tTfPay\T}oRm;u[g 'Ua+hy?GaY(7@ O8S-kL+O`V4N _ΐo?NJd Nwys\2H>=8!]MA5_IT Zq]*ʠ3LgẈ>T.ن:)@qT7^AzxœYgܗv \K7&vȧ(X}$x\JlG>3(&ED=@{g3"VN$$pSSn4 33(/U &>Tt|/! %ΣkA Sb",/1ĥ5/|+^nQ>,ѠE*2-ˠW An׊=R>"T? Dm^` MN 8e[M+2̀ O2fΖQNgCx&wDl@19K?+?כɪ@˜ {̘ڸGF KlKq~7&$:#eL荒mR_ {[ {yXB}OjW(?LdwA3fwy4M uߑ|obl7JND^Ώl`ٳQf"RS6[41׭Qrl!}N}^n +.,ӻFcYӤmzqF%-}>@ud2_Wu4"*u=y+ӛppRUlhݒuYbA^䫮Fz(p| 8}3]kd2$5ہΝYr=N'}5>E)tk>\{2urj SWJI6CdW jK3'Ԡf;3?8UēmWr-c OT  a,[Æ(Q_81K3sy#Mk|wL'!Ē>] v^l*RR[`H_^*vII) P>?!8Һ 9pͨO7_Gʜi [g2F:MlgIbΗ͆a22;0!ɸ44rn6 #0KI"Y&X|>ɺMeyh*))VE<)FKD1?3W@ez١H,HtP0-0ħ8MťzNE_1@-:#?{@Yx#oǨH]i2tw/UXړx"9oh Z%S/KoUӐ铽}gs6j A[XIaB.fa^DDɴ]BKBS_\QqEgp'~ȹKz/X`)mDGJ' 1*E5g5VE5uAt*;, -M^[,/7RoЪ,*ǫu;n^m|pynmԿ»M\KoJ]S 5|l dU׃4)yϊ bC72V\!@wGuJ(rO/]QUT_)j>."{guֽwlC&X0DxӺDalJ`7廤iT%.PdVE8$$0i1c];Yeov[)J8}h~<}f[1y+C;.&$0hwpGL@kۻ@T [:+;\q`[{Ҷ)[cX'gWcuI˧ȉhRE۽>b Ac38h4c# co3a1NbpPˎD@/ ҥhE{Gص9MqvA !ޚr'aՍuJjr?U9QIUa0b31Gb<[Y෦teRŔRAT8[|+B4̉S NbE0#ލ(%kqtQJ=FS{!U"ZNMUiPj01I1"FFT0DRإGH3KRx4X;?%Y"eV ҵnm'jrZogy1NRjDLX`&Gި@4>ΉPjXiI`=|_gsйRyDD+ɺ= n\-fGc@vrpXiFbx1e\aeB[ՉtY,LGwk6 !M±?iO(O"6zxω޼P>]9}@}rlad~z1BnLbdU{V I 4S r^a ,HtԞ5-Ơ6Ԟ'~)\#RASvJg4@}|A Ii_' =`LJC[[ hutU=iiRݨ6$UVxHߋ󖼯Y(ImJRhBCZ4{j

    O~OP( I0o=⩮y:\&3q~$o̊+d^I+ dLX"߄&.`[4<[ e.sRƊw>6÷H7H^.GbG>EV>g:jZ"mh %Vx0vqdOZQ-f J\0pyOWSvXr͖4g[rp(KMeFĥYfe7zy%O[2i]+Tf? #kEʞbaMPYO P4l*[ʟ"@e1@ӰV( P4̟*3ʟ zb<4@? mB| <؟+T ? lEc_AnEʞz[4oIRl#22R8[/c6"ګ竈trhl3bLt(@k{{{ګfgiߧQOVVxF|y5C1 'ѦE `O3RV!mK2^)|N 1 cm,TG}-{$뼳 ELm =a}3hY2μ`+** ])Fbg^E'dGP @ d{eK s%)]eUF3eeLȬ;*Rڵ4O!%̶TZO v\1o(e?G.8*|7;D;VWDX0;FW`5m+9Ы6(tC {C+})`SS(#q=yy7N6uK4AKȥ?|ϮI Ft6D0hY$-ʫ/ S(P~"ȝE+T%/ TP|3JZo }`C4[`fIŅ )>=9-f_XK{oPdu/rG0ѳTUח|WϫF=M9-UN$9vlwS^OEdqlLNFrkT—}mP $dcp~H灋m$E;+BT50P@=~w}`]A59/:kye,L$Yeڜ%=Zz7Y!nhE\ȕ_0 %Eg ŏY.񊋖qy8 5·!1p|{9I+ WIa*LF.(Ii%m%PKLSEeC.N[WlV GbJҍs+DP]XWu|!M"ue׫,\+㥕Gخ Lu npkz~F,X9C\N'z6DOTE iyFU !it`3`ssƲ*p@*✐ gNeqͻxȊ"4(rz~0-Î/ȏ;nf-0 -D}k8 hXcc/OTFOZ~T? {{b0Jc*"mLw.hs'u"`DvgGʑH f9(R/zj❃_7=S>f-\؜؍{Rg&5 Nd̉g=vgJq:( bRg4SV"qcĄ'{<_ @h 7gׯ3.dKd'NbH!ިpy[Fma]iV [IA~[dj ENǮ F2/wS'h~Z l.W/?nn^ؠ04 _٪VƕՇM( o C'lEZiU^/'@5x2k@wt0|=)B3_`p߮`xNtiHzPaQpuBO7, FQ ²U aq^ҴZ-kWϚVi=xW0EbisjM0xgfKC,9rAYóODSM\IwKj\NC-Zc 5dq-_!.UTr8;A6[ =PM#PrTvPsþ,؈ӑq hA y) -ɓ4x0`紭]f/%iĘIc|#[ge0F oҁq:ю؈Ԍ"|h>y%3}iH ,$uSwxe: `ZǸ:T%n-aS](%ٕŞ$<0٣d;9B qz9#e:MMؠ#x [| 8@eY)p4n|kCr")?*@'AtOHH(L{PDx!{"\l݀.j9)m@Ҙ)w{AQ$%OʵIJmE~إCH(R~ &Q!{}Vk~*%P8u;^m43)m.C7t]M2Gt*a_l{#T92ݙQ sm:e4YEв|oK+.n̓sm:`P2LRpɑ#[5wJ.'ĦijW`w3XVkVQ`>ß 9w"Yeeo]9{횞8&-}zKLy?gBpww3 v\6Vo4>-mS?ju֔Gۣ|`ݯn'dq6DeKWn/K'lm<1m?jOFW,/9Os,g.yxޠ oU.TA܅:%הCs~*#><: VYEdԼ.k碭צiAe ] nJ8݊އ@@ `&͑Yl^ 4b{TT*ȆBF9m. / }@0w(iYߥBwcxNހ5! )ၯXg<,?/oKAwxs!(`hm1o9s-kRJr));@9iS9S ܅%j6tw,g°@D Y :89捯x HRP*!Y"\7i0r#ax (RX*7J7 -KRYuSҩ<:A@t|iYCTjCDF90|*0r*T*SBb(!(0D|XjYSTjSϓ ݪO,PTXbf>FR'FQK'> H$6z~jRHd6$u3P- X=yaff4dLQb7b j]qAjIs:LѫV׆WVe_T |9JF9SqzqojPK 0x-u3}>De0SSCbZ#E\ ѬҞbp?7'՗y~%R[e;VDDϳ)&25](5*uOi7O!M-0|Hj_g+!;zJuRq<^ H*}O) 4"Oy&0!CuCv`c}O3*fͮ".n".i܊;y*(OE\H%YGXeݓMFkJ_bA h'C@긹W̾JqK_A ]&AtįK;vwJTPHQIBf]JƲb.zӨU˥vĉm41D)6e)CKØEҿA(=T)mՂX':J#[}OZ/k F?Tw|',7(OT( 5BЎ\6\jTT{?uǩR$u2 cRnه2wg9BdA!jPHhX_}(xuMZJl(.$O`i k*ԬWUߑaG_&tmfנ#EUo1D$Nx25L5#bբ+:^b΁Zd0Ń.m<+Kf 3Sb``WGX'~pܞtuzl4cq!==8Z覵Ji3tNNEQ鰴Qv:o[ȯG:E*3a]aVN5>/Z7ٓ<49 j%uC.KJBK<&Ep6MOfZT0cC d-wd_:'ãw_}翔syu ,ꗲw;uk<ªhC8}ɚzJ?d)~gdV#)RIy%i,MIn-VSaKAeX5jM^K?lťHՑZUXd ޓλWꭚ9e]Rϯ*mU]E,VA8sAH$@*Oe~8Ի?CɆTfȩaйQ,6bIBf&٭2v}AW }#-P: 5)HA4ZtPL(JggA"׸̃pmcf"p`ii~~tu >f4 ݂1l 3$Ğ)ۦb+12甠cxD>0#q\?eP_M5 r:*EvQܰVᶁ۟ F6 h; xQ `ZYb2}ׄNTIyjdOl%Ln7RYQ»Hh  *3b =0jsͤlvQhb+v\CΐB>YqJxupt90gm1((‚j# ŴDFWJh 4zX8{`rqs=qC=/TsVW=_G={7]AT{v X=|r?^{^1ӿ::=ǵQO=8jK}RGɷBw^t*o=&`4h( \FShj[[R04U`l+*0v U`+W05/VBxa۫h+m `` Ɓ`t4/Wxv|q@kl'w-D+L=.@ڝߏ;?ݩ?k?|6V~~=ر'2z_kkG?݆b~FsS KS~sְo|w`k^v{xhv@rw%>z{J?CAҘߓƘCB2=+e{o6EBdT a3(Ankp{D2ZJsӡYmhSGΘ {m&X3ckF"Yv~x-PL9[A{o?{m#gaMc.|&`>I7I[ho)OAg+H2Lpto)})lǁhj ?i//;k.z& Dշ / u j#}DxZT EZm].&^oA\KLN%Ocd2$h J$1R5ʣǶޔP2@8?M~ZƖ%R;! $QN*z'j 뷉GN;l`oڝL&Aq¬~D"!y'jq-̨xQ2?F}m4 0[Ole?9P]ؘgpڞ)H1XSBqpDᒙy̓npu^[?w.]vL*4%n'8F k&@7wvinx2!4V 4|DcY 4:NڈwV)Vg!bd=^gHklHo'0?:飯"M;9Gmc%V'0d:i#8U\*U|c' Pod< 2(,@)sg'!Hp剞yt1 Fjvk)D24z IxEFl<5q62qګ[dkK8,o\=C_{~S{QuK;Ba to떍V]{DtBnN ~:(C.@ ~ڈU:=ݷr~"8?_cg$:z~d "l<_Iش&LCD t7͆ǻ0ʺ??#A$t*`%<.,h_Qx =0,7 {_l>*n[Ot {asmΨ^s{=#qJ60TB}3rnXC7=^g4]9Q,z:ͮ_b- TmJHaIR'KOLL`IoEF{*#v2BSXWc= 6B+uyal`6<<}7k,;Nͱ餱#"@ѓqSd&E), P9yq q[{5l ;zA62>v m؁llZk 1?9q nU!6nO垪7)sґ19 "v4pgD&$<1%鳣CJ%EF{m͛CcjVvl.yF|2l7=tYexBxR@on[{;) oηN6?2L3 5q!R_B#7c涎1"`=^cc? ;YȚadvL)HCPR7Ob+Ea߹DNFnZػsK1uV!j;_{d W ОIr4~xUϣ=IvcKALqpK3՗==]fFgu$hXGz)+!RB< BNJ۝ΚE6e9>EǤ.iLxkI` GȦ,)rA*YKԚ_W^kd qA x:輩 1߁N1Z;7(-?NT)<o…K k'3}1l\dd2X0>#aPF±*/Mg HpBp"@rre$P=\޶^pBt0zy0(IED8#$AQH=%?Z\ő7PZ0;>5]8^AO?Oםݭx[G=mȼylb.N-E7;]f{cw. г9΢ЖRAmB*1_5GA-o mA,kͣ[B[y`k:)rl[yaF[),wlP-o"2űB:bmgɽrk1|c p\.Ft7D`!nv]]@-.j*gaI=XDDN.VP˷NVɨ (;ae@WI4g,<^Ȟ 6$2*c{XF}& + } "+%ɖٵ@J$X^x3pD >>w{4dN6 \f;$#'H6΁IlD";=vLN=_@(,״~jaiƍ5qp? YA՝`ݧAaOciaXC wlc#m XAP(cC=͎tҲC^m{;]/Rp|ȳi"‘,mj[ D@ RHom1tFHou1t۹ ;0BMMmifC( Hݶ65R/cuzs{t 1pq=jZܭ>VGZP޲<Ѵf@X; aFz[1pW?^J~xoOF6Jo<+O6D33 P3sRn+U3sEMZǒvfٜ=Xmc=B?uaZ$Zfqc'np^pe^w cJf w尭fIk/GCB/|`՘: /Ԥv`EkC RkeQ#4Nwr4 N,?wBv49L7Á˩Yto*-,37)f1ˤI.[=fM9bu$6LA[Pp'?e8`(i0Ê][88%mnGظWiw`bo{9{jӗD;_a `cv`W fEhAZiKӆx~dl2Fd;OWM|6U8VFӝ nvٲ>ӱ.&lxho:=R٢Eۦo[-n}lC[Ϧ0!mfہت{b^rKGX/2+yZt.)E*KM7=bSO5Ъ4ȡeWOǷx5{ȴ ܉$'_*m z]o^n4in31컩7:ѻُ^);[|.d,+e ֗GAV}aTz)iT*?qS |'(Yr(0 śL!$ p 5_o2N\IOz8U/E(Li=.!vTP"2hrd`BNLH.R'Bi!r ,1%Rf-8! .ִ(6&΃|J "mځ,؄qdluBg 60eW' ]Jh`%k'Z+\~.K<䔬eP0RaL+/D$[x:$Ki $:q5 eѥi:TPNXe,R' w|ttN#6:r !'N5BLJOg4@$Ӣ.ʖķ&E~*#EO NYWxBlGleZxrOj+xLF"4R7~]Q+kW4vZ_)4ڃ yژY8-+ ]'ic`ݓ`6b!ÅFc % FlWN#`&!n M4]"HsHT\ET+O]I1uLZ}6H e-֥rn ;&.ļT-a]~!ʑYT%iiW);I1o[.[œdT^>k[¼dU^Nl%Ʋ痪m ڥHR4UBۘ<8`3!YZH!C&s!oa<@tjz}P Dhdę3E큀 @ߧ7=o˷3u;ۻOLOqdb?WG ۘfx xdx+ is>!if[1.eV .ն4VhËҭPbZc\=?Ulj=;1xh:>?/DG lWF`(zxۉY"73$ ! CE$F$ d.i,ln lFm-( ;)\bRnmܲ;2h1i۲i> xd%+F,~}(# cg!8p68۹y"3y"џx˼| Ngs'~v;;ɦl1`6j`gU}p&"Xy<Ӕ7>Nn+2o'Fj`]9NMjqG`/,}B!IΑ+.Fos}LcOt٧Vi<1-3AK /Midy CǕg ɜlެȚJN?Y;Ʃ.~:ɒEQ,YHE`7ٍȖ ~Ď'+ đInԉ.BI qBaw96>䕴CRr*j{h\9)s %AK˃иHYE؊0sY͉&\|>da.rR"Jsq.gnj FIxEoo'ILNĈ'! lX $1]†| 2fd$l s,6@22e$ s7%f^Y N3i<9'׮PZe"1h9VdOJOMN6Ë7)K^ɘ0gR,r1eYa5Df WVbJiOZd% bSx90lB].{0N=lqsﰐ->p0 6XlbNv(9 U,v)F>^`vst/k{`mosowu7 l!&؂Xֻdnm>:*<]Ġ BJ%.]F0I>K[qsaGђFGq0Q9)g-k˙Ғx[hNiC,Xļu.it&vc%yqz|NϱctVNPv8s}>άvf]thbm#^/>^䀉dH]Dޫ齟ƃo*sh4bO?绿wگOOzGoA.hzۿE-+RM'.l6f#1k:5^iiT*h*1T_nQj>=S){?\z.,2<AE u3)['fyGƒO@7܄qnO/%aR|C c /Ww)d ˇ)EFY"-*eYWyF/cNt{ƶ_B`-7v 7vX!G@|f @c`_y:5 ixtP BsoR YV3?~"}TőIQF0Yn&]A't.>-<8B9H(@FgeRl J?tLOIep2zU^YiQa]]4z)-1}b8h) ĆE칄"c6Kku㞁ܽ(Cw◝w+ Jb_ |«jSUan^[ػ+Gx]Њ[AXiA;wcj/ :7|ovnYInɶ`h$5>6⍁.WvHϺS 8z'>ÛΫ߿nn&"|BM \WҸ7z<ke| d~ozOd|/oͽb~y/ ɽ|po0gxOL|m;ףI7[[˟sTGAޯ]_}oxI_@XGo;ͭ_[[Ǎc|Uj%oBBE2Ϣ/rhY"m&lr{iU'RW ,yTf٬DUzz~~՟L(dz>ܟ0a Yͧf-:0p$i5],h֮qDBjT>][[`l4?f2\$66!h/ ?ˑQ{5fQhVtmE =:JYT_6o66",Y.jjB?>԰nY[T溺wft=MJE׋3h8,P$/!b˸?lDa[38V#):0VaHUrԟ Y9<>][y>淑5ar-0c X |DFo~x>^tG ңI4A<Ɔ#x}F1tA#0pUQ4_ Vv{؅O@e4"ClH7D곎q B,oMn Zfbk*ABa0fr9G4=pe<-Iȯ3l^^gVq˪_uVad'u:T``u("xDcLI඄2Wū=^ 5t<pFa@.^J][ϸU`]8+ } 1/`0qyj  *L4jߺVA5J-FdLF|~aAcI]Ҷj ai! 9;,܉q_,pꔬ|XPpyТB+딾 -.Y*9ѷya4B tqNiE]PdϬ/EuC}HxJu$ 0grbKˉ銢QZymO&*B7љ#Y75MJuRd1O.bk5m& ? QjeEY|>ū $Dh2ΐ12VAkX_ܬ<@oNg ~슜b Ly@uVAE !-t5):+K1/~ob ˡKsbuJb(tULBjz] \j:\ c5O/QM=!KJ󕨳|e!xe4hp.QS[,1,ǫ R̰X2ֺ*'XD%^vM+uP]O0=@DUe90.W]fL,N@e T9EZG(2Z"+Zηڢi+imN~mVsa .DfIU3t8#$5F u5qO"c@:loV0_Rn5?'vya mNvLaGiFFlI-2H:8Y!8G4H(g&̬-'05efNk9haD1c{$d%I]HjEG5eMS^tѷ[t>ī&|7~#cKfե );y0lAjxɾx%=*7MhMQ{/rOVA3VLRraexBX|k`I>:8AO5AηµO`bdv8:X0b'o,*x?Eɥ1PP]»b>v qd"'fJ0>%3$a2㔢>)INհfAQ)$sX$µJSҥ6-$yĨI!X 5sSbYw3U)_U)1N E#;#߈1k0;PÖ DuVyŧ!趈d-z&=M..`)nЗZbͫս:yI vu1&檴PoQ*JE#Hp'mTDovBT^u*  A3'eWt6ijt":0Ft`8陇/rvHO!i-iȋ_R kQX/s 0(K;u e7e2`LJW%7t#7V-rS [1ɇ˳dgqˉZtFF 3|bIg'\4|:x!!6 1*g̼˘1 l:\a5W'yvSNp sVRUF$DuMj;C0pz^h2/1BES]N^HU6r܇LRB `؅Psɽ۸? kn\S8t2 sBb惌 ZPzA0oj̫J 35:~&r\"A>\\]^>¾?x׍?'xMbUѭȈLB(ރ:Wއƅ_VWs+C5]ջ3_ݒz#૽'_]W~" x KAF8`k eMSk~{͢R)(0IMBǢ9JITkn)7\ *Y`'K#AI@]@蟱̑tZYT9 @h΄\tSBx*9 6oD([y4iaMȺ𧻉5Ru/{_K,GlD+5o R zi*AϯD `Fle9IŒytlfM*[{'żq(S  2?4&TEXl 1w՟.0R2 M t:fi2BQ{?->yi},_ ?A@e r?=VA8Z;j>?osÜw{BFSto@ZWf)tKs<:sWJ9io(NSWz5Y䀉\'9I}Lax@C5@> fA@ XBS e |e;i֍Xuw^,L5N(3`F/y#cK rD?k=j4wz=64%e6`#Xúncw)0q`jMrM)0U<3xGGG-}zBO)%3&"g*r=f\h' :eDQ=Fh+mnkz1d /aYÌt͏~a5z+_yïH3/W1&~WsGPupOXqy]2^H"OZLe穘뛨DI I7,fZcZd/g9#t/ ZK<(! rp&3S_"l~q+ z *\%ݩ)TVuDY0&-d:+9N4h^"Dha,Έ4: FF78L8h7֧c!NCX-R7h.[hq1T<&4k^yZj > r1H4|'St\N/fۨ}3 0z38}|1(S2-VQJש`F5r&/Mr&[fedveJR;˽bQ8mgnwF%.V&8nGehҟ.Hl$dX L&*8M3V AmX`n 0r  `'odˀ}w=b|ZMÃħIfȑ?1YE`#o$J22L!g=0/Xz`_FZnTfGƑ) ɋ'c#=z4崸:ۚIpwf֦C p6('Xƹ,e#P &ҙs`wLyp=3cw} 4bzԵB@pt18~\ epn%p(Z9M^[1jbΛ T"54+-k@͐ ">mX Ƀg窿e6Y7_`)z)հw uN< / ΍% qqpp`Bn:y=XW+3n)E.Nŕ &2 A]\z!1k g w@g \!WeM hdMXȃХff%'J4:Y (٪7҉NM#Tc1OCPZi 7y0X%,PX(K`?}P'I Mi<ĒOY],i t.&<L!,-bSsOI+L*6ymƓ\lJ6TmX:=KNXx8c%FZ g׬:1'|̍å e8ago OP;[ﺎCEh‰s{NK=tXxg-L=Z)Ԃ 䠳i@q/5F;xU;S袋ɾ80NAO΢6*=kH# T!+.§ASQ+ih"lEБƇfjHAzFzd:8uc^~YwOK;q(힭^zJ# ] SKNŲ+z1`lvu);WU9 )PrUGb/\1޲ ˀkU E,Gdl/Z4⩕S1)Q0*ArJ6 k;\8,;$r!x)n3j81b8&N YCv%Lm!\Xo!]•uR"NU]Nݦ|qw:QOP7/9 7Â2ͽ #xt/@>%^^ S `h¡xFWyvRϚ<B(-Kga# (9vc F*4!? QFn/3 NJuR!:)^Qݐo5h/}R7)W Z\zoT}<.XS3coJaGT!.TIxSu}B6eKup 6(*a.X /7 aM'0*}+|(lzMm?kqjW]J_<`R+gK ZdY?YȰ=.P+ SaTTmUeŒC|t47R]h; /ڿi^$I:u٣(0X`j5\cvhUrZ;j,]^LUWW+~qY˻~eYϻ1~Yϻ߻~$ g%k#U+ 7)`ħzÌtۗSؾ+[}5W!T/ TБNM,JG{$eB[95 ?ꪋ=VMb_E)'] 9.BqNlW+=w_-ȭVXؗ?C-`5Xj8RX353y"V489JZu孟dLաon5%F8*Za܅F @2eO\4AAJmdT161qZϓAZLxY).ay'sv{+i;?H7͘l6rY֎沉Ms1~frDJ"9"zw^VE(H,gG)s9N2V(sxe V.#Y\vhGBア{rR cirqexٲ%2[`0&g \h#5 ]lZQeٮ ^Lr-+K}t0bET|IPm^ܸyyMWIkw7.B/b~?cc_r,/XqGBZC 2 8=>r Hp2pg!zػՙyNi;W3>d¯dlC_h5zg~il-uBQܔ %P,M֚gIM^2B.U^,./,nCY,ef)6yt06ty:^ [P{VsM V[ƚ,Yu=x#\*.-n(nxq;˦_ kUSU*tŤUH]g5ʳ;V(k]jV tf}.o]jV[pʦϼ aNߖsn[)͢z.j^ iכGva^VH' Fɒ*sË*Bp;ƾRUwHF W>p ެhwB!t$.վ8bIuN6Q3 V8CHTFGĝFү 9iMz_DlVޠ֮ , ?{}5MJƒ?yw^}|#/Yá"} g7Q&u(7U8>6CE휾>:训k Znm5 sd|(z G5C=Mp觨>PWwbD@F:1Awj4By?2VVXVV Ѯi3F\F| {Qh-g~M28 %VP' ^vYj^.'H;U]n]4d@ռ@4 0)9)i`7RUsRE(FVI)H~A tQq.J뿣M&v ɐrS(JDi?:^t/be&kcP×Pbp~fIAӵ;Fvw7 fo:aԛ̤*4+Q7T`>)VNS]fv.N3Q[9JCK)0!Yxԯp{:utlP-'tg>\YJk\ב检R Xs墀2lM*f)nYpsH` 7]l Xp.] &^k\_ZrpyOK``&Wi؝"xZ7wEzt' u)RA+*ֈ&d,ny{xP’th"Dc(k} )O>rwo/?r3 Z֪Ou'mb`0|nf",CXU(lXEF̗gtG?Bb2i-绸>\_bfKՎhnkN8Eg2roϧ/woYم99ף Lf=X`r#|^!$Y0<KF?oC{x@/ GWV_7LbDm `+֞psyiA1&`AUL-MeIBTP MQ}翔:'ãwȣ~L`<8F`/{kϩ67Ex j(j `*! z+E/ Uކݞn[ЏM@{˄cz. -/%A[?\$M;6T _@1u=jOogKL:*,F!`M?9M x讈O͚ % y4N@]ٍgH([-JIࣇO;aIln[?*XZ/GBFQ$tvԨv#0N#Q٬5f'3tQH\Q++F==Q)`5A+\gblMUS_g럻 &zA]A祮(ϞN=5Wo^Q Yd`2DJR1D,1E c ),?rO(^ڱc E.ϲTZnybjCYv֌ +J9:kk?Gc `CIk6#Z2kl$ћ6O;vEh2޴BCR@l!ZXGMq[HhPG%, œ 9 ;j  )( * w^N4jksX $9GԹ|؉+hI0eŬeг#mo,z3(|}lĂYn@\+q;Ԗf6X|B/ MuMTvM(սX &b•bmcK$w`!g c /"lt<Z(0=3=WxuIJQMa"<kRTRv={OXݼoJ\>RFM;M/Gg h<fi0V}໹ ӠwKf{tdh, p|$z^@/K2nս?vO@[LHxOQ@[Y%go-Eo}}=RGP }VA~g.*3W4.#& ít]Z?N"r 9;ۍG[kԷv׷N_߿g_ !ar:54'ѫ#j1.\`ݢt1Fi"+bMT<ĤxGhh<:S+B(KL,yC R -aI*jr)K:VXS?^v`} ArLG:i0(֣9FZm\צM<PzܔUKgiQ">%[J-?~M>CT vS1djNGiWl0ӧ" Dܧ. /|g&K O&@J/cJY@D@#AϘ, 56=6L#jit9T`QƎ&l j_ߨ*ԋW~^XɌټ7\"wQSV*%ϵɂP`O6/fS _ Ym0$)漳ls m9lwu;lx6 2Kv-S"I ZGI x8N5J")`CcB$l t/\$hX Dܳb0hJ87)-EBthSoSF:[A %tͨ+:9% /b3fe2cqڦ T]ܭ~ y3>Nenh$*Nrv4M`|amG<ʄ#,1a.ƅH&5B5 ՄdtIƠߛ]sJx*yIPnП`瑵35ߜ&x8t1%B6S>Y!ծvl&+v 0ͯDkDXjZB~p*8a(TyCNo%WzcyRl8Z'6Sh)/GU6=& WU?™pM}*;I.!-j2TV sp%⡲bԪ. > _-p^@ )~@qDay樷O^ wF^hbvUX*G Hv-4\iϠR ܽ"gU>F ʹh3-(->P||L#b9`|hZxApAe[N,H-=ySN6mԳ #OӒ#1[z]]bCKmϪJmޫYSp2kD\i*og ֟OzdžKl;Ŷ&mhȥ{pm?xzuUk&@p{."U I iZ!y/jӸV(cnh? {Q5h/= ڠGA*QiC*!XmJ*ِҎPߡ)­ ֢C% Y|՟3R9NQadx91؏c`,&F`q2x<+{s;,l!.dx}Ɔf!GYk ptqGccsB1oUX:TN@g=%VЊń(>`^d%ILIgڍ5=#$^AiUq+qBZ̡DtB&x5HE2E+Ozg_XsټE0=k~@H\ejjFi\`4FfToF[3PS1E-br[fY\N.b B#J3Iu=P҈FǠUl,RZE.q>+Tt!a-s\X..D=z OMU@-nڲGNj[?zG M } 8^xΊrYfc08 {"Zl@ǂyZX8\L #g768r ,(vڥJk)AMj;Vx>6-([0[.y-74`,3g[96ynyI {ؤg[r!,;5(օ֏Y#6LV[!?)M@:UgQ%D7">ZJ[<[%&Y̖wwө8[ P*,w<FL,/Ƽїԣc.X̕@b)jr!O7j޾h0Hz`=P]`*`bwp5!X^ 5 Pg,0@b:x  Soi͙~uk9R  woZƓkցRO#Te Jn!'"P˗i@AN-$#^ &[nWyL bIrHSY>@$Z(ilȏ$NJ֒(r]#rp0f9S,@'bF \MDaX3e{(||SҩҺI8 lJwWkn[,KfٻV_MrRnx%@"q9%s*Q}$yj09ݗFcq߿GWٙ:6DA PHq.ŘX!戳jkyя~18S%4oa|X@ !R>FO)|)T0b1>"*gn5v;&h7-Epb,f"Y1]2:"߹] xUzZ9)&ỗGSC Nϋ%Eo8.C輸kk>uOd(DnR9HƓ'|lז~`;9;Q@v =QLژ`arvC=ş٠9nF" 1I @I|-r:fn3oqtG')p`u1"D5)V91#~bsQhW@`{tt OkƚJ.N9o p>9__#XQ. DSHGa28㓸)WTŬ%2A*5&`Pzt:(e Kތ`)~ohn()K: uv RO ?ԂBVc5B-;m7>uuh'|\[{yuqkĵ[vHy}q+܏3AmFt|έ;Jko~q}F[*<~>%$"[{ѳt˩/`rӛͻKJG]1n5e}i;AIS̋rwZ_Ԭ5U;Qchpu#:a3qPȮ\ K#gl"͗X(%j2 4>^ThPZ~jB6dx%b#% { } <@? ^w氺>30[kfR*Q KFX׻x4N܀|)´'+E53FjoU)DPjy4ۃ;j-Mnv6)yr6|_f:ʏxۙyԩz~rHةa>T VOO֔6ׅE18-}3mHA:l(a+ςMJScPIJ TX()˂ZpAt*u!L۴nP]|j9(cs|8J5>CqK2J!5UH*ʎdAuoO*qN^ѥ=YJF*tSUAmzmCѳfMJp2΄ vhȷaK *VBo-Jd!n*`'I0Y - "QZ&!s[-ˀA^jTJƽ}(#\B+ҏ_Lw,(sFr=ۓ4*ޕMVsF'?*h[~ Ř^X/济r~ 7w%ɠIrV[E̓Ul7NZ3#?,?#+.Qf2(X:/~s u:Y90VgJ.~qWF*]+/"j4 8RKv͘Y#tdA%xBb,`<شj˄"3̴AXc{՝U;r`?D%!du5hd䦰p_ '1˜RV\k c@UCֵ hd@Q(z/s+@JA)*VJʿcTHnО%{rqSF]=3ҭAU%w_WV+,b㯳W6Cʛ#WH*y FKܛΡz9}ml:.% XTlmNѬ43xٹ)BCxPmחCBPY6PdAI) 7]5yD KZ-ܿځ^o[EZѻN+^Yl"}#3MU|xQXdA2ݥhFL*ߊ9\m =}QTZc /gRaEdrOdG K1+cP.|>NdEd|0s0" ѱ~]Xk47s0ǣyid3 F4o|lwY B{l&vӑ)- ]mBtܞ {MgP2amu؈ 3=-v q9{7ei6ĉBBj"{񣄨CIez=EXugP]`@9Yo&ZmĆbr1_ iZGlF 1-`p;rkh&%O0`:OǖĴfUTmxV۪<Rt: V#XfߚP}2'u+蒿 Hࣾ>|j@VwS*\Vv?&5uwD2 Z(~j`\ \dz鼆>FElch0_/ \斾ltQ{*zo%sqKs$Ҩ )c?λ4$dd4ggɷ'zL:TxU4;6^ӤXj}G,D?yNNYw4&,`n8,MhOȓ& |W&$z.(Vpm\@r(2A`6Sx CFi#:n h`af԰@cC٨٠@KbK# V/?ɔX0&s g) _ZHh%DHn sPvd1"Y X}d: n! >;0̍^J]v c J{a?a"pPosĮqKY^^=TǑTYCG{TݩhVO[ةίg0:XlO,LC4S'OZu::euj}𶯔uj} j2sSu*4΋שU/kY7P_NAyBYaf1;7|~!us~D7puk]R\K._Ɉ3ޑ!_QUQna/&7PGBHLc4\lBU5hl+`Їe5Z:b3I \xoC[M4J ipxAA^ʊs B ."|h:#t%U' VJ*baaAt\5)<ĩHu5*sI죎Vm/ ><O?"c OҲ0#4lTFnq|%k6(b/鰣yBm3( VKو,/U H" (?rLL5xWo'ڻ++n y˩hWlѧ^*u\|/4~qu[y@Ly+6J<U]#>KԧyDr"^,b UeA@97a(ay͆cKF<.hb4-sc:݉Jhx׭hhNtWƚ%"(]n .dY;t am.7羞M/f+ܸ%`=ۉʣF#Wɞzep] /X$C)RkN% p&S?}Y+'SdG$e.Rpa.҄:Dt-AgC trN8V95c3<)zWc$/9ǐ?;')5>-ՐׁE6e^>]A\oѫ; ⫱#ܬM L3 |́N7{49|m)$|cpd5K H=z:t/㑟gh8+f.)8;2έ<8EQ<RQn‹0rg@+ Yu1n %DQʖqyIJyr؟ǜArt36Ueo_ZqVLnQ2LfQԩ}0>l2CcX#<: av ۷n7*@dTjZm՛II)Sa_szw~k'R]pyw&9s.2%ƱH @b<:D\YGtrۛOwǶYĂoM T5?\Y5MC%%H.ߘg5J(iاVpx㢦fr4ɇ4 `& FKCZsifÓ%b 0s׶;+XU1L\N8^駘ϊ:mulPߥjtgnzS_5?7S/g#"}oNV+YLfkZ5R< "z~"+DY^.ߒsę5<'/iB5_tL5)ΦŬQe))upz=s0x#:0 DS"C@*o>ˌlE&9(1%NP\B M8Hq_E$5wŊx!gwEuN@qآbx$\ba(a E|T{2T5Ai_Y v+Gw)qa8lcy)e3҂EI`S)HpśOJ{d*6a-J;q ͉e5bh[ZLF/1Xs ~]/˘:ۦg 8b3(ZÂrVs 9wpz`o288D 4Tw"'#NbMװDgd妳SX& Z./֡w[y"zׅx'R<jsRκ^JoA 00J`wOVPE_E_%5<PVZHl 0 h4y7%t=zy[&ChNPt;(Ћ8$|g1&aøT3} .hT|.?%]?7O,d+}P[%a*zy_MpVig㥹WE6i.Z'(X>rAL*#~"$+MЦQBPt5\*HjJҀ nd`3d-GjXK$=; ,SG|ZD $cdLFb{PA>CxؒP}?m\(G\p0uXP:X\rh{ kQ J#׾7|mג1|Cs؏Rb;81KFbw 2{k% o8kmTl̢ǡZa"2 ys0&xWĜMD4$yCi 4F|@.{\ Ƒ.q629sCt3g|B"Ղ6v.4l{e9"[fuyi9%Tܼm"O A@]Uh9ƇIJh w73Yol2⥺6tĬ8@eEQ}ڇD.79ˈ K(sCCS`1 b.iJM&0p|`yøJ]%Q]\ n&Wfۍi{w|3K4F*%O^-=4]w5@ʝj$Oϣe,6%)\JG%q/`:JvQMc- w>ry"ۿ(li(&4>oæMtͪQmA)CW򍑛(;0ΓETyב/qÌj9̻^tv)+·gQǢ޻)@|1߼<:yZ7Wo^:74Ko9<*7|7#oN:/·W_EM _o$lo~鞞{U7&0xwS]ށ] UM8,)q8ʤ!v>L3 O8Ddl~:a x i,Oxu[Z&V6]_/M}SU8%} _A2)v󷊾l oa2tv;'U7'wL- `"sZa~m,࿉ȓi&.I<e]Q%}MТO:}CdcXO)> OWs\Z*}x6 ]WA]?B7Ym:^B(4\8:Rn̯ _NJy+ʛwr H$RbY/rʣd =t3fFټ ku _vOثHj,r쀸MGmT j~<޾  qAfܦdDd&* @S\RSS8RYʭ*|Y]1ؕ?(kȵ{K ,m7fO~^Z^D|vm'I^0 6*V" G04@ŝEu?*cm2]9΢z 5΢OTJKh|*U1pDžu!tG-熲b~D9A[qu&ւlyl@M0\86= aAu6\N$G?‚nZ\E:''"tXڨc4<̫lrY>,76oD^(hQ@(yv倠`ˋ%l_Jx G$Y GLZVD5b^ fRAٺ@^X'F/7- ߎsu*Z.I2U}%{8ڤ9CuMq p!j—~=goxb}䮭M ۂ Hx,I{>¯vz8zAX#ͱFvtst̳H(fK䟨ҚN}rHv@q Dx=!{%Pp|󃒢۳s+~7 Dlrh[ 񞒩=EE? S%RĂQLq^=!މ[mC$[Nf|o1'OSQxzB¯½6WlI%Vrȩ/q1|යVE:`uٹU`PbVđH--d;<'7 G$ VR_D浍H40RΔ&۠T'4!񩤔V70iVWs&n\ ŵxH福->S k/wuiesxN"z SZک%SJ A<̯5 A=VDqN*Q\n=Ji#ſZ1CܿcNSp!C=n`u gk lƚƎ'115W5ii&)xDkWOpr3 ڃgri(P6bYF֘A֬5fl46;0Ŝ5jc+\sp ,\?P?~" `Oٲ%qǡ ` R/?)RK7:|vvvRo4Go׷55ilom=z[ տ7!og/%A[?\$ͳdQ{z};]\ΣҠLz*,FUQ2=;1 FYͧf-:U+:NUL4';Nb1:7xwϷk7}M@S@^1Z ((+<(+#tLơ F5oZ7a3-10L 12Wk3W9Vۨc> ͭȴt t 1lu4kFIv)t u&>JCQ|~Lݡ`L/f4^”Oij3`J[4Ez4cFfc%L"x:l)xA~V*\U@C\h )[1ZP "l&!m|6Q<@ d>Q" Q[Nίx x0m-(:4VvV$^ܒ08:h% 2Y&+ !ApYѴAڠ|_hNj4ϧnf#}7%~Z/SW7ß̗x47&;f{ۄu]M+t9k8A/"{= gO/l m2,0OAُR%:`WDܺOZ/9<|V)=J!ڃ>|\_AntU`q* Yi1"r +a(՗ͻKʃv^EjjX7ʬ-*js]]^lȞb vtDﬔY hYyx*vu0!"x`3+/^,c=jvaGf#j춶vꅧ\e#G1cۿtDQ ?GF]-AB_j6[Z 3nOH$]] %X̀(%y!ޟ.dNQ _#MvqQRZ&- =|~̺Z>VuDd A 0 .**iV4bhV'>eDb 4btR.̛434l(VbRI`(#j*S`xf Ŋm-S(AANZrpqumUsQ4C0aG `C;5sd{jM&@Cl g<&+du3W5f|q4!dVm%ְ l8bp?gx%:@KmZp(Oukϒ]\dDT0^tӓ*z$sxTfwx#!$txᔺ|SQ4A)|e| /K,FOO|[}Rk3+$h5u]~P}x쓜BwQ ]q@?b~ bB3R:D5!-$32=ry~PRA| c"!/W#5.s*.9 -we4KHE#TrK)1]j 7o$^_.l#m 'v媾\Woz|tr28,~ Hvf%Nm,[-z$ە%lSTgf-dRQ Bw}}ӗ}d?Ik\ -½hA8Im7S儲Vͯh,]^h`CmJ`|$z^fş^\<-b0"L 7D(X!8jc)(z`7] 06ԇ 0{$;W1#_$(k D vDkT2S?ycmdrvoֽYQ~z/t^p஄bM1#͑U<ԕKGeS7W۝QvgqxKV) Dn,:T~=}j0˺ o(a#7)VptCl4nA` )JUZg3E~a9#ioI~.n&49şݧڦ!6Ca-vjvpx'3?|FH CCj¶Jj躢>V?>x`X<+ffq T蘴G!,e[Zج*_".Ӣ*>HF @JK1pi}0iE6$KF5${p~!JK9B'2>߂CE>#[톦}UK^lKW83βX ]S yeYѲ*Y12ǣQ c `b_yRѾNy{!ipg6oNޮe{asVl!1u(uME:0K(32"b=BNFQ+-R3sŧb%H=UbjH[9H GT!+ޢXWhnjʜo!ƌ `{ ¬ E_OZ] e~9G'qmO+ rC#oM@;'J8:݊S Ωf_w9Ct:%r9gGx7iXLf A3S0B$`V g5&Xhk6 ޛI/f{qn[Rv!Q-T<\F] ޓ@ H>]*cU/tCwyZ-[Bhq ݎaDY6{IZq^\ͯNuƴh~-+=vjFu4&v!]e\i~԰i3po2uV8I`_ޟ5ܲ-G]. z?/^rHyh R^I@Y]৲ݒ:lٛ.OL\==s*M+ͨLQq64FsuvIOA5*p񿠪g<0$Nͪ6$Q(]D;!6pkm.Z/# =h?>ht8|hKV(Vm3lS9U:|2g*s6wpȢ2<7 Y?_ϗhWUк-U6_h/YUI0HjI8qkA_J5.L'R}E_i:eV Wx S cRdS , *nK˰du^B }z4tEI\g$P]NY 6m_Z҈vvgIkK} d9C+5M`kbT|nEZn~_<W3.&^,fwJ[KNE˂/@׏qZcӘ}ɤ^b:Uvֆ8?SG|f s.=.cn:cVep3]]+1$EfzL,/0bd]K3e\6[N:=;d<61Ԩq/急Il;C,Y҇铪?g2M?+ ;W9W%i1vgM%aS-y,J;-\ .<֕»(rzu\Eիx ѽ)*l-xg%kiu8Hswm"c/oٲ "8(`[۫mX$z1sFb=stQ.`8cD`^&FFz||O'/AQ{Ul%(/1b]b:3Mr7?2!(3>Ï.#K#[ -6Ku:K\J[.:[5'֨bhɩ'e}fN ?B4GڰSo[3+/װD04 Df? /t<iA0A`!\dJwN̩M'pxz y\uLn_\Eku4I'9i~׫ayd?uzv]/vSi%d\n9.,o%f9hdM)M,+҇54llsג@M)g_f#20_XJo~j;y愝SDg\hjZ/-ʉ{(Vvu'gf_n71z@Ј.XIpf(#Kj+cs2= 87ˇ]Dz.wxQۉ5K kQ OnknЫ~8=٫W[*se+̭y55.a3۝7orםJ1kAM.1lH(ճ&54biK[7:f*gf S5VͯlV䐣>S"trcϧ=b':HCtƸQIۄQ"ZR`W 8PtϘ&ͬ-œ3 3UCQ$$2P5UX;C > ⛁ ֭NQ_CG;-[3¨j]f<@t{?\p*cFkzCv =?[fz ?9`:w Sa#Om#1"8[V>UqwV{٧[a^'&Wj W!&[V-Qϼf/cvxWzN*q- ݶgGztBl?fA7j&T^:j  xXISOGj4ie.V\ǒzvk=/08۩7%='NM8:bn?rOHjto\nz݋~Q?s#{ 9WsyyǀpiAR 'h뱳s]c_8ZÎ;U>gD4Q<(%@BD]lcRӻs{Euj)8݇*BPa,t<WH;P!߲Y$ቡ3+~{$c7M|j!9G0(Z`ѓIJN  @sLfvGZ;o([e.HuEy̖ɅP;sg&΁ Ozï[* x( ^/?Z*XqSV0n纹3gIa_Cn֗ \3 Q+;rʟsX4a滊(VfhDPL /G0a"\X{2!#tQ j:O[ώm1yhwHIqzHq00r]6ue%b=!x瓎ʧ]3ՌejKg=B4ʚS"%qc%g\}}h\.WΒL$țHteS]3GMJJ( /S zC7c6(ńX-R4@9şcnZ6*.[CT) 2%-N6aZgKC/^/m‹(DS\w;c QKZodaU/J"t=EE16ϖ̎)sҽW<ÃG<ʇ,ֶ3#0 ߅z]_7uZ)QsPTn? Fv/$CI .x'ņPzݭzS6Vs~@M쯫==?\@?)2F׊bsv7;^d/`sqyAm Ht+CF6o㼄3*7ES@m_yX8]WqF5O'|BpTρvgk!;m=B0|dC^+&R oF`hʗlH6Q(,ۋFLWSg2gv(v/B R U5?ҺS(bl_9Xg=odZ϶>r]Et~=.P~NS$m{4LC_1_GfSY|L~_0o]Z46 L2dɍ"/FfJxrq) ev6l^sL$~Q쓼dE8`4vVs4jʵڅVqR@]#⯸f:$5hx4Icr Kr`w$LsRO8_~*EJUj/pN2TlDg[’Ƿv[11ÌFwͦ'dGopT)΋ eJ/%z^Er qUN] nS8o@?,GpcfMI4 dvrEFOxYL#l#DwwK'pv9d *IE_ PW_?4k?~.4 sdb%X .m原&Zќ":nnM{^'C%]~UUƻ+blY5rr?fp%XrW^t08h#0M0қ*IU%Mw2F>ڝU2tQmJ툆ҔNdu?֤ĘL?Q] W !v Kmz4a@B7R&9E4uc1}r?Fj!p&1rNNqF SiVeCE}L'P) ‘!rޣfk0}AsFc5.s*1Kp|%kjyMp_?D2F[fz!QpiK)0S ̂}٦ex@r!adcc1սM8`2'=O[~CIa@Oh\nl40WU\{ܸϛ 薠D( “͏ޕ(k/:,\`QDB^3&"dpB] N@@pqHG5m#v\C%V1|uó8s_x~ 8uf"YrMfAri/hH62`B UGNE_)0bS0/Z"9=4hjA/4:tVdsp\7JVuઐ ^IlhX>+ڐt<}Hm#h_Yۨ6횯**놔̫)cҍxpD 7r%}>'Q)PlZ@RhGbO0% Є`U"rI|nZ-ׅGJJ@(Xy׃'1s!J0xxfYTElO@2My%ҐVzfdBӤUQ3c^[u3\*7_j[^ה*(W  H.+#Iϡv~~x]=HMKؚyb&2ꕉkFww^ h=bY)\A|jqtO0N|Ci4c͒}9/t3 p ,{#Qh+?N&ݸS d;Sr^f.6uKo횟(&nB7FcPVJrE'yw*mn_u.]`L~0}eH$ͧ,41)NZʲf(2"qԋ,x!ȋjdQP+f)z @i(%W(ɖ%uipҡLE4_|/+#ñk~l^^S_4ͻ5c끆mh#iėt5?,&N0JݬvW:{L۪6aUܗ9[5`dLּ՚CLX‚=vR65@|AKGMQ6=S9FQ¿tl18 Zy\3je@3^(H Qa]g*P|)"47"1 eda21,Ӻzh "#K@cl~L+Z7iZx)-tc4s:*na=%VFT}#S#o7e1͔ߊ|+8+e&7\x1STJl%\a?_( DQ^t ߒA$_tPڰK2m؊9;[Uc8Gwzxf~T\T.gSy8`3ftP.G}LqgHi^< q}IVd  >hb}F6t-j.1\.c'.jl]!P޵TqC2B{Ƴ"MY? DW2g']ۍ&H7Nw𗭽my_y@<[J[:b18Q_xR>g}kj@F3V,E+8ߵXE]O^> o_"-4)UqscΙE\.-%ucC7"M"YU\*{w޲Թ:MOUa-:imT:kownQx<:8YRF7`"]Xqq䓻0nZ+2m`dwn<\|'ߋx^dZ^l(M +xt-`)`>c|9k n[ !+B#})YO"bo/9Ka|ӾkBV^@(<> nz.ʣoט< S2m4U2;Z݌"r$n%N}E, 3wk+YIA Lr#咵AЦ;/}R3eL @N!] EDW9u`T|#)2u!gһw^f7^=HU -o2`#F$TԘl_OMv 8HI0 ,}yaTD%ꓻ* ,,;6̿(FJg1aYj~a~& AWRF~FC S#\m0-/HoKWOk;!.>'@ܤFI=̫ŕ1 \+/ķ!2!t3F;-zvkV)8j1or|R\%cp)kIBv4O(4FKh" 0X:5Ek1"'I YvvY1ז8}vB<:"xPgg_K&2FkDԡj'Oq[g=>J'IT M7 PM5U' r* reOxX$\S3mlɜU!W'DUI"Zy X*75a s4`ce+vQ^QZyа]~qg&ԞMDeE#s8'Xfpӗg]GV쐣CQiOFݰL/)}! D=utѡ(zި hzgMC# 2hIskčNZA ~gdʫ^5M⇧il3CUڹqE~-h x^lpjL\%tM%296>deSADF?;}Gv o[V3cUEu&x˃,DHpS W~G/9A.ǨT&VWxe&\_+*0p8b^%k>kV_F̛L<|7LZV$>dݏpV;qyFIMKYYF#1"A)S?9z*C>+#;қq-#bOuGCfn3fյ] W61T6'4ҷ?Ws 4 EX*%3O:h;Ѹc㕔́4ȵ9Gc݉9` y4:"8>zl#ř[)g=cʔ>bdK7(Yw ]u+l6zG=vΓ_|\shʱh<)3?g=.°߭wq\oЗ 1/[g:PJPJq@cMbCw@k$ G@ C]>I,w,"3̈6zi}t/T"[_aJx}oBAd8>屖I>i>67nبr)ayگh e:I_9Οn<8.&<5[eQU"ƥZHƉNϸ~\>ɸ%x~( G Κ=׆MeS-Jt,ͭa7`r06߫JVϖ)C mUt4oXH;&( 1vzHt]0p,93LWې?4E f>gϓ,0HD@т@, ,,#PAS zA;|ztT~J8<&#bOٝIt6ee%8t;B w)rڟp41cgu3Cg6guk}jOJ>t.iIRjՅzca=Z pv}8 w aE| 8|\1/bԽ$s>]I]K"z]-Y25'hTCțRSѝEj.DB/dՔP>dY8kHJ<|}*EsWFvY668FA'4 `xB>^E3Yt$Iu ԅ P(lJ8 (k 9;S-o@оTD cuԻIB49Ӫd5%S2kXbDhGfFkAbnH; )ұ= xÇ-8J* ǏJߝDԖFGөoJtvSO:Vex`ې9<`.@xbE(J)Xģ㍏ylYxrngs,2R(ԊSJK[L|.ś C%uυ R n1ž٧SYpVc%R%ʨS'Kבpe&S)(Eڃ)`a>6Nm|0м[h~h,M6,8)7 g*՛4v!JU=akw ,i?5Z sXDJaS]D)wjf[sjtdc$щ,ŒD3z@-{=G uV_"'DJ~u0;\ wGO# P:# 1gti[j]r$<'ۊd"EM{ȡ rur}:?KNdkr|rΞF:8Z]UWdu *r3j`bX=9ca0fʢoۆ=V_n^!pNaóQLRIkhNde6ʳ#Yk.:ƱKv`h_$? O,[Izm<\7Tj17x2 2zj,Ƅ;wuf% S5[ "b񤶫!{M|HN&1RaX ZL ::ЬuɌSB)/ =7CDٕo-LdYV:"J'5m4GGGG;&'Grʩ@UwI?KR3L$Џ)I&jr 4JAhPܴ9mTn'W܎U r=Fs3”ۨ}H9%cTa+b~ˏ(FުGx5*j^DufGyXVCH`D/V6:ɵY[nMo0Y\Xk4y (Iy<5Qc(MHO` :+_eXK 7@ϒS\Ym}/P'ţ($ݯ1b-*b)K>)նKa!^sb ;)igaҵݳ+2@÷ =h8|1$ޥ}pi5ܲcCiz4W[ J.ӚU Dr*5GA2cNJ0QluHb _&^- ;E}43*L=]U5 xxL1˛iwS*%i|妊1nB% `Gj,Rmv*)6rk F#NID9f(chhkY]B췉Fn3/7ZxjqssSQ=]U#Y6BsHy{EK㨯*9-Sϩm@ |91lwHj,1PXBRmT+ ~sC<㱻s,2}puK#0shdY.`{׉nKe=csƐYy2d.~kRxYg7,S!6O(#"%n#{WL+#&a%f18ʝߩ3YprJN ˳LΈ*qd{C*n_dTEYSg/M?4?SO٩pLնP R^VQ p[?y5S@'$rЎ zl8eŇg,%܄M#ˑ*p^8A>m&c\2VS>1׸!/>7rC/Fdiy_|&t7Qo|K߯yT~4H ԋAV$̈́ChzG0@ 4(]*̒oY@˛\ NN]?#6V6QbLMGm!UZ4yW 0IP8\; F؇hn,UxzT~$9|tix5yJ4 Dδqb\1'>Q^"NJE5H%6pAUy9uw7lῷۻ(1kٗ4X 1es&El73!73Of"$M1Wu<LܟqEӁ ȯsJD_r dK[m\PKX1Ξ`8tةba:+cɒOe]gU\h+uGi8`$mqVVmW0iyin9'K/QN{*=,mF?9͕3͵7rsGSyN&qs.rs mh]QJF5;bP_нN)v4a% ls3*TЁ+4ڬ 90PY鳐{7SksI>Q* nER:SNO_΀!N^N/|~f4bR%~_g /[{R%[: 5i;}4yvx~k^<\\+9_cg-@\«ؙ:HsCKP=+Tvpмzl ]>ڵEy ]1|^tgb9\PLŻШn/Dl 7V6 ޑLjhα[kx/)8\v頽1?`Xr$W4%L4FE1Mr? }$/OL&FVBqF%KNJ#+ ċVvSe냡$לj+zm)yO5zݸ^էAp+cfaMyH'SwP^Cm+PvէzI=*%GLȤ <r{=lؕCr +3p*>M17ҽs^u T!<_}m ŏϵg>$!˩'y2twi{T|z oS.!9L\Q?'?TtOL&[;P0ȧnc|ϡyލؑmpRZ/ ZT gbdqZ1m!j<^ண|,b) S|L oF- V|֋5\7oc;IgS;!WNV 8ǔ'tPޫ×QzAԥx451ps7<5'dO`t K*׼Z@WŋWDUy Y44%@0uN?dN(}w,ލ<9~g-Ϋ7a,κ&ZUvc&4 i%{aɜ1S[*+Pˤ ]@Ur6n%wcir 0B7 UwN_ϭ;Ǖ]Xߕ~h Xǹp>G Ф uaRô8$cۨ_+n, [8^'?zjy9\8~WUUWH},ְ O>[SDYJX eJ(leQŜ4 XrmzVt?=LHpY-QeeU2ȯh]K֣bϕ`Q1zc">4%4`8Ow:ŀ~ [jB!6n"'iJES|+[K痧W#8dZ{<=-t^otu['+(~,&ToԦEVh{=T_ nொ `<"mt/f~-7/b_t؁'ZƃMn`}د f nﺂ^|Y̬Xю('9bZT`N,#ӏ̤ v/{dz~d(KgA"!rl|f6;ͬꏃR̟}ضܳȼw|'-MoL?2(9L'{`2apn[qdd h)~yTԝV' IjKd&܆ל$\_1I&&s!\0syJsc>JYPWkzg#گh9g|bf %| kWF7i#ydg_NKgCy3Z9-,6/jj8Ȁ-Z1lvLm(h|lmFtf"|XDVZtCzq#-F J ( kR mmëjA_^V1g{X^jh`ļQZU ӅFvQI{Ru9҄LRurc`xrFX86rX-W1pg}e-OlUǃAnnG>aN~#@tݚI:+zK#EM'ѮH/,t-w."N*U&W+ou.T^4O6mN]Ia7fgE( sagXnG"#9/W1;2q9`d4D'P"gP)HC(*@4O@Jo dL"25Q^$1k#YBtzS qzFl6;`>V ^߿{*)ͨmU$c,77U o\@\ҪQ1Ah ;^ZӞ*|NֹvsHd p̈́[:a9u>?Z`=#QMGRGH,6"2qh#QصE0T *MmP3ЬӇ[+UPU@3w7VZ6{jVkn_Rn,ޓ3Q8adkV&DK O-ӄժ ⸧y#XS?-)Z }FK=ʏrKb)Prf]Oٚq\1 zV Z儔L mlwCז~"DwrGK"gcf|2E2epxS51W |i*C  h JkvIo/x9y04_IItuzV֊>@7epi :3(Z?:IMHۈh,jЏ:Mq{%]ǫe)PwwHaE.T|47&pxpZ (09˞+Na#38wMk5bi9!b-p|Ud:GVs`xSNznJ,yatBL~NY('F* 襹qR1^ʘ]J>4P+(n:{ܓ8%͐ĂWL%2sL!٦j¸6kDɪR8nrnUm}SBu-Hɠ Fd p1rjQ_MxqVm; W1e)׿*(mpAe)ސEC#H;oJT#8NŸz_{2VGV/I8[)աNn{)ܪ ۂ̊q=ڃ*H'bܪD[ȿ 0NtIoU e[9X:%PuoOCT/Nlĉ}\V̫N,94#.M {*m3+R|2_ksab|`p4sV^VQEQ:!,mwwadԯ*SE8:q r3vnƖkgp?l EwX? G8}-NgH?FxPb:E.$:ܼiU1z8MtD?ȑq9X"dhx{2;Y%:l(rC)#'_2R0C}:e augG2$zEdnb@687GlAЈ-="#<|{kmjv'(pw(O6ugh*vT3*4VhT{Fue2X؝1/4#P}qouu/Tum_8TҽpKtwN $]^,Nj("|10k*g)L\@=9@ %H8/}a&ԠT-RNXS7Jz j56vQ:9jk4K mܺx%(=@ڔn^4; KjYA6{kY Y|qM~x`CvD:Dq'ͤ +=far9i+1* +ad>4"H]Dbi[ovf z!'U6d>eG7[t30,8n0rdÒcIˎdEۄE<hFוć5FP[S]$d 7m)elbM}3CSj\BM)ɘ-s23O)J)e#ş1Da}Ǒ27lëD"d8j>7X@WUSڸ3#K%!F>:0]%N7YxAozAE)O== +ϋl=e+ L TF>:Ћ%2 tV5%=3ɇUZȺU[jlIpj U?ÈW mM.«1z쾐y'M>[?C z'<;Xtʈ$()A A_e#lhG q9Y`SwutpaPDM&R$Za!7=ϴA׍`VFDOi^^aBG^\8{bN~6-͂7Eq6˲2p@?/ dm`B@3c hEw(Ӿ0 هEF}.4Oe-U>Rݝl7ЃK6P*dq m ͼ5Rz%]zFO|9YT2I8/!wD. S͕3 zT9bO Voj).4 .)I{Ux zFJϐRd1>UmB2Jl? #6' mƙZ.0Q<8X"PMZ7ijej̮nv\1{ڔpX}vw{7ON64% A^(U_g tZ߆u< -η6d Il}FI2Qqj}c.B@bTra-(|iS̄xPӆJsA0rm&odpU&+ٖet+js|R_JW񓍿Bu~KgĘۨѲګbEfg&E_?ĉ$`| 0{{9FX *(wkbQ}@`$QżꞞ8/+IJP5 gb jH:@>,DEɐbIP ܉avdlzQ-JsnU4.%.d932/YQx >#2Te a8̴|BF7HG PbrV35pɇN7M*.‰`5F[PO8(H%"" Ѿq?~WGxfe`ƣ;#\U0Zf*o~[}wgoEt7WnmX&v10Πn}`B+=O0ג]> ??SHa,wkc^Drf8lKQ4”ptI="ue D΀'=e`c M(TnXr@b~ 99R):I-TckKxbkX4"DdB 3]*;$KK֐dmL@!dlAfR*+Gyal<fp`k>~]>:D`t9},4:p ȝFj_VLnmrn*8W^b$-@IKjnT^eF?TJ㏣<kRr+ZVrD*?f k@Xn& >дMZpE:e_9ԩIU\L6imyuޤj̯^HE.3$4wu~:Ghʡ^: Qߦ%ͭFOw&Mi.*h:&HK,0 ,̍0k3`e{ H;D|T03E ^…U.;ƫ#O̥ER#@"緧Daʋ=|hrC +bĊ2$3d.z2~ʲ#F`y>"dL6;/FLK$Xf9pLlϵUT@E(W!Y8(^tHZsa>w쇼@<;2 5,P7&SHgt8riƔDkgiqʺ^64m~FaD13LY툲XeU(̟~7GElӱM"~SPI.Qm 'eTTUm]aImy|22,DagFc:DW2/gS,-"?(}t3]&r*%A<~/0R?hJ~'%@KQm3Cfn+Co0vqRA<~ݟZzї=d6JwB|=2F#{<0L90SdUy ; @_*֝7ar v( pHKptIwH>v%8I61ఘWMmdjœ=Mk#Pޕ$#f[Cm!#G2`h/xU&WpDZxo&.*'hOzt|Do `U @cC}xj(*knwvoP8vЯQsNzfYZY B$l[|rXp2|AcDN*"~*L+ пա)YT(L1ÔZ.h, AH踻>~{TvpPfoa:'A,P֗R(-Ps1&Bú41I8btII["i6$b -}ސ6L#lNꥐEi0;߅!LQSdHK'gε9q/x}Ŭ6 ^IW=D٬#]sHy6|ۮ=B@NTJvVMd*ii׶&bY5Me3`ëvՙ`Sq*8MFPM:Ac\5O;.4ϯgl-AXn744*8.)4i\찡#÷X/ XuPbdE'*_e0T")?Aby,VnF1g39γW a{Ε[.Иٲ o^Iqd6#"/:A)j>CU"[g; A_ϼ&Ob5»xwRूOxUNHțYI 5]eP*u'>U%H|H#<2H$?]'J3OPEJN9~{ O)Wf_l:uIh =>Ama`˵t4zG5`+8GT~0'̆]"Y n0G~ϗQ]v GP# gQ >|xCzw2@.ӜW lz3;(\t 0m5N3 Q](%w"H٫>#j ,^؛}x"ٯ`k&1rJ[^fATB^M9>j9~*=/FT?9߅Azc&8fljwAwtL퐫 \u7^kK5[D03u2 v@fSo+a .Af֧=w'UɂƚA+ Di :W5s$H8N((, u@t7p2^tJ⋋>:0ÔVW; F5]rlkג FVwuT}qI, 8i RIs:XB!a-ܪ 6<a@$0~N#RْR0DZK2{B/EILS0ZF'"M'Pa.8.Sk}*n:*=4Wh3&'zAQ{K-RD-j$s̽ `u./)u6l 爗Ċ\3F!W\֦y^Xqm<.{/aBқt•LCyyZPw;bLD?Ȗ~D}>譂_I+_d׭7Rovz7SuW@ַEt~xP=yJTW@}e["s | Ex:[: o}@ m\PA}0'ZAA+_QZ@p@Y'n0QaGggUZ۝ȇ4؟ݫ?+ @` ïڳ෻&=Xh).Ҩ/7Șje uSr! N풰O>B ߷q | 6OwH Qg~1S=!fcD1݄glXje+Bu J0cQhL{&Q@ >Ĵ|Fa26q x(MGagh;3e\RD"M2o$܆$P9f76%Q=Ǻd@\VVg˅WGL̑L$:̓îLʣw z2hyq23uSdr~u# [ =*[:00@(z*qRIm҃ش}b*abks7p[29U RSiE=j%OPu]`!j:|dJ1ιzF& *؁M*m*uA9i=-^Ҕ t2UrMQ̡Q %Mʔ=+d; `+@H]  DFXæQ کI%ia LMh{2~ߥMVS b a>,8)s/:~&cѽC{K4쪕/-mҝy$$-ȩJW#`پ<teP=/N2A*^.UG︑Z;"sqQ:7Ĵ$  QR!BM$'lL &).\Qc>{_GUvI</\RUUz%g.2pZiI">Qb#AY}R]']X=U>* Z*膦ܭ 1\zD7FG-B]S|HWfhu{K%L3U6(؅WaR OJR;%}2Rg1B8dxȢ7(#=IPUF);2k|5`8T( I S0h2Ŭa'-IHëo|?ߖKK/ɿ|ilًWV~ҷHg{L\.D]`=/׀Eo`R 5q- ͫxx;"MD[!jjљS 7Nobs =^/;,:!Gc'v8~UROd9{H0u愈1$`0cxkBZ0%dZQznk&h ec? 488)1Оֵ a _C@W-Z(F@cqpԆ*<_QU 핗+M8dVEa}me5D0¸Lv8rS9VA6)=q+M3CYlBqP>[b$ #K0"9; amJ6ERR '+0,L/dtJJvdhfb=(GUB䀬&Pr4WIC6S_-]$Hx'^qR 2vu$OZ8.CIgLU@b"&\ȦmO`^#32ʫGd>'G@(|fuD\:`&nXmJ֙*(tc~9JNqpmn;AZD2Օ4ԋ~ @NtւNU/qadAu+iu'sl _aX%r !\]PǾ2}Jf0mڳ%~3߳G&/8yd9eiW ë*&L|\D u~gb|sc1 '.:$"zU$TM+peymׇό1qR;Sq1fԥF@]{<؀\wjk/*M+l~i SZGo޶|{Gx'~.l sD_$,  ?>ٵUHiȿ"Hĉ}:/s7̬A/nK4uO)Q%,%c*3b)3O TGTbٻ@s#/K?֛/+1E;gw&4*-r{3fCK3#gy"O[ԎH$H%\xVX-oz1DQ p2a+a)>%)AG+ 9&n9y"JBXH;II[RWo;+Pd;]9":H1f#m2`y9Hp轻?E*Lf VJb~-;@;"wE[puug}\70! Y" X0gV.>ȸ;,Ud+ 1Vȟn\YU ߙ,HSD#f_Ę?xYMhltNgai8鸏 T`J\Q+4QNd JL@*FJF]G@j(\S9bE L¬~TI'/ڟV`5gc4ʆw\)hDmp(@_6D (Xy\ZrWj<%yT̃Zݏ2߲ϛ+I\zgKAsxo{X5KUH#/H9A9 'G0q}cC[v-Y@AE҂{dwx;F6j<,%ܮLSdny="μi1%^$X,#'#+$tb'!Y۟֨Zx^fd0ٍϞY֏=H,< @f3tXz+aɱUTI kԯ7S%0EZ +j֟XzVWVρQ]Hf}yȶ 1բlv&a%d%6Gȡ4ή_V4W=WJG -X9j/}yA8VZc' 4A{}|R['v&ԭKart1CK;k'i9O+"ve؀\F ]( |J3hPEu@CEO_2N5hj7FmU˿ aĐ m򧯉@'HOt[e='ǂ\L*.\+' K>VUW<0G/vfF L,3WTׄ$ 3]Kk =o;DRTaр(+  E#5T8 80߱6!46w)/SJy\aFoۭZn֬ץk!Pz]wOU6s*Odv6D @bSί({slT@n[^KrL(kmV0|f hi wݤBozc5ai FLGK5Y6l`tT6" dRC=瀺a6;(&IU`0uS)݉jY寍2obe~96ObTm) :V^`jb9.4\u?I샎A$[&AO^z ÛCI8ec3 YW;27KiEJw %~':Bct;R{AF qأʁ:\@=!(ԽUCQC^&;E8pE=TebhWqi>>=o[DB:eEᇓ8{ܩbiOyG:W9yZA?tv*tX0!|d3 TUi}Uǯk?TJUa]T.6\Ze%*W"-U1;W€,UuUbFRVZ̆71XKsNz§GSehkV^X@muUZ"'k}/*3(&GpԉrHLwY^c^neT ݴ6l=PEhYv$Y[7)#oqVj:O(QpQTO͗ɠѸkI(?B7{yeR0o#_Ldp+r4E?U+"_1j͜,9i(Lb*z%DCh6)9Gl:e op(J*z+H+v$K.˶V )d ( '&"񖒍 L2CZv]ʩ&4ۚdbZ?E}ˇ)Z!Gƞ '(Y؞LbaYlQ^W?kfnD uH!D8qiY2ԽAb2m6p`΁nD&%: iv# AV m?U8vREUk:K[ *x*goh,8 3xvxӏv]XV&6u7x/m\qϲ@bZ%.OKލȬX|pP}*8K#0I9pX}&P(9k{hSe#3S 5*)rd] ;W$Y//xLMǍ$_Z|eC.fc-lj^o*6(dpvq4ܓœEe!"o'p9%&)%*%D9Y0*N9-S^ 5@jnH#5BJz~zڭ N z#$7 ypկxWTiּITPݔwJ-@ht:u2JV I`qt{g-ɡ0cIO˓J ϓEZeSgt3;4m򂇵;}{wvk{]ecO:rܚJwm=4pi#Npvέ/+0E]qhuc/ R|W1Q$ O(-8W#8Ü@(33 h^b,O)U]hzLB݇ZTS5]Q\FOM7Z8DwTP"`"{D&nzh}}T 5_yBu ̪yU?[:3rkvfis:ǭ3Ammr1Un{ofWwv;^Y;[]hbV;Xq箽^{xJ^ܻv.zz?z9>p'̜v杽n[;>.Y;nww̆:8w_Z{u||`E3N߁:G;S6 -N2ʚ!}Yr9f fX}? ?tކ} #nBH\W $K4ѕ›|I]It)+ph:Acϯg%*R#o3t %w@e,LrbI~[$rF[\}T{RTk VEDgqDV# mPX͈x^2fƬVFsJrv`vIBO]֥z3,0ZSRFуv9;OoFD_x6a&ƵU?TL{N?+'*,4﯒50Z#vyi"Qv2 -t0 Y5I{D#7+tBh@2d)+[U^L~=|\*фF.^IQ.pb&?YT@9u1$3yR&+gG[J!CԮR\h-ոp&A_rΙ Dž_iR檜}ǹn1%2dqc$aԳQ&ZY$SWw FŽ*Bx)`^(a2^hTi xKXZ+J۽jq?UisDk\hv&{MVOMbMMQNdSx~xImn3U˪:;$n׵_XVäxZj*[-c'("1Q3DFpCjo:R~5&2ZI{UeJ۷4# BJ^JLm;+T=M{ 27 h !'iFf0;wj>e9vVe_bZmT j~}NOi:lU*3ӛ ) +cjN +x1\w#3Z!ef%ŮM K4p"A!3ƾoɃnn _i~wwۅ1e'P0fn5_IG`i^фU#xOjAVVagH/Di갽6 "9#Q6LE4 6Y 0,T2uKd%㺥t] K^$_\ERz\a/B1Lhxu'}R b 9RlSSuvp*Ucqf5aQ4oD જ&@[. gr(O6b%.nM-bF[`%uvl]ŎužӉBONybޤRǑ턡1xa ZvYG2R.Дxzl7ɢcӇU}ʎ eBImdN5p\ـzYrjrO@,+)貌b @?K2뱇4/![$nNea.MFt2!&coRIߡ?ԇDNo"'.N @RIܜLem)1I5!SἉltMx ae1/O(9L)`*$$])2&Q4d!@@ggvܢO%;lfg3 Iڪ>F^V, 0?w:ۢI&%μFxRJdX~$i`( 6+ܖ֠$/pĒ=F q>n+,)n60䞀%8ǘl˃FOܽ4 i/ uꪍ[b|IQ~sBd)L il~Lj{lmI|O)nH+/x^'XQ!0>tȲN }N,šigŖ^[Ik6aS)"Djf\9y\gƥ-[ޤbH+6`+<ѵTݴZM7ɸg;iG!ZlCYdg̘bc7p#)D䗀[@̃U O*%{dXTnFłGWgB`1GR=W6b'Σյd]GLWwuKQ!t([DK-kͿ<.bϖdl0km B2*o`"Oş&M8A,hH+u Fi6b/'n2Uk|C&c BsnXc'qB 뫓t7ɁǁuEӛӬ)QFJDDY"+׭9LN+PNltfyD$\10O>֔q4$D]=~$o:Iy~ GЄd#5%#dx|f]L~BL% ܫz{AdIW4&ʝ:eСYC`iptT'&6 LpY4c N ^s=R;IyahR*ti6bseD)˶fIj5< CrIn""C |8 'uO>ZNc]ӹXˀvºf帉0#)`,>pt)IzɅ3$<,X-]VbKSc }I$DkaB@GAi,qz;c!/㔀W"-c(,{bؚȋ9} 5Ō P+*2wQ4h|֑#†: )k@ n?~2Y7k?{lJg/hb]xߟ ˴ <CjsI2.PեULS1M%)JJ3_;TX.p&Bsg*zK6vi`Tco[HTzIq6}M ue*/b@,3*a1бA5kݠ^D5 tjH-Lto,fy LKxwWW : 4SH"u#@g7PVlCtZ#Hq9 lX/Mm1iQ4EQoH*īYK$D Ϣ;]GBN f'xD `&hyBrDBQ+=@"\EU&Qri kAsq0aF0>FՆEnund|fvu2:WĔ<1J} PI;s>q'_ޏWiGI2 hj8DDPBu'w[['<&:3aqHn^$F'w'| kpm7U+HIGroq׉я/.1V:~D(.{rTc;Aӟ4v`9 m Tʈo 4IA P#rfx2M'>U TL˖XJ錘?'X:$@/_΁P>#"o'.N^}Y%9Fg&>)cZPҎ . wc]H|6Ah!5 (`x~ҎKn!h-'zWPQGWNؖ1[0`7v,ZD|:RC!*HBgzMG gA?z{B9/OL'ndI i&t0B#G"a'#zF&r3osqQF5r"BB+%F릫{*2#g q$S¨[DUCJ=#ۄRlKD.A61ۢ5.k!! @lj2!X]3^Pl&!LgNr6eĄە2Xv:j($^a[%}qm+|1kǠf]2I3ͩ<BJJSȞUB('Sadc'` do?7\"ÚEJvkI͍ ҄/ѡBd"1#)܋Dpcu<$8v_gdԒ٘%r_+,214!iD: 16bF 9˪hF?.5K:CM[fyTg'Xgob-Y* b\" -΂%'8`9#KL#15Lb݇Bw `%%v8k# 1!.d@}~69 9mc`%0z b+a-g9uNbrj+aǶjV_,snAۀT:Xtv9(co^J,P.:7j.P ߽v!^ڕ$*a|B3&'5[.rݲ]cĴa]$aN&=+Kv ;ĨN K@dK+,Ѭ,gzk#Ep™ f<|li@&f TE q{PixaD<kI #105R3΀% Od̋dV vJFVeƭE4H<̇XN- 9VrVov6 5PYFħe(a((zFl.LL_rmXՆҗd o[Q,ɻq_V0(=+ Ev$ \{MU.Yh|GyBcʌzĂp3֝ʴMf8>CQ0%ʇY&yE,|] X@WaZLgr5NJ5 @`67šJ}ǐM5c}mWMAv1Bɕ*:*OkN?LQD떁F_Hh uJDr._ʘ*ܚG"3: v?tQ`|r咗Lu_᷉HM<>0AqCh 3L):߹0jS#JF |}dr敽s˲hĈW~}2eljHM5: jUGw,u}GW%Mq^v #L vc6+r8 ʦht1If|L7UEL \s^N .kOF{r wvs"/*AhZ7KqBǘ<+{ E‘,gJCčMOI]HCյU66XORc1א\D4Xf-E k}dp>Ώ O70{P1f^a"P?0+t'ڷ,Bq1k\!bZؾZ[}D ںѕbP_,5)"pڝ,JJ}]Xvi?-&W"$xn~RA?=xL^Ml*S aKFhll2kJuё+P$cAn1;qZ7,pMζQ ޕ\|4&zj Qρ㛕_2~9$⨗r$V̐>$AیШUVs1Mk,ߘ9ՈDWFqQYLeҚi쭧S-Ut`@,s^UES٪+/9+ؤ߳jNk|Z?QKZm/œQ午7 ^>;Mn] 5­>#s(|ۑ}qw~wceD7ۀf̴_'`U\ 4}>\%8c@taEEz&KI.ҽ?e}1GAL"uG[j_G. ";FGRwǞ5M )kpOQ-V;"„~t N$̴ſpֵ SfF;ܨnGMUĸ k)L@$~8t:005D!XrMLocH< 8x]4\LadsܷBh-=w^TH1xrؑĹ^J 4tjJ4H|O~<F"1d`ǩW\ L13"L| Ui)$[IFdGH`ӕO$p :Efq{Du))btl(Ljj<`)DLʪcU\\d9&:(kc3] kzd:cR?;e"wϺj ,kgwC@TF憄"tcºw翘(W&H<[4kՠC EG([D98ܫ,V3)Sf\4*a] Öw0:t0lV^0֤kG}a8V'Ӳ(ȵ6^co䎚}Nuͺ ߧP>c/8kܙn"ie,xm5ʕNEЦu4@Eʵi ID4tú&\h`8hNo-E\3=Ҏ5h!OsLg/5?lEHHZæqqC;(\idɏE% 匍q nQʬzڇ@4t]Ma~7 mYoUbnJ!-͌jǑi'vlEKVS沨 4ǸZsQ2530mU -(#F 8uy)|SR7K[CZA EJW` ۍLy=IRHXCC =ޅ~7n43ςH!>iDŽG" c[xSĨi՛V3ykE` -L[g[n_as!cNׄM B9)e]B;YWd3d ;(}bHgf0?!dKz? Egbgr֜T t LIUyf̢Ghh:ΙXpHBugv cw(|)z<9,ieN8Y|W6n>CkhRqZsgI/3 X&V fL.y`ZƬA gƸBɄ{n#ܞreƅ  P4Dׯ?`Mĥd]cR[|eeey ,-X~\i>+>ovp4o揫?.?Awnԝ&9әyZXbuNwchImTXy%s@r\V:o[s6 2-.m՚opM:iMƗ1Q=D6ȅrkϵX+ ϶^0.Z[s-J74ۙcBP$UBa.{sbcrBk\kˀQX{ 5G+sسТN;iۡQOyqgt "ot{(SPJyjtJu$a&ɤa-hny|J*տJ>wNMy>5l'9Dr#M֘WKvW -)`ᆰijZ[V&D^}#vĆan:;?퓗^@ӵ~h7u=G~x|s|4ro;9s<@f\8(ܻyuw;t|-Qa;ϵf*Tj?Ǒ@=lmrJs2FCձ&s{?fZG[Z~; z}>]ăC(3l7*sQt¢J9Q"9ďM4Mn#XF85 AS藹9Bc_>O$b>×朱ߐIB Bk죰~6I$)޸])jm^a0xh9CTݹZۭh\9FWQ8d "IU DT"P~:<-/?2L`Gw0 'x*Mhw2MmLϴ:D&t!t=j_8V~xdkP 襽hup9w=#~a,2+x8h!1r} WZPԵ:g,I{AܫQ|\>-PsVϝwo ac0_a"TLq8 R׌DsM yeMm&c}%Os.c 2R8R 0|]o::$`Vܵ^am t.|x+ 4#XbT=X5@<5-j(ԭw_V1!.]q9Yde 3so{ &N9-1Q0 Vʚx%2U/w8~0K,(t%C F^4}8u  8BV{9N%T!<#] BH}]9akï\ygPsһ9Ͷ8)l6u(<[{9P}&{Eћ9*Z?p|)~z [oj[[0x#,Ҙ+:#*&^`"\yƈ\MPW^^ʔ\^-Y#@~u##$ReC܅FtP5tn5܄&$_Do[.r]k|n3lBCy_X)<|s<_qDq3l;؛1~:L`ݟ̐<(#k=0 <>9Cu7@guXo T<'wF۩do vmE:N.Z]ѡ [Gf; {$Hsp.G 1hU<2"zFϠLkpƇ0. D lN]bGbpQA;HnsH@ױȠtsNH&+X樽5!HLS6*v[-bof= m׶1xe4ڊnc+u]AT ֔#,RG/ ȩ7$١@WDR9泥~Pm\(#6MCˍU@8 ȣ7~ɴ!JjG,+aD\[c`4˅cvS/QɨQ>< 1r EàOD(^ϞϑHB-?1"m4a<ֺxϰ֤\0Vy`pk7/ @%:-sl +A6;zBRnUcߞȕ' 0&}am1iC%G2~xU)lݲhD,$UP\U"H]{70nom͹ 1"(XKw m& LXB%VV}˰: / \$Y¼ѵE >aڍ/h|1Jӧa^97F$2 gPt36I۷>`"Q7ABA&V.iZm$CN9JQJоGy-w>" <|ȩ꼀!ȀHZapN6iv=h::̃eN뗲'3_[8箅Cq._hښk~߭ @GaJ !6 m56ݣ8[Hs鎆7) wvR%jv Ṃ4v&cdfFSHm R'Dizva~1x9GSe p{;6 WJ޼S3#beQ U +MFR0/7>7˗ ۷imw:G$PEMF~ ]>_Iax;B0(>K.G0 ./5x92m%UoZJofB*\T O{'-1B{kﱨK6hpLߏ@ d#Oa#ZVZI[86n:})L >R0D+xT{ +QUJLOyaϲ#n H88Kjn mClwKmp5L̒FoZ۰ޢй(يo+l{ {|9يse{? q^D5g=@@W[lE6rF,;;HqPA!8M%Gqᐠ?YHIiwHkzZh[(=ރANi-B͇ (aBhtLɐ/؆r秊.6h~_2p;9]ZaZjQz^ТOu9E̷@ϛi7Gma)O FNJ50wƴ@y8M[k. RYFP`?U>h/kL޶[GǯvmmgCV!d` 5v Ҁ+;㸏$a&Mtj]NI$D) `~n^;D5$?g,ZfmxfY#`z$ P$ u86,Pt+#z2|{ DC$ ^;乕h8CΝ /W;TۣNg.L@ CK0)/ޒR=ՌS W3f0K*{ 6/X@oԶ!("A}kmgK Q]ܖ>>0ۇs;pMc紃8LQŘ,I(:ڝ7-DS ?M  _< aai=H!#(70S:`sl5;ڶ!j \/_"`]c&el]Z&σ@N'Ahx֢·#P_:mr[t_76T0S)i /ܕ2djcHI"3?1S.9'(c h~!ˆS6 VN /E8sp|?Eګ1p[VNwcwW0vO B0FR8A)R{ÐfѲW^ː&vRx3nZr₝+rBh0VH,w,0xGNrO,\N ;kߵc- r-»\j#;x/J^=7_w,SG2ma- (|O\\|K#Pva-_:~_Nۏ_O2w_HƾsSXeݝ?ꗴ;b- }4+=9ڗ7F( E\s"ZǸrBbo;8n\=jbaB0ɧnd>?<<F:0ZX-bLgpvCI7:G0!m՞/K U+;(ꗓ8J\I%,JyThSk_FpSBRktT1+G hxtuyËb {[8LxwS /**1_U@-ӎbT$XOeS >K?|>/(82ޟ OЪj;`} )[ɘ[-0`h{o`فwl<'KږCEƃ!phMx{p$䡵$apW) 1_b>҆i%St?l#̬M~՟+vXZN~bRc_HtQp,>%#w&J f2rC $"*GR<~~~^73[f )ET2D_d&֞QD*lٳܱ p0Gu| iF U 4+/IuV@+. řJ"2ӭU(z/0,)K_詿T\ {7gk.ufY/ )Ge*WNNNP/"|;G+mI :?;j뭉'?9٬`<|ޘ(͛+!&/q1q= j:S8ǧg'93B-<>db2HLn rr$6 +'2aSY+)OYb9{v Oc@o^i!Kct ~/7;7QeoSk?P ^|W9D5pR0Ko~KVSLq>)NN˖,ZKB}m?)}tv!"Tc HXWN{8/{pg+TIaFyAO Z@ow& +g m~~B*޼jarPCW0=xEy}Y;k 9k<mx汒 mOK3y7KV'0BqY[L xeY\ f,ɐ:\8*Qf8I s Ϡ5w(Bju 3R0FdcKȋjٻ.`FI9=ҧ'} ڙcfZ0gsHVW#YNAEi,C$)+v2L.jz5mQTc$;#- ]R8.-B-Ʈ6)U }XHbBG+!m=1_{RȋoE٣zuk.枔sΉߢZ+@DznizAu¨dh r$fo[2ćvЖ jӃtrUR+DPv__zE_} }mYŢG1wH #ٜVIl&g=]@.Lg?Qn V>NNK.\ȩWhxq~ 8834zh~;9OK%V} Z:A0&T[]M>/Yd8p k?O+|Oޞ~|VxF|x{c{sv()U&&Q+ maIyQala) ~٠yIݨ͵mj/Zz'WcW>nV7 Hz. owgBZg['?jCvtNmj}Ha[ ڒc]ۃSNF6 ^!hj26r~3{͕hX`!eH秽ɷNϷ=KtzZL@;3=y=FS8:Pg]8x$0}:]4&'Q`blL@Ϋ"DAwԔQSo8[g+`aLl\Yna:]ɜXtBg8zXvcy3hm*gFw0'uΟC(TI<4|».uEc#n9܇bQ?>ne eArgg-1ǟMţu[;4TObw߂"8m`wEе.I|{ gGR;Ι% nSpIX$p,?z%޻a NPwcؑȈ#E]cޱRB?0|3#; ="=ڳmWʁGD4>"}}Vfe)}B ~߬,7 "`h VL¤d-/?HŇV- Lvy𤅊oyV-- rRc^=gPMNWGt?0~$46<i ӫ[^-{p;=eY$GՐˋfٻ~a+/=BWKЕ7K9K|<,9iXގަ֖3/5͝χ>1,yfFNbiQ˲|| v|g\'7ug`1L2 ?ݠ =l+@ȭ{Gv>@+( c#F5U:/!h_=IKN{-:}򷼾[^[^ͯ>e 8tC-:*J)L$,)j wjA/wn:HuiB;WuF7^ |0Ls) b@|LƟg#Q4DG##6TѤK~O! =w QѳىYOm~DQI͙ ~Ȳ*h6jm|_)c*Nr2EHѭ3O5Y>xM_z3;$ϐK%8Tu#8bޫ";HI9~YfhcNl|$V&%&7}%g3][/VgA qyEM򻒶}$_{r֎A7Tri9L5JM@:l:`јDP-_ТݼHX|^>3,{LS.a0?Qa#wFL ,x3?}_Qħ6T :))vdQih n.Ӻn(Xȟo,#K)>L?:lvA09>Wf 2K9ubf񲝑9"ؿQjh̳ wook%c=F!v brUet" sA?=v*ACWʯ@Y9Cg~!ANJF`TV:\Y* +rIJou |󫘍7Npp-[o Iܚ!-r>ny1[*OH=sJ.M;f5HTdk4 xP s2nmފXh0Ȓ I}=(LA1H%srnq{GYi70qK;*F2b5o[ΆEcwGw0?]CzHG *tY:݅l"U??olnN0ʜ{RCae=񝭭W!+^'!Ka;=?gŵL=@D(X{.MZn(wօ .ʦ<`μhgVɔ"^alrpu䖾X%qEG,|5 {-l?Qhct WbLjAspc2TdQ{LA궅+}a#Tz_93%e;]ZrU_ZTU_UӣW|̏i*370ȁW^% HѢouOә}oX|fwP%CzF#lFv{ӈ;,I eS5~SnAL2P'%3#dO~Aw>٪)VV>=Z;\Yӿ'[%//|zWAO'Lt|gXS`XgR`Qx 96K~=|qs:&xdy?6Yy YKVtl_&R),ֳOh,2IXдW>q?$w.x[#Fw?}R+AV'RR?V ,|+/S|cgyכͭm_3~inl5lWVNZ_w\,[3Mb7;2tI7Ìc0=>ntM/Oz's_ _y Tx*b#;B7Isq~ pzJ'ٜn7x!q}L7g0ACduMGɥj"0"R- #@A5xZЖǒ Q%Xޘ٠L֎ycxԪUH}SxbְQݰ:j< s4{E4{΂KUCaζ~I5 w63L9Msj n@50|/^z(xkF@Q؃9RN7M0 -uGVT ejyלk8'S:rU}7};L ,08Rt1LA0SB²KN}&'3p,bbGF6h~-%;pݙp_h+|<hBoOax&S7cKGs}*kL7 M)6<q,-M~]+Ĝ[)7iW` 2FyL&/9 ` (Y̝f2&#ge{D췥ӻ}QVқaoҟ/Rv)e\<>{D>t ="H7p k/Б*֌rFZb֠'ttQl}qXМD.mfnb% gB 1]LycM3 Pe!=㩿gUIkJ &^q2ԾuH'zyQD62h \ݖF$T68P `XB>?sb֭{ ^CK–)]餤@NS&|ɜPT8,==>sPŌKRk:$2x85lYgY Nd0^akmw1 PZEX"6Xj[nKG3:TJ!VuF}R( qy4|FU'v"pmߏ4!M%9)"CϮF;'yg`}7vZH/Ԕ/A հ9a=2{;!edEU͛TlW(K&<EHI:ˢ|Tv=) Ɔm,8*i.*̀i?댎}LvpAK sWVX5zpjNN{1޸];ct{.2Is™hp)K2n%/0>rƘŪ%ݜnYK|3a1C~-ʦP筚l- /WqI`݂f )tJ taPlm&RB G ܜȸŤAtP'5at^ESk ZdC_XSߏQCFuׅg8? ZNm&=dge/HΙy331Yj1%ˠ2Kv%p +I";xtP;ܪ#wMX]djiF$ɆIVIȗq{"Wpn_<p |{Fn!<./Hlp5jE#94W mUn X0ᵢ]`v\Q1dP" Hh -^+6YZ-0_qӰzh4kr _Ѽo0.y{q*Bprnowz~ |,9uL9|jx.+H06D0~VYF%ZDP뢄[]\Qk E ڭ[[ͭ(ٝE}n7 [ӽ:9iSf5뎱 3)zd#58Ȁhe}7*ʠ%/-T194VDOrP-3W@\ ڣ' e%'d(o["SaQGy5}4`0܎trN +!#f%i)t Ò`Dy0M.9u?|q3R,w NG 72:2>VM|5!Ey18wI1\7PXq%̽ XO+;\y% q2P3v KV'o6_ʇ??wλ(ٟ?/÷k]<,0hp _4_z @*Uϥ[6CWvNT2lח6@8{D5sw.5և܍5>j7"s<d 3ɴt䶦d4f?lnf%7^h& MoDpz6-#MRB2i^LìxL$z?Р r~&jq>BY*{"r4 Qw_SmA5u>)uG) 1N'I.%P|Q>ng%0[7aWepi#)9LHU(G|#,O(K W!/Jg=Bd,Gh\vu+RXm,c?q{"Yc-1$z寈o:  +~\B܋oa6q "~ci`W]H4q VpQSwCfrHnvtb*&x")X /yA / _s)/Tḏфmͫrpǥk:Tyil3r^aJ ' JE.iUPe8,״hdp"=?2p1XMiW eaNWdb6,ßfpoUE ̧q 7n쀞VzN#g^rjIX 7xG." $c`V56_ﯔ_K܋l"h ~^?s| 0 ߸񳵑w.|,9g.suČ. d>D JN¢[pD WT_U+书Ɂe;eA\94 8{l{(aֲ)Gm%3lYp q7O_*,Tn)1d*X, bL9U)ڙwkܸѡ_Mx@x&SMzsW^#K?`Q";<~nT̚&Y(tUN^Y zO\n{Ŀ2Eʇ:$Giquű`ziiJSS7v(Vs{gE*"'@bHͻ<8AR#V0[.ڻwJX::j(ºf&Q+ Sf"FFbҢ^9$MES8d΃hb5w ]p k/J98rz,61م|Hr/gx1ºg|Oebp53Y qnPFSpȫC}QtNo)%dhqy)w3׷-*8tcS) 1^/߇%MnVԂq9ƮJxmv+QdGyl$)5;r_;].<(\ )Wscuw(|J Р>͌'=S =)M4Tİ"f]Wm63U( b0 D@]Lȱ'(H1gy>B8B:V4ŗ=y M넼B%+ѩnMUК59I7 sM/m(w&GNQC }RNk=A oejCwL=/V "jnEߘl)$/$¤/lJ3XPdkS !>"VUp\=fY4b,7bRwf Q/Yv^-yQW*1Gnbl\җKe*vͪU>^cPhm]nFuex9g v:h#iLןѧlt᧩Ri!vA:B RwkH5So")j?βd ,y@5p-kKU.Nga'1:8z`jr}Lp^ԺAiQnu(h&,iBBUo,[%>gc'dR[[FCNd},^-\R8=  Jv`Rt,#ࢱb(8!bc>$<0Ǜ +8*lqZNRSهFl5 AJd Mq@bkIr~ bUOCu]lc,Ue܆֛($WLEG=[CGܚ7Mٴd; #14 u&I q}J7N}LBg:E⦭MWcu>ϣmRd>Š^uR*4bc(ItyUzD(K9G ҄UO?QnN zh;X @*cd+G3]l8/ƛOdoD T'ldŅ #F@Pِc [I;Q]qvd“:.} €W{^[G[o)趧'hh0plW _Bb aȈ"ׁƜkW[ۻIQ(DQ:yJ*0 =([p_;-'lNhaZl'C Xb {:&n4o{h[ sFˤP~F&-5*hS9M7Ç1HO>t<یbma)O@q~͘D)Bu),C(D=@L.V:ć~WD>!ݤ:=˘u+"&s׮%H'~ Kv`۷SC0tWT!Yn@_*:jQ(j]B$uDj-|RW)tv(goVQO〩xKGV;r${ :ϦG@٣p_Vk)XV*UhMiˆOW?<"}/[.5^GljA>q+X<%l1׈fq)n ; )1M敍K<&34S. Vx.=c%E[';2TJ𫆂>\DgCr `INk̻!F${e>=4æMBÔjIZXpMָKs$Xcz93uMuJ1xZi5)nbWQP,4>I0d1v/'Ҧ&$S5̔MbkkV:ɻ,t,#-f|V,"-DW0~8}N<'DW'5Ą@m\oT6_޴UT0+q"gи>gO r}ંB|c"=`9ۧ:9Ho:}1B%Gj"M568JI|tx|k8[*زI?Ko3|+ɔCW+lpypXR?Nab2j?VqUm+Y~fR6Gi|Ųʐk(wН8Ò"I=MN, j\k=C5  3ϋpilNO鉡eۓFT( WbK\5m۞-H]-X)h<I^K[S}g&ݡW~j=5mBKdC"p&9HNP<<ըT}WhZXOh}#j=MazjT+MM0,zͨ4U1|bb;& *t$qYE5MuԨ$5gGUKͣ&=-׉t}QͽQ&P )8졪ݨM_Nvwn)ГG:>;RUM|m|1|/O[.DRL3ync=jb[[9\ lnuB3T%ExDXX3$1p  [焜$y2"Q܌B0+ &{&ϭK=yˁ)Ŕ" R{Z(Nмm sZENÉJtj,FcD;e& R^QjŠns {3݄zX+VsEC<[rΜͺ9W@%Sc,n$fn6?^ ^we°Bg~8i}%]7|0Dd#v;Rv~"=-6dLP7QauQ1td9%-#°)% DzPt> ,ܰ!?2 hyNTbLh Խ~k3nʩSN.g ϻdUUآYFqxu +DBvr)B+9NNUUQ^ e5b{%*n 7KS# G>C#fi'N?N'\ű⇟У \-4_G2Jb篂C<@\,^eq6)Ii9H'6/ @c6b|`҇lh}XM^" UTM}n<:f̆"UɄ*gbUƽ|C}G0%5u*ۣB,720* GUY_ìȡWE/[gA[e`[i.R&*YpDج L@έfUP.$e)~Ps/"l1!@ RycFߣgX$`/o^]l{sKgeXګq2װ`k%f`$r,X - lb/2o,ЏUJJUCsz9ElsRVXM]^F%z 6c$:y*Hh JwBĚ#6׫6zFV19n5UĮ26\crɕ B+ʙO L9T]Z%.YJE4wؼjz Sy-vF3 ¸l4͸AsjJY `팸OS%2= g 7| !GAWR, -ڡURi!p]WfD`õe hˤ7\bUg7Z2b0϶H:T`G*ļ3ovM{<dv$kRʀ'm!o}b-0 z+}o#l!4TV?磥GcQA$.1oGJPvđ%jd?}ZG3ʴ›&v~~ORA Ԕ5roCQ"AR8eצ9>= gn_բ]!T~hɉKyJ%3]`ꔲMKؼoCUՍAs 9R+$Ob7 - 6WSᬿc48$Ng Z WlaN*[wE47,WtbF[8S7XU NƠ?0Ic< p 7bZĖUrOӺzAhs%\X_tr)7hL֢#$eR(am=F7fZ4y:œ9 LֹTWx.*PbEQ܄fk)i,AT+(Ѡtan?N9$Kn"VUB:;]̦xȚo<R *L^wS)sY4WiŢ?sCI'LuLMxGd˝͠|Pؐl!J 5v͸r2C ħEA +u vƏnm݋H/X-Uh2ٍTeKkgEp01uݢ#,2ZՊqgF(|V"ۭЗ`:e+;(̊t};P9{0v]ӣOyԜr~ H0G/<9ˬbLzinf9Mn0ɲQӋo 1pf,D/p3%}(YRЌ\ec3]>[t>C}S2~WAJb2!;$ZJY?H u$H/4H,yePr8צDm{hNǎ{'礫!*}4oD) dـ8Kxo#K[H*@'52(uBaփ< {RQD. ~ϭ`3,JTJ.8:%tJun+z5^Lˣa:$#`dU?nSwҡ#Ϻ*UӲ}>㠗1uLһ@ g&˙<pQDáFa%_JY6Iʞ0WMQSCxPhGrJT[$(wˑY"f=lQ§ i\SWBӵPoM+lBն1ּ0gg{O=:.Zy$o6ѕFuǟk XqOj@7(z κ4ˮ#:!jhv'N;S!Ux>WضiMDCKF_Mg]|-wt|_+ӱ{ syWи &yUjk{SA2P1Qv+;/TZ"P_D NeieNlo+?|+v@Nլael`Q@N$҅ټ*8O8v] LX!9,+a?T]!>sXgr*Iz> ]V`XgP`md 1Yfd'#?5a+GБ8 i#}&"{":SUilNy 4Q:SYmU-%"û>ڴ r|&,N \giɅosl@Q]<0ѭ>t/`<>5hlm!~akÌCl_G1ͳ2.KE͟B*К۪++ X 1x;LrjV30[^FIB0]܅ݠuCT Ɖf(t<QX.@"^0I CFi9u%J)sѮN56?#ZBK~> 2)%|fe#R6R1ՑF7`TA " JMaGrtk\tCohZcsH C!/Ѐ~ O2qEd11{뜰G=lZPzH^3RmD:?K`K| ;u &UPrɸVpd/cd [ C;dP|([T!k @˵Þt#އdR" R҉Лi>P S+u.1B36$zHuVqZoO& R by\X+ ̾X:Ihq; &9ZVh;n '7?WrXȚ3oX](QX*) PEEH& <vkFFG(Nf0Z[ 2ts>ƭQI:Nfy>@ШYցi!hM xzM~[1y .b>[ @{ ?&b*y-Ѱ:Dȹ3Cb#$KͅĤBLUE'KRȓ:2PppY&}rH#6aY|AdOxJ?Dh<ԧR0@d`-C?2}PC^6Kb>l*>Y 2y&&i/0]>_³X{2j3a.jO&ϗ`=F/U"|%eJi\Ui\=}ѹ54?F/ְqvxO% ׋Ď#@uNh1Kͯ_ju,B$ãxr'9~lNQ`a9RGy>w Äb'?$/ԇ劝Xa`&@ĬN&EE4ѢMк}gW )YDuMfTÆ`L*jwAQҊ>k [)7IFM/=.kT{?d'<|ύZ焜K^=EpW]QzDIsSIPnBwia4 G vʚ%칀D䡀;=F~@mf{i_YxNJ3B0d)?: G8\k91V,Ъ,WvĚJ>(}V,+k)JH/T빃L vB8!AyrgC ZnFл59h!T0)yu='Öws{^eM#SJ,F&0o :d'X:H/VԪupym[r m "֦wi<_bhm AԉKN$4lt¯8_C{W$'8m`!}ob^b6 3JSKUag 7숤ddlpw5|{}ztq|u9D$8Ҭ԰u.W@kdhgu7*F%A0P:^Bl9A"=P'lazJB IFh }XBMI% $,A?9S@J+ 㪝Y8W^Hx WT-$>-7QDTz7s=1XrH畭{ 1`y@\ޞtEF@?DϒGqkNLٻ"$05s:yT]KPOsL\DUJlC0L`QaA#rO1mXH6@J;"Wvɖ>⏹s7=&EFL:D(Xq2@zG 6 >=>nt$mj/KLu C&DP9Q ,Xi ďInԪ cBaZܵVT-"C%z*I+ 'ZokZ}Cu>Ʋ[RԳ4B[>F ~r} m*-( YoVI!PM/AwMDN5ɭ;Va$vjtƫj#+P^)vm1ZOYoէMxT9jEUd&ٗu;T,Ph%E/aiZ㰴C2I\*`[)j!·4qxmX3v ݺkY4O1(ɾk4܍";ʲq<q[-{D%'ƪRpugQng[ۻp\^ZOl&&טb`۴ 3 H&{nUƔ[Wn05U8Az6f IeM{B4r/R%)e3~.E,W|ڊh1+ә%~{p¸I1-~n1lA1[.<O)>xf*2T#<Ve'kLf{sz]L A^ pCW*0F;NE*d:ʹR_2oG* Q ,kϛpO䟏,`nTi!\Na7o-~[K_Į %?\B1 !W5;Jhq>S^]s]QDD]a2WۍJ7<9&?kz@Q⑿OetwmK9.Yoy5>EpOl:=kpMNϟD`2!n tfi֣YCѭLBbJjR- d)/$,ߝasϗyM$Hw}rgCN1X4w% w'9.<[@#+\>F* J/bVɡ3.&+Q1Y(CdPF" Au)*?u~a`O >n"a53RS ͈j`)KL*͎,E!Yހ^#S!NԖ׬ jU&W*&#T1Y&.v7$3GH! z{XyFfd(f-82i/3XdhJLZ(:5C]!pbRC}E!3bP^vEVo@R"8}hS%!mt>CUN 3Tpq? q¨+dui.* ۃ+i/0e/iy}+s) G@-ΚVTD"Q5+,Ƃ;ǗcO՛{j#k`_u趧(*G@#(! Y 56'Cً=/y-:ג}Bu{zpkD_)YF _7M lPCl揸H3]7CXaKeReD]PP]X0@CYX1!84k6 [ -6*J>k O>3-GFkIE@󇗱qufDڜ1ˁ@ؒ!n>R)h wle$gǴG_jTp]DXP\<(lW3|" 4IU+K%=Ï)dXx8o@ަbJ:.^¼Rٷi/H2Om)xfZ?K \m594b.^{jK8s)p*JrH"z֚D);{ֵdLG RS]4%W6K*y^Wo؋彑uTQq>64ˍ8+SC7B"⻺pQ`Q F4**SQH}?Z@F{dhRl't "abZ_A- *'a?Gścplp.KrwB-aZeWfz0 *4a?MG%Ik57]Afm hW/@a Ds O% }D`eu,aǾG蠪{x!G4V/MGNn[}eg~T/<&po*%m4Fߠ+껏{1HfZe Ji &7v5r† \I%.˩&*1/Q~1_NNϺ]~jCY+ًfKŰШ+ c|E>,Mo(e-<.pR).EfM* Dں8 pAIyt9 'ퟪ 9y[ c9c '-bGZ>cy_1{=7_eI;نM8HkSk@i7mzȖe&%~V/xV GY%1蟻4 R(G6(9߮‘l 0@dn\.pEfk ư.;Q\E͢үpfsk}~q&cSBCʟ }+? 1ƞv| J?YT T&MGg)0Z@.JQs.{FP9oo?Ɂ^>p#%|ܬ%Ĵ`鷃GlmKoGcӭAI%p{G70[,O#(ohHBlA(Ns=j:^s8k[ocЂ쩠߶!g1 6]wPzp-51TSIxPM\K{_"¢"zv(_#D;Nx5X>dmmC ;rSQLgS5}H7ecIrxƙR΋T'M|ěNKF\Yz^4qwYs<|R ;3=iyΤ֗0vqXъSI`S0A4rg2/ir~,f E\0B %,Qq urN]jhR]895Wr&ICcRCS$ic O!V%󽄃IkDŔRۺG`0ln(ŒcɕI宅7'4|Q /MNJrԬfCStzXm]NYsi5f&d"QqivYϫӞ#*h_W:[fQ b wW4=:}pQ7:jp:vK5}iX2nnfAQ {"D+ónc&;#;m^m_缢4LyiXcZNqIhi;=s c01]JņyEq:E;p4ebJ7l0\Vtotpu5Bw*BnV=;{vKi)>0wz<A뼛fެSo;-3R:qf\=![udK9N?on;tIaǣ#~\g燺\;(P6r΄|uκ>ѳ_6v3#S~>tZ罷GW\-%z_66^m> ّR/tQ"$םzns&58^lľYfNn m?:SP-(q;ĉ1!,x,&䁀yϢ=w i1 ./z`0NAD {U͂f84YV|UXW̌ߒvI !\"k:a@Y2{ΥQ=&Pk\IO,v*wؤXS)o?N`ld:aJ=i/4o9?^^6 A"bi|Obx6p"g˘utgtRl`^/l^T;[o ; #wc JGA,.7*P]xZ-@n@ ,qFjĕn哛YH!l/Cs3H~# oMX ~]طYQ6Nχ6ﴩ./g윔=cJKsW[(Bho놈A`#: *s 5꿭 Os(7[r(;&i($@/VJ۔%$g ˝hTr}Oߎ Z'D/)8us51{V %\X{>pbݟT_0fWQi%4PŪn;`8o{0lxkRhݎvu|Y:zX})@` nuγtqoCEa8(e'[;wNzsXWWdAZre"け&gNl{?lj M7Y37Bnld 1_&Z7oAeh.XgUΊD]cxY~k!(^(4P3י0֭P0߫]$ E,X~)wꕾRk^6n|/2=$1ii~˃ ˳n/T[X579tOON::g=6g\^ jCqIarV=$ӏ'wא椞ֱ>{4yeOgCR\%#81 hc:0'F 9s n)+,0_WSumA>GxԐ0Uo@nތt2ZAk,.w7[oFYEȿL"@QkVYb6\bS'b ѣ܁6XB/x_:JS!ms-Uݖ.wҚt=#Ti lxo -9]v٬j^_mm?읐 R6,ɂJ/?ۭwnYs 'g^͘{=a n@sq~DJW_Q<,et?`[GrOVy*2 _=<]aW $d|{f)򣏎PğLt'9FBU1=cSkB kpϡ:$%EaLFƑK ; GA֫7/I~i< @P~2+*8u#wͫݝΘLSۺ@aiRi;"5fE IQku6%ARW R|nlLf^pOe˭* Q"B딊!31+dSؙG $|R@UbqҰ>՟GI6V]3^P( ^]r硆$F >{ #YFOJx4)9Bmfn^6~8QgBk2&d亏7NKXVLm}_*{:Q.%CknM|}Uʻ;Gy|K[Д5@L$8&.븸 $~J )Qz~368֙d|X`aVAK6t F_>܃*CɆ3-68|Fk8D78gcU^>-0-:G5쩤ngӠ0o`2"dLb3ۯ6xJ;8:<>$K&,]M^-\Ǽzk].(f$q 6ԺiY|8Oʬsh`l78>:Һ0'!7>Uww5D\:zcQqrWɎЍ#|Z05;[f-/%!+ sK8+WW2 v,0'5J $ @k^FNԐ !wL2 ;)0b^Tk0ECR L7+]R&h9 Ƌa]|Kv.%|i`FޖU>?6A9-YG- IWv XZ=2ϊ}*D d:-]C4yuxvZ8olrk͛W/77/cZ* ?JS< \]6ɹJK7ZEal*RR%ηTZ̊ H3VHRxdmQ*۱Y+|]6A]GҿTY^BL8 l)m ;eCs8L1+@e,/D'[=p;fN.=dٶ<6OQ(*CҦ/kp^D?[5cpMK-n1>:UH8p$6{~ ^O_g zw4(G X0_c/~Ө~#o;޴݈x"XB\|e~ȐS`#D#DX=Hh%3\^W u$:Aaxh2!e{ú rQYjx}%}P?(~R\V}=j0@jB)Dڨ{^7!"o#_ZĭmS$38kӼNd<_>L'֔AVpC%0gv]f ;/~Vq/DkV.G^ }0j'` 9#luver'3Qt&Oa2 |n\:dRcFDK =J=JIahXm9J0ؗޢK]l) CˏQc% TVD&|ݝMVs]أ̘.C;ΜVV.|FCoiAyYgjgw\~v=ڇAycs{ksM"gF@u?Ǵ_É^eG]FeD9#u 0/%kHJ4GzH\mgD}ުث8!Պt.DU+R۴ϑ#xuт0VkA${}^"M/ > %4\#[l/Ж҇.ץ_“ ;@<w|0׆y/2cKA.J}C~/bR>7L7@ixP: >ӭF/\O24lg8ddwN ߉pԄ?$2"ꎾ4zEHM @rK4;;9/P0)3v^%WY|@Y'*,4ݙ uA,3>'%)漘]EWWi%A4@>JW^xQx9rGQb"t_ci3$ m Oa@t#rA9 YWyI/#t~yE 4fP9C~a؇iN}\GdRglm76OWrUҫtL+g \f˰?b##tFXcӑ|P5@OfwҜ 6 R@O,p@W1~Y뗯֛ast>c+{}8nEq'_"ιܾ̉|Hl- bIN*-.('v0Gc`ܤ_mtf !,BbѬށYTe^Q?\eg=DK]"EyM8qR HIsv##~ZFh-i-p@|h`,&r95 Nl^+tVP3Hv-V_Y hnݢ  @1:u2ʺMÍ{NTF -K* E[p GیbgˆBpgbkﺾҼZڭzhw3xh>uIܬ~\QZT&J0T"K`n0 "eW,VW//y*o܂cyE%YnNXnjb:ۯ-<}>۪V?ڞmU=R6; /zTmrS)1rxQ9HD@{\ܠXcn`~gw򻴲ci1&(Qfr&*!*}{H:;G{Rb6hB[$O95KIK0-\k/ ~: p6/b+Boڍ~ Wɋl~_G_2ڰtDlaC!xh Nlے`%~&D UOo\^2:F)a;qF~,i6*6~vpYEǾg0D1HlV7ϒ4L>ٲ(F8hk ,<)nȲhgl ݺM}~tql_wi}(\Q IX3RErBDC@FDv-%R|($nlfY?_K@HpU0]~J/КGA{cSe}ձ]ѧ.ؙMA簻\ѩ~[Z¦GlGm2a(m8IJ♲ }D2Ft.wcV )WeqrZ"TLeHBe^` VM:;ȡh%,(Zݐsa-[Mg^jQXV# QOeVMaI!tiu2J-?x#\[錒\ O,6&g<: CatոN$#pp05If@g`f lyu8] Xm}b߯U{|L vm8OkfMGnl\(-6hFl;Јɡ#'aV{tėp,LbUpA˵Mc-L^Uct8 dvS5UNYā䨛T-;0^FsPQjNO&𷬄lX֫sM2X d#mVlbtއ&łsbYġG;ݢ>;R}42tQh1Ͷۼ|t!GC $$ͭ|gLTGSCaɖ|!$|nNKZ|+\UDG,+\BA\hUKH.0q6# [;"w3F:~gqpmLm\B Rm_;xl W _xk\H Y~l zK\;>8F~p"\?,^ۋMt;hlL8j[ QG$]Y#v_Z]X?F]lj7la>i;E/w"K L0@Kƈqnv/Ў7\!p Փ:D*$^Oc?RY(aJeT?9 p)kExq]aV̕m%yOIX85c0~\:KDq MaI\n̕5k@ÄGԊ:XFe;XuScM 0c֮p٬DDuQP|!COq&٧1Np0Ĵeto=0{9&t13,.L#5 >XvͲkh@ٙ@ތ+'Nc]p 6z0A&YO[HZp/Q(d0DHio{˛ 2Za%%(I«1rnrI߿o6lP7À$^΢应+5T+Sgw$4\udfmT|SVlхn !Y֗S qQY?<׉jx5YL.d5~ƼSj+_y-VfϕxUk/j27Jat{EWߠV0ĸtHl8V l1|-0*lÒ liDa8 >- Bh\I.~W:'?fV9m6'$PоUF C1/ y˳VtQxiFw 1@ HjjN:'k6[u3rCf-<**ӓwSmY~k&#G8i=S`{CMDmd ˧T~9yx.utt/}c͕Ewz|% FeW=[0(F[sspX(0^(Us/*D ZO8!s= u}!WA2(PݠP8J!Y6y@0^Yw>vY ԔN-#UA!V8j(S;Z&aozK6f< K+&G }A 9.0,R.j M4ZCF258 uw.aNR;輽x)WG~]qxmѰ@nxC~x0`.%#h Hlr8:f0'`LJv@?(ksC)UubB!N}x/J` (Ū A?)DW9eB5</Q83S맴5*GN95sbe_N*t7qs ƭc45#壨OݦCoXՕ m5'M#YĬ9] X-L0w'~卍 <%O9Hy P_sVvז~s^/ s1z.]wOήNKr "3ijfzk #u68.$b⏽&'U/沚74։]>ğ%6ෲR7lYF\fƚ1‘ 9?pUm9 w#匥;/gձB` ! U5#ƥt﷏RļM ܥ}ش*==7ۇg:itGU8'TM~s³ʐxSg/&@,+PZZnCڪ#a 4r!Bl:f!کT ;BD/*j[ Rq .F7˵KdX\pP",a6xV2G|]!a s\%\6ӰaH՛&xo>υ5# +@W9t;`:7""rCI7%/#_Vݗj( 8v=95k" 4+pK%G 7ؠI/]4h3~"&9I~ƄY .* Y˾֟&ֵa>_]zO4qmEx%d `iFD$cHo(I:%+0 u -oJuQѐ_&Aۧ8@\)"v4ͮŷ[=)Sӳ*o. ט~7tkAcjJp]q#tw/VǠϫ#& J7ΒSC" / \S"ya"Kv4V%qbʶ XU(0oh47.z:v;SΞ:` Ug]fũsgA%[Fr-di ,TTQFv @FGM;{>[xH1_놓>ײ'[Xro_ӅKcfu,YB)i\:1{MI^AY;PBaKM7['*Zq`k[~O~yt 2@5I"Ĩ]{jXiYod(pVk⿊Z2Cred29uYVI븣&cDF~}:q\eC ~{{&DJm`mV66#Q3tjžFVpɚjoZOuEz٤!;@,|͍u[^ M3P"e)%b:K 7.Åє`+Vv)h*q@M 9bfw Sv8qT['SY pMNV/}LU&` "V)%SWx|z:k8$;ب0>^6b7!'7tKl/;vUȁgl+L'kM*џeZ+d.fSHl20_J'+n. N"vb|'燭V24Tt Lu\ *;#F.U?L9tj Y9ˊݓ a"gڞ*̏Sy/j}d*(d+HM=u>K|i@\JIKA&E9PS3HCc`RkmG,wœs=Rjk^I$E|D3I05?ߡ"C]E|)uq+]/7]IC 4m"|5j-s;x`Z/ۗ%нxps9}嫥b ɬϵ BxmqX[F-Z)asiʐ Ǵ8T0(f#eM(;pvohzQU8 H38:wU u2QY )0*J%[( olS^â)2;5ZUdEj1Pu oE2 t_o`)(ijpClj ŔͪC2VUTbq`e#/?F&S&l'p(Z)3˯QN zGVl٧0vK}/h XU(aSa~D׸N4ݡqb=%&  !27b]Ni|DGձ'\dOC <#lNNO.ֿlN_;L Hbgovw^5Y6X L7SEzP 3t^ -@p\N.urSyµ$,/Gk/&&_>9KIǷ-wb)'==$=<'sOm:u/nEHjM%s6ւ밌UZGQxAYk Qe0p|V@"C%L:V,ghώe%0NBAxX^^# :VqnH*ţ(cμ+ #8OJ&ZxFI))L/tb~"Ǚ焇:+w X]Zt:0uQ8K4aC'3tVYMIQPi0tgyɰvΐb$_i jyF%L"-|cϊdvY|m~5Z u(.uj OMl tXkJKcz~(ڧv$h^wG%=fd$uUp<-B+ }ȉ{47ςMR/bctrj27^dZ*䤬*fJ'0j8LT: b]\"ckDy\X|:ktv!~li?GKl~3ջ4\=NUWˌ~|<{rOH mĄhK^EǍp^fLT| v-kaZQ/It*T܇NhާC>PsC `]qF+]b*[A򑤂jӧfv2Q꿻(d?לg Z5eQ- RlkjxAx _x=n$ڭ.'E1 z.Ufه 4oNo"k̯Kzs#$lmRw=(Sx t9Dw0}JЏ=f]4Z$"=MADS߬w'_;t#Ncsh?)$b@eQ q#摸Ӕ hTp%i$brhofD{oCDb2?364)9 P@ F}e5 8_T^9^=YA`_}>.nC{ϛ[˖R ]xcÞ_uI8C~ֶW;ly!U_sA׳fI?G!c,ӅRrOSzo7_Wꂘhq;1+!bnv8B /~yBeP={i hbE2K@|MA&WV:B(ACnthȫ2N7X>:)ȄZZ̃^m,cC*Xd4 Bf`GԞY? בF 6O‚)Q𤹰p}CRPgБ ]kܑU]_\puCdX~v`XOzd iZ[=W4h~650TnQ=Ds8,)Ky!U鞠Gm|xC4H$ *\W2aHvŊKpq~j MIhC\ao)nLgGC/%3 jEL%R\^kiU&pq3uj^p6D/e@eL빘CO%<=ĭ̱FTЖ|.>'7sDCY>DbwzzTFLxvxQQQN֑Lcw 13EJ p﹮qig%샮d[g-TIdVhӌgPyN3aZ )[@2<=An]|F1ډ{%BfݕdQHC!*\a+0,tdGCWCD |OXXRH@Gk"zWlpO#bܥ~3 Yep(eWBQ;^.+[ De9E16&z. *6 HAHe= =hc0!]ز;:c|'(s:['@^" Gc8i8Z19CmAg!MDDFӱY9{^53C8]Jn}g@s߱ddT$u)Oz%~GNtb9cc;!iHW{+"FMj_7+`tY'[_ ksubugNXE6.w7HQOD%ҭ&TU(le&]ə@H#fu)g,p<`ub1ЌBKevM骑D i|BXc ͒̌ Kp=6d]E* w\DGpqZpQL0Z!D6cWf i^8 R_;-ن̈R2oKDOړUWiN);ݗ:wnpN3"6zM $`Dezo+5=Ľ6B7N蛁&og]w)qƟwam>h,T0vOugY_"-;)wh:CR+m|pLQ*%)&0AN>Vٯx9ϬZ ϤmBY0y-EZR0e߾H^G#]u, lGz22{FӰ(IzO -N6;>.oZwJyE˻^LYkLcҋJEz,!jPC%ٕyJ~)(D.qIazMEe)^H!Z)ljy<\m#V[K'~]. n0o0lct%ʜq4+'<4e;p 4e0zb٬QBiX3L t=ܡ}ZZN`r4,ZZ]PUTzǾQiMtrrJ6Q`qD$(jTAk#0wlrEs|b֛u n2 CO,r^lQ6v*: = !tcFpP0R1"[|);ˣi~qFa%ۆ_)Cg&!%zܖQK\0ڎg/rp2H>B <*6TqLQ*eA9u ]rZrFQwI"﷢n$!%+!fM;U`~g(z'<']O8ح^PT+u>P|~[+1K+k0ڥEoIB8;!~G&k9. _m py0^_ΓYг7GͦXJMZUжhFAcLuA!lrl%шjDd.C8V&wLPQ ^J13o=&j+`$_.*}qˢ4CvMXi!"?`ܤg ܩ\1u|||,cdǬ1nM4C1 R8xaha~,Fdu>gka"hᤨXwjv~|x'.#)ʺå+sl5qVʧZ1]BhkMza}6q>8$ێ•!`d}iZ>&WI+tH R(CmSQF WcW;Z$ mEju 3h,r֠S% %q4a7<||>.ZЄ`z?jzɲTx J^MIPk,a'XQw,zV,wP،r&36yz'3fxtR2;P,\@eH4KK1Vl@MXy63ۙQ9/5\THytS t Zm&v#ĨXTD Ktx!Q}?pTD[|4glt%*z ֡nY){2Wـty>uV5kbOc eԒ/wMe}ғS K("`4 "1%F䧗SvF=IxLr1drMM&9g2!~BHBKh߃˱|zd_&l( )m;7ͮ٦;O4RfDa^ێ)2^!K#Mb3irO>Ps,pমN1U2„Ej2h;HGC$RW(6:j}P$gah#*S45:rkIQ,nlFKfv_vѓMKհa٩?RPJ[j-EQt:W, EJd|lT"۸wZCi+r*:a=JfՊyh\6Ņr Bոb&AwDMXjt6aWA kJ(KkE@\>>@*{mx|@:gIPCux95gXV`lyk)Z(F?9C#tT/,#M''^舊-ۀ2.]k4OOpF*T컄Ed%]~=Q⒯O:8+T*>FP^)l)ap]=?JՃn܉l潽|+)_v Z{.N}X˟ýT9۱+ʟwZ8JE ӠFMֱ̕V:Ll zo+] _ "z>& +.\QoF PjMJrŏL0u!AIt=Q웥70X Z)> ]߯H*腁Y8Lx ҮPwٻnY'xl8șEP#2_5,FZ<%}i::ʤ:trqt)uBdВ1d cN=e+P߄1~ƙ7S*_C[c19*%ᘰ| 6SD~ מ&JWs7 Ki_~1yb]]C'a!F#=򇳁^eM`AХMs#\>XbΆ8Ka… NU|]@|&Dd6M9 avŗƘ9*! %Nv&}}su3׬b06c< sLy-xpԯ %{{ ֯T@(Q{MsUV_RD_wiՂ: RҢxi08/0VKd-0OxC9Oi19a)OF #&K ")ࣤ#4INOBKS6<:o¹[\Pva8zzA≯D!Cf跄:v(dA-n&măd nݰ ,ykH 0ƻ]aU52GY+i;Oyn7DW:].<&TB̕} PIdTrPLAG <7 ޯ7Fi5b< חc /qmI !:"F΢b""\h7Jawx\ ')=Yc\j:(p|4)J< m%3'c/RvM讍zcʾˑZ?.UEW}n%*]d7S`v?B\E JZpz$ڇ|eu<7L3d<|I L1:ꣶp$1$?ݐ"C7bf># @߀RK2;.q] y:Д"ܧ~:Kha\ei;8ŸSe(şx5؇St@ Cc./a՛ߗ<󔇊NGb?dj#>q)*ͻu 2ΧqtK.Խ8u-ΖKz c_mw+wy62U(nBa#|r8w_("CS8y|Ox} 6Jt$in>*Vއ/{=!ku;'ӏ' \dzos ؄F8u.ߟv{z8xw$łDzCJ @e'>{ja2V8iaJjp u'Gt^z"k gwD#m #}K_$WE6e{dU{XwAeV¯=%Z7e/H>M&7S~`6E8)%5Q51]]z]OTZ48)Z-GW+*+4]zҷ5d5rd긦nML0j5f[jIv Jώt,"ڝu݋[ 5$ke`=^E}COÌyӰ@U;x|W+Be:5g;?+^]S~b~{qm 2F{Bno8d neUY!*a<:NՏ/8顽QwO~)h=+PʠL~2{I|x>~,?~ń}!A$ 𵺵r4*JzN$ T n^"*aq)#4lB.$4,l}-m1%G^^{o*DiW7k6Bw;#8 sT |cDr܆L bp wGtplҽnQ%G/ mX 2~x@ٚNqwww͌#XJj:K'0kmRw+nd1p FEYrjB#O{s8/7sν5Ͳ3&ޞ^LajtO6 ]Xkl>:ykwòCC| 9J5mO=g]=Ԣ@JlUfjGr7C|ć~sz̋UrruRf9^e\ bwiý0d)6dȃBpPc@)fuw6<}:}C %e؊of|PĹ8?Zo8tYCGAS*.@IמFb>I(X 6"kgCB;wʈ{*:S<ǭgh=.m5&@L qk~ɊypSs:~T"e(B=/'ӭz3x0 (_5[~ҫg [[xV&@A!桹B&\^RC^V'`7pk@{UY5D!ũsN)vơh3vj&Oq#׉=uڜފl>.l-hXo-<^b|IntоUo40Ő1m\[Fx1-]-.HFR{|xN#(9zv5avVYBn-Zj!uf i$c6c9KаתL ˪=ѧ:31dJ $6"YhR/3 !oNa$J} \DɁ%) 53iE#BAl[;lI*j^اx/1=]ctNXp jXsWD$q#C p>Vu@*&7[.g1> ^$vz`V+`jEO: P ^Zgu|wg=o'ƥeQ`B>pg sxNfb2u8Z Wk*gau2}CIX`f[)_=&^d vTGZRQB.[Y8ԗ۟sj3 PxgNmmnm5vMpE&)+U{Rb *&!yBXiRԐZ1K}r@{'Iю=s淆trCBjȨ#ٷNuI,שN6g6y=ZsS[P U|2dM8s\]N9s|GۨlkQ+C)\+ ?`G,hyjΫ4<\lG0Gp`5K˿wPҩ}rK3XbI]l>XQy霓R@6B>$m:r" W,H$KhqL–PJ-]vUw&`I.ІS!]+6z|(Ihr{ߚpna\KdGb @y;y u[{ dݺB(Х9=Ɵ-^uvQ9ȧD֥+m*pm=4GSXh\gUA>5!R@{q-,Ҝ'SuʋBŋ=(O#0 ˒BM[G@|EFj'$]* 54픜h߷|wv8:<:|{:2b-^|" %*q(y<M #4U ad:xҡ*GQR5<;(בJ7Z em]] |;L:Y()Z&ıޒr@F}Q3X",sQr'EA-PC윯/u:XebZRO{t8ݜy+rO5ܜWu"&8嚍KfwHx nLg)orP5Y`oQS x0Jwe1VY>ڲxSy+`C?^&84H zu+Xȋ !DlNE!%ZK/[s~×N nX.hTۙ!<'|&|Km9[]i2#t1je\uf1~hSܕqa+jhO)l nT.=vխ ;Y lrzq ʌ|TxbڐpZrLJBfGBJ $s0FqL}OekO-QFvU%\@ |p$tSmFj( ]lT?O`);϶RC:cvaQ.SVY&7Mz'6Mt sD'+CTMQ7q*g$#L]|81'EoWJE!昑DBېv+Yc[26WЅ-T0aj) cD] %@]`" $%x]3l%Ï/[|jOM/Tv5gl[@WЄ.|,9([>1WRVih5_27U9)q(\bF9>%~6(Yl#ZRYkk*nsCPH\z=jǹeL-* zVRRz&;փ呀`kɐWғGzۃ zjW/+7LzxPÓ4#$%w ros&U &I3Vq˔+-|bɕ46sxiժni|w)#rc κXBjlWadƳmiݾ|YJяmLOG_7|L(0 (i&l.}v9Dl,q 3!X~=6P2+[2$Y,Fu/!hZh`\gUA}:w٢ћtU($O(|벋f/2%A^$q 8/DOBdioXD׈uqĤdE2Q@tzrl%\|6ΑEEP{h"%x!{v6ի|C cɭ&qNp"ERNU Ċ]LFVظ~\ g AA_D p HZ;- >uf=EnJkyۧ'eR埱U)ϗ|t_JYJ9jQZ^F<翁L6'2DYҶJI9l^5.E˲ùn zh8?f@3 y4[2UnE1gy E#>e bU|x'/tl |!h舛)+{׃~29'96͡Y&-SNWl*2| P NE*0ckz;蜟G8t9eR%lRǸsx` b4&s޶ga=gMvKPƜ`(3̮A8[AQBu,8)O8 .7Q\+p vNr#d 8+Nu`aAD{p17)z -;pw7 p}ӳq-ֹv ,X GJw9Łz~}W\$3ae"BRvRT;ukFɴX)8.[w((Ͱon7mJæ'm~ҫ&]J/z$ƜklТpdvEs: Ej|ko AmZ5 .]3۵$/)/[2E1_]o+3,*XA5U+CqaQm+\;v \]([k>F5FHxM'!tm]ʀ 9_;sӔ*Ŕg9V_"b;.GJޟԜ @1x`wX҃:CK pg$*+s>@y;l&|{1\L^ԟںvy>BOi<>r4F? >g~N+>j EcX|&qɿ^ P@Êɉ5c8%G\0Hڟ[Nt>h{jWPv՘jq1,zxNU :&'eVk]ad{HH1W`IՏJ.Wi۰Vl}T; u'F*MHT4iU?$0 A AN-h-7! jXfAOdx˜W UB%԰Ty4[Q6{c7#rNEs6}8Y2x‰K2l{Aw!S\o!jeQ"raN:=Ul 9@YX'"7>S9h$B5zfH&VySKk.&ɼ~ \$zQQc^5ں)f ?>2W _Gc1'cLʦ1-%|. 0| 8u_Y"~As~FdG?:#zM)5;esgsssks4wu]G~*0=:Bx3hfv7oi4ʹ7Ao"skf~nmwZ;nkבzz~z~z~oi?[{vVqNqKy|{ׯUխ,aZr7B o!oG#l^Q4:=~'a$4h|Q?Í˭NB epvs3[+e7Z6rU{/m;D}Dx„.%)@ j͛k#Y;6UmoGpM`"`Ud]rU|kԣTQd֤Ldv_{J-UY[[{![͝]gm&ҝ߫o~ U=z$&ç[IƦ(I%s T+ .`1q[!5ٕG K a3J$AqS(x)AZf%92}YSaz2 BhW\D)ϬŠ$0w)]43Ľ͕^ >RsaV\}/+&0\ȓ gs Me*;h4>.(p`v$mCJW&9ZMmxO隆 9whfi\Z}eU|yǖ2Iz\wT .ف]U*W˹pߜtm!ʃ^l&-$Wv wԂ|} 9aѦĦF`Ȁgjv$l@>:Qvry3pX,n_Z ҿ?}Z=0O{A\o3cS:Yjf GQ1UXdtiR3&M&? B2Vp,Fr3\£y `%{q9e^Gm_6yِQ@u7P*㨡vXl>YEaZe<+dhAk/&AIi1PS5Z:.;^P`'(ä׍*u>5n{1ovY^H $>9$ ʊ(jYJRf įcO#Xi@:aYS'-a9ʕ* NAM݌ J"madku x-@|rm̯aOlM!b5[|Ǩ1B@ ܚ& zZTP@Sa9 _3HI?bQSQ uVK0v& M$C Px h'aJT/Vur9chJP@|^CG+8HNŸ|/҂bY9pOa)+=_uuuR 7.ղ`MhHs_z8T]ݚR!O]|ju~)ְԄ(-jQ~=E$ևߊe|ɷ [b>Va QLL?c^<k/ȥ֣M7tG?ߝn=lP\@NHxf3_ormyK_+0f2TF/kݓu G1't7EhqV1׏4{?b{䙫j)GT6Ljʏ%@H"?晰1zCZNw{UUI;sMƶXkfܫl1^>FK{A{X`TbdFRy-PޝG&p0>^yfy#qw*fB@Έ ad/Yd0h҉0Bɵ}=fL"!4iSSI(4밳,%*@͏ ]e Ô![|8D=X9 7>*/wq>Ju7NeS'HS&1+▖̏?Clx?Ra}غU> Ñ]OKORks@']+v'V1JR{y?Js2/Lr $ x)U3QHZZ{h<= m4oGA\V@u"J;O6jR@ݟ%w˞ג~n`` '7P$y-4\֩I\* s.SE{'.lQEۦ] ZbmSW!r4=$+Z(GYS S6}$eE|_A226Rp %v>}pHUT|7JɗC5nq=rDk$\rrѿA>gHj!qŌ`eR.]2C` Y{ կSZVbbop߿17jDVo> p(tq@_p̡6 ̊#Y43_Mq++ `U?M-8ɯKz ?539EwOiska$De1$.D3㢥 u"QqkE-Ff `դKl(h)TdG-coעnãܗHS`M]yyz;:GgQqζ>qtᢴ6uv%Q8w ` 4?6NkNǦE Nd#E|D_ I\jGnЧ mv*QeZ8=( \.GQ;9šId[k@ iHoVȥxc$/UqG%gyU9MmCJ 0$}ɜf3ނ?w 1*M/.U|4=wA0)+qNEs%m$n*>28&$}tJx^U XL/S2A4xttk|;Q'uӃf,7X%]SmȽ=.E[1 W C;?|{yP8; 7xzS V4Lgĝ$}nNu0e Sɔ+44u@޵%rzÜ~lu(f`I ¬ D"ރIYn+ s40PT7m:T 1m1Fɇ"s\`js'b<]iZY6F !~IK1mCMßmP0{ `@I1 'A۔TTw=ݺupzjX65H\ŃaSX=v~f>ڸC'>m#Ik+Ǝ͇3dC=,0"[c䒔__s?cӒ zwKnvW׫%7:d* |R^[xwBel˪9'^~˔ީ4H`c* #w66,2R/c Tך[!f.x=D A04WupԟۗS`6ձCF }9җ :KXk΃`1=埦 ·"8ح#<#DHHui.@ȁůOv6]nm} nu{!ֵZFa8r`1I֮7,88[эX4g QnK|m! +B=W,=Cw[F TG疝e$=S$UY(|N0T3;v_6WQ1L? ~npTZMCFx7@h/ N؊Sk0D۩O_c i=u$ѳOMo"Uيwd= @xSYnSp0gu(8/&½v@@]4ꞮO /iH5`n]aMǃhmx/<{N G=(6M)8G2YC18{SI -vQ/'c4'{F0eЗ\ 7ʛж 7E)Qe8@-RTgAZ-MȺA Ya9t}EAUu%ڨΣ%VBt\ka0W<ȏ)YTŭ>sxC㨥i\Gx.=|)pVj;` Q*_LO{<^ O?=4aO'A$ amT>/m[bhSe C/rzRPȳ{Ptr2xU<7kKI#m8l y,r޿$9cg.ӧ(P:(O}4`?E@Tȕu7|&7*ʘ.[5EWB9%@z7<a)LUB`;esd_ߛTWyjb6X]bsl]SZ>yla)3v׍(&?(fLrXn!~>X2뙬HjhF؜:{@տH'!SGk+&v̶e_,jLU۱fߧ] b7?k+|]껩p?>&cx ,m&r̝gApG;;-0 א]}}m3]c͘"śr8إ@gy ,A' PEaqà&+B0e k(wo >51>?l,>͖+0p=lAۛyV`(,uN18)+PF*&z"1 ^􌡘ZL)c|U%8n@W?Ok{EZ_1>e" _9U+AhwZ xAzs7!pPa>Yk^o8=WɠBTjC[yGuOӮ.30`tQtrvDnu_dsZ{/@8pR"z(@Ym~@σp&a}~|q(h |HAj 6C[yq:l #x-py;7噻C0mZx-1G(| r2x2+\h?{xyRBtFLof(K BU(aADL=vيl_ǚH.5|քQ^U>8}J/Y] ;~mܓA.3ov 𳃱T'|!UYrh ]v.$Ȏۀ.'$8ȥ1PXGN&짛OD2KW*W;Nz+q;p Mi:0fp|S\ bǰ쓳sR!x)1feuLUW3MhT U V?W>#40 $- 3,VAjh[Ou¥/nsFQM<"$Nj $[C\mOQFfh {R rj58\H yPvƩ|`|hKh0z4 iF'ևqUJJc~iy'ֹCh0`kӓz!3 kێ<`./f;gу"dE,tmd"fFǍJNyr70ݏ$IӕG,;I@a,blq#Zh HIх^'e]6Bl`8`MOńRbABnbc~kg0t)(@z`lTF!0{EhvǯoԷv^{ "IO`ﻵy~FEKZI3Tu!U԰3f,>ʦ! b`Hg9ts24g^Ϛwt]ky" YDJm64Yg/FG/Of[=F؀No,PDRhcXڕм<_L7dEE V<&Zzwߊq#k}ê)iI{dԈ@ wܙc Mo|-yr ̂c~9rmK$)ma_;MD{HC8o_磶pD$47Hͧ摤&Y0& 흯bMp'Kix GHE`wRK56#:yn&X@K?8<1 }~M &0Hձo#Z d[n{TOz\ʹ@0ab-AXB$w&t om`eы:AD_XGR2Cy-RvTq跱Ooc-7!rUI)ZC_ jFՅ-iZgq]0X$9㓋iE54៳ȋpsBF{sV#͖yEෂM20Q9ppPQ~s__-%QG:$Xh fpMR -6G[I['Qq~m}<ִY4dRYS>< ha\8> fbEܨIy>0.BgGP飱qDhP;!:d0PڡݭjÀqe|yYݏ Z 9s @!97<=ڹ8DƆ%2\6!aOՌ!-˧m֐1֙슾cE9wʱ\?6upVjSܗCsU'xO?_jw:~gzxkv>3~L 4T;̴ޡ>=C{ CPrV.'U(U))~cʿƵ:P_ؕIj&!HM~!+oIUm]އ_&`R$(N|9kGBNY*6T&!Z!Ywo``,#@}>F#LDϯ@01uT`R`S:S>fdqe%,e=Ze˟wP}gdPVhi`|lk3ufgDM{`Bxp_Rq.V9Nƃtاrdu/H2 7 薅q`0(Flxc-(O5 TXlKg2*^Sw,"(Y;y56Ǘ+To󬳤DSAԲlf8|p =T8UIݖj"l صO%SAguH?h<7Qrn< Fc4%C:2٧wJ}a2Tѩ`~^# lݔ$_ LZ(1aDL`y*gf>ZQڨOZi[ |DZD4myK1ɡ;5]5 8$;!^ZXt9{{vS|RPB.%csD:0ZڨR {<-QE^aRf23 ! $BI(b&3dd23ΝI(uUt׺b]WcAQl]Ql^?s=;}ˮ0ss=aQTeBjz#d͒" R-ǷnW1a})s>HH/D8 }@Ҷ 񆦚ZlDy 4vBRSLh4c ES7&N1&Aӭp?oFL$i,@ۖȉa8kClj&2GM]'t/@Ȃ݈QmJ!. Q`y.vlk.&R0T9R=rrj[۴`D,cOcϬNA*叡i-Z~f);^B2$d=QO+J4+luz=N(-N$< ~%y,o@J@x iѮ3h(فau ^Nsd:b@5+]E#DUR#rY<t)z %ŀ',D׿?[\)b_YN-?lgKhD4S.<*MJvK(ƘVq! PLEz3.S=yyOڛ 5ߙ>lk2C˝SVfs-)SxNh\0Z #/rRk^;+J,w}zyv|USfJg74 6;N]S0H4*dd[Xsp3t^Nyi{X6*BnhDRȝv&4uYҸ+T˽D:S,ӆ_KPƧJk P#85^OIIvmM{+FD8S/]{*K:d,zP(SoeEI60Sơ`KS{NqI;V~(*!HFdƺ暼ʊrs[ۄ"/h{SaӤ@Ѐ =ͪieώdӵ֤!b!4d1dQ b(l=F9`,qfCz"- l0d@Vf\OEh Bc¤4x7q@B%-ŽljD Zkf6B|CFV@ؐAn:j:h78Ju$Ф~w4ά#ʯ^l{yCDsU+zp"dNIyiqv}m6#K)!#wpGIrɴLsSc wpsQP "C]3sV8:H0 .ev2dd#Txʳg!B!RGx]H ,)nok5u1DYvqD (,+_e-f_=lj1/ (3H ՈO)%_\z -fzr*ܞ7[NVL̶iUK 'hf(AV 9DfDf U"<_s[L0ƚS-^ZgVsl\ZCW4+<`Fkۡ-P|6쾌yOQ+)sW:xr3wCGBԝq :i)TTf'~IN _"?)ﺣ5C( x3XX/e&q]48 &u @Wf_mme_CM5`gO oS"J[젚:[Kp`K 戱K61tigz㡈s~Ii@s̚N޳-2q pEpSqLhuѴ#sK*ty`55SZnnBβ 0+D=YYٯm5dJJѦA f@M#DR|gDT-v{,5 9e4BR 1 7J Bp#"i½$>ix^\-h9U9] VG[l% %$vXܞl2Hi D--s.&L`-jH"u--Me[Nyf8T"HwJIeץaZ^&X`dtR_)$;cfl񁗗=OPL(eGe-,ĊR+YahI1`%\87ʈ,J Ǭ{l{QR0gȬW4)$w9^q f̬tO !n8%' ZL SLn[=aN^KB*+iRD:p$ڒm\\OIEI 43jD8b&Jx Nͷ9ew-rԂ[\A0RwE0S>J1͂Npp sJD!m#k4!Z ALJ<KEVT Sbs8 H)@9̕?6HwaG]Cm+9t=.G"ऀה-RY:ȏDfS(UV^SQU<­oa bz@&C־ ɥZ =r*ʉ&C]$ّSx\V1>_s**&-Jz|cCQ&x$ Jڮ7@U=r4 1ꤸ&Xp4ARÝpdն4ַvH' X [ Ikd,Ô%Gj<9KBڤt:[5P%7FL:X>OK†4h1#; p(J񀩁(=_atQj5bdzag,J/ <,YX_̞1B+bWׅS4?B(h[*) 1ޏ$We˲!e0obg* s4ҘSjg8Xq&j3 młxgC.d6%5U' z$1jW~4nl/JbaFt–aoeBx4XwE٩J9)ێ\:l)$L}nf楑PFcDODiUUդ) T(' Ȃh!!фZ]'q L%bjM˨s=qn!-m$d̬aqnM[3ѩ DP~Ć24"E DF p/y͞J8+CP<֕NSD9D(M04ָwi]ƂPkxx#ЉLi g_gO?Ic0L$,{ΐ? w ߢvfo.BZǴ:EZr!Q%_\ۈU"G W@y!#eHH6mֆREg*ϟ+qz饙Uv V?oŊ'l*D@L<j2ddhJ8RIi F u1|6va(,8瓭Aznޏ=yUGIgD*l,ʫdI4Ǔ- ! bx7ѩ񝍗v,Mh*N!(S2XW&z@"f} H0;;޵QdAW>}'I1B#Rk E R7&Tu03HOJBF .W[oAiPZP*T;ɍo"L;5%vհnhijlQ-=f#OJOzƃDZy?Bd6lI 2o/NLY/n HKQr& $YHL!X{ N+"P?k1ffblЯdήpLlɩW:^UԬkRlz꺺Mh-"$ ˑQ"B^J@0q-Mi6-mVɼE=fT`v(X(ӑt'Gߩjz;Ճ $i)Zϙih^Jo ,(tef_@M H)ybdF[!4'Xz;N#Veٔ,d\,gpgIg4+“X՜zfV{fd+l"5:iaEKK,gN}[4+<^\fpi.Hj=^!Fsa2gd(.z=@S?\ɜqkA?.:5j" `{ PPRFn]CsA3Fe@*EB  [`yxrP 1%n?!Xt栖$'h\'uf`,w{Pg 1wPHHpwO"$ʣZ5d +xJt5:2A25&Мt1삾N4%6$5q۟s{@h}f(QJO2F*_''XJȡN"lA_FPS|nA5AhAθq?) ?|3+toE)=Q9R.!_7h[M~Lr={ _qĀU &Ձ8qN oʃ1'&De߁ D@'#:#LuD M&wɞP2/Xz& ,e@"Io⤟]e#N '{W\lIG|_xTw[A}u Ryy>r AУa%~`N)d<>OFT:>N  T0C,35#%kjJ(  cp?!8` Ch_ 'SFXE\tvZ{Ʋ0xH&pƷ >(A !pP#HSp]Iue/XLOYA__]$2Y~qx l떋i#FcA22`M+RN57D۠ѨPw>,(7d'3ь/`EqlS ǁM6BWvH_gy!An0P.Z{e޴vYrEIKb\>. |3v GIu58C顠TY I,xT(}y*PyaeDX-d:; nh G8B=FG4\FScƨi8Bޯ"[X ȐVPJi]!2օ ,4D:"'3+}ƿ'1\[4,~}d6@g$";{fP Q $ИzhzK'Eo1`"\=&o{u'^DanQ( fcI]/ @| Z}WHǦ_3OA,˿2X/3o>Z^WS.@/jH6>HϣWhsB*(xH08xIASX19iA/_3/ `[0rܵQot_|I(,*]?ӕ/[= ^v o6fpw ct0M(r]I.+ g`M OE,HY\oSكhl$Sn\=ތFK̆gr~ň{T/`_9GfPIzRXEӤV{EJKk․7U% :Lo`A |:٬ D u 2t63Ml490F28J$G|sKG!tʆ6i(* KD]4KLhȯyD2x\((oD/IEvIla3GCtBZeu'9`AIڎO ,Uha*"zVBߎ(\¿8"%գ=܀|5}4NKϦRY܂Nm0&` EG-$ѫţ|o jY~'&.Wk֓\wNV8n;iz)rxf6LbIT \EPj0L2K:źI(?%vRKa,`7NDwB'HK) RE)iX#R؎@"ⲓ,2Q"Ge[= a !$\luM8$`h]Qdo [ZOĵR-/y8*;'q(|B7Ϩ&/L'`q5yHj+ wl_@! Kqi`e2[P+H'dWYX'+WeCHCfjBъ6ВtiDcGBN"|]HhaƐyȫs(Ɉ,X)𩴌~_z50k`nzɩ Ըخ:hh f0.5 {H*pSc`h"}N=EbPf?J{ #%tqxXc:oO ?h8Rf-Z, aBJB[`edk?G<ʷrJ,']_唉X, \a;dO'2sO@kqlԊSAy6.JP'$EeŻZdQ ]/p^~ CV$z5!7ј-"[}5Y>0?qɑeRKM `P/go(x7L7 3쌚&mB'&iī#Bɣ90E:a^ם7dO``ԬS5{<4N{tF`x4qx _CǴ*`l[?@z)"1"Z, !s;kC2X Ր0e  +;'pGN22*>תm 20v]q ezN=lzurZVmQ@1:2lUȕ ʑ2v,IMݓzuc6Ƞ8Ȃܬ0Pƪ޺/Us-dGZҚċ_qz!Ұ@zfsjfͮGS6"x)Gӂɼ,F-:16"<]GE 92ITNM6Si/6!ri)u*`p`E6ŸpKQI9%WS*$'=*cC8 S|i_ʏ,hԱt> upJ-K jmh8@(SDc"C:4u)ֆHҠa*ڽH2MPGV/D}/'u(0@P8@ME);[w8pWz"ӉP _=P3Ec͔_TIoM+uF ;&x;̳6B\8". )Y)TҖ=NNn$C!e S`NgHb2dH:]El@]qJ!tDC;P.>2#ȏ#xif4B+/9./f!(LAm0rR,N qm¥05j`);P>'8aF3h249PFAGZEXkgjpuS0Hb{I`@/zRl13186d"&#)XUJF,[˥xk #2q%NP]=úH%¸A"J  zWyi;SQ rrf Vka@MP~>;T'fQ6pLv/S&?Fda!݀ |p'uniqgN1 .5Zf|]qbi93\,?Kč2כl(MOt"&1%ItNH&280P(ӾF\ 4[ io@C*8z#QZ_:a_*WtuwVB]`.).v2PY.K:˻J̗Ţt r(N%?epF 0JA<6cmCM3WVxy 5񔖻T* o%!96m1"&AJ6YZ©hld1LFq\I?D,9XwҤ YE^LtkӞșwCOAʥ-G߷Q`2aTk`Q/Ob ,Rg`K087j: t!BQ2Ջ6b0A2(W>LuiUEz6k0y6;^فDYuI2 i#ɻJ˅2 át0 (ע@#F()GjBRJaF3G xIWSZQ 6HVaTQlo*eZ}ȾWW)M>3vZm>;ATN:5rMg,.}h>6Uoa,9AOOC0)Q,r^:8ʼnW5q$"G^+YdūkeׇpDP]cpDܘ,7dIz  \kZCN'39QB0ViQ$jb`AĔ X{ZlۋQWj0-@pBlkOnmlmoмnF6tĻ<2Sl6_AFu+9WDQ7Kh盖/FQ4Wqag 3 0Yh4F;`bNջwp^S6K<|tX݇4]˝k^^cΆ_Mq"Ծ3?]/a=@琕@f=ge-Ĩ*2v =@AU_=3<ɶ fcb?QRzn@TeQH [OOg.-0|hJکؚ̼Cg5vx>81u==2^2! 4'E{5 @`:bڡʬ' *DIYSpyPc~?eOC #8e:pYD!EQ2j. I-M:@3BAЙ| bR^ԋ8B6zʫ,?w`k%_#樳=a(21d!.i |C(nlt#7YUUUzbQ$}RD۩_ '&}ruTdڬ#fjb3pI\hQ4"D B憅2`=HrLۃyX1a Ȥc9\(^D]"DɆsPU$FCuEJ/NETtS9X=`:p;gZqy.~4tX  gW:QAhk3Umklo5Z=m}I '!alط'ְ|tGb4hEX?+h r5r?~FxgmmSgɦB&4^'A#lۣ'2ѫ7@өXә]ڟJ٨))Tc̝"fB k~U,âuUTI1Ri\\9ɧQS {Yboꏾ"V6cfSapQ^)ͩT!+)uS>֌a[{q GHD ߤ(B;Db0326plfNNبPwɗ,!VO\%םZd:,ݤ)CW| f>.?,_hLZ$ rR`}>[%g3~CMBOK4]E{q63 v"QM`8Ca- [AP 6%L#Sww S9@%x+&uY(R(<˶!0o7$d'A%&tCYU5 ի2u3ti71!錁4 3@9aD y~H~!|rPXJdBJ*MFtXoLNQG&bt D`,lXvSQ \ 2lCr Pսxbn͉Kj%G蠻HCN!__s8bYnqR1gnizBU|d;G>IkҿD([BZVHU߲'=\ a}hxanXyŠ/"D4``&T$!tP>=2UkC3+׈]FAN)Fq /&ި6;.}Gr!y'(I vA/`[8:C )R1e0Xt6oXag\-jE@KVU O'sqjwq)+/f# I˜ih^#1ӛjeY0In~UGN0 U,ei mÂ+Z0(69ٸ&GSЁXf -7h \KQp P_𜚦@=r 8T! ѧ0KF`gG4H4|Xr{q ML ,@(~c)Fb,N>s:$᫚zF 'c, 9_=qV=؎%0: a23YOT*cPLwyee?;cB59}!(#s')[yPBsۍg U9݁4=a ;LXA3<u^iL#̇ u`fU+Ӵʟ?'ZtUNs\5D}]E '!?jP9L64'Y|+6)Q ,dv` F:ir "U3T3^xhdr% L4`7tOah\? bOb:0]fJX8" :mL9*kr3 nBF_*Rsێ~뢑j̨ٟ[.ŜM5͹BmWcx8qK<9g>4"i݄i>T赂IWAiA*,^"їL(L*Bk7y#D|#%!!ٓvGdJUÆ#&l5a6- \!z=y!Q7d50 ǧ΄ h('؉KYC3X[$N²2|C:¨;ɚ(ĥ.(Х`u-f%IWy:s-(KzF3<.vauU""+M0 ('۷dt/ $7D;&L6?alҁr%IcĻ7Fv2P[bڨch>nQ8Δ[3o.Loj$θƋEָJ;6E!gɷ}W9}FkEDE Pe^\n D@Nl:cAMAm蛣YO}Wrbۦ@uѸ!LQMj+כH 95Y$DSc_K:\=Ds|pԗR_QPzRk +Xhy4}gc]媌 6GTYy ̵S8R(.iEiG9,(+.+z|G]ȗv0D/H8>Qm&93 =PTqmh6mmj 600F{G]O:4-ԌB6 akOƒQ3 6,1XpLoy tlA^mps30214N爓IΓ5jP(G(57as82 C[R !LM2RuSkCi{ӻE)`~73JCn[W< L;f]K( q xDX"]dð$pOsYàG,%r$RLGAs[>8lV@4F70u@t$/ Fꌞ19”!NG24W5_0lj}8$[ٕd$T4&dr)[ p 8m9vH~D!Z7fŝ1!RLoP2`ʍvgLl}s;H54m (!* FD6)s#=R$P>+8Em dV![ BvXGH9n&M^JuU"LT BEЏ!WXL7&6ɒ" HqgOWH7Dz( С<4Z2sJ51I,9fξ/ݚ1IbԞyWQ:;] o.'\S&p&nji<-18}UU6HA?놛EUxW~Gw#V J֏KW2EC dXA"̶a8?nssdJ)KTU+ !qCV1(>_*(- aN!o{\!,<>մ^J;z2>,4f4l^D^pdthAnFm6^j%C͂Ҩ,歖rIJXPSJ%-58:H؞JHF9llH8^ CsF8pFo Vs BTd ;-m9h:7.х*y~E/Pӝ0ξK!.03\fte)Ej:ӲC2ށҡOiChbV C)*rDp"/Il@/׮n'^n¥ l^͝FD("Ki#KH.!+hߌZEP<"̩O JٞfE. l_xe\"J0$#]5.9cQ!tZk'kH 7#Ar(3 Fctk3sT74ZSeFMY͐D'!`42X/pҒ!H HRT'8PnO -G ,*CJ LltM?1@O^zkj % Rl;u.ԙpNƇ_lI.Y5Nci%0q<%DCgxUFI{q@KmI2{Q ;yL,,tVdCәF`1"W]0+Tfy7`0f_PZLsHLVA y*N^jd(F)Yj)%HՀ5<#XLd ̈VO7BޯD lVpNGfyU·AORt*jr=h E59mijmo&g.:ہQDqYJD#= RzPȮ'Řm%ʥDxt)VpbwyZNdSrbƺtRsG-Ɲ4_є\FVsѯƾci`M!ڂ AN EZ+ -=TR 3ue|`2Nv>O荨u&[03G1unX>8# `v3J@ٰ$<_6K,c%InƦzb%y܏)~ՓA Vu䈚h;@>Y; ]~#aH#X'Yݶi-1,i'X+ymҟM%lR:̭D˱JtN9о4L GIT:8-6GuA0VNC4c<Ae0,:W4@a&j{9 aIUbOaR? `=ҥ6;{ :2g0,Q=Flp4d3ZZ6T FU}%%4LJerE&fZE@69,RWlJ`鷶ja^xHFJA9bKr6hXzHmIA2t{=noL;#UѠcuƁdRg% @ ەkuKǘ an0BؕYJS\ZMg Lo\Eޮh6J [UcL-54G`| (Vg^á:IrLp ƲX$`A4tY_Rd;DP%܌y \2#a A)Xe9#kjd\mm@<Ei/.ҫ=l';T7` !5 nZ$ډդLǵȧca u: u.?\Tdu_,PI⽅rm@[UU[W4[|j?yҕG (;%0ۅ8PemIYhSm+~ݮ L+vmW\Gt$2h.=ɗ RDF`sx/K(a 3^#EX|Ռy,5iм/5mD,EXi1K.]Q?OU ]SL]GL++gҴƢުܼex*"G -R 8គ~ԤW E魐" _ߡ2x;C#'̷̢H!$C5EZW2Ψm(ؒPdxGEJp3JhÞ)|*jzyUUU_h,uT\Pز-#u&X=kwyd-l7 E0 _ `HϷA24CeW/ BOш]Vd 5@3=$jĈ!L*3_Iz W_VD1h9"i=^Pt"y @Jc+˷!x΍4S0zQ^HE6Q+Acr%EcN8,j8]DW* yK`+H_zHZڅ6Dѡ~ Wb禚zv*ў ˀBKT5cgNj9IXMPKQX[š*TSL/OQh4/i[U`^y2^fVT(f@xXfYkJd7):Qg>at6$*/*`cˀ%NRE 5t4򶹩!Ch {,󺞂O3j `RⰠ^[l- 8ms K 8`NP.R" p8\ 0 c`tא8$D]XxE_Jd!3#'*1=Ed!mN%f2dHž*ހ1Dǰ(}ÑO-V(FD6FVTz=f a6sޔ ,IExAWCo-c' IK`q3q/5l*YLqB R0i$&RaJ#2i qY: j]9iw9! 41h8#]n1]w_@H3.=Za4o5:AvX[Wɳ<^|ȓjtLOeit0՚:CE`?4 l[F@,}h_&d(O{΃scK t<)ҌiJٛùU4D ">OUDʿ $+auo2:Q=W7&0 !*l~M8x(@s;QKFr91ƴc9nOA&7n *Ȩ^3E ;5ylGG TW7@l$ CTTb`uNh?“d* hKuB#A%ona0mN3 ӫ9nON$Q{1nIʼE32l. Njϯik40(U{dڼŴ/$L"|eH M2?5(9hLц~nn Yhb+]^K0xNxN1&2O*8c0QtLncuW,嵡 #QXo[ dG?ǽv=d ̋]AXFֆ *WZZ6Ĥ!R1TP[)¬IΜF!]o2C}[IH~9W?xI{]j mq9^pyLyd3Ki. V8*<]idNbxj({Ȑ LTIVȺR;t=3W$^3_Hk"t؂/Y#{* B (E^jV̆yty 3 kQ"܎cB -5Ӓ }Dh"('`'h9Ĕ[ ؒ"Cƒg BbE$ unooloODaCL9b,ZRGp2*S>*T`=EU3D*^G/UV zR)r閈;h#B"$ѹXMX7)Y5QvA 7bMFy(Cza8nOzG(yґUQ<NHx" =zbB _RRZFu4⊛ !}v`N oAUsDqUSxWM+ L,30yb/c9Q%@}BZ;@p%ZTehJbi` *+#`~FQv/mPNjFV,PT%7jQZ1Qr("3PVGRdχ+y!sPj} 5 =2$~2L%mp[k[YI<"J@`yFLk"85JVi!BtvFb !z+xmi:63&TۡyZ$K(4)M-GKMX3#YUdctjw­FBP"?C)0?`~BqT/*txM6eqR-f=ң⥵U46Ulf :H03BMZ9γΕ|@٣y:-3p;7>FPy Ȟ(>}w+uwy½8,'8RIL0 y&?I1Q+0fKu7k0DO "}k"MTbIDCDch fImi/,'0{!2RMGcKH:X*A3!رXww$d?¤҄y٣X~iEjhE,&X*MKkjBPJĐc.̖ ?8DK^#M?e6_`@`noWįPyB{[B&3|_>f2Q)9aÌ,=ʐ1̼j3k)fK#V"XA>j+1 ߏ ݸL3dXȩG,1bBp+ FA rԚ[EVsq)뒎$M)طb&\PuwHL32<ǨaN_є,`_y"eհ8u* s;pt# UԴɹg0FNL{{xԑdйOa ` ŧ.]8C8?/hAZE'%RR9ȭ6ybɎhIn2}6fw8 OrywZ'AJm!4y&ө/f$:fMX+a"9lhZ*Yi44XdW6cQG"N$CSQ[\r L# fT[ 8@mRcH#cJ1C<`RXp}F)GZ1 nAh}YcPBРE~ .pVU5-Řhe"dҗP"J,[]9vr VlpYe @+ia\<ݱX͗φ1T^7%pπ`dIRӫ0R-94q`-a5mo Wf71 %ȣ!Ѻ\|&42ciUHim!%ҕv2լnPqa) {;v5 q $ f|orIIu+ ~=Ω^ck+Q$w9>DT)ڄ#$&[l~ WLe1\Y\X8en9 yQ( b; es#zAhΤm͍j}j0ENĥliDt 1X 䨠,2 Bsk%/R ]DyBdBhn40hy_B-!$\ 3  p+E5?/~PfHw,AXr$APa)`?ҍrn˺Y+d4IkҝYa铱ZXîwKV\pֆV 'Mcz?wX<6nZ;*Q:2(~+"!Q3zNRcؘ! ZL*SNhLOM\e(FP L [Nd7jDH8+On-u]F1lHhXSV8D89қt{#j'er;?^[[X/oEi3/ TTuOn˦E3G+xM V*#!0\!2"_@e֖'UDM5kZML_{m,J;)ZN,aL lGWK! u\<Jc#NIk!Sӓl&>t'_4hXl,KxIH`vvk軰FQ<Ǽ8MVg!kgVU!wq) O4b"䶒 `%J uF::naޟe4Bf<:J[q ? Θ)MeQfQ@ls1)3ř"``PG9 ^} &hiVq_X?̢Lxs H)gy}VJ40҄erާhH'RH 2vbs;D$Hg:0 ҥjHR[{eA%G@c5Nhe6h\lbRʌr/ '$Vbz~U:l1ᱩ$kO4IÊ!or:QTs Q[ITq ]Ր3X d'kaCvT]DљEaԖXryiN);S,/kwn, `hLK]֓F9^QtT%*i6Qk˜ (~8R,žgm~z";N&g"DuK4K_%!,uG*&rV %4Rۜy:O-dDDiRj2+49M g-wGc:5A?HBP dԲ,98L ?MmBQ؝ +`(29{%9 rr1ȶD:ըn-`% ŐШ4 -;lV.(dXB4$pd!3}?Ō؁-77[&=XӏΪWyOPGd(uLc z]6^ӱt^&;]  5\<`@! CΆDdrjx.ñh Vn4+',w~r [NZ1\M-;-[Hhjk85a؉THGe1vwZP6 1kVeRJ/+}Ũ 8P!EJC ĸh(fetn3.F`XLN!KۮHwrs|!UA:kH`~ueDٚ yK Qd#4i DfBjyS-MG~&v:t|"D."LZ!,)*a6bm$}BXh'bS0HM-[%.kFE!YKv>3赺4ÈbBP{D PN*ԧmɀQiXĔ6}WVW6V&;aL^ YEMIYnhIRH]uS}GCK]7` !aukMGx"NxQIjeGZ 9?Rlj&S*=6? etXP&ŷCrc&vKp@5LX}g#,@ \QA-';dSz-/ѓ`^ P&jmR me9=@C Q ~0PcoR:>Z P*$ מ/#+UX;ߔCn&Hﯝ8TgMuVY( '# z*T'vGtHNƲH)9xNe+1,mH^pI IV$@A֑ϙ.੓rVox7>ɬjR75 9Ac5k)^K31%ڼfAw!$}!%RKSs08%AC?t{(EX?Vg m]4!kruk16[.P$S 3IEIZ$xQK|,*Skqo|nؼE6#IsB?G(4xnQp(^@E9Ps r2S gF'ߖ0`Qj1148"h@Ame-> 秕 yV#'&E`!aKt.UJ <.^7XMj*b $C5P3(\[֍A,4K%t68 IlBn!`.~ \e[Ɠ}hlbFj/;qB@DfbPuhۯ,(9Ƣ ^vInh*,(laͺ3Nj9DT5J6#"B!FBKNa_ !sM,bfPj؎4t]R tO#VV8(LXDI^7h(a^J|gU՟4?>,X~x@EHp<" (0i퍢ݔaU}E %YYs*pE4WF3Xd\jT6PkmoQv?PhPXSh@)BC 50ҼoFI~aMoBZE%r*l5>Nir M8, UYY=HD?R9Nkt;c1"J*#pMZ,* fX.T]+rVi Z\_Cx(=pD\vI1=ʖ[NS aUKEwvr<2&p0isCRW)3͍r]Eg6Ks:rƆ4>T<"x\/*0ji_[mZcY-ɞ:Ԑ-I5TkF @Vҋy30\H̓yI6Cb}%BgՌ PZ&+Wg)?x4tOvuh(iq:CѾH W)]HkJ h AJAv-aq%bhYۑ ӹ">vcF`>1 'i/ڱjf.`oJk;)VqPt5L^4ʁ2I~JXNKhf@ER'"@H\ OSXMun1&y A-Ps˜/P+%+Bɀ' &*2hhR2 mQ^]GmKSSMs]{ <SI1gP5XOl: NG^z1 "IK(ũd)+UYwP'? .R ӈVy ba8NZk'32 5yA陞mЖtcL3I|YG>@$ZL[k|w&*̫ǝ!M TAO %]t7'bQS:eGKi'`ójϲ/Zsv}sGikupV$BƔXEXBS"VvV#z|]bn򧬬$_/^wnO)ť2,Ks;^p?)Ѵ,Op@#i9j=vʺpS]1H KYdr4гhaZgF?CHp,ʂ&vz;*Jxs?-+kFO YYZguԏ5j];;ͻK6hQŮcզtԱNӽv+m8`rg@7uzޱ2iO?- ߐ}.j193cƌs}%p8<0001y$w)Չrb:'̮mm|;wqVM8 4uv}?{傲w}JbNgnYROjZ-n:.y '^y~;ٷ,f-:n?µq.׎{g[;鎪xI:{V.w|ۭ<7k[}*ؘ{gZv~b۵-]CKrܱ<ˆrlܦ>;Kao!o-)oN{Nu3<Ɩn ~{J>z'O?tȗO҅_=-=_k{K=݈-g#pOoN|.]߿fg;ry߬,[(~ĺT_n7s>5uovMwv_qȟSsyv|/,EgqE]t{y+WY3]|Sy]wݶ;ܶׯMWݏ6 9۶m~۲޿?]:fޑ/_0=oWge'w.}q]˚.9q-~i݊ɝC7/?:qy|uÃc>Y/[l>vkf*q+_+ozƊQS /s<e#+w g<#nkv}{MU'\x΂3Q_Ӌ ?_euvuGvzwھ9:`e7rsw1eW{/m9m}O-?bğWtѻ=Gg5Gmx8۾˾8g17|qT]w|>znK>bW^;hD+[3Ӷ9bه~ nqq{uggge~_];&r󛋾߲[_^ڽ">x Kje#aYoCZke錼mg>C֍?v;AkoC_yĝX[<{ߜvCG\y'|ūGvG+N~[/{GY;]]֛ʬ`~7ߜqWy<+YZ[erW'=>;lnЉY7鑭Ƭج ;m'|QYv/uѹz5lm?l`rZCpo^{[}~+w9gu?=}[v?_Z>[|s{Vtc͛vzg};~]+W^do+~cZ9?v彩17p㥮5,jv+k75,_LPs?Xccz?{?Lh9?̿~]۽p7\fs_}?<{͏P|W~/:eYq%_g;?u _;pW_ڥo'Gv56Oz~V;m]9yJ}=}ÿ]:N\ḻ? ʑΙlxjwzpjM9wiTV]faVւ1ǝk_h W=1pħW]ƍ(nC_9xkg9WA?wv˔ض.[ObdQҷ8׳{OhQݏԨ+R˸3^w>~TgT%O:n_]2bpBlqi8Ԓ{oGl9w0w?onCpGDs_~ n|j .zm\ᓗO y#[HUOh0aQs9e>@/+|%Sn/+ {4o}cӟvŵk57.xߘW%ʮ}`?ugr7xgUlQ_whe-uW^2agB<|۲E#ܳZ7oWo}t/aKFЭ'FL]CVҥr^oI_~д[G3SW+,W\rǓV}wܟ|'h_Vr%y?>_(-aEㆿ42eNyފ_}zl4s'NS\qۮh{FaVwMII#NYDO `3o,{mzieY}ogwz{{`uwcnw庍/yWn=?<z/L8vR;LuI{SO;msC//o?{늢66X^˾8|1/O/e˲vkTl"y?~|^ _;X/#7^Я}+7v]#oc9z~JW:wʼn$/;}vj[tv6Zz~'7=K{2O ;k?}Ə> [ [~ȱׄL׭Ƕ OLJǽ[XuEO̸W=~lʄ׽}ժf {ZZ=eѽ'|P/z勥?7ȥ/U~;Zy)+߬M>/ˊw_~ .䈿ZϬw>q`էgsy$ŗ6_{琍rxO;uo_=뵋z/9}ƪ3/驧>{tGǢݻsqa͹_y"=\sS?.?]sny}Yp3Yݒg\֕zƒ4[q7tY+Bߌô.p]lkDlzݒ=6~G9}isx`Cn2ְl3#;hcwϯgZ̤S_絟~W3浇oW)ˉlqʯ>}#|O}ɦ㯸Ϋ\L[.tK/}ls4fZqs[vlK1߲>{Tx{ჯ/}O| 875;>mĮkk>߱pgOapqUyon>:eW}>w;鲇Nq_{̅|Edi[kJ?}zjVo;ɺƫ{/^1_gϾb+&o=ƕKO ?c.[QdSL{os_;[wreWq{-Us}eܼ*3wBg[n.isŦiYGL]9ߜruW]o< 荒CD_7X >mǪgQ/=oșw} TҦ[{ϱG;z;m-[:ԿX~.{ڻŗp>16F>u{N ~)e}yyI؊Gv1|P{2.^I=m/-g ig7[?ԋhs' <~qV>pky>[mK{ԂkY¿Ow'm#G;J_Y7}nUXYr'ߟ}~U ^y;{Gމ_/S~^n-Qߞ92Swn>|5OLJyM6u**j^'nqXbS/z\|BŊ+~z͊?]Ʀ5nwon3f]{%zo `uW_N,͸#1>tŬ;w۰}=w] ?mܫ#gkN ^t}C/u/p>v!]fU}]׳>nkW>k3[.Y'4<⽑5o}?4} ߮sQuӷ,xL8|{ u;)Y@6~;+E|^o{vxYkǜS1[GvnkϾo_k\YR{ɞ'L}K7o̞K~ˁ{/{xɫzI bW}5nt7囷|i .ii;N5p;:g;8nk{/+m|qO>sgsc?h7lz߬C\Q{{~tW筛vZ3F>sW;8sU].]i='GE;}^ߟ9dQMn(p񵑗˺郎◖-mn}zG޿9OEsG/;ݭ=z~}e}oxIJ]u…_dnA| }kn;z1 njy;?LZ3嵗ǯiX r} /= K8:eYwgj~xKG ̽Gfכ"f/~~{swsM9C7_Y{xW5vAnaӤw=s˃:Ozݳ>Z=ZQ\7w]jg}g?vCvF^;_t膾v9ﰝ*>q]/g}K}GW]?mu~݊_~} L(c;>味7\;~/_="?\skE^s3YGO>*?79c΍-o֞~>^]Փ.{f O)ṯ[ܹ]v\7wŧ޼ac䊦c /jnҊE^O}^n^OX8mGw^|n*GK_,=#+aXtpֹnGe}iO}~7ߘ{}{w7~zfoꏭ??zo_|p F?TZ[wo?XQoܶmg۶m۶m:۶m۶mM&wI67ꮥJT}8 p /VXA\NPmހ?کd@jUZ_j wu:=_a쀈o' 9i9FFV(46Lg.oշw(w#}_ٍB=86:>6Pq2NGN <,ـA7hh(46[--8Q; {/|[e~wb VrwyF}iOodXUFTjj)w_g4PG `V01YpKV!ПhXz;-pXT~A)[UU+eUee4Ue9_41.Vʄj2Υ+ hj+ICAHd=f Yƨm w}$< '@UTlWKth\Y:S#HC(xhT<`3A^3@gϤW9Ȁzuvj\VuzVِuC"ʿMQ*e5^3 Qk-ZY>^M`Rt!aSB83oԍDH:1_?!ǫ`(:`,/O&/5 %'(; IoBޝG۟MPTI~\&hrjl']q/`\tߟ@W(az4c)8oZռqcJE@2=D#V1SSSZa>Ҡuت4TI GVuuIOӋ࣌8BUUiЦ,C>:!ܳ5,|E(B5LFlKWd|b)>&cj{UH]%X5ulbblFG=;Om- %Rb*ЙG7{3`1Rq  С%ō L 4 3@*$ZB.]/>!_'69 %ѧDB8%D*(C~*H7R]2=ˑ_oy+: gܤOa30T09z}Q$)29ɾ&<,ܥPjsi&@ԙ y`n}m׳3`*_~,KrjBKTl4zڷW#E qBJ%oq6, .ܕ}x4 ~}4>ģf3_#i+"o}ƭVD-,O5Q-;@DX^0G oqZty>(N>_!R; 4}f$Tp~]J,0Z^zpGy}%6;"]=RpE@~3BтwD2_ &=^!ܢ!$D"9 e(1+n4LD\9(IJ-\ W]^o&fCќbMKPi ÀvhR93UH1 !8.&C)MU4DGN0{DH FH @KV/ը  $D}LD g"T{Sc4b딜oȪp4 8Q>'4ghvp&hq0>#?qv=R aKjk3 narݸj ά>k !}܀)B}"&&y}}T]$LGxtF&ܱ%0Mf@?ݑxjq\&A)xnQ(ZDL@u~ ڂ&zkýA =A3͇( [@h(0A%~N|S?_n{Aґ@ V%g|Lg|VQ/+(+gy& ՝!OB' h#@L aA(|u90H|hA'I&"Ƨnv^Y?y,搀%0S@ )_%RD6LQHDB&U@ۉC sLu'Gf "+O r 4 }+l .Pv5܁^58guTO0jl4\{ 4L7<EЋEBb兮c@ PEf1@J)#?=QG" vb $)$;PP cx9Ҫb?0I5/3H`u]!ǦJ(8$H$1dW+}yV+Iϒe7 dki&V#,DUO 0@PRJA7HUK[[~RMWr۶U%9麗c@?~ }eI $IKπGSm5XQ|ok[:' ٦_d剥$w_'ep08o?.=kwt8^烄 6"ά=Y&M ͛8%9OUM48fԓʁZ5Y6 sUVl~_|Z6j ~\=_8I* {?Wqk=[:(9= %[z:8^tAw#rpMp=?(x?a](!G׸JaEJz !C@:W, fw9DCNY-Oi'*{ACH&/:JvTx.Ł*jͽVӥtQ/x,J֚ɊiQJ!twIXڅ\M&"8D\>(b o#WKzxdus5bHU6&=`a|^*ԑky#*;]KP,ҢJYu)P>"RiylD1gD&x!pbz> 麄he#^YTKI!/,Fٟ+bYTۡ|`vi}ٲ7)Ϲt3>XLUHcf)&q`4k8!,5_yXL߯'o|`zT^gJ}Ym'1Oױ%,vuJ9 d i[sBe_y qkr8E]<_:{;1[H?=(EDY8X9X9/߱2_i/o0̾L'u{#鹵,9@ $G貧i\HT +֡6 ҬZ*D/D"ruSsY56usQ1UUG~S|;^tDN}?mN!q x_ !}@\>Aj+eR+-s/؝N)0k(`{ ;}7Ŏw\s5 >Dm]&GN˩nVzƅB-M0\/ v6,|b,_]nAP =*ޏk}Q=Ԃ&ãq>de m(G7@^>>G+u6-DIL14~LI&1zR1I0%yReNm ¯يSJyG|g{CWdzugHB|G H#TB+s7!p@lYho{R1B6IX1 `TDH鸉e*RGsc8IYBBol-= ze UlMezm~XIUy;->W)ri]Dޟ'U#]yD1جu*35?%]/r| =_<~wOx* W!b*D迶m u<|&hx)"Q,%6%T;ޞ2|r<TnftΑYlP\,\~ &~H:@%~~QX}V ׭D5R!$}h~}Bu׃_Wjﻈ78Ẩ04ELzoTeMоR}xA-Rl?)0{AۀFU<3oL2ٹ6;u.W^NMxҺ &~9U}=Z_K [3NB2."F&P&t`S6T QoU9oIy~Qz%Si-0l/ٜSE؋c<̇ۑzD,L#ba-D! ^2:o[uѝϼ֟[{ilw#hIWGfVAI,NeգtLOo\){,8: 9ʸJ( v2qw~ȶ^W6zJt*PlxNSZɍ~~G~|r&C=C~oka"s@ Jɧj LTTXRR\(+ Hz_E( a 8&{N|U9_ȿ9oR37j3o!o!ty>[]f^ytFЮ3Cu8MrqsB?$8YJ?KI¡[y39oRHbJ,itM8<usP4J|[A!נ1A{ y|QO6.kLCOB^{v? z| Rpm='媬ܞvIr7unf+#/Z|' THxk{NGE޶]OF1M*m02u ±辋6qY r0 _^[' QНq.znZg_w輓Ep+ ήDmㄣŵ3Q.T(3;4QUBs4,vV? ${lZ9T'E%bZUNPD`kVbFGE팀"Ϩk y2`=# Ve|,[=C;- G)Yo͵py<6Mv1D耂XZGD.zG+R4 ܃V4<!$'[Rh\x*öz0ѪJud iCҺp?|?}}r:?$HߏUOI _rWKCyʍLt=Y3 SS.DX$$JF$}L- /48JYŽGљ&<kHFHD¤Jw*C$N*6>aƅ/ƖwХoQy0+9ow,M~C%"'z=Ir '=7M᭜PX7w4,хC3y*96X Uo18WE;b,h=zYW[I $u/&s$&؇UڜNZ}e` Q^Gڃ3 }?{k}յ {MMCTNws=&BJGr6^CD701G>M݀ACOK+[wMSH 2ö *V}[JNB1d%WNxUg cLVNy~ת7Z|fB6PbKMs܆q嵾(boy.:8xreL"TDDÍܞVV=ZN2$jW 9¨YuGͅӃ&6ѵ[SF4H*W )c7횼GKf~рo,$di{!!Kӌ]6p[7t~dwI(zsD^ 6'=|^Ѽ ɳJ$c3Z$bQ-gtG3q 3e¿i#UOHV7p9f􍞵s)1cY+<xzc tK$F{ufuN_ïOB> `ٷaAc{ 3#q#-'a芉8C4V>hRb[1<4'$8LI \$&q/0A/ pVA2G P G"qt9fk-~#mRP{YuҜc)@1)XY rhcZmdvb뙁tH2Rxw2#dQ'a߽nSKyKI(mJ+ꌸ5GcҜex_b:EE(+KX" A r\mY1|aήﱗb{`w9gV۸H$2ORmnt1GL"Bo8ٟ^)Qw6Rnt=v1}6u5XMq[!ΕkNQbmYG1JlӆI =kpRd$QüЈfP; ^](@=_LX1WM셜W+6{-/a"gU>A.xmm =wqau;Y~ Vↅk@iʯv3׍͇F_B81UIb\*ȑѱJm}曀i[Ds k,_)qIMVxy&-O K;N[,pmk8p`a> 5 }Ǚʢ[\Gq {k4WxwDVǽEMKu]bR.pilíG?86WF =pX9 "Lcp'y }n 5C4>*Gx%Ef/!v {Ɠ=A2vș_|zLvh?̇ˑȦ%=#zHoOր<2)n\0E bL!dF>ܘ"B7Ȃzu$fB-`UXr-3IrȸkyM[p:ڨֈ|WŘéH |Bug/]_|4bKxov  [/δzb9t($n847rܓj5/>XW@',6pƥ.(G0^%Dھf;j-?e9W5~̲+gZE \ VȡUQ$&u&M\Vr0ϲr?'iu@3[ᖚhHov}4e*Y#\7һ٩޺ߵԱgش.V'yE)MW1T[vKre ľ{`S=8ϛH~$ܥ[8@5De@Ü)O3Mf,M{Bt]Kl͡orw]]bC|rb}LKQ*qU~TyS$.9O uCS%I(IC1нx"\ h|A[gA{i~ے:ޓ/fc#}W3 =ڄuᔚj*ˏz0>ORpg0׆cD8QDa$\}jk¼LI-pY9D)Ffh=;d~iY1onygME#vd٠pVɸhQ5kAKN vr Br"H.sA$$ %=2Q񊊵NEu{7(Дܑ2^unU Q 8]&r`3|/qċPX@ nZ'oz!21u=\d;O>gJƕ:KI!6?{cld#ٖtt@z<I]\x&+ !Y9?<$/叉m8,ϕ甭pM[ ݿ됍uCO*uh:g^HZm%m,=\e p9#I|@EeuŽJ-FÂAzb^)R}'C [g6 mgZU;-]1*2'2pq@^!ȊZf{ 4$aF=}x 1Hf<&jڻpI URd5fx:m{!nnh=,,a%uK;:K05wF/Sq8o侑ёrYKN36w0~{j!{PhB$.5NJ=TFޱ|w8\ANb;w5pJd (=eZ V˃ZBl!sw8)AU2\:O*#pARp!݌r몔gb-W$ @JΉ{sRe5yB2a"eI+ϮFMMɜ_ǮvY 6z5=1N* /`1tf䇩Zm n=z7YU*&O}Y\a;a_lbmVN7ʢ RڀϏ7%HQ<Kg98 WO`y:)"SᅗZf'!vB*qVI)5pR@$R z'|p~bהS\`FB>0qH`VXPoMHL踑`ʪ)lIzw 1'Ad9+%UVU5i>hR,y0Fqg_iZX [/H]GHvǞkp ͝÷%vkş  _rЗk{h3\T` ȶ*?0Sv=RQACc̫-Ao8(llP.z*)o1/^27AWtzI;px d]J2M6_!w"=[bȭ~˒ 8lI V]ac#HP2]ѷᝃB=4.*A"TA$D}PR3e 窚M ij _ a֔Pg_7w2š&,h ۆ 4AkhAo $p:~h.^/v7%؅%\u7 +xq3{,]&ksJʕ{xu4|F- [ei=y6&' 9yU\h^bX\h䐯޶7Txܵ;]-d_kzBK ^o R!7^3J/49p*bӀ}|}k$74*aR1ohY[2\*wV/EPosq܊Z5jHaέa&KH:udogZ'iKM^Df!zOIDB.3,̜N!.ư)kv ݺɝ lR)j6f[WYfm!w}!cNįM ?~pU L,]'J|Y~>̹Yc@Ͳ>AZ/g Ux8IES#*O Ү w]}%TDnߦڠYv+ 4~X&ETT 3WWR7a !Q |Kor0Gn·!]pJ<5sM2 ut@"^^"08j"-}/IO?%v۴a k6MIMH10X}pn5aL]Ib)nӂrLVa*/d栛p.uvkQvU-uޔ$U){>w+Q3m/БVTXi?7򒁫c4K IMU?wbOo>g򿔐АX 1]]a0ֶDž$TJtق೙"cr[yzqc`Ha7&as$; p&>z"f K܆vO[RW;rUՙfZ2˶}욬]i X*0%[rg$L%ufn`U yA5m`tX^R: \׷n y{Ū߄SU@lftA*nND^`w^Hh4õcg}mc_A}<#9\F-|2lWa]_ 5Q2 \DeQHEcPX=5:xivW$m^S2]Ydl˯ B!zKD-56ئ[(vϽQl|gQ|GJ &g0\e \SV%iIUtU\kJNԤ+a: 0K4#0TX҈.[9rpvFIMm*-+n/{]sqwȢˊ1$PUM=0K"h:qlA˶tc}_k˞zvWT4m!c~e՛Y[5YmRbuA T__{vyN[\ 륞>V2Yzus Z~o`$qSjkM`2- FU[*tv^9M# i,_!=&\~?SւN6Z1SWrF^bZE%e냯)6Fq{i\N&٥^k^+ʆLK˒m5Sw>nL|`i?։;g\ fLg8q7h(w6X)}LZ{z1Ε&u쐶]Y_ۜa%R4'F徻u<|o>ZG -YBS143׮̀#ZwKsmǯ}E2E' 3-Z4W\dW*t 3o^uhKτnQ֠?P7ol4'DB 1Qc4Fg_fö)`ղGW6W<:O"&iZ1x: `?E],uFdt٪\h QyZZV?h{S띙w:F)cY׉*Thl!/AT~ZNCqUȒ V2 knyr4a/I!dՖej#J!T XeZPNؙ^s>:8z_Xj TAj;`g5M GI{NV~mLt, ۠6eFTyeۑJg۔ Kn;X?wG~4$BI{0aoW|t_׸u↸ cBDpJg/qnT p9u! 4dE'd-LoQKeiKnZb!,I/yo`jd6ǣǹ^HJޏµN9/AF|%)Jl! M3 N#n -K .-҃J|oH2t$أ$@5v~`η>s Gj@m`%8a6Ճx>QS^P=ќ''9,WM3*i{mk%IskSNUMcV~jDeŪʸБH@AQ;SN cbx"|z3,c57 #[Th*͌J[ r-UY‘8!<"\$LkdEb&rvJSK#op!W1#5# Ԋ$ӎ^Rz%$ vB_;費iB$G |l uq/2'NrKx[b fm+u^#l?)_<9,gjo(f#*&E.qUBK ۊ~Cυ-GwKСu4IOl.1'&H&vwCr5= \s'̸0rGeUpbtؚ ѠH8p)UG0E`pY6mvHXI2G䵥.x` rwm U@)Dt!᫢}.OU/UAETLkO%d|IоkoNE/Lhlro!&.ĞR,wIQeMlaH$,*a9,)k)S⦐*Wܓp$B(-dYYj~㳭[x1`BzZăA]7wC3T/xns4l2f鄼TI$:\:N Q cN*BP Pq«PVBItpI2YKłlY׮]c>[ ?-uFw$s-&%RO̝/U;C[ 2vAbXAy_DQKxQ%D=-:;e:%{UUF9f0Wczcek$(unU:-f{YrbD'̉ޙGA:Px+p 爩gO,Dm?*W<VLa}Fb/p3>V 9 EJ@pAsqa{~[dnlEg?r+^Nΰ"͋:\y߽֘QGLz9FpL2NQDJ? gNctLÑ>a8]قD'ہ>ŮJLޕyi.8BgmΏ]'<%`JӄiRbX612Xʵ'N>PmAe#]6{msZBBLEGYNh`9i9>% D{0LcR>$Ĭ%l.3C@1sn۴( Cv`2%Alez`jԓB(Yú->}x9ָK̄mpއ% ,(ǒ?d+^.nAK# ̻m-0'g57}W %_$A0ծͣE}>n,/p缚@?dc bG\"Z.9H7 V"csDityjr5r$g+%k X96_D%ʼn%~4DFcVk $ƵAJ&.[+-f# DskEhЅ\V fg@5sP :,1]2@KdA{_vld}RCZM ͋J;D+.]ISHCpżƆ 3TiϴWH%x#C$Mݽ?)[08Bú]ۢ0(yX#NUTDqlftM̰pZpɚnJt^h` Uq%Tva%$z֪G ~8b\1̊N#KL>4k4ܼSÏ-rٰY2mJL(x^L Te{^__>lmQeGi1KDi"nE"U'K" P5kYC~o= SG0V%5K|@P +jIzBxE:Z\JaMt7>ǁI3S9_b^O ?(S!V~Ts IXIjQSVq)0&쐼2//U~΅;P4o^22k+nE^?U:9W*?p&5MzQ\(j]VbL1Y.WNܰB,b_yIµq]ɤ5ASX^Wv 5$&RASLr2?qDHv\{{!9 &ib)T7Iyxǥp㸼 [L6q[F0:ڜaJ1|MfA^R q]$AFUA,3k{U}RHڼQ֌߭$woo$%bWxl+q^\g7m}iʗvM}HVe1.g]y\I6jj?[SE%{YL?ǵ|7BP^LyΡ$[= ·GYc5":YU- R.y:8 \S#m#pM/HpFoB<͒ qz7T=깶 |\fv!soW/,|Q?}8ݔs$Z-zhU 4Rʄ}^\-"K&}@=2b MGA^, e.C7ty!IDp4WYY[c%)ȠdɇB8k5 J,C尵+1zO^yEܖ=F.1!ӗ/q]×Й̬~ur4 gmYRYryasȝh$X[N]QgJvRpWf\6dG_v_eLqk6d \kzڜtk!/3'A:8}Lz#fn,L>%kpx/R҆V{:+Azcad/n\j|WLr3]:Wɱ7Qg.qÁ!%34J}u,/7bw]d-RҪ:;݊Njqu̲V/.\k*Wj:DM*v^Ȝ(s^W^׬.uDdͪ^cԾX)yaZR5͝m#͇}AjYogSUo}Rs˫ 0'$tFJAV!e*jF27\6$29e -ZsLd"lva6Ų)fEXTЏ\ozUWU]̙(@|9{Ȫ`U7MTwY%,ܐ͹,ct2O\$t*m-q'sA5ߦ(i^.s5º"WKč⁅N=٤oxԸ9;&Uy%k-P}X3uŅMNGGڈ^ k29mQ3rWR㶗mk!U5LJmyEئئ = %U7R~9{oȭЛWqqzAAqvfЗ-P?n95q `M=5BŨ:b{B_U8ӞRVI3$+Q3<Dsph[7v- mDb{bmYeYR~7 (q8P)ALGN&mY\܉6LbeїUUlc"U2q,Vm`eB|k7D򟷩1PkKK>`2ev@*gcTv9[V<:i*LUcUUh靯{Oޯ8n#z &X9K}"[UO SFLOFX܈G iGy-0 m^Y)>\aidWL V)}eOmE?ONf2lNJNكE\]B쯏㝦NX [قpR+8m׏qŧ||̎`|n?Ʉ5E:3e`ݪ6y[W鐾 "y;j-$qul W R/vr(lRmvq?R}ۂ )v~nܦYߍG}-0 DK*WUg1MNm_ 2.| n2)dI4Ҍ(^zFHnG"25 YrN(㐶l7s.Z$#o6F0ul|į/tˑ%ύKoz^id Gkb]_YE앹h5qyo`fЂgmtZځ ise,sC i+qȝogᮙ_[T Dn.62 `Hn sW5Bnij?qO/,(]M]IJ/Qoԑ'QƺǪG41-e[nAWj]$~Xqnݐe+.vuǮO,q@sҵf /QQOCg쒔Qbf <~du:X_Y:+mٵ|ہ]79֬^ґ\m+M5y?ZuW<$bR̵Ӝx@5HncK/Q쟀І]$Ln7>viW[dR֌H?sOU9 %Ee=rxꍽB謺UX1V[dʖ hG3o=#YӉ_53T=hm7G Ԕ(jQosz6iré->fbZ0?Y[ؘB6*8/ػpsj1[\~N!M0#yYnхlO{v{'{.%W59 Mp%&]à2xөثv\bGzpR:b Vau-b+q8z/$kkRѡJL샖x%Nlݪ1fү\qZ2ASL)\R7S5ϸ%3p@C؆OZq U^:ccRh}JI}J./7MEޛcZкDc J5v[7IHgAt[.ߧ?{op>rif" {:e]>1ؗ܂\Yr:)By{Qy`5}-tFѝdJ?Q e|Gjpf!OC#p_-V ~=CJ]7sof3<2BP}٢&vim*ϱE x|,RmL,/\y"wx~I1nx ¿?'kW:l+?䡃%Ls#Px،T5+!v&uD}ͯϢy^Arjt<=~kcе*:[?^, xFX2H5/w`[hf8"u&m`X}~}L99OSd}pk^{?#u0O"C~;VvQU+G8!{`VMm֑s&nW9|ݰigLx,J}jSsI^nR+3$aڀToj1z9C-9 gV2[GIR G87ʧAe*{˕aZr ]C^ȯg/u1WXbv&Zee|8ulm?3Vt,a?|+?rN=-j;u%C&p@6U2p7~ 9K!|NUO&-E&՘Գ{JJ9ׂ9;1YY)-{[71ОI`1Brd)%v~PAgvJ1i26f[טgzN3Q,Wwua σKN@<-٫`G@LG-C9 滋)I*AGE8s;'ʋ) aGxyg 6h,n#B17i&%,< ZdMQ^[o%[;5:i: N͑k]Lb*A'D6sdȖg К5|Yn%t70k:j&9D5a{;5'1|+TVAAeܿ0$tqʹ+nxED$7Od+s;=} ] KmlK'x ?1t߁yHآ#vYۄWѩw (Bz|@ˣ!j[!,s,jfFzFfz&Vf&fV?NfӞVI'׵wK ;uZc$Wms݁ADIR+;=r3quTim3ޏ4g=Wz./BL7I~2V#ZcN3zVV~>Zg.q^.Ҫ<"g4|K; \.'$?H8=̻ctu8keF?Ng2kfГTy?Cy2YWoe量IpRMI`d/9B];#H}{]C ^w#c]=߈Bloce.ʼ(L{χ>;8`{Ϸr.n 7Eo+;Er4:: 8ρma5M#<OqSWJȯ <4^I=Py _ r~دZ!Z$lSu&`W>eTtFY.<3&`-58 J'RvT|; J^4pkڂݷΟJn>k2r&=ł$WӪf٠,d>8,c K=|wJؐ `FT $&->KY;LB/gnwU\8CLH(!r5oa7R7Z]m%`6dhh: WճNV-e0"w/g!uп̳.|l&eP(cUvd6vzʛdȢ[ϡ/2j_ +;?:ǒNq!3B+z%zEbp0jMj4Y˲ܑF9qq#кY~68!ɛ 7&fW9"A(MЦn |vAvަ꾜^j\+t:>kll.0ߕ6+sydk^UV=ODJCǵ2Gl ¨m"y gt3GP͙WVg&D}$Z,,iE.\Q`3}~mw SgEyIeʌ-;d=Sfp:-A$4#/Pfngy+ }b)(e5>Ѭ Dnw*E'ofUV eBpFͷqC,&N }rYBkvS'I3e9פݸ+% veZM̘1.x,:Ú#]\`NÈ76IU V1K^lK$1B`iQq]%_[ZhX^XkNv2>gI4\v3*:y4kpf`eaч}w' ]dwf^Ӵ_W Ar1gʅ~=wɺJ%/ߵ;uȢDŽ"y2<Nvd&ٓSn[cdyt9aoՇ2#@991Y+,}Μ@w!᷉inuk & GF)Afk!Lir6sBdAr<9۫Կ31ϵ5ۊc]ܜǜnMDZUKՒ_֓4 O5bl]_"A;b V2;M8 BD I=ڽFr.+2Uj2%eItIêwpM `iK%dxN7pјy8(évTis{mLGFXRY젪=ģ?njsΆ(T96X=;8Y+<_N+ 8n/u!41^/8|HEnAeϼ?d=&wjRY,gTz}{ٶ4,oȢөrbp9&L-ZL!J9ے.]޾ݱ_^Y4[o7 UŤfq?ůn7cXIl*Kߘq:P#M,|:0o))^Atd]<'Y+nρ[ uq2aT^U4<6Ŗ6"-e^'Qptşn{?jADG]F-=eiKؿZ{, x(-ehi`ш櫫4$fܽ@)n[@OƊOaʔv0>9Ƃ7L.9Şx~dyW_GopɁni)дk4rϞ ƾ?!~f,]ʣ|I_bZh^]QdRܾ[课qΰm=뢈Z Xߟ|=融b*&N $"u2㽁@ }0l.[bIIPjTk`0w15oza)?"d$ܔ4->(O@XCԜEXRΠ'A|>i5Y(oBo6Xu }~_[Qԋ[M$o#k%ߐeMF^%*v  ?U $,EKL[3Q"P7l*ޓ>I0bNŹߥ@IbP| |Ac)"hMr@"Ho]%)_EC F%QL/ Cv&)|PX)Lf$! U'~?D8{5E ]j M4wRqY[dWHǀ:U-@`8ۈ3 V0| ɳ-#@^6 Y!|?|ELQό_Z0c&/fHkh'X((mt׺b]?dH:}_쎆nn(%;fj.kdwLM-#Ζ PC\M촒#sMuQрK#HRo#w):6]"oO&?-ͼ^r~h7U]A|H4f:P,KjmIw>f+~[IG-(I7GųU/H\[(bņFx0#XdJ-'00X1b _TE0@M3*4;D~ژiX`c.0>C4nR;Xy@uxYLjқTrEw=l r/!P8zwZgRV-!<%F R?>5Qx57mtj Yɥ뉳dl /3:GK4#P.XĢ@arJgFj뻝g:R~.pS-4irN; I0\0'B\ծ>9H%'s-VN{w=FK\o\voı[Kk=SDZ--0PG /.& Ѧ~oINE?iOV+t/SvZ=Ad3;؟O1E֢蓋 xH82=jBm yrDù#P5_^*?\<υƪYzU|"R"o.a?3š/7a#b!{h,ݮSʰZZ&7ʆ*^F"ci2zw'iʺ*Dd^J+p0^MRXPZ[P- ra=-Oy,d4xLco@s>T?m"nbACGa* ^2V Uܢf #!y ..^CUު+Wdn9ka!ͿQ0Wn+"UxdӟG6U~hEZݦi(#h!w Gn?oAQ^_Tu%`B_^@u ̢wۨ6F>vۏ*Ps u? T}z_@| L <ѿ1֜W_1~ݏ姡H'Ʋ ڨ QLk?#v9iGB}99#H~W/fFD#G0e+QIJC~8e_򁐴&Pu@/k[,>sAu6~䀳v\Zx0Gb_x132 132LG+=K+R?)U?ls=Rh]_O[WGw\g{KkSs]uUcM}eYyEi~aIߢL쬔Դ脤Ȑ@W/9Oogw_7[G'k{ 3+sK]cS#M}Cm-uU vi5E%V8l LXd(e*tFZc%&hP(?4A"@|r cEeߤe_TK_TthMFoK_ eFMc=p+%h?3|c(MsVJ>'q c=@uUPAoli7^@ﱐwl߸w(]}ȘwO,J`Dq .qy5~"-vg iWv ?,i,C 3i<Y`1iCBʒ50d5}(ߩx#ǘ~9iSUE͔ыir%( _ewĩUXbLoCS+xlL&XuH|aIJy]LUYf)`RWv떁^*򷾵Vuo~Pn PQIegukϷ'^?lCE]FEh]HgAr ~uvѾF&9s(6e9%O#C3 Ȱ~+-FCwiWj%&[,2}/{GuSsr$խO\YQ~UB5nyBUY M D >,WJ^7,d"vi籥2(߲96pJF.kշT)JE ? w&bBN;)C 6LGSHҸF٠IR%u߹cVS FZDͽe n6ADhخPd謴/xH{{q ؛2d4Tom rh*ϓ Ǚ#>a>Msɹ)9edLLn$E=cސ_;s qdܖ~d*>((8)%ҝ״KnKqx MmTUݹ#BvF2#`O@(i Yz4w[>o̎Y)oB?V#~C-ux`n)rqw$0)0cUqklv)l,4 G%auмۚ&9-\<&[avT $u˛]a`y, k4k6y$74mJ.D)>7T*K+6g Pfq)OD'E}qh{.YG) ZtO+r^?pk ciuLJ&f3Nh=E5ÎڥYf]ܑQr{/U"cΰw=;`P>)FD\VЫb0OĂ%M߇AMDY7ؗ]MSHg?tҏ姷vtxCOqX)Ƕsr%&.=$9@Ձ\ߖ2>RWW*H Fy0myAAEKQ?n0HA!d'S}qիLL7p. i!0G<]R-@sƕ HmܗE\Q9 h¦+ipP'y5џ3a7S&T˴߽UMwM9{s'Nu&6 OCx!O 3lkz"R>hqOITַNxi ]d]RPVN㶪EwD| lAwqqd[@rOS_0U9Kx8ƌ{Fh))@UQ!̌F1s"ςDjq5g Q΂2\ڏ)=>'b'Q*!e 3GiR<ǘO?6QDk Ѧ._ zk3Ώ݌fS縥ɵB2(OF0lZ.] uuF*˵Aҗ_gnЊl%m~^7ӕQ[SKh|߮]ЫVd".ՔJj>ѿO^;M ǦB-:iE}Cc)gtrG.톇￾`Ki_(Umae#0WTq]׬BI07Хv 5/i8|R k8: ۈ֡BORL&9ـi Z7? }\ɢM@l=qp,!:5>,lksv'P?K#d'ɉލ:q^P8L;u^] )ƒa̧Yܩf #d~Gv #^FZK;?¥Qr'hp0vzl ~HQ'e/+\f~*tK]W$p!$ƙ-aYU3 ;( ‹\fY 5ZU36%hRNaXD*D YvdЋ95f 2Vpxf!dT|Dv|dxQ\)8AdLxwb67n')54Jrw F4.P!ԁm|U_[nk5"&gm~PU%< n8eb0BݦՄ- U2Br 4촤=зٳ@ Lės\ :QVbUr5U8'?:RA U˃ Hs2(ʧ<֝^hGȑ ӛ"i8)ȫ)[1N9-6E%+UC$y02V妏4UximTٟq%D9`?ԍU "P`m+p^V UߝQQ4ہUy7:&LG}WdW( Õ`Z7pG9_o 8k=%!}X_kآT.үL7ɬG|G**5fIAAm8`lL$9u: %:Na/2˹# \ػ sRq榘Sw@cb ]̘oZY M%|5H5" Td5q%ZpPkL lQO{GWܡ󔪮B/M r [@u!{ɲ}ܜ3ujHgX% jJɞ-- |ss)7OuwwQdU^Vj̛gHZcΒۚChyT fc@ۤDlWׯok~u,Һz8H >R%X]@?\x?z_ +W ͢˹I(tnolE(m񙙶1I ee#ϦkCkͫ'""4zܯG١ L`E ;fك; _ rzo֪H vM)iaG4h0<$j_?.U3pWsEg<Rb.\hAꟂ[VPJq Uߋ.z~Oty<.Oty]D'<.Oty]D'ޒ[7aVf^t򸇇0q[ߧ)oV>>2KNG/Rr Fa2 SzISGԯ9?|z~*Reg1Tu3K#pObbֽ{&LVFn٪>Ft4rOb1& >M4_})v^XÏAȲ[?osh2-}M? [VEb|<#|$rCz[7Iz#pH3bǓy}"HZ!t R~I!ctazebA]!WŘ"$Ӆ\l>Bpm.0Y*2ٍ $6;${m'r7QlSMWHZF;"k GQῖd.׫g~%o`N =0 ֈ/uUAs`} X8Ut'/r]^ %xX$fQͺ4_+J-1ʐUiFF$a`Y/|.[b20щbY ޖZٟ 43ʌd#.Tr>-8/-{gl_ T8ÉGyqJ ,~V9XAKpҧX$l7$ b%-9mewN4Efj ^P"pg6D5Oˆ7dQj㖛wdgr?u~(`x4h[`#B_cJK8>/}L)NI;2RvxEb@>$;N=刭%NӛFg&}kzi`[))`ةlE$Ѷ% ;-^Oֺ;v\&tai,wajcp.BRJk mV&NM J]ԒWt{>{Q67guK+|#M+R4 RBC@,1yGbU(vo)0F,۸FX'E K6<΢o_ch lPw,TB/ rp JLۿryH2X"c*M!"QR`ixM{ug<q4T>6֗&E GҦE~c,#G]Fe=D`uqFRV./W41Jw׮i=}YJł& kDp+rzcq/PSw|ͿvzyΫ+Ss) 1đ԰x)hЦ Pe5vri?> "6_gt0Z:yW7 _=Uyp pA4W=VeAw)T0A]_zc(B_{嚳 *4e[n_NCH% e06Ц6v[Lky-ԏk \1y_oعK}[ P{y<`Zwa98 >R)B'85\r kdֆ_\_!4ƒ!%jP Ws(UƉ{iZmgUio$0d4㥁׋*b~o1e^ 5e-} OEՖV+JThVphhzٝOSv h0n]z6/*duRe^U~W2?7 %䘤?VlX.LKG|oSr!d7NMi;o(i1`\l$GufF h?1%kZYfv5JrzR9*3]o+Hpm.PǾ͞J Q1HP* IV!M7XEf /?X9XYXDYTZ~z 潚2剖aH9t ؞4eD;&ƫă<0!KpMGn_sI*GἻ 5+2u"<0vPZj.ZGyeX(v8/7T-Sh~c1:3 :_ A^閁J(ta ^$v_'ピp]G*7+UHJo'MW[ gё N _<kwZz-efU@e >M%aǸ@Ț<\<Z[t)Pr,+ ZU!S7dl-G]z|5CivөWt (oj%Mz9ٕAa|͚a9%JlGjqݻ_U;R%^5) O>J/"v_] zuW=o I#TRO`3\}#M=Ij|sy 2\B:'%ʑ{B0BnSx=yhqTJߥ? !(;6ΰobS`M+NpD;Y#:^ vG@F {EG VV%%%O_h[FZCbZ|$WƫɟTw_G%a7EY 8x/y>kwRH l ]/ m|}TKW5hx%HVa.3V\ǭ&.1C1) 4GXϯQO9pr $}jUZ)N$M-V.D+BjXMztGhc _'Pj$MIݗ>\[¨HT$DROMzw] ѽ>VQ3T~`hQJ qjʶӐX۸"3h,ir7/*_t‘*lM$ ePBjhE5b5σ6n[NBl }(23|b\f%":W uF>ռߋ:Oy6m:B&gՓazHJ5 ._y@U]vUaei;C}T:m3.cu{z{<Ⱥ0mCAЀ6Z`s5VEz!,,3,D*;;:ݖ 2YVkJ4`@'u6~LX5V3-ĦDAʓsz]ְdۧ3\Z@r&V5mzיTq$ Re3ƠU.|P1)1$R%3|u[%ً ةCoм=R~F#M2-^ȍ~U)-M5;玞Vex_ ^[ O8mnZ Sm;3 "8l&gG=Wmz+W+&I;;qm|&2~޷!OGH/hPjYg"7)Ԋ04QyEJNIZzz=S]"4J"TU7<,ࣵ-&&(nUC5B8|7(M! u Q"/ /( 0tQYMw>\r8,alW._-p]ږGN鏡90nϽboZ3+$%y'% mOjyVRa%킪^066vf?C?9mZ]ɩVf ,q=][*qn'>⦊N.QU.[⊉".,&#{6 ߈Ȫ׷){Ū 47vEL҈Y5}ONn.T od.<>-ɪպK N2y,xks6Fc4t[eqVƿM>/b7*ƅׅHAɁ)˔M KÍ%x]Z 5%Z_Ώ!h2K$ASZds\0<6%.q/m/;N'(}PGw`$-S(ym].L/^k`fR/ no;n k^c,({=mlܶ^X?dրlUl^xZ8 OwӺ_ۜ݅C/Tl0[Ϥѣm?¢ll̢,l"lDkuVx?>1~Hud=bɇ L`9VxAzhqAٿ;dO_o7n>c" HueǺ[Yک} kInlpC]eg p]sI, XhXǬbxSj>@{gw/ӡJ(662bBU`},Ƽ~Օo?l[/tSVz1?dpG:r`tqu}sa?TDN}ŋDŽeWα8Uѩgr<9knp<^E(h`Ij0uNtvp LaPw6 SXHOj K*)0Ceo,IEk k^kGYd,X<֪ +iRf_~YCs9"Jw=PQ->Fcda nHhm\)8e/1hsT"QMoEʒLPn՝1_ot_7Qq{x2vyD5:60/&]Ņ0\oؠ tAKhPk4?Oҁs$;ʼnBnHM9|}f ?[ʩ`[ 9X ӋĎ-se-.?_B蜸fm&Nh ٩Z9:T{AfɅPgjbz7 TD Q7:w$M]V6҉F6XR'%{oD3V -Aa?&V&k=/*֭caDP#0^$M?T["1Yr~7[EW{3HEّζW4y蓦-9װq1dzB:&7WMDkM/kn&4. &" dsƏ!7v\'G/WkͶAWIS1@GLIeNUF]3P%s$Fo8΁ AztcǷ}RqE$͡>@gLkJh/HӪ&d:WBFwǕp/O-}V灠B?H*TZwPL : ,066ISQS5z cp/pZ| k*Ҧ^1H#8 yUOٻ3!â !9YXX[KUH+\Pw3: Pta~@ڂȠ7Ȇ 3цjt`( / +v.w;3y<Л,IUe63#A MK wuAb1"i!CؠǠ.%8>(O[|Z>qdɠ o[;;ɨS6+;O084r!aM_YL$ \$q=38X=z0 BkuUj{ kM໒Gy5g #ag gSXϹa\ȔCϞϮ ߿R v $ $/4bec`dfff`cc-up [ #k5>%-,&8_ ſ^DO1?^P>,W+d:0%dPP+ձeVffjfNpsjij59_-r+r@Q>9 2 2H^h8פzcݼ1Y ʹoJG]jcR͗_ uc̏?˱'wkk\Fmp&X}xwFw 2,SYNiZK*h߁̓Lm⠏%)ׅ v6hvauPZ␋Ӻm8|wp &&}4eoU΄_p-ϭ\zOJjp+I4V^Cm;S』wf#ȭ-Սq(zi@&)rQMx*!pYT;D^8^=)ʶ2 ^4G~їF53fSpPb|tvfhݟ?>aKvN3ꠟ'*P,,I:r v >`~jyI镺,RiN;,+ Yd]F^NŃ*]?Zx|ܒf4n9 WJLls-,9nX[AJTB9bW9]" T(C;844:*20"7Wߛlv̑Hp.E4]̼-\2!AXpŜҖcyύ|;HjeCxE_ZVZ2y"eh/1ɵvܟd/C?ԡņۛcxKdWAYHImMcPE`$[Kl -ɭE '`]b"IF ;1cB*MzMTY|p8U񣱟 "L3`8fJ7sn{b(s,-hwh"[#hŨ"=0"a!T%airi5bvD]!!\)|TSi [RI<vcǚqbٕ#-?@5hZ茬Jcs4P{6+CY l3֞!O(E*% ˣj_Q4!|3"J)})-[Q+隠bḣ TtC%T"4_}izxq[,VS]&[[U5JT,9dU+u$hXwHa=p<ʗfѰs8$BN:򗪊g8TVA/aP>T  JH,)/ 5R׎H6Xמ#-@3oaFQ^S"%<ǘ(cE,O~9Y8az{5[o d6MpeY{9;ZiZx>X%v T 1-MrJ&o? _n,bۢQM/?b!r@=}e;|/V;B, kKke,ze""lUeo8]}s P] J%9\N6&S7[g3x3(Ħ0e3X@Pڡ]O6}TifanH>u:^i z7oYѬQ.q1CxH@goicI` èReD2u#cu5yj P$6ʭh"+ܖ'z0׍c+~ցRզ1𽲓 {Z e*۞Ӑ5N۷*p5(ɌM شbX+yP+NcIL< I]ίFfu(o={MyH ]ާsGz쁗Ep5K^n+aX!Pc]w|? a3"~`;J˞%zdzn9H\DI]vŨ 틷ut|P%Z  7IX7gY[Wm)B·j4uXlKr֫ͮ+1)l6ަAAB((gD ڐs9#0o0,0'j;)~B,!$!(*+y6pAg'gϙJOO ?g0LkWgb0aHe`O7 @ F3L|id u`b?LR&ǚҟ?$&LLLLLLS71aJ5a0anTTTm2:41?&LLLP?(ҟTi9RML&LLzjDӝ:a21a`N669?:L4?c1?1;&RSc '&RcptO|~Lc;?S#?70Sy'q$$ُ)4S yGO|9gf? s??tl`7J? a7?997DR+pb۹EDEXDXEl׹zK{j~RK6YFpUȨ4Z# 3_f|}q8zWcTIFpg#36Uʎbff kG]c'la{\}rdXh7Ig(v0t:>8N5Q;6RnH9|tc#Kr.Of:۹]M/]$)J?)~I:Å7\P^|UWȅak0K smFM舎bޜ@]ypH`EXo ͘$TCI5r5tGظv[hVY[3~X{,찎Z^P̰d|D_]@4USNFNG^ԾRGޯ`Wr@v*i={ 2/o̭NO܍ԥ'Mͯ"G]3I$I0yn9*Tċc*hP~rr*L}S#'a}H V^~1NiUM.*:M\3y%쀢Ϣi87JÄe@Bi[TO\޻>ڹWȢz]O} ˸?X_y6%7=!e:|J:z_6;#6f75mKYs^78G<玻ɫcT)b`l/| e>ȅH;!\ܟUηlT-ˬRv!}؂ƣʻ'!ei8|U4x6]xϽ* h"U#Wx.al ׻-lpg#=%`;b{R'䪬!K6[M].?^]]U/Cp{[ȓf& qhHCZ.?}6FwrVhb 8wqy0hPiYOҡԝPf,>N?j9US'"ٟ8ԕ3Wt:$W7vNSVѪXgwnOf&:rƾ f$@H@a+ 橽|Dr4:minkRYw1d)Z5iVz Rhyl>nitG{]-k9)o7% ,FRBrxfw:Z@>4WlLaE7*1i4LϹ@#`E"_bUS[ &05XxblHpĉz`Ǘ[(w9J[kߙhEka<"7\l t .MHS7Y6؍}V$&Tq: /3` P#*D(3 j5a^$1-%tj2="DG'w+cGZ7kMM6k%;'UQsӸy&2s[x q c"Wx^ _$E#O@5+:h xw&u{y-A#F"b7ڑ>^_ń'ʎBֿ;r8ʏ(S#P7DDXA;Qi+zm.gBA26 ͎)coyhmuڰ+)7m|'de1[cSE æU|PPәDBBԓ R+0Nz˒T~҆<.?Z8T{,dTb[bn&sn([lw}qŸں:4 9Ԥ^> 2W_mnss\*: E!D l2⃷L[Bg٪x"('$\m -D83D]C#p~=>*$rD5 GpCm|WHyRnW)ѽ=e#V/NvGusɘ bdoĆX\aPԸI,rcIz&T埨 癐*wƺ;ICE{ӠS C4$B)>yᄡ}Hae Ƣ9bm ycJ &ikk^'=[S&v+C`8KXy+46-2 ^ê.bVgL(9<;#CP㼴"º;7N1m͞,d>Wz;JՊ^s;=XXNVdO3|j4=moo] g(o[-eyDW 7ogH5M6p%e`N6 v? + hy̗$V\!j,W!JN <:/SU+*q#xd/=*/@^fdO;8 3 V $,-@rUw@7OB7gA [%"ei/ѐ3qDj_F!Д+W'˭rnk)pPj//>.'ZmO_Kטs5,uoEY\bU`FYaLm=ʽHU@y3}OEqbQm湲ZsrƝ#Sϲ;>*VʪE[lX]/9tZp $FŻ]j~|UziVS)JF$DaH&%5ak+UЯmD'(:O]HQ:bP~<4dwt粇ޫ>FĄp1Nq7ʕwqdW5 ށI'Ɗ98 r~6oFfB9vU8(|lX0,Xv+9I <[ ?I{žDni5º CbM1s3Ta J HEebd5Háȉ[% G%R@IZR p|()h A'D!`bxCS/ώ6& +Xx Tbb0ȶEO ,4TT xnxC^]Zn/mr rA!S9>QaOP? 8g]vN:ĕ4/+%N};U/VgơDا_:=Ә2+ rwGl'& 8 I,?mKQp}yrskTWu8[ۛݞk|{So9W'R7zKZnjiFWNoatsp||q^<}XQҷp.jϻͅ!T{ggN/yݷUWU`RL k(O[EGZ|4lA_|EO?nO7ݰߑ0ѓf:*m?*xRetj9a/ɝW/7bj{klTΏUsvT?36mSױ^Fx\:/fVɷsoSW57-!woHKxDרsw^۞ɡᵦ[u3/Ut~#NzngoU\Uu}XX޹;*rv4w ݖ x2`z<ӓn~X4!twnX`ڬ.y_ijQ+.ny= :z;]~gF3%}ڎYuߺ4tdݺ<=F϶?ܳr|=z@ :F2<~;4zy|<Y_}óyyH=s>ٮ Z^_ >:"l-bϝ]`q~4Qvj2Z] K}@o_'m׼[0WfKgbb|¹1>ه|D%D+7Ϫg KWb|ק]N[E _?K)FlwH U)E/~מBӃ؆+o_w?hdQьOt-o{{J'1z\g=|~ ͽeGo6،~~1\/g/}#5}j鄄 x~t~dM^8{,swn=xO|/G/p5KNϜq߁rp(W0G ʫO-tvu Ei2Xpǯ+Lw>ګ-#ߋ?/۪UzYU\-Z/\';(ݠjW1%K#tKxs2p*x2lOmb9rt ՕnI^p' 1 FM !1*=!2G@DF7ph4[,}T\j..6f-Fk؛z4-Yp{N:}*^Ũ51$1uY/[zk{ѽ;0xNaHяf5zx'K<ŽOVĔ Z\,[)`VF5{cwXjUġXcKgozVOXLPwg'4c$>G ~b V`T;p(v|o6&s+}>f$(ʲ٤xsⱞ~CWn@lGnkbP?sC*3lҀVCJRJk -ܦ7$Fz'; 5*'j'w{B[8K+ Q\V au3:oD@nMʳ(ͶydP -U)l݇H{m T 7Ruw}s@b-w-g Fj'ksb/2_u'+#@oƟ Y6S 1~P Lӗr"eQPAbOqV>uR,rKBqFUśJ2V#>u bmغƭ+_}wрY +<ʟ&oou%Jj7 :b`,3=0/Qi ֊BT*!Ϋ5h0 x^ͱ%$l~@-ǿ0^tXR\ٿ zh''d:ޙZA|,ƜۦXw^vl/!} CO;n}N{Pǰo^j's$[dk?Wul.r='>_]|z>k}b@ywZ}{b1+W8c%|py%0"RC41#h|Lqdנɗ<;vs'X6n:_^;._v˼߆cTa|ey>huIuKAn0Ȏ\]Bn'kK m nywq~{g6;nooPؤN?я`Cum^ڨM,*_Ndnf Y)T8˲⻒8f܅czқՙNp\ xz ' jЕhg1ҌCL[{0iVyH#ǁ _RVle%Ddry:f<-/x7L3wL|!1wEFGH9]Tڹs7x͈>sKLϬ귆!fj=,\6Xx@O;. ~9]OpRThxUni:LvTaE.Os6NV8F߉HO=GK͘L0q5gsSs~ץ1"p5G ;m_sbCY9C1VzCƯEiNN:t7ˇ@GgPtp<\x:?QHH:UlfRKD`jb9akBkH>.zu<'w0.,ǻW"7RM -`emZRyujMF2𨺸,|D{(Jq Q0q>W 5zE FlRa YԽn׬D2ʋE3?{!{ iF"Ex:D|*o)Ãco IP3;$!Tn;t?4i+ f=4⒌Xab)Lgn@'j8 L̑I:bgZ)@JL1hEL>LDbnfY,Pd 7Hcۜ3o53ܰB⩉ZGF[54 5L9j0ixURt1cL0R%MjLk^jÑ.`K>+ø$vZymkưB,wpVlP+ ,U}/\djػ`+gԼ)_ji+E{ CRq j9t"$:Q%b3Dʡ\8˨]V_圉*TΙR?M4y:WK}&icgX CF4js DKECқ,C\zVTt$eKe U{G| `VgGp)ɡ^\sd*F~ bJ<;#^aJ:X&;VF5:fUͪ?hyZ+l:,I$ \d ƔC)s\H/ 5(.4P*Յ,*-, 8qc["d= V b[7 XO+lj.跘ؔ@j-]n%}kl'Վr2`s1-qCLnY,9)jJ>4_8ș.IltxZȉ/-M5 ~x]`)bwbqA٘nQ4fjzD61pxX'qp~Gx_ _l/V:8>iP`bc9|s'U7MV/N7 ҃}/%HC;̈́"L#IWr!A>i_q myRGh$՜pf Vfk\L@Ў?Ή4 Wȼ#Ru.";gyǠ52 B'>œe-:ՈPK$e H!sWO뗻gA̠u$XS(DsET "$am"W{Xչ@~F0RY&f~6JϩH5*8;BYi kp2{Sk*q() D[,8 :DSm8ઌ՞KSCQ`k![qt1I@H˃IBI.-Q#uaT(r]J-G\aiX6$+6;J́HR~ ;!Y.r0Y \B]cTòBA r=^6I2$/ qwӽCuD{~)WUgx=ࡢ.@)˜ 2JQYp%)!"deNѭemd-qoP+%fX YGk\Q _d8Nih*"ɡMWS%S?XF+m+Cʴ];DdBQlXg-IIσ ,wE=0qMz !+u.KOuZ3T'KO40SArї`rѢѻL!/'fՔv2`nnd<P1{N4LC4wQk LqoƙuE.2258nfL2 CfƛF) Y.ky64d  cp#ȚjDCZ$>q~ op~K ~v.p9) >rCxVEk9SIE'>`b)9V15Tp" KNȅ!98Qei7 %tЅ7/zlZH&ӬcPSkcaj􅙲xDq % X^Кeg֣4$3/#a%m!Kp !U?LURKТԈe &܇[c JiL f. ftV&^{HH횓QYbBU `˅ChZ~mopM7Qo@ƹtJ{Fs7ÚL,bRdhafR7DZ4{'rNIFҶ-`H ݢ\Z^Gد36EĊ=6L}?Z)ˤH_ :Tbkw2Pd[$]oP(4Ѣif֩.Uw!D@٣0+2,ى!%:*.tB6Ji# *f4#h$JxoAn<J~L/` XYOxݵ$F f2:k@q~ z4WNI@{$BЪk ʥ=sy5_W^A=k:سAHHfrGxaH46SfY-*p{ܕE~==M&D982]Nayh2&#ʳ)(7ogM,vTFxG(GL@PḄlD տ 10B+ 9!tea>tA93o+ t$?"p 6L #\sB 7ꧽ]&9P{@#\s'#RPDaWALK(BHDDDPl !Ikd'lby'# %"aG%`F9Egf}J p0eڴa| <+*#aMFxx\,dc4h8gb,<-*!4o\hZ ghl>/#Ec[j>fd@CG<ڍ@^h婄kXHCQ ~clcj Q;,3!ja+(eHdG_12J|phʏ0QJy$֘U6 4lV.53cnV䔧\.7 4U+{Թ vp@HmUMNuF Oj+51F청aJ/H '9B9M,@kuS _ Q3Bnmf3})'^' FupZٛ}xК"g<@fX!Ow2&Gm|q3Զ5(׫6\sN 8$Qgb<&F!iMCm@ݨ(ds>LPN:JD`t^N f|J B{m4Np<0BšFVj6zm-&-9Lk<Mbi"W3sN  Q\OQW#"M"gYu/WMs Z1<Ъ] r{NvC8N3ñg#= cG:HOA)p%0 mw $%|ߝ0g:fzin %l4l2^"fK)ͽ 9Gv(U+4zd:,;!S ڵ4O8%qIRvsnMmd]CQIv%nHiR4YM{1Y*Ju*!eCr`@%ޔXV!za xj  ]VV<bzrux;: Zaq}fN_ԭQ)s]ez٦UKR&b ȚTjl+1͜N7Ũwxm!h"ɾ".x@v _JGqgл[DdEXJ[i֪!?q_ M0BݱsoЇ+,3^ڹXr0]roɚ$=gR1O.w~ŬGu^>-ʑ`?"/Dn0F4OZքG.?jNt\ Db>0} H<BjmL,GҭG(Ttpg=ڑeT,`}Oil5-,K`LNQo=ycvUioK R  !7`bl ?pzz}_nw;T4(4Fp&Jpm 7 Ai-4ĎiLpgUuv IϠɌiMsL yW'eU} pتRZJzy\EP+ć3+ H%W1i(ib)>QˆE7bssHNa<#*!5@Aωw1s,T!J+YHFE7M5҆+Nk@Ủ MeA4HV&T،vZ,+uq5:k매6WN=+aIṣ0H %9͵#Tj+ NE!йEt @$ճ%S5ڄ%怵m%JTg əHޘі&ʹ5Q;PKj58,bQi&HW 8WQYfk] HQB6BEs8c5z"v5F OI1wV*p)Lg(jֵF¤GmYY)®u#xYLdT-r4Nq`'!N7e2hϜBrү(ʪ44 $2yPlzv֟DU9vN4(^ſq^jQpFNQ>*ya^ !u#%qv;I\`ouՁ4j[be-aǜ*B*?(8 xˎE8!ߑO@sn(P~@8%_4(Uɒ-ƓޞPQ?sO܄No"LC,D& ؽ[Ȼ3L<`Lǭ!; yCV\&o|G 9%`BDw9:<zzl( CKnf"jlXڒG> 1B;IOE?PqQ]~ uCO_Yn=s"D XaAA ӯ\PK%!Hbߣ,sEWHakԜhħ0NO4vD3 '|?<sɲs:VxPD1ֿ)3$4 lg<L4p+ Zc RXQJk,.XI%4*wtfIFtj Rj)wc7w} f")1@pl/?4ʤfʞi)=^z<}~m#i~Ʋ X2x}C<vstV}Y Npmu̚@wYun:J5gDO>^WwmTfwyybӽD華a:H_Nx{~{E}QԪb]z9<;?r||7q>om/n ESٕSD))b} R*+OYF,}MrvY$2TRpW-Cw1%Y:)V]]egmQ c^8*^F/k(@;9;TVC&\8ʌ 2`LЫx;5N "n~Kqy]o[Q 7R0ЖG .&Yz8ԓxÛN+uj26jtƀ~Srwmf9dL>skxk2%mTl=rE0"" _۳m@TWJ:ui e|]팆kbYh>swu xdk>qU׃FJ1_8.g bx梦ΣQglWf{ycd!hr ^]. :5iBA5}a3ubbvAObB.E8SvEd,z<2d0J$Gv&R,P?=p3!]&_~c 9&sDǬ:M2']5OQm) 8V9y Nlx'nwc7u+؞&mdWktGdTd!8Z+őu)::'X(8$^=ϻN/R((,),58"Jxq)yoR432-U :\ؓ|lwT11nw#vʬlۋ`c6ovuGlC2C6D8~E|a8 o~#gX#oX#G#X#!(ȄFi`u+u1C%ThQ bGJ F.cQ8e'm"8p#b"7GO. dyҌ۔>>!E~ >vEla4*\Z7ak?;c@–g]$f5nI7S7m_Ls5bJ`Qx]29bs1LqHݛQ/ó9%~H 3%U)BzFy!*i=07:!Z?@/ %ԲF#ס Ϝ>YZׇuI[ٻՠ W2.=vXTX[e¢kXr^H)k8f`)GJK;F܃XpзjʘJ|>YŎui>\.*k/V:&}~$X,6AT&lV>2Kp";S~zJlZ@y]DW9!rB`t# _ &n<1~ݧ.y$gr`$㯕`kQQUpiǸIǵIULfn1o[Zӓ̌VtO0=KLNsnk 5ŢE}tlt9ҫk~WU$b.HfTBFH3VyH>BXcӑ3Ыђs&W !@'f*Dd5+W3B~wM*8 ASdҶ LW"#:@=B@Qge zW@S`d"=*)aDu,fH/]=MGҔMTp SF2lhVlPDNQy?\!<r$"#؈{7xbե*,P©,2~7HU"%HUlvĠ`R@iR98H&$1N4mm1u9\b&=F:]`r\4IHm̅Bah( '^}q%4 U;AP e$4EV ( SB * .L VJL@e) >C{Z {5׭W %w'Œ䖑0|b36MzR8aŬx, /5gĨ,S0Gh'pn2Sa]N$hMMjx$x,.$:DMM ~ZW Z#"l sm&V nVo.w|Q3KZÃNʞi`clrWC",%4$,Jsv*+>S{ 1Ciw Dы3W?e4j!2̸n';ZAS{ڙWrm!ͬUJq&4SM옇-5YEi@yܔ5h KJ˨TFL\ltTn+RiI܊]N0&7Y=~+ 3XGz3 z#e0y&uzT";]vôeSvs]h,lT#NY{-|a?#դ0Q7o[.V 'XW_VьepH emu_U@;< < Q ZJ'UMT~?Khh8]ѬҚ6ffȓM!s>y!c#D=t`Y'}$8GT^lV&[jr}Q4XkTJs6y켁 N)g΀(hweKlj_m 3{TpP)>ZN2@[|w'bRp@=u4P@ o ƨ8AKI-pG1$ID<k/D{NdC9-H!k`ɭ4P06|KH+$IW3R"* s4z屹9z5ȄR~@!&O`"Ϧhю̄(h֓ \^W"\#Ǩ$~Ih4¥DێZ%[$d> @؈k`=ɯP/ !A 3’HK+P$DMYPl3F9K;OW+m΅0< qIR6ڗY_OJR/vJ!AgMaY4?zPCrg3O{(:]΢CY(<|I3mI\en&9R^GZXTOCWį)||Xf! RCC|Bdɒȗe LFx(BB>3R򑴌 jT*5nޞ2eaN^c vX7; 'Ϥ,4p0ﺚ/s}^=.0x]-\U'yĨ6mx?081a̿S5&w7ӫ(K7|0?P6ՄIOv_ic> 7QY5T/\-X~ Ҕefp )Xo .Dd&"7{̤Xzt,౧3yjm0Xz paEXg^}}xWex0S {zIL xgxm~mC r)E2N$8r#ykXb-oۯu!i:-2aXU2F lDdnOudб^E ']L=&OK_6tu;h;bO ^efE c"E/_ehؼk^UiMO ţ EPNTvmUUz^?S_MumU]88o":YŌ=S{s=<}|hm3SM[+Ӗ6/3$\w9x%?nѻ|{pvzMtfk|̌Hp牵iJ#y[/2MnO?/^|z<;k9wmC͔\SK 鯏ՔkHJNq=/msNkW(o[-G;ˣ~bco9ĢM!c{[ }T)n[&MۍI ϯgK=4mW\ ~c-ވfYҠ]#r@:z6dIfѵY \|" "4w$.g~>،?cƽX2| ҫf.B<kQǖr08(&H<=ۜv v jxqsy?x2m2M69MsOzywPp.Y?Ό7u"܈糩;c-Lǿ=5U^<YN}`ፚAſlfV Ȝ9^67HHUE$|.,xb# ;6AFE%Jީ}3\uc,Wp5A*0 eQbjmM!g:5.l1U`G<<$AɲhDZ!'|PW_p3 $CN rvY(ZʱhG$'vu]-})&Ay䙦iP 8Dòb;ϹJKS4`mfOù,TƧ8Jq_ i8h 5 )~si Z1h*KWIXsLAۚ $4uȰ^}/cR2B o e9I5~rgJ5Mf!w5#y.P.o-vxPQzT9掘2XͿѶP1eVЊ8-@;2_|y'n*P+e`mGĆR[;^fi.Ў.,2gq}RC]-WSV:/N!W-ŐHZ Χc~\;8)1D?5wsi b'/u3̕KC>SəCcid:chO:|qj<(F.yYczsfu}>1Dz8<ugx`Á0\LҔjWy84[)nGD QK\Ma?--j,L4~Ze>S[ɰN0( K7N㖤bBi+:Xb35PF/MbiDƥvtڜGw4k%r3֦߯ѫE0b3 m$xA4VW&u: TWӠkQz ߻#}|W@5c18yu;@ȁv ǮVzE 3\yL[/Ria) )FJB7C;T*4 2?ڟ]L47WJ@G-2h[JiWan(l6̛&eC `UgE p:je ,)iCsL{vȽ A!1-Ge5c9/mZ7KP@xUYRMx|=^lUQWAR1*]7zE !Tce=r(ƺ""DZ_zv'º-d]1%DV9ʽah:A;VFn5ud~FY묉,{ATG ?XayxB4qE3ϕ| w/N*x%b5Jþ?Xӛ;-�Hq,K}R#V'09uGz3DƔ-#dIN0[a>s@%}NcN4ZV5[aV̯_9En9KWKAǻiUIeH&pqL"1|9`k`.nr#5"SS+sOUogd]6&Z#+"0M"*#7E-YArj4=2oBlIʶNB`\1کKscY_sWeNzR%k=j6 oD \"i>5EP^aRj\拝3amݜ T%0Mj|XI| *9H[`PU,vE%7m0+S&XU$)4`X=_eR 2c~(87qiq:"逘لؖJ:fXF J)ԑr$oӏV1bmAXBl>$Q i8D3'+ Pp̉2g4'PoNdk>XX ol=,/w侧ҕJ7a>aNPx;3\(g Pt _䔓_Pl=d2' q&?|L$ZR* sn-Ȼan |y['G;l )r 5l . Tf 2 QܓMԆQIo`?j5LФKUm=R%B]t6L&Yl&x̟ +rX=zT:W 'O+ Ťq_7׶J~>TnVHd6Lp6G'|!ճ;~_b>]zCAKf@&?gwTmr(Z7Tt< eyҊ5Td;ܬΓË}cN8SǨH5}\uIE*W)]tiAVD*3+ ,^Cl$ph:sdh]YV \-ԖGYu:dCiYjl5cϝ RU'4TGj*"ma<#1_GvDpN5nb?qUpJEa9A>KNqL áSlDϰaǞF;NRYtvRϨ-;ay<pܩCuLķ֦<¼xhmCte3αhU N0 9}+r,Vf)R-fUKVI1u!},촤~VH*j@<ZiCs7Tz602@2M_U.rm|J|N-'dGT(^vue)˹;>X gB Qt:QA  ,N1+.JgvT7/2BMڤ(VFU J9AZćĤ9،wv02|rL?Bfq p?1R:MOsa@DʽȻ*|baggx Mt/+!p+qxuvݜmN &UOӕGzcю ;h%"1|. n[qk D7|愰T^"^pȘQ&xcFu6IU*}(򆗜u^`y7y _7䤔ߤ~Un+(Ȁ/IcB##:5|SIrb*Plk^!9dp5%"+G9cp`IŖD{ ORvGjOD%KE4/e&űy& A>78N2o-9zܿiLYZ.atpd~]ReBQRj WoRsrLrs8g"XFֽqOЄFflJK8/ZP`0H[(3p"5Y+X1jm?,&d b!^V}y`],r5LR-y6Ecw ɭ4kCm&@AqT J?D3BʯwJKL<;fqCe. :)TKd&7̝M25XS.XiTdԤ0m¡ǧPj&4SQ׿lЄ eًi=.hh,*sA[1qdg-]|XS=`[uٸV%3 Y}/l Zk@x34&I3+*tDRV |J+Da%wM (줼zS;OѵAК+.'SU$ft׀0x-/6\Z,{h{o8}u;5}"x/x$VG2XAօ Oy/(];B6U\c },#}ܹ(?gOHۜ?+@BƧѧW㸢rP:!4$&?bl '3M `)W_lK ~&=3SߒOL{`'} pyRyfʲ 1#KpXh}[D):o@("</d'xX[#'|ztɰ/O^C Q1sN'o>V}\oF \tł@I*c"fP mnL{Ky9|2Z烬Ðj:e,T|2+A| CD"H>pV/DKqWfwXx`PY5JH>%8FHpH7[Lh9{)F|/S zi-j>)'R!:>^ad;R:V2ڕ $yE)14b&:4mrߞlр_ :놶ql Q),(,f'li]N.p`kOh7Zs߸؍&wSP+_9E1)Ҙe,U|=@v?S]}uvjYWmzG,./Q 4k4s5tb0|9SsK 9MXM)G}{M#4rT$SLn-{oWGůE허/{篳O??.'cځcR8ezvָ0$m젾ٸwudyEtw^UamxׁvY^y3s} n<|Cn!D}:}60~l t3W,t'j櫣Uۖڳ*װ':[]Sxһx]d;S2~:ڻƷ M[w},voU®x?^+q٨L#U^[~93CӇuiٟ$ga}c%X ?F Og{WuikI&[f^~ɓ1lہÑ-$ɜ+H2Ie1W2W2|tx{[j 6nL;ά>-L:~=4/J?|>qorW#*cBfꃑy[=ا;&P&5V\e *Cp佔vkK30P* 3tQ4Fᡞ~[WW +>'&'gk^{ȝ;){Su I8P]%Cj3]r%Kk"v68&mzLLu7uWxv9Fnr[} QCcG# $ͽf^-nxEiW6˦_/_l{VPtZ>[/-_ΞO>@2<^_4w:7HBiDkskc'w;Ҁ'1%dlm`onHv6jd| A8`7_.a;8KMEN?Ja^!'KZj9sC'gcG:߁^( 0=30  8#d 9` Y)3#=#3= +3oZGӿKr '+N H .&@/ HR)'IXYمP0 pq30 ;x;X?_)W`GE~_ l"sC~C! sг 0N6i 0=0=#;s)RNw 6K!,*,&,*&Rr3o +ȿS\UB/(L/[ߣU4iOWAE̬Bll BGM^kOW hQg`ϔYCHCQUߵU=)op`/m{`aacabf٢'<H7.(($$*)"ԿP|Tg=ҿP;OLG_+`XVog)ggӪV789u RoFz'' 6¦3J2 diMl li_)K;\imL323^3eL L lo33~@@Od@@o=GsCGc;Jk~gw|Y5ѹ;;8&S};uج/l̿2̷G[,֟UVB\Xw{I>$;`@s1`Cp4rHΤ Df@2X@h`D8ԖHT4`ZQD\̩%8%d8%%!- eee%}T  eLKGkwg[7774N_P40X|hx&*DNr&TVBD)#!!8q J'@Y#aam[O(Lx2:* xXx:&tJ8y4CYzCa4~jq8af{=6p(&rD:Vp XjB>i.EUrSckL2ړj J 6gzxI-)Wt+ ly$c*AV QMV5ab?wmS &kNg}v#5-!ͩ5ama$=rTজ'\PH ]CBۂ;CXɳCʕR#:ҍrSB_ :H#ǝ\//᧢)jgs)(ޫ R'R,g~>ݵ.,̑M_ u:br_ ]8K+wt/j+z2z+XƧ3_\e\^Rȹd~P}&s}r0:<'&||\EAu7⇿t/^!~}zi{42bafIx@ 'dŹIȁ |yG'uvJd>nǎ`>:F48Z;&+Ƙ__DvTJo\.r"1 =Er$=4`JІg | rqא^`(xbUA ^X '[Qb[J ȫS< ۗt81M%vE.{sz|M: @y@<;CstfyPD_8ecJW]G'3w HJ<㞲zYSsvZ1S)7o/|/_R{z$@dc +[NBXPV@TƃvMsos[/׆s^R:5QߟpߒT< ;`V]*ۨNaQa\TG-')4/,Y20Z5 Qn0lJ^qzᵠdֈr"KQ%aƢ?XL\sٮ"K0w9B6](0ڗvQnij*rXd Bt`?7G Zwzu=LY(ITYIm\ېI4A^tZ Q9 aI8DQN6@?bI}TVRpM̮_S3S4DSrʈ²ՙ]p4H3*vE@_IyAPʈXV,kO[v~. 㾖#AhB ee VFQY1E9 %eF\Pc h&ٍ:<[9hqo#f73~gk)@G9}G`eA:$(bJDg~`o7}l |yނ0/vŊfa'W:_ iE)ӻM kc }o,'Sn!#Zgn"A4ۏ}Bbq.\JH/FҦÝv:A]7EN%bzJLOrh70MCcu =_ "LErqE7fʾ9ce":obE6v\v8`lwcNmu .`>-4bGWj6DFiA?MKqzT~c{*/F~a?Rǥ?HS7uJCG{oߝ 8C92GοotFݾВ./<BCb!n2F$50 0KTQ^})L$̫y])ʆ>a͠V^VYz< Q cs-)\L;F$/ɷ<TWԒv+lމ#et ŝ2B;t,KvROpsQ֡}dLI yȞQgByt,L a΃9lE HDa&pr!{ô}a;b r yQ?]5hfHzwԓ׵X"@դ]2SUT|36,f'b c,^pF:)aAI_w}ډ?ysQsQA-+@&@$/bQ!a#n2(sPځ-? ҆wX77g/Q~M܎OZp@G aMPXh*EEƩ,><aR>{@ueh@i4vњNGyQčřgLyXƈ8gՈ !g(bj42F925zߴQᅨ y2E KJ'wiۏIJAd2!axY\1_etb\ ѻQ(ħ,$aBKPn8&QO,m>֙68B"mȹcYBʳ5xwSv0~:s>wj>cNAˑ5߆%:#|&ϖh" s N, JFR=xo"[ߨ%%XE"#z̳@|.&M~D E5?: xb0{+lɦeaϫx= 5~Šm#`yq*S&ҷH";\&AFطyR!8帮L=_>Mq΀͈ 5RgHQ6rכP_:Bf';EjoC}w0n nŽ*StAO}բ#eeչ1u1s++㩥0Z+!._ Φɗ+W7Ɏҵ zI271$w($ F+ 9қ.ūn"it]daIu*;RcȆk;HǏ׹w{>o| |w_ ]&_G|;|>bzL__7!ݟ_|/17S2Õayr1U=AA)]|_!t,u*mAJ-5tb:0"!ytk >- |J 't0U5$u%n[T,GbBԹ?] Q&07P8 їf΄< I^UT}%%~!:$齕1?b$#9/00*b(Sj&׉ÃOu"1NB naqA1cMD&%L2Tj7R0iZ_;4Xh`=.k }9~LD|4Ɵ8Gez:ZC@#n\%@fBD2 z珶r$ӗaܴR\TRw,"i{:P~3pJD[4UЖ/mOݩmٕ[Q8C*@+B1"2"Z&ac)\5srH*ֹͮ%)/@o=\C3=E69ͻ 7ϋ]3&Ήm!~W9GBlt0&wҤ0ލ6iK$b@t[谂:dX R>{V3mx`} #!𦑵_$21G5ɁE?aR_=䁹A83;#M珤uZ)[ղFjPXӂ9vw1g䄺SԫܳM Fa Ե&4L8ə LǡMLaY,"Ar`WQ-82+3QSGŒm&fo}<[PMaY!ׅ͆`1MNJclE (9-e0&bB_tG}4=\N61WS!B>`+6d$FR8i,T@Y4k49t)}.M S#0M%V 5vĎNRF4 yaw썒HxC0e@8DqkY& [|r(*_uUdޠl㑄:=*_C ߍ+:F5ay(z@ٲ{Eߨ_$}b%,媌}Uߤf5I\DB"n`Uq-@O1)4bm=P7zJ)H,%|2SaeFyB^x;;/?tgH>a&*¦ ̨u' \ռ5YxVE{΍9=pP6EEb7FH2OV03Ӏݱ)YfH֭=uw Z+qzDQZͱ:;>]6 }\VUu.VNJae]4 ߽@@_w މ^ECh30Zw> k#kv"N9*X0@g'HI1 a)q;O#yyp>,~8ʼh1[f)G_ H$'(*LY*,ӖsSp,C*VV]QP~ȟfٶZe,ռݡ##N3rH {LΔ} WXab EKX#?a{i5vRV>nx~v_YC#> v/f0iNaj K:!h D&Mnx o"ijH" Gzd5n9P~%@gB<L5X_όDdװ!LSϴ5t&PbS{҃;ck%ӴJ4wV&{aTԆbGTw4V fj"KDQC&Iމ"+$,~=˻_3*VZ1bbg}D)BE#růAdC3=>f``hQ4 '(fJ(.K9a‚wO>ܸgGbe""k,( Mt}mO[5@ea3!bvA748W!󦘛zaz7 mƁ, ]A$j'+K H@qYC{ ȳ}S$Ò`oFG~k`✓& ܷ &&بVBgFqOx%-t[/N<#~ &Y=xQ­ m$ly"ʧCT'7נ>!8׿l!M3rh^j5ҙWŅe'e@OmL 2TJ ,SaqQT&#uUiRFA5 Hy2j*%]MP"{]Kf0vܽm^ '󓻺вY#FzJ1Rr66e[Փ-ŸQ?4erqSIܻ$L+96}x$IA'SoȗC6Z l>h/w:s;M˄q-LU] XZ*cfn{ >n#r.SUeȶϐPe`Vٙ=ݍ"8m0*8Bs\ J00/BrpڠƣQHlIrhKnqz16DT9߶ Wzf,+st+)˛em @e\'{\2ƣk et0K2&&R&۔X}ʓx.WVѓȃKv=g |tESyq%ӳC6oAU;vÇrbϐX%\RE}Dkmg{:8J b73;{`~ӄo{~&h@ck: M}\̈Y2o -+wm`dtdi˰r&AlgauGbpƕ58UKL5Z7k36na3!KTٙ0{B'5ʬv-KFA(-ٹވFiT,¼zx 5 *!z ç P#qDtAGqEןp@c#YP1d$h{#_8NyC0 7$g(S@^4DVg ۻ4E 3vt?.c1Jdbw$mh@̂w(AiwbS Ӟ8 @C=7-ژi>cO2y1mebx)ZqQΜGXrH@a^Rr|%Lo`*3$ ԍ^Gl5iii%o2vCj78Hg|#Ef`Sn&6X!jv 1:xsn/YkƤ8ёt/V gE{՘?YS)aIw/žU7kv]]4EUA?QKm$U"Xr5q}[E\ aY_(Se>C&646XqE3-g!|ih/ Z"ֺ%!O*-5R8kT8:hί։vazx̨.Ĉ:}e0sD:koq8  ;K(S hy88o5w~܉ʒPsuyKGbt>D~C ,aشh_|"em QhC*x=PQ, UƊiZpp.fZu/ԆNuv v;i0NׇȌG46- 2H,bӊ [Ƙz3?kƸTH ?-h L_*#h#eie Ӵh+6O~>~s.͋-W6][0v0gjk|iaےT \b ׸<: "\PL1jUzÏg꽧4(}1-&34Mbh\8| $ er 0'_o{[Uof2=c1xKRbA2P"Ў%'B3>IBIؔś;C3 6&potH G_]׻sjODt+`%++Kko0뢥8GVd6<-ǂQ֐lXL' >ArώO7=`%.| BMMMUUɕͼ KKsKkP;u:.7-} ii Ld+ aA w\/./mi/_{; ~l޸3f½%Q e2v:Wi_73zݶi`y6PL/m4ܮ:\:h]|8 LނX ~yuruxtqTYi cdwwp5Ⱥ9΋HI*{t|KyA|Ljf3긪>Ou^7l^ t_><'4͠iyo4:n:zk4m;//6k{;;\V]/O=Kl߯6==\>]k`Oy:=_CH 瞬E\ўPM%c'J9y"%/,1R/$2DPi:O=Z0p{ s] >  lAi&\z5Gef_.q#tB8G 4~-}b3o}~:ȏc|⺭5/Gܒհ꺤6aoqA8+iݮTӮ([holYW"ez.󸀟 I%iiB.N{#DWo3Nl' (~Ce۶㩽sD($ 6y&QR5 GyI ЉMVx GNg:=0י&/Qp< ?t]?p<ɯx^Տm*vnv{2:zd4Nwo,x[M.b# /f\eVtBqiʎFΔW˕:m:Z 3Kڭ&,^5MR ?LI'ETMc!٪lHi}Chq5[yq@WAltp7oL-WZZ>TEn?ZfJpL۝Of}ԅ%;<дTz!L02W=Rr+cT+7X&:^dm[U\RVwܶMb)^]Z4"<2`%Wn Ʀ"rzON  Qـ՚Y EU4wؿG3.7%m-FcϠkbQܼ/c\yңt8#i$k\z0}[gm}:hsq'fob}|FVS|iii瀭oyC;w@ہOofMۺ,m7nF.y>^gԜ\%ٖ>gK'[>~]þhٹ+. x[atj`Bb~̔h^65au |OHiW\)YqWAql GpͯH Lnعq&'m5ˏK wϯ/[7ތ/7mBc8RQ.S>bgpMhعuo !W䚏W7QMه+ᷔ9I΅}B`aU<.*[ݶlhmhk Atnl^7y7HՔ:4oTRQ> ݌|s (_6#о3C$nT ]an -%J3$$o+*{nئ }Vt.KStFк{j/#+܈h_aI(VւQX>5L~4@FfE(EwP(f5aB 2\k y !9=uCMkVq] _LGY5d mWʵz.9@~;~ibY`b*$wm]R'#8Nlكs61?F3ɤ>rWIĩȏoJ.aNٹ|& vJ*qg@UuE5@=庈nAy) ʚW z~`6MJZ!*cI!Vu2$!7]B^W"e>#se/ =jIBDFJPF,!]ӟlM m=V&vX#F598}I~WNi!FR8ڧ?zSгy澇+rqpKdVrbiKǼϑ)D#..{~ KGfF foU*L\>5دڪEG7]֞Qy$j, RLY/u.`x|0:2h.ӇK=P*xJ~o\̻^a9qԤס݊I#2&pJlLƥT= )  ތ$ ud/VIx`$%Z*[)^HrnmӠ/G9X583PoQ~B 92EaAPU0Ǖ.3dhSO`Me2 Hrը{R6RО8<qj"TH(] Cؓg8XahgC"4?m]*( >/zNTj\"Ap,ڽESskCecs%Nl StY<ܒã7;>y_^7 ٬UjΈ"Ӎ&D?%Kug]ɾ+'w$ COasE1ŭs\81OQwUHg#WdV$HI ։ i.|HcWz`8PR ,o}@1 (u*sbY| So#A HE9hv7mˣP>vbH*N[Wh@$k:Ŋ'P8T~k({fLl\G '"mq!hHS]N9Djr O֑Bu}VZw3LvVCz} bw0Kp)mLO7hb3؈||;bjwj4v ]~a9g ?,@:&Ji=zZUFl;n\aSIzmD =T&)d*UCe( QR ky7T죶Q-C^Frr-\yC^9{U:kE axhUkhިC O冘%s :5 *js⟳CB#eagcgfgbfoLD? N DfЇ"jl+3.3pER]RLMF eo {nboSUNίTo@D+iidk @ W@āF;ڧf2=lwxz?"|m _@?NZ[7VРXU$tAA9#E9qp+((H˵ bTe)J3zeD*q@xF>\ө|%CۚåF˃n8N?`?xo;;KUDnp ,g|-(NVLs5rQXQ{tv4}uٚ^- 3vʌF J@[De7?yј`2?*|u|u`bA8i, |J5n ٖN ro5QQI4d\&O:޻zB-b8XZQf_M&;|Q4&R:uHگ,b(RWp02?n+:c\hn(Yk{`]5"Wx\u띒Oc24##AZzK@DI)NōEg٬I̴B PœFGMf-i((P0T{xϗTYøVQL7(mȀ ]s9&Px QɻmG|sto/F{u%zױ?P4*{B%05-ZLBs7fwEf0b_nSpMđI|7[؅om R"pb@5OHyY ͵C]y{(orj,[Q"`k̵+;+uFW(-wnpKc*v7| N":gWlꪃ%ydIӭLQ9C8 Z?H9'/j-_/]U2~VZT >Dz; #4)B?/%O/ S)' ޹[riB׽4k7%,ǃH`~(gfLmfǃ{y/'<_fAyuI?ǡ1F۾=_g06aZFvx<ԍB o͐IZcT\֙ݦb f$3,(\.ZA?#h1<˥Zk805'X7\i:ŦΠ!ڛl(i-fd}^e켲7 .۫b7rrU}Hwʦa+:.+7{r.e7O$`Y# !_j#w(c~*桓!N` F,:YWQ@WL`-ӝ Z??MFVZcEB' fyW6{GĘa7@̤IOӝ%ZC'( fO`^wrM]]tzZAEB3Ҿn@]w#Q-jFx)l:lfCg2reD''Jpqq*OG"paB`TyfRNrg`i=K]HDhpxq,\GvղoC"CS i`msNݎ edhu{{XQֳ>aǥ҃^&BA h{w#l,Y7)߬ng.|m53ɵDQC46BEoA 'oL)̐&c~ ,N8Ny-]F jsvmhsO2 SLyG 5-q=F2'Ԇ?0>&'hrj+%V4 oHsZlkpd b Itچ1z4k"CLSOH+-ܰcXT7D[X͡O=#rʂoNECWSC܈bױSEyηՓ61 .Z)"ТhX{".T(كc^4YWlY0Ɓ#BKlyw6x^eeWϺMG ԤqbBֱϷO 3 C" wp &-bW?[d?2z{pY=>mR:̰p4DFUc CcJ)rI XTLrBa}]5cl{/L9Ko֩'C=MA軩@zfF1 &X< Cѱn }B|ɍ gI)6IzJtpB81Hca.ؐT5ҐW Rё@(553333333335333ÚyII+[RT UR3Dn,PB,)ӗ/N(Ǯ^HC3~+&^>_HL\z xDE'(ҁisXsz 5]%sdkOR*nV$hnDNF=|:[Δ#nDB %L-(4nY\HfޚI=ܩӍc!B~f5pl.(- wD :VP$?&eԟ+$)ƟA:,>9{Fx6 AKShN )TXM!((Kr90-v։uٖK>° ,R"aAn Y]zYڴ^nбB1풩i:jl?i&܁-A(Z+B#, , TҘgVSs19ujK@{D-E(pP+ֶ9; Ӓ pI? O_+bVIR>cl>U}.q-wW DbLt?|$2 Sx=S1+8a{cYj2ԏv*̠z>cP2ɬ,RF]m}dRMP=Q8VN2J%Q|"O|3v Bd%_ɚ}ӊ~fg[COƑyfIͶի[pM9QY2R&;'Xn:~!*&%~sx6q2Mնn8Q 7 MppkLgiC}a4 ?Հ\QXFى2c!7FcA:0Տ p7?vLk+|i'l* 1Xz=ВZQ4CZ\-8oMx՜/! .l%ڄ45Ԥb#DOUػvnBY L+=O )rBS9CXYVT^}}m|1ן˝(UmxpOY\}~n%uq^ YwiHAWnqYx 5,{h^5 .ޱF+>im,y ~;)z6 0 Nqn,&tz+wϼ#dYDX/6g_>l՜_V˝uN F0a-?b;DiXלotw K M#I@vL@ fv-y1]SB5j2sE{<,mqbXܹ0 D\)ߔ!j/M1S$s Z~f68qM/E(ҨL+n*wxێc"tM .< LgFMtfo Mϣ_=&.cC@ %"(3 DU#I3DM'{g݅4V'#qyoZ0 /9X,PbJaGlf,!^dhbYΛA7$Ժ~fX (^OQL)z!GѶu\jwF;fxwn f{>I AwXնsl5c)koCZ&Ct(te4ywAiLk|46JKXT+IQ8T)=zan! E)ߓܓ̛8^j:Ji jī&)l1&6 }ma?L0PD$Xl&4K&V뮛vQ3Uqa!&Ő4.\oqۜ*tYyp#hegd+g lLj_Otf;:@ F36nM-10i(;ՙ Bw\}>u;&aVQ?,s7gJ^ՠX*4eK\ ]sDaDbVzMY [ ̣y{\b[-2-q!gR3PlxnjC (L$ .aQ7k4rcBmmϛ:ȯ :%LX|߽ wDA!IQ\0H͠Z׶˴9w5|[]4Mc"ڜFk'@nd0ɾ8ܩ4' e6pQbuϧe_o/+E0^yjl 8ߓ؛[@n2}m2봿0sjUN2Sw*-'VzZ3lRg~˸̗X DmuW9-HN}/ɿ1 rAgGPs3G1V n*"9,D6g = ԏܢ'LsFLHsDrQS|" `$:˿vW 'xwX9Pȵ(}ċNIDY+SH{?0$ɼ"v8kQuu )(J@szW\xyb 69@QՓb|mPB36//mnP0X;Z k9}r/W$mwui.晏&]221SN 6_JQdL,7A]Z,0Dd㧢Llv:A9a|㣠_A>^, Gc_fĨ-XYNDXRCY4;\}Fql Pmj"*-$^6ws<ۯ^D*Q_N3Tt0' i?ΗNUJ]puvo481|cP͆zZНwqYYÐJ1x ^^=!q7*i~s{ofbx/b;@itaĊ<->ujmϿ ;MnF(A'i{6=; !aonfbVJ D16˾eK+֟>ws@GGwuk'-QʚRŃzBhV:K$x\hr ڛ]sB}"黑S*vDc}U)ܿIwZ'N/99:cBF+1k.lՈ\mv{մrfkL<3YzdCL@~vwI"TUMQ񹕒јL~@6N2'=\W6?*MIJ2fn?CվG#$ Z_(?—Ce( K{@B_@9!o?KS%IYEE~fHY0a8(̍n=eAH`tWF$X'%bDG^%+%,f^ <e6C{E̸:d{- bv- d N]ߠbV(C/Z|J_N,59He68<P#'6$]z|dQf0yI FlkܢXH 0HQ42"4- !#j `]-y"T`PfIZIYR"N$ #Dehh_N&lYbUhkm&DY, aDZ $.#~Qs7&4DZQI&z#aFG ((F&rCax*!ҫc&Q&ċ6{"/7="k4]A+:\#5ʰgS2aڬM] 1S$^CG]vm6A/Ry?S/d|z=*EondXFg,B9+_Pl+{)5wWs FzFtTJH:dv ?!qPnmZY%Rֽ+Z 6H3YtQgO326VZlۮx8<&C'6p`G<9?^3U[nԵ|o﹮7tlyO|¿F麏ux]EVFP@9if.?ݏgaᨐ_u:uyۼdy޸DXu6~"@'z}z( Vn%[ QM>>yL˷#Nk5nrz u!TbZ#3K9#gy*uTe;<܁ii}Ys)6p[>}KN@ #-tj_m~e-:'G1yW],O\B jCeuZ{-_BM_Bi*C{O!}mL.U Ij=?hf`!؅Y6fQzzvXTÖ@1t%ʡc$!H)n̉gYmf̭3BN^qqsrYYzRbȘ,9Ro^:yKaB񥤃nnOkv׵pxᤕyi82'FRxPXί469L=x9qCI ;u@&&Nnf_Iz>Utt#Lɉ)5nIiǬesjuz(v)yaoN~K=} UO:0ؒ/ˬu~PBk~tp ˜ִn eҐu:<+zv%YxYۑ|Dc+,ᡰ;,ȩlŤ\,:C[_ܢf>Wm;~,=>$㒂,[PmOYmI":wAЧϙan~D2l9D5aϝ:q4H|qD2jg2d"^9x.Il~j\j>10RmJfĪؕ|SŃݼqӺґllQ*.}wM&=R̈́IDNʃʝchajXٹAI} UQWw+ UblYZL~ItKqR$Iqf [ܬCx |Jqb?Dg4O?'W@L`s`ds aQ*%]n))xRPs]vr=C q$(N}ILB4~Ď#Du5m/I:s̚,~q>G- ؍bvVk]>905`pˑ_ LkؔTY'!Z8+L4NfЍ 4WY49|H\>B6'B9!mUni'v5DԱATr'a˸qk]njeBݳL*R\5$⇗)*Q1>CZ}2nFTA06mմs+AϧHU(G6V8֩q\p(VOm$8<1+k:,} u^J_+&k,_[+SQv> YkT4Oꇬ#3] >hIFJ` LT+?>o~0K>pCgҷr=/x/,ɋ^FT'B@}&t'%6lv= K*cJ~ @O;DR9^I ;㊒j>ԤUajLJڍh`R% .|d(.d] /`BlR^("ysvf)-iҕE[a&93]*<}KaVͪ/U K*w{}Os0Kخ2Ye6^uxɉ])@/=fZ<v2rm IhWÖa&$lC5jݷ-]sٳ㋎Lb$w+z?pttl4>GJhEk,?QW0nɲ辖$;iDi* h2OjMIt,-6#. ᒅDJX87z)XR)r[.gavдZa /gGK nTM)e!nHC"ceaHH'%،QPҀ(%GQq. rr )+5B=s a?A1ej'5"Ȇf0Q @ B ! )f )~Ҁ) ).XPQ:|\g7%DZЇV0`Vc4E>!.A#3,~)(5}UǬ_\nVZG5BbĎFMAMIOnX[bDUX%F.vN9Yiq%R_5V公`bhp g<#6DiI->t-Zƣ&qt m֡C e2g XC~+W~*@}[FbWMy3b=Ӳ ű;) Ȑ.aؿwYc`ﴎ}: j1 &nQº, A+y5Ia~+;^Ee@ǰ%pfQjMxxs6 c̳%PL 0Ɇq}lyd Kx7ouώ˅D4K. SjC)=|啎>=ަܷŒXp#|pM}/5jXn!EeٰrDwCp *!\Y<0 vP|3\FB.ɱ|,_&T8hxlHPWq’ˍ3<'AQXNpqWMboh֪Y)dQ0Wzo,go&t6۟Gs7GEK(T!Jel$e[(e@,aGb}*z*NJ tJEt>,CS)Kok(U͋E6M\ X>bsj𚣿XfXry?l܇,%ᶗ;##5IN}Ntq>ѿy@%7#?Q YMG =Qs 0 ;O(3AG^= 1h!\?2#S08Ҭ70a@Ҭbԅrg*:I^%n\o^Og~*.x.@dH$$$$YIHH2D$O 嫻ٶL1qfy 1 ]dP!5?S|8bmUi $'cٺaW﩯UƎG|^bGahC]bxɉNR5T(1ɯ FhGS֔ {fgy%H<g/e6v-פz S*2]S9^Ixu~p5\G:|@VMU6r \p1YlX^XuG~qGl (%L7z=zM+&d32Kn~Pc䡈 #:lnJ& W*:[4p+Ŧ>W!OY8ml&[K<{؝ 7_vW{ӌ[rod7so2IZȩUFWG%̟C*7bom<ɂsg6cp!M/.5 yf^y86hEYQJy%uc;)[9Dz}pBK6wߋi̚k mvMkh‰ؼ|7=˿8W 2Pt}[SLlFEHB-蟱m\ms]=٢(tS)fP?iLة'-lgS2qKm ]KzSnG|y<?_7]`n fGMcȞd4YC`Rϊ 6=2Cj5@O H=dž~!,,Zx}kcwʃ)1^O<_mcr'}@1" Yz٬C rJ!;(NRc]v?er{_ Ew#Y[,7?B`]˚u7rf^m|mp7a@na1CG }W۪$~z0J܍C`hu>u3s\::IXvWi`':ʏZ_^Тl1Fqg]$cF^Tq[/ͅRw5dkZYx#Cϳ ;*"2zyCA8m&`,qܛmtN's_e/0nCDL#r7(Fkbd}]NXN˘ܯ#EqW K\sԨ\>-4݉U[!حr@Cdp3ص=Uz#O9*Sp4QvzFe_ ˛j1.@)0?QkGb'޳224bӌd_7&b`" HsL joMت}mяsDRV9#xt\c^~=`O}Nmy!lI"}Ey[<@Wgi(C(BAfNO$~Ã@`"xg輚 92da9{dc>AX7g EK"4/oX⺍8Xd5vCxIq1J$^B,Q[.&[ӝ`Đ =%E^$_ h Y57?>2|a˛: SϻXGCb<ĝY*b4:qVrp/UEQHfiqNA*\J0 P"s⹭uv<ȑ4&ŖJ~iM`R-˝A,^W!-KF*{Miț?f kŽ|Jxlt^'Gy^ HsN#&n"ngv$@^Fjl Lb[ `$45ZqiWM7&u'8YO ѝ8y& r ogh'IïCD${D>j8 'g\7|,p2!I?;g{w&%mM,X+N#C9a@.*6_y*ng,Eb];@ϝI U0e` _uusb[”[OuvPP!D` :" 8ݔñA1Jkl4덞ˉP0~<ālEzSf: ENF‰LjYC /+\9 2$`}}z"BjS?sONa?SkE t%1nШ ϫd`>. "B&46*ڞ`R6bc^08@S0lFЕa̍Pr.sEmZ%M,/:c6T @K%zd]B?J>끧LuCiCúF*"ApT`$~"V2駘JԠ?b$o'Q\ ?SfǖU} @$ UtANԱ Vsgfm!rY}٫̀}.hMҜ*Ȧ+UV(4vݭ:묨XN P!VTE=CWr]so׺[doa#FgVG鬷b?+W;j +)iLV4nqU}pH1DeY12-HMX_A^-ZKGK7CU~^T੷YC8 c3&)BN&_u)}OL`Ldڟ0S[f?y_oWu|?[]l;M93,s2vF+lE[reg3e^cCn+*'.jUKmR>!knټkHܖe؄DB5Uo؝o'~Oe!C߉Z~QqkFCDF2[.l8?hH´島9׉jû-fYyթM 5фV~f~֑bڹŒK˚}~o6Kk>Yʃ#JlzŽlf}zuhFUÛKP['͝#b)s{m {nj[hC[!<.!mݨ-B&WtOVN/rB!!~7P:\nqfOQ;JgJ%Xn ƀM)'.,BIDx_mn5\ Qr57ϮճK-eSe{loeeWխjίc߱FqS;+BNU<@a}K=%ÑF8. ) Q橰-N?wfi?19t4#A; C6Я8;3%-4 ҁS!#sEi;q2^0|ytE$nJ;VyN}]| XVZ0n޹ID5O̯4Lu fkH(*?(?ں 'ZQ!"2q (V^pTh U9) Fxz2'R'97=M1GOEWwX5!.DpT=v-v%#U?)>Y/%uqa|Ɲ#0Z (:35qh gD PMZ݌_0*U̓-A/\ڳQ8~OB,4!,mQAX|g8YD ַ ӽg%!k5D `3lY&v=GfЭԻ(Ue阶BWu5lOe z Y@2` "Z.u'bSszAXXB,qIMʰJ杂kR =)s̖R_DC`P!浊s+rnu]؝Aa? WBX鞲Uŋ2NH+O,?} q1\ÛzIqWoǶCNu?8ir{PhLAh}g@B!2,n 76 ǡ-^ӺJ1UH&`t~)a{bm;QsvFI\&ϣg`yNgV#gDjs+D%ᬎjDӇTqD ZfK xEG=9mpu2yΔqdz9ۍ63fxDIIiVDȁ*~nhf03R0ׂE0+\ ,inv&8>ar.DmNj90ծJ 1X#%J"\c=Cǒבw>`+C"#XQ5P!3v7xnHj L`. }މN,)q`jXb˿0:5/OUV%L@HlfU!QL3[Ų؏i@*ex70"9_{ Wҷب3:/hv"rrE|n;L xɷHC¦¦_G<·z3~=`|j{_̵apbyfutbV:/vUd<,G52Hq4 ZRn&N3EFGrQ8񚕻(c(嚶 0xN_$7%@[`39e#c5eXSI# $J-MUPBG``4@Hۣc2f[^:`O6#_|0k--iS3 r(eyyIvtfȨpVp62"G DEQ3c ݿkbϲy H/RZ3زyȓӰ(Ot97Z01q* BÎ" T5MQ SCkZMd;K<:C/pjι'% !?ڸ)"# qSDkFE%743x6b9z:n<^(X61DrKDŽ89psK"KY vO_uϑeN&D5mvOܞcsUi¾ .1$kl ݟG) D!Ss:]<z*nԑhƖk04ْ̨x/?r?~j]s]4{'h{N{|%v.QZ}vqy0_6ꎡ;C3Qiq75I[9_9ߚ٫4utka35b5{|_{G/ܲn̓`a<y#lP Z\[u&rG4r60΃op$mXz O\R^횺\j{ z隱ZvB" uш%oi&LփTplJ6 L;ov&wnuO4jz \MO ]3M$V+#H#FtvmKaO4bF\n$~NJ+8j):2k½5lz<^>S?KXq7I;6IS;ubPki}.p AD;>Eri &DB-_cȍj!;nbw?JZQ1h.zara=Zy=;)Ϡ0i$߻WFMGT4$%5Wׁ%EAeЧe΁d bv(T-GO^ư&˲nBxFþE)؏p`Fq m)C:Hr9H.1#'e:fU&r:@//;H#Tc[ȳv7útGH8bR2OȄ#fhR#H &$N7l`%79XKAT%vZ C$ cH+OHwI-IIdH1q=7N~iT=T"f+-[_IE) -1r6,_yUk`˟֎Mpc]07hLZGP; VؑG3 +VX*<N& #'C&52׆Е=AA!>APS~7+{ܙJZh&.X=7rG͋3Uak͛z9#/+ ֩ L$7Xbsw)j-eIeUܙtΘ%$quTf_%р5Z-k05yry#M>בP1MfEE:?Ev'17Mnio2R5 FH0d:UQSYJWq@KW\աq@ZHF'O-u~d~;QjFzLǞGIYL>.Dy=GBp$ZG/:OƟQ(a#Iwow "ω柫˻v^kPi>eٚ)D[z;ɉ3eK4ʜ$ǕFq:8>V[yڮs u4sv>%)]VbNsivRCKδ~IςK~T*`ʨ_V8"=ywz|1ױϮ|V "$ lT~N>KQc2Z6c#|]*@ vH/\|+8 S4C%W= (|`'2aFT `E|b ~;킼Ҥ\`7`E tohN#R-T@9 !˙ɃE)ud6 ]̟/F6sBWyqίpsmoܢƀ'YƏq?u+Sh_ ["aS|ăُWDg+{RU)reNNg^ӄ7ɱ ># <*^؝TNRʵY/hZJŁLn&g(X9QA"g9՚M)ZU)kJ4 d!}7|u{ҰTzf`)5'/;|F%X?3 ӏ:&,T~b}>en拱 dt~eɁOm7tĪ޺*AMAF%Κ^QUgMьedKDvQFTg^,{]2 B5J6_o/4m*0I3#׃*rwR,2YrEu]ߊ Hgc>HQIf 8FP9EMH߼+qkPʎ)MAfNW]z`F:#!{1nm\kE!]q>`(9Pe^DYn%VuF?kYs`=gsmn#o}+n;?Vm͊:5q|Q뱴Z9{}{2/ <`:gJ>}Ae&s~T{fgVb jZ a,z`=h~ Jէ[!}R/]paNA ގɬ`5J[?2./qfj~nxahe\Tw"連~|;Oy/YiW=Na3Jvڭr*oP],Et1Fg5in,S}[[p}+ LZ':xʨ i:405C.Q,3 K^WIUM(Q}Oݮ qosof0&i|OQ\y*%(2A =r 6)@+Cة+dBvb=G+rìn/ŸAղx@,_PyA3o!SBe gbSY=ϥi$/-gb]M D BQ6]a(_/1^)A5aiFZQ5]qT p4Ox; Y f*SW;qW ;Tъ4'{^<[P;JBԊ[PgƎK-Šﴥ+Ě_zk3Ce斡+QeMJ1 bPŰ驦@Rɣںf$gRJ|/KW:kBP$:Fh00I݊DV٤hdܔ(Ёa"#LB}\5grL ԑZiz*0fѦhвdnjQECY54nʶqaEw댛cmTaVnm1ύ'<ݟlek;Sxۇ]{$uvOj螜\<-͏-ޑ'ףmɵǵfow5LE5Mˋe /Ńu5`DFƁtsywЬRHZOo3{V2 GvMv ce`xMTEC%bbT˗QŘZgrdFc2dFf/:KZ PN썒> [C܀>cF8qR<_cZ>9))Mksa*{6[9u?{r`5NwGaA_Z2*o]~K':JGfQ' 3NRk#XN/ Pl&+6NQ08 .N*6L%r?4u(_^.u]읷AwT Q5`!)7'-}U(n92.5n3T^ Gqyg.uA-N2BN9 R~EJ<əfCQи35h+B/C@FH%4676NGz[zs*f\S}k[LgyJAڋCS4FbEU pZGM:Áw̕#Ơi-3ahL2hjn@FJBaU"0=FTVNN|7F X(feiטD7N^~jR[g?QN(ŃL:/-, }L,mэ{Ϸ!Ff i%w~D7EFR_gd!뭊sS1ohXܑ?{ɪxNӤ: %)S޾NwO )ܘIjRCi669mI#JC6߃,+Cgas3n4I3#]i 8N'Ƭ*( dw,0t0YTP3Y?p)3jH1zk2ɯ1VLD"&c2v>eD tƄDQƌ<}Rܐ,([V&/^1bbb N#% DDaず  'HA'_^ ?0 Wy B/CI/q(UIIτmXsE @WEҢތ~gbm%sߙm3 >DȈgXml:ld`L~[$8go8Uɡvf<@~7\x3 kAF̙OZM~3Ó? ;Mޫ|uӦ0N`NG*lYw6_ddri:;dT"л2Q 0ԇ<n '17̱!1aJ(a|}Ν8B89Gg´'i+tmӆKo=0Bb&+lGA̸N}e Is #b]? 2e̋HaaЛ3"ek˜8d2go2aP`\MYdX3?=h۲ >ڸ7sN,5)WK|p(4'i"I׮Iԩ)>VkÍJPN!+C?C/ę{a{;b#nIPI*Qd|Ӛ |0YSz<F-SW|48ck_A+NOM/x^#|R:]ANy04! ޜr$Nm R5`L+.~0kO/951Yx=n*5gddh02;za3jJ>27m%T2kW4Tr؎tP↌L-:8G fG#I>$\IKU 9\nI]D-$c FB6;ZDRpMت3m44NȢ!5C$q7 cʒL`b4ŚɿB%@pzuIs歶5z37' DhKAS0K@b)2'T_5x4YjI~EE0շ ˛”[ޙ'vPrtq;3Jk(3i)?I`R})'C0A1*kOЗ'e2XPd.)*(L:gS|]%deD@ΌvQ}ʒՆ(?*.0P+V ^Kg( 'i좊:E#X]uha 8gusx;Z6aAPO۲@^kSw\ċ+,t9W!7uMGҼVөu?mcLgR܆mvb荰, ᩻|@v2>kmikRY )cRI;|7j"R?r4M;nK&-DWis > 84xHq⳿M[kJ<ܕ9eDfY=2YZ*P#>>B2Q} ?vֆ8ұl: ZZ{VEȁ?D!b'ړ8aHWVva<$ŸCB=jH| .جM@celZރ쨘FE)7j2\89Ձ% ߁Q,ZoodX[ibUXzEG$>Xw-ǽNsQcPYf"xH>wLN&hͮp7ur5"UwBxMVED=8 qVO|ħ 8;#NOwsKr[rIչ)%ZvCeN%Y bVF>ayfw:[q 6H1 ݁45MFι@!b[G\aЀ27Zc{nJp%zb'UZ*w;IhZjEke:!7\j) t -O CZob"aILn eSvA"-1ڤ[1ڟAҶ8KDTzHRa=Rl9Pbe%x}WLW:gvQ u9BʓBrGd{Ufl\ddIsKXS⫸RSk$b*^5EǺ U?Yko %vDwIy"A /$K1F%ZK ;vظ.%_SHm;5wy&sv΀1a&MXT?m)ÈDg̷$H54ζ;VpzzۈS1CmKYk&?"0DzL)yX5+m-t248nqZ>5AfɦU!] χuirtoF?G+-ԛ(OL^3nتʫ9Q&Ikn@6{Y~FR!rFYUW}^|ug.@PC9΄j5.-zIJЩ_GӅZ @@0/,!$!(*0 {"@ +Roo/H@@L@@@@@@y&& S& & &LLM2L&Lf21PL2&F  p21e01M01}1 ojʔa4aj @N0eL0ML0}G%SD3} @o0`Y S Sӯ8t gdNd~0@uƄĄ@g|N|~'ot9 @Է `4wO_I0@WfV f\-雡o\4~koߘ]OgQ8t Bomzd з:@ f777DO|~o*yF=aY|/OsrbC!MB 4~<[/]I***?z!a&zF!!_k8"6 |WTSXU#MQn#@J%tfƌ>_GfzmϷàEeyƉ#B鼽7}~}bR/y}QƅjmgɅ΢GfO/G߆'! C#nt0 f앧nwQ3LTA:?=]A2=5SflZth>-Wu2MUz4?oUU+];lxX lZtwt_+ mAS21%?*r {.g-^LБ͟Iuܜ~IdZBB}V O\RBf; s۱W+2Ĕed3_zٗch3HǪG!i؃&0Z t9r5ms湨mJ6X h&WUOxUN<<<~BZ_Y&ɂ;脱sPly,pzώ qI^X'od= |6m̀#;,#ǪH׳^#⇮&;Ը6]6d|,!fx  @lh wvq7NCC]XfG^2p\tP,_ijՌQ{gl*H/K% Ȁ3/dps;ՀAR4]Yٍg!!;fӘz7R91&NƦLipb6XB\O8!NA E 1R|4o]eG"HA*|>A^%8ivRǾ`G} 2{SEǰ@wqRmV)~.[ijsoԎ! $͖3D'0Ek bS҇#sE*s~꛻K*VbĺA `s9*(~=p ڙ8Y&ecUcA9A0e]+8`p >]%=͏W:pH1FE j?)0,T>SF!T bCm̄a"/; x2J< P?br1Cp9q I) lHXsPL$;Ն+E  6ONBK.X!#ӴY XeOeEa` E&E/\hHlI74~xu+rF:_9lk{wVL0=n%jg؎;/ήoUh8پMͪ'v:iZ~ FH=>NjbNu4bO5)K% jBk!"@(HR/* H' 4wTPiATދz{?컳~dy|=_̙y(p~XLXi#OSgVƗ ٭Jrn%O"-v{$jD F܆W;39pb-=޾s9TEFzFs:[:p"g_"o}柲 *Cm>:#^H7vmM1uwZ酳fn:ow 4A+W:t/f!BdxE~#^J:AF䴼 4?QRau PKJМC#Nl-}~`9nBgu)stAlf~'BikUR!%D+*ċ7Sg̈5P#5"h2Մ㮱y^zW԰ ;D/ z odg˾kV@(:Z/}Xv4ƘggO [Wk ;`Dǻ16Ӟ8"c6T$6J78TK9 }:V]r mVwٌb̖˹ ޾>wHPnmP7拆[g[ϋt[\y`ZIDuҕ^Ffk Nk=BDEO8xὢ[O|}`Lig_x>﵋UWr89˱hi𕕶`Jrʉ^vBw5d@k?0@:~<qU LF v%eaߣz$f+d^-dsaL:$}&S(|5m#f˷^9u dd;rv դ&ƌArYsbjU3Y5C> xm8En'ncb u$qj"N~hτ!:UY+B`eSsn&ĆCynY+VTTJESRr8GACYⱰI͟(D 32eDQ(I$JATLL\O/e]_uI.%Ѻ$ZDh]KuI.%Ѻ$ZDh]KuI.'JxE+$D(QH(B!/DofɮruSfk7 [ڎ`R-r7C#^E1xo5**ȱHpUQOFgU Ԁԉ5kwۏ?wK>=س6i;=H]aUr'#ڛs5Ʌ`άvA)&ʣVӢ<%y}I?[RY{L I=H5e_Lф2l6.~ cXE|C/ї>{Qv۫-Q'r'"L~el@mef@[ߛ70d3Tzw%7^P gsJoUrrBey痴@9 ͰY>S y(#W5QDyԒdR<Y7WZT"*|hKCoZδ=$SonUn_/ ڰwM ":fē3wA&b?&gYbEX^Ɓ7z/:?DBm*3 )C1QX0t`q6]w%P,ZƤLzi8Ȧ\-=rLdnAzYM%&0H#n['4LZPʶ$y r;?}'@kEsrjKS;mFJ -+&H9Y.x2e*&Y V:;b8II_)$U+N& Қj^ )֩ ̷t|m^ɋ!BHr6&/dØ1r^L\dZ:c#O~U 0mpo!HcK /S]$b$YE|3Qoj㊠P:p[2=r$/̮R 3,ߐ,H[FW&H[ptd̋m1)B+֯@0T`O1 _: j֜ܽ,=ԤkvNmF8j o JOL# 9E5ʌچEHayJd{Au$1P9MA\Pe^>>s ǃ^j#76j&܎fX* ᗑ5).?^+† (ˢK(ѷFD dtϽ f_3%*v ^ke%X"mRJJ ,WQi{ D'IRȗ_[q?ǟ]Mhܚ33o_JCaMs$~GRIy ^s@JU8c3]5Tg5xjg\f8i욼sh)W4A.; [t\"kcaq*Dg.)D~1KT?Ad|ﶩKkě!kz*l!bb֛hbqskgw7R-O1Ӥ> ΫFҞp"$>E{ 6$F|\+Ս{_WuSc…q!Cpw \ .3epww>{ݻ>y֪^3ݵ-Ot"THni>gG&'O>CA'>1\ MmmX>`IAH{k*kg\ʪO:\suA_u^ Csir&FfgF)v/#s<;]op R1Jo=gWU_ kwt g!z܄^Lƽ5Ǩ S t>kc-$,hw;~7zx[Qh(KFD>yt ,YFw8iu/FCү]#o9"{&HoFـb)V_ƪ7}%SG4񅣏mGJ w@+@R e+O$W@[+a?UU۬8*l *ұc rize Yw|bx95FA"Ιjeӭ}1ɷBNr#R)ƍ}'tl{,)L/Qa4^x>nP~GgC!@}/{ ,a[p+U6:?Jֹ*cF$B0A,a*`pkhmU׶82gDBq) $Zx0]KB#wߋ GN|}k6_׆7:30,\G֝R@<gDshdڟbhQMu=*`_B:YU'//m I&))r%Š|~/sqkWn]+< mWF{"(gkEOT H_H!IP>@ o"V>vyW"6Aݓ]_M(tl+K63l^#%yg$KǃUnTۮ[Х0SeJWu!"Q,45GJ%p@yHp"QMT2{zKp0ĉv-{s/l?ԄXeiRrZji' ~BsM Я\n1tE5^u>l\?n+%|(X[51m$L{[V3IZ"׮JE̍r6Ϊ:tv(F02\ ]!A.CvJ*]?$_{!*&,r{ 10%3A[‰L׹i~P.;8 ]ĤE?Ga^ \`܍6R'n\b@4#0$mVxOQҠ{_SHoxz,mYh@()xXl+ mO_|$qA ~ݛ6;<ݠP8_xY_S23֙Hk],)fB]ݲ Fw8^yG7~`)Vvw=$:9J[~~ gWqs0 HscЩ<0Á=B<65035^a}SB\o/k1*Dj3QerdD/ziXL-;wt"mW~xe]S&iVhdIWokN _ /54 y]VrGE2?;'|Y\!JjC$nf#~7Qo\DcN qүD|T Pl0Le;721'2DqUI{L"a= 3%{…9!i/p-S}X!yG"$^.jaI!/^R8ܷ&,cy4лj(A~낫Qqv#]x{ᦉ!tO&!U? _g4ZJ%ke.=څ,(p*m JbF>nF/;Xy hkj)D%SU>#i `Q_=}>tb8ym}v+=96E}:03sHn%j5mv$?(UfB, qXCü+8NL7O,yՕfSK\/GݞR=,K 悉.e>DS/}6;[JB_U4Pȋ ;ȃG GqVR=QG+[nB2ZfنlD릹[|E%J3Jq .OywX) 'SUxX_3YkG r[N2pep់v~'kkRs%<6-socёduS*hh ҍ3/'T)]:?))sAn8䅞ܶ F;LEDՎxVm4"aXTrŰu_>NN@d.|JxlG]vA%R@w4IV3Jj4*̚?5e9-{`}6~iN.P4L:,Ke4#j bgP$kp=wf jI0ҤICF *Ks舥0c ~7*ع&r8KYw]Ym!\ęyˏ˲9H'7Wc^JиqGIm !;`\^؃31zpa'rK@9b %Q$fmΪxݍ_B:o?3c]=INlD]'1YWAtxq(/S9kBY" L!uy0=Η-$-Oa;'{x@۰FJ )mɇ:fmLZVwi c'R(f 5nXܚIe@l *wU&Θsh1ڞJ?6d 14\'9oc4^gqrw>eaJWQ 3R,xdd*h !*2 !]VpA2%ND \ʇב.[C|0a㊢{GhL2tZ`g p\: aFȐ(b9b #ȍвWИN)^?zӪJO|= s5;ݏ9y4>~{44҆9iF$]eK8+W λiyGg:MAA RG(:x=~%}Ga]7~<:єIQ!~3#kJq&ү 6UWqlZ܇zo'%T|=&9i RG9 mYsg,^CD# "tҸtT)n~Q|`O(ɠ{qٵ߿EVƅ CSTspLZ_dUڜ1jh1TWP jh|'K֐m|;D E<{=NATY)W)oj5P.qjᒔ,) %'zgfng#Va5] YbU^_~0{6R -q._ʂ8;8*,Y 9Zc|bg mNƢ|.PsQk8%zD:B]$/J3?F|nE.:eܔ{a*a~&?|i?=3|ڊ7nl",xnfNXX2_볌=SŰgeC6.%T2' Q'GXHk8|#U8+!`.ht)!ζq itߠS7^{lޔJ2oѱ.k+,6-O P,c~FO{:aqۧWFGMX:*NEz8HRAesB_]vx 9q|D|ahz&'J%l"T ".fb~y+L^uz;aaE0,_Oow(;P_LAżDW6=b; ϠKW)XyGܾZ-PnLY?mP&֗Rp*$'1NMI8Nc#a/8E%c@;Iyb%ⷤ!L12Ӻ)FWґ2l'2bH6@t2R1q zf&Rp=aJƆm֯yS"o'7E4T?(ti: R)b ??+9VLCDno5 SfUNl"R2Q>yVKi.0fbς3X&K+TRBj?5x% 3+ c`m| [%ڣFL`nY_ !(Bvhh$e풄=z'k1?|d~jB{1YbwiaN\l%Sk=C > #!Զ_*r!?)vW 0#hd2N <:Ǥ IP|IF$ i&Be3:jbub5x-$bj X; >PɺQHj˷AKf.u\[+Ű#q^Jac=m; oNGf⬁ɣC屻p%#ň闖뺗 jr?J=GW+5BS~6G"Ɂb`謰*V1*G@#< Pc}BwmڿjfU T?fZR*Z-x-*iqzeV n)y_sPj00ۦ@dM?l< u?t6Ov{|>,:b&sףǤ n`1C?zX++~"yemJX9/ lDJ9MSpN 6 WWDVBmݺivv|qOR 6FA5Fn*·bv(Mm}T`u|;qf&>CyD:W gKa]".Z]C3un a(Z W."^^r_C_:vòM;TG)& ά/d!*t5c rLفg0wHt9~Dm~lj~>O~*3ߑ-Omz|ZCO|iP$x5E= N.!tp^Ѻv5CHy|"y84ԾnbG`Qсy*=XOABaCcV-!S8yaOܝaΤD&^hhMz_%̚)?D! tdӽR ]NSw>X3Nر+R囪˪y:1y!?]^)xxhN&8F_`nXRUqZЛo7v GeCrIL vYa9֡|i6?0Cy.0Bx F,֍Ƴ~=Y8x}H5srҧ1a\)~}z+2T@h +V~婑=|+饻"NS u:>`+WSRX0w)B9$N)7˂FbOC%=r w#\t/\Rw^Kͻfu9+Ӫ%RtmmԘŃ69qȀa|3H\_llKs.A&;[`7D{7$n-b"RubT;4-r9!1Rlt \jb(oYטVc+⥑>$[#1qWw % ݑ=A{p^ Yw0v!/ roFD u[DBBu$=!;}s 4~ ?nϨ|m馐CKK?u܀`3 0Mh 5+`Kn1|A-/Oƒ`x:7IS)MGlU#'2ͮmRyYָ2CPOu> A$qj'YLxe~ãD[N98#Je8 !/'05N)8'Zr}J}!5#wqMFY=sYDke/$}UI^i_%I<jC~Tcgێ=$$jR"wmQOjz.Bnlu!İbN)A?d AA 85Cz?|ŧ^&տR}j s[w ƽO@-] Toݼ FwWqDӂٰ00܄*Fa $=xS$ǧ%,\sZw*Y#63-'ZXwtEIR,52wE7>puRժ[|PNm%S{nndۓu:)֋Vc\ A\=5WD\ J,}rnCdM\|x:=۪}]M9ܗ~կ/ތ"@yØEJ.þKEÑrF$H | wuJ;V\_d6l&6֬;:;kݩO}5ş]n}5{l=rŒ)8b_2W@kz5~e]i|'^83-*_N86^.*")._vo%Ay)U&V^M`T&X ݈N*u[^u+Vlεۣ;gS;ن*Ml6uWE˶)k"p΄pVqU*=e51l˪v`5F"eCvF/* =~~)rg=oC%;F8QuXkjsG֖,-Vz(̒0? u˯e_ms)f{:Q*9`jI} w4uҪj>µHv]ܭB ޱ΀4zVDڜ&NO,eK#Uk/(sU4]&8˿ڊ_nfb4[}%ʟl`ް<.0u֌ŸAvu*u(Z"tD}|vE9a[jcHsn5WmOEO:_6KܿF>bJUFTA|?VIrX)Hj:kRnÀYCU [=ǝ5QNԋ'GݼO ᙘu>?az f2XvǡCȵ G!!`} ?Nv9gua|F Fv7b/+8mw5ԺA,Xh0l4Ϟ5 @S/b1_&IOÃ?*?㳛_0fy>)PrhDdUq)qPKQ_o,. U0ŞJ 7 &f`ձ"Os #oRUM, jk Bg嚡)Eb7s8֚qD質E.3 P 0јiZnrSt3.2j-p̨[p48SY;hX:xw7 / :1xyv bCָΥo5h[yx$EXx>B/////]Q66v.q6.qVۿEtEtEtEtEtEtEtEtEtEtEtEtEtEtEtEtEtEtDtE>C@sG..nn6.1^nnV1/ȅt?l psbO2bdr'ba`PXc]AP毒BS0t?~Cq}̈́D+[+\@{(dswZl~-~iyvTcOC31τъQ /'&Wu~Gd]l_&L_28֘R'Q2/y%b;0DZ4!(|v-/CdOoWЉ}bPrq_}?7eȨyѩ IxTGX M y:.E ȍ +xjfj*!쫒o6M{l@ __kՆm^!GF6B-ybiF1j~sE= T1>|/t gQbBWJ%# TE_wWuSP^e+8ks7IL;s[;-쩙g.F!1pLfw)>l}<Į;K 5" pBPdiKt#n8˜{camW4E"=f-q8 x7f,]3 XX*4%4B%5>mW^zEM%S"4c[z 7S}#Y2jВl-rlsB]4Yߏ¡u< <=_Ͳ_ean dQһLnK#<\I1=>j EҀ"g}^C; :3V;Uv[֚\Gfj툺q'[g[ MI"`j88t|}.-{? bqRLV:ot9c涣IO=Bc^j 5*38M{ >û ~Ch-hF*;hhpVw? m:_pxB@Ӥ &j,ſB(FQ@I:u;17ãγe3{kk_{@mf^|g,HƝ4=jp6l'}cP[X" R̝6OixJTf^FA,-[6_BrVb7h`"KdzQCʎkėu֫ωfaL22ŃOjjSqTg+mibF&:K\}u :얚cӲBq,/01="E!N,$A?|yLJ祺/H [!!9 ?YEx%yYYŹE9yX7 TǁŢ@RaI6|% 4l_ءx,C^Vw Opߟm;{\j_5 vTh$N]^1$iIuMC6n Oi˕ӂsN9a<60QEHtE1`s~%eAnBAܷsح->a& T[*I50n<=hךtb``6Z'djϧZ1R*EfwD:cpJe@|Qǖr٭)7{ w`X/f{ RC2TfG12Ԡj!s2xCw Yaj\vIDwy㘥jcӡDqz:uc/%r)LɼcP:MR@=.&|OF: !Sp&uOՓ*TRr(] k04J_ZX| Ƴ^V\3T-gf+/ gm]iO4ӹY) KٮT٬JÁ:~MO#9J)X:#WHl$kVz R~M3S\2{Vk 9Nf!gJo.^,`hZRP8YB<Z@;rXlKi=E G \2_5ȍL~̌ vQNc:&vݏq ;&ݻUIcWKǛWn:]RE:eN<;'Z>6}[!M]us gYxqg\Xce #"q=e a5S=[䔕bͼz|V}ŞImLT^>-/Y=Z|4VX Ұ]L%m(dcG-S)1~Qb5%p`ļH{Y; ܳ\óbµeq8i RzcHǟΰ֠#$4+Ŷ* |O`ٲ9viy,atΔF);:)Cwߜ izP~Qnv=16>gyvp'=jS 7֝@`UW N/SD>C2l5#)7(܇՞|5s\ՋPؐJA Jo[jźܳ *]U!R͠2̐=Վ]fIpz.ޥaK0}!xE~>cBV3{LoBT3cO_5_f߿n:L}n@;7NB2t*-FUhUڛ:k7RD~)+~6SϏRW{rJG>?qs;^^q[Dm44ρx%GX7 vm{s?;_i@|숹s4Wn)aըd|4GP k,!,R*^r(!b:Ƣ*"-JfPb"IO͠~8wS1>\kj]$s{ZQtz%qRwC DbJU7c)λ)W \J{*5K ,ċu%g(-&2m/ `NTCxfոv8J AoLt.ttQ(dء(+U"a]1~;0J"h(+gyIe# Mg/4 ktڕO}EsLTJb鷶9sflL$d|bf?lQ =G^HٴFZjLv~K q'ݑ}rݭHWxPr5 ʘ1ҙ^,7M-'8md\1«$\rJG3˵|mqu,~cznޕ%W N~/`Ls^_C4d{cs_bs!P.??ӹܭ;aVLܕlO (\t Vu8XΛNyϰrݭxֿ| _5 \+8^>mIe}s#)mL7Qs%Nh+MS&$ Īه;VEɍ Ovf[_ԝvliX.MNΔqU)}]Jes)=Nfqx|^7(;S/yEY MH=z4W/]2?>'ꪀZզrtBȷxpԯ~h]X5бS[jagGW"[<} Kuz}ڕe!h2(TbleP{0d=4ɇʖinUÚn3z/PșƯ3\Ú^<尟. .j{־ⳏCc|AwʃfMtP X:S0T 2RMz۾WJ\4T}jz<̋m`Y-͸LbMg qſ`ٻ1c2ۤi広Gt'F՟BFuuЎf>:@/h(Ppc9ROQ*NW859-QSiPyH>\`/Tk>Up:p򳊊HoONW: ֌EJ=6{+B{:Xw5Vi޷fS?cw=JBeЊCI&ŵ/i [%IFTco_rчZ&bhϕ1^dy& ѹ87 -MzyPۋJ:֥ 5Uxh/DCukч֋auxhWuw׽L{1}J$>INt;iwAcC,V #WΚ]-S1wW~n8}Z MNlT]I;i݀`]K%iYΛ8@4O"rO}ejQKB&ry(=lBuTjtqJ)I8yw_Rx3Xl5ZUF?R^Ұ^^Q(5=z8z8C^9UZ>QZmI5W }ḫIoPQh=ςAtE\;.ȠagB{UƼ? J[SW<7\&Z͕k M.7%v ~wbv=ua-8كzuLp[FAXL  u9q9`eoLVyt8ƠQF^{_n wEWB c}@` Wي]SB-؇Ff-$ZNf#CPF@q 3YO ut"n?k7)d~n,(RƧc1jOxBkMһoƁ?jg>aauNL#vq T CWY}\[r 3& iN7YWWX$ %ڈ^QrթKC9#JdZQS@N펶Oߛ8 :W+?6խ0ef+k4竫-EK5YP[%LҌɽs8L$`H/+<ZhUpO;8~,~?k}wj^b2lR ~mPng9[=.z&J-iA] <8 wRwjoI(~W9CakwkM((o6YhFqJ_Wx&BS~|OWؘ6?3Nܭ0niAn c+礷rT>4s#fCWX䑅 A]՜$²sWn*< \bLT;i<*N.s3.x%ItީW 3- 7WUiQ>2XMJ{nMOCZZx c29PO1WFՄoGZռl?28+3\:gpk6\ 7~ e.c}"QgvMn49rL]y} |n'+<=X*ZIx(ljȡ܁Xr >[Zaơknɸk)|iGfa9g]ϭO}OķѲvi el|3t'tx0|U;!#>cRJ4s+U|_.f4Y? Ű 7"y{j%B̨=_Sr;#셮9{@;)q#dBP?JwEs摊Bc:R!Coli峺Sj/k獀 辉![PW Y)CJJ {XoFx"E$eNQ݊iVN,i C3|Ni&J:']Ңra6>Uz0xr3rn˞c+#A=1&F&ݢnaRȆH)F_k*5`Sqo bޫnt[g$ sm.b *EXzᔊńB}k+gɾC iM*"~0kYj|֫фuh>hЭi;]sG ?,`{߼y;wqh* sק'!T7p;e, f~zK0/~s2EQ=JMɣH t$Dд xt~]u[z:vj?=S,a j %e)T)癬!@&Y ~OWHf`X`smiӼlEmRyu?$#~'6Νt˜fz?}RWƐd 1~A燄^ ՅĬ3ǬȣX.X͌V⎈LMBD5 O-U/AZ UWaY1g쥺&y0sغx?TUңfh掙 =OGX^ _.':.C\vyʛ|o8@X7ةR$M{J9^g55}/D(e}tx+阣o. ty򎄿-R-l:I2 #̠?m%3H_6EKzb?=ʤeeYYK6_PBޔO9Z/"ힵ7AW*fSz,2N9 s y+L{enԭj=Z+fmy2ug8`ܖq};pBv`ߧu:#HF|{9bp&>yĘG$ o*gZ-6FghU %̇-N:'9Ae+.)#@M݅:H APzum{;tMiRPNo o,NskyQl͕~D?9Ja+q?/)ILs%c8`Eijfg)eWt?[c*|]^+'W\Jr;=eC\({> mz@rX&OM BY1ç,G?o,_`hGOC+Vu#44I'T-/֢/.ƨz?-;ajŊ5F:U] aJOaxBP3Y5-&=}] ^offgFφe6=2@NDe~yXYɐCt 0Ob?t1,VzcG#Q6 =tmf ]U/)5;}ۇϩSUfDN5 3J,Yl?6fWq.{&ӹ\?壌|'g#]-ja0?1^1`Ⱨ~>Z1YOD? r;Mr4P2idSA"^wڍUs q#;JJk $۵l=NR}r%*S5YszTΔKF"d` cѿ|elԠB, =izb[2Rj@T9pgij78sxQlX]}pة !62uG-kra砓Y ^ ^;1w \XuBj Z>;%3vof=:n?}q\>Q̼N&6fX:B@e_"Jwc*1@ʞ>A݈UF&Ʋn N[)hsl#nUxūҼJToE <l;gYngGs 㱬P,&ng.1[tz)T5QEHҾ/U/޻YP6'dyq>U=Ww;ң Sj{[Mnz7~2pޞ_G9y#5e\W: T[jN,&񐇝 aKO~qDC5vMZLi/\ݫ:.9o_37萘࠴ga+ _hYo-#\h8߇}56cUmcqܔN9=H;R EL2 VB5>J (HFutąW,)UFiE 0(gܨ'.#CT}l`ruô_97mـ,n~ihsy{X5[J/3z}ªJ\zlB>o>ӒuE;mY{a|)(ϙ: T>U F }?1_:JP4:nsZK4ChѠ<jes9mb#wI؉g_\y W dOUr+YP"AsmFnb$X3NVL"$$4D|H`4G[tk7OL)eFTY>p$NW9ҬZP%Iaal' suG #8S = =!rb8WusfB {4x/̚ z8gjhz4xV+_yG/ YV<ɯRօNg0^|1;$|?NP9:k-o :]KPg=n n ky)?l()'Zq;5%jє_4L-"c1Cm7W|FTnöOXRҮXw:u d43r&: Mhw *K??Pqq*%Y)6&=n ~,r2=ÈFN5͔*SQ:-L̀=s59^N^Od c =8__x!ƅЎf/u͇_B2Ct@'/#Ǧ0F wn_S8,;t>2,7T?=bQXRM'#oZ>TGܣ #.+r~.PX3H̺$BjъJb"T ν?=o=ˀ i6m/c,JED(,7#&V,!ͧ%57sa.<Ap(W^H6rϝv-卣,,>vYvo>lW1m" pJ> /*tL^C8:|BHɷ̏Fyz h}Xsqf(]_IaiӴ:ǹ1`,?_3}kY$9oVεL@ڦk+z= +~_c' Gu:2dAt|9+!i?]y:<%@Tѝh+n-ed3oe3E1#gEBu9k'8]?w0-wjk9&U{ؙwŋwK6/uvܹu,-܀7/]4γ܎Lj,}KؘXst{#v;z#h1h-U&|ݳc2LF-/%FVIJ]|ROõs Jy-8n zYFߏl7"ꐦ9WI)gfT`jBS<JVaU@HtŴx^v)bqDQ;mُCT G%@Cijb齌#'ĒAUMkI5@ǀ)m&-G1ڭkO)V;Bʡ릆lZ&]} 'WuËk7lO#lBr-LP_īYl銍 ]z 0j) bPr͵u|XKiEig:;<&Z%9 FqT[WFdDW}k4h2O#дtS["6ܽq|Уwn+ʹ9^odOXڸRg\~-bKD^apo-pnN'ٹsO1"^ơ^{|,G1kay0\U02 EwYb߹2mvQa[/@y个:.,7]fNBhZ@ԷsMqӓ@e"MĻnɁ^ ~p~"Ҝq:>gʷ ~#Lf^T􈼯V4{mXWyoN%l?<_Xj?KK\%C7+;7a_,U&V̌ʂ=][ț]=G+l;TQeo{g@ /S;ܯMiҸK}ilw+gvOĶUтM\ 4d-" ׂL GKnm\kXR-}Zq"ޙd׻rSs+=坤Dwf!oǗw K Q 01fM*12`3›v3Ad 7*=o~]0cjlT zw.6FBhw; zu1B]*w:%{yx+KAdА?n_K]z[je+  R!n<[`Eh$6S4auxJ{&y0 Bͽ#O헦wƪM6c{GDOf)'T{ wTGAv{ۭ>-R\ڂX<%Y|n0l@@m{$_WS+s6Q^W SsǮM9`&N$% 'n;#rw08;ܔ**!3RřndGh_oC̨ؔ{bc%L}Pw*foߙӌHN~:gyoXV$ئj>=$rqK-S_ι_w>怩j;nKJڏo/ݖS=usY/J1$t:-d}4,nQyl[9C{9.uYb3X:y)Y|Nxӧhd1{93Bͬ2d/gBGwr Qk?;i)Ǜ\6g` %RoP%ji TAeT>m̉t#&5}|a3᪾:UCr[|.wTg4ubh`BTgs+|! J^3*tgȀs:Π[!-1螛ty PT9?/i\nNF5y>bvoMykԺ'yYXb^ } ߄0>(ϒ1wNMsϚ &e4ɼ:RiHbgI/ԆqI _%{%y!NnU6΋vL˕~E_յm]`p`!Hp dwww!՚TSN`e1Z6d?9xƿx  fsxZeQz{'D2f{Yآ ȍE⥷Q=xUM HGA ݫ=dSX &S_mYD5$?ZZG76/Ͽ>c)ޚYӘau͜75K^)$Mْb/ϟHidQ3jt:łK(Qϖ9g<=#`HfkS ֟3]'s=pBF5m^ze9)?P*1# !B *\;m}!! 55 KfR?B$I ͿJċi*^ u=5S_Ua q{E-y_<0-OUR]Uw(K;|]߶~l|P%x>.R鐓T۵ mljÈsU*PMYB2ٙe+W}i#ҏVTVSpˋ0@6_?4f T,R#qk:ej-<RduQ51q}G-;i|g垀3a!!abTT^NIu3Ž?Pzm>4UOsVQ>]sI&}^lr`V2CwNc8*|cS݋-L*SUv/68(*Nk Wb9o-kՙQO,2L`L MQkeqӧvf9 oO,vfyR{6kԙfY3KOАqBD1/P>rRLt,V%N\*!5z6s o,-ReD'I㣘O;7>G7f^sQtֵ~3S%8"{}<~ ozٛfu+xXu$ u4vr-x|lAl6HQ}$Uc|p6Fxi`"xX7*7$MHn+s~i$IzgMOB9Ӫfߵ ߮,Ӵ46,}ex|hM𮫂q EFܛb 6ꫣ_u,:.d͗3G=ޥTAư:` #ZzNky/v]#q}T0/aPŠTяqK&zh86NJU x*VuT:Jn[v.^Nfy^ gꀈ{&)tXD;nh{y`q %Gtw1괨~fS/p9~v;Fhi9=ց~^X,`?Z']{{m' Ьe t|}uDW1d|IHyF(G:8eNɞᰠ܅Eu8t1z1L ::HZ+9\yqn<-L^8@ ZIZuB[IDɴ朁ܹc/Qх!R 5uVUO%):/C7?2B.,\az.Q;oi4MDcb&[[Ϡ9jT/eZy{Jr]gzhԯg2/w»͏?ShPu6m|=/t >'F\rgKڷ&|gΫБIw5`A6jCoQqwT5;T"(( rnU|0oj![G=3®T~i֞B*byʝ0ч̕ MFK(lmaχq1&1YA4?L5uV1JVgaOw s-& ?c-"PJ>/{T)2p$17 mFO,GS(;~ 7l]|d9=삲5Ou>A=MG.͇3"㔔f|=/ 6F(/.kzЄH5VjWy]qo0M6/{z֋&{Ji{0[ZF-uaHQ =Э ^ l^hZ :r$V+!k0łV˃E*킡kcOu0'0K  D/Nnq:\\muQou=i3ޟ.MPVjO~8[J#vyoG R[4b|nabΎ2M?8*ELh=kW; WW^;_k,h,1-Ro'42yM°[ ٝpL^t$tς1}ɖbMi`»_rz#Bg"pY ۏ^%V}-\d *T>,seMv}bLݐzIdPu-EFRpl\Y]ϡv][^KNn8وeLX,дh m'j]-} w K^Ѥ̺R,v$\ ;=F㜵 w"%Wf:׸G+g]`Եα`#[ `i+3Jk]a9a7v")neۘ-.wfkX,4'b 6C9AE:a$ǀ^P "kt5kpC:r}qWAnmnW} IKkN$SK Q~=}7N!)$^Wq9rBZ&!}8zb0fk O?WUrx~\C|ė4:2.C_9 ]g5Xi~#Ó睋 avE[0.&,DՇIgOTMŒ9Qs\{??7etHu{r%݅Alʀ.|.Cl#j_iCP GF$SM,Vb.`L`:Ꞙ y}\w@IִnZ)K4E PՋZ;ID8(NVs1doV+ET ӸAM9TK{cPҮXcgֲx6.z4TYAYR5nn\=OeK{=P%.6lΝgyOE 7Aubx|,*AUb+߽oE([3x #Qp4nY ұt>84#;h}j;i.z`ŅY`tz`g2a ",QAW*%Ir(:NK5*j٠x2u7nUG^J+wb#pLT }\VB޿~9y]F*Fzܘ*&ի=tF` QmAMɪI_(.E68/X/Tx~9)4zX٩;FD;4V~uDS@JvMһcǥze+IB"9$:2ya7B_$,`Z_b|lM`,B?Ld}tӷYS@zC$0ehp;*jFˤbGf:Nj l$| M}Ye1"oY43IReeO9_3M9 =-;:ix8ݏ\j!M+?Otѣ?T U Wfu?C&nbG-h=?BrF"-0"xspAÉ!ݕFn5A:?nx,֜Aۊ;ޭ:;T:t qݯkT'ik]s-$@=l㲼0ߍw4@`%Pexܴ[G2ԊYK 1=prtcCIz]?"mf/JG^h9 Y 2h{SR+vG. 0Vݟ*D0]^Tn#D!}s;g` }]Hpo!s`}cA ҵ T%nQ'tDA|hb#z( $K5OLi)OqsDR_ًLyG"^>njB6jhe[2)ViWKX?pCqx}y޳+uWpz37[$UHY/`of9ufScUk:@(.*Mbⱨv9ĵBPgK=4*ѲOvN%C ’#&nu2i[ SFd`j-Y0 4K [~E y.{ki wi]p;gr2%YG(2{Yi{6緎DTafgT3mVtn_MHT 15O :9C-HR!n}^<ũy%'<$9\~^oܦ= G mN ]šhDdRa%o@%wF ͉5Bu5X-Q4JB'5 H5V@9r2Pz63Vd3ڡÜaM)z}w1j븂0 aIni^hʦym@/6罿\{)|j|L̶?mG<#Wo)Mjie*󩨼yukN$ @*/n!D_ XљiZѲ3>WEwD ]R~.`|CW`F8 tۉs6\|*N{';=z Oq\2'Z?G%m XRNC]L2 ^$xW"1%0_dgD ?; Pj?)KhGS wmE8|Q2qE(L>UvgsTcz?^se i1c\w⯗ĝѝ6c5>f?M zh<21gD6M#ht ٶZTE{ S(KA(^Lwb rߎ<=녅L0l5vBZv:g*T9Q^x$t.<ՀM_^TCĵbE%˒<(]A":QR8"c$<G8cv j4~hC-yG`IdKYxHŞVRc?S!U6 WNѦ}e 0]Y=O|<炙sN_jMqdP""P4 >opIMS;ÖAtL1$ 6^H_UGLjb3~V)W^R-Z i-ݪqqD8CDŽ&(I{AzZuR)*zJt[U&DOGL5tGM^Q`ew##[kJ}~da摜v^?/PbLfM0ß;Mz>bomi/.D.OI(/:Ve3K@0=%xE/ۃAgEi:q'#fè*6) |o,2@F{H ZRg?mOAܖ}qKP{AYiҋ@pގ I`cuDg}W.ZG5&J=_jїOAL$]F.Bim5h'&H%ђU^V<~SPT~'/ {l|[q~}^$_Ж%^X|Z]ʄ^n^ʪ#2şo7e!V W<2͗`>:r?]\-D !K+A'V_+Myɩ (fY0^̿"p ͊~|[KQ&JTUX2ECP|J(1 M ^`x &uex+qBvӌ-p#[,K7gh n]vF>~.dغ^f䋈ҷdhmokk81DggƷ Z|6USzmn4"n=,A#$i&T|SSI1k*bˊ[<=ߺF7Ea;&=7E>|y?5l[5h,r +I07qg$Pv$<([(=tw=lp)XwmvmKa0l<_)EeLHM-pJٕdF6Lռ`G^A;+9ʣG(ݜ)뷞[jLiIG1|/P2Yۣ}hNG#˲5Ӧ\8dUF06fӖi?^sK.(/AI/&QݴR<[tn0-f6Jf<*m 86ehENVy$E Q'/#Ն)%3_y &Uhlpo(4]F]% =.>& 94nTq>+3bVf `]H'p~Ax?x?W*&8n#Y!ZQ0.OE+3&W㲭YGuj[Ȥ>2Lf9TjIh07>^׍EUvBwG}(P]mwZWaѿ27 `d= jT~tގ$q3~JJ]!sŮxŦ*T\KNKU)?,u07&1;:!pmagXEw0#TvgG0xrżWʈދkD'ЯŜe+$FL pŽ:_෎فȓ.wл2q[tuf5L "8LU-3q{51ۈ?BQ&h!Aճ$ډj5d{'ڜmt[;Oc3#> l5Nfš? 츌bo8y6C"!ژJlbwXQ]7,q=߮Fo2DQ H 9'dʇ 'ƲɈHb Qi/q,/A!ҥVʈz,aş ?3lxr38+g[\6%8muGт 8I}Nz =q ?⚉h`JkPmگg4!.\ Q,ssXLB~|HNڊFxk(5O$F#6-]wZ6ϲa\/,k RSꚎKz\f<2W^~<.Nf:CkPt> ~Be~?w euTJsX:$b1\~h> ؽnH`tZ!ǡȳ(N04SqohK4& %aV\y@K,睁ibnqaֻl`}׃ahFjxΡ8Ibs1`4sH9e5`~-0; #kKc5 Ѳ4x i٧k FIk%7LCu.Yo J˭cNG2r ioLmU'i>N J:uiry86L^B!2$.zx1hљ"|Xz[(nmC㇫~<(Ҵ[~I>$O ¨v}$Rma'ii΢סݰb/pCO`HPRu"xIOޚHAsY|Xw?,gyyjĮf>$T;K b9,YOLV롯<"ci4*w©Ng5A w5}X=!uV\ jZׂei7ra~:4vU;27a -HfWSC*x #oF6e>rk7}Mأ\,DbB]!p),x! F7?wyz .ZJl^g>ϣc|^Z'4?RO|*iGNgzJ9 y )㉬#UV]Z~T|rӟ,8oB.f%r-0V&+U;>W )h x jh;9(Xҍ0M,S,RNyl!bo9v}Sױ-rYԲ8b[;۪i2OWt.rJ|dLݑ(#P2&.ϰ1/"2 zQlJ|-{YN>&YYU ZGq[|s !97m2d[,F-yZ,C,| GXO'!W y"H 9G&#d^4A),+52ee`+:yշ& @w֛&JՆYK0~~.zXeی4]y8" C.nMU\ 9|LAΜ:=b&Kkbi͗bTGJl^sʉa=^&-@#ן}AV6"Qq.>ȸA9d D^W?e@:xdFW$6 4ס5bFHy=q/`$sKyr.Zx PQ5CE]I)@DgGJވu*+>F/dx*m;Ly.jF-4NʪUt b"MY=H0[_-@"»_AmUx9aט"Eރ 6ϖg^A?ڎpW?1F3#3ݚ1ޡ O$ u@AH$͹M"fRk0`=̎j= [ D*ޯN!J)Jp>."˰؂k}zn3 M̒ҜIktƙ96;DtDE:|؄p_&j2[,YTD``HX^`oo i&^I^Bq H+v/Qiv\=vj*)mZO5z M?[h3m^NS9ϚNL*poB{^N݌RmX1/Jw‚]`ʔ|nP7Px+S%SBUR GbnRus}^_jҪ3TgKìil*(t dzfUk25"9lMyA"}Z2o o.<_!o}l! jZeEFiyoRXWyڥ"lz굛q$9G=ۥ͢qnrQoVrhx(K'a Wsuѡs.SrՉ{''3c̊I5. +2DoX'.bE!j:=}!IhB@ oa0i5JׄMaNh"[[+eՁoz1TqG똰0 LBߛF$^fEw#|5~nk#)# ~ROџȾúf&D &L?zL=R q=ߺR,饵1aSLP`翮Y)QZO0L]C>`j`nڨ?!`w* Lhѱ.DPgW'22MH` 67ɊAOsP1 ;mE09dw`X ]T!2[weA{”ɿVAGh*@ nigU 8R['3"vB+_\@!嵸qj(>Uȹ}s~ޠR]g".'bW}6Zsj?лTV`w0'dyA郢R.cX&* Ǭ_t|*T5n9T r{|MfwF{Z2 al%`8ON RfX޼zPto:̊&}^οkY<8SJ`ӵ@[X(I ]4/,C:4DX^l*EP#]aٽ$i}dqVih oHZ-^ӻii' p@ .)֢N ,#\;ۤD۟~Ĵث8q2ӟi=kd;G.(&&v~N9MSl 7z-w=H|چxQ*+S^)eUC9C#=w-3淍UwZT88@F%]٠[&(_swxoOR.Z- @X i#+tڞIFl5r}Tax hLT֝Gƺ;f]gB ]m8AYuf0Ah-SDG>EjJ\1"lqD/ 0U ^ZaxrFPjv3(kƏ*$R n[ Vc@";`(ђ lx"F _v ) k<Xh |;Chv0Dj9*‰9m: ^:Jgσ=1 īH ݇0͡|j"*<PޠtP*u?ûAq& Ԅt>>+{xJI0,Z{8fySw-0_zNV|/%i(0lS$8S:zCu Iֶ FhP\a#r}73]RSjlթύ| [x$Mus+LoB1)+KIBeH;1#ѐ "`I)S k`R6a emn]U{ 3Աm(Ft^^l58ͪ55QQLީ ţ#1OS|tp f^"B,JMwk>_/x@XU'JU|Ǵf;U&ҏ Y3L27hnTCJ=<rőʥ'aHJed1hF+Mv7xJ;&ql/3UQ&_ƩFMPăv4 R"YD3}bjG`|Pt_? !6Abۻ6+XGْNQBcz(kL:OZ\RL޻݇1t~^SG/ہP=WlnPYtė/lJe>xռ'9VZ;nG Tk(B頭AC5ԝ{g2]7Df~zKiF@UMOښ#F瞔6=4<8*/x4ޤ~yy~yw qN\5sy}Ox ןWlR=LH40$\d!U.B$\(6"M<g$>>`g\WMYK$vu)ϯBŕ0늧|'LGl߸C wy,.VZRaW}LN y 0 `J,d rFBKjqV+rX!R~N5,*;j MX!.qeq-+ᅚ([cxB:*,- 1|[N =/^]y< :S͓z:4Y.K",q@TЪ(h&ުtgkv?CiI$Vb 8f Exh¦1q'>P>){xH %TE !)obnzM'D$R-Q=EV HRme$x+}7HiM\lL. RtkmM E@W6εcwx(˰w/i2]g~pġE9ΪiO%ı֔xUzLz %Vj߷s[\7H!&U1Uyɓ X8WzP 0#wZ7 NyGBqwN/fLn|E440iOmH[zW8P4sO~iTc8M bBb՘)&jgt|ak~D>r8OĦͰs"?e ^XSL?Gm:Y݁[̝of~@:)Fp1 yǷPV$b#c">)Ru6X(n[q:&J^=Pt>Mpd&u|wAJhOtRϼ!}X@N2ncY].iow/H6mIaJL͢.;!ErM臰f˰>8 o{3|Jqb2$٭@DI! OuW57 (4}"&ɜHqjhr 'ÍAN?}>̈́dh΀a)vS{[:;1EBI~w6jX뮈-w|B}$뢍o~%I{N,8^K4oG0^0\fNDD@*vh]nyCHnt>锜oF-O];>b>Q5̓ud(KQ'q/Sd(0:L~O:4wd,s \h1+ &$u,26yp66R!RaMRt8cYG&7=Zi,QωTF<}IuLi/g@{E͒xqȳ%ف(L*NwڲEԆ2=pwnzFd0K9kPe"קOBzdc+ZOVNڈ. R M6Pf@>t)ɿ ӈS3.LG.pi+j)ֽn*ZOx[nξ*z> U՘m.׹pE:N-.8=ౘSbBXtg;iް˺_dU} ~ީII?dF(tTkIg} X%Nq>@PP0I)K6drMc}=d(Yo&u:<K2;e…0,.h>ߏDP8@D"dTlaڢeC yt-G0N(t uo4G^0v](Ѩ~>2@c2} I<@Xke4/!yYZ.? ALrj:Z=z/P:&|O3'iMF`x!kp7ѓY58lIcTX.KaDҸlt= К*ȈߴObc3˿[%^Jymf,/Hn6ָxpՑ|,J4VչП}h*G8xD|j+$m\kՔ W"Ty'/l @wfOI0y$ Q$utDOz~$wNFT`@-*Ê֥;5__}-7L6YLUl`/nj'kUi T]>'ǓV2o1IYh@M';6 ^!`WPD0FE(4~}0vO̰!T̕b{$6z1! ٨؄`[יrЊ% C/ΩMcא!xVA_Jȿ[#+rAgU K$*5EMuȡ]E-S6M=>V&P|Sˡ2h 8kFk Ń Lf՗ wO z)wl 룺1i:KZ:؛!-OZ)uuc_Y:ъ| ΃qQSjFTygCW"ָJFkHF ן_D1,Z>*OKdNEa2.W}{جW8o$B G!qڎ_xlٚ8Th`T & ga!OےEi){?YRf3& "!"T Í 0XAT)Z-RI˚@9:ֶ˯k0+Z_@׵Vz\^~q\"0w 6oV|w; -[Sj= 5 !Sr=8W+ @i 8L0E&J2¼v3Uu֋vG&4mcl@D^lBYxOt}w1`u'&ap$fsW{ 4qƋ]'xM?' t?$TT3HzTV=v}Sr*M_xnGη<A7ϸzBnhorKpD9%L)-k߅jNDX%L_FN.GJ1,\cr}=rY#@g+ÒU pT~ɍT6Q2 3Uo2\|<(SMlhxO9Nf4>]ߜ9$UrP{EXQvHN7V>uh{U\`XTL!Մ}F)R8$E3<>`sp3V$N+KٝXaf1SBgv}Hzm8ASfz8"X'֮]8TB3Q9o4eQ]}o{ޮxԵ?"1~ ޵?;?ɒ ) M ?,Bc8tYR(Kc퀢5(3營gXwlv> zMitRz۠pHwqgQ^B|!5l>&NYN.GX2uY#bE307"}t[ÒYm߱$+U v#,eV9ۑ.jތ6?_V\.sѴm$+?MſBMIr/+imȞR7fN=q7 zY`^=N'C>6C.$}/8?0, r͖1&=j>qxb$\9ɮ]Ȗqc+*%`F涷)>zy{w xVmEr <_/l }΅ﱴ ӅLZ{{N]̓wʎ~{L70ZgiÐG#BPLr9lIX;+=kL] O1|o-qM{a__BV˔R\Gmẋ~1D.}="o3B4tz@\ޣ<+֭ǖľ+!<`TJ"*nz,8J==JQc6>jiG5$B:O@,V98<v${Y OHxd٨o_ЇqtO|f%'x\@\FbŅY_L#%u=`ȊhLo8]"Яm~ l[@V<9p!QU &p!D_*1N !5Hܶ@m@F 9ziH#q((80ڕKpޏ>z1Ihmfhl50dCoԲhB|bʒZd S邾 w EnŅ ZOɗAj1>3lwIrߚ u2 5p[MY' E 9ǞNa?Y7R4PSvUמ05u>չNgJs <ϳS:wqd>` <.TܷPaqJzVcL&j;m&Y᫋IGѐf5Dagd;i2`j|?].A-F"wb-buڄ='I *DbҘL<_(UNW9esn3o8;>2[*\Ó9"㙞lD"?-ce2ͬ)e'eYx{VI ItRj_ <ݕ7E@89qT8 kqBu7kmc\,NsEĮ"4[KAj#e3HpBܷGL19R lx]_bĕ;^+_ZiAg})-NAbrLhCozOG)G,Zsj6{^hsrR.z*SdaN >@OjO5Ժbg]P!$5B&s\?/'^<'aX&4xJ5kPc<ʭ)φp"N c^iWAr +ǃa5P{U6?+N(7@J§ˉ<2TWޤYa(QU"ơ_I|VP&*XRg5u|n%R<4y87=6VUW\]-j3ª8GJJ-=/ {1PA* si"Mh" GԅEv5"'^~b0C[x4UbZJ 5&ZR#D˾[/ @sk~{UK~~.zz:7сpk+0t)y}ᤦcfÕGV j'@LP$F <jc'YOBo2ǣ@0a@0 NDEXҷ76/f92WD4#?<# zqWRk}%Ȋz4z##x0wɒw铒`@`1TmKHlt$ K^4:-LH ~SC>CJзES92fw'E<&\ͽtC?; }lQ6cAUɉDpi_e e^yqAr"+)Q8XXAdj0 6'}a?xwAng}J[Ź2y=OtXzq-Q>6wRhԮyn}5Lf $X]Pj9 \7E,<9iC'a,aS|N"OdFcCA9u|uss:Co{nuȯHhˍ* Eyйfu0[U[šF$=)vǗbMNG (_\_V x; qsIٿȭ#^TXn]ۖ<;5kK *-(pz YxB_,Nƿ{WH!`rُXw FW'X{W}Z;ϥM>].(<$it`!4}P6k/뙍\Ys4ԲHf5o@<ҺQ5˷ asAaŁjۄmIaL5֍EeMƵ %-W^'lQi~յ,xIC-xCl 0l*1 K Sdzu]|{`k}Թ uEsSq}voPbd|^]IyoXo 9l,[him 11!u^61,g۠\b,d_oMTT/VL&z (,k^bX1B]{7/6{VMa1 gF 2GV'TxϠEbluމ_mwt"-MUf~`hC$\#AI-񶴬*+bZUs4ښ0![/F?ݕGk>{S!6@?rm ̃M!Z 1[*SwW2b{"e@6ebg"C_h^۹)zuq1 2mZxPVW;Bw=In9 x_#s#I if%# XNzhc%xBXׄj|A-،]%"sMi&+ZsT z㯶Fz3U1tRAY㈓T+i\G٘' z60+C aE5TqqCz5M@  IzPSze9Jf:@zdO̢ETĎ([:C?vX'd OxS8q7Lм0GS9] S6s8n㈪R-a=U,ݳ<ɣ,J޾Mr5Զ#^Gm{j7sʺ_=m}O0]|!w*;_Z'0l.FʰӓiL hq%885A{L2 akߴ'FPx\X.*WL4B;k)&@`G\_{VH?VJ{EPN_΁5l+ӌ 4T/,Vj_.u|xw-UJa5>-Fb汶).N3}lhϡHuS"h \#Q2lMNL`>g 0b}so_WxrO7nJ @//"윜^AX dC j`G Z砸pk+ ;\F7ru:eSf4EM8"/m?ҩ;;tof:ECP|'ˋ&-fnxkEPG٢Vk,p]U! P8^?Mv/E!yWR%`IBBN#_b?4D]+.PbzvD| *0inp/xRs=eHP)b~sx6~: H fyN{qinw0ݾ#w] i¢[. 'VZ56PenS4ّaC':ĠVU 9r\^tdYy;o s+Nb1_1KX%;P7-M+*=v‰66?)Pե7dGdmj J=vru=@Qf20G۪K\R>>f2,JRSJǞxEGr 4'qmÿpGkyR᜿ChAfUT3ìhs+Ja/FUWjzSPEz[H?]&$ v_57p!ՔLj[z*NihN%%I!.7t$UfF_hG=fn(FUfP+ic6Vys)>`s9@Aۍn\ǜ[5䳀67oL$@yCoyάừhZ~o=0춗ih PVm|6o$_ޅh~5MmsNmp]TrZC9}5T'[uT_^'֨Ꮹ[.V\n4znrmMܹ0VA;2m B 2&[+T nďS| 9T4z;ym/ĐؤDQQS7 8BAF=GqS*m\2j].&61ʌ_>/Op ރOWZfmOZF`Խ !B#̐T9"͍UzvlE+R~*"؜N3͊&[* (ғT &7GEޒsw}6p ~ĀΤsUa, IdB5M(&OdKW};ptR{+$>u"JչLy l)L.uU27sRI&hWǟ;[y7H^@o;M4X5q0gN{ l ( "J)aI@Q+z( tÆ(op=:!qȘ2՝`:PQm ]d#0 Q_~ |f6vO~Ќc{wNKE[$0Ii.1T17M|pc݇7}ƴWݘ2@2k-Sj0uWﱙAT)K?䒈n4!ׅ@D2GK] +xfJug F[1Ma֐aǒXm(&*//6D\2@Earf,a[d)~5'ëOpCsKF8Q$XACb?I_F0PPjSQT9m946 wי*%CQ24'r|~kDuUO%;ˆ&=F}pqzdH%Y6͘M d& gRΧh'y2!gP *cCJOBց)IfҖN14A`@%'Ձ"WdXʠ%{0Rþ1 #!k6 RvpfQSN96H%ᣈԓυd(uCPyi{ovJ\Q:>C-Bgztjn8 ܍33Ju^@OXXw76ZQIѶiJf.m5ЗPhXGz w1ճ*":xsAԠ@1̍ԑ^5S|>ш(P'P.C}zZ`|pk%LNP3tg(/OϷY *1l> Q.så0߃F=x4Af 'jP(U9&j.Ho S#зj|C?LmN#װ]SIR m/ DCd G`l< ܍ yq~CEEBs< Rmt r#-hL y߀ax*\H"u:i=]r`*(nzOl-赵ob \?u)E-WLD9Liqr_?[KT?vYc\K+s+\zDn=TL@{c3{q`4 Eaa4 ŚrfY36Hy)POQl_(Ch oX ŵYmP -nvVwtca't 0q YX% ??n4\wf2?fESek}4Dh3|NOk uBP#ȝh1UC*\>tG&:P$#[[An NGm.8f"-XS@1evf5v'9+av qU*?LщŹRD BQ[yl!BQA>%u=c Vwq4m&VR],ĥ2dX>*P\]lo(4+ы6Q{oc6@S9 3gATZY\#@X7r-=$ZfP0Ubkp!2AMd-ԪGCsJ$<̒'kz/t9^kJo'i+%XIp%Jt#qQ8{]_kPy}? !F#E9yC3&[>?!!MI}mh6X3^[josz|fg.#tNth/2*m!݃[ .ݝ݃>{uwti(*Toճsh6U픩dX˶](BNܘ3͍Ul_H2͍%o(-*w-S+K4\qiH?v I&XNS%AɆ0/-vGo>t ֯jFCP ExQIySVܞ:5E|sj向3`Zە'QPpN'J8]X# Ffz:zw(:^ss"$sq~C٨<;*2>#v'C{'uK3YS PSM}pṎG8'5 d]g<)ڰmrhyl?vBCҌB~|>_"8N ﻋ٫4Y%,$BR3X 9h98FINK *iur8B9賷5qxBfmz\}bd /v yݮ~eaǻMv^Ͽ B Ϛ2cIc1 rS?76E@*Di&B~tc);[Wxә0!,[V{vBVW䈨/=' uRYƋ0P y38^C!=!tu*NXLݱz.^-]Ly;>KäX$?\w?!yEQ 3$TNXD4Syt5DA')l@ ,?IGɁB,Ah ˏ")5ql SO̔QN _ɇÄPS 5Ya̶뱐?jP9Gˎ yjw u %GFKJ ֌(Iuf:͟VgloC(A)nB]mI<]1T(5U4}LFլSqŞe7HxjdX>n.zn9f)\e3Nc\ 0tvQ,VqG{~T] wuSЕ)#@ttpzdU1XbX/ZDf؇UBd٠ܪ}Ո;G9nDsχ϶O;Ur#t%䪢KJO:E F ,2jPrzl8ms݌Otg|x_Q-)3ݢ!e_STeW?脚UsfRQ[|ځLqp14ywŔj4MeptV;fH34]xqf_ A~gSnr)C{};L+["!GK-V`5Qek5yz)H*󾟸#Q|y6OBݵu.uMn<'NSЯ1eh-}1فkP]cgwåL%Rn4L+O+l '~o4C5.,;UJ~H%?]27}>ihԗ, g/ǬڋR^ײEw$n&6ftvbt W74xh;Wk9`Pp&䗽TWE<_~p,[[aʴ,}HQCL+ӿ%=;S;xc#-[xOڸ Sl2ɮ⧇8kFpa22Lj<a yW<*] zbOgb問"g8r D*A~gH@Ok@Q,E 9>=>Ti.|8@M9c Qo~>X}g޴͆fҰl_z:*^h<3`qN-aϰ24pQS RD2UphIuI "]êj' A`hVE8j>A4y!%N/k[ vP|uBj  w ;`EBф;?z}dmؔny8; 0$tvQDޅ,6^*@y+͙f5je!DTr _Hk)>ν'8.Nɏ2À=a4HPȴnTrdYV Y*;9c?ˡReƉ?ڭp׎=Hӫ$jm'< gcU/|t0]Df*`dWC;K7nII ~w~>n)Z4kQ&lE<;-zʯ)& d3Av!`G{F+j(D53rԦ)r/$% I5>A,{v&QK Y%htQX_y 쉡9q߆ 5_gPo-3ԽHTt6x%QfiGt|>ɺx^cKup -d9%jKZuk,Ml$E=aY=8ʷʷO8mX#/3ҎG9#ohK G9>m*C#3^t!֝3H2RRdVOd5da zbWRGkUgZV"6y,Qo=:Ni~}s#y J SIYƩ _G^ h .Goj &e.{bX},Ʒ-u,v+[a+$Bh&ĿϭZ.2Lv?~JV̗əq(md*ĈáNL~z QO W4PJFڪ]1hꩤ#bV5Js3@;}( 4 BguFQ…Huj6[A;np!\McQ}dWSBPBP/ExknN,7=(Z2.K)y!^„ښ&tI5ٚ n զa:3F;H4]`Yf{=? WC"I R "uKC;iͼ U gx(&&z?N,䇼tJ|E/Y7JkLhʥEčʏoe-*屙Rd)~Y{Hu9]gQD^@1ۆ~v+O:~6EOmsOM Ml60X ޣwcWO4.FHZ:az nі0r#Bhd6G.Z|L#F*!Ev<c&Mv͏/mB"ñ}D[UR¨Ql?_MpB4B78$K-m=tVƺUyZLDоkhَMp.xӰ&Ғ VwHSíL;gA&(VJn7I% ?p9,>BQt\  cW!\;D+ޗ1սV.GTdROw-OeC/ 4a' v!Gq܈˖$ڈ-AlwB7IO;؏Z,P^,cxE5o$6EԤwFBmA==^8Kt4*HRRi*LI߳{3n̯$b11I|7'r-p[3;Juk7w՜ZZfuG 87j%)@l'9F^g5j& tje.:Ö5 vcRko.V&9-ǰeJO81;V:{ v-c~U58g퓉&b56,JOeLqڛ(T *On=iQ7Ḓ$)J$2)Ņ֗lc-Ų[F;DP T񹉀t|իh:sZAKSo>[zV [.b=ϝwbl׵r-.#=Srm T'XY(o^?3=9џn!2R=ͽt,:1 G,Fxg4 LMJ33Cj;Bʀb-T8.{A@῎y^ SCMUÄG#{ @ :gVE?;Ptk7=Aߎ4253L:ة.z\j:C":qoܽL kSq3aDpRQ\7o AOS"'H%U&vwǏ֚>R,;*7ϋd 0t+SL.kJE19t|uqEj>qd^6 dk8l&a'MW`kjqU /۷U24H{%pIa_ǔоå` k=U˿]RlτY7t.{^h@ѐzBmHG {+B{qT|gZ坛"y]M{~iI8"&WghybU.\".&|GN#iO)vS _>^oWç9I gSh d&nՎ`\~ 5gi@$ddCx !DP=ALflc0ZYDvш1)nmЁM^+ۀ,R1d\mq 22gf<.P{G_^{ E2$xW:]B %Bȣb`=& ~S|6X;t?pɪMˋZjUlxwW3uDRPVBh Ϧd΃uaB}>z1 8$YVB:uՙL\<;\L#>!N U=|KKh7>Ɣ3`8܅55}E]7^ͪٯM'ik)yæ睡Vd[p p&":lI]:VDh*9lB+@K&trȈlLUc"S ĸ^JMz8;NS~$RU\s.|άO%-'rpXvyKYvNd SuJӠV奭ª蜭}I# J˄7He5 ,q^B1+ O~,K!,AkɶVpXOA BKوګ{F+;aKO>L.tW,zϜX"[íX7 <*.=`Bі=SyFrda͗q (_̲=0^Y)t#9AVj-0c{"wњ՘I4E54=~C b<֕"Hv Ao}8>.ːmʢ(iX&L%Nf6"bSL+W!Wi ,7X*Ϋڨ\|ҐuUw. 3@۰OE'"L6Eԥg߇300[Lt9QTJǁp>HD?W5éj01(ݔ 8S/u3(|t+ od,ׯɄX]ʺ 68l-O^w @r<^ bxcvd"! oXZAmI_1nxEHδ(c.)O],)Q.`~٪)I}'*ŨR^t}ٍUo,OB!tD+NdGUN48{ 7VJ5=1EV$0IB4R0{1ᖭm~ԣw!YC骡]^"Y<4nz߶.4@O>2$Yѷiv`[P+JZ7Nl6;,ģ񥧖^!(j\4ηc= [C~ rEJݧ c;vKq*0)0.Z]=L(.0ƽ7;v_dם)}R}J~0+/Zչ SUPA`0N_QQ8@]դ]o4f~󥦭Rz%πr ;KLDB"cCWJlgZR3C؉t$줿ϸIRӕ7N_jvi윆\c%z͔3CZ)J^D\(ʰީweMPT.i2W^$_*_eJ7B)j.Ӻg 6dO(@~ Lc?5BKRa3eYq#QDGz4eK t,ӿ(RBVJj⫺'2^^4|՛eU,KbJb3 H.!CV8bɀ5)-K/Skx7}P@:Px8ȘVHj&U?Y O95H!=.c̯jV';1A4!_~J>Jt3vH&$UTA³k;0U+ !: DObAX晡XGdOn쐝RwrO3aq݈b26q@da30E̻oE<4<|b<,|9%eLB _m"9I+nZ"ٵ^tδJ\a|#IQ"R((l,E)_S 4V19-5͜79{Qb3OBh$&=]AX؎Bsp< /MYUw9˹/w*?>i͍҆i0ৈ4DϨ#!4^gfHQb68ʲD1y~`uLM?tI90 Av~9#/70A}-*O;A-Onj"iuwc/!C8tghYնGM,E^|iCe$E A-3RScz-n,*gefQޔ1`u(ߧX#{g,ʃ y  1Oe.73մl:T -EH2Nr6%`Ea:zI}U/MH*ޠ-#0T]%9cpel4b Y ђnyо"N9RhE1\Hwwi^֨]F,\(:~ޥAct{{:S?S IG^DŽ|F%.bRf0&*R.%>/lظYE$KR++^b;|z f wtY<}WҞ>֑ټ@)]X&¿$ʄA,ɅN{gZyg!٢!^7ǙRSDwK _8 ElWa hN SyNlymlO^L+fpfiK7v֌Rwz`y>MaN{nCNJnhۂl&>a3DZ 4"|JYI᪕i63w<%NXV-Z;b_6Vwn ںc5!YdxL䞸e_wr'b JŞy{*p삷mo S֥5K `([ltVڜ)3^da0:yRR8ͥvBd!9qY)bC*ؽJt`G-򓬏. pٚ.={wa0u:!C Jjn/m=Md5w]1 Bp&荏6"4z? v ɉo#2И抸hXUC"Ɂ9 4$dG:X/BC&Ub&K-z(/XR8{]"MA6mF.hQh; phr"KP<0 IO7U->2Zl<ˉȢ͆0;{0 }nTWLxghI;|$yi {?h8b`0;-[n C6f>0 Qg=Sx]T<\XbQtD,l=W=`4U' "yY I.٨V4D~dH}e?v 0s!:}' Ze2Aҟ62r[Tb͠K.\КpJs,[s PМ!.6 lo%F5?? L]w< c| \75F0d߃#_" H6~D*"#og޻novWN>^yƛR71U>[uw Ǣ:~hAi7.wTs $1y6 ay@>E (%/2Y~xPXv >$-Sz.[AZ*ARytLjnayC$*C܋B>i޽ iJ>`!9r]OD|p8-vze; g)Ě#"<fm8kiaZ- oO6.=ٜ|~DVIDA^щ5%a4L +7>M|~'6!nd%/6ڰ]ણr6z C1:AU.OprReVasJQz횧d'*!̚r#MjUC@K*F!4mQUudB˰~&o)SQE>1^\mZsc F{t=hTu|s3vU7HNWovR$7\ A(F(l%sp"ki&;Xܧ*& m~^Inh|YMo-SI︪ YOДHd7-=^w X,7@ P`}g?8w-/ !H6 }j2 g½hȰd e7(b #l| X=MԠ+<4r@%Dt܀ 7=)~.FL 𠛌 Ɩ_vٍϡB@̶/|HiXy?ْOߧtQ UY0ȐĵgK vzv}X)@ml3?.DtIxՎFS45 vVCiwEm,ތU1F!j4qwi9.#r Գd.>NV~`Ϸ ڷ֙!?Ybi( !te)cw*[DIQp|ok Јӆ 0; FΤ'wG"L?tph8c1;uWqZW>N*'Ccel~L-E V(=ү EOo/C U+<dž%?6,ER rwKJɘ,_~ oj:Tጺ'8.9)mt9 ɭ}wUNi^T4T}G7L5ͷc6VG24ebP$e(TU<*~ ,$rxeթugmʅw) 0%JgCyf_h”SrTFOqE~KgHZ;s[Reh]26I i9p$ 詅=VzyFib|~12zىly[~k9͓,ceKCy,>:d,xǬd[ֹϵ΅pLTۋ!,qѿTEd^]s'YFl>Tttͼs# ^@?ئOCT Da mM.V6/.DOW- Mniq8&<'~\q4"*7߆ٓ0zMU{p\IQ6dhU o*4f? Rśv_{Z CBؑMpj)ӨG$`vX_!@n Ǜ!"k=aɆHic:C}QIh.S"JݰUDJ%[4LsHgmV3]On< _+CڀszK"KgM;љ )~&8^fp}V-ܣMџ_lxy:GY٧KFS}(%NV?t&e3u>R"J=pp-iM!I*˩B\ xSZ@1+פr4'K3`]WٹE^v RcUYuօACx)Ecg_8ؽ 񣷛:NL'$ !.VҸJd5UrϏ=~+i>l!vFቜ\X-daRC>B8|D mcօV_V3[әITm0vMD?9-$vh=0U(O=S m4 ]h\ %qҧ% E韆(OFGnpVS^M"6Aš㼫{aGnZ:ODˀ}@wJp Ve,// Nz]HHUSS \oso})zyow:=%ȓa#hǢ4Ax&t/.~='lmw&}X0~@]׳]*:JFe]wk=6{6Bb)ȀGP-R9SQI8<H %"K.ّ@Z@Ńyh"|nnΜq[$54*㝨~} DVy\8*Ԑb܊^H2צ8Jzh xem/i"3tN<卫q6+-SIf3ln._!aδ6H]?"%dMŏ=tQ"&1}t\I^۫%~$̝Y{T|oHdo٠'(~;୴/ղ_I $5Ut& Y(ATJ7.lLT@dV`ІoXt;|W&״ i`03 -# s|s) ^f<9 W؜]K)3ۯ1sn+*% d´,4HiOj0mZirzTgҠCrG &4YDݽG/ zVY2xќWo`^^xnݶ}xDg45£pk*Z2 Ȭ}Dtɒ ~ةqṗHn2wOsQ-"z㩊 Mk^.r:NƁlӇ1R0+{E#5I DI󂴧m2"W9!Z3| XFW>l=+<nEChdאFgA(ev@on & wMِ)|P-gژhT$xI>l갌AtSn&X*!:LT@ɔ,_@dYH*{kXoj/Ҷj~S#8;'MHC:=}[}weأ̿G9cHV*֡givN1K|Mq*÷ҡ#GLFlyW17]6~^U6cI|~c5t?٪7wWpǻKWI'j xJ+@OIՍ<|! ]0gaR/*0̬&BACcq>`WmX>_v>FQl5kEh/C(,,{{Kd@F6 -pCdp=Op,^$ M)Y ϫB77 ϼLzZ xؑN-z`j[Q3lAAMϨV x6g"<<ϼ4ݵ5exbw2JLhjv1X xCDZqUg>6ґʡL Pe! ~> h{6٫~)} ^/'%PieW55O2zwζ[MssreRmO)Z(Q+DW[,4{G(Fd}z !xkgMsŒݙϙ\爴hS4LlmOf=&r07 w!ぷPcs)w=.wi qM[g=(GR\8WM%8PG6PwQuRT8[0'C7E<]w԰ AYhi s*[COqf9eAGSGsw8AO"(ªaW6@,7dEGNmqͨե':+YM fQb>PHw0ěT޺QQmOH즶x# 4*r_l[&DI1TaʼnH,71dS( \ \j}kD.@s[9uZ9 Ð-Ɛ`d5HR4epYlH&!-?jvg+4x?_%w{FgS.a9v$|n,D/2 7w:Ѯb%pY3= T+GtoFޜ ]̄'pN8m+s7ctםh|;8go SHku|]pā6Y~}yRCSIeC؊\hZ`>n\1.[J/tWveLߥ/)BtWH_ՊՍ%aA? g~HJFy&џ!!H9Y坤$3qBZpU7%Ġ }V̦Y;+X8P 5BZnɥl"H^x 4jR-ou28-vRf)!$ RcC K/nr<^j E A._c Y% NJ}H {,dMTw*#od~D) 0s`{ѫ_b ^`U?w!ىjc*cvf_)+o_":jڅcmM\1f.c_Y=Sd͂ GZP͈Ӊb=ny`ƕu s_uB/+G9v5PbC%˔FՒ #4un_4iR;yJ4A76 6mᏎ(= ty e0}O* Ҿ#g/Dʥ^|Í[9~;6 $"h~!.*FtqodG'0 EmfJ$"=߃7Gdo6y~T[7zC"Y\|U^~ 2z~2솬*fqu4`rJ2,b#u+D.dz,:mptzV)G^3Ahdo5hBYGX>d(ӿ'rgX78*֒I[*T^ <[Q7Z-Bk{1x`=8XI":6_ o{4nWVD1Lp{{cXR)c%e WͪX e餫GJ}_X:iey%=S9k7rX'MT b&Xp0*'Z5m[mvOx!mUSY wquE _>u*]lrc|uU%!dzʨ&[fQveAk'17zJ>7"f4V7[v];KGh&(RK%اYDߟs/;# .'Cv. eE$po.>V!H$EH_OK >U=rzOblVQF9 %R!S!DX/t(?]пa>gzBMk EgݼWMtw>=T2J&k-ǫ̵3D=67#+I/ɮ3]nFӨ# HtD?oAv.DvsuQ`C6mj$5!&r#Qr%CcNKtS-izy6i+9R  #GZY)W Lw1Ȳm0bHW 1^k`s{.FlIrj9Dk>/gY:CC6a,Pyp~,X&jsT4#Y[-=JiimX*a%N=헛q*>F[y7B<}b!`~A-;ᾞݹ]$ϾۢGȗ-?p]U_Bڠ0JlƄݱ%ku?(㭠'U UWoDQ9]wr5eĀ]RAI"rgч=bYe7O:]O^s吀M2ZFA(ԧ_zІUFmt"S2ҐMYKu;yV=r&p?|<u?8ZۺuVt']R ~a67^Dy j36dݲ\qp5;2o=",x)w:hKp;F2R[NTEFTQX^6k\atlp3Iyo _Rv(mcNTET w4Z57x&F:{m;t5=ȼMv[EB|s &?E-*מwcׇeaK Tj UZAܥNk]G|Uѯ?^ }S+Hu/~{ npƸSVKc8)Z~9+䔔ǖXp+7wogO)_7j*UƜ֚hqZxm [.g.vfTCC۫³y0 &2Y ]sH$B_SߒĪg$^vKީG3R9"Z *{y}P{mxU+1ZLb6cňoyؓ,HsWt5Е7o6ED-oOKK:tiR; urZn,֗jKG q Fo@[(VԚPB8ߓEU'#HU6cQ)| Cm=' z?q\+{LC{ww褑i <`3ZH?C,jj?>c{c,/{gxv?^s>9ER_od,xks0b;o u{k=WzݿnD%ҟ#l<)B$b(UXEt)a嘌$5c wv8+uSr >;{C+|՝#,rFHzn\R#'4ӡ$Y>`0OiҎyxzvVQ(=1hvo钫 +a+Q?_mѹx` vӿqOɕ%CFZ#nGs&cRtޟ&i*ot # 4 <9í+ f[ͦ-g1 ߸ б/?;H_~3/˫ΩQ-y_,JTהW0sKj+q2_NnfGB#NINکmU>z-jwW[X ]5Q菢SbՍCAc˚v;IFz ULZ?NI _uoܗ>VsԦ)$eѾq{.ZPY^z[!n̸SCFzFN`5_2NbJlޒT<M/P8랿wwZpjVц/fR,>(IeYgxCw׷~9cAu֜溼V)ձ9Nnʯר5EGΚб,ɯ*V;<F䡫N#(E&]0ݼNh4chcp>}lv.QhD1<3+hVƬ*ꩩMQjxήrݻJKw~%F3Xj|fL| i*.]V&O"o5~ׇJF @VPhCb?t+5G/f+t;.o+R 퓠 !ŝ_gsÓc GEK:b&</,b&e6n;j9/LKlfY>v5ڭ fHv43I6(8W=$o.*,DNVfn!K);m֝?j<; } 95sxV_K `:R`_iSo34N#x%s&j|n+[;{͢ݻwE~Qo"Z.7$j(^9ߴEL+qTElJ tOƺ`{s:lޠ4ViP+NLXoqcQ vFy۶ W-Ԋ%۽9Bi( KVrL8Xm^Nd_Nϱb_*1,c>x$21zet0EI[*@A$eHD,)v]un 7gG:-r~p$ cuj˄/ 混oҥoa6WVLQԆ0*Uvz^), NYT7Z_ I+aS=10@T=^ 9B:~Ov-&5ơ|뚨 c%m!;ܽ~xhh~@)"w5s}H ~Sz͇%;sz-coEh5Μ2y&r}l[`H']1Õk $)Jwɗ[ H~0 `JG=mk[x #j7/j{GGXIHzSmZWTd.dӏ"_58w!ǽ]K*s:Wڧ?liɚ` 8};Y!>ؽ͓+|.yy5Z^3gZ32EǽdT_Š^|νZh>A-lk5*n؉fTF)@?ڤlT|0r:9BD;}_7ev$kẗlvf}~ud[|j;v}lYRk)$ b̊<=/qT-Q,yw,= -.dd<o_ ]6O%2F fz+d`ؗJ3-oeC=q ]dyS51Ѓ2ӔV.5n8̧)Ni6_%5$aԚ^lJ- +qMܜ]]G';NF]pU ;"s9IzRؚ|;W!ndȨL<5OY8 6\y' CG>E{>y~ hi+jܙVz㡲 lڑzi"UPTq빈N֯Hl?hsIo/t ?dF|xl>duWke>{Af-qfR!= qU" b ƜhnնkZ]>vё%\w!m֠H;-aF0'Ӌ}ohdy.?%q~*FȒ)\GiB-o<+CM3&'znޠEWo)f s3fσ#ߧn~c60aIlQ`bNux0MkGSn+<ڟ?SN CZf#k~얿̖275ܔûlA"Yဿrd9 (}f"SVGҡ:#% /H4reC MۆJWDzDgKt0}EPSo-^De4G#{C:JLv\%#dj3VK\XDֶyՉw':]b=(o}1=7-BJG95WS:-9G _&Jo}t{2eƑ<,[\b!;H/gP[|ή&`r_=PuQ#)WEm&1f~ !CoHzOKasQӚĿ<F5`d-_Upr[@qiqOK-hZ~|T72ENr=]LjkTVc2kw<'ҽ8,`BGA\-f}]qo")42)` l}uZ~?p6w:&r#Vo G]Ow dٿ9_5%kdYˇ[88 -Czhz;sUnƤ/^nٽvd$㇨v?"sQD}j{+(L2WΛᵵ:&lkx59Z<ӂLK@C`;"sKUC-?uCoA r܌8JxqODb>߸{[ h! >~yjv!2"ii@ zsXzR;), vЈ";&r aҭ=,ɴ_mԊL|Y< ;Ы!wnlieJn~fKuy93O Ai67t|Qt5u2Cnea/aL̶touHn @Z KK%Sq{JmkEĔ^%yNC{K$5Κtl w/)Ț}^]tbZ2PmJ)"r[xۗf[-j(Pq吒u @dv7ա+fF큢]ۘ+Z`4|\t`}n}EwIStu2yPamCdypAܧ!B%GDEey]9uM+_1&+/ -6e঺-aOr-¾b})%|~/r63rI!s>7Nz c9ߩ#EM +h#ȷC~{ntH;ͽc 52V3!qSQGB%̣Jq>ypqLB0_+Aj#sKJ^  K(;9ڦ;5U0Wezsɞ~l:kFa_/6(8.`qX^6 ~(y#|d(m &YŭɘE:G3>٩9aqM/-̲^ lV|ރ i)OÕUfmͥ"}ߓwoM% Z n+;T OTQ3+W6gXBWmV_KJqԺ,O%V`gp_ /,H˶dW[oɻG{Rӑ_yM s:LkVd(]ZRs B..|ZCd!TKB5* jBڕ\a= 8 \Bk@v'm_lQ`J 'Tq7]Π3EP ;}/9Oc)n7lϊY-i41HGc5tiI*'$PZa'BU ۹bDU%wOkܦLH;%XpvGF {ũf !U׊c)7Yx2%2]ϩ$w}NYB 2, (%;O?eo9e0֬N˜8p{FUQF~)Bbl_DUV3rwCx5|vZ~Ln{ wтCd0`YRŒLсD;yuۡw-YחeG Ss=FBP9>*ǞM'FTݩ-$2v&zQt R;Tз?OIi8SD &MKaM$I 3Eh;d2+zmLyӥ?~ҏ vlz*. T_IK(1' 15ὥ3&[>z_̈iȞ&>XEVDwa/^^ɶ;Z:LL-ú/yxYr˿94{W, %6"_~8-MXAO̢z$&)&%.)%l֗hmGcsQ 32 fS(ަ*J~DDwvwϏTv {QwDm+^#ô"LXkˤ0jJtV2u݈S<]jQ`K%?KxL%q,oc qJc k ?t^i8ING(Y^ԋ[{SEvk; ^StdvǕ"udjD܃:' KޖBl h<<0UQ_]LN =)n_;j\AEk0/\U.?P2hz@NtVy8HLB7f1.ϷDӕг)HW%Y9>h$,i,z$/BjdQmsG|VO"ng()i2wq(<_r #05z]B"R\kG1zn~AM)xWD`^ΫJʜ!(0d1?cHrHgl`T*TU)xc[l}:UuWz 0j*̕.ڶXBT5ǐT{~&)q0 ԗn9/8 l'ޔrBh0)cՈ+ԅxIБ+UԞ {߹y (S/?c=jG P\LW2ɕ_(_KyIL v};i7tM*W~U|gc| ztAgYXgfmFH0T!׀k@]%7q}@2,&'fvfN(%hkcYA HRbKmmR``hx#uWi1/'n+{gV̔,=̲vDj*ҟc8[))?q26vz;͖Nڟte;Z>: L[z ֹ)?lW@C*U iaD\t]Gb"Q-y{/ jjcԿ%=zExM[ɑYAvz~۞^zyR1[Vpy  âЊUgcRZ㢋eOK}imEjw1KA}R w&\ܛvmRmnr' ڜZNv8w:Rm OC$dWĆ"}^ed52b3KT`f6/!YֽL^sWJxWOC_kNubŎ& Z H} e}:][&p7Um<@l1)8LiLѠԆ8<#LB-|68 3]MXasq*tJ$$ɱ"fv)j%]Ͷd! 5En1C G Rk=O5iDHs~ϿNb WP7LIMs{akM:^#[ڞV^.Zu#LX40Ԁ2\EOh?^SϠci$S^ IQ,+;1&N2J=5]G(h]_ƪ/'a dl>\rfBVv<~;x)䨉XȺyaض|Q3GEeV 4HI 麇KpGb'RRYPGTr$Po<Ҹ|Hnɇc/&}B72l-w{lCb?sEG!;Qk]Oq4M{KPÅN?4EijUVQzW cǀs-ŷѲaj+b{`Oo/Sz͛al)@i"(=Nb9P_=+JcM䲰aODD>>Y/Vִ:^Nc iHɗ VLU,vΫ1cx%dX3rдjŐC4//qL72$g8vmؕ]}JhS7\ ؔ ۳r򞪷u]וb: 6cpU?fj]1<57_f1qhsJW u_%sqG}Kg?0=^Q˃0=:Lw4~k|ۡJ6M"1/|9M^_{2|eKtq-svҎ9ʊχS^z꒐6 [2~f4xW);#uƳ>VRܤn$ỺTL9)ϛ?k^{.zMRV-?-R~+MDb{R,KΌRM5%.A 8B<ŒRZZz׃vϕMulD*Rj;YJJ__#~EY9tJ_>?}،x@Tcr"J$:$$20NKW m*UbʯJIm ęe rtV)j=ohYY t9m \By4.4<5$Q=Y9.Q:J8+Fj 9ԴhߠߡL2Xt"%1LGKUK&OoL^Lryʒ!iPمQP 5/#X~TkPpRٍb|م I `V_5 5ߧ2$S6v;耙H)J8Y!>V bDeBB<{qj"m|&< 7f~!n ݜ0]ofSoWGQƮMu;1'L(VTJ)`v#ecpb:g@"U8G|tχOďF2ۖ:67*QVZ2{VpuvT;)ܒ ʇ/l]bSKө$Z{ʌ'#3"#*H!e]u~fKUۜGz)qÛ1b AQ%~elj^y(csKGB5kdru%$m Bx`((cUcZ'@/" P%D br;!)/<a>6܋hnF@)#RER@L; -q9H%VeÄ[+g55K'};d"Z1xN#@ 9l<g>zً xB-jlMs$BJ7hd2^!d!ʼbSw `?>)5\$(*QF%P OFgg9d-N"\WLߒ!\/mdQ M¯:w',Ui0~F֒ 4ljzmU; (`9FP*.<,L7II7FѶ;\lFe氐1Y\E-,rA戟R*#w0>m@ÝigVw2;V'='!Ecn\3bc _;yaYgJ)r62dI@o<1p+AHbA`wpsL ެo'},|?lFU(RFMhȶ>p ā^G_F+@=n#E-[M2~:iS¶Rc-G=H 5Åa"J:Tx[#+s_2./TLiϛubM0px*g Cd Qg(~)<5SqDHuS]s_O:n%96S䱮7&pAIT>uu?$R!+tf(.,cknht>L2-g>:Iw+aBOGjw<| 'Zi Zt#qlԠvmo BayQOE;[S ձuytBLkgːc6oR XH7j_jSwN N Ɋ6l ύ@J][Om/AN[Ùe7CՖ8-z-Iid~mrsQH^ːx:_yPX.dXH tuRy찜%tu>\OUfB_̾GZ/!Y[f)`4=&Ӯ U2gyc|LjAh٦W'2L& O9SŲ-sːϢ+s!Oq~K]T:,,6MIv/,܈mfw#\s̗)ϸZwo` Ꭓ\t9MCZNNCک{ep8kL;EY'\lvyW慔kxڏ<_|ʹ=4$Mx2[:y&L|ʎnrcwCQ&eW>%"wBݩ!D@Zhy',k ,!w.%W!F ؃(*VsA .Dz=KO L'BErM2L9#c9ʤG 5CݰnZzIW1d6PR$W~0@ ahy> Ҙjj`FqRP TbV0] X~jgkgj=v,V?rˡ4ޓ?# G`ry,~dzC/;f‘o?Jhs;: ,̫m \ zÛm.\ۣϽU// g8󩱞,a?cj˄M:?fkamw2:s(|w $/@!!&m"/o`qd-YR_#t>|g3nQ+ٖ>U`큧ח2-'^ڃܱ,\IqZlef#4X)u7sӕg+]44Ps5$ۖa-EZ"}Y2TV>5F8r8ύOXKTVN6 a-#'` kڶm^'F!LDMcJ1CAoGka% *A10c-;:(Jw#n } eqϢR`N|(o9X1K)i TrM W:! vKLwRb' K(pX:| 9(рآS'U5m.@~a67ᡫV`TG5Q ]r%aVJF@F䛂`(ZK]!*"MÌ~.8ւQ׷-3yZJ}%`^ Sse#י a;7GQ[ [˥i282 D7/?N'B_ [Rq-ofĂ .F֮a|VQRDPEry ]i4R:psfx^-!$&3# ~B D aA[1A]wK/[FXE΅ q%\MYؠ2AzX/ /dn؏B\[/NP`)z"&gȗ J {KJ\hD'>kXyf`Zc[R{)59c;xnQJd'߃O&Bj-_LY y9,穱zKvrl^/7$Aoo R^u8&W}˅A)T*RtC: lB>Z1MI0O@EY#v|u U_?Iy?4{&ʝ=Jϐi*8ȇH(եhNgOc$D@TB 47iOh stzT%6FR?ݽPh\ez@1Fہ!?}k/WR}fL8ȦPXo=Fz6?35JF;E~\DDbIpc8{ԧ)ZPӞNxͿ09Yb™"#t5A6Pu6I^Y:Bzhp_aWg0גyX9FA B  j>#H2 $3Mk\x a dhJ^p|2%oB𡷀tl<(niL㠅nb&ϋw{ 7JOn ΃~]g%L94VMX7RGq\x_y?O^9i&> mui* 0M&׀NN+GQ`T4tg(i|,SB7WtXu3nQQgeMRFNY3d!lNdEXA@ͽ'u١m7Lk@DbTU:F Tڂ?Ǿ|KTC3.p 9͐ڲFu-ʂWwFֵ,݈}͕JJV~6)\TDohi󅨬u{Ն^sÿJLf%?h) "33 m 8ҭCt0TJC\ͶۇL~e6<PP++#$RvrFުLGVn":8uM:$ 4=р8,|>n'mYbN)u6' %Mi> AD=5cVVvbQ&,]Uʩv߼pdn3AZ]69k{#Ĝ/ Rl.86 6`{p,kDhf +[94e NnHkjUADߡbEe}.;n[wo1/8~<CEq̃E?^Kp4,cwYcp5৶HZ uNf0ゥpe/@k} \֯B€b# TTX! lSŜ.@\KN@E "DG<y)Bg1Z$Cܴ뽎=n70(V::!d ߽qF][} o%-4CǢRerTg| Hg^ *+d}fNC_ .j7##0t^Z"䙧5}GǑ/U&AL;VenPdS6T|Q3 FxLG 75[>œ(V{+Sh p .M1\.X}'=HU6.88b+RhPpӰ4&+ZYB pAd@,[0 8h.nS)&!(!l8.-<]ސ K5E8ZMlA./%2[ kQ"X!fUTFuϐzH7T`+[ы(C7Rn]Gl ,\ Af:^4s߃' qRz 빐ߣCx]} ;6.!GޖCwl`"ʈo04 oaY~e3aгU lIT QQdgcAȦ:z{-uvms8_r$K F b h=x^3eL2GqIjp~HM \}k>εXt x Y9J*,_iŽ >`l^IA >)_ }ĕ(EZB@tB0}hnxPH#7d a}S GGT1G a]+Χ&2^ДJMow>p#At v+kMYjֶZ_:! DA=P'jxٍ>Z"B&2qj-R"/R-:[P>-)[!E=$E_#)EC{ ]"?'7d ºAa&>C^`QKlQQyO2md(bI~$qM} {fg:wyEa"w'6zlM*7NW0$@QP314~'*W U]וgF mx,>W!BkN[|Q 9d=N8Ouя|RZRMxұ;hK(1'Tɠc#d|kx ҅2]L& { @ XKjo@(6GB\3繹]9t 5G068[$*."aAM\= RqUc**%\l3;w$PMcVcȡU_ 4poyd>>TC;m·r{: ,'9p"Y> G~! $h85$ӀQŸLjNG 58WfÛkTǫը-Je(JqA&< $ BA g)`n iϕyu) T|wD>Rn:k+*L~{:~:Us5"\I"vorLFS]Z~z),{rZY?AP|_6[>Is&1u5ͅ mkxc)>`Q¥?u.Ȕ0LZ\e}YEx&Hl3Ηgz[2ӓg"^xC MA aTאVQ2!GXUYIaޏ=Dq^ ҃Vdž0&[T2 h(zAeSِڨeU?20f(G̗`d/3tӲǥ[s78}'Mm^W|=,U)ְU|HZM8hf`v CE{xW ЉҌ;}Zvz*{cw<ޛtIv7"qqLl#c&&W∁$-_<2iz>^?˲FZ8N5 ӼuNAr SaTOiDpOҤq~f:Y1}gg\*=_V2YʨNV.;Cǃ-*qVۍNҩZ |NM*#'0 fxGvu>8{wvɢ\_\{/\N~}FhE#ɷw J9 !=v3!RC+ZR,iWȨl] : 9*m`>Vz+m3nI嫰=2L\٥n5ʰđyiQq%2~0bpx~f9_49߽RwW:cgP\ nbT +}CtEA_4O=6+R`}5NC̔tIeA*$ͺPS&!gp'Gj,_gV-n}dN++uyw᷿>O>to"BGPɈ ,Z䄬~W}Q`Q@M)Tm SlWnp?^%r^b!W38`DZ1.$q*t.BH24|>tg Bv3L$h .s  q˦N|؊]ʲüֳC`\wv ~XKʌ'y=PJ Wj(9fQ dh 3ny .z{Bhm :Uewegq{{ n~1-Uwm}B{$ gT6J&:xu4hI \ip lw놓ˊ,96TUg5!J]d%={zjtq-3Tgljv]l޽o |т eMgmm: IB[M9E)1次k %n(G%U}'1rc*|OfϠ?3,+Da@-@zK(#ܐ'3'B)#x(lYmRdRSFAE19$x=HxMS>ka!BĠFH Mb!gc ݋ϰvhSf"d[2& /G@DsFV%y%gDDb^Oe u6Qq$r4NcEbL?cxD2jJ+Jֱ`֕L2G8'LWZszECX0 T06"<%:b#+=BxK-1b}ės{A 8e\"qPђ9i,;=osg}+{84Og H+Zi "\K&S%"2ל) {Hv'SHC #p@C1̐W Tf)bBt=AaV*;>΄9#,yR5] *[~iqչvSjY9  "k$G8|ߣQ6sSI cdcRQF +2!\4.8,*7 o&#2ejU\qAg*3Ga?R4im3\` 4?0eDWDbCG0Bfbf/p T<' TY:;'LuN|֋=|sdQZfA8JD̝* AXGcUvy8|~z8:Rz !A˟@JX`ƊΥ_ͮ"c|]n\d}/wfDwcrv~t1 ,yP CRl/-Q^N>KJu޴}rAcZ ޑڛEt|x mR1 zey 5+өÈ8Sׂ;].v׻$?UK |f'htdFe !U2[I3^K}&K̤CT\4EScoF}z3{/0rw9E&Tӓ):]yƻ"*ĵV+qǴ˸{AI&f48?pޣYyr%\Jnkcq7{w݃ބRɉ>QT=/I?\%>"+گ1CP"c(2h #:?q5AE/dubxZ?Xk-t잾 (R/D͝u_!]jom{]a-n 3wΩ{ R _آakYQ)xk]ty{G.Wo;H#zsl |UTi>ֳYr),̊u=u{no{a 86%uFup9:_}ͬolun˼O]8EL3ɋc|EftLK-s7xy뱺b8Ѭnڊ]WE:d#{I0Iu&ehDndCS ⰅECS>ɶqΰpN%Ӷo= QPnY{C^(GL1B1Ȫb,N04<@H2S+7c]D<[cc)&!꟪CMr!#??6[8cu. 6`f_T?Y̚1_0i\ L𧀈6߄X bB Lp|<5c4ƪb-^aa7tp8iXDL \O\9Ψ459ʏ<6'9^GLgp1afvՖgox\HNlWMlHQ涮逯.]t^^)}}v?d.]䩛8 ÞKHx]v®`ӽ}1v5$jrv]nyV7˩);R% Ғy qi؋VHR%.|NG4IˏLZ7Ԯ?msZ~ uMq7 聛r@H%}^yPBOĄq̯7ς1,CbhSlUyOu%r46QAScyK{g+>8Fsxy|}8fYgP8n8ϧo1n?_pZŊI/?byd6T~gJ7.FOB{'8s)XDkD(D/Lkio )*!  }'`lgh`o% :@eP  ?   M ``PPp? ?e <{!tt7@``KX  <\s; ~lA@  Q *2;ܒ1+%9%Գ);ABBc-lPW!ǼۿX8x0q N*j\<|4u I.nZ:zbS3s M)i^>~fW7wK-mY9yаO+k]=}Դ^6v|?i"0?Ġ ?joPzgw):23 &(;ͱ )'BJ*IfvWPON1,|o9pW*A@2pbm+Y6Dlh~/xOOz5eUx024DN\gOՑSSFO93׺*J7uNpB/%xsd|sftjEWw%NyWN{qR}~|(~PzVu ]r+α uGGIp! >xg-p^d<g(RXVS#]0j#*Z&@Dā>"P.} pC2);FJo%k}AG>׎|TƱ$Ɗbq{Uq KHo\1*?(>G5ִb*v(Dp՘D3?f4ٞY:+{VxMmb#%5*d$*>`F<٣C˔DV{ݾ]9zB[U! 51TsnH>[E;mdq1~e+${ˍSyxϳ=O\vE$L Jh n ,im<ôP[G:A$rd u^'`ǩl'!mN"' q]Vu C=O=wny+G?Oh5a,AҞK!d"q= >Fxz]l\=3gd>Q^١o`Gֳx i~/`CViƧ͌D 9\j(Y_ՍfY;klh0 2cK а*?5"/[<[߳oJ2vVVhn̮O5aa VrBН+Ɖ[5]h-Efx[eX2T+JE%lTbWә1 \۹tx.WlTq\Dpک%Z:,s7ML/ȺxU^RiGAB#Ĕ\35kU.ʋ*kL'KWWS pq7C *qߺ}\::VBM~XGZ܍D%h^7a.6Rz*#8ۿT6ϟ5S&9嚉&E,'Ųv̋ s z0)*\[Ԋ MDȑo}QUv*='A|q}"2ˁxWo vYҪjAبuUz1ݒxpҠu h2]ʵw8q[>X;ͦjf7iܮrx'u +=W"s/kk،4o^!~:%FnZ7A(N8ޖPWۉ.^]"zGp7W4it` :A;q@V'4j,0t6YIN_fp/_,[1[+Wﯢr],$yXTOdB?;]FoZJz.O uN}dm}b9'` #m욼 ىPe(I k<."oHb9j+ |ְ_EL]A*QEeIMv2𯮤c?$i3D|P ؊o_wXL_oIO⁆n6BzCsˆٜ&l2}=?dٹ=yz`J`QU-aĘX:E*bnw-pS-m@&#y%Q2>L1 ۼȐ<.w*&{)!kARZb^eÇ.6=UXtn󫸥P EZƜJq]bUFxv!ALˆa *Xf0fE {>xCcm( x3olBrTaM'6҂;r?o֊+E^#;nT/FE&κӺZ%%\qpyF׎'PC=3ַ{|M.`Qe!-1T\i'8ә'1Ea emýUl{&͒GԳ'vڦ1ZMHB@1LviKJRb2. }+R.B~(ӄg-.]|IEĄDEͺ'5[dt˒,Wn⫮*~ӐL1*^{zԘ64% s.-- 6<(%K14:@FĶ2/Jz@{c W)k/p?1M"@hH`تǁz*Kf &W̊??0>!?|]2kk kg|ɀVp{>PN/['c*\ZuhrnW[tp{q+SY.W}ٺcHD6{UsCM/"bS"a: To[INP/~[$(0 N@O[vlr$YQ"3`n=z~L :rzUS[S*YtO)E|:v#qqϝ&@EoY0UUA#Q;,xʙ[N"ke%m;кsʂv$ům5Sƃ\a#\ vnfB5 1&nZOW=WکA[B ,R9r<"/&˜{sz^h\yg dAWXȷ{ͦ*}-N o?}l&G Ԓ[~d-l6LbAguB:# ':yل9B@L?d#%\Z|ЕmK 1XP֖N;jeÑ0ĐT c2}$nl_֚_6>ʿt*2>j>+eǮ5\Nau |f|`xm}/;qZhkZNXw,;)2> )6xbB#U`2ٮ7Rc"f.?;Ie#BgE&[SGܜWYݾxAJķłؾO'O` FT۲thB8=1 ܻ6S> [OMQaٮӇa"6\ֹϚzl9\!$ݸ۴x -Ll*]4=xF, [[^=< WWW!rfW@ +), ˏ%n/%MY_j498(p8 ܣ슋Eu:uqy$. Ms끹/7ϢAoieʢ\"m[s4,sT-v|\;puOd!I~vrN}0j  VHzBO~#}.*KM=[؏{hܭBm lovפ3!C<)o,2J3K9SM[R?kɮ<'G-W|,nSEM-K)3ń߱*xȎ03ˬQ>Dl0FSVDbo W> ܂"3gr\Ӿq;M_ڣ_$8R9&餆uRܓp}9g1d]5BvOtnF15e8m(`[ NB+uL++A}tt+1:\uZ8gP"ۢhY>Y]ÐçJKu-&1ښ젰+`O *2G!Aa*؋r-q=#٩4c[Zj2`|:\/{~%bOͽىO[0č.8n nqݰ\p8o\׶^<%o8klO:LFD!#"Zi2S5[O=aQ w?K صt7|/I|x$+{z49(r`|U3(8jܯv 1BGRl-+^\aZi.*^KUU %x*ݙp^ Lqօ~`yr*KJs)}sFCl<+K^6tkNY͝sCTs†C<ɂ/~tG.=>ЈEH '(4i-?RJia7,|YZWOAVLw7<ɿJCLoɚ#@>|` TU0X5wmnswpJ ~Ѐw?-YT% ^!p|wT>#\Tm5ǒsTJ[Ep'L=@`Tݛà$MџSߞ^ٵcj1ɟ;8%J4L.l,̕|RPRԽAIEyTگgJ{zے7FZ|3o' Dbb: /ΘW4R)Vш ƌr~$Ww@{䟘˞EawQ8q ڝVwK? BEl^5%=X8%K/[-沈g{1ݦ׾cnz]Ąf`qvF9Dc{}77dX&&l?{ PRB.]]=Ì=>^sf[h8h)-7z܊_Ұ}rw;@Mя׹+/%mx+4 Y#q-$υؤ%e:2^'$E_/k\P(%m0k4H 0w)D<&Z hI!ChyBh,F˛/ I .u<8քdWy e4 0mĵ:}L,9,igcۍc|{(rx_A*qzH]RJb)Tw.{m1mڡGOjKkdӶ7WV J{ܺ-F/KJyպSSHsQ>[/䴦Ki2SVNC8;Nzf3Ɇ`=_/侶|E Rc;1(=y@gBso4M V)^IhD>~Kc;풘 G.p̪LfXͭ)VvB8=ooƤҗk\{}12:\ȏ43wL5r8dyw0~c*y𨿫} Uhf:uYƟ&q_s_"5cg[p=_ĬrOK)8jr8Ʌ/K,*ux>N8f&\{!8Nn1KзX-3,l)9Fek~7<' E s] ,0Ik$$S"B+f,1f )!Vޒe3!TOC/֗U[=Մae|Z0kj %ڸj) _n$wˍ7qpYȅm,*gZ7½f9Hw(mWe27bDӡj̥d] [H*j):v4.nMɎk2:QUM3E$I?@⩚:(nG\.rܑ,Rl&|o};U]9,qlF6@Y$=O(0+Uk;!a#[!}6gjY w8ʐPEl~ګww9[ۢO0AN6: Q/gGm-NǻX WڞAon{sovw }h: FR`@X̅{-%( RccSΚ~N0lMS\|{;\\ȿ2le R5BQVĞ-8dZq!F3ghkI "0iX(Inf0RV3P[2r0a3C/ Pt }e3cqp]E71n'qF5/Փz%+P,`#HNTp oy| <ɐqslPcPuR-#4Z:lPq޿lRŝ/ymbbziѰab.z!j74,V>LZH]Z;f<皳 3ٕ3չZ0!tJQۚͱϞϮ ߿AhXCwsN&N6֛Zm]JYO@G䫊ӣf Ldv<Y)'&znމn@$H6#O5+:h xvwu{-f#F"i|oB| [ 3JW*6cTph+; u`35-vrTQE&j~T.gmhkծ EԴB2Zyrf* 4m38HJ)>E֖Q׫ 2{vi@͇=cK]S5>M(|1$Q 5I$.T=0./fIoyr ,m(eN̿efICel%]h_\gnvn$yNMEw5`Oh /7! N.^T bID{y!E P, A]xu'WBm!yfh1 pzĤ1ۣ+)XE,z6H;Je4ګQ!w~s5N1bQ`s"e#?V](/=~'j!>v=i|Lr AHPI3dri !7$p/+Ɂ[QSuPWRM$ 2}E+Cy5Q? b4R?QŃAuB͕FѠ{!ق8H3IdصM<$?OBIª/Gă|P/zx`$s-tga/ GS&mwsL:: wz>gpPI1i) ˃> $~[]=klB3*2 Gp3Ycɶb}()EPTÑtFP6<&e A MPKTZ[+YJ'uKCn./ҢtyX=Ȉf<@́x*I;"{'g%p!>,L;^NE#tJFdt#$ʱ6YQ+]"9+Č^2]+d'Ʀ9d7rC,0Lj41^q$# Dm2(ze&Tʃn-폽ipYZ0!w: 2Dv}(ae 9bnc6|J~%R?k%(k^&~'C`8KTy,>-*^ú.bVg\(<'#CH㼬"Mw// :aVL5l_9`܇*Tk zIߘ!FrB<'{vS{deyďN>oo{[(|CUi/V9Dk˃kmN ɓ;]MvnlÖa?L/xՍ:tv5{GQh>ԑ7+*޺Cz^ 2%U6BG㕞2%0hT۶_EUtf k, hQkL{n`GdB?Oo P5 =AZU  4[(Gg9VSh E039}>E"%Md}81KG !4 ^}uj8dB&lPC*h`SJ0 xḕմnshEZdJ Ug(]$X# ]H(=`Jip?5~KHr@@HlYq!Ej D{{pƄ4 |f V;8\vyc S0=uBkY~ ~LԽ/2W=C5qV=z)WwǞwr ,Y۹:hèSvWAn| ,Cd#;[g Ko-}v_PAl%dZG)pAv)EՒWpد_>|iz{~ HH@@יi/% 7$铡Ld/>o3*f^9_xO(h_~Wt{SfvzQrݩE?+_&n_]= ߚJ[d7}_lj\[-fh[>=K,ftOmCZidzalgТGWuYdU>v]ھqc~y0GLNN;M754I1wT,R !Yԯ= }٩jLYw(^tuA.$T*-n38M̏/%U׬_!x|̿03_Wl]GIEe{ `k:Љ :saM~=l;_s= QMi5cSEXhs2כs$ôUۂ쨍$F(B1 M d3`}Re-A̗4jh/:L%s@3y}=dǙVuG=³p+lRڶzP6՘ M>/L'PlK,3=ylZ\/ VCo&$^TY^Uyl4d#7Cam_pœp'\Ff {~؀rR߰y?YJ[w8ۇ7/t9n EY C ']h8;,:(p@Het|av~99 x*~+o̘[_/UTL@i#[LעӣdhPBgt>%q\Ogŝ_{th`QpH6[^togU:cOi/Oem<#Q3\ 9cʿEޜ r my2vy]=4;J-[jagoP/(䶿 SfJڂU1C}oQo7@o=t- _8] @ZS}xKK.9[nQDD]d=GI trXs /{vX:DؕY2 eEx9yg &Y~<1WX^ECڣ0">#lc2F_-(W{ %y`*4dE_H;8kgcz!#V0iݲY]%udܒP|WQ8qP Dq 7.S1^_B/Z:FoܣҤkߵo8슴@br2Z7Mk#s-YJ6T;ތg.7DB)-qJAH(bO7{`q}jMӲ!exBsRbKVxzpz~ mTh%kE6<ڏ`k8cN7BVF rR*"k_,\pKfE:ċ%+”4u z kkh‰UުlRar,obl+}5[ 1SD`Mq)J9,fJ &oq7w)IJp;θ_KebW?K۬/gjxH0IʮڏaF̧o(?.}pmF᪨;- }@$ oGlNL0,*ܻ,`9pNr&@\ lbۋkJ4A*]G ӦqBw*5%:>Xez Xe/ys=6_ PM,gidtu ]SeGz;5xUw&FS9!3fX;72LqElyv$כ*rgxIhEh.WIxB#D-`KY+ܧn yB7QxK+#%*k7ZyTOmf1qH- CΠ 3Ow Clu[Om!Ԥ`Ȋ i-%mUuA=m]]ݭ0A "!prAw雥V/P[[Ǎݜn؅wc2ya6(ey}Ūm^R^8dP,rrm[1H6&V & i~pJR##"d;$:l0cmΉ4 W.h#X|В~©кov+XjMr7 XeqT?w~́ܰ7C6҈x.qB43:l1h9]>тk6sƅ7?0?Tq”agGH!8q@fCkC`j]͛fM 'Dg0Al Dsbg*i#ȕk=uwrQ8'x1h\+nlL጗?Ԑ|9PM:+O/%k=h}*{'0n6=t0?]ZK#Z݀9P07:T?-;"QzyIv W̗܎/{ōx.,KN5Ԑ⍝;zgT7c/6'7PFUslUU*) M+G)h3N7 ˦WZħc=91k{v^n$f(3s'/PGvD kw{^K된9/g*Cx?ZuC߀vy Z_AޝU1y$9"("h> +t O$2A>yuʊ*|8蛜+zw<~(nldlA]vgf:zC Q |i('Q&OV}ŸJLrא: -t>aKy=#(qg%O1fQur@sO"{Y~4{ndңVy=VqVv^ Xym~<сFԱ0k^!쌃d P=wDM 3RȂN$w*jTE$ k?PQq~kq5zY/@)c3L&7# PQ(n-1(p @sG;@>!|Z`ᜯ޻, xdu0R rqbPwB:ս\2a^[?Q1W|vG"4?{?-5@5m4ICl) z?0J+ *pL p,@-Y^?hϵD XCii ZnJAq.%R2+K@nIpd%v_||1ygŏ đ rB^bXӣ|< Ul47&_H)r=`5aM4Ae R&/*ber}f 1`gE+68"vb\gB!"@a5WßDUY힊8l n*L1oٜI7S pZX"]k f*hSϺ fBaxѮndk B9Pڄ9p>QB3eπM/\M9Vn}7%/¡f4S)BBCVK,y4xJ `t>إSu=i+kYף1֓A. |}/V /oί&4Wb$ի5[I?rR6cݎ#.$KZE/obulbwu[@VVjDUȊHC-K{!{ˇAj,u=+'g`}$aRZۺx<QVף)@߷/W[! u \50,8&rPe]?{hEWwUHOPz Tvc@oS ]>:YL4GOޅ03)&ӣ!m4ƒi;Ҿ_\v4&k@r[7D2U@3S8aPFD01jk/ϕcOiO"m*3~P Xoj=k0ua)M}(H(¨ 9(8Dk:6ί{uO?. 0?QKm~z ?d2Ѡ8{8dJJD=,-ɂSeN_- ֊)͞ 8W9oſ~]LqC9ءU9!@T?򩲇 vSF)>.dDyteon1_cXf'*G}Iwnu œTf pXh"h" 8d##~Bx/cH; 6yHFJ_M04 hk4^v=8@^N4ΊP'/VQ,,Ke0(AW0+}%"Grg O[Hc~FRBMVQYke)|Chu v8 huϸX#h X(`mLZ=8.~mSjjE\"9FKWUu>Hą!RK63@kM2bk43;yťAc:nCftEHQyv$Ԣ ,qvzk"iC<=ZE"(6diݲ$;!VCD $ @],2G+) X BԆֱQn\ L>:!PNI2a\XɎ9LtOt7~jy(llؓJ9"n$V-P+V8u&taќvKg@;wAsp<>AEψ $?E؈kZ孄~r2s ioeY{: (pEQq]VU35% PZU01+7* &V/oh `P`Ehl[v5BX4Hjk~W߅}k蟐޿:<0T^aYS٤gBq7w#-顳 2I}BA0:+sejlY%][tdKYjT4T yd-*2 [lwhE] V6aE,e|T3cx./ĸ՝kИ?1㈏RڐPx5j(?LD\3pgЮY9.peIS8QȸeJ0IxO#JrWQˠBn0Wbak Қ lT"*9Uw+.11Ni P!(le%֊9Y]3z=ҸL ushd$W Gh} 㭠hlo]'1!zt:'!q(l^ja|qSO]l;wxY^ AScSTZ~k0bV t&fKcQOKr~@eűȦu/<ba /Ҭ X&m}ܩ =49"}fsƅ-W!{0]9}AHGӄL/"#>9XY-0Y W݁Z#dH@ᱪ ܩWDPsYc!e:E³r0 JM@0)KcB)5Dz@1{jQk p"3ęa/D@f#GC5mHo /2g6<=Hg(yrHNW"e Cgw5I.ʠ 85gݙLzHƽgTPfK~$HVP[i_K>O~߯ӧ`|g1ѯ)߲g}RiUqţ^BNeHhiwdYߘsa?P}YvP D]jEÎ:䛘Ub7pC8(& ݉7I?ZXHj斖$oJY23=]3rmHPqz): w,%r?.Hp =^*6@&7ZpbY_T&+@JSht-FoջrhO2 `i.QP&RQ@!Rʼn>7Xbb]eМWN/E LämYg7F|Prqߗ?pÃ8q[*u!P/J1&R`|AnfL" )y0ͱ'4''I'AS`0@ro'׋: : (f"QJZrzYX&PbZu{/tz!L^ב'ɼ0]]Y&~mαO]F4涩x%WimPBPzjdL4?@l\S[ 1y=ޓ6άI jT7(Yxʛ'%SbZ7THx \G]?ZCėn .T_E[?Nz򢅤VbEC̩(o;Jp2xcJ9~ GCe4ݠ]2.JQnP9bmBUi sjמLʈk 4 :5-ףQLV75a/ږva~o+cj=֬YTUj#Q C 4F>TƩ0oˑ]MgD,#j+>XW5)H2:A]TR |oI/Y. g{:V,Lq}m%1kQ5*VsH B|&DzyqgtFOY`ɧŎ}{22Dl޼ς`,=dcyGAk2SpWvXJJ0c_)),qt&íPgn?w&{yd!bĒS+٪'w^R ˪BȨnWڮ.>2lh e >+|/ 1M̹? 茆[_FfwpTHf['a{љafDJc5O"aʓ/btUˋskTEoKxn4!bMEʅ+ {u.s^D՘LU/{W2vEϷl- ={/6448 _07Mgdajbvx'(Oe<*_OHH~K},g8!|[a+x`'~Zm5"LcP˭4߰IYYLެbon͙]$ S5()js~h8f97%2t}?R&op}3rfyض,(ڨ[KuN~gU-JQ.»/pp*rtYTl2 48}`o`ڒ2m%[bҐ1Z>hbKaswb "8y \)\mNNn_"VF /~z(Gk&VèH;|dORxBCF1wZ>\ۃs&+i\R-Yr/@X>Ց\/r!+R/g&U Rkk]zw? OjJ`pD8懚E2Ldi a,w87Q_\}B]<0BP ؔ;0a6~[?qekoppjmoni1⿇-ܢQXľ3;+ hnKdoֶop~hw卟"]#/M6x*D {Ch^%=k>@Ɉ-7hѬ1HU9ks(B7szs&'e*|U*M Ri=܊F7c1ۧW[7-ujHӳU_u<]eӇcݑ{g*}ߦbJouV(i S}O"`Y`\uy;:0xQ.eBurf7>S$LC!#]8o /K|~0aZ`н}K3' cn-/y{R0{|V Pzg@\nig9;n tEy<2'Qb Ӥn>Ģ{}L4M]iP4U!8]w7,ͭ"^$00tn1[ +lB T-n(lb6~wCTˤ>(K~~#="YnjL]̰8D%PQCuWi &Ji4qW{rm;GFO_p=0AS0߸ʫv6ߘ.2Bl`6DžuNa[$p[23iO׳;1jT^]CoFA(:B#ayog |4Oߺ2td fP}SBilou'N+iEEo9@P{{ljwL/"++,A 6y}c(yPJ^c@wMIZ((_;+;3W/Gdz9?i2Tt37uatSG{R&]"xh((R((?Qu1su*# 6+]ܵѿ]_\蠠^N? k91^Ĺ8DŸX٘ĸnJ%JPPըem"`f畅KL''7Khih,' ebbW*_z(,<A90;ſ,ط80!kW:37?blܬ,ܬL\\"Lr  3 ; nN.QX%X9$8X7PP/YD _a_W66nQaNna6Q1ο(\Z8yܿr AYB/aHL[Y][T4**;$2vbk_nv&N.vavfqaaaFr?.-&$.)&.khJ rܢlb\LbL,\f\́J<>x,D*..;(-wLNĺuҼW,03( 3hg~\,,\L,\,ozEB„CKLYXK @gFſ,7debd; ^?[;,2 sCYS2%nؚ^L/0iz5=1a1 N1`--wybx'ge7` )ןT, _{$ڛ[ebͿ>Y{*BG??u ?e37NSDϺ:OOt|OookU_ b1D BoJ_?:Z%Yh&0?=U]ML\] !m̜LL-ox6(< <쬐Y٠>2`tATG(#\L\LOn"eהIFno`bhfQ7p6rZ㯣 X?w.:?opk߷W5 Zuԟ n-.5aiV%bIS+zg{9 ɡҽu'g4JWK5k@}:Ḭ ~?Z.t kAiZ̚ kN4$dt|ܴXߙ;pmFG(dQr?&l ͼY4@gR詾2HGN/?,E5%Wmڃy^q ֕ccN'+ NW&Js .HO8-о"?G1G"~U(8/fc~⣗4s{΍r9 srZ/Ta4ilaegEZ)8*K/֜w߯t :i3$ɽGdeIM1<.+&כK\ KuZg"1GܞIu!\M Y rIA3SNhRA~È~*A0[`p,AuDBs"M=k~k;Vw K <2i:Qj*#-WJ0R t ūcYO >Q~8:*l"g5o;[q!M3+o 'xI!|g,oT2v=Gb)ۻ2[܎v܇Ws,:|`)ZԯK@0>>Ͼ׊-v +؃{Hӻɔ^݄y w裘k`yp$R&ʨ8c4`;'фs _,XȈۨlRkfr4~Nfi0Ũ;HKQ&A"K]8u ےOҿ ]ϨUJ`@M(7|{\CaiBq<? 혛-yyݺqƊ /U.8Mc%V0&NBF0*_|.S_@:Nq,[$.r)g#3 ytݏWhiΑfۆ\/%D> (S鞩ȯs#l_=aQf1ؔ~'9׫KK5.+9:(B}+2 l*wǰ/G"}kM/Jh  sc ICg?ܘ.!%4=dZ{wk5VuY >i㺅9@[ZFOEN֐,,菸 G#$SH][ޛ +q4|)pqkIU:r[B)I ?2,~g9p|hvoeW ^M^¸ޣb _ ^ׇƬg"@|4݂cK>ݐ FJj3DhemM0W*-`%4ctkn8RՐ[WU1qmqB|D mH?R޻X ~^Lן2i8N_ u ʛK,ݛ.e|T: -9/E5a5+NMR=ޝ[X9EdXem8k{]ٓ1; wb؃Z^; Cz h&!nE'*y^p2D;qv3 '[[V>V>ˆ uQh_{Q㇦Wtwvca*ani양Gv-NMHxжI9iO7j|#T`?,4Vk8@C$r8c\x^]P`#.;xCt&1ЏQGsZ p5RZmmVe$Ff.`~AM:꫐TWcП3( ?ig~꒦}SE~ ڵwUI1҂aaI~cqr947)q@ʓcc9jDY(I^O},G瀑>E$V3csm*kuZbRnrXwCk%Pܴ:%7kQbJ-.*#5ndPg/,ҵu%(V> ?u@M\eڪOGqN=tµCmlz+pnb!Q;o) [2<+S&쳧~ú7L`WNחx+?:;Ǡoᅧp Bݩ.,v9gQ܈$/l}U4iOz_Y?y^u׏/:ܯ"cF˕ #·$ߣSMR?PHYZl8̀a"yJ} T,6"UO"^XK6ûsr#/xY@(.+9o%揘$ U钜N\h;u;~S[|z~n3| JBٶn?&+?>gabe`cy9TIA %BSz:k`AATJ y k=(Naź`W;PCsC/`pmH>/ׁ#D9%oř/R fpc(?C;1,ג>v:9Ke+wsyx[ڸXp*tԶ7PWi\ylp)(j*/:;*T0VfKjkb )Ê?W O'L*UH>6L|xkͳZZhZvO rڒ&3?6_dIt(FٺӜّCjjbn˓# ;ۣ,:VJDV1^[$'f8pNz6ze`|ܷ$e@SƒC?Ss*v~#h_u2vgŬg: opU=HH/f#r Ǎ'~[h-QkIbLl~~1cY/zhg=RZʺ۶&V ȑ H1hh_NO;㷰3џvspq~O&` ҖH#[,ZV} ͐\øbzCb F 3,VDcnw"nBEjZs-̴}/յ튋:\|\h3uٺmbQWN=KwT3A I̯1ȷ),Z燞C$ .Ʉ И(M "S6k5^J6+bWh<1-QxǀMq.z3:\zA;QES*#-^v%Y2G~5Nʾ~ |]$t޼Ӵ@,{L`;Wz-kawwwm0^SOZ= ҙlB MHtqȁaLr_̙=8=Z܀ҿ;2(WX~EWH+Iyvfز&[_=ھɥ骁C16[rhT?O6BQܿm4#Z] 4(JU;9C~"k^(*Eµ\I]\'t22CRoDp2 yP–?{&3?] u9TQ/WV!bd^{>!6!ĚZ457QJrDcI``;g"<\z~J#4g~0\\\n~Go@n'q!Q"g^$ng:11_ 4!O*(Ȝ̝g@^% '~]B6K#W!}d䓳uzg}a`L@]>dp$`- gS-$uyq 7)))-*aZ -@4wslrrlϖKYk.ͶCƘIS@,AYrVƤyȸ_39W"/544@a[tGljwڅ<> ~vsr;:ӵ5"rSc[g[_B|"~bUJҎcʢ1/w[67;fs.t"}kԴ?hCL* M^wA{/>IT2q~fqqeQPffgYxjiU=B֙"44 bּ8[tzEKY` ^ܬL~.?F"2wrմovl]۞6fMUr47X`T ;Yl)ylG+v< Cح%v!_} =Tǭgb$PHOX&":еtIfj]c@F+[M˻/9#YǣO *kv@qݳ}m)"nYBKZ7Vxx^4[{4 4b(:=ϘD(,,~bSxe5gcюnS xR?W)RyBKu[ϷO MrN5$若u-vodȎ,zR]!TZXP0f agŜLna| t9ƥII#{05~?I$c2Df<(I znf=\bmJ2;FRCDz+5NF&=i{xla'08qNښxHwϷTOWw wM-BFT/g}I*,j]In'v) z`l41.uzZt<Q8`hkkgr|P1 yfjTlaHY"$}dMd62f[NIbe&jH)5JG)YM[Oh`E<'331|3љXUUçkCߞ\W.QzqR".)*Ea%c4SR߻j[J\8p}b]Ny>FG$Rz jP&QWë)՟}9[lb4.OC9PJR9qKճȔt.vx ? la3"rhR {7>?2,Zc3LLZpyY`LiXfE/j& AB1S=#Ʊ| -KZ%zx [{jW3e'*o%79MȐ1~ڒj'jt_{~}3$С Rㄈ,LDQ,;&C>>G.ݬ F_FGGR߰CfJMk@7/$Njo @aARaeeȗ VT6E8*fciwG$vFb$o~Ĩ"I|;rَO{C킊I-G+ٵE‚}Mry҄)﨤t+o!d"ArҏtXCtX;ۉyVVf1 pW)c4ɨnEį+tW1'#<ٙ HbJqjrr0 Bm 5h,F S $ 8|煮zd9aWq`ʧ"eP}Hk\ʲ>?Qefp1Y%`>=^fL]-IǾ⮈;ɕ,A8|3YC5~!&3*)&#BdN9S'F?-RVʚ5dݦPf(Xjfp9 @F醑F} bĦvXiQ_XE^#1 *T$ZPphcH|RMGD2Jk;q R+iiiS)jzAɑXA@2N{}hdUnV! cW:x.qV'\fwRi9]bwһ%$$ŅJAy%꥓ XPP?XeA"j>XR|qmѩ&UâӪ2 Pq[-Y3&T(NJ @yws3,j1$āћ S(iq?qIXH?Q@^ W:i$`洨P@X,rbC`H }c*!/ftu2q(%*+>qOr6:xkդop}8ʅ]ZzQ)~%dTN=c8+Z^F9<2lwKk}QzӦse(de#:R,#/VA%w=hzyhw)+lK$XfxBR&ځ~X QREJ}$o!9T,nbэ@c2_;|^W?֖4"jTBm]HQᥭsJsbYJMKD?|_j5m~eS}H/qڊyK%n@Ayf+%{eId&?K[d+><ύX~{ ejgK~Utx]6RtIy *LEJx[q{td}d4*AtU)S\,H#?ˣ1ګI} Jv雔QՖHkrn1gM_ݳvEx2RRN̆A*յhO >XfX...nXTCnʖ#{Ԝ1J̓jYsǬM%f60˸Zf^7]-$D& 0|!#l1]6ZϔiSɐwuwG~.H$sx3Շ-5i@᧤8d$(GaP:CM) A!Ta%v`S  mt??!>&"GTK\A{b3|ˁH|اZ;l=Zsy[[^;DD۵Fi ETuLL>DZ,N3X1#B0mkl-,B*-0 \z$J=mھ<|#i]vFkNgJ5`S0yАbf-c]nf2n0#0TDj"tF/s_0gL޳B<h=rg8d _h0$F]&:Ys%LV %vtt$Шdե1dH]dQ0x{{[+ݻY Ϭ LPb0>RY^DTtg$E,3IO&abGK^;EN ښ#4jv6c"4#$Y/X sFEnJkju%96%=D}q[bp:ck<6K5IQEUŸۥ3Kj{F^ݕei& _-2'l$kﷀ8bteuT"P0ގB~"O?WIoﮭ$i< $Fa5ܟQɔzmb_7Ce`r$=Tri*sf\'2W!&|RP9uY].t~<!#댟S$JkKf_*7qqUsj">q4iY5:/jš+L=֮D :77y`́E=1qPHeyB-%~ՉIϗ6Ti  tCnV"d/Hn22aZtCC̈́!NNN.]5zI/ԇ//?σ@yTá0x'T}"/ NY:/0eqImZ<ݿ.R^78UOa6)ܓG-hS'K .5;qŕ.h*,>O?}xMVL: |J:*AeX?Nd^9 Fߒ׼$avKzQ[ron&?l%nxCx||m=7@C#FuL1k; Wn w h|UI,nHB5$Q?6f: f;8`z1Hlq1(6Xdp{dkx:iDʖbgKCLVӀi)K_z.eM'Y+S]Spx+?"?$zL:?Y}JE+0Je0允aii B\h,{EqE7)b߾P0 Y4q_$ʗ׷֕]tS5nh$z4C~;f2$ fg$;"3Rvxz2[=ZG3!U $PK.i>h~ĠaؠAa1-]A1  _d$lDN罵tNH܂DE,%ٛ]#Үi($٣)|5eK$ |$͑Q =}BWmhM5 \љe;4f#ʕ齊za+-uc AQDp*=?Bzƛ 'w:D)a`E DgRN:~\iUC;|^l oo1_'d sGx3m4qMt ё8UgՄfIrmMcЃ54"̝.tf/1/-ek~ߵh;07H,؂SKsQ#r%Bؔ"*"A㏊S 9:YӀgi+ܽ!f.:vY0g桅KWUjaa2M&eg,{г[~kH!Gl>v+q^~>lx?1JQxhy¤{RwjȂ7]}T!oqP$\EаjYϋhm$Yx[Z>LhΠ /qοfqJVb MloOcqg:EܯJآuSZP'' +M',|inOVW K' |G;蝉R m>UINk-a ^'%'7I^ WODz`(^Tϗ94>qn3AyhZjָC}.|mciy:h}*P3u&%?0v ?WܾM@:;܊I i¶L G\-+#3?Ѽ 񝪈D7s爀a/Pp/>betrQSmwlUЮ>X˨ܷ *Z$pX_+dV&ķyO=B+ۨ]acsn9\S=v ‘xkbn$+bmo rya1Wr? ,hI>U?ӎ=vSqr{Q]G aN?oz|#`]VrvpudP;.f.L(4Qa#̕L RF7c(^e~&Jv|`OWnV['ʋхA|LV!p6|wV 8G1T|KpDd#ڞ eJ]|{` aGmiIp%3ƊiSB 7CY_'MRL1- wG4VҤm>{7t1m%taX$VfBGɯj$c39J(xjȇo|LMߝ[7OxQ21ҼaIR}@ĆMS^wĆNoh=G<2)n0ic) Yz#x4>pH%?$;52J5{R9WV n=}eZGpQhGʤWU\;Ȃl UߔieDN_ΤqMQY<#+NGur 3j )vB6)`mWR\e6+)dF+lź@V FǞ' TSv/} s)ky=.d.Тtm*(;veU5f|GC>hYߓ D5 5bwľ.dGMu &3=lQ{j([stpBb10o;^OYէFAa0۬BGׂ(%s|IneRh*><5ׄJˤ .$W@İ>"Q!S?ŤFԩ:EykkW?s2ʵQJfizZyΘ)L f!1΀H5< eGCCe-ܕYnY\h]@.c ;|/pWv{#(uGukN%vqݠMJrlt &O)2."-Rҝt\2wZ <މ݃l4ط՝<Śz#2&Ǡ2H1.ާ4)b\v4{ihZ>hT5DfQc:<ݜfvo>j<,T0IB||k28MHc5820c-%j![`|g??3TVKVqqJyVpU~!?ȇ '晎"zBI֠B0NJ(iiǦuzAy⳥,p7#Az״s VѬZdeEUX{ɽBc#OCCD 46z#!5R{t1J傊!{ 4nj0ܗN Gi_X\)zgMHQ(YQg_ByXDȴ2Brv/-\t`hT[%AJjB%%z)VR#(AXDnY'fFfZ4sgxr~[a+B`N]\k-1sWm涻e7YMU~4N\WO`i)V&\6ϙC'/ՃoiUF>(۬Pf/:Uŏ(͸sD`ݰ)sJVf;S>񐟼q/Ay|zi?IZpY!M}ݣ_IHѐEr=60Ñ,z@+4顊_eGNtg|ʾMVDb|j_/EثRy?@e)"jUdxfŻԋ]A?}H7h}}LjFdx'קY-IB! kW0&U}<%ڰd;(]CH]4[3ՋlQ]rXfmE()5`5"G{u7t˭i[VAYi;`caXt\x|p_.3 C ]}V{̕%{F.j兓HIԾ+cu[Ixed4"䰆d{R43P?,5,;帨y?T:g_;mfoN BԋLCP&2iYHѦ9]}nS| 5^U]D^Bm`ppyrx ڏ2luwp҄ǍT_ d劑Sr%ZG~70qǭ@n In C6t>ʢr_֣z{8PXLWEmL((d?;y:EZ.`0 :>7pCڃ_GX|mWS*l@69R#ںH3,2_:#kw[X8`[3c^htD,@^a(@>6fapX^˛L!z뽴Rt2-%-wۍſf][%K` xlPߨu({Eъ%0εZ >VYW$ mec64s4Pm. OCrr[Q62KupXp0tERfPKr0⡑LM#*lCIgw$Dňv *?;AQ*6)1nkd\,9ѺBà a<@ad3iO✟=IQ;-WXD?b:t.-m* Kv^PLNЊ}wwM-ُE= K^ร39Ü)j6ˏ |*b+߯foFs+ՑhCµaw0 vǝC!:ښ*nukߦT S@)y0)KUN tڷ-]] bLMz+0m`ƛy;,0=д@ۿJS&`rX,3ۈ;"nV $rD9szSaS//LfoyR6eLPWHx1Vx>1cm)`*fl?֫䌟f4Yf:YfQщ,r`b%-E7If=/_3C۹ >/eCˇ5aock1猊=^^<-rh9kCTJj"l]`vYszji_ *7f}fN\z\psvZ 4UWMҾvvU.{s˲W>LJ[]3 ]GKGǏANm<ywY7mj.`%aTN V@VMl꧿\5v/h_wA;t6HVmp;B9,,ʓ_ƥudGNw ]e8a6T;G[Ps[.[tɇdixOf`H[AyrИ DG@3M'uFiVJMR"IMa8GʸFw6Nʐ-\o? H~<`#-h5av.ۥݱԹW"Ґrr=L )WY8SZPr'nyJlZh!8}g.ؕk S7l=%5K+Nknfm&kbY=v]Be5Enk עÒ F9 Ujlh2؛ڧϝ0ʗ3CX^`ϟB󝱗-3(CM]'+4(ohfF3x5}VZܖj>N6@ņ\Uԟu9PHE:eeA# y{yڍ"':B>, [ͩDG?;CpC% vljyx:ovƲ`LCM[Z~nsqXJtuh8i~Jv;M$MMF*%d%I UVv>MJa{Sȝ^]ͪ>M]4;mPrI?EEE]***N:32VNO~ࢦB(..|@O%i1W2Z8njaaqO3Da;x^R!d"tT%RRzj,7ilgz@JdMF&Gxm{FywW^D&:Q!ENb39 >x:wzקlѐ$JF:[!#Hyjq^uVdWZDqHlOVP7hvukDĤ6s_Bcar7I1ح1BQ<.PQQBq9>O?@"󔔔ZL4bؓ-PX^!񻷯+ہ(+חsy'`Z>OhA [2>154""",Gnp,z@Nqpp>QY-Y? c9-?ԇ]S T0(BN[fA{=fz WBd2IP|M =Y\D2AcAfjOrs>&b+EhR60)`W&~NY$mE4T-R8b4X{k HK)/ܴF$ l0keTJX>5;`rrG"SJ]^ p(~W܊Olt6]JT0_%ʨHDTtDO5 c/КQr+gBl:𞖖TS>&_Tsy*p==o }65kGr03k$1RelSsĴ}?FH ~څZ$N%|z@xd?<f)W;"> v)zZo@6NV$||ᷯb ",d\`VYr/ $?#Mstǹg[0@/C*gYm?Y""n !Z11ɪfCdm-[F0Ui"}R!dSx]L|}B;u ؓυGWv.rN] gN;jQ{{Ѧ6-(Kw% \瀘+})%>n" B2|#c*i 8A#Kt9Mt{aUԁG* ɒM2ԎgMӝ KTVFPbKgQK4HU܀RbbbV/ !H p-'f#}݃3 IDwkڋ'A,CT?cIB&''_ߡ$F S///@bUV 0 _]]TaE'i ({Irx?$hYq/\]g\ZESCA#B YϔI)*vB`QMM G,E֖G!|$"< "GZ"1OB=>Hfk {~ Bo 3_nv.BͿH/𴼺iZ -5s -g%[0̣ v63^^ݏc2"CJ! B8bbj2}YTwLsh5L f4#T|Y,dlo%ɺCZ3^xZ ̶gQSp ^14K.+NȞM峭f6v3!OT|FdW)SZ1fH*%v'"u?Z/,/rD|ȓANήio"W(0k b5ve@]3;  A8 ~&;"C"N#4VJ..O{*a,/4']Yv PzQ4r#* |Yru϶c;SZO,w7$sV&*w1o>AJ7`us777_e+IulA²2yH U" 4NI9Pi]n\̵̅&$(8c3}~LL)6 Jˋ4{ qC)NNGZv)24/gFRRoPU!Y D*u~1ur% $!A7L!9; ֐)HӛD;1/7"vL zYaݎNWL@ R Zs>ֳePb*\![gJ:ίB"K{ڟ)S$6\ۧ6;3w R/0מ$Wo!ONT{c$@!S;  ^(B!A>$ du/HUBr0̙HGU7 ttg]B'/5+#~r{nXQxR4"rI]B0Iw%V%A½{Fbgg M6󝳚ჰ;p9E@vf;?!haJ;gALn~R˨ 8 -8"pp#9G@Dl@._V2'ѼW|bNx Zg;wg'&mxvKn#q_L~5˶IđZOj-#? Y \poQ}%[+ a7}IZUEE!OZtƾipw.l?g:CtKpQY,lf; MGOoxCH6Za.)Sufـ}o--+^HT Mi\ q5F0 IK.f7B/1phHOEZfq K=BOG' Ƥz~ljH4څueθ0',5Yg](ڡo8X9Wb?65>EOLAq/B_NSb n8Lw&JiB!ƳE~ d1$0Vh L>‘dytd|x2z g+@C[xY8f5 1#=WU 2o`NȾ^+cB`= d*mߡo%/P7߭d69hp..&>S/,'-a_}L dPIfM:-pax5?\GՈ. hB~tB) %{)ILYK ʸsN#ƔWiֳ钂,xJэ׈%|rtN~`5ﱿl+5qrJ$PeezÉPRu|W#I]xF@BpCCCJ̱< FJcD>P癲hf$Ba3p8vE.u %o?gLպE%A9]w>4ݲjy(b!kfv~݉7CrzvI -}QGAWY-6 I1$)M]WMj[ilfߵʎK8c"`w RYl[ǑDB݅f첗6?kpMY,٭Bp/&Gfz"Z|ׅDEDnnlDpg „EIDYQZܛh1JU,8@sID}'|EDVQ) ?ܽ]VgG $T&=׬qؚwT%}Sؗ8 )^j~\lmYrDjRv }G}bkL"7Ԇ~+fOmꪅt5JAݒWi|NN32}Oxx7U$awa.1,[D$oYo* TGۗ!N1C Gu~zl㯠_]}15^'zzߦ 3)"̀$hvsjf]I+׏1qإm4Ŭ3({OOcfKTT&᠀+"P&:w WwA7wArD?dqDD9t>D(GIHH*ސ(O3.ך*@١aB`V_,6s(EDwƗ6l 2D>s֍ ;f6CSڌ):WZfn_XA<i `;^v͐ʭ/ˤ|E`ooo6Nc/꒬P`I"%e13333˲bfffffffffڒ鞙c݈]U%WW^ބs2ދq1P>3p^3cj{g ͕uBbzԑw1?eWKLKN^Ox:)|r(_v;(ænAp ՟rHAm~<FFjo`3O Ä_P~];;sGGA 0g f-4ȚgY8K`4_iTj_c-oafPm?,kMx(cS%H ?ް]Q,Wf AD+nTJ7Nؽzyy991c[PQŇX")6V=a#X4 [X0vxװ1c!]M fK") `^ #a b07pɒI@7)&j$ύތeɔQ۸<2m?=+/T+͗ox݌1wuuOOO T/e E o/t/Q`ίlz>ekl`5R]=uN*9Tv; \۽^nݹ*t 9H~T:\G/י՘Ri57`d͕ >ݞox/54,r[,4SPȀtvvhh`$#IQ 6gQ3wL,,/4o*}ʵXDymq} 3?|\ۮ3C %Sת*;Uj:p]_^q5pўBp+Üc009/kqŊd{G 0J" lF;^joTiNJݞD3%2<|@&!8zfzӤx7x+$;\NK$geEx%ɡ"$x;pVc@ABEصu:YS/yu%h⑓[YYP:fˌ#2. q|?ӏOIzEF%HlHv`g?< \ɟˏLTNVGFS3m֚S6<8 i %L_>SS:28$XaQ "qg>/>%=!)/A_/li4x 3ԩǍʼnwDwl]wtdBK'*ōEG mll44BK4 LݴVdCs_?jt-}| j17NQvvTL*%!-MH)4Wl)Mub?&z]I @m;!^qg"M>}/Ue쟒5Ď﮴'xվQTVVwum&8ZԓK kZsQAc e8{3{y]1(=`7I`8YTvp?p۬w[X v:XS\c\IBw}lY2URerlNP `7-[t:D2*>㡺_) É BUUX*Fi E8:+('&Yu/ޝ6f)4<ً7F3ӹ.i\2wloqzenG;Wj>q)m}w4~j\ -K3Pcĕ}+R,Vb9ٝLZ oz<.LK7UGLe4$:%YL\furj>XݡSMPVZw=ATؽw ݽUxql >݋i΀VWO_ W[2}ן5''un6A] BIx/Z.̊KBn߰3DvJI㉳dv'lӹB ˟hp^ԘzKqvcgJQ-B@J5 l*:JNFdžn_f@B?Ed &9 ca Cqf%an 4){ix4lUHCJ*ov ബbqb&!2S:{ |I+S[|j@798qǚ/ 39.oĂQgdx{EZ7e+A }0f-74-`&H[4_! T~Zӯ٪j:ˑE,&\ cח= N4o8''&{RN?XxKH|I <9.Ņ ՍB6dN7^$!/fmF;E6im9M>p䦗M(RP𛙶>c(Rʬ ppxߕ W~QQY X\Ψvpw=z0h ./Varh{Ď( eZL2J6efмcUHZtp:V>T.=^w#*,%Ri$+o׏0PBiݗ"~(XWz$QۧےDzϓxOg5W  Y> O4n$"#bLC)]+쁮6> PBTHX~7{G_h2L Kt JK2#u 0t壄 Iކt$%%_~[X.()=<1;&׫e/ivC@TkHf\u1̉t̑ڋV`3_|^Z]錖Hrb {aGO>*1iiuٱ2RYŊ(k/_,ת'667lz=ړ] ) W+8yfg @zP/NNbQ(&/8#`ȡr8_ѪQnG.z4P %rs(&NB}4ۜ9~ef#aC~%X s6F*jCCA.U; +!pɑ{(޺s+SH__E{i!h[.'ٝOԿMCRKycFBlbjL=7x79=F@w uW`WBڔqqq.狙]>n= d%WezT2nXn@GF&ȉљ!<_>mNdjSᅪy<;CJKGy=%Di+_:QqϴLaFEE6a e(hBP vOOKI> yѐКQy`tWKLV 18;lU$F+i~dvٷoĕN=_\L~6mLW!nnTz|ǕhG_H Ϧ*M*m%982c;)WB'R` LDR7흛џ2@NEP 7RlRx[G}uU?lT W^z-P,~xTˇg&'~)xȁV~|j[BWn0Y0a7D25ERi"ח_MmYho\F˹\jn54##/j#h0;jeyf6m^ц;n1Sm;g;oj3fw!˼\߸gڽυ]ؚP3U:R27T=<op:+~UIR1Fd Fq煠Ӓ>Ʒiӡ +6j뿓xt~Sr:cb+Y\.nZHiɀuweH?g\rs=(",Ez/BABb[6YXX,D>bXLD[t 9i{n2JԚC>9=ZwJY)+V{~ Ge& W3GTUl7(vtIF_Y^],|c,Zk}9>gmq{L#$D)[>N cq,[:t hSGjPpp_y<1}sTp$A._V<*_>N e*#yu,ϫ0$5K۶[o6f^˔NT+q9j386{eJӍv|4aY;8"WGa` #N|ѐ>}bq&V9taI ߿?\_rxAՃӌ^<p bmQ^P_^8jr{ 1 HƵ߄U=Qp>REz?@?IC I?yMYv[S¬VYo(Uc.Vhn-EG+a:B仚0}*,eH^m_@s|0FS5C1E*w^}~Kx!O?͈&>Ti]={? Ը~y Z25U//K߶(nטCGWÞ jĕ[GCjm6qѸ*:ΧxPA5,1Xn{t VJ# jL\W1(A6@E^Qd*/(SS9z3T-lb$uϭ)+c}*-(U5þVϛ5hM %~4#vBɽPx2-vϩkwSm8Vs#83Pkjj~Ȅbsd˗dRe< (/-;aW"/ߥzszKxͭIԾfEC%DޔD%~o fLjx%_d-aɡ()UqFsLΨqT|ҽ8c#֤Ppa8!hhEFvj@OzyLEђ!G3›>g傆 #Fv]=&rq.i\۵SG*biӗFl^!1#¤440;9Q^-̓"R#2ӵH!D pÃL6Ց=8w._;]|)x1o=&(y^VK y} eZ,O9*ᑣ(1iyE5;ij/~UOz$_;"~wjɐ *_(@p U>]ҰnexC\ z( 4{Z>ƧKF.+ S?j3G "mO HiڭM5$sDGYگZP+ZO^sB^Ɔq`lĨ~)Z<&"\rI"bC(,3 s>+tF5VlF614އG*v-ئ_m$#+6ߟ=W8Db bð_νit6*N:éŌxj3E@mrhv|H;٫CaC7r; &ۻ6G <iuU[%*X&?7&.cGL?i;Q椙TBgM,BD`9aiI>j7; K^8ljmD>/g_ xЏ*KV7*>/7ʜf;eխE\f3BS}TѴih=ƕD.))y[.s{`$g"B9OP~>_C,.iSᄙsH>*Yi㴟GtP,_83(TZ [ 9J7 +:;ac\:9ݷy1n3tRx8#W")ug?bɔ}80Hg m"/@4/ܻ!  SF[+ ?, LDKiM*EI}n"#Ps*u%7"CzA67w(0 (Sw/% oFu61m:_}0SW1̯ЯI3|RD= {!N~؄\i nékTD(ꛍ.ד?c^32DW{l㉺tS\*JPrASv KESI"m0 Cߣ!Ըk8?쟦ɝH`ήO cyKo91C"K?>gB]BЍՠSodq@ȼ_,jDZ3ho[?r8wwMִ3֍p~ie D̰pp^nX6/9*1w?|!hJ#&ዔC hDし3LB9G/.JkC;=o%5v"u w+sR<7%)0Y鑰=o&{zqpu[,Vw͎\K)prpq!|LСh_lɆT-Ӧ70`L/JKKU&s,P*]|jDCqEQ l)8ɯySkY6-՚7ًx^+DFEe͚ldOow=sqq %@'cǷ衂yYza9@}\n9\X,Щgg.6+%htzCnnc>ĖBBi0qs8tTL$1,H$FFfsVK4$Op/"GĹ+z ҹȑMJfs Κ?&S(C*W-DkoWWdt_ ɐ0BjQx{R->>P&ׯ:|ÈFdٓ M,$?Bs:_z E/o{2Fb7;/GU7:q^hήvrT\r5 :Q)b"TW-MDAO "Y,>|`n\=RbHa\o>"K|FW?*[<@(gvbMkp<#X8_V{%Ѥܼ"=\VêW'xcM0hЩv`?=Bؠ!:[~G,b:@G-0W&2<-X߆)ӜEVu)f{U>1IXa2ӟWۨ> bp?'$(ss/צ]\XQ 6,B՚*h]\2秱 .NK&V1:!{\x$\f6cs-[9@:gk1/w_& @)i5T b.ѻ^iv=kA2ލ$G9?oϝfA2wU}eK}}z:z]]^p/%&*:ρJ\\ttZ@ nm|ݟ& Ic*$5\?XrL8~ūâÉ_c}L7M| c52yϓ8Mi{H.@ߏ|<}"X^aWͮZ[Rg\XIf=t'[o]Xť෴Zi0X,o B~<~<.c~9\o{5 g|Z{ Wc6ޗ |U%5k-4_Rigϣ l9Afkq^JvJf^ {fVx_܀s8Z1:EE_n6@߫FY¥^]2חҸz깜/<8{(k+Qj/d"Pb%8Gf>7GTw+JumD;dd'nB5djnо`jig#2j5qktNRQZIa{G1}t3Y.lQ=`.>Y@61d}8 E|{8e{.zP"(NHngg;ky챸" vI\eʦN@ƹmR^¹SNȌ"ly״}IV>#Ee$)h~e0d*_*=vq2+ho \Oow͒Y7=W8/-VRUnagfM ٹq((N3f~JeO0'*uZ+(&S]瞺̺=x~vtkl%S8eo'C;+wdtȵYhNhz>o&ER(Ǽr0W3KpYO3n'ˌg{t{V|mw:8{)MG<ʼ Ŀm&Wr̸'m?Y I +Eej V ?K2ߤr8ը<^՟4V*ċ=ƃx{^=M26йզRVd645k&SŸ$;M8K\/wo6q/((A^\r5dakbdPu4'[?}ZYY uafu|p7^mwKfI .ף̀P62Ո(8 򨿊.IyW =t'(,2jL-QLDzjvg!,bG"7bFz-KiaA~r= 3!=s8NPYj.عuS[@ɦ.%.:%?_lpo8pXl3|uu-m-*1xђ<@J˰fylF*\3$o 7Z&}R^OrY騫N\*='يP^ع2It8q- S5fڭp ~B3(Z=G$ږq-ZT!^ω`*^l'ΘUwM0ljz܋kuu#E';I}IVʍA{z|7Z(?D#%.rzt6n>}-2=#jk۹CuLnNj ~ZZ``| Ӝ Nx1Q+;M\Kϛ4HN6 J1GK|")j~J[0_L/1yzriS{aůn&i?k++]{w'iuE'1=>B-b`h֡Z=7*॒iCtťA=nSHtz=πgenL~޳ PM?}4A{ P@~}tOMv5k [%|g#O6Ut /?ja =WL ݱv}C4ͳ ݧmT!AMju|*vJ;}uA"RR8fE34\=ҩܜVav=j'λV~zh+$9ڨI+92`CmT&&%m阼s'?6-Zń6T?H%뜤>)SޡxA~qq>>Tb)q@JaUˣU̩A=VvM"0A Gqb8iHM57ܩ!#*CmRuwX~eVV'[v7j,nT :Q22}ekjHw1Q(LM,D+Wvq66t\=~ڳwuXSV_U'0€|۱߮8c^{18zjN!*x.$&3YP:H yn{z vi)Hd- [S^2 w*u\\W\?J[HݨRݾ9goUo (p*;޲Ap¾{rd_4B)Yzl||['5]_, BO WH/_ *yjF/S8M7+=VH~={f(=U ,2Z6MY7w1KeoR|,&T5@8aB#p4`[~oAMAA:w˺Z:Tqcn@ tosT 雽R969_dӁEr[B]Ji1BTji1Q|QBdb<$?acN]AضRN)>mq.Kݯ~9fonU|?||~ i GJS+{>@͇l`4}d OQhPhR#+Xb<qīuV_"OCPRg~WFөy@R/0ٻ )sʁ/hE(Ae,~Z9P܂G~mpBAt?406eLnљ+kWm܌c`DCzr<ׅT@07R{ @`,`"?GwֲfN2bFɕ--cęح'+۠Frix{Yvu]?#~NY?N'Y/Ou*|s]hd l C94=A\'kPH4.tEv˅Gbu/Y`7a$1lM4OY9b¬ֱ} mZU9RlR(B xkoG^7(y " t I ?mEo]m9`P2AvxZdZj))GY^i(Vtt-.]-^["ߙ32#j~f2@ixe7Pa=7wX]y*b*'p$CEdh:ynV&8v9)V ɬhRXKt,P2RY0udͶG,5T:bvt AOA*ao %z Ά76U.@@Se.ތ(muZ;>ncp?H_};դ;WP  e/(| -L",[ŲZmjnoH[y<ȹ\1-JplzՐ4zCs~f j‚} ye+TLpzfF@Ds:z(X[fHRNdRҍۋvf+ړ|FɂM.S֛\WvǂVEۨQ*V,O(V9pF$I7Ob+-P볰 T챟5t=?qg`%ո]/ŃFg:9~OWHhrJrq}$vk)IewŐ`6.W5S4!,hAFǴ)l3M=ԡq[/knRȥ* Gv4R'{:fuE!{$]&svF;pfⲟʭuv=)N͒ &raٲyD+I9鏥W@1\șL4pTn4mh#`R1aa4'k{YC0μ92h߽_XY9@۞A!`GcEu 2$@f'IrHgu! 96nT`R],zOj)*@d;5g!dW6-֣P^ˆ׽36ok"9VLMMi 'p{yfF'#‚$Ј>\h#(< rAr=[rRm:!ȋ]ڱX~ '|TI>5 BgHS`8!DWqƌ.ix["<;Dn$ϗ+WqwPrccuJ<}W(VL<o8pt,ZdGTfܚ@8$ w8?Nq舞  $4[(=kXSYO oHyHqlTV&`JAK'c Ï}}[RX菸WIah*0*`~?/[{u?-[I- ʼf0פ@ 5)/4~%]قE![-|}]g >K ֪ M@g1]# ?%>vqʺV@i 9aOQ.EA+<)>`PI;W^8}`-ie/VlORyڡPi^%rQaQYLuWt@E$jT*nX]Eۈ;6{ŚJMf."  J$i L_1jq&o=ۻBRHfycj|0q @dj(Xi{b(;`,h}|#mn!n=Ư n2|&&&K̵Q!6$*^^ʿs9CNV l|Yc0i]IFEeٝh}Z`ށ5?b:_ 5U*n!?:HdF7d:"Vf rGغ(T;ڄ L&4B}Q,W2V:՞intJg 64sVīWYFkrcDVd] ` xD?%h }'g3E~*-\<[}HAQqo,y[[a P [O*YFTI{6|\`l)]柃pKR~y׏ .;МMmS BE<#=+Hw)m=2zH(PFRv镹Ƙo\`=~ OxuP ʹ0Bs>sWv1%4 t/y]+wX ݦ]2qm?0ϙ5SbQj@'C8o~!0fUGWp^~5h,GP(G)ȷjZx9 —x,+ B2sp<ǹsߣvZ,p4Jam^_ɬE,[@qq7Jªǔ&j@!:6=!~f`r{($lx3> 5!> ԍnsSP4d5A  r(xYgoSf7;=7yӄv*_';CM(}Mr&$$͗HO4Btojf}VlIQ߁y3%[u)c23$tG׼JzsvSf iܹr$_h7uy(ղ* 3_Ρa 䄶#=aH|o-gqD^s㛛Ƹ.m܋w;E&>O?[nvR)r"d{Ko6?)~waxM*(~n8'NBa$0Aq ^$=~*aTk046 m/N*76wM3e9SAk劮S"Ph7S&:X ݛ|3p =U:\&|u"Gjve 5ӔKg&?E7ªXn蕰 <6w޷TxEĞWVV*X'C|*fW>;ewo)2'M55ZoIgt{-r<8 ">Ϡ{X,b3 C; k_"4<)mwO(is~!z Ec@ܱw9_ho ?t'd B65\Yv0['O pPFl cw?N~/(s$4{M2yl)"0+,s0X#G䈠Sf0"{j%%XP;8H z٠8OhѷGW1W`A~#fmτoy,N5N") #3W(~ e0b.lwESL7B7V) ĽlTWX8<8'lq8罱|Gp6yϦ?.`X4o.&=Tda32ک^`mqA'UEoi@9HJ ݼ6yVi FOW'M1O`'Hvrm{A`O_Z@bvE\џ_S07Sf#cZa<30OcPkcXR+U$Q^Ƀ "{F.:؊H$j|Z_^/d]DEBlvr HKn&4'2 p+j$@Ɏrl<1N`pPX춉)_>A=berv̀H")&&& Ow,߯v?# HYUK.XiO2!شHڬ'jiZg{ ކ԰sKt0YQ5W\VﶺuSp !;ƏgݞUin6+orX~/FZ/.W&w8t%b LLp<\[31(4 䛑\vӱ(\M}pZB7_2'RxB.'QQ ՊAkrN9HUKӁK5׷&HM;u`wfaO}Q`e}+y_s7Ԃ{a/?K—OF|4?YihS929> |g u\pf 2AgZ.a joOA5C!@ui:|O;/+Ҙǁ3B;\}i|`7[OHhmhlq~oOJn>tn;f7z=l.]?\6B zq`);[ocOG{|Ԧs~9}8/[8=d}xj:^ƁgffIIq|4\=}tϜQ|J­ 'U)B36Y/^{`ž\:6l|FzV؝gٟ4ǐL @'J)["d)"9y["ƪv0dEܱ@sbU䷎)Θ|]k ͣ(NU+*2L^`9|>LJf \,W[`S )P$R'Ub,uY?8𦪥uBtGP5:2$6R[vYdɎ7om_/C+mi% zg$ug9`UFYYc1>j f-*VEa.z ~Dg@$L^Ujv'K>á4 (A/ǭ]`G(u/@1%}XGoTӜ8X)_:5vq.sOAx~n0~:%CĄIQ= sm2zkZfBB㶶c׋"c;ZVzp=<~k%Af/wf4^:.8HY >l_Pz[)REE''u=WS|~%MmOtiA&p2 C6xMju\'B}evڰK3 tHvQr4wAZ ήaM! UI5tߣM%,f׀. ,)5N(FfFE`l7t 3/(}@e 1 Ufӕ'_9L7ېyFxZY2 `f䥠,G%7[Bt#,e7n%Bb#%hRuF~)k P#b-Aٰ,6mFG!~P+aёZhg8wp6-)TOiOQB ˙RHT{g~s:ϊCN|QU?,90V..ܧӾY DHR#SXDwBzM[|.qx;0&xy{0 E?X6Q"͢[ JF*m0 ev"ېU˥GSzJlq {?oAvbp_Y4+IgX[4B 7qFk,By~4CY y;=&T@IѢ4[0l4VzTsG8q>:χ"Pl69&!ƤŘijgѬ_Xr,*^'VbC>i?з, JdaTPՏ[4 U^2O.!?4;v2;lrek1{ B>wշw/SDW55bcl?&%z[B*f5.Zޑx~ُq!(XƵńZ 'G>rE@Վ=-d܈QN=S9l7&An~((ŞI$ (`/y'ӰdVta*> ͉˩ ^c <70Y2@,oB~eN/Hifz,ݚYOl3CnŷLK,\͜S7y p'q<οP{PSmb]܄Ԡg ɡCR )LRŠtz s0k7݅Ղc.ԈCTmYANIs~@垲U]NzH`$U$ >r2, (L>(_rq@[xC!X䯌mʲ/̈.G_-TG5,]Z8¦.}]->˾0L{遷>#f. h1⫱cY+-H[,-~):M.^U>58]5;Y\zW竕d 2}JANE$,7TSn@tRk=2tYf|ǥ4߇Tdb1f$bko;]cdg2K]Ɗg֤VoWjZ,bs\NoDnkyΌzΉ81{M-QBRTZ׈/2"j$ǍRD5RXԩYo+KWQ6u./O5W"6ЕA;ZZ4ܮXXFL^)^knz`G<*H74ʔŸW?mr0=D/G`J߰`A2̀Qi >K9544RW`QB ~Efvz"PyhLy%ރ5+Ș(X FhlōY<%nZ%(71Aϱ MV :m]ɉA>ϗo lMp[ Es;~ MA8bx3l՜r<w7[n0Fy4Q>*\Wq-|rz%fc0|5b:m'`iE-֔B@ES]꼃os"0 F%Oձ%R+?5DAMߚP CF?Ӳ330 5?~4Me[!P,Bׁ'{5VT?\sv o.fC4 ,oϊ[dAH dY/! ?sv?NḞJqy6^$be":Z N?"l4rO\>R,Џ9d}d_Œԕn숞s 2DgR]! J-dhZiZ\)bnѕC\b$ᗇts آP2OҢ9ԭb肭R xfT;XIGmwA *H5e:.0?hw;L짻R$sQ3.-?Q;ztA~i^ZK KBoƠ ;fyUtV9USʿIDLZߣx5j)u 9DgrEІ0e_C)2TlD$.S1ymӴVW8>s?Yhm`'0f抙]qC>P{={Du8a_dD=N{v9Z%(fsx4^ Kx'OQ\W\ ٝȋ`@q=!>|-ۊj:zD clF} ՓŲ/k%D 1WU1wC~I ?Zi& ׽=Jina /6~vYs5%-DrBB]Wu`q,Eȣ;CpkjjM}=PsԇUvo|蘦ڻ?HmIP:~r@5e d?uz)2@#N{!wM]:6D.x'Gz˥u ,gj>R7BJR۾緱I3,rs? E 苯S5V?{tse L naɒ!jvLJcqXi&.z`;m\šT96j'*gN@ZqBiˊ}?5XUUӪoqW`y2b[LmEj= Gf΢\#AЕ,kbD|4 +M# -ToboL-mq_L(qyOH2iUwAp2\{6/qEEl6)˜Fo|I0)gy@b ŎSkVNS dLɷ [~'˰-QI*&*K.[([aki˞M=yCUbGiX46[uMCVTPRn`(OKFյCǫ N5 3YE¦B~JX+YDiCChAD-S"H]` 79 U~oX !bwM8oTalLK21M UXC!4H^ݗǟ?9/L|}-w zG%KY/xIm\c cI Ȩ<ӪRM~,\>6 =~i#yy+:yXo5WVGs?!]'gx! L~6,m7vtbgWX:+#ϕ3;0OX~=NpLU< y8B x4NG7 \<{_u XIҒг9-)Vepei0=<ljs-U@lFfo նm1=?wnzσ%{Gͱ>Ƭ]?̉|r/:wP;$&qpʽdg)X@\RVx6iHZ $./P1LVLal̄I`7/TZ_r/p_""UJEuۋWuv93DMEsͰ-E2("=/Oݽ 8RhV"_>GyJ[U:t.5Oiՠ_~yu<,*;hpV[.Kt8]fRݎn^SpY<@V& Vaix"dx"Tf(xwD(Daj-77ppum夈wY1`.$S؏U u^E/=B>5;pv!HbqqĒtD'70iİ#I\HpLh:}sCmu7))Vn@IGᤂ2%9_cH]L>~ 3G(;,|fEщ,auZNq~5i|D~y 2Fv̏ZR8v%WDZQ]m8L)t"~B~Cp~nҺĊDzSX៸J}ށQ 鸍Pc7OJ@@P*E&}^ѤLgEN/8eG xv+A24ZKv(jZBh.¾U I&[$\N>WKSv,FE=Z }ӫ8e{%'}/%߈n:jf%/4BZ!6Ѻ!vC1E;4GӇUfvmPHm~<(B`9c:$ ?% Gb{kJHS]0%QU`)XraokZwI xoA6DbVL"rј^!zizPLh? I$TbMݼIKK6\% 4yBT8SiRaMrbހߝu;A& XPU{igu0YN p4 5SiFKl>4b4{ynvM !oS3LtlUTX1*ĤUW*:I};HӍk.kC$1imC|7YVH ?v;K}2eA|@pkѼF޿tpi:f7jdnAZsmՀ.ITI}x bm(:>d;//=;>*( 4BL-CrY.g8Z@̀džc0 x[<38 JZ(7@N;5_|#i7/nFt$/ D!^D[VyX` $6-wadG8`Ko ҿ!rC )QL7ݤ 142<$cB5 mvd./+dЈz[(2#Sߥ 2F@\eT}Zؾw\ORi P]Ua<1!=_nM6d %$JJZJ x" 5223%g4&41sQ U @NEb9\ J~콺:VJb￞ 3k` UAU 4mS&ۛ$R"h,2$e!]b{>)Kb0c3sh2Jim9ӑMˈĆ6OUK,6Eg~6Lr%TsW[f0-mю jbzSe&4~5e0-}Vϼ-$08%bL;HFkYIJTgvzCMK:C(h2%=~*໥Xp8#W) djZkw{bnSh;2$#˵Ԓ?ϕ@lʝpWNjIU| Zq<xB{jw}˕ӈ0aS "~-6{ n(0| ^1,FЪpX?yҩ~w`6=zM!Hz ];FguQ۶tl۶m۶m;ضm<~3cf~MdeJ{9g{OUʖT|MpX=lz'CsmFGY \ܻH(9Yތ `h6ֵ9ov<cΩw{t+ 5XHF5 V$5p)&+ٕ>y.NZ&@0?HUAKQ.vSbOUra6bp/s?U/c~dJŭ%̳ݼ]o" Ҭ[y(uch;E0Õ l:۬ÝYR%wI~I?1nWMi~[P78 .)#Owa<5NB:MI,0w0gz&gl Ou^HfH\CiX# kyPhZRnپJ/-=2 iNR|;inݒ{^?RATϦݕ\b~p;]>{q~sqvb{{l}1rrF9^U 6ryƚorwfG>(**4wyYX m>rMH+EGg/g[XLB, ̿Ymr'H8\Eٹ nug^5@k#1rsj:9QM8G}=CCT<7jcn,CTD^xw,lKau@soZ;CdCv, ;NI24Hhqslē^7uoˬTmflq,`wt8~Z|G`SɵE:#,>Sz ?{c_7{B|[2P'k}t꣟CPD4ť? ~08:5~%ތD?yg|ۡg!5tn== *%MMTym7tnxN$sv25'E-2\RyXZ˕~gOK3yxfodSr%0 [%B&/o8vN0lPCV2N𺙬եKwgfHsYT2C&񡛁+#.>\UnU43~`g&#@Aweu]("LcF iZ^Ba'k7 Kˤy/Z Fs{͆oD J`ٯk/~zC=6,Q?#>#Q2fNìAdS%+r3cC-{_?KD^Jt T5*e *e ŮegX,5tHaZ|'Vfx˞{Eܙ)'ifR"X>C ΓFt#260Fkkkݔz Y4.>8X>Ù=j$dGfp52D- Q$KKѮzUQF+*ƭo]#ɒM [ u+ajUe(̈1$ YtOy]/kAiy}[M[Z!CYX/}uʖ}|y[ 6}^7B 4(M  ZD Dc%x #g'k2]S4)LS)sqIayͲU):%CS0QJX+GfX0/*6H'w~fw,J㙙Q=%i ɰ80 y%sKMm*Ear/JM3/:qfL.-p24?97D~o  ȷ1,acf'9>6LxTJ* ԥvaSw|=6@JIWiz4k)~k{!+D1!k ]G5ˀ"[m:z~UIsr3p8&՜Vn:߯ĸ#2,%Vǭ箐[W/hf˔g"O[UTO>\InHTV<9xRwڵA] Cq9]+W/Ӝ5l:eQX[~ha L<$j6W%WndօjBx&FXXzz[z<^LڋIɍwTY) ҕE/bRtʼn=ڹȊL]p,Vj-'1 He&Z ;=ug6?aDV%t/Pݮ!)%P4HH>Apr*PՔLf }HAvN4z&nW*f`賬WdFd8>;4S~r%n蓬 ҁш ;w{&0pN0&}nËB|ePJ]ّ8K ׮Qj.`ú=|'HnMk=%[:/=6v}n'cWE%b㭕4+VWqxb0 9Œ[܇l\Wy2}fix/V42Z F]5vϮh!WDt 4p,6VEG'c6pg߰;jྡlfiC,p:\ zF ӹq{ #˷ًs7%{I9z=Kʽjlæi҅*p0}g*؞Σ^#ǩ,~2L&ڼn޵!(HxY;o4mؔ{P<;CD5#ir]|w)F$Q:\CBzDdRRl})vDghz]b!<[-j{5:|AR!۬Z* X0Kfs P2u:zHf}KuKP_ s1Ǝv@0L@,ⴟ5X=e~)~ VџS;ㅘ97Mifgu.-%ɗE>ur!qA6 v޶MV<_oΩ}?G6_1uޓ!ղK#t|7(,MA=9߂vJ]ǯ9ǾCU4{/p=|d 9l|:NMF޳ -NYu8!8o恆U*4[I 2dc_8)XȄ}ȇLz&KIS#s|TF0[JF@ qDaz,J, 4" >!z/Ow9+LWK}p{ "^CyŞ*LBOtg*wGv M10jM-vq5' W8Yyc!;W$ ꣈'}6l8$mliTDӅ# Uzz";}uZ s2zΣr{mh')ƠY3ӿiSovWqG7GOV0M/k7ƨ$xxø87:e2_辤ͻ4So4 fYƃ -v~Bjo7.+KI@C,H")H%ŽFٜ"Lt# i}ܻ)"`!b]:ׄDGvta61REnktCE( 44h#9i&Iqu)ԙ a7͆Uݯ8wԢ-?a Rl7y*jéR!@2 )â'p#d4e2Y3&CD9T9h$lEom:&nѡC:~bc/2댲H1=3jq*ENCsd(?E Bc׼ iA; vyG?b A39ey0 Rb7&EJ+lsAjDU{DF%,uDBK O wJtNҍ'5L8?ѐ`_(~oFG Did[F@acc߆;e; 9jܞ3M<1y 8.rYMxG=+z [ѷ{zM咣ʕxeavǏ/g) ~ߥe3 0 ӳ-,] ǯp_=x?~" LYmYULZ 씜KPYh@?~Z3)g盛< +3FrTBlRBC.- n_U4':ħ |YU/AÑExihXB5o?0?$~n8(Es^ۉѻ jƿ8$N?KGN6V)"-8XP ‚ )Tb6?RHHS/|FC@'~ȥT b͐9n[V)18t~P Q^T/=PRiu/@]E&nB\!"YS)tw&etWR;6;L1x=cF62Q=OS)R u8Cs #n R69>T٪$e&7:SQ S Xϸ LwJM<'ly[Q-I*BRn=VnAeaf>O@#fXjoh0,RTC-N L+txG;gQ>X62EAW{{V-,_qj?07(5bd$ 1MlluI G ; ^d8 *g{ZsEC|Aa Kff&zNf&4v*HαjRlq9?+0-y/!TVViU|u?'$H PLKxRF:VXӤ ( x&8?.ZU)`0!"Rg~AIZ'*Ye<;p>x!],ȑ%ekJaAǦCp)A@QB6{0]0}{K+kMv}q}{F['K21`lί7:}N7偅89Vl6F#Qll/.,T5VmR*&iy\*Cg% XZ H2u_[[ge*pI-Khߏ;}$㙞G+/ &uHN?orf&Q4$a,22cplu`On đI7 (Oq~,RC "ث]vl|Ƣ~68/dw;U+?4EPP [t4k}i5TK}D/[ F~ph^hDkn0({MѱP[y(}w8\PTo/,(ZY,ŧu1ZGXQ2XShE~L|  v5uK iJ{ڡQ3]M# y*Rv 0TXa k,cBg;{X4kN6s+DSYlH8ΏּVR^klJ5@-6W6'{Ok_W ^}KS[5U*5T3\cv%4`dJh`"IJa00.222RRzMv=؈a,\\\{{9e2 )(l_YTm-1f/j))kU:"%90 /l\P0d-DtqJ$?1JfU$) (q&GG/Cwl4WċÚ.. e{M43&`. XjjyB.n e/@`p7[vd^[W[,*NN{gMQ΂k(((;q?Z-Y'WaK'!~c$B\la?rȐ/Aҷ*laSQĝ)Jon:>,aDڐI2pSmoZzTg[>3Won4SgPpш{fs)_LzYF@> ޡ.0jXI$/åL H ++/-7yߑպ }"ZVax1HVAA=H!uue˵^}lsLi5ɒ8|%8a>))V-c3wSO[lA"N|ܘm5-3^X75aH\A՚H5#Zةr(Er @- /It=v<;='&&&: ` z9;Cx>[|_յ!\3KOX !SH- _l4#K3K&b!e`'8xG)\?-vh(*,NELe>h?Nit4>mu٘%a#Y,}\`Ϧ[_TijL90(zNu s,C 4$Xʘ;_&eHks0KLc}䩲qq7޸>+.y@QGMerK2mX2vSidhM4!oR)-dU4S|r DTj_Sʔl2bU0._BYFB+ PN%l ʼn$ wfDz? DH39vY $$TY,e6{PA5+φcOMq`qa{{YSE???un_nQ_(U@z*˕)zDqC>r%Ch+jOR,o b]dE>t&Y$Ƥ{,Vݲ?-%9C1{+;0UE5ynw=_Zr%a3jE0P5L.?(Y&}~hڊڸR|S"TLs#Wf{vX8,OD(|P;;{JNsb[tR6X '6F3NW%]_c45[Yv > }?tۗ@F 3{{r p1/~S"ZjjR\~|,SioS\INNO3o|OOyd`r8⏀tsYRP"f2lnEop?GNKNB ,b 4?sȤC]6nnHn񆣰tttt}?|PK[{sc a>[(3o 3RRD Tk!GֲH8dG32c{^^`~ؗdGcכu c?Q(-Hly "Io"G蛈4#%LV] $,|:(,j,>6U@$X(ݽ}@D~-plpOz2b B7EEP"D*<pfl6 n$&Ċrx ]Ln/Nu"1]M:7?[yKE@]͐9y'Fa92 JT~z5@ G?e(- {H<I??QZ (3t[{-nf )X㈦Tbѣ1y%3B T6h^K+L L hlνzr+Cw?XL'LRژטC015j[ 1NHP400&hx6w)$/b⍦}.",|I%HHpKO/ע/Yث5ҿLɸ;GG&X88Ur qF%%%()+e6Hd6<߈`YYYI$Svlzi4^9>fPNU3$?:] OdД#*YBVnF+&?3oمF_7:6s2-"Kf"T~K01-@ >.փ ;nbSvXuX7pT$̜mYܞ>ǡt{Iם)k(B7O%7MZ3`iFLЦ*e|S;۪ RIx.Og$.]ĦJ;]hhNPA R8˕K+S|s{JBK4*mBjatLK"924%r߲T ؞E|)&WR r$ vV/>@ HKwIaj/!TpS_ðwhr!F}_F&MȢS&ߴ_懻|Uw0N\%Gw%Jl0V>_1ܘr! c-$j$@:< Vdt-: (Ef3k$DS2C9bS1T!d3X"䐟'w(Dd= ͮ5]3\T'\>;61~FG@QG\<.v_ÍkN-]<#HsDsAKĔ Sܘfi[?!q$~"X, ޥi&$,vq =O6sQh2]|Co }4~FxsPZ2~YۃJ$ak-o$HӈږUY8NrlӅ1hCWisiaIe10nrCO UPc(w{c*eڃI J(jW~>7mZ}inONbrٌ3eJ`Уq]tеJ<9c9G-|9O*ŦUw6xS "o0 .e* t C"(%bJ|j:XfXFJE Fفu:X8ESt ,oq߮T(+}q2Er.Ȥ;jtC gH$#9?$1dnx:?j(\庳T^Ã;W2/:T\n]i\9 ~dqp q(n>-HR#҃{HS{^=+!ۆBx-nUEfH\?X")_ 61 `a܁U]&)'ǁLBR'A]PPd_8`tԙ@E|(xR Nf0ӅhzJr>5r{$8UC4 @p $A;?bOf3,y8̃]e,.kG"mH'1Y=aÙE&UB.Vڲ`4Z/㽛Gv-%(ixE_mv}V>H W[嫳}=c-W"+`F(ZϘk#gyS,3W/B&Jvoōf6,ln͉uN7,h+!P])Uģ|82Ge¤$B! vla&4#xEQCwMqIBƒͅAS(5]gkq-:wp/ebV4& ":CNߥ)71=R7 ;lWs]-'Q}h1/cJW_]JK4u =!跰_w,Sx¼b"._'AILK:"ښ`6'YKn& 7% ȐՅ9V-ٗSr^KJЊ%>$ Cd!x ,e&:(ji2 ) :A!,{ $ \=co8T{'[! $͖5{rKI_a5!=>%ezMIm-Nr՟[B]g*-=s1ψu1YGZo! :MD H*%߯ʄX hM$jW>{JW>,:~2KoLCbĈ*;wHjSIUG1WxR:67MA_ $`ⓤVd1حo<缿"P/s:-t<BĨz.*[jڶHLoh*͖ջHwRE($V˶1#{ ~Y"71kRd.VI.&v;ԡ@mOWxN4|Q`@w/te$p éƼ-6\R Ѻժ.4c`PKa!j[I1xRIEMNA_}Dr2tw05R 3$`z^rW5\cXH) ^&!:?%r?玒F<_["hV_w\ڹZW|?Y&Gmcfv-Zj2L k CATA qoMlΧ';VFtRz$6gJ/Bs)TKmoMh53 G_Y9vgfslJLZ˙ĤR=l]StB bSI ꊤsylwGA%5K'猢PR#<kqeAl`*:4D`_Fۙ7" ᤤ[ <]#̨s.Ȭ/?2\\J=+ɟq)#А e] YMFL=W L{X5tM9׆szm TX^0s8Mښ/ &6$ zm+D_k<슄, *IQt;-hyn.'tY,QpmĂ@= ,Z̬,z8_襱0_,mYr@x>YH!|[Q\-::,qRXMBLjY|)CEyi6UvA5/r5 6 zcZ\-5%uG=8%<ؘNjƞ ")e#\, %t4x~ҋ}>-32'PªYo*v˳K}Un7rM!:*BmMq͌ nϷ[=3ףO 5*{ |?zH'd|UQ#zd^͙ի80tdjި[)II8))݅02 a1#"I+<_Nֳyѐ- Qhލf#2ػ*NMBGxWvA_Glf^n|3&F=˘u{9J]qf'vwij6"kT:j ٠3hʉnAD/HˉЊ'4hGf^cj8f/W"tie@ -U˸}7eac=}<-fku` 38K~9w"rԣAw}Tl3 Ъå:mȨD6!HTAmtnsuO`ʥw[Vq(Tmv\scN1tbo Yi=_-Uğxxԗ$IEFďWmC3x}oO-5`]>O >u uxTS3nI#$t{k5 n0( !/ȥjp^l.rv't۵yQݳB 5u$0=DK e ӡk'fYџ֝N:2VeT8ԓ4y]0J*t"*%l\+8QsJ|- <;H&`O{)̧Ý ٖ~Q|Fze0pD_*t>݇9BM%1_~i)vAT=-)8 ABvXY.;SX5G4Sˍ}ƒd,FY a/]  ]$-J =tz5#W'*@suCwbԒBl]`iJ|fKs#M-K^X\v ]Nͷzma jLCW_LbYt@` iLgϒꅦ>)#,R*ߩC3FFݤ&au "j\(M {Ҿm%DJ%c!XSMxSp#م؎?ً +_Ѹn~Ԥ'D^xEI]Ě~5V_SKC?/n 5R(e]4½"CDfkew8ߓJ5 Ҡcj\e&?f3q/ ,&5gj5MHs9 Gk=$'QѾ1bZp8iûsqNUii!I#OK__ccuy9\ы93umY0)ksE^%~Dd9!1;*z\Kd'rbQJT X۫;GfBTڙjʐe$I^Z DV4"FBUŁј떛erc>lG:B4a[" ;g/֫Z$YݶMwA]Ǜ-V++T3s2N-N' f/'jŎD!Ї:g55@ejtݘ /71T#\ ǘ~&pX\ 1[>DC ~G;Kd=5hs$0䰠!ؐryP&NoOx:01 V]xwj!0ٚafhӍoW ץB{nSTd)\̊jC.AUϻ,\xT0< E=r4_4rBLyB\o '(}ڞhh`s_cEc.'Vkx( |{1ahnk:Mx}40Z33+}˛aC;=>/8WqA&)T?uC. sr7EnhFŘ8f7͘Mj#<KǴNyw [J[W FrN ]EnBk,FHHڗ\SDܛ`fUTa7aBɄƸa _^9CsZ)[ZdX>aKrMkz )?.z~/|)%f|o1%VKQȜyaB= X煶RumLSEgYloL# +,:ܕQX6-_ae1@7~ +xhZJ$CgUG`jF5(.e WD$˷z}Sݖ5zT&2 2|U'ay^jL\F0ф|I6X$$G2$E!>nJU^Rﻊ+UNE^gS=U;݉X{S{"˨|q,ca p,1O" \&W6P_^sgx>[7t## !^svqQ1pGoa:@ ۳Mw`R\WML,T\=e)!.Tٍy/5LmX2X<5 SlP典K%4`vZONũQֵ!ye5w}y#JLi`%1`PSB3;$Qx?AT[]t#)jK"Y9>R 1kAO9o^*e"A `B,&cJ\Zn֢)Z$I=͢}`0dZ`۫P^_Mqxg$bm5;nBye1U36CߊhωzyE$aeIoŲAn4ҷӧBE0yS˝JY:!k٪ gR5Y-OYZsG{PvkkLj:)-KRvo$o"C{~?Px]Q8P;L $ n)=٦'̅zqH^3rYz" !X!xZ ëo\e6^oaR}+*Fbk}sƢDrp{а'yEF.0҇\20^m0.:uǗw-|yID;6o`zWԢ ]l :p*jH6]y-(O9Az+7&5̠If͒Q+Y y< Yof Zp{2K_ j+le ()+qZ'{t$O8*ann`WanśVhEh 媰MSؿWD&%vJ\u]VIifӁrؒS/DY؆"nRr=.a\S Uyms9$_m46SnU]v3CYd[u:澦`N o4+. Ix]I$נnh7ћRޘaҿ^ڎ)7R [voFlzȈ'݅>&%.v3"m#aMdi^16|KY)_YBA(=')Hml1αWT7i~\8yvA/?Ӗ>lvÿ }9p)]n8К]%jpòdYP_;6WIuy eK&.-t%ok5!&lC5¡.K>C eٞ@ku٪ʖJم*if\1XDRXҒgxMMW5[B rڣJkORv#&"8$G}KrfGETa\u7'tY[DF s)3 nn0ju ZrD7ƾÞ-*UlmAl9c_6S"gwKErËNĥ$Ks⺩[w2ӎq.G|@{Ǜ&MԶ{[O\jeCC"'׺S #P U<5([ebD Je m~$&KhI+1q%O&2"DOJh#W扷i+re5.SYs&U*o{TdDZ<}/*Y ?q~pD/-dG6 )I3\Ks$5dcc  !do&^RFGOtLȪ*.Q`{7mKp|\ Ij$]r+ǥVsKftݭUl&ljc]=Ճ t՞Wېw߇]:EKKγejH*,US7à`P.E|v|DhPm{h׹URK׮)5$IAxL *:, K*2((˖UQ!)#v8orJo *OuKfUqx\jw[CK̃Qo|*r<,$q@ gQ,ԭ(nZdY~V([壂,,05@Iwx°P̉tF>Fܽ/F>= J!~A&~r3+b⪷<PK%uK 6%Diq+6u2Do4d6Kazy܇!D62 d{v?s> & lU2{M^O>yap[/&qH[~_u~:Č̜8,QS#!(wO CyUB&#tn`p 1ϸJ.XU8C(w]ia@EU~zf+ ICb)EIJ԰?7qȷ|6&R#Yw26'I6y \CeIpȼ8a}nQ,J󵊿{yLT!1GO.ƀ.*Gpb+PDŽ)w.Uݮ|,kN;j%+31"-Wrrm($D֚|>`TuhuE0m%J P㔕xQBb1dHaKD HRC$Y]x89o'|hZӯ'' .H4ӥl$xpv\S/EkB-.ѐ9 YђmpgG&V6 lG{d/=e--QG^~!/oc!:B^llP7zra\$?=m4 7)t!2ECi(ys'^o0p@'7pFt^XYʗeۚςrÂ}C)!v < $`i+œ=2"Zxvj̉r93Ϥ PF!hJ\i|yCìY 覆c,:SmZˊ[d F5E3W?T+)E!E+U~(QBdAw; D4ޗAGpլ_|(VBZPsXD_j6Vɯr[ WYaS=Վ15CӲK7rzԗ *^ڜժC_m[rp&j7@H D!!jVcAkuVtH +rMQgqAPgRrEssEBnc"`.BraK}|D_-aI*z,8l\i7 [FzC{(. )<-M5+|hےvr|}119'U>{E L@A48:Ąž#퇯"3%$W[\,6٭%1rʚp-\Yң=ėG{Kq lC[fqUw9|(pq[S‹Z |,Ӻ1@LtHQ͗ ;k͆נI63=:ʼXq/ lM!:n\&櫅WS e{i cP(d6F80 Dgjsmt) @F 6VWի:ȯzߟi|+ČQƦiO ˔Mu59E]\\&&U (;JQAB/Fxw|Ұ^#F15Ko^UOWNR( hJq'FLC/.wA1{vYGor1<椯{b+9WխY[|oä)wO 8"ˈbC{t(OH爡0auƶ+%j@bA>j(V@v]h_^d|l WO!pRA ((UC R[/6$D[xKYG>LfCBqAxg<8Ӯ_sx!vV[@{p G(yyyaaňU@gŚ?}>| }hSRҗw %Çwڱ0s^x/w5:] %Zbkm%a] >'~슡z@Ȼ3АR>wB'T _z))Ǔx}y5ZI#xz{ R1+YBdUJlt'~8 AHKO:.6 Bsyw8.\ 5% vFl -#XwTHwmF'@f{t)`.BHN o:)rG,1&O0Oe#VʚR$E}AI >|?x( ^I"PZc4ZS:QO3?@)92[.yz 6S(cs{4e2Zb0c]Oq7Ngp麭\#Ows`d6kpw0p3ex4y{{{]HkePgsuM6H X:iݶ'Za9H:eP\Lӟ"*fz: f?ំ?x4m6C`qΨ仨4 ͯ coooQf$.;.[@$K}U++j/uF?gsv\r??K5J&;X\|z]o:9a`S9Tj4AH{hQ{sprPU ""!I(Ȉ$(W$- *$ywy>_& c=Γdl 'qLeB m...9Zc0h@)%),x$v+YPdP(jBU?o04n`L˩yzc 103z@´".m!N&?/EIyO=QSjMTн=T.\V}"2gHUܭfVZssi|{hErrX,G;!lRA EUgo%em QE d˕y/GO`C$*UPTSqeJujpx$ mn Di< `c$GKmmx1cr|( a_΄GJ`$!NNVJ9_ #P՗+^k\m0q:v<~`H:=׶ja&􃭑%H^^3'TfM8qV~du %+|:x@sS+bLT7ӚOehg7 [3,+js]޼:YAJYt\Sk@ Fi2] 6l@9/p 3r^s;[tsv/f̗¹[|y{ * AO@x7X,R:VK=p BN>XقQo<p֪=>_y` fO⍶R ʎƳo%`r,lgHU5DO^K8~&A/X71Ғg4/[t}|\cw.dYs1v {gҡ$"#5?)Uz}D %#켦E8((ox,;JK nOPu?*sahNez& ]ZW)t*lmiV>Ll̎wO6з\w߷P̍_V?dLL>@BNBٙRnf|I$V'S&nkih4h,<Yf;d@$4wƊjG"P,[ϧy-ÛNpTG4^4 NJK%`y[Y1 uqS!uў: żאd86߯WQt/[<+724dP0*Ҭ~V8Ėó{?OCj P|X8N';1rlĤ>)[/Cj)*]`2I!z8,v:SQS S&\m`QŀX{-;yF3k+ A#Qt 4r=O jC ;5=_;(̌%fܚςHŏnvyYWs0b|(ݍq !(m6oy{ 4SjSY<_1[/̱ZΧ?KfY+m*x>8`z  g@-++5yd٭NwHޭ-oLvhRcC2rsi$ʏ U@d)!SXWSsv2h6 `U3ynNm ƾ5YNJlUewj~_R<%SA5>Hk$1#$ tyVc}bhlcrH?`Frp䈖$ͲuzI$&btl˃řX† #B2SX ~2:]O; gA9F ,c0BXy$'"&vR 㟯7~O$vJa$mR(!n:q{5_z^B`xa!+A bXi=kw>'M< *|j[h1Yόt:-C.u .wzKW<^% *ڠЭ, }bѨ_ !4cMMME44q~ap-SdZf?uΧI$h5fvyi#<2$~~K̫ڜA rVju>Bh,Wά*h$8b6ࠚݧ`D(8"W}I'ưP@4M'hyf&4#cz]ȵQ%rM#Z@zcE1bgan~)/UE3,)rSA b B=y6{Iᕢ("6/?=U6)nb7'Oʉ< م&O8%u-VVXXC<=[#q,xbňQj@* &+P |Q -U;PVz[Fi;[YM A 23b;Eg95Ͷĉe`ٿAbΫ8],@zD-n{)? 0YfƝAߨ#3Ynܳb}ɂ@_ _^ Rj6}8Zd8(NFvj:,, %.x>!"mdQqAÓ^pKFP )\QlL7nSb`2zSJ;?n RsfsK[/竀lLRTr2,^ü̐׳Í/m6W} m#1Ճ{:;pr##ANHb{lٱ6I`"?G՟Fƫš@y"?TH~C[+vSpH6$f*5~6\U)P. s\ZoOl+VD I$rF['؏EMcbunO׋Bm.ag“96~|o56EO:;S^/]|PF># FwȨjB,Cm3NbQhq@$2ԸmKLJ-i\9*B\զAL*^ܺjoHqNmEVsB`GI}p<ގ0JȲAZQU}Z'Qb*<5<# RrKG혊(>~r$;H1K0uV$Z? !–dsl7: Fo,T'\5}dkc(Z#M5∪*ƚyl&543#"8;t/J)ÃF{NTK, b`!#^CNjؗJu)Qk N⽚ G,v9G,9`c<P jS,#n<1(2r|Ѵnur56D2a_vq'C%虐)9b{fRax)\ MJqv[6Lj]ٱʱ}L<+QtY42,#ɏ%le>T F^v9lZ ~^Z i!8Bx+3\=*^H$JY_-Ui&JKTjВVt3d-4!yD`Qp>C,\ߪFa7u3A5j5Af n'1\fRl6WDDEt:e2^6 F[ZJLlPUAVIJn).1Ѵߺ /ފX+t5!pPEНe]dz:C]KgZir i f2"v;y5$0 UaaacI\---KpqqQ,E?yw8~Ѷp<0u#H1yʯu[nxLK@.m{G:uP&ɤ1p G8W$ă5PC B jGOd.Hm[{'2;nTV\\]C^+k0KUkȠݧ2ٗkt]]\Kb|^#WOl$[y?ޅC $\? :BGi+i.D"bWVVf@@b׺~="DIV+o:K (4x4]r>+ۉԱV۠[Tߧ6> (-h+zn&>0r};ޤ EZ1 ?(dY4 x2ô`9F< `kH0c"bflJfήPNVw\ks<>3#9oq&G3#~oɗ : M]-l([0\FsxDC yK 00$k*)ڈV-V{''!(Xo LyCô9_V#Tϐ[^ $ NKof[a>8DFE"[vgqwkFHDw \b Zmy0_0!,00SthU:v5y8Cめ&c1R@E;@찰l@:])\m6kAg[%p/ + c䴛.&8#Ңg]djbŞ -\o`9FVdEDf˼@K⟉!''ف6]&q-J< j7fAFEX{+\VJSf^tӍc%XL,X{L3ԀR$gX3Y[Mc4ur046/̱0I8@`YX  >^4$φ2}ߟOqr$8iX2d [mfu^ ;b2U6r7 x?@a@ ϱl/7uUsRSF{YVǫCen=_^Mo#.彥.e29 6ZU5I|6;:p(H}D#f ==. \Xbp,cȑmomL"5/R Z(/_x.W4_1[[[[AceX\-&www n-ACKPx 5gVw{ 5fZ}r<ϐ;M122|-`%qvw<,*ZxL!׉HW~WR*JVE\ЏϘ\o9~lYn|D`룱W3ր$1#g M}K"iCa(I41ڢhy%7-羓 +WAs ,bkÐyM0]zcbSZ0YA$$+n  9^8wɒվլ WXJYL((CTz7ld_/';0_ob:$[Gfw0|nh=katt!ˮăUMծ%@m5lvg1{d2l~<ݨS臰,}ϟ9Y+~`VO8U9׶².iO! R.7\w1}6EGsf=}AݝEMWAFPɌe^unu/^ۼ e2=xyj G ⢲lҏXcvff*ڂ #)en 3h:B)0k}y;d%X^+H\g61)':K''|ѺYOVdoBHbv-tQh_0Zsd߻Wef ƸPčdDy:io}eU'K<;>X!DIIiMJ[],F~°O(k}{;8#ro( ,Nn[_)l1+rYw#e;|jjR~꜍߻^w??2K`9^# FڟK& xxeXnrsy ɁJ}ONzJ|n9j+C^cU-ۿS\F@N,wqhry`PP} idlU TS)GyydBn>O1k?_?I$Ŏ1%X0j(4:d/0ϐ<<,֧ OtH=-g-*A:٥NT`4 8 d >]HrXR+Jbggfd I+j߷B5H-I3I}!Ϩ:g>px^7+OtnES(Ld{yߞ|?&:*u"P/)R^HKq L^brgެr1@ߥ&@ s'; nQ|7)v=Ծ FJը뱿*rN?p v6.IkIPAݗs4K 2R0B8T ;w j,?HA ){c[/c}9Hd>O(} Ll>Yԏ[@ \aS{?aCl9R#.B~FF*|oǼ.QA%{rCϔ-KUj0I5'.\q*PT o*"dJ NpWw/{!F0 ~LN|['uL* .]Ubypv*M N):s |@A%wn/2xݾPCV{XGz{-BG+G@)8zf v} 0jj 2b*O VπmטjD JjYJ9NO6#-@𙡙ٛɠ1RbҦU=/ cյ?Y[ W Y-bW$L-M(/Se[-bP#\n5@w7]?CQq1*9fX ^jl)֢o[N2 _/l; H&ooO})t[jZx:2t6 ǔAj1jY^ Q/ʥ ˖%y@Li@E+55H/l@Vˆ46Df Z?F?wż /WgP$#j Y`x(_f{z. <ɾ"5t%(]Rg/PDXkJH g/1 M6.AXgf PsR"D a|LoU Ngkڲ>̇gpX+}`̓P3[J4 { JŊ:eW?/JIt^~S %ͣέ%ҫP0*|uur?d·d&$O b݉[/[M wnzCSG;󅔋o5د >B3.s@"h4 a-]ܟ2EF,DȿVƄ0>iYz$|l1E6[od 5 <2J 'qٽ)̖[fŏedڬJ4=|_Sq e !2 o/AoHCJ\-.ZJTw@ϥ>~^!eiQW^;7^`A^G -rfטh 9dVPY(`:G![J; Ӽ!ZZ/1g'-/oTT;aZUdlʺ9pTdB2bH ")K0nf5z77e=K_as^HQHO)38  Z۔LvFCݹlNSkaSJGv_lq°8EKwu)XZE& u b[w4ʆt31 ^Z?coZDNt9cf$$^ߧc08;=T;?a6\ 3[^+*A7EPɐknꁶLBʉI˖h_woҔUv߂޸26rV*G8H50ȮMn\tJV:T=OUi_|$z;F8DTM}ʌ6->#]L5 [7q!id"I A_$$`9n)uR'N B#&[q@)k1ʅ?~RE۝eC GL宲%?y_qLΰk+\*5̟K ' `*Ϯ/lkS&K`b.?5zί-N^48 n0eؤcΡ8# o((1oI7& u.T2Ԉeӊ Nӭ ېmO!jJ(IRQCS .wԚɉ8~tIݰ{ڏ'-Lz;(s>"'O( -koA̩m>I.'ܾ 4?yb^L?j[Fӑ9p_ 4h/f*k+#2y1I*LTz[ň˚ \FdH!佳o>  V ՝DzϼC:|Stf2zsw:x+H^ T,?X|9965EbN5%Z#j!#M + p,ddz{HoU0]p/XpO/bX<9e ̫F3rÝ  qsKASdN}/_4GyD_zӧ Gz?~TUF饆51 }i7@ )vtT.ە_+9V=^ܽO 4pXfw-G -m7'V 䕪¥);aٿlH6;gV$a Je'>C5ͻ%y\ ]d-AXXC.ʫv}!Цp.`7:HE\K|By'!/z-9YVǟ{#86!X8&T 鉪ב'6_]eS§?,?x;WX͠QgaҼSW`zP֠M{ĖqY27١U~GLdw+X?px">zjR? I2,,QW& S\E&X'Nvai3*F=(+tAzWthjcTʦg LL¥.$̊2 `s7[ Hg<+59*(9AO>y챩O.!|5W_겯 9֭.⍯Y>3i*)T+u[ O#%n=ק<7괟ָq1BIL+{<4Q D)<;R(iEŚeW:rc3l}nݩOU[<>ָ弄!%>d'm!1%zUy ~ud˱@͵%Ko~>#rܪ j>fѸHsꁝI?y>O7A_XVX_M+<.fsJs4Pu/0dZ ȶʭi#tyc( GGeu8^5BsV.Q(:ږIFS|KxfiP@E/贗J2ȅЀGO0w2&X25cׯO䫹қuu۾z]#{?6o)tL^7u5]b|阊g~}B6ˈAjjiT"_j b{,AfXҰx-)' "Lat2LOi/p M㣻SmY M бaV<"ke;@guf񓴴c߲¿T O9-X|r}C^3 a$t&;Ɲ_HS1iȀadA % :i>7&`9 eɦMOKkyCX:fIG^D:X*Q^n~P`Z{$ }l2;Q9Yb*0=ފhc~漂-ITq%!Aѿr"TPٷfkln0|JUz&h B0XR2~}pBu[{pO{q#S!ϡFPQssrx׶!=bVi]mo/{hMX_?;#kʝ}{L_oDu{l* .8U8gJ< "Nӽy]ֈXa|  v D.67ZrĠ2e/q;(fp_LN/[@$]`^;:(OO i-tmNCxd\Ƴf9(V܉DZ{1rMpC*7-F"΃AJhq~؀3bX T9PݥCΥ$N1HŨ //mImS.BfhI*/CA9d:cF&nA=TT2w5wxF~zKaʭ9f2<Ob]f:*;P +i2U#Pҡ[$Tc"C`D|2hi'[ͭ_:-[EU6UB8KR%6lZä,Vk*џd[\ pZmrBrJdPi|~_e9~0 6[k>縭at4dO|hԹO(Z,OҚI)i4rQGaY'~;1~8(DU. ]rS*I0kpw-vX>*duIB?Аc6 g5lBv^ pN G  _^ o{1.þǺxx2d\&pnHdbUN^aݚr 7"E_ܧ6Aa^ ףr5UW"D?=rOJ~fX$Ѐ8T ΒO) rH\+F:oflIѢ kx_Ff>} 6򗊓8Z)@{_ ۴+}y/0lLY_V/r^5ܝhA4c&8&33UΰKK4E * NWv,vN-T=\;5xpw;kzjSHfS[!]Q݌sX!+1&88MBLywL6c`Q g?֤EzU45 )J4-b*r+p_HЩbqz"h4S]i/qUTli1갈a)!$WV -l5xC% ջ(%E8c^߳r_DNKyĢ|ӷNsoYoշCS?Ō(+&iYZ%뭂$$ׄ3C ]H̝4$ ߖQ\pxdfnF m(@+b\(/~+A~9/Ǔ(R*U'OR@Gut~rch y3 ))%m5V+8ff?%U4VP;('$Փ||o)w "!$i44P`rҷ!}CH).s@$(XKq|(9L0mX|0pf;?`];q@DէjO:K/`z: Q2SZ\KUwXZs¡C# 'P`JIw(s`iŽSFsFlf=B}v]>~]әR zWճ״ ,RB",quȎa'X|?>Ϣ[ӏ󗶪vkE#C_Ώ~ {QlGJm9 j8A-h|RY2\cfKN21.X+xMlӪH7kfͫJF4xr&7[]Sd(y$gu^B փɅ$=X;=<[C8;zAK`>,zN>uGG%x?:r򴃍+7 vqƻ)-8;[=q?Z${9JHHxnhM,pq",raVGTk*}.[*3@ԛ?e5W~, s**dG_Qgy1OZ8ARI-;+h&Os\vΨEfw27dMm=F%KzT>j\Ws9Vo: Lw9,wEte9tCJAs[F/sXPeSefOMX|d&^N25ciWPW\!esdott" O;Ɉϫ#¿У?1vP|N;bZ:Fi8@3e!} *E5kP~@ 5aENt*)}}XQa f`T~|1qbEw4{~#1 g-G"IG\C暾?X7K|tr[=j\oa.!o!fum~Vl :/>ʎ#깏\;2Zb'iO$^`hJJTMxYL<'T/4&k&QBwdׅzʳ{FM ZqqOsM R/2a ˉI$e}0FV )"%({b-'_&h'HsLtwMfZd Fd5:;d:YUeojUR.uOum^e!ZQ[A:00_27jĪ}=cn:Dasɬ1bӔhMQ0rkO"5 JR$/v1§W*+;p3I2O9.+Q\z& +|\ {7{UWfB;,fU;I`(Q]x=Y|`1@]ģ}gళt3j#'"ASO;™;_N{zEB{N~sEO& k75fF֚ ^qu%Ƙ5Zr U(EH;-83,s~0m&WL.j|z(hwJHNwi\MQDV]ACaQfjp^}^ hn?Kٕw-AF]걫8gmW|>/|v& 8g][@͕N0|rajYIBn<7/Pz- iA$Qb/Y *4F\x{m WqZ ueF2_ozW6~]1+ oh(,&kA,M뿤zԧnǖcuX'tUrB̦[-yJ1Z>3 -(W(ۚ13ru5? vAU-=Q,ѡS?98L#s{( ħj.N|lnce*PltEG~}uQm|AU&xgn4GgSMm򇞴3.6Tv~f9(k5;NmȢ{ѧ?v3*t |jubofz{xqt6_`svM 尶\d3GMeMx,Z9H#Ѣf:,#DvgQGMғ[!ɩ5BcL(*j ]u9~Sφ4*[k#K8 ^rX("Xq:@n7%BJ$;!BgXV 5 oH$x2%"XsdL9]QWwi8,_.6¯?dhG KNCRt=FKr;&O;G_xCjZ@Ғ$=y3bi7.:y g 9&(rwbW{y^<ƸLE7K7l c.6$]g2qY=~Q#ɒi2cKzsenϊcuŜhlS[Wr5!w %mC؈:__ -)j3!OZ]vy6|MIx`aAa' _}gT*5uZ 7} 8VKZLۚr2aB6ڞ4N'fJ 1wN'>C$)<ͮ?99(n ΂@=O/ 'tŒ!^BcD{|YFf*8''d *dw_QN֏V]x^c[4eS[Zk+u5Y%F&ώvvǪ dp54S{IJ3`Vݖš: qNU&_Li{ K|,b6jda&K|1ܾTy}z-Г.D>]-X<63GKz#BV<:뎊7/bFdz5e|;p:hx |T"*KeB/Ú1-a.ż=\9]nh]'?}JW>f037mRjuinOkMH&ڸA#iL>>B}bC-9e-KcfyYo2:kDh) scٞ:,wD`ʗ/^؇ʬM5=5$+V@)21cy^8|岫K1^_}8 c =u+z)!đ,}\ج2Lv֧Ԧ 5.k̮4˶880,`+:̎LHUFk*JT}Mn~aGE,SU. 6{܃ Îqvo)O.7m a=d$^ $EeO 7*yeAvAUWbRo,ׯV#t|I8%' Eؐ(cd.}{n-֍LmO[L]6}_OզqUfUUCUfath/vG`'ewѹHI~KFW՝̔-a t=]ׯ x2kCp?(6>9.լH *ҾhvVjMڢxiyy_T4N;8!ОAQgV(UX,ϏkkGIno]8|"b.'-jUZ=>=sM:bЪŠʺ`ݟ&2l}z*x8&a`2 "^ub^^^*Z#k"mJvſ+%%e0)Mnf%([@2#WQD엲*dFQd/抇5Ƶ -%!t&9,Q8ld$jyzs+^'dD;(W|jTiYR iwcMfrVL cK&zzfSye3Edv2i<ߍ:ov?Y Ebvee%[V20CfQ(.z5JEKJ^hO=.;WӾu-o]^]D?W2**qɸxIkkK/v0%0O^>wO$ޔ,Ll#&0j.XXXOR}dDa+Tl"`.I) -rssOQ_[,c 8ՐVȀqNNfLv+T{'uG4IXloF >\dd# y 7 ԽhHV}Dv,`w@PvٙZ2%7v܍-qv:@Ú[䕀/e2HR]P@xtccZ^:@Vl\gt$;CقR b(讷_FEE$5yYdv(bG<  ;y\^PKW'~N|(JLd?, oVcYxTn F^Пʶ LLacV9.YTFFFXL-Jӹ'e'k~]9IWy]r?:>nmi٢噇W*_W1Gu|# KDm}.Pke-( ?ALM󽍩0S"44Q䦆$]jX%FwNA[js5Xk[&w`н??]ra_122 .eNlVqffLIlNmWNh2vS멢O愷R9R4y*&3f%R3zBgIP8]#'''9.E5F8m&H %lq;L&?^m cWNqvQ>"B| 2`ͽόUL( 1 l+ ۼS ?s N#YQUU~Z@0Yx| Zdddр?cIvͱU-e\,E3@2,8}ukrTK.Fz(Sa1/;NY*d=1D*]$R64p[⤼Z{'\{ %t[,zrK y;鸹S~E0lY111nz*eee9?b|m;@ICIjMh <=yc02^jޞey7oߩ^XR7 )2Tp/̤'%MF7VڬFĉ2P4Y6~?L=S{eVS.& pԃjMudgQuET44;[[YSV4=C-OZ~7&vШ0`hq{4fkcѱ}qHX-;A $Gs`Q'QP11Bp$c֌UAbbIHrt豟-_7M7i(1Z ;M#:[\:WƑ;TZ ;tɉ!`"䦁X84Ay(rK _!@Q qQA1ԫ6{Z ~d*jZs[k ˎ >P<i#+MT4 Vv66XB;I-)M=MYs×LJ0d\e66Ha>иks4 :5Z?gd [*E1x~ZLv!'tc? @K &*_EƴXcF غ~RU࡮biW\ Nԛd mGל ֕Cש`63ߊ 65?!'қ7!rZGhfH~;0 b(K `)+kHӮ1K1,nk_adr;j$N*B=iB5 ?A&2ߝo鵫̅r|8CAV9L %j1~J}@vR>dK&D9Xj0#ݧB1c]Rw|ƱA'Mp&n>~46\OPp9AIoZ,!j%ШJ|"߱2">K[BwH,@̇AN@h?WMxc$6wj8 b $]qJ9:!&!1<H`dm:Տa5a:nB51U) 3K nx\cIJOԣz х^ĸzbA,0zwEhXドt7;x鮖BB5wtYA{XNjGm^MeU 9.,0( D{{ :$n,Y9{`__/ܼD6C~ H*QCzt5^*R&*?Z kvzݠʑ gϤYSe6f;Wi5~q S(MMM\aj\7CIě;3< & ͒1iv4@-D9o.]vzB5J)A8ub ßB&{etfU$Kj(M&) V(0*kfi\)ilD煲/yh+1>Z`E'otٹ ]^QU Uv+Kx:QahTe?L""B Cd97/XFIyKX4!?dW^-V_,}F! wb" HvK4[SE~~Ue.V\z;(|G872rHŇ ڭnb QElJ7m<+qF{VWSڂ"Ƭ(/_ʘxm˗A$_$];cg` 3J k_/_(!(2@&u1F@jbЭ 6^z-Kidko,h`~9vD 8|}Y2 S|&&%!ANЃLH dbo82XʍF `Y}N`Ӿ\Ѩ!$h5W<sn~i#˸GJyQpD׃bǪ+VAy|&7s =:9b!&Bʖ'l"rO{yR8]_!T k T߅fR `q$1wW@&uJrHtV@o^Ɖ()hoNbFl׸T MzT:"_^6jR1BvKxJy+db)4Kc 2 &`Tڜ6_ SpF!F,w,J~3/p[t`c]A,1n 9)!/" u7[P4HW,y 0@N/V[(e&Oا𾰢M!/".$z2xѸyhZc{ݘO5 zάƠ%F@):;OL;}kbjG~{\T P,k LkBGV8i"\ o^(9%* kP#rF3$!/_uQ5lpWPeOeeD*_SٱF6QwDؚEk&uT8"liF`* p HTФ:E4HVjպn!{ۡ_B(*yS:01᭭>јcv+M#R8Dq; d?|;ƘB)mX[l aѨ!PbZs~~`J1g04}3Δ=n/s_`e8bC~lXjgmunAʊDy0Yt`)Q'yZ9o7@XOjh!qRt!in_/VWUSp8Cx3U,ߡ$}:6׈Jޮ* OԊrL QJΠ'5.lM/b JFz^Hb -?\ .Nm+ѩ-ѳ.^y_S WCYY9\4S2+w DL܏sD?NI6M[]/&Ш*f1꭯H!pRK>M"\t56Ƥw tF TkVb[ Kه!+<|AGPH&16rLLH9M4#EGů:\^fu;'mDo{2 nlޘ{V2suEhxAV~;v@uk`{?f];e ) WJqUF'0V@nW8xh~w >B `XV =48P6覨BYjxbň j$,A1t$=0NE%{AgJ^Nd3B>6V<>d}Zq(9<֨ftTfKۋuOہ͟+La/mדi1B-m\"bETh @~YRҗL6e6+F_ZXQ:W|DyK2|-W2,Ɲb7s^:^`@WZssj4!t ^ةoU=63Kjż5cчT%5E伃zA).<:㸩5ymDJ"~\W*k:F[&˓<.8ʰ #-$kV~i7_#%򍙩7w{Y'teIh0-`ZZ)'dks~Ϡ]gW>+lp4)+0. ȁpcՑ?7n[a^n}[^|5=~H\׫KU -x.lɚiM[ټW||G/aGƷ⁜ $sYOڤd ;& |7a+FǤE5dkµ?]]/%+7>68:&8]ʫۧOh'd([_Կ|Xpz!E<nJ(Yg>G5u{x+4LUo)0m-ߓbQcBH.0+ ~y ;"BOt^'-f,~lWY+!e.o}DQe,{ .:ޛi#VfTu ~V'QfC .o+70~~T=˧ndwϕ&$ 4fPP1B0}7󹟯s)dhPdM̍=p + 3u5{䒊esY(V`% *DbmҦSGH؀4yZݤVd/_`4t+CBB_8w-,4۳YjQXT6Ap ʪvAl0I^`xwPv{ M @\*+.49mF'O4QWGv?D/m:9%yos Z=7{}~^&n24 }',OBjgɓ>A>G9ZT_A~~ŒZPC ,*y5iȂFib'U@T? fJ  `##2 _Dn88ݏ@K~5`X|uDܢ >"a,((X /۬nF~MIIY{+[{.7JDbjq[3[0>-rP>3?bԯ*3uD$GyE4#Vdzh^ Ec1jOh1^nj MJ ,.) & P z.DЩr"ц-`r -\oOIixNj1|tOxFVkBCݏAo=/i`tdkpnLj2l^PLXlun~ƒ>gR _$_.԰~xHG_:̇oRݷ;*ߔZp\jt2f]8F"9U lGYlg9eJ8+2䴏Ĵ++{{䧕ѳLmK (=<3Ӽ03/R" 8$𥇩-Z@~G-o&|ERp#֬7;o]2?6yP. !fGfW1!"&}QgPx%Z}Ha%=t!jdy*5 +@&|cQDiዄRs;0e.OriHlVZ $ɖ*s‰܎>#q,~%+ A?Jq"JZ $_~< ͦXbdg߅8l jS@K샯:RoLSStkp}p̅f`ԈXh a_,H^ ]733MB!W sX"ۛLYs 5dzz&,RQ/|f8ž3ٓI)wu0׮|쪄e{= {gWyyHY OMF*7'ɌTq 8V%j@6(J)ݲn Е >'ZNۻ%lr*ItM!l=[HE~=˺BRF"aao\Rw# $&C8o9z-K FFF7q?:lB`ZE`1ad8^bWiN*VGNe /19mѺj~П" (81mR|<^s/=|*q 2%h2EitZX`_,#KLB2٢ņS|GHX{ڡuBEqLrl]UtҹN=ȸ{Vkp$hԊ$>32~ ]izmmـg ,[~-vU~<NT}CE'"j|[g8#8ju[Յ4NB}՝isZ*_ӧOÙ94nkUq`N~[?׺b<ˣ?׏id±<==Y8yRXL2|d5h}_ճveO:\n2pjy feF/ 2xrαԜW[(z{{c2`k}zr3WXys" Bк@g=x`eKiůU?&|׃PVw}:abbbr'(ԯw#mޭ1y]>b@L~ A[NK!oz@>ygȊݾٯhr06iY@"jGtqcBkk!RU[HvwuA!dR.e狣sTbjߢ0 Wǹ# ^g Vx~L(_E9 Lr9nj|/WJX ^I–ZgE;5`@.v6J_C&'/|xA.с(9؜mK6ȱjl睗cCӅD2EƧq'###SWgBdeYc [5 8y Ѫ/R'yȉV:%$Q555mTN}_ `wIc׬ @ KO6E:q2X:;;ZK.t3R/V |oe{Akף ~: DFlüˣx$>rza#az :n_?kŢNYRrS^:goWygbgv*zU%dyJAK0n1?D ' ot*Rnkk{<G X0 X;(ɱ.!q݋1z\[[xI62\tFs""uqm1_-ᴆT =ؖmD˷+QJ_ONN^ɵϰ>mv0tw-{*ȃhbTYM&{Up'k2CY1=Ut lGGG NO,_V&'kgf҃ㆳ"q"`X0&`Ex7`?]kXgG'u({@o-臱ˣ~S[lNÇ}C* E[>XBZ;iѭ## d e":%ۺ8V -nM&3KoT`Ӣ|"fkKqxI;_dI$\d컐6X/YqD>d)Byn}@**D] fA;4EyvW<{+ݚwFu\Sʗd[ZLa X4;%jY0a%(n{Ɵe|a9q=9;tJ"n5!\*VL4<BiR +MK\ܢ2*H䞜q_o/f[{nEg]rܰ/R~I!vP8zc<vV נQN|r)Pfyߝl#3,ߕ`մ<̤cq .++Xʷ8HwVe'=M3yEC#So^dL!uzr}B$?/δʇ^I|'H$Pr9Ta|Pö &d9ݺq! k^=$ڈbHV}h @vU!uByF:Qȯaՠ@.U%_F#ULpH x4!݃ƣn .JGV1:444"|/1pA *VxB}CĠ &M^"='٠i|{K( ӓPpLU2[IZ> QL5<^|# G||Q-$Z|?}[^7$a]/"gBѨTfsBϫDLQk-vnZsMحTTT` ΂gb @8ꚢLD"BEe%/ov~Bt ۖ>&ckuuu502l N; ZjOt|߯sWΓQvAxUe=MkrHWS"R2) zCt.|L!V+ AgZ&= ?XgwGT3Ҥ*'J@ŷ]9p>՚ /8CI(:q`9$NEq/c$tFW2Kn= qt8*yXƭo`tBA 7juADzefVx>p&M7 \BGS6 90(ΣO?CL,Q#4z\uJ渣˚ю: p |8Ex{yRyc&R|Wi\h,d4d4T>2 ҡQQ+5VAzը>[czX5pfo}L.Хbɑ8 ٰz_0h 4IF0YaInSS~ IE)q?WjP~qk QN$fQa oS:+>[Ie"W'd+ɱ{b%*eW5d51fI j{oSR'L TP{\G IŏRגeBc}}Y&q=Q-Os*V,4fXMqX5~ô_a abl;yfU 7$pRMLD)kx.|d}1 QΘ!`Er?q=wl :+or?d2HVlR[_AB+YᎴE77TR|@O$gd (rXms>鵳82x2.HHY^#>tR@S1qbkz'`|{[ vuB'Fݠdp] RPkV'k ƒ_u smލ߾m, ht=]y"5 > @l%b\xYnbxC8EJYS{85 ˸X|UEn PccagBX!wW~yV&kg*Ȋ^Ċ\:FtΈȣ6-F݄i=5 ttaՉbwh3Ks0,^hIIx_J6Az'L"}\t5DvՀlfݷLkT: J)yԏ9S*?.cd8@RKIK}՞sz&p?<3WrbUtfqU'tqz$+2}0f=Td K]b{ߥ6 jHsiQ}En _tX@'A}@4!ĕ bdK6{c])eAҘ~^YIcIy Yˆ탎 }ӏ9e tTF Nk 艳wQKF,|h_^>qiV;aRdkrm5/ޥU/ImNem 84^ӀK,̯"{&[H%[Y8r{ޱ˽϶3xc٦1_Rpո/$0zR[t,9a9֞[bkVue46,nX3a<Am܋Z?Z-J|p8=d'BiQ:Ӣy^pRʾ+kq^\Q_ZOoaH¢- K;Ƒ³qh8Õ_: 1ON^|5OQbzW/YF )$S"|?^$6!&; xdpݶio/7jB4.d2 =Fyonh5˽OW] %> z^jcU˗bbGTdFEUT[D|GxgO'1DCO竩11WWLJ^Vd{[Z#$&KаLJ8 $cs:eA\*kwF:T%0v#ŊbzpP*\BJt+58ȤR, ^q,[ٿ7z[jQbH<.#-b~I}"ppHHqgq7 x^p%LDdͪ`"x]xzz2tgMbF/uMBS/_B^)!=1kl,WMҸ_nd@}J^Y}$,9|f@脇G2"1;ZqgsXƼ623h^2 JwEgyTH#+N6˧Cɥٖ1m&51:An92^vPcq?lP5Lʹ0MU.]Ζ$0L^* i|7hֺvfӧi2h^O5-A;hyc`ϢTK4:)SXpxyoM\/_6 5;/U(WOgASXmVL,;YN(OkC4X $q Um>y}%p%5ribWhjewU15"DMu;Rq*tv_ĘW-/^ŀ{f]vC!vV!fR.+*Ng + Q+($%W2''H5F\̒kݟiRr=) ;qjF`x4vD_VbhNM,=!NMNAFwLW1B ?_bӡ؏'%$-_S!Ѷ-ÙR9LzgT77`ı  S0^M`lP2P#UFF nV`wnu'}LƢβuNWB'8|-b zx$:ϱdE&A l! ,k+8;yPORC(e{G>P.p*[_C#Ts+xhGT _OЎL<\?fH 81$.pNNNcx1s@zu*+0p:Yjt=^AܠͻGz0 :ie$.d!T[c)".(bܲ6@Gc8J˙o2 f#(3"eRt6z~=|/ B#h*DO˾Ą"Q$w&.RC|َs MJΔҊtaa<kv }`|9^cOƸZy\_O:6O)4䐶/PVA!`QQ 40F^ |(܇,X(ID^L+KՌJ?iҥH$— ]Rňxۻ}MTjf>%AacPw===+++2j*Ayrraavuh©Mcgٷɫ;LpcW\Jqef@Zjw17s&h聕ԝ:k3I]mAvaz=&e=m=m}[DQF7:ZaXs,~?$Р~?4¹YY$O}я|Sє|bA khgjjoj:kSj"aG X\vHw6\Uc8UJA#JUʡdq=!n8ty*lf6䦯H{)7 '߇od:ۖͯ#<ͽv:νZ`Bѱe"[䤦|>ح[<#*1D$XB< `a=rsdM0EO^Di.7{n{XMhћ*?vtrrwȂ'1Pri^k5ߧToZ'yd}Wě|*\6Uŷ7u_PszNvR_uqљ6(Nm۶mcFǶm۶m۶qw|_=֍˅ꮪG?ɳ  Fȯow::s&Ȁ_yiSВF |SV8_ts{GLH]tX+/]#Ń& v~cƻ.OrS>ǡd2{ # m?3emdٚkSrMdJU>M*ڎ)ToTBdaDyC3%J > ˶WvT YHՆJwmOcQ;Ro?u֓0iTF;2 Ěqힱ<_y<,W.w>;OO\:'kuVre#!Va1yn*F98 !7Z`TFkyhr vEM4=kQŦX%@8pkշ%|ցzYKP8hݚ`6o0܉.*Q23 m}1u=O3?eo%qL'K{l~6|ABʲ}>)~ Xm^܍欈mc#$Wj͹nJ@nRF'_&:,V Gin t:BJ7uEgco\ksu'3Ybb?ݯXܝ !"2ޟ~H?`tCI+w' et>njɽIX( Mx$ԯHGʒhtoW~"]QpwDƸiK<'LO7.ֈ&9LޮW}t0U S6s!M!(܂Hy$ı U4>g ޿9X^p>#U (%=__Z󔼬5@~)gټF#!h_Q-NdJ\XkoO6B+7pL3~1. I?svhz;+:iw2+a it4Df :Ki`XfVY"CQ!.fZ+/=Q21gܤޑ2*,ɤ@Z/CadqhI7Quk*WMLW_QB\&%_ƁRS8r_ME4tfYHXA7.I CJt@3C N*IZxtVxsKr$R]vf@Je\U,#;TnĎ0 R}cq[kpZyv8#,M ų&`4^kXx.3=ވFwNsTb1?+!=\ݞ8f~MfnQRơC߃VЪgV1ɐQW WY) E*Sv`ƒo)e7ͤږ p{ x:[9oXi!=3WgoLTH`S5%(Q-al4=C#T޷i_"u0hzJc֭-z;J¥Yxh Y(懭5W׎8퇷@t^sr?s!}}k0.<8%zMۣkwqLV?%\=Q[#\,y44"G;9pQ&j֪/d9{<)9vj 쑧MeW?ˡLa?yv^Nvle.*~q:s}lczbdٳu{Va(<[=+2ߥ7*ވ@ %[>lvOPO\ Zw1.9vv]8-鏑ɸf!;}B^5o`p_fr>wS\3BgtiJu l P> yUQa?Ny>p( [Nݙ0Wd1Ynh^KߣД,0HHw>51Iφ8=q_Lra)aWbRf CkҜbR} dKO׷Ci&sG\^VՇ҄#~:L wOo6k0c biu~oZnGZUr[rbyS}Ad5F :7*VŌk}ђCG);k91(.q!){Qm@Rj.Bk͏siJ?U/A'Лb w'4.h ¿nhwЌ#U ]wptG3!5_RV/otTUUPOے~kVDt pD5sq[@A]` AS?+jZi~}mg2͙/`Hm"s7w\B 6s K Yrd 9qQNuks-7ipaܴ_pp7Wa"p@U?nuI5ūosSXSeQ@nn0'ѩP\]+ie.列6׏ x|raYg1E'&/CZ,78zb 4sgs@,8 9kюG[[pG:Ȩ1Nk|eM'(5I:daہ}gw.-NDy75+*,zP4b`8q,ufRxV{(p3/<D~ LmGG_j biw$2}gG쑶2kEV6SkA!҉$CsXQo끂Hע㸵u2Ohl}~n13`g*gr^хSZ&/KΖ G]B/( CdHIO/2ײNL46גW/h#mV7m|8@O:!*׀Vg7~Lp3e,M 1 9$1ƙ2,5Mm`PLچT\2h t$19;`J2 yӵK_ M*\RڼlxjPFPCT 7)Z~,[A×_ m%5q@Ӵ㾁 g Lt4rYBwa{"u"_ ep@13ME(}pK Rh̿_R~*jyδ(}zSnפ~[2(|>X14*; ,ןJZYPYsOL(Yp.H|qL< S lzi$U9Lo0hY[fxH(S:6cb*2CȩkQj,٣ cѷ;ܠ9WңY%<~PJ`3KB^NCqzcvqzzr>0oGMD\b3.@pQV2?Mfr=ÊC]LW&,8hwktHcX :2ޠCRkkq࢙oi%:# f5R?2*"yůc#~`\?=&W:OeavRB P{W@L Ƕ[͵1.WC7{QKi3Љv*0t:#04<"~ԓ{SUtw})N˔7?;Ќ6>ܡirV9$|q8*xǛq. DOR:Q׏Gc$d|ZΏ\+ 0 2Z/6ݟW"R9+ko4V8R"mA:EH%ž CZԍ5x !5Wխצfw4SS!MLjEMx<,%Z'g*F\-M1u P yJ~Y\zCMW}#3$| X*']ܒ@j}}XxXgCVgdҗ3hu߈wCK[ZؐBew2׳C?b2bQ2&܈°n`Uw^\N)thʲfBB{V4.>:8Pn'X/_+%R@mgv6(:00:Âc*=8,"d+oВᆥ5).B)e n3c$S:誵+jjjDтfV4 %s %mjY&CfD>S?!AcZ98T!GC!АS=T zW7zHMԜ h_mH_Lo+temwfpo6d\[&iLJ7/G|;1j:dyH٩Aak逵MC+gXiY1Q@J1MJDߠi - 9,l.ק=j.s 8CO7L2<CUgWR'&ƏlǪPiiɗُ% '֥a24+ɚEXNe>.辣#Leܼ UatkWOqz8gzj۸ǙeŚ'o5 )_P!gX31/p@*ӚPN_J8zh|W kB=Dh(Q|u8ңYIW0 K}qX_n\u=4flH~8X=G>5OO2s-"oѮJb橯&!6awnQjv?:!N0G6)e1<ɺqG=jsӥY: pjI~]ŸI:?43:vvAPy/:C鱖[نBUͷۍj3!J"\HW~UMKhѼfW($ÒKÉdR5{뾧_]>;ƟHZ\opyN iϹC4Ms2 iFoS,7ƽϷT ʄqz7Fh ;TM C`fw0N5N9dOh { RLo#ݻ"l XJe`L?Dv|Q$rG=B/+.aĿ.ۮ>jwM+Ƌˑ ʆ~G:8;HOK⭖g-eU)JW itD#ör#98Yl+$z-5r.vVyÿQnfPG%̵ #Z)qGǴ2ڪR녜J7 XntSRnۉt'ù}&R!9 6zftj!j}-GZ>g+sˍe)KK͋ īHOg8AQWh䷏uquk"{WbvxJUI9n<-űSVĹ)4sDV%ŹS?7K˨5^i i']W+U貌<-Ƭ+kKkJOX*ӑGְ2s]!q19M gm-uwz&tXR^e3˄ A\MV&z\eL|5%~}?@"we0 >Ut.(Ioڢf~ՊAIcP'%&|%'IgAOe|J)v$dOEE'O/}=}ѤT)'Ѥ4)'ɣI)ijT<%5U~e$/J/}SOŸڟT? O L/.Geo/bt_\|04}W9l#4NK!^EyRu7BIe?oЛU[gԵӷt27;P٬%dǶ_Y |H"rGC{斎xyq1] cŐ}xG yiC> TPvt@`DOogm0&=tq܀MϑaY0oc0mѠr )lö9ƫ2`^&"Nc'Ÿsu)j'7\߯=*{M%!e%avB(ĪH'߅F/-qq~y=5{h '8+ϥG( ?+7 #ј47<&J6uzc-<7ZԾ׀D )I6{Ưp&k4җ7k]&ƋP?aLYj4-62)&߁1'A7 ;An{rF( ziuXX &DBudݖd+^KQ,uGPC&zuk./(1|U_{iFE!ݴ4 o! 1UQ"!P:VH[W ʭ, Z'A^*h}Zr<ЏJ B8UGi*^>ժ2A@P:-:~0Ŵ<B; Zrǩ+AQz|+ϭDeǛ q[݊ˏpuownH9Fs頏Gy88Jx.R%WCFgsLTɴv nX` ܵ-1Ѝ) ?rT.G3d v*1^%p㷚|_{o8COt ̶yOFێQ*Y8 ==ܼÓ{ 4 B}GpcR+vV{K n 9SZFb f·ȎM #pĬN}Qه3p ]WfRgOubv+B2V3XPu@ )cרoUyӁe$)E p &V4ZWcn=~%;y HYN;+Kr$[#JaJL.LUXWz)S|ؽelԚ@0OKABll`yߧeA˿8T]S4bA} K,ҁxnFrXcc <@c *g6d@BOQ-O_{_>.'%\弓9%*Ax=MXO< h&qw{,Y%X OK&.] Q~yX,W wfl}cr{0ݴ5(@d;EAzoq%n~K*]L$ Z o8x'"a\T&LJ9zm-@܎D ^i͙}-z#"~e/; HF6f_ߟ;}{apa>pZz 0poi/pՃYЗk_ ;vr :MX;vhǴ,z (Tp6.(t۠!}J"<)@B+5 %iz=V2tI*Y @N/29e\%Z|Ε$h!Ql،Sy%=;BXxF,H#:/z.ӯn7J6S3 &T'&|J jl3 jz<.W}hȕ:W]8)iD+9p)N, 5) bf7%`Ae9J ҝSX9ݶzSKr *9 ۦIdwxzcH#2)EnHZiv_/ g\F`eVnBmhkP-ӮD>avpeQ䭙Fz/ЊĖUm ~m_TxR cZb?qGh Í;ÊM9BLĥpHYqb3o-t_Y$(WY"&U6wfU==-da1$NTxb/`ٮg 5Lk\gZ_ռ2'K"~ 2I~xBC3qHHL 'k F&O@3/ _QE/'ۜJfKI{*t.8$fǾ{/.:zBheNS}(ja3YKV!NԲp^7<%,Dy^c9s[|꿙C)ۚRhpop Rܘ*l}5di'c;֎>sw{V>ޜɪ hBo(@+Ʌ*0 1W X`kz]ho5]:e8aP[LJo tl*{ⷲ'j *Yi1ݣ ފ? .s[5Q^{!*b"wP@:!OJE4s.IP_TX~$!B˃/hIx4Q?-sr;$ 2 )w 4F &Hw\7=5{KtǕ4x_`bAzMdxXf;RRX&;̹y.Nh/Dȋ2ߥ0$_0-~*)G xv9ӼND F*2HaقwbzzҚH1IB[G-jIÄ~vFKnCsuz@H+[b›? Vߘ葆 ڨ^!1~8g c l&~w+qivr3;:o2$ ܷZ Dvk]',U䢘Sc 7JQ}!P/{?x [\V\Xk|h5 s*,?C6ԙFy_G 8$DG!]؏#[i-6{rM0vx7IH]9䗲0x#t`_\:wWh hosωt@_&%FA bcyVj)]3{+;uDwUv o|DB 0vcDFiC!}yB{xvVUF.;PfMκQŴhPDUl ^^ K>FC9Jjk# ̯6񸋬 &S.b!FRQX| 89uI]l4d4]'I 7˩GǿB'7:ǀO;]F!%eƣsNOFW34-W+:$<^Fl_o{xBC 6OF%ҝ셜 a'>XS }4[W?DkosK!-27v~ s6"u.gDa>M>,%nT¿{XC+c4zS:uvIR9ҔkmJBfU9WPimٌyY|R @kv3CiO*䲢 Ɇ=AB56e)/{MV<* q"Z<¥Ni`&eed5n+%MV5` + vu"p:< ?d+xc|ϙL-#>ՄEk=N5r>/G'@jw 7U^,Hym=_Ԫ xʧ)+I 06ߜ1^gL_oث*ĔRZV"ԲiڢCJG4nkrF-72.dL Ao@8&}h0@Pѣݱ-7KKaENhذc/./Բ~WL+L]4= L'Uőz +S$zljhӀb"BWsujecAdYڜdy{*Pӿ9*ajqݔo|l:+9٨IEכ1q[`iH"~jNSIFM|NK>g#1ҲG!ԁA2I zS~ȫ T,7EsD+(3e4ف#֤f觩pu,l~|C7#o\DDDB*&:\6JJJjڪ&.NNN&N ]MHIh{H6inD)䛔nXUo.l< ªڿ52&TT" /TM "׬9Dhcî?9< y 0;D4I'"XnQVhZ(X(д^T=Һz`2eܺ<m$*y2vddJ:VT^;q i(9%u'<$r44Eo2Ob,vnbjQrij~lO`qPhi^diJym|ҼkޤѐՕa@@Hl@BbBb|ApZeJZVHaLBaiZa}urHIab[a@}yJ}mzAAAViKQMQqm]mQvsc^cccП聈aI؝ވ 핼閞彊خ伱⡖⍊ʩM͊΁龤ɦ܅Ⅵ͒큀%͉ݥ‹Վǵ͒١Ձѽչ͑ݝםу僃wn?`> .CĮ;cwWa7UmϚcJ.c_1P WMu(Va+ W`sP1߮΋F$&19w铅y& "O< Lo\4I6 cL NSbh|jgi]4ʦLeiVE2*_ǂ]^B^Ǥa,tӬepO%`mr T@#I"NeSI$g6SxH#x3|% *®Q||)PCEk>6(`Lr~0U aKtoSA!͸CQI&'L~|*mƆ) V}ѐ)042Z=l҅Įx,USL uU UCCޱQ%$T!k/TaM:x6+O!c @@~0 Bl )+I9ɣDd:;-:F]Kѷ4 }ѹ NR"ަG?M-P\&YcYS|:#ڂ5C baM}N G uOlz¡![jR%ﮁJ%{˫N[qòwBxk9oə`Lhc3,uyQ^cd 6wXڳ8`x=_a]l{r|Q<\z>Q_kݟX~-pD"?,ۜ`>ٷ *'Nr>*A<0Y+Ϯιϧ &.,qI>Cq·'nhHyטa8YrΕƛ\l\1_CL2'܁'8bkj/?9FcU+y*B '@t.a ~Ze7W%K6p&:IJA~Ҩ,9?D8z;vrSђ8Lq A<ѩ7.9*BIpvG @vG, )&*NodYlA`CPVZ*̟eq_V!{y9\+=Blf8;K( sR4 s.$%s'h*C>5c/:+M(1n%k\;X{>P闆N!v Q,MK1Mh^3(EM:-ҭ2OWݭlyK,SdB+rJ >:jh5پ{d톇62]wߓ^A|'g3ٱ|%5nI1kDmog6+,|%|yC힦'XV#|dFϭM/]74XDs}5kh羻A"DR"(++s}XOE7y [:E/~Q+7|Ҥ[ P+xw( 8&4+n}9^oN)3͡v{&hJ?d \d Ĝ 8*Wq9O6` D&!l>iKGƜN9ZJ>)ՇC %cD PaEBp9rӶ3mZ#*X dD"ftxwIc`UpwcgfF89Urf}`ֶT;UZc&MZF-,PoE3s1MH"vH1L-K$s`a4!t1Z;pTӺrH.ԶM'SAE.[HaQf].NlDXlWϦm歹 cv:h%4h"z;r%}xQ/q-"0u!m/]r(Yuº8-9{\ٛڛ#bnKN#1A#v.bYxbh%roRT+(~c:t?dolPzNvWzk@K圦Bҋ;_eT Q5v*[X8 %`8C꼳l0ztfyqV5הQC>I\CvNDi{C{ĪV^K)UC[Wg+"ăru3q7ĝأݛxG0ETFyیTAVkȊ^4Vv s/\tVfPp.ʏc}S4J7*b*K,&QY0 wDQLEOa6u`0E:4*O'zs(?ܙN&> Dbvb"2 ݚ8u,  2r^#H(~]_f;I"{^7E=]t\Bv[y+x4-u@_cmm` ȊySnyke2Tfz0ڥ@WUVhKdbR8Dv3.K9 u4{OzFW)n?2FdfCIm_2_s '-mo`RA߬s(% t8^yfr TRj(x Q t%}C6+g  f Fdqp3R')ݾh-z?X(f>>5 6H@RRK!^= ;v* ='NLN^Eexbq WʜFëj&'b>ŤC&|ae2&~gB ' `\Zy_8\dܲ?cG03|HN1K\5hN. .^5mv4٪+㵤k+a 7Ix6.i('Y0&bDզ&͙xV6fiO @dT>|8t^{Kau˳}jn?E{㴇-?*m.Dy{.Ua-DvEՂ~ȁ5Oc,C#kٜ0֨jsogSPU[ jS: {4CdtGUשH4|-B1-+r7X5]-^4q|R*[v/c=s=v߄H9n~.$_ o|;]] Ny@ D/#k< VKabqVW}Ĩ.ap,UJ&Ǭɋw:6|d`jrУ_ "bqFYoaPj"[ԚFeAƱe=$ -y#DbCyȱAhvɞiyF_4-?S4]H4&H !zGVPn^% G<\\ i[kBH#o1ɭyP\"jܬ4'eE}]K3Cq#\}Ke)uY,Yaz8T3AG#;0($X=D6hHLj5@pՙ* >|F2Zf}ҐS`h<u *׺,ʨ/MbKL85YpƁT뫈)q'Vwc⋍5D JB&E{A :7kЈN!?wjfmo9)oWOD *'m5Wm_)סVNѴˡ.^<[2V-JR3mjo ,tů[b%Uڂ]6e2YK T? JnuXΏ3u$rd00Q]dsCc5DiD(MHIgCx)tw_yC_~7 &:/) 7I\rh@oNLhr`\~\``UHll@~LPuKutb|c,*#Bo^; ? GˋFY 4&s q2!lޟ[o5G~/W&Kƃ&ul,H)2(lTe<,Fw'6*mNՔ\ʼnM^ݑ3,̊Yn[ll"|Фv$5sAݧ9)M5aN=1y:߂S>F"* uDYMxX(tҠ[Dkn꡿Ug:9XA``D/+$i 4q稝&5jvǵ#(cDǃ"EG aJĮ TGFqw2U0kT,k\Uh8cacC.V1~5QDǷ*@%fj) ?۪`R@*jW[^M!,"CG ݳϧ2YU?ڧ,kra2)~onl𱗾noNp(BYLEv]fV~tR=d*!K.e+}j*&nYFf&^4exW~|TUZR=хpV˰9{=r\AMˁQSḣ2ZuGyQqugk);mK2{sVν[4Ksa<_IKTH "f;i%{![?hQ|`XoO!@iw2lhlma}>N `;f<^nL|0~lna VKs8i&$59)VY8yc2C#`TH4%]qZXKۡj!iO=\ {my\!bc|?%LLiÀ# SK}}<ѕlmz"Lf  9jb&_ԍxhmSX+BK_=hϬ@ButeHקSr>VF,rnx g|ijw"|G4-m1V `'L莲O2[0ڥ p(k4$r-8OzUBrc4ieBKfh9o8Qu{i/tn 5!:9~.HĬ#} hlm 'q zͰ_Pd\ˢ;61E‡y9YT`zt#j;F%LMfun?А6MxI=G:W\~r׎\Cb8dβl kڔܶf2.^hee pvqf a;W蝞8kvhj7N,ь e}UBB?̭ܧ/||2][h k̅P~6 8E.6R2B'6A#/&^PG,uES-W#911RIz0\%YvԆXal< ۝TS7:lx\|eV3%jLI >/ҖJ-.f:#ʗO7o. ͑0cVz-cJ3/Mƽ+?)|\g̏" MNp9'M"c{g+@ F$Kp:b{wo t/6ؔhC'ߍ ʴ'۝緯N @p|){>4B̍?%g+<!,- m--li-um',%`B?gn: 3Km; 7wP|7RXco0ig2 m]]}3G?aZ7͵ mx̵lfC G޾C*',Xlکԅ{"?Y@w Q3!f~F^Z>f::&Fz~^ޯEJ"a/Lh_IR%F޿_Yhhhiߥ\ǁ WB/̼ԂP20R3S:)!?%/R`R0JGD"(CoXlDN$`3 ZFfe?Wz~&FZj&',7$7$Hs00QS ;saU%]MZDIW\ORz_LJf "Pq!T4dŀA2 }6?Hc?HQiQYRYR~k}ޛP[PZAF+-9- 5- = =gaLgc]l|ƺ_piM-"էmeefWJ`GimklKiioYXͿCm+O3$.? @?yܺ t7m q>|W/?=F J8ND  )g+|g||m_0f/D׉I O1n"p?bX4z۔ԽqH`A/#韔tmxzLlp~ѵf!S¢'%td6+!FҴ!kQQ@`'Bp}CYք&DD@rRX'@lm`1OmIJ H9Y4iY;a}|74c3jd^z[FykvC .YκD+nbqZg`b2lM]*ooTouXKHC?DZ?+M-VQZgg8 yCiչyX!IKCGʢa)%+8ꍍӻ"$2ō(0OYfD0ͥzId +,P'P^p 7k|J{ NSwIETBO^K AEB$ɟQwG pSk"6%ժ A#T.X2D-I כw^ֺN$X! :V5Af71 My^lT5(:DԒ!UDO 0t8*x3fSfmvo03ѝY::Qf k~4`X#,xagdL*ǐTY [7BC0bFPngZ("d]@ r5DE>h?s/҇%Ql=lFT谧[ō!@Db#_0ݛ&W+Apׯx%׀=#@ rձD܍ئPXpT;H@Ʈ't1.I#{Q{p wa'd&9MwýGP,`땊%YĄ?T Wvl2ȿ#|ʝ9$Eb&r}Բ8~!k&_y<+`Wu\V> ,#A C+biT˹i6F^bxCSNQo󑒲,۩$8騄]`=q2կ5ThJ3\PbZ(|oE'WZ d *k̆}X?fbۧ A]Utu`C}RЭTٝhթ)w|A>TP+t[6eFa7]`9EH[ͩێtl+ղ%c7'̿'LPoqVOiE a#h)Zr=λQJ@'%*e+$+UnGW\ Q"H,*[} {;P@&Hϙ @MB̷>U ĵFhGs_&]Jl@߿#ʠ4-Ky1l^ ksH8 CG:.nRVɯ h|Rb|C)l=9d~?@> ({lF KU[榘K`g+8j2IZYKLN: Gx2qF5H:"%W:XG{ł-yiSj D#?hjn@5iS~eBJ7!_fe(yK|٥KKԔlD.wL. #$X9@)gU<uFX{j2!4V%3V"dc\*$kMv r.0eFc3CĂ r\VF+W-Gs;N=0~轥[T[? .oYS|y$ywD YR|Cbb'o`Q9Dӥ8%' fnDטc ?ԼqK0V*w撔׬'oskuIZ,ԉ\V2Q)Dr 5L4Q_AEό-+y ʚs)A[É%]fH`Jhi!4TKTL(YĦLZ}^;-w10/"2]O$z8"lՔ] Aƀ^Pi1KTA wjn DPT0"Ŭ:؇XyO._*x{30F*^5kq+u+|/ ~+tUec'CcFwU5f8+8Wge\dnʄRl!oǛecǎ[Jx9"YLA2;]!ڄu>o֣q6艍 };͹!/_$_ `v6??8  ض"^6_0}?}F1%XX ;fh”t>ßq^qo,'wuSv8!") FagJTɍb;Phfy )S,  K4Qc"ضKMbJ PQ$ _D+w< Ntq&.STЍ*¡ܱHy^Ȧ;="S>ZHVIŊr Na\\ى05ד^<׽S% @Tpd>3` ˠ_2zsZblr ;RE,&;z,I<(( }G"Jh;zhS|E!rCy̐d-<xG? œ3!7r;^qvU{O,Bn-'(C1[ ,8z5uÊL"7jk])p5Sgʽjh+ӻV5?M_\$XًLVhȾMBi iZo~kDO<ۖs ߿&D-z*c6SH5YWHtɑR߱-Bņ>Yr|935JF|)MK.Kx "ȹt%Ur~@/&,RN{"XuLH_ND:W: -L>9!1q*x,6AᔣkA==$J˿ s$ޠĈ*vv .yACA )P!?m֛2tt55C'Q[O1yͺf~\Y95id;WχZCw'k#0F}:̗ NM4dJ{5ՉձifF;iGkb{67y\;Iy"v1l/&Ɣ}Q.{= 9 b4Ik6Xa/ЕoOOHsA`>?D\9 ^TVlJ-֞`XY*[iQ*Ow ~SX|>rrelRļ@CjǤ/EYo8ؘ/ " .\:\׺Xmx^ҭ!>ue1hn&ma?GC;ޞ P9gFAKXxπ諧Pȥ?ZM**mkż[qѢxUo+GRk5/$NĎ.2m-1N,]tnLv. L8ce!<.fPI#[?4IMm555iB\WcVz0e-0unf Y  65&@MMH4 PFa V@Q|j[pT!8LWqp6|VVxXi#.Pt"[s}ev1/avȕ|U.Yޢsjm:?&KLI3nh)iP+|mͩ"c t#\|DyfX8,=XP ];5lB H3kN߹I#PLS$o{:={fcwK fd4ƚݮۤweظ59(6;~,6*>JڣM- h8j62Hf[ Àqpp07m Jӣn]׻±#N?0mBCh勫%o`(8kPzcP<ާˀ^ɱŷq7'R\]Ԩ痄 |\sjuYS; OЃEm}=dYDnq"yaPFm%ޜ"|F|y|BYMNΟ?T!Mr(?&N9B e%P]07rT-r R?``̵P<a\Z:2/W5HW~3,,,A'Fue2Rb"ll!577x1C?Ƣ bHFSA#rZP?rA<:% &:.%(G& s V U DŽԜ5W3_0X6k S{2+`mg/2,nFc@`;wwww" Skp +p(+viy~B޵ךs1kgRuunGGX~ {[y`:Uםk@N~ߪ|PjIL*Y !,N9Wi/V ڐOAٞ;͆Fl&͛[?3yjo5x-ɮsJI@uV3$+hР7:![E+y Oʧ!sP&t|L}( ߊ&2X|$aBHV>ID#=bZ(Ї|C/P;0LcuJ Ip-xJse: 9ez !m]̽nӴ]z,>l4YRq?{xD'Ooq pZqcUʥi9eP[1r?8ip XUGX怩&ھR&Wc`Ose k0$]nc= "%%Un&9 \V Kr*Iu/c0Zwp0NJ[w_YVp02od9 wf=3aN qu-M\4 mxj EШCcHv|t?漑T5f= Aa y`VllU~U:[*4YQQ!jSC;ߺD(Nt҈dnm^%M6~p4]$ zx0본8 z昩sXl9k5mmz[b(|ڷ)b۾=Bxv1$!bQU?J$=7)Y$KGD "HJmcB*Gfc%h%MuҐf \άȽ9{1c$5Cp+摁%)>ެ΍6FX+~6l}rƄ컉9+-2555^]ϰǎS;#і75;mFn>_\]'񴭷//]W6GjXiFM(!i ̓&w0릦T̎#E7=;5Ln|,ycذ;}oML<+ñdyW<^lx/Ek;pzQQEa@zz9Gi-_hw%ɞgw-LƉ<88|Ƭ(Klȿz(jZi*Xih-rtNZ+orJSCvsLmsMVTpc#٦݊TjQetDkci, yt{i{Kvv6a\Ѥ p#u<&vo7K[S:WnBxxxE}֐XBJ[S?@NFWtQI)ٹdP`ɷ$*1׼ #ioxHz]N83"M 2[F~RҤKߨgvՆWm| dmJ`쭤ziϞO׽7dmO[**W_7HjTG*|>ZH/Dہ {fdK: vV));SDYcV \|hJIvTzX?:|ȩƬf&e4z ҃U!_=B*6!sqB^}BVU:)y5-PKWgj*}J2>::2Y-yVpӕ}!D/JJ8I//H`zBs;SiP wZ|'ahۻUyVN=Zy6 z6P GǨaCtRBJkH7 mQ4݆)KDLvmLbzee >*>h%hv|۳8e61_. l cZPCC!F57Jܠ;˱f:MǭGUK˒Medn(tp.k!dl}ΕN#9Njw>>3TTɧ$Tf/ x;L2ӱh!e!ZR%!]2>81E:h/y vX? GL7h4.hkOyn촚u\O*++0&CzvkK.Ў` p+ٳ_Aݮȅ*: I0]:^ ͆jcN7'(Q'倉R[)]UH|P~@WHi)2d4:*ˀu!hZ"?u?%cY$^솂"$3TDQ~s:o<Cͼ7Iٍ {3ٕy]uY¸W tOOEcVa"PJaalo离[ng=[aI0h<"㴚z)!?ID|J9b%a]A~шmvFɑaIa"բf-3Jޏ!^#NMy\~ LJfS=亯VP<ϟ)Ta(Q{6i\9*L37Dnd\%HH S\x $a88ea{8%|O^ujz:>!A`DOm0@jg*ͺ$s|%~x V$K$/ۯzxc/Zs8$#t ` NO~]ƊE>PIIIK[/uKI{-|Vg3e='K+$G]>yyɍMs~]-AOū&~=t0R..1疋53QQ¾p_ў.ǟZ!TVȰ1e_XۿԍEf V="kB<^i."n-G@#k )Qbpu@qDf$"헛Tuae^!@LY8%F@`H OdK%HdI>Vb$%&Tu`--%#Ck[ϔr'0J5mvPܧO_nt#)e5{T 6 QZ#4,k xؖ^ 6zD+HBNƶo 3VV.&'%TG_ E%奥>;tEݡ8ZRNJy`%6;_y޽.(ݵj *+;M`ZjjXQB@nzjUgP9iP݊ѻ-@(~\;U7FGiU*fbi4i)Kj,߽}vpR/JJG~{}=$l> ٝ_,nr;vNhyH/_n3g*DSJg;D `Wޟ).l=6v+ΆbxqF&hĽCpv6"!${շ!juTR A6"d^қ7Ϟyd)$pzfMg$ >@Jn!V[?*cs? ?\؅~UJi缓?3qCQLB~9]`6etw4Y77ׯ?  b M|P5=MUnl^ox4@ O'vݛ,Tiix:4eȽF$U0Ɇp|j[j3Ynkdd6՜zIsydvۓu*%t8t^LJ vS'&5Ō[:&~WR^~6 nvxxx-'o/ۡ~Z꾓u2x!*,n |ΨȽ2<](]+0YHDHH;dg=b>W %/4b=8|H$! a$eTO8U&c4 O^^^Vrw(UӫM ="m'$,3RxQfdTԣ钄ZVXP)uE#^nMy]h4:2K p#_.]Np\xSNqE6CwJE]ʥ++I4)a &%eJzڕݠSUC UJ*Dndp5H8,Q={0뱟Q?g.Ip' IZ/MQv1pL1`iԠeV@wZz*;*>Y B)Z:sVܭ׵'x[lgBCog6~Vz!ZP҄Tk)mG/hn\;wl^7a$Nd #֠X9J;~~Gc[_A~hFJuD@Cih!Z kV "YUΏuN$'6EU;Y3v\mlHhsg_Bpnb[WK˩0QpK"Ja c% s#wF P<.˒$`ߜ)zvPCeKDj׷m5<񏜵G&]\0HEuh"}vMzϧHLNH(wjħ$mitT5S'~"͓<^tךxcx|ACs~]C"[ڒY"B1;b>Nۉz(8N{~^vҩ.oy "NB i mؽNN Dk h4] BJ%#Iqlv24ttVYCwq@鷢Z].Lo3j s޿n+%r/F_|j>2}ـ?S'\/$I3#/Lj↩sG7x ~@%ؖyx{Bv*~lϺVݹh5/0ǽ8d!!Kpp!W1~dmT-nwdž^ڹo$H W\Bޡ6Yj}W7o= ldУN5&I -&oR1H _].7Elv UE3~`f2I]r.)aRO펲Իa%h>n-z6ph#! DGtĠrP-?zqL۪]h8Rj1m" Kktj54fOxd$}ފ;wX,=dr݉]l%ܬF{uw'ĥ[MyHi=ߨMfĿd0ꤝ !m U5 iчݚA\ӷ@(6Lr"3vC@Om "ؔO_e4=S S?Cuւ0S%fL%/f.AI̬H: vKKϮSPf*e8r䝚"nŪԆSZ;0dZݙlE pSS#fx%3:s >/؊Q\ce̎?r^N5yL<҅ 3D}SjPoo/"*W^-aWJwfIv]'qICYjnr# UYxPsPUARwp1=<{ΒQ)pwvlkyj#2m#K/=5YgyZ_eQk//z&R]lV~:A4NZDmkB|ZZϗvI|EN} V@ŗjִ$G8ˀz/=ŭPdmjGÃkhzz9ri~"e:e{4[k^sP[t.f+~Vv6_4Z|ShpqܸsB{rC7UyX.gWXIZiji=7] 2h\Tʊ{UI?@E5zaRZ by06 Jw [. Ao}SFGO̷DK="lNOWXTa2nCsp-C+Jщ| E |yRFN1 / ؍jj>C/,,NNݠ>EN$GFv!sgWq~RP->|| EOSy5A>aL܊A.-8imz\- J}>r_nk?r]Kj^'%@." 8U3mp=\5@NڗZ%Nc+ʬ1}z :N֗DU|ĖL@64&Ոrs2aM?ƛ" 64[qUDb)2Nu.%Ì#[ b@ZQj6 2'AZ}-&j6 Bw 2Q~-ąLBZ;m0^yn:Jf,϶i+4 p[.EحfךsŴ|t B7ּK0è*7~D#dÁ[ TJz~\2u!c3m,uHM )oۼ7K𢱆vԻ(DU--ss]}CĞ!x0aoceh)eOY5i<oтRm;N熃Lw"GVymFJf.m}D. bzv/OG h;.*'2+6 Ʊy4U̯;s͞s|-SkRnKJ=RV{nc3}Qіݾd? $A֛;r۝~cuE^FqUkŪެ2F\ETOՔw&EkvZAfZiZFK̪3l> ^1VI@Z-$y3m7fjSѝ~h_B>uu{ԡ.0 `Jo?ҋBuuYІrƢgR]-EG@mHMH2U.ȣj*t`wM<.ȡspc$-U;'ˆLT ZŨʂ6PBvmJ/~VKRҤ8jK #5 ˭O9: й,+D!J|oʊl{G(LLE!Cq&؍7DܦʢBx>eFWo|.=GCܸ+WMw- ĘSwn";a+RPX"cRsVK'"F)2쎘yc%OfyiƮ^ogjH5*VOD߃93|gh=32gYNXIz硍c?`O(k CpV}e΀+9\&⋹5)>I T-/AO}|KY]hVk4B]zIݜ]`]/rs;`T/akg5ה&!<6"5\tXܷu\ T?ډރ 7 hOF`O>|!2#Ǥ7O2*S}3ş0Ӱ,\X(7D7Wm0Df^e28Әtbzg6b4浇_ g#MZ-<p`+Jn4 lc&s ||L$B%[M߆ TȲXC~6 @ޟp i("t=]l5 ҁ1H -lXu4BCV)}B9TxŢg1K3vO"9[ M6 )#IUQvT˖MDe6:r8Y6j>i`IFmOVxˈtN`Z9@ֺ09~]w'{YWǎR6E#S`>m{zDV+ }Y^BĒĦfB~B4 IauN}ixgHZ)92%+T[J,ReHD@7萗ub3+bhwknu"_cŠfM'x4MU iqs$YU=IáY%v8_oUtA41ol^Z67znu:|g ˗(6s,3[DM.cY5gWUEʇaDu(1:qL\vK<ZL{B&|-SՊmiϏ | @o9/+@ 9#J\ѺP]ŕwT; _&I]nJ{ԼMF>۩LiOB7!!s ~jy'##%ySZc&F?gޒQ̦ؔor iLp% . ]qO>}f^RMfh@-Z|O4׺z⠸T#IDi+.nYY͙K壝XKB;]mt43֪LR ņ9~yqZ=t o8FJ Qww4K?1jȾ=ZJ( LM5 aq.,qv]VePN1UCJnܲ/3JeA8S1g h7\ۿOG5 <2N+t{櫎f^Hofy;K%nu";. y&(U-G"iq?- 4^sXK5)7?3N%VzՉ3RMT%Q-7ȹ&V؏E=3cJ}; 9b֪)zĘ@JSEGp%u׬lT|j, ݩ":}_ y%s}*fIv;ˁPJ::u w taJUIҤkM[d/^Ş L#KsN J"+$<%^+%87B8u$@rwo2Ymq=7zJh;[.LQ #3byN K\N\6>ubbg4Q@.|SF0TEyF(/9cC*i>d7<<7ph$R]?[glQ{1ӽh@(10*4=kY/ر>}x+CT9m(X`קg%<وM"LBXJ6Gdm /O7jU:j0@wr`5%qu7-%~|/%!UO m3@HWty;ޓ>RPL .X\iHHФ"\|fw7hMd@'Hd+_+έwԄBoJ%PI6"PA픒IHB0(WsWaCjICo$9Vp[ޣzjg.5̍-+K ?}iYM`ZWGw`q1Z&\:׉ ]wo2;;⊚.bai ^d'%34_Z0~COi %`t84/q0O9\n4]~K,Ƚ.ztay.>%A٣UͮL٢a.4M87PN (Q7pִ,Nt@35.TKocrsK]0bOtcQKwG#K c}xg;֑KmJQiAOofT~KߘK|09=z6biWV*-$g>zr6 Baalj/?bڀǀ̅ͪ m wgTwKdJF_vrUY20 ~o:5 8yT ȀcsKN|mɋ ;.6~cor6kj($LGd7^y!'।TCPo׌wzpR-m[*T]dhڧ@䆋 ?,`<8s{⢾p+0YzTژ[7lW^f8"w?Ն]v-g"hiMf poA\nIt0S>V&fsVٞ(vMBJ!(&;``3-Ϝ8ݤnOb/V!Ay1HC4-ݵC:hp Hon}CP8-}~TKU"RpC#0U+tf&lnJ_^~ m+:_T;L&RDo(NKn&th\`Jw% ,ǀ}9/-(;f?~;X :tz0eӸ8􍵇Nڠ¾2Dh1;J_=By2ƘK7Y0(K5x-${ߐ-VЮ'/e ?FE|01waKF;H5n߃.>5{irbkBgMR<Ş͇}w<13~Tgy9'Mt(8$ˆC-?Lџܷ6;nM܅_KXxi[2ٴsub>{dUstBPw<ɴ/?lab "t{" a 54j8C!{M/J'kNjRJLREKV~57ݪnsT0hth/ _m?ZM^KaxHclCkO81ì`Q:ӣNcz*7Y5HT֊[{v1V6+aF9_Ͻ6<+;g6nTTѫ&ٟ@rWys,dCQkb-o|\E3H{b N`49O}agDצ|&RoZO#Ң9!L!f2oޝQ1F8J4ve&:ͫP$iD>;Ŧ[ [B /sQQf6]n7 \6 iؙҜirt`F۽s)oݟ}k)A~iEò.KW#!oHP=p_r<ٖ, ӬR~ڦn 7ŴfDFT|_V` .Wj1$AemfF8bX1}zSnu:=u{ԳE 28.#>bl-!H?[~+=juşqg*_¬&3b2 )Xڒw%iΆ'{2,_@T,dȋsBCע1ú==d1hmUCJUa6f.vu`eiYE!3޶DNj]2 2;noQվKtM: 79AjF1n6fZT geU'g-Zmf[~PRHmhYZK9 wl彨xBb&J676ͫ/Z=rYzG,s ,L*g{ԛj*N"K%y\[%G{U}7ggk#ΪvP GY6ujM=75%9*XIrb+by,X9(drl ~AY» j^&m_XMe+^#qLCJshGB#U0w4DaO:&k%C/Uܹ|w8v~r87?x02T{i,H"WWVw]O6ml^9zULe9Ali ӠN'QWZ$+=_i?:VÓ*^ _tB+vFJF:h/]ij=#IQ7^nr]2Ew;N*],:hY >S.Y -3/YЫ[N4G^T.g:Ale.ɳg ldd$I;FTG}bVyp3wjL4kjZ[[Kf[ҐO@ȸ̹ Z=xvygij瀻&&d) Y77; b9t%z^(dN./g& |o7q)р9NBSm jt~l8Nj ݞtt[ bzɬČ⑯; zvNm $ⳓS*12ƝϦ:mIA$c"/4̀\\Q{ݔ؈.eƪL=8oZ(v&```(QboKOҊI-9#A'j)Cj{$M# DtMXVgv2\_U 42=D:1wGͫp|RIcF=<|(T|ϗ6ҏkI*DDDu{**.Plz`!Oqqq߼y# Wcޕh2a1Q6Y6Y0OMGF%EЉ[ h9˴QG C)d{n}QhƗ*s.^P0E7G/, M`xGCaw#M>HzBLR )+nHdG:~vNi8M.EKn t b(ձ|$Hk >3Ps ϛ)i_GaXcU]I'(p澿4:zcrӇ#QFZZ/z]ԌHlx:ULPd?S}aۡ58X)LK)̸EEÑT.xz>ŨWC]@wqŒmSCTX4* XI [[y 2u +% *rմ^QwO߬otxe* H7\:'Jr{s:.0/ ]S0)q{ժH]뼍,B) We,5:9Dq)E:::ZƠ3ymH(?Zrؙ,0$<C)EDr%cBh$ $?Dٯ.\-f|N>XH~E2w\o'!ImPVB^ yI R\ _En Aťfh|qR$WҤ0|84Bԗ m]‚Oea]̊ A߿ B $x+>riׅuzeܤJĩ)|^!"#VdPJ*:8drɸi~4)b]xb )lp œQMDpc`0 ;`6W> ?M\!(pdIP!_2@"=Tf-nTlh)8߾0<BD@x%L<[d!htz+P M g->Ϙ4 VR*!ɋyc]4  E:|q`):`mB.ܐ& QUSYEyj0,5Ax\r3jE>]~V GԫR!wy/!|e0i$BYV9ώ@9fsa=SyAXƇ -*S>D'xy{ɳt-F/UcNSfų;=Ci g?/S-gAp)EfL(S{ƋzϮ%v\|nyR5+ֻuppIqpO`t]qZCq8`tbb&0{zz`ZWʚ-I 0|qzB /(56!KKxHM@v@[%O*YÒk* @@ Hb5]LU#!/E\l4I:\d"X\E 2A 7_Aa=^(F=Vh~wK-5:oYN~KK =,ܜzvT`NЬ vQ"9};z㔄Gۨ: @]9NCrHT|l[:Lj`_].7'aZځRӋ%uf PL HݝU{u#NVSȧ=&F`P~)Z9z1eZl `q,˻ Mv(L?'"HC  x;-55Ņ>{>\,#5>>M.{0åHݕ;jBcK$6XD(2hLZ%cנẌ\ '+-= d> ɲ?{B0)ncrrrccc0V LLL0~w*V-A,xEletzfc}%*YwDrˡ999ph=t{8zIˠ]'S%n2+0aӾQ%%%\.4Ū g_-,3Aa>Ciz@ͣ n석q@#ܞ锋Xبg4rgpN˦)}0TR4äH@y/ɍqhQU{Y- wcc1]ͲVLf832f$6Eѱmy]B,}8؇mx ~u!f穤]ރ)oscBn?vyGU} 3LC.(Eb=q٬!ZkI<ɵ?E ק83;['rnsWf҇nyMzf hX[ˑs<%c; F`Ԙ, CHUFl %q&o5_0.qWِfwe'z5?he04P7aNdZ9̇dk&e|?NEZBbGN99\%*_^6q NebcSJ3I;9/ ;` C8# ~p]"F-8ZB6& ?+_,[+tUw5]!MKȦRMI+1 iKKKJݙ4m|`λ]c&4Sz5#i&"(%^bAT`xN ѶeWGsss0"],(  YPImNLԕ/:aqtxdp ``"qzJ W~FIYp䍗$wy,qO&ATf/ӈWV+BsP?Ap%pTo30'/n""$aA<_0}(tؖy5h"ь͆]黆d)Yo]OKi>6wnw0$lLiљ3 Q:1 eEx ǷX|U&a~t^OF<>tcIs>R?)tiCsVא8\e>ш.$Y'X##,u(!pO嗈3L"0kJBQ%'ǬL2}8K%Ԩc! Nzi".y+}1Pfln) {@%fـ%%=WSaT=p?5J1.D"$L޵oI?[**EH7S 'iڝȣ;J Iﴛmϼ.LWwVUJ{۟5J~c5)ikUn4twh)`]bY\CEۑ|?tzmN\ n+cRА {#Klav$Z}%Iś$sZdY*P8yu[c9ٳq. 1 Ҭ:J撎[nA,wߐllCq; .wU'@ K^Zj#..X2#^LI|Zl34ZADxp90J-ּZV|z^f,/` aIQ9;3pGV:s 9wU`I!駙͒2 %%k@F# 8Gg ɆQp}}}{㻫 4<ǰ0:]v#3 16CMm%Ut|;<=Fu r.Q0rY0|>KzvK^ꗑl2>:ѭi erM=YFwX`ա&y )'ʤzK6+ޭzөmp1)i*oC'gr߯*0e+%T?`бZP,جF}?$O Ow a {onlq~&{A*#3*ÔࣴH en fWgRȸ ܮc+ǼDcjeIH8ƸL7/ |1DU+X\ֆȝeIFEvJcIqss'ɨN_ $o%<~9ҿ]HY>vT+(=?@Fz 9pwm:Xq,*II:?q=m/avauuqƇ+0w2Vȧ5I!7>Iw.hh z-Ti!|$blvoO+-S]|Kg.jjk8J֎Gt7WyCKQwȠY764r272j_hT\ oq,4pcR9!wonaX3=<2-5aP.CrzB@e ctNNC2n# {z#%#[ݥڇN>(fͣ-"/7׶[#KxLɘ&ŒY鯛6S~s;`1wX_xGR~Vt>ʾy 8963j%f&WQE18%ЖwS:&;Jw TT. K"`|:׈row@gi,2Du?q#(_"#$$$}c)/96P#y6_jj9H?+9l3DGq۽1,Z!*m ++:|@g{֪m[fjRa8E{@f~jכ/F,a4AL 5LfPaַȧe_~ap 3 qHWďShǫ~.}S#i[RnEG'N*͕uák/eqqqBYIi/>"'ģBrŜ17/?,ln$q=S…M _~i?Dg)+>zM?-Ǿ!Vs¬?0RoȄef cB|_XI t(k柶vpafaQRcҧ[_%Tfvy_hm!!eOwϞe1{K"B2\vKŦ/3,Шß1jV$׷B6̬Ƌr2]ĤO-ripxO^ j aY黰F[81벁v8 ϩº~KPFaϗîD]T/u#4Ө' 23|9K!'O Wr-}=N}rDwj @}>A߿HHI'''EIa<+ZY Fq=Fg<+"֯P#vn`pR7AVRGF@PjOCI^*/աT\\'1u35 Mxa3+Rb \ʇ@vC!IBjdIr?{ٟ6E1cqpeeJJ]FzzJHh*??aƇ aeGaQsQIU 0b4Awڧg6أL-DVΡ׋= ~A(MI֠Ð1j^=/C1 9y†͍7NQ D/]U_hfEٰu2ٷ) l9̼{Z<3`n?)٧TRdSi-yVy֓MIDVo[Të*TzSb@6+=t_S98ۏeZl^Z&tVЮihhHHHxy5I*ކvӤl :†=layLFJ 3vb5_J j {޷MxK?y`?=]@`6LhݽhKVR{An>팴ϖ/_9# ɥikp̈.Am]1"e HBa\hcTUUiq6ZՍ X|oصQJ9G~B '6"yݸt|铬&a:V5'/]l6L3>c mHY X^av%0L<mЕrZ BZ6gڭrnl%nuC0`f26L~hR|%4M77mV34T{ e͵xFQugüzk{{Pq(~T|MTSAa:)//olttRvb =yrKdt|"yK/piX,I˩2E$Lqت\N sDc?vNh5Shmiu* /v?u~ҷ:'A}ԫŻU@=ЭM۴WQY @jdWp*x _&33s2Z d1zzig&-þ5u)LrIIxnE R\V4cm 4yU d𱺐HKKznP,NʵfuSHN*,]Gܰ ̡m__"=N\|գ&g' W 谺k5?7wk.^?]zĝ'B-ڦZK lBّy١g}a@ND~~nNk-ȧ  $,a3謦1Hʼn8T6/쯛WDS?j#G޿Gv6iZuCڅzvK w-mC<;u}$8;b!;?|ɤE "0& &^Vx-Wa^[@V)xShz.@[NApgsތc^]jɭ7\8^n;JRL2.҅ON[16[F3嘋ŜjV"NdB /u9 {gn>050iop1J d Õxث,;eR)%s>__{)J|-|KppZҊ99v3m~"J{aXjgəRY,l'&xc/*x"ඐﴞn7OC]79Iv_%B Il/>@WiSc7N+//oI%04 rsto;p9b'ӭހ?xktO G ͞濚{ ^$]dza% |QƇ=e؄Y\!agg<& wF$mTIdtޕ))3a3gN{j#}Cbdf#3_Z.:b"RE;ŸRw"8$XҪ7IfHJH֖[|Xz<-j&έp1_3ʼnkkzg=ǏbF+BF%Tǯ"٪%۱x:63p'?yxёO `ɞe6h `mVjGY$KiDqXQFRvpC)6>t(N\zΪyoH6]DE@*RJ7Ruشww  pվ-6t MR*MS@R8)? 胆\f٪'C+tZw䳍X槍{_=z|YZ,OボF ]]\{۟9 D'5DL'<  ( |#KlWnIm7x^]&ʆg_L݋ "j5Eี}x4d~SPV-K>8ﶷcw0GX@Ugo+ռ[a eӞ 2>!bPFkxS,gQ>S|z Xߛ".v˪nr`{hb} )& >7@qqX-'T_aFYm @b|XDi1¿T60`y&а aJD YUÀ7# Ţ^Ҳʞ}Z[W ESXދivʦ-{PXb^άOK]38[ #<~xN䇿lv'R7Ҭmflz]]<*uN|vک t-JJoDkLw(GVb?? X@X /}2%<#gocc Wy 8zP !8IM&TVlOEhIGR1 s:"8<7~Yeu \I,vQ=Xo\Pkt 633iXӧƺv-x=FlԻ3(7޶`U08lAaaZ/OLAlG~O5N xVySP"&:YpeQķ\N~`JQ:A/cs\"xHlTV^YMi5+v8}?$`ʗJdN>`IGeʊort#{3lQ~eh^L\7 m̸hG<(]`:{/*}]8ΰH Wvv)4 0 ХNex%ڽ. ;_엔3L;yNHHh #ζUan1(-)I)B}癥H.]װ_z`4!͡F+"߳ovPDj|%ji6Xꖸ%0#XZ\=Z/z`+^i;Nq0_pGst')Mms UC )B'֑JvPW\Py]Ƴ2ˎɨ KZ1cђ̜Nnaʴ@^G}^Z9rOf<+7R*߯Nsy_Qa.[o|+O {qvńP{PgWEZ^u|![>ZmwXo:P,UI fxBʜYsQ*Ibr\w vK'`0O2ȩ즒q1 \3䏻&CrL@?~f>?;,Gʑdm`U M}c4ZAßU*jmBzs/лR =3}) D1c2^M4VX PL4#*0~> uyUUR V[_Ք8*juiWEzoM̒[n#.Z9 2trwqu@jN`79( lm%u_444x𲰣Ňupppg0 |*$}vM31{U;{LM~8rQO]+M^(9m[yfJoS~ P,Zh6>zzP!K;IQஃoOg쌾uʛbUPmomUr4}`4P\;nG((Qmn%'m⇄(0d|׏PB6epuv 5yϬsYac-gI:Myb^yzUOpwA M=>ΌӮܺy$Zㅝxzk.eU_n;[ѻ$[(^w3_!J_I pPZ[I|T /&*.pbio@: #i1Kk F~wKq;VuhV{ͶLWU,- 刏<e _J4}j{u}@ḑ5{ ?ndHK[Um $ZyMDL3ILN6sW-C75 (/Ӭrz{4î(40 /u\ ~eZ,AGT$foy-=a~șV\m/wgZdssNۦ}Q7=a<Ryz[(FNr!$rGNsx6ٷD3776Z%O\G7z-9 KlW^x\4ײStUAl-I"[/R, =0[a)☿s96'LZKjj;Bg7>B5~7ךb#7a/ETU?~PcѶҤN:A{J=WWM<xW&01~I=`eZ^ݛCgIz\(\޽R~zABNnmdB_A?edL{TH+v^|Cv*2Zߏ) "'o]jp-I=suw[*"q(Q/;77ׯ ƽX%z1455=i1;k Y$Ru ~2;5 oߋRn) ToPRGzvnnE⿪[Q .q.+-Ӛ6!<Ӭ̟6yM e%+ %WJN%)~X認NyG|ܠ:n}jegzSo 5up(xpӖLͭ%r'=#qI''j!՚Xܮ&zӡo?mVȟO:%]?ج Lw4=[v#Y%&DInet-շ\?p Lr z::i6DKR$Nnd A^VoKxz,Eq>ulJ:J^6Qh`.cN§p˗̃uϗ4?c߲03"BiFQVtLŅ~Oi|n?TVuTIYE i ܧtଚO|2t&@*V3R'ɷ42-wi+@V{Q6ߠv"!iѝeyAxp""Y*Y 7j J` - y5)gP^RBފB%a{|Z~d34Pr%yz8XψhTm.-'oD./X:"~Xb#paYd7{=@fu]'.bQT,6ڃ!iKgY͌~OB_r12wFsC}}2ο~Y*&Xxq{7km]'d~aO{eI׮ Jҙm۶m[m۶m۶o|}NݣG^#׈kŌqf|!fDUD}ÉGvGIkDgpwV4dDb8$It!A蜬,2o pۋR.흂Ù+,H'j5lK[p.P }mV #@*uxY^բb&Pe@-cpjVX5 96uhi[A|9rj&EΈ-*#E>S8h<:1C:1ddΕh:O#arFmV&/IYY21+eJȚKQ?4g@ %mpCHLmѧK B 8=7,R⥳*S>UsB=$D qb rMZzPښ:c07qa+Fy, bIL("!~Aim6xݽ _rYWNu s[jjFhjhtf?NoonrgPoIKK?T=\nH|Kfx#VGuN:qL+ g؞ԖBܯwr9N7!9)W- 9?(:Kt g:/41{z|t=@lǟ]7usRޫ ̬mN^XG꼀fkuJLT2a^6KQ07p&HXp/.ykx@z=}@OkM/EE87LLWgޙMz{nj}7%0:VkszZZB*JJXc̽QeRZ&w.S5A.]l^]F ˩1$B-mF\$BBQ [֋ud=ܹ2#Hٹ{|lm ȼz|^v&6%dxrl{W("z D[T F#bc0u6:=/l5d)t!T(cL>UPSՐKFx8tyR;h_Hƀ}A/&7zGsKzõLO Jx84/k73F=⿦}LхNK\bR۴qdk_.P75tUd@_tL*D2lG+{\"c_/1O/TJ&06CL R^al#Y|q~{{zr8 shoUW328++M[TJdJjmG_}Sa4a&ĒX+!, Wuvϣ 9 ]ɕ7WێD֬(m֚X|T5klNϳ;2h18q7lBsѦF0wMl]VӂutVW=n[ܑl$K8`!c|JZ'G!%Y0E'@X#/g%Q.j {-X3G!}]1gڹQ .MS<1g?(nFe>>[KCoލ8͡ܚu룟ɬ-7k>Ri qkݼ>- 'R f./SJ4|o '`oxbݢCr@1CAuQ- LA CyUz3qT|;kӐ, [g7xS_$Rk 0xT`HY5L3ZIλyOϢ!#۞ y8_YԔ8U*QS0^!ɲw4.X0>1Zl;"6îQH/x^ߏx&C6ɕȯ#MbVyבhSvvwd0ijҤrI &MLVèuwzT5 ]q$$y}*u']-QQsL]SB`J\oZ/mҹg_dy6[2OllmyX.F,Th*f^a\Ώu\%%-QPZ\vgV;٣c\ \Y߰Hb#bɽnk &ꩍ YT֙&8whHH1ma(0 "`guΞ Lbi,i"˚5dUU_ +}e9˵TǡUzZ} Ç " uxI;@?)ST|[+?CN($hn*eTZX k5ڔmۢoJ31?F|1R8QnRq)6^o@&i6;Z`}}---MqVh  @@vJ[ Ydе=*GD`[`"\xϫbL`viƼ5,uU9]kn-7fQ*% v1Fg*m22__F%Lj(&2Ė20-(]֛r.([tۘ"Y8:5{ه&fd'U[? tl@[ߒ 5]?{j(hjK rž?/tVRswt:_o6Ps)!na3BS8-ky1B2zd:[@H FZF&@" YxwĒQފB! '&6֡+7 B?ljs!efk*KU~Lb枹 +cQφO]4*!'4LO'ޯZTnv `9??lU6Gv/J-/ԩ3244lTq/Λnw) x:]΋Uo}@D?C< CvfXD o3¤CXI߱;LP,4Y4-?z ?~& 7޾oZcKgdT̝H}yzQ * a[a\bt44q)BBtnխ-ǩ&cB,*:Czb/R\P.oZ݌+ӆ^m+t)TO:&.l Ղ1^u3hkdw2LiI;3էq/?kx&#&\ ;9]9ww&&&+@M;p_^v VVn^f]FzK݇RHz$K(oNq@~0$D]hdCDشefPN|ڊOu&xM4Ѫ Cin.ZɭPOn)(jO6\ j&3.jjj892,bB(˧qB*np&0Z1@@ 2^M1<%<_*#NM%2Xrʩ(cnM~$1ŷ,MS{ӭ䩬Lڙ& rDg%hDpڷ(**:p-m#S6ѨכLŚ~8'C/BQv]CD CC TLG@uzグˉMNQMhy#,1#7S相Sa=Nᬄ 9>wCX-8R @يyaTHBByXjffFO(V/?%=z;~k0ICOO/~% \@˘!X^/tx]{ [ G{pwIH>ca_R7J~NoTr8#DV$*[ssf*uԸC=; >S\pXՀ47%eT3%  xJ(&KrNiO1V6 T`xOBSZc챉}+(_Heeܕ4˕x=W'_c@O4V?3VWOS%;P-6ϛ!\8lF89'zǏLLT6.q^-֤>@_t䧀rP rl9 ;1Jwi{B[-zO&`kCYnݍu)W$zq՚{SZwf)Nn u 6Ήp<b%Rlcs'/gϴ'4 tdB8$ԟhJF4ѡ)B>;7wC7лwD >"=M9 -`aıMGT0LhW߆PN-Y($Qa]?&cZ;Mb}{=b]mXЫy&g8lDt"ZȧR%)850wwwbB##l2u+: K6JDY2j@:vw &L)3wbHo;B-..hݘT5h` J ]9=O\4u*KyU}cF?J(z0S&3>"SI~u q5ſH[TosS-ƚmFa[%fODb"v!㈃c^=.7na);;xaZ4":ΝywNp[i)66aqi}9cZ^a M}ulP4}Υie5qʦq}T]F}stDV71 LBõ3o7x 6>f?|o 6\Wa 7B՝._$̙D3;ִMЛιM#`0:]9- 6twަi1Yrg4g᎚|֖?8 vL@444;98ޔc'kqtG ~D+@vRɲ[2}m?̰ hP KXcTk6/{g ^*Jxx(ۦA#Z^vp/!Rz@M-CBp$LrLNJB#ޱŕ> &R.$@jVe_@@_vC w(7mȖV "ST\u }VRL~tk_Ny!e4Lk#i`:q`,?ʞQmqzTV'zMw)[TwTqxjԡzD%05 U&K<}͞_lSj:895hΈVVVb?A%|]^um䞧?ty?$\*hyU8W:ZQhG9ͰNx-ɼBnWYjxF :ݦ[԰Ek~gɅC<#h=))(+LB8#J\joMMu=JúygSPw/6;ۼEP{),S .DlʿE&r<SlMz9 !maPGMӐD1X 7f-/ZɣM^Aq)QOhs8Џ'"rΝ2nRkĴxv/u6/ `Cb;ݙ?I ٺ14ANP:bCxwQHHs6&,LЦ 8&ˑxͳ-ejR8&+W,P@{r2ـj_ 2R(icQ]]{׈':N[GYZ_pY;R? ) ݫu#c$RSDf8gM7gWU/gZ~?ZT0$ 2g?g +RmP/!׿$?V"h>ɻv1n3r r*)֗Y[S\ U^Ǹ-Ύx>]g $&=#`T{ΖX^l4[Gظ)X@Tt9ϏQA)8/פaX[jδC@S. ):\6Dj*0n'[52UU *Z{w)WvѤϛ=>+|L _mty,}`w(J^*i݄3yST RjĽZdKxp-A%-!z౩)Ln#ׂ`P \GLۑ!zӚ)t|*]ׇ j?E.˝ NtVg&X,Fnq;@y75gT)|[o6u?-uPd65HqD2wՉmCI'8hޟ/2\„@ahc#qKEWmMk1Aeյh;5y'Y?*"p~?pALq& M3s8Aym~:#;7`PLFZmgM2fo3yf/oF M[$}1>pϮHvW, Nj'6ǿ2ɕJ$lpX5]1"wGԲCCC{Ĝвuei]$PZn=!+_;ꗭ:lVT#z{jxT֎)il{9LxU2K>!\?0! 7tPxfPCTM?LSQ3lц9a{kŷ,###݂kA 8TY*4~fCHQ1IC*Ø!jT4e޽Ty>?WV7[ˤs NKsE2L&NЉdCxTc6Gw٬]^__br8N;$PCZ9zR p|x:/jfZu15tX'5׆/K"4vŢ"ؗѪ-W a 5EnYq>`z &0D"Ng.LT Q J7_>o4`0%D̺30Da,*lj|@N鷡je2a:BCb"" ʖC-!W%zE8ZA򂉢O\o ¦E|~i6FjFQ&݀d0f\#8]Z 2^./B!Joq"!٣%-@@)?s9XИҍAiO o?qx[)Y~Jqk6W-dBX]$)~w3ObȄ1+Q}*yƅULb5)D)mo^ n{Ӗϗ_bFS -<*j.--+ۘsu ie܍3LwDkYaAEEYj)zA:'wvX~W>=/2v7h Q4^{XB*s:n7w^:8Ȣ:44T݁8MBiC΅#|ӈO#Y4jMqyƓi7 2cO/5@*29T7 TjZPI ޼yTy ,.>0'1v,0,_ևޕ&=R痃w cQEH@5{CtA _TچCB`߁&!7dE+%PPȧiTҔ%433JIK`2)%f?ى}h>r'2v52TT^&|\.Fulf^:>Hcic)$t6H~Q'aNʼ={bWs*:H!!>|||BaưܞYzV||; _k Sݒ&NJPȄg_v\|YJCAaQX.)ЄO{O IUZ\|51:z O^dF!(EP7RڪLlD:m@pJx֮ Nսk~2!M|Ȼ8) \_<2~WG/"q`j. P'y$K_mW6sWdBENG 1wJM{<$\6%hnr|/>:rT!ݱS?n@ad@Kh8!{ yXα#Y<fH8/xܫTAկľdLBb]ي W7f@Gmqszy) 2,kh}S9P~w٢zqhV(0/%%ŀ ͤ1\wX84ȟ;/ ZſTzT_̵F`n]'c ؍' v^ h;13ӓ,x>c+]֌zp=H^»}ꈸ+'IppG; 8̺ΟS@&1,\ Z,{(\-uT N:^I( nSf|,n݂{^Z+@~k}8d\hXX>Pr\ Bp 7 ه9LH8f}kNmx)_^Y?1'`yrnPJWv{- #+@C=zrzF[REgڻ!H$zTk+gcd p9Soϓ6ٿ.}Ї ^tmLR (]WyK2rDܜjoGJDΦ+ Ս Tfl7pϙ O*M\㮣rh.f^_*}`(K *9|be&Od5dcO ( 3 >m dVVRv@-0 i٤j^UR rB4vrz[} |B7jφN pe%.@P"o.`djUYVk6"9 SHd񴋯 JJJpwt7yH{z{Et?|_-dZв;}!_oC  {+F'F@O+'Hl2B $i7Htefzە Uv`<')]Bl~t͍K~}o+jr[k u`.l)*Z{}n+C+]y))+;s ɶ㤭o.ʆvkJ{5(R3߃5 n#KcG6i( nn((yN9l}ddn7=: uldKг;&$.cX҉FA~m&(,ff.k7ЍOjs<6 .λC:.*%>v@q'u6c^98|> 7yxޮ/D>q1}_ ,;߯?_ߓ^=|.hh :[=]b5ӽX[ё4 |c#iky_˚;{}B=b]PۮRAndNH;vGqH>RM MYb'l;|;${˴}y#}Kc R9,՜z=&F[g'C21Q%53Gw\ xg/V-͍~@׀D86ɪ9RPuOmbq?0gLpqROf:~Ẻl>lD558[x*c%7P8Y԰(C# ^(P^a Wrg5_GR[cH}tBAzryRAtQ,i־N~V6Ut# 5mǤװ\OʕmҤvCbw/k(:d~K}!`=_!n#tk餠  TNd%8%`&BNX٠5$ *rN7WBC$MBɔ'"ɱ0*B|A-E)jz+,)9U&Q@2"B<#r1x[dRfQceϜ iRVRqkV *|f09a(|fbV@g则w(&`dllj!n$z!:+S)0ugf%8#`vԐ^dNdaFgX_NG< ':Ay{."'10E 0%hbП<4*)ŭa6,^>i2p 4(6(n(?7BT|$h!,8fkHNnGu\#ZjRI~řK! Y/l7 .)0K.EaCCdIng0!DnY%T,4HjJTnӝ[XX=F?МsN!4bNU:;HN̍+քW5;{ ͯŝr Slڐh5O>U"2S‡_cFڐʭth`9"WX[wbbg+Wd[u_.X%Z$i0iLCf "Xb>TR~igZ -9[yQ7]ֶ;.9?[A^W' JZh?7#" KF@c|@Q uWi-m % #߷ X,,øت8L/6!~Պ& SE:v" gօL2q[nT_*P959 $a2mxJtO"n5߸$txZ3J_5`20{Je,L012n GPY%wt{pt KhgDIwAz_o'b ?X2$;9MʰIN.ؾЗ';[0i=wI?v&qHWwBʬG>k]]f6KyV,ZD]s&ll怒B!>:(-{uO%eqB$Mq@i2oaBbsA8YPHfu,qٸD׮p3 >L҇4~h?H \|i|\G(|o%?MaI9X;A`*xe&(z(mVo{:](!RHzqd%AqOo!Q2ϴßhЄ(@@iLB2б 2 ohKg󬁀ve9ebLQˋE+Kkٸ/_5dGoG$-O,KNܣ&D^sN#7\GOF@?m~~9~!u5urw®l%չ1WkTɋGV3}~2Aɻ0v v+7#&\oFS)F.eޝrJ4;BJ ,獯cK+zrD0Y|(qW.<` 2 , 2@!6ld[vsyF5Q{luo&Y<&VZۘ)L97oW_^űݸ.؞gzٱb ӎ>ݿYC VF#͛^=NAWmM7>H񡆌- ~LL5D1 dzu~P&Ij@: .搈NAyK U$ "M`)yrlae3Gug;::CC‰#+xv\uX|d"RT.08]ұl<>(--J&~m] &(oLq*_u똲ϟ]4]ELϔQr%Immu9Xo"1aŢ/ZQGx%EVB  +}خ \ٹ%(@-%~#άU0;64[6Xyi}LJ$},=M0ZRUD<'[$b|'I{3*:2<}R39/uvO=PW{Vsuz^$*:sVP-|tZqbaZxZhWG<~iFcTYi%6J8IL)[m]S2ޤŹZs@"!i,v ^! JY`6;"8]KĨ,1gkpD3`0$;1\޺<-U ZjDƝBMm?x\'0fN~Gsf$rU@#;u8;޾-Qٻlg$sk؀edց^}ӷu>+Ug\Fv2WnEӅaY[]2H^! ^mm t "b|v.RP"tzxL$Jifd0S||sg㢌pS=l)"S<]{Y ;J5 X^ !HJYYlt/kLgnd8=/%ES!EQit4JUԛ)(2a9M|xx2]3Џ'olѰ){YmЂ>2h5O, S+1mBk`Yr|*=K-*ĽbNʦ' > 〧lBQA YaKMkCp.j4$a`қ\NRPwG>GMXC}I$ |<@|y'I:<ЛO~"a^Fd%Ʊ[Eg!_LUbomۅD"tHg-td~jy'I*Yp}hܴ(v~ SK3F"|:7t,PFIp҆\ ,ޠ'a -Dn˦93E0ӟ*2,/këJp$lDMOc˙ԅVӉʤם7|ӡ%YRXI ":J)җFؚd0">SSѨʾ]O]] )g="*E4-G-յo61 O8jاk79_Tsn,w EٲȞxyvvD<{ryu|]V-jSxe$dxj9zXZ67GCI3;FNsld5_*rA@s }ƿwsk.%h Bzh(rփKvJ@Z}مٰq.4ԝҟNU,f>XkyN:NB֟+G^?'akǹ` SwyyCZ HAᣣ!_b(_ߵ-ŏOټv,#~%>YY愣(M=;[8)ĮF9o>8Ċj;B&d%%&ݨ\Q;3\(1!F[&.|DdEslJAsu&՟Zv|ZǏQ22]x?dsD&ή3dIS>CLPG烈XXRΊ8S@[x+=*,Fu?Dt#$ ^Xo~2` ݞr ͌??\4ف},SheK4vmlfʘGϡS^cy3@-%Bh%"JKL㑙}\j7BDp]Nwj ]Xs?pty15LÄEZ FKsgw`3lQ%Lm@}%LwMc ) n~3'>TB.VutT3h㕲(UcIvQJ*\yAAAD3ZB?]nL{W5ԏ8S:Gߐ'߷bx2B+UC(usKz?XNc@F\_鞢s[p2,QsPCp[-x@$z=YqGJ;#㥌mJ f\fB߀ 6e&q1gda?dzO׷fvC4!b/M=EnDq1vl <}Ě~6=Fse<܁1OJ1U'R(ѿ!*#ё:q*F\OU7gTȎ܀#"su8IOniNBڽKS{IqXQ:@Zfo3=dQK=U+NrS<殝o$lVն:ܐV@'06!-Gg~,%FL 2UQ ?{=?69gc1$R#4𝈉 8Ur呋z'Ҁ+vF9ipxrr 9ڻxҏUyJV|+EW*?;Ks|JA[D ]I#&AH!ۯ$~\З/d4 ]xti34d Xx uéyXw3x?|^'lA V箮!i޺IIY:j޺L-.>4h#jJPhx=nٔ}Z;TaBP$ّXdzCwY>}rzurd}{}jio>;vq;lr#:h/~*]ٹfN e9tĆ_@Q o1HnaUeTyy1$ZK2U`c3|hǶȟ1 xЩd%Cg팠:>L2s>PN4;}DX:nXW ׻L#s.~_cOJ}x}V 4vQ"pHQS =l¥Hݫښwdf-z&,鄗1L0748?TտI( IimJ؛|j'|frtʁxH~DD3Jm)BAInw4t!2 TpDCa=#  |H&{1!(Lvsn ܅r7*Vݜ5$4 g-}=kkyq4%;=X]m3]U4VݪmJdXuV%܂+{$P:Uj"˽E_+MYCݩ׶+ӷ1ɑ]<љ~;列8]NϯpI8QFxf(kwٲ37|tc6H<4`1~ ⫩/'^ I:4骁.uEb@ج#;o*9~.Sr0VXT}#S*xs.%ӈF -Ebffcj݂uYMmJ<{ !=CBI݊~"a|ʻeRn[\^pSKhSe9<2md/\>RrR˧6ZBP'5rJ:54=L7m꺎l2t3Pӹ1L Bv,1:UҦ@Zr< ps4tTz=sa`T~WqxXOZK I% cD/n9u=NVԞ^ ??e$ƉP< 1SDcvguVB31+5VG̡胗mEw՜XgZvOt#Iڗ޽/u0%M蘧!J{^OFrFTtIͶXԢ{I`lfp\ T0Bm;Q ۲7M,+xݙ5jL3I~1Qt F[ lzI*5b7\D~3v_R+y hI!2`@ޤ)j+:\#:om TaYYU78C3?-*; Itt 'rhܦvpE#%a=Є|\2q~h-}E6MEifiV~pt=bt⥅V'Є} cC -؛}h n[ħѓc'9k}ߩA)r[umC g 3`#;[Zn?AdrhKgSH~;Femx&gf<Ȗ#vfR?4]ctǕ)7q_6d'AAhpuqѦ 52MVt'X~ O}):T6Zw4ܽwm2z/)2׭aYX7Cǁi^mEB1Y6ׯ)^%R2rha}cx)PPdi{Qx,ʮ0;# Lu 2µ7Ýդ>HQ&8he7\JI+ lմ!vF2tڲITvO?[k̪y;C 4 iWX6q,01{X\sBjھO~]v=m%L:w'I.x~j˕L+cmGXN+4O@r; o`;S_>>&=I a uM9݅96nnBlc:s@N2|.Չ́x*s\vCT0bR_]ӸUzՑ!g)6;Gu4hy\ohn\mqQؽԚ5 )Mu0E&O&,9 Mo*pq MK@x:fRnVZidIA|% 3llz -63tҌ:iiwz6n%WWplAz$/E:p7s8IK-SmݍÑ4^a: wᾷK U(sʜ+L}yz@E,5N DM5#ekIDgi 9u<CLMWƸe!m)( ve~}vQeԗTGsY b6S %fÌĄAFFuXE@ S2'⾯w[]_ PBds{:/^Dv!d=j6OXX7tCZG[sGԄ/*Ns(f?^כ6ҽ@Tߗxj{w}@þV(>T8o;LmXRaאP>+v/410@e|B|||BtB|k*,(4H($\? - `bQa3" <_vBߡR$/s ϯԂ' X)jgAlj񴕎Iq1vVH1|x <, … [;&*Ρ߃A! r)T, JH?`69b+l(#r'?NĒ.A oh|_5pa)Ņ$ef b H%_K1M صN1TxMVc& >%.3gK גsK[ hxSVDEE7Ɔ KEK&ܞJyZ,9<FA |y; \8eKFp@F]?Fƒh({z DyޏtQF/k{^:LŲN7ˉv yfvfok C}Ӯ°=c(?_UJ (c)`|ednP [Z ȕ~")OͷCv*(-鵿dh4t=V{oR^ʷjo.1^kpl+b: pyώrIyq$qz4* Jo.8Qf1BM? l`4ѿGfMm,(IN-J\: 7kWV=$ C3]nSDl>hٵF?7Tenue{vq0W.z) 'ap'4qvn}^D'& }z}x,' Bi2n gJ_DuR5oKjy3 nB8 Bp8N++4:\>jy~q%@Uk=)4*1wxR\pU#il<9әŁ(7_[;#!c񗽧 }}_ d‰(x U0_CL|-PزީF~IN4[O^R~"V|~Ythf:eC;\y½;J\ЙҬ +R-OIEDx<\𱺰D|} {{Jtie>$ %ړ'Bo`VVoHm֪? sE6PS~ s0dWPk+$ ǠQ(ɫy>ܜ‹PV_oĉ8iiE5Աao ?!Qr bidb&1Z[ e^`@+_ϫχa=Φp"N=EnO=8bte(.G=/M]3d~ugyMPL/;<&ժlrញd+2֞ω$*+bhS1*祒7EoF2!00NҒ X]adX!`̜Y%Jdc'dNuIb:(?X>2#cI)DDZLۊU5қW+cߊ&³n`JcҟY9(ط7(+cJɓAbS/PmXkNՈ 44 R㦤Ȱuu$hN\1We&TrOŻ=Z9Xc݅hbߖ~sk"EgҴj1_v{3fxxZEFFևnӂ mby +rŮmŕ ˘ Ss%#}ىzW̍BPr>Dұ40aLƆ ۉ + .wj cv*Sqk LrqN / } KJz8YoN029~Kȹ ߐY i|a!;] *W8= (~yo\+4뽏=5h6oƣ*6z/l'PǓ%L^MMMkp }`/xw޲Dm7^D"Mf|};]a3^r)qz`!1BOBjL01ܥtË?8jcXba媁R*Xz=iYԵ ݱm۶ӱmwl۶m;X۶T{>sN~uWZ51ƍ1gU_TibB90psqxR]]lq@Jh>#:LpcsK{Hrt(qpS6[rhf!H3@|u9__0)ȷќMMxr ؽDEV}e/S #PBG $ro903E_z2}gRK !d%sL"8'%scgLCKTZ,6's%<<=zJ'H>db"6[x𸏤D? 4T}?x99m['fJ{r;LZ1g;A 驭P-VK$NN3n W/77m/9\V) )1ov{)^81Dh=XQ|SEbK$ *=ޕ:_Ge )8S~k\y~8MPWr L3 Gk@z}=0#?培cPn ,GJFOdE}Tн=4U&[wh.  xbȚv44S=e7Ұ  z< tǒdp]h<-fCzMGR/q?*/@4FMese$4J63m٬3Ii:du1*Ne>*$f&j8pN<-)r'dIiEMwN#H,ddˎX10oj#~P1R *%T5^c~k< UTaW4l3hc5)HE-1cCA sbF KLk4?2X#:]Z0ZƝU萳VN3\՚7u<5I}u|..%`>r7Zk܃{U)c]VCsZ'a&BDA}z FsLƶq %B鳐W.$ġl`lFUE͏+T(%RѰQ /\/yB bI3iQyWL.0HI!~6KfٍI%h͡'9h\p8) *(wuKL&+_VaGZk1D0@5Oj`QcH%'G-8|q/ ^tMc2uFLf3|.PҬY#߇M؞S, $D6ʦBG h)W.Cv9gZ?4KO,8NpPtv[ %X@[#M͓Ydi?=E {nhs}R)*Iƒi[@zb%V'RҤR8 Oɹ y Sl/ұ $Kv\o+ ^_Zg(Z]&@.^JJFRX<0/aa(,'PzV4;tU$M*hj'|֫)zx|^յτq+$P$E}{a/*;bgw#Ob'FuI oEq^dਈB*5:dP_t aH~d2mm+eug,2VCCd\\MV# ;#!_!ѩr9ُ tfIzVG? .6ro-!!yBS9_g5=z*, cAEng3ժ//rR&29ޣ:6xZq|U&~r: ښLGTUUkqwTCVSsPg%rv1 y[zAQd )H|$z8~YIE}2x>EBQ888؀LD}7N s%Nf&aIUU&pMf94"bk/0G;;3*Ftiؾx{"}S  _q:#ݤnܳc7¯dZdz=tp8KbȈ(p 0wë,w;}I$A (q_>3:.G.PsroW=%2`vP9@Q.S<-r +Cg ?m/ɝ~"f0&H S)]~xL7l%%M Fͧy&a! ~Mq::-N8 K(F/- 3e" "~$is8uؼI yhBT)a_os:_foa?3JRX 3Že"qLKɎ4 ll/wG<;}/Ϗ7y yPWupɰ{? ͼI#G'Ҍ0#YmU_jE$~~4zs=AM /7:yNvwo"X%UZl6Stͧs{T'eP۴[z݋~ k*?P$&JQ땅 *衁O|mWʽЏ pԡAN@Z4[ x#aD$ ~@mA;0O0mF;Zyd?``#:ZsPA߯,V܉vA[^{mݮ0U2p9ӡ/[E +C߿YN%LR٘טC˓4bd``Md1SH^(b^ˀvQt@ЙTZl dzW,Z#eM><4ŭp5.))9AExHY+#A"dzL`plzn49>bTIU7)VgrIJJ0͈r]]+\o]uc>'-"Tm&,K69az-@ZAP065a'~Zٛg›-[ۣA8`/ٚ3e֍"v]~f7#fof[mHQ^*=sR,6پsy\\waz6@f E1hܢN++p:TP{ 2Nt9v)DRPHВ#:)F i韤GVwj[3H1_^T=6]TEG/WS\yAɲcIã9I<,m%>kVwLwP1CWuaG;)4׬:~oqDτTIcGw܏hF 7f?.˨Z +9ǯw:8@cpݶ~&BP~W -einSln ~{llx%WhT%ef8Of!Tu e#FڰRM` !]1(w,ld#<SVKJo1'K9qkŠ࿄B(C͞ ARvʌWV+cy<܂ӵvڏ)s]&Rs[GETfU3U/3y!Q)Ec&zyry6j?bs=$H/ " ll׬B٢o\6bX_~~cٵgkFcw줋j1DG:淒Ԉh{A%sqM#2Rr=s1r'D{^Qh>)A{ʔkӬ~| >GD:D y`EyT f"ұ*hd3&8ׄvkz0WIYD')=WޛL-%;=8IFrF=HhmYI]U5G6]8yyV|>?1ct/,m>(,3&Y**;C3ԘޘZna#5WEڔ^gvm1ZLF˩a버tpX|0:X+ĥot%;G{]*>o) J}*_Y\V0T1CTjqP\ %u^iuZz}zZR;w5 K,u3,#&E Ձ}2X8I[`q׮\('uGp~T\n]i\9ʤvdqx y(f>+H\#ڃ0])=b͙mCp4x;*y,;~d\ "Riaq܁ES6)'ρLRJ;~}ppdoQxT`t@%YyhxyRLĀnV0hFJb JwIqj蒨p $E?;L0*y8ȃY(.o٤mH'1w0W>VLZR9[[{\l٭?d-#m *^nT.Ow}\F}v/{>bޯoYorIL3GOU_?T8ٔ֗9fa쳤Xu dfID]zH;"1-{d*,1JLtX>Ў1=քv$?4B󣻈 j)C=7I"Xʿ03hrUtL,E^LŠDvĠLr AIw髴!%:Car ^s8]"F(17Vy /X>Kٕd.g'6mqi_M߻<^\@ԅlo5(eq]@BeXG E+x*Kn1""}ڰ$0%b cROkYF$x}ۇihѐ<LiUJ=MVl-$TLN7(}w#a3g+Y?c4.?f"ia{a |RRڧcXMqHOI&$6'M.S'$,P݃&bXzP%`_dՒ毗tq&҅Kf]eU\ ?Gan{bFǿt$R )$ ʪ+<~l )SNud,D4Iy-i ņO֍7N u_q3s*-t<狀BԨz6*[zʶHd ׫-owY:Ӆp,hݧmBFʋ@RiEfWob]x$kcSJDn8;='cJ~Б"djzNFÛ֠:Qr cCնN$f$}h8JubӉp ą24R!)MW'$DzBp΢x7&rNGIxC,΄Tg/9#g˯ҍ_v'EƽIszN1ui7jBJH*ټNN&|{&v+ԡ@ }WOd^,bYpn_͗_2wDj}ΖYp QLl69ntdhMUj`~/$@HE o!?גw&cٖ.y0wj,kQeSPR5^l<\6O//mή&5Vt'iϊ4 ºXZţEKKgk;0y;.1VE䜓[_|xe \{WS߫|LC ωYUt-#pț X5xN PXtŧ5A\^^:Cpz-ܷdzKh!SeEIxk0KJCj>2z^dADuKmTi(5K$&bx)A ;1*.xʙ zlhEM޶LtTLYm2s~ D׶zSh*^sUO`W[vqaQH?n*}Ɯcf`k{!;BߤX+i.vHpرH.. 2x}Un,4\7? ?tt R͐2HE"thxi7) ("#S˧jpo,pw%t۵yQޱqC+ 5u$԰GKg ci'fZ1ԝL:10UeVh:ԓ4yJ≟I)v")%ʮ_):S rrK|(.<9H&Ly,ϥßG-Y~/ξ J?`fi-/勖ZQzy s80L8dԖW4QveEsH [R~܃㈹sU/Fܥ|cdЧo-Y"_ c׿0HX[cMS6{z%#O'2@ke]Ϩ%%wYBk'HŢ 7&2i<5-{%tTr}s-Ţ΍-ضyy!Է9ILlI^ksdsk4t* 3>Yǟ\Eѩŏ3&fM6[v1B$ꑮqELBn(K Ca5Gz2ʧn*uL[ꢏej49Ycrd3VW~Xnf#K/r4 vV\}O]zaj)UXk}5*3q1ޘوs|)fq9Y;5KnFGڳgE-x^ӯG q\SȨV 6Go)I7{gUP6R D{56/^Xӓ^W52@3܋-w װ%K J=DNx-.dW*1OthG~X:D~'X҅d=z9("-\M+W9,V9ߌF̙ y<=stJnlw h V4lKDr.q2Ni歽QA5\mԤq$5Au#oRiK`~E5=+ Pyp j|^H%s Ip^sR>m ]Kߍ|@=rţ gqpg۞ /-Cp0|A#9D|1>8^SdfBfӰ6tx$t162`oQĩP8>oq3Gk4Vb_kon룾08Ѹ:\&cӛQ׬ mz4?w<3jcYf$YTahnk:Epu80Z73+sǟiC?5>'4[qA!%\?yG.kr?YnxF՘$v'͘Cz3}wun^kJT#u+yVBr;>ErNT[%TRDJU4S>Oϵd[{󍪨`&^σ?b5 {|zt eh̞iojcԆ-7etohNY>t;05T؏ޛι̯ΒV-RL ǰ:/NNkd::Sbk}ryHDq|Ҵi8 QLmHCRr9Ҕ # RWCN0l[Uw>c`""YE͓8ѣ&AmiR#ivȽWs"76SfQ"!9ڦ)) BfCfUBr228/V9LtOGGϣsű%7i.C"rG_G$߽ߊdXsX\ڼZ[=,חfO%1}6GmGn cCf; $Bc!=_t5/V fn@X@^7ȌQ'"1_+^ 4|/~}暬r g(I8raA%2}B0\T4Սh[' Yj& C B:7 ~ +LSwzuX9 l^@ ,,6W⾮qw|Cg!!ZS..ِ֙PjƺpyuZe.,HZF-Jd*B;||_CB7sLР,Ĕ:2KQJv0LJ0f*.w|xc(I2KP7e?YOJ|m6sVIaΚ)Κ7b/JT QG<&sRBJ~Ƣ)Z$I=â}p0dJ`׫PA_Uix{Rm $^bye @U6C߈̊yz}E"acTNzk CP jO 'M]N*_D3~^4!:|y0ܧySjY:Kي׮>,>wb5!y wÉZsG;0N+kL:Im&K2N/d/bC;~?̆PxƯ1&80[L $ E^iRD]GzB (^S 9>FbIϱ!ВXaXxgѶZU 徃/&<6~oa׈R=+jTmf+}s̈́͵ƢDrAψp;аG9%F0He<20~-0: o+3sHm \c/BE3i=tFU.fl$*WdYݟDI{v؃ZnLj61Ai[̞%_ӳHqA'dҗŵF/G5.-!!M7g9+HEtH bΝ<F`8J:wsD^..׸xˍ2̷/$;oo-mFּ6DM|V~P_\ #qф&kcDu!F(6tc\r#-ԑ xF1θXl\ǯJEL HdLTH.I,AV Ѳ-Z,<4| KCr4F>&*{TENwvrRNyLds|>f.W6a/Jb;^]]Vmŗ:2%wȰؤֽE]JK?ί&":fwzlP^Gmu5ګU644z+q98?3h<" \^Ӏ|_$FVI6Ox$,9qDZJ- 'Ī!&(A^u4OE.Ie [GSmIg-z.9urPZ< E+\S/ F!룅iO;"tOVQk5K~ʖGjFNa1;S{|#;/i|vh ӕWqaC8C/`DCSω1~ϚYwyT#կK.k+:bW=i jwoK0O˴%" ǧBe9ʴK4 55rC F+b1 0>EmYzݲs *WIWd *c". o-Y2EigΥ v^8T(ORJy\Ve2 gF 4r|1BYg CƎ??mۏi*XJ956I|GQj&SShtwl>X>BM#֩d%?? I5C-n(lOHJu8w+L ؇P#ƁcԽ-ӡ  KezمM/Ŗ Z<WGZ0Ixvq3]skb^hbQoM+ c{N, ;dp[/Pu/ S6$U~b^Bגteo(0 ?jMp 2ǡnS+_ r* h}~g}~tS)҅KWƤ\ Xbve&%\ fFNQz\ROn9iEˊ4!!}wc~.Jf}9Jƹ fCC ︮x,!%~vԨ7kTyOB956Azp,Y`wuUc *qDX%ģEglPCKh$ǿJiQJFjǰH܉lF1FܽG0B0F0:2S,Mw_fVTccUyF)`􋪣qkxmH2m sk[e{݉$W9L_(m""FA| C0HV'eUW%@f}*M! 9dw%}f´7/2VL҅P6->) tIsIX=;!p{`b&GBPoA%QLG5`` IscSm/)ƻ uz[=qv`$"_!&Ht 'jZ=KNiV[>Lڿ,;&uzӱ%qQ:^ ̗ԷPV n k院L53J&k>-B|UjŢw{¨6X hFv7E$',vz P|yQvzϽvL(J9OA&U3{҄ xlȊ[2VJc;?QBk)ʎu=3$Pțy&ϛ*4 G VئP!36+jdO+ y45Taez'ց:_Tt&[7 _r/Pߜ"}*`^nEL]* )ZƬcG j]" %$쮼اN<e6Nǂ.g@e':灅j-Y<ܐTḃna-~; zBA5ݺ@p ^>L0!&Ui|UTOX&?.pF>'?kb@X|XQ]uIe-\E8Mz;0i,^V|Bp;SHЖYpuom4LcTxNɭ?j" t ?4٦byY<+㟐 D w/,,=WǛ nl6{tUԴL K9Bu0y*MW .'Pv554 b!nHG͢ȓ(Fz-D)!6mUkaOm:JжQmc 'iwBɜil2LeYOA9::Ņ ;GMTble0LO`[#h_z;4WDIPMқUk,];$HbJ~{Y=iU\*(Xv8>k+fG k7`J6æwAhD=|U&1C] -W*qgUz$RRX}Ze`ouUkUzQa*ooFb!Ka fd1F_kWPQwnQ#7tַ99Xh6VE7OO!bJb^FL@k[V`aa5PK2Iocq]on7\T*Ta$_4y4:\txnON\kC"yXYik7AF.x\IphwR9Iv-8kHfv`ޠNUO!7>zF #&8Sj.jMCKE|~IĎK!feEli:w{XC)¨=8 Yؓyo7Dُxh>SInK E2*et S;}@L9]osF C V~gr@[\dUuG(7oiK]fNk(E1zmx4 ԅ;tyxxaߘl{^[̕-@7{s-:\.VL&ҿ޶ors ̖DSdj iR FC(ƛgc4 "D'2r^kRxh-lp ~JErڂȁbR.ϧ<{!R9rLӣadZ;L|__9%$$p0G4?TT2nߒ@J~l7PvrhCTuaט7p==1XUYYv<`[z_Qo'xZ +J.X|SBz]pI>A؜i Ni[#k3ܥyfFm8"{X!nql]&RA EU{r%em 'QEKyϞw֏pCpx(UDdЀ) _ŕ)]#rXEnh0RWn]H,a.*x29`^,ut%KJhp:_rkw*=[Rw'Ep|lL]ʢ= MM_zq~&O![z d0Y>qx7mj&-HA^3'TFu8Qf~%Pŏ뗫ETKXzkx9*,bNT7ӞKY*h^ ,(Vn,z`;cJ,YAt=Ӱ:Pvyv gƗ7X__P|:8PpkknΩx{Ɋ]8Pxx8P^_)$Bh?7*G*GW\~h4)Z}Z[s-Ol\V:ap\q.x&_DuD2D vv BhjQE~ " OzyH֖lpD̑ ^TR3ۍ)bΓgV+A.5QP=hXiväJ *uX>f1J'Zu 51h)aKt说qr*m!Us_ TT弔Z|KNu#v䲁{o/wZZl\fz L_EN/9@ 5Y tݙ '(H͏K_VzzV&Ff<؝LFã}^O0ܵsT-g j;uڝ~VXH0/)gCZMJ)|6fkUpH%lAcNĨ1}{u}=)Zk%eO‚,͹D$\먒i'fj F*xdN,Fc=-&2EU{qIHC8viE.pt|X0GuHk*ԝvRX*/*AijH@ ru{f-佄$c~ax!.⋇"nRH b.C3KNj6 "{շ )|||_dVAli;@Z  P!f*e?.`X(88!eɼFRhRviD\.1~cBOWWW~TaH?lE ^ bdN>"[3L!O06DUKQp}WY~\bx<_+hl(@3KKjZ˖:*f䆿7Z^a JȢ 骍zdꐭlWo.^D*ZwSiɄq˭`.ؓI_汿_BQGxH?H>+bש J ?Ry:tH UvV mB^p&nh.X?0l ,WVVk`Nw(MݯSdO3fG~eM2z.T jd+!UTWSsvt4<7'7XosÿcߚENJ|Eewr~o/)e ӧf|'n@cFLI~ w`)ح({J0$G&uP~B{yk$k _ "HRI T,d~&=~\ْ^.6w2R `3d-+;x}˫;37}b^ PkYԓ/2#THb}bkiQjИpzcpm$)@?3U4*(N<^^PDb8|>D CreHX8a6_-gdAEH -? IgcʥMo *"6b)kɐi> 9%bKWaUUl2T>Nee.3;.CMKT^--Ɯ. LT0ͦjE?f!bcJfUUA#7!&R\FUгpD_8|1i{|"å??hWmB32֚ׄ]<$[/4 חC,fw`{a|,1fMRiв$-LP?)mދ}Ǎ^."6nSS^+YihF'~}l*ȷܐ]((fkiZRײge=׳9'f?. "NZp_ nsloJd3 ɰOWhށAu%tg 6 >dgzAo6x3p rr0cee!:z-ɝ_iX:M;qoqd'6<DX-2#o FY˦w gz+M+fڇ|CQLkQ8[ll7ϩwa"@)קyDFdImn͖J/ ~ _nxA/a<8| $~JE3%.\E> cJ:.^*6;rs4VsK[eMy5\ K0/3lp ukt"4{VjNW P6:[<2O$!ˑjkd@ @\if)$B =^MT!r_!uo Dmx>eHB1N7Y4~:\U)P&1s RZ;' $[h$|Diz^%qE;l]x[$u~gx4_@(3f)7wleP|p̄y`k\[G$3EElò "ƛՠe`wj5K%efeGİ?_(*2J:R҃ny'(<1_SgòQZqe04"+L n*͕s,Hg(R[6lzF!jTU_3$Ȏ!ގ~'S't=[打,"L|>oJgLF\ok0#30OR7@~|V$Xx{r8zj0ʃ)Iq `ee>,p8#>o+(G+wA5~9J$PA#ļ*AuI㋥5P(`|0LWH} [{dv ^.U`"l!È Ofr.蹺\Ε#e gJ%kdUeV_H[;3 `A}K1GZk]?^rj,DE^+ % ՝xgR"YœF$ivp4aj iyFLCie":ML""Dkn泍3{+\-r) ۳NN\X !YhP|D̎rŋfe2OZjjGuÂvΜ``g: vcy0 ]݂o\7Qoq ot|۬#ӟaB䡌 `+e cu.'};%"@V^iQPd*:\.4:A|*)^|944$@6(q(H< MRŨk @ hBjAQ>2  l19rrʱf*?@eo0kaYfzM#yZ,5X p8 `[Kcc[0\nHAKS Z YNSΣi3"BL>>6Vaͣ'4Y)4QUTD  х#I!H- $%l XC:'L p^87wwp%k-1̢G (J(#8Y(㣕 $jH|~> ؞mn~C 5qkǘȍ=b ʬð /}cFęL l7Kŝl.>vy5Mhwj+faîvaij&I5%! N3}OffT ^o,[: -:B2' 1.v Ae 0{0X@&b: Z.u6Muk[a![@|7O./#$dQ  h4dqj$$$]ϗpnA{^ m؄r;].QQr{>V{}w dk;rfqO3:zNk8Oj QP'y´owSb$vA*0c|?1qġ p(~3^fJ$l7jtyBךշ \=ZT J7߇ʊ9>!Ltr쎰Z/C񽝀>ޟhIUy>4;57~Dl7}2u){cmMA*wf q&}kCHhs>?y%9m;'OBʗ鮬?,C\Nټј>!C)J>rs- f#?z &##3!/9x=M' sx%^nO9>Üf|N@.dy9-s?t D=HQr}hB c)cR?mRP俧 ),(uN!ns50k(DAkz bNGaGE5n;';xC!"e~}@|}vy,lm顫,n/JW֦T*3x?߄}ZAz-Eɿc]I$5I`<,6vOWEEL7gff]h@>|PvFa!@Xwtt/Jmi vv׿ov{s]l&URZ.@M˅v{ijhX*)y}~\Fmcs3bPd` O .@vOF;Z,s>)6\v\X5,DFyk Fzoxr{4njL俬J+D$z.b2iyۋOH E{SR0 `)QTc\urn'>`=mrr`<% j b `[%lvoo﫣]GR߆'DFrl 0V`BMPU4r7ZОMhq MES?8޾W*mᇇE:'$*.,$!%Ps kxݮ ~n<9@N6\643`2? ]m)(cT3^PKִһL4qQQ2/y#M'xp,Vp[7T t7`H|o۳+g !63Ѹ`je0pZ &2]G/&mw Fܜfjc]K >Yr\0'@z<xL9QׯҜk݁0,+Q37y,.g+CLttæ*1 8@8%a Bi8 &i2K(+'FKW**)}:0uHayv4REt1Qd1g\NC#4I_rQ{6m+ћ{.} ̖GNLa~X@7a44&Z#|}Y؏il&$s;ӣ y utt`/ԠHqƿW"AKXyZrx SieQm׿‰~Qa z" _ [@?.5PyF$4cpq4 J!F5_0I|2\)BV< CT&Fh ;F6O?.RThGIkOѕYK{̇1I @x%3+ƙ@9%1"aU,/4"ƃ傟6߰FKZޔQ&1E 6wǏ?=3fûR'c"}-nVIԘٕ$tţdHZ[ùA^ Hhs~nrZ+-u7n1D'׺.C^pQw*0f( 7X:7F+6TODfކaF`o:AҕlR2ox+aYKkZyaM3~0E0sV뙊oCcg$iuL 3UqaIH@[#ߚO,v=MMz\^LVS8N-Tmmf,mv4A#N6v pg %Of'a ~nx}lc̙%: \RUH8SV-"3u羚[:G|fN(HZsse8\60Ws'!gM7a5?; kST"zDIJFsO\9:F\HgT ۱kt%fE6uߞhH]ų ą;?P`NNS91/(ФQAl***WX2oo4OiPS@BS S][VH{kn%knY3~ƣ#q1?R~*RJCIˉHł07*By&t缙H<,2?G`{*EfZK[q2,l>@h Z&SC |!ᵕ;*Z'fBKtG%tEB v E7 pT~ZdV= QŴX$ZO޸g5 Ecd!9(^)5,Yw%{XK_B0R, իugZ}V#UF= {=H8`c.x\r#~k(pCVg IW`99ԭ6w2e {]<^GH:.jw'2^2EXF2q/: D # ԞsH`cy/@$ߡg~kh4tߍiIN˕)%GwYRԐ<ӐI,6QSG3=d[IA=DqpfxCҨ\~v+yx.Im >ZMDX yZGK: F߫D#DY S/ sPF%i.1^xt{̷87ƔsI~ꞣ"!K37WcDNHE>RʲJxմDf~WCƕG(厵,b<{ K@P?^P6 b8m?VhEhգ_2#4Zclh\,5h\V CgG8b#z])ZFrWI3i9} ϸb?m6m|Qg:x̨CZw2+_IT<]~0/ڜw DkL^lD(.ԐՒ`+(Ro4?/z(v$+OB7~RX эeB(8m@32>f!;R[gTq!_<VeOJ ,wZr+`1#(]D@GfͽEoJy=r:iO<W=*)2&N5Yyi׸0/AT(H}Ԫz];n/ Ct'G cGf:kwغ.~p $?t;gp~I;[w- ?y@kNsb$r|_R6~2z@}׼pL+X:TQ W0ۂ%V-I}~L+kĒ\i*8f#?D:`$n94j_%M8T{vPVSRe=bbS PtwbדbѨDQKC')U{ ea' Yi{+*^8lZKP㼾h6Wl*&>Ux3w""i͋,C &>WTm{Hm5^3aI$dJ` !D$Q~l+}ptv%40Кw@b_G"ĶEo=8c!$4z"=NPX{Fχxxi Kz|%c.j9MǺS*"QqğQ|L;fP_:~')*j)נ-}P(0˴zea؋*R#a%Ia2tŔT2+pH [MK:Opd K(8&v0+rX#n.J`9F}6 =lȉ=ҵzN;lDI5g5ghLn%DcbZѕU r ޢ;%\IOYO$&  b Hʉnjc~j& +$fvճM׵:z)}ڟSBe:_,G `Jz}4C:t\ZH')eї~d#r\ds 'Y]#!a RDUq=@ʴ+$mm4 k_NOLF$f[ -E Km;8/a >یQsRFg/D ^_&CZ@¦MXsѨ `NWgnG2VG"NټxpyB*8}Ԙ ̡v !NW4=PxSm(eoEVW0:^נIf&g@B #/5BY>{Y{(O^S 2f4f7sX{G}}t?͖mh}W[28~K"jb ;T] ,G]:JM`W 4#bgđ|AӢY4`$$+"6_4oJ$PVm)\NEV0"S܉k5IDxv/D{VVq9HDGСz#8v䘌ߕ? `:.(P@-HV6/G;@b~< ` Ki2eg V'bi788E"gi|f$\;ƃU}a1&@ 9?Arz:m޽fb8QoSnC*ѕ{ґ֥iG(!1cdb9 _nb<"vͱڍU 3Y 2<ʔ,Sc glV ZEۨ?:W,ݵu ׿stT9fTF߰! c ض *@YYSFKciGm@R{<>OMc"SCjs* nWVa?RS7߸P5䩞o/CJgWp#v iCL RmۑlS- zSG5`z5Wr#/o=rKlom` e1hZ+24z>GkkjPBBn_ M?cx=N-. S"3"~t(<7[4Y]P4ز:(1[iRs[$FVa!vPnf6t]ҦX*sxLFdFd^W,[Ӂ7}PƔG`O׺YD;/կO9{h-Ÿ'&n Ą])$ c * #_ ٖ<դ[aK O]w ҧ=[ HONAr[\OI凤 %Rv*h^\aINxeC*Uְtԑ)bp?Bp "P'/>z!`/Q4!!$X;ww'kpw ]  ^ssp%5F1zvN`B˞O)W:Eisap*4?Z f2H)Ż;V=(Gd 鰸 ܧ+`) G`iyAC4'^yw8mL-kɍAAdFT#>ba5|= 26\A˷=.btT΢Z%gUmg9Sc(SI,Vk8UfPo?ǐGbuTK~t/ QV|WO˥B}D @v!ÀXDBPHQH#([ԊO Pb 9q_wuF=~ջFнԻ\àZ{Uҿ`є\sw1#芲QBgz3/+nO{1:*AGztrD8&>|jer4ktz"JI/X]3Ǣ7#7daN_/PIX$yVF7;2# #J |۩G#go9]+~1~hϝQ[7Tqo" 6[%>ZN~(IxM B \O,3 _*": -M+_!rjR"׹$r;GbC]KKx1z 717+!VsV/HͣHcJ  [KX.2rsG/s~:hZ`wTowSa%jO4FEAgp˟rVoЈnumbE{HW-s%;jZ^⣧z? Yuݘ_dBOՄ>&X2C5//+vwRlJ4n`RJ2Щ́;_p/KT.3Pogk() G|f-B܀SLfH RT7ddU!-41$Fh0iυ-{ 5XխXӸbbO+&(F ۲727Ϯ#Dx G)D7y/,ѥ]]RmZxz-TefE&vḾL $j*G3ϔ b| ȎaF[ S{c;oU MҿE ygW y*1mEo:+RrA?a< :lMbav1K?GjW-*E6i&y%#cw]޷@g_{c?"5OQO%\Gh'W?1-yje./l֒=W %01f=n]ᡩ.BОN#mw3&ݭab .|lo3pn_.`Ἃ|~e_ OTd S !aa D ʐen()/mʋw_}&qb2-*k;GhBcML9w"5 bqߜG;#o 4E ˀyyքrEj\riʉ,Yǜ[\u)\+$ǛS 2rcH|9zۥ#$Q[ʁў+'x4Ӏl `ἳ9QYQFn@ 3+,FddiUC&(/IS3ch~:yۯu\+A)uxhLcvՀ4AwٜF"Ő:)!XM T?l"π:mI^(m%c@CyFc ːݗ&Mӆorp-)Mǜ `u)kv|O՚ MԼp0m0,yiFdmLxtsw40/Vwq &'a$7&q=1GXFP:`y+/f/h` M^!ݦ{ҥΉ Įm56CH]Ns]l#x/r0H 1Ў.1/䶃*Ow \qbP=;۠1mgnj|[MR:ټ>1x6fWe駱ݚ䟋]^LWh5 X}YZͭq1gҸA 21$5ܾdP\|nDjeً RKw<!rb89 %0r&o>;EX{ӑ }OYŎ+'*Sl"!{7JW- ;S_xj%Y"Ft0zA7.$X8D<yO|Vf3|;λĮA'8=r"A))1X38o$\*ƈ/*y`3>ʐ|Ek/ﴒR,H^gZϖfG~K/*v{bAC^)(俢z&T$HNx֊g)0"Lza" M 1~lPm&_:u& aq/P%U +; s~[ܺ\q/x#(¬EM}e':Zc,D 8*WJsX'Pk9\qD}| '(cOYDgg>4_T AkCvW__U/qYp91,JvFG-K"0a1ԘG/>kn܃aA' Wqa>OıY9F}j*n8dNM ] БERˋNf2ꫭ׺̬Kk6펈fLM OSj&#NA'2Yc|~leye!uWlM@k5%y0\{9[ႈ H;T2USڲǚz)Q,N} vPl36? Yڴ"OEhC!+ D@ʙ~o*Icf-|ҹdGyC-jao?"{.w`k2j6iҴ :MnB3/awvƘF.4j݅ĽI,1±1o' " h 0| :I [;Ĝ>p>YL[[LgLk%>ǟbng]FY}L3'զ{eߌO-G0e2 u kKPFt׆6Jj?-B߀ܜf&]'Z=:!YuW[ҕ6,6kN?_K_i!"gbatz QrTT$Ck " u 85FGf[1f} }T >Τf kvAΐWKk^7,ק|\A#v~etww]oA~ۈ (J,kKWSN7FY2h'D6٠5Yʾ&1sntV~Gdw%) T_O{W^]:RƼW"jlݖN\D77(?fVtVo_{{g JJC!g7Tn$F,Ϲz!$OD R&N)U]~T"ehv^vjtMa߃㌒/4B~ La.&ԻG-tkSefnD!/ h'Ʒ>2R犾kJ*.?KiъKPCs}rF?R F}|uUֲHKrˣok㲍2r:Éۣ Aȳ%WL"nHzސ `"^N vr!ݬRlK$Cidx2F'kHҭJ~n{R\[$3BK" 9IuϷגa؄ 4^zj^n[ja&^Rh`"74UY^0\-9]ݜͽs:0Fbfƅz c ;@/-d!R;5^Ŗ3FH0nI[ C6c@C,4 F}-hЬ/b'Vnk.}0Z,59UIi,4(:UEmIwvFg-S!]~ǘ.S9%n7U3l j+?pf@cDIgJ<eQ+f?wO=>uFy2`PZ 72*o9tCK1tE+Z)!\m{.fVG{p^CW#F7P}x0ٍ4:xZec,ôIvʉu0%vɳErkÜpX>;xsCnE &$:W'iL 慛r9t1IʖcX,K5Za\3<H Gn٭ʨ/fҸJ)ox 2H8 Ā*;o_܊҅df4.=>[2&ׇs5Gj~qBBByMv~ˆ/7:KY6-.-snH%KƷUv)P F!n $BákX$dXs͂;ʃPf};;;S~Ř2º~AO f1O4._Þ4alP"ѢǝB֬/IL ) q9vC VK#0rŔB(rI1IjZRRV8Ź.JZk`FV͕η@A=>=M|ɓF˕jc4{qP[x2G,Tn@Z2s~peEl`8 : 'PF2\eʅ1 Q3T u`1:-OU@E?m{lq)aֹ tx=˦I՛LjKzǒo&$rcmq\&d2*A"6a/g#O"'=2K4aWM~][[[YM kS%=؊Wf(oseꋐU30a)Ř_=%R%U\fneuV7yؔi7oqFȲuxyuKS?WflUPbtv^ʊFyRv7fLKw8Τtt0j|/NnK`4CT.!Ko"`:^1%URsCW~ޞUk]=᭖y+M,f2 >m3^MmT9 đ[ kkD/(`ZxJwӧ& V}f1 nSʗ5̞hd}}E rztLwTxkõؽbSB׈<@t,!##t_oFNh_趸5ͷ]l" r3Hc`hkJtzdž B gD͊OW .*_a@k`wpn9.?def\my|^VZcb>nx?T/ RW3zuxJy>%"NGG-͛TsMA,%x$`H>d`"M0oYv|l{42wsB"X_Uu@%Gf=?OZpQeukmau=4(% ꟟[b`eNԩW???OOOX@аxx^bd1Y0vik$%MT"]rܚE^4NTZ8ٓj[Џ[Bp(xϟ3fic3S$noIS=xа5@v>υ+%r0W:G}%} ?Sk U` x1>/$FXB9B666F6_~B#w1Y?G#_5z=ܣNƂkEExj kޏpGjZ `1TT[^_g2 ZK$2(SR ?'3i  +'w.dB,X$$XpQP*}9Q|t^ jVꛖWߢyo&à챖 JBtc/k? 3_krzJoEƴPmLغf L0J4@iO0jIhV0 B6 ՀDzOڻ8 =ƉB. c(@yH\;[TһJ gI /iin[J)j11 y't{[\|9ܰ$j~s^Wc(,$`b>@#?F@px[ 5-<6.O(U?MJ'J6 _?r:+T͘D,DIXcU0n'E x60㦓)wVV .:!)_hV7rºmsg)`3Ȃ4LmI 麟q9?>>&*O l~>EgF;",KI9/7sU} O)5OGz`57K_!j)SP}ĚB&-hB.."pSԌ r<{TP y=ooit\:&_3}&RpU%=FG$"ZL`dZLh M$bQLʭdWa Sl\:Śd-Ddƞ[[kk.G>ll LFv9c%!BRʹU<2XG& & fSTS+iA,R- a.Gl ӥZ;$4%"eRfjV^|B?y:5ڢ|4sg*a#iI :& bwWc6;`hr/'ܐȋ&02dޱeh,c @(weBD}eݻ#,rBHʢ`: {0׉rUC\DwFh.;o6K&"0tq,e*ő@SQQQݏa6 N8wA`rfTAWxNLlѹbh .@w!)* nu.^WNF9YqDďM;<wݜJX#1*o0cmu,BZ3,$]z8P0 obkvvoR!7%ÓN0 10YH0/W+8HcXskeeUx&@a 37^H+J ݊A_$Z}$~#E {}_ͧE(zUU *5 ^/F/a34H~aW|_<{4 n)ZEI(b B___vQFs0 %2Eef S ?$J鸥$ nC yJJC$˽n1)($9F>o?eok>@oykwe26S\YN"AXlHf28?5"K-G22}N^@Ii%=X_wx~NC K{[W uKP҈@>{` ;g33agʒu5N ͋*oXe# U@JWbr|>Å1ƒ7kv\ szԤJ@4[;LiBAa X QȤ3=i .]$+Rg>`K YivZ|~z`ŽtZU-%a}׌CTo_Rɸ_{Sjm++@rvNNZ:a=Ic0{H|^\x(n5i߾qJ8Lxq80iDFFϩIbNOZa{7`8\rkX \O/Vn/w2-};Qc_klVNcE~N*^-O AY>RNe=ˆUvZϴy}$6|ჩT||C(>|, 3扐s#1P0J9Eɳ=%IIB`;>fbY\Z(9PF:zb"wdDn ~)n M`; @H L2rm^a'EZ~Lh$8%Ϯ=N[5C<Ǹ(#2Bvn[XDkdkrۣB5op\vZjmNj| .@<"-Rtuu^1GiN7-v~>'ʀgeL[KIWCq"t Տ- U|uȎ*T"_,>3~ΰv|g3A9-=@Y0p pdAZp&JoN>KO9l Ũ*$s.~%9ј4B'} miD%YnF" ~>tԔHƫ`qc{(RQ> ݂h0>uDAV%9r=.yZe>OP$&V!aՕ, h5y}3og,@Ƶmg4yJs?_~: 7g*FFKYPH([qZj6њD-( c@@Ҏe& -*@t$_PHe#PR>mT3Pꗟ^hcV<[0ZB0I92Kw?B[ R}$~Q11= yno҉5Y`C?=ReH+:#""^\av3f0o]shbmP"Ydx:pY-뭖597%#9G~y^M)#ݦX/01q`2`z:B2dG b63G$=2, +yB]+++}})Eo7(, fÞ$$$NX˅9K8ݾ~t aKv֨Zo `Q`HDp?S#^+ܮM;[*5sMksFګ~g6TDQzȝ]j^p%h%"*%S T* uIw_VN M7܍ R%nC:𫨲|YsTRh Ѱ +*q)17֦IQv<Vyϑ/%=pDTG˗f˃S"5uh!S[ b֣ƖQ6W0.GŒkSQ$11zEeh)AQ3 3mpOr  1T&!mh-o_>? @ ?97*$ͻR. ED{jͬm# 6pT=7,yM3SOrTme&jڨ|p ͏"+di>Tlq;a5LɝKfnK/0C=kh'Ξ_o!0#'潱|5+K*I(UfTo?E.ZWEƛޠ٧:-P(H&˾" #!ᡇ].6W6gÈKWЈ?0Ed0L@fܝVRaӡs~QΆt@/ޏ)춪OW3N6ׇP5j 2 ,,@aK@B1Y)%GvAZmɔ7KPD-M `@Uif|ʕ趸wqP>GuDQv$qRs^' I,\<\fL2 rνEᯠ6S}@XTjJM.bW< o=>! N FvH%~ް VN| Vù@ѴI>B\8Ȳ??&;222MH[Lx1obc}nX#Enc"Ko@^]gp@x~ F}L⌀l:W@ddGÿl>T;i*6"y2z㼯<( Qʨ똔d@ *y5ձO4cq:lcgjay˰w LJ˷3"T1L/[h7rdZm?'>t5ZtO_Y9b(ݯao*و``wwIN*X"g5Tٮo ,MP۹bDʥP O X"p%?6|5<=?IB.kGꉮ^udx4jt%_J 0pzGv#|8tzJ~Z3N)e.RzCک mMUU5[2_EښCD+B=C&35:HMq$!kD˿M@S9bdN|G1nObaYo7qjc wLwfzQ HFYT>KݻwowQ88Hl '-X@|e@r[yxy$ TUO;۞z æ8ʇ;cQd{yJ! S ,ek N A~)ftdoNVlehڭl8Œ4>YW:Prw>o6))T*!>`dM . ACkmWWg+A=d,V+XDrOw;vdMt'B:rz"^O-iD8'*tUG@HJF*%';>cQHx)N<y2 L2< 6-Zt{B!+$gk+J;-%TEX|: ǻyT5]>ccxgB?1ގzwƳ)5*7h{Jx'oщ>|nY;V , " e[_iͶB%h!i"Ó ί+&}I\I_ +UXGʯyNFi= C`` ,^J3.(ߴ* :WѼ}arXoVgƪy#G9iW8x(q*H9Jjl}nl]` 5X9# #vR4;N6VS=#!iS1VD1w`ay+븉ևShT6 ?{p2w>Gly*97 őŵ&4<NZR4a]>)1'[ګ7C\މHd#hO3*ZfK3K>I;r]$Opݖ{4v н#?D4ɡW#AcY%O1,l|p[juut{ ; iȉ4U=;㺐uoオ#%rQ_/!-`M.GE:M.ԵdxE,) ߾7X12fa.$@OŦc>Vo~iDEC#  DIb UtssJ| Ҹ966BX^}k\ m?u9GkmQIDžbл3ݱq9l&1yIiSg%sX Q*B Â&ђüIk~pgJCVB }͂=NBMD肪j՝'H _6.* |5᚜ ֡UBF3Vv8T\e~UxK3fֿh6n˥qDSLjNp+WUfmӝLz{TvOM&񷐁뾯oF^$>o͒& '##c\g(:-:WSS $$FݎJ_FWn:n±Cu z\`&&$^r͚lq{2gk[91UέIǂud6JiȢ:VmX?,njا^kz6<AsWM}!s0-YN]wOƐ`@IT[9,ۃGso /ULMd T O^JPuXݬ0ѫe5 I΋D*B*^DS$s7ZiEdSSST/,/ڕFE9BZy3QD%%!+Si?Y0yxp^@D3<<.'{Ш:/ D;#(O2ږԪ%owU)o'R ab~;e4Od.jTB>:}9"γAo-3JLgFx#1Q¿*DƋrAUm/ ,S PjL4bs"pV2c υv\fY>ʋDkf/R~$bg^Cf; HC̻i Wh>~H5Z #Rcs/፩uu7_@EQ!OCb BHbj^HlVIR`d@"GRifO7]RokayL캊\Ԍs_ KX0SSymIIGD,WODML1\v oE~bHkg=ì ?$/ OƐJyGqGBM7@O_vpD.#''GxO{0ٯd"zk(^WV*n2(F2U{j~mmmJc"3Zj?F ru#/Le4;&uRvV^@Qkyy4^1q|HC=1E䛛4 D1) #3t{~2)yjJLdA_%˸hw<3čvcz*J4a=/ ɸ?P>?eHwb)r@E<Q̦',f-qlduTl_nm635u}`O5 4qZë scb`o// ^s@lE˲SS?<RfkBD}F)-bBcPMq [S  uwŠd :5`gI;JX eɏhz^!Vs|G O1(J!E3uQd;~CC!)6n c;f\ =,[f X0; sVyhy <='ϓNWy˙O('Yl1 %y?1'zm ޻ΤɂDҹOLx}9_`pcmm p%$!]eyՠFx xaEaGvV!&/~Ewi:q 0EyIg@CC% M}xSnSخ9Fw Ao)>_@__.EWLrUf 5({->fZ:039?C蕈}"H (T.b5WAalk'e ks\<8P鳾 Bn 򦲁j'bC?^ ]kH۶1>ʜKcJ喟O 9\ K ߁ /G8 Bfʓ*95],1|r-ѷA"c5 'IrP5aλYT}'.E%\bBaCQ !8j-1IL KP6P`ſ5|(jȠ*Nc J ?i%TnUzBZZ0Ug_au.?ԧh8xand|vay e,8cJeS^/egW,ۈ 3c8 @1#r7{6%\;RfUxdl5m@ la{;9 =}OJI3B@?^JTI͂jYbGg(ӾAJgSd~QK#šq-f!͖̂ j%N gF Cs#h@B/fveـ,e.˔Xn=j#j#'7)mѩhU%cEHGzΆ j+N(+Oha3Z%ޛrB.6 >\1Fe>c&g)Py~v\eg!doXoς@wT:)dzVq{HA Fdm+^)_|5YĹHwlrgٚ10&!hf_!Eu.(|bC KKQv>[7~ߎyVk'XQ<|gK~0oMvoE1!?j+wQ+Se +u{tlE6F=r wmk|&2=իvmCNg() )5wIe ۂTh͘Cc(~z4 '| ,z²$4e0X$Ңge01R ~=WwL"Qxªwis;;LGJ;d#@R)70F7$u @;W%D(n^.L -Ca>7d~Qizu kƇd=3a?46[o_K3eLb,((ĥv󷱉&qsXHuʈ',Ϸ|^Ecf + _[\ΒnKaO/;z,hj@4Fd =S9nn6Y̗#̒ծ lӀ*VКWi3F]npvޯx[e< ]鐟$UkEG,x/]Ox 4cQ3U=5e8?Q*O#|7 V3m;٢te Pj]')Ob@ ަɍYL;W*1/w)3'I [[ُgSXz\ۀhbBɎ->T[/iPcOhd/SGS6D> PtJh4*$# y:df 's)v5w^ub)FT.-\FCgw!vAD}++/O'3z>Kzmcmeށ_:+++@)R\Ԍ:c3Se5Z_Tޯəa>P[/]䟳 \硰7*06t;84o^D_E hۭ}De,]fL~TDx42R0W*u 0':\X$ěG>4JDӳ @_]k:&kUViY7XklNx^zmFe}9"#&*:.( 8O'$x":)4 fupp؟ȇ`n1{4V'A)nikZ4HVZ>fV@' ėܣl}cc tId.Aʘchg8ue>vO{7_ J,&|{֛~J%P>F1!O)Ƒh)wjSQz_ $0#'kT1ps{ (b" tww///K*{L(HHKdYԱ;cF(qZJ3zFlB-En*z3|ۉn+ Sip +FBW$arf)a䨸 SŔUO =i2FRGjaT2kF:ykpz[kBSk_:C'2c:kc-)unjiw1g6`BA2AWWv)clIy D抵^IbyGuء0陠޲4#B)b:pln'>!'Қqx;ԺdrŃ4;(}<7ZӚzbHnrp*%Gbg> rM3LJqt  lqEz@meŅ+ƿPR'Ya^=UΠ)WX:ƴ;nfܹdҒ>uPp^Ϧ_s"M޳:Nr|S&JDw,Q:]#FCE=#TL/%uw$>M2!?_ _LY|),T^OaPBP9R ԪU,_AY/M)J1f<$C=՝Vns?>Ne\UtE.D>y(3Wf:VZg ɪs߇4d j?4]S`YڞMT2UӃ@I}j!h"~'W; :%'fXbTФ]Q( Em=mS,'g3i ͐ό!jlh@XVVtOv!4{H2'( Y~tZ-;i錵xNj⨂6`}q?2H#3Q8?\+Y#5_ [Σj#cd/u[V3|5>=ž}F9GSkh~ "@pn*M/Ă|.sj91ӨYmo"q25%&0ܧ% -CL^D}Sz,FSvf`JmTEMWhk; qBN.IRǐ #gEl_~.oaC'6^d2`գ:PvbA4{8\^L[lѽ.nkS'/1Db6-I'R9 q3j')YnNbp'iퟟ0OOOŪ^zhݣt޼.A q+OVl͵W(J0Fڒr$4e"m)NWȥKi]0$J*fbFrsȸ-cmnLi_ۣkuְxIn1ij]oUc=]Mg] zd@FNclT.Wň3zlVϩ&$&Zo4x$ c4W~%?Vʸ*3ް0{Z-cץ ^PߢOV>eGtz{zU'2>b嚒^\kd\ #TOx9O7 #s/HViVTjΧl(;@7'l;>AáN~kC ( $u MTG%U fCx‡be]3ޘ>%)W^B-^';Ph-%;):Aގ :.4]Cp4hGAeU;4[r@OR!ȑ ?:*GrZo_+*rLQ3fC[Bknj/it`%QNYشy$.}r+mx(R*-z>g*D![٭.KsZY~B1 }6P=SqggG32waGt;~X)u3eqN Brhk=|ll Q4C~Хf4ZG=SɩfE)DgIA' AybՆcLI7e+TboƝ8gb6Z9iR z)s0bz,b6>'<{˸d'$XGҕԲVal/v26t^|mEbrۖ>o},;V-Fi)13V٦NTs9=< # EήVfqoxYbuy%9]7w"yf'H_q؇9랪ztHo.$RtLzƎ=i描]wo'j\ۉDh[Ʋ+i(6/[ rw~RHe3]"=|{{q~ƹ|u!RxT S_Ev[>gd&c._9bXL`rV N^ea-t=^~X;V!4kF[6%SF񭜖닻|T+)n#],_>ѧsx\qvD7JbsŅ85#ԫaP'RRot<#:,MUERZj)hՎ1"w~/K Oܰ2{ŷOm1[5?VK̫mν{Ws4E 骏Լٿu$4oꎡ$1NnMȒGlhc*֝^݂?a֦VjIYP3$+mUBlW lEEaڑ>oV<\w2E5{C{.{i&Hv ,ks|D~ х`D,z&v8ƈU<Q, 41[^#Zpm>f8Q YaLW~+jT|}d[7\kweҕsmX+cť?ЊEH` hllW,"6r=iu O70tJb^&(?p~/%TZ:Ó ˇ"rc55 Ђƹd[e]#܇wȮ@{fUa{<2ʊc=$lsk9a&H,xaOJnG[C(7>?yQ'*2=t&34mv%Ц)dff$(B[鸍 'ݍ^V+! K\Ǫ7R.nrX ɉ 2ahw%ddy›{"/]y ׻(G~x\- DD, +z@vyuj: iQ*f/Ǫ ~ʹEw>Hx1FZ<؄,,LJVW+c;ʷ&Y7H[<.0NDze6Qo|SC>]N/Zb4 ٝXv9[Iz./+l|+FTS3Sg4_C3f6Zxs+{y޳ި?P:%]fm48Hv>|D-7, ƴԤnj9|c'/|}۟ %ٱy܌$F*5to[-itn.#H2JmL]'qɘ>dَ!4ƘOY.S Kس4ARIH{r?W -n,P=V=xN gi쒲Kyq74>]cC1ҋ;M&#z'K' ]2a$ᔴ L]/-mB]UuoƓIJ?߻g[:}1!s9_\Co BxƎXMks졡y|y<6=N9 E:Y5K%|E@qM3Z)17|ö{34fdCg[Y*qtd=`.ǖ-izѶx B"$be':7i<~\E{G}Ye#u,]))d!8XLQΪ63xA 8u'̔y9> T$sǫ!7c_h/~YambG[+.\Sm6T{'3#I&&h=2sKبL2B\|X+W͍eL| Ǻo#(Z:~*]n*irr|  d{׻!.;0k߱bksvP3@7HLzzRC[ {1Plγ6kV{+T8gεΕ l}B-jٙW ͯ)rK;dmuBushxĥF6K3m84E I(8fNҹd .QD`<9y%O\1L]sDU*+=j<\S)J:!@ l9S#n{59v G89O#cj6|92o&\mî5B'al^gjA]4#LZ׊wU^<%*#d$Ylٙv=iz'Kb-A]Xlqm6 =Ab_"^w? -hsj9vtWh7Us u$F_ziPw\|󇞍w5hX'Hi{ͻM;z&iCMLdLy51RpLiYCXE_{3:4H &7"z-lx7y{sP(8['T>Beݽm$ \]ꡔ⼨\xy4\ڰPuh;L6pWhsw :Yi'wwj.n=`)U[\AXF _Q_<_`RH)dT̒/Mfx~lhBznlӼ T^nOuinځd= YBBQ8)l7z\pF~A%ɺFeuA9S&앑%T @1%͵džF/4CK>¥:C|jf,JET\ӫZ"Wk O >%=DX߀wg?;Z!*@=Ă3r*`k4gВl a۶JMoP ry.ÆH\]sf#fl-]{`,ZH|W8_<]^a Zy -XƶQ.E 89:']Iw/ƋP, M-[W"SX|&?MyhiJ~ڏ\c~ltcbI(@&BBO=O*U-[򂞂T7OZFыs cڡò}3L͇xZle[3:w3`ԗ L4•ޅi9ޫRlG;=x,x68pprj~9}rWELCޫ.4+AFiȱtM)R~ qк@#M!&[,E5x_nq.:HtKKgfbi}n9b7Yl ,N9y\$[oHyӖ7d!,1x(=11cy9:cZU4zNY,  4E>91Ԇo)G'b: |WNFUϸ\<< Ȅ ,EgRNφ}/0n1ItCw+9Zѩys""tB" blLAS*Tx}b0FłxN%%ʦ.&+;9fVD:a xNՁY^ٺFHڗ?YkH |Y?-S֧ ar3[F/|9~n0SV}RgW^^bxIi>y`J9c.VHWe )ג(52$R0c-b* 0وMO2G6K>T\P%1rO`-t`ԩ&ݒXFJ+H4t bw>z13XmI_Z_x,U/z= dsցnfڏAIV9D3a9+(c-Sf8oOr[EPhxhaLS `#MZoEs„wiM3=ȺFu܋|pg խ;HTF(O?/ΎwL{i^m z/Ʈm뱶v2C'-[ a;n, GMZ!CuC%\KqB}e4Y+Ofj Fn!x4v{fG;6$$j9pb\c5~zoZP7{~\ۑ{/"JܔE":'?mPao⢉g&ԓ`R]Q,޾} Ρ O$?-R}QbkIu ztt4AaemXw1>}:i`2NC 8̉j]sw Qgi׸5ZJ :Vޛ@zsËzfof[x^ >Lgc'sDϮ**Kȵ ;C)ͧA!L2 54vmhVJ~\D-yzن$dqq?qPU9yg=ǗhJEi.dghT 泜xT8j?QLmNxi"`kz hĩ"=vj1T]9;q FNJuh+tt+N m`. 9М:#{T+Tf-.Vlsq=|pG ~S)?׻KJ yTUs+r1m j 25(5vVEu.6n ?~ѽTt~nAmab/캆aO1a$@q`` J [[A@LlE[2@ g0{ܷ9^^{jdc@Kʌ\ݸ~Oz&05h<Հ\IC:X56ң8ܾysM foP:헯AAƅ-7GgzNloQ*UEa{;-6`ƫ^ /v.q]e󰁓ޛhƳg6ӈpذo>u][}wG-ZeaCo}.4ooxIQ>דEw/gWZSY#Zn_` l"$ ~jӥ[5g9ɖ #rt0Vb]6m\ub g~aO"Ka?~\R*>@ћ.3r~D(c\f=w>0Q&o_XZt+#Mݖ]1ѷ#sl5qW앩Q%ڎ;Ǘ{#ʼ>/ۺk|6ԉfin<]v Cg WU2qɋ.R<*=M ]W9fkA0_h{*1uIJѿcji[~}CwZ *,ӿw7L^F_[?xp3)pn@'>8g‡&@@f U7.Vn6i@.0હ{Ds1T<6Og„ ߉'ttjtjjj_5NNN|?[ZDYd[YԠ-ttttjۖ:Q::E:5eNTNvNQN eYU]S-!$ =(KlK"K1eeYeYʶζ,ʶAoGYfYY֠QQ55E55hЖp``P`p0wUUf:jЄ8EQEEQ5h`X욨pmbكձ3Cce $%kR碢``뢚Жpw`uKmXn!" n%~jО35h -n^/:p᪃el W.oK8?8"8dppE0K.xPC:_|]BW tl?_P T] ugڧq贲a52R$U%e-9>21C_y%z3E(7*Owjp[O.Osnqȑf+lΪG%J7|yȨ~߬yY[Fgޟؿ7mvm=v݆puIWomts^&ߎ+KRZޮc"z4YPXA |sQm1rv/ݛƕwmH;z/ϳ }`Kxzqquw'hөK%Mp.Ky7jofɍMMJ~,\G5iߗG* phnx' gZć0+ms"M,wXx?]=pMߚ҂G >9`~̈́l9)`uz5FW$x<|k}WXzuխ9_w)3V^ -z-mװˏ_Lj zcE\(׍QhKҠ[8rdMiV4sj.!jWeZwʃwۦCȔoe aʥ#:+߷ue;ؿpWz[ɞvQ{sjRJ'ubtN  \(eěLJLr=H֭۽g .`PٙŇa-5>lh}[*T :bsbhᐽϙN[ }Mh9?zQ#X>rܜ,__߄wn˼Ux@b}OʵOK.ɉgqq#W V>>h냉J6Zuۖo{_I,~W}Oy{rнNw~|[>G6SgOSG]1یW=ppv-a3?$t9ZpB_)}Uev v8ջ>wFm0KQۊ}~) j(awkc |zDAN:s"|じ/ܳΠᐹgy%9vf;SofD $ Mcϝ&ƒq[۬lu]7~u{yf:JikÍkBG`|7n}x)>fyOlQl='''-pwA;^-1>k6,Po$d){vنё7~b-ېFG9mzxJي=O__q돊ʡ#.=*boFݺEQ٧&5j1s7G}^ Ÿ#ڳK/ A̚(A׀ mZt3V&6Ԧ>w7;17>>l15d)Wg/tipL'{IuSϨ1ixdWۗi8w]HܚW,l^)۳FyM]YYr㜱wب[ZG&O/~SeӕS[ul`ڢ:):Θwּ6=7N6k޺1Q6cG}evjGϴ~7ƼWzM9'|_xI&jci9њ]/5/O?Y7c٢eo:2UY-{֭|߻hI5Y?,$ŷ>[a\=_hђ+Ohk8S[?t)z8ЧMRvt󫓿e_:4 sU`9{FzpL>t Cn.bvf'`xC2}c޺d\m4\r5%O8_ }hN7M޴R*x)nC5:kw[w ~n__Upհ? :H?}$.m;H}*W.yg㠧A}ƚ_0{+t=Sxv&!JmRM_+[kϰU&M\BV{.r5DO YJBO_]Yan-6N=zMA8q8xʳ/-0zzâzZ;c"1w?|G|+P|Bjqs.784|-:-'h@7E]N|wb.`fp}[ٺ/>իAVvsm@,õ~\|@wדv >2)zK rn5a7^jǻ}ʻ2ey ELKXDBSQ֊ӃRlg<Δmɹ7OyWfK yzmWtU|^&g򉧺-uϧ?-7aS-zo:O5"¯,ͭ B-9A+|38'vRSYM:ߣYL"8ݮ΄skձ~3unv/q5q_JǬ6 fn u8;ˉ>—#Z,6_rM͏)vt׺+ {ͨ??熟lO6/%鼺qSW4)TTu=-Z\1]_63:aa6;NwVz Myr!1ݲ>L_d N](l:M9eJf,<-dكR5<>s~~VMQU0?s4<ߗ 7}Z~ޝ.fi {3iѱ Wl{ua8p|ٻ.?|l;:>}wy+opwjw|w/x Y?c^vFFGW-oSEv}޷ӳ+ɫI_=9/{'&*hLR(|}6.=_slvߔ7s.nto^ܥiی|{v]gʩszN!u]}ׯ قaϧT=]|o]o7_'S9A]p?)N5jhYn.SnܻQ~VJXz{kVUmVzҙP&Z>~A x۬[?,K';2ݳL挙zmyGӾ܈5۫^'wzwd"یG[zkZߨN,$vw, _=}g蕫'2}Qd^'voԳbϪl~Vz:6{ômV-W9<1:adz{ ? 缨6ƒ'm\Qe93^L|(@/-ӡ,2,يۄ-vw>h80M|Ooj-i5|ćs+#VazN4w}U f;llx]NvWߤmT+#ԛ:d(umƯ^;ȉ*{-]*_2qНL'覲!-cۈ+X=Z2ccGomaƉ&4[_ձŪIz6oiw{A˴!]o2:g]tn;zmtW2{7~p+r9{>4kCb|6-?ɸ}bHfHƝ/eu)zlb^soIJj6QGĥ6 .?S'jG;wVo۬8 +7~-im/uz*辥 Ss7pn5w&^7n<շckZswyluQA#Ikz|ꨗ+m>,3~V . ༄?{~^V{þ ~uInOnV_fN5/V]3,YEW[eI6w9]p0\3p3~-!Lz%i 571;ݖ{Q̎ZV~I㘃WۖWv7oPogm<;b~]z^|䊕[~;Ҏ{EO4RoHʁb\y_]#_iB##tr;;&}{sضS?;mGsﲡyEg^4?Os:}Ķ qs*LgGo41'}9knc"ޤ}{ ^HY Ly~WU305xyѳ闟]%.0r_Csmo_K{Bp:k|[ysB5*_W>lzSE-:Zw0J/,mԢ8nN߶5ۯ˾ vv0ѓ g/}7ob%>kwխϺLIuޱa`J߂&]|sɒۛ5kGGn{@}]ָi8QֳPNfBT {8]; ݻlQ?Œ짱G.bYUfB7oFzЭo{dv_8?vMؼa7=k:5`:chgɍK^ _ЍsG>lp2X )T|YgxqREF^8xr%nn^)I=Pmub%5qff;/[ypX>1Qgvkڱx洆Չ{+^u9Įk;6:itR&|pӞXkWl%m]ƭiZ=xY/iۋwwW[6{3+ 4w9#>FS'9)Ō6gȞ>LHۣՓ# [vf{rZ7IM[wq'm<GK2wG6~-7}N;[#7ҭZ.q>aѭhu??l#MO;4~G9c޺~^8m0Ą] ŭ̢QZ|jqko|4/ixK[#.ز+领?nѺRz2g"Cz.)-7)4 Z]ڲ 8,PabNot=qpWW2P*7תSM[a3M68&ٷ47pf̾/\ŒqN[%M)$ ;K[IۏE5?W-R2dWM<38 #)Lh|]cمv~s+e?3%}Nϻ? Wvf@[,U5x7(MmV\:m]-;9 sz:H ϋaguh#*B[x#g\ }נ׷NINKMI2{"ь0st3ό_x#GD -O ?V D qqqXP(ǍKnݿ'~8 * +MIQ:q{&-;[ǝ&+]ff ]4exx$}bZĥ11y ;Ǎ9(aeLݤ3g΢Ýn(|ڪ~3r-n}nnun%;W4Z{ltVj9}9u_rKgNtsFn{_Td3jokJl+;6.nMl?mqΥ_Ox{Oͮ|\ZV"{Ws߶z{hn^mݜ'O`?rf,q݃#K>u>J r1Ҽ=֟bIqv=(} S~Nqykvu{{UڡE)_J.T}0Eil~ĭČM_pm_׎duksw ;n:kȑE;[pLbdkQe_wv[ >i_Uӳ(:-~&n8=l,܄~-gT}ӲuS~HmnFmqf); /\ui@wuR] XwvX`7 ׻!½7kmEsl 3W2kD)fg9C2^4*p"OZ_; J,!̆ݷGl}6>'TW|ՋK*MW:tnI:i-wutNDFeîĔ_ ,dގqƞAϨn(wwJ4;zN2ݬ||ꮩvSg1[sIB#Kv߱o')Α>OC\3OWw:%ԏ/P8 }YwDWKV? \tC㪢rlV\7/u~h ;ήy|_*ͼ nWov _*rQs4TfSz<&z ]n(tXq$m!]:6aVP8êPwz ?QŴ'Lyju7Yk1=sK޷0t(-J*ǟ,H||Cێ;^NddKz&濪LYhu;L{vє7vz{ɔpƅk3fK y3[,s =e%#^z8O/,]o77uvCPƝFM.*Iݿ\uf7Nly&7X]aqӞ?s$o?ش羚,cˊ'{LoYdЬܼ #FҁۛM"4̝Yf\jY7v*u^gTsS#(޵7]qTyO49QveҪ<vVJYe\G1Χ-S~aJUxYrSt'~vfVGJyf|ciPe3L,~l8=pV ˝zWT.i[ †ntk>=|{IۑF[sG.tex_Sn7roy㿗մrM? gӟ(u[R4jJĀSZv9fH^4+u阭Zn TL/禷Z}jS}/O?[vR~NY]oj$,mN֮i9|z﮾OHϏg<{}ު#FoLwx*_riEġ،7w| ڽ~|]찛>:־i/氭Mݜb*ӫ #> k۔Kmޙ-w}gc6ӭ4"f6=]ە~k_hXF6IoּstTMw/.46]f?$<xxrׇz~rM굵Y! e8&F^4fHT>&M->4\<8nӰkVD1pp{*%Q7HKߠt˯M2̱9uJԪoE|ǫe_H3tlϙޢazk-@ܚ{KZ 0lawaڔV7_9mqڐV?>>lĝ߷ kNђ+o[XtvUv={֜W;||K;?kN9tк;7K{ۣ8gOcK"Vp^hcvMwOczt++hibk2$1.hܸӹB|憶sŖamLnR8lE+wۅ_&k_[0@Zq÷k[& gmx +GZlSSuGN-ɰLF]Ω=,ZueUңǍ]Ysˊ3>^|oqǟ.}hƣWO^a>d;-fvGZeKn\2^N8Hͫ8^>6cy53w{?ϡz;o0Lds:vÍr[=/5cک Nw>cZ&L?-xbaɅ9

    =博L|0ŽӁ~. w?3eY ܧOU"{oc SZ< [297L7zW%sw2Hvu[o wT ժXo3+?bUnsK_xwwq^q~EUy+'Z1iM1i]Xv.VZ5mW4y- PZ埧g4ik7轶}<va#acOK60ntC.(-,ʘJ՟C^ltX-XWф>\l8tY=Fz_vB`Wge 6k<+sF/h&Gל[mtۿi~{e0rfWAeN@'bGY?:2m X4* }҄ˊ+;O[Qz ~jЄ El{շśզ\S-6l ҏ}׹=ubv1g] *)pq.~Iۄ'>O531DZq~jyV6(.\ZnːBQөmV9m}ڟdb[9=.zqֹݭa .O!o1oONlXzz/wO?w»ܑ?eZ0Ts2>5ع\s掛gNr]goTzozgƑk6o5mo>.?F|˰et8`9/3Dʁ m+hZgYscZ$ٷzZ)j2k~QU}.ӳOY$-Ⱦq#]..(ڒ$?U|ךOy7)˨۲ Zf{4'O<[_6)ﮥ F-dY'Jb}*sOPkx=ͣxn{o {a}VwwZfK- (^^qͣ}n$t]taނMctUvh7wQk/ܺ-! s?bgxg}r%l#ڜh..2>T>I\~zUjƦ5+ZOWtYέԔΎׯ9 xlfz7w'l"MԔlƏ3>6]sx¬獎tۖ/+5_b}7qG<{m9WeϿPwkR< [yGڸ8@m}gOؙۼТ^W'_JJtMF֐+6F?u^|~eR#ϵUGAgplwWx{/iw>=9-q Y>_r{{lXɝh \-IS>u/g}8l{SUcCM_6=L9ĨKnZ ?XKAMZex^wͱjJgeF [r;K/τ]ty痙J\r&nI wu><8_UOzόxNq_wGuzܑu?RN5nZD5I=U=}C%ߤ^^ ^3oYoKVܹqŧ'/Oz*~lt܄n#+J ">_6$Wc=$3mšwmkz8RɊ.w6zH\.ߑg+ FnMuCn>,_="gEUd#n1s@x',dkmj/Z&q9O7t΋D>?诹߽Qk]~wH0r~q\]vp1ŧ>Uig޼Iγa{lڎht {[-ݝIn}0􃂞Vd%֛]v d)ҷۦ˪|7#m~r5yV(7,t j˼&aKׅxެGoޒI67{zϒ;zI7ԿspNqIQ?&S[PPRa)2)c *znzuBv%fAQzS&tazq'_Rӊwvi5͏];m5VN 'vYձ[ G7bU +#MLPC'n)D޳8M}[^h:HlX Hqz槞{{-v?soy7tx-mce>jcɶYtEoE4}}<%-/[WsWIe92/{Y5KTJ*Yl=R'7ž=8qg z'<שj؃W^Ki^oM'*6{ 0'j?:\܆!G>k}4{)E̦5a-OG{L{??`ԣ&B'y0蛟f?^_:m"ݴszEWInsvZa߀}w~jkVɻEՌ{Ϙ;W۷]#^/>(ntNG/^qedY]VufshVHG&>硨bx^K>^$o~O8og8{ޠ|QUb=f|wE^'(q/z' 7jw{ w2ϗ2GoWR?;uuIQ_c3^?cFz)0k+_\ l|I?VxE?NEyzx^xVۃCVE`nt-jѶE/=?C ~@KPOxg1W?{|sgI^jKw/wXtY/c;7+Ȱ {qkڱStɏo4oibƗӬwtTQ%zj9jbW޹xzpNw^ՉW s=<'eNv^z|N9NyG^fqwWGNڮﭿR} + fo;i<:L3}4`fL̾ZA띻n+ive dKgkbNd~rG^oW,KLi9~>}P 6ݒs{mi;퍷7|dڔQ+/]o Fki~֍P({v]6ƾ-\z.0I87xW&+ѣƌ5s^K_U2WOG>0O[i%Z=m.t(}71erI-y) ]Ku.oWh5~N_-Xǎi/5=UW7 nqTV.[ڮ#5mC2OԢ }JkIZX#g\q0ӽq޴͛,1+=b匹݃484́k8w96]>{Uww畇_kOݽ x'QxΊvw50N2W߿7#~5 _%-:u"ߛ_:`7`G~1M\z:: rԫN`_;m 4&OPf+;Z d(qJWeRiDWe("*{(]Ԡ%AJhh$m4CIKEGN\-)mD@R(Jᨏ8|@$CeڐhU'(h`}M3a::5`B"0CAx}::Z;i˺Yzv6nv6V0C 4۵]lمٓ+ͭ? jϝ>FGRo4pC]XJcDBH)2! (?=,Q$a&29dR!R H r~ŋ Q>9e*p+EJ#eI"Љ DXH@AAR?RRY&Ј"/`SBĐ= L\D tUk(%XCj"@ĐOKiGk%+, {à 77CaO#6!]4,TpH`q "CRFq_hNyp8\" %8M䃱 ERpФ8a"&Wps8M<Lx!>8"%1M8X(m ~/E 0 RH@bOJ)?^D`WI$X_"BY<@$(A#㧒(&ATTzș:߁c%8yY|B(D<9 nXP!q|Lܸ>N!ASI`f1x[@I"75&́ ^3 \v p\)1"BR.Bpx{=pBb` 2D A?(^ ;",teA ,P{LP:Z(~Y!' p8m{":x0*( x$nc mO -@ qḊ!eplb) `Ks{*T NHPd`| xAtTA6@)p}`яAJHm(# EBr¶1~rɆ8xJw^,'ܽ $e+sxqlXC^2RHVsۮbDb'=3B޿MEw DH$CLTIe){ET— IT$ge( E "pJɂ3#|y?4@ȃ:frh#\nb!z S!'֍VRBu|!aGM,jBVȑXpcIw q501 h%`XR@01tnA>!S,OPok f? C" ȈR@vRi 5XKJR)@UEsJs;/%b8,H.*0Y}^'\,ÌBX)i  ` )oq8 .R!hR,R } R܂|M@ch] %x1 j A@RL Hx1 @Xr50(WX4>II)Hk6GtXD>bБͤ2%N" >Rt Z:a5, gT1:w r"EX<84G0S`DpFQpH>9)DzWbbF@P)]fצ#w pTrb"x!+J-nUn12htU/Z@̉X9 P* _κ(N|i ȹB KcK x"|'#Y<9Sh+X*\>xQ 9`DŽSQIu_(ehR -A.@ 6ᛚ_FR ҂VsҎ'yz0+b|"!O$ZI)9'BA]֙=w8ڻaH ?4!SLR3<%G B@V(ŨDvnHѮ1bԬ%]R4?\pQE 5ߡ[~Jǡ.+p!KmN!"_ #|8xtG, ;Qu}@c_psH)A*sVo 6$Ҋ&&#}I?/7dL<+`Ϣƞ =<<|I?E :| 0KuA1 <6pPO!}pmt<" ^b-|̨¡0_5.*fQU(9pPǦ]!jb>A V !Z'C\8`E %{זC<ܼ}\| sz~L8}&vuX09I i`y7#R`r,h w IaP0ءy9ϼ?j/RN&:s>.ډM!b  %\ÚUJq$A d_Ȕ8H[=0iL. {X}8AD#.xfMpBM҈OH%G ##eQfӦ,.$KBbƗ 8a *u)YT^G 0hO1b YyTTJx,R!= rO`.\Y.LA/j JNۦcH@/ ў# b0 D8ʒIOn@J X6S#PAXP' _֏F(ȅ)Rl"P`@3?ԗN^K[}iA:a_rzH N#17Z PŇLH(("cS(I9I|$!{/8 ,!L8eB$'k[ق"&d@d?"/:FC˄x4NObB$nn2O5=xs_Mx'wDP6rE"n_MP(qzMd^2#vaQ1KIwQ2Vbv!RPDe>_]OJ F$.9Y/6ݯ{RoovҤEYNM#nQ"BpۂgߌԕQlaH:`+sBD1=X!".ۛ!1 l,,q.Q@쾚"OP 8.ѣԐnHI=ArS*KHyu4upXbL>\ gsc vӪ/E|`lBҜ-+H!Te`n. {#:I TpIHYr>sPI%&%jdmT%$Ftק ׄT-_c͌g5vۉ< ;ߗ -zkȰ?3]]oSQ ڿrP])lʼȋ-YƨqGTGk:!݅Ǒi#%E \i6oA~-yKHt ɸ㐞.^5`jSr|IB ?RDF`)ThvT&?S?R}TL` 4  ToSVuP55$`JKț^çQU<]HRBC'ˠd\4 53tW'#Yh"Q^6baF(Yj3$BC(C4=>=54%C -Z! =ap%!jzx-~rR3cP!KleU06R\T[)J< HNr!X <0e` Q`MzȀXJb4C ׇ{y/H ܡ U`+D5" ɥ ۓE!SPHrP"_|a O<`#g+[9ޑ|:`XGѬt˴ $f% aP$".,#$;a]Z15.K[+=&3I8P>BR|3 im#09ƫӧBBH"mB (>n?<_,#"zQZAPFک3uP -Ff &i4:L,Djͳ.ur܆:5gY:.TEGc$h!x{iQDv/<9 RSH@(y+r=ϡu48zP+w@[(*ZDrW(LU<!U'(ϰT` 8 j"%1._55E,n"VR!*c0p`"9Dy;$$ұ R;,î9PtۡgjlRhЋ!CE T/ALc%] 3,5(n HP:s|$hIރ&M3]eS_ Bd:Z%@V qD Ăp/( &A8JwR@`6P(4(jUdn/nH &8B{i(٨U`=> %S^A$&8^ćtxR my"{h9q8|XF$ Sh(<,Hw7<4t?w(oR D*ĿYL`"$kfanf@}6\+(@@QoੇB3.:[C49z Ã:\MqS ( :PU1a-8UDD$VƀE5B85mtW'6X,PTbxs* d&`FH_WWP(n ˣTs.I8mfoeeId$Z09)48.+{8(Y.u&pP E}Ex!q.1"/#z)(Fz$; sP}*rR[f ptH4l@2Q1E= GS,TmK6WcRINҤ&Ov1GMVX_j6`xsMKƍdژzZMN' a$GI MGG7@o 'F+$HGpLjRc$WLe %Q&eTMk9 7`)' Q'FgN`ݠ+稏G&>#&f""óB (2i4C8+CY@06x grKHZ6+.P ~aq z`x[<( _6D1JO@jC@5NĘ+HIE‡ħgGǗʤ).D yU^x\wBU) = 0BBˁT #XhpKAnVZZHۚ.N>W(At%eYF^%覄{jOhA`^Oa(b9XYEܧւ:m7Ax(QNC?ڣ i  pZX!ӥh$bRIuG6ۃẈ+e O7Ch5'Hg4vHKW^RH'}`c%bh*7``RND1y需j4zH38SztDiO 3Cqǒ bD"4͗i|&аJ-_شJ4!d:Z(NF L rҿf-[= # 5d/6D G&_|Cˊ`5&Ea]8(\BImb@-' efs>4"xvZD/` S8d%*_ilkuMQhγΉb 3QdK_3&}5~AڬHZ$(%%(\k$b>|w4zn^>ڢ J 4P9W_?vK,if SC(dz!hJ GB$S##D1^V J&qtX4E _MT-- 2!uUӚrk"tD$ |8c8ã#ݑE(HJe>p8am/ ]H.;XpvA'O -T $HS@;~KlTFU,<"C((jg<P'腃j:zFp ?LC}Cs#2- C ɞ Dt< R(ѓqZ&Rϒ3_Ix/;i-SNX |6dlHKH!_RHYgTEש@3IČM͋toO Hz' 4~.@KgH` u/<.у Y+Yoʍu0̟4\!aRH*>%#Lb%nLA& I!PvT QRI+7N3rAH F<Bb2 1XFD%oOF TJTJm#k-N>܋r a.U7P$赃irΐPiȌRG\%lKrErMW! Gequ*&8]Jr̄I %slj뗒i3&N kBzB:8x<''#n: c;5O7!,1h VohܑRZr5R e[&mZL4)< k7QA74Ex !ȗ+YYH(*hzV,CBfSnDJqUHO|ZjȱA.FhbuQ m( `]JǪП(#e C|ƵIy$qPXOLl`{*2 x,Im4 V>IY`5/g"-Nts5$4\ʴdj@ Ϟ`^j%G2b àm^  "DP@FS[" ]['}s*b+ L!A ݁QL"SX!+ l+FΗ &T46RDQZE{Q ۲ׁچ0j|v⨉XO'L #ٰP) )W(-!j5ny4~sQYjd,LJWpH-KD&KwS ?j~2?'a  AAS|2 h$U? 㻙,  骩`  tI&v`UЍb&)cDF #_[Qz!WkAΎ0P%\pJ` Pf8JTSp^7*[0H4LC+ʍ';0y(JNI<90dr% DxJ""_G,ktG8w*[K$YNrW[&5KeF46 0bBt\fpQ9cCg\E߼"SjՂ$᧦Dptb|àbP8'N]97ɰuTARa2!Z")oas~$ RomX2YL}g`ɡP`.D¥|<% ;)qtZN<;*#1\}RUdAE|MB95b$ [  9Y2SS⌤n!"-"$u$AyбI+h*?L6F2Zxvb Kd Hvc'䆑sV.V8 )9ʕ4\{ЬW':ֲTAP;PNup83pMC5 ЧӢss@dD J䣺4n$\X0мR#o ;T*^u,M"P*Ե*{ X @6kP7T?Ia\-1xH(s!aƶw`&X:Bu NAӔIxHjQKۑ2QE(/*3T~7Qjۑ"OغuXDGzt VG3o9 mLw?*`F "+,؈!֖8N@M%U!ciC89cQ9W`2<|DϰXJ'[0琕&_Q\y &5xEBNYH?/Ҋ ayj(xZSJ 5(UBS!}LaH Y &BtlF;䫮ޙ# }1TJBƌcwi v4R,53J[iv Ф#47c5bT6uOV8DG`j1-yl\Ɋt/?sFTmNl~SʥM֗t2-{9 uKjGTx9㌞ Tڴ-хd !@X::\BjN5!JeLJ/DI' Y \P.e#G]O C/jH/39, i!Z{cAA#Ѣ/%rQEijP5]N^HP "E.Ot)$e1Ӵ82hN[ #VaG Pk Ub@DR蒇GbP/FEXYb:I* eUOCźv^l]în,ȿJ c-jn %80Z,4AOk=Ģ6`Tyt^Cɑ,iz홅gjOzhևjgꂧƍȢ@DM'Е9/knAAͩ<9.VŅ_d6H 3WOaNVJ!B#{T1oyj“Ud7wAS E>~8+N%)G l}IGVw{W%kf$#OG1ƄݍZjhSv4}mQ*8+Lhi*I2q b|2ЅYn!yѹQ"$ۣ("@kIf!Clkæ$Ȋ1JӶ^lW$@ Cn9j@Oa_DcbGv]hj!!_'Mذn2Q4z*eHBwH*Ȟe\ =4[i:^A/.{VNaP*sP &saOg#EF1; ؁v `y06bG$w:_ilP/tVzIs(P<vbG3NdSB!FEgD`T*L1daE>JK(Q`xFɤjQT5ij4A$&xH8jL:Rk,d|M9Ɍd j& iyYdd*Dm{)a&X,*cpH[Xc%b5I*QT^AM 0Ln9(qat* ")i;bP$F0(7E.~P2躄_F`% mb \D2"<CGy{xd06;"-xȪ&1Ie(?TFy]ȶ|" Z<I]0BH)C&P9jV,}”L vR%O /etX{}u(c Ҟ{d,KK>\(mF$0*%E;9 Y&5Hp:foA'>ȓG&T83HT#г2Gb13i/>J->%GC0ohҧA]P!VE]G#Ywr:=Vŗjy1LJWĨbR!+܅Ъ-CbGL:iz?#JTFQ߳kFhٳAZAC89OC?֬V4 VQ$hWDDʄ)d2ޣ`1%<({&a =K_-!L rdF(_pvDpR<L{M _}JLfq -uP $"$)tG }$$0ܜ jC z VIGx4p\g­rQO(Yؐ$>t}*%`1E#4մ[>k#ۙ ڧ 0 -K9t:6 *) Ҡ$bg$ea(%}hh4c򷩓KI<j8 @1.~"6tNl!jgTB5Cz<3mj!IPMa T?c!ۂ)A% Ԡ֏kEqisJ <ήD)dxE _\BPTi1~wm z,?C+r4DHGZyDpM寫!`7uZ UJ zSvWU\*טZn(\_G8M'.B'Ja52 ``m˯j.<0b9,)wՒ3B>fhA8UIGCR1H`J# 2+:bLH*xIp 1`d8Xj8I)"ͧx- R#E j4g4AZ'_xuJى!ABr%@fG+ R*)хw'IQ Al)m&T]L~$T?6"/c,,HiqZQIB\ L #R{IcUb[cm RL$wc=pKIPUnZTw9KVǔP\ ?q4K,\3S-bDZIC[L+'T! g dH WW鸹ZfU~Ep 'ObLavuK1dfv]LOXd=r uMY!Y,B-ΝHL ONUC珀n2dv4-3P8yG` TC.x/%%D$dr2%`uX=fD5jo?v?+`nN .:l*idȥ#jy.bP¨CI#ѻ#XFmg3nA+6࢘H}6u[87*CLIe#QW0ͤ~^N{0 XDI[)mC,vҰxΡoLJx.`UipemM ^^ <*l0>eٓs3D2`K7IQL&|L\݃ab.%7:C€2^mtO[m6W _Xpɸ:JA р!q R| F׌Z6i^$($ *Q7uך)f$*͒`{b<Nqp\Fqd{c"1t@*)sOtv5=),9i #YrQ8K)ЉAjQ ҏU$N=3(GOc2N7$J7I L*N D`zJP#\$ ȩhhCoT j>K4Ed6,)jAz9&bE k̲ 3Iޝ@ q&O 36$HC6<j @J8 !zWd3Fk"/XOo}~$3Dz&E oZ>e@[PK Acw+P4%bM/s_-kggݟk3Bȴ@T0fK ?I=O#B1͑u4Q;MZڕI"y DuH%)&KHӈ}!fL6 ˔1 эj:m Ơ ZҠȉRɕ,M M }|F;}sb @kBO#؍I@z>$FKy n$ R׵/p5yDDGERӠuCQ%X%mԾb^Ƞnb^.bı7b&EAR.[| @< $p?6V~/>R}T"HkN*`9Υ:4̱5؝@s'&w.@WVHB4:BZ#+?C5N/?|jb.Y;A7c#ƨAcB{RQA ȲhEuKpQ뿀2V"uݩh Z4>n{wP l0V\@BBa06~u*J.,M%4G RY'%,7PfT!AoXC Xğ }X;ͳPUl9yyIGjƵ4YXA?Cn^bwqx%[zv2_qpMzu)ng  FhvXJ Tf8$ +PI}@qJwBjsX4:Qœ;TRZ ^ 51G&B%e҄FN.B*veQ}Bg 2b(`BA"2y9gv$"Y n<1"CYle+>) Y^orjU*XZeAFHK?u"J$#e ھRHh=FF$mEC*,#lwGO\,,&ډb5ߚD<#RGRjEnȤv,58rԐlxU&`OjV HP&dRJw^+5Dj ѬU&zM}G ]b6Z1XX#db.!ͲRԵ+) PmIm(m2y zX2x _YcH f [ȁ 0Tel m1D10`B.vТ"EPbX ?e|hJ Dhn -+`V"QG "J ^ PD`d% [1!B Fn?f~( ` 9awh}NTSPIѩ;:V@A1i@;g*:txڕ6䡮S9io5pB߶_w{td^"M{H~߶hWg{ÿӜiձɔ RBbقz"\5HmZkMX%rr Mրt(V*D(]$a1& kX-\^!i*23 s Yj}50Z!+P{mpg`QP*A_w)J"- ͇8acIt[b@(CFM0< v9D&8MLdUuhSD B}{{ݘ|"S uAEڠn3&&b%/?rH-c!Ηo\ !ЧU &?9 D̥D`#JX!* RA)͐( ]q5_T,gä9hw~"qМu1Lc&)(NUOsl 6:!O5ۅ>^NiN[Ʌ$!A&F:m>jcʐJh?7+j 86C5=)ĪXlF'aRJs|UnL. n)~De0YwpBLs26#e2ܖ/# Q'։gVᅬ5UVNo!8+K*)ٰ751>¿-0931YATdn+ֵ"TӗoV,Hv TGpoH0>؎oBB-" ,UZ Ê}VPA"/eu)h!Y4DyT"@A]IdLa{ӱwҊOlN&I 젖@&ך΀X.t9')V@&@F.Ndb@Я$?H ӕi wV/JH-'@-v:h_s:h_ L qħ1,ӪRn<3=fBy5BK2{3#40X=K'aL6L[ ~b) ˡ(I0(3T@ӄ!"M.A~Q'|5͢Z _~߽͗ʤC>/'\ڣܽ]9D% #؄pFO|؅B*kj愛`T9pCކTR传&I,bۀd̓X)Ul Giq"&3BI%Hz)]cRF# 4AE AƲBR$L$xr 0 dtp 2et +SÊSiAytM2$"=S-pSH9-^H.1dJpSK&)@c52H N |ߛZ[7%'H9+>X\(#IXU$S TX!\KU2J&-c _Tg0IUW/OɢzI.8SK}TP@^DV ˂&t! 2$i/Do+ EAeNJAiŎWcRJjWuP.n50B-Q[QÉ ,%(/tfrSOvl531P~kw\e'"fa,|~(n 5nV3Bq%@@:-07r>Vx2D]3n>]dC(,Ĕn?Ńw!·AWF. ( m: L~}‡6!+ R, _Yt,?vINJCDљzD _G%N rܴ<5xzhdA f*A\ Ad@ EL$>'GKTJDjYT'z5L_} h63;!33IǺ*BGeqKUaX.r"H̆žSC8cG@Z@'ˍ$ xSX2I#gw2 Aws@Ge0$ -EoZ-қ^vMIt$#ܺ%}yN0U5ma~d/%W5VV(kٚ 䝷pTq9BKfEGn!sxst/j`ÿH&}2tܒ$vn? ;eѾMɻxqGn 4Ca Ԍ.^˪$*6>q ۗHG NCNF*1]Ju VW8ԣ Ӧ0ȋ 挡T,M;k3YI'5qJ2h~_HS1qo)@;l&KQe%W U<MHB+wްe[!4s>{^%/"uuۂLY}4G8{>)3ٮ567KDj56QlXl UR躧T2BD;V\}y23eX) (#A-.-{lo\}m'ڰ9=B*$'r c7~k:|ս`/FOmc[2"pDX ` 3al0쭐1T]4WǗ0/WP,f|:|4l9z$n_wu+E[-d gT] 35åB2xx@'EQ'ՓUO؆4wVٴ1#[>9AVJ-~-tBͲӪ8ށGpU "&{gVbSPrJX65%iю WD7mjm9mGVft_o p\ơn7N x^)Ǫiz:նP xGr64bb rd/%Rz`2IYӷ]olMd6!4kiTA+?i:P{C}x>LS. m㔂Lueի^l:6U3YIWlq^'LSzz3.|3/:-/c Aqˣ@?{j#PrđhZ D%ۢH{qu;KhG~X"FF F$Si&zS0Z'MQ}E%i>Ӧ,5҄Xs7Ο-c4j d!q,6vkx7jfĻfOIE7D;2ӫ 6,Ei3fM [5m) wSϩzF<9EQe5,bȻZ+Q"V5m&H T`< kL ,H~1p՝ |K ylSM#V("uԄ2^SsO9g6U٣w5Fu:tN$`y}Lo-?v[ ve4$=E)!n <Bȝ>Xް>yi[&fI6 ⛧VuZU6gтmz}ѽrДRnoj*kk_jZ.c3g&'}BiNʖ#BDH6]=js|}eJP;dz}hzVK ɵI3%d|wPzLFF+dZYي66sl+?Hܱ,X"e;ᨿW^`[)\$^ #BPw~OfC`~wx.|ݷf (;vn]T³obvs,|uH,hEv}0v);Ǯ 찤RwLLZ,OYv\)ѓo (7v5p ls Vd2a Pz#|wGz'wvd7ԲA+uhM(aE +Q2E!3#.2އ_?X\G%_m$o~!ik>6):%Ƶva cT';8S{HG7WjzQi#j':mrpNVA 5!Wn08SsB&vHr1_hU( Dx:IإukJϊ^狔M`\0{')S1qD Zh ,tޣt(O=1Z=2Ru(O9i{h]+2@|gˮ/&h~XX~uLH۱KFX|2ۊzhz*66w8@Q΃O O_1 Fw5jpt0n P1/o'a, i1tI,)j1?A+Pƿ\#T*/ZN8|_M<:{Mgݳ_'Ymo8]I_ //!*TӋN6HG c:݁UzS$ЅA1I_C f?c`0q<ȏ9~| b&f(~`dѴ:YYJck'&rf.˕Jq}L [;Un?CӇVZƷ5 ,IG[Qm{[jm6|4%t}rs'gF+EZ􎡴xd;3a CVskΜde;]J#yl"1&}ѿBITrh @{TGirԖ3?FA3c?S09Ǝ͖Z3h`S1L9Wn,}T@o=m ysm1j1vDZz 04 g# Qp"{HL18SܣNXkэhEPy?:eS::ex4 ^)9g,{ 얢U1( Jwy$λVBb?xI,0)E7aR L G3)_͠&H01MH^5׸|髾EQaҩ:JTHх UW_c{d>Gqx*#F[ GZV ;Q[;TfVHy-(.6E쮼hHIx&ֱL0R7a`.|v9 | #0ư"ie3ϊ$kĺEځ<,[!4p(Zzݤ̏h FUq{D80xy/A 0UVb7*斸A7@RLٟ#qe! = (C13,|٣rP &v,I^X m98Fa%wIaΩBzMB'M:B'0QI,:GYlj1mA#Y贫jF*mbvP),V_%34 rnYF|@Ȉ`WQnLB?Gkik/`w%P )*V0.{ҋZ&S|+r Ҋf 5Ԇԁ_q`^0|6nU `6͏Hmd;#ɂ $ w[݇uwW!8\x6/XidboT)]{7)=1y_|+g0V dTg&wtHT*AvǑsV 43=9#"Eοᵒ[<p5Vec2G!d}S>pЮz3Tvht 9)b^AsO#/cl6@Yνrt٭;x"P7vV^ԪR.I\̈5+4Pz##%6U41ߊ"I>w_Ix71hq 3GC〢ǯ]hNZC ,gnGh.j%RڻːPPeL,uѻ}(G~Ⱥ=P\?lAz3FBȿ6R[m|a=UGuu OnAy[P[NSZāN^|9Boΰ,;i%pW^N)^SsIE-eW2JhȢo |NbSS&[C8o7fDq3 H3 qvg橊gYHX_͢kDLzM b׺FZS),'Z浑**[i NY-k>9; :@)Gv}&ETXƛz` ~8pMuS,Ns0.;_.7klwG$}3QB&CJZпd"ڢ %dӖIw:Vu*3/rYxI6ͫbL9aYۜzMs?f.V[DX ue.PDs&My^fBU#@'8@Y*GA69L6 ֺ'xWWߪ:PYͲ+awiH 2EhW2lkZ4[dk#܈h"VU6玬c>cqr-TZlq5 1L<š| ,#{%ℌejRxI0 ,Isy3@4Ttog *=cӺ 奧0{tTeX@\uŘzkd.K$&ZUiyKZKC ,$+dr¹s4x:qRL湄=VMWJY(HN?cR0Zs^x'B{ FQFB}kJ"$@CMdߜo:&+M CCB{(\yCAVL>](űkʍ o9}bl]NXs{}:f&`HpEQ۩GCjtO6`+h誾׸wWZ9svXԲI" zˏ"ALOz %rz]NLCbPh,0Ȭ7:|?!`92QPEDe񮚡7<:* 9kkqxIպŋ%$oCT]W8*ͫUBBXqSA{* 0jvcgrSV4W; c.q1.kb[yi$R}0Ɍk CꭊSb !RgcuY}>_bo4{M󚅔6 &츎' ;n ͦ\Y f'5_,"^ Mohӑ$V )K~)JɄZWllG #Gd=5VM*<%_:rx+BqKI5Rur:qYsƎ6]ŨSEb-Up15>6X $Z䪮p#iH':ѰDs׿8: N1N bǂ%A%JdISqR'?>/?=cD4aZ)BSb1I5(F>󘰴*(S *Itb sQؗQ: 1}V{~kW9[eCZHO4.cvH`ɿ|T]paZYo6P]͑ _X6# GWu.} 4f%ptps"?8tږ0-;۠l=trcd3mz8fЇ/q4¬4r`Cۘ&}u SLdĥBVW?ڪǬ X4 c^c͚FmkkhI.77o9NC˦_ߠJ0,NDyG'-/כׄV 7F׋hȳ{".;G:e5ձq|Vk\{hJL塴A(~E/Rs[ؘݐ0hJFP!Jj\l峣looD4=NdF^,LMZcdpNcҫ;?& 3̴>Bz3I'H| fn|ɷΈ@wӥN( ;LXI=^RPhX!,*#1җ>*=` bN:$b yte-v)fNϔAC M,M3ny„p惴Dxa}ל@t/ <@$|2qET$[zj6*pvahY"%C*pnpb ֵr52B}rfRz ,sr|?xl'&1F~EXi!%4|6ՆѸ~eA\fKXxk_> Ë V!Ewʝ%ҠLeA<\//7p4"⺰sT6)ڨ8S0fȉ~@59+?b>B'[;:{I;-ZT"Od7̻HyƓp*.oj^Iew]g UD#&0dl4} fATע@ns6I`1_ȭTYhPB"VƬ3CK#t uiU6Տړ̙#ĿQ7,):^+Ld(sjG, lٰ#_*Ri7-+tp髻L$oGE?i(y!XrDr{#`6Wh=(J QBξrDI~wjU?RF{w}cb~o?N iHp_ߧ g LG>0Dd u8*e/@nVx6G<4WX=LUo+#uP:D8޼. s{$悵XDp:G;/ K,V}^Y~p0LrytPsLgPɪqsk`zqaד0 &?f|UoO.)ѐް^3R3Vy=W 'ƞA<BA%5Pa 13R #W,Eϑc)}ycJXZ88Ly(呠FV_T.f^k Ʈ}i#z9-}SXa͑2ycSx{+8UOe<;F1ÒMKj>OsKU!|F1-k@υKR i.e>%i|Թ6& 2DM# C%֒YQ" m0ҩmbѾH!Eq:߰%ΰ|\Bxiku":mT{uwXPIJ;2#L#1 gAfbN.ZFZi u Gd,1M$ cަ8 ϜqXTVu#๡inOe_Tz &Sx<SIT#)!,tTqd;.) 4:,hZCaϴNZ4fWٍ{>cܰxش/V'\< 둉B9lfOcr>$gZ4. S9Im0E/2zAx}[NJ:=F>cJ5"+A.WI1q5$omؐFzw!\=4л 5ztN9!+L KҒ9C ʶD y۰hyFMX5y4ʰoQ"FbO+] T, `qWr)\ 3޾f">l6=) ˵QW䕘4*M$u>lIT;rFQ䜛eؿV%(ţLȸOxP\Lbx85sLTO K8bΔ߈=s|YŐX+&SFۡ:5ń3ܡE&zoJ='0WtL<ɎS%ν'Z";W# z]bu%ͥтix2RsFѢ;T@:N|yųcJoȿP ^ d7&$lyJ 4« !>PJtsCep '/O~TTaEH<1$ G$V,l((s&+)V#iXχr8|R뼌cL;֖vѵ|Eeq5-tп|Lz(L#c %yrqo' gF6c:γ|zl|Mѕ޸&2<#7E"`kޖנ4 ɿJj%V{MF xПҕx-T57*+4*@EL1}P4wl&`$h_2YtJ7"? ,HZ0kR-A;!oFm @^5v/[v+q7N<\WVkפ5_S^ ;rSUU3 EJw=cfɯ@|C߁+ KiʤDGișb{1huU+˲rQ9ג\Y/B ClՍ"scj'<ƌ XY͟hAXM1ju`#wM!?XpXl}h٤\N!*|ODֺuM >YCY m$F֗_V/X//|/^g"L Ύo$( u+#T^R!7.{n*.NmOhű>;FĒ5)rQ2t(Ns~9owq>L,"; v0=@u|x)b$ i?єȈ릙aj4}`rs(w`:=TL/)㴥m?@ .PlQJ1\oIX~V-|LEy^-#GgwZg:ݙӫN0} sAqh8sQhSP6I801 EI{pն;6ޤQZ]D^J.-z219|j">fm귚h>rFeq[T2?<=²B }|hHZ$;:ac3w c`vǮ(!ZwoL\]L-|6%֬ ÎSRª+Mich3Ja㏵yoi_CcT"F-;} g䂜zN-F{ֹ*R<7Ԁ=Zu:l{Qϻd|jߤH.a'q}xq^mF_ K >`kKtH^ P_\q~i^y;4*g Ϟ)s\xxS5AO 3u`Rhš3*򠜆i9~om|;=jmn8fg )d1=ܶ=:bVFQ3PwNR'SIh^im.U]AYFު`xѣ6VVZRxS+wW$e-i^:K(ƅ6*; l~{8ɴ_ҍYck`gLr0?cn%?>cɘ+ɱ2(l\ zsbngвvc9 uQ߭IlO_Wo_D88z(tx=PE1p8 (=<2H [E(pҸ>_>8@U-(]@Bk5Yx A(ʚ)^ vA|»)Pz9M3 w&EauV>Oʕ9-fxI_r)ZV kB>OET0rwEx(JBgB7REvZj69Uo4_Qlo WsPp"'5!fUZ~&~]NUg5mpگD }G")aQW*8r3Ywh?G[l7; l{y|g}}-T18E>#7ΞijƋhtUoRaS^*Y`xƕjw{ YKY}-x/ae#RBƑk@\T?{ѫM]1eGf2ɍZP*cdd c-tIFLJnذC=$!"~Ns/UnKcު6jFV1ODnj! AIu3&uh;wQT ZU-9ʭi*Ol kϙlR5LV`;AfK $fb {ULIn䀓(4ta8}1) g4V: s̖o[ ێёB)=3EI}l=f^UFe7ӟWOG^;6lk2iKLvRo06$b?Iuolf8ot8?m./̜g${ǍgBܑXa`ݙi8 xo]#Jɀᵒ}T@ߊFdYUtQ+Xi41XQ)oxtvGZ5"H4:*-C_OfҭlV[z;Yoi1Ѕ[,|6*`5J&)U^W(.$aωg  @0s-H #"-}EW *d5OJ+0utq9*ɠ9҈}p')jPۧ]H }˒++ac`b֫ f>"lXNϕ xtz/8G9C> Nm %=̈́&E\U],H.LUZ%VW'$kA7œd\z<=F   ;6K'iLj4Sȫx1[**تzPYS%8COzᔢ,`x' +);./:Z^[(NB6kn `J[Mp0䜫`/C6X6 S&?w NJy7f.W!sPIaK(j"7Ī@SE`,&=p* 딍҇+m*50^ Yb]DGW 9ZeE'x󺏬^+t36 @v8-5""k{'[9]snqp{ D8z%\$EOAyƙ;r +3XvԌhv؝}a]I:+:?STJBkMuO.4 J T,7FjQwHP%Yxߢk J4 'RDZ/Z{TF0W,֋rff>\})$r\ VNC4T[zZbMį7wIs i!Y7I`NF痽=0% P!kA Ш +C0/ WLD5F|GV TV) .a^ 6.64>35PfTx*[q^s8ITrj(5klJR.:_y(r¦iKL]澓' {),KP}ըuV괹lgeS<tZ&˳lT BY03T~E7 ~V?V,R ^)^q~gp]@ ZJ)njUP }˕ i3fIXjQYG ד~s xic;jT MVkήjXMnXmX#BGR>3MK`Y}W">EiL6ʕI” dPS'WDDw-eIHxE 3N Ot\qx%ZpF*~d;D;dqT*#;n=0<& Dc{!3ZsI#gzϤ"y㗴P$#m;y.䨨Lz2 #Y&e8%=VzDo&^i9m3,ZvIöYeKWHhKJ ƒ'WS#|k f2 lm@_G)EQb%ʈጱg,::(dCuDEFxHoi|LjslXlfz-\-"p.6!a@9}0W_|&?$ pbG,DW] c33?(%k@g*ы'1ӓ82+n.dR#!xop>Z?C`oK%"Ŗ B) d)v*[#kp%[SZҪ]Ruyn2z%vԞd])#,8vZ{3R) h-LVkսwp葃WRmFcN5@#qӋn=*45Ӎ+ې"NQ݌olB8M#n lonLRlof{Te(!?E(;E ZT$Hm5Z5RhR}6t׀0 !FHk?Z1~{2re5PӐ ('$W^kH<1udS8~& ?._YOԫĞzl,q~no9: 0fGY=$R#.n1hlKRn7TΛu; ,% go$hzm܈[sEAM)/3,+EHU-#^NoHm&"l ()O24[+"%]iuEV\#C<ًh8=Y$5_e/r!0of #2`G8}/ʍh4QGޥ)36=ʢ0hh!Q6F@SKdA^҂DR $:rVA4O58'IM/Cybc|zHJvԁeIz-ZPq]aVR$(QS$цQ:R0u^=̓`x"'~"6SZCCL8V^7<䞤豭:-=AѨPoW9)'OՂ(jV@6[}@v (ixA?`#8zN[3Cm" M=`/mWvJIe My#}MyOq WgT\;łTiu 2L# qz0 I:"< 9\$A TG5l2SXS5nR!r: .; }qi8Cby}[8eݴMZLD.:LSN[~! w|jgVEM|d'SbϣYIT4y~>גgd!7LgEGj}+35[v@M3bܬO"I[sԿ,hNR =C6r%S̋Ŗ-V: Oza,"sikXD(aDbT’\TaxT?zqV"\pa]d>Wk[?[ϔ!fS1h9ᠣ$1/Hf1AT)#U{ b=djr_qW!"=ieT~U7L&$I L_+]T#3L5\kU7L??ZlҺڷfsgsK@eKwZ?]w;<%LoV*]'[U:}CZvwzE,YQf"ѝ8om]z,hGw2?Fc@L*fgU ^`:6 +꺡ՃԞc:l4<<ԫM.ig'A;S YBZԘ_Fa< xxX,(jXp<,-Hn+kJ͜Z#I5lb*bcM2ݯoTc.ƍ|Yw&u:g2Cx[1:!քѵ9*1+!DdEWG^,vgi,}ɄOONvjNP[ZoOuhڮVmI5;^SWQҳҪύVCnfkַZ[vk[iϻ]y[jv?N?NM9{~'X[n1}m WuUOjU-{|j &v~UT|N-5DcwO״ }Pԫaq麹N:gc!8c7NK߅7 + 9?exqLŁr:J*IՌ˦_u3{U"Op["AJ/\881BEsJ IysYTXk$pVԀ^,m5 Vu{N̉JT8]B ІiP^[ A~]pq_pFBk3|]mWJf`Gӵ@P-@|bոk(r:?g_+n\[nD}^zÝV`Ʌr_aĄoж6wռ=wW3#p)Qo_@1GVeAO)ݨzF4Jv;+LuJlsnfs߫q] E=*mնC o(d i)fg!Z$g0[`Vwq7͑:7u)77 uRXb-=UHtm5_̵ f/'*sqR96붹[} +znttB{YS=ۅ+%atz!]-$Fr%dp(bkQz5~Q(ol6_hxq'}\O7DU=F|c` 77os|9 b^ny6*F*eW ,sP3tAת+ęDu6$ pGzW71 /i.oWf/_*nn;s?Wic]I?g}^iJ2V 2-Iz )9=W5iCDԼ :?3j#$| xo#" C1FJU\Wwe“1):Ŵ<3h"Z:@ndV&kqT3I{nP>STM-8ڏq:OJX0X]/{!.t>W';ԗX $hTӌ\cvYRrK!2uWOs%\cm)WTh5bFPtޚݧ5+qډG!6_%Kc>@6v R٬!eYtYVWщR?S֚.bF[&(}H=JJvgjU4ĵ*MVuMvMcvGv\XxXm5oS9@aᚪYhSm*f%Sz[KZTl6\Y:T"#m0_$SۉtbQe61#Ot ǁ%0ldq4HU &hi~V Q,]}lUM0)zGŲ^EI7Bwrw~Zh|jv4J_b-)O ! к+t$qL6 ԄCUׁR16nadIP!;w9rd%37:zG} 1L⼪Q i':L@cgxTyp|SՕUf:RR /'/0`jP4i 2|&2|rP3s6i^ %'"e Bn_%e;&-CHyKb r73[\Kk*y?AE`tR (+s)!$1,U|iN;bdAO$=CsDәqgij+h 9u摨)mbUekM$فu^ÖNR8bC2W$?Ou!kOͷk/}9e ~'zq#.c`уn`o?Z1v>ý~-B4ӓ^]Zf#=hkLK *>:{I4\i w:O#6129t ϣMIZWN˰Vb_VFdeuZxf=3Og=J3%7a)7h9ݐ s1ZڥjmPXP|L,L!$ΜT;;'3Ws ٬'3׬z뿢/R ]~p(p? w 5*ć^:_, ;U`R@`vߌv[vWEX9!-A E!=W4FdDsKWk/T&}jXh}c W%٦0/16M9q3wŌ?ebZ3~r0d%-r<ht$RkV_/:"b>ÐbM'SW+=(Pb* vC-?lE5i]@9Da`C=&.S/IX4Nۄ+Iv])C'H$V\vaXfɜ>o(]eČ 1^ _w_|4Q4H%]}:mBzVDJO/ ֨MTR1Ewrcj]64HdP|bOZ\+>R -V.Zَ$Ecgs[L8,zdñrN=*`X65iH&ͱfTi "a".A+wV(9&%5G WE"v3fd =9nEH O+>Tz~殔HS%b[08//m0G`= iqAi+%pOCjV qk8w. 1'aG}LYοp^CMWX2J%L]$mWO3GuTf1v\#sk#ã/gFhrm yp kq4*v:cʥT4u>=%ma4:}x;AVe/2HĊR N=RHRtqO&Xl^5#(-z6Ym A1s.7py{6kZ׽*3ଳI7 ~`p]wh樬'c5^r|>贉j@Vc+}ct>#JL4Ԩ3x❟腝O4Y@T`[Ln|#jy&.f]2G$tHް_5~m[hn&ߴfYu01mĮ4ϥ&P{$ ^7k, t#V  >` ܗnS>l8]%#٬6{NH{%"OmVgPy>{Q&EF8,n=\c pηY4ųˣ6] CZCɀݳ~ ('yu:P2.^[pk]UF(";$V[|^|oeqCqCt+4䒛Wf]^2o/]w`AQ 7>~pm 6EVܣkwK5֬v$_QexיŔ;@FM 0Ā*(([$g4&Mܨ֐ w}%™û)۲Cſgmn61NQ3r$JRh1 RB; ^S;˚o\L^[y"pH%|-1S]v޷?] :}r1sy=$oh^|<N:xsy1^Gw?X'ѷj*IAAR8xPRY,T>ʯ^qtA'8EЗ~ytO% ]i)C}ot?6>”fVV/v;H({w_'@߿sd6C|t5ó{h2S]CQ7>^=LHD me2etcNWDyO8rI/&گ@] jPm=ыEݜo6<<%"KUJ Hl$ءl|u^-^礰b ID|p[ۡvwn-M0H,! -E49>ݰ:bFCyn' LsY;ɚ(!pL-җ?yTQP;hgLjq$!TDWV}9_i\] E{c81`b*J5{W. _TPC\F$f%ew$eG_^s8#0-fAB .? (7R*[k] R,AVH-;Bw[T'^_O+|t ƹ qvب7juolBO^<hV)s0G]!*Ó˾ >FF1ڎ)NP5h& 6.~zS G^t1I)/+L:,3|у9\طH]t;'d!~\Zר.>M7w #SEZ UcE6+O,IrgQk!uw"搹].GVa Qk9tńDV-\_?aRT>Fc#Cd'oq4=r!suU{ mλÂnŭVv*6w_F(o= ??wcpEgKy0crh&u uZC9f q|H˒49Rh3ۺQ}qfbp}Ka(+ l!Qz£Q'M-^^y C8.?_s4C%!afE(N#L-9Yt܇]|z;JmWArh _G&zZqȉ]p 4}Տ?ZQ}˔le{sEYk9(ֶύD9Obu!KQ=|?xSs:(\oCV%5ITe XtC9w=8"?)# Xfp} ̋u]`3Or2/AKr; ڭ)Sf1ŷ6N$7xy >S@E| Pم֛> dbѰ"_Zyb Tc]܍d|(% 6 X0/=‚똼(Érw1,:`c+&(ˑWR>l6E OG9l^1>5o^Ck߆ŋ6 SA4 Q[ JdH(O= lfߒ?{$`I};nrv<}?3,ig~a[CiaL&!fXS+^BD +G@*ۨ唭(Es`FVyy%TsP3Z=ܥ(=mq ܨĠy >!*zۃuzǏgwC +ŀwN+_+~`]٠`mOÊ&XIE>eb]WopeE1)B`OAJx%źt{Y EeySÞw C"!?2~~lT>>|X¯IW:o8c 8l4NéP0}zo35P,:Ù 2nH+CҀ82Ullm?P53 q~UIbgW89E/p41=p$ &TyMn0w1t=&HA˺юgBSO^u)K:'^8i\'Rp bj?}|`)!T%5ʞ3J?N5F>wއN`7;,S1pɮ1x Վ :LD8DǿK. ?r/q S[V:ǝDdLvK0ĤsʬzV j8ZºQ y poC[O. nnޠ sC} I hK@JDeؐluF6\@+#l.@ kJP%V:xѭG vZr°yb y3ۣ83|Zᐺ#q\nhR[A9x7 oQN#8nɋHdhJ ZK)@1>Lx&/9pe7 npݣ}Ha,ȅ^*c`ѨMP{dxu"=ԝ_1*,ɠTW}~<:ߦO@Y"\k}:-@)+rNZSilM-_PXKAe9똶wZ_ r6O3Q?|gNW5Qwbs0RD8oGc0RS_}X{+:nCGݵE8xx"nL Ŝ 7:ORq@S};R3l` Dz?" XF^53Wt5K*t>#Ryrڝ{O3i;3?q' dhM^ G!y"j"Xb#K@Et%N{WIr Yx7 a1}C4ÕB4F,Y -c'x1(^Y]AzdN)3B&Y@D k(rBWώ3NkOWM҄}*%'u8zg1ߖ4ӣBqFkϵ w3İLF Z:#mV݊"s [\R[fxp޵gQg1D1F41B6ZORx*b_΢ϓXNC 8:>sJ.DKhAԂJvP>8XDPoyvE?n;DjBKⱽ ]b=P!B؆X1,:Vn*8իl"0w0N DK1YZT*%1CL"c[QJZdY/WNڅZwBޕ dȍt#‡ޠpn=shvQ ee+K4e8*qegGw:)D]Err| k@ QL2Ba4.5/C+% nR@A}o˯,FKUcR:q0PgVKRN#:\–>V:_z!6g 'Nv+uWm[NewZs^C{]#KmԹ 91roCl~Brd׉ufU9'UGXm%Ϸǩ_Tlٗb3ВsiݔAB޶] Sk+2F63PShx߿H-L *EA#ZݓVC Z.hS4p2oO&]e 0HGK}PoR?mㄛ>w-}+O  gTm kJ81 'B0xv:ʟ`J ti.bE4xy^QB=Qpsq y<#f8A K<ڪpycFab[X>x7V?&_NH/$0إ}cƥD6IDE>x-^8/~uUY}lZC0(d93gaP  =>̷~ZB+H#=^[/,b̜B?L;+?hLwPUAu\ xݶ*@U"~ا{.\$fua+,\  "d, /o Ho K{:b`!W3<.:QF]`p1wüMozqmOcǼ.NRļ{~\I™m{˟bY|q/@̗7o8o^ثcJ{ehiķԾR*}{kdz)ϰr %L,ۥ ;OJ)MozD<t`>h?X=zd 'GH|$a(| vaKD<-"1b?}E.{ָaq(.Qֹ9YS )Cit W}A' JJ4 $ \ _o5̛T S[U8y! 8F6ٿ"E 5wjA+Y<)>{9Y›`.HI 1uL!vjT kሢTmvP,{R9/uw!'TC:vΰʈUA>z[1^RWtT 9k E9=Igg@f>vvcUA ĝyei"PT!"j/x'uy NUzC)RAa#w`:EBIq+%i;/쒃$l <_P:W-\(6|>|_zY߽Y|{A]Unz 6R gHqV*5ٿ$1/ nv}KM(⯴.e]M QE.@Tb)=aqDK;:w-({90c$,z P9Zf[dD/G8XF_Kn] 1M猟5g sz1L %Vm zX$p| -O*` фb8b8N+ ?yg[$* BP" NL)`fm~4v)>fXɼXa\ qOh@TߢP-mER=9 sd~%vHʦq%R iǵ2VWpK[Y7LmRubV ;q굎 mJ|m8iύzhe(H{GO":^ WU"pgoA=;Rdl=؉rhu4qwlE? =P8۲ENؓ0^*%B".Q4k-@!MJ#̓2V N؝yOޮ9SER[}H߳,of=%oz[ƸGϵB4-+waȦw\+Uw_>]^SSۇ#f#zJs:녮gaLW7M Q!#s!Ѻjo@WpC% 1gY!$eB$ <̗=O_ÆA~ew5, j/. CJȪ$ 6se~{9(`EJ xJwʩoevf跺G ޠpDZv1A.ae: )%ۛ6 -=A4}q\k+Qk+RAo \jI-M|*qXQxAtkuLǐMF0F5@v} =ډ#Y(>sʼnҳ3bDp,>9bCo2n(VHyM7I3[ϺɓGn[]l`fVcBY2xVk5x.I8 TD5օQ<Z;tԁgZS*X:̨gBI\ϫ bm.N(m>W,G1QW^*Pc3C%sK@[nn-Dw- XjVF@FZFxl){jxLTkҰWpol|B/˧cg.Q~N( Cx=SԐUJBgn8 $)ο/w:ӯUN-ߠҼ«R Hn%CM9<7!W}ҍ`h\ Ѵ(EQpT>bkz,Ly3s֯UX@ hŝeR#}~16j?W ԕy9ᒻ 0QI†i>$" zes)~|ҮbŚTgy2܁  ҅)ShjMnp9 u9`9'ut&\L*ֳ!KxAM*D'YK)緁2d)9GHi_uf7c,Q8_G'q"-H_ lbL?Q˼>wn$~wFf!XXL6t/پ~%Tք.U`- ʕ]O[ Z50T  Oyx,qkvzv9|?(pzy GgEy S{f~Rp󃜧G7N~)BڪmΤjzg,̫duiпT"!ZƆig^Ëg(D7-7ɥl-#%?Wj 1 5^ a[rN&ٷ^ZtBY 6 W ,_O%0џ= oKY4D _,!j mtkzrmJtr7I>O{)}t?׸WQN(XDźhhq)3,Kpկsmif+.Зn@ Vm@'ܦpN'B' K%K6\!?/F$8N~Ar/ˋؠVJ`0|1h4\F~tKE_b/4iċCl$WЂ_ ~r:7T,$ZQa Mk; [W'(HI+#wbZbtqe!/JZ= ½7 VsU8'NGIP;l>j?X#)"Mٟ>Fz|~3ӷ~]|˫;ZQ2K?X@O7->tҶ_b1XD$ ~+A U /. :]- vpSl3~WkB l=Tz^٭t})ۅkUt/N/w yK9/>y3 v"b3T|cCRp+in+!jgkz GFVP'[eVJ\a:{xCUs.$ )Q[fonTVL,7 *d~0QeuKQ.Tܪ>{5(|k #6fWWsow'Y{YInުfTBU)L/޶V_SJʮ/!zީ4g mԾnIIt dXkEΠM͹τЮv۳K2||Eqh}q%2m0hmr XEjHzAL)u?vցD3ER[UQWh6*؆j:aI& 2$zy>v~8Nd(N1jfSa0u'"2[\Q'.hkh\K/9߻s!x8L ˭+P|M=llL[4͝WWmХKUqNvk_RGcV&cH/`NDMT `]KU]d[$S$8"B.%Dtw, TadW­ݝd$[{d̖xZo;_`LZ}+{&Jr w4_/$#}PQH39QtނʼnʼnFu,Zeb_A\3kPg !hҊR[̝f71DOW-kiM"&b\J.L4}-KH*Jd>௸wcDU\[sWClV!!@MJT 1l!Ɩg6<ހY+)T6M*X "Mm9u; Y1O'nv n% $c_$UKB#O WZ%(. <-!$,XT,~.)If] QfZ]KF IMJbZ#˰&M`"֯B{r `Gl?Vco繈Lß1%yQfͭ)W}܄*88D E 5v g)mطlffWĘ3~|E@u3{;YR~gF"6;a,l,&c񖹎 ]n&brNs֖{V~6'ED'@o@}E:P{)\!{jҭѝ,_^/ZZ}#RPAF\ _6^^4wGcGMKt_3[p 2顥3n`u`zWv>%2kvaVаTأvPw™ 2`y&Sh2C[ "P: Y٢R7rEwܷWT$J|EU|KU_~k;4ni5d19)=L l˘M6Cyŋr"VZ"p{:m)4sAF"* C|{ws+&TgƅJ-[p0)&Ffs6]q_bت6_Pҽ+W(퓸ۛ598h,V*lց'q-d +/cE)vp$MڇvN.3 qOڌ4|[s \ڞR=b;^hC1L>o,FT;-&3 (=lv2IQW_1$6J|{9Z䉓O B m4mO41X\(lN&E7k@pӨ5ȹk׸mPUÑ*rGGr;Q sdu6MP]|-Ż]-hE}Ydhy ZPC?[Ö1ZcWV]ZJN7e'R|~u}}-^x%JriQ77JD òP=FFրCe2(vaKX,jc8 BsިP[cUL{rx8`޿ QYN )k2~;/2Q`8ab3&QU>&7WQ_f9B:sF7WKH \8\mz`zMk"zRcckē|34ާ- ]`0=s4,1:t_Jdk5$' xkݣuѣ0UU:*X ha6nh8Owcٛ/آuP=0^/}_ \Iڇ8+uӿw;hu<\;2=H dfք ϻD1o 0Mewmu+0 *|YNacbcoU*f )C-[xsVf72x/3[17Orޔb _0[S->{ @ЬGO ׇԀrA1Y;T}u1+Y Ra\J J| tU_!ORaz_7.JJ䩪u>:Oǯ0FHǯ`/yƆͮ⿈QC!afל`SaHnoޛh 'yc &}Pcioyu(-ѫfX3|Gi{ʥcZk)7wn>xߝ`oF2wPДY̡~#Tz3SuNhEyr(^ҼyҰа۟hΰмE ?0xo̊XG.q[c1 Ĺ}Nƥșp1oZpNܠwߓpݕ=>s}BSw:gr4pɌD<@q0<<}>c*^F9L_G(;x۰Ճo ۣ :Q$qt`q;ҎG4Buou;5N3!9~-j"Kof.ݘzwP)w4a|W <+lBܐXu%1 F~w@ o;m )@"܆! 8It'VO68T%6)ʛu}QR{:$֣$L`7;R s*T[4͝ ;nxq|}Z TߣdaO2ʍʄ&vSkԵqKlJqĭ+)6Ui: xoޤ.岀zOiFD *v<>cV^z{0coEУh(|ܨjF^$.{7%޲Ev%&}C4ȑ<1L˝՞VY p"byD_ :CEc=̣00$c0kkY=K2=uZP0UyQqr7kؐ=y UUhJE\ּLC{  HEtZϞlaM4>OҤR%%spmFU<,׉ &p ?`jAjldZ Z=g ounnnޚ'p*'ˀx5Ecx]JzB=@} X+Mˏk4΁=vAژ^Zn~>:Zơyg7gE ܎IV#qMꕻTȫ~>cgis{=5Ջ`^jo[r LM܏mZT:خV8I˸R`_޺w8pMﶷܿEϖV@|oZ.E.ÌNe7 ~M4]Tgu8wkn=`szt +O)JC/Pd9B.B#+ݧ9)ZX>mQ۳[@e>/{ka]$fU'tdm85#UjfF[hct\$FtoE{~шX9wxMVnRm=lWK2ExUy3 4{kW96L06COJW лkNл+jSPOtJ/׏h[w&3z̟Z=}f6R{HVYraJf=0n'Y6[IP]nw 0[ڃ3J#MNVU4ЎT"Xa¿2@#݆fSZ8ʋ_.ųvPt2tCt,I?]UFd.j@to {oMr-쮩Ϋu jkukMI~vVy3L޵JYg^u24-)BSyE |yNG -_#pTO0EA>]}8C56yጩbY@[>hIv6יH5 |ľ> FPkE2}JD[;)R g+$%<,7.A SqmZg͂.Yyʊ|fQL&fš|?d\kڗژNks''zp}x*pfeى|x3<\ފޝ>,H0sBŅ.$'6_zڧ.SJ畖z}{bYXs4 ūQ?RZȁe A 4˘֘g> 2 ?LWpf/z5=K4I]`wM/CW^&eՄC3Ccc_V{s&t2ۿ [&g%yXɟTtToN_:#%WAnt3tfIděEQ{/i=ggu{sx])"G7}8yڿQ7^T 'xt-W<#{vƈ]ֽ 5%p<];:z36 UN"OBz138פy9GOSF?cWφe`>qk zNNhp9^s|?}Agji?I}}2[<ſu]b"f\.cFIEg\+Cl #@k) Z"+TYnݚߡ4pXށ hT@H2=.-/r6ٷOlQ)CkL<&&9*Kol{B' סDIEͷ0a[;lKJ~\m5www?oum~Bu^h[7lY\ =L$r2(ync·D?_݁Z}{nyMggWEoؽ8/gW#v5RylͿJHj/\p 7Ϟ/p= ?` 34"#NW-i$Fِm`0I%q.I_9mDFft;йF)VǛ*;Q+`;߮tOaZ@ntUtWXD6>2 ֣8,QTMuӹdoJ8}ZPL'9cR4Ye;3hd[dEn9n - \ateq ?8<8[>rpU<E[B>+EV{C~LnMBGtYN/폃a?6?dMQdϻ8.H.lGm#0C)4MDmJ,ݷ}ѕ]'}k4@7 sE@I<[u.?lo_l.}${ttEfg+j<@^ҮTw/[q3&6#™3ܛ`f"=n #^Ξk/{yz9s$|jϿ9^RlIW!ѩ_DOz$Zy= .~dtU]C0lML"NCm:ñD j᝞7JD4xm JxNӸVR H|DRxXUÌRc/|"q F̘vӾw?٩T5s_ o86sl:S ꀬk~ͅSmOr^%&еnH҆ćy(f"9ج鎾?㨻a7:v-nfP}ʪ}rl lS{LiYM[6k}Y' ~J* $wJ֮nv))g'ĀXqEc%PLS}9 ϰiV5 N"k!GSڲVUns1~ 1f4@{ ETI=є$M3{[[-o50ڟִ$6RJħP̀mNVr!xy1MM4}E3K5DA@({O3b{O3xqՀDQ Yaj)ÂZ1ʓ bU=GeaT 41;MVӲY:L#Lf>Q! ^mpFv&0ZmC<"|r9xŹ__Oo`9~/۝PWl)3!TG]Az#! lS=D~`Hqy0=jg^̞"vi8@V%lR rmHcۅz`-B2ҝ-3?B(3*(eΒ Z]&{aW%V۾WTmksZX0Bb[=*-3+Am[A$I {&WBR}YNqtGŻ}teF*[U5@.F-'% SF<"?XUc[&5)ն,dl$8{eeo]̑嘏mCHob-E|x -]އ4fl5-L{i;6eNl7vDL9+y܍q 'rl9'pveQ[=;5A;ߥVn--<hV5D4n ?P(hjy:5(oBFqc#Q~0jE_ J0Y"Ѳ9NŴ-;tD134,N*"< jΖlMcLH38PTiZ'Ig,.05?Cu]{3]&Ofwu@WmxzN!`<R0?gҿ4g߬'Wj4sG(#RvΎAbpRLɳ1ix4{em3\Jŋ }8 9ߺfYApy*b3 Viґ]e/xYӝ+_37?3涉F&@5d&b nRd?e:ZV4#4fܴI{&M>XRXUskY-C&+敝bACr'w A@&b SLT-%rm 0Fa-!l6`=g37^op6&k-35Gi QܵRwH/$+s'qB;dqϒ1i"r3G\69A!cH*P&ql Ze`)A&AdёclɑՊ=ҩ}_3ߋ{ -̾ dS`*|,/prv"%Tyw+GBWꃢWFuJNuӖGhnه`oEu kAu_>Hmwߪ*UHUϹPKD(߉Zk>$XF%O#*֥,\C۠G 3fO~7!y7 eKh9[@EVx C}+}e3٬+e1`*66mK\cq8lu!eHȳ֛ec5E' }&~4jά|ϝ5*kZ0i(\̼%}Frg\V)(\3TcQHh݀z>Rz ^QOU#9Go]%8Vk6lx ~fN/1G >"mKF03.ZҲ[K8iՖi5JE4ڡ}ȁCCHZ{ĜZ8R| LPc1HnjlmG4M͆z'lRR?JAWaD63ImVI.r}NLd6^8/+-›(x(^*k(Zt1kR'T,ܪceϻ|t1A-;tqH8ۜ&Lü1SІe\.\s+ λG^%ztq%'tkF A{I Zm>/ Z9('<>/scg<5o$T%hJQ5* =~mەMF/ `ݡ k0xxYo\ :tLNuSVa>; d.K£MinRn]=%\:8!l x.PKA+8ekr$Nkj^t[i{< !  ՝nZB U9>dw4T0]yrv]E2f yE+D1̌==ojlbZMtƕ,d{iJX%IpfH~i HUcW *xsB t$M8Mb*#$J03t. 0vgL^Q{uǮ6r9oE7 {<3|~P\ݏ=93-ӝ\j; Vgj q>]+6|A-Kb` vZbnDȑGȘt INI)LK}wsôt^*"v2y*;fsJ1]|d蝧Kvw?Mym-"~vi\iom汓I^T>2TH ޱ']jL|RX*D逽8igo"؅EsTuҪÆLW-NLlyKzw-'< _h9kjR*VU%d\b۪wJtŕθLC4zG g+ǀ?_6~)EJ8IJ%3)"LR2 "PYsy/>w79OkSĎlwR"<~keN}yBjRNHcDBfʫ]٭mkoda57θwLN!|5&5֬12+pk!7%D.Nҥ]4$PfJ*9ZY35Ae 3~xrN o[ǒ[,2('/PFbbM) *?dװ≺q"p.2#{#yTUei֡*JWGhP[>Ő%^;Lzd!|Mw/.D;KSK߳K8_~7*_#6!V)9j% $X5FfLө1h UVRZ8 eKg߿ T lOY\o!G'lg?V3]* ElFjfO#|֗$3Mo#qɪO1] +%tgf̮[M5?{|\Qޘr8f&%vǐiç~׼TEX>Ni d4q~YTuF7[o[P898<ʔ>Gq9Qx?:o0m>*&А\"@EY%;b4^0eo!;~/mܗ)ϋʶe.)|Y\c6n,B!2q$+_ނ9fȰ΂$B2 鬭 VWp?Ѿ.slzrP >60џs֖KyQ7'+ᵷg|ӔGѧ1s~W+9"ӭt9pFe JKKJZfVZS(|{i "/ځԗ&?l*X00"a ah!F5ӦMK{\kV:䯀5سa!=[]&n\aFY<9+&Mfd/(4;:/.YYmSExSM\f*l 9H~Q]Jn1h+ܿ/1 -U~WƸ뎐4kòsG /3Rbd {`6."ԵNBXmCs ՀYJz-qyh$jLGך>ip>&|JH˰rd#CJ`P4b1DÕ#SA`] ɼTfPkg{Fe3 $} [~5f}V7*[lڐM>jgS%NWJSѪLȹԯ8kEGO12}8TF[UFG۪Lu>?znnz<1Rg 8O*YPWngV |3aK/+V.'αbv)s]6r%Vn]*ϋrXIR>>K\;TU3.[ +ԄW4Ȫ%"U`︼P^AԲH qU]1(C7 #nV= _ToFnO{t>QjG<:+s;uv[<ַj矩x!ǙIH0][,&$u(>eMEy/,G"f7s+%˹[hRc+Ҵ{` %f!8~JQn##pZ0t1xě7)*Fh~4v=u4߷P:[ڛѤTQ ZSubK/uUmvm ^4ˢ\ >ϪefR=m,K`kŁ&rUYC_vUzO[,=OC{t6͐e퀦: 67rշGW!v40ܭuDIg7Ϝm؁RFW͵KN;\)^VtNE)YNroػZwgp[$]eAفZ&7}EKT'6,|'tX.4_/B3 @S|E+`f8p}nmSiNԛܥ7Kҽj۳z }#! F t#!Ä޴MM.'̉-nlL(MG"kҪw m=Qo')=z.;h݄jysTrM a ':f(pݫcY?ˁ|ܻ򮕃e4vaMQyMPu],6Vg!dc2Z|ih9?9:wAWM*lU-Oqe$z|JaT3wKVmJr{+- ,"Py1莚(#_pVVʋVVz4T;"^P?5+֠L#s@=e}su_dyy*/y˃E7h,WMgLj71.<l:٥Mm1V4vNWBXж&SeZ^7rcsO=AEhTdvnj/[E+ҳ]IpcH^fJhCS./ׯXxxB'VlF#pmݱGТ-q2<\4nte xW{?sYLȢ8i&ߐ|X^' &e*qk/#\KEVRjc= ]4E#FܺKR *4v8MY6??;/xACGo؝/q;[GXKKKiV0׿f{c"`US!o=[g_1Q5(u^#i,wJ44c_I9 *%U쵼ݪ}~v]=vۦ\4@uߕ;9dS֟Gua&)р`DO>hݩF[J_T êReݘO$ڛOe]Бy>PY]9[`!Or/%ȯslB&rJrxQ2SGM| B#|QkfsV>&jΦ>yh7 G P+Zc(V󂵛11l2{QzFZ$wĄņUv(A4P3wţVȎzLMGdUjSNYUOVڔyp  sχ:@V1jknb(4!M.| {}YZ*mk ]AqJkDJ(N^4Bi.=PDJWV>|J-)Ԋ:n_ Q%A)mUXUsfa{3)J)W3oߌ۪ j;J79 SOGVEhE3O$'lr? Nrđ͚p3gZ~r_EJe#;iWx^mp鍣}hP`Zoj䛐ƛĒ\:X"˜Lb' vM?75TSUOKJn)޻9_^Ɔ">pxD['BS,XzJE$w. {'㾪_FSы_4( b?BW{[u-lt ǏP(nCDeP\-J8޹'j nѫ ,Ƣ\/r.?nS+ R~Z2*BIB*&zHPc "wi6Nn* ,3>{zu2_>-*h*v9VGkHx0ӷkNzِ)f7 gWRK3Pytmۊq,|?ZyyȧTbx&v=FFvޖD3%#lp2 Fymk(c=qIbj,L9x]#1ԙ(Ŀ%aqLwXy{UsJrkY|fUKѡNyt53P! XwCڨzߥ,iMm@RtͦVq.d no9pr8 l(xao=R.FZv@lLraϖv*9&C:ܑ@G*I*l JTr/#SԑaGb#fpFQk/ٱ#۬<ܢt49&5c*#_@KVO&g$~א2n#CDd?~P[>_n:;>Mr8[y{j{;.HnvR{0;ҦOz歎w!zEߙ!lz MrHמՇP<6]8sђ%RM(59dK Jrsl= +'Zjv-SG-_57Y]{B*DetjPA[ˮM즥8,,\Vk#`]85 ]iZ,ڧ`\7sOϟ#cPm`Y|{x8dΪFZCtzhӽkTjY:/Ef 02F4qDݢy`(uB~":SdٯjjbiJ/ +nօԣyPd"4JZ M19gZwaf hk6z y<_.υF.(I+:!k4â#>),1aywm:\zH$C-ź1WǦCki+q/h:!6yDͳ09' uDB".l,o}'Qrqɜa-:>>ּ̳cXku5t!X^<0ǧJj;nvAJs}~c]~b]Եa_Pb-D|^mCI.W_]W m/మ |W,)J: iP,89DfVߤ8ʩ_Sxc&>栽Q ʏ%Ui(@hv (^U'c !#H1OQGaן̵1>HyӲu&WwD13ւN2Ѥ7GRQGGOl#[> ߮ͭ7״=Iն}R?' 5 v}hmԸ;(sq^d5Cևɴ3x#ѿ!{| mw]]^k?W"QyJ$ȼ g[<"R\|ؾޗTJ֛ WrZ}I"pSTtX H;lIޒQtQVh;ض.\  ]& )f:Py[;r0۲\MUj7@Xׁ8U.]*[7Ƚj'cEʇ\;c R|롪+qQ H}'ň}QB/tlJiy7M[7?9xx =q%z [n@.h%E6-N Ax@cLV[w۰3B""/^a.Ό(AEuu ~vr{AĄ*mJa3@9W<4Md1 \;%S۪+jX6,mWRoפ.ݦ'M=oU׵^nW׵~o7q YSj=]7ycOǍUZ~K$ܪ*>Úm_.ԩ-yrU8}S5lq15ZUyaAi^ސhQ9-K'WuK';m+X=gݦlʟoJh0zG/`yX`c4&zD$uJ6h씝*Q+LY7(Sj\$ג0F8k J4Ewbm1vfN[,-neqh^*mxgaؒD{ \%/նjۛJϙ^I֐nNoa;v=&cy`FqH&<5cf<˽$KSx`m`  GM+r&%6qTB5Qpԉ~ :%XaL G.Uʏƥ^ַ2CWjt_77Ө<NN@/+=2Y + q@VC/~ im|X %ٳ\-eH>jcD3Ek,[2X>cYy`kI{- xgFb4\U.銣f_[;DvKKr]{)ʻĚHSj+ukY.oiv~l]$)"V>!JG!j{r:p4rT(Y:4ujfEz6󷥚-9N?ѱ+g) babIZ+ _4C*PS9fg4of|Wc4kAEcM:V(HIJNգzחS e$iG/ V#)Czh(ElOg`0`PnXkySw x8Oo'0:N^E#⥌$:HVSQ>{Yy'ˈ|~壧vi\VwnDOjueI!|g-zwW+o=mh:ƥ7Nm88>Ln"/]& m]DX??9<:Q)[}Y.gF"yk)_bihڸ5coFxY;MߘgB[uaLbYH: 6Iu#@zO`vw{6W^ RۇZ+hul7}fŬ-yAk-4%/D>3W2r"4D zըKk]VL݇ ?, owAZXNP* ,쪍-2R&4WmeZ=2YAlX0hp<9bk=;:f_bi8r$X:,"'I9$ѽ#OM3٭;(lqy/kzky2?cW s|a+O.'eQ_\fzyiG]4W2 OSTW&>bA*EF΃ I.W+Q-.+maxVGQʃ7v'smer{w獠u+o[VS}Ñ(`MhL)+WN9KdQ?qpD@yB]7 MhhI/\({-"ۦ N#,2hzE4B^P!j]D:%Lv>MNXGiEo+ |e۫ʈ"".JE+mdS`\8UXen|WCqp[ %)U 0ZGCEorNkʪ KQ/y񗷜N,D 4/N[@їTp<| A],xHQLvJQiN-ZDɨrAvB}(/.>3įȣD Ԓno5!ʏp}Win)?aič ]}He`_aMc'x`><9kQs}d ϥI&y8hq!$uaߣrU=,5OК $:LBqf"giU }k֡7 {X")"3{W+\.K^+dhc6}HL vdkkö>yyKd"ǩUJ4.j-<ð}"5J mY5ZM]\kqˡ05ZSdaYMIޟ=p F8UJs)|k28]lw 6/>M1=UxQLZ5-~4߽<:'}A6JTxՔ>jiZ-Ž]IG(& 6',(q,qBkչEűC,cۃ`Q8;ny܂9˖,<^H3zK=TMOLLsVmU"C"2h9iϊ2bzf_.d\f Nˢ3]5)ly*褿P#igqڴ fyT5N M$쭂ga)@*Ԙ<1nHCLŜ0U 0`MywPH (?)czg?B\ă:E%hй9KR{ T>J=|4M.MN\{i˟ZQԄg]DW1_:|$ D߬ -D9q 03dmVe+[a2R8 0^|j*VN'N  tRk(7X A=UkjNIj8yu!Fq~XPkzÆl63w(QKpf9* %>&Obw 7}B(@" ̣dC`aoZ뤪ҝ>羱m!_bNFSYH,!\wypªjR蓯ibvlXٷ$M2L6C9xZ+i!ia4cIz*Q&Z rwU \hɵ͵ޒ ]lxk̗| aB,n C0I7HAY4Gx 5C̠ Z$АSY$lMn] DQl\A#KA%l@m&vl-`N>5xC&@^X+O }+*x* %m裒~!<EϠ N%Bn\b]ǍpRB-[KV8FѸK hzr,Ԑ= $9lWF?m{kƩb =%'`x˒h s3FTeiN>1PPp$nXz ~Mh6?9ȫsZq0oq|-0i_;˼&&85g5Es /mmcN>RcUnydrF刱J }pPfйO|WoୟʧT_|Kh7#P $%WBqaB*f\ Β=Hr_AGsoJwtu&4n'NC[|=r="=c:Uԍ2T|J¡{+ Qµ?0644ϑg+#˱3,Yhm`#k,,MTDQ u֪EZRӈ[=zkW֯]!$~`H:T\*HLK02G20 ]sTXKIe5%l87Ӱ 8KaydLLU#ZGD#cwz0K/z(:ciZTp L04I(q:eOEp@9N-}a lKDҤ3MQ{.YFS:^jC߼yM^Aڟ+ Wq1c4j=P6&qLĉDp+4<QbP 4/cj1SΆXO>}챇s[0DkHEDTT.=656{ˆUd8M̒<"N¼f伥=\6(ljOn"wLc^'H0̵꿆 |:)`]@Vex< }vjaþta`-F:JHPkg8m'D2M4 }8 I)dlޜ;'ķ 3e{; .]B#t]Z5l,NSѤn:%8B/f;CtiR] MWjd U/Y;*74:#nPH27; gJSVᚵgu=dh??OO&Т5cF az .tV&V0~1UJ]t*ab.UcKC҆ǃҔ5d\R9O!YCh+/N J#y?,LI:qP'4<]f7oeS)IѰc "w_*\` yHDSuƓD:^ C:s՞vV,M.B(?Uyjm_JYJg T":w9K蒰V:?y {QS Ue엍^2m!< >?ByP__kIyR:)C#nRm8܏S]'q  D+}kV*W=0/y(DoM`f9J[elrL)!4!R[ y/9r_$n1\ aʕ6YV3@O}澯CB(/y۸aKv,[h3 &YflŢ ECKФ'GO>η"v[Os 2bFp_|-@uذ$jf2+;l+Jƃh|8Ú[z<>qN?O^T b7Ź1*uR[;}[`bZ޿ʦ&=}acziHz2"(z h\?d-$zH16~cʗjMMWh^` ,iumǀGQyeSpԯomcoKt_$omtƧfq%y4W5a~;p`!GԄfBW9-.7+o swWȻ'W\C+yCW+3(nk 9çtiX䮕muN0 68!EԶ܊6:*ɣRR9G1{&nr1KM /AɶGڨA #t|<|httb2w}Nn2pJP n-b!oѹ-1'~]f\> WO$NHQN,M&)7Q٦q 5Ij9"jc"⇻W;8-aŕ6w(s=kd P/:Trsv BgT/0~ Tf1%W, E qҴ[~)x9vܕl`Y}*O f$w`~4ʬ!9Hyg+]k9ǖ׉QHx AjQ@˳83-+ Z x]+6v5RM80[XMT{MJK3ys}р❥CM觍g1VL{' Z@]6š.oZ[6#r,wkjHݐ ϑlxTs ծAˠƴ>4@[o9횺KLNҮ㖅]Q,dE&G{B5GB'u1y-TAt6_hN~Vk{ENEM'u5n(ݖ&q(noԱ2^U5:v\Pk3X[t_4?Mky48)x1}#o=u2^)C~hb>e)XUelSDxB YE\F8deSlѨ;2:h{KW}եMC{ :'KP7@DRLQhlĚ1-k bUx]) h*!,[8_|*s3yQ 1NN_rwÉU @(A$Vg#FU +/lcjlu%ț51oY$ޚݯGSSo ;" /^5[H/^_~ؓxgj<Gz ҳE.;Cs[^lC`٬<8)2}kkc}^Jݥ#|OUy&;َ>a bs1\ ~'GOz4}R~:{DX5~ڰ;(6Ȃ>k*NSp'HFca8FCiT[e"h7x.@@fp LؤَfbߞB}GPsSJ:σ)#Ly> `f|[bK'۶`%'Պdy;b: 1[ B/fQnYBBbyjm|s>>?4}L؃VHF %(AGse1ʩ+ ZXkġh({r0sZS+6B"=s=m>Mc'A)ACqh40tWcjX[u,28x*gփ)`Z8UMk4n` Sf}iS*Zw#j'M2 3¿ؒ=~pel`12~ | p7skX%gďGa6"0)e̪0qTQ<1D.ۿr1@?tp@ ;zV{(:^~U0D+T`ϱ0!sejSN[  0\|x9@FӋj-sި?.>^=Y<<$ %BD{ۛ-p4*SGpAZD(2WefaҩI` 6Clfsm1]ypVs!}b]խGyp[J&gPGoʃ'垑ii Nkh71q񜟝aQpn;>4Y:L; %[%gήtC$|W\.]֋==ol>Fl^]}P-4 vPuQTlouh0'\ɜfbm:TaKԚGx`//7؜9]**9KΈ8LIc?AT #(8HgK=0B b%XPn0u\7n"ƪx7)Rxs$jP#G|0;|$i8C4+mD%_:=#]DݎC; .>7:6Ϙ;\6^!) F(G\_uM9p-}#k~hSw{WdMNZ͸6{nS^bx#+J_w0K=ߟ#.%4\Y4I~^V(DXI _s;eW(ѼBҭomlno|=̧uз I?MS?QPڠ]@i?)fܒN&'xվ k$ 'PjR6v}[8O܋:hJ]Z _^9%*㓓iA밠I'7Y8UC 0oQ;¡*"xu0\QvtH>%aj{xI%"aN QZ~{Wˤ]/ayaG5FzñO]d56 ٣dϜTC,,r$ULj4gYE."cD%},d&PzQ9^8?YJEI|uC8!Z!\Qg\bAYtP(fưugq@BEFF6c4\,0D%P'^KY"qz}8]BYdM|%ѧ5 0yAs1 T33@FŜfA ݐȽAX>=nnwNdln.a/De0$Ҵ4RIbe w(Vm9rE$#1k @ViK'%n\;!$ <3~~Gcβ4eUSf9(gz6śb.QWtT TIYO{*J n|@"|4C הLHts"f A)xY4ӡn#,!܇Fy9Ѩ48JX]$Cۇ wܜL3 *>;cW2 Vj88K1%h<%IpSshn0F)W]V5\ə9(obe ^@DdY݀psDB)%<%)kpqH&f4pNyp;x*ŵ(C ſQ4Yo&_ I^Jf$eFn? tjւwVrw>NO֐håhx~Uw~ .^{#D2H+4x6aʯZ埋 )2WFeYe4(|Cv~橬:,?uVsNj3N?$/>(aTu|V uNjyjEk|vREI_\ |V6)7yrZ^@:L'NUo*FlY \3w3SF%`16=K <A{38WN؏@ CྒྷT罸35ޖPql=mBךP 3 >%Vh.ghrrTʞ<>>: pxf֫3Li-S sy-0XRIÂyw|yڿ{rFZ%tki&7i!SDzU9]jL=/7thr؅lYzFSj*c3AJ%14rG{[̦Aи~l[6׳&L_BYbgOͺoCtj뗖_0>Ն %JN("Of Q _Fe{1![<t$]2]%9&#՗WMojgQW+ mM#A8OQ3kQcr)BwA %m1N!<$puuzE^J,D&A|Zբoɹ Sm(Hu{Q@ۏ=ϐs99jó iJr z驲.$A:rVP6Z0nXCnV҉gb }A_Y&VߖcY,P:`5Bq }}Z,S)!FeW] ^$(7f'MڈUrWqlQ 7%M ,8%9S.khεFpbBe>kG8uhG"~"𡏕d.?|y$Ā*4}w/xiuap}-KdDZE ˑ\+? 6Oe)6dy>O 6tTJ3LcAhmny+M.Ú[brCO(4f^2)'R*+RUbTja1KT/V V[1Z0tH&jZ"C咏ޚrWu1yJKQՔ;κ(s-šs;lbg|rz[YJ9j8L\A m?X9ե1>g @(n*>!/Ps֖ty>Fa%&미69yhljD0z=̯7U&wo7k%.)!ߥu%n,o^C G(K ߕiq m ,{kbC"^>"<.Az-y9 -݂{&Śf*k+1ZKjg%AN 42>9򣸯Z bhzׯ,-Z\y\<0\N*ԡ~GtђqɓQb*}ߪz Jdhͪe3ofBwUBSƓ"/k@waHL<Կ,Bز~z*BoRy멪1Rfr7@a,\@S䓟>'Z X>^n*. I:_\|h7[7@2\Z1yJ4͐{Bgǣd~X>F/U &4S^dߵMeBN% y i v%ƱO ,:PFjVj"يaUG##'WƞrתjCM `huq6-vK`,h &V{‚;sU;,Xu4{O 27/IevPN^r&3lp䤠yц ް6q/8_0 tJ6N#إ{粭+:yeQ?0ã^qM/yhlѹyAaP ^إJ4$Fl-yX3E/W -t-1VN1kȠ`TҼC#슯MiJRZ{#ͫk&;aLjs*AoLEdƠ pAS֥92XʣI:́<᭽4a}uA)2Cr ?>6ƻ)0&0j"MuMhrSW5N@P1ƛjo:81b( Jߊ M57!A{{}ȳp`U04?<*p %pl !eaRyRë+KA@G`h-d鈋v|$´b6c.yLx%FFLAns;v$lM]J$=3QLE!Y_A,XgdL:'$%cy<=؃6P8N%EE0..=yzʗ,;Yv#VAFm(3 =R%b ct#%| ”hj&\zVcWu.%]? vԝ& 5*%bl0F+C@YSl*m!8QYO9Bz ̀Dk3hۗ4A"K T2Iex *@ xR_JTqb rF4.;9]uiHycpp;˃_2Kgc<6Zʷy`uS(P!Kgt,fY*0(HK?w[F2=6f} ?ˤ MI4ds`e ILUvn86xƐ >\KS*cѦ,ɎNSVdw&dT8t۬J/Yٱ 9SBc[BoiJ=:6P,$frwO>( I58E4'j#a.0рm'wgJkk0~VYZm΍&]kww7iıRNvUt%S*tC\rl,hI\Yp.Y Iqؘq|.H=x%I1&˨p-rjM8zE ֕O.dSp+ ?Ltlb猘J?Y5g c (8o$M*>r!c6tAONsԘxi3J*6LGtc`G$8`2ETn]ZBc&E22A'gav@m>4jb$sQ8DOV!0 ]`HhbD 7GcOf9`GNMn8?{u+\ߕL6`4Mд۰/vH4ޝE1*߼=%g]Qw1P_:%b|l,ֲH-TEG:(\v CSjM/C뀒Ҵb @tZ|ɿR;v9IRGOK9&qsw X$D/?(lkyO{gK h%>#@a$r9UpywQn?=mPb;plTi0*952>+xyj&»aebgS Vgi1C'T#s)iȘ'-#Y/0  Pm4+*u|p}|bC&֠DjmKsv~xsgm#P`YRgۋxoQ2)jc#A5vD۔[iX/N. `KZ&4P]H+{ưVuJ\3W#4ˁ cՅ<ٹyqv=#wLbLCU*NB[/\?E4Uo`fZמ&_*koFE;8|{B(e#wDxA<CB~OVa a@TBCW)Nr21 !k@w(C7I]Wk#Ѵ*YؤxJ3< LKr( lJs xA9mPtLWJv>R{uv:MGk,$eC-H.mf/(~&tՆkDCDiQ[0;Us%xk#qelEЎk1Z+H$41L_zMoյv&* ҕK| &"]xLc+k/0LZ!$f5Tw25q]8 >^=FtDnY >;u_GȎڝdIK}ym*Q1zSٜ2!0HVHJ>J3;pjKid*5LOG;:2-y˒}]}&1G/k`24J#zTF]̵+hv%|&Bh0J$*I`֌? F'~n75{"#DO2eQUC]hAKdOu4g ABEY552~pywQ:FVFn-9sg ((1svMz~ƒ k"..G\,N" r@B>(kS@)\8q 6Zw)8-z,sOT }nnCp+$UH/!L'%GR\0$fe/*v-ļmh*=.g܃Fd'd{ʖ3}@a.UkSBu~|-Z9xnl. Okij0GT ع"B'Tr]OYa$5 ޵xז֕y9JCzuȪVãA Sⳳ)xR^8O|UA[!i&[JE2b 2鏇 2X]12%r3Hsc龅vϢ^_to-)~GTiZrft;\ml4ָ•ی5zءklT "9"6D|lb :`!Bb$wCCÝ8Ll]LWQB:@uo<O{?8 y92o1m-"(\FT٠KcߩtJLpVaI8[\B/Zb1kHQh'{M%,};#NY2 #/`APԁ2mZ7 `d$egmlh-Yʁ·z*A⭎L6"i2@ɁyK:]x{.It9Qߕckq`'ف攌w}.gʒsd }MН Z8K$֯0(ɡ2x̂LT:ɬGVp1zT.RbK_9On 7NLZ;(&YmPѺ`Rhƭj]t@@D{=XmV)X1]pk;`"51Aq;V,"}Mr-1yԖړFýPj"?AwZNY4Ƹ-bN bmw Cl96)o5dT-9,Hib.SWOLa4:`U ^+oXtG_(V> JP xsIㄪ=;c.˖)ck eNDrb^ܤZ!׮.qk,CSI{}eZC`lW=ڲ<W5S ,̃ZЗZY &o{d(:xd ~!7$ (.!&+_/yx~"FqkckS [Yn6ͣr!q$3 gZBgY%8/QѶ ~D@$Yʉw,U'*Au EpP(%Ht=wr08[^TE:%Ns,Ѳ,!'/ 1B Vjkypz ^y=$DUXܘ B G qA3 WbK4]\FY!l} #%!Œ%ʜТ!Ѓuu8oi64a w5֠"tvfppՇksfEU+{6WEpil%]r+@[)uVqe|O]Ƒ(-N?@^iHГXx]'򌀗7A\Ma3Yw08Uނ5q5R Y%깞U`zjY>>fHoq_|Hj=-2\辫₪FB,Mg3q~H_Z-S>BeѰKhrU4W"VA9oU _`p 1,"rHBL [VِZQP!E ol#K"JYre܈u`]C@Ew%vN1qWy]jVקe=DP'g޷jhMRE/Ş5!z=go _ +C|3)\OfunN.AF"N.3doV\sʲ9c<AqY|~ hqhpŨHo$ K'^YZ[,&sPܠ"I"'V9g@2WO[ߔew~ys k9,tJC2J0D-4"ݠ0xeO\1QD蠿{E4 _[j\CZ[g_`/uZh0H+;$cxϙ t+rm!FmS VzS^ڒ{\0!$J=IH2Q lp8C٪,K"t0Zƣ?|h,!Fi4p @ƁkX{*HWG4? Sf(g̭0FPL+HG5<"Kӆ'!ؠ a|.h2*\6MsT.[s8,I˅Ğ𽤇M3|;E.!%̂jڂ0\|h#ȀJCgQN~: /(U[܎ArR_Xϳ ̔<5+'Ԁ+rסmDC:G޿&@P+x٧0CCܯ4n$騎+oD((yXu܎9T+/[%:1Ne8ԖGuy RQ.$__"tڻ8=:~'+jH*3ӈ)k%QX fƞ㥯 ez6\X,r"{;'<{TgGɡS^KWҀ˥_z;*\Uw.޽&(}yQ4gŊ-/TQ歍W;~A՘gPL;/_n U,kgi/oTB|H{" DeOP\4$ :^` )j<8BDB#::$4Q QUN4K/_>66A-tA;kʕ =gn}z"T@Fa3 <|niBUod,EY^/BpeרM~5ǼJj3J>V"DπekUK!,u4*aD#Tv}7.75EsuwHzs뛍AeIaA0n!,"1p7gz"<\̖Юn|Fle|To,Yfxq`n+HUR;::[Lf^O*M+h#c\V-G.j3:B o@!(cێV$Lv;[jg]Y:Z?wQ2N3Z@֭] B" =TBk򕷾eV]xYT!.w[ ;/C_m+ٶ?Y16U:O83:oബF l Z7"ꀧPZDEo^ݳnrWx$ sV6֒2X܈HC(14ye=xuhTvCoҗYE sdRTȲIA$Mul>(YA+gvtCU>)~w}uD Y|;Z M3Y$cGFprcd ڤϝ ^}"SI[<+!(' ߬~7XA7Ň@#m~[?8_P3VרLSé~嬾/P\+r7t]A>"D$@P @d,ɄDlY~>u[C]}0)(kt6VfdjAr"E5ub.V%izsۙ/R`S8hGMNHϽp;W?27q+F!d]ɕC!F_;H;<|_ zЦdcOe18`jUER۰=1v]8' U$`6HBo(rQ=J:-[x44tbS bXJ$,\}%vpH B[l˕ЙB"F,V mBW^]GWRb2(B~AnN)RסGVdKGdE`9Ɍ!nw4pN% )A`C0UWs $0G+ eϯEb͵@~B]R|ѵo=1}9Y)fF8PDWNؑtS |cs)"*0إ!(^[ U0ޙuαVp+o7yĴLQh)wy **3=tMh6NM*p%v1*V@M0Qcʾsuw0@Bqz)&$1z )u-nWR@xks^F-Y沞xC}͚ИQz4GH%iE8 3Jz5[.Uc땍@br"aKzC:5x0{X'1,J-,9G*SB<CZ%/}bhm/CgwܫQT @040'@la׏P067x< ڳ7`Kwp.?`? NC8Ne#o:/HHYh27iNU$He=쀖 q/W"铛4tF׳˴jZU;.ZppzI1H5H}yUPZ7`Vds?K 3Q57lZAj3llX27vrIJkK '6Ä+'N۬:J^}ƸItI:j5PS`]Uwxhm~6:rB=\ӔN,4I)zGĸb+20YTZyH*5Ogkv}SM.9S^R*nQ41&M&lZI]1(@p,S5Gi{W(6n@HʛA@~cɆqBɿ{I ʎ.fo0U* oٜ GwZ`k=ZAR;ƼTb(s Sm }8#̞7jRٝ極&@>rٟ՞- ؾ"AA $Zz_rL*R؂z6g8ܞ/E4%@ۡ(P+)M4޾_yM'M)QVydXy[iD#сW&+hL] *&7.Źf#[t?JL5 lū=Q(dEA*<GoAJ7~8c$F33^avf|ʉLK-tųqRQ`J 4wAPG,r]0ٝ()C|ms1Bkubr8!b`|s#v̺bb&CQ+iӸ6Gm+E,ۋ?Q.[pN)~ rr 9%W(o\IE;v&J4v_z4aw>RJzub>T)/ڏNx٭Bd8Sx[}.{U3AzULpSgk-ʳB, EQ`ukc^ijX?) v,m&G[U[?k-@J?OsN഼-"5o}kih2~Pq딡Tb}> !)DၴяzU(dвf%d7^%L%3|q Pӝ!83(^*hfP;5b4*Mv-ўэy*pKi^ l J-1h׎&r10"ЋGAoĠ׆<xٟD|}lW/Qj fIv|1{(NR3 5i /XʼnQR4|;r; iq[!^2@/nڂ吕haGd}MƆp[~3!^7CǸ~0{'*4Gug3 5Y^ps$UCSR8B(3@Es+<MY7Őr>u8L@DLBsh[S}}a#%@hjΣDrfkEpLa׏U{K,RPi2Yo&"}aTKPV9yn8G#f\ Q=]9jyQNn4| luM\Dѿ3*:)3mxdHtk >ZJ9QvQf_5Ag/2E}[@kWR@*=_3M\cŠhz!R`ϸ[LnqulxK8x:nY2g2$ ,&s93ʎE$ Ź%B-@v,1Ami$JaaFK컭?l[iiP'JPj|^{z&M2-6T0*lxmUhB؂1;ZΨȆB 7O 9ZETa|0U4^azL;9/Uq5$^#EUV\cGaaqnMQ0#Te"gP(I.QHfx2#T͵!cNӱG鏾rr3Dg; F)pɄqH4״1P,u q\+w}1fLk3%^[ǝFlÿ}K徂-Z.td} 'QHQ{ޚbU%^G:'2Dڧ6$F?4:coQ*$$*"jHOODҧKU0P, W@6B1g3 Wa3qeV|(|ۊlsVKomuZ3߿WV_Çgu.ՍD y԰U: V# k@fDb"o?[CrE8U`^@ `̡|onW^,gbиudw> TYj~n6͍Zw +hDQ>IMx^nS=כiRGu=S7ydYEj혍 ;4hk+,U\z`|.q."T;#&1 (. x(vC_DS~*JT{GeGvu[h඄hV%"47>jFx~`&GW{{j oPrP.j\\b@9R*` (d4]AÔzԦԻka֎P 3\JttzxOò&`~[ѭBniQEFՄ+;;(ogde G|e FZSYV<*ف3@l;^^@.WJ%pBaL *FL";µ[UQ4̲F왍"-Hm=qAzR{SQ6A5sE9Q,a! "+ÄCgugpc#XoIQ}5}T OnWhjr.j\p\_8y&v cHH{V{MS e֙GS'vzzd: f'F\{T'"3 kǓ<`ؑΘB4$t{>Q| h1x(mԪuDOek|SJ8gg> _yjT؛n宜Pw8|Nӓ;;{\g;L9 ܐ7 6^4."wzPSN*x.crDm=bTY\j QZ;v+9hSmn䲻~s1@s\^ [)kjEݳC1吚hZr1s] 4= IlKq]w: 4H|,Mʗ-- hR2]IGRt}  :(o? ئm~f#3 ]gD=Du~,fİE=l֙,h&G\r79Xn>!c17+8Z Ɠ%gPL:Rs-k9R"/b D [l<}#Ca- @V4xڞ&WM;5"z/[k]y O)EvIpein%Bթ닏9 6v儎}"?X2gpeV{mx`bQlI?bz En-_&Mk'.vO/l6mk6zOhQ.{4n=%j0PB(-;0BO(=$΋7֛e$5 ;h"W'ߟ]^]cAl ~RR덨@$<äPse4nDB|E .7]5iߨߨ, ֯M>'. 0$O>6 7/vۣqq_>ZF-meudI9-\0\YyZ= %a'-AkF}{>A4wEF ޱ\ yc$o"պ4֌ F%G 2de6AY0l E9E̱a Dc _u$~ZuRWh/&7_o-)'+{(J4)85/slׯ*&CsˌΞ_?0jPMh;:YU ==x]xzpkӪDVz1W*Y"bʸfHDoX7,dM]ßn]@US8:;>x".xr{p(HՇyƐM5(-WD7icͽoUxlQ[\|~).`5*RթܕcpNkS^prDQ4@n ŧ~(E)=8:8X^0Gcj*qWeP̸TdG{z-ba}˲xWյo3W16)jbwLd ~`'grA1z-3katb6@!ok6*Ih`e1 dF=YwNΏ~3"|wO&/|LwUe綩en3\Nk-I렽%"_Eu8ec Bo|"4x4~4U!5FK$#2 dGH=ĺxYL*/۝!fg\b'1!GD!iG;h1Ob6g R,N }zпIxʮlm ܀|Խ7*E(\SK g6Mdk0]i.aYdJ1t]f ޵YSDu2quOblI<(CJRA1XCt#6n DR(t<. FCNÕ+W,Gn$4TpY:hJmG"/Y&S(1b[`kc+ı'TH X3zGr9&]n^y p U(Y]4~hAN#7Xrm&73 Xv}7&Du=cW8w*NŨb]vrRӟ:ŔibymaDc*$y?V{NP\XWq qɲhb⃍тԠeɲD2?|t ':>14 ^Cbc5惐6*"2?l㹳7nٴ~%D:,Ø^gw7`pڇ9@)Ds)s[D$95!+uwIEUl5 wRu;yD{Ȗ~fZ@2p?˃jg $f]}7zE3Slc>p z09EOUЁUZgL|[vr23e&M'w4QVh&~\X 3sPkiuKn&$3(ZtdeI& 몪Ց Lu< 2agWAA.͹ XIY*fPAQ[tEu51BsT9zPG)dK kh4J[gA4(I'E9eTYX.RV]M!jޑ u财oF}cc4[@pX`+()DO 0yV!JXWۺI0@l?V,xF.H 30dXceM(-*BO HiU&mO{G;6 ﳝj͒ZpZu#Crx/ўY;hu7}ؐ>I2Ib/"IشMa89WbwגY3ɢ,fa ^/*KȊuoGF0m ؜^`ODȔIK\L]9etБ$ ,M,sxѿ}rt@Bht.wN] )K9e??ʶM\e*s{JFY˂>B.ꣽUhk@ADh=e>U)鋥|ƵvjT寫p(66|T&~=lGTF-.5W7Ja9jP:A:]{k!G4*$Pm ,Z ).ls` SDq #8 0aKUA6 pڬf Z&4dZP ִJ5J(i[ًƶ&s|p}|bӀ*sE"Br)M)`@hȵ 7B9>[wP1 =;95> ʸ ά2X"noP|t/dAv ТVu/0+:YT)4Tz- K&%N9O.2*h!n425j\rtD ]wZzyV B3Tcj+־c_rRdv\CPK>OeM\1{,к5o/%* #ޣ哭[$%{xەl= d2eRZڹlh[F uhh9O9vX'G܆ŶK4,B1%5 Ùfh*keI;uu]D.ߢbK53Yr7z&3+l"Sƍ4Oȝ c^j.L}8.Y+èP,\$`1c~'*sJκe>݆29}#aC>w$L1N*PP9Y|" y&B7wݴq'eNnOڡp=4+,$+dLz.ZklLRm!Exwm`/Y"F̣&4^$.ф^iuQ@ag1B:cx9cl 1,=K Ձeډˀz̺ju*Das! g 0(EM6 b( |jyqG'1i`kd˞L㭫hiנ"µGML߁P˲}Y R8kùI'v5vZ0jk,(j*n·2ei⬨):_n} j}C^R%^I[9{bGG:jn7/;'ؙ.zRo8S O>嬫Lt1 yC6Mm.U-j5FIo_:ijUhȧWSu%UUi6tPtIs{&ƤCLw,bUo_nU׭h [ (Lt/J^Asc?A4B5ܿLIX$Ș01S1En-SsKFz5߱:3F.GIZGI61wEI 糗3t4ZtߊDaD'8 ra"˝@m))kQRosW4S2+ւ ҟX? Q<')D{z'T:\ Y^Ŵ' VGLJpU?{E/vC2i\4{c,6Dr~/s<}v Ȁ&Q(*(RuK(bu[G+1JUIF;bt$-V&p"AYLQ;ƥ  nF6a(I`Lr#XEm94?Iy s7tSFOAFK3d &V~~n3j`^:]5PoZ]~^Ue{8W->ACzYidbD6z3:[Dō'NWtfb@e}j`&yEqN;pWԲE;gI-4rp2cgCp_%.]8EW GN8s,;бP5 %-t2iFy'_/zJ ٜB}H2f&E2س;a,i!ZB4†ʷl`_8 !Xի/HE. Ru(@:Re#&VP/ў$Ӥd38>"齱y)'Qۡma)|ğ!s,!m#8$WƼX z~7FdZ _䌻#De/u>xyx!P]2~$70Խ H|'Pqގ;`i\`F') oјŮ@S4IS-Een߁fWlrǓT8,zLHPE'>LiZnHxW~ _OZ=წ B=B9\}]Wmk-evmln/z_tzT6M @sU>rfaG4>=V<ʭ<˙WteLf$ ?PW װ)!$JΘx,z>c:۷bі=hply:AчQm7ɛ2>FxO]= AѺGCU%7g4XyQކ >Dd7tP:Ҁ-Mv $S_XPЎJ5my60$P/[^pF_F>uf]p,sqt@B%Z$I }F%8"tWNqj>_Elō3=HS4) VQ,PTB8޻8bM?;7@wv|+OE6]]O[Kzpzxe@#֨JgE(]sC5sifw]j~4膀,"%l!jq!ķN6tQJLQSi2vφapI؂gZrrԂ Eý.~tzx wFD R`[L9rvvZNT;(VäƯй㽫g'2K }اvh;,u[/oVji * ^*R`cү t3{E-3O<кրR|քOhnsMclbėTګ]Ef>(2ZG clѹsR3Z&ڰrYp֖ T_1IZ11h-ű%W}x9xT08<^δLa/(+/X*nZJ9rGaTF`u Y SY μ^jL BK{Vܮ,;F6fWC xy U dP0Tlmt,fKUhb+P/~1\݁w nvmNkT$=[9s (*s%~Fw* ) ?`m}6ʡUZ+w*4;o6~*󷷱gloS߷{/x#^{f7_{Q{{ޡ~ d[{\]DK׽T @aR5e/W \>]Cl,S~}ap/Dt@R{jf6a-؛߲o/۷6^V˯@,U^ol_(_C+t3צTǛWg6z_r:-Xrzh}_b$9|~?j񤰠v(Uk߮kǗiB\E'.y!Jx]@HQAѿ_}\^SJSt_/W.>=5P }K>-k+&ϋʗO+Ǜ]NJ%tEPel3sjCtϢce}6[xyu̴NyJ5v?P7waCK+z߼Y^.)U)lm!,V"fb9]kXe] (T壻60FG#)JVI6 70 _n dnZl Cͷ`wvTKvW4/lv$^~.tpXIjs#!!Az=ׯuxɡQFj-_8׶jЙ#4sQ2=~K/絛ͯxխͿ-;[PQl nh,;$o^mVn)b,nސ,q`r;? /9'0F}JKo%PW UūC:՜_ol~'̠$ax^}o-Zr+6ӠM{_;"!=F- p @7ǿ=.W.v~/mK损k_e:jO'k>oV|{ 3\3a bQ> V:! |xz#:uJv415Leg*: VM(ڇӚln >__",Ţav'}F [.~v]N4TÇ" %T7m~Dڬi 2Mv\>OV6_uaLkK5iP߬h>WC_^W1͒76u@G}*o2'.WP9L]NBH=Qb)7X0$afhfF;Y  ?1&fBqZ+x%2:]tV(ҮW3;tKi:@dq(p>?{N$dwbIolA.胵^CZȽC\|. LĂ2*E8g>v8C S*!/}⪟ z轆';@E @ R³[`m9j8eݦУmM?uFZ嶔 mSoc7ƾZ `\dg"(e=*+CRݲ%UџD0K'd ޥO^9r:2X왁E?,`^V 7/3IOj S$0ZǺ AW޶&n {U߶#` n*ovZ~YHh0*bժRIfQX^dD)h#R-mnB Z!4&)[`5K2G&^I)b shws ;?-H "ie X=\-e7P Pmk,˅BtF%XȎ%xG' (.Kcz#D1FUi KV59 jUx[aQs]C%E/0W&KGã>P <>miZX萒 F4*H59< qΑ֞Z& epS"5txeBf튧Y Ic6p>v #$N,MAM!6䦏r8 ?jq 3?-jis8_KB(Q:m,ͭ(sVd0# 0 !Г@S)M rCTi[WZ%Uۥ4^_;rmRPTY4)]Jʧ(Nм*U2@23tKXT0|C*! ,k=ba-#9M8zܽdK/ay.)zl*^w)Y_ tA.2}sZ'~$6UZ1Ĵ4 MvY@؅a: C!CzeN5l&؞P"񝓹~Y5T0Lq"CKh:--{'-yZ#V@62):@\gmF[ ilq}l hk䮴0Q lWe6OAؼ5; Avˋv uL"uB>z[i?j5C+:Ǹ ކraVqa<%dcCOÖFa.[H0SSi 0bqt7@$qUnVОHC+ k KcI{o=lE-S /NĢ,B%ǣ)xqpx&Da&@jӥ LhhObƱNV mu:KF&)|]с HoYR{ƐBt>`0w{'LJW?}U#`өuE,Ԛo~ϡ'j-()ޠ[l{ձD?-24Xd.7QF̐ `eeE ]ƧDiO.pzUxi%t^EPx$2Sz`HTY[ wbeex)9r(K$`h>bZ'qOdg9y",pt;b koУ|no yhj)ϘiVHQ;ִH>.K2/^_~k۪˚(8 >XAkpUZ߶Na)Fpϧ+Y"|Q},c;|CZ,P- jNm0kE@xɺԈt-R/2XnlMZtU@0xp9B咎TT%Ӷ I;L'ێf[0(Nn hj(0"7:,h/sVe 6_SO)ʎ[۾ZF4J%;Z TYvu!Lhd ]s "= am3v7C}v11(`&sBMQ9Lz Xd)#u ljm?g䫐 "F[5;U1_w4ZWӕ9IިҴ(Mc'(\2-#^XE 鬤IRIչdtW}4XuEKFf\s^?4 _A:aSDV‘ϕeȸtuLC$oL T(f7g/ YMjF9F^3Uug5s{UjnX)xp)q)+ʹQf*WvV2¾d ш)6i6297VOɣ' 6)Py!==ǖW8K #rEJ5HzCW>diFBMrU9Pp:Ea:(xYfHL-F_Zq`1BmjՒ$iI!Ck,31iZK+˸" ]YMgΐ%hLB3?|S٥xHt2˰sڙf(.-aOv>(FM*oFpOnȂ<m9;~Ac#$PqcpeV!Bc!/(UQ*@< Ŀ^+hI<ҫ;P5Ϣ<@ۼ++88πʏӟgdG;l>ޅ Op: 9> 35%a V~e{ bi۷4%0ȃclPvaO{d&8xD6]Wa,fϢX?,~IOK\4FCFE<<@K̶ Wi|LW{gƲ]Rf=2n\aSXi+tMi sJSRmp^ȅm/h2|N3dV7 yON[xgwo /b֓!^,_N,!֩h@77"%T&` `Ufj:h%F[y̿~cD4ƏW.F7.k F,N&pL(A|{އ|f7(=4}>k٢M{r}e5 ^Ds"#ua>7˴g_27z௬-xi՜p׈}^bp֊VU0<6q8w҃[(y8u3s8@w4V(?~[ZTh*H]y9~/Wp?gd>z܆c|ē`:^}>[[s ԬjLӳoX:ð #a-2pGt⏞V#>B1;bߞ}PNŠqGW xϢCV2L{<cobgJ'1Qx˅}bwlW??CzlG~{KJǓՕ@<@'\ TOO|˥p~x,P/xbfxD݆&YZ$tϼ)7/JVQD Vu^؉z<֠8zxHOOu+sN\FLg0&c[4U'o{ţC'4e/3'mG vW+[Kn' eIwDINSdRFYC+;i5Y7=pҎF iN?^Qx1xN\m~]qBP!a#g{1+k)!q]Oǫ3N?u {PhE.N1?D-ޡRZ3ٚIABxZlW'lc{ņ1l(x=^nt  / 7qGpŒy_AMom]` ,6.T/l^'k.O%b&"̜gNUx.ݘn|̿j+n׋0MAdEcy1.HlEpH",c> (b b\8e !PYXN8EB4ܼZe*ʷeWg)?ATu>X/X Gł<MRfz WڗXUR啪ټTMA3W&9y=/y0[l-q:^ yOq;vsq@J'ov)Y,@UW`#xuQ֮Zng_"(2tu^œ@*7$eopR} Vz E3 ~L:*CN{-_zeS ? ߕ5=kC?] :w:UJ0j6 h4Cӡ:&U1q@{54` ׊.j.s'dJ֓yt*={V:5ѣY;,سPY/M+O=zX+>_mmll"]QZP81' ȭm NrNjZtP,9"L{l,z.Ç95͜-X_el-i#wh+HW~=plj/1VCq֡qB}DVwǻ4]4_`ÓGIu&x!--t3-?sO׬VN.0!beFb/62XDžc(iD"˵E<NϮ.~ Ǵ( ] ƕJe$3Pq4.? ͒okK yWSZJDr.@Y#sɏme 1vTNjޡ꒼SdnE"^o $6*v_ȴSDppx_V`yxNd2ּ®$or,"~|ڢȁT;OCQP.Ppf}ika־"pvم_4a,ztˀ; Սo͚8îyxӏв)AavSWk )&;˨~2bgjk[=9rȤm<=Yfl4U4Ǖr+y\pymtMe?[. ǩT|kH&%#3^l(ɺ4~#B&WXrdfD2;4P4F2D+<+ܡ%XYs[ֿ%oAޡ0 {`# KҨ*cLRMl 2p!k[3ihٔ'I#ncIUfNRm=|`BC%qf~D.J0|Wh2o'|=/=8+C4#s^Iѝ 07R⚠[Twc-Yj,[?Aߺc 5a3Ӓ'PvpkHfЙ BoR-mB3A/WAPU*]>0M7u{R#MNR/TЊA,BOg1M+@˕;W.Ȏgp@;C||w?"u>8z٢;`E\ce_"9DQtzzRfVA4j$jb֙2#!2##2P<#'9nw7yPRbUansssl` VgM X/+ТDp>)3i|LPHynen3+9N\B`|5uwyg3EfxG hQt&K J_Gr;ڽ#޼C)H EOxy+!vԳ{V%l!EKWq!,r2^o]ŝBvE niZn9EHl1¾};d+OIA&%*"P7cȠC2UjO4zNWWg(y?;i<ndrs5A{l5QQ EoCo5> >JX5]jeuv HJzoY7hN <گ,v+sCla -j1{ ?+Q\je4Eo/`D=pJ@׼j3%(үk\m>diyas.t؟9Vފqr9ܤp._$ooy6~K!7 (j$'tAU(R-tzz s 0oܥimXR KC@r-o 0O-щ0ՠQǦ v_9ݯu4Kf2(CY? ^iWxu``m)<oA%ΡlքŽuq~|{_v_~. 7K陖*¾)*DUcƍ6$dh5a;x)퓧;U\΅Br#bM?'֮S6|m1Vm=1dz@;VZm|Z(Xf,ϒA|P»R(18y&\dE.|bmʞ MYZiQ}B~$~Z/k}i\jIx ͇s@E[Fm^ޜEh Qpӯ?;.>4|MxptfDt^sڀq`c~ng3 #ton~|v^Pu?w| U~tϾ X[0GFU0Z KE'wG1}t& {߶%6/Wws 7h6y.y(7^0BpJTD=ЌAS-:-U.^Ѫ64rz"Qc&$BUNa$xD19{'cxZw!#0Xن/cDF lBVi? &Պ;Η/2rR Z/j^Ep-.iB ?Zx օ'ZZ"c j-ˌvSmQCu#7ƛ\Dx2 &8`HL 4 |yf n Po i ANBCW滿7BR oBqiabNVj 99ޛ. # \^"Q\  g@%z A 49 :P }ˤH12~ }>|zY(G/04Kӏ3?/К\A`oxr f0lD!m/GMC3lp5IOes{M"MWzPͿT3kdI^U}47z~MV%sT\kj(N3`Lf&QVѤCR` BNbXpdbdbۯhJ7BM 3Vο WЁ Y4~FFtǘ|dQ (.i.lZcZ+4ƀO#$Lpf 38WYAPF7sFX%x\J3e3ϨX,h!W'1E#N;=e洮rf)9Ft#nObLEfFqfB2gX:uAu]) ` 6GzCc!MSHRڐ+r[\f Ӗ9ErLJDV>Xs (]8Rm9ALNMMΫ7\C^},Ta)o<, +g EZct,iˊE|H8΄lґhdEIHlh:S[3=iPl2,h-`iB9Ob!,GOL^حsql2_CjIT+XDf}3:sȪ1Qtf )T[Jgso0uwnӧo|ECŶ!p%PdgpEmv7iks* /+ib#RiS:^ 6޵pivMuPVpI,p d1i~+b7pY a+ScfMB n_*ps9k%\C59믂ps ' 3M#wݍI&ZC=efD qDC^0I}j$äo0A9q: 9vi4w%(C)ah H# i n/b@B-컍 -kߣl2VwKd\&1Wέ:=Ia QlZj(W"Eo0#N (}TSz)t]r?ۥ~[ iD=}BUC\L0a>&<.QZ2&eԩp`0P1NR?LI$Rr%P(]A JVHfj\L1۵?urr>N-Zo3OJ\V9*aVe|u0H|'9_ 0X+5?E2M Kv#Mw|LkgZ*f\ZL!u5+nZ;I_%=E.5_9%ߠdoe ʨ _bIi),ScW7zjIބ\BT cv} x] Ar(FŅR U?7nf q&kK{ E2X9wOH=@gvJz;ZʵQL6,*bA/@S_.J]7w(Xy XzP%_Ʉ#a!e$FjK Ira50VL,W^rҐaN Po4Ԉ`#{ }twJmNթ6$[kmU5ržnAݿj_M[:8˕5A]o 3ϣA% X1Q?E "!Itu9|bwrs~GuH{Hz2ƍfa:~6dsBL@J2q=JJibMdIPҋ?L9DڌoIN0@%کj v kY|$^/0P$"M I% ^ Is>T4|#ޘ% ` o*lp`.- {ekvfnTOL2uL0O.} }&&|n(*XI΁N+QH] "TEA3.YTn#:fjT:'Ӈ\)M<2,,ag"Zh86s8RVPQ ayHDy5w[H-ZP̪j3f[g30HC}?NnB. k nE~yQZ 8lZpY f֐Y;}ʦA*iwڨޝzij5FVv\\^ ,,);:w2j 6&:&PU1AU$Agly&j$0,-py% ⧜ e(& YaR8lhͥ$@uhzOIBƑ.ތ[G.CaðCaD_0PBmDYCY[aBA"A  SW%y]1 ß>|kӚ7ُ8`2PձiU}sӰ'O,2` K| P |xfLN)筈/E` _fC]7fؼ57HEsLI"@d{8jA HرRtA T;E'gxazBstGTC5W^úYFs|Ue*ʀEƵf]+؃n;>T5ߚ␞?))$nWa?4L5}i>xBؗ(uNꚡ!^ah+Y R% ?&{I tB!{qtЎ~'.K`5?&XWb$E)z1P?7!#5}}ta oO?R$$\MԷM7OB 4-!\WBHؖJ =mݸj򘸭XsYว淆Hj@Փ±}"F KωPBkj$r 精/x|B u0V NmkؙRkDža#tJ?w,` pPtq{G7 .!fNqu+CM FD48_B Z>zu۽6." #RtMym&u#Ieڥ%(Mʹ-ZNjHdW0 jbU%R LQ*۸Trh!eiV5,;ruHCT$[8%4QQ^I[B" @54ҧ j,,_*jJD PajHj!W)+/ɒ(U#y8 ?`4̣Q~M,?4DP=b: h3ģOMk׃" L%&XGWI#\ͦA[vMY*'24DW˸ltz&ry.e X=A Gs~8.rgi쏁X@m\ޅL8DT1w[߅gA~Af@a }KT]'[s| { \e_sa[0>UKe7Ku- } $1`]לqTIaWUUBԠt@oJT-V8{)[ht|޴ۋ MB-:`>coT= #R P "8Ɠ!7 Kv |Bl3"K!J͡lzγ.kRVꗏ,n]گz`0cyol>S%W羚b%{+"x7@ |OnovFNi;O"mi=(n.?Yѻ/zNR79M&#̎#Zf*3v 2ںIWb QlP`Ù$d !HՁ]mqf}"/m6_q  ơD|Cֽ},dnr?p:E2hp9w7Dclt:c$p< nnogiP̅(_/#J ~`@ -C/zx~iW4^bc7.Mw- W.pߚ*qBWItZ:; f.q_~Zzɋ; CLX pC41Hs>I=@HV c\vxi`\ p5&pYu5byfO5: kL薕 Y 6  k2Ⱥ1͚|ES%$<Pؤγ:OсÓ>_OVݞ pTK|E*ST =" VC؇VCHjȢOD0OWtE)3 HoʂХ?>T1i367֛<Lƽ1u4WCړ1C"÷= xYy|}:!`N1pz6D7p@d!х9i aLťJ hJHg]қڂ-Gt`& Qъ ]8' ~Ry6hRz=cPJr&)!` X$* Rʹߚic;7pA( K62{Up|? hX9W.Ȇ ㏗0 :Me3"U+FС?uQrp=WS̊ӮŅmT/]t\XO2[t+:mDh c<6GUӬmHBLA7P=&v U]$| 04vz=cڻ?= I) %*Q?v`I:4OP.x]͖iKB!|ԩUlpuz>a$ ,!T-BYly3!2hV(ұȳ]! FBƏa `!P!IZ FTHf&GctHK{t6z6c:a]D/+W3_aCg 8(l ]BA,`Gi ΃|@q8Ai鼧ke¸:A)?NCB"Xo }\S8C2+M%?KK.-Rtxw@!]:ip->*E0H? c-?C|MV]b}a#CaOo&]\>)Pwp栆~0 "ܡ)YsΏoQjPMR3}HCA8[NhIoSށ8@_X?|d.,֤Rҟ>} -M>%To0sH<&L=' }j(0} 8_7p,]Ŕ/" k堿;r>%CDo/vzE;rSޑ+AԜeÄa\9MKaEzB49?,NHs$ąmra[HX%͎H}: Tu>e`RWR^TW_GDC_~1= 0ӧxEpIInbӉ~Hr}sd1$L΄So"Q-~lw!icV4L2қ0KSD | 6(Y|70h\VjҟW&_~q vI5p*?SyhWy+FQ`f¨j`p3uȣ~ aQăNh0=B"l_wYsuͪ7s|KX"gyʅ.=s'tx9Nޟ")I?;G* eyft4z%W? teAOyvkw? IK޷$dS 03 ;Un%Wj1+-ꐦB %\+42IY"z: K:)ń1Sq 6UV`?g=^$ˌᏒ,z)o`ҩf4W&ZeQ><G'k0E<4Z<<˓wOn` _Œ'a~tyY0 ZbTG"hpfe݃0 =M@ɓvo1@k]r#J$7(~5oM`.jxy D)V G= j @PH`"y>w&',zGDP_07y$/_=dكU4Ͽ= ƼaACߤJ*\)d+*j^S(4d](р{ڝCq[M &[jS3Ww fXS$K.߁tt*wÀϝwm2 R.NjވK 7`ý,oeywkĝ?ca*:r]:[ޅkqc  ¾Xmh:`mX+֕}[5T#Ε\1 B;05"GpT!mUYȳ.۠8qaE~&O2"DIHT?v<90H,/JtdIDJ(i* J؃dœI\EP<0 VbL71 VBӹ-M7!ZJŽ Mmߓ$`OYV J*^8ڲw6Uz0lEqB_zҥj iFUR@e\n^p\UuU:FSkQ#|5h"_XӲm 1/iw'i -^QrҥWT |qx N:iX^!H9w^/vw^vZw[]>ُruO˓µ1ŷA@˝/CXs>Sk:Xs>ƤnWlJ=;U( LPe? I>"YW* %N4Z!gN4:N& 7]lo:%:8kb nŏK8G=պQ3` 'r^q<ٸV5%s¸RTqnOG2}JvʁT.14)6!HÜ'9 l﮿4 `ko(ͽe,z:~ઃF.Psz2Nwe>K/._"ېYucZ׎.|qG5 $_gֶi8DL0zBsa]it.:B6Fv 0^,.?.l;= SC~CVCP!i1%\r{zF6<8 }w; Ռ0R=jZqY нf~3" U쯉%=z ֌?}p0tg q>9*w k! b[/`tY8kSy s7TB6RT;RµJbSȅ0|υmYP/O `lÖ?mQFK`p0C=?}(nFyO}TEfĐ-h6k +Khc.͒حH^VH! LȠp*L|>T`:˻{mkU֘ԓ*soI\BHkGcM I֣o[|z2an et5ɧ!ǐmʂx4YI4Z2Lw_8td5-t̚/:3OHІD>  )Ibh a&vi'8 >dt>INZM<5ӂzQuu@;yl2L Cpb>v󱉘,r#LNӔ93_5LKU=1;_EI!@^’aIfRb0Bsڿf̼ܝT50GU4µPSIgJi!˥i@t 8ؖ5.pu'ӏKjӏꝑza[0UK\!WHPHvaۄStSE]4T^p>.%jU~cG?.@Se>=8hX#^Ygf.<.NŁ^SM/_t]VuT74cEu#TSE,͘7[|_"N6uDΰ/ZGS6oxzÂQQo7i':~K .L4"{ҷŠ&W֧z\/$-Qp`ctq:  #bcd*ZG?ӺHfzzOX!\ kE/F_y#jY^Ġ:WU>* XtTq(V3+Qw[hf hm?+hmni^_gޝxHtEV~:^&tBs%[`j/6KAx$)ZJ;ŽM!͊~z>a7o_Ma[Z|:olyc9ihW8p㻻ZܭfQ;3̒w(:s3|--Ua)g$x-L!ڇfb)Vߔ8 uVx|>"/^DǠS+}F[=U/k{[ i-]fYF43rR|\Ҩ֤f`&;H QSx o;miE9Kr50GB~s[^(`%Ү)GBDAaA(aNd*15<.ZIqH$f56z7+ڑ{)fZx~\ Փ~ayKHUJ{fgSבӨT*wc+>niuoX7*]Iwzxtb; 2܄aP#JrTKxO@ҢVh^&VEk=ʏjmK'*J>B@D扚%rl ~25I1j۳ V<V38$Gd߮HQqӮ˥d?kJL[\%"czqA]Bir 8t!/! InȖ9Brr`>J FPՐ$Im&Xmp֦ dkC7Q4=GUvd-9L˪ c= vj#lě\bGy_&uys6h[#8Râ14Ң+D=neqcmҝWR@0d#V6B}п"jc7V[y&iFm*Wku0C=1i|}F XB M;m\Zב;vihC`W'T'o :(I=ͮ]ѻі<5^[o;ƽgph'j>7Xd*-AUXքX "#-nU5ƭ]WKI;iV] v /FlbV- $ʥYͿ^9NW\WגcQTW9I6/:3w2[}Oh:ZwƠjDk:<>}/rNl;lW'gcz/B; R^s'ƃ@Ej6n7/Sp^I.+%r$rNݧѻ9w||jay%n3P;ûH{p`DK>>i2g# V>޾6"x_EkhE/txfy^՟NXd5$ꢯ>*EK؃ZXPAt dĤ b~ 4 @[?wCA!39%"ļyv+-h0%y JTuzL}j:gL%]Y"y3D fH [!#ۛ 2!-L!~Y<|n~jSP!:exALʑтAN6{Z·c5xz^ߑ*DؿZLH`90T JBd-40_r X_ꆹ?{M7L} &=ɿ!-@'z) - 3fUYe=[q10Fw.Nã+rrH"Ǻy}\{Ko|]"0oofs7#}sa7# WwBD>`U$%P]a#U)XfZ_r| AOv$Ge-[#B揧n_|nlxZ̃JW-5xL!sfu7ϜEY]6۫w278fyS{Mt:kheҰ}LR=cG {H?f *4O|5gYi#2oDR-i_rTyS͓>;(pQg ?u2S3O\ I 74 xS$) +Qb>/Ygln%O$m% !PY یhhzyyy BZW5 AQ2 E$3KZ$W:`4' 0%|MO[p 3qk{jPQ ?5& cbgER. s\%#?rTP͢2NUYBkoW]m[|S![f dYMQ1`OAt}A=//hGNMkv(j!i0.a{2&5}[^< *2TDuI3BARSHib38# X"hͩch7teZn^?PmfGó4g+?~y' Ū`&\ V̪jzYQu&y*.m5&+o ҌnP'M dkB5s @jU$xVxq,jMB͍>,h;ݗTK{ſj2F(=詡LbٽW^v"+zejb|uqyY=-ƻjZFj0jQ+ibbq6j^tr KF`<6^@8ći!Ymܛ3Ӓ>>O7;^M"츇 ,qoc`aѯ7eN`(^k^An '71h-AAZrגؾNZЯyȋi;*,83?Xp@"X(l) Qg-$> WNIK<;a}hdWU| `B5ŧmZ\u^@jav'` cͻY06m4 3$g{uXxPzn_\]hm\`pzd'{waJ'oj| Y9\|xcS}8EE2<=iVXhu8M#xpn!l]AZO$@_֋J]8T3ByX'u9]ɬiioq{j_T0fO>TYXRb$~tc2)+19L+ W9rD\RnH֖GTʠќGp7v拎bbف8"l'&s/b.D{'`KhOW'ï7=]ES^.7;IgQ1U|ck: V9^Ժ!'j M=Q!C@?>4jخQ0pf lIXϽbi&}u SR-jHc$-SbnQu.K'ykF|N1eY{Ek͠wPQ_dA4O?t*U*e"5K.G؟1F@5l˱+]e_Wa=TMON b\)Wjݔ"32)Ο@Jv_gJDA?O@-*%U)z(M j{$ex߇maFAVx r'QMD2Ե#uYb5G#@O-zZQ`宮O9nc2mՁ&L |p?k>jbЗt6LX^ H<$vp[9x;'wQ}f_õ C5*zuӫ5vz p^;>:yA]Zj=NzmrRmNOI@8*}k?tz"q̳FѲ뉺pHE>~k5mUt@ Vii JT^TEݲ8}_#G^'d#6A^-XL}Nh[*)덺\D9HU%oT[5MӶA_V0|]"a6Ҫ|H6_4зfd>+ .K0{!UM :z GVnecu&}}DP 5զr2#U~/V])kF4.$,jkm6b T91tICJ)k@1@_57A!|d=͎Dܑ2|& ܊;Y6MKKkJ[GAԅf`# n$۬ߦ"N϶w[&މ niNKZng$JzVl1thMM}ibҥvX'38⊷X~bM 1R6p>- J!6vL,bѤT1./@8I`k"Tj^]$g5UW+0{F%e99WbO[/ \(uKU ~oڶFV[nu:L0,S38|xQoQ4O6^ f-ߥ8ImCQ~&Ujʌ le4MN7<]IxqKyj`;ӪQqLÛd~U±nV hgfx[/1YSK'x l8ڡO5Ȼ ¯gsΚj&A;}3)\U{{ o{|N7?CNcP$h|F^\?;x%1Y+v.o%o[msfRGC<%^aO LZm0i$.&w8}T)НGĹA˦ӣӓo/.TycJ%>Ԋd "qtۏ~D/U%vTKe; tE{?bZ–d\9Sk)؟@$IV(U[z(KVxd(Bj2Q[tJ9kHBp5%* &e#6X)el&j.>7Û2Gu໭Q+Pݢ𩉣0uG6q$&f}&VLPH51dR8nƊ??v˨Slk?F.&h]B'$>f(;;wCPc>ma0O]Y6p1F/iMÆ 4Ijt;"YXR)])8#Evc$Oߍ#o'sT6uMMpXKAj]fu/& \蕜90GG.X1TUK 'x$ҤuJF'ڪ0zfǘjz=e>ĐMfvE:aDB 14uVq+((cGGtzCJXu??KVUoIwY0RQq?9;'"{㩬Ju2]TQ< ).i-5ǎ~Jch(ZXrudR &Eҝt::*[I2_:;wd na[{~8է( Pc󣎑Aa U4& <,mmqt#duOՆ9GA95%6t D=$HMy";oBS,a벸V `8]jFalԿϭQGաi'4^1* LSu%rAC-0^d(Q)uk-gav3Iƭt{NR]o bߪ{%SD$DIRCjDiZ5S3E71<3/(6DtSu\ZB-;(ɪdę'S~p;h0; BuXB5]av;uq6ohLȚ9z7uS ]lvChDQ<!bq?Z ɷVTlhcGfNʓrI+d^jyR' `Y^Mc뒢Is^9!Fy2ۜESbXz{-◅~d4YN\O{aR(V_3hAgW?Շ1au{XUk bkV@ zJU$RW*+ԑ?uQIpO#Q-בըGx!Rtx馽a4~a\OWSh1,vuЅzd 9?]/΍ t ZR,Biv}ndHe^=z%F%M<FoB-? } ~ Aw|i6`L017vj+hK.2d poH]cSGN(zйL]+@'ںLn?ntFFH x/66CѰDz$=a$k3Wl;ey9+)!F Kd?aMs= u`35N;ˤL@C3Kg>?T~ꄕzY[4U@ J(vξ_)!8_'K6'>:XO חwvƥ9/k>ˍ mUzCP MkPr̚(5u C.&9NOޫ${zھ.,ܕ3"Q CwbHXkd~v5r^=DoqQMyοX* DtU?W%c~+|< 4*֤XSD(өc>n@.Z5xVjp7E^JI2s @ȫ/Z>Z3H i?m47ns I5̙~oW 4V TU@LlQO AD_@t5/wBE.D џⷾck+ Zmb} ZKۦK{`;/~@;S2Aԧ }QZӠ}66ڴmMni^mۦm{M74lM-7msޛnaniƛy꠮M"Ӧm.:c5z57PEÆ(\AŖ4z+\%h1j@_VnZs?9 㮶 VWx05wCWy[zo.0k+ȷ ?:$+/ɲ!])tᇉC~-:GNDA d_j2B7p$ B(dn¸ԣ֤Wxg{]fv/ǽK /3;v"8=G;ҿ w-xF(E 1-0 ('=jyr*6NCJI~pmAshP |ܨUmjC'H,*sxsaumf\6t*&j =t'ːWA9-xN}W=+uE=is#gJRWsXr{k̊BfNMp/7\))an̩3ͳw*[Za̬5LY~M;;]Sfo= t 2`twӦSn: H`ZrOM7UӖm5uմecM5횿 9gښΖ Pعi1+S"q2LtNC:s3@lQ*~ÓVe^i["XqKmIh2C,W%#2V=3:`=azEcx e 9ͪ zeb,4(o>g4~jiJäP92'6kV &p]Kajj"| K'r䡏^]]h3!IBqowy{]6i@k|}tړ5).: pƺ` Nޓaq,`Z4-fAYbXv&YgXכѥҭQJ!:qIQޓjo6/ƘaY:\巷0kU4\iY0@n:b!5Ff @KACGA/r 8k0, QT;{d?Җ0e,JOIh?Zpq̫= t*10eR:.tL1s 0̊np=om.brh{)&qX!Μlj*,2=mm[]\Dvݖ0ƒ;{ ._ ۍlp09+!єrP2kd15(252,\^С *(ҽUg>!{͖ӑ#=#O3K7@EY!FYtr!k&ƶ]$ ;[, ߭]R(Kn6s/J)X& X" PW:`(55]rgj'66P˂M@Ft`)xRWYОP2t ޠ$vNEBoӽȺ { x\']dZKfyh  q"9I朠F?\d>3*l}A$Χ [weIކl]eg~jY/=mwWk eژ[DRAwUX(ֲ&iېR!=.78m.ݿC8*>xI@@$35N&U<j9fx 7"9VKJQkqG}3%CkQ`WL#ťsI $)&.Eۇ  D'am9+dTE&>E"_H keP1ucvUSFXz4HdMH0Pr4@w6Mr}o nO,x !ȼ V7%h*!KpC#EԺ5M1XG>R@wM^v'j%+8KSL ]X} |B!=֊g:[F-ڑy]-sxP[gڲY&-9>i0R<_8Δb3U', /rXI tUT؝.ITBr(5WJNRhffs⼸O-]z~Tm5 sqko~ V{t=wEo>aD0EqYCE# +_6 ;‚&VRU4q Y5 f[\4PozIWӘ VN0PU}+~~j:F˃nu]F"Y554w1 iM+qiw1l@0[M7/qӲ /׍!MyueHM$̠PƘ4*њl,dn7Txr1^$ =AfH!h dɃc=&I A1|/K;<剢w}INvvɿ"ʕ XրBZfB6S,mK#:&CFBf?|ڲk^ɞ(2w/ Q[0:7L8Tp~IVM%M~"S55(L֊Xm땥>m1Kks'5-jV[ ٍH>i-\myp]J&%, V-6YD)[-SkԠcm!)\(j`NZp :2p~l|M"ul7-M]diLׂ/_cZwm춖"4>i|fj'||&cWb6ҡOtv|yL$D])?lO\#3NeBbt>oyZ͙p? @F-&PM?CF?^4_ݰHr:!3bƷk ڥ1"Ȧ 2|5Y_TSNi"jub񻋫/ώ;:9:9?>9{s~=>oC*~zk* O:QS-dB*ΜV>6N{f+ɕigx|נ-̮1:HZ5uX,)lo':,o7Lub<)HUHWFZI?&;ƃ?a(546}uS[>:FK eQ6/n^23z$-![]:[6nm轥 !5mtߑMh=d.s  +0cC)q͝!g9 n/ TAӤA\Cޑqv^kX%،<ݼdGTj"Y/ Yw颮@Vt !sPujMx!Uc.)FF4펍>ev_}?TW8]Ek%d̝>eu<' .P0RӬ.>%@\eFE]?(ôKa#vݘ9N죳qwSRQ >8B&J{ט>oaj4})eځj^]]`XY?ƙߧ)XAd V36;mi^Xt!+A3k.`ke $X{P / 1d72SRrsA 02ɧ :$#C:uYcGQ Fԡez|LxCcqӳN{Qaؕ ɤanI&T] tdNF'Mf|}D@G+6%$em.,Gq0EW5a8e2x#^ŇR74seUw5OF'WWL,~=ϒxE H9+CTQ^.B͘0뉢_Yy J٦ev$3t-] 1LY˳^k_fÉXɗy׍QurUG߮qEW!w'C'D])bkEՈywtmWJ7 c|EM>O$~5a*oP|PPϾ6q  [|Y̛?Z B)9K"vJ͒e#T °[8V5xпLP<5Jz6Nd+[%z&Hz7bnG ^{DRq t@Q"UA0´V_ܤkէd 4{ #L,NMk+m^rs4^ҲE !֙lp`SV=<=]AC-X)G<%Z_1Ó^!6BUCs~l-(lC`կu?wm~;)~(2؝Z0ڶvg kKg7۶?,ZXA-X@M:ce=q;p?𦬥t)rjEH\i"KJTRBf4k 10buD]>*|9YE/`5U+qnE[5=W+e9hCT\#UW:$d2g}+m+5VChs IE _1{{/mE [n2.D@f. Yl&T@-=?wZ];`Q&W&a~|ud6^;bfj򇦔 )6?=wi75xwb]wTfEq HJaujo׀Bo5+zBD*&o6 QB5 lpBlX/M:Y&dhQ;ƼGԞ@҆ Bǔٻ+ 2KRȷ>j,z!,hg:>@&ĕe=5B'JWën4TO`SlN]Xu!E5ZJIu'M}%šET򕬙lk^a8Dp4=8Tx*'MUj>D/PF ]ͽ1sʚ06 T`Layy8|srzi6~Eh/xB{jBRxާcD3Ŏ9KQ?wJJ>hTݑK.Yr5:nNB܃anӧq~br9} Am]h G(ꗕ^Jwqy7_h 1 QpYvM-UtO^NξxͿսUČwWoϻ{&l{b yc2 m3.Rg|񺮴pYA Ko fZ}KW:')glP_U Lߤ|Fj$|d9[Pijᚴ!`M[m i})e'hg8`yP9 4 k}%bʧ7W-RTw&ɔ6SSZ.S˙PYGM18WRXKl7{v'f+ 7qV`!U FvD g&/~u~<?k;[^Re JJ+y]ύM}&`\^zҹ{/m$vvRX5"ZN{N vTjSui AL oKa"WT0eQ(N6f͂}ȲZvv7,^SO<,'v`q]P>}GF`0-f2e6 8s|tFi zEZu_XCu>}^4?0O>_o:?iZeQ.1#A>L]ko< eQtGG-B22^=7{QPX:Nj4IzE-㤾PQa80ć>VOaV]1x,=b[ig͚_L}wD>A 6ב" GK>GCSh]B5aE-G߃1 SuQJlX.1JK'@Ql` %d;UTcacTI9S.z.z^$Hv,ĕ!0kB[]}) %Huv1ikT`T%"̀V)k+&5iT&M'j$HqYmŃtOhiHe^.Lk<@q}>$N,2S UϝL)v#Xiw䫷'cÿz6U^~ s FͧhbK^⛛¹܍z,ۇ,!H d|հ!^Y; #!"'ls-nDX;Dxʪe%]0hOVkK)D $e)]RyX ~{.4Q;0; 4V1wBQ{QSTFuQq:r7NSWޖ_ӯ7)j}E"VmHJ~J%, ib?cvb%eщK2POuEU/it5nJ,XԀQ`B£Zߘo/Eu؏F86|Q}*uU7DI*; |~݉ZJl2O"Ň_!o<}5j}%]﩮հL}ypT1/Ush!ןeF{VH8_<'o%ĞLpQuvS.) oyx~x],ū_Ϋ/ KU#zQ=QL'e2K`gF\s!OGxzg:V%FOuT(uU[c=MW&::l?g㓱jKUWRգdz4$&?(tQ|}ԠHdDcX G@QǵCP/: x\@~![w:х1{,ݤԃdѢF43XEBFIvdި`͇HD+Q4:zȗ'д9ܤ$áWqul?s@  #Px|xyf2x:#"nN'ƍ9@,z^I*xAɴI;ԝCwb:B>:mi'ukTiv&?9v-婸 Rq}ma6xCuplFk ,r,no"cYAK8{mj>Ց).Xw0b$-FfVa6u۝j(A65euZIKK'g<=V쇷?m;H %$[BnG*%\=B#cӊ": SpSʐ_ YX"$?;LIϤ>- G`aPo@nJp|1C13TLj[3[l5AX/a⋗_@*Ei% ŶG!!4;W J&\Cb0(0rpҲ\#=kful]K/\xXj(hrX$mn6>TvP9_]}iGU=L|F6<i%˵M( :?_ ݑM)Z]KԪpNL13)0+9eS% &Ԍ/Jډ h @!_8wRG){&Ir^YPf)z bmNjfgkg{kiNUSqACdBFfe9=KBR sFI|y˃+[3]3$3ØkH7.XhQf` ˦">:w~?**\ɰWꎔfeNbeNV~{d<TG(zKDmv̄Diɏ\Ĵ4]1#e/3P״Od/KSJ'>R9Vm lch8?TCBH5ho4R.ޏ-mc>W,*؀c]ݡC_Lk`sG+vp{*ba)CS(JjX:S=#9lG r3ZLHȈ )05%KZ"x,mW`+AO3f1ŒIbew@gI<չH8{Xbo'w)KER3VdV<1WN+<$[ݥa*iY-hHU_]AsrGgWqtXW.qëwc`_gWco%j9 ³J`=+F\)USmѾaY20= ^ P|$IQagaH%GT*l @Fq+j`rØ W `v)q W\h cPZJkh2lU:dR0j>!8[RM.rbo\uXߞ*; yz5%\!NlIJXy,@櫹PoӪdJH~ )9~Sf3 5R#JB~ ZoBmpZݷ2;jQ)H FQMDKq0 Djw9p!ZSȼ__nH>Q$5C)g ͅՎl51^.)&rmbt =EJ!j|W|Q : z4E$ :XqFI1Nz0Ҡn?; rRE( Ͱ2uOMd5#<'l&:WXQ*W҇x$Ê*P1VJSTW:?cG?_A[>k3=yԻS?O[,Ɩ4фTS%\؁yadzj*Q[WNC/YclxVGNWiϼU%H3fKuOQ Yz u02P|cjPVao/F}j?X]&v_| wS֛yy7F)_oZ&΄w?b1)F7l;#4vaNK0e:_xֹ۞*]GDeإٴ*P]$i0{dH2$Ԣ ;WrxPE,O*W(.3)SzU*PLF#Kqx=ROaAiW^]d;dk!?p ς&1Za'dG'/> alΰq0,0&= } `RmoM6h&.&uHbHc|_Άi+{dr =>Um}1c[~cZY /8#?N#ggEζv"ؒyrv|_k ro^ K7;}e]237YuUކdl7S+;Ч=u\x.*fFubi A%tJ|9ģU,7 ,l^-bH|S_ȗ \-SڧW`0'|PJcR# =wkCq#'u53_ؘPH(bptƜű%1;Ҵ&eBt[iIiуb*nPLy7}xP•qss ąljMІixCꓽ㜨 L-GW_h9uN| u>MhV ..ʚ.vwߋCuk_vzEU(/h+daY#-i]g`.h 70g !W}v({Y旓i}KUJ p?Tqiϯ봼`+C*T_(G+9[#E.VW:|C6X]|vlYR ">st`"8@5W)8<ԛ>%7K'Ejg6ƾ;Һ'uiwJG>6W}4 QGq/ufKh>@daNС2r}34ڨ(7k+IȆŮQA|#.5v gcu#*I!{nu 6Y ~82>R/e+.k+!HWN ~K(9|wS&R^h.zex*ِP "}I̴"=e֞:>yy; XBz1-e}Md TNby'L"cCLF#c!ꉌܼ<$+\BTmo4pjk no+h͘MmK+4vTy% nݨ6I9G ]JQ6>3+TIcn ߯6]hSךp<;s~BN|ZqWEkx ^``v :2qӅ_jJ.)7+XlV[%  uA5@ɤI^_[u+.RvLh3FvkeuOEqO]䨒?4Ih~@ d`9;], m}Xq[11Yd$ȫlJR] 㑴q5+ͦJbq*Q"COR֊^]]hnFO 4'FKfSXa7EuG6N q! Q4?EL7cشRM3rCϞ6m+G|vas 3'+S ^)zԞ(v0sk|vMN#t;u' )Ӡ1v|]]_"˝/ȧ6m9juXGtܬLdacˌ dfҟ;O՝CG.kDVD9 A4\yVz4"MUs[yF)a#MYt9Y)3e-t8~)Gn OW^Fj7]+]3SEO| d]9B1c ZHRuj+fW'dq2it<qe!fmOK7;SӨ ZbQn~bW˴\4jTQkc;Sج@aW[xɵckN <}:Jl4_X6Qg1YgN-{K%"mh#8δ" DC60|~ʑ6utx}an"z4$y2&\yvk& Hm.{ZkYQ9i"OD&8͇z:aQUJ<ʿ`Ah(D\롚$Z~+pK C˲ZH4<|B䡋W.^(#D>UfX/恒Mn FHZy\,H *%()ɘH_e\!v* N}c@5+O-:x[Cب⢮+\zJcnMuͳr`mh!4O:csB2/U큈=CQDb}]nړQt;uT$\=tSɎWk@çQ[nOv!W8OVֵC4=TwtC:v|I8mF(CD XjEo{" UڐtaJH6/I|5PlZH`($\"3RL4W[=8N}x 62eN_z$nxq'XIV@qتnɞ ZjĂWZDfN@98Bb H7`7U}V+wI;4L5F6C?HGGK#~Z-m+KUHлDsB%j2a$l?EtBφLnA6B&ulNt\wF JC.UsAd>Y+t,Z}aG]u.ߗށrMzARt>⢣Qg(T&׻_|!RfV@70jD5}mGgΊ3_G LF⚷iLGpv6%O`dJpm>l4ݎ8V/DQ,0!Ac[[%{6F5mj%5o/wv)4jc#X^MZ>sBPqM `R~C mLWʴ櫱Q(c-#(MX¡ͭuk%ݹR mk>3ޞυeiѺON^g!6_X~f`#&*ͰM<^x\P55"-nk#}4a#C@SR\J!#%箊 oI Ki2SvYIC`yaՎPRo޴Qw4:hEs*91g T>y9T=D4 GQ7RNorh rrկ'oDK RōVۣV5jyBciv ҭwckQ+ٮl/gByڱbBm,UmnJxf2? W#w0)wǕF!r7PqL?% 9 =ؒk||x&cFL_6ٍs[cb4'm"1{3}]K}9O/ҵ:J 1!yß6ԁg7tdCȶ%bXGSzwnC"145iɐG8oD-vU۳0 鷧Dg{&'>aNhH97YuzYyAE+MrM&ܧ4z=3/SJAf52//OK &Ul\[&:ѺYV,O' ){cd!7ƹMkgJ $8ӊT#&#S|;oqlmԽ`yҿɫғ!'\C5mDrcWX=o(#2<ddMiGȪߞc"qm6RxUx,6DKH0 mm>'{*]{lu!Fn: Tdֶ&"W+A 6`Жs\&S~\L pde14r3:!ygPv~?RCQY0L(Lu6]ʕhv!0R&'{jJyxZrаMr].饌M(=㸊e 77?: GLn$P) A &:\Ӝh~λ1q>m مڗj0%Q7A0t[<:8^ ȢD?c|A!(f4~T78\S3\vlk 9zfB"mp ^N*~Я? 5Zs 5ڌΩho?wr~.b%B5ʏD53d?3rh͏!"kcEi6IQ 2#UeesBU?ɻE( !2"ɒ|qx eAJ:Pց=n9GVLsśYOX7IzMȮ~:rub,?,u֕|h%xۚbRFEX}RIZ PiV D S|^(k^䍙mE*Qs9αO5MVȪʓ$}o _7/Ԕ_1@Iz(@뢵-5tÎtW"x l&ie % &c縰@'j6/v`VTnЫ-"k|axcZ$bs^(a35c ˆ|"t5vpqkzLFS2sP첔 *0kvm<^ }Y)p*Pbgo{|7d.!HӨ;[C2lR:23+ qʹk1W7NUp;L}zt}z0΀ZM& `ҡ9YAl-t<5G2au1%LMr4 ojpe:ɴJMy(npFXC5*F$O?S'P) [&dI6. HVuԉ:8NԨIr1r ty\ YX?E L>HT}[cظ/0.E#*0)ë]^g?9;[#3w!ASO%Y?Yteޖ9eE=ϊ'>y1[<_ZWgqO9#Bn3>!_=?r*br;f_8y3܄Z^D^ˆdZtiKxl[,YuY\[a-iWAd_^Uxې$y8BU[ raqҢM ۓ1'[3/56xFQ2AS"l۵ԉ}6VH:k%zV6af1-[^7KVAdl<$ n2jجrU˔\C]ureJ06:< X"vfna' ƒiGo8=h#W0Ll8da;YOjbݰ\>\~SMўyF#r2Y@W-qQn2XFfVWR-~SdKdz(8E,%Ji֣1XF~fϓyxItKoom k\vRc"yD]lws:bn{ 8|)8OuFBÖyQ[26u;?rZ6&|+6 ̩aXl%JȘۍLcǷ6D.Ȗ #3_trW,P чVs3Y/8˕:'IYx7ϟi<GMb^>[q7|Num4͹>$0z3PTz?uk5/lݗN#^gg{mN TL[Ë?~OCl6JH;x*ӣY_XX9PzE3.UrrDñTHRVSK0GoN^_s_6A/lsclAqmNӡ u}7ϒ S߼E(7NO L^?lVDcpEOry^{Fa؉-wvNmDM8~PLVT/MHB] _@+qiBHLG Pts =5TRƥ\]%79U{3o)V]CD hBm9ļJq)vʘ(ȳ u\93 qPϤFgLE%wdljq6Hc>geLNa7w._ SgwG_8&E&V~D㇇6lb Q|Sy4^R^'GVӕD?A;[o|uu 3'wr4jǕ6=(sIJvk J/s+G@JԁMFC'PX5(crJDN:\.0&U01|Hm y{X:RS#`*\EIzzȃrMX۱>DxJsRcz:+'טxe >X"-o*nS_wpޚhgoo C /GxYd=FƇze+V "QQʄN2t̋*>"ԩ6>T!psjGѷ@oj!pDdf]c%%,om؊}B,I*2мm[n`0>-& $&6LMj Z3.kT8+v-Zc$haV` dk$ػVօrI\]! '16>jtNu1J`ncw5r؋Rrb?,7 (%vw$њ@t"W5_9xt2!vrQ:M1lOlGȅ*Y,WZ&ZS-hWiS%RjPpA(Dkjrr/4 0څa3NֵH"m襡ݏ&aڲ H]WǿVUL-k紊6pWICCz_ ~pܢJeY_ DéZw'E! ˎyJ+hSU֏`HնxT({)|Q|g.f9n3?:6='4(?:~W Z鉈wv~x|@wgWGSEMR9ciXw"ܔ'4`^:$%J[Ygêъd{mCFNG _4h^htbs=!1i%84P%Fȱv#햺@dϗ#,SJӄڤ~] m"[fΟf(Kn[@= R¦CO4}9<~<888!=O6Ap%ݖ~ϱ8S M٧q_Ig?/EYAf)_p)`4ݭ*={EP'Y#.`S=Qvg=RVҜ<> hb:*R~4<Hr`wi')p*?=~ds}-aj ݇4?C98Ja 9Fd}4%έ(/lN˙8.?uQ X*lRB7hc:EV0Yz I_aG2i>@?zRgZcxfFcvu2&k#Q{} hiR\2:>ܮ{!: w:"L7?˚6dmN;#Ajyٷɋvҵ=>TD*$Z] yOb̾ZRVY]7 ikj|0 Znlڵne{<1p68 _k#[k"h $j5}`c 02C\+l9)p5q9n³?NP@tHul*cOo mE5ObNPSMRYSnass^9].#i/b>9k.$X7(lF~I@#TO3a]3?DPq@y pa߈lXdbO 4 ,G)`" $ \fأ ۂE#Bmv9?Ug$pHUh9Y hyڃUKM^B@Zr,>]vM6,Curdqc(Fjme#) 8hmJaNК' "u:86Zs>-WvzFq bEo1ŔiEtva)$n%Kd@>NAK(DGEe`:yQ !UB"onvjIQ?D@a*tj#v؂aTq;$Kա.R>g?g&>JO\,Ng8 SoB?ek 8UM});)ٜ.]QZi]Dx=MWBeJ _iq3t֦ioWsj+ik11mgx>MrT؏؈ &m$8'ԌVF0(>@NH͵gy2~fD| A{Q,9-sYEVaZpɸ(1(10 5eu7EɹsG='wf ;yex%{8葹o#U/)z"5p<}3z_y,tG:dl4@Y a Nk(DZz`LH5E+v枣^Pmն@#W8Sd0֑MJ$b"-"c>kuk1 b +^B,tخH0o:*k7.K~}fIv}$L=MMҗ MԝSp8nk(q a#slsдN!!aI&At qUfqQ8{aܧpTf?+$zo$/Bx;tG$"?8/=gCqwL"ol6_]d]b=.^3QՀU>dbX֖ykELns÷[ޫcBr>Pq3t%T M?`,0`x૶0 {_ҿ94NBd5br5 ywZѝݥJZS᣻%,bB0$M„n!R,l73Ռ*|Cqtaٳݻq$NxV6G;gG擞& A #x&v$ jiCV$Υu {rSy ,y< *R03R=.8R!$Pc|`tuF7jmp>AYbj$3xRc弎÷!W<$˥ߔ`% ̞ȒY.rH l^۶@Y=z'$jŰg쫺I1Օe,XW+z|XotxW{֋WGﯼ5 //GM١})^_a VD`7X#[Ԇ Z|eBU^}%Ѧ^6P R  Κ+OP ̘WCG GĤs3a@% ~fw2:} [WԲ;qpr bb9`pixm-:v<=D;_ï75֮8c>zV^C4E;.{|P);Z^`,(L fp?Αfigܩ$H 7GN ^p=NPB}~<Jh8MJuld5.Wh'>:jqNrJ usiTknGQ .DlE'fV[ghW8ϙ6@m'bFCGR9)suK y uovZxHz B{5āj5 : daJDz6IoתO[YAgV[дbǒH02Et摫6^+VJ# i\:̤"Ջsp;lAv][6a# :KB]tx? m}noe)BXm[P  -UCˠ0W-cх[M6(HZҼnU?4~>mu|98'TԐXm[obB5r04h͑kZjOd2sHV}21#'%ss/_%%1dv;<|sY_q9Bˋ |V{#^Qs_;Bdnu<'c>u#2K7 ږ]oHCf=T?_j"iTI#m̑ cWr+!>SOB?na5Iu`PB &37;/u+^L`> q_?՟>!MBX8V1R /1L`1]K~u>$zX F6=f`M@yɼJKoE\Ϋf_b~ qʞ<[|dxA{~90pQu ]7jΏu ő?o,؍MjC4^wjtPcX ("F XO| 7q[ލS`:$/컨zgN=~ EuYD:HD^Rp[>%gE,)m01*vdgzh3.n?GFY\ͤ⨊ hzŠ_+77 t!n(Ee5eK|&)|e;:eT+ZFSC1,Y{nu(8!\~#[|vItM&Hd'*yM*8o(cYB``+ "Hv5c`kG4sw۽5)nqřZg6϶n$} Fb_?uKŌPJ(ƗyHC{Y),rv#U->mP^XHĵH`4x`%.n::\R3ed˲4e-T VŘ2UcXИwxsь)㐌BX h8'kA6j>E >+m^am_U<=aQ^8+W82ĬYu Q" %j verJƌ!FTfQ܀{ZX0wv dC-WQS BJo5VžTɳ7I2[?\ɯJlW֭T(# <o_+:Ca@dS ;ɠT01gV:jD~]aA@?niϮճ5<3C_hUm^Smƚ3Ԡ7W}_[iTR,J `M5V¥I3歶TX: }mu#KUlC w`s{d~=CO'܌ׁ9]|& xQ9;?L2Xz9'_1@jrhE%>ې2f]>KA{2 WkxSAy7Z*_WdWpxd (`pAF7x&~V}yQ>ͽ"gؤ/TA^m,|eSp|ܓ2[Mm h[BN!nS xZcdj1[gg1A-(MhWȠL@)9/*AΝǺ@:^SX=wc ?#1$U?qV27`}C/t. Xzѹ>Oó.k`)OdJA.T`ﭱy[iMly~n,1O]9DSG7G:?f8ڼĻ5`}*P`G}>G{E|iVV uuSv<*N9tEjwc?βY Q}?A ho{/7Xr([/,i-…H}Hyyt8ja ᕌؾ䢼Xlp\rmF>3eB$ ON._yVJp|߹s5X2/!6 CobX A'@ q$vn_Kl0²$<ȍ!ʖ~?Q*d/Huܽy%+Z᩷hg{/:=a;>:yno}|S, % P өwr0ol$xi"I8gsk w=௲gϐg sy G wp?:,ϞE[(oGo;j~{ب^6^Po#*mL~Li.ƿ}U݀=<$,mT*Zm{}ܥwM==~WKq>|{ [gmSR@>6vBGYJhTz6o@Tnhu/̻f:cs(3*mFN.0@lo6[D32g75( ]e74g%*77iMhCºx5&࢏ky>QYLkifDѼ8??:=3(Ƶ"plj+(GĨexŽu9>-Yԣ[ Yu}5P%~H>SAD-D*K!ZG.{/sr1zAi F/7Uީ>P >j8{Q֏d;/j^%Iq>CD[یyq-q/U4tmeYlJ0nxƙ׹VԄv.'kI@@~\<~)渞RA'$k#2ע( BԞj{BpJ@n+̊ !6Y>q>N&E2y.ވ Hʀօu #c2ip\P>5ͷm9<b!׬L0'so w8KĦ0E~l}7ϓ˹:~7yjhfr9}톺R~Ow}uc-s<"h /{LPjC!%{rC]pyU\V5VG GZ݆Z“8A_D!y8<j*tyr?޾} [˜j)̔)GK%5E _ _|yiUpaM|o/Β!}܉Ho%nip^/+Iͩu I B=<ZU.zGa˂;0 c+|o٭:(["Р;0=(KLYkč3EIT%/&"VpC)<X_ G $Ƈ`UFh VZtRRH`)锢&t0}|2 )9c*UB!/q#`<'&t{ Nt-/A]ZVodǠ'w1&M@G+h<)zL"YOAV@ꮾ5 L^j|Xdzڛ\AZTI@q^pH~qჂ!t2AKB0rXrp6=} \$U=]Fj{OC?h/KX|$6ON߁{'?VC @o"-6qݗɦ+(ވq<~:> ߗ+@&%g0m*^hvBv,q%$"Lov_3V(͟ FZi3vt8A&5 A~@bE><̡r ;VvtYuGfNWc s&1E>&Z"Wt^ނy G,_1:!J Ed"@`d WSp}^+&ss֑y#{xV8چmt`)e4yBPx`T(oA@<׊%xQ;Q7y6̍"A˻-/4Hٝ )1ov)j%O\5|x 4ZE~lhzt}l&15Ļ仍=4dowRnwa=})^k5k,d>/fk,c;,VU|mFmn/Ϳ%$ǴSӑU` ͎~ԭWե.J^ԍ;_ls3RW0SNJPη=+ޛӱu>?_q qƭKI[<#th}͖b|> %5bl慒D0&m1 !bIԴMh<jgc`]F 2)qAb~_WK#KPsNj_lt1U 6/$.W檎NJ%IdFNYMElZh"15V+˒Se%.֥4=}4_X*4!qQ4Oլӯب%`{GXM;Yb|t=(/Z;l|X z5Rwi`m"ih0Qp#<)q\7.0(6oC>O̝9fêZaܑCaBVǚxs=VؗykAK iDVà K'  fx&w<8kӟS؄i:w&nFՌt%|%lz#Gv.ͧȦI OuZQ*Z<@Zd@FdQV b]߾w~${#FD&H$k-n8GeߢSՁ]h5g('gW9޶ fc#=uG# 7sy6K߻9oEߨ?>{=z}: 3ev,#XLzAӻX{>Z*npƧluRvB6i` eu]m4+(_[NB4),dGkXNIIS"I+C'N9bC]YU xnqyv Uo|#M{zjHC#mXNrOж5WԃWӻdLr>PSVms7vE]?Il¸ HnMH~ӮsĦYa"/.W!3(lV̦ 6ʏס괰_D켁Eig͛W/5a{"tU~JSf \]IK:\7ZEal*RHö 0dΕM:L57a|D%jƤ]vꥍBe-V!Q4e3G5W Bh0ϊΰѹ=-{ރqĘS֧$_;|8.|<)S^ϡ \?Ϻ85\ b @-n1R/3ޚsqyFqmR->#K s p\(BBIoo+\&c(#-ҎDnDT|["\{RD|XH J:>=ҍ*c`-{vS8 /lJs L_ (5Pz8GjIb$0U {ؿFhv,#4GqQų Q"I= ,X#趜~ޢK8TnCˏx6I:#y̤MxW;)sl;ڕΝqЊ*qq졷8*/ZY8˧Ρ|"äm8É~CT GBCv94u(ѵ*KB*\Y=\|BYhyV9!w0:!zo{tn3 3~g & b f|8!>dI'Ds+^Î5`NE*дZz&_.=|ޔqw/y>6"=8IbZ7n!N%PQջFau%9݂No!Cz<^/$&[sj 6|'.f&..`sTfmzʀҠ`I1.ni]E{͝^^@ 񿃀%y4ez 4zmgrG`As(K380o1aA_zEk"$n,@>R-S(ֈj&f7SWN LJҽ]NCZS @>'tycx?WX7_޼/ W9Sv; 6țSAύQ?U8]%4N>*-.ٽh&@ iRܐԽs^j?U0tL&tA*F^jy8m& NF% 9ǼyvGƓ@<@GFJVLA@ȣl7nLM6fIʵN֕‹i4\v*E^[gPG!bFסg]zEs&|S[>! .aw97cTKj&3 t'JN.xދ;%31itv<~^J"7E g9J *WV2f yeWxWEh/F*J1i*)4+-@=w4H܋WE3 f_*-xSVuB~pҫ(aHԔ8?RH<|N;~-S|)x$?( V\?|VZ-By$\huKZn.E?i:m 0%h\>"ׇ|< "<|SZ%G{\u)ެFG| 6MW{վح'<U)>h(=G7US2\esu SU MIO`m6zy>d/FG'Lߋ&m+7:UYƝ: j^wTb}`5kSEr&VJ"d[Ōj A^)˚W'#,qؽCWU v:VɈ/(,wKؙDVͮ6]-_VA[8pKpЍ (ӹ^=fy^O^`h᫺WT%6k2g,a 6^9O&Fdذ M:\dd#6TBG>|B;Rdb&tTءG;Dm1X43Ōyx G<[Vy{~Em9vZ>O61!DŽHk  5kkMoMܫ$_$2 -FVtUsDln>nLs4I67+jLg ~Si.g^s?qxłU4Ao a<s.(RGaՍVu:L&78oq9PfH #?Ӧx?$G:jaCA%&;! 9 xX#M1>qV|db tQB~cɑ_Su &Ir}QuQ}8_XöhѧtO<]T (BH NJvOqo >J:"9DAsҸ\4>BO{$x7QV>7[CCƎ414CyFH~LG!C}l/8:E.D$E!B9TG P aAT_` r8+6ϯ3Llw^f<ԕT9M#(k+8FeS`1<"IH>£ҹ7)l |}H{243Ԉ2IzɊ8+]~t;XT`w-st36lenux9z LUXBØб1_A -umj_HA#Ц|g꘣'ۀ0Bm vr@a۽FZn¢ =K-\۸-*5ѿ7xy^#-]f|ݡlv|AEncEA:NRHџt׺'? o\9m>N6<|Ұ.ߞ8kCg.D^訋+)Ivz=zk>dQ'WU~Vr9=yx-~j'Iꏣ0\BLyhd+(LںSX7-3N]ӾcIZK9lr!.σppNTE{2|_ aVt=Ӡϱ> wJm UT9:Cϊ]^4gjv jM0+@}ԆLSn6J~ի>1w@.r9V4[(h  1Ar6$4j\ 'Ɏw ,>?+Rˊ+L(^ܱv‘w'J(28jc cEG i<+ gS2&/3Ƶ 2ښg.O> Ӯ_4^ [?7tLHVJ9:XI`˅Q|҄IW*&cT^Q16B.%O9 2 $o8]|e`Jao?{t?<劽)ܟqNExT(=./ [;Iw!/am?[F_6k YX[OIK/N9\1_51W*Z:=+Ghި``񁋭jPk'}4.U]ϫ`bUvᲘl1vg d̅l(t c0+ -Ą oF#̂P3Q/'W-A8~g~}_Dr~xl.^jæd "Xyӆ;.' K4d+QTC:& 4,SƐSRPVƱPXaN3+gEάKgggCħ,qARCsHYKQ>aZAg='>)_&?0^Sܖns ]滌Օd4w O$FND!(u!i$Yvyw;ΩcH΄M"*B.u}EetWU?VWF~`nD:z]Oj|ݍO@Ea Oz2ssUﻔ[oʤUˆ6?fs A/#O*e +t?I&tQ'6d+ޱk2˸kAI=ɉ\FQipsИ#nbaFomNHI%';JW.؆fdjSik AVXaΕY`EjVRRK'jb O .piw|&tщ}ߖg>2v +nr@B"]xl]eRSV\2<Wo%{V"*o&]mS&;X?qjYN,9=ĨZc >7g7I]v쏷~DM!HA o}eO:ĢEw)@_Ǫx @HZ`aߵ='ҋk\m¼*2oZ%&!b9'*GXDp}d3ԉf<&Oޅ]Cc<88{=:J-BbPMqִ)3uRW뷘r%ul,.Ⓝ31D{zJ:=]1FqOݤ) cB:3,i hiŎ;>nK9iZqD"C&X \@:L5<ԚejxeΈe2׆$yJ  .LPe>FAr~ Q\=;˂Cr>رA{Ȃ#P>BP4.iWoaO> ĊCd?asz2܇Ez锶 5w.":lj1,̈@<fE5RF|20|ܩ+0r 4,X&nD - HK#zgHE6 N8Ow3zr`$)hs_0!En¨qJn0sBkMQZ4WtM 4S8+kGD>Օ-ԡhKT}f'Y[AΈN\EzrM{5 wo>8rL)6`0n@$ s^4"S0Bԍ7.z`C :ߘp'u-ՆTkK<[۟;՛g?I BCS@I <%` Sy/+Ƨ$]02?wM\x!zr:^~s~v y<8?r EOq`+TYU"Nڂޕ+P 񻺨y=/IVYPE}jE 8<+'P,dQ"򊄃D34!)G|&$r賒LQ9 B[Bq B7y>&MduSuWP( ◳rtHDw_RF3BFQ>'@6ZhHnuFhv-ƚ`Zv/w/ݽ a헟-0Rudm]?&\O&NJb:B^,*55CW;6 Rŀ: 蘴HT4FH1t!s¼ɺBbBM7)KӤoօ$cPʄ I mtfeޠ9ޟK=If#|14T=.ct~M)StSVz]=f}%'ԄOx !BF}Du9)MUGp/t9CU~ONO.>t ꑟM˫@0{Ҧ+mOF b=ЂFx6y]23@.LsXO~)'5G)*}J,KkRÉ9ꦤA}|"f}ҋϟbU7E,/8]|SSak$xւB0IV" $Jj٩pQ+[sVPPlQO!zMByBhXe$a^>#1:84N%6YxUpsaDw)sD<+Tޙp+t@7)(-CYyM^~)] dt1aJ]miSJd"=HW9qYt jFj7L4,x.*k;WwFUyA q8n ަFEG矃A՛A~5]uQ{5htZ-~<|a@$HNq>G܅a+Ld-B&^)4WeMR/$ wIUߟ~\~S9$'.Asϻ?iL;$Hgbt)aK)G/rJÄl`WEXaҁ FFД(CNƺuyn OaՑa2m` CE$ng''ߵ`4[#.9nA4VA KDDY5 3]Xx ُi8 wJb0'}T Iw1s \{?0҂w~T 8~~*iBȣyMZw:)tnTa,旁2O0XL!5hZR9G=8e p2[vtˆ}I oh~GӲZSiRw_NVrXf45Qŋ?b]rM2-m~Ute>NIOIi@C7& #RGïM9yiE>4NtGr*|#czBsLDU(%I+h (qOu2> f?Ӧ0z_M#UY4Z_n3G9%խ&1dE y>^RoN~7g7QKEN}!|nJnCݯ E^]o oYQ TjqG6f75^ܰd.~5 {ۓot7EHȰrtSw @ %ƖU=D'Y #g1%@NNjQPPMNkKb }8? Moi2;T.bP¢ej5b\}{^y'`ǷOh3zzqx LJ}up X+RD~:"2 'px΂;_G`9  9CViv}g32~PTX݅0Yd6Ƣ̷xJDL:?]^L&%rw'fXk6d~nP=h (,992@-t{R 322 |ݗշ_־rX gV/^P./$v,Oi8 ȳb=UZ@b@+{9uօ5p<5~(rL'iQ|Y4ӂ(L2[EbH ¾|?@q_^ јo`h3bG?{Lבnư'Y-o Z [HܭgD)Ng'BbTg+ ^A):VxTUml' #A, 9l~ɱg<y<D"<<+Jsg.M>{Ʉ (Epo12,U7\m3~O-xؼjr O&n+| ?؅ u8BDۙE聩/.D^y>Z̜Hd\Qi>E62-ƻƠ?)Gi-$Ã0OէFRBK?==J YBG,ތ@!q=!] p&tal.XȰ^QNA vUvVb:24c] Tǚ;!W%cA`Wlρ>\!'  eeUe/U#P%ۿK85 /ƛKwt5%,&V"]Y06|1c~Rl:ͳ;L)Uī;*\WWjStje.'b efoT4:7q**=km;23Qj&UKJ@8xU>UW-?)؉y{1)cׄ$ `nN/g1 A>\ Qmqq,s4T#D5wXydIV>y47)gCQOExҭ&["&i鿀5"gZC  88K4h\yBA|fӕMWF+ElVoغZ7:j[5G pT;AG^B>i$#ՐfਊIn[ 3\XQ/"U۲ջFxjښQBI+ރX tMĔդ辴wqDm$ܹTJi@ozd;'~AeH>^{'4 nwg-w!T⛗0anv_L6dN*Hb'g/Vz1)wh6G0I ]|q\¬MtFyh)7c0(namR:N,I݂Zԫ&Y1Oo#.Z~UD=SٺD *O{*&Wy9 ehz`2ĸiy~^x"EL L\O'ٕ6eI`z+0Qy?i~CI|Jr*+#-#i%%EFobv;p+LF-! .R.P@ ?! b\n004Dt%˂q4+ԽuӌE|5ɳv¢|S-stwR:4iےLɱXAr8Zdy\}VUχ.W\- EGRص-Z,S%;:,\"4VΤk,Ӛ#ySC'&1sn\|f,+5 v)6Vu6-'ټs̑q8\'$?ѡy(o37ūM8 q!SSW.b9[2/2<3ޡiJiB("WT rxS.'wYM 郼4D)\*&ߑ$ hA (^bg0e^=ŝ@+>p: ; XR !g9|X \E+QPvkڥօ!Ot/&~P}PϔSHk3̩&P$Y6FYlOsGKFʹڄ|Y|%>-!m`-vL.z1@GFŌ)vEM&LoŪF Jwf<S k|OX ĂmLrM;ƸUo'-]GZ[]fY|{97߹s`),Ksux}l,r-I66`&KjPxavE -g2G౳G!kƎܚɏ<L4 `IPnlڡ3=Čo=op b#a=#ܥJfYiGi#4jg[)ˬ `02<2L`M2b'UmyĨ XyK b.2;QUze LzU>Tōt/.?xVtG/_b/ŗV];FFKR7^Wy. Y\J6aN1$ >?V m-ABI\ʥ_ADm-̙5+"K<tϺ'ݓΡDUWK='N?` ![KꁨnCb2J(QkfsƐGHi2t/ -^Op9M*<8PVYEKqOǪQƪ{L$\N  MA?G=1[0O[ۋWvf&a`0=j302xR )ɾEl.PJ9Ж|4i۵_vSͬyb|i>x6߃ sL/Zoq^(zU30tiiX~L#;oۯߒyH> ̘e2 eU{$e `3*rA*rma`@vBᄪNV^E3JhtNY*Uw@,I2K_ $A euKFA 1iG~ܠDf[^M8~q2.wc#EY]/~?ȖcsK~G0˛h{` 6j=o^s 1x=9l*33ONN.)H6ms(æPxt&qnB'D9/ AME|b<;g8!^/Ʀ|la6O%:C{,P n<(%P1cc4( "yAW 0PhX:j{>9:eS#\P մ(,' WϘ܎*ߌչ[lD=5!6>9,~/G2;!JU#zK |gi9-ȑpJv՗|6sE/壄?Z[dW0,*g bF{9H?uK{Oy5|e1.v++@&=}x;~{~x=>.JS4=$٩?n}gCq]EP}WAc|)um7p3~obūWd%q_gȲ4.;/7㳋N{ Ro<:VVŌǪCJ e7Y9{jar;̚"D4F )/ GNN&~8S'vI3}n^Qi\n<+zwEeVŸ=%ڈ7Z/TM'C&`_UCA?Ι4 Ms".vvtBɆW QRE7Q+pWY'0cOFKT^<WeR@L' C )'VkȬKÂR"#t vֶ{f`7!uɍ2Hn ^^ݢ\7ֳQNҼiXHL +2~1SMnӳ gwwWI*wxoޫ2$9'Ɓ!I p]lr F d5enON/0\-@OO.N>'$۟w(zLq y@ mB<|8b'cWc﷎f1o {7N*ͳK^mmHK6'eUU >lfCӉ .{Y6qCo8J`K⼼l)P_Yr.a,luwDօ$i@$hZ^_ kY7Nv& 0&՗zA.D7V:F;\\{=H& |tT~HHVxkix x'u=}BzCC\ɌJ3лՓxx>.QGd/_1krqUmtCǍAIC1 G^5Ã[)ɬJ$wC%  W )i.RqDEn=1MʅC g IeS~Ӕ9P|I;lX+=t@|U31V/  L,,_9Ñcs-yjbd!̒F'i p0ݢ>IȎҪ~Сkپ7m)k1B =Bo,SAU[Yd>Z 7[ڏJJ Di,LzۆQjn wd"$i*qt{Tt)F7s L=\XJng鄼\bx Xm a͔v1*3򂙍>mjno!umf͸]3uAW,[)Y}D&?$[njUj/daaO~0U0#&iFԩ6y dzOw;GuϱE`6X؁Yv 1ϲmO6"wql^acu$ws3:#|VFN]xGdFIu۾ s|wH27ZDz9u9(D`-e2H1<>bcِ@ íCAis܉`lQz[U֥S}Ykw>vll`o*tFΏjw]ؠ;дbДZ*TQ窑, b9Yp=P HcװE)G68M!CTH&a}ja怒!T ꐏ , !2q'xi 6 ~&II%vk}΋Epxzt(ƼO}Ye?n u?d+糞Y}G뮙7X% jR@tdw`2sYt$ i5e`|KJbJlz >/?«L>5 O'S3M/DGn=u䜼𣬋QϦ.z yp%sd"]A!G>aOݛE?la9#bήN$e{t|Btt_F B0QpxFnZ.3B#ќAdylf̮8]gZ\'1}|uRT4&E3< ZYPfZH$5 Zb|p~kP`H*y1Q~Ct'I*Z3agx=1z) 1qaùUs7(`bӁm!-)!G q_8\E+ =5x8̯b'quu9{n>^^cQ`r=65uRE%jP6]_B=>uLuY"mErxN*Q8XY ^/r}{PbXzGɿNtqS>PhM4z b7֭̈́ʩV)RBEs8)h!wg ĵ܀6]bt`@yiL-Z6 )K\0[lhTٕWZEnqFoYm'ׂ6Nzyo%%>&5֔d6wh Q6rxOȁi&T0_ mtfFh} rJԡH m0YdĿiFCXNIN;a+fEA6};D &䡱oYW= bpomE .>TZi RbLt-pX-\4|£Ǧ{{(d *[SK"M$gÛJŇigr$gQ~פǽ6h\{^*dŊăH+,&c_weC3R"nVIHO!ti@K.G820X,7|UKC 2]8s^f Xr$mV1B/@BY@6;~hDxL5^j aGqǰQ#9й J|%,֠ LE{O*e0#uА,A:tN!`{|x{\Bv>"ʌMx>l+4siav5^IS{#K7s3U7GIhţˀ #(4͹ԗ{]-CCwb3Jo&;lq̽ѧHF(Cxhћ?K5l7'C0ZVa%0&RG̒A 5M6,/l4;McUCE({\<by5j"$ xτBA I0`\swP>.onI$Y#[ij _MsVQiBq !dm" /95UE@NjaHkUe4dш.M vqM.0)Y<2v䓭IS4a(`dS\ 7 7?c<˯_lF9EH⟂ _ Gԅ]WQɇݼruu?;V( wV _~`}JP>|ՋH*^T oT+P̚'iq7rࢀN'罝Rv@4##t5IXuZuRS܅ydUKz R (罚XVO\%Z϶ivNE)Ǿ1^}Z c|*XTM@NF]eRa*Noe`D{13PϜ-_@u%2v4iA:IYQUM)c-JK kH.F:.`Vb91: gsNsHPFKuM ;Zn 'D"F"M[o+ϭ[)p97F D;t pgF [5v՘DILFJzE{uஒ!dg̪&Ȕ\JMJ ?;+.Uf+}k0Uw~]3;ۤJ!A%]`.ˁsqbT ֣d2P &'lsb'<.JmuC'}8jx'Al{dxnK> f3(>H$W#eB"OGE?_SS!#/w+,zR~ΖIzMh5ƺ=-ofSKg-(OPg}k4!vOO7MUc/ʏcYH*"bg&O+&Ek.8pIw!^|^ :x5vP88LdΥD1F5]HtLg0@ WL6ͦaBH/Y+KU.'RI.Wi7aҨ(uI"&$И:Ӫ}4Uq4Ag=xU6B=UcF04V)/S.00 s1 &-x/}c՚QuNBOFuN J};G+*oE.9;ܗUkV IAVUD>f@ȥϵ._{4W-q*QGF _z,"ٿZFa<ʩec&P$ƖqX7 I3>kL*c9zцbAf(tף:6TEgcb~x5֘\$tEDVM!8+hЂ6\MAa G1FC2]Ϊ<ULzt!俯Xg.i5I|B XMs );-;Q@TI6%df}VeNaY[NJU?4h4*ռxwbbՐ*K hIXo(~9#(Y{Q fS[u~%j3oXAqސvcjΡQ?#UxB`U?{n`ւ[@c} cPOlYyѽ 7=㲿j^JAh{;Iw];ʙTKA3P6gK3Ύo ~ffSes=oHh^mϯqίo;h5vbj㵳[__v;R ./w]r84v݊n]F)˅;/v۰8\Ѧ7ќr^-9kH$H3lch3APG ^>]](KUۯKG|]jP4Ӊ= i&{cXQgxbh𰰆2VKo~Y*oV #Ns)q媽B[TR0A_?aBxt@ .Mi͛/k Y.=F*`[+S!(BǮsSU|iY{+Xg>Ѝg%*+sfDpqvUnG_=o7`b%hӽ}t:24O\'WWhB^>T{WӿBw1NIkt)V{UV>]K*ul'[e5U~1, ¿"js-]}T05>  (0D $UP%W@:ش1F3E(Wn̍CRPt/8?|@!sVD4sQѬD ri!;P]rjZ5q씫m>˼ B(pq/k1fmYs0.B'u΂7$y 6Fܦ:z;Xbq2Aiqؠ3ZKI5Dڂh~E06C3KAP qVnY4 ))qrDk(ǟ؛~e)Sگ4r`t/'(:Qk56\ UIᏅG\m l!˒TV* x$\,Эr[?Szo(H{eɿ-6zR!:ׅ peT5LՆvlCM y6m4Q)/CDRGF^1 HOmF(KaݙxW[6.;^si=1Ad{AO6S2,ňcl2_y5?C2Z b}FbP ´/{s]A[-"fH{`ɦA݆[˅>w$0&ĻOQpA ?&*K?K \?@@/.YalMւZҷ:fw(uǤw^^5j}}k{/D%rDl=TAٽ\"[;4WJ&nZR q:}akA6ծM>t@֓`hQ@#lb1 "C:A b_]esNH z jp+|?g_lm%!<Vu!Rn0dWv'Bߠ3 eok(pg!K f£ hB\I$ds΍ Z D*#YԀiceWp ~/6~gw!:ߊA2u1s!`lVy*W r]#OsqvS#$]q5*\Gm}6SAO0=1~f7 SN_e#J+~!fodX[1P-x>q P4퐜ΖxYajBzź1Tqv?%ɪ >?Sv'l<8LOl<:$X@"WV`(;Bʐ"&1h6Ka Ԟ &L7YL;s)@co7%%c}6cD@9$Ս_Lu/-x,rm, ɚBmh Q@VpG_`C-c PcfE0iMtI(ոԠ"NPA,t&rM恗Rlx t#.KC>=]uR(?P{VkPNJIq[0B7b'.%do\}aG<%5mTX׼"6kӫv YqҵgGݞ_MiB42v-2Q ;[$Kg%kz%`d'+^ pDɋ ȼ2s2>RSA_w/)zN&Cp)ǪYtZ+?C5SV L L'#A`N6{'5t肩nUrHw!Y܍A^đ<N` GoXVDhSWq H6*vpU5ӣl^joݗ6zU}7e5X6=' gu.5BctzDSփ\ ~Uå ƼQ ^{5cؒc1 lS_Og:59(c=CT̑t֔`}uo c MOhE 1l[|`I_6.FV^3\M9`\Chvس&N^ͱN^b0DT\OILa0_r8C$3&'҉ǘIzcxx_XBƞUލLmɊPMFf[r lJ.HH}bŒ_}rc4bt"⭦0OW38b!#[Bڹby7MuV  \ h.IjF׀{Td9L6&Ӎ.D> }뗻/NDXX H&%vtSI\n%")Kc{ZTF V I/hӶNxU|yU^3+g?{xͬf]嚾}B1JnJcPڃxTA=Kmba 43Tg(*KQb)8>X3?` lkzisjͫnn4\pbkVп9; HMO]X <,@}xfF@ Q|XS)3A.m##8`$;X·I8[Sd\cTj~yse[ mƒp-4=O1#It*uR6)'WQ"vLu̧1v:2g7qVTxK{t9IeB-욲,T]DMP S6$n:ՓMlĝM,W"*<y)F<~`q3fi${:UI4-ڇ=/{Tme]l!Ikf%鸱1'52f~G9xV t1'ړNݤH(c1L0M; kX\NB<_R`v3W[Ÿ9LQ5gE\|+nOh;+AÊ[D[WţՄ|~4LlgȉG la Lk|8F %A6I&E4SEu~v9ZX=$k8i mN|9_ho?ަhTu:Q 75Kp?T^”gQ تD& М*k[\vcwF[ m b C\_5n˟''/Y P&[RPNJ(5~io:/0OwEKg?Mw^wr5΋:.sϧA1]AgIBH%FL,Ǩp!{3Q:[;LMo]^BG?s64l0E-<<+A.|k bk0nR|zq`5sRwfP`I79!ظO{;䟖ppv:IO//5v=Yqj\ӻ5󫭻;?>M[Dxߵ }ه.=~v^O{|gK^[zoѣ>5F.h.7Sܤ>- JI,(J]\O;7h4ְ"xQdžQf=;clag(}F-Pߋ4rKIRc2sxV2ȯ|T vlXY_>ѓl-Q~ ->ou&T觟$2ZTx]_pF?=AO?Ql>Zn˼Wjxrz;qݖms}rϚE O=FbbWOX%KΕh݁,[S "` ɐ`5T,3sϐhՂq ~+\g-jY`*`&&pَ2%ay^i_jP5t`p-T.-7i`%_f%FȳF\ړ{`:N ,]')!c3 uaP?'J:,D0Δ 7ļ-(5' k/ym7qJ+*SZޘṬ;R?8|2)ojJq ,gUD=r>ôjk0ssѶF&[,~ XMnkmEV}i5?QQقZprCl(H.Cv֩0w ZV틣3o^Lj<-VTN; #SN}gt{ @œc8`)>Yҧ~ `cGxI7^i*T7W:UU'![j p?⩪.WawqA C{·uBQ_ⰌӸVPjbA֦u]=/I<XX+dJ!y}p-ҸxM bQ 57fkjk4Fbſ%/ _KBR}l/aiaI~Q]>j_v-a~we5 P_엟O9:"/e+J=$kRJl.r96(iR M-& gdu1Ĝ4ژJB)Йߖ@*t2h!fofM hsp#sk0a1B8Jj[Oy3\W/_DaP::S AtNAc,/Da8yŒ?8;w&{c_Vq W>aɲ8µ-8#Y"FcۍL< o48g@#W]B}TuF')Px$(;vV!s9?'Y=@A#>qoSDJȵ/2_Aq л^.p>)9ͿjkaGMt~oE"'˽\0N+,4Jn;*k&i63$#S>AWgpFMjX<*jM?9ɴH`"0$9qk9KIun%Fߡ]M68Oh$Bߊ4 PJ?e::8MCQphI}k^/9=IO>t?tޏ~sz{dN-.%yLS=cAy$>7XpJ\4Y+t|^,`;Wݺl#_c&#UYu.&řIGwb3]HӜ&!Q\E1i"r*ݿт!,\prFb-y? =u90 m>5ZJxp:$G"- Zk/fKDtKt9/3õs$0):'O.ΊBjI.[<@$Zs!>&U9N&QgUvTt"pnœm$(GV'&9A88gֱA:ZL'N[ຯJ H1zx Hf|k-QHp\(߁*1dc@.产r)/m!M>;hQ K# r2ueBƯyh4<_ejUwI>{ȿ%a?9촏;=?n7_++x=oq$⹱" ŘgJ)sl2̱w`:&~YXX 1;_5~k*N)s=i=ŏ$N6~Ɔ(m76'H!fkq}g}+oW+`-w?88eF%P>'<¼W2uᰰ-2O-B $)EjIV5A=#_ZG \"5!'މ9z9[-ZATѹ0K6!-/c=\d&ǵW!,?_ -\Z֕͊Mx=dUpit~ Ma%-U<~QS][peI E,ؗmFFZ-UHdw F(b]7:CO] KDI:pFܛ64]:k\J}i!`X^du@ Ky#!YpiRVXgC9k`N}LHp8%aŸ1 B7<q62T"h l .:l!2^0H̉s,q>cH`-='&rgr֒Ĺ&OBgim(,Z/}b;nlS ΫRuи3(̩maOav% I5uS@SzB:1\ H4?{dM;æ~K-pDs^3u' +29JP,) &H M7)(BG8`<\DkHC&x"%IzKtqM g"pkIf^ <%^B4UGTt--|]0Sre'}B=u*QZ7ֳ֣~4vJY?J%6T6b*ZPk Fyk&)'R&u [W>32zOЂL.PonVg,2px~ze8ce&7x&U9ޣ8Soڅp"^K}l]ީWNrx{{)v+S dnzaM * 9*}JMLteE214KVXS\ue[0%)lpXΥ.'Dr DZa|z3ASV_=DU )"ح- ~H{&٢L0`}STWsތ B5CliH.m%5F+]CbJE$3_yG(H3%‰5sCU'?4Fבwᐆ&1/nowfK)Jde =%=\BUVbix/;۽mm:ڽI'< v΋ݷ͝7ӌ54.Ž3U r◲R{æ jQ:㶭Gs#fn(E>9Mx̆e 6P>$*ʆjÁOuұ8v${;cBWPɭjE}'sO̟W?}0i \$Z1E/K7Jf~Q _n _BNT/JЅPj2*b B7"טb8w8fX=D:=m)HR;%+^hJfJ\N!qۥl_R2I7Φ i_"a bh'vzO=ZŶ*.:J",{;ؔLQ ftFڗ͗YY =fe+_'MfqnKo:kx p tKDZ|k R>нL$or7CX һ\gdisvօzt{~|C"Cp(+MZ$9I3PG"қ尊s T\[RQsPV_IgkP%$].>mZ[i1&5rwo1Y ;pBk*Q!p#F#Kr&HZ]hktLvg}Ly\0bX4sȿVR0Ʉ\z{lVݔ Qb(h~)ZE7)G'^% Xd,q z)A p1b6_K٫D6<_*t5k3 gg9V ' /`w`=f]F2 Q3ld "--f<$Uy:sNnÐ3`SQ M5 W#fi8̌/pv Y:?ҝ=*] \*iaNtۦ>zEܴ0i!%":^+,4&DLAR]`@A~<@٥)\. ꧤA8fB* ~O6vr)/]1?snX*~F`bz@RyզN0KUNKApAc Z7yH=CK/~mKCZ7;'u@o'DI=!"|yc{wg{KM׽WNW>^kIfQ:?dȁ HZlĕYG܇U0u9?gVĄk9M¡/D Lfojk`y3s6>}gl6 6`P@i(.)HY4&zbo/]7ZL&o Ҁ/Tm.z*Y,ljZs!>e Zds3HYſwo)87ƯOKG`u[/#J'sp@R%wgdV 888wftU̞,s <>Ȫ142#rEuVI;:&ig ɶ Acosx{, dAFe/կ?Q@ pd)얟ߠDEZ9RWf<1wSߠ KfpCT}.偀-Ct=ejGL |:5M&Սp%)?N)Ρ'mK/*:܉.݋l^SqI!ZVnG;q.\I3Y}6?pQY[U Eajʾ;kA섲A7o(HokS9Xwp7TPtHhwx_da0vZ&M2Q-F~UUSjҠ%RyǡQ,@Ea&{A '|,‡xQ5yԣ{u=YZ%lD~fF-6|?-tMvm: (^tHNA{I\=RMaV3[5`Q@,I N1d:e ϔn:2IKu?EeSXTH4P³It8Q+fy,IJ_GyPEqCtlVm@;YA^4UJb_cʒVWZ7}݋㉪)LHTnz3VMΥRZo0RSP74&ϋ'/I.8Rwe΋]> (Z5J/Q2yD &u}-ȚXkv,4wNvC6~_S}Q0aa&7ĜXYö :;>s.Ʃ.AЩb _qGl^hM\n5uoׅåzs{ R7cx!1F2Y81]'yDl Ie_qFDyĠfs-UH{Uq);Eus;Ŀ58 rz¨K1AU9O W'NyH]eTrk#U(G )?PTEaIf5X]ᣴr\UZ;A3R¡iTWNʘHRQgAWӭW~h2rOhdn*ъ&UYjHCC`TV=*] u3?7T9>ƺ/. cdkX"4j1UqtQn6@Ohę-KsTL/x5rw݊Z\6N;Hȴߚ40yzN:R*o΀OD!?nlydiȚ1<{(>9WAΏ K&O9.QĴ8{ W@W𰠻؟U;qukoX%J pTb㾉[dvS`]jR^` N?-gBfDOĄp詚I mj+vzgBSb>|8Mx3Pb![ 6$^/  >4 RsOr K!tA(G~ .ㄡO+sKLԱ(q`լHte==g)dN[L;u|Ϯ3o"O]4FAK'U8,#'3̌DjPJ atBO2u]BQfHސ&$& Vu8Nq0g<q梱#˞]gB>XC YHVqWޅ;r-_4q ͻWߌjG=ZMy*%v]i TR,U c"CV]-j)wGJJ|35p'YhkwMc$]+ݺM% k*4ؗZNuytxܮz=;;=ۋiڅ󃸲Wdzٙu8~j8h3 0yO[fD H%4F=ݣ2 C74_(^!0)jnAjzŅM 0^=6ZJrnGK805 y=M.&QVх*Ѯ\LQW6Le1c ,}ls/'PuXCˡ f֚N'Z rH@@ͻTFBʹ"|ec$#'$<?y]@&t^X>ٵB-1p=(l~Mۚu9X[)wh,tDcٻ^Rq.\t $&􊉢=?]J"UR m_kri`dW~i1Ua?AvuFY~hE9 jȍZ0E07z%n-HPm0Nֻ9їf6a\'NO[{ք2*lE[">-JZFW &6UDhB J ,i6͌! ꥄ/B (.QG lQTCsN$+A:W*tMG,Y9lQ&A_f1 XQwk7\m- L>vR-*iƾ )#Q@04(ڳ2F7ISnu/䨞Sp tAYT닳NF1J,é,qbSȽHo)< (mVɠa 2HOo&9鳧*I C?B[C`;L.'+ި'oE V 4J7vM, Γj87,I8ar~nV m/kUb43\Zψ= tX~)퍅hd:wV,n;o쭨aaWs(zJB?!;?@S$0bD9A6hw3{bDG"S9ean8[oR&fTu9OԻ)H0M|3bP$< LM9hpYnBnyɇ7->eIn t䄼\L@bNOI~?tP 7%v\(<}X-\9ZlJ[D-Ib)`*h[uDytQVGR[QS%$D)SsRGz2P ?= ~Ej)v@q[>̔ >d'N [!~x" d6apO^SH-(Y{. l, u@_.F9Ruk qJ9Z&#\$5۲5H~*$(s BPy;Jiq-(+T5J@Z0O(-L8onꉶa+"!!UP \Ɍ):&’ң楽"[,Ƚvʾ*u7zH; +%\d] 5W[lƧ'̨hz;Wb)VY5'[ {~*cLu/|DеVVswyl YI%qxl=?m$bom_vlYr9j4)"-=TV9V~|z5VX,QGd O좡2r"7(!W{⭨Lxra1 6k3e.Ӏl{48e>ųi|ޔ僭g$#Z; ;Xb~vDsJ9fQP\3iM ðQtا>Ў%۟oe]s8Ϯk%?AKv7`}{E~TrI\^2T;lB` ڷՑivCo+-$Ph4h)z)_z\w^0+unNV&?U*ҩS.OR->&QDN{}{q]|<쿿8X}sl_-U w2pC fR9οn)f0JjwGG-keߔ{tQ7n̪=`d1`9SNC/H-"j0V6A 4/pU?p+4,3nfj]1h%a"~M+"<3x9& Y ʊ.Dz\3|[08ֱsA/y2g@k9.0",]H~J)La,vI#"ubkC?@7z8umYexR {E0eZF.e[F<-3ܺMNi>rX/l-t5o5 Ξj ?#"]| BRJL0/y-κP 'hewe/Y$XyxGxi գ x*lJ n3rzV0UUOJGM*U6FY%csKE+fC㪞U+j/UΏP@,*+LY4xʨ ٥o-|v埦FCowߦ~hpN9ZJx~*j-3rH;1*rA_?V3Mk6ka-4[NIT&晴h#Y<` =I'n^J7ö_={8ZMvFAdž,Gw{ sstTnze46UB[^+İ׈Ƥ^(9üXEKʐ[Qg,A!&Z?_Ҩ(!$3RX6 . +zj[d.Qwgisd)F͕A(ώjESNQK El8srT8_w03AzkGDR僣7ػe/iIzi#KmWLbsР"Lv5".ol^]UDq 0mȶ['{Ut1X0z!2q}G6H LwK`ĭE԰Y󔐒"cARDzP{י@7L#wӍ=PmO~oCh#ΦN nt z6Sa6FmSTi^=.XEd/١a;9'?v!wOz֋qG88[X rP~$6U7S0iuI1)1w /<Cљ'92,5zD:JTZNj? 4 ÒʕT\.sXJ#cW> =J{t;/43x6 \BPG3(htO-?VY|t9쪺r#kπ9yTX:ix%8 f줦3m>ۧA / aG0U~˄N~LV\Z`ۡ!nYf؋'{-LygDZ0V`?a]Gj+8ȯ?>VT*GU"P&80>$ˆ^بunդ E'5%USlh"ó66CsvD $ >{bgB򜄝H aB"⽺G]zyc*`'OCU }*$RNAa&ݿVoTgp>gA﬚"vjN}s/0̳X[E6 Sd`[p1Yv&_c7u  ֞u|΁ԎUƭyYW/࿋)fյ*;iP"8PLb9y_BK_*W dvlʷwg^ʚv߅5a诫]T)+EDt6ߨx`9~]Z.*FhkqDnwp=3ϕNjtdtٶ`8mUw;lxzG+v;TabA*H{4]SA#ofQߕQ{0+"S!lSLy߭N;^쿎6iyR"|&E7JǙgck&5q%*;gGjj5ěD :L7ݠE6c"Lv^bۍZG% h9DB].Q;l}8^9QYNjI!_ *Eɱ\S-dJ&ȅgtRܡP{ɺf;A72^^fsT<3vXe6l2'vS컳{Eh׸'Cݵ<k":U1GEYCj ]9x8f4B\x3q!1U |! tK}X9 4!' yw yP & n`(P F a*v5&$#)Lǒ]нhaHj< eBL<3x&yV*vNfJ9#HF_홾es0[,nd' 5\lfjĺsˊULGE1f :ct/.˔U3btUSELX D2Fy9t*ًXR"NYҸV'knus81w;ǘd2ֵ ]4WRNq>yy6uduO 쎸P BhgDbj=QvA fn3aS`5|rWcQnc>M  8c{'tM_+7ƵV`>u]#IkgFĴ@8"gRL{b˱ \ΧF&t"IGS^^Wr?T|Ij؝5+ >}вqu_Sg^t@W.TˡZyM*^+p>:a۫NQ76X̢`'8g-Obb<#|5NQ7WڴnNђJUCb{pCxZ!E7$TN:)a`7 -gIv6(d9YŌqHS96M>NTP7f5pZ6NL8z-SuFMP8Q?ą«}e|C䈂"yp˄k-Bn] _v#1B2f׮fIBQ(}+Hl3Zx𤋮u<"R49eFi ZY6_N >JI$*h{/憗]9~)1{F6pˑ.p: ϠSWψHU45 mpѺG =,THzC fFJ͝zsLQ%zln(,[$Z]ø x,I}K|ާTUnBX&Oj8>7Tvf9LBU6lUpt\gP63`,FiMr^ިxbwr OW;T^C|78LNYh뉢SI3ބLQAn 'y Y1:/A6Myh5:lk J,!CѫpJxm _.ENYxnAp֬lc&$WH9OQhG⁲ɶ*2:+?&HJ0kSWH9byuԭ'ݗu˯9놺y̜Ot1T{?}c1aj"!Hh )X@rb\*${lah񱙜(]s^5*q+fVH_([k|aKs 9ba^(pa爮bdHt<$xQi\B܀uM6)47hr YqRl<|4:s8S2ׯ& #J3L~(C&djՂjKtIeG7=h6RK@ы7j 0.jEEA!S%2bRmvPJwD+Oʔ0pi\TV*tfPSN6a0QOP;܂z 2s@c5oIKTۧꮐM HqcTveg e `_\MA6>Eڍ.G3.%0w5fRf:MOm,?y> /GO!cGb^14Bf_LѴ ?([78n'[4;."9g6c@~ )|"6~xyΓzSC]Ǵ? "K_56?LJ=r/%YtTEmU_qtRyƷ " a,dPC ޅkc^yБ:R^_[DPV=UI4‹0s~caxژjI@ShIK 3T'-<gstd@#\!muKbIY;B9]x(àV尼w5ZkhdpNgđonvkpX (waU-ܟw.56=K`Z("uif*K_1idԬT0{_Sw\B||ss eRUbfVylyŨ/Y0,ueROBi,ΌCN:qS>43 cq B0 >RSoMXBM`>x_ QSK̈NS(qh Ã=V%Br,7 ElrZ+`jB]g$k ']&GBE$m ֫9q u,)=ټ\1]/etws7Ay:cwυf5ƤF< L^(7}+'« $EmMʓpQC)D%beҐGG~ώ萤P,;0&uut/Mtc8ΣPϰQZpNJz-U MF?o+ӌǚ7>"OsV4 &_N&~"*BgE15 7scC`?DԐ+ih=q@1k K_%^|cTWd6!==Z\klFr-l~{ _f Hx˴EM< *\NFn6c\0/bCz5hAzLjᏫzP#RFcG?vxĕlwaV ?] Z.h_.f:%LY|ĆSw BMP'R|ښ̺O0G |6' uDfE/m̷EDયZ7Nj8jVϞ}l7Wz\-gEt6 zXk?)r93)}jgEabng=F(վP:V U"k:"^y‹+euZk<~bSާ,0ux~KޫY?ó[ai9>$w).QTet0 jK 4nW\D+|8L(FRsls4)s|0cyjVLJ1b*d~1Й!]*❴42~jy5=B4Hyx L%u0GO!ӾKC8P2zȿJlnQ_HLЍ"}R )Α&=V#؇_88%EaU؋Fz}RdmV#5h=ĆeD<{ |)dMH\tUlT,u {Ѥ^, V 4ěC&2͙l\}i 0S+ދH7ʃ{2^& ^蟻,D39:1 0>yGVJ`4tK-\(79f8kTM̭ɞ3cnNsSk%Gqqfc_% ; Xd=Q\CB#ѧ6`(9I!8PƀR%4žx<~=å\<>>wK:N%iS3M0E}V~#=Wl۫'݃nxbynQ19},B:.=!G&B_]w} Z,t޷+~zxqBJÚ_qPIλ"[tÂ3}TO`pڕ\zII".i(_VHާvĞZY8^m&AɕU"U%JW:ﻝ-SyQǧ gJ$7;+8{)EŤ9HVr + S~Ov3C|t$4๣bHNPJ9ePgzeöHȶߠ7?Z\cda('>8:gb=UMg S*z~ d➣C21Egw@T۸ ><{gZv۽8砙:q&lBz|B 8I J=Yus~htb{+#tľll3_w~ضrR5I& e^z+<u1D7JMOlt@s=Ȉ._aMºaN*igZGYXabuK1iK{nO?کAum ̊&Gnr5OGD{X64>8&l"P ݮ #:\O܅NKۀ_6w_PYBEUBZj>=vʧc5PeiEc{6+em 4>7xEVo|̔zrD3&`_=p_k@J Y~uΡf!q?ֺ ~hw"pxvC@|K+`4*zZKKIfˆp)*y^|}@'&QYVuhz#럙 d{Rt|ЃY:nwK+Ⱥw+2QX˝~ `9tWt{H0yT`39O~i*(Xy|11b**"ы̄g]۵fⱝ%D;qaB!+ޜQ`>MCG2Q;Tl-'_<N!wa 0$OF[/<7/pӗ1N\WH&<$\p,?0LoD,H?O'BdMyQ[PJ0Vvt('adՒیPG"Qyko~36q$.0@B(ŝxbW^/>0o. eF=!ųWt wWƀERP)+t㕭 &8:C4)8s1 Pﻖ$} yί#}~#|ūZ<}ܲXWPOg^q`$Lm6ӻDzcR!:t4CUGT7!h{jiގ Mv3# S Zj|炈 2 ĹO`<;bk؈;2q4hSOy_OHȨ'_ra" #I.jY=W(|1;3bR+2ո&HQR=bޣŘUw<.XϽC럭Ff _OGޟ.N{}9 s2 1;''Nf+vbVy->}Lpл^mzIH+b88_=x~Ǥ#k8VJ wl{3AJNUPy { LN5}6of+uJ =n N">Ɨ qbN#3u[Q+s:Wv=-E O d}Y*}ETYnIπ ?a}S-BL$ Ն#J+g{{U}(1Dr儷T HD(V;W;/LVQ%%i|OS7z}7q}i޵z]upKv|8?K>K@pVXWZBGs?\)0QxS΁ |V_on9>a3~WThMO{ct^I3p(=mr#od QW/_fPSRO3o҂d<*c0<'zHh< bd^e ^+"٫WP`0s)*6CUx/kyQ=1 7b&pe _q2FB=zE*ԭTRj?%}L:K]~I4-V˿>^GNv0~Q#ܢ57{$ü$}]O^4ALKSBVa|~ HFr0H~@yNUv톃#cVdɾtϳrCޖq:\]B45tT]ZU0t%)rR+|dz{l]biohW77$j?LCw'z?D?<6 KίIsouNW-MiMu8fhS{0,@ /iv ?G7yv}>r~RagO=Qٳ1]~?\qh(}!-Ozң#}Z` ʡ3l:gS3 0~j<[Ё z M{tx|oJԱb1fV)={-9_g>OG/ ߑ1tΞC7]X#Oj:c6-W0zcPz(Aڂ/v-QYnp?r:/oCsh4Bqxº.(plRcn:TA=:Ie!^ *&#-qdmAα%k׸S 68lPPjgtrrez -X`O/0:hGFu!r6gvPJ  )&.^-y>@tioWq˔TX,#4/|5Eok8Rfl`S "GSDٙX}wЪͫۚ#6L]GW/j73)I]<IVw ,ԗF~mP_%i7VF3*T) ID SWUO\t( Vψ^(,ȼ(5+AF9IZ{yxf݉,HT17 M Ub(0.C~(g?AO**o8Y\TD=ý6i$(_Kq88&UZ'? ^JN@E!z";H6/ [;W0 D&8t0q8gRW~vOǖ3%~L(VTÃ1c(wZT &[`fm8Qzu&oJ65& }^|S=F0Ӆ %}0Qiz~캣 ;>QA{S* =[9J-\]P平^1]f hd1NҹRf:_"T;"Ї̇ \8GFs[I': ^^A o8? <Za/tyc5w%JtFoKzz:A1<e%Tphi-[ UDpw\~x9,?äm:Rhd*ʽUˇA hrxWNTT !P 85G< leer0jc&~}RaO/]ԥ^Hۢ*-2J g`~"ӡ XXugX|4rڲoGc{fہg/H`IT>T_j%ZxH\%VY">`:G[%+,̌5T1:(tvxOt gI|xwZ$TaNH3aK&ܺ;ͽ7,Ji@z]YaDJx<_RE~I }=g׷${˞u!)uK%zRG5$2>8=P<7<.r{K^_@#6a7Zuu ~m~ f #k& vsç b\g|vs\܈K u7mgW٘; 2'q|MDJ8ϦCAxPD]hW9@_bϔ8>ו竐}6%09t B5/_xUkJ?[-۝F{Y\`0dW2\3 \n>@WjMgB./>X29e0]LFwƳf^dS_JQރQ.*BY3+{Ë5S1ja.vϻ/hRg;;N M(RgGGț^"ˤę"aТB,'B tD\2(AF 7;V^-I=J׺> pxQp^`Cd`oaPxE)+}3Qv*w,9|jk4ۻA6l:HE_A83*$i3*T!(DtU1#ZrhI5jJeuQ5a<r]ɇ$ ]3+\_U^/KssWɗ6 k_#k-Xlɱ6ogkH%7.p0;DGIl|#F)[{Aݥ n\Qlnp;o}Rp7N|q_GT)z*TjIUJmQv (m4D/QO~1/3t_m¨-tORx~i<E ^%,͐G~j& g\c8[0<]BU*$" D JEWӤ!TstGSvs2SfViAٗZv"ǎWQQ+H71A9L(m]ؔjMAgPk*{>B"Ii{+z:93> Om5ӃE!?''q߂ʂh(MMw֞Y m]&>idvwlQ8Z]ΰ[ W_ 9Ş:с6 6U5ֶ{Q3:7ųf0;Oh9L\'I߅p=@ KR)(Zԧ oBZEh8X~NkG&)73tz*a߸}/ta-r!˄09MԬTT"鳆GR' / *G2 m05ɷ_%GH(;9tرƅ}[%cn {>ɿh$>Yĥ-c쒎GuYBmXvn6ZO^`ϫ RV뢣 c3~3F~M8x*iqQ.)/7p=8 jU4͎;h xGZ(]E { p9i\PQ=h7 &ʳ{n6uqVwh,wN6A I.,$$pKpkuz" ua| # qc0v2bF<[jHJ[7\c>XWtw>Q@+<{昲km/}z> τig0.Tq2U|掙C%10ߢnB -mUW0Bl7ܩorD[W~vXό#S;rAba}pȤZ' ~DM̈́=`_Bdd =EZkmq+Q-#lTl΢E%18vI?_ ^G|Q+E9_vpuQLT&EG\>ۚ95bC Q[2#Zf f1CB7/}$U1l&'K5B`kˤ|:TO޻Su#S\@HNhY0BG*^SbD<-&ThW"SGѕFbRiķH 0Ej*Gird‘Zn,KY9Ǎz 2 l2MZ3]C\#R3mo˜qSj2µI03Jlo:MHI7΁ QCpv~Nבlni %nz9:ᘿM-a2 dGPD1)1RsY6^(xcwuAB# K)p鰟8mA,v$6cxDۓ,{.$Cn $޺˾Xm,O5ED2ipx~zky|>9x0Z:÷/8:L!HD}PYArN( qש(32/:'/QprIcF0Rpt1ɲw>LJ=ȳq_,[nBg*G1]z/ 9 'e0p p݇sby@*DSs!4\nT=O}FvL\f4r+?Η 9zB~>Zr4/9 *:_WHP)ڒK=ܦB{FEYn ]i, gotXN#>4| s_z] &B&lFMsH1Q.w<r(du Ӑ\yeSງ?dO]h{B=NOA;rS>U5Ԏ;i̓΋r)&I {H(=6aB}hv^5I,dݐęAgwt+U].e\DQ| 4<ar2#!O 3rpf&Kd*Bn0q^|ZDF2 T44oI~8t [UK,*N 2 |jlVY&wP+'21l6o>q0o\_ȑ~BdC w~P;6.uO?rfzQbv[@֛T]C]h74m>w$iG(aše"+ {A)Fè#TOoTpJn{4KE 8Х_ya; `V;BbM/Ýoo..9Γu`L&Co4uO0PN3~w{}kU8cjcɚ9<{=ߔmmJn5X?.SjrjRtlhS ܒsh&T026r7mK,$X28,;v.7SbOfǰI 3ǤstȘi8lerVniՠ%dFN=x0+qQwnC \Qkģ6W\M]Jp|"1Q7BlB Û[yggSw Oed I ;&:ūkŸh[ H:a]Ujzh @Xt6q֝P3f, u%ZLb3̓{F· ~p/$9/P tT% -?aأnM6GEdWh-;V5IK¥NC3ǦpD1d$Ag4*!A%:r60#S٨ŸzYO*Wj^C!2~V`kR /_ EwN.\<_, `J/6d ;K^@n5=3"> e OpQӽ↶gj2ьH^y$ ,t,'9MzıQ6YN,&:[ >7g7@54o5Bb$8IqO:`gv©;_ ǪX3\JP;l2:d3fҧ,}>O׏#puaNomJbv:FTKDH[KuTx%,0ƣ鰪d9Qx~2RPh*QǤ%A5YͽOɔ\$JuZbN̽JM' Ӌ@@9i1PnR=1AI]&]2cnh68jӨPMgYR~S3[V qgg BBVK/dd5=4`CI{k-qZ<LEio y0# Y źG)Rf5 ,K$'ڽ<*:H 2,H0УvEnLByd,bc؅s|ZUl:]6ԭ 5,}ȝ':l&AeF:8K[y}¥*G9Y]r,3Y #,Ng7*Z${uTquL+9 KN#Ob3rŽDӹ-dMy'n8tܡd!?h( cBe:(Ho)9Vt2Qx9񧟔YwhDvj4%p+J{>i3gS-,[_p%Քb.B]5m9;l`&5h'Ɂc#e HEcozϩ"kxUcn~61OZ m{SKq-d`;鴿B" ѝ0=+IF„.c6I{y{w{wky@ ԞMY$bh=Mڜ/gTES,S4#ʺA%_%K ti]Xe57'4|p4Щ 09ޡ$aypq.Uy:>WNx ^H~]Hs"5!3r P>@%}άIo $+/Eʹx@*&OawQi(±+ݗ._Oˊo+gCG!Cr89"z{gonγ]]0+P׻݃4s7T|bkG"n=LKM; |{9ﵹ~MR1wKq7m7veF[9UP%ц#Q]/③`d9$-TORdY!80(].q/+9aلfxrwjGQQ\[rkK AXr ί BaH3,K[ t{Wj\;(aIK! Uϛ;5 &d81hb¿ W}`yOx ï4RXn`>VT)T&}7{k0O ""=$uu}@LVthr[3L޷c*tӓ (gL'n%pYXzp@C֛( bؤCyɠ'% bḑ a2pxMQSd.*D$,Ǭv)[sQ鯶.:1 Y]Ԕ7AWn3 [ $'fa(ﳤtk'EHKQHXky?T؊õ&)/ڔ.BɒzIg?Giarұ*MDwHI*8}; ?%uEےo `+j6ػL*t! cZk3m~j:Z];FZ1">YEG5iZwTp Ha d`$5$*Pqr!t3ȯˢ.'72N TE)U{#|apR@*Z>6^5"['Ibˆ@DD$U͝dZ Hz.b.7~If#VdFJmXb¨nG&H!K{,TfH#P?$GLJ;qJV6Kjrt8j2(E5K>8+,.fW1N T#^:q@,P_j fC:E˖x]9_BCTZ!VO[_o%JndYq\p҅KfC%oUƸqh{qH:'O~|lmllCsnc>m?)dݱkըDseTӋQSaoә7X#1~ӑ3MP/9 C\ $yk l=@l&<,иEKNfdoE0?`/P^u᝻,=4yToT׹{f~hfqNHN(J"1 ֛U~>pyG8{L@?~K|>I.K?grsvOvVUFXw6n?{G՜gUy{^PyyRқSQ~A+y8e ca6QmB@(67M~Y\Щj*S$l)xRD!b[5Lwg.@v6IlG%48,-JpZf7ZSt@D jDuIBx빆;fk0YzߝԪ]A\c?۵`P:2[BWX[cZzׇC inMoos+[ULDq/R3} %\D0LYgIN I9 04\+ܔb7Avclm{ĘDp|lhP!x,+Pӝ{)]:?:nA)7‰iIsdɎ~WPt[/*Զ[AJx [٨ݰ񓗞?7d mlCnBRVatІoyu» ΍@L= vp[">mzi}w8u5|:12Dm&7_m( ;b6*bM-FSS]%yx,$`Y:@qX^t 9C{e O -O3jL 税p+iiׄuHugajp6意*H|!lA&|^?qJ4j&UƵWE)h?;BGUp] GL>|襝KsEym #ܳ)!j[vx:mmv.l(gm0`rGwI;3:YR Kt84Dљ ɅVdD"<o&N6 OJ26hy4,~D4UbRFla &aX7>WIkN=.`nxKXc>\28 t30ނȆBrKsKN&ٰ̨äFW"DLt5M;ݴЏLK]w3֦$Wiݬ7g@T_a`CJyזփϿxpB Z.ɊD]ł?+ IPlA%O?}H)V+V~T#-;&5*Ae@ G(U.8N$]ږo 8giþ/jKXF'fNM OǕHdL$ԏh+&!/kh8ۻ]@eUΕ$r #=bB"8aӌB JLXbeMCKC[ZYWvբUJ/j"uRp=vwaltLL28#p 3i[!.qhd`52r׆q2E^ * yѰƫzwe<'* bwS*lh?Ab g"n"n\XC"T=n(ʶNjA|j3[;ٿ0F&} Jx;J{i. 2x H7g c+ ~Y"ۦ$ME=ؠd(`C=~}5?Gu^| &˿R+oJBtb:ɺ\2+`;$f nLfkxRdjBxQ}RS.Qo65a1G:Rvے\L8J ׉D&4$앎Us ᯰQeX}wM``a]yF^UBN :daMm6[9: 3\ x_tW.,!c{^nIN ߧHIDF\4F; kLY9TxaNT8Ez/=!MJQ[7-RJ@9F(y" *-G wRK iV8E=I׉懕e"i}<敻~_+f9;2ک-3ԢuM=1{OyWgӀpG/9;zq4'0OotJ*NZRh';RBSCsԽn*xxzBw9Ԇ]^VGXr^`T%}Y@ߒVG~E*axcBB ` Bg66\GʻIrJbĀ+FF],-$%8l*S|㠈E]: y`e أǟdrSiI54ٹ@sB 9d fR˒9I-U 8lNTg|B]s\uJ(e5kXȴGZ[u}:NWVS #ң)yޏ7]pm]Rĭry1 |lt?@ʅS"O5zhW u> _D ]TF@hKGIϻos <1LYi^0A6.B4+ܪ9g*"b*-}NޓJF%|HEA)ʡ(?T;QcR1+6 Ğ(-74VN;&Z0rJUm_s 3 #d0=iDwԇUJ VLXdfG!>9?,B৺j:7ǝ78T!/ s o7AV|`iRTQ\VI1KGڴ4CNҰsqҸ`lי]K풇F*{G ű.22&si^gE /Cq S|usz<٤՟Nm$]d ~t5~JM[wE2YsĊ7g't" `DfsTQN ":x0 OٌXtmWΏ@(2>d  L eN_=Gѭe9vpo>~ e}ۢmv{m#sᙿdߒjϒ6T/ iV2^Djd%L) ~ Kt~ʴbr$H/fx|ZD_̝eV'%2)6J*ĽiDHEf%W7HCIĦLxYA4,6â, t2xHQ"QS<m>+Nc^eӲk,?o//s%fقZ9"XfaE TA {ȉ+cbJL?󠹱s@ nCfRU4 >g(B!'OjT)eiyKX/&AnGոݽݽDј@B :Ax/!b. K^`}RfֈnHj-(&9E/'o)wVo*SA`tꨟt2(zP,!HR" NSw#gaԘy:EWBD$bn`4xY R !C E<] 8'UҼDT 5IVaono-鈟p{^8dΥ>V mPL|MR{w{8zl0_Y+sCͅn *¡LEuD >=?|O,IG.s#.=ѱ$SA$VTD  {ZTmVbRػ'G٩iv'-7UG0ßHB5ga6ûUPAJ $ 2玑  Rɽo؍Ll,#0AqsM,mb &ze޿}_HMO_qĸJ<08aB+( Ӡ@+]%|Lb) 46 G$I5ᰔ6XLA:tf_~_(zBq+v' _Q5Bp΁aXzt>%Au s.kƩ6-nm/yQgY̱SHeHw#1nHS0VS#fФC|2JgȢ{ =76:lv ?~_`f0x.uFh/<ő';z ѷAM.+*vci{=0Iqn쮿>tUuAѹηMjWY-m̑3#\0]Q"kch1ml)[Ӌ?@uBAX9F;.v<5e露K_E Ui'#!=ulJZ‡Nmqyu ߅9D̸8ͲN!/Sn*T_^1vvk~ÛDөqͻaaWh ة5 !FZؖ"@쯔׫5(ی׽sDD儝pTȔZBOi+xS$mpPSʠܯ,37BSs |9P«*aJ=lp+GEfVVVJ0vB2la ?p);;A(-0-#1Vxhٺn-E~&XOvg<ߣ$ VEC捿QAM$&rG ~L'1 Eʍs`v:hxsޞsҌ{'k+M1*dK<_7[y=Z*y_&k]NUVAx"^ 0|\ePp?R|ɹ3 9zK=A,Wbv:xluחְ!xxFt^\ j|W^gxɛ?y_9ygQw\AJwg  rPuыlZ$)WRDڛJ؍v';SǣGRnKΙgjx`xlEה%MOgx} o.&;?]pwNG+g}xm~/5^jKQ;3kDg4l}7q^&/_ /'3 h:6Aƥsyo(={wt9wvDG*clSh3yڡV tz 9 9AAAbW^41 JJ#s( I.{KU!u)Pڕm*H 쐙A(-,xHɊ$ѵT;X ]6S]O`MmrxwV]^$N;}3U$PNgW[}~zo."6>#՗k n1:Yuf;8c>WہUEHf7}B)VΕwo)4w{owz2ke^E+8ƴƴcB7f:]ԯ/01FKn=9pGzZU݂-Pt,8cD_iwtwyL,Y-|w]58%L&A]/inr#peS꼳Igi]̾.1Y?, qTG"9sa U4]mmȖsAN B't&yTˌȏ -X'>v=_g`lk0ј=S[~.Et7]MlƖ~tΗ`3H0 3~2kΒ#.Ny;K4XnPGDYeItpAXd|J .2I]:,4JIK=fB9R|ھ+83Ůu]up$k_?vsFF\nVq9P+6eሃqs3elscO~찤YPe3~szz0Tc,8$F5G2<1dH( ]Q<]߿wvwІ8TҼXtT0`۝vcbUp)79خfM7k H/d =5"aO1Cr^Bx$g' :PsjNw{B+(<#•M^ť-[={0HU1{Q'03޺apjmjJQ0MAY?InUd&JhT9{.+.J{~[X8K.ՙ^Yr5Mkg@o*\@OB"(K 7CZAu@tF U L t渉C գ&^`JeQ(g+6>c ;s 3QƤ.M?tcj=擙3HzOEbSJPM5wQ W V$*OfQL0#rTU\CSx&)íȶ`]ABdvI\ Oza!O ;՘ LCٲ6T -S47'9sȡŁ  Ep ?d#f_-?dǮ߿vNۓC+lv=6] mWPd+ <@j 8rMiN`j\n/[qWDͶYL̛neZf(e,{98TT\__Udd)X(+ծ0₮QXEN,lH96a*L4-_[1ضZ@B&l +lZLD Q}< &@^:FwyReM$ +I5'FlZAGbLCPT,cEu}-X$c"gN|nd 3[Y|] jwЃr9- v@sixl/@3*c^C=qپ5)7_bi.|㡃1d툥\R:"(6Fģ&f_R:M^l'5S5,2#"y6dvy/VJxwZ"iCrTF(ue z@@&nE=:@c5gų^ɏ37Eamۋ\ 4l\dr!G>gEXGar dhS~V ہ<^u= ƬA~,:QUi)qe4uA'BhL@:jbdݨjf;,0.?(v:/[J GM)⁒ke[ ={ SE%PtXB\A.ed,i}& 43BNMq((c;PQ U{i3OQ( ݄A/u|im+D 9 dVYhu;a|FY-V+v %L$\%V bBC%_Yt7j'ظX F2ov)! A-7vU` ^I 2Mܚdc2/A`8ޏRԘ)'d?kn 7-m \؊x&2KN Q`F)AO$%$Hr[-CӇE nRr o A{gw,.5(A_8SgUr~," Y.56z F *X`Džr~'q&x E4&r~.*=,"íRk;#UP@rR]rk9UW /u/s^uOySD)r FiI0*\Zջ94N'}32v37JלڕyAECT4>y*j0VCzʡxwI?%.3Ol(L V&J%I)lY1Ұ&'{Dp >|~;Djb-K%+..'ef cPP{/*%hSRq1M9"׈㽄6v%&Ϊl H ׁ\Kgc ;Q&t&P÷@m+=w_OGa[Mwytբ.g:7CmE0\MVM)ްIL6\ |îBN+x]eÿoG4F4Nc`"v䜐ְ\aoQq9Pd^¹hf8%*$}n-EԀ]6V`38sNN8/D|Dnkd \|,X{N6O`W:4-*mG $g%jMgCΐ ;fFuBәȳbB4˻,8w(Нɮgٗ=cp82p~3_8‰M秳bXhfjVS EkC_N:n!5ҙ[Y}A F? ;$0|Є4VU!RRX+ gu%]r߄X!J%{ h.$MYqMmۢل?+(4C;Y?..Bnl Q֡x1JR5ɹp1E/([I>kI;vLbRy| K:4Mc *n?e3dM&.bd<Phr`\ ad2k*XOg|pg&}R(*, +N{.,LrgqA>vUջKNgllZz[~Nީ_^T'e&\,zֺcWLζ8~VWn;h~{?vD GE[_(8@5[֩cYd"34$ذfT@/wdBSM+'e.1vS QN$:Agq\tDE_&U+KD,PzJ";U1#-p\uew1[Pu˯S` JP̙؂&T֑#;٘&6`wm'kD·BZx,B*\8%Sp)azd?\O{ 0r;&GS[Y7_|lg*u5~9?Vw N1JJt6qvT se<wқ%>z;}}xZ@f-[ԏ4Odg7f|9GldĨk9 KrwҚ:R1=n8}lf;铀?$GU+xWVurEk0}\]̪h)ͨY[ږhĪVҍ=?kl:!ɰ&kEqWz_r;dx*c@+d!?TVnMgA5 GЍPWX%$/uÞ0H??s=bWֺ6 ij~t5q7 C K$GU Ik'iP4\gK iBD+MTlҭZ4Vl}A[v]{W*X;lN!DNBfUI7psu{,E4," ?oo'ݮku[~g߼x.U AƖ}=} ~?x  |{n{ަ}~{] >=wpM`~WW~~z{׽ rh84?\h;i ӧֶ6b!?͵?~ ?|a4ʹ]o_O?~_*ˈqSm4%_k m_@_M'gs9FzCb}5Δ}{|ZtM_R5o/z5o_7T`_կ M%6My_LtFoFF;ɱ鮠 UIe_6HR?&&pj {ͺxpܿ\}W_/YvN 7Ȝ'j![I"ފy]<Ǐ;џ_D]ӒgNƄ5P-NF~6/:S&~Kg:~5Z@<`ZxԱ 姵,j gs67+vąU0bB qJbu`mh:#TX޿{@#A! lZRqΦF}MKGev=-4Z@^zpfoFT3#UOoenle ?ڳg u?[T>sC9)HTg_x(K}\_n5E#%\`>O' 4֗ {}TccKTp˸T] ~3ŃgL|R;u7r+_}y}!]UD=]jL'8Z[sn{-߫y?A'S k'a_=nw?MV!8Gjֆ v8dfsfM)?O߱kp(0d߳ 8 wkyKI}vA},wT㟥E/V}|QWw~WjYO֌WP?TqX@ 3" vT\APT0H.8f|*cmi .Tn1 SQ1ڢ@q#M*.64L3 u< ZU~q]ONN&1бG3\l`sD:H@2鮶g tIH!+r s2 Zbv?ဳރ%8Nui}Ǒ"Vr ]u9.>5'l+8[f pI܊ľKH[1:8ROEmtf؊Kj(P`1#H&/3 @ 1jBX1 ӹuG ƨr";\*9.ȟc;Pg;%0z!<.zLSU<0VBIjU+MK zx!:&DA?Ax0ݶʧ_K?d(T:,˜ igAe nR$"nٚPN+̄[}[MX}Eh&neAX܃k$cڰM^eB(Yomg2 cWn'&F\D_nSΘIA /Gx͏ lQ<Q0Cod[нc ΁AEg 7PbyS@1@X’σ K@NUG|9rTnZ 2xZALep6%8UJՑ{з~A"Kš&̂4pQ*I'}4K'upyA4 {n ?łDF XUy@til1+47]^tNi3)qx͐Ypj 焏_; S2=S_ĜP1F 4 )thi~uMGPPE+f88yOGԩx4O_֏:=SτGs&/'vM| J 9Nf 4wN )3:Вlʹu '|WU W@(2=P 3 ;]Qq+ 'yP[I'cAED n:7ݤj"n_E7G[KF[1#SCU:UR)Id2l{ԛP8_Q jEA'=^g|aﱠ Y8(GweT NpK$ &\`,Edm:i?F5tps{y d0>d `A\2f5#aThS&cN2ɠm%]]m HL&\-bZB;3Ƿy:b]1Di2rCd / Xxqe93qK ^JbX%a{&SGVj%c5VoeDa2f-j-4zWʇTO+X"Qn~:( db)#8&~ |cjY\H9<:O Ю3|*vۆ1z,`bmwRMz.)+bǮsO{H]#1Yr.Kx;BD~TW!<534·U)G`, 9'ϽwGoNdWL1Q˪'oF1dUgh=Y$12/EɈT /Cl~IRҼJ޵k:&$c )TjZ{e䞘`T~;`SpU3ƦVQ vl' eT@aQ_WNW/yc}t x\"9',4p}:ۦFpCC.YYkg(eD9y +="Xuin #}f ~E c EvN ]RXܔ aՎxh X w;$&6ioXϺpďU;nnL(Dl"Z,m!kl<0F) ]ݧ?ۙwUr" Z9bL )X-֎X_K#0b ʪ2.`1to'4BL 6U} }VY~fA\?堊Z2/gT_lο̅ӜwAs!4k(n"[<Ѭ׿I(tLxj^XD9#*ƝNJ7S:XEjjږ}bôRR$-l 6 &)*Bn(z#8uvTq#Ի|ٌw:ف.|0|+¦6CX7n!I ҡ^ξ!0yӁgeD` o5<;Ut@5 Ծ|@Tq/źʃhy5Vg.O[j| !}BLz- H~K'~ԡxXO kmD`)۶'?_osuNnc8HjeɿN9&%{Jexw!wf. L,TwW8 %Y[]:!~;GYp:| ^fͦT8jɢH6H^[_Itn Hw{=LDhynJwChlyr;X5f&=0ޘ#4]0uHtIRRz)ml{[%O tbn+4uvZΚf:HYRl֠e#2ime+  6W@$;Mk:(eHjDJЀlgaFnъJ"a߁OGT&4rr[Fw|ﳍ Rkt#yv%^GoG;o{ǎa6%5;e 3{t}y[ەe 㷺&)CƳV0 %icJ,S%*6Hzs+q@] #:FP5]b.O3vB_A,^!5xAAv/'m?ζiq {#%mGS8c/0oJ)%%MG"#w n¡q ,n&rTk'b; ;oU`׬$룓;9"  0xzb[ O+濎r!>2N9Cq*BI@I)ϴx_q pŴ@W#LB4>.L[7u<'ES:+9)ѓCRt #4kNfqSXvy y?MXYMz 0*\kkWp^]k|mÊrbT\ݤ0VNQGsrυi6lbR"[WZu)ޟ9<[]6C7:Io:X LkKI^ݡ܈e:Ld֠imyFߵ$![q'_c͒)ͤ *vַkL]ktom`0 ns6nןom"nn];r]z2G?{(YwLCZZCzxПW>[_mdwS:Eca\`n|~Z]qN& T# xS.dcN2l:n9Io1z]cؓVO%gg>0178 '|\k,;{\Uqd' Fx5_~ ` YB}d*s/Ly(|/-?v( 'OD?3dnTs>[`Q7ǏQM΅##5ą ?Ɛ%Rbx 64.8 )1T`]flOX:nwϮw6&SY[Bl(u PrLr xf|+7;KQyEu׍խ/%۴gM=rۿ_/gkuQu~;[n~}؆ =~l2hBQd7#Z&$}2yےS9ǯ3h:aY ɛ z[|zv?ok7m_ݠKqilgG#ꄖ ?b?+^'nR7!|g~PȠ7,y):-8ńx "igPK!Ԅ,cSNÈ{tսtLo:YI!\Q=" \VuQ9&pÌDI=jl}Bayn݀=d KF)0?Zgn?|w{tN$ }1'I *swtbTOplhEp'T)@ .![)ٱ7*)4 "sXYI`KGj~@wj!.wi<kg TK :R ]dFJy)頃- <q,b5dʭP Mts-xBr1 OI8-Wל4/?(ϗ5r4<xGKgY&_89eb`.:4ډ&t٭[.@A`U|\#5GɣYkEM-:#7!$ԶqÝ7|X/pyOm1rrT" vٍn+8_=ƢIF#gr|H< :d#eNDfæ  xhAڽg.">[dK]jyd$t`Y[86 UǣUNnbK-͊AF^d.??{dOjZ?oh~Y7@zl e>#F$s~$3-\ *hUZMPuA#zPPX0S ?"=nLLd3S@|.bԀ({a'K ǿ:Kk \I$mY#0agI$ ~{ײ%Dʵx_" `¬(1I4~x[ oߒ7H̿ 9~=*β;.5W<0NCSaHIjGrp>ů-veg;.96`@hE?єÑ+ F0bm0**p0}y7뺴nU6 ksj+K^I*̉m8xsYiհRq)rQkkIɅGϧ ~9Cq9p9c3_,p#B;2K8p{Ցܫ+#uepn:)5DE_*1􌜩!R0Q~k^V´UaƅǪX/nG'ʐD߶Q;ho0MNayO&n82,G9$BJWqv$]P$ccI Rc8c1ma|1E.pktt00\mekVbW`*3p|ǃќdWwro+DAe 8zrR> *zҌ,ECdG#nY]|֩qdžGH‹A)%WbO1)t N䨂!$.VݽWolRTR~#)<[7sG-r`sek S\b(ԩ /XjL}j=Z!N"?Ƽ?xSNevoⰤ 'K\*'ͫ,.Nld#4|kb;|E098=AwKw*muB9N 0zsV؎TzzG&@ 7Hx~i~+Jv\kE5 _#{7[^խ] El:nŐtwXefV)\ tmjC/ڎ$LN :o|C~=Q8ln%\ɅLrБ8o97}QtOCU!NRRA6 gWGB@%Hl*ӱ hIOPEf-rlԄV4GTR %re|LG/ꑪ`&*ǒT-0F"cR0023F尢Q"G+Z:5pP,cg)әT8ֻS^&:RVFbA;o|Nvd uK>yث/.cQP+_ysua6 >}-+&' (6\?G_~^—_/g_asi5T` n{lz|V<>b/'A/|3 'y:ҴM@Z)'u*O?hp HV.< !WJ[7DYTvaN!'px |+L&7Fz9Ѱ)zI\(:2yMK{SR>?gFC:nڎ#9Lny#"esVQg[x}NwПa΄Fz`(`k\!';V3y?SqEd/{;;sFhC&Y6B _l,TTZm۽ʾ X)[~]nfʿ ~moX%,ȾMm 6\ nnaL:*LeL*r{ [dz%4-$l z݂ma:2lfT.zR)M/lMtb~nSSZ~tHnaDC4#\"`sD[^0Y$&BLڂ ώoJ0gGuT6ed@k}nc Q+c#'x5 ʱ~Ml,Yh^}bDA7ej640*ðƶGZ\M!35w̡Ćl? eJy:Υ]}f']٘^ HŽ  Ŏσԩ0KLi߾2+~zx#U:UvVnq9V@ wHC ~6ϓk6*,^_/-I|:ܪ[xRUmR&1UAS)4 Z9QQmzN[ #4ZW"Z *we!$9"=fL<' erj@2Ijzs860n|%Ä$õ&HcC?{MD=lQ#J^`q.N'ŬK^]UGU۵GL&˜Kh ;mnNjY ûtl: . ^UU-[ 1!^ }(2JvԽ4[תzV PQKΓiw!ڕ|$ SֈՠFɻ3y*T2NC}~ )n\* 8]{z˰ä$I9CG26V3{P5VSJ(Y6I&CYm0 ٘TS[ y7.SkԊ|rHoI49Dۋ[؂oPV0IMGǖ9l?'fS:8Hވg[2Rr;\QsyP{|rO }4mh\kQחiTm/A: ^@/pz/wCvOM;-|$kZfkHbч5S )t>ᄴ9gLh=,\AV{@ "-$ ㄋdU#%/ė#g;/?Km3iX%/0tAPv+$zF'S-*~cQ > L4NyI(sӟD0*K'֋ GUD4|!j1T~m!.z@Y/Ɗ-L 3* 1BbT2!F4MR]M'p`Z& QrOJ9{n̛Ur*: |%^UPkc:d7T ( N{j18`o[']?{8fVN |YfK1-Յڏ87f(U^u1#|7׬tl|5n'BMt7L.oi?x{ܝL1%gvEgA"z+FcbYH,'pV Bj:rI V n " QVxxRY4@`v!hVZ>D*3*r$^>RSxK-wh_$4'l,Hت1ȏp^)<n{Jaρ09M0Gc6fx!'@9wWfV/9GnDU`MN"ܭXZ ġ3PA[mcjD I-#tlQzyg6MvhSaM;TpJP ۤ:6j1MAWqlKLE5%ڣKuQ+~q%+~`nU&gU8lfX垚 =`BbTl?Z \@s ^Ofr 7.E[]?]o]5Rza/e%%v7r⌎|) T kΪX̓}Ss0jKʖD#% U#(Һ,^;3RV |j'A3&[+QA7jIdVY׬b=WL< 8+3K]fNܧۉG*]_,a 4Jap7֭R|\V*3Tt;Og9{c#f&$ Vk6Vkℹ`x2Xak w>עU(޶ ѥZ7?ՁM1.}!y=InnVUa2)-mVE4Wɡ0t8Q@nrՕ׌gIUPy,E%Gig|3Dݟy BCS0NpR086 _܅-<@<묆0'x &-MGWntoIURJW[L}VRR:ܒNSpJ[լ@( OuUw"EY\eJJ{ebF{g9S*]|" ܫmug]XێXn 16PX(8ڱ{nIRfto6c66dz Kq:dghQ#6,A ~yE p*Ldb*%uӴ5"w,)QXm:=Npz0.5^p`-_蠱<-'{>K`}Ǐ$AtmIݱ. t헾4g͵B;+Wˍn9TxHa^`ykfeXL\vNp>2Juݵ}lU(b,: 1#AO "7>>|EmfИ' y2ǢFm1RóxBMZN" /fGx|nE+ХrIH-s /Sw/9/;2H?G֮D, #Z`rs-SO1ȎߨFu:xHa w_1B<:ow&ZJ.VŦD4WQ04@Ow-̕Hjj&YЂW(5"<dk L/h FY<)zǛahި@|B W'E-RыbqT F>nL]9 o3;+!hgp.:X/uVy]%\}K3:O:X,40J6V2 fsIp2}j_79ou%QRH3_f%wUǿZ× "_ecHU/Y,`=g=J2]QNgwF3F/1,`Ɩtg:Ik-c W\ɩ ZQ夁JA΃Ob.D 5!re_MpXMF:}sk V^$-鵔0m) KtYL^T o Zm[sYF9sqx /dcyn"*au,lj.n%bדiCT\'(aJDܹMRW*v %?l{ Z#d͖b}X=?=s_0fW}`\HN4V&~]em=|gl7Qw+CE @ (646)XҖQzYM6S,ղm:]UA }o=X\@=EےɃjZDJDpJ5Bß(ƫ{"مX9[evBJ9S7s_~R wxnŽ ʫha$H/.mHO:̊hȉ>92•ㅂ59ߖXy>^.bm QY4+|]Cpp /WQ jرn. Հѽ0b zEL/' 08'Fŷ+q&{#A^]lFz f CAޗ.ùx…:).JLw,*:PH[nysxrڰZ)~._"̟e%";Fu덪#K.mnE-q$An iT$Ize† iC;o2Nb&& l~Laȴ6 ۚ%\5w5a5,T3L&uH79l$%ϕ0p1^Ay$- uh`bW ^]i8ЊyKb!WIuRKO7# "y}3K3@X, @!>Z7p!wi>t%oeM2֕2y爳;H1 b]vqŨ`X]~ BsgpuYeZڼ-o'L#_i>+26Hy9a*Z'S`f,8Q1;MT㣠UM Q*28̟-q1\J8mTzQ3;ԒrNŸ_w A.E,;ԈsiU߱$dvĂD"˰@@[. 1tgBn6J =MUqɰ#Nvń ؄8ld\32E(-rZk=Cojq_%{?&ȶ |Ng&mOa4R3 ~RD}?7^0VOud&iN:Qh**&e98b?+[;Yk/"%O䧽w/M'}ke], lQ߃X߰unfԳBçO:PSư|_0k6c-Wyj|S>b\BV> yfFzZT&sI@|xGF$^“t̿NqvUr⡾cg)1@k/ۜDvd]p7 ba85܋Pq)vrU`>KSGg3Lz10rFmEw:mI+fZd;=XYܑSF%|R{&ce%X-"G֗QbyM§<^L~Y@w?e)^M1c6`~zі#xA@+#}ڰTAK7cH jЉ퇈o 1NzxU:Ÿ0ggd~u;)%PCVz)/ ſ?'o ^J#iq1k؀ z۶)r ٌGжF1쎞vkƥ `{*)mf;z(d @Ƴ|MgdEᖳ RJӝX]b9I};7ǝy)"֋^CVȾ2\Tܲ%QslxmKխJ+l%YfnE!-WZLgf@XqƦxt׼)*[K**uԁDśOIDp=6ZLX>0 GZ68akVݫ_#ΙɇhȻ7>a:^ !".|<̦pyJ$ǞAȒ3,2m0 nY=KzNfXF2| y!>EV% uk@?QYQ 癌ܽcdHo[Jod; Op2"Yg\|~y>App&3M drc%"t[=_v) g3Rl!e[B28,. 1z\tjz^JLΔetjlDM;N6|:7&\M6.j |8BßF<\9)Y _hw,?LnTyw3_sX2,*&Ok>էa_ٱ )5gpz&7C6"X Ar{L[zrbN[؋ٖՑʓu3tP.eni?싈? EZc i)P&#T;d*ux\V$iAW0X7dYr$8I58z[1FFY@jKCG/دc5Sro ?@_ޱ!]Oǣ"uy$$9$)Hb޽u)ȴ;i'#Ϟ,ttwb΅N uu>4G 4|5f3ݷ^?v#TtDA ӗ[qqD̙A?ܛBzhyK!UwrV 髿_=vײ-e6o[KP?GKuo-?l4SF+I4i&fW"b6 @)?F{ُ۳T1UZZ\+z rM+TŚ*yw۠] cU8*-h& u/Q2\Jˉ/?:d\*/Dyw= 4fs&F0äqpcqFԦKPH$ AVlBm4X{š0ZuoER.ʧKY̯D`Yi?l:HAnٿL+ ɒ>d:l=o3iKY\qvq_׺(I2ގwYM8Q3VPWNZ+McVݗ3ވ~crCfzMzr>m4LrJvlm'jvoi`}ɩM ta;=99iqs\OtxT>… ?@g a3.lz$$J| 9ssK{onc”FUh3`tTK8B!}N3d^{Odp~6ГL g_Z6-Yj?금ŒzÈzj܅?kP9Yte#zZ?3'K@J:ʦ3ޚVKюIzؖǘgE/>\<aO3;_ .B7o RXj sɏٖTEGg!pN\~HIqKg%ƒ -XhyV{q8-c mԛsߦPFԞu>|B9;1x٭mQivI_v3ţ<$dJ"MIlU︳}]9Ԕt թ_L9ȓY1|%EbmpBs ^j.1{ ^T:R^.(>g ;\4adEF<\4adȰ;~ΉB_t|yQl\x]~qf͂o YQWC,yP Ea0";}<Ȇ_-)mO]v)~Ǥ4 & MVF>(. Y9ڤno[ :a+t߳FEo7߮0+r5э4Eim"JWT_<8GƱaě1_]ƙ8YY%N<\,h@'U=*j<'q&%9I$Q{}X]s4u=o'tjWkݬu1=|ZBIJPQK52iu̮w;/!HL7(RKN0:[!X A{aN =p GD [,7&>(&## y烪3s"> be- ᑵZ,*媸=!na8X9:(Xqv ,.5`NXJ !ft[JS?UJѣL-=d㯏LSfiI$l B c sKfP'z/B p//.ViHTiReB˴קUj}*qNV*L"K? AI^Ū!aG |r&F2Zר?GZq4C;Pt} ;˜y_]/h !cc1ct9[_e$рbX_O]5,s|j̪_/lѺNI1~[g<c%Ǧ*⃿dJNߞKB1<32X1 ÷Fxs__C/d?hl>Ysu66Rsqyt͏ Vnkf>PZҩY̿ʂ"=cUmΈYA$u:}o8EW8B&\j] Kϐ8tO[SD(Es*ak'U?dPKOWISx(4V]t~ݶE+,@r4|X[1¨J6#Zb~K .ƥt5Й06[Xv˟S;UìRwG}xO+7(dq}! F?.{ਹ+(AV:.P{mJ_cʢ42)7+/ư癣Wt rܓ"(̞C<=Mr B:Ϯ03c >L@u-Fte\%bt{8 Y0P{q@ ,u~tY3lav Ys# Q2OG|"1%gsKxMEL&a6(\ln9(8 k V#dqH\X+lum;Aw%ySucI;Xniװp! yе<(M {RV|_ *KB;F!r~iB;I EAIb1Iـ$kC-B˃҅əbIQ T\ƏCCN P]jڲ{Pđz# ݶDAfr{!>.[{ Oy6sÞrXjE6l2ja>0 ,[B,PA"6_#ƬИ.HÞn=mDEqi R"S'էʥ$]5K}90evQ|,\3Wł:БvcDp8fth<@x&RY[|UJc"rԠWżLi^=J E r+jD|hFF}"c\..(J@Rא>P! - uga$$DNѓd>Kt,懬il W.%oKþAt*Qr ﻖSe^Φ[фy`$Sזc`N͓TO`O5 h@àݤ ny/|&Ƞl;OA>|Ҝxf2[0JNzԅψ3հ!0WpcOCy[@E:+^/$Ʒs67sP%>0.'2|BŠe5//l`p5 -":eUg gK9RorֹZN/RQ沺᳅w]j(ơRC61<,8Ai`gaasZK av=~i o@{Tnja*&uT>!ƳvC&pml.ueQ\0%_1hHK$6%Jc l$)-ky-&3ηt{j< /\@QsT p3׺$VZ̶{.&'ΰLs44K/d0EVᖒQI#[omF#0ʲq_``@#ۖf"F($wݘ@ډ6XقO'x vMa`jl5l%xǒQiEiJUa޾z'zb(uVQnI;$4J4L(d )0欘1bI9rQ6_W0L779'QvTzʱH?YoPՐ|z-*o֢]/i >w ?u`+duW`<$%g l 2[EQ + 3 .xϵjSq"$o$]y3Rconԛ(`7cd7o0LEOK4]#}@..SXikx 8{%~1Piv)orf5h_6HMͭ]ь8QZA&TLTw"<[*j31Fh9.tZ>^DWb!J>@ T!ʲdb@iA=@IHMg5$o߿;ة?- 3 ]p q8ZR,vyzRt#!f"C|hP`t:;nsd%@DTp\dS_뿔$_:r2_&4[@ >@; 1\>Q HGGCLhp,&Ft΄k5j Cwz'gذxb3?l 7>%WX*iK=%/ !G|@R`5źOXs3[ `qNYXQOlbZ .ÛI$wVVh*LsmRj9]f(cҋzO{7bqvrxpX6V 62I[ؠ٢o#Vc5thVOAvduHkTž $d::yE\GMg/~kLGKkB54J'04v P<'{M~)`=& MtF{r{R>;>F7 3|+:@ѷ IOA[OZ‰"MÅ1`r./9xAENcER`g BjaE>|XYj${P]Hq¬|J 66r2P$_g.S]dGʴ}u hWyDn)%1vqrfU( Nixv66oa^Wx7gI6ta58B!mp3jq= ^%۽XF1 ?@9ݠDOxɜAIX+l}A/rt氂̧`1:+`J/}ݰi}$4@ NM zg~[ /^(C:4޵1GFW"xT/n*E0_!:MWƞZ\D\ q3oqcP |=]UwĉQ\GG)aLp`$<1ΛÓS7+ @P [ܴ\n?J-D Z + Vzy{W9NbHt Pf'$:z;~:cOG~ > ?"%3LG{ߝXL$UtxE@MSFX;1NYKzۿ@ @qs_rE5 hŗ x.Ɲ2%}mb燽_"-N7rYg0?9=|BN97@!) ڝ'M0>[JC4 -%˙>+| c{7(rSN֗:WWe>3Dױ_&-! ]a94k7Y#_+=')ͧ PGZZw+E_GU#t2K9`b>&m%]"jK6|B)Ù B;34A8yЅ 8%а7Âj5*΄a8D=[+>&ȽτEWrB@2cw n $?d9;$.XzLy>E9u+y72_8qL3[?w4ט͕eC=}u4oXeJͶ%,@{Klj /ec5La NpNpxMŻn~G MHqs)~{NTΠޝG74?AB$k%vFPl1?c`?gg",(k{]H$,L.s>Yy$G1tt{4E% ;N6XM6a9L2zegxH8 D @eӝԪ4X]'43+s9Q7T} R 4.ӫo Y֌"*x#\}4X+Osrkܶ%cr`''"bQn4Wuw {P@TA4cXׅOdcʋ>f{z$5Q}I_8g} zz<=iOBٯ3h1G|<;PdYz!T:`lt5v^;Nn=mo <خlH\C/7#~i+LO;>?>녵Cǃ?; r@J*R 5_͵S9O i>el`U}de*&'Lz1J]<ʧ%"j8mV9+D }AZ>MٕffpuU앋rf؃ ()%{ wXE{^\!Gh"wuTt0*F)UF~ҩ86DM-ӗsDQ:kԠfFQct0Se˺"OؙQ^nф'oGo{䗃ãމo8 oT8 0o5m4KWVeSK*#6C3OѨg=j%Va( @A5#kV*0KϮKTg6F*Evr5.Cnp>urNxޟыO7ONi?0~+sӽ,mmF;ȯ.0cf,+m>|ɦ룓Ƴu> k.&5K-7k1(fJ‘s2JAorĦ _J #/zw>LQFrSSU.1vr`U$Y$'L&~OHu6?Ct g VHgd̩M cט bo pv['%W9F0XN:An QP=>dDp Dy[ܯ!3v oו u^bcݤw (JMUz-5׸SK 'HDsle2I蘭AKs,# a`l4瘾KpNvY#:Ii F-eޯmol}o@7#4:Cot)'C)#bەynR@:Rd1|wZ~P<ϭۊtrK:$-:=>ѻZ͠{wǷ 1j&5꽸_MkZ殳yWŌo\^ 0:`r>e m:3%H r}fw|nkBtźFHy#upfObVfTN83;tXl:0M٘r-F0uP^L~HqD/D`1Y) /d EYqkJ,}i >88|Xl|ȡF%D4I8TIIUHdx3Z,8"WĆom9.-эqDD'6QQ:oƹ01C^VKLQv٥jZ" P[ѱ8K{KvE lO;e^f%DB I,|!4M܋;Fi@,*{.gM|ϖothg8Ts97q0;VŴa*X5)4,xs{B8B͡S5wISu1a;il5Hm7 `*]M%L%0|_)q=0]Kf[YTdxShq#R%pbݜ |E ̓#@?+QHIǬ6-/ %MRt.̥`9/JOfjYїM  d]O N@J0o 0`8 `IN16j'dYIE)HRQ++WqJa d@;Di(ˡ)gLaF[8ЪOy)Wkw>&xs8WU ׼ԕug&\o'h:'*@eY9rJ4GY}k /{{N|m㸋"!"PJPcsS@fɝ/:l>{fyb* kfxk nbZMB1ߏMfJK7vB2Z;!) k+6tvng{aq+&"?GݢL`WhۄǙ*(wB TK2-F "_̐zT3NFϨRPd\tTGo"8M$%«(NB'WVή{fÓS'͝:dO;#I5dęwʖs[~'nZJKC@f4oͨZ L>Aۯ{oOjoI 5ux5uh3Wy6d~6eHZJCˆm݅M}>曥窘X@y}򙉔cŖJe} y23g5Oeou^cx|kcD 1A?ḕ%\AW"r+7GUͦW4RATHb Y3Ń<-Z"'ފ9zSP:l%&Q E*f Rd%0dԏd(c֥m=NdmOGw}$AAǻo=Xm+o)4 JL $v8Q//ɳFwW2[cG$.t#Xb/%_c`x0UĹU|gQvDe-G|,(OzT>:CaR<XÛa0I9%>%^u=%G>lwŗmZr8J {pgX:Hrxfa_s1C߯Pe:u!/uU 2M1 1.?Fz!$];eʎĖ6ݐCe3ƟuCU ex03h.S%wznW DkQRL짤kX9Y}B >P))%?*R^I^|M ||WP~ 7Qkd.Y4ݫ,F n}@J8[ZRgVZlfʬ%R9MKNNbOa,29~%hlM,ZHV2&uBdq UZؙ*t8FDӋ!g@-B*,i۟팼l }HUƊVLzjUlԠgx038laK~[W~`'2ĆҭJ`Hͅ:HohN DPlJN+O|y+E:̤R^tP|M'rRؗ< oR9Y.[3jK :l|:: nPYmJ?Ԇ/jSgT-J[oX_23/(U=E2WnkLjy=WaA-x.=%vd'Hx9fGꫢ@ W`l'qKVfeJ%vZ4Nk*Xlh2"af2\M(,3 TUn-f'f`nl<=::aRI6jxX%Pꑠ-Zƣl.0vK'̉5ѽ.B`HqBկ;B Fjʭ_DXLG|8)<#R^ǼPo€ѷ=2x^Õ"gFk_)Hgħ8OkvSPZ[Dof/3</d8Eqpט;--4Sa-JxݰY Sdш:^Gҳ*OO1Q42ЃC%VM0PI&n+ؠsד`Octx5F֏I:y6=Dy0l:F C8{T |)lWy !/E3oO597!W'1mou6=}m<\|V0PcӦe!:u0IU*"Ԕoq>u[q0l (X*~.Rvj여 t7~Ry I.HTr|NAN’[AFXBtTUaPv]a×cqQDRMm`#{o.bkK=k7Z\V_6kTïs38կ0̡å3r$0B cl|FL4ߚ XޏSOݗLv==P{gstkkI3v+_kNf?4ivhI^ FAa \ /u._XvL*!Z\xLbb  \xIOhjӁ[Yv_k2k!{3j׵?Gw~7/ Zx / )GDz_bL#Ga6Ϳ_M!iy_ݳd>J5zk{=(z~|ޓٲ7e2 -lDY)/2 [< Awbz"PgP9B}M;_wib/:C-)ͯ[>Ozs s-1,|,WMެcI`QIYD&YmQ?4/R|!NwBvC^C"0jU b8p<`p0P*a0\'e‹'~94U/Ĉ&~}m/uR# YӍv <؜nj1X 7I0gDT[]rBExyؼ $=3)]Ϯy+oK}k7gS =˪|!>Q. \yeB_mP2;ZAU5 S0Q~Q&+wobHk'VY _d3tt-[~FJ+W%\#k04C'a\ b_U(, \Y؝޻ '>|~syYIE+Sş=N Ƈ=TXx5Xsϒ{U"ꬪ7<- F>SZ~j3Oe9'9gZ_gOO`F?I#r\Ѹo2P]4QJb(Z2Z7ESYS7)Ua^:[SNVwvRIMYǣ\ DA g"#˓ҘzW֊հg۸V(;ڱݱEDKS Z+qQn.)Z\VOeQM%Z*</!j.}Hb,5*:G!ҁ5)QW]R%gS M/}:M¡ N$&RVc0I*xA+]V#B⑺OhC4X 5j`0?;'^7-SN mE{whm!:kd1J󛉻OxT*$v`QӋ1U^Fv@FDQP,(`HeItVy8ckD6,L_ü%> PRȰqyC툀H?]Ht1h$"Y0HzF[θ@qa3+M*8bcA=ק(P;y/>b_AHx>֕4ח3^WՓDㆈj­j z &a" 6(mxCz|dpIq3OE}y 083Ư3cWpq4$ I?*EH>Zj Jd濘@ `YĉH!%,5(QDkJ/?5c+#[gHd"$ s&"Aé} ٤+Y:X%-9ǠLUd{cN~NL5 p$`INj #8˨Vi!. fyK=$ 2d8jAIt\0D;akW,S˩`kD{CbZ& lu܃ !0m!'lZ?|pǸ修qGL>|G:='s(0T?^RonYg |*G{/%cbAW&+LeeK$a[f\]4fF\)nr* .vYZpp)AO+tGM/|=oHS> _uU4WaSƹm)QBG!L&"(o5Te;R ň ;z]_n}n8y+2(]ªQ>nZ8 oa"BO!!1J $ E gU&s ,%S80d>;eXt[zDtX34.y 51cl :FY!o'{DZO=ovԊ\)lCh=Jtk>dK1ȟXB}\ԃ. @E}|ě1PE' #Z,4'I(qh8N_=tϪkh/}/4 o,bL!O'U&:# DC;8 <=x ] w 7u/_ F挱 @-H_' 1Lj A} \IF "%Z^Leq!`faC'^a_TJ3_DN .b.VAV޼B;tiHtEGK>$jA xQ&8c@.+fb"TZ]4n;w;oON tʊr pKMlfX&z5[A2vUM[UPh5E!6M49%1GbӅA vX+$&h;*#Mh YA#ΕMI|ؿ~ִH̓oEՒ>DƋaSl[#tAy]Mѓ5WFۡl4}C& wӦU\A.ell&E-4wa${WKT&ּst퇇Lʒ_:@ZLLEYYVa8Ap tp 9ת>w'ppT?NJw0p{ YY& 0Ofr}7{A/m%?;"$:=:QiO>Up/cUQ̔z2,fm,`"p_"(80] AQfMRInۨ$hEԘBCzпL͢@#rW.e;зMVT);t<LlE0J%ARi>e(}̳%J;tѰ7 LH‹7By{At%XܐtYx lcۗwe&>MdQnA!S;b4_EYt1ɾ؝$mqz¾dcHJob?35䳙Q TШ Nsa^Th4`cvuqxHuu,Z|x ʕE;0yȝW^NѰԻJ>IIVo :#5lN}!.^HS]yZ$T7s )u%XeaxW,-?8t"s)1}e+g*)1\MƉ&3?,%Mjn"BO,U)uq]`I̊lV ud^IE]v%IލoIXH|<Zlv[ֈ@Te0,bo,aѢFbXr{Wo<\xcAxǍap_A``aHnBbF(qė` FTqH 5Vm|ũj8 uѨYA"0O*Jf~+8h!g΄e{ZhdU|*?QxS ^ٓ 7Џlq"Jnʳ=uƅq3!E(Tk0FM:aWRM{ٜittq} );@!rM\a= Z}/Vk*&ڱkc=.J5( w@8V 9qζ#|^9O^A}3ZyʊVwpxp,ٸ_]R1b)panq@֥s:>kXn&4EE<%*G({*EKP ԡYܢd[J|< 3{iv;6Aλ{RmTJ>~ MgY6 ܩwI$I΀yCݕ%5 ID}e#- R B#vhKZZaL3ȗ8eyh$~^\I7K2Y΂My|EF]tHI+9e.%ۛ 0 .EеayswqmheDr065V\m*7)HBFyZfkkb"hѠhrآ*7Cv˷U2-mS=s9.$wQ0^lWl &8sE~U˶8L5 uQG_r jnve_]-P;;<mB,D|~$lG.v;r w`d}wrc*\.sZ0fHܓ!v {zׅbAlosݚܬv[?95װ? xeb??$k'"|wgVC y*{1nJq1k;sj3C۲z<@0Z7*ݏK^\C)-Ŕv\87n_!$&SpD*)n6["CՇ[ՇQyQ{:d};qcs\ ^%@u?zH@AڰJ$vw* Y(͋ۆFx1.꿦7ob7H۬ [ p~_ΰpMt&7[ji!(M{o|%e/T>f9PAj E*%@'F{Ï&L*5?^CX'ՑCGoYɋwm D|Xݯ#l Z0uZAW/6"S R,'yK(Q .%9e%~=/.}-,iܭL5Vcvj(pV; ϡ߇'&~h".3Er@ylyqz*-7]IWZxsdz>1TjxkPo~uhѥ}ksRE`1&ӚXO,x ;4U? b`L"K:BҼ$R s4FKpx:Lȯn!/F_{>˦}xL BЍ*a"Ic´-e>WX{* !3! XiSu =AG䏖G[6!W}P3WgW}=YBN+C[(q;C`h1I3g0C~˷H)y;rRs0-9XbT'5;EJޓbN>:8ZD`߁%"KJdW\h^ɷ2"D*:/Ut~OqT2"ʳTY+&60D[ԋa\9tϙC#; bBbXLė ͭ5ByJi/[9TӖYo]lE[% V:M1œ0SQϻ89[Ed54,c32Š;Pkc<עL9FG<84U{։uS 4JP0TLPXr?SVhӇ aE@Bx>ʢ?y޶ MHWlU*R ǧv)o=CSA$w!Z+d%r4g[*00$un[ZHg~w]cXWoԩsjPD=GItRpV/()YYK"@Alc}#ک܁ "ch+EP#INC#d QEml&%'S2]Nص¦%%h>1@ZU KXuXNm'f``8ν3ƢmeɑHx:N `VUڰ.W}!p{qG-+6-AWqV_Q /FI=HVp*lh=!&$%gip5K'$6%TZ* Bvפc5}|ZB&IDpb->1l )ܖ~鸍E}P)ooh"oqI®5EH&SDW :IE7cbt4A|N*FͬϷBx"BˡV]'? J _!ޜ()*γN[ObྕYR6$u!V{Eg9Y̗d@ WF+|`Ate$`:Zh#|l$a ԜgW>0KcÞ(@F"9:<>sp)ud͡@HȼTm$R3.#̳A*c%#A112]Է|& ^pEđG_NaO@$DKȯ$&Yyg蕎,Ә`5涝nvwFD̹e}^%Vn,9sfaÌ ;|Rhlha bƎz %~9ȾuxRFIXַ yQ7s95/=)zUor?7F\jZ`I>\1Uq*q0⨽L$d&AU)k3iR~GŎ5'\2H'(x,amU=z~u+N*$"d#}çEJ)7'A BSe.)踄;N22:} Ovvn!b f,c}j+ORF}akDևOᾺ^_k V1W`&fBpP7Up)HK(5'.18dzO|Qsnx7:p _ԴM4)&3{OVQ7z*Ċysai`K[ܺ אwFyN.GF<uqb%>0e%^Jii(VD+DB ͋NJ>ʥe|e!a-_0b%ҿ M?+Dd<}eJ$$K?8RDZhU. X}3&J#Cq`:dYg i<uu7KY'zagtפy6}U9B EurmɮZ6&~/;&@3KcD2A"ˇ6cTyMO7O7؄c^_C5sUGv:jEc&jG4)<;Ѯ7e >kO iߖ"beeJ٘4G|=qeLh)@xDKM=k{`=`_6/@n:떤=eN'O+>Gٳj[)#19FjU W*S/uZ K/+(/EHK]/TDtT[s@@uM=Tī.7cyd<"ڽuiRՈC%tϺ'ݓa & gBR*!D PJ7^52EBRiO[Dr{i@m,=0*ߖÓ^}t$I"%o0G"@|=%JZ4.&;D\%EӀs?Zv}r){x,\Y"po~-2!orueBDP2׍okRpMuǃ%+2aHg JUg"1ܱQP7X'CioO]p^dA'{d!!_aL$y1_3s8Su%az%>bkxcu%nvSD=m.ozǣBրrӜ\!vl;Cޢ-+vJenU)|0]]MfN _Ss>B|FfLQj^ I`i]̖!QlPbxU1a(xK-k9oСc,b+Ã/Z!_u?d틎s2¶kniU)+7(W˔})W~4]٨|A=CתF&Fjmm]4[gz%In[k._W҈vxw.xL݂+3p`poewq1s[XًcQ]`cn{ES._m@-H7, ]ϟ݀Q~YP~\nYY.\>/0C%8p56Jl9i~W–if Mp 2pĀ :4%{yJ[֮3j:@ե{p̻)bD=`C6fY s(WlP#/tJ!":Qd0 3z..l+ad%ئ+TR(Is2Jc'o%Jyu,?S* \#/$ XbQ v1Et=k^F0OevŲ L5O61#ߵ6`SK (ƻ͛bGh0NWM֜J\g \Ra9)FMүmwF#Y&z^E[Y@z^(ӉFRqk0=Fޚ(}9K>{a9[/_CD齪/R6##x[L ;/3behߛ[_hA0[8~GѰpבcIC?5QnE\Mz 'J*5ss0,!_ w߾Vw9Mͫr.M 0@0wv}ngO{K÷SW@-BYƩba)I)J I< b,#p~H2M[~݁KvJf_8 -dN$Nnx־kq=8Zzu'\2' CA頤:wbX$k>oGpe[ɽ )%= hk5%SSS[loe ZB4_vT#!rSRgtkv& + FⱙrgG~2Aw`ƻ%&{!mz &yދ 0ͽmfT*]OF< DuF s^&% &{y 7*IgsP5XсkHu/M3/NzGx;Dm'3ӻ  .&Ak$RBr;U(f!#KH"연o4}<.ھ٦#ma 8^uO6K|m7?yhwWz.+a8r2rJzzuU<<* (Yw*ZN Wxʠ ڤO.|ϝ-E"{*]JmsUȈi[x Cqfޣd -ύcϏsc0P%,ProևK6kbN雧г*R6J7m0/s r}{,Z,䪂#qiaZњv0+gp]Ljn O)H!#>^bsz|vӾHc/VxS W7tɹdV}zyX/bL^|ⲚeZg&2«ڌ-Mqò*8W^!* v:`"(nG\?Dfx9xdGPgCr p,(3بB~Uz'S< 7 hŽnOulYwW`}k. H@$|b JnUy:7ZWC VR µU*]!r#C CIϒ_5̥} qav#}_0lq!ub1E:_|șύRm^nM@h[5/KY#}Fd*X3BUT˕綂LckգHOY t>gcA:v֡8 dPQu+p-Z]C 4k0_lV=~a@dWRcV@Fzq^:Y.i.A3 (v8!> Y|VN/Q6\L̲Yv^ڢ ws8#-[f~nE[6\=-93EӀRe$ї7-`٬y3+k8' ߆Y4gύ^m#ng&@vk}8olxۇޏ ŭ%'ƤXE2{:ǣupQ!41  zD[Nj?G~zW8IMTק_2O6M]¢ \G D\,щ,؜Nu]eib](9Bq%Ԑc3/.04V/7԰r#juC=!1*K tl8EM,Aoydi %s3?>V%h"喋Hja,HXI%CTw *>DŽQzWn%ut0QJn<;trrtup@ܑEꄧacg5nn1T +E/,/VFީ?iT@b}5D@׿=L}~=\ǎ~ܺ-VW\W!`OE@G~d}7x#AԆQD'_Q*ǥya27Rav^R]SWT ʐ|Ql u"A]pnJ½@M5Ku#)X>b:L2bJ(KPIJQ^}g"RH/[0[\qPL!!)Ad#g_ eQiNsu\qtHVߙ`9Ll؝کI5{<$DCNM) *O|542,e:@8C>E2 ehki+Y6p9V;pqSd #X&dv}(:_ui栉ʐ zH$q$SM\tdIQ}-9-]}gZ=9*f{>^T;@SBhnlP+OyyNf(+bݔW=>9dH3df;K9UV;-\ C9sMd#%GA`ߚv'"8 @+ Hnd_Cɽ&T| OP#9OBb?Q{L.ABa"8plKKh9Szy#{ L1m.DJZ g<<|N/|Dq·^`͸5vsnq̻C,Y0A@Ass>NYI 3$'ڸ/]s\/fR z'drA)pȁ{_ N僚T900kX 4M>^O7p1RRN)g2)K#y]{v-5^+$QVp<>Ɉ)C7#B01XtqWWpkB&ə |郩qz5xt4!8.]ݕL`rYC_A=1+i&Gq t.jfdk SЭ/NZQ#7' ߍP@Φ1;..,? ]=X0 @i$fRDH##L$;xl]h'j)t)t$p&1X1411Jlp sLoFWL-9G0hUo"JțkonY ͦ]& p -mϫ,t@)9 90dfSKˣuKyB<$H/dѦ߱:!()h3_@ *INnUxq_aN>0?LRVCA`I/&"7bhJyY =šԈJ^'f9iGP7ERtY%:XS@":@9GVmN9`SCm<mƭ'|6GDC*,Ct+TIj52CEFL+u.>B=;pfd~d,UR#v%RJy^- ÜzJXJ<|8ViFqhlxVn,-K!S!Y yj|10Pxk"Z=4)M63ą+,Lwq KZʎ@0dc0~)HhA7[D~c*k'~*fkOZБd R-n'"XT,,mG$IJ{V-%V75vjT_xtT)M0HDTܭKL\-OPq*,A@؇;|1M﷎!BqY`&#uP84l|ŻM+&P VkD^KϤy) KkwXK}DL^ZTPn 4W(eC/5I]Y*jGm* Ú]c1.0YP*X? "1N)a$`'(O+{f5ńF44S(Iqдm:,Oi6Q+PӓN~uXnbQ.ΠyKvG3 ;k:T.~S^Dx׼jsߡ#ъ#;fL$ߦ#(Bcqؼn˕c(E;l`vn9BQD5GR T=u@f&gOciYN`1!"uJYoЫU]yA a5,JW, yflOMhN$3OVSebEfWN% ׀3Q=?D{I&@7ۙ\ފ~lʚc Rfal8:k;]$I?辿ߐy '+昢u7)Ym2tj/ٚ:b6ZF?"(b|2\ޮ;N3М8B/::YǠ],#p1J F롕Œ80T'͵cxt FRP Y-  h3efVin2t(V\JtYЛ NdQhOୢ|,2]өEMY3!E]tx/=6B AEIq[+%A2|E{ֻͲfA^$vf QO˒vA,YyF2]-(߀-#㠔1X[-S{ɲ$,gkqjse9{ ];F/ZלM/ 4C}Wx`MB_cpho ]8QɘbPhq%(SUAi7r̂GR4KѨzc熙oѪt/ÊUe5J:1Br:FӕS1> }x4HSQXC\`߂x^g;[ZᅬP3sdLxe lºp qk0#,Vͦ |xp"ѰAI7q"ֈU{?-MdT.Qfu:wC)$SSVÌtI2S| mUR懦zQvw6hcz4N ½19Dd6wvN7RL+LK8X@n?hTܗP Ϳث0X/Pf6YUwZ Gԡ"ܣk?'K{TUdoUseD z':vch%yv3JK?DZ_(oV, rKE18LO}H:cHmN:G[L@B+^ɚ9">Lyïܮ[L$4Z'NT \gř /`VQ!QbDIcwt7kNH,ٰ(&IZ;2%a.R%f56HSgx{Ϸ K$._#:ƔY^|բ)#F Ѩ2F(mE}q2F.yJ97T{w45)ĞNW Y7^}ѲŸuۿ\W~=xx{:U(5W@'a KOD:lQ8$#43QUP qfCFh٭WQk{jEβ)JDMrAE&}L׉(g˜D[Nuxմ6G۝.6JTݒ%M8kjY7+ހֳ:؜=.CÔ*yf*]KeeXpV@e* &7+z+mm#o! M>*Bȹѣ/<ጪG) {# W]:(vh0zZ_:/!g~K!<)|^p0ݪhG-yl'-3PBXZjߞrW$y I/@PD,,ig_3-EN N(=Ӷu ;BG,4!WKiv9  DI0MZ(JM~28ALErLA7Ϛ7&q-㕅ٴ~SH2m!#wvSאx;;||W}Ʊݶ#ޱ-n{ռn$޴߶ߵ߿m5մ͏x~o;??xU3Xȣ`~ul K!h|itF="͎imF'Agv:L"AHOh,ۊ: +|բ_ۮ-.~u7fK;lXw:ϯSad~6ݪ7W7n}vw}߽RNxȌpBoC\28K+v $;9$xyliGO;o#WVo@^1_m&~h}*Jkg'&Gn+ d!<# jyr͒DA?Id#ffp`ԧS-OuNWI|f6I6.n]A0WLOQ&BD#|wY]>CwHnq="|jI{\onG[%!ǧ} C)ô=BoAXTttL) 59NbHQ'0 @PQhZ2V7D| $ȡarjWnX.NS8 ؂b^ A0*0ŒQL^FD x8&GF#Da2x-J9"Ű{#s'r*67L(.`bf`5WS,˂x-*2GkqP)+_FI#Ê)}Z, 3o,ЗY/O-6،*z{͋\)Apj55G Յi@Y4$zhDцmD簾f(:w\ʅVّsf&K>AMvIGۿ?uuK[]ay㵨J|1/jpYe:‹pᆍA 8JCmfQ3s VoU.2cAKkd8irGCH-/"|䴖5yMMي.k]]Ťœ*W֏ zNf@̀˛81%"Ou{]8 ziL3jjY+o&v1addŸ@J$gSF%WM(AdP} !,ȞB $UhQI6N b OXNk}=KN4ܟa =b`&&YVx匑5&>aU%yx!,1:PL0I>2u=:QZW R%txe#&Le$jFL1㛒 M _4l32ӹ$[id@ D>ga%zU;t1LutAlPw#c.N;`oʳJ6Ӕ_RJ+I!"L(nE+Du+ԊHlsH9W (D,H7/X)aOPJa<U-*[ AҲ &!\*|%M5 e>7DHJt",U*4朥$̮֕` En N 胣،ڔlX e< wG RWtW D4wZE.[]-c43ʨ)I1X2'Stn<5 :gFZݟgGݞopO7u)ϫе)fh-|$Pp/ \ `We#RR3dY}ΉQzF7b<\˓%541˛qjh} ujBIFOI,༣=kj>Z|n>WT܃ zR:1?0 C}T3pX E1.g {YX 6OLse[86sT<_ nޯjKze>ƊȚ;(84TM:'rm{Y/ s}`/`ɍA7~byǛ7A #Cxfq QsH_E\fwiXHe`Z0}rg[~q+\i>\)<-UOg:~R&/o#3(LW[vG?($X^.<~rJ(6Kc`Mлj1gwjQtUc1A3=h拇_AfjD 6E^n:n읞oj;NyO&%dqp҇?k/} d, $dzxt曚a>A8bJ 3~(0,zĎvXnƦ9{Dn[p?{g{Ա`.C "Oc\ya4§&9YLq3GalHgAvy0\$<^!X HL(+0!8-nfE?x^`Eh pǹMn=k cų9K\]F^9Q{czU[Qں6,c1hnkߧ[ vbk0[7&j!x[g–*U4mU`)Zma1sӧks/lZ *Göɢ8/󹤗SY*kt7 w%z}Sjުr-DsiAK -'nGDx!D b)(\G6k沰<\;Ae3zG@"%F,™x;̲\qYTɡ}\(yz =wx5yAg:*\v#:ҹ΍H? $U}%q$ݾ ݳKDE}T"s%6G7]yW4+G6נ(a7 1pg'20| .|޼OƕlxoT7.͇ƬHx1XQZb|j|*j&{1MgT}Aa/NFf5'ΓkP]G7_Ɠ }N/` G?o.II<]Kj dcYۑbO^:˛M}hŃdNe8]:42%ߑWBZ+(-%V691K:ln@R>%QRyAZx]b3n~i,v1vLt[4 vi1ΛWph1,Y/ku,Ky"ɏg'X'VG:`orD< h,l̿z/^vǓI L^O)k#V0d;zmγbkB$qE}xGY ~_'S#g#s6_V-' $ȧO7o^흖Eۯ_z}ڼ}_߼Y\bfu"?E?k'ښ,>ZQ#Ve&(Q_F偳ZӳaUtN's/gp+?{_yQG-f 9C)BR1#yٸ9M1; z(;p##\ ״%ZWm.,nGZ`~7Q<^r G #ChBMתu3Jj/75+hm4Lih4wkO/􌲁AOWWŽ^ԂfEѸQ4fW}|=WI!\&SYLeZSv2jΠc lX=g6>>s۹8?R']cHR-0R;=WBnM܉Il*̪@7ht$ j(^xp"DŌ}8,q>G}>꺆r\rGqXz|O l"v_7%`BB"+W2nFT#YxqG$-NY/t` PO8R/uZuwp+БQ_dtaf:F')8tÚj4EbV~@:#5{ؠV(H%+=b@RAwHİb.E jjQȕX`߼~48?WqtK؂8?%Uhvb9^<5΃%-tQK@(\z fA~>:c>T5߈}gG>蝺!4BoMeY["0rC%pգNuG6"h{}`lbY:NbmTDD#8|vu\.-5jW?H9I nR۟" n5UN nk^ӇYr |=.!`8DmpM1x1nJ scFI|'%-Lq9٠XhPfP#|ġQs]ARkkeQA›Zz=Q6C3KfOG|9RuhlFp11n;\R7u3qflU!<`V"OdP/ŨgշqXQ|q^qM3i_ ECK>Xe%TˆȼR9W\S-ՇzЙɺs!$J#. bNQ-\k or7sg߹lɐnq qai^(Bۂ_n+6SNH;>Q.ᴽ%V`\H6fğ5qBOf̻}Uv`]olrpf]]{7wg:+6W:T` ظrbvi'13G.4$'* %IcoO=Cvr8^Q.ޚ7q;$s_?1=(`0.FNm:xZ>*z;AܑC}j5V YV̀%=ZZ %])YHfZ)zeH2MoYn7m_4$\&Md/;}ij$C@go~4 Zp5>"&΄(]#їl:.36PuPzuSuS`UWMHÎۅI}ﴒ~ԭiH.xOk e_7򴮲qR~3hEJNArT:Ӡ6< 0}84Rw+XWX.c?^*@H|1z#`2s}7O؅S!3B1-0&=•FД<v3D]K\l8MhO`gÈ7d }ʩ.>lN[j_  N~<ҶI7﵍1 d)KrW^CZ7S^bG NNЂ%b',1x`XM@VR)./ʊ&wvuc+"XvzFI<-=C)ti;n;"/@׆HA1?mN*{Fo`%A|q/JV娭ߋ4[NFmwJEj8(E"-n8w,Nm#?ie!F v e+C`]\k+1 %2%8| 썱3edjh]ޏHbÎ"pNg0@< Z?L8U6U:arݨYG_폺|v\"{XEl5uK[T8=U[+ &=;H6Z1ICFge !q D *dĬ钨BK mLOc](=U C8DF=B+ ܙ MDW5< R5k1 Vl42[ _G88ZZ 'T85-Yu|qIr`!sK\aRJ(&㟺$QX\@bFEs7stA\&|1~"7-nKs@p#S}MyՂ^IBAH!E)rx$V r0ZTLj^(M?&n^HB !mQtN%-@؟@;bcHKR]y~ [, p@E&2.@W<"`N5db#[<<:Xzr{C7?5%Sc#R.BbqdUQށ40RbcH!uFgzjIREWBy$bw@m5sa8[Dяm>c6m+O84WIi,2sR\,; dwr="t;o x)jnsRt:8fPOCDnl- SQNnDX#:n5ogy0,634U]M7פb׌y! 7V0ފp:mdfU:Xw\w@ y6\'f<]:6 O=4 o[vFa@ U D+lI^N.@S}I8,Nsr*7ҍo0Z NL~%5vL{˕50niLsʱY1ʯ$u\kO DٿSi /Jvz~Sj7"Ģ主8AL9yM=^_FAa6K<1m<ϦnmROQumՖ+:`e]ʳ}SZɨbݒGݑRhy i2chv;brr?, +HQ@PvrqtT&nzqŘTxM& }@fx3ZT")u>;=[>  ;;ej#G#|)$;$$'9-M :.kײNHɛcs)m򩢴K)剙f6ˊtN~D=H'iT%5K%J|zN z$N[, ьzkѨ0\Q!J}oc҆dw#GYnN 'S9Wih_}*D.R?;MÔ {ѼڃCh=LnA>(S%˥=JԻx+i%ْanA0oe['[X\J6$u][B+$z؈E:ZKʷXzL\66r;M< UZ۷AVw\ޝF.I qRY ~ULH䊬;5XIizUg*\"䵥N:*/BlŊC-sF]ف.=چTv}yG85N'W*G4t" ;dߣ7鴼7Us !("IK+ ^Vw/+zʾhk5jYwtuwc|CjZ{ݧxSkS+*x={\h _ Bel rV iye~J]i`#6 e AJp>-`T8P1r ; =ؓ-d$mnf57tsK/$je1c5 oYB|B5{UжJoUƨpza6alը#FkMiG N{}oz&ssMEG$ FIcZN6Qƶ|ybQq¡pho_ 1򿱪Z ^J:jZ-b BDs@Zs:%#6.TP%,FHM?v3j{;G!̀a쮞X)۹U(+V(ً|\`Z3а bQRB @>6J{WlF~oN@8=`r#-j)t\}{Lu9) N4 ?K];f/U \Rm.! [tM.̣V cA)(?#0Awfk6jfKՅ= )X^>ujAp5Q^*6Wl-9dAQSe2SWhH?Dݟ;, m⬩7W~!(Lv#CDEBgJHD9xF.aL]ב7D ^b\IcQ6/m"Fj=qz ;+UT&.[21\"Pǔ#t g1YڈӟO0݃ËcJ9>E^]BG2p4ǯb [§eb0Q86G6 3&>!S:$Cb/hT‹Zi>,mV\z8l Ug~͓irSVZ`,hk:!ݱP<0 *4~b %$ɚVő}-ނ\^9+^'Ro]iC#.I/}**X3Д.eu< N&aIy'.<]-t (O(3mE*(g^Vuirb"B*O~#$~p Eg3嗝ӓV(HEzmB)>`g;]).QؤMޖ̓cT'%\ (* <`2mA3 `c*j**%/bųf)jqTC K.Nz_Y$Ɩa ` RaQXo:H}FƮy瞂bOw76Z[>t맿N%Ț!=721hYiYCv1'-7M*JB<#FQrZ G(No0Scel\?or EUyg8鬈?%__9<ƈ+_3W~ uYI\WH:M渋s1$w4s!3`^!G9sP0<{X𝀭o?b}' DW/Ԋ)VhLv$91_ FAjr \Kx'r Y |Wnhq+A`oKR|E}S5y] uh}z +(qKTٖ>AFI;K$#Z꒙QCW|- %o|hkdgщ[V-.ss+SmȊ 2*-.(6OD<~u6~&DLjR;6Ѫ5}PCwN<FB/k@X! G ى٠UJ,`qT$H,ZXOڍތt\^A=r`bK/ ,dxޜM/^37%΃mu=j%J|fI-i:N^q3]B,#[+ha@] UlQ0~G> %I+%밌2N[ft+b>w)d?Vu5XaHIE%vCl'9 K0_6[yQWdl]{s|z)lC̩aX %J1kKJ%!ocgW5J%blX#0|1ݰXk@&KY/8>ˊ9IQx~ nēц5X'b2t++~#]:͵ђ͍ >;OVYfz `envݺ-Qߖ+<VUv%+JYnRX PcHRSKp>u/z˟.;.wZ.1Weyy6 hT06L}B]'fy pqE)7GG{cO%Qp$F_/Ι;9XئήJnA*_@YP=[5()|ul˲<aLG P :HO),si<6Wu0 ݰµkjp5I54B.DSHk[ zS6uQ賎& ZӜYB^g VBwht!Q."7NT'V!"-oO]A}Y4SX1&ʦurx8>xټgc{۬ oh PH  nE>݀(ґͼI )gk#ZӹDDA-onSI-"Z\8 P4z56 U%M% pĕɍWMkz/ۖTrڵ!NWg}: n;ru  !`zv~yP~*=ȄG;'ZGu-\%%zJ%XdW7ÿZ]-qk2Ǝ/coS~iPjcãS!WRі^^(;v_.wH_&fV&.[]m5; L٘M &tAg4Zz(3= # UkS-0J֠h+*Z熣oMe{[A/fo{ _U)6b9ci(vẲ Zq%NSyFKRX#_,Ar$)_;疎:v rGՁMn$B(,EҌz$ rGI'/M;dt #ArCa.wy(RSZxU rQQA)`8, j?ֻtHi9'uGrj w7|WGF뛊${tN(&`ږPPyTӘg׶ 3 /Σ؂r;-VƇPއJE" dk^ERq:T5 IOyhF0oŽDv]%- >_dKolEҳL4/g=]0O B3\g~@Q!CijY8+Vq#hT/6ǬSF7Hh]9ZqU$O @Ob$1jUN0ip6SpXOkn Q{QJ^N8lx]suDIrIQJ lQd润 1$ Oٺ YlW_fl6e##U2E *uȣֲ9C43-#OyJZs_W4 0! /z]t-eϨeI5R,'at h!R~s_k喺B<ڀrm6r*1#dA~7FfQ/+6 tq j~ P m q`i.f9jҨ1~%g~px^<\;me"h;*ܾ~Kq=Q̣^7M)9Wcw? nJS}GNy $F;K@ &)^cXV#:q|{]a!=BHÏ:D9Ħ`h$nCe'sIX\ҁdgp-F4RA)Af*=SILgSO{P34MRօaSJB B4`шYI-VimD&!5}M.Ap)ݖs\ cԧoҔ~ UthCf) W6.Shp*Հ'U2͢ uOfj^Q2xٖx|Tʗy+ 0l]x-M)R)qWsܩQ,GJuvQ׫Q@k?ȰS5ׅÙ*}CzdsQ]\[iZK%t˃?=aI/"D8U`aVkzQZ+OpaH^ [6)~"vj[3ԙ ̏~OZF W\RD0'cw`m<ֻkyĽ.ya?t\hOI OiXA=7 ye=O)Oo:IGE9J): H1u-ގM _=NCD?· :(R59Wи{Ÿ*ue8}nv+h\z}4W*?㲺A 2ܾ&J_wg~8Zp'$ Yje,k֭{.({b'ފzzJt^' g2,w 9B9&V~|MZ7_-P] l4eZGЍƌ1$x=CC.*P~v=n(? NEr:M D(KHlU5n0Q0g|ꔂ%m+8%(Q7?/FYIi/TT)N31~f=lDiq2Ħ+3VCT z*UXNIEN65+aX<,%Al,kR痰,֍ o`[XT]t۳\8L11L+C eĊn0yi쵆a̡ YZVo:]j̲6'%nm?F="O uFA֣q| r{ehAY3d bw"f]uVT$b(=E3jUNRMӞd6O큯$f7 x[&̕c귱-둤4` ];St *T.9}:86;<U5Kc,Y,=>>ΔnQI׌~E3OgB^`UxH|1HN ?29 ǁB X˙c0R.c RX8@ijuCH^(M|Б&˹X'p2K]WhDщ7ImYZ@xx`JN6 ~J>k lK!tdҍp5FDttY-xJUJƍ'S 0QaSq7j@D1ѸӸ~8/𫯡)_ ȷˡ OY%O E\푆/qдI(OC& _r0c? &m%8jFԼ)q:1 )\*6aլHk Ftey1qQb.MP<#0NnA[ܹIE!ldwI)4Fd|2AA{5#+3fQ\ m"嚍.( #<,)r[pA%S]@1+eSLkV..sE,٩ѐ^?{gA$Ռj&\ɿ.RFMy$>?y!6&RhLMxH Ъ,gW6D%oSz}>\zUzbdQߕ|]$]2w5 o PDG>];G;zVx>7}`s: (!s$=juA7ТWvP;F9sK 8sTnrQ3/!:TR ɦ8@y+vƞ^0!L ;hEG~>A 3lR7"&4d5'~ŶŸ][[=ͤm8†:b(LGxON|ωdWotN.Oz6x{%P;/+L7PwNq\W(aAr8K’  L:m5]yQr©R .H6`gInSَ!)H|K  Ysrp&tod._[[Hx<LT:5(F-iS>db-k[03r8WO畵;kcHrx(8q:WS~AK*ŴYJU0ɪ`E Tm! !^T U̗c4N{%Z_\mEBsA/Me6Mj<!|ths|>yo;( Ig\eD+f)jƐ1=G t0:IYOz:Ym2Fӑ&ӂx".n$!ikU 2X`=^;k@_̌*KGJJ`^}m=lpacK SeEC(Dk'%z:9V ߆|d_'ː`# ̞Ȓ.rI\IֶZN` h9Ȩ{8a/*.W爵UsTUaE7ko{pz֔y=?oFCbr^0_;jc9MQ3 c7{0km!h>-n8u._N[Te+ =-ڐeonusIBjtʂp!!gx&& }p/C2}x/`5l9>`"_ _=!}0F[L9l[^< FZ9֣Nun k{[J[\JjHyw1s%}dc&qQ~fSl|H();Q90Np|ӥ׶c51Bڜ3!ԪÖTϪE~Y|GMxXE|"4~^> Z.eHnz 4VԜ+zneM׷O7%B5G ,@(\&43fgO"P@PL*n:;*ZԸ88"ie @y2c5yg9D V1?ۆM3>4rշl6$0^-~2,|l}J-v5܌XA12PZJVyƎd5A1Rz9IZPR{ SŊ{Q cOQ A8j );;a"SS5?:yqZր7|0mt0LJ%JV߄s/duK_aa(9jsMĊh1u!]R_)g(tжvSrGQ)XѴGΆ/ICinqHј)'Ə6lq1,/Ja*!4}rqX< 1{S:`DA^j(>MOJZEܥՃ~ |rȀA%%ltSMYFKɼJKo8\Wa_j~˓ /qʾz' W|֣Ϙ3r#_<`g78CI_㣿͍ h`GJ+bx5{MS Qq ί_ECE됾@Fnx1*ՙ'LtQHK׽T^> WǁÍш'xP`f_iQppȣ>h38)ZK;??O[Y `6yQllfrI*8 ,B =o2bC ;`7(x!\!_mn>uItkrO&֛N#TZӚn<DV+.c9$ A*ΙRu$*%VY=sZS yv$WwkVWMmJ ,@n&:ؾ榝 =F@dAAiDacgWY:*AyM"|eA@?n=XgWٖ ہUS_K̠/}GtGU}KwG Z.4cjeFPaD\#kUUlC r{L~1. 90Ws:/P9 Bxd᧞kB___}~ba*hxx*)hs,9F.fcO/w 'bg)a>x]mpo)xԞ&r Cxj[9Rgi~Is}r)t_n'$\- D٥6ͅ4Nf 6d695@O >&ӀUl-kG%rrz;Qɪ%mJ.@?'#d Rs^*AΟ*? mw`4o OI}I~5Jfc꬯a E*ó=0F}q 2N\YtZU|)[%ܡf֏)@b-r-;S)+c)rAʪccgd30ǰi85A 2~*"4E .&{K9 H<+ sqǰmX&¾T"1M JT+WQxMin7wj{O{pxq\y!t{ȜY࡟.v@Lu3H>8]Ӧ9^Is9 ^rWً؃]zc~{Xpʿ)Oh3n~iQ >v]{kit{{m5,`Tz$t1Y6Lg^䑅C2CZPMz}OfoƹmX)ݒ 1т.%ͺ n?0p}F#5|p!Ȩum!ayoE|Qƺ\BPrE恳": شPL]9*N*"H'0U'@Ja=Q8,zNDLǑĈV|EN [n GxÔ5xJImV:B?j:HՖ@!ad# ='V0O=uZ64nFj*b#͙6-J#^A ޞ;ODZ _ZPķ`9wXxObjhe=ט]g÷XXZ'%hTӤΧn@ ܆^rf0#CȈl9< a˺ ]n o6kD32g_P@kMj_J0RM1t,WZ`&Nq,FRcM 0E+〡q2YUQ=?}ڷDQ{ ], zFŽ' l*>KlnJTwI2m=rbIAQD-hT?JF.w/pxk&r `f{ͲR]teݝ@-^3-mfh{M1eTJ5ʲڔȋ#aLxƉw'(\N,#6WtT')a!"`2 #Mο]{z_X'b 7BwWV6!1- bS{F؇BpJ@a+̊3,8%<>DgHn[{̗.kI xNӥH{S-͖VhZ.߶mLPgxj!WLsaM:_]FW]wcbSrE~L)imm2av\c} >N F:mC|7̕{RKc9{TSe/r+TIJ˝0Y2}[[A 56#R-^݆Z*8A_D<]\CyuJ9סOZI(caj{nmBJn•#">uG35!p;o=H]^0IV鐏YVq>G}攸E5Mm/Iiu$El~e">NB@ w`B80',s+|oksx[jh0GTSuAQif jz]U23H'D-GCq?%Z>Ź ҖNY:h Z~⇑3wvbagCp胍B[3:WR%fl*=Eg=}h!1P5# A& {Cuv/w<>+rҌcg_iUv2XeZyP{ىRB>` Bb2af|8 VijŻu]>zjH!edRBM`dRpyj6MuiH6a# W&tz?]hWA(@7SRt0&MghZm;sH|[H׷X!Yx_͇E I / ,`Gtq݌ a0.F9t;HÅd;.IjjC.S3CĎ} ք"R%Y{_oY^IBoj`t7<ٝu'蟡N1 HEt~z\uOQQxڏ~㳣q=x;u&Jai*vw0o'$A7B"1!j'i|z$Ox4|ڜ4R] ~I|(#=7wSnRu$YtYgUV_^^ܞx-eUG9q^q"  Lѱdcdtb?w-WtYrerO^@Ro@e,c'>٭=Af 7o<0Exd~:r/ ӓn_mu`)e4yBRx3ʳiVڂE >\uz`vX7`n J).nBr6WfTTgwҧ'xg>[r>קHfwJg)DkjV+!Z:JW v}X>utУXBnY=zg.zR>55+֬y_ /Kf b pثL;IV'4mQ۶_]F¾\05 [o 2LvlJ-#2^-(Az^5ovZkp0Uqyvxi}h\iwV.%b8?#>#c}d pG tƂTaFxRFYn$Ąvd\}،S:1Pğre1(|AQ&~pe?z[K&9%.I5; ZgKc+UX[=Zhu{U %֒Èu_g',f5XݡY 1o#RsB9X-g.7 [~l31KumfݜXQׁ 0V53NGM~hOŢE&ʆsRnj_P\64G%jDLT#HTg:u' 9B̝3cUTeD!?o=#6O*,p§luv X-5 f 4+"(Z_ZJt4SI\3s=_wwML,1v/JB|'-8! ڰA8t<2F7aAƵS=4Trw27,% ̂+& ՜N(-H>ou%MМû=ԶMA8-<lNy+v@̹/6vN_Fa|If<lN&SO)<ZCkwf?'`Q~ͫmI^&fҐxn[#iSBha=f1NTa P"&M4cɍy G\ ِToWW:/*D&b;c m_PmYQ3hg/@D=Aib]S֧D_;|8r<*Q7Ý9 94kӆ./3/D4_nUYg'U:!A( ,2sx*`.XHo ^p"nu41=|1OW~glb[g.퉇| 8ZQ,ՔMҭMn" Jԝ̮꽅i&OBIU* Fsa%0Ї7Oal%JepF:ǗX5\0nN`I$[ﯣFΈk)WY!Ŕ>ω8dUwWL4Kawh.=t-Z߰=pN]R}hk1;3xб[3R4(t5 J^{z4'|aemvfolfY6>3.ߩ̕?ߩXkRӨa.fF^Z`Wzku,CinE`] #-l}ߥWků1/ O* ^+@R#~7uJ(j9qO+3dXg 8Ze*~Q +vP/4@29TvZDhyJE`ϊtPt r\:,@*>,</6yl"í5!A_,>ˠUn۟_9 i^%l;q{ClnTiTv=5ylz/z}2m7 3Y~00-y/Ln-sBBNE3ڬ8|8s\bzE{SV_<*uLFp36"#8pzm' NG9ǴxvzލND^ %bz(: x_Qa\׺px6g}6t+x D<^ϺӝuΤS"x7rcYa-K$,] tJs8"GJ콰1(9IRxv1-'P*')M(Bd% zJ*͈*Ր"8Hr@E)&"/*UB^%dpg*{*k&!B 3b Tä*ЎIq,*C;Ώ|$qRxbC3ʯSoPz>_=FR-K'}r4_ uknΕEkB4YXD Y a4Zu a]V.dy%\|0If#u|CT]Q@}[cNDx᫪a}P.#eohdi3Bpixl󾡹r#.v4R^[r azOWM\:JW,&Q~3s}8O<"S z޷0:I_V9)ZXC BC"bD}5 e}%͋#Yz c{'ev;-#B#fe"Ҋ MTi[r+\Q\\`,GUDճiq(xE\")Sx+ U;oqx5 +z}n Lặ!$Fp/M*. чv:m} =Q`ezK`L #Ӥȓ#XdQcm-A'Yy?/tI}- |qak2{1IG objPGУ sI:")FFs tYK]FQooy=Mrxabu79?"'k-S9'W ql(Ȼ)Al7#1N~կ %`sӀJw&ol7\Tizti0<X8摎# FCJW@܃i<=b`ot z.OXB ]s$qG"У5G%\e6ˊEcc1:,eDFP27_i}Մ)Ƌ[^8Y 2 3 XjtXЂcZ8$'%4$ƃPtv#jIS+O7. 857tqVL9h:KæWq%-5QFM3+#^A* _ʠL% 9 8H߰ZNȀ4w>/} ;SuGrz ='naw yIg܋6Ư?_n77?om<mNӪ095rBj$Q =v[ɮ.O?Q87kaMb`qVFNߵ>K*.O#`lY"*Q#R*RSltyۛ2cz+т,G,!bDwV$]7;G5r/{˯(t{OKP=x;gT15R">ҩl:{ԆN%'DxS;. <r措nG#@U/ 2 )E,&%ei u4CrW w6hT!tOL|ɢ7 $,F<$cV\\Rj17fzX&gp@8.yI \׺L~z!̤dT!:\\n'q6!C/J]pZ7`UBSY/{a1AR/Ѳ/!{y1xYM vԨwp4W( cCxڰW0;^j|&@zߦޚg[O˃^:W#b2Meޥ_ylsi(N(CxVeX (xԴP9Kh$qIx}7vHI%(JWmڛUW ҫK"42þ+W@zAVRiނKjc1׏}sPʄ]ɔnX>rbOa '9$_ra Ch?a YjaؖlZm™ G|IT-J]OIY@r=NAG> V:8BYAܦ;X剞9ghP'+a`,ͩ+o8\.@}F F+< okުVZzW,BقH޾t*ToucP 4=SlAJ0 )Q{q lR GD#fvS^I([ ̱aw~N7*,( a|HeA* EOq`+H,&bMT XAk]5BSleeR?*Zs@_EHcQi,sE ut%Y^3^0qX<P,d^1 8g`jVnʙ8 ՂJ" 3^RJ圢&@nŝ"o1l|WGk1s?b! >_$psN 8R7%6Tό c]td`d&z:x!3OO(!J# >2^K eO046P(?''Zֿ؀O;LHi'p)Ǩr~ΠW{Z `d0q;/Pf#K . (BמULo>\Mя7&ȗB٥J(<&1 .nrǗ-AV'|Ԃ{O&Ă䑙^p8nKqAEV \ 8z8?[4y4˽eRo9cKqs{ ?yU`q5yAEwi% IASʙ8~DԺ,N–aBY,E$n~KTKiP[ۯN Vr3`kǣWv(<1-,~Y%ǨǤti/ :={46^ @S 11VNWL}OƝ`|pw.n)M!sJ~+Tf5lk"Gd2r)Kv߷8iav6Q +OM'f嵒Y0r`z 9I[f9D7>1{4ss% Yi}823`X45zA%n/u ߀34vQC6wgRdXXe~n ;5,"/-O:yӭ^<0"0~Y2 `Ҥ`{A*"KKE FU=XǰY#1<%CN Q@PKQpпn(qäD1w[j fj0ۖ}c=y/eϰ(o31G+<8d E!,N3.Rշoֿ֕Ǚ0$ \T7)d81ljytqh,9ŰʜAJ4Pw_ ³ eQw?0})Y/2u=k|ł9^m,t3<&B6|yۺ&wM !˗,/*g'f@U Y-Mn`뤝H 8 =p{k>L?K 达o[kOk:%h,.·׻C'4߂г,b5TZs6A: %=w:B@EMq51RNP?NƉaY4o9 v]bm$+}k/>ztDKae?#dҴ t3J>vR|ڃ]d[,j X SO ŦS8!{6  Q94ze,ʻ8ˣqXvK}P70S< B+煮Eo&EIn /^t=F>O&-pe?2\w[a#"=L %s<SF46.mP욾`gLpIǓ|-ъ/.r-HYJ]$ IlM֐`V* @)_ W<\3bzzU#tX х(*C:C<6Cr#\FgWmй8{!âA:ɼ%4@y6RS:$wEQkv,\`y]彍=}8CCNW eeUe+P%aC]KjƻMwt=M9, V\Y 6ŧF`aJ Qt,ݦ$*WjnStj%6'(K xJC Ppz(9#"#LЪ0AgsG祶|3NiHÌRI_fgVnK;_ȊNz@y&K~,8Ep&sb>i-`9s E4Z K4~4$j #Xm9/hSʁMנOs";,%E'pZ`lHPd(;WO*J%EG;2 V1!g4(y071gCQZAYMP*T^JE)2I(8@#LИƩXaE:@M j%3t2)d[IJhC Z Ѡ5[I>GPmXz`Uo.CXQ|EIy|S;Vy,1T/VGryEw [qjʠPH[*bJkRd] OukT6,f"jn.&&K)ؑPlu1WQ[/=nnw6X콂wwc޳Z~ Maٸ (Ɇ[-Z9X0*7h l)rN.TU)rAP^.)2Y[;:<>PJG|QwyfSzSWA,E_Wl{oHkS!Ly>R)}qHE5X q-G)Nn˫֍WY+|.H5߹р4Vަt#c1:H/A ~&Tvzޏ$GZ@0SDw>ap;yG[mA%+3kw>jqW4 K Yn/m ? 2 D/zZ5ь#)i9yo`Tyqe)e j#/{.M0!j՘Ii;Фo6ryxgQeȈ\ICwW}9₤` L(?îoQK`+(j쀶@0$[9LK&hN$e1ʳn<|ItQ֕*;T*E: 6 ߹H9D.Xh<UBo37O٫MX q!s3ؔ-p;.4<3ΡycL! ,@t2IM|EyNbA6)\&g[(p (^Ѻt1AǝRGU8{y}Fޗ_ , _|I?,((l;9WP^R,o, #dg)(z߁fL%EdBe+SZ5 9.g1~!,}ZBZ@];6\ t{$'E3&|/"mDWa*U}9V5MvZjʩq}v>@1I|04ZYiw(7P-䴔ɢe+! O En_зs:_q iwζϤDt=&Vc taN5+9fV3tCo٣9#GnF$ ڼ<ģQYc/&#w *۬(|:E!3۶$(D HQ*G#l$AS{SPM*(dQdŸ,YSxR m +)~E?k9s|\RW@? L~ qv 4fڪFMrYU6%NT-mLIwVMLβ x_Hǀ HSXM'DߐP ]Dz{1lZU!ILjx[.$%f[[9Gr尤Wt@Ȩ>u.Fu,;O4βDa'52,Sxmi?-[͐WG)L0GG"ܓ6 [?у̩]EG҆ ȑP}d 4lR'v-,v%DAp0s)!Py D:Rc%뽹b".Ü\2?VPo.͆_Keֿ]VSx7!5"12J(Qk fsH+<# 힟''~s-}_eܺKZ[ ݋g? ƫtA6IgX١Ajݴ̹փh) \\V/(=V;V 5oZ19e,l(0YxII[;ʆ^Ỷ^рJ.Z7Ϯxc%oX˭1nkkW[)MbeIL ДKɜY`cI> 9s`18 z] 96e/EaJ@,C` T/IZ?ȅy21} @uú@8zލdG?#2eSw(uDf^QB5')JBڄp'Z yuAֽ/Rʺ4N\Ae=jY}js<2! ӟZBq6Kܒ#T wO`z|j RTXU@i)|aeS> I"za#+ODe2D:+椁YDڿ&`ـsjy {j ]u3qGϨ CT2ˈ[xn)5_"7%MwvvM7דY_p^K>xW߃ u,;søQ:8<8Yt^-buW( -GgTLC;w)׆&t%g)ݲhae9 8+]^[G֗ሪNVV3JpNQ*;@$bEGۛG: EÈHn#?ulF&[j obn}~2tnFXcD#P.QpBxɑ&oC$X^FIVFMϛ׿z_os 0p=ٯ*3 Of`'$M L)u.3h:JGG3N2s~_#3xv`frlCL6u+:ҡ>m](zx#D摍1}aBa< y3PD:Ԟ1O%W㧖k9W-.H5.J@?).%3dʒ:wGAOz#;˾[~zW=QɾSdqY@$h~yքyJ>rx9w JZPx%J!Fmϭ3JĉwMp?P%pplR?:’تb1r'm09|#:{3dwr0/sx8srN {0 գ~?ZVT cd0I"E9k9mIݧ*ƻ͛EbY5v$Kܦ}~w.eq\.)PmIQS7V}o4VвoU^U էi/AcDલ0vg,C><\~[/`ϓ_D^[Ρ#P|tR>tfh|_,pأe{rpt?8ekȺp kvW}@:_M94;pݑG{YM nI4;HFǀ *y%s::p_C`<.%eU:tcGEl4p([qk8|L!޸ǷY|_d4lu~_Yd~mM{w *A4D:9ӕt۷ߺz/i1]yuy=^UV_72quvة,8w.?8xw$EDzMeŒE5I)JdMaI a| N$ Dl,;i-o{)\SB;.7/+$YxU${pޢ<*G7zn7Z TC& _Q~3j0mql`(kf9Uzj*xxDNahOFMT^לf$Ā(:J5AcJ6,X=Iƃ =;6ώtwY;=^6= Inss3Ѡ0W/>Xb=)M. 7 Bf=`2FgλgW8QH;<7UEOšiI^1e'rk>.=$EMIʖentӏU}xrz )ʥl ?<=<8~=w(\znA"(Km+/I]0ЏWc&1o s7WaYܥ< 68 c񔁌hy!w7c%⁂ q%ibr^^n4,:{Ml 6Nʺ;dJcB5L$zp fOolm< sldNL6\|BT}bcck ᪒@GY+cw w{E1#>^ b'Ȟ+ǐ3Ԧ4n0[Uz"_GW x&3]U_"qm6aWD\QH@WMV^hVE;ZEzx W )2 NȤϝGGI5.|d:+b@hf߽1ۆjq߸.(+fk oDК}J}Xnm['CVBuڃ*\!O9Y ƔUB] DFd 76r,HX8-Nr/Q%NZ'hj5/YdsgV)9^C\~+v{~ "*]>|OŠ9jKp׏-j0@EQjO e$i*<v{T. lp)G7 B<\)zoy11Ȗٲ ڱ`<ܢA(KT_4c\ŠXL f6ܵ=5oqwww_;,OC6'R3U2Km 8ml}w,2-9e$. sG!,41&oLu ߟ^ V PSd6H.|9:D{t&Elg)mY,@-sO; ;6H HғsBcS?>M vyxdN!ʕg؊iYu}en0X:uƋ(Z CxxPl@x K@btnPWt6/u'L| !pgN1.M"q@htq~T_}8c{HMVCʫP*Gl^Ffa`%V]ƌ/a!94`7QP!b}.!TNꐶ,Ag퓃5OSdU:z0ۜ]&dE$ǃeIrso {paj|c*ϳΡt{y֣p;  {5T] 1о(!]]4x`un]- S~z`zgyY%bh_p@t;C>a M֊b6B1 |fW.u32aiڡX =԰9|P@+7lC;('%^~۷F\'ڬ*=p՚h rbH'fQLBˀX֩n﫺k,KjQ2q|f4̪BIB_EǛ1A*j3augp<>]LeqеúUS30`bӂm/q!Gm9~j?X]Eܶ)=ByW1Ӱ:2n7jNhwAR\ 0e+ꂩ:຺enAu[WT)2 |O>UTt/+酽wdM2N[fd 2W0Ylg3ٌ,Fd^`gordT.nf~p2&L3555h'A8oO\+8Ry5IQԱE4M(%md^*RTTk0^AKX'toy.C^kp&o߼Ɉ/!s 7]mT <2ٗ`BSBɔV], E-0;zu*Øi"ҜÖFחlkM*q 0q[׵۔|gZ 2Lh I-FC!$bbWVBС4Ȫ2! OԲTVskV8v.8;2g3JNgS-*MD#DRz6ܩx{nCϰx< ERfzCz[L^ )qxνʵT33GZ%&ڕQ䲏w 9,y p{,{Ez`,Fi<c m88[i,Ȉ{9RǃŎ/K;UC/ ede#%3?Tqb&EMo K&8 ɠsWc'TƢ^hBMq^u H]Z[_=`'/4dK )o\DI6n2>{^#{`uWf)^`44i Hg{vXϘ|!6D7 -):Q@ˀ E+8k9IMroI n˖xs:jMvpSxFڇqGqFkMCFxŢ+̬`(OE$ 8[I{hfLC;B;CY D0yh,(8=>S}v(N,mH'uyG<# Yc.+EJ&$LKBh.+TGᆳk'n_zCI^1-8'ؔREr\u:h'Ffn!#u-<24{~{_N)x)x;\KyF8]E( G?ZS%ijPĦ/WG @ fqQޙBR/nAG3M;8h4}QP|pB`AW&ط4=FƓL,&!m 5섃L=qR1i $ŹՒjE-B͋цzSƃnL\wCq:Bt^=?; nkG9Yw./hO+H"'ORý$eq63t6F=AZ 77N)A>j.a] ]ݵ4A:M TkTziTZ,s_u9E@EFpWk(CX"yysw[nІR9Q(uؐ.u4ĩ"8.)X vH9rD׀M`vlLjS{SOwLOxWPL  oSf00HAoe56g;C-55vbr$zՑр$9$JxF8cf#(fdwt~}e;D]`:#"k%[j!*Z:p<] #> Hg@V;v+Idt^epW!#t2*9FdR9LD@[Q+n+u SnY_^Ӻ=bCsR&<8t!7(Nh|)XbT ֍d2@{VNu^^}jRL"5= 7xoK6 E/jJƃ9VZjH7Hd<02>4/2>-9q/?3P^sIK^Ɣ|D?S;kTw %dc4ͤ+Xlܾ+~WoQIUS ?7]E tmku-%\tkkϋmTc$fd!1]-zp]_b/B;ה]&օ,OnqkCAf"c"0?H&h]i,PFE1]&hn@~/cqwf`XIdjhU3UJKH4y% k440Xaj{Oxfmn5qB &U⓵vnG44S "r<6GF\[r_ ۻRqTΏgi+7#>[xz",E`k;v~3A6"wRxӷvb'y,GU8h#г B* |(Oig / 6U"ZoWe^j(Irɮm%Ԛv3Zu,WUrDwlڗ?!Dyp\7uQY w"O?ET~uJDQ"PQ߄vάSZUGG mNFZd;uL:,g@ؼ< Lɾ 1=PpaS>(U+>[A( :žu( D?+pErc"\34W*F6 :, 67ůՊM{o(j0rT X!M7Xݙj I8QG抹\.Y[p>O/*gġsZ3@N4/OyjTA3ժ:W35Zn.bَs%W#[υJA~.VsR\R+NeG~ޭ{y uP9\z.?V# Ȝ!fXc/;u+1MKpChѪ~%ZqfCe\4IJ3ЪWKG+wD¶6\P>뤐+Wz¿m#9_ChO60ZN|Qs5ܼ>H`>+#ǁuHaiQW8@ow*qp&&Iﬦ6Yx[NmHI΄zC_M \:Xeн{4so!jiիA[D߳nc37 x+!ގ޵q8ۚړIjoΫܣgv2+vweplkFQ;SڋԗԊͬiL&<o}C3r4+4*lu!mDh3wBϽwSOK "OֻG[^BsRs_GCrhͼ i1se*iRNh j&4]NJ{Φ"-f S<!Yz)mU鵤F ISg3 `@, " {2&PP[RxaRop#Ar"c  DUBW%IwpS1B)+̕#o051 0dȡ,qoD6+ dvւ BNѾfy/c<2*iJ9(aatMoĂ\!;.qz)@N\8:ykSUË;;%u)vQ widwX.brZK,&aggыe@hoX`5@xk=jct>xZؠ"F0.[/~IM.,6 χLp' ZHUU⊈rZ44`))Ȗ<&3Cջ"ԁR馘sxk)4y.7]7СH x#Ȩ9Bmʷe.$5>Y Yfu|R)=A$\E9n79u>L!5b]z>HIFAwuSDHQܑE'@uR`Knݮ2/{Z3W0d KX07FbJ%bıd6nF#iqӽ\ѩô+8ɛA=0" ME9Ry{Udm<-F-{KkĂwxwAeNňj ,X\T}! ;"L?K#XE4FVmV&"~TY_|B5Pꎒ^sum1ϕOuǿMw&t5BKQ~ߡؿX58Xs#g8U67(fHuqӪΥ|J HPg r^͸dQư "&(Pp1F@A*лv28d!yϡ ۟woyosu0 Z(iBvݬT.(A a kGqg4:s(Xq^9 $pѸC5/u`i8gZm{LǕ Lm{X e6coA2G%134q ,v![.{W_X^5cڭIج]%2 kkӧ4ww=J>(S!"&e=hL11O K!>cx;b= rx(mwRg[Y*Si`(k׆e я>qQx1Ia_MoV8jx [&Q )$PM͒[+4q_ƴ\U֤EcF"ND߁SHW(Gṕd$Ug7BpbF6F7nO /BVE |GEAbyQxU?kf+4v0k䧡L#mzs\z=:x(/5a*WP8;ڛpZDIq$E!V<֢8_qUx\0v 2ƺJ(?/$ZA E_xUa:cIl0FbWy1P̮!`2 N)}ƆAɡBR{V*yey /2upՅvBL]-]Z9m[)CLC[?*c`d>t1y(9Vٓ xM x8i,D gE H)άo*wA 'k&?HBydM+`]Z ^U!OIZYVt`XHgrZxm:DIώi/dLA1 =?ͼa Y mbv7&7 1HV/pF5w.-r$&cA'Us?#,-GQƽ :)r,UjGv*Q%B5u)X m7jGJ\j v&X\<'wC2.2u);`u )<ϣF*]"ޒlSrLJ?q! ۀ9n+/K"}핚7E1A,ёw;%D(A'4B=sj8sQQC!WW̟Jı僕>1gljJeT+,M5?Gs8^%&mKW* bk&7ɇXfLh<2]YS67J`u7fnQ!U8;x[>S!2J~֮`2M)RLԟQI(˓,cYv%t;c><;,\#c$x4QUݤlx$5⺾ 079(]Rf:2yo3fyЇGa(fC3! =5%b 2v75l9SGô+JrН1\Ja?.YذVzCč# @KK"/61 $f%qccd 0N2R4vƫڊRn1&\ QyQ_ ˜J>XԟF˘7F%"FIT5 4 T׋hml"~6^@ 2Gģ"1(lL㍩;ԺF6nOkIC6?6uu{9u<$gI[ƗZc+9kQir4d>vzw7ΥKZ|B3 g@J+c2,Pݰ0 w U7*-/Voe2<#VG7ſYaw0ta^>{aިjxUE('%>e!0`cu))ɥe?-Mz7d:\^Z8#_˖US~r,m=&=T}3Ѯs764{u q[nZÀu} om]_nf|mݕm0.{˭[^Er;b^7}laES(w Hk߭HCOfߴ<^`U:7ޭu4ITȀz9ؗm8`xN$)74+} =ET>Nj ٬>GISlU32Dw=w, ϿUrg~:N@hk^}[A˵ۇmOBSwW:ˮSzPWY9Pi nY.KS5\qu w쐏Ty ]V-a_~*SF׿ k>}h<+ee+J2#Z#i~mu{~d;6j(CdVj󊪁W\Vt\pTTؔku>ݺ]o|kZ9C2o}DJVM[9Oe17;0S`QX#v?KR{( ߝUN!lD&پu߸O`=w\pzqtxwZrSf\H)#~;=/Ǎ#BONЅuEAYnb{_{}^+?,O=)/? V!`Eqxyc}DGsA̋_gKAތ:?q?ǽ, +RCV}D]-^FB߹u%Bo4m(;X5g+łjM#N}F<ԗ)þ{§ʉ_' Jorލ"WXW }!{kl-,#ǥOy 7|yFL̰I}S?Kg '~#]r!(5|sHucl?$r ?_n}SOI.Jt{}G\~=.4[ /.ɘ=ZC;:&=F]~ 3O@||Q)蔻V_74V} >]|q/hLd ҿ|񺰢΂_jnhqFSU-jP*6؍VP 1eTeB œzP 2i}N< У=ӿT~SÚ%Qֽ5znOWޒ`B hk+= ܌{Fl;wLWWo);+=7/"bXQ¿De,cl[dŔ E`>1A[9Jk]zˣDҰ2wIO,N W;ZuoIqGn|\) ˞ױ>ӻ@usSUhgMma[40en?+ mc?hO]ΟݡQ^Q:e O = 5@yØF׻yXnjLɑ.]YEo$z##D76h"":I :0A5z. *D3NLg&,,QA ,Tpr_1("!)%yջգT S޷V@~}z#CMG\-Ψ*'5MU`$K1o0Q01FH7g* zԊRO.2 ܙ;;VJSmrG&D :#jXM6Nß' G$|.(\f+)lJ!Чk\ w5 ^q6UC7?hS^grBy?^_)I\3 Y^ _*ME4G܌n0  wcЯV9TƕKZ{%60b+*P|R^[b[4(83.$[0J".ѭF P!֩O+o@t85e,.+īp;*EuQ`eR̲ȺOQ_h'~;ԕRfuh:RGdE>-N$(\yKBt"xw׏:FdZkoTIcQlǏ#uH'~ yY:|,ʆ"7YAVD/~ԡ'qM-u}.eÓkQT3A@V@I4(\ ֝P:Fm\5zgʹ(=ֲQQߕb*RzؽjF}jGVC*h49TTLzp[ktV)VA\s'Syi2ѳ&F7%=t2G! /f5,zb-P hYQ^^ɢv ~DqbLaYtD2K(! Jl7&A/Ԏir<<X!&Z"/LlZl#>8dkC!֯̓PXM =sRx/TT~x6% dFIK]mDm4f1DNҚM1b5(S 6t,8Er(:3fATRm*e2VvNT&el2b5)+F1IY)`\1̱e"!0 0fsLES|NoU6^gXevQNO)7X ID-8;]G2}/ Xޅ.`8K&zP\XjA+;<ݻj5&]p"B~7<0TAT+hͰPngH17-J28;jF ɵB*i0uaȀ<(/:L j(WFuRUL.5\s2k,Z^"4 ?P`MՄ"fȪUoGgZ\(ӓ_T("wH~@CFMlE4pa9@Ę%9h=\斒譆kW%'{VK8sј"w^EGtd Ph4G@$Lqf&Lc%CYNO6zO|xUCNЕ.jƷP ~\VpN>=䋹2_Y|h Д$Pt<}z育n P|TDs<{+%٠Ɣe/ 1TԵץ?>3N |vAN"yhm0•Zv0%.CZR,|]1wu8I= xz/^`}c?j-٬'|ֺ^Cßۭ㟡sN=Ct6])rL5raT ?n?҃ 8XkM~/*ҹNC듆 <3q\Ӛ&˚ʞ4ΰ]Oܝ8Vŭuhzj%&l>IipinR?u!1wo1.#!5矚:" >&"΁dGu0UǠR3īZȽz`!h4zhMRP \~sfٰa܃>X5ymJύ]( [ lȷĹli;.wLJEX\+FMraZ(tZwzD1cי*{@M%grf%_!(xɖ!Xkg ߽ 1 W~ooO_I'L5u` ݹ ;w—_^ϳN]+6a8nϪnڿlZcnWm+az0GJ5V լk%yX .*RAb.Y}o6ɗ MRۥB(bb(ֵڳ(jxZ_&z{ P `,rƼF$~TIa`V9dѾnb4-P LZL1C`u7)>rXWx{%hw(ǎ@=Qa2T9>J9XdvzrZ?9]<^rRK1!q;Y|@~/a<~g.*Vӫ:Þ1E ol"Rx@|N)kR7p>wS(X?@ E:.db.6٠嘮;8P3w A _ݔͱNw#** =tD-vSg 'fE԰O+MٰC9WTv`62T'P㽊Pz ދǴ:Hk[V$['B=ĎUD*1lXs#U4S[kT?m@9ZGi{7wӵm<)@Dۺs;֚p5+J9cq.cJz<y[.6AmeǪM˘i4Cb4+XgH$|(<0^PYA۽4%| Ҧv+W,U0-)00p03m C06pg6io{lU G:r&,OmE(,q|RcQSșu[N'(AxRl* zh)q6Iy7/.W_jk5>V[z1iêgg~2RVzn9ǯ^fiZ~OTY+!u=g4QTP. `ӷρ;b=/2ŽzK/:ݫ)W;i%U80jN$-hoP5eS: }!vU:CY;kq1h^4uLqN45Z;ـxR_aP$J  ?5l@J'%!, |㮏ZdU,iÂn<aF`7L*U$+.W.)~+sc{cZx&wy ƒBvV5*ټM&ՊS~B_ӪH,+Id>xB ܫ+ /t qX,턣:0 $SXn W`H ak7|*=4XVbXS#Ŋ銕/r [( v: ֈ4IpaYhMi ,jԅѭ^^C:9ka4 ;j֬| Y0@\6[8!4}F_k8YF nLC|Ua?[(vKעqȋ &62p8n4\ WFa~mEpDL:j>o<9*SU;`sC_uWH^Ȍ&?#4m̈́nReۦrxHU'(3W2ۉaeZ{9u Yt pf6 iTd 1UMwz0 O!gsEL2 xUgm:e E+ZaaBy<{[ JEvӿ.y oel |405uR4Șîc[5<1;@^ZÎE =˻Јc<xvB1 mdLEb.)dlނR{D%;3#by@CF A2]gm;f+*KN!>Tjjp+{@62E>sR }EV9mS? GO;|`&"nܨbd v" ) A2O,ŖZx ^K%-chtOMg?LN^G7-m 4J #~\*SZ̺GD=(WtP(B$C |S?L5ȷç\͗v]Ml$f#d>TE1CT nPQ<ǩ'(- 9Y^G2 Rt8N|{e)2T¢&խ]_fL?2' ޶YiUP֕th^7 '~h>aH^ G-f$h;1ϣC -ޏ}aGgv*.Gj{_`7p;Vw8!?Y$Ƕ)4Hdi":FM}!N ݒʔ 6BNoInQ>ƛc%7lE6o~-gz-:tQ,,jph7Tw܈Q /jq=gzSrT@^Ń>N i۷qe#Eu\pk7F!C*)Kqga!b,mqޯcTOqAvXdkUq}WѮc瘎bq+dϩh>WL qbcn?^y(@{}H*㳚-ԏt@E\خAra?ߞp]JKw80ULš(CQQT#t6T0[#G#QH#⥄.^57?ҵVcFX GJ|g1+Fr\AmNpyfb'ZbԄ8~^cFj%WHǿ`φҕ"S֙5]D0` Q)a(z#659Jy!I',NlxW\{x8&]C O\9ip?/ n0) FUwN~r|jr gv# ZPҎ&AÙM^J2IhM1겘Xs'_hbσ{ HP\y)ka?mQ3/MLp2xW[wR0M~o')oF@g$%0S=n/P5ޒ ⨬2,/ƛWTr>nx|z̔gg"TCғe*stt z0wJ) |2 J[Z;[{=# Р+#ijͣ$A2pY.S6L/#ZK$D`X./ډO :ј|p2V5t`?]N?lU1bqySl_QCOAz2= )uk\i/-ވj6ǿ.mD4dڤU#r[,eN[6fg@ZF8 BX8sx/Fo6&㒂NxS TvtD\vgd-~+Q)Si07 res+WR:43w((`K0|&fN^ٛ 7Y m[?5r}^7M{8g}f]YUG2͈4T+*T,s20+xCP1P 7XtaPW? <ϊQVjsU.;7Co71Jqut~My͆kK#luBiAv.,Ȣ '4Ҏ1΁xG}J[l]w1\3֍.HY7ҡ eHTuF萀#()a>pnhpE5ZbDvۄAFr[C [Bp*ŤEw\䃎ᱟB`܀9׎r8H5gp@ݼsAwҨCzoݩ̂- ?(bB^ `4gH3CW]Xk 2 1Aaa0#> ]:Fc!" {teTkxoSk=v\ "mW: w}r0X(c"涂s=F%l,,iK5!O;/‘lg#L5ӎIdI6KeWReT"# @h<\0}㒅3 (QwI@ISL>p쳫+$xKv]0pFp- |9p~e敃fwB  }< JN'ہqukl-~,92N-ԹR) &bV q`5Hwg5>=WC4ExtѮE1=g,x@1"qBvj:L\tAu^(2 7*LYoڱj0km7gr; 5Q< F$,V3TuP*6A>7U&*oXvTPjCE 5TPX<4;>b؏ -<hkz7HӸy<0Qc5~nDq!n.{CF'. $Y:N/E2FOF:t?}3,gzszRVΙVAl9W10M Ԏ?Qv9=CF,Lgo:]+  y[׬bE!퍅B`ZH&"@9:{=!tt^-L7tdy}CFs"[֧WR_0Pcx|!r?Ӏhe\SP;ܕlslm}Qv DǦ5' Zܦr&jܞ~2Z1~LCwx=&J{pB3s?6_[xxF8ACѮ07zbSg_g#cPC*!K+W`)^qJsG/Gnv~^k6X)< C9_ۭȚ4Ȥ? =wշ sm | ,bhZ0O^2P4y8U;tn`.d)b)c|ȕAWcCY,?hJ,"Έr[/芿ίS`iEYydl=+(-V6V< ͭV2Fks- Kfl<-Э>GVR'J9߷NpѬ 10}B(NQ4PgqN2k,6lBNFhFkq6Rjts:rsUA?W$TƲё l1OvO}]a UDv2SuGLn@wC|]3ڠύ3%rBGwkSJxC͇$,j7}86>kkӒ$(d!`3jC UbM偹?KA${RmYw+i'Zu#Kh} ,߄{bݶwMn{5CiqM&߳1  ^]y᣷z',ߖXYFQ(Js58r@5,D8RO܋]N ).e8(ay} kڰF'4U4}R+X&l#`̞kkluU,)iLEz%JuTi>)]a#|.;FɎn#[ bے4o!}*`9>!^>ٿܱM":(UE<٪}&PQ a^}t&$errz"~屛E,0_e@6V\v'Q1y3{O? 6ډw;̃Ԉ )L^)?7mR6{b57JQ-'`DE+_'D ŽU1Ѽi<' E_/q 4;4 nW:UxHïۻ(Jl3?Ǽ6wnHjސ.],!#دIID׸4"fNdtHY"ᵂN/)a+s~.Ǝ+ le6WبV(V佲a1)_e"[kZ{s ֡6"wqܮFwZE%R2yݣ}M]>G_i1"ꧩ=WuJ|sݮQ=x[ אap+AP*Tb뼺"0To?ڗC\{$~>taAbG FM=H~ tuQTuz\fn8DK'WݣكG;|Gu$ۣ R}z"F[ #RjwWP yOQ})=:ww.ts_͘SENED]}$oB4xv7R*t0P D=]3EJOoQ%)e?Tm3^.<RVb*P%mϿ&@$ψ tP};G=3؋<h߹)LꆬT7D&AZpH"}HC㢛 /ݣ}GJ04~t=tn}Xe:2!V|%2*eQ\5|Z{h纝I(=Qn`V|U"ג0qf=^ITrFN`ʵt')Jڣ մt-G ܬ{E!'TlJK-8(&h|oӻCk]9T ׊> ћ Dgsd܍#j܃"Sw3<EP}$p*;tTWJģܯQ;o-~^ >p6zww~^y;°(A^zFYZp| Q7 $~cNJ o)zܱ m6s?Xu<鐹^cČDR7$y VsIE%V gb*iJn|_CTVR6R3$QI{U>IJ#`5w?QI{U!fT%V)'*iJ1J=Ǯ(#>R*QRxxѣ0%ʢ n qWSkL Aw@Y9º_YI}T4Jo1cڗb߯,ek>zIFY-,T *pT bܩGd: IGu(³SEΕ*IT ֖*1/U`ir~E7JRudgbP$BTEXU IDRH$BBE d JDRH$BŽl/eRUVRqwO*6ߗ F%IT-E^JsD}WBS{W=Zby{[}T*cK9苕6T' R.g D-6; ;#Ra7t:J*ܝЬxxUٴa[j*ɇccyTɻFSJ;dFЅ;VJ^LnQ;cv- |xѧv\܉$~{Q- z]:Ǘ~gM$/x{,VB-,kt'4a%=ć݋Ĉ4Ɵ 6ro*z۽*`}KtO| 77%AKq]WJx%jA,’ eH=T,Jwn lr~ˉU+v?o}P &v<'/];r\AXl-[[|,_{x\N)gXyŝgPX eMb{Oh-lsAfQqƷ}2> &d]E?xx:/æ$( hn{%^.a,Jh$SK+Od^x9A2LsS u\= ->aQb'[sbLնwt/ kVx V9i辳X*P *ވBC@E=ꌿwdj0ޚb_̢miP.F2ziD0 ӋQ"yW )7mA}kd-~eao}N{ޥZN}+}Z H_~31θ#j #~`:KqJOiBQ++֣wC6ol;.JԨR ͽp,!~]#n#_#S[S[ɽu1 uRrSb\tݻM, J/=eU"~ TEOMS!puE'uӐA&o#d#G!qs+bwĖQEY$w u՟) N_}ߪ60 2Ixhg茪*X)ipƨ Mld' 1O-k<)C,dnJ6?V>f%ZՒ`5F(an#1^WX$>Iz,$ZadEU{ݰ1EY\fOAƃZYkN^(_H._G|ȃ]q(]gPUxukCakQ/LF lzR[+_PZ("NW+S41lf7¹t|i3q~ 3bV`K;+iCK*^Nʙ%*ʓ;mdLZ?_]UnMR#jseTnBQwEp"KnQxQ|[m9B-߷?Pѹ?o翜.g[ի[+Wzt Gbw/X?r50C_YbKx [Ɉd8 >qC$ͺAƔ{_jgˌAsa_\n/y *\ z9hJ/{i21j|E6FŐj[N- cI?gDweY)EtNgX9D1lN"KrKh $5+ߎqOQZ-h 0a\7l x"$U؏[J,4"sRct7ӍnuxhR,zk7VP |<6ARR} yb|AEg͹x D&oo`-ܷn F+%t) Sʢ$>0Ny :,Epoś֎"^Tp>Zb54c)ial}ѕ]{؉F}vTAma. ,'bS실B<`Hqf*†ܸunmw=Ĭ5k :a4` `w- F oDS%^nǍMqH. )}T4'zmEcDYnu~F`y?AP/ե x\tG._b2X>$HIQ%Yml7t('lr}9AVCVHvcX@0ۧ^T'D9|pn=-&CgEKX|⏈L3]W[De(.&ς}zg6KQ#m̌1z:NBࣰ[pMXL-[鑁SFe#KDt,8ϳ}Ɲb nl$2{PA+4nΕ+9hDKgjVK޴ƣj"]4 7aДA/Ĥ)eH:ï;zF+,ۡA;]6Ʉ`U!A+!A>HPń ,>3" "ֈߓ?hnRo <Ҫ:7lNQSsO\>QPjC':xh}gF㔧O΃x+J~2e3@QQV@qg &MwW`a)h@Ld\p`<T0C,`87Ow.(ӑ0]fB-lzΨC X7ܠ=ӛ^:`z{C1C,᜵[+.ziE@8οdlb5U<{5vWI:C;/G%yvJ2mu|8Zu9 (nz#h 7R^QJoZWxȶD$ķa]=`' &o01|bjYD\>?DLC9sblu; I]$-߱BxDGtdI'Xo8u! g!I.VBBy{4t:݈YF7.=}qj"<_dq ꃘ>8:b_{(m]sHP*1Um,UM3pAhSF.2Պb.UEqKݹ]b(׉AztG/$ ]kV1ź7'Aen p V1ʩ(HBe)ʨّ jɖ [E?0HޡA0_ӂSjdW ұDw*,tU+V]v q8 W$("`NNj++[#xBSG5D+J * 5(iPbS0pK(ƃoAq (S>.׳\Y, %ob%QX>WTO'P8t=JF3XlIjmzs0:ݎȣ: TٌįmN#:H'Ř7=@MIYJ˟N K(a YN,5-*a`8;{[n+C҆r9ߕ<q\pYdz {WݧbV|txpKWn;lAg +vsViFqa4 !^l$5a@j1Qgd1lxf,{ǂhBl'9~MV|5C\"h( @ b7{I0` U>I!GSx ,HfVvU2/*lHUOtmZ}p}Q?XX$5EeF+3?WʹQr%^*p|ȋ̶҅(dG|]!aVT5bkN-YTǑؑ";pNTDS>L'£NF\VT~owˤW>p歶۹{jzQ{nݤvt{ 7|Ǯ䡧fO^geZI^M/xapAϪWmx^z[0, A>ﹰ`3bpE}t*◿am}B[]}_ CK2.;D`;'bf" %FD~{w5A iuIpÝ>() _Fvsg@x U7.7Vhż{"Pw(䣑Q_?dQVi(=kn @50-J+E݆Ħ4 GXȰc)pwu Z#a9aR&,{hJrxvPwAnP~Ga>p6S7jEՠ669`Z:ɦ FF`}Eo݂,_nlI+E1Fwp.rp~Rd =Ju"3tPTIHyqĊE= j6yzF#D B(lMo7zذXNSY!pAظ*+-h -y;7*XX,߸q}qچ' x'7;aXAovĖRnX:9j+UAUn~g;ch茡qY߷⌷H0d kgV`X-9x\,g͸ ^]LZa3#N`Z=Fm=g΋,&]HDʂH`+>=w bBM 3l[{CϯFI6Sv@Qu;ΐWglZ^K1;iBMAU'gHHX Kxí +* (!q )qKY');rzCZ&vez -<`o`"ʷ^A;-'1>YK>SE(@T^uCg(P0KF(c(5¼F|~"08P)[*L .`-߳Ivh)pkga/|9O$kBH^C7bkMzm;xxh:꽻"P?yA(<Emꃇrڸ|`P~}@_Nw=ϯ _RBQ`cȣZ*l&qχ︉ S6XLj&C;уW1sJDS*#R@ÖCfZ-XOert 1<^k/c,TQQ 6o?vyzʛy)}< U5*>a=vQwopwCC; Z}+X ԎQլa(|}h]W6~B vAR;:BcqXY'3 io?v=yEmze KǧME~OivT 1Xwz=|UH" ^]l3<ͱؿ콍ͭwں:uǫ-(JeERf$+ko(#H#L6ȘUj6ooPoG~5GVL2,ÿV>`}Y=*P ȇ/V{@z hZ ZJ 5\@|s/QWٍ拹:_mA+ 4l4AIf]^`rz~wQ6FW~C$q\h}akla8Xc,N+D1>BeBxwM&S2`Fy7j`,)xTx36`=FC/j [/}aECLYiX9U5lw(<#ݯcϻ|8#lI#԰*%$uiv_|]Iu/X8T}ǣ/^XxD+!o 0Y;Y_چۯ <:#3ti{U-(E[od С5 T_Qms}Ƙz{KA+ꔶgmPo󔸂f]c1;䑚FT V1-,5J2 Jh;| Khll:Z9^*.[07Tއ"R0 /"fj\di27WܙB*7ħl^< 򳵖 q}$wh?6e`>Kw8=_biqX.kRoa[iJp5d khOdiZfag5h}GfQXZf?m+HT_FjO7\L*e(,6a&u{rs %c0wFRpbum[1%$ 12j >c@_naEigS XDAog?>0]Ccס{(] |xTqAt; aTS挆 Py:H7ǿ΍MfvSRS3:U`=Ss/ } Zq'?re!Ҵh< !2ȗ cbI7J0*ètky*]:3vM e(qC f 4iy_[cvOh}4/ŨIQuSaACކ hYNhl(֯S[#a+-BIHPJ9dݙ+f[H$n&mƙ#<h[$S7fXpv 0V;aFTceojG L2,q+e;Fi:eRHph<$%aj9'uܛr\p*YA"HC7춷s$]^umSx*i07>WYiYM}:I4^"R,}GLL SypGL1};beLeؘq}BzIKiaVZ݅k- GL2H ѝnQBX@P ^%""-bT[6=U<޸ƿzxpz}p~lœjo3}nnۛ ֆy O=v=cjt.R'LWpP4JTl!4h^Z?FC׹7 `Rv]I'#=]Ʀt=H̞!Yѩ3F7g2eҠV78u|H%%Xٰ*<6d.0E(cF=#4w"ژW_dve iiG26M;#+MembȈepHSgUm6e9/ 1'+F3Msjlp"bvڤTZ9Il PJ.čk*jyC!8ผBw1@#()ÎiB}eL)=r5ЩɲqL1Z`VJ١lcú[kGv]RKʯy*;9 t+,a5&u.1ЅI(Oy3sȠ(pzlD33dr)8_"R4mvٰjِIgQ}$[ErKL&ɮ0v )z 9u{h* y[=QRT0&v&lI~jmW'̕'\jwp~ޣ=IK n(Ȭh5hiG&Sn<$K !BYKNA谋8t{Z#ܤ K]0[y̚Zk xlӴk8qt VMD:]:7frwLb*Ԯ>N`ҙ;9fIQe#OO@j?Î~G}M9+^Nt7ջf @ R[p0Hr̓JrTk}lX' }*c @q8#M cm2;XL5M-ro}$)50^K3N8s/+ yxS~,?[kn$## XǏpq(87\ҴQ|C7ۻ7xwGƣ+{M2!<(M;tmWAj57s-*)6FiںQ&xϘZf.{sݼ뺨ˆnlw{Y7]˱gA dPTOW>whX{?| Y<+ m/:HW1`4< %\!(G)r>X%ﶷXc}/o?)~ۢ|]d6r}jDy˻<$УKy3ūs-{ 8Z2|XG˲BYCgV+wƈ6oO`=o8}lXlatQ1Gw=Au9kAn 3=>LZ]$}7z&O1? {42kSlL? hR3mt,_ʸa͋d䣊>+4AZВRm6K2|ci~`Def>}D CQf.gW:9> WWv9}n@4_TJ8X3K6/ NaG$K<9w>@_|Bt|oȂ%;BZY1, PڅʌamVutCJ ?0hFx^i.=v 몥05CcO^.FW)m3rx*bUhr,UhTŘƅf9sƒSF+ tB:qW_|ܚU^U]W{7%!"_Q H6Zwz1X?hۍ#Ao= N ?!2fG[oQz \\y<68Gʌx*8Gh4`bwolNH GYs|VkM&zo+ƕ/Z]ƭ *EQRkԸ%PxUAH4[Jv1\  ^!KJ>VY23RWxlo4E+9RNAQc߹5"Mً܅aAt!T;Pa{|ǂi)a5\3tE]7otQO,~E@8V{)5}Ч\uBl=^ n,HSjپ@P{[]c?aODX gd0D*j )BAu$Jb"zT9>{ ]>kNwTie;"sZ+.#F%T BրZpD٪\`+^ RFq$][m`X'svbZzE C_ S؅r٣pV}quQ=C H:. |",O~ne=/әM!]M3} f 5O- vi^ Gu?˟1alpl.lMpsgQL"Xe'p~B]/`0xV.}ߜņ-$JJ MPE,l Kkud#je":ԀZ!<$7r(MW)elI pg(ab-f4@kH lMi Y"U|x e|^Ň'AgO`C|M|;y*> ]CA!U|s[PV?#/b"F:zd_"?rz|tpץz+7*d'OmG}| R$ڒB:Y-v涅NVGz{V'^CsL?0ߣ<'_7NA,:bNhQ=Wh%l`>bNJMwuNЏqLSS -u_1lOw* uh0_x!_=!gs[o ޞT0ԧM ?qw:rLh$ qï&|6V|T)̏^b:0/yq)6>b \N[JCbFo$B@3*t:+Tmkb&?DjAenvHNU(Ė}APۢc) ^qA$^KV^[I#4f@k1}9Nl 2y#1 Vo ;ѕfes; q>k ?.y*KVOTO-}rJ.thafXE@$z!Yːi\bCv=1G9@;mcaR8|zJ/O ֹmu7J&~k3%~_z6qKKYwnkz]ښk[ʾ/ ˚Lbg٠ڌя({]^BsteSk #K V ?k- gfЌn%1X+:p7ղvIUA3,$b dٌ UR>hKUh|zfvПOIF2@%Sl@7of3_;+|{ela`WMM!,[t8k<^qegwЪ*mS:C8w:PǑOˤ"8eqn`tr"E R2 ۥ.i" 4@,B ~k>&dߩ5"T8HF=}^M6Z|yoԃe+}R&NHn=ģgD(px x^^vdA A:LBPg YhZUе Elf:03cV2Taj3iӘEgkxn3T<ɶSdKE "t8'M52t_tsf].$f*&[:6 8Ԍ@`mMq\;J<ʄgGF!Å9+I$}k$1Dr)w& mTƱoG*fr-p (W+JfӚJSP}>/|1py;̪:+e`L9+\RBA;3Av&$?gdڙ]"yl+<<\[a;+¦"Kp2Wpg}EVFQ6-/JbNHXJsGYCF΂j! Zy;]\'ʚZgbI]m̤ &oVΝ+,SS)xK4>kg' 8X*p8Jy\δπ̹smIdrUC: i*QZ3xk4XaSJP.k*k.7,5YSRsj #՚'ʩ8U0:cdbasR\xLv)Ӽfc &ll)ll;wß=Ktյ"!ȷ}^_1&?wÑ=Kt 'VHDrLH2JױdŋBċdd*)P^P+[\V-fd[̥Ӭ;>F!g \~IAKqH}\TYJK>ge)=5dϖf2-Vt+ f m(&gPsɠsB1sz-i8sr^ƻג0̋9v"ɑ]n,SM2ȋoL 'O֔3]b9qv&4Kp2o ߧeNV4{n<JRg,*D[p/Jᅁ{n e5?ؼS@lYpu~E2ѷПOX7Z'@cC2*3qag/'qe [,¨Dfr5M 4 'mIUb3FhgU|) M6۞x63>л ]RyiAlݝBEltf6#{Fg (fV=+gd(<^ۻx^+pCJ\/^-&:N,2wv<'{NL ]x& /\ 79J$6 OEEp*qa!@p,gC"(3Ep*F@pU/ٿnlސzҋgWz7B9o:+bMS!zxnmvC.|LO nqpz |#XoofE)ἑ~y1LdC)G`eA ˂# ֎sBJqNC?Exe,yd,&tlwv?TOL } 4yLC ='P+JF1HdMѣYO%)o9Lf)jv9L iw_L}DΎFf6ZΚe^dO d L\!Lv) [;f9Wfdf]T6j1fd>?d_,;3dw,%s_>Uâ2 -tl WY6 s@5ʲ cYT6AVQ3e>?d_e&[ݦ͎ʋ05kO.!1$rFWòx#a%噱l{]߬Mc,r;[fnڱ'$kF7a5S/Tc`MMV#MFۅ䰙F YP6iQli;j3T.$}~>?]&Ц@&!#[څ䵩v.lQ;hSZe0??_H4gfWT~oRJ\P|^QJLQj& htwy=H6Mq!zU#H$pK!x_Z lq'Qc/"-Sm,g#sJlsR ; 8T֪[~, TkO.$;0\}Z= 9q~|1W/D Q%5zp |B+`פlZ{Be-+l3mrlv9LH)w2e˝ui9fN.#[*<%F#h22ݒ=(ufg[}Oo<-RvFG2Bۖs^좜ܞ}h[d!<{6q:mrEn{J|V3g&mE @ 1{?urG'un[+2b^,f綻EZ1 DW>f6ELYrPxG'i@P]WΊds)*倥Bk*30P{S}0pV<mYUىh@kF&f6эdȴ&2/ylTcaD֌.S  Ȋh+:ULYv[hg6#=g/2^PΩ0#il;k0y$<{c>vfڡ ]ҎL{i;^l;#2vH5KqoΫV}Lf̤yrLBf̥rdKtO ;='O+"f$ Ϧ}57gKoL:茘"uq ɀB|&SE͂մəI!}Ģk x3RE5-R /&(Ϣ\L@i'A?3—X8^'6ϠkJ^Xm!2dCTYI ˚t_%&[=BƷ?' r>0f 8]i \M.J(.6(`1zjg€))CSɈpOd橁EaԄgBS/lMgm}Ronp9pl<'_qN]^䧅o lw~Mq}:ubwy͍sQBاʑmPi2s#4C@4y ܡ8p8Mu4&R2kW2p- ʀgQæʆ^*+0CۅS4پ75H3A: e4z MRxֲa#%4颬ّl; R3!.S}f(n 5CU3Z.*>5RgAj6/Z.Z\S5N5-ǘEK->+gpTΈ.,h}hMs L=$^$Ivri.ű+ٰ55P@]@}D5لu"PH`ppԷT^%קFn}$+nr_h&[Bn,w9gK!)$۸NڧȎX3ۥ@J,E,H)!ds}&g_59a\Je_8] `NX g%Y,2>iiG cxpB͆;Od9 %%*9҂Y9ӂ9[2cƼ|y+%R~sFs&p~ ə=/3 \+3 ͛3/2S^!#s0OTaiY[W^=xgsӎCR#ўl~#(ebW(U+\ v p4# s.t Ob9$L|SYNF*?3l'D,BdrڼtD>6!!۷+Ǎn&1OX;m9r2 ox2Ұ}Fp&4O}X!B$qTKÂ>R8Jx܎gXr.Wg`,5 3D?_7,')L<|>_$ E?qxisG )>8;G|8x&1}EF ,BY\Bs:?YgP?ȑI^ZE+ `>1`qbD.`:I9~K r%'־Ѽ7Xʯ\96{{'O_jf wH{c!{/ѴҘΊd+)Y F|Ax]N5wJZ}Z}qx]HR5wJx5ֽUOfLSR]BLl/_=y*|7 4Y/_͗v⏟~;kztn^Fܟk* brnv ӴwsGb2 NmH:׷s9eK乽#AV͗v.gv6>ް+g r}S>lXf\z_*` m*ddЬWZu;Dj({6nma~9 p~%S5>=&Мnb]7 {W%>nyƩc-dF\C{Lllڑ Ψh|yN3h^ jZWZsly[}4cq>ȫIG^^673/{=&Yɖ;jߚc7go?Vߧi>Tle2ϗ(^ ~octr"2[ ~ȩC3IOx[&-L0{ ˩.1o=5ԞZ,jj;$ V(Dims8|zl-A~XS'}1bߚWgL#57©\U9O_9a7o3yw.##Ώ!O/jNۈ&7o޹4o߶g=߹5Gޠ}|y~l6fnۃ7湸>ȭrcn>:C3C{)u^Pl«?wRg4oa4lj4ۙj4`7/=97[$^pKQ\ԿXuLtrvno $|'{g;R_M; h|B`k|k|n547>DW_F>ՏQOsRmqZj7T,";@@4$DýW{`)&H1Cƣb*a [|={HIL[$4ȯ1z/j-h–8v~ hVz.S&诨-~$5/Nm1“ѥw_Uy31oB:Fѓsv8#KnYll<" N6Qg{CFe2Wt_D: J>!~EҌ̷v9a8y{F7u\nQ榷5uƛݽi+Uv/F&s6;8}8+o~{{]{4^]}mGhm6K 9^?D;aفΣk/q~\㿯GOE|KZ;n%kq)!WR:vZu4LJv42lndJjZɩ /'0yK:-2$GlzsI'Ѓf׉ݓ_qۺn"(wOvǣ?괚#i~kx7 2O;WݸAMkoɵ&Q}r%=GQz r!݋,,ъu=}뒨#Q nC,ʪE}DI镼_N+_@kTymㄊ,u6^)<[ESlVW}Ez䣽i^_@*խ],xP!{ujiFg6A|цh_yHOb Qe9B[AtSʂ&62.u!;ؘ1gR9Uxh DߦJTtEGDrijݻhȎ颣.9:jOtUItl.>%Sl%)s<i~ǶX~XcrTiBM6ZeW^=@۬6u_&hUd֧2ϣ"R֚,,%}صYhC]Nt&Z ?g,VԔL "] >V[AKǽuA liμ[pLz;~mcl:F}[ϽϾf-Zk5Gy)t码ׂ*HҔ@dS;-{u*2=.fvs==fCK5lzq+/9hPazGkE#avیs]fM.bQWF).\Usc4#]6Y #K_ql ig{EU$ziHshHn I7OC{m*8fLĤeU2!XXTmml޻i2Myvg&v-ßCAEE "lV_uy^!So-tEf\| &Es/DzM~|Nvbk#d^QkTj8Kp2oziڼO# :bbi^#qz'L7xLOvd19LHwֲJ2+螙짿#V~#㞸jw1Vz1VST%"^|}^lhzbK YƏC-&~L@fo[O.jp{>4r>WQX-SXN?2L3v_g~v@p23eg6V,ȳ$U!9_vtmfve;QfycAYmf1"<̩Q6{d+5=-˞ gsoU7xp>>DoSnV2mPRO:K^9llLw$d^*s[a6Uq>ՔY+Ws(P>4oy,Ou"s z=T{]&y=6;P߽;Lc&}(r-R}\sZ<9^ǂlmfA LX]BFhݳ먰Mpȶ`wǞ[5Mjk1HSr9dE%|] =]0?[yo -wz5XUfvƮ<Hؘ] %#ɫ Lژ_bIp7tgyw9-Lz؉Ls3?ԗdKOdڌ4ՙڣӮ7yVHS? ~6[]->GW6@UPSNe|9ijxC<3ElZS`vwfyyQV<{gA +TӳMi/XN<=E/(3ٛ[MO{BM,j#q6®†ؑ~#G&Xq+1Iܖq艼5iTiY-kh_{ln&\A+@,  ͋(T1΋G0/nE7jjbQϾYVԳ_q"X{Ti΋$;(1\ovϋ$5vIù̅g>:чWh<7ou5B˄3M4e<&3t\~&_,7 7mwQg(چ"Z66 l{M8Hx줶^)osVeEwt;8*6JiZ7o;[7B*Br%W%RʕSJ+.@c:hDjeqP4<7XKIjM$G u,F-|[v1s-{qcfzdk-k ЄMr[vV1*4'(7g|A4X{Z?D[MrxC6~07[OЛ6Z&=)aS om=Aor۵78䞣{Hm7q͡orK䞣R'E"0<+vRrrԘ53kM<ۓ|k啬,W b>EahΔ{Tܤ:Puٓ5"_|{,?%}M*~'Sf/{N|ͳbp?/!0EAl yl뵮lGeQ$1]~(-%lu%8  v|Yd:~l>؀IW;yx2[ZG=U%>E^ ?8ٮJYT)pX/R8<4"!$dµ㘄r)cя>}) D?YdՏm23N.w74G4%M*2|(o_hY`8bF'AJٶ#L1Fr9_}瘏rt3yf39{j`':V^tm3.ږx5~ xES g&/8&G<~QEшcZymh?p\:U_V+Suke7}̳LSQĻ|SH٭`I=e2~2RxVѕR}*I6qVEfݚY7I9*f0Ϯ2qOgG)KU6t*vyfM#}͎ǛuKL9N5֨ #(}q ΛuKGǵsu-[{4QvNs:h[/ۊ.SyVԺ;]2]hޑ5duh7>R`Q+C1˘: V9;lJLa栘=͕cpE.˞U 8;μeMq ̗=4`yuLK yAp_z;bsGhjy˳=Gz͙pycs-Z^'F@4`(2 ce H/~ՃN(*N8oFxUY-_N_,w|'xWa3"ش}\+'242\2q`e6 U{(*N2]x._\l,^k{.ラ~Fz,кu3qfE'3Z:9g6ta,rP]L']6_ pi擉uJ"MJlKZ 7I`YjgHN9{hWrlpD띳runLw_U)QvKA,JWՁ栠fXrl@Jłƃ}l^}nӼ|l8=*pV8|brO\W9"b^rŗ {Upv73sQuaE5|␻p/jeJ[W+NM3r޴xǧ J8pV欺^q&lz?9}ΜV|rNBYeJ[zwUC4͈nۇ2N- {{/R1YżWP{,G/ׯi|rp8<;&e)=Gƍw~8ovBj&q4~' Q4y#5b}Ӑd:>9i6Je=—`* e . xڊ+5*ߴ rXT`%y vsD6"fP$M{|ֱ^4ךFF['V(FULUj QAaݷj+Gځ 56Nh]7P{uh ԠuvK"=ρT {qR+һ,{]n6pXθ`9ْ9UHVIsju^n2GLv{*loȱ$ ig&㥾xn`D=ִh_X?y8~T@GҶчlF7h^3kEo&(`&*KxpECE`X6* o UjUj"ժTߤZ$,RyKM uI{KuT7`+F9GmW{pLB_loH-x҂7[Ʒ RݔiꦷT7IH$oRnIRݲHu[[ߤJm궷TIuw{LkꮷTwI.PH"WR}M{evPN{os!8v9N0'ǙjW{5T+UӬ= j"kKZRJ_Ʈ8ڴ4ޛ3QiM#FpFR 4RSшiid3 ⡏f3Lk"(vW`k 6QT |0k3L}8XQFAcVgo̡mgO$mFAsP.EMYS)d*s` y%-wNrN o @R4;vN iW__ў,' 뗰А֝':D!e|__kSQX3]OǵeLTx\3g!JEk_tokWүTu='yS}cs^}&/'s'z澲x:ת~1~ E<|Ee3},fwA^"ߔEZ^1yV+/d8ft , >fs\jH[3]LIsŭ/?bKۚ.pkt/2/A-Bˣ_RAArA@s/c((o8*S<2{Z^'{N Np0OQJA'h/A'N!VuEYNc^:hcUP#ռqO{!WkuW Ut: PGPC@feN9BݟY륃9BBM2BSI8{uTʭjj:j.'E3 nRWS.ϗqT8խ\<IIOy<ǩ'ݓ㬞zA&yyo.(t6׋7qxwuiFO`h6!P3mQ;n+_lf|fY9m[a-3dig]۬e^;||ʺ>];zn҇(4gF=z6vu۬BKS=<1-eή4UOwG*j?.^jj`ξ4UWwO/5r% d+Iȸnzij-kU\'Yj16y_oW,fsZ/3}l]ly\sYG0=>?yNWա8H&thUNP5C%un*0Ǖ5p囗 -|u S7|ӌVL/z/QL]祖MT-v ;XqL1З"VVȩ:MasͬΫ|4sl& TEP=hVS>ږ܃ԝa)Tb(zquz&a.Ov@u>˟!I#=3;ެUzRA|o*ge\9RAnÃ緫#X`rV qw@q/7UaaNW*r L*6Ix|b+&) U̷W|sz3Y@hsh<|Q̂GЇo@11>sziR!CqQ(DK1lh@҆%ghJqc&9M]41@."eeY/5XPX 5X[T W {+ϸPʏt'b8~fuf7>yw;^aqu̻z_ܲ9K斉Jўr:ydsˮqo_[&:џ_% }qo_[&:ڟ_(G?dy%xCb](xfIL5]*ޟw%C1Rt:z\sӦqsV>侐yjkcP#\<㾐9ksu9ʯh~n6+cEv^_i1囃Y/#/#gsCW(\/ScLC\=qPgLw: JTX%3v3JGf> ^bJ2^A}6k' ;ɔyt3 Fne u5iKXR\؀ YZOG˼7 p"[kv~5O~)dvr}k&35;ߚhetw\Y`3%izm*u\c3&:/Hc׺V0./yƺM.bVͣ[뿨a{60!MT㛽d;4}TGYk۪+5E>5]=j7Nsҝ=">鋨ۗ^όfGs&>\$Ž%t}iF>ܣ):ޛg*g5tՃt/}z)OMץG}3VYg=SĵK󿾙j++wrO:KDYnJXV_LUC7SMեG}3:YC{V%ƽu/mZuv. yv:z|֜/'ُ:#_n7rNlͳ٫h Zۏܠł[_9fWv]Y;tB]ͻS㛝)nT3)y][ʵ8eF=״{n*DFSCSGEfOs]}ESl;To7{/y{Vm!y4Î^ PT3*`0{q:oG灚P ­{|[D%YkFTT»ëqU<PUd Zj52f@uG333Sk,Rw]gܜETtV/buLl+ E 3V#A6 mi]J+DNPCnaFڵ S(Ћ}&^l]ˌ%S[F9pV7 ig_lcӊE?6{Kcydͮ^#b=5ٯf 5BGy}ۻW^fh/Wf♁z´' mYxE?]ՍJ`*7l@(d&,rK! W8+Mx<9ӎhU󑗮^:Ols+TBW_*5{/Ρ ,wD8]΋p%]5tr餢$ NrܯNou䥓*OtdAt^:!C':u6Vjy9g`WӄM!5I4]z"Mķ+܉{C4Bky&`l]!.s7DJRC~{{KwviJGOq3:SƦ~ݿZםCB}jr>HXqw4c#%D]לHu~VuhUY|chZ;:+A`hJ~ږ<y~*}*gEHuJ}<)=ys=mvufy& e d9Ȑ.K4&3S OًsGZsk2.Z.?>R+o`0op$?u%wmnSTeפIfN-=|ɶCfbQkhb\U+oYtKZWZWg@x_eHֳ֑Eֻlx% a >Tlٴ~Y+S5iHM{]K sVfUhT sVEq_9|;Hm5»/˖t?Ԑ!a,6>jE^4<>SNQNNdq4ȴʹx<^ʩYф<:YߡђFti8-50▪:X9$;*72mle3t@{I1^&y IᖹTH 6*9Qi~ݰCГ&׎AgrڇIܯY-*n2Szfɞ!qDjGccnvh(7jf\7ХX4zѶWr|=/3q4E1GUM[x19ӣc=BIaÆ.̚!LN;lM*u+CbI5LGLO/IC*BC58$&@L%̍sz4/(HIfGDN* "U xaُ(hv&\jU@;7L;&crG ԍ?Fh-B3ŭ+lr5 R(z;R$."VRfЏ>( Rq0iaj2$h9$`T;TV [ 3JKTo۱Rd5eǷ|KZ;n%kq)!WR:v>6}hAS(|4\ollGeVX߬nBzeZ<|d4pID(ѽ~~4lH7 ڻ2vU@|)uwdp0Mv4X.Bh4@pH&O=9K%b?J 2"u=D[ ]P*zI53ʮjbX%tZqP=ҼEM_~J9Qd۫je]f܍bw٫m^D] :uJ2 ưcC&d`Ȑ"cQ+|_zFT*DTMiSj&!w-âhQhQwdHuiP\]@5\b :B# ^)KZZ"Q%Yf]UMBl6K".@ ;IxVBvjvA:?~*w̿KH=$ ;1JksOKaN>^! Kc@ϖDPے2M6Ȅ6; 9FE f*uRb@)TU DfvjêٺSop5+ HcV-}OJ,qQ,1b: #nOt&18Pq.UU!jG(Z\iRLXc y]KL!z56eW+X@G+pgIXd*dNAVS] Z2bI `cQ+v3"K 2Py9tlwh^5'Y ~-FTFKоC'Bi4J&'j8sD[PQqrzp|sxA> p\d]vc23@[UL6P lW}kҰ1)lצ_ӱN!!IdRa"VaW*Bm,UHa- v@Vq}CaA,.ԩNtbKjmlTރHs6Zq`ɐKց^,@bs" [U\Z$r^b*i lJJnB{;_-l65n׃gQs8 ˯{7, A\FNOk/S($X!'4|[T[o{m,Xvi,Np)x!aQ6BU6ۨ5A!ׅKMQN ttB/r*R%@-?4J|KKHǯ2rL5K#2tm'20UUێS"ƃ:$%Í(tl+ xUX;M/Nk]ׄ06[K|a2202Q*cAT`ÿ/"_0=CiagWHGdAj!٢Eioi[ttp˙tΣXtaY|sQ٦8Ұ`!ՠ%YlQ(h#b|_^nF5FyK(Q H NٰrȬ-QjOvZ2 aJU8Z}¡-mZ`[ RH:*t*.K*ZUC c0]z+Ԫzb 6Y#E\2۳y2'HUjثFitBn*ytwlAXzF$HLqn;uAfT&ifUA'jw0iurma?ڨ;YhFF.P7(;V>ED{hoOGͩ| bTn2FF+/6?ó7FٓꓵvDW6ieP*o;2tb'/`_d;YcIZygOpeG|\vK׳Q'I\?Yh~hOƥ4'k D{v89 }.?=$WwzQ ~rd]';0Cl?'k:dm?6haq 7&iW;ړ `&Q!I< P˻BʜVH,ڿL:w&Z\{dDﭶ;ÕӓAweA2')DAR:I?]/mhf=xR7Ugz뮨JĖ|;>_ۯ'yE!m!; I8AHdAN&xRw5j $+&?H'6hWQ?am>T6`@*-x*ZQHRiFLVJ1"_x䒶B ƕH h mt7Fb zRS4H1&&h'ÉfV-/˰K!󡃐H xRs)<cG)IdLMP?qNW/~z,Ҁkj7ra  &~x(n7V8RiNJ\bEVLAu$+ϓjnW-KbRBcfk&5WWמ*Yωv2e%*d Z{]BBqY>I@~~gc} ӝe>]B''d\VbOeZQ˜ylOLoeTDK$dAZgJH+`|_@dSZ9Xs3Y#ahʒQ `*9pV$ \͒R\ݥd!DME Y ]\_űqqq \rj`|f;r(kM(Cgɬag<9$P)([;a,;P>;+0aWT6aC5qh_Ar`ә\n>ƃBrb!0rYΓ 41]|.4fHemS IFH14|Ӄs U&lR+rnbiZѿƝ;EOtҨ\. %WQw[E $-.tsԔk6x`5fWqpu>wU<ȰiROs˛ l lw6Gfe=D[˧ƿ^;j_km_򞤱xrNʳ|8#lO?;|)Q}u= CTkتpH):LFDN/V+3zDѓWY 5YsFt3I%hʬg@n3MA 33xh-tl\M6(#*Ϫf7 ^ik@ˢtJĞ z% Khlzd64o9TVȵ'ri9~߈}7R[+a_KmI0\|zC|Y_jKtgcE'X7NNfLK&L% )? 0Ӭ nmuCU& FX"1(1MUpZiѨUb^F 6Rԩ<<;&DZHTlx.|n%lZvVgŧo%~ctMlw\;#gGخjLg*鐌 BB[S5@bG4|itW5xIL]KgP?:jO;/EiH?WN5,G~ d|$-g1k#G9ӟ9sb!QfJ$m[Qr$ȳ 1WHiV :KFʦA˓.8:р64 \%JG/#UcKQϧ2RDâP|m]96&آ 0jI#f.9ݘںfL-L)M9;ipFV ڐ AiRd>306N >j$D:}I #\/Ij'Kq2B25eckͮAL4Mv\q NK٧KN1o}2$H;0=y g]Sw L9/§(Base_Q]6x D1cŐ u8.K?$ ؾ,"oPhc I.i#$~Os ,s[؋FD`g^3DTWhy)[z˷Q9'Ȕe ޝhjɄ -2&?6^/_Z?8YR=jR5ZknOM!`pL7.o",|j9Y}Yt6LBOT*Uo: ?F, zv@tЄaR.ǧgz~Id&xg]hIԑٿBd.wSs]MR%,XKW2[(cxatq2)Z?^`g5h8:78:U*]E1YEf|[)M:X,v`ڶy+Oa|Ӓ: F`~Y5+M<<$*o,U۹F,IýB՝-8qB.z??>G vOz<ʤ$+5g\ZɥU<#Z:"LsOnv~Tu3K_m;j-xarYo*>OyȎ9]ғP%@j+dI!#@%UYݞ:ĖVJYv6( CEQl6) MmooQ>;(JZ§uYpg4-:Re?J$mv)f2/+uL&윔Qt a <sc%}YOZZ*S\")>uAJH~|IfOr}$7fN2{Tf/K7k+^J{Cj`2m?P|?D(,m>C|"a@t{)K+eenI5N5ĢϿ @YwF-q;5 ˺U3j9fQ΢$AMiX(]p}m؝#崈@e`ZYȷ¤|sԖ;;w^<{I<ʮ^B]\|ʕyQd`4%嚌/VRYB?r79q`6o~S ,Ml,IVzHw~>YMv2ڪ*uJgѰg%LmG1n7abzPBtbx"H]v]ԃz£( Nx(BBr.p[Rc$iHqy0Z/FAx&'IbQ9%u8Av>=!=\9NdY hTb0F;Zq! X6dEXC7-!4j*P67@L'jq,(GqGXiSv%K嗒_00ѺP3FR/ܴHx'TkXWrYWR)eh̋?U=ܞ:²˲6YSbڮ^uִpo(Z ݵeZaGK7_N[mbl,a3Xu;X ,6X)Gx@`6*-SfyGH0I+v6=T WȤK7Y:;&&\SrήhP^SvczzHgi1[)=AչL%^!VX(q8eL183D|kQͭoa4U'˪^7&W<?\r&^Ufźj1D|hQ> GUѫd:[6X1V_{pv$TƤ*eYda6<3Jc:`Jy77nήjWf2<̺dioA${,W8b6Y cs^LhSRStsxޯsSEكskϜ*Ф7{R*J 4l1]w PG !+9;+Ω,~' Y@+?zxK2Vo2j$-JR%}#v&)ꯔ>ylֽjn`=^5XϩF l5ȭW 6rjp1ĨMٻ`wÍS9֪5M끦 <~.<Zo!b)b07B:íHٹc* c sqģkxfZ_Zq\.rdnaU(wtIe;Lyń-z\,sJb:(B薀s,@.KE[,C(M̖!sBS0>g8˱ ZݔSL^sD6Q99BN'aBr5zj[*iqI+: atFWwKj%>)g(I"Zbr/].'o@2)Ŀ_ z+`-8 ֵ,pE]Gs:i-7# ;'2?^baTFrdTrymAFec2Inkp'KiNN\L˘ѱ] ;܃Nv2WÇ L2sS0"Ʊ#xlphP~We!Xn"A^g+&1{L3~}.:\tiOYs/zM!c  né܄-l 8\(cp!{8 e,dkF o_*s'F>f-$%y}") \-O#B^@߶R+(U!z MgMuI a`+w15F r6ߊT\;K ɔlc-&|Z[5futD uE7,n҈䧢em~$%ɛ-IO&dds-/HbWx6%pG 8 WNl dBkX"k0¼t~HomЄ^sBY884o`%"9JOVLY⋨],GH#j ѱmXJ#$;!hsz?R Q[faNas{ <%otMl%P . 9Up=:kEW,L"TmƛHlfybC*)ixU k@g  []7!Tx4īh}Q ~؃fB'%B?f4A9&$>:6DN.(9J>([= +`VR`/Z49 . Jc\fdV )ρ`g/zOb֎𨝙 I!hy7wV_^/sHIiXO8 x$Nig>JÙR6BOÖ >b`KYT ףv 2f"✳P ȵXRb X ڲBLXO)NH1=vf_;ʯk!-A"/=e5bV[ +\L{(|Rmzo+s ;^rƁrL\az ,~pu x+B*DM\yƗH d DV!c By"XN!߷`+(c0E$ 3D;gS8wy07v;^)$9]X:󨤼4tۭnLFg;HM` .n0C@(ۦDdb :QwEBb<,cTlNAiz$хہ0aǠ^t p\ 9 'Clz5kEߢgK5wUtB:D 9_lD1L',J#ͱ\޲qoZ7@iXc ~{#=50>bGD(G㩩"m#wskހarZV7FZ8EQ)}朓2W [ep]by;r*t" B;ϓm][Dbw7ml8֐IMchڛ"EVYOэ`̦R-'_lK:u)+@_f(lO[3tS]vHmL=d' ꜳe²]g^qZ::> ~o65Ki׏{:h:rw.! G3+ c }g?Wl36 N69FKS-sH+eQޣE@K>;dYe]e'UVu cIg.uwcf\]u 'Dk6z ly:wR@mZSQH` Iy'k[}Ty\ E1YQ$ux4˜b)R5c{Ien:͓hU`^Du nz%$zH]d>y:aKF)l6Q, P7Ewϑ67O{08s{b0Ll2DB=ˉ>in^E Nx!kAS`8"k*q}. ]'L2E8m\AP}D\KUq4췽i,ą!+<׻Kr=HꓣI`FKӹp_*V;as'I#{*BV G Yte)lI:Vߓ^+R.?N7dbC'@A:Kec[wHqN~LGG$\&qu\sc nv0ؘǽ/H}P! 镢+mP,Md`) ZQ ,`Ji@!4⒅3R1R? ~4Іx2f(4}N}$``ݭtc_+<(@5Ҡ#L"xƌlp05ݴj& TUzڎ]=b|J v]=o*Nt#yݗO O~=lP^oJRF}r2LC>D8[Xi?O UXiIg'jC8<8j\R(a>8~vtǮ ā8KYiT@@.AvτWm<_w? \!Б)ΔkdgoXF2hM7 Ȅ4jrLCCTha ~4L0I/LQOq2hK##VR\=kUo1x*J#(-zό >&'(^; m$0'6<2bAHfv0UAȊG) ̏ Pz$ z,NclŌƪP3ы3%΋$Qa35O@Ȝ'" t:#' (F'=1eř%֠lqőI/.#|ÚkB& -Ta% h"BXJ%ځHza2A_%EO\J@&ZsSP, s)Jf?"E-wj414S ?@‹vi{ëH??s.= B<$٠ cm],I~3Υ t6Nk4Z==z.*[x> RwR?  Z8#!=-ӻ?U7NPdyJY=Q0\ W$޺"_gi<^7 ڐ.A)iX8(^)lACpjE>CDAK4^e5f}%07WP.7yln-us l:X"  :!*2MY \F -`d%@5V $pAob,4bsW{`qZؤ_{oݒ-R*{$_aϢx|"K?נXqJ%i/L!f7G . a&Q?I\LKOZ6wM %Hۉ7vZ'Cu.7:3nր\јa7sȸѳ4NN&g;aힼIcLF0$ dp_F;ecβԆybpӵcIwVW*_T]bi!W7kbl1 '\{M)}@dm+ /}J:*PlvrA$g=a0206{e$%;mj7Y3^=& uIrT 00pws_;IjCNK_tl΍4` tIe.e!meJ6}VPԑlw^95Ji)hx1tG~)}bNMQK r2YSJo9#pmcee_ؑj[(첏{=p+"jiTjdz [cN^ޑYJ.lGTjG֝%R=#[s5P(n"pB y/tOw_zo4Idp2"`2.?*^LWˤwQ⦘,&ޅnՀe:+&: ]8S 90xS,z#*S2=bL^P8orݹ[F]/hȷ8l QӞ1 NQ[+AQXr=ye)szzАxGd kMrk4[Q%Er*L(n't.WXZUjaް;A49lEgN(eMG˳!Xצtc{2v]BЋ7}&YhGMadZgfΤGL- EOUˣjW r8>g>UNũ(,H &*5|j;FzVwAw:&n7[$<:ɟ'ǀ 0& OaZK ܟsKCi!2'a8}u|r89(bË,l} m/'5~;kpmWKGC. xb[i;\0^'oNv/GU.Hҳ΢NT6l+Wflw>kxx_(;*R}wBmPϰM/bR2j@:i쇯Ov@x ʨSPX)#BC\p''D^+Mmjdn3tAq(:eX[.O2r#`q` xMdX IKƺ@ M4TpwF<` N7ԌQI$MA~=o>8jg0k[i~qg[v~ZxpGt43}T۝]y4K+O\$:{4D\)~]C:b'wd^#=:gK5:+̰ٚ{owqqtF 1}CLMl{ѳgrXL2V#ý㣣ޙfp vL~O'DѰN-N !ӨaxE+DbS"> Fˋ`< hFHvvJD߮\!:urpx~:+H eU_wJ%)D1UbEMTKB 2,)#! \aCw^;`=6ZII2d̮>x#vU<(ȧ~2f(oheؒW'!%:1hIB{ أmQô"elRX]nOR w(wQcdLq$Iƫt,:C+qf%+&ph)eR|)4uA5~2(;K2!6Vrt+M|ozeLM ,lz'Ip }ȭjuE]Z˨Լ$R9|櫑}"n ]JYuzL,cXG\~!+zpսcOS4o{;<0}lo]^eGO?~W{XIo&k8%` Lb}BND_quiMTJ!]5gV&NnN;QBB JaU[OmSHs%Lk^L"[칟^<ЧYi*i9n89: z}ƞzŕ~țՆaK\4Muzg| gpLMӆ>rz+d?dž>nēqZ>H_}2o_z" \ gNG7{!hK{|Ϧ|q%xP}դ/4ey1EQ, 6Xqһd#\FC_Ӱ2[{eէjt3 Vf+'$>cbH#n0o1 M{p{Q̔vn2KnimC9f!v;4wab'=b7B!g9m ~Nb&9mc#يJ|iYV#!Gzkjl[6 ~$+ UuߢF@^Dlz0ޏnG!K2+$;Fd4F̈́2̢EACG{Z ?1&4F}ZvVüW1kJ-n$@?tYz"=C>9hc`70i֖ MfqcOܽܛX1a@7Q 3poW hM sqoU=Ta~;ͻq6?Fŵmҧ猩)ϽѬ:-3O+ZyhjΕ +SrVjgBVl}c+e6*z;a#ڣnrSV C.tR'P )uғӽH^y]jv}V;w)lQi BmGcHAw((8FQk<ȒW6 3;+'fmugs֎|趓9O,+ `,߫g lhY[uL fqS-L#& jpĀzt0mCsj U5d> Ip9{J/RqB 2CAJ,Xot ?/(5Úч Y8>-cIkΞ3C ;-p fQ$'QBך3W FwA0`@޹engɈ;c5{9-a'!&U$lX>-_wS}>9[IAy2)W5 rzTrt[@'4K3;?N3f9E{Q!.9k5}2Q~CbbbL?)SDžFb˰blZn],V-a)%n"rڶzXlT%WK(V? Į'ITǁ|b&^S{ί0FI'ѝ0Ð_'!oYF#!pq~1֦mZeMe=2pqBDxXzNƔMp˝!oH*Υe}lQuM=Jm42N!xsEAZ\A&<AsnBɔt#@J%Z/;(T\mAxq)LzҔ*^Fgܦ$b+.R,"4 _ +N.Ԗju$$K~nB]%/L}@] 8rVVK6i- V}9 ,e/L"Ҹ;Rli(-! ȄMI (a6MW'd\ $e\+6!@jBAk2^/x}BAb xIuQyY:&e 3;Hb ;сNw' ]B *Dv:+ _w¯J2<'6 $?՝^jXlNDV,'06\K.=h2Y(T)ӌrPҩ0)QZRYN3huFJ S(g ]t::d|d^R!(a4GnK @aEA[A>ʆ%$-ZOc+Ed:l(jRd@fTX!_19E  j98*=;Q/cr JtlW6&0>VrI͎[ F9X387~;-%(HA船3u=T L\9/59hBISiTDsO4ʄnJi8TvP Rwx@amB&)nY$4mgu?\Xfgu%JnhBח=yCL?x &\界씓'r ⶋxDɕ#lywZd#:2n|UJƗwLJ(@jͻRa[y"Ch&w;N) &GÓE@V]9=ONHtAR#%e˝Kefs>3D7+++K}ExrnV6Uf.lD$@oRji-cp;"ȯbes!`.5<>D1I0'2"⌓x 0ƉW I%Pbg&`1 砤Sa#FPZWu8Z; XKO/^QiyЊ^?xZ=?' 8N4!iOüs}7gL:vvQ)Gj<i_V-:mAN*\Ò c_W;Z>N.iQ-y΁N ?!:DuW! }F`"$w=!AfNVīQ]x>ME#,>TϜB2i;+ g`#!T7d|b7" [H/z{%`^cZahi7nNMW=kigL>#Qh]M[!s6< z ]q1)LHyE*Böcc%D7VuO`0@w 0)~39Vm!#{'$3K-$SoFd#ɸ aNI9 9M^+T|nW&Ӯծ qɶe e@&mL.m򇷊411%/߆6^E{[ֽ /ϊAFq'gO_Xx{Nw޽7lXRJ#-ަ@Ʒw%2'{ .HOK7d}%eR*Q:ϿO cPJXN%W%Rˍ\9JVruhMX{qKb?I2vtM\f;`&p03ydXz94ꦪj ;~$"s<9ca!T 48|.K *~Mv9WNe-:΋̓Z+ϧЭr9yTN;_ĹVGJ-r!j;!)k}𲴰X,WIM:_{#\jbw+irʣBB_TV>{ T óݓ7wϚȰSl3 K4M,kVhQLg1{0hX0`=(6?ŗ?~ICe(Ht%s[0_)eP:˧" jٷ)TJV>88@D\s8 G0@|DNeH& ҆ ۝Neγg+nwx4yZx~|YtO1DG(uDJ|DU|C.ȅ@(]de}.sESKT|Ihm&| &?\Ϝ(ؿVxJ8po״+?Nƚ̀rqQc,dٗocz254fό DF*2g) zPq"J;EahlelQTtV)a 5saOy܋#P'2ڦ~D1$ j|M&on&1`r>ItcTvz{P df\mna!Jۘ"fE— d`ۤe(c0H5e驊߻ l{dQ N$dC%wxp԰f24D /AI*He&QwqZ4((yǤ$rX<+aBa Zi^Y,ŝJqY\>=#M^ZSB$ϐ;f lҾٞF7` l 3{lםupq{@\qeQʼn:C8 7d֓&[R4дLB؊@LdNVi8 ^e@e%3Rd ŀ6DS%5dGI9F+If$dQ]1rbC 'HJ2qI#Yf ejгȴS * o5½_ɿgIq['D~6T6a3]6 x/FW0'4G4r0J"bvw9ˎ,G qQRfe|)SueO),9żPU(mmYh$G'Ĝo0w%Gs4bHen))p]Ct0!WlK3 ې2m Qc1nlt.alYgJL,IkIƫ9-mKYgR(AfJdt'0BfFUd[0"]MEf@-hH8:렁!7])BDO=Nm stuCEz!hX.Rh">)!''=7Ď{gF&8Z 堈Bl|Z;I㰱{PlFӕ .>ۗu~@$ׂ/b|m^X_ b|}^8=WJd@農ZݔImYVPznY輷6TǼ嫅Y+JeF&RVJPӐY腯*6ϊ< y[O-GϗgR! 6*|:',*3.sHCn.M\e3< FSB/O,WXC"jCbEE4/60J^4πF\/=~;[)9K-A9$Cta4.Ef,sgYA_jHTq) GIt54[Rd|qQjB1[pH!:wB61(*>8K7@ߌ+ߚHxHU-Af8`R8r8Ek"_)onڨ7急H 3ORggK!Tn0H@.]tYlF(`O<ZX%}7b (6 ^#epս9mfe,TɚX.~ 1ly\vZpeFy;G89 ކqrL]3B5N,Qْ:ƒ3^RV"MANMJtʟ+/)1 yr("fUŀ&9ˋ+)x[ YV֧k{48`U^,Nw )!0>3>g Lh.ȍ&{o#K|ޝkJ*B7H9 Qac1Ah';Ml;BKOEsI^<}b=~;GT}Ea4EPodT.z,Vj]D]I!h9$a/iw9\ϟ#$K??e7;Xa! /c#H#=)չB~Ɣ':n!1OSv͋B@ЎUJVÑRpEtf2󴲝<{lJ mG)R2}&턙gmpҡQDi0;R;C.0; R4o4a5ꀖه$Џ}=&O ΃ZĉuN'E?ŸK9YꀞGׯ)R+RN'GFO7 }tг_28W^ e ak>]Zps9l"dK ϟ<`#N _Ÿ/f2(umŒʝ8w1=dDƝ!mԔM_KOAN^]9|_;/9_5H=_{: yĢJU|lA;ju>wJ.jihN4Vs8uf( n.ZFq14FtqMM O?iC/ybh0Dxt㶵Ο4? `mn׶lq$Οe@;YIILY  Q4HiWg$:mR.A!gƯi`_G#n]DW "s^ *eLILQgbJdZØގLɐ1ӲƔ5~x YQg5q8N܍mY4\^D^c0#,dxyesEF7)sMR*"QH&8KE iAWwDPzDЖ`# W%UI+";G"Xv#:ªEfම&i>p[4Sǃ 817 ,Մ q0P?;A'pNx_N.׎HMd4RjnU`gDwՖϥcW[Œ~GЩcɡh-a+9CT5Mu@ĴH40LJ_J7Je2 Hk}ˍ 4`#14zV|'bC:{{r#ݞ!qyMo.i&u phk6 E6? 6Q<(1$Vʏ/gn/=;\ŲV*$~Vi .\jq(tmĠLf Xbl&]߫Wi!&|ny)t,=^V"E BĊ #cR9n崬%hb:|\JZhtgOA] 33;`YP(5Yҡy1.e/_˟-]| W>? ~ƉrV[A3ʙea(@懗 !3qB/$3ŰQ˹0jh4Dk,Vk\Yh.;vT rn|?͞e#hSA`h>Yt`X:JmPz' +{$4hu8$UҮ '^|tH--,}ՔT dAr֭I^ƽOS|iO_Ls%xd4aۙr.5rRevCxΟYy\q6NKo~{'quJ5wj J9q z Vl:yo-7W'XaJ]_ N휟Xŕ5mj&Q)NCg0g"9Y9N{%^4/׈Jl8,ɏ#}]^"~M%n-NiV`lgsu^ӷ6@ ^ d=hl1 T#CeM=gMC7\R(k~ZKjNV# 9Zr `L$1‘mW1<Űk@1<;2K v/.,<@BBzKx|LMGh÷ȗBl?[ |z}7%4*"jWLN"棐Mp/N8夬wRImZGK^JGߴZ ŠK-V%-o/Oym叵K^w{:Ko/Uw{l/y-l/,wPXm2ռVs(+VXm eL1wl1wdO%V uW!,*³T!:/ƻM58vhiRF!)) +|Rl &6يoGUóP:V'uS*1d2n$/14bhCeLu}䙼%ţh|&5|bj'ߩKBB:`{Simg"P1NlAi]'^k{\E͸U5Wkx]E^zg ^/:^UpR.R]E" sY粡 O_Εl9{Cq ei=nȕ C`! 3 2i6mҁe?Nȝ,/_S;`w`&̞[8(}ﺓr屿u'``ˢ_swDrV0{Bf57pɏp K%f¦Ž綐' I XӲ}' @oPe=|nw-ʕ@ƙ@2@ 9lv0Ofyʕ\~͊y &B|&cAh~,e85B-JC+BC54iHFMOV4V#1ƊzaLo0C(okeT`T9ȅ( iˋܭzP 84 Sv,Kj d#kr@VQ/哠`6r !9 j\f; A/IP0K1. f>XmFaí6\wt~%?dv'?dgD8?,ϔqH'Y~;駠5I0n 6t2D1/R֮R,'*ǀH K TcRfFkLxXDvNc`Ys5m n>`tl}"FV߼XY6kdZ..JKJ;1peTKʇ֜֜)<귮fA}m~m"#~:0M-U굪s%4ZAk?;RFdoJrlPaItJzS5etc- -F g]"ՠp5ZZRFώ8"O ?++zZu(:-z­&qEܘ@~VVpP ZHM*?;⬋άeO#| ;dj9@G&x8^udLeqpsZkk%IV82)$Jt.-v ǒqVQ+RcʂYJuc@βzdK7+H4@;9BO2F[U!=_$ }hy`dEfT$XkaW%lݎ`Ìͫ#,C=ͱذ۶=[u@Q ڊ򑔇N4q]m`YR+nvQU aӳ02|d,Z/R"8CBlDb-~/l0 À7-ZYV3O9Xowq!Go\Zc{4V@aύIMLM0Ha;{PȈ>'P/׻NT|A2ntiVL[ /[a6? UH  : ķ² 41#"P4~d],D!up4Hu7uw=+  B+ /paE^ д6xP@Rof((a:|uQ!Rסq dadI(O-8J Zɍ~ A DNu`_-+Ɍ~,4hf=hX2B2M0Iz*ѶSN: 1þnT.i\.q$Y$3ii&eLƆ~Zj5M@$RC*3v杛,Oɩ!1E+ˆSyXGܿ+t6]|G)Hi^=hFe*UwV36W>}d30" y!lrl0As'^(oa yv xx$j,n ;j; !RGL! I9$l҅x9D M=GևecN60$2ld%|Ayu`YH&E༟n:G2L~ewFQ]aQ^[~|4 Ss *=nctMn{qaV*aͿb,js^)ܻ,﵂Q *07{lq?'ʽ+^+8<:QVfHqiJpd1hhf'!)I i2)k x8NV@ ֆSuyJ]XBH{ rԔg2{~ Z;vrgM8<\s%5FbNC%q1 + +,[(ID>h]4"L|ZĆ݋`2YxF?.;2OYnZq((Rh]Cf/:.H`nv'tfX{@ypwэ[Į[;vf"Abgzq[Xp/6#fO 'uwr1kdMq>|ݧɯ 1:5n?Eܾ fNQ-^mE:c?;ViQ^~U~E@>HH1@#eǿI#J;ͫSvO4ΠFAo'ju44s?ޣ)И* Tq?n!LsEМ.dpWY*l;A I7' $k7IP~D)i UOف,I:TbޖlZ1ASIєf,`aN K%h0v 2g!36!rYxRH@|H Ao?Ls$r}#ߎa*L BZzn=K<*pg .Һ[~vˬ _vCtg}5z M.$[` YQ**hUI.I`1Pxu3 :T~9(f̚F>WQ{[ &MK]ʃ-U@ZP~l~lGS vl;Nr!;:_%!F@0XR'<7Ӆ;>dPrȻ]$uqanUGv ľźiЈf Jw3(  pN6,BXf@TMP+ŒCi;J1NeIrj̉5jΠj X;jCzj3Fʼn"aW%\w5El@kKHŇΞDs{A{R9I\'֛xI #lf!:n%vDsΌ?.}cDٰ;vϧRѬgN.b8@vT-^L&8ٶv\lHv6/,lMgC"l6ml⡫@v65z'Ά^/Мln|n ٰ|h~>[V>1⒲ y^蕦k}5-iD/=ѣUW{rWfZ+8VHڐV*ud__ο>>>_NR2{S}Eh5N] Ȇ _2d HW uPHtȬ>PY}CO^R}Ħ "]m@PGw;eIsޔI`]'Xj^tVOcP2e 6ךR5x˧vScMH@x4gl ea(`X3ɡK+NrKGɡa6ck\yMM#WmM+'ib Ps4^ꤏ5*E6-A5U `%g;s3@hHJO 4gz QHFIƝc?_S!| {n@ۇ#˹I!è7))KǒERHB@n%X^%G=Vˀh|( h-!|咢 f9[@ad\'C4! YKG}{ fd'_uiݴݴ%ab8;j( rX |&4s2H=TNpQK p'1 'OepL-d +\fƝDx,'e?1K]skIOz,Hi^e#h yfL8,8xqtM,r @ K ȑleN^ؖM(I9zkXARY!K`1z\/ A|&H +Qba!@yf4%{R$hqKIzҧ{cpJM !9N!UʛL=ot')+,`jHt5jH3c @ӕ<13/+d !Ӟ @2i 9?mG}9^_W~vҰ&jfaCLL/t7b؉. DCu21~N/{0N#w(= ⥡dIh`2«ad/GX47<86n!f^ 疷݊.nٙ-n醥 Q2Mn+dL9WQODa&j dNk [zDfFr$J%ӈv6MN'и=S<3.`.PA GT:m f# ؤGE,@ﳛqtEvķ 13o|GNTfVRJѽPRQa+bl a0~LxqHp2:t;x{99;袌Ru‹("U)HR 1coef8($mv\l%(!-Tbo% (,F>crÇ;u!:W_>$ \%a, ;B *f>k v+͆h,?=)t蒉(0=|WT,iK?x~Zi T(j3NQdW^8l!oP+kǾmהfIڶ sVBCMA6m68`?KMY7a$z k*ʞDfCxJO2:^YEa)U"%#kER^V^m0g%@3:meמH;dM֚7/:[]ԁ_p<%4PGrz:H=Mсeag o\+ np>3͋$GRߎn/5W/nt9* ZzOe̅/{*P`~v@*{9R3_CtPP!i~ꖔGH4S|<v: ̈́4Ĭ2*liSn ϣmr `֚uwUQd#3Na0.ɒ5r!ZS;( A5zC~=M σmm}lrH,UHE4C;!l_benظVX0A}O` 8*Dž,ޜ.xdU4XM,H,Dr:ih0BNzFzA]aլDRȥmmW$ҷ0l6,x\6Q^9*E>7a;V=VLfO4gр0 6!I_8:2dV\rqE:F*u{gU>df=RteERUR@3<!XCeRyC>x60>#@E1`o+>ȶxzf 9l] \%(ΐy|Nsӎ#}9FdˑozjHgM^BOoBj `'l63@M+"R Y((M'r\J|U]"Pbxnx<ƃ{tz0T 0q(E3n 7J 9'\}=3D&PA~I6__yP}ꓞðRӋ!UgwTnneOn؃PZm_~PZ'l/~l/~5_~ȣQZ??(=߇'C)=߇7C=)-Oe ۀMA=Lu058 mn~;[ oM;T¥!\[LDmNc N-5ie 6xz\M4 _ґ2dEm'*1 $]Չ`"í e`) t*c(L3t,=N`i]:LDIs)6@:t0C[Sf% Rt]؋FqrH5fBc,UU%Ö8J.V˶`c`>ZgY2D>K9ne;bUٸPXsg 8O톏thV!,Z<*wje;Á x 4a(xď]˲ yPFr99|O$;-E0FwRt' },z,8FfT6̬hi,6U _0YΊAL](~ogIi] .y pCr xV]]7H߉f(+yYmmI(dyh9+]:-TiJ4$BYlp,O!w[RY7->*@z*qs>M@j``;b KQOo)+@yxspT퉉xH"9z9 DCvT_%;POKedR2BN$"[C7m`a<(H]F0zګ/&5B |!tZWqQ4Z^USJֹ4Zk+# 5'YH89=8>BVVQ%"Y!֎dr^)kfWv! .+ abR?r"0^/0w#%MA5Ji;<75*4[ﶍ#{քԋy3BpJ3FR~<_qSUOU+띔wA5O55e+^-B85yH;gpk2| З|WZm}s\.{Ȁ#˰yqY.9]BD%^ 8d`u;njvz H3L.=0ix+6pNA%%C.a(Wu'oNa, ۳փKQȻ4xUѝ\UςA*;ƂQopƢ$A-H-ht ̺R&ptݠnTꏣC) xfDa `܅Be:K3eV ;sȟ0knVLVn=Weۓ%H8ui`OqHUDp"9GX؂B]Oŋ$uuM0ˮB4տWrQ`Vv] C/2>hi$wqάױYecRa-ǡbhf U-Ȁ猧 h]7d,+mȎKݓf_-.X )6nح۩iy6z3oQUز $,2چ4Oxb.s[:u:/7l2h;!wvPǧgG+;?N3{GܔI}yߞqSJ&r\;CЎ&ld.ob]aTҞ\*\-K vrHp8Y4MGʗMݘ"2$kQUuWnb(X>8{`C1WqZ8Tn^MTZJa=QOT)/ʶ1yJ%t3*CmN]k1P1q̀˪wx@Dw01K=9/T@M]CR4~(kXNU (9gy"'Eo tC!؜v4 eJo+S} zgD 0I+`t%գ,Z2@%ZhcwܬKͦ7{ n{A u}=Wٿ&vԋ?j@F.0 YYVF]])GmJ3CjŇgu, ^NlUkwClN.mǪ5_b;(Nvaҗ:۰ї-RbFNNSa57ѥ͍Hܨg&A:RfTA\914 Sa;5!d%sRPIn/*lr2d9M'szqgoFEkߺ0ã\NuČY}rR jK`Ý 5.kjeo*<ox< 0LGM V cC[w[BN3 6[ ||[a_>';1iE8ku'?Ѱ/s1ܜZ95& B?kEQXhj?lBzη`jן| kݺrN^C-ԼLK;QQu"VPo0Dz ŝ sp#KWb/5d3(p\b4X nd0 JB;96,yp$=$!3m0ڴ3ǥv?a_{S;L|+9B`B׏a8h+bI켙DsP@2՜VҽdV-VJԾ6ɭ[w.j9խa%&e0e\fNsĚ͸KIENE_`qw_BS>\z6_G9"~5W3/ 1+Ϥw6*F템b+[h?$rLz|.(|{pb*b-uLFda?$_R>u3Ksnz&`S-;Sc&|s'3w6v ʗNV|=L>P1TGB,?hirj%G,|Fk*6".%~찪C:ZpԹ촚(uP.T|SR p0I%{ǘ'z5q2T¬M}6q*3-w3'O5*عv?#FENV epudahaNDx2aPv@a5bJ g`ړu=pQm*G^( << *s.5 L8^ǥ bZqpN>J{_xImaeA&R00eLX4ӂch1?t X lFF^ <57U?OI8!<ő As 痌A{8`+d܂w/ݠou#о[CO7 [q?U(J}; 9_ ,{%%l!Ru+*CK2HN;_Y8F`>b-R Ǔ16H{nC3u>;@_CTN*xݡDieݻGIЏGAt w: Fk}4Q8Yy}I"q˘&Xs;awV&P 8$ þ[6H'9>ȴlFN|gWPH-ݵ@ƙ7]c.!ڙ86j9\B3Om;9ЙKv)2n;\B3Oq!wqw>6ޙ1d:/T6W۫xl]7WQ;\V'h|FVxq2yDQTsĕ[ zq9MfNg!a,HA;h,/H?)E CȨ%PX,b9 5Kk.iHD]OD{|@8mPn]S[Fa< I[ow!Rp/ZޣR4Ñ!vc0WQQdi,VVoHma8Cغ,xƉˤ1x jy\^vZHz`[e[b S@21=jExxW";0ڤLy<7ryn8y`t)\Cj3faVG3 js./r9|,NmqEkpG aS lڝZiL6UrUs㣷,W_gVfQ+ޮ6Jm>^q"wߦ8.qM7l_:ʉAeZˑ+O\~ov`B _qwAs8^sԺRqmvAЃqgHLd4FPTn{\{sDHV\V.R =۹ug0ƄAUp)w[ׇfO% ?luD?]o8\E$C€x i"QzI:?!9K cJp_ɮSwW T:^$su=LTlo='=/iz;`8"<e[,s>v -%~Lc.m|c+Ã7AP'mΰ[Zh~нLs"C%Fgv:~ `uqGucA(@]7Kڛow/GE7qnKWl)n<ػsKsiKKA vBk~ b,:Qq~SvX]:OGjD֪Bw< 0$n5X:OjLˏ/?-ݟe .Ey?vFAbǷ3S);0C"FA$ zߥ5? }Э|K%YPVt BrƘ/g6FAZƋ) M,;YvsB} %VG/ߜٰm M-ơă.̃7kuP\2JMR@tڽlx&KZ[z~_=饂%NXytKdte/zc $XthI2,aJHJKi^bl'IY2[joփwRmxE_J(E G/cklT~,#M Ò *ƛtKɑ9袰jtaK< ~zr7%pF`Szį.cن_Q=d]ҡɘtXKR_լ~v⇚D`ӕS#On^K-; a?܌. &)N~,ZV΍(̳QpˬbXIK0Ҋ\ğ`)}G e%JvZv 1cX CC[F' ;X n . &ji cR{#>+]~vte.dܝt]ɠ=Xz,3iVrx`ms(`0fcܒ)^px=|H -Vlvjp%VFNK>0?\z.7 NY;pIubz?NxEqIKy%Sݿ%Pd_(3rXJ.26j(kvD,9,x,^y$j`z %.u9,8,nyGмv4NZ8,x|j\hI|:BG]Ge9*#8>,v؏'KՓa:y->O^O4,mσ7zS(zJx2JjX^֤cI]MÓ,ŜO S=;w:fc3@Rmx< e0ǕN. Յ{Rdvn^jpiS)zq  FXO:<=)8<j%~2v )7|mDf5_~KP3)4nB}K(zef>1JRJB;4cT32"od[x75CqƫL| (Sw.p-=?9b-+^כ鈛Nh|s'gyq5+5]ҞԒΎps a*4aLH .X\Z-٬7>5N_vw[cz7\f#'4G|3TEM]zkP/julHE/#r7Pϧ\T+͵oGl=i2qZ1C 0罢QTGVۭrI[@E,ލR` 4?I #cHK"Um`xړ}WG=y_=sMgAYÈ3l5f5C6 j4E"Ⲃ# X߲]aWQ!a(8CDBca&lHKUc`N.3s7^ g~/qrފo_^Ot.'gg|EQn)ÁRkPp‡)%7ez@ A%%EHvAQ,!e{O&= Tɠ9[5[܈y*P4OC 5g:̓{ȵ(QbMOZ<c#Pwg8߲"aqCR;ُ_?qPg͐Ȯ\C^%vk!LW_YM&ݦ䫒!Ia}e/Mug)A/~ɗq~,tkbҫy]h Tn6fs9Use dIi 8"ƕ/^mX3ytnk)>Pa@¼¶Ld.C:ee p:T鲒PʆUܑ+Qɢ-Jγׯ^W9M.A+GF5VO31.q/BhC݄1gd{$7[ڛ{#X?W j-脆; 7j%?t־R*<*.2Oevs C 6B3Az9IQ`0#7 jԡ×ܱZCp/ ѥ:5!nd^hGQq6ZMX;t#/kTB2Z&%=;!Ldz)#@,>h*r})Xvt"וj,U Uцl]O78 W\1•_4aW%KFX(O&D+-Kkd@՝P+ ~]9&eUKӁ0]A5 Ey(ʼn̾P'g'ǝ+ٗ[J_rӡ a<{}zq+g*v%uxy7'gZI 7B'#/N ` #z}˓sW_m99{ r7!CX.7_:.I/ ޼Q?o_|%y+x 75d.fҳGaV_i/{QY @n<`FtBY la+W!"nG ^N&T3Nʤ% ^ft:)\J2f$wXWj,TcoN^!\":~{ߑ:tT2Jڒ*UcM~,O7%, @[['n9ʀ,e2sF7Ide#5!80G4} NX ⚴V*H.M+BD YPPwq~A?;Bn Y.z u{+bwq urm;)=W&R %s aPDiQVr󟃈+\%2ѻ-?k8 CHzn:5\;VƜA!"C|#:W۪tJi2S|pa m1 LPuNֺ>A&~^]=;s`Qlj׻DhM7UԚ&3PẌoy}$*Op#F0`aa4O k},h,MJM8QZM2Ih1k7}7-;Cd\cA>N7C˦&'5b%fC׆wC;4@N Jv>{v(E`Z_4[ߺsJ&9hAul 7~_H̉x }|HOa%i5Tz$,(H[Ex 2Nx[jZɔ2@.Cff`$8' 27<#C\?0OnWt7-أ0F;Nw7+o d=K3p?xV7АBWt2D7c^ioPw[r>Qy]c^$CjrĖ꼊+r43e"./U1ɀ$ǷIM oauNRe0C`xQhS};Q1-\"[Fd _%zxT))kL_h{{vLtǭvׯ_)l .TקHl_6FWl܁Ͽ~?{7Uz}_ǵ֮ڪldoi@gZ&UקHW5$tOZ 1' U2,"ގX3ďmȺ8qpif X%JѕhsW%YkRH)#x"^\%7IodYݝ<?FN,v20x<#îɉ) M9}A v@3EXw 1iBx6C"˱ȐVuuʉ!-3I8"2CN*OUQ& 5?nV |/pP9Mj2 aku2\-4"[w2_rpE*' ӝ͉?,|>P 1B hZjtJ^m;h Sz]8O0Zt'8p|{E !6@.Cގ1 lK!LJ!L!:':.y .jn1vdꖛ;}e1V'N|i۬ Be[`͌,?"cbv]{nHn^*Q* lL]"m+ɗudK'1Pd7]oUXZC&'$u?hSܯ~ Uoqaa$y7;B#v'.ٹ ׯY 8RJ͛l,GN^('77 fӘ%~Yp%0$Hu-E)hˬH;曆%z_KwЪ3n",I=PeBducNѵ+,qVzɄ @''# Z$/UzZ S X`3ݒQl()S0$i3hۦOZN6SxLߺ ԻZfQVgxvcTZ)BL `6 ϐd)1ۚR1;Ͳ~iėZyHɗ[@)4PO0L hg|Υm ˩ٗ>\sktLN}ܚDZm['vj.4ݺ~dV/:b2RRd,ՠ3>f>XOGХ4ϩR'zM WFiֿP!.`G2 E$Gf?{QQAԨ0M2q͘j 犙5 hKJCfӜ[m1t{j8RA|JO8p'AAs7`S,zӝ_Qy ; `F m A&-kc)qXxk?*lX sM %eQ3 hejB,DW'ݳ8f-'οR(@-Ξ]k!غdA}Ԁ'լmL^)˾;6sDv?{~r+TzNZfi6ՠ[}]qY(7(eY +rQ[RUA- ;2r[Js3.PrRP60t :(|íGc\8&o4F#h?txK:Ȑ}5l O%Ft4.Rh+NNk`'!!\$JŷjJ.cruQ={T`%X*.i51B_#+F1`F={6\ $=IN/}N2!RI\cҁI{w#iQ}`tgX\n2J]HgI+[7ŀ%XKLC Zqw> zV0TZv6?%sB!mqR*IE K0p,:X}kٝlZ;]z㪝(ps+L=;WmX4GK'JNeS^qtArMX=2y+&P{#ѣ9 SmuՐ;Bp#EPkלoѕzm^&dknt2%6a r懒mcl,,.Lt0J9x'60|]3j_qeբuf oȫ3[x#= r({» >F:T{Em]qz)V.$ y߽ pGְgњlzE9Cw뿝8>fSM~RG׿,G⏛fL}>>k ӈ)KcC[X%ޡʄc@ uh@wppPoQaqvV,\Ae*_د^gQC8B倛ͮumhtJ|0>kcckm NyvU9|^Ǎ]ڟu5'WHrlWպU;B\A5ؙdpUO\)W>'aY|9#{$O,M2@s$B۩-F5Egr])ZcY-kzY77TIT~ޜHom T_w'/&ZPO|w97@x4[yX8ӣl q4Όr38He_jYX'UGb>TK0["6~Uo"yۊp(sm3jP3.q; ,F;7;̨z$ǖ@ZMJ( -ⶉd2(plloE۶&=#aQ k̆߈ihS|TvWYIpŽl!mMG# OW-ڨ76i쵚$'qw<O~$M8mq 䰡4. + 2%hYVS+*/;b\nI1V Fpr~C;.%|FVٰ4l+Ok+eBL~vTzN%l/.S4 1))񷥩_Xq勯ΎξHzWq/}E(_AIkKo{w|շ_H0'ǝ_g`XezqB3o ח%K~͹}rӓsߡS]ٳγ3׫;\dB!/fgnVmm4b@*9*WUlkxՠ/-W/R@1֌hOlXFg4w(ɝ^(}/'I0xvH+ԅE#C>Ҙcusr1Smxs2 wއ_h_ U9m^,;F !'!/CH= d/}G"@,!Ź ӟfhʧyK4^rLt3ʼs0iz)nBCH'h%bS7K3(@T\)2@ZnsV;GFwlHs ]L=8[x:Ӹx@S3{!јX#9 "o6`%U*(}C#ѯת^4"W`2H#xkzZ#=(L࿰,6CS~;mm˨@ o}"YM~צcè8GU*}[7/_:.+;1!3=&$ Utu2דSCjG|"'^ЃBzS9?^}^+77]WZ_~ɿ"UeF.ݰ \yW/sc26Sm.;#+3lrP9-p2xr6 tVo% m0m`b BW¦7hS[V u^ C,^I&т;υC7xљ~24H-VsVG|XN:WVbm$T:xѡ:[5-nIF7C+1nyFfI% 0]:De*i6(ʼnժ!"<M=HWJCW(+ooʇ_Atڎ~=3rczBRT4UEo?ĠW$1#DřFWU~P 8R6;liڅ67G He}Ӭ1kz-M2Sx96>F4Ht>x!կ%vȐC:3&363P_ˍ{Zn:0#z{1/X_ Jy>(Ϭ£Y_ tIJ$ax>cwS&]ʜY<߳1휆xa9N6]:'D5ۄiZ ̷Sw d8 Juaϧ*χFcZCa#Y?-v50]~`} JˎZV Ǝ~+r]ws?ނ)PڜME_74TdiV3@8VJ $kSBIBgE!E q^R[ ZYޚXK^Wd89xf6[z:Dɑ\{G%Qm9&} w|DK&0"?T܈҉OuTC mP_H-RjKY2^jNR-xs< !7GX'3*3<*T . VCDkszl̡' kÍ_t~eMI2d ^YPatorƲr{0fY9aV\]" L*6VV+K`Py۔u Ypt#T EYR,:mv)d2@!kf"J$R*)J yiQXα.EhV]FrOR@q/YC*Dme=GQ!%I3ЏXya2J{1KU Pu=={ DL5c<\F݁rEչB;q XO|ꤔ)04%vގZ&_> MDTyo$%osВ0[&d/x%b(GySF>H TK #Mt_>mkʣ9SJ6g)sy)Z}[)(}:_RՖӖ[SzTRLb,aYzTV%ȕGeR՗vJ-ҸsGee1S,=*+Kڰ,lf|QnpQY~r/J{0*@CM|Q|T>_BsuZuZZE)AGWm9O(>*+p(>*+:.xμb\Q|T=]/,?*+=H<*?^XL Azw >*ž 7E\>xT^8?wXUƪ4 0=W6ʖ nQ.\//Z3yYŏţ_/b#b[^l_|./>ϿEq,//ˋ"|Aj![ǔr %?~?!lςw?>4\Pٷg/Ϊ<*{TV\}uq7/AoQY38 GgU_=ʗNz&Q `U[N^eQ/ORУ9E]Gsv^yeωvN>׋+ʃ]e{w3~ܣ\q`!aQxѷ//:{>ʗq'8Q<:88qգ|7g'^V/ߜ/!G'^}.P" QϡEU|'Gߞeݣ|ٿ8ʞ~WK>%Wl9O{Eh +Dt)H6; vfIz^?^{QտxTΐG0z%/ yO.?mf `noEr6xe*G(8Fřk-~QdػA|$2i%"EN8P+Sd^L 6 "Z+sQw;YL&{\Fu|b)nމ̾s#ڮn#n#䬄$6 Kt0[Rty-*~! ,[A.]fNYvHzO!Ō0<G_b7*gnb6Ƽ\)P-Wb +>[2 k{I%q)1,Z^F0 ^<_P]ZGKao:#Vߚbɦd6Қ'1Gp:EJ)ŗ9>>6f ;lKShBu%=QJ,#1zhU"q(ەi ~!YψDaj2#IP\;"Em!a:R:tEhd8aM5$+2\].'BKRtOecf;YMٞ}̈2 ) U+"ł5rQJc܃vV(5hD@̇Aw*Fc8?f4(Ž H{a*,~r(pZSdu3y[ ) 88ȧ$W^vH=]Vן?VY WvObA qJܡS5^O۬6"Űmb< RyJ~1n~4ίVGTn+.:qGE'n =0ûq*ĬepHL6 oXS--q GY/^.)E[C$L%眄ɖ/au,ɣ&%weYC6%A#0"T&m&ZbwH)-X' W'2^*^ a Rg%*rE;p8Sny \rh4WI[` ЍddZIV.`yara-,GJMaZF:wdG׷wOD`=&Qz#71BUk/@|X  "iEC,an}ԁRH0gWA/~ɼS qHb-nP uJhHt3x!,[5xa0*fg_<DTКI S Ȩ\k(sо`;(/ Е rX%rsPgu&l#h`WpX)1ڥ ;-2[^Gt&XP-y45 AA.D52 +~uET>3#>TLV4N,e%TPD1?MԼ.|!!ߦ3fsF7@Xz@fj? F=ZcCAQ 4>OEg#@{BdJktTS29A&pM!UˤG!rE65)J=p\a<]z Wfc|%Rb]tLm=wD-8Т (Q7|Ď!Qqui*Hͣ8f޻({udoԿ(T,6,r;Oj)̳f L,%X *&f&-5m*tb*=0\/p TU+\p)؁1hv;ƧLo= kIWA:gEbH?[dɖ-5S acp BwhK.*%p)C]L8ϗ.a! ^:Xˆ0dI>E\jg=var>2/ 8c,>B!Y*ԄT+"C6hH.w^%?r omjEB__Wt WEH4) ւj`~=|]^"׃[ܜj7dޒ`rWC휱M{6W ja~5x[^ 9a 9!@39`Pa~e.0g()_0^Dk6ؿ*(Wō~+ƍݻ x+|c UC="/2,6rs5fi7FɌiH d%9jOV0}`dERs ڔ[BS_JNp46u*AV⺴ P{|zN(1Fze-O 4K^Hd 2tČ@ e,S(;S Pƶ qjfƟmLH5ozlE-zV?mGk95.h˷eqSZ̔V!=*0%W8.&ٿ#9  yѫ]uNJ2;\}w|9,N27YGz):e= [&V>*74{)2 $ϗ>MF}^ا6v7 Am QYN'8ЯEwp;؅j ӐX"{^|MUހl ΰ\Tt[tG#la;/05Xaz}e[B2 L5Bb>Gb>^w 9Eɇ)uIJ&`>)9,[ۮ,j(-sEN)(P ~wүAa߮XQRuqa},38$ m~#UWsȧ~3ꨈ[v[y$5œ3L~$N0d u/lA'<]6|xfle3Bӵ*,XR6QwLjVwū4v\H5>i ]hae9.tUe.]΄=|@\L>QUHAx}J*&(H G^M5(䈒P$R>[XYYc=YMVm^Aclt !Cmk)E_F7I./7DQF6qQEa=RL+o/bN;/bJ$)%uʭajj]8Zk%.\ oNc6Ed[yw; ?6IxqO!kk3C/GcԽY\.K{Y[̿g3&;p41*ZoY >zV6ܠxAoο;w<K* j3ݮ+A?;{CXǒ"ܺa+>yDNRArkCg͝Fc4~S}{3Wnn[;R-NE6Vq _}w~}ÓHNRwVl|QOno>ks{+~"Dm n'/ PmΦ9u%W`LQv-Pv<°fhlL9#u2A" _>F(fpPrK2Q}4Qn\?d]IH:Z`xD<:,$!rH.^_|:sj_Ԉq-C{%WRI`s| q,+L/- JUN?L~_ Cvnնx|yګ7]2;>R;Q5jUw h^ckF`{㪠i* U9>ݺX^(T`A"5TXf*yrco \<vd4VD@|O”%=>:O^Kй -@^!'BZcM1 Dٜf#F' W3;j\g  I4&ꠋ@<8W#3̕DT8|[(qS Cy.L#&|w7v`\;~ԔTsG1 WlFRDR/d>&x0IilN\8aSB14ԊfMJj vQ> L/`$c 6[ZqWL{ˍ,5:<%H.V^zT&wAv<1vUY]4op/JM s@CϦWOL=/ϣih7u̕lK>;r%'kY2r2H8-}dҦS( Hs)P۶XF ?{ĥG*7 xO$@=/zdWt&b @ƊtNq˓@䳵UP|C2~bx;& M]ws^od](m4fIhvuǓIؕ3mζ;(:x&3>$?tPF.>9!~A %iR+?(RԵVmAiUpa').A7'FFZ?4yXGpFQq^Sϛ˜JiZ9c$?90-wh!SrdT#ڈ`-U-Zn-S v\ 615pu~((~.̳8CmM? 8569pד|U=_8e{(qBVM᝺ ovBC;jS8f˅^@/L7'GntGj.蓷yI)%xe֠f7 5kc};93VdLd|nFW3]XY]Iyܫ߿,7nfY[C-Iam(<0&[3$RW8D3λ_*=7㿘Ý-E%PYQY(#,sCF&SWU7ѿ=W }{~J,ֿiߏfY2gsξ> 6>bݵ>CLJ0*}3 +EDcQ"@W3yZIꓛN]H"J=@̑J.5p|߽Ls'!|Pd50p@g: ZPH϶Di<Qi :n0a"1Ԩ߅|5=ؒjQ;[ 爝09.E 0PIC# /Bꜜ{hlHb'(Bܟ-0 Ъi$W\ȢYl.M?q"24cJ~z~bu<%.Yp IA1C+p`~h. 6,r@B6n ]7$v9KiNv~ ެ>UNkx.dWt{}L?L+Nwk@i$[]>6~YMhZu'DHvZj f ~÷Ѩ*F&36jP}~T }PM^7N߶"ey{z~zn7?,ojn_ d!K|J` G413 O(&^*cp؄$uHa^ԯ봇ƘcZmKDArw aki Ѩq #"b᠎8PlX¯0^r.[L{wS k{#ҟ*Ҳ 7m^7mZ$䏅Ypu 4-)a9<>`r 0\KP%~h'G?lw~ޤl&󟝷oױK)C͍U{asmjoTA[o~^[?m]/崤_dT4,$N׷Bb0;2E8,nf+`dRY^ZƎ3Wc(()iŗ.)t`0;g ]W(&IRrx myz(?JfJ]s9B˘.b3:ZљzY\OMh8qۮP$Ky.,SU*=U 7$m#>w!\J2_NV+9]bu}9=;54XW(M"ERROR0jí7-IJtV uuم%SET)(b:cx~Ue2#?؈"|e}ש0K7e Ob3P PuWi.SXIT«vt99]PJw{lы(ke`i.8$c$t 01f^wx;,f-*^Ó8fVH\B`IA>Mbm&^Uw*0Riֈr @0 XLǢP xluM0~`]C Цݳ=c{Ez?7]5e#`n( PHz>N5!]a* Ǯt͸͖g& n|?߯p:| _Qc-#Zi R4fKQ-ϑ7[@la q?-Ƣ^(A At-%)#POa6]w"l{8Yͫ~`tt7k$eHm(?V .]N9Q*/iY&}Lۯݸ|`1GT6/#]tM$9'%.i'10Hx<d,?~`ϕweZ# Ma{xjI]YHj͌fB3Aa C`";fTm5ZJryEa6V*⢖pќAC!h-]&I2 b0YmӬƼ/GYy>X)[#< -p}mC SfstJ`4> J]wEp5ĺj4ħrRph-t`3i8wsHa ȅMc%35Z' gt{Yr<9ь%KobH/ ,eH^:o1KIt~0lSf@ Owp L͞FYeE@7Z(aCs*j6UI323cT:gy4ITߪJT\.!1$GVg}KZo8'Io6;T:MOd#{n\Gڥ'QHc8Tze'&* nsf,iN|b._y V2z4U1a%%e#EL ?kv ZrcGj#Rt [gnNՒ#|׷mk6nc̈/doʊ yQYCU`n AUy`QTj8B$¡,3IjOؒb`$i9~RוއwN9Ѭ70-J f­5Ǔd J"l~h'ly6(k7@-ȮWk2J>a-uݕE9f n)jKAp5a,sNsarR!סvG 90T)m21NEĨ!w ITV3TE$<-/9MǺ úLsn5JTaB@> !$Qnĺ >N5ID elq4LDIpϜet;RN`io4 #*p),+CܖJu Q^P"ËƅIłr/b).(&3@ ѸIغ9{(82`*4D/PD`&B76m5uky9.:Bv(y"9<|{1N*VdAM2l;0/η'bB}˜+qnB(8(hhenxc%)cZ\F 6"UYVZʅ[:8 Tv~&#[>5Rr*dN;+SbF{TFZ$W0yhՕ2.$& bnNHXRqP W$xUPwGu%7e> q ?G߸ǻ9>ۃG;|t c~LQ-" M)gE?؈ɖ4o^ K`h&JOۓBD.鑈&[M&\9O>_ɧ-EOQMS~jE$UN#6 ڜ㰷h05qtE߇l{4pcH(S~5%Xi7{'pi0 (΃ɣQ6EH~>9W|3zdn1V)scQ jMj˹~w"^UP4vmqP:o`Y?b4ʶfJstuIARc}kJ0\U4XiP3m΄r?&x!:mf^:\Z(iF.YXĂRl|KJ(bP7sϘ4E^.K= V=Jn20k^~#rLne'8n>dURϠd-O#;j6اo44I2amA`&& Au# [)$N1f S@d4(NVfvX>*.*E\{dbަI暏fq"۠E{CDRbffDg+Q%vׇ!oֻ0x8OxGw%~\I?N!#Cw.{kwɒ]7+SI֪s8WFl*5zz PBR{J(Ǩύ5L}U۽E ɖyx68WhYv?0ϣgbYқbe1|#2w||f Bإ/Go|qVh"@paj o͘xd>Wω ?(4/nl3<8=[B)ƝP=GffvmI!?⡿S?$1P ;k59+Y(=d|UeoI\HӤw3LaA lƫ.&(X)X JyB|.itS jLOzx\ٻEΊ +} b8 .m*Wpm3KsӬ Pu+$M(T 6"LVVfA,ODvt$CK8wUz7]Ђp^BokK ]iX(\#sNIBdLL'>$PDHl4 ,|- ym;SSV /)@#mc` ML/us>$ٴq8Xµw훴ԍTyv}>(}fPblaBE;ܜxȐ9$$kt}AS(q'i/虼a3y?I3)RW3igRH*hGI 2 >yg1r~0qRqb3 4fV4_-p^ޫs#B{:3 |%=ip[aRe1%tv{0A8W|c 6  ([$gfEȋ/LCxL5"Qmk>KS00#ٚ7R4>T`Sodk'iHq:,'a$]& Uzk0㘺Wc I*6Q|`R H=kug-y"@i&3):V] N>/ ׂɺ(R}Z(̓ uR )X71ВShht4(paRu}L]/J Y|y rz8)ExgPɍO 9J齞fcyyđuK nuwf< -\,7_( XVı Y^:4JIʅE2vYb!Enr# XYLV?[Vvt7KGD-j)͖vt'YP UbxwR*O.x1!Q):or;sGaZ96xl%=fbE:ʸW nѐnE80 )B>S|orꋢ5G7v9܆jzf(vd-H8i4CrJnmL O&=;])6!y`0NA)=Az\gJvni(5\'j:B] Ԭ:l{==aO)E wA6GI{ k0X[:̟ aHA8 E V!Lk-3>BKctTt7fN&!|DGm#wP> `Ef_81vk:- ]Ddb S Tvdj%S0X; =-joľ`@y[/ y:̎(=U-;.٧Se3BHmNƿ&!MtQAd#ΤSc BZڡ` g7# xd&Abhn|0A,#{.o%#bN=\ܧ*9g]U`b0J.bxQ)kStSQnH#ebT+d#Go(Qtf 7SixSy g݅Jz ;3N9L&T2b(Y:>3]HE*sjX s:0}MYodѢG5:8|$L5"M#ΌIl),o43 Ashc)6[$幀:K'#n^eHBR躉^`U}^+$YBN /}`2C _z$ "Hu:<STFK$kSI2ǽu8b;J)5 aZV׆eYP$PSLbT zhP~b+emк#-ؔ~w4otbqw<%Rm4H@&Iq(ܚMzZn{@?}z+ Ϙ#Iqs\w]4V3m[4-n3V [Ev`${ zy^, t֏sJjL(J#xvQ0P h(/ʯHXK\iX }B9L^ <;~񘪫 ii‰䇾E&F"y SsRn_,-/lħӼR`.w.T(]Igh߀B6BN>\f?V '[ h@(jf0 sMQ; o+BmPfq7˼#AmPxQ [D6LFݗS;NG(.\+8l{a.hUMFIյfX!q+5X˧6 tlT!sUڦ -z&F]V6ˢOȄ K%ף48+<}5ݚӐ:~C^!^,w JqG)JI)jv 9NhrW,>a[lē%ђav8Tֱsa(]FtJ3]LElN%$|Z|E^rM aɟ: 23gm@ '!N e_s;>N*:J"Iie 6Moo~ Br@i '4ʵKH!(Ü f޼>^=>I=ձ̶vHYt|G H&prl BPYz'~iM/v-3ra_m24_%UW*0J|5$V5'+ լs@dqg逭! wܚ znŁT,͢4C$]]l% g22 GZBU04ұDVö"ʽ;>IGVHX!V]9S 5X4ddqDG_i, OG>u`CG2dtNUNAu(@^#Av^U{N`NJ >JcDE2s8ߨ (N Y2+YA#{Lu7WVUWrJ5-FpB՝Vufr\ſ .m~$lܸ,& 5-Ln# p8S{JQeiL3qtBn6bYS_pѠa6CwX( ~t]qF8PNAx]f$'{ӓѨ%+=N#J[Sv#Jn:h~yVRrB5.fbis\N[P ;X&k [\TH% ܸ7@P)Yg(7_6[ νS|`~m=W0|8ߎJts#Piu>rElGh,23\41v9O^ɳק'xstԕٵk̲ l-tI ¿ OtLF;N]ewmP:92*^@]Qˠ <Р: 9>Z 07ojuXa*+*濱 8zST a}}=!['s|J٘ҍdX2E$qT.s9 kV]gxm9@(G21e6zSAs9Y'3JE܃㜐m9DdK,Lɳ6n6u1'E:uLo(&L2^ޕDOV\l$++nGcztIV+6- z0Jj,硢 /;򤡮+e;8(t;@⊕<:iH-2"+dѶT,] AJNQð0XaZ\g!#3 Ug^׷ڙ]VVŋ` .]i{#TԼp/uFy8Y.1Ǡ,ި$ҍ0qV lzcs>iD3mw|?i^-jEbB՘fuv E%6 ˴aACIf_ŗPL`s\ȤUk ΋) Ȅ2[O_g(–Pو(&&m# qqq ش٬G\Y$Z=/(` cܘYu N 3vK|L.g9TǍ[;&_ 2|&;zrhʙ`܋m?x|jYO'rnZBdЖqM= 6B)ݺ9/0Ȕ91?>JtsB**xZW:LN䔴s!d%?8Aat%A8_wQ]g 6Q] HiSgÝ6L`6R2 (x7!zli]Tbk(Arq`jjBՒ̶*&> [)1 .5 ˼)mZbxpB~~?Tn-:ʃԦ TM5s"TH(XLJz.(Ɯ7:)؅yWZ+TyAF%D5yGF%֥$ɀ2'FGoqҘZN:]QGC<E /-1P8Fq4c%kom?C!wC允g^AaYb)İ8sXbݤ?_7iyP/?Y mQYƥ!dSY 8E}1dG⤚X`M"Z:se=XpJ4}PX>tEiWgL4(92xI;̈y8|]۔j=󱪉۱TݚRɥYڋubݠ]<ߏwSJjD-s +(ݎȟUEKU r%ϡCӒ 3J0|M0MEqy_~66;Jm\n9IyMi;Gg_q#1^DAAma/k+ڗm\b+$ps k>6 &͉B4 &8}&jy %# gm&ie8PiIn{26ewëSMfg'%R.Qޅ6ȸFbh]!Cd-7,Fn'I>%&RBH.e3@,}ʸuǴh UE#܆}qCљWw2^` " "v0ޥ@9` ?xX,]eo0: @Xm-7+,!V4fcE͌bEB;x%m>x; kem} 9v)xYQ3QqC‹+~"ªL>xW9xMςY(k[ txk4ae%rIEBQqd,yʁk3SfBI' e0`q\M[~ߙ$h !GXCa?t? l%8Or>! X>y#R3+t60~rf.Yd5I.^BbeAlxMȒ*HCgp0FTʂ)![E8fגԕ9;9v۪9b,Nͼ@:С>utؤQfo`\4"6p\c.fcgfevb#hp̈;ڴI4s)Y膓WrF0Ì*Kx(D+HȇKX4Q2L%e*_9a;;?;<<2e D9Xp-XW6GMvPdC{1(3tgkskspi ?WNPįƞ#쉲5)+O6iyG V٦) B53jILIQ^~sC4&X!b%CS8]4"Ҥe@rI)ĉn,p>et3-nj3'H,;R؈zTI[R*_" 6sUM-NEVѦRRuh?1Eu tDx&DH| ]Df~1,#59E236ediJ,}k2WI1F|%!ZlfAش̝Rʍ& mٓB4N. g\#8fr.f>OPΝ#2%"v>`)(WHIU'w).)w:XG dm"ևb)#.i>%]XKQ=u Y5f&Ɍ ]6pOUTLAtc&0KOdRڃ搛]Jړu:/be'* y;:`Kcل$ĤHް C"<[$:Ԣ(ѼP L0#:3{Q >xtqrOfCPY|Or&6'$]g *nYao)yׅGn,Dɋuj}ɜ]NNhYgɝ)f.f|d7^-y.( v6$5p$I߆SGބH)YFYoGotև=SWTS}40!A#ح9\!Bs:e C}Yxym>7_V؃}_.*Y5F,ߟtɤyJIά0urCA[RE~Vu!+Cb6}U ʵ^aa#:F3f89kN_xM2ZG 0z!3ILF!a&.GHrקu ZR=/XJ q%"}ܒ$`5缙0 59WydA"7Ң!m¼6G.vXcx yv=uf$z9>H2[!.*F$ zc[>O|8'[\ GԁZQc,Mzsr7C=kMKR/y9(bzȖSlD;.h)"MGVFжyLjsy"hS.~"|y٠{b cםO7pEz1]\|n_┺O21'bș3n)QQj'jS$V\yQohhٞ]g.МxhCpMF'+CpWyEWZY=1͔K NKWJt2UZ/8BTOD. Ӊl:l- ϒc wjѩ+v͟v{(m>>z_^_x%n@SGbt}sn{Uv#{8.ܭne-ԒV5gt636X/&.mjFf`ه(竢0? %@ '2=p.]G*iRXD^#[7mܚc37KoXe2Ƽ[FNM[\"8d{#c%Ž:ks{RSR+֚ ,) GKț+D:ٰë 6C}{FϷ_RRCI_DG|4;ڈk$&V+/Ck;I  a'M+Hŝ4TgdpYX$Zͨj=Y4P:Zlޖ X`]@)>?z~A(Li e5>؛NӬD},46#0Pt]d%櫗|K7$G$ڛxw5@8K(|011K&!U *4g Mș\<4~i 2CLCau=Q0Ps~qF oʡ*s8& x?׾A("") 7^PH,ƋU &"d9lKoZ_Clr͖n9*%M`-{#|`F4.Im eHN,  +(݉GU䑁ߵƶ4M6"Ƴq 9[ц LFWLqeFizՐBu˲2@0Δas1n6]|`4\"L Q #7X߂UUU&&>;+>$o'!n7aHq-wC1X{p,ԣGjLooז-4 v0$j|c*Pn6n"}&C7C>NZW_8 )az&U"ٛhq kլL:,K:?~ϓF&d!y#ŭ%" V\i%S4iBqPM6Ț@ΜN &E`# `; 9nNWw4t1!@# TMRa-:G1[cp8<$Y}@\=;[c ;O͘qЅE6d)SfIk+²7?)%H6lŮhNnܨQqh( ׯmĒع4AF-HS^o|o^߫_`c12hbQIHÚz CX`xuĘF\쒅}QhYG(8'uT o%qF.UXN^%[<;&u[`cWA5*d\kt;uDȷ~PXن}W;ej .v.ӗ@>gַBWVnH0E$*ފܵ9#+KU}P+ ݃ffB({ӏ|HU7 [wޓuV`j2noۈtk$'TvC6J/(ɦn7*^ΑkƲEAß|*2$) *&c&M4)g5C,6VҁgĔ:xy;)e.VTM:њrwGemdfJ HvR3B-v߁?;4YDl݃"+ э50zDD%TE|JbA?Z_gQrn|if#fiO `<̦-Y~ Եp~_-(ExNaF$qC~:ҽ kPHxOjn*>{ׇlQs֒ |雳8׽ <4InMZ#7@E(5C=R׃uv'pxڧq?88?h7Qh6Y7`e(ǡ8ToXiXʙFv?i6Lo4$n<7`_J7׷ϞͦRJz>d|'pg`/2B2bo!Pُ1B;joF0N`"LwSCE([jJ8*1p)5|_Q7_J h'}hU$p,_!sWcxvIE"9ظE\R?B,%)gtu6"u+;=\&dt& O亮n8O574PO(@nx<"&?AӽLu@ ܟ|&_mZ Gvh#3 Va`,0.VqʫΆ釅byuWOׅs~{|q](/?iA9r4ԧ( .$+5iG w{7_o]vTa-nAM5ie]G5sF|+t.1^DJs*C R4WmI5$ɛ\ՃUJVp?ۛӾx%>“;?j.VVB%%NǹJKpTRgɆ)dJ ܁k,R (Woɞ'j-6LH93Jj8 v~dP쒛*K6 .\%KN4R|2.XCCY1q[,FxD\[{ psX8濅4Arr\ZJK6l~7|?j-ɏfCJ[?ݰ ( ,ġƹ 75T)%khφxuWxy ǑZfsGMַ7v~ư23gAѯ7~h7~]ׂx99=C͜;e>B<W;EdPXGQVɾ+SRGAjgrvUA s]ʗRÙ(to0tLQ98TZHM'8Ή򅔦QT%:YMP+sXS5^9xAZDkFiAԑ6 fZ@ehn鼽TOQۻm,}{=(hJX(gÆ8×VužYF: c^^XeX(3Ok/RbQǢl:~:j?\*-UBRu,v;(U-)U)`m,|8m=nhmDz2$UMfPuCoێVֶ2Z㣻t*CBuZ̆dVKǞ+TXÑ&8ؽڞ7X:ހIHcNՐpq~%JG1&z?Zn֭'өOʴj-k?8bj`3PeoWN&ը:wW'GQod@nR6췫" !)8C*dۇUM|̇"'~!{m7?v4-BkaX Fԁm'+_'CRS IP.xvJ`s7pMmP JRAi:Qs9WzlbNIuxKzdեC2W"Pds~k n09eb`{{OoCnY @`RS]@fJY]~/יG:1^E%@b9%2X Hec&NL m…tG 0 MZFmo7m OtNK5;QB uIqUJ iƒr-DF]q~/. 5o$fVj;0;`#u⡆:ɀb  NS`Gp672.H<:㽔P>HMn*a8m#rח>60MIUq.q>}va-U4K%w$5%7:r(Fr0XW; :=>72UJ,GTrd-Xђr¢K{J4q Px|CL"xHӇV]Ϣjv7lum@]S_^xـuE`vrT >B&ȫwK?gW'_8vU/ԭƟ{ETljτ SWw^^krS5fvxjWW֋_. UsꃆT}^_߇uSޅ;zO~&ٔ ]X 6='ώ<{ިcBՋ&OWt$Θ} x=4fӛ";F˿UHϘbS(TAS$jp'Pz,Og6< UwҚqTee!Ä6(7w4B{$L4;+O6rd']Q O܃gf[iiə]Zp[(2TVt(yz[1+8?C!߬oᛪyܜEcA |1YRhH$6WWaޙ7x -m4wsF| UjIy \:Sg$FO2=ٓV]ꩴjfO;.1 ya%-X$!>=>|rZ7O}O[<NڹwQCe?:qˈ|]lCe?wT@ixu",6'=bY AO dnA6j$cGA#Rjw*;*)UbwD/]1!KGy(ܪsu%ֳDmp!쬆p4_B' Eh 2+%Xu²wOl %"iqcIOԦh.eLeIN\Q^Tn`9J@; )wbWnQ(giV5Pn{92p04n>M6mU(^ٛ[yc| Ήf0!2\u Q2tn /]'v&B/O*/\} x;Xb2Pe攱~ʿ o%|o]OUMR큂(Be\x Qh 6K'٬.7TܿdE+koeáaˆJ|\?25.pȆS=D퐾G@{sxB6; -V:A6PX`qnuaor xyj̵6^t3"Iz0eK eM}Oqnpv{ wko]q,}};:=;jD"'|#\ЍF'HO@5FPZh mAgCޓ.~R(GMA8c@Q~NCڈ\Q'=oĜL<27?שQزECiM{zd:"-4R/~LrFu=mըקߵrTMB/Б^IXoeaiXouIi;:GLJ| |V.,%E=}Y}o,^,=h6m>俿o8E nxﰵ#J)2 /D'M{Z^祿*t7]E* pT+2`\@WUzbY{it+ YKqB1'vK0v%/;uxXK6 eKbArheЊPD?V`A !'AA"L(㐠bF0y?N|Dd0mtD2ud5O+I?g ̻/Mf#蟸~P{tQu)/Q[0fu=}ܬ]Pq%FhIL#hѦb ub ¬Uo_N>p>ul!sr KD I|T ^%d|5M-vWʄvūXCs&2?:;-3]{f}w2a>[sake"fO lٕ OX5otjTɏZ@OGJ\qc>ާ?|\qMm?(m7EFtURz 4 ta^ 0 a%aLJN0@sX?Ԉ?y$)DIj =%j$wФWz7ਖ਼IaHRi6>QC0KACReQp%ukCBhf: a.}&)㊳k a=ރ @lf DzC9d]F}'zAhnmLѧ)yRpD )ǧGNl=42? nK2 5K z 㱃QI`I zرAk+FΑ7h>*hoW2"]C>+@dI`82n!̥ʂbG_xz)oIT-gh6h$Ⴥ(u۽?q/t" KTtuz}b7v}>QDTEDO5CQ+o:µ7+̓ uA.[ۯ/xl}]WPƺlp(}e{-u oᨹ4=K[W J}ܬ7Wj*i8W6W[%[P5W}jUqdymA=W>7\Uz&x}A5WO긴Vm[:YߓZ#7>/W}}v}=7Wtl)~t!kH]WATcoor{x'y) u/G9|u?Uwۨrܻqgܽx/](w#Sa<]T-Na5߻PݎZ꓌$(RQ -y(xͩcVBQRo#[GeXؽRHD,c@zd86\$pd*摵uD KL ͒ʒPy4qoOξ_8]!@G@KZE{{s^Rs& 0xRP ++Zߏߘk_n q 3"3uac`(xS}d e˚70J'9Nj ̟/+Dk\Fq8)t4Y&(4'}09Y:t Dn7M3 U^jfhV؊~'^AɼCS R &cE|~Jb#'QQsBK Fla;_ɶiT-ӽN\TEKGPF|JLiB$:htȰU2k7PSJa,IBb ĊPIJBIқM.1(C!sS0iEGM{L#X5N&bGbY5G_vS8Uݡl%eu`iOZ'ƃNΠ "Ee*l;w(% Giڀ}&I+cs7Hmr{[w0Fև4 +L6 ! #&x^U;&HʎPa?2 Z"'GtK_f>M2A^sYZA+/54Jz/~-T@i E )^EHT܏țYmK LWnuFZ 7\9M(wҔc @hʨvVWY5H0Qz.ƒ8!叛Ȣϡ t8Ec.G-VN6Bδ&O#˒x%zBSSOƃ.Bȗ[lw>l LYr FCd%vaQO3dtA AGAwD]_/ISQP+/J n]8 A%fb!K+/V|jYfpV\ ?ʣk  a2KT~;,K nvM K70\4sqp'-Y3/NZAV4;Fa"5.AV@r̫05od=C5:8g3fN$fO6`7acT d-=s: kj2AZR.$ڞhy`u?2+$Gm㲺|z!4zR"}>\$,*:7 ssO/*> a qAE>xȈ06(svBE;LI˜PҶeKY}yqgb` \ n:w﫰n> u:-*AYѓ)$]*nr[r2pUfKuGn#L4ث=3Zsk-2YM[|C? m/1۹oޕ3%z`V3L<0W)NuڌB)i|'N"Ef𴬸פW 0al/%[lX/*\ !x n>-#biBpv6s&cE)y@")pHEio,}pw?a? Nw5pJoTar?J׳u%t1fo45x8EB ąWqqr4͝q䁱No;t[:Q÷Th6XG_0.-&3uX>?*Qlz1eKTR-ˑ V-osj!wݧ-' ˠ-kA6!6Fo^bT+vg8D0ҕ0rL,)$ C)NqU'žLOc6_/2B^/v A.ۖB@)1;9s Ǝ#Ǯ[ H`kkiU0L(2sm.sf[YPb8{Ӽ,9%-gA"@lW\p*&^/?wrnN5ƚBND;9@6-;"\t L>n)d. 5WQdDGw쉎$MuUAD$vHIEg`O8?SeuL|$}rw9?Y:mxcVXȧee4G0/+cuVK9 e/ by(b BW%]9Ep({Y)w`X])?z)C?G\d=iQ{fsw`俇.{q?$ƂQg%RA'Ά`|T}(Hhlסp ;TH}$K(8Q`ʂ+g瞮=TS/yJ q x>g;F@! {jH^ճ*G3t_H;|7Ss5r*Y賠:%*6~ hm6Z6`sHalT s][B7GY/MG/w1 (aLzuyoM?c:s~kN>q01%Z˫Կ݁,ghJź1D~bzO UXd2Ypٷfz;0s4qqOH:{r <__ Jn$k:tWwʪmQOa'dHi:[^Lx,h77 ǽ).+Q *{P/qqwmgjL 'kܛQ#ǭ0[<Uҭ֑l"_ ^"|=oiΧ .aqOxM~B-ΦjہqIxF9tAw[b Bկfڐ}|qG$v5 cn/Dx:8pfk! vd-8}ғvPfqRnYJ>@gW)|̳!D8Xl7&&": ^CUSv-4_En #vwq9"bƿ\dJC(SU @$pOT {r.*n^00{Xy2B?Ywhn?\b96bztQn9"ua(C`#;."U {=1uzC('.ݺkw*#fut5kO6ylODOƩ  eR^:Iۄ/R:asߝv Ѭ.[rpqW/q9nBuK[SCf)C^.܋>jg녚\Tv@Ve⦟[+Tl;ʑ:bp`yp&~V@Z+RP|$oQtb8n#.cҠQ9Z aqRXI߯ƥny>"Gf9l%3Ht0J`zhՕQ~t#$_~odK ·gU-6ZPY\9g46Ҭcto]su֚?L-H($YN  ~]?JW#GЇ!Ef2vцxCXl\2W婿K}-&x"M_A-g:}T<.Py.#סk7Z5 jNj$x{lpfNǝ-䖢'DM7 TO Dn\=.rK$ Ǭo_ "b\ݝ8kYpGTcxp(bw$@HeCQ[sA k}r sn,4)1.~܅[jZIe1r1'YO__N. tSzurzqrqG(Lb<. V#) yFw?]| kܜTYM&׸Jw$6j8E9{LB3IzT{)1|P&(J ¾l;;oXY#s+ `1J˾OYɈozw{I3qi3H/Ih=h; ܥJU˙^Yugts wXLiکU*4ڂm#^xpA_7aq!J;:0gpfcJ94gɇ-zŦ;+NKoNΈrzsUZ U,?:t0܉RvQ3bZΎ ݨV:@WsfË?ˈ][tkNWGv/f6L-vСuӵV(y=xޭvҮT&YֵR^0}D$$W1hOsZ.>6wBq`%+((OA8&WuG?B<fq}G`%/,Wg(L_LWRx'zO64*1_v I_tO~jyaĿo|) "Ɍ|R=6&B^nK1)ځKCmylI*$-4tbqdVD0ĻX\Hײ>n T.ne^Amt,n6?oABܚqߛ;q 1k8#/Gqx} *mc W~LaRKjhϽf%.])(:9 Q%ae 6 $ڐJ9D{BA%}ɢwf2VJ^w6߳R%lV.]^SN/[u.yGq{`nL-Җ'MI^\xn ,P;^m[,pT)pxaEw:BW4dG⌅1]@i4KJy(eg?Dşb/{vm,o71Wq(_gQ/\,Ë?~ɉk,.CEsS|+pjz\ݺp4p199u_C%@%Q:Bo,M93kW F0..NSx:xj⢹YCTGg/N{9j a4+JK - J48h1$*sdaRB5':L[xYŋAN-6Sҁk8H䃾Я_|rvךqopK__W[*,]ޖC{EbJd7v,3̵b,$dz4'<|d-NGK__p`XrsC[CN _i}n$Ԡ.nl*u( 7~6VPS,Pp0|" T8|z$ qQ4_ۂ[ iQoJo)d, Dc{ h9xx 9 YX~4!|4 &;t pnCqlKwPYng;ocvq.E gV n?ߟxI V]d.'4"koʎ]QCm-[Vkݱo- F|HhulVU fۭ/hw_/*b͈u2eÊ[M_cU虭hƥ(*FH` G% [n/EIơ㨖c0ˈ; %"̓ S&tRJ{_0{3*kpX ]2d%8 .yAaM$+J.eJ8?'PD =`gm$˂0x_ Q uP.UQ$U-RTչM$$De\J~qll^?~oK-S"yx{+0ܫL|J"t4nsCz0lU07PY`}sǸsM$=7\ !(7r5n~ycjM18ZЗm_Z$^e$2c3҇*9ކpttD =[0'Ѵר'(>r.&B2b rlGs\|z4M,̹B(B]&xXN!􁃩c5׈!疶5"B"Y*V 7Dn_EC']F%',7wאd[E:>P7SduA8Cr>ݡa0aT U 9G1y5 9$q4J$qѲ3t8g".!O4Lb_(xc$ƳS`I=O+/Y&|VRs:2KLQ3Š'i!W+se3kFAO"LG#>l] ~ Gq:, _Ri+ 7{rA\K!-J tG8#Na"{i ~t[0ѭ0ރޜ*M2fD-ކP'04:Y<@8^OɠW"+!g{ + ]Y'cŭ$v;ܜkT -ի-;(ך wFƪ(1B z=2j{9eMFcZ @ۏve}`FŰbX=Nx|7w?DLEh/0#j 1;#0EVl89_"@tsbخ|*wۮ8DZӀPog3zP66 Crct5r>rs`֏hȏpT8V*PJ%ʙH$Jwv+N0'8V*v1LNGG!w&oG$of~b}lG*^Ÿ͆%BTPe-Hߌ8wO+vR A)I0zd7' D¤hB , T>$F-2!)s c̞ЯGr:F*HS7!8,ԈC!&y !H>Hx!`HNN$i6ys>9 ֺ#<[ `; c` $u,0dI8q}\fư'VO[7kft49a!?FFJz`ԝSuü F:dUjݨ?]kYfԛOϑsBӵbq껲ZfpJWe@ &M%{H{(0=+!-|:{mBtD1w22})Z)+wf4hi>ZCGٞU|7d }c&cA2y?|7g 9$*YJ1?j'.棭|i Qr'3 lP YVg3Q 8՘rub0 d+K t a w(dq̯a.~tF: aHIid~',ͽOi> V:`rXxV#0_ H܀=j꬜9x}B'Z*n`5cvЉgnh}$+,xs}UZ☬ߑދ08/Hr~K5ƐǸAsw;xwe>I@bW*r"HX''2[J4 lN'Q&RglP5 {@bfunie_;uG(T{p=G%ݯ0K@k[(wye\(Su @vj*6jzQ8$oaz$피N׌N)h0} T@Gv{`‡\ m@`  X.tD3n E mx+ݢ&=-=H J~%E牎3-=y2ߪWۘ\!H$lkO`!!m(c2nSou@}\X<]#!*Itn8/mږ1U!kG 1ىJF쵓92EΫ_.1}Q#0!GRd єiPT{#U"ƽ_&i 9D?}bᐗEfcE¥xRW5w2!eǹ`j)796b.? C,? X; =8r)/#uAS =(t^p>&., #Bey/+8a8u zAx'QsY6Z`-| 7z\:Ԝ"i%9E"%>1LXSw0I=M-OcÓώ͟dw9ۘh[\Q[ko߿gZFvǹTjsc՚ QYY4X粻HJGSs9pj.E5oQ͍ѨȬ\,+dZ&9A b7\`V,)UL>þUXN)1bys63)_-O<: ѽ2twKiDMTAUCX~ZYluVJ7@"oFHoH)0JK8QQev(3E)w_@2{ @MQJT.0Sӄrbl}W$D* <:)).<8c`(,BY'C~ /g#GGn! Q7ae91>Eao?92124U('{΍J}fhaҰDlp9%{n$듬3ZE)kXnQѬ}`%rʪ<QI]{NI/* 8{{ߚ6iJљY6PcyมjCĎR! `IR>l}S(Pu;\SI(3A| H%PbTs[{QȜ[ax^eDwً|^W6HFu0rߣ𳈓S.$3U6Dے"k5r&h ֚:/`]΍+/ 8^s0)ibSg+qPSJr?"!F[b5?$Ɲ?5rF23 p$GjD+%iz圁 򆤛.X ~[_휣 f$Fvh<ƣ\_l Hh|/΃ivT]Z҆[ݼJ!"鉪('s*7 `KKRc4W?_=ΑXjԄe* #GϲZg<A MR&\ MP7нgاgԩ(G@7^2Ax$$hX|:j^8kwgʦ pJgrwrӹ uy:?qHN%Jl~E@ng]!d;(_wL>hJ OSN”&sbК|Nm͢_*3>A ҥ}Hm!R  55&Bj= 5saO8u iM(@ a\'V_]%\f'WL}quf}f˫zZo͙Lz,ZxC1䟍oCT%`@^AW+K2Qu i ^f%.*S`m:h|]ݺgL)c6,b*-~gu`_ҥ˰qa ߿Rm8oC$v&IJ C("sO۩O Ja21]*9GCDO$ > KPvO7?iʤHI\ N'+NHrYBc _P?'iշ>sZvZUSGJ2rQ]_A˯Fx$+ZYϰzĖ_/kKyqh0I #HCva+]:j:( dY G[)2 tT%͌*,/c[8WWE.l7dKF_ 2]?P_ 򵂶QI%ʘvx 8%sNJ[՝U}0(Eٚ R](EO{ P.Lưoh{H~o 5<WF?ƽAG RG?}}й``aXʳ)}+2*Uhq|P=9G)b]^d{o`ZoOtsͤ?n S5>W.JRm@g\ 0 .zAJ+J_<^<]h‹܁ӗ#J('l09 Eݾ5@"Òxt"_u޵-6w!%H@4ؽbmD@pHy` ܠ --{K:f-9ʰBz*Y`yMWNY%)z(oO8 =@u^},NO?鍣)Sk>Nq,dIO I9$ k8!\#_lLi(49c*DH =U*NW2 V0tj춊zcdlĺoJAx8Q)9}r/Un8x-!$IF&Ҧ-O?fK΁}˝mڎf/ A ' Lp"*.k򇽁G *tSt5ڶ8ZoP a\C :l78^\CJ +d7$X;gשBU$,[2tn5K;QT++lo1 ]J(B  "r|j/xo0}A8yyf18`Pz.'0w0l>=4[B6EݞʗHˢh7ݕAĕcכs6S'Xm`J YNF>HBKňQ*k!> gnb09sV@JS^A*%nKo@PLп8 vKcMgI$j$ʒRd͏''oi4j56/*1u:; ^L0pB'D䜜&q*&m@5Ba4'9%7څ֜& &5RQLS؉|coexTJ3)}@ܗHLmFCrJb&FΏA(-]Y.ø: ȴ[ʙulI !fgьldžOTg+1X]騚Drդ⋟vDEJq<xNT9هHqX sV(LA_-āWNb "+DQyPIWiXh:O8rQL+b3qW*&0ޜ> q2Ԧ("i+tpS>zP~+hB/%C47575 u*:&DpegDtjH=̊ѩHj-SDfa>"5sڦLzL;#`qc|nD#B܉dgUT.YaL}rYn7;bm}#z} Z7ܨքX^y՛c^0DC'ZC>| BRyzxQo 5 u"k4elXJX9w'{Пr9Y "Jx cƅ6{TݜBjBD%i RV/+++*f x8O$$jOK?}2>RiN;%h\&@NdX¢,μH݇\l-+ehBd؈d󱔂lBo@Q1׺uDш+7EM(k4KWyEK1SZ-z$c)ơɒR4O\3J0}>Rw[!ݍx Ň&4F8A8cBV3wބ RHw-CfzqzQvtő8EY;5W:S WzR,o.  ̄@Q }AJeEX)70Jh.P>P7(bxO3*sUNm1eVm,VrVm,VpVm,V[^iqp%/#ёel|+ BY魵')R'<C)^Lur庰)(rWzx FVcvT#pQ(~";M!JnJnH?@?>@pJF>.~\shR>F?̻t4{N)L<5{'n߷=79Tܘm^UlQЧv4R1M1&킊y 5:WR蜾1lL! XH/ "d#(*|:xx2\}v14:S';KK~=ZKK' X>Z.NVcKAiisQ|'PӉJ:-Sm:>4T :k[>DXh6:fge%ohI ?QT}ْ~Aaă7^Gp6gA,?U}~u?::vড়34zԷlJIB(SݎJ)L)SHSk:~"[f1 CdjVѢf㘹 g^ +LḫhT%Ar8!yJ:g,GC&:1ɍL)3jHZfCsӓg摵iaؐEaVlH#AX˅]F\xߙxjl]ޡ,f߉1"M6Q6UP[\qhVS]l0^{b<*DIT_D#P:/"pUMʑ&(%ۂ^(_Z;|FK ]zѴ0+ ˴G]<_3 Rى(yO̍E$ DdZ %vͪ W lB:ǽ̫h, g5GQ낚7HBY91~mͦB>G+H_ؖ?̚2'̙ !=3bD@4lVD\T+\2R@ sFjټ+h#EN:-P/ K #Bi\3zʝ3c6E=Z!]A"{r2ܱ zKnHō'`t I0OKdTɣ{ $*.a= dg)#k'{;:~CXZy`bW3 rzQ=dSoPw{Jb吡#@ƍ;lW?|qW85p튳cSn#>o!i+/$ cMPK`3B*^∑Z_q7j]{ gEUY+,/'?S D}};gø 8eĆ\? $#%bJ |B+K -~ ^3╀srDBPR{GgrKΑs*"R $Vk+:WRX+C}wy+v6a)vR4l\Flޗ2[ƽE(=N$SOH()}<覬jI\4ȅiJ1mߑpYtɝTLC`s>08h®ޟw:v(CuNg. 6B:@2,3ˍYU6MdeĶ,:oY*'|dmoWIV59J PӭVeoם;7zǭObqپU"|U.]sfjh5lWRTpѐ:Xx2&_\*F- (D 8HƐĽP-!8_(% )ȯ4jkkQbh„ih|e4%/3c)N*RǘӼ -FkuVs{`USW͸+42߮|m̸m֚2jEڷ߯|/eonݽg_3rnXh603^l۫aJFSot̔9)i2n_9xcN> q55lL^fÙWÛh*z H鉊zEm1=8 = .dRC~i_GƂRf\8ZX'_OP:4 WP,2Gn2}<~#vgeT|kĮ$*{^u( 0 L0ʝ+[IQ65qF+ꮺmamzÀFO)) x ~T@(t"|=uYf0!IZ6%4l;(7ŰkøaIW3pyu;@z%{czj *&٩BI$""EQLɅ۶^PRۭk X)= J1~5:zqe#$Xfƾa:N@`FS~@pR+|ػ;.'O6F='Ǩ&oapD)LuN"z,T LNFA8"~YUZSև! Q065suܟ 0wvUpiE/p= "E+bPYCMp(m`RQ.įO;c//f*[=3ʕELseNagN䟮oQ9߿!S٨m1f6xoYojs1]Vת,Z[U>}?|)8gMj8QW_od:ޟ{_*ؽqIR޸Počo(+[dj7_SM9&+n.YpNjz̒}$<ҩUL3IuƘh&d&dhQLfLSHVBnZ@B^@وN@Kv繁dQC}WTΠOd K>ra+:մN)w`Jd.zLfluR%b[3.$W*3TŝOB.e'U`0=s' Y-F:| }SHaBSRQ5CrskDӉv8%~Yã$A ] lmum%yU~HRQpJ7?vC֏SeD @N2 H3.cKg83J7zFŹ8SK)a1<*ë/)y eX{(2ȻXWՁvAA rQA~8*>rԭ.pF~($@*;Тjћ\ljѥ9#w#Q[ U;Y;8,%H&qEΤl}6ff%VVVyl5_]d5&[\bet]a5^ba'>VloYN].ဉCnqādV#(->)$ژg *n5>HH u`Yyԩ?TY?+J Rz6d U>n _)03cɂL@S@@膒pRY3wa,Z/r;~uEvW+ S'%R썆'H+j{҉#̼t(1ýnF^ M1xEK0_Fܣ#OHR P09P,⇚ٯc !JndʂP& Ѣ*02Eqc^_E-(?Ug1w Jb?OؒWQ8Lڥ$8 K#%7T*Cqu2X0IgANkgD-V_mJKQf%|ęR&+j4w:"KN%O p'jj-"TTN*N\0R'ٮ6Y  RoU5ma3?Jo@JWyM eIn8ʉ*' ܇րdE+H'"~Ii]_ B9ߛ $aY Our2c%H%Mȹ>e;/I*g:yތ[S Zm7qn賚5iHJT]"O{'A2!8;9wCOT{R/k"] oCL"0t"bE>!>4ҔA/-niɜ~KJtΆ*B:]?AMk.C%L`od ]f~0MaҾO?OW>Sjځ Tz!, :e$ O3XB%@Yi k+T'x4a}U>z'k+͕iBҖ>BSF +2p̐,Ufz}*2>"\ tb x<Fo؟L1vv"SYT&-\,ĮuNek[A:["cHԥn0A_ǣ 73f  6 3J$B)~JeyǫP}W̜%iGl†wK.]3Ø`2Ե. ʈbJ{ cFGeÜS$_С놇)"OLG4ڏRw+ˌ,2 7l4E.Dz2TAj؇uo2^h%m1ߺU(X[^NW/,0[޵Lv}/vsYoZl3^ʮ?Uy_6ht.*\ NTq=W+q#1KWwMxChz,g[6T=A ana 9ޠ `o E.V[|%>ϖ%S kV*_`JjTjaQo1w-a1OyP1XvQ֠]Q@GҜ ."[r| E5Ib} y+`U2NMpuՃb7)AbFO"Yf 00 Zrt#{P^4UeMՅ9lqbF x94ѷ\2Bͱ٨pX _s RhK&Z{Zo /bdx_%,sܾƃ}rǿιPv=A;\;9ܚB7)7sp)E@`ov߾8O*>;s3"C4Q/ 2ĿCC8_z{ (_1m>o?*P¼a{Ȧyݧ;?Փ=WT۩u VkKZ#ц{.v=ALz& &ģ|^D}= #AtҘ-J=TcnW H `hB5u5GqtMf|7_f?;jkw3 DljK슖טf7VŏOś͗Ng`mfw޼y~|iGLݏ &q.\ %q}F@H@v*ft.lH՛AM7@ ?*ꍌ[惰g1"pj(.F{_zW5J 9**L]L'8Ө6Үh<4W))?& ޸vNbwGw9hw}}qqvd@ݨ0R>Ãa #TkK]ѭbro$-q[2C*W.w}77b |,x*z跔_jr P(q.T¿`T(7Ԏ%a<R+66r RiG -h~/^n!p9c.w(*7bVg9b'ַjd0@}'{]) ;L䶣 sP]ЩܙB?Ԡd9z B~TRIV5U>fŬ8!ҊU"T޾ E%ҳx!D3JJ;a(Waq#`ǿyHkݳ*/ }lK2bƳVGC:0^^J&-z7tJ &/1ah(mU:\Yi:)[eHGYn^a*0KeiAoHcT7?-e-Aꯜa" 4vf`8%$ ιyok-o-@uR,/KJyi@cpSpl1U3če8lTR:h(. ;:C+0%فw4fڷw1aA1xز6|E:Q_xFxXx-L 4y0R͐L*0 Z`fv#@ B.*P9`|?ԑŽVKgrxS|JZ*0MN5 `*[[Nf@SF!3!vre 3ʈ9dc]R/RwJa!:"i.l 6)/^:(TYZtH|N㚂P!9]I_e}ŀXG}k6UտGxkkXo5FO1uZ]]`_5cm.N݌m5f{ l#z2Xm|їhye썭z|6f#_mj4[UYYfU>[r{R"v@!r T&K;bAPLS- eOްf\iJk1h䏃W-L4% 40FAt#PQ2*+sJkp0;3i I w$,=-(O0C $$FX"#@^$h˝X 6׈G*K4Fna *kB'vacotw5 :J:SD҂j6<-t-Y^(ةQ~K=tݥƆ&3aQÁtFGؠ\jhd_@SXK]Opcӄ]OV6KS|OA*A/rD9mc%P6=L)%?xg  SP(w]DSWfT'F ZGҷ~=tQudVɇԟ2>}L)7@2 Iq/\ rْ#};yTQ&I" oՐ;iW>LO8Wj7_b&!i ]FnG1j%$F}C弼W /E6WCS=>冗P@TFb =7`N,p \mv*\_s EbW/.Mwb 8RKUBy"+9W\Z/1h0v.ك@L~j2or % 6ޣ^h]([ߠIʳ3*kD@ e9*>AR:~6f͕ Vn?ߑ]X4roIXZF5!E2gR`+s8\r5k'id5wRG/1-zrzt^#hbsŦ#mES=d]8:1Lw-\1+,BY`qL#Bj<> gI/=XҀ#~|wBfq]@Aץp&T OEߺۧ$sr}|V@\C?o; ɾ!k,[V',fEòK"v3)Ă_ W+ߢ9P}KF޺ߺ^K ,[)Z@I^<DSaǏA oݱؓ'$u(Е1ܿN{is@޾xaNe |paB˰ԒOș uӭVZi*|=:W>!cږ׀I|."7pp9PXCsNg|ؕ7D(2P'dĚ'h*Mt&қZcc4e+|`s_d|Kw6F}:ɟO%bnQ8ѸCa@7 S(؋4ݓ`b #:<)8[Z'J(%lhhb^`446h#l0Kqr{1];7oǷQ6QaZ@ DgD9a&cyͷ!HBV^X+4mZKxPʱ+Fd"vdgi/w6()4 3ƪBk~nwd0R pz>44Fkxc2FBb*2`hʊSbkk\׃Ccq6aPo   ga";;b$!"R/C d UhvN[Lsn\[+\*V S\:@ϊ@Bbz*ԶDK`0puYе2FsdJ.ûe, 0۶p5` N>l&کp@hGYt9s.w 78k߻pNkΜY"8-&42|2//mÍ oEW»/UT]c(Vvs2$󝭟շF9dgO}e3`1wwЩ]w4~MXxл2& mb+{Ϋ|QT{?BsdDGro˂y\}oݎtI&AA2W#=^d6@/@ɣ Gi\6Sfƪ,tB#^U8 ɤùLEtm3rPjCB 8l!&@0_3\uPs-#U(H 66t1o;PYB?a9 S&p d|Sѹn|=qhNU)UX*L%z} TO'c\.Pc&}raC<푅Q#Cq0}nN`]e%a&n.  pUɋUZ/0-K3w XJT=B(S0'2=`1j>20r{h%m2>8G(T8E .#w޼{&&9Vb>I Npq6npN,z@MG6N+*Ke\$WMl=u>zP-Cz=Bzq ȕ1L?Ծ/PA<̩S} [t0PQw`K8n 63Fg=6s>!txŒjL y,@@MB}$NZRMyI4vM1p )BxޔQ9Jpxb.WRn[ԧZDi x+j;jU.4 sP :4¼Q/h;Ńn`8FPV * C&*p+s3R@ӎFqz10M7QsJF䗱!c<%-[&y+cXX LX h֛O\ߑDR8XRaGiaй:aj]h jWSK"A jѸ *o`tfW qB&ReV䀸yq* XH)F‘FY,Sty0HVQD>!Km9h^fWc|D6P|iOġpX~T9ոI/weJHyhΩĮ+IX[*nfD"2Evh(5*wd(eуΖb .JeEs3v VJ+}}yt"y>s1vp0PhGw| K$ۑnߝ#WQmhpDH'@`i ?>mUy/Ox\2B,݂enHS+u,j d@~O-)OƁӧu;28[!x2 K#ephPFp\jZM%V#*\X'p$Ew{% I70iK0m\8R " Y+͵#hO"(O7vFwL~K agwE{80zdH,O )( @B{HNey]uD{;FoZdu貾f75 gk 5%͑\5J`G4a΁Ț9g+;7bR5X()2L@K_Je4!s g't>5AMUĉKYm'vS =ollR hWN. zs` S;s(h~3ޔ*4P,4&. 4k|pB `IY͜!<{_2cFIT|#Y0Y&ZlMe' G"‘jJ+UYRБ^XA ΐOrrvYˌDW*#~8ѷ೎{Δ沱} ֭gH NuGza(;(+4qA=W:&n$ 4)lf7&saw7=}q K<T*2l87a9 GjU3hR%!&;s7S_kyVpMlSHe I ʮtYd0_.0XFJ3sڹ# R ە=Y1ޭhAж-RcK{ ¿%wJFq;C; y 0&*ςS:Ƶ,3ƥ5-T8hS`b CaO2e[i11=a35;ͦeTy7C)|ԼDyej,IqlJm WMAzO*x7ZY$bB1tK?0R],Uү3JFԻGͰ|F,t~ &;xϩ9pzKP,oޢ7{F0>sݰ ,T ryqm+ ݵ6/+X<v̾HUPB6{VjNxy P5N?h`lsNDĹzN ";WVȃ<;SA|[6ֈH O:7tC)J|HuahHy:*zCT ~b)l(]QzK(^?\F| V6z`XGE y`x@|,5›g4.Rs_.A~KYvn&AH)d󡕮]7%#}Z;ῐ5a~í_q:]ꢙ[|ɜO 0e)/UXBZ 볰d/=ytj2$k'6昩= f*R&Ŋ)zQܗh2&'LAvF|y#X%S{Z(V @u\L"CгFvK^J@:m*[ w<a`3;jFS[0K5&2 D}vkͰHіIh+%e?!9jѣWWM;VF|Ia'26 _-,D柄R-|tu,l/ItЈdtMo\<}ha>>QNN:_҆j){iZdψ$BafFc]JstG7Qi -cx;ڲc#|qP+d.:1})(8JA u6Jw5ZgEO,iM*Lr>q4`%L7 Pk߷?4(eͳ"m=Haz*.J7ƾ\ 2&aȜ,}%Z6$|2[fP5̴/jeJy|j~Z lJeθ+f ]F1H) --^^=ovz'xWrG| ~I֔!%HT*,T(qg,2-İ/蹟 iSL̕0*h3\r2єX/A{}1&Iu]dƝKe /0HGvh9f]adm!'( ThPQEQD:̟'1+jI_V+vޯ|vJ*xȗtl/JB0Y9Y_ǽ.YtK2ZЁUDAC><|zLqiߖT䖷?cΊp!+#8(r/QVl Ms^bX}^$`e,-0{ҷ{_>34N23`|]qK4S-{ˁ;hpr{;3/e;Ty?PگGkS,5 ﰦ78%f%QO|ʚX.2˨W* af |hPY8|X9cxB%#cW6_|L>5.Lry )m|Nbx{sDo'W/_!}wXsiRGpڛ/[KqLu%Ra*$J(lpZ4`k&0}G3 hi9> 4YDDOs{ʼ#. KO>?0,=sGP<_P-,0Okڝϟ0o5*S:zpG@LFdQLCRUfD5$WVHb@ہ$M ް*7F-s?bffM_6_(w埁Lt9g$p]Xdz,ޫh́=2cA>#L,N:Ɋ+2s0~(?3 P/39e<`eUօ%t2k7531/-F,ҝd'SYœ"bb;s>n*o1?'I>0+7W3Aa):k[gzVe!@Mǫa0Wt@F@{l|k<M~3xeG漀#t"[ rjԻҩQ»3D^7ga3cY} C+ ~|?MxR#@Lz@YNhJ&x ;^PCjV]AClS^lt2v7mEcVTkFӨwk\^7x3 7@sp繅#:&|!_. %(w]~+r 9Vt!珏sC w0@yO|}\AWǏqJw[pPNEPH_-J=dWFkGR lD"5k&V,Ȭ u-ի `|;г5e/o;^2NN|3-AJs-jPBQxrgj/bw,#n y:ZZU"A>&s8PU1r(z oEFG/9Y InIXOX/7kJ,Gσaqf[5oH/{1*wyNN9nq}zq;"7| P7"A0^c+T w[w'fפ/ u_L )&s{p|7PCc`_|Ґ͆I6tϠ!;ūFVODd"e~ DsjRj (L'Tlp[:ZN$ܶ ɾ PCkyD䕙*Đ1QzEZ{_9I.ch_;DE)@&@F~ON'2(b%*`$ ~w|1F~>)H-J8fט]kJ*1F/ZW|ߺE(p >SwZ Ӈu@W8tޗCM*Ř/xPL:pSd[ S{@+HM.IT8Tᅣ=}Yh\ `y޵owť?k.vk%~R '4R6M\ErTzn N,yf66z.ERBU6콚1Ctݽq~CcW<>O~+={R/gj߀LnK,0~E1?szt 3߉RubO&x\y\/}'֠j<5Zƙ'ja-Ad0tKY&z~iTs,kP ! %gI@`}[R4 n&75!bEɃU,/Kvx5YnVnŸc.`+:?o1yj\B戣(ߑxy(p9㟣{Akl)JۧأC<߉e>yq3A&pGyCz"m^o`7JC!zQ^@?*^vr _›]1-$C\KՋ&LRت#OK;VۊXjԬeZL$X̧[sHPϹ(;L И,~=ypC3 4wkS?hՏ()"k 08]VԱWRS)HB##`0t]Z%T"H 5;W;ֹ=kj >B -~M%}R@f[T/ޏKޕF Qz!Ό?@-i]/c _ѕ[j??e3Zk4Z++Օ5Ҭ}ϴ(2$};?9t0W3*]}Až47 To0ia(e8XݕAl* K3 ׺d=-5,d?zNeXyZ)LlU /" ȄוiYr2v eJY3# YMƈ.*͹Tx1  NZEn<#ҥǰ4yۃ7;o_cwu2+cQ%#M9)2efZDz[_} \ b::^{)B;_+tXQco_Suݻ{b @Ǘ"uTS;Ei]_,q4,Ke08(kLhU"g^9i-[TK[Q;BMgg̢h=;tq@ǀaC1NKE5 (?-fA%ccEGc7G%] QF9qqѨSϪ:="$DdX5N.JEmnLN8)BR|?R*)...k b'e!$o&ܾJFe؀U* +mttr|ʩIzuj8 ;*0h^= z GLuF&C y}oћ44?@QQrNxrJP:נf C#4 &PgDbo4[a5sc|H2GGƗ֭NA#J3U뗲Ը׭䔔NI~we|N穄ܒUmOP(_ЖߘsX ȑPT"'C_#./t˗{xc.ԠB죅-q³s88p!mJ׶:n1Ү}\ 5l79pcl:VnZzlP8O|Bb#;W܁Ñ0}?s@aa}A r|'{Α?Ei"J_y FPP@>LSQcP$)a<*c򴼌%5Ҫ%ըv sll0oݕy0(kxFq@|`sJ4z[&%){wd5mpI d U?؀/|fKWӰr _4tJI! (Uޥ|3BUD #C 1J IUƑ1 ӎ]O4|ILHHGH^lGYf^ Dǃ䑔^_vh1LT;6ZB]4&!4vm]#/b?Qq97ZFZf{M?WWK%k  48o`p#}%TCېI;4`vdܣ$e8Q ]PBh?k#|r0` d]~yoXJF)kZ"Jn;ת_'45w0sr:1K9G9GZYςFnA&`T̀0Zx/cN~CrlcGĕn"xY {!tp:a~ ꊥֆ stj :A0H]zVMÚvpn>u';U3"0 Ț>  JKӚ1Y*& ÷A8Q<*>%espI.p)չ{ r* l7Z9lɦ7M &A鉟)=bӖH0k HQ6MB*{ĝEXjt󰡖G2(pVܡzCa2Y[TJF6;Yx4{ ܝ0xOF@dlLW@`f`hI1wmg܈CLƌv,u1D{= *)Rw<'-{{SmN^$B#`W@o`8#<4IB?Emk[@1 %ASgQ+Ѩ(8Uʢ]±E`BW:TJh%aPբQ~X)JqdЗcيc\BN]t=.\@f>mOY@SP cJ#VuE3K1`oC]a .$CMDYؑ]HU ( S- %8[XO  j&:GY͓̓C3jÞ{܉ʙqTzPY4G>o˶```c޾D .~vk ?zkzN};ls){EdVGz+y xkr60.)MݔՔ]5BOV_|TXjڏڍzs^ͩ\כNW`()]4!s6o6̗ݕMhiiX\֬?zl֣OƷ#Ѣp8>u(b0_ _yLJ\I gXM˹ H{&v|=+m(6 f|j2th4v(gВN}|e6b6;4DEjӐ6wԞӛg-!O]FF?kX 2֒ #%39A]rP,/צ-oa/[o8s,l2XAȬ~P2cl*҄Ӱ,fW=eÕDNa;dh'&~6fFv}[OG@O4f!?ṿE|MeHa2I3p4!SQQsfЌ_Co0 yA4 1e uYerL,.f=m+ }|;(T*QHÌ STLFQ2'ꫵ*#kv3]lꈯ& )/Js/kÿ8[\1+Д;;HH !9A>x,rYأq$5UtsiGce-E.*o"yD0:i)`߆#02߫J\=N"!a6f2ONj$T/lj$ZeaӔDm_GvU8e|cOއƅ*2Ř{unj?vLh}  - _+lV_CI#O6V]'E6C''EN*-SR3Tt$E\,.=9E Ƌ[~XFwH|OQ :JBeIE& b.^`$X1+;G@I($"2JRWB %\%kv];c8.3JcIa8E _⯹a~"{' e(U HnF=hkNć" K>F CScaX'x@N"z&ȅ!YKlO7 xd] T\ mN V@N,zF\X+( -V:G]K|(QHSԆP 0`RLQi Y@wj?[$&3{m[fn51s{M*{aNNIn#If_J(X;K('Rv0d7N-;v.ӭEeNd%d9J ,J%HjI YVJ5a1xp#f 3x񈰈wOrO 2>V=1VxO\q P6Z92Ƙhɳ7zpkF=A_N H;= EtAg 3[>K0Z#UZ#UMod*Ɂ)Jz-, >Qoi>/?FWcMQxtvd85`ƋK4M<^6I EQtTYZ4꫅o%A 7-N5n‡Z=l'|\:t"0vvY>9c Fsmj4@o'b.ʸVW 5Nfe V~ϲwcEwfP)I/~'g<huNY"iՓ4Wt9a8s?:W`Nh"/~5)_'\4f_]m(Zַ__3?hq?nayhY{y W9_#^ԯ&EiNzv`o6}YWV`ȔKM?f8տ_sFcѮSfWGchA' جd3ry&1س+ڟEuepĒU&CD+0qixoS.OI8q-ol K{0-ަD辚}Sga (GfgNYGI(kv8$5 5Bw^mĪ"uL]ҥ C ?s XG%āлqAld1gNSy>)?f|GeǏ)oaIJ/w6_[ .70UksgpQ\8c2Lyיv7lt7J 'k=#q|34,g,8hk8G?KT\LBı}4QzZquBf_:>UtRԳ| 99[ίu,.߮?[A.SgE›A ;&~̘l f̢;*L'mahToAIaޙ2lƓ?(JFnx+RoҌb w:ׁC/=~Wp "h9ʢTօ2lX 1Ze].tEp*L,W\b(g2)#,brHp!pMQs**5"m!"ZÈfX I6V7&@^,g93Q㴏yߛo@i7O+򟪣0bsnH9|3B.~šG?d) ~I?Ms-nAE:OkAvjx~OLp r%ϒ۫mmh?&OB~gCnϜOIzdnύ句Z\esuDKb ,.':Ps g[Ba&SxI}>Ag"- 0Q@P-vaYDv^锤Fevnbhx0x9.kۿ]hUR&en5Ogl5+Gɡ_Z>z0 |?|⯡m ;Jx00o]e&@]ŏ6`{[,ޡT/U?طWM3 ܇_bۯ׈F#-B8lOs \]/SO[XOjר^ǭ{W[9cebktwqyBa%2^ *&xJfLhSWag9/mK ѱ/G m3ٕ ޙ3v&2FtEdghPiV!xc6qJ~Oz^^ѹ|Xܐ1 {,Zv(g31gAf UB~vfbmYh#>=X@ -L߱s9^25v7Hp|W-ա %ߠؔ3tyYoN9b"fg͎8u؃qv_?y/xг\.čҖw®]Q[/?˝ݷ/ۋWݽgP W^WoBwE_o|u1 ߂Osv@^sR] G/~,;4|**=̾d0FS ǔ=u{ FW xݒPf d$]R v|@w;3fɷy@ܳ7ADj'x0k@Nl]+ږG$_fg/ka`^qzenoFx/eԐQɈ%ZڕטjEe\NeW DCJl:VpplJrR)Y uSIذU[~|bGFO0SC+Q4bԫP Acx8r224K9 [Ľ"m.[ܟ0aT\%HgKx+rx' K? P2NWxm~<Bt>lG8SƂ.W7Λ<8 ?E(曭/6m C.t8MKU%uƿ'Pww0lb+ 'DlD^sH 2j ra)_B,4)Ĝh\;<{;^/D?wo߽+ˁ|6.a3z[l͎;x92= Q~P [/6}3_r+ #1es[$ 4A^x3A$2& ASmw. J(zS L|Bٯmq>y#vPMe:Șms7v_wzh0o<~1K#Nd;Y7i?ru"*qh1U*Ѽ9կt~N 4e|jCěěW{U7PG. 2:٩bO^pov=} @ٙ0vGkP4%þ<Ə=?=xs^ZוݙkPDLmc <|0 +_|g2r~fFu,5D7ɧ'q~?j-QW2tB~"*i,h6ȇ"P =:QUęQ\HIL9ϓ.B%ϝkɖX>+3WnF9brVPR%\T n&ÅR; p:VC\X6E,~gP|>`I'n6طMf)TM "gzQ1Hɜ h 7nHC=?lSC{Os.3}a/b)67ɏ2?0*؞Z9m^0j"H kM"H^r3%ź~6VA3"NIJ-ɟE?mcho D|nU#qE}̮b{FZgn_4aGW2_&G}ڢ+E%%8>IW7 IHxQ[x |nv]$;O|m J_yMw@N~i&XQe60JZ$!5db]JMY?. Dq?P*@6:ϥm,-ng+8Br.~<6F|a+W.wR͉gH `$J,  vRF_[흝Ch:S[.735T6![5N]^jƴgVcԔMƥ3ۜ1ǝ-*Ӈ޴Qh+f\5A F7OhR5Os}MܗQ?e٨9sn<}#Qj(szD5гP٬v~axz׮PE{Rιh~3-S`J AVSVnD"a$Q<-mD8P-}!KE(EUolohBgecP4I>?^<)-,W]׮m'a;l6G{j_C4 }Aפǿ<.H\7g_s E yiQ$($"KyGNC#[YGGo||ك ؁ߗ7etQP-ϪPRϏ|49FIѷ'?݇ #?wiU( @w ^.tS2aBnҡZ1@\uqށ)&2$4-0˭}=A5Xk]@Zj3.,񵍸Һ}Զk]Mh [ jnТg?.`jhLY{ 3>gK} ]Z2K'|mhɰv_8hpt/^lګR_J2׵ŧP"MUܓxԤ[oqa0&=0?X|;DBX'$dq\?ߧE0N¦WhZ 17q,H*M"kQFZ3A<02msl߰5qcCMmC ~='O O`m%a|.PA'2KNHٔdBޕp$P%FS@C̈xLi#/L3U'F,y w"f.,SuaxN2~8m,X -N_D_l %EL.8gXTE2eu6(C в ADmh"Lݾă;{mwbXt`f`JpoX1%xgk؅jZqek=(\v]d@<>*fPvOc:+pY,wPF+/IC΁v*q:ud(屠K9Dfl,X=T& Xz$`!AU<%okr unDz_]%$g+mYC\X-C2&8ytQ(VyK Obˠ0S w]_ S\nbqsH8\MJ܍#!f<"A.ss٘PdGdtj;-mq`5{;\/:͹О1iW>jSf>?P'|'H?̔y /$ꦸ|RCYoƴhʈk]YpipJ?`L>OΈרu^k -h^UUFmy߾E@*ZEK7ﺼ?\(jl> ʨ$UvU4n*'xWFu\Y=qzV[aΑz oO^zoV}!C47|/3vOibg3#{ڏ[ L`g`t˝/v7OdrҩOw`m,V +>R+G( 4񁿃?1Pnwvya8v84=\zB7b*ύʻp=uL^Z.[Spa~ê?٨ |l_yGoP#(+sZkJ;ɮfˠ*s/2A? D;q0V0huߊx҇@,Z\$tͩ5@؄zXvV{ X@7F> /N1+gK!?MX]C__uxZi}}O,GZϥG'zdh!Y6gg@È6.,L\T**#90Ľxlc,zFO`ke 7cr:=o)SS 4ĢT~羍MuIL08B~5 Ib(\RPIF9(<?V&noPAܜK n՝ 7㠓Ov\ih8>3t%}Fs^#]Cۗn,MZA0bfߏ쯝>t P$Q$_;`144vBԦh&vbP$06qZ8 l|QgԃbҴXôhpM+P-[?݀s*3& [ě+ZH߮&sU(C tˣ[ ~sܻd/ Lz6q9-aҩa, iIpoDЛ-htNv˭4VWH{;=nJ͈qElh^jKrB ?oswHHKwHevJy @P$-.P`pt Νg6oO#5eb1%`~Ȑc!NȺ4ǖp8dIYw޼Cp2+s1iarӾyIfX N^;LU7!-lui[Swd{B! fD1޳0Tp#gdq0"G}"!y')[E% }1W8> :u1o(ޟR֭$ P`S ;V LebT75ʅ&vLF#ד 3aoSMp o@&N-E~'h1x'~@`Pº3z\)o9^FGQUkKhw79mug^9ǔW2RHIqXd& UE!TI4pw*t1̏BJ|_⸭&*A1Q5jʺB|tD =h> SI| c-]X'=BаQPuP!7#8ۉvyBi0X28^-*C8vS )c- a虥wH֫o_I1{NGt07B%1ĉZ"r> H+;+.jT?X~͜{xyĘ$c163y\LHqWR"  ! 1|V"HZR|!Ao$YsJӭ$GNwNiPHZLFSB, W %L!t/b(uEb`^ fbĕi`U=[0X(@.LRoBз˓sߺ-cov_?: UmBR%4u̷ ~}]`i:i(=$d* av̷ ~ uXCQPuVu̷ ~ uzkcm[NYgMvgl:k\8p¢NDY3(lN G"Gi922ՔiV\:;zuot阅D;RLdH wl)$s6ZEͽcاy( '~gk{O)y,yK%e J!9@v‹[ "D)pbp ?i#C} 0~"c"2SOaX<^,/:Y%V,OYIYUb?mXܔkR˯'#/pigQ|rqP3j7Ɋ&̊c0q` E.&.Xs ePMj|e3C/O>R)-GdM:!$M:EO"t8N8Lʩ:RH)ؒUIQr$p MRjJM:ka=|֥N7뙓&OICVfȗd ,EC%+"`VZX?TL"LO=Qu 'Ih)al!Rsfѳ lhscN`0;Kj*#2l||QZ}܉Je~1<5{|KcrAj̄+)Lυ"5u򹏔kFi Ȫ\HV(@"E6EA)' K0 R)A >ֺ F:"EhEAr RFEUH?N10~-?: RB?6H@1lL=Iv_=oNMKآrHeHFPA_Y{]eTQǿFp S9y9x.HpbF懩l(BM~1|)h! +6oh|4v*Js+!ٗpz0El/w:nmÔ^hފq)^#IM(Dw"C R>SJ5Be0Q<^PIX:TlTFDQa*4?q! _jg R3kE Qyr,<4(=xVY/a:i1MpNW;o޼zqhj!hLRU [1ΥG4R Q[>G~a5*59NQ0R#:ǏeWQQqDSÇ5c9J5fK2[' uO1R!EVן)eUM4Rӿ@,jI$IS$R9EMݝ.jT Ii%x@Jw}JY|RxXRFtr'C!( ?w(4dA8 ЍCq:F +4SbxH$b^zjfl/'#T6PtBh!Y\R?21q~Q:tfŬȄ/HES7y 8h* k2|xo .KMCb2ܒ6T DlAfЪBYqMJF0{9OL L7Qcr01#ʆ`dr Ud;){CRD@cof`yvHjߓE ʆ6ᯇ5*jFe)u;kJ*Rwh>.RdPPՓu jiulP.R|EĆLt8"‚j-Ϟ2n^ ᇽ\3pCX(\^{'O4;m$7a [;.SI2ؔ/^ֽo;ۻo_E$~J?>䂳*/suʮ{nE.צT6aGl}Q?2սwxRZ6fWlsYw~V7o'%d^>Dlt˱d0}'# / NmΎRP+bXj6jQ/*b,\D=B "jq%bQIV-ЪYʣjaoWJ5Z#X q lv|\:Cjی'xxiwTO~@-`lܢ|ZaX Va@^ wTȎ|QS\/VM%ƣ,{3p%Ji? W~4Wƿ4Zk𩯮j,~''P 9]~?QG8o8 ΃Z^ܙڤy,F?i>|JF@pdr_`,xJ04B0âMea =cei{KsHPK8fDZP@ =h"a9̑YQC3 85e Q]'FFYY x 9r.Gyʳ`8,O̱ˡ,[Y:.ʒRb17̆@}J`r_z{. cbΜ2oB8jwCL"y-աcĪC|5 ]\9Xzy\` ?rt]C[ϱ~[A%xAo?N#"!(/2(Xr(JaI>y;JKʕ*vb+& <8kqR ].$!dDa WEu8w*G}⃣*3+1Q On#=--Z5E!Wdz@.JGps˚_|? ,eᾳ(]ILN hJáK$y h7 򷰽ٛ- ְ۳NK7t0A9? =웑<ϋpjp)bΛ79(F"o^+FrNLc95 RVP˅`Иk=iB:::F) ʌ8(&Vd+uQ'ȕgsAl 5SSAn8MhxC6_D9S|uٽ`S_FqcOjqG@n_+]/a8Bx!_Z(tfZR6ģxeiLݗ[b J x,Kb ph-c: ޗ/W8_!+Wa֭nhzsNz&,$ ěOSY*ъ&ŵ_nsTՈD.ް.'*wJ!EQצ;4u~ dYX R Ƥ{}#0Un.^73 ~NNeAB&4ȓRif%Op Ep |'r|Dt-iɓ%5"I#"J"H?$r V$r !XɼFs*i,q OS4Dz.#ޅ8, f)É(30=M\e^ˉ- ߌ Z4\ d YCaZ/B>S.jg6ܯ= 4dnG4N|?j <1EY\Q\*_{0*e M<%گׂSR][× 2+h=yUUCLGF.2ٓ3)"4,e \io0SoBq]i8\HK]k%('ygqRH! NAnUy,d_A$y^D <t@Z ԱȣR d cϰV1cnIxwi{xS/'WzLVӨ}L|X!~P"h i̖ $ qxt!IYjf%e ڐՎ9tqN+.팡bG檃 u voYI2X+uK"gj^Z^F`][W5mٖOaT:F7˷v|m[%Uf!E9Q@% -VIE@rjBk+-dwqg*+Knz+W6ECQ!u5龋? OEidQt1[N3ztEd[Pr.r]qDf&l0TɆZ@#dB-bjS>™}Q~16L'fÔ@[lm'f כ+k\[k[ xn4O,X NkhJL8bTt_$~_l[`Pa; RwYod9vpuFfajl$s|㈑JxW%`,Zc~ÏSh{w"/`7wGG LXP53d;X_Kb+4W.-#KErK.tRK-4J8$Xjp0ƞ/ZTŦC%& 衕;~$ !t,]5ةJnf2fSQ7t r=/1/艱z=A+F#{&ٲg6o4VZh5ZfUX[v3ܿț, 7p7y@ൖGP<@jW%}a't\k}mU|5oRztPJCkeA7)Pe aZKޒٴE8Vig M1MF2FT5m @Lz=wi#A 4 -P2:aBg ;gg6!29ɻl ,MFU};@2{i\xA]پsD~q2BtʅMơIjJhhan5H̥AS/ Za%{[7\VZv ÖU$jrOQʖl(_ZO(>F%Kl]enjI`9-/al5aj:8k>Έchg  1jhg5)ͤk5 lajYhVwrR]sq l뫨!Ί==ywFٌwR!=ztUd LDs;Ezb0;7^v` @=ѳ gaY,\"SXBqbk?nDcM w2&)ҁA0\kpbt(R[GkAm^jb{q6%Fp<s*b_ڷ4j[.?b8t BMnbFWބ޳\v06< =g0:BqpgĎ IålY_0{FHPBd'jn "h͗_D6Nu<=S؟K<Ύ|*)Oc(&\г4[vV>?& `Do|>zξA&QцXĻ<n!-.72R Я}aHz琸"WऩؾfKJ? no5r+7 WZFԳ+:9]J?WR3>$J"(A.桱+ߖ+4OK]_˷XqvKvwkus;uVlhhc>:JEl -$pگV1#ZKEG/&?[,CKm c7ˁE6[q, @((MY_7EBf@E2%:v= & XCV_}\EACh.{jx%QYk2gIAm>[&Z[`D5ݥ+?Iw,U{StUoe~+Dx)oW.ۣa+'yTXu2.WIA2Rfd4J~j+hNZId e'\28s2w2:fpPb~U9Z6CE(RMrG=k;;ޛ\En &UzX%PTVrM]`rq)Jt0%#wicOBFMlf>/;c;)O',O~j5zZ` ٳG94χ q^ a:>:dݼ$yeNQOa:)ڟ_Mڒ^bCB7EA_>  a2#tFxҲ*ACkrPFD/6EX2%61 ac;}F#ȈDJѨ" iL'x9 jіm81Wn}~lg@_~1|yw _&x" ,ۮjb׹ z ܙ 's%у^Rx %[Pe84> ȁ )*u,pXvsrOĕOJ=/{0ÙD{=~}Uc_c=O9f]j;H-vՇDBp 'E]7 hzH*m0. ,MpQ:C cJU# ͆p$o:GF&Nuϡ xp uoQH2mr}sYřt}&Fst,~Vq3 'ĉLa`$;[ xqp?$"u~ӷΗ)`eOx!)$^PAf6rd?\߅N6r]ѽ ܡU GNW !eCF4\R# ;.aFkQ ;bjRBx EK *ɸ*Iq:@ 4CdRVU%aVF6*GǠqĔ+r]6a&bƴy0 )m0=܊Hzu̞x8xȭ h yJ-0xa2K&A 4]zwES,Kg:,E+ {;B+u"L9ejZLwŎ9 N.&c4y{ߺ ^zck#rʼ&6lyv8MLirƐVع*?<rq8J|Ln?-=gh[]NxRmVϨdv0F;{IJjStF2/ / gT8]B"{}:iEv2>霌RU3dgT:dQ=GZS vl/ě-g ύ6 Ȭp@A8_,ߕ'$;wۭz%z9dѨz2V+3 (r+]qF~z8m?YZ9tX GtP{6$Q"]$АMrC P 16(@$-_a/VU)nʌ̌;r~_xa4<`|*A3멘]eW<"y>{nȭcЅU.p0=gt`J8Bwմ%2qkro2cUۆA\RuV]∊4/5 IMQTR|$i NiZx}|V^"E{SAV=x`l7DzcǦ+oXڎ 23طcxcN ljT ?'56~-[y߫'/K^7&B{R皇ZCtn l~@kbz->Iyo.*zu'_몸C֫7c -Q!7q2~hhݐw T @&3fx_ PT\Z֙O ]ςO5̣rY*0Ԁ%|b *<$;⏑#}i.6Z178OmeTmAyyxMd\p [":k:BPŌeG,#Ir?KDS/UlmMqT +ГDPĮAio9;\]Y}0^IrrL\ }-EXTfM/;!9jr,ux>xqPf!ڼ܆=N Uy[9Ѣe1;Y/f~@r. κ1R>/Znp,iσɐ4d5xKC!|%{W5N Y$u-wK 'T.g; _(IG6pq3)';[Zm}c>+qƥ 1/lTKj}S{In/s/[U]̣c\K$)Id֞‡Dȁ&h)4F%@o 5x 8z8X<0 5fStg0(lro4 n7t xx`\ %r{^r7v0s.;YBzl6&C*$2ыt%UVF-zAz}NT{EfLaϺ_fiօ+*> lzz!ת8 Pc^24Uwʼ|i<8l7dǯ( J3HX(z0xnYC ̗ 'm `pT:z:XKQ~k2du݀U&0нQ2T<>i'!ڶ#!^|M~(&{.Ϣ;A @p'qܙ]'#' qߥGasqWn v˛5ݢDT[LxǗ )ܒ1=9ث<k f:9_3<(+֔%a[<(X7K^^]k}2,<Cr,]aJT6/>z]3t -jt78cGn/9V3Cq¯W ߛ൉}}>Z/V*ugTX? SDrP!v=Il`&hʗ#_#5ƻSp˛ah*$5'|{<$FQ|}6+{$a~P|k{!Ƕrá_uS, h][پz2>EHE$NlAY6*I7I[r+-? OkO7617Z:ewִ1wo*B{k\܄Ƹ d1JC?=̾ƁĄà(fefc!",&]H!P@:F.п%3{?ovѡ|/`X#-`ȵvcwڽH&&gɘo:b_{Lݨi)tBgk`/K$&y髓6ơGٷe1D"[Y\p1o8;giGN,qҋP 䆵ZfWp'3QZN?hR" ܫʧ!9=sf˟@sgE?Jm1@nc6o]ZP=0[v-AɪB9ˣӐiq@ճk2կL8 BrhIiHM)Z)@Li?xnuQQ,3bB)Vvx𡪄1NlXcv񃣓gýGZ-hwgXNE0j^J@v𤰴 'Ү feGxA5WΩXoLu+Zxx] Qo0jhjJU$uhRw5Y9fS~A':[ t%<:l N̑:Fthw@Xv;ꌺpU[[[&GsܱB;3[.X;#N=.7"lQ=}$>?q0d ']hCs%O9`^ @7BvEˣ=P{*;iBWzp &3 n蠉NU6cH''vσg'ar)> [77ꛍz 6k_u$h0Ӡ]Gћfz>_,*JAtFnxS7}7QBO8yCbW2eJ׋QFԫE= >QiῡMM߳ksa35ph5bML %Bgsf~=ڝv95,q?>8?574ty t!lwU>.5UkHvK $Sn 2S;ir[ x 򕻪 gsKH1QJݡ.ڣ19?߯LjoRCyĎR)R%7V~ @W Tܨmjh/Vī #s;@}'opΛBBGGpoĩ:ªXH-(b}/QPRf^ۄI3-5x6 yy)s.:]CJI`19u+*`_R/&1l\pj @ݞ?脻`pЧ}{}`''/N,HbPIW9t2%ͺ*jt‰D.Z[s"&0>71|r9JbMZ]7 ^yr?yxNNCg5~YLBgz AۖaG0x\WjHV-4 I#b' t lw(~0O>.9b`fNQnس81HL9| m Ⱦ*# ѱmi&% ƶnkT XŌƯ $tT:7ٷJ~ 2HcD ;2ĕi4Z6chLa2S̃)ԹS_O'RJ.4N])SQBsF-L2wfgh^ef XcE-WLbgF'YEI&9lI&ҢG{ԦBep,7ȝ.b9MG4<0[2PJgZL+1NhɹD4ӺڏGx>-֝OoŔ|BopsIh|.S4<ʉNj|kyr0RSauT2? ֽr,R𮱵mE{'@gp Z. /m@e5aIE]-f焋.mYGNԢfIVm2]dSفwzrݕe+p^6C ˒VN bv\PM3{vGKQ4*Ԙ3pFѥ٪302ii3Sa?~u~{S 'agqczLJc"$ܰ4SB7C@-rL.*I:J6`B<)h={ "-f;%^, ( Sey%14Uٽ*΃M_+gwq!&ZP֋09лޟ9 !mBSly+g UWы+r;[,!?{JY o1#.IHWsb [LF̅ދ}xϐj: 4VK4-%h~L?SS6;e 'EvMRCxӋݧ%ޖ\+qI8xl3Y9Β%uʠ@ܶ~XCsFCWp=;l]ɿ/qLTln#Ɓb촠'fTYIJdJI?sѴa*V+Y\Gw|蔙cըS$՛HH$Y&06pk6[LWY$<+`R9j=XZ C4jgF7ꜜ6j$B#X O<;V}nnβ/Ëahs #X=ܒ @;$8<٠ *U+[JoG`Wt8't~5[y.,s!7x[̓h$x%@9:3ƄQe7pAcλ`<8ǣluD#ں4zz>Ff~ou:'Z4V=i mTB7&eQh4 NۡGaN( LΔ# :uAڃI;&١&䈐 h~A_QdU "ԡ^4OwGZx_<-oBZ!=YXr̕nFh&BTO p*J0@[av"~ H*ǽ ߨ&f^Ynw,{7״1qЧ j bFW)͚nLL3]x'ڎ:|"M.է:X" LmCb.&hZ5ϸ/&Xȹo)~>dO:C5L D#?'VyZ#䥚L̓`~jDlHS$+5Vn5@gZ3j=>(jeyEDs FAxtS CjNR@@^S,@ʎ-VN+{ CMcлjQa#5j|G>}˛t06I #']Xl0K;,Rl&Ϭا=- VPK?moqr"3/oC۱ K+ ּ~4eQ/QB0ns@ard5 TFEKpow>yK$c76Pà"hF>: u`3นlj9H, SLSg!8#W`ژ9q$UH[uL~*x=cjlMW#3|LmMspv8OulU;G_2sg{h3@J;-Z9l~kκ8n#@ү YLIwhtsZ!MY,kQ#~D-|{.8ii qbUcC2߀UXu{JڼZ}@UX`l=Z qXJ0mb6ψϲ`~ۓݩ7ta4bнNv4T~98դ,8D?)7"$x`Jn2B3R}NhrgL_=QgTTEAգ]CH~=^Hyz͡M'hמuIP̥t G߭ST<,#BdrȏEFk3`t&P+FW.v3?Pi [kgh$$gހx6Q2웈l#sMZ`튲dbB#c+)j? 53my5߅_TC':[(Q'TP Xt >'.0{[Zh7H@j5SyLk ,`@}7D62ՓWsJ'BK {rqkjܡ:A$=U ߔr,2Bm3rɯ4\tA#4m'tgf->9QQ#r2`ű.;:# !nWGX:S& Ak΄2l/%n̠]X`Fc #nޑzOlZRc.$;J 6ZՋ@l>do,B[-=w鑑~Ź"Lg8Y 0hDʍqR8LXNgeJW.}kEU=-@Ah/Ok-t`ƒ'٤K`g ;(/`hU3F0_GZB:vuJ-]֓P:")j[qyAR2nw׿Beʻ|2Y_t|xM*P{ϸYTv!F⼌oGqPTHB#`Zu/q#۔5I*-XҏG'8P޳Վ.FK6]OOӄv& %)` klm kHI# )!Xykagmy1'v":v;=c뺯q_% \@HKa1Xt;s׳{y 'A#i,?z\~:'/gn, O9㥈!R3hɄhꡎ7YRFb-Rqy+vDb3"h)P FzNN$IR]T[2l^24u-IoejLC Yr#T:)KZVi˃sFtFR|O|>VƼ8<(etX4(l .eRo'X3EnEx|YE |ם:3U&j~ S>v V#] vt'tJݵd1hQpk(gУަ!hκ-NUbg_wו[3*n1r~PWq Ayw:5G^]tt#S4?pȫ9 -Bz3kQ]oMˋl8yƛ~w Oۛm#vla?(Ӭ~[}UFz8_}| 񲍸hCꔈRA$꿘HX/lx FvsQэhMEaLx)r]8܃<0OK"Nc&pqsdNf!y0s*|㨗woL6T;:0h*802J*l)_.{/ kÀvP0BG6,N:=J¼E|NJ4}E^8_ʢ4$#2G Y<0C(Ÿ~X(w;Kr RT7;Q|荶^b"coo?;>zqnXRo7zX,:UTqMV瓪ש5*(&h t١8!)֙1E|g6tCu J` ɋdItE=:ZڱzІ2R瓥qiSk|E!C:X|f^dt[ڬ?e]xM?ʀ`lt,Vl%.KP1q!D'HD߻ 9]|$+UT"[!f'3r]JBI,jN:gOSrhM1s|I݁'=ZUlk{ҟN<ϡ hH|0q{,qO+,Srj;^OɢhmdO<| |;J2_z%".9[KM*943LɁLSݐJx(!5ȵ࿜!RYV!Gk"]fm]OUřtLha TmQX7zbD ?39ׅ2v@/ON)Y4 @9ҧz75p/߬ x;B+>q|DGD6'BeЙ%K3WS?;m%̪[doe:6( l>7H!z^AHμc:liStKL4L)G7 hVLC,^S[}t;{>sT$"p0pOE3wgԪ}?IoVO\b9e/F6g8E T4ίK$z[ND 9I7g"yuݦ~ ;SZq?}+;ݵtN{?#QE9| K;BZOR4%E(lz9 t׸O«Qg업`(%yEI,X_ea^b䈖'-?Fh<_|,3 0,@ uNA w :D>zKj.~T@Q1f(0 bnRX<fYYJZFT)x2[{N_Nר,3`gQ4.φ7ƫoE8J0]ksl) $؎;;AY4`j$A^ށͣ|r_9:E1@9Sjt)x,%c@aQ°0d»y/I5m {ʈbv/wqhmʊh$+|K㡨Ј&`Az10$n/쒢HIS4 Ed,VSw-H庝Uh4(IK.*0qfHэ#)WdEgǷWQވTP)T!2j>y13*9 DV!U}0bhx/*#b!]-c\J .+)ƨ8Is1Ş%``Md8,;3䏧|dLx&U#5<$Q;P^2Bv{-n+2ݧ?y:8|vd26H6Wnu pfjFؗ]3:L `.ΰ $+$ 9$&'vNHZJ&Cxb79s EPB^/f]دk X.a}ı#J\,0;563 p:JP&ͧ b2B\Տ0jpW<ڪxД9I@K,(֜O8|!Q F \ż[R C;k h,IIR ђu SyYcmuZ *ڂUaf ffOTw;SZ >c2!+p,f^U lY`%&2Mldv*uzsc5uLHBl,@Az]YEdNEgiǸdvR 0^"_^`a؞I)ǀpHYivJ62+%c96H+HѢ z %; Gl΢ಃbf腏`)jc'>(ᗷQ4pNw@kS=.DJ`gF g[BkL6;,":_ypb;™&+i;|`돪ZcdS_sDDNWՙgaLovzFxҔ#(-t#ցQʎ KײzS$w+Ebyrpo#=3g6Bt&ExaXw ٗiDB"\KBI00tDzmS5zPZsZeeGr}3dV(^&>uMxR0a%T9 EJS.!.= oV1I4`Y)p i&+3"jJfbc' 䣮>`Цժ$ysr+#1 thgLa|>(q-@:W"AnYFK)H`KYڱil9'6|茫y~0µPdCjy5/@}SS[ >νe'^+,P٫SV;? ?CAWMpLUPh6^3ogσ{ 9L>lR泯F)"sϐ]fĎ9}s ִB(ޞ_wp E,ӕy&Z|80{з9FdÌ99cYQߟv*˙]# ۓ",hMK[a32Lʏ=ph(gЬ+g _kͽH/XW@:_uMxvKr ;0Y 8h2Ug4a<䠡 XІʆ0NLv(s9|$xg eQ YlyPŗgmkjs|ӉJ4:yh|Ė .|咛o "iupFe[%j;.'>J> f o;EȒ`*C:,V e&qBkUul,I+C4No翅>ћ* yf5Ո+z_@UD&ȂW2F9+RȢ?Pvs"Gq4I<"BCcS}M>31^K";U~^JI:lհ~ߘԶùk6:DCwOa5F>b5m9UWs$rݜPwE,h^ (H$wpo -2fFWә.\V7HMSw~ A]b'&%#NI+kwr1(][ _8IZ{Y Xx‡66Wާ 5bܿD u@!29߫3Ў ʃtʿo])M%_sC y'T*'4BiKNKYM fcwIߊ(g֚ jcX48amF!m,Y ) F:N*T w{閶tF%#:FB[N9#oE-T=KDzݲNJ}NpqO2ɁK9jkZ$[g pjh8"ʅLS}WOkak 0IV*[`.s?|%Zu{C a)؏ mN,~i.weQU'-Me>h'9ޥ,:AeuL,ċ7M^JqdY#r< 5@1G6 &e5ݢk0%O.zw$ [BK5vhT%wP,XBk &OV4dFpeǼlP0Q:ΠPcPJeݩ~o2x -Ⱥ3A{2}^$7E} m 0o-e6 UN&OofZSHo?xǥor3D<*d̾Z >{ ZcNEe2f7@sW5Xs:s 0"pǻCèWImvUݲjCGR$l\KS7HXsMV,ͱXCPxZmXJ,Ej4(_3$_; "<8n#@;ٻ<͐ԵdHZ"m$PyGEۘDBwj,>q^f(3–;2TN|A  ;~-nE+;Ƶ'sLJZ N[rX@h POZsd# 1t#1({{!T ;hCńVX/#ϘGqXBjTZپx;|Nx2\ӵCn4AZr,tGדS?/x|4U3ݡosf;!쩽t$/9r Evh+kbWl^`<<Mu,cEvv4TKF=)fÌg#߯&ƪ%yaqFMa0( M<j,wƸQ+گE\B{s^Bӹhg=o+\~"|WTߩЛJ:X,!%d }{U;riHn\ ]gJn4UfLW{JQӄ&A)l}{]R0\Ťg.64 R?,Hrlx^܎p0;$9k.`tzE Fמv˩F+¨NrL+V7cxײbg(~fd- ɰ5 _΍bBRgܮ:jșe-H~hgC$u7-Ç]&Y>kjotdhwi+yw4o 1y&T SFH D} @$2q]C}@xZFYurxiS!'#/ɬI.6=}uv,T (O+I,x Z}D.ɢ^|igf~<@wU}4g7֪^ 1i+K+ʗĭX+~pa2(GޏwvؘcBM&McK|a E!-o%8TCpu}%A%vwxhe90=~+udU*"ePBuo[$u 8o l8p׻>r,sgP%A=Xnjt. pvTp(99i[Ŏ/i@Y`OdreF6pZm[míƟ퍇~Vo,pSOA7DЏHh]ƕɢ d=8<Ko;e'V&'A|Vjەp {'O(_+7NֿL2/&1l\X Euã''𖑨Cj8Z=˪Y::~_kvQ(NHF 8M^ ]TL}K`/F!Hէ/wb2^z {z% c^+)ndZ{XmlFVoSMQ Z쇫*3M[g|Dn=8^/ad\Gw_ZAE.8?~POPО\&opq{ruI)1t‚W3}S, uz=I ]%*)Ia0uql#]b4z!lmd/i(VAxXD+%OFp8?iPTzXko7EV#zܨGw(gÇ^?o4j=KovUfpk!﷾S:r9Vc5A9.2sM) + %mQ02 e?-OfsOq0R9ժ7?U3q6{zMDȈtp/:. d0nR | }Dafn:E4]Yλ^bN4O!E<.o>6*U`@vج+%"rYvLcTIjCaxtrbnk(ԒQ> .^1[sE>pA<7ۀv)5.WsJic4^xu|{[hV;(޲(.v^A.\1k0U{e% j#Lb'pUe\`n#$sܮ5Ws jnSZL, ]VO ˫b[ufDJg`揍 t|v^V"K*Ԃ_/a?~hߟc+jδ͜ߢΪ|k)͝*P"C]Oҫb>L9YxɓJ*U:I:u2aXX'Y~t\~"E dΩI{G`/ r"5BgVFn-L]kƠsh[6JGJP .?,VDZޯӰ EOOC>+G N(і_^6;}'vjBJhJ[Gy锨>QB䴖hL:ki`َ*Ӎ@'½[o }~rI| oOn#gc Z$7o/>E'ZAo(p' d!odc:%oYɏoQG5VyU2{{?2# ܁?l,-H-^FBF㫃; UsoݽU^V61ݿ :?ʖM776n>hvG|0' j qT3d2@6*,c3cVI1jsq+pk"iV~U*UΪt@V Ej\8aM9ݏ NNd{_`S9eju\m/<>:A LvoR==_L]:ϵyJN (J—[[>ȵ <mӇ`5mט*b7TC$ZQZdѦZv\0kL=4c*HqzyOQnH~kOn6?KϜ> Oy=Dޟ9N@gy+34@zW w96* _)BB&GEnŝ|ӡ2]U^0[$U\|*kkuY[@3b4Z-h8k'hi$BX[JeфX&)*jao9Guج1JNJW(GP@WۛeW2.{]σSYY'GUQE龯@lvJدSm -Ct0z% ^Ud .6}N5u(Ց)Ç^QFR&ulyUt gK+FWd#TȊ VLC,^SX?ioۿ{g/vܝљ~ I zy@,ψ,%r?K3zck~_{>؂cL5j 1};kZԞ62mUJt0;Dz~:KH#-&E^b>rHS? F_dE/(ۃ% 2˲mx%AhYp2@rl_2P_XQ rCc^ |o]BcAgqrȧl^>:]\]h*eBpk}Oei\|;xڦ[;Yg"Nezg|ue[+t3^Z;Uʣv|3\oJ8u;p֙˝WY7Qm}d"T苶\VKl1^yޏ,7_Wi.(C{wovQ _[fI]ð50^Jp2)ףpٌ,vn봏Ɵ_Y+-o{7,-sf?@q$8"kR._sL57fl y&YJ?n%w\o/:[KQY:&tZ`col0 ձknzIMETd񅙈AOɐҩ2|4hrY4NMghGJ X^UL)L7E[[XCWl) $؎ߖ /D4߹(|v+<"Gg(Z+sSX`6of8nT$ȶZeA  UYQ4~17 Mr ÉZWba!UkthV#&ݭ.ZVPuܽ4 &D:;LYRtcHJUf;cQU7"U8|Jʡ,*a=әq@tNM`, XvqWFW9 휡%74Sq"wv~'{ahB_w+޵M٘ MG&g}Hv4Wd\-{˓مv%]_4[V)eOO tpH9;ZafX#0S}MӚNn5KUm<WjcMȆ\DF\Q'Qď 0 N0aMcCybGapru4܊[DasQJ#“&\Âz1?Eaj6V~~"A{8,٤ v{_ S'; FQ{V[ 2@uS$N0wb,SrtD+")0ǻOa R}M%R++Z M[R&Sr򘤾QGK/^&2H_4sxrۙ;@^ey;FfQJ0Ӈшhbc5 % E*tP9˨& hI;d"β"w Ӈmր]+Ө),ڎ@XC , ; -Ew

    //83s["D H1);p}9$q@pg^ 049E5 \ ZsQ49 g߶j*ɩ:R%*&.= oVx3I4`&F% P.:uG䣮B>`Цũ g # CA1%l!Ѩ2nYFK)0a2|'XcwtÜru@:PW`9kkyF;ʇȷ:j`_$ Rz4aG) t#,@5 3 VV]9LVq. lǰ$Xufs%gEɷ`|])f:} d=[8зt3B:iĤqyI16 =ۭ> 1L+я(Z-~LDJs b4 @GTJƒĹ ] M&{/,i,N0X㐸oH0u?]L͔If]h`^Y7ӡy߼M\B*`οTb!y&K,YJ=r~tL?&>ʓ蜮v'lNe`m+hA,$eTGS{1@EhHE8 K./M/y Ky>&io/Z} mIQGu!=kSu>=Wsz3C>fwrx_e9CA(CѸۍ 8s4xp#<(3lR3Jڒ'L9%gOCOI|6wR^"7/Tv(ݹhDca76P |`l, ma ߧOOQ&2Eo0dz tT S^E1f6ߧQ&+HNDwR򟝙 OUMwǝ#ڨ͜XO4 VL{#0x Fת;#5N'\&g Jţ=ap CD'57~֛wBd>.R(dv|< esԙuWǸ  /(ůmWԙ !-hHV沯m5_1w9(t!shoOc.)gkk~CNwIcNPb > L/7 ؏BΒwЅF7OnX{ϙPٴ|'q鮀)'y''0Xn"zpI7qB,- .hT[-6YNF0`"m?r.1,g' š1bR 6_[luxڤmjkkIL\ o8#eMs6'eNuzXjq&31s)d/“'DFM[nU6IX^7*X@׋/j0e!ey[D2^Ʌ˔vr2O7U"*I@۬wSs㞇Nmlpgሾw6j#ګHokkFvc~ޝŠV9&Y0o!g^/׍zuP*/PN QŽ'5O)i)=*|j?5$3i __BBma4Vǁ@s|AȾo*fSu3򸓨Sa8n B%g iLz]{wm2:u C9,}C) ⬤tI2g?,~Mmc.8 t7\.s{=ϬM0 nh_+|DڽNeYr h .o6>eOK^yPC]2y#!%R>Ĩ|p#Sfbjn9֖c#KsD' T^w-Fu\ ﰥcYn]c>'l+&9`@-s$ִH*\,W ؛p_+EY\}UE<|gsU*S:mA08 0IπLpA3\TJ*_%*_֦RTY\$EyVY|(+G74EÒDx*+wܲBw,/xuS+]˒eTٲWxiY2qǶ:v->PeݺW־,8>ekɮ,T;KTc=LFv۵XZK`.U}dUwc̮azV~\UbVwDJ9Q']%5ޅV@-Bd]̲|MZ[cVku3צSzpUM"ɋ8whsVʉـfeVϗvE%0@bПtb5#2&lsD%g8ìQ'\ҩv/_`ilq ec\JH<#(KIg>E-Sus"s{ZhN-8SC9N EmdaH@|*b$2Ǡ+)T.]+LNk8V1~cAzpvdAPGyDƿ(oJ\ES]DHHs,g\vهOS58M}M10,=|Zj32)z(/&<ަl56So@!{`]mu[^)<ᵁUqލ_$7xY.qF\fJ,-2Wr5`q4J$hg\\stpwE dùC .r::CЅX˓;'f龆V2zО`y*'kɧL3V7SYyKOl2f_-O=-1a23 T9s9  E"pǻCèWImvUݲjCGR$l\KS7HXuMV,ͱXCixZmXJ,Ej4(_3$_; "<8##ٻ<͐ԵdHZ"m$PyGLj;1"X}l] V4g4-weש՝\Iwϱ r"@wd݊V0wk+WO ˏyggo1ʺci )@=iUD8H!FrKE{/K ldcHy3ƚZxK+rEj3w<~(yX(&SXe2af3ЍQ(84wB`3;1CZy%k[v2=t7ܺOh{\#KzG4}T#vvxtߤHp 9ahNʪTBP] O`3&QlհVoGH-XO"a>SfAꢙ'홥GS|I|hϔ+$;DsIcC"ʱE\Kgq[,YYؙ_eF;y ;D_i\=%Cn(M[۪'`ݤ!{4`Iw]yNSBUVA]v7MD ..ڹ=)AE|iκ' ad[1>3=+FMUe*dfr9SRܳO.09O4C^>6RJC.W;OkZ|. v(ް&O E+ͯ*G4/gee5-RQ) 4jr,tGדS?/x|4U3ݡosf;!쩽t$/9a Evh+kbWl^`< aMu,cEvv4TKF=)vÌg#߯&աyaqFM bQ( M<j,wƸQ+گE\B{s^Bӹhg=o+\~"|WTߩЛJ:X,!%d }{U;riHn]g!Sn4UfLW{JQӄ&1q2[uIs5$2B~(̳+JC ųxq;Vhk&:fw -DѕZF@_{څ/o"( k;1F?[R]ˊDH-M⦒DS?7*fR8\nӮ 10lc9xf傮l6/ rE})I(H+J6JDǛ#dbsbΪlpB%mNk|R2YzCs׈VW5JDµ2ċsP=KQt(gWhc:,~`o;gZؓj/DxZVx:0AIAV<@Gj>F[^pz" d|4kPNXNQohm+sP⚄f5W@dP E(^FWV'>ꋷ/I-5hV}GK$fׄtO|:7~Y J!F6 @1#gB?#rL2.fyݐ2v}d*d^ҹCݥ=U˓/%8Po4Lɛ")cJ/#Bu -ծj}HfO O|wF7$&qPU[LHS춋:P_s@}c>$g(N8㕲'xbk9f@$"{aBIrl#o<ݝgW(VXRx]7dƤ/%*_b1rRSɠy?bc *6컎 7m#b.#%-R (ڮb`1VM^M_|͒UmA ]mx .HF1)•{^S)8RC`=.*7I&[@˘g'@Bu`+mprSt]ֹ- &[pO-Saft-22.11.22/osaft.pm000077500000000000000000005654501433765727300145470ustar00rootroot00000000000000#!/usr/bin/perl -I . ## PACKAGE { #!# Copyright (c) 2022, Achim Hoffmann #!# This software is licensed under GPLv2. Please see o-saft.pl for details. package osaft; # TODO: implement # require "o-saft-lib" "full"; # or "raw" # full: anything for o-saft.pl; raw partial for SSLhello.pm ## no critic qw(InputOutput::RequireEncodingWithUTF8Layer) # SEE Perl:binmode() (in o-saft.pl) ## no critic qw(Subroutines::RequireArgUnpacking) # Because we use @_ for better human readability. ## no critic qw(## no critic qw(Variables::ProhibitPackageVars) # Because variables are defined herein. ## no critic qw(RegularExpressions::RequireExtendedFormatting) # We believe that most RegEx are not too complex. ## no critic qw(ValuesAndExpressions::ProhibitImplicitNewlines) # That's intended in strings; perlcritic is too pedantic. use strict; use warnings; use utf8; our $SID_osaft = "@(#) osaft.pm 2.28 22/11/04 22:44:34"; our $VERSION = "22.11.22"; # official version number of this file use OSaft::Text qw(%STR); #_____________________________________________________________________________ #_____________________________________________________ public documentation __| # more public documentation, see start of methods section, and at end of file. # HACKER's INFO # Following (internal) functions from o-saft.pl are used: # _is_ssl_pfs() ## 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 =over 2 =item use osaft; # in perl code =item o-saft-lib.pm --help # on command-line will print help =back 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 =over 4 =item --help =item --regex, --test-regex =back =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 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 CONSTANTS =over 4 =item $STR{ERROR} =item $STR{WARN} =item $STR{HINT} =item $STR{USAGE} =item $STR{DBX} =item $STR{UNDEF} =item $STR{NOTXT} =item $STR{MAKEVAL} =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 %ec_curve_types =item %tls_curves =item %data_oid =item %target_desc =item @target_defaults =back =head1 METHODS =cut #_____________________________________________________________________________ #________________________________________________ public (export) variables __| ## no critic qw(Modules::ProhibitAutomaticExportation) # perlcritic complains to use @EXPORT_OK instead of @EXPORT, but we want any- # thing exported. # See NOTES below also. use Exporter qw(import); use base qw(Exporter); our @EXPORT = qw( %ciphers %prot %prot_txt %tls_compression_method %tls_handshake_type %tls_key_exchange_type %tls_record_type %tls_error_alerts %TLS_EXTENSIONS %TLS_EC_POINT_FORMATS %TLS_MAX_FRAGMENT_LENGTH %TLS_NAME_TYPE %TLS_PROTOCOL_VERSION %TLS_PSK_KEY_EXCHANGE_MODE %TLS_SIGNATURE_SCHEME %TLS_SUPPORTED_GROUPS %TLS_ID_TO_EXTENSIONS %ec_curve_types %tls_curves %target_desc @target_defaults %data_oid %dbx %cfg get_ciphers_range 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 tls_const2text tls_key2text tls_text2key printhint test_cipher_regex osaft_done ); # not yet exported: osaft_sleep # 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' % my $cfg__me= $0; # dirty hack to circumvent late initialisation $cfg__me=~ s#^.*[/\\]##; # of $cfg{'me'} which is used in %cfg itself #branch our %ciphers = (); # defined in OSaft/Ciphers.pm; need forward here 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 standardised; 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 = ( # texts for protocol checks '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', # RFC 4347 DTLS 4 => 'new_session_ticket', # 4 => 'NewSessionTicket', 6 => 'hello_retry_request', # RFC 8446 8 => 'encrypted_extensions', # RFC 8446 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', # RFC 6066 10.2 22 => 'certificate_status', # RFC 6066 10.2 23 => 'supplemental_data', # RFC ?? 24 => 'key_update', # RFC 8446 254 => 'message_hash', # RFC 8446 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 7507 Y -)], 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_EC_POINT_FORMATS = ( TEXT => "ec point format(s)", # define text for print FORMAT => [qw( "%s" )],# define format for printf #----+-------------------------------------+----+---+---------------------------- # ID name DTLS RECOMMENDED RFC #----+-------------------------------------+----+---+---------------------------- 0 => [qw( uncompressed Y Y 4492 )], 1 => [qw( ansiX962_compressed_prime Y? N? 4492 )], 2 => [qw( ansiX962_compressed_char2 Y? N? 4492 )], #----+-------------------------------------+----+---+---------------------------- ); # https://tools.ietf.org/html/rfc6066#section-3 our %TLS_NAME_TYPE = ( TEXT => "server name type", # define text for print FORMAT => [qw( %s )],# define format for printf #----+-------------------------------------+----+-------+------------------------ # ID name DTLS RFC #----+-------------------------------------+----+-------+------------------------ 0x00 => [qw( host_name Y 6066 )], #----+-------------------------------------+----+-------+------------------------ ); # https://tools.ietf.org/html/rfc6066#section-4 # Default is 2^14 if this extension is not present our %TLS_MAX_FRAGMENT_LENGTH = ( TEXT => "max fragment length negotiation", # define text for print FORMAT => [ "%s", "(%s bytes)" ],# define format for printf #----+-------------------------------------+----+-------+------------------------ # ID name RECONMMENDED RFC #----+-------------------------------------+----+-------+------------------------ 0x01 => [qw( 2^9 512 - 6066 )], 0x02 => [qw( 2^10 1024 - 6066 )], 0x03 => [qw( 2^11 2048 - 6066 )], 0x04 => [qw( 2^12 4096 - 6066 )], #----+-------------------------------------+----+-------+------------------------ ); # https://tools.ietf.org/html/rfc8446#appendix-B.3.1.1 (added versions manually) our %TLS_PROTOCOL_VERSION = ( TEXT => "supported protocol version(s)", # define text for print FORMAT => [qw( %s ) ], # define format for printf #----+------------------------------------------------------------------------- # ID name #----+------------------------------------------------------------------------- 0x0304 => [qq( TLS 1.3 )], 0x0303 => [qq( TLS 1.2 )], 0x0302 => [qq( TLS 1.1 )], 0x0301 => [qq( TLS 1.0 )], 0x0300 => [qq( SSL 3 )], #----+------------------------------------------------------------------------- ); # https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-pskkeyexchangemode our %TLS_PSK_KEY_EXCHANGE_MODE = ( TEXT => "PSK key exchange mode(s)", # define text for print FORMAT => [qw( "%s" )],# define format for printf #----+-------------------------------------+----+-------+------------------------ # ID name RECONMMENDED RFC #----+-------------------------------------+----+-------+------------------------ 0x00 => [qw( psk_ke Y 8446 )], 0x01 => [qw( psk_dhe_ke Y 8446 )], #----+-------------------------------------+----+-------+------------------------ ); # https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme our %TLS_SIGNATURE_SCHEME = ( TEXT => "signature scheme(s)", # define text for print FORMAT => [qw( %s )],# define format for printf #----+-------------------------------------+----+-------+------------------------ # ID name DTLS RFC # comment #----+-------------------------------------+----+-------+------------------------ 0x0201 => [qw( rsa_pkcs1_sha1 Y 8446 )], 0x0202 => [qw( dsa_sha1 ? 8446 )],# Quelle suchen & prüfen! 0x0203 => [qw( ecdsa_sha1 Y 8446 )], 0x0301 => [qw( rsa_sha224 ? ? )],# Quelle suchen & prüfen! 0x0302 => [qw( dsa_sha224 ? ? )],# Quelle suchen & prüfen! 0x0303 => [qw( ecdsa_sha224 ? ? )],# Quelle suchen & prüfen! 0x0401 => [qw( rsa_pkcs1_sha256 Y 8446 )], 0x0402 => [qw( dsa_sha256 ? 8446 )],# Quelle suchen & prüfen! 0x0403 => [qw( ecdsa_secp256r1_sha256 Y 8446 )], 0x0420 => [qw( rsa_pkcs1_sha256_legacy N draft-davidben-tls13-pkcs1-00 )], 0x0501 => [qw( rsa_pkcs1_sha384 Y 8446 )], 0x0502 => [qw( dsa_sha384 ? 8446] )],# Quelle suchen & prüfen! 0x0503 => [qw( ecdsa_secp384r1_sha384 Y 8446 )], 0x0520 => [qw( rsa_pkcs1_sha384_legacy N draft-davidben-tls13-pkcs1-00 )], 0x0601 => [qw( rsa_pkcs1_sha512 Y 8446 )], 0x0602 => [qw( dsa_pkcs1_sha512 Y 8446 )],# Quelle suchen & prüfen! 0x0603 => [qw( ecdsa_secp521r1_sha512 Y 8446 )], 0x0620 => [qw( rsa_pkcs1_sha512_legacy N draft-davidben-tls13-pkcs1-00 )], 0x0704 => [qw( eccsi_sha256 N draft-wang-tls-raw-public-key-with-ibc )], 0x0705 => [qw( iso_ibs1 N draft-wang-tls-raw-public-key-with-ibc])], 0x0706 => [qw( iso_ibs2 N draft-wang-tls-raw-public-key-with-ibc])], 0x0707 => [qw( iso_chinese_ibs N draft-wang-tls-raw-public-key-with-ibc])], 0x0708 => [qw( sm2sig_sm3 N draft-yang-tls-tls13-sm-suites )], 0x0709 => [qw( gostr34102012_256a N draft-smyshlyaev-tls13-gost-suites )], 0x070A => [qw( gostr34102012_256b N draft-smyshlyaev-tls13-gost-suites )], 0x070B => [qw( gostr34102012_256c N draft-smyshlyaev-tls13-gost-suites )], 0x070C => [qw( gostr34102012_256d N draft-smyshlyaev-tls13-gost-suites )], 0x070D => [qw( gostr34102012_512a N draft-smyshlyaev-tls13-gost-suites )], 0x070E => [qw( gostr34102012_512b N draft-smyshlyaev-tls13-gost-suites )], 0x070F => [qw( gostr34102012_512c N draft-smyshlyaev-tls13-gost-suites )], 0x0804 => [qw( rsa_pss_rsae_sha256 Y 8446 )], 0x0805 => [qw( rsa_pss_rsae_sha384 Y 8446 )], 0x0806 => [qw( rsa_pss_rsae_sha512 Y 8446 )], 0x0807 => [qw( ed25519 Y 8446 )], 0x0808 => [qw( ed448 Y 8446 )], 0x0809 => [qw( rsa_pss_pss_sha256 Y 8446 )], 0x080A => [qw( rsa_pss_pss_sha384 Y 8446 )], 0x080B => [qw( rsa_pss_pss_sha512 Y 8446 )], 0x081A => [qw( ecdsa_brainpoolP256r1tls13_sha256 N 8734 )], 0x081B => [qw( ecdsa_brainpoolP384r1tls13_sha384 N 8734 )], 0x081C => [qw( ecdsa_brainpoolP512r1tls13_sha512 N 8734 )], # 0xFE00 .. 0xFFFF => [qw(private_use ? 8446 )], #----+-------------------------------------+----+-------+------------------------ ); # Torsten: ex %ECC_NAMED_CURVE = # http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-10 our %TLS_SUPPORTED_GROUPS = ( TEXT => "supported group(s)", # define text for print FORMAT => [ "%s", "(%s bits)" ],# define format for printf, space is needed -> no 'qw' #----+-----------------------------+-------+----+---+---------------------------- # ID name (added:)bits DTLS RECOMMENDED RFC #----+-----------------------------+-------+----+---+---------------------------- 0 => [qw( Reverved_0 0 N N 8447 )], 1 => [qw( sect163k1 163 Y N 4492 )], 2 => [qw( sect163r1 163 Y N 4492 )], 3 => [qw( sect163r2 163 Y N 4492 )], 4 => [qw( sect193r1 193 Y N 4492 )], 5 => [qw( sect193r2 193 Y N 4492 )], 6 => [qw( sect233k1 233 Y N 4492 )], 7 => [qw( sect233r1 233 Y N 4492 )], 8 => [qw( sect239k1 239 Y N 4492 )], 9 => [qw( sect283k1 283 Y N 4492 )], 10 => [qw( sect283r1 283 Y N 4492 )], 11 => [qw( sect409k1 409 Y N 4492 )], 12 => [qw( sect409r1 409 Y N 4492 )], 13 => [qw( sect571k1 571 Y N 4492 )], 14 => [qw( sect571r1 571 Y N 4492 )], 15 => [qw( secp160k1 160 Y N 4492 )], 16 => [qw( secp160r1 160 Y N 4492 )], 17 => [qw( secp160r2 160 Y N 4492 )], 18 => [qw( secp192k1 192 Y N 4492 )], 19 => [qw( secp192r1 192 Y N 4492 )], 20 => [qw( secp224k1 224 Y N 4492 )], 21 => [qw( secp224r1 224 Y N 4492 )], 22 => [qw( secp256k1 256 Y N 4492 )], 23 => [qw( secp256r1 256 Y Y 4492 )], 24 => [qw( secp384r1 384 Y Y 4492 )], 25 => [qw( secp521r1 521 Y N 4492 )], 26 => [qw( brainpoolP256r1 256 Y Y 7027 )], 27 => [qw( brainpoolP384r1 384 Y Y 7027 )], 28 => [qw( brainpoolP512r1 512 Y Y 7027 )], 29 => [qw( x25519 255 Y Y 8446:8422 )], 30 => [qw( x448 448 Y Y 8446:8422 )], 31 => [qw( brainpoolP256r1tls13 256 Y N 8734 )], 32 => [qw( brainpoolP384r1tls13 384 Y N 8734 )], 33 => [qw( brainpoolP512r1tls13 512 Y N 8734 )], 34 => [qw( GC256A 256 Y N draft-smyshlyaev-tls12-gost-suites )], 35 => [qw( GC256B 256 Y N draft-smyshlyaev-tls12-gost-suites )], 36 => [qw( GC256C 256 Y N draft-smyshlyaev-tls12-gost-suites )], 37 => [qw( GC256D 256 Y N draft-smyshlyaev-tls12-gost-suites )], 38 => [qw( GC512A 512 Y N draft-smyshlyaev-tls12-gost-suites )], 39 => [qw( GC512B 512 Y N draft-smyshlyaev-tls12-gost-suites )], 40 => [qw( GC512C 512 Y N draft-smyshlyaev-tls12-gost-suites )], 41 => [qw( curveSM2 256 N N draft-yang-tls-tls13-sm-suites )], # 42-255 Unassigned 256 => [qw( ffdhe2048 2048 Y N 7919 )], 257 => [qw( ffdhe3072 3072 Y N 7919 )], 258 => [qw( ffdhe4096 4096 Y N 7919 )], 259 => [qw( ffdhe6144 6144 Y N 7919 )], 260 => [qw( ffdhe8192 8192 Y N 7919 )], # 261-507 Unassigned 508 => [qw( ffdhe_private_use_508 NN Y N 7919 )], 509 => [qw( ffdhe_private_use_509 NN Y N 7919 )], 510 => [qw( ffdhe_private_use_510 NN Y N 7919 )], 511 => [qw( ffdhe_private_use_511 NN Y N 7919 )], # 512-2569 Unassigned 2570 => [qw( Reserved_2570 NN Y N 8701 )], # 2571-6681 Unassigned 6682 => [qw( Reserved_6682 NN Y N 8701 )], # 6683-10793 Unassigned 10794 => [qw( Reserved_10794 NN Y N 8701 )], # 10795-14905 Unassigned 14906 => [qw( Reserved_14906 NN Y N 8701 )], # 14907-19017 Unassigned 19018 => [qw( Reserved_19018 NN Y N 8701 )], # 19019-23129 Unassigned 23130 => [qw( Reserved_23130 NN Y N 8701 )], # 23131-27241 Unassigned 27242 => [qw( Reserved_27242 NN Y N 8701 )], # 27243-31353 Unassigned 31354 => [qw( Reserved_31354 NN Y N 8701 )], # 31355-35465 Unassigned 35466 => [qw( Reserved_35466 NN Y N 8701 )], # 35467-39577 Unassigned 39578 => [qw( Reserved_39578 NN Y N 8701 )], # 39579-43689 Unassigned 43690 => [qw( Reserved_43690 NN Y N 8701 )], # 43691-47801 Unassigned 47802 => [qw( Reserved_47802 NN Y N 8701 )], # 47803-51913 Unassigned 51914 => [qw( Reserved_51914 NN Y N 8701 )], # 51915-56025 Unassigned 56026 => [qw( Reserved_56026 NN Y N 8701 )], # 56027-60137 Unassigned 60138 => [qw( Reserved_60138 NN Y N 8701 )], # 60139-64249 Unassigned 64250 => [qw( Reserved_64250 NN Y N 8701 )], # 64251-65023 Unassigned # 65024-65279 Reserved_for_Private_Use NN Y N 8422 , 0xFE00 => [qw( ecdhe_private_use_65024 NN Y N NN )],# 0xFE00..0xFEFF => "ecdhe_private_use", 0xFE01 => [qw( ecdhe_private_use_65025 NN Y N NN )],# 0xFE00..0xFEFF => "ecdhe_private_use", 0xFE02 => [qw( ecdhe_private_use_65026 NN Y N NN )],# 0xFE00..0xFEFF => "ecdhe_private_use", 0xFE03 => [qw( ecdhe_private_use_65027 NN Y N NN )],# 0xFE00..0xFEFF => "ecdhe_private_use", 0xFE04 => [qw( ecdhe_private_use_65028 NN Y N NN )],# 0xFE00..0xFEFF => "ecdhe_private_use", 0xFE05 => [qw( ecdhe_private_use_65029 NN Y N NN )],# 0xFE00..0xFEFF => "ecdhe_private_use", 0xFE06 => [qw( ecdhe_private_use_65030 NN Y N NN )],# 0xFE00..0xFEFF => "ecdhe_private_use", 0xFE07 => [qw( ecdhe_private_use_65031 NN Y N NN )],# 0xFE00..0xFEFF => "ecdhe_private_use", # 65280 Unassigned 65281 => [qw( arbitrary_explicit_prime_curves -variable- N 8422 )], 65282 => [qw( arbitrary_explicit_char2_curves -variable- Y 8422 )], # 65283-65535 Unassigned ); our %TLS_EXTENSIONS = ( # Generated on base of IANA (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml#tls-extensiontype-values-1), RFCs and drafts for RFCs # # Added a self defined general description for the structure of for PDUs, e.g. tls extensions: # len1: Len of the next bytes, coded in 1 byte (-> max 0xFF) # len2: Len of the next bytes, coded in 2 bytes (-> max 0xFFFF) # len3: Len of the next bytes, coded in 3 bytes (-> max 0xFFFFFF) # size1: Size of the next value, coded in 1 byte (-> max 0xFF) # size2: Size of the next value, coded in 2 bytes (-> max 0xFFFF) # val1: value, coded in 1 byte (-> max 0xFF) # val2: value, coded in 2 bytes (-> max 0xFFFF) # val4: value, coded in 4 byters (-> max 0xFFFFFFFF) # val1List: List of value, coded in 1 byte (-> max 0xFF, 0xFF, ...) # val2List: List of value, coded in 2 bytes (-> max 0xFFFF, 0xFFFF, ...) # raw: Raw bytes (number needs to be previously defined by a len or size element) # sequence: Sequence of structured elements that form lists of compound values # # Hash values: # : Extension name by IANA, RFC or draft for a RFCr # ID: Official nr by IANA, RFC or DRAFT for a RFC # CH: Client Hello: describes the structure of client hellos based on the general descrition language defined above # CH_TEXT: Descriptions and references to decoding hashes by the structure element of a CH # RX: Received Extension, e.g. Server Hellon: describes the structure of received hellos based on the general descrition language defined above # RX_TEXT: Descriptions and references to decoding hashes by the structure element of a RX # RECOMMENDED: From IANA, 'N' or '?' if the extension is taken from a RFC or draft for a RFC # TLS13: Whrere used by TLSv1.3 according IANA # RFC: RFC according, IANA, RFC or draft # DEFAULT: Default values for client hellos (used by val1 ... val4, val1List, val2List, raw, sequences define an array inside the array lists). # CHECK: Internal value, if the VALUE or CHECKing for a list of all (supporeted) values (might be reserved for future deployment) # COMMENT: Optional comments # #---------------------------------+---------------+------------+----------------------------------+--------------------------------+--------+---------------+-------------------------- #Extension Name: (ID (Value), CH* (Client Hello)*, RX* (Receive SH, ...), RECOMMENDED, TLS13 (TLS 1.3), RFC, COMMENT*; *= Added comment #---------------------------------+---------------+------------+----------------------------------+--------------------------------+--------+---------------+-------------------------- server_name => { ID => 0, # Hex: 0x0000 CH => [qw(len2 len2 sequence val1 len2 raw)], CH_TEXT => ["length", "server name list length", "server name element", \%TLS_NAME_TYPE, "server name length", "server name" ], RX => [qw(len2 raw)], # Example: 0x0000 (no data, only as marker) RX_TEXT => ["length", "server name list length" ], RECOMMENDED => q(Y), TLS13 => [qw(CH EE)], RFC => [qw(6066)], DEFAULT => [ [ # 1st sequence element 0x00, # host_name "localhost", # $TLS_EXTENSION{server_name}{DEFAULT}[0][0][1], might be overwritten ], ], CHECK => q(VALUE), COMMENT => q(), }, max_fragment_length => { ID => 1, CH => [qw(len2 len2 val1List)], CH_TEXT => ["length", "length of max fragment lenght", \%TLS_MAX_FRAGMENT_LENGTH ], RX => [qw(len2 raw)], RX_TEXT => ["length", \%TLS_MAX_FRAGMENT_LENGTH ], RECOMMENDED => q(-), TLS13 => [qw(CH EE)], RFC => [qw(6066 8449)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(replaced by extension 'record_size_limit'; Default max length is 2^14 if this extension is not negotiated), }, client_certificate_url => { ID => 2, CH => [qw(len2 len2 val1 sequence len2 val1 raw)],#TBD Check sequence position RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(6066)], DEFAULT => [ ], # [ [], ], CHECK => q(VALUE), COMMENT => q(val20 oder len2_val?), }, trusted_ca_keys => { ID => 3, CH => [qw(len2 len2 val1 len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(N)], RFC => [qw(6066)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(?), }, truncated_hmac => { ID => 4, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q[N], TLS13 => [qw(N)], RFC => [qw(6066 IESG_Action_2018-08-16)], DEFAULT => [], CHECK => q[VALUE], COMMENT => q[Shall be empty], }, status_request => { ID => 5, CH => [qw(len2 val1 len2 raw len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH CR CT)], RFC => [qw(6066)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[SH ext_form_val1_len2_val?], }, user_mapping => { ID => 6, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(4681)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(), }, client_authz => { ID => 7, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(-)], RFC => [qw(5878)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(), }, server_authz => { ID => 8, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(-)], RFC => [qw(5878)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(), }, cert_type => { ID => 9, CH => [qw(len2 len1 val1List)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(-)], RFC => [qw(6091)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(Server: val1), }, #elliptic_curves => # old name supported_groups => { ID => 10, CH => [qw(len2 len2 val2List)], CH_TEXT => ["length", "supported groups list length", \%TLS_SUPPORTED_GROUPS], RX => [qw(len2 val2)], RX_TEXT => ["length", \%TLS_SUPPORTED_GROUPS], RECOMMENDED => q(Y), TLS13 => [qw(CH EE)], RFC => [qw(8422 7919)], DEFAULT => [ [ #0x0000, # 0x0000 (Unassigned_0) ## disabled by default 0x0001, # sect163k1 0x0002, # sect163r1 0x0003, # sect163r2 0x0004, # sect193r1 0x0005, # sect193r2 0x0006, # sect233k1 0x0007, # sect233r1 0x0008, # sect239k1 0x0009, # sect283k1 0x000a, # sect283r1 0x000b, # sect409k1 0x000c, # sect409r1 0x000d, # sect571k1 0x000e, # sect571r1 0x000f, # secp160k1 0x0010, # secp160r1 0x0011, # secp160r2 0x0012, # secp192k1 0x0013, # secp192r1 0x0014, # secp224k1 0x0015, # secp224r1 0x0016, # secp256k1 0x0017, # secp256r1 ## => common default curve 0x0018, # secp384r1 0x0019, # secp512r1 0x001a, # brainpoolP256r1 0x001b, # brainpoolP384r1 0x001c, # brainpoolP512r1 0x001d, # ecdh_x25519 0x001e, # ecdh_x448 0x001f, # brainpoolP256r1tls13 0x0020, # brainpoolP384r1tls13 0x0021, # brainpoolP512r1tls13 0x0022, # GC256A [draft-smyshlyaev-tls12-gost-suites] 0x0023, # GC256B [draft-smyshlyaev-tls12-gost-suites] 0x0024, # GC256C [draft-smyshlyaev-tls12-gost-suites] 0x0025, # GC256D [draft-smyshlyaev-tls12-gost-suites] 0x0026, # GC512A [draft-smyshlyaev-tls12-gost-suites] 0x0027, # GC512B [draft-smyshlyaev-tls12-gost-suites] 0x0028, # GC512C [draft-smyshlyaev-tls12-gost-suites] 0x0029, # curveSM2 [draft-yang-tls-tls13-sm-suites] # Finite Field Groups (DHE): 0x0100, # ffdhe2048 0x0101, # ffdhe3072 0x0102, # ffdhe4096 0x0103, # ffdhe6144 0x0104, # ffdhe8192 ], ], CHECK => q(VALUE), COMMENT => q(renamed from "elliptic_curves"), }, ec_point_formats => { ID => 11, # Hex: 0x000b CH => [qw(len2 len1 val1List)], # Example: 0x0002 0x01 0x00 CH_TEXT => ["length", "ec point formats list length", \%TLS_EC_POINT_FORMATS], RX => [qw(len2 len1 val1List)], RX_TEXT => ["length", "ec point formats list length", \%TLS_EC_POINT_FORMATS], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(8422)], DEFAULT => [ [ 0x00, # uncompressed,Y,[RFC8422] 0x01, # ansiX962_compressed_prime,Y,[RFC8422] 0x02, # ansiX962_compressed_char2,Y,[RFC8422] ], ], CHECK => q(VALUE), COMMENT => q(), }, srp => { ID => 12, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N),, TLS13 => [qw(-)], RFC => [qw(5054)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(), }, signature_algorithms => { ID => 13, # Hex: 0x000d CH => [qw(len2 len2 val2List)], # Example: 0x0020 0x001E 0x0601 0x0602 0x0603 0x0501 0x0502 0x0503 0x0401 0x0402 0x0403 0x0301 0x0302 0x0303 0x0201 0x0202 0x0203 CH_TEXT => ["length", "signature hash algorithms list length", \%TLS_SIGNATURE_SCHEME], RX => [qw(len2 val2)], RX_TEXT => ["length", \%TLS_SIGNATURE_SCHEME], RECOMMENDED => q(Y), TLS13 => [qw(CH CR)], RFC => [qw(8446)], DEFAULT => [ [ 0x0201, # rsa_pkcs1_sha1,Y,[RFC8446] 0x0202, # SHA1 DSA,[RFC8446] (Quelle suchen & prüfen!) 0x0203, # ecdsa_sha1,Y,[RFC8446] 0x0301, # SHA224 RSA (Quelle suchen & prüfen!) 0x0302, # SHA224 DSA (Quelle suchen & prüfen!) 0x0303, # SHA224 ECDSA (Quelle suchen & prüfen!) 0x0401, # rsa_pkcs1_sha256,Y,[RFC8446] 0x0402, # SHA256 DSA (Quelle suchen & prüfen!),[RFC8446] (Quelle suchen & prüfen!) 0x0403, # ecdsa_secp256r1_sha256,Y,[RFC8446] 0x0420, # rsa_pkcs1_sha256_legacy,N,[draft-davidben-tls13-pkcs1-00] 0x0501, # rsa_pkcs1_sha384,Y,[RFC8446] 0x0502, # Reserved for backward compatibility,,[RFC8446] 0x0503, # ecdsa_secp384r1_sha384,Y,[RFC8446] 0x0520, # rsa_pkcs1_sha384_legacy,N,[draft-davidben-tls13-pkcs1-00] 0x0601, # rsa_pkcs1_sha512,Y,[RFC8446] 0x0602, # dsa_pkcs1_sha512,Y,[RFC8446]? (Quelle suchen und prüfen!) 0x0603, # ecdsa_secp521r1_sha512,Y,[RFC8446] 0x0620, # rsa_pkcs1_sha512_legacy,N,[draft-davidben-tls13-pkcs1-00] 0x0704, # eccsi_sha256,N,[draft-wang-tls-raw-public-key-with-ibc] 0x0705, # iso_ibs1,N,[draft-wang-tls-raw-public-key-with-ibc] 0x0706, # iso_ibs2,N,[draft-wang-tls-raw-public-key-with-ibc] 0x0707, # iso_chinese_ibs,N,[draft-wang-tls-raw-public-key-with-ibc] 0x0708, # sm2sig_sm3,N,[draft-yang-tls-tls13-sm-suites] 0x0709, # gostr34102012_256a,N,[draft-smyshlyaev-tls13-gost-suites] 0x070A, # gostr34102012_256b,N,[draft-smyshlyaev-tls13-gost-suites] 0x070B, # gostr34102012_256c,N,[draft-smyshlyaev-tls13-gost-suites] 0x070C, # gostr34102012_256d,N,[draft-smyshlyaev-tls13-gost-suites] 0x070D, # gostr34102012_512a,N,[draft-smyshlyaev-tls13-gost-suites] 0x070E, # gostr34102012_512b,N,[draft-smyshlyaev-tls13-gost-suites] 0x070F, # gostr34102012_512c,N,[draft-smyshlyaev-tls13-gost-suites] 0x0804, # rsa_pss_rsae_sha256,Y,[RFC8446] 0x0805, # rsa_pss_rsae_sha384,Y,[RFC8446] 0x0806, # rsa_pss_rsae_sha512,Y,[RFC8446] 0x0807, # ed25519,Y,[RFC8446] 0x0808, # ed448,Y,[RFC8446] 0x0809, # rsa_pss_pss_sha256,Y,[RFC8446] 0x080A, # rsa_pss_pss_sha384,Y,[RFC8446] 0x080B, # rsa_pss_pss_sha512,Y,[RFC8446] 0x081A, # ecdsa_brainpoolP256r1tls13_sha256,N,[RFC8734] 0x081B, # ecdsa_brainpoolP384r1tls13_sha384,N,[RFC8734] 0x081C, # ecdsa_brainpoolP512r1tls13_sha512,N,[RFC8734] ], ], CHECK => q(VALUE), COMMENT => q[], }, use_srtp => { ID => 14, CH => [qw(len2 size2 val2List len1 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH EE)], RFC => [qw(5764)], DEFAULT => [ [ 0x0001, # SRTPProtectionProfile SRTP_AES128_CM_HMAC_SHA1_80 0x0002, # SRTPProtectionProfile SRTP_AES128_CM_HMAC_SHA1_32 0x0005, # SRTPProtectionProfile SRTP_NULL_HMAC_SHA1_80 0x0006, # SRTPProtectionProfile SRTP_NULL_HMAC_SHA1_32 ] ], CHECK => q(VALUE), COMMENT => q[], }, heartbeat => { ID => 15, CH => [qw(len2 val1)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH EE)], RFC => [qw(6520)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(Syntax prüfen!), }, application_layer_protocol_negotiation => { ID => 16, CH => [qw(len2 len2 size1 raw size1 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH EE)], RFC => [qw(7301)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, status_request_v2 => { ID => 17, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(6961)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, signed_certificate_timestamp => { ID => 18, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(CH CR CT)], RFC => [qw(6962)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, client_certificate_type => { ID => 19, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH EE)], RFC => [qw(7250)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, server_certificate_type => { ID => 20, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH EE)], RFC => [qw(7250)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, padding => { ID => 21, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH)], RFC => [qw(7685)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(val= 0x00-Bytes), }, encrypt_then_mac => { ID => 22, # Hex: 0x0016 CH => [qw(len2 raw)], # Example: 0x0000 (no data, only as marker) RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(7366)], DEFAULT => [], #empty CHECK => q(VALUE), COMMENT => q[], }, extended_master_secret => { ID => 23, # Hex: 0x0017 CH => [qw(len2 raw)], # Example: 0x0000 (no data, only as marker) RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(7627)], DEFAULT => [], #empty CHECK => q(VALUE), COMMENT => q[], }, token_binding => { ID => 24, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(8472)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, cached_info => { ID => 25, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(7924)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, tls_lts => { ID => 26, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(-)], RFC => [qw(draft-gutmann-tls-lts)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, compress_certificate => { ID => 27, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH CR)], RFC => [qw(draft-ietf-tls-certificate-compression)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(TEMPORARY registered 2018-05-23 extension registered 2019-04-22 expires 2020-05-23), }, record_size_limit => { ID => 28, CH => [qw(len2 val2)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH EE)], RFC => [qw(8449)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, pwd_protect => { ID => 29, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(CH)], RFC => [qw(8492)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, pwd_clear => { ID => 30, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(CH)], RFC => [qw(8492)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, password_salt => { ID => 31, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(CH SH HRR)], RFC => [qw(8492)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, # 32-34 Unassigned session_ticket => { ID => 35, # Hex: 0x0023 # CH => [qw(len2 val4 len2 raw)], # Example: 0x0000 (no data) CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(5077 8447)], DEFAULT => [], # empty CHECK => q(VALUE), COMMENT => q(renamed from "SessionTicket TLS"), }, # 36-40 Unassigned # NOT official: extended_random => { ID => 40, CH => [qw(len2 len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N!), TLS13 => [qw(?)], RFC => [qw(draft-rescorla-tls-extended-random-02)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(NSA; March 02, 2009; DO NOT USE!! https://gist.github.com/bonsaiviking/9921180: 0x0028, RSA BSAFE library), }, pre_shared_key => { ID => 41, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH SH)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, early_data => { ID => 42, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH EE NST)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, supported_versions => { ID => 43, # Hex: 0x002b CH => [qw(len2 len1 val2List)], # Example: 0x0003 0x02 0x0304 CH_TEXT => ["length", "supported versions list length", \%TLS_PROTOCOL_VERSION], RX => [qw(len2 val2)], RX_TEXT => ["length", \%TLS_PROTOCOL_VERSION], RECOMMENDED => q(Y), TLS13 => [qw(CH SH HRR)], RFC => [qw(8446)], DEFAULT => [ [ 0x0304, # TLS 1.3 # 0x0303, # TLS 1.2 # 0x0302, # TLS 1.1 # 0x0301, # TLS 1.0 # 0x0300, # SSL 3 ], ], CHECK => q(VALUE), COMMENT => q[], }, cookie => { ID => 44, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH HRR)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, psk_key_exchange_modes => { # MUST be included if key_share is used ID => 45, # Hex: 0x02d CH => [qw(len2 len1 val1List)], # Example: 0x0002 0x01 0x01 CH_TEXT => ["length", "PSK key exchange modes list length", %TLS_PSK_KEY_EXCHANGE_MODE], RX => [qw(len2 val1)], RX_TEXT => ["length", %TLS_PSK_KEY_EXCHANGE_MODE], RECOMMENDED => q(Y), TLS13 => [qw(CH)], RFC => [qw(8446)], DEFAULT => [ [ 0x00, # psk_ke,Y,[RFC8446] 0x01, # psk_dhe_ke,Y,[RFC8446] ], ], CHECK => q(VALUE), COMMENT => q[], }, # 46 Unassigned certificate_authorities => { ID => 47, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH CR)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, oid_filters => { ID => 48, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CR)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, post_handshake_auth => { ID => 49, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, signature_algorithms_cert => { ID => 50, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH CR)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, key_share => { # MUST be the last extension if used ID => 51, # Hex: 0x0033 CH => [qw(len2 len2 sequence val2 size2 raw)], # Example: 0x0026 0x0024 0x001d 0x0020 CH_TEXT => ["length", "client key share list length", "key share element", \%TLS_SUPPORTED_GROUPS, "key exchange length", "key exchange"], RX => [qw(len2 val2 size2 raw)], RX_TEXT => ["length", \%TLS_SUPPORTED_GROUPS, "key exchange length", "key exchange"], RECOMMENDED => q(Y), TLS13 => [qw(CH SH HRR)], RFC => [qw(8446)], DEFAULT => [ [ # 1st sequence element 0x001d, # Group x25519 "\x01\x02\x03\x04\x05\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20", # Key Exchange ], [ # second sequence element 0x0017, # Group secp256r1 "\x21\x22\x23\x24\x25\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F\x30\x31\x32\x33\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F\x40" . "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F\x60\x61", # Key Exchange ], ], CHECK => q(VALUE), COMMENT => q[], }, transparency_info => { ID => 52, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(Y), TLS13 => [qw(CH CR CT)], RFC => [qw(draft-ietf-trans-6962-bis)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, # 53-65279 Unassigned supports_npn => { ID => 13172, # Hex: 0x3374 # CH => [qw(len2 len1 raw len1 raw)],# Example: 0x0000 (no data) CH => [qw(len2 len1 raw)],# Example: 0x0000 (no data) RX => [qw(len2 raw)], RECOMMENDED => q(?), TLS13 => [qw(?)], RFC => [qw(draft-agl-tls-nextprotoneg-04)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q[], }, # NOT official: channel_id_old => { ID => 33031, CH => [qw(len2 val4 val4 val4 val4)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(?)], RFC => [qw(draft-balfanz-tls-channelid-00)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(channel_id_old=0x754F), }, # NOT official: channel_id => { ID => 33032, CH => [qw(len2 val4 val4 val4 val4)], RX => [qw(len2 raw)], RECOMMENDED => q(N), TLS13 => [qw(?)], RFC => [qw(draft-balfanz-tls-channelid-01)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(channel_id=0x7550), }, # NOT official: opaque_prf_input => { ID => 38183, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(N!), TLS13 => [qw(?)], RFC => [qw(draft-rescorla-tls-opaque-prf-input-00)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(NSA; December 13, 2006; DO NOT USE!! https://www.openssl.org/news/changelog.html#x44 [29 Mar 2010]: opaque_prf_input=0x9527), }, tack => { ID => 62208, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(?), TLS13 => [qw(?)], RFC => [qw(draft-perrin-tls-tack-02)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(January 07, 2013, expired July 11, 2013), }, # private_65280 => { ID => 65280, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(?), TLS13 => [qw(?)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(for private use), }, renegotiation_info => { ID => 65281, # Hex: 0xff01 CH => [qw(len2 len1 raw)], # Example: 0x0001 0x00 CH_TEXT => ["length", "renegotiated connection data length", "client verify data"], RX => [qw(len2 len1 raw)], RX_TEXT => ["length", "renegotiated connection data length", "server verify data"], RECOMMENDED => q(Y), TLS13 => [qw(-)], RFC => [qw(5746)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(Default value is empty => len1=0x00 => len2=0x0001), }, #65282-65535 Reserved for Private Use private_65282 => { ID => 65282, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(?), TLS13 => [qw(?)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(for private use), }, private_65283 => { ID => 65283, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(?), TLS13 => [qw(?)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(for private use), }, private_65284 => { ID => 65284, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(?), TLS13 => [qw(?)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(for private use), }, private_65285 => { ID => 65285, CH => [qw(len2 raw)], RX => [qw(len2 raw)], RECOMMENDED => q(?), TLS13 => [qw(?)], RFC => [qw(8446)], DEFAULT => [], CHECK => q(VALUE), COMMENT => q(for private use), }, ); # %TLS_EXTENSIONS # Compile a reverse Hash to %TLS_EXTENSIONS by the IDs our %TLS_ID_TO_EXTENSIONS = ( #----+------------------------------------------------------------------------- # ID extension_name #----+------------------------------------------------------------------------- FORMAT => [ "Extension '%s':", ],# define format for printf ); foreach my $key (keys %TLS_EXTENSIONS) { # compile a reverse hash for extension IDs $TLS_ID_TO_EXTENSIONS{$TLS_EXTENSIONS{$key}{ID}}[0] = $key; # store it in the fiorstv element of an array for compatibility reasons with hashes above, e.g. %TLS_SUPPORTED_GROUPS } 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 #----------+--------------------+----------------------- # ID name comment #----------+--------------------+----------------------- 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 # EX: incl. OIDs: our %tls_curves = ( #----+-------------------------------------+----+--+-------+---+------------------------- # 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 = ( # list of texts for some OIDs # 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 %cfg = ( # main data structure for configuration 'mename' => "O-Saft ", # my name pretty printed 'need_netdns' => 0, # used for better error message handling only 'need_timelocal'=> 0, # -"- 'need_netinfo' => 1, # 0: do not load Net::SSLinfo # following initialised 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 initialised 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 'time0' => 0, # current time, must be set in main 'linux_debug' => 0, # passed to Net::SSLeay::linux_debug 'verbose' => 0, # used for --v 'v_cipher' => 0, # used for --v-cipher '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 customised STARTTLS sequences 'starttls_error'=> [], # STARTTLS: Array for customised 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 'ignore_no_conn'=> 0, # 1: ignore warnings if connection fails, check target anyway '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' => [], # "-" 'slowly' => 0, # passed to Net::SSLeay::slowly 'usesni' => 1, # use SNI extensionn by default (for TLSv1 and above) 'sni_name' => undef, # if set, name to be used for connection with SNI # must be set to $host if undef and 'use_sni_name'=1 (see below) # 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_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_files' => [qw(ca-certificates.crt certificates.crt certs.pem cert.pem)], # common PEM filenames for CAs; 1st used as default # cert.pem instead of certs.pem on Android :-( 'ca_paths' => [qw(/etc/ssl/certs /usr/lib/certs /System/Library/OpenSSL /etc/tls/certs)], # common paths to PEM files for CAs; 1st used as default 'openssl_cnfs' => [qw(/etc/ssl/openssl.cnf /usr/lib/ssl/openssl.cnf /System//Library/OpenSSL/openssl.cnf /usr/ssl/openssl.cnf)], # common openssl.cnf files for openssl; 1st used as default 'openssl_cnf' => undef, # full path to openssl's openssl.cnf 'openssl_env' => undef, # environment variable OPENSSL if defined 'openssl_fips' => undef, # NOT YET USED 'openssl_msg' => "", # '-msg': option needed for openssl versions older than 1.0.2 to get the dh_parameter '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) '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 '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 'ciphermode' => 'intern',# cipher scan mode, any of 'ciphermodes' 'ciphermodes' => [qw(dump intern openssl ssleay)], # modes how to scan for ciphers; # NOTE: commands_int must contain the commands cipher_dump # cipher_intern, cipher_openssl and cipher_ssleay 'ciphers' => [], # contains all ciphers to be tested # TODO: change from cipher names to keys 'cipherrange' => 'intern',# 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. 'rfc' => # constants for ciphers defined in various RFCs "0x03000000 .. 0x030000FF, 0x03001300 .. 0x030013FF, 0x0300C000 .. 0x0300C1FF, 0x0300CC00 .. 0x0300CCFF, 0x0300D000 .. 0x0300D0FF, 0x0300FE00 .. 0x0300FFFF, ", # GREASE ciphers added in _cfg_init() 'shifted' => # constants for ciphers defined in various RFCs shifted with an offset of 64 (=0x40) Bytes "0x03000100 .. 0x0300013F, 0x0300FE00 .. 0x0300FFFF,", # see _cfg_init(): + rfc 'long' => # more lazy list of constants for cipher "0x03000000 .. 0x030013FF, 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_base'=> # constants for ciphers for SSLv2 "0x02000000, 0x02010080, 0x02020080, 0x02030080, 0x02040080, 0x02050080, 0x02060040, 0x02060140, 0x020700C0, 0x020701C0, 0x02FF0800, 0x02FF0810, 0x02FFFFFF, ", # 0x02FF0810, 0x02FF0800, 0x02FFFFFF, # obsolete SSLv2 ciphers # 0x0300FEE0, 0x0300FEE1, 0x0300FEFE, 0x0300FEFF, # obsolete FIPS ciphers 'SSLv2_rfc' => # additional constants for ciphers for SSLv2 "0x03000000 .. 0x03000002, 0x03000007 .. 0x0300002C, 0x030000FF,", 'SSLv2_rfc+'=> # additional constants for ciphers for SSLv2 long list "0x03000000 .. 0x0300002F, 0x030000FF,", 'SSLv2_FIPS'=> # additional constants for FIPS ciphers (SSLv2 and SSLv3) "0x0300FEE0, 0x0300FEE1, 0x0300FEFE, 0x0300FEFF,", 'SSLv2' => "", # constants for ciphers according RFC for SSLv2 # see _cfg_init(): SSLv2_base + SSLv2_rfc + SSLv2_FIPS # see Note(a) above also # TODO: 0x02000000, 0x02FFFFFF, # increment even only # TODO: 0x03000000, 0x03FFFFFF, # increment odd only 'SSLv2_long'=> "", # more lazy list of constants for ciphers for SSLv2 # see _cfg_init(): SSLv2_base + SSLv2_rfc+ + SSLv2_FIPS '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' => "", # SSLv3 and SSLv2 ciphers; initialised in _cfg_init() # see _cfg_init(): SSLv2_base + SSLv2_rfc+ + SSLv3 # TODO: 'SSLv3_old' => # constants for SSLv3 ciphers (without SSLv2 ciphers) # TODO: "0x03000000 .. 0x0300002F, 0x030000FF", # old SSLv3 ciphers 'TLSv10' => "", # same as SSLv3 'TLSv11' => "", # same as SSLv3 'TLSv12' => # constants for TLSv1.2 ciphers "0x0300003B .. 0x03000040, 0x03000067 .. 0x0300006D, 0x0300009C .. 0x030000A7, 0x030000BA .. 0x030000C5, 0x0300C023 .. 0x0300C032, 0x0300C072 .. 0x0300C079, 0x0300CC13 .. 0x0300CC15, 0x0300D000 .. 0x0300D005, 0x0300FFFF, ", 'TLSv13' => # constants for TLSv1.3 ciphers "0x03001301 .. 0x03001305, 0x0300FF85, 0x0300FF87, 0x030000C6, 0x030000C7, 0x0300C0B4, 0x0300C0B5, ", # GREASE ciphers added in _cfg_init() 'GREASE' => # constants for GREASE ciphers "0x03000A0A, 0x03001A1A, 0x03002A2A, 0x03003A3A, 0x03004A4A, 0x03005A5A, 0x03006A6A, 0x03007A7A, 0x03008A8A, 0x03009A9A, 0x0300AAAA, 0x0300BABA, 0x0300CACA, 0x0300DADA, 0x0300EAEA, 0x0300FAFA, ", '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,", 'intern' => "", # internal list, computed later ... # see _cfg_init(): shifted }, # 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 [ 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 ), ], # List of all extensions sent by protocol 'extensions_by_prot' => { # List all Extensions used by protocol, SSLv2 does not support extensions by design 'SSLv3' => [], # SSLv3 does not support extensions as originally defined, may be back-ported 'TLSv1' => [qw(renegotiation_info supported_groups ec_point_formats session_ticket)], 'TLSv11' => [qw(renegotiation_info supported_groups ec_point_formats session_ticket)], 'TLSv12' => [qw(renegotiation_info supported_groups ec_point_formats signature_algorithms )], 'TLSv13' => [qw(supported_versions supported_groups ec_point_formats signature_algorithms session_ticket renegotiation_info encrypt_then_mac extended_master_secret psk_key_exchange_modes key_share )], }, # extensions_by_prot # following keys for commands, naming 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 ], 'commands_notyet'=>[ # commands and checks NOT YET IMPLEMENTED qw(zlib lzo open_pgp fallback closure sgc scsv time cps_valid cipher_order cipher_weak ), ], 'commands_int' => [ # add internal commands # these have no key in %data or %checks qw( cipher cipher_intern cipher_openssl cipher_ssleay cipher_dump cipher_dh cipher_default bsi check check_sni dump ev exec help info info--v http quick list libversion sigkey sizes s_client version quit ), # 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 master_secret renegotiation resumption 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) ], '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 cipher_weak 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_weak cipher_dump cipher_intern cipher_ssleay cipher_openssl 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 cipher_default cipher_dump cipher_intern cipher_ssleay cipher_openssl 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- ocsp_response ocsp_response_status ocsp_stapling ocsp_uri ocsp_valid 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(https_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 useful 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() #------------------+---------+---------------------------------------------- 'ignore-out' => [qw(https_body)],# commands (output) to be ignored, SEE Note:ignore-out # out->option key default description #--------------------------+-----+------------------------------------------ 'out' => { # configurations for data to be printed 'disabled' => 1, # 1: print disabled ciphers 'enabled' => 1, # 1: print enabled ciphers 'header' => 0, # 1: print header lines in output 'hostname' => 0, # 1: print hostname (target) as prefix for each line 'hint_cipher' => 1, # 1: print hints for +cipher command 'hint_check' => 1, # 1: print hints for +check commands 'hint_info' => 1, # 1: print hints for +info commands 'hint' => 1, # 1: print hints for +cipher +check +info 'http_body' => 0, # 1: print received HTTP body if explicitly requested 'traceARG' => 0, # 1: (trace) print argument processing 'traceCMD' => 0, # 1: (trace) print command processing 'traceKEY' => 0, # 1: print internal variable names for %data and %checks 'traceTIME' => 0, # 1: (trace) print additional time for benchmarking 'time_absolut' => 0, # 1: (trace) --traceTIME uses absolut timestamps 'warning' => 1, # 1: print warnings 'score' => 0, # 1: print scoring 'ignore' => [qw(https_body)], # commands (output) to be ignored, SEE Note:ignore-out 'warnings_no_dups' => [qw(303 304 412)], # do not print these warnings multiple times # SEE Note:warning-no-duplicates # 410 not added, as it appears once per protocol only 'warnings_printed' => [], # list of unique warning numbers already printed # SEE Note:warning-no-duplicates 'exitcode' => 0, # 1: print verbose checks for exit status '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 'exitcode_quiet' => 0, # 1: do not print "EXIT status" message }, # out #--------------------------+-----+------------------------------------------ # use->option key default description #----------------------+-----+---------------------------------------------- 'use' => { # configurations to use or do some specials 'mx' => 0, # 1: make MX-Record DNS lookup 'dns' => 1, # 1: make DNS reverse lookup 'http' => 1, # 1: make HTTP request with default (Net::LLeay) settings # 2: make HTTP request without headers User-Agent and Accept 'https' => 1, # 1: make HTTPS request with default (Net::LLeay) settings # 2: make HTTPS request without headers User-Agent and Accept 'forcesni' => 0, # 1: do not check if SNI seems to be supported by Net::SSLeay 'sni' => 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 Net::SSLhello::checkSSLciphers only) 'lwp' => 0, # 1: use perls LWP module for HTTP checks # TODO: NOT YET IMPLEMENTED 'alpn' => 1, # 0: do not use -alpn option for openssl 'npn' => 1, # 0: do not use -nextprotoneg option for openssl 'reconnect' => 1, # 0: do not use -reconnect option for openssl 'extdebug' => 1, # 0: do not use -tlsextdebug option for openssl 'cert' => 1, # 0: do not get data from certificate 'no_comp' => 0, # 0: do not use OP_NO_COMPRESSION for connetion in Net::SSLeay 'ssl_lazy' => 0, # 1: lazy check for available SSL protocol functionality (Net::SSLeay problem) 'nullssl2' => 0, # 1: complain if SSLv2 enabled but no ciphers accepted 'ssl_error' => 1, # 1: stop connecting to target after ssl-error-max failures 'experimental' => 0, # 1: use, print experimental functionality 'exitcode' => 0, # 1: exit with status code if any check is "no" # see also 'out'->'exitcode' }, # use #----------------------+-----+---------------------------------------------- # SEE Note:tty # following keys used when --tty (or similar) option was used # i.g. the code will use the values only if defined $cfg{'tty'}->{'width'} # option key default description #------------------+---------+---------------------------------------------- 'tty' => { # configuration for tty and behaviour according tty 'width' => undef, # screen width (columns) of the tty # NOTE: the value undef is used to detect if the # option --tty was used 'ident' => 2, # left ident spaces, used to replace leftmost 8 spaces 'arrow' => "↲", # "continous arrow when line is split # ← 0x2190, ↲ 0x21b2, ⮠ 0x2ba0, ⤶ 0x2936, ⤸ 0x2938, # NOTE: it's mandatory to have: "use utf8" }, # tty # 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)], # not yet used: csv html json ssv tab xml fullxml '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, prot, path, etc.) # to be processed; anon. list, each element is # array; first element contains defaults (see # @target_defaults below) 'port' => undef, # 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: some servers do not connect SSL within # this time, this may result in ciphers # marked as "not supported" # it's recommended to set timeout =3 or # higher, which results in a performance # bottleneck, obviously # see 'sslerror' settings and options also #----------------+---------------------------------------------------------- 'openssl' => { # configurations for various openssl functionality # same data structure as Net::SSLinfo's %_OpenSSL_opt # not all values used yet # default value 1 means supported by openssl, will be # structure initialised correctly in _check_openssl() # which uses Net::SSLinfo::s_client_check() #------------------+-------+------------------------------------------- # key (=option) supported=1 warning message if option is missing #------------------+-------+------------------------------------------- '-CAfile' => [ 1, "using -CAfile disabled" ], '-CApath' => [ 1, "using -CApath disabled" ], '-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, "<>" ], '-nbio_test' => [ 1, "<>" ], '-tlsextdebug' => [ 1, "TLS extension missing or wrong"], '-client_sigalgs' => [ 1, "<>" ], '-record_padding' => [ 1, "<>" ], '-no_renegotiation' => [ 1, "<>" ], '-legacyrenegotiation' => [ 1, "<>" ], '-legacy_renegotiation' => [ 1, "<>" ], '-legacy_server_connect' => [ 1, "<>" ], '-no_legacy_server_connect' => [ 1, "<>" ], #------------------+-------+------------------------------------------- }, # openssl 'openssl_option_map' => { # map our internal option to openssl option; used our Net:SSL* # will be initialised from %prot }, 'openssl_version_map' => { # map our internal option to openssl version (hex value); used our Net:SSL* # will be initialised from %prot }, # ssleay->option default description #----------------------+-----+---------------------------------------------- 'ssleay' => { # configurations for various Net::SSLeay functionality # 1: if available is default (see _check_functions()) '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' # see 'use' above '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 }, # ssl_error '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' => [ # list of known values qw(cnark sslaudit sslcipher ssldiagnos sslscan dump ssltest ssltest-g sslyze testsslserver thcsslcheck openssl simple full compact quick owasp osaft o-saft) ], # SSLAudit, THCSSLCheck, TestSSLServer are converted using lc() # osaft o-saft are used for comfort '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->type RegEx #----------------------+---------------------------------------------------- '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 strings to anonymise in output 'anon_output' => '', # pattern for strings to be anonymised in output # SEE Note:anon-out # 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 cipher-suite names # 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 # RegEx for matching various strings '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 'security' => '(?:HIGH|MEDIUM|LOW|WEAK|NONE)', # well known "security" strings, should be used case-insensitive '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_AA' => '^(TLS(?:v?13)?[_-](?:AES|CHACHA20)[_-])', # newer (2021 and later) openssl use strange names for TLSv1.3 '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)[_-]|(?:(?:EC)?DHE-)?PSK[_-]CHACHA)', # all ECDHE-PSK-CHACHA* DHE-PSK-CHACHA* and PSK-CHACHA* are C too '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|ECDS[AS]|GOST|IDEA|SEED|CECPQ)', # PCT are not SSL/TLS; will produce 'miss' in internal tests # 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 to 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, SEE Note:hints # key for hints must be same as a command (without leading +), otherwise # it will not be used automatically. # 'key' => "any string, may contain \t and \n", #--------------+-------------------------------------------------------- 'help=warnings' => "consider building the file using: 'make warnings-info'", 'renegotiation' => "checks only if renegotiation is implemented serverside according RFC 5746 ", 'drown' => "checks only if the target server itself is vulnerable to DROWN ", 'robot' => "checks only if the target offers ciphers vulnerable to ROBOT ", 'cipher' => "+cipher : functionality changed, please see '$cfg__me --help=TECHNIC'", 'cipherall' => "+cipherall : functionality changed, please see '$cfg__me --help=TECHNIC'", 'cipherraw' => "+cipherraw : functionality changed, please see '$cfg__me --help=TECHNIC'", #--------------+-------------------------------------------------------- }, # 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 information '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 ) ], #------------------+-----------------+-------------------------------------- 'files' => { # list of files used in the tool 'RC-FILE' => "", # computed at startup 'SELF' => "o-saft.pl", 'coding' => "coding.txt", 'glossary' => "glossary.txt", 'help' => "help.txt", 'links' => "links.txt", 'rfc' => "rfc.txt", 'tools' => "tools.txt", # following are used in o-saft.tcl, but are generate with o-saft-man.pm # the keys --help* are used as pattern # TODO: hardcoded docs/ and o-saft.pl should be configurable '--help' => "docs/o-saft.pl.--help", '--help=alias' => "docs/o-saft.pl.--help=alias", '--help=checks' => "docs/o-saft.pl.--help=checks", '--help=commands' => "docs/o-saft.pl.--help=commands", '--help=data' => "docs/o-saft.pl.--help=data", '--help=glossar' => "docs/o-saft.pl.--help=glossar", '--help=opts' => "docs/o-saft.pl.--help=opts", '--help=regex' => "docs/o-saft.pl.--help=regex", '--help=rfc' => "docs/o-saft.pl.--help=rfc", '--help=warnings' => "docs/o-saft.pl.--help=warnings", '--help=ciphers-text' => "docs/o-saft.pl.--help=ciphers-text", }, # files #------------------+-----------------+-------------------------------------- 'done' => {}, # defined in caller ); # %cfg our %target_desc = ( # description of table used for printing targets #--------------+----------------------------------------------------------- # 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, ]; # <> just for documentation when printed with --v, --trace, etc. 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 #_____________________________________________________________________________ #_________________________________________________________ internal methods __| # SEE Perl:Undefined subroutine *_warn = sub { print(join(" ", "**WARNING:", @_), "\n"); return; } if not defined &_warn; *_dbx = sub { print(join(" ", "#dbx#" , @_), "\n"); return; } if not defined &_dbx; *_trace = sub { local $\ = undef; my $func = shift; # avoid space after :: below print(join(" ", "#$cfg{'me'}::$func", @_), "\n") if (0 < $cfg{'trace'}); return; } if not defined &_trace; *_trace1 = sub { _trace(@_) if (1 < $cfg{'trace'}); return; } if not defined &_trace1; *_trace2 = sub { _trace(@_) if (2 < $cfg{'trace'}); return; } if not defined &_trace2; *_trace3 = sub { _trace(@_) if (3 < $cfg{'trace'}); return; } if not defined &_trace3; #_____________________________________________________________________________ #__________________________________________________________________ methods __| =pod =head2 tls_text2key($text) Convert text to internal key: 0x00,0x26 -> 0x03000026 =head2 tls_key2text($key) Convert internal key to text: 0x03000026 -> 0x00,0x26 =head2 tls_const2text($constant_name) Convert TLS constant name to text (just replac _ by space). =cut sub tls_text2key { my $txt = shift; $txt =~ s/(,|0x)//g; if (4 < length($txt)) { $txt = "0x02$txt"; # SSLv2 } else { $txt = "0x0300$txt"; # SSLv3, TLSv1.x } return $txt; } sub tls_key2text { my $key = shift; if ($key =~ m/^0x0300/) { $key =~ s/0x0300//; # 03000004 -> 0004 } else { $key =~ s/^0x02//; # 0x02030080 -> 030080 } $key =~ s/(..)/,0x$1/g; # 0001 -> ,0x00,0x04 $key =~ s/^,//; # ,0x00,0x04 -> 0x00,0x04 $key = " $key" if (10 > length($key)); return "$key"; } sub tls_const2text { my $c=shift; $c =~ s/_/ /g; return $c; } =pod =head2 get_ciphers_range($range) Get cipher suite hex values for given C<$range>. =head2 get_cipher_owasp($cipher) Get OWASP rating of given C<%cipher>. =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_ciphers_range { #? retrun array of cipher-suite hex values for given 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()\t= @all"); return @all; } # get_ciphers_range sub get_cipher_owasp { #? return OWASP rating for cipher suite name (see $cfg{regex}->{{OWASP_*} my $cipher = shift; my $sec = "miss"; return $sec if not defined $cipher; # defensive programming (key missing in %ciphers) return $sec if ($cipher =~ m/^\s*$/); # .. # 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'}/); } $sec = "A" if ($cipher =~ /$cfg{'regex'}->{'OWASP_AA'}/); # some special for TLSv1.3 only, aleways secure # TODO: implement when necessary: notOWASP_A, notOWASP_B, notOWASP_C, notOWASP_D return $sec; } # get_cipher_owasp 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 separator 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 RFC 2246/RFC 5246: 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 # 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; } =pod =head2 osaft::osaft_sleep($wait) Wrapper to simulate "sleep" with perl's select. =head2 osaft::printhint($cmd,@text) Print hint for specified command, additionl text will be appended. =cut sub osaft_sleep { #? wrapper for IO::select my $wait = shift; select(undef, undef, undef, $wait); ## no critic qw(BuiltinFunctions::ProhibitSleepViaSelect) return; } # osaft_sleep sub printhint { #? 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 =pod =head2 osaft::test_cipher_regex( ) Internal test function: apply regex to intended text/list. =cut #_____________________________________________________________________________ #____________________________________________________ internal test methods __| sub __regex_head { return sprintf("= %s\t%s\t%s\t%s", "PFS", "OWASP", "owasp", "cipher"); } sub __regex_line { return "=------+-------+-------+---------------------------------------"; } sub test_cipher_regex { #? check regex if cipher supports PFS, uses internal sub and not regex directly local $\ = "\n"; print " === internal data structure: various RegEx to check cipher properties === = = Check RegEx to detect ciphers, which support PFS using the internal function = ::_is_ssl_pfs() . \$cfg{'regex'}->{'PFS'}: # match ciphers supporting PFS $cfg{'regex'}->{'PFS'} = = Check to which RegEx for OWASP scoring a given cipher matches. = \$cfg{'regex'}->{'OWASP_NA'}: # unrated in OWASP TLS Cipher Cheat Sheet (2018) $cfg{'regex'}->{'OWASP_NA'} \$cfg{'regex'}->{'OWASP_C'}: # 1st legacy $cfg{'regex'}->{'OWASP_C'} \$cfg{'regex'}->{'OWASP_B'}: # 2nd broad compatibility $cfg{'regex'}->{'OWASP_B'} \$cfg{'regex'}->{'OWASP_A'}: # 3rd best practice $cfg{'regex'}->{'OWASP_A'} \$cfg{'regex'}->{'OWASP_D'}: # finally brocken ciphers, overwrite previous $cfg{'regex'}->{'OWASP_D'} \$cfg{'regex'}->{'OWASP_AA'}: # last secure TLSv1.3 $cfg{'regex'}->{'OWASP_AA'} = "; print __regex_head(); print __regex_line(); foreach my $key (sort (OSaft::Ciphers::get_keys_list())) { my $ssl = OSaft::Ciphers::get_ssl( $key); my $cipher = OSaft::Ciphers::get_name($key); my $is_pfs = (::_is_ssl_pfs($ssl, $cipher) eq "") ? "no" : "yes"; my @o = ('', '', '', '', ''); # following sequence of check should be the same as in get_cipher_owasp() $o[4] = "-?-" if ($cipher =~ /$cfg{'regex'}->{'OWASP_NA'}/); $o[2] = "C" if ($cipher =~ /$cfg{'regex'}->{'OWASP_C'}/); $o[1] = "B" if ($cipher =~ /$cfg{'regex'}->{'OWASP_B'}/); $o[0] = "A" if ($cipher =~ /$cfg{'regex'}->{'OWASP_A'}/); $o[3] = "D" if ($cipher =~ /$cfg{'regex'}->{'OWASP_D'}/); $o[0] = "A" if ($cipher =~ /$cfg{'regex'}->{'OWASP_AA'}/); printf(" %s\t%s\t%s\t%s\n", $is_pfs, get_cipher_owasp($cipher), join("", @o), $cipher); } print __regex_line(); print __regex_head(); print " = PFS values: = yes cipher supports PFS = no cipher does not supports PFS = OWASP values: = x value A or B or C or D or -?- as returned by get_cipher_owasp() = miss cipher not matched by any RegEx, programming error = owasp values: = xx list of all matching OWASP_x RegEx "; return; } # test_cipher_regex sub test_cipher_sort { #? check sorting cipher according strength # TODO: see ../o-saft-dbx.pm _yeast_ciphers_sorted() return; } # test_cipher_sort #_____________________________________________________________________________ #___________________________________________________ initialisation methods __| sub _prot_init_value { #? initialise 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_AA'} = 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 { #? initialise dynamic settings in %cfg, copy data from %prot # initialise targets with entry containing defaults push(@{$cfg{'targets'}}, @target_defaults); $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'})]; # initialise alternate protocols and curves for cipher checks $cfg{'cipher_alpns'}= [split(/,/, $cfg{'protos_next'})]; $cfg{'cipher_npns'} = [split(/,/, $cfg{'protos_next'})]; # 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'}); # initialise cipherranges $cfg{'cipherranges'}->{'SSLv2'} = $cfg{'cipherranges'}->{'SSLv2_base'} . $cfg{'cipherranges'}->{'SSLv2_rfc'} . $cfg{'cipherranges'}->{'SSLv2_FIPS'}; $cfg{'cipherranges'}->{'SSLv2_long'} = $cfg{'cipherranges'}->{'SSLv2_base'} . $cfg{'cipherranges'}->{'SSLv2_rfc+'} . $cfg{'cipherranges'}->{'SSLv2_FIPS'}; $cfg{'cipherranges'}->{'SSLv3_SSLv2'} = $cfg{'cipherranges'}->{'SSLv2_base'} . $cfg{'cipherranges'}->{'SSLv2_rfc+'} . $cfg{'cipherranges'}->{'SSLv3'}; $cfg{'cipherranges'}->{'TLSv10'} = $cfg{'cipherranges'}->{'SSLV3'}; $cfg{'cipherranges'}->{'TLSv11'} = $cfg{'cipherranges'}->{'SSLV3'}; $cfg{'cipherranges'}->{'rfc'} .= $cfg{'cipherranges'}->{'GREASE'}; $cfg{'cipherranges'}->{'shifted'} .= $cfg{'cipherranges'}->{'rfc'}; $cfg{'cipherranges'}->{'TLSv13'} .= $cfg{'cipherranges'}->{'GREASE'}; $cfg{'cipherranges'}->{'intern'} = $cfg{'cipherranges'}->{'shifted'}; return; } # _cfg_init sub _cmd_init { #? initialise dynamic settings in %cfg for commands foreach my $key (sort keys %cfg) { # well-known "summary" commands push(@{$cfg{'commands_cmd'}}, $key) if ($key =~ m/^cmd-/); } # SEE Note:Testing, sort @{$cfg{'commands_cmd'}} = sort(@{$cfg{'commands_cmd'}}); @{$cfg{'cmd-info--v'}} = sort(@{$cfg{'cmd-info--v'}}); return; } # _cmd_init sub _dbx_init { #? initialise 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 initialisations 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(); # initallise WEAK, LOW, MEDIUM, HIGH, default, pfs, protocol _cfg_init(); # initallise dynamic data in %cfg _cmd_init(); # initallise dynamic commands in %cfg _dbx_init(); # initallise debugging data in %dbx foreach my $k (keys %data_oid) { $data_oid{$k}->{val} = "<>"; # set a default value } return; } # _osaft_init #_____________________________________________________________________________ #_____________________________________________________________________ main __| sub _main_lib { #? print own documentation or special required one my @argv = @_; push(@argv, "--help") if (0 > $#argv); binmode(STDOUT, ":unix:utf8"); binmode(STDERR, ":unix:utf8"); # got arguments, do something special while (my $arg = shift @argv) { # ----------------------------- commands if ($arg =~ m/^--?h(?:elp)?$/) { OSaft::Text::print_pod($0, __PACKAGE__, $SID_osaft); exit 0; } if ($arg =~ /^version$/) { print "$SID_osaft\n"; next; } if ($arg =~ /^[-+]?V(ERSION)?$/) { print "$VERSION\n"; next; } if ($arg =~ m/^--(?:test[_.-]?)regex/) { $arg = "--test-regex"; printf("#$0: direct testing not yet possible, please try:\n o-saft.pl $arg\n"); } } exit 0; } # _main_lib sub osaft_done {}; # dummy to check successful include _osaft_init(); # complete initialisations ## PACKAGE } #_____________________________________________________________________________ #_____________________________________________________ public documentation __| =pod =head1 SEE ALSO # ... =head1 VERSION 2.28 2022/11/04 =head1 AUTHOR 28-dec-15 Achim Hoffmann =cut #_____________________________________________________________________________ #_____________________________________________________________________ self __| _main_lib(@ARGV) if (not defined caller); 1; O-Saft-22.11.22/t/000077500000000000000000000000001433765727300133165ustar00rootroot00000000000000O-Saft-22.11.22/t/.perlcriticrc000066400000000000000000000416451433765727300160160ustar00rootroot00000000000000#! /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.15 22/11/06 12:22:40 # #? 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 [-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 #[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::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 #[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. select 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::RequireBlockGrep] # Message: # The expression forms of `grep' and `map' are awkward and hard to read. # CHECK DISABLED # other people, other opinions [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: # Missing "OPTIONS" section in POD at line ... # CHECK DISABLED # cause we consider following correct and useful: my $last = ''; # Perl::Critic is uses a strange list of required sections in POD. # Also there is no possibility to disable Perl::Critic's required # sections, hence generally disabled. [-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-22.11.22/t/Makefile000077500000000000000000001141531433765727300147660ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing O-Saft #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile.help Makefile.pod #? make help.test #? # HACKER's INFO # For details please see # ../Makefile Makefile.help Makefile.template # # Naming conventions for t/Makefile* # * variable names have the prefix TEST and HELP . # * target names for public use have the prefix test. # * individual, special targets have the prefix _test (exceptions exist) # # Summary variables extended in each t/Makefile* # ALL.includes - list of Makefiles # ALL.inc.type - list of types (should be suffix of Makefile's name) # ALL.help.tests - list of documentation (help) texts # ALL.tests - list of targets for testing # ALL.tests.log - list of targets for testing writing to logfile # # Variables specific for each t/Makefile* # _SID.myTYPE - version number # _MYSELF.myTYPE - name of current file # HELP.myTYPE - documentation (help) text for the corresponding file # HELP.myTYPE.all - list of all targets for the corresponding file # HELP.myTYPE.internal - some more documentation (help) text # where myTYPE above is the suffix of the Makefile's filename # # Each t/Makefile* may also redefine following variables # HELP_TYPE - suffix (and type) of Makefile* # HELP_HEAD - descriptive header line, set to HELP_NAME, HELP_RULE # # Special targets for documentation (help) in t/Makefile* # help.test.% - print individual documentation using $(HELP.myTYPE) # help.test.%.all - print all targets using $(HELP.myTYPE.all) # help.test.%.internal - print details using $(HELP.myTYPE.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.142 22/11/13 13:26:27 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.test = general testing targets _SID.test := 1.142 _MYSELF.test := t/Makefile ALL.includes += $(_MYSELF.test) ALL.inc.type += test ALL.help.tests += help.test export OSAFT_MAKE := avoid writing random data (like date and time string) export LANG := C # LANG ensures same messages and sorting everywhere first-test-target-is-default: help.test ifndef ALL.Makefiles -include t/Makefile.inc # defines variables if called directly (not from ../Makefile) endif help.test: HELP_TYPE = test help.test-v: HELP_TYPE = test help.test-vv: HELP_TYPE = test help.test.all: HELP_TYPE = test help.test.test: HELP_TYPE = test help.test.test-v: HELP_TYPE = test help.test.test-vv: HELP_TYPE = test help.test.test.all: HELP_TYPE = test help.test: HELP_HEAD = $(HELP_RULE) help.test.%: HELP_HEAD = $(HELP_RULE) #_____________________________________________________________________________ #________________________________________________________________ variables __| ifndef test-remove-environment-variables # most environment variables should be ignored, to avoid unexpected # behaviour and to keep our list of variables clean; # forst define list of required variables, then get list of existing # environment variable and remove all except the required ones $(eval _keep = OSAFT_MAKE LANG \ DISPLAY HOME PATH PWD SHELL TERM USER NLSPATH \ DT_RUNPATH DT_RPATH DT_NEEDED \ DYLD_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH \ LD_CONFIG LD_LIBRARY_PATH LD_PRELOAD LD_RUN_PATH LD_DEBUG \ LD_TRACE_LOADED_OBJECTS LD_TRACE_LOADED_OBJECTS_ALL LD_TRACE_PRELINKING \ LIBPATH RPATH RUNPATH SHLIB_PATH \ OPENSSL_CONF OPENSSL_FIPS OPENSSL_ENGINES OPENSSL \ OPENSSL_ALLOW_PROXY OPENSSL_ALLOW_PROXY_CERTS \ ) $(eval _env = $(shell printenv | awk -F= '{print $$1}')) $(foreach _var, $(filter-out $(_keep),$(_env)), $(eval undefine $(_var))) $(eval undefine _keep) $(eval undefine _env) test-remove-environment-variables = done endif # store -n (dry-run) option in own variable TEST.make-n := $(if $(findstring n,$(firstword -$(MAKEFLAGS))),-n) # internal variables TEST.dir := t TEST.logdir = $(TEST.dir)/log TEST.logtxt := <> TEST.symlinks := ../contrib ../osaft.pm ../.o-saft.pl ../Net ../docs ../OSaft # following may be redefined in included t/Makefile* #TEST.init := --header #TEST.args := # variable 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 = # $(SRC.rc) may not be defined here, hence hardcoded ifndef SRC.contrib.dir SRC.contrib.dir = contrib endif # Tracing just the log-targets is special. Using $(TRACE.target) is not an # option, because it would als change the final target called with $(MAKE) . # Hence an additional variable is used. # TODO: not public, not documented, variable needs to be defined here TRACE.target.log = # example = echo "\# $*\tcalling: $(MAKE) -s testcmd-$*" TEST.today := $(shell date +%Y""%m%d) # current date in ISO format # need a usable way to change diff program; EXE.diff may be set on command-line EXE.log-diff := diff EXE.log-xxdiff := xxdiff --geometry 1600x1000 EXE.log-mgdiff := mgdiff EXE.log-tkdiff := tkdiff EXE.diffs := diff xxdiff mgdiff tkdiff EXE.diff := tkdiff EXE.log-diff = $(EXE.log-tkdiff) # chaneg EXE.log-diff to use another program # need a usable way to change generator for man-pages EXE.gendoc.perldoc := perldoc EXE.gendoc.pod2man := pod2man EXE.gendoc := $(EXE.gendoc.perldoc) # default filter for testarg-%.log targets EXE.log-filterarg := cat # default filter for testcmd-%.log targets EXE.log-filtercmd := cat _EXE.grep-opt := -q # grep (mainly used in message-% target) should not report matching lines # variable can be reset or redifined for more verbose output _EXE.sort-opt := -n -f # newer GNU sort (~2018) changed the default behaviour, for example # case-sensitivity, these options do the traditional sort # TODO: need to check first if sort supports these options _EXE.perldoc-opt := -n nroff -T # newer perldoc prints with plain text format by default # -n nroff enforced the traditional behaviour with ASCII-escapes _EXE.pod2man-opt := --utf8 # --date=DATESTRING # will be used for testing to avoid diff in generated files # define script or parts of it as variables, for better human readability # SEE Make:target matching # _EXE.macro_by_line.awk - extract all variable names # _EXE.target_by_line.awk - extract all target names # _EXE.target_to_arr.awk - extract target names and store uniquely in arr[] # _EXE.print_arr_END.awk - print collected data from arr[] # _EXE.print_file.awk - either print separator line or the filename TEST.target_prefix := [a-zA-Z][_a-zA-Z.] # matching target names not starting with _ _EXE.macro_by_line.awk := /^[a-zA-Z_][a-zA-Z_.]* *=/{sub(/=/,"",$$1);print $$1} _EXE.target_by_line.awk:= /^[a-zA-Z_][a-zA-Z_.]* *:/{sub(/:/,"",$$1);print $$1} _EXE.target_to_arr.awk = /^.*%/{next} /^$(TEST.target_prefix)*/{arr[$$1]=1} _EXE.print_arr_END.awk := END{for(idx in arr){print idx}} _EXE.print_file.awk := (FNR==1){ x="";for(i=1;i<62;i++){x=sprintf("%s%c",x,"-")};print "\n\t\t\#"x} # if target was test*-compare-v or test*-move-v TRACE.target is not empty, so # checking this variable if not empty is sufficent to print verbose information # not tested if following defines could be written as macros # SEE Make:defines with commands define EXE.log-compare cd $(TEST.logdir) && \ echo "# compare "`ls $(TEST.target_prefix)*.log$(TEST.log-suffix) | wc -l`" file ..." && \ for f in $(TEST.target_prefix)*.log; do \ [ -f $${f}$(TEST.log-suffix) ] || continue ; \ [ -n '$(TRACE.target)' ] && echo "# $(TEST.logdir)/$${f} ..." ; \ $(EXE.log-diff) $${f} $${f}$(TEST.log-suffix) >/dev/null 2>&1 ; \ done endef define EXE.log-compare-hint echo "" echo "# for informations and to show differences with $(EXE.diff), use:" echo " $(MAKE_COMMAND) help.test.log-info" echo " $(MAKE_COMMAND) $(MAKECMDGOALS)-compare" echo " $(MAKE_COMMAND) $(MAKECMDGOALS)-compare-v" echo " $(MAKE_COMMAND) $(MAKECMDGOALS)-compare TEST.log-suffix=$(TEST.log-suffix)" endef define EXE.log-move cd $(TEST.logdir) && \ for f in $(TEST.target_prefix)*.log; do \ [ -f $${f}$(TEST.log-suffix) ] || continue ; \ [ -n '$(TRACE.target)' ] && echo "# $(TEST.logdir)/$${f} ..." ; \ mv $${f}$(TEST.log-suffix) $${f} ; \ done endef # FIXME: does not set _stub properly if $* is set define EXE.log-move-hint _stub="log" $(eval _stub="log") $(eval $(shell [ -n "$*" ] && _stub="$*.log" )) echo "" echo "# for informations and to move new files to .log , use:" echo " $(MAKE_COMMAND) help.test.log-info" echo " $(MAKE_COMMAND) test.$(_stub)-move" echo " $(MAKE_COMMAND) test.$(_stub)-move TEST.log-suffix=$(TEST.log-suffix)" endef HELP.test = $(_NL)\ \# The term '%' in the targets names described here, may be any of:$(_NL)\ \# $(ALL.inc.type)$(_NL)\ \#$(_NL)\ \# Following variables are intended to be used on command line:$(_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)\ \# TEST.target_prefix - prefix of log-filename; see help.test.log-info$(_NL)\ \# TEST.log-suffix - suffix of log-filename; see help.test.log-info$(_NL)\ \#$(_NL)\ \# Notes about some spezial targets:$(_NL)\ \# help.test - automatically generated target; alias for help.test.test$(_NL)\ \# help.test.test.alls -$(_NL)\ \# help.test.test.all - be prepared for huge output$(_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. # following variable contains (huge) list of all available targets HELP.test.test.all = $(_NL)\ \# $(words $(ALL.tests)) targets for tests:$(_NL)\ $(ALL.tests)$(_NL)\ \#$(_NL)\ \# $(words $(ALL.tests.log)) targets which write results to logfiles:$(_NL)\ $(ALL.tests.log)$(_NL)\ \#$(_NL)\ \# summary targets for tests:$(_NL)\ $(ALL.help.tests:help.%=%)$(_NL)\ \#$(_NL)\ \# for more target and details, following targets can be used$(_NL)\ $(foreach target,$(ALL.inc.type),t-$(target))$(_NL) HELP.test.test = $(HELP.test) HELP.test.all = $(HELP.test.test.all) help.test: help.test.test help.test.all: help.test.test.all @$(TRACE.target) # convenience to satisfy help.test.all # help.test.test would only print the HELP-* texts from herein. # All other tests from the individual t/Makefile.* files have their own HELP-* # variable their. help.test.test should also print hints how to get information # about these other targets. Therefore the auxiliary target _help_list exists # in Makefile which is used as dependency here. help.test.test: _help_list help.test.test-v: _help_list help.test.test-v-v: _help_list #_____________________________________________________________________________ #____________________________________________ target for help in t/Makefile*__| HELP-help.test.test.all = print available targets for tests from all Makefiles HELP-help.test.test.alls = print available targets for tests one per line #HELP-help.test.test.all-n = show command for all available test targets HELP-help.test.%.all = print available individual targets for tests '%' from Makefile.* # experimental: some targets print too many shell commands help.test.test.all-n: @$(TRACE.target) @$(MAKE) -n $(ALL.tests) help.test.test.alls: @$(TRACE.target) @echo " # $(words $(ALL.tests)) targets for tests:" @echo $(ALL.tests) | $(EXE.wordperline) | sort $(_EXE.sort-opt) @echo "" help.test.%.all: @$(TRACE.target) @echo " # individual targets for testing $* :" @echo $(ALL.test.$*) | $(EXE.wordperline) | sort $(_EXE.sort-opt) @echo "" @echo "$(HELP.test.$*.all)" HELP-help.test.%.internal = show settings for tests '%' from Makefile.* help.test.%.internal: @$(TRACE.target) @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 " # -------------------------------------------------------------" ALL.help.tests.all = $(foreach type,$(ALL.inc.type), help.test.$(type).all) ALL.help.test.internal = $(foreach type,$(ALL.inc.type), help.test.$(type).internal) help.test.targets: @$(MAKE) -s $(ALL.help.tests.all $(ALL.help.test.internal) #_____________________________________________________________________________ #_____________________________________________________ internal test target __| HELP-_internal = _____________________________________ internal test target _ HELP-testcmd-test.internal = print GNU Make's internals and global project settings # dummy ' to keep some stupid syntax highlighting happy # internal information (nothing related to $(Project)) # NOTE: $(_SID*) variables indicate if a sub-makefile was included. # NOTE: $$ needs to be used to ensure that the variables are evaluated when # the targets executes and not when the Makefile is read. # NOTE: when target testcmd-test.internal is called with -n ; the command: # @echo '# $$(MAKE) = $(MAKE)' # it will produce output: # # $(MAKE) = make # SEE GNU Make:MAKE vs. MAKE_COMMAND # TODO: list of $(_SID.*) should be generated using $(ALL.inc.type) test.file-1: test,file-2: test_file-3: testcmd-test.internal: test.file-1 test,file-2 test_file-3 @$(TRACE.target) @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.cipher) = $(_SID.cipher)' @echo '# $$(_SID.make) = $(_SID.make)' @echo '# $$(_SID.exit) = $(_SID.exit)' @echo '# $$(_SID.init) = $(_SID.init)' @echo '# $$(_SID.misc) = $(_SID.misc)' @echo '# $$(_SID.cmd) = $(_SID.cmd)' @echo '# $$(_SID.dev) = $(_SID.dev)' @echo '# $$(_SID.mod) = $(_SID.mod)' @echo '# $$(_SID.etc) = $(_SID.etc)' @echo '# $$(_SID.ext) = $(_SID.ext)' @echo '# $$(_SID.cgi) = $(_SID.cgi)' @echo '# $$(_SID.gen) = $(_SID.gen)' @echo '# $$(_SID.hlp) = $(_SID.hlp)' @echo '# $$(_SID.inc) = $(_SID.inc)' @echo '# $$(_SID.opt) = $(_SID.opt)' @echo '# $$(_SID.pod) = $(_SID.pod)' @echo '# $$(_SID.tcl) = $(_SID.tcl)' @echo '# $$(_SID.docker) = $(_SID.docker)' @echo '# $$(_SID.legacy) = $(_SID.legacy)' @echo '# $$(_SID.template) = $(_SID.template)' @echo '# show some private make variables:' @echo '# $$(PWD) = $(PWD)' @echo '# $$(PWD.dir) = $(notdir $(PWD))' @echo '# $$(ALL.includes) = $(ALL.includes)' @echo '# $$(ALL.inc.type) = $(ALL.inc.type)' @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 '# show some make variables:' @echo '# $$@ = $@ #' @echo '# $$< = $< #' @echo '# $$? = $? #' @echo '# $$^ = $^ #' @echo '# $$+ = $+ #' @echo '# $$| = $| #' @echo '# $$% = $% #' @echo '# $$* = $* #' @echo '# $$> = $> #' @echo '# $$- = $- #' @echo '# $$D = $D #' @echo '# $$F = $F #' @echo '# $$T = $T #' @echo '# not shown: $$(%D) $$(?D) $$(@D) $$(*D) $$( ` [ ] # # 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 _FORCE: # target succeeds if message is there message-%: @$(TRACE.target) @-if expr "$(TEST.args)" ":" "^TODO" >/dev/null ; then \ echo "$@: $(TEST.args)"; \ else \ echo "$(TEST.rc)" > $(TEST.tmp.rc) ; \ echo "cd $(TEST.dir) && $(EXE.pl) $(TEST.init) $(TEST.args) 2>&1 | grep $(_EXE.grep-opt) $* " ; \ cd $(TEST.dir) && $(EXE.pl) $(TEST.init) $(TEST.args) 2>&1 | grep $(_EXE.grep-opt) $* ; \ _status=$$? ; \ rm -f $(TEST.tmp.rc) ; \ exit $$_status ; \ fi # following removed from above, too noicy: # echo "echo '$(TEST.rc)' > $(TEST.tmp.rc)" ; # target succeeds if message is missing # TODO: need more examples beside those in t/Makefile.cgi no.message-%: @$(TRACE.target) @echo "$(TEST.rc)" > $(TEST.tmp.rc) cd $(TEST.dir) && $(EXE.pl) $(TEST.init) $(TEST.args) 2>&1 | awk '/ $*/{exit 1}' @rm -f $(TEST.tmp.rc) # Simple target to calL: $(EXE.pl) $(TEST.init) $(TEST.args) testarg-%: @$(TRACE.target) -cd $(TEST.dir) && $(EXE.pl) $(TEST.init) $(TEST.args) # SEE Make:--dry-run # following pattern rule should be unified with testcmd-%.log testarg-%.log: $(TEST.logdir) _FORCE @$(TRACE.target) @$(TRACE.target.log) @$(eval _NEW.log := $(TEST.logdir)/$@-$(TEST.today)) @expr "$(MAKEFLAGS)" : n >/dev/null \ && echo "$(MAKE) $(MFLAGS) -s testarg-$* 2>&1 | $(EXE.log-filterarg) > $@ 2>&1" \ || $(MAKE) $(MFLAGS) -s testarg-$* 2>&1 | $(EXE.log-filterarg) > $@ 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)/testarg-$(*)* # TODO: target should fail if there is a diff # 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 could not be provided in a make variable all together, because # each command may consist of space separated words like: "+info --header". # Hence each command is defined in the variable TEST.args, which will be set # for an individual target, for example: testcmd-001 .There is 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 GNU Make), 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) # # EXE.pl must be defined wherever testcmd-% is used/referenced # 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-%: @$(TRACE.target) -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. # diff's STDERR is discarded (may return: "file does not exist"). # The target's command output is piped to $(EXE.log-filtercmd), which is cat # by default. This filter can be redefined as needed. SEE Make:OSAFT_MAKE # NOTE: all target commands are prefixed with - this avoids that make reports # errors if the command fails (as failture is intended, somehow). # NOTE: testcmd-%.log called from within t/ may return: is up to date. testcmd-%.log: $(TEST.logdir) _FORCE @$(TRACE.target) @$(TRACE.target.log) @$(eval _NEW.log := $(TEST.logdir)/$@-$(TEST.today)) @expr "$(MAKEFLAGS)" : n >/dev/null \ && echo "$(MAKE) $(MFLAGS) -s testcmd-$* 2>&1 | $(EXE.log-filtercmd) > $@ 2>&1" \ || $(MAKE) $(MFLAGS) -s testcmd-$* 2>&1 | $(EXE.log-filtercmd) > $@ 2>&1 @-diff $(TEST.logdir)/$@ $@ >/dev/null 2>&1 || echo "diff $(TEST.logdir)/$@ ..." @-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 # 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-%: @$(TRACE.target) @$(eval _targets = $(shell echo "$(ALL.tests)" | $(EXE.wordperline) | awk '/$*/{print $$0;}')) @echo "# $(_targets) #" test.pattern-%: @$(TRACE.target) @$(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: @$(TRACE.target) @$(TRACE.target.log) @$(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.gen)) -include t/Makefile.gen endif ifeq (,$(_SID.help)) -include t/Makefile.help endif ifeq (,$(_SID.warnings)) -include t/Makefile.warnings endif ifeq (,$(_SID.cipher)) -include t/Makefile.cipher endif ifeq (,$(_SID.cmd)) -include t/Makefile.cmd 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.etc)) -include t/Makefile.etc endif ifeq (,$(_SID.dev)) -include t/Makefile.dev endif ifeq (,$(_SID.mod)) -include t/Makefile.mod endif ifeq (,$(_SID.init)) -include t/Makefile.init endif ifeq (,$(_SID.misc)) -include t/Makefile.misc endif ifeq (,$(_SID.critic)) -include t/Makefile.critic endif ifeq (,$(_SID.docker)) -include t/Makefile.docker endif ifeq (,$(_SID.legacy)) -include t/Makefile.legacy endif ifeq (,$(_SID.make)) -include t/Makefile.make endif #_____________________________________________________________________________ #_____________________________________________________________________ test __| HELP-_test = ______________________________________ targets for testing _ HELP-tests = make all tests HELP-test = alias for tests HELP-tests.log = same as tests but store results in '$(TEST.logdir)/' 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.all = print available individual targets for testing HELP-test.log.ls = list files in '$(TEST.logdir)/' generated by test.log HELP-test.%.log.ls = list files in '$(TEST.logdir)/' generated by test.EXT.log HELP-test.pattern-% = only execute targets matching '%' tests: TRACE.target = echo "\\012\#\# $@: $(EXE.pl) $(TEST.args)" tests: $(ALL.tests) @$(TRACE.target) @$(MAKE) $(MFLAGS) -s $(ALL.tests) tests.log: $(ALL.tests.log) @$(TRACE.target) @$(MAKE) $(MFLAGS) -s $(ALL.tests.log) @-$(EXE.log-compare-hint) @-$(EXE.log-move-hint) test.tests.log-compare: TEST.target_prefix = test test.tests.log-move: TEST.target_prefix = test test.tests.log: TEST.target_prefix = test test.log-compare: TEST.target_prefix = test test.log-move: TEST.target_prefix = test # quick tests for development # the target is named tests.quick instead of test.quick to avoid future naming # conflicts (if there is a Makefile.quick); # unfortunately the targets test*s.quick.log* must then be explicitly defined # because the pattern rules test.%.log* do not match 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 variable in each Makefile.* tests.quick.log: @$(TRACE.target) @$(TRACE.target.log) $(MAKE) $(MFLAGS) -s tests.log ALL.tests.log="test.warnings.log test.cmd.log test.exit.log test.opt.log test.cgi.log test.tcl.log" @-$(EXE.log-compare-hint) tests.quick.log-compare: @$(TRACE.target) @-$(EXE.log-compare) @-$(EXE.log-move-hint) @echo "# 12 logfiles with differences could be expected." tests.quick.log-move: @$(TRACE.target) $(EXE.log-move) # aliases for convenience test: tests test.log: tests.log @$(TRACE.target) @echo "# to show differences with $(EXE.diff), use:" @echo " $(MAKE_COMMAND) $@-compare" test.log.ls: @$(TRACE.target) @-ls $(TEST.logdir)/test.*log test.%.log.ls: @$(TRACE.target) @-ls -l $(TEST.logdir)/test*-$(*)*log # collect targets in this file, should not be added to ALL.tests ALL.test.self += tests tests.quick tests.log tests.quick.log .PHONY: test tests test.log tests.log #_____________________________________________________________________________ #________________________________________ targets for checking test results __| HELP-_compare = _________ targets to compare and rename generated logfiles _ HELP-test.log-compare = compare logfiles of previous with latest test HELP-test.log-move = rename logfiles of latest test HELP-help.test.log-info = print more details about test.log.* targets HELP.test.log-info = $(_NL)\ \# $(HELP-_compare)$(_NL)\ test.log-compare \# static rule to compare logfiles$(_NL)\ test.log-move \# static rule to rename (move) latest logfiles to "standard" logfile$(_NL)\ test.%.log-compare \# pattern rule for test.log-compare$(_NL)\ test.%.log-move \# pattern rule for test.log-move$(_NL)\ $(_NL)\ \#$(_NL)\ \# all above targets can be controlled with environment variables:$(_NL)\ \# TEST.logdir - directory where to find logfiles$(_NL)\ \# TEST.target_prefix - prefix of targets to search logfiles for (files to be matched)$(_NL)\ \# TEST.log-suffix - suffix of logfiles to be compared to "standard" logfile$(_NL)\ \# EXE.log-diff - program used to show difference of latest and "standard" logfile$(_NL)\ \# defaults:$(_NL)\ \# TEST.logdir = $(TEST.logdir)$(_NL)\ \# TEST.target_prefix = $(TEST.target_prefix)$(_NL)\ \# TEST.log-suffix = $(TEST.log-suffix)$(_NL)\ \# EXE.log-diff = $(EXE.log-diff)$(_NL)\ \# test example with adapted environment variables:$(_NL)\ \# $(MAKE_COMMAND) $@ TEST.logdir=/tmp TEST.log-suffix=-0815$(_NL)\ \#$(_NL)\ \# to see what the targets actually do, use$(_NL)\ \# (environment variables may be added as needed, see above):$(_NL)\ \# $(MAKE_COMMAND) -n test.log-compare$(_NL)\ \# $(MAKE_COMMAND) -n test.log-move$(_NL)\ help.test.log-info: @echo "$(HELP.test.log-info)" # summary variables (mainly used for INSTALL.sh) _ALL.devtools.extern += $(EXE.diffs) # default prefix, may be redifined per target TEST.target_prefix = testcmd- TEST.target_logfile = $(TEST.logdir)/testcmd- # default suffix for logfiles TEST.log-suffix = -$(TEST.today) test.log-compare-hint: @-$(EXE.log-compare-hint) test.%.log-compare: @$(TRACE.target) @-$(EXE.log-compare) @-$(EXE.log-move-hint) test.%.log-move: @$(TRACE.target) $(EXE.log-move) test.log-compare: @$(TRACE.target) @-$(EXE.log-compare) @-$(EXE.log-move-hint) test.log-move: @$(TRACE.target) $(EXE.log-move) #_____________________________________________________________________________ #________________________________________________ collected ALL.* variables __| ALL.tests := ALL.tests.log := # add all tests from included files to ALL.tests += ALL.test.$INCLUDE ifndef ALL-macros-generated $(foreach inc, $(ALL.inc.type), $(eval ALL.tests += $(ALL.test.$(inc))) ) $(foreach inc, $(ALL.inc.type), $(eval ALL.tests.log += $(ALL.test.$(inc).log)) ) endif # satisfy generated variables ALL.test.test := $(ALL.tests) ALL.test.test.log := $(ALL.tests.log) O-Saft-22.11.22/t/Makefile.FQDN000077500000000000000000000002331433765727300155060ustar00rootroot00000000000000#!//bin/cat # # 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-22.11.22/t/Makefile.cgi000077500000000000000000000336171433765727300155340ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.cgi #? #? VERSION #? @(#) Makefile.cgi 1.60 22/11/12 09:50:04 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.cgi = targets for testing '$(SRC.cgi)' (mainly invalid arguments) _SID.cgi := 1.60 _MYSELF.cgi := t/Makefile.cgi ALL.includes += $(_MYSELF.cgi) ALL.inc.type += cgi ALL.help.tests += help.test.cgi first-cgi-target-is-default: help.test.cgi ifeq (,$(_SID.test)) -include t/Makefile endif TEST.cgi.hosts = 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.test.cgi: HELP_TYPE = cgi help.test.cgi-v: HELP_TYPE = cgi help.test.cgi-vv: HELP_TYPE = cgi HELP-_cgi0 = _____________________________________________ testing .cgi _ HELP-test.cgi = test all bad IPs, hostnames and options for '$(SRC.cgi)' HELP-test.cgi.log = same as test.cgi but store output in '$(TEST.logdir)/' HELP-test.cgi.badhosts = test that some hostnames are ignored in '$(SRC.cgi)' HELP-test.cgi.badIPs = test that some IPs are ignored in '$(SRC.cgi)' HELP-test.cgi.badall = test all bad and good IPs and hostnames HELP-test.cgi.badopt = test bad options and characters HELP-test.cgi.goodIPs = test IPs to be passed HELP-test.cgi-NAME = same as testcmd-cgi-bad_NAME HELP-testcmd-cgi-bad_NAME = check if a single NAME (IP or hostname) allowed in '$(SRC.cgi)' HELP.cgi = $(_NL)\ \# Examples: $(_NL)\ \# $(MAKE_COMMAND) test.cgiall$(_NL)\ \# $(MAKE_COMMAND) testcmd-cgi-bad_42.42.42.42$(_NL)\ \# $(MAKE_COMMAND) testcmd-cgi-bad_127.0.0.127$(_NL)\ \# $(MAKE_COMMAND) testcmd-cgi-bad_localhost$(_NL)\ \# $(MAKE_COMMAND) e-LIST.cgi.badhosts$(_NL)\ \# $(MAKE_COMMAND) s-LIST.cgi.badIPs$(_NL)\ \# $(MAKE_COMMAND) s-LIST.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. LIST.cgi.badhosts := \ localhost any.local # hostname.ok.to.show.failed-status # range from - - - - - - - - - - - - - - - - - - to LIST.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.25 \ 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 \ 127.0.1 127.1 10.0.1 10.1 224.0.1 224.1 \ 127001 111111 2133465000 127.666 42 \ 0127.0.1 127.071 127.0.07 127.0.0.000042 \ 0x7f.0.1 0x0b.026.8492 127.0x71 127.0.0.000x42 \ 0x07f000001 \ # last line contain IPs with ocatl notations; should be ignored in general # 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 LIST.cgi.badIPv6 := \ \:\:1 ffff\:\:1 7f00\:1 ffff\:7f00\:1 \ ff01\:\:1 ff02\:\:1 ff02\:\:fb 64\:abcd\:\: \ \:251.1.1.1 \:\:251.1.1.1 \:abcd\:251.1.1.1 \:abcd\:\:251.1.1.1 \ abcd\:\:251.1.1.1 abcd\:\:\:251.1.1.1 abcd\:a\:\:251.1.1.1 \ 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: $(LIST.cgi.badhosts)$(_NL)\ \# test.cgi.badIPs: $(LIST.cgi.badIPs)$(_NL)\ \# test.cgi.goodIPs: $(LIST.cgi.goodIPs)$(_NL)\ " # TODO: *goodIP* not yet ready LIST.cgi.goodhosts := localhost.ok LIST.cgi.goodIPv4 := # 128.0.1 128.1 192.1 \ LIST.cgi.goodIPv6 := \ ffff \ 2002\:0\:0\:0\:0\:0\:b0b\:b0b \ fe00\:21ab\:22cd\:2323\:\:1 LIST.cgi.badIPs := $(LIST.cgi.badIPv4) $(LIST.cgi.badIPv6) LIST.cgi.goodIPs := $(LIST.cgi.goodIPv4) $(LIST.cgi.goodIPv6) ALL.cgi.goodhosts := $(LIST.cgi.goodhosts:%=testcmd-cgi-good_%) ALL.cgi.goodIPs := $(LIST.cgi.goodIPs:%=testcmd-cgi-good_%) ALL.cgi.badhosts := $(LIST.cgi.badhosts:%=testcmd-cgi-bad_%) ALL.cgi.badIPs := $(LIST.cgi.badIPs:%=testcmd-cgi-bad_%) HELP.test.cgi.all = $(_NL)\ \# targets for testing bad hosts:$(_NL)\ $(ALL.cgi.badhosts)$(_NL)\ $(_NL)\ \# targets for testing bad IPs:$(_NL)\ $(ALL.cgi.badIPs)$(_NL)\ $(_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 TEST.init must be set explicitly # test fails, if it reports something containing exit=BEGIN0 # All tests for good or bad arguments need the same initial options testcmd-cgi-%: EXE.pl = ../$(SRC.cgi) testcmd-cgi-bad%: EXE.pl = ../$(SRC.cgi) testcmd-cgi-good%: EXE.pl = ../$(SRC.cgi) test.cgi: TEST.init = --cgi --exit=BEGIN0 +quit testcmd-cgi-%: TEST.init = --cgi --exit=BEGIN0 +quit testcmd-cgi-chr%: TEST.init = --cgi testarg-cgi-%: EXE.pl = ../$(SRC.cgi) testarg-cgi-%: TEST.init = --cgi --exit=BEGIN0 +quit # check host argument without --host= testarg-cgi-host-localhost: TEST.init += localhost testarg-cgi-host-127_42: TEST.init += 127.42 testarg-cgi-host-12742: TEST.init += 12742 testarg-cgi-host-2133465000: TEST.init += 2133465000 testarg-cgi-host-7f00_1: TEST.init += 7f00:1 testarg-cgi-host-ffff__1: TEST.init += ffff::1 ALL.cgi.badarg = $(shell awk -F: '/^testarg-cgi-host-/ {arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_MYSELF.cgi)) # special targets to test bad --cgi #testarg-cgi---cgi_ok: TEST.init = --cgi --ok.to.show.failed-status --exit=BEGIN0 +quit testarg-cgi---cgi-miss: TEST.init = --missing--cgi --exit=BEGIN0 +quit testarg-cgi---cgi-bad1: TEST.init = --cgiwrong --exit=BEGIN0 +quit testarg-cgi---cgi-bad2: TEST.init = --cgi=wrong --exit=BEGIN0 +quit testarg-cgi---cgi-bad3: TEST.init = --wrongcgi --exit=BEGIN0 +quit ALL.cgi.badcgi = testarg-cgi---cgi-miss testarg-cgi---cgi-bad1 testarg-cgi---cgi-bad2 testarg-cgi---cgi-bad3 # arguments silently ignored by $(SRC.cgi), hence it will not die; # target succeeds if $(SRC.cgi) returns exit=BEGIN0 0; hence testcmd-cgi-good- LIST.cgi-opt-ignore := \ --cmd=list --cmd=+list --cmd=+dump --url=+dump \ --traceARG --trace --cmd=--trace --url=--trace \ --v --cmd=--v --url=--v \ --cmd=+version --ca-file=not-allowed --ca-path=not-allowed \ --cmd=libversion --ca-files=not-allowed --ca-paths=not-allowed \ --rc=not-allowed # arguments checked by $(SRC.cgi), hence it will die; # target succeeds if $(SRC.cgi) does not returns exit=BEGIN0 LIST.cgi-opt-die := \ --env=not-allowed --exe=not-allowed --lib=not-allowed \ --call=not-allowed --openssl=not-allowed ifndef cgi-targets-generated # SEE Make:macros $(foreach arg, $(LIST.cgi-opt-ignore), \ $(eval _target=testcmd-cgi-good-$(subst =,-,$(arg))_any.FQDN) \ $(eval $(_target): TEST.init += $(arg)) \ $(eval ALL.cgi.badopt += $(_target)) \ ) $(foreach arg, $(LIST.cgi-opt-die), $(eval \ testcmd-cgi-$(subst =,-,$(arg))_any.FQDN: TEST.init += $(arg) \ )) $(foreach arg, $(LIST.cgi-opt-die), $(eval \ ALL.cgi.badopt += testcmd-cgi-$(subst =,-,$(arg))_any.FQDN \ )) undefine arg undefine _target endif # targets for bad characters are written literally because it is difficult # to replace the character in the generated target name # the bad characters are enclosed in _ and _ for better readability testcmd-cgi-chr-langle_any.FQDN: TEST.init += '--bad-char=_<_' testcmd-cgi-chr-rangle_any.FQDN: TEST.init += '--bad-char=_>_' testcmd-cgi-chr-semikolon_any.FQDN:TEST.init += '--bad-char=_;_' testcmd-cgi-chr-tilde_any.FQDN: TEST.init += '--bad-char=_~_' testcmd-cgi-chr-question_any.FQDN: TEST.init += '--bad-char=_?_' #testcmd-cgi-chr-dollar_any.FQDN: TEST.init += '--bad-char=_\$$_' testcmd-cgi-chr-percent_any.FQDN: TEST.init += '--bad-char=_%_' testcmd-cgi-chr-dqoute_any.FQDN: TEST.init += '--bad-char=_\"_' testcmd-cgi-chr-back_any.FQDN: TEST.init += '--bad-char=_\`_' testcmd-cgi-chr-star_any.FQDN: TEST.init += '--bad-char=_*_' testcmd-cgi-chr-lbrac_any.FQDN: TEST.init += '--bad-char=_(_' testcmd-cgi-chr-rbrac_any.FQDN: TEST.init += '--bad-char=_)_' testcmd-cgi-chr-lsquare_any.FQDN: TEST.init += '--bad-char=_[_' testcmd-cgi-chr-rsquare_any.FQDN: TEST.init += '--bad-char=_]_' testcmd-cgi-chr-lcurl_any.FQDN: TEST.init += '--bad-char=_{_' testcmd-cgi-chr-rcurl_any.FQDN: TEST.init += '--bad-char=_}_' testcmd-cgi-chr-caret_any.FQDN: TEST.init += '--bad-char=_^_' testcmd-cgi-chr-bar_any.FQDN: TEST.init += '--bad-char=_|_' testcmd-cgi-chr-hash_any.FQDN: TEST.init += '--bad-char=_\#_' ALL.cgi.badchr = $(shell awk -F: '/^testcmd-cgi-chr-/ {arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_MYSELF.cgi)) # check HTTP header options # NOTE: target name is testarg-cgi_ instead of testarg-cgi- because it should # not match pattern rule testarg-cgi-% testarg-cgi_with%: EXE.pl = ../$(SRC.cgi) testarg-cgi_with%: TEST.init = testarg-cgi_with-header: TEST.init += --cgi --exit=ARGS --with_HTTP_header --cgi-header testarg-cgi_without-header: TEST.init += --cgi --exit=ARGS --with_HTTP_header --cgi-no-header ALL.cgi.header = testarg-cgi_with-header testarg-cgi_without-header test.cgi.log-compare: TEST.target_prefix = testcmd-cgi test.cgi.log-move: TEST.target_prefix = testcmd-cgi # TEST.target_prefix not yet used # FIXME: general rule can only handle on perfix, but we have testcmd- and testarg. here # NOTE: --exit=BEGIN0 must not be the last argument, because it triggers buggy # check in o-saft.cgi (at least up to version 1.44), hence --dummy added testarg-cgi-%: @$(TRACE.target) @$(MAKE) $(MFLAGS) no.message-exit.BEGIN0 EXE.pl=$(EXE.pl) TEST.init="$(TEST.init)" TEST.args=--dummy testcmd-cgi-%: @$(TRACE.target) @$(eval _host := $(shell echo "$*" | awk -F_ '{print $$NF}')) @$(MAKE) $(MFLAGS) no.message-exit.BEGIN0 EXE.pl=$(EXE.pl) TEST.init="$(TEST.init) --host=$(_host)" TEST.args=--dummy # TODO: following target prints "#o-saft.pl..." testcmd-cgi-good%: @$(TRACE.target) @$(eval _host := $(shell echo "$*" | awk -F_ '{print $$NF}')) @$(MAKE) $(MFLAGS) message-exit.BEGIN0 EXE.pl=$(EXE.pl) TEST.init="$(TEST.init) --host=$(_host)" TEST.args=--dummy # alias for simple usage test.cgi-%: testcmd-cgi-bad_% @echo "" ALL.test.cgi = \ $(ALL.cgi.goodhosts) \ $(ALL.cgi.goodIPs) \ $(ALL.cgi.badopt) \ $(ALL.cgi.badchr) \ $(ALL.cgi.badhosts) \ $(ALL.cgi.badIPs) \ $(ALL.cgi.badarg) \ $(ALL.cgi.badcgi) \ $(ALL.cgi.header) 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.goodhosts:$(ALL.cgi.goodhosts) _TEST.cgi.log = $(TEST.logdir)/test.cgi.log-$(TEST.today) # use 'make -i ...' because we have targets which fail, which is intended $(_TEST.cgi.log): @echo "# Makefile.cgi 1.60: $(MAKE) test.cgi.log" > $@ @$(MAKE) -i test.cgi >> $@ 2>&1 # not yet needed: test.log-compare-hint test.cgi.log: $(_TEST.cgi.log) $(ALL.cgi.header:%=%.log) @$(TRACE.target) @$(TRACE.target.log) @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.test.cgi.log += test.cgi.log ifndef ALL.Makefiles # NOTE: needed if called with -f Makefile.cgi %-v: TRACE.target = echo "\# $@: $?" %-v: % echo CGI $(TEST.init) @$(EXE.dummy) %-vv: TRACE.target = echo "\# $@: $^" %-vv: % echo CGI @$(EXE.dummy) endif test.cgi: $(ALL.test.cgi) O-Saft-22.11.22/t/Makefile.cipher000077500000000000000000000142011433765727300162300ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.cipher #? #? VERSION #? @(#) Makefile.cipher 1.27 22/11/17 16:25:01 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.cipher = targets for testing '$(SRC.pl)' commands and options _SID.cipher := 1.27 _MYSELF.cipher := t/Makefile.cipher ALL.includes += $(_MYSELF.cipher) ALL.inc.type += cipher ALL.help.tests += help.test.cipher first-cipher-target-is-default: help.test.cipher ifeq (,$(_SID.test)) -include t/Makefile endif TEST.cipher.hosts = localhost ifdef TEST.hosts TEST.cipher.hosts = $(TEST.hosts) endif help.test.cipher: HELP_TYPE = cipher help.test.cipher-v: HELP_TYPE = cipher help.test.cipher-vv: HELP_TYPE = cipher HELP-_cipher1 = _________________________________________ testing commands _ HELP-test.cipher = test all commands with '$(TEST.cipher.hosts)' HELP-test.cipher.log = same as test.cipher but store output in '$(TEST.logdir)/' HELP-_cipher2 = ________________________________ testing a special command _ HELP.cipher = $(_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_COMMAND) testcmd-cipher+cipher--cipher-alpn_localhost$(_NL)\ \# Examples to execute group of similar targets:$(_NL)\ \# $(MAKE_COMMAND) test.pattern-+cipher$(_NL)\ \# All following examples are the same:$(_NL)\ \# $(MAKE_COMMAND) testcmd-+cipher TEST.init='--header --enabled localhost'$(_NL)\ \# $(MAKE_COMMAND) testcmd-+cipher TEST.args='--header --enabled localhost'$(_NL)\ \#$(_NL)\ \# Some of the examples above use localhost as hostname by default. HELP.test.cipher.all = # no special documentation yet # SEE Make:target name # SEE Make:target name prefix LIST.cipher-mode := --ciphermode=intern --ciphermode=openssl --ciphermode=dump LIST.cipher-pattern := --cipher=AES128-SHA --cipher=0x0300002F --cipher=IS-UNKNOWN --cipher=is_invalid #TODO: --cipher=0x0300002F invalid with --ciphermode=openssl; will be fixed later LIST.cipher-range := \ --dummy-no-arg \ --range=c0xx --range=ccxx --range=ecc --range=SSLv2_long \ --range=rfc --range=long --range=shifted --range=SSLv3_SSLv2 \ --range=SSLv2 --range=SSLv3 --range=TLSv12 --range=TLSv13 # --range=safe and --range=huge disabled, because it takes a long time LIST.cipher := \ --dummy-no-arg $(LIST.cipher-range) \ --legacy=owasp --force-openssl --showhost --trace-KEY \ --cipher-alpn --cipher-npn --cipher-openssl --cipher-curves #TODO: TEST.args += --cipher-npns=, #TODO: TEST.args += --cipher-npns=, --cipher-npns=,, #TODO: TEST.args += --cipher-npns=, --cipher-npns=ecdh_x448 ifndef cipher-macros-generated # cannot use GEN.targets because ALL.testcipher instead of ALL.test.cipher # is set here; see further use of ALL.testcipher below $(foreach arg, $(LIST.cipher),\ $(eval _target=testcmd-cipher-+cipher-$(subst =,-,$(arg))) \ $(eval $(_target)_%: TEST.args = $(arg)) \ $(eval ALL.testcipher += $(_target)_) \ ) # for --test-ciphers-list see Makefile.opt $(foreach arg, $(LIST.cipher-range),\ $(eval _target=testarg-cipher-+test-ciphers-list_$(subst =,-,$(arg))) \ $(eval $(_target): TEST.args = $(arg)) \ $(eval ALL.testciphers += $(_target)) \ ) $(foreach mode, $(LIST.cipher-mode),\ $(foreach arg, $(LIST.cipher-pattern),\ $(eval _target=testcmd-cipher-+cipher-$(subst =,-,$(arg))$(subst =,-,$(mode))) \ $(eval $(_target)_%: TEST.args = $(arg) $(mode) ) \ $(eval ALL.testcipher += $(_target)_) \ ) \ ) undefine _target endif # testarg-cipher-+test-ciphers-list-* do not need a target for testing, hence # they are added to ALL.testciphers instead of ALL.testcipher to avoid adding # the TEST.cipher.hosts below testarg-cipher-%: EXE.pl = ../$(SRC.pl) testarg-cipher-+test-ciphers-list_%: TEST.init = --test-ciphers-list testcmd-cipher-%: EXE.pl = ../$(SRC.pl) testcmd-cipher-+cipher-%: TEST.init = --trace-CLI --header testcmd-cipher-+cipher--%: TEST.init = --trace-CLI --header +cipher testcmd-cipher-+cipher_%: TEST.args += testcmd-cipher-+cipher---nossltls_%: TEST.args += --nosslv2 --nosslv3 --notlsv1 --notlsv11 --notlsv12 --notlsv13 # simulates a server not responding to ciphers ALL.testcipher += testcmd-cipher-+cipher--nossltls_ # some more individual tests testcmd-cipher-+cipher-dh_%: TEST.args += +cipher-dh testcmd-cipher-+cipher-default_%: TEST.args += +cipher-default testcmd-cipher-+cipher-selected_%: TEST.args += +cipher-selected testcmd-cipher-+cipher-strong_%: TEST.args += +cipher-strong testcmd-cipher-+cipher---trace-host_%: TEST.args += +cipher --showhost --trace-KEY testcmd-cipher-+ciphercheck_%: TEST.args += +ciphercheck --trace-CLI --header # not yet implemented # TODO: hence missing in ALL.testciphermisc below testcmd-cipher-+cipher-order_%: TEST.args += +cipher-order testcmd-cipher-+cipher-weak_%: TEST.args += +cipher-weak ALL.testciphermisc = \ testcmd-cipher-+cipher-dh_ \ testcmd-cipher-+cipher-default_ \ testcmd-cipher-+cipher-selected_ \ testcmd-cipher-+cipher-strong_ \ testcmd-cipher-+ciphercheck_ \ testcmd-cipher-+cipher--trace-host_ ALL.test.cipher = $(foreach host,$(TEST.cipher.hosts),$(ALL.testcipher:%=%$(host))) ALL.test.cipher += $(foreach host,$(TEST.cipher.hosts),$(ALL.testciphermisc:%=%$(host))) ALL.test.cipher += $(ALL.testciphers) ALL.test.cipher.log += $(ALL.test.cipher:%=%.log) test.cipher.log-compare: TEST.target_prefix = testcmd-cipher test.cipher.log-move: TEST.target_prefix = testcmd-cipher test.cipher.log: TEST.target_prefix = testcmd-cipher test.cipher: $(ALL.test.cipher) test.cipher.log: $(ALL.test.cipher.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.cmd000077500000000000000000000203721433765727300155270ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.cmd #? #? VERSION #? @(#) Makefile.cmd 1.61 22/11/04 22:16:57 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.cmd = targets for testing '$(SRC.pl)' commands and options _SID.cmd := 1.61 _MYSELF.cmd := t/Makefile.cmd ALL.includes += $(_MYSELF.cmd) ALL.inc.type += cmd ALL.help.tests += help.test.cmd first-cmd-target-is-default: help.test.cmd ifeq (,$(_SID.test)) -include t/Makefile endif TEST.cmd.hosts = localhost ifdef TEST.hosts TEST.cmd.hosts = $(TEST.hosts) endif help.test.cmd: HELP_TYPE = cmd help.test.cmd-v: HELP_TYPE = cmd help.test.cmd-vv: HELP_TYPE = cmd HELP-_cmd1 = _________________________________________ testing commands _ HELP-test.pattern-* = test group of commands with '$(TEST.cmd.hosts)' HELP-testcmd-* = test commands with '$(TEST.cmd.hosts)' HELP-testcmd-*.log = same as testcmd-* but store output in '$(TEST.logdir)/' HELP-test.cmd = test all commands with '$(TEST.cmd.hosts)' HELP-test.cmd.log = same as test.cmd but store output in '$(TEST.logdir)/' HELP-_cmd2 = ________________________________ testing a special command _ HELP-testrun-CMD = test specific command CMD with '$(TEST.cmd.hosts)' HELP-testrun-CMD.log = same as testrun-CMD but store output in '$(TEST.logdir)/' HELP-_cmd3 = __________________________________________ special targets _ HELP-testcmd-cmd+ignored-keys = special target using commands which return random values HELP.cmd = $(_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_COMMAND) testcmd-cmd+info_localhost$(_NL)\ \# $(MAKE_COMMAND) testcmd-cmd_vuln+BEAST_localhost$(_NL)\ \# $(MAKE_COMMAND) testrun-+cn$(_NL)\ \# Examples to execute group of similar targets:$(_NL)\ \# $(MAKE_COMMAND) test.pattern-+info$(_NL)\ \# $(MAKE_COMMAND) test.pattern-+check$(_NL)\ \# $(MAKE_COMMAND) test.pattern-+summ$(_NL)\ \# $(MAKE_COMMAND) test.pattern-+vuln$(_NL)\ \#$(_NL)\ \# Some of the examples above use localhost as hostname by default. HELP.test.cmd.all = # no special documentation yet # SEE Make:--ignore-output LIST.ignore-output-keys := master_key \ session_id session_id_ctx \ session_startdate session_starttime \ session_ticket sts_expired LIST.no-out.opt := $(LIST.ignore-output-keys:%=--no-out=%) LIST.ignore.cmd := $(LIST.ignore-output-keys:%=+%) # The ignored keys are tested with the target testcmd-cmd-+ignored-keys_ . LIST.cmd.withtrace := +quit +info +check # various --trace* options to be used with these commands # +quit - the most simple output, no call to a target # +info - output with call to a target, hence trace from Net/SSLinfo.pm also # +check - some more output from $(EXE.pl) than with +info # +cipher - # TODO LIST.cmd.cmd := $(LIST.cmd.withtrace) +quick +vulns +http +hsts +sts LIST.cmd.vulns := +BEAST +CRIME +DROWN +FREAK +POODLE +logjam +lucky13 +Sloth +Sweet32 LIST.cmd.summ := +bsi +EV +TR-02102+ +ocsp +preload +protocols +fingerprints +sizes +pfs +sni LIST.cmd.trace-opt := --tracearg --tracecmd --tracekey --tracetime --traceme --trace --trace=2 # --trace* options used instead --trace-*; make nicer target names # Note that --tracecmd is same as --traceCMD is same as --trace-CMD # SEE Make:target name # SEE Make:target name prefix ifndef cmd-targets-generated _TEST.cmd := testcmd-cmd # arguments from LIST.* used in the target name must not contain = # hence $(subst =,-,$(arg)) is used to replace = by - # target foreach command $(foreach cmd, $(LIST.cmd.cmd) $(LIST.cmd.vulns) $(LIST.cmd.summ),\ $(eval _target=$(_TEST.cmd)-$(subst =,-,$(cmd))) \ $(eval $(_target)_%: TEST.args += $(cmd)) \ $(eval ALL.testcmd += $(_target)_) \ ) # targets without --trace* options $(foreach cmd, $(LIST.cmd.withtrace),\ $(eval $(_TEST.cmd)-$(subst =,-,$(cmd))--noout_%: TEST.args += $(cmd) $(LIST.no-out.opt) ) \ $(eval ALL.testcmd += $(_TEST.cmd)-$(subst =,-,$(cmd))--noout_) \ $(foreach opt, $(LIST.cmd.trace-opt),\ $(eval _target=$(_TEST.cmd)-$(subst =,-,$(cmd))$(subst =,-,$(opt))) \ $(eval $(_target)_%: TEST.args += $(cmd) $(opt) $(LIST.no-out.opt)) \ $(eval ALL.testcmd += $(_target)_) \ ) \ ) undefine _target undefine _TEST.cmd endif # TODO: need generic target which compares results of initial command # with same command and more options, example: # testcmd-cmd-+info_localhost testcmd-cmd-+info--noout_localhost testcmd-cmd-%: EXE.pl = ../$(SRC.pl) testcmd-cmd-%: TEST.init = --trace-CLI --header testcmd-cmd-+ignored-keys_%: TEST.args += $(LIST.ignore.cmd) testcmd-cmd-+ignored-keys_%.log: EXE.log-filtercmd = cat # testcmd-cmd-+ignored-keys_ prints those commands, which are ignored # in following targets. It results in different output for each execution. # testcmd-cmd-+ignored-keys_.lg ensures that no EXE.log-filtercmd is used. # avoid output of random values in some commands testcmd-cmd-+http_%: TEST.args += --no-out=sts_expired testcmd-cmd-+hsts_%: TEST.args += --no-out=sts_expired testcmd-cmd-+sts_%: TEST.args += --no-out=sts_expired testcmd-cmd-+sts--noout_%: TEST.args += +sts $(LIST.no-out.opt) testcmd-cmd-+https_body--httpbody_%: TEST.args += +https_body --https_body testcmd-cmd-+info--tracekey-norc_%: TEST.args += +info --trace-key --norc $(LIST.no-out.opt) testcmd-cmd-+check--tracekey-norc_%: TEST.args += +check --trace-key --norc $(LIST.no-out.opt) testcmd-cmd-+check--trace-norc_%: TEST.args += +check --trace-cmd --norc --trace-time --trace=2 $(LIST.no-out.opt) testcmd-cmd-+quick--tracearg_%: TEST.args += +quick --trace-arg testcmd-cmd-+check--nossltls_%: TEST.args += +check --nosslv2 --nosslv3 --notlsv1 --notlsv11 --notlsv12 --notlsv13 $(LIST.no-out.opt) # simulates a server not responding to ciphers testcmd-cmd-+info_%.log: EXE.log-filtercmd = awk -F: '\ BEGIN{OFS=":"} \ ($$1!~/Target.s/) {print;next;} \ ($$1~/Master.Key/) {$$2="\t$(TEST.logtxt)"}\ ($$1~/Session.(ID|Ticket)$$/) {$$2="\t$(TEST.logtxt)"}\ ($$1~/Session Start/) {$$2="\t$(TEST.logtxt)";$$3=$$4=$$5=""}\ {print}' # expected and changed lines like: # Target's Master-Key: 0CAAF5CF1.... # Target's TLS Session Start Time locale: Fri Nov 4 21:17:06 2022 ALL.testcmd += \ testcmd-cmd-+ignored-keys_ \ testcmd-cmd-+sts--noout_ \ testcmd-cmd-+info--tracekey-norc_ \ testcmd-cmd-+check--tracekey-norc_ \ testcmd-cmd-+check--trace-norc_ \ testcmd-cmd-+quick--tracearg_ \ testcmd-cmd-+check--nossltls_ \ testcmd-cmd-+https_body--httpbody_ testarg-cmd-host_url+cn: TEST.args += --v +cn testarg-cmd-host_url+cn: TEST.init = localhost/tests # target to test hostname with url (path) # TODO: add to ALL.testcmd testarg-cmd-host_url+cn.log: EXE.log-filterarg = awk -F= '\ BEGIN{OFS="="} \ ($$1~/master_key/) {$$2="$(TEST.logtxt)"}\ ($$1~/session_(id|ticket)$$/) {$$2="$(TEST.logtxt)"}\ ($$1~/session_start(date|time)/){$$2="$(TEST.logtxt)"}\ {print}' ALL.test.cmd = $(foreach host,$(TEST.cmd.hosts),$(ALL.testcmd:%=%$(host))) ALL.test.cmd += testarg-cmd-host_url+cn ALL.test.cmd.log += $(ALL.test.cmd:%=%.log) # testrun target to allow something like: testrun-+my-fancy-command testrun-%: EXE.pl = ../$(SRC.pl) testrun-%: TEST.init = --trace-CLI testrun-%: TEST.args += $(TEST.cmd.hosts) testrun-%: @$(TRACE.target) -cd $(TEST.dir) && $(EXE.pl) $(TEST.init) $* $(TEST.args) test.cmd.log-compare: TEST.target_prefix = testcmd-cmd- test.cmd.log-move: TEST.target_prefix = testcmd-cmd- test.cmd.log: TEST.target_prefix = testcmd-cmd- test.cmd: $(ALL.test.cmd) test.cmd.log: $(ALL.test.cmd.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.critic000077500000000000000000000212431433765727300162370ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.critic #? #? VERSION #? @(#) Makefile.critic 1.28 22/09/21 09:55:11 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.critic = targets for using perlcritic _SID.critic := 1.28 _MYSELF.critic := t/Makefile.critic ALL.includes += $(_MYSELF.critic) ALL.inc.type += critic ALL.help.tests += help.test.critic first-critic-target-is-default: help.test.critic ifeq (,$(_SID.test)) -include t/Makefile endif help.critic: HELP_TYPE = critic help.critic-v: HELP_TYPE = critic help.critic-vv: HELP_TYPE = critic help.test.critic: HELP_TYPE = critic help.test.critic-v: HELP_TYPE = critic help.test.critic-vv: HELP_TYPE = critic # not really for testing, hence we have 'critic' and 'test.critic' #_____________________________________________________________________________ #________________________________________________________________ variables __| EXE.critic := perlcritic TEST.critic.dir = $(TEST.dir) TEST.critic.rc := .perlcriticrc TEST.critic.severity := -5 TEST.critic.opt := TEST.critic.pretty := ALL.critic = $(SRC.pl) $(ALL.pm) $(GEN.pod) # $(CHK.pl) # summary variables (mainly used for INSTALL.sh) _ALL.devtools.extern += $(EXE.critic) # using perlcritic's --verbose options without ( and ) ; see: man perlcritic TEST.opt.verb8 := '%f: [%p] %m at line %l, column %c. Severity: %s\\n' TEST.opt.verb10 := '%f: %m at line %l, column %c.\n %p Severity: %s\n%d\\n' # same options, but output prefixed with filename TEST.opt.verb8o := --verbose $(TEST.opt.verb8) TEST.opt.verb10o := --verbose $(TEST.opt.verb10) TEST.critic.opt = $(TEST.opt.verb8o) # perlcritic --verbose 8 is default ; hence we use this modified # some aliases help.critic: help.test.critic critic.help: help.test.critic criticdoc: help.test.critic #_____________________________________________________________________________ #___________________________________________ targets for calling perlcritic __| HELP-_critic0 = _________________________________ targets for code quality _ HELP-critic = check files with perlcritic HELP-critic345 = check files with perlcritic for severity 3,4,5 HELP-help.critic = print more details about critic-* targets HELP-_critic1 = targets calling perlcritic with additional options: HELP-_critic3 = _________________________________________________ severity _ HELP-critic-5 = perlcritic --severity 5 HELP-critic-4 = perlcritic --severity 4 HELP-critic-3 = perlcritic --severity 3 HELP-critic-2 = perlcritic --severity 2 HELP-_critic4 = _______________________________________________ statistics _ HELP-critic-count = perlcritic --severity 5 -count HELP-critic-stat = perlcritic --severity 5 --statistics-only HELP-critic-stat-4 = perlcritic --severity 4 --statistics-only HELP-critic-stat-3 = perlcritic --severity 3 --statistics-only HELP-_critic5 = _____________________________________ single file severity _ HELP-c5-FILE = perlcritic --severity 5 FILE HELP-c4-FILE = perlcritic --severity 4 FILE HELP-c3-FILE = perlcritic --severity 3 FILE HELP-_critic6 = _____________________________ single file verbose severity _ HELP-c5v-FILE = perlcritic --severity 5 FILE --verbose 10 HELP-c4v-FILE = perlcritic --severity 4 FILE --verbose 10 HELP-c3v-FILE = perlcritic --severity 3 FILE --verbose 10 HELP-_critic7 = _______________________ targets with pretty-printed output _ HELP-TARGETp = call TARGET and pretty print output HELP.critic = $(_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 '$(TEST.critic.dir)'$(_NL)\ \# * perlcritic uses '$(TEST.critic.dir)/$(TEST.critic.rc)'$(_NL)\ \# See also '$(SRC.contrib.dir)/critic.sh' HELP.test.critic.all= # no special documentation yet #_____________________________________________________________________________ #_________________________________________________ targets for code quality __| perlcritic-%: $(TEST.critic.dir) @mkdir -p $@ # 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: $(TEST.critic.dir) @$(TRACE.target) -cd $(TEST.critic.dir) && $(EXE.critic) $(ALL.critic:%=../%) $(TEST.critic.severity) $(TEST.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 # FIXME: gawk in critic-pretty does not work properly after 19.01.19 critic-pretty: $(TEST.critic.dir) @$(TRACE.target) -cd $(TEST.critic.dir) && $(EXE.critic) $(ALL.critic:%=../%) $(TEST.critic.severity) $(TEST.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-5p c5-% c5v-%: TEST.critic.severity = -5 critic-4 critic-4p c4-% c4v-%: TEST.critic.severity = -4 critic-3 critic-3p c3-% c3v-%: TEST.critic.severity = -3 critic-2 critic-2p c2-% c2v-%: TEST.critic.severity = -2 critic-2p critic-3p critic-4p critic-5p: TEST.critic.pretty = -pretty critic-count: TEST.critic.opt = -count critic-stat: TEST.critic.opt = --statistics-only critic-stat-4: TEST.critic.opt = --statistics-only critic-stat-4: TEST.critic.severity = -4 critic-stat-3: TEST.critic.opt = --statistics-only critic-stat-3: TEST.critic.severity = -3 #critic-countp critic-statp critic-stat-4p: # do not make sense ALL.test.critic = critic-5 critic-4 critic-3 critic-2 \ critic-count critic-stat critic-stat-4 critic-stat-3 $(ALL.test.critic): critic criticp critic-5p critic-4p critic-3p critic-2p: critic-pretty c5-% c4-% c3-% c2-%: @$(TRACE.target) @$(MAKE) -s ALL.critic=$* critic TEST.critic.severity=$(TEST.critic.severity) c5v-% c4v-% c3v-% c2v-%: @$(TRACE.target) @$(MAKE) -s ALL.critic=$* critic TEST.critic.severity=$(TEST.critic.severity) TEST.critic.opt="$(TEST.opt.verb10o)" _TEST.critic-3.txt = $(TEST.critic.dir)/perlcritic-$(TEST.today)/severity-3.txt _TEST.critic-4.txt = $(TEST.critic.dir)/perlcritic-$(TEST.today)/severity-4.txt _TEST.critic-5.txt = $(TEST.critic.dir)/perlcritic-$(TEST.today)/severity-5.txt $(TEST.critic.dir)/perlcritic-$(TEST.today)/severity%.txt: $(TEST.critic.dir)/perlcritic-$(TEST.today) @$(TRACE.target) @(echo "" && echo "" && echo "## Anzahl Fehler ...") > $@ @$(MAKE) $(MFLAGS) -s TEST.critic.severity=$* critic-count >> $@ @(echo "" && echo "" && echo "## Statistik ...") >> $@ @$(MAKE) $(MFLAGS) -s TEST.critic.severity=$* critic-stat >> $@ @(echo "" && echo "" && echo "## Fehler ...") >> $@ @$(MAKE) $(MFLAGS) -s TEST.critic.severity=$* critic TEST.critic.opt= >> $@ critic345: $(_TEST.critic-3.txt) $(_TEST.critic-4.txt) $(_TEST.critic-5.txt) # TODO: dirty hack target critic345.log critic345.log: @rm -f $(_TEST.critic-3.txt) $(_TEST.critic-4.txt) $(_TEST.critic-5.txt) @$(MAKE) $(MFLAGS) -s critic345 ALL.test.critic.log = critic345.log test.critic: $(ALL.test.critic) test.critic.log: $(ALL.test.critic.log) # test.log-compare-hint does not make sence here O-Saft-22.11.22/t/Makefile.dev000077500000000000000000000324031433765727300155400ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.dev #? #? VERSION #? @(#) Makefile.dev 1.85 22/11/19 15:07:20 #? #? AUTHOR #? 19-apr-19 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.dev = targets for testing internal documentation and functionality _SID.dev := 1.85 _MYSELF.dev := t/Makefile.dev ALL.includes += $(_MYSELF.dev) ALL.inc.type += dev ALL.help.tests += help.test.dev first-dev-target-is-default: help.test.dev ifeq (,$(_SID.test)) -include t/Makefile endif help.test.dev: HELP_TYPE = dev help.test.dev-v: HELP_TYPE = dev help.test.dev-vv: HELP_TYPE = dev #_____________________________________________________________________________ #________________________________________________________________ variables __| TEST.dev.hosts = # TODO: other tools should go to Makefile.contrib # these targets require the symbolic link: contrib -> ../contrib # list of source files (executables) to be used for some "grep"-targets # NOTE: contains only source files with potentionally marked control flow. This # is for sure in SRC.pl and SRC.tcl. To avoid the target re- # turning "failed", it must be ensured that the last file returns something, so # SRC.pl is the last in the list (see t*_flow target below) LIST.sources := $(SRC.tcl:%=../%) $(SRC.pm:%=../%) $(SRC.pl:%=../%) # list of programs LIST.programs := \ $(SRC.sh) $(EXE.docker) $(GEN.src) \ $(SRC.pl) $(SRC.tcl) $(SRC.pm) \ $(TEST.dir)/Makefile.pod \ INSTALL.sh \ $(SRC.contrib.dir)/bunt.pl \ $(SRC.contrib.dir)/install_openssl.sh \ $(SRC.contrib.dir)/gen_standalone.sh #EXE.o-saft-docker-dev := ../$(EXE.docker)-dev # no targets are generated for empty LIST.* variables LIST.o-saft.tcl := --help=opts --test-o-saft LIST.o-saft.pl := LIST.o-saft := -help -list -help=rc -help=sni LIST.o-saft-docker := -help # TODO: LIST.o-saft-docker-dev := -help LIST.o-saft-post := \ -post=HTML-simple.awk -post=HTML-table.awk -post=lazy_checks.awk \ -post=JSON-array.awk -post=JSON-struct.awk \ -post=XML-value.awk -post=XML-attribute.awk LIST.t-makefile := LIST.INSTALL.sh := --install --clean --check --checkdev --expected --cgi # NOTE: ensure that EXE.install is called with --n ! # NOTE: EXE.install-sh --openssl does not work from t directory # TODO: EXE.install-sh not completely working as expected _TEST.dev.tmpfile := /tmp/tmpfile LIST.contrib-bunt.pl := --test LIST.contrib-install_openssl.sh := --n --m LIST.contrib-gen_standalone.sh := --n --s --t # command and checks NOT YET IMPLEMENTED are hardcoded here, # should be the same commands_notyet in osaft.pm LIST.o-saft.notyet := \ +closure +cipher_order +cipher_weak +cps_valid +fallback \ +open_pgp +lzo +sgc +scsv +time +zlib \ HELP-_dev1 = __________________________ testing internal documentations _ HELP-test.dev = test various internal documentation and functionality HELP-test.dev.log = same as test.dev but store output in '$(TEST.logdir)/' HELP-test.dev.EXE_pod = print POD of EXE using: '$(EXE.gendoc.perldoc)' HELP-test.dev.EXE_--help = print documentation, using: EXE --help HELP-test.dev.help.all = print all test.dev.EXE_--help HELP-test.dev.pod.all = print all test.dev.EXE_pod HELP-test.dev.help.log = same as test.dev.help.all but store output in '$(TEST.logdir)/' HELP-test.dev.pod.log = same as test.dev.help.all but store output in '$(TEST.logdir)/' _HELP-_dev2 = _______________ summary targets for internal functionality _ HELP.dev = $(_NL)$(_TAB)$(_TAB)\#$(_HELP-_dev2)$(_NL) HELP.dev += test.dev.help.all\t\# targets for testing --help option\n HELP.dev += test.dev.pod.all\t\# targets for testing perldoc generation\n #_____________________________________________________________________________ #______________________________________________________ targets for testing __| # Automatically generated targets for each program are: # testarg-dev---help # testarg-dev-_pod # Note that not all programs in LIST.program support --help or have POD, # this then results in different or empty output, for example o-saft-docker. # Some of them are explicitly disabled, see "useless generated" below. # # usually: _EXE.perldoc-opt _EXE.gendoc-opt := $(_EXE.$(EXE.gendoc)-opt) ifndef dev-macros-generated # SEE Make:macros # need to call program in this directory and not the one found via $PATH # SEE Make:generating help $(foreach _prg, $(LIST.programs), \ $(eval HELP.dev += test.dev.$(subst /,-,$(_prg)).all\t\# targets for testing '$(_prg)'\n)\ ) $(eval HELP.dev +=\t\t\#____________ same as above, but store output in '$(TEST.logdir)' _\n) $(foreach _prg, $(LIST.programs),\ $(eval _test=test.$(subst /,-,$(_prg))) \ $(eval HELP.dev += test.$(_test)_ARG.log\t\# see test.$(_test)_ARG but ...\n)\ ) undefine _prg undefine _test # generate testarg-*_pod and testarg-*_--help targets $(foreach _prg, $(LIST.programs),\ $(eval _name=$(subst /,-,$(_prg))) \ $(eval _testarg=testarg-dev-$(_name)) \ $(eval $(_testarg)_pod: EXE.pl = $(EXE.gendoc) $(_EXE.gendoc-opt)) \ $(eval $(_testarg)_pod: TEST.init = ../$(_prg)) \ $(eval $(_testarg)_--help: TEST.init = --help) \ $(eval ALL.test.dev.$(_name) += $(_testarg)_pod $(_testarg)_--help) \ $(eval ALL.test.dev.pod += $(_testarg)_pod) \ $(eval ALL.test.dev.help += $(_testarg)_--help) \ ) undefine _prg undefine _name undefine _testarg # generate testarg-* targets $(foreach _prg, $(LIST.programs),\ $(call GEN.targets-init,testarg,dev,$(_prg),LIST.$(subst /,-,$(_prg))) \ ) $(eval _prg=o-saft) $(foreach _arg, $(LIST.o-saft-post),\ $(eval _testarg=testarg-dev-$(_prg)_$(subst =,-,$(_arg))) \ $(eval ALL.test.dev.$(_prg)-post += $(_testarg)) \ $(eval $(_testarg): TEST.init = $(_arg)) \ ) $(eval test.dev.$(_prg)-post.all : $(ALL.test.dev.$(_prg)-post)) undefine _arg undefine _prg undefine _testarg $(eval undefine _prg) endif $(_TEST.dev.tmpfile): @mkdir $@ # more individual targets for SRC.sh (calling contrib/bunt.pl) # TODO: use pattern rule to define TEST.dev.hosts instead hardcoded localhost # testarg-dev-o-saft_--colour%: TEST.dev.hosts = localhost testarg-dev-o-saft_--colour: TEST.args = --colour +unknown-cmd $(TEST.host) testarg-dev-o-saft_--colour+ocsp: TEST.args = --colour +ocsp $(TEST.host) testarg-dev-o-saft_--colour-line: TEST.args = --colour --line +ocsp $(TEST.host) ALL.test.dev += \ testarg-dev-o-saft_--colour \ testarg-dev-o-saft_--colour+ocsp \ testarg-dev-o-saft_--colour-line testarg-dev-o-saft_-post%: EXE.pl = ../$(SRC.sh) testarg-dev-o-saft_-post%: TEST.args = --no-rc --header $(TEST.host) #testarg-dev-o-saft_-post%: TEST.args = $(TEST.host) # do not execute script, just show: --n testarg-dev-contrib-install_openssl_%: TEST.args = --n testarg-dev-INSTALL.sh_%: TEST.args = --n /tmp/o-saft # # returns following errors, which is OK for --n : # # ../INSTALL.sh: 787: cd: can't cd to /tmp/o-saft # # **ERROR: 040: /tmp/o-saft does not exist; exit # # **ERROR: 043: missing XXXX; file ignored # additional special option for INSTALL.sh testarg-dev-INSTALL.sh_--checkdev--other: TEST.args += --checkdev --other testarg-dev-INSTALL.sh_--install--gnuenv: TEST.args += --install --gnuenv testarg-dev-INSTALL.sh_--install--useenv: TEST.args += --install --useenv ALL.test.dev.INSTALL.sh += testarg-dev-INSTALL.sh_--checkdev--other \ testarg-dev-INSTALL.sh_--install--gnuenv \ testarg-dev-INSTALL.sh_--install--useenv ALL.test.dev += testarg-dev-INSTALL.sh_--checkdev--other \ testarg-dev-INSTALL.sh_--install--gnuenv \ testarg-dev-INSTALL.sh_--install--useenv # special option for gen_standalone.sh; must remove the generated file # generated file has permissions 555, hence rm -f # TODO: target works but gen_standalone.sh returns errors (needs to be improved) testarg-dev-contrib-standalone-tmp: EXE.pl = $(SRC.contrib.dir)/gen_standalone.sh testarg-dev-contrib-standalone-tmp: TEST.args = $(_TEST.dev.tmpfile) testarg-dev-contrib-standalone_tmpfile: testarg-dev-contrib-standalone-tmp @rm -f $(_TEST.dev.tmpfile) ALL.test.dev += testarg-dev-contrib-standalone_tmpfile # targets: EXE.* --help test.dev.help.all: $(ALL.test.dev.help) test.dev.help.log: $(ALL.test.dev.help:%=%.log) # targets: EXE.pl = perlpod test.dev.pod.all: $(ALL.test.dev.pod) test.dev.pod.log: $(ALL.test.dev.pod:%=%.log) # useless generated targets (as these are shell not perl programs) testarg-dev-o-saft_pod: @$(TRACE.target) testarg-dev-o-saft-docker_pod: @$(TRACE.target) testarg-dev-contrib-openssl_pod: @$(TRACE.target) testarg-dev-INSTALL.sh_pod: @$(TRACE.target) #_____________________________________________________________________________ #______________________________________________ special targets for testing __| HELP-_dev3 = _____________________________________ some special targets _ HELP-testarg-dev-grep_subs = list perl function definitions from '$(LIST.sources)' HELP-testarg-dev-grep_desc = same as testarg-dev-grep_subs but with description HELP-testarg-dev-grep_flow = show flow of functionality in '$(LIST.sources)' HELP-testarg-dev-grep_hint = list all _hint() from '$(LIST.sources)' HELP-testarg-dev-grep_warn = list all _warn() from '$(LIST.sources)' HELP-testarg-dev-grep_sub = list all subs from '$(SRC.pl)' HELP-testarg-dev-o-saft_notyet = test for 'NOT YET IMPLEMENTED' commands HELP-test.dev.grep.sub = alias for testarg-dev-grep_sub HELP-test.dev.grep.subs = alias for testarg-dev-grep_subs HELP-test.dev.grep.desc = alias for testarg-dev-grep_desc HELP-test.dev.grep.hint = alias for testarg-dev-grep_hint HELP-test.dev.grep.warn = alias for testarg-dev-grep_warn HELP-test.dev.grep.all = all targets testarg-dev-grep_* # extract from our source (information for developers) # TODO: need to generate individual targets testarg-dev-grep_subs: @$(TRACE.target) @$(foreach prg, $(LIST.sources), echo "" && echo "# egrep '^sub[[:space:]]' $(prg) ..." && cd $(TEST.dir)&&egrep '^sub[[:space:]]' $(prg); ) testarg-dev-grep_desc: @$(TRACE.target) @$(foreach prg, $(LIST.sources), echo "" && echo "# egrep '^((#___*|sub|our|proc)[[:space:]]|[[:space:]]+#[?])' $(prg) ..." && cd $(TEST.dir)&&egrep -s '^((#___*|sub|our|proc)[[:space:]]|[[:space:]]+#[?])' $(prg); ) testarg-dev-grep_flow: @$(TRACE.target) @$(foreach prg, $(LIST.sources), echo "" && echo "# egrep '^[[:space:]]*#[|]' $(prg) ..." && cd $(TEST.dir)&&egrep -s '^[[:space:]]*#[|]' $(prg); ) _TEST.brace=( # ) beat Make's foreach dragon testarg-dev-grep_hint: @$(TRACE.target) @$(foreach prg, $(LIST.sources), echo "" && echo "# grep '_hint$(_TEST.brace)' $(prg) ..." && cd $(TEST.dir)&&grep -H '_hint$(_TEST.brace)' $(prg) |sed -e 's/: */\t/'; ) testarg-dev-grep_warn: @$(TRACE.target) @$(foreach prg, $(LIST.sources), echo "" && echo "# grep '_warn$(_TEST.brace)' $(prg) ..." && cd $(TEST.dir)&&grep -H '_warn$(_TEST.brace)' $(prg) |sed -e 's/: */\t/'; ) # TODO: all above $(foreach ...) requires a ; at end, which may fail on Windows # function definitions more beautified for $(SRC.pl) EXE.grep-sub := perl -lane '\ 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];} \ ' # NOTE: $$ and \# in perl code is contribution to Makefile testarg-dev-grep_sub: @echo "#make: print all subs in $(SRC.pl) ..." @echo "" @echo "# function name | description" @echo "#-------------------------------+------------------------------------------" @$(EXE.grep-sub) $(SRC.pl) @echo "#-------------------------------+------------------------------------------" @echo "" ALL.test.dev.grep = testarg-dev-grep_subs testarg-dev-grep_desc \ testarg-dev-grep_flow testarg-dev-grep_sub \ testarg-dev-grep_hint testarg-dev-grep_warn test.dev.grep.all: $(ALL.test.dev.grep) .PHONY: $(ALL.test.grep) #.PHONY: $(ALL.test.grep:%=%.log) # some special targets testarg-dev-o-saft_notyet: TEST.dev.hosts = localhost testarg-dev-o-saft_notyet: @$(TRACE.target) @cd $(TEST.dir) && $(EXE.pl) --norc --header $(TEST.dev.hosts) $(LIST.o-saft.notyet) test.dev.grep.sub: testarg-dev-grep_sub test.dev.grep.subs: testarg-dev-grep_subs test.dev.grep.desc: testarg-dev-grep_desc test.dev.grep.hint: testarg-dev-grep_hint test.dev.grep.warn: testarg-dev-grep_warn ALL.test.dev.misc = testarg-dev-o-saft_notyet #ALL.test.dev += $(ALL.test.dev.help) $(ALL.test.dev.pod) # pdocuses duplicate ALL.test.dev += $(ALL.test.dev.grep) $(ALL.test.dev.misc) $(ALL.test.dev.o-saft-post) ALL.test.dev.log = $(ALL.test.dev:%=%.log) test.dev.log-compare: TEST.target_prefix = testarg-dev- test.dev.log-move: TEST.target_prefix = testarg-dev- test.dev.log: TEST.target_prefix = testarg-dev- test.dev: $(ALL.test.dev) test.dev.log: $(ALL.test.dev.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.docker000077500000000000000000000055551433765727300162410ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.docker #? #? VERSION #? @(#) Makefile.docker 1.6 22/11/04 20:01:01 #? #? AUTHOR #? 19-dec-19 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.docker = targets for testing $(Project)-docker _SID.docker := 1.6 _MYSELF.docker := t/Makefile.docker ALL.includes += $(_MYSELF.docker) ALL.inc.type += docker ALL.help.tests += help.test.docker first-docker-target-is-default: help.test.docker ifeq (,$(_SID.test)) -include t/Makefile endif TEST.docker.hosts = ifdef TEST.hosts TEST.docker.hosts = $(TEST.hosts) endif help.test.docker: HELP_TYPE = docker help.test.docker-v: HELP_TYPE = docker help.test.docker-vv: HELP_TYPE = docker HELP-_docker1 = ________________ testing o-saft-docker and o-saft in docker_ HELP-test.docker = test functionality of '$(EXE.docker)' HELP-test.docker.log = same as test.docker but store output in '$(TEST.logdir)/' HELP.docker = $(_NL)\ \# Testing docker functionality consist of two parts:$(_NL)\ \# - building, installing, pushing the docker image$(_NL)\ \# - testing the docker image$(_NL)\ \# This Makefile is about testing '$(EXE.docker)' working with the docker image.$(_NL)\ \# Examples:$(_NL)\ \# $(MAKE_COMMAND) testarg-docker-status$(_NL)\ \# $(MAKE_COMMAND) testarg-docker-call-env HELP.test.docker.all = # no special documentation yet LIST.docker.opts = -help inspect status usage # TODO: build apk rmi gui sshx shell root cp # in following: = used to simulate a space, see $(subst =, ,) below LIST.docker.call = -list call=env call=pwd call=id \ call=o-saft-docker call=ls call=ls=contrib LIST.docker.tool = +VERSION +version +quit=--traceARG=localhost # SEE Make:target name # SEE Make:target name prefix ifndef docker-macros-generated _LIST.docker.all = $(LIST.docker.opts) $(LIST.docker.call) $(LIST.docker.tool) _target=testarg-docker-$(subst =,-,$(arg)) $(foreach arg, $(_LIST.docker.all),\ $(eval $(_target): TEST.args = $(subst =, ,$(arg)) )\ $(eval ALL.test.docker += $(_target) ) \ ) undefine _target undefine _LIST.docker.all endif testarg-docker-%.log: EXE.log-filterarg = sed -e 's@\(HOSTNAME\)=.*@\1=$(TEST.logtxt)@' testarg-docker-%: EXE.pl = ../$(EXE.docker) testarg-docker-%: TEST.init = ALL.test.docker.log = $(ALL.test.docker:%=%.log) test.docker.log-compare:TEST.target_prefix = testarg-docker- test.docker.log-move: TEST.target_prefix = testarg-docker- test.docker.log: TEST.target_prefix = testarg-docker- test.docker: $(ALL.test.docker) test.docker.log: $(ALL.test.docker.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.etc000077500000000000000000000154121433765727300155360ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.etc #? #? VERSION #? @(#) Makefile.etc 1.18 22/11/04 21:12:55 #? #? AUTHOR #? 19-mar-19 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.etc = targets for testing ciphers with various other tools _SID.etc := 1.18 _MYSELF.etc := t/Makefile.etc ALL.includes += $(_MYSELF.etc) ALL.inc.type += etc ALL.help.tests += help.test.etc first-etc-target-is-default: help.test.etc ifeq (,$(_SID.test)) -include t/Makefile endif TEST.etc.hosts = localhost ifdef TEST.hosts TEST.etc.hosts = $(TEST.hosts) endif help.test.etc: HELP_TYPE = etc help.test.etc-v: HELP_TYPE = etc help.test.etc-vv: HELP_TYPE = etc HELP-_etc1 = ______________________________________________ testing ... _ HELP-test.etc = various legacy tests HELP-test.etc.log = same as test.etc but store output in '$(TEST.logdir)/' HELP-testcmd-etc-sslscan1.8 = test with sslscan version 1.8 HELP-testcmd-etc-sslscan1.11 = test with sslscan version 1.11.9 HELP-testcmd-etc-osaft_* = test with o-saft.pl +cipher* HELP-test.etc-cipher.all = test all tools with cipher tests HELP-test.etc-cipher.all.log = same as HELP-test-cipher.all but store output in '$(TEST.logdir)/' HELP.etc = # no general documentation yet HELP.test.etc.all = # no special documentation yet EXE.pl := ../o-saft.pl TEST.init := TEST.args := TEST.hosts = $(TEST.etc.hosts) # sslyze may have problems due to python2 vs. python3 # sslmap.py may have problems due to python2 vs. python3 # manyssl may have problems due to missing modules # tls-scan may have problems due to missing modules # # testcmd-etc-sslscan* are defined as static targets, similar to testcmd-% , they # can be used in the corresponding *.log target (pattern rule) automatically # errors in these targets are ignored (because they may be missing too) testcmd-etc-sslscan1.8: EXE.pl = /usr/bin/sslscan testcmd-etc-sslscan1.8: TEST.args = --no-failed testcmd-etc-sslscan1.8: -cd $(TEST.dir) && $(EXE.pl) $(TEST.args) $(TEST.hosts) #testcmd-etc-sslscan1.11: GNU make does not honor empty pattern testcmd-etc-sslscan1.1%: EXE.pl = /opt/bin/sslscan-1.11.9 testcmd-etc-sslscan1.1%: TEST.args = --no-colour --no-failed --no-check-certificate --no-heartbleed testcmd-etc-sslscan1.11: -cd $(TEST.dir) && $(EXE.pl) $(TEST.args) $(TEST.hosts) testcmd-etc-testssl.s%.log: EXE.log-filtercmd = awk '\ ($$1~/(Start|Done)/) {$$2="$(TEST.logtxt)"; $$3="";}\ {print}' # line start with space, hence $$2 is first text testcmd-etc-testssl.s%: EXE.pl = testssl.sh testcmd-etc-testssl.s%: TEST.args = -e --color 0 #testcmd-etc-testssl.sh%: TEST.args += --openssl /usr/local/openssl/bin/openssl testcmd-etc-testssl.sh: -cd $(TEST.dir) && $(EXE.pl) $(TEST.args) $(TEST.hosts) # get supported ciphers from each tool testcmd-etc-ssltest.pl%: EXE.pl = ssltest.pl testcmd-etc-ssltest.pl-count: TEST.args += --list testcmd-etc-ssltest.pl-count: @$(EXE.echo) -n "# $(EXE.pl)\t " @-cd $(TEST.dir) \ && $(EXE.pl) $(TEST.args) $(TEST.hosts) \ | awk '/iphers/{next}{c[$$2]++}END{print length(c)" ciphers"}' testcmd-etc-sslscan1.11-count: TEST.args += --show-ciphers testcmd-etc-sslscan1.11-count: @$(EXE.echo) -n "# sslscan1.11\t " @-cd $(TEST.dir) \ && $(EXE.pl) $(TEST.args) $(TEST.hosts) \ | awk '(0==NF){if(1==count){print length(c)" ciphers";exit;}}(1==count){c[$$1]++;}/Supported Client Cipher/{count=1}' testcmd-etc-testssl.sh-count: @$(EXE.echo) -n "# $(EXE.pl)\t " @-cd $(TEST.dir) \ && $(EXE.pl) $(TEST.args) $(TEST.hosts) | awk '/esting all/{print $$3" ciphers"}' testcmd-etc-osaft.pl%: EXE.pl = o-saft.pl testcmd-etc-osaft.pl-count: TEST.args += ciphers testcmd-etc-osaft.pl-count: @$(EXE.echo) -n "# $(EXE.pl)\t " @-cd $(TEST.dir) \ && $(EXE.pl) $(TEST.args) $(TEST.hosts) \ | awk '("ciphers"==$$3){sub(/= /,"");print}' ALL.testetc-count = \ testcmd-etc-sslscan1.11-count \ testcmd-etc-ssltest.pl-count \ testcmd-etc-testssl.sh-count \ testcmd-etc-osaft.pl-count # testcmd-etc-count is a slow target, as most tools test for the ciphers # to print the used/available ciphers _testcmd-etc-count-head: @$(EXE.echo) "# number of known ciphers supported by various tools" testcmd-etc-count: _testcmd-etc-count-head $(ALL.testetc-count) @$(TRACE.target) # use testcmd-% pattern rule for all o-saft.pl +cipher tests testcmd-etc-osaft_%: TEST.args = --enabled --header --no-hint $(TEST.hosts) testcmd-etc-osaft_--legacy-owasp: TEST.args = +cipher --enabled --header --legacy=owasp $(TEST.hosts) # tricky illegal option to enforce another (second) command with +cipher LIST.etc-osaft-CMDS := +cipher +cipherraw ALL.test.etc-cipher = \ testcmd-etc-sslscan1.8 \ testcmd-etc-sslscan1.11 \ testcmd-etc-testssl.sh \ testcmd-etc-osaft_--legacy-owasp \ $(LIST.etc-osaft-CMDS:%=testcmd-etc-osaft_%) ALL.test.etc-cipher.log = $(ALL.test.etc-cipher:%=%.log) # TODO: targets for following: # common test wih openssl: # echo | openssl s_client -tlsextdebug -msg -connect ${fqdn}:443 2>&1 | grep " Start" # DESCRIPTION # Debugging with special ciphers. # All programs need to return same list of ciphers. # Result with or without SNI may be different. # LIST.ciphers := DES-CBC3-SHA AES256-SHA ECDHE-RSA-AES256-SHA ECDHE-RSA-AES128-GCM-SHA256 #_LIST.ciphers = $(shell $(LIST.ciphers) :) #_LIST.c-regex = $(shell $(LIST.ciphers) |) # without SSI: # sslscan --tlsall --sni-name="x" $host |egrep "($(_LIST.c-regex))" # o-saft.pl --tracecmd --cipher=$(_LIST.ciphers) +cipher $host --nosni # o-saft.pl --tracecmd --cipher=$(_LIST.ciphers) +cipher $host --nosni --force-openssl # o-saft.pl --tracecmd --trace --cipher=$(_LIST.ciphers) +cipher $host --nosni # o-saft.pl --tracecmd --trace --cipher=$(_LIST.ciphers) +cipher $host --nosni --force-openssl # ALL.test-openssl = $(LIST.ciphers:%=%testcmd-openssl_%)) # # with SSI: # sslscan --tlsall $host |egrep "($(_LIST.c-regex))" # o-saft.pl --tracecmd --cipher=$(_LIST.ciphers) +cipher $host # o-saft.pl --tracecmd --trace --cipher=$(_LIST.ciphers) +cipher $host ALL.test.etc += $(ALL.test.etc-cipher) $(ALL.testetc-count) testcmd-etc-count ALL.test.etc.log += $(ALL.test.etc-cipher.log) test.etc.log-compare: TEST.target_prefix = testcmd-etc test.etc.log-move: TEST.target_prefix = testcmd-etc test.etc.log: TEST.target_prefix = testcmd-etc test.etc: $(ALL.test.etc) test.etc.log: $(ALL.test.etc.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.examples000077500000000000000000000156001433765727300166000ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.examples #? #? VERSION #? @(#) 1.9 22/09/21 09:58:23 #? #? AUTHOR #? 19-apr-19 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.examples = print targets for testing documented examples _SID.examples := 1.9 _MYSELF.examples := t/Makefile.examples ALL.includes += $(_MYSELF.examples) ALL.inc.type += examples ALL.help.tests += help.test.examples first-examples-target-is-default: help.test.examples ifeq (,$(_SID.test)) -include t/Makefile endif help.test.examples: HELP_TYPE = examples help.test.examples-v: HELP_TYPE = examples help.test.examples-vv: HELP_TYPE = examples #_____________________________________________________________________________ #________________________________________________________________ variables __| TEST.examples.hosts = localhost HELP-_examples1 = ______________________________ testing documented examples _ HELP-test.examples = test various documented examples HELP-test.examples.log = same as test.examples but store output in '$(TEST.logdir)/' HELP.examples = # no special documentation yet HELP.test.examples.all = # no special documentation yet #_____________________________________________________________________________ #______________________________________________________ targets for testing __| # These tests are not yet added to ALL.tests because most of them are mainly # variants of tests done in other Makefiles. The test targets herein are merely # intended to check if the documented examples will work and return the proper # results. # Following are mainly the examples shown with: o-saft.pl --help=EXAMPLES # remember: testarg-% executes: # cd $(TEST.dir) && $(EXE.pl) $(TEST.init) $(TEST.args) testarg-example-%: TEST.init = $(TEST.examples.hosts) #testarg-example-%: EXE.pl = ../o-saft.pl # EXE.pl left to default o-saft.pl without path, because this Makefile is # not part of the "tests" target # TODO: following targets should be generated like: # $(EXE.pl) --help=EXAMPLES | awk '($1=="o-saft.pl"){sub(/some.tld/,"");print}' testarg-example-+cipher: TEST.args = +cipher testarg-example-+info: TEST.args = +info testarg-example-+check: TEST.args = +check testarg-example-+quick: TEST.args = +quick testarg-example-+list: TEST.args = +list testarg-example-+list--v: TEST.args = +list --v testarg-example-+version: TEST.args = +version testarg-example-+version--v: TEST.args = +version --v testarg-example-+help-commands: TEST.args = +help=commands testarg-example-+certificate: TEST.args = +certificate testarg-example-+fingerprint: TEST.args = +fingerprint testarg-example-+after+dates: TEST.args = +after +dates testarg-example-+check--c-RC4: TEST.args = +check --cipher=RC4 testarg-example-+sni: TEST.args = +sni testarg-example-+sni_check: TEST.args = +sni_check testarg-example-+sni+cn+altname:TEST.args = +sni +cn +altname testarg-example-+cipher--ena: TEST.args = +cipher --enabled testarg-example-+cipher--dis: TEST.args = +cipher --disabled testarg-example-+cipher--cipher:TEST.args = +cipher --cipher=ADH-AES256-SHA #testarg-example-checkAllCiphers: TEST.args = checkAllCiphers.pl example.tld --range=full --v testarg-example-+cipher-dh: TEST.args = +cipher-dh #testarg-example---lib-_foo: TEST.args = +cipher --lib=/foo/bar-1.42 --exe=/foo/bar-1.42/apps #testarg-example---openssl-foo: TEST.args = --openssl=/foo/bar-1.42/openssl #testarg-example---help-cfg-text: TEST.args = --help=cfg-text >>.o-saft.pl testarg-example-+check--cfg-text: TEST.args = +check --cfg-text=desc="my special description" testarg-example-+check--cfg-hint: TEST.args = +check --cfg-hint=renegotiation="my special hint text" #testarg-example-+cn-hosts: TEST.args = +cn example.tld some.tld other.tld #testarg-example-+cn--showhost: TEST.args = +cn example.tld some.tld other.tld --showhost --no-header testarg-example---legacy-quick1: TEST.args = --legacy=quick --no-header +info testarg-example---legacy-quick2: TEST.args = --legacy=quick --no-header +check testarg-example---legacy-quick3: TEST.args = --legacy=quick --no-header --trace-key +info testarg-example---legacy-quick4: TEST.args = --legacy=quick --no-header --trace-key +check testarg-example---legacy-quick5: TEST.args = --legacy=quick --no-header --trace-key --showhost +check some.tld other.tld testarg-example-+fingerprint-raw: TEST.args = +fingerprint --format=raw testarg-example---exitcode: TEST.args = +check --exitcode testarg-example---exitcode-v: TEST.args = +check --exitcode --exitcode-v testarg-example---exitcode--ignore-out: TEST.args = +check --exitcode --ignore-out=ev- --ignore-out=rfc_7525 testarg-example---exitcode-no-prot: TEST.args = +cipher --exitcode --exitcode-no-prot testarg-example-+info--no-rc: TEST.args = +info --no-rc testarg-example-+info--trace: TEST.args = +info --trace testarg-example-+info--trace-key: TEST.args = +info --trace-key testarg-example-+info--trace-arg: TEST.args = +info --trace-arg testarg-example-+info--trace-cmd: TEST.args = +info --trace-cmd testarg-example-+info--trace-time: TEST.args = +info --trace-time testarg-example-+info--no-cert: TEST.args = +info --no-cert --no-cert --no-cert-text=Value-from-Certificate testarg-example-+info--no-dns: TEST.args = +info --no-dns --no-sni --ignore-no-conn testarg-example-+info--no-http: TEST.args = +info --no-dns --no-sni --no-cert --no-http --no-openssl testarg-example-+chain_verify: TEST.args = +chain_verify +verify +error_verify +chain testarg-example-+cipher--v--v: TEST.args = +cipher --v --v testarg-example-+cn--trace: TEST.args = +cn --trace --trace test.examples.log-compare: TEST.target_prefix = testarg-examples test.examples.log-move: TEST.target_prefix = testarg-examples test.examples.log: TEST.target_prefix = testarg-examples ALL.testexamples = $(shell awk -F: '/^testarg-example-.*%/{next} /^testarg-example-/{arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_MYSELF.examples)) ALL.test.examples = $(ALL.testexamples) ALL.test.examples.log= $(ALL.test.examples:%=%.log) test.log-compare-hint test.examples.all: $(ALL.test.examples) test.examples: test.examples.all test.examples.log: $(ALL.test.examples.log) #_____________________________________________________________________________ #_____________________________________________________________________ test __| # main Makefile not yet feeded #ALL.tests += $(ALL.test.examples) #ALL.tests.log += $(ALL.test.examples.log) O-Saft-22.11.22/t/Makefile.exit000077500000000000000000000051621433765727300157350ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.exit #? #? VERSION #? @(#) Makefile.exit 1.30 22/11/13 21:36:02 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.exit = targets for testing '$(SRC.pl)' --exit= option _SID.exit := 1.30 _MYSELF.exit := t/Makefile.exit ALL.includes += $(_MYSELF.exit) ALL.inc.type += exit ALL.help.tests += help.test.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.test.exit: HELP_TYPE = exit help.test.exit-v: HELP_TYPE = exit help.test.exit-vv: HELP_TYPE = exit HELP-_exit1 = ___________________________________ testing --exit* option _ HELP-test.exit = test --exit=* options HELP-test.exit.log = same as test.exit but store output in '$(TEST.logdir)/' HELP.exit = # no special documentation yet HELP.test.exit.all = # no special documentation yet # all known --exit= are shown with: o-saft.pl --norc --help=exit # SEE Make:target name # SEE Make:target name prefix LIST.o-saft.pl--exit := \ --exit=invalid_label_to_show_failed-status \ --exit=BEGIN0 --exit=BEGIN1 --exit=INIT0 --exit=CONF0 --exit=CONF1 \ --exit=INIT1 --exit=ARGS --exit=MAIN \ --exit=HOST0 --exit=HOST1 --exit=HOST2 --exit=HOST3 --exit=HOST4 \ --exit=HOST5 --exit=HOST6 --exit=HOST8 --exit=HOST9 --exit=END # all targets are generated, see Makefile.gen; only one program: SRC.pl testarg-exit-o-saft.pl_%: EXE.pl = ../$(SRC.pl) testarg-exit-o-saft.pl_%: TEST.init = --trace-CLI +cn $(TEST.host) #testarg-exit-o-saft.pl_--exit-HOST0: TEST.init = --trace-CLI +cn $(TEST.host) ifndef exit-macros-generated # must use GEN.targets instead of GEN.targets-args to avoid setting TEST.init $(eval $(call GEN.targets,testarg,exit,-$(SRC.pl),$(SRC.pl),LIST.o-saft.pl--exit,TEST.args,_TEST.dumm)) endif # some special targets testarg-exit-o-saft.pl_--exit-WARN: TEST.args += --exit=WARN +force-warning #testarg-exit-o-saft.pl_--exit-HOST7: TEST.args += --exit=HOST7 ALL.test.exit.log = $(ALL.test.exit:%=%.log) test.exit.log-compare: TEST.target_prefix = testarg-exit test.exit.log-move: TEST.target_prefix = testarg-exit test.exit.log: TEST.target_prefix = testarg-exit test.exit: $(ALL.test.exit) test.exit.log: $(ALL.test.exit.log) O-Saft-22.11.22/t/Makefile.ext000077500000000000000000000110641433765727300155620ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.ext #? #? VERSION #? @(#) Makefile.ext 1.29 22/09/21 09:59:14 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.ext = targets for testing '$(SRC.pl)' with external FQDN _SID.ext := 1.29 _MYSELF.ext := t/Makefile.ext ALL.includes += $(_MYSELF.ext) ALL.inc.type += ext ALL.help.tests += help.test.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.test.ext: HELP_TYPE = ext help.test.ext-v: HELP_TYPE = ext help.test.ext-vv: HELP_TYPE = ext HELP-_ext1 = ______________________________ testing with external hosts _ HELP-test.ext = test all commands with all hostnames, alias for test.ext.host HELP-test.ext.host = test all commands with all hostnames (sorted by host) HELP-test.ext.host.log = same as test.ext.host but store output in logfile HELP-test.ext.command = test all commands with all hostnames (sorted by command) HELP-test.ext.log = alias for test.ext.host.log HELP-test.ext.host.quick= test some commands with all hostnames HELP-_ext2 = ________________ testing a special cmd with external hosts _ HELP-testcmd-eDDD_HOST = specific test target with HOST HELP-testcmd-eDDD_HOST.log = store output of testcmd-DDD_HOST in t/testcmd-DDD_HOST.log HELP.ext = $(_NL)\ \# Examples:$(_NL)\ \# $(MAKE_COMMAND) testcmd-e001_localhost$(_NL)\ \# $(MAKE_COMMAND) s-ALL.ext.host TEST.file=t/Makefile.FQDN $(_NL)\ \# $(MAKE_COMMAND) s-ALL.ext.host TEST.hosts='a1.tld a2.tld'$(_NL)\ \# $(MAKE_COMMAND) test.ext.host TEST.hosts='a1.tld a2.tld'$(_NL)\ \#$(_NL)\ \# Note that external hosts are listed one per line in t/Makefile.FQDN HELP.test.ext.all = # no special documentation yet # SEE Make:target name # SEE Make:target name prefix 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-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]/{arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_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.ext.host = $(ALL.by_host) ALL.ext.host.log = $(ALL.by_host:%=%.log) # don't set ALL.test.ext and ALL.test.ext.log to avid useless make calls _ALL.test.ext = $(ALL.by_host) _ALL.test.ext.log = $(ALL.test.ext:%=%.log) # TODO: use target _no-hosts test.ext.command: $(ALL.by_command) test.ext.host: $(ALL.by_host) test.ext.host.log: $(ALL.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-compare: TEST.target_prefix = testcmd-e test.ext.log-move: TEST.target_prefix = testcmd-e test.ext.log: TEST.target_prefix = testcmd-e test.ext: $(ALL.test.ext) test.ext.log: $(ALL.test.ext.log) # test.log-compare-hint not yet used O-Saft-22.11.22/t/Makefile.gen000066400000000000000000000162071433765727300155340ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.gen #? #? VERSION #? @(#) Makefile.gen 1.5 22/11/13 21:57:41 #? #? AUTHOR #? 22-oct-22 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.gen = make functions to generate targets _SID.gen := 1.5 _MYSELF.gen := t/Makefile.gen ALL.includes += $(_MYSELF.gen) ALL.inc.type += gen ALL.help.tests += help.test.gen first-gen-target-is-default: help.test.gen ifeq (,$(_SID.test)) -include t/Makefile endif help.test.gen: HELP_TYPE = gen help.test.gen-v: HELP_TYPE = gen help.test.gen-vv: HELP_TYPE = gen help.test.gen: _HELP-help.make = # text from _HELP-help.make is useless for documentation here help.test.gen: D = "$$" # need a literal $ below #_____________________________________________________________________________ #________________________________________________________________ variables __| HELP-_gen1 = __________________________ testing internal documentations _ HELP-test.gen = internal test of target generation functions HELP-test.gen.log = same as test.gen but store output in '$(TEST.logdir)/' HELP-_gen2 = ______________________________ target generation functions _ HELP-GEN.targets = GEN.targets(prefix,typ,tool,var-name,var-for-args,var-set-empty) HELP-GEN.targets-args = GEN.targets-args(prefix,typ,tool,var-name) HELP-GEN.targets-init = GEN.targets-init(prefix,typ,tool,var-name) HELP.gen = $(_NL)\ \# Beside the target 'test.gen' for internal testing, no other targets are$(_NL)\ \# provides but only functions. The desciption of the targets can be found$(_NL)\ \# in Makefile.pod, SEE Make:target generation . #_____________________________________________________________________________ #______________________________________________ target generation functions __| ifndef gen-macros-generated # SEE Make:macros # SEE O-Saft Makefile Variable, Macro names # arguments from $3 used in the target name must not contain / # hence $(subst /,-,$3) is used to replace / by - # arguments from $4 used in the target name must not contain = # hence $(subst =,-,$(_arg)) is used to replace = by - define GEN.targets # parameter: target-prefix=$1, Makefile.typ=$2, target-tool=$3, tool=$4, # variable-name_for_args=$5, # var-name_to_assign_args=$6, var-name_set_empty=$7 # generates targets: $1-$2$3_$4 and $1-$2$3_% # example: testcmd-gen-some-tool--arg # beside the prefix '-' $3 and $4 are identical usually, to avoid use of # the tools name ($4) in the target name, $3 can be set empty $(eval _help-typ.prg=HELP-test.$2.$(subst /,-,$4)) $(eval _test.typ.prg=test.$2.$(subst /,-,$4)) $(eval _testtype-prg=$1-$2$(subst /,-,$3)) $(foreach _arg, $($5),\ $(eval _target=$(_testtype-prg)_$(subst =,-,$(_arg))) \ $(eval ALL.$(_test.typ.prg) += $(_target)) \ $(eval $(_target): $6 = $(_arg)) \ ) \ $(eval $(_help-typ.prg) = targets for testing arguments of '$4') $(eval $(_testtype-prg)_%: EXE.pl = ../$4) $(eval $(_testtype-prg)_%: $7 = ) $(eval ALL.test.$2 += $(ALL.$(_test.typ.prg))) $(eval ALL.$(_test.typ.prg).log += $(ALL.$(_test.typ.prg):%=%.log)) $(eval $(_test.typ.prg).all: $(ALL.$(_test.typ.prg))) $(eval $(_test.typ.prg).log: $(ALL.$(_test.typ.prg).log)) $(eval $(_test.typ.prg).log-compare: TEST.target_prefix = $(_testarg-prg)_) $(eval $(_test.typ.prg).log-move: TEST.target_prefix = $(_testarg-prg)_) $(eval $(_test.typ.prg).log: TEST.target_prefix = $(_testarg-prg)_) undefine _arg undefine _target undefine _help-typ.prg undefine _test.typ.prg undefine _testtype-prg $(eval undefine _help-typ.prg) $(eval undefine _test.typ.prg) $(eval undefine _testtype-prg) endef define GEN.targets-args # parameter: target-prefix=$1, Makefile.typ=$2, tool=$3, variable-name_for_args=$4 # generate targets with argument assigned to TEST.args, TEST.init set empty $(call GEN.targets,$1,$2,-$3,$3,$4,TEST.args,TEST.init) endef define GEN.targets-init # parameter: target-prefix=$1, Makefile.typ=$2, tool=$3, variable-name_for_args=$4 # generate targets with argument assigned to TEST.init, TEST.args set empty $(call GEN.targets,$1,$2,-$3,$3,$4,TEST.init,TEST.args) endef endif #_____________________________________________________________________________ #___________________________________________________________ testing myself __| TEST.gen.exe := Some/Dumm.pm LIST.Some-Dumm.pm := --arg=1 --arg=2 LIST.gen.inc-type := tst LIST.gen.expected := testarg-tst-Some-Dumm.pm_--arg-1 testarg-tst-Some-Dumm.pm_--arg-2 LIST.gen.TEST.init := TEST.init-arg1 TEST.init-arg2 ifndef gen-macros-generated $(eval _tst=$(LIST.gen.inc-type)) $(foreach prg, $(TEST.gen.exe),\ $(eval _name=$(subst /,-,$(prg))) \ $(eval $(call GEN.targets-args,testarg,$(_tst),$(prg),LIST.$(_name))) \ ) undefine _tst undefine _name endif testarg-tst-Some-Dumm.pm_--arg-2: TEST.init = $(LIST.gen.TEST.init) # Following targets tests the above generated targets. It first prints some # information about the expected output of the following called make. While # is shown verbatime. test.gen: @echo "#### generated targets for:" @echo "# program: 'EXE.pl = $(TEST.gen.exe)'" @echo "# arguments: 'LIST.Some-Dumm.pm = $(LIST.Some-Dumm.pm)'" @echo "# Makefile.tst: 'ALL.inc.type = tst'" @echo "#### add TEST.init for 'target testarg-tst-Some-Dumm.pm_--arg-2' only:" @echo "# 'TEST.init = $(LIST.gen.TEST.init)'" @echo "#" @echo "#### list generated targets, should return:" @echo " $(LIST.gen.expected)" $(MAKE) s-ALL.test.tst @echo "#" @echo "#### list generated targets, should return:" @echo " $(LIST.gen.expected:%=%.log)" $(MAKE) s-ALL.test.tst.Some-Dumm.pm.log @echo "#" @echo "#### list commands or each target, should return one command line for each:" $(MAKE) -n testarg-tst-Some-Dumm.pm_--arg-1 testarg-tst-Some-Dumm.pm_--arg-2 @echo "# \-- program --/ \-- arguments ..." @echo "#" test.gen.log: @echo "#### show commands for test.tst.Some-Dumm.pm.log" $(MAKE) test.tst.Some-Dumm.pm.log EXE.pl=echo @-$(EXE.log-compare-hint) @-$(EXE.log-move-hint) # Last make tests functionality of the target, not of the program EXE.pl # used in the target. As the specified EXE.pl is a dummy string, it will # be replaced by echo, which then will be executed. test.gen.log-compare: TEST.target_prefix = testarg-gen- test.gen.log-move: TEST.target_prefix = testarg-gen- #_____________________________________________________________________________ #_____________________________________________________________________ test __| ALL.test.gen = test.gen ALL.test.gen.log = $(ALL.test.gen:%=%.log) O-Saft-22.11.22/t/Makefile.help000066400000000000000000000371721433765727300157170ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for help targets of O-Saft project #? #? SYNOPSYS #? make [options] [target] [...] #? #? DESCRIPTION #? For detailed descriptions please see t/Makefile.pod . #? #? EXAMPLES #? make help.doc #? 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 #? #? VERSION #? @(#) Makefile.help 1.90 22/02/22 08:11:34 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.help = targets to get information/documentation from Makefiles _SID.help := 1.90 _MYSELF.help := t/Makefile.help ALL.includes += $(_MYSELF.help) ALL.inc.type += help ALL.help.tests += help.test.help MAKEFLAGS += --no-builtin-variables --no-builtin-rules .SUFFIXES: first-help-target-is-default: help.help help.test.help: HELP_TYPE = help help.test.help-v: HELP_TYPE = help #_____________________________________________________________________________ #________________________________________________________________ variables __| # internal variables _TAB := \\011 _NL := \\012 _CR := \\015 T := $$""(_NL) # define _SP containing a single space (tricky as _TEST.empty is empty) _TEST.empty := _SP := $(_TEST.empty) $(_TEST.empty) # internal help # HELP_TYPE - type of the Makefile*, must be the filename's extension # (the definition here is a default dummy to avoid errors # using this Makefile.help, resulting in wrong output) # HELP_INFO - formatted header line to show general informations # HELP_NAME - formatted header line to show macro/variable definition # HELP_RULE - formatted header line to show target definition # HELP_LINE - just a separation line (used in tabular output) # HELP_HEAD - actual header line, defined per target; it's usualy set # to HELP_INFO, HELP_NAME or HELP_RULE, can be individual # HELP_HEADER - complete text for header in tabular output, looks like: # #---------------+---------- # # key | value # #---------------+---------- # it's mainly used in internal targets like _help.HEAD HELP_TYPE = help HELP_INFO := \# Name | Description/Content HELP_NAME := \# Macro/Variable| Value HELP_RULE := \# Target | Description HELP_LINE := \#---------------+-------------------------------------------------------------- HELP_HEAD = $(HELP_NAME) HELP_HEADER = $(HELP_LINE)\012$(HELP_HEAD)\012$(HELP_LINE) HELP_USAGE = **USAGE: $(MAKE_COMMAND) $($@) '$($@)=your-query' HELP_F_TARGET = _file doc.all-v:HELP_F_TARGET = _file-v # HELP_HEAD and HELP_RULE will be set conditionally per target/rule also # setting if Makefile.inc not included help.inc: HELP_TYPE = inc help.inc: HELP_HEAD = $(HELP_RULE) # Define scripts as variables, for better human readability. For details about # the commands for matching macro and target names, please see in Makefile.pod # "O-Saft Makefile Syntax" and "Make:target matching". # Script variables defined in t/Makefile: # _EXE.macro_by_line.awk - extract macro names # _EXE.target_by_line.awk - extract target names # _EXE.target_to_arr.awk - extract target names, store uniquely in arr # _EXE.print_arr_END.awk - print collected data from arr[] # _EXE.print_file.awk - either print seperator line or the filename # Script variables defined below: # _EXE.HELP_by_line.awk - extract HELP- macro names for documentation # the HELP-_* print as is # HELP-* extract target name and print with text # _EXE.gen_eval_target.awk - print f-* and _f-* target name from HELP-* macro # _EXE.gen_print_file.awk - print # NOTE: FILENAME there is an awk variable _EXE.HELP_by_line.awk := \ /^HELP-_/{sub(/ /,"",$$2); print "\n\t\t\#"$$2; next}\ /^HELP-/{ key=$$1; txt=substr($$0,index($$0,"=")+2);\ sub(/HELP-/,"",key); gsub(/ /,"",key); \ tab="\t"; if(length(key)<8){tab="\t\t";} \ printf("%s%s\# %s\n",key,tab,txt); \ } _EXE.gen_eval_target.awk:= /^HELP-_/{print "_f-"$$1}/^HELP-[^ _]/{sub(/HELP-/,"");print "f-"$$1} _EXE.gen_print_file.awk := (FNR==1){ print "$(HELP_F_TARGET)"FILENAME} %-v: _EXE.print_file.awk:= (FNR==1){ print "\n\t\t\# ---------- "FILENAME" ..." } # Tools used to gather information from Makefile*, take care! real TABS are # inside the sed commands. # I.g. awk should be prefered where possible and feasible, as sed matches last # occurrence of a pattern. # Above script variables and following tool variables rely on the conventions # (variable names, etc.) as defined in Makefile.pod "O-Saft Makefile Syntax". EXE.eval = awk -F= '$(_EXE.gen_print_file.awk)$(_EXE.gen_eval_target.awk)' EXE.list = awk '$(_EXE.print_file.awk)$(_EXE.macro_by_line.awk)' EXE.help = awk -F= '$(_EXE.print_file.awk)$(_EXE.HELP_by_line.awk)' 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 '$(_EXE.print_file.awk)$(_EXE.target_by_line.awk)' 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:... ifndef EXE.echo EXE.echo = /bin/echo -e endif ifndef EXE.dummy EXE.dummy = /bin/echo -n "" endif ifndef _MYSELF.inc # dummy setting until Makefile.inc is included, keeps errors away _MYSELF.inc = t/Makefile.inc endif ifndef _EXE.sort-opt # setting until Makefile.inc is included _EXE.sort-opt := -n -f endif #_____________________________________________________________________________ #_________________________________________________________ internal targets __| _HELP-_help0 = _________________________________ targets for internal use _ _HELP-help.HEAD = print table header for documentation texts _HELP-help.BODY = print table body for documentation texts (all HELP-* lines) _HELP-help.FOOT = print table footer for documentation texts _HELP-help.HELP = print individual documentation texts (HELP.TYP variale) #HELP-help.LIST = print targets for getting list of targets (testing targets only) _HELP-help.LIST = $(_NL)\ \# To get a list of targets, use:$(_NL)\ \# make help.test.$(HELP_TYPE).all$(_NL)\ \# make e-ALL.test.$(HELP_TYPE)$(_NL)\ \# make s-ALL.test.$(HELP_TYPE) _HELP-help.make = $(_NL)\ \# To see which commands in a TARGET are executed, simply call 'make -n TARGET'$(_NL)\ \# Note that the *.log targets then report a bunch of shell commands.$(_NL)\ _help.HEAD: @echo "$(HELP_HEADER)" _help.FOOT: @echo "$(HELP_LINE)" _help.BODY: @$(TRACE.target) @$(EXE.help) $(_MYSELF.$(HELP_TYPE)) _help.LIST: @$(TRACE.target) @echo "$(_HELP-help.LIST)" # same as _help.FOOT but unique name, so it can be used together with _help.FOOT _help.LINE: @echo "$(HELP_LINE)" # neet to set own variable name because $($(HELP.$(HELP_TYPE))) does not work _help.HELP: _HELP_HELP = HELP.$(HELP_TYPE) _help.HELP: @$(TRACE.target) @echo "$($(_HELP_HELP))" @echo "$(_HELP-help.make)" .PHONY: _help.HEAD _help.BODY _help.FOOT _help.LIST _help.HELP #_____________________________________________________________________________ #_____________________________________________________________ help targets __| # line printed with help should work copy&paste, hence some dummy definitions MYmacro = dummy macro/variable used in examples MYtarget: MYVAR = dummy target macro used in examples MYtarget: dummy_dependency @$(EXE.dummy) HELP-_help1 = __________________________ targets for help about Makefile _ HELP-macros = list all macro names used in Makefile* (alias: list, vars) HELP-targets = list all targets used in Makefile* (alias: rules) HELP-macros.me = list all macro names used in calling Makefile HELP-targets.me = list all targets used in calling Makefile HELP-e-MYmacro = show content of MYmacro expanded (all in one line) HELP-s-MYmacro = show content of MYmacro expanded (one word per line) HELP-m-MYmacro = show definition of MYmacro as is - exact macro match HELP-p-MYmacro = show all definitions of MYmacro as is - macro pattern match HELP-t-MYtarget = show MYtarget - exact target match HELP-_help2 = ________________________________ targets for documentation _ HELP-help.help = print this documentation HELP-help.doc = same as help.help HELP-help.all = print all targets, including test and development targets # # HELP-help.all - same as in ../Makefile (cannot be reused) HELP-help.test = print documentation about test targets HELP-help.critic= print documentation about perlcritic targets # # HELP-help.critic - also in Makefile.critic (a bit different) HELP-help.makefiles.doc = print documentation about available Makefile.* # # HELP-help.makefiles.doc - also in Makefile.makefiles HELP.help = $(_NL)\ \# To see in which Makefile* the listed targets are defined, use following:$(_NL)\ \# $(MAKE_COMMAND) help.all-v $(_NL)\ \# The targets to show information/content from the Makefile are:$(_NL)\ \# echo eval macro pmacro show target$(_NL)\ \# which are used like: $(_NL)\ \# $(MAKE_COMMAND) echo echo=MYVAR $(_NL)\ \# $(MAKE_COMMAND) macro macro=MYVAR $(_NL)\ \# For easy use, following alias exist: $(_NL)\ \# e- m- p- s- t- $(_NL)\ \# which are used like: $(_NL)\ \# $(MAKE_COMMAND) e-MYmacro $(_NL)\ \# $(MAKE_COMMAND) m-MYmacro $(_NL)\ \# $(MAKE_COMMAND) p-MYmacro $(_NL)\ \# $(MAKE_COMMAND) s-MYmacro $(_NL)\ \# $(MAKE_COMMAND) t-MYtarget $(_NL)\ ALL.help += help.help help.critic help.doc ALL.help += $(ALL.help.tests) # add all other help.test* targets # our own targets using help% or alike help.help: HELP_TYPE = help help.help%: HELP_TYPE = help help.help: HELP_HEAD = $(HELP_RULE) help.help%: HELP_HEAD = $(HELP_RULE) help.doc%: HELP_HEAD = $(HELP_RULE) help.doc.all: HELP_HEAD = $(HELP_RULE) target: HELP_HEAD = $(HELP_RULE) help.%: _help.HEAD _help.BODY _help.FOOT _help.LIST _help.HELP @$(TRACE.target) # The main difference between the targets help and doc is, that help uses # external tools to extract the information from Makefile*, while target doc # uses make's functionality to display the same information and also evaluates # variables used in the targets. Both targets use the same text. # legacy aliases help.doc: help.help .PHONY: help.doc # Following file% targets are used for doc.all target only, they are just a # dirty hack so that output of target help.all and doc.all are similar. # NOTE: quick&dirty as $(TEST.dir) is hardcoded as t/ in the target names. _HELP_LINE := \#------------------------------------------------------------- _filet/%: _file-egal @echo "" @echo "\t\t$(_HELP_LINE)" _file%: @echo "" @echo "\t\t$(_HELP_LINE)" _file-vt/%: @echo "" @echo "\t\t# ---------- t/$* ..." _file-v%: @echo "" @echo "\t\t# ---------- $* ..." #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 \ $(EXE.echo) "$(HELP-$($@))"; \ $(EXE.echo) "$(HELP_USAGE)"; \ exit 1; \ fi; @$(EXE.echo) "$(HELP_HEADER)" _line: @echo "" @$(EXE.echo) "$(_TAB)$(_TAB)#$($($@))" .PHONY: _notempty _line help-makefiletitle-%: @$(TRACE.target) @$(EXE.echo) "Makefile.$*$(_TAB)# $(HELP-help.test.$*)" macros: @$(TRACE.target) @$(EXE.list) $(MAKEFILE_LIST) | sort $(_EXE.sort-opt) macros%me: @$(TRACE.target) @$(EXE.list) $(MAKEFILE) | sort $(_EXE.sort-opt) vars: macros list: macros lists%me: macros.me targets: @$(TRACE.target) @$(EXE.targets) $(MAKEFILE_LIST) | sort -u -f targets%me: @$(TRACE.target) @$(EXE.targets) $(MAKEFILE) | sort -u -f rules: targets rules%me: targets.me # eval target quick&dirty: # @$(EXE.echo) "$($@)$(_TAB)$(_TAB)# $(HELP-$($@))" # pretty printed format using awk see below eval: @$(TRACE.target) @$(EXE.echo) "$($@) $(HELP-$($@))" | awk '{t="\t# ";if(length($$1)<8){t="\t\t# ";}sub(/ /,t);print}' # Following targets are used to show information about variables and targets: # echo, eval, macro, pmacro, show, target # The targets get the name of the macro, variable or target in a variable with # the same name as the target itself. Example: # make macro macro=MAKEFILE # To simplify command lines, a pattern rule exists for each of these targets. # Example: # make m-MAKEFILE # These targets search in all makefiles, using $(MAKEFILE_LIST), and not our # own $(ALL.Makefiles). This way the targets work in all other makefiles too, # somehow, (if they include this one). # FIXME: echo fails if the content of the variable contains braces or semicolon echo: @$(TRACE.target) @$(EXE.echo) '$($($@))' show: _notempty=show show: _notempty @$(TRACE.target) @$(EXE.echo) '$($@) = ' @$(EXE.echo) '$($($@))' | $(EXE.wordperline) macro: _notempty=macro macro: _notempty @$(TRACE.target) @$(EXE.macro) $(MAKEFILE_LIST) makro: macro pmacro: _notempty=pmacro pmacro: _notempty @$(TRACE.target) @$(EXE.pmacro) $(MAKEFILE_LIST) target: _notempty=target target: _notempty @$(TRACE.target) @$(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 .PHONY: macros targets rules list vars eval echo show macro pmacro target #_____________________________________________________________________________ #_____________________________________________________________________ test __| # NOT YET IMPLEMENTED/USED # HELP-_help4 = _____________________________________ testing help targets _ # HELP-test.help = test help* targets of our Makefiles # HELP-test.help.log = same as test.help but store output in '$(TEST.logdir)/' # HELP-test.help.log-compare = compare results of test.help.log (if any) ALL.testhelp = $(shell awk -F: '/^testcmd-help%/{next} /^testcmd-help/{arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_MYSELF.help)) ALL.test.help = $(ALL.testhelp) ALL.test.help.log = $(ALL.test.help:%=%.log) test.help.log-compare: TEST.target_prefix = testcmd-help test.help.log-move: TEST.target_prefix = testcmd-help test.help.log: TEST.target_prefix = testcmd-help # TODO: explain test.help uses "make help", while test.hlp uses "o-saft.pl --help" test.help: $(ALL.test.help) test.help.log: $(ALL.test.help.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.hlp000077500000000000000000000124741433765727300155530ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.hlp #? # HACKER's INFO # To avoid naming conflicts with Makefile.help this file must be named # Makefile.hlp . # #? VERSION #? @(#) Makefile.hlp 1.48 22/11/13 21:35:36 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.hlp = targets for testing '$(SRC.pl)' --help options _SID.hlp := 1.48 _MYSELF.hlp := t/Makefile.hlp ALL.includes += $(_MYSELF.hlp) ALL.inc.type += hlp ALL.help.tests += help.test.hlp first-hlp-target-is-default: help.test.hlp ifeq (,$(_SID.test)) -include t/Makefile endif TEST.hlp.hosts = ifdef TEST.hosts TEST.hlp.hosts = $(TEST.hosts) endif help.test.hlp: HELP_TYPE = hlp help.test.hlp-v: HELP_TYPE = hlp help.test.hlp-vv: HELP_TYPE = hlp HELP-_hlp1 = ___________________________________ testing --help options _ HELP-test.hlp = test help commands and options of '$(SRC.pl)' HELP-test.hlp.log = same as test.hlp but store output in t/testcmd-CMD.log HELP.hlp = # no special documentation yet HELP.test.hlp.all = # no special documentation yet testarg-hlp-%: EXE.pl = ../$(SRC.pl) testarg-hlp-%: TEST.init = --header --no-rc # --no-rc ensures that a local RC-file does not change the results # all other commands with --trace-CLI testarg-hlp-o-saft.pl_--legacy-%: TEST.init += --trace-CLI +list testarg-hlp-o-saft.pl_+ciphers--%: TEST.init += --trace-CLI +ciphers testarg-hlp-o-saft.pl_--help%: TEST.init += --trace-CLI # these are kind of help, but do not use --help LIST.hlp.help-like := \ +help=commands --cmd=VERSION --cmd=version +VERSION +version --h # +list ... LIST.hlp.list-legacy := \ --legacy-no-arg --legacy=simple --legacy=dump \ --legacy=owasp --legacy=openssl --legacy=ssltest # --help # To get a list of used (at least documented) --help* options, use: # o-saft.pl --help=help # or: # grep help= OSaft/Doc/help.txt LIST.hlp.help-section := \ --help-no-arg --legacy=simple --legacy=dump \ --help=FAQ --help=WHY --help=CHECK --help=SECURITY \ --help=alias --help=check --help=cmd --help=commands \ --help=data --help=exit --help=content --help=compliance \ --help=help --help=links --help=glossar --help=examples \ --help=hint --help=opt --help=intern --help=legacy \ --help=range --help=regex --help=options --help=pattern \ --help=text --help=rfc --help=ourstr --help=program.code \ --help=toc --help=todo --help=tools --help=warnings \ --help=error --help=exit --help=ABOUT --help=cipherpattern \ --help=cfg-cmd --help=cfg-check --help=cfg-data --help=cfg-hint \ --help=cfg-info --help=cfg-range --help=cfg-regex --help=cfg-ourstr \ --help=cfg-text --help=ciphers-text --help=ciphers-list --help=ciphers-html \ --help=gen-docs --help=gen-wiki --help=gen-html --help=gen-cgi --help=gen-pod # --help=* aliases (not yet tested) # ---help-problem: TEST.args += --help=error # because all above LIST.* are used for the same SRC.pl, they are combined to # a single LIST, otherwise multiple calls of GEN.targets-args with the same # SRC.pl may generate duplicate targets in ALL.test.hlp LIST.hlp.all := $(LIST.hlp.list-legacy) $(LIST.hlp.help-like) $(LIST.hlp.help-section) # all targets are generated, see Makefile.gen; only one program: SRC.pl ifndef exit-macros-generated # must use GEN.targets instead of GEN.targets-args to avoid setting TEST.init $(eval $(call GEN.targets,testarg,hlp,-$(SRC.pl),$(SRC.pl),LIST.hlp.all,TEST.args,TEST.dumm)) endif # some special targets testarg-hlp-o-saft.pl_+version--v--usr: TEST.args += +version --v --usr testarg-hlp-o-saft.pl_--v+version: TEST.args += --v +version testarg-hlp-o-saft.pl_--v+help: TEST.args += --v +help ALL.test.hlp += testarg-hlp-o-saft.pl_+version--v--usr testarg-hlp-o-saft.pl_--v+version testarg-hlp-o-saft.pl_--v+help # --help=* with special options, which must preceed --help=* testarg-hlp-o-saft.pl_--help-cmd--format-width: TEST.args += --format-width=54 --help=cmd testarg-hlp-o-saft.pl_--help-why--format-width: TEST.args += --format-width=54 --help=why #testarg-hlp-o-saft.pl_--help-cmd--tty: TEST.args += --format-tty --help=cmd #testarg-hlp-o-saft.pl_--help-cmd--tty: TEST.args += --tty --help=cmd # alias # --tty does not produce different output, except on special devices ALL.test.hlp += testarg-hlp-o-saft.pl_--help-cmd--format-width testarg-hlp-o-saft.pl_--help-why--format-width # +ciphers ... testarg-hlp-o-saft.pl_+ciphers---dummy: TEST.args += testarg-hlp-o-saft.pl_+ciphers--v: TEST.args += -v testarg-hlp-o-saft.pl_+ciphers--V: TEST.args += -V ALL.test.hlp += testarg-hlp-o-saft.pl_+ciphers---dummy testarg-hlp-o-saft.pl_+ciphers--v testarg-hlp-o-saft.pl_+ciphers--V ALL.test.hlp.log = $(ALL.test.hlp:%=%.log) test.hlp.log-compare: TEST.target_prefix = testarg-hlp test.hlp.log-move: TEST.target_prefix = testarg-hlp test.hlp.log: TEST.target_prefix = testarg-hlp test.hlp: $(ALL.test.hlp) test.hlp.log: $(ALL.test.hlp.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.inc000077500000000000000000000070711433765727300155360ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile.inc - define missing variables for Makefile #? #? SYNOPSYS #? ifndef ALL.Makefiles #? include Makefile.inc #? endif #? #? DESCRIPTION #? Defines general variables used in Makefile if they are missing. #? #? VERSION #? @(#) Makefile.inc 1.33 22/11/12 15:07:42 #? #? AUTHOR #? 18-may-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- _SID.inc := 1.33 _MYSELF.inc := t/Makefile.inc ALL.includes += $(_MYSELF.inc) ALL.inc.type += inc .DEFAULT: @echo "**ERROR: unknown target: $(MAKECMDGOALS)" #_____________________________________________________________________________ #________________________________________________________________ variables __| HELP.inc = $(_NL)\ \# Makefile to define required variables. It does not contain targets. $(_NL)\ \# Note that all definitions herein should be idempotent, so that this $(_NL)\ \# file could be included several times. That's why only = and no +=$(_NL)\ \# assignments are used. $(_NL)\ # ensure that messages and sorting are the same, important to compare results LANG=C 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 TEST.logtxt TEST.logtxt = <> 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. Existence # 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 OSAFT_MAKE export OSAFT_MAKE := avoid writing random data (like date and time string) endif ifndef EXE.echo EXE.echo := /bin/echo -e endif ifndef EXE.pl EXE.pl := o-saft.pl endif ifndef EXE.tcl EXE.tcl := o-saft.tcl endif ifndef EXE.docker EXE.docker := o-saft-docker endif ifndef EXE.dummy EXE.dummy := /bin/echo -n "" endif ifndef EXE.log-filterarg EXE.log-filterarg := cat endif ifndef EXE.log-iltercmd EXE.log-filtercmd := cat endif ifndef _EXE.sort-opt _EXE.sort-opt := -n -f endif ifndef _EXE.perldoc-opt _EXE.perldoc-opt := -n nroff -T endif ifndef _EXE.pod2man-opt _EXE.pod2man-opt := --utf8 endif ifndef TAB TAB := \\011 endif ifndef _NL _NL := \\012 endif ifndef _CR _CR := \\015 endif # also set pseudo variable .SUFFIXES empty (in the hope, it's never needed) .SUFFIXES: O-Saft-22.11.22/t/Makefile.init000077500000000000000000000067051433765727300157330ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.init #? #? VERSION #? @(#) Makefile.init 1.6 22/11/12 14:09:44 #? #? AUTHOR #? 19-dez-19 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.init = targets for testing initialisations of o-saft.pl _SID.init := 1.6 _MYSELF.init := t/Makefile.init ALL.includes += $(_MYSELF.init) ALL.inc.type += init ALL.help.tests += help.test.init first-init-target-is-default: help.test.init ifeq (,$(_SID.test)) -include t/Makefile endif # no target hosts needed here TEST.init.hosts = help.test.init: HELP_TYPE = init help.test.init-v: HELP_TYPE = init help.test.init-vv: HELP_TYPE = init HELP-_init1 = __________________________________ testing initialisations _ HELP-test.init = test various initialisations of '$(EXE.pl)' HELP-test.init.log = same as test.init but store output in '$(TEST.logdir)/' HELP-testarg-init-D = individual target(s) for testing LIST.init.cmds := \ +info +ciphers +check +checkciphers +protocols +vulns +cert +cn LIST.init.opt0 := LIST.init.opt1 := --no-http --no-dns --no-sni LIST.init.opt2 := --no-alpn --no-npn LIST.init.opt3 := --no-cert --no-tlsextdebug LIST.init.opt4 := --no-sslv2 --no-sslv3 LIST.init.opt5 := $(LIST.init.opt4) --no-tlsv1 --no-tlsv11 LIST.init.opt6 := $(LIST.init.opt5) --no-tlsv12 LIST.init.opt7 := $(LIST.init.opt6) --no-tlsv13 LIST.init.opts := opt0 opt1 opt2 opt3 opt4 opt5 opt6 opt7 # only extensions, not the full variable name, so they can be used directly # when generating target names (see below) # TODO: options to be tested: --no-openssl --no-tcp #_____________________________________________________________________________ #______________________________________________________ targets for testing __| # SEE Make:target generation # SEE Make:macros # macro GEN.targets-args cannot be used, because all content of LIST.init.opt* # must be assigned to TEST.args ifndef init-macros-generated $(foreach _cmd, $(LIST.init.cmds),\ $(foreach _opt, $(LIST.init.opts),\ $(eval testarg-init-$(_cmd)-$(_opt): TEST.args := $(_cmd) $(LIST.init.$(_opt)) ) \ $(eval ALL.test.init += testarg-init-$(_cmd)-$(_opt) ) \ ) \ ) undefine _cmd undefine _opt endif testarg-init-%: EXE.pl := ../$(SRC.pl) testarg-init-%: TEST.init := any-host --no-rc --test-init # some individual targets (not all variant of cmd and opt required) testarg-init-+ext-opt901: TEST.args := +extensions +tlsextensions +tlsextdebug testarg-init-+ext-opt902: TEST.args := +extensions +tlsextensions +tlsextdebug --no-tlsextdebug testarg-init-+heart-opt903: TEST.args := +heartbeat +heartbleed testarg-init-+heart-opt904: TEST.args := +heartbeat +heartbleed --no-tlsextdebug ALL.test.init += testarg-init-+ext-opt901 testarg-init-+ext-opt902 ALL.test.init += testarg-init-+heart-opt903 testarg-init-+heart-opt904 ALL.test.init.log = $(ALL.test.init:%=%.log) test.init.log-compare: TEST.target_prefix = testarg-init- test.init.log-move: TEST.target_prefix = testarg-init- test.init.log: TEST.target_prefix = testarg-init- test.init: $(ALL.test.init) test.init.log: $(ALL.test.init.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.legacy000077500000000000000000000071401433765727300162260ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.legacy #? #? VERSION #? @(#) Makefile.legacy 1.9 22/11/14 10:24:50 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.legacy = targets for testing '$(SRC.pl)' +cipher --legacy=* commands _SID.legacy := 1.9 _MYSELF.legacy := t/Makefile.legacy ALL.includes += $(_MYSELF.legacy) ALL.inc.type += legacy ALL.help.tests += help.test.legacy first-legacy-target-is-default: help.test.legacy ifeq (,$(_SID.test)) -include t/Makefile endif TEST.legacy.hosts = localhost ifdef TEST.hosts TEST.legacy.hosts = $(TEST.hosts) endif help.test.legacy: HELP_TYPE = legacy help.test.legacy-v: HELP_TYPE = legacy help.test.legacy-vv:HELP_TYPE = legacy HELP-_legacy1 = _________________________________________ testing commands _ HELP-test.legacy = test all commands with '$(TEST.legacy.hosts)' HELP-test.legacy.log = same as test.legacy but store output in '$(TEST.logdir)/' HELP.legacy = # not yet used HELP.test.legacy.all = # no special documentation yet # other SSL-related test tools, not used in this project, just for documentation _TEST.tools.ssl = \ cnark.pl analyze-ssl.pl manyssl SSLAudit.pl \ sslmap.py sslscan ssltest.pl sslthing.sh sslyze.py testssl.sh \ TestSSLServer.jar tls-check.pl tls-scan TLSSLed_v1.3.sh vessl _TEST.tools.vulns = \ beast.pl ccs-injection.sh poet ssl-dos robot-detect \ ssl-renegotiation.sh OSSL_CCS_InjectTest.py \ bash-heartbleed.sh check-ssl-heartbleed.pl ssl-check-heartbleed.pl ssltest_heartbeat.py _TEST.tools.cert = \ ssl-cert-check chksslkey smtp_tls_cert.pl _TEST.tools.cipher = \ athena-ssl-cipher-check_v062.jar ssl-cipher-check.pl tlsenum _TEST.tools.unix = \ sslcat sslsniff sslstrip stunnel _TEST.tools.windows = \ SSLAudit.exe SSLCertScanner.exe ssldiagnos.exe SSLPressure.exe \ sslscan.exe TestSSLServer.exe ALL.tools.ssl = $(_TEST.tools.ssl) $(_TEST.tools.vulns) $(_TEST.tools.cert) \ $(_TEST.tools.cipher) $(_TEST.tools.unix) $(_TEST.tools.windows) LIST.legacy := \ cnark openssl sslaudit sslcipher ssldiagnos sslscan \ ssltest ssltest-g sslyze testsslserver thcsslcheck \ compact full simple owasp # SEE Make:target name # SEE Make:target name prefix testarg-legacy-+cipher%: EXE.pl = ../$(SRC.pl) testarg-legacy-+cipher%: TEST.init = --trace-CLI --header --enabled +cipher $(TEST.legacy.hosts) ifndef legacy-macros-generated # GEN.targets cannot be used, because it would generate duplicate targets _TEST.legacy := testarg-legacy-+cipher--legacy $(foreach arg, $(LIST.legacy),\ $(eval _target=$(_TEST.legacy)-$(arg)) \ $(eval $(_target)_%: TEST.args = --legacy=$(arg) )\ $(eval $(_target)--norc_%: TEST.args = --legacy=$(arg) --norc )\ $(eval ALL.testlegacy += $(_target)_ ) \ $(eval ALL.testlegacy += $(_target)--norc_ ) \ ) undefine _target undefine _TEST.legacy endif ALL.test.legacy = $(foreach host,$(TEST.legacy.hosts),$(ALL.testlegacy:%=%$(host))) ALL.test.legacy.log += $(ALL.test.legacy:%=%.log) test.legacy.log-compare: TEST.target_prefix = testarg-legacy- test.legacy.log-move: TEST.target_prefix = testarg-legacy- test.legacy.log: TEST.target_prefix = testarg-legacy- test.legacy: $(ALL.test.legacy) test.legacy.log: $(ALL.test.legacy.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.make000077500000000000000000000102701433765727300156750ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.make #? #? VERSION #? @(#) Makefile.make 1.18 22/09/21 12:10:39 #? #? AUTHOR #? 19-jul-19 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.make = targets for testing Makefile help* targets _SID.make := 1.18 _MYSELF.make := t/Makefile.make ALL.includes += $(_MYSELF.make) ALL.inc.type += make ALL.help.tests += help.test.make first-make-target-is-default: help.test.make ifeq (,$(_SID.test)) -include t/Makefile endif help.test.make: HELP_TYPE = make help.test.make-v: HELP_TYPE = make help.test.make-vv: HELP_TYPE = make HELP-_makefile1 = _____________________________________ testing help targets _ HELP-help.make.doc = print documentation about available Makefile.* HELP-test.make = test help* targets of our Makefiles HELP-test.make.log = same as test.make but store output in '$(TEST.logdir)/' HELP-testarg-make-n = execute 'make tests -n' HELP-test.make.log-compare = compare results of test.make.log (if any) HELP.make = $(_NL)\ \# Note that test.make uses "make help.test.*" to show each Makefile's$(_NL)\ \# documentation. In contrast, test.hlp uses "o-saft.pl --help*" to show$(_NL)\ \# (user-)documentation of "o-saft.pl"$(_NL)\ # dumm ' HELP.test.make.all = # no special documentation yet # Following target lists the used (included) t/Makefile.* , each with its # description as defined in the file itself in the HELP-help.text.* macro _HELP-maketitle = \#__________________________________ purpose of t/Makefile.* _ _HELP.maketitle = $(ALL.inc.type:%=help-makefiletitle-%) _help.makefiles.doc: @$(TRACE.target) @echo "\n\t\t$(_HELP-maketitle)" @$(MAKE) -s $(_HELP.maketitle) help.makefiles.doc: HELP_HEAD = $(HELP_INFO) help.makefiles.doc: _help.HEAD _help.makefiles.doc @$(TRACE.target) HELP-testarg-make-help.test* = test help.test.* targets of Makefiles HELP-testarg-make-s-ALL.test* = test ALL.test.* variables of Makefiles # special/individual help.* targets in Makefiles LIST.helpmake := help help.all help.help.all-v \ help.doc help.doc.all help.makefiles.doc \ testcmd-test.internal help.test.makevars help.test.log-info # Makefile-specific help.test.* targets # pod and template are missing in $(ALL.inc.type) because they are not included # help.test.%.all is rarely used LIST.makefiles = $(ALL.inc.type) pod template LIST.helpmake += $(LIST.makefiles:%=help.test.%) LIST.helpmake += $(LIST.makefiles:%=help.test.%.all) # Makeile-specific ALL.test.* variables LIST.testmake += $(LIST.makefiles:%=s-ALL.test.%) ALL.help += help.makefiles.doc # contribution to Makefile.help # TODO: help.test.help, help.help may exist twice ALL.testmake += $(LIST.helpmake:%=testarg-make-%) ALL.testmake += $(LIST.testmake:%=testarg-make-%) ALL.test.make += $(ALL.testmake) testarg-make%: EXE.pl = $(MAKE) testarg-make%: TEST.init = testarg-make%: TRACE.target= echo "\#\#$(EXE.pl) $(TEST.init) $(TEST.args)$(_NL)" testarg-make%.log: TRACE.target= # targets should print the command, the TRACE.target variable is misused # for that (assuming that all target use $(TRACE.target) ). # $(TRACE.target) is empty for testarg-make%log to avoid double printing testarg-make-n: TEST.init = tests -n testarg-make-n: @$(TRACE.target) @$(MAKE) -s tests -n ALL.test.make=$(ALL.testmake) # setting ALL.test.make= in recursive call avoids endless recursion # might also be done by checking $(MAKELEVEL) > 2 ALL.test.make += testarg-make-n ALL.test.make.log += $(ALL.test.make:%=%.log) $(foreach arg, $(LIST.helpmake), $(eval testarg-make-$(arg): TEST.args = $(arg)) ) $(foreach arg, $(LIST.testmake), $(eval testarg-make-$(arg): TEST.args = $(arg)) ) test.make.log-compare: TEST.target_prefix = testarg-make test.make.log-move: TEST.target_prefix = testarg-make test.make.log: TEST.target_prefix = testarg-make test.make: $(ALL.test.make) test.make.log: $(ALL.test.make.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.misc000077500000000000000000000445361433765727300157270ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.misc #? #? VERSION #? @(#) Makefile.misc 1.73 22/11/19 09:56:51 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.misc = targets for misc. tests and development _SID.misc := 1.73 _MYSELF.misc := t/Makefile.misc ALL.includes += $(_MYSELF.misc) ALL.inc.type += misc ALL.help.tests += help.test.misc first-misc-target-is-default: help.test.misc ifeq (,$(_SID.test)) -include t/Makefile endif help.test.misc: HELP_TYPE = misc help.test.misc-v: HELP_TYPE = misc help.test.misc-vv: HELP_TYPE = misc #_____________________________________________________________________________ #________________________________________________________________ variables __| # internal used tools and files (paths hardcoded!) EXE.bench := t/o-saft_bench.sh EXE.test.bunt := t/test-bunt.pl.txt TEST.bench.host := $(TEST.host) TEST.bench.times := $(TEST.logdir)/o-saft_bench.sh.times TEST.bunt.log := $(TEST.logdir)/test.bunt.log TEST.args.misc := +quit TEST.opt.cloc := \ --force-lang=Perl,pl \ --force-lang=make,cmd \ --force-lang=make,inc \ --force-lang=make,FQDN \ --force-lang=AsciiDoc,pod \ --force-lang=AsciiDoc,txt \ --script-lang=make,make \ --by-percent c TEST.opt.dprofpp := TEST.opt.nytprof := EXE.cloc := cloc EXE.cloc.filter := cat EXE.cloc.total := t/cloc-total.awk EXE.analyse := perl-analyzer EXE.analyse-output := perl-analyzer-output EXE.dprofpp := dprofpp EXE.nytprof := nytprofhtml EXE.podchecker := podchecker # summary variables (mainly used for INSTALL.sh) _ALL.devtools.intern += $(EXE.bench) $(EXE.test.bunt) $(EXE.cloc.total) _ALL.devtools.extern += ctags _ALL.devtools.extern += $(EXE.dprofpp) $(EXE.nytprof) $(EXE.podchecker) _ALL.devtools.extern += $(EXE.analyse) $(EXE.analyse-output) $(EXE.cloc) _ALL.devmodules.extern += Data::Dumper Devel::Size Devel::Trace Debug::Trace _ALL.devmodules.extern += Pod::Perldoc File::Find _ALL.devmodules.extern += Perl::Analyzer JSON Text::MicroTemplate GraphViz2 Storable _ALL.devmodules.extern += Devel::NYTProf Devel::DProf _ALL.devmodules.optional := Debug::LTrace Devel::TraceCalls # not used, but may be useful for debugging ifndef SRC.contrib.dir SRC.contrib.dir = contrib endif # cloc detect file types (language) on file extension primarily. Unfortunately # some files have no extension and some extension fool cloc's detection. Hence # special options should prefix to these files to detect them correctly. # Unfortunately this would result in rebuilding $(ALL.src) with sophisticates # use of Make's $(foreach..) and $(patsubst..) like: # _TEST.cloc.src += $(foreach src, $(filter t/Makefile.%,$(ALL.src)), \ # $(patsubst t/Makefile%,--force-lang=make $(src),$(src)) \ # ) # _TEST.cloc.src += $(foreach src, $(filter contrib/%_o-saft,$(ALL.src)), \ # $(patsubst contrib/%_o-saft,--force-lang="Bourne Shell" $(src),$(src)) \ # ) # ... # Up to now (03/2022), cloc detects one file contrib/%_o-saft incorrectly as # Ruby, not worth for more complicated code here ... _TEST.cloc.src = $(sort $(ALL.src)) _TEST.cloc.hint= Ruby detected by cloc incorrectly, should be make #_____________________________________________________________________________ #____________________________________________________________ various tests __| HELP-_misc1 = ____________________________________________ testing misc. _ HELP-test.bench = call '$(EXE.bench)' for some benchmarks HELP-test.bench.log = call '$(EXE.bench)' and save result in '$(TEST.bench.times)' HELP-test.bunt = test '$(SRC.contrib.dir)/bunt.pl' with sample file HELP.misc = $(_NL)\ \# Make may return status code for any qa.* target, even the result is not$(_NL)\ \# errorneous. The target test.quality is not part of '\$$(ALL.test.misc)'. HELP.test.misc.all = # no special documentation yet bench: test.bench test.bench: @$(TRACE.target) $(EXE.bench) $(TEST.bench.host) @echo "# use '$(MAKE_COMMAND) test.bench.log' to save result in '$(TEST.bench.times)'" $(TEST.bench.times): @$(TRACE.target) @$(TRACE.target.log) $(EXE.bench) $(TEST.bench.host) >> $@ test.bench.log: $(TEST.bench.times) test.bunt: $(EXE.test.bunt) @$(TRACE.target) -cat $(EXE.test.bunt) | $(SRC.contrib.dir)/bunt.pl $(TEST.bunt.log): @$(TRACE.target) @$(TRACE.target.log) -cat $(EXE.test.bunt) | $(SRC.contrib.dir)/bunt.pl > $@ test.bunt.log: $(TEST.bunt.log) # TODO: test.bunt.log should use testarg%log target ALL.testmisc := test.bench test.bunt ALL.testmisc.log := test.bench.log ALL.test.misc.log += test.bench.log .PHONY: test.bench test.bench.log test.bunt #_____________________________________________________________________________ #__________________________________________________ targets for development __| 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 HELP-cloc.csv = same as cloc but output as comma separated values HELP-cloc.total = same as cloc but added "total %" column HELP-test-cloc = all of the above HELP-cloc.stat.log = same as cloc but redirect to '$(_TEST.cloc.log)' also # NOTE: also possible usage: # make cloc TEST.opt.cloc=--3 # make cloc TEST.opt.cloc=--csv # make cloc TEST.opt.cloc=--xml # NOTE: --quiet suppresses count of files also, hence not used by default cloc%: @$(TRACE.target) @$(EXE.cloc) $(TEST.opt.cloc) $(_TEST.cloc.src) | $(EXE.cloc.filter) @$(EXE.echo) "$(_NL)# $(_TEST.cloc.hint)" cloc.stat: TEST.opt.cloc += cloc.file: TEST.opt.cloc += --by-file cloc.lang: TEST.opt.cloc += --by-file-by-lang cloc.csv: TEST.opt.cloc += --csv --quiet cloc.total: TEST.opt.cloc += --csv --quiet cloc.total: EXE.cloc.filter = $(EXE.cloc.total) cloc: cloc.stat # cloc is ugly, writes to tty, hence we always get the output also, even # if STDOUT and STDERR is redirected to a file _TEST.cloc.log = $(TEST.logdir)/test.cloc.stat.log $(_TEST.cloc.log): @echo "# Makefile.misc 1.73: $(MAKE) cloc.stat.log" > $@ @$(MAKE) -i cloc.stat >> $@ 2>&1 cloc.stat.log: $(_TEST.cloc.log) ALL.test.cloc := cloc.stat cloc.file cloc.lang cloc.csv cloc.total ALL.testmisc += $(ALL.test.cloc) test.cloc: $(ALL.test.cloc) # TODO: test.cloc.log must be special as it compares generated files ALL.test.misc.log += cloc.stat.log #ALL.test.cloc.log = $(ALL.test.cloc:%=%.log) #test.cloc.log: $(ALL.test.cloc.log) # alias for convenience test.cloc.all: test.cloc .PHONY: cloc HELP-_modules = _________________ targets for testing ancient Perl modules _ # TODO: build test targets # already manually tested module versions: # perl 5.24, 5.28 # openssl 0.9.8, 1.0.2-chacha, 1.0.2k, 1.1.0l, 1.1.1d # # IO::Socket::SSL 2.044, 2.060 # Net::DNS 0.66, 1.2, 1.19 # Net::SSLeay 0.49. 1.82, 1.85 # Time::Local 1.2300, 1.25 # SEE Make:Perl::Analyzer HELP-_dev1 = __________________________________ targets for development _ HELP-analyse = analyse code with Perl::Analyzer HELP-analyse-output = analyse code and generate '$(_TEST.analyse.html)' HELP-test.norc = special target testing with/without -norc option HELP-tags = generate tags file for vi(m) HELP-profile.sub.entry = generate function calling tree of '$(DEV.pl)' (entry only) HELP-profile.sub.exit = generate function calling tree of '$(DEV.pl)' (entry and exit) HELP-profile.sub.args = generate function calling tree of '$(DEV.pl)' (in, out and parameter) HELP-nytprof.out = generate profiling data (for nytprofcalls) HELP-nytprof.html = generate profiling data in HTML format HELP-dprof.out = generate profiling data (for dprofpp; times, counts, calling tree) _TEST.analyse.src := ./ _TEST.analyse.dst := ./$(DOC.dir)/perl-analyzer _TEST.analyse.dat := $(_TEST.analyse.dst)/o-saft.dat _TEST.analyse.html := $(_TEST.analyse.dst)/index.html TEST.opt.analyse = # TODO: --with-constants --with-fields TEST.opt.analyse.dat= --datafile=$(_TEST.analyse.dat) $(_TEST.analyse.dst): @mkdir $@ analyse: TEST.opt.analyse.dir = --source-dir=$(_TEST.analyse.src) analyse-output: TEST.opt.analyse.dir = --output-dir=$(_TEST.analyse.dst) analyse: $(_TEST.analyse.dst) $(SRC.pl) $(SRC.pm) @$(TRACE.target) @$(EXE.analyse) $(TEST.opt.analyse.dat) $(TEST.opt.analyse.dir) $(TEST.opt.analyse) $(_TEST.analyse.dat): analyse analyse-output: $(_TEST.analyse.dat) @$(TRACE.target) @$(EXE.analyse-output) $(TEST.opt.analyse.dat) $(TEST.opt.analyse.dir) --format=html analyse-out: analyse-output ALL.test.analyse := analyse analyse-output ALL.testmisc += $(ALL.test.analyse) test.analyse: $(ALL.test.analyse) $(GEN.tags): $(SRC.pl) $(ALL.pm) $(CHK.pl) $(SRC.cgi) $(SRC.tcl) $(ALL.Makefiles) ctags $^ ALL.gen += $(GEN.tags) # # just because GEN.tags is defined in main Makefile ALL.testmisc += $(GEN.tags) # check if result of +check and +info is identical with and without --no-rc # commands LIST.norc.no-out.keys are ignored as they always differ TEST.norc.host := localhost _TEST.norc.dir = $(TEST.logdir)/test.norc LIST.norc.no-out.keys := master_key \ session_id session_id_ctx \ session_startdate session_starttime session_ticket \ sts_expired \ http_body https_body pem text LIST.norc.no-out.opt := $(LIST.norc.no-out.keys:%=--no-out=%) LIST.norc.opts := --header --traceKEY test.norc%: @$(TRACE.target) @$(eval _cmd = $(shell echo $* | sed -e 's/.log//')) @$(eval _log = $(_TEST.norc.dir)-$(_cmd)) @$(eval _ext = log-$(TEST.today)) @$(DEV.pl) $(TEST.norc.host) $(_cmd) $(LIST.norc.no-out.opt) $(LIST.norc.opts) | sort > $(_log).$(_ext) @$(DEV.pl) $(TEST.norc.host) $(_cmd) $(LIST.norc.no-out.opt) $(LIST.norc.opts) --no-rc | sort > $(_log)--no-rc.$(_ext) @-diff $(_log).$(_ext) $(_log)--no-rc.$(_ext) || exit 0 @rm $(_log).$(_ext) $(_log)--no-rc.$(_ext) ALL.test.norc = test.norc+info test.norc+check ALL.testmisc += $(ALL.test.norc) # TODO: test.norc%.log NOT YET IMPLEMENTED # 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 _TEST.profile.log = $(TEST.logdir)/profile.sub.log TEST.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=$(_TEST.profile.log) profile.sub.%.log: _lineinfo = LineInfo=$(_TEST.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%: @$(TRACE.target) @$(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 # requires perl module Devel/NYTProf or package, for example libdevel-nytprof-perl _TEST.nytprof.log = $(TEST.logdir)/nytprof.out nytprof.out: $(_TEST.nytprof.log) @$(TRACE.target) @perl -d:NYTProf $(DEV.pl) $(TEST.profile.host) $(TEST.args.misc) @mv $@ $< @echo "# inspect with: nytprofcalls $(_TEST.nytprof.log)" nytprof.html: $(_TEST.nytprof.log) @$(TRACE.target) @$(EXE.nytprof) $(TEST.opt.nytprof) --file $< @echo "# inspect with: firefox $(TEST.dir)/nytprof/index.html" nytprof: nytprof.html # requires perl module Devel/DProf or package, for example libdevel-dprof-perl _TEST.dprof.log = $(TEST.logdir)/dprof.out $(_TEST.dprof.log): @$(TRACE.target) @env PERL_DPROF_OUT_FILE_NAME=$(_TEST.dprof.log) perl -d:DProf $(DEV.pl) $(TEST.profile.host) $(TEST.args.misc) @$(EXE.dprofpp) $(TEST.opt.dprofpp) $(_TEST.dprof.log) @echo "" @echo "# show calling tree: dprofpp -t $(_TEST.dprof.log)" #dprof.out: PERL_DPROF_OUT_FILE_NAME=$(_TEST.dprof.log) dprof.out: $(_TEST.dprof.log) # useful options: -T -I # dprofpp -t -f "(Carp::)|(Exporter::)|(Symbol::)|(DynaLoader::)" .PHONY: $(_TEST.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 ALL.testmisc += $(ALL.test.profile) test.profile: $(ALL.test.profile) ALL.qa = $(ALL.pm) $(SRC.pl) HELP-_qa1 = ____________________________ targets checking code quality _ HELP-test.quality = search for various common coding mistakes, see make e-ALL.test.quality HELP-test.pod = check generated pod file # SEE Make:podchecker qa.pod: @echo "#make: $(HELP-test.pod) ..." @-$(EXE.podchecker) $(GEN.pod) || echo "" @echo "" # following checks based on http://perldoc.perl.org/perldiag.html # NOTE: all qa.* targets never fail, they are just informational # therefore if egrep fails, "echo OK" is used to avoid failure qa.double_dref: @echo "#make: check depricated double dereferencing ..." @-egrep -H '\$$$$[^$$)]' $(ALL.qa) || echo "OK" @echo "" qa.defined_arr: @echo "#make: check depricated defined(@array) ..." @-egrep -H 'defined[( ]*@' $(ALL.qa) || echo "OK" @echo "" qa.defined_hash: @echo "#make: check depricated defined(%hash) ..." @-egrep -H 'defined[( ]*%' $(ALL.qa) || echo "OK" @echo "" qa.defined_warnings: @echo "#make: check duplicate error and warning numbers ..." @$(MAKE_COMMAND) warnings.info | sort -k 2 \ | awk '{nr=$$2;sub(/:/,"",nr);if(nr==last){print warn;print;}last=nr;warn=$$0}' @echo "" qa.misspelled_regex: @echo "#make: check misspelled grouping in RegEx ..." @-egrep -H '\(:\?' $(ALL.qa) || echo "OK" @echo "" qa.misspelled_critic: @echo "#make: check misspelled use of ## no critic ..." @-egrep -H ' # no critic' $(ALL.qa) || echo "OK" @echo "" # some simple checks for Makefiles qa.makefile_HELP: @echo "#make: check HELP- macro definitions in Makefiles ..." @-awk '/^HELP-/{print $$1"\t"FILENAME}' $(ALL.Makefiles) | sort @echo "" @echo "#make: check duplicate HELP- macro definitions in Makefiles ..." @-awk '/^HELP-/{print $$1}' $(ALL.Makefiles) | sort | uniq -d @echo "" qa.makefile_help: @echo "#make: check help target definitions in Makefiles ..." @-awk '/^help/{print $$1"\t"FILENAME}' $(ALL.Makefiles) | sort @echo "" @echo "#make: check duplicate help target definitions in Makefiles ..." @-awk '($$3=="="){next}/^help/{print $$1}' $(ALL.Makefiles) | sort | uniq -d @echo "" # # duplicate checks for targets need to avoid collecting the conditional # # targets which just define macros, hence $3=="=" ALL.test.quality := \ qa.pod \ qa.double_dref \ qa.defined_arr \ qa.defined_hash \ qa.defined_warnings \ qa.misspelled_regex \ qa.misspelled_critic \ qa.makefile_HELP \ qa.makefile_help ALL.testmisc += $(ALL.test.quality) test.quality: $(ALL.test.quality) _TEST.quality.log = $(TEST.logdir)/test.quality.log-$(TEST.today) $(_TEST.quality.log): @echo "# Makefile.misc 1.73: $(MAKE) test.quality.log" > $@ @$(MAKE) -i test.quality >> $@ 2>&1 test.quality.log: $(_TEST.quality.log) @$(TRACE.target) @$(TRACE.target.log) @diff $(TEST.logdir)/$@ $(_TEST.quality.log) \ && rm $(_TEST.quality.log) \ || mv $(_TEST.quality.log) $(TEST.logdir)/$@ @-test -f $(TEST.logdir)/$@ || mv $(_TEST.quality.log) $(TEST.logdir)/$@ @ls -l $(TEST.logdir)/$@* # TODO: same target as test.warnings.log HELP-test.misc.todo = search for 'FIXME' and 'TODO' comments in '$(ALL.qa)' HELP-test.misc.shebang = get first line of file with '#!' (shebang) in $(ALL:src)' testarg-misc_FIXME: @echo "#make: search for '# FIXME' in code ..." @-grep '# FIXME' $(ALL.qa) @echo "" testarg-misc_TODO: @echo "#make: search for '# TODO' in code ..." @-grep '# TODO' $(ALL.qa) @echo "" testarg-misc_shebang: @echo "#make: search for '#!' (shebang) in code ..." @-egrep -m 1 '^#![ /].*/' $(ALL.src) @echo "" # # get only #!/... and #! /... but not #!#... ALL.test.misc.todo := testarg-misc_FIXME testarg-misc_TODO ALL.test.misc.todo.log := $(ALL.test.misc.todo:%=%.log) ALL.testmisc += $(ALL.test.misc.todo) testarg-misc_shebang test.misc.todo: $(ALL.test.misc.todo) test.misc.todo.log: $(ALL.test.misc.todo.log) @$(TRACE.target) .PHONY: $(ALL.test.misc.log) # define PHONY target to avoid misleading error messages when files are missing # 2/2021: files are not yet on github .PHONY: OSaft/_ciphers_iana.pm .PHONY: OSaft/_ciphers_osaft.pm .PHONY: OSaft/_ciphers_openssl_all.pm .PHONY: OSaft/_ciphers_openssl_h.pm ALL.test.misc += test.bench test.bunt \ $(ALL.test.norc) \ $(ALL.test.cloc) \ $(ALL.test.quality) \ $(ALL.test.misc.todo) \ testarg-misc_shebang \ $(GEN.tags) ALL.test.misc.log += test.quality.log $(ALL.test.misc.todo.log) # NOTE: ALL.test.misc does not contain $(ALL.testmisc) because they are too noisy test.misc.all: $(ALL.testmisc) test.misc: $(ALL.test.misc) test.misc.log: $(ALL.test.misc.log) # test.log-compare-hint does not make sense here O-Saft-22.11.22/t/Makefile.mod000077500000000000000000000147041433765727300155450ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.mod #? #? VERSION #? @(#) Makefile.mod 1.4 22/11/12 00:11:58 #? #? AUTHOR #? 22-oct-22 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.mod = targets for testing module functionality _SID.mod := 1.4 _MYSELF.mod := t/Makefile.mod ALL.includes += $(_MYSELF.mod) ALL.inc.type += mod ALL.help.tests += help.test.mod first-mod-target-is-default: help.test.mod ifeq (,$(_SID.test)) -include t/Makefile endif help.test.mod: HELP_TYPE = mod help.test.mod-v: HELP_TYPE = mod help.test.mod-vv: HELP_TYPE = mod #_____________________________________________________________________________ #________________________________________________________________ variables __| TEST.mod.hosts = # following names of LIST.* variables must match the names of the tool the # variable should be used for; general rule is: # for tool named path/tool.pm the variable LIST.path-tool.pm must be usd # no targets are generated for empty LIST.* variables LIST.o-saft.pl := LIST.osaft.pm := # Ciphers.pm supports command/options with or without + and -- prefix LIST.OSaft-Ciphers.pm-cmd := \ aliases constants rfcs dump regex description overview \ openssl osaft show simple sorted ssltest version \ get_keys_list get_names_list # Ciphers.pm supports command for each of its functions, test with key 0x03001301 LIST.OSaft-Ciphers.pm-get := \ get_key get_sec get_ssl get_keyx get_auth get_enc \ get_bits get_mac get_rfc get_name get_const get_note \ get_openssl get_encsize get_iana get_pfs \ get_aliases get_consts get_names get_notes # command/options for Ciphers.pm composed of previous ones and some specials LIST.OSaft-Ciphers.pm := \ $(LIST.OSaft-Ciphers.pm-cmd) \ $(LIST.OSaft-Ciphers.pm-get:%=%=0x03001301) \ getter=0x060040 getter=0x02060040 get_key=DES-CBC-MD5 \ getter=0xC0,0x2C getter=0x0300C02C get_key=ECDHE-ECDSA-AES256-GCM-SHA384 \ getter=0xCC,0xA9 getter=0x0300CCA9 get_key=ECDHE-ECDSA-CHACHA20-POLY1305-SHA256 \ get_key=DHE-PSK-AES128-SHA get_key=DHE_PSK_WITH_AES_128_CBC_SHA \ get_key=DHE-PSK-AES128-SHA256 get_key=DHE-PSK-AES128-CBC-SHA256 \ text2key=0x1301 text2key=0x13,0x01 key2text=0x03001301 \ find_names=DHE-PSK-AES128 find_keys=DHE-PSK-AES128 # only $(LIST.OSaft-Ciphers-cmd) is tested here, as they all produce the # same output as $(LIST.OSaft-Ciphers--test) # some command and options supported by Ciphers.pm are supported by $(SRC.pl) # too, but must be used there as --test-ciphers-* LIST.OSaft-Ciphers--test := $(LIST.OSaft-Ciphers-cmd:%=--test-ciphers-%) LIST.OSaft-Data.pm := \ check_cert check_conn check_dest check_http check_size \ checks data shorttexts LIST.o-saft.pl += $(LIST.OSaft-Ciphers--test) LIST.OSaft-Doc-Data.pm := \ --usage version +VERSION list print \ get get-markup get-text get-as-text \ # tests are functionally the same as testarg-hlp--help-* from Makefile.hlp LIST.o-saft-man.pm := \ FAQ WHY CHECK alias check cmd commands compliance \ content data glossar intern help hint legacy links \ opt options ourstr pattern range regex rfc text \ toc todo tools warning exit abbr \ cfg-check cfg-data cfg-hint cfg-info cfg-text cfg-regex \ gen-wiki gen-html gen-cgi gen-pod gen-man \ # o-saft-man.pm allows any of the above listed arguments like: # o-saft-man.pm toc # o-saft-man.pm --help=toc # o-saft-man.pm --test-toc # only the first form is tested here, as they all produce the same output LIST.Net-SSLinfo.pm-t := --test-methods --test-sclient --test-sslmap --test-ssleay # TODO: --test-openssl #LIST.o-saft.pl += $(LIST.Net-SSLinfo.pm-t) LIST.o-saft-dbx.pm := \ --tests $(LIST.Net-SSLinfo.pm-t) \ --test-memory --test-data --test-init --test-maps --test-prot --test-regex # o-saft-dbx.pm doesn't handle the options, hence call o-saft.pl with them LIST.o-saft.pl += $(LIST.o-saft-dbx.pm) LIST.Net-SSLhello.pm := +VERSION --test-init LIST.Net-SSLinfo.pm := +VERSION localhost $(LIST.Net-SSLinfo.pm-t) # command and checks NOT YET IMPLEMENTED are hardcoded here, # should be the same commands_notyet in osaft.pm LIST.o-saft.notyet := \ +closure +cipher_order +cipher_weak +cps_valid +fallback \ +open_pgp +lzo +sgc +scsv +time +zlib \ HELP-_mod1 = _____________________________ testing module functionality _ HELP-test.mod = test various module functionalities HELP-test.mod.log = same as test.mod but store output in '$(TEST.logdir)/' #_____________________________________________________________________________ #______________________________________________________ targets for testing __| # programs to be tested here are in $(SRC.pm) ifndef SRC.pm # define dummy to inform user about missing macro SRC.pm = __SRC.pm_ LIST.__SRC.pm_ = not-defined-in-Makefile.mod endif # all targets are generated, see Makefile.gen ifndef mod-macros-generated $(foreach _prg, $(SRC.pm),\ $(call GEN.targets-init,testarg,mod,$(_prg),LIST.$(subst /,-,$(_prg))) \ ) undefine _prg endif # some special adaptions to generated targets # OSaft/Doc/Data.pm function needs a file where to read the information # it's found automatically when using o-saft.pl but not with OSaft/Doc/Data.pm testarg-mod-OSaft-Doc-Data.pm_%: TEST.args = help.txt # o-saft-dbx.pm does not make sense without a calling parent testarg-mod-o-saft-dbx.pm_%: EXE.pl = ../$(SRC.pl) # more info with pretty printed output: --header testarg-mod-o-saft-man.pm_%: TEST.args = --header #_____________________________________________________________________________ #_____________________________________________________________________ test __| #ALL.test.mod # defined in GEN.targets-init ALL.test.mod.log = $(ALL.test.mod:%=%.log) test.mod.log-compare: TEST.target_prefix = testarg-mod- test.mod.log-move: TEST.target_prefix = testarg-mod- test.mod.log: TEST.target_prefix = testarg-mod- test.mod: $(ALL.test.mod) test.mod.all: $(ALL.test.mod) test.mod.log: $(ALL.test.mod.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.opt000077500000000000000000000151421433765727300155650ustar00rootroot00000000000000#! /usr/bin/make -rRf #? # TODO: initial version, needs to be completed ############################################################################## #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.opt #? #? VERSION #? @(#) Makefile.opt 1.28 22/09/21 11:42:29 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.opt = targets for testing '$(SRC.pl)' options _SID.opt := 1.28 _MYSELF.opt := t/Makefile.opt ALL.includes += $(_MYSELF.opt) ALL.inc.type += opt ALL.help.tests += help.test.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.test.opt: HELP_TYPE = opt help.test.opt-v: HELP_TYPE = opt help.test.opt-vv: HELP_TYPE = opt HELP-_opt1 = __________________________________________ testing options _ HELP-test.alias = test various alias options HELP-test.stdformat = test various --std-format= options HELP-test.opt = test all options and alias options HELP-test.opt.log = same as test.opt but store output in t/testcmd-CMD.log HELP.opt = $(_NL)\ \# Examples:$(_NL)\ \# make testarg-opt-alias-ipv6$(_NL)\ \# make testarg-opt-stdformat-crlf$(_NL)\ \# make testarg-opt-stdformat-raw HELP.test.opt.all = # no special documentation yet # SEE EXE.pl:--trace-CLI testarg-opt-alias-%: EXE.pl = ../$(SRC.pl) testarg-opt-alias-%: TEST.init = --trace-CLI --traceARG --v +quit testarg-opt-alias-enabled..1: TEST.args += --exit=MAIN -b #testarg-opt-alias-enabled..2: TEST.args += --exit=MAIN -b testarg-opt-alias-ca_path..x: TEST.args += --exit=MAIN -c x testarg-opt-alias---test-ciphers-list: TEST.args += --test-ciphers-list # folgende noch in passende Makefile verschieben testarg-opt-alias-HOST0%: TEST.init = --trace-CLI --exit=HOST0 +cn testarg-opt-alias-HOST0-ipv6: TEST.args += ::1 ::244 testarg-opt-alias-HOST0-many: TEST.args += demo demo:42 egal --port 23 localhost # 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 testarg-opt-stdformat-%: EXE.pl = ../$(SRC.pl) testarg-opt-stdformat-%: TEST.init = --trace-CLI --no-rc --help=pod testarg-opt-stdformat-crlf: TEST.args += --std-format=crlf testarg-opt-stdformat-raw: TEST.args += --std-format=raw testarg-opt-stdformat-unix: TEST.args += --std-format=unix testarg-opt-stdformat-utf8: TEST.args += --std-format=utf8 testarg-opt-stdformat-UTF8: TEST.args += --std-format=UTF-8 testarg-opt-stdformat-UTF-8: testarg-opt-stdformat-UTF8 # TODO: vialid options to be tested here #stdarg-opt-001: TEST.args += --sslv3 --ssl-v3 --sslv3 -.sslv3 -_sslv3 --ssl3 --ssl3 #stdarg-opt-001: TEST.args += --no-sslv2 --no-ssl-v2 --nosslv2 --no.sslv2 --no_sslv2 --no-ssl2 --nossl2 #stdarg-opt-001: TEST.args += --no-sslv3 --no-ssl-v3 --nosslv3 --no.sslv3 --no_sslv3 --no-ssl3 --nossl3 #stdarg-opt-101: TEST.args += --short #stdarg-opt-102: TEST.args += --short-txt #stdarg-opt-103: TEST.args += --shorttext #stdarg-opt-104: TEST.args += --separator SEP #stdarg-opt-105: TEST.args += --sep=SEP #stdarg-opt-106: TEST.args += --nocerttext='no text' #stdarg-opt-107: TEST.args += --nocerttxt 'no text' #stdarg-opt-108: TEST.args += --no-dns-mx #stdarg-opt-109: TEST.args += --nodns-mx #stdarg-opt-110: TEST.args += --no-mx #stdarg-opt-111: TEST.args += --dns-mx #stdarg-opt-112: TEST.args += --no-http #stdarg-opt-113: TEST.args += --nohttp #stdarg-opt-114: TEST.args += --http #stdarg-opt-115: TEST.args += --enabled #stdarg-opt-115: TEST.args += --timeout=23 #stdarg-opt-117: TEST.args += -timeout 23 #stdarg-opt-118: TEST.args += --traceKEY #stdarg-opt-119: TEST.args += --traceKEY --showhost # TODO: valid hosts and host options to be tested here #stdarg-opt-201: TEST.args += --host=a.b #stdarg-opt-202: TEST.args += --host a.b #stdarg-opt-203: TEST.args += --h a.b #stdarg-opt-204: TEST.args += --port=42 #stdarg-opt-205: TEST.args += --port 42 #stdarg-opt-206: TEST.args += --p 42 #stdarg-opt-207: TEST.args += a.b #stdarg-opt-208: TEST.args += a-b #stdarg-opt-209: TEST.args += a.b:42 #stdarg-opt-210: TEST.args += https://a.b:333/path #stdarg-opt-211: TEST.args += https://a.b:333/path?key=val #stdarg-opt-212: TEST.args += https://user:pass@a.b:333/path # TODO: invalid options to be tested here #stdarg-opt-501: TEST.args += --no-sslv #stdarg-opt-502: TEST.args += --no-sslv1 #stdarg-opt-503: TEST.args += -no-sslv1 #stdarg-opt-504: TEST.args += --un=knwon #stdarg-opt-505: TEST.args += +unknown-command #stdarg-opt-506: TEST.args += +--quit #stdarg-opt-507: TEST.args += +quit- #stdarg-opt-508: TEST.args += +hsts-sts # note: no sort because we want the sequence as defined above ALL.test.alias = $(shell awk -F: '/^testarg-opt-.*%/{next} /^testarg-opt-alias-[^%]/ {arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_MYSELF.opt)) ALL.test.stdformat = $(shell awk -F: '/^testarg-opt-.*%/{next} /^testarg-opt-stdformat-[^%]/ {arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_MYSELF.opt)) ALL.test.alias.log = $(ALL.test.salias:%=%.log) ALL.test.stdformat.log = $(ALL.test.stdformat:%=%.log) ALL.testopt += $(ALL.test.alias) ALL.testopt += $(ALL.test.stdformat) test.alias: $(ALL.test.alias) test.stdformat: $(ALL.test.stdformat) test.alias.log: $(ALL.test.alias.log) test.stdformat.log: $(ALL.test.stdformat.log) test.opt-%: test.opt.internal test.opt ALL.test.opt = $(ALL.testopt) ALL.test.opt.log = $(ALL.testopt:%=%.log) test.opt.log-compare: TEST.target_prefix = testarg-opt test.opt.log-move: TEST.target_prefix = testarg-opt test.opt.log: TEST.target_prefix = testarg-opt # 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.log-compare-hint O-Saft-22.11.22/t/Makefile.pod000077500000000000000000001247071433765727300155550ustar00rootroot00000000000000#! /usr/bin/perldoc =pod =head1 NAME Makefile.pod - documentation for project's Makefiles in POD format =head1 SYNOPSYS Makefile.pod perldoc Makefile.pod =head1 DESCRIPTION This file contains the internal (developer) documentation for all other Makefile*. This is done to keep other Makefile* as simple as possible, and just containing the user (developer) documentation. Please also SEE Documentation in o-saft.pl . =head1 ASTRACT While the main Makefile is intended for ordinary users to perfom common task for maintaining the project's installation, all other t/Makefile* are intendend for development. However, as Makefile includes most t/Makefile*, all targets for developemnt can be used there also. Most targets for development are named: testarg-* testcmd-* test.* help.* Where in general testarg-* is a target to test one or more arguments of a tool, and testcmd-* is a target to test a command of $(SRC.pl) . Most test.* targets are summary targets executing a list of the above. All help.* targets are for documentation of the makefile's targets. For more details on target names, please SEE O-Saft Makefile Targets . To get a list of all target for testing, use: make s-ALL.tests To get a list of help target, use: make help.tests make help.help =head2 Quick Overview This documentation here consist of following main sections: =over =item L Most important for users (developers) is how the Makefile* work in general and how macros, variables and targets are used. =item L To make maintenance and usage of the make system more simple (for human users and developers), some conventions for naming and syntax are used in the Makefile* . This is described in this section. =item L This section describes some GNU Make behaviours in general, and those used in this project. =item L The sub-headers in this section are referenced from other Makefile* . =back =head1 VERSION @(#) Makefile.pod 1.57 22/11/12 09:47:33 =head1 AUTHOR 18-nov-18 Achim Hoffmann =head1 O-Saft Terms Please also SEE Documentation in o-saft.pl . =head1 O-Saft Makefile Quick Overview All Makefile* provide a set of targets using a well defined naming convention. Examples (for Makefile.tcl) which provide help (documentation) for available targets: make make help make help.test make help.test.tcl make help.test.tcl.all Get a list of (nearly) all targets: make s-ALL.tests Just get a list of all targets for a specific type: make e-ALL.test.tcl make s-ALL.test.tcl Calling targets: make test.tcl make test.tcl.log make testcmd-tcl--v-host_localhost A common set of variables and targets is provided in all Makefile*. If the makefile is named Makefile.Ext , following variables exist: HELP.test.Ext TEST.Ext.hosts ALL.test.Ext ALL.test.Ext.log and following targets exist: help.test.Ext test.Ext test.Ext.log Show what all targets will do (huge output): make testarg-make-n =head2 O-Saft Makefile Example Usage To show readable (for humans) information about variables and targets from a Makefile* itself, see: make -f t/Makefile.help To get brief (mainly technical) information about the Makefile, use: make -f t/Makefile.cgi make -f t/Makefile.cgi help.test.cgi make help.test.cgi make -f t/Makefile.cgi targets.me make -f t/Makefile.cgi macros.me make -f t/Makefile.cgi s-ALL.test.cgi make -f t/Makefile.cgi p-LIST.cgi.badIP make -f t/Makefile.cgi m-LIST.cgi.badIPv6 make -f t/Makefile.cgi e-LIST.cgi.badIPv6 make -f t/Makefile.cgi s-LIST.cgi.badIPv6 (Makefile.cgi is an example, may be any other Makefile* also). =head1 O-Saft Makefile Limitations * Requires GNU Make > 2.0. * Requires GNU awk (gawk) * Requires GNU sed (for generating target INSTALL.sh ). * 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. =head1 O-Saft Makefile Preconditions The tools used and tested by make are called in the $(TEST.dir) directory (usually ./t ), but they are located in ../ (or ../contrib). Some (most) tools expect "includes" in ./ , i.e. o-saft.pl itself includes private modules from ./Net and ./OSaft. This may result in perl warnings like: "Can't locate ...". To avoid this, following symbolic links exist in $(TEST.dir) : ./t -> . ./Net -> ../Net ./OSaft -> ../OSaft ./osaft.pm -> ../osaft.pm ./.o-saft.pl -> ../.o-saft.pl ./contrib -> ../contrib ./docs -> ../docs =head1 O-Saft Makefile* The purpose of the targets in the Makefile* --the make system-- is testing O-Saft functionality, code quality, and performance. The Makefile* are located in the $(TEST.dir) directory (usually ./t ). The default target in each Makefile* simply prints a brief help. Note that the default target (the very frst one) must preceed any include directive. Most included t/Makefiles.* contain very limited comments. The details of their functionality is mainly described in this documentation here. =head1 O-Saft Makefile Syntax This section describes the syntax and other conventions used in general in all Makefile* . NOTE: this description is independent of any functionality of the project, it just describes the used "coding syntax" in Makefile*. Makefile* use mainly GNU Make's built-in variables and targets. None of them are disabled explicitly. Therefore, some behaviour may depend on the local make configuration. SEE Make:automatic variables also. =head2 O-Saft Makefile General To extract and format the texts, the targets use GNU Make's functionality like $(eval ...), $(foreach ...) and $(shell). External tools like awk, sed and tr must be used when information or text are to be extracted form other Makefile*. Each tool and its command arguments are defined as variable, see corresponding EXE.* variables. =head2 O-Saft Makefile Includes All testing functionality is grouped in individual Makefile*. They are all included by the main Makefile and organised as follows: Makefile include t/Makefile include t/Makefile.inc include t/Makefile.gen include t/Makefile.help include t/Makefile.warnings include t/Makefile.cipher include t/Makefile.cmd include t/Makefile.exit include t/Makefile.opt include t/Makefile.ext include t/Makefile.hlp include t/Makefile.cgi include t/Makefile.tcl include t/Makefile.etc include t/Makefile.dev include t/Makefile.mod include t/Makefile.php include t/Makefile.init include t/Makefile.misc include t/Makefile.critic include t/Makefile.docker include t/Makefile.legacy include t/Makefile.make To get a list of all included Makefile* use: make s-ALL.includes It is possible to use each Makefile* independently by using GNU Make's -f option, for example:: make -f Makefile.help make -f t/Makefile cd t && make -f Makefile.exit Therefore each Makefile* includes t/Makefile depending on existence of the _SID.test variable. Following Makefile* are not included and provide additional information: Makefile.pod Makefile.diffs Makefile.examples =head2 O-Saft Makefile Variable and Target Names General rules for our macro, variable and target names in Makefile* are: * macro names are lowercase characters - and _ only * variable names start with uppercase characters or _ * names consist only of characters a-zA-Z0-9_.+- * names starting with _ are intended for internal use * names use well defined prefixes which are separated by . or - * names may use variable suffixes which are separated by _ * target names use only lowercase characters and . and + and - and _ Examples: EXE.list = awk HELP_INFO := \# Name _HELP-_cgi0 = ______________________________ targets testing cgi _ HELP-testarg-cgi-host_some.tld = test all testarr-cgi targets ALL.inc.type += cgi ALL.help.tests += help.test.cgi testarg-cgi-host_some.tld TEST.args += --cgi testarg-cgi-host_localhost: TEST.args += --cgi testarg-cgi-host_: @$(TRACE.target) @do something $(TEST.args) $* ALL.test.cgi += testarg-cgi-host_some.tld testarg-cgi-host_localhost test.cgi: $(ALL.test.cgi) =head3 Used Pattern for Names Most targets and variables are named with one of following prefixes: ALL EXE GEN HELP SRC LIST TEST _HELP _TEST _SID help test The main Makefile is an exception, because it uses commonly used names for targets. =head2 O-Saft Makefile Variable Values In general no quotes around texts in variables are used. However, it is sometimes necessary to use quotes to enforce the proper evaluation of used variables in the text (mainly in target actions). It is prefered that the complete definition, name=value, fits in one line, however, huge definitions are splited in multiple lines for better (human) readability. Sometimes Make's 'define' functions are used instead of variables, mainly if it does not fit in one line. =head2 O-Saft:Makefile Version String Each Makefile defines its own unique SID as variable with a version number as value. This SID is used several times verbatim. One might argue that the variable _SID or _SID.* should be used instead for all usages. But it is used verbatim to ensure that exactly this string is used and cannot be overwritten (i.e. with an environment variable) when make is called. If a Makefile is changed, all occurrences of the string must be changed. The value of the _SID.* variables should be managed by the version control system. =head2 O-Saft Makefile Variable, Macro names Following internal variables in each Makefile* are used: _SID - version in project's Makefile _SID.* - version in included Makefile* _MYSELF.* - path of the Makefile itself (in included Makefile*) The _SID.* variables are used to check if sub-makefiles were included. Following general (global) variables are set in each Makefile*: ALL.includes ALL.inc.type ALL.help.tests More variables and targets are defined in following included files: t/Makefile t/Makefile.help t/Makefile.inc Where t/Makefile may include more files. =head3 O-Saft Makefile internal Variables When internal variables, those staring with _, are defined, they should be removed when possible using Make's 'undefine'. SEE L also. =head2 O-Saft Makefile Variables Following names are used, which potentially conflict with make itself: MAKE - make command MAKEFILE - Makefile (i.g. myself, but may be redifined) Following name prefixes are used for variables: SRC - defines a source file GEN - defines a generated file EXE - defines tools to be used (or parameters for it) ALL - defines summary variables LIST - defines lists of something SRC.contrib - something related to the contrib/ directory TEST - something related to the t/ directory TEST.critic - something related to perlcritic targets HELP - defines texts to be used in help and doc targets _ - names of internal (helper) variables (they are not intended to be overwritten on command-line) 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.tst - list of all sources used for testing the project (ALL.tst instead of ALL.test used to avoid conflicts with ALL.tests) ALL.includes - dynamically generated list of all included Makefile* ALL.Makefiles - static list of all source Makefile* of the project ALL.test.TYP - list of all targets from Makefile.TYP aka Makefile.* ALL.tests - list of all targets for testing ALL.tests.log - list of all targets for tests writing to logfiles The variables ALL.tests and ALL.tests.log are generated in t/Makefile from the corresponding ALL.test.TYP in each t/Makefile.TYP , where TYP is cmd, cgi, opt, etc. SEE O-Saft Makefile Includes also. =head2 O-Saft Makefile Targets Naming conventions for targets: _test_name - internal target, not intended for public use test.name - public available targets use . (dot) as separator test-name - internal and pattern rule targets use - (dash) as separator test.name_arg - some pattern rule targets use _ to pass arguments test.name.log - same as test.name but store results in logfile test%ext - pattern rule used instead of explicit target rule to allow spelling variants, like tst.ext or tst-ext testarg-TYP-* - targets for testing tool arguments in Makefile.TYP testcmd-TYP-* - targets for testing tool commands in Makefile.TYP "tool" may be any of those defined in macro ALL.exe see variable ALL.exe for defined "tool"s testarg-name% - pattern rule which finally uses testarg-% target testcmd-name_% - pattern rule which finally uses testcmd-% target Examples: testcmd-cmd-+check_localhost - test command +check of $(SRC.pl) with parameter localhost target can be found in Makefile.cmd testarg-dev-install-sh_--check - test tool INSTALL.sh with argument --check target can be found in Makefile.dev Targets in the Makefile* are grouped, usually. Each group should be headed by the help texts for the targets using HELP- variables (see below). =head2 O-Saft Makefile HELP Texts For extracting information from the Makefile*, i.e variables and targets and their definitions, following special naming syntax is used: * All texts for documentation are stored in variables prefixed HELP- * Anything following the prefix HELP- 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, usually heading a group of targets. Example: HELP-_help = ____ targets for help about Makefile _ * The variable with the prefix HELP. for example HELP.help, is used for additional documentation; as the variable often contains multiline texts each line must be terminated with $(_NL)\ which will be evaluated when the variable is used. It is good practice to start each line with \# . 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. The HELP.typ variable is special as it uses . as separator). It defines the help text for Makefile.typ itself and must not be matched when extracting the other HELP-* variables. Example: HELP-_cgi0 = _______________________________ some targets _ HELP-help = print overview of all targets HELP-doc = same as help, but evaluates variables HELP.typ = $(_NL)\ \# some additional text with more than one line $(_NL)\ \# other line These variables (above) are used by the help and doc target. They are printed as follows: #_______________________________ some targets _ help # print overview of all targets doc # same as help, but evaluates variables # some additional text with more than one line # other line =head1 GNU Make Internal testing of all functionality of the project is done using make, in paticular GNU Make. In contrast to traditional make, GNU Make has more features and behaves slightly different to traditional make. =head2 GNU Make:Terms Some words about the terms and words used in GNU Make in this project. * macro is a synonym for variable in makefiles, here the term variable is prefered. * GNU Make uses functions for its own built-in functions. When commands are grouped using the 'define' directive (function), GNU Make uses the term "user defined functions". Here the term macro is used for that. * GNU Make uses prerequisites when targets depend on something, here the term dependencies is used. * GNU Make distinguishes the terms: explicit rules, implicit rules and static pattern rules. For simplicity, target is used when explicit rules are meant, and pattern rule is used for static pattern rule . * GNU Make refers to the commands executed in a target as recipe. * GNU Make refers sometimes to targets as goals (i.e. .DEFAULT_GOAL). =head2 GNU Make:macros * macro is a synonym for variable in GNU Make makefiles. * macro definitions in makefiles must not be sequential! * $$ avoids evaluating $ (the variable) when reading the makefile, but it is evaluated when the corresponding target is executed. * deferred definition using = - variable expanded when used. * immediate definition using := - variable expanded when defined. * immediate definition using ::= - variable expanded when defined. Note that := (traditional GNU Make) is equivalent to ::= (POSIX). Only := is used in our Makefile*. =head2 GNU Make:include GNU Make's include directive doesn't understand variables, the used path must be verbatim. Multiple makefiles are used to keep make's functionality (targets) maintainable. Beside Makefile they are all named Makefile.TYP where TYP describes the content, somehow. I. g. it should be possible to use each of these Makefile* by its own, like: make -f Makefile.TYP target GNU Make's include functionality, in particular when including files sub- directories, is difficult to use. Hence following trick is used: * sub-directories contains a symbolic link to . (itself) * Makefile* always include other files with relative paths Example: ./t/ (directory) contains: t -> . ./t/Makefile.cgi contains: include t/Makefile This avoids 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 also cannot manage recursive includes of the same file. This must be checked before including. The private _SID.* variable, which is set in all Makefile*, is used. Example: ifeq (,$(_SID.test)) -include t/Makefile endif It is silently ignored if the file required by the -include directive is missing. =head2 GNU Make:important variables Remember important variables: $(MAKE) - the make command itself, in sub-make with additional arguments/options (see make's documentation ) $(MAKE_COMMAND) - private variable for the make command, without other arguments/options as in $(MAKE) SEE Make:MAKE vs. MAKE_COMMAND $(MFLAGS) - contains all passed arguments/options to make $(MAKEFLAGS) - same as $(MFLAGS) but omitts leading - character $(MAKECMDGOALS) - name of the target to be satisfied $(MAKEFILE) - name of the target to be satisfied $(MAKEFILES) - environment variable containing makefiles to be read $(MAKEFILE_LIST)- included Makefiles in the order they have been read For details use: make help.test.make make testcmd-test.internal =head2 GNU Make:automatic variables Note that variable definitions in makefiles must not be sequential! Remember GNU Make's automatic variables: $@ - target (file name) $* - matching files of the rule, the stem of the pattern rule $+ - all dependencies of the target $^ - all dependencies of the target (without duplicates) $< - first dependency of the target $? - dependencies newer than the target $| - "order-only" dependencies $* - matching files of the rule $% - target (archive) member name (rarely used) Use of $$ avoids evaluating $ . =head2 GNU Make:pattern-specific variables Processing pattern-specific variables changed in gmake, I guess with 3.81. Makefile* in this project rely on the behaviour of gmake 3.81 and newer, which applies all pattern-specific variables from all matching patterns. If interested in the difference, read on. Example (pre 3.81): VAR = default foo: VAR = foo bar: VAR = bar foo: @echo foo uses VAR='$(VAR)' bar: @echo bar uses VAR='$(VAR)' foobar: @echo foobar uses VAR='$(VAR)' other: @echo other uses VAR='$(VAR)' When calling these targets (foo, bar, foobar, other) the results are: foo uses VAR='foo' bar uses VAR='bar' foobar uses VAR='foo' other uses VAR='default' In contrast, gmake 3.81 and newer return following results: foo uses VAR='default foo' bar uses VAR='default bar' foobar uses VAR='default foo bar' other uses VAR='default' Note that the modern behaviour - applying all pattern-specific variables - has a big performance penulty if many such variables are used. This should not be the case in our Makefile* . =head2 GNU Make:.SECONDEXPANSION GNU Make's variables can be used as target, in the rules commands and also as dependency. When used as dependency, it must be a file (or directory). When a dependency to another target is defined in a variable, GNU Make's "Secondary Expansion" must be enabled using the special target: .SECONDEXPANSION: and the dependency have to be written as "escaped" variable, like: other = other-target other-target: do-somthing target: $$(other) If the used make does not support .SECONDEXPANSION: , the targets must be rewritten with the real target name instead of the escaped variable. =head2 GNU Make:Pattern Rule GNU Make's >3.81 documentation states that the first matching pattern rule will be used and others are not executed. First means: the first appearing rule in the Makefile. On some systems the last defined pattern rule will be executed, unfortunately. This behaviour inhibits that the sequence of rules can be used to ensure the execution of a special rule. As workaround a more specific pattern rule is defined in such cases. =head2 GNU Make:MAKE vs. MAKE_COMMAND Traditionally $(MAKE) is used for the make command itself. For convenience t/Makefile.inc redefines MAKE to contain -f Makefile . When $(MAKE) is used in documentation (variables or texts), make should be printed, usually. It is recommended to use $(MAKE_COMMAND) there. When using $(MAKE) is used in quoted texts, for example: echo "$(MAKE)" GNU Make behaves strange and evaluates the line before printing). =head1 O-Saft Makefile Annotations As in the source code of the project, some descriptions in Makefile* also need to be available on more than one place. Such texts can be referenced to using the "SEE " syntax in the Makefile*. These annotations are described here, this file, one sub-section for each annotation. =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 variable 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 ~ /^target-/){arr[$$1]=1}$(_EXE.print_arr_END.awk)'\ $(_MYSELF.some-type)) (where target- is an example target name, and _EXE.print_arr_END.awk is the awk code to print the defined array arr[]). Target names may occour as following constructs: static-target: pattern-rule-%: pattern-%-rule: static-target: VAR = value pattern-rule-%: VAR = value The result should contain real (static) targets only, no pattern rules. Duplicate target names should also be avoided. Using awk satisfies both requirements. Matching targets is as simple as: /^target-%/{next} # skips pattern rules /^target-[^%]*:/ # matches static targets /^target-[^%]*:/{arr[$$1]=1} # stores target name in an array awk's array arr[] now contains all target names. Duplicates are ignored because the already existing arr[target] is overwritten. Finally we just need to print all array elements: END { for (idx in arr) { print idx } } Matching targets needs to be done individually in each Makefile*, printing the array is always the same. Hence the code for awk's "END{}" can be put in a make variable also. =head2 Make:target generation For testing single arguments out of a list with the same target, a target for for each argument is required. There're still some pattern rules which do this, but they need to be called with the proper value of the pattern. That's why we need a single target for each argument. The first goal to do this is to write each of these unique targets without commands (recipe). When called, they finally match a proper pattern rule. Example: testarg-%: some command here testarg-tst-tool--arg1: testarg-tst-tool--arg2: As a naming scheme for target names is used which includes the tool's name and the most important argument, elongate target names would be created. There are also many targets then, which just differ in the last part, the argument. Therefor, GNU Make provides "user defined functions" which we call macros. They are mainly defined in Makefile.gen. =head3 Synopsis General macros (functions): $(call GEN.targets,testcmd,TYP,TOOL,VAR-name,TEST.args,TEST.init) $(call GEN.targets,testcmd,TYP,TOOL,VAR-name,TEST.init,TEST.args) Wrapper macros (functions) calling the general macro: $(call GEN.targets-args,testarg,TYP,TOOL,VAR-name) $(call GEN.targets-init,testarg,TYP,TOOL,VAR-name) $(call GEN.targets-args,testcmd,TYP,TOOL,VAR-name) $(call GEN.targets-init,testcmd,TYP,TOOL,VAR-name) =head3 Description The goal of the functions is to generate all targets for a specific tool. Any tool may be called with its own arguments. Therefore, each argument to be tested with a tool, requires its own target. Also, each target must be added to the corresponding / well-known variable, for example: ALL.* etc.. Finally a target -pattern rule- is generated, which groups the targets for this tool. Please see below for L. For these targets, the variables EXE.pl, TEST.init and TEST.args must be defined properly. In most cases, only one of TEST.init or TEST.args is needed. The other one is set empty. It avoids inheritance of its value from other matching targets. Abstract example: testarg-TYP-TOOL_%: EXE.pl = ../TOOL testarg-TYP-TOOL_%: TEST.init = testarg-TYP-TOOL-arg: TEST.args = some-arg As no commands are defined for the targets, they (above example) finally As no commands are defined for the targets, they finally match the generic target testarg-% . Currently supported pattern rules in t/Makefile are: testarg-% and testcmd-% This still allows to use special or additional settings for the generated targets. Such settings must be done explicitly in the calling Makefile.* . Example: testarg-TYP-TOOL-arg: TEST.init += other-arg =head3 Target generation function The target names follow a strict syntax, see L. In short, the naming scheme is: testarg-TYP-TOOL-OPTIONS_ARGUMENT where TYP is the Makefile's type, TOOL is the tool to be executed, OPTIONS are the used options for the tool and ARGUMENT is a paramter to the tool. The prefix of the target name, testarg in above example, can be specifid too. Note that a corresponding pattern rule must exist with this pattern. Currentls there are: testarg-% testcmd-% . To build the target name, the prefix, TYP and TOOL must be passed to the functions. They are passed verbatim. The last parameter passed is the name of the variable which contains a list of values to be used as ARGUMENT. Because there are a some (GNU Make) restrictions for allowed characters in target names, some characters of the values need to be substituted. These charcters are in particular / : and = . Means that ARGUMENT can be like: --option=value Note that the tools are called in the test directory, ./t usually, they're and should not be found via $PATH . So the value assigned to EXE.pl must be prefixed with ../ . All generated targets are also added to the variable ALL.test.TYP . SEE O-Saft Makefile Variable, Macro names also. SEE O-Saft Makefile Variable, Macro names also. =head3 Target function variants Depending on the purpose of the tests, setting the variables TEST.init and TEST.args should be swapped. Therefore, the function provides parameters for them. Swapping the variables has no impact on the commands executed by the target, beside the order of its arguments. For Example, this could be used to generate the same command-line just differing in the last argument of the executed command (may produce a more pretty output). Additionally 2 simple wrapper functions for both variants are provided. =head3 Examples =over =item Generate targets for various options TOOL = path/tool LIST.tool = --opt=val --arg $(call GEN.targets-args,testarg,typ,$(TOOL),LIST.tool) This generates following targets and variables: testarg.typ.path-tool_--opt-val: TEST.args = --option1 testarg.typ.path-tool_--arg: TEST.args = --option1 testarg.typ.path-tool_%: TEST.init = testarg.typ.path-tool_%: EXE.pl = ../path/tool ALL.testarg.typ.path-tool = testarg.typ.path-tool_--option1 testarg.typ.path-tool_--arg ALL.testarg.typ = $(ALL.testarg.typ.path-tool) =item Generate targets for various options $(call GEN.targets-init,testarg,typ,$(TOOL),LIST.tool) TODO ... to be completed ... =back =head2 Make:variables and quotes Values of variables in GNU Make's makefiles follow some strange rules: * anything right of leftmost # character is a comment and ignored * anything right of leftmost = character is part of the value * single quotes, double quotes and \ character have no special meaning * single quotes, double quotes and \ become meta characters depending on how the variable is used, in particular used with or without quotes * newlines in a variable are not preserved when the variable is used For most common usage of variables, these rules are less important. But if the variable contains descriptive texts, some care needs to be taken. This description is about defining and using such variables with random texts. In general it is not necessary to use quotes for variable values. However, reading the values would be easyer and syntax highlighting in some editors more accurate using quotes. It is more a personal preference if quotes for variable definitions should be used or not. The decision here is to not use quotes for definition, but use (double) quotes for variable's usage. This also has the benefit, that a variable is identifiable as "descriptive text" when used. Keep in mind, that newlines to be printed must be explicitly written in a variable's value, $(_NL) is used for that. GNU Make's define directive, which would avoid the use of $(_NL), is not used to set variables. May change in future ... =head2 Make:macros This is about our macros, which are "user defined functions" in GNU Make. Some notes about oddities with 'define', 'foreach', 'call', 'eval': =over =item using 'foreach' function in general To enforces execution of $(foreach ..) in the macro, macro definitions are defined inside 'ifndef' .. 'endif' scope. =item 'foreach', 'call' function While the 'foreach' function allows seperating its parameters with spaces, parameters for 'call' and 'subst' must be used without spaces. =item using variablas in macros Variables n macros can be set directly by using: _macro-var=value or $(eval _macro-var=value) Unfortunatelly a simple 'undefine _macro-var' does not always work. Then '$(eval undefine _macro-var)' must be used. It is difficult to debug such variables, best is to use our target like: make help.test.makevars | grep _macro-var =back =head2 Make:defines with commands (recipes) If defines containg lists of commands are used to be executed in a target, following rules need to be observed: * using shell's test commands inside GNU Make's makefiles is tricky, as single quotes instead of double quote must be used for test -n '$var' . =head2 Make:--ignore-output Some values of keys are different by nature for each call of o-saft.pl . To avoid diffs when testing with *.log targets, output of such keys must be ignored for all targets with +info , +check or any other combining commands (like +hsts). Output such keys can be ignored using o-saft.pl's option --ignore-output= (alias --no-out=). Alias --no-out= is used to keep the command-line shorter. The variable _ignore-output (computed from _ignore-output-keys) contains these keys (commands). This variable should be used whenever such commands are tested. Unfortunately this results in untested commands, those defined in the variable _ignore-output-keys . An additional target should exist to test these commands also. =head2 Make:--dry-run When make is called with the -n (--dry-run) option, make usually simply prints the commands to be executed instead of executing them. If a command redirects its output to a file, the file will not be generated. But if the command is $(MAKE) make will be called recursively and redirected to the specified file. This generated file then doesn't contain expected content. Hence the generation of the file should be avoided. The recursive make command should be printed instead of being executed. GNU Make has following documented recipe for this: ifeq (n,$(findstring n,$(MAKEFLAGS))) @echo "$(MAKE) $(MAKEFLAGS) $* > $@" else @$(MAKE) $(MAKEFLAGS) $* > $@ endif Unfortunately this solution has the drawback that it * depends on the version of GNU Make (may work or not) * is not compatible with other make Another possibility is to use shell's if-then-else syntax for the target's commands. Beside the ugly definition of a shell inline script, this script then also acts as one command in the target which makes the output hard to read (by humans). Hence following simplified if-then-else construct is used: @expr "$(MAKEFLAGS)" : n >/dev/null \ && echo "$(MAKE) $(MFLAGS) -s $* > $@ 2>&1" \ || $(MAKE) $(MFLAGS) -s $* > $@ 2>&1 Note that $(MAKEFLAGS) may look like: nrR --no-print-directory =head2 Make:Perl::Analyzer For generating documentation of the own Perl modules and a calling tree of them, perl-analyzer is used. The tools require the Perl modules JSON and Text::MicroTemplate (beside some mor commonly installed Perl modules). =head2 Make:Profiling Profiling is mainly done with Perl's built-in functionality: perldebug. There are also targets which require the Perl modules Devel::DProf and/or Devel::NYTProf to do the profiling. =head3 Perl packages * debian: libdevel-trace-perl libdebug-trace-perl * debian: libdevel-dprof-perl libdevel-nytprof-perl * debian: libjson-perl libtext-microtemplate-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 more conditional rules for each pattern rule to set the variable $(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 5000 # TODO: to be implemented #--load=EXAMPLE # TODO: test with docker #testarg-tcl-o-saft.tcl_--id: TEST.args += --id=docker-ID #testarg-tcl-o-saft.tcl_--tag: TEST.args += --id=docker-Tag #testarg-tcl-o-saft.tcl_--v--gen-docs: TEST.args += --v --gen-docs # --gen-docs should be used with o-saft.pl only, see Makefile.hlp ifndef tcl-macros-generated $(call GEN.targets,testarg,tcl,-$(SRC.tcl),$(SRC.tcl),LIST.tcl.args,TEST.args,TEST.dumm) endif ALL.test.tcl += \ testarg-tcl-o-saft.tcl_--v--no-docs testarg-tcl-o-saft.tcl_--v--load \ testarg-tcl-o-saft.tcl_--v--img testarg-tcl-o-saft.tcl_--v--text \ testarg-tcl-o-saft.tcl_--v-host testarg-tcl-o-saft.tcl_--v-host-host \ testarg-tcl-o-saft.tcl_--v-host1-host2 # test command which require user interaction (in GUI) testarg-tclinteractive-%: EXE.pl = ../$(SRC.tcl) testarg-tclinteractive-%: TEST.init = $(TEST.host) testarg-tclinteractive---gui--gui-classic: TEST.args += --gui --gui-layout=classic testarg-tclinteractive---gui--gui-tablet: TEST.args += --gui --gui-layout=tablet testarg-tclinteractive---gui--docker: TEST.args += --gui --docker testarg-tclinteractive---test-tcl: TEST.args += --test-tcl ALL.test.tcl.log = $(ALL.test.tcl:%=%.log) # *test-interactive* targets are not added to common variables, # because they cannot be used in scripted make ALL.testtclinteractive := testarg-tclinteractive---test-tcl \ testarg-tclinteractive---gui--gui-classic \ testarg-tclinteractive---gui--gui-tablet \ testarg-tclinteractive---gui--docker ALL.test.tclinteractive = $(foreach host,$(TEST.tcl.hosts),$(ALL.testtclinteractive:%=%$(host))) ALL.test.tclinteractive.log = $(ALL.test.tclinteractive:%=%.log) test.tclinteractive: $(ALL.test.tclinteractive) test.tclinteractive.log: $(ALL.test.tclinteractive.log) test.GUI: test.tclinteractive test.GUI.log: test.tclinteractive.log test.tcl.log-compare: TEST.target_prefix = testarg-tcl- test.tcl.log-move: TEST.target_prefix = testarg-tcl- test.tcl.log: TEST.target_prefix = testarg-tcl- test.tcl: $(ALL.test.tcl) test.tcl.log: $(ALL.test.tcl.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.template000077500000000000000000000123721433765727300166000ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.TEMPL #? # HACKER's INFO # This file itself is not used (included) in t/Makefile. # #? VERSION #? @(#) Makefile.template 1.26 22/09/21 12:01:24 #? #? AUTHOR #? 18-may-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.TEMPL = targets for testing SOMETHING # Makefile with template for new targets in Makefile.TEMPL _SID.TEMPL := 1.26 _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 ALL.help.tests += help.test.TEMPL 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 help.test.TEMPL: HELP_TYPE = TEMPL help.test.TEMPL-v: HELP_TYPE = TEMPL help.test.TEMPL-vv: HELP_TYPE = TEMPL #_____________________________________________________________________________ #________________________________________________________________ variables __| testcmd-TEMPL%: TEST.init = testcmd-TEMPL%: TEST.args = # TEST.init and TEST.args should be set for the targets herein # only, otherwise it may confuse other targets if this Makefile # is used together with other t/Makefile.* TEST.TEMPL.args = \ -TEMPL-opt \ ifdef TEST.hosts TEST.TEMPL.hosts= $(TEST.hosts) # list of TEST.hosts can be passed with environment or on command line endif # or TEST.TEMPL.hosts= host.to.be.tested # define our list of TEST.hosts #_____________________________________________________________________________ #_____________________________________________________ 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: test.TEMPL.internal #_____________________________________________________________________________ #______________________________________________________________ testing ... __| # Description for private help text. # SEE Make:variables and quotes # SEE Make:MAKE vs. MAKE_COMMAND HELP-_TEMPL1 = _____________________________________________ testing ... _ HELP-test.TEMPL = test functionality of SOMETHING HELP-test.TEMPL.log = same as test.TEMPL but store output in '$(TEST.logdir)/' HELP.TEMPL = $(_NL)\ \# Examples:$(_NL)\ \# $(MAKE_COMMAND)t.TEMPL HELP.test.TEMPL.all = # no special documentation yet # 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 { # initialise variables for 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: 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..._/){arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_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-..._/){arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_MYSELF.TEMPL)) # pattern rule to map to testcmd-% testTEMPL-%: testcmd-% @$(EXE.dummy) ## 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 __| # more verbose target: test.TEMPL-v and test.TEMPL-vv test.TEMPL-%: test.TEMPL.internal test.TEMPL @$(EXE.dummy) test.TEMPL.log-compare: TEST.target_prefix = testcmd-TEMPL test.TEMPL.log-move: TEST.target_prefix = testcmd-TEMPL test.TEMPL.log: TEST.target_prefix = testcmd-TEMPL test.TEMPL: $(ALL.test.TEMPL) test.TEMPL.log: $(ALL.test.TEMPL.log) test.log-compare-hint O-Saft-22.11.22/t/Makefile.warnings000077500000000000000000000555721433765727300166260ustar00rootroot00000000000000#! /usr/bin/make -rRf #? #? NAME #? Makefile - makefile for testing O-Saft warning messages #? #? DESCRIPTION #? For more details please see #? ../Makefile Makefile Makefile.help Makefile.pod #? make help.test.warnings #? #? 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. #? #? VERSION #? @(#) Makefile.warnigs 1.73 22/10/29 18:58:26 #? #? AUTHOR #? 18-apr-18 Achim Hoffmann #? # ----------------------------------------------------------------------------- HELP-help.test.warnings = targets for testing '$(SRC.pl)' WARNING messages _SID.warnings := 1.73 _MYSELF.warnings := t/Makefile.warnings ALL.includes += $(_MYSELF.warnings) ALL.inc.type += warnings ALL.help.tests += help.test.warnings first-warn-target-is-default: help.test.warnings ifeq (,$(_SID.test)) -include t/Makefile endif ifndef TEST.host TEST.host = localhost endif help.test.warnings: HELP_TYPE = warnings help.test.warnings-v: HELP_TYPE = warnings help.test.warnings-vv: HELP_TYPE = warnings #_____________________________________________________________________________ #________________________________________________________________ variables __| # extract all line looking like: # die $STR{ERROR}, # warn $STR{ERROR}, # warn $STR{WARN}, # warn $STR{WARN} . # warn($STR{ # warn "**WARNING: # _warn(" # _warn($STR{ # Because perl comments with # cannot be used inside Makefile's define or macro # definitions, the following sequence of the perl code is explained first: # skip assignments # remove opening ( if any # if line mtches die or warn or print # replace die|warn by **WARNING: or **ERROR: # replace _warn by **WARNING: # remove postfix condition # remove ") and anything reight to it # remove _warn (if still there) # TODO: warn and die not detected, if they do not appear as first word in line EXE.extract_warn := perl -nle '\ m/^\s*warn\s+=/ && do {next};\ s/[(]/ / if m/^\s*(?:die|_?warn|print)\s*\(\s*$$STR.[EW]/;\ m/^\s*(?:die|_?warn|print $$STR.[EW])/ && do {\ s/^\s*(?:print|die|warn)\s+$$STR.ERROR.,\s"/**ERROR: /;\ s/^\s*(?:print|die|warn)\s+$$STR.WARN.[,.\s]+"/**WARNING: /;\ s/^\s*(?:print|die|warn)[\s(]+"\$$STR.WARN.[,.\s]+/**WARNING: /;\ s/",\s+"/ /;\ s/^\s*_warn(?:_nosni)?\s*\(\s*"/**WARNING: /;\ s/ +if +\(.*//;\ s/"\s*\)?\s*;?\s*$$//;\ s/^\s*_?warn\s*\(?"//;\ print;\ }' EXE.gen_warning-target := perl -nle '\ s/^..(?:ERROR|WARNING): /warning-/;\ s/:/: TEST.args = TODO:/;\ print;' #_____________________________________________________________________________ #_________________________________________________________ testing warnings __| HELP-_warnings = ____________________________________________ test warnings _ HELP-test.warnings = test **WARNING messages of '$(SRC.pl)' HELP-test.warnings.log = test **WARNING messages of '$(SRC.pl)' and compare with previous one HELP-message-STR = test for specific STR in output of '$(SRC.pl)' HELP-warning-NR = test for specific messages number NR in output of '$(SRC.pl)' HELP-warnings-info = get all **WARNING messages from '$(SRC.pl)' HELP-warnings-show.todo = show not implemented tests for warnings HELP-warnings-show.difficult= show tests for warnings which are difficult to implement HELP-warnings.gen.template = generate template Makefile for testing warning messages HELP.warnings = $(_NL)\ \# Hint: message-STR can test for any string in output, example$(_NL)\ \# $(MAKE_COMMAND) message-Certificate TEST.args='+cn localhost'$(_NL)\ \#$(_NL)\ \# Examples:$(_NL)\ \# $(MAKE_COMMAND) warning-042$(_NL)\ \# $(MAKE_COMMAND) message-Certificate TEST.args='+cn localhost'$(_NL)\ \#$(_NL)\ \# Note that using -n reports a bunch of shell commands. HELP.test.warnings.all = \ \# for more details, use:$(_NL)\ \# $(MAKE_COMMAND) t-warn$(_NL)\ # SEE Make:target name # SEE Make:target name prefix # testing warning messages TEST.tmp.rc := /tmp/o-saft.tmprc test.warnings%: EXE.pl = ../$(SRC.pl) warning-%: EXE.pl = ../$(SRC.pl) warning-%: TEST.init = # How target rules in this Makefile (should) work: # The pattern rule message-% from ./Makefile is used to check for a # specific warning message. warning-%: message-% @$(TRACE.target) # The pattern rule message-% 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 target test.warnings . # # To log the results of these tests, only one file will be created, not # one for each target rule. The target is test.warnings.log . # # All targets define EXE.pl which is the command to be used. # All targets should define TEST.args with the arguments, which force # the warning message DDD given in the target's name warning-DDD . # Some messages can be tested without any target host, then the +quit # command is added to TEST.args . Others need a target host argument # somehow, "any-host" is used for that. Using "any-host" most likely # causes $(EXE.pl) to fail with more WARNNG messages printed, but they # are silently ignored because the message with the specific number DDD # only is extracted. # If the definition of TEST.args 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 be tested easily. They are currently disabled, means that the # "TODO" text is printed by the target. # # Examples # warning-049: TEST.args = +unknown_command +quit # warning-004: TEST.args = TODO: testing perl status, difficult ... # # 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. # # NOTE: in rare cases the target may succedd wrongly, see description # of message-% pattern rule in t/Makefile. # TODO: the message text assigned to TEST.args is mainly a copy of the # the text used in the source code; should find a way to generate # these assignments (done manually here, which is error-prone) 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, disabled ... 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, disabled ... 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 ... # 016, 017: programing error warning-016: TEST.args = TODO: testing undefined cipher description for, difficult ... warning-017: TEST.args = TODO: testing partial match for cipher name found, difficult ... warning-020: TEST.args = TODO: testing die, CGI mode requires strict settings, disabled ... 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 /unknown-host +quit warning-043: TEST.args = +cn --port=' ' unknown-host +quit warning-044: TEST.args = +zlib +lzo +open_pgp +fallback +quit warning-045: TEST.args = any-host --port 45 +quit warning-046: TEST.args = --rc=$(TEST.tmp.rc) --v +quit warning-046: TEST.rc = --cfg_cmd=new_command=quit 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=$(TEST.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 = --cipher-mode=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 = TODO: testing configuration file cannot be opened #warning-070: TEST.args = --cfg_cmd=$(TEST.tmp.rc) +quit #warning-070: TEST.args = TODO: need special test target which uses unredable --cfg_cmd=$(TEST.tmp.rc) warning-071: TEST.args = --cfg_unknown=dummy=dummy +quit warning-070: TEST.args = TODO: configuration files are not read in CGI mode, difficult ... #warning-072: TEST.args = --cfg_cmd=$(TEST.tmp.rc) --cgi +quit #warning-072: TEST.rc = --cfg_cmd=new_command=not_allowed_with--cgi warning-073: TEST.args = --cfg_cmd=invalid_default_command=default +quit #?# warning-074: TEST.args = --rc=$(TEST.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-081: TEST.args = TODO: ancient Net::SSLeay Net::SSLeay::VERSION < 1.49, difficult ... warning-090: TEST.args = TODO: Net::SSLinfo::next_protos no longer supported, please use Net::SSLinfo::protos_alpn instead, difficult ... warning-091: TEST.args = TODO: help file cannot be opened, difficult ... warning-092: TEST.args = TODO: help file unknown syntax:, difficult ... warning-093: TEST.args = TODO: help file cannot be opened, difficult ... warning-190: TEST.args = TODO: open(OSaft/Doc/file.txt): failed, difficult ... warning-191: TEST.args = TODO: no OSaft/Doc/file.txt found, difficult ... 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-113 .. warning-119: TEST.args = free 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, NPN disabled #warning-131: TEST.args = free warning-132: TEST.args = TODO: testing openssl < 1.0.1, NPN 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-136: TEST.args = free #warning-137: TEST.args = free #warning-138: TEST.args = free #warning-139: TEST.args = free 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 = TODO: testing connection without SNI (errors), difficult ... 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-306 .. warning-310: TEST.args = free 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-407: TEST.args = --no-rc +cipher -ciphermode=intern --cipher=IS-UNKNOWN $(TEST.host) warning-408: TEST.args = --no-openssl +cipher-dh --exit=HOST2 $(TEST.host) warning-409: TEST.args = --sslv2 --sni +cipher --exit=HOST4 $(TEST.host) warning-410: TEST.args = --sslv2 --sni +cipher --ciphermode=openssl --exit=HOST4 $(TEST.host) warning-411: TEST.args = TODO: testing checked cipher does not match returned cipher, difficult ... warning-412: TEST.args = TODO: testing missing ciphers in sorted list, difficult ... warning-420: TEST.args = TODO: testing empty value [$cipher, $ssl], check ignored; programming error warning-451: TEST.args = TODO: testing function obsolete, please use cipher_openssl, difficult ... warning-510: TEST.args = TODO: testing --help=unknown-table , 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-651: TEST.args = TODO: testing Net::SSLeay >= 1.45 required for getting version warning-652: TEST.args = TODO: testing Net::SSLeay >= 1.33 required for getting subjectAltNames warning-653: TEST.args = TODO: testing Net::SSLeay >= 1.30 required for getting commonName warning-654: TEST.args = TODO: testing Net::SSLeay >= 1.45 required for getting fingerprint_md5 warning-655: TEST.args = TODO: testing Net::SSLeay >= 1.46 required for getting some certificate checks warning-801: TEST.args = TODO: testing connection returning unknown label, difficult ... warning-811: TEST.args = TODO: testing 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 # o-saft.pl: programming error (cipher missing in %cipher) warning-862: TEST.args = TODO: unknown cipher key '$key', key ignored, difficult ... warning-863: TEST.args = TODO: unknown cipher key '$key', key ignored, difficult ... # not yet used in o-saft.pl (1/2019) warning-501: TEST.args = TODO: cannot read OSaft/_ciphers_openssl_all.pm warning-501: EXE.pl = ../OSaft/Ciphers.pm warning-502: TEST.args = TODO: cannot read OSaft/_ciphers_iana.pm warning-502: EXE.pl = ../OSaft/Ciphers.pm warning-503: TEST.args = TODO: cannot read OSaft/_ciphers_osaft.pm warning-503: EXE.pl = ../OSaft/Ciphers.pm warning-504: TEST.args = TODO: DATA line%4d: wrong hex key warning-504: EXE.pl = ../OSaft/Ciphers.pm warning-505: TEST.args = TODO: DATA line%4d: wrong number of TAB-separated fields warning-505: EXE.pl = ../OSaft/Ciphers.pm warning-511: TEST.args = getter=0x42 warning-511: EXE.pl = ../OSaft/Ciphers.pm warning-513: TEST.args = TODO: partial match for cipher name found, difficult ... warning-513: EXE.pl = ../OSaft/Ciphers.pm # Ciphers.pm warning-520: TEST.args = testing ciphers unknown format warning-520: EXE.pl = ../OSaft/Ciphers.pm # Ciphers.pm: programming error warning-521: TEST.args = TODO: no key found for '$txt' warning-521: EXE.pl = ../OSaft/Ciphers.pm #warning-522: TEST.args = TODO: testing duplicate openssl key, difficult ... #warning-522: EXE.pl = ../OSaft/Ciphers.pm ALL.test.warnings = $(shell awk -F: '/^warning-...:/{arr[$$1]=1}$(_EXE.print_arr_END.awk)' $(_MYSELF.warnings)) _TEST.template = t/test.warning.Makefile-template $(_TEST.template): $(SRC.pl) $(SRC.pm) @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 "" >> $@ @$(EXE.extract_warn) $^ \ | $(EXE.gen_warning-target) \ | sort >> $@ @-ls -l $@ warnings.gen.template: $(ALL.Makefiles) $(_TEST.template) # TODO: Makefile dependency does not work, probably need to use $(MAKE) # TODO: hence missing from ALL.test.warnings .PHONY: warnings.gen.template warnings-info: $(SRC.pl) $(SRC.pm) @echo "# generated by $(_MYSELF.warnings) $@" @echo "# list of used error and warning numbers and messages" @$(EXE.extract_warn) $^ | sort warnings-show.todo: grep "^warning..*TODO" $(_MYSELF.warnings) ALL.test.warnings += warnings-info warnings-show.difficult warnings-show.todo warnings-show.difficult: grep "^warning..*difficult" $(_MYSELF.warnings) warnings-%.log: $(TEST.logdir) @$(TRACE.target) @$(TRACE.target.log) @$(eval _NEW.log := $(TEST.logdir)/$@-$(TEST.today)) @$(MAKE) $(MFLAGS) -s warnings-$* > $@ 2>&1 @expr "$(MAKEFLAGS)" : n >/dev/null \ && echo "$(MAKE) $(MFLAGS) -s warnings-$* > $@ 2>&1" \ || $(MAKE) $(MFLAGS) -s warnings-$* > $@ 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)/warnings-$(*)* # TODO: target should be unified with testcmd-%.log # $(_TEST.warning.log) calls "make -s" to avoid printing of executed commands _TEST.warning.log = $(TEST.logdir)/test.warnings.log-$(TEST.today) $(_TEST.warning.log): @echo "# $(_MYSELF.warnings) 1.73: $(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: $(_TEST.warning.log) @$(TRACE.target) @$(TRACE.target.log) @diff $(TEST.logdir)/$@ $(_TEST.warning.log) \ && rm $(_TEST.warning.log) \ || mv $(_TEST.warning.log) $(TEST.logdir)/$@ @-test -f $(TEST.logdir)/$@ || mv $(_TEST.warning.log) $(TEST.logdir)/$@ @ls -l $(TEST.logdir)/$@* # TODO: same target as test.cgi.log ALL.test.warnings.log = test.warnings.log test.warnings: $(ALL.test.warnings) O-Saft-22.11.22/t/SSLinfo.pl000077500000000000000000000040741433765727300152000ustar00rootroot00000000000000#! /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-22.11.22/t/cloc-total.awk000077500000000000000000000035201433765727300160660ustar00rootroot00000000000000#!/usr/bin/awk -f #? #? NAME #? clock-total.awk - reformat output of cloc and add column "total %" #? #? SYNOPSIS #? make cloc.csv | clock-total.awk #? cloc --csv file ... | clock-total.awk #? cloc --csv file ... | awk -f clock-total.awk #? #? DESCRIPTION #? Formats output of "cloc --csv files ..." same ways as cloc itself. It #? adds the new column "total %" which contains the ratio of code lines #? per language. #? #? VERSION #? @(#) cloc-total.awk 1.4 21/11/08 13:15:02 #? #? AUTHOR #? 12. January 2021 Achim Hoffmann #? # ----------------------------------------------------------------------------- BEGIN { FS = ","; l = 1; } /^ *#/ { comments[c++] = $0; next; } # comment lines from cloc /^ *$/ { next; } # empty lines from cloc /^files/{ next; } # header line from cloc /SUM/ { cnt=$1; sum=$NF; } { types[l++] = $2; files[$2] = $1; # print files[$2]; blank[$2] = $3; commt[$2] = $4; lines[$2] = $5; if ($2 !~ /SUM/) { mycnt += $1; mysum += $NF; } } END { l = "#-------------+------+---------+-------+------------+-------------"; print l; printf("# %-12s\t%5s\t%7s\t%7s\t%12s\t%s\n", "Language", "files", "total %", "blank %", "comment %", "code lines"); print l; for (idx in types) { lang = types[idx] total = sprintf("%2.2f", lines[lang] / sum * 100); if ("SUM" == lang) { print l;} printf(" %-12s\t%5s\t%7s\t%7s\t%12s\t%7s\n", lang, files[lang], total, blank[lang], commt[lang], lines[lang]); } print l; if (mycnt != cnt || mysum != sum) { print "# mismatch calculated vs. reported numbers:" printf("# calculated cnt %6d vs. reported cnt %6d\n", mycnt, cnt); printf("# calculated sum %6d vs. reported SUM %6d\n", mysum, sum); } if (0 /dev/null if [ $? != 0 ]; then echo "**ERROR: $osaft failed; exit" && exit 2 fi echo echo -n "# " && date echo "# $SID" echo -n "# o-saft.pl +VERSION: " && $osaft +VERSION --norc echo -n "# System (uname -a): " && uname -s -v -r -m -o echo -n "# Perl (perl -v): " && perl -v|grep This echo "#" echo "# testing with target: \$host = $host" # dummy to load modules and alocate memory, otherwise first test results are misleading $osaft +check localhost --trace --user >/dev/null 2>&1 t="%U %S %E %P %Kk %Mk" # format for time, improved by following awk 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 #dbx# echo "$txt #" echo -n "o-saft.pl $txt" && $time --quiet -f "$t" $osaft $cmd 2>&1 >/dev/null \ | awk '{printf"%5s %5s %8s %4s %3s %7s\n",$1,$2,$3,$4,$5,$6}' # awk is just for pretty printing # NOTE: --exit=BEGIN0 is some kind of minimal (perl) resources # NOTE: time writes on tty, hence redirect to STDOUT, the final # >/dev/null at end handles output from $osaft, crazy ... 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-22.11.22/t/test-bunt.pl.txt000077500000000000000000000025451433765727300164270ustar00rootroot00000000000000#!/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.

    [ ޲1}&#*u;Jͨ4/h}CUK*<(9]ת%P5>N~jgwSNY i`]OTeqb_U>Иun/lmFq.pօ"AĨdxp.2xϲ)NVe4Z6Vv:z ՎN1J +vsF,̅tYes.+9ĶLrCJ^ <9>ȇ#S^MkC o&I}c" 5O,+[qc;nGncvq tB*)$I.K܏.p~S0'+IrKSQ@pY`{;K2 :~^*6j2FQ!p_`A,5)-[ULsg݊Ūd\NK9)JK;K6tpY_t!AI41W ^]_'fHVU4]ȯ)\%VmY?k ^bbԓmj˚Q#4s2iYvf@-ScݝsI۠s!: }JbX=et`PԷ^|r{רJJ&0V9o9N >! h_=zs#Q9Iw)/@L&û}lSP&"bKL*2]g*> 'szZ͒(|p`1㌬tvk}}ڳatdb>Am$okDG(uG ݹ/|Uѱ­,ZD-6*=њΏƀGI{5Q{SG̓ؕB.ͱ k!ϓ DW&CpSz5e!7gN(!\Lk֤(s@q(u9G\$ J&yȵCH;ӭ)J8nS_׵|Tuu|W7Rf3ɹҪNH햲^;P5|˫JTR5e,;AInWTQ.kt)S0o~_rNQ.-gFO~_j?9rNe# 弳f\T\gJmH$ ҉9U)n!, +?;R\M)pTqB.]@-b452cR5I0gkk24#UyT9s\LY*'b*(ƚ_sUKlc)Wۑ몄Bw_Jv|R eiRK͏! MZXho!ͱ@=|T_i:MQ~+Kfk<"sw F{zvwg_ʷ>p,\.2)Ko.+qTTch]d@"M$63wʶUQb{NQ9?yC)n)^$Bqn8`t;[5-з  +7EYG}dt櫪@$9)jG<1˜֎M/Aa;F%3Qo"MI6_-`tXru.(5 в| w!~̼ mF&,]3[gXnSSVIF|y1.PyvߪZdLM%>S!ͱNe5p~}툮^@IS]6M0Y2T4ER.>=)p5-wB8c!Gu'3#P@,浇ǖwϺQwGj~蝖 iCp"]hE!2Fm.%ml(ite:hSu=DA?j*y{%?TKŽLC_1aky(7ؘ;a6skߨd-Ύ|}:ȚoϾk9(NI>OtU ]' 3c2" [y[IkQtH LwLdH_Kt!&0JB t 5Uw>ooE[uyҷ,:IH|n@A@QDZ \; ;&=]a"T I`{p>l޾qA籂L0m(A;GW,k mt$8$˔ð \a p.HXCKeFFpl^v[~kGG|]F$} vH6Dĭt[2ˉ,$rA@wQ[Pܺ>}z%b2@m\P=z}cEC67) `"h(ۨw֙gd)x,hh=@y p`yt,*,T_~P|Bgw+|كwG >H:o(No).i= 7|{ZИgcu[Ɩvat }`lkNw>0v4i}`<0Ϻ㙆x}~5Ƌxa00^v_K 㥁х{j]m}`0{ݽ0 }`kFۻ30u;w? /?!@ym¸[TSzma>^qlx4w݃Cu^{z'CNp{mGvnY@!>d 3w2do*؝} vp촿|ʃ ݋?@Žhq^Φc<Ū?4= } _?1z?|@ap( M_Jz?^ӿߎ[>TxvtriƱΈ;c&x^/Cs0`}DzdXq(IOCc1郧4nIh > ֖ͣ pVM6ֽz{.xۺEV_L;ng;V{c ̏!xQT͹mÖwo-uZV(pb5N!o/h/ķ4 a`i3@73Ag "O M |ۥsg{Yso*LH_h?yLŖ+p]Nakl;ԫ2CDfwQvw ,ٝȯ|07m OW_wez/CE/ek": m DA$QCh!zR^q;fD:TBuVWzwvpY2Wz/ܴ).ĒC2۫z\J.}Ae(qga*9;{T3 T7z/ h%~ ( "TDL;9OI^X)⹅!BWp;|(yyYƇ_ݲR< SS1 PsE ѿX[dt/UD/λ j-8dTII݇'ol<Ƨ9Y wb2H]r*v: `.A y3uA&᱕pzjܪjfȎK8k|mAˋOEY\^2CV`yX]zu]zC*jR\\eX\w.b悁][u>V5n(ȝ{=*@G qA ^ Kd\#M2>|oYSAvmxȈ<ոe6m22lz{E'47%g.(ߥ+eQq] u?~'"w$|qOOG+[~W4mu?޿?NK8ջP^4;:x6u!~e]y;_7^ɀ{׍W2c~f1ogjd>ZC(]S|Gyˣ)|ﰎ/`rvru\"BV9K,?\W%M~ {˨;b_Iz}:%W1'B !OCwNfNʐ9;L|:tUg%w{KƸ^~_~ؒmp>ze"PQR^[}޳_(*H!*4bL/%vH,qR%Y]V%~IP,qzRx VB] IX JyWRʍ8”*^P8J# Z9=orz`|9=n~g\\d'ǽ%NM9:|+bxr/ѹ_t: 2x v N).E$\OK!a9H#YM#;!C#>:50~_D" }U sY | 2µQ8]" H9qX+Uy)`ДrpW9I ̑p[<,"tղnP#X K:ק/7m?d{gkH[;{g},C[t)ɖ#lnnZpC+ edK#-YFF Sc+GWfE6[4n ƾ0XBBWKAM1 J|g> NIJ Mq} UQ*;r>|m/mQ`q^t^Wɗ;".B孹Ї5Z w-\{](Yg+ zdz=rE|zKosѣ"hQ .a86 _YČ ?^pw˰0졁O0W GC!V!#ZН(<)]vev?xyB2RxW48[@DdٴND۠tSA,DA'yk`AKxpAoyVkAKpݠہujH+jvq`@ꏵt# 워Z6VoE fv .>ZVoE r+e#5mGv)ZGWDb$흲+v)ZlFK~}<]HQq{n͂pi^;uPj.ۭ尝a)Nlwvf|@k,Aoޔ.b 8d3(ւZ]&0*\؋ t{? 0.F{ JYZ^2@&9_F/WºlMAXD".ŎraPBcحؗWЈK|mmu>(t/.;+`/ל+}]^>f(%h;} ew- _[eglQUNE[GTF?e\(@86ZLSrUȦPfXNnD.1{fBQA 03zJ@^Yk,EF-rrabcA;S$cՈ\Zшܵ{lu-W;SW:sK&ny+Dƅ;ҹ[2u\UGϤ >yҶTX!MWa%`}etAAVhn9]Eu|}jv/SDkdZ[X +!IJv|f WcOQ-Ng+H,)*0!={XQo'C۳&⋐$>JDi8:ATN = H d.ֻ*l,l J&]lΐV\*l|l"^+[uv+ /|;! _~)?xR;0xZُ+[!5*4p `+e^)d.zGGF\W79;ʢrS=җKWڀG !_6qcoa|s /–ZUpІW9gChG[8HV%c]y\ْ:Χ2ϐZ԰1ЅwAk fش!@B b/K3T<[^>pKT6pW|+4pV|+2`BUinꑆsohkjV G[8|+p/g0Weܵś)w*AcGW?WP@p.aIyVbL`Wy]*,sbVi{yS2KU̲:h0ʲY)> X=d$YBT~}" ce!08Z=p1qE ?)X,We8q8;OKbII1Z8^ \ܽjڎwb0W=Dd=tա iɈuĤG'`O\uԁ+5Ep>֩܅ZV(d4YqJQJaI`04JlHP2X} ŞTY C޼O Q99ssϩ ѥ OsvJK3\XtRE1'-raj9b/"pMTI|k:^ޣ#A { IntĿ5DKI?<AGPR@I]"2̂g]aޮ؍P2e(*8NrgϞ>UUp{?p𡅩 ΞsM pd&XTY8$}WnސSY8 GKq,Z7(] ^׬_>(˖텷n>~w08bh^.‡08*;E=XQOERí`AW.FwvQQy1(g_$Az|){cۻ{;>ytn,9[h\B ~GE툡| hN߷=OLl\`w:0Mv=]RgIQ͋BEp${hxq<zMUh,6J;UuItS8YN>5ݩ pb2|% b@rUcp|+.\K%EL(LE0U¨ h(JYTLe1'ƃ ? \رPyag]y_`Qj!_Q+aj!_a`qja-+ݽju$#B^njյVTU8ܧjcuW<-{QEݲ 诱B'J,ʫm k*{l#UtJ[֟MX֟}Uʫ+m.*ukO,$lBlI}pV$` ^UK0f._٘{rP` W@!~ ;8>5ԙL"TxOy .Ԋ+"FJh*H+" !|c{phæuɤ6tnو??}&=k_ʂr0ƂKM [/Eܱȃxyca謊k/^*˺\,2`^C_6 {v~*JwzzKjwPz'Ԕ*3SWF>l9?O絇Ur I>MI1}/Wy: ^%f|Ϸ=hHgY[|U.OE'z?Od#=|ȠDh3jE7x:MfQ>y4Ϣx2%NN8'ʉ1uu }HGC"͓*',M|;I>Mn8uHb~qp!խ`F4_m̳,xv@涞¿(iͳyd4ql:OF0rZ7k{:M&К{ LDy2Zu ;̢ Jnb4 D7W<at@5;k^u2;rE:|}'D>K.|>۝ǗW0nT ZlAݤ[@x:kXvߝ ugDQy伏u:&uВ1y"=fIzp?"Há9bO&ͨ`w]ΙF~w*> ~*!kHx_#ŖShּ4&}GLsCb` şިg^^-8((|:hd[]<m!E?=Ԝē;`JϒQ`~إ_fj-y~ $ Xoo w rtD: ME8V 4d6p1qNo،$-fm?(faE* oш==pwB}2r쵁fuDŽۨϓѝ5w[Dp|kYxX (Õ!>>qΝlPlI㆕шNS>3XHd+&oT/:\M4;O|%ß!-]yY:}G{"XБ#Z0}[Ʉ$S& pim~zo#%꛿$Y·ףǓlȼh #p6 ޷.M2p3<(ןޒ)vE6!G OӟPûfRv:Ռ@.tq4!~aڢk{9k{[ azqPE Bu[@ykY7<>9AF$yCmh>_^8n&f\UD=JVr;e)u~׊s2w04AN76l* \BRW Zqȫy>]'Zn2 9[yp/?•0=a$'ЭcOH~QnŧH%"%SEP'%*3?I @d%uwݏЋ^79O6J:P"ܬ$J ;M ƠtbN#(^B11̪·438"qYC:ܼ "G=* 7`M՟2h_(jeH45q:@E=^gA Kbtxgm5ubs*dD~@(2) h ,g X1'ЉR 7v/l`ҵtyxYWt,zY? N>ڋ0%m㷗{?NűyuLI l&PMdؐ.EB`43aV?6»[Kwa+C,93)T'X>PJ4hX{ o%GXa 4wjFMExmN~ 1rXYK·;)Ҋt]5, `'(RK4d#Zz?M)@՟FU.cYy4⌱Bs@ ؀(_ :ƾ_, \M3hzQoΜ9\,1}wH/MT@ƴ٢.)j% ցxK^r,<:H?z}fVAp.&2N4Iʡu+` +?VF6zvn7N~<<:h\[ ,;r8_kUBjhgkGy U~V+i馶NOOwt=ژhY&hCag8h0 >"Tdg sGLYBKRToa5UJ&]'d6Kxg LQD7z{p`jĢƦlRiamCϰoba4qѧ lBca(f;|"K#_?Mg9W ^[fAp,aF> el-II1#>u(%5-][b9e;j jJ20TޭŞ~D{w2b^@7Dq吝_6~O?S" X06e~.Ɓ<9,09O4mS$r,i8>8}%L1" u x[ؐ$]~/M2;3rϽQ.$?I Hx?5S? Qy{z#HURsAz3W0d ,N%$?tnO1woJVĖv @vi{%3uϽyF ?KMfC)es!w]6Yj_dgRoz:JxWp p~4pkZ6h8$z%oTB&!zQav9gRTa#jf9KoSZ:*2!$ $(coDuk.J%{CU#TqXx~*ކQW= OMpBf\V,O^{A2U16 Í?-:"lV=WqcxzVT(ןJmYSZPž1wA 9C;wGl#1v]&<q&BًCX8#\_& ٚƓG^AxC1^iWʝ)[rvwg#%hfADrsm'IJgz.{yW^nlGM~&aVDO^8'@Ab}'I &[FWva)k!+XrRڢ iAAH/ZWAMG˅vKA0(_$t"Vupр[JKS1ub,8SŝK1N&l#.N|Fʬo J|NC& 7' hՑ1י@P-qOࡤ F+(d^8V^i~Fa;G[5rMɣraLrG S1Fk _<ܷݿRPB rPT56ӔQHk:U5͚4C2OL0 =Of]\,40!x^o\>ۈ7q}LJMȩO*Wq7K(2b\,??X"TOV`nV}*>"͛ e>7t?`q;EȇO߭U[/ր]VM tjQ>*QpDAGLeXȓJ2g>" I@bc飌*pWVǽ'Q2cDbL ˨TA(DM{~l4 v-:vِWlj{BN9%nubݗ+ NJ0`| I7uTe++`{9&k =.vsEa2ҡXxקtӑr*#Ve%w@thϖd'IRY@ہɢ'^ԑXG3Oct1,:i֮gc঳.E)4LBͤ;%6bɺ]2ϊA+j@ |%r1婚/& #{(Ǩ{8xՐ1,TӺֳB|'~ѨDC]X,_|+iz系s%+؋$t6^_OFwi^LYiGuc=Pfap`ƖΊ<SNV )%`D7¿ʲ0xZc/mI:Zc'1ݦ]05Lr0hK~hTۑ`n_g1 5vf܁J@ GX/75B Yy(SeiEPgfNbA{ggD1tV:e/ޢ-Z4Qew'#zM6z]@8 r(=h'/A?̃rᢊu/Rg>1| W G`MM&.ekYE&L1.8S%k̴)lnq`8ERg srOE%7P N+S:=_Crҝ6ۃ|S%׫h`/ .ӱ)eML~X%bU&OQLz,["Kn~)\/ƠŮYkM+bEc0DcRVR/Ϥ˪D 9I S+~OKut6b Iӕ0$"Ȩߒ9Ą)gy@HFVpdCGzDVba(DT~WR^q>T@[SrE׮hDyNqy;LC*DT'ؕBlץtC3ш`%O~kwܠ%Yek;:eEkd{%{_)SHbv5E٬?Ӓ=H!כ83ѐGAEO #XDօhꚺ%Cv JW-IOnDjpM%1,`R w t_Q ,Y6,||0n&S肃SH^ 3Ʌ39 ߅s}']ͨ\b̈́ȷi02)T_;]DɜN.q5B9#ٻۃܺ\D!u$Sr@ BuJj=\Q7P !qqZu/mrv-4ot@*(SFa=[$ .G q%=FV$cT9͓="aaɷ u Q?nZakt3!WƯ J* @j:d'qB:DtBeO6ՠ9HeH m6n $"J}"7r4 Ƹ`G}hTZFlS+zk#㨃t&Da4' [WFnz+`{%K+'M!(V3]-VZ \TߒoEث>+ʧDo %7?:Qέ] 3NXIJXi]J8"80bLajc|,fɭšz`0"Ia=ccM3ᦰ&hEQo<3WzxU-s ~C'm, ˬ4n֞P2mu^>bQk6ӍŭR^Je D mL?=.y%m+=Ci^/in~w[_3F?.RV"}!n7X=;{.S֞ixYf1L BȥB&_;*6b#kSq8MM(/'W6ICXκ@4۔$h1CBF⟃>3+D=hb-_C=<>ۍey5ɉ"Y{u#Z7tYD;"M5}|x'Qb(Uy^MlTNW$D7F 6i<~LqeԽ܌"rvF( @ wEQ|C~/ޅ;JvysJe{b_Z]{F5єҲrvʽTuﳫzsؕGtYr'&Ep t:kw+l,߸dLb#PtCU;rtכA X#ԉi6GogwP>%?qW.W8GC<څgwB#j8my=6K6,f!V%K<9G,~v ܚ+\cU}kڹ c8 WJրdXNNݓǧ^mJ[ae6UBEף[9Ƀ:ސffi9·MK˪, S8eKI-^%˗##px(USUf|I]~uSHLDeCquDS=G>@qy7娚 ^: 뻯p|v tc dÎyvk!tn D~dzlשmnnOf;[~7z<}P1Nt~sj?s}wr&PT\k2|lFMQce z=<~,g3YL-}shT1.>?l!OFJOV,&`/ȒN?oK[Ge^U>rvgnɎ9#T@综23~,-{Smmol{[mAGd[rl3"I-9v++@YdyIqmiP)ڑY0n|J^(w"~ߑ]f܌dFݿX>Inǩ& E IQ 7l6sa $i5m]m@pG8F0ͯvO_I >](mOP^bh5_KPBhio ptf?6P`_-d|b/}W,F]:a } 0 :gh*xa`(C["Xq@왝+4PCaR2Ri#ǃSaPc-4RF`va#\9}BGArC8u;؛٭-T"v[DBcc[%sN5ѣX 2x(WVTb,$7J 9}CN_j+. ^ᩐ.m ;g]w <`O$6裴n0^_֋$74<1912'9o쌂ŃHW(xDPg+x|vqNr9VܞB"Dsҧ"\{ 3}%n1,B[ؕg TQG+[e:J~M`#G] 'g#凵_8&H܄á[hIQ~Uבx-&N'm&p²CZ[#KJ̒ 82RJDvҡ1MݥH"[[^CBф6 QGV jD·TϭhofLrWBD[ʊd'R .9 B+Anzz鿸i%ay'%➩mg*<{ s.0AwA0]tn%.A8 ex)N\k3,G:h#k궕Hmw<^F$#9BVNmm;kºLiQi\L+}DDNyeaqd^2H˻S:8KᘝQ!Fˣ|-PڥP-[,k`?2SܨwyB5_yv V:' d*`&.tDΪd&cP`c4`VɐJBTIKkދ̠{-5^Koơq)"^Wdhp|7=uie_A{7; 2{^^}Zo|7|8 |o~0閴5 Ueª* MxAVwr0A)rNPOEFs 7Kx|a%zX*T1ϱbafy<,fWu[IdѬ 8q:emy^U+,,kPɛ}2MYp5d^J΃II>g)e.qy4_]vKw&Y m\ A?=yʸd1s a>:LzVQdzguHyI̓}D#׺S"le1 tM]j.ԭF^2z 4"/)ꊿBAm|4pN[R*Y1}xsd?"za9c#\N3.h/:*ɡ}uQn!okm~XgYr\vҘFx!Yޝ9:PZkكsWMn!ʁSJ@P9Ϲ\weu .(%v:C9r.(b~Qȭf߇J``"uSzUaQj:`xu>}sF"UYt8_Zj$dHIpK%3V] e#Z%_9 71˫~8+*iGcxΪcS"rvf $A2&^`%Q^Ay8AeoԀRŢB$lȽ;gGIA l1Ҕ3ϟWXǞ&e=ՕiaO\g  cԤ[=P(ߛy @-Yt(_D ߸2t={v׸ &W6&+:LO5'*z)马 ]Є &W'-3eHd.e^{3+)G #42TUg'1#^oREQm#Q%kK$;gS8{:;CqH*$*> 6QINX-gi+QvYA94r1r\yN&.K'xYCWzM.Mхg_ ⽪r藕LdMT$tSsGNw봺Ws? {D;iW@$w$W'Z@ϐ O9 i88TX8ͭ}GֻpxQhvo;)O}Kk~kJd}t^ܷRPn` c:5?ϓӽgnfykݍ'hT+N,pO!yׁ=R: t:<̻y @dJ5Vio_GBxG1U$Bx,5)ez hṰ#.n jEwrOB`Co^iwf1 =uC J!䓛0@f -;5Ȯ" LIYNF.3'5;M ը<e1dI{Y[\Zñ,?\Vfy,&e՘Ed4ȸsZVt}VH%_!q(Ыk_wޛ{@鿴hNMvu{c]^&*XS'|ۼ$9 O?yml¯~pB숝7Aa8K2>O(/R8ŎNCOEѮvL@j.R% (B'I,~'?'ʤdãamIPQkװy&7G@-M~/6j`+ 2qAq,!a6iZ Iu01 ċ'|seB]6(s<.RB{ !u72;糉Cޝԩob ZzvŧIOMy OSY˝aN$[wft2@c#t(x##>q:XD¼69zrsU<i ҧI *:9ģJ|htHIO?N ph:'Ŭ>vwYѬ%┋]Y;x75Ev~'|T3!_2Gh6 Qyjm{?~C4_'{?\˪Zg]U/wC2217 X=*py=f$~8miEXr eOteE"m*TEi6QMM*XswҾ2<TWLh4NG_ox:wvN"ag~~W]Z-q=HaRΦ 3OhM]bAIPHMM'(5^Ma]Vp'wtQSpwvNU?9q7q`ҮI-ŝx;u;˜,4L7NBQt/SO!i?ʻ_- d4(~mF[ ް딬Zxx(As(SѡtT"< ,=G@ 7TSviX餷>>@9߅_s~BW#W^ߩ O96&嬾_iZ]|6e*ΰ6Ǹ 윇oOסv/y O/`l{r7dڃGlnJ1(xBA_q 84`nZ \;:ceLz6g\[FA7 K6 žFfדI;uPr,C`h牣- JUaNf#6uZO(+ǺXZ‡/IxMl9H}VYT9LpF`hr@Ct@.0 ,T|7UIjp&7#fd y1:(bـWD+NȺWc<x_WXdU 2V3h&;\\e#0ӊ=[]GfdDbROԓ?qG~ !vر,l4 UjlM0H ywi {-B zh-`EcAcqxGq @<μ$M* zmQ1 8:OcQ~#G}}B GN9:hpA@zco{>ʸIVNR^@DG{rkLqYC|^'wydu(E`j0YyL~vڝicG`GI6gddI;/k*)r)qݚ1,k&<bo:]%G)fIh&ȸ1}m)I'Z_F8r- <;QXa܁iU]47 tE?B%Z],^iNb:lhri}w»vxہ$Ymw^8$(}&e{?_3W_ PtnrrM۳?~:;~}|8;hi}: UDa_y~\w'yfMn05uj`rr?$A#7mPrW^h <f>uhz2dzWso2_&9mg33@dg찂fuPAqN9tPAqN9uPAqNyL O~oCj߶HH%so,S(ǫƼ2U;xLX? DN$㍿ nMX{zƻ hDdd5_v{qK܌\+wB<ƘFy*؂ r4؏:hʌ{AfPlipCī d-YVS5V^$@ iĤ2 4dAH?πe@IZ.d-Y cuZNBz /9ZHb ?c`%_^H`1(^Na `,`?Od\Zx? F/2\Ne@vc|)]^p~r# -&ǩ;"g^Ůh}A?Tƍ ,TS<6f\1$)q%nrNWO+ícVvag8)rIFIny]/xY+ѧ<ƽVJ!*)~U^+c f* 3^`Ozc˱0܊5dD[RB<;RkHQIm32VDr`=\kYOڻNjf@bhѳ!o (ǎ7zvTUimM{c4mx*iy PX&  Y8GH I@%"b#lR ^j@jqK;ReN ފǂth$07ȿd%Fy:T;"p|(ΔKeܧBiUqv>@0 ˬ dfeP8 dK$Zd1T)N^"ugtYcy iK0k3x lU ͸G=vO*5E QeGC6Sm1StZHÚ>)֊T2 y)wT6ၻK|0i%UdF0Y _BnS§}΋;ɭ:Š^oOȅِ|T;D>e |yEgڗ=CMg#8©=#Qˑ:~zgwi/pU68< 2V7k3a{8).$_`߳8nFg w> Xӎt{v;]"*:{A(F!I8'_4_I=YZ.0X//zXmsPҹCjҹ/*ܛ:w0/A ږkT^dtwNm;tpϠ R!n،MS6P3NroJE ijJ*Vn^ݴrHQ-+Ŋ6NmHe xZV٨;CKXZBU ]cthܸtr;=/g.0,[e#G gܵ<(7Hѐ ӹ빹q@e7RahaO {s͝״#;bKPj9E!#$fY#*9֞>##У+skIkTH/dĥn)|g}c40W@e'dR-ɳׯ[GܯX7[؝~Q۾Pdf p~uYGRL>GL/7tP{ۦ#~8Z:-VUrMXB[f~21~klXx:|τq?_g6`nuwFh!>fWkyګCzMâח[/]BՇ& lnRA8\ KIR"dKĔ|q7 ayȧ?1">Rk߷U V9l*'~}a qR E6x\ y(4Jk-p60f%XAwk1OfM-&ٳlO:&˯kBsU]ho<띗xWU;2}/>onn*`ie%IIzީt btֵBa$w#Uvfw];, lf?̐Hᝩ͹={d|uT9$Uxm|[ W石[s˜=~(XA{{mvҟ :KFr@NV.6w 5.$~7U%=\}6 nw.?Jd̛Ǿ\I뇥Jra~v?_cF\iq<&%oY# ZѲ) ` o[~,znv _&HKKc%ֿ(1 \DDI@f[Sy.  I OQ7(0}k%$ѯ>E$V|ߧӿߐ/^ڕ'S^Fx)XC}(??ɘ;/ G6 =+zS\t"ԬYf}9fS͏a]M*=9RooUљ׬}H@ @j)8lgd{H#\2:L3d+U9 .VVs2 ͙ Rlx8Ok2ĥƦ <ROk2ġر׬ff$kLdy [.ȶ3d; Ŏ}A%A2~.45asH- Q LbY͔2 bIsc(6!7g+hT9i axCyd$斗Ƈ~.keIAxQxL({j#xa|HYf ne!vٯyvaK^^ f /?^RPH#50c|QÌ Crm_|1xa|H]ך[ˏ^UM/>_~0>AR3Ɨ/Ff/?^RoU_|1xQ|L]nzj|a#c|s'^:c7'ry$>naC t8`/$V(*"]E) R>*¼95daš_ڜ6da9m}s 5gF++lsNaޗ) e%u.O B6ɸBU䎲3YD,]%Uwiy}S_ӳUC8 #4rQO퉵l#Vf/*/e[/} Wg+P=| voyI H$vBÓ7qI :2btP? pl H+( % Z{WvQP|~B8pj8rE=ݰd_ jX]XSdm b,SƩN eӲWx#_EZhc俕JE5r6`Vcʕ_ 7`qk2'C28 ?GxpLRcD BvGpGoX_=*mS4\qb0r4R`04_;ht CE+G̃&|<ޱX#F{/MfȻλO~ Ktj#E;00&JLӹLx ^N9`146Z8*6w!t&#v0ވA-À O[wv>%+н_; >$uAɡ̫3(Xj;wVK^!p NR rz% ,}c\:\SU@vLx`Isf;%%=ce AT;16M mkGݐCL/٩{M*v.zqk6Z3<3\5dσX&Y$+n|T<ٕrQzUR:q$WjkXx˄H⣞rF0iƣ2AH Z^Y?V6*F]X?3.`_݂3A3~_m0>#g l}N }Qy{k8lc?~*WW4Xu5*B;\z&-ŸYNYb86~*-[z+u]:/Nky^~O|@iu Tq'Z|M>9.__I&(ܲ\hxrg{G~__ܳNuqlճ,t͂n_A h4t C2.D(Ό/462FU4xdNH`&t1/e$zߎ9&<ƗfF7<3ݟa#>KNiЉL\s1&ƗMVر8L!sJ,]iT`YP*mP_<>С;LQ_Dơ c\ϔR7t't=T\O/Ɵog_;\bE.:{t?{A;괿?tHVO7 dvr2v= >&|aiϓA̴h0_ǹ]N' ?(Sj{0kڐ 0yGeBYuM4Ӎy/" /(]ef?toq*g1Ro,XDmv۟fioou;3Q,[nLԂIgь1]G$b`<1eTg/%ogU9` *Ŷ=w>YK5nQudZdu&:^z-~w&9 tuYS4':;F.S[=q;#Ȉ/9Ue+g + (g)erua6$y(1.9{*^QJы_n?4oZPP\'WӋ a??۾mUwO lEK ΐ h=ZzXP{1kpF,_ smv8:[>80`2Q -3powVƣ|Q7-fZ.dAzyE}6X^[kl /A-YGy͒/ej]K9ZrL$evuvJ,X,wC>C"9Rwwm*^Q7,<bU~svN`J@{QH~x,/gPX»Emg0W>cv{G?گoa˛Wŋ >aJ1Q e1cz{Wlۆ{z iy@07baB6G^8ɶ Z9<$Q*.;67tasQļ? .`8y51WB?8oLj# c@A7C n.H{%sYO\0;#)"M\W:fVǾ59!3X(6s&ɰ2] IuAĝyB2t =u ]~bq Mx|:׀6-oۃׂ^ WA~{M0< 0< 0jU=?$,݈w%=Jq _l6JzX>}C_>C?>C?>s ƪykVAX5F 0jQ`^-<vCu(֡:[bPlCu(֡:[bPo@o@o@o@o@o@o@oBO`av 7Ώڢ 5$vMo!/ ZpЮ Ѩ sf&|p̘ۜqFj;BRF*񠗶3Ʉ\P%rA; cp9 !t~^ [[8I&(d1*EZ5T-)|4߂M|_^0'fsoW:-?bޭn6/ 0Zw X01!40 _Qt"1aʋC'};jCe2пS 뵃^_9fMe4q<ˍaxot>]V&׃U.6Z$ m MYݾ_C ~bFQoja,ch2opDw!܏t(P >-cWQ#XUHyÏI!CJcv7bޠQ-k]r*H8Q*fJ*MBtS&]H?QwG/;).Z/2^_`C2'ȬS2nIwlNQkO4z7ży u\fhgM&1ϺL>cc)I?4W J+J9| -mR&.1@%7d) '=+q}'';=ߜeBCHAܰcÆg o~Ú|ӧ0 ((|"C"^œ`Yz" ;*߉Z byKa,vÕˊȴX : @z{;P!ܲiR>{ىX(59udbx/l|WgVo4MIj[u ו%fm"L]TB;]TB;ҽ{vfGIcs1!tJ=Pت֭.s#nU٩&mU٩nlU7eq-^ gR"ݖ=vD>L (\׸VyiThƫ0G6RZ$.j'ӬR:x2. D 蘁ؐ"%@l*/f"B-/dZs.^}"`V^K4) WZ7,Z8zyQ6,%%hR2>ʠls5X8^ Ɩ `d&qd{3 dn%uXIՒ&JT^*ưTE؇]~8~{SFkM?^n$Yɚ^n%3 rTgj4^ h>1!LHN<]hrF2*5UF1*Wa׭7[l~nmt ٹ "?3_9#910GY9٨flTegYY[$g=+g}y9P.BDQ\& ;`l_NZː~Ro򵸋O(lb4DT|s2Kr#ԑY/Y|Rr{SACc6l~aη .qós!. Aݿj-Y\l̹3?jDk>x5,CB xZūjʧ$x nM0^KY.̚7Ru|{o;57T7R <<]PHUs)$"<|3^[ n1Uo--h XԒ_[2S3^][~,QoXݒ_Y隻3-VsHsR$b5N;3t5K"-9F7KqEf | ʡ\mnɸNە/Hȅ'e5N`~eZ76lͨ;{E v`>$b-B$x-"5FǦ͘Rג ܀'b3o,  gڳyBkhXݕZ}wړzpHZk53J!}=Ū &gjȻִc3LB9GX@BBpWr|p#]XRRS`6b^O&oZskUVmD7wEwL?+#xbo=SypfIM6xKM$6Fc^v ᧥ܝt^Rn@- b_ t)y%W<UO[fkY~mc(.^7<wKÀ7-M ^Ohǟ /mRj^O`T'T?[RH%Ϡzr@5pxZof-[|+ -A/K9kz~Rk) Ӭ}F[44Ӕ/<ĆO6Ӕ/<ĆO6Ӕ͛w4_z8WiGM3z 􁪲JF^eR.Sf%g2Rsz9֎=d}! !.Sm& mXg?;XP˚ --qah5Ul? 5,e{L>͞X݂'孜Y|ZW2~X:a7ژCV}q><WvIY%?*yBtٯYo\0L8GdgU¦C΋A?;?oak륌w#9D(͇]b0&\ |it`.I0a ] _PEtVAnjFv&1mTi(@D_QZAy LՖ*oq yU]@=iBKfEGHL4饅 tA>4^Ht\)lfĜRnB_.zv@̎Kxh7Yc2_%J::1ʄ;/p3VĽn>ok(EQZ b0&Zx[UL ={sE3d<>0*g0G;\ϻIV6.FƠ7qO ݳH|!Zá$x 4C-V. \}ѿg#Z4 /ao0 LK@: Q(wakЇ=Q `';ha  `@`BOk?W:VFU&8I"DOz\עH@ v8k:kujwNuUp8h/YV̵1DbɸwtׁC4*&9e2SnY;khn{<@ qlsj=v~;*Ry0`AZ.@n]̰ф"4H"B zO\l#ޜ(7V^sA]}"7s̅B'8iFm2 ͟ESYbYEsb.CyxW@ۺN4GAMpsp;!@ϻ}` & \L'a9 gewpGϞݪ-F2 s`^Zs?ggW(nɇжfN0þyBm6,f2) \'ǐ^j={Rwi<'1`W Ӂ4*n!vx8!ql G:_53wsgǖDYͰ?o< &Srm\lHL0 mKj$n_tVM~sОQ(bNΞ*%b/SQ'@/N'q.Rn=t82H,,~08b=wf\Őn]P sIv-CyM|8 0u3:l3x&\< É$`a< (C'Mq4=lǁTS?V:\Yh682D;,u۳A^=ln#hs*C(P 7V:>ޱL̘ B]$.j17{PtEfbEn؅\2Z)5\\wýWϪdꆼQ\6SCgFiSMOi4XJLA2{}젲g^_KXz R IRœ:fb Q,k zUS105l۟UK y KT\ZT# IGdtxyj",2;N48@i@+ѵ^qD9S *ovɭy*و?(YzRGbNǡ0j>`Tv6P=RsE,i<17`]kiD!r+(|Fɶ/E: ]&޵z-q`8 f&*Pup"[mNqPߣ$YZ|9mZ9?{3fu/;Kuп*Pȷ(fDCա:p\> zA.ЯY&Q8 Ba0tlJU-i}2/ c05@ˉ+ wڤ)+]&(YT#(PLrArK%Q{CTZ^Q=#}Neīު˫". <~%z !~FɃBh#nBZb-)V 5,:uUhH:2 o42Iu<"17hGR0`?G`dn@Oeham-:a1~)O{Iyaq PbRZ+#㷸uHմyշp;&]Қ4mؙH Kp񃱼a|_o1"VUwaӶB8{ұ&\l"W&H\Ahl>X4M\xS5i"JM & /-Lm^L/,Sȵ0̊h[.۝&Yq^2S3dt{w5'&H!/dOPmGIeECL324&2""9uf 8fsZt$oa5HIhDuI0JYfuOh2fZsHSC/@*Ƞ5>SOgO¢9_Iޓ%qr|R+'g%_??>9q =˽'MaHn7k,5 8 '_ЩqC㫀9=1b;jИ$|.($6mz${FϜ΀e3![ @!`vVPqڤer̲ɈTSXK"l`%5x(aŠ A%8C,n" Ųj"l:+_?I %CDIXŷCpƷZH!Y-w`/[-;MFq;J.VѬBC6ƾ{uB(EotwW/݆We?5Зz/e41@!(Q~ ?F9V2k Qa 4bf$#~l<@_)hG^Op A1_qiH:B#!7H>6n[p~($lnd 8Ri VwƕL惸2y 3vlClZ6L]"DM`'50Ca7B3ocf 1AyH/rU}nAP@ K 5]Sb-u^^ȶ$ΝȹTl0:tJb͜س>2e1rA4_ߘ{l1/j(sZ^L"uÆ7P( 2HPU[ |N!vA+g)Fb5=aR)s+S<b( %T:B_L=eUK;E,w렒>g8MoPkxox+j[ڍlk,n^J5 tU@s3@84®cMx9TX濞oM"n>øȬlbA!rO~pXknS)RLL&Yl[W)SN穄 kg!HHp @eYjw'O;OP EWUEDU>mUW!cuv\L DBH?V bpCHe<{ƕ`C H\"p Zndl7Rm2=t5oq{0ccmЉcKv%q뼋>QW&%u2T:ߒEŁ}7zPq¤A $# Gû4.`YZH"tZ;xyY"ص_Qb,uV[E'?<Ȃ(b2hBN~Lk7?<ˏioi"*'Zq=S׋<$b*t{aXb-7-B$q/$q:=8 ?;[JR־,"řg{9Ru Dpvu-UIl2F6ߦ{>dfzDB oX}ܑ5|t:y=}g*hڈ0Y };b#mDTȌkn ndHvڠ^lMă|vv/68Mu%(Z \Hf !p+Uܐ74U+rKm&`0:5lmӥlm?c)R뙥@c<c N<})_R Bk3 >jmx}NWYnJ:t좽uRRcJk@?oŃ lp(x*sZ(Ac$A:ԲJeR{P)AKŠT)RgRbF)bR<# X%ּӓ<Wi fԳ{E5{{P?hp9Eٚ,U6H2;A51& >8]<Q 2bu?$vP"ׇ эKF7٠=W}TůsAv7_ up_H_Ee4_/-Kx/x@'Tm/OQ&鼈^ o쾸#>ZT^FoZ>/B\픭uAUO~%A gԳ$ X01aapwJ% h l(dy'"60#%2BMz+X8t\ځ-7g qeij@IB` >xd6 ŶA@;;[zKX5$5S4hVعzmFudl)Lǻ}jz;9Xs%֏U[C8}T0zJ/teն\r#c8Ax>~(N5Q ]m~/*yG[!Kv0DlT(34:KSTe) ѯkvZ^ސQݽVaxt])«9F ]zC2xZ" 1toQ)FdL[;-Ʋ4CϊnM| 9{YC5M/sn [؉Qŋ7^ yp}k3XΛXAu~-;Nj3rf@N[{g-ݵA+/:%;]7g0d8_{h ۬m.M/˨!!+wќ$Zwķ↗h=ygR$JIp?eVϼ/Q%,.7z rzPEȧQ;`!=_: +ƊnDɖ:>oTF/TZ,%ɐ2<4"KkJ#X H+Xh̚ݴ)h_ț)Vg7~,;qnUKݷ׬u>UTR=}'A}@5*dnಫ[L)GhxNJy& ׵4u/p-]keH"9af|(~=dUdoo}&t5->l7!9բCe6l8_IkZWXzS H=\džsjuj55,V=;vƂh;&ؐ=Nľ6:x76Hb $>}Z߿x&pBqM(͍`70y[=3ޜ'W9M~_m-5byeYljm(kUb%z@<dy)hM.,! .6T-t)^TbϚʮ[L=!P͵t67Uy0"m96 =~cDkDfKo6b{6־PX=tun`JSSYk<{WmX,9%צu{~|Y'_.<ޫuwk{fu\c7ަom܃J|ﭽbE>Mٙ+e ~v,FRf- ?Q!7烙_Ұj~9 a%Oz1T'cmzQ+Uヶe@Z+1hN:_2`THB}&(ܯ;E){U26'm2ZliQt7R/]U2&.ynK UUu@oNvKX{l[-gNיΝ>ܩV?9=+VGRet;A}9LQ،Uer x8־Ͼ(019n"כ5+,`ϒ!Kv&^[$m7g~Moΰ|>o f3|۶/~|[zLfm%pß[ :'Bf39WOx;$·O z_CsovÏbALj4=rF+Z HCmZ3=շ/ٷBBU'0p^`6aۗh:F6ym˻Ѕ1V=s`*~.AHUJIEFA5 ?Y6]d4N'Y:% Cx)a'q!k+C6*"a/=iwF㸒nD!3 kBܭ;ҥO6:r #`)uQ&m;.U@NaJHNo!\wOT tB<]j]n/ȧRd@-l`4+ଡ଼w2 2ǟ;UKT{2؃ex[=5:h'C(W`4XGW-xx~vIH8#KR"'toYmOᐑ.oT,K4XFFu>ofa%;baqц-j3ݸM!gK iRA?Y;,zT\djD<5[8޶t.jjx,KIG:Јޅn(ݬP̳bOx_Ez bw#h8nGe_!ҹQ#`S]tZa]8\Ðg ^f/ /viPdi7MzڶJs~>SXyHOXw/Wq5q r^A v,zitџ잾Uw kDҦS>˕Yfݬu0qh kYWG7S_ѵ[(5?hC^QZ/ yDI(!$#;-Vg^7~CLv[Ȟ!\R-Q'QqOZ][K&E5D&H,Xcĕ͔6WBeub$=H\J̟݉ι{7S稱2bK(%ٲ"2 uji0jD[eL_[Rԕ-묏sDJ/YLV)&zM酳>;[i[#z,l #oURJ#@ [˂ `]c26T~+DPv:Q[>A.~nߏ?=חRJ bSiV{Tbz0]'w[%F_-$/,vLJBn'dC>qQ}@46;?\qhp\\Pq'w$1+Y -GmnsҲJz?lfl ^ 1":(?~Ŗ^/%,Pdўƴ'sYP%% i-9ٛPtG3V/} P4VHGZu/Ad Q5c80S̥NC&q 6][/Y{3_\$d 1 nK2{1Zt]gO W[bw9 7xjꇲ2B5iЙ̺*\A%nj/Ps֚\v_ d+4OuX!|BwF2rƀ<MI=2`G]c[ zpݝ{)lhSJ A3Z NF2~7gL/t11 RϦ/jƴȑ{ʣV'3u\ɺr9sd"8V ʍLlK4HkngKi$?/y:/+%B7xtX-Wȶ/S޵bwDvN%0<-o㓦B d" m6 LV`-4Xrj(}D`r/A0:2αM|􇼡]dNH[ŠT8\[̦7mlI=??4gx=vb";WA4nejy4O˺BHy$UY3U@a/7u/1)c$c SKrhNU8Z?(ǫ @q񻥢&@&,^]ӠC QF,U,@l$]fwq\/SQ,iD_K`|L\8[8,sThY~faudlBχ fX5,;)ZՋIKMSM1nl/ /k0xmX{|˧!Ggb0}bWLЕʎT`df(4;3I`J nNW_au ,>qVϪsq7.]Ķb܊9F?z?{hauY%gx1<삯Ց XoKVz Vy&a9սa)QI"j;ARhnUukѡN/8v}2'8NNW?ƃEc"N#֬GEcbFcaeWJ8tp;0 )uhP*]Q>d3P903mͺ1:mFc4k]ͪI踍3O[ggGJ4[ͅi3/kҒ/=so 01s}R0 $(>H?8M蒻ҙkv-2Eƃ$!l<+?ۧB2-_mh4rdsd%߱ :}+q;P$Ts>ń$2ߌIp^۸+oJ6<.z8Ƨ.j3C+G:Ɋ[HʊF[r֯`z=ו|#8ĂhGRT&pB''\. \l=$:M򍓠A؃-ț%] ?O(5n$RkG:ZxCQ*Oԅ~0"i?z{0_@/|Ze`'EʁA xvGΉ餷U0G@Pz#Q|$ &df>Ζ2l.fпBM#,@wu4u K_1^ЕM7tW}UX&!y ^pZ6$,3 tCEt (M8.q,?(]RbW]{ѫhxeH'%UlwGx3UoeJOv}[D;FvZy[#w *&LQmUo˜b7쳸R[:,9;:O~J$o0UINeGIO1ThX'+*OEA=UNAr6hfu>L)痎 ZhIFf+iE1 )YbO5+.%qylÑ5n dP$Tѕ$ϧ!Ί0s>kthMg2#}X%q/o"ˋ'3y !q_"x4 2k?/͋<#+vJEērDQBӇ5`F%i-$0h2Cu<@6^imip'yJEĥr^),)d/*(#xfoS#5R7@ 4`{ڄA} |0: B]e,{JUr=%e7){tطl1codJ*1V%uT9*a( b ?-^)Zmk ;}s:,y3`XWea`xͷ톲FWHt8-ȀM2 B6!0bjvP,R0%HijYNHygY:̃})tǔ񀜌R0y~}yU<9Q+ 0zB΅ 8;&}~mg`P`&@]_6t]g) m<:<^f0.s=5i ؃jC{Fl45ѹT| :w :&YRض嬥`or: Yj7)`l_O{SLF&=y{;L#=-꾕 c^AYp Ovr/_Plt9SvCxaǵq֭֮uP3OPi)޼~:# ھ'!UKvmvnXCu 畼s[d8/L*k\` Vanʎ[B@1qԋdi(>hQ{q5;?;i Q<6M&c PzG# C[ݰgK_ Sl-̇vIgΟǮĴ$!-QM:{d CD:M" /*;L'}X%*Z9}ps}l+\wL ȼPl >bIo`6cu|ɼ:b#wXy#MJ!K"Ky{}۠7MnQF9ûYnuoj 9]E&N_z%Dxٺ(t2rpZDxDzc">kKM("rhMx.II]:Lv( :ٕFA̳W I.DT*w s˱1֍Fr/:E§a]k(JtD"^CPb&D*G,be,( s|)m;e9lÎXvS:Ŏppn>9}:jp|~wRыcMo~Q/>F Gx1NFqumPn|(0!@?`M A^ht Kro: 8,HY|Zʾț.Bd[ ty=>]dn?W<%3 !*˿KvϐQ:X"Q՛q{1.0Ї1Ӯa E3n(cC -fx+Ny ::u$-?p`GmXJ f,eDb\ q,NH'v)$:ٱQ(fyS;feew)=4YX“ْhڰ4{-^8iIN0.΁!I%;Fɏ4-S?:XUq0 Uu;.,X ,Ht=!WN4i`Rzl/<.H<F /I$P_)gg.DwKg8CI&D/ҁ_.fwi}E1Գ{${ .=:"Ⱥ DŽ챰S[d}ٗ='a@iwЅ7)1?]1vC~\^M'~=Ϥ{^SHzOw崹ǜIc L}x|p=z TW 4tL Q6CR1tۖ={7hлG {g{?΢rФ˘ٓo;0w84^(r߶Ԙ) gf:}ҍٵwS|/(6Ȳ3??\u:.BkBϯf9'9Z{İ-aZ9hXa,0JV0pBk|#Y+މ*~B8,EeW~)}m~^Q/c0߂ Ս3[#$oME/,^ J?;xy=xv%:۠xgv~@Jl'SEEz6y޴#Z/MG0Bx_9]sV!&`vQWw|PbJo\;h4"ih =<_ksqǸw< PoοfHutU:moȲ*ek^ OBD iKAzvZY^(p)_>8۳u(Q4$)9Ne:udVɹH% Jn9ܭ'8W7^կ?[W!wI0[7P=/Ns{z[{.4*M" ?" hn6tH x(-^ n_Pi>[m~N9""<Ak8 ]Qa+-,,Y ,, ~rVQk-CA_{^|r=[hĎ`Ⴁ ؑ089*,9?>[#_ߚn>!YsRgg{gg{G{Դ{6$h yF!oZGvZ5ɧr%+xަ4wx$ d@T'}^;oݿu%c(7^]1'Lh#!yxvN~A: ۜ}P]Y&:7ev& Fw',; #ـhPm3gDvK-uU'3"'S0svpN?fpp8q ͓C+>z?|[7:P}j`-~Yzgi?W^ ݿ:}tY` hKSF?aùع+%7`?[?ϳwjLlt;)Q1(VM><8JN2Aݓ|ޣkAߙ> >8$%’P*@'%W*O*̪VtOxDb_j+wmjuhZ;:9grY짍cd[(kV!';A_!p]}OpKiz=;iΪI+ qVMV.V'n!Aa c$&WP ^M0}w4ъ^@D.b ,fĨ=Gz}|Xm)l_* h_=ZH]OuB\BRK<ۡt GZkC3Rԕ,ūURtfb_wKgvU,ϱ8iS'x*9V 9#:G>YT;Pz00~? ]d17қDњwR 5Tk[>HE\%9_SFnCb[蓑'YsS}oPV@1d;B K@xrqvMjEҝ*95N.5J.- !/'"XҢadJ/ϲnpCH ; ?6"C JG"G(n(A_!G"C|: T7\&#=79y!K5x" W"F֯wvY?\zw#̻d4 '@ҸU],HEk`s4[8cCJgH ohdR=ZOi݃ }Eʉ ԘZ G<99/++MQ~?s1 V.xP$kRԺ"nKY3lj)||VB@F"MQ=c-8 GsuYO*A eC4;ߓr L[}℔@O^%wyd ed)H!%;%0ۃ$)Qs6N;~]~gP<K6dCZ]"0I~4׵@܉=66yP+%pmupģ)GGu6.y&#X .C27g//ɓ<|fMYIE>w(ӓGDX/GNF)Tp{5f"N0E1] 2SeFd:`jjkVJ =|]|W/ &})?FD;:J!?#* M>jx}+T]d)wݰ?ѕv jԣE>c΋iQ`S.RL MQ(Ar\Bp!zSQhss-QE+'˜MF#9]Xf z=qJⲂƵ" ȹAsyxנW44@x -i[/iP գ_(q@_/Jċy!4ɛsϜïQ a_bU7֝Y=qTMr9C,?hmah2Fkݓzf kpv~:>[aA-NKoEU//iNGVz"£F?x]YeimO_q= ƙ ąK-]=' ❡pU`9_Gܒ7oG\Yѯ:BmeѫT6h5V@; 4ffM3?vJDuAɓE[ėNxIJ:ğC(z؜9i 䪉r)n4ooxkܿlkhtjB-~^s݉@+͚}ۍ^=_ѠO~TգkI>;8U *3_w6Z s1L&ƛUql*ȬJ&@@LHS63+B~u@&Y! !G,j$-zaF~0qI+jYe w( Yu)9r/q׊%4S;~zR628[.՝2؉.#H g2jg2 >>oIL:?)/A4Iאַʤ3{V2D-DG)pt-  VfVr_ Cvѵh'ׅ a]C\^A5TS$t@^N2 B*·)3@)3$Ȕ$1SfH_h P,3E!:Ǽ*eֈν<fR0-^IË~䘰h$ a*o:˕TICY+T6GD0挍L`耈}R=^kK/^bv NƇ_t톷pIUͽ P'JQAK+$^*cvMߜ%_ڑ0MLJ'rYj"bIayQE@= 3yWhAI}׽`"^P7fIv5y]&[s}xA%Qء,OdMDK(,Uqy/+bOY>M_[c/݈+jMetg-_b.[}=.n/V^ Yd4,ɈI|tPJEGyf8W22%qxș%/>YnE$?G0qVJg"0Ƭ=aR;hD.%3o j*>.)%y'ȶ($rPpzw*Oi vvhD8LMuNZNK'9\s:Z2!Klw^rjGOAbKCw}4k̙x40R@X8^DY؜= tQ98 8؏FC0[r#HǧMbF:}x##f!6;3yK~> ըv!뜄`P+"M•'m̨g1-kN't:}xknX>B`&ç/->p$t\oApȂ4 6O 2SNP|O:zl͖mX@mN!wb _jLMj~Z*ypD} idBفMU?a_fw-@6i|=T0o[?J;jw];?Z2OxT l#=it.Rb/N|&0;Рs~{$\)A*o:X5:6islz&0rΥc[~-؈vq4ACʅ$Fґi6M!n5 rG[N&,X>z128%k0vsBEV4<{M7"W46o"1Mc-5 uyHtw$s_nzXA=)|kaT>pTˉ4 ›.ԭ CD l%}~ȋPNO1C2l*+6EF`hYbȓO)yw3>tJ r!v]I~w1&J}[CӮaH ifF1vů$g_\ &I/p:%0dG׆߲GO+O>Vƨ>A}"<>ˉS'D ɰ{&(Wha@; "myNᔟu|Yk,e>$u2(˾5ƫuIa˪0 a0m[{5׫229vV]5`r 7|dݰdvq_`]H `pU KrzqYPJ8-ɲ{5؄s) O 0VMl_ <@ܛ^Wԭ{gVH/29mR#ej׵m"*޿,y|}lA/InIH, n nxnM!T m3WqseI==Vcʌյ WP):$Y6׊ TN4,9܇ S,MV{Bu>rtUլfR 7fVQQ\6D58\ 15ہvD H';Djlj()慎boO AP2㖣P(GD0FFN@Z9.Oi >ZNnNW 0l8-ΥL4 Yq`k=%*ך+ (UrR}3 ,6,JuN,ˉ[" 4|m-,#! E2U"oS׽< a["y>Ǚ&Z^DFɣ6i$f) qÓܗ-:yfWJ("_1H\?z}}s W[b8'xv7,SVUhUp7Fۍ-"xmg1 Hpb녱yD%MVW&K^E_bhFxW4YѬh0\fdɬQW/Q_eXz\Tæ+@>?xANRCI&LP=dJكу;[,LS %҄߃B"BEV%r-ܢpj5ܐ~ у5UY`Nl™PXd9z /)'ZrE r!rR{%稤fYh!Ih@C,L;!-y$RmfY6 \˦A7]4>|՟W%O@Zula%ʡ$7,F#gἙ [/lۀ0]?;>} |zdDc±&gr/r(H #ut/΂WJ:tAf6uER.x]m1\Z:NOi<) L}%xM嘮j:6Pj؄ 飊_ ZHP^Štڣ6j3؝3ڕ\Z,L@;O ILzt?1p1zVק,N#[g%X W,i'6'~ćI|'i ~Љ_6,Ї;IKSvN'}$+q\MN!ɦx8̏9>&=19^ KYTpy1NdSu{>keY7R)O9S=Rv*kT6'lF#ɴowe^By+S Ae.Ab٤GyB2FDiKN[^r?4@J'N)dJT I;"$^R9( T q$H%m&ֵxqU-y9 S-nnņ -ʋNRo0U&/|Sבp?+LꝲfK(ҏd)vw/+ LS 0,ЖF!Xߥv [ xQ/tI]~.4[ǧ'(Cg~MdLB73~׮?<+N݆I qY^6qh$=B&{L3Xq2?UOTW36k2<]B2hWS OҒdXFPJseYH@Îufegj$<nk{u{6KKJ}[ԫjZ] ^:=n)6Aw+^ ` %ѿDoȊo $bhC01zsZeo$‘%^R2_kccߪznkZmjkk[[[-Q7Q|h+ĿE7YNN*lh*ǢB?*&wCGD:EZyJYN7*_{<+G<:FXb~{_a N'xBUqe@D?9!м2x(bEK@ '.K1#DLm#<=UaD^KL]{q >&-w & ~aHl.͡ ^*4G6 cc!zprkFɁ`pmn{2БhcDlV"zWKhe}h4è˞9mdo;v8D*Hc]:3lmmG T}8)eg_乂-۵L OawvLNhmmI_З NHd Q+gGdrǵ-\$_Y7 QBSadǒFUv)"nrZ\`f ƙ3TA!MGGk8!7(G'cH oE%ϨWe/mҙZizB>] }HHLQ{kQbG+MOZܠq61O l婈WdLFL'o* J2 lS9bk5QhKcbgb¾`=1W$ʘ2Дcu^yD"# v͆eCǨăt+B V}նrcbu؞^ GqL- hH0 ACݶ~㐧B-rV'&:I;l٣BqL)}Dx^5|Hv 1ޓ_!( UӼEB9mVp1q'M8^&{y~p/|# Xxqtnp0RB =S)4yB|x: x‘& 3]ARf? t VVM3*^JY RFy)ӖTȤJR:_O4l O^@.+/ CeQFAcϢ5[ tAp}%txw#'` .pw0JgƬ Аѧק %D Dm4*$D EGj5JtO^<$EkI[4[2t3$6 Hq 1uPS>cYBMzT , [磕ޡ zhN!W{x )Êspq᫲eU {2T)A 9d51Z65&d.oPKOC "װb1/Hri0(IcgS0&k_A0&PFCw h@JIeR8v)-1RҀqA0iɥ^ 5t@ ZQ>U \7倉MtzNd a U;2DN7>O#x&1jʙ p^[B7֓+:KۈdH[`-O ʛh^Ôar:'!ۘhh['I)͒B!uB`yd7oE!8qGeN`Gq< S 916uDθ]qo`U$Ϧ§=Zq'i!ׇ ?<(sf!3EɨB! PTq+Ѕ3-!>s%k]V̭BU 1B:q1|\EGvJfգAw=}Qꝫ圳[jSC]Ex1szeB>LsX\FM9:nΤ6"'Q )#ûG 3(A668Qr qXAIW } 9O#odGZeUlln*|: !5_^.tKj 6؃&VMqqxy@=]m G@K{8GHV驻L̵pJ 8FKo67ZD]83ٳ,q`4T趒)iB2n4Gw|ϔ\Ž-c АKHNXVCK rǸ|DDyY[ SN;;ګ# u>OX [DRIVVyV)(ӳ+^~t ]閦+̥sB.p{ sUZ,x% 0U,#:ԺwҍGAn/!Id"YP 2C,%}" ?hCXd +Iٰ6 \|tL)v@y'CX N9ɱDΟu7`avf>W DY,2%|'p1ATgN߱P6^e;ڠ@ PXax[;E Hwr27Uj)<J\*Kf(TZ>M!cLLO%@"pNҸYM:Ƃu_jYBb lXO=H`6&4%if֞E'v$˯t)cìANױXg'HOuWk'j5Еrkug*exiħ1$:#%TpE!5:99glPNz W O{1\.̺;G:DCA/ښTK516K]*qPGj{Q[TcԶ<д͑M&Qh+=S& F kw9ƽ8) 0%H ѵmPau5pN.M}ԅٕЁVQ) cU j F8|XIɥp,HMXxV0;%l{R btmW=1f̟ f]PrR"+^8(OIY$ŗ~tO=6% "<oe 8nUmWT1־K))ǹD }<ŨdPKqB5J@֗ jY1/pjT`$wZg\_ޜ-=Ȑ^98kF=d> q=+Z7_tM>YI\^NqDs)Y%(cDWWKv U\%J]^$+I..i ĂK qqI }+'_&|-+ TZ\#^ ?SR=ƾB%~&qv~uG-V]+pvnP1oϜLpjewi<8<@ (bnF^np=ۤ$FeRtKDcx/c:n6nyXkHP+@G\d>/iJ@ ZoRQP\q:(#B9!?ΡSU/!i&Jnx;RP;g *B9\Z !B@%xO8/ɣDY/Y8ϻ*^m@W;M7\!Wf@'p68s"j_wKZ;Oitu3-C v\`\L6Z]K@Kmf\o"Qz;9q#rrE7p1z]K: N;U[,ڟ{oocꊥG[,t,ci&Tv@-s[1^~ݨ sxJ+4H ͬ#&F30-CTHAaE^!Omo$Ju5#\uPL|)myNبKØGŞ"uϟes ]O]Ej1 ae; m嘆ܿ}y>9>*/cīßmB"xMG )Dӎwf6yhH6A/bP%F}]{V^ڞOv] &IN&YIn;\NYQK>:>p6BϭLK`>䬞-j_?AFm<:fUumVZJl\9jZ없4XN~M66,ndjgk]]xEm+m|?aX糓P?.6ʗ\'QrufҦOΘD+~UE~䟩μDZL6atL+Eơܑ>^Kxsyj|Kux3[* \bu%HYT4N5^LWWiBS\(\K|bug@Fdi^:= igMP:zQIBkt!7&Z{TɄlް:/i+։z*i$^G׸H @yvIk:M(ibAtP Í>"FGu=| dģU$Gួ rܘaeI<*T7Z%fɛ"$:%.PqGVX %|O&@ {ħche AĄ >%N?Q>y8Wb䘇Z&}&sGޓ҉A=iuG7$ޤ?6=;=&oڪ{-]BEBo}rkTF%!){Z`uNoM"uݦe-Z  aS^PW6pfh/61:IUFѶ}Ztghi:qi]YThcDq M;Icfl͒n;yݷFI 3YP:.%yMM0>ޟk`5][ݻLv+& l/S†>\Ƒ5dV>Űqya0!hmXY4H@GR?\n ܕ`!o}f0yO9x.0VUb6߅m3Uۜ'.pukCLL.V3-]~R+oDyf ڮϘy|xo.{?;%y/#Ssz2neY͟QTC ,[y?<׷ѝ;uߍ1jQD>O׽(^[T;-;RԻl;rMn 7fھoR2imo;_$7./z]k8mέo[Kyk2.u< R_8IkUۃSͶ6Cps' ZގWݛ9C"WqZk\@ޟ[4&a5؟ztkύ/˃Xp}]T. /Vj~aX^l9]9[/fM(拃/C!jf\4NaV ƆpLk&]3 =Db/I2G#U].f3Q D?IY9NRx*N4\WkZʵR2ޯJѠLK?kCGu:P@sD*W8ta}Uk*Zvԟ}T8˴Yd 3\c<:ʔШ'B.((S²EQy|\)gA/S\:ڛLR$+(2,͚]fg<æ ڇ3?)s"dkjF7r}A"!eV\ʼnVFc<~!pϧRjAp$<:eqv&q$|*B7᤾lMYZ:Z2b;taO[YgTsvk%^4˾@/2l:l IK&d6ImMM "HR|+Ixl= k߰=Y M*c7#?#1uYNنC61 T0[Eu cO86isis,ܡMSl9* ! U@ MLtog雳f.{ɺ?Qi&s} FCd&>892W+=¡R Ӹ.Ni¦%ODq9{Jy t1HGԯVKŝ[mxvQO2F3@E(cAv숞Xu~kTΘ:;9h̒[QFqpXpJQnExET1DPEDtw/Lːb9Gi&YEV?/j>/d2g= r23]#3XV]Bk}57Qh\ d`/rXEs]SHobZkL,otC4q^M:LHN4ӗ:n]+n*[uI6ţ]6PܮSーr VG4*|Ҭ_v`j_ӂh{v-`nꔲk(m֜40ԇ29q9]0Ɲʊl+W~$t[l? Y@ɋ2+!ա7!l#X]H3zg:0]M'L%V.;}_8"OGN}Yo% =)SHJ.1O;VoV q8ƨ.uXOi əhE]>wywcY.G3xaϫ|>04y>P:%~5t[D{u,`ԍSn/Z}eXx~Nvޣ+$-*=O,{o< T`j T(0G -Y:֒xʤD%f"KؤM%] #z2j:kJ@&؜b(9ZzQ-lmsW93.V钁*\V[Ю{ABsV|!Izc3[`KF0ocbxIcF(/·™?S*|aޠ3!uw]#$o?GIb b HbZWq] k1Ue$#Sةǽn,BT^A (b5y#=G1p|N_N_\[V}|~y:<8k_f(˃߀I"ym į2^n5h!tfDס׀ȋs?eqyx?[ҀBvu>|}/ Dh؁#Dq }ݡ xtp(ͮ<ՠE&֗1zīxy~ԶpQfGC$[E;}a?(CӕY3]ɰU' Ji zePv㷰^O(F̂c:%t O \FsA\R!LAW%E5h’FT"'4} ^(ၵvq#YZH^ӱ-oxraUXscs|SE(u͚JyW@\[`LP,r|f *tkv ΂a}̋?oQ)Wͽa T9+zJ 2?0(RɛQ|Bijd'Si,aL^Q2N8J$ĘFbn3Vd1.9:{kA"*j%F|諾LoK-3ՄIh+M *<?X{akw❘VY=Il`̚%xR{NhƊ*))@#XgyVڣP1O` DBy'!S񘫒G{Z8&ue@7O>_Z6QHcSH?V/psӐ {GE3{ˇh$ۧeU Z/-iV֫֫CKR@EvI>/hQ36{XB/AI/ԗg46KRt' ]_}`t:7 S%3p~k rכZJ2c9e Fٔ%kwބ,p0ЍqJaTK3ӭhKu/P!sTF*Tn=Mw?A(ݽj=i_A W^|W,wP!.!ؕE 57aLPܨ^ _hxhl?ѴRe20Ew-Xe.NNF2!zC|j^\]QrjCBv'҂ /{$T}Wp%]iEy)H*[Vtb_HS\-m4lv0~;a.ERjZJJryM5#%B0g퉸*Iw30e|M)cq5ĊJ ͂G)}܆͌OlZ3> jy|F}] =g|o:uzd+w#gQ HUy2p̼kY郓F]YQyu dg7U\m/O :l'+{=Q3Y/Fu($yxh"bC'# em-,U5 xN.Ro>Q}`@O?:݇T =B ZDʌK[?qB17ۥGv$bqW2ٚ*h@t?0jMMJr [C`ַ%sb&"bibCGg[ψ~>%Joe 8'c#'0uyQLX-슥\?#E|ȉ*m1N_hz*onm F*KS{R8A7Υ@w6aG՞UW؞y9@N@mh/3iBHJj% 0t>!)LB/DN:&Eff'VK˰sehAc\sH2۟NŐEX ƔAv>g0=(Lo/1jql]E D&+=)HE'{o0Y4|˩fm*H< IYKԡ>~ޯ}p~'i q[3 7! ә1 .,bBͧP{+59s)=:(ʰaq fD)ԕ$<,;% z3#]J g-%6F]Q* wYCֵ~ކiNQ:z%tai@:*Q PHjG3|L/ P: ?k w0o+Qq傘\g=Mm/充bw!o@Z||'n+=U(qYSyO6R%%`Ȃs+(aE()0+wv- 4 ?w,O\X>y,?̞1VC ZE+%E7[#=y}Al ɧNhʭOqʭQ>@{xPa C[ś:ƅٙǤE ꐠ ABΞt9HF0H-n|(kQ:L?ΧN2 XY=|QBlNYTawL| ;$>Cdw M/ KAg:]-DP2*QכAIhkR}t|_9It_To'oEI/d4v^N'uVڤ)0dܚ^ o3`>-'5lL (Av.-[A`0^uoqu&b*!19zy?ǫK5W5vUo_y/+~a+t]՗I]v"+P[uqknuMG7b^}Kquխ.B<-,ɍG6_[xQ{F]PPIpD/&·9$Z__K%u-,椠:̫TNKÅkUÌ+p<C0*hM\Ddf I0 >q K}qC?{!tP<1&O fh^Z`u^`C n(1inI|a&nJ ;idGޥXvLMcg3z>2?ځ=3xq7~d8| G/br~1*9~t:|2"D^dT~aTH92VZ7vX8 %0Cv:>ډQgJǩK}uB_S^:b Q5ׁصSNŧsٞXh,=BPh~"% s8;8tH5Y9(%E R2*)kcoHoi#op MY=;~*)wYJPD~扩 @~zۮ@zMg!£irSJҩ&Ezémϛ}*B꺐,rǐ%g'MyIIEmmѪى3bgYĎR@!o,BjXblq2Xta>{|bh!d$O $?^}>cӫ>^u>=6{Y$!gҲHͧ5T1f'|jbC0QΫu 1Nw ѵgĂg`f gj͟V,zc%ӷs(Ag@/C>ܡ3i\^B[I)B;Fdw0{ʀF ƪ`C7DE& n%ڌ+gWĪR5b<"+)dW2飗fYeSV Q<su QF~$~GtT0L)i:YlT:6(G}|?0 sV!zbHkɞ@_l OpnEuW΅ÏHӸM=h%0>Ex%"A τJp06>,1Ƿ#8{&'gyqG"vcI }㈎1Bf/)J 7Q(?F{F\ϛ˻9p[74Om8$QK{W_8}Y7¢x&j!EH ]Cvmzt k3B?)Kxa9d~+H <0(F"ks*= dM: YuBd= })@,ez˜Ul0d(ٵ9d׾lݢKwAAV_C UMQdks־l}]Cvdv1{YlGvmٵGN?o9do'ceAG:f<|pUL(mfyJ̳-s 2Lo"7PE7ד"A ̀bxOGMkĊZ`Hˬ.D6 > /" )g NRȷgܬ9)oy~}>?Cm} +mek8M̥/h,92gͬ#3Lm2 f/yb]Wٲz+W@bȵGR}0[Q7k͓gSr1Wtu*(/. b9"]@znx҉#,&,v$@p91i`?2wBl7A5$a!j K)h qt=P_+gimwz뽝N*..fޠ-tN&t+ߙ[l'@6W;Lx8aRK\MԀ0EZgQH y[rUP'A9IC7ۙ03 j.c&x6`&2#2GN|+(6!$7M@\4gPtzRAST}U7CX4D$829z6|E%\oIewv-c@yT|gGYXL*6FZ?y𦄾fh6_t4TxhgM ^_GJ]SV'eE8lq9vo~S/"C j5$<$3[Uz:un~P]C]'MVDDX/^( NFeiΣ0Mpb|^.2\ʬp̾d.ǃtrJ7F{:-4#>G/uqtfwX0 GǧrAWm ly >$$`-rE)8v Zr3wv-6'w5&JĒU!@wywh|0&5L=􈘦QIJU IZb^AYnlzogq/dKZ^Wr_&$ՠA[ndsDsm`OH~ir|qN%e=<$'R1_B ,[APlKPʆDX1,n`S`rIlr@^$.t}z׶,k]Up|f ٸ$1*xG2P7u)ˆa0&JpE /-8N: -rֆhA Ef8~zF8%wƚJjHĽ$[>!F#ooZv?=y??߰w?J]{TjX3R/?O Bꢵ.K(VJmi5Va-dNQz2ձ|^ ge}[jr)vri)bEk'5I.ISrL[c\ꆜ B).1_ · mUe z鸤uU}3&nL] }DM\-ɮWXNr{Lb;/_]F Ypbn9:[`3^tv&σ_y:>="G!7؞* DG`ÏxuO$Z~ H#RKIij[t H H1Y V 2s׋6ԪUU_IX)}2qx|yn5/_4ϛKIE6|m<8>HKH4JY[V'2Fa\D ]nt=JCỤʛmUaK2+nD}(C@3I*?b\A~WD KWK0Y $*t3hjkͯ CFTާj ql Ar)#IYw÷hhUk0+9QMO7'$Į 6(K(o+u\]t;^OWv괪HD)ۀg%+r&m<7^f$@di dծQ^b.RZ@2~\J_]ŃǷSЙ2>g =64\4졇 ">% ziz)8o?z9G9jɡ: h'I l.X v*֓Ri q Mkƫ[qh@,AqP{ZVN;v?ڠtֲȚU$]r]K=!U{Tz7DZy#N+0WVjdu%v!91r0liia"H|_5㻸3K6;cn5݃ql6@ꬄ$7ӹ7b?!Ċ,/~ӛ/Z}U!hv1YNm^?Ŋ=ـ]l:hA(I`Hsq\.lhtn#~_@૗u_G DW%ؙ%ǡu1,@bN'M_޿tnZ/7+3g#^BNj&N?[v;!Wa 9bfeNhm!c)f2ƾvvrp]&79;d藋7g.!doJ$JAV bFUz$Vj*j^ݘqdh(Y`Z@H\dLdiC:ac-lP5O?78I|VϴsbnϣG4y;5uX!hUͦ`؏V`>x:D/'j#,/'زOSO 6)\`V xX^޵H/9L*$/A#.JucuAy>Q[#7dihAi&F]S?qhjh(i:B rbWx?O5m=Nư`FÌǮBH%=ڦw} 7vhz1;d_Wk]5Ʋ8Dfb7Dh`=/K(qfIsJ$'V+#MG+snOfCl/{@,In"OkZXZߔe`(QE7a=XE5=(̅み?fTJf;L2;"}d9o` o5VnWWS݁J* 9 BBmM9 &YhiXor9uIF1_lӢ{]ꐉЗo0%ԥ_.+.F[rr:0m#3pepR>-NX~?%ݫ֨d2ć#k%X;gEB E>b]YܴY͗'Z%󬂰XY#@K)BeG/T?Ҁ՞4( eeU4 d1(?!(1t 6清ҡ3¹ o@N0j)˕G_ca8U55tɵ2H瑉_Q$uIH.qv& oQ2lk oqYUL:hLiYEGV,:1ot9{ AGйC'ꐬaI"5JV4M +dHria2sSB!pLC>2%ZEҏQV( 5&YH/a<jZmhVaD4gTeoئMR!c$pLTzPt˹1rw+N:'&ĺxj8x~ɡ@qu4i$Dns!4cah>@d%FX-4 _!ʧ&fi0PBhщ{b34IH=c-1ˌ)hXQ+`_oT.{cN#:^] _gXmcV_4}@ /ӗ)wqZxD _09nn)Tk4T e3:eыX䏤W *b=2C1Ļ]\C,#!{xS b yF bxDo Fxt}Eŏ E3G,33+jT dC>ffY73"kl/ق˲<,H` <=~/q#6V1:N‚ iqIK7.{mi;郥l F2)O@I\9 w9@X93uʓ`/w[spǤhOߕգZzdUUш'Z ,8Q۽6_p8Od"z)|RN%(NJCKVՙ+O[by)j[ZiL7(j.!K\L@'4/}\#& ?:w՛ QƩA N-jɈҞwIy}cKRXr]RmtzU}hN/QS@ђt)er;Ӓ6LZ)\$ʩgHFYf5) ll!2'c9dLy`r.W+H$@Q;yR9Sb:v*ѯuRPL( a@2EQ}h7rRC`IgTycbo?fʨ aCy";j6M0kdգSw?RPN3.:Kj\ xg/@X Wc $oQ`9 ^YLYiȒ@1!@Riu5sp/\aNе?Dc4IP coGӤ- ߳\E%j?@(%lJ㇃ԫb=Ixw-Cڤ=Jr?2{YPc62EI3 J - KUYԈte:b/ڕnCY\ C֩ $dJNéԪ߲hF4|4`Pb)ZTY-h|X>D!}o'#<-ze P@Cq'_> —S!GMHeGQ-Nw<./+S[ ^:<HK#93PkʋkhuRt/#a݊]W 즭G tc*).aq%7j&w>{> jܨmyj2k[hQ&lrv|˓f^k*=?r9092  ?J–`js&0n(в)f& PQ{ɰZ 9-ԩ0M8βh 3z,!>i/]W8;4r6jǒ4=z'ESsC0*}n8lLOCAfJ`J{C RZ(ɜ~ٝR:ao@/Ya+A&~+N>șt6]uL@`;d_# $}n$1P ,-? sQ2~('(ORgq+juEP[_&ն;HBS:epp8+KW"P;kamjkuzJm/uleҊӃׯ'oGL?#}.fsit!0KmB-`SF}tp.`k=S9P6T !u-c،uUk91ZH;ؽ |?g T[(KUFZ7ѸX"}E$=`XZ:| (%8C%j(uw/Ҋaoۥh=ڟ+7l&al5.^y~n5_hÉyD6Z+Qnnɸ68UjMG9ʏj_J¶P7n_^> {h󽷃#U3@b gQxnm:0V{k6/:J} n5KM6Pʩ\@y0,hR.e' ݒymŃӃj.qYJuʏb{}tf(J>={|C%j>dkWZڐ<"fb>0ĒRy6X(|֠^2c2RTAtk7Fw7(\{I/2:`@)T*m7:lKN!2Xgm^g2a7 *L8ݒʸ%Ye .vD+T"V CL҄'+iep483 :,ZCmdM+>JI98) h@RՖ6{.=/kg}}rܺ6lw6fm7M)ᑗ) VT{L, oM<=+ꛗ*Q^*R &cNB{r-ˬu9CKirvFk8 ; ?{8P^CƟʈdJr>>B<"HPfB!V%4[;5~AWA/ A»X I˔ISsgBqGLjmV| @Mk_Z)|֚c ڽyWr #8]*=s8b';x(}A}bSښ,B;";["9-&GS@WĨ`?{kF#~kY=Z.02WtmމKgB=!8tu6,mwKR_ ZMT ,};Dz&`G,^GOhQT3l,!Kt~PMOP=ZI;n_wN2lfdDZ(D&Sfqv3j;\6cT6f,)VG|ޝOw T߇_`dT#%r]w2, ")eb,B0p yx.#=z/c+iZ0d~H,?A ;4+c,tUud#lfltm '6_Mnl@R f~آcHLE|˔.H~>a3K??^DKX۞ JmT"FI IsoO/)JJ+م‡q}OD $ZS3+5 q3ثEp|_*WU6WK|*aw:m_6`clO2r{LB׷ZwCndC \֏aڒ%I4ں8xۢH,~nc9dŸ/OOϛ?<2Iޞtrˉ7u&L#8^^ W:Wt%>Lh@ IU%3YzgP$8KG2DLq;O:=ZGL'cqc .Oӈ'*U9\}sS`۵لESF;oNOZ͊FŤފaq>u^\X!sYb*t`T2'iP9*u,w!ۭVׅ^,rc[̯A.E;%EwZ&H2_Vf"S0qӆżPZ`EBt b,4۲ih\8owyBӚWH(DxB4A7a2t?a~,ȗSϙ fGߏV7*UQ4Sc^K!ڠW5D*~  X͋IرJ O}M4!Uy5$,L} Ǘ ɤ*,m9u!K iBpB*$e+cS.<-rHj 5S,20(`Hfp$ ?lrWrvf-*rO"z ÍsXAf(觕rXX)at)^|iqU_~9WetR[;=­X)-{AVNdܟ{{U6%%%FBq̖I,fԾ=Wy6z`K.Y.\՞m5Ν0PoRͰ'zƫ0c𨡱clN'x]b 7{8H6zT+l W a`hܜNm߄j<I<=bVR=l!$.+ I秎Q[1`q!kY'ʭLy0IUzIT JXVܙRq~tOr (2{xYwSdy'bUg$@@6."=c\AB +˽»ws4|6dzު{Nڍ[ˣ!z&~x$Tޜc+WsnI2!W]>a&n +mj_IQ}6(E']w5ZpSO)a X+ \@!w9QTc#%nC V8[T:G  vq4}1$Qr/<;a_-p7٫v- x6[t,gEmrD0˚t'h], V}%w}PdH`hL14vuiB%(66*swԋ77N|:5? ooGFGjc:;%Lh[4Lǜv#APTԐ-}^CP&lե:jHA?`yE !]h'wp cU#y)vgH(/_x5@"ĢS*CuŽkX'YM2+ ]!/qDhZK6[B?Evd]\yb MX( -"&)_ﰌakZeykU) ͌* t0wwQ6^!-ɽvڟ(k*FM3_OKHn%(\[Y=x̻P1+X~Q)Km,&S'g顂J?**=sTK%DO/.UF@xO>/~hWk,w}-]@ɆUЯhڷK`=h(#%P5SmTi cPx9B 3 /KUZ6>dE`h(KăËနĚlzJS0^'ضVb(|>]d"/lch`!1_-Y4%2/-ǘ OO'dЪm TyXh4؉(n^7|1f7*4l5X(0GD'h/5bia "KU?o-4ȡհI>g;w;IJ--#\9ŒS)Z*T$G!CqHat\ў',b |R|@V}Iu]/e->}P@;(!R(O;gʻmg 6((*_]1Lv؝ɣkZV Yg.4nn!(f&(D| "3x''ǿJ5@6G^W׷g[cX[ |1;Sn0\<{M]NoO}6fꈌQ6 C>0ksEգм?|=hrcyQtY;fp}˯:nLʓ7CoD{쭮30ICdT[(≀wדBi . I\GU zz^tr4D٫ hg@H2q*% EM6׏xdSn u 4)JYӤI)~,=SM[{Ewvςl1jm>NI7U!4(L,eP'RYeZ^Y;ךGGzssV]_?^خom6[UprgrhI,VwNxV_^l??8:ybfssYXQkV5zumbͭZ}{m}KG_5pb:(g:k$z]ZV9YfqJs#Tj5؝;g,I]|N"Z4X41$HU1vwE.vyju[m8&iXc2#b{KT֥X+qQ#v"!v:Wkϗ*!5$#vjbc]D;bRlE0DSܮXuvG\nmQEu ;xZ%:\kDQ$.MU vE T֝}9rW1t2c;bAAjZ;C!HzIc!κ讉FЧΦX늭-]ZX~%6"Jސq5u|_>ق:*#JkM֛HhՑlcp)_ (t ]ݍ޿ZP^![|Е!P;d5ͫr Ζj;"w{l#i!jjGtk"Ѷn[:0sqMtXQTiiިc\6jPބ/z?A!ΑS+J_GHz<&{^W X((..nzm7jJQva ы޺C' r~D%@%)K~~u-ߊ/JY/#@[-Jߌ ܵy!ao(FǶ!:fwIo.q; &9bB&GtQTse~/9r0t8 '= ʕ "#:ޗLQAG[M# fΓ(sbkSMi{4>M”;WGLE))Ɇ4Wj'v3ajW=ri*ύVAdKrU[4b8V\8krn IdۻN)29{zR]G7F dxаV)]*]NY#a)2JK=-59fSt]X%jvukmmmZ]TܪlseaS..oh\'xY|?H]dSl+v|ϾחheG@!J`T?QutY֜ro0 "x?)7bMIJb ݏ)F L؋# +rA3&rMPx]=t+W٢F[U7A D46WF=nDzho7˸mDUyˆ^?,34oa?j0eHq2\(oDs)@0^D<誣/SSfbٴV&$x h+=|h`,43TAB8*{IRTՕw Kv6]i4YSl& -LҨF!{-q4&"$ad>i BD>lĊX%]vxYy^fz#rt%|y^]lGHKTW^aZNP^w',tg㕍;Y=&1{EZm4هrNE4tr1Ғs"fJ9/ěhrh<]&Y v>n/mZZ i 2}iڷqii)tL.Ľ#FҦ^(]eߗkPtLk83;'ڄuA trLI"GHʈ*}K@П06Tsz]s{7%yfFe=1 `H 𯹍4@eJɇ'h-2x?$( `GԌ=Yd;8jh 1LI g F1_q f(ihWCID[llfŅ"rc}}{gg'tE z76~A{! BJ֥`hh 9[:s2eP:7Sw鞷9ļJ|-iz ڥX}@_MxdA}!3ͣ]HxyXk=m5^lݢc|ZS{`8{V_yyHPK46(!,G%!/^N#mCh!0ؾV`9v\ .~n; 褎"扺?u~*r7÷V}[V;IfeEfR|tV>k*~0eV:;j5cLqNGAqˊhӋ\\@4|(/B}Z+)+_ YX?8~^{q|~t\_8Z~fscbz<:|QscNu8Uw;/m V}}FzicNIlc+_w&š7Qn pNi" ~"lO@TBLdM!1<7bEݦFu4#).ܥQ\ކW ]muJBeiBq'X$7; P+ Ќ\bɾ5?k Lá MJ#6ٵ@>Ԯ >|1kmKFQЦ3 覢 ~?MT(EP)EH_Fs#bKp4!Moŷ C۫Ֆ}b-N1kEiIyz#u#\=pd R^ڰ#;9Bo7 d0jà# xr5jy=ܖ;) ~˛0mwV,Veq^D"C*f0CP&AM0vqub5,)qlSJM0*QL.i%1FUJة@9e?Hȁ+) {$ssRTw~\!_5/N-aK_V1π3jFUq:Ԭu4"bCѨ$F[=`2"Hn'#4~eTL[ӎi1/?K'(ZK)OGpHͤP*6L{klUfI>~_ԊGa^П4S))^.o3&?<{4}hӗ¶5rRJǰW"59_N]]#u lL|9' ^XBӥBٝ'F}&)WoY59LemQrG2wmQhjgDQX_vaj[uITȐ $?"PzjIr/ehܚ:Lỏذrw`Sq?Hh_Ȭ~6|} ͧcsolK;Jױe/,Xiҁ,iJm;(鞔xјmA!:xxj8%}Q͎elZ10 ! Af1vnf&=yhwE0*??r+e6B+g 6 ZįڷPLf6ՠ2k6?z(Po?ц eEW'/Ns5i7ҫw²K)kR)Nc IoS= 26[ %빨m,PVg.PG|5[!֘sؠTK8VAKK{!{$^W_(WA7569nWnD0#I<,u%]++E!zw̦Fi`)88~c{7s>%洪eiRR!ؒ!.lTo9A7 &mfص<YCD-J Z- Ajs呥_x7sԗhOZq7%QiK1ף.xFC'Q? ct|%zN~"*y_FcçeQe˾_Rk'ֶ"/MlnQ {J0`,6_ z[\|wx%TCVB(O/_ SH#G yIB`UHQsTktO--]h HV0C0OoėsKKR_@&1za >ջ E ՝06ՐMr[#Jw|c9_7%S%*9г6H_z9DrӻjFW3w΁3Doqƨ2 Eh1 8;A:::XK׹ずt"RȝM0+ `r`%G= szbMQ4mm`m< 3"_l(H.lEhj~uze$0aZbҹ]N$~瘵n~Hj#0u!&^(o}&i!VV%Q= )Y9)>ɽ&p#{/`j"s|BFBnjwMbV| Տ\GPcOiBozar R< GDn!a,oA,w-+&8#Ҽ M($Vs"c͡cBqv!Ϣc;ܤ(!.*a]LRA՜iI"7s' B(_SUk8oaU Y!Wp dseDd BfߝL<k ;Nlzf.3 TtsdoǬݥY%Ugy npZROlS̶av9KAd(af]¼mu5ֈS~EvVu)EIZJ[\e^ܕtL 6s3D_A8F&FL?jʣy!Pf{sQuEђ 5c9HH f0~?|7X@А=H̀yp$V)`~L$RȠ ݐT?nrZ[U+ ;V۞ (@H@`4xu>wd8 =;4W7jْU%Ӛu [0A T -hm6 %0$ok~`Ur3$G8 e"§QJ!_tUe>ee" Kߋ$eE<3_y@oڼ 'H?:6۳nSTi,G-l@]0~h໨0Shnj K-a(@%N ]CK|qGi(Yz'?%9h[?VwٺE ^.bD^PᠤEb4"#1ԟ:.J$^jK1X!p'c^(tw5-\ !>xcýAw8/ א_lXT. a+N{b_wT& M ]Fdr)$9Dk.Z"coap%E9B:NPKnl[zd<"'7ت*g7P㷺C=NEɆ&Y=T?+ՙI"C:Vǘ$՜l0q% uv66*N[c6}D7L,l*Bꎅ Cߙ yU[5hoJ-)#̭,*{}(n4kiS nvGb`< 4!cHϬt@C"Yօ*^X^v!eN:|b~dM슪^ו*<@np-^є1mgz=o1{l}y e#9$ܽǺHgHڽ %,] 9*!ͱvޔa|,d'K_ŽbR"dRCZN#M&=6$Cm^ğ "+s+V+m{P("tnn3K'^qW62,$byH|#B)Y2I#h+UbʡSY9v8bJA3fC9 @ ʗMe%lRK2V2gFj̸0՗Wn>sS|):T*J4VF ۬RWgScxkz 8i4~s0~; ՊpD#D< I4{bЁrza oWFI1{$=uN`$/d덇V HB9QA `]T $c:zt,b?߻lH FO~-@%`Bnuqb}0ǹe2D?aI噊yl{ +`W)+חZO- ][ ꓪJ->2ԅΪ"k]5!/l_caG[%L{S:$1 |E-+Ó"3rP'+V/LG |П HV2trC!ހJK^taC'E$="KBZ]oks 3ʓ.1a2xRQk]Z4zoyio!죟_dLdrR0#՝Ok& " 1!YW$0l1h}z}Z eS?'Qop`PÍB%=L\7Ek#Kbș +)dk( yV}DX3ʉg Z6"e cLGv8Pǒ}e[GdlpF>[2Q7ߴw"PJu*X\zjb9X'z>("%|KsÌ輅3XFG3Eu(VrR@ҢU8)D!'HLM,Ex%#t&܄J%B( DHD6G[g%})`%O*8i7ʀќffN錊ihtK&+6Tbz,.v&=SX4N_Qan'. ?\zn<u:СԊfMD2'PV"A^̴τv74 hܳˊ=Q4djѺMW܏Rh #$LH9KT!C:!%7}ɦIkT{{).)M5>"Sj16W8vӃpO??K7lIPK‰y :5qT|w=[B*{;pY*P[J.{ 5cP)8L AJv1LŌuBeL }̌fvA̤0ABplЈW֋ܬuOޘO@vZKWj_co0?ߌ]_1Xgטd:s uDB   epY +d%]Ѽ$qXjzEǜS+) 5vST^%uƳĞ؀Iba-8t^_5b6E(7|^.qBZ6 %L3{f#%B,lVp㽫fFTQ1S#=%F~y'J8'vr?MOy$;&ɘK(-M W)k GdP(@D^b5\BUNW [_b L+8jXcTUQOtrSq|5+F GCG(Ǣ_wY$EBJU.OkruF.h8Ttoy2cHc#Ե lfRfQⱺvIb ʄRKjʟ^FnFvs3^6h` -_]y-IåE+.mt'u,GMeffXڻC#&؟vhB\hcBMG@n^NzBŢ:#]\UJ^A34emHMSۺsL`K&Xi~@hw]fJa=6d/& ktȡ ddNKȍۿ6'v>y [IIy8f([ 9K-@N pqZ!'R䖩>d=y0jT+Z. ş.oe | ,9g*u̫|=>2᳸A&O92=X߹ϮJf t?w(Xv%A4PQcs?&vC+O+ɟGN&"EH@ dPlViS˹3Lg3fQ/Bg%3;b~N:7{-$#k@f6&g{Ϛ\;]HCV/H9JѕH ѕ t-M,v Y,,rv,YKY]X9?u80^ T2waEilr:9\?-dsvH|9+٬Y*Y\%8sq g'XK=vVeM2|!V#@cm˸YLdsJ.,{(ͪe9wғV8Wj;Ey<9?~{SfN4.XLHc-r*<ǶECN%tGNkk)G'$g \y8ٌ 1.L6k)u%?1'3g1e=.:ټm9L6vLr:Y4^/@! 4V%˒ fg20ød[9wH\r $9e5H7 '[j '/擻e1lrh}9L bjnd1,/擛PYɲd0G,NkPgoV:2Yd3G:q9lԘ9e2J;6@j'RkFgηnٍn&9fl7v3șI$ & dsT :ټ%1&$(ifL#kld)9dY#klfI=g]f?%ZNɈ+qP&rw#jWo^v!> Ǘ8M0<4jg$3F`Kn?#C]Ϟ{0{VߥP:e CՅ `P?Z'@Av'J4w961͟WZ(D^n^4D`hK'*HH*^ܑ~e\I\͒Dl? nCɼCb:!̿jØL scf ^V:Ns'CU=Fc<uC&Rն@BRjʲeP1mY!NZ $SA_d|3Q%QvEQ<+8q҉hJ!/aas@Hdϊb&0qZ5<3dP[91.|+v5܆gdxfgXNIeo6}hM`_=f+ ˬ:9P)87M|Kj rrI~ @T1WU>_'{6 _}(blM073AwO>X?)j;还KW;&HˈC.Vq) 3/9hsM (wQS@ƪ#L%3?fќvp˄I! 35a uU2tx~ĿIb}6eѯ /"'лA_[ʛL7vx<9PЁkՙQlMŋ}<.ʎzZAD&3H GB2 v./&'KP_].\b_,ɹbxZGo/ yc:5\: |0 8T@IԑI Aqץ@]?w ,APބJHRZ#RRq(C5gᖵaTXO:xlaPí&YRʳTTnRyFv'.IJHS_wd%b7?_ I{*߭N* ^` qkC[+ؒpt?]LDSj^qk$XB P -!N9h!>rY9' D U ēF5$O. %ܰ]ހ`#$E~]q&&`:A=2S}cqKWј΃^pF& qюV|E遢k*#s**jaߤQrw- 1O& 9DJr%B!D,L # Q mфVP9rFNOn{B.)8~m< 0:[Uo2@>,CGpqD@LBa_{$ppe!Py)s,^T7OQf[R=c15g-izOQGUn03/~PV&YJГP#hk`eb]?\eLJ͓Vr%zg4QľQ&[p`ug)$bxy-,A1A"v'78^CFIp|4!*DP! cz,#Pڽ)%ֆce/8Kd(񰑞{LFQ WV <pVkD/wAR`9!ьhC1Jku˄*N?(G V"/TSfeN4TѼ$A'ցg7pLh_fU8dĮ%%F:3N^JzBsz#2r $NStH/hCECMYƉz&i XkXW0L"‘C6.%[ Ã(N7).cn;H5zHH-,O"WW8R]q6 ~=-=eqG 0QaNhGM ;K^4kP+?twXJŽ"7'JqC=; qVq&PXJ{ x8,3A8Ṉv@ YZu*JvHCnq]zcQ/;xRh<XQ^t \6rw3//z@xbP5&%7G4Dބ+`J uJScrx˾Cs6Ly+,E}rFfȎ߆>(\ۑ4D3`Jӑj%HCZK+ mxEglT+'qi8<[=>c!PPArEYzW$\ 2ΏQ!lOx+#VLga+ILӂNUC6`weN,?0 Qߚl m)E+tyH[dx@i +/~|u%jJ2L]*Q0oNZoiqb ebbt \[s4$ñ*V#xKDwtgE'Q'.@ӯFk8 ][ޟ$l)V Y r&׬ޣYhn=AtC0Lg\N$%*?J_OB)[ , o d3a$C_o;Tt[!Dz_BK@>éw63ԮjnaO} Nd-*~ӝ|%&|usk %: KS/vnSQuz5zh@pYoU<;ݚuDɠ;(~ʽ'DD#we>5@간iM 'QCl]Fl~qk7^Ao;1 uB,s"4ݻ+D1%]kuR蚞\jϚpuj*'N-9eHugg秿><=9i^4[͚L ԞFޫJ@nn5_"#Px ?/NV~^/1mSw9G^Rn$]=4eI8I`;v~eP õhn6#(rjAQՏ(qqI4zz.V!* hQ@.kkۋ5F|C`2 MGz Rk^usrrj%R?U$>=yIVMuQY'd:vR%kcFBOcJWPaG%n1Kr72RX ;3ˢ'hr'ofCs0p&ݎR$`mѯM HT`'Fʁ%b/N iĽO5bzES?vsË CF&WN jQkPt6R@цَA*/ rPbTZ yǿ6PC>xջzwmTS\P䲛A'nd3-w Jt>Xti2 /BO/E \k{rq'] 40qdq?Ԫx&V}XAq\6HWgfab#̚*se,Daxu) j?$G=m!3!Ng,9[GN^NǨ1"lhh94N>9^"M$ݯ=~C&NA9aK?fd>]gfdT6D1ko)!V`MHS,o'*(Ŕ,,灔$hJ@:>TVJEb.α)=SpzُP.rщ 5A{'R8BOqjk-s8)Vl{o8Zoj7 =\2鎹J5C.l|nI'B%͵mL duA~P.UAP(i(}aQLFfJWY(1 M.!ݕ!F-ldȧYZ&qTR &~fZ5?(ml ozVѐ`K%>ރ,=A`%q]޾Y;RP6Ў*p3u|ޒ*qwxXо(>`_˪YyX!RRzd٬.B=QUS|\{v{Gч[8@5^셎]8iJTr1A*F`"ҽ.}ogMKJ„M:Y9$y/ԟ^e`0IM&J|*I]Q2$klOQYIp Su+l7@]UPn{uprzuS3X)75q|fuSYo0,}4dHFEA-=A.OhrxvڦI[%g;iG 6C [skam~VJ+Oh$M[]"dWBǿi6 xOP7[.!RCҀ7R )Y-U7ti!O2:zϝh~[UW0*oj?uO_ެtO@#^" OBvb"=pE@pL!8߄x[Xx&Z9:eԅ]j}:k*u͉q*$=^C\0Zբo`Tb3LZNAB ?72rc0lzcV'oj8f(gRYz}ۘ ۦneQ)#rmwA/tcy_NěpLw gƖΪAm,^ t? H̴]5x՚Mp Ό~\2Lh Kn^RCx̱;|kPGux\œ+Z)jH]c4( qԍ Ϥ &T kdb5=pip܇&dvz{A5 RgzȹKeD/Y+c zpEIZ׳㦪Y7{[;V£m1S`8GM}Ãb}+yx[_ߑ.yÐ/NT:_JqNDw,S)e2خo{'t?N*FKQMij4u?M=fOnƺf=fO#7G֪K$]?d%M>?1V/_x;Mp>n:t2[ݔ76ta R c8tStv3*WZo]ĥ{ O| 4щ}^.Xfg1RE]]uoz՝=vjXr2Uٙ lڙ;NlIyVZy3-FU;~NN2kaT&¹sת箥sʽLlIu5]b2OC>hnU3ުdVܮ,SEtkp݂Kv}=U[&(w9./mk;Uag߷EE@r}VߙQ|_ 7[&[ڬ"{z" Z٘5==vnl I7g 7~O7_$*llnn~;HS^_ܞ5}'=vnV^ڮnn~;HVy6k{z"0FycZ5==v~lYnn~;LS\nn~;HF>c,:oaEtWq[Po"K9lA9ۦ_>/{|vˬN(+K253 ҫϠGjQנk᎑:ؿY2&z(C)AdJcRQt"w:z?GPxvWV yEXꄻX7񝝼 qX)d(S?y̔0:E{yWbD4&w$3.7 ;yDv)Cءh [î濨/Ų8#wo޲ke1 %Uju4w073CqKg 4|^.~k?6fb6pe㻖 }Wr[{bħ욫1bt ޝo7;y=4.ȡ8,)._c`l? VD}Eȟ>{2Jlg1O.* ZP 8m- o[L#pf,q[$L+>EPOW6w ?2%`̦iBᙉQ2ŴI Pzej笑hCEMT"\)g눫%%Z"'sYHJdvS =J fO+Cgzes$x.<)I[Ate>[ ^>O0+Fyd 9IF׍utĂc2vM{d+)Ad ϰ&_PKTlnHJt8_ӭ˨zsjHa9\F}H8L`aU|ei9Y#c.ZfÏZERt׉Ū]t Y^ \BRYײW7%HaRX*~п(LQVӷ7>s8Oj<3E@LQ<g7d24ş8PmN^u~cgg p-&oCN̔c*_SSl0+jisZ إ|-Q&ْNV4FTR@-|,&ᜳAֲ8Ώ/ `xZi[o;re&'Hɩ LuI*pCO͡L6UITU-4r=-SM_Xkς>j, Кρ g(")EQLkttpU7?{up"χ` L%яۇ^p(; cnC^x P [̲ HՓ YOTX3eYJ އ[,~^Nnjkf|Hj/[%u^^Vٹ%IGd&G*ڒg%<~;8b;m2 p$^yOP!!&v Pt|~0k*yIWﷷlyg/ְ0+سljtx΍ OLBݺuJZSlQ*z2X巊ɪdqX kKRD<'0ye*.C3.T0b(ЁԪNJII?X˖)ǬCbӣҪtc(/a0xze1s,XΫE+ @ԕaRO+B՞U0~Ǫ<97`$鮰zI+K%.+.> j1J z`#")6A変LRN*ߍ"|LBW# 6+,&g2\LQIB8`i4*L"34jwևڽ!."R 8@K[Yކᶤ-}q6u"UB ֗+ʫ*t ?=e}FA'ƹlv+lmCubEץTUוuslŎߊ?W`EqeQQڐD@˜'JBMR 4KDR [P ϟ5J}y: zET,^[MBz`*٘k)?76?4ʢޢyBhhX!5Ҏ//p;8{/ ?wf~Gt̞LƟ#cHzxI?{^k(ƺЛ׈BQ,nmKО bQ23t/ή@bzVNS5P u,\h+ЀѷAgs?9z QfEޝk8ߢ_c[t mǪǭA-PU`t K 1Ȋd>-MH(H*MV(!KtZ9ʊ.TV ȍ Ȋ%=L<9XCdS,&QraO\PEBbTʕ<ПizxoEҘMIW[V=r03}]JhH_kR[CZLI*:E/}xm-"$:`>r Cj>Z6;r2\W&jV5XonHG2[x_lr0g|XW>L"k=k7+&*ɳ2d^ /U^7ǛL {;z :ǒ7qÒvfƖ`{cDcNS9.uvib_>2l꟞=y\ TZ\d[0گ޼:AkV5:1 )/z>/^4GocqkWWp%cV@%ZѴw: Zd:wܛ%ˢ($CVެAkfx9Xl,Z g\vAމBe:xK Y7OӖ/򗝴X(Åo3R˜DQk*FЇi2K6;Uu"/%_Z5VD^'[紇ь$ HՃPÇzн(o?6*1)˶ϽaEdžG@F"]z]/Lt;66JDNV+U+ 5Hh;:24h!Lh&j# ˗'u jWmx|Q}P[S`VaBC0˛7ޡ4TqGMv$:vh>v~LƮy\ bԁ" f)v& X&SKX/-WHi0BVhU7GlbV@P9hȓWUc1EʈT? M!\/'@.s3`CCt:H1d7p{?{Rv?41yA,u.m!0ST\ @s@҅l0+f'/ tY0Zj: uh..dsAcՄSD7@$xo3ڠ yM 0T:&4v{/֜h D# )@ Iy[DKh&ϐ}&ҁS IL*Xt^⤵܏fOkxvqWpOpit2q5%z~WJ7t7Q[rjV8vVq{u~]e_ X{ݭDqrQH9z7Aү~60rvxsxWszyk=CO,'1x{Oݾ(7t ߻HB(~E6o |}- 8)&p4gP0sA}Jh]&3{ZsZ$: U Zl} Cu'^O:D O;*D f-0Re. hk)}f]'O_z^`O3y`_`kNY f,'al[NY{ÖoEr ;!Ȯtr !m|P}kA^ !$,'9@H_ MBP3u`.e -k!>n +e'ly -\[ x }$/Ԭec?X,ܬe ڊ;ӆűذ }V<^srXvtvvM5uv&\s9z\[9B; :[}'*h@[q)[}NjQVTaBu&m5>Sg@ FdA/Pwn%ؽ@Rޑ,$!NJ h,ӛga(0:Lt/ y}lg ֿ0r"\sawFz1\`WK?\Ql0P c\`Ķn B n~ ַnQ]8.D7_Inj<@O<0`6u<0xn;CVM=i[PNO׫„ܲ`fEL7)׵pH\37ixꏾYux t8;*lry7[s)HSΏrl;y]q \ gEemŏ^`~Ǜ'fm @π_XF!n :qإ{!zƒD[}kD@W}Ba;fGm.M`OhBт~!Z4}2g8N! P3hP&mGt8xa߆9Nr2OjoUĢ'Ϣy4^&\`n֟R?ꓧZH'0F d"oK!7(\R?D@p{+S 흃뷯ylҨ~_a7r726#>m#7x ¥p;>N'h4OqB>xz#ڧ?ٟML,ЪCpJE10n.ڍ&ҿ(UPA;$w0k24E7ob&jY}{c$sSޤ5wAׁӅzB|CBI,KJaCw]>ʃ?=?mu?[f6n{\lfn BmSc(΃j}-x\5'.`*,$ 0GjZ|ͳxjBtsz|1G1% \y+ d oneJ)l`36Upp 6VҨ eun)eM 0S|Y l pn_@ˏ~Ab7/=OXeXL 9 nߌL w3Uz /e?vzr9.y1u"G@;5\/?#G>]3|;Wv0gD{&yq_3 *H>SLtJzڹ?c:d;qli.:9mL 令NSǽ+MWnxҦ{p8\;ݛvXcQD<ەŋ-r)S{^x@Jʸ܊T@~@(:ޡ/[^ ŽΚ8 0 }?VM&3\\vu ͇z*{)`͵z] Cs^ 1 jγzMH*yVo<7hXm[#0q{Z6ku߂tmWl>l |p=pWë7kku"&"^qqeZ\Sp! /<(VdƜ+˧ HsAHˣ!)ɎW =U~8$ba࿦Ճ6cq[+Ch с>7J@V(݂ _Ӑn$ aoױmn¬\n]1 sx&f ڦj{>C"3VnKc3V=}vtZ vqgZ~Pk e?8rۓV=i ,'nkwhVLVkx˗L 4-DB2DBzȹa%$w.#\C0{% ::+COuTQU@ 6Y,8^v ̓{3wpMpƽk;&ͱ$D1j/(cq `QQ|JtS5N0j2;͒_Z1X%d|<$UKYE`mz\ډgI/-}.i&;<BiA/~=ING@/< hMg߸K!6u0%D_~F|ˋ%ŸPI4T9lz<q5gɰBFшr&A)^ssQ]$hf(E-ah;o\p:f9IǍ3-Gaz\ ֊V"\I#Wwsw'bYj<\M~'=d{$%۪lXlk~pp 4xT1 Ϊ4fN*P_'WsMkzU0)5\ RpSTՠh׎-:)w g܁ۋ_lTl:z҅r0.l=>MBI[ (K8׃ǹ :ׂ'mQ-{QN%tDRQb[szl[aԜ/ N. °20#Q3Ř+ouw ǭ[δM͟x9m},MDJټB |[SvhݮS>AۧN]3=X_ ;Y:$ti'R*@BvaG⏴ڸ ,N o[ \b KB[@m(0ǥUN[s2_ m!׻S>; L -@:M6̇2w>Dh u=PlBu{+ ,׀_dZKf))QLQ\]G0lx>p< *o%%?Dž e͕楖o r0zʀ0 Ѕ3K58{75S?,t48SN83 ǓbʸAGpq/G= h86p^Z \,v `Mp`Qn)3*~T5o.v: ێK?TӠf ?Ieyd-mN@MIP3qRx$RaeHU\W>^lx/DԦClne#@F ssX{#5#Uhk"nbw$K6ʲ)bخJcS0^ L[Py^ MOy]N. SAEax `$d:(!En a "hqت7]&U4.=NH@GҪ3xw>L' {gpۆGq [%lE{ogl \'fpqps Nօ&kɳ[RuȦ5'@!wꬫ{6;Ybfc*Ø>ua `umbؕ^xgeX6vp][Nlrb r_9?Əu*sH >nn޽N*JItL|Xa!MzQ_^>m"aVX>l!:S+ج"K l:|Iv.RX}lOo?:|:F\F,HKΪ 3;Go;Mc_L'-nA%^NL0ӿ4Uޮx2B)v>X-cLxY_ɏO~d%-tx/Փq2nԅh4(Q;{^wVxJi>mVͪ?rrv맷[Z6w u|X}mt_}}Ui*4,mMZAjv'` ~Tnksb?kV' b?kBr}M ^ti0:gl,y'D/t>fʏSS7Wڰk&D[:Q"/h*/{w0D&ezgӺV:QM?|g?ʂ0-rzX!BmB_)s=¯WQrJGqjM{}}mnw]uU:^u޼o3~gΞe=wtS|>S4JI@xڄ;Y+a)y>j́NY9Udjf}b%&4eWȯCCgwt_?k/迢nۆZ]z B%cyG>PEJq(UcfVU쵛ovVN*mҀ Bxqp$F]5ح Ӂ:P;m:͜*CGN΂G"엝/_t,Ki5n[zGX!cQm@M,rK*Ȏ $fi O&pd㑊vS^9-q2{:XͧX77s@ ;pnڤ<PM3MyÆ,\lT#PUKcu`eƜ) qW8 +A Ԭ!fq' 1w 5$4®Cx5 V$ `_yjc2 c !\^-:Kw0pvy6Ak p}w{wiݝ띗*$Vٽ{Kݛ|Gɳ8Qo6y^r~g& |&K1dG FNc7ūoe1${d It>H):b|%A%>ᨀdΧgѰav gބ$qCCB߯t"t{xC+@d㇄4>mJYtp|DX\t8]ӘѢTXڭGdzVk'jQ(Y;lRm!:OwC#$djIR¯_o^kR?>StvW*<> YFrc~u ۯ, UX,We}1Bn!<P|,NDz06a8Gu&ckOqu&} 7۷,GFoسv1XCr̼*OgBp̢t~V~n:l\P)/8˭_,qUN/`̺Q?d g_lfj Bȅ]Dy1!IDF'ԉhјN:U(܏{~MfSJ_2913cCF8bRBu?ُe W5Gf=cI幌{m:<zk~w3O.~ifo]혽fj>UwuPha(zb>MRL}Mx;u"[}j:9,U (lzIEi<0c UQXnj6833mޢ+7ތaĈi(gt76a:x#s -yΓxtp&ѢgdhwMjrVoZc@:ʴ2u޾[ &rNm9:G7WZoY=f NF|w!LiM9 ޾^/ci}MwџulQk?|6x{tIJu:Ng%ڍ5}2O8HbU7?3WX,WA͡DQ0_*3NdKKNb2袋P`i0 W!{;x"S8jS/?ښyw%t]0gY*筲s+ȮjOr ۙNSP+=TʵB~A<_hWtʅg^MkҖ ǟx*:-Kl[ܓxJ,\mZcwT ^\Wa-(i@w@+CҢٝa q{}\cs8<y M2Q q;5>d#g<-`k6O]sKrL8yzs^8Vj~, 7Lхk4_[9z2z^) z4m :[oSwӏD"j}pDX(/bүΰ蠠 : y/2ʤPCV=\Klqk`#?"'@gBg:҃n-fp]L1 1D0$_mxz~L3e g({O>IԻ,ial2¶s͙#,3MS?8MIBon)}kGKhQ=@RL2m_ft*$H3٧Lk)pF2؀LP#T%txڏU,eOIt2UGG!_T?b 4Ыՠ4UYQ0l&i5jx_p|GViJ\.S:A|/JP]&4O^ m3 E=ydg HY^~Ua,?T䑆4̎;W ڮ"SN|,sQY!VQoFDM(*; 3x'Ez.!ޟşGg=~ԎɢV f`2`4>MP[Q b_[F7gsܧI [Fj{04}J]Ҫk_L ,]}̵y|. 9Fc%){ ԠG?<R)c{vdl7]eP|kʧTQs<0IwX&j 7BI4s>[j _NP0З&ס˹i .}\ME{_jbX̕jeUWu뭝-[5xym.ze:ǷCG m&~ ڗoX; ÖZʧF#{YM6bA{] u q96 ה*cNUwmZ+urA0"gPE{ٮns:Jhz$<*,ԴurcTMI#& K<3~xQ viVZ'tGgu׹"B /5,>]_5R(C nڽ Kq£GZkO(zX:U7}7 D?d*r~%xz~#j/Pnrn)eߔ:32oYl.ON͑FߤVȥ<5+Z$"( gnZ=-+0?k>$lM%?b\ [0,p1Pz٥@Gq^,-DZ5LHWS$矤g  ؘ3JpeNAr/ZM2";џ%2>~4гI0 YtY[t.XL;958#vl[(3JhzIX+uʬG1<ᤎmeώ]%eGn3Oc=ցQͱŜ~aAnqdC2+GYѐ y LJr6"khuUCa[?׶"6UPD>J<{w[OKٺJ<}p2/)~J6.6RE_*n?t}zgu߼03Od[JQ - y|KclJTK7*>`ـH:FU-K-TNDҀnKҏ-?a?KVeU~;`w|(/'&&̅-j+4Hr HaܛQ<. NKo8vNs ^h)@YˆGKwS`up[d`_&d噃l=Ί^+pRofq,WU 9K sʍ:JcIMltr s8:L=,72T_Wb_>eRC~S!bi1ϑV"dVkmL NqP kq|"ΩN[2-92# g;`bJmPon?c ̃D H}Cef4ɐ;[mEg]TDE'8Z u"Eɠ]6Ii ط[|WxJ7qўP;Mhtll)5Ox}PB5>R\mR?;E'e] JMZN2d-Ccҷ8u/Fvf_ro'L{.'qn2)=w;{{]u:{w_m8qQTjVfѐt. \DxN&.> xp9YBJQ X$t'Iz vSq(D$(.)p(SFdD9[uyJ0@!#慈ΩJfIȧh:sM77!#ve!Ja1ϳvPr#|N9]szN|j+)Yk|'nTq#|Fe)Z.٦xv$KB{q2E8A:PNgoR>Wv>*E9D*F )6) KlDհ) d*_oOJ9<ꃞao Mǵ9ՙkLU*; Vv O4>E(T |?D_ݽOvv:e,K8"b;|?w E][coٗ4\Q0D8Npk繏f=p~X`EBfPV:"CQ#b"x̹)N/\ ]<$Bd<[ Ok_n+>[P^lB6*.ߟNh! -zxgnӻoڧv‰]+iܗ;s笳9uYgsódyndC/7w&9kayJyPn;O|a4ofb.of︠U>pssCn4'Wno5m՘hK|o*(ͦzyư}S'*wHz%_ -йwÑd}kX,a 8PVJ7Xl{bO(qrD8: s#$$Ƿu;J'pv#%? "2hg ?а}s >WX. % e1Gd 3EVݡ_Pos* MĿ]_0z+x؆=`{BH͗'@Q}CI_ɸ| V} y=EO]Sq]roVڒh{ JRW?dy8Ttq[&`| /0:9J1m="p%- OjfXBs<帤|2Kp2.Qؿ&ds'i`&iIqPavkwg ZTU9Ÿ蚧0MC>PUQ̨Lער&+-^ RqS%7SR|G>c]#VD-V>T=18(l/S*->VcY Y !ސ͘IQk&gp[(ʺv¿|\A0uCiDS=|*+^|ەkºVv04 X6}Np{4KU*'8ǽD~iDX2۰=ЭbB}`41ٗ8hd$1Z_r.'FKc=xk>MH?>oz bvl~E?Yֻ+d}@[u4yzynBlm^pLo~{>lШA{kӟSB(/-MOoOkAxȾi̚V{}N蠠nϢtpA6+ Ų@uҏyx8*7äP!g;Vu%<¤H lRcҪF%*M6 *ݠ~7 WovɸDdz~G&fBo]3uk@P06=Wۡ䚴5}/Ɵk 3E%+Pj̥9E| &t7b6dz!h5s6&Tn f-8O,Wȣյ(_{aK2e;.SV߉v*uG*WdZkV_o|smmU#q gYnZYh]0L3򁶽h߸_@&i .68+_$<oŐ;; b<?ҁ n3mL" ;IP@l1^ɓfƼcnq=_X&4"e8'8E|&ZBGޛA(1>r?[ts}t~F>O17D]ĭ. qKZCMoA !-2|38X y\']!+{ru.b0DհDz%ru^ *n>yLXFT 5מ=g'1 R9Wk0i-/Sxz~iyiJ$^7^>Ϩ(0YSGrߩtxnwXoU'!ݟ 45qIUo@ 2$YL  e5=!n(9qgfعneF'/مXc4k~Ou+S$8bQ$Fc}Iх?x:/p<),Q%5ċo(-B͖ԄO_&%v G=}KV[ҖUs&z~,5!;!sy߀NX j9>Yt׈@o_Z6+G/NO8O%+QQ">k5 dU YgoO )V)A3wHĸ o 鰘g) `}q'?8tϯ]|ea!8X:mҨԚުY: O}Vk|1}#D[lr,|"/U+ph AD?{8Iχ2G״/ 2b~m0~x^ԛ~ |"m֨f*Q/tBO%%U'ЄsxX[UP?rUQVyܤ-nVvʧKk׀;z_|Pϐ0NY8p:QM6\psƚӓe )jU Af2 5F'E/`ozqӊH"ؐh0P3unјUOlV183cX-P/Wl%o8h jOt/ù"S0&r >}Tijc>eMbj7joC@G8;;OEϧ) o?&*mV\Tέ\ Sk9 yKZB$r}|N [XpeXOD.õ:PT;kϗͿ&=)pZ1l#px>pt>FhRU?Q^ Ωb-ukohp7B-3SARӉ5QM-{9ܜt)o > L40MLfuրE'E* f'`v|ވF=Ǒ;K@U4R @Q]ÇdgL}P?f 2HL!-&\ Y*Q[EuA65|NUӘ,Gr«JQ_ e66Hנ?VY!X?8>xFB g1El| g) PX#Y.EßZyw:-RAX./' :$nRړ8fƧ spx8Ş+sN#js5b}Ӿ 4&fS6n;j>NUV.JVe`X=<,#) 0.1^#'vHɷxEjqfER)|U٭6ǔeزgsC\ڗJƨnN#úN%9{}m^(l+.-JҹVV[I2T[%@V-Q '\Ժ,^0RRca !3J!%V44NAq,>k'58Y%[6quWWjs+ϝ 2">P<+ V Pc<A_W?`ཱི)f_#ZKʨNJxRc!b0{ZM^-K͆ 5ė5TEJ}bS&rQzERL:DJ9WX/R[!~x{Zf}Hwg ]IuP1G'J/QOGIZcjȗtgg 57Qyt :7)^ 3Oc,@Wl\~`_}J7Z_s)M(68V;Z=h˳\QJLU{}9[}8d@2?Cm!+ D^zU)N@b)" 뷝][|s}xeUa |Qݧˮ*nδSP h4@]+M\cl{_otl sAuє}nv j\d+=.l?& HЬ#c7庈A+`e)SRZF%!gЫ{\usv(pIiwKŋ\[8Ǩ߆L7K|(j΢Wy|DƢ%l 5djd{ x>yxu?爨سwKQ dz L)&-)?uT߻ߵ xx""mAY7GiQW-Ŕ{rFcnOܛ;΢S-6^[^-A7LA"i\ֱ\@d(].',baei#`c/[xnd}vx-'Ԣ̦TXT@BrSjѕT`v'NQOY:S]/Y;;ZOz gLs5O| NV Z$ܚ7Z nYoi1xwf(:ZDw U^0E65'߂&!,UԴ d}h64N qwݾnѿ#jWJO3`|Y :{ӺRN{; N陚>y`kwx>{]5,N@@H&`:afaP ["k\ sw׸/4: ?\HԄ!g!pB7λnsgխ[Yd|3S Z˗tKʕ%֏Dў*dx1hO~:G'SW<֧?`ոDrdZVf 6*{}*I00;4Ƙk/-}F͵:9 RN :'Ae;SW<G"g]~3ҝF{ʝF(u9hoHu2fRAnaf%v TmPcjVSpvY%GV٤;+*!N,52 v&ZK Rp2Ka|rV'S5X"U*N>B]ь >#焼 yAtJ;CV768BV.e'ӹ)e*UY{?|P.nTVpɉE@:R ޷gܳGprgjy^hKR&uZݼS/ zu#J5+q7PSVcn߁[Oξ4$&5|_;h/G D-Q'k>SVr$ɍ~8žP?<2~AJ`o~VҢFyh h0̏ -;!9x%mX{_i"{ ̷HzL-w)n-!,]LRC~*!'"I B3M D޺D ȢlSOOxuΙbU}HMP٬l6] dy4%I?^HF/ߡekJA;+{^6jւasL´W- P?sä H~2X;TبA?-7b O&Y4Dəi&*mq2KwJneY`uUDf"^7tH-fEXƨ>U/"{^4B6;Vhxrti$Mb`2R“{Dy[f,l(8Ǔ9}KӀgVO<"Gl@*=r "6 *>ՄgTb` T[:H@3 _Cp։yT[N<<2/d9 F47%qɰL`Gej0p 4ا˅fҫqEkēaEd-Ï׋]h{]vD&{qdGh2@.\I>$glBpTI=gAK cI U[v\"ܖw^ Ȇst\Nm,8TyjVv걊)$-); 1iI n+;税fQzo8MdV8[$|(d^ Xh{/Fi 6דP\$Rb ]J?|wGK,}+wx.xMD)$h_!W7M56ԦVdRC2y% :vr(*i?r`_#7 Z^ղ- [ ZW"&X_c - br*┝O";t0sdzu6tg+,1OY󄟥s3.y>|`0&侗 cƔq.Ƕ->wm"c]ٜ n[vۮ΂MVn97r}Esjx'F8`mzvmDX5p`To0`m4sƫYYLkNGpɏ6ύ\4q `݅eQ+ک:]Oec1>]Anp(xX/fj._0mUz"wqkz@U¾ ]*CcɾhM%7dG1YVLZ0&1 [l,,fPǼdu/v/աUPx1o [3D*~^7mteeqgt>̵] !jM 9nV#~:YCo ~B!Ykw!Yw!Y7vu8Y]HwuXwÌacq[PZx0NVK_{)AzΨa=6WWF8` D^I\4c_.׊ZZWk)oV2:vE>(6&&)]Yy+Su z09a#Sh"ʸߧRтI.H y:.Y,ҹ̜ȕ>t0$`gsƦA.4aGWTZ1EG"{0;.xKΏH?nƽ?4Q<{@؝K?dpv6{Hr udTZNMs؃_u~"kx h8d{PSY&@_Mio {qo<'}o/k,{ly22lҮ蟄ʈX r>b)QP}O;ǃ%qK~[+0"xV.Y0eGAҍ`8DGB:W ;F{uoLicp=AqDe<;!#n6dZdodLgFՃI~e j` g  ·,͙HlKd20❖ (xqQ1-|+vg}\J'}?6iÏ!~5銫銻)ԓ43}hjA?~eMC{UgTWPXvxB%"[ggL ALE;HXXނup .t*PډL$֑aG NSpQ M{C_~G蘷G]2h^qz6 D tK.CLnC/2ZrSs8: /W܎X ^nj.!]E;^{Z{r\f+uWK~~Gp~' :K4Ap..ir_aX}qp*?qc_~"p[ -Foq?G*&t94 }Ф f"T@bYJ+֊4|&D?b~Wyl_|0Lz(x(9TS`;*ߚ.o G&?UUy t ;[*'(zuMz8 Kz" HhAL WLG탃ޅ5;[QƝܒbuw|u[Jg.xGph.Vo)3QK'js[r1w;.j%%x8~ӭ~M_y:~itdi;>·?A?,AQBؤYoKx݄ҐV[5)'ϟvT_~}j䣜0]($90ӶZh[V?u7;;]jdu;{T"S>W^۹AKfPX3{ oTeT%RQ+DUK-SSE=fw=g6B8wM:WPwݸ*x},V?5 "nv(C2n6LsgQ'DGSkcs_[T K$/=U,l5p_8w\fTiB 3TMůR*S$qZsm n#cUXIo?&݊׻ %y %:u8|oGlJKϓ`)Mf8=H|g[s;Wdn.07vDT= t $bpm}A3rB|\/LW6 l\kl+xr2B}!:/ w3w]#^̍Qomlh |Θl6ڛUFZ[9Ȗ;0#PlpjceG^x5B.hi]:IǭF;j/6@70m\ t]: R)R ֭wPC/ yF,$^|*(ha( Ĩa?pE4 G-X\ Ә-2$a zЩ6`5beqtQO](NX082H`F A.4:?Av0q3S4 \cX)7D}{745Y.;z@3kH# }uz٬ CjcgbSjT }m8S+}8,NGK!RjU,"j?[`œñ 7Ng# \ $Bh#7{R'w 5ǩ]V 7 Vu\{!W ׮R_tpu P*Np $9?h1G;bqD4uy!Pp݂ea lx{x2 kxE 4 M٢TJŬl+^[ cKկ.J$ɮOy .L8I o8 Ts6%pJ^dr 4o>xmqOdnBrRs0%unŕjW!ѵ~.Jx۞[BSӀTT!cFx$sÉc&!\х\!H2P( hLy twƝp1-wRZ;xa4ur#szWFѽ"z/G IAzw= ݈)/ n7 N!ɺ#}O%I(s˯-@1i:"0f/&x \ɵFnW3WMap݌7X5lL*k84NcS1`vD8DZD, X ;+(G _w֗`OD3.AȈ<^DnYҁY[[t ޺M"TB*n{"[+):/1(%cxpaW -51Pf<p?y᭗nݫ~/;۵c7E=0HgTQfI:8*G=r~ `_Dwt>4%LFS/@+ו*Rwsdo﫯\z:Vxۉ8( H%ʗxgJzR*qQO'eam:D~ے8jyqs>4n5 SyI,I*6F,j'I"8fzl0e*XPbGQ2il&z tsy:nfG0:3Y,V7KW#pfsqΨNU^\+=NCU\l"`1Yzqӛ_'L_yt8}p/t;Pyz,?-dœ|$`T8itfҪ3 &GUUTkp6Hx&c8al6IZ'ԗG㋋d$l<&GYP-a Q=k:zMܯMEh"} ϒ. 2b{V_R j<`_ƻkBY؝Vɷ/RS0 9h,KD!2W -Wڀ pghze(MvuoZi ATyҽrAq@w!9b4^}t7w*4kAyk]}1g3ʶRʊH) M>@Nd3Ƿ}[XKO`^𜔹=iz/3~8bpi1o&اLEE}O 獊\Eo[' E&Fj2*>A3l#햔TrvŒO:omQ'>oE|Ze0Q22HI#I裗 / #M*qQq}$Ktv_ک\S4BQ%Œp|!%IVt(QqI9,TZW6YLmPxodZP' 5T^xcɳ?,KZ걭skU̗6btl~#;$=)ioaZrՅ!/oˣ 8}+q9oK. xx} u>* rxn m 1z})VY%dzfg4e!}k &aEQ bY;f7Jo*DӮ14n~LC|#;x<V,6jM9rk;=pZNa+G*GA-:bB +uEASudQm9R_.㸿γL%,2;_NX44}MɯVw.c)gnt0)7gzR}%\!L8+t` l\/8٫:X(LҖo:Xf }+G E!E|jw2!mvK$L#"T h3y%tUAM~#}Yc*DJBZOe}֧qIV4ɰo)ϻw6^j7ܮ`CxPicG$£҆P}՜"Bx[?SCQCZ'(0RseY>zX2-$+Yfxq$_R4.;NwA<J6(ɤq'$9?u_yRHP2{84k:lsu$%P9_<)Y(ƛ@Xt7+S Y<UdzcX:|fDqτge'wJDDt% VT3 o˰^ @:s>d-׃>?uh'E 8 4|sQY6ɍ +k,Rlh gҚ2:$L9u_ǛR'5ڙR*6_&;3Kt[)=7gB$wA󫈴it# 5M4ݷznHmݽ!q ō@ [*Bq7%wJ,ǟ GVPwBɪFP;Ynp᥼'k\FKiim*o1&jS Ɣ:+pP]^s&qLS$dqvj&Qk: VYLw+[9Iɥ7V@e+{AGemjXe [ǭ2ؚ_c$ZVN:/_S:mQJiMqk͹5fM[޶4e(LgF9Yy !5 gpu/^&6tl-zs :v-6DA '-Dz&`B1"9jJֳ2Ya)\^Q%gXa5V5BLHܞǂ<6c#> RIuu[UA+g%B7L-{ = S:KQ G12Ψj5Eͨ&\f\&\m`fCv$p= :tbB>e'¶ײ0fpIxӈBMei0 h yS^sy+e-j>'Iu'цYX~>'>Qp/;@42&&]`䘆4%3}Pm|7< U9"l\ Oa=ʬ<8 #*lF%.V]PB9#Cǭ41I|43Grھ2ȶῖSIo.~秷2 %~@4d,Zr8OYo)q^b-J0jo;[o;w_u~lº]B+@}:zj5UaZ]z暌O"'HGƳ̈34wj 3V&XTC ar+(/t>JO: $*<}H`_KY٭\bW03i\fیt<2:EN2I p=R^(R4*$wgs숶f)8DCꇅ&^kHFĴ29Ne`@H1lzM9ɀVNM& 'Kr H횒A>5ZyEԍҴ DU.j*65L(nSi KaM* 3jѪnD^$°g!' UZ% &a/)Z PE9Qwsr5dk+Z2mc08\vhx;`)tZhqrGkSI/.'NYDԼBpj0^#kYf%s0r 벝}BZJ:OH܄%5×P-ćH- |ؓӹ~=eyT3Omj",K3-B1E`!1cKV&L}ݦ?;{,o?!O-9 d;Py?-~))(y~ESOrj'3ځ2Y$> [J(A)qqReLJV%&JP֓&,3\GDu UDQ9;1;qRՎHQ2x[u3(FU@ryCڢn*V+?3l{v wD)( Y3Mg' n ^͓ǝ܀}FnJpX; fv5nj-6c7'6fhCgMyu,hSa(9f؟nĠ/o@lPu[M2 K(`eO)AZQ_MLs3U찘q3$ b+ C[zK"2quo+9t3*W. M!7Y.VYx;^4ap}5E)󷷱vSfJ8rK}Ѕz;;^"[Q$1jq=hzCU:YZ4q![0%F ƒઌa/\ . A?$pSp ƮHdmZ& /g[jRnvn'z|FA ސMP[)x(Ofg| ؙJn,R!0 `ZXV~cVT]d,b Kp|tI<+Z@D е[+#lK*nV@׀W<[a jm 3a-2$pt[g͝ޥEOY(x 05:GVWV+S&!qrR,0 ; Sf| nExD.X&"pМ?c> % .vӡ;n5)J)+M9gt9qFnA5jΒhPR_G#V'd|SxIpq(-bn*}N74GMOW)MCUPsCNе(E㿴i|K%o|X$冪]MhhCr(`fW(WRWYd3W5l0A٘<a#zPErIr!$o솚Ktxs3;jKٌn6W%ln-0pcm ѿ l0XUH"(S\Vp(L';87(ivS.3ʳd)sWijGYql')~XF!wH pb2F4s%* N, U$h ~oFu'z*SwgY44vU^?Lfce+}fm[mMpn|.[y?KHo<>7~xmöղvHYc5u,YS왺 & \ i0EiϯJ!{INNǨ!_ua;KaCy^V[#4cl}U gnHdG3jﰪ |ƦhLG MR"Y )*L&l:轪v縔eIjbf&,C;fԃ>} xX jrcx,NpR#e=M%e䛗`U"~_j΢-@!9Vs[kAіo>s[>[TY]gs[s zeU\ײ"՚cYR1̳lPuٕr-\LmݘBsLne>^W-:MgU~U=+akWÏ}>9N V(,d< *<UE^4O ^p[h?! 9)b+Jιz6L>PҮ 1$oڵ4Wx̳lrxI%nǝvB<}J6Еa|ܺE!}jgpP~Qgb'xsBZL%R/x3f41MLbeGIeOO]O ȁh?^]?˄lh%S<|ϭ;?[iNmT2yX4f eTK, 8j3`d4}nbCK(̈)Zkny۶z0>`iYOy5^VƖpBK̥Hʫ1C {j¹TT)[x:UxW%[Y( 0/z@[N)d#9s脼!Ra܏g%9DA!-%KsH4a9$l.ķC?D槈*ujq7]^$Eoqv{٦$w=[Vhś*S_F ڋ}jDVq%q)Bb:`Tf/T7֞{΋ⲽ-Ov ZAB:"NUh5*7Pq}Xg=- r ǜ}>m;Py3\w!֎K@owfl K^*TREUa-NZ/nl/Ngn^W 'Nl[t?@^q/+s>VW>I)yfC~a/#>uJG~0-[S#5C 931BǙU`mk<g<ƪzjܓ{7[Ku`.vVghOC3X̌ Ԏ@ n:3@8w,f1{s ns殄Oj1gSD Sbߌ3OTY]oGk+R_8 TP_4r@ၻȁRf79ηD9o@~ Щx6p+aɹwoGP.I4%8Lb'BxSg áwŕ.}N|C!Amdk8|!oASX,mLV cEg1V~hHgW۝ϻ#H*|"@NY[aɃKjtrJPKN I1FFAOVq3ZӣbϰT>KLD- ;>90ADN-K$S*Uͦ=9  i3&w%L`LX&+CǃxODdKI+UQ8s%%6*[~Ug[,Fd8TrPQC&AXϘUXR=]H5P J?5F8BnAAWJMG[\" cdAssq.9T\qk%%6C` %Vu1;]( &YLC#6a?(xhI?e j(k.*Rw6?FN٘ryhǛx%؍pPxdg*,]PKS: >f' iP;?v)zl3u;l|e9ۼ_Sή~ru\rvqIE}!Iۜ[Ү䓴+w[+wf$mPf 8e4֍O^&eJ^Y!QW-Цb?>e@&~'ݝzB(}SB\p@l YإqjtZ=u\?n[9%9EK| >n4۬fz%¬%,N;X+kLa Ki I`8Hpוrjm1Wނ%ȊhKڷeSC֖;x)| MVҴV.Oga](rrot zlj|΄D(4י rDƖY7%VF7+wbK;b1o눖-;~Ѳ:˓dJ#8Xa]tNp[ ߼G8gq_LhM9/` (QZEm0Ndg)-ݒUSW%̻GCygu*JNɧ@;meDv[qi! n78E6 L] utņz,|`T҆V݀:uB2I VdIA*Z&^EP'aO͗FgGi.&`| /;-\ :?c\cx M+c_4T@d⦍`ŏG}npf~ 66n%9~Urh2_8gH)`֊l,mcRj ov̱_ơV-[$/Ӧ}O%s߉À8CR|N?zSXaY+e=M DL- ؔ;;TMlV>>}e)Ղ°YbjGtٹ=e.d9n~BKUIS6zt]Jְ bO#k )d46#f:Jo$\Ix<yUO7T1HaL'G҅jșFKeΤlҮ1&K޷Z5[$Ƞ2283yRzsOg RXy~1!j( 2Y(Ji%фjo=_|"lwpVCfE/)w/ʽ.FU݇ڵ-G⢕q^Syel]l}AydX%gC^SV5!W⋄U%bJ)nea,0/i41$&,#e!XvO'C!դSC#2'rgh&>1)p՟+ .Eu]$?9iQ] ~@GԚO\ 1g/Ë+ U![™yh0R%S>XBǚ}A<Q^+d05_NFT+?P W<+-}pK|^g;/wF|3Yx_ڀH՛+N%b>A*"eUڧu&e`~RbmQMҀ{1$vd/aRp i\Z3s웱$UAfrƘe}5JݓZd2';?zDx t ;aHgS.kV);0ףrOzl $Y>Lj,ӟG?.?h,\8$,+BOpB(8;8GU+r]ShCo&'/Jo ;_Zz `H'HqWꃐV9,WV mז*`˖( V^Z6\xΩ;: Vҁ,vN[˭_@0}>S (&Ҥ)͹9 ׃<9g phr=W5H5mEAwa5EtSQԋO}x0'j`m*%naoّG/w oy<|yɁ_ ?ȟҕBީa^Ҽ,Ȗ"`+#(e-BZֻ􃸅37*۸ dzEگZj B2),Y|.ΣG. U$>6'>' )&i๲>я;8954|pHwŭjea艣V#,tq\ӾW)KcD5`!I$![%״L(.oج wX_Sq#=n\]zxzFSԕs^+\*`>cӉv}9\ng-~[zKsLǚcpd_ Iv y3ع4":|%/ # W3E )y`ҹC~C3h2GݕIp4"'Hn[/u ,e`BD;\^+9XMU W)W\#@oe[$WY"2]tdr>l 9=mAj j@ j<ǪMx^ 4X$cn8($%[m3IaD30(kG%׬QoGUd%/@y89JUzv`f%+VGJJ[RukUvϑ2@KZ#VHJi8#5Ն) ir-WT׃V !l/Ap/L TL[2ɢ*YYJpv0{)<+u"z/WUxE.Gol=_) K*-r'S> !45~Pnc^yG^7XJG6g[2Q.ϓK;ţ/Q MQZ-$wkGOEU<܉ţgyW.>h'V.h'dJaQϽȺ|&K):TRxZ7aѡ3aKW&((-+XLkf{+3:q*h&`GBeg\Jc09%L păqO)VLAhS8{ZD6OX!5%噜&nҥpjGʣ@2Db1kxKY"%ԫFEk;bNvEN6#DJIV$t~QŚъĝvKQUT *{_p+"t0ex4 e[) qȊ?KsBlh*͕ is@DĀW0`xV Yin*`?l^4T 1B;hBא0ъJÊ9VBJfNteI.'C-8b椞WRz`4LI`%KB]"' )$N :9j;Psy;6P윆fӃ&vO'|*9bUH!PTw[{![B}|`hwMC5?j5|fZ-$#{aW}o&“*$LYS4~-cT<0O4jL\PbaǸ{/уLε@uQI&~U`w5cDp,X ګM:ik&0MZrIq:$[R07{ @c/K<«’f]}ƊM[\ G }"^&럕3x(TDl/d[jbd-*b򈬢PFA|'eׅ>4P8}JgP'.ru3PH:.TW(lҡ4[궠[XN!P-ǵ(-4I45+=9aXΖ=)Z}Ú/s/e8ϖZT.JwW85{zjYe "d*cc69AK0 :peUfKJ9CR漳 V# :},}īQ Axf+F919; g2N9T0.Hr0'9G0ag~N덴C1NH=ם*dàЕ99V6rLoshTy@}PX97FKM<tFɽf/neк<ѢF|Ƶ.wy<Ֆ-Ѫ^If% )8ѽ}Q΁nRV{c#^TDtP,rN_Ξq[^ '|9伜 8jNg 隖nK^lzlG=}<6N<•xhtήt:5`r{O"{L2ES*Pg3hыF0=GܯKi߹ύ[ޏ<wc/>'c+8]YFx@s⥗S/M!!#_nqi݃Lrgx1sk8Li^,/ɀ Z:')l/cKAz3_~,80[z95"z_a6|SG[EֲLdXhXr@u$[[| \kdj4uG"dUà >{oiI0$PI? cl+~VcUpsW8 T~R~1#ӷC:EjT[#T*|-ԑ"Lj1rR\SjB6|=;1Ht1j.tL Y ҎEjw +7NdO(o=BdhC{$rqt /*4P?Y?>!x xfC%ÇVL/4݌QDݐ"HRDFpx)NkF~/hH vP7 /PQ Wf<Imώkl<=5Wח Z}\[ܫWNskn CJrxBG Ҩk2ѧ(4O(Oa3LoƏKb4^iMq4ضLQ+t秓`<0\$wOIul'ftCȨ/dMN/In@T9F`DU;}R&RdqI6jMN4)oŻ_oNaJDLމ\Ꜹ0 Mi^ DYW9 FT<3 I_G*1H|e%S0?Y`:du7oHgԃR齭>y6oY͵'8[}%'Ճt-+^(it$sX̃GzYrREr 'zvUG΄TTzaiRMNǟn0M4 6I08U:*FI],R ƣF qkuueEM`f1Fh`y{8z<bZ+"ڠtRjMmKUwv6yuGCPͻ2socBg*ZݳK*@!dgJ)v)84G S[9‰US#tꩩ7Rn܎f|MxPV)Duyt#*5{ڜSb겸APg?i*~pCjR񁾫UpfxX"~Вl/Y3~`r,<'RdNu#$xT JU*?n*@U+X{| 7ʜۯ*dK~wgr TD  uhJ~Ƅ"fW =BO켞 Ek"<"l~Sz%L_X:^'tsd>GwG0"/N7}Onrm,@yۥt>znA0ʯPUo (4pE u08\GI/o,ςo*M=y!y_يWdu9tnU "'(%ي-5E " q$G35yKR-Uu!Dphم4YO1.Umuj\|,= ԯBY/UQdwV GϦJ`AW輑Q۷Ѵ$ G:/{v|.kF+ oJiaT%EQx׺BVewUDyv_AlP Vq@Yv=0 L JziּIԑbղ(q6\f,a% =WtFKeQr&%?#> +'i/&Ao0RUp%YYKX# b@&:ӭDiHs%Krfi[ߩ[ͮ-9Й-CT`4ʷcGVSQ|7eޯI N𴘌!3ڥZJ&qo c0E;m y Ei 'nNE?",6pP<[m I'ۓ%.HXGwUI]IUWQro~SiT+~gOQe(wӹQ=;g20;{w-8LNм,0Y>s2}<9for<)<1bddȆ/Rૼ=/$LK^>i])b`on-BVǎ#) #/! 0T0 CV[A+ަ*$NJƫZMɖF?p`ا{J+tbY3M8M,lNI?D^mޓcxY!{!o 06(jB+ Y.`T ) jrFK/oi?6!lhTv})Bp h~)۳pc͹'9:YAm-8kIF(¶D /|ȿL?e#AΏ}TjW7(D>C`D]:o+X\2X!˲&y6 ~߰>q2et|\'pm2]UGe4;3>iA5Xĭȼ=wE P~g!@AϷgz"75FvuuJTWkΊ%%[x-+-C9 (&#m:` +LC̜e&Z!Տl3Zb6TPwP GJXkIK(c$~%ڼR>)W :؈ϵ\nr701S! uRA*TiTp9"X 46ԅП-\\D{lMP0Z5wTп蠵%k0+d_tP]:}>Y~mBxBPgK<9}%T`E=\hq0OCF/a}6JYZA)/\Ki!oLe(>DF)Y]xݷ]92d$ƋMA-*QIGt7PARq?iգç̲Hqh|doиӅA231ϋ1f`Э޴ju!KJQf-73NB P]YLs(ipѭ $[d~Xph9*n(ݝq$.瓤#ږ,}" h|=NFPhM@;]K`e&Hu,Yo}ҰۭTgQڎ|(t(-+WhZ-^l, bX$#>Y'Ԍ;?T*eVį~j>5($\w6 ^D\R>U51g̃e7>8t[ LP#V&_R{xJA*O ffG}rf׺?T|YJKÆw(s`EhDvi?ݕi ?9n  x>b`p<U4惭ZcԃxYPċ' >>)%oUܭtj=ʨD)D,Dtv#2Μo9e2}~2[>M?/+5{)Xe(A ͏.e8>Ƕ)}I 4@- 8K2U 57@5 Q"6o7WE ?M3n2V `V\ @H̻%F>U[+)dqOe4-{=dSh 2;*t|s/wrW貄Kv ""F36i,٤6/VsI BJK2NH;1xsN! Kw܊:}I4JjGQ?IHJO%8b3#sA :SΡ4B1؉JHkxti5~Qq)~](?]ehϽ;Օ['HZ94TpF>GwW_8$|7Ӓ{\e|w-*]HHpqI}!+bn$))bR8'%2/ }IG_; ߰d kTQ/alƭəQV SCP {a8=iDЈv"W̌ge%zbC`%p0Ok% ~9K^ /y`Lutdu0X(>"*E<=Bym{XQM<8 ..}uL d-\0A:3|8̵ i (/;/ @O"e?'P~z {-m_AGIzكb Ę/Q[iv2C6I3Cv O`z1LlӋʕF"b2vNz\̲}"(^ڌ<Ғ "E"Z7j \4XR]d 'Frj9I skA݂ {QZ0_U\׊cN.,@1YM}{ XƵP'2m O4*眑GQ`aA:,I~JHoRO@p 6A;3,".97vp"/[xhl`}oz,#ƏqN֛ڶZeI/pc`F:MZ˟>} VTOORLgDIgY]V"goSu('q4OE"2SN&X(h`^0`-qcG q|:]ñ#]%$.k&Q%'~G* xH06MJgu h@QדzqfMFS;Cw8Z&Tj.4nW\@&{>5,J݌A1JySV#m&8H#3 @dpH4m;C)#Bfp%2~LM0ji4j }LgT֞O_)AʁRsܯb2xP(yΕ.h NQִ)S+fۜS2ƗD[BFV12x-ұåF(w 8a$,V2)ף>8f0D|;L5n'y8Z3ZgܥJ Vͫ,v15H*;y~˅?HB:f<^(hN0V uR~C˛GMu| eˣK8(r4fQ ϣjKmO (zwj9; g?eTy6R\"b3]ZD_Z=.pajO,ȁ ĩ[_;|# ~+'{gV-V"w>E--+x9=GO坱uַikO˭hnݦeCiY%heXDە /T4j].5t#XnvPR`H285VGcGǽ^8 ģzn]Ӣ à1nl؟_a\,ɛb1CH4kkYB#M"zd_IQu#2ŗT8*_4ԣL'Sy 4ېMJӠRkY8y8g4Ha~+1 =5$4]w4KS8T0ACh3=O4gBghu{5{z;Vↂ&B!gfg^XX[Ki~-nQ76Dnz=vZՃ^0 ! bC7`GQCn㒑sWE"Ќ*RJ"Wl 9LT,q荙' VMX Zl4ŏi19N2mLȰt`$=-('ףq5~NsIdx qDjkKU#J܎)1xt R^mywGbCƖ:BPkp+7LtUQ&5Rn'78GVVf({@kZ?FxZcBVfhvE5>\#<To USmG1-l"`ZW߽uoRf5f<5n*5xvw>E-2ES%MjiS69eA Gű5#4v%VxU)eo/)O %sJ |kJrIy4b"K8iQ)?)0S=kҜWdxZȘPFF<"ƥin s!mku`'ec [Vct}o,ETbt}^՗yeC*zni[Hn{n4CezLrQ]L^<ܓojL*2AXQYu T32 @G~~3`4$AƌHX#UmV3eT\L~ ڕz9eRtFd+aV(~,S<=Ƴ9wJE22(/RC$!ӨFF-qVJD;J0 kzz)Яmu_",DND2Va4h2OW arvCwzٯV#WՌtzxZ)}bE4{o9Բ$"ERjŪȒV23TT>V,a"wK9{ߖԝ[R1 #V}aVb&Xupb&awZV6(#uBgLiQ,yF^^wMuZcrD4rz 3*)L^#ä@*5͒ ^n+00 y+o_~XQTW#A:,בPd2H ޕĞ^))J1*ESC8.J Z._SU #j3 .YG(N%lSYSҦ]t]ӕ!e^"IWdߛ3-bՇ@,"oS@]#з%.Vbӟ\-ۢ\]E|KA@S~9#?~@J|_(y(@\*uA'έ"b[ȁ#X{TtaIG#;vȡo6֔lB~ߚdٹPOɺa)+W' uDNo+LO\tx fpsyMƒI?垻[ ۡ? i!K_ zA&vkbH^h@$?N}9ʹx}al$Eh, fDlJ{q0 M5FGlG^ǀM?wxbKD:6)4]oTވo탏@mϽmN‹U1H(`1%rc &4 asK l ĵVeTA8|$b-(skp):C۝c,q*QݝD~?imŏ6z'w庱`cBn/pzĈO$WWQZ 蟥Kdݍ+P4{jDZ+wH>m=Z&`g= hitz{cU! UFj; BㄛC%]p:xy b =r \>;!: S@9W JOԱ۷"@}'!.QĥuAN#70mvHܒ 2#r2X7A7~G`Hy@[BμNp+9 qvn|F[Wx[a&M?{7XhoAܼ~?vF; /o'aJSxџRg&<ӄ61Q9H;dMdqHtI=pڪUj5٬ѯZm]j*Sje+ABѿ.BeGky::4(Ed=\T4]] ~g_(fgKƊ"튌u!;YHŃIPpR===+nc_wdWJy'ZJe/opN6HKWfzO Jшgi崂uInm^96K:;wg6屺 l-nc; `\ͭv{DpbL]dK%e^q% »Vh0 ex0sGN*o-+6 }Pu>@M䤣Nh;X/V|hJ_&{5&6SgvX'O/,tߔjnSAtEX(XX6b[ ;JmmRv{'l?iTv+ްT* 4a=$I@+j d˸e۶#==k{8J_v?v%3(ܞ>ϳ̴UqmB+><]$i .'S,ܶ&g])%}l _q$!Y}JQ"Qk+U(= ^<C>a,E-gE%xY `о ?` ]rvWY[.xPa~ Ll$Ԣ !J /XKp;9 ה.lQnubyKA^s<Y>P t, \?c ~\!zpŖMNup>i:_@qzq; 2C@_ȷ\v}%imIz(Sy:¬;'S/g1P()&|zg77f=tkLKp^"s9ʬh8 O$Î/N; 4YȚsm2pn$ż:o( q]0q# 4k3_]kJC q.<9-Of9q x5(5Rx4'?=`4?H6qIƃ9Ph aVщ7qԛDGb# sS />kj)h|:͍:-'ʴJ}+8yƪ| ->>Hm#Y9B:5$XsZA5vYN<{9{P*?)q'5Cpͭ0cI,r1 G'i4u3Ju[5H'K|WsuxPs乶v`˵&)X%/k_a::` "4b'4 a^gOP/mf=+j*$1[\bVl^6T @U! #bcoȄPY8:cbcL*t4yOY@cs%@AC!8]`MdE)Q5ǪiAwp`/< f} CZ=[W}6;&+F51=M/~C /&Bi_GsoYl8pyrv6?r70 &Tƛ +񧦾4fXs6ϱdG1.`d'7]; FLX- )\ $KC]~|1zy!|u|a^AbiɆE.'wN_r7G:8mWL$"kOjlS6$xf qh1} c1>-Nb" g:9M>L.G)y!WC, |7z+p=ԁ9G a[Er)r be=: doV*oSטL䊿V2bY@7Q>=\q-V̦IR)`I*sHQq'H֣וӖn? u*O'/v]ݟ)'ǕQv:J} HYeϸ}lzFmŒ&ŏDAYԍb~ط6'tBv 7G}jA)"*Cܗ%wO`WΛ7 mѿ/sQtJnRDS" S  Ng2HSi?W7f3zÀ&-/4aj=nv_7*sHv&AB \g@$$-*-(K>ƧhBE%L{'v=mDE+x9>x-d9~Q'F-xO^KIX1j#.EAg9dHeܟQV1f&}uPh%(ޥJ,"VNbe b9ri2ç)P$> NbDŒHFnp(9a+׋ mvm:VK4څ1y*<7Q%:v*Oа:NY! = "܊,11X̛؞؝;p I u^qO_ŻM|=9+"FY&Qt s=)|_], -]߁QBBX"O&`J8q!`QoH@`C[{إt;2bT Xzۊ2.@CiD j꼦& .U$&TIۑ?vrd91ɻdD'bõIhlDS @f*!PGaldYۘDRl׷hi(m`xxG8x1:Jt5 zr\WEHէ.itb"CDxժaojCA*E<'ONS"OR/Dz;zdPQHQŞ<$`PQG짒Ot|~s 1Ԧ>ۋ ͮx/:o0jN Dҕ)'_[_ v|חV]}Ut #>_ۊp_ u_w=oA|1trϒMK!*>c%d~3u6fF[/2V[XE]VG8H}{b;Rۺ!IzpIRTz7;so[rNso~I9$( g>{~tV>oLD * "U'7G_!H=U>dq63 ?;1{qD_ De^!cy 3sV>ó(:X#C`o|ߵjhi\ǃ/E7DQR*6m6x.-i8L3 l7VF0\>w2Vu@+_뿖77/dȸ`TQ|7?bFj"#LJ[Qf$V~P os;kQ0ȭWبiEm1 P|m\=WWv?U BdaƇ|PM%E\5n.@ԖKT$jy  (O.qx0oDZ,"".\'DPF<^&RC~ ]5'[[M`|{NHꍒH g>%QiqƔ |PP#_LLȞ|IKfVzSݹ Py-rY@J q~^FCXZ ⃗:=*ܘPGb uuaƝR7 FhxHȒcGBo^6@ʜD-|uW}H,e*rd&j.KgNC9U"1eİ.9Q޺>4oёUx>^˄WUv]VgC+ >3 'ĉvN`tKfL,$C 'L&d6r qw6egMG}|˜*_Y|xS)G kbCKPP)ǔ,q4p&[!۷NAvT 81Awk F:/i m2sb?HJ stlb35.FD<|U|Hd<33rdh: @)lYI-"TLHO^hog]n36saȕ:~ 7Gw0gbsq$:p9OK+hs5ON^K@JZuTݤ­˯E/|Oя_VDkbTZr? 03?JʻԵn89[S(8( tXq؇wWkr0Lj6&ŋ5ieIMrkҦ͒m֤%59ȭICKjr[&mD-*nMrG5K~M(?>[[bֵ ԪOe"uUmL`ᩒ 7'Kڤ۽Ӵ /ɝj*_}ՍG4qٟLf{jP!8A+V$墦ۛޤgsk CMnillӃԂU%] *$.w_h K{Gp27pTdTԩ’*&6?i?E^bk6hb`uP|D8_G%b.q©Rmއ@XJy\"((6uuXatF;mϫi|!/_xDڈ1+47W~nVW~vKg φGr۴8<O1478+F< Gks s`=oŠ +*%WJ`_ ƺ^ lP17雡$Q_DmPMb Rɫ"EŨn)G-p@R\BJ4»Mh QV`"_C5@TP+ЬVKj5%K[ΠKK6x-rQ1'~Aya% Il.pFi2Z>ûBAJ&HX1.b}'~Vk0#ڨ2*ijsFpQz aU( !|O;pQ k,i5Zm / i52D>XW* h6ЏN<ֈRfRal&lF?KŰѻ`R^jx@x>BZⳍ`x 줂w>o%$AĿ 7olwBP6< 74|'FZ`k=acU<DCQg"2Ωެ9j+cH@&pp;ۏBqz\ lP$#F2X)I8!hC iA\'>W2Q$:~F1=- AzɥOQ9[Et7`t j[9K ڿ2:tulT11/c$ $;XXݔo_ 2%S0!l I#.T K~ݼh+&+ 6TVRit0j1Q Lt,)QmHcߎ6<m Q7Fn&'qy3DX1ʸ,&2_?NFE4D.B\O csqsRzBQ=$XdRHCCcHu*=k7>>؞{3$5kE.(_O%xO׷w:jNb|l@9vŪł00QDc;[sR|N$7<ŧTR*NGڱֽ(8l[Ip0퉏1ѫkbB%@ +^.'%Rb{I)g؟^RJE/)%R^1NPPi0 eRe=P( )hgbw3}D*HRGאڑLQ"ATPp_9z."tn?XQgV}W"`dK"ٽhdeUw5@S2p8t;eԢ_睃Ͳ-% +J8by^G'%ft١{ ezyY.nfT2([AR e "Yh9K !Qy^yxLOÖjLb S0n$~e8to"/5jc &٩m.Xe. t,cZA_HF)+lVjYyhCJkp@m+/oPAvK@e%% OruViy(`+I{hřid'r" R3\h+D0R8?!ARt+}TG<;)HtwHy70@R,P8@T&QygCJFdi08(6"n[,M,ɩ-r,15pRyϋHNJ5mt7qg3cN:\ Feqe7į$-!ܧ#sl8In`Nx:&[[Unk8Np61rDS!TLn O6X9NhJ1qE,}ӚpMxL-k͚ Q-MB RI=pVBeɻrKܬ1u$U@CXتTk^3 TU 7Hev_tn # 4 P <:#d=}6hkHƏ&[3bܸ"jq4e m8-*ĞBWJi +1> =;$T"yӼ)W}.NSv! NZiaS^Bۃͭ7\Yuy՟L'^ vQѸ q-ӝa*mwI#sԵIsDۍf w/zꤳTVP;HK>? 4jsZ8We?JkY-<&NĂDǃ1 3Ɩ_ųl;&ӆ k5ÒJEl|T=ٟSln ('%^J_ `Hv5Oe2{bE`ˤF INO&(w 0a@QN%W~nd֣mn205[( FƤF,2 2-Qr/Cc{Z}TJ;E9!1#=f.c;Du&I|=9x@2 ;j26 6zd}a50t=K(TA,9x2u/Z2ߣMBO6˄X0+(Őݷe@W:%4ڰ554NbڷįY܀oddi+*Z+>< `f L`^ L>i/hI,xv,* *3Z 5\ofrKҏz)-ڗ ̕kKU؇ h]];uXlSm&KI@nѷ%qpm8ltt] q]Jq?>}VBÕ4c9Q+!=ru`-ǫ^*s;ٸ- J|dWxW3{M[$lFI=\̗: ؜Ҧ|]Zp"2ĉrUӚ20{193[lK, pVdƈhK=vS[C" hۂ, ~@ױ A YsFo8]H훼 ZWdm=$>'Tu ,PdGg[~2\FTBaJ۬QcJ#M9А4#f5.y/&a"6T6|oQ%=NDӅԯ\C5jѮ'gX|w㏳SXf9} +VFצo6J~( *0ɦm{cDmݐ >ǣ˹<=ju1]pi^pM@?{/о2 Cю*yu{^rz v!VF_.޷+nUh@^o"QK$Vֲ=N#ڭG %&!Rmt;Lg$TFUy늕:V@JRC4e78Q=ԟUJAG_Zaj_T'ŠBQDJ-ThT1V niնR%JZTWXzqZ@}=v /ܪ|N`B= #ʡFT~yܾV)$udf`+klU)349ۉ,WBQ;?tZ RX,z(ہMyDDphoT̀N-WKrxF J;a4D؊L qv#jn#u6DtrK

    Z$V^W>۲دl 횫vLe*g5vZ/^;].v䰉隟9#K ~/!͟c]eIl"*<ߏcVwڝB撺Xƹ&>plmG~Q_;|YgW},K'sŊ-0~ɊFb?mMe!}^ 7sϯv>u5vaGpE%|^T\Xv{w%Siu~ѝiwmw_G/Kc9]dz3\ԏ5[&5lͯuA/ ב߯_߾<_RkfyKN_Ef_w*n;˵@E~4KQ'6ܑ6a빿ͯYgyad߼:lI:pd`#?g{#hzj8b9ƻiY^W?#u7>WYNJ8;~$:[iv/^'xߊV>{;5_{bjQ#c/&SG;YYv5 Y?W O8Ptsog̭߁٧anꉐWX__S:5bz~gWT/ 1#6‡W/rsyOȢ_m/rjZjgg~?"uRNv4tިv1t?J.OaeOZ`zp j}=̮_\o*^GOLoydX?q̵yc`OwNi/m_#~A+Wز%Yj+ͷO v;YF|e_òR}R<~0ƵXR^>ysym߰_ޗ^]|N ˫u o7^в Ѝg_CC)O9@W>`vs"ocD%itROzd#<{!tëUÄoR}N,g=[]9{DUl~#ԹxϸO=tm5 I?<;f'SPBك>bm d's$yjYO<'fXf0,z{y\cך dg糯s+'|k׏Wߢ{hߡWx`u'^w\71EnVr9u4G7El\B)|g!4BĺTd r ;F+ځ~߄F/Ոl*AX+:8 `m0  V5F=w `( &@Q.۴39Ԋn? <1@WEq"iø @%ERt;-߷QgPDê`u@l*q#rF.rXQDg0[=%Ȟ7geH)c֒͢c]4.vfK sOr/lȁn;#Sn5C}hv>g )rVO 84|%M`*O y mn۲xbu 1ԭhre.{*jrE?GhxAnVͭv"c -U +b-Sky DM&{O]AI҄~3؟NPN,3+Q^͚r nlE\U9[1ʵ9g P2ڟ-H0CrE37Ay95&K( db6lE(!) :rLZO #-ܲ4^#}{ٸ,dFZpt5l9WO^#qN[Ћ97ύiU.~k+_pg+0wh9FnH|y:Mf?[/,ESQYg6;F&ϖ;nSiG4]+`38B9o :9Jz \%UC7_ꝧZ:ppVtg+,K\{EW/+^#fVS/jHv?q`Kԙzϵ=5 dDCS!_bN]Lv| [V.fϖEih&U)%p-2JԵce4qE?[qZ; Z鬏v\V gKǪumP NĆͬfϖ`[F3Kr|bsjbKn]KM#ڟ%X_FdZMh W f?[=aі}c/o_w0)2g#^O 6_ȎWVMhI.$PVTR4t )* O%fljpgK,jXhiNM G5%!@F?[F4@1r̺Zy5)3rxԋE7ƣY5PHw2S%@E?['j`㲅5sJy&pVE|jY=~B 4e>rmesϖܛ;GmyX{>rg+pk e"9 > f Mgi2S&v|^`Lg*ي17쨫.LIM5jl"П-2LՄ 6à cRT, dUY^SVÓIiB[dM1`[97Z2W%PϖB~BYcul輞(YK"ΟGUbUѪ*̔&3П-܀Yzbﮩ/ԣPc#옚ZM"̟WfWM~iUuơ)d%7)XLc,ʺvDM;[ٿijf,qܚI"ʟibQב n6alq]X<{iיMX#ҵ2يE=p$F_94uWAfsۈP S-|3H=%15UŊy;'`VAݹ i6fk\.ͫ&&-s9<"8+*P1/ {3̟?}+#ݛ&51҇!~ `u=LU< oWwv5KvgK!ŝ{iju'}Un6Qlmh tLEkjP4SȈgKua*VPCsri,&2̟P fViЕTYV`=q]dL2ĥ0֬B^[G*Y'`Vd^zo+%4Bb:4QYld%Ơ^Z-scHXg~?.%eEN yjC}ߚgPע )dB%+r$/wL_"=.rPg ԆC3 n1Y"YEc.%0)͔s@$hYtlѼn6XHEB-.%/+Mj~uJn2E ö1ҽ1XՖO%Ld?,dICkuIY'_vT hO S.(YQCub QN%Ѩ,W2VІj _#uA:4'Hg[es%sQ)|e ϑ{jf%QF# .r} dD+rUF $hW$upQf)_ ^Nϣ#ƹTM++Ʋ1ҝ'`%!#TTak1:5@7J.QW07b@ӎځѥ,h:J%Yrt}hf>/ͣUjU Vޥ@j*QUs%粎aV|G uOhΡQ:. p+I$J7:8uyx_Qa=#;2E%^R^PYwθS5P"5gG"F>4%tmyKTRvJȑs UӨ5..wbd ܖHw#\&K"Y]eIAFMu%Tlx~MSu"YljA[5޶M[&:`h*Få =\ٛRt97K]m$JIj1){Fr=g+.k&!UP|~eR~6l|wE{ |=7Cc50έ,'VQrCA1'M3xF3ҟ-g YetQ9{dp$`|~lIv5ơuٜN`u>17F?[f C}#wPe?[bQފchr Qډ>V- 7`wT]0}jrSUm|5Mf?[o4*j"CS/j prn q%/ˀĶCT.Kߖ C0:/ͭ%pV\EUILRU*7j~6qhq` ̈aV"0,ي1Dejf ecSc*1mZn/< N]KdgFd% +fkGtC <0F_Yn:{q 3/7cdU> \9>߲J{]KM#䟭Lj|G @LKL/4/i&3蟭tzitN׵\-I<2ْ|'wIM:Ʌe?[qR`>ɭs:4TƌLً'= N`ISWSHj/zCt@E?[FȪ}U"/n gKn1>.[ jWͬf^~lE-1V)Ο[dZ5\4Mf?[QV<ޖO1|BMCN6R+MWV!N#TtM0[Y>4ZrkЅl.#ْ.U4aV^U0[3+ `Dx`FUA*Ʋ1Ҟ5ɌgKrԇUy\+KZ50 <1Hz̪#8&i5KBK"- 'pg0H%1AaK܊n6Xd ^J$h5jr)ZK"򟭸L\K~jqKYs9;4 ]4N .4&՞1Lv <(ْ0i^_=Yc`ܡ%v0 , _[|m24NXKD3-< qSy5%z TDUYUTSfdPᓬ2eh4=J6gѤ*ܧf}ŬZ}[ȗԎ|~AlI\_S?1̦ ؉D f?[fqk84u7 3t42. 4i!7[OM%pϖE{J2Ӯj䁁.kn%.esV\QBn/($7&Ҽ1̧1n@d?$/)b%uz*zAdgVdriܨ$7\c͔#W܊nc qkf̓"xx65#tkyZ~alI^&pE˥Tt])5chr7ˠA%@?˗F@Pα%pֹҨw=Jo+Rj '@&3柭gʀ.C95?ȗy d%yqxGVM'95vM#柭@uJ"&U1L1nXwu8xX%vQP7R tՁ87E?[qE[,jqfR4˼l0#0S}硩. 4sj)]/txΖ)ZwCYcͼ#O ̼2Bي,NT/M 6k-8esϖE\uwbuP_Rx ` 9=oއk0W~6h]&*KCPV 0UWStg+0MWShyZ&vw15@`$OMqPVr|ij͂왗E>ϖdq'ɾ2?ʰ1!-U+ dY5/%AM\`bcmjk; `%xa IfGX7`w}j%{\$$+acc䆡 O #蟭̷JqBjPujx[l2ي,H,+ƚI6Fʳ!V u穹ujXC Ҳ7/ H$;F%V\[rW f?[rRgkrY8LȈgK28", j䁱f|hMf?[ə k؆qB{ކT+F;L 4fYPN 5lȉ>AAVdqz[5l\~C}^&3-Sӫ>C7:hz"}_nl ^ j5.@irE7 5 Zn$ƚy6[t]PO #-d ҩ *w`fc\ M^l/1+4ɭ 5l-c)4/?$ =\yb/XH 5lȉn%`V؁!Dymn~db^6y::zzPet776 XDyb|NL( jaf^O #Tde$cʅf5`  f?[ǀaP0ƸC4O/6(RlM"Sf5b/d7?!W-3n ߿)YL4š1CƉTAup6Cjr~z9?_گ#?=ip*O/X7#[@עZ˽K~x=k7|ރzZ]ٵzaowff?w_jBA:OT, QJFA:=:ǒbaG~|7=7: fh}ke,5Ijht~<~0c&'ZE.$:ùҕu|#~U*ٮ{[K xx/ ҧ[LfVD]7;zkO9o}jkR-dSUqŤAjz:і];\":4jַVhc9^1چskU;>9B6$G1%HݻK 0b'lW) 5dxUtCB%4mTK¾U p霠![O:cZo/xf$crXx5OKj?A+hU(RN.VɌOkk֮ɭLBkG}sxcmmL]suI;k/ZIlqVyw ,{3RF8{X$e2H6C"*oTFi[ݯZ^_cG^bܟm~n=ǽ葋b룯ڟR9z Z_Zղ_Ͼ~{L2 i򀏿~J|wx3:q/EW뻱w??x3 8R=+8L"gE{8]䇗g^Xᅙh{0O61ɧ4' Z9Ǝ^#KiV:JukWezkjynzi5ʻJx.֑o+_~?-P׻n DV9]ը%P?s'1wψv\<›uo^g|~/Mj݁\lyAQ@f?׏5u醫~[ 7"-‘As;{c& jcïG8_RM@h@hg-hY;xd`Bi|߂Xhgk*̽22+4 4t3rEMJcPl2S%<[|KyXo=i~yL f+&vKgj8st+,hWoyE/4l7_@,*@-ڽoUpL̖\CuWU[P4\Wc[{)&%-s[Mݺȅ ~?ZzO&3K0[]E߶Д<5ǘ1(K0z \p0s3LU d](u@O^~Iْ-Wr:+4?vVЎGWU7PJ0+̖սouqiXֹ -y[|g g#a<9 L{ dfd*xu p|=uZţuqAR n)ي5!CoM.{H'`& fK{fT[\@SWHVdB4pϪG}z` fK`lT[hY- q樺O/7%lVn.hk5TfR1K+ dd fK2Úc[jh(]tjQ/? u]^ny:XՁjP]Q#"QosAOSZ 80Ӣ@E`-(VIj[O c8[)=5P+y`%f,aȇ,/e'Ή 0r%Xz (Q2N/E7lnbeIz97$l VĽnHoxZCCV ~IيzXEgl.S%i[^bKĝ! CP4hDe3KmU6ű\?*2%xuni0Wh(F`g".BL.lAhVH"v%.ʉ*mb>^SM3G42ُ(v"BUO=CFoy XfKٖ̂?PB>7uI&dffKâB<:sSjWO #=0[KT2_a[jjtV\KaNPTd\rLM#90[ ))Զ]dXHO #=0["Y ۗ.Zu7HydfKaZYUz/2Z{P@F`"7ȾnRYAZYWjsҏ n6xѐ 7bcN_nE`"wUQ\pܤH̖\-%VV 7U"AԊn6 ->m wUw5y dfK୩5}YHW4]s+'Z]"anHzӪ n3-OfԤ 7]bF/{&rh#4 f?[疗ۏ-'_zHs ~@F?[WDs wbV`]U~OT@F?['vǠ(ۅ2+sHP%l0 \ ږDٶ.[.``p4_t@@"4ٶ.Gۘ,*ْK뢚*^"qnD?F؎|/&Rj{S=?&bYRp![GYkZE7ctKBpm1©k@`pgK../ *l^~ܻ!hl.cيͥ'A֦i墒{?}32bْ =+w <)ZbV0^lU|lajf}Q_^6l]q=ngK:K"🭸wRq-'aCS+\%WПA7מi"4ŋwo] *}[GwχHC73䟭2C,hlsm[N#0l2Cْ:D\%7t(yTx dY=/Kߝ>3l05E#B7&.]7ν9~(5;: LV]kKgX99&2^%Yݻ%w0?4]fyy,[}Lhr\aO #C*'!]Uc:hkNf7xEP6 n {o#d?̀$LqUɩIqoN lVt<*ي,cItv%xl.ي=3R&! %ǐ!V[fSL {aYUgK7.M,I) PԞXs&V g+rin SO`k#j|E'X²{̒ҟR eCҹ#}`%ۺK`7UC2@ ^6Z[wr!vg<`̖dur@^b7TV{CG g+2{xNz(,ppgKp2JcY{G}mtg+[JƬ\\f/cc?[W~$ĨL44SqĜH"ErO7oyk l0:8" vS`I^M#Ο_u,yC~Z1jtxT)7s 19 gƯk wFn{ XY֗ vL;C7n,:6w\)@ ;r&Qal9N;Teo{ `D%xI;vAY1X?ʹD؝Ӿnon#~2̟ct %ŝu<22yo%:x){70RF9k&Tt g+pY]u%kc]Sk fgK`յ ɝu]c~KQRO #̟9ǝu~wFak]?s$Cy[~ $ .ي L9GVq5H2/`%xH ;Uju0]+ dp0֝E,e,Vi%>'`ϖս˝Uir!8p~6lEn;ӿ_ƹ2ي<;i !ɝU>jeVG(,EgϖdrHniEq2ْ{H`a}F~#⟭ew ͝VFj`VI 4MgVdvp }AvsU  ܚ`O #-ɐDI.ȍQX;W5XSnBcɌg+)^$ON( 4T02kHn:8t[ӖN0b vLCf.žfϖ)^/΂8J~/5ιUh)E?"|蓄.!y%!fsPȃn) hu=2cSJO"* QQ"fVx9̖տjL#A/?|3h55n8vVRFo@E?[RWU, ^fhV]R ^lU皮`T `/OߟЏnl2CيGKq3 d㼔yНid67Lͫgϖ[ z;’qZ}?pD#*謚W$u6.5MMG0[r'wCI՝Su%63z&Vg+55h6L%.B:W [F t*VN&Fk2^NIw"X;qU8I2 dD%Y t\w&Xsck E?[qE.pTVNc ^~6lI^I^Bu5yv AC}J p'm$ ɮC¢E]Y`폁u]ߚV.A"twM(7tjNE?$s2$QwXqY5ޗjg+r!#u:s9 ؇$6vNZYFQ&o-%pVܱȝLy+N>4fG[lO#}DXwW \!78Y¨6-S ; 9\qRj%gKݐBn%>i'y&3\ `(WG @_~qlIY`CJ;-E _MI"柭m+(? z[%Sb g+ܙ]%*Y~g.&ϖ`DfRsH~Ctl2Cْ:'T"K=O``-;˰T=,)*J9 LV}kKej6A\|e~2ڟswn%gu{cpg+j9bϙS^yyH2dF%yuopq*@ڮoⓛE?[qC)Ź0F?[/|Aҽݹ_oQ< A~(.r=(ӿ$w/^gKR"F˝ Jq ~6!lEn+~\:?wUd?.޴%W[u|^9W K"ޭ Ē k[ f?[3~ F8g~lEfYqQvl0ш:VZU%᷅1`iz7~g \SgP6n`VnȝPw%^G̐#b?[ qjj_M#[ Nxg+] 92J~uSpu*mߚ[O #̟-ɫS `ÅÃt%zl2يwz#e ;,<&XtgKq=epg .di&3ʟȻ 6:u5y>㴸BơPV \ ,9'`VHqT k[Aը_~6lI^=mh Jpļ6lE;ϋsoݣ f?[Wh(\)TyђЇtEhDU疨hL4B8p4a"@Ϝ 6x=V: /?h$V]w% KB6 72qȈgKa= vjl'5'FahvE?̈"r(JR yKG7ϝp;C`0U'{} nmgKrvYe'[1/7tE05WGjqvnql ^+S/<l2/b4Ø+7&Pϖջ%_? |( l&*TVg+ :bSZFRp_4L2-^+%M]G'g+.{ǪsI`-j䚥cM>J^N_WCsǩҖ,"y咠rmskƎ.:wMRwJkl!)-:l.يb*8qYn-8K:5 dy.JRՖP%2BْjnA2k~MW_JRms˘n/wԺے_ZK"🭸eu[5q>T5- ?d?"6HM:,Yht:8>,72շzhV݅Y_F G_~lE83uE%6v;5D~?l.ْwWufuaiT1 `#tNמ2 pzҼ n6lɭSqUwԥN9OM%pV=rkJ~;EslInօϔeqN13xTe?[aս;\0KrKԸ7}hjE?$ -x`W.(,G`F! g+ȭemŽ$0ױtăƻw{uyp-@wTNNlUߚnYeGâLߍﺀ f?[N"x/s4榦XO #-ɫL34wHn1=voQM:`8ۿZ3ٙhߟb^APiTU*xhc Ҍk. 0}$6T:n7`SȜի# x3!..mpzQE_LkV1WŻ|ΕT612#9F;|p?$|kx}\h_FrFg+r`fnh+<_#iҶqTAיq`lǔ`Oq;P 8#''z9F3 = Zw _ҦmY>:)ޛ5.ٳe:ZNPt61ӕTLI֎2/|R4}1ڿlP;JZo8*6cJp˹:f?)qT@؛Y`ǔ`_SU`CjfD;|O/Y`At@k S9#ʍu*{釞WL5nC+c4 ,Z9խM,e6I 8&}1R%X{p1 V"s?$1P$ h72R-/WaG.LEf h`Ij-:ج,*wcJj?W;SfKtP{ߏ*\UqmLnFIT{=1'z?ձ~L Ql(dЏw7;\v;}jΧz o%aN`y3seDr|)*6gfq*^fASrcw{,;MU#w4ш͎#c?"\a>`<<ڭ8pגߏm9x{ lpǼn9*Hv͎#c?$_ 8a^`nٶF;,odSH; ΁0`Z45ӊo )qЙ!ݩEB>-~YE}ͩB1_u_+C19FToR c=92 2cTO}MX=3q0rai 8iʴZA2GtbT5clRd{DKQfjo.5[_ bhNk:^0稊<DYO~?LeŢ=rUm|2σ`pNe IG2Fk5^jf;نF[V'xU| ~n4-쉖%SiB9VYn?gh@՘F%Ը5x|t gcL-w?-(?i!o y{'6!/5ʃ[W+uT`e2BX;@.1φ9MŇA_/ Jޑbѕx͜)!腨DUh3#.'͍pBid4HތK`7*`k?m՘'ci}{ l^mrvYoTUV,Vʞ]NT>k؆[vrz_x0Z6Gv)K=N_k?go'ASW4/81>kOpcھFh}$N8ߗ߿lwM6/iO435,!K(ʎqo笟oxt3և-a;&ea+Y̊::65݃H']W(ڻ\ q1uny Hs{un}w2\2l^kM*.gETa>ˆY41 1U1'4kXŚ0+6Ҝ،K4i9&V^t55[܍N|3txW.zz/_oq~3ݣV/bo3Fƅ%,ٙ+NmaaxBrW*xĔPT-:3ӥbr!&ޥf\S^Uv>uT8Q'ޝ /P4uy1X-2|eTw[R>7;6mA2!0_Q*DwYe4Ę\\rْL_ O=/Mv>!vBkדR cʈ1ޛcbLEnhPM<}]@"YQV\3hCŪjqw6kVW,x=ƔŲ*-ihȨt@y wTh:8Yd:>Td;`y1w,i^jLnԧI6>1%+5؂4u͞h*nv\;W_"މJO{ZAmry;`_5ʰ5ls3rk&i{;VyS'=>)u{Wofg1RS{FKEE>NΎ/2QtگӁ?do_jj*ϠcrBeKD^|?980cj*Û3=nےY,+0of1ΪjU72jpt ͨ! Icj\X Sɛ~BujO/D3X<)ekyMWw?!Z򖓢Ry+蘊+JR-zҲFf> 0c{;s☒lmZI y727v\Khaueo=,gHK{ek\#G;蘊QiPՌݻ,*m0 kK9qۊgW's>~tn/v{7ă蘲H=[ecN(.<. 4fǑqS ȚJ҅LݼC7g^,2ϢcJ6p 8V[KyrRAQ;/Nrܨ+mG',U5n'6sUr+'ߌf\CN[ꝥߥSj zFՄ#݊+%,Q`)DDcLTHzס!8*c*0" Q?fUU6Hy G%_,,OcJ,bvOvA AaOl6Nˆjց&/f\ւHl*AwCN28:,VT' ~ 2ZkONԦGMLEFԥ5IFP}eGV>f\Q؏ ZeҍԼ/*3xS+4鄟l!nY" ifƁq"S+ڭR> $R5(ovG1%d\̧ PX^?SRގ+m 7DK c73c \V6KrAþ\^?y5G^,2OcJra~ȕڭ9(8$'h FƼ}h|ǽhƕ g1e=NT蒶n9(7,.Oc*.Y7`*Bj9O%fƁmR[B[AP͌RJi~XN#\+G3gY7T͂BS9Nf⊄TLYIG GO#SCv15r5y1l21~TnFÞIJގ#8"w}IjlhTVyXtoffKV[(_ 5td١ʿr`:,u2[fQGUAɜΎ#d:"ToF`M۸m8&cJ}~SMvTa_S{<"pۛ׌7cr[%vz?/MmތkvS6YF~jvĕ*cB5otFC.))7;S蘊Qw4P|]*IԵ)qfǑр.!+O( qF5MN͊kZW3Ϩ̓TX)kfǕ 1ebScDmR.8QtL [E OTZ.]C73 h}JKILt4Zq̆y"ZygQ|KqdFǔdF}SZPRyzϖoThjtf1M0n<%RE]8nRJv\S^yEYRQ &T=:U0HǔX*uPFF-'0SFLЭRR:x<!o8UͬR8:,U>V5 94ZXގ#ck/"T)%_}iVu"7r2~Vg1%\sC׃RQ<OL͌kRW5Z/뗊3̗W+:ͽU.Gǔ媌cճՠ'بz=Qe78?** ܚ E6OMj1`AΌfy4mގkNy}KܺhNd: MJRD:,Xgh2**Ne]L8.mb:ԮS bUP<YQ9ŀIxdSu4 5}7 lGE_䀗"sSPlkuɃ˨Kmf\pS:Q wMyϋ[GjTfYxrG8pUΌ6s73 <1S@;%ؠNыS۪,n Yq o 69Nb_E'q}aqYtLYTnGXuTC5Bu7жyY`Eǔ`[06R+zaځ+lAW$VYq\  F[ӌasiV[QMX ˤnTe*⊄c蘲T\a6r&Κ)*7<)^a3mMӱn}o-e%1qL Y3w0ɾ.ތkW5Zo.8W4 <ԽbDSOpvjy<+Cuh_mB*zgW?a}._"O>ɮy,Q;HъP~A8߲'vmdr9Z.z/Z^߾fnmv,&m"EDqe/zu+hRCJ0});jSmFZ6vόb9W1/Ѡ-#yGgˈ!tʼns p1_ 4ye5t (Awɟ5(#4= AQjC~'ePN-lYyȮ".߃u"Ѓq8o'hg=Q'2R=-?>"dCn'b|0qʚ<*{V+g!lੈSV;\NW.–gAAQT͈~Bb{J2 (W1FRO̬8rȮȟ /*%8GIX@Su䡚)}M1/e!QR_\s)h8GտX@[W>+DoDryC.bFLG@ؐyfxd~{bw`֩;*|APrݲI9|Cnĵݲȕ&nNjyJls:ZsCw"CAuSs}CnE59$sUSV;~8 {#1+rpCp޸&;/!Q-`"n~~l bu%]A)Yԏrj2v.#oVZ@,?sv?e=QJ-bp5=o3e!Qqjlؑfg?Eɔ;3pmCv'EXG\NN;8(~EX&7v+C͐=@!҃NG5ڱ%Ru먽nTX6boܸ54"ثӇiH7F ]=I)E紃}b^d X^Q:NI$qHf? \e-+E F.>mm R)HAMm x~0 >Ԟ7T Qmk燜wOyyI$RqHE GEks'+/;ɟX/x/ܓuy7;Q1e+!ȸ|罓}^jj?)lǩψ1r*OYyȮ5S"&rvpr;&г\6hoTM6 b;2pofDVV4]n_}C.t oYyϭ{_ikqOqnvt |06h4lߔx,G>۟@.u'e'qOnɽYcCGVKTMwpXYq`gƁ?E |?C= 10~Ā "nΧgvb?Ewi |m\of?08 [V;ɏ7WޱC')#O7}d29w"1!{^Z>(\S^;ɟ˻_07,G+ 18Fީ:u];8ܐ }1._cgCNr+~>}{1C; *!'O7x={h'Eեe!" qw=SC"\j8F,)+9yd`d~{N'SrGq`a|{F)&cH%!?an+i)'OQ=f)l;L7o<qj{C5 1H!8\0ne!)!s.eN7V܏a/>s;?} @JA- -oOQ7]A[vac^e ,4C qOQ7 Tr`0?)!s?; +7{qlU9 ņOvjN;;ufQ)pSlg塒DLEvVT?IPN0c*D7y䧜gVXn# t>`#] (JPb/}ԩs ƦL )W{|CvEW#'c?";{l&1v uODu P(4M:C>:+`ǔ`!9}T)}CnL^r N,vcWX _O(gàj0T~?d1a.*}=e!5MnLIH}}r?f! 0mQ fLv.LpȭiO|@B k #F[Nr;),n9wٍ,*c*{#L"5\{,0cJ/ m rPM("E2L!#y\t;rܹv}r?_\;{%M,cJ[0*ټN9CF*.csm;r)68,c**wްgw:\lT\!ؙ0jJ]SuVM7>sS+=γFp?v4z\N |"c9@bv0ҕtxbk?7&ggd؏醽;OWKxp[?: Dbo+5=燌+`T`87ʛNuh \drCf'1%S(az}Cf~Lw}%\Jɛƶ~Lv/Ik!cUQ1($bA N(vcs[kpvpN;؇>S=Q!OW1 `"\_fRO.H{O4F!/ 3 p!Pt8cLjI]ӥAIQ>C"w“{kFHmΞdʧbߖO4xP9avx!bC‚5dFt"T#ǁ!a7.5. 'fOFxj929a+./{R4nWhU*|'R7KzeO}#ꥪ}~~Z<6׼Ze&~^2b[mf}k??{qf7W8m4j$ i̱-f_qX#Ʋs aPO0!|'6eLR)礙iZX⼦RccpV5kM3?fkEhf6Lf~ jof go&QcD-k؛ޔn]:lrͷ-G!qZjWYø s=lr*5Wp.6*k0c +yE=aY%2bL?!ggZ{1s *O. q/ eQb!FԛrANƫ]2^iVu=sm#>xv)O^mڰdaE 6~ASVO<~O Zݸמ,.gZ/Ƭ#l|#V|y[Qk*՞,*g*Zr]HDZ~3ʰh,9mԒGṼl7eQO<~oG߸c4rڏ<[y26xmZb=$O?ZhY`qSeÎO'k?Xo";>s&bG ˍ .h'k?\oP&V6Q0'Mf#C3lE%l-wPm(bFjO?Zh坫)j|#V~>Ÿ<!rڏ<[y2b3PxGLmuytTo01nSdaV h'roeϵy˽amÆ ʟ,ht49=GElƐz+r|mκq*?Zh坫8;x.z.xsp~*#^iړ7Zys@<s! |#V޹_ cmÍXgO<.#lF_=s,"ʻO6 ϋ珞xn ?py`،_{_֞,,~ƻ# MOy*xj>~;C ̶: ;|رwK󍃽̦tw3@:JŁк@Tv(lGm6~b.Lki\8yzr97lً'X_ho lBM_t1rfYVUWu]lɒ fQ!Sjx,>/"͹Z^vv$ |4~m8l9ѮgeFmgeN-4f^g2{ _t&bZSqN\\Tp>Vpr9Lkor̂Nk#Δ߫5%%Z?Q?W8Z/t_|i37 {;9ֈk{ ␚.v~7-l'[7^#%a8NThy9=o{8=&c{efm;*K~5aEkhޓPp Nx *Hp 'z1 ng BO+DbCj Jk*V_n?y7ag}Zx6uXh s(N'JỎOy~?}>_?WBE(t)F5sp-UYheAP_?o{YG.ɞ P yp+W5s,<5=<O K<5_o,N:O*\rmlYx ݎ#]BC# 2$ʼn^OIݎ"YLé̋2}_weTs:z*"+)n#3YLt#|no,3:֭;9i]^7ˌ%? s"~\Cܧ\ DxLΨln5BޱQӗkZ^x{3ь×9OXnU̯sݝgҹ𳍩T5mE]pƒfgSi R歬VX*3L)!E Bywu-oeqSr'k J[W*FJv͎#)"5rF5'|h8iKRM{3 owN[]|4څY]ڽqD,2=EbJd 'E}k|ڗLp2y3 / ,LWӯi4 RN76T7+ *}tA2~]HAKrky;g1Ye_jntIE]sNގ#é9$ONpvŠ[cS<f!b*'M$[<]Q׳j.ވ"YL=mw`5]qu["3YLE1BMe~o>5}pQ8] ׍**M]]fު~CO-0o[V~qTD@5TSΧzV6B;5Rŕ֮&f7[cJPA9gX4s`ʉ3'7v,L˛-Ә@d;D#VR5rCU[p73 1?_}'W`!,/8-;|Bl>QCY~[=6Tt5*xJxT*VAyϤX Qvffy2c3m;ŮouQ8J{r-ߛGƍĘPIe)|=[q,ifcJm] ̭dcc}2AN,]6]06$ ёPWpv7b*mf26T*oAeYovwbJm]p,1 Amhr7* pT\5TndTt34./8Z߭,,Vw> ۴ßg ӹf7b*pC.m ^eL 3bx3Sm#/m7$*mIX^.|0m7;\17MS,zV*eg:^Dvv7bJ\_Ns~5QnJcumHsZKvPE!aIGSTz2Y1xݾOFSnT.T-+knov1%ns&޲:{JG7^<ߛLnRMA>{*I4ƦL -&i^Yʮ ZV.]աGƾLEЛz k}3)۩E߄j7.eAS]icԳt=9{]v% &ofSygF0+o;΀Ȋc%q`ԮKHmSu5aC`"՛qTlT`F)Rg61`Sov1%MdPc9A3'-ЊƑ􏩰ɥFɭ; [x+oeqSYQأi䞼yxŹOqp}]GƦLI>yGoyuJ[7c4+ 7GƦLEu,L շnZvf{1T^?Im,'nth<%g؛q`lT`^;oK)ȷç?~3)7CYɈKYA3U}qT|uTյldxg&^GITgaSbqyi,މ]8RAq^iɭ,2wcJS:m ޭWgev,oƁS3* %;jXm5-+]˛Y`loTۣ_*4="k5 C$՛qTT *W8;{Z3ճŧ`LuB䢞e'6HLLp~Ln4lḋ\JaI޶S=qdlǔdۥԳl^G7'=9 .8U@YdnTd\n+_M(jf[1%a1B?6Q*[VNlovKfTvCq-Ekӓfÿ \D6ṆA|}SBNX/+j{T4ps= ml9y돩3/ n=S|^ڥ826cJrSf ;?ʑfnqSq4ųWBF甐,2c\̫ڸ\TB6=i\N.eQSR4 <-g#c-# ʍ KXgV a~hq9wJȨ[[cP6hSopY$~D;|eaTEJRrf1%-Q'%hVvf;1-U y)n:3J'Pf[1U@9lSx}3_Y9O"gqSq;jb_[qY)Zގ#c?*gBSg{w3~Ζlof1%XzQPOJp8VluV1(hFMK=)wj 8VofS/>M.d^kb?ZqX|pTXPwWǺ Ru"w 6>Lv؛HBC MLyHB57;},ų"\NE w+c80cJpBE)xr4u,YA1Œ3 !#vqFjP~e!$ԛqTlT` F; \Vկ7`LU~UjY4n4>y^ș][5 J[>D|O+oǑS+eڥNt]b!'Hf1XF:א J#ݒW:s?ۮ]V2ד\LԗV 8.cJ J`_&atiBA߬,.wc*nA e.G>Tt /Z.KRlWoǑRk@mE:U$g'WT2:qXlT*J_/-\-3r%3ү )-4 x*u[=C)#ю#SL*"3>Ǔ3i0ƨ_Uz ofXN!%ض W:WFp[CX7+ }%j[Be<șOsX tpREr8ohgvRmhpQGp3gWg+yU7 l`mKpAeIi,BJm_ZD]ڕP~,j5ǥPHm4@Re;Uu.oƁSmh`:WPӹ0*j,tqB*rG%C[򥺆k5Ԛ!^7;,#T&AznJYJvٜAq E4eB;KxӗfxkWfUJ1>zҡ3A溶Y@!#[v˶xPA7 b|Ϡ(`\z7m tq.3 n&jy)Mގ#{287*)>}RLvƨ|_O9?nQwR#KH 59԰~fuP*]6݌RZ$%!LeHjQ#ffƇO.׸li%v/: `O9QG֓|ϤHގ#S""WTpy#⾥wh$7TԻEEHIN[q3=fF84EHrj,ejgpm'7FWF7&1[VײMד4ZB=תU3g &oǑ0bm{h@7FzQ?Prcof1ө-A>T=˭~*jd,2cJ2Ws0ٶAGf4m8A^tUuFmչzCe窡,07cJ!V:*zk>f>~f1[6FLK܆vԴɼq`ǔNI#tOƵiҼQwUf{15pB_,H#p`m"wTn wGƶLEf~Hi6RI/U?TS3~)ɶQ48`dIDUEPէΆ;VRʤ2rQ=KPwŶLɽ 2(v Lq>ytjdELEnr" 9=.g =gy3m|3}.Y 4Fӛ[SK:"c'vPjJ4wB8t;1)3)G4~lH{j UJιcY/hoqISrmh`.nG=_YF)5,RԵIS_4ȅEfdAfÉR4fƁSma?FBi>iԤʗz7 ut&u.GZAcG],2cJm1'ȶx?qTlT Q?6g0Npo>ԯL \I4~Bt%皑\PG;\QI# u|9d/ 2TMa)G4(_Qzm_gެ8.d]"(C򏐟V=ԱRC5ӵ>U6;`LI[=V4S LߚAFyms?V~*G>/4s]@VZqdTBѓeI+0h+ Yu"s?$n~l;J .y׌{oy+[QGgR YlнfݘL 9')'.Tu %z7CJpaPt6 ~q'4k7,2w>!vB݂ft`;Gf78,vc*8`NR0N))Fq%8,cJ(Rꔰ,}Be`of=ffS'P$>O }#ypb?i}q UM4%of^pT5.V3O̼ٙ4ɊTdq]KbVzh3m;1F74&CRN㴄jk ThgS'Vײm {ȵzs#+80c*0îGR Nxg5n}Ydnǔ> :%y֌ 5`~f1%W|h,6#p[Qs qk͊b?⊒Թ 3ce5MϚ67;̍<9Eɶ䆪kxrKWv1, H+s%T6]k7;̍yqFO;r^ڦoˉF͌< tNҊ:}6ߙ73<1܋zWJ'OUf{1%+0衾*j5P7Wю#c?"sȶP_K{KB]_<v>!vBP :EH$sdwLEk8f"q!GAΨRv_1%yrҰ8$M]6ɉ>@17').M6;#'nf1%xb:'Cxq|6\_ %£GLI'PaQӥ5B) NOWd/PZABMMW677;<9UcvγG-\oeqySqIOu/PZ1BseUpj@y3l;K>!u2.&MRdNP;ꙮ6ɉzY}qXTdq ӰzG^Ɠ<)ɓٰ3((?angdoNgSm82b*8< SZBn#ov15pqݱrs'׍ھx8->|B4:_v(9!fCsQ'O)@L t.H%0į=k?h/X W! .wv\y>?w\5S8ܝJ[8ˢGw ЯVuŸX\t׏ۿq׭p>iծ ][u9i.L'{ɶ^S7 ƦQL( +(7^*EJb'?M>յ)%v84Ot~5a]veRάz_}ۅyP)1D70௯}~~74%ҹᓧL 64|%?ؓ g;aAO o,/5`T(Pu (00c)Z!稰XA'VÓbF(Z n1?&oIrbr;ʝ y}X~XNFrhU4oԭ++jFeZ:uih 2F]7n7Mkk)ځaXԵ};XZbȲ<äˑmcjCnoʋ%2FVT$~FYnPh!Ρ ^V,uB7oیYz "j-z}sIe1՝?hߋ'ʂ,(2}: 6]1u&篯)>T='Kc{ { D@X>^)noCBVI';S #1{) [߶/ -h^ 1VΣ$,JF{\B5͡5Mֻ=Tm\ZGمZ3}zլ}mUIYpJw7|rQz{ڇZ5k&)㹺#qal{z}3O]8w^U<> ^/o}H\n8"=<)_S"Ugbre3}K\>y \Jk2j~U`?0U>jќ:Ⱦ78'@V$>Ʋ0]_1QFbr! e,ǯ'?6 ί% AfUw Eub["q靺ٙ[%N1%Nb )p@@m-: DfǑFSU 6]Mo|t7hfqFSqm&m UNpua2{ZYq\8ƔY1i::UH`:t")В&T$8&6_Y^.ffǑDSY¦&UE|#lVBVrf.1%[béR (OFD;5ԹEDP\Qΐ'\SfaDSU%ȜEDŽOW+^T?sͣ3d&oQGSU+)`g sV1%Bgٶ.X['fʦU0ϼ nv 0aLhO2/ojEqPԻG6;K> 2/~2tF&G8(|cJ G)~Jo_ wd$]t,7p *%Fzc\b"Ӂ0$m*5z7լ*{%}&aɵ5OJ:\m14ʅQ^v3`LUʔ/T x {1}4t,L0uJYaup)RK?%1~aa?u3cJ:3KT{æQկt2֬)|8.|cj\iM񩹶/$O_S@qdT܉H8ִDLJF yt!)ɳ]MEkឪkΎ#Å0"SƻwQ1du_}|JYT|B$nM<qc ~qX8TdgAm T_DtGȳrV1U(=e¼W*fgASg\ 0 FfSbFތÃ0I6&jI6@abY/'=VI4ߘ3GPRbw'gf*c*T՟/ٓmLz7y#;K7Eנ0orG;̭l;`&TlVs*;y3< ՝3wX7f, ͆ fǑSUE|fmX`ܩL 6e\n< Vm0r/؛q`lT`/MF9^ի@pŸELI% k1Ȩ_.,eMyULIśgP!V\K=ؑ:rC=˛qTlT`.KLrKC=MMf)",27cj%y(i̥(gyKAL7菩*`Ȝ (1F.EFLI"N/Xƨn`JJ⸶yxZXؾ_P8*ނ1%x-Ka+=xJTYdnTdVךRJxũJ([ގ#c?$O4 Eغ1MZȒ]v1]QbV煟.hlXS)7i6,s?{,7쏩\҉l`,zL)ufgSXr˔=jF3)*R0 "Wj,0x>-/R(?4؛9;rٛGfL Vᖒ$!a~3|S)R^`sCX upOPO"s?$K 1}]Ol;݌b?|]= j ,C}vpW!fKMɥ'1>/rKΤeTgIrq9~eLOތ9q|Jz;-.ׯ \"s#:"t[k3BnәBh)ɳSMʘ:sMY7;M$82vc*+ ɅX]j3':J(i%2wcJ2..?0Ąi3ߌ8,6c*,צ`"f#XXuNtRFKdggi*IJ95;IY[16-.rf̜.c b'oǑSU>)~Hu1aj䎾}Ja՛Y`T`0]N`%a;n3{3 ܗwв]`sPql%}[l73 . "Pw9ߪVf{1qΩ 08=U2t[dǔ|/.KBW95̜NѾaVn,0c* 8uK` 1PRV5BD($K;(7&ޭof1XeХ]_ MQu l)ɳUrD jK}5goqSq"FATs?){1V :eg,\/+806c*+.&CPPOx qW ],wgfqSqU|c諭e80cj`W%XܣX ]>ꏩȶ.=fPin0|*TNؐX) rC+K806cJ,^$&DyWUԻE&O-˳؆V`džAjԱ .vv1%o_ Ry1%82 c*J8mS \^NNoP{L c8xl{Òk͎#c?"0$X<:ԙMR)*5:TƗP),.7c*Ë: %:Ҙv{1%Yd! |<:Q)%KYdTdWBsC)W]-$XSlJ>/W/`MعuLK9WAQv1%Yc|G;ytj'9Qs??]t R U6rپGXD`6;3 ̝ N〷<:'RܠGŇOe5fl!:U] 0c4x!Tܺs=OoH7;I$CXyKqdTd==+’m0eLӥhfySm Ȏo;:u̡EN4vf1WūR[$ӄ;VgH͊ 䚴4}5 uk6ABYdM!,_/)"9t251)UoǑqSg ^:ݥjAjbA"Dw t @LI+S#D~DUAh|cy;%"<ꁉq)F3 *KW;0 +ÎhfNT`{*\ʛR8uLUqOjZ %-XPǔYd뉐Ru/SYq\lT܊fN]%$4j@V1%wҲ ZP&rBOpv1YKZZux07`ĻWƾL tܡLzLZILť))٣I՚+ 5k,݈v]bHW[b=&T忻͎b?"E2%Tj=sELIV Ñ2IҔvv1;SϞ5c^HUELE˱ \ەWA!mRO6;1%՗T虎_aF_{*}:dT䶼Hk}uԯLɝ&$\7Ǭ DhǑSYzH9=(M 5;0 @1L 6 u:wNL ȃW­82c*2 ԻLf| =_g%igQSRg麺 w wg ,.c*nY]Vt: >Ss~ގ#c?$1#X;1}BU˘G["c_'ªxMsR8ǁmBqXǔdowKSsq;xѤ8,b*r W'Q]]˛{1%XSv͒b93n5[qXlTش|-kp3n42v1%yb9A)ny 1ѱsb9pGW0hfSU@`0p `1}*A][q\Tܾ<= 6cLgU3PYY\KGn :qfd2֬S^Il[G>] ml@+^ǰqPlǔ^N^_ M͜/JJV6+nnfSUnu6{vY6gv[1%:ȷ,'OSp,0c*p]N^7ؠ#Wt$)G%u-oǑmbgD 3c`ГUqHc*j^^V6cJHeb~LUq<l ̴G[6- Wގ#c{?"|`6xZxߏ)@\s(gcLު:Ꮹy9\;AGAgJtW5G-nǑSQByܽ'X0BS[^ of[1.tOj`7.L:⏩ȫ& 0(E'pPj) >Է6LEnNjd;~`7.L.-oǑS} A65nut5%2c*rY>^$71yW[qdǔ~M'k&tcղ2&t% =CƙѰtөQ\/ jHΈTb ᅚ~2(%2po{,oaXN>'t0tЗMZח]qG||IZ$َ?֓kju7 ,=XzWVH+[c?e|1~hp,8%y\4p(=:θuvli`;l+ EsXub;KzmҹqkOw4\M9O彊6mYWetT=ߦ-?%&U6Fx5ˆkjOG3BbuWm'.7nUt?}rfktYqv_?fUx?WTf jxY_sc ыTf3rZ =vNاd3CZpÞ4 òm}ړ;! mClV)~^DeƘ}WJX:ʄBoV7i`a',n8cK |1=_`VBf4V0 McDKK'z5 Ywi.QOFKĐcMx~\#<:!r7ׂ^ve:'.맹ᬢyٿ~ *g]<PxZV+lq!b۱]ae2cG^ƔVCJ<^Uuי'pp -xl=(7=ْ]6կIӞk+\Y;elMYr-4kތbWn 12^xo4n\XMl#x=; ]O2/6^/ċסW؄T#X~ҩr /qdŔFCE$&CO"pGl"u_ځiM5}SCE8Zqx'BӍLY*dC͎+bR4*Q' K͚;*:U(gQSQ j;g_c5J1%V+sEjüH#q 9e#ԭ5r釆Ee:ov\S΢rՄFх'[ʢZWC:#Jj& 1iHk-"vTgo~ lPKGQdLE4`4 4VьkG[m*fƷ ohh,tF\]S*@"6uk1ZC YNM"ӿ*$Reppv5mb1U}X͎+brMέ` VU3ڶ˛Y`Ŕ`[8ɕ\(;NAʆ*㴝ގ#,"7`jѾ ӳez~9hƵI*6sa-& DKΓbѯ-,-WF).˖4|KP=_\BSVG6 Pwz`ڸH=/Ԧ G,D4pl)ZJQyQ̸6F=S2qh )A: s.u.YŢ\LX<禊ɹF\ G; l+'I"WQyw 9Y`T|%4ʙUt㰵j;)yٙmٱh1Ѧma38\jDuώW0[_KT{F}֤R#Mhả)ɶr19d[݌K6ȍ)fgS8Y 4)dyאri6Cͯ*L7nvD)K$F;5; Ei,r,2}b*rCUb q.hju 8.Sv1ήRfͯ;GU,BǔŲud [BB:{i۲U*oƁqS'D%npuMn>ҙ潝U.Fǔ"r͞l]_r͊,:bŜOrmA3Sfg1%xb l @A[n:[YV\;NS\*x.t\+:t[eYwf\lFv$m+OӸ)8,517ikQyyTi*9Y|:ۊȶ7,arі%nK}G<8s8:,.vWٖ55)ct%\U.ofySm20YEe=YsK8)C-j9DN~ZRSýguXR֙cZwf\pSH-N#O)HMQ-݋0:6T0{i'GN֑\ӧv15r‚ep˙)61]Ӌ7rF;!%=f괎byVRŕ[*>g|2re UBmI3S<*^y[:ŅbTю8:$#^ɸyQ5 ٜ 8GƙqLE=)% fGoov\;Cɸԩr%=94! evJ防TzZ8xPma$ޥ ^}8 ՙn2.,DdمC,[ɔqMT(^qy ݈k7[LJ7.6#y5eGVJ,2c*rn V4LD0:bn5HV#'^yV`BmndF+P8) e_#:˜U yaljBfD+P/pP@ǔW"5'5:Y 73 m)ˆg^QK "ݤf6mJ;;\<)e F_״S׉I@V1%Wۋ\þlՈ p*_OȪv:bblov\B`mGk*V:RL?ЛeySREa\X9MeZ613pkv 46%n%`ёJ<)ɝѬaev AC8a{3#;PkiRuMe݌+cj8|R΂aЦ0T1J>$q82cJL-ᓹeJR5@B|YdT­l#:XS!u7m{Ohog6%eT oDc'tFy7:N̸r:,-PʨcoAz: pb+&TNWIۛGF D؎Zqb*55SKFjCEϞ뭸V -aSUWMD(nLG͌+cR vL8/5TIz;s蘊,ClZύ[FnhUfoǑqRSO5HKK΄RYJB݌kJձΥo.>`L.5 jmovVxS) e4 ld[d[X'q#2*̸ CzpUQ:ܻB :,[+)U8r93c蘒 -N4#\XPd:s9QV'1%Wrdʇ \;Mq #+9#|AKjP0o:D38'0Ţ}o~XejV.A4}œkVnݟѯAk\/~8@2׏ɨV^܃@'Pżxp|mK<:<d{6/*>z)yq-Qݿ}HzQ?@o­}͠O 3sFC3bfBS!Qo5.#ep̐z_SX@ Eo9yfjjPi4tCv' &3'g!qYaC~'e䐌}M-+XK#Y,20m8Sr_\nxd~r-@>B ި屨TK[q؏bniΕNGH!7c@4-=#3+gBwLpnUfƁ? |\Yy'?( FlKK*y~T\e ^vߓ$n\;C5?O!5]aàI´{F޲:E"$bڱI9u?={Sww}V~1ۖjK)#܏|q˽sY4N9x ϒyA(׮Jhܧlv+ ,!6h*T0[6:6Nu-+ٝOgQs#~<(T;[o1'Ogq`,W$ EZ`'or:/CY,bȥ੎|N'=2C瞘9mTfdA?ŒJyCGM׎;~ (K%`!I,^ 'k_K׆!R܈;Zr;6 'F57Ŏ&ACnA߂Kp#8䞻qvN'ɭ!`Xh)/u"f"7#0UՆ eAmCV'BL9?yȟF^㤶{Ua@V-3g!IEcڹmܐ73 QEj+_kATĀks\^-|guB?<9;RkǺ|Y؏ Ohj;::(A1rVC lyȬK\9lVqXga?0m-T4d6 \4[?$mw L_\Dܘ$)]xub?i$E ׹sSF*G ](Y76nٱ!I(R-zo;gV܏F}%-+ovQfh{c@øאw2!Igh|{2=3؝SV+G! >Ih{[TF>CF*GH!6,]۩Bly> ]fe~R(^MC51CȘQ'R5k' v?=ICos;G Cppнq #*SV;ɟDt6%LI䖗N'Evv!7R&v`J#i\67/,r$sy#"#T ov!12nn= ze!Iad[3Ȉy>[Nr;D@g?D CnV8vr?ilKg!"-9? ulrbŶō-/OJzWC~E({rIINc㐜0:h/9, qHf<^դW1x,vrw˛G+'_&Kkrȗ UWLFt7CIcs9Ս|}^8H[ 7r9]ɷ1!DLc9hyy$9$S EvvS4|΍InS-<Ԕo [sg<0nџIsNNf^Y7F[k|0208%^")l!挜]?F1c]k{Cn'Cxpq`'8{6pRӏ򔕇zS|C2q: I{L"I\ԸS 7po;OufƁxo B#xRsؑ ԖN0;`OK)kϬ,pȮ<x 189@?/i{,+τ [y,S=`+!cn'>٩ިsZ*͎US]HJ"'BdZ1qHv5y$BP{Cv'1xa"w'rYay"O؋{}o8)B.0|Cf'1a_O9yȭC/Q@Lupزσ:ucN2+0w>!3HnC~7j*Ox$ qSd4V?ԞWȹj~CvA@L^r($=gvbq ӿobP2X&^$%k/$ @L )gXs @Ls?; s, Lv>(7FK▕N2cjs'"1Ɍ}@K9wF[Nr;uǦ+rs;`}Fv#ʍ 1R^z?=uɆ<ߙsԘƋ緂śGŞLvE1_iSa7h׆=w/[M&vcJc0"e|TXtֶqzmt\$vLv#;8 ࡚&[1q@. ➊mk܊ˍ)ɽFV\l37wesW = [uM&{1>!m 0ō"n&1K* )ME#CF޳:ޏ)2)oXX݌bw?;7\ `~LEvOtvf[1a"Xu1@=+d(>1SD:!nF?ߑk7p3?{ AyT`_1ajMAy)sn~Lpoӿ>ݿ_ÿeuF7KƷ2N/k6{pU*=hƓ~zk~>?QƓqUs=7ٿxr=ycd7`vS> ]wo*ΰh0ưlA!\GtWƯd㴿r>]1OLV+09Ե5bq]9b8ӷ'C޶ `RO2ył@?Wa+`௪8൪|4Uy'Ug15?%x2fpƷ(VO:)Q <{]u=< 8ϑ}5^q^׀:aYҶ dAy;}6{r I>;4ǼlandLżo]l;u(&5[Q:9]q3L$=ݳi!m@7Zeߦ+V~t<)u߮̿؋ok[p}OxԳ'wh؃ZX踋4JLFiXLcn5 Gd};lG9Z>1Mrb3kpRkcpntզSU._65OkCٱz˨㍷|Kט6soo¶^=x5ߴ|=k߷AοMN|򽦊N%f\~hk*I^"Jb;ߜE3eA=y5MH(-r\B,ǯך?/_qEx.۵N1b Uғ7;oyrv\Q>Ƌm~_؞80~o{)pk_v('KG~AnvlOrh3yn*|'|2*2?uHzڸ5kOrh3Wۊ;W6NkUԊwD6n)+GvɊ9)@~-|@v~C֞yF= dU {;dFۚcZbmWim>qdʑE,8Iۯy+^oo"؞80oS}^'s{Կy$W<oHnaʟOYZΛ3 roTG]ukOrh睬"~b O@_w&"yD= dU {;d4A\R o({ޖ=+GvN&qٓs9o\|oze$}Hx,=OrhP*<"yD= dU {;N*vl'Fp&zF+o.>׌bmWq|Kdo7乩 HngU_9rNVO<Y~U4YKx/I ۯy'+'ǭ \fTѐfu|G;~@e#ݤ'wf睬0L~@mS:YA$G9 Ymra,'I yseZ.qW|{ }"Ov ~)/tKOEʿŅGj"';C!'m9i89iЎxPƓ#W*w_Wh8ܰ:-ܾ8)i,כ/gN;l/5}8߹n80Wql,W"6 /Hزx['O- ăd~ܾ5݋]gwU[l)go>]@}Hwkqjx^C<͗f:kL>-ED'i(O\LC }UQ*/[/kXy}h\~ڟ!qs-˽`VfOéj:n|=Z_8bwx~?}>_?WBE(.I\գ8!,ft.*,hzLȂ2JknRx'\?]oۛlyv-oNz{I+u9?'ҁج+1Eឌ3zei1O3y~Mdm25Nr5!7 v򭬢Ëp~pɵwLcǛ_-4\mh^2V>8dnЩ2(֙NGgN;7WmR$d>#P,x~cM]5ƚ{,}2x/Yvd|ܠή`c\}>+o몾/uV0vf&v{XY 'rޠ 'io{ެùu|_WϯX3D( BWG#SԀJ4[kE殚4NۛQ;q07Ugyt}5w-{Rw ?ߎϫ=/?8=:<k՟,1O_{#~ӷl+͊NFf+.1P/tߟHChb&- CYs<#VƁwƽ),l2WY|VF5)c}R ' de|r:àviř*-e7%l ^<>6ͮfs@°2RGZ?B)fUC4,l-N\vXʖa_#(ea䁑fV\VT1f,hyAx[~/|UWS`<"ȭK 1+\x >°^WO^Xia & ?Nuso m? elCL~/թ-wT;2q3֝0%xaq;r`wPzy`+սMfz"5RΩstA]K>0Ң%abVM21؅E@Fn"SU|ɹx8cbݤܻڷ&33[k~M斯c#xD9YT9 `df+0Z~hz5cS+\&eKͮ:3j{U]肊n)Q ,Luh4LȣV[ni:*N5 BkGj4.LCב *ddK87˖1vcKSit v;ȋ\n2Yjd4ҝU6p/v)Eh9s-uAnS*z PT V\Rʡy/iiGo?SUAn'-\.^dD_.Ncpk^E7 w 5ϱKzX{" ykyMzX?DŽ ׁMS 15lkUMflE/rXS˓H>Y* d W:_o@zw[Sڲ@ElF͟n~[]S1;Wp9-ɥbɅ۶c&']wA|As+z \l`V>u5%{ "!~y\n"V܆f]1ҥjF-rΪO 3G4'~`lk;Ԋ~?ي1Djuh 7F l FVI{0u䬚Y}]~-ȉZ|vؘctvM-MӼ1'q0bVf0[=nekijs]JZ=5lm(].`YS䆡fjT.'/[=Z}-d >_13bl2weKǭGj|ߪr:0'\.#8>ݲՓms#ɍUvv)7,[.1$Ճ)# +膝Hgm91ʇTD7=g <0@єba+p*\^[%׃V[#4vjg+['辴m)e/^y9e "?(26`eKG×M}quhj…llisЉb@a,1u`a ^3꟭]LR[K+ܻh7Q: `D%is/Nn:xbp>rpSt g+cjiֲ'Ztj G%0bmfk7;rj> #Sg+ :Ǭ/mC].ecϖXT)^έC\$]m- M%pVXaL]KںƢ;ל5)d\+ozRR0r[Mc!up7O5&uPa87:p`[Rtg+0Kv4jG2pGKG^Gyz)_o~6lI܈Ӹ0=0ױ.&V`m,v 5g 0>A[Ҷǭl,r?Ǫ=RN$p5F WJM#-'7/PؑCs$[;̷'Vd+EG ohVa|Tvg]+~De'8x`ktĿ2يq["r=t̖~ l.ْ[X)Tk1+j57K"-|+<)_]gϖLͬgϖdU7,KF漮GSCRtg+A)CMfesሆPRiVa7:9h6dzM&PViW5>3eք]KO #ޟT]JFk`&y_GVSVp gJ(x_GQ~g>gSJ7pO?t1yf䖾v=[R4F?[kTM. WfkBK.fsϖ\Զ2ڍmvGAkBSȈg+r]&Q|sOy5)3ft ,k}ҍGQ^`Jjvg+hṁ rOxsg>, B)BN9л*~6lE.yi=biUntPi5<.Bْ*b~;= DL=ѿcϦ _Gl`x䩾_Tfn- 6#Jt d<,Bjr=h­{ф2iMyɌg+r/C򍑮MDy̔Ԗ2ْ\:5n6&:DGSnl*JpBԔԒl.C٪$[ZnͭvaSJ -[M#؟-ԥ2㣡wY-Z˦2П܂u=;w9U;фTM'1U_ִROKgs_φܚVO"ԟhucF%9i=z<ݔzh^7@B$~^`>>{gbJlJ9uc~lEK`nVo0J M5e?[Gl#:лcgC*9, ; iv˔k_Y4)'S@F?[}j~eWx`;55%`%X;B`Kǖ؉xvg+.eW i[@ot]6t* >;'70^{JMyAw7\w}xI;[aFmܜ_t!}";;M"Ο-2LӕMk^]+zɌg+T,>-SRKC 2onql  ~n\p,Gh+C}*" bBYu Miܽ * X'Jybj^ֵAUx̖XU4 V @-\BKQpQlX1݇hR͎qV.McH_jVE?($wjNi5Nto*)LTkJHS[&V`nS<0o?kHI=gϖd 7Ѯ!tYF@J ;R;tF?[=(d\^ TSv_We?[aFsbmx%}T~ dH5Xlٟ1ږ1̒X^_Ga~alEp8p5V5X g7,d a54@*<)eKȍ^:UɊ˂7=t-_k$LxmtJ` ~΍$ʥ%.~ `h6CDŽU=X[ѭ0}b+OR)Yo94;\ҋF>uMvR${ȾQ4:OM3W\k,Y.&)`o纘P{_Ӭ#m`l%كD\`b!1oC]%<P{ʾ%rBaͯguE_o^Wr>ђ!"Tͮ~a[Eh+T%7MN"OQkeͮɊJB˼ dIDK2JFM/P8*STT_l0m!:1е ֕LcQ Д^S2 0 WK%YF\z~4 u Y ҵrZ+)AzdPU)keԼR1ج_'@2`ցZQb25ʘP%ɝDA#')btB#u+MSv$Y=4d(P(Qi5{ݚb(] gG"7|>u0j7uv ŧ&-2Ԅ>`}): d*a$+rG)q.ɂW$N`U+d)a$Kr[FVu PTM50)xb@>% jq[WpJ[!؃H&dBhajcoy%p8 2ĥ?m4ceeH*_onlf5E[BXs`=IecϖXV:$m5=ͷ<>ޒ0B  i, C]&Wt g`Uo xk)"O 4ݮy2o~AlEfBq$YuwIRM8/+&3-'o0{}j2c}P_|N/ ہRXlM.ܖMci֮nalɽ3 S:,d>l0 <0Dviji,c#}ZM#-ۥJ zOc(g2o~6h,^t-U.fVi% XD%٣D@ߨYNQ%XKAlpx̖Te:@q:eP_mݧa/Mf/F-T6vA LMeB,ZRt%E7{U?@ q~EhV =4F?[蜚ZFڅAu7?${E?A,-{``~2Rk,k<.ي;1F]n",v֥l.ْ;X^Β(q: S@pR4zx2NTcUa(F˱S77|nAR-NpTx#KĊn6ql!2z.Ik P>Pg?"wM䆱nO%+3-%opƶ4s[c-W7Ԯxx \#(̄k,rs_eLZ T fKLJ Ү :<CSTn6al `~CwV5P1L1lH7e7/ ;bH* A#ͼk˅2يLujvy i5rP3`>Gg7̰ c> p:]lfXS ޚ\O #-ɋbAХz(cy3O7˸ 3t9Akp: 4k!8PNͭ$`1|[ JFefؑ)3o~qlE! |,]0'_WMf?[g{iW/;\6M#쟭CגGT`{R=k 1G̊~6lI^q]TbTf^/-USgK4ŖU8gc*zaM_M"🭸܇~T4 y5{0)`%Xz8p<0̬#WM'Vdq2GAYaf$-MWT gM֟|i|m8̬''0c k`3K"-gX+q:E-]l.#ْ(\%횠hfy` 7g?"]K$ZF>tAՊ.:dD;!vAfVa)E1[#yLk"~lE$tU33m|cQ&Z- 35V`b:^GnJ>KS5xL#wQ4@F?[p.j"3b֖[TȈgK4]PEQ2q:b/ޖl2ي⫧旇vPWh3bF>uAE?lI R5,8̵1h[3,dd+8M3lPeBM·`lcm1MG!u1Fu'e#}qn|^+يKuinMMF\gfHZrl2%yq'(8s&mƹvͭ'p)`" am#o;2tM@NE@A@0s:\mX[ FMG4.&-WPZa? ^?ي+ zNē2E\W8\ ~6ْ,KDpi 583599: d,d+29as"αwt)|n6k0MS#+N(kdXSݰ@*@"O u9P`[s8m l>4*@{˾qj~yde 5 e} .r@,+le@ɕoCwb{n 0Dkr  yc%nu=E7hHkvzZ]XMb [; Dde _d#7 'Ҽ d,dKǰP`^Om83Zrb98Td+$ej^ BÖ-zh͎q.SQXȖ\` (TQ}NܕkcM)Ru|A׽x'_#Χd2Q:zeO(b Ya-Fr>}}SUZF¾d/+MȏOMgL\-*{?' i1Zpdk[Z{PsAe?G~M{Q(u]n637י_ԟ2Xg\G\鐻`YctJՖJ%7Vm^SqR$GYuptV&H#yudr҈Iqb1>~TXJ$ :&jag~=j^d:(w>,k ?>??~="@t.Zh=S>z;9zwhG![YCH]rCMѯC-g BثHV=~ C'$ K:raݞ^ocjKb[p{choe~1XGVMci(WeU'n+kw X孴.>?+2{AMσ}#w[|}dXTNK/Wh?JǾļVT} {|5?<._+h{p#elYws.,M=?>{hA7CG y@c~>zd}e9u߃QIzZv@>Ne8d a$CͩA/Mi3{H!VdpHTP Vۚ-T&30[KXBA$@A-sH~ZP)mIevǒ^يqb7`{q&30[#\|P9.۶^y[.LsN>2Y=K_ :%HFaSդ}2<`E?4lE8;EkȐEwQƀnsS!tu j'g.w=ЛEa$ M-zU(E*fFIuU,qCm T_C KƻKR(x Xf+-av n zEtMf`$+m OUfp0 ̜]* `$fK:hǿd%l~ i&V_'ZY}I41u=]5 g+.t]PR7{`T5YnStgKz'qhim+rWp#pl0C LI*svpYcE?[r=i4Ke\V ne U!O #84zw_V@l0 e<w]rK'9 dv,.40^+t gKݐ6>.I\@BV›#"bjۅJwlw,"ْ:7%%vK8ͧl2Cي\$OLIl1Ug+ę9;m{hoToN6al:ץ_zA϶@{rNiEE7{ ; Hhw|}H(z \%wuOX0$f 3-RWyfsV\i^Q.rH*z \%e-ek]ao:CDMf?[ٿ2uaZ5yT;&/l]ݻ5<&(^qfVtg+pùt]oI:!9X2ҟ-wq0N-+پϥ0 U I"oʍ:Fލ`hfE?F4JoK\۟4 sg+:W5 G+g#L7?lIV)%9ḧbzy&eaMTi2mRC'ϖտA)\0IzY)z"O #̟aPCoqV| qnͮfsV܉mhrArɾ.kxgK@%̧| ϵ)7l0c 4KSJBv4U+ d EC,(/T.Xs팵0}5ͬ'`Vdvo $*P9UZ3ʟ䡴1&2* kjf70E05Vy L'?&3̟-ɫKR҉J8eI7шzD/R%x-;=ե8/E?_lI^oʉ]SUymMf?[áɵoΦ6c2Bْ,X'ª[28\tg+l#ڄ:ŧN~iv}mlgK`dv2='V 36*snV (F ޸ڶ5&Qx g+z5ۨRdNs=%2ْzd %9Ga 7/h;ՋP n&d{?ٛE?[rWזD vCXL[LԊ~1lE#bqs8V%SI\F%WjWXZJq|\qn7?"ȝ vC\Mf0JJ\O‹; ]uČnf?[q'ŝuy{h^*O #-ɫ>N!z&1Y)bˠ[wЧT׍9F` rF/ ݫR^:Nq1"#-7xǒ,9jn_O7KaiJk.+/XK"-Dj1m^!dMf?[""jFfuQ4@;x$ɭJkPϵ9 K4 `D.q@)` PFIdcϖq.ng5B϶xC͢K~lEf&D6wX0q!ǒ^6h;ˠ׬^&ɚ$ks# XD%yuK`_YUAK$nZM0[];Tf 9K.Yss::穁!x \W[h=m'zWh_*sI"-w {6ů+k ^t g+pg?9(wNotgK]ռkuoE3ofV;qxY5 -G!o< PԂy` 7^I 7Eм nal B>]i`%t35ձ,7ԗʘݚSY`w255 @pg+SHnsSXǝ+hc%#l2ْZȐi`gej?jD#,di.%QHI-um4:I /[AN`*ơ~?/1bCϖ&%ʼn3;CLKM5@F?[N"y"CJ/F8]cPtF/PԔzNkY)2Bي8F?[SnYJsE ”j g+:d[ `J=<C+ dq0Bvw QH0+!x#&PV`nICCv6eAn8e,gϖ"q6[= %pV{'wSy ^6l]+KGbC7-Fa'V?CM=C<ôgKdmO#Hwg Byl2Cي|.Yl^`|2Kɞ,t.M#֟Cd `c" f?[=]wJskM@Ƌw"ϕu…ҿ,mNϓE?[rտ~iv,(}kml0c 6q݂FhK; d%Y=TM16!.A< KJ7dذ|8粜c_xR4v# N)̨vc8Ryx'`ϖl[#05E?[qN"sf܁3|tgKpf uRM8]s+ g+r)^$anǥ8 Cs+ d%y^;ȧ/HDq."Fn6 ]wdW !Q͕)al_7?k0Xʧ;{g` BUį?,d%7Drv{]KŒ_oU}C~~ςM*d'>nޟ?su;7o@A.s+_.s5dCXy[*ydjV8e_gɣmG 2nF?֙>4yUG~=[NbjcvZncxշ|5^X^#%W)hkO:?P8k 5^㱎` Z^1\Kmh9&kRvup.Njt#%r[kqFA$l`t-]dR:eQ6OA}]dVr߾_@'rKCneTӵt3KA>5Xs" $< ;'ɖ:i]>Ѿ3TohsPO8[f,X9hbxX3Ķ?Rpϕ;Q >8q쇟@FL$7FeCSWgw5b[s)g X3(԰{ BFNW8suqNJ5|Se&Pa$Zg7|l7["hx^(}:|:0'[g^H܊qW&R֖@8uKnꡃElaT)(KPoDON7PgO#2 WcCnP/" |ݪCg,fGXꇫ?[L!ʖ:])E؋UY6((FQ_'#g>3?кN ?DMC+'l%i>aJݽWP{ 'TCyyUB$ &W+d(e^pʞ Km] ]Kz3,ғa5it<̔ƭ>*VZ^LPʖdT1MgJf\.PW&E*?#T [E, Uկ' Pٲ_ w]V8)quWcZV[Cec-d8p5FOӻZE M%p t ILze 4VjM8v{t9Ǝp^:nmKRežr\B\:pPAa3*[0|:xyQMo`4UUN:Bs=0wlA90 CH;;bߦ NFlUOc:RazaE3=zt]U}-g8 Xle+q9T,.]Q:s[pxÉR/[X+̖4oĀ^vhuJ<ȃaي쯥tٟe|˭*,pp ˖`T1LQFn Xސ@s|x џFWuO,#Gg}V~Bp-8C1/~hƥE?̌lI߹|3A>1[qK# de+ó(;Vrp`S.2 I[$-~:ԭy!f-fenӊqO4ZoErݚzWȞ+ c]1(kRS,GY$ٲ%՟TでRO̹4召A'E"1g>RIL:|zn1Y.[VJis$Mt]7k{{sH˖`lo`ӜʍhNƚ-&3[.[[\.`uvrctpN*?S>ii ["{x h)d1T4 0oY(46O5#N$Sq֜x)eU7 qM_l2y`S}'#_9tno6[>n‰.IyUö-en-KYE/ȦzկPfs역 /巅m8ih&ѼO7z \$eK?=7<=ŽSwɃ_!N'y џY'k^Gn11YnBJ-,-*U`@5+WL%̖ddo.u SC$H~P>܄ũ.RG0܄n!O1[vY Zkԭ|s<[n6`u#gtv.{pKjHTV䆓؁KxVls.lI^4994O^˗!\UjKr=hTE~B-;,C1p cSqX]g?lES]q,wvz\Q6y Kkxt)Unʀw J+nonB-;,2KBR}-SW|\ΖřLlZб"jIt/^Al%e ik: =u ~mM-܄H>0g{iӲ;na9:[օgNz_rV,ZYU&dGgK, ǫ90lŲq6Q?ؑ-"_Q Srr7-)pN;\]l3VOIcfw hا WQX'QS%ChkI.4cKMbI:[rFCO5値ז okAN-*M"p-\|JdR>Q7OqLoXk{Π? +> [NƱ$! zn5.Hgn3K-$s\woi7yS0X9C'klW`7ZBnKܸUj S%P]8R /CG'Jf^?טpnKVɅ{f ٲ_'/<6%]bؐ@XΖE35E&["g`-ɋ=~ÔQM::8fhxMw.Q׋ u" `{4ޣc[eJrz2Ktd\3 XGg+r6 i%p-,m#g/k0 IUW6̥|`Ϛܶ8g7W\Ζk4e<.zZup&}8'׽%9&Xn{l/@2C(RweϲO[yN6k ;0+Y^ Ny.`J'o `g25WϨ`<~։x,1g; -Zb˾vJ3n]&W \HsX Rݚے(T~kْR%݅I#Vn]ks- rf?lEkY(kV.m7?yG4,FO8%Ŏ^ClzWUdlZ?O* Zt?7.]\c%_ځbܤ n^le}Yuh5bj5B֔@ո-xQAhoNznV*e_R=]  `,Fg+) 2s-AYQu0%؟X{ yZa_Kc_KZZ&UwUeWEUV^Z{.!i~E?_\Ζ, vz`]"F85Hrt}[lcƒ5lciJAĂۛMrtNxna5UZ:p7=('aCk-gˎV<݂T(yh].-Oܣad_,z4_-ID<&P"-k_aŰ%gSJ6Mq"]{䁊aKECrRR<T|sca-+$wu@в4hfv%l-ra 6'/x%5Knon6k v6QO!8<,'վdD~V!f~N- @颅֌[K8pJkt0Ң؅A܄SO$}F 5&^q5:[VX F^ s7֥0%X9K}m]-noGSM?X,:s. nšz(i --5ۡ> gXa ] %[rYCqK6m`Kjt(^#*}mŰ%.ڍZ鸝(ޕ׀ieF &r$5<1כ JtOֵMdqKUCqKk`O8EǤO)uouPsI/KXֻDqV]-mո؎[*O c:[g l|*I+K! akmo~6Kيv5]Պ YCqFqb~i9k}a5!_TgOMOhQ , Rt? #ZR1璢"rۛMjt$ˮ\YūkCkrKkvJ: ``D+ka *b􊣗pф_X׵]Gk=x.>' ٲ[7sY5':;:bS4룛 jt]y `uW0sTu9 d,gK2Yoi Թ4 / YSホp&;u&{'dYRqk=μO h?4;-Ggn3 1*.Tg%T:XK~Kْ ¢t?*"O5Sޒn/lc#eNZLȽztRx4b6ZvW ,-mo~9b"ʭ}|#Wԩ&t ٲ_q[ i)a,"r[r1:[re9VdG U:ΙBKm0%xa|ު5O6U$8 џXlNIָѯuXn{sCtr9t֯%WE-Rً ޱ>BB*w{ Ѡ?ցꯌecyǟ|u>?~#6Cr2( :b#&+Kn>TM4660OLKRq%׾VF5 mu~f*џK‡Aϖ|hptez*Qޔ.C0+M.?̥ҤGS>4wGoKPf%j4Q BMV2cB,{|hɇƊR?ʥj÷By!?5㽥Rdr`R!*RqV1Q 1d_\-yoK9f 8=򡹋bd2~&".򷊋CrcܲN{oɇ֊b[%x|h~+ WzKpQW;Dߋ!/28!K~)Q WrK>4v+o\MS3pՒέ{ j_n DJ~*k鮱-/)C[[U~OrŖ$? АD_%J1!5\j>EV/Cvfy'v궑ۺj} &Ǧ{IX;4ֱj-V/a2#xOMyoK}rlRs5ςyA*K֏6hLJ.췢yCr \У!+vb@=bR\v5T2ZTI+ Ym/ߊe '.,yJ?[50jBRZSKjv\|*#|h"9$'ᢩ秖|h~+ז(|s{![G[p2kEVI-@Vדf?+=U@mS;>uaSR{pHpz6F֔]"fo2܃u+nvq;_<|_~MzdN01ϰcCzdC.u)FyO yo~FUD]11R#SӒja{'^On`-wjaq5ތrrjZ򡵋ZX%''9~/\q4Ǹ8Zy% 'Bb͙5맖Uos诸\z 䏂[ek<ں ne EQL+l~oEn!Uz؂ow*XWk~h `=yiЊd0NhƇ.wUȞwxO Qჼ0'@%8}/Q1V1=-~Wxk{k;Y뉽JH=z՟y=7;~!1zl´]Nؐ.wO4Wo%7=@s" :CW:XUC665vazpH>5zۧ|hJPƀ[v()'%[!L!e-4V+V%{4佭 Qe/<(29v~hɇ NEyTւF[\MENH'ot. m 3N\6򡽋΃C2zt/MSS>4wӺ xfUr?Sc壽[vqy`>`}QVV%Z+g9T&z@NѷqM\9Za;-> >"{ŽudeS{;Y?›Mz1ߤyI^FҾuypH.S{)ߩoOnOpfsUuy`>'zSK>v]y`ŷE}ι'~Sk;ٕ lN)XoQ#1a;q+^%"<+~xQu򭽋Q#wfliOll_a0ypHn,4CsV$c0ߚNd#k˰j<(䞸, #fV,?Z 8@5:<򡹋 o@o[aجpsԖ]@$T;ٖ[&3fxp@b&6[[>wxpH||-+IxpH>TT pOm^?kj< Ğqz~jȇ.w΃ۿڻ^<8 {7{ ?m^@f{c[w΃\'yOmEN!њjk؜钷|hߊGD&Li@myߩG<8 {-!;2tVۉ}hˇzDƘJ(O] wxtX660-wɬիN}y"Qۓ\myI0!o~;eG"y jxpH.Us^%vhˇm>ɵ<ɱ-o~>xU|W, ̦FUum$2ɵ?hOrl˛@|IOZѵNb|hW?b`A_ fS68 ?i >pHn \;\4w?C{ɥ>GdeMd -,򡽋fBў؊˧]秆|h~WVUM'R8ۓ̶rj֕pH#kk:Ԕ]o> N%-)9+M77.we3XTS %]ʾ/\z\Vn6۲  .!E,Cr ׎m^+&S9!Q/MQqy~jˇ.7ӟLQo]GS>4WJ`Ma'\4d^|F~,l@yE!6S3[ߔ%XG68 oj?9 KDJ@+G"/|h/rHnQ9|jˇ.7g)ld')jƊ]v. U6o^S LVz4㽥 M'`OYt BlpjN,@AxT~r@U ;.Om^"-ɑC2UzL!ٖM]d-m-ק!x5V=S_90lEݧR|Ώ-z@nJŽ'.zޟ򡹋Oa0 1^(|0}4彵&pR)gs>ug{Ef?Bv?W)FHdF%9rH%!נ0̸?5Csl` %z$p[wS g+`ђQZ\7`)bZ>5Ccl۟z=1d?[aޯ'|Pch1ϖ z(K˥/2{;>T\}rKyr~w'8V>{|8 aZd9p@nDHT_ڐ)+00ɽuH_ZXD{cvsI@F48O/8OEEx?[7SC޿x[*dz0>މ+fސM]\%W['A$Iβw,}0ȁC rvݟ ~ uOplʛ fT?'=cE:`?v`f=YG\#8}32_N/X?zM̱#|-6?Sp N4'5h巫/2f/֯ q>Z9Wcx|xtyD8 S/l?V`5 Q3Z6QꬺM{nD75i8Ju(vtm_ w$c #}̟%StOϐ.6͠n%)ǚ_5&/^]{Tq Lfx^]LWF.GK˽k-iVkX7jnN~镀ty_t<.?8aG*Z\Mu3٧[W_9hHgRy`;O?֘ۧQSbm'ΙyΪusv]vO+|ksJ`s^Î~݇W}l~:纮ӄںaG ",ocVRc C- >G䲑9<ʝ7y_Б,kUeₑ;ӷl$>&"#oG|#r#y'ӿz}R66Uw6S0eo1"߅?'#1Yo|JyĜw[~#0wM Nω=}|dS:fW7/xO5}ֵV ωH/b>`{xkX=UUC1 y7W,nb1Gx}-?oNF\Ln_PωHSźs31QN/}' 2"n&6S Gf Y~1Dm<q֒7B/^YdcfZ.sb7sxVu2!XNđ?#ρ}+7 w~NFdI;~y-1?7F`FV'?l>'#1vNE<_^;M761m?׵q=mcgDo$AVB<8ppgSQLpRቶ ?B$mImlً,nԷ_d/ClfE`A$,^?W@Hvq$noȹo *^/+4֌o/ظRk5^GmAZZRkw_lQ?^,Xex]k;ls٩7.CSw^kUgmjpG~}Fڵ.: u=-Sd:Yۻ\B;bs+1p!7'ZB{k Ŷ9DRxEu.w]#z]BU^̥ <*Ϲ\U3hlB쒯5/3j ?y[ F}?-/ f{՟'Zaf6qZ3Pcy?#\|]Z{_f?n\W},^OlW.__]rw1yc{r$VxY]MjPPާg .x'#x 5[f<L~7|Euǯ_ol9q 75Z|?@o!4xFт*~1Ёgrwϫ-#Cc '@ZIֻ[;_lz8l))ژRƋ͒ oƑ3g~m*2%nGv#_}Vp 6qSf+cLo=j֑Y~潈n큵kxmO6pk3h"gS&oC9$FӚ?b?6y\{LL<\`Z[(WPhDҷ_}2O { Y9؟EGЄ-|v[~M]_+ϟc쏫:`'~C? #h>S&q^Ȑ]Hk_[.۟~O«}0Ȓ_/Pgwx|U6)\ɟ3 q曈3ZO=tdbGakh5 w ^ޞ/B/H%V¼qz֯XhErŸZ9#ͪC..tksPO@5&՛n?'px^@cխJ6k;GgYu",<2sf=9ךB Qʚb-y+'8,7,S ~cFV:+N}?ۣնW܍£k}NyWz)w(HZ7e x.w\D_ztOM9שy{\f S6zAL+0(.Ttkv+:Kj|<쪽 6;;sXVۄ4{b,̂>a'xϦdS R녆7n0o srwԍ!?}GbQ+[B^8ڏ @ٱ6ІW@"SpB-h}s6u^UC|35M2S.lBR2"'=hzsXVXA_M>=aqi6E'˵lDD @xx^ڼCܫ.#01hB[ b&G"PkCS)H6-}.{tAK'=g Ʋ]FrVfX{Vۮ1f2pו*RU[Si-pful,S%vA.7&vBt?ŷzȬV܉{qD#ț{3""wK"/4[,J!5[Ӟ'- '֎<{P&fKbEmNFQ,rV1NRßԬ!\:.nLʖE v;䬜S RG"([Q`{.h8ڌQG$_o^y+*L)@ӫNύ/Oyɦ2"[Q ]?*>DAlmvWbC|7NR' ~>6zθ067kU8,٩'gi9ȍ^w`|n>"sixcj w0z FޚQ(y8*7'ш91:b|lr"l -7N0K1;ǻMltU-K8.}Xr>y*Fb\qk>E/nي/Ւ,ɽqy1. K"V@Ot܊-`2zĎ=}`a:KbOZv )4*d2KbXJ /_;pw'Ur'WKZ4<2a1Y5']Va&ơkȃ j |6`ϢIl,ۢ!cLFQ6liD:8UOt cZzij:? ;Hؗ-fl!7/rßD}M-ȍ^6{cKX+^@+̨14.5UBsNq++i%/i`ͨ8Â!nN2 ^6lɭE:o]37sQܸ̑9ׁP כE8>[qcLM)vm0'4f!SPt gajiq/Nq`Ag 0gՔ^ܳoMƍS 1(z9uD/|6VibNQb>Ճ\W3fT gKhVh˅AJ9](" ]{E!Vei+yԸ5eH>[r=d=X>37yLf{3!I""TzT岼X}>S): X%vVF)=jK3jZގk'8TF;ܚ{q5 qmr2QQG" tr<$e-qu~9X%P~QE2e׎$`✭ܻuU[b3te`={xrY>g'ˀ|vhFy*NNi畚q8TD%ՃKӗhw/OltjDՄ >6hD$4M&le [GZ1H䊑i]W|Of1$`:-Uo\K0ʛai(}esS޼,nc4>[q.t7; ؉P|v{ϻᵲN>g/_lh7r=vbgj@bʛe>[a'F]QwznόL^ Љ>1lUUWG=OO g+l,c[!agiJܕ،': XVaKeGAw] (QI"-ڝYf=,A( ݙQ;8z\ﯦ+hmS]yc|*"ْ%ơ)QsJWjT|NљlǛE>[Ք9;hx ްCJnG94e=[a!xs]y6$PϖT,²=ƸMAl[4M?薁@R=ntcn߳e%9j2) (o^lŝ8|{1]ِ7/{䞻 KfAᓓ@E=[D:0>uj]uRy}Ԏ!Yٌ7'|6 O-RE/ hL a$>{\%{˭9U8P1_%cc NlEkjJƂ2**:$؎)l.ْ[C:5G \N@R5#(kܚPwg@b#nͨ$ ~ϖTD# |':|،l*ْJ8(@,rdvcHhEa >T{a寜<6vܚMɦ2*qsLf`( vsH[Gg+nǶ>tjL@(҃UBCS*z \%w : a'+ f]:f2*TW186"UŠqgׄNlEA=Z ya!<\CWO gqkM mcN 0T| G,?7#ٲN *g{eE[S"Ø ^B?zϖ\ <م؜2hh9T 99{PFSE=[BQ;ȋBZX3,Kظ|k6ߌ''D4B:;Ra-CX%e# {ϖԂGES=u!LN&*b͸1d N/rي ǥT -aa'9 v`^2-P_.v;dj28M̧E=[boԲ[7{bQUjb3<" yVHS u2EncK):XF޳%8⩾nx^>ux*T~: X߳vqq+Ot2GevUt gKqUb4\Pϰ g'+d d ۇz5,;ʎe N 00 ?Yb/O7qcU{/;X$Ks|Yz95-NdeN᳏@FKzP{( c|c(O⚿޼S%:kOSk)ԩ*kȅQ>^6W&Ɋ1BȾG'ӣ*KE|TG%qMFSEB9$bl,Gs`lSWOZ8P0Se>7jFE/*Uh`QfT0¥kǍMOtQ#igLs|7.>0Ή!Uo~hBE/+dŽ1@EJj[  'ԤTgc>9 Ԩ4&B:?^ e;*֊ c2Ǧ~H#rvMyc\&Tø"÷`\,N$)$i11"*)&(ׅq-: 0+ i.%w`PDPzRrݬ7j˅I(O'5A*MD/biTXxy*Qx \ >D+D1UTI܈^\^HD,%p),ɱoz p*ՠ68ޑ}l%C9I 7ۗ!/JV+IR YaF<:CK>!/T*⇗zQ.'Ӝ^'Wb((>OՏNۈ90:ǣ=ƬOc"1 wzgKne*JO/bX;*sQN6!lE2tB5{K*hyj:E|z<Ǿ+LKQ1HbOEy󲹌gKtX}P؂/>3[ޣ17^>^1lm,eTz|l(Bш16w̅V֤.?\"bQctͦRsS㑹+}.w$ic|tS1+[۵_eq/F%@TEJ/QfT0{fʛE4>[b=  8{ސAltg+9HģcQSSޜl,#֠64ȠsWc\Tg+jVJ61Wn u E/ː|6B*v=K8Ksۂ,FSKz(A~P*^c{{ZʛDL>[b="zG"A9f[3*z\wbtzӌ^*UN&ΔAiCC,v܍wbCϖP D UZuH_ |l, ;08V؆!.'SW,!F$`ϖXR^*Y͏cSVԹHupvN'hJ^̔7'|zǾw AUV1Xr0C%pϖBE {"w"[ز :dcuNVXAT*g68 X%Vǣ@*iԁV0М N6m)<5<Tcb Ebg+ENC ^9Fd$G" -bt%2FG6bHޣ N6lEd D̝3t:{\KI"-  1U˴_e KSގK'z/K򰏊B:2q~ָ $l ]9A|AKk%TD%UzzjB:cXFq:l.ي+ **N9to`r뚉^l(aGXF03wu`P>T dy!U @aJwǞɦ2-XIbZ~L!f 4|Nl!URʗ/ W,hSdcϖX(k_dfX|"^ BK *MiPy1hWy>g/h|Ru@^%! .1X,P2- 24<*Sv`B1;0tD/|⒢AB=xLziFmh|d.F|򘏊SJ: %X:<QuDX|qR=䣚.d/ W,{|^l>4 ┦O{`ҡ3e"7z\zzG5!0Mf 5I"- H*M9-Z3dSϖ|<ÊNc&X1ƸSI9[a N)ʔ-T<>uD'X|.HQUt 3(bkӔ^6lQUҔ+ ,'a7/K=d(wIœg;>6)+B>2D` E 38 L%vADBUP&m ''7lI]F+>MiԎe"%Y*oN`0>[a :QՇ\+6`F峗E4>[rt*Ti\[|qbg*rkBE/p|tT9e L!S*z\%Wo"UrRθgK$6: X ="1̍gfUtgK4ͪF[Ԫ4i\K(k(z \ECB ]AdHv qՁ>0Ԕ^l%4<*UL1f2 i.esϖE<dfX< , +ДBG*1% 'TF%u1(uLS'4qb _EhjFyg4I#\ ARkd^wْ(|LY}a2R7dF/˘|ݔHЪV9ܹ'|19{ \E rS*ekJfDy| gK0<ZQe)ez'oF#4PҫD:Fט̂Nel>; X%M Puի43Ot^6Al,Dg㢷r7,VD.,V ʢ`Di0eBuv[45ux4Du"0ƷctD'|zɾQ4<*%c+gq+ډ.al hkQ:1G|0uM]):X15vM]-`bY2uD/|z) t 3tN5 ťo_g_#_?srz~;aY@ fk[tnXcY?>rp ~tk+#3 ~zYCBoPyU^{q_(ȸxյ?__ogmN3nmиrF[uVlO$' <:U h*Q pg~~aa3 ~WplW.4skGʽ4]dWbnۅYx@k;5S5QP ky2xQū: g~QKƘz% j,V:/F/8( k `ϯ%=?Tm_VyXb,:KiЏUrmYK 1xB_&F®#yнD8ѷ؞*t>j:B? BkV5p`]YmYgvUFѩgm53P`M>xO\;5Cw4T!U1rJxlJ@^r ;JȬ}fkcmUZ#g ծ*cݛpOLm<ߛg7sD~szyԬ_HeIr`^X.i8.zMqT)zXEƟB0es~cI "#h>١_Ͽbu W1{_Kz`f7~P<?oAϘC{t//5|`A 6كo}~|=4?NC--\K~0dE0&3}+;㒞;K ETdeKARVWʇe]myP^Ii|*ujې Dnmu >.2y9dsWͪe'Իl"6~mmye`y \e+:5.hrP<ÖτÇe]º򒉜 q"orL!IS"+Ibl!RYF%BNg鬧D]d^mZ 'DYٯG& N6Yw [кlsRW=.W[H1yke]BIK^bGEr'̻lE8/R'*R-#o;D]S*: X$eKۭ9QivAF^U%-esxܒ Pг wͩ$`x-PRB瀅۽tN.X;~䰇e]s,U.! EetћxwҬ"SEjג/M%-.U LA*? _wcSz-[4}%KX##G".[Q3KH*FN9l.r!JN[]^jG5]L-P6z Pe+.v[9{>8\"mUXV܁r,m(BUW Nvp.[J Z"9"'heG".[Rյ4^$;DVE]⺄( ]$vHG̽V\NZxJ ΩC7'ܻl][+*(6lxJ/Qdc{E䒢Z7MYg7'iѐ:6Ur K)z Pe+z&aJ^ەKBߙےl*%UPwI rK$): X$e+6գ= f'̻l]}[byп ~It/$`"1)܇4+Ifw12V]Z˖3NacG\V/̖"l*U}Ɖ-r*b NYw ;qNYMU-[QٟhLwAfRgK.&_*-\^b&Rp g+jř8.#ϙY2q>&>$Ep>[r92lp̥ Ҍw$`VXunjJ[ 2yj+:v){h$)PRv1<' OWl\Zb>'umgD66~?lŭ8ג󁒛T#[>s|e0>[aչ[3IZnx*Ұ#l~gK\]rH}'W*Ǧ".f$PϘc'7E/`|cU[B1]~ZiOWlUtԔױm օi$-g~(kb>7'QlU&gh\&c'ଞMjK" -\=a}ak[)z\Fἔ3ۘ#Fejլ\@E>[Rշ(]6; 縷ߺ^Me >[Q䐄zq6VWͨ#P= ڋRC=s7+#ݚNK"<4UD+r]9U):XZw[Qp,vFbiF/ |䎝N,X_`VO|-EB)!)ϰ0vh>E'шYv1ZrYbS&~Voryo݂?֣h[t gз!%CwsR?.bي+)դSVٻXt gK>бׁdLv0!3LR_c>[qC"TK~7i`)mQϖT&< ׁ{mag>޿9XFV]KB}H2lO=5E>[rWtX ő $[4RQRc5wJ15I`"-gKDNwȳ@Si805E>[ACcA+{{}h>l՞ȱ`M MW K"$N8lDA-=&VytH=K08YlU[:{Kewf޺ G'{ĮM#(*ʗ@Q3V{"d2NJK |%.ي-T=΄XrO5@E=[R7 -?jo1ɞ[1TƆ)RR=ɞLK"-oKKRHӹH4ͩesVܱm1j"@l${ c`DqsK!.)ޘ I@"mL; coL4j^כe>[bշA%VJ R=cdƢE>[q6En[R!ܸ5$o+x9wio+$"i%p ܒ1;Ya^Ԥ^!lɅ%-1.]$|h.esV\vndȥ t\*.vjE@>[BWז|*DWE,6D|=cpSD#f!X*0oVۢGק.%@ϖճ 5X$U*8ס .^Wu_)P~QjV%w;} Ld)9 XV5 ;m..m;6BԔNlUߪPJU ˒*C?}ɦ2.uNbvV]PK~8z \Dun5yT+K= ) ̛eh>[aC爭1ʸuƬ/sيw3yq-M<7@{l^6qlɭLY;%*ʱy/m"0V{OڙYs/^;_4eP>[rյq.qM o ʶ=jzk:E/|wm : $o{ag~ь>!lDK;5 IUԑo=Hݒ6<`۴3+NS@E0>[RWR.1\Q&o^6jZq6ʡL%WԋF/& ̥XQp܂7ׁD5@E4>[Rc׈EE !J{~QVԱ3H1jU" 0ۥ.ْQKZʱxY_,|cCO ug.ӪlkW{+ >0S3B3{W;3RPcQVT-z@:Kxt泗e(>[rW-!V*uێLjxOF/P|⶝e^E(>[b kZYbso[K2R<ӫTܩB>c1%H L~D$>[bկڣ;J)X|.C)P%t蒽gʮQxܡM): X)`[MUSޏ%l.يΕ%zʁr eNQl#쪊+ZѩyAl;yؙ<$CﻦTt gKvj]u'X lOQPI"ڒE)D%XU^K;zw~)eG|s'O:KʯOJU^v9 X,g+,6@쀏[uokR\jo$`ϖX3B@Վvc]/K6x\fZ]uugWU+rŝ>l6%誫+ʫAwSdD4Bn=x̬tlX<8g/{z!zM{̪9 %p>R.:}ni #3 >,{NR\U9~#jÏ?|&ْL"F6{mto^x~sgKZ_#%WUDorl.ي{)pkEuxfWrҾP/M%p~V\ny ̵UJֹ=e=[rcuٝku4%Z]SkMcFо1ƍrΟTtgKYӜrٝiuVp"߼l.cي%Rl,ëlE>[ru Φ9կmu~iҬHdxe >[qջ[s,0RҬuYġ/֒ eS*@l}ׅ(~yTJqÔJsk¼o^6l]+Fwq۝nuC{޸&]$`VXu֣ԼqnQzkWߖp𲹌g+Tƭn0WђLlgKzm|ŠZ<."ي;v2K)f7/;rΥf0ʷq\ 7n}sg+d2gpP]uIK85:X[r;VεB}׼q;Lb~X R~Ս Qϋ},|cgOJm/ߺ[5Eh>[Aձ;|0hC}\24-ڵ]7=m4@E`>[QΝ"*l3.bْ:74:(_ =.ER%e啁&,C Mͨ^`Tס.sg+Νu) KCTw𱡌gKꙺ:U&d{ZE`bX!pujCڠ]V2oNQl-;g X*D֐ '<#l.ي=4WjUL`j2E/|N\!w\ ڭ\yj2Eʸ|:EXd)J| Nalz*ԑ]e+@g;* >g1V{'Nڑ*lY4 saC/^6Al]]OF^ VT7k73=!lY>j'ي5'Gu [%2l.ْJj[ lETS"8L4NG"$-c Ά˱U/esV܊)E +F*S=CzLXv)`ɼR:/L7AC䒃'zVvtu& N7`}sg+SΔbEVi\Z盦Tx˖\vdJz=tWPig]%y0"ٸ4yEg:?E"$-зTlD}uXu$[euĉ-&Sg+cN&t+ȿ0H4ng&TgKzwqD]A+J pkBE/|⶝QE.sNiԓ~/hp gKh0qLl}gYTD#sl)ݪ.ЊRawϫStgK[Q5NkbڙVo=:pNOH<,64Ja/kry\T*rgʶB[Fi#wr|qO] qVv1Ӛ1K%^!lUtnVU.eǦ?]l&ْYϝF]b=]F8ԄNl =#v3,KדC*xRճuͶ3Y ^ &ƆOͧ%@V\T*W#$, [qRjկ]c}J g ; X߳%; q3ndq'5rMzv1{x0o,ej)SJ}׷ N=Wܳə(<? o~tf6ܟn5u[O 5&n.e ^=9^)sŕNOg\>k(֑gS`tt8V83W9uP8W9ÃRug/.­3ȫ>Ǽ, abf窚yR N0]ݏΡo:WnZr]7#XkdJ0~v(3hDh g)DP\&b7im' V(*P!-N͉_O|mgqi|xO֡+0=Ou0B ,s[C`:*4~w<@{;ڶ`t;u؃o'+\ٿ>^>y7\]ݞ l//a/}αŸ [ƒ?XNn_p{y5xf nFj!oѿ4OyXI<顆Z6o^BS-t~OX6YZƲB2WK?l.sJckY[%6XAV[aY2b I"$[bKL]kelEQ#@9/uU5ϟ?=I8ʲ!ddՎU\4: f/tlU|S ko#qz=/zVVԁv 2si`jXK8,a."+nj4QPa˓/S̆ɖjp޺P̎߫5(3$`q!Elonȭo7//)I`"!&[b bG\َ=Y+UWIrwu5p3=bMtwWvqڑ^#Fإ j\U}=BO90wQ H1WSE&OQ '˟v:䱫ӛe"ON PX.Ũƣhn㲓p^.5V8X.B -DK/ l.'J bPfR6;Xe+Ĺv4f nދ;Pf|X˖z gۧqyKr&K_^ ,?ꢫ-] G0 Lik-ҌwWSB#NӍF[uvZ%LM[g a=V~l1 TͬXfڃX=mjU);=?~z-&Y,.bIvN.ZQߋP_3n-6$ZdqQ&$ D6Œ Te7HCo#㎦,.{}A-d3fN0sf]ݪ\W#ȦX [qx(i`T1E u01o^Jc Jbd|SCME օ^>fŵ[p%,C,@#~K؊~<ưXkSͽH=SX5NZ$5pTMŒT[X5V*-%yŕ4mX.wwm1LqY  29w7+QeŒk1ϑQ儃lTRePV,MZrҠVɨBXԵpLdRLٻ])ӭܸ_H5*]E$\,MlܥmyY`;ND7' #R4mb٤ѕWaJi)+&!.l-E:\jelE%J>k)`񰲸 ~BԊ;VHћphˍHXV<}RЏLF?Is[qA_,[ F-V:GLNE-rF_ Rzh.PJ^[s84 D^,IՐ:o܇C^nF(IGF+ٲg\>ԍݾFNUڮ*icj7ڄXM-{`27/Jrkl})iƢ220F-X WѓYV3"7^X/'KXd S+K/X-l=ƿBA=P$Ĥp7̑)'LTp,QmZ[l_fZ5'& 6;$A1DTn%|J2Zq̖:Ô~* tJ1e ڥJ TjaqGKrm1(YIWҸ |ވ0Dg[ ]Ʈ3Z`jwccLpJ6I檑$oqKrA9uqąS}fekH z# Xk S67~;w)) CoǷyl3X^/ӮT @ ݈Ͱ)_ڃ 6V&>T,NL}V̆'o,́K+]ޤ@l, Z0AFO4ToR4\F+sU>RxEoU:F+Q%5):V,PƕP'\E2r7NR8 e '%3b6*yh-uL>tE_R0dqS U~<a7ltE8%f\ bS V$"89)$\XZ?穉o=$H~)*!%\;h+dE=ΌaEjIjQ(ǒ刽n4HqV*onjSXTnǒT1&Wl (潳pŒP1ڡCouq^Kw*Cuض8$ΓM ݈k6c&5/(vAAYi^I w X `K[KZ]TSGm,Iy9=t &-{ Ď\9Hi8c%fTWtcNj]X9Gxuh$N~U2o,ɝWp( ^Ial,*fc)*M<ǖ$}.K*;T4ZΈ~5]<!\Ly56|qM&l?lZq'nCJ IF$n.uq=Tt%L5hu-2lP-u#^n8.}ܚj7~c& 1O;K9a#lTR;DmXdBm2x=i^wւ`dQKR'dR- ~x-"mY y%O8%I 3lt9ߊ7"[ͱE:42o樒pjABcXR\ +r-Jbӽ9r7Bd^[,AX 6ʨNcR wl1 AOm,wiblsvF\KgBInk+W%MVNIaIr7*dTkmb1k&}̎UXoaKaᚷc2B$.W.ۄ]w)lִ+$ys6?5pMžo,$[ FSj8-o6r7ftui*4PMo&^›l,ɵHC::r;z6=`7 6.ywmѐmI2|$]U9=&oe $`l!29XX6OJTY;l5o,ŵ4#2k p̔"8,gciMVsenAF]oly=l CnVMj5vDZBD\onM[&&}XYMo,$[.SqiAܤ+X#ek"ЕKP[2K8Y/'TGSM1q>3ӵb/ljQt嬸fːa\4CE#R6bae6$s7lD@PXڐnj9c(m8*c)jA'\]&rv)KT9YXnƒ dށ8vqCf QPVE05mw ʙP  3TZ;A6I F\K6 Pm@[HHZkKe.Շ Go,IuHC|Pmb:%ɬ%^zXqi/HG4Ӭf zaSad[dl! f}eɤPtHM)Vև Go,EUJAؐt t.EheqKrmb%0MOńTEn|oeej×6%n^QŽÊk+ExF/5LH)(Bd݆#b8Rh0n܉[TzѩEp,I%ej6%5a*nޅHy")E&}^'/s KƖĴH)%ҺJxeFV'r7V4d s2gҩ=m,MQZ[D+S&LUvΆs09.0|Hԑ$FG&}po,[4h Ivr3c,5.aeqKrm54(\o *SqEt(tgPv4؛ 7RഅJK jA''K7uiOHkЉK:qTxYbI-A䖚RFGIOBvF5Tב7E&%&"M2Ea[f$oe)q7lӤ^#oU(_Yzd+Xk]%k L堕:^P&FۿR.zӭWF'I7*BhC[p0Wj 5F2^LpЪ孬Fq8lTe2C.Mz@r&TD2p,K澭XFv&m}ɍ1j9heq Krm9`**wMq1Ӎ델[Eۅ6d?;c5ý "͙*׃I@Цd()q9`L+ AEսVm,ŭL_zE<ɲQ1&#Xt0lۺdQB{:6V\Kdƥ ꕺjMxQaeqKrmA`ښeT2=1ɯu0ⰶAr0"1?ֵ1&幎]݈}w^ `;1JW׾[q(lҤo)Q91&]Ȣr'8vܪ5Lbw Jg]bd*,цb6ˆ@5ݑ\JOS ᱎ=w˹rx_Xǖjc6قi5KCǏ%մ1Fq138,cI-H X[4DXbMbWkzXq\Rܶ҃[Y7 b@`q'j }5{=[h fq[ 89ͭ1GSpYYfp,٨I<0I]%_i-/am8*c)jCr&YRUn%-մ/&e]Hr3 ldCЏjv֫){Tbj>M|a 7s#䣚6Ǥְ%a~0Pm2Zq4B8ioBl`ԣވb8^̦k˕#Ÿ>w2s8Mm*1jVUjwc&R @l zm8*cIdSN)Ϯ3'3vУicL/'T愉5lVzTsGLrQ ]+1$G*=0 TF=ʽhaoƒͱS@S zP[L:)̮Krm`Vf7; DUaf9^2H$Ӌ-Ok(T͵p72RɶQ?T&婊] lƒ KdJ@Ua"9UlrKqE+- n$UodaCKbm Ą` 5fk6!8jXocAjM3M7j1a-PM{ކk6ci 1pj+v@Tmn~R~r7ںeM5R!&ťݮ GMsu#-5m2f{T5[q7ϖ2 p ѤΆs;+E%ek&#9LmzܒF$sBiYTJFGg~nQKKRm |`J;jvJ)kΈ9F/.Vq=V׆CҚjc61RkeA1 69X j2HFjCG"WWI f7ا%iVf*>K%qފu펎̉M y~`&9E%[\dR;EU%U>"oqKrE\JhwgI!T%-U$K[q=ُ;>٨pk};fMXQХEޯz+U 5,eԧ}y4qXbiX "%Ppy*ɓ3֡t4TFp,ŭ+%|c˭1UV=emV8ؤ4,ai elq8l`T;d FGr_[BF:Έb8^QԧN0RG3rsc"(ptЉRP.E6(7:dF)ꌸw+!c0^p)6E~4Ec ǒm4m(E&@Ø2S릋gi5VXk+#/sf{+(Q}F&vm,-+1i&E&95\w 3/Qfꁎeu%wƛQ2EA{d ku>kc$jԩl8(vcIheV{C0魾΃xXoeqYKr'E^#UwD⾘]9pO)h͸;h+ fq9.%q_lU®ÊkcFw| ~ZuoΘBU,0c)pC7AVU;5f`;Jҵ8}a؊u s{2T7!UFO39wba”`ސӧ65Mlьkcf҄L50Fob,TE`of'Ks&"iJ*d(J# \gamKaE[>]M\qӰKf蘌v}ja3܃:*gMɇld-wa +ڇykC[stvSs!7]-, v mJa-@~k/dk n+ d˵i15s3bƊUw BԿG%r`q$ cz"ヅyGޭ ?v:V9~>.nf4[G3BfLbsQg]'_bMYC}Rz<~T9broH 7xSӉEBA4̭o*:#\)*05yS[?er?' b3CjNMM]'h`{Ķyɳ~V[F@?V iJz^xVU~nf\Bj{Eur?EJ"{.Lpߋ޺AQ7_,ʛNG֮n}8".+g;Go:/j䴃}̟H{&*o䟨Eg n4%RE˛NGee||Rs{ehYSH-gp|<NG5ȈT8l]ZR{Jf_} ]|T~MM'Zl>G LSXΟX72ڿ76Z03Q7:Z|`JRˉUMu'Ϩ_~1Pm.w8yTU fB,?8LQ7uJc?Ϗ3X|;])٪c)*oj;"fO$X>ZO($5yS 17 FndQjwE';5m>vyxT:Wy!q>hjy*]CvM!9a&R=O=j~?0=Y/'y$ʪDu@-~v I6ԱϚN+l`{*}_}UG~ҥfm?;hR?RELQω H}xq,,OzQF ~r2?hEm߿)fƓPLVgM~pAWޡo6lL;MVs"?9mPo P+&=b=5wxhb?H.RIzo~\(`98k]ŭϚNU$ϘPF.&"RlWD1Gߢ1=uK,G55E"leyVdָWޱM'ѢlYp@"ϺNa!Oػo\ێ٭,'iqۮ/A瓶FT(kyWgM}+)O7$b" {=369mdoe>)z6 f@)6IvVdbC]'@F؞wӡ"ϺN}bXͬ8ȳ~(_>h;V6ub?l`d׆="Ϻ IG _7nQIl Õe yPI tDԬN ޙ?a~(&Lm'q~TYWa?glMu~Wg]'[Ywl.6'bX#  2t?*~й(LtNm?*~Уw~(LArYQ*K]Eur#؄<*'ɈbD#6aAy^ r<:T#6 n0]ZUYWa? ; t6 'BN93yȳ¾vDڌpwxVt2?/loƺNlD(&m>0W=ȳ~THpӆMڱ" Q">wl/*~H(%ND+ȳ~0a|'`yha}Ev+A`ӫYq7FGEuA[ϲc۹ca}H{e`^;2 *잉 2!8I5& 7tz7U#a?ew5 L(g_`LAƣ!^{5S'}zQ? 2`^DϪ 6GL&<.Qح8l["v&_b}.ԏ7 s{$/Qȳ~/2)}zFCm:}\)5Ged0>:-?|#cVwϘ+ryhnA?t']ZЉP)1z1nLLVgU'CuORwQv,+2ފ~Ȼ5.br;kw}{c]7Q 5]Eu=ebϝFTgdQ?%GCN`@K|j}H\!̘WzEfҖo @/ëՂZR{SgE'CrvZNMmÆ2oZb wޱϺNXUܷ G~Wg]'Cnq{7+ )Fw.>~H!$躏 +j<**YΟ1?SIoj~˽1͔Ⱥzlo񬨨rgU] C%G mȳ¾M!iRS=7YϊN֎ꊰފ~HnQE󭻘L~*s[G FBv~_d~H=J@ua2 zzkXvDSaP 8({ko~H A@|M4pnʠ;AjB H3P3tl߭8컔L8-3xVt2?l(Om T-&3TTOٚGo&C04y\*RD:c GIzkN^32c=' ؐwِ%MwZ, u Ujk xvǒP0Tj SM5Tc jΝz<*,]ž~¶S,|$QMjg ϚN($t2[ MjRPM%bק<1Czųb-拁 קut~Wg-'XCH%艁ߧȘ՞xSPcIcT"zanܹƳ ?z,N3K-dd-3$g:I%}nLyD =?7~X`H{L0'Rzg='X F"kƳ y,A@= ƚJy,#Zn0%Roo{KRT*j;j5ctǒXG1,|SD|wxVuRѳؐH)  G =fY #C%cI"H3hJN$籌lsڈY+2ϒ|uKB]{j<{gb:%bX[_Uд$dz y,7j͑zN-}Ǧ#tT4PCxT8cITf2]55XnԲAwh%WdJ~A蜉<@:) hNoj񨦘ǒL]4sL*D1өac /t0tMEhJ<9ǒT5oL*bzW 4L_O=4%*:+Ŷi DmKRΝZ6hf15e`f-'ސQ 2EAy,\C^?OD?\қZ<9y;b3trQ[ݩ%ՇLؗ gCD_KR YԣTIm,(汌r -G}$Aź([0w}WgME<;4N!i_X7ҭ~q:edr 4(W0=^K1%BxmDN wy,uKWYSa.j+%VYI<:7a&PƤN*$A@=7xTTzcE͇ctǒXGyaǓ SMyշYUQ@FS`L ` ZN"ܠWE,&0 _}~~u9r?HGG??z]>7ty?o4owX~Y<'=Gm_n}Xч^oon7+n~/mtCTߜyGm_fۺșw3+tèZH/]9GrX^-!=B ߇k!尴9 a?JrYw2qqfC1~zt`][e}L6߯<Е,g<߯וbavgE=Gu|bJ4/{Œd:z~}Ԝ~Wur$W/FwzM]?v$gG62g3C2TÅ>UpV5îm8>9^mtwfGg9<?9g&=*t_6_OtN::Bslvlr?st @.k9_2mͅן7͕| 8I4Jڅ4:ZSH=~<~GǴGxZ4e|gO@u U9=yw^I.n^|Y|_/0zh+Z/ ziz@j* 3e99n5g|r>9aKGΜЯz,ʏo1˴_KtJ_o w2 5b6uq/pQaU?ET,2އ#o:w2͎W\=W]UHL2~D;ob);,A(ծ8*c[Wᨁ#"2*d/r9lW~2M;1l35*+_9nKA+mo# ~c ]3}IB r-z.#WZ@6ũ@+_9r"r_x"g:YW~#DDq3E.ǵ{޸=ޱ].긼ovd7d d;v%WLz]q`q7XV>MKx=efr\^ Zv@,ղ'[:@+_9r$3ҁ))vހe>Ma-#W|&s`ĒŽ k Xovuʹ2;FmTכfG9 [G8p^P@vd䑫1GڄH+l do Yym1KZXG9yD]{F?r'} _r{$3 kĞύhW,[̭3uZO+j ToKg1Q6HOvő+Gv~Ba_Le疷XF0*N$ yoqB.rW<3O%__LC(x%W̓ qmR lW?r` V6Zް+t%pWB^WFs$G9yFspyn-,qy%pW|Ȱy}rnRbOW7J|&f )z)S'N8H]8gYW#/ޡzLMFcGǦsSێ/䟰a9PPmTβOwezlHƷegߗ[`_y͓z `8Dm|+G>Qvm, {O'|}zs(NQ6a?cS{pG,?.M7|]߿em MMVE8KZe!ùz+Ni뺱cyյ:6~eggx-e輁)Y(Mf} /6mG~9ȆA0LF5Pp l-nm#՜.2u9e+t_WRoxܰVͰoGwU&KV>lw[s_ذǼ(};_|{86"=w)Hs$6w{5/8f˕ZwYyk~}>gs֜caW0/É;mr^O*f>k|xV٢f} O+zͷ=g$VuvK>e5sXDbiAHu<_'|0J$wҏ5e[Sjo~N,گ@3,a rF_XRb[uWW}_[Qݑ9aw\b7'Sυ݃]YZWj!d7‹6m~|qʷe55ک>Bfl}#u c+ze6{af?=d^l@ܶ:ޯ9 r~16bN,(+3+Yy<+k1vOn$Qn,2Ư|[1~86GAs_kMWz<~|-WC3SbBx,5'.ՈibDj@_hE?Z= [m"oPD w9ן CaM^?.{!'ZmqRdˀ^]QdA5 M/כU«*!m4vO< LR&Uo QF1WN}ݞfv3< ooe1cU0ώK F"DEi-k7}%̹uFZ'|2]EW/ O^:cv$^wu~ qGof6ن\ﱴm'4?]ņ#Ov ZMlcS_^[cS[Ǻ5E#,P/c;a} -N AIV5Lϵ!ړk?Q=z8^9jWݽ=*7f`̦&'XY1,nQj!ecͶc9x[.n|̲$ke/bޅr}˻dQX\wږe 6 =68k·NN 75z\sĘs⸿mTL?]lp #@MCkY>HqtQ.uML;~' |dF ?x|0c@wp]_q7kf fNsw 棿O6>f~1-HՂ|~)+1?hkv,ч.aY͉d9Xn"33$3\At.%oƁRK'&i2Ղ#˫rLo@\"3-"4ډ#QqNص5<叇GF,T,Fnr;O չ\f؜X(Bߨ5u#rW%2:9'%of5"$xb,tӼ !;:7h+ THȈa ~0F(/F5APO8( sY\w* vybIm/P|q 8.c)05|фIAI z'_6vB7Ov6q-P:F82R.M22  NW m>%KVLf'uFUq3[,nO :;K%M& ]d؛q`$|%)ѕ/5T5^.B<63 ̤o64S[e^)8Zvld9X]4څN.Uɥk.y3o$2Re9T;̀dogyR6"tЕ5\(>8F?p!g ,oƁqh5IgT†u;:nJX?vGGc)rC'n[,y&3KC#A86|AjC5#?}۟5{07]d6в(g 'HDf(cI0_+'% lp,zF7_8KjeA>«x.RpھL8Kq+z(.nAOS+%#4.O 4ogy.:Hqr貽l8 թNPt38K;:)qA]G)#mR'pQ6Op8;/5_F#R9ANގY,Iјld$wo |^pI\ތW,.+kp+uLMgWI\vfGbI9j6!<=m]-oƁq*Wɏyq&l،t Z5 fK@Ѝ~9#=i44 M;V쏥<|ЫFTejV4zfS k|UYoǑ%KW@D+D,ky+Ko,mk<"|f\qK]PnM!oqQԎWacQ쏥5?x85ʍ>+aǑ%ߞ5,:FͥrFR؆/khU ZՒKTv9PVh8tS24G?"ۙzi$$^YW+|揇?i6u7bGefU7%Ž22RЂ)fRÅH];jFVNXk*;3u|z朗5?Wt8 \7}:b5|v=Vc%Y`89|A?go YBUF^~jSG?wrpQFy]U7NTEdED@%j\Uf&KS50]܎Gyh`K3d]53 ,-袓ʡe<ȝuVX7sAEc+15*UGܽ?WPb3U3)Ð_zG?$?}2ȗF#j|M,.y4\t6lFR*2ˆJ7i~qK]\OD!WkPy+ o,EϋvsW*0F5DK3yS6ZaHJ֘fXl)S6715*EYd:c)rE'yTQgp:TNqǵe/N.eunA 3N<[?V+פhdy;Lg,I64,d<8Zƈ_v80|3p\2ɸ5 \ۥ,0]T&?򷃢R dDJdvX2y,q: qU3R^ =!y UQfoda%f3efռ4nΞyg=ތKB\ukijո&3XTS;]K0BF(WJlfX AԸSl ٪R|=9 eJHX<1N%T䭳tǒģҹjdrhd{5Ċ<8.Iݝi _vjdy;H3T)8g2' j ;菥 Cp! >)*U76N.$׼S5iC SBq4[UvX!ZQފKr+LPH0utd8X݊K:AGв'ҝ4Ʀt -og過]t[5҉lMi3vXqg;pi>wj5E?*1B܂+qqތ]_RjpqKJ>v\iȉO͎Kq^vf 7%}ݲ9B?~2 YLn?vt"e:ۃ{(rlrfnXM)t]Fa6ԷGE߬8.$Wwi}2tGfefq句tj5Y+]9̼G?$_ȶ5 P|/ :ڸfnA8.uBIlWc*V4jzlTOΫhy;,uPl/N<}߯abHAhHYq\h4¶]SԂ/ԩx69/ eg1)Ja+zz8W(yةȴDZָvY2I$yI?#nlC?fjEBF3 IgGL֘g]svYA$|CIt)5әf;ÌKƗWtU gJNpCOgz+H5ϐEo^^'hF#g Z@7g./En術v|h o]73׸^KXp 蠻E)khe慔E++IPk!y%܏Z>ь{]2~aAaحZ-V MˡY/G,]C*utoHy$r{[3ț;x BTގ3hTM3|Frvwxqdds N׈B&q&BnbDπvyj}R^*fQnVX[3⯍{kHy++_k^!;!e#;ou-l)~k{3LP EC˖` U=]F7%bFRp$/%&0Q980(BI젙Y%<Պi34E(@0~Q-l$;^x\׉^Ig Մv"# GJ')hq쏥_@co\([KZQ4Ͳ%ZEVXxh6:odЈ82yǫ䂮Η;xYdzcIrbѕ 9% zI̅jUɚOތ <wtROD еg4MSF>4G?$#6@ɠV8͋Li yYdzcIyGw#BIL3BH%kx9+ ,e({`4PV>ϦԘD"K3V) oatZ ԙ%~V3V-daƁaKUd MRM#L ߐzؙ^Xr]Es'T׊I+Wdrf^Xk"S5ѷjF:5?  t;:Za5ݶn* S)Ydc)rFD /I)8sSK5ݒtL5G?$LY[AI+zͰ}} qfeq܌ηFRj Sk,ьW(CET$T~$ZDfX Asdh52 ˼2 ,gea%&WuX:#q%zYq5#2\vXT#' =}e,+[r%KvXl~iY73{ *9*MSɛq`ʺ̴g<2GpQ@/ͧVjs4ŋ0"3ɏ OJ j( ?{+K,5~k^4Hϗ_.ъKqZw,s))f-fag%ɕl2p.>KF=+idy3 ,HײԎ#U3em.D<80|$E rCzz񖂾>VWP+J=5̣ڡ "ǩ8.\W sCI8S5ZQ,0v0b2':a5vF=*R0pǒ܉8RCӡQtW2#kh!\JG3 ,blWc:͕Khf%p%]ORNz:+zp q\c)0Mf"s愞fdDVKuduv5JjH ո@mM3əqPcITEXnk_j, .S? sheD+2t baƁ񏥁 roy^9y "Kš{NCa5pm\@G; ,Ig$uwt6jƕ`? CLjzlFXF!tvBJ"K'G}m$e4L> J`q󏥸}t[4 ͨ5yYX:cI\Xs)aʅfT%BG_Ycqd|wǒɩ[>Zi@Y3=}RP9qdxc)8M\Hʾizy[K'F|H+ez{'hl}mQ3Dž? 4̇ܛ_S{EMQoIf_:MCG+M$DCi&y3 ,&f$Gʼ p6<ԡ82cI{…\'z6=m3;|K'`Yfί)k;m#5G?"s\EZA-3&z ]&oƁ%\z~t\Qܕ봮4ť? Cif,i?FO80\4&0z{Iu%DW':E?"wrF_3FF>͎#?N]5p$sFW_vnX<9i"CO3Fģ*\geapUGR*N 7qg$tUu4ǒ Blmj{dogdͦD VgAwv vBVNЁ{jh50"3~l$'L6Y؛Y`cIrZwtdmGM&7pǒJظ4WPvpbc*uN"Kn2 j+V5Cll勾.P 82<$ټW K nCWyed.oq}tV.󪬴F_3$שj:y;L,I6s~l^ac_*tj|y; ,EnHĠ^GAgߺb B;;wxUׁ^ոW՛qT8c)}Ds j 3ClS~G?F^1'`FN!6*7:Y`zcIyZfvPSya"lˁ>q`c)pASRr'-+Xtu|A6/l1إy/ifOb"rzdZT'r1ͅL07!yꐙ>keix꼝 ~\0~|hGߙ#aTF, j%Q]LEuV9ۯx:ΡНGڵSin9D@lJqc.E[&-?*5Q*ʷ9Jd-_.kt^}jFL=ѥq}_7Pj@tf"9TRӜ>6_̛<VIƗb-[9 SkT.ؽdV{9fzWA;-됌T3~AJyhW\Ubq?Hfh9[_bnnDZWA~VHRq%saϲa1ԣ23L0Gs+`$_8M u`]Ctskʷ~O>gazU=(Adz^G+]f?vh4RhsZ+'O6k\y<x5-+Z]6Ėu.sQeb :"芪 ahM?vcu/ _7 \oיO <4~/c9tbWe;ʇqБq읽r ކUMͱiL6uuUMmpu$놻j0/s\L. ,-'[^ەkxUNOr:V8g>ՍsO͘W.J^_Buq[ΚE;oy]c}X(OZ}8ҵzپ1<b+ciZxVlnݵ5;RoՃs 'ΏT҃S;_|d% Wou53BscعR_Gfo{֞Bs:kj֍;ţIl) * ogM:# cI2oSEGu#^ڣ*Dq\R\jtoSBTy3 xXlɠ).t(8ѱ5 D$a,TniYj2V%sfV4T 8r旨E;pX [*r>uV$V;-&fM}"$7nM:ܳiP1!Sj z+uj̘@Υ:;5:3ʫv-? U}RGF$a,L[jT5ճ阎GEa,Ee1շ5΋klY4Jt8: IěY`Fƒټ) a2.ko9;8X\ߝTAJs [gRC=,2C cIlaTՙQɡv{Y-_w]6Kg _ˌ"0Baw'gOQRvY bId#0Nѕ#aƁJKgTIJIgOfhuþ6; _K]6U mlk1Ct1M_Yv$y6i+)g;r.6fǑK)]a$)u){Lrb,En9N)6ă%9dF,a, ]R&'NvIB`֒FwBvᄱ$y0O)0K5Aj_R_zaǑOK¤ ;Ȍ'%Y[![2'.녩8ŨBT.i~)*bn[ފ"0ζ/:(= '&_Ȍ'&Yf#JϩkhezYٙq\'\(cee9TEf8a,Ef&Ė9:̻<;Ab3ތR<Ҹc5ͬ'+5ʉǣҼ<8*^$Xzْ? ^$r,2 cIxI bbR6QΏIXΌ"0޸3N$馑e.[ vf$x4זɽ-uPv"%Ɲյu;'A &%jS^ptY;\SumZqTRԂ!-q{.\BX.qƅ'㰈$l\Ӹ*/4EDg`Β݌"0Bnjb3J_V"30"_҈ ]݌"0UAGǃr3CI2zjdy3 ˳Id99#Դ5OdU:cIlRx-Yɞ+y]80X+OP[b&J M!NogM2߿-9))FrnKrg k[EIWqL; ,%$d/ F cr }%,0}͹g_V Ι5!WI y3 ,f ۶ԃ/@e]IKbg뒔 owܣ+р*EoǑ^Ҷ[qC,uްKc<8,$y6/idAŃsGHr͛Y`nR`(ZKʉ; ͙zvArVX 1!=6EԭiPy+ ,mWlmGHS)R{v͡ "Kվjb~EJ2ۆeKΖ?82Y-g=X6= oX\O,F+K#xڵR7;,U/0q"}$.PaƁKոt0pgޭLcEH,KuӁ:ds㙨.xqdxcid׾&7i-]*d$S82Y-tIƓavP⛷ǒd vz._5+QsjG?uUcXRż9OSkKqy҅ zA`q{ B%̸8\0Kaßs!lG~vX<[WA&I@TBtvX|(7 PҢq8.W+S E݌1L#7wPag%j1W XNa.h?[FԖ,uJ&* ,Q}uª{)/$϶]4Q`(Ў'ƕRdָb<ӣFǒd-f ,2lDNֹť?>EExjd]='ԗ}+X%SkҳR KTC.oǑ句ey\`FktNxY`:cI. .I6*,ASN8p"pRd6PKQ` R𪷳XXi<^Tl80Xk\P~\_N~|7ǒپwnௌY:7aWWPbM1,:aa%ɳuKP\q_q)=M`O#˙Y\zc)ڗ'8د jҔ.Sәq`c)pǝ&WW#ԎNk+,2=$y6p&CnreךTѤB5G?$cWƳw4bOM2\]CseTIgse 3EJs B!!4-hǮIRތKٸk < g(,q| ,oǑeK"%Fb28{~]{'(F09:OH d;` q\xcI'&JG8~ hVXMD[!` `Yi=pkpy3 L,+ Be ŀ洲,.W͛G`2mX.`͎#K#KuHtW%J3wA{b7XT23i*{(7?M V X<ۖl ŀ<5mWGpR@[c -{'̎$.}$g fW$=moO[q\c)wk\AcvU(V^=mQ,ogijS(ZWW|3ͤDtR؂]Px\Z(GH08]5G?$}zn\Y/-яKqվ[ (`܌gSכq`cIp*]_KS3`K`rFXZVt1r5q63'+oeq돥}v_*C 0ݯ9fSqd8cIr+Bу:clC8|7tǒ)J eěspkhy;>v XJ 9u+0pRXKʴ+KYp >),24j^(y Mn'>_uVX [q[.Y̳诊cvX<צnB؄*Nd]o|pRdBkRP$P;j%~  ;_] y`ea菥j]j+/Ƨ3%fƁ%yS9/WX] TuvX\VxVʘLGv,I-\:7l(^tF])#8.W\i+>WnM[Y\cInVfߥ{g82YܫIu%il9+ dž/l+ z0K{,H:6{3 7, . 8L895Bza5;;LG,IV T/PX3ҽˁԎG%/ezD-ĘSA5Uś0vܚ|H`W XS 63hʼnM0]$xk6 kT_b.vXT˚dmfu,2^Q^ Eu,u۽vYOPVTbY, ]궃\ϩ,0ǒ@nvT(H9wJ>n4XBԲbHt ]헢n4pǒٸ:oPX3Tˉ;|[ގ#KW .5nb*xl$.$4i> tN]@gaƁj_Ȓܐ:Squp)hfaMUП[_R MoBogNzc)2wI%F~u<8ةowB˙q\ci\>qBחxj9HqR\5o LޫPS ƪpR@6iEŤ):;MpgƁ%!b:D% 2?ܩǒ Fܓ8v!yo`7R{u{IcJjly3 L,^mঃG]CH2:miV 2gn*SGM]jOޭ; ,E/JHYkE'V<P4E?$efq 28zn7R`K+Wen*{N ,*$5'UqeK\{|h~ְV^X;GjQ_&QwhR%&΀.pMH{} x$EF7tRb/ 9 v^XS]裢nG]qvA)ť?En a#3Av_ޱ$훒'"'2+3pRH6<4L{<iN+5^ť?Ena_p{4G?$1#ջWؗka&]M˞+yEªy6P܎j|A9B<8,\42Eyf˜Tkx*t5#oX֕ pBl?n`2cR \Qqv&?$ym _ԭ65ݭ v+ o,e=j!˶>/: ǔtwvX<ǝN5v{>+)gARd~$~Iavhty; ,Ifr9vKK T kl9#Jw,Eu#q*|0o5tĚb&$g؀v4m.tfbfX "C,VX4E?$f qwf0F; o,EWl2uz'E>!ZY\c)}!K Иj%+jGތJmt6t@$8`-\ ͭ,3xRԊrW/ @ q,2=$Y;-!l1`2 Tx*ؙq\c)GW/AdEa3 L7, fȑ86..YqXc)l]n{fYءA.mOibDž?u:T6B؈9 =R2eÈR5pF3prp|ތARoert>I`|!*02k`Qh8($d/Lz`Cqt"6; ~,Ev#2)[0q|ttR.`#~Y4o#mv »KRp܌٣lVnf6]nIG5RcjlO?Gc#5ed9ԄB5ca _/|@jڴ  ezovJ!Sx.,nNeB"튭ƕsc&5f'_$~[WΩϩߌdvVOnqۛFUq 2f5mlǼl|7ܺTf';tF_29.ۺv8QtPmca`NQWW~pt?Mi'4b$ݗN[5kݤ>X~!`=MCK{^~׺ #tM. ۩ ˺ss,c^x~5bV-ZWqk[4x΍?Wq.vN9xm$]sfy;= |RmvxMc7~kuk4VoM[ZhVp[mtcS㹘Ԁ+r7egw_bbAӮiVKYniUrH~GǙfaW87#{y=lg!xƋ*5u劀ig"tmEF-}ab|kL~+6/ߜ71eؼܛT?]lp5 -@m3b@?xeQ9ǺJIgv485VL0hOe G>1mɎ75/xeΛw||a[|{(-TI NX\^N;yS5ڙ+X<,+828)hԅYnDmvH6cvߛ%hy{60]P ˜zr.Ē=%(fnb.Q:Y`FĒv#nĩyuCy.<0/AEhǑK+:'dlф>>ff%_&{3NN[ԯIa.cL@͌knbio'SczR2-X,2nb)rō; 3&Rug#*OV/+aǑ{KO2:3ٳ*_ok_3Y̼ ˗-j#w]M#1RƗGYbhO,ٮ˾Ǣ#޵OthլĜC1ьBЎ^{7t&O *0Yf=$Ǒݜ&$%*hij?z8%/2Wخ̬F1j(lTc 5ӅݸZU+yY^82†bIrθkTˍ[rM FU3r(tg=JG__y2pڎ`:rxn^3zl2Hd3z›0&Œ ljX;У:u:\tn7᠈L 0-lIci&9Z#YYX%ŒX[|Kk˚qkD ]Mގot;&Wd#RatśJW,=Œ@`gR2nY扺w53tF!O4jɎh6bOe-$^,[9{͉rQwZV(lŒ91#ю"M5wՃheqM A إnΈ,"D-=8FZ$K"BM-n`5b8@2]Xa@[X Q|0W 7+Y.%e2Ink˴SRU5]p֦YLrc,X,E6lH6NQE fݽ0&)`Iy"qq:l-TL䴈l+kMjiH6؅EX nX˘RZ|.sUD94q`R`:ʰjex ߌF 7tuᡠhGwҢeZ KӛBSzx'Yt,([v4i+4ù0H4؁4r o2֢d.2#a:`gfqCKrmd՚0ȇq܅T婣hE[Yڕ:nIП܅Wɢh5 lSbXyjcLm^m q( y6qX@ǒd[-e^Wm|N'6Y`R`PS[ȌNm6lCEΊFM([ --NWhܛqt,٨Ij\h\iQA;q9 7l=Va':lX]dڄܒAѝD;̝X\:{bU3n#j^`gQUKQÑkS;I>5cw#uv[ؓNsڐL{vj|`0CO[؃RmY:w\5ڴ8$c)*):L|bMcЮs5kBhǑṉ%ɓExQ͒LxqJp{qwHØ^PSܓ$|~nf6p/:lX$^3SHtQފb':ڊH%Whr׹)']%)82c)2OSe&*K_5Pڔ0yņ̼,SyBbaf5{ѱf]XqKǗV G;X,k5E5ܕsuarhgkK''7  0ƒCގ|Y d>ƹ Ҧt7e.w_M^t Jo9L;%fm3-fKA9&vCsaKBK 9qia#ۢeҔtܤ'^jcFZżfygf\3Ìc/:YppAy̪}ϪK`ogKũl jBHY[mv}Ƹ~]88ot+smiHs͸vlhN["uݸ }q8,6$g "A<+H_zy3 X \CwW;އNMi)IJDz x36vm elk]J\slv\K hoWOZ񒧖b3r/:`SqmQ3EV1SUPt؉%LcIc{S6ڎ[ɶ3u;󗅗4Sby#~GY v\ðK6HSyҠ*ԁKUvt, 0)v)3ڏ+PpwBю#c8"gܹJ/5EȨɅ糵#Ċ͸[ikqTlb4jos@8cae 3`lbA3P[ TLF̔;Xl+ $ۢԼ\gߪ"hƁ]K'g5 fn-u}wm4ufH8Ͻ9J 3jwcvi"Q (_^x xӥ}qdlGR䆞GϤC"╘v_4[XE-g,v*ž̠rIbDfEj`xb3қMsGNJU03!K6+Cf‚fO[H.]p3YÎ#cK:FNXX(r}r7SkW!Y`nR`a(=o1Sr= MnI[72amdAƯIdS!;=dV,HǒͲu)PΌ6SJ712Î#cK:"[8Eq|Bbd-'ل=ס&mbJ}u&I݄,ngƒͲQlI3Ta7V݇GƮt,INt͙ي.= ݺ]xܕ}y‚΋M=UQSW53Xqq*2ns;X6K*UsQZ 6FH|tI]t{Ҥpf[ұOcV܍C֙9ΗUC&#XX㵣gefTO疜4do={ha,Ubî&;VgVBf=Xa.el\+erG:2e -e'J9$ծpovƱ*]K;nC3[];ɺzҘܔ8(f\%KkV gѝN1TbZGe⇕t,ŭLj mЛ{\-%¾8*cI-VFNqmA3S@/kCN#XMތ&L M()Iqd㇙,nFǒͲՊ׸ N{VT{rd.wtb[X)ZTr"~RfƱ$V+SHA^sOդ͸)[\gGV9L xy=9~"ne5{ѱdld Nq4v6e]ʓ̠0؎%Bia*#/R{Нyqdxnb)22;gg,I)~^ΊO[^,Zk71ZV%nFZ8͂ S>feI)*Î#c;:"Wܷ!#_XVAj;rRtފb3:ڲeϩ sQIqt{3N,Hc+yѤhgP}0XYV붞.ATIGMndynU`oƁKmk3WrP4=E DE^t,Ef^dŝyѤgPus!{baJ[0eS01m9`ڸfw_UK{VU0|@gĆÌbG:| \7hwZLuj6%ɅJV+.1@;>5E7-K`3NJ}sS}v_ޛq¦t,٬zk۪FYBe,P ^zv ,0c)pCG[-e[Sr4ތ2z@56KuhONBoE[07tRςF=9Nl≠6aK6KʱWZ4Y h=.og%K#Wz-n $k3v`aǑiK;n1My$ Kj3+QHAۛbknk[kX(H vqW:lD]]ͺ˫= Cr9wPѰ>4W.o!N1Ͽ/\>ADZ_cy4IhZ0u ?_cO%5U O};oV%Ӑ3+#eO {}#u%?}~8f$q6U;~"eJsis"\<_H2зF7$R03})߼ۗjSe 6Ɯh?͌ R4)mR Qek1+"ѳ&oj;e-ܫ!UMM&wnUyvr?NUnN?~VshN1)qWMu'd䐌tCů&oj+gUȿe@$WGSC^wSg5'"d{27,}JnDbeU/(1 m&oj+gƀ!Ɇ7 5yVvb?J*ʆ3WWvr?*F 3M3="VM p~T> bHtfu?*򬫨"rF~P7Ur?B? E 7fTaS^}ɛڊYX.rH̑) p~˛NG鷟_~ pm[mkPk٪~T~5yQ7lk 8[{q.8s0zdȳQ;mQ6"af?hEFijeǛNG!Ϩ$IyQ7fwȦ|ɾ.;Y,rH>0+nhNV7՝fܻoH; :n dI`vocX1E1y]*~T[?(ua˹ckMhƑKTxGIlli ̍$Rs`OYwr^䂉гR:N𦾓Ik̡2*o+G/KnM;7k )6hhIbk|R u3oVV7ֆ>o& {.UnfU-%ֿ QkLQ[ _Z;L$RIVtOÎ#RZɊC>+Um)]|λ|`䳼ʛN'-)YGYUyYRR}ү0WEm5yS 0_ɮ*3 Qik2q |zOX}tL&1٫"d򐅽ʎ-yΊ,l~LikF~I]I$ʴq@H/wuyS_?&m #'h;XUX $1wzVVgm'l҆!pl"_+Σ&oj+Ga C UOF`AD{UTW䏺F O0}daǑJmbHo]TVXى?qH01Iom1y-E2aɟT6pQrn ˻U6Cgl>uDb˛N[mO:>䄙!1?y˛Qg|br[Z3&NluySI$):<6!cM}'!9K5K꽽˛N'AWEvv"!!ق:M}'"!(Mw0ӻUkfJϽ.o+GaCɡFȡIX"\N^xY//, B2PoHg헍CrƄhLr$~qhǵs'v!>wr.o;ɟY6ɇ?{mtdőC}'>E;՝w%T|;MOM' C2OSnLwuyS_?lFV=m6 *3'=+CPFE{˛Qdx8r)򦾓I=H(IqHy8]$$8$آr ^yuySINq@F&1Ή9.o;ɟC6ɩna*o+Gu3e'u Cd<ӹvfʛN'u 3egL]UMuE(st' Cr8<0f˛^c{ {.D!ySىq"ε;ɟ265kGu˛Ys&Yb,;aǑ?Yl5d&]w2U/tWMu'S|Ys"84[W7='?RUN5{% =ƭ"ϺNLLۼw,Lf򻚼Md2eLd~J5)*v?&;W5Y\_Yq?&035z5ic>wUySIj.&>afQtվq}~J)2]\l]no*~J~_R[ݩm'D\dϿ~;.=5yNL YrvL 'l5yS[?Rt柃?Rr/*LYб)~JaSm |R[][UTW:^?'vqHf5;|W7}H 2yQўxr?! Uu6S AFX^b=T97 &c 3&&oj;;KL7m\zʒ髞vʳ"||\0eUMu'SCWzQsU c oZ>έ:aa&+;&%+~ʮ1HMЭ];XSq?fK֫iÌʯa>Θ15wUyS]ߏȎnn\K9lK _ԾA~{/亶Kmŭ\_gK~,uqRLv^j ~,^ȭywyUTcJ9MPc)c*?)83a1 xSɅS?z s{}W7YOP+>ޒ{9NX8$S1ks5WV\cs M3ʿN&oj;ǒ`ac}Ev#JW~,Eub),mZ焢k]ۙwb҈2 uxqLc)kvtoP7#2q@tԩBaY껺$Ñ˝\wn;;ׇǒ\>r)._Dɛ^\c)5h4tM’ wyTuBƏچuJja{ڱ>4#?_;w&nX)7L"o*.ܹ-/s7p޹>iOXZG7_D74R`!_W7/,+[}W7^X8${,r:䈿dxc<Udk^ <0 =6}b&aӻjNN%<,2=y䴁Q~ |.#_ !;*` ϚN&$M?"YPcAqjS{ݨ%՟8ɏB !; a L?Me#?|;XUYdgǑm b=dNE]aTD =w_,wrָ*A*vTM}E7?"w&ɪ";; w~,EvHrYwr9$sH.9k(#›L~,Ev[;%McxʛN0lؘjQ?_:Xtpށ̲@_oLRR_GLT^6J:ߘb[^P*u6D2ǕӶ*|mvػ:?va;ܖo㊝?yeyZTpځ %Ns$kBj ߿+- )m5V_ڕ{Ĵu-yuߖ7uZ,ð Ы4mn d݄ac]eayesOׅuUr ZCf@88>3w<9W,&%h^%FڛqHT2:tNV~wW.. wqzZ&_ӶVOsP'.yƇ[Ҝ^WF ٹcZ#f{Xys^_m`wZh"m7(éXrc6iH}_lnF1G{Y8;l:.4sq$Ʃ:LNו7dю?qdWDCP|} =Lk^y5#MfA@:īA#q֪ؖ=ZZjYE*񃆣"a.|ӮTكywxy^&mt_WFo7D_Bk5wt)vIM>Nz6Q^Ɉ4,܇yMs6>T|/{E쯿mgOԘ&T_){,JS*>h>)|,^ӃS'럫MCyŇzk@} :~pTrѨG㒯'7r+5KsCHNC/YN?\ &US| ʏdڌ/%øv-a;l4^|)ث|0 Ea,o0+[p^c17Z{=ZBl+Өϙd+ۥ+vLm+Aj{WTL[boᶁ}m`+?9~P_dUĩ#gĎ1#ٮ82ge5t䑕d^ dU {;ojy[qGBȵ+_9nKANqpв~c7[A3]ʰi/@-9m\#G;Oixr1wlɼ@v~Bw}#rnd@vސC^[ۯ3682#`Sewyە_+wsGm]q`ʁj0"7-*7d.yX@n?,~țG›g+\[5xZUa 8lfz/%L6p$y2=ê v֍#G;Oxqdud^ dU {;oʏCjY+4.ٮ82#3_XrxG#J ۯy>4+=;g3TlL|^cW<@gM/NM-~6mv~Bفa5~).~m`+0B!sį,J־ۯ&g"VQ$7]qdʑyx`GZҕ@_H",He#ەE֯y YviܱVp|IX΍++Gv>uva"4%t%WK<2{ߖa;r<(_ӵÆh-&i9.Uh;'6KwZߝsMP-!j77nr.1ܸw?CߦJ2`]3vRjPOP@lN̆]\'w-nT#ᚕ}3ꏿ˗ThϿF#޲̴a@0 բĥgmQ //f¦!e}fItHc^>56KYcc (qNq l0Fk I5S6 9k c s5e"]s_sf .ʉ$܀nKklQV\jWYzuյ- vWX?}x=w8>7GE+sakemw ǖʤ6Ǜ;ݞIVj{FsۦMYTWZ7qE 'i=Ny>~1gZΧ;|B3L7_x ~_wOJ>Y:W|j$i<X۶ȗ5bkzU8fM?֬o/Ϊvowǿbs 7n1*m ,c#TyGJUZW_e3πmcks wfmt )mW̞^9fuԨ'Fen~0Cte~}۲,‹ ݬUÂs\TW~+zeSEyO,([6ں#X]vTxe `27ތxWnoyW*=Avn7x+ƞ+s`ʷeY"r!q׎=9σ_˕n^^5JW,jsijCzsǟxDT|?G ^A?-qQty8]|w窕>kR$O<% _ + FxM }4! o#$%,R"zbW- 2.vfög3^::` 9{Ss0'g^SLPv nx 9(^O X1iqFtwD؅ӎ!XHL2'b[r{PՙY>ί<-V#P{]|7(X1i;NO߄0q4[`&g@[`vj J=n)X'ʙp\qĎϛcky4N >*2fqWߘč Dd"TN^xӮ ksM\8.Fi, c^IŚmeoX,:G#`әCV8}f}_sҹń}6dǰ#\1NJ\]y7jap Wz~ />f|TGz.Yg= |Z ?h3ÑOm}K׃ œ?֬9i֟M wol۳S%SuhR϶1OT[qoS ?+N%8}3vZǟ|v\~qe02)O\cd*^W2&Ty׌c+5p6+۹'KaI~pMdpTزV$wRR>^3;>0 &^ag5K) j0ו29shdFCmؠI&ρ_]]<} ֊fd$X[-655:o&eGR8+ MX +JB8;dˇ'(kp^XgqWKr'j.ѓ וGXTnQRT2KlQ\փ -v rk")ZKγpqX$Te؛#eWK70W溗Kȗ̦K37+'KjoƁK'gԽ^7G@8ϻ,2c)8Zuǜ\Wtt .͌#6:OL! F/ǩ+w TGFn,E& 2A4,ZKk6e %ɓ5ڧ ;:V ތ#0 N uWG4ͧ\׵kx93ˈX+L:o;Ztt4ʅ擷\z䌪_i ::''AƖ7Չ턩[DϬ.tjmFOz)YdĒi >[ӼbXUqd4RdqtX0F_IB5E`/ȜTm)}yEjdy3jXehTo=c4:]MSqdCǒdq~vT8 Qv­LpcrX lS8IJ0LTl n怣`p+LU`gƁ]-!jQibZ\'>:أ.;3Z,p[q;\7m^PF]VbIyrɽt܆UC>pD7̭K+z(&pAG]I-MUdgǑ/ntP4`8񫩔s5҉~E7HK;z辋}e ,BJ=]f<=KsnͥrSM7} \gaq5 >EgL2P1*b+z:hkfyXY\#tjoN0:κRsݚJގ#ےsdM$󣔑C#6&,=xRd1Jy]hM%;5jFO["Xq8\s\)|idYDvVKr-fgc)E0f;/OpE_9zfɥR_>,0ƒ`sZ L7p ^̼V jG\f' csv6[3 ]{8xC}qdTü)̭= [agy.$jp*~ӕzx~pTy=ZYNIukR]2XEn-Ub <8*ΝRaeW H1,7:+_$׼VïwY5̍?%p*TSvǿb)rG]\Il휚NFnt8Ks58Ic@7\[ix3 t@D\C7P ׼])hh=LV?ΈӀJ<}ҺTnt5p̓IΌK97|FB<n ѻ )0tR`ne4RDj+a0ǒ`5UsXaY;4v*<4G?"wtRUdA pƭjSݭ,,$iz[;L,I?<ӈMd pO=t[wPgs=80$ƃKWnJ7Ӳ]Muߨ ю#Ky8uGAo D 7#n.?:z2e8pCgI82\ om fM&M AïSefq%d.q 8j򎥨 S>y])<PОR cXDž?mY@5Ɉ?Gvf5/ׄ+"KU58gϧqTiǵWU?gK@S1+ʭ,0| T4pBjCJ9z$M$oa=D]dD,UZ4 -ga1K<)2ʩa;ZTfV&Kq::5{2'ۍ>Mp1UIXގ#KS58ECsb(_80[lޓrY ȚUthhy3 L, 6Gdp7YqIV?ɧV0j.WX[VXEk\g-_TKo(kMsvXw5&F7kSGHu ȚHތK :.HCqůϸW,2$\TFN5]v4S\ͪK95G?"s]KDy<1\a5*Yc˙Y\cd(Lw -Xcͥ~}||Ϊ?wtђGQzXj\UpRd|C?(# TXK=vK;_ۯ@*ʱ8&*$tR.#VUaƁ폥l>25nKOfg폥85]2'#.mFlU8.|$UEFDٕ%I)X4н$ @"%T Pj^menY5hO[xDz[j>f,G娦sӪ HT[DU9`˜IM -}/F,kITaoւB4y$/nlcYt I`mJJӂ~lI.kAiz?Jinlѩ;1;OSHʥ,.٪1Gzig / #Y}F?[*ӵ_\]Gב(ɂ2ӟolG^_!ʅɝr]ZWO #+qkUuI(\k4% tE?[1^eվ/^U%Mв nlɅ(zH)/)a>G'V! >\Yf iPK%Y\U94sqzK{5y_cJ*Y`f% n$"}-rhfq?Bݐnylťs[|7^* 9uSf"ߟ,.ْkA׭UCnֻRolϔ˞`t\.uI nlɅ<l=N2j7_'0>/Ef?[ ]a?vƗ-5Q"&ϖCwR8 ѽY>Mnٍh[Pq{DϢ( XYT#ֵcha/_+Ch@ȺMn8t#/-Lg+lG|کG=*i٬ï/~ilI.tt)j(AM޵M7RtHg+0_/~y!kHY~?<$[Zh$C@B[-珎%`ϖXK Mʭ{ :/ [?OvljM +XT!<a>UtP'a)5!ߖO-+婒&'`Vg|LdZVۙFV[Rhbn33ue}C)lX.yMS*YraX|? t'X_6mtJ` Ϳ`Ÿ-&JxP__0t!RBQjpi!Ulɉ8Fg?KdEPoM;--(8Uh8hmE?,dISk ګOSGG8Ρqnn"F vnB'ٚAKji揈 cZ\"KL(Y-C49Mv YYbclTnZB <”134Hz'+EhK_}fBEIGIV!n(kq]!A"kuE?,uhIF㙫2: hr/lU-qt T4D<]@UL3 Kf!@gz*}Jc^n8*DݕIϩΤL\F4Jm$CK+Y` $+@CϏrէLdruQn%ʮL7=rN4}#* {g?4EϪU;+{_>nv'ٓ(21V?_j[-hI;-^F#o6O S$Y-=4ԚBnT; -NY}UɼY`VV~yk 6?%l2Ɏ$ϗn:ks(R7Lad~咉} ֪T}4]^0|ڲ,R=V[nn#ːj祅rOYگ/nlf/jaY ΟSy:\ngϖt3Yivg_ilpoBA \ZMaM;0[-;41M+V7*N-3+k&-Ig7 ̴[M? fójn?p.VVg+rƥe٤tK lygKr9ȖMR7ίvf`F/vC˲I-J4+ygK%F~jq Jrҩ{GKz>'KsV%VgIS5F/Ru;Y.I8ɵ|ĉʙ?]4 -,$kO k 졛) XzfdzqZK"ЬdW XM#-Z[kt 4kP.{#8Y`%1]7Ԏ`{frB&V`bnn&Π o9 \c'6^Vո㉒?Nx"-tGi\7˲9y^'ϖdp ݑDRN^_F/ˬGɛN՘P_ZwConE?[rRqtM 4+kP.Db? ddYG2H$7D5 )3-V[ Im8 .Ě5s(7}Z\O #-ΩSA] Pm?nil At4JJkHhqE/Cʲ j:v"zf~bf^,يLNt/AGv8w ?̴$;iiYi5}?9\9P6&V`an&"' LpG,2ْ,}imYiu-C5s,7mu3/~lIvԈXf-qnfwg+0ҩSFYY3GRj+yqgKca1?-sPf~r ~ylE4 :.-׸™?̼FE~ent-@O:'O Wx"ktr+b툵l^lIe@H&Aʉ@fFOd7 ;ZI+$߇Iμ dYt>$5rQyKAp~hZY7{)+t'2e(En~lEd$4,Lܳϱ4'0[ӵ,ڂNPf~2s,]wSlEG%Ԙ5x'Uy[G.ْ[J"t-5lH}0옢)ٴfB]Wg+8 3OZMBM.5 bmE4/~lIdcǥ4 '^Ÿ1" [ѺTEf){#جC./khtDs@O?>7,|'|=ZYK [qIy,&S"ʬr$E @$3` a˅0U++ dd+8< xPZ}B'yC6ciE@Fq|R>ZZ<'&WgnD&m b4nnVI 5e*K0[qEsA6)/S 1-C:YddKs~ZZmB'AYhczBl'qp[ ޜƙWoٞLg7 #l vLҲj:n2̡\vc) dd+ $֜7Ě6:)@[kr/˫6Soday-MgPb%{iqͤܺsd)Z[M ["tT-ۄj-IYȃ@H,06xѐj+v*j cӿƁ(߇Ut8V`;i ZWUY]B",@_'q-ɖb P߹ \6s('  [qbV`3R 9B툴Ѽx \dK\K=qgbhS++!}_N, 2I m>%6ߣWjLjz4^(f~ww/jB5/x3f ,E% Z wcsv?߄* d_n]);{/|VڿOLo²9-PGK.ܳzzNVO~o u-jK-XcGa_P/WƸ_.riid\{?߄(u]j^ rtGQ N/ȟ/tǟɿXOٕk̏%: +Wtåf߇˕^OWXK_\lRbBj71^QJWرDZ-X6Y,u//A lsHJYO _e;27=7ly74v+e kt64\ݺ '=9駾 :S6WGW+2iyV}pLmS~'G@?9ꊑ61=ãWBOK){=Ga /ĺ}eEV9׋ܒ{(^v{{o .h\vo^k(W5QrTK?'8vHҼ<,$Î~V2?}q%o<2X(I:R|<D2'O|ID oAh@kʛZhv@KN-^xa=a$CioAF-=OH'QOȚa 4?Hy˯n~يl#hDu+87a{NْkY!{W'QpRI0[aqx)ե4B0' S"0[*խoAu_q6<`{GRn~ՄيV7ȸ^TأhiE?zlIV7M߂>|J`ˮ8z \8A5?!u:gSϲ?zlIɹsfC(WkS7 rl2sAvN' }UASE5a,)>M )L6Y`f+wkaA;ȝmK Zł@F1a$CY߂0/GtD%@F9a"kKruD:xD(^Ȭ'̖dͰ)Кj=: T-&pQM8-M_|1x磺DY`f+0W. @oyugѡٞj'q-ɚ}H\ Ag E?lE:%2j~~A:xHԋEfEavTfx~5Di*7O 0[5G+'Շ#" Q],YdODC,ļ5wjW bRoc9qkTf+fhuAJ2c-&qΜ-=`'b2hяOG `sx<'j)'QQ->C?!1(W()Vsw)AkKF̸-(t$e7 ̊l I%g<+/n uJ H`:`"0[\ݻ&Yׯj Ap'T%b}z=+EC*w{BЋEUa$T7p0+zD/˚lŽ܎ KQU<WɊ^ي5-ArkiS4hT?̊lI$g8(-) wG JsK3 9ZO"3럭Ȗ5&6'E`#w\9snf7] rsw\ĜMriV/~lEV"k7 18O-fϖNڂے\=Xx~w@F?[95(-r5ǃо_bwLgKϮIBww4F!5M#Zq]$],U|R/5?$4s'1L>FZY"3KZW|n-,{4KE?[q1:w(P+,"r?8YX5l] J>jTtg+ > ~pSa炿IB0\/x \%קjU[b7 /Kw{mzfEf?[5~kNE%pϖ\h-[i-zUE?̤"s~Eksi t ^%֧2YVWo?[1]k+ `$҅sz͂܆"H,xYXf%gwkadEg==WyV%pV\ή_ZX&7k(-Aë!EFj#bM pNֲjH=:׫qEoHg+.'W/]FZ)ГKv_2~fK2$PMRe6Q31 N"%&NGWU׫IJh@F?[5딆uX1Pd!ZXO #ϟȜ+ROʜOrp,*يUt]?u-/Q޾S.rْ-EPi@ύ%,0S wjf7#riiE?l)hJ9a@C_qѺ~)lED&q@Ձʢ/=ץ,.SwJ"s^ E,ETKJކg,.يu]$U5]B+F/6J=+ UXCH1Ydf.Y.jl\1JQO-&<[}Mk{5HL> :@F?[*"ٓau1GgK.OQWkxe{K)G?"s~U ZAiM9r +./ dG4bU5ٜⓊ= ﺇE?[}rHY'(;-|heE?߄9̐$]5` hiԺf/>3 9RVM"^~s^8rsI"-ݸx]i4)E?"wNI!JnAlHgKʂkx~ˡۣQy^,0 Gp\`w<XSlhHUrk]3ܪkxxꅼ ,rيWBl=Te?[b}zd_,j: B5H2 d$B/YW6<g VLgK2fB/-:Kej ,@-G4BQ?hM} P*TSN_ */`;fujP/ZSł2->G_ C:t'x풯O #럭cxS=J:^:^9l=.ZCe`0T1uy@F?[5uŒJUuh#b/7x \d%wP z*M n]^,0 鍬:Tȸ,tݛN5οZYbCmwQ7 kҪ~l&zCif)SiHg+r! ׷z&?Kaj#-)ϖd4]'Ԛ]e`h [v<'t%pV\OT֡[]nzKGR~diF] ^qCqC¶n.bޓמcI=礟,l+'#͟->U΅Sþj5u*q,2ي6&̃o\ ̣]R7 dd.k:SOo)JWK"ϟ->[-W0&_,0 3u,v=`viC\%: d%*Qr+fx&(ig+Xm$\vQhZ]O # ޥJ!x./"&PVྊ05צ: hZ]"3՟-ɚ}>'jT{K/TUEn%` 47 lkzhheW,x.uU棟@F?[I7IArt$?l)I"?QpgV亊Hfy7BU#\&k} ?l> yd׳e?[q +Cjgu`OQIpʔٝȚ+ _'|l__ EzHgKfX-/<Sx5:FfV`uuiߋm#U6 ]ܓlUC+X&ϖ`_欉*o1`{#mUwjbW{8H:@rO"-]; ˑ K5G%nE/a*"gT:$0ϖXr'lx~RbF?[-lr)tb$,s ;V&J&r,<lI K|HpAv1Hf?Y]!D`])4sq~v [K*` q_bD^ @j~]+ 5*,C8)D.2->;7Yt+78%<"zK"]X%ᤠ<(gV"->jy8 Z/M ,2يu$\+Q)/nl ~U5ϔ %`S2U EPC+YdfR=\lgYj"@E|1dԶOV{(ܝ_*2 \Wi˿uwy> 1'3->AMz=wgjAkpg+nRqkr .xci%7> `yט&㪚=}G"-qr޸, ie 9IlE'Mf! к^)l krګKuw^MnlVa̟ ϣeqϖ\Tg}`qp7}͝ȘZ9Rt|M|rލH1y X%֧w Cw7E1K됚jwTŻO"۟-&.Y0j3~SN['3ŵ΃olu&sُ%y/Kt'nϻw%`Vزʻmlrsr,{2ZYO #ٟ->?+7^6D-SqhUKfV`M .L*ߘ:nl~VJ&5F}/qpLg Geg&laS4u| -B#ՃMj|),rْ|ޫ Ɖ]YjcpfV`MR l`fXWM#ן-׹o\aVQ.* !,鰻Y`&XkZZM|ޅFnh dqDCϮkmW㙥C`=w//lŭ΋ܞj&@7RLgKZ:O VczڣqF`haE7LkzM VVBQ )~sYdf%ͱoA;S->pv1ZXM"ӟ߭{up==)`/<gVtgKϯjm' 7]Tݻ"3ןȖq~k*䂋|85, `8Lqk9޿Q3M+Jd!g5=JTZݪZZM"ןcUylǽX^հ8ߴE?[r}* !ZY9L"3۟mxl4 2ْ\kO;C`3S.--{@(T-d %~L~&&F+_U@38ۡ|ϣN%'!U4Sa痽yU[Һ>Lg9zZ󝿒J݅Mܮ+ JLڦy铟HƿrjZ13߁d̶L}o!~~.q0fTɯ&,]sR^jW;0ϑ1sk&)k#y{Ҍ`x>Gy-:= u%~q}V}5|?Lrsյr]n5r,?|jZ뗇Pw-~{בwu9'~ώ__&A3⻵Hپt'i[efRсBޝ =gt֗S5'H ˚GY ǂ8=ݸR'Euibv7<:}ZISܢh2.ոу o0̉0&SH=kؿ{7ٱ П*^ڿߺk铹QYF[Yu7)ʢNUoЧ,So>763ғC\ W^>m]yvp_2p?ׅ¬Iˤ0WeG<` #R -y΍U.?:b6vBYWɚZtKov.Qwv7Om9ͯMG #WKybb۾g`7_'v[mskB䓷Cqs- z+ lDٞ4 0E]@O+]"=t.Z|fm->W]ɟ\ndz_xڟ\/63s=/H7[g6۾ ޢi%լ2>^aK$ߦ?1:˘/ ^6lz4r ?$vɇR@=U{& e2r^ ּꅈE.Rs(uzȬVQ2k:q>x6O25x{ȨɖZ%-{vߜeUӋp-:4~?<k7ș+ B-NW{p0@I1Pעl4Pk,.+q%W\ l%hac ?ԋ@F)N${t3?0i"~|yERvrϏ ~{>侬x|fJnn֌X-gon/2Xvy5URs,2.^0’IAEqT;Y*yv֨'8W|(W3Ϣ( WCSXjl"'lsϚ+ΎHThLr(U*&vMnء\M~5Dْ|ݸlh3/:ə HO 7/l}L&#WWdkCyRݭWKyr#Ь&F4y(9B)[ΩujN ~Ty&,ʓ!|9ithZ>^F}f= Eo~Jْl銳hZ;&=e 77ywybktEjkp]y BT=U eaY-m4S7.qijs n ]rn5O Si4 77:|ںfe{6L'EeT8[E&l9)ۧ̿ЃͶ2idT#w3 xYXVeKR&U'=%:q}fF?L:rYxpAV6Bpu] }>N$&Eu4Ni('Pi%ֺj < `(VZ̅~W4)`R OՄuЂQQzN7i松0+fYeR }3?1Lѫ3YՃ-Pq`9X"ۏj!mӪv~?cO5ipfnFAXeũ)vQg_,ȉ@7F/26dw`I/+0-Tei96["j0+.m=4fYm-]j8&g<̱ݺĥ-g?rlEKςpQSc.wĚjMw۰q"gӴ r~ִX̖-eɩeZvꗵ5c==+ d؁51iMy!j6C֓ PԲeKRN=|CX*}-5MНw<<6iMj8ck=Yb\6`&D/{Ȳ, ^2J%ٶL'S4#gm3"V.[.qhLj·&vL#ڔ|a851L|3ӧt1t='LvpV8+! T/ ,C*kf?MN$۾er|i{_Mxr/~xي<hζmOk[yx=rv.[ ?۴[UێF8 B_cĵ/VcY+,.Kw} $<_όфF_jš[_$?s$_kCzE&\G۷I\mo3+xiEedڮeR:䁝<~ժ'by3-^.J A|*/״#ΒO!f?2d:뚖m^y{]'&M,Y8xS2v(y hnyܺy~۬F|\Σ97x \gK&휦N,yk5s(5}lb݄g gu$.ϑv ݬi:[N)/s+.9}Twհ"K|8Ζ\ۦ*Nfr N5+@gY.eb s>h:K^ْ+=>0WEA|a8YdgkaOӪ'oI\ yڦh`#愋 't M60r P%oD:5&Pq-=W'0|JջtDRq"8[1ԛOla/!h>($\?۝LOU,8v s;mhRO夜4+|r }h}WEt" fvA5H[#qO4.(>~NMۊ$߲0-Bgiٖhrw Ԙ]~Έ~ْlz tWw|X/y|q݇H :[4\}HC&˖`a l.{ CS*_KY~&7:h~̝|ܮ7jI=~Oi]زL^V:\lШ`Kgy-{K>!xuQϒݏ䤚q&\B"͏뵡mqx&-e9KSKx`ȪyE73lxdժAdʗp86ΖƗ cY4G.~-Sρ'\K۶Lg&f[2K.(wYtX+$*Eÿ|(]&pq(-)mcR|-Qra(Cgyn-QwV͘b)]=M8x 6I3ɫ'tբ[oBmB_9Y=Ѝ ϹOY\E!=!&/~gي w7v5IQK#9{XؕLWUӲ|˻4u&"G7kV<Ζ:TэM|!Wr dIgKmXNmj&Дk"n<Ζ\ܚikMEĮ]\iF/:{txҖ.>~´l d yH ~\$*0(+}3&6 whց!MS+J_&,0%+sz[1uU馇mwmJ6.u6sIG Gwztfl9+? ۖ>.hSnGlەy4cO\l[#{1 `EgKcjƎaLER ut.b&3iI5XqK3+ Yt&vc Wwe)IEslEBaZɀWM i]&qP v*sr#f&toӸ%_\I~:lH[:ߵKbK-Tf_2pNS fj荂P(f?SlIFn"?fj~ra,qf?lE&}יR`K0OVJ2jW'R(ps9"dMrRm~ \Q+E][O (:[p =jA8O@6z7unK#^ԙujtS)4#In=no>\kFʳŏ$:f/~|"rRG;߶1CfkpH[틛9t5cTI!MےHם,.%Wb_{HEfs $6z ѶDwdlg *ȃtki:[NKS4ͭy&{ol'q-ɶK (T)"qHOqR-8k{؈ٰ̏bRZWn-8T{clmZ9`LiAUv_&pq-I5/kߩov]R:[a8C>fvpq+j,)%'\GwexoWeTIDM^0~hRqpeTIDi_,<}+rec/YIFv'7ˣlɵ=0Yz` $#{OΆeJ둳ή:\鍓?ab8Ζc]a vq漮WFat>3nm#SnZq,]M8[rGګ&lٱh̜ōeЄp!wILȅ1o?:( atm_p\M~hoA =_,,%vOri¦l_t6-KA(g?lI=M5u&3]t :H':'\IۛLg,m}ADTqD/kZ<֦հifƦ6 咚' dd#שf]].?, y8/Ζd۶L490 J@)'~'f5gêb:AʻAtl PzA)P0Nړ^,0шѠgÞVkbNlc;^WH|S?"چe:kmjjŗ!y#$6'&݄I(:[˶,/L&^ځACܠQ.27ي] uR(^~G9@ؿޚ]˥gK_r S5/J \7DK$:[q+1`NC[4jj&q-wb5#t rqAIьpm[j^%SqyE?k^<Ζ4 Fۮfv0j|@ޕ_0x ǐ@kfz .'gm/~ck Wj&9)l_tq{ŏ_ˎ @C%F.N"Ks< {4CԨ/v]% S'rv8Ζ\;YؗMdL?qr6Y`g+NsPTM;:J u..V] %UXλIrb$`_K.q|N5I,:[ACvJzU/ͮ],0%akVt?ToAykv=8k{.þc}ځ}-UqMms愓lmNTg5`m \i\u6n,Lq5c]u P\YۋEYq"x dt\&MSn*R՜- m ͤͷwƹIۋ0-Egin]˔\k"4:[m{k 6zt9nf4>Q7wtC9Hzv4٥i]& u7yytr~ּx-7U>k{mMǸ8.EbM(:ۿnjy$i_MX1a.5s5{K0![<VImfBft15/EgjA7Y@O}%22M#-WY}ׂnF3ʍyۋ@Qt$ll5\*få43$? 6'F₈-UW;o{qlw;hi"zQ;Q_CM@:ۿb] JųSS3PɫF?\j4JԭFa#ٞ Wvq'\F]hV^:MxHn:^݄ID:[6J/n&w[M }hqۋF&[:M*Ϝ&m~$7P;n{䋇%oKvmn336W2^… egs0(;bv3Q{~´p&-e{^ ̦#:Uc2%Ya1oeX,25rPKƝ<5ӱ<m3=w3 9$9 vIF 䬚װ_QbEӻrm8p{qC'd+˖ Fۏ96.оj.uYmL'4s-#?٫0g4!}'3>PN/E )YyM˳~"2ȳqاx_tX_˿>l)?Mdo\Gyrz@G6ˮ9K7|PCӵ/o=NMr(hf :!qu?J\iǏ 3*4ry)uo1qꂺDӸ pQ&#Y2sHSƩ@9(ڇf(A1{`YZ[IGf~{~^Z7ב:Pdvܤ7y3Vq? 9 ^c{մצm$c}8T>7uGx=Y893d9C{$Qס3q]?H ֹXwc5-o{kw/Q 1SmlH  3` W%ms`,XީعOyK~s#-e!Q? fb[:^R}ƛ:`w;n` f7Q/Osgㆁ oAҡ6ב:_lre8zb:([y`:9wE2`bpcUn#y3ZKʻVϢy\%[Si?^2/3Hez)̐^e8ތձE2@>7]GERОzx2roTz<7Cu{ߣ2->7\€k KQ~;:ar?+e 5tP7? pQ .sHw0_`û /Cy3\kKĥ.~Ԗ()zq9y7ױ:Z8׎288Qu\;շioO:jd* ]k7^f$u0| \NCyq2\;Q.TorQ6:YQvp=rdۤHk䋜&6}#roFIi绑ֱv<;6M޹}9\؆`V|WyP ɟ_'q@Y䏢^ ?Qwp ›:WƐ{TQqMUe u~Gr\;oQm~v|fN1RPb+ؽ ub~ ee_p'ADjݪ⪛1Q kcJY[j_N*;4&ڷq?U"w .9~'?Um3U7ʡ~ >Ue .V u$(1νvl6 d夶%uۯ?('1Zl(ɜoH^OrO޹ǵH^,Gmz|=NE6 7nmCy3\+2Emǖa} 'Mmz|G{7Qr'Q~w#y,52X :c6;Y4V~RLʔ}HrXI.)Se\E绁U؏bF\{o"wrMu'5 Cp]vʛQ(]>6*/'jmboza; 4X~8$)C?]^f"ɵ>.^UĜ{(fr+n Z3AEoFl#yc Ig{ᖨ]ײ4v+监{6 Vb?D:t-ny77u'qܞ%T8$7Ϳˁyƻ?lTZEbڻ? D?O9Y"8?NTi_67u'0S~q"uj#PkF/If-ўf$oBO"5`E`5܆f"T8 ۻMuWFX9ɟd_q6E"E)7im46۞IqHn%t5ENu'병‹E(qH>ϝ^~77u'Q [y;4Zd1~o_P6xȹMD"^k~wCy3\jb1 ̆>5ncxP^Gܷ-7}\fe~〬ۏgd%xEi~K7yi(oO_`O;V`07=Cf>SE{iƝss`u~KU=r05j07t$WY4Xq?uqWs&/^] A&/h}pHjH!-q7=:j6i"j;d{À+Žqq`e?[bX*Smj$Mu3٠6tͶ X|f+rɔ([Ncy%V!-K2*7sVEIz;=o:TQ?`OT lF ,"oFfF?[`նqɛ s p+T F?[\i=֡m?K.nCyEChdJFκN4ϸލX\V!ת]~_HތV\fwQ,gV`+*uNE??~"@z|y_/7#d?[#`.ifr}77u21Lg+Kqٱ!݆:Z"3П}ʛ: l9so}"3Ng76oF\XJ8/UeGlcAV Jc^:7u,Bdm`zf̤/&oF&PV05%Wq(oB$23ْ9$Sj[M?1)xO#y3Z"}v 9);ˢ2>7R)'699lE r*E%SM8ތչgskQwnݰu"dJ?[a7h׎=7jKl~dFvp?_I^LJ^f2m₲q˵q7nXu0~_g+pgl7ar2ي8  ýT+f3-G\s_GEB?ۏ؊lO߹1cD#h`t^pӔfNEJ?[z7׿q*~eJ{/g+j[;} W;qP\~:eqKݸ&:q$/~lw7u^;9'كlEO7j[7Cy3\#8P^,0s۳1x s-] A*d.W!5͋XJqoT}㦑^l779Lg+l{x5/ɛ d~ |;C 'm a]VױK5F`lw{j]O pf6?[K CY&VٸߦV\&ݹnٹq_FfFJ?[܆ۢ tٱcX|~7 Qbb:7ClwS8^.ي('EE#l{vշrAQ黾ț:lwr\F~ξclI n W=6 Ax3\V![SiQbR\ S(ӿ(tN2o??R=NT|LկvXWn7?U~pIO'_2o?6. 1O?ٹDf./:?:?O}cp<_ǿ } DoO']T+Fc.>y{Kۏhڣ?z|߻:iy3rqEQwD?w@Dl' )g!/6m?UcXQ$wǿ:O(u{3>^>9W޿Ҫ endstream endobj 140 0 obj 357424 endobj 170 0 obj <> stream x}|u"QvT۱c;8q$KeI$P* A hDޮWzݡ~g8DI o޼yҿ_ظv6}}ݮw7{6}yһoo9&sƃGQv7}l{gk~{[~Iuauёb2bj$)&>>*l"Qp*Xӊ)E‰䣧Órc2=WYqeueQiy2EbUCb|zUpnaeaqbXVyrr".5>-6(eޓ>ΡS;%?sbc2J?r: 2ҏEŷ{?Y5X#f֬k-kh5vpjlS&dqKBy?i̖~88n;:;;;::{]Hoo{ӷ_p8 ł1[m.Fk6qlNf7؝v݊nK̫kw&pd-@bQz"`4u hj\.J>Њ?LojjjɤlO!kUHRaL־l6iuZZ#&jd2FKKSRR[$ ƭ&<<|޽o/>===""O>)//8eYs HE\\\__9*1/Qv\@bas6si;~yk?ifiۺBBC׿~{>gݵk~arr'?(z-qܹs'dH{+6O^"n)WVQMO8y$tEHHHFFT-[rrr!f8ͅ:ذaCYYD_+@0z}]]]EE4ZZZiiiuu5NMFSbF>ZvCB?Sxun/pRpzC G!y"OuB]]]puRZt% XXڅXXEEf9#7O&655?*rqbͺ=Z^%D@Q zjHj 9e\UK *k PURiT C |ߤT,JMҤTjf^8$0Ⱥں,MV" 5 JeWH I>ER*Iyڤ@T޼OvڎFW \BM UWYVQFVنa]6 ?r[jŗ1oC;"7M@p4dLg7/h4ztՄ>iGeƮ>M6 4w! tw9@BnoGuJ t?;?q/NV~'{jǏq;J!^\bɣؑjnzT!iSLFP9;7&Uv,?|G떽 wF.+N<HhL&mw_r`ETʀM6vxɡw< o=+l&uo^!ͼ$΃뗥zM~뗅}kl~K+Ml"¶~{Jv_U6tɍ5j^)rM~^Jn-{^?=}COSw{j%y2dqs{|O![?u37^sn=hDps9wVM|^w~{oA/^kUA737ee~ivʪqKK˗',-(ZݻFF-mjYZQdi-K&,MK_ZXaLڢ4X2EC""Ͽ%GLa墤D܏D?wD96% 1r>=i+}??ݣ'd|UmDLY]CCvZp;olS/כLeVfYdՁ5D uF  EEMZxPM].746467jZTbs{{G{zr}}}ȃT*AiOOOWWbj NR0#h/**ɓ$%%߿O)\Y:h]V :uĉѻw A@ _PώXӬ,MLLLHH'''ر#(((&&&..-Nkiضlxk+tƍQuՂ#474 ^ՠRI3QQ[snܢ{I~hD''GG Dx@@rbbdD`/斖m2XmKsc4RKK sN3F/;;c^]]]T\| +Z[ڜrbG555 aFLEz!(}t ۵kCzرP@jb^8GFJȠ j]ikl%_tϦ7LMMNNb1b)`BWcicpaǑ8v b}Qsz_"X3hgUKLJf;n8 v@軬.\Lյ fT1}ll,QQVGr`KJJPLa`Pdh@FV \Xj.|,+ @^ 8  °yf4p)Q!OKK!#B aA |*Bp8qϣG³U$H[ !U?HiUtn N1ZFoiZ0mo Ip)\*9+VB"- Ʉ?$ËÇ18o`` }ڵ Jc0P - 6к%; "L1& D % !' 8?q`ZQFrЇb3/@S fĂ&؃hJ U5`Ga ]]*_MM+(aaf8jxjo 3 d[ á|ڈ+nvp@K12Ghu:1 -ǪbǼ@$z:ҠKTݷ j[x %k?$ AB݂ 9–0}T=L "a!vvL&.: ^A*364j;:t&^\ݶeAÁ To .14THi$SZK/xW}kXJEe3?7HwԛF ^E9(#8\O 0w53B0繺秃eW_lSMӻPEEMM0-Ng|>/Ri\"Xk 4 2"^% xC3ޣ\mȷEԢ-*f|˯ŏf<@J|9yD$|$Osk/4a!"Qq.|A$`;QdƆzb8- Q仺RNMMMLL #A((7OrەezD"A9w CHӻR1s 酧Tzh@ CK4564Zc/ł>y$;!a@@5{=vXPPN1#H|PHII>:t(>>>$$`PA"##ӁRTH % QXf~Z%#L(FkYu.4͈dؖJM>ɦf/b?zT*ʹt,M8GـMP6h';͋c[HE8P&Bra>a4L] slSX22f0UIYkceu4bի4(m,*Y5k94=us=~c#|0Ш5]=qN CÈ̜Ng =}/gETp-LugN'%CXfbBװlI dz"EulA4auJ6Q&YQl^*B4gCjy&iJ5EbeJm<MNOb٦rd6Wlqd*pZ9xlQ UpuEl)65esA՗qH6E|)ck5]^)`riݑ!fl0FLr\@'hx2MVYs)փ0} 4<Jzv8D'0mYH5K xP&jĖe&VRICbն&n'.jkjgmǶcBj(_"dE{M$p-bX×rbبCla6'"ڃwٹb6猿'lgt&)t, õ ɬ% r*F..+7<@lLgzR$# 7@J p@! AS1B-g {ai_fsy'Q(p,A,EMἘ_YEqXpVȝs-9gixιu1ls13ϸx}frsΩo!meAp|qcZA/13չ#up Z'5}_R[7jf{y?N :\O'g7r=]\C$n-@\{Ǔ|M9ɞ.s˳3GM;ltҝ NOPNp_bztā9xoH[IRXb^j^9 oz|(9Dix4vZCXsN(1h\Nsj]}`!"1Vgu}&GoxxdMl BϮ^|dೄ&7n<2X#pf #u hӍid<)umYx ޶@=r/|jm $ƁSx#`N[Hbђ1Pggi:P@daH"#=<"AKX"?nlQ2PXİd&x!;ٚ|6;-H cf$A@pJd*ypzRvXF!)L&{fo]`"m;F.t'>t ƆQSS,DQ')Գ<]:y8qIC *pSFf ?1lQrjaxeDCe{:Iu >aqo/O\#S_D蒨]FhX}7?ˏ }|_gl{K=ΒAneEz;;yPĉӝc{;١>~w9؞K%!aoKyyq a@9(yf|߼tީaR^CCCiii|||NNzn8Q䱱1 geeb5^^PPPWWWRRBߑr];pDBƂ<`mG T$'%''>} ד%t7ٙDg*j롡ᢢ"??cII6)+>s?]V C@@8ܽ{7[nāPFFǑ72\)CCCֆ 0;tvvr>oX)0.ghv@qoⴵUWWl64 Jp.;Xz 8 όB ~ *VD-'ЄRһ V5.,,,**رcIIIAAA111@@C`C03zY^B(&$$GFF=zDY׫RUBA_؎.XP2%sz.><^´4Pipp0F&daGXX }o m:M@`^{5a}^{B20 / baMT*j*+%NLL@=z kMCׅHf?W5*r` J`rBꂦ'‘L$)8Pkȣ! `WW.(xQollҺ0|ArNU Ѡ;`sեXb!g'yAcXxaMVʵ%~Z(dY\lw~m!M£7ƻry r t&;)pn{ A D lT?=-AP hBhuАv/euOj )0r}%wx53UŘ2#he ͉<>>;/}b(`a( k4Gap4c9_a]RGvV*jGγHi# ʼ[8?3ǹ{Hr/,:y 1O;ϨYhscKQP%  1ھN$s<\J$Kk4#R%fv%:]ƹNXk iڏo%;''ȓͪlV%&{ۚzrBR_B~'eJ_mmPyE3M!oCG$~ ;`[taC\Y&icO&4U2.6d($DsF 7;ٳ ` C|o«lf~k}Ns_^sk7C7ϋv}=w{{'o4*vN?F=CSkQ|u}Wy٭\]4Y^}Nx(F?Eҫ^;50fRHHHHN+dYJe[qIQnnffVZEE9y<`--+lk v"8Z >>6))zAA`ӕ8]^|L*Eu@!334f+3ƳbC @ MdREtl6n?777114D>G=Hpoo$SPtvvl^xT*j5=1n/—M=11q%ZKd- ~V?ݞaZ }x FD7T OQȗAttj(:h2WأZ:j4Hpǡ D,]m\f+u<"p!`=i&h NX_PeJ60~I #uCo޼f9lgz6oB0 sֳ0oWt}9ը/̗wGM*慇f^ì=u4;|#hA"x]+ob^V\<^Y}#k.^FG!WeGQ̋> 'Uэ4/<*<(α1/"/j1).XX@O`vaA "[<:sLd`m\x7?zn4ލPQ EE.} 1) K)&V( Bٝ'־$G$F;L_Dh pT@@V:jL%ǂLGFF}z2e<D!'|T:===??G(\^Aʅgp#3lv|.,jyYsK2s9*Q&]8рʅ"F~C ;)RlP2  @Ho`LY|Buug5]2ЮtZC 7`F`yvp3TjlpQwqx5k%_ї /y.󾘈ty\4"}s ܜ;y燹w(W k a65DKx_F_# 3N_ϼ;wzsOЗw/N5^hc|;<ƲVPvs9WIWʎ 5Cf yVN!ipL+h!Dc:9yms9n,"C>|͖yL%Ts3~1aȊm~a;lzT}m'/9ogmFQ~x;@Jѫ-S( 7U d˳<1'I'=ĆLeadf?K:\ݲss k Nc'fnApm! ~oaQXn͏PpxmNRfkё ?>Bx&ɋ|ٛbq%L%#gNT+$ZbllmFQoT HOoPaZcccvl| 礯A~98}Z st:q ZSzy˗5fT_tѩxA RtAY*0H借y廹wy/3ox%l.5_i}lt!|q,.%>g力7,?OXk"`Q$a,"̂EXY(0 EbfH,,XE"`'?ޤEk"^ZldsAgtv\}!y>".."\B]n7Ð=*0gEby l2(ZQjJF9&%àPɘJeT Tkj-= %I(!Wj`*U*RI?D3GB aT JsR$W2{R}H\Vi ba6Ɔ&i+֨4:٣'xAƞx`#O>ӿSi2>>4~$!TlC4ճdUaQ VG===n)aaQ4|?_Ub|/GGX25p6b4RkoBK0&]g{EwE?oI%yPdHMO";"[&Ǧ~,"-Stz뢢CwEE0QaWEQlSj=yÛf۵k``֭[+** aьF^O4\Z9K[uIkʠa7io쎼IsF.}~%s7}a9?i(][QVYQV__-]Ǝ?y+O+=vnܳ߳o_ʯ^o+[~_3+;oD?}C3_Wcg ~'+zw|Em |;vK?裏>>lmmX,El^՚EX }֯/sæ]xG+7]]?߹~ wkUjyi :aJ|:8吝x9l&ܦgMcACG{#'G&L{_|g;<⁍noKanjv#[?NlҫPP999 ??#cPPPeeeQQpwK@_ft'<#JxvI.YQoDj?\55'Eq;~ȜNVqmQA_&4J-atV~F,3_u%_K){j3hیQ2ch^ M7 32322q/o+ژ*HBnnnqqq^^dD"$2L\2ˉӶ VYїxd<쑡G~4G&NLO#C'Af62-%6>6"!. tCH' h)1IgbV\tRBLbh&ƑrXAp 8Iq 3}Z8.<?"f:EƝHJx6fm,Zx<'ƬÙa[7gW%SJNo;az覔 LEH;I$؇Pi~@wՕ)Jv%8)牢l?Q顛֗'M&կ"i_ƩE1;eŁFlCMYAA^hmʋ֐y"q8(ڪLއ깑RNl@>Xf=-0'ޒt.\_|&_ےu(;UQk^Uʡa?h: MuQ=LFn ; c0Ua9;OlJ<2 Y8G)'T=!.HVĎg}|ؽI!O}"6tD198EXv, U{p :<4ajVpRy<^ x{!*|{;e"֜r5#YBGk„9w˜Y Y$鳺Z2ޖϷbNrxw !b/2{IA1}&,U$w&HE$G1-1#~U*! u kejȴ: <\Kn"yIڌ]&Gl4 &j*钓)gIIIH9Ck cv)g 2Te'Ua۳#wO'@b*ðr զۛC3)K(O눬Drfe?҂ Ei#Є<B5nȂX.KNzmjjR3opK3L9cL[KlcQ|ԑuyѻSF=~߆}l0Gw}ِ.l p0;@X7`/DG3Q!>hkI}Zi¡k Q\{a]?D͉2 rBؑcJ ,"#K3"-xW!:cH)XPCtdԩ( 5qKX`&`kh U &-O0QHEe ǀ:N(͠O*QV'^@ D#KgEbsRo7@yX0/,)!aQ#<Κ4TGri+"G)0IuOWOMW̥hҤD(AVH٠FVG]_@AK{(p)&3M3%9ʁE:SkVƇ`,8i:̬>Ue%sޘ6j%cIץ-/QJХL蒅<)ߐ>K=;bNde)ΊYL_ٌ+N ;=?gi*ʊc33֬czb2$[:e2]ۮs 9Ne\'CJp*V,_]jF^L_V(ޚ7Od >f̛7gL|uQƨV+uZMD-6iw1}i@RlOq7Lů }o<6/K|mOp;> stream x} xTוgIfcڀI'mgI:ˤc;^}XbG $I @ @! v{i)jz}7{WUIts=sUM oɝ:rj=HZYoНYi/`cNX0p@7M{NnϴzǁmwЙnc]xܼ/`wCgO7 [v*uzMtjYlzELZ9\G".{#.h@hTRN%8!wލˬN.hH]z|d| FY,IK+,&eFT%礋d +I"T{/"41>_z7Ip796>?>h߾1("7(_I}ӟi˶˱ASB"R4`pZҿ忿Ws.b6x:xo?߼t4z-I5M83ԥ۷o7RSޞ՗ZQgUUio:n};TVOTo2M]gCoZSUHbA]A[,-=y%G([RKWc&q OKȋ7 P\^a$jK$tVTgd*ubYTv[VY9TgjTMLuTF`nQFh6(d[,4M&Lz\4&~1}fQ֮f\Z,ֶήD!]Vkf]$ X*tШd`0 fd54Z&dXKڰFh4*JVS,(J(r|^jIJ Rt:B.J|B I!/e2H$ R@%&b?a Pt }.-1:p$2L.S/U*#*K]ۨ7S/qlAQqlLLRRR}}}CCCmm]uuuddd```TT8>>>Ľfeeɔ>%hooZCCC---6pvpi#gfmv0)xQZ^Ք4Ϯ߻wZmرcջw^jU@@͛>|ݘ7|ݺuk׮ݴiӍ7m_YYyڵ/޺u`"VD10@DF{1 x?{A0z`ܹ+ɭ)z?EzDaqqjJJrr+W 411#ѣG 00á |0]\.WȂT*nv }ttBUUUiiiEE:2VݨC>., ^h[H(I793|DϚBV Ĩl2,tuuಣ&\kfȝonnJ`OOOD8??%LĻonֆd+d2PRR e v&@%\$H,UEaw}D֐ncI˲⋊ ҒuZ l{z)0 v|  |\d∆0kP3AؙGHI;֦&*%U'y:!66V `RѨ- QDSSS^zq8h0ˀt]gb( qhLXe@Grz1۲e 8矯Y|88Ο?#sppY E'cuPX+W $OҥK p%ggg!#F!Sƨ($0T{qqqGȺ%f8f8JJJ"D!TP 9T, k$xpϬ|iдI1! HwlQ\\p" M4)((ǡT!cą%.B!e9 bƌD&dEsT?)M+p˜t:,LA.O8#qQX"ɤ hX[bJQ0rSJfU,Lja8R&\ʈY*ÊJ2D2pQ VBVs\>,E*LYX'!Q]blډ!"k>)g4md2&tivv5 wSJ׫+12AR?BHaGqr9/;35#3]f*!tssPcs=ll:rM ~SKJAtc32?7^ob%[54ސy0(&CR+Tfֳ|{Xe]ːjmHr[rnet"6Yʥ;=m^[>ֱZA/R=o]N3DO0;n{HV'\6;xN՗Gvڷwѥˎ_‰K–\.~utu؞03'/ueYt>K<7/v^ߢE- ?/ц=uFBlKGZ4S^ /[}vS.j Ʉgo]zxqЃX(%w-|t3K_o] ,zţu?XڑE;ğ^zsMOtEgw.O/JdR̰JT$$7c??U,+A NPCۗ9F^^ry ï,=rh󢣞MI^g?c?iE57rb=bA|K lGzfgO$]{xK]6,{KKXyj?=~x듗}\]'=0?jپ/kz /тeβK/*p|ЫG;ϟ-e/ zDA~tgaOmpϻ,]TwG J3'9 6'W?}y_'z=CEiyIt}..|{{!8񫛞+?NLmyP*"I$$vv햋B45J(l(OC/_n5dltF^8~w=SWVp~B~^~Ge/~'Ŷƴ?HS[e ˀp%-y!ak)ڋս޲l/W0TU SZV9VЕ .qP2t`]Le/##cl)YbKy'ni%#?C'?Zu\nKN|Rh<"ۭ}7Žp֢GEas O8Ÿv=5p~3O?z~~'ͧCÞ1gUzm3Nrx^)/V4L%mZjD)J zbX)FXH@QJ! ղ"QUuTVQdP G+/+4RL4 JM%qFRdTdbH'-DX'-b²BVjDjaN\ REqyDPi(P +r2@/b&Uuy@[Ա _Son@l!O#SjRjksԵ<=/O[gu<]]3B.A1)Fj^D7.F=A%%@RP )ℎ+r0RE81TБKy®( FFF0A6b\ɟ("V1 2Q_V0| !ReJIJPGU:F@u'^rJL:F@fܺiBZ%\T.*yܚZLOAD`#j42T0^F&LZ5KOZyIh\IP*x<d%ppaa!f3IY,ɤg~&z9#*Ód^ZZZYY (y ! &% #+W*P# I( jzX% IIIϟcΝ;׮]w^DD۷ t߸q#>>>77799#J_;??[n9s]yyyeee \x1333<<} 3JGԭE\~=66644"H& $ʊNLLDYhjuҰLwlI*Rn޼9x#G;Çn:PC8pٳHG7ʕ+'OD:u*00ܹsOF8qʀQЁݻw=zt޽P-t%kDt.ųW,{yyJ(A̫l |28P9*$$BJ0LTqCaJ"KHHصk38;m RSS Qm why1RPh50p[q*"fK!wp25%Ů;lS@$:&! %ܹеpb2HKHGh&d t=CF]zQ~6t8.I,ɜ) )Q~h&%|W%|!n n-4P &şwMt Lx'WO˻/IU22|R)} Mxhm:xiWWCR K'x$ܹyא2q;7n erbHV i+ Dd r\dyN!Pક]E`Mċ!c+PSsdI|2[=om3#jT aXL& W k8l6&fd.9j@dsΈ`w.w@d'LC<HM(%,LԁBtFQ+={dI:FJ6Z@5!M0ApW<>ڸD/sd=d_Dy95iT $,@P걱5EBD}'h;*KTM@у2d#7D.'erH/blق&cN\*HPo?OJ@O8m۶ 6\}/pѧ11n|嗡9{7HEbw>غu;^ jꇛyUV%8 S.>a. D0ɷw8DO=IttYwM@5YՓPF ⷢ®!)c}d0Lh E,Y'24!IAHBAa<8.yrsdRC?QJ7 E"m*Ax;GrIRbMUK$IZWYdV9bWN51(>NLHf9JjHKWKٓw`͙?pbgyIM7jQ|De/`_T_qk`C;?Njm*8Ħmo$)R 2ZVUUq8YYӀ xhrWΟSʣj`vv1A>a%w5e*L48_iF[R5S$PR6 X.Q@@ @dc4q 513rR ƪ񢧲u@gVߍTXXD4m#)%4))q#znq8iiJ-]ѡgihvbgB t; ڔrhul̢qpt8u&a6.K(1dZgYP„fzv% al62՚;r0f캩COӆ.kTQ$ / ;:d߾7oz{Kv 'nE:?)9jxMW%yJe .3n] ߸q&4DJ5?}ǀrQ 6@1@%M6ygAT"yTc%>[rf@D\\ Xz =|dFߓ^lO6ED>spڱ}AG!vǖ-bغm5bC/9FaTNnn@ ͽx"ϯx La`V~S$pL;}hHk5Z;2L–1nr8VypHА|aq8Tm,dQOCئޢ$DIIINNN|||LLL~~>҉T yɫOHD$wJE@# @. x9ʾL%Whue$7V vJelر犊1YWTTTVV  gJE;wKzw҉ 0.nxHBQJRR2Y!wmUgyU}>co8H gpz{=]oQPmWMF殺jLAz[JEzC:HawlCвQͬ`y04̦uHb2ŷ<SZfz̠3tǍ=vlWq=IWܽ@qn,dg^Jmc9<:X2vpɮ3J| 0:豝!}߿U$g?3׬` e .fJ u" z;jLZg ::jPTPUbXsD<meK _(b(6uu1̆;o` "pBw`?=-18,Ǥ<8qD5RMkg h6~l adT:6UϒjiTJ$R(@VVFljkkgJ8jGT]1&&՞%w֤}[#N0uU`PSu:N(eRzS0{$e% bσQSFWQ:8@[B';4tN#s}+\2Z0&-v3p<&ͬ 8(Q-,5ˌ ,IBOa G7ԊE-{ gkk+9q@=^c`=4`l6L"gX_a1'\i`nд066QmmAR;896fhj2yQA(M+o54ιm2vvIlz09#j\v )iQJHZuдk&Ff5Jʞ^zFDk#IӍЍs"V7lر_SpȱN?ڻ%_xymqOпGzF 45vX}׿~mM)8Ïڻo38hјM;N(9i&8`55W&iQ #9xlH WĒ;KKKK32n&%Ć2n9ѥe霛i7**qέͨIs" хEw/]>᢯_s|ٷ**STP CЊ躺R.KؕX:a2$ȍ0*h]6 {7 d6EI+K MrPROӝ,_S@rMz}H$.,,p85 3 _%XC&WTrE!T"Jg)J$ eR3PR35Őxz3[U)mfCC=^D( 0)^ M$6$9M"%Rş ,%+!|֛wKXpZȗ'qٿ׹z)VVVN8vgf.cc&CAxe,6!g‡"I54$1MlPF{\ +*rZl]:R iA-gvó1Z*kR?v;hY`+C*kHXQ-d2555ÉFVء=oBG0>Cq;:豝O`+]299>&; >ZMu;xx\|rՁgݻrI#>mz5.C=v]!--mݺu\Z `77eeߊn݇n};UצcJUi)?x3pWO[V6x'N91UVB®=*YsrBB9J[]vyzٞͬi RЍn=^DQ+Z\VƘ8fvnv!A,&4YUoJeeeB1ΉQk7[-V”e2蔲3+e(}xq5 /VWWcdz(:njP\ ӆ|> ೗VPW+Ƀ`il5{ОZ-좺U]JiC.e_I;$( $|BQU;J̄IsQ(W RkqԜ%f 5ut ::Dmn!b:n; 5wv Y:gpd52em6HO CP 'g{{;qBoB v?;綇ZP/#5H {tNFdcotL{/>ljB)KnF 9 i|BXDeYAGyoɹ.M{țP)4",` v7=]P#G=Nwr狵fD5CJe7 ͟:ƏyO?{"9I:d6}W~̙HEӝsBn _qBJYYY;v ?J1*Anc_<>!L)+*Tގ9r˼ʪԡaF[i6ו''%f / <4>!L^\[!5fP%1ap:RSSWVVRsE%73cQkP)efbvh0N+3T^:=ɑ"1ZA~2P F,~$ U"W("("&EUA%8,h[@ UO!B\%J (3IPBPH]rS7 I&qfj-_?m`m1fktqtP6p6 a9lWvZ\y1PQ5UHCH P3DŽ^/z"I͑3n^:2RYZMak3N,яULJ]-a?r ۣY)h,zb[FGu^1>VK݄r,whEoqݻ > 7رp@xms}W~o/'z{V_=/E=%>ʎ:SxLX&$LKK[v-dRsgY nFC%Ν;v/唔Yc v*졻qpQcb/]={p䭠9m63m%;+++""(5wTb_?NDxOm`Jk!JN5$1l|b׷gz=O( MHH{.\y9VI Z w ^_K :':%5Cz&Ub`P jWf2 ʙ3ôHk4ZB~@Ԭ%y6ٕ=44vxT;%62;vvv6;ft[{6IgD]]X1Vhf~9&Xlߡ1Lmmm--C[[[Yxh6<Y *o${A*+_S15+QQuЋm+y1/AsmYYBgdApL&)+O Wnȳ.Vގ>Ͼ1o}c0ltL*1 Wr/3^}#G9IfdD;6څAf3SlnrhH=UµC[ (j$g)A>\N8002{9m ! 犋Ce[f'tBƿq-p?1Y߲'YOՀ UU )Zr&-(HsU* 􄢈ŒRv\O2Rq1BIRaEWsGsonx}h4%%ii 8`nnj^^Zn^:'#)'757'5++XP_NcsrRYɠHdA =#yJq,V"#֥U ¦:MfȨX%sedFGwt ZZ[M=ЎNX_}i/0+a{#CJr@``*p.訟߾>9wڏ֮h۷ܵvz\ig?۷i*?xOVv谇Cm6~MlX[VYdhKSӮ5xm81$]_UYXtW $\fddD(d/P7buanEEWV%F˨HιVYJh c RbcgeepJK3rr))ᔕgYQ]R)*.N̮ʎ+@PH%#\P\XqX RPw IqDL6 !NR D.eȼ')\zKU\(L;7UxJ)¨u(1*a`TB+Wd5E"d˵VuW,a&a`JJ,SהhJRmU[bP"R HS)djs|.u)t#&Rжm:l?}w?߱~acW_['_ђ1b%VUҩmowm}~1;>1?Vc? EguzB-IFΝ;W^qƍ7ozL"L%ڵۺ<2ڒyV-XɼMX?B?U/Vqb5kw}O>O{_}ڵֺοtp-SmK?N_<[4aW +Bl{t풸&?JWRK';;1&_tʕ+/^''''###??=P~x 5SJmkOo0 2vN:,tmҶW)V"WTT3?q P@~=P28G;0pJ'TR, ([%e,Jv~YpÜF \.S!AtJ>7sPcv{A nnp$p&[%0 *IV 7LJaLR +K7( ^5qhH$?1Er&/? +*n5pR`"xƿ%6"'0TUWUp+kj+UZUTpU\_ͭtE 8WJtneqEժǥ99{Ę3h$uSƌ9f^U!gD=Q j2[ʼn@)oԔ;e{>e:i\ٶzI8'4/_ZxU{YVw*ޜ *S1R)EN(SmQ-gL9DQ+EmaT"b˓Ņ ؑq`ڌ tS~3ni[^‘A^1}氆3pFt]Ϩ&%?n+v˓: ~ fcֈ>BlƬvib*mD0bZpFuȓntQbqP_ѐT^pᇹkܰԐ^E͐FUj,J,nv~| Ғ՜ A W_u~+xgiY1nkgv^=yL(I+SᰖÍsуvGŎT}m iRMՑ[u3ni\KCL ?zPdӥjS ܛэ={ݒ&ѝ>y<IӦqv`&i 2*rJRkjj5%+ȩ{1I8P.29/y#s>dg ߷> stream xz{|Tյ^1$d$`dDQ.g1`Q&3YFUbbT5 <O!\#8uQq0CIxG%+[~Op{"Jz$wq[;luh M|4w> hWXEA>U- I9W!'R>L*C?pǰ)º'zVts vU+8fK2[xVcm1!p1/‡8H$B%զ':┌:'x)v'_O*rHrEXy҈ 2 lKen:x0So'lDQOa'cEx")&g OYŔz;עndZ$RIM Wys2]r8r9i/I?STD«@ HEqA+]jqAֶVdOpɉd֞$x22gπ⢫KK22Ғ$>i:G nuSdc{h/|4Wwuv^jKA?rd`٭{wV.(./:{&S9uAIR133Sw-}>.XrPKvyή7s5Ja?FW!P7c]۵!gʾI?('^vQyϧՍuL:;gomuKj.Ǔ,Tf&щ8!8d,$ u>ha' :2+'>TdKĵᲊЀbf4m:;]/w?#;v[[_]'eS9R}[嘫LǛ 9DX3 |DLq A%`'J](vx5}`ߖom~Kر ϼm۹?Ϗnyx fa8OMU0QŸYk;°8+r2In4Ƒ8o#Η谚-&/t^@S&]wﱕdzf֘ a]b3<3I冢^yJ={}u= viW>.ɤR0-)LKbAu Ti.i.Y1j/d-MT˭It x9򈹱C:LoЩ^)HXUlĪw8x>[:a9!i, ¨b%zl1ǖ}emzlT ]fKͣc j~`sQƾ'HRHPY4YmR\L+UkI"Y$1YyoH{\tA \PVm"eL99W 5'~"<]{^L?l cXq# IWTְƏ m7&tuGf+.&hzEQTŠ PW+JL1_L5Az;mR׉G/#ʱބ:yJ'&ڧ4o"[unuq;1Ŝ\{WMlDřԠN`A_* Ɵqh] OolJoo;;.ȝwpzV"m({ФĒLH8$d8 - !tD\s ayMBRyg_۔xh@k#ˣ?dBn#ܭvf6gX4>Y|56Ǚ,x3 nς,',Y; H΂Y͂=Y0lUKMm`TwNXmOhp\$ƙh}7\r祺?ش!} ="=׮ý%2:α2˷ВĒm2˷XvuNXRK2Щe?{ 拸LY, N@iI艶$9^T0$a@^]\&扱_㌢z)5G'zl0pշ;W{o@xK]={g?ؑXJF)f@$Ģ ͟(;IJ7v%ùd&C %)y8ňZZd)Ŏ'k,={0k )\ѡ]z(w@O3F(!95ŚD]%zTؕ R! 18 gSl_[UR5ob: )Y|YlcxX(R\:uA'r&,E*wV[.z\ Epif5#D[nA):=I@2U{ 0˔3x!A{"BNscEyAIJ,<+p2(Ў^8{2*`}kk|`ML ˜מ:5ɓTmm|vS$"3d㧔+ej| 2|`\/xZ%׮O@&)&kτulO; 2wjO% ɩ΂IX˓A ^<(~_} uuY}_~^zpA4uP9:@梬:*Ҡē$N'M#BnN|"OOxSϪzPÝ*:y䙙xKK!3_(-VwɎg8QSh.Lwtѭvo7$ҶB?y@Ny xy#KU7<k*ԋzG_[a%+/,Zwgkkf9i62&$rI5() ON&_[ :#)H$ RK$GJKܰt@BH)H`'dY [qZFOhZĮZmԶ~5p٥NQ5ljS5>L=@m%1G!!k p䍜\| ܖKvơUMHo":?DHEmǎꊿavx_g9^}x7!}/ !UU78|NՒ]狷8~o%l4HD!pqhUV;>]vP;i,}/%Wc9lIOk5V qM/}X:7r\s{UQN²SM߿ӳ]w L#7{ޟ?g{=j7;9\dlŒ:.fslB8{ g=N̙x.ĉIt2ofߙ>u^RV¹mg K^X 7@XvÍ?:^@y^,Vr̢` Om>boC; !d#vkB;v30QOq Q&)a_Xi%X {~QTLz_|Ǐ?_q72mG]J5 ;e@3#R298#X@O%8bO V Z\{ 0&U=n8F#qfܾR)//wgLjn7fQ&w~z=Y8+c{ aRw9^S2Ƕ{Xx,DZzlw c?v?l#P|76m2$.'sWH7#.]4^M 5loG+ըkAz GL|k!a#1C^'CW 颺`uQPnbx)twqiqki"P2ZIzD6:'|Rw@,m@̓TңI"`khLF5؀5\j4=Фqdsjp)l&|9J[5 `YyR"di@4X$ӄ5XG2'煗5@ħ5Hkjpp\ F'uN 6㯫zDzntʝ_6YrQByQ07 / HO?ߴJ"I#=k1\ v.w;r|Mb/ iGQ~aa~% GL ~92 n]"#闛z$rĺ Dt6 ;{:(pBh1G"pF^(ق`[˝p~\Y|~\Kp#Er%Hȑn/nFp4֦H7}4?& u*xyᎁ@;kzz{"H?@ez:L9ϫ0 P^BDb {7 ? SCt{q2 oK x)v#85(;;qͨ`dž>j"pdB8@BR wG"96mkV@#5 hTz60E4.^*ׅP?5(!9+=u5KIfxG3U'cۏP LV7$ {]D ,e8ދeIbO?$$ -"4)j\ѩte҈~&ř @~)Ls6ׯ٥ŞaƷyOKm2Ә?f>0şZ~b\hiߓ,{I1oTf!L 1PL* YܯOLn~fрfvBKڪ!֓G7hh\YbRikGYldzDIX؊{Y6q*]bdB]L7kIԉ?1;<*s70Ţ(ÑҜ7 EE7UeJGM-R5 QBLSb`R>qaJNX3R%Bh@cʜ9 ͺb1ovfgkXua)vv$o/4ӿ@iڻݰn|%07}<7<#pf M߹Mqf6_,wv:ӵ~q|zx{Acpx ctק{?~]pn9,m;<쩳?~tܧl<,<ɝ`A̠_!)͏JVʴnr~'4p#E2OnJXn53i5Q2~6MF!8 Lnr!rPH_?t8 PO?}RVOƙk,r#|B*Û'>EȮq(8Pq`rf<z|q~h SԃTԟ< ςP^_}A{~&˽}m}w w [Żp˝glwoMpm5q#x+|·෡?B0:~N% ׺kܩܜRܬ/uh?mo+r{Z 5U+or%6h]o`+:>oŶFPrki' izS8_]O7 J^M{qM^j]RfkX2A_V%nKͲ"X,:K2l9e+ſt#0(k1'gɨ~aIT_* wDSY2#JWj͝;I%ѢƖhtߒh' NH/ G6h#E+@8LvMp8ؔpN'>I!"E_OB160&oO֢Cx={%/cz endstream endobj 195 0 obj 8998 endobj 196 0 obj <> endobj 197 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 198 0 obj <> endobj 199 0 obj <> stream xz{|Sey6IASnӖGJH66hhRl"XDpx Έ"B@q|::gq93 x=bӳV{N[o&DG: KXGC:B9B ysR`k-FfwKl}9!\+!m[[~]!/[s 1Rwۅ[Ԭ]ڢa{V{z!! Oe_`5h"yL$Dñ{v!"~KRj3,PmY9&:.q))Α+vJ.n![Xj]{VB~$92܎p/!SA;>Mm ;QQjBVZ%?B)7ZE^$}*F~@E3|GmgRA `CC&rV5M_kHD("#dKc?isDF̤ τOI*cHVUn`bd=A-];p^ސjhv"fƛW 46,_Z篽%57,WUhg͙=k\eSK&M,.*tۭ9F>j*c %MU"[$}AG#X=DVN-rD!(B +8$ze 70̕L8|C腕ut Ha6xlJV}[G.r, knmn4(L5/ŞVCҖZXtTRYDUE"d]uokrBPF l[uhtmZaQY%:%5K\3 N;O> eDEfKXwu+;ع!]:]W Mw=6wo@44œu1nU bȟe7`X08|) {zd6κt[ l&7D15H!ʰxs[S%rEC*عkA–2 W@"( HI@__@1K@5*GUՊ  t3]Eo%ޠnWJ0aJLs +Uo"H$MͲXVEǕPTvAk|+i7 Jټ1"ڛl!w-B-_0Gc8 FhrGʲƚzGMY#i+hKEjd4 B!X8HNR.+4 qd*\)IQJR9-ҦgQ-?0Hd(Z=Di jE%*;VAIQAc.j٨ֈ`aH>R0E62=ܬC^p㹛{Q-1*3XLx+BbVh .+\Ƒ,hrO_~t·޻?LH}ȸRS߽ R|#-*d+Ul͵,=g{ξK9\N (cNeRAem!BaJf VFⶖ]z]Z"nδArcUPB{v2+?tf<) m~ FQ ϧAz׫5h9b9yH 4W˫N_x |xL*-+g/lm;7faFwPzAet n vwRWi{jAO sY1Y-^_QQrJŽ#?rq4z4n lpmi lශ7-2DF$edZtVi"͊ r~|`qS^z3w ˰#̉[6Wzx`/[vdvmlu2>xA |NN^8)SF3бZdL/<- ,-,6Tn8y)Ӎn0JiL ~뫯=jߙw~΁radʔ/eY)+6ZoQ5.R'L&43WGa9tC_.\=/e:8G%EAHOYRiL≎LX>*Yح[;2+]~5Cʪ3+9>ڣ_vJu!W>TW){"ajV"( H}Ƞ5pI}5pXi ~ RPDW:48mb1(ǿ\}k>'+i^g2Ԫ,ո\[l.B_.p>s?Gr!;%8oyF;Q0l0oO/)M ݱʘhÁ;RϻCƵ)L!!\g /`V?g5Z@Ś %xN+%_}%T%touSw+70Z3'@z.R cʙ ,Կ_xba{7y;y?ؖtѾO硟ݹ׾n2?`ҍ޾'jJN)*wCP]H,δQMq31&?`2jS g<Űb`/b/b_:#_0aҳezτ?jQN+gyVCw 'Bܴ?xi }Vj{s&Rrʷh4vd4vUhs2sC4%y] M.Oa%G\2]p(^30qF#m-EDζ`pW̘ƒ5rJLa̺-<>Ͼv>qQs+OW}]թ{:skP 7HpՌǾEjʮ¯гCkҁd;hLH&_RksJ)`5KABNq N'؝wߜp :q'qmN::Jp$A')yV9 6'\ue*