Starlet-0.32/0000755000175000017500000000000015176575263012461 5ustar kazuhokazuhoStarlet-0.32/Changes0000644000175000017500000000604615176575156013763 0ustar kazuhokazuhoRevision history for Perl extension Starlet 0.32 - [security fix][CVE-2026-40561] prevent HTTP smuggling #34 #35 (Tokuhiro Matsuno) - improve META #32 (Aristotle Pagaltzis) - depend on Parallel::Prefork 0.18 #33 (FUJIWARA Shunichiro) 0.31 - send 100-continue immediately #25 (Gregory Oschwald) - expose new callback for sending informational responses #29 (Kazuho Oku) 0.30 - add child_exit hook #26 (by azrle) 0.29 - fix workers being killed too aggressively when spawn-interval is used #27 (by limitusus) 0.28 - always shutdown after SIGTERM, but only after notifying the client (via connection: close or equiv.) #23 0.26 - fix abrupt connection close when receiving SIGTERM #21 (by shogo82148) 0.25 - support listing to unix socket wo. using Server::Starter - suppress warning when receiving broken requests - fix test issue with Plack >= 1.0035 0.24 - worker processes always receive different sequence of values when calling "rand()" 0.23 - serialize calls to select -> accept when listening to multiple ports 0.22 - listen to multiple ports passed from Server::Starter (ttakezawa) 0.21 - support listening to unix socket (passed by Server::Starter) (kazeburo) 0.20 - support HTTP/1.1 (kazeburo) 0.19 - update the dependencies now that Plack no more depends on LWP (miyagawa; https://github.com/plack/Plack/pull/408) - add support for psgix.harakiri (audreyt) 0.18 - change threshold for combining headers and body from 1024 bytes to 8192 0.17_01 - reduce rt_sig* syscalls (kazeburo) 0.16 - Set REMOTE_PORT environment variable (kazeburo) 0.15 - unbundle Plack::Standalone::Server::Prefork::Server::Starter (see `perldoc Starlet` to find out how to boot Starlet using Server::Starter) 0.14 - support for randomized reqs-per-child - support for slow restart - do not send Server header more than once per every response 0.13 - test compatibilty improvement: ignore proxy setting while running tests (datamuc) 0.12 - [bugfix] fix infinite loop when connection is closed while receiving response content (thanks to Jiro Nishiguchi-san) 0.11 - suppress the warning "Use of "goto" to jump into a construct is deprecated" 0.10 - switch from alarm-based polling to select-based - use TCP_DEFER_ACCEPT on linux - performance tweaks 0.09 - [bugfix] enable keepalive when --max-keepalive-reqs=n (n>1) is set - accept --max-workers=n option (for better interoperability w. Starman) 0.08 - [bugfix] delay termination (when receiving first SIGTERM or SIGINT) until all HTTP requests are being processed 0.07 - hardcode set $PSSPSS::VERSION 0.06 - set $PSSPSS::VERSION to $Starlet::VERSION 0.05 - rename to Starlet from Plack::Server::Standalone::Prefork::Server::Starter (is backwards compatible) - no more depends on HTTP::Server::PSGI 0.04 - follow the changes up to Plack 0.9920 0.03 - try to find start_server from $PATH and $^X, or skip most tests (but not all) if not found - require 5.008, recommend HTTP::Parser::XS 0.02 - require Parallel::Prefork (since Plack intentionally does not require P::Prefork required by Standalone::Prefork) Starlet-0.32/META.yml0000644000175000017500000000140115176575244013725 0ustar kazuhokazuho--- abstract: 'a simple, high-performance PSGI/Plack HTTP server' author: - 'Kazuho Oku' build_requires: ExtUtils::MakeMaker: 6.59 LWP::UserAgent: 5.8 Test::More: 0.88 Test::TCP: 2.1 configure_requires: ExtUtils::MakeMaker: 6.59 distribution_type: module dynamic_config: 1 generated_by: 'Module::Install version 1.21' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 module_name: Starlet name: Starlet no_index: directory: - inc - t requires: Parallel::Prefork: 0.18 Plack: 0.992 Server::Starter: 0.06 perl: 5.8.1 resources: bugtracker: https://github.com/kazuho/Starlet/issues license: http://dev.perl.org/licenses/ repository: https://github.com/kazuho/Starlet version: '0.32' Starlet-0.32/inc/0000755000175000017500000000000015176575263013232 5ustar kazuhokazuhoStarlet-0.32/inc/Module/0000755000175000017500000000000015176575263014457 5ustar kazuhokazuhoStarlet-0.32/inc/Module/Install/0000755000175000017500000000000015176575263016065 5ustar kazuhokazuhoStarlet-0.32/inc/Module/Install/Win32.pm0000644000175000017500000000340315176575244017324 0ustar kazuhokazuho#line 1 package Module::Install::Win32; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # determine if the user needs nmake, and download it if needed sub check_nmake { my $self = shift; $self->load('can_run'); $self->load('get_file'); require Config; return unless ( $^O eq 'MSWin32' and $Config::Config{make} and $Config::Config{make} =~ /^nmake\b/i and ! $self->can_run('nmake') ); print "The required 'nmake' executable not found, fetching it...\n"; require File::Basename; my $rv = $self->get_file( url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe', ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe', local_dir => File::Basename::dirname($^X), size => 51928, run => 'Nmake15.exe /o > nul', check_for => 'Nmake.exe', remove => 1, ); die <<'END_MESSAGE' unless $rv; ------------------------------------------------------------------------------- Since you are using Microsoft Windows, you will need the 'nmake' utility before installation. It's available at: http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe or ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe Please download the file manually, save it to a directory in %PATH% (e.g. C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to that directory, and run "Nmake15.exe" from there; that will create the 'nmake.exe' file needed by this module. You may then resume the installation process described in README. ------------------------------------------------------------------------------- END_MESSAGE } 1; Starlet-0.32/inc/Module/Install/WriteAll.pm0000644000175000017500000000237615176575244020155 0ustar kazuhokazuho#line 1 package Module::Install::WriteAll; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = qw{Module::Install::Base}; $ISCORE = 1; } sub WriteAll { my $self = shift; my %args = ( meta => 1, sign => 0, inline => 0, check_nmake => 1, @_, ); $self->sign(1) if $args{sign}; $self->admin->WriteAll(%args) if $self->is_admin; $self->check_nmake if $args{check_nmake}; unless ( $self->makemaker_args->{PL_FILES} ) { # XXX: This still may be a bit over-defensive... unless ($self->makemaker(6.25)) { $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL'; } } # Until ExtUtils::MakeMaker support MYMETA.yml, make sure # we clean it up properly ourself. $self->realclean_files('MYMETA.yml'); if ( $args{inline} ) { $self->Inline->write; } else { $self->Makefile->write; } # The Makefile write process adds a couple of dependencies, # so write the META.yml files after the Makefile. if ( $args{meta} ) { $self->Meta->write; } # Experimental support for MYMETA if ( $ENV{X_MYMETA} ) { if ( $ENV{X_MYMETA} eq 'JSON' ) { $self->Meta->write_mymeta_json; } else { $self->Meta->write_mymeta_yaml; } } return 1; } 1; Starlet-0.32/inc/Module/Install/ReadmeFromPod.pm0000644000175000017500000001016415176575244021110 0ustar kazuhokazuho#line 1 package Module::Install::ReadmeFromPod; use 5.006; use strict; use warnings; use base qw(Module::Install::Base); use vars qw($VERSION); $VERSION = '0.30'; { # these aren't defined until after _require_admin is run, so # define them so prototypes are available during compilation. sub io; sub capture(&;@); #line 28 my $done = 0; sub _require_admin { # do this once to avoid redefinition warnings from IO::All return if $done; require IO::All; IO::All->import( '-binary' ); require Capture::Tiny; Capture::Tiny->import ( 'capture' ); return; } } sub readme_from { my $self = shift; return unless $self->is_admin; _require_admin; # Input file my $in_file = shift || $self->_all_from or die "Can't determine file to make readme_from"; # Get optional arguments my ($clean, $format, $out_file, $options); my $args = shift; if ( ref $args ) { # Arguments are in a hashref if ( ref($args) ne 'HASH' ) { die "Expected a hashref but got a ".ref($args)."\n"; } else { $clean = $args->{'clean'}; $format = $args->{'format'}; $out_file = $args->{'output_file'}; $options = $args->{'options'}; } } else { # Arguments are in a list $clean = $args; $format = shift; $out_file = shift; $options = \@_; } # Default values; $clean ||= 0; $format ||= 'txt'; # Generate README print "readme_from $in_file to $format\n"; if ($format =~ m/te?xt/) { $out_file = $self->_readme_txt($in_file, $out_file, $options); } elsif ($format =~ m/html?/) { $out_file = $self->_readme_htm($in_file, $out_file, $options); } elsif ($format eq 'man') { $out_file = $self->_readme_man($in_file, $out_file, $options); } elsif ($format eq 'md') { $out_file = $self->_readme_md($in_file, $out_file, $options); } elsif ($format eq 'pdf') { $out_file = $self->_readme_pdf($in_file, $out_file, $options); } if ($clean) { $self->clean_files($out_file); } return 1; } sub _readme_txt { my ($self, $in_file, $out_file, $options) = @_; $out_file ||= 'README'; require Pod::Text; my $parser = Pod::Text->new( @$options ); my $io = io->file($out_file)->open(">"); my $out_fh = $io->io_handle; $parser->output_fh( *$out_fh ); $parser->parse_file( $in_file ); return $out_file; } sub _readme_htm { my ($self, $in_file, $out_file, $options) = @_; $out_file ||= 'README.htm'; require Pod::Html; my ($o) = capture { Pod::Html::pod2html( "--infile=$in_file", "--outfile=-", @$options, ); }; io->file($out_file)->print($o); # Remove temporary files if needed for my $file ('pod2htmd.tmp', 'pod2htmi.tmp') { if (-e $file) { unlink $file or warn "Warning: Could not remove file '$file'.\n$!\n"; } } return $out_file; } sub _readme_man { my ($self, $in_file, $out_file, $options) = @_; $out_file ||= 'README.1'; require Pod::Man; my $parser = Pod::Man->new( @$options ); my $io = io->file($out_file)->open(">"); my $out_fh = $io->io_handle; $parser->output_fh( *$out_fh ); $parser->parse_file( $in_file ); return $out_file; } sub _readme_pdf { my ($self, $in_file, $out_file, $options) = @_; $out_file ||= 'README.pdf'; eval { require App::pod2pdf; } or die "Could not generate $out_file because pod2pdf could not be found\n"; my $parser = App::pod2pdf->new( @$options ); $parser->parse_from_file($in_file); my ($o) = capture { $parser->output }; io->file($out_file)->print($o); return $out_file; } sub _readme_md { my ($self, $in_file, $out_file, $options) = @_; $out_file ||= 'README.md'; require Pod::Markdown; my $parser = Pod::Markdown->new( @$options ); my $io = io->file($out_file)->open(">"); my $out_fh = $io->io_handle; $parser->output_fh( *$out_fh ); $parser->parse_file( $in_file ); return $out_file; } sub _all_from { my $self = shift; return unless $self->admin->{extensions}; my ($metadata) = grep { ref($_) eq 'Module::Install::Metadata'; } @{$self->admin->{extensions}}; return unless $metadata; return $metadata->{values}{all_from} || ''; } 'Readme!'; __END__ #line 316 Starlet-0.32/inc/Module/Install/Metadata.pm0000644000175000017500000004343715176575244020155 0ustar kazuhokazuho#line 1 package Module::Install::Metadata; use strict 'vars'; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } my @boolean_keys = qw{ sign }; my @scalar_keys = qw{ name module_name abstract version distribution_type tests installdirs }; my @tuple_keys = qw{ configure_requires build_requires requires recommends bundles resources }; my @resource_keys = qw{ homepage bugtracker repository }; my @array_keys = qw{ keywords author }; *authors = \&author; sub Meta { shift } sub Meta_BooleanKeys { @boolean_keys } sub Meta_ScalarKeys { @scalar_keys } sub Meta_TupleKeys { @tuple_keys } sub Meta_ResourceKeys { @resource_keys } sub Meta_ArrayKeys { @array_keys } foreach my $key ( @boolean_keys ) { *$key = sub { my $self = shift; if ( defined wantarray and not @_ ) { return $self->{values}->{$key}; } $self->{values}->{$key} = ( @_ ? $_[0] : 1 ); return $self; }; } foreach my $key ( @scalar_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} = shift; return $self; }; } foreach my $key ( @array_keys ) { *$key = sub { my $self = shift; return $self->{values}->{$key} if defined wantarray and !@_; $self->{values}->{$key} ||= []; push @{$self->{values}->{$key}}, @_; return $self; }; } foreach my $key ( @resource_keys ) { *$key = sub { my $self = shift; unless ( @_ ) { return () unless $self->{values}->{resources}; return map { $_->[1] } grep { $_->[0] eq $key } @{ $self->{values}->{resources} }; } return $self->{values}->{resources}->{$key} unless @_; my $uri = shift or die( "Did not provide a value to $key()" ); $self->resources( $key => $uri ); return 1; }; } foreach my $key ( grep { $_ ne "resources" } @tuple_keys) { *$key = sub { my $self = shift; return $self->{values}->{$key} unless @_; my @added; while ( @_ ) { my $module = shift or last; my $version = shift || 0; push @added, [ $module, $version ]; } push @{ $self->{values}->{$key} }, @added; return map {@$_} @added; }; } # Resource handling my %lc_resource = map { $_ => 1 } qw{ homepage license bugtracker repository }; sub resources { my $self = shift; while ( @_ ) { my $name = shift or last; my $value = shift or next; if ( $name eq lc $name and ! $lc_resource{$name} ) { die("Unsupported reserved lowercase resource '$name'"); } $self->{values}->{resources} ||= []; push @{ $self->{values}->{resources} }, [ $name, $value ]; } $self->{values}->{resources}; } # Aliases for build_requires that will have alternative # meanings in some future version of META.yml. sub test_requires { shift->build_requires(@_) } sub install_requires { shift->build_requires(@_) } # Aliases for installdirs options sub install_as_core { $_[0]->installdirs('perl') } sub install_as_cpan { $_[0]->installdirs('site') } sub install_as_site { $_[0]->installdirs('site') } sub install_as_vendor { $_[0]->installdirs('vendor') } sub dynamic_config { my $self = shift; my $value = @_ ? shift : 1; if ( $self->{values}->{dynamic_config} ) { # Once dynamic we never change to static, for safety return 0; } $self->{values}->{dynamic_config} = $value ? 1 : 0; return 1; } # Convenience command sub static_config { shift->dynamic_config(0); } sub perl_version { my $self = shift; return $self->{values}->{perl_version} unless @_; my $version = shift or die( "Did not provide a value to perl_version()" ); # Normalize the version $version = $self->_perl_version($version); # We don't support the really old versions unless ( $version >= 5.005 ) { die "Module::Install only supports 5.005 or newer (use ExtUtils::MakeMaker)\n"; } $self->{values}->{perl_version} = $version; } sub all_from { my ( $self, $file ) = @_; unless ( defined($file) ) { my $name = $self->name or die( "all_from called with no args without setting name() first" ); $file = join('/', 'lib', split(/-/, $name)) . '.pm'; $file =~ s{.*/}{} unless -e $file; unless ( -e $file ) { die("all_from cannot find $file from $name"); } } unless ( -f $file ) { die("The path '$file' does not exist, or is not a file"); } $self->{values}{all_from} = $file; # Some methods pull from POD instead of code. # If there is a matching .pod, use that instead my $pod = $file; $pod =~ s/\.pm$/.pod/i; $pod = $file unless -e $pod; # Pull the different values $self->name_from($file) unless $self->name; $self->version_from($file) unless $self->version; $self->perl_version_from($file) unless $self->perl_version; $self->author_from($pod) unless @{$self->author || []}; $self->license_from($pod) unless $self->license; $self->abstract_from($pod) unless $self->abstract; return 1; } sub provides { my $self = shift; my $provides = ( $self->{values}->{provides} ||= {} ); %$provides = (%$provides, @_) if @_; return $provides; } sub auto_provides { my $self = shift; return $self unless $self->is_admin; unless (-e 'MANIFEST') { warn "Cannot deduce auto_provides without a MANIFEST, skipping\n"; return $self; } # Avoid spurious warnings as we are not checking manifest here. local $SIG{__WARN__} = sub {1}; require ExtUtils::Manifest; local *ExtUtils::Manifest::manicheck = sub { return }; require Module::Build; my $build = Module::Build->new( dist_name => $self->name, dist_version => $self->version, license => $self->license, ); $self->provides( %{ $build->find_dist_packages || {} } ); } sub feature { my $self = shift; my $name = shift; my $features = ( $self->{values}->{features} ||= [] ); my $mods; if ( @_ == 1 and ref( $_[0] ) ) { # The user used ->feature like ->features by passing in the second # argument as a reference. Accomodate for that. $mods = $_[0]; } else { $mods = \@_; } my $count = 0; push @$features, ( $name => [ map { ref($_) ? ( ref($_) eq 'HASH' ) ? %$_ : @$_ : $_ } @$mods ] ); return @$features; } sub features { my $self = shift; while ( my ( $name, $mods ) = splice( @_, 0, 2 ) ) { $self->feature( $name, @$mods ); } return $self->{values}->{features} ? @{ $self->{values}->{features} } : (); } sub no_index { my $self = shift; my $type = shift; push @{ $self->{values}->{no_index}->{$type} }, @_ if $type; return $self->{values}->{no_index}; } sub read { my $self = shift; $self->include_deps( 'YAML::Tiny', 0 ); require YAML::Tiny; my $data = YAML::Tiny::LoadFile('META.yml'); # Call methods explicitly in case user has already set some values. while ( my ( $key, $value ) = each %$data ) { next unless $self->can($key); if ( ref $value eq 'HASH' ) { while ( my ( $module, $version ) = each %$value ) { $self->can($key)->($self, $module => $version ); } } else { $self->can($key)->($self, $value); } } return $self; } sub write { my $self = shift; return $self unless $self->is_admin; $self->admin->write_meta; return $self; } sub version_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->version( ExtUtils::MM_Unix->parse_version($file) ); # for version integrity check $self->makemaker_args( VERSION_FROM => $file ); } sub abstract_from { require ExtUtils::MM_Unix; my ( $self, $file ) = @_; $self->abstract( bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($file) ); } # Add both distribution and module name sub name_from { my ($self, $file) = @_; if ( Module::Install::_read($file) =~ m/ ^ \s* package \s* ([\w:]+) [\s|;]* /ixms ) { my ($name, $module_name) = ($1, $1); $name =~ s{::}{-}g; $self->name($name); unless ( $self->module_name ) { $self->module_name($module_name); } } else { die("Cannot determine name from $file\n"); } } sub _extract_perl_version { if ( $_[0] =~ m/ ^\s* (?:use|require) \s* v? ([\d_\.]+) \s* ; /ixms ) { my $perl_version = $1; $perl_version =~ s{_}{}g; return $perl_version; } else { return; } } sub perl_version_from { my $self = shift; my $perl_version=_extract_perl_version(Module::Install::_read($_[0])); if ($perl_version) { $self->perl_version($perl_version); } else { warn "Cannot determine perl version info from $_[0]\n"; return; } } sub author_from { my $self = shift; my $content = Module::Install::_read($_[0]); if ($content =~ m/ =head \d \s+ (?:authors?)\b \s* ([^\n]*) | =head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s* .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s* ([^\n]*) /ixms) { my $author = $1 || $2; # XXX: ugly but should work anyway... if (eval "require Pod::Escapes; 1") { # Pod::Escapes has a mapping table. # It's in core of perl >= 5.9.3, and should be installed # as one of the Pod::Simple's prereqs, which is a prereq # of Pod::Text 3.x (see also below). $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $Pod::Escapes::Name2character_number{$1} ? chr($Pod::Escapes::Name2character_number{$1}) : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } elsif (eval "require Pod::Text; 1" && $Pod::Text::VERSION < 3) { # Pod::Text < 3.0 has yet another mapping table, # though the table name of 2.x and 1.x are different. # (1.x is in core of Perl < 5.6, 2.x is in core of # Perl < 5.9.3) my $mapping = ($Pod::Text::VERSION < 2) ? \%Pod::Text::HTML_Escapes : \%Pod::Text::ESCAPES; $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> } { defined $2 ? chr($2) : defined $mapping->{$1} ? $mapping->{$1} : do { warn "Unknown escape: E<$1>"; "E<$1>"; }; }gex; } else { $author =~ s{E}{<}g; $author =~ s{E}{>}g; } $self->author($author); } else { warn "Cannot determine author info from $_[0]\n"; } } #Stolen from M::B my %license_urls = ( perl => 'http://dev.perl.org/licenses/', apache => 'http://apache.org/licenses/LICENSE-2.0', artistic => 'http://opensource.org/licenses/artistic-license.php', lgpl => 'http://opensource.org/licenses/lgpl-license.php', bsd => 'http://opensource.org/licenses/bsd-license.php', gpl => 'http://opensource.org/licenses/gpl-license.php', gpl2 => 'http://opensource.org/licenses/gpl-2.0.php', gpl3 => 'http://opensource.org/licenses/gpl-3.0.html', mit => 'http://opensource.org/licenses/mit-license.php', mozilla => 'http://opensource.org/licenses/mozilla1.1.php', open_source => undef, unrestricted => undef, restrictive => undef, unknown => undef, # these are not actually allowed in meta-spec v1.4 but are left here for compatibility: apache_1_1 => 'http://apache.org/licenses/LICENSE-1.1', artistic_2 => 'http://opensource.org/licenses/artistic-license-2.0.php', lgpl2 => 'http://opensource.org/licenses/lgpl-2.1.php', lgpl3 => 'http://opensource.org/licenses/lgpl-3.0.html', ); sub license { my $self = shift; return $self->{values}->{license} unless @_; my $license = shift or die( 'Did not provide a value to license()' ); $license = __extract_license($license) || lc $license; $self->{values}->{license} = $license; # Automatically fill in license URLs if ( $license_urls{$license} ) { $self->resources( license => $license_urls{$license} ); } return 1; } sub _extract_license { my $pod = shift; my $matched; return __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?) (=head \d.*|=cut.*|)\z /xms ) || __extract_license( ($matched) = $pod =~ m/ (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?) (=head \d.*|=cut.*|)\z /xms ); } sub __extract_license { my $license_text = shift or return; my @phrases = ( '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)' => 'perl', 1, '(?:under )?the terms of (?:perl|the perl programming language) itself' => 'perl', 1, 'Artistic and GPL' => 'perl', 1, 'GNU general public license' => 'gpl', 1, 'GNU public license' => 'gpl', 1, 'GNU lesser general public license' => 'lgpl', 1, 'GNU lesser public license' => 'lgpl', 1, 'GNU library general public license' => 'lgpl', 1, 'GNU library public license' => 'lgpl', 1, 'GNU Free Documentation license' => 'unrestricted', 1, 'GNU Affero General Public License' => 'open_source', 1, '(?:Free)?BSD license' => 'bsd', 1, 'Artistic license 2\.0' => 'artistic_2', 1, 'Artistic license' => 'artistic', 1, 'Apache (?:Software )?license' => 'apache', 1, 'GPL' => 'gpl', 1, 'LGPL' => 'lgpl', 1, 'BSD' => 'bsd', 1, 'Artistic' => 'artistic', 1, 'MIT' => 'mit', 1, 'Mozilla Public License' => 'mozilla', 1, 'Q Public License' => 'open_source', 1, 'OpenSSL License' => 'unrestricted', 1, 'SSLeay License' => 'unrestricted', 1, 'zlib License' => 'open_source', 1, 'proprietary' => 'proprietary', 0, ); while ( my ($pattern, $license, $osi) = splice(@phrases, 0, 3) ) { $pattern =~ s#\s+#\\s+#gs; if ( $license_text =~ /\b$pattern\b/i ) { return $license; } } return ''; } sub license_from { my $self = shift; if (my $license=_extract_license(Module::Install::_read($_[0]))) { $self->license($license); } else { warn "Cannot determine license info from $_[0]\n"; return 'unknown'; } } sub _extract_bugtracker { my @links = $_[0] =~ m#L<( https?\Q://rt.cpan.org/\E[^>]+| https?\Q://github.com/\E[\w_]+/[\w_]+/issues| https?\Q://code.google.com/p/\E[\w_\-]+/issues/list )>#gx; my %links; @links{@links}=(); @links=keys %links; return @links; } sub bugtracker_from { my $self = shift; my $content = Module::Install::_read($_[0]); my @links = _extract_bugtracker($content); unless ( @links ) { warn "Cannot determine bugtracker info from $_[0]\n"; return 0; } if ( @links > 1 ) { warn "Found more than one bugtracker link in $_[0]\n"; return 0; } # Set the bugtracker bugtracker( $links[0] ); return 1; } sub requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+(v?[\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->requires( $module => $version ); } } sub test_requires_from { my $self = shift; my $content = Module::Install::_readperl($_[0]); my @requires = $content =~ m/^use\s+([^\W\d]\w*(?:::\w+)*)\s+([\d\.]+)/mg; while ( @requires ) { my $module = shift @requires; my $version = shift @requires; $self->test_requires( $module => $version ); } } # Convert triple-part versions (eg, 5.6.1 or 5.8.9) to # numbers (eg, 5.006001 or 5.008009). # Also, convert double-part versions (eg, 5.8) sub _perl_version { my $v = $_[-1]; $v =~ s/^([1-9])\.([1-9]\d?\d?)$/sprintf("%d.%03d",$1,$2)/e; $v =~ s/^([1-9])\.([1-9]\d?\d?)\.(0|[1-9]\d?\d?)$/sprintf("%d.%03d%03d",$1,$2,$3 || 0)/e; $v =~ s/(\.\d\d\d)000$/$1/; $v =~ s/_.+$//; if ( ref($v) ) { # Numify $v = $v + 0; } return $v; } sub add_metadata { my $self = shift; my %hash = @_; for my $key (keys %hash) { warn "add_metadata: $key is not prefixed with 'x_'.\n" . "Use appopriate function to add non-private metadata.\n" unless $key =~ /^x_/; $self->{values}->{$key} = $hash{$key}; } } ###################################################################### # MYMETA Support sub WriteMyMeta { die "WriteMyMeta has been deprecated"; } sub write_mymeta_yaml { my $self = shift; # We need YAML::Tiny to write the MYMETA.yml file unless ( eval { require YAML::Tiny; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.yml\n"; YAML::Tiny::DumpFile('MYMETA.yml', $meta); } sub write_mymeta_json { my $self = shift; # We need JSON to write the MYMETA.json file unless ( eval { require JSON; 1; } ) { return 1; } # Generate the data my $meta = $self->_write_mymeta_data or return 1; # Save as the MYMETA.yml file print "Writing MYMETA.json\n"; Module::Install::_write( 'MYMETA.json', JSON->new->pretty(1)->canonical->encode($meta), ); } sub _write_mymeta_data { my $self = shift; # If there's no existing META.yml there is nothing we can do return undef unless -f 'META.yml'; # We need Parse::CPAN::Meta to load the file unless ( eval { require Parse::CPAN::Meta; 1; } ) { return undef; } # Merge the perl version into the dependencies my $val = $self->Meta->{values}; my $perl = delete $val->{perl_version}; if ( $perl ) { $val->{requires} ||= []; my $requires = $val->{requires}; # Canonize to three-dot version after Perl 5.6 if ( $perl >= 5.006 ) { $perl =~ s{^(\d+)\.(\d\d\d)(\d*)}{join('.', $1, int($2||0), int($3||0))}e } unshift @$requires, [ perl => $perl ]; } # Load the advisory META.yml file my @yaml = Parse::CPAN::Meta::LoadFile('META.yml'); my $meta = $yaml[0]; # Overwrite the non-configure dependency hashes delete $meta->{requires}; delete $meta->{build_requires}; delete $meta->{recommends}; if ( exists $val->{requires} ) { $meta->{requires} = { map { @$_ } @{ $val->{requires} } }; } if ( exists $val->{build_requires} ) { $meta->{build_requires} = { map { @$_ } @{ $val->{build_requires} } }; } return $meta; } 1; Starlet-0.32/inc/Module/Install/Base.pm0000644000175000017500000000214715176575244017300 0ustar kazuhokazuho#line 1 package Module::Install::Base; use strict 'vars'; use vars qw{$VERSION}; BEGIN { $VERSION = '1.21'; } # Suspend handler for "redefined" warnings BEGIN { my $w = $SIG{__WARN__}; $SIG{__WARN__} = sub { $w }; } #line 42 sub new { my $class = shift; unless ( defined &{"${class}::call"} ) { *{"${class}::call"} = sub { shift->_top->call(@_) }; } unless ( defined &{"${class}::load"} ) { *{"${class}::load"} = sub { shift->_top->load(@_) }; } bless { @_ }, $class; } #line 61 sub AUTOLOAD { local $@; my $func = eval { shift->_top->autoload } or return; goto &$func; } #line 75 sub _top { $_[0]->{_top}; } #line 90 sub admin { $_[0]->_top->{admin} or Module::Install::Base::FakeAdmin->new; } #line 106 sub is_admin { ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin'); } sub DESTROY {} package Module::Install::Base::FakeAdmin; use vars qw{$VERSION}; BEGIN { $VERSION = $Module::Install::Base::VERSION; } my $fake; sub new { $fake ||= bless(\@_, $_[0]); } sub AUTOLOAD {} sub DESTROY {} # Restore warning handler BEGIN { $SIG{__WARN__} = $SIG{__WARN__}->(); } 1; #line 159 Starlet-0.32/inc/Module/Install/Can.pm0000644000175000017500000000640515176575244017130 0ustar kazuhokazuho#line 1 package Module::Install::Can; use strict; use Config (); use ExtUtils::MakeMaker (); use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } # check if we can load some module ### Upgrade this to not have to load the module if possible sub can_use { my ($self, $mod, $ver) = @_; $mod =~ s{::|\\}{/}g; $mod .= '.pm' unless $mod =~ /\.pm$/i; my $pkg = $mod; $pkg =~ s{/}{::}g; $pkg =~ s{\.pm$}{}i; local $@; eval { require $mod; $pkg->VERSION($ver || 0); 1 }; } # Check if we can run some command sub can_run { my ($self, $cmd) = @_; my $_cmd = $cmd; return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd)); for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') { next if $dir eq ''; require File::Spec; my $abs = File::Spec->catfile($dir, $cmd); return $abs if (-x $abs or $abs = MM->maybe_command($abs)); } return; } # Can our C compiler environment build XS files sub can_xs { my $self = shift; # Ensure we have the CBuilder module $self->configure_requires( 'ExtUtils::CBuilder' => 0.27 ); # Do we have the configure_requires checker? local $@; eval "require ExtUtils::CBuilder;"; if ( $@ ) { # They don't obey configure_requires, so it is # someone old and delicate. Try to avoid hurting # them by falling back to an older simpler test. return $self->can_cc(); } # Do we have a working C compiler my $builder = ExtUtils::CBuilder->new( quiet => 1, ); unless ( $builder->have_compiler ) { # No working C compiler return 0; } # Write a C file representative of what XS becomes require File::Temp; my ( $FH, $tmpfile ) = File::Temp::tempfile( "compilexs-XXXXX", SUFFIX => '.c', ); binmode $FH; print $FH <<'END_C'; #include "EXTERN.h" #include "perl.h" #include "XSUB.h" int main(int argc, char **argv) { return 0; } int boot_sanexs() { return 1; } END_C close $FH; # Can the C compiler access the same headers XS does my @libs = (); my $object = undef; eval { local $^W = 0; $object = $builder->compile( source => $tmpfile, ); @libs = $builder->link( objects => $object, module_name => 'sanexs', ); }; my $result = $@ ? 0 : 1; # Clean up all the build files foreach ( $tmpfile, $object, @libs ) { next unless defined $_; 1 while unlink; } return $result; } # Can we locate a (the) C compiler sub can_cc { my $self = shift; if ($^O eq 'VMS') { require ExtUtils::CBuilder; my $builder = ExtUtils::CBuilder->new( quiet => 1, ); return $builder->have_compiler; } my @chunks = split(/ /, $Config::Config{cc}) or return; # $Config{cc} may contain args; try to find out the program part while (@chunks) { return $self->can_run("@chunks") || (pop(@chunks), next); } return; } # Fix Cygwin bug on maybe_command(); if ( $^O eq 'cygwin' ) { require ExtUtils::MM_Cygwin; require ExtUtils::MM_Win32; if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) { *ExtUtils::MM_Cygwin::maybe_command = sub { my ($self, $file) = @_; if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) { ExtUtils::MM_Win32->maybe_command($file); } else { ExtUtils::MM_Unix->maybe_command($file); } } } } 1; __END__ #line 245 Starlet-0.32/inc/Module/Install/Fetch.pm0000644000175000017500000000462715176575244017464 0ustar kazuhokazuho#line 1 package Module::Install::Fetch; use strict; use Module::Install::Base (); use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub get_file { my ($self, %args) = @_; my ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) { $args{url} = $args{ftp_url} or (warn("LWP support unavailable!\n"), return); ($scheme, $host, $path, $file) = $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return; } $|++; print "Fetching '$file' from $host... "; unless (eval { require Socket; Socket::inet_aton($host) }) { warn "'$host' resolve failed!\n"; return; } return unless $scheme eq 'ftp' or $scheme eq 'http'; require Cwd; my $dir = Cwd::getcwd(); chdir $args{local_dir} or return if exists $args{local_dir}; if (eval { require LWP::Simple; 1 }) { LWP::Simple::mirror($args{url}, $file); } elsif (eval { require Net::FTP; 1 }) { eval { # use Net::FTP to get past firewall my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600); $ftp->login("anonymous", 'anonymous@example.com'); $ftp->cwd($path); $ftp->binary; $ftp->get($file) or (warn("$!\n"), return); $ftp->quit; } } elsif (my $ftp = $self->can_run('ftp')) { eval { # no Net::FTP, fallback to ftp.exe require FileHandle; my $fh = FileHandle->new; local $SIG{CHLD} = 'IGNORE'; unless ($fh->open("|$ftp -n")) { warn "Couldn't open ftp: $!\n"; chdir $dir; return; } my @dialog = split(/\n/, <<"END_FTP"); open $host user anonymous anonymous\@example.com cd $path binary get $file $file quit END_FTP foreach (@dialog) { $fh->print("$_\n") } $fh->close; } } else { warn "No working 'ftp' program available!\n"; chdir $dir; return; } unless (-f $file) { warn "Fetching failed: $@\n"; chdir $dir; return; } return if exists $args{size} and -s $file != $args{size}; system($args{run}) if exists $args{run}; unlink($file) if $args{remove}; print(((!exists $args{check_for} or -e $args{check_for}) ? "done!" : "failed! ($!)"), "\n"); chdir $dir; return !$?; } 1; Starlet-0.32/inc/Module/Install/Makefile.pm0000644000175000017500000002743715176575244020154 0ustar kazuhokazuho#line 1 package Module::Install::Makefile; use strict 'vars'; use ExtUtils::MakeMaker (); use Module::Install::Base (); use Fcntl qw/:flock :seek/; use vars qw{$VERSION @ISA $ISCORE}; BEGIN { $VERSION = '1.21'; @ISA = 'Module::Install::Base'; $ISCORE = 1; } sub Makefile { $_[0] } my %seen = (); sub prompt { shift; # Infinite loop protection my @c = caller(); if ( ++$seen{"$c[1]|$c[2]|$_[0]"} > 3 ) { die "Caught an potential prompt infinite loop ($c[1]|$c[2]|$_[0])"; } # In automated testing or non-interactive session, always use defaults if ( ($ENV{AUTOMATED_TESTING} or -! -t STDIN) and ! $ENV{PERL_MM_USE_DEFAULT} ) { local $ENV{PERL_MM_USE_DEFAULT} = 1; goto &ExtUtils::MakeMaker::prompt; } else { goto &ExtUtils::MakeMaker::prompt; } } # Store a cleaned up version of the MakeMaker version, # since we need to behave differently in a variety of # ways based on the MM version. my $makemaker = eval $ExtUtils::MakeMaker::VERSION; # If we are passed a param, do a "newer than" comparison. # Otherwise, just return the MakeMaker version. sub makemaker { ( @_ < 2 or $makemaker >= eval($_[1]) ) ? $makemaker : 0 } # Ripped from ExtUtils::MakeMaker 6.56, and slightly modified # as we only need to know here whether the attribute is an array # or a hash or something else (which may or may not be appendable). my %makemaker_argtype = ( C => 'ARRAY', CONFIG => 'ARRAY', # CONFIGURE => 'CODE', # ignore DIR => 'ARRAY', DL_FUNCS => 'HASH', DL_VARS => 'ARRAY', EXCLUDE_EXT => 'ARRAY', EXE_FILES => 'ARRAY', FUNCLIST => 'ARRAY', H => 'ARRAY', IMPORTS => 'HASH', INCLUDE_EXT => 'ARRAY', LIBS => 'ARRAY', # ignore '' MAN1PODS => 'HASH', MAN3PODS => 'HASH', META_ADD => 'HASH', META_MERGE => 'HASH', PL_FILES => 'HASH', PM => 'HASH', PMLIBDIRS => 'ARRAY', PMLIBPARENTDIRS => 'ARRAY', PREREQ_PM => 'HASH', CONFIGURE_REQUIRES => 'HASH', SKIP => 'ARRAY', TYPEMAPS => 'ARRAY', XS => 'HASH', # VERSION => ['version',''], # ignore # _KEEP_AFTER_FLUSH => '', clean => 'HASH', depend => 'HASH', dist => 'HASH', dynamic_lib=> 'HASH', linkext => 'HASH', macro => 'HASH', postamble => 'HASH', realclean => 'HASH', test => 'HASH', tool_autosplit => 'HASH', # special cases where you can use makemaker_append CCFLAGS => 'APPENDABLE', DEFINE => 'APPENDABLE', INC => 'APPENDABLE', LDDLFLAGS => 'APPENDABLE', LDFROM => 'APPENDABLE', ); sub makemaker_args { my ($self, %new_args) = @_; my $args = ( $self->{makemaker_args} ||= {} ); foreach my $key (keys %new_args) { if ($makemaker_argtype{$key}) { if ($makemaker_argtype{$key} eq 'ARRAY') { $args->{$key} = [] unless defined $args->{$key}; unless (ref $args->{$key} eq 'ARRAY') { $args->{$key} = [$args->{$key}] } push @{$args->{$key}}, ref $new_args{$key} eq 'ARRAY' ? @{$new_args{$key}} : $new_args{$key}; } elsif ($makemaker_argtype{$key} eq 'HASH') { $args->{$key} = {} unless defined $args->{$key}; foreach my $skey (keys %{ $new_args{$key} }) { $args->{$key}{$skey} = $new_args{$key}{$skey}; } } elsif ($makemaker_argtype{$key} eq 'APPENDABLE') { $self->makemaker_append($key => $new_args{$key}); } } else { if (defined $args->{$key}) { warn qq{MakeMaker attribute "$key" is overriden; use "makemaker_append" to append values\n}; } $args->{$key} = $new_args{$key}; } } return $args; } # For mm args that take multiple space-separated args, # append an argument to the current list. sub makemaker_append { my $self = shift; my $name = shift; my $args = $self->makemaker_args; $args->{$name} = defined $args->{$name} ? join( ' ', $args->{$name}, @_ ) : join( ' ', @_ ); } sub build_subdirs { my $self = shift; my $subdirs = $self->makemaker_args->{DIR} ||= []; for my $subdir (@_) { push @$subdirs, $subdir; } } sub clean_files { my $self = shift; my $clean = $self->makemaker_args->{clean} ||= {}; %$clean = ( %$clean, FILES => join ' ', grep { length $_ } ($clean->{FILES} || (), @_), ); } sub realclean_files { my $self = shift; my $realclean = $self->makemaker_args->{realclean} ||= {}; %$realclean = ( %$realclean, FILES => join ' ', grep { length $_ } ($realclean->{FILES} || (), @_), ); } sub libs { my $self = shift; my $libs = ref $_[0] ? shift : [ shift ]; $self->makemaker_args( LIBS => $libs ); } sub inc { my $self = shift; $self->makemaker_args( INC => shift ); } sub _wanted_t { } sub tests_recursive { my $self = shift; my $dir = shift || 't'; unless ( -d $dir ) { die "tests_recursive dir '$dir' does not exist"; } my %tests = map { $_ => 1 } split / /, ($self->tests || ''); require File::Find; File::Find::find( sub { /\.t$/ and -f $_ and $tests{"$File::Find::dir/*.t"} = 1 }, $dir ); $self->tests( join ' ', sort keys %tests ); } sub write { my $self = shift; die "&Makefile->write() takes no arguments\n" if @_; # Check the current Perl version my $perl_version = $self->perl_version; if ( $perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; } # Make sure we have a new enough MakeMaker require ExtUtils::MakeMaker; if ( $perl_version and $self->_cmp($perl_version, '5.006') >= 0 ) { # This previous attempted to inherit the version of # ExtUtils::MakeMaker in use by the module author, but this # was found to be untenable as some authors build releases # using future dev versions of EU:MM that nobody else has. # Instead, #toolchain suggests we use 6.59 which is the most # stable version on CPAN at time of writing and is, to quote # ribasushi, "not terminally fucked, > and tested enough". # TODO: We will now need to maintain this over time to push # the version up as new versions are released. $self->build_requires( 'ExtUtils::MakeMaker' => 6.59 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.59 ); } else { # Allow legacy-compatibility with 5.005 by depending on the # most recent EU:MM that supported 5.005. $self->build_requires( 'ExtUtils::MakeMaker' => 6.36 ); $self->configure_requires( 'ExtUtils::MakeMaker' => 6.36 ); } # Generate the MakeMaker params my $args = $self->makemaker_args; $args->{DISTNAME} = $self->name; $args->{NAME} = $self->module_name || $self->name; $args->{NAME} =~ s/-/::/g; $args->{VERSION} = $self->version or die <<'EOT'; ERROR: Can't determine distribution version. Please specify it explicitly via 'version' in Makefile.PL, or set a valid $VERSION in a module, and provide its file path via 'version_from' (or 'all_from' if you prefer) in Makefile.PL. EOT if ( $self->tests ) { my @tests = split ' ', $self->tests; my %seen; $args->{test} = { TESTS => (join ' ', grep {!$seen{$_}++} @tests), }; } elsif ( $Module::Install::ExtraTests::use_extratests ) { # Module::Install::ExtraTests doesn't set $self->tests and does its own tests via harness. # So, just ignore our xt tests here. } elsif ( -d 'xt' and ($Module::Install::AUTHOR or $ENV{RELEASE_TESTING}) ) { $args->{test} = { TESTS => join( ' ', map { "$_/*.t" } grep { -d $_ } qw{ t xt } ), }; } if ( $] >= 5.005 ) { $args->{ABSTRACT} = $self->abstract; $args->{AUTHOR} = join ', ', @{$self->author || []}; } if ( $self->makemaker(6.10) ) { $args->{NO_META} = 1; #$args->{NO_MYMETA} = 1; } if ( $self->makemaker(6.17) and $self->sign ) { $args->{SIGN} = 1; } unless ( $self->is_admin ) { delete $args->{SIGN}; } if ( $self->makemaker(6.31) and $self->license ) { $args->{LICENSE} = $self->license; } my $prereq = ($args->{PREREQ_PM} ||= {}); %$prereq = ( %$prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->requires) ); # Remove any reference to perl, PREREQ_PM doesn't support it delete $args->{PREREQ_PM}->{perl}; # Merge both kinds of requires into BUILD_REQUIRES my $build_prereq = ($args->{BUILD_REQUIRES} ||= {}); %$build_prereq = ( %$build_prereq, map { @$_ } # flatten [module => version] map { @$_ } grep $_, ($self->configure_requires, $self->build_requires) ); # Remove any reference to perl, BUILD_REQUIRES doesn't support it delete $args->{BUILD_REQUIRES}->{perl}; # Delete bundled dists from prereq_pm, add it to Makefile DIR my $subdirs = ($args->{DIR} || []); if ($self->bundles) { my %processed; foreach my $bundle (@{ $self->bundles }) { my ($mod_name, $dist_dir) = @$bundle; delete $prereq->{$mod_name}; $dist_dir = File::Basename::basename($dist_dir); # dir for building this module if (not exists $processed{$dist_dir}) { if (-d $dist_dir) { # List as sub-directory to be processed by make push @$subdirs, $dist_dir; } # Else do nothing: the module is already present on the system $processed{$dist_dir} = undef; } } } unless ( $self->makemaker('6.55_03') ) { %$prereq = (%$prereq,%$build_prereq); delete $args->{BUILD_REQUIRES}; } if ( my $perl_version = $self->perl_version ) { eval "use $perl_version; 1" or die "ERROR: perl: Version $] is installed, " . "but we need version >= $perl_version"; if ( $self->makemaker(6.48) ) { $args->{MIN_PERL_VERSION} = $perl_version; } } if ($self->installdirs) { warn qq{old INSTALLDIRS (probably set by makemaker_args) is overriden by installdirs\n} if $args->{INSTALLDIRS}; $args->{INSTALLDIRS} = $self->installdirs; } my %args = map { ( $_ => $args->{$_} ) } grep {defined($args->{$_} ) } keys %$args; my $user_preop = delete $args{dist}->{PREOP}; if ( my $preop = $self->admin->preop($user_preop) ) { foreach my $key ( keys %$preop ) { $args{dist}->{$key} = $preop->{$key}; } } my $mm = ExtUtils::MakeMaker::WriteMakefile(%args); $self->fix_up_makefile($mm->{FIRST_MAKEFILE} || 'Makefile'); } sub fix_up_makefile { my $self = shift; my $makefile_name = shift; my $top_class = ref($self->_top) || ''; my $top_version = $self->_top->VERSION || ''; my $preamble = $self->preamble ? "# Preamble by $top_class $top_version\n" . $self->preamble : ''; my $postamble = "# Postamble by $top_class $top_version\n" . ($self->postamble || ''); local *MAKEFILE; open MAKEFILE, "+< $makefile_name" or die "fix_up_makefile: Couldn't open $makefile_name: $!"; eval { flock MAKEFILE, LOCK_EX }; my $makefile = do { local $/; }; $makefile =~ s/\b(test_harness\(\$\(TEST_VERBOSE\), )/$1'inc', /; $makefile =~ s/( -I\$\(INST_ARCHLIB\))/ -Iinc$1/g; $makefile =~ s/( "-I\$\(INST_LIB\)")/ "-Iinc"$1/g; $makefile =~ s/^(FULLPERL = .*)/$1 "-Iinc"/m; $makefile =~ s/^(PERL = .*)/$1 "-Iinc"/m; # Module::Install will never be used to build the Core Perl # Sometimes PERL_LIB and PERL_ARCHLIB get written anyway, which breaks # PREFIX/PERL5LIB, and thus, install_share. Blank them if they exist $makefile =~ s/^PERL_LIB = .+/PERL_LIB =/m; #$makefile =~ s/^PERL_ARCHLIB = .+/PERL_ARCHLIB =/m; # Perl 5.005 mentions PERL_LIB explicitly, so we have to remove that as well. $makefile =~ s/(\"?)-I\$\(PERL_LIB\)\1//g; # XXX - This is currently unused; not sure if it breaks other MM-users # $makefile =~ s/^pm_to_blib\s+:\s+/pm_to_blib :: /mg; seek MAKEFILE, 0, SEEK_SET; truncate MAKEFILE, 0; print MAKEFILE "$preamble$makefile$postamble" or die $!; close MAKEFILE or die $!; 1; } sub preamble { my ($self, $text) = @_; $self->{preamble} = $text . $self->{preamble} if defined $text; $self->{preamble}; } sub postamble { my ($self, $text) = @_; $self->{postamble} ||= $self->admin->postamble; $self->{postamble} .= $text if defined $text; $self->{postamble} } 1; __END__ #line 544 Starlet-0.32/inc/Module/Install.pm0000644000175000017500000002714515176575244016433 0ustar kazuhokazuho#line 1 package Module::Install; # For any maintainers: # The load order for Module::Install is a bit magic. # It goes something like this... # # IF ( host has Module::Install installed, creating author mode ) { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to installed version of inc::Module::Install # 3. The installed version of inc::Module::Install loads # 4. inc::Module::Install calls "require Module::Install" # 5. The ./inc/ version of Module::Install loads # } ELSE { # 1. Makefile.PL calls "use inc::Module::Install" # 2. $INC{inc/Module/Install.pm} set to ./inc/ version of Module::Install # 3. The ./inc/ version of Module::Install loads # } use 5.006; use strict 'vars'; use Cwd (); use File::Find (); use File::Path (); use vars qw{$VERSION $MAIN}; BEGIN { # All Module::Install core packages now require synchronised versions. # This will be used to ensure we don't accidentally load old or # different versions of modules. # This is not enforced yet, but will be some time in the next few # releases once we can make sure it won't clash with custom # Module::Install extensions. $VERSION = '1.21'; # Storage for the pseudo-singleton $MAIN = undef; *inc::Module::Install::VERSION = *VERSION; @inc::Module::Install::ISA = __PACKAGE__; } sub import { my $class = shift; my $self = $class->new(@_); my $who = $self->_caller; #------------------------------------------------------------- # all of the following checks should be included in import(), # to allow "eval 'require Module::Install; 1' to test # installation of Module::Install. (RT #51267) #------------------------------------------------------------- # Whether or not inc::Module::Install is actually loaded, the # $INC{inc/Module/Install.pm} is what will still get set as long as # the caller loaded module this in the documented manner. # If not set, the caller may NOT have loaded the bundled version, and thus # they may not have a MI version that works with the Makefile.PL. This would # result in false errors or unexpected behaviour. And we don't want that. my $file = join( '/', 'inc', split /::/, __PACKAGE__ ) . '.pm'; unless ( $INC{$file} ) { die <<"END_DIE" } Please invoke ${\__PACKAGE__} with: use inc::${\__PACKAGE__}; not: use ${\__PACKAGE__}; END_DIE # This reportedly fixes a rare Win32 UTC file time issue, but # as this is a non-cross-platform XS module not in the core, # we shouldn't really depend on it. See RT #24194 for detail. # (Also, this module only supports Perl 5.6 and above). eval "use Win32::UTCFileTime" if $^O eq 'MSWin32' && $] >= 5.006; # If the script that is loading Module::Install is from the future, # then make will detect this and cause it to re-run over and over # again. This is bad. Rather than taking action to touch it (which # is unreliable on some platforms and requires write permissions) # for now we should catch this and refuse to run. if ( -f $0 ) { my $s = (stat($0))[9]; # If the modification time is only slightly in the future, # sleep briefly to remove the problem. my $a = $s - time; if ( $a > 0 and $a < 5 ) { sleep 5 } # Too far in the future, throw an error. my $t = time; if ( $s > $t ) { die <<"END_DIE" } Your installer $0 has a modification time in the future ($s > $t). This is known to create infinite loops in make. Please correct this, then run $0 again. END_DIE } # Build.PL was formerly supported, but no longer is due to excessive # difficulty in implementing every single feature twice. if ( $0 =~ /Build.PL$/i ) { die <<"END_DIE" } Module::Install no longer supports Build.PL. It was impossible to maintain duel backends, and has been deprecated. Please remove all Build.PL files and only use the Makefile.PL installer. END_DIE #------------------------------------------------------------- # To save some more typing in Module::Install installers, every... # use inc::Module::Install # ...also acts as an implicit use strict. $^H |= strict::bits(qw(refs subs vars)); #------------------------------------------------------------- unless ( -f $self->{file} ) { foreach my $key (keys %INC) { delete $INC{$key} if $key =~ /Module\/Install/; } local $^W; require "$self->{path}/$self->{dispatch}.pm"; File::Path::mkpath("$self->{prefix}/$self->{author}"); $self->{admin} = "$self->{name}::$self->{dispatch}"->new( _top => $self ); $self->{admin}->init; @_ = ($class, _self => $self); goto &{"$self->{name}::import"}; } local $^W; *{"${who}::AUTOLOAD"} = $self->autoload; $self->preload; # Unregister loader and worker packages so subdirs can use them again delete $INC{'inc/Module/Install.pm'}; delete $INC{'Module/Install.pm'}; # Save to the singleton $MAIN = $self; return 1; } sub autoload { my $self = shift; my $who = $self->_caller; my $cwd = Cwd::getcwd(); my $sym = "${who}::AUTOLOAD"; $sym->{$cwd} = sub { my $pwd = Cwd::getcwd(); if ( my $code = $sym->{$pwd} ) { # Delegate back to parent dirs goto &$code unless $cwd eq $pwd; } unless ($$sym =~ s/([^:]+)$//) { # XXX: it looks like we can't retrieve the missing function # via $$sym (usually $main::AUTOLOAD) in this case. # I'm still wondering if we should slurp Makefile.PL to # get some context or not ... my ($package, $file, $line) = caller; die <<"EOT"; Unknown function is found at $file line $line. Execution of $file aborted due to runtime errors. If you're a contributor to a project, you may need to install some Module::Install extensions from CPAN (or other repository). If you're a user of a module, please contact the author. EOT } my $method = $1; if ( uc($method) eq $method ) { # Do nothing return; } elsif ( $method =~ /^_/ and $self->can($method) ) { # Dispatch to the root M:I class return $self->$method(@_); } # Dispatch to the appropriate plugin unshift @_, ( $self, $1 ); goto &{$self->can('call')}; }; } sub preload { my $self = shift; unless ( $self->{extensions} ) { $self->load_extensions( "$self->{prefix}/$self->{path}", $self ); } my @exts = @{$self->{extensions}}; unless ( @exts ) { @exts = $self->{admin}->load_all_extensions; } my %seen; foreach my $obj ( @exts ) { while (my ($method, $glob) = each %{ref($obj) . '::'}) { next unless $obj->can($method); next if $method =~ /^_/; next if $method eq uc($method); $seen{$method}++; } } my $who = $self->_caller; foreach my $name ( sort keys %seen ) { local $^W; *{"${who}::$name"} = sub { ${"${who}::AUTOLOAD"} = "${who}::$name"; goto &{"${who}::AUTOLOAD"}; }; } } sub new { my ($class, %args) = @_; delete $INC{'FindBin.pm'}; { # to suppress the redefine warning local $SIG{__WARN__} = sub {}; require FindBin; } # ignore the prefix on extension modules built from top level. my $base_path = Cwd::abs_path($FindBin::Bin); unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) { delete $args{prefix}; } return $args{_self} if $args{_self}; $base_path = VMS::Filespec::unixify($base_path) if $^O eq 'VMS'; $args{dispatch} ||= 'Admin'; $args{prefix} ||= 'inc'; $args{author} ||= ($^O eq 'VMS' ? '_author' : '.author'); $args{bundle} ||= 'inc/BUNDLES'; $args{base} ||= $base_path; $class =~ s/^\Q$args{prefix}\E:://; $args{name} ||= $class; $args{version} ||= $class->VERSION; unless ( $args{path} ) { $args{path} = $args{name}; $args{path} =~ s!::!/!g; } $args{file} ||= "$args{base}/$args{prefix}/$args{path}.pm"; $args{wrote} = 0; bless( \%args, $class ); } sub call { my ($self, $method) = @_; my $obj = $self->load($method) or return; splice(@_, 0, 2, $obj); goto &{$obj->can($method)}; } sub load { my ($self, $method) = @_; $self->load_extensions( "$self->{prefix}/$self->{path}", $self ) unless $self->{extensions}; foreach my $obj (@{$self->{extensions}}) { return $obj if $obj->can($method); } my $admin = $self->{admin} or die <<"END_DIE"; The '$method' method does not exist in the '$self->{prefix}' path! Please remove the '$self->{prefix}' directory and run $0 again to load it. END_DIE my $obj = $admin->load($method, 1); push @{$self->{extensions}}, $obj; $obj; } sub load_extensions { my ($self, $path, $top) = @_; my $should_reload = 0; unless ( grep { ! ref $_ and lc $_ eq lc $self->{prefix} } @INC ) { unshift @INC, $self->{prefix}; $should_reload = 1; } foreach my $rv ( $self->find_extensions($path) ) { my ($file, $pkg) = @{$rv}; next if $self->{pathnames}{$pkg}; local $@; my $new = eval { local $^W; require $file; $pkg->can('new') }; unless ( $new ) { warn $@ if $@; next; } $self->{pathnames}{$pkg} = $should_reload ? delete $INC{$file} : $INC{$file}; push @{$self->{extensions}}, &{$new}($pkg, _top => $top ); } $self->{extensions} ||= []; } sub find_extensions { my ($self, $path) = @_; my @found; File::Find::find( {no_chdir => 1, wanted => sub { my $file = $File::Find::name; return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is; my $subpath = $1; return if lc($subpath) eq lc($self->{dispatch}); $file = "$self->{path}/$subpath.pm"; my $pkg = "$self->{name}::$subpath"; $pkg =~ s!/!::!g; # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) { my $content = Module::Install::_read($File::Find::name); my $in_pod = 0; foreach ( split /\n/, $content ) { $in_pod = 1 if /^=\w/; $in_pod = 0 if /^=cut/; next if ($in_pod || /^=cut/); # skip pod text next if /^\s*#/; # and comments if ( m/^\s*package\s+($pkg)\s*;/i ) { $pkg = $1; last; } } } push @found, [ $file, $pkg ]; }}, $path ) if -d $path; @found; } ##################################################################### # Common Utility Functions sub _caller { my $depth = 0; my $call = caller($depth); while ( $call eq __PACKAGE__ ) { $depth++; $call = caller($depth); } return $call; } sub _read { local *FH; open( FH, '<', $_[0] ) or die "open($_[0]): $!"; binmode FH; my $string = do { local $/; }; close FH or die "close($_[0]): $!"; return $string; } sub _readperl { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; $string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s; $string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg; return $string; } sub _readpod { my $string = Module::Install::_read($_[0]); $string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg; return $string if $_[0] =~ /\.pod\z/; $string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg; $string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg; $string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg; $string =~ s/^\n+//s; return $string; } sub _write { local *FH; open( FH, '>', $_[0] ) or die "open($_[0]): $!"; binmode FH; foreach ( 1 .. $#_ ) { print FH $_[$_] or die "print($_[0]): $!"; } close FH or die "close($_[0]): $!"; } # _version is for processing module versions (eg, 1.03_05) not # Perl versions (eg, 5.8.1). sub _version { my $s = shift || 0; my $d =()= $s =~ /(\.)/g; if ( $d >= 2 ) { # Normalise multipart versions $s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg; } $s =~ s/^(\d+)\.?//; my $l = $1 || 0; my @v = map { $_ . '0' x (3 - length $_) } $s =~ /(\d{1,3})\D?/g; $l = $l . '.' . join '', @v if @v; return $l + 0; } sub _cmp { _version($_[1]) <=> _version($_[2]); } # Cloned from Params::Util::_CLASS sub _CLASS { ( defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s ) ? $_[0] : undef; } 1; # Copyright 2008 - 2012 Adam Kennedy. Starlet-0.32/MANIFEST0000644000175000017500000000154015176575257013615 0ustar kazuhokazuho.gitignore Changes inc/Module/Install.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/ReadmeFromPod.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm lib/Plack/Handler/Starlet.pm lib/Starlet.pm lib/Starlet/Server.pm Makefile.PL MANIFEST This list of files META.yml README t/00base-hello.psgi t/00base.t t/01plack-test.t t/02graceful.t t/03post.t t/04-bumpy-life.t t/05server-header.t t/06harakiri.t t/07remote_port.t t/08chunked_req.t t/09chunked_zero_length.t t/10unix_domain_socket.t t/11multi-sockets.t t/12bad_request_line.t t/13expect.t t/13spawn_interval.t t/14child_finish_hook.t t/14interim_response.t t/15smuggling-content-length-and-transfer-encoding.t t/16smuggling-multiple-content-length-header.t t/assets/baybridge.jpg Starlet-0.32/README0000644000175000017500000000631715176575244013347 0ustar kazuhokazuhoNAME Starlet - a simple, high-performance PSGI/Plack HTTP server SYNOPSIS % start_server --port=80 -- plackup -s Starlet [options] your-app.psgi or if you do not need hot deploy, % plackup -s Starlet --port=80 [options] your-app.psgi DESCRIPTION Starlet is a standalone HTTP/1.1 web server, formerly known as Plack::Server::Standalone::Prefork and Plack::Server::Standalone::Prefork::Server::Starter. The server supports following features, and is suitable for running HTTP application servers behind a reverse proxy. - prefork and graceful shutdown using Parallel::Prefork - hot deploy using Server::Starter - fast HTTP processing using HTTP::Parser::XS (optional) COMMAND LINE OPTIONS In addition to the options supported by plackup, Starlet accepts following options(s). --max-workers=# number of worker processes (default: 10) --timeout=# seconds until timeout (default: 300) --keepalive-timeout=# timeout for persistent connections (default: 2) --max-keepalive-reqs=# max. number of requests allowed per single persistent connection. If set to one, persistent connections are disabled (default: 1) --max-reqs-per-child=# max. number of requests to be handled before a worker process exits (default: 100) --min-reqs-per-child=# if set, randomizes the number of requests handled by a single worker process between the value and that supplied by "--max-reqs-per-chlid" (default: none) --spawn-interval=# if set, worker processes will not be spawned more than once than every given seconds. Also, when SIGHUP is being received, no more than one worker processes will be collected every given seconds. This feature is useful for doing a "slow-restart". See http://blog.kazuhooku.com/2011/04/web-serverstarter-parallelprefork.html for more information. (default: none) --child-exit=s the subroutine code to be executed right before a child process exits. e.g. "--child-exit='sub { POSIX::_exit(0) }'". (default: none) Extensions to PSGI psgix.informational Starlets exposes a callback named "psgix.informational" that can be used for sending an informational response. The callback accepts two arguments, the first argument being the status code and the second being an arrayref of the headers to be sent. Example below sends an 103 response before processing the request to build a final response. sub { my $env = shift; $env["psgix.informational"}->(103, [ 'link' => '; rel=preload' ]); my $resp = ... application logic ... $resp; } NOTES Starlet is designed and implemented to be simple, secure and fast, especially for running as an HTTP application server running behind a reverse proxy. It only depends on a minimal number of well-designed (and well-focused) modules. SEE ALSO Parallel::Prefork Starman Server::Starter AUTHOR Kazuho Oku miyagawa kazeburo Tomohiro Takezawa LICENSE This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See Starlet-0.32/Makefile.PL0000644000175000017500000000067115176574475014443 0ustar kazuhokazuhouse inc::Module::Install; all_from 'lib/Starlet.pm'; readme_from 'lib/Starlet.pm'; resources repository => 'https://github.com/kazuho/Starlet'; resources bugtracker => 'https://github.com/kazuho/Starlet/issues'; requires 'Plack' => 0.9920; requires 'Parallel::Prefork' => 0.18; requires 'Server::Starter' => 0.06; test_requires 'Test::More' => 0.88; test_requires 'Test::TCP' => 2.10; test_requires 'LWP::UserAgent' => 5.80; WriteAll; Starlet-0.32/.gitignore0000644000175000017500000000010615176574475014452 0ustar kazuhokazuho*~ *.bak Makefile blib/ inc/ MANIFEST META.yml MYMETA.yml MYMETA.json Starlet-0.32/lib/0000755000175000017500000000000015176575263013227 5ustar kazuhokazuhoStarlet-0.32/lib/Plack/0000755000175000017500000000000015176575263014261 5ustar kazuhokazuhoStarlet-0.32/lib/Plack/Handler/0000755000175000017500000000000015176575263015636 5ustar kazuhokazuhoStarlet-0.32/lib/Plack/Handler/Starlet.pm0000644000175000017500000000641115176574475017620 0ustar kazuhokazuhopackage Plack::Handler::Starlet; use strict; use warnings; use Parallel::Prefork; use Server::Starter (); use base qw(Starlet::Server); sub new { my ($klass, %args) = @_; # setup before instantiation if (defined $ENV{SERVER_STARTER_PORT}) { $args{listens} = []; my $server_ports = Server::Starter::server_ports(); for my $hostport (keys %$server_ports) { my $fd = $server_ports->{$hostport}; my $listen = {}; if ($hostport =~ /(.*):(\d+)/) { $listen->{host} = $1; $listen->{port} = $2; } else { $listen->{port} = $hostport; } $listen->{sock} = IO::Socket::INET->new( Proto => 'tcp', ) or die "failed to create socket:$!"; $listen->{sock}->fdopen($fd, 'w') or die "failed to bind to listening socket:$!"; unless (@{$args{listens}}) { $args{host} = $listen->{host}; $args{port} = $listen->{port}; } $args{listens}[$fd] = $listen; } } my $max_workers = 10; for (qw(max_workers workers)) { $max_workers = delete $args{$_} if defined $args{$_}; } if ($args{child_exit}) { $args{child_exit} = eval $args{child_exit} unless ref($args{child_exit}); die "child_exit is defined but not a code block" if ref($args{child_exit}) ne 'CODE'; } # instantiate and set the variables my $self = $klass->SUPER::new(%args); $self->{is_multiprocess} = 1; $self->{max_workers} = $max_workers; $self; } sub run { my($self, $app) = @_; $self->setup_listener(); if ($self->{max_workers} != 0) { # use Parallel::Prefork my %pm_args = ( max_workers => $self->{max_workers}, trap_signals => { TERM => 'TERM', HUP => 'TERM', }, ); if (defined $self->{spawn_interval}) { $pm_args{trap_signals}{USR1} = [ 'TERM', $self->{spawn_interval} ]; $pm_args{spawn_interval} = $self->{spawn_interval}; } if (defined $self->{err_respawn_interval}) { $pm_args{err_respawn_interval} = $self->{err_respawn_interval}; } my $pm = Parallel::Prefork->new(\%pm_args); while ($pm->signal_received !~ /^(TERM|USR1)$/) { $pm->start and next; srand((rand() * 2 ** 30) ^ $$ ^ time); $self->accept_loop($app, $self->_calc_reqs_per_child()); $pm->finish; } my $timeout = 1; if ($self->{spawn_interval}) { $timeout = $self->{spawn_interval} * $self->{max_workers} } while ($pm->wait_all_children($timeout)) { $pm->signal_all_children('TERM'); } } else { # run directly, mainly for debugging local $SIG{TERM} = sub { exit 0; }; while (1) { $self->accept_loop($app, $self->_calc_reqs_per_child()); } } } sub _calc_reqs_per_child { my $self = shift; my $max = $self->{max_reqs_per_child}; if (my $min = $self->{min_reqs_per_child}) { return $max - int(($max - $min + 1) * rand); } else { return $max; } } 1; Starlet-0.32/lib/Starlet.pm0000644000175000017500000000633515176575226015211 0ustar kazuhokazuhopackage Starlet; use 5.008_001; our $VERSION = '0.32'; 1; __END__ =head1 NAME Starlet - a simple, high-performance PSGI/Plack HTTP server =head1 SYNOPSIS % start_server --port=80 -- plackup -s Starlet [options] your-app.psgi or if you do not need hot deploy, % plackup -s Starlet --port=80 [options] your-app.psgi =head1 DESCRIPTION Starlet is a standalone HTTP/1.1 web server, formerly known as L and L. The server supports following features, and is suitable for running HTTP application servers behind a reverse proxy. - prefork and graceful shutdown using L - hot deploy using L - fast HTTP processing using L (optional) =head1 COMMAND LINE OPTIONS In addition to the options supported by L, Starlet accepts following options(s). =head2 --max-workers=# number of worker processes (default: 10) =head2 --timeout=# seconds until timeout (default: 300) =head2 --keepalive-timeout=# timeout for persistent connections (default: 2) =head2 --max-keepalive-reqs=# max. number of requests allowed per single persistent connection. If set to one, persistent connections are disabled (default: 1) =head2 --max-reqs-per-child=# max. number of requests to be handled before a worker process exits (default: 100) =head2 --min-reqs-per-child=# if set, randomizes the number of requests handled by a single worker process between the value and that supplied by C<--max-reqs-per-chlid> (default: none) =head2 --spawn-interval=# if set, worker processes will not be spawned more than once than every given seconds. Also, when SIGHUP is being received, no more than one worker processes will be collected every given seconds. This feature is useful for doing a "slow-restart". See http://blog.kazuhooku.com/2011/04/web-serverstarter-parallelprefork.html for more information. (default: none) =head2 --child-exit=s the subroutine code to be executed right before a child process exits. e.g. C<--child-exit='sub { POSIX::_exit(0) }'>. (default: none) =head1 Extensions to PSGI =head2 psgix.informational Starlets exposes a callback named C that can be used for sending an informational response. The callback accepts two arguments, the first argument being the status code and the second being an arrayref of the headers to be sent. Example below sends an 103 response before processing the request to build a final response. sub { my $env = shift; $env["psgix.informational"}->(103, [ 'link' => '; rel=preload' ]); my $resp = ... application logic ... $resp; } =head1 NOTES L is designed and implemented to be simple, secure and fast, especially for running as an HTTP application server running behind a reverse proxy. It only depends on a minimal number of well-designed (and well-focused) modules. =head1 SEE ALSO L L L =head1 AUTHOR Kazuho Oku miyagawa kazeburo Tomohiro Takezawa =head1 LICENSE This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L =cut Starlet-0.32/lib/Starlet/0000755000175000017500000000000015176575263014645 5ustar kazuhokazuhoStarlet-0.32/lib/Starlet/Server.pm0000644000175000017500000005116215176574475016462 0ustar kazuhokazuhopackage Starlet::Server; use strict; use warnings; use Carp (); use Plack; use Plack::HTTPParser qw( parse_http_request ); use IO::Socket::INET; use HTTP::Date; use HTTP::Status; use List::Util qw(max sum); use Plack::Util; use Plack::TempBuffer; use POSIX qw(EINTR EAGAIN EWOULDBLOCK); use Socket qw(IPPROTO_TCP TCP_NODELAY); use File::Temp qw(tempfile); use Fcntl qw(:flock); use Try::Tiny; use Time::HiRes qw(time); use constant MAX_REQUEST_SIZE => 131072; use constant CHUNKSIZE => 64 * 1024; use constant MSWin32 => $^O eq 'MSWin32'; my $null_io = do { open my $io, "<", \""; $io }; sub new { my($class, %args) = @_; my $self = bless { listens => $args{listens} || [], host => $args{host} || 0, port => $args{port} || $args{socket} || 8080, timeout => $args{timeout} || 300, keepalive_timeout => $args{keepalive_timeout} || 2, max_keepalive_reqs => $args{max_keepalive_reqs} || 1, server_software => $args{server_software} || $class, server_ready => $args{server_ready} || sub {}, min_reqs_per_child => ( defined $args{min_reqs_per_child} ? $args{min_reqs_per_child} : undef, ), max_reqs_per_child => ( $args{max_reqs_per_child} || $args{max_requests} || 100, ), spawn_interval => $args{spawn_interval} || 0, err_respawn_interval => ( defined $args{err_respawn_interval} ? $args{err_respawn_interval} : undef, ), is_multiprocess => Plack::Util::FALSE, child_exit => $args{child_exit} || sub {}, _using_defer_accept => undef, }, $class; if ($args{max_workers} && $args{max_workers} > 1) { Carp::carp( "Preforking in $class is deprecated. Falling back to the non-forking mode. ", "If you need preforking, use Starman or Starlet instead and run like `plackup -s Starlet`", ); } $self; } sub run { my($self, $app) = @_; $self->setup_listener(); $self->accept_loop($app); } sub setup_listener { my $self = shift; if (scalar(grep {defined $_} @{$self->{listens}}) == 0) { my $sock; if ($self->{port} =~ /^[0-9]+$/s) { $sock = IO::Socket::INET->new( Listen => SOMAXCONN, LocalPort => $self->{port}, LocalAddr => $self->{host}, Proto => 'tcp', ReuseAddr => 1, ) or die "failed to listen to port $self->{port}:$!"; } else { $sock = IO::Socket::UNIX->new( Listen => SOMAXCONN, Local => $self->{port}, ) or die "failed to listen to socket $self->{port}:$!"; } $self->{listens}[fileno($sock)] = { host => $self->{host}, port => $self->{port}, sock => $sock, }; } my @listens = grep {defined $_} @{$self->{listens}}; for my $listen (@listens) { my $family = Socket::sockaddr_family(getsockname($listen->{sock})); $listen->{_is_tcp} = $family != AF_UNIX; # set defer accept if ($^O eq 'linux' && $listen->{_is_tcp}) { setsockopt($listen->{sock}, IPPROTO_TCP, 9, 1) and $listen->{_using_defer_accept} = 1; } } if (scalar(@listens) > 1) { $self->{lock_path} ||= do { my ($fh, $lock_path) = tempfile(UNLINK => 1); # closing the file handle explicitly for two reasons # 1) tempfile retains the handle when UNLINK is set # 2) tempfile implicitely locks the file on OS X close $fh; $lock_path; }; } $self->{server_ready}->($self); } sub accept_loop { # TODO handle $max_reqs_per_child my($self, $app, $max_reqs_per_child) = @_; my $proc_req_count = 0; my $is_keepalive = 0; local $SIG{TERM} = sub { $self->{term_received} = 1; }; local $SIG{PIPE} = 'IGNORE'; my $acceptor = $self->_get_acceptor; while (! defined $max_reqs_per_child || $proc_req_count < $max_reqs_per_child) { # accept (or exit on SIGTERM) if ($self->{term_received}) { $self->{child_exit}->($self, $app); exit 0; } my ($conn, $peer, $listen) = $acceptor->(); next unless $conn; $self->{_is_deferred_accept} = $listen->{_using_defer_accept}; defined($conn->blocking(0)) or die "failed to set socket to nonblocking mode:$!"; my ($peerport, $peerhost, $peeraddr) = (0, undef, undef); if ($listen->{_is_tcp}) { $conn->setsockopt(IPPROTO_TCP, TCP_NODELAY, 1) or die "setsockopt(TCP_NODELAY) failed:$!"; ($peerport, $peerhost) = unpack_sockaddr_in $peer; $peeraddr = inet_ntoa($peerhost); } my $req_count = 0; my $pipelined_buf = ''; while (1) { ++$req_count; ++$proc_req_count; my $env = { SERVER_PORT => $listen->{port} || 0, SERVER_NAME => $listen->{host} || 0, SCRIPT_NAME => '', REMOTE_ADDR => $peeraddr, REMOTE_PORT => $peerport, 'psgi.version' => [ 1, 1 ], 'psgi.errors' => *STDERR, 'psgi.url_scheme' => 'http', 'psgi.run_once' => Plack::Util::FALSE, 'psgi.multithread' => Plack::Util::FALSE, 'psgi.multiprocess' => $self->{is_multiprocess}, 'psgi.streaming' => Plack::Util::TRUE, 'psgi.nonblocking' => Plack::Util::FALSE, 'psgix.input.buffered' => Plack::Util::TRUE, 'psgix.io' => $conn, 'psgix.harakiri' => 1, 'psgix.informational' => sub { $self->_informational($conn, @_); }, }; my $may_keepalive = $req_count < $self->{max_keepalive_reqs}; if ($may_keepalive && $max_reqs_per_child && $proc_req_count >= $max_reqs_per_child) { $may_keepalive = undef; } $may_keepalive = 1 if length $pipelined_buf; my $keepalive; ($keepalive, $pipelined_buf) = $self->handle_connection($env, $conn, $app, $may_keepalive, $req_count != 1, $pipelined_buf); if ($env->{'psgix.harakiri.commit'}) { $conn->close; return; } last unless $keepalive; # TODO add special cases for clients with broken keep-alive support, as well as disabling keep-alive for HTTP/1.0 proxies } $conn->close; } } sub _get_acceptor { my $self = shift; my @listens = grep {defined $_} @{$self->{listens}}; if (scalar(@listens) == 1) { my $listen = $listens[0]; return sub { if (my ($conn, $peer) = $listen->{sock}->accept) { return ($conn, $peer, $listen); } return +(); }; } else { # wait for multiple sockets with select(2) my @fds; my $rin = ''; for my $listen (@listens) { defined($listen->{sock}->blocking(0)) or die "failed to set listening socket to non-blocking mode:$!"; my $fd = fileno($listen->{sock}); push @fds, $fd; vec($rin, $fd, 1) = 1; } open(my $lock_fh, '>', $self->{lock_path}) or die "failed to open lock file:@{[$self->{lock_path}]}:$!"; return sub { if (! flock($lock_fh, LOCK_EX)) { die "failed to lock file:@{[$self->{lock_path}]}:$!" if $! != EINTR; return +(); } my $nfound = select(my $rout = $rin, undef, undef, undef); for (my $i = 0; $nfound > 0; ++$i) { my $fd = $fds[$i]; next unless vec($rout, $fd, 1); --$nfound; my $listen = $self->{listens}[$fd]; if (my ($conn, $peer) = $listen->{sock}->accept) { flock($lock_fh, LOCK_UN); return ($conn, $peer, $listen); } } flock($lock_fh, LOCK_UN); return +(); }; } } my $bad_response = [ 400, [ 'Content-Type' => 'text/plain', 'Connection' => 'close' ], [ 'Bad Request' ] ]; sub handle_connection { my($self, $env, $conn, $app, $use_keepalive, $is_keepalive, $prebuf) = @_; my $buf = ''; my $pipelined_buf=''; my $res = $bad_response; while (1) { my $rlen; if ( $rlen = length $prebuf ) { $buf = $prebuf; undef $prebuf; } else { $rlen = $self->read_timeout( $conn, \$buf, MAX_REQUEST_SIZE - length($buf), length($buf), $is_keepalive ? $self->{keepalive_timeout} : $self->{timeout}, ) or return; } my $reqlen = parse_http_request($buf, $env); if ($reqlen >= 0) { # handle request my $protocol = $env->{SERVER_PROTOCOL}; if ($use_keepalive) { if ($self->{term_received}) { $use_keepalive = undef; } elsif ( $protocol eq 'HTTP/1.1' ) { if (my $c = $env->{HTTP_CONNECTION}) { $use_keepalive = undef if $c =~ /^\s*close\s*/i; } } else { if (my $c = $env->{HTTP_CONNECTION}) { $use_keepalive = undef unless $c =~ /^\s*keep-alive\s*/i; } else { $use_keepalive = undef; } } } $buf = substr $buf, $reqlen; my $chunked = do { no warnings; lc delete $env->{HTTP_TRANSFER_ENCODING} eq 'chunked' }; # If a message is received with both a Transfer-Encoding and a # Content-Length header field, the Transfer-Encoding overrides the # Content-Length. Such a message might indicate an attempt to # perform request smuggling (Section 9.5) or response splitting # (Section 9.4) and ought to be handled as an error. A sender MUST # remove the received Content-Length field prior to forwarding such # a message downstream. if ($chunked && $env->{CONTENT_LENGTH}) { delete $env->{CONTENT_LENGTH}; } if ( $env->{HTTP_EXPECT} ) { if ( lc $env->{HTTP_EXPECT} eq '100-continue' ) { $self->write_all($conn, "HTTP/1.1 100 Continue\015\012\015\012") or return; } else { $res = [417,[ 'Content-Type' => 'text/plain', 'Connection' => 'close' ], [ 'Expectation Failed' ] ]; last; } } if (my $cl = $env->{CONTENT_LENGTH}) { if ($cl !~ /^[0-9]+$/) { # content-length header must be digits. last; # Return bad response } my $buffer = Plack::TempBuffer->new($cl); while ($cl > 0) { my $chunk; if (length $buf) { $chunk = $buf; $buf = ''; } else { $self->read_timeout( $conn, \$chunk, $cl, 0, $self->{timeout}) or return; } $buffer->print($chunk); $cl -= length $chunk; } $env->{'psgi.input'} = $buffer->rewind; } elsif ($chunked) { my $buffer = Plack::TempBuffer->new; my $chunk_buffer = ''; my $length; DECHUNK: while(1) { my $chunk; if ( length $buf ) { $chunk = $buf; $buf = ''; } else { $self->read_timeout($conn, \$chunk, CHUNKSIZE, 0, $self->{timeout}) or return; } $chunk_buffer .= $chunk; while ( $chunk_buffer =~ s/^(([0-9a-fA-F]+).*\015\012)// ) { my $trailer = $1; my $chunk_len = hex $2; if ($chunk_len == 0) { last DECHUNK; } elsif (length $chunk_buffer < $chunk_len + 2) { $chunk_buffer = $trailer . $chunk_buffer; last; } $buffer->print(substr $chunk_buffer, 0, $chunk_len, ''); $chunk_buffer =~ s/^\015\012//; $length += $chunk_len; } } $env->{CONTENT_LENGTH} = $length; $env->{'psgi.input'} = $buffer->rewind; } else { if ( $buf =~ m!^(?:GET|HEAD)! ) { #pipeline $pipelined_buf = $buf; $use_keepalive = 1; #force keepalive } # else clear buffer $env->{'psgi.input'} = $null_io; } $res = Plack::Util::run_app $app, $env; last; } if ($reqlen == -2) { # request is incomplete, do nothing } elsif ($reqlen == -1) { # error, close conn last; } } if (ref $res eq 'ARRAY') { $self->_handle_response($env->{SERVER_PROTOCOL}, $res, $conn, \$use_keepalive); } elsif (ref $res eq 'CODE') { $res->(sub { $self->_handle_response($env->{SERVER_PROTOCOL}, $_[0], $conn, \$use_keepalive); }); } else { die "Bad response $res"; } return ($use_keepalive, $pipelined_buf); } sub _informational { my ($self, $conn, $status_code, $headers) = @_; my @lines = "HTTP/1.1 $status_code @{[ HTTP::Status::status_message($status_code) ]}\015\012"; for (my $i = 0; $i < @$headers; $i += 2) { my $k = $headers->[$i]; my $v = $headers->[$i + 1]; push @lines, "$k: $v\015\012"; } push @lines, "\015\012"; $self->write_all($conn, join("", @lines), $self->{timeout}); } sub _handle_response { my($self, $protocol, $res, $conn, $use_keepalive_r) = @_; my $status_code = $res->[0]; my $headers = $res->[1]; my $body = $res->[2]; my @lines; my %send_headers; for (my $i = 0; $i < @$headers; $i += 2) { my $k = $headers->[$i]; my $v = $headers->[$i + 1]; my $lck = lc $k; if ($lck eq 'connection') { $$use_keepalive_r = undef if $$use_keepalive_r && lc $v ne 'keep-alive'; } else { push @lines, "$k: $v\015\012"; $send_headers{$lck} = $v; } } if ( ! exists $send_headers{server} ) { unshift @lines, "Server: $self->{server_software}\015\012"; } if ( ! exists $send_headers{date} ) { unshift @lines, "Date: @{[HTTP::Date::time2str()]}\015\012"; } # try to set content-length when keepalive can be used, or disable it my $use_chunked; if (defined($protocol) && $protocol eq 'HTTP/1.1') { if (defined $send_headers{'content-length'} || defined $send_headers{'transfer-encoding'}) { # ok } elsif (!Plack::Util::status_with_no_entity_body($status_code)) { push @lines, "Transfer-Encoding: chunked\015\012"; $use_chunked = 1; } push @lines, "Connection: close\015\012" unless $$use_keepalive_r; } else { # HTTP/1.0 if ($$use_keepalive_r) { if (defined $send_headers{'content-length'} || defined $send_headers{'transfer-encoding'}) { # ok } elsif (!Plack::Util::status_with_no_entity_body($status_code) && defined(my $cl = Plack::Util::content_length($body))) { push @lines, "Content-Length: $cl\015\012"; } else { $$use_keepalive_r = undef; } } push @lines, "Connection: keep-alive\015\012" if $$use_keepalive_r; push @lines, "Connection: close\015\012" if !$$use_keepalive_r; #fmm.. } unshift @lines, "HTTP/1.1 $status_code @{[ HTTP::Status::status_message($status_code) ]}\015\012"; push @lines, "\015\012"; if (defined $body && ref $body eq 'ARRAY' && @$body == 1 && length $body->[0] < 8192) { # combine response header and small request body my $buf = $body->[0]; if ($use_chunked ) { my $len = length $buf; $buf = sprintf("%x",$len) . "\015\012" . $buf . "\015\012" . '0' . "\015\012\015\012"; } $self->write_all( $conn, join('', @lines, $buf), $self->{timeout}, ); return; } $self->write_all($conn, join('', @lines), $self->{timeout}) or return; if (defined $body) { my $failed; my $completed; my $body_count = (ref $body eq 'ARRAY') ? $#{$body} + 1 : -1; Plack::Util::foreach( $body, sub { unless ($failed) { my $buf = $_[0]; --$body_count; if ( $use_chunked ) { my $len = length $buf; return unless $len; $buf = sprintf("%x",$len) . "\015\012" . $buf . "\015\012"; if ( $body_count == 0 ) { $buf .= '0' . "\015\012\015\012"; $completed = 1; } } $self->write_all($conn, $buf, $self->{timeout}) or $failed = 1; } }, ); $self->write_all($conn, '0' . "\015\012\015\012", $self->{timeout}) if $use_chunked && !$completed; } else { return Plack::Util::inline_object write => sub { my $buf = $_[0]; if ( $use_chunked ) { my $len = length $buf; return unless $len; $buf = sprintf("%x",$len) . "\015\012" . $buf . "\015\012" } $self->write_all($conn, $buf, $self->{timeout}) }, close => sub { $self->write_all($conn, '0' . "\015\012\015\012", $self->{timeout}) if $use_chunked; }; } } # returns value returned by $cb, or undef on timeout or network error sub do_io { my ($self, $is_write, $sock, $buf, $len, $off, $timeout) = @_; my $ret; unless ($is_write || delete $self->{_is_deferred_accept}) { goto DO_SELECT; } DO_READWRITE: # try to do the IO if ($is_write) { $ret = syswrite $sock, $buf, $len, $off and return $ret; } else { $ret = sysread $sock, $$buf, $len, $off and return $ret; } unless ((! defined($ret) && ($! == EINTR || $! == EAGAIN || $! == EWOULDBLOCK))) { return; } # wait for data DO_SELECT: while (1) { my ($rfd, $wfd); my $efd = ''; vec($efd, fileno($sock), 1) = 1; if ($is_write) { ($rfd, $wfd) = ('', $efd); } else { ($rfd, $wfd) = ($efd, ''); } my $start_at = time; my $nfound = select($rfd, $wfd, $efd, $timeout); $timeout -= (time - $start_at); last if $nfound; return if $timeout <= 0; } goto DO_READWRITE; } # returns (positive) number of bytes read, or undef if the socket is to be closed sub read_timeout { my ($self, $sock, $buf, $len, $off, $timeout) = @_; $self->do_io(undef, $sock, $buf, $len, $off, $timeout); } # returns (positive) number of bytes written, or undef if the socket is to be closed sub write_timeout { my ($self, $sock, $buf, $len, $off, $timeout) = @_; $self->do_io(1, $sock, $buf, $len, $off, $timeout); } # writes all data in buf and returns number of bytes written or undef if failed sub write_all { my ($self, $sock, $buf, $timeout) = @_; my $off = 0; while (my $len = length($buf) - $off) { my $ret = $self->write_timeout($sock, $buf, $len, $off, $timeout) or return; $off += $ret; } return length $buf; } 1; Starlet-0.32/t/0000755000175000017500000000000015176575263012724 5ustar kazuhokazuhoStarlet-0.32/t/07remote_port.t0000644000175000017500000000175415176574475015632 0ustar kazuhokazuhouse strict; use warnings; use Test::More; use Test::TCP; use LWP::UserAgent; use IO::Socket::INET; use Plack::Loader; test_tcp( client => sub { my $port = shift; sleep 1; my $sock = IO::Socket::INET->new( PeerAddr => "localhost:$port", Proto => 'tcp', ); ok($sock); my $localport = $sock->sockport; my $req = "GET / HTTP/1.0\015\012\015\012"; $sock->syswrite($req,length($req)); $sock->sysread( my $buf, 1024); like( $buf, qr/HELLO $localport/); }, server => sub { my $port = shift; my $loader = Plack::Loader->load( 'Starlet', port => $port, max_workers => 5, ); $loader->run(sub{ my $env = shift; my @headers = (); my $remote_port = $env->{REMOTE_PORT}; [200, ['Content-Type'=>'text/html'], ['HELLO '.$remote_port]]; }); exit; }, ); done_testing; Starlet-0.32/t/14interim_response.t0000644000175000017500000000212015176574475016642 0ustar kazuhokazuhouse strict; use warnings; use Test::More; use Test::TCP qw(test_tcp); use IO::Socket::INET; use Plack::Loader; test_tcp( client => sub { my $port = shift; my $sock = IO::Socket::INET->new( PeerAddr => "localhost:$port", Proto => 'tcp', ); my $req = "GET / HTTP/1.1\015\012\015\012"; $sock->syswrite($req, length $req); my $resp = ""; while ($sock->sysread($resp, 65536, length $resp)) {} my $expected_interim = <<"EOT"; HTTP/1\.1 100 Continue\015 foo: 123\015 bar: 456\015 \015 EOT is substr($resp, 0, length $expected_interim), $expected_interim; like substr($resp, length $expected_interim), qr{^HTTP/1\.1 200 OK\015\012}is; }, server => sub { my $port = shift; my $loader = Plack::Loader->load('Starlet', port => $port); $loader->run(sub { my $env = shift; $env->{"psgix.informational"}->(100, [foo => 123, bar => 456]); [200, ['Content-Type' => 'text/plain'], ["OK"]]; }); exit; }, ); done_testing; Starlet-0.32/t/14child_finish_hook.t0000644000175000017500000000106015176574475016722 0ustar kazuhokazuhouse strict; use warnings; use Test::More; use Plack::Runner; $SIG{CONT} = sub { pass('child_exit has been executed.') }; plan tests => 1; our $main_pid = $$; my $pid = fork; if ( $pid == 0 ) { my $runner = Plack::Runner->new; $runner->parse_options( qw(--server Starlet --max-workers 1 --child-exit), "sub { kill 'CONT', $main_pid }", ); $runner->run(sub{ my $env = shift; [200, ['Content-Type'=>'text/html'], ["HELLO"]]; }); exit 0; } sleep 1; kill 'TERM', $pid; waitpid($pid, 0); done_testing(); Starlet-0.32/t/13expect.t0000644000175000017500000000207415176574475014554 0ustar kazuhokazuhouse strict; use warnings; use Test::More; use Test::TCP; use LWP::UserAgent; use Plack::Loader; test_tcp( client => sub { my $port = shift; sleep 1; my $ua = LWP::UserAgent->new; my $res = $ua->post( "http://localhost:$port/", { blah => 1 }, Expect => '100-continue' ); ok( $res->is_success ); is( $res->content, 'HELLO', 'Expect header in standard case works' ); $res = $ua->post( "http://localhost:$port/", { blah => 1 }, Expect => '100-Continue' ); ok( $res->is_success ); is( $res->content, 'HELLO', 'Expect header is case insensitive' ); }, server => sub { my $port = shift; my $loader = Plack::Loader->load( 'Starlet', port => $port, max_workers => 5, ); $loader->run( sub { my $env = shift; [ 200, [], ['HELLO'] ]; } ); exit; }, ); done_testing; Starlet-0.32/t/16smuggling-multiple-content-length-header.t0000644000175000017500000000236715176574475023276 0ustar kazuhokazuhouse strict; use Test::TCP; use Plack::Test; use HTTP::Request; use HTTP::Message::PSGI; use Test::More; use Digest::MD5; use Plack::Test::Server; use Test::TCP; use IO::Socket::INET; $ENV{PLACK_SERVER} = 'Starlet'; my $app = sub { my $env = shift; my $body; my $clen = $env->{CONTENT_LENGTH}; while ($clen > 0) { $env->{'psgi.input'}->read(my $buf, $clen) or last; $clen -= length $buf; $body .= $buf; } return [ 200, [ 'Content-Type', 'text/plain', 'X-Content-Length', $env->{CONTENT_LENGTH} ], [ $body ] ]; }; my $server = Test::TCP->new( code => sub { my $sock_or_port = shift; my $server = Plack::Loader->auto( port => $sock_or_port, host => '127.0.0.1' ); $server->run($app); exit; }, ); my $sock = IO::Socket::INET->new( PeerAddr => '127.0.0.1', PeerPort => $server->port, Proto => 'tcp', ); print {$sock} ( "GET / HTTP/1.1\015\012" . "content-length: 3\015\012" . "content-length: 9\015\012" . "connection: close\015\012" . "\015\012" . "123456789" ); my $res_str = do { local $/; <$sock> }; my ($status_line, ) = split /\015\012/, $res_str; is $status_line, 'HTTP/1.1 400 Bad Request'; done_testing; Starlet-0.32/t/15smuggling-content-length-and-transfer-encoding.t0000644000175000017500000000240315176574475024353 0ustar kazuhokazuhouse strict; use Test::TCP; use Plack::Test; use HTTP::Request; use HTTP::Message::PSGI; use Test::More; use Digest::MD5; use Plack::Test::Server; use Test::TCP; use IO::Socket::INET; $ENV{PLACK_SERVER} = 'Starlet'; my $app = sub { my $env = shift; my $body; my $clen = $env->{CONTENT_LENGTH}; while ($clen > 0) { $env->{'psgi.input'}->read(my $buf, $clen) or last; $clen -= length $buf; $body .= $buf; } return [ 200, [ 'Content-Type', 'text/plain', 'Content-Length', $env->{CONTENT_LENGTH} ], [ $body ] ]; }; my $server = Test::TCP->new( code => sub { my $sock_or_port = shift; my $server = Plack::Loader->auto( port => $sock_or_port, host => '127.0.0.1' ); $server->run($app); exit; }, ); my $sock = IO::Socket::INET->new( PeerAddr => '127.0.0.1', PeerPort => $server->port, Proto => 'tcp', ); print {$sock} ( "POST / HTTP/1.1\015\012" . "content-length: 12\015\012" . "Transfer-Encoding: chunked\015\012" . "\015\012" . "5\015\012" . "hello\015\012" . "0\015\012" . "\015\012" . "world" ); my $res_str = do { local $/; <$sock> }; like $res_str, qr{^HTTP/1\.1 200 .*\015\012\015\012hello$}s; done_testing; Starlet-0.32/t/03post.t0000644000175000017500000000305415176574475014247 0ustar kazuhokazuhouse strict; use warnings; use LWP::UserAgent; use Plack::Runner; use Test::More; use Test::TCP; warn $$; test_tcp( server => sub { my $port = shift; my $runner = Plack::Runner->new; $runner->parse_options( qw(--server Starlet --max-workers 0 --port), $port, ); $runner->run( sub { my $env = shift; my $buf = ''; while (length($buf) != $env->{CONTENT_LENGTH}) { my $rlen = $env->{'psgi.input'}->read( $buf, $env->{CONTENT_LENGTH} - length($buf), length($buf), ); last unless $rlen > 0; } return [ 200, [ 'Content-Type' => 'text/plain' ], [ $buf ], ]; }, ); }, client => sub { my $port = shift; note 'send a broken request'; my $sock = IO::Socket::INET->new( PeerAddr => "127.0.0.1:$port", Proto => 'tcp', ) or die "failed to connect to server:$!"; $sock->print(<< "EOT"); POST / HTTP/1.0\r Content-Length: 6\r \r EOT undef $sock; note 'send next request'; my $ua = LWP::UserAgent->new; $ua->timeout(10); my $res = $ua->post("http://127.0.0.1:$port/", { a => 1 }); ok $res->is_success; is $res->code, 200; is $res->content, 'a=1'; }, ); done_testing; Starlet-0.32/t/02graceful.t0000644000175000017500000000130715176574475015050 0ustar kazuhokazuhouse strict; use warnings; use HTTP::Request::Common; use Plack::Test; use Test::More; $Plack::Test::Impl = 'Server'; $ENV{PLACK_SERVER} = 'Starlet'; warn $$; test_psgi app => sub { my $env = shift; warn $$; unless (my $pid = fork) { die "fork failed:$!" unless defined $pid; # child process sleep 1; kill 'TERM', getppid(); exit 0; } sleep 5; return [ 200, [ 'Content-Type' => 'text/plain' ], [ "hello world" ] ]; }, client => sub { my $cb = shift; warn $$; my $res = $cb->(GET "/"); is $res->content, "hello world"; }; done_testing; Starlet-0.32/t/05server-header.t0000644000175000017500000000210215176574475016011 0ustar kazuhokazuhouse strict; use warnings; use Test::More; use Test::TCP; use LWP::UserAgent; use Plack::Loader; test_tcp( client => sub { my $port = shift; sleep 1; my $ua = LWP::UserAgent->new; my $res = $ua->get("http://localhost:$port/"); ok( $res->is_success ); like( scalar $res->header('Server'), qr/Starlet/ ); unlike( scalar $res->header('Server'), qr/Hello/ ); $res = $ua->get("http://localhost:$port/?server=1"); ok( $res->is_success ); unlike( scalar $res->header('Server'), qr/Starlet/ ); like( scalar $res->header('Server'), qr/Hello/ ); }, server => sub { my $port = shift; my $loader = Plack::Loader->load( 'Starlet', port => $port, max_workers => 5, ); $loader->run(sub{ my $env = shift; my @headers = ('Content-Type','text/html'); push @headers, 'Server', 'Hello' if $env->{QUERY_STRING}; [200, \@headers, ['HELLO']]; }); exit; }, ); done_testing; Starlet-0.32/t/13spawn_interval.t0000644000175000017500000000372515176574475016324 0ustar kazuhokazuhouse strict; use warnings; use File::Basename (); use List::Util qw(first); use Test::TCP (); use File::Temp qw(tmpnam); use Test::More; BEGIN { use_ok('Server::Starter'); }; sub findprog { my $prog = shift; first { -x $_ } map { "$_/$prog" } ( File::Basename::dirname($^X), split /:/, $ENV{PATH}, ); } sub read_status_file { my $path = shift; open my $fh, $path or die "failed to open status file $path"; my $contents = do { local $/; <$fh> }; close $fh; my @pids = map { (split /:/, $_)[1] } split /\n/, $contents; return @pids; } my $start_server = findprog('start_server'); my $plackup = findprog('plackup'); sub doit { my $pkg = shift; my $port = Test::TCP::empty_port(); my $status_file_path = tmpnam(); my $server_pid = fork(); die "fork failed:$!" unless defined $server_pid; if ($server_pid == 0) { # child == server exec( $start_server, "--port=$port", "--status-file=$status_file_path", "--signal-on-hup=USR1", '--', $plackup, '--server', $pkg, '--max-workers=5', # just for finish test fast '--spawn-interval=1', 't/00base-hello.psgi', ); die "failed to launch server using start_server:$!"; } # wait until all workers spawn sleep 5; my @pids = read_status_file($status_file_path); my $sent_num_before_hup = kill 0, $pids[0]; kill 'HUP', $server_pid; sleep 4; my $sent_num_after_hup = kill 0, $pids[0]; is $sent_num_before_hup, 1, "process still alive before HUP signal"; is $sent_num_after_hup, 1, "old generation process still alive for a while after HUP signal"; sleep 1; kill 'TERM', $server_pid; while (wait == -1) {} } if ($start_server) { doit('Starlet'); } else { warn "could not find `start_server' next to $^X nor from \$PATH, skipping tests"; } done_testing; Starlet-0.32/t/06harakiri.t0000644000175000017500000000176215176574475015063 0ustar kazuhokazuhouse strict; use warnings; use HTTP::Request::Common; use Plack::Test; use Test::More; $Plack::Test::Impl = 'Server'; $ENV{PLACK_SERVER} = 'Starlet'; test_psgi app => sub { my $env = shift; return [ 200, [ 'Content-Type' => 'text/plain' ], [$$] ]; }, client => sub { my %seen_pid; my $cb = shift; for (1..23) { my $res = $cb->(GET "/"); $seen_pid{$res->content}++; } cmp_ok(keys(%seen_pid), '<=', 10, 'In non-harakiri mode, pid is reused') }; test_psgi app => sub { my $env = shift; $env->{'psgix.harakiri.commit'} = $env->{'psgix.harakiri'}; return [ 200, [ 'Content-Type' => 'text/plain' ], [$$] ]; }, client => sub { my %seen_pid; my $cb = shift; for (1..23) { my $res = $cb->(GET "/"); $seen_pid{$res->content}++; } is keys(%seen_pid), 23, 'In Harakiri mode, each pid only used once'; }; done_testing; Starlet-0.32/t/08chunked_req.t0000644000175000017500000000163415176574475015561 0ustar kazuhokazuhouse strict; use Test::TCP; use Plack::Test; use HTTP::Request; use Test::More; use Digest::MD5; $Plack::Test::Impl = "Server"; $ENV{PLACK_SERVER} = 'Starlet'; my $file = "t/assets/baybridge.jpg"; my $app = sub { my $env = shift; my $body; my $clen = $env->{CONTENT_LENGTH}; while ($clen > 0) { $env->{'psgi.input'}->read(my $buf, $clen) or last; $clen -= length $buf; $body .= $buf; } return [ 200, [ 'Content-Type', 'text/plain', 'X-Content-Length', $env->{CONTENT_LENGTH} ], [ $body ] ]; }; test_psgi $app, sub { my $cb = shift; open my $fh, "<:raw", $file; local $/ = \1024; my $req = HTTP::Request->new(POST => "http://localhost/"); $req->content(sub { scalar <$fh> }); my $res = $cb->($req); is $res->header('X-Content-Length'), 79838; is Digest::MD5::md5_hex($res->content), '983726ae0e4ce5081bef5fb2b7216950'; }; done_testing; Starlet-0.32/t/00base.t0000644000175000017500000000246515176574475014176 0ustar kazuhokazuhouse strict; use warnings; use File::Basename (); use List::Util qw(first); use LWP::UserAgent (); use Test::TCP (); use Test::More; BEGIN { use_ok('Server::Starter'); }; sub findprog { my $prog = shift; first { -x $_ } map { "$_/$prog" } ( File::Basename::dirname($^X), split /:/, $ENV{PATH}, ); } my $start_server = findprog('start_server'); my $plackup = findprog('plackup'); sub doit { my $pkg = shift; my $port = Test::TCP::empty_port(); my $server_pid = fork(); die "fork failed:$!" unless defined $server_pid; if ($server_pid == 0) { # child == server exec( $start_server, "--port=$port", '--', $plackup, '--server', $pkg, 't/00base-hello.psgi', ); die "failed to launch server using start_server:$!"; } sleep 1; my $ua = LWP::UserAgent->new; my $response = $ua->get("http://127.0.0.1:$port/"); ok($response->is_success, "request successfull"); is($response->content, 'hello', 'content is hello'); kill 'TERM', $server_pid; while (wait == -1) {} } if ($start_server) { doit('Starlet'); } else { warn "could not find `start_server' next to $^X nor from \$PATH, skipping tests"; } done_testing; Starlet-0.32/t/11multi-sockets.t0000644000175000017500000000411615176574475016064 0ustar kazuhokazuhouse strict; use warnings; use Test::More; use Plack::Loader; use File::Temp; use IO::Socket::INET; use Net::EmptyPort qw(empty_port); use Socket; my $PORT_NUM = 3; my $UDS_NUM = 4; my $WORKER_NUM = 2; my @tcp_socks = map { IO::Socket::INET->new( Listen => Socket::SOMAXCONN(), Proto => 'tcp', LocalPort => empty_port(), LocalAddr => '127.0.0.1', ReuseAddr => 1, ) or die "failed to listen:$!"; } (1..$PORT_NUM); my @uds_socks = map { my ($fh, $filename) = File::Temp::tempfile(UNLINK=>0); close($fh); unlink($filename); IO::Socket::UNIX->new( Listen => Socket::SOMAXCONN(), Local => $filename, ) or die "failed to listen to socket $filename:$!"; } (1..$UDS_NUM); $ENV{SERVER_STARTER_PORT} = join ';', ( map($_->sockport.'='.$_->fileno, @tcp_socks), map($_->hostpath.'='.$_->fileno, @uds_socks), ); my $pid = fork; if ( $pid == 0 ) { # server my $loader = Plack::Loader->load( 'Starlet', max_workers => $WORKER_NUM, ); $loader->run(sub{ my $env = shift; [200, ['Content-Type'=>'text/html'], ["HELLO $env->{SERVER_PORT}"]]; }); exit; } sleep 1; for my $listen_sock (@tcp_socks, @uds_socks) { my ($client, $port); if ($listen_sock->sockdomain == AF_INET) { $port = $listen_sock->sockport; $client = IO::Socket::INET->new( Proto => 'tcp', PeerAddr => '127.0.0.1', PeerPort => $listen_sock->sockport, timeout => 3, ) or die "failed to connect to socket $port:$!"; } elsif ($listen_sock->sockdomain == AF_UNIX) { $port = $listen_sock->hostpath; $client = IO::Socket::UNIX->new( Peer => $port, timeout => 3, ) or die "failed to connect to socket $port:$!"; } else { die "unknown socket"; } $client->syswrite("GET / HTTP/1.0\015\012\015\012"); $client->sysread(my $buf, 1024); like $buf, qr/Starlet/; like $buf, qr/HELLO $port/; } done_testing(); kill 'TERM', $pid; waitpid($pid,0); Starlet-0.32/t/assets/0000755000175000017500000000000015176575263014226 5ustar kazuhokazuhoStarlet-0.32/t/assets/baybridge.jpg0000644000175000017500000023373615176574475016702 0ustar kazuhokazuhoÿØÿàJFIFHHÿí^Photoshop 3.08BIMBZ San Francisco_ CaliforniadUSAe United Statesÿá ‚XMP://ns.adobe.com/xap/1.0/ San Francisco United States California ÿÛC   ÿÛCÿÀôÿÄ  ÿÄU!1A"Qaq�#2‘¡± BÁð3RbÑ$rá 4Cs‚²ñ%56St¢´Ò7u³Â&dvw’µÃÿÄÿÄG!1AQaq�‘¡ð"±ÁÑ2áñB#R3br‚Ò$’Âcs“¢²CS£ÓâÿÚ ?ñ #ÉçZÉÂ]cÆ8Ç?M0%-Q3Ç}|è‰L«8Æ=ôÀ$–X¼Ï�$è…@ãêtähvJR¢?ƒôçKiH%–/×�.ä‰ UNíÏßH¦J¬xÇM"�.!îÇ]?zP–X½ˆ`q¤%„„s‘�ÏLZ™°çßÏ#LÔè„€ “ôΉ‚×L‰JaÇÏ<é€0’])ðG�t‚P‰Z|1Ο[$‰Øã ýpt‹wNŠZQŒöóôÓ80R”žHàãDZRJŠLŸÝÏ:n©Ò‘ReÀþ:!Ñ4¬¤¤=Üã?ÓJLJR†4ƒ¸p?="Ô–F”�Ê“úie>IÊé¸ÀiƒL&BKN@'m1!:à'ŒdŸm?zHg„ž|i ¤…h� 1d’ ùqƈ™IÑó�¶‘�“’‘h€ÏpÏ:¡"Ñ‚8ÒÉ‚£'8þ£KDé23ù>É›ÄüôDrNm×$gøi‰›”)2˜Ïÿ=07I"ÉÜçÛßJBu�@3ÉÇùh@ä’H¦9ãΞ ,;83ýt“,@ñƒ§„’]œ{s¡"É/Œ¸'Ü{iÈN’+åŽ~úsÜ�X<`~ÚÓ²e‰B<Œ :KÁÏh#ž8Óå$$°ì@÷ãBRX”#œdiÈI|í ä�li“ÊĨƒ‘¤IcØà¤:„…ÖF #ü4sI&Td=>š¤Bįps¦0„‘^?Â>Ú}”›(ÉÈÇ¿å¦ rC)&AÎ :PŸdžÞÙÔZ‚SÊo–œç���ß]&�Âdá18È ÿ]8S'(év‚>šB|N1PƒÛ‘íôÓ—�’pŽÞ8àãüô‰Cä¶ä ¡ÆqãB÷Þé‘klÇøq�8:$]ÉMj=Øã�Nå ’5ÌÉŒ{éÍD›(qlíVàž1çßA²@óMòÐ`¶GòÑæè‚h¨£<œ`{è òd´Gå~ž4Ä¢M²Ò|s¤!:J^Ohç맘IôùŒ}4‚P„’Ü8Æ”§7„ìsõЃ eÝ ñdð§9ÓÇ$À!^? Œþž~Úº ïÍÀÁúéI4Y Ñ�äiÓÂE£Èàù{iw¦!Ìc>äãØs§€¼JHÇöß�6hL ÒE2=ôЙ`SÈäûi"cÚ9È})æ™`WŸlcV)�g¿?–š$ˆØm"wN’l£“ä�î=ô§É)I:dž3í¤‰IXÎxóÐ<ÁÒR‚n¦Èƒ p5"’ë±F襖0}Ž4‰;'Òè¤@| òÓºx„��¦‘u“j–XŽGOoá§<ÂP—H�â] 1ªmuD,G'Œž–ˆ‘ /ÓO¢h¨àíÇ×Dã°Nîh¨áÇ#ÏÐ�6aºb'Tlpþ�mЈ�гiÆ—CØ©²3ôü´…ŠPœc¥>ÀçÏ×N ’"S”4‡ àôúiî'hh�}3¦R!p;[ëœiš%,Û"Å�€&OåãDBby#él­ÏÉïôѰ(ÞûY 5™Ì¸ìÀü¼h\Ò e#- ªþé?ôÓĈF$ÍQkÀ<ùãL Ä'¢�Ô[~ƒþ4ÐŽ5E¸ ’¹×Nœ&yèˆã·ùiÃú% ¦jL|¸þº“HÛ-(ÈÊàç¢OºJnG'ÆœÈ(ö@ÉNxñ�ÏLtL‚’–oóΘ™Ñ< Þsí¤t€š$BáñÇ} òO!š/ ií¢Qc>€ÿ]!Í?D‹BᦞP†„“ÜžÞ=ôÉ$LGò?}0;’M¸ÇDœÂ£ƒïõÒ”0’hüqΘ�™"cä`3ã:y²rF3à‘çï¤ÞV1‘Ÿç¦¨L°hÀÏ��$S9#ØÓw§Ê±(Æ1ý4Ò†e ûŸ#N9" Uú ²EcÛç'òÓ›è”,=3í�>ÚÒ jEAÎFGŸÏF.œø§�¯ßMÜ›¹%ØqŸm-“…ƒ({ )�d , ç�} 7L°dÏ<ñ¢iKhX2{�úhsM’d8öÒžHâÉ"ª Ÿá�O$Òž¤Ds�#RŠ 01Àòt¯ªH•…€sãòÒJ脈�c¦%' ‘ ¾2tAÀ‰O u„ûãçH€Ÿ*!b9R†Pî‰Xy$å½¾šM;„¢tK¤^4ì¢Q:£#€;GõÓ7TA¨ØéÉÁ}4íx:¦Q©OŸÏH%?’Žs¥ŸiHç ($gó:`mdÀòN�RgÓ“dÄõd s¦mH@Ÿimä�1€~ÃÆ”¤TŽ’Ö[·äôÓ‹”*OEf<š&ºÈd)E-‹ f<�é¢f²EÂ$)>Þ@r~šwuQ:„éÚã÷3ãÈјº…ÏN´»h”'ÓÁçý JƈCRµÀMo·ˆ‘ÏgçÆ„¶e¬#ªi­³cÿV1íÆ„·r¦c�”N²Ø3€5'ee¥F*íݧ¼é§dj;UCŽâF9öÓá1TPòp¸ûhÅ“Ç$Ç=Éã�ÞiÂeš“ÆOÓI¢,J|©ªjqàŒé%8±MÒ@CŽ4�ƒ)ÜÔß$þt³ºp9!N¿’ÚwtLà�h~Äc߯4Ù’#t‹Cÿ?NtòvD“1r0¤¶�)‚ÀÀqçI4“F9Â�¶“ˆÕ(XzCØqíÆ„X&ŽI3ÇÕtà§X˜�<Ζdé3’G?] y&+OƘ�Ò„™ŒžÞ¦”óK,•‰B=»qÈÒî—zKÓϰΔ„Ð„}�äže3Ž#ï¤O$Ð’(OÓ‹hœ‹¬9ç{ñ¡BBI£çœm80,�%ÙÉîŸÏ@â7Bаò8>}ôùµ”a‘6@ÆšNÛ'„JÅŽB÷Ë:Y¶K,˜„ˆg¸/m"‘Ñ,�žx#ÛÛLŸ-î‰X¼xóôÒ&d#Á°‘à~šg8§�‘) áãßH[T´’ŒHWéãNÒ bÔdpp¼`�6då€jŽŠŸÇýt€%—dá1ÀÈÏßë§cÆÉ€Ø§Hi öûi�Cd‹ Féâ <óÚqçòѦswOTÔ$‘Æ8Ð „¡p… ¥·ð¹lçt3²“QÛ3ÛòàþZ0Ê!L-öœöü ËO(\TæÝcî ˆÏ‘ÇÓFÝ!DíTâß`-ŒÇŸÚ–âʳž¦t{eˆ§¿ÓH… $h¤�m,�û3ü5$…ß ê  �›Óå8ãR6�¥U©Xƒ)Š}¦Xˆ™p¶…¢•µ9¨=Ïn$Éü´®0•¸XXòäþ^ú…Óª¸Ç(E}¡�cÚAз’�¢5–Æ_ðûñ¤O$@(ÍUPÄŽ~Úi3 n£Õ4XîÊ®šN…B`šŒäŽÑúé‹¶ É3OFsžÁÝùèÜå$&Ç£<ñŒèC®œuM’R¸À�ùi®šRÓàóÇôÓ”@I‚‚’ž}¹÷Ój“€ Ú>Uˆ`ý“ÁB¼åóÇ�dáˆV€œq¡Î£ˆH´ãÇñÓ)ØÕ"bç´i4ÚP†ø¤L ‘£�)ˆf„ò;Aö€·šE¡ñ€3íÆ�2`Û¤Z,sÎ3¦kå"Û¤L#æ ¤è{’MAÈ#Nté6‹>söÓ“t€I4~x9Ї](%%éƒÎ24¤9, �R~—ó¢;„j±hüñΆ†D!Ê’1£ôÑlœ˜²OÓÀá}ô.tÙ#É&cÈ Œ ý|iÂ5X˜óà϶�;”CšM£ù¼xçI¶LÀÇ�8Àü´Ù’JÀÇõý´ù’ 3œóÒˆM’t÷:py')6N9hfFˆR!~ªOÓNà™ÝUš±=ÿM@ÒvS5·„P‡÷sçLçÅÑA¡ ãåϱїM‘ Q }¿,èZø”ͺ%!ä�á¤×sNÖÂ! Î~žÿm;Œ„@uE-1?UÓIÙ"ÙF%1àã?C§!+ê�Ž™ø!A9ñ¡í#t¢Œt„rA |èKÆÉÀNqQd�ÛÿŽŸ´¿TƒL§:z#�Ÿ>øÐŠ¢R!žtaÉœþ×jÏkzxý4m}¬ %Y›2ü£ÓöãF*ÙZ�¾´v/ðÔ mº¦ç쬻VÖîìÄJÇòÔ�lª.y¿U? Ù…ÐbaçR5¥Dê�HÆÉqLÇÑ>>š°Æ@U»VÌ ¹íCGöl?M Ûb§k䪢õ·YK“ÏiLÏ8#ŸÓv°n–é€àü™ûiZé9¥ ðä`s§Ít£š öûè‹Ä¤á)3 $çΘT.vˆŒä1§k�)òÆ…$b<}yýt5t%‘ #¸ËEžéò�DÅ�ÆsÇ8Ó ]a阎>Úpy'ky$Ú r@ü¼igƒ Ž�ɈùçNt�É`càþö–xM’F09ûéf3É9hæ±1ÿ û6dÍéªDÄG#?å§Êw4”Ÿ¥�$ ió&bSÈ9çL℈RLƒÁ�9€lŒ6é&�Ç禑¢Û$L~ñÓî˜ÈÙ$É“þÝt%[iMöçΪæ�U¸;¢’œóì8÷Òq›"!´ÃŒþšYÄBrÛ¢’�1Ï�w$Ä"’Ÿ'�“ý4��g4ZÓ{ë§:].ŽJQî¸>9ÒÌP–î�Š˜’>^~þÚäe±dá1Èã>ãK6Áa”ëqçÎt26J›éÖ2t‰¤;'hh†2Usçé¡Ì�¦S¼yÿqþºpîh2O”ÔD‘Æxþ:bã6C“e §·ƒò°:"ø6M–J”ÑÛ +ÁÇ�'N".ÔæÙh¡íÉûê@UwYYv‹P%>N1£a¡*ײY�)•Ç?MX¦ ª7W^ÜÛË!ŒzË:°Ð³++ÿl줩ôñ'頻`•�R§5zØú`Ò¢þÃ’¶¬ \Ö}JêaSÒÇŠ‘»©OŒxÕ†¶Ê£ª’U;¹¶¤%&�í�AY‚Wpõ`J×­Ç´FLBçTªÄ-JUIº¡7 ƒÓg9üµYÆVµ#*š¼Úʨ\Ö‹IUuÖÚA~ìðxãQw©B¯ëèð[å9þšlŒ (e]?ï|¸–…ÎÜ©Zn¢�ð þ\h �ÔÀ&9é\åˆãßÚb@ºA4MDß0€4‰ðI­MrQc`lŸ½6ËGùþ¾t‰ òò@ËIïƒöÒq'Te²ai ?(?M0u¡#¤ g†(U Ì‘™Ó@|ÈÄ•G’x8“�pÑ%XI²*íb¨´WKo«j©T�ËSÕÅSW�]JË27 àžÖîS†ViWkă*Þ?†ÔÃÔìêDÛB¸�A#N©–JB1ÁÇùhóÝR!ôÞ àçY“eB=>Oq8?MŸ)e(f§ó�ÓL ` !šœy#úi³ÂE·º¡ã?èèÁ;”²I44á÷º”;Óþèúý4Ítj”n‘xsþG¾œ¾öÑ6©’>ƒCš4LÃD›AÇ€~‡';ÉHÁ�8ϸÒq$D„“AìßN×sL’0ñàcÏç§0Sd¤Ì>ݤþz~ÒÝ’h8Áþä‚I ýï—ûxÑò²Fçû�!ªA£2E£ÁÇú,Âe„›Dsœ>‡CžP–€f.8ãê~úv¹0<Òl‡è~^4¤ÌÎt�¦Np1¢ä)‰�Ç${q¥$ZTfUϺ8ÿ®ªfZ¨¤ƒøçÆ–c²l¼ÑkMŒú}´�TàQQÀO:_¨ÉÒÌ!>K§H©>Ç>çtݧ$å� §xiT@ç>‡9&É�¡¥^>SôÿGMÚsH�ÓÄT cå$ý´9ÀK/$ñOKž;{´šé6L[ÍHi(ñŒƒ�9« ƒÊMED´ãÒk ]F[¤)�¾Þ¹FƒãÇþ0ùUœö×nO�ç:•ޏUê7ª³¬¶²ÝŸ&}µ(t\*ÄB¹ll”Ì~ÿMY¦ûIU*‚n¶híâíPþ£WYhXõÝ{-½Ø;J)Zñ€3ôÕú@,ŠÏºèßEzQ¿j©-¶Ê35K€1�'ÖËe/j`-’êÁ¦äÙ[uîÕ4tõ`ï “ÿ<~zŽŽ9®0 ŸÁžÁ™s+¨›:*ÃÈÈñ«„ÈTªÓ í¶;=`°·xÕ: Ä-l;åj¾èÛ’wÉûÜçΩTiÙmPx…Eßv̤· <ê±a‰Z ¨ UEÛlà¿yþš�À� z®.[~�;‰(<ê á2¡Ê]g§RI馘¿%(F¶ßN¤Œr?ž…ϼ)›™F*©cÉà{�{Ý[& é—Ÿ�i‹¹£‚še¦ú è?×�>hN{¦ÉiFx\}þšôí��@c箣ídÝ;YOÕïm§¤¨¿STí�ÆÙÅîÌ+hª÷ì1†/”F ®ÉQÛ+ˆþUï Ú¬.ª&p ¶åº×iÔ^:$Nϰl»>àk]{ ›TÞk¤ü7|õ5‰#'ljîëd0¢¨hç’˜åqw—aªe2FÞ>öVøs2×içÎÜþš©U_R¶¦à©Ùµ›¦[8Ø-5&’®žÍ”gtC8ŠžY¥å´J]âôä�e¨v‘¤’9†Ò,ÅIĂٸƒ´‚®ó2µ±tÈ ìâvšìn;È·DÃW±¶Ní�ª¶EþšÝxš�îK·«f8µGNµ&ª)îõ_…Šyý:XªbH"s8¬ @É'LqÎÚ}ûîY_ÓS>ö·‡ì¡·¥³iQW^î6™êv„WîØw 2<–k”¤NѽyQDR¥%L‘J„¬‰Œ¤„nÙébZïÒ¡u8ýVU³Ð6�r‡ O ô9ñã�Y&.¢ æ›ÞŒ‚F0>šl֔哠B½)Ò.�S9�…zcœ€3ô od9-(v¥ð{xΈžiÃd¤œŸi³„²òCµ3gÀüôÁ÷ºQ-ž8ÒsÄ!ÊtH½9ñΞSä $Z䌟¾˜ÄJM¡<Œ|Ãí¢6O$‹ÂÀ¨ó§Ô j’01ù‡Ÿ}&™Fi™„‹EŽÞœ P�h8#�2`f~ÙÒ ¡ ÑpÀŸã£&éeIO°Ç}ô%ÓªbË‹Ž@ÇÓE¨„ú¤#Éǰýt¤“(E£ü½Ïv�Dák¤ÏÌt.w$³«Ù)1�”j¦a+G ;#R�<Añùh…Nj@ÔZÒŽ˜¿šLJ*:3€{J�qÈÓuG”£#¥äqÏÓMÚY"ÄrQ¶3ÛçíöÓg€‹*pJSŒ`Ÿ×Cš{’"BpŽ—ó¡%,©Æ:O˜qÚ=´!Äj–Té1ç›4¢ :'ŠzLã·ùhƒ¹%–éî 1ŸÆ4!ÞiÍH)mÜ‚Ciƒ÷C•I¨í¿LçóÒk„ÂD)] ´{çFÇ좩¥”ÚÝmÈ0G¶�}Õw4ê¬;E¾?“’G·ßVíÊ«Q¤è­‹0ôò¹ÏòÕ€æªO^r–—1ç³Ií ¥f»e²[:exǤWšû�^›µ[�Óô§@{ÇZ4ªÙbâ)ÕŸ…Ž¢Úv⡸WÆ^�ÔÅ/n;”0##î3¨ñtKÁÕ¾\S|•¿½XëOêöæÝmºGtª­§0ªzeDYÁËwÈÇ�ï¬Ê7彈ư°†ÞW :´cžª²DìpI8Öë] \�Jrå¡{óƒ?jF8ÈÕ:õUì=JÔ�Ö$&\ÇØj‹ê[´)¯»†9O'íªO¬M–ƒ9x§™Œ™Ï?SªÎ©*ËiªÎçHýÌs� ¨IV%¸RÜyƠΧ YAžì©îÇK4n§”b¦ƒ |gÛC�HÖndžßžï”ì4Ý¢|—MæÜ[Tçí¦så§ÉöŲ&¼ÒÓߪªéìÛ%nÔVŠûÓ)¨†ØõìዺyBÇD¥bF$BT|ìŠÌê�$þ}€&¾÷RU¶Ôlûm¦ói²Ac¼- Þ²ÎàE{~ê·L憷PUR°2(ünL­Þ¬ëèKGÌO¨F¶úŸ}þ)2˜25O~Â�ÜnûzÃ5m&Ç£ª�Uºª†ór„Et –²âBfŠ5i��s $+;…„Šch´i;™fæçß5Eõ²ë¸/»r¶ëqº]¯7ô³ÔÕOPòÔÕÏ*J^W•‰w•ÚBÅØ–,rI:�[-vŸ¿¿Uo‡ÐšÍdjcí÷N2Gg’JE´R=”tðÛ+"EQNòĤ£ÆÈMãYçN2ð�4±¦™9šApæ$‰ÆHèce©ˆsj`ÃÃ`´†žD‰ƒß=GT™�ÆA' ýq­Ìë%áJ,›Ówmë� ÚÓ~®ŠåK¡£šnÚ– €É꧇vÈLˆÑhܳ¡Vf&Ñk¯¿5#\b6%Nh·îÁ¿ËJ�KéÀ®Ui+«.z´Ñ]ï÷d2=u]H©� ”zîñÓAdÒ cwBǙ͸>|û­>C»D�'LzºZÉÕêæÕ¶]ª)ÍuÉ7ùrÙŽžÑ¸@{É«ýò…Q–Jhд²FË,e°-…%ƒ*ÈÊâÄ{û£›Á´{îUt¶™Gˆ®d¼¹ä{r<�~cRê7H2S{ÛÜ€‚: ûjŸ&è6£?ðž?M3j_TÙ¯GíÚq�y›'ȆjSÇË€>ÚläÎfÈf¥<€_"ûjŸ&å ÔŒHÂäø9Ó{”ÎjHÒžx?ÃOÚ‹Gð¤xS�}8| (r$ !#…çH>ÖHÒÔ$Z›œñù�?jvI¦ó�>º~Ц ¤š•°AyãCÚ›!ìÐÍNß1 Æ4aèLl“xw8Ô† §îI˜¸:|Éd)§ð1�å¦BiÚɧÁÇnõÓ‡Á„%‰Oÿtiä(ô[)>ÞØñªAÄjVÎYÑ)àà¨O˜êŸ/4dt¹íöçŽBH¸éã‚xþ:äðŽZ6ò‘÷ÒuRhGÇGöçÁÈÒ$nœ5'  â.Så¼#ã¥Î0¿øèsÚJ ÝÓ”Tƒ9 Ç饙8nÉÎ^W‚4³�Qnž©¨òGho¶„¾Ée�Tê˳÷%êKRÙ6åòôÕ·:{-)¦¦fŽZù’G†ŸÔýÁ+¬2L÷0S…8: g(þTosZ~b¦u};ÝVË…òß6ÖÝñKn5zÔÚ&§–ƒÒuŽoÄÄ{šJW9r1PÅKÕ:xƼ–�[¯NþJÕzLi¦Aˆ:j†¥¡`‘ŸyÔ�°&UsLToÃ|ØûêAVL„l©•¾šO”pF‰¯ '´B°-4ÌXqýu'ixPUfáZv8ÉÁÇÚ²×èJ¥Q‚ß¶àL Ç3�Za …F­ŒÚqÃŒ’GÓ½F¬X¬Úô¦Ëg6�|Qz=¬<�«ÔêrXõðö‚¶‡jnSL#ì˜ùøÑm\öYÏ£ qtÞ“µ8�ñLGo‚Úg™¡ÇU¯›ÆöÕK+z…›ëŸ:®úÛ+Tè’V¥o)ZF›9÷÷Õ*�€µpôcPµƒtÇ&d<ë9õ$­Zt• ~�É“(Ú®ê� 㪋­;|ã´ÿ}V}[+Œ¤yq¤·œh3ÞB�”Ô&¶‘rÄ‚9ãC�X섨•eå‡nGå�}Ô�j�ÏnfÏìØ�}1z‘­Ârµtþ{’Û+ï7;NÎÚUOw3!¥ ¨ôDÄM -N;RÉu$àFk­¦Þì„_K”èûVÝiÚòÔ\6¬4ÏqÚÐË7ûVæ�»ê«1m†8]©Dîq*aªÛ´ªÄ˫ӡõ÷×½i˦m>çöM»—~Añ©Ý´ÕïÝåÖ¦Xw>䤊g¹Ðˆšž9íSzð)Tˆ?Ï$ eÑG,fA�¯Œ©eÊtúwB¢kÞ²ª8EEEUHŠ™ ‹Õ‘ŸÓŒB.O ’N$ã“© òˆIÙóÕ1ÏFÅ›‚pþƒK¶‹÷£u/²¬÷�Pºôù(äŽ Ãws ŽjH"=¬qÎÁãž5WVh86Vp�nر“~]|òé´ã [5ößqþõ¡¯¡‰ªšG‹ñ\¤ZŸ^4Çi‘ó:±Pe㸫k�áµ]KpïÌDÁi‚Ø'ý?¤�£ªèø�1SýC ‡3$ïýS¼¦v¡%™BöžîuÕ ³G½W-Ù\ûÝÔMòü§ýæúýtæ°‰Þ§D›uBšcò#'Ÿá¦mQ%¥aï’ø”ó/¢G¨¬sãBkDÊF�‚”ì}Û¼úu{‡qtÿtî}‡¸¤†jW¸XîÛêž ?~34 ŽQ½×8'Ÿ 3êfçïÅ8Ãè5 Õ²õÆöô½;²ï]ƒÒ¾¥í ªü%žébJ8ë%•X«êí¦–¶¶U.§ºyÜ0�ƒ(Æ“êå°6nƒoϪŒàÁ;÷rÙ)cŸá¿rŰ­›ÃkuW§U“_j¦Ý‚Å[Mx‰mîXÅOl²N)Dm©îš¶BÁ<€q§mw‹Lë<üž·Aý1?§¤¬›}%WIºiw±|í.¶me¼Õîsf¡Û·û}U¶² k»¹×\3m…r,‘$îêDŽb䏯� �µ·2E‡¾ôçñqpº_��з߅þ¤Zì½[ݶÚ}¥½z²®”Ö‹îçÛÛ‚Šáiõê¤G0‘d¬†B­Û41º¤±QΦn)²n-ïxQ£\ �W¼:O¿6ö·ko�“¼vN概ª‹mæÕQCWO±¬‘K$"ȑɑº»®®¬ “µÛßš@ƒuY$i2“H§µÕb„{9‘ÁÓšâ`£c$Y-’xðZUö8Ò5Â3F5BÉdŸ´7¤Ê¾ÇÆtB¨˜K°´¤RÒò¸URÎON›·I)Û†'dTûVá»RÌ!òÏúý5Xc™9fê˰ŒÑdÆöÒ{—äï22±#óÏ?mLq ý3u[úGDÅ�†�™»Bý½µ;ªˆ•h’a:�¥sjoŵ1Ž2�”þ¾þÚ¢8¥âÀé#mÇz¾xM\¡å¿/=¼›§»·wËw‡jí}ʦ·ÑOs¯[u µF†Š Õ3ÔúpFKÊØDwu&#ˆÒ¢ÜÏpAC‡Ô¨Ki¶aD§ 07k=õm•¦ê�J%¶IÃmy�cTbÞØÉÀý4nªrŠ�"ã SííÑ® ôÞåGgêÌÝ;óSEMr§£»Û壞zIãAP©*«dGWIíu9RF³hñŠ5 Èf žþ—W«pŠ´ìñ>ÿÇDžøèæ÷éå«a^·•š;M¿tYSqX˜VSÎÕÖ÷šXVr‘Hí^žUì˜$˜\öö²±Ÿ ÄÙQæ“uoßóçÌ®R‹ß¡ý�Ü*¥è°ÄO嫆 XŽ[!¹€Ïh:¦ç�–¡j6;{vò¤}t�A2ä(Ä·8$:�´ òlŽJ�J~šnÔ%Ù˜º1h(þšÑ¤Q©@A&~úF°GÙîQ‰D~à{}ô"ºsK’>2@ñÿ]1©¹DSœT$ãå‹´äSäÙ;ÓÐsÈÂùÉ8öþZÔæˆSVU¯hÓ[­ÔÛƒtÉ%¶Ó$r½$*ªnˆqÛeôáiÄ’»#§õ`J‚½ºž@ªy{÷ÉDLœ­÷ïö0™ºƒ¸.Vz­½–ÙlÐÃw§Ž "¨¤OK7i˜·jÉ3Eøej‰É:ö¼Œ{pjãÜMÌ©aióóëÉ�kÚæÜ‰ú¾Ê}²z�v£Üvû>õž«röYV¯ «jk•¾�ªHj8&%‹Ó*KUŠJ‘$½A’@ÃåÓÄ8;-@dH�âבêÖdh¥­…Ò0 ð�Áml¶"ß´öÿQ^„Ù*i$½Íé,ÒÛh�j=gü7¨õ6uî‘Ç«SXÆky—ÔZO’Šš0_WL<‚Ëø_Ëñäªå=¾›Ú|µó*û:éCnŠðô¢k+(?�†Eš=°’¯"äFA©�nßÚ7`ËmΈ²‡X#¨mÌŒFïÁÓ²­Ôf�ÔîÙI‚>Qçë©™R ‚£U“i¦ Ùû£S² …N¥"tVµ�‚�ÓV[]T©‡$+žÁ\cí÷äxÕ¦U²£R�W]‚ô°üß–®·£S®;&èôÝ;^epuYupÆð�îÀwvz§Æ|éêW¼(Ù„qU½ës æLçUÝ_ezŽ ¦7 Õ%9Õ*•¤J¿JŒHß$ïïÁçßê£êÍ•út?x§ïïÎªš¶²ºÊD�ku·“Üݧí盛ºÚ«Êûc;7j“�Fqu3hÊ� «s¹5b[­Õ× ¥ž¾e§…¤h©¡ŒÉ,Ä($Fˆ¬ÌÞ ž4"¹6FiÅÓÅ·¤³\.tvç¬KÕk]­öùh¬%+å–*ŠvœÉ X?� C,ñ¸�²�3Åø�#Þ½tðçÜ–BlÞí¯§Õ2ÕZvÅÛzjãµ­·:�¸!¨Šv¼Ïp¨{–[¿Ö(–š…�wDÎ$ pÕrúu?­.þ÷¸·M:•oú'L»™÷ßœz&‹ÆðºWî[–ãÛ”WÝÜn5íÚ­®—Úˆj ˜*jä)BÆdùÄ ýÒÈÝÀzkwã¼Äýís¿¢°Î˜øtça·ª¥.¶ŠØÌ¦¬Ìî"@ÝìI 0sžÓÛJŽ0•¼þÊÛðŽh%Âñ>©‘6ÝU}CAOHâFBñþ¾º†®=Œfg¥nÎ~P/)ºñ³nV”ŒWQOLÏ‘{ÐŽà‚F|Œ‚?M5+N¡9 Ü#­Ã_N3ˆ×dÝIµên_‡¦Œ¼ìcí 8þ::¸Üƒ3º§§€/9¼m\> º÷MÔo‡¹ß£ÛÞåfùŽÏKLöÉ—ûÆäh–¶;r©šy`^åŒâŒÎFy\gÄ´q8J¬ ââAý76ÔˆÜ1®‹¦Âpáq,«Zm̘פÚtS¾ü&ß: ´*n×ý»sÛÕ«�ö†Ùâže¶UÑ ©—Ô‹å)8€cËE# 6¹†¾,­Œâ´©Ö³…24#‘ƒ�°ÿ‹s�ü=G Ãjº„š›yÈŸøËÊÒ ÕiÐφ^§üFu�¥ý%Ú— á½*¥ŸðöúP¾´â(ä–NÐÄ)“à}p¡q.Ì=0@.$@I6›sϹq8~�îÌàÐÛ’Lx¹ï�â™®½¿Zv´»º¶¿mSÒÅz¤¶Š.1%ƤÔDÒ¬ÐÑçÔ–™De^eˆÏ“™UðÿÒª@mÁùøûR®Öà¥üÿ‘'eHPØÍ\¶¨#Ç|ò_¿îùÚÞ}ÕïšçY‡½–Îî/„ÝóFª·FãÙô¶Ù·i·L* ä¸CAo–¶I JÁÜÑÔBóR›ýâà e†¹¬7Ä‚³ªµ�$°�ÁçLipn× ªÿÃPÖ˶¼‚7`±0êE�;Eî�“i±ï ¶þÞÜvýçdв® Å-<°Cv§I;R¦(¥HÒEíp’ê�×§Ž{¨š�z0ykä±*`ØÚÁ�3o¨�¤-�ø{øeÚÝUéŸP÷Å÷©›gg^¬öÆ®²Y+b�Ôn™¢¥Š™†Z1F7âø†bƃ3I®æ-‰&` Z¼3…Ð8cZ©ˆ•¬L‘3"ÒdªÞËÓþ˜Rì«�Ëv_wUôªzi6•-2ÑV?ã U)_3º¼b„´~š¹w`µOv¬â8…rø§ú`ë×X-Þ•>A”³¾ß1Àœìf-¤è¨škr*iÉh•î¾€noìÁÿ=m‡»7‡Ýb·ÞÇ6Ù¿öÊÜ¿ˆŽ�t+`t·lî>�ï+®éßpÉUnÞÜ-ñÓÿt]£«­„ÁE0%¦ˆ­0%Ã}8ç’à¼c‰¬Wô8Km´÷ÜD€A0E¤ôügƒáèSsi‹Ó0Lïs"H�;¨¶ìê,»"ÏÕ=­°÷?Sl{¾K}u“y^Žê¨š›yÙ%®·ÇKE5#(+O) ’<©7©Ë¤mð·W¨X›8^ ÷å~§�–N?†k*4,‰ÜÛøƒËÏ`:wÕÓxêCÓzYúa½­[sbWÑÙ¨7Ó·ÕP-½m÷J •$1Š·&hæ¨2J¯é�ÿ³@51®¬Êå›`n.@ñü¬^€¡Z±eiÊdœ¶?+I±ÚþŠÞë[|2n‹×E6ÏAú ¸­6û~ H¤¬ºVUî:Õ’–ÏÔrÍ|Â$¬šHýtœ`]²ç¸elSQ�2Yó^äØËde-0Cf"g~Ÿ‰`°î4ÞÓä³�D: Þ&LOzŽu[}ü%ub_h6¿ÂÇQº-]¶¤›mÂÁº »Ç#Õ]ëg]MU×2SÓÉGÑ‘R&-!V w j¶·hj$H "Yù\ÆoÐdW£4²AŠD@uoH’ÒO|_U_mnœ|,]7ÎÈ·¢uãmØ"ÚKzÝRUìz;�BÖÇmš¶g·Çr#R`Sb9ˆ•@Ÿæ�„ÌøœuRß�Ÿ.„‡Aœ¶ DEŒ�ªÑÁŠNœÒë H`‰ ˜ j ‰Ð­²ø­›á—®;¤[ßeu[¢"ÝBËÜKM7%¶‚æháÍ_5TPUŸÅ<­nB°Ìž¡!�pŸ³…53Ñ%òV½‘ú�s‡ÌH$ˆ‰½�…ØñªÍ¬Ö8¦ìÙI¹D¶ö‰ùw‹E¤Ô»³áÛ§»gwtbÉý£ÿ sôëeÜn·Ë]%úÅ~³VUÝ%ô²¬ÌmŒ"/%,TÅÍLð!ƒÕPÙõ¹K�ÿæoéê[gÒ ŒÁ­hyt¸Øf€ É~{€ªÚF‰-–º›Æh’b-3`geª•Ÿ PQÙvmÞ×ñ5ð;º/·šš„ŽÉIÕÛE=Më5ÉXðBRwõÕQ¤OAŒŠ�Ó»{ÿRÈK©UÙ<‘`o–F‡b}c8U@û9¼ç0ÜÍæÜ>¤Òn ýÒ=¿ðÙwøÀþÏ ¿OºZ75v׺ÓuGoQŹ¿‚•i©\¼urOS7âŒF¹cT C¼C·»Ú#qYjD@šO�ÔIäÌv2áÜ@…¯�âU‡k’®2Ø|»™Ë­‰’µ�¥·™íK†é£øÄøWéõÚóIu²Þ¬Ô�SˆWÁn_D¼U߀¤´õCÔU¥V‘œÓâH×¾>íjÜkU�…J†E…7OŽ`hfzž™Øjuç‘UŒ3˜_CarHîè.¹õ·7•>ü¾¥¦Áb½Í!�ê'žeXã¥�FZI,ÃŒX’ �uØŒE<;3¿Iޤì½.¹¬0v&¦Zbm'�ê¶®ÇÑÛd½0ؽO¦ê§M+ï7ýÇSc¢Ùô’UÕ_i"�c2×WÒÅ ~ ùâXã—άÒÄ®‘ÈV®'H6à'ºÃI7ˆV0Øz¥ßå¶b/}y kewu¢»doî«ÔÙ÷ׯ u6Á·ö´fÓ¾¨vÍêÿ窡ŽJz*zHð'JiÝb…$f"(»X#€±œŠiP{›�êwˆ�ÔAç¯ÑjÔezÌ�K ‘Äë0Þ’w&ú¨}Û¢¿6��³ïïŠk�·|^åycµÅÒ]ÁøZ:H^Jz�ÅTÈ‘ÊkVXâaPˆ@Ze�tÌã•@§F\H‘Ú3åýFuÞHˆ2a#ÂØê‘R´0 ÇüÝ#MD˜¸åtá{ø[éVãþê«èWX:‡Ôk 4¢–ëvªéîµW4‘Ä�o¶¹ˆ¢hÌ‚¡– a"®G‰ø¹ôžYÙLñ))|Ç)óU£ðá{s=ÄOÿ¡óùbyÁ#‘UêQ¸í w.21á¿-j—ƒq¢¬Úd#’”©¡9ûyÒ.0ÝΉÁióǤ‡ëòÿ£¦/\©;#(˜éXàvvãMÚY&ÓF%#œeCË@÷„B™”jÑ1ÿ>úlñªA›#b·ŒÙœùñ ‰´£ì¯té°qˆ�ŒiƒÓŠJe·6]ÓqW už‚Zʰž¤œ¬iOÆešW*� ÷<²2Æ‹–fU†¥™ß¦ÿný½ø¦t7_}ÊÖ²íZ)©«±ËhÜ·z>Ã=Ö¨¬ö9²¥H2®jª¥§nÖŒ¢´Sfž¶�„ÀÍv³ô›�öÄ_Ë�ˆºŒQ/±°å¹õ´òÞuɆ¾éMBVX¤¹W_É�žùY”¨‹±�¦”qäþcT§À™b1:Æé …gbÌÈ7翇/¯#NÊôÛ÷ûòTÆå·ÔÁ[ÓøíÔ�=O÷ìm E{cfZj†€ËÆHž~ºƒ‰`¤ìÚ=\<•œ-º«C ›Ç–Ý~ªSdÛ”t{¾™)«ÍÂV²¿ã“¶ATeF=ÊhR… xNÅ vŽê¬Ä=¯-~£N£n¶¸¾¦û•f­úb£4åÈÞch6>Šè¦´�;OlÑäÎAî�å«-ÄɾБÃY_{¨»Æ–¯ñõÓµöéÚÁ.2J•èÅe ƺ&IäíyÃâV�~Æ$±¯i±Oˆºe×=uó×ÍU©�í·¾^üÕ“EL÷ ×ÖÔ[¯nváŠ(¢ŠB¥K$Ji¢ô›*–è³øhG|“6]Xº/»ŒrØwªÇ Q¶}õü«t"²¡*«6uúüm±I"úÐMlʯVv‡u!’ß< ý˜î-¢“þ[ƒ½ŸçÒY9Ûßé¶íÛ³½5ûn_,’#27â©^5 ­ÚøŽÓ†r yzµÍ;¼Bf჌5>QZ*©¦0ɉ2œ22à©û� éRÆ5À8 Ø2ÓUµEµw–‹rOf¹-‚iÚ–*ãz̪£Yí.¡•Šç 0$`�OO‰4»(7÷**¼1Ṏžÿ àéÞÅÞ;îJê}¡·n{†zJsWT´ÑdRÀ)’V8XÓ¹Õ{˜�–<�\w {÷ÔÛEIœ)õ&=ûä9%-÷É‚±cŽ|þZÕÃâ§ô•�‰Âå$͸w}¢Û_-Â÷hµÕéª2¬ÕóRE=dôÖØDtjŒFbŒcÓˆ� "§?Ãø»ž3¼ÃLÁ2çe"Àh¹äº Ü 5Áf‰d“;ɉ°ë¨{ qì«îýÙÉÕþ¢mŠÍŠ»¯fÃ|´¥öŠ’)m“ÓÈóÉéFézTÔþ™r�ÈdùΦ6¹|ÌÇÏ'”�¾ñ ™F�§ú@˜ik‚~»]uÿ¨ÝÝÛ®ÿ_ÓzΓì;5¢X¨ìÔŠš¡Ï¥\cˆ3ÚIêžÙ€B®êмk7…¾» Tî©€Zu1±±6°+_ˆS¦æˆ�Ó:\‡ ÜÀ¹Žio†~®|>lޱìÝ÷»7‡F7®Ä³îŸÅÝéî—$’×SkŠŸ/4òàÄÔæQé’N•—È#UøÈ®ê9CNYˆ7!ߦ6˜¼rÕXáͦÀ]œ7æg@Z>`n-´ï²?¯{›duBõU¹åêGCl¬Ö¸¬”4vZK“À•1È 4h´6·W•iÌd±î‘ò¬ìÅ‹k�V¯‡`h£QÐA6l�—S/ÚNº’L•wо…w˜ ix.™±ëÒÂ`Y4ôovìnŒõ3aõ’—tÓîkNꦿRöìmÏWK=12æÒæxÈTcó…ã»$jål]z¬ }dÒÖm­B âlFÐw­þK û€¸›@|Á´uÐØ^e=uçxXúÉw¢Þ�DêŽüˆÉMqІúS¸ÿOëÜ%©ü= – ŽzÂìˆUbi‰`¡»Žo~3Lµ´4�jS@’ ’©•Î#ˆÃÖ{ ž�7Àtï L’&V¶-E6þE [ªÕuUvhZßWsÛ°ÚàšOÛ�ÅF'¬ÃAû`Å£‘AîRæ"¥J”EZÀfŸÕš["E„ê`ˆÒ6º N©§HÓ$DC¢ÇR9~š«÷«¿»æýñ­ð¿Ö^¬ž±m;µ³zÏrš¶zêňÙ)é©¿<ò3Ô!ô™FAôä�ƒrq áîÃ6¦,|ÕdA;†Ü›�}"6EŽÄSxn Y„ÁbLf´\Ì›k*±°õZ»ªÿ†›_Fº™wêƒ_ÿC»ou)Ci¤¶Iè�ŒJÍ""ʵE›%Uê·¿$ë›ÄðªX>0Î.j5Œku0eÎt‚ G;œº­QS‰À?)9ÁĸµÀ éqaôžJMÒ}“ñ°:±K5³¥¿ù¸­¦Ün(·=~åš5=*E%JbëIož# c`J‚¹e s­Äü6¥æ¨GöÛ1 €na‘¦ÄÌÙGG€qQî¥EÍÎ�wŽNÒÚ•¹ôƒ­sõÝgê>ÞÙ;Õe¯–Y·féÝÖ:ºx ƒÓ-SºÂïLc ¨Åd›¼/|”øþRwôõ‹Çéÿ1Ô^ Òdè Uw Å9ôaù Ì�„ ß-­;*Wmt²ùcÞ±RnÝåÐ^˜mm¹=lÒnKåæzêÐ±ÇøwxèÜT˜Ä�ª�’=Sƒ Ý»‰ø•†œRkœ÷lä4܈ù“¹M†8FÔ@hˆ9šf:H?4Ds‹óBÏy¢³îê=§Ô~·ô `l}«Op¶G~kÜ5pš”šžYi(®_ˆ�Í$Qq )fË€«ÔÄT4˰ôœçU‰le�pèqd ¢÷"L ÕÖbÈnW¹°Á±™ù�¸Ì.K@ä«M«}é�>ñK&÷ë¿Jzo´l�_{Žßl]Ã;CâšOÀ%ÙLí#$@úa•UݲiV¯‰©E¹)¹ÄÞË©¼œ†í�:¬f¶�{Ü\4Aä .Þuƒ€œ¶S:S·7”;Cu|PíKJmsÝé÷bµ[®Wíµ-GZYj3Ê^ i;QÇb‹r„,øçâÃsá©û›I™¹tÓ –º‡ÌPAt¾ò@;k…¤ê—C©:ƒh³\þ"æªé ²ìj­õÔv«yºjgf0ÉM,/TâFoIœ$-B7w¢ZcÄà1-kªa˜{B"æÖ‚-Î'P²$ ú?7P«w¥GAöÜVQ ˆP[é­¿…AQÁ%*—"8¢I–ONQ,糺o™Ü;¾Å; hv¦L|ÒâF³5ˆ ™ËrA"áOŽáÚð÷²bmh:D�9’M€€‡ëÆVÀênà¶U[z °úS·mëOýÝiÚûu‘´pµL@ÓÈÒTKE ;Îeýªwžøñ>ð¶+ K-JÆ£·./“"óxý1#,¶·41?aÜHË hð�6m£c&âÊSº´Búºfé]/ÿFö.ۆ╕uö[M %ÊéLÑ45TuÕéHÕ5QMQ§yu9§f‘eY}8ß ð[éKÝP½Çžiæ#æ°N[¶òpRâ>-£Z  fFï¡A·1lß«�Œ(ïK¿´*ñÑÛd¶=­ÓîœÝᨷMASr½Z($Ô³ÓÍø7«¥�ÑŽÙ¡ˆò©èüânÿ”ñÿ·PתâÀˆ ˜"n $Þÿ)l^:ÐcE^c] Úäã˜2µGucqõ!–©®¦ ™iÍö®VkÍdk�ÄÕw±.ã'ň$œóÇI„áì¡`´ÒÀì=…ƒ�ân®éŧ©ëÝ·šÛŽ“ìÈv·F×pÚ(e[­e®{�\ä7sÉéJQ{†E Àc$‚ θž1‹51¡�Ѥé>+µà˜vÓÁvŒ “ë ¹¿´ã |tÇkt‡qõ›tVôÒÕ]ÒÛaŠ xh)æÍ:ÇÛ*ð8“¿ÀûƒÓ�†ptßfnN¤Üˆ'[Ï]W3SâLSþgŸš�,6¶Ã`¢]7ø¹ëOF·]£zì ËWb½QVÖ0æ8« +#ÁP±”3BêÅLy©R±a±* ·8"ó ‹´ÛPeO‡ø¢½Ò·¯:øÍÒIøÅê_U·ŽãßÛÞ;uÿx\ê.sÜj#–z•š¥Õ„¢yæ–Y$�Qc‚IšF�ÉvÅžðí: É™2]¹“bsKôÍÐYP­ñ%Bìá  @þÛ[’&ïñÕñ¸æ‚§rn†Ý3C‚™îƒñ E{8§ƒ¼ŸNi²!ò l.,7Ã4h·%:˜ä×9²`\�bbê`Jz¿bjÕ!Ǩy‹í{ —`é¶®Áêr<ôwO[pË"Ç RQÃI}™ÈE]£½)ng!TÔ[¦Jž{žšRp4ÅJ“sóÄg<³6r¿þfëÝ¥kº‹ÁãËß§P«ûÏF7…‘ë˜ZÞ÷KLïDÔÉ#Röã?‰¥tJªO#Š˜b÷ÆpN²«á*²rŒÀr›wˆ w£iÇoÛcàJ‡ÁašEľ¬yÀtù”ãèGðÖoõ-Ôh¬öGtãØ«“i؃Ççÿ] Å´"nÅ:QmJÚ׊*Jw¬’Bbd2nй,-@qŒ‰Iý#ô…:Ú�ÞûÆælÛOinMÏ{óUš;mÕSþ$2I/¥³v"+;60ª 'Qÿ^È–™÷ÒvòSRr‘­•ƒÒÿ†~­u‚[Ä=5Ø[�zµ¾™ëkZ†ÑÓ@€s#CÚ>b-€[ƒ§Z£›™‚[ÏnùÓtÒ‘cb=è¯~‘|nþ¡X®Û¢Ïh;º’Šž¢©Ö;Œ»t�CNg’¡n5%MdƦY r°‰ ¡š Ô­N˜%÷·8úŒw4vÙ&`jT9[c1ÌÌ�4×ûˆô*Y¶zOóÚº¶ÍpéýþÛ·-²]͆[ƒXí’ǃ$ðÄJÕݧA*©/$ÏW1‡‡Î²qŸSiìämô�/î6ÒgRZx_‡ñŸNºŸý£¨ÌìZ6¯Bî½aÚ{Ïu_:‘´öÝ^ÛµK[m²VSË®‰$ËÁn†šÃÀí%_rÆDBF–f‡'#ñ˜àÂ{µëa‰ÖÄ�÷ÒÂp!Q’íi“pci¹ÐËçL~ö¾òÚ�B»nmïS±ïö«eE}¢ŠK$ÕÞ¥‰Tµ3J¬ <�ê �Šº·l�Å;AjØ®>)TìÉÖ"Ò Ò$\t$Î-6°œµf`;ï ‰›ê:)U­› V ÖééÛî]ýÏJk…ÁRÍIOI¶®Õ‚HÄ’Æ­1š„@¨p ÊŒXä!)ñJt¢ÐçÀ&ÀÍF:˜‡IÁÚ /kk4Ô� �—[ƒ{ò‹z§­¯µúGq¸Zw÷¨ý1Ù°ÃpÊI·©ôÙÑ¥¬¤Fu3ÆcK+`äFî²ãâ1XzÃM®{K k²�f2¸Ä �ÛapgaÔ°Õ©š� ;0–ÈÐ G~óýÒw y×#ÐFÿÜ÷N’nzJ–™={]5mÖ;¥}"E–­©�±¼Œá%pªÄ2®J:œ&&©`{šD›omA° øv²çkѤ•®´ �<.mn±¾«÷Pî{2¦XŸetç}m+vßµÚ­×ɎܾÌÒÜj4u5�-6)æªi¢Ó€€§§Ø­ó9›‡Õª2ŠÑ.ë¨]yxyÞ>!F–´¯iÓžÂãÄ›“Ñúáp¹Ùlw�µQÑ®ªÓÏh½%Ö±ö%T´×)ÖAMBòÌ#d-Ó¹¥<¡#„ôä슆4‰xù„‹�Žöo¡1!­A¹ Ct�Žóvê¶nõfíÒ.�õ×o·Ãöû»ÕÎðm[�Þ¿m[ÍE¦wr==“Õ‰#•âD4jB¤5*̦ªëÕ鹯0¶æ>I"ÖÜHÔÆ«C²k)¸»åèbN`‘c1dÌø’êÇA÷]ÿq—ÔZ:�µu¦4•û²ÅèÕִ󘡎#]2U:Ë.Á;Ð$øì¤x©­M‚…R3‰i¶Y&DDÏêÖt7ŒÖp¶µÎuJV>2 uŽRWíéñ¥»7.ëÞ›“yìž‚nŠôh®’ß7žÚŽK‹K-ô©ä†ÒT¦¥F%‚¢ÍPYÏ©8Ö¶ˆ<1…÷&ߦæpå¸çÍgãxKZ]ÿª@Þ7æt6·$¥ÛãêÒ›"ÍÓ­/ÁÅ«nEn}Ïûn°WÍT”’�Áa¼¦&=?VãyH$3áñ1¨HÍÎ3x½¥Ð”8Œ3\ÑL¼nÓ#Q/a³2M¤¨e·ã÷§¶fÛËO¼þv¥=ôTAu‚>£njØlôæ©SÑ«ô¢î˜‹!bï9ÙÙýHÑcÐ{ÍRsQ?,lu±�&à tå¬FM6ö-†TŒÓ¸ÓKèF»�–¤õÛãz~ m*zm¾zM´® }u¨ƒb^/Í_=á V©š´Ä^³8ÄRùaVRÈýo /5 _NLÍ�HÔG=9N«—âÔi´K7Ó~ó·¿ÌÍçÖ­ó|¼Ö­û~î»â™Qœ×\f©`C9á�‹(ÌŽJ© IÉ€D¸ÊMÌLà¢À½ÍoÊuê·‹£?; bôë§–+·Ä_Q6íÖŠÌ•”Ô}?¡¼-=jËV#¡IjiöªºÉ-CË2ÔˆÃDŸ†C®KKÊ“‡¢ÜÀÝùzH´l ÌÙu˜:¸G1¿ÔU!Ñu›�͵2FÖ•hmï�NºÝ ÛÕ»6“â²÷µšJ:º:ÊžZ^Jh£Ê…ލQ�VR6šŸ×cŠ˜¦t•p>mjÔƒE?Ô:�¬-?È™¹Y4ÞÇ8ghËÊ/çþÑÉXÐüsïý»-Ò×C±?´ŠÝh‚*zzz7¦¢ô%Â*Z:aÜ´ð±§…`ôWä”D�0«añwiò‹s6"`¶ÛNašcôØ-Ü5|8icË�ù �æö¶âäܨŽãø‹ø€ÞK%wG>6®ÍPªdKŸYk)`‚'›×+E®ƒì'¶>á3/«+¹wí�àíʘ›À¿, �ÈD«íâ�3A¼[–Ò Èé3B¦®®¬Ý¤í¹ü3o)©c•Þ™*úÂááF”·§$�,�Pн¡RRÝ­ÞÁ�`Dg„´U5XûZD�9lu¸2{„ÅœiŠuLhA‚>£ÃN²dq¹õ6¯Ò®§ø2øb°nk^7rúù^Ö-O,sÕï…cÄŒÒö—íe’– ¶¡=±p ê¡Àˆµ·ˆãAd{éË�º  )©uòš¯‡ï‚Ý›fJe¨[rÚÚëGUYN�Ôј™ãF‘pd2¿¤f’lHÀk …¦$>«ºXyr$h6äl^:´ç¥I®v—qÒGM¶BZëúñj¦»Ì›{àö›ÒQÑ[*vÅewý›¸<ëQ©ÕÞžU5>©‘‰˜ZA¥íªàý,Ÿ¨·˜ØÂUqÕÝP3²nCÔÚÑÐÜß�<å1ÕîÏ‹‰¶ñÛ³õ¡ôCÓ� “mU-ȼ¬¦Iž´:É$ÅSÒ9,‘� !*c0í0Òì³9de˜åð"êßõø™ÎHˆ›ÌwϾk*þ¢|bUî Ô~!6m‹qSTCU]£g­;#ÅŠ1ÙêûXáB€ÍŽâX֩ðn�k‹@Ê%Ó[n< 6ãë´Ër‚Màtˆ;ШUu×âZ¬Ö5WÄ­M0©¢šÛV”›RŽ5«¥–C#Å0bDˆX÷v¶F@8ÈN0xi‘NLÌÉט÷)¿Ä1@tk~þ|”zS×�+ÄŸEŠ*ª¨«ª!¦´ÐõQã²sõT ?{µ�sÚì¥Ý€ÂÌöbE¦N‡nîþýPÿ[_\þƒð¢í`êLF�Ÿˆž²B ÔÀ!’š%‚F$–Œ*á'%@ �§UÄæ†Ïùbúõ÷ÕFÜE{óm4ü&²·4t¦…úß×I(Í3Q˜ÖüP4 1œ.Jª;sŒ xÎd8z‡šm']ß„t±øŠveW EœEŽ¢Ü÷TGWhî»V÷².ƒxuwÝ_ñ‹Þ.ï[4CäÊÓ—Óf5ž3—nìgͬ>ŽBÆ04ZÀôîUkck—µÏyqêgê V;~Û¼õ.�kÚ/[æ»eOHñÄó]%ŽIˆ§bpËŒÆhû{p{_Ø�[¨Él¸ Ðsë¿UI•¥ÙA1ÞUÙ/Fú~Á¿G¬î>µæ¥û†sƒósÏ?Ÿ>yÔ"«ˆAIØ4‰?TÜ:Òx¤3.Ë·¼ùÉvšRÙüû¼êvã*úŠŒa)r Hº;ÒêvÌ;oÆÞǵÉþ?ç¡8ª‘úŠ!…¦?µ�1éÔ¢�¶“·Áùíþ'CýCÌÜÝ¡OH¸öɇýÞÏÛ GÿÉ!ÇñÐÎTB“9%¿Ù]¯îí�¸£<ÿØbÿót³¸É’‹²hП÷ ’3òXìˆ~ÔPçÿ‡Q¶¡‹%�lÃn C”·Û£û-˜ãNÓ)¢Éªëv¢²ÐT].·XmvÈGt³Ï7b'ÐîO€IöR4fp ¹è‚£ÃFb`uZ{ÔλK§žÁ´�} ¤º™+ÞGŠyû[#ÓU#ÓR@ÉcÜÃŒ/�ná0!‡3Íþ‹�ÇñLÿ-==}úªkÅΤ�Su¹NÿyTì™Õàѯ%’jnP�­!Ëæ'‚Ãüþš<Ö²`ÐuY?¹MÛíòà±úé�¶©œîZ"b¶\§² ¯›?ðBÍŸà4AñªŒ4¢[oÞ¡„ÔÔZ®ôá‚wK"– �2@…'mvóO��’Kg¸3Æ /ÂüÃæð=¿1 f%“§sª³6ÍžZdZ:äô*ä4gƒœ`ãß�V®f]²¹†ˆ…íû)³3¡?Ÿ›Ç¬=Vê=^ߦ³ìjʘè)ÕW줩ww‘‰ÌAQ� ‚x#Ƽv±n#‹Ö¥R»hä ¶n\d1Ýc&D פÓÇ>ˆm2ðë³EÆ£œïeÀ^“|'ôc¯7ë­¢ÝÔ}•¸)è*.‚(íÔÔ‹m„B¥Å]u}59˜´Àz*Æ@JãæÕÎ=ñV+Iµ2æa�rIÌdèÖ“×E‚akU, âˆI‰VnûþÈý§µú½·zMø³ÚÔ›†«{ÜvõÒŠßµªîU;BÇME`¼W$L#¨i)æ’_BšVEX×öØbÂÿ ÿh¥f.¸ÊÒÀçÙß,¸ˆùºÉ&ÄM—œ´œ[ø.¶;‡©Š4ÜÐÚt›š£�sA!¢\âÀìÄe ÁÜrNÿÓ+ºå=êés§ÅA§X}hÕÙV@™%{€ ÚI+ÝŒœg]V�Ö}0^À 0HœÖ~»êPmZÔË@–ÌÁ�"`LkGnWJd«£†á4 Ào�gø�Oˆø†�7eyãöXœC⎆©ÙW¨½ô^ƒèºwЭ�>­¤ë ¿vÕUÉ ÜÖ4ü%<¶õ�`uü-O­:N³zåQš%xûC´L®¹ó¬Oq¡ÓȴƱ­çÊÛɲú�¼‹@sž#¼[} tÞûD¶û+rtWaïÍÃ[SpëOUº5CFi6óÖRÖ¥ÂÚM3ɤéC<*±Éê�JŽ)!õ$&> Âß‹±tÜJN°X6ˆ2è¾À^ÀA*Ã8àæ¼A0GQ &ÂA:A7Ë w_ºQÕ®Ûýcø_ÛÇz¼�v“sÜ«?Ù»¤©%ŽY¿ŒUA§=’Äò+·Íć·X|Tê�µ+ÒeF˜€àIÐAlÈ�@:XÁ²ÏÄp66ZÂæë”±“0AÌ[QhQî¤|Cü]¶öÊڒ쮕ô¾é·c¨Y®4=^²½UÅ$†’³Ó³Ï5LðÈÆ˜K#;©gbó@=Q1ôk‰n ”Üo.h˜’l- �U0Õ)œ†«-Î,E¶qÔìE®‰ëGÄ÷Gï×]­×ÕßÖ«Îª ¡¼Zêîqú¦Ýð‚hÌÆR©Iã ÛŒ5Bââ>gµºDåÉï6&Ù–Wø�×ì¨cK�ÐçjO9ð´(\_W]¹ÔwÞ‰j¾Õï+uŽŠŠÕx¢Ø[�®Â(¨„4‹O]WX8}€«°Q%8E |‹ q4éÅL;A0Fg’á¸3óiòÿÓ!Nq˜z¯ÏN±"òCLÞÖ“7;’Jao�;­-ÖŽ÷µö_\­·zVY)*-û"ÑM-$‹)ü=e沺¢�É) ‚6‹¸ü’÷±ÕN ÜV$5Õ2ˆ¸ù‰�G-�$� å= ¸zSÙ—:u9@žºïaÏœ¨¿{Ò®¦¢ãþÀ|K^®ó£G5Âí¿¬4³ÊX;,Œ½ÊÆ&Œ…>aé¹â†'…:«æ³šc˜{®.$’7¼ë6¸W(qfÓik‡þ�¬M ÷wuM]lêu5­Ci$µJìE ׬7v„ÄÑh¤üq³ÅYY];Hc($ê˸U+Dˆ3’úÎç}íÔBñ‡a§/,ý#`ƒBêÍE°Yߦ½†•)â‚Çn=Ép4²,�䨌<¡yŠF²”P’,j$êJ´憹Æ$ ­‹íl6Ôï)ZFl¬‚`~§m¿Ûœ¡ë/]]ºS[©i-? ›V.uG‚�cMYOU,ÁU£ž ©Y%¦ÂqLÙ‰Kª§TΆ|î.6Im£yg­ÎÚ¥©Ä«9†›ZÖÉÛ4ißüø®ý]µõ"†ãÒÂÒôzõsJº‹EŽ‚ÍÓÚWŒšY]–Nös\¸ia¨-—ôÀaÚ�w0èÅH.’]צ–ÜE¶Y8ìMW|­ähå¿1¼ÔÓ¥›ç«­¿h6fÃëÖï³ì+ÆÒ¸SÒ]-vÝEOq¢Žujš8)¥IàL³H®¥U^A í!I0âðt…,Õ.k´.q‚Dt¼mÊ š†>©¨Â"Ä5½ûƒûw-¶[GX.“T6âøªøžÜPUCIK_¿SÓGp§§íA7§O–Š?N>Ä$„ì^Ð05�KúvÄRhË kiÖ.´)º¨~ròg]ù¢h«èÝïq\ä®ÝÝ}ø£ÝI<Ë=tU[ÑÃWº«i%X»ò0’ `jÅU&4Rh�Ú`!Ë˪9ÎɈ“µÇ)þ5JÅðÑÓŠ©Z¢é?T¯• Ìï%fõºH]›=ä‘0å»›?\êFñ,ô�-4Tªáë¹Ä�L“sϽKåøsèµÂšÝMpé庲::cI IWUê2z’ÈZWYAš^éäý´…¤+Ú�ݨª.ÿŒT @Öhò¿¦‹-ܬÍ×3úœ~þƒîT‚¿áó Wk¥Æñ?BzIK5L¦g‚–̰ÓFO´Pì�åPŸ©ÕšœZ¥Ggq�EGÁ©áé M�þ¢I=ä§Š†tB‹Ÿ£%…Ç¿û;HÇÿÆC÷Ñ7èŒÇͰ­aX½…Ó‹~NºuD3ŸÙmê%ÿþZ´ÌS§õJ®ü0Ø)í Z$’Ç·é>‚+u:ð Ô½½¤•QÔ9Ï�k™mÏÒJu*‘%šç'j¨3UB3Àú éx!–»¿ì¹Î1L5À.J_kÌ—:ÂòçßSU?1(¨¶T5„('æÃý|xÕ:¦H²´Ø‰^ƒ¾.Eþz;ÝÂíšdÇ8ÃÈ?‡ÃÅV‡Ÿ{-l5•[•5Ž~Ѱ<`ãý VuVø«‚ˆQz¹Ï õ:¬ê’¥ÈTj±ËŽ>Ÿmr>ÎTZ¯$þñ-çí Ï&†ì¢õˆÇ8ägMž™6Qª¤b|’=އ´Ù8i¨ÕJœçŒsÉöÒ.K³æ£5@ŽáœaŸ:qtÙTv§¸s�>ú�it×LUÏçÇ0 !ºfŸ�ÏÎŒºæi¢a’qÿÏD.5BªüA­DÛ‡¦tuF†®I*DSž=ii•dÿÝ$7é­<è'¯åRÅ7æhQŠ]³K²úﵬ4U3Û£§ÿ³¬¤³AÁ?ÈO×¼Jß“ >rêEÅDT¶r@qôýuHD«ä!}ø'<}ôäÈ„Ñ ƒ$c9ÐQFå'ØÇyóŸüt0‰}JW’DAé!c€euEg–brFœÔŸÕTùPòÓr¹SÚHá�¡÷Ò/2šæ2 ‚??:Œ¼GD²!Ú�²Ã·'é§lR„#Áîñ£/t¨W¦8ÏHÏÓNÊÃtîjÖŸˆ˜)Å¿k%H§$IVè²c öÂüÈÏÜëSUòKzLx¬^,Æ�Ðzý–¬TRÛ€¨dJEÂËŒ{|ãË:Ö¤ú¹„ôú,'Ó`ê¬�±Ch²l-ï ú–ˆ_ë)„T1YjR@rr£-ít<ã9ã88 @¨êÌ-ý ßÞ÷Z|>•áªÑ$[œ�Ù@í�­þ¾sRÐ~¶(™£f¼ ¨Ç’Ä÷Õ¶f4á×6Ÿ5’Ú@U�-¢i{UköÔECp“+ séœÚ;qŸ×øhƒm”éoÝ@Ú&Žõº=<¸Øêên´·Êø-–VÛ—%’²ª&ÑJ) SÉ’¤†üJүˆíw¶hU–Üs_Ä®�EÕIkvi&m`?*5¢ßÔ*:[3n‹.Öiª ’:‹•5\Ðz¿<~�4ÑJUÃ8ˆìòF§¥H‚½þË5íivW8 9ë{›ú+R»àëwÚkÄ»ëeRÒTÕ·á»-·VYÈ=àGŠQ‘�ù¼j,=6³äÍ%½ýÊZØ&& Ñß…llÿìûë^ûe¼m�ÇnšJËœôÔRZö­âu¬©@ÒIM ¤ÈŠîT…¿Âu#êS ˘ uîŸ;w¢£‚lÚ y;ËEØÏ‡ëGö‹ô'¢û� {o¥û†-¯>Û©³Í5FкÁ*SË‘H KÛŽC•_”äyëÍ8¿À˜,n0c�xv``ibÊu éâš~VA¾�½ûF¿U7o…pùŸ=ä­†³ü9tÍa§¯Û½=ée]$˜h*(íôӤòHCwyãž>Þ5B·ª$8‘æ?=Uæà)-h*N:{ �úû%ŠÜå„¥†01ŸŠ=ühF*ñ3ã(]‡h´}ï`¹£<‹$é+ 3+XúŽN¬ –U�E�¢.#–w@ÿ.A^ð|’=ŽˆâIÝc¼ ¿¹ä oKvóªãu'c=éÒ0;­L1²öþÍ‹w7$qÆ8ÆIÏ�s� ±HÆB: ¼$í8br02pGòÇßóÐm¥Ký8”ÿE´‰.cœd �É9úy?ÏTÝ‹;+#7RÊ]£TUsOXÙÉ'³Æ�ìxÕwã„« ÁÎË]þ$¶ÅÄî‡[=«rܪ«w%xj+L¾�²¡´T¬q‰ž™W33R”��k›YÒs ¾ý%Sâø5ô›’ãmôÛ®É×§siß>,zeÿ›JjÄéµÓk_ÞÓ<#Ñ·×Oqþ*KtDJpÉ nH ÓÃPTe\µ|n2«8}C\üí-‘¸“iëyÿ”‰Ù[Á`©¿ÁKô`ìL^:}åtÚ‹¥R£ôªŒœ[ƸGqè:®ÕœrŸ—¥Ìägñ{áq�åã@Þ=2‰Ü Q‹ÓSB}bx<‘Ïòüõ;8ÙUêpf¥ÅHûà ÁÏ’|-^¥Æ/uB¿‰„ Ûf{–I]>Ãé«ôx™‹,Úœ0Ù=Š"YªPc³lú­jxÒUnmŽ�–©©`rqôúc�_Ó²Î~lŒJQŸ÷ÓýA(¿×—úØ ©Á\Æøû-÷é�(Ÿ×–=»W+*§(¯ZB–Ç×ÓlÝ:íþÄRsºý—ñ-Ú­oO¹\œ¸‡zª™=99sÉR3«ï2O%Iƒå ½ÔÚß¿ãúj¹7VÚmuèŸáÜ.¿ ý ¬†Eœ …Ï?,‘ÕT#/èPƒùk‡âxðÜCš}Ø.χ`3Ðïú•϶¥ÃaU¸Ï’9þ¦8€*ÿøiL“mІnÓÉà|ÙþXÐp”¿ÃމгkN;³þG8�Ü@O¾ôލõFÕ�²ª£)�Øý÷RŒÊ9S´jг�ÅAˆð¿®£v<#þ„¨ÅfÒ©QÝÚÞ>˜à£¤8Œ�Rþˆ¨…~ب÷ ÿ×R ZŒá ‰Uíº€Xúmã�NÌmáBìÔ(�]Še$®§f1¤_U]ørn{4ç%T•ûs©Û‰iPöGtÇ=ž ý“ô‘©¨Û—’Œ°¨í4]-Þ¦ª¥’’±èÝf@¾¡Ž$Ny�„ƒ´œgŽ5+ÞZ�Dûû `Í=¡|LR¥>ëéä±Ô5*ÑTM2¦;Ú3Q`¾ÝÄ!ï­~ðXã¥þË;ÒÕ °[· 'Z¶l{©+—qÔÏ•~»{ÞU G°ŒB˜úƒú§Wc©».�‘åî|Tmc…AšÆËqÞÑ/hàøÏ�:ÊíÀ²Öì¥D·­ÎŸeíkîè­ˆÍ "E�»·Õ‘ˆTBÞe� 2OSá?ͪÚ`Äû=æx’)0¼‰…[Yú¿´¯µ*”T¡Š$­©˜…†™ÁA~ª÷ iªW¼®}>Ñ’u x]P&Û@�oÓ5RŸ¦Hå¹ÛºU—·o{rºÇn­"¥»JG&�à£)*àà�‚sƒŒê†3 Z€Ìáncï¿¢µƒÄÒªr´ßÞŠAž‚ßIÏUGEsaª*Bó–?¼í’p ä“çT*âɰûè´)ÐhmÊÆýý϶¬�ÑxªØè`5sB†rˆì�$ùþ§À'QR¨ú�Ø>bm·]ÔµšÆ0Õq°ñú'vÛL£»Ó>Ÿ³cý1¨N7ÍL0a &Ýr¾ÛLÜh”�„²m~F¬4�M2Géw,Á—±äË~Ï·=ÝݪH8í' œ�5a˜�á ß—¿¢�Ø[Ü/ÒX ï@xÉÆ›ú±Í °«A¾,å6=ñµÅ F–k&df‚«S(P2,IÉÏ s×ü:óR‹ŽÀý‚ã~"=�fƤ}Ê£vk×Ü¿Ú[ýE45Öͽik´Ñz$¤Žg‚š��g«‡?P;xîκÓ€#çÎçYÆIÐUmÛ~—Ö2W ê´Ìæ1—bIb<“úivL™(?¬x²7%âiQe¹cf^ç)�ƒ?¼@àyÀýþ¶OEz']°vÿZwwÄ=^Û«¸nzzÝÅ$6ý«qY}¨`¢4}’‰Œë1¨,¸ÁR\zvi—œSÅKS‘.D_}��ÿƒÖm0æ°—^Ûkmù]n�̦Ϳu¤è¶òÝýnø¿ÜŸ½Oþð«¥F³kÍ»�æ†;zI~h$Ô´”ä³á*‹Ãh¹“Kæ#KAžüÃkø §ˆÅÑtUlÖDw\*C§û˧»í7TúC|ê%7Q/\ípU[Ý$’$žœI 11û*8 Ùíe\ä66ø­hPnÎ{Ë̈ÿ„Ä‘îeTøs¶­WqíkËsæó#FÆ�5½—Cz?°î½kèü�uê'Q·m±ëÚåµà“µ¿QvŠžže©–1KÜhœ¼Ýê¨ÎVËÐàŒá»‡%¬ÊOÈ$æÑ¢4ç3¡Kñ.)Sÿh¨üÂsYùµ¸:FºèT¨#éu’Ýlƒ¬›ÇvW[ì7*JX¨mÅÅ5dóÓV¸�ñtT¨ÑK9¨�³ì Ç=Š]Šo5(»Z«D¿;‚ ¹MÁç«dX®?‡à>&ìë n‘22eênkæÌ!®h�$8ÚBØ=«³~ íƒrí}¹ÕNµì݉¸¶= ºRÝ)¦ZÑ‚Fd¡bð)‘–>ÅhøœŸ+Üx“Áª¥PV©•¹¦{þ˜Íþm4´M°püâã„©J®–y²æ†È’C "Ò@¹ÐAV¿Mz·ÑýÕzºíÏŠÿÕ�ϵ­õ6A²¯ Sã­ªjv§–ŽE†(�Å4Év:àùgnñ‹…u ÅÎsÈ‘i‰¸3¬c¿Åmã~ã¦ö°Â†� À˜îúʾ*:½ð+¶¥4V=Û×m×BàJ'7ZŠ5„€ÒHÄcåÏ9î<ñ�¯[„.ÿ.«ØÝ�ù�˜t,|'Á¼]ŒŠ”©—ÂZÑÒÅ“¢ð£·:¯¸ö–ò©Ýöë6Æ3$”Õ6¹l0uÏNëéÉLh”*¤l¥”úe$^æ*êÇ:òìE՜֛ÚÚrîþW³ÐÅ>“¥·Úâg¿Ü§í¥¼z;m˜ïž–o‹\ubJÕÛÛ¯ð¯5>A1BµPJ#8îPÆF#+œö’ÑסUÀ–8´�]¼•Šº2;Fè ­óøaøªøné=ž]�W·º¡5ërÇPÕµŸ‚ŠŽÁK3zFI›ñ Ó×Ów’4�½%¦_žâÜ&½QžD´µ´ò�gA§]—CÂøÆŸùa¦ Ü�w¾œÏ¢ëFÔ´Ü�²»nÕG¸lÕñÒÏn®¢J{”uïO $H’žá÷€p3•^:ƒŸ0‚9ê6ÓŸÞÁtõè�%—ÅÇ�>iá:7U%–ïp®±]©¿2RÇÝK"»Oœ´e1œ„ùÉ öñÿÞ­vÓªD�``Úˆ7:DwXµj5 æ÷·¯K·Ö¡³]¯[;rÙ­W(¦šÝSSCQ5éä’‘•Æ“*##1*´ØZ`‰Ðè5÷²ªÌm78Ói5¿¿{(½¯`ÜoÞÛµîuæŠ�WÔŽE1CêEc`¸ï™À' _÷U™h†=ù‹l/¼kŸNû+Î.Óë¼ é¶&ã·Y¥¼Tíy-Z*Z¹äªªEj˜êåu†XQ�Y™Ê0ÂÂÂÌÁNuYØZÙ]P ÂÆb/y Á&Û)pøÚ.x`0Dɾ­Ôô‰]Wë·N7펢–õ¸6~á§ÛÕÔ“5 ´ñ2ÈðJc�ä Þß±eu`Ê„ö¸R{XŒšØ¶µÌ‘ú´Þt3y6t]çÒ{Eâ'¤I ‘c$n òW¾ÕørêeÖW§§ÙÎî•vêF0ÜhKÃ5Zz°FèäXùV*˜ÊS�³q™û2‘«v±‰w;gIW°ï×B &ÚI"tÌN¢ÿƒe¡� Þ4ÿ]émEL÷µ¡/7ËÊÞ®Ïi¥µÓKO鄚áOA£’¥ikéÕãFtoœú|J78%*¸jUN!¹Èh˜"D“ ¡"A�1&%fq×ÒÏG+ÇË'qcÖÜMÅãKÂ�t¤v;oö•|:ôër.žØ§·Ümô±ìÝß5ûiÚ««é¥†8a­4‘EO*Ñ+ÅOJLŒÑ¼²®³8öþS�ïs@{á Á.‚$f‰§`U¾Š¢qLĵ�Ö5Ç#Iq¼4†�bñ¹êW|÷ÏÂU×en¹¶õnýéÎÛºÃKýåUà¼F´†Ÿ±¦_NXÕÝ%p¥EKÞºÿ5Ïÿ�n‚ïë�["¶]våÎÓt£Û6¨Žx‚Í™ª§Fuä¯z¸eîÁÇ·‘®ïáüC©áb É:À�: Í>1c<‡ÔýÖ‰Ö|$oSéN(fŽ9ÃP¿0È%±€ ~ößÁGY÷R˜v—á=Ic„ Ù’š6•éÚ !f`TúhOo ž0¹ÊÌÆËH¸E±11r6ºèÆ# ”¹ï‚/gXåÏÜ(Tß ½@7J]µG°ežï4QÌ÷Œ_‰e,}3(XÕ½hÀ(l*ã¿Z8\*¤3³‡:âH:‚l6¸×EN¾+ ?Ìù[c™&ö±˜éb.B’M÷�onÊM¯OhÛ· U=mÏV‘ÕÕRú¾€¨– $ÊÊå}W ˆûs"AÄÆâš[–œ D� LMõ�"âÊl%L<÷É ŒD嘈 æÆêÁŸQk®”véiPE2³¥L÷½/L+ý¡»ð¥_ v0=Ø:ç«ñW†Av’æ‰;ܺ-ýÓ¢Úþž“sIœºÃ\c–ƒ}¹ªÊãð‹Öé÷íq¶í$z•¦zªË¼4‘Bs&DóJcü:±‹åi3(ù@,aÑøž“ÛŸNŽ-b~iwË0`›E•áÇH‰°qŸù`^$HDóO“üü@Û+íö©6EÆjêë|·*9'«¤U¸B³zL`a7¦Íê%Êá•Xe�ªÜAôËCÛÂD–Üêƒ~²v(Ì9ÁòZ`Àu‰'å�#RD ÞV³õ áû­ÛV¸ÙªúºR½êš ŠÓO<’YjDhí(BÍ ¸ÉÉ•_ŸZÌÄTa¬·¡¶Ù¾€Ÿ5T�N“ÚM2ã¼ ‡2/ÖtºÕ½ë·¯û"û·¶fø¶Ûvfè»4+L—ªÚ*FŒÊªñþÇÖî Êëƒ/f „x:×ÃTªóòt·;ðA#ªÎÄS¦ œ;íÌŽò,cÜ¡¸ºY¼cŽ»>تÜ6ù¤¡Š ªJÊ*˜æz¸Zzu2SÈȯ$H\ ÆxåÕÊ5Ÿ”9í"tÛi´žWè5U*aÚç× ýãaÏ×EPÐ쮣ߨžëfé¾ð¯´ÁQ%5EZÚf–8¥H„ÒFÑÆÓ²6䎓ï‹T1Aàg0<¯§w%C†ÿÞ§K˜¹=u=U�;ž&Z[œ‰W¾ä`0$dŽÜ`öœŒƒÎ¥6&ð~û¬º…¹ uþ<gº7}‹bÁ¿÷næk +P~+ðŽáb—½#"$ä¡nàNHàsãZØl ê5�oX'§‡ˆU*W`“�:é÷²×?ˆ]³¹n]P±½&×¼P›-4Vy2QK =Q�L‰.TÄKÂF!$|¨ö&,?¥I¥„Ÿ“Ó§§‚±ÄøF&�Lµ™•Àhâ½ô=/öPK½§Tõ’͹ÏÔmûiµÖ@òÞjípщ'¬=8ØÆª…&R䌘äÏoaÄÔqt[‡$˜�l§ÆÚùÆ‹*°q® ´\‘~ë÷-§¬ºRRÅOt(R6Tä0$~ñ# Ÿ8íoe:Ïc …·Ÿ=çÜ­·¸Ü£ª¨!¨†X*íÏø'ý„ÑJU’\“”ÁÁ`@9øûê›qiúÙKÙ´•Ë}ß_¹~z™L– ê_lÐRÔ%ºåh)ÜNÒG؇Ó�"¨0ÍÙ dwŠ.à{0=ÚXü7ù�ƒ7܈1<ĉp&!pÕñU¸~&i›m¬Ô[Q7#Cw óÝ�vøsêOG6ü{siWts­0{mßðeÞË{ hÚ9d€ÂµâXa¦ì‘½PªÎèð˜le'å{»Jz€ui™Í…ºMÓb8–­2rvu oé#C<ÌhbgxVÞÃë?­‡aìä·ôãqnÞ£[¯µw[­çý±Ž5†zzŠciôM¾H¢¨ôäLÖöÊÃöª‹éô²áNDÔ#Cb7ÛÎW5ƒ¢jÔÿ0œ tŸ ›÷ÏruŸá¨Ý>ÞÔ[‚%éÇV¦ªj ÓEvþò†ŽÑ. QEjt�§ªï…âÚW=§±bŒƒ/‰cë’h6û o=û ÇBaopü ¿5\KÄAÄí{‹s kY ¶ú¿·{.çèGYk÷ŒiNÊõupÖÛݰc ³‰A,ÇÔ1€Aäk-¼Øã°ã›ŴÐs]¾á\MföÜ7\:æYç1EÕl?�­¼@’=Éã»þÑm�›éÄ‚7÷üôAß ÖÕ¥ŸúÇÐ�¢«Á¾!¤bÎíûÁR=«uëLObû¦[Šßq[…0¨† ,½žŠÌX;Kt^ñ àžÞH8É©Ã0B¼ajKLÜ»§#ꥈ5ŸùŠG4�·ÖD‹ªF£â:8á·Ç¹væÛs+Ó¼¢¢# ¥YЇ çØüÆ®7àz¤M­t‚5è²*üPbµ'6#QùZÍ×ÛÅW7Û½íFïJ{i¢–»ƒ‰=fqŒ."L r§8ã=ø{„¦êu¦mÝßÑsq:8ª�}# ƒ=ê_Ð.”í»¶ÌêÅíßsm;…òÊÖµHè#¨JU§¼ÙæYŽf�ä&@".V0ì;ˆ nbé#@ö»Ë½gá©ÝÈ·_™ºs*°z¶·tèÕûªÿ`�|Ó5ep- !B;üäïi¿wýÛr"…^)•ÍhÈÖ}ô]FàÚØŽ‰â@€Ê¤‚aÇ1Ê2ˆ7žqiäœS¢1¢ŠºÍù]Uo¡½ÇffNÈÖ«¾ ‰{ã ;‚? ÙÛØÀ³�Ÿ´w5Ÿê]Ù‡�7èw‰ÔºøM—9G×Ô,?,^ò#¦„χ¢îOYþ ~7ÇÃçÀ}fðêwUv…V×è󯦣ÛVk}Wã ¡ÞÛ€‰¥žJøÕÊÕ1¦13’BßÀ·> ¸€à.D™'[ 6'n‹:»Ï,kdxì;–Ä|0ggÃ% Ó«Ý-Ýnµ[lûs¨[†Õ^h-V¨Òå·îú6jª™ëk£––«ñjbFHO,ìJÆÖq<-¬"¥J¡Ò@ m§~p>Šÿ âØš_åQn¦n/Ëu®6¿†ûfíê…Ûdt¶ùÖn¯ËYxŠÛµb’�‹øa!‹7£$Š˜Aýž�‘Q»1è°».{“ ¿8ÒÆU€»ý>˧ÿߨqÿ˜–ô—vu­T×þ¡îáiÙ—]«Gnyi¶õ]t¯ÿéàÕ‚«0ñ‡Ã„8íf´æe!™®o#UˆÌcq!Õ*Q‚`÷x®˜Ù?òVz´ ¹_aø¾ê¢:SO#¥=† z"â6 ,� ƒÜPwö–$ŽæÁ3©‚µX-âlcäQ¥ÿ;mÕsKá›à³mu3á÷¥t´ß”»H\®’¥l›%]u=Ó³<õrWþ6/šX_ýÐD†("çÓ'VÙðÃk0â^L[ñ§Ým;‰¿ ]N�‰›ùr>�|!ôÛª?Õ� ¦Ý‚kWû1ý÷Cum‡U=]]hØ»�¯#ZAòEûª[:»‹øLQ¬(š‘òæ$‘I¸çÑCˆø‚»pý®ù¢tùí eñCðoÓÏ„ýÃ[·ªo=>êò¢¯µ�ÀÔtòHi�jU&ËÌnR¦V)ENÇ€‚Ú ß µ˜#ŒkÉnÚI¼J©ƒãµ«â[‡|߯ìºßý•Û3­Ÿ —Þ§]é:/³ë*÷Mm­)àém†âÒEK8 å9g•»U‚Œ’%˜ÔlÒ`ÊãyúŸÂÇø‡Eø€Ú­Ífùµ½§O­“ü&Z:³Õ¿‰(¦ªè­ž­¿«¶ŒRô¶ÏOýá==3­D‘EÙHTö( lHý0«óæ'M‡!ÑY£‡¥…¤Úmk›iŒÄA$“m½Å—ó²ÿl%2ú²mí¯;³KÒÈ{�¾i“Ï:¢þ×jçyþÊÈâ®™-o—î‹�yze{¶†Ë”{÷ÑÎ^&�Ü0öŽó… âÄX±¾GòŽMòcçýˆØŸoûW£Cþÿxï1ÿj�q{ÿ»o‘ÿ¹[Û3â³­?¶QÙ¶6ã¬ÙÖx± £¶\.TðB*€A#Z¾Ô_S´ü ê¥_‡i9⫝̸s Ë=o—Í_ÃüS^‹rS —ÍÒÙ•ƒnø÷ø¦¶UP×RuS¨)YL%JyÚÝÂ^–# Š­ýã•4lï)*r4Ô8 i»=:¯i¶ÿíõÕ_Š«Ôa§Q�-:�š̃¼|jõÇrÇGã»×nOE®Ü[Žu�B²¨{¡íVÎt€@�YàÑÝþŽJ6|BA/ìY6ÿ_ýècñ‹Öé'©ª–û~’¢zhh¥ö£pú’ÓEG ÿÞEÚ$GdX‹ Å@‘¡?²?ÞºtþßûaN>(©§fØÿ«þîhê/Œ>´Ó=<°Ýofx�LJrߋ§Ïak�ìÏü¸Ï¿�F߇C}:®D’ÑpË`6ô„U>(¨ööo¦ yK£Ë2>—ã¬È5vá—aSþÕ_×µ v+Å‚e”ãþwÿˆæµO„¨8dsäZÃa¦­Úml®QøÆ»KwÙÏÿÕª°öÿÇw]ì•Ô÷[}fë‚éwAUöÜTó@ÝýùGZ¤óßõ-Îs¬Êá)Ti85ÀÈ!”æyÎY•}ÿbj0ÓªÜÍ6 ½ñËIÓè¥w¯íø—ܵÖ_wgQoUNjªú�¹&-)\w’õ�–Ç9ã�TÅÿ³lzîÄ× uGD¸Ó¦\cI9fÛ+O�1XzB�ZÁ xÂaj5oTïRÜê.T�n =l²½C¼;²ñ#¼Ž%VròT³"ª¤'$O($‰7iKSÿÝ3ÜÑô ˜ÅñÎÑùœËÚåÎ:@�€@l¬ oYªkfµ>äÛ7MÍøT–8…nó¾JÈæI@Y*]P;±w3ã’s¬®)Àê×nGÖ$r-a‰×oåhð~<ÊÌÊ`Žpû­“ øïêU‹nÒìû Fì³m˜!–žxß·¹iã‰äwxý7�©BÒÈJž>cƸv³L1©Ú|¹Œ_³¦܇EØTÿhu 6ö3w¸ýO‚ŠKñ¡Ô÷�Äw+‚HÎÍê~Ö±`xÁÉç>O¾´Ùþΰ“.ÿÒÝ|• Ÿí  ó)–O‹ VSSRVWÔICÂB.Uˆ89çóÔ”¿ÙîŽÌÆãrr7ܨ*´,s€cžâ9f*Smø˜†I)êî»zý]Y̓Ż«RH¾^ß�zg.Wã8Ô'à�%”ò€øm¿z�¿¹÷yqÿ­Ê_Ö]©QVïM²7$Cá¼Êä[Çþïé­š ¾˜�æÇü O�XØŸŠ˜á¡ž÷õ E·¾!Ežé-H³Szž©Š�zÖ@¾¡‰¢/ÛxéÉ$}Þ{$eÎ óx-f‚À×ûAÖÚ[kj‹8ý,ÂZyX‘ë%[õ³i_(eŠñ´ú­{õ™ ³~VÉå ïG¥=ØWuÎ0š áÜÐ*¶?ùcm?ºñ²Ñ©Æ°e¹œÇ“ÿÌ?ö­”éó´ÞÅ5¾ßfê,AÚh”o«Šˆf< b+DÅeÄ«¨î‘‚u0à8’é/a6ÿôÇ~ÎTÇðÍÿþ§ÿål.ÑþÌn¹uyî÷ž•õR£jIrxª'¨½ï}Í<Õ’"vÆóÔ 4j‰F±%G ŽºlKD> =Í�ºåx‡ÃUqp¦éæ_?ûQ—ÿì%þÐv´×S·_úu¸lÓÃèši7FìUÆ8 Ù-# àðqíήòIU0øþÊ£jSA‘{ÛªÓ>«ÿgÅïI®ÍsÞÛðW×Q=EXª£Ü×ù^’‚Y#¨’”y#Ž8œ«w:"#eF«š$iôðæ¦­Å{gº­i.&I›“32dŸõLt먽^øiÝ {Û]GëFß¼z-M<–Íçq…%FVB®Œ�®;^@g|Äœ «P~¡#¡û8w²Ýá\n�#ò‚'¨û´­¦ÚÕj»|“\úÝñ¢ÕÙFÅ7Q»cîEÂ’�œ€0>ƒ�¯<­ðÞ ?(ã¹ÿÿd/I¡ñ%ÌÄÔž…Ÿö*ŽÿñÇÕ½ígsu—âçpíXê¾³¨&TYr �Fh]{ò3œgøêßþkOmÙÒ/'$˜åzšxÂÎÿÄ´ÍC•ÕsÀ>”Ô†åñ#Ú]ÿÛ¿Œ*�c‰eSÔÙcF® —ü#= “ÚŒk%ü.½Jƒµ§D–ˆNàræ’§E°Þ#N›Icê€n@©¿3þZ®*¾1÷nâ¿W\7WY~-/óʯ=]Vö‚ªªbЍ®òOnfgUHÐ19 ª8 k㾩ZjÕe78êKIŸÿ�éµì4Xø?N�ùTŸQ�n€<ž™#½/¸>' Q%Ê—¬Ÿ× ÏQßW½([¶WýçÿêðK60Nrpð5™Cá—8–v4FÖc´Ò?Z¿_â&°6µSÿS|?·øU´ûªåW*Üz»ñ,ižšJ7ô÷%(/NàŒƒDT« säçZ/ø/M�Ú®gô˜'ÿW°²¨üa]ï—U©ÿ¨OÿŠOpüLܪi¤£^´|]V@ÎÓ¨Þ”æ<„( D¤^âœ<€ädj:48žÂŒIù ç]]¯5&#∸­VçVjË×Z{›Õÿ{õÃâÊŽ®¢'‚icÝô¹’7(]]Ú—¸££$wrQs«máœ{<-*MhØ1ÃX�ÙVÂc›úŽqÝÎiú°¬îûïbíF5»/¬ÿôµÁ�2E»-ñ7 ܹ0ÑŽîpÃ'ƒÏ�VÿÅcbèQwüÌqÖÆ3<øóÑ[©ŠÁá�þž­Q10ö �4`˜ÚT×§ŸÛº†ÁGÅÇN׆í ÓÜšß¾i–JÔbƒJð>bH`O¹Ô8ŽW PUÃáèDHc��ôÙútÑGK†Å0SÄUªZ €\Òæ%¶=EÕm¾º�´ê¨ªg¬ëoÅmÍ2**#©¾[„3²>§ìiÐ3$¸, F9:ÐÂ"Hh¥D ¡®á›èªb)pÚm.¨Nò[«�÷>¬îýõ·ì”Ï|o=ÏIb ––Ö•ÕsOýÙE%KUM d“ˆÚ¦¡æ*II;¾˜ô:”�ò† i÷Ípø|C!Î&]ªÝ-ë·úRݸn{×T~+®]UŸhE%]%]þŽ¢Ó=RV:vÌFg¢Iк!rTáƒwüÚóü7â?âN�!@;,óÌóÊúG@½Šà¨UÀ^*µGW-’RÒè�bH‹sˆ¨¥z†áÓMÊÇ~uÞŸu½EÒ–Ž–’ÿéZ ,«S'kµEKJ;‡wªç˹n«‰Å7Ø ìàf™Í¼Åâ4‰qø|øw:\ Êe´DÚFúØýCêM¢zѶ÷¾ê´^+Ú‚7¨k“¯¨¯:MIêLÄ”A4qÉ�F ÌA¹‰Ã3W6Âú F¤ ξ*–U®ÈÃú£ÿ»I<¹©?Zlý6¶o;%¿iî>£njaCK%UUé)R¢†aZ¢U„DBöˆÈ!›’H�fp N2¥>³Ø&f‹;ÌH c�áð”ê†S{� ItH9®´ëâ¦×Åxm¶ûioN¤Kd¸lõt•6óO¾v3̤m!-"Dx`AÆ­púµûY®ÑÒfE·é*Ÿ§@ÒËEÏ;^ ga:ÂÖëÎÿ¸Ý/Wú‹¼×G¡zŠI$©ô’j´ž–#à¢`*ºÁ8:Ñ®É7IÝÇ’ÌÁ.ͬŸõHðæ‚®º×ÐE¸-5[vájв`jc¥­‘ ŠÌ]Qà 2;¬O:™´LÓ·/ãè«>«FfÄ›ÁôÞɾšÅk¿-sm{VïñSO_ -2ÅÙE*ÃqžÓ– y:T�Pè©–7‰ŸºbÌ;›šˆu¯±Þ/¡é¢WzMAi¨£6{�M®®)ê’(ài e‡×lÜ0ÿÇžt°ì–C„ƒãè¬qG†Õ!®",–ç=èý»×κíßIvçYº£o‡)Çꥣä�£±Ü¨äqí¦©ÃpÆî¦<‚7Äöº®ñâ~’¯Ú‹OŠtÖíϽžç_¡4ô·uŽè¬"'Ž0à ópÙ8 ùÖháx7·;kèOv‡ðºñj/ÉZ¤‘‚š‹�÷WODz½ÔÛ�Su ë¸/{’åQ_YQWÕÊö÷��«è`Œ#Œù}2¥0ñ�q8ž…7å  ÷Ï?ªèøÅV¦k=Åĸë§tr�#E'ÞŸ'µîËÆÒê/Â~ËܲQL‘ê9iU僚“¸2ÿ�ÎugÁ«º˜«B»›=O>†=Žõת±ä¿Kr· ¥Ò;µ0œÔ,rº¾fÈ*ìÿ¼åÊwéóÙÛ“�}�>AÐg ƒ£BM;x“õ'ÑNz×îª|?uùÔ¾ˆïkŸO÷ÊÇýÛýëCAOVéO$Q™£ÅM<È…ŠDI yÁ °i&n�F�Q–¥ÄŽ|•×Ö_‹¿‰Ïˆû4s®[ß]C°-À\Öšk}=­X‰âIÃQÓBæEIdU=ß'q+‚ Ê`Tí@ù¹ûöwJ– ÀZÝ îwO–_Œ¿‹j+m–½õ’*šë­Â«!½jÊŠââ©åœÓú²zŠì;]Ø/¤ILs tð÷â€à°å¹H·Š×5%NÛ—pÿ³í]‰nÐÉMqŠžz裫ŠJÃȆ {P<8�Š,¤†''7©ñ ìnF<�oÏ.wÕ5\¸¹àOŠŸmmßÔ½—½mÝDÚ;¯|ZwÝ1¢‚êž¼ÕQÒšoÃ[ÔGW�Ò ¡X ûÀ6›ÄkÕ©ÚTy.€$òÐrBî…u>Ä´ÌÅõæ—ßÝNêßQ·U û~oN o+¬ÍMKRÕ‚NJjto@K"£اk,¼|ØE[UÔ»2âZ4k?d°ü3 Eí}6€F÷?U~tƒâÏâ·¡[N}…Ñž²õ3§{6ZÙnP[(à1µS…W�4´Ò>[ÓO Œ€2sEß5¤ÙK_‡áê;=A~ò£�{ëÕ¶á¹o4Sê�ªç}¹Ï{»ÍÓF÷*ùHYjg Ÿï[ÓPN ¸cNj–Ùº"w¢ø�-m׌qC|¹_áãVd.ˆX&໲ý~CãQÈ›)afa<%‡ÜcJDÝ %BrÇOiœJ 9%U~žš¤ÚÏ,*é¦ÂXDÿ².ˆÉ¾63Üþù¤R>ÇöÇóÔ�®gôŸ#øUÞÁpó•ú «N²DƒsmIAÀ-Ò õà9:•õ-¡ú(YLi!Név54Ô¬í»¶Ôˆ¼”ZøË)#ÀPãŸ×Uˆ!×i…}´AoêzM�EQ3wWSvgŒ¬™úëFO¿Ÿã«F»€€>¿…M´ZMÌ{ïK�™ 3+MÒŽ“ê=ííÎ `É‘ù®§c‰7U«5¡ÖÑ^{CdX«©â’Çr–ã(½å·ÇV$Ð ­ÝõÇŸ¶¢cêL8z§¨ÊD|¤“ܺ±ðwÓÑSz¤fºlÖ©�LÍöR0°Ë�¤ÀR»{ã‰dÄ,׎¿EìWás¡ûß´­›ÝÜ@�ê4±Ó(*˜ã(„28ãWÛ]RËu¸·o‡-…}°VÔ[vu–²Wû ½ rÍ&ynCxúrE£’A«Î—ö�ôƒ§{šzxm}7޾f0¬"ðÂ_Ýi»ÈUgì^p2FH¸BŒ™yEêfÛ ª¾Õ~žÛUNß2IMAW$g'»œŒyäs¨ê;䲿…ñÉF�K(žÝºÓKMLã¶9%´É61ŸÚH@÷þ§å+cOhZÓ§]<‹¼£‡oeœ�ä¡›w¦Û~§pÓÛêî›rŸ½ÔXú6>d0Ï9þ>5>>³ÛD¹·T°†°a1ö[Ǽ~ ¬ Óª]Íf–Ó]BÊÁ¤§šÞ}'”ÁŠ9}@‡ñíõט`~&{±F“µÁü�½Gðõ6᳂<üJÒ‹ÃÜ×;á¶À+$©9ìŒSG#1ÎÀh×>=ÿñô,g ¤÷^w‚Àv•‹~£øS£ü.ïÍ«A•›n¢lc¾+u<%N!¿jG¸ð~‡ßY\#�RªòïR~ËS�𪔙.m¹À÷äª]«ðï¾/õ2-«kÜkOi<˜£Ïçß*¯¿œëw‰ñZT[5…Îp¬êÔ†‰+=÷ðßÔ�¨�K¸¬”öêVæ5Ô­ÜÐG!úyÎ5K‡qª5�ùf| »Å8mjCç<>ËæÆéu$uqIW$¡»³ ñe?æÃHÙüñ�}GÆ8�#(û«'1ú£z‘²(;™â¹VŒóJ`Q�Çž}óªüᮾ*Ï¢–Ÿ§ãeÓ~Ÿ^ª¥ƒpõ^͵œãöÕžŸ ¿÷ˆ,GŸaúè¸î6»jtË»µ÷â¢àX*.µG†÷¨ïÄ×Fö¶ÔÙ••W«½6Þ•u˜§Ž:½v<’=ÊéòC"ŽåÎÈ£–/†xµjÕ jÒsbæAîpút©‚Ê�tò#ßî´vƒh5UŽÍ·pn 5KÐ[©=9檚[�<ÁØ­Ü®cLåñŒ�v5^“£MÉÚÄýã’ã¨S&Í»œ,xE­Üµ{yq¹ïòWT ƒTP³“ j}(é”üÃ,TL[ŽÔP˜ä�&Їƒ”mx¾äûÕJìSÜÌ¥Æo"m´{Ù3­êX©$’*‰šoÄÍ1§SˆÂzB%l†ýâYò¸öÎO´¹o~ŸY*ÝÑ ïö€�m™(V¹)®wJ¯^ÙLb�ÙE\Tå¥vg ;{8 �©#·QÔ` $_ÖÞªJ5�py Ï…¡Mﻢ{ä6 ÍÍ ïtî:ŠX*ªîszÒT³TT½C!cêI‚à·r¨£‡¤Êd²”5 À"Â4Ûu³ŽªàÊf¨Ì÷âLß1›Ò5Ý%º÷EÞßî}®ìî2wÔt ÷ø{ÛvZ‹½m^ö°íø¶œvÙ¡µÏ5Õx JËlÐÆü³(TóRÇb`€Ídëÿƒ×S k‚`Ëó:¬å ßñöÐtvöéWIê®W}çq½õ&ÛK0^ZÏ=¢•²œEOQSK­Te‘ÌU¦x•OÙ…câÍ7ÔÉ>SËš«ŒÃP5 �0/xï�yQ6Z³O{Ú�¹ëžšÙ}ŽË5òžªš/R3,T‹U+údp¦NÉA/pn@ ê~ΧgÜXY³ÎQi·t«ã㻥‡¯U—.ˆîªû¾Ä­±Úª¢¦Pg¥˜Òžû•e‰»‘•Y€#޹ï„ébi`²bÛÖÛ[GC¨°î]ŘŒ=|yvÒÂÏü·ž¡Riu®†’õSk¹ßí4Ï-kÓÒC^Â8Uc�€Ê·ÌÁ_$�ƒÛç�m–4�ÓêVK*¼S%®#ScÐ~S’’ý¸.õEE|Üu�¢J�Jª¤+�b¡›žùks†1½ i€ß+,záõ>k—y•`U÷ ®Õ;ÿF§Q­µ(¦S]Ëx¥Y‘aЬsÀ[«�ž¡Kx¿¤¬{f±™Gd¤S˔̎ß7ËÇ·Ÿ¦¥§Æª4]×å›™UÝÀØc§@Ÿ¨÷*ÓG7+4ZES…÷À £ÛŸ<ëj–:«©sñ‘ܪ;ƒ°:tß•µ;htf²›oÝo=Xèµ]eE4�Ui©º-÷q”0‰e‘ãPÓ Pò*�Kª‡$6¼ÿâ>9Äk86�71£vêO]p=åv|‚`(¶j¹¯'caIæ¥Ý(²ü<Þº;Q¼7~éèý»uÒ^^�­õתXëj©‹"«­;ºÈcY� ÏvN5›ñ?‹7G´ ÊßÒÅæ7;ýÖ‡áœ9ØcÛfÜÄÆÚ¦½õO-ÔñYvÕn–Àÿ�–‚¹nPˆ{ÝèÞ�ú�d`a–<å‚eŽäK€â|AØ`^犙¯®hÐ ¤ 3ÖÊ,^j–Ók2A�"ùn6›*ëyG¶¶¾ÈÚ•´7m½_w­«¹RMøk¬3IKÚ±dp®Ìf\ú ãW…qŒs«Ví\øk¤ÉÒF¾«+Â0�§O³ ’ã1Ê7�·Ýé­´÷Hnwйî¥"–‘QýE@² rcSƒÏŸm;xÆ4Ô`eWMÆ÷ðæ¡<7âX3E�_5² °Øz‹½Ršõ£zeŠŽÞìÜCâ E>Iîy%×°�4u·Š­K†QbÐ I¶³¾ëWÿ´Ûá¿á¢],¢ë7@úoA±ékw­‚Õm†×¸kªV²Šd­z€°ÏY2”"™q#»��…ø¥GâZÚîÌ./ò:,þ!ÿòÏìîrvñ^�þþÿ²"ãý—}ß=AèÇÀ­û{ÕôJß{¾Þo”ÖY®’ܤ²úõTÕÈÆoĉ]ÉrÝ轃·ŠqW‹>›ßòÄLͤlîÃhS¦ËàúÂãçögÁ¿ÆÇÁÞðêwÄ~Ù½ï]÷lÞQX!«®ÞUÖÉR—ýœ²Vý(*£Vk…OÎÀ±Éñ�g‰üEVŽFÑt<¶{€ô¿TØ>IÙ�Y&y»p ñ!èT©#ÐŒŒû6y×H ©ÊE–KO&;„¹÷-Œÿ×BuR�Râ'äv øÏœé' ºÉ#›¸Ü¶ÿ'BM²úÑÌ„$T>xÆ™¥"Ã+5ˆpDÅF|<ÿ=ôFˆí8^Ř€áÀþgH)óD¤°vcÁÊçïõÐfFhE-:"‚ñJ[ß /3dY2‰KĈøoÃJ£þdyi”ŸË8ì'ÇöLÆncßz±h¬Ý0ý¨¼C( =†…ïwÈC~˜çUMJÀþ›w•s²¤D‡z)µ­:)ORïU{»É!2R!¤ÀúÊ£>ù ôñ¡p®D<ÓÓìsðVUªãÐÙ§¤ü6ßÞPEMþÑ# 1î™yÇŒ�Ïð-Lb@2àPÕþ”‘òŸ2·?¦Ý&¾wMC]ÕúʘfNÊYªiç§�Ok"S÷c8ù•ý±œàé�ÆMòÇqŸ¯Ù OèH¶`}>…w_àâ—yRUÛëí;R’íM3…Œ\褧ôO—3S ’8ÂÇ•2øÁÆ{­K¦ãßšÌp§?_ÇÝz9èíEmFÞ¥˜¶ÝŽi´©mêõÆŠX‘NìÄQÆ™àö)økEªŠ{ß+Ô½ÙWAQÓ[EƒqÛÕ Ss^¯~ *©lÅøwŒ‚ùP½þ¦r[#�¦"W#¾-~+¶àÜ·»½‚Àhc…{Þéo¡¹¼Òg»ÒIë#tHÃ0î,ÎNHUùAÐ8 º‹//½Sé¦ÐmÓV÷ Nâ‡Öíˆ&㆙»A=°ÁPñ¦;°«ÜFÀz“7V©ou¯w½™ðùn–º_î~¥m‘OÚCºiÕ‹Ã'õ;›ÆcÜgÁ­Sã,Žr|mù]v¸f ç4ﺀڭŸV«¡«ÜÛëªtv�TÌ&[� ³²Œç·È™8áIÏ�SÅÔÆöyh´Oq�±ú«xJX1W=R@ï×dÿê§ÂÄ·mŠŽ°VÜYKKk¬ŠÜàÉã µšbr¼ï íŒc\í>Ä;|õ0̃¸�?ú�ßA ¥Àö9)âÜC~¹Õjmfö†Žñ%ÖÑÔJ×–Cľž�Ç< �ïþþZêÝ…ÌÜ¥‚;‰ÿܹFâƒ]™¯>qöû+MÑ}Ý<B¨>� j÷í-[°SÀô"·$ã�Ôë.Ž´ß-Ñ„z—~VŽ&»êÓœ×�õƒè>É«nYº�YV”ö¾·í{]Ophãydüð{h¼~CWñõ(†—T¥#×ëªÈáâ©|1ð}ôGïK/X­4¡oýDé¶èL²«QIQ4ªsŸÞ1Âëàj‡Äaïòé¹¾ƒêV—¡‰ ÿ2£Hóû&þŸõwì:ås6ͼTeGán–¯ˆó᛺S€rThxƕƄu�¨¿š“ƒbŸ@ê–-Ÿ¦žKïTº‘¿.SG=]¯cZ„‹€mÖx£É>ݱÃòžÄs¨¸.‹3ˆæ.SñÜMW�Láû":1ºúåþÐSÒm©j`®¨nå1íïÄ=»ìÜrF0WœùÑ|GC Ø—ÕñGáÕ1"¨e7IÄUgR+ š�l«EžfŒÇ+ÿ²‰LóýK–~ óò¨aªŸ » áÞOýR<•�‰Ù]ÍŠÍ�úas¯nPE ÔoL²¨P%‚>~ìÌ03ý5߇íÂóèxnX±ü«Šé²:%S±­ÂÉå¨Þ_„ VÒÃF´éPÀz‰LÌ�À�Ý ý†q®pcq­ÄœÁ½”ÛõLmý±>+ª?ü0-.í#þ“¨˜ð•PÓôòßýÝ$“ÐÖ ÃžÖ0ÄAàˆ¸cùvãï­·ã†hiÞ œ:ZIà™aØfNñ¾¦¦ËÞVà ü¹Ä>¥}v’ï÷à«RÂÕ#åi#¹vÚtVêº_ÂË<+F —ŠhÈ9ù¼áÇ#è9ñ¦Ã¸T—8iÖ}…66™fQ>zŽõ†â´ZoÕ²ÔK]q=îÒ;K+IÝ#ïv$w݉œçÀÔ�Î?HU^À÷I:ó”ÎÛ"І/ÃÝåªfb_Ó,…±ù±Î?×:Tê=ÇælE¶û&«E­»]'Çî·Á:Yðoøk¨º õÕ{ÏÄ=A0 p®–*j$à“Ø”̲#œ—÷Œë8Õź´e¼ÈýÕ8"ÃE§;zóÛ¯xŽœRVGX#3»u-cJR3_ÛÃ&°•í$êó°�qiå;žõ­†âOcOgté�£e'»o}á»è*­Û«qnÚsR�V(�ýóª##󈻻ü 44ðm¦FFûóVkqgÖµ`ÛÃ–Š´}•biYQ/®2y þ¾yÕÐúº@žõ‘ÙÑŸÔ|�U{R×fJ#w’b z^Åí>GwqþŸ]T&àGzg2ˆ+Œ÷&†·[mýŸŒ’zJ@ìTºc%“µ—éÈw5ãdÓæ¶�áBçÓm»¸7}Uë­7Ε–¤£Š™è«pv�ƒ+÷Å +ì~;{A-“ŒjX‘ó{‡Ôc*6¦_ºß‰7·N*Y$§øë¼ÀÃäÃî+cd{$Œ×�0cFËpâN½°óL’QìIÚSMñ•C^ÅÒnÚŠë,ÝÌ®Ò+ÄCHÌ?ï~ZrÔ(?ïZtä¤ïâáGIo¦øÙ†*HÜLНf`ýü°”1ËrA>äxãA•±¢˜º¹ Í�–COÔêÕ�ø®ÙUÃÁÛÖ‰rà›D2‹_Ì£sñfâ£}¹Û=T+ ›¬}-º;F²þ×fP7zçáŽ5 Ä¡pñ(#->CÓÞ¤GS]VöØšPòCþÉÑŠBÎ�½Þ™…È9¾Vº© ò ug\µÄÔ¥Ùbµ-iÃñ÷@×t�{Ýká„SônI•¥m�DÝÄ:¯h˜FçœqÈ'–þ¢«¿¼Çy*'á«�i¶{‚ù´¾w~Õ žm½&½<’I0{–ØYýþÐâ"ôÄÆER<èé>£LŠ„(Y†¬ÁjM'ºTί¢q¼µoWѯ†ºÑ…#ÔÙôÙÏý”ü¸ó«­â8È�\ù¹Fh8þ�žA2Ôô>9;Ѻð�4A€‰_l@½„ã'9ñþZã1/>¬�Ö|¥(:ö ðò�ÛtÓ_*>¾·EUPÈ”SÚ"¤D1’Ì…£^æWàøÇÆ€c1 çeRШ¬L;Ò9{%#½ú7A¼¨.ÐÛþ~6ÅUP�GWES –™›Ã®)£%†AýáùêCŒ®ãóºNò}ù¥ˆsmî…«Ø]%Ù´V >äø=è¥êâ("&²{¨žZ° !–F @fhØ• ñÆ�¼CmŸKj>ãE^�Mlv?¿]W)âÚ7íh¹„<Ú)XLkœ8¶^ãÌ+#ãx>E8Á±êe—ÓZK„2/%^Ý9íSòp>úަ<͈ï•nŸ$ÇØþØØ51CêTSÍÎktù?q•ƒüGfýB±þbÿB�©:|µ~ŠÅNÒH|·T¹'íÚ?ù}µ N%éÞ>êZ|4:ßb�®é]]$°EQl«‚iNPuTþÐq݃¡§Å› Û¼jš· ÊàÒ/Ü~éÚƒ¥ª²ç¶]*däöÅf¨gO¾;N¢©Å‰Ò<»C„ ÄøåoéU=l³GßÜ3²à�lÕ2Hsàzh½ÜèjqW4˜y€™œ1®q¦ÝØ%èz{LÏ5Ú;–¼÷`öíjöŸ Áý9j¸ò ‡�ÿSPÒÀ°ü¹Ið)Ο¥2Ô±ü&ÁÝ-!88´O'?@¼äþœj¿ø¶]^<œpÐtaò)Àt¶:XÏ÷¶Ó½ÛKV[^1ÇË¥s�q2ãò>G|ý³†�îdx(´û�=I!·-ZŒ( ̰*®;IóÿެÓâÖ}ùl vOé÷à«ê­µ’þÆÕU. Ùü>l nS­òôX8Š1²°6I«/RÈÅ{‡rö™dL"³1?¦³ø‡m=MýîUîÃËö•lU|>ÒGIG4±îಡe"•OØfÇŽAçì5�K�8¸én¥jÕà­¦‰ú·¢ž?Fçyî`O¥$ð1#è )þzÒ£Åã<%gâ8SF¥ C«¤ŠJÚ ;…} “³öy8Ïk|„+qÈÏÓS7ˆ·49Rw1 HS{OÃÍÚá@’ÿ°{’ >^a]N„®3ŽÇ*F0yíªŽâôÚ`­¨Ë�ey9ø°é�P)^²¶«Gp¶ËÝ5,wºÈ*R q©Òª pÎX/ q�EQà ÅY¢ÂHh\ç­éÏSåŒIK½¯¶…ì,ñTnúºis–¼ß0ÁýåÛœ�câ1Ôƒ Þ:YtønðÜß§Ç젖Ιõ"¦²zë=þ²¦¹x˜ny}b%˜äãÛPVÆQk~anåc ‚¨] 7ï÷öSÛ­—âtÙÌ:µ¿§°¸õ„n Þ‘ûy’\)#ìOÓÛX,Äà;RáLs�>‹ vÙäíIoyŽvÛð©­‘¾ç™ñtUªbuUÀ|ÜþöJö‘Çœë_úºQò š,3„ª].>ª'ré¶îŽ£W qV1»°çIùr#žqöÕŠ|B“¶ºŽ·ª7·¾Š=S±¯•.ªntSHIå\0n9ÁÆ~Ÿ]XÆOúGb›ŽÄÜqÔ´?�¢ F m,�¿<:cN1´ÎÞüÓ?öêG¿ ¶mûj¨’ªÅt»EX«ÛÝMS b?áÀ#9Çùj–#AÃ-@#¨ î \ÔÉž‰:†ß½•wëØtÏì¤�Ãp|�ÓüôôÙD] xD'­Ú‘ó:{ѶÉ:£K,u=ùèj¡#RVÉD1œV¾3ä`û�A‰8h" cU&¸€e„ƒÑ3nKÿVn,Ë|ßC¸ùµ7êÙòlÌ@çœ-I„ÂáóScGƒƒSë=Î>$ýÔfeöEŽg�Ñ�íª¯ŸµÉòqê`êZµ)Ìî9øOB…Bu'ò†®Û±CÄô;m©Ï¥Y*ƒôÁg9?a¨èâÉu‰ò�ùS?ˆo™ü¦!Go*Sýœ·zÇ÷dK„£ÿ� �×SšŽ×? ýЦ)¶?@¿üGïdáo¨½Ú‹E%ooi®e&w† -EY´ª\�:{*J.©NÀ�â˜ow+ÕkT5EÉe ÚJú¡³Ž \ãmO„¡M­¡AŒÄTq%Çß”ú¨-R–cÝ$Yú÷’u¬Á¬,J•9¬aIÃvÅÚÑ’?¦¥•YÄ•!’¾®zJ‹`¯¼t+ßÿùã'Ç騭3'Í•ž+€È3ö‘œa±©föFDJ-Wq>´ç³ÿ-na)$Ù,±•qU1øïΜ> EÑHK|ο4õeüç/Æ…Õ¦à$)N©¢ªÃR“$ÎÀ’ÙÏnØ({�´ÓÛmÕ•Û­µ2Á ’7ìípÁ²;Š‘ÝÏ×è4�@J‘� ‹„V½¨óCPöhÜÉ%\Ì’œòwGäF¤s¢À¦šs$z”E×oÚ/÷;�ⶪ»ñÕS4ó?®,Ç'ãè=€Bt ê5®%Çt ôûnœÜª#ƒÛ'ø®ˆ¼ÝEØ3Á=Qt–Ã\1úHó�¡©#'?OP¿E””ð­vŠWEðåIr bÜñÀÄ‘ûKf@ǾGç¨F8h¦4DÊžX¾ w–àž}»ºì3³¯p&7‰U~¬pp>úµN£�p:´˜ÛfW*ÿf/Ä44¦¢ á±É=‘Üj #<²©À÷äãSöOåê ÎÁ¹L§à+âºÛÞ´7ø/S|�tÐí!H*�£Šd©øaøÁ²U~îMßA+ar»Š­8àdI÷Ó}6«¿Õ _eøPþÐk£÷mÛ—Uk¼Žèw5`Ps�Þ2`é �tô@ü[†µ=J¸6ŸÀ¯ö¸î ßîý¡CÖ›�wûÎÈw¡ Žy%ç<“�ò3±-*ñL·5O™[7fþÈü¡ª«j^ì}øŠš…PJ ïÛRÈçÒ’´?·ÓÛt#Ù"’‹üe»T>«[÷ÁöÓí»Ô»wvt³â†½ú-×Á'¤2[´2HTŒ±<}CSH›Ô#^M_Uy¾ò”Zö UžµLŠ�N•x Ê�Bp02psô×�3þeM·Ò2½ØâÿÊaÃËÁN¶GRd ê%ÆD(pðUÖ¹ô‡oÎþ¤Åä Œø¹óΪãxp8@Mï°¿u­ç~jî—[ÓCõÜùY!E¿—fî Økªæ¨Š­˜=4ñˆ�À Š#íœç'p5(ÁbZȱæ=™åoÆ�÷ÌÁ:Gñ÷舿_ž}¹±jÂ5mDЧªa‘r2 ²å�>^F|cC‡Ã´U¨Ý„õ÷ëk$úäÒ¦E‰„oX.5”÷¡-—xUÖÀÁe0wHÓ§ø}.¤žÜyàüÀyçRðf´áêvŒƒéìªÜUΖdt�_Ï»'퇹è.{í¬uÖÛ„tÕ4«S5Ml=¥$ªz‹ØÎ›·¹íýibpÎfUiƒ:ïm­çªØÁâñ“�ƒy>çÍ)±o¶ø7æì¥¥½Ûèìó i”Alj{�-ò‘íŒscŠSs°ôÜám‡în{¯;ª8�n)íiï:"v ¡jk÷KE¾7e¾  OŒã ŽÔylV¿kW¦ñµY­ôˆ¶+ß©©o‘¤¥¢�£`�ÎÎÈ\‚¾{p9Ϊ÷.1ïÅlñ@ ïš„\n÷Yh©iÍ]mSa€Š–²9žìwv(ìú|}5¹…`Ì]ö…�ŒyŒ¼ºÊŽ½á ’Hࡎ»?4¥û›'•L)É_?MjR¤ òþV3ÞéË"ÜÔïfØã£«µOD [#’‹SQ[øˆ‡nq+Ú3çàŸ Õóè½pô~’ŠŸnT=-¦‚i*çic¡P‘¯Îs’ª«! Ü=Le±ž9Q²Vµ½0ИÄÒ¿{‹ï㤒æ?Æ5÷hÿ²w¹' Ÿp2ÙãÏ¥%NÅ�Ÿ@È2[)§y=¤eÍ�ŽOŠÞ¤Ýw¾ò«­¤ªµ^ö�D”–È©o&ã ¸³�’tŽ•ÔERUgv|g=ÅGu S€i¼BÒáì—€D�ÂÔÛu²µeºÔÔl[ŒÈ{‡÷Ä}­Lý̧€Bð9 �…ñ®YÁùø| ýÚu^‹†¢2f1ã·�ÂhÛó[èb¨¶m¢ËzsÓÎñ˜Ô=@ýª¬�€rF5��’ÉõŸ‹+øŒà8é?·¤«qîŸZ‚eµm õ3DÑ-ÐSƒÜÀv¯l¡B*ùùH#¸gœ‘®i”|—ÁOÛ_z.–­oòÀ ž¾�Ê‹´‹…UIÙ¬H=SŠW©Gˆ²òK§µ¹$Óç[µœØ†¸÷ïu�I®.š‚<ŠÎûv©’5npO®±´4ÝÈ?áŠÒž0[î~ø #!óæoçnè cçˆËö‘å>2¨w�j\+Ý+h-¬„÷ ‰éáìSîÌ„xÆ|ó­÷ö�tùý×9O!0áôû&›èÚmâÑw�IQèH³„çíVùFO‚?!¨pý¬É0|¾ÊÕwS�”ëïÅ<íX­v×"+MËÕ’Áidj&P9Dš wxòiÉq‘ì3�>TŒÂ㘰ŸB–3 9]grÔýÓMŽÓµªÁ[ý £o˜Ô2É4i‡^9ý˜Ï‘•9ÉçXºõ…é}ó⃠N™ÿx½ècétÙ¼¬Tõ4Qµªãg¯rîݱCPÇçæŒ$kŒy�à,b×ðDs�½ÏDøÚaÍùN¾öþŸNvUªá4¿ß\©Š�©§R¡�ÕDŽªÞGŸãçUx¾-Ì$¾ß`¯p\#\ïów�¾ŠÔÞ»"Þ–Ôš¦×=U2D�¡¿vÀc,½Øç�¯Ør¸\k³ÄÁ=Oà.»„4�;¾²V�n8v…¾½ée±ßà*s x{9Ç ±ªö�~|ûûëºÁœCÚ:^} ?…ÂãEº LûéûÛ) T ££ŠW±…b8B9à»LAóîñÐâ{reܶþáD`çü¤7ÞΊUW£é¥*ÜÓSTLO�ù”Œýóî8—…cH5YèaCÅp@¶YJÝ%QgoÁø¤§šÙUN…¼³Æøú~^?ñ×`1',‚¸waFxpRË?L)ëÊN³STÂx1öˆØôT'#ÇÍ÷Õ Ü`·åÝY§Â2®JŽ‘[)ìÑÉ•ªîUÅ\Œ9À œ}ˆàê˜â.7›w„ЉËûªÎ»¥Á%E{ÙïÓ�«P„`Ü““œ}<êOñŒÃ&`:ÏÜ-Z| ©ž[zû•§ÙSE$ñÔm«…-DN@Yã¾<ã°§n@#ßß�hÔÇ <ç÷•B�¼9„áé¾E±î•f�6¶æ—ÏÍ�öcë’Üÿ-Dì{CC³SSáä»(að„áÿšJÙá5T–ûÐ@Œ@je¼¯8S'qç骮âí,‰÷γÁDå>û¥An{ûE1޲žñÁàD û~cùkN†9�l´…‹ˆÀTkï>J s¶OJÌ­OPdÿŸ¸‘�¶@Õ¤ðë…—Z“‚`Ž–^쪺'¹ ãWbo  N1QOܽñ4Ã8ý›OÛ�Fæ�”Á·º!ã— 4S'Ðg�X �Çš|¢Š~äùf‰G‚¬£·êH÷ã:�ôš™+g¶ ‹¶auµH;ðûûò�ŸnA¬úm´º€Íl¥´ÍSºi*"šžžº‰&J XÜæ®#Ü{°ÀwñÚØ=¬§‘㕱 -¿Å—cÁðxg6Ày/Cµ¿[.õÓ™§¬§²Zé–”v¢ÓwöÆ>`HQÀú.OŽäk�«³æ3ÞVéÑ.ìœÑä¼ÊÿhCº7Ó ¥ú]­¹7méDjËrQæíI^ÍÚ²E41¿­LŠÀÐü2ºè¸ž mB EŒÚ<y²ÆâÿàÅ2ð ô“+L~·µÊ{ß«_¹*h©ä�c†šøÀ•…Ô¨Àò>Yó#Ö#ÁT”tKxKÅášœ9t4pK<ݪĂ̓*G÷¸ÁdgZ/©9K�‡¨“ÞåH÷レêä‚ó�²ÔÃْãûºV+•M–°Êw=²“é £¡1•Ý¡Eg+ã€pN�X¨Àà~O8þ¥Aðà §»ñ­”F¿ý²ª¾G ÝW9»‘QÐÚ*)r¹ä1pÒó�δðÝ›Y9G˜?K*8ÁP¾ >Dxs…}[í{†Ýh§“ñur׫DU±Š–xýûJá—8Á?/æªÓ«LÔS¬\ûñWªRp§2gnEt àׯ�BÚ»‡kØ­v¾šYí�Ö‰§y67÷ÔÈ[ä?4Ò=T†"ID�ÏË!ÆsÒЩ”�LwŸ`™> ”ÄR.´'”zô�Ýj¯›FÕu¨Žhh£ŽKWàžð”I"¶ò®ÃÁ#ïƒ+œVuVcPÆ32žJŸcŒãí§IyòþÓ�‹Ÿ…íƒýëµn»»mõ|U†‰väòÜ¢5"#ÕÁMU=‘>YJ߆hÕtù¢å ¹/ »æáQWºÍ}¦¶çY·evô-ôµ°RÄ’0A+`Ì�{Bã×e_Þ“$ë+æå‚}÷h¶8p9¢/Õ[T;}w^¬SSTÄ¥RIãC(>1ßIêöŽI"A�<ëÍñ˜Ìµ9ƒÎm¯'G¢õ ¹‚ß0åwlúª-Ÿ}ºn™)mrÜ®4©*ÄêŠ$CÇ( WTÈ$²Ÿ}YĽ¬¤ àO3K÷Xª8gÔul¬“áûÇªÚ ×Ó-±Iµ)ÖífºÅ¸%3UÍUWÙŽYgu�ÓÆ#ãæ�p´1§·9-ðÎÀO‰=cP»ìF v ¾f'Î�î0´âÓMýÛxJJ*Ì}þ”M-L/£ e„#’yÊ…>2<믬ZY$ëÏóÖd.:‹�Ú€@·½Œô°(¾¤íÝ¿%ª¸ÓXãæ5§2÷DÄ’¤hÉ÷88ÆG�AÂj¼»(>ôµÈ÷`¦âìhd»_}'ðµú– –Xíu´µŒhJSÈ1ŒãÕ\Ë$�mâK‡êw‹zÏá×lãTÕy–ñ¡i/wê2‡²8ëe‡¼84‰{WÎ;A>úŠŽ]À#¤ýI>öV+¹ÚÜ·ô�÷RŽšÐÍ,“‚öz©Y¹I’7•ÉÏÌ Æp~_±9ñïª]äCDøL}­ï¢¿Á©Ì“|¬cÝ”¨h(ë⥦y¬ìYä-øÉ£vry?Ý>ï÷\>©so}–ŽôüJ˜k­o1VÅÛû¾¯ÑŠ…÷ez°†›Ñ§> fÀúwyÇætKL~¨Æÿ+"á”ï•’GH²ýÔ-©}¶5Dð½:0v“×2È$÷æN÷Üg>ÿC¨øf-Ž/Óíb¤â˜w7Ùú¦“m–D·Ei¾_,Lî¿ pDi ÚÅQ†@á[Æ‹ŠÕÔ–‡wƒžvº—„#®ÿÆ�êÖÜ[Róo¶Î•»‚†åQ*ãÖø„‰‘ʼ��Ì<ýpuÉ3ǼC`wŸ¤y׿Q´ÿViè>¿[¨»šÝWc¸Uzû¾¸’0P4 :�žÂGp}ˆë®ÁVkÛf_Ã^|þ«ŽÇ4ÒyÌóïe0Ú;_wVÓ… _«#s‡4wÙwœÌy öÏœUÆâ)5Ù]½£í²Ÿ‡ªá™»òqŸ[¨¾ð°ÖÀÕrÑU^çœw0åÉÉýòàsàä}ÕÞ‰i:=ò�wT8•' ŤÈ×÷Uu4sEPó\)j¤ín † 2ÿí>oÓßøc[Õ\ܰÃûx.v“]˜—ÿ>7RÔg­’œA=ý‚ʪHŒŒG$DãØc#?®³é.à=ø«ÕŒ‹O¿kR5ÄÚV�íFÒŠf¨ôÕ±ã#¹Oo'†ú•În³§�¾ýVM0EB`ÁðNRlùo´3A=-²Ùïz­w™Ÿ�Ió!ö÷ÇŽ}³’üY¦ìÀ“áõÑuØ|>ve"|~UM¸¶ÌTS~+åÁf6HnRJs‚ 3ù{Ÿa­&*LåJž/ 3y’Ò¶ô��ºÖ¨àG ÅýGêÊy8ÀÎyÔ˜œFaòÛ¬(0ÔÃzŽ…|Üv«cH•ÕÔÔVêVVÏ9žxÕJòÜ�$ŽyN8:� Qó•„“ÝÞ§Å5€K€¾ê«¹ÓÓ §Zj‡–(—´™âC†?b1œkv…G\\õ\î! ¼ÆÊ¨º¬ÈõqUä“�MT�õöÖå>dBÁªcª�I(ŽiLD‚Ny>~ükV›„ Yn²M* Ǽ�?süµ-·HÒëXÙcê«`@Ñ·T%Ò•Šç*�ì9ÎB÷å 0ˆ?’ŸØ7uÂÜ««¦x¤�û% �ÏTëPk„•v†%Ͱ[QÒ[Åö[©–…]ã2#4aÈ2{”’û�·ß@Ú «³‰/@_]ë}�zX)­ßÝt‰A1¸G;×~®«*áÖ”Ó",�ûÒpÈøîb´7ŽR¦ÖælΞÏzî¸%JŽù]½jÚºãºi¶ERPnzj•�y.ÓE$®{r½Í*…TÁ€ÎpFNx×b\BÞìÛ›7åy þÔ-ïº+ú�¸gƒ¥öéï•ùžk…45‹…£p„¯á* ˜Êðò"”fù;OwwUð˜—]ÐÒÛ÷é~Z÷,ˆœæ²Ùžÿ·Ýs‡¤žíMÔ7~—\·E­@Y=9c€9 4RdH€ŽÀúëÓ\dÈ^GŠ:“²Ù^�n|}SÚ“²“tú8®QÇG'ª¦(0ýÆYönÜ3w&Xdx"¶)ðÃVn)ã!´¯fÝéü=áC-E¾5Šš¸Œò…_Üj¨P‰QT¨ ò¶|k •[I\ãš¾$ý<¹¨™nvûa1jÇt•q಻‚2û@f¨©´EŒ/ç¿5¦È”Ó==*L¡û¦FG$“ت¼wy$yç:ãÜ@ªù¹îåº÷†^“0½·V–ÿ[nÝÕPÔÜîL”n#Xåez~;ƒÈcq�r£Çœð5B¾? �'¥ú]ë_ ˆÉ‰‚fÜÿ=ÉŽk¥DtW¸joõSHXµ4ÿ‡bÇꊭڨ0GxçŒØÚ\ÒÖ÷‹y�J�Ø‚àç_cöeÂõ ]ƒmE-ÊëKSI(‘§‘¿idgç|�¹vvƒŸ}’£ä 윿5& 27÷öOÛûsRî&°ÔÛ÷47(â+’F¹·¼È@!‰ýÜy8è¸U>É�k›6ý€úéºn*ñZ«^Ó ýµü';5Î�7Ls[w]Ö¥a„%-,m"ÅPI%ƒ�Øc‚[Ï’G'UêSq£ó4u6‘è=ù+øG´×³É�¯œþPv;Žò£Ü7[¦ß{mEÉfé-$Ýò°bB»Æéœs–î Ç�³‹M±Òl~Äñê«aÅQ]ÏlLéô…–Õ»núÙ.4O¸é㦕˜É÷[¼fQÿ«“Õ˜°}ðG�§Æµ�­ùg•ÿmO% ¼½Ã7¤ùßöS{ªáMs¤¸×íŽèûŒb5Lw6É`Àà‚{AîËÄÓ ÊX ùÏíç-L%RKšè·¾·ún¤�;½ÇJ×*{¥¥,'öu0ÒÓ7©ìÁ» ž|áŽ98Á ê+Hå¤uÚOà#á5à–¼iÝö%1Û7jÒO}†Ýº§˜T,Œ°Áh£Œ2/jŽlñΤÄÐÌ\Ûs}!¸Á®×–ße¬;¾ó¹ªo­~Ù¤îl÷RPÄ®ÿsÚO>5ØðêTò‰·2}μÕ7}•¡ÑKäÑîŠ J™$¼K+aàJ0ëžïÞ!X|r?ùþëÚ÷ÀUÃsÿæðÚ÷%�dY¦Š8ˆŽÍéá8ÏkY¢p8¤†QØ  uÔæ/ªâž.·ær mÜ„Œ;{³ú:4+Êçö¼ï�ã¶÷L—ûvüÜÖ(ꢊ)wÎÕø�CP•ÑIMCH®€ó~$€v᳦&‘6+Èæâß—'¼Èïe‹oÑ7Ì‘Ã-[åyùƒJÅ”pr •\ìuC¥ià_ó(¤êêÚ-ÆÞ�ÛV<ÿÚ&¬šDhÀð.A#ãøë‡Å`³»3�ŸO)^�…Dz'ÄûúµuJÓ.棞ŽÅo©Uy%|9îà–�±8ÿ‹ÛÎе(‘˜Ìsþ=ÙE‡­š»KZ ž]}ße±»×âlÔíÙ¨­ûqÜkÞµ S4ŒÈ,{‡#Ûóç�pøNTUÎ];ú]wؾ-G³ÊÐdûß½i}£~\iw fÓº«-²HàF %Ic¸ÏÛÈÆ8×q‰¤×ÓÉ"Fë„Á¸Ó«šätþ×õ,WZP7MÖÙJ€ØRM4ÑûüÏ“Ÿo>-dð¬W~©>Cß’ÓâøÒæIlU¯¶î¢=4çÒ²ÝR2{Uå£�„?ò€ËÈüõ½‰Ãgn£ÍsXÀ}õ[ „[ì¼f'1çæžöOQ7q ÊÊ_ÙéÎ9Æä/�À?ŸÞŸÁÓ-— òW¸n1ä€,;ŠO~õ6{­BGuŒÜëTfW–”?çË\ó“ü4¸V %†'Ã쟋bóÀx’5Ý5mõ@W–É*æ8=�Â0¿e €9úcíÆŸ‰31ùŒz á�-oÈ'ßE–ê¾Ö@$kœ4öÒà3%8v�þì­ƒúvùÏ4Ø*AĆ^70¤âÑ5-çîÈ}›¸ÝSÙLý�·y`L?óÜIþ^ÙÔJ˜{cß–ýªÏ ¬æ;å:ô÷îêð¯Þ3XÜTÏp¥ã´ÄÓB˜} *À}†1ïç\ômí-=?uÚ a4àŸQû-PÜ—HMÐ=;F�›°úµaËñã*Xã킺ì"C¾‡ö\†>¤¼ïê§6 ÉsŽ�)ÒX$€œGèÞˆDÆ3�UN8ûxöΨâpÌ.“ÿãû•6àØúÁ¾7½}RFµRÑÜ$D1ÄÔÒ¹8óÈ%†}�¿¹Ã0blÞà~¡Äøƒœ>kò�ÝT´бjV¦ž˜·ïåÄŒ9òsäë¤ÄáÚ@ŸÂæðØ—f±�Tö*îS¹¦¤¾+ÝÃ*$çóó�ÏÉúê›XÐeÌWQÄ¥4ñï5ü?fë¬fÊD®�¿l¨9•ΤYf@º£O>x%JmæøbšK…ê¦Ycå;Þ0Ióò�L–üá¬l@düƒëù]VÔ‰q>Ÿ…Ü­-RKøú›ùbÝ­‰qôà{ÿ=^Á�2�è©b‰7$¨…žÛO-IXÎá%HǦ9ÙÉ÷óü¾º¿Š« ÙQÂѯ)ßrX$« d¤ÿh*dAê*×úqáû¹ÈîÏ�ŒžsôñªØ<^J’ð<¯o%6?ž”0™ÚUup¥¹,³ˆ`�æGîF<ûr Èþ:ÛeV9ÒÝ=óXUi=­‡*Îé&¤M ˜öP߯µiƒ,šÑ0¡-4¦fb'ë­›YåÚ•Š–µHSŽp¸Î¦�†9, Ê £Nˆ5Bã{¥âhÎ{dÃ}�çøé‰Oe"¶³$ˆq£ŽÇùê7@*j\ÖÂtòd4ý¶êˆ»!â,Çúÿ–€@ÑN$ì»Íð¹á·nZ=ã‡2*K=4Aâ/Ê’Hj£`“cç¹N�q¹Å¶29~˽øhKÕu£ª·Ù6M¶žËb¨²GLÝôµvò®þrÉ1r¢0(Ç ¯\«9*ëvÄ’ªvw=Ôäò^d î~ÞþøêælUŠl‘uüí–²FŠ™å�]VPA.N>¸³ƒõãYý˜Ì`j°I�'~iúß¹¤‚ª¢Yš†D?8�deôŸþ0¨8úü¸ýuJ®å³ï¿î¯ÒÄÁ%ÑýÙ(nUäÈ�ÑÑF’–VqÎÀŸg8$ž=óç9Óµ‚D“m¶òý’5l7÷îVp½A‚‚–uD‘¹pf߸KxÇ8ËF÷\âu÷¶É©ƒ”….½ÜëoD4¾„0†>”tÝý¤ðNNœÿ]VÁÍ'ÌMµSâÝÚ€H˜èšèï÷+|óJ•m+¨Plq)n1“‚p¸/<œd᪑•Ü]ÉGîW;Èyæ’KdFFÌ�-[ª¿9ù•£{{{~Z¶à ¿�ú̪u\ö’M§[”ç·oU”3ÌcªÛÕAÀ�¥ü[³¨0=ü�|}µ.�#B' óë�Ûê� Š 6G—ï)ÒϸîðRÉ÷¨žvùJzoPÀ��GxUSϼ}G†½&�‡pü«zÏ‹øŸÇ¢¦w•|Ò\¥©ª«îv`~`¨?�'ô?}t¼6ŸÉ.cмö™‰O»ý¾óG;VÔG"°a �Æ çÝÔðå¨8“êDmËððºÑT:~Þ«e·§Q¥­þíjš«µK÷ ‡×Öâ“´(p�°Oãàk”á¸Ë€ÓM¢êøŸ&3w›žíµèªû§PLTkÜØÉ´í¦qìC’y÷ gï­ü61u…‰Ç|‘›ÐÛ×ê£ðuybz:»Íôð]ŠŸÈû}¼êóp#4´ 0ãœæå$B�m΢Çg¥�(·*D{›ÿE¤ýòF2Ì c÷�§‰Á¾Kg¿ø*îN3Gw±÷IËÔx)ªgin2ÎîAõf�yç' ÞÅAÇÛóÕÃ…Ì�~AQf##�õëû¡†á¦©�'©½ËM 7{Ç Èì@÷$?—ÓV¨Ò-°ÁAZ°&I…jX·‚¡a¶ÐÕ_®5“Q Öv9cãê 9'(ûq¢ì*f·IõFüM>ÎæG~ž  ¶KûöÇO¹mÖ: ç¸GM ÷±SMøYU;Õ‚¤´ª~nÅfyi‘ß¡JƒÉÚ{ä²*biÁ×Â>ÿ²÷/ðG¸hvÞÕ’†²÷c¸OS3´‰JmñÅ Ê‘øH#ïʪ|Ä/Ôç÷޳�L®ƒ^/�ÒÛš¢hjÖ6F=ѼJ@ñÞËœŒŸÈÆ�2óEý§<¶ïKFè®]ËGAbX¥é¦·­aΡ¦eïOQû@B¤€ d¸À9Fu^5ú—v·l­Ï{´RQ§”ÄÍ=5:ÉÚ̧ö0I•.̤�°ñRÒJ§žù_>Oœc�:曆k]b}躓ˆqm¢6Z÷$»ž²ã3¤öéUeá©�WÆ0}¼ùÖûšÀѬûÙsyž_=õJVÝ®ôд,‰HçÍX™äÎxîwà¬ê*Mn£éo¢*Õ”ƒUZ×î‹�4Ìȵ%@ÇsIP>˜ù³úë[°i Vx6LU[’ëU:Ì*kjj²¦C±þc}‡M¤ù´Iï'©R+fèÝtKéÓT=¦?Š¿LŽr˜ÆOŒÿ–uGB™2í{¥hajÔ Ê-ïß_�~éÝm+ ëÁ­“¹ë’[ìÅ@xúãóÒ§A†íl{ꊽgÿy”­³qßbŽC ZGù�c�Âçî�”ç僧tZë>úÏÛ¹>£Æ‡ß¢g»^ëê¯Q ÷?”žeb `«�?ÏÇ¶Ž…‹ y%Z¹77AZ.æÖ}k�†*˜‡iÈÈWôîóàãùjÓåc”ØGd»Ûï¹Mgê E1§¦Û·'$1‰"qõÈd°ýñ¬Wp×w�_eoŽ" 4ú*Úãv«z�WlÎŒy4ª}Ï�á÷Ö­,gÉcâ+™Ï¢s¡šëPѺíSQTAíq LOß?AöãóÕw¶˜�o÷ 69îþËùý’7¹·;¥ \LÈ'GÙOùcS`™GZd(qN«£Â‡I5<’•š’)P”KÚF~à`ãòÖ»Z豃ÑdÈs®,Ÿè«©Sç‚Ón�€²Ké�Ï÷‰ý9Õ'Qq¹q÷à´Qú)µ&ꮆ˜Fµ0¤yífä}¹ qÀÿÃOR€‰…R™{_bŠ;æ¤Ã-$qÌIcÝßQÜ\{çÀýxñïªoÀIv[´1¤ °¢u÷Ë•Zº8Hà Œ%Dƒ'ô8'òÕ¬=´Ìý? õ\DE”mn•À‡Žà)πߋ|�Ðþš´)�Ç U)Ô#Tî²Õ=&±d‘�xq#Œs‘çòñª†æ!Z[s*1r§ª@í%Áã'Ï©!çòëW FÁdbØ[©U�Þ�ÊÔ-Cx,Ïæ5½F¦ë�¬/¨Õ�ÚNڼ؋ê¨ÊÀTªŸÝœþîœÊ|Ö_šd9ùê1¢l›¤G5š3ä0 =Ï×NJWNôrÍ”Eï)Ÿn?ÏQ8�T�»6Z\ DÀ¬Ì;[ƒƒŸ§þ: Ž‹…=fu¾ÚëU¸-KIo¨«-ò$4R §˜4]§ÉíÉðx#…ø„ýüüazÃÄ ÓÆØ£ÜvÍ¢²Ýíµ·%¦s5=] · Ä¡äR;qŽI>r8Bº×™=WŸÏ�zÊ:]͸(*�]ªV”òWµ JÁRž±8%x8ùI5Õü<ÒH"ñÒ Ž;å#Aß ’–‹U;TL´ïF!ö�pŽqœŸñ„Æ<{có×§Sy1ø…ä˜Á?™[#Ñ'‚—}Y꣢·½TÞž2¬qÉfhˆ÷ã?¦£Åd,%yûOÕ%àT“/uL†;š� #ìÄqúiéÓ"ÇФꠙû" ¬©ž?ÃÓÖNðÿ�4Lœ{äxþ¸ÔD — £k‰)¥mò÷3=ºif I÷œŸ¾uÉÏg€î�cb©°>$O-×K�©S!0cÑF½k׫Ü-ù¦7bSÇ/Íõg%TñôÖUP ™Ÿ?¢Õ ç~˜·HOrn È¡¦Ü·BBçôðd ynÂãè~¼}2{&æ2ïµÚ»/éü¨÷•ÜL¦[l±HN;QjŽ9,xãþº½ˆºÌ/ É·šo­J©„¾…º�»óêwvßsÚÜ'œ“õñ©é< £¬ M‰lžd&D¥�A 1�ù€ÁmOQíÇNåL4»T²Û�‘iÒ;gx/deŽ~ä{pyÕnÖ×VNJœY­UÑ H)¤�Ôcö1¯rsÏùþŸmgb&çU¥†¦rÄy&û¥»öèk"ˆJí’j;Â÷ç“ÆëÆŠ‹ˆý'É=V‰ù½SAGOø‘I-#¸íÉüÁ¤qôOsˆù‰÷꣦À?L{ôQ{„—×WcZ‹Gç(áGÛ éŸmOLSÒ/Ü¢v}A²ÂÍ`ÜU�¤Ž®i#qÈJ¢†AœŽ¿åçQâkÒoÊEû‚±ƒ¢ópuê§5-¿zµ d3z}ý°Ty>A |ßÃÛXŸâÔ�ƒÜ·ªDɽWW-žôÉøª¤“,£·¸à€§œŸçƵ(cÃÀÈ=N#”œÊ[·¶�Ö½} fï*¡™Ò¥Õ<`ddùöóüµK‹kL»ì¤Ãáû7ßÝ}«Ú÷(Ý£†¢Zèí|UÊägY°<MKu"<û!«…#ôßÕD”þ5ÅŽ11i�°s“ãúyÖ«\rÚz 2>kj¤Knž0¤ÓV§†“ çå>sÈÎ=°~š¦×‚~Sïš´öÚê[Ih¢©§§üTM,„0LŸÅGœÿ–¤Ìÿí›xªYÙš øü¥)6� ýä¶›l¥™ F;˜yæ*@ú}r5^¶%× “ï¹ká¨>hL÷½‘kÿÒ¶ÈYÌÇÏž{°÷_<�ãn]=”XŒu1ïÞŠ%G´íòTSG$“ÒLGpïd¯¹U'¸pTóÆWëbž`$xÿ �;KƒO¿}S¥NňJ ë=4$0Ž HÍê88„nG>F†ª7F—éëÉZ~»ÎeU÷Ë= 3OsB…H °füÁ'ž-n`ë¸�2¹Üu‰*êém�S¹�cð÷ ÿ¦¶è½`Wf§E–%O›ç�iÍ¡PÐ~š`|§}?E Hö‘íÏúú�;B¢"8næÇüÜéæf”÷B#WSþïÇïs yÜ)iòWŽÊŠÝQ=1ªQéx*±d·Û9Ôfêv: ÂíÁ�ÏcÕnkVزíǨ¹NŠ+ŒÝ®rq(ï¹*nÐH>3®'�ažÖæqôÛö]ïÃØ¦;åëÕVÖÛ==¶tþÓuÜÛüìù dŽŽ’j‡¯h8nÕv�ÈoÝ çéÇZÝ&ë¯í]?(^`ÿ´ ­—÷%æÌ»]+¬rTJRâÒè®á#ÔÌÎÄŒ‰[°|¹ s�wß pênùƒŽn[ý>’¹/ˆ±µÜ¥¶æ´3cU[î #ŸÇ•»•'BÌêFr{0?¦»ç^e^¦c+cöò±míÝ`ŠãCMF†tF•¢3±Ï J�NÿäHÔXš2ÈY˜šY‚ôÓÒ;þ̧ٶ‰ †“rÖ”Rh¤Y%©o—=±’ì¿—h8ƹ†Fh\µmn··b5 ómÑ\¡Ùj$“žÙ)LŽÜ 3öò¬A+aô±—˜ Íܺ}×ó ŽÇkrY¥–EðJÉòÿ×ôÓº«†ËÑÆ›¢ã³Y8$ãÏíHcüôϪýO¿E;p´õ_ZÑl`Õ—ËJÅ¿†�.˜(އO©Y-Ž’D( ÅÈ{ˆí§í]®¡7ôÍ_eÚÁcS Ô†?~Ä8þ$ŸÈè[‰¾‰�‚@NtÛzxÕJUS@¸ðËüÿ{PTÅ7q>úª¹ObfrmÞãÛ5⊷÷AþaÎIþ:1ˆq'+S$êï~hø6ë4qúÕ.¨x!¢$7æ'Ÿ¸Æ¢~&æˆéàí'D,–*ˆYb�k‘=û!| ûÕÇé¤Úó Á>ú¦8x0=÷¤l×HË$Uw>ÌžßÙ8ý‰>M1-�èœa ¸'Õ9½šçN;f¹U—%Ê~¤–ÏòÐS­M×hR¿öjLûê£ÓÑ»LV¢åTWØ~þGä8ÕÖ8ÇÊß~«2«`ÝÖS]·j‰¤S T¨Ã<“G “õ=ÄãÇÓ9Ƴñu}ÜýŽ�ø ©±Ê”âZÛêLÌ"† �«÷lÇ$ãõÖu™ÊÆú{õZU)>wzûôL²SÅ"+�Gww‡s‘÷< hÑwö,Úå Îdão†±d�”N=‹ ãõÇ·¹úèÜѺ®]}l§–Û$utÈjêíóÓ‘•X£!XûüÄðOù{j›Éi¾¾ú«Ôéæ'mÙÉô#�³žÜ–oÌœŽ=¾Ú¶×˜h«vM&Y¾×µš…Y!’x òTŒ8Ï·“Î¥§P‘aUjm Õ¿dŽ+U¾�ýjŠt2*£Â€)cû¨C8P8n{sǾ™µ$ÃEýú)_L5¹œl» ð=žçþ‹|l뮂åKsTWÜŒoøF–bÕ…‡b‰½1Ú¡€™ìÕ Ù¹!câb+ÜÂä•·=­zRï ‹|Œ’SV é�4˜Â;*ˇeeíí$ ëI§šÌ+h÷5ÿÜòµ-¶ž^ ;Ãê2�ÇÈ[œ†ýtI—¾4ªm›bÕ_¹wfÈ¿ßÞoþ�¦ºWß¡¡J¥(cy ´x‘{°Hä60ÍØ JJò ñ»ºEvÝ÷}³µ,�RÚé™-öûÕÂhUhâ•뿱¡F`ޚÞþÕØ‹ª˜—åi'Eo O3€ �×=« q,4µXiV(¥”Ut~Ð彊p>b@#'Œë—­]…ß.¿_E×Ñ¢ð �/m½ú&jM³jŽH¤’ñm¤‡9ïžh»@Àù�sàçÏ œj�j®Ò =ý£ÞŠõ*L$Ì�›Õ[ìµ7 z{œq(…ÛÒŸ{E ÝÇ ’ ñŽq¬@Ú�pvSç?�ªèCé–Æhð�åQ·y$–ë$vÕqß,‰éá²@'€|Ž2Añç[ q©÷Xh¾cnãø@Ü6’5â…êÚ�2~Éä�ÑC ÔdcœiéV2Dºiçï’Uè‚ÌÀ�§ÙE`Û’fŸûÎGä´ª†Lûß8ã<êÓë ‹,út�3™a%Ú¥0‘& pTHç‘û¹úŸËAóžŠL´Ä)^Ùk]T¤-²�Ìò~(I"Ƹà’Xd cÏõΨã)8jï/ÂÐÁ¹®0ž‰ÒÿWEM)élòñÞ°Fžš g$~XÏ$s¨0¬q7žžãO%cQ |±éü$výòÙ$¦?îºZjF)ÞìŒ)8 NX~^üã�,NÃ]oïEÒm`cñ¥ý7N·iàŠ�¦†£û¾~×h±Ydžå+�=°A#ž~º†�#¡¾ÑöñSÕ­:ýí?EÛÓÚ½B\d–àYf_N`ÑñƒÞï„ÎHÇrœŒcœ ñÔ[òÛÌ_Ýù&áØ†f—õß·š·/4òOIÙA5Šž6Qß$q�À„3ˆ”�|`±Uù�:åá›çÓï¸y]uî'É òî÷u¯—44ÕŠô¦*”õI(HHÇŽH~¤p5ÐP9„y®sÈ’/}l§jðíò\Ù®N®$ÙM•9Yp[ŽAàÈÀSÄÒkf¼}vSàë8ºþÚóAÕE5MÖãl©Y ï�ÓÒúŽ£æÁb{{x_ð¶56 †°DÖ^~¿{AŒkÈ/y‘Êñéé*�¥�z÷‹ˆe Ñ«³wž=½ÀÌ{k¡«%Ÿ,ÍS?=ÁufGmèR³ñQÔSD㕦' ÷3—?áò|ë¶|ë×—ªÚ©H†É:tõåÑGxš–– ¸¢�˜²ƒ lI€ràà€ÐóƵ2´€"{¾÷¸:wê°Z@%ÀÄóß»ØS+MÃjAMøZºŠËn{âq#HW• Ê‹•ÆpŽ�®²1 ¨N`'^Ÿs~dX®£ úmnG[ïâ"Ý ­÷U¦‚fž¶'¨—%DeÛÓ…�€ª½ç»óñŸ®x¹�ªZCû÷éè«q ŒÍü±$TuÂz¦‚óÌͶÿå%ÛÁÉårÛέc-µ½|›ªX6Òn®í}³¥$”4PÇB#&œ÷ÄÊF;‚w°CÚ?|Œç8Ç�fS¢òs:ß_ òŸÊÔ­Y�l7ºß^�úª²÷#±—ÒªYâÌŠLŽêx÷ œ`{c[˜B56ŸO~kŸÆµÆÃAï½TWêzªpìÐÔÁñ‘Œ�§òã:èð•@�~ù®gAÌ0DJ­jðî|ÌÞy9:Ói:›Þ›ZB0s�%&m’M'¶ 8úèÔed’öòP1ÏñÓ^:¥Ð' yÈå\¯éãM©’ŒJÙÙµ¾…]+K$’S_H†~ÌòBž3ÏÔ[XÜ)Xà ×VþzƒÒú­Ó¥¬V×z¨£Š9ªîµô©M#÷÷,ô´¸ŒEP¸ÁFwå‡ €uËqš»2ìÒÙäIÓBcNK¶à˜Šã,ñ[/OÛ+©•¶Þ‘RS­âé[4”ÑC(I#jx @Сúµ {P2*3¸l½ºóLjyY÷ûÊîÚÙW><él—]ÁSY¶éìWÔòKæ}µ­¨ sW &"1•ôÒ0Ãç ½Å³Û|0÷Ikæ;ͶÐ~{¬¹OˆØ–D÷}ÏásnÅÝh¹Ô~Ú¯oÔ÷äŽX’5 �@ìÇËœó€r| kФºó@!ÄyôÖãW6ðµMAIOIPzV%K$òŒAe<Œ`¯9ãœj@$AYx¨ ºï?@ŽèºÛ¡¦ƒoÓn‹eJ¤f˜[%ÂýÀ:¿cÆ\€Àüýʼ0ÉùuθFšûô\Õr3-ñ°\:µKnTµSlk]v1*âA*ƒÚ‰@RB€T‚ŸÞ&_ÀQ6© ùøÇT©!ÇY±ö9Ñ�Jõfº 'Sò3'z)í*xü»xús¨ÚËÁV›µ~BU¥™X1 ž,Ÿ¯¾�7½8tØ•˜­§eµ_'?1¤~žþ8Æ–Wo_$‹Û¥þˆ�Å4ë”M'`>™#+’}¿fs¤Ð;ýóNâLïÑ ÿge%¢…{¾VÍ0Îå8ÀjG8Ʊâ�kwˆå’�;`V2Ÿ)ìçž[#ßÀöýu‹‰&-¯¿eH2Ø%㬙’Y"ž .{²¯’Gœ~š‰ÌhG¿…Cx)Ö ÖNé$w©GsÚÉϾIùûÿž…Ôÿ´@>jvT‹ºãÅ;Á-eg­ÛM]P{K¸XØ g’qÎŒ9Ujån¤z+L/&@%#5K-2GUKOO’£º@ŽÀóÎrqç9ÔÍ`ÎKLÏ| 5nWˆaCêjb’D@C1àáˆÄŽ?Ž´èXtXÕ]1•L, %4ј¨©¤eáÝä\¡þ ¿óÕcšD’{‚¿‚iiˆº�WMNµ9žž´©Pªxù0îòÏ#ùë?NXÿu¡X34¸[ß-~Èp�R^Ê#$DBΤvý;sãíŸ:½Ù´Úcß=UÐLHESÜkÁTŽ*z|]áqü†ƒ²lÉ$úyj“^@€#½N­·›ÊÁ"-ÕàvŒ�ÙîŽ>¯ž}¹÷Õz”˜M†žö_U+q/Œ³´¹\Kú pwʳÈ^ ¹¼ò¡È#\ãSµŒ7p¸=>°¡}WÛ}T‚ŠóP°­ )ËŽc¡�T9–ã>Ç<êÝ15üÕzŽ1–Þ^ϪœÓWRȵ3ÅMå?vDõ �ç$÷ƒ’óõ&“lß�c»]ÂgÀ=oßïm—J~ >·gP·–Ü}·Iö°ÑÏwžÛJoó<‘Ó²³GU«*ÎÂ!nåF å—³Z”)s ¾‹6½@Ñ{êJöoýŸ°Qm}œ»b³dレ\)Ú)*?½î7 �u¦©f1~¤c,@?s2J™Œ×¹�fA¡e7]8¿îÙ¬ÖùåŠá¶éÝ£ˆD÷ — VÊvôŠä¿hîÁÄä˜DÂeçóûB«6îûµÑî«—ÄOP(ìtHטöžë³¤5r¢z‘ÇTð[Ì�Çވ߼¬¬{×»ºEñmR¶ëÈ�Y¾º—¶ïÛã|Ag¸QìªYªª«®×}Çm©õ&P$©ª5²ú÷´ÐöANÕ•’"ä<�¦(¤´HW0mÂ}«×ÖÜ#ê*R¢HÁOE'õ•±ä°Æ@ñžyçÛ\¡�í=!vˆs¤ßI»·©Ž* ÁÓÕ•ìP`‘f¥‹€å(\xãAW D¶^tžvô>¿DT1Õs|¢Æ4�¬ˆÃÁM®ûŠÑOe¬‚éjJK²KNÍ#\d!wwFcý˜�±†ä€0FN°iQq©!ÒÓ6òÓ_§Ñt•ñ ì‹^Øp"ÿQ´ßϹk´õ‚iäZ„¬¸�¸QL ‚#>W»»ÜÇ'κ  7å�â=ùx.q¯’I%Þ$®ëN¶øêi£ª¦BÏtOM /qÁvÂ63ÈRH#‘ãQaÜK²Ÿ-ÿ>|ú¢ÄS†Kmôüy(…ES1‘Þy#õUÁíúsŒûàœjþ"Â"<–f›I‘²ç]R„N�,¿+€p¨ÃþQïŽ~Ã:‚�" ÅãÞªjµA)îÕqŽ=ëZ…a�Yc”)œdsŒ·8 e±’yÏq4äæ�y~kG SûAÓ˜MòÝcý¥W­h­d?*Kww?¼AbI ð3ì4B”œ·ß§�zÔ&¿¯‚"Ér™ZœË%ˆ»vSé @ÁËÂÄáx@áN3Œh±4Ø_¿Aæ–÷—@ O’*é¹}ZS5(¦ª‰Ü*ñ'©Œ÷Uª¿Dð�5 3³CíÝé®ýT•ñ#.f߾㮂<6H*[ò­JQ ¦³÷«¤uT¡¡æPÀV@và�Á>xÓÖ c´7�‰ŸÅúÝ´; ùO1ný'ì§7kÍ¢*÷„n TQ'iª«ª�¢�A ±îl’ß!úžpyÖRyšÒ'aºƒV›NRàcrL}oܪ{µê–ãS~ÓµIb̰©U„ŽâsÜN>\þ/ÏZØl;ØÒK#¿í‹ù,lF%•úïÑeÝÛl}ïQMY„fWÏ`§lpHPYŽ õtÕðÕ·Ôþß²ªm¦~Þ_DÿxÓªwPMGYÜÁÖ8‰•{pGÍó`FppsãR`°N'ç{÷×’ƒ‹h þê¤y$žŽ±#§ ¤9�œsܧÿ,~|ë€!Úø¬·I9�·‚qk�Â:XjMÁ$�$À¼lêy²Œ€2sŸ¡uCKÈu“Ô'&m@ë?Âx¥Ü÷´©F¥U+àa¤Œgž¨P3ãÏ·9ѾƒKyåSew‡ˆV6ã”ÓÍUq·Ú®×&@œW"ȱ©>SÓ=À€~`F0sÜ|â>€$ÜwñþWMB¼Œî‚{ùx~긯”’VNñÙ&¢¨¸zÅ_´HGibp0Ày9´°Xge�#§¿~Š–33ü­ƒ×íû¦ JêZš¸fw¸v¬`«2;—�n û }½µaôi=ÑT§U¤É'ê§U7ðÔ±KoX)X¢‡ùÀàÞò¼p0G?BAÖK0òï›ÞšóZïÄZYb«+�\SÎëpü©aÚª£*À9>}ò?ž|maå­†iæ°k5…ÑP_ÉFšŠÛr¥ž9¦¦�›&'@~Fúº~_L{yó«nªúd뺂� UZZë§î©ûå4Ô2ÀңǴ�ÆA>GÞÃÕkÛ!s˜ª&›²•.sÏòð5i¢Š¬’8/ãé§#d�°FT1ã‚tÎ�ó$É:'JJ”Vª¯ØiàB&º °lxa–�f2Ç?1 |�F[¸D ºè'Ãnð±Qß!¨»]:„�è+Q¥4È줕Hý7Ycn3òƒÆIÈàó|e�, Gó¿%Öð°:äúmê½ôÓ­6Çk§Š²÷`¶Û$ATQ—‚á\Œ{L…$ô�3RÞ˜W-ÜäuçØŒ3‹ˆ$Ÿ¥ºßíê½– +ŽŸ½MÛ;Îê¶Zsr°E”ôÕ³Û lÏÀ‘¤9 ÉBOÞìç#�vü‹²f2 ëô÷ê¸Ïˆ1 ˜zÂÑ EÊzúpƦÝT@ÁX;"ôÀÇÌc�lpqöíC¹^wUò¶g¤´Û�ûæ–垺y’ZßÂGé‘�šTŒ’¥Ô¨ {I¬¸ÕLM„mæ²±E eý×júC{6š+]]æ¾ã32Ã4-ø’® È‰F 2XÈÀd¾æ9{÷ªç«fA6†çÚòÙc¬‹tÚ6ªÔI%A¤§¶Fª 1%¸^Ö$äå>_×:®÷Á¸žò¡2z/1Õ÷cÁÆ OÍüun¶ÝËÔñ§Ýfî$.‡!iÉþý}4ÐÊ�Ï·T°–¡U–IýáhN}þšwA‹HL\Féhæ¸ –ë& € v9 ùqçóÓ?!7 Fº ùAú¬?^2߉ª�Böœ2FqçBê ‚Ð>©ÛUÛŸ¢"š¥VC+Nèݤ€[<ý {–€‰Ú|ÔŒ±”j\bŽQ+ŠfBÞ†îüóÏ?¯×UË „8¨Ðs�ux�È�ÑnÑÃÅC“dž*ª?_ó:š�2Ñ¿Ÿä”«¿3ŽXð€=õQ™åÁQè@«�ýÆÎu}—ßïöYO¶ÞüÓõ L°G/¢˜ ŽÙ;Ч¿ ûžN©Öp.!Z¢Ènhú©:ÕW$@äÁ…âU A\ñË ñí�ùj»ZÐ~ß°k:'ó÷A´õJÑ—žz‡ä,ž~þ5n‘nR4ñTêµä‚ã)Ö†áY½œ+7úc>‡ÇNö�‡3ƒ ©}ú¢)B'¬®ßýц#€r~¿q÷󪎧¹W[R4±>¡w¬�°�^xû¹ï«�Ê`øóŒ:˜´Ú>…DL‹§ú=Á\Š�BŒ~wU�aAÎ{[ƒƒç·ÛFÊR&~¿ºT�5òRÊóÓ(’¸ËKJ£µ¦2+€üÁ°r@O'�Õ�Ð-:žéUŽi˜õ•Ô_�߉N“tߨ{nÑÔz{�eŽªd©¤‚ÝYq¹Å|�¯5ã)á†Eh�Eó ”ú`0õ ê%¢ÃEB©r÷eðÓ¼z[tÚ{~ë±`¨Û‚¢©¥£þñ·Ö[–¥AŸöfs8.½²©š5WB ¼­à¨J½w� ¦ï¶V®ï[l½S×Ã,¨±XÚišEr�éafY 2„””gp¸`mIpOûAº×ÓëÎ×Ü=/·³tãwZZ Ë ]΂áWSLê³™ä°Üiª!WuÊF•ëëLI+ ­ ¸”¢W�«ÓW^÷E×pÛ¶Ù±QQÔÌe†¼ÔfIØ ‰cŠ–”QÅ,Ò¼jÂ( ša ‰H\Œìi ^JÒÀ‹Å¾ª¥žªÙW5TtÒÆˆtSÉR>n@Çïx ’8ÿ„ó}½A¥¼�¿.¡Ô˜D~Bg¦»í—1¤¶º0U»ã†9UòÃ# >~Ÿ¸<žÞ•aR>G{÷ºTLA>^þŠÂ¸\­µ–øî&(¨ ‰½CBð‹;]”˜Š£b#ÞÐ��ßÒzšŠZV¦y”zMI‘Žö`¤Êœgœý|èËÄå7ßOßÈ i f´wG¿�uÎ9©åŒ"ÒVw˜æe™¤ï#óÎ|ñ�§ç¨ÙD‡ÌÈòRU¬ HhƒºÊž¦áÍU3Dq»T³Ÿ”áTO­€¿‚³iê‡çö•kjE͹ûöÜ·+SéQZž iZ8d�Šä3>Ulj ¥D�âH¿OÆ«Aµk6C@ÓÐøè¡Ó××QvK<’Ë(g9¢ti¨v-ܾ}†:»J�7|¬Û®žÕ µÁ™à_§ÞWÃx†ZyŸÔ¢Ž_PÌÖL+•Ê’G8 �ÎOýœ|ÄýÉžFOéãV›L’4žÿdªÂ°kIÞþ颢r& Õ-F0B•QŒøÀÇý?–­ëÉg¼‰¶¾ Eº´ž”5o+D š�¿‘ÆOóÓ6�óªj�$e%¿…ª(PÛ–@{ŽS÷³žK` ?×râÙ™PÓa$§4z8½•!p>` ê ±çÁã‘þ®Xã~~ûôZAÀ|§ñ¢ý[v®ôD1þ‚Ý \€Áldàr|ùÉÓQcsf¹<ÊzÕ�DÓùõAÃw¬i‡¨Ð³*€D]¡H8G<ý³“©�M±#u*¿7á9Iv�¢gALƽ¤ä‘óò|j©aœÑ}ÕÎØDM½ø¨�]tÍ!ªXó”$Žãõ$cßýq­65fU©˜ËÒ s§ôZ&îE<¡¸ñÇç€yÜ~zw0æ²zu„ºˆ*•ÃÍ)o™“!› 猟�\¢KD…R»ÄJ€ÎÞ“2–}j5ò±ÞȲ×¹‘Ž<àùÓè2–Y²qÇŸx�Êp¥¨l‚;ýNt²Á½ÑfSû±™?cüj2 ê§.¶žûÐÓTÔº€±„ yŽÓHû€A÷þ›³'H>J!T Í#ÍlÏCí=EÝ·'´tÆ=«eÜÜÊnÕ·5¢¨X²Òi*eX—»³Žà /pPÜbÅdicàUªƒ®ž~‹ÑÇönlÝÓh°mšiúaÔÙ7 ªY*ó=ÆKU¶é~ÙÞhæHeĬM*Æê’»� l‹´Í®³ê8O˺ôWÒíÛÔû}--]Ö Ã²÷%ÐCM]ÆJêÅfMd·xٙєÇ$DúŸ¢zœ”ïÆ5îÓ“²Ep›ã2«§›º}×A»àêŽþµCh´mÚ*ØV¦ár,I¡Š[„UÖɤ”džz\7¡ ú‡Ê&7HAÑy—ëE£ª}KÞv­ÁIm¹ô–‚Õû-·oÞ;˜CÛ†º¤ ~Ê9=:H î^ö!‰v­Zöþ õå¼}W=î·ºúŪšZš{•3Êóú²ÔÉó—$÷—,Yƒv–¶‘眀É0nFö÷äµéÔòˆóARÝ"8ÿ c«ç'-�ABO#äøû�Q¨Ëënï¿ÛE{V"ÿ;B¶íI's=‹±‹†q5LÒ!o'Ê�p¾Ùýt gÍ ù=7ú+©i-õ'øQêö¢U/Ml†š0% ŠF#»+–ÆÆ3ÈùF<êv9ÄÃ�=t÷Ë¿B«83a¾ÿ ¦ZõX Z‹}® ¿?s¬Ž{OøU íU÷Ïaï¢-’r“§O®¾ '�Ö€@çìhš$«ïŒ*ÐÐÇ#(A`o¿-ç‘Æ?¦M‚Óþ©ï÷uS6¿(ð²ª$f (¥,¬0r¼à4æ$YIýKäòF�Œ Ï×ï§ÈMšf=Ûd⸋ÚPKyì!¤P‡{òJöýy?MJÖÔòªÕ¨Ãî=ø¦y+iŸ±@�y9ùI ãý×�[coÍS5‰JÚl¡2$rÃ98ñœcbǧ¿²|í™D-Zƒ–‰�ýì° „yðN!Ml’¯âcqN­ÈÈcÚíÏ·ë¦|D©)Hu–Ùtªã%<â®’ÙGøR;LѳÊÀùíò?/ðç>uƒ�Ê~Ry+¦á¯3˜ºÜûmö�h? !Z°Šcôêœðx`W ¾~^0|óÏ‚ëëàºV»å…«]B¼¼Õw ­šŽ9Éh+GSœ–dÇŸ ‘Á{ï`X?¾W=Äjk–Š×�YR³öÔË_WÉdeeÀ$d6Œs®Œ@²äkÉ&Uѱj¤¨–�Ó‚œÄ¾sAÚøÈÿ&sþ‡8Ô/7…�ˆl·ßát£¥µQ-*K¬´’±&+ øòeŒ㌆ò99γÈ&Þýû+®¶[ o̱ æiÊ U’g�G¿Üc�÷Õy üª½†¦™1È`\§?oòÕœã_ßA”Hw²gÎUŸÏ:h�û£.ºP° ©W<û‘¢m€„DIØÅ‚¬˜eWÇêtžy§ªYpTw#õïü´�Œ/  í-Ø<—'>ÞÚgÔäšépñ†Ï©Jp?ÀŒ þ#HuNHÑ-�W °œçåÀ6a2y(ˆæ—ŽöY<Ž;Û�:€¸L4G’‘®‹’³5à™ˆä„$�ÓO¡‘õD*uôCM3|¢0ß›ô÷u+\/uÞmd©Ç*”¹Æ?s“üôö*èä�‚iY”NÙò*ãò?Ç� .mÞ¦cçdrÔ:¨,B¸$eÿ_á¨ÚÙ1R—À¹ºü*dv>šÈÄÿÌ3ÇØyÑ´/e ß&ÒœéjåL¯¢Ì ò }°F~ùÐ:é5älžEh‘R?¨$÷w+`�õöдA™Óß¹F^4„å |�„1BÝà÷.eîí?–pQ�¶�‚âéØÙ:Û*^yf–¦b’D¢R­?¤®™=ÈH!»�€wr05 `‘¯wáFjªÛî‘îiåÜVÛ€´År¸5L‹Smi«!ù *Ã"†3ÆG$k‚±€ä«@6déïÝåVy1zøbܫĖKë¦[W§”±ÄæK´ö^û˨bÒ£%aQWÞʪӴq’_÷ŒqÆ«`‚U'BôСÖZ¶®åY¶©+èc êÛT$ªªB’»Aû;Q{ ‰;z’ÄÛhYE;« ¨p¤»Xç§–Û]y jj–¥žšÍ%LRÍÛÙÝ$ý±À£¸äwžÖUb¿9á‰M+‰5V£ÍaÜ›ÐX«f¤“oTÉ=ðÙi¨UlT¬QCV_ ¾�‰ŠA”1¬`H&¯?]Mø{Þ×*;ݚݿ—©{ÞËSG¹²[lTÓúé�"˜ÔÂ! ,ž³ ˆŸ$*i¢ž›ÃL•ÌÚȬToMÂx꥖¡„²C<Áà"_>‹Ã�Ì�ˆ Ø!Õ¿ÃØÔjÒ"ekQªÂmªŽ~2™môóæ)N{ ,$ìÎ[»)ñé€2IÏh»9ì�5Ž‹F�Hh&=Rµ3ÑM šh½1H¢ZÔ-$“�‘ÜX€!X ±Æ ÊOàž›+M9›?u©zdšsÔL¬Xº¨gï0`@úqÏ€ �#]"2ûõPÔh9]÷M�[)… Xä“È+ØÝ¸÷\ýÿ¨Õ‹kïøPœ±M-UV�щV"Ü:(`I €?nxÑC]·Óߢ®áad¨)k$ˆÙl0RpÃéË}?ÏNA&}ýf`³ªDp•Ô 2„ƒä¨ãlhfm*V´ ]î³ÈJ³HѰùó&IÁû�?Lý¼ê1M­·/|ÿ NԞ⇎ã%+×îVïUÆUÈÇ‘àþ¼hÞµ÷AeBÍ¿ºBZšÉÈËé`ÎÞ?1“�Ëí  '%ÄL$!º×ÓN®µ•œep{sÏßh\Æiá‡?¨Ð6˜Ô)»c¢ûêK!É‘å+Æ[þ£Î�´ÚHQ¹äï(˜ý^äf>™>qäj� êœi�‰ì(¤œ€ÜŒÿ P‚Žy©]¾%h %J’Ç8<NsŒ`€1œiÛmªïØW:Ëem5ÎÊoÆÍ$ŠñTR¯íÔ’Y£o”3pW€?0'ÛRSj† Ùtw£«}Lª{Åš!B#-4TñÈò÷ÒóF}P2S ½à7zª1=Æh´*Ï]oèíUºåMQf§†ËSG-:KêÅ)(ÎZaO $ˆ`ö»®G'�54 ˆ]#é«P^¡7�îño©º¢þPVh@NØÎrá«209³DÝY»5òªÖ ¥º-Þ x¦R¥õ’¦nÐAQB9¸üÝä¾@]#Ñ4• =p°%®)ÿôòíÌ~1‘%§‚†–FcÚ"\“$’ª³ä`žÕhDZ4 ƒ}~†š´î´²Þl51Hõ¡©ÑV*¹T 2´…˜œ C¯`|ʼn @ˆR²W,7�ÎkítÕ÷{•þçX™�š®­¥íääa‚'^8#ΩÔtÜ- & ‚UÍ4²‹ZÎÙsê¾s÷#ßÁþCT^»–…96 ¾g˜¨\îùín?ñý4" œŽA6Ë5s ±®NN?Èù{éÚÖÌý”Ns´ šY&qûGvùxàþCV€€«_B›e¬‘ªÀ²òÍÿA¢�æSÈ! miÀ1$@û„?ž=´ù wD$¤¿V;j)#´¿>2:Eƒp‰®!g²6KÔÕ<žAdþ¾tAÚÈú¥�§™dÁÆ@ÈÏ?Qï¤æÚi¶«)_™³€9Ïïùžu!ÒÐ¥Í ¨�¸d9ääÓQöGmT­«±Kúð‚Ž±.O¹ÏñÇ:®‚U€æ›¤Zd ÅþVÆxSÇçöÓ6žè\îiRÃ*Œý󢎪,Àè¾<‘üÅ�g�r9Çý4`P9ÃD©8\0Ç9àjV´¨3Rð„uÉ��ù|þº|¤ÞSµ ÛT¸h^ظÇÿÇB[(ZéR6ÂÇ0ùùGú:§R„úPîç+Œç÷pOóñÆœ8{)Œ¤e5©„’`}´YØÜýUiB¶©‚N˜ãÀ�?é­fØ]sõÙ]]?H„�ËU¶X‘‡{° ± þó�<yÔNl³ñ–%nžÒ¯¢¶SÒTËF�à•im¬ÌÄAEläsÜqžàpuMÂfuY5‹+&}ΊQi¢¨¨„.I, x$0Ëã8?\ûêSÝ¯Š„Ñˈç“”'ê1©$ÚŽ©oU²rëöäèHóDR©0ç–í϶yý4íd¤›%–dv¬ÇǼi‹J) ?ÄaqéwãÏs�0¤u)g/ŸŠ<Ž?ÈcßóÒÊSæ…ôVËÏȪ~�£�¦/2”üLÌIîDûq¤Ö„³�«¨óøŒ}F@ÆŸ(‰E˜ÊÈK3ßR¾ØÓ@6)¯ çt rį�„7Õf²:�?ñÿÃMÜ•ÒË&I˜óã³ÎžRD,±üÀ*ŸÓL2ˆ¸l–Yrʹü€Îœis"£™ûp[#Ø}>‰�GÇ<¸P ì?óiˆ”ò�àªô°È±Ì¨C‚ÞÃ#Û‘ÿÏí§a½Ó¥–ûåah„íëÊe^Àð((í'ÿ)ÏÉ89È9‚7[cÒÍý¸æ¨µZh?º»½&‰ãü$R0*[ÔJÏÚ2¤4h$*Ç$‘©�P‘i]¥è7V.›2;bÜ·nÏŸmþ+Ô¨¦Š÷wáÔ÷"ÁTb.±óßꀨŒÁ;F HNê&˲}¹ å%¥lÖ*uï¨²ÔÆÔ/O4™s$Êg7j/q žì™"¤lcE-•ݵÓP$ƒ`î;­xVh%Žjzuic ,α¾¤lO~I‘ò‰H”=˘ŸÝC±TÓ]èå³Y-h¤žº²ºí ý�’X•ª»¥9Up^ù£b™ Bmb“Bà�S/ªƒuÁ¶oòÝ ¤x‘ntqµ3í_F–@î«M•™K²öÈBùϧ¦Цiæ¹­»¯ö¨*å§´Ål«­ïh^v§,dÏø”{ÅvÑ4uuðÆê˜j�Lv�û½½™\døã~š¨ÖÔ,}¯š±`«íÚÕRÝ´éR"I©'µ3Àì ƒú Ï�iRc‚ÊÄUi²…ˆ–I!JÃ÷÷Éú}2Gå«¢MÖKýâÃp¸ÒUS}»9ùK!šÂÎ4/mîWÄ-›Û}Cª¤·Óú•ÖØ%?¼@‡q“† …n@ÉÁÀÇ’5›Óß¿åfÕ¥2~á^u;þ¹¢én²^+^4-$®“åOÚÇ·ÆHö`hJÖU›D‘òÌ.K+ó•Sôñª“.·TªòGGå¨Éº0–%G©ÛŸ¸çõ:E×JaãÀùóÏ>ú7D¤y%?c• ÜOØñ¡€ˆ%¯TçÈÁÔ•*l”Â]db1Ú?!àj,Ð $JÌIà2)÷:POêNL´r®¢D¼~ºL"dJ)YþÕ�ÌAú:0bé�+ça-ÇðîðtÍ6ñJ/uû·´€ ϸΖyî@X+ç•�®��td%°À·Ê«‘ŒŒçI¦B`X‡óóóõÇ� ‰—F$¼Îsä“çNatYQ°º(ÌÙýß—<ýüqüôó)¡+ëSüÌÊùÎAUΜILën�©%¶´rú³WÓUE�€ƒÞ3� dð$cÔ“¸N5•wì‹õ±ëíÔuöJk­¼È²L\v²Ä‹Ý�WöŽ¥A¹»{NBaÑ‚ùP8 —`>v¶Ü¢ºC]GvØv²fxà�ê!y©Ù7&c/©›Ó‘b é—¢�ÅPKšÖUÊî¯Oj7ÆÝh¦»\l–š×Š „U¢¦xŠ!»EÚJSF0¯>D!q1`=š•¦`(Ϋ`«òãoŽå[¼¶õ’Í%,f²ª²u­ª^Ær½‹‰e"4‡³pòid�E£�f²tÞª¯xÍ&âÚûÒÝ+«ÿôBK$õ3‰aW­ž¨Ó5CU%=2 ¿¨\ Bh›. |EîËpV-VØÿÎ~÷ T„×_ç–’„¢Ô4°f^÷c"ŽÔ.Ä£JØ,¬DdìT¬+šRÞvìõ“Ô׆ŽÅ,®ÂH³Ý;d<Žª£X¯ÎÄ^ìj¥F� ûú-Uw=e:–P)»AÂö)‡<žH÷Ç’@ûê³ØMÎÊÓ w ¼WåUB¿ãóú{cQ:Š”VMrU.�cÆ|–ð>£œþ¼jPÛÞÊ#R.²UFCw€Ù$8éõÑ�cåQ—_T•Ü$'Û œ�;Líïð�κE¦Œ�À.3íõýtä^éH²É&î9ùØ‘€9àþ\hvѯÂfPÿ³ìˆ‘ÇoÛB[Q‘”²v¨$ã.pt%ÃBœ»u��œ|�ãè2/ã¢{ ÈöR×_£~T~Ñ_�Ž£s¤D©@7Yã<ýðÿÃHÄYM}P­é‘‘/g¹‡~ZkÆŠ3u‚,m‚0|r<ý?ùhœ\tBÐî_³R¨P<?ž˜DBP"nrC«/wÔÁ×ÑWy›¯½Î£8ùsÇ éËD@L4ºüf é#¸LïM™+êÆ·Ðàž�á§=èÂú^!��’8ýþG×B)’R0,GƒœcÀÒ¸Bb.±Gí$³ à€9ûûèÜ$÷$�‘‹ww$yãÆ™–² Ý~RÇ!‡*r×DAL@AÈ ©c)cï�ääãü_7ñÆ«Ô2ÛÙ^¤á2U�n–É#JI©¯4¬§'½KžWŒ~è }üäôæ§fI1úûóZ%íÑÓ*/p±Êa Tªƒ¶1݆<~÷pl yル {µn¾öüªu²› ª2ä¼pȱƒæsÉ'ïùêÕ:€kªÎ¬Ó²“Økéi¦bZ®Ö(g*ÙeàáHÀÎGç©MÈT* h¶+bnTª…j+èå­—¾@Õq²ú¸åùÈÁðUqà1ÔNo¿ºÍÄ0ûº²(ö™. 4°¹ùYbŠr];˜ûdû¡sˆ1ùP»(7÷õ\ãñʆúãTrŽ‹«l½òœad#9óãHÀÕ8™YbSË {ûiœè6H)@H?¼‡?AãNãÙ(Ýf§r0>ÚNqÕxý4YI ’‹! á_´ó‚ré¢^”¡i HUúãNÐ)D”·r‚Kz¬??òÓ˜Ô¦ J¤±©P$�ž¶–·OÐ#Vx'ñÌ0@–úçéöãE½�NT’Û<%d•Z…ã‚&qJîD„deF>làw``œœ�£ QƒÍl7N·íM¢J’Y6Üu0ÏYOn}'4溔 'ŸÔ|«�œ |¿_ÏG–Èðl�2vä‚¡x?};@²cÍ`ó8ùˆaž1ç:1K‰Õ Ü\ào'Ç�Qëªû�¿àöÆr2F„ó%02ˆõ$ RAÇý~Zc§~5R/8ÏØòž‘h‰EY`jÝS*½‡>Í�å¦ìÂEå"ÕE›ýÑÆ2yÏ?A¢ Á1}×ÏÇ7ÌZ5 x$gNh�S6¢M«2¶x'$Ÿ·�až‰œëICµA ŽÙ÷#œ~¿¦‹(I¯óHy\¹#:’¥17MÕ·{.Q¹öç?}mûÔqÑdŽà1ÀjVÌIQ,;€÷Àò=ôa¢جՂ‘ó/?M4ìR�Ó�3¡Æ* °9÷ú{süôŽ’�¢E5³WÓA$2UÓ:Ç‘Ù?i|ðœ~_O¾«Ôlˆj·IÂn¤õt©$N¯ r®êYâÆ2B¨ü°0|5˜ä¥cÚ êœîSÛZ =u",Ÿ¾¤7q‘†Ç¿ü'Æ|jy‰µ�úJƒ=4.�`LÇÃæóà|qùêóOŸ’Ì|‰R U Àö´F©S8! OäsŸçü5$õUàÕ©oš×o5RÃ]"L‰Ø±z$¯scá°žr<ŒñãA}Õ{À Y>Ñ^6ÝJK5|¶XªYùPž>Qç Œýx—¹c˜èŠGÜ-Z‡ÿWù�dRýÁmŸÖ-à~gR?d~ýVMþ/Ëüõ36Q¿E”^òÔ5?AñF‡÷—ôþš1¯—Õ8_÷†¢©£{Ó”¿º¿¯ôÓsHj”oÜ_ûÚ’®�JGþïõ…ú©‰?¹¥CW!zGÿVÿû_óÑQßÞÈÊZOÞ‡ôþšgþ‘ÜP�JÁ?xjjš55=JZ?Ü�ó?×Q·ô{¤5Y7ïOÿt–¥§þì÷¤ä)ó'ëý4Õ?B�téÿ«—ý{hêjŸdä¿î?Aýu#?Z&l¬)?ô;ÿƒÏÿìt{ª»cIÿÖÖ?ý´¿üqè›§�á5µ[Sÿ±{‡ÿ×7ÿ%›BýüSUýCÁzeø~ÿë½�ÿööÿ&m\oèPÔ×Çÿ¶Ô¿ÿ]]ÿg£nž 'íàµû~ÿúºÿú‚§ÿÊ ÒÄh;Ô‹—Û·ÿÑ�gþÞ§ÿŠ·P?ôcõ®9ÜÿôZ¿ý›ûUÔu4÷Õ[vŠtÿzÿû?ÿwBuð gèP³~ôÿ÷�ô»÷Í ¿Rù'îîÿÓLÍOz•û&™?zoÈQ¦­¢ºÿsõLÑDVÿ¸ûßå«t[,éü7úÿ¢~¥!ªÊ_?¨ÒfÊÉMÏå1¦¥FÍÏñû£NíŠA"ß¼ßëÜiö_ºü?Ý?ëýN€j;Ô¬ý)I?x¯m -load( 'Starlet', min_reqs_per_child => 5, max_reqs_per_child => 10, ); my ($min, $max) = (7, 7); for (my $i = 0; $i < 10000; $i++) { my $n = $starlet->_calc_reqs_per_child(); $min = $n if $n < $min; $max = $n if $n > $max; } is $min, 5, "min"; is $max, 10, "max"; done_testing; Starlet-0.32/t/09chunked_zero_length.t0000644000175000017500000000116015176574475017305 0ustar kazuhokazuhouse strict; use Test::TCP; use Plack::Test; use HTTP::Request; use Test::More; $Plack::Test::Impl = "Server"; $ENV{PLACK_SERVER} = 'Starlet'; my $app = sub { my $env = shift; return sub { my $response = shift; my $writer = $response->([ 200, [ 'Content-Type', 'text/plain' ]]); $writer->write("Content"); $writer->write(""); $writer->write("Again"); $writer->close; } }; test_psgi $app, sub { my $cb = shift; my $req = HTTP::Request->new(GET => "http://localhost/"); my $res = $cb->($req); is $res->content, "ContentAgain"; }; done_testing; Starlet-0.32/t/00base-hello.psgi0000644000175000017500000000016315176574475015767 0ustar kazuhokazuhomy $handler = sub { return [ 200, [ "Content-Type" => "text/plain", "Content-Length" => 5 ], [ "hello" ] ]; }; Starlet-0.32/t/01plack-test.t0000644000175000017500000000016715176574475015331 0ustar kazuhokazuhouse strict; use Test::More; use Plack::Test::Suite; Plack::Test::Suite->run_server_tests('Starlet'); done_testing(); Starlet-0.32/t/12bad_request_line.t0000644000175000017500000000150615176574475016567 0ustar kazuhokazuhouse strict; use warnings; use Test::More; use Test::TCP qw(test_tcp); use IO::Socket::INET; use Plack::Loader; test_tcp( client => sub { my $port = shift; my $sock = IO::Socket::INET->new( PeerAddr => "localhost:$port", Proto => 'tcp', ); my $req = "GET /bad request header/ HTTP/1.0\015\012\015\012"; $sock->syswrite($req, length $req); $sock->sysread(my $buf, 1024); like $buf, qr/\b400\b/; note $buf; }, server => sub { my $port = shift; local $SIG{__WARN__} = sub { ok 0, "No warnings"; diag @_; }; my $loader = Plack::Loader->load('Starlet', port => $port); $loader->run(sub { [200, ['Content-Type' => 'text/plain'], ['OK']] }); exit; }, ); done_testing; Starlet-0.32/t/10unix_domain_socket.t0000644000175000017500000000323615176574475017144 0ustar kazuhokazuhouse strict; use File::Temp qw(tempfile); use IO::Socket::UNIX; use Plack::Loader; use Socket; use Test::More; (undef, my $sockfile) = tempfile(UNLINK => 0); unlink $sockfile; sub doit { my $create_loader = shift; my $pid = fork; die "fork failed:$!" unless defined $pid; if ($pid == 0) { # server my $loader = $create_loader->(); $loader->run(sub { my $env = shift; my $remote = $env->{REMOTE_ADDR}; $remote = 'UNIX' if ! defined $remote; return [ 200, ['Content-Type'=>'text/html'], ["HELLO $remote"], ]; }); exit; } sleep 1; my $client = IO::Socket::UNIX->new( Peer => $sockfile, timeout => 3, ) or die "failed to listen to socket $sockfile:$!"; $client->syswrite("GET / HTTP/1.0\015\012\015\012"); $client->sysread(my $buf, 1024); like $buf, qr/Starlet/; like $buf, qr/HELLO UNIX/; kill 'TERM', $pid; waitpid($pid, 0); unlink($sockfile); } subtest 'direct' => sub { doit(sub { return Plack::Loader->load( 'Starlet', max_workers => 5, socket => $sockfile, ); }); }; subtest 'server-starter' => sub { doit(sub { my $sock = IO::Socket::UNIX->new( Listen => Socket::SOMAXCONN(), Local => $sockfile, ) or die "failed to listen to socket $sockfile:$!"; $ENV{SERVER_STARTER_PORT} = "$sockfile=@{[$sock->fileno]}"; return Plack::Loader->load( 'Starlet', max_workers => 5, ); }); }; done_testing();