package urpm; use strict; use vars qw($VERSION @ISA @EXPORT); $VERSION = '4.4'; @ISA = qw(Exporter URPM); @EXPORT = qw(N); use URPM; use URPM::Resolve; use POSIX; use Locale::gettext(); #- I18N. setlocale(LC_ALL, ""); Locale::gettext::textdomain("urpmi"); sub N { my ($format, @params) = @_; sprintf(Locale::gettext::gettext($format || ''), @params); } #- create a new urpm object. sub new { my ($class) = @_; bless { config => "/etc/urpmi/urpmi.cfg", skiplist => "/etc/urpmi/skip.list", instlist => "/etc/urpmi/inst.list", statedir => "/var/lib/urpmi", cachedir => "/var/cache/urpmi", media => undef, provides => {}, depslist => [], sync => \&sync_webfetch, #- first argument is directory, others are url to fetch. proxy => get_proxy(), options => {}, fatal => sub { printf STDERR "%s\n", $_[1]; exit($_[0]) }, error => sub { printf STDERR "%s\n", $_[0] }, log => sub { printf STDERR "%s\n", $_[0] }, }, $class; } sub get_proxy { my $proxy = { http_proxy => undef , ftp_proxy => undef , user => undef, pwd => undef }; local (*F, $_); open F, "/etc/urpmi/proxy.cfg" or return undef; while () { chomp; s/#.*$//; s/^\s*//; s/\s*$//; /^http_proxy\s*=\s*(.*)$/ and $proxy->{http_proxy} = $1, next; /^ftp_proxy\s*=\s*(.*)$/ and $proxy->{ftp_proxy} = $1, next; /^proxy_user\s*=\s*(.*):(.*)$/ and do { $proxy->{user} = $1; $proxy->{pwd} = $2; next; }; next; } close F; $proxy; } sub set_proxy { my $proxy = shift @_; my @res; if (defined $proxy->{proxy}{http_proxy} or defined $proxy->{proxy}{ftp_proxy}) { for ($proxy->{type}) { /wget/ && do { for ($proxy->{proxy}) { if (defined $_->{http_proxy}) { $ENV{http_proxy} = $_->{http_proxy} =~ /^http:/ ? $_->{http_proxy} : "http://$_->{http_proxy}"; } $ENV{ftp_proxy} = $_->{ftp_proxy} if defined $_->{ftp_proxy}; @res = ("--proxy-user=$_->{user}", "--proxy-passwd=$_->{pwd}") if defined $_->{user} && defined $_->{pwd}; } last; }; /curl/ && do { for ($proxy->{proxy}) { push @res, ('-x', $_->{http_proxy}) if defined $_->{http_proxy}; push @res, ('-x', $_->{ftp_proxy}) if defined $_->{ftp_proxy}; push @res, ('-U', "$_->{user}:$_->{pwd}") if defined $_->{user} && defined $_->{pwd}; } last; }; die N("Unknown webfetch `%s' !!!\n", $proxy->{type}); } } return @res; } #- quoting/unquoting a string that may be containing space chars. sub quotespace { local $_ = $_[0] || ''; s/(\s)/\\$1/g; $_ } sub unquotespace { local $_ = $_[0] || ''; s/\\(\s)/$1/g; $_ } #- syncing algorithms, currently is implemented wget and curl methods, #- webfetch is trying to find the best (and one which will work :-) sub sync_webfetch { my $options = shift @_; my %files; #- extract files according to protocol supported. #- currently ftp and http protocol are managed by curl or wget, #- ssh and rsync protocol are managed by rsync *AND* ssh. foreach (@_) { /^([^:_]*)[^:]*:/ or die N("unknown protocol defined for %s", $_); push @{$files{$1}}, $_; } if ($files{removable} || $files{file}) { sync_file($options, @{$files{removable} || []}, @{$files{file} || []}); delete @files{qw(removable file)}; } if ($files{ftp} || $files{http} || $files{https}) { if (-x "/usr/bin/curl" && (! ref($options) || $options->{prefer} ne 'wget' || ! -x "/usr/bin/wget")) { sync_curl($options, @{$files{ftp} || []}, @{$files{http} || []}, @{$files{https} || []}); } elsif (-x "/usr/bin/wget") { sync_wget($options, @{$files{ftp} || []}, @{$files{http} || []}, @{$files{https} || []}); } else { die N("no webfetch (curl or wget currently) found\n"); } delete @files{qw(ftp http https)}; } if ($files{rsync}) { sync_rsync($options, @{$files{rsync} || []}); delete $files{rsync}; } if ($files{ssh}) { my @ssh_files; foreach (@{$files{ssh} || []}) { /^ssh:\/\/([^\/]*)(.*)/ and push @ssh_files, "$1:$2"; } sync_ssh($options, @ssh_files); delete $files{ssh}; } %files and die N("unable to handle protocol: %s", join ', ', keys %files); } sub propagate_sync_callback { my $options = shift @_; if (ref($options) && $options->{callback}) { my $mode = shift @_; if ($mode =~ /^(start|progress|end)$/) { my $file = shift @_; $file =~ s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; #- if needed... $options->{callback}($mode, $file, @_); } else { $options->{callback}($mode, @_); } } } sub sync_file { my $options = shift @_; foreach (@_) { my ($in) = /^(?:removable[^:]*|file):\/(.*)/; propagate_sync_callback($options, 'start', $_); system("cp", "--preserve=mode", "--preserve=timestamps", "-R", $in || $_, ref($options) ? $options->{dir} : $options) and die N("copy failed: %s", $@); propagate_sync_callback($options, 'end', $_); } } sub sync_wget { -x "/usr/bin/wget" or die N("wget is missing\n"); local *WGET; my $options = shift @_; #- force download to be done in cachedir to avoid polluting cwd. my $cwd = `pwd`; chomp $cwd; chdir(ref($options) ? $options->{dir} : $options); my ($buf, $total, $file) = ('', undef, undef); open WGET, join(" ", map { "'$_'" } "/usr/bin/wget", (ref($options) && $options->{limit_rate} ? "--limit-rate=$options->{limit_rate}" : ()), (ref($options) && $options->{proxy} ? set_proxy({ type => "wget", proxy => $options->{proxy} }) : ()), (ref($options) && $options->{callback} ? ("--progress=bar:force", "-o", "-") : ref($options) && $options->{quiet} ? "-q" : @{[]}), "--retr-symlinks", "-NP", (ref($options) ? $options->{dir} : $options), @_) . " |"; local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). while () { $buf .= $_; if ($_ eq "\r" || $_ eq "\n") { if (ref($options) && $options->{callback}) { if ($buf =~ /^--\d\d:\d\d:\d\d--\s+(\S.*)\n/ms) { $file && $file ne $1 and propagate_sync_callback($options, 'end', $file); ! defined $file and propagate_sync_callback($options, 'start', $file = $1); } elsif (defined $file && ! defined $total && $buf =~ /==>\s+RETR/) { $total = ''; } elsif (defined $total && $total eq '' && $buf =~ /^[^:]*:\s+(\d\S*)/) { $total = $1; } elsif (my ($percent, $speed, $eta) = $buf =~ /^\s*(\d+)%.*\s+(\S+)\s+ETA\s+(\S+)\s*[\r\n]$/ms) { propagate_sync_callback($options, 'progress', $file, $percent, $total, $eta, $speed); if ($_ eq "\n") { propagate_sync_callback($options, 'end', $file); ($total, $file) = (undef, undef); } } } else { ref($options) && $options->{quiet} or print STDERR $buf; } $buf = ''; } } $file and propagate_sync_callback($options, 'end', $file); chdir $cwd; close WGET or die N("wget failed: exited with %d or signal %d\n", $? >> 8, $? & 127); } sub sync_curl { -x "/usr/bin/curl" or die N("curl is missing\n"); local *CURL; my $options = shift @_; #- force download to be done in cachedir to avoid polluting cwd, #- howerver for curl, this is mandatory. my $cwd = `pwd`; chomp $cwd; chdir(ref($options) ? $options->{dir} : $options); my (@ftp_files, @other_files); foreach (@_) { /^ftp:\/\/.*\/([^\/]*)$/ && -s $1 > 8192 and do { push @ftp_files, $_; next }; #- manage time stamp for large file only. push @other_files, $_; } if (@ftp_files) { my ($cur_ftp_file, %ftp_files_info); eval { require Date::Manip }; #- prepare to get back size and time stamp of each file. open CURL, join(" ", map { "'$_'" } "/usr/bin/curl", (ref($options) && $options->{limit_rate} ? ("--limit-rate", $options->{limit_rate}) : ()), (ref($options) && $options->{proxy} ? set_proxy({ type => "curl", proxy => $options->{proxy} }) : ()), "--stderr", "-", "-s", "-I", @ftp_files) . " |"; while () { if (/Content-Length:\s*(\d+)/) { !$cur_ftp_file || exists($ftp_files_info{$cur_ftp_file}{size}) and $cur_ftp_file = shift @ftp_files; $ftp_files_info{$cur_ftp_file}{size} = $1; } if (/Last-Modified:\s*(.*)/) { !$cur_ftp_file || exists($ftp_files_info{$cur_ftp_file}{time}) and $cur_ftp_file = shift @ftp_files; eval { $ftp_files_info{$cur_ftp_file}{time} = Date::Manip::ParseDate($1); $ftp_files_info{$cur_ftp_file}{time} =~ s/(\d{6}).{4}(.*)/$1$2/; #- remove day and hour. }; } } close CURL; #- now analyse size and time stamp according to what already exists here. if (@ftp_files) { #- re-insert back shifted element of ftp_files, because curl output above #- have not been parsed correctly, in doubt download them all. push @ftp_files, keys %ftp_files_info; } else { #- for that, it should be clear ftp_files is empty... else a above work is #- use less. foreach (keys %ftp_files_info) { my ($lfile) = /\/([^\/]*)$/ or next; #- strange if we can't parse it correctly. my $ltime = eval { Date::Manip::ParseDate(scalar gmtime((stat $1)[9])) }; $ltime =~ s/(\d{6}).{4}(.*)/$1$2/; #- remove day and hour. -s $lfile == $ftp_files_info{$_}{size} && $ftp_files_info{$_}{time} eq $ltime or push @ftp_files, $_; } } } #- http files (and other files) are correctly managed by curl to conditionnal download. #- options for ftp files, -R (-O )* #- options for http files, -R (-z file -O )* if (my @all_files = ((map { ("-O", $_) } @ftp_files), (map { /\/([^\/]*)$/ ? ("-z", $1, "-O", $_) : @{[]} } @other_files))) { my @l = (@ftp_files, @other_files); my ($buf, $file) = ('', undef); open CURL, join(" ", map { "'$_'" } "/usr/bin/curl", (ref($options) && $options->{limit_rate} ? ("--limit-rate", $options->{limit_rate}) : ()), (ref($options) && $options->{proxy} ? set_proxy({ type => "curl", proxy => $options->{proxy} }) : ()), (ref($options) && $options->{quiet} && !$options->{verbose} ? "-s" : @{[]}), "-k", `curl -h` =~ /location-trusted/ ? "--location-trusted" : @{[]}, "-R", "-f", "--stderr", "-", @all_files) . " |"; local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). while () { $buf .= $_; if ($_ eq "\r" || $_ eq "\n") { if (ref($options) && $options->{callback}) { unless (defined $file) { $file = shift @l; propagate_sync_callback($options, 'start', $file); } if (my ($percent, $total, $eta, $speed) = $buf =~ /^\s*(\d+)\s+(\S+)[^\r\n]*\s+(\S+)\s+(\S+)[\r\n]$/ms) { propagate_sync_callback($options, 'progress', $file, $percent, $total, $eta, $speed); if ($_ eq "\n") { propagate_sync_callback($options, 'end', $file); $file = undef; } } } else { ref($options) && $options->{quiet} or print STDERR $buf; } $buf = ''; } } chdir $cwd; close CURL or die N("curl failed: exited with %d or signal %d\n", $? >> 8, $? & 127); } else { chdir $cwd; } } sub sync_rsync { -x "/usr/bin/rsync" or die N("rsync is missing\n"); my $options = shift @_; #- force download to be done in cachedir to avoid polluting cwd. my $cwd = `pwd`; chomp $cwd; chdir(ref($options) ? $options->{dir} : $options); my $limit_rate = ref($options) && $options->{limit_rate}; for ($limit_rate) { /^(\d+)$/ and $limit_rate = int $1/1024; /^(\d+)[kK]$/ and $limit_rate = $1; /^(\d+)[mM]$/ and $limit_rate = 1024*$1; /^(\d+)[gG]$/ and $limit_rate = 1024*1024*$1; } foreach (@_) { my $count = 10; #- retry count on error (if file exists). my $basename = /^.*\/([^\/]*)$/ && $1 || $_; my ($file) = /^rsync:\/\/(.*)/ or next; $file =~ /::/ or $file = $_; propagate_sync_callback($options, 'start', $file); do { local (*RSYNC, $_); my $buf = ''; open RSYNC, join(" ", map { "'$_'" } "/usr/bin/rsync", ($limit_rate ? "--bwlimit=$limit_rate" : ()), (ref($options) && $options->{quiet} ? qw(-q) : qw(--progress -v)), (ref($options) && $options->{compress} ? qw(-z) : ()), qw(--partial --no-whole-file), $file, (ref($options) ? $options->{dir} : $options)) . " |"; local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). while () { $buf .= $_; if ($_ eq "\r" || $_ eq "\n") { if (ref($options) && $options->{callback}) { if (my ($percent, $speed) = $buf =~ /^\s*\d+\s+(\d+)%\s+(\S+)\s+/) { propagate_sync_callback($options, 'progress', $file, $percent, undef, undef, $speed); } } else { ref($options) && $options->{quiet} or print STDERR $buf; } $buf = ''; } } close RSYNC; } while ($? != 0 && --$count > 0 && -e (ref($options) ? $options->{dir} : $options) . "/$basename"); propagate_sync_callback($options, 'end', $file); } chdir $cwd; $? == 0 or die N("rsync failed: exited with %d or signal %d\n", $? >> 8, $? & 127); } sub sync_ssh { -x "/usr/bin/rsync" or die N("rsync is missing\n"); -x "/usr/bin/ssh" or die N("ssh is missing\n"); my $options = shift @_; #- force download to be done in cachedir to avoid polluting cwd. my $cwd = `pwd`; chomp $cwd; chdir(ref($options) ? $options->{dir} : $options); my $limit_rate = ref($options) && $options->{limit_rate}; for ($limit_rate) { /^(\d+)$/ and $limit_rate = int $1/1024; /^(\d+)[kK]$/ and $limit_rate = $1; /^(\d+)[mM]$/ and $limit_rate = 1024*$1; /^(\d+)[gG]$/ and $limit_rate = 1024*1024*$1; } foreach my $file (@_) { my $count = 10; #- retry count on error (if file exists). my $basename = $file =~ /^.*\/([^\/]*)$/ && $1 || $file; propagate_sync_callback($options, 'start', $file); do { local (*RSYNC, $_); my $buf = ''; open RSYNC, join(" ", map { "'$_'" } "/usr/bin/rsync", ($limit_rate ? "--bwlimit=$limit_rate" : ()), (ref($options) && $options->{quiet} ? qw(-q) : qw(--progress -v)), (ref($options) && $options->{compress} ? qw(-z) : ()), qw(--partial -e ssh), $file, (ref($options) ? $options->{dir} : $options)) . " |"; local $/ = \1; #- read input by only one char, this is slow but very nice (and it works!). while () { $buf .= $_; if ($_ eq "\r" || $_ eq "\n") { if (ref($options) && $options->{callback}) { if (my ($percent, $speed) = $buf =~ /^\s*\d+\s+(\d+)%\s+(\S+)\s+/) { propagate_sync_callback($options, 'progress', $file, $percent, undef, undef, $speed); } } else { ref($options) && $options->{quiet} or print STDERR $buf; } $buf = ''; } } close RSYNC; } while ($? != 0 && --$count > 0 && -e (ref($options) ? $options->{dir} : $options) . "/$basename"); propagate_sync_callback($options, 'end', $file); } chdir $cwd; $? == 0 or die N("rsync failed: exited with %d or signal %d\n", $? >> 8, $? & 127); } #- default logger suitable for sync operation on STDERR only. sub sync_logger { my ($mode, $file, $percent, $total, $eta, $speed) = @_; if ($mode eq 'start') { print STDERR " $file\n"; } elsif ($mode eq 'progress') { my $text; if (defined $total && defined $eta) { $text = N(" %s%% of %s completed, ETA = %s, speed = %s", $percent, $total, $eta, $speed); } else { $text = N(" %s%% completed, speed = %s", $percent, $speed); } print STDERR $text, " " x (79 - length($text)), "\r"; } elsif ($mode eq 'end') { print STDERR " " x 79, "\r"; } } #- read /etc/urpmi/urpmi.cfg as config file, keep compability with older #- configuration file by examining if one entry is of the form #- { #- ... #- } #- else only this form is used #- #- with sub read_config { my ($urpm, %options) = @_; #- keep in mind if it has been called before. $urpm->{media} and return; $urpm->{media} ||= []; #- check urpmi.cfg content, if the file is old keep track #- of old format used. local (*F, $_); open F, $urpm->{config}; #- no filename can be allowed on some case while () { chomp; s/#.*$//; s/^\s*//; s/\s*$//; $_ eq '{' and do { #- urpmi.cfg global options extension while () { chomp; s/#.*$//; s/^\s*//; s/\s*$//; $_ eq '}' and last; #- check for boolean variables first, and after that valued variables. my ($no, $k, $v); if (($no, $k, $v) = /^(no-)?(verify-rpm|fuzzy|allow-(?:force|nodeps)|(?:pre|post)-clean|excludedocs|compress)(?:\s*:\s*(.*))?$/) { unless (exists($urpm->{options}{$k})) { $urpm->{options}{$k} = $v eq '' || $v =~ /^(yes|on|1)$/i || 0; $no and $urpm->{options}{$k} = ! $urpm->{options}{$k} || 0; } next; } elsif (($k, $v) = /^(limit-rate|excludepath|key[\-_]ids|split-(?:level|length))\s*:\s*(.*)$/) { unless (exists($urpm->{options}{$k})) { $v =~ /^'([^']*)'$/ and $v = $1; $v =~ /^"([^"]*)"$/ and $v = $1; $urpm->{options}{$k} = $v; } next; } $_ and $urpm->{error}(N("syntax error in config file at line %s", $.)); } exists $urpm->{options}{key_ids} && ! exists $urpm->{options}{'key-ids'} and $urpm->{options}{'key-ids'} = delete $urpm->{options}{key_ids}; next }; /^(.*?[^\\])\s+(?:(.*?[^\\])\s+)?{$/ and do { #- urpmi.cfg format extention my $medium = { name => unquotespace($1), clear_url => unquotespace($2) }; while () { chomp; s/#.*$//; s/^\s*//; s/\s*$//; $_ eq '}' and last; /^(hdlist|list|with_hdlist|removable|md5sum|key[\-_]ids)\s*:\s*(.*)$/ and $medium->{$1} = $2, next; /^(update|ignore|synthesis|virtual)\s*$/ and $medium->{$1} = 1, next; /^modified\s*$/ and next; $_ and $urpm->{error}(N("syntax error in config file at line %s", $.)); } exists $medium->{key_ids} && ! exists $medium->{'key-ids'} and $medium->{'key-ids'} = delete $medium->{key_ids}; $urpm->probe_medium($medium, %options) and push @{$urpm->{media}}, $medium; next }; /^(.*?[^\\])\s+(.*?[^\\])\s+with\s+(.*)$/ and do { #- urpmi.cfg old format for ftp my $medium = { name => unquotespace($1), clear_url => unquotespace($2), with_hdlist => unquotespace($3) }; $urpm->probe_medium($medium, %options) and push @{$urpm->{media}}, $medium; next }; /^(.*?[^\\])\s+(?:(.*?[^\\])\s*)?$/ and do { #- urpmi.cfg old format (assume hdlist..cz2?) my $medium = { name => unquotespace($1), clear_url => unquotespace($2) }; $urpm->probe_medium($medium, %options) and push @{$urpm->{media}}, $medium; next }; $_ and $urpm->{error}(N("syntax error in config file at line %s", $.)); } close F; #- keep in mind when an hdlist/list file is used, really usefull for #- the next probe. my (%hdlists, %lists); foreach (@{$urpm->{media}}) { if ($_->{hdlist}) { exists($hdlists{$_->{hdlist}}) and $_->{ignore} = 1, $urpm->{error}(N("medium \"%s\" trying to use an already used hdlist, medium ignored", $_->{name})); $hdlists{$_->{hdlist}} = undef; } if ($_->{list}) { exists($lists{$_->{list}}) and $_->{ignore} = 1, $urpm->{error}(N("medium \"%s\" trying to use an already used list, medium ignored", $_->{name})); $lists{$_->{list}} = undef; } } #- urpmi.cfg if old is not enough to known the various media, track #- directly into /var/lib/urpmi, foreach (glob("$urpm->{statedir}/hdlist.*")) { if (/\/hdlist\.((.*)\.cz2?)$/) { #- check if it has already been detected above. exists($hdlists{"hdlist.$1"}) and next; #- if not this is a new media to take care if #- there is a list file. if (-s "$urpm->{statedir}/list.$2") { if (exists($lists{"list.$2"})) { $urpm->{error}(N("unable to take care of medium \"%s\" as list file is already used by another medium", $2)); } else { my $medium; foreach (@{$urpm->{media}}) { $_->{name} eq $2 and $medium = $_, last; } $medium and $urpm->{error}(N("unable to use name \"%s\" for unnamed medium because it is already used", $2)), next; $medium = { name => $2, hdlist => "hdlist.$1", list => "list.$2" }; $urpm->probe_medium($medium, %options) and push @{$urpm->{media}}, $medium; } } else { $urpm->{error}(N("unable to take medium \"%s\" into account as no list file [%s] exists", $2, "$urpm->{statedir}/list.$2")); } } else { $urpm->{error}(N("unable to determine medium of this hdlist file [%s]", $_)); } } #- check the presence of hdlist file and list file if necessary. unless ($options{nocheck_access}) { foreach (@{$urpm->{media}}) { $_->{ignore} and next; -r "$urpm->{statedir}/$_->{hdlist}" || -r "$urpm->{statedir}/synthesis.$_->{hdlist}" && $_->{synthesis} or $_->{ignore} = 1, $urpm->{error}(N("unable to access hdlist file of \"%s\", medium ignored", $_->{name})); $_->{list} && -r "$urpm->{statedir}/$_->{list}" || defined $_->{url} or $_->{ignore} = 1, $urpm->{error}(N("unable to access list file of \"%s\", medium ignored", $_->{name})); } } local *MD5SUM; open MD5SUM, "$urpm->{statedir}/MD5SUM"; while () { my ($md5sum, $file) = /(\S*)\s+(.*)/; foreach (@{$urpm->{media}}) { ($_->{synthesis} && "synthesis.").$_->{hdlist} eq $file and $_->{md5sum} = $md5sum, last; } } close MD5SUM; } #- probe medium to be used, take old medium into account too. sub probe_medium { my ($urpm, $medium, %options) = @_; local $_; my $existing_medium; foreach (@{$urpm->{media}}) { $_->{name} eq $medium->{name} and $existing_medium = $_, last; } $existing_medium and $urpm->{error}(N("trying to bypass existing medium \"%s\", avoiding", $medium->{name})), return; $medium->{url} ||= $medium->{clear_url}; if ($medium->{virtual}) { #- a virtual medium need to have an url available without using a list file. if ($medium->{hdlist} || $medium->{list}) { $medium->{ignore} = 1; $urpm->{error}(N("virtual medium \"%s\" should not have defined hdlist or list file, medium ignored", $medium->{name})); } unless ($medium->{url}) { $medium->{ignore} = 1; $urpm->{error}(N("virtual medium \"%s\" should have a clear url, medium ignored", $medium->{name})); } } else { unless ($medium->{ignore} || $medium->{hdlist}) { $medium->{hdlist} = "hdlist.$medium->{name}.cz"; -e "$urpm->{statedir}/$medium->{hdlist}" or $medium->{hdlist} = "hdlist.$medium->{name}.cz2"; -e "$urpm->{statedir}/$medium->{hdlist}" or $medium->{ignore} = 1, $urpm->{error}(N("unable to find hdlist file for \"%s\", medium ignored", $medium->{name})); } unless ($medium->{ignore} || $medium->{list}) { unless (defined $medium->{url}) { $medium->{list} = "list.$medium->{name}"; unless (-e "$urpm->{statedir}/$medium->{list}") { $medium->{ignore} = 1, $urpm->{error}(N("unable to find list file for \"%s\", medium ignored", $medium->{name})); } } } #- there is a little more to do at this point as url is not known, inspect directly list file for it. unless ($medium->{url}) { my %probe; if (-r "$urpm->{statedir}/$medium->{list}") { local *L; open L, "$urpm->{statedir}/$medium->{list}"; while () { #- /./ is end of url marker in list file (typically generated by a #- find . -name "*.rpm" > list #- for exportable list file. /^(.*)\/\.\// and $probe{$1} = undef; /^(.*)\/[^\/]*$/ and $probe{$1} = undef; } close L; } foreach (sort { length($a) <=> length($b) } keys %probe) { if ($medium->{url}) { $medium->{url} eq substr($_, 0, length($medium->{url})) or $medium->{ignore} || $urpm->{error}(N("incoherent list file for \"%s\", medium ignored", $medium->{name})), $medium->{ignore} = 1, last; } else { $medium->{url} = $_; } } unless ($options{nocheck_access}) { $medium->{url} or $medium->{ignore} || $urpm->{error}(N("unable to inspect list file for \"%s\", medium ignored", $medium->{name})), $medium->{ignore} = 1; } } } #- probe removable device. $urpm->probe_removable_device($medium); #- clear URLs for trailing /es. $medium->{url} and $medium->{url} =~ s|(.*?)/*$|$1|; $medium->{clear_url} and $medium->{clear_url} =~ s|(.*?)/*$|$1|; $medium; } #- probe device associated with a removable device. sub probe_removable_device { my ($urpm, $medium) = @_; if ($medium->{url} && $medium->{url} =~ /^removable_?([^_:]*)(?:_[^:]*)?:/) { $medium->{removable} ||= $1 && "/dev/$1"; } else { delete $medium->{removable}; } #- try to find device to open/close for removable medium. if (exists($medium->{removable})) { if (my ($dir) = $medium->{url} =~ /(?:file|removable)[^:]*:\/(.*)/) { my %infos; my @mntpoints = $urpm->find_mntpoints($dir, \%infos); if (@mntpoints > 1) { #- return value is suitable for an hash. $urpm->{log}(N("too many mount points for removable medium \"%s\"", $medium->{name})); $urpm->{log}(N("taking removable device as \"%s\"", join ',', map { $infos{$_}{device} } @mntpoints)); } if (@mntpoints) { if ($medium->{removable} && $medium->{removable} ne $infos{$mntpoints[-1]}{device}) { $urpm->{log}(N("using different removable device [%s] for \"%s\"", $infos{$mntpoints[-1]}{device}, $medium->{name})); } $medium->{removable} = $infos{$mntpoints[-1]}{device}; } else { $urpm->{error}(N("unable to retrieve pathname for removable medium \"%s\"", $medium->{name})); } } else { $urpm->{error}(N("unable to retrieve pathname for removable medium \"%s\"", $medium->{name})); } } } #- write back urpmi.cfg code to allow modification of medium listed. sub write_config { my ($urpm) = @_; #- avoid trashing exiting configuration in this case. $urpm->{media} or return; local (*F, *MD5SUM); open F, ">$urpm->{config}" or $urpm->{fatal}(6, N("unable to write config file [%s]", $urpm->{config})); open MD5SUM, ">$urpm->{statedir}/MD5SUM"; if (%{$urpm->{options} || {}}) { printf F "{\n"; while (my ($k, $v) = each %{$urpm->{options}}) { printf F " %s: %s\n", $k, $v; } printf F "}\n\n"; } foreach my $medium (@{$urpm->{media}}) { printf F "%s %s {\n", quotespace($medium->{name}), quotespace($medium->{clear_url}); foreach (qw(hdlist with_hdlist list removable key-ids)) { $medium->{$_} and printf F " %s: %s\n", $_, $medium->{$_}; } $medium->{md5sum} and print MD5SUM "$medium->{md5sum} ".($medium->{synthesis} && "synthesis.").$medium->{hdlist}."\n"; foreach (qw(update ignore synthesis modified virtual)) { $medium->{$_} and printf F " %s\n", $_; } printf F "}\n\n"; } close MD5SUM; close F; $urpm->{log}(N("write config file [%s]", $urpm->{config})); #- everything should be synced now. delete $urpm->{modified}; } #- read urpmi.cfg file as well as synthesis file needed. sub configure { my ($urpm, %options) = @_; $urpm->clean; if ($options{parallel}) { my ($parallel_options, $parallel_handler); #- handle parallel configuration, examine all module available that #- will handle the parallel mode (configuration is /etc/urpmi/parallel.cfg). local ($_, *PARALLEL); open PARALLEL, "/etc/urpmi/parallel.cfg"; while () { chomp; s/#.*$//; s/^\s*//; s/\s*$//; /\s*([^:]*):(.*)/ or $urpm->{error}(N("unable to parse \"%s\" in file [%s]", $_, "/etc/urpmi/parallel.cfg")), next; $1 eq $options{parallel} and $parallel_options = ($parallel_options && "\n") . $2; } close PARALLEL; #- if a configuration options has been found, use it else fatal error. if ($parallel_options) { foreach my $dir (grep { -d $_ } map { "$_/urpm" } @INC) { local *DIR; opendir DIR, $dir; while ($_ = readdir DIR) { -f "$dir/$_" or next; $urpm->{log}->(N("examining parallel handler in file [%s]", "$dir/$_")); eval { require "$dir/$_"; $parallel_handler = $urpm->handle_parallel_options($parallel_options) }; $parallel_handler and last; } closedir DIR; $parallel_handler and last; } } if ($parallel_handler) { if ($parallel_handler->{nodes}) { $urpm->{log}->(N("found parallel handler for nodes: %s", join(', ', keys %{$parallel_handler->{nodes}}))); } if (!$options{media} && $parallel_handler->{media}) { $options{media} = $parallel_handler->{media}; $urpm->{log}->(N("using associated media for parallel mode: %s", $options{media})); } $urpm->{parallel_handler} = $parallel_handler; } else { $urpm->{fatal}(1, N("unable to use parallel option \"%s\"", $options{parallel})); } } else { #- parallel is exclusive against root options. $urpm->{root} = $options{root}; } if ($options{synthesis}) { if ($options{synthesis} ne 'none') { #- synthesis take precedence over media, update options. $options{media} || $options{excludemedia} || $options{sortmedia} || $options{update} || $options{parallel} and $urpm->{fatal}(1, N("--synthesis cannot be used with --media, --excludemedia, --sortmedia, --update or --parallel")); $urpm->parse_synthesis($options{synthesis}); #- synthesis disable the split of transaction (too risky and not usefull). $urpm->{options}{'split-length'} = 0; } } else { $urpm->read_config(%options); if ($options{media}) { delete $_->{modified} foreach @{$urpm->{media} || []}; $urpm->select_media(split ',', $options{media}); foreach (grep { !$_->{modified} } @{$urpm->{media} || []}) { #- this is only a local ignore that will not be saved. $_->{ignore} = 1; } } if ($options{excludemedia}) { delete $_->{modified} foreach @{$urpm->{media} || []}; $urpm->select_media(split ',', $options{excludemedia}); foreach (grep { $_->{modified} } @{$urpm->{media} || []}) { #- this is only a local ignore that will not be saved. $_->{ignore} = 1; } } if ($options{sortmedia}) { delete $_->{modified} foreach @{$urpm->{media} || []}; my @oldmedia = @{$urpm->{media} || []}; my @newmedia; foreach (split ',', $options{sortmedia}) { $urpm->select_media($_); push @newmedia, grep { $_->{modified} } @oldmedia; @oldmedia = grep { !$_->{modified} } @oldmedia; } #- anything not selected should be added as is after the selected one. $urpm->{media} = [ @newmedia, @oldmedia ]; #- clean remaining modified flag. delete $_->{modified} foreach @{$urpm->{media} || []}; } unless ($options{nodepslist}) { foreach (grep { !$_->{ignore} && (!$options{update} || $_->{update}) } @{$urpm->{media} || []}) { delete @{$_}{qw(start end)}; if ($_->{virtual}) { my $path = $_->{url} =~ /^file:\/*(\/[^\/].*[^\/])\/*$/ && $1; if ($path) { if ($_->{synthesis}) { $urpm->{log}(N("examining synthesis file [%s]", "$path/$_->{with_hdlist}")); eval { ($_->{start}, $_->{end}) = $urpm->parse_synthesis("$path/$_->{with_hdlist}", callback => $options{callback}) }; } else { $urpm->{log}(N("examining hdlist file [%s]", "$path/$_->{with_hdlist}")); eval { ($_->{start}, $_->{end}) = $urpm->parse_hdlist("$path/$_->{with_hdlist}", packing => 1, callback => $options{callback}) }; } } else { $urpm->{error}(N("virtual medium \"%s\" is not local, medium ignored", $_->{name})); $_->{ignore} = 1; } } else { if ($options{hdlist} && -s "$urpm->{statedir}/$_->{hdlist}" > 32) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{statedir}/$_->{hdlist}")); eval { ($_->{start}, $_->{end}) = $urpm->parse_hdlist("$urpm->{statedir}/$_->{hdlist}", packing => 1, callback => $options{callback}) }; } else { $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{statedir}/synthesis.$_->{hdlist}")); eval { ($_->{start}, $_->{end}) = $urpm->parse_synthesis("$urpm->{statedir}/synthesis.$_->{hdlist}", callback => $options{callback}) }; unless (defined $_->{start} && defined $_->{end}) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{statedir}/$_->{hdlist}")); eval { ($_->{start}, $_->{end}) = $urpm->parse_hdlist("$urpm->{statedir}/$_->{hdlist}", packing => 1, callback => $options{callback}) }; } } } unless ($_->{ignore}) { unless (defined $_->{start} && defined $_->{end}) { $urpm->{error}(N("problem reading hdlist or synthesis file of medium \"%s\"", $_->{name})); $_->{ignore} = 1; } } } } } #- determine package to withdraw (from skip.list file) only if something should be withdrawn. unless ($options{noskipping}) { $urpm->compute_flags($urpm->get_packages_list($urpm->{skiplist}, $options{skip}), skip => 1, callback => sub { my ($urpm, $pkg) = @_; $urpm->{log}(N("skipping package %s", scalar($pkg->fullname))); }); } unless ($options{noinstalling}) { $urpm->compute_flags($urpm->get_packages_list($urpm->{instlist}, $options{inst}), disable_obsolete => 1, callback => sub { my ($urpm, $pkg) = @_; $urpm->{log}(N("would install instead of upgrade package %s", scalar($pkg->fullname))); }); } if ($options{bug}) { #- and a dump of rpmdb itself as synthesis file. my $db = URPM::DB::open($options{root}); my $sig_handler = sub { undef $db; exit 3 }; local $SIG{INT} = $sig_handler; local $SIG{QUIT} = $sig_handler; local *RPMDB; $db or $urpm->{fatal}(9, N("unable to open rpmdb")); open RPMDB, "| " . ($ENV{LD_LOADER} || '') . " gzip -9 >'$options{bug}/rpmdb.cz'"; $db->traverse(sub { my ($p) = @_; #- this is not right but may be enough. my $files = join '@', grep { exists($urpm->{provides}{$_}) } $p->files; $p->pack_header; $p->build_info(fileno *RPMDB, $files); }); close RPMDB; } } #- add a new medium, sync the config file accordingly. sub add_medium { my ($urpm, $name, $url, $with_hdlist, %options) = @_; #- make sure configuration has been read. $urpm->{media} or $urpm->read_config(); #- if a medium with that name has already been found #- we have to exit now my ($medium); if (defined $options{index_name}) { my $i = $options{index_name}; do { ++$i; undef $medium; foreach (@{$urpm->{media}}) { $_->{name} eq $name.$i and $medium = $_; } } while $medium; $name .= $i; } else { foreach (@{$urpm->{media}}) { $_->{name} eq $name and $medium = $_; } } $medium and $urpm->{fatal}(5, N("medium \"%s\" already exists", $medium->{name})); #- clear URLs for trailing /es. $url =~ s|(.*?)/*$|$1|; #- creating the medium info. if ($options{virtual}) { $url =~ m|^file:/*(/[^/].*)/| or $urpm->{fatal}(1, N("virtual medium need to be local")); $medium = { name => $name, url => $url, update => $options{update}, virtual => 1, modified => 1, }; } else { $medium = { name => $name, url => $url, hdlist => "hdlist.$name.cz", list => "list.$name", update => $options{update}, modified => 1, }; #- check to see if the medium is using file protocol or removable medium. $url =~ /^(removable[^:]*|file):\/(.*)/ and $urpm->probe_removable_device($medium); } #- check if a password is visible, if not set clear_url. $url =~ m|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)| or $medium->{clear_url} = $url; #- all flags once everything has been computed. $with_hdlist and $medium->{with_hdlist} = $with_hdlist; #- create an entry in media list. push @{$urpm->{media}}, $medium; #- keep in mind the database has been modified and base files need to be updated. #- this will be done automatically by transfering modified flag from medium to global. $urpm->{log}(N("added medium %s", $name)); } #- add distribution media, according to url given. sub add_distrib_media { my ($urpm, $name, $url, %options) = @_; my ($hdlists_file); #- make sure configuration has been read. $urpm->{media} or $urpm->read_config(); #- try to copy/retrive Mandrake/basehdlists file. if (my ($dir) = $url =~ /^(?:removable[^:]*|file):\/(.*)/) { $hdlists_file = reduce_pathname("$dir/Mandrake/base/hdlists"); $urpm->try_mounting($hdlists_file) or $urpm->{error}(N("unable to access first installation medium")), return; if (-e $hdlists_file) { unlink "$urpm->{cachedir}/partial/hdlists"; $urpm->{log}(N("copying hdlists file...")); system("cp", "--preserve=mode", "--preserve=timestamps", "-R", $hdlists_file, "$urpm->{cachedir}/partial/hdlists") ? $urpm->{log}(N("...copying failed")) : $urpm->{log}(N("...copying done")); } else { $urpm->{error}(N("unable to access first installation medium (no Mandrake/base/hdlists file found)")), return; } } else { #- try to get the description if it has been found. unlink "$urpm->{cachedir}/partial/hdlists"; eval { $urpm->{log}(N("retrieving hdlists file...")); $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 1, limit_rate => $options{limit_rate}, compress => $options{compress}, proxy => $urpm->{proxy} }, reduce_pathname("$url/Mandrake/base/hdlists")); $urpm->{log}(N("...retrieving done")); }; $@ and $urpm->{log}(N("...retrieving failed: %s", $@)); if (-e "$urpm->{cachedir}/partial/hdlists") { $hdlists_file = "$urpm->{cachedir}/partial/hdlists"; } else { $urpm->{error}(N("unable to access first installation medium (no Mandrake/base/hdlists file found)")), return; } } #- cosmetic update of name if it contains blank char. $name =~ /\s/ and $name .= ' '; #- at this point, we have found an hdlists file, so parse it #- and create all necessary medium according to it. local *HDLISTS; if (open HDLISTS, $hdlists_file) { my $medium = 1; foreach () { chomp; s/\s*#.*$//; /^\s*$/ and next; m/^\s*(?:noauto:)?(hdlist\S*\.cz2?)\s+(\S+)\s*(.*)$/ or $urpm->{error}(N("invalid hdlist description \"%s\" in hdlists file"), $_); my ($hdlist, $rpmsdir, $descr) = ($1, $2, $3); $urpm->add_medium($name ? "$descr ($name$medium)" : $descr, "$url/$rpmsdir", "../base/$hdlist", %options); ++$medium; } close HDLISTS; } else { $urpm->{error}(N("unable to access first installation medium (no Mandrake/base/hdlists file found)")), return; } } sub select_media { my $urpm = shift; my %media; @media{@_} = undef; foreach (@{$urpm->{media}}) { if (exists($media{$_->{name}})) { $media{$_->{name}} = 1; #- keep it mind this one has been selected. #- select medium by setting modified flags, do not check ignore. $_->{modified} = 1; } } #- check if some arguments does not correspond to medium name. #- in such case, try to find the unique medium (or list candidate #- media found). foreach (keys %media) { unless ($media{$_}) { my $q = quotemeta; my (@found, @foundi); foreach my $medium (@{$urpm->{media}}) { $medium->{name} =~ /$q/ and push @found, $medium; $medium->{name} =~ /$q/i and push @foundi, $medium; } if (@found == 1) { $found[0]{modified} = 1; } elsif (@foundi == 1) { $foundi[0]{modified} = 1; } elsif (@found == 0 && @foundi == 0) { $urpm->{error}(N("trying to select nonexistent medium \"%s\"", $_)); } else { #- multiple element in found or foundi list. $urpm->{log}(N("selecting multiple media: %s", join(", ", map { N("\"%s\"", $_->{name}) } (@found ? @found : @foundi)))); #- changed behaviour to select all occurence by default. foreach (@found ? @found : @foundi) { $_->{modified} = 1; } } } } } sub remove_selected_media { my ($urpm) = @_; my @result; foreach (@{$urpm->{media}}) { if ($_->{modified}) { $urpm->{log}(N("removing medium \"%s\"", $_->{name})); #- mark to re-write configuration. $urpm->{modified} = 1; #- remove file associated with this medium. foreach ($_->{hdlist}, $_->{list}, "synthesis.$_->{hdlist}", "descriptions.$_->{name}", "$_->{name}.cache") { $_ and unlink "$urpm->{statedir}/$_"; } } else { push @result, $_; #- not removed so keep it } } #- restore newer media list. $urpm->{media} = \@result; } #- return list of synthesis or hdlist reference to probe. sub probe_with_try_list { my ($suffix, $probe_with) = @_; my @probe = ("synthesis.hdlist.cz", "synthesis.hdlist$suffix.cz", "../synthesis.hdlist$suffix.cz", "../base/synthesis.hdlist$suffix.cz"); defined $suffix && !$suffix and push @probe, ("synthesis.hdlist1.cz", "synthesis.hdlist2.cz", "../synthesis.hdlist1.cz", "../synthesis.hdlist2.cz", "../base/synthesis.hdlist1.cz", "../base/synthesis.hdlist2.cz"); my @probe_hdlist = ("hdlist.cz", "hdlist$suffix.cz", "../hdlist$suffix.cz", "../base/hdlist$suffix.cz"); defined $suffix && !$suffix and push @probe_hdlist, ("hdlist1.cz", "hdlist2.cz", "../hdlist1.cz", "../hdlist2.cz", "../base/hdlist1.cz", "../base/hdlist2.cz"); if ($probe_with =~ /synthesis/) { push @probe, @probe_hdlist; } else { unshift @probe, @probe_hdlist; } @probe; } #- update urpmi database regarding the current configuration. #- take care of modification and try some trick to bypass #- computational of base files. #- allow options : #- all -> all medium are rebuilded. #- force -> try to force rebuilding base files (1) or hdlist from rpm files (2). #- probe_with -> probe synthesis or hdlist. #- ratio -> use compression ratio (with gzip, default is 4) #- noclean -> keep header directory cleaned. sub update_media { my ($urpm, %options) = @_; #- do not trust existing hdlist and try to recompute them. my ($cleaned_cache); #- take care of some options. $cleaned_cache = !$options{noclean}; #- avoid trashing existing configuration in this case. $urpm->{media} or return; #- now we need additional methods not defined by default in URPM. require URPM::Build; require URPM::Signature; #- get gpg-pubkey signature. $options{nopubkey} or $urpm->exlock_rpm_db; $options{nopubkey} or $urpm->{keys} or $urpm->parse_pubkeys(root => $urpm->{root}); #- lock database if allowed. $options{nolock} or $urpm->exlock_urpmi_db; #- examine each medium to see if one of them need to be updated. #- if this is the case and if not forced, try to use a pre-calculated #- hdlist file else build it from rpm files. $urpm->clean; foreach my $medium (@{$urpm->{media}}) { #- take care of modified medium only or all if all have to be recomputed. $medium->{ignore} and next; #- and create synthesis file associated if it does not already exists... -s "$urpm->{statedir}/synthesis.$medium->{hdlist}" > 32 or $medium->{modified_synthesis} = 1; #- but do not take care of removable media for all. $medium->{modified} ||= $options{all} && $medium->{url} !~ /removable/; unless ($medium->{modified}) { #- the medium is not modified, but for computing dependencies, #- we still need to read it and all synthesis will be written if #- a unresolved provides is found. #- to speed up the process, we only read the synthesis at the begining. delete @{$medium}{qw(start end)}; if ($medium->{virtual}) { my ($path) = $medium->{url} =~ /^file:\/*(\/[^\/].*[^\/])\/*$/; my $with_hdlist_file = "$path/$medium->{with_hdlist}"; if ($path) { if ($medium->{synthesis}) { $urpm->{log}(N("examining synthesis file [%s]", $with_hdlist_file)); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis($with_hdlist_file) }; } else { $urpm->{log}(N("examining hdlist file [%s]", $with_hdlist_file)); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist($with_hdlist_file, packing => 1) }; } } else { $urpm->{error}(N("virtual medium \"%s\" is not local, medium ignored", $medium->{name})); $_->{ignore} = 1; } } else { $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{statedir}/synthesis.$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{statedir}/synthesis.$medium->{hdlist}") }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{statedir}/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist("$urpm->{statedir}/$medium->{hdlist}", packing => 1) }; } } unless ($medium->{ignore}) { unless (defined $medium->{start} && defined $medium->{end}) { #- this is almost a fatal error, ignore it by default? $urpm->{error}(N("problem reading hdlist or synthesis file of medium \"%s\"", $medium->{name})); $medium->{ignore} = 1; } } next; } #- list of rpm files for this medium, only available for local medium where #- the source hdlist is not used (use force). my ($prefix, $dir, $error, $retrieved_md5sum, @files); #- always delete a remaining list file or pubkey file in cache. foreach (qw(list pubkey)) { unlink "$urpm->{cachedir}/partial/$_"; } #- check to see if the medium is using file protocol or removable medium. if (($prefix, $dir) = $medium->{url} =~ /^(removable[^:]*|file):\/(.*)/) { #- try to figure a possible hdlist_path (or parent directory of searched directory. #- this is used to probe possible hdlist file. my $with_hdlist_dir = reduce_pathname($dir . ($medium->{with_hdlist} ? "/$medium->{with_hdlist}" : "/..")); #- the directory given does not exist and may be accessible #- by mounting some other. try to figure out these directory and #- mount everything necessary. $urpm->try_mounting($options{force} < 2 && ($options{probe_with} || $medium->{with_hdlist}) ? $with_hdlist_dir : $dir) or $urpm->{error}(N("unable to access medium \"%s\", this could happen if you mounted manually the directory when creating the medium.", $medium->{name})), next; #- try to probe for possible with_hdlist parameter, unless #- it is already defined (and valid). if ($options{probe_with} && (!$medium->{with_hdlist} || ! -e "$dir/$medium->{with_hdlist}")) { my ($suffix) = $dir =~ /RPMS([^\/]*)\/*$/; foreach (probe_with_try_list($suffix, $options{probe_with})) { if (-s "$dir/$_" > 32) { $medium->{with_hdlist} = $_; last; } } #- redo... $with_hdlist_dir = reduce_pathname($dir . ($medium->{with_hdlist} ? "/$medium->{with_hdlist}" : "/..")); } if ($medium->{virtual}) { #- syncing a virtual medium is very simple, just try to read the file in order to #- determine its type, once a with_hdlist has been found (but is mandatory). if ($medium->{with_hdlist} && -e $with_hdlist_dir) { delete @{$medium}{qw(start end)}; if ($medium->{synthesis}) { $urpm->{log}(N("examining synthesis file [%s]", $with_hdlist_dir)); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis($with_hdlist_dir); delete $medium->{modified}; $medium->{synthesis} = 1; $urpm->{modified} = 1 }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{log}(N("examining hdlist file [%s]", $with_hdlist_dir)); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist($with_hdlist_dir, packing => 1); delete @{$medium}{qw(modified synthesis)}; $urpm->{modified} = 1 }; } } else { $urpm->{log}(N("examining hdlist file [%s]", $with_hdlist_dir)); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist($with_hdlist_dir, packing => 1); delete @{$medium}{qw(modified synthesis)}; $urpm->{modified} = 1 }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{log}(N("examining synthesis file [%s]", $with_hdlist_dir)); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis($with_hdlist_dir); delete $medium->{modified}; $medium->{synthesis} = 1; $urpm->{modified} = 1 }; } } unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{error}(N("problem reading hdlist or synthesis file of medium \"%s\"", $medium->{name})); $medium->{ignore} = 1; } } else { $urpm->{error}(N("virtual medium \"%s\" should have valid source hdlist or synthesis, medium ignored", $medium->{name})); $medium->{ignore} = 1; } next; } #- try to get the description if it has been found. unlink "$urpm->{statedir}/descriptions.$medium->{name}"; if (-e "$dir/../descriptions") { $urpm->{log}(N("copying description file of \"%s\"...", $medium->{name})); system("cp", "--preserve=mode", "--preserve=timestamps", "-R", "$dir/../descriptions", "$urpm->{statedir}/descriptions.$medium->{name}") ? $urpm->{log}(N("...copying failed")) : $urpm->{log}(N("...copying done")); } #- examine if a distant MD5SUM file is available. #- this will only be done if $with_hdlist is not empty in order to use #- an existing hdlist or synthesis file, and to check if download was good. #- if no MD5SUM are available, do it as before... if ($medium->{with_hdlist}) { #- we can assume at this point a basename is existing, but it needs #- to be checked for being valid, nothing can be deduced if no MD5SUM #- file are present. my ($basename) = $with_hdlist_dir =~ /\/([^\/]+)$/; if (!$options{nomd5sum} && -s reduce_pathname("$with_hdlist_dir/../MD5SUM") > 32) { if ($options{force}) { #- force downloading the file again, else why a force option has been defined ? delete $medium->{md5sum}; } else { unless ($medium->{md5sum}) { $urpm->{log}(N("computing md5sum of existing source hdlist (or synthesis)")); if ($medium->{synthesis}) { -e "$urpm->{statedir}/synthesis.$medium->{hdlist}" and $medium->{md5sum} = (split ' ', `md5sum '$urpm->{statedir}/synthesis.$medium->{hdlist}'`)[0]; } else { -e "$urpm->{statedir}/$medium->{hdlist}" and $medium->{md5sum} = (split ' ', `md5sum '$urpm->{statedir}/$medium->{hdlist}'`)[0]; } } } if ($medium->{md5sum}) { $urpm->{log}(N("examining MD5SUM file")); local (*F, $_); open F, reduce_pathname("$with_hdlist_dir/../MD5SUM"); while () { my ($md5sum, $file) = /(\S+)\s+(?:\.\/)?(\S+)/ or next; #- keep md5sum got here to check download was ok ! so even if md5sum is not defined, we need #- to compute it, keep it in mind ;) $file eq $basename and $retrieved_md5sum = $md5sum; } close F; #- if an existing hdlist or synthesis file has the same md5sum, we assume the #- file are the same. #- if local md5sum is the same as distant md5sum, this means there is no need to #- download hdlist or synthesis file again. foreach (@{$urpm->{media}}) { if ($_->{md5sum} && $_->{md5sum} eq $retrieved_md5sum) { unlink "$urpm->{cachedir}/partial/$basename"; #- the medium is now considered not modified. $medium->{modified} = 0; #- hdlist or synthesis file must be linked with the other same one. #- a link is better for reducing used size of /var/lib/urpmi. if ($_ ne $medium) { $medium->{md5sum} = $_->{md5sum}; unlink "$urpm->{statedir}/synthesis.$medium->{hdlist}"; unlink "$urpm->{statedir}/$medium->{hdlist}"; symlink "synthesis.$_->{hdlist}", "synthesis.$medium->{hdlist}"; symlink $_->{hdlist}, $medium->{hdlist}; } #- as previously done, just read synthesis file here, this is enough. $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{statedir}/synthesis.$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{statedir}/synthesis.$medium->{hdlist}") }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{statedir}/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist("$urpm->{statedir}/$medium->{hdlist}", packing => 1) }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{error}(N("problem reading hdlist or synthesis file of medium \"%s\"", $medium->{name})); $medium->{ignore} = 1; } } #- no need to continue examining other md5sum. last; } } $medium->{modified} or next; } } } #- if the source hdlist is present and we are not forcing using rpms file if ($options{force} < 2 && $medium->{with_hdlist} && -e $with_hdlist_dir) { unlink "$urpm->{cachedir}/partial/$medium->{hdlist}"; $urpm->{log}(N("copying source hdlist (or synthesis) of \"%s\"...", $medium->{name})); $options{callback} && $options{callback}('copy', $medium->{name}); if (system("cp", "--preserve=mode", "--preserve=timestamps", "-R", $with_hdlist_dir, "$urpm->{cachedir}/partial/$medium->{hdlist}")) { $options{callback} && $options{callback}('failed', $medium->{name}); $urpm->{log}(N("...copying failed")); unlink "$urpm->{cachedir}/partial/$medium->{hdlist}"; #- force error... } else { $options{callback} && $options{callback}('done', $medium->{name}); $urpm->{log}(N("...copying done")); } -s "$urpm->{cachedir}/partial/$medium->{hdlist}" > 32 or $error = 1, $urpm->{error}(N("copy of [%s] failed", $with_hdlist_dir)); #- keep checking md5sum of file just copied ! (especially on nfs or removable device). if (!$error && $retrieved_md5sum) { $urpm->{log}(N("computing md5sum of copied source hdlist (or synthesis)")); (split ' ', `md5sum '$urpm->{cachedir}/partial/$medium->{hdlist}'`)[0] eq $retrieved_md5sum or $error = 1, $urpm->{error}(N("copy of [%s] failed", $with_hdlist_dir)); } #- check if the file are equals... and no force copy... if (!$error && !$options{force} && -e "$urpm->{statedir}/synthesis.$medium->{hdlist}") { my @sstat = stat "$urpm->{cachedir}/partial/$medium->{hdlist}"; my @lstat = stat "$urpm->{statedir}/$medium->{hdlist}"; if ($sstat[7] == $lstat[7] && $sstat[9] == $lstat[9]) { #- the two files are considered equal here, the medium is so not modified. $medium->{modified} = 0; unlink "$urpm->{cachedir}/partial/$medium->{hdlist}"; #- as previously done, just read synthesis file here, this is enough, but only #- if synthesis exists, else it need to be recomputed. $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{statedir}/synthesis.$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{statedir}/synthesis.$medium->{hdlist}") }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{statedir}/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist("$urpm->{statedir}/$medium->{hdlist}", packing => 1) }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{error}(N("problem reading synthesis file of medium \"%s\"", $medium->{name})); $medium->{ignore} = 1; } } next; } } } else { $options{force} < 2 and $options{force} = 2; } #- if copying hdlist has failed, try to build it directly. if ($error) { $options{force} < 2 and $options{force} = 2; #- clean error state now. $error = undef; } if ($options{force} < 2) { #- examine if a local list file is available (always probed according to with_hdlist #- and check hdlist has not be named very strangely... if ($medium->{hdlist} ne 'list') { my $local_list = $medium->{with_hdlist} =~ /hd(list.*)\.cz2?$/ ? $1 : 'list'; my $path_list = reduce_pathname("$with_hdlist_dir/../$local_list"); -s $path_list or $path_list = "$dir/list"; -s $path_list and system("cp", "--preserve=mode", "--preserve=timestamps", "-R", $path_list, "$urpm->{cachedir}/partial/list"); } } else { #- try to find rpm files, use recursive method, added additional #- / after dir to make sure it will be taken into account if this #- is a symlink to a directory. #- make sure rpm filename format is correct and is not a source rpm #- which are not well managed by urpmi. @files = split "\n", `find '$dir/' -name "*.rpm" -print`; #- check files contains something good! if (@files > 0) { #- we need to rebuild from rpm files the hdlist. eval { $urpm->{log}(N("reading rpm files from [%s]", $dir)); my @unresolved_before = grep { ! defined $urpm->{provides}{$_} } keys %{$urpm->{provides} || {}}; $medium->{start} = @{$urpm->{depslist}}; $medium->{headers} = [ $urpm->parse_rpms_build_headers(dir => "$urpm->{cachedir}/headers", rpms => \@files, clean => $cleaned_cache, ) ]; $medium->{end} = $#{$urpm->{depslist}}; if ($medium->{start} > $medium->{end}) { #- an error occured (provided there are files in input. delete $medium->{start}; delete $medium->{end}; die "no rpms read\n"; } else { $cleaned_cache = 0; #- make sure the headers will not be removed for another media. my @unresolved_after = grep { ! defined $urpm->{provides}{$_} } keys %{$urpm->{provides} || {}}; @unresolved_before == @unresolved_after or $urpm->{second_pass} = 1; } }; $@ and $error = 1, $urpm->{error}(N("unable to read rpm files from [%s]: %s", $dir, $@)); $error and delete $medium->{headers}; #- do not propagate these. $error or delete $medium->{synthesis}; #- when building hdlist by ourself, drop synthesis property. } else { $error = 1; $urpm->{error}(N("no rpm files found from [%s]", $dir)); } } #- examine if a local pubkey file is available. if (!$options{nopubkey} && $medium->{hdlist} ne 'pubkey' && !$medium->{'key-ids'}) { my $local_pubkey = $medium->{with_hdlist} =~ /hdlist(.*)\.cz2?$/ ? "pubkey$1" : 'pubkey'; my $path_pubkey = reduce_pathname("$with_hdlist_dir/../$local_pubkey"); -s $path_pubkey or $path_pubkey = "$dir/pubkey"; -s $path_pubkey and system("cp", "--preserve=mode", "--preserve=timestamps", "-R", $path_pubkey, "$urpm->{cachedir}/partial/pubkey"); } } else { my $basename; #- try to get the description if it has been found. unlink "$urpm->{cachedir}/partial/descriptions"; if (-e "$urpm->{statedir}/descriptions.$medium->{name}") { rename("$urpm->{statedir}/descriptions.$medium->{name}", "$urpm->{cachedir}/partial/descriptions") or system("mv", "$urpm->{statedir}/descriptions.$medium->{name}", "$urpm->{cachedir}/partial/descriptions"); } eval { $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 1, limit_rate => $options{limit_rate}, compress => $options{compress}, proxy => $urpm->{proxy} }, reduce_pathname("$medium->{url}/../descriptions")); }; if (-e "$urpm->{cachedir}/partial/descriptions") { rename("$urpm->{cachedir}/partial/descriptions", "$urpm->{statedir}/descriptions.$medium->{name}") or system("mv", "$urpm->{cachedir}/partial/descriptions", "$urpm->{statedir}/descriptions.$medium->{name}"); } #- examine if a distant MD5SUM file is available. #- this will only be done if $with_hdlist is not empty in order to use #- an existing hdlist or synthesis file, and to check if download was good. #- if no MD5SUM are available, do it as before... if ($medium->{with_hdlist}) { #- we can assume at this point a basename is existing, but it needs #- to be checked for being valid, nothing can be deduced if no MD5SUM #- file are present. $basename = $medium->{with_hdlist} =~ /^.*\/([^\/]*)$/ && $1 || $medium->{with_hdlist}; unlink "$urpm->{cachedir}/partial/MD5SUM"; eval { if (!$options{nomd5sum}) { $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 1, limit_rate => $options{limit_rate}, compress => $options{compress}, proxy => $urpm->{proxy} }, reduce_pathname("$medium->{url}/$medium->{with_hdlist}/../MD5SUM")); } }; if (!$@ && -s "$urpm->{cachedir}/partial/MD5SUM" > 32) { if ($options{force} >= 2) { #- force downloading the file again, else why a force option has been defined ? delete $medium->{md5sum}; } else { unless ($medium->{md5sum}) { $urpm->{log}(N("computing md5sum of existing source hdlist (or synthesis)")); if ($medium->{synthesis}) { -e "$urpm->{statedir}/synthesis.$medium->{hdlist}" and $medium->{md5sum} = (split ' ', `md5sum '$urpm->{statedir}/synthesis.$medium->{hdlist}'`)[0]; } else { -e "$urpm->{statedir}/$medium->{hdlist}" and $medium->{md5sum} = (split ' ', `md5sum '$urpm->{statedir}/$medium->{hdlist}'`)[0]; } } } if ($medium->{md5sum}) { $urpm->{log}(N("examining MD5SUM file")); local (*F, $_); open F, "$urpm->{cachedir}/partial/MD5SUM"; while () { my ($md5sum, $file) = /(\S+)\s+(?:\.\/)?(\S+)/ or next; #- keep md5sum got here to check download was ok ! so even if md5sum is not defined, we need #- to compute it, keep it in mind ;) $file eq $basename and $retrieved_md5sum = $md5sum; } close F; #- if an existing hdlist or synthesis file has the same md5sum, we assume the #- file are the same. #- if local md5sum is the same as distant md5sum, this means there is no need to #- download hdlist or synthesis file again. foreach (@{$urpm->{media}}) { if ($_->{md5sum} && $_->{md5sum} eq $retrieved_md5sum) { unlink "$urpm->{cachedir}/partial/$basename"; #- the medium is now considered not modified. $medium->{modified} = 0; #- hdlist or synthesis file must be linked with the other same one. #- a link is better for reducing used size of /var/lib/urpmi. if ($_ ne $medium) { $medium->{md5sum} = $_->{md5sum}; unlink "$urpm->{statedir}/synthesis.$medium->{hdlist}"; unlink "$urpm->{statedir}/$medium->{hdlist}"; symlink "synthesis.$_->{hdlist}", "synthesis.$medium->{hdlist}"; symlink $_->{hdlist}, $medium->{hdlist}; } #- as previously done, just read synthesis file here, this is enough. $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{statedir}/synthesis.$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{statedir}/synthesis.$medium->{hdlist}") }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{statedir}/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist("$urpm->{statedir}/$medium->{hdlist}", packing => 1) }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{error}(N("problem reading synthesis file of medium \"%s\"", $medium->{name})); $medium->{ignore} = 1; } } #- no need to continue examining other md5sum. last; } } $medium->{modified} or next; } } else { #- at this point, we don't if a basename exists and is valid, let probe it later. $basename = undef; } } #- try to probe for possible with_hdlist parameter, unless #- it is already defined (and valid). $urpm->{log}(N("retrieving source hdlist (or synthesis) of \"%s\"...", $medium->{name})); $options{callback} && $options{callback}('retrieve', $medium->{name}); if ($options{probe_with}) { my ($suffix) = $dir =~ /RPMS([^\/]*)\/*$/; foreach my $with_hdlist ($medium->{with_hdlist}, probe_with_try_list($suffix, $options{probe_with})) { $basename = $with_hdlist =~ /^.*\/([^\/]*)$/ && $1 || $with_hdlist or next; $options{force} and unlink "$urpm->{cachedir}/partial/$basename"; eval { $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 0, limit_rate => $options{limit_rate}, compress => $options{compress}, callback => $options{callback}, proxy => $urpm->{proxy} }, reduce_pathname("$medium->{url}/$with_hdlist")); }; if (!$@ && -s "$urpm->{cachedir}/partial/$basename" > 32) { $medium->{with_hdlist} = $with_hdlist; $urpm->{log}(N("found probed hdlist (or synthesis) as %s", $medium->{with_hdlist})); last; #- found a suitable with_hdlist in the list above. } } } else { $basename = $medium->{with_hdlist} =~ /^.*\/([^\/]*)$/ && $1 || $medium->{with_hdlist}; #- try to sync (copy if needed) local copy after restored the previous one. $options{force} and unlink "$urpm->{cachedir}/partial/$basename"; unless ($options{force}) { if ($medium->{synthesis}) { -e "$urpm->{statedir}/synthesis.$medium->{hdlist}" and system("cp", "--preserve=mode", "--preserve=timestamps", "-R", "$urpm->{statedir}/synthesis.$medium->{hdlist}", "$urpm->{cachedir}/partial/$basename"); } else { -e "$urpm->{statedir}/$medium->{hdlist}" and system("cp", "--preserve=mode", "--preserve=timestamps", "-R", "$urpm->{statedir}/$medium->{hdlist}", "$urpm->{cachedir}/partial/$basename"); } } eval { $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 0, limit_rate => $options{limit_rate}, compress => $options{compress}, callback => $options{callback}, proxy => $urpm->{proxy} }, reduce_pathname("$medium->{url}/$medium->{with_hdlist}")); }; if ($@) { $urpm->{log}(N("...retrieving failed: %s", $@)); unlink "$urpm->{cachedir}/partial/$basename"; } } #- check downloaded file has right signature. if (-s "$urpm->{cachedir}/partial/$basename" > 32 && $retrieved_md5sum) { $urpm->{log}(N("computing md5sum of retrieved source hdlist (or synthesis)")); unless ((split ' ', `md5sum '$urpm->{cachedir}/partial/$basename'`)[0] eq $retrieved_md5sum) { $urpm->{log}(N("...retrieving failed: %s", N("md5sum mismatch"))); unlink "$urpm->{cachedir}/partial/$basename"; } } if (-s "$urpm->{cachedir}/partial/$basename" > 32) { $options{callback} && $options{callback}('done', $medium->{name}); $urpm->{log}(N("...retrieving done")); unless ($options{force}) { my @sstat = stat "$urpm->{cachedir}/partial/$basename"; my @lstat = stat "$urpm->{statedir}/$medium->{hdlist}"; if ($sstat[7] == $lstat[7] && $sstat[9] == $lstat[9]) { #- the two files are considered equal here, the medium is so not modified. $medium->{modified} = 0; unlink "$urpm->{cachedir}/partial/$basename"; #- as previously done, just read synthesis file here, this is enough. $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{statedir}/synthesis.$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{statedir}/synthesis.$medium->{hdlist}") }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{statedir}/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist("$urpm->{statedir}/$medium->{hdlist}", packing => 1) }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{error}(N("problem reading hdlist or synthesis file of medium \"%s\"", $medium->{name})); $medium->{ignore} = 1; } } next; } } #- the file are different, update local copy. rename("$urpm->{cachedir}/partial/$basename", "$urpm->{cachedir}/partial/$medium->{hdlist}"); #- retrieve of hdlist or synthesis has been successfull, check if a list file is available. #- and check hdlist has not be named very strangely... if ($medium->{hdlist} ne 'list') { my $local_list = $medium->{with_hdlist} =~ /hd(list.*)\.cz2?$/ ? $1 : 'list'; foreach (reduce_pathname("$medium->{url}/$medium->{with_hdlist}/../$local_list"), reduce_pathname("$medium->{url}/list"), ) { eval { $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 1, limit_rate => $options{limit_rate}, compress => $options{compress}, proxy => $urpm->{proxy} }, $_); $local_list ne 'list' && -s "$urpm->{cachedir}/partial/$local_list" and rename("$urpm->{cachedir}/partial/$local_list", "$urpm->{cachedir}/partial/list"); }; $@ and unlink "$urpm->{cachedir}/partial/list"; -s "$urpm->{cachedir}/partial/list" and last; } } #- retrieve pubkey file. if (!$options{nopubkey} && $medium->{hdlist} ne 'pubkey' && !$medium->{'key-ids'}) { my $local_pubkey = $medium->{with_hdlist} =~ /hdlist(.*)\.cz2?$/ ? "pubkey$1" : 'pubkey'; foreach (reduce_pathname("$medium->{url}/$medium->{with_hdlist}/../$local_pubkey"), reduce_pathname("$medium->{url}/pubkey"), ) { eval { $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 1, limit_rate => $options{limit_rate}, compress => $options{compress}, proxy => $urpm->{proxy} }, $_); $local_pubkey ne 'pubkey' && -s "$urpm->{cachedir}/partial/$local_pubkey" and rename("$urpm->{cachedir}/partial/$local_pubkey", "$urpm->{cachedir}/partial/pubkey"); }; $@ and unlink "$urpm->{cachedir}/partial/pubkey"; -s "$urpm->{cachedir}/partial/pubkey" and last; } } } else { $error = 1; $options{callback} && $options{callback}('failed', $medium->{name}); $urpm->{error}(N("retrieve of source hdlist (or synthesis) failed")); } } #- build list file according to hdlist used. unless ($medium->{headers} || -s "$urpm->{cachedir}/partial/$medium->{hdlist}" > 32) { $error = 1; $urpm->{error}(N("no hdlist file found for medium \"%s\"", $medium->{name})); } #- make sure group and other does not have any access to this file. unless ($error) { #- sort list file contents according to id. my %list; if ($medium->{headers}) { #- rpm files have already been read (first pass), there is just a need to #- build list hash. foreach (@files) { /\/([^\/]*\.rpm)$/ or next; $list{$1} and $urpm->{error}(N("file [%s] already used in the same medium \"%s\"", $1, $medium->{name})), next; $list{$1} = "$prefix:/$_\n"; } } else { #- read first pass hdlist or synthesis, try to open as synthesis, if file #- is larger than 1MB, this is probably an hdlist else a synthesis. #- anyway, if one tries fails, try another mode. $options{callback} && $options{callback}('parse', $medium->{name}); my @unresolved_before = grep { ! defined $urpm->{provides}{$_} } keys %{$urpm->{provides} || {}}; if (!$medium->{synthesis} || -s "$urpm->{cachedir}/partial/$medium->{hdlist}" > 262144) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{cachedir}/partial/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist("$urpm->{cachedir}/partial/$medium->{hdlist}", 1) }; if (defined $medium->{start} && defined $medium->{end}) { delete $medium->{synthesis}; } else { $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{cachedir}/partial/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{cachedir}/partial/$medium->{hdlist}") }; defined $medium->{start} && defined $medium->{end} and $medium->{synthesis} = 1; } } else { $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{cachedir}/partial/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{cachedir}/partial/$medium->{hdlist}") }; if (defined $medium->{start} && defined $medium->{end}) { $medium->{synthesis} = 1; } else { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{cachedir}/partial/$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist("$urpm->{cachedir}/partial/$medium->{hdlist}", 1) }; defined $medium->{start} && defined $medium->{end} and delete $medium->{synthesis}; } } unless (defined $medium->{start} && defined $medium->{end}) { $error = 1; $urpm->{error}(N("unable to parse hdlist file of \"%s\"", $medium->{name})); $options{callback} && $options{callback}('failed', $medium->{name}); #- we will have to read back the current synthesis file unmodified. } else { $options{callback} && $options{callback}('done', $medium->{name}); } unless ($error) { my @unresolved_after = grep { ! defined $urpm->{provides}{$_} } keys %{$urpm->{provides} || {}}; @unresolved_before == @unresolved_after or $urpm->{second_pass} = 1; if ($medium->{hdlist} ne 'list' && -s "$urpm->{cachedir}/partial/list") { local (*F, $_); open F, "$urpm->{cachedir}/partial/list"; while () { /\/([^\/]*\.rpm)$/ or next; $list{$1} and $urpm->{error}(N("file [%s] already used in the same medium \"%s\"", $1, $medium->{name})), next; $list{$1} = "$medium->{url}/$_"; } close F; } else { #- if url is clear and no relative list file has been downloaded, #- there is no need for a list file. if ($medium->{url} ne $medium->{clear_url}) { foreach ($medium->{start} .. $medium->{end}) { my $filename = $urpm->{depslist}[$_]->filename; $list{$filename} = "$medium->{url}/$filename\n"; } } } } } unless ($error) { if (%list) { #- write list file. local *LIST; my $mask = umask 077; open LIST, ">$urpm->{cachedir}/partial/$medium->{list}" or $error = 1, $urpm->{error}(N("unable to write list file of \"%s\"", $medium->{name})); umask $mask; print LIST values %list; close LIST; #- check if at least something has been written into list file. if (-s "$urpm->{cachedir}/partial/$medium->{list}") { $urpm->{log}(N("writing list file for medium \"%s\"", $medium->{name})); } else { $error = 1, $urpm->{error}(N("nothing written in list file for \"%s\"", $medium->{name})); } } else { #- the flag is no more necessary. delete $medium->{list}; unlink "$urpm->{statedir}/$medium->{list}"; } } } unless ($error) { #- now... on pubkey if (-s "$urpm->{cachedir}/partial/pubkey") { $urpm->{log}(N("examining pubkey file of \"%s\"...", $medium->{name})); my %key_ids; $urpm->import_needed_pubkeys([ $urpm->parse_armored_file("$urpm->{cachedir}/partial/pubkey") ], root => $urpm->{root}, callback => sub { my (undef, undef, $k, $id, $imported) = @_; if ($id) { $key_ids{$id} = undef; $imported and $urpm->{log}(N("...imported key %s from pubkey file of \"%s\"", $id, $medium->{name})); } else { $urpm->{error}(N("unable to import pubkey file of \"%s\"", $medium->{name})); } }); keys(%key_ids) and $medium->{'key-ids'} = join ',', keys %key_ids; } } if ($error) { #- an error has occured for updating the medium, we have to remove tempory files. unlink "$urpm->{cachedir}/partial/$medium->{hdlist}"; $medium->{list} and unlink "$urpm->{cachedir}/partial/$medium->{list}"; #- read default synthesis (we have to make sure nothing get out of depslist). $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{statedir}/synthesis.$medium->{hdlist}")); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{statedir}/synthesis.$medium->{hdlist}") }; unless (defined $medium->{start} && defined $medium->{end}) { $urpm->{error}(N("problem reading synthesis file of medium \"%s\"", $medium->{name})); $medium->{ignore} = 1; } } else { #- make sure to rebuild base files and clean medium modified state. $medium->{modified} = 0; $urpm->{modified} = 1; #- but use newly created file. unlink "$urpm->{statedir}/$medium->{hdlist}"; $medium->{synthesis} and unlink "$urpm->{statedir}/synthesis.$medium->{hdlist}"; $medium->{list} and unlink "$urpm->{statedir}/$medium->{list}"; unless ($medium->{headers}) { unlink "$urpm->{statedir}/synthesis.$medium->{hdlist}"; unlink "$urpm->{statedir}/$medium->{hdlist}"; rename("$urpm->{cachedir}/partial/$medium->{hdlist}", $medium->{synthesis} ? "$urpm->{statedir}/synthesis.$medium->{hdlist}" : "$urpm->{statedir}/$medium->{hdlist}") or system("mv", "$urpm->{cachedir}/partial/$medium->{hdlist}", $medium->{synthesis} ? "$urpm->{statedir}/synthesis.$medium->{hdlist}" : "$urpm->{statedir}/$medium->{hdlist}"); } if ($medium->{list}) { rename("$urpm->{cachedir}/partial/$medium->{list}", "$urpm->{statedir}/$medium->{list}") or system("mv", "$urpm->{cachedir}/partial/$medium->{list}", "$urpm->{statedir}/$medium->{list}"); } $medium->{md5sum} = $retrieved_md5sum; #- anyway, keep it, the previous one is no more usefull. #- and create synthesis file associated. $medium->{modified_synthesis} = !$medium->{synthesis}; } } #- some unresolved provides may force to rebuild all synthesis, #- a second pass will be necessary. if ($urpm->{second_pass}) { $urpm->{log}(N("performing second pass to compute dependencies\n")); $urpm->unresolved_provides_clean; } #- second pass consist of reading again synthesis or hdlist. foreach my $medium (@{$urpm->{media}}) { #- take care of modified medium only or all if all have to be recomputed. $medium->{ignore} and next; $options{callback} && $options{callback}('parse', $medium->{name}); #- a modified medium is an invalid medium, we have to read back the previous hdlist #- or synthesis which has not been modified by first pass above. if ($medium->{headers} && !$medium->{modified}) { if ($urpm->{second_pass}) { $urpm->{log}(N("reading headers from medium \"%s\"", $medium->{name})); ($medium->{start}, $medium->{end}) = $urpm->parse_headers(dir => "$urpm->{cachedir}/headers", headers => $medium->{headers}, ); } $urpm->{log}(N("building hdlist [%s]", "$urpm->{statedir}/$medium->{hdlist}")); #- finish building operation of hdlist. $urpm->build_hdlist(start => $medium->{start}, end => $medium->{end}, dir => "$urpm->{cachedir}/headers", hdlist => "$urpm->{statedir}/$medium->{hdlist}", ); #- synthesis need to be created for sure, since the medium has been built from rpm files. $urpm->build_synthesis(start => $medium->{start}, end => $medium->{end}, synthesis => "$urpm->{statedir}/synthesis.$medium->{hdlist}", ); $urpm->{log}(N("built hdlist synthesis file for medium \"%s\"", $medium->{name})); #- keep in mind we have modified database, sure at this point. $urpm->{modified} = 1; } elsif ($medium->{synthesis}) { if ($urpm->{second_pass}) { if ($medium->{virtual}) { my ($path) = $medium->{url} =~ /^file:\/*(\/[^\/].*[^\/])\/*$/; my $with_hdlist_file = "$path/$medium->{with_hdlist}"; if ($path) { $urpm->{log}(N("examining synthesis file [%s]", $with_hdlist_file)); eval { ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis($with_hdlist_file) }; } } else { $urpm->{log}(N("examining synthesis file [%s]", "$urpm->{statedir}/synthesis.$medium->{hdlist}")); ($medium->{start}, $medium->{end}) = $urpm->parse_synthesis("$urpm->{statedir}/synthesis.$medium->{hdlist}"); } } } else { if ($urpm->{second_pass}) { $urpm->{log}(N("examining hdlist file [%s]", "$urpm->{statedir}/$medium->{hdlist}")); ($medium->{start}, $medium->{end}) = $urpm->parse_hdlist("$urpm->{statedir}/$medium->{hdlist}", 1); } #- check if synthesis file can be built. if (($urpm->{second_pass} || $medium->{modified_synthesis}) && !$medium->{modified}) { unless ($medium->{virtual}) { $urpm->build_synthesis(start => $medium->{start}, end => $medium->{end}, synthesis => "$urpm->{statedir}/synthesis.$medium->{hdlist}", ); $urpm->{log}(N("built hdlist synthesis file for medium \"%s\"", $medium->{name})); } #- keep in mind we have modified database, sure at this point. $urpm->{modified} = 1; } } $options{callback} && $options{callback}('done', $medium->{name}); } #- clean headers cache directory to remove everything that is no more #- usefull according to depslist used. if ($urpm->{modified}) { if ($options{noclean}) { local (*D, $_); my %headers; opendir D, "$urpm->{cachedir}/headers"; while (defined($_ = readdir D)) { /^([^\/]*-[^-]*-[^-]*\.[^\.]*)(?::\S*)?$/ and $headers{$1} = $_; } closedir D; $urpm->{log}(N("found %d headers in cache", scalar(keys %headers))); foreach (@{$urpm->{depslist}}) { delete $headers{$_->fullname}; } $urpm->{log}(N("removing %d obsolete headers in cache", scalar(keys %headers))); foreach (values %headers) { unlink "$urpm->{cachedir}/headers/$_"; } } #- this file is written in any cases. $urpm->write_config(); } $options{nolock} or $urpm->unlock_urpmi_db; $options{nopubkey} or $urpm->unlock_rpm_db; } #- clean params and depslist computation zone. sub clean { my ($urpm) = @_; $urpm->{depslist} = []; $urpm->{provides} = {}; foreach (@{$urpm->{media} || []}) { delete $_->{start}; delete $_->{end}; } } #- check if supermount is used. sub is_using_supermount { my ($urpm, $device_mntpoint) = @_; local (*F, $_); #- read /etc/fstab and check for existing mount point. open F, "/etc/fstab"; while () { my ($device, $mntpoint, $fstype, $options) = /^\s*(\S+)\s+(\/\S+)\s+(\S+)\s+(\S+)/ or next; $mntpoint =~ s,/+,/,g; $mntpoint =~ s,/$,,; if ($fstype eq 'supermount') { $device_mntpoint eq $mntpoint and return 1; $options =~ /^(?:.*[\s,])?dev=([^\s,]+)/ && $device_mntpoint eq $1 and return 1; } } return 0; } #- find used mount point from a pathname, use a optional mode to allow #- filtering according the next operation (mount or umount). sub find_mntpoints { my ($urpm, $dir, $infos) = @_; my ($pdir, $v, %fstab, @mntpoints); local (*F, $_); #- read /etc/fstab and check for existing mount point. open F, "/etc/fstab"; while () { my ($device, $mntpoint, $fstype, $options) = /^\s*(\S+)\s+(\/\S+)\s+(\S+)\s+(\S+)/ or next; $mntpoint =~ s,/+,/,g; $mntpoint =~ s,/$,,; $fstab{$mntpoint} = 0; if (ref($infos)) { if ($fstype eq 'supermount') { $options =~ /^(?:.*[\s,])?dev=([^\s,]+)/ and $infos->{$mntpoint} = { mounted => 0, device => $1, fs => $fstype, supermount => 1, }; } else { $infos->{$mntpoint} = { mounted => 0, device => $device, fs => $fstype }; } } } open F, "/etc/mtab"; while () { my ($device, $mntpoint, $fstype, $options) = /^\s*(\S+)\s+(\/\S+)\s+(\S+)\s+(\S+)/ or next; $mntpoint =~ s,/+,/,g; $mntpoint =~ s,/$,,; $fstab{$mntpoint} = 1; if (ref($infos)) { if ($fstype eq 'supermount') { $options =~ /^(?:.*[\s,])?dev=([^\s,]+)/ and $infos->{$mntpoint} = { mounted => 1, device => $1, fs => $fstype, supermount => 1, }; } else { $infos->{$mntpoint} = { mounted => 1, device => $device, fs => $fstype }; } } } close F; #- try to follow symlink, too complex symlink graph may not be seen. #- check the possible mount point. my @paths = split '/', $dir; while (defined ($_ = shift @paths)) { length($_) or next; $pdir .= "/$_"; $pdir =~ s,/+,/,g; $pdir =~ s,/$,,; if (exists($fstab{$pdir})) { ref($infos) and push @mntpoints, $pdir; $infos eq 'mount' && ! $fstab{$pdir} and push @mntpoints, $pdir; $infos eq 'umount' && $fstab{$pdir} and unshift @mntpoints, $pdir; #- following symlinks may be dangerous for supermounted device and #- unusefull. #- this means it is assumed no symlink inside a removable device #- will go outside the device itself (or at least will go into #- regular already mounted device like /). #- for simplification we refuse also any other device and #- stop here. last; } elsif (-l $pdir) { while ($v = readlink $pdir) { if ($pdir =~ /^\//) { $pdir = $v; } else { while ($v =~ /^\.\.\/(.*)/) { $v = $1; $pdir =~ s/^(.*)\/[^\/]+\/*/$1/; } $pdir .= "/$v"; } } unshift @paths, split '/', $pdir; $pdir = ''; } } @mntpoints; } #- reduce pathname by removing /.. each time it appears (or . too). sub reduce_pathname { my ($url) = @_; #- clean url to remove any macro (which cannot be solved now). #- take care if this is a true url and not a simple pathname. my ($host, $dir) = $url =~ /([^:\/]*:\/\/[^\/]*\/)?(.*)/; #- remove any multiple /s or trailing /. #- then split all components of pathname. $dir =~ s/\/+/\//g; $dir =~ s/\/$//; my @paths = split '/', $dir; #- reset $dir, recompose it, and clean trailing / added by algorithm. $dir = ''; foreach (@paths) { if ($_ eq '..') { $dir =~ s/([^\/]+)\/$// or $dir .= "../"; } elsif ($_ ne '.') { $dir .= "$_/"; } } $dir =~ s/\/$//; $host . $dir; } #- check for necessity of mounting some directory to get access sub try_mounting { my ($urpm, $dir, $removable) = @_; my %infos; $dir = reduce_pathname($dir); foreach (grep { ! $infos{$_}{mounted} && $infos{$_}{fs} ne 'supermount' } $urpm->find_mntpoints($dir, \%infos)) { $urpm->{log}(N("mounting %s", $_)); `mount '$_' 2>/dev/null`; $removable && $infos{$_}{fs} ne 'supermount' and $urpm->{removable_mounted}{$_} = undef; } -e $dir; } sub try_umounting { my ($urpm, $dir) = @_; my %infos; $dir = reduce_pathname($dir); foreach (reverse grep { $infos{$_}{mounted} && $infos{$_}{fs} ne 'supermount' } $urpm->find_mntpoints($dir, \%infos)) { $urpm->{log}(N("unmounting %s", $_)); `umount '$_' 2>/dev/null`; delete $urpm->{removable_mounted}{$_}; } ! -e $dir; } sub try_umounting_removables { my ($urpm) = @_; foreach (keys %{$urpm->{removable_mounted}}) { $urpm->try_umounting($_); } delete $urpm->{removable_mounted}; } #- relocate depslist array id to use only the most recent packages, #- reorder info hashes to give only access to best packages. sub relocate_depslist_provides { my ($urpm, %options) = @_; my $relocated_entries = $urpm->relocate_depslist; $urpm->{log}($relocated_entries ? N("relocated %s entries in depslist", $relocated_entries) : N("no entries relocated in depslist")); $relocated_entries; } #- register local packages for being installed, keep track of source. sub register_rpms { my ($urpm, @files) = @_; my ($start, $id, $error, %requested); #- examine each rpm and build the depslist for them using current #- depslist and provides environment. $start = @{$urpm->{depslist}}; foreach (@files) { /\.rpm$/ or $error = 1, $urpm->{error}(N("invalid rpm file name [%s]", $_)), next; #- allow url to be given. if (my ($basename) = /^[^:]*:\/.*\/([^\/]*\.rpm)$/) { unlink "$urpm->{cachedir}/partial/$basename"; eval { $urpm->{log}(N("retrieving rpm file [%s] ...", $_)); $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 1, proxy => $urpm->{proxy} }, $_); $urpm->{log}(N("...retrieving done")); $_ = "$urpm->{cachedir}/partial/$basename"; }; $@ and $urpm->{log}(N("...retrieving failed: %s", $@)); } else { -r $_ or $error = 1, $urpm->{error}(N("unable to access rpm file [%s]", $_)), next; } ($id, undef) = $urpm->parse_rpm($_); my $pkg = defined $id && $urpm->{depslist}[$id]; $pkg or $urpm->{error}(N("unable to register rpm file")), next; $urpm->{source}{$id} = $_; } $error and $urpm->{fatal}(2, N("error registering local packages")); defined $id && $start <= $id and @requested{($start .. $id)} = (1) x ($id-$start+1); #- distribute local packages to distant nodes directly in cache of each machine. @files && $urpm->{parallel_handler} and $urpm->{parallel_handler}->parallel_register_rpms(@_); %requested; } #- search packages registered by their name by storing their id into packages hash. sub search_packages { my ($urpm, $packages, $names, %options) = @_; my (%exact, %exact_a, %exact_ra, %found, %foundi); foreach my $v (@$names) { my $qv = quotemeta $v; unless ($options{fuzzy}) { #- try to search through provides. if (my @l = map { $_ && ($options{src} ? $_->arch eq 'src' : $_->is_arch_compat) && ($options{use_provides} || $_->name eq $v) && defined $_->id ? ($_) : @{[]} } map { $urpm->{depslist}[$_] } keys %{$urpm->{provides}{$v} || {}}) { #- we assume that if the there is at least one package providing the resource exactly, #- this should be the best ones that is described. #- but we first check if one of the packages has the same name as searched. if (my @l2 = grep { $_->name eq $v} @l) { $exact{$v} = join '|', map { $_->id } @l2; } else { $exact{$v} = join '|', map { $_->id } @l; } next; } } if ($options{use_provides} && $options{fuzzy}) { foreach (keys %{$urpm->{provides}}) { #- search through provides to find if a provide match this one. #- but manages choices correctly (as a provides may be virtual or #- multiply defined. if (/$qv/) { my @list = grep { defined $_ } map { my $pkg = $urpm->{depslist}[$_]; $pkg && ($options{src} ? $pkg->arch eq 'src' : $pkg->arch ne 'src') ? $pkg->id : undef } keys %{$urpm->{provides}{$_} || {}}; @list > 0 and push @{$found{$v}}, join '|', @list; } if (/$qv/i) { my @list = grep { defined $_ } map { my $pkg = $urpm->{depslist}[$_]; $pkg && ($options{src} ? $pkg->arch eq 'src' : $pkg->arch ne 'src') ? $pkg->id : undef } keys %{$urpm->{provides}{$_} || {}}; @list > 0 and push @{$found{$v}}, join '|', @list; } } } foreach my $id (0 .. $#{$urpm->{depslist}}) { my $pkg = $urpm->{depslist}[$id]; ($options{src} ? $pkg->arch eq 'src' : $pkg->is_arch_compat) or next; my $pack_ra = $pkg->name . '-' . $pkg->version; my $pack_a = "$pack_ra-" . $pkg->release; my $pack = "$pack_a." . $pkg->arch; unless ($options{fuzzy}) { if ($pack eq $v) { $exact{$v} = $id; next; } elsif ($pack_a eq $v) { push @{$exact_a{$v}}, $id; next; } elsif ($pack_ra eq $v) { push @{$exact_ra{$v}}, $id; next; } } $pack =~ /$qv/ and push @{$found{$v}}, $id; $pack =~ /$qv/i and push @{$foundi{$v}}, $id; } } my $result = 1; foreach (@$names) { if (defined $exact{$_}) { $packages->{$exact{$_}} = 1; foreach (split '\|', $exact{$_}) { my $pkg = $urpm->{depslist}[$_] or next; $pkg->set_flag_skip(0); #- reset skip flag as manually selected. } } else { #- at this level, we need to search the best package given for a given name, #- always prefer already found package. my %l; foreach (@{$exact_a{$_} || $exact_ra{$_} || $found{$_} || $foundi{$_} || []}) { my $pkg = $urpm->{depslist}[$_]; push @{$l{$pkg->name}}, $pkg; } if (values(%l) == 0) { $urpm->{error}(N("no package named %s", $_)); $result = 0; } elsif (values(%l) > 1 && !$options{all}) { $urpm->{error}(N("The following packages contain %s: %s", $_, "\n".join("\n", sort { $a cmp $b } keys %l))); $result = 0; } else { foreach (values %l) { my $best; foreach (@$_) { if ($best && $best != $_) { $_->compare_pkg($best) > 0 and $best = $_; } else { $best = $_; } } $packages->{$best->id} = 1; $best->set_flag_skip(0); #- reset skip flag as manually selected. } } } } #- return true if no error have been encoutered, else false. $result; } #- do the resolution of dependencies. sub resolve_dependencies { my ($urpm, $state, $requested, %options) = @_; if ($options{install_src}) { #- only src will be installed, so only update $state->{selected} according #- to src status of files. foreach (%$requested) { my $pkg = $urpm->{depslist}[$_] or next; $pkg->arch eq 'src' or next; $state->{selected}{$_} = undef; } } if ($urpm->{parallel_handler}) { #- build the global synthesis file first. my $file = "$urpm->{cachedir}/partial/parallel.cz"; unlink $file; foreach (@{$urpm->{media}}) { defined $_->{start} && defined $_->{end} or next; system "cat '$urpm->{statedir}/synthesis.$_->{hdlist}' >> $file"; } #- let each node determine what is requested, according to handler given. $urpm->{parallel_handler}->parallel_resolve_dependencies($file, @_); } else { my $db; if ($options{rpmdb}) { $db = new URPM; $db->parse_synthesis($options{rpmdb}); } else { $db = URPM::DB::open($urpm->{root}); $db or $urpm->{fatal}(9, N("unable to open rpmdb")); } my $sig_handler = sub { undef $db; exit 3 }; local $SIG{INT} = $sig_handler; local $SIG{QUIT} = $sig_handler; #- auto select package for upgrading the distribution. $options{auto_select} and $urpm->request_packages_to_upgrade($db, $state, $requested, requested => undef); $urpm->resolve_requested($db, $state, $requested, %options); } } sub create_transaction { my ($urpm, $state, %options) = @_; if ($urpm->{parallel_handler} || !$options{split_length} || $options{nodeps} || keys %{$state->{selected}} < $options{split_level}) { #- build simplest transaction (no split). $urpm->build_transaction_set(undef, $state, split_length => 0); } else { my $db; if ($options{rpmdb}) { $db = new URPM; $db->parse_synthesis($options{rpmdb}); } else { $db = URPM::DB::open($urpm->{root}); $db or $urpm->{fatal}(9, N("unable to open rpmdb")); } my $sig_handler = sub { undef $db; exit 3 }; local $SIG{INT} = $sig_handler; local $SIG{QUIT} = $sig_handler; #- build transaction set... $urpm->build_transaction_set($db, $state, split_length => $options{split_length}); } } #- get list of package that should not be upgraded. sub get_packages_list { my ($urpm, $file, $extra) = @_; my %val; local ($_, *F); open F, $file; while () { chomp; s/#.*$//; s/^\s*//; s/\s*$//; if (my ($n, $s) = /^([^\s\[]+)(?:\[\*\])?\[?\s*([^\s\]]*\s*[^\s\]]*)/) { $val{$n}{$s} = undef; } } close F; #- additional skipping from given parameter. foreach (split ',', $extra) { if (my ($n, $s) = /^([^\s\[]+)(?:\[\*\])?\[?\s*([^\s\]]*\s*[^\s\]]*)/) { $val{$n}{$s} = undef; } } \%val; } #- for compability... sub get_unwanted_packages { my ($urpm, $skip) = @_; print STDERR "calling obsoleted method urpm::get_unwanted_packages\n"; get_packages_list($urpm->{skiplist}, $skip); } #- select source for package selected. #- according to keys given in the packages hash. #- return a list of list containing the source description for each rpm, #- match exactly the number of medium registered, ignored medium always #- have a null list. sub get_source_packages { my ($urpm, $packages, %options) = @_; my ($id, $error, %protected_files, %local_sources, @list, %fullname2id, %file2fullnames, %examined); local (*D, *F, $_); #- build association hash to retrieve id and examine all list files. foreach (keys %$packages) { my $p = $urpm->{depslist}[$_]; if ($urpm->{source}{$_}) { $protected_files{$local_sources{$_} = $urpm->{source}{$_}} = undef; } else { $fullname2id{$p->fullname} = $_.''; } } #- examine each medium to search for packages. #- now get rpm file name in hdlist to match list file. foreach my $pkg (@{$urpm->{depslist} || []}) { $file2fullnames{$pkg->filename}{$pkg->fullname} = undef; } #- examine the local repository, which is trusted (no gpg or pgp signature check but md5 is now done). opendir D, "$urpm->{cachedir}/rpms"; while (defined($_ = readdir D)) { if (my ($filename) = /^([^\/]*\.rpm)$/) { my $filepath = "$urpm->{cachedir}/rpms/$filename"; if (!$options{clean_all} && -s $filepath) { if (keys(%{$file2fullnames{$filename} || {}}) > 1) { $urpm->{error}(N("there are multiple packages with the same rpm filename \"%s\""), $filename); next; } elsif (keys(%{$file2fullnames{$filename} || {}}) == 1) { my ($fullname) = keys(%{$file2fullnames{$filename} || {}}); if (defined($id = delete $fullname2id{$fullname})) { $local_sources{$id} = $filepath; } else { $options{clean_other} && ! exists $protected_files{$filepath} and unlink $filepath; } } else { $options{clean_other} && ! exists $protected_files{$filepath} and unlink $filepath; } } else { #- this file should be removed or is already empty. unlink $filepath; } } #- no error on unknown filename located in cache (because .listing) inherited from old urpmi } closedir D; #- clean download directory, do it here even if this is not the best moment. if ($options{clean_all}) { system("rm", "-rf", "$urpm->{cachedir}/partial"); mkdir "$urpm->{cachedir}/partial"; } foreach my $medium (@{$urpm->{media} || []}) { my (%sources, %list_examined, $list_warning); if (defined $medium->{start} && defined $medium->{end} && !$medium->{ignore}) { #- always prefer a list file is available. if ($medium->{list} && -r "$urpm->{statedir}/$medium->{list}") { open F, "$urpm->{statedir}/$medium->{list}"; while () { if (my ($filename) = /\/([^\/]*\.rpm)$/) { if (keys(%{$file2fullnames{$filename} || {}}) > 1) { $urpm->{error}(N("there are multiple packages with the same rpm filename \"%s\""), $filename); next; } elsif (keys(%{$file2fullnames{$filename} || {}}) == 1) { my ($fullname) = keys(%{$file2fullnames{$filename} || {}}); defined($id = $fullname2id{$fullname}) and $sources{$id} = $_; $list_examined{$fullname} = $examined{$fullname} = undef; } } else { chomp; $error = 1; $urpm->{error}(N("unable to correctly parse [%s] on value \"%s\"", "$urpm->{statedir}/$medium->{list}", $_)); last; } } close F; } if (defined $medium->{url}) { foreach ($medium->{start} .. $medium->{end}) { my $pkg = $urpm->{depslist}[$_]; if (keys(%{$file2fullnames{$pkg->filename} || {}}) > 1) { $urpm->{error}(N("there are multiple packages with the same rpm filename \"%s\""), $pkg->filename); next; } elsif (keys(%{$file2fullnames{$pkg->filename} || {}}) == 1) { my ($fullname) = keys(%{$file2fullnames{$pkg->filename} || {}}); unless (exists($list_examined{$fullname})) { ++$list_warning; defined($id = $fullname2id{$fullname}) and $sources{$id} = "$medium->{url}/".$pkg->filename; $examined{$fullname} = undef; } } } $list_warning && $medium->{list} && -r "$urpm->{statedir}/$medium->{list}" and $urpm->{error}(N("medium \"%s\" uses an invalid list file: mirror is probably not up-to-date, trying to use alternate method", $medium->{name})); } elsif (!%list_examined) { $error = 1; $urpm->{error}(N("medium \"%s\" does not define any location for rpm files", $medium->{name})); } } push @list, \%sources; } #- examine package list to see if a package has not been found. foreach (grep { ! exists($examined{$_}) } keys %fullname2id) { $error = 1; $urpm->{error}(N("package %s is not found.", $_)); } $error ? @{[]} : (\%local_sources, \@list); } #- download package that may need to be downloaded. #- make sure header are available in the appropriate directory. #- change location to find the right package in the local #- filesystem for only one transaction. #- try to mount/eject removable media here. #- return a list of package ready for rpm. sub download_source_packages { my ($urpm, $local_sources, $list, %options) = @_; my %sources = %$local_sources; my %error_sources; print STDERR "calling obsoleted method urpm::download_source_packages\n"; $urpm->exlock_urpmi_db; $urpm->copy_packages_of_removable_media($list, \%sources, %options) or return; $urpm->download_packages_of_distant_media($list, \%sources, \%error_sources, %options); $urpm->unlock_urpmi_db; %sources, %error_sources; } #- safety rpm db locking mechanism sub exlock_rpm_db { my ($urpm) = @_; #- avoid putting a require on Fcntl ':flock' (which is perl and not perl-base). my ($LOCK_EX, $LOCK_NB) = (2, 4); #- lock urpmi database, but keep lock to wait for an urpmi.update to finish. open RPMLOCK_FILE, ">$urpm->{statedir}/.RPMLOCK"; flock RPMLOCK_FILE, $LOCK_EX|$LOCK_NB or $urpm->{fatal}(7, N("urpmi database locked")); } sub shlock_rpm_db { my ($urpm) = @_; #- avoid putting a require on Fcntl ':flock' (which is perl and not perl-base). my ($LOCK_SH, $LOCK_NB) = (1, 4); #- create the .LOCK file if needed (and if possible) unless (-e "$urpm->{statedir}/.RPMLOCK") { open RPMLOCK_FILE, ">$urpm->{statedir}/.RPMLOCK"; close RPMLOCK_FILE; } #- lock urpmi database, if the LOCK file doesn't exists no share lock. open RPMLOCK_FILE, "$urpm->{statedir}/.RPMLOCK" or return; flock RPMLOCK_FILE, $LOCK_SH|$LOCK_NB or $urpm->{fatal}(7, N("urpmi database locked")); } sub unlock_rpm_db { my ($urpm) = @_; #- avoid putting a require on Fcntl ':flock' (which is perl and not perl-base). my $LOCK_UN = 8; #- now everything is finished. system("sync"); #- release lock on database. flock RPMLOCK_FILE, $LOCK_UN; close RPMLOCK_FILE; } sub exlock_urpmi_db { my ($urpm) = @_; #- avoid putting a require on Fcntl ':flock' (which is perl and not perl-base). my ($LOCK_EX, $LOCK_NB) = (2, 4); #- lock urpmi database, but keep lock to wait for an urpmi.update to finish. open LOCK_FILE, ">$urpm->{statedir}/.LOCK"; flock LOCK_FILE, $LOCK_EX|$LOCK_NB or $urpm->{fatal}(7, N("urpmi database locked")); } sub shlock_urpmi_db { my ($urpm) = @_; #- avoid putting a require on Fcntl ':flock' (which is perl and not perl-base). my ($LOCK_SH, $LOCK_NB) = (1, 4); #- create the .LOCK file if needed (and if possible) unless (-e "$urpm->{statedir}/.LOCK") { open LOCK_FILE, ">$urpm->{statedir}/.LOCK"; close LOCK_FILE; } #- lock urpmi database, if the LOCK file doesn't exists no share lock. open LOCK_FILE, "$urpm->{statedir}/.LOCK" or return; flock LOCK_FILE, $LOCK_SH|$LOCK_NB or $urpm->{fatal}(7, N("urpmi database locked")); } sub unlock_urpmi_db { my ($urpm) = @_; #- avoid putting a require on Fcntl ':flock' (which is perl and not perl-base). my $LOCK_UN = 8; #- now everything is finished. system("sync"); #- release lock on database. flock LOCK_FILE, $LOCK_UN; close LOCK_FILE; } sub copy_packages_of_removable_media { my ($urpm, $list, $sources, %options) = @_; my %removables; #- make sure everything is correct on input... @{$urpm->{media} || []} == @$list or return; #- examine if given medium is already inside a removable device. my $check_notfound = sub { my ($id, $dir, $removable) = @_; $dir and $urpm->try_mounting($dir, $removable); if (!$dir || -e $dir) { foreach (values %{$list->[$id]}) { chomp; /^(removable_?[^_:]*|file):\/(.*\/([^\/]*))/ or next; unless ($dir) { $dir = $2; $urpm->try_mounting($dir, $removable); } -r $2 or return 1; } } else { return 2; } return 0; }; #- removable media have to be examined to keep mounted the one that has #- more package than other (size is better ?). my $examine_removable_medium = sub { my ($id, $device, $copy) = @_; my $medium = $urpm->{media}[$id]; if (my ($prefix, $dir) = $medium->{url} =~ /^(removable[^:]*|file):\/(.*)/) { #- the directory given does not exist or may be accessible #- by mounting some other. try to figure out these directory and #- mount everything necessary. while ($check_notfound->($id, $dir, 'removable')) { $options{ask_for_medium} or $urpm->{fatal}(4, N("medium \"%s\" is not selected", $medium->{name})); $urpm->try_umounting($dir); system("eject", $device); $options{ask_for_medium}($medium->{name}, $medium->{removable}) or $urpm->{fatal}(4, N("medium \"%s\" is not selected", $medium->{name})); } if (-e $dir) { while (my ($i, $url) = each %{$list->[$id]}) { print STDERR "copying or looking for $i:$url"; chomp $url; my ($filepath, $filename) = $url =~ /^(?:removable[^:]*|file):\/(.*\/([^\/]*))/ or next; if (-r $filepath) { if ($copy) { #- we should assume a possible buggy removable device... #- first copy in cache, and if the package is still good, transfert it #- to the great rpms cache. unlink "$urpm->{cachedir}/partial/$filename"; if (!system("cp", "--preserve=mode", "--preserve=timestamps", "-R", $filepath, "$urpm->{cachedir}/partial") && URPM::verify_rpm("$urpm->{cachedir}/partial/$filename", nosignatures => 1) !~ /NOT OK/) { #- now we can consider the file to be fine. unlink "$urpm->{cachedir}/rpms/$filename"; rename("$urpm->{cachedir}/partial/$filename", "$urpm->{cachedir}/rpms/$filename") or system("mv", "$urpm->{cachedir}/partial/$filename", "$urpm->{cachedir}/rpms/$filename"); -r "$urpm->{cachedir}/rpms/$filename" and $sources->{$i} = "$urpm->{cachedir}/rpms/$filename"; } } else { $sources->{$i} = $filepath; } } unless ($sources->{$i}) { #- fallback to use other method for retrieving the file later. $urpm->{error}(N("unable to read rpm file [%s] from medium \"%s\"", $filepath, $medium->{name})); } } } else { $urpm->{error}(N("medium \"%s\" is not selected", $medium->{name})); } } else { #- we have a removable device that is not removable, well... $urpm->{error}(N("incoherent medium \"%s\" marked removable but not really", $medium->{name})); } }; foreach (0..$#$list) { values %{$list->[$_]} or next; my $medium = $urpm->{media}[$_]; #- examine non removable device but that may be mounted. if ($medium->{removable}) { push @{$removables{$medium->{removable}} ||= []}, $_; } elsif (my ($prefix, $dir) = $medium->{url} =~ /^(removable[^:]*|file):\/(.*)/) { chomp $dir; -e $dir || $urpm->try_mounting($dir) or $urpm->{error}(N("unable to access medium \"%s\"", $medium->{name})), next; } } foreach my $device (keys %removables) { #- here we have only removable device. #- if more than one media use this device, we have to sort #- needed package to copy first the needed rpm files. if (@{$removables{$device}} > 1) { my @sorted_media = sort { values %{$list->[$a]} <=> values %{$list->[$b]} } @{$removables{$device}}; #- check if a removable device is already mounted (and files present). if (my ($already_mounted_medium) = grep { !$check_notfound->($_) } @sorted_media) { @sorted_media = grep { $_ ne $already_mounted_medium } @sorted_media; unshift @sorted_media, $already_mounted_medium; } #- mount all except the biggest one. foreach (@sorted_media[0 .. $#sorted_media-1]) { $examine_removable_medium->($_, $device, 'copy'); } #- now mount the last one... $removables{$device} = [ $sorted_media[-1] ]; } #- mount the removable device, only one or the important one. #- if supermount is used on the device, it is preferable to copy #- the file instead (because it is so slooooow). $examine_removable_medium->($removables{$device}[0], $device, $urpm->is_using_supermount($device) && 'copy'); } 1; } sub download_packages_of_distant_media { my ($urpm, $list, $sources, $error_sources, %options) = @_; #- get back all ftp and http accessible rpms file into the local cache #- if necessary (as used by checksig or any other reasons). foreach (0..$#$list) { my %distant_sources; #- ignore as well medium that contains nothing about the current set of files. values %{$list->[$_]} or next; #- examine all files to know what can be indexed on multiple media. while (my ($i, $url) = each %{$list->[$_]}) { #- it is trusted that the url given is acceptable, so the file can safely be ignored. defined $sources->{$i} and next; if ($url =~ /^(removable[^:]*|file):\/(.*\.rpm)$/) { if (-r $2) { $sources->{$i} = $2; } else { $error_sources->{$i} = $2; } } elsif ($url =~ /^([^:]*):\/(.*\/([^\/]*\.rpm))$/) { if ($options{force_local} || $1 ne 'ftp' && $1 ne 'http') { #- only ftp and http protocol supported by grpmi. $distant_sources{$i} = "$1:/$2"; } else { $sources->{$i} = "$1:/$2"; } } else { $urpm->{error}(N("malformed input: [%s]", $url)); } } #- download files from the current medium. if (%distant_sources) { eval { $urpm->{log}(N("retrieving rpm files from medium \"%s\"...", $urpm->{media}[$_]{name})); $urpm->{sync}({ dir => "$urpm->{cachedir}/partial", quiet => 0, verbose => $options{verbose}, limit_rate => $options{limit_rate}, compress => $options{compress}, callback => $options{callback}, proxy => $urpm->{proxy} }, values %distant_sources); $urpm->{log}(N("...retrieving done")); }; if ($@) { $urpm->{log}(N("...retrieving failed: %s", $@)); } #- clean files that have not been downloaded, but keep mind there #- has been problem downloading them at least once, this is #- necessary to keep track of failing download in order to #- present the error to the user. foreach my $i (keys %distant_sources) { my ($filename) = $distant_sources{$i} =~ /\/([^\/]*\.rpm)$/; if ($filename && -s "$urpm->{cachedir}/partial/$filename" && URPM::verify_rpm("$urpm->{cachedir}/partial/$filename", nosignatures => 1) !~ /NOT OK/) { #- it seems the the file has been downloaded correctly and has been checked to be valid. unlink "$urpm->{cachedir}/rpms/$filename"; rename("$urpm->{cachedir}/partial/$filename", "$urpm->{cachedir}/rpms/$filename") or system("mv", "$urpm->{cachedir}/partial/$filename", "$urpm->{cachedir}/rpms/$filename"); -r "$urpm->{cachedir}/rpms/$filename" and $sources->{$i} = "$urpm->{cachedir}/rpms/$filename"; } unless ($sources->{$i}) { $error_sources->{$i} = $distant_sources{$i}; } } } } #- clean failed download which have succeeded. delete @{$error_sources}{keys %$sources}; 1; } #- prepare transaction. sub prepare_transaction { my ($urpm, $set, $list, $sources, $transaction_list, $transaction_sources) = @_; foreach my $id (@{$set->{upgrade}}) { my $pkg = $urpm->{depslist}[$id]; foreach (0..$#$list) { exists $list->[$_]{$id} and $transaction_list->[$_]{$id} = $list->[$_]{$id}; } exists $sources->{$id} and $transaction_sources->{$id} = $sources->{$id}; } } #- extract package that should be installed instead of upgraded, #- sources is a hash of id -> source rpm filename. sub extract_packages_to_install { my ($urpm, $sources) = @_; my %inst; foreach (keys %$sources) { my $pkg = $urpm->{depslist}[$_] or next; $pkg->flag_disable_obsolete and $inst{$pkg->id} = delete $sources->{$pkg->id}; } \%inst; } #- install logger (ala rpm) sub install_logger { my ($urpm, $type, $id, $subtype, $amount, $total) = @_; my $pkg = defined $id && $urpm->{depslist}[$id]; my $progress_size = 50; if ($subtype eq 'start') { $urpm->{logger_progress} = 0; if ($type eq 'trans') { $urpm->{logger_id} ||= 0; printf "%-28s", N("Preparing..."); } else { printf "%4d:%-23s", ++$urpm->{logger_id}, ($pkg && $pkg->name); } } elsif ($subtype eq 'stop') { if ($urpm->{logger_progress} < $progress_size) { print '#' x ($progress_size - $urpm->{logger_progress}); print "\n"; } } elsif ($subtype eq 'progress') { my $new_progress = $total > 0 ? int($progress_size * $amount / $total) : $progress_size; if ($new_progress > $urpm->{logger_progress}) { print '#' x ($new_progress - $urpm->{logger_progress}); $urpm->{logger_progress} = $new_progress; $urpm->{logger_progress} == $progress_size and print "\n"; } } } #- install packages according to each hashes (install or upgrade). sub install { my ($urpm, $remove, $install, $upgrade, %options) = @_; #- allow process to be forked now. my $pid; local (*CHILD_RETURNS, *ERROR_OUTPUT, $_); if ($options{fork}) { pipe(CHILD_RETURNS, ERROR_OUTPUT); if ($pid = fork) { close ERROR_OUTPUT; $urpm->{log}(N("using process %d for executing transaction")); #- now get all errors from the child and return them directly. my @l; while () { chomp; if (/^\::logger_id:(\d+)/) { $urpm->{logger_id} = $1; } else { push @l, $_; } } close CHILD_RETURNS; waitpid($pid, 0); #- take care of return code from transaction, an error should be returned directly. $? >> 8 and exit $? >> 8; return @l; } else { close CHILD_RETURNS; } } #- beware this can be a child process or the main process now... my $db = URPM::DB::open($urpm->{root}, !$options{test}); #- open in read/write mode unless testing installation. $db or $urpm->{fatal}(9, N("unable to open rpmdb")); my $trans = $db->create_transaction($urpm->{root}); if ($trans) { $urpm->{log}(N("created transaction for installing on %s (remove=%d, install=%d, upgrade=%d)", $urpm->{root} || '/', scalar(@{$remove || []}), scalar(values %$install), scalar(values %$upgrade))); } else { return (N("unable to create transaction")); } my ($update, @l, %file2pkg) = 0; local *F; foreach (@$remove) { if ($trans->remove($_)) { $urpm->{log}(N("removing package %s", $_)); } else { $urpm->{error}(N("unable to remove package %s", $_)); } } foreach my $mode ($install, $upgrade) { foreach (keys %$mode) { my $pkg = $urpm->{depslist}[$_]; $file2pkg{$mode->{$_}} = $pkg; $pkg->update_header($mode->{$_}); if ($trans->add($pkg, update => $update, $options{excludepath} ? (excludepath => [ split ',', $options{excludepath} ]) : ())) { $urpm->{log}(N("adding package %s (id=%d, eid=%d, update=%d, file=%s)", scalar($pkg->fullname), $_, $pkg->id, $update, $mode->{$_})); } else { $urpm->{error}(N("unable to install package %s", $mode->{$_})); } } ++$update; } unless (!$options{nodeps} && (@l = $trans->check(%options)) || !$options{noorder} && (@l = $trans->order)) { #- assume default value for some parameter. $options{delta} ||= 1000; $options{callback_open} ||= sub { my ($data, $type, $id) = @_; open F, $install->{$id} || $upgrade->{$id} or $urpm->{error}(N("unable to access rpm file [%s]", $install->{$id} || $upgrade->{$id})); return fileno F; }; $options{callback_close} ||= sub { close F }; if (keys %$install || keys %$upgrade) { $options{callback_inst} ||= \&install_logger; $options{callback_trans} ||= \&install_logger; } @l = $trans->run($urpm, %options); #- in case of error or testing, do not try to check rpmdb #- for packages being upgraded or not. unless (@l || $options{test}) { #- examine the local repository to delete package which have been installed. if ($options{post_clean_cache}) { foreach (keys %$install, keys %$upgrade) { my $pkg = $urpm->{depslist}[$_]; $db->traverse_tag('name', [ $pkg->name ], sub { my ($p) = @_; $p->fullname eq $pkg->fullname or return; unlink "$urpm->{cachedir}/rpms/".$pkg->filename; }); } } } } #- now exit or return according to current status. if (defined $pid) { print ERROR_OUTPUT "::logger_id:$urpm->{logger_id}\n"; #- allow main urpmi to know transaction numbering... print ERROR_OUTPUT "$_\n" foreach @l; close ERROR_OUTPUT; #- keep safe exit now (with destructor call). exit 0; } else { return @l; } } #- install all files to node as remembered according to resolving done. sub parallel_install { my ($urpm, $remove, $install, $upgrade, %options) = @_; $urpm->{parallel_handler}->parallel_install(@_); } #- find packages to remove. sub find_packages_to_remove { my ($urpm, $state, $l, %options) = @_; if ($urpm->{parallel_handler}) { #- invoke parallel finder. $urpm->{parallel_handler}->parallel_find_remove($urpm, $state, $l, %options, find_packages_to_remove => 1); } else { my $db = URPM::DB::open($options{root}); my (@m, @notfound); $db or $urpm->{fatal}(9, N("unable to open rpmdb")); if (!$options{matches}) { foreach (@$l) { my ($n, $found); #- check if name-version-release may have been given. if (($n) = /^(.*)-[^\-]*-[^\-]*\.[^\.\-]*$/) { $db->traverse_tag('name', [ $n ], sub { my ($p) = @_; $p->fullname eq $_ or return; $urpm->resolve_rejected($db, $state, $p, removed => 1); push @m, scalar $p->fullname; $found = 1; }); $found and next; } #- check if name-version-release may have been given. if (($n) = /^(.*)-[^\-]*-[^\-]*$/) { $db->traverse_tag('name', [ $n ], sub { my ($p) = @_; join('-', ($p->fullname)[0..2]) eq $_ or return; $urpm->resolve_rejected($db, $state, $p, removed => 1); push @m, scalar $p->fullname; $found = 1; }); $found and next; } #- check if name-version may have been given. if (($n) = /^(.*)-[^\-]*$/) { $db->traverse_tag('name', [ $n ], sub { my ($p) = @_; join('-', ($p->fullname)[0..1]) eq $_ or return; $urpm->resolve_rejected($db, $state, $p, removed => 1); push @m, scalar $p->fullname; $found = 1; }); $found and next; } #- check if only name may have been given. $db->traverse_tag('name', [ $_ ], sub { my ($p) = @_; $p->name eq $_ or return; $urpm->resolve_rejected($db, $state, $p, removed => 1); push @m, scalar $p->fullname; $found = 1; }); $found and next; push @notfound, $_; } if (!$options{force} && @notfound && @$l > 1) { $options{callback_notfound} and $options{callback_notfound}->($urpm, @notfound) or return (); } } if ($options{matches} || @notfound) { my $match = join "|", map { quotemeta } @$l; #- reset what has been already found. %$state = (); @m = (); #- search for package that matches, and perform closure again. $db->traverse(sub { my ($p) = @_; $p->fullname =~ /$match/ or return; $urpm->resolve_rejected($db, $state, $p, removed => 1); push @m, scalar $p->fullname; }); if (!$options{force} && @notfound) { unless (@m) { $options{callback_notfound} and $options{callback_notfound}->($urpm, @notfound) or return (); } else { $options{callback_fuzzy} and $options{callback_fuzzy}->($urpm, $match, @m) or return (); } } } #- check if something need to be removed. if ($options{callback_base} && %{$state->{rejected} || {}}) { my %basepackages; #- check if a package to be removed is a part of basesystem requires. $db->traverse_tag('whatprovides', [ 'basesystem' ], sub { my ($p) = @_; $basepackages{$p->fullname} = 0; }); foreach (grep { $state->{rejected}{$_}{removed} && !$state->{rejected}{$_}{obsoleted} } keys %{$state->{rejected}}) { exists $basepackages{$_} or next; ++$basepackages{$_}; } grep { $_ } values %basepackages and $options{callback_base}->($urpm, grep { $basepackages{$_} } keys %basepackages) || return (); } } grep { $state->{rejected}{$_}{removed} && !$state->{rejected}{$_}{obsoleted} } keys %{$state->{rejected}}; } #- remove packages from node as remembered according to resolving done. sub parallel_remove { my ($urpm, $remove, %options) = @_; my $state = {}; my $callback = sub { $urpm->{fatal}(1, "internal distributed remove fatal error") }; $urpm->{parallel_handler}->parallel_find_remove($urpm, $state, $remove, %options, callback_notfound => undef, callback_fuzzy => $callback, callback_base => $callback, ); } #- misc functions to help finding ask_unselect and ask_remove elements with their reasons translated. sub unselected_packages { my ($urpm, $state) = @_; grep { $state->{rejected}{$_}{backtrack} } keys %{$state->{rejected} || {}}; } sub translate_why_unselected { my ($urpm, $state, @l) = @_; map { my $rb = $state->{rejected}{$_}{backtrack}; my @froms = keys %{$rb->{closure} || {}}; my @unsatisfied = @{$rb->{unsatisfied} || []}; my $s = join ", ", ((map { N("due to missing %s", $_) } @froms), (map { N("due to unsatisfied %s", $_) } @unsatisfied), $rb->{promote} && !$rb->{keep} ? N("trying to promote %s", join(", ", @{$rb->{promote}})) : @{[]}, $rb->{keep} ? N("in order to keep %s", join(", ", @{$rb->{keep}})) : @{[]}, ); $_ . ($s ? " ($s)" : ''); } @l; } sub removed_packages { my ($urpm, $state) = @_; grep { $state->{rejected}{$_}{removed} && !$state->{rejected}{$_}{obsoleted} } keys %{$state->{rejected} || {}}; } sub translate_why_removed { my ($urpm, $state, @l) = @_; map { my ($from) = keys %{$state->{rejected}{$_}{closure}}; my ($whyk) = keys %{$state->{rejected}{$_}{closure}{$from}}; my ($whyv) = $state->{rejected}{$_}{closure}{$from}{$whyk}; my $frompkg = $urpm->search($from, strict_fullname => 1); my $s; for ($whyk) { /old_requested/ and $s .= N("in order to install %s", $frompkg ? scalar $frompkg->fullname : $from); /unsatisfied/ and do { foreach (@$whyv) { $s and $s .= ', '; if (/([^\[\s]*)(?:\[\*\])?(?:\[|\s+)([^\]]*)\]?$/) { $s .= N("due to unsatisfied %s", "$1 $2"); } else { $s .= N("due to missing %s", $_); } } }; /conflicts/ and $s .= N("due to conflicts with %s", $whyv); /unrequested/ and $s .= N("unrequested"); } #- now insert the reason if available. $_ . ($s ? " ($s)" : ''); } @l; } sub check_sources_signatures { my ($urpm, $sources_install, $sources, %options) = @_; my ($medium, %invalid_sources); foreach my $id (sort { $a <=> $b } keys %$sources_install, keys %$sources) { my $verif = URPM::verify_rpm($sources_install->{$id} || $sources->{$id}); if ($verif =~ /NOT OK/) { $invalid_sources{$sources_install->{$id} || $sources->{$id}} = N("Invalid signature (%s)", $verif); } else { unless ($medium && $medium->{start} <= $id && $id <= $medium->{end}) { $medium = undef; foreach (@{$urpm->{media}}) { $_->{start} <= $id && $id <= $_->{end} and $medium = $_, last; } } my $key_ids = $medium && $medium->{'key-ids'} || $urpm->{options}{'key-ids'}; #- check the key ids of the medium are matching (all) the given key id of the package. if ($key_ids) { my $valid_ids = 0; my $invalid_ids = 0; foreach my $key_id ($verif =~ /#(\S+)/g) { if (grep { hex($_) == hex($key_id) } split /[,\s]+/, $key_ids) { ++$valid_ids; } else { ++$invalid_ids; } } if ($invalid_ids) { $invalid_sources{$sources_install->{$id} || $sources->{$id}} = N("Invalid Key ID (%s)", $verif); } elsif (!$valid_ids) { $invalid_sources{$sources_install->{$id} || $sources->{$id}} = N("Missing signature (%s)", $verif); } } } } map { $_ . ($options{translate} ? ": $invalid_sources{$_}" : "") } sort keys %invalid_sources; } 1; __END__ =head1 NAME urpm - Mandrake perl tools to handle urpmi database =head1 SYNOPSYS require urpm; my $urpm = new urpm; $urpm->read_config(); $urpm->add_medium('medium_ftp', 'ftp://ftp.mirror/pub/linux/distributions/mandrake-devel/cooker/i586/Mandrake/RPMS', 'synthesis.hdlist.cz', update => 0); $urpm->add_distrib_media('stable', 'removable://mnt/cdrom', update => 1); $urpm->select_media('contrib', 'update'); $urpm->update_media(%options); $urpm->write_config(); my $urpm = new urpm; $urpm->read_config(nocheck_access => $uid > 0); foreach (grep { !$_->{ignore} } @{$urpm->{media} || []}) { $urpm->parse_synthesis($_); } if (@files) { push @names, $urpm->register_rpms(@files); } $urpm->relocate_depslist_provides(); my %packages; @names and $urpm->search_packages(\%packages, [ @names], use_provides => 1); if ($auto_select) { my (%to_remove, %keep_files); $urpm->select_packages_to_upgrade('', \%packages, \%to_remove, \%keep_files, use_parsehdlist => $complete); } $urpm->filter_packages_to_upgrade(\%packages, $ask_choice); $urpm->deselect_unwanted_packages(\%packages); my ($local_sources, $list) = $urpm->get_source_packages(\%packages); my %sources = $urpm->download_source_packages($local_sources, $list, 'force_local', $ask_medium_change); my @rpms_install = grep { $_ !~ /\.src.\.rpm/ } values %{ $urpm->extract_packages_to_install(\%sources) || {}}; my @rpms_upgrade = grep { $_ !~ /\.src.\.rpm/ } values %sources; =head1 DESCRIPTION C is used by urpmi executables to manipulate packages and media on a Linux-Mandrake distribution. =head1 SEE ALSO perl-URPM (obsolete rpmtools) package is used to manipulate at a lower level hdlist and rpm files. =head1 COPYRIGHT Copyright (C) 2000,2001,2002 MandrakeSoft 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut qs@;u{s7ҾnlLNQnwzrIJϤR*(9 4o$9:@&AoOnIbAF@ I]d.Ҳ-ĺhD*'ɟ_n˸RX]'-4ݻQzD! f]8W# 6}#66˘ea!ۺӐ`H؎⺯TKi4@>EP[6`?)AVR'I*v.}\W+J&xJ`IƇYB!{*fI,ŭ3Y5le1Ztݮ-=o<|'D*DU[4.޵>45"ǧWn6 swL@})P&jgxA ÔsB~Vj(kcl[83;#>F~)J-:{?YYYD3 l\Z'ŇLY̳)@:o:z. -vܭrLWNDA9γ&w++bWUq3B/pҝ$q?lbbџ/Pi#IV)(de =ۧHOՇp:f7{и B 0K١ d@|I_H3~ΰM'7 Zؑ^cD7j)^|fxWbP[] vq /wc&*J(QV',6[G577'[6߻H"0Lr=&|Ei !l pBy_aqF/ewr.Q!i}bMRUj,0 ֮3kMT(f$`TkmsӭD[[ӈ=~p2& b-65ׁu֞hT`kNsl- f@el FCɓ%M HeK$ RRŗ<ݻ+@sG_f?)`{?42b4K wԌH@J#W3 upDQ%Fzsd[~TF 5X}}a&JnĞ"h8F(Qu)ʯyKwgXf{Jts!r WHPסּHhxds`HqVA},=ՄP`gS| ݳ7RoTk-$PnH3=f?IT!ؾKnQĜ?툤Affr\!'tKqf94N먵pʊl\D"3AR$y8[nao ~9(O"v g yhFj|'ߊ|gƪZ̵/viqcWȢs#@O4F!^/τc0zJQ0:x@p  a_^;+MLR|6#1F|;&3,l܆c ixC>:]{9A`* Of¼88NejmZvAVK75ŏEۋ-B9}~XֲiA ԉb W_4Vb.LCzkR%@9Kv1د1u`ְ7 i!PNܞkՄ,.,9`]*'ÇM,5tI+of ]a!miü?4*[X*,?vxfGe҃mCg6IxίXhbv}jN_SE c@$w:MǽN=PRD4%-)IuÚg4pMm3@(\KhHaqW+ȷq Re'NPk0ϰb7NdzGe*&*=jr;&U;L(²rP!tk' Q*ۖ|^=rg>fIޚC+6g4U Q>iɽNpAꎲ& '"Yw !Xх섶]Fq8\ݐ_UM?g RFJt!+Wf>KAuSg$-h@ebNʷßL ]|jiDB F;H_kA˕M"bϏFܑȄZpTFl7 wn,;:%)w?hTtBH7Z{ *ˏ̢A L)!gS0mC5a/ w6퇚H r K9ʀl0=JO؃&$g0ٔyVpzRв$@A#LnF!qn XǽMqsNIĸT(xdZ_/˵_T=aNV~?{r1GqoՓpS+42nffI͡~j=NmM<-rc)3W~+ˁVfiϪGFbJn|Ħ|Dwсϊ~tG|cL|Tȡ!Q0 &5mQS }% ¼(L [~I\lqk2jqV ~1d%F-wD=W=(O 9;j~R:690LCwި_Y^}Y!LL"ĵCiDݎ~7ޛ# K4sW KR(-pfq9bFS3 xrrffRNM- cChSD@]cLj$WK(䠡-5(ͪיb8he-*@W`D6K%DǠ)3&dל &08냵q,=y|r^sWqgiy. ږhzk~OE]^ѵdZРtR,ɈT5-=U-ɎC+H Z$Cp/?_to18* ހ Y'2ޏUKNT[բHv@?}Bc-#$pf"hXA.7MbXGA ׬񨧋ޟؗ|kšr:岆ޱbꏹ%J! a7̈n'[a;G,5a'Wڽu(usF>`†JA@Sz%4-(F Uˣ! rp'tFe}.kUVcdCL}l$ QA*N'gzraQ-U|^R=h'9lH_ ^Xwz5<0V,z "U(0a(0_ߡe,=&fj)M0i.'Pu_)9!|yl_2.67E^S8fgUrcW0-N5~P<;Z8ΫiV{AL;Ň̷*nDx+ޗaz flb|jя)7vH1@^boP9t_l 3$wg&ps==ţR6''[vC{SU\-տQSM>Dw`Xǩ$r<@%"e g|?sd%F:*GTAT&.pJyVg<'V$ZNU 3qT2k߉' ӦAŦbMRp͋4pSjμf7`jʉ ?S{T`S}m`RX,muPs AvJ E[4ەems7a1RHs, j5D [~tnHq$x񼏖Oыя}:6=I{ <]ׅjrn\mw:v6E`D^N$j ΤO-ibnyQ{Ax+V~:XA]XG@R]}]78͇#c3O8'*F,piu mM_ NÏ?#gjyfgHQr" Rz-x esKLø cY 7'Jڥ0AVɁh'hjqx{}rX4=N†VHqW}ܯ!LGNKۺTA36P BK/N ~H\>l{*t,ʣ0Uαc=DaNgpAcjYHݩۘ/u+o~a}L^h0pIK-jQø 胱< !7d7JC2lE:Ѩ_ޭ ctk/: bb B1Rң 6Mz3Եָx-RZt%gњ/Տ/q;bih)/Xo ݢXC^®{L\^}w2uO~v|[_3r`(rYDTa@tnhe FK 8׼BVzQQ]\TD] 4ƒ`v-JŧO֦~0@`(Tw'h\J(Hw\FB vXߪ}6mM 5^W 뢷!ƴR(p~o' Ohi=\ZB^ɒ:}0{~~yokrXEXjlRGڳg wT4Ԙs\*_{IQ\1XY!&R+앲JgȋvE;_CQXGw1%BV&EO׍Oek]R]ӏ/leea71`ݵOhm1f mT}!vۈ6bi.|(.+ dٚKh7@4g= ]=J#58|ӞRT+@"wpnkFV|MԄhEP9Z.qDx5iQ1:Ꮲy,krßonM$:rdqiMvH9E%?Kd4*oP1y;<-KW< F/6t7 w딳դ ضָ@eШKz^)'lH೶|R?ɛнH(t^(#Wd›vG[ifȏTq`X>G7o1JFe y=xB4įq"{tTPGe;Gsޞg7 "G/wOkm*Ϲ1lng;ATxzz`.ڍ$~4UiOXSGv.C-Vw*xАl-Zȍ.:ia1ܙ{AIC:rGf/7:C9ݢ3m/Ujiʭko5jFVPAAbj-^O!+kAjaK* 8Nn: zz'$?Qt E)97ОaA0je~ @1s2ҎT.{VYp*se˜E:[kYoS2rڐo/x̖̳_V#ЩN+Fc2fRQHnL*whvCZՄ6J~Yݔg1Cws~|Gk.ɦ\Pp5̵~Ū3(I+'/Uvi ٯ8ek\-NsXrOeճ>.A YZK@S[L(γ W?t"Ɏ!feZ~!Q! DYlw P sblK`C9'|p}+Nt,&U,Ԡg}~:'`Lb`jȘqFT# @L2dVhC=t>6g;aMƱP&䟡EcB&jBzp]@-g?,?ßY#3Lv 6?+-S~^&@+i)uts8GeLuTtc: UCH\hCBS${= c"# 5U'T)S (HӂFM4J~˔ W;gfFRWX]7LLY4o̧Rj<1NRMӻf] !qqD⟹юWb» =OZ/"YjP^ 4 _"};yYQ9K1.?0vP|#_"5H5]Rv3z`GBNSP:v6J7̍c?z˅oKd* ={&QI3A"Bհmo"Yπu8 $HF̜}G"XIiw :Vk2Q) K&&lYrD5)AfmefPUmD TT*@G X>>8|j2{xV~T""O8# =ۼu~ a Ծ''۟ l~. \u۬-g5T"n@0xX:F ƥuF~5k=Chq:W )Dv:y0ZS bB/WQazCxqdEfhp@(vɧH`PL m-m OZF`?QDbzJ˓!B:2R7סS3#ռ[J6i 5pͺ׭#q#h1+e&k ,EO0\ΔTa1qJ+DGˋhW[Muf4υ5f ,g8T4yC5s1@~EǏ1V2]#;?YT=r&,N/z 8Ԃapt])Aey?L_ч0+@fTa7F2VLqGwV.(2)BbmɑVOb硩lwrZ3p?iNd1գq9Ć;9;1 7b8g-N#4&͝jB7U0kn;"!rT&{iȷz1 9 ( mr,lZCOc/2$0!<8q1d *:Fy9N}  5ҥ@ioũCu`^ބX8E>oϷvg 1Wbm Ŧ*Ump꡺} >@ѭE#Ս-u~ɾeć@Bw5-&X1Vƀ0ՕvCM؛N6Oh*{&f@`<}3I}A'%4rc(ɾ g(xp0[/0hΣ4XΛ vKQSi\ **fG{Bd[WtV#:|G66yd(c1qVc]b9lW' ^]L^(%J.ĘUv xʜW^Bm_L{KMMӖn _ЮJtA| {BW_YG˳9,6>&jr.yŵ(Rמn$.g$/.ʕEyѱLB$dadbM* d!.O=]5Fgs0Nmfu6kPL 8._{6kuƽSOYD0UJ;D)cs^s]讁yN^\b`.A]AOdIe^-p+L5~괳zn] {M[׫g$%hi+=hLckʻq*@H3|C(?!ņnUO%%mKU# TMĬo$i|_K>o}^lkvLJ[s<<9f_?}HkTG-r p-*N (Qsk^1a߯˥(,nΨ$`xc%7 .m!x:v|,|kmMM3 ł3h3]to?{i~P8)hz&ܞQqaY#IM3>ZU`{YkF,pj/ܪ>FʺޡL +wDzVH.@**H&5<A7NoYMV^BF- y.VS RwL)av9#auԟ^}`~ V(GWE:.m'{`~-k7To=8I4(W( 4$R (l, gJjYc\xUe‘uTe9rxy_>+F޼)LTU 5rZpAATڟz3S390|xx⮷)c.wjH^EI3A%-M4<Aq/g@>,36NXDɂ_rKdК:24G]h]˄ij4gM - Ĭ,\t0 {\Z78åΌd X-4_ g"ގzѲZmC*40nV\N6*j޹965!LG\h,[ț݉aqǙCBq7ᘙUؤYz:L]CVYF[%iΎ}H*MRi(+C-u Ay%1CAJ7qSDX u|DP U,xS J:IB0j]!{t4×a}T gQL?F '#'r$z.>in ^?dzE~R@ 7/6¥ f;V)6W7H?z0xt͉vZKaJkO,YYA ϯӪbz hx$(Wk>^vPEHi1g0x , E_`O`MNq&[@2qRܵ|?R~-*UKj*q fdZ eŀ.Vwj{|N03"ߖ\T~؁P"nPؾM`ԡ%Tw'raBz+ E7^堬0^tuH 2f,';x(/"2,6vOAFc0<Sj[[k`zZVbfdޢaB>e)qFm )ܓ[9uR&|#KJO WjJ ӵWUMY(BaE/<-+j{. [d&(ynۋ_ ^\s{&92AW\43୮E?fBp^']^n]4t2vjkvƦcnb!f{11vםhY>1*m` 61v|}vwAxU)Q@KW,8fY ,,*acd~F}9})TE$X@@H*:*eO~Jvn;T#-uqjOT%MJ.Y/RH #@4ۇA={-z"׳?<229Ed>rK41%7 0hj嵒 +,EΣ}G/1 W;ڻ~5{, m[9M~%&Oo^9mI*Νn`-S|]w>GzL ]Nmں&$[>c<%/`PțI_.A ٺFV=( ㈼Uzp?9ٿ)V?$huLOzG!A+ddKUDD+ j&NJ#dCT_GRUl.ZP v nhpG\{@H>@X*u1a?QMȷ(' A7L+KZoD3щKi24 !' ~ƍ`ɯ$ӚD66-J ^A3|ka /⡛y)AaQME=CRO+:C&qgs&~بR' ly[2yxsCgǚHo~/s"L;jUkr8vx%KE(ܿcTQ<~S 'zgN ,8d_mj ʔ zuڙnEY|_ԟvF⃘A,~&.S. _$*[zb}|-Y%4 vT<֬U=YΛE uNio zPϙֲ:5b\w&h-?Z![v P1|6Fƙ, ~sN-}T*H*(؉&3&xbr -T Yo) O& :c_mrq|f:_.ނ0guM8o8xTJ?dUMoqy6̎dĩ-Da )zurɡdv tJHHذJsp9v.KXeV w#73GjwrW"|vi0D[m]XuU 7maVok"s¸t9T+K1/mԹWON`'kq||˚Rrb~:@P2BTg?oqPP`! [U^UI I.ST}~tP!MT NQo=?.ՎVf7qJC5=і/.8]DKtԇ/|JF.% Ye-D?"c% 2W( I@fu/ޣ8XkJ@pbu7!| |-N&TW ȥ/!Jb\heK 35\K. 7QT6WVboKi[Gl8y Ȍ(!v=~-GI=x~}pxmߨFIeYZӊa5H$U5)<ҥ) i֭܆YAf ^O9 fO08)j25APL1Q WF)ӡ(tL#ʹ G_88EHk-UÐa@2pNnAu.j,vnPfU>;:8?(h SrS(CQi6: bm<~oe=ff6*WF}8E7FE +(xd8g~JC.66@xbUzOG;D".4Vsh&P)4jh(1(6Q6Ε^Ӭ>" Fc#QS'=4m1OwAѱf٨ׄ+!Fk`jbsTfՂYAU"p"%L7cv܀pxՐU+KQ ,Gk?M6)zEVm,MIpQ;a]^;S&,Ll|;˚w'[b z-ܩ <G_NCR*Q>3C\Xqu Y{ Лe.Jt\h\EgK a/~9ͬJW̃&ϧ٫qrN[UTXVȬOTJH99QN%O4i}UAZ+Yd;Q\/ciᾶy4ko:d-DR5B';7&ffJ}ч0/ Vź!̓v8.hԺ-[t:ÝGP Y>a nl 5ye7R⧊v)$3Ed%V#.Q-6Ñޝ3- zdd6ocPMZХ*Xjz b:@-ւ,~t ύݱP]&]=R8EGh։G'9q lr~58R-ue!!w zvo7hnpM9;n"y] a at~h_ظ8B+nn8UagC//8panQvH>rI4@8u5_oRȜ8uc WRD3RqvaMj D LsɏE`ҚpZҋY J\;ڌG}S%讕,y`Fm7G咖+2{dcܫ=B)&Pҝ$ŽlKԌےpivtCDO3~("#$}'^/t'0ٵ3,Re;lUZWmvb/ -`^/3G:453N1 ̶s,|BQîͨkac ˸9 kp:0ܟףۭ0 vN,'w@ճ]8"["ؘ%8`PDp kL{MF%ȇx5x)'e2LV^=I rqP44DV*87޲l`-рu(IC|uY(@d\ch^><·/BÐmX |KkXL{{C=l|; msGG*AojrDM8v؈]p!R 3<@ 3Wl+D ዲo|IuDVI_KO qyLQ#6DUa!e '.;,/+쬈tGL. OY"=*a%`)^ #ͪ&@=& :c$x2whw+#,6S%JKnM}Tpfӌq*u1C Ϊ9X]ꁳ̒r; S&Ȱƃƛzjњ{({YEw;RahvepV Պ"1xcXI"-Y<-УCd02@ pas y}%[ɍc^M]ǹ' o<:_MݛKsl(TOd _=ֻp Q#sԔ\ϐw XPeM]9_!èxM]5bvmlFulo4o&<7jAiy [DQ2Qa !wOH${;#\h24Ӱsfb]϶`gݦzZdcGq2vEM>^pkHQ?e2!f%۷n18 vjk~@ ޅIOd* pDpR_;ABgm*Є.<7.ڭ3bɡ> oY*7` LLʼnH5mItymk/qxaܮ۷bT@5"hPpS]=4#+pOCi_!yȊےىC\ ٭z8s ߹)%;[P}`zJHkdjK9G׃: .4Oo: 8Gc₢Qh], ~HM. j=B5-d᯿Pl9=S>Lg+&&ﵳ^{- #!c0栴m7!>uchELDF[L'!K7e+?[BN[J8 ۫4e]bW 8Sd*iyG9E o*C)=ڟrw: yՌ=h_BR+ul&7/u +(O~_%(}CMw*٦]Ýd>^o%ʼĦVb?P&U  9w'J[qsAcs#`?te2S޵ãeGluO#U\ʁBwp+ow`cFQ\R8tqz뮵UTh}/˧.*NXD Eo޵N%x33엳c{#ѹ=)AcYIf%4aU|Jdfm>.+{VػkC9(ɲ289==uP"7eR[0F1}E0kee4_$[ pa[yq?U_4RsMNpm[@[gCLxea~IQWl !['Lg(g*ySi/b+ ywj3J{h]Kr)EXm]ߚ;KAF?[F}' mS(c]5#t#2.* M>8.ҕ%{ݜ.#EU=Y/b~fKy$>_5Ҳ'.EKtL}?5[ Cc'+r (ȇ}:~^a-eF+{s NA6w+"phw,T9~ϙ~alD.7QAZTnGCfr'+ͲZ_=M'!sO9 Ag/l*xˎM=Y7yG/=ej9.C,X}X5q3C! oOCAcJ<j.rMR^v 1]4bթTe: y/l4\OM{9rQ-S, сmȩ%l[ A%e$yG?|H?t1_Q(Ңj'LZM=}.H;\}nƍXO弿Xݚ遆qz҆|W{{ sT.wq5b8>PDb,WBmDnAxk-6Ty kg3AGW#Ef^BZh.HDʫXk1~@HMZWVI&C}v.ce!1HRrM:g."J5=e x9܌ Bւhe(S5E`~%:,J]7E@˥ZMAPo9@vt #m†]g9kJ19?Ϛ !V)[Ex 67:J4{51'ٰc'#4&JwOxu)%[ǧcjn i`xz9nGH4_D6sN|u6";X6dikI^SE֛/=2GU2\j;O_spH}9 ^ϮڠJ٩ڬWT)R^xgO:8?Xf;f5 jU1Sr\[E#)σ[tIJzNC&;6 7wg~O[ 6R*RY翲nA\ CwA& O#{қalhuXcwAzz88/\ _jeClzquM<jV efc<2{ X; y gb"%O.x$4WIWR SCEGxޜְֱY x3ֲ,I񪽞2R|̀n4vlus}p-} tC\c+-CdƊRF](句/z]chx_*4꘹<&.H5v$&%r-7].Ԝ.GV3Q/0*Qq^%hW厹Vvk9qD0=Hw:tCiy,gו$ʸ# qCDEpA#_0RNxz)Tp'O3Qѣ!2;yc۰ 䞟yu6yw̗gCUZf3LM;n\c8c>IRZsM#DH\mK;T$!ayƁOJgRPi˘^)cR*z=Op[d"^uz:xN>ݑ/S>~7L7xYggs;6l  ,I/koR+:<}5]XO ݄ÐU^,'V݅bس;PXrt;NsE15[~7T%'kg٠CiG `YO;@EFzXnDI%b|. #.I,CYժMՒp M*.! " v+Vn&CBݩ g#ű]r%G"{ ' ޔ19|P>UOB(b\HpkpDڳp,toLaO2PʗgZ妹t\jzJABZ S[:9|`%@Xj_\6 7Һa_QvM; GzSZ:t24nԹσ:;=Kaol> ,%Ke\& $iHW=߫0=eSN=X#;;(L008k2 I.0J,Mprz.@@WAuNߌCz0SFA@FڑKo&D-hr{|ll6,Ub~0܌'j͇[m7o`@ꂺ Pgd\X7ȉ--dzDI+؝Eg@|CvjCtLfCХͲ@hL/A=Z4CHn2W@J aʷYWo7=bV >k Ӯc?W45}#Iv'|eiV% >l CO; A%Fjqoip|HٱgfqlX_Ok sEM GScs.62sijq1Md&ŶjP *WpZLe@Pp4mG; xfI,^m@*e9'ݻD"Y[QUjH=+>O2]_yN-olry iC 2j|pjdx'&I+<"#wVݸ-?>`ʰ̰҅b7xTkUDiD u`H@H>wIlmEԳ)⡀\/} HrW4z/_ˇ:պand6b0:dqdQP#2 P }MFi[!xup.P"QXz`jk[U] kaF[kOuYjxT"ߍa^&G}K*^fBOSSkT+[z:Wy Q-6w%t(Nn5'eNEÔizFoP| r=U}^eQ _!69L;h^.Fshx"JdhNC2!:c;B=N_ D"KfB8GO~|~Ak雜ł o:+OfAls@l/馅!Up:T/ρ>TA䦰ߥSpνj>EXgLźɱpv@7P[@E=4AL\8m 5~|J!}qnɿHN^W.OU4-uw/0 OJK,1ׁm-P)_J7sGykE.tۙG6N1xp^={ԁ PXj=$~Z%uFa..GܳZUV8n&ތ-ez"( ^p#}+ _L|t BjV6ͣHҫ ߞA=QoQH|+ ~Lbz"ul #启\bn!Bɳծ C?ZFas w֩c9Jd(#z2xb6$0 CHY4S=|M_p(=mZI 0`Ep*˥o]ϯ.Gm|3tI>e>$P)1lIU*!*^@YK:ެfwWmWYڵ.r4ǗsLhT5!]B&zj Q۲u֬@Nt`Vhn6Y78 p3ŻDXfƕhaؑQ3,'"{x[-ؐ)47: %"̘}Ρ`9(=a w*,M5|Bp#v ntAN[*HDx8nQOTy2Ϧu֠\*@8^H NJU=o_"*^?@aH&gmˬaq^T])Ñφ1DC'R|gbcD>"q|PxW4ő샹t"g HLȫi G&٤vdHDlRM!Uoz:KREZ;v̥Az.9_,7V\˭̭~%(?uSjO2hju,{S#ȳyP|#ÞWFiڤzbFyŞva<}{T'PYZ's㩂B8NZbfEMyN/GǸ>YYwO֔OV@[J>T]xoFo$92nݪEeo.9Wa 7=-[AEDiJwZ#=IW.7:}ZL:mӲ㰁 X6zGb&ˉﳍ |F:q\~xzِm*҄޻ɖꋫ_3l$Ιt'_39>Y╜\\xN>7n]o4GT:Eg9 F9B;($-l砛a 0L01k'ߴzWVԨ(y%XI탯~ܔ#IHҜc3hQ1..fO'|,kp1&K&Z^g0uN g˹A,S:Q}&SK\Ʈ_6'2N^> Hh ͏i!/w;eLuQP9KxatFJHz.7}P@ڍN]1@ yDQGb#"3a3,B7&3,=NN_ԥ׹񷳙~"L2H ^ůܩzg’@+ 0,w*o!=[$RZT D!Uea-:XG#7W|(/og*YD:}ԖUとs\ "q6%v,F[*Cjg6?|o~Nݷ`b, c!^Jn>}5^Y;%kM$Hx-X5CO"}cDfuY=cKҫ'_ w զ ěTޥauJR/ ;CҢђdx: ^Q1˽tۆj#mTsioڬAwT :w,}8<0>-#vd䴒:WiX}Œi%)ycsO?[O:/\h #trc-)2AKdx_8Ͷ6jMqѝr?V|oaǘj<.CzҬ5H,6-e=K.)B;F;wYr bM}JzZO5quyH1NŅ.NFnvu?3+@)?[(F's7'AYNm +iuO$x@Kj .[;U#T[ŸJYPgC <Ǽg\IUY~(|ߊ 7{9}& B}1w}6d4cHuO Xu2u䝄)J^D[\'#C_UR_6E#AFkZdD3wFjmUI*mPH Ǹ@yfhE''$ƚUvr x8He#1_9TI( 2 oh,v6NbNlk^ 8=*g o6ot$4 C*N ؎*pQ8[ok?.Qǡ <~N FLb802]U5fr/*Bn#lP{]C$[MF+?~*Ia|hl)\fet<8Ks73*(yB(6ΞEkycl%/OJnD[I jkZH2 d5 nrlppd9ڔ%v^qJΨ3ܚ[ LLHZ;3LDz㵪RJU7>~./7Xp$Vʪ yɦ5)RӖÒ1)`p^ ̃M,*q@F8W.Q4SG)P.{=`=U}lq]X$ xzC~=ZM,ZVt=?qr3zZf~QA/`V0 0TA0@/ VjnB܇9Nk#̦P}FC%)fjD7:x^C:"%6뙵PN"Ⱥhxӛ=-Q~D<ۍ+8(l v/q!=Mf;ڬm3oJXBӛKv1ExԿV/hjJz5Kr3C}1j]$S4-͊iZ s/g(ҳ-9,iרf.8{WMgYM@7uYD6.]"wzCCtgyéϋ̥\Nu{^iy9 )&"ZqB&%èAw-Y#TX:\V8ɩGu$jx>ƅz// 9#6p+Ȟ>{VzfeþDIm{*z>O2Q!!+D 9s->Fc[>W"Q[l0QvlY/5*$k `cXk剌ڋN?A7@]m,( :FC~UkT4FFjo8&R$Vw4 L ISVlbs~ {&QBXu"eY9j~_M+ vsVp̰4Eu5rQ쩹U ӯ`kvۧ*V/R;7qc׏@Qͫ`bX)FXϤ5|_JKN^O*}=v#QWni ,as#Q 4J8b;[M/pۘPaUqv8a1o#lM9o2x͕% KS2v-wh5Vi8<p$(7iA'4#6GS!b,Z`iN<_uq/*ߡY NMfG%#+C)YS~Y ]?W-Z[јsG[Fdy|Ծfn$Z_=v9/" e?e>ی D!a nFouQ$+>K(E8'TJF40Zz#ŮpDܝVm i#Hz|=31ċcnOx+fuCzBcH#uIM+11d|qb/hL}F(#9;I#!FBDiZX4ou֯**̃ ?:1)Oć =3<͸Q`dssF1#t`"egԩ\A*0;bSE=a^,LMl-ax[rmD䒇̷Y4jH(UhHr+n#Y 9;%yqvyow\n6"_#;Ex+k0$Cd}ځBxE2NؕK 4)?+Q1$@ٔo2NiZ,{1@(ϯ ,MiPTǪcpKG F.[>`"(>hctzZ2? dGmk\D\`Bo8E%g8ZRak|#szFuSܫvBɲg<2 4VZYѝ ~Fg`K JcnxQp,xɔe4w_ \ƇE COΰ4RrC7;]e>Kx=G)OA91#l 1zv+҄Û5cbu.k@ ;-HabY@6GEi*][ #UnƗuM1 =|RSE۶/a幻D`:a,Xns:GI CBj&J@"' ԭHc談L .w2kVs*A"L2 3ٶ߁9mMS ߬qi|`G 9@Kxf$m11r9>/}p5U*Yo&9~܈|0~AD]*t*%YM7opE/Ay)بÚZ}qklJqQ ,,pVQ dCѾ17&,=5 _ts}&B d3܍zS8t^X>>jQ  8Ex,Q;6bI4}:JUࠝ\r̸O6ܽ U#wHGv5fYu}1ؤ8Y .Mjˊ,MvJ|5'Tꑒ t`_ GL0-"q4Ll@ lD#_WCS&ţn 9/3r롚Q[:9xP2o4^0S@^+&*\S)2)/Y~DIZX3t0 ;7[q;v'} |9^юt{r"bq#Hy!`ΘJA(oJRg]fa) I (kv㿒z>NޙJ0rqH` L91WM-3|iLD6;/m7Osյ?<+,=[RߛqίN\s"Zj'`R;<|_&F?O\6?X*LsK6z~4L^xӆ)LY3o,UI4ՙmӍqﴚp0șgkr ǁ R:T4,whw 3]kCZZ,v(= d+A hmvBRrK?OWdɳy8x)w2ZAmXu|8a&s| nQvEKb"~/U"0iM5VYh_Qo #C4)Ocd}-fP{3QԆL `D]x9A~j,;IOH"GgDk#opF^G_,In}H{Q>X'"Zw_s=7S4S O"ltu3t r E;NX`KnP&a[yoڹ!ښ/ViVAfCٷ]7屭R"M`=+^ B\ꓞ!laJ~@.QtFuk q.Rd_hwQ|64S1G.ʚJL)Ac]C1ڽ]:hŶ e?^~FOa'MhAl>cسm8Q wlJB msR.tQhO+.NHcFIg ߬$SF8U&u{[2KF?fXY#LQ1c5,lm5˰HzGA,U%'$bB"{-V00h2eJOt:#hZ JmHc>IO֍?%ejHh_bǒq6e{ɦD=&ʯ5QXl+:S,Vn4*b%v>3Ft!&q}1嵃iWa5'hɛ?l FHjp+mpw5 >j߄0F"in S <}+qcfjZҝ < @sOߵPo]Z坅6@>eP< ֑W*z|yVֿ'1 :Amڴ S{ISx)Zeyf|I型gIVj/l% \lW8?6i^HY`D]s;rv6"=\QG2?e UDyx}7RXX#2U=';@'aXDzDݏT?? U˱lTf0~ ThلO?hm<C
G{gAvR3|jC^>»HR9Rzl;Im~]?ՙoӜ=:%T[Z}`cek"r}9xau џ¿O+w`!/Fʪhc~aoØo|_Kp*,`Writ턇IrnHhʶe) 1ņĸƇy!wY˸;tؕm`<)*'k1bBG2@{[{l=|3%j6UA_pb\u-tk^7Y1㊒-6Kx^;'j8uzX9/8Cv aM0eaSpo(} kݤWf%Gi9o6~Ħ:d9ƻy]7|?YBDg[kR "T#.Ws3B9&"w_zTP'\[2bs;Ae MBDH;`Kpkxz~S,,wRwOoQWG吇2qebKniL(r?m%XyI=yp4\UeU7dOO<Og[PuV.n7#8J_j^vɝ]كe(=̩Y:'%A1B0AWVƣ:5wwm3~\^lU'2^V37İ@z.Dhc鮛52)CK,FD\fBB$5+ 0t)ŃW:`S+J;c`LFlCA̷;CjWv6}4~-)m`15(`RPnan+>fTm-D I+H>ڼ,ٙ|n/7%>fh%wm;4ye- ROx W~.֒kL4PGPyJ|5u)b>_?f[V6ݷ^l,dT(#.$[EETCr.$b kD3Ģ7:D*}wɅ4 ieYz5v+DN.a Fpm.5dk w~X8Ne)@Dq;AjK O<HWu"zˑz٩wCI7v^o<{Qy#_rO?6!bD5XY?tͩ1_n-Hτ]Z2Rs A pL=dHty8Z ,*,k4λpjZBZ~fyu|>'&I! {Q2 "??Gw B)wyR2")Ts`p1ˋN+yu>NA2jq.…VDC@K-L;z8Ek"YE8_xn2넬Vw 3~QZ!K$|Vu^)f`oO8aWrnVp\Xc,GLb*Y R O]I9*FLeuOBY>:\cB~?5z-̸T$z8O}`i'^!2&2axk=UHar-HBW5NTM# ::\QDe΃^gpwL޷Ňb܊96M"J_]nrĴbzW"oɷo v#o1paL:h;4;LL|#)#YnO``q+չ \Ŭ1*# Dph'uVoY(u}c~in HК# T3=dƫkyu!n5S~)Qdj'#{s,mr-2vw)T|"P1(6!r2 -ɘ*  'G3/#u|ﰬbc׫&İ@ݔr;&gJ&߲ ӟBm%\wl?|M#=8DkNԭQls U0o-00a}{/;}Df 0֧Z3U%;IvJtyD!IU}Y`M P /4MRь_U}U"$ O-J(uW_Ί5.m+W \еSw[+w2pcSӚ`$8VYqǧ綠>@^9+W>w9G>sY5'@[r" Dtqi\A!7z[Xٝ ]ފ/z2\5O_6q;mMmEFO<6ʕ),?HF^u1ܑh[.#zNХ 4̣Phx_ v9ڝ軮wml},1ޭN׵S6 t+J,Ͷ@YFd`:kfY-*8޼k0iU6#M<c(xڿ&TF z߬BCAzT5 >% 5(}ֵ~\C՚tKeiGl&SbgY @b蜨93xKקw0T1+e:5=\Z=pX])lb/q+mzbt1NU?q鬜pl=q>7]s6!jGsҘ찆51Ms~b[MsC}&8[K2_2/$7X|D:v7xN-;dD  "0w?7IU86ʑUpdA!"?Z \+}KަaAˣ쀱M"[\x(P' Jq^@1ӕ^ Rz? >fHV_\ռ2(&[xK՗ԗ"Xc \5)n:,1BUf{_00J܏v0rCm+X?Gߔ (_u/録BBQL>T)zS\Em]Bl<yFq]mIKQS>ڝVYN'ʢm -`C!ʛ,b^jQL^pnaL.t i?H4LPar); nJ1.@I3RS N!|,P#N()UЪ4=smA :m~,E_CH-,N.h]MyUXV#w%$Սj!%CG-MڲtO+9A?  XD _\9k?9ҒX7  Ǫ_K*9-,$}'ZvEk?gO-'HaǍWI)r }FxlDU3$u ?P&߅p̽s>"a<\4F Uhb|dnЪsn,a*a]cUg54xgDd}grSAUyޞgIQ?v$  ?eyl PcD+ala3rz8A#Vk1T<&5W7$ia.wp9׽e}`a10xHLFmª$F(1ӡ6E=xn^("Th8rp&<iO @ʝBrAh7`L\uw8"olG_9GJN~ NWXU!_,~++=?SK[Gxy'Vq/ x-++6CV!+;|\eX7&yjc0:0%?Uςb}u+WPsQ>w{ǵ׼xT!|zHDk4>Zeaڲ|XX%=tBoBZ2p+Ol~[^FjDO*V⎿:;NpO&q_IWTa8mPDm1,cLYs"^-p͝{'GP^ԯH~J$M{>LS/2²obHfX1U=@۔Rio8]KS O/z"0' p>AGnsغv8v[a +BqmV$C]}vƎ+S?GQqvjE)l`d('u3? >$Xg^9g8A*CgcTD`˄i*7bB#WeJw@ 6vKzruiY܊ ?*ALא8 8X}qXϻX/lHBy*B@xpdiaT͝.+Wz{\Kycq_#PL7zCUrk?3Bx6!8b)͵ʿ̂oɔKMrK 5FQ%(&B\H Rƫ}%q>y3^ %߰,?MQ}Ί2nSa~5c v̲emd?.V #QkƈoD;D a-3˰])IiŐ}!˗9K,WA#^J](c |jq)wR|SѻV[n*-muF̠-)"zɛ*;#~Ϛ',--fG !-њ1H ֎h{7@֯[:0 8]RгN-~MRxv0Pf):gkOC EptF A>rt +W.MbA%ѱԎ!U!I˥⫭T)/OTZ AE}@SEXvpп9k3XdCQc|.Xe {ce8QhZ(dT*u!@'%PHEIM I}{Uj ݋N,@Q;cW#8: 89Y1QpyZ3La'iq|c3`ոgS aZ'HŐjě^"~OLXp8&Z/p`Ǚ~nLiORC `3 Ӣny>; x$ښc64\?;iV|޳*Q/"q'o@@&g Bр/9 7&Ԝ7e_`Q| oA21.f=Ԛ ȴc6{yr2_:R-X+F!H Zk2,W(;!e@΁a+kRSXPV/u>[:Sx:aiq6qc}eYaTcet,Z O)1uS ZO<1Roq/x 9cvKthK"Wf̞RC z0+UӺXa#Ȫ2nxK䂇@K:pLA6) ;ۀ}*.fӓfU8lqs_w{jO(1m<|b& pa߂;-z]!*\@μN d]weRJ'գnYckrr uIJ91bƝ8E luĴauv-7 bx⃙'xA!Sʼnm_SAxUQi4tú1fuR5>i׾+(kJ8ܦ&Z`uќ4 a$,I)92e^N<TSGvﴃe63ٗ&)0:)ZAw:Sut#s1bSjMq&LK-ƕbī\9.;g+Ķx}61:p3ILIjD4t7BhTW(Zkxe}#L3Fň2VZ2ve'z[5&Co=5lj mAfr>}bi1]O&%v*e a.gw`9;TȘ"u1y+m2e'yf̓ZBpv;o:PNZ>ԭ 0*#|GUGAȚ"31]/lCkʁy{]=<=\qT84J1JJXo'uLPxO%S,!N& U\w6N׏H%1;Hd NEU9 ZCֺt+m3v`ZeU,Um=&VDR!M]hm+j /ݺU8 \3%h QXC< A}ʏ3DIk3}.ǂ:WdRSFi>YZ?JxƻGK^f^GQӢ-Љ1-Q`4'_,h ,;#M:߉jDtkf y5*"W}e)j(E1ϺV3Tڧ\q3bV29ױ 5P,QJHi\UsLEjc ζZ@I&2 [^Oki5FTM \)V#cz݌p}5 i/h-i6$fs:A_T`qoo2FE. +72y,=Y5SItLD3וoID.b>OcX=]D2/s*Xu4r\Y{^HN@u\Z?bMi&R2a}{M5.^D˕#2?0E\j6BzV:3OlUzSTբzfWϥ#'2ʋɝdY%sDcNΣVnjyf`-V>(/}ίKFWaP:`(v1F>} g6H:իo ޙ֎M G W]TLՕK-3vnDai6g<&"ё\diϓT*}H--M^qI!"Cz\ R:C*(ƸGlnzrH!S\WC5ܚyt]> L)$:yĽ">P}:S~R:ť P!f[fe*8"gG`Mv.m+ĥm|cL06=b:U`di I}̉Wrq3j9[nOӊU{kԣAM(?*c?j`C돲L;L*R]9[L[I8ZFFPR+\L&mRC֕>rX}-ۛdKي g׈|t0ag֬' C Åbq@euAEx6g:^\) g( r;n4&ڜytATI?s9S'ϥ92<#(\+S'l'hHl惌QfoSAQ/O~e"ʝǠFhsWI w>7K>u8Ҍ\BX76/odR l)aʹ4,oHQ:˽Gй>]O ǂ2VQP˜IqL$6KsƷˎ9)LKy|d>kjO^ʱܲ[e2а~čSAw$b["[·xNAѪ vL!DvrQ&$@lGzܡ^f Հ^KNUH ˙n~Y^_P3p|NW &qYuN;GY?ܮ^L?` HcWƭXCĂ@߸T3y[ ,R^0`AiJPZ癁0/-]b19T͜zhQ?`8);]kXO+"f?<+O`jY@~b%9,@`!zl nk\r /Um:ip ~bG X1|ԽԇFHxWF`WGy?)I udsJD2L0m;>8%hbҦ%~|ndIxa9)d(b8*Zq΁5*qϑ;˳n!BDے/Ze9XL:wr)>Ӑˤ~O`;z}XxC& \Ԋ896tV^.Py FZ~GWOGM1[":| ɝ~I[uo:?_ǜg$' bO9[@{lO tsrv>R-H'k~h=&pA&k,Z3X6īzo+7m9OK"mL>6x]Zl,RpI<`#~Jjს#ٗ&6i%S͑b r0RC2_ns1K6 :i;(Oc8$|m|1s81%IwV7a6H `R!ҮڏL ?po^L ٱ6 (= 4>8S~1;j{V1:흢H(jEkY" IK̵S'L.{dFtQM .97C4x>= X9x\zfP3@K),2!ǭdGڵpv?Tyږ ^3[`ߠʲ'"Q=^(!21O7-3@? K2+{v2d8Vs6^/C%J@,|[ʭ=P;|@N]"s8CI¼8/k2. `{/_Y;3SG,\wi-?xiz֧/ּmŴ& ZBd.,%5% ն*} (wgtlbT{U4BC7kNo ,CkT/s뙒6Qژ7p@H20'8CPB'ghhWyǥLs&8*NU59T Agbu[C=xNVk*|8@œQXƎ_.:)mJ]QKd9 y.6f] jxm;vԠfKAl#7RD**< z =`Sp9pE'SEV"#R͚Y'Ȃ=#њ*}*h_mK_VX7 ϗ趏^m?["`1PV }u]roc'53A.!%EMib`Ç/: Z-\)J˛+_--Qvi,lZ&ls^$ssOÁ4_zn{2$ j@Pψa(Jke3re=]B(`t3 V]ܛ+ +RCL2 R,Tv Eyt&#rఠ24obOy֢yq.CJIKj{{$sG8ɛ2{8즪Zij]0áDGx2?Bǒsi5(oS:_nQHo[xb @`5< *&v;-y:o|c|n "=NavuTY)5|M2=`( }~ߴ H=ё1qЫ級c1P}GF&^$dSG* exo _Q^eH V5?U8#F[b4}c8oҶWPyAQl8m0H"} &!6 2CgZ@piC߬6YP23n.M%j $X-s"\!{0M*0^vXaޯ ~?;I2-qU8IT_Fxpe hQb8Oe7A$BY@&,m58:|o`&8Kc#`$19GVFCB\x^^U%x?vBIwtMG[4E=z ^hp[Tm0:M%0%F-Ԗ{y/zTqib6h}h}Pƥb{([WI;Nk/5ӹTTd, F$vzᙪ;2ENulQre+ҡfcƃouݺr KOD Ü"($$/l>S+VzÂ杭S|OeY'D4V[X&*@dύ' hPATL& O[P(g<$@&*h!(uT+&NmL)Wiz*/Nj ݡ5?@=햙ωU"rJ#TPjOrյM-xA"PC}~wA# FUH7u=taD_E2 ?`J=aGG]PE|U@$p_͠?υU~l4Цn`xAnͲ"\WX>Qn"=?k~!"ht=Fv^Q\Zח%k48olv%D=tU#!WTyv#Lk0B}r*w_>/#˳-G8!Qx$햒8 L%FMeSW]3}3~Ri`@wOkPTTJ*kcϤ@ Yhh< nMUeR\Ifη_wʰՠ#"*~ :VQox0>t uz2=W5Z.jSnp#}%Kx߲7-6\G"sYQ[7ڹGD*EZF%܋'c-^.]{m^gCEP0qE*["FcDBBl6AH"p!; Pꞿq=G'LLiж0"^k? KɅ`M'e2c%[hi[ G.Qqv$ `ұB nu_Sg.1AZv`XN]KɄ@ S0#tiyooH]j: k>k*" wڅum#D!Qr趌( G涡 rU}DɪK(ϸWg\s߻]$$dPvAh/R^,jW9C,3+([HgEmP`%fMYe$IiriB˜wxYcKß t.}|a08@gr3A#(m8C\[tYLtpPQyQPӠ;c~AIY2 6RAH'Wk||(j-B R\O$5}:0?8MwsQ+C-n,U+&MkG愳 !偿cIŴ N+t`מqtqA}(>&qFSt6!\DKoZ !䥽.laOk46!ԍsX[0tYZjوAǷse"6 ~= D6AG 8}xKL4)o0kRGaĩS,cVRcwC5by9гbťef n\iV<= *W:g04Su0u=#3ss:D`Rs5Dȋ(Yw 'kP5_|pȆ`ǡnWec}RCR>;iiӼ\ T:m #crH%J4${4{W g:c _#ӻhyUk0}<Ҳ|sVXVYr/m ?6Ks*wg(@ZR3}}06*EC6eia2'BTCTWt-; ecyud꫺!Q^a~'nټsux`|3+RR=agǑ]]W蝹!i[hvOju̩"/$h1Eȣ,u(W(nW ݙσ@Zv\~~?&Ó@Bu#0<9|l0s\ ʪ'{%ka1ɩ)xVRߎr`^y))ߪ0+T( eWuITϵ{e$EoH[d>3ͳQTFb=kHpM1ŵE9溚bI[CtXx֥A 7<RPDibFGt5L{Sݿ)OԞNGCԮT"O% p30MaՅ"y`DPnǡ)]1a^/kh p؊q })wD-,'jLC۠vOBa -ر\7a@- :'#;g^h`deu-k NHC1 h"蜤iXt:B Jl_2$q?)-.@{kB@&S&%2eO;4+E7n6ߞgò wuB3hI W({ e*T #gY0xa=x>M,V/dC9Gw8={ ``lUaQ:P584TkF'"_e嶯YFo39Hp~D 6Hm<]U~"LD@[P6o^ơ ya1g3W( 4{2Jj&Li7S?H9{Ib%/d H['M j<ߤSSV2q7 U.,|d7UiРI-yc&(ST\wCASf5yj4Ο~Q`SUY5B>`'Y-[Vmq+xyi#ψ@0yRnnˎUJ bVK6;x`X&[]uū[5ijoSr,N{F8X;9HP[]*i͘go/)Cwz`Kn-ɭޡfg2!0 V]=2eSB|Dl)}6>w˴AR mj]EnemrƤi;B\Bg3_dȖ۰`7E9MvYw@`J󔖧[:Jƻ l%l3`|?3` @Qm'a]vI4M]F:M C!;fWgwY=awa꽧5>h h` t^T1Y; *A2U9iw*y>,d ]k ?[^ykpTƧg~.d\#c6 Egl+Bn&3M# j4# < E܆$ll- tK?Khƣȸ-8 c2ETfԺgFMJ.Dz2 L `܈k eIhgvNbƢխ^7bj*ۦ7h#xk1?Ķ8ANOW‚U9Ayh&2Z6`EkkAr#dӈPGuiw%nķЯ_>֌Ţ=s>XFg ʤ[CY-$ӰeYӔ"gnMI9sp,z-dWY{˄n}F iO%v^4ᮆZ\b8)kn~Zy(O[Oi,07:0O*Tcm$rS[vx-F`E%v"j&yЕNCkX5ԼRM ٝC+cm ݎSv/Yhc=E.^1+{ZuG0X Q➖i]̞yan@$A%bvC'U5lnvWӭ;V)B-(g!-h+q)y#swjt)VSK6ij=wp)jzIeA)l2k sDu13ܴ5^r jpK4`v2m.q=Q\GJh2Qv0؊YCvZ~!@r}i=BRoQm59ܐ`$$7jlx}`9p+C.$I8 'K"q8+'qǗ@ th0)ՉEdFJyXK7q[ X?iH,`WT[+縠!{ _tk.v{9ڌN/W0vkmC%$Y~(Y[V 2tL|\ZV`ʒ[Aj28wWL|м scWZRWAp&KKܳi2!knr? fSVzf]Vz?߼`F,dv'݃>4y[/Sѿ6@'BʓL<KD!؃DXH>V2t<²1V_r"\'6;x{^\QEomm#҅ (WȒ d(fPgfJ {0fxKW{țZl0SƅXJjMGM&SmՓ|0j aĠR;Z/ ez/+vBfI<&M4T.(>|)T; > : ȣhEySHH0{ /#*DY?Tryq>9:R}}up;`ԛE'ٸ"RdF)|e]#{N x| 3+*dsvoPԽv<> `{i^,#/lg.]zض"HP_UN)V2~<N,`ULT$"wb4b?]IgJȪ@JZە#靌CDW|tgᆲ UǺBy1T b Lߛ=nW؝9Xv2YTZ)%?Ghײ!1% kZZU~qíSwhEž~n?t =pX-HI? Dt+/=AVbX(U#Ńkr~kJ<.bBq$'vH?^#giK).zgxovJZnCNK aǧMU& X@={lLGӏGݚH+.LQ$*nq­EѴHeF5 gTw=˕0].v=y,D.F/5s= rŢ ( ʩS(( uwD=ߗ? ! W l1QYMyAX^[ c]ċOUd~C0*UE'QmG<.o_Ču\-~ϥ4eU@# #h8'V}qpK#@iTG=rvolP5Ϙ ۞p%bYQ+r %[&}"cҰψl5\| (S6Z0+8`@"f{)i|i*)01yQI˝5P0 Gf_p%iqS2\K\^mN~&DD-'{:PgVdAHy᲋aqm]ОF/~g6:)T;{\#Ԉ^3*pD#%ي(k$-qc>hDS0ʏj[Z$ϿH<4oX{dz^[Jӂh/ir@RhDx$I(y+TУ N-iT 5aoc}";ا3" 6&"‹IXOz cC^@ Ż\= [3E\J+`kW;3z<d.Z=?֌:ZgsWҚOB%h2k& ,V#\ILf$UٹAk!1$(!s>>+!_vǟt̳/'?-sr/|iڑY$'c(9V?3$l5$xA/"[XUwB YIla#6{6~gAIw:])124=opx-a$f;!숲+zTcPݽeX<b>|&حP]J1jcXaCqcra㉴%fJVormvt4{1j-к; ty!6{_ */NL/%f Hb^Wqur Jxc4οBp|rP&՝=+?]FʒJ!x(j GFJ!d`NFhRꖑKI@ rI27K-Ok{ȐNk#rKtRLg' <KpOq qz.k 8[]?ֺܘ)U) HWhpXE"6}4%vH2J3Ŧe^n!gEhG fQ߼XʀOHTRQ$1_uKH}@L3}OփHriGj5Ӎ)&'A{.wQ\#VJAb;}qvjz'@;/{*.@V^~[u3W$U~Go&%Ku ]xﶋ&*'!.̸ڞ0~AkGkQݚM1!CL .iu0"ݣnY,<9p鶃ѧI 7.YH?{Ry^ Gaɧ!G%H(I[?==)OupU8#24f2GTn;VZp-rCQ⫐\vGi (ex5m;ca9{+`[@Q"eI}p{,? x3&Z*;y e2fEH]hGZ]<9ĕƍ̣tkDH]( 0,s ֓ҫ\x (2).Н2u^cYY)}F,K׀5`́"mo][>m.uM 2I:/ɡ?:G!D$~-#I=p'ȣЩi4Y(2@m yп\a@tA%清ȒBp!]zObdJHr1t7!.7d'mC2j!0,y@ aa8O~+oN %xLrYBͣ6QqK M;u_ʼLWIkүG:G[(o+:>b;`]ZLռU{O{י7&6;bt9Ⱥ |KӸZD^*j0[S__7ubk+ӫhSz%lܾꫨ~[haH*a:Ͻ*GLvA8 |#WqJ5Xcl>չI̙W{SzcG5vת9<#(5PRYb J:u< ,AEKZ6*^拙C~UhAXRɟ͆Qv74R+>iXsoT-OD`wG ];#=8%74zk~)򗝑iG8%OL7pz΅~_+^Y*B* :o(FsRp͏>VbӔ)#cj1[0[X6zA kbr^tj&~}WFliC"| hR({>Woy9jqק4q**jڿM|=$sN6el3Wi -10Plf!zMw8 j6l2Gʧ0e<.T~NLjvpfSqPYrkIAb=ViaJtOgAYVg%8{Gv fPhNa}4JNB+5֏,h JmMA(jiDq@Jva@}4W\3춲@I5E.IJ{rC@MSQ eilhe4W'K"eDe@ΧF|@ +[bZ=,uR;T-!00޺tIe7XKxq7eGk5+F*4l+#8]Y-.T(JE%hOSOAi3XPJri2 0]Dq,U1 o\Phm\vh`LiG v뻢0\io&.Xz!'uIOTb-g,1o_Xj +`i.'Py9~ ׆7PhL Xxtn[Bg,!:4mPMsn~N=YYaSE68U5nM(jQ(Xѵ2C7{ ˢ,1}˿OEbvK ĶAG{f' +'2kGw0۾:'5 |=IWUMkL#`1Z>Y+EB5^`r*/=[ӂ^^U/}hIo I7 =$, hYR݁XdLJk\} tƍt 騅U2ʔJ+x  ue"C0@͊hSl56=KO v㗡LTh.Kr3}\fLj8DXJ<ؾ  Yc$FtL mQ`GR@KHS8KҶ[07 [g/o22q.wIR:җͷqS3 dFh#vDY=aV`?ZTg3w Jn ]2+V,ATkYopb8U|;Q ߨʼʻrmj(k fdyF i nI+tw0L:;PYzKuBF>Vfygץ;@5(wdiTykrg`iur8bdP<VSR%# K3Vc{=Dž)ckkn<^ml}!vuUH(&/ܞNC ͨ+ ŦnKa(U@>7\f+F7b@=f w"|i޹(»( BT~׼CEٱIOy "Lo9Pk5J7Ejּ$2";Ijۑl~ek X4pfaT"H\mjB!׼"-̛Eٞ[!9S1/W~ o2}c]&A#9{Xy,UۙR 26]7pSL,$. G!ݳS(S.NoͼJ]qo$y7=: 2(*힄`ozםDL͟O|-X)2"Y BH(sZXjEZ1{YH^Rcw" RgK ؐ&@bT"R+)fUBQчnB68(ɝrv y*q]A!VN*Бoam̻M ;TAw=r{ I!6jԥe3%V\5+>} Q BY,'\ֱs0o6CLk`)Z*9^tBV7Ѿr ̮c|"Jœ?dib뎉0 _So/ý&!ՀӤ~TZaU Cu| cXd@4D(f)xozZdJ(]1Oڄ$6 #e6u]KCٲHn:Mc}`4UܾɃDZ-mvz'~9v"P2ODbS [ԁ-X Z((.&TU<K*, >&y j'id#T(QD5'(D9 ـVSbC?+uJB-]wtٙ Tze5Zq ޽``9.J$؉\H uGE&o}I74v3(mi QAPC_vD٩i4md4"ԝ cg/çLES;Iru_YoG˝Et+$?^3+ R.Ԫ0]iGU+IlꇝPmS:g)(idd̖ibB>&eK/JO#x%̪TjKii< /cwI/'bmSwrq}aZW5V4QTQ Ƣn*V@{{/#CA&Uº՝}S당J֏/=輭0iu+6xz)A cbƴZ9wWNUXNDW23bxn6sաZ:`VxΖ> 1U?t9aMJkQZU~R%8=>HЃ.P_@\$} fqhV7_cO>ƌd=`7HP?L\iY^k~ܬ2Ԕ:-L:ѰN<)]N=-[Lzv>@z~eS@~duE;Ns%8#uN{߆R5 s,R|8S-yo#%-B~ѥ]^/d*-LԘA%]f RQ on~R 9>zL#7^J4 sp:}YS[V$vm!Y@brQciUǢHɤ” BH"4'; IVq/ßph;OrO}\֕4ID5Qd̾F#Z }>C&Hɼ#v5H~&f2 w1P򞊦boe3$qSͷ "zR1I>l[Y.r|W;)rf pJ҃hew,Up>qM5K~Jv"U¡⠕xĪGcTljo}Gov&äƈȃX"R`h\%rԜc kx8-&HXEm|%1_]ݷ 8~.$^ @wJuv7VPd̬`gs|b'(WP4OAyM" [F#6pԕOnD!ϰ"}oV.vlfg \"CF@R3i?)z;reNP-{:iJ\suϮ%LM2 A3Lâ6P>g>eA'EWf_eN!'Ay A39bh0Z.4@Piï(yxݾ>Vv{`\M~MWl8y:5}/f=mrp#HG %' 9#!äL;/QD3mٍf v>EmyN8#>xc3ܚ{rJq쐲B@:VڴBn H9eꂸRNE{Def=ɡR  /ӓc"9zm'] -˝ί0NNoVW}JIv,*6xV*coPh02#BS8"5b"쁥hxZt+(P1뻓2!\41ʃ^*w]p2hf['b{bZw1X\;Doo?U]U;iHhśP7ш䧰…o@C/vK]!ӆQ9Yġ7xM@>Kw'Z\F DSM}9ud!z`%o`l}6Qj6HHqba}PkKIy:ʕAِq5ifm4i!<ǍJ bMzdN 7ZHhs8#퇨Ga>Yxޝ -g|  8 6Zhi yO8r.F쑿9<7]HbpAo!Zw35@,^& ~a7gA8 ?tҀżi\;~szr@2xY? TB+ፊ^Kˊ{LMY#@> 0Q W_gVːƝӼ _|.h/V>V*h"5+_|%fiG!:"F% u9`@%Lȳ}PsH43RuVd6Z-,vS6{ɄQ_ YJ\Qq} y*/)5KL!:0zk:^jiA >f0:%2X)4r3lppn~N!/i 2wVLw)W5XGL)sj?{[+ )JQMѼa'{ݢVg&8cݩ:8e'p>؉Y[#T. ˼[7blP?Ny64Hhsj%֦`Ğ^Xj<l(pv5(Z>"m; F(HW(I̪ ^p/DV9r|ݙYP#Ijꋪϑ[Z1~J #D~"6џUY]*3ݠ";m/GxEe)^-oF+]-"' ^,O10HψG "h\ IH̏OQh-< 2)T;C^*O]v'$H pK<ɕr7S o綹A G%L!dװ𡡎Տ].bΫE.&yNQvWfURHZdv<@Ys ʳGmOt)ntK\pϽoST!+yj ";#}؞%-"7 4&SbntvQ!f]? |i[M4%vj݋ G.[0Reco#JI3\H:rJ <,cN 4tArMG%^!3,~=Vq.6Ql]V6D>ISa !OԗH^Q+5ΪYzVnr}({Hn>rO1sƚWdjĞ;1y'V>@ qrn; ?hص w ֤@%7, [4 IT! &ke8K"O/ʹ*x_Z`IzeTSVl+SzLoA/eK6K,GmaV]e~TWCZR5}%-?o j%ӯaL =Wq#Y-KA(u\JeP Mފ57]$ (HɊ),:]bۣ#R3 o?M@̦?( -({8AKBsP/šQ9H++{ϴscV>`s ?Tzr^A< t9u›ZZi/wp:s‚̽)eٙ,V^_~0c2M=Z5LmK_cۖ"T9}p,O'|+ł<lu?{UD~(&N<[{#%TB\>3/WCo/)' vIEuH8bvRaer]S!3bu1(U?Io&n› $`2P/8eTu ԛ2*7 ܢ[y_mm<IP`v򬗩`p_3>֘ >8+ e3PAďF ClL2}0L^)DZHH6BcWGo&.YUHiI{Bq7Oϲa ݇3ۼacI[m0mohwo4j!>ϓkD2$U.\29WxR"Z^$xJW21ѣV:ʉB ޟT #Pȋڠ0QT'Fb_Qr W᫒)5B-'g1quYbb# +J OqR_4pš'LZw*F,)aDݓT`?CZ!">!e j_D)_9pq|_Aoǿ5.m?ic0WFx'#RG;ƿ` ޞ,%5e3&fdJ QPM,jjar2ſW5: I;Z6ac-PSZTRN-bE@'cuGxG` @HW/Ɏs&zAvmՁB } %9,A(3(S@g|䩉o]>̘0͋Htzިk]zӫd1( ᰳn^]N}T_M+$5ت X(8 5Kū>Ő Z%&JtoA0{,i67*THEW\|p .rɟbBia:<.%)RCqg5^] ુr,MvY&Wd*m2z(m !O+MxIck'zU22{PPH@.|j!LS)G" $ӵ 9Sjo|f5YئnS\ZU!9Kįxӫ$VTMP"~Ꙋt:cY1T0xpV1ڑm:^8eYwK[ ':q_\.'`x<_`?u؂_Fa} A:UTQЋ1,;ʩ@$Q>KwgwKǘD),%=A7}φZ;R8p򤞯oۂJ#auglY]‚2KmDrL;6 R@E%=yjcTڙ^ j*<#h~Bc"Xx 3ayu܏@qÈw8AOh  /2I/;+C '!i:cx_rCЇrwuW;6 Wxzz)`|NFr6xKA?ڀCZw#V蛛L[*~i6^UTPgߣ9 9Z)@҈iF%1Ҏ~~R1Pd#E[8Hﲰ\5qXhptbiiLnluzcc!җd ΐFv.R!AxOlp x2/~oUbudڙ|~qT U͇h5r}+/̬Je5*V{ݳҼՇ!ZK"3djЁIgȗݺE 蝪iԽ'<$Douw⼃#h(tDgUE_̋M<5%BfCK;3If*#l6p$c.@( #ƢbBe7~Cfh*1˝*z]nD-'n"~+d%AmAMƏ^Ah?W?plt0JYgp1A-4C5fFSH%r0] 3 a-udf fcE [k kn K'jԡEh~wmpԶm:ju{WŐ\\6CcHoGn)yt]-RC~>lWfi{s )}:`:`B#T#Rtj.g|ev1b'B\"qϿHd7AwiK҂ ʆ*Xv2Bc.]ߕ .bA<7,. WՐA%b˨o@@<ع huLFtLt4z`-EmYxA+}FExբYYb;+24 X9ju8Cu9RSOن,੿8Az0,qxRU~ ;)KbeGOeYMZ} pm: ^7_x%jQ,$ý~Uܽޫp)mW$G=7%P;n,- !amzviC gmME ӟT3k,@O3 WhYdp-Ÿص6c45;NH Bԫ 3d JvMRG!|]\%\|j l$zwǒJdeg9Uxj~!o ywW1EY$`<c_K@w># áBSZ:Lp1׈Wc߿@W%tLD$_#R}aq;yZ?ʶ(\""z|38dT 5FG0F5zY! ^F5l;,9 ؽ t`Nb7IJ&69$A\eq9Bx%hj*$t;(}H(絙@W s#ʧT}LW2:Db={uGE֋;aZwNdwE{"vtT-l){$f3tR#%%Ȍn 3Gz8 z(|dP ~;Ο;f 4YcI)kfG(`YޥZPb x1эb0v-ADYD,Sc GٳW>M(1M)\}S1qÔfw|23M~rz1t*ܩk߁ix=ʓw#D:+&d#i $!B9U]G}lPPӲb$k'i,(I.Kra1FvAha.+m.|]3n#Z!VE-ӑdȱOA؈ (:8/Z/^LCL5 7پ&^F &p%aBro/Br6Y-Ot^œM+mٗ2hYFn!eے7; 83CsV#4UW[+Y?!J.Zߥ39Ȏ708$ RKKnW|BNS"iaݮˮJѕ?WVk|p+qbX#>uAOb1[nuGɓ7u:F"Jݼ>;.|FY zi˯H953ꚽ(TwF.~ rlھ=?4oVZ=J^չ Q*>ÓWr!13#0f V xҀBnxqN^rd\jw,ٝ=7^WL<Y-N`:RJ߾p{* kEC:#eLB@?0VfkKqca} VWAB.IjW4}^Ԛk@9L2B.MgD"1U3>皤pGg}_ǯG*'%` abb.BPėC0lP1zVg8'Kr|,lj殼MX1N7U+."bn|*fYg99MEgn9BPEN5p @)o4+^,T3 ] v~Nڲ=y aaC3qs+^&\wvL]v&QI(s"3d21-ץAj(Kt[W B2q %aRC\=4vxR5 o6D8%G: oyRӛgSPMM*8ozثoG$:?5j[HHb!y7 l`>=$N B}z5ͧ5a;YZ+7, ,Y BؕTUqki_gPs4eWOH)EN!ƒFDWZ @dm?ZRNJgz^ ]>ba،eZٯxK_)qVXm}FaTkr. *z9Nu]7OH__sn:GKߖ(q;I%tR\F$+_mRz^ c;IgBy_ S3[&K+6%)s|QGOӳMHvDp(ZųU^K4Ku' &fȇgu"uB N;؎H):ꙮGpmA;rxPfg Szi6Wkyjme'^E.O)!47i#'!5AuF+L/.BH(c ;J'8@'iV2O[bCߴ~hc2,O^|\Ǟ^_nBx2)aY@rmCe}8&&P9[)^ #0Tgp:Su@e| M%U_M@uqTc;.SC1Ue'viqG' AEצ_呧_ mWgpLgP@>tAd _}?ȐouhlwϖTҴ{2_ \t ZUQjQû6z'ù2*B2#D"sY Z[Z3D,&߀X@Q:wrC !.y$iLOܭSv-AccZ eHnJ ZODc *7ɷ0cTϮaq(J0}0 8-l=,(H2Ϭ7(]t[8[Y쇊[p_N (MwYX9)gUXe  ]hL8a׹0(f]Y KꁡTyQxeojQg¹!jyG&֒A#M۸)1m=wA3 q}uŒXG~+_/DUw/gۋmhA¨_y\C]/) #R+a]꺦im]_K}AZSܾ EFs-Ib`~7-iE\SsG5Џ-qg#"Ї$AӋo6 M\6ػ]ѱܘQ ZK"[gAhfQAT2cd a=u]Tz"1S~@go o:L%s܀=DT?+],< "GP|=Q'*"%IFyKIf{m.W.E#it8Lp|cH\K>;[>G^_[npHdYX9׸Y+xP7C]Vx v PH0$dI-& @ɋ*]o%t'˟M2;FjdPBOɢj=aWuaʘ87Hng0طQq+vR m$NFfS^ d%PN^ p|ܜmˤ&$3Hh+2>ds\)])jTML=|ᝊ&?.nbG.xo Zn3@H*z>d&wD *m}k}E 3H~i;+ ׀cvѻz⥥/ QE๵c@6rҫ bqx^H.p^: 0l$uy,@n5K 8L(X"3͢YsTg&~I>FZh|&TL(̣3^ZhRx{z3eVqIqHg=iTyN{zOo2pρ2 FbFh1cĆ]fN?;^ZaBf^ֶޡg):xYLGo3t%qyd ~N`X1̦hGt P&({| AtiiKA`oISrn_-"47>K=3Jo5'd"TS p35A?2)ANry_nOSlFG)|Fee/LvZEUt+j) 85i;."NqY$9τm Hʻ_!å qxݖc2ӂ!aѓWǠ:s6W^ iӎ޹8c¶ZC@m>ܥfR {c0ǃE fNZ0K'ȅ$/傖7I֊Ux'4&1Ж6M|>G#ͣel3ţr\lӺ9_+ޛẋu8@ K gy)4 CUa1qz6{i.vμMpiP=dGdrc1lVM1*B`찯{YWA,qk1$T⬡9vf [CPb&<Op@yqxTQusùu#>A?ZzTnyP7)I/oyEZMɀ]%|Eq?!3tvq!Uwi |1o^{J3DC*k1 Y+KaDGh8l du{ե\ *?<9 aQVGgqвKcz7`B[ Z}NhjMPMFʦN-r ɄB'x~AFSd9P-1Ă jWA#PA V28OR x.OoHu(Nc6beF4Tjtь!Uuȵ*@ȥgerFZ]{ Ij N/Y9[Zh܃ȓ}7;{ Pg{Pbjϣz%6!˛KNNГ}OE{弪膗MBmLkqf6ˆDP .掠G1 3{/ [&҃7}" }`\˥`+ 7MOC_۽1Uxx)m#s\ASzF(J!!nΐ_c2. F[z`8siPXufq.Ԋ δʴT3a2&p&d,*^(f}Q۴}E$Y~tlE'Y&]4Q5ɕXi~[|0ܣDHz4/MZkhsBTfm|{69Poqhcדfa w83kVW_QIªi氄"_I{ϭb+y\m|5P0חb3`٭4%,y|@Զ@:!G/89sLGM:?L#Œ{nۧ Y3; H Įd9#r]D8D?M([?.IPDL;|QuJ1 1ltPͧ\o].1Ά;'=] /[ͅ\^-  jƢ*J)wVx(lSt`Eփ.>*6,&&`gbN4>?}gWm+{l:W;,qc0Ndxq`lnr w]`>i YBX<;acr!(Ƌ:O #DZ6, iym,ЃAېw-N 6h$tT~B6L7]T@a~>NCw5Q_Iop4b\I+E̗LI({B2J$k7"]| 6#|u"OD\1x4[v`/_JfS&mmB|cQa0˫o+ps<2 k߽31ZoSkv^|mV<1$g=n iy?,(_% U"utR/M˦k%GG' (pRM;7+e+Y[62޹!) c\pyLp878/\ 3T:>`B ̟⹨>5X >n!6(Ǭr,Ę%=_}+~4i#9q $Ll+1U׷7̘U$љD^;<فKERgT`~M^2%AWѶ`d!!|݃> WuFqͻ 4d%0!w^&2hz[3Ƌ2(#)[_0o|@iFiJDH)lڄ(W_|镹eFQ v7G{zU-R)}˽쯬rhirmMZ2y魠t͒ef7N9)IPH(Kc;~mO^eC5.$¸ܲšJǖ9K &;Z"4[,Jq! l[1XEqəsm0triE!RPv j:RA )xYDg$SY!j6{&%![Մ)Fx3^̇q %=Gͭr̋N7YF15j?;GY `"^qG@.A9pcr|AbZS %9?7F?8NX"㧸R3MIpG# ZxLsr<т⁧G?i Bjt;4m*w4G,h<%^)'#)j0;sX-ϸSNk(ȫn% ɭFR$It =3V ,E(ageW95c:Gv>Xv.mQc!=2 N E.C޻-Rd`eCx) ӦvT] [+ !E`Wxd( ]ф}kS6`ɗUgݤMR&*|*_r^ (}B%pAXRw5c1coP"p^|n7pܞfv ^dȏq M@‡:QREK|.qIe!=Ƈ1f2ŋA@yȕbs9)CtZC3-:J-JgfcB-w=Cƹu oo+_]8<BfV Q#?DG[rNhULJI-wC4󚭄 H> ۝Q6ă'䩄U;Z0+9w\s?imzXr(UM r`;NqqU*>骍o)KV[xpJܢaEj5LiJa ȿjՇ/q??5N(r4;Y=GFNl( !+1"zI"ق/Wg麙Y^ * . Mm }( mV邟8H:ÿ Lyl{uyAKݵf-kG, ?98ɒ#//FRRJ fM%\mԋ$vZ33LssN.œ:84X"DPM:Ȋ%gKpZ@qɰ?3.w3 s " `]:NZQgEcbt< rU%O'W<4z_~$+ƹúp&Y F}ދg-k>a ΄RB\zl_ *0\OV_WUMI *8."|lj>D0k^k /SC F X]i OQXO2{*<^zPrLAXEht@xt,*̀<ӄ?\W[XwJbMvѫxcp{0p&DAIJ%GGjq׆X3(dHa3#@Q.n7D![yM,v/0p,S'OJŶ؝2~6cP6L(E[V|au3io16ߢgt9'", p94a^ \E 2ץQs]=ā 5)AD BlS-X3d,r,^0:ιqJ\ 3\iͧs;xT"fskTkw!O Yٜس=O\!_ K\:Z!d_ 6eAA}7Sclݣ)ﶗa1LRPlzBP"a9[=)Q"4ܥtk M Ҧ#fB\6B4v \-gQ`?ps^CA&)a(#e&ei&ly̹^^m+KA凑tdnQRQц_ޘ*A)0"(Q\e)t[x!ZFsQ5,~9HvCdK51?,qF'8 Ҥ*=\ЕsG3: ՗a6ن%O ,bxė u]#,/~bKt3jX*}jq_ *U6 q%[B$__ qdž9 "'6<3ʡ&a $<#U܍:{u`m, #}w~p4bAX7r:uBvQ0qM,iƘAydᰯ4Pds%Zn_i{ڪ 38UbBa$PQ$@%-D,̫SFͼyЭvipImFBCOhf#?#>V-]eͫE6 GEx=bl4)mqEݳA+V`PP:Zʍ꧅s/X¯tPub7Y%F9ߝ#ag970*6Bi@ߵhDRmkef6ᣃ%ajޔDt62#kƫRiήؽ +7Z>֦P}I194v4K0:7>#U b_ad7dZ-!dt =)4jN,`DSh7I" ,c'B/URRL|a3_h (z(gu.Q(#Td A;79T)LfewCI)<俨DPE O"c)A`;Mt7=ki}:͑ll1%+0Qr/[LY5 bf\rj%q w|yL7\ .!JS]S`Z=6wNTe84c ;TV/ M <,jY[F)U{E|ߙO)˜Vaký`0AsEq{| PC1؆U>WI$T%8e|<|\pd4Vgv ABҾNp4O:aJ]g|Bs_}j}je`6Pi14F*dI[7~Rھ1xg7X:܁(2iD-en03}C]{Mifg #[kdFwwPL1%w,,@JKo Xi*OL"{"yAxQ_F}#A˶\LJ sCpwEm0g[&-*푒7a v ~I"^ $[T9tM`|) JtRW{l;nzV(K@:vo`d `wVQ,lhP`m5mE)=dסf;~t{M9|O{@p.|HBӟL,L5 <ߊ>35iPy|u~Z'ȶlS,Ԓ_52ej_YsYeLbaeˣQQH(6l;ww r0ET)=LFMg -Q#S;䒋jOYv=#tݲ6ǫ4\|}fkn+~t#?GA_(׿Zȃrp]/0$]:N6!^Qu8X ZI<[mLuvdo&*7 Wik<7gaFkmY8HEl%a O%a|(t>皹nsD، ΣBKkͳK9Ɯ^= i喎ItDN)C{AUzOl4=o$Us+[C5ni Ni͍ӷiF1xtrW0`22#56A6wߗ [zJr)xAj0of9(x\8k+ȉu}$-1@8"<>*9_Lr#B4"[E ,R0#Eh&x1)}P|wϩ@imXg |[av*m8y/ *h2,-M.橜EO- VYsEl{DڢUtIcyf m{dYLι[.{Ss4OQ,r}/5 1W˹:0g%d]GO|l/nE@=ⴑ QI*ڌYc/ [,@ eƑ[EAvhȷ״y.M͓Gc2gGB6^F̹ڧ'%%Q($Y #̤3 mZ|eWiMget@=_80 VPdN kz$A? .7e)a&kUܝ!tw8OVHㆡ;=]N*Zyz!HU= Ŀh2cpXWCh%⭀wEQ{\yHlg IHA2Ak{f('I`K&!Q^DZoKM)@.,n㧐=Qb\F*d5dZ_ʇŚty3dN3-j [R+roc%1gBb6O9쿟PYqm.Zɧ#׾a[#-e/6)} `ÿsWo&Bq*ئ5Tj[:.፰p$fL]`KX^vO+0-1XbW`!$(#= A'GU4v6}.FU";` aGg,8X7amڭ,8e3i'[:rlC!*h^x m !iǺmGSFN-;4a8Ysek|\Ix݋֌+&kѻUc>\?\G}4yZ wXCjn *yT n uƻFakZ@šսi9ZW1 qࢠ kuOߪv$~Hc1Xk3X- rYfXps.V 8sIƨuh_r~x?5%-זoiLd֪ؔ{`BGǰG&ZaJ0 [:V ,5 㘿Ƃ@eIǙf2$%nopXrud`dUOqja/RՍ}8;y٥IIof^s/LB1o` kdDPJ?tY30p%i>וrK[bn8)Bv{ C3v&Zjړ-ŷ!1$Kk-!pI\Q^+ DQ56F[ *zۺsMp Y3"'maT:#xg7p/ClE b1ϥD;?ܡ^T2Y1-J"љ0^`uO(^Y"[o.ȏ`>s"Yc+oٳW53vGh` k+=JEICe kepi:NNqqW[ 8=r vxсX AfxH 긖c:y QNo*u_}(sP 4bǶP⡆*i<8vm׏BWfV/$X#kbAIs. 1UINe%[dm*їݦ1EV3gJVXbvufLַ|sGW_?+|R/Ndޱ-G[D?g۞p|yK0gjaa)AT 7=hÙB4 vgtl+^m7z\tvcۉJZis֒QCs*K?YywB4Ub~~?tl#p1MPM \9:",6[CКQ4¶134iƗ]\[9x3qV=gśI04M$bXn@mOv8Z)xZM0<وz vRc6AfA6Io 6ڛW.?{d[T UY2byt"(d3ʨB5H3c] -dkXEWO# O*izB"8Yyԯ'*N-IjZ`W);G=cH SS¥P`o HB31&/9mzl2 G0LCEF):FR_Ԙ9#gecz\hYز̜>3G@]2D][Q _JIZZeG3${/ wQ5+W>+ku7 63TKp^/s-DaM n5'!klqa1=|QÒ 0n s&vl)Y48yW/,T6pi ~C~3mArnv^`mOwr3#t[a?XaA @hdU]ԕ4G2Ju^ |G:o654gwt06R~82s%98 gW1nE&k{i}UY үY*&Wz92tk:]4E{iX܅>ѓn\:MW"i&ymZ]iZ-n( vFn€`"K,U߽y<-~ I",^|κ4sN5GSzFS=j r4:ZX\@+b Zv#l)+a.)&D\\(7^?FhM ʈDxITx zDȀ NzHT4ȎykD"E?8$:{ d+w;3bR{ΒfA$?L\"aQ4%Y炓B(Z>ђ=M[R W{8Ѭ,vz 4$\Ifnz$ c@ɛ\Ɇ:(l1jY`MJBGGd\0 N"SA - Wx-8]Akq[e }P VJ<)cCkݓ7Jo~ 5eyL ȋ 8F4CbX7MIb.R?( (옿ad%]dy&e0.`mvs>DY"Ud%0XeRap4Z_0oX7'4d7+4jIbQBWቖaUMT]A9/εLҪ<%ZZ-\g0(4@IxΫ!:HW'[ZzL?cDQZ!#ć({H)N?0z7/: B\~fSCJ6cl=Heujv1+£!rh0oVߏ c,Ĉ9ðC|P$$>]^y䵳|NT>3,>AZdmN<*vfᡆ|M:݄J=i⬑2wg? tx WUQfnF BiV߯Eϩ]CSo։Lܵ*~]i49rR 28hB]Le^?Vug%P *XVΑ|ࠡ:ޔ r%Hg6ueVSIҚd ]01`c(DtϪ ݣ~#o_ng 9j+Sl}v!;?Vu]!t_텧Шؗ bY~)<}{AGOVU,}F%4Ҍ>%ﯲU[޽|UPmMmc =?iWS ]e@sk 4=\JUj+mRDky(y~"+F(ɢuW; 5=( <,A<yϷ?]aeF]!ܻ^%ɘ7^zl/:\Ö7em@fM3χM9On/x1٫nvI9Pmӑ;>*+GʃsekG.DQ*;n>g|ev6'B]'_Ҧ nێ _y&rNu`W6k"*~: 4lTNT뽙`ZƝj?u/'C+=:$1DPU7VĆ+wޤ!ƨ݋⌃u/hHpL=/ş9CeiKa(3uĢ&#ݾfE8/8>LXḐ1 x&r%!zG DjW-w H+4x "I@\޷]|~ }3hΥF *NEWQ}ڴmitF@ RvN',E6}&j?Ƹ9.';^udm (.76 nh+;̷=Nw-9UaۂYWhHʉXngw#vPr8Fd_uoqSVN9 Rh|2ۼ5XIؐ- c֗K}=7oC,0NT[Аˡ.|h"}/}ν8 W;h~q>h ή,UСn$Nmq/oz9Z$i#U/RC8i#"MՊ`yڵp|mCS@ttż rEOՑ!)f {sSI\| v)nP=o=GhbIZ^ҖqD,{(Kn ʻЙ26~ARY[:S4jus+0 m=ڬ5t7; )f~9f"ŋ=/\ٽWα3Ii7)'ʛx=5=Εh$HCgK_:B2NI#5}49yߥIjibՅ M",1`'d4S1VJ_cՅm"cf~Kpg񖾣S&/O\îX~VWt*ȋ>ToӶ3mŤZВ"vM(_2PmW{Faq$cq<ȱJڗMNPvOetç?G'6=c_ 3E(D uJ㗙Қ(^2^򒓨ZœdIoOŜ 9k-V2340k|澨Т#!\3_[I8< L9#IrRߩ))!;uYl ~a/͹E2EɩB&ִ?lRklCKmR@W `_^Zy1P<~Ķ%ׂp,Uq P Jt] ]Rw?>Alc E0{8^ƒ`=N|I}dDa @'=Ex-pRr/ƴM@ڏd8[,n8=)Ouû[$Viaoe{=3%~Z@fQds-Cvr*Bu>  uKHŴB04N/O.DobCʖe !_8sr/`, $]. .R7Ĵ ThorlYk 8sY6{rT LۑDjATغ ^v8%}*Z2tF+N ۸'k E`bl(2qտ80+sb%ƢU;=:ޱ`!GƛDP"2&eTr@o*Јi𷥠յ5]5gp<4BZ¡fL=Pdo O3H. ?6%>5Fcwꊓs|eT> W &e"B{& b7M'*پt rYP[> i&###} nJ añ.v@oZ?ʄFTKQOyjm~ŌMg6QyW:@ρxaė0ymx-0ԶL3ZPjkhTW-u[ /Ӽ4(%W 2y eTG`npUA vQn(@Bt@CheTJ*p@SC1In_cv7172`|Ѫ0M?(6ekl LZ*m雛wdR_xomfҬ!;zbӕ+8Rm4Mb̯E5r'ɑRpW~Flx.<癁2(5뾑KZI5 IK{Ŝ*:l:m I_B9w-Zbw;>"}GcWrAaYJP3=On10/wS<~|UEtHK$.N:}]3 WiѹSh9ku|E:Un&05 |D|z)o\]w~{^h'cp+!͹])e.,iGn5J s I{Gk)ƀ̐ٸDhrYd6'wgVEFOXA3BcYj$S,I`o.[;BA ȾkhwEZ=S5eIfu,bσh[yBjrƬ9ndLSɗ/fQ8M\afjʹ2΍4/V8-եXO(M{CƵ_%[`{Q%啒{ČhiSe==49["wNIZ% `z qI2`^Kl:D҅OccӃ't)'̢H˶tpcgzYqQ]::5,O ;턷BlpSIhΥYOR4hA5e')!'?S,-E <'}Hge6韏M֩(;Ց^̠%\תx~nܥHжut'T{@կ=\P \Qꣁt󰩮^=/C=S'sΏŭ$v#<&N%V=*63P;7X'ߞ5tZq ' JpƸ͸435zt-uʪdh$CklIqg !Wf0V #W) dBJr7rk`i]WVkQh{vL3ԁ8KdVl M%.(ov (W00B#e)ϡ H?9ZpẎ}* w羓I7`_6_чP:1—0 & y .<'?z}bitQBvr L(l[ _+JtGM)w6т%s䦱Y 6VIJ?PV`l-Ca!,#zGp+D|,"˕] ,P zk 􃼷C郑ʨܴf&YtFAv3yE8h` bVzWƘW҄[vF)ÔcJ$uuy>gPid*,^Q[!꫷~]<7#p0ElPzlU="FA XR43y|\g5q7Ʃ5*:j; >y!7!*\b( e!$C*X\$).]ae0acF źR@l#FA䮼ؗPl( ~9[G ę#1vQHs1x.1D 9)DjȢ"JA!sNr>5Qն^p9+EF7Ux!&f],9͠qZ.:G}aO3 :kaٗ;cʟMFJD-Ho ,;"ysĒD)M)- J[2wu?ֲ\ J [ xvE&s_ iދ:ׁ+*dVqL $<$4TC6iߨƛIgX@GԢ2EyBj:j^I'YfRZ.p#*n|^x5{kjl6ml8JbeOxHnXڀ9 pwEfZ;w-2GYGd4n7WE6d+Tnx3# dN$86#Y;fk%X=T`k!Ϲof G$?\3):DiPmzX.L"!d|[ )hֲ#ѝ Aj؎F9yo/>]cy閡Zt]b[t0ڏE"P-5$1ͧIDVș`K #->_I,UT[pO@ؖv[q>lPYvr2 vQg\7nŵg}F~ʬ3l$cu;Xs.q6Ҵd8t͙{46QvD!|Q7I)vs V x w^\ֵnGJmaLˆzT}% JIޚ^cq/D;Փ.`,(6~/ Nj{D*F7yW8z>tޟabFo- RB[ʣ)Jklt.]uzxWkК %yjĕ_ !Fނ>1k|#8_Ҳwi$sUt8D.nGtC8Y9t/`q_n)D:<"Wj7Gi@ruQ7g<$Ƕe 6_`lkTcʺ7l ) 0^52QأuQ4(^f ?D ul\SX ZA>Y:č,h5D$m k>$re\H̍jGPmYz􀳿kO.ipQD8P{8(_-V|h%{GD\s& $'{yɋi^2H/, \Y|{h#lBJCi^e?L靳E {l[4,g4ϕL칆>r $C⾻}l]VWͩ5o-WD Zp(|3ޔ22ym(DTd~#75addA>X߲$k[/*X QcPԌKlLSF%4]ГFќօ˥x&{Pl!, $|NG6A8XV:8MVu/]k.{_gQtD.~>[YXgzF4+R L "{H8޵\j'dF6 Ry9Z {`1L,ܱ@E3/u5wxqKxoa:ùWEdž\:BL#[GJiЂEߪq;Hkx᡺SX 'ķl#(XP՞M>w')dW(ӕ_FBmҍ{(~5%S6 P`F`'5'@d$Sj)\FwsLj8OL;̓$NܟK̢aF}4j[ܼEU:zaU4u/72r%-3]|߁Ij KT}-V+Ұ? ='"~ከafw{fӁ_s8NXeDȿa[<ZZ4C4o#ʃ1Q*UR%; R˞p}]EUTr~VG>y:.{a 6*A( xU4/ Dfs;o:Dz3 1pގ ˌlg1Ӿ`O2[nqP~9?eKZ omHVcKv7>l,1T y7nG+ $mFbE< dVUi4yMj4x|ΊW1NAݨk/Q@P[WMVLaX-{FKU=_ k@qKfSכ_tF6kmϨm7u"hapH |/16y_K:&_噞zbE!]?4C=j-?RԹRyNqXt7-XmrN-K9wDv KnmJA^&r%qbwu̜ԇ֗D䩣60y{%I- ZN 3D8^H\#s,:A@Q0tlvHG*P- Έwlbs^qsz/VA/S#K ^? VcIo\[{v/jisjo Bꓩ#V4qL }@VD^q ><.fl1;Q n\2^]MTՀpqD_mR`6jءe4QQЛcx2Ԉt!1=F+1#[6` `v$gLM}^:ƊDw QlvlMYYS@7T lX\UNъ]8rQjV;E=>uAq t 1^u+V̮&1ϣrb˷9m40@8Hβ{U?Z\3>/2nkeN^&}l/no -5mByj [xkT~ BcMl`H0f#6PPo{^LeN8Wl6OrIdDEDnũ/.(Zu9Ѵs<;QȍDTڑp3@#;WQ [f2-I۸=1#>(R+km"U=#\g]Cpdzwf4亇)%>,G#.?I~~JV㸥3|0s|r_M@vf ~M $4Ʒ{bDy.Ƒ (ߢdtykJьʹ*v:|2\Q޲kH/BQMYڕ"R玊x $~0!Umz["*3;Ԫ۹zwKNrشYϙj/!Oe40zۇݕ6#v\b@jY4(վ=kRd޴NOI yɪljV fdaʓ3TDY@JR9}Wkvq:Sq~Kf]K6{& Z F!SK?As]62o^0Z|[P~4* HlH `uخo#w3ԺeCt-j}2JGW,: _ڎkmgM`hKtyAOM6BuliI4L?wJ&Ɂ/.TuiV5(id R%EnOi5ЊkiЋKЋUZJ 3֭lYؼfCWN@}b)Hu 3Pe1NCmACjB]*>wqb?{6lJۏ#0E/2`b'M^iE>{wnwJ>1$',: ^J3ZI,'BF$ګ-cW[HdtWZt'<.~@`\sHLcJ \eK T}݋ƎTPk MGjbTlĒ*2,@6%twz:^ %KXDـ9OmlmDMc =cNbu=6éڦR@r^63J;}x?T".:rN`q$A:­.^<@K]jMbWCgCt;)&y~Tļ=ޭ嵤Ɂ)ObnlFUc2Z6֒+z@%^o]ȸL@X)Y?mA/w]::-DøհNwB nL{p7^1J'BX+!p*xE|h7?-"u1pP#-gpwX}(_sf ̯$r#ثg# a=ܚاr}KPS#5\7٪!R]1W6/ R*XR!,w[L$σ:ZF\e.!VnqHJ;K h-tkˈ|pTn7w%@?@@7$xrC;ܣV]DW9bk>V8{R#eOcP mM.yy&Pj ;a|x  ]S@hm6́I5#3VQ8Zڟ%|[ͯf7Bn0Y6)n4Unc RtX)v1b!Fw*OīBÕw"Аd3.VB.2[{`r#:\c7Bo[~ulCZ (Dd]lq<ұ a~֩P|-9 xC''Ȕ_ z[SEf೔jD"d1n08r"4 å:3O,ncG㌼ׄ6?RT]T^yԼZ8fvKW4̞SKHD5m^vdʔ@}zt7&錄%& 5s{Ck, ڐRWZn$Q,x]/y7 豾{=uuIeKOď>]̐B_xI.Y[]Q+,7#o ?7?b(*;4E*-:{fkQԔ>:GrE3>)'sc{\>bE@97KMI{G,̈́IJKK&,6 p`M^IRX[h!=:k0֤Ø0QZk&ğ-fq_&(ƪecY C"C {9>n kGVsn)`.W:*M:K>| Sf::ȹ~< _~ 1 BJDBU^d%j MwR!h\~}ERp-So|讼Driؕj7+ *8\dp; Mr"+M3ޏqUG;<SDo(8- +_ @@%D/WY*,,].`mUm|%u(sC ˃[gy~yPZ.P8 Of zzfJ7qgƬcc9g{eLx>H9"RTdaK{|{ HJPy/o9N|hbXړj9+%wz 2ϋ,]LVKSh$~uh8>7)H;kvQV8.Xe`2Zv2;#wqbG5DJOvxB@ ^au4 E40֟YvbZMq@æGmeZ40-0V7ן{̊XZ(ehíȜv&D cFBbHy7jJڦƔ,Ira6,)bgUo`J YE`f;%kn'|SOnGMNC ~N! I}l,->O|iQ~v7CG'NszT k09- 1*`cŝVO"-sߚ^zH݌y%Mj.gZI4Du,P6,MTAhzzNi${宔L-r;tÕK5V/se3ג A+ |ez볒Vzl ʡX" MY4>DZMK\}6[fVYZn]7Yӏy+`Q]4)$NKk]2I ayX(5AF f`LZ e= [e-PQD_Fn]t0,×jO+kw\;D3 ˻%1b"ʅ%ߵAϱ.߽[퐜C[@noH+YҾw*e~JJm<ѭ1-L++zL=~d DѝB2 4PÑUU.oϞz"\j*j`= F3 Wid(An|5L؀fnmI^'HmB?D:p)71ջu ߴ)W3^x$ ޢe.nGaa?4{D[`ˬ6c@|y??- C]k9$VXڹ'}ee t۶XoS6Xw8u|X&nHp#@ےg7 qEh`Ir\ @Җt -p஑VYLBM?S7{+TR3"/rq}lV]Z'1". )UI֡tl1*hfP f`b.6 |>}-١_*邸S]Be꨽P%2,&+UI0JE{R]?pi<_2cqfDw5\umך JTuq|uZ5xx2@]8n'qEZN"֯H=Ɠ! PfAB }j}@1= s<2`cKy6M@OqfdH5x %)e-Re*l3&O߳iU p&i7xE D6j*(ch $ţM^h?F}]de_TSe[YPf u CF0@d+[qpu9)$xzj D D﬘PFYҔ| .vY v&='d5쾛ć\A|a!|08i1wTJ2O%lkW)g$͓HK]."987M73;-nؓuY@aI3O³$WDd eSvЬȭ1Pp/MJx؈4XZ5=-4yu\@eVV4ɷAM5Ǣȼm ؎̟hxPu_{Qb[<1Qy4~?q|^q3i+jz|hfQ26 ~$JCU(|>}^i=foxn$W#9\Tza7=2 IO"]Q4]-,6$ΝNA`%C}ZOgeQD0)U{QCwS!Z)Z p~eAA7i*#&E!NZ} K3N>: ѯsq8gځT jY$W(tJm=[oi\&bO(i-Fv }#Y  ʃ!gjJT-q4M PQ%Q f@5fmFj\뤇/~ZwP@EXUxڏc;Ԛr - yzA9GpIY~ayA +Op>'?8;f|]!W;iMWktN_D4p$V\$eY] \zz%.MK,_ԒRVl~ QZKGUڅf'{fY8᫖K[t^*,|D"XޮT^R]:`Vt&nm}?nB^L+?Y!+NGs;7iˉ*=r*gu+F\縻/tl Ҭ:ڎd/2 t؜['_mn!!v$)ɓ##̊W1*/}v+UfIT*"AEBMNM{}Ct_wЈ&Z^2f%qD2:ٝ9I@z<2pN|Z _=4:,jI  U .YEBҾSo yZ_|%䬇#d@'9 !^:셡b~Ϥn ћ'}"ͺ=SxSm,cFeTW|x"•} "ЪRuH{ZjdS#YH] ײMUDkųUQCkP hl1jx|Ie$;=/`yH %?t2F-I6hTT0|{W:J S )3`]UՌ(gI9/H(a00v 4 &\}/K= Jm0ʇps_9H ܹWwE:!#tގ$ 笩.Fvdtbp2\B!brx~Ǽ։NK'CQ\DZvpw&<%ZHqM6uj=, hpA%)+ufO|6o |zmJUg5]W"٢b?BuVrۓՠ93 Vi`CS!:A^^ZcOgl#vc!^)t8)ktSkΠB}WAP YḦZDjE4L4jdmT.}|6AGeYhut:nS:85e"O*#"NC@F ;{$sԝ,Eo(vZN60I7T &6"=[ ݔ ׄiRT%δL" dzgr|Gn.0!`;%@bUG<;˗.5YEr)겏hoSN p1fx}8~ ZXʃ//˫r.*BM"܋p'rܭy6&׼ JppFxX&-P8|ry5\*q']7^ (~6Gͭ;{'l B(l]ٚ指uOOuGM 6uD_=6~8.g };80_;(V1^JEI# !Ʃʜ̦Մy!M^9uu-;=a>奄,Re\b'iRycJf1]hr H-B}יBاCyH鉮Cu>}LI< O;CUR~2$:5aZ3z1}n@2%mj*H x-乒`^|`K) ]HI*x>>1 ց/ۨy|ukE7ب鐐=bpv pt" u $׼p;CߩA1Q=J -Z-!,x5h JH裭EL0T\- `u$ usѷYYf$6!!;`kĊ0{FHOË[Q,e~?UʛPۙsh/JE,2WLiozhQ2$ߎ0Q{ukܪzL|p'-%`;\2bʿ\iS5e="2{læMFj&+%FfxG-&Luc!cBn,j${?E#ôC!;MIz?`qh]P]EUIv-΄!+AI-D8& :4|m'M2F7w5WɮX:-elNW`XKۅ'4!:HmZ 1ոjbOB|W_/91'#1F,i KD3r~ۋKk|xqv}cf6M\?A3b k'X,RDhdPgK$!c_%f_5w,ѠPۚdpHfI!e/ rthB8\3=R;޹j#B-|m jP` iRL1A25䥿aR2<ƣU>&Xsp]3@Y(#)?  -ca/ (M<1R/_ 'O41 M{q~ai5n6tL}ue/[}}pEl2/@flzVD>р**Dqto;%-u%eܤ!zaJJ6pH#p>˪_ uH(=-G5ﮩaY'5Iƣr%yw #g!X6sC[17xCHQoN6WvnLfvr:k͢/rD펛t o>P8.(ZET`R)T-?&2'q\b~8UJq2' |G6hK(XRڟtSj ԵM#=ym)D?)^zZoYH.9NIv:XwR1gim~qKkj9Z [/hM|.=3>.bLv&8YHBDX\W^mYѹ5bF jOc9rdo+wHl ٍ%|%R;NK4WF];>H3kr~w"mx&dc,BaEzމ'2!r0V cy}!ÛMzIRR{GALvޙ@p"sёWt{_9pL^X9@C |%Y*Vqw `/lz;@0!YrJ.CRe9z'lJZX9Ys˖^Uâ~-+@bَ"R!~:3!FѣZn7Q^ro{'~l3k+S(㯕wB#١`γN~xQ cD;n1CK rۆ)OR对..Z2$[n*TY7y2&kN@==Hs@3"Pm"M]2ev$ҟ]W$(ϛm|#ʰ4,{suܴĠ~U]ϳߒQH @:dOb $w wh4%b]3D#Y'4Ξ X~B,HN A'pC2.jtCj19[T^n="EDA{OO$KDgARI3ՒZvR湶F"D@* oϷ~ڕ#gR'ع?"uzo)DBuƝh'ao5-G0^J_ऀsL̄&{-6wgML!ŭj!VpD] Y v4EntBv'Y;C@bypX/`8# Lr-"Av|jnLA\toҔ n»o06W:47[M`5V,wYRMBj>H(OK -k%Ӧѻ&.ѻWX#C{CքkAAqN9앛|Z쫯d6( [bUJP(f}W XKi#?5A#o&(MkfۗR[# yr. ?k? d~Rq:""%93<>8d0k wIpԵj#k~d=ÍṙBK5<ҟU4Y:ݡB7A\" 4!OۄU͑i O#tuvQP`<MhS")BQљce)K BJFmtTy4Ab`DWԌkdP'{XhKE vyG*]E? `]VrsSl^ONdwH[[_U;|ז#@m쮓pa>wg1ٮz%%-eԎ[&wp OewiTD7gl%/:׌,O N9 R3{I:+,*w,(iNOޫT䝞\Ǖ#M?Bܫ% O$Pe/4, dʓKA- nW׉2xvPJ&K(Q[D(/DrӊyI3;9Bm$DG;nG۬/lMms1 wYGjACCFY2Nx_mo= wh~y lBQ~⸽PLkJBg$jg$ܒ;>oN%O {X/gC&h%dI~oc WQW\|ݪ5.aӱvNOǮٴZmzoR{e3%"$2krpѩeӰ #|rԭj5SpϾ7܂Zh!qNv\;|N2!r ٟ'%#_$4VfOTw/~ B)5XxH-G[2LGЊVH׸]ě$)TtW~LqUu֬jN Oڕ (xY̺"ĉj%J9w.@j2R tLBc~+!Mfcu BkMxN&0=>v * .aY_g ؿÇ|gRjxx$oh [hD?# R!lvK7:yKq*,*Тf+ġruטJ8ή-BRYe ~bxtw3)L"^dET4ڮ?4 A/a<,QieTd{̾rY @P:kp?|<e!AXYAXϛQK\@>=b$ENpdoW.Γ5 nĹ/-"7UqƄM(57,{nCvuc:v ,uܱ8a:ª>B`o4YߑўY\4zf^IJ|}` ;(Vsfm4{vEn>^&&1b 2&y[%ƶ$*7(Q=p8(2Y#$79<{5*߅&^Z-E/ a^řWab+Nzude7qI-/dT;O Iz@E&u:b2g^xcn{Ll6vǬy킷-y<0ƹc`DK>HtAN6MɁIt%W!2HrS~WC?l|v2bTA3TIё_' $q46=)~A@Mz(,dDxۯ3IΧLЋA = 5[9WCH~@{u; Ze^z"3T& \BMa2OߌC+gـBu_Niü˧n^(A!LgTL yLI 텗\`i唯9Ϻ{d,_|St(=z)I+9k\az92üBTF+EZ|tKPځ9ACaq7|߇rI:S J@S(FrP0-c[,&RoNN<70GN4JJ\l"܁6ŵ?chN!̩씦ߊ6Ryp|g{3ӭoBC *6Ov@'ڪ) : >뜓e~{ƏVT?%5:ĭO.6p3x}lvcHM@XITnoI0*@<$5RM?ggJaз3E=8F=L0bR))φ^dg }t/7`0ȕ_ _и crxb@N- ~E;tu›Hc*tW5K(^2K>uAQ5/0s =*oDp~/|K3Y/kR2O0 Uq1.U[-4M׿-rop3%=g-!|tO~=<.QG-uW6E H[I-N IRSU֐'hO3WYKn&!2 `s=+kbDMwbK^ 3䓟\l!qz 悼vtdM|ViڤӦlϬYRbĚD ƛZ ;*,`N+"5(|9βS$V E틀!H;l87g)@O0| ϣc Dz-G*3k?={AzU4\rm>ᩅ%X3/сOuZv;Gq8:o2!̊^ RKtR ۰vhd]'8Ҵlrs_F. Eiiw"Ӂ adBVD<0ȋ%| \#ݲN=>и{a 8gRNgdjTx` ՋسclSJ~f ʡLvFf6`ZPQmS{B/sBٺ%+K <qD :p#",ӎ&.j:9()WQcw>[HĘGV3W%gTA\]ɻ:*(mfPqR)ؔڒ2Oأ~IL+)dXԤwv|(닠Ǡ5'X6jH=B (mM:m'DH1|HzI Nc w)\:=i"..1SިpAۀJP$7O u$Ai:˺6S;>E؜s<cTykj6ŨcGqAb7No=t"M_̤[pF}HJl)ֲH=r2ɖ:| dR8 w.D_̑U)½^Es,4@KOAV^JR/7iUjfD04a)\_t\ȟE^ -ڐt8 OfK} +DxW0L$u%jq⫒Q`U--2 b*ʬ{ *+(}ow}_ Sy) @ou0#)=h`7%%o5H4G˝$0-QU$Fejh[LO `OXM>A_!/ta]ʧʚNKJE{'19.3u?¾5΢8YPjgr!]2 /zh^ҷ^APK'mΙ+ ZvbN%$O`†M7r_EDJh{ӝj4WC}% fsf|  M{ wv\6dYi_m\CǂT(Gvpe"|;Τ9 H0EwW2B9D Z{Y/Dt]25?DLe}EWu]80&1CEoo̧Y1fqc_i\+?y`'Ԙ _|2:sNZ(Z"ՉDKzYl+BIh$6|\ tƤzl,d1 o9W(q*ܧwP5$ )Чʐ"p߿ m$e{˰<5m ;04Z("j/B?iJSĎ77v)#~֜|73xZ'aoŲ߁k(MMoJ??^A?fJ7L}Z?*Z(\P>|ȚA}#1^6hf WZ5D$`La..Nz6,M%`)b]ɴ/EnBdg xr=֝{ˉ8__tn!Cڋ xr@OaFplgzLVc~m#D>vk w#ӛD64'ݺE?Ȧ" 9lp)FHbs9A$(FϲxSNY1a'6 %C= x0XgCQۺS soNP|ڜRV1ߴzE=ujޡEĻ~_+%(vYw3p着`$4{〴U@C4lGU7@.fh8|͞WGWZs%F#8-07 "2Z<)=.U:nuaE3a,~uNpn <H@cy/m۷7;$r{>ǎG?7+2 ^ wL b܈UE('ԛ&dP$ i㗯',Vem 16F[ӑLX߅'rNd3HtA]|&23}zBenîX#FCPSvi/<ۃsn#SR~; EYǃ) wꙦePwg7NF4*T| O!&MԔIޥ{4ш) >ܕK Rϴ2Ÿc$PQrckF;ժvΎ;ƤҎ8ev{\Ati?iՅbho[z26=Ϸ}$xd5 $c塽Q@ÏYbxڳTFP*gNxݕ6)~FkMΏyHWV;|( 6*NIzU؟-ʰfP(*̖^Xf3/TtdK1ܞwuTGN|Z%^ ^-sŚˠ FMZHmB(fͣ0uT7<Q5t57"C&@bm֓44D #(2$Ի&"JD$"|H_|zRRԖ#VJNWP-<*fvlXL1ZW<"hfp0( "q4âf:X7 mj&HgNaҩ`2{&EhUTY!~PuhFCuPB 8i^o֙|u!K~ುP"{umty48C\DKӓep>ms2% z~Ve U,7s![8'F@zMvxOSDh &V2c;\l|B y0΍T`,;8薅7 Omy*/ >*;0%;/9A 2xf%w9aWN.SŔN9TMp^JEh(OWA17F..>H#{HkJDf9ŵj9b`A!2S@i 8Tn)ҬY"2ƑH v7*q[4-.ERfc"Z*Ɯ)%e/qA'}bhqg}icv:y,Gמ]n3%8=e!7 (l"wɯa=[B^>n'hg|LzO_Oaf+A wDm!`Rz(Au`\P`M~̫>{my%xNA?clD4mVcB IzHﳜ6'o'FCTpYa٘ݾٲFz]}7=:?@F^CRule4pϭ#FTK%AEɀ&ze:lN=`HN,OE:oOi9/!y4:F/FM̙ u5P#ħieq~I6DIuƖ) EީnyNBiڻQ1Z#C85ȣ45U9̚V:A(IaqEbp \˨JLfbʼfĩ"9 !ٻl^qԡp.O';+aa+z1OT~;wǂ [K@Ωsi$0`#l' 踱h\ %R7Xܦ&]Mp ɝMhc) I‚K1'Zvk0JCC].005|:bڻ,7F xyo$c.5#`3u[M^:bgU!VŤCO@u[cW.ٺu(=3\_l9wͧ 6}[|`ykf}8 XBg%J2":2JoEIo):I46% _ʤ" ZSXh@e9z+Ŋ+Hi"p, pFNějMjRi'`76#8Bz 9ɺ4P9CTp di#JJzNSk)02%4<^6QE(<˴]4Me$%V#t4 s=LQrYAQ'o=iˈ:*f`v-_;=q,[DBĵD ,Bʻ,_X*SxtD Km!dghLCr:V>8iSu\&{ b*U JE}Z! !7q-"3mbYf/}ږ .zJiig4/寕Zw13c4jz:=ˤ:`9Љ9 TkSl"'ta!BYxgQT?ͩn2=?hF~V  a4֬vu̚p7d/Á4r$寢:epNoX7Ku^М#/S|y=c!{h{BsWS㲱"HBGR`T+n X3A+Jz%+~׌db-jK#Z8Lُmmcdn'sNCJ _:b71o6{gd)螧t)XH4~$o)-ZE8"F} 8]9o S "9$A+ Wmtm<3 DYE0{]Ț 10#+2W7e |Dї-h,sJa=D6)V' _1Id^M?ax̸l']F B|Cw[Jd{NYR3$y0P1K}OtϾ#DMp#y&Gl~2ǚ6Lп]]<,j4 8U=]yAnVF(5& ìK7vM,x( MaQjJʸƓ3&ٿNߎۊg Y{p2M y&ϑ{q"kM J9<+z񛽙Bnps9X*FI\q2r^B [SAj8+}V )C'&iL)E):=Z<t6?uIkޟT!=x*oaȒL[r{xׇoGU!.՗7ͣO僚0|-2Y{Mc;w 16ʚ  U_խI [up\wr)D Gy3e03\||al-C|<6(8_7oѹ6T_'i UR\w^-(LeSʽ@xhtqos5ԖMQSgо2|E{p 9Nd?1Ǹ @=lLFd@Q$"PE} +)hU)ݙO2p9~M>dT[Pg϶#<h0UיLZqik_֘L5px$Oi}9P"H/I[~$ui}j lj{)$ڌ|2`ēۦ ;f` :[HpkTک%mv; rP4 gcE|vg&?qs;ZUB3]4xSB%C@$AX~p0-8*6,Xᇗނo[„=YDVu>bK\|}۷ ~2숽9fX;KtZD/m3+.%LxkؒҴJ_6MIEf,Ćk*0ocaJU (1g6~=寲c믄/ fxYAKtqDm0 bTF{F*^ <&iT Ɔ[3[3VC&.v n!3W,{7h@`9eK5e5Z?d ޛong@b08afHpW Ms9b&Iu,f79|˜ 3Y/4l@%Joڧ9=w}NI=$IG.:ڭgG@-OG_Hkȵ..;\6p81Meg1)*@ܛJe}ٜiJQ0va2J%A/WؠEnRiXmۤEph2P&STWfV67sQll!ռ aVRb  ^Nk|ӕՂa;OKeE꧲UT VE+rqVN)}yZ7Keĉl6v'(KZP̆^v>[! an:`,.D "tqm1y;L/D0+NMIY(tIv#T[ػ|PCKD }tW\SN\ gm{(=ONʿ^|ϺWΨmNˆ^S[+1 gٮB9Zr|.K P_5z2)#6D+ 14z ,{H?ĚՈWpXު/!ޑ ̺2_k us~.;mɂ4~u;)i˜9ԥtૐݾʴI%vL8i!`BNuReKE`pns\&V{ZWjRG*]ƖmzFUbSqhx@~ܫF$Ś;D&+,l6MʸRWP D>u@"f'/I49(%o KX-SU&`o= !i80@Iڣ=sX )XC,#uAi>4R{kgvhhYq>Jjsy.ud[pd.9hdqȹb 7uD3"1=9ϗz2_9myDb1#&:ݟ0Dy{heX30BK a$)+P٣!u,RW\X!Tgg3j#!@Wcmf~zYFeK|AĔqA),iuDI1 gTRTdcyZmu-G($bVwoP L'';'J\@|c9D!Sa]<'M*Dh!6|O5,5ykJu/h 4ᅅo>TG`-CF;Ôa Z*J̴MS ;S|J] e$u8[j ;o\7R$~AIZ[&,iޘ?&Gb8l1@TI#(KgߏQ ; 9,V4=im=қcBn56\]5rfuQ\矸Qc{ϴn٘*{o%]|dIU!m7ik0n{ϵ~H cգ Ȳ67cFژ_FN?i`r7$T0zoAFWK⋽{ n{gE}◌rM5:tea$Bի_5q:H#5]NMb:&I%F;wBY(c^Qܪ8-zZj/0f:<ۤQ;WK5d[I%p5Q#h@bpdmd,u3 5Ŵ |Y~3jRzرIA,C~:Jhⷄ/M8"1a /3 f׌"hSͰp$Hd7$L! P.lQSQoґGg\!4є26D~PPB{yh2+ R# a2w2YJ%3N{O_o>wm +=5 9\53977ڥ9#S{hJ8j:+yà|7i``ˁ(ri7V!aB^r1pY)܄+G7晁؋dXvU"Aeԯ\d)c.>JXHmI ޅ>I߇׉yU%{{űB촯$> K ni'o~ _B2M( ) d-+ zSXN}n`] _־-zYm5{B|8ݚ5!O[۳_h-7߷SloY"YrNp/>qZfiX$W,FQ(;`rSE Bo)Z+{{zӅE0jlgPL,ĿF ZQ_}1kSޜoʨhPrF + " Z-i cڧ7X,G`uLYP+/Zz* ;)UOͽn﷏!$zõ4'0"ב wι )vv,a7W1H E[liAo$:Qlv2ԨF~%nFvr#cxԫ.Kl[)Hvhdp8g{UyC@fˬSgUVWДn2-*ءռ%+ꗂV{_q{ܛ h66~CF]o^b|NRXo#C͓Hl++bt"P *&# v Uav 7M& uR#oi}~,u"hf%( Ebe&gQ/|W@ɜ1)XK]9>&FdiOmc^F0„)h:l|\;rKFnrHzJ=4{=V-1ݦ?.Y/)%%S%^jGP{_䠫9NI#jbcׯV n+J 5rNѓ&]u$vm7ǸZ⢅[ m/ {5 .aAk}Ĩ]^^{#œX2A+6s, :K#Kq,S[+H{5`26>9y.ƛ @IvRH^$& ߆EݵVޗ2Иt4\ 鍽'Ifo6tf7}& 'ST^M0N=5Z2maؼ'J2IwҪ5tͬ5  iKE /ͫu3ٮgMfD~e r>IdʰeC[ώ]7>.dۦuǷi9Qpқd#BE} ~J`J ȰM("<,R( ojGB Zƾӿ͟o8S;AJ KLrRz gSPyW3J}y"u0+r+l_ (1y}<~oh94}&&\ /#S:$2rdgLb7|W&LeH{0M2=U:9㼎ꅆ/sd*;jZKEǑC}g)_{T3 ^qܴ4ܧ ׄHw??'qR بQw]4Sci9Jj! ˖v[])"LJ>ZPHx?{StKH9K5l"aT)}W'y\<lǡɇ_@QnPh6R9(j~Lyswy!T_eIfY R^1uOF(N~[߇'mLv|lk@jm̮@EY+AC^= :ÜC. ՟cUXU~&k~, U6KdKNk UҦ c̴Mzog{2`)"&*nSPn$336as@5F N! 'ȩB_L=FDIS\[uY-&Se1-bq.[HDQtd)-orJ%"!iA> v$|0TǠ[G-7rFa0"U]%~nCا4$5F|M#j 2Vj!}*KL947aPG;z]9v"d_Q^rvE̳|qk)c (g%kDcZ OROGq{9GHG6dgzU] X>'Qtc>դ-2ǭ2J &>UM&S3Ƙo1h^9gnNrν0_˚+ M@[| hVJ'K8-EB=W'=Y8㱟znLwrp@}_HpEpVkN7;4k ֙VrjMq8ő|W*zMy@|vX[/ƒNcMz3̞-Wڎ`θf<xϙ'P76M<`+|>us=X SӓiӃ~ϷAV@ZhѾƣ-Ikt47AdYWuʜQfPզFFInMSa@|X]}#87QR@z?@emI(H[>Nc+*e3vˬDf$͎imlo$[o<&mK2^衾õO_a]$<R- pe|?v\Iw!}LJaC$CPDC(U'1 7%@&k L}D؈kiS1j{n5WoSwk̩4YGWXm-[%uEA. mx'pܯXG#g`0m 5kP;2Ǿsb~v*ȹ$i6V"=-וp ]A .DJ?eknOo5)Hm)Z5hfs!Bݺ*5D ;e U^45R -io|ڍ2yҏO(QJleRΏ`<bu>vKݦJ@PfԝKmHwbNT2¿^,zH/<~ ѷTJt@nyv$֧vk! yWJ}yNv;7{"3׊ ͮ]6G 7'硫 X*ezѡѧA{3])g.eS ۱#" 3-`L߲o1gx xz#笑Zw*P$fi}wR>6>!GsNy$[n6ϫ|ɻɸ9*o"K란g>}~ w:@=Jfd%(LZ"bO!@KN_ 0YDvZ ݪVÂӖi~P҄ӄ-m!&C9MQ=X^Y#4Bd^]:ra4>9 Ht\lP =?2PQD nCr2sXF%)J"Ȼ%ҠQλhXÉ7mL kWg<}l|%X&~[e `k^q^ޯReTZ뗩≙KgeɓBaLRb|!?b7E#@)4*"Jp1pDuh3Qe,!F5`2S<0xKGeauN{R8)v5>{T$Z)nmp*!'M|< Q#hfRsI삂/J}9> 5(l j;,Ita([c8 uG\aҦ D-e|ө0wH)f 肃RDj(Ap .8V^ٓ~IC ,!a0$2luS8[CIPsw\:ƒ=:q񎕮=KlW@-T)|tJUc0;t4nLr\R@Ol.G,i!Hpa'=?q K8oZTqќE#sox_,)ک!r\ !;V~۷:L-E2@c#tE1Ry$ `qo7#[I~*ahe3trpeaV4ֽy@1|쒕SS³N (;~Pvѻ2u_Μ/֮:}\1jRW9͈rK'yRL׬HhB--0 ਐ|ռ3Xdc4xI^4Q#,v;)7c(Lzv >Q,҄K雋!a&rR3-?ը4C?OWY4m{svة+Ƙ!a1X\9OF;2vIR X5W0Eei^z4J#h  RU2hjxА}vI3mPbṆkLLFz/CƱ t;nP1DEΦ6)TՌUV |p|~ȏpDyftzɉHקd+ [²1bfyͬbzUquG#Vڼ6h?7I e)@Xxw74L8}9r< 9%8~w-ńKf[zвML程_99`*g-v!z"Ҭ҈ǝw+Jվ2Q*^dp|,(0CF^ b}_>P7!"뿲)X ?$cFx n.t'˴?/qEO㫆dkM<3X9~4Q/ 69U姠g$hY RoF mq 2"32P.脰K7)kH6 W[[_w6bKǖB$8xN !i%>e?"_dLQ:8ݿd͒f]P-ql[1X̓7wh,+ ?wxªWۉSAziaEC3s6V*en&K,{;|O4n)ݰ áF|ٷE)4t!y0 V]JFh FҥU<,}Z5U7XOrPop1!rwMFl8oQvuhHSb%bZ5]/]ȇ Fh|\,rFBʊ|2[zxFihݘn‡eH u._͜ '01 JfV^WBz?TMwJ#Pz̡B| cQ؞YJBeU$`(FyXMNAVT 4z}w,SX~eOr/ w%MMQt/~է K bA=a`#Gb2Knze@~}G;?ӛɄ, _|jcXBYـ4@s\T_u+ bcT-Pv~7pۍtx,ɕ׊@NHA}W 5XZ>tJHԶXp7'bHZ!y#мxl\: j~$/Ͼg:) -1u}h&@Ç-qK?G3mXikd_mQB\$hΧ#a:'aLrc!~4bP: Q e}Z*,Iw6VAGC> YHZüD}Ϋnl"*&.yunr ;@X267&=â\dЖ{bV2Z{jJdq77sơ[ϜSJoe:Ʒ`P{O6pH_:}@HђW<&%G6wg~pu7=I1]r 0"_LJg0{I|BG)H r+x⾷jr|G%W"=lӊȕF}\` oEWX x^ CTHfV^*K܎[. t'>#Y$G9X\$XUuo˞X2c؃IHU8KU]ZrPIz0 Tho8+lӢH3K*8Q[j|̫g+S(0 r0? 0eD[,<|ARדYyrD%1ͻg~e\!E<'N1W$Y@V7 )+YvHg }}0>k6fela?kdP,Z/YuVW2' >Yq&˩ţUPR*qjE(Oȶ`HWl{e׺ֺL{ Wn)FmqGɱye[[CWL`\Hf;-ظü1&[asX#Gpowa1x17?=3/^jWR.`oqخq e& [ ta< b` Z|$3֍QTn,i4ؤ Y؂"P+?؅+<2}shj[櫺'8yS;~,WXgAc ]wGQv؇QYՙy6i 8;,lȷ0l:0\  |';z{3Z%sYK|%2>HVQkh8xBeL.*d/PforƂ1ץ{{pR̎\3j I9D `Шܯ@)7̷)0N oquV㓛/ UxMfcz0oCyxaٵ6!:+v[,m[4x-qk.r9R5Cn`(~,2zW\7KR~(H.v GҬ)9.[!@( X"x$7 "ނu)PHkp!w}q}i*} ^ |%ra _ϢQ) WRoOgH^b7joLGwC`30I׭}#v/^[p}HYVf,0{V'}-dzǴ_G{gMý"S; \ݞ=zlSeNlӸK6$-A"!u}k B=Ehk  mAT x孪W$ڹ# O4`m(G$ iM˵y] Jt~LPska /! 4~alS'Pn3ӀG"ܘыC#uf]T<4D"VFF֗ߎ>!"wc{XFdX0K#g\$-)nL,o%ҚXb#;w+B\}c/f j8C(=~NQLL"|HJ 9`1gm@xe1ӎ{9$j:7茿 {?캘fT|^J$=TwR~lӫ 3G 2“e>vS>Mr+oF8Q d-oc2@H68S.ix/Xaqiva0Z$Z_ԍӰ:۾ xW/> qF~,kʼG%Ft4Asd*ʐؖOPF`A>uY_km`l`VO:טPYwiv#Rh^E/LP{+e`8gX[՜EL%Ӛ.BkرR~-L]כM_Fl1M51xIjlVf-io88M ݰȟ?ABY zLU*w{F(&,b A u3xUŨJiڧ]z#ng^)V;qӃ\aɈž* 3t cU`G!iDRv]A(,kMrׇ'§m(IFNJ =fMZ7G>H.Q*]` )[q"vQzk X>RNJn0RYMĪjʩ%ڻg?-Gtg}\;ʼn~G?eY,aOh5Q r>8.#Ue~sHnf?#I*߇ڴ c#1VS6s֝APZDK{;ʚz R#SC>n!#"U:pra` M BJ<QEӜ|LVjqCt%~X(&[Yaj]q`7D굝&&x#Mss㱙,͊ycA*1ߓrMn{=D/O[aqdD֎" H#KBA(G̔S *aؚb[v ۠Ea߷J 1Խeg؊u^xeBӥ<]yߛ08KRqMbSb U͸;F\7`b[Fu^ _ _u!j0*3Uv6 D)T ɕC-qLQt<}';aƓj-V"Az{2%wZC|E<@}3B0B6(UT9]L̬!}Y̲ޟ si,f@aQZlJPqv|I#r"}lJz(f=3{Ͱ*gh)V?y77qo)ts md@UyMLLrq"/щuuvݙzps9|3⨍l}I* ȸϫ|'͟CEKVRg:'T@4~Gf&A 镕 Ռ8])6/ 88e"mߦ.5ǤY&R$:xئ7: 7(?~< c):o Ume_\P>F CT Бװ5NʴKs7^ۚ 4`wBmZ.rC.Uӑ#X%3SItQ±0|V9#\2H+Z,p 9N`ib 9Ѿ}xmW>cV  kR 7ca㢓>?+ ^ VrQQLWҗ;OK^)Ua,k,*`)_[_TZcNIVbG7&9`<.{/n, P)ʹyRz&=2a``; gqxU.dέ[ź~LR ulӈ&?ȩHhV &jTLxtg,$)86YZR]Q1>"\R|:T8'wPgz&A8cNv[/ŵA8Td)៕ ]iWcXq]5TeGtucpjMaEc4=;eAC"Si"yM"[;q[9B`5MVKEVSE-7 Jv ~E|t^I7G[bAի㽧*tMZ@ZK`@f"C_4/YIB;Iph(.Pqkѽo.Exj1B6s[߮n1P{c4oK@5L(dQoΣ2Lq@4&£[C8,l2 {"91p:$ 46x5j&g  h@6? hKȑ`ET$l9.ft G|F_L/kX2F:`J!x̢BnD -Qji|t"K:K07{[>8n 29zoFyrCi#tJj2Fd('yZ&ңCkYQ͓ͽMRCAgRL4FNHRImUӏ)W 9^A 3'wQ3\ $~{PjR(rdUh NA1%'ٱs9Fpgj겲u()lW9fDBG;d6/MWN=#ؽ2HLjod;%QC]"WOvb-z v/Y+A,|AB`P #e,Am6ib A i-,ڕ~y~ރlcx{rozd> FnHss =WpEWf3Uځ'Ȧj% c {ٸQP'~<œ-:.eVGo[QSj4\AHs.6ʋ΢Sy-6S6*Z54Ƚm-*FBKt#3nJ> ӌVQ : \%Q/{h]$C?ѐ=0?/" )^%~nb61BSF`S(@za%t/ojD{}U\rNg<͂^W~.PZn_͐ ƢH Ɇ~\#[ h r7-Z"kW-%|t LX8r'z[hwӮ`9N`q2Ə](hZN"9mc]TR+ߑ.ui&;uiW\sH|L<KYL@9ТE ~?,nXmMs PoOM]ыkKC0铩vvt[XY>ӪE?J^ 1|Cq jgWr8ZNGᆓ!#}Kjq*XյN{i~.d^g_Uc)n/r`*FM4%$!i[+Dr _x 0 RN\vs/c&Ayp`6X@굸~F㘂jʹjNv^XyϰVN-T_a阪T4l#l ݋6R9WLȬʪ4V{:Ew%5g9B@vupmJ#d0/GǮZ1]IdhPZ-.jH21X-4J[}^~gҎMd72lX&v5(m Vc4_kWWp;K]4egڃiדТ qQo"`)˗l-"]t:dPVB[}DU3o80 Y89 F=G|e^)2ի<Á9+~~UT3r?K`kB@0TJd.&/A&t d4/^I,V"!$:$T>f)EMB~0!DV#vcJkpED^iʭT1 .!\zuo&jn뮗z* ,O^4-AvZ# 7IEWm9M0uk{m1^=ɚUo/}ho~V!e;垕"8kh⨡O 5"L9 ׶CbVd\oMW~oT}pMFb6%ɔߤȊS¼+z_z Gh|M|H=aoPEpQz4(}dt%遷tW:.Qf(i|Eg~ϵL3_+954da&I2Cu-4LczfrEiNCS=BJC{ 5%ɀi>H" )NhC04oICkZ BBx]GDiV=iƊ f|T6K:6ˍϼEIaXaX^. 0R%QWE,vJ>1m\I k-1nV{jI|,]"Rx 襓Ymİ+DM<k?UxpjU:B)B[ʕ 5-~?Oѐ֥y˖BHڰYcݮTH4PΜmI,{غ*H{d_!/` E FdVEYو^ D:AyC=?7. L!ICxq5Uq)t?7t,^, 0q:)eRʋ )͙|<љc7rkoII8O udGށBE4%trriSΙ xS <[W0Qco'z\]xcI1Gk, eTc[VHR:2!r.X 9XЯ_Ru9mv.bi0MS>k,\=;LO#@ 3O"ep!,hav 7bgOa3@.am5|''?reAE6X6Uuitmw?ߞF;qVԗGxâ\[z&mSݝ،V7ի^H@3UNy``*'~SA`) aW5C'Ԋ w vD#t{ȚChÛ6gTƺQXG#崥Q>fL+Ӂt ?NN ֘-yZ|03D8B4*m!q1m84;HG2uLKʋwHܬJU<)BzsvXGy9=, O<:WZ"@IjeV};9{Xiؙ%żBiCa@uۆknͨ:8P:%@rI   _s1ohKKGm!oo-Cctl8K#r˰]CL^O,ْ=\ξڲ ؗTb#Vcw鼌Ҟ DB{>19o_ֺP:N{lߟ)Ĝ9BI/{CX^#tHu!.isFYGֺ1qnJ7Xȷ5lPs#R4d6ޭ 6| 0S_oeNmf"Lcp\}%I#!1Jw.Av~QD<RFq@p VA=#9Ն"`o[;}_MeX~FvְL+n 40=zR-bt`qE ,ٖhf`*I{Zc=pLu4) 2 &p`vdGQ|FM}GBnyfR*n24/RT ڍOwtIWn̒YcuwR+3̭` lmx6 >K P:c0ɮMK]Oc:y˒nP f1'a#Oh wqt9,! -:j$*3؈6WldJݚ&э:w&bq aνqmwQS?5N|&e{_!ܝ):KNA_=7"pA̧EzӶ'/ 05%?yDLSIj34Q0q6j\xN(7xPSe3y%!8),3/uuQꗤz;C6$gט]&7sw:|vVhx˔TAosج<E-LU/PC6*n0vRw!i޸P-?X݋ƊoQ W?E!l" \[%v8OQ"- ;FVМ1ε/˷[!0rHF~O'M(Jl\D ;_*L­e +Q*^E J6dCߜcO1i`Gunډ靇7X@){(*?0mӅϑM_~.Pj6f-4%B^; ~ HU#{4;%g\GTk&KHs}oWm\ʇ:;YH͛ʶs@T=Jū})1f3,F,R *RiE k6)USY.2m,!Ѻ `J4Ok[+J(CE^dq~cv& z9uzd\h>!#m{.ݐDUr3'NBoo1ץIKUpe'G|tמWv` X{aMaP.0{_cb@%Agk[RVA-a.#-[z,œT)a&c( 2(M@6ƒtIJ5vIA B7Fx4)N00~([P[9r)J~ɋ ǯ`ҠF!Ac|kʊǡ4tsdmg 7$o"n{ Tá#3X1ҜNG-IjC^V~ez|0K8>2o51Ɩ9{ɖd?Fy:>֔GFx">W%m r2lvc (q_P@jQn񭆊C/QSDVl^uK%>JaK<%i~qIKDRVg3NО3 RY( \Tdg\!OXNz?Aoo3JxWM:N*Pet56`PZ"9{)iYRj"c9hO_3n[.2Y5UXLľԸ/d0-^xCNb)\0BDt?&Oc-XF1vBgR \"bIr $ 3Dܱ铆R\w4Qa  53TTK݌(^z'҃½a"dߙۜ&p' ^Uhk ȫ v NO4ԣ|WQ}꓌fNt 70\Wqwה8=- 5*\N];h3{R/4}9p99䖄CFi.H IIP L)2!]Ctrlc`tߙy\*~ ]<)n? #^șB LBՄ_6V:Yg W,kfHd ' 8ܦظ+u樥E ֓zTzJX Gcup['Ч1cUhSkxr>ȶn<,Lq̜Z;zoљü jykRعR<8i2 keS.$JS/1;!ason iOMm^E X^6ߙu Y`uR#dpTWVehČX, lĮ\YR ,>Hո*##i@ Nb"ގxgE(>O[ N *s P40[ml*ͮ!~M|XZR-~3?Ftrt*SKQ&Xp_;X]=N ׵$龛q*N? c42ҞE)z(K1:\"@i [v؞I',dwxGCZuHEhS53wv!X)iY|):Fvu'ݾ8Dy!+5M Dε_6tD|˸6{BwAwi*Rw!9P&R$Ώ,wLAvB9a'hP7;N;Sҹ}ѫ^KA@L(:JnY$3kFTZJe=yبln2# 5AP!*@ubi[dfJ͕~kBoWb3 ߄jh"z"+W=^+T=hE:G]8F{|Eԯ- CU$!foT&(2y`F~X )Ş? aU&W|D"q"l ê>SΏOmްJS&g!I9J!<2 75 1SS>xj+>G7{r6X璸w>ǵx֘'OzJAf 4oPvU2Qs' hk{==ⴢYf{qǢL}Ђ%JA&='uWjCo6DxN-U9zTe˷H5Yjb6("5le[48U!]z8aT*8 ZЫaɚb& 0KK1f e8(GǸu(q %x#"noZfV y&^oEB֨kH+a%$/9z񟕼j>p/s:3$鹡!p(;ΔK([R%HuͽѩCRH*&L%hTI{w?b}C<HCR~rަ#ȚjpˎuR WfWE5cB%hqؠ^HP84yf\"^Asc0m>`:}˪.zM*[ ¸9%y@'b\Z07<(2?g0L¯M7x~nT}wuqӫ9Bf9QU籛n bMG "fd%Vp\IUCG0Pz i i*DB+䙾o0nczlM& G;A-]w#I-Ňj^Wm4pѹwkhH;IS>%`c OŐ!זY`33,!GZ+9jfn+h.zwyO(+MI?"Hʊ2۴Vz:BhF<'x%L|G'M~օҡމd ;y }=챵y1B/€ƻ̻*q P1@<+4cMe;o! C/ywț4_H -Fʓ:R e3@yFjg;u" \qO}O vsa*j|x]p+.0]/ODIYӦr4 .a2@ᴏF:]>Ay& glQ>FPy:j&R$ѪȘ1Td*+2U]+y#:rwx:`R_AeTUy2$(B "O&i@b{AJ[87P 1Xd1XA- >ukV045 ӮrgtA BP ?rՐtz+9d=jA{,HGQ fX5IreQb}sdxxyMXD㲉޶T*'w':H*3[AQw\h&3#meNaFv[ZL$"6~ݵ'K.\| M`dRžOm@N2T,Lڋ/ne7ˤ]}Yy\G( ߾|hqwj+7I"͊ӕA5ZdY%M;]ITŕs3i`KiV;/aDN>fx"jgE&*] WD6,:W9tqe?lL6KZg ڒbib}`27U 0/c8Sk thwd*&c=63~4SԚDWٓpߑٲO?x d*Ld&khF]`="Ii8`VUC8$=3d` d*((IâanT)tZ$,Tq&GMn#l`C٫\{5TZ*BwrѺ#Y#"}Y:H!ز &R3},"]|n6ύ6U +P~qAidj4k+ XH%-[{cLWDZG+E&)-DȖf# Z4)o: ބZFOFT6 )VrYh{)Hd9kY vܑ3t~-%8ӷG:6Zr`bh1`N9АhO 0f%J׺3?&j.4,*'W5aLњ?Mu 8c.UcO{^ȮD%jA:S=1"'eV3/}H gXӽݩ7 A"(mߦk\D>d( Gg.6%\f[aN08v>^ebƁR~<,\szIŊva凚t>b*ń,V~Dž]ww,FZlw]x^}+2[H"~ʟw\!赆{j kD** saj _Lm #^X3hOAxd.m ɾW~wbAET Y=%0'ibPT_KBcv=ѐI? 6:С*LOiqa1˴I@ٮz YC'xfXeLba^%)yCE%@w盱ﶺN19; {sTu>mâ[aAlE!b"EgLmi e?#d 2`黃:䋼LJZ0n~4/SzcE|ڵZRLBѨ۫JQGi3S(6hno*@)~W/+k1(<̃mRciZ |s_TC.Z=Ȱo5LHM}B}~*f(=sQi(*2pEc]Q(C6!m;0{;@4: CEjN3/45U:|`D)nD)sI =w'~Q^.8RW+\ :Wa$z/,QU/~ moxSww)l A[.(eA/C0ܡwfEZr%nؘ}Э"6Njɏu\S$b}NsPS2Eʶڄo3[zLk51)q Npjߑe]3VE +Wz"M{n+DYu_;jC9yo0f%ޞpUкksCX#b럙e[p9ɗ@*@]%J qB8M "Jȧ ɦH# ՙ7#fvΑ +a dw,lV*+z|]$>GTB=Rgv 4բ'ja5ź>mcҏ;(1kh'C8a@#ljdjRI3fjs34b-^*:)L47I !)P: | ڪciCe"1X C7Old?-7mcY$@+_glS,hshF%\ Ћ_U„} #BAH2ɵ6- "f}LN1qȶU|V2}8=˔uhC$x#' d#Јc6"`ssPwS1tF2  Pw7@ueu.Zހ f=~ *i-rp]4"O9>If @Ђנ@Z 6%tC-W1#<}&AvYVXmw./m-m>tAS0KU5FenZiF:T$(ڽ/ޕ,@ǍoVL z쟏8U*,l jW*;u(&W{O'uk:&pwVvF/aD VTޯb*cFqǔBtQ7et&iոy#LǦhg鰈F1D%Ru|9 ])pf[~{2/F\Pna]Z#^xO[)9Uh G-;rBev4d|L9m$wYLGcr"~whȃ/rmQGC2 oXoWTqJP~`stgWD`F Lڨ$wcNEWRq1\OjހSCy4~YtJI~{Cc3 (QZQ4 nZ)^Z{ '^pO SbP×d`GM}x:^z"ߦ^ȎDly]IE:)ҋ!PLs&BQ7dJe9=@רϻצQ3 RĒ,i0p &rG'[%حCIңUEO˩ @?~}t l1gohfS(^YKu'1͕N13U4E"Н5Om?'sv?nr{Dci=eFe& w*3cadr{!N6P{w~OEX\^ Lܿ]'@ãʏ@|,6q"uEVH+Lf\̦ԍ ]xwL@2fHkh`M妓"1_PBXYccxeE3q's= {G՘Mf?蒝_Ժtpuu-Ix nS*A;e'7{_4 ImmWn5+ʾ[I֦tΩJ@#- \_,< ] ]OpqꙮׇzJ⤧,v$p &1-6:а>;;Ƕ_ jw[֧Jz~*puYpϴd" Ԗk'G>AbfG9{ Kie_ɮNAFQe rGX!ɼў[fzGhOQS>M?*B>-m@_K(!r$]/  =Zǖ?\@'4mHi 2rN8Er1AttwGJB "s:KtٻN4†SX{y"OufUY"kŲ9_-t 7zb‰*@U$4]zqgsY͚l?n:# RbАy)m8rQ.R㪙3 rޮUj-В|`қ"^ s[3 Ʊ{VĔ绳aW1Cwr.](CTV !(3bxz71Sb jN]E@!jIŸtvj6'G7Sh,b@A. rOPfˢz,W*+:I$);h2yQ ƦV_peFcgpAU͸K͗EXQSSz#6+{MS[4 RrMbP#l_thlF[1 PQns2W]n&&@Qag*J}SE0t.6Q+ZEY*IaqT?9%M"txS"?1 4t?G=C8 [_`AzͯWF~C !ADYqՈ7U} Bا` i#6Y}QRPJƮ{7ӳłb (H.cue}Pj_[dSjAok1K(#Xo[x>Y )6Psn8geL!wS^R759*4d\7$8zYY/0 }EXDs l]Jqg}isyo8+QObA >n>GHLLBHĝѫh3r}`ٲGKĥOv.Wm$T$~ W= (ŝe@p`=)P"/5QØ3A H\]N٢*ٔnb6󹩨>#~&މq2ԿmGGT2m'RŒ~E)/J:ݠKfU~`Ky4aHH2tڿ[s^V0/QҒ12 mҴ [ Ӻӏ[rpD,/uOn\xikиēis⪧?CMnqIf+ߒAN]dW3l^*8_ k?# ښC 8h.QvQzI&K^.pvW˥pFPWٕSe޵nƀs΍j2L4mq$%m=ͤh=SlВI#<萴Iߋz ޡ0BqcAJ2 .Y!$J#,fO78y;88 uwv._S!n#&bNξsF e:=)S)ѩ+T`3,{' T:s3:BOG}R1{Iun,|ֽP[D)w%dhRxQ5"M,r]2D{ge/jtIc7ExeuZJE43BŞ PS#Brn[s|.KV'gUMU巅Ɯ7tHPwfb \⛑0km"zjoVK8SÏՌ&\j__S|X!#uߡ*PY>C}lJI7V!sL K&^NU6}A̭%7"T<Ws ' C"=HDAR"ЁX}]`Wf8=`/hTizU\;=ZNY6H۷[ 49 ?#9.j5DjvØUr*qIzrrּ44ARuI,V\",4)A}FˆP%T먈c24wl\z(ZgEA^lO;—Ѝ"M׍ )V\R +0>2g5˩kVP/Xs}$':Nh1)!I5O7O'ӜNn}ky;!\eTN>Wв)/GU-?}/JvMm_.8KG{5b5Ic#B/GVTp#Tf4nnWLJ;h"x,@8Ӏ{.X ֊4_Hwh֚ɒjߛp f\L3j|ߜ?s7m (T0a(%;Oc166lBe; cN`+ZD r$,_GϣSF$[³D3+3&Kħ#. w`~-?ǞZN p3n|*F=-=ġ|`7YƮGZünALsV--Gg2P5']Bd+[Ճ2zvѝM GRud0 mG4 '^ܟ>{Ѱ6۴+ 5ptƇr_&8@Wց`O5k9U0]K4V]P(9p⠑?YjlÀ3vKEWZrSzjm;%/2y+bє};j~!k kKȨFyZCa?Ffw,%PD .zߠ*@^v\wXpPf>x9 }h ut&TkcL3ƌj*/ I$9+˕羿-\Rrz>#I#z[@N<5U>m1)-A8}"PmY-¿m-r$l sakwWu P\'SEbyRhj(EQw7Q E@J^3ĒS.`]'{RAIA MK]xq."I''5ҹR{SƬi0܇vy+V2D)Ή6j^]$Hs&˫;^Uٍuj'x[ '#NXyS; q<=[>`kro}\! )VDZmbFs![f>O@}:&m*PnF</|u`tnC5H5ݬUs RR5 ~˰vۓ8Fz >=]$i:2(*)JmlR\8PaB=~E_UxƝֿ0CBLIPLa{-Cvv ~@E:m IάDb158OqR76"` vDS%<-[$8 tMH<܆TӾ pKc,t=U֌ 0 ͢RȰmbbHqX6aniS D^_ba,9D}vCʰxpxMk=@=exγN !K*N!V BTb:7? {E(W d4>ruߺzsݴx@`9L0Xn *L-*֖OAx ;\Cb u4ž>$QHbMuIb#m7=ƓZQ  B鑨 Bm?WE[kV%{6[R =~;<L&D楃Ӂ&qE,HlKPZ dL/Raq,{Em1Z}N.`/ k- $V芰h_d17܄PAer:e5b&x,ޞp^M,liDMü`:ژSGU x7_XY?4fJp5׏]fd#vd\Tn@_r9IurLE\>n-co*?Of3dt1>NcJFqi`;>M4b4Pnb_'1Ѩk1bMƕVI%AUv-yzL(eAr@ysVndG蓮Z|[m,lD7g6æ>Kzj9X'fw# ZIVؚzZڃKч1.W'XI2ZXpaP/9urs-$ Bm._>/N}*J zLZ.)J톮U,ЋO⠸ⷰj у},Xkzkɣ~5? n˲Bɽ]5#?z^6C5K7KhfݞzYnQJ @ͩ$y. d0h8geG*tkV7YBFV x}[T:]-nbL! SQ -gGL8b9btp\F-*&f,JipJV&C-1bO,'ȶ^sq, _7U :Ps-!2u4@JˁEobASrU4VJHN|y`vYeݙQyI'V-1(HMۀG*:'A_V`s>d#rZnƀq ?vT(_F?< vŃN>wl̩򈿧(ֻ7E3rh< %޻GCd98k\84>:p gbY cfN9^J"e}z~aO0S&V%;W(Ht]61^C=i*ETTYULXtdűS>\';%轫t`/?ݯS_LJRK3EVZR>"A ,ZNTJlj1~ ӊLUDWK Kp?N9W,ل?Zr{#=}O˓z%3|V mD۴_TT)@Yb9}xSg5ǒSYtLrB Tpb7@t\h,?.L{}y$RP1CI=~2DCXT3K>1@,G,Y׃,j_4hgjȟOtȧ|½L5 1Q7Zmb++Vn;SLsK6dJ lFzԡtl#7dH$ FzA=%k/O,o7YIŒ;U *LA?wvekr'֜DzAfy0ΗjQǯ Kׄ[u+gJeHÆ!',`d1Փ:-)!b%0lX,qɪ *ل/V=78aTvJn1Poc/V۞\xu\0TTT2A_3{hb~?>tˆ~Sj\YԶ gjLYĦT㬢v̤w?{Ag8 'xws (MRBjd%{]Hߍ&KlgztbpEGum,>GR3Fհ+,ŭJC"(Y-@~B!WFA2<};X}z2)A[Y0[; o zp xVYgSߔH櫕;Vew~Et2&HiwLJ07oƶzCcV̾0csJ5<”w:4V] xJrȷq9\%1׈!ܢ? G^+}r N8tYꚉk$B ⨠`X;W9wG #Hzgpi H+C"f+`wdm $XK<]T(MSpXr^)n)nc I5ܖO@ÙFr>8Xp/W+vO.V fi>ԷV=e /q6QZ ނK cơ@8z: UX⸠#g5х 4;ݤaк2~}c}A=L/W eG |wZŚK_&X|L8"Q h~:FEjܳ™/'(^LKNn֥oNpѼ~Y4ROn{0uxY@+{&a;3xBw^k Mm:td`8F;L1!/Ͽ><: 6J8m#Oιao'"$ +Ch L,]G% |bds|SiEkŞpśA KL~ɟrIچӪ?Am>t39(ntX +L"xr^vPxȚ34+{ JI1T.S ,cՀb.%Ko6f_0L2fK R^Or7o+ܘ@TA2u#KIi;kZ-z۪h*R ȅvjNBiMb]g 'f%yfY PTI-qa7%zqHl{&lӀO3Wņ"0ꐎ}-^3rdMNux/h 69\Y,5bMrh y$w%j^E mS9NPb}‡Bk$;,fr-J8izw+@$A~bt`{i +bӲo| <,Oj ˧\{c=Yj搗l*sq[ߐÊa)&}cN%T ;&Yw5кtkԂS wOfn3`T *>lxn+ g'XQ6//*yNAIWNծzk+,aj*v ]q -`hcm^(u5g4)Yra@0tzst'!?ykÜumYgqp)=\3- Uk-^'+=ˑ ,Ѧﰬ=+'jHaC栒o/mmD&;er^p1KHzĨ[hk/4%;mm und1uJ4q";Sbww{C]wAW,W_F_ib4tgyygqpBGF^b0CGnSy ]/TVY+7a-ȵ:aHCA|֭^=OH>Vdxayzr LŽ1\W\LֆP!SڙOxΐ_0ե"q hc #)ghvI#RlfÍ6r&34Ah"JIQxp'NG3Ǥ(ǻERLgJ49:ѫǼ"b"S}Ke*5˩&))S"񶧼E0)?jI;NI.7jY]V#Myǝ ڴ^zlyIJ;EUC1y,gk=\JNÀ|x0V~W" \K4WM#X\o7mP.4/ fc BB#Jԛ + 7?)V`)jL߿ 3v6p_\O[2uԮ03t4ӔDJ&.L[sUU^4%GkQ|;64 ZB#Q atH?qڂ~wFK(7:)d D$ouy0gL5&ػ͔/1fWy.؅_WL/N""]y.tC1,J\l) Г,zYEyn6Ǚ N&Ͳlj +Ef=^1wSV{*zGA.mM30X`\S1z'̓&/\©$ޢ(zLS˔}^f [XNfއjeҢ+dnZgg{RJ!2c9Ѐߎ}Gxŕs'LwBޡ9/eqk} tJ Y8ӡNjqZFBM2vMڲ)>:@p+t}Q`#T /Qᦼ9D >[LeU2wp9e73.]u$({m8su LK- U-C,cJB]tmY+ SȇLh\b5w?,dȷFM;oMg0Ɲ}?;6ܑLU fEj[!߉˻Ȓ;:>+ҾE"2~b_aXG@1f}a3!N`>OFTqhh>\6ñ {*?IIB)_Y/D8ڗP/Yh#&`.fT#R6d"2n)N)9S=H$Z+anV6U>;#خVfG 9%\_jjm ef.JLaEmjtWI@1l1ݾiLNZ;j?'gT w@(TLq~VzM9)#km{<)(X3Oa#rR9E yBq厜6$VE0>Ji ZmE#P__( "xCW{YS!'ɏO"Rr%#ۖuAvn#z:'y˄#muS$C 2W^oAv#bV* ҆@>fcNG$N$085 Gibk^oN֪7 Agz,e¾&" |%`$cFd`-ߢ {Vpz& ʪ)s]Cϳ3ĝuTiwֲ\LCoLhzg">M$x\)=ݽ1}yda&,/D)/aϷM,S.qŋA1/w,ޮ .$į2aUMĠZYr1ƓjN0~#"ߴ#D" FWS&SC a7 oҜ`ƶja"E@]mhnMa0Ae^VFu3"t@kp//n7CupdY]O8`)/p{>ɤ3ʔh$O\!uJڰm(UC)O&_$  V9"jcР$ &@ҾrZfh5\wSGBO;yxaeԿ`KaeW)6(ڵ< [O{L~߹(4dJ x?r RgT0S..)KaQ_n CW #Gɓ`f]ajZ([7`W@ za"tGpL.(#^ZX)pk aT-ZM#-IS]vK2x#f(`N"˽${s7O$ ݟ@qu  ͼڊƂ }Ovt-ϮEICq;ohe磫KۻCijر~sS KyS\+0{']ck q|f:'e¢\ 6x>PE nL oXzj q]2-](j`5L̛MMo4\dM_d]GE$oG5f%CtBU=JCsMx h] _q ZAgv$ _Н9s$!FSV޸UlkM T^k CwNB}-vuWRRa\xG1ZnҼGO%iaϳdjx}rTL-,qhQL?=` 3P\<'HK+R$6 ;weUv8G7_)y(8M_ ƀ|/'֐9޹Wk3R]ad5΅gbU=DP1{/(ʥ^/@,h؉VO_Q ]ZDT6i?h_㰎`b-8ow>a%d$b:* 1yu@bcH~ݶ:ˁdhr&(WT!DD'*Nuس}ѤL%1@HGTz@K/Q6sUX7`e肐 }3ǗH&SqcRR) ⊴łnZXr["ӷ## b:67"iKmW *Ӗ-p*Y1Qu觝S۹{Y};uc @0a(q0+DOThO 'jl8fS闑"WOE~^,Gp&Gv0NsHga |M^&zW#RH!.d]*=a"\\i7<?p0`l?G9Ybc2z- fɜcN_\2\^$'8DMԦ_/;Pѓ!>ɐ_жK֎=G(|y!԰R.Ɛ+V;BNy5UC?_.26mTU˚b[G(i~,!ku5{>Y갅بK] /xghN#B*2Wg_tc-(T 73 j\Wܕ~S)\A `/X]IivyxOϜlpr*2fjDsuŌ?:6a-Ep@t $l饈_·9F:pn5˓` @#1Uf#?* iN c, -9hx2-LvBC{e4.2^EzZ$%KwCo<\FfdKF gv{@F@_m,r]{Adf@) ɖaTb#C%{lNc|Ϥ_i%3v/! Y/Ajh@)ph#}BkZd>9 H8be{v+zV",~i)ꑟXaٷ`uBMz%żh-ԬZP0t}maGfqD}6pt[Zˉ{e=~G{muFژ`z-QE()` p7cg>0 .,h=g꽸/ ![;oLS^,ߛK"V﷦:K6pwйܬ(9ir go +WPRgj;H#|7F&Y'dy(ލlDl!&^Y}a26kxh$V,q  މʈ*2hi97+35Ӊ`_ÔyÕC焊y'(uNBa?!Ӊ l6WM?RmPޠF8[0)a.5J Xm'B|4Z79)䆭78U{*wz 3%| ;^i$VJHlX:2nJpfDvDv2.Ӡ%;bdh4Q>W $hHٴ5P&VqɰE>ڬio(R tQZ*{[#CSI%&4x9B 9]+-'$2,=VrAm¨Oúhfu׽˗LT*\R18?sI-\:1POʂ΀ꇟ NdlوO\X!n~\n=Ve=ZMitW9DbaՃIJ!Ǥy { ƂK430Ez0\%$mQ&sTYPTۜە[&&Ǣ건%{Ev״nԾR~Ōݏ`Q%_۲~ɀvu\Уi@#95@+}PФ:xg`?wr<Sѫ!,Rwީx Uï{(SPeo}m 5;\ CHSP h=E?{,[tI1rC67;Ez'>E*cߏB텖-yktg~<'=\249/S^ 8Bt=ߩ.ZD>f)=3d  6+`Ċ$GdJv Q몎'0w~l)i/ߵ.Πw:hRzARcP5*p Wo-SuLU4-KfۯGdCftf ':kX *|[dKK菢ʴ6qx]` T,BB"\0qyDuW;DqΎ.n|,p o`B3Gb B9Qvξ 4O52r(L}LV@N5Kܨ*ý7?׾jNi~aϱpνAfmdͽ?}dfa>\vXWUv' #_j8v6-ʬI,!P^xf?;)NXZExDa&/O0e'iKw!i2=i a/'IΉ)|"xߐߡV 4֧#5/7A7Q+JH5]dbf+k; qr\3 v^\Ee5z/Hxbh1va^a-ї]_Z귑 НUy"{ީ 2rv0u Ŧ#wVHی )K7u9\s .eݠq76*+$s+;pGU%C~,o]ePa "Qbuc2{b7bIX0ݕ2q b5{@g-$# &ǒׂwԔYH2\SR29~!6l8ϟMp me G?"R߶[ | zv g${ Mծ(R w\ܶnXg_jOٝ 2ڍAmCGW,Zg ޾^Q^8K wTrnDk&ǿ7i2=+5`Di1j3a@e9&4LcmEL`9ncb 4OagaUd[Vl}47kwPU3iJaXfR5X0_"ۦcvY^"Ms;퉇%N"`{U&H\XYFuZ/⡋.fd^|M 9ۦO,Mzz(djDS]<҂O =d;QHݕp<&wq3BjUUָW"!^yE~'G&]&3~dUƆ~'ݎ+iwW>Ѱ}~U.H4AF=ttxW_KяL>ce$!)dP S@bmu=& ov#)G?`Ǚ-j!lְ@ʊk!K!N38npe^_ ߨR1Կ \zp3e3nAȎNL~{|t,6dgB4rw?P&Eן@,$zV,hӟɱںr d*$Lû*YtIC` w6ug<νjٙ{jEJws>O~2GTi4G~6ÀKcM![/FUS.l_g2*lA[GPIԁ:`|QFI&$ʊV}wXkJ .J~*mzoS R}]PDc y %#hr(m}8;ޭq2e_uZ⣇,b»^f O(8~\!N:t )B 5 Q Y7uȫO7q0;S hD}뀹W 7K`^,㚖yx.d_) bLu6ny84ex$C`U{8噣pIE"Z-x/\1; o&i8.tWP6@ե6^q t:{/8 +F,⼤q,HJJ-!@vyAf| }5wE.PR N f%Cxy)T%H~*| Z9X 7I]IsBR_nroBnege#~F*!{0 -sJ"<8sp?u52Z6V-\)0\dY:,Jxa(_  SQ;~.:ǤLBb^y+J;gh-+?b]=^--DGQ,[rcDXBۇg%}R>+^$HͶn(Pەص4fEEqBw{Kb hlR5XB)RINU:J4ƐͶymn`x[|N HT Fd vRt-W%_ٚYV`$]3SH˯lF&ne7O'ڤ)iQv{x?_D1l)k)IsxO`W'#8.mـ@UTzB{a}koAEU57iQTj1NmނvK#}3@c}vAǩ'`a5 4d(eNpe'qkj#8!H؅ hy%?ãop`Zl|m;j<8O͙`ʖ2!O|h~ !0G,ͩg"VGxFRU jmuia>mG8Os{RcnTjۋL|շl9؊0R&5,ؕ!zrrv]ow& ͎2Z_H(`^D_&樹]UmSOXSf紮d֩PY7侣`ɂO3R`'}NMD٠ 緉?b)- vjJι)F(F"ɔAt_>MTXbZ'pa(geOg/ ј3?-Wh) eЕ2ReVyWޥ<&o(oBuJdWaz]A; ~W7tO15[I;|Vn*8lGDzOH&"Bētc;+,#KhXFIkL8vE3nXx?gO}k>3x2-p*8JsHniL< 'n7/f7(kG+M oxOB6X,V EG\ J27~V:A-ΖIZ(>Nʠjָ], W*}z`4z i'5`O'Seа|\=ߒR^L)e4~ ggH&ٍ|jr5YE/b `A-,tFѣcpp7s|.9\O 3#5BQ7o#X: 3 u>5UbKmLt:?`|Wskl{IS~{ N xտn5>i$On= g"YUG>-w'ZGDSPmRI̷)eA\s lf;s9>|(2V[U4~47mtTx"+ZroG"+ipp!(TV=@+$a7>L;%X ܔĶ< L+n}G{< :te4%!-;rJKcʣ>a9la7͆T9L*0r J@^ݡb=o#O| £mm29aӱ7ւS)eEĬB D. +q΍Y El~m2DD39. z[Pn&/줅CWw:錰^u'獇5Yb>!\~C]ϕ@Q}B5':O11 T}1x[cYtN'rEM~cVn/ZC@yv $iyd9#n-o=)ҺnSu;ԠŜFr˶N.6e_TnZHTb" <)c;zEGjsk9^APċviGARHέ#'`Nvŕ%w_`Dڛ{nf@3~޽ ǚ6#aI:x_z;3Dw΁1^}:$=Bqr!0C.t W3|c' S@VpKcޤQI]۰=wrGfGx6ah"pNMkØrݙP6 ]eSsyfT2sGbL(f[N2Mɇ2!k-RE!.AʶR&N|l%P=m,4*{%3OIKV>2oTC0!H}]}H6k) 4.ERQ~TP_*$Dc_x$gi &n Rz}i1_uS:##Ix(qvα)=.nsJ^V&tw%O4wMtk&_34_h^u);kXϑ5BX" 0'^jҦ "pdҁi9šMʍ}+! Q:\)5/ 4z~!V˝ry}凖e`HETE,enכA = .3d̉E2>}muN74 P׵~ɖ̦*M0e9A/J)׬ӉI?^9`ʮgq-˂$g8<ۺmEYnCr_qJ&3lTȞ }~XU-ԲxD*ȡ{;eNMϘZػרuZ ya0<;35_ۘyui?"Ejh0[ȺƷ>3]Kc׳;2L]@a6Kɳ>%"^w/sG šoשXeq^}a8ȍD=&wTl;i$'YK 'R} )$),iY}˚vqi6V_r{Ǥ;`i&EnzHO>Fݣ c%T ɚ,sot=;v6:raD@uѸ(,6wC NP'38G7 øvJanFWKp-$TrGKeRՙYxz޺#lbdmr2V R'L^6XULL=@%2\6F=s hR,:Av 4d&~A 5Ha]sPZwm3x3J2H&vNm;bK5*=kIOnNquګjB ޷hi|W q8LNִ޿KٿDd-"o(P?#XN=xjЄ[g̏.0!2_\΃t`m= t YN19hz>qaQ3~03cpE y+T~QQG)ll6#rN5\,J8tw=h S[\ op%IU ;9Òbq"U; 3EheI vo,G.rT0^V7Uq슃9 XqGk ڰ8wC_̷t9x[ZR!-фSo`pHW 5 ԗLMvɍ%/׉".geH 准&<D.Y?(Bfv& k.܄]AaU7\Pb}ch~~OjpgꅖA0Zj i Ipv>EE j6E5Q\4M>D@QJò\ǚX$xKIz/?IWw((Sr42gz-cR&&S6xv( A-V[xHT[vWPopcPi(r1?pU0S?#D5361yC=~ȡLItF ɲ.]׭KYdqPe6J7Y&+2}I:nk9 Hnb\?\0nxw蕴U>bVCc\j^o+nCJ0i?c^ZCps@a: k->>߯5gvd{H.{ OF4,| 0Mv~I5Kdjk<`'vuL:%ѡŞeosV6MVzdsȴ]4bu~DTPO|\C%kiE7ϱ8lm ؿ9 R]ыw"Os2^M钛y\H*RH;6aE(oSD Gŧv׋,8)6?Uta(~c7XN]'I# +㷺 C1>d v b`v>4XSֆ~ 9V(>jica,_|(B* e"c`A@!Un CҐovy_@dpL%Р{&j儏17Ng]'>Uϼ5"%)՝pI%B1|mcv"~Ym 35K SlD DA\yk0"#>Pf!@4eOKp۴Ĵ,3uS~xEאe}"5[6F*%-+-CjVbIs2Gtk,VL:\9ԣQA'1 6ӈ&Iw@$U04 0uoL)G\U%H!>+*JP9  F3dYEL`1\ObgqXɳ/3Ku<1&^M}>c^D Ls㘃QVB_qƙZsjMΧ$♨"$6䀌%W V !锂/W󖤟߲O G&~ YIjI/=c=EDOd@@ ^U_Zs ߟ\ -6ke=lZ.˼rg$sv<q rCq\eRSA2pz>UQPoOtU_;{S!I818xyy]6\RAT ϒv'w졺ȥS⼐V09k=\N1ɥqͻZ^egOpyd}{CW\(Ʀp u|^oje4]K["zh9rӔfDYv&*$)Hϙ{E{”'OהŕK?Mec:`#X"܄ @J訫~5@⃽$eCp'uyz>QLIz?Mh1?CVBO)MOomR/lf^ oȱ|[CįJ "m"RhYp6lds9~Yk|l T TBKA~I`S f zvh]Bt[Sez>][}9[Tn(Y>9&|J7M #G|/5~Qk ӡBܒ«@ސd_xC>mKTPO̳I4@} ՝@V֊*4  W\e'{ϹT$ES[ X]u@'䃯M1L7~0'EA ^v{Fh&X^#2;wCVqP@CLekbӠvi Z< wh83,/e_d-$aӂuYjvHJɫkSA~E?:<  ՙE, ̴!hxMnlƓhD, %N7r5f_o+"`8dx#aIW% #zLM[m uתNF?&2wfICRc'm8Ӿ ξJ"6Ir"2^B9-+{D,CM\*ny{~/>C=>> qVT B3(g4"H4!T"0;?kP3%0dR$eo"*Гc ֣~a7hS[(a)'mQ6Uqa^Y ffƜJI㯈>Xı -H ^aP _sS/3s)M֋y&y+~sYlnٽÆde3<۸,.9ǠEӶ{4 Uh t斵2pŷG6V`VI"DOC g_\y;~]O\ J+Hduy!Řn?;gHԖz,,@ /R> r8Vo|lq1[kl'W#.eiZ`L[xEAz5u,=.l)9Z2Z՜n)A-li{)`_EZ[_ L[śgJpkҒ}[jDjYۅ|<SƼ̪WYI!i!m^ܸ1ϰCcwM 0Bx#xmRȐiT+t@.jRBaN޹= D "VVh(bOO"Skouˣ\ڥh5G{7Հot# } mS>k0N`wgfu"LwE9̅0 C`9r^xJbK/)Sbڝ\irʤXY#U.^*zuɫm7q.6C`" Q9a? pD8VWYHa<3aT.RAx:k/63I~eC-`G^hPŨ$sCK!&-Uo>G "JU̸OK8-8=S-\̢i8Uā9뼧ϧ=g\}im6X.6s.,m2:/ς(ԡ"&zhbDU d#n[+] vJVB݇? 7+zr|Ze2IӃդ) (-39b*#  yEPDJkeOWv^*=APp> Wo.Mk-&aJAֳ!z 3:ǧϜl቉{=G g`9.Za Nt5M"cϬ-X QP8Z&EjShP'ex+z/\$Hu^#@i-eg01<L~qҽJ\)?epL:hb_Daw&M}ekń-֥* gDєpkqեꭩqIJT}.$d+oXVu~ n@K@C,ޫYS_MeC*geĶ#w$θN"\MwbRWm 3ܘj1@<iEzf)5@78g[hx.V`K%w=BsJGkЊoG8TgiΤOdHg$:h;0-1F2!mn+*)߅o!q&W, }f4@RYOj៉c1O`?T$tZXoe9p1BpsDl4PsXkvl=ja."51?>\ /r DQɒA\"FS]HVgZ2Nt155C$51r `` wPv RyX)*~M62|D1dZ?WhBVS#=fRsIN!c¡eS~n9s^9A#*^dI-T,N@Ds |semsq[Pg$AIRhwo4"KTbG=FS 'J[V7v1_@ o~ScN+%=#)幀s`sUܞV3q:z`!Ae:$U1zU~ =I E MFn]AY('<|ѷKؚn/xB~zrnk}x7 ȴ.撤E>w /sZ&MId~ڶVUJD|B g EYF^: x yzV c[!R+'c,6A@Px s#V&d")tĤնAX0~6SsQ1Fp~!dz:J>oE3|.7|[ >̕AWӷ :Foo z(e< Rz R6؏S^x]*LbV1?[]V>*\aˈQ(0 '!^]h|rIsbK" xe %gM,юRWLP`뽗y!uJo"0N\uu:N:];![NSAW"6; W[l ddB!]a 9eޑ8, U3\E\1BW8ѷw߾ Q1Lnl" KIzI)E>רra-%gɀ|I۩6LBJEr-ߓׇXq=۸))‘\9ݍ&jpYNH_ہѻџ{&0>id X2r8׫z"VS/n,@Dh,sʉ}ZB'6ᩢ%G;E3 L]EiLI]&1Vd %3_,^zE 4:#xhYc8dߺ _A@יBU0a&lD-eW6 >F,G*6=͇(nYJ;=ND*lc\nnTzigk6F91?`MKA Doehl,/lGK7eַ~\lbW7C z-G{3,?_ݵ6? *a`KQY2bqмmB$c@UA l!]+FR>`:%>oNh;M*[kd]T:J HP#drw0iaFaaAePa]#pGP5|, UDh3Zp|o`;鞅_ nLgB>@=HL `*@y'`!R/>NtAT/׭@x\ a{E3\͊tu;er6 p&k4C0Kԁz%.e6K#l0P5p-lPL,j} {}* ok•(2[ =.azgDCڭD4 ~_ _Tz剑EQ>cè[4TE{y3UHk+q~ȸ@]bAV: 6uĴ۾S{| ɆA`uBIlm-OpGuӞ D2+x;tl30lha0"lL(qeheYrxh-~G 깚Y3^e0|j>%+uWtS&2/}"wT!بDeSq@:.8̟- oJ7A U*fԣuaQ{]8 ,ݫ8&wؒ/Kks=VSSjH"M #Ai~Dr1Ǜ2XybuVE{'g] C(اP O 2v4l6B&>*8vtnS n\} PO.0X$)8Cz%R׊~+1w4wzE!7l{K;P1 9eprA0Q ]%1GɠB +]hZfzkDY737hOXH<6bEHn f)߄tP6@Z؞n:4yeO}/Dy,ƅ aR̐Y }+q99)Q0liJWfl;4`:}4NK0qq: 鐜A{ sSd,  95wԴAN8L8mEr"26FiOS)hMI }7A؆mɅ?nV)(2z ִ͢P魦/Q5qзkƃ)ɻbY5dNjwlz.J+`oyz/#f@:pxT^2dlGˆ [Ɇ%_A #[:s#~.^7ԡ $e R{~YUT{>8z} h#ĸفGHZ̹mLO9t|W6an@f ɾᨬF3WD 7}`ddC0({5kw !&HJ@Tt=+/ /RS,1בnX_Fl[rxNk\^Pf f nz,?W1^/9:;I칳# N@,}+:DN \wp5͏HlS'`xLR)eT9FvRSq>i"^b|,o7j@f$ȣ?[t T='>n\ @p A/H㊠$,[׷XQ ּ˦]g]F;:7Ι1_Cq)YZ %RgSaIݚE#_ JOC9Un*%lR=*$/3՛'0G9ߏ!똕W2%K;[MF6bίOB2g ʍ)OZ9QQ0:ŭ?L9|EG0ϣFOIPs yM%Ln،b6£B{ʸ=wBk2s"^ (Иc{FB}fŽ1:?CĊĪaNhe9ĦJHY.v0)`JGV۵=H( |$Y1Y}7 IOS1[ X !ۖ/Pw4_κ""k_NKU`ԘUSgXCɃ>?`ϙ4ge}Jl#vFz |p tt;,_[,vqIHǾAi:L.i4R*wd,(ݰ`;Xrt ,m%~ $t)1&JS ?hȜC\)՚HvU1kй_l ޱc1RthbhLP7yļ 题\R܄8iw}NgzT6OfU=3Q KĹp8@ Ђgjidcm QlE b'ZmbpuI?zڵO0Q?JځUҶxQ?,piß kLxB#~8|(Rs/Rs'f\_}9ox?X c.qMN6 D%67[uf?쟨+qϠQG] ZL?QRs(֬2Qa=bz-?*C1@3ebWfm=1y Sc|형wBS |t(/Zn4HI8Ԧ%R0o2Drׯw֫[b.P?]mb6{$?#lTje׷Շh9$ɨ:<@yەE@qե% TG%".0+2%NiG~+"Du3kT "n< ٝap$mRP>rA8lm;+BŲSr3jl~[3 f]jhYb3mVkƼ>V; 4=vg<~YizgA*osEϰuO7:vB:]yB.|s[ע?a󃳐DŽqDm=~`Y%E& 'Y\Mg1!no48ϴ5#jxwE>wɢɃOcU f]rPۛ$oz;:!S}]:RaH;w؉ dKu}&M.Ę,]0j@VZere f$- 8)0 &\>!8dCY]"pNuIW*AVU! kַ/roV4>osD=@ VK:Vq":pj cA2 _'G-~|~h.8,fv&64{ܞ-[WT'j1ӀuDZ>$!Kv!g.H_:FH Fϧ1ղ'_ IH,Ŝ( RW̚<*9{K̑o^9$0j+v 8Nދ,bض ,M ے:(<蚕ی 3n.Q6 F%GkjNjÞҝ Emj 7r' œ0re^{˒'5?ǫ_JwGɎ[9#e(.O}kdXx]449ñ3Bw)2~rxKm Oi>;V5oGq&O{ =O!YN׍?3}^I>pcQ9%Hͱ8ЩC 𺺱z*ZU+]uȸ(o [o~}/a~O'ZinSߊQ1uhH0G: MvNLu= cqy'nfR*^&E窥zפe+.`鿿?} JhNjKWjvk34N6S >اU **G%4xsC}^bRJ,V #&~ MӖ }Hy$kCqpyKy5QfsxY<J5?$ nRK6"wOĿ`Uт}bnwa7:еtB'ARk׋ H\Ow@tu*k▮؆hrjV% {#eQQ;߾PN -oڣtXP$IӸSW RlO3Uc2j M ^5H/p)bu DۉudےÒT,[}yOdD,N|UfHE 3!( umh ̑ash:CtVI)!:|eֺGE]hlJqш-6] Ek= `-kwXh"P3h؂Aoa}E+`&Im(ԪfcFK{qIn 'L6JL>.ﴈ޺ 6U`ipk6 5^DzsV#wnpﭭS^qчHC #$ ^x/6c7"鳡uS0Õ-%jQ(zK둓q&\*p?ꡜv`MbChX#&-Z9lhFzݪw7h2iN*7C#.,{l9ʎrfMwwea ѸF❞  97Cͯa%p.>OX&I NiIF)o >42fQC%UBďW7W>i x3+5L!6IjTW(_}A+Qa&]JȖˋ:5D֬q{GiBVGjG*Ή9SO u~zsEߎ<`1n?f"@%ysVҖ~7Aj̹./dm_s*WԾoz^vg3PII)O 6!* T ^,Ma.[ 3r5.acٶWծ NCֽaOε9x&5t;|#'fhRC&&!#jE..Zgݖ}]'KLՉVUwl(A2CsLқ5*\E8~l#&]eaS-Hvr$J* 9LIGPyˤW\mJ4?ZL#! `GIGe3CHu0LoĽ\14'Xz$Nt6%m)ɆhF]:$ }@8'-1ދ)M=SL˨,.p1Z 3y<:4ʐ as1vM+gkeq\ :ϡk9sY}. o%$7U5^ }.-$L7-@PɢgFR#nyKqЁl.5z´Ŵ@Hh"}DJD] K{lѠ 1JK!þ-đbeдf[=uRƎc&mtk+_s:}6t$yy>}_j,?TyS ]p}rzWϷxLCL-[BO|TۅtȬ|]m;^ /?Ճ]G+D,7r;0npLhdePZOxp(G'sLbW! ͡Rm uj-- ggx ?_CxȲǎf鑓 22oy439cvw *1=b9ܭ}e*" ue;[07s<1Dh #QΦY/:5?7 Mm."6ﲧַPf5}Qhi^kJh#ZR=,Ge4]2Y݅@ ciZɓ7GVyKjJXwDŽqo1ڳUY)DEr.Z7ArSsR'SQ'ŵWK &ڻ1RQ%E.f+T(r~e-_@֦h~{BNk -}X.I۰E@5#<4IُWܷ>s+ZBNQf@HȻgLW7Y#4 @ۍvG T Z SQ}Nيb.\w5p'E y,w1izY?}b@IK;iQM1#rFQTHfTaw;\ e ߔɖEZ貇nDLέ%"9ࣹDBjAϗsͪ\P0ۺ{b`5~u3US,Z3`[z&IȸcSMRR3?]eⵠ#2e "12#+AR4LRX9&OjOiqf+Wg*3xwWnd^/[J&Y2(!B9(qqDT~~jR]^@˜P3aw551\}{R]]۪A4E lW P>GAskҝ_^ CD\=CcnB\]ݚ*­G**140V蔛q* ymLߜ͓ƲhF*"ƧwJ,e@!I` AL€'[ n\ D_5 fH^`ZwA߸o7d}} 0۪lGr.lƹ>&axjh鉊2SJ jnO&F6 ),n]mO8_/5ޔ*;c^_5s$bOaOѓt.ȺPT<Ga. Ht/֞EFˣbV8y?{vʣȇYmZD -;u_tT7,}Ðq  Uruh-8)U}nʦR) RL}M1sP`Fmkx xāQPe/s y[<}W>MH @@ p8=&JQ:}#;߿Pw{xMSnub R@4fFA1<-m醷ngܗ3jKBV0wksj-mBD:]ը zSqLEeW9EʺGXС a² VĩO;[?2ʕX6q7a3@wXJlنiׁ]qo2t7DT2n(td/ԉρa~AвrY="PEz0% QGs(³m5&ʻ{esUx*ʆSrc/6T4jфT[E4=1h]/@P1ifJ2BVۋrk-߅M|,5_@{ ژ z!ڪ̘7J0\--[Gր <Dp6i qEM;cڄ>y@,` LjFXV=e2g'ˏf[1\\gSaZW*YB7?SOKS˒aN_r+U>[w+^GO4[NP+Te[l-ۭ,p\!4mCl_mj!5#9{c^hC\S,8'o^te;zo ڞS=³r0|0 Y0N&#~c^R`(WSWGu`0nˇ`eA/ 6U8ItLMNYA*Hu\_މ52 N20M{=cB|ZNUClxRv=9 oFrӘ_/ժžJfekܰJ:Pi*o42l)]q8hw mP 9z+͵qʡ8m aԇtn-@sus 1>x1(^Q6kĹ0wU/AuL~`ǔ~D= Js;53b HRw?sֳ$b6ұۖw A 6DLLQ]z~kϏp=Zb:未H@Y$e8#)= (_͢m&jt捍'-?:nGp$!=> ڬy0Qv,w>ۃf諈 fRCxN&Y Ԃ:zG^ݽVg {)xޔbm_q {oƅTI,RN-<0}FETC&@ o^K5"{#b62MVhr\+uji!&9TyF˛QR4$bY8+ ." z0 pGK?vHv?l(ߘasQk3E xQ1 ,аCHu' pMr\!2şi44NFeɂhY~`keB̵'T߰=Q1*ZU*Su:1`6'_[6 ;z_*⁖ssеR?/9037?06#`:^,p=v\γ նZÿ/m< H83+a_g. B~78W2h%J\2ftC5F*" CFDJJ*\* 3'_ZP.G&z 5˧_Y^SBsU&jZ |A\:EBB{Zm! ?)WR=ƹp4RGL$Kf?*@iPiji{Hӎ7B'Ϗ &', .:~ ȱJ2SJy{ uo6i+I6:@Iaza"aSv"1CU'`_@/¬! }t$@_6=dAI%WfP_~܀{0{7Ѯ9Qt!r=/ zȖ/^1 ]H=A1{q£.6$`jLUybntw_GhYj3i .~!@ Oi2 BуQ̒m jQ^4,QyH$ԡW@DUgG#Mұ;z`7;0~Ѕ`+A:| DwqW(U]U{:A^K^*cPQ>);bvU%jdjSB7mJ5sm9t$߯3#JqrHWpIm4-ɤ!$QēuFU8D}Khp*Y5)oxp*hER(7%0͎_oǍ)skb'aRSX= ƃzRp4g#lޑ./Mq|LkP)70.xdlȟw5W2z|;aI ^aV&hN;.-<~r܋ʨlX`[8EN~z+'[&JG2!*Á1A'@.l:M?ΰ˪)(rdCVL 4zK;<4ѝ,m0xJij =1#1G+JN:ޤ+j 7]O@cE +sKw @†:/f PM &D>8m[$8SzN|^AKLp #3óƴ//9r)J i$P>c 0dwWo|lEI1JIJpt[+S6vɹd-Jh( RF?:r&LOuV0) -UDARMlxȕH 9Ĥ V7vvD-Pcز΍/Wk5]xyΦ9_q \ fj"R<н OS%@F^͒IJ;oq^I v+fx-Amׄ/' f~\KQE㻥2eˡ{.d} IXq'/X_*i-ns&,V^q"Qs >VޙPy Ua:9AGх<blY֯Vn5UӓW^{L3cZ^[n.3Ē5y8>-4Zɸ"lƼ;}Hұx\>w`U!0 1X,N|mencL{^9'Ò.X '?hRO'\ӏS\&給̅;m4co*;)Bv9fN9(D7&6^XĮ#]ȝRUаK1GX}ilQF*OLM;ggReqU^rXh cE$3_wSҌA7xPy$iW+'AzAePP ׆,!Hk{G>z9Vz -ψ9J82Me;m#O$)[Џ ;4JufTݰ_ad` OmBd3|ca'҂EMovtLL]lltHhȅutۯ8AS]d>%MŰʊpŭnNț&ueS'~GrvIZZV?{8'T ;&^e4zĸ k>erb^LjB@06ь'֛lh*izq,$;p4< _[fnfaϥV,Bxa`~r͈K ۘc\RX{R2dḛw/aO1aR(芓-ig㺦uI0`iJZ/JYMKl\2JJ$LʲiQ_Vh {ʉ#œK'w1XR.`\ ҹ.$"8vʪ="908?\7)y/1 8vlWLK֐x:H_f ˁ M՞/ ,r#,?1l(AƁJ<(3c.,lV^:8DQn5mƗ'VO 3`uSJk~u>0'&$ }C(BEbYl4S<γot fKxs̭as2Z,q5fxTȈB @๲L )u힡1U 'Dzg0҂ߥQigwd 2BT~zf*T ALɰW GaMhE2x$wԼ- IdHY(@DJXЋXb Lw7 'b,\=0nOr]kCuj+M9N,E>$xS~`;-N2e Mȫ^s޲cq2N[?M>N 2_,20K]07P 1mNoNJ]zÑK)Hx+n? FߖBjA<f,;*I& mVn,^%K,HL"I7~u3TȡS>>&7|P@‚t{0w_|$R5g}jRפulNÑBejkvyet:'-9Sd<lU] = $oE@[sdt+c@8;v T j{BWb̡eMHn?{LgJ}" ۮ8ӱ dG]m -QY.Yɒ?U@5gv1ה_675Oxԫj-4⧣2B:]5~ZcO+Xw{13gvsM[%'JoCOmbd} t !{u|Q|1AruT: x?#*Kqnϲ,TM=C_pJYb%fQjUꗝ"} !}7Չmݐfi{ xL&}^: `e%ZiWS4v4.TNJ^W+MqkRZhfIEL99IrmƵ9L"so!3Nc>I Ŧ~rB"o >jwNy{ymrH@" NagMZdi[Zx}[8ֶ0v1k#+(y)=53}wl)!í1+` N<-f'8\v+*\ѮN2u҉|S\[bjcN9 me|6E○@!')xaiI PK-uEk.>D7qaM:1dh0YJ,C&W+9n"tA2 6V2C6 7 A:#Đ.Q@kFrpO}PP.$ QS@=9tR n>9<`7nMn br>^Y6iScX)c;q {4IPfKz,.djzvƎ yNCCsY l[N`.B 2Q됲]NvɎ.$'?3Y*']]m$W`"1bx}Qhx܌R6 ٝ;#g!0*OwQЁ0zyMpA;ŔIAg2:%<8 Ag%ʁ!E@Sbn dA_äzKii׮ssR&Lw"*U\oe L>ʍx(-AU0>9 v`S(`5\i5z6?QFG#+J~ l~9b#E_/ںvWE*60rp~zI$[IcO0T#*s y|ix`Uq+`D^ /OMOG1+MgX8(hLg`T:ݮ>JKH_5,/:T=nf>$cwЈKWnz;a9Y&j"X94T~P^UG~bt \ة #7* W ķTDb۬Զ7wHճO_tڪ 0u֮JoB+3e2z ۻw=-T$MVc -){Į M.N[$:/&YvU޸2cyeE4<׻w0@v!M@Y&̦jCCDjZvŸ/1 e2}+Ew! Dm56"GDQq? +UzbQ%(81Q?Efo ?[4`-xuvz8|C;0бYcSp,,% KsY8m*GDW}%e "E~QznHZ_}u_~9#~V2PO g8}KbLy/J!*"nPIgD!(.c< OsW?H7;W} .L{2( L,\2W`]43Xz,I+٧mvăK1|Z VA(4pWAaE(*F[ ʼn~L]sQg` 8RUvX]K. A2똪ރp/65LSIJaZ!O+?.Fط|Lrsۏ 2*khI-"SaOGȅO<y)NT+Ew3\.s\ ;AFط;jxd$ɷP.?c&<0V fT4x+ ~SiQʌΑai)%,Ù>L\UL|i2F m~t,jOvxݻk-߁}V}.d=@k"~԰u^zn\;#9'Ul'ɛbv"%DYH&Xrד !XCS(kLZ Rde10-[~ <.' 'W:e(GW étS_RYvq梞 I^߬wq?FrY&,q` Y6V9rRf߮!@P9Lo1@z9sCHt6ek%1)h#ֺwlNc~vE7 m"F eUkEQ:I.*ý/R 1i;|13hĆ2? %jG(RjjN:^ƈR`)KP#A 5Ԙ LrM`2&$QoG ߦ5oAw=z1)Nf>OJ(oJ vJ`@Gɦr`-Ta_̅snp{sK/m+9뎮S{Y @Kd/ƕK7M&&$;К#RSXpχAB%lϼT4%v!'ӶG}(1K$c-i)3^~H;+6tB"RZGgY^|=AvK[h:\[kCܜM@")ݓ"7{PIVFO[LJWU~_9 )ὟI2뿏3\h=>;Wi'x`(0Xwˏ u!JtOc;]0O#^/u}XcWӤT){ai$@9_XSFA442zxA{Ў*L;BVt-2tXBB3hDb\7i+켆}< ~jaQ;];(1#5'~ %h428{1NAp N*<ʪdJҶ&XwiQdn܇vT3’1f9~MttJV^iBƟ?=SVoX12g?d֛㌱e~SjÎf!%NpiU$hXcB'wS ({"1:c1/(Lyo5Os&ǙM&ogyr0*G\|2 )Kv% 06e!l۪3)8+Q&۬x9ip Pjv°RߛᝉxG_/Ow7Jq6Ww6t;ZʼTՃ>m1rɑN Ṣ! ?}4`LǢKd6t[d^S|rgL2^E޿fZ Sڃ^=&6&`TAUPyu5Ce Z#_y֔.`qbfaƉu V ܗlTkbJ0J8끵CELDkMU Uhp l"zY?ƿ֌2֚Yq]c_*cOg?P{߮Um$f t$qUd}Ju_2hOq *,{"D3()vwHGUi;-^%-390"W4O %)[Lg Q>r|(FPWؿ3kf HX oFA\rTK8n[zUA4¡D C\Kta9/WpbWUg? IB}t6[p b0ܘHK;\* 1]9o@&Zg㫳!N莪^o&^4;p9֌SԐ=v%"Mjsz.v$)آp5`k }07oB*ge/(Ҳ kKM| HL_=>j֣I9='3 =(fflAoq{& K24 ;DڮlY XEI4.kȋU#W !a%|{ 7#%LZ/Ӏ+} Ovx_>&/Mɜy@ZH]^ko[ۈlR<L+'<1$-rW• iZR\L/o՟vtvdy8mB_7[Vd_*Zq|SE-*9i;s`'wČiAٷ(,N}?fzk ]6*!gpo 3',,"h02據 OPI;'0䃈3c yoo H-'^i8IZoB j!+&Ku .x_VFUc^%ܼiICpiOxZ;׭p=H]9F)4CUUh g*I^\XM>eґTU$Z_=q̺f|/ .ʘ%VbsR/Nu^>nAOoK.|Bz(!Ԫ/#v+¹(?KlM*خQ_U!a2Dnc5Z{oxPTVa'JP{Z^ _"̯s_} e4xqiDVBifWC NO>taud8FLy2"jV{ D%Qy#p$}::NThN^Iy8eK$}g5E6M0geٵǟ2i+5;1xhZn{Ϗr{`}&THf?hǿ.F7e*DX*j2SMsF&;D]n{ NٛRðv^ܜ;#ni/UOZC/A؆W%_ܳ=nE{7Y88WU[Nʍ_P/|YyL26v~@:BǛ?1}Ay*ڸA_gXF6WR bP/0ʦ#uj92KosCUg/:<7|YT;i#YIbl-2wrϮTV?IS"b"e\l|%LW|Ve}W mNZTe"<_)b=$˧!Ja[3.Y)ЏE/!z nj 0kP6ME?5>d76++pس Wq\@g4&āEI15b_Xdi{,EUMA{U}cK}k9"*Fmlc _4KC#sa,v'{(Hxdk~BS&PY(]`CgOdN p TN.1#撿Et{l(:97߬te4- "9ى?̕J(A*u XԘ8}2nDUmΌ@xAۼx)k]]C||m'`êfx0%&&\}r+`^@AUlsISۿ^[f1.pW:_d3_aIz2pFV2rO'/%_vev(JV.1+J6TPUeS ,! aM-] 㴯Xx$ҝ %@#ЖgDw>|0&W"qb=EV˹/_kI!~HC0椐CR$ qGJ0&'cO߫hWzZ8"CBY[x:6<:(y1{HE!I#)A/ f4$wTR(_Ƙ_o~q2+Imc66.. (xE_g-zCpa%o(*HWկtA 6D%| hGmFW@P(?v[{>ZLcy)hkCE2(wNCsFfI\ ꐴDoݧr.W$+y aݞ2qg \*h^|Oe \{^W dcQWEgHz.Pu6x!JM7ed@L圃ч 6ds쌗/6l(u1Rr+3ݞZ0}B9(4*Rm \ĬՆ"fFo\V&1m=:lҶv#Oa3>TFȥY˷pqmEWgr<ʝn@`"JvkMXeF[^Uف[k8v5O-/ uT n/} t1&qn8/@ +B+qaL֬`8|*Т3(>,i5YMoTw|~\WjGl p`d$#A4m>䅁 V[Ŷ^jmC2gbe`0yc/T; D&IkחuFS32Uu35b>w;d}j)wۚkN*-]2gDIofGys8TWsz{Tl+q+h9TXz~_Q֬PӶ|;qh&mQzw}eygH `t0 7.w(--,1v+)plP,<3Ǻ~ 7l>YQJpI/<4J,U7lŴQ!L8&s sqY abڝZuQ(ww+|T?3ci$H.0S7j-teLEΪAJ{Xe5 5О1N yQc;9/@Uayn[\o^2Aѓ3[9̑vWJE,/KL,xuCʎQ.[vȎXܣol̲+v<, ^m\Һ̏c6VAi7 gN3O螦w>D*qOMrV,À CmG6:N6a2*x:K:ʵX &HZ!)x%;]͂;>Jзh!/\E;C>6}t^\=V`%}9_=Bm9iJhG>.jOgOa&J 栃Q}4 %*-J'ik?Cݲ=6x,tZҔM}j uĝ;q;,HGa$qr%(z~bu?'I&C23;K JvtT ԈVCؚU WI?wb5A"p-'`@uh&>.5~ot= &E#eD^GʇIIOB лqڐp)./!7Hﮩ.'|m5.6X/>6ʹ<_Z]B$2_qWVs+:nN*T9rݒIb4C|qǽ7af8Q*OΡ Æ."i>%&n6=KWƜ|Fa[A2dLOG6 Y}DmuSSm@+L$>w=C!8<~|1731{܈%])`fU}nڑ]em";ӣsr}&7#u_eXꭵY[q;n֝u9~ 9=ClӁ-y坹h*A6nw'S׹/cҚYEp#qb_ U@}!AR}7,3U!H>]&0<'mwjm[ Ƞh!ԡoQ.`Bm!Vp牯nBʄ9WҤ%$w{_pJhÞeKG`p^d$,'moAYM,H KJ༟O C9oEP?ZAwL?ޅrAMKŝbli(t(̢bb~ )}4,eM{4$00iX$bB-Gc;JjFGQ{X9)|Clå'(j%X艗y4↶ÁnLAԦw[݇uՖ؛RX1˪G3>EO#5~ 7 ?kαdcC==ua"! r|V@(672%vA1dwBH uMgSvnذ؇q{s 0)+ CI1YM\SD'lQВ5K$Ž20bSJح:qhHQxHo.X>T9,yCw2Q4׶39ғvV3zyEd`+[pjT?ވݰ/d}vpmMQdnjC"ޔMrB%-Y 'C)4ui6I6kۢvx.y%6qO'CWWN 7Kr2ߨ*A6w8ո(@\5d jɝ%Pt"=,rmZjӤ}gIQ#SL~ji*֤8Dz*mU_vvuNOβ抪" lT-a"9 m,]\T)΂ѲWPX"G ;ScfmG(x$ ِ P{̻~ +&PPyO]f;k?~iHbm?I%T!= w7^Nfq/8̏Q n^5|gTeÚ ֺӧ!sEmQ t.`~s7Rʆ ~Mn`ȹm\XP=r0/X/ Douetާ>L 򁰲 T%ʑ_**C۵.RZ _k5E8&iY!1?"͛Ag:vFO;v%qMѹ1.<0x0PRi肧93A"˒٠qN}!9? BIbVB7WGEdت ?$FCprɬ㪻TP %5z[>ek ^ǔ]t yJ۬J*!`7 *'MCSGCpN x^3C!e=VopThw3ފ˾xt *aX3 Zq4v _t 1GG7ǰ@%(6GF:C,%DLiIQ0;% @~cq+7iV v x}%DBFXV[lpWEsoƭ&VwO(6e0g,>rGыo 7;.Ektr|tXrnB,)'С=9Bo|F9q:EUk%T1) U9( ^2QlGGpچ%rj8:.'%y)v c/ĮZ](R"e.qGGbUbf>tsmUѵqk {k=hHh}töN?:b%nnn ;IR}5((j)%-_;fnGћ 9"ݯ~zb %.6=} ;ʛ MWBe/!; gD̖=ʟ4Hzw3apRR_pi2-p7%υ'cYVjT~QΈ^ 5ϫ<46'Uw튛 8 %X2Cr;#~RFS'2O u" j+04k(g^TPgFΝ3^Jk\j7GO-R<G,𝝖=W^OE:d[(yƾ[ׇ0_0(h`٠{/LJhIljNt!#0w1&?2O,B5d~KX7/gR$.MbjUM|ݻ^Oj|hiD4WI@ȣLMiwv͖}>g)>q${;1>__LcHV[Vs ;Ig5 h_Dzӏy=Xqyo NYaXjTWr;+9څkjqZҺOe KvG2Si~[<4.k"JV53]]VQ{*E% ]6A欔vDWZ m LIT]ِ/KOQfajJXsYM\=J /C h*HtW\$@JVnvV!hМOoZtWf"y1ʤJˏFqvyn YAD@?+̱u6h2f\ 6G"1k )JXcp'A4uB eޚkQ|,W5x(sєlME&$:d?,Ka˝˜sOl/D<=`7E HFrwjsYTFX}-U3rs8Pg"'o (T-=?L7 r'scZ'ݔ2}&TLXh;?p瘮S3SI?w7CFJ"},#j xQz*LmS|c%gQḀC j";:YIib, =jAD*BzC)≆QBwCqv0FؔG%3xVm`HI}e̺>CCHgn@_T!΄?&H{[ofjEt*:gG*}">Hb|V]3M(_$Vy')]E.A'[ar*~X/-3fL_n +Cl>,Ƙ~Ѿ4R(^A5Q(* òcJVc[2i "j|:e<=D <bUwuGBD ҙx ncp'V5ϯ>`=/ۡՒETq S71#O0mM(7&R >X@% ׂ(z(ZhhVWsGF_/#pBvLG[@:;FEPsWBrf;x36D158tNM˯+A 9 0`{2t!eބ2Ɓ?L;с^Q)i~8*5M(DrlvG spnh‘OrXkGEӺPB[7_a*KM'sh; (bøf݆inJ ^@!%-_~ G8Hk$5VEʽk/.eX"m\~E0˘udxvqP8kK#_C 2P>6s յΎlN++w8P(Pbyo=~}JbNpun:V_m;lH`7[Nj6ʫn̍xsDSkRQ$0H`X) w[V}вZ39#{a)唂g+2:@j T5uNgMmKOg(,0]wt /8Ɍ$ixʓHiU)G`"-"v(~ptQx 7Ø%c~+B]'e4^>51x#<3tR&5j+5l)`YƗXy\iU4 M|ʀbI3R2!FǫʋnJVKgsi$a"|;+.׭ut~?W"Zxc [oD ;cd^Oa)q RQ6R(d'>z :Ċ@drUX.MGȔX_Dv7u߃ڻ3QXs,byي|8hl;c}4W Q`΂*X\(]Go\5ejVqv s"х+FI\#ſ1~3^4]-ɈL/؞}^KVo2in纕 Bę%N6+.|靤OCi۵" ' }b~A?,I\'Hښ2dZxToٟVۖr̈ri˝[X/`FQWٌIJu۪nbv*rG-˫x)煵K(}D7%$: Y1/Zx׶!35 A;RC懻w &-]qyٔi)"]:bVr =T[3ЀCq/AO枮{;ގxUV˜qo1,i vcW'~ NH|N?D*ɨVsU  a"C]`HB}`U(7-{{ۓMO]cL)cXw'ł'HΦuG}>fJ+&踳*x1Z)j4JG÷`^&~aUiǥlv:)A靹mt!Pdqm(s + ^Y>#Ջ޶E=j*2݈+C:) xuІ!W15GR |UA4ՀjΠU=i3},7S3Sa2%/qm;hKVNnPRdƳqM }Nrl E<"o hDm"_c!Ab y| %_mN8F8X RC@A @1#姪:$8osuHJKu,CUG]E9&,L]0^9|W`d6@b%a}7^ŷOPYLS-{" MCH)+`Z[5?w/>՘n):}&"79;su2Jub&F|0}V^!初 TM~R'T7 9eNШj0⬐KYyC7~/Yru"tAw:M:y{< Ha/F< PH˥8hs!s-;aJH 9: ,[g .R Nk;l; ej7^>Z {qQe!sR1u84nO-rg 補 ]Bsa[k11͍ 6kw]BzlXв}QgX>ޠD^DWp8EWE=a<1rm5o+M- hN͚*7gz;1 EK|`URǭֈe$X =-"ײ\uf*G*~TЁf807<桴c-^h"B6>z$#^W)>[fkW gq0)9>žj_bb#nWHI @]\MbF 7yL{Q+*H &mmJ^ȊK1ihPI 5O9a*uwmrADrfF! OImn,JDҳssfC.|H}p{#k5Pz?)eJmpZ4?cm&G`5"O=1y_;1,2yB?4?EaZx[J5YĈd\0.!.8mkq=m@Ոb+hoh7nE!6x3\+|fM0AQt7WPF$.8n LgY4Y̶V;l=hG!I?=l%@AK=GO1D;'t7d/imbsbo 䇺[en)@ʜG>/Kk]VmٷArd,YH1!>u3'V ]*Q,|S"w们d*`.$+sB(l ,5^@6=ls-C ]LZmwǿC #!23յ5tjFSF`K2Xh7/}3=OUkznjN~dǏV5§ӧ= ^J`ZpY w&}.vB Vվ%̼fg>cr5 Q!K|°cdT)2=%0<R{u(% mY&&He@ ,+5,\^Qvj dK~[;F%3rmtdEw ]O3]Ϋ!e 04F4ΩTu &Pqv*@IԸ"`R7$n ` ("9x˶㐹m+7uy|xm1 AKzoz78nE-g˂UsK'3K ͱGοʓ[1 Dn$s=9 (Q/bփ z9jTi|4k Hd(֓p s`z(W,fKFZHP!}Ė,"Y14Nﲚhi^0 m ʘ {^Co?4MaG \lkx0= ƙT`~5 [-V!Y)BHeWEH =Z_e ]Mg2^~-/3\wt]1kd)3rGvl$B%O+`To΅A vam^TkϚOhc>q7? TvAÙ2_TOC/9X?%}cui/v fh᫚EdAnE ' >@p_{=65Ә۬3Z%QH?x=JC_ʣaevv&uĞQRs\@0HwK3+z lQPk;? SR1ٕr+v0dΓ)^ReL`kI?ZּUc+|݃Tm.4F˴Z+]źqOFr. :x;"omMg:"aʎFl4:WVj1w1f>ٺ~Bo zV|r ;pūt+#N9R?TR? U:<)׽Y,u@k ffx}W 6˓ߊyOH47K GјkA#͢mS`͇g ~ַshJ7ܠϓ#ζX v(\<,bU|N^בI-dӳw>{u[Kϳ>Ug(ڰ[d8\o%;TmyJalxy6_͓]<kS}s>L3{7epbDlX[>~)[9![: Ml{JC[?J @?))M.k4'%VH*&`bsg_QiS/M?.mCM C _b^Ndf@T<#IMC1E# yTŝ R?([,8[onqXW%Ɏh[X*SPFfBّa3x0'GdY>!#"2LzfӴ09barM 'Ŋ.N !CXJPd6"@)αnG( bh˚J%Y1Ga{r6K>drHT{MWoիϗBE v';z› !,~s dX-<"|nDǯC*[`)+K`kt CwC;kI'\}gmGĈ_XSEn*YՎwF|`0<_RzP&;IDUWk.TE{R~ueGȹ taLc}%TBOORC8&ab^>3T &{zާT _OȆH  l(G:$:Q:aaPꀦ0Gi>RaB:=2@4{W + ?N= =G)Q&J&t069Ժ~@AXpOt5gzcr+LZg1=7 .|љ%'ے1KbHVnǞ o9^}0d\t3<͹`lRp6uD9r'hKf2,Ubw?W8'hSZ)l3菕1z\bO^пE/{~7hBQW;{]c64I4X?kgxd6qa6>45g5w*UL0%u7."yqNZzHac9ad1KdSQꑁ7.48 Ͼ 3͌`9YW\4p^L#q) H=4il9ܒGu+ ;{.nWa)j-[}Nf-iyǭS-s(:FXTz;ړ.;YFo*&Aj+M/AЦ>W4( `֑- 9w)ţVq%WN^0P` D&# K'ТU(+J Q/hZ'`J zHh.}4M, w bF$;YRN?<+>2bլ_` Fhc3ʘ o7sA(lڰs/<1дR4d;V}aQ}s6Ӟ)[|^۫UQf5,c5LJ|Xfoýe&̞X XDh3$J fPG? a=]O@7҉:oAZ.>b |ݐDaLyчLK'd1z`\F *Ol6fkZ`W1Z7fz`%+Ɋ6hICĶ#W70BW׍քs}!eL9UjpK*(!7og Hj Ѝ?̗R-ͯ!HOQ[c-}4d+T)\{;t疾!~wа("g`$e8@P4?c6H FR8,о3qN[i { H,.1&4ή@9ayA+RfY7KV?r/GA.'/¦{L omM75=zU#s@3T.aSܬ;?1Otvg2m$C㫛AӴ Q^^N"X~H+{*p˳j÷h'vRhNY\0O~ XR&aBRL{^"L594_!; ؊lH4JCLRхɉAeP}دWe"egrrA3l4,k1Y䳺^Æ E 8)v(<;Net"BJٶ_?%3 !Htǹȃq@4@=K<3x.T&لDv3Y(ʋRr$Je'CNE~4dq!.qe; ;)CO28zC;cA6ʴsph2$Y@P@#>X Z1 @)J孺D%6>IA [n7Ŗ 3a%xc 뢛TE;@3ń >qx `% /~ٗrM"5Ɩ u`$xϰ&xV:W8Q@b%mƽ(rϳ2~_m>=\'4-@ȇƃN!rxj5֖YG+Ef{kъI t݂}YZL]vBo m'ľ52ʲwLvK/'ō>uaZBgRӣ 7UԴDG^ɚ]) ~۾2-*Tz&l0̀3uKhW,f"&EB#;gpJ5|{N <(eP 2G&; ܦ?_ -V>qsIeY w>w4!(᷃b-Qm ,UQz*Bҷ /q%Òp꽰 Ė=c^-gtW~ p^{WI+7.]CbjH! s`OU:dj+1af$NXJՖp6Ĺ.^**T٥ ^>ᄾ\wǝ)w"rkH1z9·{ƝOJ50V'+öy̵_fיLCq8D.=W{ˌGr:> d.κt~7OݝbB9P"~gaVIܾ6;%U~Qc=٦[+p쿇A웚'q][bT L+E蠍ZсG%#hLmjvhR֍}Bn8"T5i^{>c9:7e;vF$Աa'n?g񦪎V%՚vOl}HC=S]*ũCLFbLDqqp n\A#_QHaRW@BCLE7 {ܪ3;?斎I`AR*34yF^s2,8|_Gyp aFo Ugtj" ڏs1c9kҙD"}n4ѥU*'|EMC'U mEeD,'쎡gprv+BBxOδ ^svM KӳMkż.cE Ek!4/b7 4zVE ,UԚɳg{Z4Oܤn?"_IkUӏ.TD\YD>酨vD>  &BӬ/-q;'LA7ECٖ3Y3f4C}l<}u+\,偧HT fNS-D_lMIZ"b; fKRj?tZqMP&G")݈uOx=8T`Ql^i?'jNﹰjvUxHOȢ3~ AC[:Gv3R޲ f/ JDGB6W#B m\XYN4 $"VcJS ̐yY9QfTtnK;5[ ~`aIl|oqIzZ>{Wת!#/QT2oqp//DЌꈲ^aFpg^BRw.BښIUd>_3'݆+sK GS%~ GX؏ B3?c"UGYӂ H|^N^mJLz1?~ܦγREqfLFX ?L74s|pP!bEPd|)'-nu18-%/΂ԧܘ{ݑu1=\h D>ShWvӄؚua$Y 0grT:$㔃ٛr) > Қ$)("v4P911  M)=O*Cж{`jfP͜H4[l1-fl]qӛI\%TႶS^6ce6MbDD#/7(ѐ(YAo9kE`|28մҬ,<ˢMX70iG +;2IufؘCd]K0SЁPI'ݫ$.zp.[ʖI~\$j|йKΫ)c'-6X;\F/. u۱ęa\3Y~uyiEY@n5Z~cLQU{4fGTVp|ɖwb _u4i=l+θhnL`j4HXMeBupk0K}KOpDW8}$]|^Z8ڏjŅˢ:J[s9+lLS)m2=y%ЊǬ TkN܊b9Z^-#%bOۚqt4!PPcs}p^[g3wO$ا2m@[q}~B>w_yk{laVCuY(m$猈T;y\Z=S]fjV]q埪cKO%tO.FD.o v4S[pUPSk8^|eodr1"{-K@T}j=h.ztMCp쳊|ɳ|"]pFu<5mHD q<]p-# <DRcAB8Euo}J.O5b6> DeN{ #5r'wj }z]&-o=[ lϙIl)nKR@6A,",O"(z`|=ؼ/S;42_KXmF#3 ^GjP҅4nua.,`AG$0IG3hAga%dc7Pk8/$xȦ-odCo9biь xx,8M<yF6ꧢl«5gpRy;g\9teD闟bD PwWk\"T3Reɩ{Ij(P?]NwL[. ]Mܩ!w {?%)I2M6@hE*Y8=m_JYv26*.o3tWlH5BnS 1 ȨnRkCy(TQ%#=AD6Ivuec Q}12B$W*YjAoF7W#9[nj tu ꂧ!C%\-=/VFen(;p^Bz,Ӳ1Ƥ hǯD; SS]"_F-+4Ǽ)bl$SvO4 '(ڲi9A^+"ݔuk{Sv<혈U),9SeuNS#R5 E};קk lcKfsQdxw$QKmy]z(@ξ[6PNKȓeQW»=?bPbD嵑ぅ,.oV z9CUےK8LJ9e7R} FipKo Áe  *|neo36T-5Aާo U8/0S :Hڬhr0٭F%q;S~@L3ajP&xv*B4X)hQfOEqE&QpJrR):㜑>;\GxH 2[SV[xknC.6LzziR_Az77*)rdHsnbþe6CaDlopFl$fٛ]F|5S9?3C6%hk`Nv9҅tr=P6~ZCc5%IPJp]E/UW Vu1?U7pַnZdDBNGjt*޿&6Pg` J4UxsLsRCR?r46e$7.uP,Bw8q4,՞3~I]G}T`ZYɉ&W3uCoVАҁTR}& οp|L]|tՑ 4B{OP!X֚?,[ՋV7v()`oR/<Df.@Uf;0T&RqϠәD-5_ vy2^~ՕkЌs-7Y -;;~bq,УldžҀ91>Cÿ%3Fk~pE[oHv9?ƾ: SeZ`ss}$L} ڢH@XKPQ4q@ z钽Ds"8TY6Bk4KD<k ]-M(Sœ\N6F?L|L4Qg٧:,y{٨~$CGCFOCD8iڈ* }G|vD󔚄4G3qK@r'՛ńsM8XC8B;˚" Jd_~qC5ɽFxW3_@.n$&H8njSv3^JGK& ^Ǩ|?~.GlSb3.r2ꑛcK } > [[܁\OQA ~q6 HD GRKnW&qh'O&ǔjzbgB`(ڊq,ˉ6VG{Mst[x6f! uC'AM0jGׅ>Ąn(([hI_UhI9Z:ÄJ\kd7P~^7Uh5&78{Wo-AT} OcO<\AS9u<~=Dn MHGf|p=-;)&%g$@4 8}ؐ@fԓԦXi8SjJO?s$xT~MWُ-XF^6`6Na JI4ҡ>3#^esEs.lj4+ozXqB W7,}eT1:*( NcHEjh'JV3JJmå=Feu]F!Bq sf䀌͟%ֵ땽䮹7_2(ؒiJ\z@~z|-˚P095j. b vuY3~MJs|7g!Źr%W8Ţ46!r+e.Oc.EE 4DΡ&(U\=/dHI=cލwNfv9cF~@Nr%z=A- FXVhCQo8:YnFnհ.p CgG@Usi$5ԲRsQvʰ<,Xh}#N>L Sh{W% *-v]jb'8an2.IcƷ/`~+-[^% /M9GIb۳{3"H6 Ef|7άW|_Y$mfo OhQr"g*oҎC"*)7s:U:MkaFlg}ήUMQ )bzuCpd 5lj{?_88㒚4|#q&\xi2^2^Ov҂UgEDAv#˻öm#&{rS+ δ) ȥ{1ȼa (Bjk!: 22n8YуGe;"}* U| ]m=2 ?@YpyJ=PZ$C>c/u*p#쓠f_пұ:t0r]$;kvZNQMjqcÿ́вw 0ybH=͗h,!k>C]zU. tf׭2' [kM0xsX&<4DƊ k[HS)ߨT#5yq5wG7FÏRn =C)RH2=nZǷCe@MCZM[c7ku,e=xF:POF#,hlASe8n/ń Bb2GTs?Mj 5p"jP%y Eł`ec%/UO[Lw6gSjb.dʝY19nD=&Sg4C|5A.5RqY'蘻e4y#B"m^]:JW.To^qgh^V}ѥe4qQlwoTՊځSRh=$ ']7Ǐ2]d$#P6 w_гMz:r;g d/W.T'>TSB۸\ GnHw(Zl)Ł0k5sZ3kԝkRRW a=6zuB0"Y!0 Ŋ+тa:&i!tf<X1H^_Г@E*Ƃ3V24("uE_ga,f)7G.=dNvU4*h4Y`JF6BePcba5ֺ"aƻ&J]n`['kG.:z[. %Q;?qKt Ӟl_mQHoZaMSDnagqYݮtˠc\6j_QF%Tc2۽m|+a)>qڽ;v݃tppFb_}^'0A&f5Dh/HT#Ǒ (u"{d=7It&'ʍ@T+E()k5V+6i1[L= S dgV]OLF"ٺ[2 %)&٠ 4,=UU޼ qP$y.pԔq[>S [WJ&aTaC,tyeIEStZ@r>g7diM^Y_Ӑ:.]5΅J+`0nىK YHEcj7<nsdBlUco(5/4}<&$ $x BVGW4xɤ~G͆*hG_–O5` !lq=:&*cFYZřiAu >m\n&ǨG5~߅gV#gv-Wem~\w4H9On|2ZP!ލ2jY7 g?r2fXL.^csP6cF%7)j'?Bc2#]pRÞ| Uq Ό??>搜ky~.8= R;2rߠ Nlp ,GPW+1Mְ IZ8[Qئs8c,-oTkf(iR={bCٗzH"gy6~oWJҪaeOvTli9d@NrIS?2y zCer|Y|E0\D^$E=d1,V)udd2c2Y .a˅s4kbM{K)qk\u۟o3j4!cCSEKx]\Z?{c 8-'% g-9\7`H~x%Z+> ^ul؎ٚVjݯzO%De 00)6 M{^{^/qՓp5`~%\,ZwAץ染"Vȝ.I]̌D]:A@A9QbSWoPƕy/;CyfYBgKE8a|oٺ*jO?}c=ʍT+H/~^K9؎ҕպkړ.2[{ZL^fN6X9P]N2k͉lyNtZI#i룥 Fv#(\ȔP擼]%>3cD@{7s[!C'wu~8mՓ8fHBFK<a1 }qh^;ד$ sL6U"/=UT$ވѻw+rK {lH<Hf[q= =DGoo@r$ZhkK?2wuE͂{ө&Xf_|sҙB"Ѳb#h8SҀf8=$.Mhi_0&pfe'>=+CPUpHig MʜGOR{j r`X[l^mWV1 9 M:=?u`5) 0D )@`6K(Zkpz BNnYYpE:Kd5Pz=Ȓsz9`C1R^ Ϗe$0׮!1;BWavm|Gk>ӹ6QCF4fL|dG8}+te&O#|DM MA`@7N=][ 2g|DD(yf{ {QQlc6T? }ɐKDEpschWbKı$#.nr-kQ}SIB7يԼmqz:vm bcdrit`W7ZJT4XxȈd\r*f<"ItQMbK$Mwq=[1ͪ_2dk@@'Vh/ʹ@k@4 i:=@@,LWRK~&Gr"Õ΋!lU$#,/#eh?3Ţ?o@R!QaK8(}L%`-aL̞ץB7oNI1r3AX`m *N~@Zu'qN%6&u3b>(gvHTW9~$_nxqV!~aE轝}`Y˥Ú 8c~`L|81ZPתmˢ 쫢2?Dbt/~EovXѮ旃E *TǜDC뮕oU8LHᅈo$nŊYMp6@r31'W5عsb /ϵd!Ԥ4DNgsf%M9zn gڞOW_|h찪.2*6p?vZJ>,NU%9yg>H DMZ~vguI]gf+!QI&(.O6CT`;5_N 34"6DQK3,狝shO_Bdn?WS)zw $CCV,).bg9owiFeN߉|7Z=ɵzwv1P!`Uu!m]ffG }7"ٝhl+-IV9T%JKF x͠biyՉ k ԼzܯCxD\Գڰs#{ovACܙ\-w]{\<hkxw{՝A&#xi`&.?LJdfPB F] #jt|>$Ǟċs>סPn|Ko 4ٰ 0-O)}7N[)>mϜnByw[,d~EX>@?⼏2l89x:2iobD5̽$\Y"!VLvё]7P?as6'# w!ה<1kI5s|@S}ҎyC$yP(;Yo71+d@D5;G9&dY̑.ip4F61x͑ՍD:(#] Ř1xvgׂn(=ʏ:[Id=YPм> {k"4q^2o#]݄1hMz7 DS -He-`(jt&3^)N|oERi-,*r*Qf8J3A@J %R6 쐧Wz ;l=Z})~5UKU7 3+AG1Ae^ùH&i\dk#qĿM~LkةOb| $Q_X0 )!YԡP(tɄMpF = OUOL<<'iOg''oa\`yN*LJyY_qnx &Yw#<@lTc;EA.¿ "/!CkO"P,np#IȵbdVoOA!Eqz(tMysNh| B[tCӊ9PCI4!#zaiLNd͆gmLSy $bzLPAk+2^%W&<8 L2nK|ɕ#pnɢGAfɿIom)n;mh 0Ջ0ap{Ğj Z5}&WE8?>d,=.1E8Mل"j0^|Ȯ&U:3#ǜZ`o9'>Nܦx2r10l]erI"t* HltIC8VQfS)Y㻰._*7Ux. ;N9NBܚYD˲+W$Y̪v,sVOUC7ѥ\!N|A ǔkR#Yr!/vSuEH63=Mcw \ cj91_c^^e] 9Y3<(drV8d%v.PѤ=mϋZx b9żXJA w ZЌf9BK>/V=GwE#O OQ#m( jho+LCP 4Xz 557/SC3hXhEQqNG$,E>#.}SD!k\|mx^H_X?~;d |_\$:XvZ+$с>'q5M. ߅'!@6,݂ѪZEA1 ڋ6 hu<ߐ?Yk=$\LAwc&W׍h ?<ʍ(j6{bsE:$CF]iǐ܍ =J<$wFVf_C6X4dO| ?[H?g=DN@^tYIcvOL= ,/K 6^P!1 uMh*هwBYD.lrJ_X R~a-iK!n q;.4$ncCg3S0X1\ "MfMg$bvVCVH}HESSKE9ipq'G ‡C籰@,F'2QL3ۑu *ZT]gL̘a8o?[|3^ C4۹ZD$ak``~EVүn-/ D5RƂQC?;ChlIyV8kJp-Ұ<ß%SN DIlzҙ[UI!SaT!5.tk:SШuxYõ#tA`^gͶmܜ%6*q-Ӵ)>ܱ&޴WG` 9j|=f 1>3g_q1¹4hV/f0/&tZ>qPV [Oۡ׺C0sWgsӾsp>= ]jZ$ÍIb}~؋ 1Ŵis~BH=dsș*Pt!jހ1,%_/;F+NOd]M{jd(H"JԾC`m$]Gj/,1fSˤ;a}u^(\ܾ:EA%UFJ,󏑵2B.):XFPWMv㙾?wDz$fwhdqጃ|Shܳ/C9M sd|m3A-B { Yfvy PMNG16& G=c;je₩$CjZO}8%I*5 : k39\F2iZh~܂~]S~=%1 Vt &$8368X)Ώ(;Ckb$U!QNa7T҆A&s*о2-"O0OU:svJV!m[4iC6.c_9BP6'w$BBp4lIU9ֻ|<$~\"xC]J!bap G!?eQ3~1YQNLo?ZCv_w1&i,=,̞O kqCf=0qz0 '1Y![*ӄ*ox;q~ndt%F.RKM8Ņdы mA15 |݀3.J@HZ=+;|T^ 6/&X ; gK1:HMK>&zuBu*S{(RLBYIϒQSĕbx86ưl!&jZ8A=4<*$qKPN3swWuyOL6lʂ#(Iesz G/#7"< ˚ l͐M{,nl)gxx@ 6|)1W%Ɋ~b 獿i"F( +X"¤QȬ_t5O8ep ؀B}W\9j w~3%Qsl+WbZM#;" 5[ ( ?5оn}1"  4yaT3Χi? ?ʬ#FۭD6p^=W59Y3 O<;w\!L=LefQڙ'nqzQiQ*c:\ِ0;V|$O'DZ_s߅nmJ釀D@>  HY'/)[2hoʎ9U,[/#3O i}baZ7'9|{0M~PD 'inb]A۶hW83ojYޯ8> I}]0r5zZCE6TPc>0+ e8vnlgI酲Mw;UN Ə\Ģ! PJD+ۮ7c]c a =BW@q189܍D]dKZ$boDqcbtBձ ݷ^$M-̀)_I)-q}U[yd8AYJO<л9:L *0![g B6-"up~۞5Sy߷JG&3bg{)uj1M"mg?)S_V{ z%/BC1Im>X6y1סA-b.*YyZW6'$pWvs DXȢ= LQ68~%@ r(V(p4~;?za:Oco52ݣ8HKf(F \^p#ow{G='ܱ =A 2JR0pCf얊GAǣӻGs$k| ,A(;ڗ(s:L<6=\dER'PNmDVsw|5b---\>rۢU[Ãy_rc4Gm1,ܽ4z&|Ȅ;fe>+5w٦ S4 >7ipА(ȎFL%\Eۇ#[1EyZ" V7̻/W+Zk.Wo$2vJ}}8Nm>QыiSY۲&O1

G ptߜ>#. u)tI }JDyᡙ,,2{䐟+\skWA׌II(27&83N&Iam~m={IKuyUMlk(ֵMlwgCԈ(33$D(Ҕt´(Me%NkRׇOYWE>{XRje?_g%a&^IVمs=Y':+ J#gAZ}Ț>oEY2)R5#.bX¤0J&$r vzO7 /$yNr% Qta9| \G_ qdۇA⣣Pem-GKdց0J.yN-GU+ ?*;]{۠Iv5qM'*őu[" AG̗зm`7_bMg^aV.jimg^o:_HtY<(9m4C2bk#(=`\&#n#QLt袭^#'7HWk [m R+ha{ȂU|[TBR+&}N9<9y  p* &#ziu`CQ2]ԌclQC6o7rmHDՄ[~rTD2bybSNvkK,~uxK1Q>vVۄy㱶O!5$qIZeѲTԉ%O['N%$i9Zd-UÊ1$ ,g= b$S"P'lGZXsKГ)wiG_4l XY.M'Z Q~|y+<;d?*zOZF`p3-cטMdaMtEL^}.is)~=_K5-m. )C.ksr=6iJ >? Xl}&B>FDcR]TG "J!ZC*+WLt0}Td?dIXɞRrb_1EMcWU73mztvit z|ȕ cђtߝ<顥bd](ȼ4纜O? ,wUӕշ,PmEu_pU L5xo$)Mh.lx]FmUb#Ol2̶`f0%c_9CEKY+R" Ӭ֍<%(.:@Z~x//pM4_*MluR}O= 8%;mF  a ˑk, GQcuӂv7Ft5V*^ '┤Cԇ/"|OvK' ΰYԋ đ#mXlե'ل<89dz BU[oۢt渄IJn4Ɖ\xM>.xv~g͘!qVFXt_/.3NHd\!IKna@lOײGo]q8D^DVJE2 oמ:6X{{\jD'n:#1Aݘ 롃.UKB9J rWr{sݧ}q`KEG{]ǐL.d0恀Q;AEup>{|׫EkfM%\ɉd*b_{ =J_'-2Vֳ{)v.N5e" ~dqdcc@V39PM jݩj^r۔e ʫ!Ixtuav6cWȅwj5؞v}fetأ-S2b {~Ni;Ћr y&*4@๖CJ\ᶠIaLadzR?P9Q5&SXQӍqZ 1,jlÉl}#_s9!@ [F2v&gPՁ6ڃ}#'*]a{hk\R.exuOCbE{Xݚz]$[SiG&)KXGǠ*5g˞ɸGIr=LBu5 HJX+MD]FY5L}?/ ۥ~2wkz"\u`hKYS~A1Vb4U}ힽQә"FqL<)-WoþQ'<%ģ$uYihĄdS6F^C1a gD@S%tGRwa`Syk(>Ss35+n$||*J'bo5,6Arj/jG@(-E  :\`T&b ?%f&JLޚ5*m\s@Vlw ϸ%G_ }hv 0nbM y4h`uqtOΑXlդaTBV7',S: -YXvcq%?mkm@!IwR}߼6&͹zvne5"63t:GtGFlAH24vM% po)x:Megi;V%}G5.&$`J聙$~, r}q82DwrB"РѲ:>d*Oue͡6il쬡0ؠ8`s)ݥ5D\xWxNW"iq|zzjH-7(go1z?hq zJbͿ:NtyBS£wqXLgg> C+[{68V{$zFr;94>I`g (bi3]V]$SIu \l.&&pDH _f%"Ob}C"ż w:kN0tGdN&E[~*?PĬ>'f),y:R0Q,ӔZqtFow gPbȽsC 8iige7:}xO^=wi(w"@FF0@.` 'J%K>T=z_#ح)X,p@rw%EާR OqXBFS>(J\,oAXF[xitHP6P0Ls.\SvhF#]jß+ߠ 3Q姅xEEEfI0vq82a J Țȁ~GL483$",`VcEzmj4 yG&A;㗯 $!LEsERDžVvuŶ]DoVM͎(;!y^Y8hyG|Z!G9"S8e$`\]bcr)?,xj.m4ay_L*;n]q@3^g`4crpZ4HyR0 ^BAxHhm 37 wz"kIN-g)]WL@9VN<1DŽ%V0WxZӽd5É AT]SUl)-mb>ۭ UȺR^JaRI؛׽WL~K;cA:wvGr>.7u!@QOH&_ ^QDŀ1MNǏfhDɔY2RG҇T$,誱}II?ۋ5\'(.67i+qL ?OouSk6PLp;X#e[^ ϰ W?ʶ9މXa%Ę,H;qatD$T\B>>0C6)CYwxK4"՟ƵdmbDω9A#n75 KM-@K"iI6II/hz|B"(oz߶uR':|Uk;m)%ޥ+U"_:AN2zl DYˠ(R` FG/Gٴ9L^wqРJt+Ah 開*?[xrQXq󑷆99ř/ZxW+?%KƸ@,Qf |smٴ?!࢔9}o뒴n$f6]=fϽ z"w\WI&-7j-3gTϬF'@)3zZo\':35O'UiAji6EЬ^ݝp*gl H EXsHR/3N`Rt a{$1ng`GnuǪK_t?HO k ? qj)iµ`NMΔ [&!]G(wzCyB`,׹Q`ǦI=܀ݲ b2B{xF:"!(+N&nx0:@4VtV b;wEoT(a lG-޶Qօ3{p"ix'N-ea߻uOBrIH_g.,WL.}>HпCi"AchAxa,86j @Z=3vq05VlD /()^K׽s H¤VsDծ1qU<CL^)ɛ8L]@VZvk>L x)WY_f&gOt*ay S6HgI&u?2}2M4v fdl{ wNVT}`nZ,VBTOM]pGJV~#7Vr_(_+H5L5[-䝴Jl!zŇ(x0ϘJۜ8B/nmh^茰t @X1zkD2.v̼Ig`eBe` BFAx&r\,&#4d5=6uLDu=s$gj`.4&Gvfg25r&s0,p+sSCERۘnEY}Շ `ಭ#u>CMR:dLc>&Fe+1Am a5*U0wZeݽ9*00H,©9EKZǽ/>?N(.K aLqÓ5j4a)'RA즴.-I8jތ~N/ J&q[k6j&ھf,%ҵPҜrР2{%FDCθfb93#TkH̅)-4G`E"BޖFKI5zeyj}val h'fz  ] يYqΠk9|>\wmbgDiMa@seotV̵WtɎFbh\@\wQ7Z;ݬ2WҶ7CQQb#Ԉ2A u$ı=0Mɼ@7Eh{]|IYPfRr =I+`Db60Q?d_>5"Io>:oO1p"BWpj;c lP#K6nmXXP?4`t6bo1溢CFgw<=hj B5e3}na _A&&9FJE5gW( ! 6B s=[>S==!#jhxPFM`(7> ,w§[.4j]b .9' %ڲ::8#LqVՂ [r7=O bi 솭WREEH.l&X <<* 4X,8]3+q߹~_Ԫ7#cljO&;cy7thKU :#)BX!1zY#&[U3>V@7#g̚A># P8!S5;&yoVюsK׃ sDo%[]P]knGB<J, gZ :7ToZq{6;T]봃08,7ue\ 1/P^@2DacɳPf`{2# ELgbL'8zնPl>eel]xҷQvr'xLy6ϭX허L`uGT8YG>7[7wU10_5@ؖSYϵjb[r"v wUT5+ֹ7P0v?z x- tj~"7H֛ۓFG0+omzl\9FN=S<ȏ 4=іeO={ 2dctF*BzRi k6xd{=l}nݰU龻 "VRs s>>r/o[VƑlҷnR8g5F\^}z~XI'NB`[4K'$S'ݭdۆdS9Us1-Bs} sR{ΉĀ}>3"^Ezdv_%)@vvTey&!ILs3K<7ԃw(h(%r'f:s&lV_ ñ2!'`R >aTmzDI541syE0wY6Ubxr:e+1SB" ¥=3VezR}tꬍCߡ'`@+Ky𡌴j6'&Si,  W3]VňH! ,Ə~fc4ԒA..(!Y*#v6fzhBjL/}@٫+rEr_ʬYvO 3oG: RNc`Al6j.Dd?)(^i<#sGl Dez2$4:a {;5cc8^Zr~y >>'?`{0H-k @ nFL~ 321ujr-ux:ŝ?kI+ *c ii37K٩\T@z@cC몳5H6yybGSâ Sga(~hRPևy miAx\nU{/%8qͳuaBG1ߐuZ:cPK%S3)]YZ9OX݆Ggeՠ +{(25e%&^jR{E !LWG˭x YP[p~A.{p|YM3QEΩGKLkzD 7$4ĉ^A'm(,$'C%}8_CHqm m/w0Ж74]Kl}o|7?q-Ufᆳ?7|1yva^Qd06ޯ%;` |8[5( ;;FH]ȧ:!?D-I'Bs0m;s;fJ;LAz#u#tF I.k0JB2=~%omgTq弢tŞV XԂ8>ڎ)ս%D}`ڞjD~m0jR+t朲gu6 K|#!$TFˆʾ4:F3f /-GS4a&niՉG3`G7KTjB|orr(DG<(k`WSr2q8ǜiؔ)L {_:%xRMw?@R4fIxi 3Gc;PcC!oeWR-1%BޢөJ,c=G5^bp)ne0eOX 8gL1 R ʬ#X0h{My#ܜqު(U}a8^;Z!>pNYٽ?Ε, 1g$n7?WF\AA.\R X3 s&]x O?MW'j,(._AH&V PNP Xh@(޲nBg $]_%{t|) @0AR"Q(UL("a>_av7Y~D'pN9+_a mlԸg }){䤼u}nJZ,.r10YKy/~l&[,Rp ,.̋`etO!O??LƇ߫_ !݋u7UIbPU AB¤װ ctp~F5WxX͠^PE|ÏB;ŨsQFl2iNtÔ @xk`tDL Uȃذݻ%*Gbk%ыJe$j\K!< Uau 5dwq;$mf 9bT՜/[,rX7ٝ+wyL9J95;twfbc lsߟ5Nj̸t ap^LJɒo>(lq 5:xRACV*E9ܡY:z0ʘ?C5R *(= DRܼ@_:X0=g WYa|'(s-4/D*>?Om5\/AlnnC]_"Z Z|ⓀÍnƝc+ӝ Ϯz IYEK'v1!idcݕMH$d?.Tvkj|'*7!G˅6:n\z;{L* +LpZbT"7\*BԽ{MM2+m[YX*EFIBuMJȘC͞Cڢ wK;#ͼUHkpH@PAx+e3uƔ )z=M'Q?F.ic2%>V.u|Iu-r}C<&oϐn.En\ӿ'a&`xk2:@Ў-&kj=6&-P^Hj_x`V>Α=E\|ދsG&<1iH -_)V}w% q5|jOuzP|ztE7 ᙠӉ @2[H ?_ONChe/=A,2X' "wӖtG}8j56HQjS2&Dtʙ6E<{_(͏2 ő]Xm4`hwdz6f'fPpq5f9/9}\moz=}sYQy`Ds:Ou!V0V obX%,9VO"rr"A%;g|;̓./ C,)*<'.$Y+oyo{XwH;νޫaSQcoG(PxI|ӟo#D2,] s E=Y Z? 9vaTcYZZE@a \zp*N]V& r^G,lX)PAZeFf[ r0l>gx9!gŀ?)5Olt7hRL،j4urD]qr\T$`Cy(t(K"[ Fc OE MĘ<;9lMo |$e+h̅<[D%I|[Lϫd/d)bݧU63ֿgeT@eF;Ooz3Rv4CrjU59DƇBmHr)|S&;.lŒoC>r8=[hH9T;B+ESC,%lf֤ Zw2|=i4|as3XEAC]y«@ӱ5Ohwr%m lQ)!>U -3m9p\y&+4uW<$[oPa <7py{PNG:~<>mtȧDIayhH]ܨua:rh#&S>h8ǞbACkKakYX$QeĮ TO ]s -BM ъc TfѮ5x#94Cup2@hȢoyROOp<|[˘ꪾzjRd_{6T+k9'#򤝩JTYHHjF,DZ L$5`("lA!(--AɯT½wd[1pASӒ5XtX~P@L4[9!7'=& /!{L$[ŠwgA/ewcδpPk]fKd\⹄j_ JEz^􈩴q!E~]LvEqK4wD"j[܀V6$td$Mww,;8uTBAOj!SUKdI9FSȈC%=@˪ul8j=2%mg " tuk 5 tU{W]"iwHD֢jn/_Dk_OBC\szz-qLvG3@0x,wNOn \p(\d4AҎ"B#"3Dh]By;tSHZȱsA59j)ėKWZ8Z;kOn䴿]ijeZs .W2`㴗_LZ״ԥ$~f,T4\'`0L9qcך)l5!OσOGjt"Q?}*kk`"}݅u?BXP0o>9 NƀnyODO3`_+B{ɲcZS(t5ڻNIT`e#(1!yX$"A1FyLf,morv x@0MaƥU۫ݲw7(481_ `кgϊX%)3PNZE /w!δj;!fZFcwTۡ}IN)T;.uI(5]H2Qd"CD P͢ _z63/dW^ANn[/+0c;di e*Co*,==B~ݪ֌)7v:D3c炭 +:QY;.zBO+]&ѸV??r +-VP̬Ks-NuRmVeAI`H},Pa) }M9Cj+h4f$XDIlX 0 %QD&s80_HkC5VZ' Ts6q |}ߵzO@lås_Xf@S#X7ɑ̕nE8,%oFպ}|4ZsTHw.WIw<&'.'mYmw^"8}yQs9BI|9+??L?=4Op AmhO\ 1ahXUرuH@pa^ }N9z{<u`X'X87Ӗ l ٫{g!Ƶ^N+~x|3^ѽo0Ea`]3Ҭl 4VU ^ugEP}3[ !x0žϨQ&;KSq ʔO{I X"YB_V\J/W(ҷyK=oPLq hp!n/ fAOȯE:lF-ɶ`; t3.{N<*qiO}K}/%wTE, QNx*&v<,n5<ׅѻ)'t :(9veȟn)uP_rD+\[Mq1VhjsMt;!%s=\#㞎MNv0:q#y$2% &8bCA(m uMYJv6ÚLH5ѹrY89?nV^OY|(2-9r<0>[p Kk]k(6ÒNtF92l%!t]%h1V I&;lJjfYݸJ1U)uհػQkIZ# }{R?Vп3x69inScP;IY/ |C &'a2ZK$׍סV86Lom$*